brcm2708: add 3.14 support
[openwrt/openwrt.git] / target / linux / brcm2708 / patches-3.14 / 0003-Add-dwc_otg-driver.patch
1 From 8065edf883d2adeea72ab1d64d50931501959a83 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 03/54] Add dwc_otg driver
5
6 Signed-off-by: popcornmix <popcornmix@gmail.com>
7 ---
8 drivers/usb/Makefile | 1 +
9 drivers/usb/core/generic.c | 1 +
10 drivers/usb/core/message.c | 79 +
11 drivers/usb/core/otg_whitelist.h | 160 +-
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 | 224 +
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, 56440 insertions(+), 43 deletions(-)
73 create mode 100644 drivers/usb/gadget/file_storage.c
74 create mode 100644 drivers/usb/host/dwc_common_port/Makefile
75 create mode 100644 drivers/usb/host/dwc_common_port/Makefile.fbsd
76 create mode 100644 drivers/usb/host/dwc_common_port/Makefile.linux
77 create mode 100644 drivers/usb/host/dwc_common_port/changes.txt
78 create mode 100644 drivers/usb/host/dwc_common_port/doc/doxygen.cfg
79 create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.c
80 create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.h
81 create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
82 create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_linux.c
83 create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
84 create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.c
85 create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.h
86 create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.c
87 create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.h
88 create mode 100644 drivers/usb/host/dwc_common_port/dwc_list.h
89 create mode 100644 drivers/usb/host/dwc_common_port/dwc_mem.c
90 create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.c
91 create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.h
92 create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.c
93 create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.h
94 create mode 100644 drivers/usb/host/dwc_common_port/dwc_os.h
95 create mode 100644 drivers/usb/host/dwc_common_port/usb.h
96 create mode 100644 drivers/usb/host/dwc_otg/Makefile
97 create mode 100644 drivers/usb/host/dwc_otg/doc/doxygen.cfg
98 create mode 100644 drivers/usb/host/dwc_otg/dummy_audio.c
99 create mode 100644 drivers/usb/host/dwc_otg/dwc_cfi_common.h
100 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_adp.c
101 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_adp.h
102 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.c
103 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.h
104 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.c
105 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.h
106 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.c
107 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.h
108 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
109 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_core_if.h
110 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_dbg.h
111 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.c
112 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.h
113 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.c
114 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.h
115 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
116 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
117 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
118 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
119 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
120 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
121 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.c
122 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.h
123 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
124 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
125 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
126 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_regs.h
127 create mode 100644 drivers/usb/host/dwc_otg/test/Makefile
128 create mode 100644 drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
129 create mode 100644 drivers/usb/host/dwc_otg/test/test_mod_param.pl
130 create mode 100644 drivers/usb/host/dwc_otg/test/test_sysfs.pl
131
132 diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
133 index 1ae2bf3..c4a45aa 100644
134 --- a/drivers/usb/Makefile
135 +++ b/drivers/usb/Makefile
136 @@ -24,6 +24,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/
143 obj-$(CONFIG_USB_FUSBH200_HCD) += 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)
149 dev_warn(&udev->dev,
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);
153 }
154 return i;
155 }
156 diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
157 index f829a1a..4a44ae7 100644
158 --- a/drivers/usb/core/message.c
159 +++ b/drivers/usb/core/message.c
160 @@ -1888,6 +1888,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
174 + * sequence.
175 + */
176 + if (dev->descriptor.idVendor == 0x1A0A) {
177 + /* HSOTG Electrical Test */
178 + dev_warn(&dev->dev, "VID from HSOTG Electrical Test Fixture\n");
179 +
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);
183 +
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);
190 + break;
191 +
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);
197 + break;
198 +
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);
204 + break;
205 +
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);
211 + break;
212 +
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);
218 + break;
219 +
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);
225 + break;
226 +
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);
232 + break;
233 +
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);
239 + }
240 + }
241 + }
242 +#endif /* DWC_HS_ELECT_TST */
243
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..ca0ac47 100644
248 --- a/drivers/usb/core/otg_whitelist.h
249 +++ b/drivers/usb/core/otg_whitelist.h
250 @@ -19,33 +19,82 @@
251 static struct usb_device_id whitelist_table [] = {
252
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*/
257 +#else
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), },
261 +#endif
262
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...
266 */
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) },
273 #endif
274
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), },
282 #endif
283
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), },
288 #endif
289
290 +/* OPT Tester */
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 */
299 +
300 +/* Sony cameras */
301 +{ USB_DEVICE_VER(0x054c,0x0010,0x0410, 0x0500), },
302 +
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. */
310 +
311 +/* HP Printers */
312 +//{ USB_DEVICE( 0x03F0, 0x1102 ), }, /* HP Photosmart 245 */
313 +//{ USB_DEVICE( 0x03F0, 0x1302 ), }, /* HP Photosmart 370 Series */
314 +
315 +/* Speakers */
316 +//{ USB_DEVICE( 0x0499, 0x3002 ), }, /* YAMAHA YST-MS35D USB Speakers */
317 +//{ USB_DEVICE( 0x0672, 0x1041 ), }, /* Labtec USB Headset */
318 +
319 { } /* Terminating entry */
320 };
321
322 +static inline void report_errors(struct usb_device *dev)
323 +{
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");
330 + } else {
331 + dev_printk(KERN_CRIT, &dev->dev, "Attached Device is not Supported\n");
332 + }
333 +}
334 +
335 +
336 static int is_targeted(struct usb_device *dev)
337 {
338 struct usb_device_id *id = whitelist_table;
339 @@ -55,58 +104,83 @@ static int is_targeted(struct usb_device *dev)
340 return 1;
341
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))
345 - return 0;
346 + if (dev->descriptor.idVendor == 0x1a0a &&
347 + dev->descriptor.idProduct == 0xbadd) {
348 + return 0;
349 + } else if (!enable_whitelist) {
350 + return 1;
351 + } else {
352 +
353 +#ifdef DEBUG
354 + dev_dbg(&dev->dev, "device V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
355 + dev->descriptor.idVendor,
356 + dev->descriptor.idProduct,
357 + dev->descriptor.bDeviceClass,
358 + dev->descriptor.bDeviceSubClass,
359 + dev->descriptor.bDeviceProtocol);
360 +#endif
361
362 - /* NOTE: can't use usb_match_id() since interface caches
363 - * aren't set up yet. this is cut/paste from that code.
364 - */
365 - for (id = whitelist_table; id->match_flags; id++) {
366 - if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
367 - id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
368 - continue;
369 + return 1;
370 + /* NOTE: can't use usb_match_id() since interface caches
371 + * aren't set up yet. this is cut/paste from that code.
372 + */
373 + for (id = whitelist_table; id->match_flags; id++) {
374 +#ifdef DEBUG
375 + dev_dbg(&dev->dev,
376 + "ID: V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
377 + id->idVendor,
378 + id->idProduct,
379 + id->bDeviceClass,
380 + id->bDeviceSubClass,
381 + id->bDeviceProtocol);
382 +#endif
383
384 - if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
385 - id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
386 - continue;
387 + if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
388 + id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
389 + continue;
390
391 - /* No need to test id->bcdDevice_lo != 0, since 0 is never
392 - greater than any unsigned number. */
393 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
394 - (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
395 - continue;
396 + if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
397 + id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
398 + continue;
399
400 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
401 - (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
402 - continue;
403 + /* No need to test id->bcdDevice_lo != 0, since 0 is never
404 + greater than any unsigned number. */
405 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
406 + (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
407 + continue;
408
409 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
410 - (id->bDeviceClass != dev->descriptor.bDeviceClass))
411 - continue;
412 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
413 + (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
414 + continue;
415
416 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
417 - (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
418 - continue;
419 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
420 + (id->bDeviceClass != dev->descriptor.bDeviceClass))
421 + continue;
422
423 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
424 - (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
425 - continue;
426 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
427 + (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
428 + continue;
429
430 - return 1;
431 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
432 + (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
433 + continue;
434 +
435 + return 1;
436 + }
437 }
438
439 /* add other match criteria here ... */
440
441 -
442 - /* OTG MESSAGE: report errors here, customize to match your product */
443 - dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
444 - le16_to_cpu(dev->descriptor.idVendor),
445 - le16_to_cpu(dev->descriptor.idProduct));
446 #ifdef CONFIG_USB_OTG_WHITELIST
447 + report_errors(dev);
448 return 0;
449 #else
450 - return 1;
451 + if (enable_whitelist) {
452 + report_errors(dev);
453 + return 0;
454 + } else {
455 + return 1;
456 + }
457 #endif
458 }
459
460 diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
461 new file mode 100644
462 index 0000000..a896d73
463 --- /dev/null
464 +++ b/drivers/usb/gadget/file_storage.c
465 @@ -0,0 +1,3676 @@
466 +/*
467 + * file_storage.c -- File-backed USB Storage Gadget, for USB development
468 + *
469 + * Copyright (C) 2003-2008 Alan Stern
470 + * All rights reserved.
471 + *
472 + * Redistribution and use in source and binary forms, with or without
473 + * modification, are permitted provided that the following conditions
474 + * are met:
475 + * 1. Redistributions of source code must retain the above copyright
476 + * notice, this list of conditions, and the following disclaimer,
477 + * without modification.
478 + * 2. Redistributions in binary form must reproduce the above copyright
479 + * notice, this list of conditions and the following disclaimer in the
480 + * documentation and/or other materials provided with the distribution.
481 + * 3. The names of the above-listed copyright holders may not be used
482 + * to endorse or promote products derived from this software without
483 + * specific prior written permission.
484 + *
485 + * ALTERNATIVELY, this software may be distributed under the terms of the
486 + * GNU General Public License ("GPL") as published by the Free Software
487 + * Foundation, either version 2 of that License or (at your option) any
488 + * later version.
489 + *
490 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
491 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
492 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
493 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
494 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
495 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
496 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
497 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
498 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
499 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
500 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
501 + */
502 +
503 +
504 +/*
505 + * The File-backed Storage Gadget acts as a USB Mass Storage device,
506 + * appearing to the host as a disk drive or as a CD-ROM drive. In addition
507 + * to providing an example of a genuinely useful gadget driver for a USB
508 + * device, it also illustrates a technique of double-buffering for increased
509 + * throughput. Last but not least, it gives an easy way to probe the
510 + * behavior of the Mass Storage drivers in a USB host.
511 + *
512 + * Backing storage is provided by a regular file or a block device, specified
513 + * by the "file" module parameter. Access can be limited to read-only by
514 + * setting the optional "ro" module parameter. (For CD-ROM emulation,
515 + * access is always read-only.) The gadget will indicate that it has
516 + * removable media if the optional "removable" module parameter is set.
517 + *
518 + * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI),
519 + * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected
520 + * by the optional "transport" module parameter. It also supports the
521 + * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03),
522 + * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by
523 + * the optional "protocol" module parameter. In addition, the default
524 + * Vendor ID, Product ID, release number and serial number can be overridden.
525 + *
526 + * There is support for multiple logical units (LUNs), each of which has
527 + * its own backing file. The number of LUNs can be set using the optional
528 + * "luns" module parameter (anywhere from 1 to 8), and the corresponding
529 + * files are specified using comma-separated lists for "file" and "ro".
530 + * The default number of LUNs is taken from the number of "file" elements;
531 + * it is 1 if "file" is not given. If "removable" is not set then a backing
532 + * file must be specified for each LUN. If it is set, then an unspecified
533 + * or empty backing filename means the LUN's medium is not loaded. Ideally
534 + * each LUN would be settable independently as a disk drive or a CD-ROM
535 + * drive, but currently all LUNs have to be the same type. The CD-ROM
536 + * emulation includes a single data track and no audio tracks; hence there
537 + * need be only one backing file per LUN.
538 + *
539 + * Requirements are modest; only a bulk-in and a bulk-out endpoint are
540 + * needed (an interrupt-out endpoint is also needed for CBI). The memory
541 + * requirement amounts to two 16K buffers, size configurable by a parameter.
542 + * Support is included for both full-speed and high-speed operation.
543 + *
544 + * Note that the driver is slightly non-portable in that it assumes a
545 + * single memory/DMA buffer will be useable for bulk-in, bulk-out, and
546 + * interrupt-in endpoints. With most device controllers this isn't an
547 + * issue, but there may be some with hardware restrictions that prevent
548 + * a buffer from being used by more than one endpoint.
549 + *
550 + * Module options:
551 + *
552 + * file=filename[,filename...]
553 + * Required if "removable" is not set, names of
554 + * the files or block devices used for
555 + * backing storage
556 + * serial=HHHH... Required serial number (string of hex chars)
557 + * ro=b[,b...] Default false, booleans for read-only access
558 + * removable Default false, boolean for removable media
559 + * luns=N Default N = number of filenames, number of
560 + * LUNs to support
561 + * nofua=b[,b...] Default false, booleans for ignore FUA flag
562 + * in SCSI WRITE(10,12) commands
563 + * stall Default determined according to the type of
564 + * USB device controller (usually true),
565 + * boolean to permit the driver to halt
566 + * bulk endpoints
567 + * cdrom Default false, boolean for whether to emulate
568 + * a CD-ROM drive
569 + * transport=XXX Default BBB, transport name (CB, CBI, or BBB)
570 + * protocol=YYY Default SCSI, protocol name (RBC, 8020 or
571 + * ATAPI, QIC, UFI, 8070, or SCSI;
572 + * also 1 - 6)
573 + * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID
574 + * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID
575 + * release=0xRRRR Override the USB release number (bcdDevice)
576 + * buflen=N Default N=16384, buffer size used (will be
577 + * rounded down to a multiple of
578 + * PAGE_CACHE_SIZE)
579 + *
580 + * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro",
581 + * "removable", "luns", "nofua", "stall", and "cdrom" options are available;
582 + * default values are used for everything else.
583 + *
584 + * The pathnames of the backing files and the ro settings are available in
585 + * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of
586 + * the gadget's sysfs directory. If the "removable" option is set, writing to
587 + * these files will simulate ejecting/loading the medium (writing an empty
588 + * line means eject) and adjusting a write-enable tab. Changes to the ro
589 + * setting are not allowed when the medium is loaded or if CD-ROM emulation
590 + * is being used.
591 + *
592 + * This gadget driver is heavily based on "Gadget Zero" by David Brownell.
593 + * The driver's SCSI command interface was based on the "Information
594 + * technology - Small Computer System Interface - 2" document from
595 + * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at
596 + * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception
597 + * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the
598 + * "Universal Serial Bus Mass Storage Class UFI Command Specification"
599 + * document, Revision 1.0, December 14, 1998, available at
600 + * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
601 + */
602 +
603 +
604 +/*
605 + * Driver Design
606 + *
607 + * The FSG driver is fairly straightforward. There is a main kernel
608 + * thread that handles most of the work. Interrupt routines field
609 + * callbacks from the controller driver: bulk- and interrupt-request
610 + * completion notifications, endpoint-0 events, and disconnect events.
611 + * Completion events are passed to the main thread by wakeup calls. Many
612 + * ep0 requests are handled at interrupt time, but SetInterface,
613 + * SetConfiguration, and device reset requests are forwarded to the
614 + * thread in the form of "exceptions" using SIGUSR1 signals (since they
615 + * should interrupt any ongoing file I/O operations).
616 + *
617 + * The thread's main routine implements the standard command/data/status
618 + * parts of a SCSI interaction. It and its subroutines are full of tests
619 + * for pending signals/exceptions -- all this polling is necessary since
620 + * the kernel has no setjmp/longjmp equivalents. (Maybe this is an
621 + * indication that the driver really wants to be running in userspace.)
622 + * An important point is that so long as the thread is alive it keeps an
623 + * open reference to the backing file. This will prevent unmounting
624 + * the backing file's underlying filesystem and could cause problems
625 + * during system shutdown, for example. To prevent such problems, the
626 + * thread catches INT, TERM, and KILL signals and converts them into
627 + * an EXIT exception.
628 + *
629 + * In normal operation the main thread is started during the gadget's
630 + * fsg_bind() callback and stopped during fsg_unbind(). But it can also
631 + * exit when it receives a signal, and there's no point leaving the
632 + * gadget running when the thread is dead. So just before the thread
633 + * exits, it deregisters the gadget driver. This makes things a little
634 + * tricky: The driver is deregistered at two places, and the exiting
635 + * thread can indirectly call fsg_unbind() which in turn can tell the
636 + * thread to exit. The first problem is resolved through the use of the
637 + * REGISTERED atomic bitflag; the driver will only be deregistered once.
638 + * The second problem is resolved by having fsg_unbind() check
639 + * fsg->state; it won't try to stop the thread if the state is already
640 + * FSG_STATE_TERMINATED.
641 + *
642 + * To provide maximum throughput, the driver uses a circular pipeline of
643 + * buffer heads (struct fsg_buffhd). In principle the pipeline can be
644 + * arbitrarily long; in practice the benefits don't justify having more
645 + * than 2 stages (i.e., double buffering). But it helps to think of the
646 + * pipeline as being a long one. Each buffer head contains a bulk-in and
647 + * a bulk-out request pointer (since the buffer can be used for both
648 + * output and input -- directions always are given from the host's
649 + * point of view) as well as a pointer to the buffer and various state
650 + * variables.
651 + *
652 + * Use of the pipeline follows a simple protocol. There is a variable
653 + * (fsg->next_buffhd_to_fill) that points to the next buffer head to use.
654 + * At any time that buffer head may still be in use from an earlier
655 + * request, so each buffer head has a state variable indicating whether
656 + * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the
657 + * buffer head to be EMPTY, filling the buffer either by file I/O or by
658 + * USB I/O (during which the buffer head is BUSY), and marking the buffer
659 + * head FULL when the I/O is complete. Then the buffer will be emptied
660 + * (again possibly by USB I/O, during which it is marked BUSY) and
661 + * finally marked EMPTY again (possibly by a completion routine).
662 + *
663 + * A module parameter tells the driver to avoid stalling the bulk
664 + * endpoints wherever the transport specification allows. This is
665 + * necessary for some UDCs like the SuperH, which cannot reliably clear a
666 + * halt on a bulk endpoint. However, under certain circumstances the
667 + * Bulk-only specification requires a stall. In such cases the driver
668 + * will halt the endpoint and set a flag indicating that it should clear
669 + * the halt in software during the next device reset. Hopefully this
670 + * will permit everything to work correctly. Furthermore, although the
671 + * specification allows the bulk-out endpoint to halt when the host sends
672 + * too much data, implementing this would cause an unavoidable race.
673 + * The driver will always use the "no-stall" approach for OUT transfers.
674 + *
675 + * One subtle point concerns sending status-stage responses for ep0
676 + * requests. Some of these requests, such as device reset, can involve
677 + * interrupting an ongoing file I/O operation, which might take an
678 + * arbitrarily long time. During that delay the host might give up on
679 + * the original ep0 request and issue a new one. When that happens the
680 + * driver should not notify the host about completion of the original
681 + * request, as the host will no longer be waiting for it. So the driver
682 + * assigns to each ep0 request a unique tag, and it keeps track of the
683 + * tag value of the request associated with a long-running exception
684 + * (device-reset, interface-change, or configuration-change). When the
685 + * exception handler is finished, the status-stage response is submitted
686 + * only if the current ep0 request tag is equal to the exception request
687 + * tag. Thus only the most recently received ep0 request will get a
688 + * status-stage response.
689 + *
690 + * Warning: This driver source file is too long. It ought to be split up
691 + * into a header file plus about 3 separate .c files, to handle the details
692 + * of the Gadget, USB Mass Storage, and SCSI protocols.
693 + */
694 +
695 +
696 +/* #define VERBOSE_DEBUG */
697 +/* #define DUMP_MSGS */
698 +
699 +
700 +#include <linux/blkdev.h>
701 +#include <linux/completion.h>
702 +#include <linux/dcache.h>
703 +#include <linux/delay.h>
704 +#include <linux/device.h>
705 +#include <linux/fcntl.h>
706 +#include <linux/file.h>
707 +#include <linux/fs.h>
708 +#include <linux/kref.h>
709 +#include <linux/kthread.h>
710 +#include <linux/limits.h>
711 +#include <linux/module.h>
712 +#include <linux/rwsem.h>
713 +#include <linux/slab.h>
714 +#include <linux/spinlock.h>
715 +#include <linux/string.h>
716 +#include <linux/freezer.h>
717 +#include <linux/utsname.h>
718 +
719 +#include <linux/usb/ch9.h>
720 +#include <linux/usb/gadget.h>
721 +
722 +#include "gadget_chips.h"
723 +
724 +
725 +
726 +/*
727 + * Kbuild is not very cooperative with respect to linking separately
728 + * compiled library objects into one module. So for now we won't use
729 + * separate compilation ... ensuring init/exit sections work to shrink
730 + * the runtime footprint, and giving us at least some parts of what
731 + * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
732 + */
733 +#include "usbstring.c"
734 +#include "config.c"
735 +#include "epautoconf.c"
736 +
737 +/*-------------------------------------------------------------------------*/
738 +
739 +#define DRIVER_DESC "File-backed Storage Gadget"
740 +#define DRIVER_NAME "g_file_storage"
741 +#define DRIVER_VERSION "1 September 2010"
742 +
743 +static char fsg_string_manufacturer[64];
744 +static const char fsg_string_product[] = DRIVER_DESC;
745 +static const char fsg_string_config[] = "Self-powered";
746 +static const char fsg_string_interface[] = "Mass Storage";
747 +
748 +
749 +#include "storage_common.c"
750 +
751 +
752 +MODULE_DESCRIPTION(DRIVER_DESC);
753 +MODULE_AUTHOR("Alan Stern");
754 +MODULE_LICENSE("Dual BSD/GPL");
755 +
756 +/*
757 + * This driver assumes self-powered hardware and has no way for users to
758 + * trigger remote wakeup. It uses autoconfiguration to select endpoints
759 + * and endpoint addresses.
760 + */
761 +
762 +
763 +/*-------------------------------------------------------------------------*/
764 +
765 +
766 +/* Encapsulate the module parameter settings */
767 +
768 +static struct {
769 + char *file[FSG_MAX_LUNS];
770 + char *serial;
771 + bool ro[FSG_MAX_LUNS];
772 + bool nofua[FSG_MAX_LUNS];
773 + unsigned int num_filenames;
774 + unsigned int num_ros;
775 + unsigned int num_nofuas;
776 + unsigned int nluns;
777 +
778 + bool removable;
779 + bool can_stall;
780 + bool cdrom;
781 +
782 + char *transport_parm;
783 + char *protocol_parm;
784 + unsigned short vendor;
785 + unsigned short product;
786 + unsigned short release;
787 + unsigned int buflen;
788 +
789 + int transport_type;
790 + char *transport_name;
791 + int protocol_type;
792 + char *protocol_name;
793 +
794 +} mod_data = { // Default values
795 + .transport_parm = "BBB",
796 + .protocol_parm = "SCSI",
797 + .removable = 0,
798 + .can_stall = 1,
799 + .cdrom = 0,
800 + .vendor = FSG_VENDOR_ID,
801 + .product = FSG_PRODUCT_ID,
802 + .release = 0xffff, // Use controller chip type
803 + .buflen = 16384,
804 + };
805 +
806 +
807 +module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames,
808 + S_IRUGO);
809 +MODULE_PARM_DESC(file, "names of backing files or devices");
810 +
811 +module_param_named(serial, mod_data.serial, charp, S_IRUGO);
812 +MODULE_PARM_DESC(serial, "USB serial number");
813 +
814 +module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
815 +MODULE_PARM_DESC(ro, "true to force read-only");
816 +
817 +module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas,
818 + S_IRUGO);
819 +MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit");
820 +
821 +module_param_named(luns, mod_data.nluns, uint, S_IRUGO);
822 +MODULE_PARM_DESC(luns, "number of LUNs");
823 +
824 +module_param_named(removable, mod_data.removable, bool, S_IRUGO);
825 +MODULE_PARM_DESC(removable, "true to simulate removable media");
826 +
827 +module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
828 +MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
829 +
830 +module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
831 +MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
832 +
833 +/* In the non-TEST version, only the module parameters listed above
834 + * are available. */
835 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
836 +
837 +module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO);
838 +MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)");
839 +
840 +module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO);
841 +MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, "
842 + "8070, or SCSI)");
843 +
844 +module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO);
845 +MODULE_PARM_DESC(vendor, "USB Vendor ID");
846 +
847 +module_param_named(product, mod_data.product, ushort, S_IRUGO);
848 +MODULE_PARM_DESC(product, "USB Product ID");
849 +
850 +module_param_named(release, mod_data.release, ushort, S_IRUGO);
851 +MODULE_PARM_DESC(release, "USB release number");
852 +
853 +module_param_named(buflen, mod_data.buflen, uint, S_IRUGO);
854 +MODULE_PARM_DESC(buflen, "I/O buffer size");
855 +
856 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
857 +
858 +
859 +/*
860 + * These definitions will permit the compiler to avoid generating code for
861 + * parts of the driver that aren't used in the non-TEST version. Even gcc
862 + * can recognize when a test of a constant expression yields a dead code
863 + * path.
864 + */
865 +
866 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
867 +
868 +#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK)
869 +#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI)
870 +#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI)
871 +
872 +#else
873 +
874 +#define transport_is_bbb() 1
875 +#define transport_is_cbi() 0
876 +#define protocol_is_scsi() 1
877 +
878 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
879 +
880 +
881 +/*-------------------------------------------------------------------------*/
882 +
883 +
884 +struct fsg_dev {
885 + /* lock protects: state, all the req_busy's, and cbbuf_cmnd */
886 + spinlock_t lock;
887 + struct usb_gadget *gadget;
888 +
889 + /* filesem protects: backing files in use */
890 + struct rw_semaphore filesem;
891 +
892 + /* reference counting: wait until all LUNs are released */
893 + struct kref ref;
894 +
895 + struct usb_ep *ep0; // Handy copy of gadget->ep0
896 + struct usb_request *ep0req; // For control responses
897 + unsigned int ep0_req_tag;
898 + const char *ep0req_name;
899 +
900 + struct usb_request *intreq; // For interrupt responses
901 + int intreq_busy;
902 + struct fsg_buffhd *intr_buffhd;
903 +
904 + unsigned int bulk_out_maxpacket;
905 + enum fsg_state state; // For exception handling
906 + unsigned int exception_req_tag;
907 +
908 + u8 config, new_config;
909 +
910 + unsigned int running : 1;
911 + unsigned int bulk_in_enabled : 1;
912 + unsigned int bulk_out_enabled : 1;
913 + unsigned int intr_in_enabled : 1;
914 + unsigned int phase_error : 1;
915 + unsigned int short_packet_received : 1;
916 + unsigned int bad_lun_okay : 1;
917 +
918 + unsigned long atomic_bitflags;
919 +#define REGISTERED 0
920 +#define IGNORE_BULK_OUT 1
921 +#define SUSPENDED 2
922 +
923 + struct usb_ep *bulk_in;
924 + struct usb_ep *bulk_out;
925 + struct usb_ep *intr_in;
926 +
927 + struct fsg_buffhd *next_buffhd_to_fill;
928 + struct fsg_buffhd *next_buffhd_to_drain;
929 +
930 + int thread_wakeup_needed;
931 + struct completion thread_notifier;
932 + struct task_struct *thread_task;
933 +
934 + int cmnd_size;
935 + u8 cmnd[MAX_COMMAND_SIZE];
936 + enum data_direction data_dir;
937 + u32 data_size;
938 + u32 data_size_from_cmnd;
939 + u32 tag;
940 + unsigned int lun;
941 + u32 residue;
942 + u32 usb_amount_left;
943 +
944 + /* The CB protocol offers no way for a host to know when a command
945 + * has completed. As a result the next command may arrive early,
946 + * and we will still have to handle it. For that reason we need
947 + * a buffer to store new commands when using CB (or CBI, which
948 + * does not oblige a host to wait for command completion either). */
949 + int cbbuf_cmnd_size;
950 + u8 cbbuf_cmnd[MAX_COMMAND_SIZE];
951 +
952 + unsigned int nluns;
953 + struct fsg_lun *luns;
954 + struct fsg_lun *curlun;
955 + /* Must be the last entry */
956 + struct fsg_buffhd buffhds[];
957 +};
958 +
959 +typedef void (*fsg_routine_t)(struct fsg_dev *);
960 +
961 +static int exception_in_progress(struct fsg_dev *fsg)
962 +{
963 + return (fsg->state > FSG_STATE_IDLE);
964 +}
965 +
966 +/* Make bulk-out requests be divisible by the maxpacket size */
967 +static void set_bulk_out_req_length(struct fsg_dev *fsg,
968 + struct fsg_buffhd *bh, unsigned int length)
969 +{
970 + unsigned int rem;
971 +
972 + bh->bulk_out_intended_length = length;
973 + rem = length % fsg->bulk_out_maxpacket;
974 + if (rem > 0)
975 + length += fsg->bulk_out_maxpacket - rem;
976 + bh->outreq->length = length;
977 +}
978 +
979 +static struct fsg_dev *the_fsg;
980 +static struct usb_gadget_driver fsg_driver;
981 +
982 +
983 +/*-------------------------------------------------------------------------*/
984 +
985 +static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
986 +{
987 + const char *name;
988 +
989 + if (ep == fsg->bulk_in)
990 + name = "bulk-in";
991 + else if (ep == fsg->bulk_out)
992 + name = "bulk-out";
993 + else
994 + name = ep->name;
995 + DBG(fsg, "%s set halt\n", name);
996 + return usb_ep_set_halt(ep);
997 +}
998 +
999 +
1000 +/*-------------------------------------------------------------------------*/
1001 +
1002 +/*
1003 + * DESCRIPTORS ... most are static, but strings and (full) configuration
1004 + * descriptors are built on demand. Also the (static) config and interface
1005 + * descriptors are adjusted during fsg_bind().
1006 + */
1007 +
1008 +/* There is only one configuration. */
1009 +#define CONFIG_VALUE 1
1010 +
1011 +static struct usb_device_descriptor
1012 +device_desc = {
1013 + .bLength = sizeof device_desc,
1014 + .bDescriptorType = USB_DT_DEVICE,
1015 +
1016 + .bcdUSB = cpu_to_le16(0x0200),
1017 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
1018 +
1019 + /* The next three values can be overridden by module parameters */
1020 + .idVendor = cpu_to_le16(FSG_VENDOR_ID),
1021 + .idProduct = cpu_to_le16(FSG_PRODUCT_ID),
1022 + .bcdDevice = cpu_to_le16(0xffff),
1023 +
1024 + .iManufacturer = FSG_STRING_MANUFACTURER,
1025 + .iProduct = FSG_STRING_PRODUCT,
1026 + .iSerialNumber = FSG_STRING_SERIAL,
1027 + .bNumConfigurations = 1,
1028 +};
1029 +
1030 +static struct usb_config_descriptor
1031 +config_desc = {
1032 + .bLength = sizeof config_desc,
1033 + .bDescriptorType = USB_DT_CONFIG,
1034 +
1035 + /* wTotalLength computed by usb_gadget_config_buf() */
1036 + .bNumInterfaces = 1,
1037 + .bConfigurationValue = CONFIG_VALUE,
1038 + .iConfiguration = FSG_STRING_CONFIG,
1039 + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
1040 + .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
1041 +};
1042 +
1043 +
1044 +static struct usb_qualifier_descriptor
1045 +dev_qualifier = {
1046 + .bLength = sizeof dev_qualifier,
1047 + .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
1048 +
1049 + .bcdUSB = cpu_to_le16(0x0200),
1050 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
1051 +
1052 + .bNumConfigurations = 1,
1053 +};
1054 +
1055 +static int populate_bos(struct fsg_dev *fsg, u8 *buf)
1056 +{
1057 + memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE);
1058 + buf += USB_DT_BOS_SIZE;
1059 +
1060 + memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE);
1061 + buf += USB_DT_USB_EXT_CAP_SIZE;
1062 +
1063 + memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE);
1064 +
1065 + return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE
1066 + + USB_DT_USB_EXT_CAP_SIZE;
1067 +}
1068 +
1069 +/*
1070 + * Config descriptors must agree with the code that sets configurations
1071 + * and with code managing interfaces and their altsettings. They must
1072 + * also handle different speeds and other-speed requests.
1073 + */
1074 +static int populate_config_buf(struct usb_gadget *gadget,
1075 + u8 *buf, u8 type, unsigned index)
1076 +{
1077 + enum usb_device_speed speed = gadget->speed;
1078 + int len;
1079 + const struct usb_descriptor_header **function;
1080 +
1081 + if (index > 0)
1082 + return -EINVAL;
1083 +
1084 + if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
1085 + speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
1086 + function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH
1087 + ? (const struct usb_descriptor_header **)fsg_hs_function
1088 + : (const struct usb_descriptor_header **)fsg_fs_function;
1089 +
1090 + /* for now, don't advertise srp-only devices */
1091 + if (!gadget_is_otg(gadget))
1092 + function++;
1093 +
1094 + len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
1095 + ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
1096 + return len;
1097 +}
1098 +
1099 +
1100 +/*-------------------------------------------------------------------------*/
1101 +
1102 +/* These routines may be called in process context or in_irq */
1103 +
1104 +/* Caller must hold fsg->lock */
1105 +static void wakeup_thread(struct fsg_dev *fsg)
1106 +{
1107 + /* Tell the main thread that something has happened */
1108 + fsg->thread_wakeup_needed = 1;
1109 + if (fsg->thread_task)
1110 + wake_up_process(fsg->thread_task);
1111 +}
1112 +
1113 +
1114 +static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
1115 +{
1116 + unsigned long flags;
1117 +
1118 + /* Do nothing if a higher-priority exception is already in progress.
1119 + * If a lower-or-equal priority exception is in progress, preempt it
1120 + * and notify the main thread by sending it a signal. */
1121 + spin_lock_irqsave(&fsg->lock, flags);
1122 + if (fsg->state <= new_state) {
1123 + fsg->exception_req_tag = fsg->ep0_req_tag;
1124 + fsg->state = new_state;
1125 + if (fsg->thread_task)
1126 + send_sig_info(SIGUSR1, SEND_SIG_FORCED,
1127 + fsg->thread_task);
1128 + }
1129 + spin_unlock_irqrestore(&fsg->lock, flags);
1130 +}
1131 +
1132 +
1133 +/*-------------------------------------------------------------------------*/
1134 +
1135 +/* The disconnect callback and ep0 routines. These always run in_irq,
1136 + * except that ep0_queue() is called in the main thread to acknowledge
1137 + * completion of various requests: set config, set interface, and
1138 + * Bulk-only device reset. */
1139 +
1140 +static void fsg_disconnect(struct usb_gadget *gadget)
1141 +{
1142 + struct fsg_dev *fsg = get_gadget_data(gadget);
1143 +
1144 + DBG(fsg, "disconnect or port reset\n");
1145 + raise_exception(fsg, FSG_STATE_DISCONNECT);
1146 +}
1147 +
1148 +
1149 +static int ep0_queue(struct fsg_dev *fsg)
1150 +{
1151 + int rc;
1152 +
1153 + rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC);
1154 + if (rc != 0 && rc != -ESHUTDOWN) {
1155 +
1156 + /* We can't do much more than wait for a reset */
1157 + WARNING(fsg, "error in submission: %s --> %d\n",
1158 + fsg->ep0->name, rc);
1159 + }
1160 + return rc;
1161 +}
1162 +
1163 +static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
1164 +{
1165 + struct fsg_dev *fsg = ep->driver_data;
1166 +
1167 + if (req->actual > 0)
1168 + dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
1169 + if (req->status || req->actual != req->length)
1170 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1171 + req->status, req->actual, req->length);
1172 + if (req->status == -ECONNRESET) // Request was cancelled
1173 + usb_ep_fifo_flush(ep);
1174 +
1175 + if (req->status == 0 && req->context)
1176 + ((fsg_routine_t) (req->context))(fsg);
1177 +}
1178 +
1179 +
1180 +/*-------------------------------------------------------------------------*/
1181 +
1182 +/* Bulk and interrupt endpoint completion handlers.
1183 + * These always run in_irq. */
1184 +
1185 +static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
1186 +{
1187 + struct fsg_dev *fsg = ep->driver_data;
1188 + struct fsg_buffhd *bh = req->context;
1189 +
1190 + if (req->status || req->actual != req->length)
1191 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1192 + req->status, req->actual, req->length);
1193 + if (req->status == -ECONNRESET) // Request was cancelled
1194 + usb_ep_fifo_flush(ep);
1195 +
1196 + /* Hold the lock while we update the request and buffer states */
1197 + smp_wmb();
1198 + spin_lock(&fsg->lock);
1199 + bh->inreq_busy = 0;
1200 + bh->state = BUF_STATE_EMPTY;
1201 + wakeup_thread(fsg);
1202 + spin_unlock(&fsg->lock);
1203 +}
1204 +
1205 +static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
1206 +{
1207 + struct fsg_dev *fsg = ep->driver_data;
1208 + struct fsg_buffhd *bh = req->context;
1209 +
1210 + dump_msg(fsg, "bulk-out", req->buf, req->actual);
1211 + if (req->status || req->actual != bh->bulk_out_intended_length)
1212 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1213 + req->status, req->actual,
1214 + bh->bulk_out_intended_length);
1215 + if (req->status == -ECONNRESET) // Request was cancelled
1216 + usb_ep_fifo_flush(ep);
1217 +
1218 + /* Hold the lock while we update the request and buffer states */
1219 + smp_wmb();
1220 + spin_lock(&fsg->lock);
1221 + bh->outreq_busy = 0;
1222 + bh->state = BUF_STATE_FULL;
1223 + wakeup_thread(fsg);
1224 + spin_unlock(&fsg->lock);
1225 +}
1226 +
1227 +
1228 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
1229 +static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
1230 +{
1231 + struct fsg_dev *fsg = ep->driver_data;
1232 + struct fsg_buffhd *bh = req->context;
1233 +
1234 + if (req->status || req->actual != req->length)
1235 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1236 + req->status, req->actual, req->length);
1237 + if (req->status == -ECONNRESET) // Request was cancelled
1238 + usb_ep_fifo_flush(ep);
1239 +
1240 + /* Hold the lock while we update the request and buffer states */
1241 + smp_wmb();
1242 + spin_lock(&fsg->lock);
1243 + fsg->intreq_busy = 0;
1244 + bh->state = BUF_STATE_EMPTY;
1245 + wakeup_thread(fsg);
1246 + spin_unlock(&fsg->lock);
1247 +}
1248 +
1249 +#else
1250 +static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
1251 +{}
1252 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
1253 +
1254 +
1255 +/*-------------------------------------------------------------------------*/
1256 +
1257 +/* Ep0 class-specific handlers. These always run in_irq. */
1258 +
1259 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
1260 +static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
1261 +{
1262 + struct usb_request *req = fsg->ep0req;
1263 + static u8 cbi_reset_cmnd[6] = {
1264 + SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff};
1265 +
1266 + /* Error in command transfer? */
1267 + if (req->status || req->length != req->actual ||
1268 + req->actual < 6 || req->actual > MAX_COMMAND_SIZE) {
1269 +
1270 + /* Not all controllers allow a protocol stall after
1271 + * receiving control-out data, but we'll try anyway. */
1272 + fsg_set_halt(fsg, fsg->ep0);
1273 + return; // Wait for reset
1274 + }
1275 +
1276 + /* Is it the special reset command? */
1277 + if (req->actual >= sizeof cbi_reset_cmnd &&
1278 + memcmp(req->buf, cbi_reset_cmnd,
1279 + sizeof cbi_reset_cmnd) == 0) {
1280 +
1281 + /* Raise an exception to stop the current operation
1282 + * and reinitialize our state. */
1283 + DBG(fsg, "cbi reset request\n");
1284 + raise_exception(fsg, FSG_STATE_RESET);
1285 + return;
1286 + }
1287 +
1288 + VDBG(fsg, "CB[I] accept device-specific command\n");
1289 + spin_lock(&fsg->lock);
1290 +
1291 + /* Save the command for later */
1292 + if (fsg->cbbuf_cmnd_size)
1293 + WARNING(fsg, "CB[I] overwriting previous command\n");
1294 + fsg->cbbuf_cmnd_size = req->actual;
1295 + memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size);
1296 +
1297 + wakeup_thread(fsg);
1298 + spin_unlock(&fsg->lock);
1299 +}
1300 +
1301 +#else
1302 +static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
1303 +{}
1304 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
1305 +
1306 +
1307 +static int class_setup_req(struct fsg_dev *fsg,
1308 + const struct usb_ctrlrequest *ctrl)
1309 +{
1310 + struct usb_request *req = fsg->ep0req;
1311 + int value = -EOPNOTSUPP;
1312 + u16 w_index = le16_to_cpu(ctrl->wIndex);
1313 + u16 w_value = le16_to_cpu(ctrl->wValue);
1314 + u16 w_length = le16_to_cpu(ctrl->wLength);
1315 +
1316 + if (!fsg->config)
1317 + return value;
1318 +
1319 + /* Handle Bulk-only class-specific requests */
1320 + if (transport_is_bbb()) {
1321 + switch (ctrl->bRequest) {
1322 +
1323 + case US_BULK_RESET_REQUEST:
1324 + if (ctrl->bRequestType != (USB_DIR_OUT |
1325 + USB_TYPE_CLASS | USB_RECIP_INTERFACE))
1326 + break;
1327 + if (w_index != 0 || w_value != 0 || w_length != 0) {
1328 + value = -EDOM;
1329 + break;
1330 + }
1331 +
1332 + /* Raise an exception to stop the current operation
1333 + * and reinitialize our state. */
1334 + DBG(fsg, "bulk reset request\n");
1335 + raise_exception(fsg, FSG_STATE_RESET);
1336 + value = DELAYED_STATUS;
1337 + break;
1338 +
1339 + case US_BULK_GET_MAX_LUN:
1340 + if (ctrl->bRequestType != (USB_DIR_IN |
1341 + USB_TYPE_CLASS | USB_RECIP_INTERFACE))
1342 + break;
1343 + if (w_index != 0 || w_value != 0 || w_length != 1) {
1344 + value = -EDOM;
1345 + break;
1346 + }
1347 + VDBG(fsg, "get max LUN\n");
1348 + *(u8 *) req->buf = fsg->nluns - 1;
1349 + value = 1;
1350 + break;
1351 + }
1352 + }
1353 +
1354 + /* Handle CBI class-specific requests */
1355 + else {
1356 + switch (ctrl->bRequest) {
1357 +
1358 + case USB_CBI_ADSC_REQUEST:
1359 + if (ctrl->bRequestType != (USB_DIR_OUT |
1360 + USB_TYPE_CLASS | USB_RECIP_INTERFACE))
1361 + break;
1362 + if (w_index != 0 || w_value != 0) {
1363 + value = -EDOM;
1364 + break;
1365 + }
1366 + if (w_length > MAX_COMMAND_SIZE) {
1367 + value = -EOVERFLOW;
1368 + break;
1369 + }
1370 + value = w_length;
1371 + fsg->ep0req->context = received_cbi_adsc;
1372 + break;
1373 + }
1374 + }
1375 +
1376 + if (value == -EOPNOTSUPP)
1377 + VDBG(fsg,
1378 + "unknown class-specific control req "
1379 + "%02x.%02x v%04x i%04x l%u\n",
1380 + ctrl->bRequestType, ctrl->bRequest,
1381 + le16_to_cpu(ctrl->wValue), w_index, w_length);
1382 + return value;
1383 +}
1384 +
1385 +
1386 +/*-------------------------------------------------------------------------*/
1387 +
1388 +/* Ep0 standard request handlers. These always run in_irq. */
1389 +
1390 +static int standard_setup_req(struct fsg_dev *fsg,
1391 + const struct usb_ctrlrequest *ctrl)
1392 +{
1393 + struct usb_request *req = fsg->ep0req;
1394 + int value = -EOPNOTSUPP;
1395 + u16 w_index = le16_to_cpu(ctrl->wIndex);
1396 + u16 w_value = le16_to_cpu(ctrl->wValue);
1397 +
1398 + /* Usually this just stores reply data in the pre-allocated ep0 buffer,
1399 + * but config change events will also reconfigure hardware. */
1400 + switch (ctrl->bRequest) {
1401 +
1402 + case USB_REQ_GET_DESCRIPTOR:
1403 + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
1404 + USB_RECIP_DEVICE))
1405 + break;
1406 + switch (w_value >> 8) {
1407 +
1408 + case USB_DT_DEVICE:
1409 + VDBG(fsg, "get device descriptor\n");
1410 + device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
1411 + value = sizeof device_desc;
1412 + memcpy(req->buf, &device_desc, value);
1413 + break;
1414 + case USB_DT_DEVICE_QUALIFIER:
1415 + VDBG(fsg, "get device qualifier\n");
1416 + if (!gadget_is_dualspeed(fsg->gadget) ||
1417 + fsg->gadget->speed == USB_SPEED_SUPER)
1418 + break;
1419 + /*
1420 + * Assume ep0 uses the same maxpacket value for both
1421 + * speeds
1422 + */
1423 + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
1424 + value = sizeof dev_qualifier;
1425 + memcpy(req->buf, &dev_qualifier, value);
1426 + break;
1427 +
1428 + case USB_DT_OTHER_SPEED_CONFIG:
1429 + VDBG(fsg, "get other-speed config descriptor\n");
1430 + if (!gadget_is_dualspeed(fsg->gadget) ||
1431 + fsg->gadget->speed == USB_SPEED_SUPER)
1432 + break;
1433 + goto get_config;
1434 + case USB_DT_CONFIG:
1435 + VDBG(fsg, "get configuration descriptor\n");
1436 +get_config:
1437 + value = populate_config_buf(fsg->gadget,
1438 + req->buf,
1439 + w_value >> 8,
1440 + w_value & 0xff);
1441 + break;
1442 +
1443 + case USB_DT_STRING:
1444 + VDBG(fsg, "get string descriptor\n");
1445 +
1446 + /* wIndex == language code */
1447 + value = usb_gadget_get_string(&fsg_stringtab,
1448 + w_value & 0xff, req->buf);
1449 + break;
1450 +
1451 + case USB_DT_BOS:
1452 + VDBG(fsg, "get bos descriptor\n");
1453 +
1454 + if (gadget_is_superspeed(fsg->gadget))
1455 + value = populate_bos(fsg, req->buf);
1456 + break;
1457 + }
1458 +
1459 + break;
1460 +
1461 + /* One config, two speeds */
1462 + case USB_REQ_SET_CONFIGURATION:
1463 + if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
1464 + USB_RECIP_DEVICE))
1465 + break;
1466 + VDBG(fsg, "set configuration\n");
1467 + if (w_value == CONFIG_VALUE || w_value == 0) {
1468 + fsg->new_config = w_value;
1469 +
1470 + /* Raise an exception to wipe out previous transaction
1471 + * state (queued bufs, etc) and set the new config. */
1472 + raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
1473 + value = DELAYED_STATUS;
1474 + }
1475 + break;
1476 + case USB_REQ_GET_CONFIGURATION:
1477 + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
1478 + USB_RECIP_DEVICE))
1479 + break;
1480 + VDBG(fsg, "get configuration\n");
1481 + *(u8 *) req->buf = fsg->config;
1482 + value = 1;
1483 + break;
1484 +
1485 + case USB_REQ_SET_INTERFACE:
1486 + if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD |
1487 + USB_RECIP_INTERFACE))
1488 + break;
1489 + if (fsg->config && w_index == 0) {
1490 +
1491 + /* Raise an exception to wipe out previous transaction
1492 + * state (queued bufs, etc) and install the new
1493 + * interface altsetting. */
1494 + raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE);
1495 + value = DELAYED_STATUS;
1496 + }
1497 + break;
1498 + case USB_REQ_GET_INTERFACE:
1499 + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
1500 + USB_RECIP_INTERFACE))
1501 + break;
1502 + if (!fsg->config)
1503 + break;
1504 + if (w_index != 0) {
1505 + value = -EDOM;
1506 + break;
1507 + }
1508 + VDBG(fsg, "get interface\n");
1509 + *(u8 *) req->buf = 0;
1510 + value = 1;
1511 + break;
1512 +
1513 + default:
1514 + VDBG(fsg,
1515 + "unknown control req %02x.%02x v%04x i%04x l%u\n",
1516 + ctrl->bRequestType, ctrl->bRequest,
1517 + w_value, w_index, le16_to_cpu(ctrl->wLength));
1518 + }
1519 +
1520 + return value;
1521 +}
1522 +
1523 +
1524 +static int fsg_setup(struct usb_gadget *gadget,
1525 + const struct usb_ctrlrequest *ctrl)
1526 +{
1527 + struct fsg_dev *fsg = get_gadget_data(gadget);
1528 + int rc;
1529 + int w_length = le16_to_cpu(ctrl->wLength);
1530 +
1531 + ++fsg->ep0_req_tag; // Record arrival of a new request
1532 + fsg->ep0req->context = NULL;
1533 + fsg->ep0req->length = 0;
1534 + dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
1535 +
1536 + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
1537 + rc = class_setup_req(fsg, ctrl);
1538 + else
1539 + rc = standard_setup_req(fsg, ctrl);
1540 +
1541 + /* Respond with data/status or defer until later? */
1542 + if (rc >= 0 && rc != DELAYED_STATUS) {
1543 + rc = min(rc, w_length);
1544 + fsg->ep0req->length = rc;
1545 + fsg->ep0req->zero = rc < w_length;
1546 + fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
1547 + "ep0-in" : "ep0-out");
1548 + rc = ep0_queue(fsg);
1549 + }
1550 +
1551 + /* Device either stalls (rc < 0) or reports success */
1552 + return rc;
1553 +}
1554 +
1555 +
1556 +/*-------------------------------------------------------------------------*/
1557 +
1558 +/* All the following routines run in process context */
1559 +
1560 +
1561 +/* Use this for bulk or interrupt transfers, not ep0 */
1562 +static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
1563 + struct usb_request *req, int *pbusy,
1564 + enum fsg_buffer_state *state)
1565 +{
1566 + int rc;
1567 +
1568 + if (ep == fsg->bulk_in)
1569 + dump_msg(fsg, "bulk-in", req->buf, req->length);
1570 + else if (ep == fsg->intr_in)
1571 + dump_msg(fsg, "intr-in", req->buf, req->length);
1572 +
1573 + spin_lock_irq(&fsg->lock);
1574 + *pbusy = 1;
1575 + *state = BUF_STATE_BUSY;
1576 + spin_unlock_irq(&fsg->lock);
1577 + rc = usb_ep_queue(ep, req, GFP_KERNEL);
1578 + if (rc != 0) {
1579 + *pbusy = 0;
1580 + *state = BUF_STATE_EMPTY;
1581 +
1582 + /* We can't do much more than wait for a reset */
1583 +
1584 + /* Note: currently the net2280 driver fails zero-length
1585 + * submissions if DMA is enabled. */
1586 + if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP &&
1587 + req->length == 0))
1588 + WARNING(fsg, "error in submission: %s --> %d\n",
1589 + ep->name, rc);
1590 + }
1591 +}
1592 +
1593 +
1594 +static int sleep_thread(struct fsg_dev *fsg)
1595 +{
1596 + int rc = 0;
1597 +
1598 + /* Wait until a signal arrives or we are woken up */
1599 + for (;;) {
1600 + try_to_freeze();
1601 + set_current_state(TASK_INTERRUPTIBLE);
1602 + if (signal_pending(current)) {
1603 + rc = -EINTR;
1604 + break;
1605 + }
1606 + if (fsg->thread_wakeup_needed)
1607 + break;
1608 + schedule();
1609 + }
1610 + __set_current_state(TASK_RUNNING);
1611 + fsg->thread_wakeup_needed = 0;
1612 + return rc;
1613 +}
1614 +
1615 +
1616 +/*-------------------------------------------------------------------------*/
1617 +
1618 +static int do_read(struct fsg_dev *fsg)
1619 +{
1620 + struct fsg_lun *curlun = fsg->curlun;
1621 + u32 lba;
1622 + struct fsg_buffhd *bh;
1623 + int rc;
1624 + u32 amount_left;
1625 + loff_t file_offset, file_offset_tmp;
1626 + unsigned int amount;
1627 + ssize_t nread;
1628 +
1629 + /* Get the starting Logical Block Address and check that it's
1630 + * not too big */
1631 + if (fsg->cmnd[0] == READ_6)
1632 + lba = get_unaligned_be24(&fsg->cmnd[1]);
1633 + else {
1634 + lba = get_unaligned_be32(&fsg->cmnd[2]);
1635 +
1636 + /* We allow DPO (Disable Page Out = don't save data in the
1637 + * cache) and FUA (Force Unit Access = don't read from the
1638 + * cache), but we don't implement them. */
1639 + if ((fsg->cmnd[1] & ~0x18) != 0) {
1640 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1641 + return -EINVAL;
1642 + }
1643 + }
1644 + if (lba >= curlun->num_sectors) {
1645 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1646 + return -EINVAL;
1647 + }
1648 + file_offset = ((loff_t) lba) << curlun->blkbits;
1649 +
1650 + /* Carry out the file reads */
1651 + amount_left = fsg->data_size_from_cmnd;
1652 + if (unlikely(amount_left == 0))
1653 + return -EIO; // No default reply
1654 +
1655 + for (;;) {
1656 +
1657 + /* Figure out how much we need to read:
1658 + * Try to read the remaining amount.
1659 + * But don't read more than the buffer size.
1660 + * And don't try to read past the end of the file.
1661 + */
1662 + amount = min((unsigned int) amount_left, mod_data.buflen);
1663 + amount = min((loff_t) amount,
1664 + curlun->file_length - file_offset);
1665 +
1666 + /* Wait for the next buffer to become available */
1667 + bh = fsg->next_buffhd_to_fill;
1668 + while (bh->state != BUF_STATE_EMPTY) {
1669 + rc = sleep_thread(fsg);
1670 + if (rc)
1671 + return rc;
1672 + }
1673 +
1674 + /* If we were asked to read past the end of file,
1675 + * end with an empty buffer. */
1676 + if (amount == 0) {
1677 + curlun->sense_data =
1678 + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1679 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1680 + curlun->info_valid = 1;
1681 + bh->inreq->length = 0;
1682 + bh->state = BUF_STATE_FULL;
1683 + break;
1684 + }
1685 +
1686 + /* Perform the read */
1687 + file_offset_tmp = file_offset;
1688 + nread = vfs_read(curlun->filp,
1689 + (char __user *) bh->buf,
1690 + amount, &file_offset_tmp);
1691 + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
1692 + (unsigned long long) file_offset,
1693 + (int) nread);
1694 + if (signal_pending(current))
1695 + return -EINTR;
1696 +
1697 + if (nread < 0) {
1698 + LDBG(curlun, "error in file read: %d\n",
1699 + (int) nread);
1700 + nread = 0;
1701 + } else if (nread < amount) {
1702 + LDBG(curlun, "partial file read: %d/%u\n",
1703 + (int) nread, amount);
1704 + nread = round_down(nread, curlun->blksize);
1705 + }
1706 + file_offset += nread;
1707 + amount_left -= nread;
1708 + fsg->residue -= nread;
1709 +
1710 + /* Except at the end of the transfer, nread will be
1711 + * equal to the buffer size, which is divisible by the
1712 + * bulk-in maxpacket size.
1713 + */
1714 + bh->inreq->length = nread;
1715 + bh->state = BUF_STATE_FULL;
1716 +
1717 + /* If an error occurred, report it and its position */
1718 + if (nread < amount) {
1719 + curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
1720 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1721 + curlun->info_valid = 1;
1722 + break;
1723 + }
1724 +
1725 + if (amount_left == 0)
1726 + break; // No more left to read
1727 +
1728 + /* Send this buffer and go read some more */
1729 + bh->inreq->zero = 0;
1730 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
1731 + &bh->inreq_busy, &bh->state);
1732 + fsg->next_buffhd_to_fill = bh->next;
1733 + }
1734 +
1735 + return -EIO; // No default reply
1736 +}
1737 +
1738 +
1739 +/*-------------------------------------------------------------------------*/
1740 +
1741 +static int do_write(struct fsg_dev *fsg)
1742 +{
1743 + struct fsg_lun *curlun = fsg->curlun;
1744 + u32 lba;
1745 + struct fsg_buffhd *bh;
1746 + int get_some_more;
1747 + u32 amount_left_to_req, amount_left_to_write;
1748 + loff_t usb_offset, file_offset, file_offset_tmp;
1749 + unsigned int amount;
1750 + ssize_t nwritten;
1751 + int rc;
1752 +
1753 + if (curlun->ro) {
1754 + curlun->sense_data = SS_WRITE_PROTECTED;
1755 + return -EINVAL;
1756 + }
1757 + spin_lock(&curlun->filp->f_lock);
1758 + curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait
1759 + spin_unlock(&curlun->filp->f_lock);
1760 +
1761 + /* Get the starting Logical Block Address and check that it's
1762 + * not too big */
1763 + if (fsg->cmnd[0] == WRITE_6)
1764 + lba = get_unaligned_be24(&fsg->cmnd[1]);
1765 + else {
1766 + lba = get_unaligned_be32(&fsg->cmnd[2]);
1767 +
1768 + /* We allow DPO (Disable Page Out = don't save data in the
1769 + * cache) and FUA (Force Unit Access = write directly to the
1770 + * medium). We don't implement DPO; we implement FUA by
1771 + * performing synchronous output. */
1772 + if ((fsg->cmnd[1] & ~0x18) != 0) {
1773 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1774 + return -EINVAL;
1775 + }
1776 + /* FUA */
1777 + if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) {
1778 + spin_lock(&curlun->filp->f_lock);
1779 + curlun->filp->f_flags |= O_DSYNC;
1780 + spin_unlock(&curlun->filp->f_lock);
1781 + }
1782 + }
1783 + if (lba >= curlun->num_sectors) {
1784 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1785 + return -EINVAL;
1786 + }
1787 +
1788 + /* Carry out the file writes */
1789 + get_some_more = 1;
1790 + file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
1791 + amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
1792 +
1793 + while (amount_left_to_write > 0) {
1794 +
1795 + /* Queue a request for more data from the host */
1796 + bh = fsg->next_buffhd_to_fill;
1797 + if (bh->state == BUF_STATE_EMPTY && get_some_more) {
1798 +
1799 + /* Figure out how much we want to get:
1800 + * Try to get the remaining amount,
1801 + * but not more than the buffer size.
1802 + */
1803 + amount = min(amount_left_to_req, mod_data.buflen);
1804 +
1805 + /* Beyond the end of the backing file? */
1806 + if (usb_offset >= curlun->file_length) {
1807 + get_some_more = 0;
1808 + curlun->sense_data =
1809 + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1810 + curlun->sense_data_info = usb_offset >> curlun->blkbits;
1811 + curlun->info_valid = 1;
1812 + continue;
1813 + }
1814 +
1815 + /* Get the next buffer */
1816 + usb_offset += amount;
1817 + fsg->usb_amount_left -= amount;
1818 + amount_left_to_req -= amount;
1819 + if (amount_left_to_req == 0)
1820 + get_some_more = 0;
1821 +
1822 + /* Except at the end of the transfer, amount will be
1823 + * equal to the buffer size, which is divisible by
1824 + * the bulk-out maxpacket size.
1825 + */
1826 + set_bulk_out_req_length(fsg, bh, amount);
1827 + start_transfer(fsg, fsg->bulk_out, bh->outreq,
1828 + &bh->outreq_busy, &bh->state);
1829 + fsg->next_buffhd_to_fill = bh->next;
1830 + continue;
1831 + }
1832 +
1833 + /* Write the received data to the backing file */
1834 + bh = fsg->next_buffhd_to_drain;
1835 + if (bh->state == BUF_STATE_EMPTY && !get_some_more)
1836 + break; // We stopped early
1837 + if (bh->state == BUF_STATE_FULL) {
1838 + smp_rmb();
1839 + fsg->next_buffhd_to_drain = bh->next;
1840 + bh->state = BUF_STATE_EMPTY;
1841 +
1842 + /* Did something go wrong with the transfer? */
1843 + if (bh->outreq->status != 0) {
1844 + curlun->sense_data = SS_COMMUNICATION_FAILURE;
1845 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1846 + curlun->info_valid = 1;
1847 + break;
1848 + }
1849 +
1850 + amount = bh->outreq->actual;
1851 + if (curlun->file_length - file_offset < amount) {
1852 + LERROR(curlun,
1853 + "write %u @ %llu beyond end %llu\n",
1854 + amount, (unsigned long long) file_offset,
1855 + (unsigned long long) curlun->file_length);
1856 + amount = curlun->file_length - file_offset;
1857 + }
1858 +
1859 + /* Don't accept excess data. The spec doesn't say
1860 + * what to do in this case. We'll ignore the error.
1861 + */
1862 + amount = min(amount, bh->bulk_out_intended_length);
1863 +
1864 + /* Don't write a partial block */
1865 + amount = round_down(amount, curlun->blksize);
1866 + if (amount == 0)
1867 + goto empty_write;
1868 +
1869 + /* Perform the write */
1870 + file_offset_tmp = file_offset;
1871 + nwritten = vfs_write(curlun->filp,
1872 + (char __user *) bh->buf,
1873 + amount, &file_offset_tmp);
1874 + VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
1875 + (unsigned long long) file_offset,
1876 + (int) nwritten);
1877 + if (signal_pending(current))
1878 + return -EINTR; // Interrupted!
1879 +
1880 + if (nwritten < 0) {
1881 + LDBG(curlun, "error in file write: %d\n",
1882 + (int) nwritten);
1883 + nwritten = 0;
1884 + } else if (nwritten < amount) {
1885 + LDBG(curlun, "partial file write: %d/%u\n",
1886 + (int) nwritten, amount);
1887 + nwritten = round_down(nwritten, curlun->blksize);
1888 + }
1889 + file_offset += nwritten;
1890 + amount_left_to_write -= nwritten;
1891 + fsg->residue -= nwritten;
1892 +
1893 + /* If an error occurred, report it and its position */
1894 + if (nwritten < amount) {
1895 + curlun->sense_data = SS_WRITE_ERROR;
1896 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1897 + curlun->info_valid = 1;
1898 + break;
1899 + }
1900 +
1901 + empty_write:
1902 + /* Did the host decide to stop early? */
1903 + if (bh->outreq->actual < bh->bulk_out_intended_length) {
1904 + fsg->short_packet_received = 1;
1905 + break;
1906 + }
1907 + continue;
1908 + }
1909 +
1910 + /* Wait for something to happen */
1911 + rc = sleep_thread(fsg);
1912 + if (rc)
1913 + return rc;
1914 + }
1915 +
1916 + return -EIO; // No default reply
1917 +}
1918 +
1919 +
1920 +/*-------------------------------------------------------------------------*/
1921 +
1922 +static int do_synchronize_cache(struct fsg_dev *fsg)
1923 +{
1924 + struct fsg_lun *curlun = fsg->curlun;
1925 + int rc;
1926 +
1927 + /* We ignore the requested LBA and write out all file's
1928 + * dirty data buffers. */
1929 + rc = fsg_lun_fsync_sub(curlun);
1930 + if (rc)
1931 + curlun->sense_data = SS_WRITE_ERROR;
1932 + return 0;
1933 +}
1934 +
1935 +
1936 +/*-------------------------------------------------------------------------*/
1937 +
1938 +static void invalidate_sub(struct fsg_lun *curlun)
1939 +{
1940 + struct file *filp = curlun->filp;
1941 + struct inode *inode = filp->f_path.dentry->d_inode;
1942 + unsigned long rc;
1943 +
1944 + rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
1945 + VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
1946 +}
1947 +
1948 +static int do_verify(struct fsg_dev *fsg)
1949 +{
1950 + struct fsg_lun *curlun = fsg->curlun;
1951 + u32 lba;
1952 + u32 verification_length;
1953 + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
1954 + loff_t file_offset, file_offset_tmp;
1955 + u32 amount_left;
1956 + unsigned int amount;
1957 + ssize_t nread;
1958 +
1959 + /* Get the starting Logical Block Address and check that it's
1960 + * not too big */
1961 + lba = get_unaligned_be32(&fsg->cmnd[2]);
1962 + if (lba >= curlun->num_sectors) {
1963 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1964 + return -EINVAL;
1965 + }
1966 +
1967 + /* We allow DPO (Disable Page Out = don't save data in the
1968 + * cache) but we don't implement it. */
1969 + if ((fsg->cmnd[1] & ~0x10) != 0) {
1970 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1971 + return -EINVAL;
1972 + }
1973 +
1974 + verification_length = get_unaligned_be16(&fsg->cmnd[7]);
1975 + if (unlikely(verification_length == 0))
1976 + return -EIO; // No default reply
1977 +
1978 + /* Prepare to carry out the file verify */
1979 + amount_left = verification_length << curlun->blkbits;
1980 + file_offset = ((loff_t) lba) << curlun->blkbits;
1981 +
1982 + /* Write out all the dirty buffers before invalidating them */
1983 + fsg_lun_fsync_sub(curlun);
1984 + if (signal_pending(current))
1985 + return -EINTR;
1986 +
1987 + invalidate_sub(curlun);
1988 + if (signal_pending(current))
1989 + return -EINTR;
1990 +
1991 + /* Just try to read the requested blocks */
1992 + while (amount_left > 0) {
1993 +
1994 + /* Figure out how much we need to read:
1995 + * Try to read the remaining amount, but not more than
1996 + * the buffer size.
1997 + * And don't try to read past the end of the file.
1998 + */
1999 + amount = min((unsigned int) amount_left, mod_data.buflen);
2000 + amount = min((loff_t) amount,
2001 + curlun->file_length - file_offset);
2002 + if (amount == 0) {
2003 + curlun->sense_data =
2004 + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
2005 + curlun->sense_data_info = file_offset >> curlun->blkbits;
2006 + curlun->info_valid = 1;
2007 + break;
2008 + }
2009 +
2010 + /* Perform the read */
2011 + file_offset_tmp = file_offset;
2012 + nread = vfs_read(curlun->filp,
2013 + (char __user *) bh->buf,
2014 + amount, &file_offset_tmp);
2015 + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
2016 + (unsigned long long) file_offset,
2017 + (int) nread);
2018 + if (signal_pending(current))
2019 + return -EINTR;
2020 +
2021 + if (nread < 0) {
2022 + LDBG(curlun, "error in file verify: %d\n",
2023 + (int) nread);
2024 + nread = 0;
2025 + } else if (nread < amount) {
2026 + LDBG(curlun, "partial file verify: %d/%u\n",
2027 + (int) nread, amount);
2028 + nread = round_down(nread, curlun->blksize);
2029 + }
2030 + if (nread == 0) {
2031 + curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
2032 + curlun->sense_data_info = file_offset >> curlun->blkbits;
2033 + curlun->info_valid = 1;
2034 + break;
2035 + }
2036 + file_offset += nread;
2037 + amount_left -= nread;
2038 + }
2039 + return 0;
2040 +}
2041 +
2042 +
2043 +/*-------------------------------------------------------------------------*/
2044 +
2045 +static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2046 +{
2047 + u8 *buf = (u8 *) bh->buf;
2048 +
2049 + static char vendor_id[] = "Linux ";
2050 + static char product_disk_id[] = "File-Stor Gadget";
2051 + static char product_cdrom_id[] = "File-CD Gadget ";
2052 +
2053 + if (!fsg->curlun) { // Unsupported LUNs are okay
2054 + fsg->bad_lun_okay = 1;
2055 + memset(buf, 0, 36);
2056 + buf[0] = 0x7f; // Unsupported, no device-type
2057 + buf[4] = 31; // Additional length
2058 + return 36;
2059 + }
2060 +
2061 + memset(buf, 0, 8);
2062 + buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK);
2063 + if (mod_data.removable)
2064 + buf[1] = 0x80;
2065 + buf[2] = 2; // ANSI SCSI level 2
2066 + buf[3] = 2; // SCSI-2 INQUIRY data format
2067 + buf[4] = 31; // Additional length
2068 + // No special options
2069 + sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
2070 + (mod_data.cdrom ? product_cdrom_id :
2071 + product_disk_id),
2072 + mod_data.release);
2073 + return 36;
2074 +}
2075 +
2076 +
2077 +static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2078 +{
2079 + struct fsg_lun *curlun = fsg->curlun;
2080 + u8 *buf = (u8 *) bh->buf;
2081 + u32 sd, sdinfo;
2082 + int valid;
2083 +
2084 + /*
2085 + * From the SCSI-2 spec., section 7.9 (Unit attention condition):
2086 + *
2087 + * If a REQUEST SENSE command is received from an initiator
2088 + * with a pending unit attention condition (before the target
2089 + * generates the contingent allegiance condition), then the
2090 + * target shall either:
2091 + * a) report any pending sense data and preserve the unit
2092 + * attention condition on the logical unit, or,
2093 + * b) report the unit attention condition, may discard any
2094 + * pending sense data, and clear the unit attention
2095 + * condition on the logical unit for that initiator.
2096 + *
2097 + * FSG normally uses option a); enable this code to use option b).
2098 + */
2099 +#if 0
2100 + if (curlun && curlun->unit_attention_data != SS_NO_SENSE) {
2101 + curlun->sense_data = curlun->unit_attention_data;
2102 + curlun->unit_attention_data = SS_NO_SENSE;
2103 + }
2104 +#endif
2105 +
2106 + if (!curlun) { // Unsupported LUNs are okay
2107 + fsg->bad_lun_okay = 1;
2108 + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
2109 + sdinfo = 0;
2110 + valid = 0;
2111 + } else {
2112 + sd = curlun->sense_data;
2113 + sdinfo = curlun->sense_data_info;
2114 + valid = curlun->info_valid << 7;
2115 + curlun->sense_data = SS_NO_SENSE;
2116 + curlun->sense_data_info = 0;
2117 + curlun->info_valid = 0;
2118 + }
2119 +
2120 + memset(buf, 0, 18);
2121 + buf[0] = valid | 0x70; // Valid, current error
2122 + buf[2] = SK(sd);
2123 + put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */
2124 + buf[7] = 18 - 8; // Additional sense length
2125 + buf[12] = ASC(sd);
2126 + buf[13] = ASCQ(sd);
2127 + return 18;
2128 +}
2129 +
2130 +
2131 +static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2132 +{
2133 + struct fsg_lun *curlun = fsg->curlun;
2134 + u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
2135 + int pmi = fsg->cmnd[8];
2136 + u8 *buf = (u8 *) bh->buf;
2137 +
2138 + /* Check the PMI and LBA fields */
2139 + if (pmi > 1 || (pmi == 0 && lba != 0)) {
2140 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2141 + return -EINVAL;
2142 + }
2143 +
2144 + put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
2145 + /* Max logical block */
2146 + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
2147 + return 8;
2148 +}
2149 +
2150 +
2151 +static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2152 +{
2153 + struct fsg_lun *curlun = fsg->curlun;
2154 + int msf = fsg->cmnd[1] & 0x02;
2155 + u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
2156 + u8 *buf = (u8 *) bh->buf;
2157 +
2158 + if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */
2159 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2160 + return -EINVAL;
2161 + }
2162 + if (lba >= curlun->num_sectors) {
2163 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
2164 + return -EINVAL;
2165 + }
2166 +
2167 + memset(buf, 0, 8);
2168 + buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */
2169 + store_cdrom_address(&buf[4], msf, lba);
2170 + return 8;
2171 +}
2172 +
2173 +
2174 +static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2175 +{
2176 + struct fsg_lun *curlun = fsg->curlun;
2177 + int msf = fsg->cmnd[1] & 0x02;
2178 + int start_track = fsg->cmnd[6];
2179 + u8 *buf = (u8 *) bh->buf;
2180 +
2181 + if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
2182 + start_track > 1) {
2183 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2184 + return -EINVAL;
2185 + }
2186 +
2187 + memset(buf, 0, 20);
2188 + buf[1] = (20-2); /* TOC data length */
2189 + buf[2] = 1; /* First track number */
2190 + buf[3] = 1; /* Last track number */
2191 + buf[5] = 0x16; /* Data track, copying allowed */
2192 + buf[6] = 0x01; /* Only track is number 1 */
2193 + store_cdrom_address(&buf[8], msf, 0);
2194 +
2195 + buf[13] = 0x16; /* Lead-out track is data */
2196 + buf[14] = 0xAA; /* Lead-out track number */
2197 + store_cdrom_address(&buf[16], msf, curlun->num_sectors);
2198 + return 20;
2199 +}
2200 +
2201 +
2202 +static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2203 +{
2204 + struct fsg_lun *curlun = fsg->curlun;
2205 + int mscmnd = fsg->cmnd[0];
2206 + u8 *buf = (u8 *) bh->buf;
2207 + u8 *buf0 = buf;
2208 + int pc, page_code;
2209 + int changeable_values, all_pages;
2210 + int valid_page = 0;
2211 + int len, limit;
2212 +
2213 + if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD
2214 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2215 + return -EINVAL;
2216 + }
2217 + pc = fsg->cmnd[2] >> 6;
2218 + page_code = fsg->cmnd[2] & 0x3f;
2219 + if (pc == 3) {
2220 + curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
2221 + return -EINVAL;
2222 + }
2223 + changeable_values = (pc == 1);
2224 + all_pages = (page_code == 0x3f);
2225 +
2226 + /* Write the mode parameter header. Fixed values are: default
2227 + * medium type, no cache control (DPOFUA), and no block descriptors.
2228 + * The only variable value is the WriteProtect bit. We will fill in
2229 + * the mode data length later. */
2230 + memset(buf, 0, 8);
2231 + if (mscmnd == MODE_SENSE) {
2232 + buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
2233 + buf += 4;
2234 + limit = 255;
2235 + } else { // MODE_SENSE_10
2236 + buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
2237 + buf += 8;
2238 + limit = 65535; // Should really be mod_data.buflen
2239 + }
2240 +
2241 + /* No block descriptors */
2242 +
2243 + /* The mode pages, in numerical order. The only page we support
2244 + * is the Caching page. */
2245 + if (page_code == 0x08 || all_pages) {
2246 + valid_page = 1;
2247 + buf[0] = 0x08; // Page code
2248 + buf[1] = 10; // Page length
2249 + memset(buf+2, 0, 10); // None of the fields are changeable
2250 +
2251 + if (!changeable_values) {
2252 + buf[2] = 0x04; // Write cache enable,
2253 + // Read cache not disabled
2254 + // No cache retention priorities
2255 + put_unaligned_be16(0xffff, &buf[4]);
2256 + /* Don't disable prefetch */
2257 + /* Minimum prefetch = 0 */
2258 + put_unaligned_be16(0xffff, &buf[8]);
2259 + /* Maximum prefetch */
2260 + put_unaligned_be16(0xffff, &buf[10]);
2261 + /* Maximum prefetch ceiling */
2262 + }
2263 + buf += 12;
2264 + }
2265 +
2266 + /* Check that a valid page was requested and the mode data length
2267 + * isn't too long. */
2268 + len = buf - buf0;
2269 + if (!valid_page || len > limit) {
2270 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2271 + return -EINVAL;
2272 + }
2273 +
2274 + /* Store the mode data length */
2275 + if (mscmnd == MODE_SENSE)
2276 + buf0[0] = len - 1;
2277 + else
2278 + put_unaligned_be16(len - 2, buf0);
2279 + return len;
2280 +}
2281 +
2282 +
2283 +static int do_start_stop(struct fsg_dev *fsg)
2284 +{
2285 + struct fsg_lun *curlun = fsg->curlun;
2286 + int loej, start;
2287 +
2288 + if (!mod_data.removable) {
2289 + curlun->sense_data = SS_INVALID_COMMAND;
2290 + return -EINVAL;
2291 + }
2292 +
2293 + // int immed = fsg->cmnd[1] & 0x01;
2294 + loej = fsg->cmnd[4] & 0x02;
2295 + start = fsg->cmnd[4] & 0x01;
2296 +
2297 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
2298 + if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed
2299 + (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start
2300 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2301 + return -EINVAL;
2302 + }
2303 +
2304 + if (!start) {
2305 +
2306 + /* Are we allowed to unload the media? */
2307 + if (curlun->prevent_medium_removal) {
2308 + LDBG(curlun, "unload attempt prevented\n");
2309 + curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
2310 + return -EINVAL;
2311 + }
2312 + if (loej) { // Simulate an unload/eject
2313 + up_read(&fsg->filesem);
2314 + down_write(&fsg->filesem);
2315 + fsg_lun_close(curlun);
2316 + up_write(&fsg->filesem);
2317 + down_read(&fsg->filesem);
2318 + }
2319 + } else {
2320 +
2321 + /* Our emulation doesn't support mounting; the medium is
2322 + * available for use as soon as it is loaded. */
2323 + if (!fsg_lun_is_open(curlun)) {
2324 + curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
2325 + return -EINVAL;
2326 + }
2327 + }
2328 +#endif
2329 + return 0;
2330 +}
2331 +
2332 +
2333 +static int do_prevent_allow(struct fsg_dev *fsg)
2334 +{
2335 + struct fsg_lun *curlun = fsg->curlun;
2336 + int prevent;
2337 +
2338 + if (!mod_data.removable) {
2339 + curlun->sense_data = SS_INVALID_COMMAND;
2340 + return -EINVAL;
2341 + }
2342 +
2343 + prevent = fsg->cmnd[4] & 0x01;
2344 + if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent
2345 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2346 + return -EINVAL;
2347 + }
2348 +
2349 + if (curlun->prevent_medium_removal && !prevent)
2350 + fsg_lun_fsync_sub(curlun);
2351 + curlun->prevent_medium_removal = prevent;
2352 + return 0;
2353 +}
2354 +
2355 +
2356 +static int do_read_format_capacities(struct fsg_dev *fsg,
2357 + struct fsg_buffhd *bh)
2358 +{
2359 + struct fsg_lun *curlun = fsg->curlun;
2360 + u8 *buf = (u8 *) bh->buf;
2361 +
2362 + buf[0] = buf[1] = buf[2] = 0;
2363 + buf[3] = 8; // Only the Current/Maximum Capacity Descriptor
2364 + buf += 4;
2365 +
2366 + put_unaligned_be32(curlun->num_sectors, &buf[0]);
2367 + /* Number of blocks */
2368 + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
2369 + buf[4] = 0x02; /* Current capacity */
2370 + return 12;
2371 +}
2372 +
2373 +
2374 +static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2375 +{
2376 + struct fsg_lun *curlun = fsg->curlun;
2377 +
2378 + /* We don't support MODE SELECT */
2379 + curlun->sense_data = SS_INVALID_COMMAND;
2380 + return -EINVAL;
2381 +}
2382 +
2383 +
2384 +/*-------------------------------------------------------------------------*/
2385 +
2386 +static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
2387 +{
2388 + int rc;
2389 +
2390 + rc = fsg_set_halt(fsg, fsg->bulk_in);
2391 + if (rc == -EAGAIN)
2392 + VDBG(fsg, "delayed bulk-in endpoint halt\n");
2393 + while (rc != 0) {
2394 + if (rc != -EAGAIN) {
2395 + WARNING(fsg, "usb_ep_set_halt -> %d\n", rc);
2396 + rc = 0;
2397 + break;
2398 + }
2399 +
2400 + /* Wait for a short time and then try again */
2401 + if (msleep_interruptible(100) != 0)
2402 + return -EINTR;
2403 + rc = usb_ep_set_halt(fsg->bulk_in);
2404 + }
2405 + return rc;
2406 +}
2407 +
2408 +static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
2409 +{
2410 + int rc;
2411 +
2412 + DBG(fsg, "bulk-in set wedge\n");
2413 + rc = usb_ep_set_wedge(fsg->bulk_in);
2414 + if (rc == -EAGAIN)
2415 + VDBG(fsg, "delayed bulk-in endpoint wedge\n");
2416 + while (rc != 0) {
2417 + if (rc != -EAGAIN) {
2418 + WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc);
2419 + rc = 0;
2420 + break;
2421 + }
2422 +
2423 + /* Wait for a short time and then try again */
2424 + if (msleep_interruptible(100) != 0)
2425 + return -EINTR;
2426 + rc = usb_ep_set_wedge(fsg->bulk_in);
2427 + }
2428 + return rc;
2429 +}
2430 +
2431 +static int throw_away_data(struct fsg_dev *fsg)
2432 +{
2433 + struct fsg_buffhd *bh;
2434 + u32 amount;
2435 + int rc;
2436 +
2437 + while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY ||
2438 + fsg->usb_amount_left > 0) {
2439 +
2440 + /* Throw away the data in a filled buffer */
2441 + if (bh->state == BUF_STATE_FULL) {
2442 + smp_rmb();
2443 + bh->state = BUF_STATE_EMPTY;
2444 + fsg->next_buffhd_to_drain = bh->next;
2445 +
2446 + /* A short packet or an error ends everything */
2447 + if (bh->outreq->actual < bh->bulk_out_intended_length ||
2448 + bh->outreq->status != 0) {
2449 + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
2450 + return -EINTR;
2451 + }
2452 + continue;
2453 + }
2454 +
2455 + /* Try to submit another request if we need one */
2456 + bh = fsg->next_buffhd_to_fill;
2457 + if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) {
2458 + amount = min(fsg->usb_amount_left,
2459 + (u32) mod_data.buflen);
2460 +
2461 + /* Except at the end of the transfer, amount will be
2462 + * equal to the buffer size, which is divisible by
2463 + * the bulk-out maxpacket size.
2464 + */
2465 + set_bulk_out_req_length(fsg, bh, amount);
2466 + start_transfer(fsg, fsg->bulk_out, bh->outreq,
2467 + &bh->outreq_busy, &bh->state);
2468 + fsg->next_buffhd_to_fill = bh->next;
2469 + fsg->usb_amount_left -= amount;
2470 + continue;
2471 + }
2472 +
2473 + /* Otherwise wait for something to happen */
2474 + rc = sleep_thread(fsg);
2475 + if (rc)
2476 + return rc;
2477 + }
2478 + return 0;
2479 +}
2480 +
2481 +
2482 +static int finish_reply(struct fsg_dev *fsg)
2483 +{
2484 + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
2485 + int rc = 0;
2486 +
2487 + switch (fsg->data_dir) {
2488 + case DATA_DIR_NONE:
2489 + break; // Nothing to send
2490 +
2491 + /* If we don't know whether the host wants to read or write,
2492 + * this must be CB or CBI with an unknown command. We mustn't
2493 + * try to send or receive any data. So stall both bulk pipes
2494 + * if we can and wait for a reset. */
2495 + case DATA_DIR_UNKNOWN:
2496 + if (mod_data.can_stall) {
2497 + fsg_set_halt(fsg, fsg->bulk_out);
2498 + rc = halt_bulk_in_endpoint(fsg);
2499 + }
2500 + break;
2501 +
2502 + /* All but the last buffer of data must have already been sent */
2503 + case DATA_DIR_TO_HOST:
2504 + if (fsg->data_size == 0)
2505 + ; // Nothing to send
2506 +
2507 + /* If there's no residue, simply send the last buffer */
2508 + else if (fsg->residue == 0) {
2509 + bh->inreq->zero = 0;
2510 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2511 + &bh->inreq_busy, &bh->state);
2512 + fsg->next_buffhd_to_fill = bh->next;
2513 + }
2514 +
2515 + /* There is a residue. For CB and CBI, simply mark the end
2516 + * of the data with a short packet. However, if we are
2517 + * allowed to stall, there was no data at all (residue ==
2518 + * data_size), and the command failed (invalid LUN or
2519 + * sense data is set), then halt the bulk-in endpoint
2520 + * instead. */
2521 + else if (!transport_is_bbb()) {
2522 + if (mod_data.can_stall &&
2523 + fsg->residue == fsg->data_size &&
2524 + (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) {
2525 + bh->state = BUF_STATE_EMPTY;
2526 + rc = halt_bulk_in_endpoint(fsg);
2527 + } else {
2528 + bh->inreq->zero = 1;
2529 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2530 + &bh->inreq_busy, &bh->state);
2531 + fsg->next_buffhd_to_fill = bh->next;
2532 + }
2533 + }
2534 +
2535 + /*
2536 + * For Bulk-only, mark the end of the data with a short
2537 + * packet. If we are allowed to stall, halt the bulk-in
2538 + * endpoint. (Note: This violates the Bulk-Only Transport
2539 + * specification, which requires us to pad the data if we
2540 + * don't halt the endpoint. Presumably nobody will mind.)
2541 + */
2542 + else {
2543 + bh->inreq->zero = 1;
2544 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2545 + &bh->inreq_busy, &bh->state);
2546 + fsg->next_buffhd_to_fill = bh->next;
2547 + if (mod_data.can_stall)
2548 + rc = halt_bulk_in_endpoint(fsg);
2549 + }
2550 + break;
2551 +
2552 + /* We have processed all we want from the data the host has sent.
2553 + * There may still be outstanding bulk-out requests. */
2554 + case DATA_DIR_FROM_HOST:
2555 + if (fsg->residue == 0)
2556 + ; // Nothing to receive
2557 +
2558 + /* Did the host stop sending unexpectedly early? */
2559 + else if (fsg->short_packet_received) {
2560 + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
2561 + rc = -EINTR;
2562 + }
2563 +
2564 + /* We haven't processed all the incoming data. Even though
2565 + * we may be allowed to stall, doing so would cause a race.
2566 + * The controller may already have ACK'ed all the remaining
2567 + * bulk-out packets, in which case the host wouldn't see a
2568 + * STALL. Not realizing the endpoint was halted, it wouldn't
2569 + * clear the halt -- leading to problems later on. */
2570 +#if 0
2571 + else if (mod_data.can_stall) {
2572 + fsg_set_halt(fsg, fsg->bulk_out);
2573 + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
2574 + rc = -EINTR;
2575 + }
2576 +#endif
2577 +
2578 + /* We can't stall. Read in the excess data and throw it
2579 + * all away. */
2580 + else
2581 + rc = throw_away_data(fsg);
2582 + break;
2583 + }
2584 + return rc;
2585 +}
2586 +
2587 +
2588 +static int send_status(struct fsg_dev *fsg)
2589 +{
2590 + struct fsg_lun *curlun = fsg->curlun;
2591 + struct fsg_buffhd *bh;
2592 + int rc;
2593 + u8 status = US_BULK_STAT_OK;
2594 + u32 sd, sdinfo = 0;
2595 +
2596 + /* Wait for the next buffer to become available */
2597 + bh = fsg->next_buffhd_to_fill;
2598 + while (bh->state != BUF_STATE_EMPTY) {
2599 + rc = sleep_thread(fsg);
2600 + if (rc)
2601 + return rc;
2602 + }
2603 +
2604 + if (curlun) {
2605 + sd = curlun->sense_data;
2606 + sdinfo = curlun->sense_data_info;
2607 + } else if (fsg->bad_lun_okay)
2608 + sd = SS_NO_SENSE;
2609 + else
2610 + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
2611 +
2612 + if (fsg->phase_error) {
2613 + DBG(fsg, "sending phase-error status\n");
2614 + status = US_BULK_STAT_PHASE;
2615 + sd = SS_INVALID_COMMAND;
2616 + } else if (sd != SS_NO_SENSE) {
2617 + DBG(fsg, "sending command-failure status\n");
2618 + status = US_BULK_STAT_FAIL;
2619 + VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
2620 + " info x%x\n",
2621 + SK(sd), ASC(sd), ASCQ(sd), sdinfo);
2622 + }
2623 +
2624 + if (transport_is_bbb()) {
2625 + struct bulk_cs_wrap *csw = bh->buf;
2626 +
2627 + /* Store and send the Bulk-only CSW */
2628 + csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
2629 + csw->Tag = fsg->tag;
2630 + csw->Residue = cpu_to_le32(fsg->residue);
2631 + csw->Status = status;
2632 +
2633 + bh->inreq->length = US_BULK_CS_WRAP_LEN;
2634 + bh->inreq->zero = 0;
2635 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2636 + &bh->inreq_busy, &bh->state);
2637 +
2638 + } else if (mod_data.transport_type == USB_PR_CB) {
2639 +
2640 + /* Control-Bulk transport has no status phase! */
2641 + return 0;
2642 +
2643 + } else { // USB_PR_CBI
2644 + struct interrupt_data *buf = bh->buf;
2645 +
2646 + /* Store and send the Interrupt data. UFI sends the ASC
2647 + * and ASCQ bytes. Everything else sends a Type (which
2648 + * is always 0) and the status Value. */
2649 + if (mod_data.protocol_type == USB_SC_UFI) {
2650 + buf->bType = ASC(sd);
2651 + buf->bValue = ASCQ(sd);
2652 + } else {
2653 + buf->bType = 0;
2654 + buf->bValue = status;
2655 + }
2656 + fsg->intreq->length = CBI_INTERRUPT_DATA_LEN;
2657 +
2658 + fsg->intr_buffhd = bh; // Point to the right buffhd
2659 + fsg->intreq->buf = bh->inreq->buf;
2660 + fsg->intreq->context = bh;
2661 + start_transfer(fsg, fsg->intr_in, fsg->intreq,
2662 + &fsg->intreq_busy, &bh->state);
2663 + }
2664 +
2665 + fsg->next_buffhd_to_fill = bh->next;
2666 + return 0;
2667 +}
2668 +
2669 +
2670 +/*-------------------------------------------------------------------------*/
2671 +
2672 +/* Check whether the command is properly formed and whether its data size
2673 + * and direction agree with the values we already have. */
2674 +static int check_command(struct fsg_dev *fsg, int cmnd_size,
2675 + enum data_direction data_dir, unsigned int mask,
2676 + int needs_medium, const char *name)
2677 +{
2678 + int i;
2679 + int lun = fsg->cmnd[1] >> 5;
2680 + static const char dirletter[4] = {'u', 'o', 'i', 'n'};
2681 + char hdlen[20];
2682 + struct fsg_lun *curlun;
2683 +
2684 + /* Adjust the expected cmnd_size for protocol encapsulation padding.
2685 + * Transparent SCSI doesn't pad. */
2686 + if (protocol_is_scsi())
2687 + ;
2688 +
2689 + /* There's some disagreement as to whether RBC pads commands or not.
2690 + * We'll play it safe and accept either form. */
2691 + else if (mod_data.protocol_type == USB_SC_RBC) {
2692 + if (fsg->cmnd_size == 12)
2693 + cmnd_size = 12;
2694 +
2695 + /* All the other protocols pad to 12 bytes */
2696 + } else
2697 + cmnd_size = 12;
2698 +
2699 + hdlen[0] = 0;
2700 + if (fsg->data_dir != DATA_DIR_UNKNOWN)
2701 + sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir],
2702 + fsg->data_size);
2703 + VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n",
2704 + name, cmnd_size, dirletter[(int) data_dir],
2705 + fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen);
2706 +
2707 + /* We can't reply at all until we know the correct data direction
2708 + * and size. */
2709 + if (fsg->data_size_from_cmnd == 0)
2710 + data_dir = DATA_DIR_NONE;
2711 + if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI
2712 + fsg->data_dir = data_dir;
2713 + fsg->data_size = fsg->data_size_from_cmnd;
2714 +
2715 + } else { // Bulk-only
2716 + if (fsg->data_size < fsg->data_size_from_cmnd) {
2717 +
2718 + /* Host data size < Device data size is a phase error.
2719 + * Carry out the command, but only transfer as much
2720 + * as we are allowed. */
2721 + fsg->data_size_from_cmnd = fsg->data_size;
2722 + fsg->phase_error = 1;
2723 + }
2724 + }
2725 + fsg->residue = fsg->usb_amount_left = fsg->data_size;
2726 +
2727 + /* Conflicting data directions is a phase error */
2728 + if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) {
2729 + fsg->phase_error = 1;
2730 + return -EINVAL;
2731 + }
2732 +
2733 + /* Verify the length of the command itself */
2734 + if (cmnd_size != fsg->cmnd_size) {
2735 +
2736 + /* Special case workaround: There are plenty of buggy SCSI
2737 + * implementations. Many have issues with cbw->Length
2738 + * field passing a wrong command size. For those cases we
2739 + * always try to work around the problem by using the length
2740 + * sent by the host side provided it is at least as large
2741 + * as the correct command length.
2742 + * Examples of such cases would be MS-Windows, which issues
2743 + * REQUEST SENSE with cbw->Length == 12 where it should
2744 + * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and
2745 + * REQUEST SENSE with cbw->Length == 10 where it should
2746 + * be 6 as well.
2747 + */
2748 + if (cmnd_size <= fsg->cmnd_size) {
2749 + DBG(fsg, "%s is buggy! Expected length %d "
2750 + "but we got %d\n", name,
2751 + cmnd_size, fsg->cmnd_size);
2752 + cmnd_size = fsg->cmnd_size;
2753 + } else {
2754 + fsg->phase_error = 1;
2755 + return -EINVAL;
2756 + }
2757 + }
2758 +
2759 + /* Check that the LUN values are consistent */
2760 + if (transport_is_bbb()) {
2761 + if (fsg->lun != lun)
2762 + DBG(fsg, "using LUN %d from CBW, "
2763 + "not LUN %d from CDB\n",
2764 + fsg->lun, lun);
2765 + }
2766 +
2767 + /* Check the LUN */
2768 + curlun = fsg->curlun;
2769 + if (curlun) {
2770 + if (fsg->cmnd[0] != REQUEST_SENSE) {
2771 + curlun->sense_data = SS_NO_SENSE;
2772 + curlun->sense_data_info = 0;
2773 + curlun->info_valid = 0;
2774 + }
2775 + } else {
2776 + fsg->bad_lun_okay = 0;
2777 +
2778 + /* INQUIRY and REQUEST SENSE commands are explicitly allowed
2779 + * to use unsupported LUNs; all others may not. */
2780 + if (fsg->cmnd[0] != INQUIRY &&
2781 + fsg->cmnd[0] != REQUEST_SENSE) {
2782 + DBG(fsg, "unsupported LUN %d\n", fsg->lun);
2783 + return -EINVAL;
2784 + }
2785 + }
2786 +
2787 + /* If a unit attention condition exists, only INQUIRY and
2788 + * REQUEST SENSE commands are allowed; anything else must fail. */
2789 + if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
2790 + fsg->cmnd[0] != INQUIRY &&
2791 + fsg->cmnd[0] != REQUEST_SENSE) {
2792 + curlun->sense_data = curlun->unit_attention_data;
2793 + curlun->unit_attention_data = SS_NO_SENSE;
2794 + return -EINVAL;
2795 + }
2796 +
2797 + /* Check that only command bytes listed in the mask are non-zero */
2798 + fsg->cmnd[1] &= 0x1f; // Mask away the LUN
2799 + for (i = 1; i < cmnd_size; ++i) {
2800 + if (fsg->cmnd[i] && !(mask & (1 << i))) {
2801 + if (curlun)
2802 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2803 + return -EINVAL;
2804 + }
2805 + }
2806 +
2807 + /* If the medium isn't mounted and the command needs to access
2808 + * it, return an error. */
2809 + if (curlun && !fsg_lun_is_open(curlun) && needs_medium) {
2810 + curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
2811 + return -EINVAL;
2812 + }
2813 +
2814 + return 0;
2815 +}
2816 +
2817 +/* wrapper of check_command for data size in blocks handling */
2818 +static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size,
2819 + enum data_direction data_dir, unsigned int mask,
2820 + int needs_medium, const char *name)
2821 +{
2822 + if (fsg->curlun)
2823 + fsg->data_size_from_cmnd <<= fsg->curlun->blkbits;
2824 + return check_command(fsg, cmnd_size, data_dir,
2825 + mask, needs_medium, name);
2826 +}
2827 +
2828 +static int do_scsi_command(struct fsg_dev *fsg)
2829 +{
2830 + struct fsg_buffhd *bh;
2831 + int rc;
2832 + int reply = -EINVAL;
2833 + int i;
2834 + static char unknown[16];
2835 +
2836 + dump_cdb(fsg);
2837 +
2838 + /* Wait for the next buffer to become available for data or status */
2839 + bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
2840 + while (bh->state != BUF_STATE_EMPTY) {
2841 + rc = sleep_thread(fsg);
2842 + if (rc)
2843 + return rc;
2844 + }
2845 + fsg->phase_error = 0;
2846 + fsg->short_packet_received = 0;
2847 +
2848 + down_read(&fsg->filesem); // We're using the backing file
2849 + switch (fsg->cmnd[0]) {
2850 +
2851 + case INQUIRY:
2852 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2853 + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
2854 + (1<<4), 0,
2855 + "INQUIRY")) == 0)
2856 + reply = do_inquiry(fsg, bh);
2857 + break;
2858 +
2859 + case MODE_SELECT:
2860 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2861 + if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
2862 + (1<<1) | (1<<4), 0,
2863 + "MODE SELECT(6)")) == 0)
2864 + reply = do_mode_select(fsg, bh);
2865 + break;
2866 +
2867 + case MODE_SELECT_10:
2868 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2869 + if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
2870 + (1<<1) | (3<<7), 0,
2871 + "MODE SELECT(10)")) == 0)
2872 + reply = do_mode_select(fsg, bh);
2873 + break;
2874 +
2875 + case MODE_SENSE:
2876 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2877 + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
2878 + (1<<1) | (1<<2) | (1<<4), 0,
2879 + "MODE SENSE(6)")) == 0)
2880 + reply = do_mode_sense(fsg, bh);
2881 + break;
2882 +
2883 + case MODE_SENSE_10:
2884 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2885 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2886 + (1<<1) | (1<<2) | (3<<7), 0,
2887 + "MODE SENSE(10)")) == 0)
2888 + reply = do_mode_sense(fsg, bh);
2889 + break;
2890 +
2891 + case ALLOW_MEDIUM_REMOVAL:
2892 + fsg->data_size_from_cmnd = 0;
2893 + if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
2894 + (1<<4), 0,
2895 + "PREVENT-ALLOW MEDIUM REMOVAL")) == 0)
2896 + reply = do_prevent_allow(fsg);
2897 + break;
2898 +
2899 + case READ_6:
2900 + i = fsg->cmnd[4];
2901 + fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
2902 + if ((reply = check_command_size_in_blocks(fsg, 6,
2903 + DATA_DIR_TO_HOST,
2904 + (7<<1) | (1<<4), 1,
2905 + "READ(6)")) == 0)
2906 + reply = do_read(fsg);
2907 + break;
2908 +
2909 + case READ_10:
2910 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2911 + if ((reply = check_command_size_in_blocks(fsg, 10,
2912 + DATA_DIR_TO_HOST,
2913 + (1<<1) | (0xf<<2) | (3<<7), 1,
2914 + "READ(10)")) == 0)
2915 + reply = do_read(fsg);
2916 + break;
2917 +
2918 + case READ_12:
2919 + fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
2920 + if ((reply = check_command_size_in_blocks(fsg, 12,
2921 + DATA_DIR_TO_HOST,
2922 + (1<<1) | (0xf<<2) | (0xf<<6), 1,
2923 + "READ(12)")) == 0)
2924 + reply = do_read(fsg);
2925 + break;
2926 +
2927 + case READ_CAPACITY:
2928 + fsg->data_size_from_cmnd = 8;
2929 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2930 + (0xf<<2) | (1<<8), 1,
2931 + "READ CAPACITY")) == 0)
2932 + reply = do_read_capacity(fsg, bh);
2933 + break;
2934 +
2935 + case READ_HEADER:
2936 + if (!mod_data.cdrom)
2937 + goto unknown_cmnd;
2938 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2939 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2940 + (3<<7) | (0x1f<<1), 1,
2941 + "READ HEADER")) == 0)
2942 + reply = do_read_header(fsg, bh);
2943 + break;
2944 +
2945 + case READ_TOC:
2946 + if (!mod_data.cdrom)
2947 + goto unknown_cmnd;
2948 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2949 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2950 + (7<<6) | (1<<1), 1,
2951 + "READ TOC")) == 0)
2952 + reply = do_read_toc(fsg, bh);
2953 + break;
2954 +
2955 + case READ_FORMAT_CAPACITIES:
2956 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2957 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2958 + (3<<7), 1,
2959 + "READ FORMAT CAPACITIES")) == 0)
2960 + reply = do_read_format_capacities(fsg, bh);
2961 + break;
2962 +
2963 + case REQUEST_SENSE:
2964 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2965 + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
2966 + (1<<4), 0,
2967 + "REQUEST SENSE")) == 0)
2968 + reply = do_request_sense(fsg, bh);
2969 + break;
2970 +
2971 + case START_STOP:
2972 + fsg->data_size_from_cmnd = 0;
2973 + if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
2974 + (1<<1) | (1<<4), 0,
2975 + "START-STOP UNIT")) == 0)
2976 + reply = do_start_stop(fsg);
2977 + break;
2978 +
2979 + case SYNCHRONIZE_CACHE:
2980 + fsg->data_size_from_cmnd = 0;
2981 + if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
2982 + (0xf<<2) | (3<<7), 1,
2983 + "SYNCHRONIZE CACHE")) == 0)
2984 + reply = do_synchronize_cache(fsg);
2985 + break;
2986 +
2987 + case TEST_UNIT_READY:
2988 + fsg->data_size_from_cmnd = 0;
2989 + reply = check_command(fsg, 6, DATA_DIR_NONE,
2990 + 0, 1,
2991 + "TEST UNIT READY");
2992 + break;
2993 +
2994 + /* Although optional, this command is used by MS-Windows. We
2995 + * support a minimal version: BytChk must be 0. */
2996 + case VERIFY:
2997 + fsg->data_size_from_cmnd = 0;
2998 + if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
2999 + (1<<1) | (0xf<<2) | (3<<7), 1,
3000 + "VERIFY")) == 0)
3001 + reply = do_verify(fsg);
3002 + break;
3003 +
3004 + case WRITE_6:
3005 + i = fsg->cmnd[4];
3006 + fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
3007 + if ((reply = check_command_size_in_blocks(fsg, 6,
3008 + DATA_DIR_FROM_HOST,
3009 + (7<<1) | (1<<4), 1,
3010 + "WRITE(6)")) == 0)
3011 + reply = do_write(fsg);
3012 + break;
3013 +
3014 + case WRITE_10:
3015 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
3016 + if ((reply = check_command_size_in_blocks(fsg, 10,
3017 + DATA_DIR_FROM_HOST,
3018 + (1<<1) | (0xf<<2) | (3<<7), 1,
3019 + "WRITE(10)")) == 0)
3020 + reply = do_write(fsg);
3021 + break;
3022 +
3023 + case WRITE_12:
3024 + fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
3025 + if ((reply = check_command_size_in_blocks(fsg, 12,
3026 + DATA_DIR_FROM_HOST,
3027 + (1<<1) | (0xf<<2) | (0xf<<6), 1,
3028 + "WRITE(12)")) == 0)
3029 + reply = do_write(fsg);
3030 + break;
3031 +
3032 + /* Some mandatory commands that we recognize but don't implement.
3033 + * They don't mean much in this setting. It's left as an exercise
3034 + * for anyone interested to implement RESERVE and RELEASE in terms
3035 + * of Posix locks. */
3036 + case FORMAT_UNIT:
3037 + case RELEASE:
3038 + case RESERVE:
3039 + case SEND_DIAGNOSTIC:
3040 + // Fall through
3041 +
3042 + default:
3043 + unknown_cmnd:
3044 + fsg->data_size_from_cmnd = 0;
3045 + sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]);
3046 + if ((reply = check_command(fsg, fsg->cmnd_size,
3047 + DATA_DIR_UNKNOWN, ~0, 0, unknown)) == 0) {
3048 + fsg->curlun->sense_data = SS_INVALID_COMMAND;
3049 + reply = -EINVAL;
3050 + }
3051 + break;
3052 + }
3053 + up_read(&fsg->filesem);
3054 +
3055 + if (reply == -EINTR || signal_pending(current))
3056 + return -EINTR;
3057 +
3058 + /* Set up the single reply buffer for finish_reply() */
3059 + if (reply == -EINVAL)
3060 + reply = 0; // Error reply length
3061 + if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) {
3062 + reply = min((u32) reply, fsg->data_size_from_cmnd);
3063 + bh->inreq->length = reply;
3064 + bh->state = BUF_STATE_FULL;
3065 + fsg->residue -= reply;
3066 + } // Otherwise it's already set
3067 +
3068 + return 0;
3069 +}
3070 +
3071 +
3072 +/*-------------------------------------------------------------------------*/
3073 +
3074 +static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
3075 +{
3076 + struct usb_request *req = bh->outreq;
3077 + struct bulk_cb_wrap *cbw = req->buf;
3078 +
3079 + /* Was this a real packet? Should it be ignored? */
3080 + if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
3081 + return -EINVAL;
3082 +
3083 + /* Is the CBW valid? */
3084 + if (req->actual != US_BULK_CB_WRAP_LEN ||
3085 + cbw->Signature != cpu_to_le32(
3086 + US_BULK_CB_SIGN)) {
3087 + DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
3088 + req->actual,
3089 + le32_to_cpu(cbw->Signature));
3090 +
3091 + /* The Bulk-only spec says we MUST stall the IN endpoint
3092 + * (6.6.1), so it's unavoidable. It also says we must
3093 + * retain this state until the next reset, but there's
3094 + * no way to tell the controller driver it should ignore
3095 + * Clear-Feature(HALT) requests.
3096 + *
3097 + * We aren't required to halt the OUT endpoint; instead
3098 + * we can simply accept and discard any data received
3099 + * until the next reset. */
3100 + wedge_bulk_in_endpoint(fsg);
3101 + set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
3102 + return -EINVAL;
3103 + }
3104 +
3105 + /* Is the CBW meaningful? */
3106 + if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
3107 + cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
3108 + DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
3109 + "cmdlen %u\n",
3110 + cbw->Lun, cbw->Flags, cbw->Length);
3111 +
3112 + /* We can do anything we want here, so let's stall the
3113 + * bulk pipes if we are allowed to. */
3114 + if (mod_data.can_stall) {
3115 + fsg_set_halt(fsg, fsg->bulk_out);
3116 + halt_bulk_in_endpoint(fsg);
3117 + }
3118 + return -EINVAL;
3119 + }
3120 +
3121 + /* Save the command for later */
3122 + fsg->cmnd_size = cbw->Length;
3123 + memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size);
3124 + if (cbw->Flags & US_BULK_FLAG_IN)
3125 + fsg->data_dir = DATA_DIR_TO_HOST;
3126 + else
3127 + fsg->data_dir = DATA_DIR_FROM_HOST;
3128 + fsg->data_size = le32_to_cpu(cbw->DataTransferLength);
3129 + if (fsg->data_size == 0)
3130 + fsg->data_dir = DATA_DIR_NONE;
3131 + fsg->lun = cbw->Lun;
3132 + fsg->tag = cbw->Tag;
3133 + return 0;
3134 +}
3135 +
3136 +
3137 +static int get_next_command(struct fsg_dev *fsg)
3138 +{
3139 + struct fsg_buffhd *bh;
3140 + int rc = 0;
3141 +
3142 + if (transport_is_bbb()) {
3143 +
3144 + /* Wait for the next buffer to become available */
3145 + bh = fsg->next_buffhd_to_fill;
3146 + while (bh->state != BUF_STATE_EMPTY) {
3147 + rc = sleep_thread(fsg);
3148 + if (rc)
3149 + return rc;
3150 + }
3151 +
3152 + /* Queue a request to read a Bulk-only CBW */
3153 + set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN);
3154 + start_transfer(fsg, fsg->bulk_out, bh->outreq,
3155 + &bh->outreq_busy, &bh->state);
3156 +
3157 + /* We will drain the buffer in software, which means we
3158 + * can reuse it for the next filling. No need to advance
3159 + * next_buffhd_to_fill. */
3160 +
3161 + /* Wait for the CBW to arrive */
3162 + while (bh->state != BUF_STATE_FULL) {
3163 + rc = sleep_thread(fsg);
3164 + if (rc)
3165 + return rc;
3166 + }
3167 + smp_rmb();
3168 + rc = received_cbw(fsg, bh);
3169 + bh->state = BUF_STATE_EMPTY;
3170 +
3171 + } else { // USB_PR_CB or USB_PR_CBI
3172 +
3173 + /* Wait for the next command to arrive */
3174 + while (fsg->cbbuf_cmnd_size == 0) {
3175 + rc = sleep_thread(fsg);
3176 + if (rc)
3177 + return rc;
3178 + }
3179 +
3180 + /* Is the previous status interrupt request still busy?
3181 + * The host is allowed to skip reading the status,
3182 + * so we must cancel it. */
3183 + if (fsg->intreq_busy)
3184 + usb_ep_dequeue(fsg->intr_in, fsg->intreq);
3185 +
3186 + /* Copy the command and mark the buffer empty */
3187 + fsg->data_dir = DATA_DIR_UNKNOWN;
3188 + spin_lock_irq(&fsg->lock);
3189 + fsg->cmnd_size = fsg->cbbuf_cmnd_size;
3190 + memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size);
3191 + fsg->cbbuf_cmnd_size = 0;
3192 + spin_unlock_irq(&fsg->lock);
3193 +
3194 + /* Use LUN from the command */
3195 + fsg->lun = fsg->cmnd[1] >> 5;
3196 + }
3197 +
3198 + /* Update current lun */
3199 + if (fsg->lun >= 0 && fsg->lun < fsg->nluns)
3200 + fsg->curlun = &fsg->luns[fsg->lun];
3201 + else
3202 + fsg->curlun = NULL;
3203 +
3204 + return rc;
3205 +}
3206 +
3207 +
3208 +/*-------------------------------------------------------------------------*/
3209 +
3210 +static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,
3211 + const struct usb_endpoint_descriptor *d)
3212 +{
3213 + int rc;
3214 +
3215 + ep->driver_data = fsg;
3216 + ep->desc = d;
3217 + rc = usb_ep_enable(ep);
3218 + if (rc)
3219 + ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
3220 + return rc;
3221 +}
3222 +
3223 +static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep,
3224 + struct usb_request **preq)
3225 +{
3226 + *preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
3227 + if (*preq)
3228 + return 0;
3229 + ERROR(fsg, "can't allocate request for %s\n", ep->name);
3230 + return -ENOMEM;
3231 +}
3232 +
3233 +/*
3234 + * Reset interface setting and re-init endpoint state (toggle etc).
3235 + * Call with altsetting < 0 to disable the interface. The only other
3236 + * available altsetting is 0, which enables the interface.
3237 + */
3238 +static int do_set_interface(struct fsg_dev *fsg, int altsetting)
3239 +{
3240 + int rc = 0;
3241 + int i;
3242 + const struct usb_endpoint_descriptor *d;
3243 +
3244 + if (fsg->running)
3245 + DBG(fsg, "reset interface\n");
3246 +
3247 +reset:
3248 + /* Deallocate the requests */
3249 + for (i = 0; i < fsg_num_buffers; ++i) {
3250 + struct fsg_buffhd *bh = &fsg->buffhds[i];
3251 +
3252 + if (bh->inreq) {
3253 + usb_ep_free_request(fsg->bulk_in, bh->inreq);
3254 + bh->inreq = NULL;
3255 + }
3256 + if (bh->outreq) {
3257 + usb_ep_free_request(fsg->bulk_out, bh->outreq);
3258 + bh->outreq = NULL;
3259 + }
3260 + }
3261 + if (fsg->intreq) {
3262 + usb_ep_free_request(fsg->intr_in, fsg->intreq);
3263 + fsg->intreq = NULL;
3264 + }
3265 +
3266 + /* Disable the endpoints */
3267 + if (fsg->bulk_in_enabled) {
3268 + usb_ep_disable(fsg->bulk_in);
3269 + fsg->bulk_in_enabled = 0;
3270 + }
3271 + if (fsg->bulk_out_enabled) {
3272 + usb_ep_disable(fsg->bulk_out);
3273 + fsg->bulk_out_enabled = 0;
3274 + }
3275 + if (fsg->intr_in_enabled) {
3276 + usb_ep_disable(fsg->intr_in);
3277 + fsg->intr_in_enabled = 0;
3278 + }
3279 +
3280 + fsg->running = 0;
3281 + if (altsetting < 0 || rc != 0)
3282 + return rc;
3283 +
3284 + DBG(fsg, "set interface %d\n", altsetting);
3285 +
3286 + /* Enable the endpoints */
3287 + d = fsg_ep_desc(fsg->gadget,
3288 + &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc,
3289 + &fsg_ss_bulk_in_desc);
3290 + if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
3291 + goto reset;
3292 + fsg->bulk_in_enabled = 1;
3293 +
3294 + d = fsg_ep_desc(fsg->gadget,
3295 + &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc,
3296 + &fsg_ss_bulk_out_desc);
3297 + if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
3298 + goto reset;
3299 + fsg->bulk_out_enabled = 1;
3300 + fsg->bulk_out_maxpacket = usb_endpoint_maxp(d);
3301 + clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
3302 +
3303 + if (transport_is_cbi()) {
3304 + d = fsg_ep_desc(fsg->gadget,
3305 + &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc,
3306 + &fsg_ss_intr_in_desc);
3307 + if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
3308 + goto reset;
3309 + fsg->intr_in_enabled = 1;
3310 + }
3311 +
3312 + /* Allocate the requests */
3313 + for (i = 0; i < fsg_num_buffers; ++i) {
3314 + struct fsg_buffhd *bh = &fsg->buffhds[i];
3315 +
3316 + if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0)
3317 + goto reset;
3318 + if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0)
3319 + goto reset;
3320 + bh->inreq->buf = bh->outreq->buf = bh->buf;
3321 + bh->inreq->context = bh->outreq->context = bh;
3322 + bh->inreq->complete = bulk_in_complete;
3323 + bh->outreq->complete = bulk_out_complete;
3324 + }
3325 + if (transport_is_cbi()) {
3326 + if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0)
3327 + goto reset;
3328 + fsg->intreq->complete = intr_in_complete;
3329 + }
3330 +
3331 + fsg->running = 1;
3332 + for (i = 0; i < fsg->nluns; ++i)
3333 + fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
3334 + return rc;
3335 +}
3336 +
3337 +
3338 +/*
3339 + * Change our operational configuration. This code must agree with the code
3340 + * that returns config descriptors, and with interface altsetting code.
3341 + *
3342 + * It's also responsible for power management interactions. Some
3343 + * configurations might not work with our current power sources.
3344 + * For now we just assume the gadget is always self-powered.
3345 + */
3346 +static int do_set_config(struct fsg_dev *fsg, u8 new_config)
3347 +{
3348 + int rc = 0;
3349 +
3350 + /* Disable the single interface */
3351 + if (fsg->config != 0) {
3352 + DBG(fsg, "reset config\n");
3353 + fsg->config = 0;
3354 + rc = do_set_interface(fsg, -1);
3355 + }
3356 +
3357 + /* Enable the interface */
3358 + if (new_config != 0) {
3359 + fsg->config = new_config;
3360 + if ((rc = do_set_interface(fsg, 0)) != 0)
3361 + fsg->config = 0; // Reset on errors
3362 + else
3363 + INFO(fsg, "%s config #%d\n",
3364 + usb_speed_string(fsg->gadget->speed),
3365 + fsg->config);
3366 + }
3367 + return rc;
3368 +}
3369 +
3370 +
3371 +/*-------------------------------------------------------------------------*/
3372 +
3373 +static void handle_exception(struct fsg_dev *fsg)
3374 +{
3375 + siginfo_t info;
3376 + int sig;
3377 + int i;
3378 + int num_active;
3379 + struct fsg_buffhd *bh;
3380 + enum fsg_state old_state;
3381 + u8 new_config;
3382 + struct fsg_lun *curlun;
3383 + unsigned int exception_req_tag;
3384 + int rc;
3385 +
3386 + /* Clear the existing signals. Anything but SIGUSR1 is converted
3387 + * into a high-priority EXIT exception. */
3388 + for (;;) {
3389 + sig = dequeue_signal_lock(current, &current->blocked, &info);
3390 + if (!sig)
3391 + break;
3392 + if (sig != SIGUSR1) {
3393 + if (fsg->state < FSG_STATE_EXIT)
3394 + DBG(fsg, "Main thread exiting on signal\n");
3395 + raise_exception(fsg, FSG_STATE_EXIT);
3396 + }
3397 + }
3398 +
3399 + /* Cancel all the pending transfers */
3400 + if (fsg->intreq_busy)
3401 + usb_ep_dequeue(fsg->intr_in, fsg->intreq);
3402 + for (i = 0; i < fsg_num_buffers; ++i) {
3403 + bh = &fsg->buffhds[i];
3404 + if (bh->inreq_busy)
3405 + usb_ep_dequeue(fsg->bulk_in, bh->inreq);
3406 + if (bh->outreq_busy)
3407 + usb_ep_dequeue(fsg->bulk_out, bh->outreq);
3408 + }
3409 +
3410 + /* Wait until everything is idle */
3411 + for (;;) {
3412 + num_active = fsg->intreq_busy;
3413 + for (i = 0; i < fsg_num_buffers; ++i) {
3414 + bh = &fsg->buffhds[i];
3415 + num_active += bh->inreq_busy + bh->outreq_busy;
3416 + }
3417 + if (num_active == 0)
3418 + break;
3419 + if (sleep_thread(fsg))
3420 + return;
3421 + }
3422 +
3423 + /* Clear out the controller's fifos */
3424 + if (fsg->bulk_in_enabled)
3425 + usb_ep_fifo_flush(fsg->bulk_in);
3426 + if (fsg->bulk_out_enabled)
3427 + usb_ep_fifo_flush(fsg->bulk_out);
3428 + if (fsg->intr_in_enabled)
3429 + usb_ep_fifo_flush(fsg->intr_in);
3430 +
3431 + /* Reset the I/O buffer states and pointers, the SCSI
3432 + * state, and the exception. Then invoke the handler. */
3433 + spin_lock_irq(&fsg->lock);
3434 +
3435 + for (i = 0; i < fsg_num_buffers; ++i) {
3436 + bh = &fsg->buffhds[i];
3437 + bh->state = BUF_STATE_EMPTY;
3438 + }
3439 + fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain =
3440 + &fsg->buffhds[0];
3441 +
3442 + exception_req_tag = fsg->exception_req_tag;
3443 + new_config = fsg->new_config;
3444 + old_state = fsg->state;
3445 +
3446 + if (old_state == FSG_STATE_ABORT_BULK_OUT)
3447 + fsg->state = FSG_STATE_STATUS_PHASE;
3448 + else {
3449 + for (i = 0; i < fsg->nluns; ++i) {
3450 + curlun = &fsg->luns[i];
3451 + curlun->prevent_medium_removal = 0;
3452 + curlun->sense_data = curlun->unit_attention_data =
3453 + SS_NO_SENSE;
3454 + curlun->sense_data_info = 0;
3455 + curlun->info_valid = 0;
3456 + }
3457 + fsg->state = FSG_STATE_IDLE;
3458 + }
3459 + spin_unlock_irq(&fsg->lock);
3460 +
3461 + /* Carry out any extra actions required for the exception */
3462 + switch (old_state) {
3463 + default:
3464 + break;
3465 +
3466 + case FSG_STATE_ABORT_BULK_OUT:
3467 + send_status(fsg);
3468 + spin_lock_irq(&fsg->lock);
3469 + if (fsg->state == FSG_STATE_STATUS_PHASE)
3470 + fsg->state = FSG_STATE_IDLE;
3471 + spin_unlock_irq(&fsg->lock);
3472 + break;
3473 +
3474 + case FSG_STATE_RESET:
3475 + /* In case we were forced against our will to halt a
3476 + * bulk endpoint, clear the halt now. (The SuperH UDC
3477 + * requires this.) */
3478 + if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
3479 + usb_ep_clear_halt(fsg->bulk_in);
3480 +
3481 + if (transport_is_bbb()) {
3482 + if (fsg->ep0_req_tag == exception_req_tag)
3483 + ep0_queue(fsg); // Complete the status stage
3484 +
3485 + } else if (transport_is_cbi())
3486 + send_status(fsg); // Status by interrupt pipe
3487 +
3488 + /* Technically this should go here, but it would only be
3489 + * a waste of time. Ditto for the INTERFACE_CHANGE and
3490 + * CONFIG_CHANGE cases. */
3491 + // for (i = 0; i < fsg->nluns; ++i)
3492 + // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
3493 + break;
3494 +
3495 + case FSG_STATE_INTERFACE_CHANGE:
3496 + rc = do_set_interface(fsg, 0);
3497 + if (fsg->ep0_req_tag != exception_req_tag)
3498 + break;
3499 + if (rc != 0) // STALL on errors
3500 + fsg_set_halt(fsg, fsg->ep0);
3501 + else // Complete the status stage
3502 + ep0_queue(fsg);
3503 + break;
3504 +
3505 + case FSG_STATE_CONFIG_CHANGE:
3506 + rc = do_set_config(fsg, new_config);
3507 + if (fsg->ep0_req_tag != exception_req_tag)
3508 + break;
3509 + if (rc != 0) // STALL on errors
3510 + fsg_set_halt(fsg, fsg->ep0);
3511 + else // Complete the status stage
3512 + ep0_queue(fsg);
3513 + break;
3514 +
3515 + case FSG_STATE_DISCONNECT:
3516 + for (i = 0; i < fsg->nluns; ++i)
3517 + fsg_lun_fsync_sub(fsg->luns + i);
3518 + do_set_config(fsg, 0); // Unconfigured state
3519 + break;
3520 +
3521 + case FSG_STATE_EXIT:
3522 + case FSG_STATE_TERMINATED:
3523 + do_set_config(fsg, 0); // Free resources
3524 + spin_lock_irq(&fsg->lock);
3525 + fsg->state = FSG_STATE_TERMINATED; // Stop the thread
3526 + spin_unlock_irq(&fsg->lock);
3527 + break;
3528 + }
3529 +}
3530 +
3531 +
3532 +/*-------------------------------------------------------------------------*/
3533 +
3534 +static int fsg_main_thread(void *fsg_)
3535 +{
3536 + struct fsg_dev *fsg = fsg_;
3537 +
3538 + /* Allow the thread to be killed by a signal, but set the signal mask
3539 + * to block everything but INT, TERM, KILL, and USR1. */
3540 + allow_signal(SIGINT);
3541 + allow_signal(SIGTERM);
3542 + allow_signal(SIGKILL);
3543 + allow_signal(SIGUSR1);
3544 +
3545 + /* Allow the thread to be frozen */
3546 + set_freezable();
3547 +
3548 + /* Arrange for userspace references to be interpreted as kernel
3549 + * pointers. That way we can pass a kernel pointer to a routine
3550 + * that expects a __user pointer and it will work okay. */
3551 + set_fs(get_ds());
3552 +
3553 + /* The main loop */
3554 + while (fsg->state != FSG_STATE_TERMINATED) {
3555 + if (exception_in_progress(fsg) || signal_pending(current)) {
3556 + handle_exception(fsg);
3557 + continue;
3558 + }
3559 +
3560 + if (!fsg->running) {
3561 + sleep_thread(fsg);
3562 + continue;
3563 + }
3564 +
3565 + if (get_next_command(fsg))
3566 + continue;
3567 +
3568 + spin_lock_irq(&fsg->lock);
3569 + if (!exception_in_progress(fsg))
3570 + fsg->state = FSG_STATE_DATA_PHASE;
3571 + spin_unlock_irq(&fsg->lock);
3572 +
3573 + if (do_scsi_command(fsg) || finish_reply(fsg))
3574 + continue;
3575 +
3576 + spin_lock_irq(&fsg->lock);
3577 + if (!exception_in_progress(fsg))
3578 + fsg->state = FSG_STATE_STATUS_PHASE;
3579 + spin_unlock_irq(&fsg->lock);
3580 +
3581 + if (send_status(fsg))
3582 + continue;
3583 +
3584 + spin_lock_irq(&fsg->lock);
3585 + if (!exception_in_progress(fsg))
3586 + fsg->state = FSG_STATE_IDLE;
3587 + spin_unlock_irq(&fsg->lock);
3588 + }
3589 +
3590 + spin_lock_irq(&fsg->lock);
3591 + fsg->thread_task = NULL;
3592 + spin_unlock_irq(&fsg->lock);
3593 +
3594 + /* If we are exiting because of a signal, unregister the
3595 + * gadget driver. */
3596 + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
3597 + usb_gadget_unregister_driver(&fsg_driver);
3598 +
3599 + /* Let the unbind and cleanup routines know the thread has exited */
3600 + complete_and_exit(&fsg->thread_notifier, 0);
3601 +}
3602 +
3603 +
3604 +/*-------------------------------------------------------------------------*/
3605 +
3606 +
3607 +/* The write permissions and store_xxx pointers are set in fsg_bind() */
3608 +static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL);
3609 +static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL);
3610 +static DEVICE_ATTR(file, 0444, fsg_show_file, NULL);
3611 +
3612 +
3613 +/*-------------------------------------------------------------------------*/
3614 +
3615 +static void fsg_release(struct kref *ref)
3616 +{
3617 + struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref);
3618 +
3619 + kfree(fsg->luns);
3620 + kfree(fsg);
3621 +}
3622 +
3623 +static void lun_release(struct device *dev)
3624 +{
3625 + struct rw_semaphore *filesem = dev_get_drvdata(dev);
3626 + struct fsg_dev *fsg =
3627 + container_of(filesem, struct fsg_dev, filesem);
3628 +
3629 + kref_put(&fsg->ref, fsg_release);
3630 +}
3631 +
3632 +static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
3633 +{
3634 + struct fsg_dev *fsg = get_gadget_data(gadget);
3635 + int i;
3636 + struct fsg_lun *curlun;
3637 + struct usb_request *req = fsg->ep0req;
3638 +
3639 + DBG(fsg, "unbind\n");
3640 + clear_bit(REGISTERED, &fsg->atomic_bitflags);
3641 +
3642 + /* If the thread isn't already dead, tell it to exit now */
3643 + if (fsg->state != FSG_STATE_TERMINATED) {
3644 + raise_exception(fsg, FSG_STATE_EXIT);
3645 + wait_for_completion(&fsg->thread_notifier);
3646 +
3647 + /* The cleanup routine waits for this completion also */
3648 + complete(&fsg->thread_notifier);
3649 + }
3650 +
3651 + /* Unregister the sysfs attribute files and the LUNs */
3652 + for (i = 0; i < fsg->nluns; ++i) {
3653 + curlun = &fsg->luns[i];
3654 + if (curlun->registered) {
3655 + device_remove_file(&curlun->dev, &dev_attr_nofua);
3656 + device_remove_file(&curlun->dev, &dev_attr_ro);
3657 + device_remove_file(&curlun->dev, &dev_attr_file);
3658 + fsg_lun_close(curlun);
3659 + device_unregister(&curlun->dev);
3660 + curlun->registered = 0;
3661 + }
3662 + }
3663 +
3664 + /* Free the data buffers */
3665 + for (i = 0; i < fsg_num_buffers; ++i)
3666 + kfree(fsg->buffhds[i].buf);
3667 +
3668 + /* Free the request and buffer for endpoint 0 */
3669 + if (req) {
3670 + kfree(req->buf);
3671 + usb_ep_free_request(fsg->ep0, req);
3672 + }
3673 +
3674 + set_gadget_data(gadget, NULL);
3675 +}
3676 +
3677 +
3678 +static int __init check_parameters(struct fsg_dev *fsg)
3679 +{
3680 + int prot;
3681 + int gcnum;
3682 +
3683 + /* Store the default values */
3684 + mod_data.transport_type = USB_PR_BULK;
3685 + mod_data.transport_name = "Bulk-only";
3686 + mod_data.protocol_type = USB_SC_SCSI;
3687 + mod_data.protocol_name = "Transparent SCSI";
3688 +
3689 + /* Some peripheral controllers are known not to be able to
3690 + * halt bulk endpoints correctly. If one of them is present,
3691 + * disable stalls.
3692 + */
3693 + if (gadget_is_at91(fsg->gadget))
3694 + mod_data.can_stall = 0;
3695 +
3696 + if (mod_data.release == 0xffff) { // Parameter wasn't set
3697 + gcnum = usb_gadget_controller_number(fsg->gadget);
3698 + if (gcnum >= 0)
3699 + mod_data.release = 0x0300 + gcnum;
3700 + else {
3701 + WARNING(fsg, "controller '%s' not recognized\n",
3702 + fsg->gadget->name);
3703 + mod_data.release = 0x0399;
3704 + }
3705 + }
3706 +
3707 + prot = simple_strtol(mod_data.protocol_parm, NULL, 0);
3708 +
3709 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
3710 + if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) {
3711 + ; // Use default setting
3712 + } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) {
3713 + mod_data.transport_type = USB_PR_CB;
3714 + mod_data.transport_name = "Control-Bulk";
3715 + } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) {
3716 + mod_data.transport_type = USB_PR_CBI;
3717 + mod_data.transport_name = "Control-Bulk-Interrupt";
3718 + } else {
3719 + ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm);
3720 + return -EINVAL;
3721 + }
3722 +
3723 + if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 ||
3724 + prot == USB_SC_SCSI) {
3725 + ; // Use default setting
3726 + } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 ||
3727 + prot == USB_SC_RBC) {
3728 + mod_data.protocol_type = USB_SC_RBC;
3729 + mod_data.protocol_name = "RBC";
3730 + } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 ||
3731 + strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 ||
3732 + prot == USB_SC_8020) {
3733 + mod_data.protocol_type = USB_SC_8020;
3734 + mod_data.protocol_name = "8020i (ATAPI)";
3735 + } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 ||
3736 + prot == USB_SC_QIC) {
3737 + mod_data.protocol_type = USB_SC_QIC;
3738 + mod_data.protocol_name = "QIC-157";
3739 + } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 ||
3740 + prot == USB_SC_UFI) {
3741 + mod_data.protocol_type = USB_SC_UFI;
3742 + mod_data.protocol_name = "UFI";
3743 + } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 ||
3744 + prot == USB_SC_8070) {
3745 + mod_data.protocol_type = USB_SC_8070;
3746 + mod_data.protocol_name = "8070i";
3747 + } else {
3748 + ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm);
3749 + return -EINVAL;
3750 + }
3751 +
3752 + mod_data.buflen &= PAGE_CACHE_MASK;
3753 + if (mod_data.buflen <= 0) {
3754 + ERROR(fsg, "invalid buflen\n");
3755 + return -ETOOSMALL;
3756 + }
3757 +
3758 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
3759 +
3760 + /* Serial string handling.
3761 + * On a real device, the serial string would be loaded
3762 + * from permanent storage. */
3763 + if (mod_data.serial) {
3764 + const char *ch;
3765 + unsigned len = 0;
3766 +
3767 + /* Sanity check :
3768 + * The CB[I] specification limits the serial string to
3769 + * 12 uppercase hexadecimal characters.
3770 + * BBB need at least 12 uppercase hexadecimal characters,
3771 + * with a maximum of 126. */
3772 + for (ch = mod_data.serial; *ch; ++ch) {
3773 + ++len;
3774 + if ((*ch < '0' || *ch > '9') &&
3775 + (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */
3776 + WARNING(fsg,
3777 + "Invalid serial string character: %c\n",
3778 + *ch);
3779 + goto no_serial;
3780 + }
3781 + }
3782 + if (len > 126 ||
3783 + (mod_data.transport_type == USB_PR_BULK && len < 12) ||
3784 + (mod_data.transport_type != USB_PR_BULK && len > 12)) {
3785 + WARNING(fsg, "Invalid serial string length!\n");
3786 + goto no_serial;
3787 + }
3788 + fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial;
3789 + } else {
3790 + WARNING(fsg, "No serial-number string provided!\n");
3791 + no_serial:
3792 + device_desc.iSerialNumber = 0;
3793 + }
3794 +
3795 + return 0;
3796 +}
3797 +
3798 +
3799 +static int __init fsg_bind(struct usb_gadget *gadget)
3800 +{
3801 + struct fsg_dev *fsg = the_fsg;
3802 + int rc;
3803 + int i;
3804 + struct fsg_lun *curlun;
3805 + struct usb_ep *ep;
3806 + struct usb_request *req;
3807 + char *pathbuf, *p;
3808 +
3809 + fsg->gadget = gadget;
3810 + set_gadget_data(gadget, fsg);
3811 + fsg->ep0 = gadget->ep0;
3812 + fsg->ep0->driver_data = fsg;
3813 +
3814 + if ((rc = check_parameters(fsg)) != 0)
3815 + goto out;
3816 +
3817 + if (mod_data.removable) { // Enable the store_xxx attributes
3818 + dev_attr_file.attr.mode = 0644;
3819 + dev_attr_file.store = fsg_store_file;
3820 + if (!mod_data.cdrom) {
3821 + dev_attr_ro.attr.mode = 0644;
3822 + dev_attr_ro.store = fsg_store_ro;
3823 + }
3824 + }
3825 +
3826 + /* Only for removable media? */
3827 + dev_attr_nofua.attr.mode = 0644;
3828 + dev_attr_nofua.store = fsg_store_nofua;
3829 +
3830 + /* Find out how many LUNs there should be */
3831 + i = mod_data.nluns;
3832 + if (i == 0)
3833 + i = max(mod_data.num_filenames, 1u);
3834 + if (i > FSG_MAX_LUNS) {
3835 + ERROR(fsg, "invalid number of LUNs: %d\n", i);
3836 + rc = -EINVAL;
3837 + goto out;
3838 + }
3839 +
3840 + /* Create the LUNs, open their backing files, and register the
3841 + * LUN devices in sysfs. */
3842 + fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL);
3843 + if (!fsg->luns) {
3844 + rc = -ENOMEM;
3845 + goto out;
3846 + }
3847 + fsg->nluns = i;
3848 +
3849 + for (i = 0; i < fsg->nluns; ++i) {
3850 + curlun = &fsg->luns[i];
3851 + curlun->cdrom = !!mod_data.cdrom;
3852 + curlun->ro = mod_data.cdrom || mod_data.ro[i];
3853 + curlun->initially_ro = curlun->ro;
3854 + curlun->removable = mod_data.removable;
3855 + curlun->nofua = mod_data.nofua[i];
3856 + curlun->dev.release = lun_release;
3857 + curlun->dev.parent = &gadget->dev;
3858 + curlun->dev.driver = &fsg_driver.driver;
3859 + dev_set_drvdata(&curlun->dev, &fsg->filesem);
3860 + dev_set_name(&curlun->dev,"%s-lun%d",
3861 + dev_name(&gadget->dev), i);
3862 +
3863 + kref_get(&fsg->ref);
3864 + rc = device_register(&curlun->dev);
3865 + if (rc) {
3866 + INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
3867 + put_device(&curlun->dev);
3868 + goto out;
3869 + }
3870 + curlun->registered = 1;
3871 +
3872 + rc = device_create_file(&curlun->dev, &dev_attr_ro);
3873 + if (rc)
3874 + goto out;
3875 + rc = device_create_file(&curlun->dev, &dev_attr_nofua);
3876 + if (rc)
3877 + goto out;
3878 + rc = device_create_file(&curlun->dev, &dev_attr_file);
3879 + if (rc)
3880 + goto out;
3881 +
3882 + if (mod_data.file[i] && *mod_data.file[i]) {
3883 + rc = fsg_lun_open(curlun, mod_data.file[i]);
3884 + if (rc)
3885 + goto out;
3886 + } else if (!mod_data.removable) {
3887 + ERROR(fsg, "no file given for LUN%d\n", i);
3888 + rc = -EINVAL;
3889 + goto out;
3890 + }
3891 + }
3892 +
3893 + /* Find all the endpoints we will use */
3894 + usb_ep_autoconfig_reset(gadget);
3895 + ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
3896 + if (!ep)
3897 + goto autoconf_fail;
3898 + ep->driver_data = fsg; // claim the endpoint
3899 + fsg->bulk_in = ep;
3900 +
3901 + ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
3902 + if (!ep)
3903 + goto autoconf_fail;
3904 + ep->driver_data = fsg; // claim the endpoint
3905 + fsg->bulk_out = ep;
3906 +
3907 + if (transport_is_cbi()) {
3908 + ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc);
3909 + if (!ep)
3910 + goto autoconf_fail;
3911 + ep->driver_data = fsg; // claim the endpoint
3912 + fsg->intr_in = ep;
3913 + }
3914 +
3915 + /* Fix up the descriptors */
3916 + device_desc.idVendor = cpu_to_le16(mod_data.vendor);
3917 + device_desc.idProduct = cpu_to_le16(mod_data.product);
3918 + device_desc.bcdDevice = cpu_to_le16(mod_data.release);
3919 +
3920 + i = (transport_is_cbi() ? 3 : 2); // Number of endpoints
3921 + fsg_intf_desc.bNumEndpoints = i;
3922 + fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type;
3923 + fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type;
3924 + fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
3925 +
3926 + if (gadget_is_dualspeed(gadget)) {
3927 + fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
3928 +
3929 + /* Assume endpoint addresses are the same for both speeds */
3930 + fsg_hs_bulk_in_desc.bEndpointAddress =
3931 + fsg_fs_bulk_in_desc.bEndpointAddress;
3932 + fsg_hs_bulk_out_desc.bEndpointAddress =
3933 + fsg_fs_bulk_out_desc.bEndpointAddress;
3934 + fsg_hs_intr_in_desc.bEndpointAddress =
3935 + fsg_fs_intr_in_desc.bEndpointAddress;
3936 + }
3937 +
3938 + if (gadget_is_superspeed(gadget)) {
3939 + unsigned max_burst;
3940 +
3941 + fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL;
3942 +
3943 + /* Calculate bMaxBurst, we know packet size is 1024 */
3944 + max_burst = min_t(unsigned, mod_data.buflen / 1024, 15);
3945 +
3946 + /* Assume endpoint addresses are the same for both speeds */
3947 + fsg_ss_bulk_in_desc.bEndpointAddress =
3948 + fsg_fs_bulk_in_desc.bEndpointAddress;
3949 + fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
3950 +
3951 + fsg_ss_bulk_out_desc.bEndpointAddress =
3952 + fsg_fs_bulk_out_desc.bEndpointAddress;
3953 + fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
3954 + }
3955 +
3956 + if (gadget_is_otg(gadget))
3957 + fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
3958 +
3959 + rc = -ENOMEM;
3960 +
3961 + /* Allocate the request and buffer for endpoint 0 */
3962 + fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
3963 + if (!req)
3964 + goto out;
3965 + req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL);
3966 + if (!req->buf)
3967 + goto out;
3968 + req->complete = ep0_complete;
3969 +
3970 + /* Allocate the data buffers */
3971 + for (i = 0; i < fsg_num_buffers; ++i) {
3972 + struct fsg_buffhd *bh = &fsg->buffhds[i];
3973 +
3974 + /* Allocate for the bulk-in endpoint. We assume that
3975 + * the buffer will also work with the bulk-out (and
3976 + * interrupt-in) endpoint. */
3977 + bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL);
3978 + if (!bh->buf)
3979 + goto out;
3980 + bh->next = bh + 1;
3981 + }
3982 + fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0];
3983 +
3984 + /* This should reflect the actual gadget power source */
3985 + usb_gadget_set_selfpowered(gadget);
3986 +
3987 + snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer,
3988 + "%s %s with %s",
3989 + init_utsname()->sysname, init_utsname()->release,
3990 + gadget->name);
3991 +
3992 + fsg->thread_task = kthread_create(fsg_main_thread, fsg,
3993 + "file-storage-gadget");
3994 + if (IS_ERR(fsg->thread_task)) {
3995 + rc = PTR_ERR(fsg->thread_task);
3996 + goto out;
3997 + }
3998 +
3999 + INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
4000 + INFO(fsg, "NOTE: This driver is deprecated. "
4001 + "Consider using g_mass_storage instead.\n");
4002 + INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
4003 +
4004 + pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
4005 + for (i = 0; i < fsg->nluns; ++i) {
4006 + curlun = &fsg->luns[i];
4007 + if (fsg_lun_is_open(curlun)) {
4008 + p = NULL;
4009 + if (pathbuf) {
4010 + p = d_path(&curlun->filp->f_path,
4011 + pathbuf, PATH_MAX);
4012 + if (IS_ERR(p))
4013 + p = NULL;
4014 + }
4015 + LINFO(curlun, "ro=%d, nofua=%d, file: %s\n",
4016 + curlun->ro, curlun->nofua, (p ? p : "(error)"));
4017 + }
4018 + }
4019 + kfree(pathbuf);
4020 +
4021 + DBG(fsg, "transport=%s (x%02x)\n",
4022 + mod_data.transport_name, mod_data.transport_type);
4023 + DBG(fsg, "protocol=%s (x%02x)\n",
4024 + mod_data.protocol_name, mod_data.protocol_type);
4025 + DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n",
4026 + mod_data.vendor, mod_data.product, mod_data.release);
4027 + DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n",
4028 + mod_data.removable, mod_data.can_stall,
4029 + mod_data.cdrom, mod_data.buflen);
4030 + DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
4031 +
4032 + set_bit(REGISTERED, &fsg->atomic_bitflags);
4033 +
4034 + /* Tell the thread to start working */
4035 + wake_up_process(fsg->thread_task);
4036 + return 0;
4037 +
4038 +autoconf_fail:
4039 + ERROR(fsg, "unable to autoconfigure all endpoints\n");
4040 + rc = -ENOTSUPP;
4041 +
4042 +out:
4043 + fsg->state = FSG_STATE_TERMINATED; // The thread is dead
4044 + fsg_unbind(gadget);
4045 + complete(&fsg->thread_notifier);
4046 + return rc;
4047 +}
4048 +
4049 +
4050 +/*-------------------------------------------------------------------------*/
4051 +
4052 +static void fsg_suspend(struct usb_gadget *gadget)
4053 +{
4054 + struct fsg_dev *fsg = get_gadget_data(gadget);
4055 +
4056 + DBG(fsg, "suspend\n");
4057 + set_bit(SUSPENDED, &fsg->atomic_bitflags);
4058 +}
4059 +
4060 +static void fsg_resume(struct usb_gadget *gadget)
4061 +{
4062 + struct fsg_dev *fsg = get_gadget_data(gadget);
4063 +
4064 + DBG(fsg, "resume\n");
4065 + clear_bit(SUSPENDED, &fsg->atomic_bitflags);
4066 +}
4067 +
4068 +
4069 +/*-------------------------------------------------------------------------*/
4070 +
4071 +static struct usb_gadget_driver fsg_driver = {
4072 + .max_speed = USB_SPEED_SUPER,
4073 + .function = (char *) fsg_string_product,
4074 + .unbind = fsg_unbind,
4075 + .disconnect = fsg_disconnect,
4076 + .setup = fsg_setup,
4077 + .suspend = fsg_suspend,
4078 + .resume = fsg_resume,
4079 +
4080 + .driver = {
4081 + .name = DRIVER_NAME,
4082 + .owner = THIS_MODULE,
4083 + // .release = ...
4084 + // .suspend = ...
4085 + // .resume = ...
4086 + },
4087 +};
4088 +
4089 +
4090 +static int __init fsg_alloc(void)
4091 +{
4092 + struct fsg_dev *fsg;
4093 +
4094 + fsg = kzalloc(sizeof *fsg +
4095 + fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL);
4096 +
4097 + if (!fsg)
4098 + return -ENOMEM;
4099 + spin_lock_init(&fsg->lock);
4100 + init_rwsem(&fsg->filesem);
4101 + kref_init(&fsg->ref);
4102 + init_completion(&fsg->thread_notifier);
4103 +
4104 + the_fsg = fsg;
4105 + return 0;
4106 +}
4107 +
4108 +
4109 +static int __init fsg_init(void)
4110 +{
4111 + int rc;
4112 + struct fsg_dev *fsg;
4113 +
4114 + rc = fsg_num_buffers_validate();
4115 + if (rc != 0)
4116 + return rc;
4117 +
4118 + if ((rc = fsg_alloc()) != 0)
4119 + return rc;
4120 + fsg = the_fsg;
4121 + if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0)
4122 + kref_put(&fsg->ref, fsg_release);
4123 + return rc;
4124 +}
4125 +module_init(fsg_init);
4126 +
4127 +
4128 +static void __exit fsg_cleanup(void)
4129 +{
4130 + struct fsg_dev *fsg = the_fsg;
4131 +
4132 + /* Unregister the driver iff the thread hasn't already done so */
4133 + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
4134 + usb_gadget_unregister_driver(&fsg_driver);
4135 +
4136 + /* Wait for the thread to finish up */
4137 + wait_for_completion(&fsg->thread_notifier);
4138 +
4139 + kref_put(&fsg->ref, fsg_release);
4140 +}
4141 +module_exit(fsg_cleanup);
4142 diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
4143 index a9707da..e252b95 100644
4144 --- a/drivers/usb/host/Kconfig
4145 +++ b/drivers/usb/host/Kconfig
4146 @@ -689,6 +689,19 @@ config USB_HWA_HCD
4147 To compile this driver a module, choose M here: the module
4148 will be called "hwa-hc".
4149
4150 +config USB_DWCOTG
4151 + tristate "Synopsis DWC host support"
4152 + depends on USB
4153 + help
4154 + The Synopsis DWC controller is a dual-role
4155 + host/peripheral/OTG ("On The Go") USB controllers.
4156 +
4157 + Enable this option to support this IP in host controller mode.
4158 + If unsure, say N.
4159 +
4160 + To compile this driver as a module, choose M here: the
4161 + modules built will be called dwc_otg and dwc_common_port.
4162 +
4163 config USB_IMX21_HCD
4164 tristate "i.MX21 HCD support"
4165 depends on ARM && ARCH_MXC
4166 diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
4167 index 7530468..876f024 100644
4168 --- a/drivers/usb/host/Makefile
4169 +++ b/drivers/usb/host/Makefile
4170 @@ -63,6 +63,8 @@ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
4171 obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
4172 obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
4173 obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
4174 +
4175 +obj-$(CONFIG_USB_DWCOTG) += dwc_otg/ dwc_common_port/
4176 obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
4177 obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
4178 obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
4179 diff --git a/drivers/usb/host/dwc_common_port/Makefile b/drivers/usb/host/dwc_common_port/Makefile
4180 new file mode 100644
4181 index 0000000..f10d466
4182 --- /dev/null
4183 +++ b/drivers/usb/host/dwc_common_port/Makefile
4184 @@ -0,0 +1,58 @@
4185 +#
4186 +# Makefile for DWC_common library
4187 +#
4188 +
4189 +ifneq ($(KERNELRELEASE),)
4190 +
4191 +ccflags-y += -DDWC_LINUX
4192 +#ccflags-y += -DDEBUG
4193 +#ccflags-y += -DDWC_DEBUG_REGS
4194 +#ccflags-y += -DDWC_DEBUG_MEMORY
4195 +
4196 +ccflags-y += -DDWC_LIBMODULE
4197 +ccflags-y += -DDWC_CCLIB
4198 +#ccflags-y += -DDWC_CRYPTOLIB
4199 +ccflags-y += -DDWC_NOTIFYLIB
4200 +ccflags-y += -DDWC_UTFLIB
4201 +
4202 +obj-$(CONFIG_USB_DWCOTG) += dwc_common_port_lib.o
4203 +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
4204 + dwc_crypto.o dwc_notifier.o \
4205 + dwc_common_linux.o dwc_mem.o
4206 +
4207 +kernrelwd := $(subst ., ,$(KERNELRELEASE))
4208 +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
4209 +
4210 +ifneq ($(kernrel3),2.6.20)
4211 +# grayg - I only know that we use ccflags-y in 2.6.31 actually
4212 +ccflags-y += $(CPPFLAGS)
4213 +endif
4214 +
4215 +else
4216 +
4217 +#ifeq ($(KDIR),)
4218 +#$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
4219 +#endif
4220 +
4221 +ifeq ($(ARCH),)
4222 +$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
4223 + cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
4224 +endif
4225 +
4226 +ifeq ($(DOXYGEN),)
4227 +DOXYGEN := doxygen
4228 +endif
4229 +
4230 +default:
4231 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
4232 +
4233 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
4234 + $(DOXYGEN) doc/doxygen.cfg
4235 +
4236 +tags: $(wildcard *.[hc])
4237 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
4238 +
4239 +endif
4240 +
4241 +clean:
4242 + rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
4243 diff --git a/drivers/usb/host/dwc_common_port/Makefile.fbsd b/drivers/usb/host/dwc_common_port/Makefile.fbsd
4244 new file mode 100644
4245 index 0000000..45db991
4246 --- /dev/null
4247 +++ b/drivers/usb/host/dwc_common_port/Makefile.fbsd
4248 @@ -0,0 +1,17 @@
4249 +CFLAGS += -I/sys/i386/compile/GENERIC -I/sys/i386/include -I/usr/include
4250 +CFLAGS += -DDWC_FREEBSD
4251 +CFLAGS += -DDEBUG
4252 +#CFLAGS += -DDWC_DEBUG_REGS
4253 +#CFLAGS += -DDWC_DEBUG_MEMORY
4254 +
4255 +#CFLAGS += -DDWC_LIBMODULE
4256 +#CFLAGS += -DDWC_CCLIB
4257 +#CFLAGS += -DDWC_CRYPTOLIB
4258 +#CFLAGS += -DDWC_NOTIFYLIB
4259 +#CFLAGS += -DDWC_UTFLIB
4260 +
4261 +KMOD = dwc_common_port_lib
4262 +SRCS = dwc_cc.c dwc_modpow.c dwc_dh.c dwc_crypto.c dwc_notifier.c \
4263 + dwc_common_fbsd.c dwc_mem.c
4264 +
4265 +.include <bsd.kmod.mk>
4266 diff --git a/drivers/usb/host/dwc_common_port/Makefile.linux b/drivers/usb/host/dwc_common_port/Makefile.linux
4267 new file mode 100644
4268 index 0000000..0cef7b4
4269 --- /dev/null
4270 +++ b/drivers/usb/host/dwc_common_port/Makefile.linux
4271 @@ -0,0 +1,49 @@
4272 +#
4273 +# Makefile for DWC_common library
4274 +#
4275 +ifneq ($(KERNELRELEASE),)
4276 +
4277 +ccflags-y += -DDWC_LINUX
4278 +#ccflags-y += -DDEBUG
4279 +#ccflags-y += -DDWC_DEBUG_REGS
4280 +#ccflags-y += -DDWC_DEBUG_MEMORY
4281 +
4282 +ccflags-y += -DDWC_LIBMODULE
4283 +ccflags-y += -DDWC_CCLIB
4284 +ccflags-y += -DDWC_CRYPTOLIB
4285 +ccflags-y += -DDWC_NOTIFYLIB
4286 +ccflags-y += -DDWC_UTFLIB
4287 +
4288 +obj-m := dwc_common_port_lib.o
4289 +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
4290 + dwc_crypto.o dwc_notifier.o \
4291 + dwc_common_linux.o dwc_mem.o
4292 +
4293 +else
4294 +
4295 +ifeq ($(KDIR),)
4296 +$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
4297 +endif
4298 +
4299 +ifeq ($(ARCH),)
4300 +$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
4301 + cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
4302 +endif
4303 +
4304 +ifeq ($(DOXYGEN),)
4305 +DOXYGEN := doxygen
4306 +endif
4307 +
4308 +default:
4309 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
4310 +
4311 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
4312 + $(DOXYGEN) doc/doxygen.cfg
4313 +
4314 +tags: $(wildcard *.[hc])
4315 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
4316 +
4317 +endif
4318 +
4319 +clean:
4320 + rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
4321 diff --git a/drivers/usb/host/dwc_common_port/changes.txt b/drivers/usb/host/dwc_common_port/changes.txt
4322 new file mode 100644
4323 index 0000000..f6839f9
4324 --- /dev/null
4325 +++ b/drivers/usb/host/dwc_common_port/changes.txt
4326 @@ -0,0 +1,174 @@
4327 +
4328 +dwc_read_reg32() and friends now take an additional parameter, a pointer to an
4329 +IO context struct. The IO context struct should live in an os-dependent struct
4330 +in your driver. As an example, the dwc_usb3 driver has an os-dependent struct
4331 +named 'os_dep' embedded in the main device struct. So there these calls look
4332 +like this:
4333 +
4334 + dwc_read_reg32(&usb3_dev->os_dep.ioctx, &pcd->dev_global_regs->dcfg);
4335 +
4336 + dwc_write_reg32(&usb3_dev->os_dep.ioctx,
4337 + &pcd->dev_global_regs->dcfg, 0);
4338 +
4339 +Note that for the existing Linux driver ports, it is not necessary to actually
4340 +define the 'ioctx' member in the os-dependent struct. Since Linux does not
4341 +require an IO context, its macros for dwc_read_reg32() and friends do not
4342 +use the context pointer, so it is optimized away by the compiler. But it is
4343 +necessary to add the pointer parameter to all of the call sites, to be ready
4344 +for any future ports (such as FreeBSD) which do require an IO context.
4345 +
4346 +
4347 +Similarly, dwc_alloc(), dwc_alloc_atomic(), dwc_strdup(), and dwc_free() now
4348 +take an additional parameter, a pointer to a memory context. Examples:
4349 +
4350 + addr = dwc_alloc(&usb3_dev->os_dep.memctx, size);
4351 +
4352 + dwc_free(&usb3_dev->os_dep.memctx, addr);
4353 +
4354 +Again, for the Linux ports, it is not necessary to actually define the memctx
4355 +member, but it is necessary to add the pointer parameter to all of the call
4356 +sites.
4357 +
4358 +
4359 +Same for dwc_dma_alloc() and dwc_dma_free(). Examples:
4360 +
4361 + virt_addr = dwc_dma_alloc(&usb3_dev->os_dep.dmactx, size, &phys_addr);
4362 +
4363 + dwc_dma_free(&usb3_dev->os_dep.dmactx, size, virt_addr, phys_addr);
4364 +
4365 +
4366 +Same for dwc_mutex_alloc() and dwc_mutex_free(). Examples:
4367 +
4368 + mutex = dwc_mutex_alloc(&usb3_dev->os_dep.mtxctx);
4369 +
4370 + dwc_mutex_free(&usb3_dev->os_dep.mtxctx, mutex);
4371 +
4372 +
4373 +Same for dwc_spinlock_alloc() and dwc_spinlock_free(). Examples:
4374 +
4375 + lock = dwc_spinlock_alloc(&usb3_dev->osdep.splctx);
4376 +
4377 + dwc_spinlock_free(&usb3_dev->osdep.splctx, lock);
4378 +
4379 +
4380 +Same for dwc_timer_alloc(). Example:
4381 +
4382 + timer = dwc_timer_alloc(&usb3_dev->os_dep.tmrctx, "dwc_usb3_tmr1",
4383 + cb_func, cb_data);
4384 +
4385 +
4386 +Same for dwc_waitq_alloc(). Example:
4387 +
4388 + waitq = dwc_waitq_alloc(&usb3_dev->os_dep.wtqctx);
4389 +
4390 +
4391 +Same for dwc_thread_run(). Example:
4392 +
4393 + thread = dwc_thread_run(&usb3_dev->os_dep.thdctx, func,
4394 + "dwc_usb3_thd1", data);
4395 +
4396 +
4397 +Same for dwc_workq_alloc(). Example:
4398 +
4399 + workq = dwc_workq_alloc(&usb3_dev->osdep.wkqctx, "dwc_usb3_wkq1");
4400 +
4401 +
4402 +Same for dwc_task_alloc(). Example:
4403 +
4404 + task = dwc_task_alloc(&usb3_dev->os_dep.tskctx, "dwc_usb3_tsk1",
4405 + cb_func, cb_data);
4406 +
4407 +
4408 +In addition to the context pointer additions, a few core functions have had
4409 +other changes made to their parameters:
4410 +
4411 +The 'flags' parameter to dwc_spinlock_irqsave() and dwc_spinunlock_irqrestore()
4412 +has been changed from a uint64_t to a dwc_irqflags_t.
4413 +
4414 +dwc_thread_should_stop() now takes a 'dwc_thread_t *' parameter, because the
4415 +FreeBSD equivalent of that function requires it.
4416 +
4417 +And, in addition to the context pointer, dwc_task_alloc() also adds a
4418 +'char *name' parameter, to be consistent with dwc_thread_run() and
4419 +dwc_workq_alloc(), and because the FreeBSD equivalent of that function
4420 +requires a unique name.
4421 +
4422 +
4423 +Here is a complete list of the core functions that now take a pointer to a
4424 +context as their first parameter:
4425 +
4426 + dwc_read_reg32
4427 + dwc_read_reg64
4428 + dwc_write_reg32
4429 + dwc_write_reg64
4430 + dwc_modify_reg32
4431 + dwc_modify_reg64
4432 + dwc_alloc
4433 + dwc_alloc_atomic
4434 + dwc_strdup
4435 + dwc_free
4436 + dwc_dma_alloc
4437 + dwc_dma_free
4438 + dwc_mutex_alloc
4439 + dwc_mutex_free
4440 + dwc_spinlock_alloc
4441 + dwc_spinlock_free
4442 + dwc_timer_alloc
4443 + dwc_waitq_alloc
4444 + dwc_thread_run
4445 + dwc_workq_alloc
4446 + dwc_task_alloc Also adds a 'char *name' as its 2nd parameter
4447 +
4448 +And here are the core functions that have other changes to their parameters:
4449 +
4450 + dwc_spinlock_irqsave 'flags' param is now a 'dwc_irqflags_t *'
4451 + dwc_spinunlock_irqrestore 'flags' param is now a 'dwc_irqflags_t'
4452 + dwc_thread_should_stop Adds a 'dwc_thread_t *' parameter
4453 +
4454 +
4455 +
4456 +The changes to the core functions also require some of the other library
4457 +functions to change:
4458 +
4459 + dwc_cc_if_alloc() and dwc_cc_if_free() now take a 'void *memctx'
4460 + (for memory allocation) as the 1st param and a 'void *mtxctx'
4461 + (for mutex allocation) as the 2nd param.
4462 +
4463 + dwc_cc_clear(), dwc_cc_add(), dwc_cc_change(), dwc_cc_remove(),
4464 + dwc_cc_data_for_save(), and dwc_cc_restore_from_data() now take a
4465 + 'void *memctx' as the 1st param.
4466 +
4467 + dwc_dh_modpow(), dwc_dh_pk(), and dwc_dh_derive_keys() now take a
4468 + 'void *memctx' as the 1st param.
4469 +
4470 + dwc_modpow() now takes a 'void *memctx' as the 1st param.
4471 +
4472 + dwc_alloc_notification_manager() now takes a 'void *memctx' as the
4473 + 1st param and a 'void *wkqctx' (for work queue allocation) as the 2nd
4474 + param, and also now returns an integer value that is non-zero if
4475 + allocation of its data structures or work queue fails.
4476 +
4477 + dwc_register_notifier() now takes a 'void *memctx' as the 1st param.
4478 +
4479 + dwc_memory_debug_start() now takes a 'void *mem_ctx' as the first
4480 + param, and also now returns an integer value that is non-zero if
4481 + allocation of its data structures fails.
4482 +
4483 +
4484 +
4485 +Other miscellaneous changes:
4486 +
4487 +The DEBUG_MEMORY and DEBUG_REGS #define's have been renamed to
4488 +DWC_DEBUG_MEMORY and DWC_DEBUG_REGS.
4489 +
4490 +The following #define's have been added to allow selectively compiling library
4491 +features:
4492 +
4493 + DWC_CCLIB
4494 + DWC_CRYPTOLIB
4495 + DWC_NOTIFYLIB
4496 + DWC_UTFLIB
4497 +
4498 +A DWC_LIBMODULE #define has also been added. If this is not defined, then the
4499 +module code in dwc_common_linux.c is not compiled in. This allows linking the
4500 +library code directly into a driver module, instead of as a standalone module.
4501 diff --git a/drivers/usb/host/dwc_common_port/doc/doxygen.cfg b/drivers/usb/host/dwc_common_port/doc/doxygen.cfg
4502 new file mode 100644
4503 index 0000000..89aa887
4504 --- /dev/null
4505 +++ b/drivers/usb/host/dwc_common_port/doc/doxygen.cfg
4506 @@ -0,0 +1,270 @@
4507 +# Doxyfile 1.4.5
4508 +
4509 +#---------------------------------------------------------------------------
4510 +# Project related configuration options
4511 +#---------------------------------------------------------------------------
4512 +PROJECT_NAME = "Synopsys DWC Portability and Common Library for UWB"
4513 +PROJECT_NUMBER =
4514 +OUTPUT_DIRECTORY = doc
4515 +CREATE_SUBDIRS = NO
4516 +OUTPUT_LANGUAGE = English
4517 +BRIEF_MEMBER_DESC = YES
4518 +REPEAT_BRIEF = YES
4519 +ABBREVIATE_BRIEF = "The $name class" \
4520 + "The $name widget" \
4521 + "The $name file" \
4522 + is \
4523 + provides \
4524 + specifies \
4525 + contains \
4526 + represents \
4527 + a \
4528 + an \
4529 + the
4530 +ALWAYS_DETAILED_SEC = YES
4531 +INLINE_INHERITED_MEMB = NO
4532 +FULL_PATH_NAMES = NO
4533 +STRIP_FROM_PATH = ..
4534 +STRIP_FROM_INC_PATH =
4535 +SHORT_NAMES = NO
4536 +JAVADOC_AUTOBRIEF = YES
4537 +MULTILINE_CPP_IS_BRIEF = NO
4538 +DETAILS_AT_TOP = YES
4539 +INHERIT_DOCS = YES
4540 +SEPARATE_MEMBER_PAGES = NO
4541 +TAB_SIZE = 8
4542 +ALIASES =
4543 +OPTIMIZE_OUTPUT_FOR_C = YES
4544 +OPTIMIZE_OUTPUT_JAVA = NO
4545 +BUILTIN_STL_SUPPORT = NO
4546 +DISTRIBUTE_GROUP_DOC = NO
4547 +SUBGROUPING = NO
4548 +#---------------------------------------------------------------------------
4549 +# Build related configuration options
4550 +#---------------------------------------------------------------------------
4551 +EXTRACT_ALL = NO
4552 +EXTRACT_PRIVATE = NO
4553 +EXTRACT_STATIC = YES
4554 +EXTRACT_LOCAL_CLASSES = NO
4555 +EXTRACT_LOCAL_METHODS = NO
4556 +HIDE_UNDOC_MEMBERS = NO
4557 +HIDE_UNDOC_CLASSES = NO
4558 +HIDE_FRIEND_COMPOUNDS = NO
4559 +HIDE_IN_BODY_DOCS = NO
4560 +INTERNAL_DOCS = NO
4561 +CASE_SENSE_NAMES = YES
4562 +HIDE_SCOPE_NAMES = NO
4563 +SHOW_INCLUDE_FILES = NO
4564 +INLINE_INFO = YES
4565 +SORT_MEMBER_DOCS = NO
4566 +SORT_BRIEF_DOCS = NO
4567 +SORT_BY_SCOPE_NAME = NO
4568 +GENERATE_TODOLIST = YES
4569 +GENERATE_TESTLIST = YES
4570 +GENERATE_BUGLIST = YES
4571 +GENERATE_DEPRECATEDLIST= YES
4572 +ENABLED_SECTIONS =
4573 +MAX_INITIALIZER_LINES = 30
4574 +SHOW_USED_FILES = YES
4575 +SHOW_DIRECTORIES = YES
4576 +FILE_VERSION_FILTER =
4577 +#---------------------------------------------------------------------------
4578 +# configuration options related to warning and progress messages
4579 +#---------------------------------------------------------------------------
4580 +QUIET = YES
4581 +WARNINGS = YES
4582 +WARN_IF_UNDOCUMENTED = NO
4583 +WARN_IF_DOC_ERROR = YES
4584 +WARN_NO_PARAMDOC = YES
4585 +WARN_FORMAT = "$file:$line: $text"
4586 +WARN_LOGFILE =
4587 +#---------------------------------------------------------------------------
4588 +# configuration options related to the input files
4589 +#---------------------------------------------------------------------------
4590 +INPUT = .
4591 +FILE_PATTERNS = *.c \
4592 + *.cc \
4593 + *.cxx \
4594 + *.cpp \
4595 + *.c++ \
4596 + *.d \
4597 + *.java \
4598 + *.ii \
4599 + *.ixx \
4600 + *.ipp \
4601 + *.i++ \
4602 + *.inl \
4603 + *.h \
4604 + *.hh \
4605 + *.hxx \
4606 + *.hpp \
4607 + *.h++ \
4608 + *.idl \
4609 + *.odl \
4610 + *.cs \
4611 + *.php \
4612 + *.php3 \
4613 + *.inc \
4614 + *.m \
4615 + *.mm \
4616 + *.dox \
4617 + *.py \
4618 + *.C \
4619 + *.CC \
4620 + *.C++ \
4621 + *.II \
4622 + *.I++ \
4623 + *.H \
4624 + *.HH \
4625 + *.H++ \
4626 + *.CS \
4627 + *.PHP \
4628 + *.PHP3 \
4629 + *.M \
4630 + *.MM \
4631 + *.PY
4632 +RECURSIVE = NO
4633 +EXCLUDE =
4634 +EXCLUDE_SYMLINKS = NO
4635 +EXCLUDE_PATTERNS =
4636 +EXAMPLE_PATH =
4637 +EXAMPLE_PATTERNS = *
4638 +EXAMPLE_RECURSIVE = NO
4639 +IMAGE_PATH =
4640 +INPUT_FILTER =
4641 +FILTER_PATTERNS =
4642 +FILTER_SOURCE_FILES = NO
4643 +#---------------------------------------------------------------------------
4644 +# configuration options related to source browsing
4645 +#---------------------------------------------------------------------------
4646 +SOURCE_BROWSER = NO
4647 +INLINE_SOURCES = NO
4648 +STRIP_CODE_COMMENTS = YES
4649 +REFERENCED_BY_RELATION = YES
4650 +REFERENCES_RELATION = YES
4651 +USE_HTAGS = NO
4652 +VERBATIM_HEADERS = NO
4653 +#---------------------------------------------------------------------------
4654 +# configuration options related to the alphabetical class index
4655 +#---------------------------------------------------------------------------
4656 +ALPHABETICAL_INDEX = NO
4657 +COLS_IN_ALPHA_INDEX = 5
4658 +IGNORE_PREFIX =
4659 +#---------------------------------------------------------------------------
4660 +# configuration options related to the HTML output
4661 +#---------------------------------------------------------------------------
4662 +GENERATE_HTML = YES
4663 +HTML_OUTPUT = html
4664 +HTML_FILE_EXTENSION = .html
4665 +HTML_HEADER =
4666 +HTML_FOOTER =
4667 +HTML_STYLESHEET =
4668 +HTML_ALIGN_MEMBERS = YES
4669 +GENERATE_HTMLHELP = NO
4670 +CHM_FILE =
4671 +HHC_LOCATION =
4672 +GENERATE_CHI = NO
4673 +BINARY_TOC = NO
4674 +TOC_EXPAND = NO
4675 +DISABLE_INDEX = NO
4676 +ENUM_VALUES_PER_LINE = 4
4677 +GENERATE_TREEVIEW = YES
4678 +TREEVIEW_WIDTH = 250
4679 +#---------------------------------------------------------------------------
4680 +# configuration options related to the LaTeX output
4681 +#---------------------------------------------------------------------------
4682 +GENERATE_LATEX = NO
4683 +LATEX_OUTPUT = latex
4684 +LATEX_CMD_NAME = latex
4685 +MAKEINDEX_CMD_NAME = makeindex
4686 +COMPACT_LATEX = NO
4687 +PAPER_TYPE = a4wide
4688 +EXTRA_PACKAGES =
4689 +LATEX_HEADER =
4690 +PDF_HYPERLINKS = NO
4691 +USE_PDFLATEX = NO
4692 +LATEX_BATCHMODE = NO
4693 +LATEX_HIDE_INDICES = NO
4694 +#---------------------------------------------------------------------------
4695 +# configuration options related to the RTF output
4696 +#---------------------------------------------------------------------------
4697 +GENERATE_RTF = NO
4698 +RTF_OUTPUT = rtf
4699 +COMPACT_RTF = NO
4700 +RTF_HYPERLINKS = NO
4701 +RTF_STYLESHEET_FILE =
4702 +RTF_EXTENSIONS_FILE =
4703 +#---------------------------------------------------------------------------
4704 +# configuration options related to the man page output
4705 +#---------------------------------------------------------------------------
4706 +GENERATE_MAN = NO
4707 +MAN_OUTPUT = man
4708 +MAN_EXTENSION = .3
4709 +MAN_LINKS = NO
4710 +#---------------------------------------------------------------------------
4711 +# configuration options related to the XML output
4712 +#---------------------------------------------------------------------------
4713 +GENERATE_XML = NO
4714 +XML_OUTPUT = xml
4715 +XML_SCHEMA =
4716 +XML_DTD =
4717 +XML_PROGRAMLISTING = YES
4718 +#---------------------------------------------------------------------------
4719 +# configuration options for the AutoGen Definitions output
4720 +#---------------------------------------------------------------------------
4721 +GENERATE_AUTOGEN_DEF = NO
4722 +#---------------------------------------------------------------------------
4723 +# configuration options related to the Perl module output
4724 +#---------------------------------------------------------------------------
4725 +GENERATE_PERLMOD = NO
4726 +PERLMOD_LATEX = NO
4727 +PERLMOD_PRETTY = YES
4728 +PERLMOD_MAKEVAR_PREFIX =
4729 +#---------------------------------------------------------------------------
4730 +# Configuration options related to the preprocessor
4731 +#---------------------------------------------------------------------------
4732 +ENABLE_PREPROCESSING = YES
4733 +MACRO_EXPANSION = NO
4734 +EXPAND_ONLY_PREDEF = NO
4735 +SEARCH_INCLUDES = YES
4736 +INCLUDE_PATH =
4737 +INCLUDE_FILE_PATTERNS =
4738 +PREDEFINED = DEBUG DEBUG_MEMORY
4739 +EXPAND_AS_DEFINED =
4740 +SKIP_FUNCTION_MACROS = YES
4741 +#---------------------------------------------------------------------------
4742 +# Configuration::additions related to external references
4743 +#---------------------------------------------------------------------------
4744 +TAGFILES =
4745 +GENERATE_TAGFILE =
4746 +ALLEXTERNALS = NO
4747 +EXTERNAL_GROUPS = YES
4748 +PERL_PATH = /usr/bin/perl
4749 +#---------------------------------------------------------------------------
4750 +# Configuration options related to the dot tool
4751 +#---------------------------------------------------------------------------
4752 +CLASS_DIAGRAMS = YES
4753 +HIDE_UNDOC_RELATIONS = YES
4754 +HAVE_DOT = NO
4755 +CLASS_GRAPH = YES
4756 +COLLABORATION_GRAPH = YES
4757 +GROUP_GRAPHS = YES
4758 +UML_LOOK = NO
4759 +TEMPLATE_RELATIONS = NO
4760 +INCLUDE_GRAPH = NO
4761 +INCLUDED_BY_GRAPH = YES
4762 +CALL_GRAPH = NO
4763 +GRAPHICAL_HIERARCHY = YES
4764 +DIRECTORY_GRAPH = YES
4765 +DOT_IMAGE_FORMAT = png
4766 +DOT_PATH =
4767 +DOTFILE_DIRS =
4768 +MAX_DOT_GRAPH_DEPTH = 1000
4769 +DOT_TRANSPARENT = NO
4770 +DOT_MULTI_TARGETS = NO
4771 +GENERATE_LEGEND = YES
4772 +DOT_CLEANUP = YES
4773 +#---------------------------------------------------------------------------
4774 +# Configuration::additions related to the search engine
4775 +#---------------------------------------------------------------------------
4776 +SEARCHENGINE = NO
4777 diff --git a/drivers/usb/host/dwc_common_port/dwc_cc.c b/drivers/usb/host/dwc_common_port/dwc_cc.c
4778 new file mode 100644
4779 index 0000000..5ec2ae2
4780 --- /dev/null
4781 +++ b/drivers/usb/host/dwc_common_port/dwc_cc.c
4782 @@ -0,0 +1,532 @@
4783 +/* =========================================================================
4784 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.c $
4785 + * $Revision: #4 $
4786 + * $Date: 2010/11/04 $
4787 + * $Change: 1621692 $
4788 + *
4789 + * Synopsys Portability Library Software and documentation
4790 + * (hereinafter, "Software") is an Unsupported proprietary work of
4791 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
4792 + * between Synopsys and you.
4793 + *
4794 + * The Software IS NOT an item of Licensed Software or Licensed Product
4795 + * under any End User Software License Agreement or Agreement for
4796 + * Licensed Product with Synopsys or any supplement thereto. You are
4797 + * permitted to use and redistribute this Software in source and binary
4798 + * forms, with or without modification, provided that redistributions
4799 + * of source code must retain this notice. You may not view, use,
4800 + * disclose, copy or distribute this file or any information contained
4801 + * herein except pursuant to this license grant from Synopsys. If you
4802 + * do not agree with this notice, including the disclaimer below, then
4803 + * you are not authorized to use the Software.
4804 + *
4805 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
4806 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4807 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
4808 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
4809 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
4810 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
4811 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
4812 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
4813 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4814 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
4815 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
4816 + * DAMAGE.
4817 + * ========================================================================= */
4818 +#ifdef DWC_CCLIB
4819 +
4820 +#include "dwc_cc.h"
4821 +
4822 +typedef struct dwc_cc
4823 +{
4824 + uint32_t uid;
4825 + uint8_t chid[16];
4826 + uint8_t cdid[16];
4827 + uint8_t ck[16];
4828 + uint8_t *name;
4829 + uint8_t length;
4830 + DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry;
4831 +} dwc_cc_t;
4832 +
4833 +DWC_CIRCLEQ_HEAD(context_list, dwc_cc);
4834 +
4835 +/** The main structure for CC management. */
4836 +struct dwc_cc_if
4837 +{
4838 + dwc_mutex_t *mutex;
4839 + char *filename;
4840 +
4841 + unsigned is_host:1;
4842 +
4843 + dwc_notifier_t *notifier;
4844 +
4845 + struct context_list list;
4846 +};
4847 +
4848 +#ifdef DEBUG
4849 +static inline void dump_bytes(char *name, uint8_t *bytes, int len)
4850 +{
4851 + int i;
4852 + DWC_PRINTF("%s: ", name);
4853 + for (i=0; i<len; i++) {
4854 + DWC_PRINTF("%02x ", bytes[i]);
4855 + }
4856 + DWC_PRINTF("\n");
4857 +}
4858 +#else
4859 +#define dump_bytes(x...)
4860 +#endif
4861 +
4862 +static dwc_cc_t *alloc_cc(void *mem_ctx, uint8_t *name, uint32_t length)
4863 +{
4864 + dwc_cc_t *cc = dwc_alloc(mem_ctx, sizeof(dwc_cc_t));
4865 + if (!cc) {
4866 + return NULL;
4867 + }
4868 + DWC_MEMSET(cc, 0, sizeof(dwc_cc_t));
4869 +
4870 + if (name) {
4871 + cc->length = length;
4872 + cc->name = dwc_alloc(mem_ctx, length);
4873 + if (!cc->name) {
4874 + dwc_free(mem_ctx, cc);
4875 + return NULL;
4876 + }
4877 +
4878 + DWC_MEMCPY(cc->name, name, length);
4879 + }
4880 +
4881 + return cc;
4882 +}
4883 +
4884 +static void free_cc(void *mem_ctx, dwc_cc_t *cc)
4885 +{
4886 + if (cc->name) {
4887 + dwc_free(mem_ctx, cc->name);
4888 + }
4889 + dwc_free(mem_ctx, cc);
4890 +}
4891 +
4892 +static uint32_t next_uid(dwc_cc_if_t *cc_if)
4893 +{
4894 + uint32_t uid = 0;
4895 + dwc_cc_t *cc;
4896 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4897 + if (cc->uid > uid) {
4898 + uid = cc->uid;
4899 + }
4900 + }
4901 +
4902 + if (uid == 0) {
4903 + uid = 255;
4904 + }
4905 +
4906 + return uid + 1;
4907 +}
4908 +
4909 +static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid)
4910 +{
4911 + dwc_cc_t *cc;
4912 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4913 + if (cc->uid == uid) {
4914 + return cc;
4915 + }
4916 + }
4917 + return NULL;
4918 +}
4919 +
4920 +static unsigned int cc_data_size(dwc_cc_if_t *cc_if)
4921 +{
4922 + unsigned int size = 0;
4923 + dwc_cc_t *cc;
4924 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4925 + size += (48 + 1);
4926 + if (cc->name) {
4927 + size += cc->length;
4928 + }
4929 + }
4930 + return size;
4931 +}
4932 +
4933 +static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
4934 +{
4935 + uint32_t uid = 0;
4936 + dwc_cc_t *cc;
4937 +
4938 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4939 + if (DWC_MEMCMP(cc->chid, chid, 16) == 0) {
4940 + uid = cc->uid;
4941 + break;
4942 + }
4943 + }
4944 + return uid;
4945 +}
4946 +static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
4947 +{
4948 + uint32_t uid = 0;
4949 + dwc_cc_t *cc;
4950 +
4951 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4952 + if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) {
4953 + uid = cc->uid;
4954 + break;
4955 + }
4956 + }
4957 + return uid;
4958 +}
4959 +
4960 +/* Internal cc_add */
4961 +static int32_t cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
4962 + uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
4963 +{
4964 + dwc_cc_t *cc;
4965 + uint32_t uid;
4966 +
4967 + if (cc_if->is_host) {
4968 + uid = cc_match_cdid(cc_if, cdid);
4969 + }
4970 + else {
4971 + uid = cc_match_chid(cc_if, chid);
4972 + }
4973 +
4974 + if (uid) {
4975 + DWC_DEBUGC("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length);
4976 + cc = cc_find(cc_if, uid);
4977 + }
4978 + else {
4979 + cc = alloc_cc(mem_ctx, name, length);
4980 + cc->uid = next_uid(cc_if);
4981 + DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry);
4982 + }
4983 +
4984 + DWC_MEMCPY(&(cc->chid[0]), chid, 16);
4985 + DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
4986 + DWC_MEMCPY(&(cc->ck[0]), ck, 16);
4987 +
4988 + DWC_DEBUGC("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length);
4989 + dump_bytes("CHID", cc->chid, 16);
4990 + dump_bytes("CDID", cc->cdid, 16);
4991 + dump_bytes("CK", cc->ck, 16);
4992 + return cc->uid;
4993 +}
4994 +
4995 +/* Internal cc_clear */
4996 +static void cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
4997 +{
4998 + while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) {
4999 + dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list);
5000 + DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
5001 + free_cc(mem_ctx, cc);
5002 + }
5003 +}
5004 +
5005 +dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
5006 + dwc_notifier_t *notifier, unsigned is_host)
5007 +{
5008 + dwc_cc_if_t *cc_if = NULL;
5009 +
5010 + /* Allocate a common_cc_if structure */
5011 + cc_if = dwc_alloc(mem_ctx, sizeof(dwc_cc_if_t));
5012 +
5013 + if (!cc_if)
5014 + return NULL;
5015 +
5016 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
5017 + DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex);
5018 +#else
5019 + cc_if->mutex = dwc_mutex_alloc(mtx_ctx);
5020 +#endif
5021 + if (!cc_if->mutex) {
5022 + dwc_free(mem_ctx, cc_if);
5023 + return NULL;
5024 + }
5025 +
5026 + DWC_CIRCLEQ_INIT(&cc_if->list);
5027 + cc_if->is_host = is_host;
5028 + cc_if->notifier = notifier;
5029 + return cc_if;
5030 +}
5031 +
5032 +void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if)
5033 +{
5034 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
5035 + DWC_MUTEX_FREE(cc_if->mutex);
5036 +#else
5037 + dwc_mutex_free(mtx_ctx, cc_if->mutex);
5038 +#endif
5039 + cc_clear(mem_ctx, cc_if);
5040 + dwc_free(mem_ctx, cc_if);
5041 +}
5042 +
5043 +static void cc_changed(dwc_cc_if_t *cc_if)
5044 +{
5045 + if (cc_if->notifier) {
5046 + dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if);
5047 + }
5048 +}
5049 +
5050 +void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
5051 +{
5052 + DWC_MUTEX_LOCK(cc_if->mutex);
5053 + cc_clear(mem_ctx, cc_if);
5054 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5055 + cc_changed(cc_if);
5056 +}
5057 +
5058 +int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
5059 + uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
5060 +{
5061 + uint32_t uid;
5062 +
5063 + DWC_MUTEX_LOCK(cc_if->mutex);
5064 + uid = cc_add(mem_ctx, cc_if, chid, cdid, ck, name, length);
5065 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5066 + cc_changed(cc_if);
5067 +
5068 + return uid;
5069 +}
5070 +
5071 +void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid,
5072 + uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
5073 +{
5074 + dwc_cc_t* cc;
5075 +
5076 + DWC_DEBUGC("Change connection context %d", id);
5077 +
5078 + DWC_MUTEX_LOCK(cc_if->mutex);
5079 + cc = cc_find(cc_if, id);
5080 + if (!cc) {
5081 + DWC_ERROR("Uid %d not found in cc list\n", id);
5082 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5083 + return;
5084 + }
5085 +
5086 + if (chid) {
5087 + DWC_MEMCPY(&(cc->chid[0]), chid, 16);
5088 + }
5089 + if (cdid) {
5090 + DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
5091 + }
5092 + if (ck) {
5093 + DWC_MEMCPY(&(cc->ck[0]), ck, 16);
5094 + }
5095 +
5096 + if (name) {
5097 + if (cc->name) {
5098 + dwc_free(mem_ctx, cc->name);
5099 + }
5100 + cc->name = dwc_alloc(mem_ctx, length);
5101 + if (!cc->name) {
5102 + DWC_ERROR("Out of memory in dwc_cc_change()\n");
5103 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5104 + return;
5105 + }
5106 + cc->length = length;
5107 + DWC_MEMCPY(cc->name, name, length);
5108 + }
5109 +
5110 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5111 +
5112 + cc_changed(cc_if);
5113 +
5114 + DWC_DEBUGC("Changed connection context id=%d\n", id);
5115 + dump_bytes("New CHID", cc->chid, 16);
5116 + dump_bytes("New CDID", cc->cdid, 16);
5117 + dump_bytes("New CK", cc->ck, 16);
5118 +}
5119 +
5120 +void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id)
5121 +{
5122 + dwc_cc_t *cc;
5123 +
5124 + DWC_DEBUGC("Removing connection context %d", id);
5125 +
5126 + DWC_MUTEX_LOCK(cc_if->mutex);
5127 + cc = cc_find(cc_if, id);
5128 + if (!cc) {
5129 + DWC_ERROR("Uid %d not found in cc list\n", id);
5130 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5131 + return;
5132 + }
5133 +
5134 + DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
5135 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5136 + free_cc(mem_ctx, cc);
5137 +
5138 + cc_changed(cc_if);
5139 +}
5140 +
5141 +uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, unsigned int *length)
5142 +{
5143 + uint8_t *buf, *x;
5144 + uint8_t zero = 0;
5145 + dwc_cc_t *cc;
5146 +
5147 + DWC_MUTEX_LOCK(cc_if->mutex);
5148 + *length = cc_data_size(cc_if);
5149 + if (!(*length)) {
5150 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5151 + return NULL;
5152 + }
5153 +
5154 + DWC_DEBUGC("Creating data for saving (length=%d)", *length);
5155 +
5156 + buf = dwc_alloc(mem_ctx, *length);
5157 + if (!buf) {
5158 + *length = 0;
5159 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5160 + return NULL;
5161 + }
5162 +
5163 + x = buf;
5164 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
5165 + DWC_MEMCPY(x, cc->chid, 16);
5166 + x += 16;
5167 + DWC_MEMCPY(x, cc->cdid, 16);
5168 + x += 16;
5169 + DWC_MEMCPY(x, cc->ck, 16);
5170 + x += 16;
5171 + if (cc->name) {
5172 + DWC_MEMCPY(x, &cc->length, 1);
5173 + x += 1;
5174 + DWC_MEMCPY(x, cc->name, cc->length);
5175 + x += cc->length;
5176 + }
5177 + else {
5178 + DWC_MEMCPY(x, &zero, 1);
5179 + x += 1;
5180 + }
5181 + }
5182 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5183 +
5184 + return buf;
5185 +}
5186 +
5187 +void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length)
5188 +{
5189 + uint8_t name_length;
5190 + uint8_t *name;
5191 + uint8_t *chid;
5192 + uint8_t *cdid;
5193 + uint8_t *ck;
5194 + uint32_t i = 0;
5195 +
5196 + DWC_MUTEX_LOCK(cc_if->mutex);
5197 + cc_clear(mem_ctx, cc_if);
5198 +
5199 + while (i < length) {
5200 + chid = &data[i];
5201 + i += 16;
5202 + cdid = &data[i];
5203 + i += 16;
5204 + ck = &data[i];
5205 + i += 16;
5206 +
5207 + name_length = data[i];
5208 + i ++;
5209 +
5210 + if (name_length) {
5211 + name = &data[i];
5212 + i += name_length;
5213 + }
5214 + else {
5215 + name = NULL;
5216 + }
5217 +
5218 + /* check to see if we haven't overflown the buffer */
5219 + if (i > length) {
5220 + DWC_ERROR("Data format error while attempting to load CCs "
5221 + "(nlen=%d, iter=%d, buflen=%d).\n", name_length, i, length);
5222 + break;
5223 + }
5224 +
5225 + cc_add(mem_ctx, cc_if, chid, cdid, ck, name, name_length);
5226 + }
5227 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5228 +
5229 + cc_changed(cc_if);
5230 +}
5231 +
5232 +uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
5233 +{
5234 + uint32_t uid = 0;
5235 +
5236 + DWC_MUTEX_LOCK(cc_if->mutex);
5237 + uid = cc_match_chid(cc_if, chid);
5238 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5239 + return uid;
5240 +}
5241 +uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
5242 +{
5243 + uint32_t uid = 0;
5244 +
5245 + DWC_MUTEX_LOCK(cc_if->mutex);
5246 + uid = cc_match_cdid(cc_if, cdid);
5247 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5248 + return uid;
5249 +}
5250 +
5251 +uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id)
5252 +{
5253 + uint8_t *ck = NULL;
5254 + dwc_cc_t *cc;
5255 +
5256 + DWC_MUTEX_LOCK(cc_if->mutex);
5257 + cc = cc_find(cc_if, id);
5258 + if (cc) {
5259 + ck = cc->ck;
5260 + }
5261 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5262 +
5263 + return ck;
5264 +
5265 +}
5266 +
5267 +uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id)
5268 +{
5269 + uint8_t *retval = NULL;
5270 + dwc_cc_t *cc;
5271 +
5272 + DWC_MUTEX_LOCK(cc_if->mutex);
5273 + cc = cc_find(cc_if, id);
5274 + if (cc) {
5275 + retval = cc->chid;
5276 + }
5277 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5278 +
5279 + return retval;
5280 +}
5281 +
5282 +uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id)
5283 +{
5284 + uint8_t *retval = NULL;
5285 + dwc_cc_t *cc;
5286 +
5287 + DWC_MUTEX_LOCK(cc_if->mutex);
5288 + cc = cc_find(cc_if, id);
5289 + if (cc) {
5290 + retval = cc->cdid;
5291 + }
5292 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5293 +
5294 + return retval;
5295 +}
5296 +
5297 +uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length)
5298 +{
5299 + uint8_t *retval = NULL;
5300 + dwc_cc_t *cc;
5301 +
5302 + DWC_MUTEX_LOCK(cc_if->mutex);
5303 + *length = 0;
5304 + cc = cc_find(cc_if, id);
5305 + if (cc) {
5306 + *length = cc->length;
5307 + retval = cc->name;
5308 + }
5309 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5310 +
5311 + return retval;
5312 +}
5313 +
5314 +#endif /* DWC_CCLIB */
5315 diff --git a/drivers/usb/host/dwc_common_port/dwc_cc.h b/drivers/usb/host/dwc_common_port/dwc_cc.h
5316 new file mode 100644
5317 index 0000000..f86e6f2
5318 --- /dev/null
5319 +++ b/drivers/usb/host/dwc_common_port/dwc_cc.h
5320 @@ -0,0 +1,224 @@
5321 +/* =========================================================================
5322 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.h $
5323 + * $Revision: #4 $
5324 + * $Date: 2010/09/28 $
5325 + * $Change: 1596182 $
5326 + *
5327 + * Synopsys Portability Library Software and documentation
5328 + * (hereinafter, "Software") is an Unsupported proprietary work of
5329 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
5330 + * between Synopsys and you.
5331 + *
5332 + * The Software IS NOT an item of Licensed Software or Licensed Product
5333 + * under any End User Software License Agreement or Agreement for
5334 + * Licensed Product with Synopsys or any supplement thereto. You are
5335 + * permitted to use and redistribute this Software in source and binary
5336 + * forms, with or without modification, provided that redistributions
5337 + * of source code must retain this notice. You may not view, use,
5338 + * disclose, copy or distribute this file or any information contained
5339 + * herein except pursuant to this license grant from Synopsys. If you
5340 + * do not agree with this notice, including the disclaimer below, then
5341 + * you are not authorized to use the Software.
5342 + *
5343 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
5344 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5345 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
5346 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
5347 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
5348 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
5349 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
5350 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
5351 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5352 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
5353 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
5354 + * DAMAGE.
5355 + * ========================================================================= */
5356 +#ifndef _DWC_CC_H_
5357 +#define _DWC_CC_H_
5358 +
5359 +#ifdef __cplusplus
5360 +extern "C" {
5361 +#endif
5362 +
5363 +/** @file
5364 + *
5365 + * This file defines the Context Context library.
5366 + *
5367 + * The main data structure is dwc_cc_if_t which is returned by either the
5368 + * dwc_cc_if_alloc function or returned by the module to the user via a provided
5369 + * function. The data structure is opaque and should only be manipulated via the
5370 + * functions provied in this API.
5371 + *
5372 + * It manages a list of connection contexts and operations can be performed to
5373 + * add, remove, query, search, and change, those contexts. Additionally,
5374 + * a dwc_notifier_t object can be requested from the manager so that
5375 + * the user can be notified whenever the context list has changed.
5376 + */
5377 +
5378 +#include "dwc_os.h"
5379 +#include "dwc_list.h"
5380 +#include "dwc_notifier.h"
5381 +
5382 +
5383 +/* Notifications */
5384 +#define DWC_CC_LIST_CHANGED_NOTIFICATION "DWC_CC_LIST_CHANGED_NOTIFICATION"
5385 +
5386 +struct dwc_cc_if;
5387 +typedef struct dwc_cc_if dwc_cc_if_t;
5388 +
5389 +
5390 +/** @name Connection Context Operations */
5391 +/** @{ */
5392 +
5393 +/** This function allocates memory for a dwc_cc_if_t structure, initializes
5394 + * fields to default values, and returns a pointer to the structure or NULL on
5395 + * error. */
5396 +extern dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
5397 + dwc_notifier_t *notifier, unsigned is_host);
5398 +
5399 +/** Frees the memory for the specified CC structure allocated from
5400 + * dwc_cc_if_alloc(). */
5401 +extern void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if);
5402 +
5403 +/** Removes all contexts from the connection context list */
5404 +extern void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if);
5405 +
5406 +/** Adds a connection context (CHID, CK, CDID, Name) to the connection context list.
5407 + * If a CHID already exists, the CK and name are overwritten. Statistics are
5408 + * not overwritten.
5409 + *
5410 + * @param cc_if The cc_if structure.
5411 + * @param chid A pointer to the 16-byte CHID. This value will be copied.
5412 + * @param ck A pointer to the 16-byte CK. This value will be copied.
5413 + * @param cdid A pointer to the 16-byte CDID. This value will be copied.
5414 + * @param name An optional host friendly name as defined in the association model
5415 + * spec. Must be a UTF16-LE unicode string. Can be NULL to indicated no name.
5416 + * @param length The length othe unicode string.
5417 + * @return A unique identifier used to refer to this context that is valid for
5418 + * as long as this context is still in the list. */
5419 +extern int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
5420 + uint8_t *cdid, uint8_t *ck, uint8_t *name,
5421 + uint8_t length);
5422 +
5423 +/** Changes the CHID, CK, CDID, or Name values of a connection context in the
5424 + * list, preserving any accumulated statistics. This would typically be called
5425 + * if the host decideds to change the context with a SET_CONNECTION request.
5426 + *
5427 + * @param cc_if The cc_if structure.
5428 + * @param id The identifier of the connection context.
5429 + * @param chid A pointer to the 16-byte CHID. This value will be copied. NULL
5430 + * indicates no change.
5431 + * @param cdid A pointer to the 16-byte CDID. This value will be copied. NULL
5432 + * indicates no change.
5433 + * @param ck A pointer to the 16-byte CK. This value will be copied. NULL
5434 + * indicates no change.
5435 + * @param name Host friendly name UTF16-LE. NULL indicates no change.
5436 + * @param length Length of name. */
5437 +extern void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id,
5438 + uint8_t *chid, uint8_t *cdid, uint8_t *ck,
5439 + uint8_t *name, uint8_t length);
5440 +
5441 +/** Remove the specified connection context.
5442 + * @param cc_if The cc_if structure.
5443 + * @param id The identifier of the connection context to remove. */
5444 +extern void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id);
5445 +
5446 +/** Get a binary block of data for the connection context list and attributes.
5447 + * This data can be used by the OS specific driver to save the connection
5448 + * context list into non-volatile memory.
5449 + *
5450 + * @param cc_if The cc_if structure.
5451 + * @param length Return the length of the data buffer.
5452 + * @return A pointer to the data buffer. The memory for this buffer should be
5453 + * freed with DWC_FREE() after use. */
5454 +extern uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if,
5455 + unsigned int *length);
5456 +
5457 +/** Restore the connection context list from the binary data that was previously
5458 + * returned from a call to dwc_cc_data_for_save. This can be used by the OS specific
5459 + * driver to load a connection context list from non-volatile memory.
5460 + *
5461 + * @param cc_if The cc_if structure.
5462 + * @param data The data bytes as returned from dwc_cc_data_for_save.
5463 + * @param length The length of the data. */
5464 +extern void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if,
5465 + uint8_t *data, unsigned int length);
5466 +
5467 +/** Find the connection context from the specified CHID.
5468 + *
5469 + * @param cc_if The cc_if structure.
5470 + * @param chid A pointer to the CHID data.
5471 + * @return A non-zero identifier of the connection context if the CHID matches.
5472 + * Otherwise returns 0. */
5473 +extern uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid);
5474 +
5475 +/** Find the connection context from the specified CDID.
5476 + *
5477 + * @param cc_if The cc_if structure.
5478 + * @param cdid A pointer to the CDID data.
5479 + * @return A non-zero identifier of the connection context if the CHID matches.
5480 + * Otherwise returns 0. */
5481 +extern uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid);
5482 +
5483 +/** Retrieve the CK from the specified connection context.
5484 + *
5485 + * @param cc_if The cc_if structure.
5486 + * @param id The identifier of the connection context.
5487 + * @return A pointer to the CK data. The memory does not need to be freed. */
5488 +extern uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id);
5489 +
5490 +/** Retrieve the CHID from the specified connection context.
5491 + *
5492 + * @param cc_if The cc_if structure.
5493 + * @param id The identifier of the connection context.
5494 + * @return A pointer to the CHID data. The memory does not need to be freed. */
5495 +extern uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id);
5496 +
5497 +/** Retrieve the CDID from the specified connection context.
5498 + *
5499 + * @param cc_if The cc_if structure.
5500 + * @param id The identifier of the connection context.
5501 + * @return A pointer to the CDID data. The memory does not need to be freed. */
5502 +extern uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id);
5503 +
5504 +extern uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length);
5505 +
5506 +/** Checks a buffer for non-zero.
5507 + * @param id A pointer to a 16 byte buffer.
5508 + * @return true if the 16 byte value is non-zero. */
5509 +static inline unsigned dwc_assoc_is_not_zero_id(uint8_t *id) {
5510 + int i;
5511 + for (i=0; i<16; i++) {
5512 + if (id[i]) return 1;
5513 + }
5514 + return 0;
5515 +}
5516 +
5517 +/** Checks a buffer for zero.
5518 + * @param id A pointer to a 16 byte buffer.
5519 + * @return true if the 16 byte value is zero. */
5520 +static inline unsigned dwc_assoc_is_zero_id(uint8_t *id) {
5521 + return !dwc_assoc_is_not_zero_id(id);
5522 +}
5523 +
5524 +/** Prints an ASCII representation for the 16-byte chid, cdid, or ck, into
5525 + * buffer. */
5526 +static inline int dwc_print_id_string(char *buffer, uint8_t *id) {
5527 + char *ptr = buffer;
5528 + int i;
5529 + for (i=0; i<16; i++) {
5530 + ptr += DWC_SPRINTF(ptr, "%02x", id[i]);
5531 + if (i < 15) {
5532 + ptr += DWC_SPRINTF(ptr, " ");
5533 + }
5534 + }
5535 + return ptr - buffer;
5536 +}
5537 +
5538 +/** @} */
5539 +
5540 +#ifdef __cplusplus
5541 +}
5542 +#endif
5543 +
5544 +#endif /* _DWC_CC_H_ */
5545 diff --git a/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c b/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
5546 new file mode 100644
5547 index 0000000..6dd04b5
5548 --- /dev/null
5549 +++ b/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
5550 @@ -0,0 +1,1308 @@
5551 +#include "dwc_os.h"
5552 +#include "dwc_list.h"
5553 +
5554 +#ifdef DWC_CCLIB
5555 +# include "dwc_cc.h"
5556 +#endif
5557 +
5558 +#ifdef DWC_CRYPTOLIB
5559 +# include "dwc_modpow.h"
5560 +# include "dwc_dh.h"
5561 +# include "dwc_crypto.h"
5562 +#endif
5563 +
5564 +#ifdef DWC_NOTIFYLIB
5565 +# include "dwc_notifier.h"
5566 +#endif
5567 +
5568 +/* OS-Level Implementations */
5569 +
5570 +/* This is the FreeBSD 7.0 kernel implementation of the DWC platform library. */
5571 +
5572 +
5573 +/* MISC */
5574 +
5575 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
5576 +{
5577 + return memset(dest, byte, size);
5578 +}
5579 +
5580 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
5581 +{
5582 + return memcpy(dest, src, size);
5583 +}
5584 +
5585 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
5586 +{
5587 + bcopy(src, dest, size);
5588 + return dest;
5589 +}
5590 +
5591 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
5592 +{
5593 + return memcmp(m1, m2, size);
5594 +}
5595 +
5596 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
5597 +{
5598 + return strncmp(s1, s2, size);
5599 +}
5600 +
5601 +int DWC_STRCMP(void *s1, void *s2)
5602 +{
5603 + return strcmp(s1, s2);
5604 +}
5605 +
5606 +int DWC_STRLEN(char const *str)
5607 +{
5608 + return strlen(str);
5609 +}
5610 +
5611 +char *DWC_STRCPY(char *to, char const *from)
5612 +{
5613 + return strcpy(to, from);
5614 +}
5615 +
5616 +char *DWC_STRDUP(char const *str)
5617 +{
5618 + int len = DWC_STRLEN(str) + 1;
5619 + char *new = DWC_ALLOC_ATOMIC(len);
5620 +
5621 + if (!new) {
5622 + return NULL;
5623 + }
5624 +
5625 + DWC_MEMCPY(new, str, len);
5626 + return new;
5627 +}
5628 +
5629 +int DWC_ATOI(char *str, int32_t *value)
5630 +{
5631 + char *end = NULL;
5632 +
5633 + *value = strtol(str, &end, 0);
5634 + if (*end == '\0') {
5635 + return 0;
5636 + }
5637 +
5638 + return -1;
5639 +}
5640 +
5641 +int DWC_ATOUI(char *str, uint32_t *value)
5642 +{
5643 + char *end = NULL;
5644 +
5645 + *value = strtoul(str, &end, 0);
5646 + if (*end == '\0') {
5647 + return 0;
5648 + }
5649 +
5650 + return -1;
5651 +}
5652 +
5653 +
5654 +#ifdef DWC_UTFLIB
5655 +/* From usbstring.c */
5656 +
5657 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
5658 +{
5659 + int count = 0;
5660 + u8 c;
5661 + u16 uchar;
5662 +
5663 + /* this insists on correct encodings, though not minimal ones.
5664 + * BUT it currently rejects legit 4-byte UTF-8 code points,
5665 + * which need surrogate pairs. (Unicode 3.1 can use them.)
5666 + */
5667 + while (len != 0 && (c = (u8) *s++) != 0) {
5668 + if (unlikely(c & 0x80)) {
5669 + // 2-byte sequence:
5670 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
5671 + if ((c & 0xe0) == 0xc0) {
5672 + uchar = (c & 0x1f) << 6;
5673 +
5674 + c = (u8) *s++;
5675 + if ((c & 0xc0) != 0xc0)
5676 + goto fail;
5677 + c &= 0x3f;
5678 + uchar |= c;
5679 +
5680 + // 3-byte sequence (most CJKV characters):
5681 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
5682 + } else if ((c & 0xf0) == 0xe0) {
5683 + uchar = (c & 0x0f) << 12;
5684 +
5685 + c = (u8) *s++;
5686 + if ((c & 0xc0) != 0xc0)
5687 + goto fail;
5688 + c &= 0x3f;
5689 + uchar |= c << 6;
5690 +
5691 + c = (u8) *s++;
5692 + if ((c & 0xc0) != 0xc0)
5693 + goto fail;
5694 + c &= 0x3f;
5695 + uchar |= c;
5696 +
5697 + /* no bogus surrogates */
5698 + if (0xd800 <= uchar && uchar <= 0xdfff)
5699 + goto fail;
5700 +
5701 + // 4-byte sequence (surrogate pairs, currently rare):
5702 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
5703 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
5704 + // (uuuuu = wwww + 1)
5705 + // FIXME accept the surrogate code points (only)
5706 + } else
5707 + goto fail;
5708 + } else
5709 + uchar = c;
5710 + put_unaligned (cpu_to_le16 (uchar), cp++);
5711 + count++;
5712 + len--;
5713 + }
5714 + return count;
5715 +fail:
5716 + return -1;
5717 +}
5718 +
5719 +#endif /* DWC_UTFLIB */
5720 +
5721 +
5722 +/* dwc_debug.h */
5723 +
5724 +dwc_bool_t DWC_IN_IRQ(void)
5725 +{
5726 +// return in_irq();
5727 + return 0;
5728 +}
5729 +
5730 +dwc_bool_t DWC_IN_BH(void)
5731 +{
5732 +// return in_softirq();
5733 + return 0;
5734 +}
5735 +
5736 +void DWC_VPRINTF(char *format, va_list args)
5737 +{
5738 + vprintf(format, args);
5739 +}
5740 +
5741 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
5742 +{
5743 + return vsnprintf(str, size, format, args);
5744 +}
5745 +
5746 +void DWC_PRINTF(char *format, ...)
5747 +{
5748 + va_list args;
5749 +
5750 + va_start(args, format);
5751 + DWC_VPRINTF(format, args);
5752 + va_end(args);
5753 +}
5754 +
5755 +int DWC_SPRINTF(char *buffer, char *format, ...)
5756 +{
5757 + int retval;
5758 + va_list args;
5759 +
5760 + va_start(args, format);
5761 + retval = vsprintf(buffer, format, args);
5762 + va_end(args);
5763 + return retval;
5764 +}
5765 +
5766 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
5767 +{
5768 + int retval;
5769 + va_list args;
5770 +
5771 + va_start(args, format);
5772 + retval = vsnprintf(buffer, size, format, args);
5773 + va_end(args);
5774 + return retval;
5775 +}
5776 +
5777 +void __DWC_WARN(char *format, ...)
5778 +{
5779 + va_list args;
5780 +
5781 + va_start(args, format);
5782 + DWC_VPRINTF(format, args);
5783 + va_end(args);
5784 +}
5785 +
5786 +void __DWC_ERROR(char *format, ...)
5787 +{
5788 + va_list args;
5789 +
5790 + va_start(args, format);
5791 + DWC_VPRINTF(format, args);
5792 + va_end(args);
5793 +}
5794 +
5795 +void DWC_EXCEPTION(char *format, ...)
5796 +{
5797 + va_list args;
5798 +
5799 + va_start(args, format);
5800 + DWC_VPRINTF(format, args);
5801 + va_end(args);
5802 +// BUG_ON(1); ???
5803 +}
5804 +
5805 +#ifdef DEBUG
5806 +void __DWC_DEBUG(char *format, ...)
5807 +{
5808 + va_list args;
5809 +
5810 + va_start(args, format);
5811 + DWC_VPRINTF(format, args);
5812 + va_end(args);
5813 +}
5814 +#endif
5815 +
5816 +
5817 +/* dwc_mem.h */
5818 +
5819 +#if 0
5820 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
5821 + uint32_t align,
5822 + uint32_t alloc)
5823 +{
5824 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
5825 + size, align, alloc);
5826 + return (dwc_pool_t *)pool;
5827 +}
5828 +
5829 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
5830 +{
5831 + dma_pool_destroy((struct dma_pool *)pool);
5832 +}
5833 +
5834 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
5835 +{
5836 +// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
5837 + return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
5838 +}
5839 +
5840 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
5841 +{
5842 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
5843 + memset(..);
5844 +}
5845 +
5846 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
5847 +{
5848 + dma_pool_free(pool, vaddr, daddr);
5849 +}
5850 +#endif
5851 +
5852 +static void dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
5853 +{
5854 + if (error)
5855 + return;
5856 + *(bus_addr_t *)arg = segs[0].ds_addr;
5857 +}
5858 +
5859 +void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
5860 +{
5861 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
5862 + int error;
5863 +
5864 + error = bus_dma_tag_create(
5865 +#if __FreeBSD_version >= 700000
5866 + bus_get_dma_tag(dma->dev), /* parent */
5867 +#else
5868 + NULL, /* parent */
5869 +#endif
5870 + 4, 0, /* alignment, bounds */
5871 + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
5872 + BUS_SPACE_MAXADDR, /* highaddr */
5873 + NULL, NULL, /* filter, filterarg */
5874 + size, /* maxsize */
5875 + 1, /* nsegments */
5876 + size, /* maxsegsize */
5877 + 0, /* flags */
5878 + NULL, /* lockfunc */
5879 + NULL, /* lockarg */
5880 + &dma->dma_tag);
5881 + if (error) {
5882 + device_printf(dma->dev, "%s: bus_dma_tag_create failed: %d\n",
5883 + __func__, error);
5884 + goto fail_0;
5885 + }
5886 +
5887 + error = bus_dmamem_alloc(dma->dma_tag, &dma->dma_vaddr,
5888 + BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dma->dma_map);
5889 + if (error) {
5890 + device_printf(dma->dev, "%s: bus_dmamem_alloc(%ju) failed: %d\n",
5891 + __func__, (uintmax_t)size, error);
5892 + goto fail_1;
5893 + }
5894 +
5895 + dma->dma_paddr = 0;
5896 + error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, size,
5897 + dmamap_cb, &dma->dma_paddr, BUS_DMA_NOWAIT);
5898 + if (error || dma->dma_paddr == 0) {
5899 + device_printf(dma->dev, "%s: bus_dmamap_load failed: %d\n",
5900 + __func__, error);
5901 + goto fail_2;
5902 + }
5903 +
5904 + *dma_addr = dma->dma_paddr;
5905 + return dma->dma_vaddr;
5906 +
5907 +fail_2:
5908 + bus_dmamap_unload(dma->dma_tag, dma->dma_map);
5909 +fail_1:
5910 + bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
5911 + bus_dma_tag_destroy(dma->dma_tag);
5912 +fail_0:
5913 + dma->dma_map = NULL;
5914 + dma->dma_tag = NULL;
5915 +
5916 + return NULL;
5917 +}
5918 +
5919 +void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
5920 +{
5921 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
5922 +
5923 + if (dma->dma_tag == NULL)
5924 + return;
5925 + if (dma->dma_map != NULL) {
5926 + bus_dmamap_sync(dma->dma_tag, dma->dma_map,
5927 + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
5928 + bus_dmamap_unload(dma->dma_tag, dma->dma_map);
5929 + bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
5930 + dma->dma_map = NULL;
5931 + }
5932 +
5933 + bus_dma_tag_destroy(dma->dma_tag);
5934 + dma->dma_tag = NULL;
5935 +}
5936 +
5937 +void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
5938 +{
5939 + return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
5940 +}
5941 +
5942 +void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
5943 +{
5944 + return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
5945 +}
5946 +
5947 +void __DWC_FREE(void *mem_ctx, void *addr)
5948 +{
5949 + free(addr, M_DEVBUF);
5950 +}
5951 +
5952 +
5953 +#ifdef DWC_CRYPTOLIB
5954 +/* dwc_crypto.h */
5955 +
5956 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
5957 +{
5958 + get_random_bytes(buffer, length);
5959 +}
5960 +
5961 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
5962 +{
5963 + struct crypto_blkcipher *tfm;
5964 + struct blkcipher_desc desc;
5965 + struct scatterlist sgd;
5966 + struct scatterlist sgs;
5967 +
5968 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
5969 + if (tfm == NULL) {
5970 + printk("failed to load transform for aes CBC\n");
5971 + return -1;
5972 + }
5973 +
5974 + crypto_blkcipher_setkey(tfm, key, keylen);
5975 + crypto_blkcipher_set_iv(tfm, iv, 16);
5976 +
5977 + sg_init_one(&sgd, out, messagelen);
5978 + sg_init_one(&sgs, message, messagelen);
5979 +
5980 + desc.tfm = tfm;
5981 + desc.flags = 0;
5982 +
5983 + if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
5984 + crypto_free_blkcipher(tfm);
5985 + DWC_ERROR("AES CBC encryption failed");
5986 + return -1;
5987 + }
5988 +
5989 + crypto_free_blkcipher(tfm);
5990 + return 0;
5991 +}
5992 +
5993 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
5994 +{
5995 + struct crypto_hash *tfm;
5996 + struct hash_desc desc;
5997 + struct scatterlist sg;
5998 +
5999 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
6000 + if (IS_ERR(tfm)) {
6001 + DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
6002 + return 0;
6003 + }
6004 + desc.tfm = tfm;
6005 + desc.flags = 0;
6006 +
6007 + sg_init_one(&sg, message, len);
6008 + crypto_hash_digest(&desc, &sg, len, out);
6009 + crypto_free_hash(tfm);
6010 +
6011 + return 1;
6012 +}
6013 +
6014 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
6015 + uint8_t *key, uint32_t keylen, uint8_t *out)
6016 +{
6017 + struct crypto_hash *tfm;
6018 + struct hash_desc desc;
6019 + struct scatterlist sg;
6020 +
6021 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
6022 + if (IS_ERR(tfm)) {
6023 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
6024 + return 0;
6025 + }
6026 + desc.tfm = tfm;
6027 + desc.flags = 0;
6028 +
6029 + sg_init_one(&sg, message, messagelen);
6030 + crypto_hash_setkey(tfm, key, keylen);
6031 + crypto_hash_digest(&desc, &sg, messagelen, out);
6032 + crypto_free_hash(tfm);
6033 +
6034 + return 1;
6035 +}
6036 +
6037 +#endif /* DWC_CRYPTOLIB */
6038 +
6039 +
6040 +/* Byte Ordering Conversions */
6041 +
6042 +uint32_t DWC_CPU_TO_LE32(uint32_t *p)
6043 +{
6044 +#ifdef __LITTLE_ENDIAN
6045 + return *p;
6046 +#else
6047 + uint8_t *u_p = (uint8_t *)p;
6048 +
6049 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
6050 +#endif
6051 +}
6052 +
6053 +uint32_t DWC_CPU_TO_BE32(uint32_t *p)
6054 +{
6055 +#ifdef __BIG_ENDIAN
6056 + return *p;
6057 +#else
6058 + uint8_t *u_p = (uint8_t *)p;
6059 +
6060 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
6061 +#endif
6062 +}
6063 +
6064 +uint32_t DWC_LE32_TO_CPU(uint32_t *p)
6065 +{
6066 +#ifdef __LITTLE_ENDIAN
6067 + return *p;
6068 +#else
6069 + uint8_t *u_p = (uint8_t *)p;
6070 +
6071 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
6072 +#endif
6073 +}
6074 +
6075 +uint32_t DWC_BE32_TO_CPU(uint32_t *p)
6076 +{
6077 +#ifdef __BIG_ENDIAN
6078 + return *p;
6079 +#else
6080 + uint8_t *u_p = (uint8_t *)p;
6081 +
6082 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
6083 +#endif
6084 +}
6085 +
6086 +uint16_t DWC_CPU_TO_LE16(uint16_t *p)
6087 +{
6088 +#ifdef __LITTLE_ENDIAN
6089 + return *p;
6090 +#else
6091 + uint8_t *u_p = (uint8_t *)p;
6092 + return (u_p[1] | (u_p[0] << 8));
6093 +#endif
6094 +}
6095 +
6096 +uint16_t DWC_CPU_TO_BE16(uint16_t *p)
6097 +{
6098 +#ifdef __BIG_ENDIAN
6099 + return *p;
6100 +#else
6101 + uint8_t *u_p = (uint8_t *)p;
6102 + return (u_p[1] | (u_p[0] << 8));
6103 +#endif
6104 +}
6105 +
6106 +uint16_t DWC_LE16_TO_CPU(uint16_t *p)
6107 +{
6108 +#ifdef __LITTLE_ENDIAN
6109 + return *p;
6110 +#else
6111 + uint8_t *u_p = (uint8_t *)p;
6112 + return (u_p[1] | (u_p[0] << 8));
6113 +#endif
6114 +}
6115 +
6116 +uint16_t DWC_BE16_TO_CPU(uint16_t *p)
6117 +{
6118 +#ifdef __BIG_ENDIAN
6119 + return *p;
6120 +#else
6121 + uint8_t *u_p = (uint8_t *)p;
6122 + return (u_p[1] | (u_p[0] << 8));
6123 +#endif
6124 +}
6125 +
6126 +
6127 +/* Registers */
6128 +
6129 +uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
6130 +{
6131 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6132 + bus_size_t ior = (bus_size_t)reg;
6133 +
6134 + return bus_space_read_4(io->iot, io->ioh, ior);
6135 +}
6136 +
6137 +#if 0
6138 +uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
6139 +{
6140 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6141 + bus_size_t ior = (bus_size_t)reg;
6142 +
6143 + return bus_space_read_8(io->iot, io->ioh, ior);
6144 +}
6145 +#endif
6146 +
6147 +void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
6148 +{
6149 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6150 + bus_size_t ior = (bus_size_t)reg;
6151 +
6152 + bus_space_write_4(io->iot, io->ioh, ior, value);
6153 +}
6154 +
6155 +#if 0
6156 +void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
6157 +{
6158 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6159 + bus_size_t ior = (bus_size_t)reg;
6160 +
6161 + bus_space_write_8(io->iot, io->ioh, ior, value);
6162 +}
6163 +#endif
6164 +
6165 +void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
6166 + uint32_t set_mask)
6167 +{
6168 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6169 + bus_size_t ior = (bus_size_t)reg;
6170 +
6171 + bus_space_write_4(io->iot, io->ioh, ior,
6172 + (bus_space_read_4(io->iot, io->ioh, ior) &
6173 + ~clear_mask) | set_mask);
6174 +}
6175 +
6176 +#if 0
6177 +void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
6178 + uint64_t set_mask)
6179 +{
6180 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6181 + bus_size_t ior = (bus_size_t)reg;
6182 +
6183 + bus_space_write_8(io->iot, io->ioh, ior,
6184 + (bus_space_read_8(io->iot, io->ioh, ior) &
6185 + ~clear_mask) | set_mask);
6186 +}
6187 +#endif
6188 +
6189 +
6190 +/* Locking */
6191 +
6192 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
6193 +{
6194 + struct mtx *sl = DWC_ALLOC(sizeof(*sl));
6195 +
6196 + if (!sl) {
6197 + DWC_ERROR("Cannot allocate memory for spinlock");
6198 + return NULL;
6199 + }
6200 +
6201 + mtx_init(sl, "dw3spn", NULL, MTX_SPIN);
6202 + return (dwc_spinlock_t *)sl;
6203 +}
6204 +
6205 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
6206 +{
6207 + struct mtx *sl = (struct mtx *)lock;
6208 +
6209 + mtx_destroy(sl);
6210 + DWC_FREE(sl);
6211 +}
6212 +
6213 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
6214 +{
6215 + mtx_lock_spin((struct mtx *)lock); // ???
6216 +}
6217 +
6218 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
6219 +{
6220 + mtx_unlock_spin((struct mtx *)lock); // ???
6221 +}
6222 +
6223 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
6224 +{
6225 + mtx_lock_spin((struct mtx *)lock);
6226 +}
6227 +
6228 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
6229 +{
6230 + mtx_unlock_spin((struct mtx *)lock);
6231 +}
6232 +
6233 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
6234 +{
6235 + struct mtx *m;
6236 + dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mtx));
6237 +
6238 + if (!mutex) {
6239 + DWC_ERROR("Cannot allocate memory for mutex");
6240 + return NULL;
6241 + }
6242 +
6243 + m = (struct mtx *)mutex;
6244 + mtx_init(m, "dw3mtx", NULL, MTX_DEF);
6245 + return mutex;
6246 +}
6247 +
6248 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
6249 +#else
6250 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
6251 +{
6252 + mtx_destroy((struct mtx *)mutex);
6253 + DWC_FREE(mutex);
6254 +}
6255 +#endif
6256 +
6257 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
6258 +{
6259 + struct mtx *m = (struct mtx *)mutex;
6260 +
6261 + mtx_lock(m);
6262 +}
6263 +
6264 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
6265 +{
6266 + struct mtx *m = (struct mtx *)mutex;
6267 +
6268 + return mtx_trylock(m);
6269 +}
6270 +
6271 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
6272 +{
6273 + struct mtx *m = (struct mtx *)mutex;
6274 +
6275 + mtx_unlock(m);
6276 +}
6277 +
6278 +
6279 +/* Timing */
6280 +
6281 +void DWC_UDELAY(uint32_t usecs)
6282 +{
6283 + DELAY(usecs);
6284 +}
6285 +
6286 +void DWC_MDELAY(uint32_t msecs)
6287 +{
6288 + do {
6289 + DELAY(1000);
6290 + } while (--msecs);
6291 +}
6292 +
6293 +void DWC_MSLEEP(uint32_t msecs)
6294 +{
6295 + struct timeval tv;
6296 +
6297 + tv.tv_sec = msecs / 1000;
6298 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
6299 + pause("dw3slp", tvtohz(&tv));
6300 +}
6301 +
6302 +uint32_t DWC_TIME(void)
6303 +{
6304 + struct timeval tv;
6305 +
6306 + microuptime(&tv); // or getmicrouptime? (less precise, but faster)
6307 + return tv.tv_sec * 1000 + tv.tv_usec / 1000;
6308 +}
6309 +
6310 +
6311 +/* Timers */
6312 +
6313 +struct dwc_timer {
6314 + struct callout t;
6315 + char *name;
6316 + dwc_spinlock_t *lock;
6317 + dwc_timer_callback_t cb;
6318 + void *data;
6319 +};
6320 +
6321 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
6322 +{
6323 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
6324 +
6325 + if (!t) {
6326 + DWC_ERROR("Cannot allocate memory for timer");
6327 + return NULL;
6328 + }
6329 +
6330 + callout_init(&t->t, 1);
6331 +
6332 + t->name = DWC_STRDUP(name);
6333 + if (!t->name) {
6334 + DWC_ERROR("Cannot allocate memory for timer->name");
6335 + goto no_name;
6336 + }
6337 +
6338 + t->lock = DWC_SPINLOCK_ALLOC();
6339 + if (!t->lock) {
6340 + DWC_ERROR("Cannot allocate memory for lock");
6341 + goto no_lock;
6342 + }
6343 +
6344 + t->cb = cb;
6345 + t->data = data;
6346 +
6347 + return t;
6348 +
6349 + no_lock:
6350 + DWC_FREE(t->name);
6351 + no_name:
6352 + DWC_FREE(t);
6353 +
6354 + return NULL;
6355 +}
6356 +
6357 +void DWC_TIMER_FREE(dwc_timer_t *timer)
6358 +{
6359 + callout_stop(&timer->t);
6360 + DWC_SPINLOCK_FREE(timer->lock);
6361 + DWC_FREE(timer->name);
6362 + DWC_FREE(timer);
6363 +}
6364 +
6365 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
6366 +{
6367 + struct timeval tv;
6368 +
6369 + tv.tv_sec = time / 1000;
6370 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
6371 + callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
6372 +}
6373 +
6374 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
6375 +{
6376 + callout_stop(&timer->t);
6377 +}
6378 +
6379 +
6380 +/* Wait Queues */
6381 +
6382 +struct dwc_waitq {
6383 + struct mtx lock;
6384 + int abort;
6385 +};
6386 +
6387 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
6388 +{
6389 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
6390 +
6391 + if (!wq) {
6392 + DWC_ERROR("Cannot allocate memory for waitqueue");
6393 + return NULL;
6394 + }
6395 +
6396 + mtx_init(&wq->lock, "dw3wtq", NULL, MTX_DEF);
6397 + wq->abort = 0;
6398 +
6399 + return wq;
6400 +}
6401 +
6402 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
6403 +{
6404 + mtx_destroy(&wq->lock);
6405 + DWC_FREE(wq);
6406 +}
6407 +
6408 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
6409 +{
6410 +// intrmask_t ipl;
6411 + int result = 0;
6412 +
6413 + mtx_lock(&wq->lock);
6414 +// ipl = splbio();
6415 +
6416 + /* Skip the sleep if already aborted or triggered */
6417 + if (!wq->abort && !cond(data)) {
6418 +// splx(ipl);
6419 + result = msleep(wq, &wq->lock, PCATCH, "dw3wat", 0); // infinite timeout
6420 +// ipl = splbio();
6421 + }
6422 +
6423 + if (result == ERESTART) { // signaled - restart
6424 + result = -DWC_E_RESTART;
6425 +
6426 + } else if (result == EINTR) { // signaled - interrupt
6427 + result = -DWC_E_ABORT;
6428 +
6429 + } else if (wq->abort) {
6430 + result = -DWC_E_ABORT;
6431 +
6432 + } else {
6433 + result = 0;
6434 + }
6435 +
6436 + wq->abort = 0;
6437 +// splx(ipl);
6438 + mtx_unlock(&wq->lock);
6439 + return result;
6440 +}
6441 +
6442 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
6443 + void *data, int32_t msecs)
6444 +{
6445 + struct timeval tv, tv1, tv2;
6446 +// intrmask_t ipl;
6447 + int result = 0;
6448 +
6449 + tv.tv_sec = msecs / 1000;
6450 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
6451 +
6452 + mtx_lock(&wq->lock);
6453 +// ipl = splbio();
6454 +
6455 + /* Skip the sleep if already aborted or triggered */
6456 + if (!wq->abort && !cond(data)) {
6457 +// splx(ipl);
6458 + getmicrouptime(&tv1);
6459 + result = msleep(wq, &wq->lock, PCATCH, "dw3wto", tvtohz(&tv));
6460 + getmicrouptime(&tv2);
6461 +// ipl = splbio();
6462 + }
6463 +
6464 + if (result == 0) { // awoken
6465 + if (wq->abort) {
6466 + result = -DWC_E_ABORT;
6467 + } else {
6468 + tv2.tv_usec -= tv1.tv_usec;
6469 + if (tv2.tv_usec < 0) {
6470 + tv2.tv_usec += 1000000;
6471 + tv2.tv_sec--;
6472 + }
6473 +
6474 + tv2.tv_sec -= tv1.tv_sec;
6475 + result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
6476 + result = msecs - result;
6477 + if (result <= 0)
6478 + result = 1;
6479 + }
6480 + } else if (result == ERESTART) { // signaled - restart
6481 + result = -DWC_E_RESTART;
6482 +
6483 + } else if (result == EINTR) { // signaled - interrupt
6484 + result = -DWC_E_ABORT;
6485 +
6486 + } else { // timed out
6487 + result = -DWC_E_TIMEOUT;
6488 + }
6489 +
6490 + wq->abort = 0;
6491 +// splx(ipl);
6492 + mtx_unlock(&wq->lock);
6493 + return result;
6494 +}
6495 +
6496 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
6497 +{
6498 + wakeup(wq);
6499 +}
6500 +
6501 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
6502 +{
6503 +// intrmask_t ipl;
6504 +
6505 + mtx_lock(&wq->lock);
6506 +// ipl = splbio();
6507 + wq->abort = 1;
6508 + wakeup(wq);
6509 +// splx(ipl);
6510 + mtx_unlock(&wq->lock);
6511 +}
6512 +
6513 +
6514 +/* Threading */
6515 +
6516 +struct dwc_thread {
6517 + struct proc *proc;
6518 + int abort;
6519 +};
6520 +
6521 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
6522 +{
6523 + int retval;
6524 + dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
6525 +
6526 + if (!thread) {
6527 + return NULL;
6528 + }
6529 +
6530 + thread->abort = 0;
6531 + retval = kthread_create((void (*)(void *))func, data, &thread->proc,
6532 + RFPROC | RFNOWAIT, 0, "%s", name);
6533 + if (retval) {
6534 + DWC_FREE(thread);
6535 + return NULL;
6536 + }
6537 +
6538 + return thread;
6539 +}
6540 +
6541 +int DWC_THREAD_STOP(dwc_thread_t *thread)
6542 +{
6543 + int retval;
6544 +
6545 + thread->abort = 1;
6546 + retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
6547 +
6548 + if (retval == 0) {
6549 + /* DWC_THREAD_EXIT() will free the thread struct */
6550 + return 0;
6551 + }
6552 +
6553 + /* NOTE: We leak the thread struct if thread doesn't die */
6554 +
6555 + if (retval == EWOULDBLOCK) {
6556 + return -DWC_E_TIMEOUT;
6557 + }
6558 +
6559 + return -DWC_E_UNKNOWN;
6560 +}
6561 +
6562 +dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
6563 +{
6564 + return thread->abort;
6565 +}
6566 +
6567 +void DWC_THREAD_EXIT(dwc_thread_t *thread)
6568 +{
6569 + wakeup(&thread->abort);
6570 + DWC_FREE(thread);
6571 + kthread_exit(0);
6572 +}
6573 +
6574 +
6575 +/* tasklets
6576 + - Runs in interrupt context (cannot sleep)
6577 + - Each tasklet runs on a single CPU [ How can we ensure this on FreeBSD? Does it matter? ]
6578 + - Different tasklets can be running simultaneously on different CPUs [ shouldn't matter ]
6579 + */
6580 +struct dwc_tasklet {
6581 + struct task t;
6582 + dwc_tasklet_callback_t cb;
6583 + void *data;
6584 +};
6585 +
6586 +static void tasklet_callback(void *data, int pending) // what to do with pending ???
6587 +{
6588 + dwc_tasklet_t *task = (dwc_tasklet_t *)data;
6589 +
6590 + task->cb(task->data);
6591 +}
6592 +
6593 +dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
6594 +{
6595 + dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
6596 +
6597 + if (task) {
6598 + task->cb = cb;
6599 + task->data = data;
6600 + TASK_INIT(&task->t, 0, tasklet_callback, task);
6601 + } else {
6602 + DWC_ERROR("Cannot allocate memory for tasklet");
6603 + }
6604 +
6605 + return task;
6606 +}
6607 +
6608 +void DWC_TASK_FREE(dwc_tasklet_t *task)
6609 +{
6610 + taskqueue_drain(taskqueue_fast, &task->t); // ???
6611 + DWC_FREE(task);
6612 +}
6613 +
6614 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
6615 +{
6616 + /* Uses predefined system queue */
6617 + taskqueue_enqueue_fast(taskqueue_fast, &task->t);
6618 +}
6619 +
6620 +
6621 +/* workqueues
6622 + - Runs in process context (can sleep)
6623 + */
6624 +typedef struct work_container {
6625 + dwc_work_callback_t cb;
6626 + void *data;
6627 + dwc_workq_t *wq;
6628 + char *name;
6629 + int hz;
6630 +
6631 +#ifdef DEBUG
6632 + DWC_CIRCLEQ_ENTRY(work_container) entry;
6633 +#endif
6634 + struct task task;
6635 +} work_container_t;
6636 +
6637 +#ifdef DEBUG
6638 +DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
6639 +#endif
6640 +
6641 +struct dwc_workq {
6642 + struct taskqueue *taskq;
6643 + dwc_spinlock_t *lock;
6644 + dwc_waitq_t *waitq;
6645 + int pending;
6646 +
6647 +#ifdef DEBUG
6648 + struct work_container_queue entries;
6649 +#endif
6650 +};
6651 +
6652 +static void do_work(void *data, int pending) // what to do with pending ???
6653 +{
6654 + work_container_t *container = (work_container_t *)data;
6655 + dwc_workq_t *wq = container->wq;
6656 + dwc_irqflags_t flags;
6657 +
6658 + if (container->hz) {
6659 + pause("dw3wrk", container->hz);
6660 + }
6661 +
6662 + container->cb(container->data);
6663 + DWC_DEBUG("Work done: %s, container=%p", container->name, container);
6664 +
6665 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6666 +
6667 +#ifdef DEBUG
6668 + DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
6669 +#endif
6670 + if (container->name)
6671 + DWC_FREE(container->name);
6672 + DWC_FREE(container);
6673 + wq->pending--;
6674 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6675 + DWC_WAITQ_TRIGGER(wq->waitq);
6676 +}
6677 +
6678 +static int work_done(void *data)
6679 +{
6680 + dwc_workq_t *workq = (dwc_workq_t *)data;
6681 +
6682 + return workq->pending == 0;
6683 +}
6684 +
6685 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
6686 +{
6687 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
6688 +}
6689 +
6690 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
6691 +{
6692 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
6693 +
6694 + if (!wq) {
6695 + DWC_ERROR("Cannot allocate memory for workqueue");
6696 + return NULL;
6697 + }
6698 +
6699 + wq->taskq = taskqueue_create(name, M_NOWAIT, taskqueue_thread_enqueue, &wq->taskq);
6700 + if (!wq->taskq) {
6701 + DWC_ERROR("Cannot allocate memory for taskqueue");
6702 + goto no_taskq;
6703 + }
6704 +
6705 + wq->pending = 0;
6706 +
6707 + wq->lock = DWC_SPINLOCK_ALLOC();
6708 + if (!wq->lock) {
6709 + DWC_ERROR("Cannot allocate memory for spinlock");
6710 + goto no_lock;
6711 + }
6712 +
6713 + wq->waitq = DWC_WAITQ_ALLOC();
6714 + if (!wq->waitq) {
6715 + DWC_ERROR("Cannot allocate memory for waitqueue");
6716 + goto no_waitq;
6717 + }
6718 +
6719 + taskqueue_start_threads(&wq->taskq, 1, PWAIT, "%s taskq", "dw3tsk");
6720 +
6721 +#ifdef DEBUG
6722 + DWC_CIRCLEQ_INIT(&wq->entries);
6723 +#endif
6724 + return wq;
6725 +
6726 + no_waitq:
6727 + DWC_SPINLOCK_FREE(wq->lock);
6728 + no_lock:
6729 + taskqueue_free(wq->taskq);
6730 + no_taskq:
6731 + DWC_FREE(wq);
6732 +
6733 + return NULL;
6734 +}
6735 +
6736 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
6737 +{
6738 +#ifdef DEBUG
6739 + dwc_irqflags_t flags;
6740 +
6741 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6742 +
6743 + if (wq->pending != 0) {
6744 + struct work_container *container;
6745 +
6746 + DWC_ERROR("Destroying work queue with pending work");
6747 +
6748 + DWC_CIRCLEQ_FOREACH(container, &wq->entries, entry) {
6749 + DWC_ERROR("Work %s still pending", container->name);
6750 + }
6751 + }
6752 +
6753 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6754 +#endif
6755 + DWC_WAITQ_FREE(wq->waitq);
6756 + DWC_SPINLOCK_FREE(wq->lock);
6757 + taskqueue_free(wq->taskq);
6758 + DWC_FREE(wq);
6759 +}
6760 +
6761 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
6762 + char *format, ...)
6763 +{
6764 + dwc_irqflags_t flags;
6765 + work_container_t *container;
6766 + static char name[128];
6767 + va_list args;
6768 +
6769 + va_start(args, format);
6770 + DWC_VSNPRINTF(name, 128, format, args);
6771 + va_end(args);
6772 +
6773 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6774 + wq->pending++;
6775 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6776 + DWC_WAITQ_TRIGGER(wq->waitq);
6777 +
6778 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
6779 + if (!container) {
6780 + DWC_ERROR("Cannot allocate memory for container");
6781 + return;
6782 + }
6783 +
6784 + container->name = DWC_STRDUP(name);
6785 + if (!container->name) {
6786 + DWC_ERROR("Cannot allocate memory for container->name");
6787 + DWC_FREE(container);
6788 + return;
6789 + }
6790 +
6791 + container->cb = cb;
6792 + container->data = data;
6793 + container->wq = wq;
6794 + container->hz = 0;
6795 +
6796 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
6797 +
6798 + TASK_INIT(&container->task, 0, do_work, container);
6799 +
6800 +#ifdef DEBUG
6801 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
6802 +#endif
6803 + taskqueue_enqueue_fast(wq->taskq, &container->task);
6804 +}
6805 +
6806 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
6807 + void *data, uint32_t time, char *format, ...)
6808 +{
6809 + dwc_irqflags_t flags;
6810 + work_container_t *container;
6811 + static char name[128];
6812 + struct timeval tv;
6813 + va_list args;
6814 +
6815 + va_start(args, format);
6816 + DWC_VSNPRINTF(name, 128, format, args);
6817 + va_end(args);
6818 +
6819 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6820 + wq->pending++;
6821 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6822 + DWC_WAITQ_TRIGGER(wq->waitq);
6823 +
6824 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
6825 + if (!container) {
6826 + DWC_ERROR("Cannot allocate memory for container");
6827 + return;
6828 + }
6829 +
6830 + container->name = DWC_STRDUP(name);
6831 + if (!container->name) {
6832 + DWC_ERROR("Cannot allocate memory for container->name");
6833 + DWC_FREE(container);
6834 + return;
6835 + }
6836 +
6837 + container->cb = cb;
6838 + container->data = data;
6839 + container->wq = wq;
6840 +
6841 + tv.tv_sec = time / 1000;
6842 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
6843 + container->hz = tvtohz(&tv);
6844 +
6845 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
6846 +
6847 + TASK_INIT(&container->task, 0, do_work, container);
6848 +
6849 +#ifdef DEBUG
6850 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
6851 +#endif
6852 + taskqueue_enqueue_fast(wq->taskq, &container->task);
6853 +}
6854 +
6855 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
6856 +{
6857 + return wq->pending;
6858 +}
6859 diff --git a/drivers/usb/host/dwc_common_port/dwc_common_linux.c b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
6860 new file mode 100644
6861 index 0000000..440bcfc
6862 --- /dev/null
6863 +++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
6864 @@ -0,0 +1,1421 @@
6865 +#include <linux/kernel.h>
6866 +#include <linux/init.h>
6867 +#include <linux/module.h>
6868 +#include <linux/kthread.h>
6869 +
6870 +#ifdef DWC_CCLIB
6871 +# include "dwc_cc.h"
6872 +#endif
6873 +
6874 +#ifdef DWC_CRYPTOLIB
6875 +# include "dwc_modpow.h"
6876 +# include "dwc_dh.h"
6877 +# include "dwc_crypto.h"
6878 +#endif
6879 +
6880 +#ifdef DWC_NOTIFYLIB
6881 +# include "dwc_notifier.h"
6882 +#endif
6883 +
6884 +/* OS-Level Implementations */
6885 +
6886 +/* This is the Linux kernel implementation of the DWC platform library. */
6887 +#include <linux/moduleparam.h>
6888 +#include <linux/ctype.h>
6889 +#include <linux/crypto.h>
6890 +#include <linux/delay.h>
6891 +#include <linux/device.h>
6892 +#include <linux/dma-mapping.h>
6893 +#include <linux/cdev.h>
6894 +#include <linux/errno.h>
6895 +#include <linux/interrupt.h>
6896 +#include <linux/jiffies.h>
6897 +#include <linux/list.h>
6898 +#include <linux/pci.h>
6899 +#include <linux/random.h>
6900 +#include <linux/scatterlist.h>
6901 +#include <linux/slab.h>
6902 +#include <linux/stat.h>
6903 +#include <linux/string.h>
6904 +#include <linux/timer.h>
6905 +#include <linux/usb.h>
6906 +
6907 +#include <linux/version.h>
6908 +
6909 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
6910 +# include <linux/usb/gadget.h>
6911 +#else
6912 +# include <linux/usb_gadget.h>
6913 +#endif
6914 +
6915 +#include <asm/io.h>
6916 +#include <asm/page.h>
6917 +#include <asm/uaccess.h>
6918 +#include <asm/unaligned.h>
6919 +
6920 +#include "dwc_os.h"
6921 +#include "dwc_list.h"
6922 +
6923 +
6924 +/* MISC */
6925 +
6926 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
6927 +{
6928 + return memset(dest, byte, size);
6929 +}
6930 +
6931 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
6932 +{
6933 + return memcpy(dest, src, size);
6934 +}
6935 +
6936 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
6937 +{
6938 + return memmove(dest, src, size);
6939 +}
6940 +
6941 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
6942 +{
6943 + return memcmp(m1, m2, size);
6944 +}
6945 +
6946 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
6947 +{
6948 + return strncmp(s1, s2, size);
6949 +}
6950 +
6951 +int DWC_STRCMP(void *s1, void *s2)
6952 +{
6953 + return strcmp(s1, s2);
6954 +}
6955 +
6956 +int DWC_STRLEN(char const *str)
6957 +{
6958 + return strlen(str);
6959 +}
6960 +
6961 +char *DWC_STRCPY(char *to, char const *from)
6962 +{
6963 + return strcpy(to, from);
6964 +}
6965 +
6966 +char *DWC_STRDUP(char const *str)
6967 +{
6968 + int len = DWC_STRLEN(str) + 1;
6969 + char *new = DWC_ALLOC_ATOMIC(len);
6970 +
6971 + if (!new) {
6972 + return NULL;
6973 + }
6974 +
6975 + DWC_MEMCPY(new, str, len);
6976 + return new;
6977 +}
6978 +
6979 +int DWC_ATOI(const char *str, int32_t *value)
6980 +{
6981 + char *end = NULL;
6982 +
6983 + *value = simple_strtol(str, &end, 0);
6984 + if (*end == '\0') {
6985 + return 0;
6986 + }
6987 +
6988 + return -1;
6989 +}
6990 +
6991 +int DWC_ATOUI(const char *str, uint32_t *value)
6992 +{
6993 + char *end = NULL;
6994 +
6995 + *value = simple_strtoul(str, &end, 0);
6996 + if (*end == '\0') {
6997 + return 0;
6998 + }
6999 +
7000 + return -1;
7001 +}
7002 +
7003 +
7004 +#ifdef DWC_UTFLIB
7005 +/* From usbstring.c */
7006 +
7007 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
7008 +{
7009 + int count = 0;
7010 + u8 c;
7011 + u16 uchar;
7012 +
7013 + /* this insists on correct encodings, though not minimal ones.
7014 + * BUT it currently rejects legit 4-byte UTF-8 code points,
7015 + * which need surrogate pairs. (Unicode 3.1 can use them.)
7016 + */
7017 + while (len != 0 && (c = (u8) *s++) != 0) {
7018 + if (unlikely(c & 0x80)) {
7019 + // 2-byte sequence:
7020 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
7021 + if ((c & 0xe0) == 0xc0) {
7022 + uchar = (c & 0x1f) << 6;
7023 +
7024 + c = (u8) *s++;
7025 + if ((c & 0xc0) != 0xc0)
7026 + goto fail;
7027 + c &= 0x3f;
7028 + uchar |= c;
7029 +
7030 + // 3-byte sequence (most CJKV characters):
7031 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
7032 + } else if ((c & 0xf0) == 0xe0) {
7033 + uchar = (c & 0x0f) << 12;
7034 +
7035 + c = (u8) *s++;
7036 + if ((c & 0xc0) != 0xc0)
7037 + goto fail;
7038 + c &= 0x3f;
7039 + uchar |= c << 6;
7040 +
7041 + c = (u8) *s++;
7042 + if ((c & 0xc0) != 0xc0)
7043 + goto fail;
7044 + c &= 0x3f;
7045 + uchar |= c;
7046 +
7047 + /* no bogus surrogates */
7048 + if (0xd800 <= uchar && uchar <= 0xdfff)
7049 + goto fail;
7050 +
7051 + // 4-byte sequence (surrogate pairs, currently rare):
7052 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
7053 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
7054 + // (uuuuu = wwww + 1)
7055 + // FIXME accept the surrogate code points (only)
7056 + } else
7057 + goto fail;
7058 + } else
7059 + uchar = c;
7060 + put_unaligned (cpu_to_le16 (uchar), cp++);
7061 + count++;
7062 + len--;
7063 + }
7064 + return count;
7065 +fail:
7066 + return -1;
7067 +}
7068 +#endif /* DWC_UTFLIB */
7069 +
7070 +
7071 +/* dwc_debug.h */
7072 +
7073 +dwc_bool_t DWC_IN_IRQ(void)
7074 +{
7075 + return in_irq();
7076 +}
7077 +
7078 +dwc_bool_t DWC_IN_BH(void)
7079 +{
7080 + return in_softirq();
7081 +}
7082 +
7083 +void DWC_VPRINTF(char *format, va_list args)
7084 +{
7085 + vprintk(format, args);
7086 +}
7087 +
7088 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
7089 +{
7090 + return vsnprintf(str, size, format, args);
7091 +}
7092 +
7093 +void DWC_PRINTF(char *format, ...)
7094 +{
7095 + va_list args;
7096 +
7097 + va_start(args, format);
7098 + DWC_VPRINTF(format, args);
7099 + va_end(args);
7100 +}
7101 +
7102 +int DWC_SPRINTF(char *buffer, char *format, ...)
7103 +{
7104 + int retval;
7105 + va_list args;
7106 +
7107 + va_start(args, format);
7108 + retval = vsprintf(buffer, format, args);
7109 + va_end(args);
7110 + return retval;
7111 +}
7112 +
7113 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
7114 +{
7115 + int retval;
7116 + va_list args;
7117 +
7118 + va_start(args, format);
7119 + retval = vsnprintf(buffer, size, format, args);
7120 + va_end(args);
7121 + return retval;
7122 +}
7123 +
7124 +void __DWC_WARN(char *format, ...)
7125 +{
7126 + va_list args;
7127 +
7128 + va_start(args, format);
7129 + DWC_PRINTF(KERN_WARNING);
7130 + DWC_VPRINTF(format, args);
7131 + va_end(args);
7132 +}
7133 +
7134 +void __DWC_ERROR(char *format, ...)
7135 +{
7136 + va_list args;
7137 +
7138 + va_start(args, format);
7139 + DWC_PRINTF(KERN_ERR);
7140 + DWC_VPRINTF(format, args);
7141 + va_end(args);
7142 +}
7143 +
7144 +void DWC_EXCEPTION(char *format, ...)
7145 +{
7146 + va_list args;
7147 +
7148 + va_start(args, format);
7149 + DWC_PRINTF(KERN_ERR);
7150 + DWC_VPRINTF(format, args);
7151 + va_end(args);
7152 + BUG_ON(1);
7153 +}
7154 +
7155 +#ifdef DEBUG
7156 +void __DWC_DEBUG(char *format, ...)
7157 +{
7158 + va_list args;
7159 +
7160 + va_start(args, format);
7161 + DWC_PRINTF(KERN_DEBUG);
7162 + DWC_VPRINTF(format, args);
7163 + va_end(args);
7164 +}
7165 +#endif
7166 +
7167 +
7168 +/* dwc_mem.h */
7169 +
7170 +#if 0
7171 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
7172 + uint32_t align,
7173 + uint32_t alloc)
7174 +{
7175 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
7176 + size, align, alloc);
7177 + return (dwc_pool_t *)pool;
7178 +}
7179 +
7180 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
7181 +{
7182 + dma_pool_destroy((struct dma_pool *)pool);
7183 +}
7184 +
7185 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
7186 +{
7187 + return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
7188 +}
7189 +
7190 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
7191 +{
7192 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
7193 + memset(..);
7194 +}
7195 +
7196 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
7197 +{
7198 + dma_pool_free(pool, vaddr, daddr);
7199 +}
7200 +#endif
7201 +
7202 +void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
7203 +{
7204 +#ifdef xxCOSIM /* Only works for 32-bit cosim */
7205 + void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL);
7206 +#else
7207 + void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL | GFP_DMA32);
7208 +#endif
7209 + if (!buf) {
7210 + return NULL;
7211 + }
7212 +
7213 + memset(buf, 0, (size_t)size);
7214 + return buf;
7215 +}
7216 +
7217 +void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
7218 +{
7219 + void *buf = dma_alloc_coherent(NULL, (size_t)size, dma_addr, GFP_ATOMIC);
7220 + if (!buf) {
7221 + return NULL;
7222 + }
7223 + memset(buf, 0, (size_t)size);
7224 + return buf;
7225 +}
7226 +
7227 +void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
7228 +{
7229 + dma_free_coherent(dma_ctx, size, virt_addr, dma_addr);
7230 +}
7231 +
7232 +void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
7233 +{
7234 + return kzalloc(size, GFP_KERNEL);
7235 +}
7236 +
7237 +void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
7238 +{
7239 + return kzalloc(size, GFP_ATOMIC);
7240 +}
7241 +
7242 +void __DWC_FREE(void *mem_ctx, void *addr)
7243 +{
7244 + kfree(addr);
7245 +}
7246 +
7247 +
7248 +#ifdef DWC_CRYPTOLIB
7249 +/* dwc_crypto.h */
7250 +
7251 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
7252 +{
7253 + get_random_bytes(buffer, length);
7254 +}
7255 +
7256 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
7257 +{
7258 + struct crypto_blkcipher *tfm;
7259 + struct blkcipher_desc desc;
7260 + struct scatterlist sgd;
7261 + struct scatterlist sgs;
7262 +
7263 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
7264 + if (tfm == NULL) {
7265 + printk("failed to load transform for aes CBC\n");
7266 + return -1;
7267 + }
7268 +
7269 + crypto_blkcipher_setkey(tfm, key, keylen);
7270 + crypto_blkcipher_set_iv(tfm, iv, 16);
7271 +
7272 + sg_init_one(&sgd, out, messagelen);
7273 + sg_init_one(&sgs, message, messagelen);
7274 +
7275 + desc.tfm = tfm;
7276 + desc.flags = 0;
7277 +
7278 + if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
7279 + crypto_free_blkcipher(tfm);
7280 + DWC_ERROR("AES CBC encryption failed");
7281 + return -1;
7282 + }
7283 +
7284 + crypto_free_blkcipher(tfm);
7285 + return 0;
7286 +}
7287 +
7288 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
7289 +{
7290 + struct crypto_hash *tfm;
7291 + struct hash_desc desc;
7292 + struct scatterlist sg;
7293 +
7294 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
7295 + if (IS_ERR(tfm)) {
7296 + DWC_ERROR("Failed to load transform for sha256: %ld\n", PTR_ERR(tfm));
7297 + return 0;
7298 + }
7299 + desc.tfm = tfm;
7300 + desc.flags = 0;
7301 +
7302 + sg_init_one(&sg, message, len);
7303 + crypto_hash_digest(&desc, &sg, len, out);
7304 + crypto_free_hash(tfm);
7305 +
7306 + return 1;
7307 +}
7308 +
7309 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
7310 + uint8_t *key, uint32_t keylen, uint8_t *out)
7311 +{
7312 + struct crypto_hash *tfm;
7313 + struct hash_desc desc;
7314 + struct scatterlist sg;
7315 +
7316 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
7317 + if (IS_ERR(tfm)) {
7318 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld\n", PTR_ERR(tfm));
7319 + return 0;
7320 + }
7321 + desc.tfm = tfm;
7322 + desc.flags = 0;
7323 +
7324 + sg_init_one(&sg, message, messagelen);
7325 + crypto_hash_setkey(tfm, key, keylen);
7326 + crypto_hash_digest(&desc, &sg, messagelen, out);
7327 + crypto_free_hash(tfm);
7328 +
7329 + return 1;
7330 +}
7331 +#endif /* DWC_CRYPTOLIB */
7332 +
7333 +
7334 +/* Byte Ordering Conversions */
7335 +
7336 +uint32_t DWC_CPU_TO_LE32(uint32_t *p)
7337 +{
7338 +#ifdef __LITTLE_ENDIAN
7339 + return *p;
7340 +#else
7341 + uint8_t *u_p = (uint8_t *)p;
7342 +
7343 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7344 +#endif
7345 +}
7346 +
7347 +uint32_t DWC_CPU_TO_BE32(uint32_t *p)
7348 +{
7349 +#ifdef __BIG_ENDIAN
7350 + return *p;
7351 +#else
7352 + uint8_t *u_p = (uint8_t *)p;
7353 +
7354 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7355 +#endif
7356 +}
7357 +
7358 +uint32_t DWC_LE32_TO_CPU(uint32_t *p)
7359 +{
7360 +#ifdef __LITTLE_ENDIAN
7361 + return *p;
7362 +#else
7363 + uint8_t *u_p = (uint8_t *)p;
7364 +
7365 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7366 +#endif
7367 +}
7368 +
7369 +uint32_t DWC_BE32_TO_CPU(uint32_t *p)
7370 +{
7371 +#ifdef __BIG_ENDIAN
7372 + return *p;
7373 +#else
7374 + uint8_t *u_p = (uint8_t *)p;
7375 +
7376 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7377 +#endif
7378 +}
7379 +
7380 +uint16_t DWC_CPU_TO_LE16(uint16_t *p)
7381 +{
7382 +#ifdef __LITTLE_ENDIAN
7383 + return *p;
7384 +#else
7385 + uint8_t *u_p = (uint8_t *)p;
7386 + return (u_p[1] | (u_p[0] << 8));
7387 +#endif
7388 +}
7389 +
7390 +uint16_t DWC_CPU_TO_BE16(uint16_t *p)
7391 +{
7392 +#ifdef __BIG_ENDIAN
7393 + return *p;
7394 +#else
7395 + uint8_t *u_p = (uint8_t *)p;
7396 + return (u_p[1] | (u_p[0] << 8));
7397 +#endif
7398 +}
7399 +
7400 +uint16_t DWC_LE16_TO_CPU(uint16_t *p)
7401 +{
7402 +#ifdef __LITTLE_ENDIAN
7403 + return *p;
7404 +#else
7405 + uint8_t *u_p = (uint8_t *)p;
7406 + return (u_p[1] | (u_p[0] << 8));
7407 +#endif
7408 +}
7409 +
7410 +uint16_t DWC_BE16_TO_CPU(uint16_t *p)
7411 +{
7412 +#ifdef __BIG_ENDIAN
7413 + return *p;
7414 +#else
7415 + uint8_t *u_p = (uint8_t *)p;
7416 + return (u_p[1] | (u_p[0] << 8));
7417 +#endif
7418 +}
7419 +
7420 +
7421 +/* Registers */
7422 +
7423 +uint32_t DWC_READ_REG32(uint32_t volatile *reg)
7424 +{
7425 + return readl(reg);
7426 +}
7427 +
7428 +#if 0
7429 +uint64_t DWC_READ_REG64(uint64_t volatile *reg)
7430 +{
7431 +}
7432 +#endif
7433 +
7434 +void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value)
7435 +{
7436 + writel(value, reg);
7437 +}
7438 +
7439 +#if 0
7440 +void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value)
7441 +{
7442 +}
7443 +#endif
7444 +
7445 +void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask)
7446 +{
7447 + writel((readl(reg) & ~clear_mask) | set_mask, reg);
7448 +}
7449 +
7450 +#if 0
7451 +void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask)
7452 +{
7453 +}
7454 +#endif
7455 +
7456 +
7457 +/* Locking */
7458 +
7459 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
7460 +{
7461 + spinlock_t *sl = (spinlock_t *)1;
7462 +
7463 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7464 + sl = DWC_ALLOC(sizeof(*sl));
7465 + if (!sl) {
7466 + DWC_ERROR("Cannot allocate memory for spinlock\n");
7467 + return NULL;
7468 + }
7469 +
7470 + spin_lock_init(sl);
7471 +#endif
7472 + return (dwc_spinlock_t *)sl;
7473 +}
7474 +
7475 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
7476 +{
7477 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7478 + DWC_FREE(lock);
7479 +#endif
7480 +}
7481 +
7482 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
7483 +{
7484 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7485 + spin_lock((spinlock_t *)lock);
7486 +#endif
7487 +}
7488 +
7489 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
7490 +{
7491 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7492 + spin_unlock((spinlock_t *)lock);
7493 +#endif
7494 +}
7495 +
7496 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
7497 +{
7498 + dwc_irqflags_t f;
7499 +
7500 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7501 + spin_lock_irqsave((spinlock_t *)lock, f);
7502 +#else
7503 + local_irq_save(f);
7504 +#endif
7505 + *flags = f;
7506 +}
7507 +
7508 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
7509 +{
7510 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7511 + spin_unlock_irqrestore((spinlock_t *)lock, flags);
7512 +#else
7513 + local_irq_restore(flags);
7514 +#endif
7515 +}
7516 +
7517 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
7518 +{
7519 + struct mutex *m;
7520 + dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex));
7521 +
7522 + if (!mutex) {
7523 + DWC_ERROR("Cannot allocate memory for mutex\n");
7524 + return NULL;
7525 + }
7526 +
7527 + m = (struct mutex *)mutex;
7528 + mutex_init(m);
7529 + return mutex;
7530 +}
7531 +
7532 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
7533 +#else
7534 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
7535 +{
7536 + mutex_destroy((struct mutex *)mutex);
7537 + DWC_FREE(mutex);
7538 +}
7539 +#endif
7540 +
7541 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
7542 +{
7543 + struct mutex *m = (struct mutex *)mutex;
7544 + mutex_lock(m);
7545 +}
7546 +
7547 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
7548 +{
7549 + struct mutex *m = (struct mutex *)mutex;
7550 + return mutex_trylock(m);
7551 +}
7552 +
7553 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
7554 +{
7555 + struct mutex *m = (struct mutex *)mutex;
7556 + mutex_unlock(m);
7557 +}
7558 +
7559 +
7560 +/* Timing */
7561 +
7562 +void DWC_UDELAY(uint32_t usecs)
7563 +{
7564 + udelay(usecs);
7565 +}
7566 +
7567 +void DWC_MDELAY(uint32_t msecs)
7568 +{
7569 + mdelay(msecs);
7570 +}
7571 +
7572 +void DWC_MSLEEP(uint32_t msecs)
7573 +{
7574 + msleep(msecs);
7575 +}
7576 +
7577 +uint32_t DWC_TIME(void)
7578 +{
7579 + return jiffies_to_msecs(jiffies);
7580 +}
7581 +
7582 +
7583 +/* Timers */
7584 +
7585 +struct dwc_timer {
7586 + struct timer_list *t;
7587 + char *name;
7588 + dwc_timer_callback_t cb;
7589 + void *data;
7590 + uint8_t scheduled;
7591 + dwc_spinlock_t *lock;
7592 +};
7593 +
7594 +static void timer_callback(unsigned long data)
7595 +{
7596 + dwc_timer_t *timer = (dwc_timer_t *)data;
7597 + dwc_irqflags_t flags;
7598 +
7599 + DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
7600 + timer->scheduled = 0;
7601 + DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
7602 + DWC_DEBUGC("Timer %s callback", timer->name);
7603 + timer->cb(timer->data);
7604 +}
7605 +
7606 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
7607 +{
7608 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
7609 +
7610 + if (!t) {
7611 + DWC_ERROR("Cannot allocate memory for timer");
7612 + return NULL;
7613 + }
7614 +
7615 + t->t = DWC_ALLOC(sizeof(*t->t));
7616 + if (!t->t) {
7617 + DWC_ERROR("Cannot allocate memory for timer->t");
7618 + goto no_timer;
7619 + }
7620 +
7621 + t->name = DWC_STRDUP(name);
7622 + if (!t->name) {
7623 + DWC_ERROR("Cannot allocate memory for timer->name");
7624 + goto no_name;
7625 + }
7626 +
7627 + t->lock = DWC_SPINLOCK_ALLOC();
7628 + if (!t->lock) {
7629 + DWC_ERROR("Cannot allocate memory for lock");
7630 + goto no_lock;
7631 + }
7632 +
7633 + t->scheduled = 0;
7634 + t->t->base = &boot_tvec_bases;
7635 + t->t->expires = jiffies;
7636 + setup_timer(t->t, timer_callback, (unsigned long)t);
7637 +
7638 + t->cb = cb;
7639 + t->data = data;
7640 +
7641 + return t;
7642 +
7643 + no_lock:
7644 + DWC_FREE(t->name);
7645 + no_name:
7646 + DWC_FREE(t->t);
7647 + no_timer:
7648 + DWC_FREE(t);
7649 + return NULL;
7650 +}
7651 +
7652 +void DWC_TIMER_FREE(dwc_timer_t *timer)
7653 +{
7654 + dwc_irqflags_t flags;
7655 +
7656 + DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
7657 +
7658 + if (timer->scheduled) {
7659 + del_timer(timer->t);
7660 + timer->scheduled = 0;
7661 + }
7662 +
7663 + DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
7664 + DWC_SPINLOCK_FREE(timer->lock);
7665 + DWC_FREE(timer->t);
7666 + DWC_FREE(timer->name);
7667 + DWC_FREE(timer);
7668 +}
7669 +
7670 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
7671 +{
7672 + dwc_irqflags_t flags;
7673 +
7674 + DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
7675 +
7676 + if (!timer->scheduled) {
7677 + timer->scheduled = 1;
7678 + DWC_DEBUGC("Scheduling timer %s to expire in +%d msec", timer->name, time);
7679 + timer->t->expires = jiffies + msecs_to_jiffies(time);
7680 + add_timer(timer->t);
7681 + } else {
7682 + DWC_DEBUGC("Modifying timer %s to expire in +%d msec", timer->name, time);
7683 + mod_timer(timer->t, jiffies + msecs_to_jiffies(time));
7684 + }
7685 +
7686 + DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
7687 +}
7688 +
7689 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
7690 +{
7691 + del_timer(timer->t);
7692 +}
7693 +
7694 +
7695 +/* Wait Queues */
7696 +
7697 +struct dwc_waitq {
7698 + wait_queue_head_t queue;
7699 + int abort;
7700 +};
7701 +
7702 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
7703 +{
7704 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
7705 +
7706 + if (!wq) {
7707 + DWC_ERROR("Cannot allocate memory for waitqueue\n");
7708 + return NULL;
7709 + }
7710 +
7711 + init_waitqueue_head(&wq->queue);
7712 + wq->abort = 0;
7713 + return wq;
7714 +}
7715 +
7716 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
7717 +{
7718 + DWC_FREE(wq);
7719 +}
7720 +
7721 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
7722 +{
7723 + int result = wait_event_interruptible(wq->queue,
7724 + cond(data) || wq->abort);
7725 + if (result == -ERESTARTSYS) {
7726 + wq->abort = 0;
7727 + return -DWC_E_RESTART;
7728 + }
7729 +
7730 + if (wq->abort == 1) {
7731 + wq->abort = 0;
7732 + return -DWC_E_ABORT;
7733 + }
7734 +
7735 + wq->abort = 0;
7736 +
7737 + if (result == 0) {
7738 + return 0;
7739 + }
7740 +
7741 + return -DWC_E_UNKNOWN;
7742 +}
7743 +
7744 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
7745 + void *data, int32_t msecs)
7746 +{
7747 + int32_t tmsecs;
7748 + int result = wait_event_interruptible_timeout(wq->queue,
7749 + cond(data) || wq->abort,
7750 + msecs_to_jiffies(msecs));
7751 + if (result == -ERESTARTSYS) {
7752 + wq->abort = 0;
7753 + return -DWC_E_RESTART;
7754 + }
7755 +
7756 + if (wq->abort == 1) {
7757 + wq->abort = 0;
7758 + return -DWC_E_ABORT;
7759 + }
7760 +
7761 + wq->abort = 0;
7762 +
7763 + if (result > 0) {
7764 + tmsecs = jiffies_to_msecs(result);
7765 + if (!tmsecs) {
7766 + return 1;
7767 + }
7768 +
7769 + return tmsecs;
7770 + }
7771 +
7772 + if (result == 0) {
7773 + return -DWC_E_TIMEOUT;
7774 + }
7775 +
7776 + return -DWC_E_UNKNOWN;
7777 +}
7778 +
7779 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
7780 +{
7781 + wq->abort = 0;
7782 + wake_up_interruptible(&wq->queue);
7783 +}
7784 +
7785 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
7786 +{
7787 + wq->abort = 1;
7788 + wake_up_interruptible(&wq->queue);
7789 +}
7790 +
7791 +
7792 +/* Threading */
7793 +
7794 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
7795 +{
7796 + struct task_struct *thread = kthread_run(func, data, name);
7797 +
7798 + if (thread == ERR_PTR(-ENOMEM)) {
7799 + return NULL;
7800 + }
7801 +
7802 + return (dwc_thread_t *)thread;
7803 +}
7804 +
7805 +int DWC_THREAD_STOP(dwc_thread_t *thread)
7806 +{
7807 + return kthread_stop((struct task_struct *)thread);
7808 +}
7809 +
7810 +dwc_bool_t DWC_THREAD_SHOULD_STOP(void)
7811 +{
7812 + return kthread_should_stop();
7813 +}
7814 +
7815 +
7816 +/* tasklets
7817 + - run in interrupt context (cannot sleep)
7818 + - each tasklet runs on a single CPU
7819 + - different tasklets can be running simultaneously on different CPUs
7820 + */
7821 +struct dwc_tasklet {
7822 + struct tasklet_struct t;
7823 + dwc_tasklet_callback_t cb;
7824 + void *data;
7825 +};
7826 +
7827 +static void tasklet_callback(unsigned long data)
7828 +{
7829 + dwc_tasklet_t *t = (dwc_tasklet_t *)data;
7830 + t->cb(t->data);
7831 +}
7832 +
7833 +dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
7834 +{
7835 + dwc_tasklet_t *t = DWC_ALLOC(sizeof(*t));
7836 +
7837 + if (t) {
7838 + t->cb = cb;
7839 + t->data = data;
7840 + tasklet_init(&t->t, tasklet_callback, (unsigned long)t);
7841 + } else {
7842 + DWC_ERROR("Cannot allocate memory for tasklet\n");
7843 + }
7844 +
7845 + return t;
7846 +}
7847 +
7848 +void DWC_TASK_FREE(dwc_tasklet_t *task)
7849 +{
7850 + DWC_FREE(task);
7851 +}
7852 +
7853 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
7854 +{
7855 + tasklet_schedule(&task->t);
7856 +}
7857 +
7858 +
7859 +/* workqueues
7860 + - run in process context (can sleep)
7861 + */
7862 +typedef struct work_container {
7863 + dwc_work_callback_t cb;
7864 + void *data;
7865 + dwc_workq_t *wq;
7866 + char *name;
7867 +
7868 +#ifdef DEBUG
7869 + DWC_CIRCLEQ_ENTRY(work_container) entry;
7870 +#endif
7871 + struct delayed_work work;
7872 +} work_container_t;
7873 +
7874 +#ifdef DEBUG
7875 +DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
7876 +#endif
7877 +
7878 +struct dwc_workq {
7879 + struct workqueue_struct *wq;
7880 + dwc_spinlock_t *lock;
7881 + dwc_waitq_t *waitq;
7882 + int pending;
7883 +
7884 +#ifdef DEBUG
7885 + struct work_container_queue entries;
7886 +#endif
7887 +};
7888 +
7889 +static void do_work(struct work_struct *work)
7890 +{
7891 + dwc_irqflags_t flags;
7892 + struct delayed_work *dw = container_of(work, struct delayed_work, work);
7893 + work_container_t *container = container_of(dw, struct work_container, work);
7894 + dwc_workq_t *wq = container->wq;
7895 +
7896 + container->cb(container->data);
7897 +
7898 +#ifdef DEBUG
7899 + DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
7900 +#endif
7901 + DWC_DEBUGC("Work done: %s, container=%p", container->name, container);
7902 + if (container->name) {
7903 + DWC_FREE(container->name);
7904 + }
7905 + DWC_FREE(container);
7906 +
7907 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
7908 + wq->pending--;
7909 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
7910 + DWC_WAITQ_TRIGGER(wq->waitq);
7911 +}
7912 +
7913 +static int work_done(void *data)
7914 +{
7915 + dwc_workq_t *workq = (dwc_workq_t *)data;
7916 + return workq->pending == 0;
7917 +}
7918 +
7919 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
7920 +{
7921 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
7922 +}
7923 +
7924 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
7925 +{
7926 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
7927 +
7928 + if (!wq) {
7929 + return NULL;
7930 + }
7931 +
7932 + wq->wq = create_singlethread_workqueue(name);
7933 + if (!wq->wq) {
7934 + goto no_wq;
7935 + }
7936 +
7937 + wq->pending = 0;
7938 +
7939 + wq->lock = DWC_SPINLOCK_ALLOC();
7940 + if (!wq->lock) {
7941 + goto no_lock;
7942 + }
7943 +
7944 + wq->waitq = DWC_WAITQ_ALLOC();
7945 + if (!wq->waitq) {
7946 + goto no_waitq;
7947 + }
7948 +
7949 +#ifdef DEBUG
7950 + DWC_CIRCLEQ_INIT(&wq->entries);
7951 +#endif
7952 + return wq;
7953 +
7954 + no_waitq:
7955 + DWC_SPINLOCK_FREE(wq->lock);
7956 + no_lock:
7957 + destroy_workqueue(wq->wq);
7958 + no_wq:
7959 + DWC_FREE(wq);
7960 +
7961 + return NULL;
7962 +}
7963 +
7964 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
7965 +{
7966 +#ifdef DEBUG
7967 + if (wq->pending != 0) {
7968 + struct work_container *wc;
7969 + DWC_ERROR("Destroying work queue with pending work");
7970 + DWC_CIRCLEQ_FOREACH(wc, &wq->entries, entry) {
7971 + DWC_ERROR("Work %s still pending", wc->name);
7972 + }
7973 + }
7974 +#endif
7975 + destroy_workqueue(wq->wq);
7976 + DWC_SPINLOCK_FREE(wq->lock);
7977 + DWC_WAITQ_FREE(wq->waitq);
7978 + DWC_FREE(wq);
7979 +}
7980 +
7981 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
7982 + char *format, ...)
7983 +{
7984 + dwc_irqflags_t flags;
7985 + work_container_t *container;
7986 + static char name[128];
7987 + va_list args;
7988 +
7989 + va_start(args, format);
7990 + DWC_VSNPRINTF(name, 128, format, args);
7991 + va_end(args);
7992 +
7993 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
7994 + wq->pending++;
7995 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
7996 + DWC_WAITQ_TRIGGER(wq->waitq);
7997 +
7998 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
7999 + if (!container) {
8000 + DWC_ERROR("Cannot allocate memory for container\n");
8001 + return;
8002 + }
8003 +
8004 + container->name = DWC_STRDUP(name);
8005 + if (!container->name) {
8006 + DWC_ERROR("Cannot allocate memory for container->name\n");
8007 + DWC_FREE(container);
8008 + return;
8009 + }
8010 +
8011 + container->cb = cb;
8012 + container->data = data;
8013 + container->wq = wq;
8014 + DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
8015 + INIT_WORK(&container->work.work, do_work);
8016 +
8017 +#ifdef DEBUG
8018 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
8019 +#endif
8020 + queue_work(wq->wq, &container->work.work);
8021 +}
8022 +
8023 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
8024 + void *data, uint32_t time, char *format, ...)
8025 +{
8026 + dwc_irqflags_t flags;
8027 + work_container_t *container;
8028 + static char name[128];
8029 + va_list args;
8030 +
8031 + va_start(args, format);
8032 + DWC_VSNPRINTF(name, 128, format, args);
8033 + va_end(args);
8034 +
8035 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
8036 + wq->pending++;
8037 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
8038 + DWC_WAITQ_TRIGGER(wq->waitq);
8039 +
8040 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
8041 + if (!container) {
8042 + DWC_ERROR("Cannot allocate memory for container\n");
8043 + return;
8044 + }
8045 +
8046 + container->name = DWC_STRDUP(name);
8047 + if (!container->name) {
8048 + DWC_ERROR("Cannot allocate memory for container->name\n");
8049 + DWC_FREE(container);
8050 + return;
8051 + }
8052 +
8053 + container->cb = cb;
8054 + container->data = data;
8055 + container->wq = wq;
8056 + DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
8057 + INIT_DELAYED_WORK(&container->work, do_work);
8058 +
8059 +#ifdef DEBUG
8060 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
8061 +#endif
8062 + queue_delayed_work(wq->wq, &container->work, msecs_to_jiffies(time));
8063 +}
8064 +
8065 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
8066 +{
8067 + return wq->pending;
8068 +}
8069 +
8070 +
8071 +#ifdef DWC_LIBMODULE
8072 +
8073 +#ifdef DWC_CCLIB
8074 +/* CC */
8075 +EXPORT_SYMBOL(dwc_cc_if_alloc);
8076 +EXPORT_SYMBOL(dwc_cc_if_free);
8077 +EXPORT_SYMBOL(dwc_cc_clear);
8078 +EXPORT_SYMBOL(dwc_cc_add);
8079 +EXPORT_SYMBOL(dwc_cc_remove);
8080 +EXPORT_SYMBOL(dwc_cc_change);
8081 +EXPORT_SYMBOL(dwc_cc_data_for_save);
8082 +EXPORT_SYMBOL(dwc_cc_restore_from_data);
8083 +EXPORT_SYMBOL(dwc_cc_match_chid);
8084 +EXPORT_SYMBOL(dwc_cc_match_cdid);
8085 +EXPORT_SYMBOL(dwc_cc_ck);
8086 +EXPORT_SYMBOL(dwc_cc_chid);
8087 +EXPORT_SYMBOL(dwc_cc_cdid);
8088 +EXPORT_SYMBOL(dwc_cc_name);
8089 +#endif /* DWC_CCLIB */
8090 +
8091 +#ifdef DWC_CRYPTOLIB
8092 +# ifndef CONFIG_MACH_IPMATE
8093 +/* Modpow */
8094 +EXPORT_SYMBOL(dwc_modpow);
8095 +
8096 +/* DH */
8097 +EXPORT_SYMBOL(dwc_dh_modpow);
8098 +EXPORT_SYMBOL(dwc_dh_derive_keys);
8099 +EXPORT_SYMBOL(dwc_dh_pk);
8100 +# endif /* CONFIG_MACH_IPMATE */
8101 +
8102 +/* Crypto */
8103 +EXPORT_SYMBOL(dwc_wusb_aes_encrypt);
8104 +EXPORT_SYMBOL(dwc_wusb_cmf);
8105 +EXPORT_SYMBOL(dwc_wusb_prf);
8106 +EXPORT_SYMBOL(dwc_wusb_fill_ccm_nonce);
8107 +EXPORT_SYMBOL(dwc_wusb_gen_nonce);
8108 +EXPORT_SYMBOL(dwc_wusb_gen_key);
8109 +EXPORT_SYMBOL(dwc_wusb_gen_mic);
8110 +#endif /* DWC_CRYPTOLIB */
8111 +
8112 +/* Notification */
8113 +#ifdef DWC_NOTIFYLIB
8114 +EXPORT_SYMBOL(dwc_alloc_notification_manager);
8115 +EXPORT_SYMBOL(dwc_free_notification_manager);
8116 +EXPORT_SYMBOL(dwc_register_notifier);
8117 +EXPORT_SYMBOL(dwc_unregister_notifier);
8118 +EXPORT_SYMBOL(dwc_add_observer);
8119 +EXPORT_SYMBOL(dwc_remove_observer);
8120 +EXPORT_SYMBOL(dwc_notify);
8121 +#endif
8122 +
8123 +/* Memory Debugging Routines */
8124 +#ifdef DWC_DEBUG_MEMORY
8125 +EXPORT_SYMBOL(dwc_alloc_debug);
8126 +EXPORT_SYMBOL(dwc_alloc_atomic_debug);
8127 +EXPORT_SYMBOL(dwc_free_debug);
8128 +EXPORT_SYMBOL(dwc_dma_alloc_debug);
8129 +EXPORT_SYMBOL(dwc_dma_free_debug);
8130 +#endif
8131 +
8132 +EXPORT_SYMBOL(DWC_MEMSET);
8133 +EXPORT_SYMBOL(DWC_MEMCPY);
8134 +EXPORT_SYMBOL(DWC_MEMMOVE);
8135 +EXPORT_SYMBOL(DWC_MEMCMP);
8136 +EXPORT_SYMBOL(DWC_STRNCMP);
8137 +EXPORT_SYMBOL(DWC_STRCMP);
8138 +EXPORT_SYMBOL(DWC_STRLEN);
8139 +EXPORT_SYMBOL(DWC_STRCPY);
8140 +EXPORT_SYMBOL(DWC_STRDUP);
8141 +EXPORT_SYMBOL(DWC_ATOI);
8142 +EXPORT_SYMBOL(DWC_ATOUI);
8143 +
8144 +#ifdef DWC_UTFLIB
8145 +EXPORT_SYMBOL(DWC_UTF8_TO_UTF16LE);
8146 +#endif /* DWC_UTFLIB */
8147 +
8148 +EXPORT_SYMBOL(DWC_IN_IRQ);
8149 +EXPORT_SYMBOL(DWC_IN_BH);
8150 +EXPORT_SYMBOL(DWC_VPRINTF);
8151 +EXPORT_SYMBOL(DWC_VSNPRINTF);
8152 +EXPORT_SYMBOL(DWC_PRINTF);
8153 +EXPORT_SYMBOL(DWC_SPRINTF);
8154 +EXPORT_SYMBOL(DWC_SNPRINTF);
8155 +EXPORT_SYMBOL(__DWC_WARN);
8156 +EXPORT_SYMBOL(__DWC_ERROR);
8157 +EXPORT_SYMBOL(DWC_EXCEPTION);
8158 +
8159 +#ifdef DEBUG
8160 +EXPORT_SYMBOL(__DWC_DEBUG);
8161 +#endif
8162 +
8163 +EXPORT_SYMBOL(__DWC_DMA_ALLOC);
8164 +EXPORT_SYMBOL(__DWC_DMA_ALLOC_ATOMIC);
8165 +EXPORT_SYMBOL(__DWC_DMA_FREE);
8166 +EXPORT_SYMBOL(__DWC_ALLOC);
8167 +EXPORT_SYMBOL(__DWC_ALLOC_ATOMIC);
8168 +EXPORT_SYMBOL(__DWC_FREE);
8169 +
8170 +#ifdef DWC_CRYPTOLIB
8171 +EXPORT_SYMBOL(DWC_RANDOM_BYTES);
8172 +EXPORT_SYMBOL(DWC_AES_CBC);
8173 +EXPORT_SYMBOL(DWC_SHA256);
8174 +EXPORT_SYMBOL(DWC_HMAC_SHA256);
8175 +#endif
8176 +
8177 +EXPORT_SYMBOL(DWC_CPU_TO_LE32);
8178 +EXPORT_SYMBOL(DWC_CPU_TO_BE32);
8179 +EXPORT_SYMBOL(DWC_LE32_TO_CPU);
8180 +EXPORT_SYMBOL(DWC_BE32_TO_CPU);
8181 +EXPORT_SYMBOL(DWC_CPU_TO_LE16);
8182 +EXPORT_SYMBOL(DWC_CPU_TO_BE16);
8183 +EXPORT_SYMBOL(DWC_LE16_TO_CPU);
8184 +EXPORT_SYMBOL(DWC_BE16_TO_CPU);
8185 +EXPORT_SYMBOL(DWC_READ_REG32);
8186 +EXPORT_SYMBOL(DWC_WRITE_REG32);
8187 +EXPORT_SYMBOL(DWC_MODIFY_REG32);
8188 +
8189 +#if 0
8190 +EXPORT_SYMBOL(DWC_READ_REG64);
8191 +EXPORT_SYMBOL(DWC_WRITE_REG64);
8192 +EXPORT_SYMBOL(DWC_MODIFY_REG64);
8193 +#endif
8194 +
8195 +EXPORT_SYMBOL(DWC_SPINLOCK_ALLOC);
8196 +EXPORT_SYMBOL(DWC_SPINLOCK_FREE);
8197 +EXPORT_SYMBOL(DWC_SPINLOCK);
8198 +EXPORT_SYMBOL(DWC_SPINUNLOCK);
8199 +EXPORT_SYMBOL(DWC_SPINLOCK_IRQSAVE);
8200 +EXPORT_SYMBOL(DWC_SPINUNLOCK_IRQRESTORE);
8201 +EXPORT_SYMBOL(DWC_MUTEX_ALLOC);
8202 +
8203 +#if (!defined(DWC_LINUX) || !defined(CONFIG_DEBUG_MUTEXES))
8204 +EXPORT_SYMBOL(DWC_MUTEX_FREE);
8205 +#endif
8206 +
8207 +EXPORT_SYMBOL(DWC_MUTEX_LOCK);
8208 +EXPORT_SYMBOL(DWC_MUTEX_TRYLOCK);
8209 +EXPORT_SYMBOL(DWC_MUTEX_UNLOCK);
8210 +EXPORT_SYMBOL(DWC_UDELAY);
8211 +EXPORT_SYMBOL(DWC_MDELAY);
8212 +EXPORT_SYMBOL(DWC_MSLEEP);
8213 +EXPORT_SYMBOL(DWC_TIME);
8214 +EXPORT_SYMBOL(DWC_TIMER_ALLOC);
8215 +EXPORT_SYMBOL(DWC_TIMER_FREE);
8216 +EXPORT_SYMBOL(DWC_TIMER_SCHEDULE);
8217 +EXPORT_SYMBOL(DWC_TIMER_CANCEL);
8218 +EXPORT_SYMBOL(DWC_WAITQ_ALLOC);
8219 +EXPORT_SYMBOL(DWC_WAITQ_FREE);
8220 +EXPORT_SYMBOL(DWC_WAITQ_WAIT);
8221 +EXPORT_SYMBOL(DWC_WAITQ_WAIT_TIMEOUT);
8222 +EXPORT_SYMBOL(DWC_WAITQ_TRIGGER);
8223 +EXPORT_SYMBOL(DWC_WAITQ_ABORT);
8224 +EXPORT_SYMBOL(DWC_THREAD_RUN);
8225 +EXPORT_SYMBOL(DWC_THREAD_STOP);
8226 +EXPORT_SYMBOL(DWC_THREAD_SHOULD_STOP);
8227 +EXPORT_SYMBOL(DWC_TASK_ALLOC);
8228 +EXPORT_SYMBOL(DWC_TASK_FREE);
8229 +EXPORT_SYMBOL(DWC_TASK_SCHEDULE);
8230 +EXPORT_SYMBOL(DWC_WORKQ_WAIT_WORK_DONE);
8231 +EXPORT_SYMBOL(DWC_WORKQ_ALLOC);
8232 +EXPORT_SYMBOL(DWC_WORKQ_FREE);
8233 +EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE);
8234 +EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE_DELAYED);
8235 +EXPORT_SYMBOL(DWC_WORKQ_PENDING);
8236 +
8237 +static int dwc_common_port_init_module(void)
8238 +{
8239 + int result = 0;
8240 +
8241 + printk(KERN_DEBUG "Module dwc_common_port init\n" );
8242 +
8243 +#ifdef DWC_DEBUG_MEMORY
8244 + result = dwc_memory_debug_start(NULL);
8245 + if (result) {
8246 + printk(KERN_ERR
8247 + "dwc_memory_debug_start() failed with error %d\n",
8248 + result);
8249 + return result;
8250 + }
8251 +#endif
8252 +
8253 +#ifdef DWC_NOTIFYLIB
8254 + result = dwc_alloc_notification_manager(NULL, NULL);
8255 + if (result) {
8256 + printk(KERN_ERR
8257 + "dwc_alloc_notification_manager() failed with error %d\n",
8258 + result);
8259 + return result;
8260 + }
8261 +#endif
8262 + return result;
8263 +}
8264 +
8265 +static void dwc_common_port_exit_module(void)
8266 +{
8267 + printk(KERN_DEBUG "Module dwc_common_port exit\n" );
8268 +
8269 +#ifdef DWC_NOTIFYLIB
8270 + dwc_free_notification_manager();
8271 +#endif
8272 +
8273 +#ifdef DWC_DEBUG_MEMORY
8274 + dwc_memory_debug_stop();
8275 +#endif
8276 +}
8277 +
8278 +module_init(dwc_common_port_init_module);
8279 +module_exit(dwc_common_port_exit_module);
8280 +
8281 +MODULE_DESCRIPTION("DWC Common Library - Portable version");
8282 +MODULE_AUTHOR("Synopsys Inc.");
8283 +MODULE_LICENSE ("GPL");
8284 +
8285 +#endif /* DWC_LIBMODULE */
8286 diff --git a/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
8287 new file mode 100644
8288 index 0000000..49b07e1
8289 --- /dev/null
8290 +++ b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
8291 @@ -0,0 +1,1275 @@
8292 +#include "dwc_os.h"
8293 +#include "dwc_list.h"
8294 +
8295 +#ifdef DWC_CCLIB
8296 +# include "dwc_cc.h"
8297 +#endif
8298 +
8299 +#ifdef DWC_CRYPTOLIB
8300 +# include "dwc_modpow.h"
8301 +# include "dwc_dh.h"
8302 +# include "dwc_crypto.h"
8303 +#endif
8304 +
8305 +#ifdef DWC_NOTIFYLIB
8306 +# include "dwc_notifier.h"
8307 +#endif
8308 +
8309 +/* OS-Level Implementations */
8310 +
8311 +/* This is the NetBSD 4.0.1 kernel implementation of the DWC platform library. */
8312 +
8313 +
8314 +/* MISC */
8315 +
8316 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
8317 +{
8318 + return memset(dest, byte, size);
8319 +}
8320 +
8321 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
8322 +{
8323 + return memcpy(dest, src, size);
8324 +}
8325 +
8326 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
8327 +{
8328 + bcopy(src, dest, size);
8329 + return dest;
8330 +}
8331 +
8332 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
8333 +{
8334 + return memcmp(m1, m2, size);
8335 +}
8336 +
8337 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
8338 +{
8339 + return strncmp(s1, s2, size);
8340 +}
8341 +
8342 +int DWC_STRCMP(void *s1, void *s2)
8343 +{
8344 + return strcmp(s1, s2);
8345 +}
8346 +
8347 +int DWC_STRLEN(char const *str)
8348 +{
8349 + return strlen(str);
8350 +}
8351 +
8352 +char *DWC_STRCPY(char *to, char const *from)
8353 +{
8354 + return strcpy(to, from);
8355 +}
8356 +
8357 +char *DWC_STRDUP(char const *str)
8358 +{
8359 + int len = DWC_STRLEN(str) + 1;
8360 + char *new = DWC_ALLOC_ATOMIC(len);
8361 +
8362 + if (!new) {
8363 + return NULL;
8364 + }
8365 +
8366 + DWC_MEMCPY(new, str, len);
8367 + return new;
8368 +}
8369 +
8370 +int DWC_ATOI(char *str, int32_t *value)
8371 +{
8372 + char *end = NULL;
8373 +
8374 + /* NetBSD doesn't have 'strtol' in the kernel, but 'strtoul'
8375 + * should be equivalent on 2's complement machines
8376 + */
8377 + *value = strtoul(str, &end, 0);
8378 + if (*end == '\0') {
8379 + return 0;
8380 + }
8381 +
8382 + return -1;
8383 +}
8384 +
8385 +int DWC_ATOUI(char *str, uint32_t *value)
8386 +{
8387 + char *end = NULL;
8388 +
8389 + *value = strtoul(str, &end, 0);
8390 + if (*end == '\0') {
8391 + return 0;
8392 + }
8393 +
8394 + return -1;
8395 +}
8396 +
8397 +
8398 +#ifdef DWC_UTFLIB
8399 +/* From usbstring.c */
8400 +
8401 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
8402 +{
8403 + int count = 0;
8404 + u8 c;
8405 + u16 uchar;
8406 +
8407 + /* this insists on correct encodings, though not minimal ones.
8408 + * BUT it currently rejects legit 4-byte UTF-8 code points,
8409 + * which need surrogate pairs. (Unicode 3.1 can use them.)
8410 + */
8411 + while (len != 0 && (c = (u8) *s++) != 0) {
8412 + if (unlikely(c & 0x80)) {
8413 + // 2-byte sequence:
8414 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
8415 + if ((c & 0xe0) == 0xc0) {
8416 + uchar = (c & 0x1f) << 6;
8417 +
8418 + c = (u8) *s++;
8419 + if ((c & 0xc0) != 0xc0)
8420 + goto fail;
8421 + c &= 0x3f;
8422 + uchar |= c;
8423 +
8424 + // 3-byte sequence (most CJKV characters):
8425 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
8426 + } else if ((c & 0xf0) == 0xe0) {
8427 + uchar = (c & 0x0f) << 12;
8428 +
8429 + c = (u8) *s++;
8430 + if ((c & 0xc0) != 0xc0)
8431 + goto fail;
8432 + c &= 0x3f;
8433 + uchar |= c << 6;
8434 +
8435 + c = (u8) *s++;
8436 + if ((c & 0xc0) != 0xc0)
8437 + goto fail;
8438 + c &= 0x3f;
8439 + uchar |= c;
8440 +
8441 + /* no bogus surrogates */
8442 + if (0xd800 <= uchar && uchar <= 0xdfff)
8443 + goto fail;
8444 +
8445 + // 4-byte sequence (surrogate pairs, currently rare):
8446 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
8447 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
8448 + // (uuuuu = wwww + 1)
8449 + // FIXME accept the surrogate code points (only)
8450 + } else
8451 + goto fail;
8452 + } else
8453 + uchar = c;
8454 + put_unaligned (cpu_to_le16 (uchar), cp++);
8455 + count++;
8456 + len--;
8457 + }
8458 + return count;
8459 +fail:
8460 + return -1;
8461 +}
8462 +
8463 +#endif /* DWC_UTFLIB */
8464 +
8465 +
8466 +/* dwc_debug.h */
8467 +
8468 +dwc_bool_t DWC_IN_IRQ(void)
8469 +{
8470 +// return in_irq();
8471 + return 0;
8472 +}
8473 +
8474 +dwc_bool_t DWC_IN_BH(void)
8475 +{
8476 +// return in_softirq();
8477 + return 0;
8478 +}
8479 +
8480 +void DWC_VPRINTF(char *format, va_list args)
8481 +{
8482 + vprintf(format, args);
8483 +}
8484 +
8485 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
8486 +{
8487 + return vsnprintf(str, size, format, args);
8488 +}
8489 +
8490 +void DWC_PRINTF(char *format, ...)
8491 +{
8492 + va_list args;
8493 +
8494 + va_start(args, format);
8495 + DWC_VPRINTF(format, args);
8496 + va_end(args);
8497 +}
8498 +
8499 +int DWC_SPRINTF(char *buffer, char *format, ...)
8500 +{
8501 + int retval;
8502 + va_list args;
8503 +
8504 + va_start(args, format);
8505 + retval = vsprintf(buffer, format, args);
8506 + va_end(args);
8507 + return retval;
8508 +}
8509 +
8510 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
8511 +{
8512 + int retval;
8513 + va_list args;
8514 +
8515 + va_start(args, format);
8516 + retval = vsnprintf(buffer, size, format, args);
8517 + va_end(args);
8518 + return retval;
8519 +}
8520 +
8521 +void __DWC_WARN(char *format, ...)
8522 +{
8523 + va_list args;
8524 +
8525 + va_start(args, format);
8526 + DWC_VPRINTF(format, args);
8527 + va_end(args);
8528 +}
8529 +
8530 +void __DWC_ERROR(char *format, ...)
8531 +{
8532 + va_list args;
8533 +
8534 + va_start(args, format);
8535 + DWC_VPRINTF(format, args);
8536 + va_end(args);
8537 +}
8538 +
8539 +void DWC_EXCEPTION(char *format, ...)
8540 +{
8541 + va_list args;
8542 +
8543 + va_start(args, format);
8544 + DWC_VPRINTF(format, args);
8545 + va_end(args);
8546 +// BUG_ON(1); ???
8547 +}
8548 +
8549 +#ifdef DEBUG
8550 +void __DWC_DEBUG(char *format, ...)
8551 +{
8552 + va_list args;
8553 +
8554 + va_start(args, format);
8555 + DWC_VPRINTF(format, args);
8556 + va_end(args);
8557 +}
8558 +#endif
8559 +
8560 +
8561 +/* dwc_mem.h */
8562 +
8563 +#if 0
8564 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
8565 + uint32_t align,
8566 + uint32_t alloc)
8567 +{
8568 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
8569 + size, align, alloc);
8570 + return (dwc_pool_t *)pool;
8571 +}
8572 +
8573 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
8574 +{
8575 + dma_pool_destroy((struct dma_pool *)pool);
8576 +}
8577 +
8578 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
8579 +{
8580 +// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
8581 + return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
8582 +}
8583 +
8584 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
8585 +{
8586 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
8587 + memset(..);
8588 +}
8589 +
8590 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
8591 +{
8592 + dma_pool_free(pool, vaddr, daddr);
8593 +}
8594 +#endif
8595 +
8596 +void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
8597 +{
8598 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
8599 + int error;
8600 +
8601 + error = bus_dmamem_alloc(dma->dma_tag, size, 1, size, dma->segs,
8602 + sizeof(dma->segs) / sizeof(dma->segs[0]),
8603 + &dma->nsegs, BUS_DMA_NOWAIT);
8604 + if (error) {
8605 + printf("%s: bus_dmamem_alloc(%ju) failed: %d\n", __func__,
8606 + (uintmax_t)size, error);
8607 + goto fail_0;
8608 + }
8609 +
8610 + error = bus_dmamem_map(dma->dma_tag, dma->segs, dma->nsegs, size,
8611 + (caddr_t *)&dma->dma_vaddr,
8612 + BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
8613 + if (error) {
8614 + printf("%s: bus_dmamem_map failed: %d\n", __func__, error);
8615 + goto fail_1;
8616 + }
8617 +
8618 + error = bus_dmamap_create(dma->dma_tag, size, 1, size, 0,
8619 + BUS_DMA_NOWAIT, &dma->dma_map);
8620 + if (error) {
8621 + printf("%s: bus_dmamap_create failed: %d\n", __func__, error);
8622 + goto fail_2;
8623 + }
8624 +
8625 + error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,
8626 + size, NULL, BUS_DMA_NOWAIT);
8627 + if (error) {
8628 + printf("%s: bus_dmamap_load failed: %d\n", __func__, error);
8629 + goto fail_3;
8630 + }
8631 +
8632 + dma->dma_paddr = (bus_addr_t)dma->segs[0].ds_addr;
8633 + *dma_addr = dma->dma_paddr;
8634 + return dma->dma_vaddr;
8635 +
8636 +fail_3:
8637 + bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
8638 +fail_2:
8639 + bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
8640 +fail_1:
8641 + bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
8642 +fail_0:
8643 + dma->dma_map = NULL;
8644 + dma->dma_vaddr = NULL;
8645 + dma->nsegs = 0;
8646 +
8647 + return NULL;
8648 +}
8649 +
8650 +void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
8651 +{
8652 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
8653 +
8654 + if (dma->dma_map != NULL) {
8655 + bus_dmamap_sync(dma->dma_tag, dma->dma_map, 0, size,
8656 + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
8657 + bus_dmamap_unload(dma->dma_tag, dma->dma_map);
8658 + bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
8659 + bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
8660 + bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
8661 + dma->dma_paddr = 0;
8662 + dma->dma_map = NULL;
8663 + dma->dma_vaddr = NULL;
8664 + dma->nsegs = 0;
8665 + }
8666 +}
8667 +
8668 +void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
8669 +{
8670 + return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
8671 +}
8672 +
8673 +void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
8674 +{
8675 + return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
8676 +}
8677 +
8678 +void __DWC_FREE(void *mem_ctx, void *addr)
8679 +{
8680 + free(addr, M_DEVBUF);
8681 +}
8682 +
8683 +
8684 +#ifdef DWC_CRYPTOLIB
8685 +/* dwc_crypto.h */
8686 +
8687 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
8688 +{
8689 + get_random_bytes(buffer, length);
8690 +}
8691 +
8692 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
8693 +{
8694 + struct crypto_blkcipher *tfm;
8695 + struct blkcipher_desc desc;
8696 + struct scatterlist sgd;
8697 + struct scatterlist sgs;
8698 +
8699 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
8700 + if (tfm == NULL) {
8701 + printk("failed to load transform for aes CBC\n");
8702 + return -1;
8703 + }
8704 +
8705 + crypto_blkcipher_setkey(tfm, key, keylen);
8706 + crypto_blkcipher_set_iv(tfm, iv, 16);
8707 +
8708 + sg_init_one(&sgd, out, messagelen);
8709 + sg_init_one(&sgs, message, messagelen);
8710 +
8711 + desc.tfm = tfm;
8712 + desc.flags = 0;
8713 +
8714 + if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
8715 + crypto_free_blkcipher(tfm);
8716 + DWC_ERROR("AES CBC encryption failed");
8717 + return -1;
8718 + }
8719 +
8720 + crypto_free_blkcipher(tfm);
8721 + return 0;
8722 +}
8723 +
8724 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
8725 +{
8726 + struct crypto_hash *tfm;
8727 + struct hash_desc desc;
8728 + struct scatterlist sg;
8729 +
8730 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
8731 + if (IS_ERR(tfm)) {
8732 + DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
8733 + return 0;
8734 + }
8735 + desc.tfm = tfm;
8736 + desc.flags = 0;
8737 +
8738 + sg_init_one(&sg, message, len);
8739 + crypto_hash_digest(&desc, &sg, len, out);
8740 + crypto_free_hash(tfm);
8741 +
8742 + return 1;
8743 +}
8744 +
8745 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
8746 + uint8_t *key, uint32_t keylen, uint8_t *out)
8747 +{
8748 + struct crypto_hash *tfm;
8749 + struct hash_desc desc;
8750 + struct scatterlist sg;
8751 +
8752 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
8753 + if (IS_ERR(tfm)) {
8754 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
8755 + return 0;
8756 + }
8757 + desc.tfm = tfm;
8758 + desc.flags = 0;
8759 +
8760 + sg_init_one(&sg, message, messagelen);
8761 + crypto_hash_setkey(tfm, key, keylen);
8762 + crypto_hash_digest(&desc, &sg, messagelen, out);
8763 + crypto_free_hash(tfm);
8764 +
8765 + return 1;
8766 +}
8767 +
8768 +#endif /* DWC_CRYPTOLIB */
8769 +
8770 +
8771 +/* Byte Ordering Conversions */
8772 +
8773 +uint32_t DWC_CPU_TO_LE32(uint32_t *p)
8774 +{
8775 +#ifdef __LITTLE_ENDIAN
8776 + return *p;
8777 +#else
8778 + uint8_t *u_p = (uint8_t *)p;
8779 +
8780 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8781 +#endif
8782 +}
8783 +
8784 +uint32_t DWC_CPU_TO_BE32(uint32_t *p)
8785 +{
8786 +#ifdef __BIG_ENDIAN
8787 + return *p;
8788 +#else
8789 + uint8_t *u_p = (uint8_t *)p;
8790 +
8791 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8792 +#endif
8793 +}
8794 +
8795 +uint32_t DWC_LE32_TO_CPU(uint32_t *p)
8796 +{
8797 +#ifdef __LITTLE_ENDIAN
8798 + return *p;
8799 +#else
8800 + uint8_t *u_p = (uint8_t *)p;
8801 +
8802 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8803 +#endif
8804 +}
8805 +
8806 +uint32_t DWC_BE32_TO_CPU(uint32_t *p)
8807 +{
8808 +#ifdef __BIG_ENDIAN
8809 + return *p;
8810 +#else
8811 + uint8_t *u_p = (uint8_t *)p;
8812 +
8813 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8814 +#endif
8815 +}
8816 +
8817 +uint16_t DWC_CPU_TO_LE16(uint16_t *p)
8818 +{
8819 +#ifdef __LITTLE_ENDIAN
8820 + return *p;
8821 +#else
8822 + uint8_t *u_p = (uint8_t *)p;
8823 + return (u_p[1] | (u_p[0] << 8));
8824 +#endif
8825 +}
8826 +
8827 +uint16_t DWC_CPU_TO_BE16(uint16_t *p)
8828 +{
8829 +#ifdef __BIG_ENDIAN
8830 + return *p;
8831 +#else
8832 + uint8_t *u_p = (uint8_t *)p;
8833 + return (u_p[1] | (u_p[0] << 8));
8834 +#endif
8835 +}
8836 +
8837 +uint16_t DWC_LE16_TO_CPU(uint16_t *p)
8838 +{
8839 +#ifdef __LITTLE_ENDIAN
8840 + return *p;
8841 +#else
8842 + uint8_t *u_p = (uint8_t *)p;
8843 + return (u_p[1] | (u_p[0] << 8));
8844 +#endif
8845 +}
8846 +
8847 +uint16_t DWC_BE16_TO_CPU(uint16_t *p)
8848 +{
8849 +#ifdef __BIG_ENDIAN
8850 + return *p;
8851 +#else
8852 + uint8_t *u_p = (uint8_t *)p;
8853 + return (u_p[1] | (u_p[0] << 8));
8854 +#endif
8855 +}
8856 +
8857 +
8858 +/* Registers */
8859 +
8860 +uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
8861 +{
8862 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8863 + bus_size_t ior = (bus_size_t)reg;
8864 +
8865 + return bus_space_read_4(io->iot, io->ioh, ior);
8866 +}
8867 +
8868 +#if 0
8869 +uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
8870 +{
8871 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8872 + bus_size_t ior = (bus_size_t)reg;
8873 +
8874 + return bus_space_read_8(io->iot, io->ioh, ior);
8875 +}
8876 +#endif
8877 +
8878 +void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
8879 +{
8880 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8881 + bus_size_t ior = (bus_size_t)reg;
8882 +
8883 + bus_space_write_4(io->iot, io->ioh, ior, value);
8884 +}
8885 +
8886 +#if 0
8887 +void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
8888 +{
8889 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8890 + bus_size_t ior = (bus_size_t)reg;
8891 +
8892 + bus_space_write_8(io->iot, io->ioh, ior, value);
8893 +}
8894 +#endif
8895 +
8896 +void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
8897 + uint32_t set_mask)
8898 +{
8899 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8900 + bus_size_t ior = (bus_size_t)reg;
8901 +
8902 + bus_space_write_4(io->iot, io->ioh, ior,
8903 + (bus_space_read_4(io->iot, io->ioh, ior) &
8904 + ~clear_mask) | set_mask);
8905 +}
8906 +
8907 +#if 0
8908 +void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
8909 + uint64_t set_mask)
8910 +{
8911 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8912 + bus_size_t ior = (bus_size_t)reg;
8913 +
8914 + bus_space_write_8(io->iot, io->ioh, ior,
8915 + (bus_space_read_8(io->iot, io->ioh, ior) &
8916 + ~clear_mask) | set_mask);
8917 +}
8918 +#endif
8919 +
8920 +
8921 +/* Locking */
8922 +
8923 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
8924 +{
8925 + struct simplelock *sl = DWC_ALLOC(sizeof(*sl));
8926 +
8927 + if (!sl) {
8928 + DWC_ERROR("Cannot allocate memory for spinlock");
8929 + return NULL;
8930 + }
8931 +
8932 + simple_lock_init(sl);
8933 + return (dwc_spinlock_t *)sl;
8934 +}
8935 +
8936 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
8937 +{
8938 + struct simplelock *sl = (struct simplelock *)lock;
8939 +
8940 + DWC_FREE(sl);
8941 +}
8942 +
8943 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
8944 +{
8945 + simple_lock((struct simplelock *)lock);
8946 +}
8947 +
8948 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
8949 +{
8950 + simple_unlock((struct simplelock *)lock);
8951 +}
8952 +
8953 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
8954 +{
8955 + simple_lock((struct simplelock *)lock);
8956 + *flags = splbio();
8957 +}
8958 +
8959 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
8960 +{
8961 + splx(flags);
8962 + simple_unlock((struct simplelock *)lock);
8963 +}
8964 +
8965 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
8966 +{
8967 + dwc_mutex_t *mutex = DWC_ALLOC(sizeof(struct lock));
8968 +
8969 + if (!mutex) {
8970 + DWC_ERROR("Cannot allocate memory for mutex");
8971 + return NULL;
8972 + }
8973 +
8974 + lockinit((struct lock *)mutex, 0, "dw3mtx", 0, 0);
8975 + return mutex;
8976 +}
8977 +
8978 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
8979 +#else
8980 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
8981 +{
8982 + DWC_FREE(mutex);
8983 +}
8984 +#endif
8985 +
8986 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
8987 +{
8988 + lockmgr((struct lock *)mutex, LK_EXCLUSIVE, NULL);
8989 +}
8990 +
8991 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
8992 +{
8993 + int status;
8994 +
8995 + status = lockmgr((struct lock *)mutex, LK_EXCLUSIVE | LK_NOWAIT, NULL);
8996 + return status == 0;
8997 +}
8998 +
8999 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
9000 +{
9001 + lockmgr((struct lock *)mutex, LK_RELEASE, NULL);
9002 +}
9003 +
9004 +
9005 +/* Timing */
9006 +
9007 +void DWC_UDELAY(uint32_t usecs)
9008 +{
9009 + DELAY(usecs);
9010 +}
9011 +
9012 +void DWC_MDELAY(uint32_t msecs)
9013 +{
9014 + do {
9015 + DELAY(1000);
9016 + } while (--msecs);
9017 +}
9018 +
9019 +void DWC_MSLEEP(uint32_t msecs)
9020 +{
9021 + struct timeval tv;
9022 +
9023 + tv.tv_sec = msecs / 1000;
9024 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
9025 + tsleep(&tv, 0, "dw3slp", tvtohz(&tv));
9026 +}
9027 +
9028 +uint32_t DWC_TIME(void)
9029 +{
9030 + struct timeval tv;
9031 +
9032 + microuptime(&tv); // or getmicrouptime? (less precise, but faster)
9033 + return tv.tv_sec * 1000 + tv.tv_usec / 1000;
9034 +}
9035 +
9036 +
9037 +/* Timers */
9038 +
9039 +struct dwc_timer {
9040 + struct callout t;
9041 + char *name;
9042 + dwc_spinlock_t *lock;
9043 + dwc_timer_callback_t cb;
9044 + void *data;
9045 +};
9046 +
9047 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
9048 +{
9049 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
9050 +
9051 + if (!t) {
9052 + DWC_ERROR("Cannot allocate memory for timer");
9053 + return NULL;
9054 + }
9055 +
9056 + callout_init(&t->t);
9057 +
9058 + t->name = DWC_STRDUP(name);
9059 + if (!t->name) {
9060 + DWC_ERROR("Cannot allocate memory for timer->name");
9061 + goto no_name;
9062 + }
9063 +
9064 + t->lock = DWC_SPINLOCK_ALLOC();
9065 + if (!t->lock) {
9066 + DWC_ERROR("Cannot allocate memory for timer->lock");
9067 + goto no_lock;
9068 + }
9069 +
9070 + t->cb = cb;
9071 + t->data = data;
9072 +
9073 + return t;
9074 +
9075 + no_lock:
9076 + DWC_FREE(t->name);
9077 + no_name:
9078 + DWC_FREE(t);
9079 +
9080 + return NULL;
9081 +}
9082 +
9083 +void DWC_TIMER_FREE(dwc_timer_t *timer)
9084 +{
9085 + callout_stop(&timer->t);
9086 + DWC_SPINLOCK_FREE(timer->lock);
9087 + DWC_FREE(timer->name);
9088 + DWC_FREE(timer);
9089 +}
9090 +
9091 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
9092 +{
9093 + struct timeval tv;
9094 +
9095 + tv.tv_sec = time / 1000;
9096 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
9097 + callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
9098 +}
9099 +
9100 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
9101 +{
9102 + callout_stop(&timer->t);
9103 +}
9104 +
9105 +
9106 +/* Wait Queues */
9107 +
9108 +struct dwc_waitq {
9109 + struct simplelock lock;
9110 + int abort;
9111 +};
9112 +
9113 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
9114 +{
9115 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
9116 +
9117 + if (!wq) {
9118 + DWC_ERROR("Cannot allocate memory for waitqueue");
9119 + return NULL;
9120 + }
9121 +
9122 + simple_lock_init(&wq->lock);
9123 + wq->abort = 0;
9124 +
9125 + return wq;
9126 +}
9127 +
9128 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
9129 +{
9130 + DWC_FREE(wq);
9131 +}
9132 +
9133 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
9134 +{
9135 + int ipl;
9136 + int result = 0;
9137 +
9138 + simple_lock(&wq->lock);
9139 + ipl = splbio();
9140 +
9141 + /* Skip the sleep if already aborted or triggered */
9142 + if (!wq->abort && !cond(data)) {
9143 + splx(ipl);
9144 + result = ltsleep(wq, PCATCH, "dw3wat", 0, &wq->lock); // infinite timeout
9145 + ipl = splbio();
9146 + }
9147 +
9148 + if (result == 0) { // awoken
9149 + if (wq->abort) {
9150 + wq->abort = 0;
9151 + result = -DWC_E_ABORT;
9152 + } else {
9153 + result = 0;
9154 + }
9155 +
9156 + splx(ipl);
9157 + simple_unlock(&wq->lock);
9158 + } else {
9159 + wq->abort = 0;
9160 + splx(ipl);
9161 + simple_unlock(&wq->lock);
9162 +
9163 + if (result == ERESTART) { // signaled - restart
9164 + result = -DWC_E_RESTART;
9165 + } else { // signaled - must be EINTR
9166 + result = -DWC_E_ABORT;
9167 + }
9168 + }
9169 +
9170 + return result;
9171 +}
9172 +
9173 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
9174 + void *data, int32_t msecs)
9175 +{
9176 + struct timeval tv, tv1, tv2;
9177 + int ipl;
9178 + int result = 0;
9179 +
9180 + tv.tv_sec = msecs / 1000;
9181 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
9182 +
9183 + simple_lock(&wq->lock);
9184 + ipl = splbio();
9185 +
9186 + /* Skip the sleep if already aborted or triggered */
9187 + if (!wq->abort && !cond(data)) {
9188 + splx(ipl);
9189 + getmicrouptime(&tv1);
9190 + result = ltsleep(wq, PCATCH, "dw3wto", tvtohz(&tv), &wq->lock);
9191 + getmicrouptime(&tv2);
9192 + ipl = splbio();
9193 + }
9194 +
9195 + if (result == 0) { // awoken
9196 + if (wq->abort) {
9197 + wq->abort = 0;
9198 + splx(ipl);
9199 + simple_unlock(&wq->lock);
9200 + result = -DWC_E_ABORT;
9201 + } else {
9202 + splx(ipl);
9203 + simple_unlock(&wq->lock);
9204 +
9205 + tv2.tv_usec -= tv1.tv_usec;
9206 + if (tv2.tv_usec < 0) {
9207 + tv2.tv_usec += 1000000;
9208 + tv2.tv_sec--;
9209 + }
9210 +
9211 + tv2.tv_sec -= tv1.tv_sec;
9212 + result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
9213 + result = msecs - result;
9214 + if (result <= 0)
9215 + result = 1;
9216 + }
9217 + } else {
9218 + wq->abort = 0;
9219 + splx(ipl);
9220 + simple_unlock(&wq->lock);
9221 +
9222 + if (result == ERESTART) { // signaled - restart
9223 + result = -DWC_E_RESTART;
9224 +
9225 + } else if (result == EINTR) { // signaled - interrupt
9226 + result = -DWC_E_ABORT;
9227 +
9228 + } else { // timed out
9229 + result = -DWC_E_TIMEOUT;
9230 + }
9231 + }
9232 +
9233 + return result;
9234 +}
9235 +
9236 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
9237 +{
9238 + wakeup(wq);
9239 +}
9240 +
9241 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
9242 +{
9243 + int ipl;
9244 +
9245 + simple_lock(&wq->lock);
9246 + ipl = splbio();
9247 + wq->abort = 1;
9248 + wakeup(wq);
9249 + splx(ipl);
9250 + simple_unlock(&wq->lock);
9251 +}
9252 +
9253 +
9254 +/* Threading */
9255 +
9256 +struct dwc_thread {
9257 + struct proc *proc;
9258 + int abort;
9259 +};
9260 +
9261 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
9262 +{
9263 + int retval;
9264 + dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
9265 +
9266 + if (!thread) {
9267 + return NULL;
9268 + }
9269 +
9270 + thread->abort = 0;
9271 + retval = kthread_create1((void (*)(void *))func, data, &thread->proc,
9272 + "%s", name);
9273 + if (retval) {
9274 + DWC_FREE(thread);
9275 + return NULL;
9276 + }
9277 +
9278 + return thread;
9279 +}
9280 +
9281 +int DWC_THREAD_STOP(dwc_thread_t *thread)
9282 +{
9283 + int retval;
9284 +
9285 + thread->abort = 1;
9286 + retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
9287 +
9288 + if (retval == 0) {
9289 + /* DWC_THREAD_EXIT() will free the thread struct */
9290 + return 0;
9291 + }
9292 +
9293 + /* NOTE: We leak the thread struct if thread doesn't die */
9294 +
9295 + if (retval == EWOULDBLOCK) {
9296 + return -DWC_E_TIMEOUT;
9297 + }
9298 +
9299 + return -DWC_E_UNKNOWN;
9300 +}
9301 +
9302 +dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
9303 +{
9304 + return thread->abort;
9305 +}
9306 +
9307 +void DWC_THREAD_EXIT(dwc_thread_t *thread)
9308 +{
9309 + wakeup(&thread->abort);
9310 + DWC_FREE(thread);
9311 + kthread_exit(0);
9312 +}
9313 +
9314 +/* tasklets
9315 + - Runs in interrupt context (cannot sleep)
9316 + - Each tasklet runs on a single CPU
9317 + - Different tasklets can be running simultaneously on different CPUs
9318 + [ On NetBSD there is no corresponding mechanism, drivers don't have bottom-
9319 + halves. So we just call the callback directly from DWC_TASK_SCHEDULE() ]
9320 + */
9321 +struct dwc_tasklet {
9322 + dwc_tasklet_callback_t cb;
9323 + void *data;
9324 +};
9325 +
9326 +static void tasklet_callback(void *data)
9327 +{
9328 + dwc_tasklet_t *task = (dwc_tasklet_t *)data;
9329 +
9330 + task->cb(task->data);
9331 +}
9332 +
9333 +dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
9334 +{
9335 + dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
9336 +
9337 + if (task) {
9338 + task->cb = cb;
9339 + task->data = data;
9340 + } else {
9341 + DWC_ERROR("Cannot allocate memory for tasklet");
9342 + }
9343 +
9344 + return task;
9345 +}
9346 +
9347 +void DWC_TASK_FREE(dwc_tasklet_t *task)
9348 +{
9349 + DWC_FREE(task);
9350 +}
9351 +
9352 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
9353 +{
9354 + tasklet_callback(task);
9355 +}
9356 +
9357 +
9358 +/* workqueues
9359 + - Runs in process context (can sleep)
9360 + */
9361 +typedef struct work_container {
9362 + dwc_work_callback_t cb;
9363 + void *data;
9364 + dwc_workq_t *wq;
9365 + char *name;
9366 + int hz;
9367 + struct work task;
9368 +} work_container_t;
9369 +
9370 +struct dwc_workq {
9371 + struct workqueue *taskq;
9372 + dwc_spinlock_t *lock;
9373 + dwc_waitq_t *waitq;
9374 + int pending;
9375 + struct work_container *container;
9376 +};
9377 +
9378 +static void do_work(struct work *task, void *data)
9379 +{
9380 + dwc_workq_t *wq = (dwc_workq_t *)data;
9381 + work_container_t *container = wq->container;
9382 + dwc_irqflags_t flags;
9383 +
9384 + if (container->hz) {
9385 + tsleep(container, 0, "dw3wrk", container->hz);
9386 + }
9387 +
9388 + container->cb(container->data);
9389 + DWC_DEBUG("Work done: %s, container=%p", container->name, container);
9390 +
9391 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9392 + if (container->name)
9393 + DWC_FREE(container->name);
9394 + DWC_FREE(container);
9395 + wq->pending--;
9396 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9397 + DWC_WAITQ_TRIGGER(wq->waitq);
9398 +}
9399 +
9400 +static int work_done(void *data)
9401 +{
9402 + dwc_workq_t *workq = (dwc_workq_t *)data;
9403 +
9404 + return workq->pending == 0;
9405 +}
9406 +
9407 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
9408 +{
9409 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
9410 +}
9411 +
9412 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
9413 +{
9414 + int result;
9415 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
9416 +
9417 + if (!wq) {
9418 + DWC_ERROR("Cannot allocate memory for workqueue");
9419 + return NULL;
9420 + }
9421 +
9422 + result = workqueue_create(&wq->taskq, name, do_work, wq, 0 /*PWAIT*/,
9423 + IPL_BIO, 0);
9424 + if (result) {
9425 + DWC_ERROR("Cannot create workqueue");
9426 + goto no_taskq;
9427 + }
9428 +
9429 + wq->pending = 0;
9430 +
9431 + wq->lock = DWC_SPINLOCK_ALLOC();
9432 + if (!wq->lock) {
9433 + DWC_ERROR("Cannot allocate memory for spinlock");
9434 + goto no_lock;
9435 + }
9436 +
9437 + wq->waitq = DWC_WAITQ_ALLOC();
9438 + if (!wq->waitq) {
9439 + DWC_ERROR("Cannot allocate memory for waitqueue");
9440 + goto no_waitq;
9441 + }
9442 +
9443 + return wq;
9444 +
9445 + no_waitq:
9446 + DWC_SPINLOCK_FREE(wq->lock);
9447 + no_lock:
9448 + workqueue_destroy(wq->taskq);
9449 + no_taskq:
9450 + DWC_FREE(wq);
9451 +
9452 + return NULL;
9453 +}
9454 +
9455 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
9456 +{
9457 +#ifdef DEBUG
9458 + dwc_irqflags_t flags;
9459 +
9460 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9461 +
9462 + if (wq->pending != 0) {
9463 + struct work_container *container = wq->container;
9464 +
9465 + DWC_ERROR("Destroying work queue with pending work");
9466 +
9467 + if (container && container->name) {
9468 + DWC_ERROR("Work %s still pending", container->name);
9469 + }
9470 + }
9471 +
9472 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9473 +#endif
9474 + DWC_WAITQ_FREE(wq->waitq);
9475 + DWC_SPINLOCK_FREE(wq->lock);
9476 + workqueue_destroy(wq->taskq);
9477 + DWC_FREE(wq);
9478 +}
9479 +
9480 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
9481 + char *format, ...)
9482 +{
9483 + dwc_irqflags_t flags;
9484 + work_container_t *container;
9485 + static char name[128];
9486 + va_list args;
9487 +
9488 + va_start(args, format);
9489 + DWC_VSNPRINTF(name, 128, format, args);
9490 + va_end(args);
9491 +
9492 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9493 + wq->pending++;
9494 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9495 + DWC_WAITQ_TRIGGER(wq->waitq);
9496 +
9497 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
9498 + if (!container) {
9499 + DWC_ERROR("Cannot allocate memory for container");
9500 + return;
9501 + }
9502 +
9503 + container->name = DWC_STRDUP(name);
9504 + if (!container->name) {
9505 + DWC_ERROR("Cannot allocate memory for container->name");
9506 + DWC_FREE(container);
9507 + return;
9508 + }
9509 +
9510 + container->cb = cb;
9511 + container->data = data;
9512 + container->wq = wq;
9513 + container->hz = 0;
9514 + wq->container = container;
9515 +
9516 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
9517 + workqueue_enqueue(wq->taskq, &container->task);
9518 +}
9519 +
9520 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
9521 + void *data, uint32_t time, char *format, ...)
9522 +{
9523 + dwc_irqflags_t flags;
9524 + work_container_t *container;
9525 + static char name[128];
9526 + struct timeval tv;
9527 + va_list args;
9528 +
9529 + va_start(args, format);
9530 + DWC_VSNPRINTF(name, 128, format, args);
9531 + va_end(args);
9532 +
9533 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9534 + wq->pending++;
9535 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9536 + DWC_WAITQ_TRIGGER(wq->waitq);
9537 +
9538 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
9539 + if (!container) {
9540 + DWC_ERROR("Cannot allocate memory for container");
9541 + return;
9542 + }
9543 +
9544 + container->name = DWC_STRDUP(name);
9545 + if (!container->name) {
9546 + DWC_ERROR("Cannot allocate memory for container->name");
9547 + DWC_FREE(container);
9548 + return;
9549 + }
9550 +
9551 + container->cb = cb;
9552 + container->data = data;
9553 + container->wq = wq;
9554 + tv.tv_sec = time / 1000;
9555 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
9556 + container->hz = tvtohz(&tv);
9557 + wq->container = container;
9558 +
9559 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
9560 + workqueue_enqueue(wq->taskq, &container->task);
9561 +}
9562 +
9563 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
9564 +{
9565 + return wq->pending;
9566 +}
9567 diff --git a/drivers/usb/host/dwc_common_port/dwc_crypto.c b/drivers/usb/host/dwc_common_port/dwc_crypto.c
9568 new file mode 100644
9569 index 0000000..3b03532
9570 --- /dev/null
9571 +++ b/drivers/usb/host/dwc_common_port/dwc_crypto.c
9572 @@ -0,0 +1,308 @@
9573 +/* =========================================================================
9574 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.c $
9575 + * $Revision: #5 $
9576 + * $Date: 2010/09/28 $
9577 + * $Change: 1596182 $
9578 + *
9579 + * Synopsys Portability Library Software and documentation
9580 + * (hereinafter, "Software") is an Unsupported proprietary work of
9581 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
9582 + * between Synopsys and you.
9583 + *
9584 + * The Software IS NOT an item of Licensed Software or Licensed Product
9585 + * under any End User Software License Agreement or Agreement for
9586 + * Licensed Product with Synopsys or any supplement thereto. You are
9587 + * permitted to use and redistribute this Software in source and binary
9588 + * forms, with or without modification, provided that redistributions
9589 + * of source code must retain this notice. You may not view, use,
9590 + * disclose, copy or distribute this file or any information contained
9591 + * herein except pursuant to this license grant from Synopsys. If you
9592 + * do not agree with this notice, including the disclaimer below, then
9593 + * you are not authorized to use the Software.
9594 + *
9595 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
9596 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9597 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
9598 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
9599 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
9600 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
9601 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
9602 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
9603 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9604 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
9605 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9606 + * DAMAGE.
9607 + * ========================================================================= */
9608 +
9609 +/** @file
9610 + * This file contains the WUSB cryptographic routines.
9611 + */
9612 +
9613 +#ifdef DWC_CRYPTOLIB
9614 +
9615 +#include "dwc_crypto.h"
9616 +#include "usb.h"
9617 +
9618 +#ifdef DEBUG
9619 +static inline void dump_bytes(char *name, uint8_t *bytes, int len)
9620 +{
9621 + int i;
9622 + DWC_PRINTF("%s: ", name);
9623 + for (i=0; i<len; i++) {
9624 + DWC_PRINTF("%02x ", bytes[i]);
9625 + }
9626 + DWC_PRINTF("\n");
9627 +}
9628 +#else
9629 +#define dump_bytes(x...)
9630 +#endif
9631 +
9632 +/* Display a block */
9633 +void show_block(const u8 *blk, const char *prefix, const char *suffix, int a)
9634 +{
9635 +#ifdef DWC_DEBUG_CRYPTO
9636 + int i, blksize = 16;
9637 +
9638 + DWC_DEBUG("%s", prefix);
9639 +
9640 + if (suffix == NULL) {
9641 + suffix = "\n";
9642 + blksize = a;
9643 + }
9644 +
9645 + for (i = 0; i < blksize; i++)
9646 + DWC_PRINT("%02x%s", *blk++, ((i & 3) == 3) ? " " : " ");
9647 + DWC_PRINT(suffix);
9648 +#endif
9649 +}
9650 +
9651 +/**
9652 + * Encrypts an array of bytes using the AES encryption engine.
9653 + * If <code>dst</code> == <code>src</code>, then the bytes will be encrypted
9654 + * in-place.
9655 + *
9656 + * @return 0 on success, negative error code on error.
9657 + */
9658 +int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst)
9659 +{
9660 + u8 block_t[16];
9661 + DWC_MEMSET(block_t, 0, 16);
9662 +
9663 + return DWC_AES_CBC(src, 16, key, 16, block_t, dst);
9664 +}
9665 +
9666 +/**
9667 + * The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec.
9668 + * This function takes a data string and returns the encrypted CBC
9669 + * Counter-mode MIC.
9670 + *
9671 + * @param key The 128-bit symmetric key.
9672 + * @param nonce The CCM nonce.
9673 + * @param label The unique 14-byte ASCII text label.
9674 + * @param bytes The byte array to be encrypted.
9675 + * @param len Length of the byte array.
9676 + * @param result Byte array to receive the 8-byte encrypted MIC.
9677 + */
9678 +void dwc_wusb_cmf(u8 *key, u8 *nonce,
9679 + char *label, u8 *bytes, int len, u8 *result)
9680 +{
9681 + u8 block_m[16];
9682 + u8 block_x[16];
9683 + u8 block_t[8];
9684 + int idx, blkNum;
9685 + u16 la = (u16)(len + 14);
9686 +
9687 + /* Set the AES-128 key */
9688 + //dwc_aes_setkey(tfm, key, 16);
9689 +
9690 + /* Fill block B0 from flags = 0x59, N, and l(m) = 0 */
9691 + block_m[0] = 0x59;
9692 + for (idx = 0; idx < 13; idx++)
9693 + block_m[idx + 1] = nonce[idx];
9694 + block_m[14] = 0;
9695 + block_m[15] = 0;
9696 +
9697 + /* Produce the CBC IV */
9698 + dwc_wusb_aes_encrypt(block_m, key, block_x);
9699 + show_block(block_m, "CBC IV in: ", "\n", 0);
9700 + show_block(block_x, "CBC IV out:", "\n", 0);
9701 +
9702 + /* Fill block B1 from l(a) = Blen + 14, and A */
9703 + block_x[0] ^= (u8)(la >> 8);
9704 + block_x[1] ^= (u8)la;
9705 + for (idx = 0; idx < 14; idx++)
9706 + block_x[idx + 2] ^= label[idx];
9707 + show_block(block_x, "After xor: ", "b1\n", 16);
9708 +
9709 + dwc_wusb_aes_encrypt(block_x, key, block_x);
9710 + show_block(block_x, "After AES: ", "b1\n", 16);
9711 +
9712 + idx = 0;
9713 + blkNum = 0;
9714 +
9715 + /* Fill remaining blocks with B */
9716 + while (len-- > 0) {
9717 + block_x[idx] ^= *bytes++;
9718 + if (++idx >= 16) {
9719 + idx = 0;
9720 + show_block(block_x, "After xor: ", "\n", blkNum);
9721 + dwc_wusb_aes_encrypt(block_x, key, block_x);
9722 + show_block(block_x, "After AES: ", "\n", blkNum);
9723 + blkNum++;
9724 + }
9725 + }
9726 +
9727 + /* Handle partial last block */
9728 + if (idx > 0) {
9729 + show_block(block_x, "After xor: ", "\n", blkNum);
9730 + dwc_wusb_aes_encrypt(block_x, key, block_x);
9731 + show_block(block_x, "After AES: ", "\n", blkNum);
9732 + }
9733 +
9734 + /* Save the MIC tag */
9735 + DWC_MEMCPY(block_t, block_x, 8);
9736 + show_block(block_t, "MIC tag : ", NULL, 8);
9737 +
9738 + /* Fill block A0 from flags = 0x01, N, and counter = 0 */
9739 + block_m[0] = 0x01;
9740 + block_m[14] = 0;
9741 + block_m[15] = 0;
9742 +
9743 + /* Encrypt the counter */
9744 + dwc_wusb_aes_encrypt(block_m, key, block_x);
9745 + show_block(block_x, "CTR[MIC] : ", NULL, 8);
9746 +
9747 + /* XOR with MIC tag */
9748 + for (idx = 0; idx < 8; idx++) {
9749 + block_t[idx] ^= block_x[idx];
9750 + }
9751 +
9752 + /* Return result to caller */
9753 + DWC_MEMCPY(result, block_t, 8);
9754 + show_block(result, "CCM-MIC : ", NULL, 8);
9755 +
9756 +}
9757 +
9758 +/**
9759 + * The PRF function described in section 6.5 of the WUSB spec. This function
9760 + * concatenates MIC values returned from dwc_cmf() to create a value of
9761 + * the requested length.
9762 + *
9763 + * @param prf_len Length of the PRF function in bits (64, 128, or 256).
9764 + * @param key, nonce, label, bytes, len Same as for dwc_cmf().
9765 + * @param result Byte array to receive the result.
9766 + */
9767 +void dwc_wusb_prf(int prf_len, u8 *key,
9768 + u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
9769 +{
9770 + int i;
9771 +
9772 + nonce[0] = 0;
9773 + for (i = 0; i < prf_len >> 6; i++, nonce[0]++) {
9774 + dwc_wusb_cmf(key, nonce, label, bytes, len, result);
9775 + result += 8;
9776 + }
9777 +}
9778 +
9779 +/**
9780 + * Fills in CCM Nonce per the WUSB spec.
9781 + *
9782 + * @param[in] haddr Host address.
9783 + * @param[in] daddr Device address.
9784 + * @param[in] tkid Session Key(PTK) identifier.
9785 + * @param[out] nonce Pointer to where the CCM Nonce output is to be written.
9786 + */
9787 +void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
9788 + uint8_t *nonce)
9789 +{
9790 +
9791 + DWC_DEBUG("%s %x %x\n", __func__, daddr, haddr);
9792 +
9793 + DWC_MEMSET(&nonce[0], 0, 16);
9794 +
9795 + DWC_MEMCPY(&nonce[6], tkid, 3);
9796 + nonce[9] = daddr & 0xFF;
9797 + nonce[10] = (daddr >> 8) & 0xFF;
9798 + nonce[11] = haddr & 0xFF;
9799 + nonce[12] = (haddr >> 8) & 0xFF;
9800 +
9801 + dump_bytes("CCM nonce", nonce, 16);
9802 +}
9803 +
9804 +/**
9805 + * Generates a 16-byte cryptographic-grade random number for the Host/Device
9806 + * Nonce.
9807 + */
9808 +void dwc_wusb_gen_nonce(uint16_t addr, uint8_t *nonce)
9809 +{
9810 + uint8_t inonce[16];
9811 + uint32_t temp[4];
9812 +
9813 + /* Fill in the Nonce */
9814 + DWC_MEMSET(&inonce[0], 0, sizeof(inonce));
9815 + inonce[9] = addr & 0xFF;
9816 + inonce[10] = (addr >> 8) & 0xFF;
9817 + inonce[11] = inonce[9];
9818 + inonce[12] = inonce[10];
9819 +
9820 + /* Collect "randomness samples" */
9821 + DWC_RANDOM_BYTES((uint8_t *)temp, 16);
9822 +
9823 + dwc_wusb_prf_128((uint8_t *)temp, nonce,
9824 + "Random Numbers", (uint8_t *)temp, sizeof(temp),
9825 + nonce);
9826 +}
9827 +
9828 +/**
9829 + * Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the
9830 + * WUSB spec.
9831 + *
9832 + * @param[in] ccm_nonce Pointer to CCM Nonce.
9833 + * @param[in] mk Master Key to derive the session from
9834 + * @param[in] hnonce Pointer to Host Nonce.
9835 + * @param[in] dnonce Pointer to Device Nonce.
9836 + * @param[out] kck Pointer to where the KCK output is to be written.
9837 + * @param[out] ptk Pointer to where the PTK output is to be written.
9838 + */
9839 +void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce,
9840 + uint8_t *dnonce, uint8_t *kck, uint8_t *ptk)
9841 +{
9842 + uint8_t idata[32];
9843 + uint8_t odata[32];
9844 +
9845 + dump_bytes("ck", mk, 16);
9846 + dump_bytes("hnonce", hnonce, 16);
9847 + dump_bytes("dnonce", dnonce, 16);
9848 +
9849 + /* The data is the HNonce and DNonce concatenated */
9850 + DWC_MEMCPY(&idata[0], hnonce, 16);
9851 + DWC_MEMCPY(&idata[16], dnonce, 16);
9852 +
9853 + dwc_wusb_prf_256(mk, ccm_nonce, "Pair-wise keys", idata, 32, odata);
9854 +
9855 + /* Low 16 bytes of the result is the KCK, high 16 is the PTK */
9856 + DWC_MEMCPY(kck, &odata[0], 16);
9857 + DWC_MEMCPY(ptk, &odata[16], 16);
9858 +
9859 + dump_bytes("kck", kck, 16);
9860 + dump_bytes("ptk", ptk, 16);
9861 +}
9862 +
9863 +/**
9864 + * Generates the Message Integrity Code over the Handshake data per the
9865 + * WUSB spec.
9866 + *
9867 + * @param ccm_nonce Pointer to CCM Nonce.
9868 + * @param kck Pointer to Key Confirmation Key.
9869 + * @param data Pointer to Handshake data to be checked.
9870 + * @param mic Pointer to where the MIC output is to be written.
9871 + */
9872 +void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t *kck,
9873 + uint8_t *data, uint8_t *mic)
9874 +{
9875 +
9876 + dwc_wusb_prf_64(kck, ccm_nonce, "out-of-bandMIC",
9877 + data, WUSB_HANDSHAKE_LEN_FOR_MIC, mic);
9878 +}
9879 +
9880 +#endif /* DWC_CRYPTOLIB */
9881 diff --git a/drivers/usb/host/dwc_common_port/dwc_crypto.h b/drivers/usb/host/dwc_common_port/dwc_crypto.h
9882 new file mode 100644
9883 index 0000000..26fcddc
9884 --- /dev/null
9885 +++ b/drivers/usb/host/dwc_common_port/dwc_crypto.h
9886 @@ -0,0 +1,111 @@
9887 +/* =========================================================================
9888 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.h $
9889 + * $Revision: #3 $
9890 + * $Date: 2010/09/28 $
9891 + * $Change: 1596182 $
9892 + *
9893 + * Synopsys Portability Library Software and documentation
9894 + * (hereinafter, "Software") is an Unsupported proprietary work of
9895 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
9896 + * between Synopsys and you.
9897 + *
9898 + * The Software IS NOT an item of Licensed Software or Licensed Product
9899 + * under any End User Software License Agreement or Agreement for
9900 + * Licensed Product with Synopsys or any supplement thereto. You are
9901 + * permitted to use and redistribute this Software in source and binary
9902 + * forms, with or without modification, provided that redistributions
9903 + * of source code must retain this notice. You may not view, use,
9904 + * disclose, copy or distribute this file or any information contained
9905 + * herein except pursuant to this license grant from Synopsys. If you
9906 + * do not agree with this notice, including the disclaimer below, then
9907 + * you are not authorized to use the Software.
9908 + *
9909 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
9910 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9911 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
9912 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
9913 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
9914 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
9915 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
9916 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
9917 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9918 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
9919 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9920 + * DAMAGE.
9921 + * ========================================================================= */
9922 +
9923 +#ifndef _DWC_CRYPTO_H_
9924 +#define _DWC_CRYPTO_H_
9925 +
9926 +#ifdef __cplusplus
9927 +extern "C" {
9928 +#endif
9929 +
9930 +/** @file
9931 + *
9932 + * This file contains declarations for the WUSB Cryptographic routines as
9933 + * defined in the WUSB spec. They are only to be used internally by the DWC UWB
9934 + * modules.
9935 + */
9936 +
9937 +#include "dwc_os.h"
9938 +
9939 +int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst);
9940 +
9941 +void dwc_wusb_cmf(u8 *key, u8 *nonce,
9942 + char *label, u8 *bytes, int len, u8 *result);
9943 +void dwc_wusb_prf(int prf_len, u8 *key,
9944 + u8 *nonce, char *label, u8 *bytes, int len, u8 *result);
9945 +
9946 +/**
9947 + * The PRF-64 function described in section 6.5 of the WUSB spec.
9948 + *
9949 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
9950 + */
9951 +static inline void dwc_wusb_prf_64(u8 *key, u8 *nonce,
9952 + char *label, u8 *bytes, int len, u8 *result)
9953 +{
9954 + dwc_wusb_prf(64, key, nonce, label, bytes, len, result);
9955 +}
9956 +
9957 +/**
9958 + * The PRF-128 function described in section 6.5 of the WUSB spec.
9959 + *
9960 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
9961 + */
9962 +static inline void dwc_wusb_prf_128(u8 *key, u8 *nonce,
9963 + char *label, u8 *bytes, int len, u8 *result)
9964 +{
9965 + dwc_wusb_prf(128, key, nonce, label, bytes, len, result);
9966 +}
9967 +
9968 +/**
9969 + * The PRF-256 function described in section 6.5 of the WUSB spec.
9970 + *
9971 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
9972 + */
9973 +static inline void dwc_wusb_prf_256(u8 *key, u8 *nonce,
9974 + char *label, u8 *bytes, int len, u8 *result)
9975 +{
9976 + dwc_wusb_prf(256, key, nonce, label, bytes, len, result);
9977 +}
9978 +
9979 +
9980 +void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
9981 + uint8_t *nonce);
9982 +void dwc_wusb_gen_nonce(uint16_t addr,
9983 + uint8_t *nonce);
9984 +
9985 +void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk,
9986 + uint8_t *hnonce, uint8_t *dnonce,
9987 + uint8_t *kck, uint8_t *ptk);
9988 +
9989 +
9990 +void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t
9991 + *kck, uint8_t *data, uint8_t *mic);
9992 +
9993 +#ifdef __cplusplus
9994 +}
9995 +#endif
9996 +
9997 +#endif /* _DWC_CRYPTO_H_ */
9998 diff --git a/drivers/usb/host/dwc_common_port/dwc_dh.c b/drivers/usb/host/dwc_common_port/dwc_dh.c
9999 new file mode 100644
10000 index 0000000..2b429a3
10001 --- /dev/null
10002 +++ b/drivers/usb/host/dwc_common_port/dwc_dh.c
10003 @@ -0,0 +1,291 @@
10004 +/* =========================================================================
10005 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.c $
10006 + * $Revision: #3 $
10007 + * $Date: 2010/09/28 $
10008 + * $Change: 1596182 $
10009 + *
10010 + * Synopsys Portability Library Software and documentation
10011 + * (hereinafter, "Software") is an Unsupported proprietary work of
10012 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
10013 + * between Synopsys and you.
10014 + *
10015 + * The Software IS NOT an item of Licensed Software or Licensed Product
10016 + * under any End User Software License Agreement or Agreement for
10017 + * Licensed Product with Synopsys or any supplement thereto. You are
10018 + * permitted to use and redistribute this Software in source and binary
10019 + * forms, with or without modification, provided that redistributions
10020 + * of source code must retain this notice. You may not view, use,
10021 + * disclose, copy or distribute this file or any information contained
10022 + * herein except pursuant to this license grant from Synopsys. If you
10023 + * do not agree with this notice, including the disclaimer below, then
10024 + * you are not authorized to use the Software.
10025 + *
10026 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
10027 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10028 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
10029 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
10030 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
10031 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
10032 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
10033 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
10034 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
10035 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
10036 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
10037 + * DAMAGE.
10038 + * ========================================================================= */
10039 +#ifdef DWC_CRYPTOLIB
10040 +
10041 +#ifndef CONFIG_MACH_IPMATE
10042 +
10043 +#include "dwc_dh.h"
10044 +#include "dwc_modpow.h"
10045 +
10046 +#ifdef DEBUG
10047 +/* This function prints out a buffer in the format described in the Association
10048 + * Model specification. */
10049 +static void dh_dump(char *str, void *_num, int len)
10050 +{
10051 + uint8_t *num = _num;
10052 + int i;
10053 + DWC_PRINTF("%s\n", str);
10054 + for (i = 0; i < len; i ++) {
10055 + DWC_PRINTF("%02x", num[i]);
10056 + if (((i + 1) % 2) == 0) DWC_PRINTF(" ");
10057 + if (((i + 1) % 26) == 0) DWC_PRINTF("\n");
10058 + }
10059 +
10060 + DWC_PRINTF("\n");
10061 +}
10062 +#else
10063 +#define dh_dump(_x...) do {; } while(0)
10064 +#endif
10065 +
10066 +/* Constant g value */
10067 +static __u32 dh_g[] = {
10068 + 0x02000000,
10069 +};
10070 +
10071 +/* Constant p value */
10072 +static __u32 dh_p[] = {
10073 + 0xFFFFFFFF, 0xFFFFFFFF, 0xA2DA0FC9, 0x34C26821, 0x8B62C6C4, 0xD11CDC80, 0x084E0229, 0x74CC678A,
10074 + 0xA6BE0B02, 0x229B133B, 0x79084A51, 0xDD04348E, 0xB31995EF, 0x1B433ACD, 0x6D0A2B30, 0x37145FF2,
10075 + 0x6D35E14F, 0x45C2516D, 0x76B585E4, 0xC67E5E62, 0xE9424CF4, 0x6BED37A6, 0xB65CFF0B, 0xEDB706F4,
10076 + 0xFB6B38EE, 0xA59F895A, 0x11249FAE, 0xE61F4B7C, 0x51662849, 0x3D5BE4EC, 0xB87C00C2, 0x05BF63A1,
10077 + 0x3648DA98, 0x9AD3551C, 0xA83F1669, 0x5FCF24FD, 0x235D6583, 0x96ADA3DC, 0x56F3621C, 0xBB528520,
10078 + 0x0729D59E, 0x6D969670, 0x4E350C67, 0x0498BC4A, 0x086C74F1, 0x7C2118CA, 0x465E9032, 0x3BCE362E,
10079 + 0x2C779EE3, 0x03860E18, 0xA283279B, 0x8FA207EC, 0xF05DC5B5, 0xC9524C6F, 0xF6CB2BDE, 0x18175895,
10080 + 0x7C499539, 0xE56A95EA, 0x1826D215, 0x1005FA98, 0x5A8E7215, 0x2DC4AA8A, 0x0D1733AD, 0x337A5004,
10081 + 0xAB2155A8, 0x64BA1CDF, 0x0485FBEC, 0x0AEFDB58, 0x5771EA8A, 0x7D0C065D, 0x850F97B3, 0xC7E4E1A6,
10082 + 0x8CAEF5AB, 0xD73309DB, 0xE0948C1E, 0x9D61254A, 0x26D2E3CE, 0x6BEED21A, 0x06FA2FF1, 0x64088AD9,
10083 + 0x730276D8, 0x646AC83E, 0x182B1F52, 0x0C207B17, 0x5717E1BB, 0x6C5D617A, 0xC0880977, 0xE246D9BA,
10084 + 0xA04FE208, 0x31ABE574, 0xFC5BDB43, 0x8E10FDE0, 0x20D1824B, 0xCAD23AA9, 0xFFFFFFFF, 0xFFFFFFFF,
10085 +};
10086 +
10087 +static void dh_swap_bytes(void *_in, void *_out, uint32_t len)
10088 +{
10089 + uint8_t *in = _in;
10090 + uint8_t *out = _out;
10091 + int i;
10092 + for (i=0; i<len; i++) {
10093 + out[i] = in[len-1-i];
10094 + }
10095 +}
10096 +
10097 +/* Computes the modular exponentiation (num^exp % mod). num, exp, and mod are
10098 + * big endian numbers of size len, in bytes. Each len value must be a multiple
10099 + * of 4. */
10100 +int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
10101 + void *exp, uint32_t exp_len,
10102 + void *mod, uint32_t mod_len,
10103 + void *out)
10104 +{
10105 + /* modpow() takes little endian numbers. AM uses big-endian. This
10106 + * function swaps bytes of numbers before passing onto modpow. */
10107 +
10108 + int retval = 0;
10109 + uint32_t *result;
10110 +
10111 + uint32_t *bignum_num = dwc_alloc(mem_ctx, num_len + 4);
10112 + uint32_t *bignum_exp = dwc_alloc(mem_ctx, exp_len + 4);
10113 + uint32_t *bignum_mod = dwc_alloc(mem_ctx, mod_len + 4);
10114 +
10115 + dh_swap_bytes(num, &bignum_num[1], num_len);
10116 + bignum_num[0] = num_len / 4;
10117 +
10118 + dh_swap_bytes(exp, &bignum_exp[1], exp_len);
10119 + bignum_exp[0] = exp_len / 4;
10120 +
10121 + dh_swap_bytes(mod, &bignum_mod[1], mod_len);
10122 + bignum_mod[0] = mod_len / 4;
10123 +
10124 + result = dwc_modpow(mem_ctx, bignum_num, bignum_exp, bignum_mod);
10125 + if (!result) {
10126 + retval = -1;
10127 + goto dh_modpow_nomem;
10128 + }
10129 +
10130 + dh_swap_bytes(&result[1], out, result[0] * 4);
10131 + dwc_free(mem_ctx, result);
10132 +
10133 + dh_modpow_nomem:
10134 + dwc_free(mem_ctx, bignum_num);
10135 + dwc_free(mem_ctx, bignum_exp);
10136 + dwc_free(mem_ctx, bignum_mod);
10137 + return retval;
10138 +}
10139 +
10140 +
10141 +int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pk, uint8_t *hash)
10142 +{
10143 + int retval;
10144 + uint8_t m3[385];
10145 +
10146 +#ifndef DH_TEST_VECTORS
10147 + DWC_RANDOM_BYTES(exp, 32);
10148 +#endif
10149 +
10150 + /* Compute the pkd */
10151 + if ((retval = dwc_dh_modpow(mem_ctx, dh_g, 4,
10152 + exp, 32,
10153 + dh_p, 384, pk))) {
10154 + return retval;
10155 + }
10156 +
10157 + m3[384] = nd;
10158 + DWC_MEMCPY(&m3[0], pk, 384);
10159 + DWC_SHA256(m3, 385, hash);
10160 +
10161 + dh_dump("PK", pk, 384);
10162 + dh_dump("SHA-256(M3)", hash, 32);
10163 + return 0;
10164 +}
10165 +
10166 +int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
10167 + uint8_t *exp, int is_host,
10168 + char *dd, uint8_t *ck, uint8_t *kdk)
10169 +{
10170 + int retval;
10171 + uint8_t mv[784];
10172 + uint8_t sha_result[32];
10173 + uint8_t dhkey[384];
10174 + uint8_t shared_secret[384];
10175 + char *message;
10176 + uint32_t vd;
10177 +
10178 + uint8_t *pk;
10179 +
10180 + if (is_host) {
10181 + pk = pkd;
10182 + }
10183 + else {
10184 + pk = pkh;
10185 + }
10186 +
10187 + if ((retval = dwc_dh_modpow(mem_ctx, pk, 384,
10188 + exp, 32,
10189 + dh_p, 384, shared_secret))) {
10190 + return retval;
10191 + }
10192 + dh_dump("Shared Secret", shared_secret, 384);
10193 +
10194 + DWC_SHA256(shared_secret, 384, dhkey);
10195 + dh_dump("DHKEY", dhkey, 384);
10196 +
10197 + DWC_MEMCPY(&mv[0], pkd, 384);
10198 + DWC_MEMCPY(&mv[384], pkh, 384);
10199 + DWC_MEMCPY(&mv[768], "displayed digest", 16);
10200 + dh_dump("MV", mv, 784);
10201 +
10202 + DWC_SHA256(mv, 784, sha_result);
10203 + dh_dump("SHA-256(MV)", sha_result, 32);
10204 + dh_dump("First 32-bits of SHA-256(MV)", sha_result, 4);
10205 +
10206 + dh_swap_bytes(sha_result, &vd, 4);
10207 +#ifdef DEBUG
10208 + DWC_PRINTF("Vd (decimal) = %d\n", vd);
10209 +#endif
10210 +
10211 + switch (nd) {
10212 + case 2:
10213 + vd = vd % 100;
10214 + DWC_SPRINTF(dd, "%02d", vd);
10215 + break;
10216 + case 3:
10217 + vd = vd % 1000;
10218 + DWC_SPRINTF(dd, "%03d", vd);
10219 + break;
10220 + case 4:
10221 + vd = vd % 10000;
10222 + DWC_SPRINTF(dd, "%04d", vd);
10223 + break;
10224 + }
10225 +#ifdef DEBUG
10226 + DWC_PRINTF("Display Digits: %s\n", dd);
10227 +#endif
10228 +
10229 + message = "connection key";
10230 + DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
10231 + dh_dump("HMAC(SHA-256, DHKey, connection key)", sha_result, 32);
10232 + DWC_MEMCPY(ck, sha_result, 16);
10233 +
10234 + message = "key derivation key";
10235 + DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
10236 + dh_dump("HMAC(SHA-256, DHKey, key derivation key)", sha_result, 32);
10237 + DWC_MEMCPY(kdk, sha_result, 32);
10238 +
10239 + return 0;
10240 +}
10241 +
10242 +
10243 +#ifdef DH_TEST_VECTORS
10244 +
10245 +static __u8 dh_a[] = {
10246 + 0x44, 0x00, 0x51, 0xd6,
10247 + 0xf0, 0xb5, 0x5e, 0xa9,
10248 + 0x67, 0xab, 0x31, 0xc6,
10249 + 0x8a, 0x8b, 0x5e, 0x37,
10250 + 0xd9, 0x10, 0xda, 0xe0,
10251 + 0xe2, 0xd4, 0x59, 0xa4,
10252 + 0x86, 0x45, 0x9c, 0xaa,
10253 + 0xdf, 0x36, 0x75, 0x16,
10254 +};
10255 +
10256 +static __u8 dh_b[] = {
10257 + 0x5d, 0xae, 0xc7, 0x86,
10258 + 0x79, 0x80, 0xa3, 0x24,
10259 + 0x8c, 0xe3, 0x57, 0x8f,
10260 + 0xc7, 0x5f, 0x1b, 0x0f,
10261 + 0x2d, 0xf8, 0x9d, 0x30,
10262 + 0x6f, 0xa4, 0x52, 0xcd,
10263 + 0xe0, 0x7a, 0x04, 0x8a,
10264 + 0xde, 0xd9, 0x26, 0x56,
10265 +};
10266 +
10267 +void dwc_run_dh_test_vectors(void *mem_ctx)
10268 +{
10269 + uint8_t pkd[384];
10270 + uint8_t pkh[384];
10271 + uint8_t hashd[32];
10272 + uint8_t hashh[32];
10273 + uint8_t ck[16];
10274 + uint8_t kdk[32];
10275 + char dd[5];
10276 +
10277 + DWC_PRINTF("\n\n\nDH_TEST_VECTORS\n\n");
10278 +
10279 + /* compute the PKd and SHA-256(PKd || Nd) */
10280 + DWC_PRINTF("Computing PKd\n");
10281 + dwc_dh_pk(mem_ctx, 2, dh_a, pkd, hashd);
10282 +
10283 + /* compute the PKd and SHA-256(PKh || Nd) */
10284 + DWC_PRINTF("Computing PKh\n");
10285 + dwc_dh_pk(mem_ctx, 2, dh_b, pkh, hashh);
10286 +
10287 + /* compute the dhkey */
10288 + dwc_dh_derive_keys(mem_ctx, 2, pkh, pkd, dh_a, 0, dd, ck, kdk);
10289 +}
10290 +#endif /* DH_TEST_VECTORS */
10291 +
10292 +#endif /* !CONFIG_MACH_IPMATE */
10293 +
10294 +#endif /* DWC_CRYPTOLIB */
10295 diff --git a/drivers/usb/host/dwc_common_port/dwc_dh.h b/drivers/usb/host/dwc_common_port/dwc_dh.h
10296 new file mode 100644
10297 index 0000000..25c1cc0
10298 --- /dev/null
10299 +++ b/drivers/usb/host/dwc_common_port/dwc_dh.h
10300 @@ -0,0 +1,106 @@
10301 +/* =========================================================================
10302 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.h $
10303 + * $Revision: #4 $
10304 + * $Date: 2010/09/28 $
10305 + * $Change: 1596182 $
10306 + *
10307 + * Synopsys Portability Library Software and documentation
10308 + * (hereinafter, "Software") is an Unsupported proprietary work of
10309 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
10310 + * between Synopsys and you.
10311 + *
10312 + * The Software IS NOT an item of Licensed Software or Licensed Product
10313 + * under any End User Software License Agreement or Agreement for
10314 + * Licensed Product with Synopsys or any supplement thereto. You are
10315 + * permitted to use and redistribute this Software in source and binary
10316 + * forms, with or without modification, provided that redistributions
10317 + * of source code must retain this notice. You may not view, use,
10318 + * disclose, copy or distribute this file or any information contained
10319 + * herein except pursuant to this license grant from Synopsys. If you
10320 + * do not agree with this notice, including the disclaimer below, then
10321 + * you are not authorized to use the Software.
10322 + *
10323 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
10324 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10325 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
10326 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
10327 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
10328 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
10329 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
10330 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
10331 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
10332 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
10333 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
10334 + * DAMAGE.
10335 + * ========================================================================= */
10336 +#ifndef _DWC_DH_H_
10337 +#define _DWC_DH_H_
10338 +
10339 +#ifdef __cplusplus
10340 +extern "C" {
10341 +#endif
10342 +
10343 +#include "dwc_os.h"
10344 +
10345 +/** @file
10346 + *
10347 + * This file defines the common functions on device and host for performing
10348 + * numeric association as defined in the WUSB spec. They are only to be
10349 + * used internally by the DWC UWB modules. */
10350 +
10351 +extern int dwc_dh_sha256(uint8_t *message, uint32_t len, uint8_t *out);
10352 +extern int dwc_dh_hmac_sha256(uint8_t *message, uint32_t messagelen,
10353 + uint8_t *key, uint32_t keylen,
10354 + uint8_t *out);
10355 +extern int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
10356 + void *exp, uint32_t exp_len,
10357 + void *mod, uint32_t mod_len,
10358 + void *out);
10359 +
10360 +/** Computes PKD or PKH, and SHA-256(PKd || Nd)
10361 + *
10362 + * PK = g^exp mod p.
10363 + *
10364 + * Input:
10365 + * Nd = Number of digits on the device.
10366 + *
10367 + * Output:
10368 + * exp = A 32-byte buffer to be filled with a randomly generated number.
10369 + * used as either A or B.
10370 + * pk = A 384-byte buffer to be filled with the PKH or PKD.
10371 + * hash = A 32-byte buffer to be filled with SHA-256(PK || ND).
10372 + */
10373 +extern int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pkd, uint8_t *hash);
10374 +
10375 +/** Computes the DHKEY, and VD.
10376 + *
10377 + * If called from host, then it will comput DHKEY=PKD^exp % p.
10378 + * If called from device, then it will comput DHKEY=PKH^exp % p.
10379 + *
10380 + * Input:
10381 + * pkd = The PKD value.
10382 + * pkh = The PKH value.
10383 + * exp = The A value (if device) or B value (if host) generated in dwc_wudev_dh_pk.
10384 + * is_host = Set to non zero if a WUSB host is calling this function.
10385 + *
10386 + * Output:
10387 +
10388 + * dd = A pointer to an buffer to be set to the displayed digits string to be shown
10389 + * to the user. This buffer should be at 5 bytes long to hold 4 digits plus a
10390 + * null termination character. This buffer can be used directly for display.
10391 + * ck = A 16-byte buffer to be filled with the CK.
10392 + * kdk = A 32-byte buffer to be filled with the KDK.
10393 + */
10394 +extern int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
10395 + uint8_t *exp, int is_host,
10396 + char *dd, uint8_t *ck, uint8_t *kdk);
10397 +
10398 +#ifdef DH_TEST_VECTORS
10399 +extern void dwc_run_dh_test_vectors(void);
10400 +#endif
10401 +
10402 +#ifdef __cplusplus
10403 +}
10404 +#endif
10405 +
10406 +#endif /* _DWC_DH_H_ */
10407 diff --git a/drivers/usb/host/dwc_common_port/dwc_list.h b/drivers/usb/host/dwc_common_port/dwc_list.h
10408 new file mode 100644
10409 index 0000000..89cc325
10410 --- /dev/null
10411 +++ b/drivers/usb/host/dwc_common_port/dwc_list.h
10412 @@ -0,0 +1,594 @@
10413 +/* $OpenBSD: queue.h,v 1.26 2004/05/04 16:59:32 grange Exp $ */
10414 +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
10415 +
10416 +/*
10417 + * Copyright (c) 1991, 1993
10418 + * The Regents of the University of California. All rights reserved.
10419 + *
10420 + * Redistribution and use in source and binary forms, with or without
10421 + * modification, are permitted provided that the following conditions
10422 + * are met:
10423 + * 1. Redistributions of source code must retain the above copyright
10424 + * notice, this list of conditions and the following disclaimer.
10425 + * 2. Redistributions in binary form must reproduce the above copyright
10426 + * notice, this list of conditions and the following disclaimer in the
10427 + * documentation and/or other materials provided with the distribution.
10428 + * 3. Neither the name of the University nor the names of its contributors
10429 + * may be used to endorse or promote products derived from this software
10430 + * without specific prior written permission.
10431 + *
10432 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
10433 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10434 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10435 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
10436 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10437 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10438 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10439 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10440 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10441 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10442 + * SUCH DAMAGE.
10443 + *
10444 + * @(#)queue.h 8.5 (Berkeley) 8/20/94
10445 + */
10446 +
10447 +#ifndef _DWC_LIST_H_
10448 +#define _DWC_LIST_H_
10449 +
10450 +#ifdef __cplusplus
10451 +extern "C" {
10452 +#endif
10453 +
10454 +/** @file
10455 + *
10456 + * This file defines linked list operations. It is derived from BSD with
10457 + * only the MACRO names being prefixed with DWC_. This is because a few of
10458 + * these names conflict with those on Linux. For documentation on use, see the
10459 + * inline comments in the source code. The original license for this source
10460 + * code applies and is preserved in the dwc_list.h source file.
10461 + */
10462 +
10463 +/*
10464 + * This file defines five types of data structures: singly-linked lists,
10465 + * lists, simple queues, tail queues, and circular queues.
10466 + *
10467 + *
10468 + * A singly-linked list is headed by a single forward pointer. The elements
10469 + * are singly linked for minimum space and pointer manipulation overhead at
10470 + * the expense of O(n) removal for arbitrary elements. New elements can be
10471 + * added to the list after an existing element or at the head of the list.
10472 + * Elements being removed from the head of the list should use the explicit
10473 + * macro for this purpose for optimum efficiency. A singly-linked list may
10474 + * only be traversed in the forward direction. Singly-linked lists are ideal
10475 + * for applications with large datasets and few or no removals or for
10476 + * implementing a LIFO queue.
10477 + *
10478 + * A list is headed by a single forward pointer (or an array of forward
10479 + * pointers for a hash table header). The elements are doubly linked
10480 + * so that an arbitrary element can be removed without a need to
10481 + * traverse the list. New elements can be added to the list before
10482 + * or after an existing element or at the head of the list. A list
10483 + * may only be traversed in the forward direction.
10484 + *
10485 + * A simple queue is headed by a pair of pointers, one the head of the
10486 + * list and the other to the tail of the list. The elements are singly
10487 + * linked to save space, so elements can only be removed from the
10488 + * head of the list. New elements can be added to the list before or after
10489 + * an existing element, at the head of the list, or at the end of the
10490 + * list. A simple queue may only be traversed in the forward direction.
10491 + *
10492 + * A tail queue is headed by a pair of pointers, one to the head of the
10493 + * list and the other to the tail of the list. The elements are doubly
10494 + * linked so that an arbitrary element can be removed without a need to
10495 + * traverse the list. New elements can be added to the list before or
10496 + * after an existing element, at the head of the list, or at the end of
10497 + * the list. A tail queue may be traversed in either direction.
10498 + *
10499 + * A circle 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 after
10503 + * an existing element, at the head of the list, or at the end of the list.
10504 + * A circle queue may be traversed in either direction, but has a more
10505 + * complex end of list detection.
10506 + *
10507 + * For details on the use of these macros, see the queue(3) manual page.
10508 + */
10509 +
10510 +/*
10511 + * Double-linked List.
10512 + */
10513 +
10514 +typedef struct dwc_list_link {
10515 + struct dwc_list_link *next;
10516 + struct dwc_list_link *prev;
10517 +} dwc_list_link_t;
10518 +
10519 +#define DWC_LIST_INIT(link) do { \
10520 + (link)->next = (link); \
10521 + (link)->prev = (link); \
10522 +} while (0)
10523 +
10524 +#define DWC_LIST_FIRST(link) ((link)->next)
10525 +#define DWC_LIST_LAST(link) ((link)->prev)
10526 +#define DWC_LIST_END(link) (link)
10527 +#define DWC_LIST_NEXT(link) ((link)->next)
10528 +#define DWC_LIST_PREV(link) ((link)->prev)
10529 +#define DWC_LIST_EMPTY(link) \
10530 + (DWC_LIST_FIRST(link) == DWC_LIST_END(link))
10531 +#define DWC_LIST_ENTRY(link, type, field) \
10532 + (type *)((uint8_t *)(link) - (size_t)(&((type *)0)->field))
10533 +
10534 +#if 0
10535 +#define DWC_LIST_INSERT_HEAD(list, link) do { \
10536 + (link)->next = (list)->next; \
10537 + (link)->prev = (list); \
10538 + (list)->next->prev = (link); \
10539 + (list)->next = (link); \
10540 +} while (0)
10541 +
10542 +#define DWC_LIST_INSERT_TAIL(list, link) do { \
10543 + (link)->next = (list); \
10544 + (link)->prev = (list)->prev; \
10545 + (list)->prev->next = (link); \
10546 + (list)->prev = (link); \
10547 +} while (0)
10548 +#else
10549 +#define DWC_LIST_INSERT_HEAD(list, link) do { \
10550 + dwc_list_link_t *__next__ = (list)->next; \
10551 + __next__->prev = (link); \
10552 + (link)->next = __next__; \
10553 + (link)->prev = (list); \
10554 + (list)->next = (link); \
10555 +} while (0)
10556 +
10557 +#define DWC_LIST_INSERT_TAIL(list, link) do { \
10558 + dwc_list_link_t *__prev__ = (list)->prev; \
10559 + (list)->prev = (link); \
10560 + (link)->next = (list); \
10561 + (link)->prev = __prev__; \
10562 + __prev__->next = (link); \
10563 +} while (0)
10564 +#endif
10565 +
10566 +#if 0
10567 +static inline void __list_add(struct list_head *new,
10568 + struct list_head *prev,
10569 + struct list_head *next)
10570 +{
10571 + next->prev = new;
10572 + new->next = next;
10573 + new->prev = prev;
10574 + prev->next = new;
10575 +}
10576 +
10577 +static inline void list_add(struct list_head *new, struct list_head *head)
10578 +{
10579 + __list_add(new, head, head->next);
10580 +}
10581 +
10582 +static inline void list_add_tail(struct list_head *new, struct list_head *head)
10583 +{
10584 + __list_add(new, head->prev, head);
10585 +}
10586 +
10587 +static inline void __list_del(struct list_head * prev, struct list_head * next)
10588 +{
10589 + next->prev = prev;
10590 + prev->next = next;
10591 +}
10592 +
10593 +static inline void list_del(struct list_head *entry)
10594 +{
10595 + __list_del(entry->prev, entry->next);
10596 + entry->next = LIST_POISON1;
10597 + entry->prev = LIST_POISON2;
10598 +}
10599 +#endif
10600 +
10601 +#define DWC_LIST_REMOVE(link) do { \
10602 + (link)->next->prev = (link)->prev; \
10603 + (link)->prev->next = (link)->next; \
10604 +} while (0)
10605 +
10606 +#define DWC_LIST_REMOVE_INIT(link) do { \
10607 + DWC_LIST_REMOVE(link); \
10608 + DWC_LIST_INIT(link); \
10609 +} while (0)
10610 +
10611 +#define DWC_LIST_MOVE_HEAD(list, link) do { \
10612 + DWC_LIST_REMOVE(link); \
10613 + DWC_LIST_INSERT_HEAD(list, link); \
10614 +} while (0)
10615 +
10616 +#define DWC_LIST_MOVE_TAIL(list, link) do { \
10617 + DWC_LIST_REMOVE(link); \
10618 + DWC_LIST_INSERT_TAIL(list, link); \
10619 +} while (0)
10620 +
10621 +#define DWC_LIST_FOREACH(var, list) \
10622 + for((var) = DWC_LIST_FIRST(list); \
10623 + (var) != DWC_LIST_END(list); \
10624 + (var) = DWC_LIST_NEXT(var))
10625 +
10626 +#define DWC_LIST_FOREACH_SAFE(var, var2, list) \
10627 + for((var) = DWC_LIST_FIRST(list), (var2) = DWC_LIST_NEXT(var); \
10628 + (var) != DWC_LIST_END(list); \
10629 + (var) = (var2), (var2) = DWC_LIST_NEXT(var2))
10630 +
10631 +#define DWC_LIST_FOREACH_REVERSE(var, list) \
10632 + for((var) = DWC_LIST_LAST(list); \
10633 + (var) != DWC_LIST_END(list); \
10634 + (var) = DWC_LIST_PREV(var))
10635 +
10636 +/*
10637 + * Singly-linked List definitions.
10638 + */
10639 +#define DWC_SLIST_HEAD(name, type) \
10640 +struct name { \
10641 + struct type *slh_first; /* first element */ \
10642 +}
10643 +
10644 +#define DWC_SLIST_HEAD_INITIALIZER(head) \
10645 + { NULL }
10646 +
10647 +#define DWC_SLIST_ENTRY(type) \
10648 +struct { \
10649 + struct type *sle_next; /* next element */ \
10650 +}
10651 +
10652 +/*
10653 + * Singly-linked List access methods.
10654 + */
10655 +#define DWC_SLIST_FIRST(head) ((head)->slh_first)
10656 +#define DWC_SLIST_END(head) NULL
10657 +#define DWC_SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
10658 +#define DWC_SLIST_NEXT(elm, field) ((elm)->field.sle_next)
10659 +
10660 +#define DWC_SLIST_FOREACH(var, head, field) \
10661 + for((var) = SLIST_FIRST(head); \
10662 + (var) != SLIST_END(head); \
10663 + (var) = SLIST_NEXT(var, field))
10664 +
10665 +#define DWC_SLIST_FOREACH_PREVPTR(var, varp, head, field) \
10666 + for((varp) = &SLIST_FIRST((head)); \
10667 + ((var) = *(varp)) != SLIST_END(head); \
10668 + (varp) = &SLIST_NEXT((var), field))
10669 +
10670 +/*
10671 + * Singly-linked List functions.
10672 + */
10673 +#define DWC_SLIST_INIT(head) { \
10674 + SLIST_FIRST(head) = SLIST_END(head); \
10675 +}
10676 +
10677 +#define DWC_SLIST_INSERT_AFTER(slistelm, elm, field) do { \
10678 + (elm)->field.sle_next = (slistelm)->field.sle_next; \
10679 + (slistelm)->field.sle_next = (elm); \
10680 +} while (0)
10681 +
10682 +#define DWC_SLIST_INSERT_HEAD(head, elm, field) do { \
10683 + (elm)->field.sle_next = (head)->slh_first; \
10684 + (head)->slh_first = (elm); \
10685 +} while (0)
10686 +
10687 +#define DWC_SLIST_REMOVE_NEXT(head, elm, field) do { \
10688 + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
10689 +} while (0)
10690 +
10691 +#define DWC_SLIST_REMOVE_HEAD(head, field) do { \
10692 + (head)->slh_first = (head)->slh_first->field.sle_next; \
10693 +} while (0)
10694 +
10695 +#define DWC_SLIST_REMOVE(head, elm, type, field) do { \
10696 + if ((head)->slh_first == (elm)) { \
10697 + SLIST_REMOVE_HEAD((head), field); \
10698 + } \
10699 + else { \
10700 + struct type *curelm = (head)->slh_first; \
10701 + while( curelm->field.sle_next != (elm) ) \
10702 + curelm = curelm->field.sle_next; \
10703 + curelm->field.sle_next = \
10704 + curelm->field.sle_next->field.sle_next; \
10705 + } \
10706 +} while (0)
10707 +
10708 +/*
10709 + * Simple queue definitions.
10710 + */
10711 +#define DWC_SIMPLEQ_HEAD(name, type) \
10712 +struct name { \
10713 + struct type *sqh_first; /* first element */ \
10714 + struct type **sqh_last; /* addr of last next element */ \
10715 +}
10716 +
10717 +#define DWC_SIMPLEQ_HEAD_INITIALIZER(head) \
10718 + { NULL, &(head).sqh_first }
10719 +
10720 +#define DWC_SIMPLEQ_ENTRY(type) \
10721 +struct { \
10722 + struct type *sqe_next; /* next element */ \
10723 +}
10724 +
10725 +/*
10726 + * Simple queue access methods.
10727 + */
10728 +#define DWC_SIMPLEQ_FIRST(head) ((head)->sqh_first)
10729 +#define DWC_SIMPLEQ_END(head) NULL
10730 +#define DWC_SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
10731 +#define DWC_SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
10732 +
10733 +#define DWC_SIMPLEQ_FOREACH(var, head, field) \
10734 + for((var) = SIMPLEQ_FIRST(head); \
10735 + (var) != SIMPLEQ_END(head); \
10736 + (var) = SIMPLEQ_NEXT(var, field))
10737 +
10738 +/*
10739 + * Simple queue functions.
10740 + */
10741 +#define DWC_SIMPLEQ_INIT(head) do { \
10742 + (head)->sqh_first = NULL; \
10743 + (head)->sqh_last = &(head)->sqh_first; \
10744 +} while (0)
10745 +
10746 +#define DWC_SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
10747 + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
10748 + (head)->sqh_last = &(elm)->field.sqe_next; \
10749 + (head)->sqh_first = (elm); \
10750 +} while (0)
10751 +
10752 +#define DWC_SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
10753 + (elm)->field.sqe_next = NULL; \
10754 + *(head)->sqh_last = (elm); \
10755 + (head)->sqh_last = &(elm)->field.sqe_next; \
10756 +} while (0)
10757 +
10758 +#define DWC_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
10759 + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
10760 + (head)->sqh_last = &(elm)->field.sqe_next; \
10761 + (listelm)->field.sqe_next = (elm); \
10762 +} while (0)
10763 +
10764 +#define DWC_SIMPLEQ_REMOVE_HEAD(head, field) do { \
10765 + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
10766 + (head)->sqh_last = &(head)->sqh_first; \
10767 +} while (0)
10768 +
10769 +/*
10770 + * Tail queue definitions.
10771 + */
10772 +#define DWC_TAILQ_HEAD(name, type) \
10773 +struct name { \
10774 + struct type *tqh_first; /* first element */ \
10775 + struct type **tqh_last; /* addr of last next element */ \
10776 +}
10777 +
10778 +#define DWC_TAILQ_HEAD_INITIALIZER(head) \
10779 + { NULL, &(head).tqh_first }
10780 +
10781 +#define DWC_TAILQ_ENTRY(type) \
10782 +struct { \
10783 + struct type *tqe_next; /* next element */ \
10784 + struct type **tqe_prev; /* address of previous next element */ \
10785 +}
10786 +
10787 +/*
10788 + * tail queue access methods
10789 + */
10790 +#define DWC_TAILQ_FIRST(head) ((head)->tqh_first)
10791 +#define DWC_TAILQ_END(head) NULL
10792 +#define DWC_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
10793 +#define DWC_TAILQ_LAST(head, headname) \
10794 + (*(((struct headname *)((head)->tqh_last))->tqh_last))
10795 +/* XXX */
10796 +#define DWC_TAILQ_PREV(elm, headname, field) \
10797 + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
10798 +#define DWC_TAILQ_EMPTY(head) \
10799 + (TAILQ_FIRST(head) == TAILQ_END(head))
10800 +
10801 +#define DWC_TAILQ_FOREACH(var, head, field) \
10802 + for((var) = TAILQ_FIRST(head); \
10803 + (var) != TAILQ_END(head); \
10804 + (var) = TAILQ_NEXT(var, field))
10805 +
10806 +#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
10807 + for((var) = TAILQ_LAST(head, headname); \
10808 + (var) != TAILQ_END(head); \
10809 + (var) = TAILQ_PREV(var, headname, field))
10810 +
10811 +/*
10812 + * Tail queue functions.
10813 + */
10814 +#define DWC_TAILQ_INIT(head) do { \
10815 + (head)->tqh_first = NULL; \
10816 + (head)->tqh_last = &(head)->tqh_first; \
10817 +} while (0)
10818 +
10819 +#define DWC_TAILQ_INSERT_HEAD(head, elm, field) do { \
10820 + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
10821 + (head)->tqh_first->field.tqe_prev = \
10822 + &(elm)->field.tqe_next; \
10823 + else \
10824 + (head)->tqh_last = &(elm)->field.tqe_next; \
10825 + (head)->tqh_first = (elm); \
10826 + (elm)->field.tqe_prev = &(head)->tqh_first; \
10827 +} while (0)
10828 +
10829 +#define DWC_TAILQ_INSERT_TAIL(head, elm, field) do { \
10830 + (elm)->field.tqe_next = NULL; \
10831 + (elm)->field.tqe_prev = (head)->tqh_last; \
10832 + *(head)->tqh_last = (elm); \
10833 + (head)->tqh_last = &(elm)->field.tqe_next; \
10834 +} while (0)
10835 +
10836 +#define DWC_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
10837 + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
10838 + (elm)->field.tqe_next->field.tqe_prev = \
10839 + &(elm)->field.tqe_next; \
10840 + else \
10841 + (head)->tqh_last = &(elm)->field.tqe_next; \
10842 + (listelm)->field.tqe_next = (elm); \
10843 + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
10844 +} while (0)
10845 +
10846 +#define DWC_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
10847 + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
10848 + (elm)->field.tqe_next = (listelm); \
10849 + *(listelm)->field.tqe_prev = (elm); \
10850 + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
10851 +} while (0)
10852 +
10853 +#define DWC_TAILQ_REMOVE(head, elm, field) do { \
10854 + if (((elm)->field.tqe_next) != NULL) \
10855 + (elm)->field.tqe_next->field.tqe_prev = \
10856 + (elm)->field.tqe_prev; \
10857 + else \
10858 + (head)->tqh_last = (elm)->field.tqe_prev; \
10859 + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
10860 +} while (0)
10861 +
10862 +#define DWC_TAILQ_REPLACE(head, elm, elm2, field) do { \
10863 + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
10864 + (elm2)->field.tqe_next->field.tqe_prev = \
10865 + &(elm2)->field.tqe_next; \
10866 + else \
10867 + (head)->tqh_last = &(elm2)->field.tqe_next; \
10868 + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
10869 + *(elm2)->field.tqe_prev = (elm2); \
10870 +} while (0)
10871 +
10872 +/*
10873 + * Circular queue definitions.
10874 + */
10875 +#define DWC_CIRCLEQ_HEAD(name, type) \
10876 +struct name { \
10877 + struct type *cqh_first; /* first element */ \
10878 + struct type *cqh_last; /* last element */ \
10879 +}
10880 +
10881 +#define DWC_CIRCLEQ_HEAD_INITIALIZER(head) \
10882 + { DWC_CIRCLEQ_END(&head), DWC_CIRCLEQ_END(&head) }
10883 +
10884 +#define DWC_CIRCLEQ_ENTRY(type) \
10885 +struct { \
10886 + struct type *cqe_next; /* next element */ \
10887 + struct type *cqe_prev; /* previous element */ \
10888 +}
10889 +
10890 +/*
10891 + * Circular queue access methods
10892 + */
10893 +#define DWC_CIRCLEQ_FIRST(head) ((head)->cqh_first)
10894 +#define DWC_CIRCLEQ_LAST(head) ((head)->cqh_last)
10895 +#define DWC_CIRCLEQ_END(head) ((void *)(head))
10896 +#define DWC_CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
10897 +#define DWC_CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
10898 +#define DWC_CIRCLEQ_EMPTY(head) \
10899 + (DWC_CIRCLEQ_FIRST(head) == DWC_CIRCLEQ_END(head))
10900 +
10901 +#define DWC_CIRCLEQ_EMPTY_ENTRY(elm, field) (((elm)->field.cqe_next == NULL) && ((elm)->field.cqe_prev == NULL))
10902 +
10903 +#define DWC_CIRCLEQ_FOREACH(var, head, field) \
10904 + for((var) = DWC_CIRCLEQ_FIRST(head); \
10905 + (var) != DWC_CIRCLEQ_END(head); \
10906 + (var) = DWC_CIRCLEQ_NEXT(var, field))
10907 +
10908 +#define DWC_CIRCLEQ_FOREACH_SAFE(var, var2, head, field) \
10909 + for((var) = DWC_CIRCLEQ_FIRST(head), var2 = DWC_CIRCLEQ_NEXT(var, field); \
10910 + (var) != DWC_CIRCLEQ_END(head); \
10911 + (var) = var2, var2 = DWC_CIRCLEQ_NEXT(var, field))
10912 +
10913 +#define DWC_CIRCLEQ_FOREACH_REVERSE(var, head, field) \
10914 + for((var) = DWC_CIRCLEQ_LAST(head); \
10915 + (var) != DWC_CIRCLEQ_END(head); \
10916 + (var) = DWC_CIRCLEQ_PREV(var, field))
10917 +
10918 +/*
10919 + * Circular queue functions.
10920 + */
10921 +#define DWC_CIRCLEQ_INIT(head) do { \
10922 + (head)->cqh_first = DWC_CIRCLEQ_END(head); \
10923 + (head)->cqh_last = DWC_CIRCLEQ_END(head); \
10924 +} while (0)
10925 +
10926 +#define DWC_CIRCLEQ_INIT_ENTRY(elm, field) do { \
10927 + (elm)->field.cqe_next = NULL; \
10928 + (elm)->field.cqe_prev = NULL; \
10929 +} while (0)
10930 +
10931 +#define DWC_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
10932 + (elm)->field.cqe_next = (listelm)->field.cqe_next; \
10933 + (elm)->field.cqe_prev = (listelm); \
10934 + if ((listelm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
10935 + (head)->cqh_last = (elm); \
10936 + else \
10937 + (listelm)->field.cqe_next->field.cqe_prev = (elm); \
10938 + (listelm)->field.cqe_next = (elm); \
10939 +} while (0)
10940 +
10941 +#define DWC_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
10942 + (elm)->field.cqe_next = (listelm); \
10943 + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
10944 + if ((listelm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
10945 + (head)->cqh_first = (elm); \
10946 + else \
10947 + (listelm)->field.cqe_prev->field.cqe_next = (elm); \
10948 + (listelm)->field.cqe_prev = (elm); \
10949 +} while (0)
10950 +
10951 +#define DWC_CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
10952 + (elm)->field.cqe_next = (head)->cqh_first; \
10953 + (elm)->field.cqe_prev = DWC_CIRCLEQ_END(head); \
10954 + if ((head)->cqh_last == DWC_CIRCLEQ_END(head)) \
10955 + (head)->cqh_last = (elm); \
10956 + else \
10957 + (head)->cqh_first->field.cqe_prev = (elm); \
10958 + (head)->cqh_first = (elm); \
10959 +} while (0)
10960 +
10961 +#define DWC_CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
10962 + (elm)->field.cqe_next = DWC_CIRCLEQ_END(head); \
10963 + (elm)->field.cqe_prev = (head)->cqh_last; \
10964 + if ((head)->cqh_first == DWC_CIRCLEQ_END(head)) \
10965 + (head)->cqh_first = (elm); \
10966 + else \
10967 + (head)->cqh_last->field.cqe_next = (elm); \
10968 + (head)->cqh_last = (elm); \
10969 +} while (0)
10970 +
10971 +#define DWC_CIRCLEQ_REMOVE(head, elm, field) do { \
10972 + if ((elm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
10973 + (head)->cqh_last = (elm)->field.cqe_prev; \
10974 + else \
10975 + (elm)->field.cqe_next->field.cqe_prev = \
10976 + (elm)->field.cqe_prev; \
10977 + if ((elm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
10978 + (head)->cqh_first = (elm)->field.cqe_next; \
10979 + else \
10980 + (elm)->field.cqe_prev->field.cqe_next = \
10981 + (elm)->field.cqe_next; \
10982 +} while (0)
10983 +
10984 +#define DWC_CIRCLEQ_REMOVE_INIT(head, elm, field) do { \
10985 + DWC_CIRCLEQ_REMOVE(head, elm, field); \
10986 + DWC_CIRCLEQ_INIT_ENTRY(elm, field); \
10987 +} while (0)
10988 +
10989 +#define DWC_CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
10990 + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
10991 + DWC_CIRCLEQ_END(head)) \
10992 + (head).cqh_last = (elm2); \
10993 + else \
10994 + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
10995 + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
10996 + DWC_CIRCLEQ_END(head)) \
10997 + (head).cqh_first = (elm2); \
10998 + else \
10999 + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
11000 +} while (0)
11001 +
11002 +#ifdef __cplusplus
11003 +}
11004 +#endif
11005 +
11006 +#endif /* _DWC_LIST_H_ */
11007 diff --git a/drivers/usb/host/dwc_common_port/dwc_mem.c b/drivers/usb/host/dwc_common_port/dwc_mem.c
11008 new file mode 100644
11009 index 0000000..ad645ff
11010 --- /dev/null
11011 +++ b/drivers/usb/host/dwc_common_port/dwc_mem.c
11012 @@ -0,0 +1,245 @@
11013 +/* Memory Debugging */
11014 +#ifdef DWC_DEBUG_MEMORY
11015 +
11016 +#include "dwc_os.h"
11017 +#include "dwc_list.h"
11018 +
11019 +struct allocation {
11020 + void *addr;
11021 + void *ctx;
11022 + char *func;
11023 + int line;
11024 + uint32_t size;
11025 + int dma;
11026 + DWC_CIRCLEQ_ENTRY(allocation) entry;
11027 +};
11028 +
11029 +DWC_CIRCLEQ_HEAD(allocation_queue, allocation);
11030 +
11031 +struct allocation_manager {
11032 + void *mem_ctx;
11033 + struct allocation_queue allocations;
11034 +
11035 + /* statistics */
11036 + int num;
11037 + int num_freed;
11038 + int num_active;
11039 + uint32_t total;
11040 + uint32_t cur;
11041 + uint32_t max;
11042 +};
11043 +
11044 +static struct allocation_manager *manager = NULL;
11045 +
11046 +static int add_allocation(void *ctx, uint32_t size, char const *func, int line, void *addr,
11047 + int dma)
11048 +{
11049 + struct allocation *a;
11050 +
11051 + DWC_ASSERT(manager != NULL, "manager not allocated");
11052 +
11053 + a = __DWC_ALLOC_ATOMIC(manager->mem_ctx, sizeof(*a));
11054 + if (!a) {
11055 + return -DWC_E_NO_MEMORY;
11056 + }
11057 +
11058 + a->func = __DWC_ALLOC_ATOMIC(manager->mem_ctx, DWC_STRLEN(func) + 1);
11059 + if (!a->func) {
11060 + __DWC_FREE(manager->mem_ctx, a);
11061 + return -DWC_E_NO_MEMORY;
11062 + }
11063 +
11064 + DWC_MEMCPY(a->func, func, DWC_STRLEN(func) + 1);
11065 + a->addr = addr;
11066 + a->ctx = ctx;
11067 + a->line = line;
11068 + a->size = size;
11069 + a->dma = dma;
11070 + DWC_CIRCLEQ_INSERT_TAIL(&manager->allocations, a, entry);
11071 +
11072 + /* Update stats */
11073 + manager->num++;
11074 + manager->num_active++;
11075 + manager->total += size;
11076 + manager->cur += size;
11077 +
11078 + if (manager->max < manager->cur) {
11079 + manager->max = manager->cur;
11080 + }
11081 +
11082 + return 0;
11083 +}
11084 +
11085 +static struct allocation *find_allocation(void *ctx, void *addr)
11086 +{
11087 + struct allocation *a;
11088 +
11089 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
11090 + if (a->ctx == ctx && a->addr == addr) {
11091 + return a;
11092 + }
11093 + }
11094 +
11095 + return NULL;
11096 +}
11097 +
11098 +static void free_allocation(void *ctx, void *addr, char const *func, int line)
11099 +{
11100 + struct allocation *a = find_allocation(ctx, addr);
11101 +
11102 + if (!a) {
11103 + DWC_ASSERT(0,
11104 + "Free of address %p that was never allocated or already freed %s:%d",
11105 + addr, func, line);
11106 + return;
11107 + }
11108 +
11109 + DWC_CIRCLEQ_REMOVE(&manager->allocations, a, entry);
11110 +
11111 + manager->num_active--;
11112 + manager->num_freed++;
11113 + manager->cur -= a->size;
11114 + __DWC_FREE(manager->mem_ctx, a->func);
11115 + __DWC_FREE(manager->mem_ctx, a);
11116 +}
11117 +
11118 +int dwc_memory_debug_start(void *mem_ctx)
11119 +{
11120 + DWC_ASSERT(manager == NULL, "Memory debugging has already started\n");
11121 +
11122 + if (manager) {
11123 + return -DWC_E_BUSY;
11124 + }
11125 +
11126 + manager = __DWC_ALLOC(mem_ctx, sizeof(*manager));
11127 + if (!manager) {
11128 + return -DWC_E_NO_MEMORY;
11129 + }
11130 +
11131 + DWC_CIRCLEQ_INIT(&manager->allocations);
11132 + manager->mem_ctx = mem_ctx;
11133 + manager->num = 0;
11134 + manager->num_freed = 0;
11135 + manager->num_active = 0;
11136 + manager->total = 0;
11137 + manager->cur = 0;
11138 + manager->max = 0;
11139 +
11140 + return 0;
11141 +}
11142 +
11143 +void dwc_memory_debug_stop(void)
11144 +{
11145 + struct allocation *a;
11146 +
11147 + dwc_memory_debug_report();
11148 +
11149 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
11150 + DWC_ERROR("Memory leaked from %s:%d\n", a->func, a->line);
11151 + free_allocation(a->ctx, a->addr, NULL, -1);
11152 + }
11153 +
11154 + __DWC_FREE(manager->mem_ctx, manager);
11155 +}
11156 +
11157 +void dwc_memory_debug_report(void)
11158 +{
11159 + struct allocation *a;
11160 +
11161 + DWC_PRINTF("\n\n\n----------------- Memory Debugging Report -----------------\n\n");
11162 + DWC_PRINTF("Num Allocations = %d\n", manager->num);
11163 + DWC_PRINTF("Freed = %d\n", manager->num_freed);
11164 + DWC_PRINTF("Active = %d\n", manager->num_active);
11165 + DWC_PRINTF("Current Memory Used = %d\n", manager->cur);
11166 + DWC_PRINTF("Total Memory Used = %d\n", manager->total);
11167 + DWC_PRINTF("Maximum Memory Used at Once = %d\n", manager->max);
11168 + DWC_PRINTF("Unfreed allocations:\n");
11169 +
11170 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
11171 + DWC_PRINTF(" addr=%p, size=%d from %s:%d, DMA=%d\n",
11172 + a->addr, a->size, a->func, a->line, a->dma);
11173 + }
11174 +}
11175 +
11176 +/* The replacement functions */
11177 +void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line)
11178 +{
11179 + void *addr = __DWC_ALLOC(mem_ctx, size);
11180 +
11181 + if (!addr) {
11182 + return NULL;
11183 + }
11184 +
11185 + if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
11186 + __DWC_FREE(mem_ctx, addr);
11187 + return NULL;
11188 + }
11189 +
11190 + return addr;
11191 +}
11192 +
11193 +void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func,
11194 + int line)
11195 +{
11196 + void *addr = __DWC_ALLOC_ATOMIC(mem_ctx, size);
11197 +
11198 + if (!addr) {
11199 + return NULL;
11200 + }
11201 +
11202 + if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
11203 + __DWC_FREE(mem_ctx, addr);
11204 + return NULL;
11205 + }
11206 +
11207 + return addr;
11208 +}
11209 +
11210 +void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line)
11211 +{
11212 + free_allocation(mem_ctx, addr, func, line);
11213 + __DWC_FREE(mem_ctx, addr);
11214 +}
11215 +
11216 +void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
11217 + char const *func, int line)
11218 +{
11219 + void *addr = __DWC_DMA_ALLOC(dma_ctx, size, dma_addr);
11220 +
11221 + if (!addr) {
11222 + return NULL;
11223 + }
11224 +
11225 + if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
11226 + __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
11227 + return NULL;
11228 + }
11229 +
11230 + return addr;
11231 +}
11232 +
11233 +void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size,
11234 + dwc_dma_t *dma_addr, char const *func, int line)
11235 +{
11236 + void *addr = __DWC_DMA_ALLOC_ATOMIC(dma_ctx, size, dma_addr);
11237 +
11238 + if (!addr) {
11239 + return NULL;
11240 + }
11241 +
11242 + if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
11243 + __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
11244 + return NULL;
11245 + }
11246 +
11247 + return addr;
11248 +}
11249 +
11250 +void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
11251 + dwc_dma_t dma_addr, char const *func, int line)
11252 +{
11253 + free_allocation(dma_ctx, virt_addr, func, line);
11254 + __DWC_DMA_FREE(dma_ctx, size, virt_addr, dma_addr);
11255 +}
11256 +
11257 +#endif /* DWC_DEBUG_MEMORY */
11258 diff --git a/drivers/usb/host/dwc_common_port/dwc_modpow.c b/drivers/usb/host/dwc_common_port/dwc_modpow.c
11259 new file mode 100644
11260 index 0000000..2004538
11261 --- /dev/null
11262 +++ b/drivers/usb/host/dwc_common_port/dwc_modpow.c
11263 @@ -0,0 +1,636 @@
11264 +/* Bignum routines adapted from PUTTY sources. PuTTY copyright notice follows.
11265 + *
11266 + * PuTTY is copyright 1997-2007 Simon Tatham.
11267 + *
11268 + * Portions copyright Robert de Bath, Joris van Rantwijk, Delian
11269 + * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
11270 + * Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
11271 + * Kuhn, and CORE SDI S.A.
11272 + *
11273 + * Permission is hereby granted, free of charge, to any person
11274 + * obtaining a copy of this software and associated documentation files
11275 + * (the "Software"), to deal in the Software without restriction,
11276 + * including without limitation the rights to use, copy, modify, merge,
11277 + * publish, distribute, sublicense, and/or sell copies of the Software,
11278 + * and to permit persons to whom the Software is furnished to do so,
11279 + * subject to the following conditions:
11280 + *
11281 + * The above copyright notice and this permission notice shall be
11282 + * included in all copies or substantial portions of the Software.
11283 +
11284 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11285 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
11286 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11287 + * NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
11288 + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
11289 + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
11290 + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11291 + *
11292 + */
11293 +#ifdef DWC_CRYPTOLIB
11294 +
11295 +#ifndef CONFIG_MACH_IPMATE
11296 +
11297 +#include "dwc_modpow.h"
11298 +
11299 +#define BIGNUM_INT_MASK 0xFFFFFFFFUL
11300 +#define BIGNUM_TOP_BIT 0x80000000UL
11301 +#define BIGNUM_INT_BITS 32
11302 +
11303 +
11304 +static void *snmalloc(void *mem_ctx, size_t n, size_t size)
11305 +{
11306 + void *p;
11307 + size *= n;
11308 + if (size == 0) size = 1;
11309 + p = dwc_alloc(mem_ctx, size);
11310 + return p;
11311 +}
11312 +
11313 +#define snewn(ctx, n, type) ((type *)snmalloc((ctx), (n), sizeof(type)))
11314 +#define sfree dwc_free
11315 +
11316 +/*
11317 + * Usage notes:
11318 + * * Do not call the DIVMOD_WORD macro with expressions such as array
11319 + * subscripts, as some implementations object to this (see below).
11320 + * * Note that none of the division methods below will cope if the
11321 + * quotient won't fit into BIGNUM_INT_BITS. Callers should be careful
11322 + * to avoid this case.
11323 + * If this condition occurs, in the case of the x86 DIV instruction,
11324 + * an overflow exception will occur, which (according to a correspondent)
11325 + * will manifest on Windows as something like
11326 + * 0xC0000095: Integer overflow
11327 + * The C variant won't give the right answer, either.
11328 + */
11329 +
11330 +#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
11331 +
11332 +#if defined __GNUC__ && defined __i386__
11333 +#define DIVMOD_WORD(q, r, hi, lo, w) \
11334 + __asm__("div %2" : \
11335 + "=d" (r), "=a" (q) : \
11336 + "r" (w), "d" (hi), "a" (lo))
11337 +#else
11338 +#define DIVMOD_WORD(q, r, hi, lo, w) do { \
11339 + BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
11340 + q = n / w; \
11341 + r = n % w; \
11342 +} while (0)
11343 +#endif
11344 +
11345 +// q = n / w;
11346 +// r = n % w;
11347 +
11348 +#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
11349 +
11350 +#define BIGNUM_INTERNAL
11351 +
11352 +static Bignum newbn(void *mem_ctx, int length)
11353 +{
11354 + Bignum b = snewn(mem_ctx, length + 1, BignumInt);
11355 + //if (!b)
11356 + //abort(); /* FIXME */
11357 + DWC_MEMSET(b, 0, (length + 1) * sizeof(*b));
11358 + b[0] = length;
11359 + return b;
11360 +}
11361 +
11362 +void freebn(void *mem_ctx, Bignum b)
11363 +{
11364 + /*
11365 + * Burn the evidence, just in case.
11366 + */
11367 + DWC_MEMSET(b, 0, sizeof(b[0]) * (b[0] + 1));
11368 + sfree(mem_ctx, b);
11369 +}
11370 +
11371 +/*
11372 + * Compute c = a * b.
11373 + * Input is in the first len words of a and b.
11374 + * Result is returned in the first 2*len words of c.
11375 + */
11376 +static void internal_mul(BignumInt *a, BignumInt *b,
11377 + BignumInt *c, int len)
11378 +{
11379 + int i, j;
11380 + BignumDblInt t;
11381 +
11382 + for (j = 0; j < 2 * len; j++)
11383 + c[j] = 0;
11384 +
11385 + for (i = len - 1; i >= 0; i--) {
11386 + t = 0;
11387 + for (j = len - 1; j >= 0; j--) {
11388 + t += MUL_WORD(a[i], (BignumDblInt) b[j]);
11389 + t += (BignumDblInt) c[i + j + 1];
11390 + c[i + j + 1] = (BignumInt) t;
11391 + t = t >> BIGNUM_INT_BITS;
11392 + }
11393 + c[i] = (BignumInt) t;
11394 + }
11395 +}
11396 +
11397 +static void internal_add_shifted(BignumInt *number,
11398 + unsigned n, int shift)
11399 +{
11400 + int word = 1 + (shift / BIGNUM_INT_BITS);
11401 + int bshift = shift % BIGNUM_INT_BITS;
11402 + BignumDblInt addend;
11403 +
11404 + addend = (BignumDblInt)n << bshift;
11405 +
11406 + while (addend) {
11407 + addend += number[word];
11408 + number[word] = (BignumInt) addend & BIGNUM_INT_MASK;
11409 + addend >>= BIGNUM_INT_BITS;
11410 + word++;
11411 + }
11412 +}
11413 +
11414 +/*
11415 + * Compute a = a % m.
11416 + * Input in first alen words of a and first mlen words of m.
11417 + * Output in first alen words of a
11418 + * (of which first alen-mlen words will be zero).
11419 + * The MSW of m MUST have its high bit set.
11420 + * Quotient is accumulated in the `quotient' array, which is a Bignum
11421 + * rather than the internal bigendian format. Quotient parts are shifted
11422 + * left by `qshift' before adding into quot.
11423 + */
11424 +static void internal_mod(BignumInt *a, int alen,
11425 + BignumInt *m, int mlen,
11426 + BignumInt *quot, int qshift)
11427 +{
11428 + BignumInt m0, m1;
11429 + unsigned int h;
11430 + int i, k;
11431 +
11432 + m0 = m[0];
11433 + if (mlen > 1)
11434 + m1 = m[1];
11435 + else
11436 + m1 = 0;
11437 +
11438 + for (i = 0; i <= alen - mlen; i++) {
11439 + BignumDblInt t;
11440 + unsigned int q, r, c, ai1;
11441 +
11442 + if (i == 0) {
11443 + h = 0;
11444 + } else {
11445 + h = a[i - 1];
11446 + a[i - 1] = 0;
11447 + }
11448 +
11449 + if (i == alen - 1)
11450 + ai1 = 0;
11451 + else
11452 + ai1 = a[i + 1];
11453 +
11454 + /* Find q = h:a[i] / m0 */
11455 + if (h >= m0) {
11456 + /*
11457 + * Special case.
11458 + *
11459 + * To illustrate it, suppose a BignumInt is 8 bits, and
11460 + * we are dividing (say) A1:23:45:67 by A1:B2:C3. Then
11461 + * our initial division will be 0xA123 / 0xA1, which
11462 + * will give a quotient of 0x100 and a divide overflow.
11463 + * However, the invariants in this division algorithm
11464 + * are not violated, since the full number A1:23:... is
11465 + * _less_ than the quotient prefix A1:B2:... and so the
11466 + * following correction loop would have sorted it out.
11467 + *
11468 + * In this situation we set q to be the largest
11469 + * quotient we _can_ stomach (0xFF, of course).
11470 + */
11471 + q = BIGNUM_INT_MASK;
11472 + } else {
11473 + /* Macro doesn't want an array subscript expression passed
11474 + * into it (see definition), so use a temporary. */
11475 + BignumInt tmplo = a[i];
11476 + DIVMOD_WORD(q, r, h, tmplo, m0);
11477 +
11478 + /* Refine our estimate of q by looking at
11479 + h:a[i]:a[i+1] / m0:m1 */
11480 + t = MUL_WORD(m1, q);
11481 + if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) {
11482 + q--;
11483 + t -= m1;
11484 + r = (r + m0) & BIGNUM_INT_MASK; /* overflow? */
11485 + if (r >= (BignumDblInt) m0 &&
11486 + t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--;
11487 + }
11488 + }
11489 +
11490 + /* Subtract q * m from a[i...] */
11491 + c = 0;
11492 + for (k = mlen - 1; k >= 0; k--) {
11493 + t = MUL_WORD(q, m[k]);
11494 + t += c;
11495 + c = (unsigned)(t >> BIGNUM_INT_BITS);
11496 + if ((BignumInt) t > a[i + k])
11497 + c++;
11498 + a[i + k] -= (BignumInt) t;
11499 + }
11500 +
11501 + /* Add back m in case of borrow */
11502 + if (c != h) {
11503 + t = 0;
11504 + for (k = mlen - 1; k >= 0; k--) {
11505 + t += m[k];
11506 + t += a[i + k];
11507 + a[i + k] = (BignumInt) t;
11508 + t = t >> BIGNUM_INT_BITS;
11509 + }
11510 + q--;
11511 + }
11512 + if (quot)
11513 + internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i));
11514 + }
11515 +}
11516 +
11517 +/*
11518 + * Compute p % mod.
11519 + * The most significant word of mod MUST be non-zero.
11520 + * We assume that the result array is the same size as the mod array.
11521 + * We optionally write out a quotient if `quotient' is non-NULL.
11522 + * We can avoid writing out the result if `result' is NULL.
11523 + */
11524 +void bigdivmod(void *mem_ctx, Bignum p, Bignum mod, Bignum result, Bignum quotient)
11525 +{
11526 + BignumInt *n, *m;
11527 + int mshift;
11528 + int plen, mlen, i, j;
11529 +
11530 + /* Allocate m of size mlen, copy mod to m */
11531 + /* We use big endian internally */
11532 + mlen = mod[0];
11533 + m = snewn(mem_ctx, mlen, BignumInt);
11534 + //if (!m)
11535 + //abort(); /* FIXME */
11536 + for (j = 0; j < mlen; j++)
11537 + m[j] = mod[mod[0] - j];
11538 +
11539 + /* Shift m left to make msb bit set */
11540 + for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++)
11541 + if ((m[0] << mshift) & BIGNUM_TOP_BIT)
11542 + break;
11543 + if (mshift) {
11544 + for (i = 0; i < mlen - 1; i++)
11545 + m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift));
11546 + m[mlen - 1] = m[mlen - 1] << mshift;
11547 + }
11548 +
11549 + plen = p[0];
11550 + /* Ensure plen > mlen */
11551 + if (plen <= mlen)
11552 + plen = mlen + 1;
11553 +
11554 + /* Allocate n of size plen, copy p to n */
11555 + n = snewn(mem_ctx, plen, BignumInt);
11556 + //if (!n)
11557 + //abort(); /* FIXME */
11558 + for (j = 0; j < plen; j++)
11559 + n[j] = 0;
11560 + for (j = 1; j <= (int)p[0]; j++)
11561 + n[plen - j] = p[j];
11562 +
11563 + /* Main computation */
11564 + internal_mod(n, plen, m, mlen, quotient, mshift);
11565 +
11566 + /* Fixup result in case the modulus was shifted */
11567 + if (mshift) {
11568 + for (i = plen - mlen - 1; i < plen - 1; i++)
11569 + n[i] = (n[i] << mshift) | (n[i + 1] >> (BIGNUM_INT_BITS - mshift));
11570 + n[plen - 1] = n[plen - 1] << mshift;
11571 + internal_mod(n, plen, m, mlen, quotient, 0);
11572 + for (i = plen - 1; i >= plen - mlen; i--)
11573 + n[i] = (n[i] >> mshift) | (n[i - 1] << (BIGNUM_INT_BITS - mshift));
11574 + }
11575 +
11576 + /* Copy result to buffer */
11577 + if (result) {
11578 + for (i = 1; i <= (int)result[0]; i++) {
11579 + int j = plen - i;
11580 + result[i] = j >= 0 ? n[j] : 0;
11581 + }
11582 + }
11583 +
11584 + /* Free temporary arrays */
11585 + for (i = 0; i < mlen; i++)
11586 + m[i] = 0;
11587 + sfree(mem_ctx, m);
11588 + for (i = 0; i < plen; i++)
11589 + n[i] = 0;
11590 + sfree(mem_ctx, n);
11591 +}
11592 +
11593 +/*
11594 + * Simple remainder.
11595 + */
11596 +Bignum bigmod(void *mem_ctx, Bignum a, Bignum b)
11597 +{
11598 + Bignum r = newbn(mem_ctx, b[0]);
11599 + bigdivmod(mem_ctx, a, b, r, NULL);
11600 + return r;
11601 +}
11602 +
11603 +/*
11604 + * Compute (base ^ exp) % mod.
11605 + */
11606 +Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod)
11607 +{
11608 + BignumInt *a, *b, *n, *m;
11609 + int mshift;
11610 + int mlen, i, j;
11611 + Bignum base, result;
11612 +
11613 + /*
11614 + * The most significant word of mod needs to be non-zero. It
11615 + * should already be, but let's make sure.
11616 + */
11617 + //assert(mod[mod[0]] != 0);
11618 +
11619 + /*
11620 + * Make sure the base is smaller than the modulus, by reducing
11621 + * it modulo the modulus if not.
11622 + */
11623 + base = bigmod(mem_ctx, base_in, mod);
11624 +
11625 + /* Allocate m of size mlen, copy mod to m */
11626 + /* We use big endian internally */
11627 + mlen = mod[0];
11628 + m = snewn(mem_ctx, mlen, BignumInt);
11629 + //if (!m)
11630 + //abort(); /* FIXME */
11631 + for (j = 0; j < mlen; j++)
11632 + m[j] = mod[mod[0] - j];
11633 +
11634 + /* Shift m left to make msb bit set */
11635 + for (mshift = 0; mshift < BIGNUM_INT_BITS - 1; mshift++)
11636 + if ((m[0] << mshift) & BIGNUM_TOP_BIT)
11637 + break;
11638 + if (mshift) {
11639 + for (i = 0; i < mlen - 1; i++)
11640 + m[i] =
11641 + (m[i] << mshift) | (m[i + 1] >>
11642 + (BIGNUM_INT_BITS - mshift));
11643 + m[mlen - 1] = m[mlen - 1] << mshift;
11644 + }
11645 +
11646 + /* Allocate n of size mlen, copy base to n */
11647 + n = snewn(mem_ctx, mlen, BignumInt);
11648 + //if (!n)
11649 + //abort(); /* FIXME */
11650 + i = mlen - base[0];
11651 + for (j = 0; j < i; j++)
11652 + n[j] = 0;
11653 + for (j = 0; j < base[0]; j++)
11654 + n[i + j] = base[base[0] - j];
11655 +
11656 + /* Allocate a and b of size 2*mlen. Set a = 1 */
11657 + a = snewn(mem_ctx, 2 * mlen, BignumInt);
11658 + //if (!a)
11659 + //abort(); /* FIXME */
11660 + b = snewn(mem_ctx, 2 * mlen, BignumInt);
11661 + //if (!b)
11662 + //abort(); /* FIXME */
11663 + for (i = 0; i < 2 * mlen; i++)
11664 + a[i] = 0;
11665 + a[2 * mlen - 1] = 1;
11666 +
11667 + /* Skip leading zero bits of exp. */
11668 + i = 0;
11669 + j = BIGNUM_INT_BITS - 1;
11670 + while (i < exp[0] && (exp[exp[0] - i] & (1 << j)) == 0) {
11671 + j--;
11672 + if (j < 0) {
11673 + i++;
11674 + j = BIGNUM_INT_BITS - 1;
11675 + }
11676 + }
11677 +
11678 + /* Main computation */
11679 + while (i < exp[0]) {
11680 + while (j >= 0) {
11681 + internal_mul(a + mlen, a + mlen, b, mlen);
11682 + internal_mod(b, mlen * 2, m, mlen, NULL, 0);
11683 + if ((exp[exp[0] - i] & (1 << j)) != 0) {
11684 + internal_mul(b + mlen, n, a, mlen);
11685 + internal_mod(a, mlen * 2, m, mlen, NULL, 0);
11686 + } else {
11687 + BignumInt *t;
11688 + t = a;
11689 + a = b;
11690 + b = t;
11691 + }
11692 + j--;
11693 + }
11694 + i++;
11695 + j = BIGNUM_INT_BITS - 1;
11696 + }
11697 +
11698 + /* Fixup result in case the modulus was shifted */
11699 + if (mshift) {
11700 + for (i = mlen - 1; i < 2 * mlen - 1; i++)
11701 + a[i] =
11702 + (a[i] << mshift) | (a[i + 1] >>
11703 + (BIGNUM_INT_BITS - mshift));
11704 + a[2 * mlen - 1] = a[2 * mlen - 1] << mshift;
11705 + internal_mod(a, mlen * 2, m, mlen, NULL, 0);
11706 + for (i = 2 * mlen - 1; i >= mlen; i--)
11707 + a[i] =
11708 + (a[i] >> mshift) | (a[i - 1] <<
11709 + (BIGNUM_INT_BITS - mshift));
11710 + }
11711 +
11712 + /* Copy result to buffer */
11713 + result = newbn(mem_ctx, mod[0]);
11714 + for (i = 0; i < mlen; i++)
11715 + result[result[0] - i] = a[i + mlen];
11716 + while (result[0] > 1 && result[result[0]] == 0)
11717 + result[0]--;
11718 +
11719 + /* Free temporary arrays */
11720 + for (i = 0; i < 2 * mlen; i++)
11721 + a[i] = 0;
11722 + sfree(mem_ctx, a);
11723 + for (i = 0; i < 2 * mlen; i++)
11724 + b[i] = 0;
11725 + sfree(mem_ctx, b);
11726 + for (i = 0; i < mlen; i++)
11727 + m[i] = 0;
11728 + sfree(mem_ctx, m);
11729 + for (i = 0; i < mlen; i++)
11730 + n[i] = 0;
11731 + sfree(mem_ctx, n);
11732 +
11733 + freebn(mem_ctx, base);
11734 +
11735 + return result;
11736 +}
11737 +
11738 +
11739 +#ifdef UNITTEST
11740 +
11741 +static __u32 dh_p[] = {
11742 + 96,
11743 + 0xFFFFFFFF,
11744 + 0xFFFFFFFF,
11745 + 0xA93AD2CA,
11746 + 0x4B82D120,
11747 + 0xE0FD108E,
11748 + 0x43DB5BFC,
11749 + 0x74E5AB31,
11750 + 0x08E24FA0,
11751 + 0xBAD946E2,
11752 + 0x770988C0,
11753 + 0x7A615D6C,
11754 + 0xBBE11757,
11755 + 0x177B200C,
11756 + 0x521F2B18,
11757 + 0x3EC86A64,
11758 + 0xD8760273,
11759 + 0xD98A0864,
11760 + 0xF12FFA06,
11761 + 0x1AD2EE6B,
11762 + 0xCEE3D226,
11763 + 0x4A25619D,
11764 + 0x1E8C94E0,
11765 + 0xDB0933D7,
11766 + 0xABF5AE8C,
11767 + 0xA6E1E4C7,
11768 + 0xB3970F85,
11769 + 0x5D060C7D,
11770 + 0x8AEA7157,
11771 + 0x58DBEF0A,
11772 + 0xECFB8504,
11773 + 0xDF1CBA64,
11774 + 0xA85521AB,
11775 + 0x04507A33,
11776 + 0xAD33170D,
11777 + 0x8AAAC42D,
11778 + 0x15728E5A,
11779 + 0x98FA0510,
11780 + 0x15D22618,
11781 + 0xEA956AE5,
11782 + 0x3995497C,
11783 + 0x95581718,
11784 + 0xDE2BCBF6,
11785 + 0x6F4C52C9,
11786 + 0xB5C55DF0,
11787 + 0xEC07A28F,
11788 + 0x9B2783A2,
11789 + 0x180E8603,
11790 + 0xE39E772C,
11791 + 0x2E36CE3B,
11792 + 0x32905E46,
11793 + 0xCA18217C,
11794 + 0xF1746C08,
11795 + 0x4ABC9804,
11796 + 0x670C354E,
11797 + 0x7096966D,
11798 + 0x9ED52907,
11799 + 0x208552BB,
11800 + 0x1C62F356,
11801 + 0xDCA3AD96,
11802 + 0x83655D23,
11803 + 0xFD24CF5F,
11804 + 0x69163FA8,
11805 + 0x1C55D39A,
11806 + 0x98DA4836,
11807 + 0xA163BF05,
11808 + 0xC2007CB8,
11809 + 0xECE45B3D,
11810 + 0x49286651,
11811 + 0x7C4B1FE6,
11812 + 0xAE9F2411,
11813 + 0x5A899FA5,
11814 + 0xEE386BFB,
11815 + 0xF406B7ED,
11816 + 0x0BFF5CB6,
11817 + 0xA637ED6B,
11818 + 0xF44C42E9,
11819 + 0x625E7EC6,
11820 + 0xE485B576,
11821 + 0x6D51C245,
11822 + 0x4FE1356D,
11823 + 0xF25F1437,
11824 + 0x302B0A6D,
11825 + 0xCD3A431B,
11826 + 0xEF9519B3,
11827 + 0x8E3404DD,
11828 + 0x514A0879,
11829 + 0x3B139B22,
11830 + 0x020BBEA6,
11831 + 0x8A67CC74,
11832 + 0x29024E08,
11833 + 0x80DC1CD1,
11834 + 0xC4C6628B,
11835 + 0x2168C234,
11836 + 0xC90FDAA2,
11837 + 0xFFFFFFFF,
11838 + 0xFFFFFFFF,
11839 +};
11840 +
11841 +static __u32 dh_a[] = {
11842 + 8,
11843 + 0xdf367516,
11844 + 0x86459caa,
11845 + 0xe2d459a4,
11846 + 0xd910dae0,
11847 + 0x8a8b5e37,
11848 + 0x67ab31c6,
11849 + 0xf0b55ea9,
11850 + 0x440051d6,
11851 +};
11852 +
11853 +static __u32 dh_b[] = {
11854 + 8,
11855 + 0xded92656,
11856 + 0xe07a048a,
11857 + 0x6fa452cd,
11858 + 0x2df89d30,
11859 + 0xc75f1b0f,
11860 + 0x8ce3578f,
11861 + 0x7980a324,
11862 + 0x5daec786,
11863 +};
11864 +
11865 +static __u32 dh_g[] = {
11866 + 1,
11867 + 2,
11868 +};
11869 +
11870 +int main(void)
11871 +{
11872 + int i;
11873 + __u32 *k;
11874 + k = dwc_modpow(NULL, dh_g, dh_a, dh_p);
11875 +
11876 + printf("\n\n");
11877 + for (i=0; i<k[0]; i++) {
11878 + __u32 word32 = k[k[0] - i];
11879 + __u16 l = word32 & 0xffff;
11880 + __u16 m = (word32 & 0xffff0000) >> 16;
11881 + printf("%04x %04x ", m, l);
11882 + if (!((i + 1)%13)) printf("\n");
11883 + }
11884 + printf("\n\n");
11885 +
11886 + if ((k[0] == 0x60) && (k[1] == 0x28e490e5) && (k[0x60] == 0x5a0d3d4e)) {
11887 + printf("PASS\n\n");
11888 + }
11889 + else {
11890 + printf("FAIL\n\n");
11891 + }
11892 +
11893 +}
11894 +
11895 +#endif /* UNITTEST */
11896 +
11897 +#endif /* CONFIG_MACH_IPMATE */
11898 +
11899 +#endif /*DWC_CRYPTOLIB */
11900 diff --git a/drivers/usb/host/dwc_common_port/dwc_modpow.h b/drivers/usb/host/dwc_common_port/dwc_modpow.h
11901 new file mode 100644
11902 index 0000000..64f00c2
11903 --- /dev/null
11904 +++ b/drivers/usb/host/dwc_common_port/dwc_modpow.h
11905 @@ -0,0 +1,34 @@
11906 +/*
11907 + * dwc_modpow.h
11908 + * See dwc_modpow.c for license and changes
11909 + */
11910 +#ifndef _DWC_MODPOW_H
11911 +#define _DWC_MODPOW_H
11912 +
11913 +#ifdef __cplusplus
11914 +extern "C" {
11915 +#endif
11916 +
11917 +#include "dwc_os.h"
11918 +
11919 +/** @file
11920 + *
11921 + * This file defines the module exponentiation function which is only used
11922 + * internally by the DWC UWB modules for calculation of PKs during numeric
11923 + * association. The routine is taken from the PUTTY, an open source terminal
11924 + * emulator. The PUTTY License is preserved in the dwc_modpow.c file.
11925 + *
11926 + */
11927 +
11928 +typedef uint32_t BignumInt;
11929 +typedef uint64_t BignumDblInt;
11930 +typedef BignumInt *Bignum;
11931 +
11932 +/* Compute modular exponentiaion */
11933 +extern Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod);
11934 +
11935 +#ifdef __cplusplus
11936 +}
11937 +#endif
11938 +
11939 +#endif /* _LINUX_BIGNUM_H */
11940 diff --git a/drivers/usb/host/dwc_common_port/dwc_notifier.c b/drivers/usb/host/dwc_common_port/dwc_notifier.c
11941 new file mode 100644
11942 index 0000000..8b3772a
11943 --- /dev/null
11944 +++ b/drivers/usb/host/dwc_common_port/dwc_notifier.c
11945 @@ -0,0 +1,319 @@
11946 +#ifdef DWC_NOTIFYLIB
11947 +
11948 +#include "dwc_notifier.h"
11949 +#include "dwc_list.h"
11950 +
11951 +typedef struct dwc_observer {
11952 + void *observer;
11953 + dwc_notifier_callback_t callback;
11954 + void *data;
11955 + char *notification;
11956 + DWC_CIRCLEQ_ENTRY(dwc_observer) list_entry;
11957 +} observer_t;
11958 +
11959 +DWC_CIRCLEQ_HEAD(observer_queue, dwc_observer);
11960 +
11961 +typedef struct dwc_notifier {
11962 + void *mem_ctx;
11963 + void *object;
11964 + struct observer_queue observers;
11965 + DWC_CIRCLEQ_ENTRY(dwc_notifier) list_entry;
11966 +} notifier_t;
11967 +
11968 +DWC_CIRCLEQ_HEAD(notifier_queue, dwc_notifier);
11969 +
11970 +typedef struct manager {
11971 + void *mem_ctx;
11972 + void *wkq_ctx;
11973 + dwc_workq_t *wq;
11974 +// dwc_mutex_t *mutex;
11975 + struct notifier_queue notifiers;
11976 +} manager_t;
11977 +
11978 +static manager_t *manager = NULL;
11979 +
11980 +static int create_manager(void *mem_ctx, void *wkq_ctx)
11981 +{
11982 + manager = dwc_alloc(mem_ctx, sizeof(manager_t));
11983 + if (!manager) {
11984 + return -DWC_E_NO_MEMORY;
11985 + }
11986 +
11987 + DWC_CIRCLEQ_INIT(&manager->notifiers);
11988 +
11989 + manager->wq = dwc_workq_alloc(wkq_ctx, "DWC Notification WorkQ");
11990 + if (!manager->wq) {
11991 + return -DWC_E_NO_MEMORY;
11992 + }
11993 +
11994 + return 0;
11995 +}
11996 +
11997 +static void free_manager(void)
11998 +{
11999 + dwc_workq_free(manager->wq);
12000 +
12001 + /* All notifiers must have unregistered themselves before this module
12002 + * can be removed. Hitting this assertion indicates a programmer
12003 + * error. */
12004 + DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&manager->notifiers),
12005 + "Notification manager being freed before all notifiers have been removed");
12006 + dwc_free(manager->mem_ctx, manager);
12007 +}
12008 +
12009 +#ifdef DEBUG
12010 +static void dump_manager(void)
12011 +{
12012 + notifier_t *n;
12013 + observer_t *o;
12014 +
12015 + DWC_ASSERT(manager, "Notification manager not found");
12016 +
12017 + DWC_DEBUG("List of all notifiers and observers:\n");
12018 + DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
12019 + DWC_DEBUG("Notifier %p has observers:\n", n->object);
12020 + DWC_CIRCLEQ_FOREACH(o, &n->observers, list_entry) {
12021 + DWC_DEBUG(" %p watching %s\n", o->observer, o->notification);
12022 + }
12023 + }
12024 +}
12025 +#else
12026 +#define dump_manager(...)
12027 +#endif
12028 +
12029 +static observer_t *alloc_observer(void *mem_ctx, void *observer, char *notification,
12030 + dwc_notifier_callback_t callback, void *data)
12031 +{
12032 + observer_t *new_observer = dwc_alloc(mem_ctx, sizeof(observer_t));
12033 +
12034 + if (!new_observer) {
12035 + return NULL;
12036 + }
12037 +
12038 + DWC_CIRCLEQ_INIT_ENTRY(new_observer, list_entry);
12039 + new_observer->observer = observer;
12040 + new_observer->notification = notification;
12041 + new_observer->callback = callback;
12042 + new_observer->data = data;
12043 + return new_observer;
12044 +}
12045 +
12046 +static void free_observer(void *mem_ctx, observer_t *observer)
12047 +{
12048 + dwc_free(mem_ctx, observer);
12049 +}
12050 +
12051 +static notifier_t *alloc_notifier(void *mem_ctx, void *object)
12052 +{
12053 + notifier_t *notifier;
12054 +
12055 + if (!object) {
12056 + return NULL;
12057 + }
12058 +
12059 + notifier = dwc_alloc(mem_ctx, sizeof(notifier_t));
12060 + if (!notifier) {
12061 + return NULL;
12062 + }
12063 +
12064 + DWC_CIRCLEQ_INIT(&notifier->observers);
12065 + DWC_CIRCLEQ_INIT_ENTRY(notifier, list_entry);
12066 +
12067 + notifier->mem_ctx = mem_ctx;
12068 + notifier->object = object;
12069 + return notifier;
12070 +}
12071 +
12072 +static void free_notifier(notifier_t *notifier)
12073 +{
12074 + observer_t *observer;
12075 +
12076 + DWC_CIRCLEQ_FOREACH(observer, &notifier->observers, list_entry) {
12077 + free_observer(notifier->mem_ctx, observer);
12078 + }
12079 +
12080 + dwc_free(notifier->mem_ctx, notifier);
12081 +}
12082 +
12083 +static notifier_t *find_notifier(void *object)
12084 +{
12085 + notifier_t *notifier;
12086 +
12087 + DWC_ASSERT(manager, "Notification manager not found");
12088 +
12089 + if (!object) {
12090 + return NULL;
12091 + }
12092 +
12093 + DWC_CIRCLEQ_FOREACH(notifier, &manager->notifiers, list_entry) {
12094 + if (notifier->object == object) {
12095 + return notifier;
12096 + }
12097 + }
12098 +
12099 + return NULL;
12100 +}
12101 +
12102 +int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx)
12103 +{
12104 + return create_manager(mem_ctx, wkq_ctx);
12105 +}
12106 +
12107 +void dwc_free_notification_manager(void)
12108 +{
12109 + free_manager();
12110 +}
12111 +
12112 +dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object)
12113 +{
12114 + notifier_t *notifier;
12115 +
12116 + DWC_ASSERT(manager, "Notification manager not found");
12117 +
12118 + notifier = find_notifier(object);
12119 + if (notifier) {
12120 + DWC_ERROR("Notifier %p is already registered\n", object);
12121 + return NULL;
12122 + }
12123 +
12124 + notifier = alloc_notifier(mem_ctx, object);
12125 + if (!notifier) {
12126 + return NULL;
12127 + }
12128 +
12129 + DWC_CIRCLEQ_INSERT_TAIL(&manager->notifiers, notifier, list_entry);
12130 +
12131 + DWC_INFO("Notifier %p registered", object);
12132 + dump_manager();
12133 +
12134 + return notifier;
12135 +}
12136 +
12137 +void dwc_unregister_notifier(dwc_notifier_t *notifier)
12138 +{
12139 + DWC_ASSERT(manager, "Notification manager not found");
12140 +
12141 + if (!DWC_CIRCLEQ_EMPTY(&notifier->observers)) {
12142 + observer_t *o;
12143 +
12144 + DWC_ERROR("Notifier %p has active observers when removing\n", notifier->object);
12145 + DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
12146 + DWC_DEBUGC(" %p watching %s\n", o->observer, o->notification);
12147 + }
12148 +
12149 + DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&notifier->observers),
12150 + "Notifier %p has active observers when removing", notifier);
12151 + }
12152 +
12153 + DWC_CIRCLEQ_REMOVE_INIT(&manager->notifiers, notifier, list_entry);
12154 + free_notifier(notifier);
12155 +
12156 + DWC_INFO("Notifier unregistered");
12157 + dump_manager();
12158 +}
12159 +
12160 +/* Add an observer to observe the notifier for a particular state, event, or notification. */
12161 +int dwc_add_observer(void *observer, void *object, char *notification,
12162 + dwc_notifier_callback_t callback, void *data)
12163 +{
12164 + notifier_t *notifier = find_notifier(object);
12165 + observer_t *new_observer;
12166 +
12167 + if (!notifier) {
12168 + DWC_ERROR("Notifier %p is not found when adding observer\n", object);
12169 + return -DWC_E_INVALID;
12170 + }
12171 +
12172 + new_observer = alloc_observer(notifier->mem_ctx, observer, notification, callback, data);
12173 + if (!new_observer) {
12174 + return -DWC_E_NO_MEMORY;
12175 + }
12176 +
12177 + DWC_CIRCLEQ_INSERT_TAIL(&notifier->observers, new_observer, list_entry);
12178 +
12179 + DWC_INFO("Added observer %p to notifier %p observing notification %s, callback=%p, data=%p",
12180 + observer, object, notification, callback, data);
12181 +
12182 + dump_manager();
12183 + return 0;
12184 +}
12185 +
12186 +int dwc_remove_observer(void *observer)
12187 +{
12188 + notifier_t *n;
12189 +
12190 + DWC_ASSERT(manager, "Notification manager not found");
12191 +
12192 + DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
12193 + observer_t *o;
12194 + observer_t *o2;
12195 +
12196 + DWC_CIRCLEQ_FOREACH_SAFE(o, o2, &n->observers, list_entry) {
12197 + if (o->observer == observer) {
12198 + DWC_CIRCLEQ_REMOVE_INIT(&n->observers, o, list_entry);
12199 + DWC_INFO("Removing observer %p from notifier %p watching notification %s:",
12200 + o->observer, n->object, o->notification);
12201 + free_observer(n->mem_ctx, o);
12202 + }
12203 + }
12204 + }
12205 +
12206 + dump_manager();
12207 + return 0;
12208 +}
12209 +
12210 +typedef struct callback_data {
12211 + void *mem_ctx;
12212 + dwc_notifier_callback_t cb;
12213 + void *observer;
12214 + void *data;
12215 + void *object;
12216 + char *notification;
12217 + void *notification_data;
12218 +} cb_data_t;
12219 +
12220 +static void cb_task(void *data)
12221 +{
12222 + cb_data_t *cb = (cb_data_t *)data;
12223 +
12224 + cb->cb(cb->object, cb->notification, cb->observer, cb->notification_data, cb->data);
12225 + dwc_free(cb->mem_ctx, cb);
12226 +}
12227 +
12228 +void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data)
12229 +{
12230 + observer_t *o;
12231 +
12232 + DWC_ASSERT(manager, "Notification manager not found");
12233 +
12234 + DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
12235 + int len = DWC_STRLEN(notification);
12236 +
12237 + if (DWC_STRLEN(o->notification) != len) {
12238 + continue;
12239 + }
12240 +
12241 + if (DWC_STRNCMP(o->notification, notification, len) == 0) {
12242 + cb_data_t *cb_data = dwc_alloc(notifier->mem_ctx, sizeof(cb_data_t));
12243 +
12244 + if (!cb_data) {
12245 + DWC_ERROR("Failed to allocate callback data\n");
12246 + return;
12247 + }
12248 +
12249 + cb_data->mem_ctx = notifier->mem_ctx;
12250 + cb_data->cb = o->callback;
12251 + cb_data->observer = o->observer;
12252 + cb_data->data = o->data;
12253 + cb_data->object = notifier->object;
12254 + cb_data->notification = notification;
12255 + cb_data->notification_data = notification_data;
12256 + DWC_DEBUGC("Observer found %p for notification %s\n", o->observer, notification);
12257 + DWC_WORKQ_SCHEDULE(manager->wq, cb_task, cb_data,
12258 + "Notify callback from %p for Notification %s, to observer %p",
12259 + cb_data->object, notification, cb_data->observer);
12260 + }
12261 + }
12262 +}
12263 +
12264 +#endif /* DWC_NOTIFYLIB */
12265 diff --git a/drivers/usb/host/dwc_common_port/dwc_notifier.h b/drivers/usb/host/dwc_common_port/dwc_notifier.h
12266 new file mode 100644
12267 index 0000000..4a8cdfe
12268 --- /dev/null
12269 +++ b/drivers/usb/host/dwc_common_port/dwc_notifier.h
12270 @@ -0,0 +1,122 @@
12271 +
12272 +#ifndef __DWC_NOTIFIER_H__
12273 +#define __DWC_NOTIFIER_H__
12274 +
12275 +#ifdef __cplusplus
12276 +extern "C" {
12277 +#endif
12278 +
12279 +#include "dwc_os.h"
12280 +
12281 +/** @file
12282 + *
12283 + * A simple implementation of the Observer pattern. Any "module" can
12284 + * register as an observer or notifier. The notion of "module" is abstract and
12285 + * can mean anything used to identify either an observer or notifier. Usually
12286 + * it will be a pointer to a data structure which contains some state, ie an
12287 + * object.
12288 + *
12289 + * Before any notifiers can be added, the global notification manager must be
12290 + * brought up with dwc_alloc_notification_manager().
12291 + * dwc_free_notification_manager() will bring it down and free all resources.
12292 + * These would typically be called upon module load and unload. The
12293 + * notification manager is a single global instance that handles all registered
12294 + * observable modules and observers so this should be done only once.
12295 + *
12296 + * A module can be observable by using Notifications to publicize some general
12297 + * information about it's state or operation. It does not care who listens, or
12298 + * even if anyone listens, or what they do with the information. The observable
12299 + * modules do not need to know any information about it's observers or their
12300 + * interface, or their state or data.
12301 + *
12302 + * Any module can register to emit Notifications. It should publish a list of
12303 + * notifications that it can emit and their behavior, such as when they will get
12304 + * triggered, and what information will be provided to the observer. Then it
12305 + * should register itself as an observable module. See dwc_register_notifier().
12306 + *
12307 + * Any module can observe any observable, registered module, provided it has a
12308 + * handle to the other module and knows what notifications to observe. See
12309 + * dwc_add_observer().
12310 + *
12311 + * A function of type dwc_notifier_callback_t is called whenever a notification
12312 + * is triggered with one or more observers observing it. This function is
12313 + * called in it's own process so it may sleep or block if needed. It is
12314 + * guaranteed to be called sometime after the notification has occurred and will
12315 + * be called once per each time the notification is triggered. It will NOT be
12316 + * called in the same process context used to trigger the notification.
12317 + *
12318 + * @section Limitiations
12319 + *
12320 + * Keep in mind that Notifications that can be triggered in rapid sucession may
12321 + * schedule too many processes too handle. Be aware of this limitation when
12322 + * designing to use notifications, and only add notifications for appropriate
12323 + * observable information.
12324 + *
12325 + * Also Notification callbacks are not synchronous. If you need to synchronize
12326 + * the behavior between module/observer you must use other means. And perhaps
12327 + * that will mean Notifications are not the proper solution.
12328 + */
12329 +
12330 +struct dwc_notifier;
12331 +typedef struct dwc_notifier dwc_notifier_t;
12332 +
12333 +/** The callback function must be of this type.
12334 + *
12335 + * @param object This is the object that is being observed.
12336 + * @param notification This is the notification that was triggered.
12337 + * @param observer This is the observer
12338 + * @param notification_data This is notification-specific data that the notifier
12339 + * has included in this notification. The value of this should be published in
12340 + * the documentation of the observable module with the notifications.
12341 + * @param user_data This is any custom data that the observer provided when
12342 + * adding itself as an observer to the notification. */
12343 +typedef void (*dwc_notifier_callback_t)(void *object, char *notification, void *observer,
12344 + void *notification_data, void *user_data);
12345 +
12346 +/** Brings up the notification manager. */
12347 +extern int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx);
12348 +/** Brings down the notification manager. */
12349 +extern void dwc_free_notification_manager(void);
12350 +
12351 +/** This function registers an observable module. A dwc_notifier_t object is
12352 + * returned to the observable module. This is an opaque object that is used by
12353 + * the observable module to trigger notifications. This object should only be
12354 + * accessible to functions that are authorized to trigger notifications for this
12355 + * module. Observers do not need this object. */
12356 +extern dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object);
12357 +
12358 +/** This function unregisters an observable module. All observers have to be
12359 + * removed prior to unregistration. */
12360 +extern void dwc_unregister_notifier(dwc_notifier_t *notifier);
12361 +
12362 +/** Add a module as an observer to the observable module. The observable module
12363 + * needs to have previously registered with the notification manager.
12364 + *
12365 + * @param observer The observer module
12366 + * @param object The module to observe
12367 + * @param notification The notification to observe
12368 + * @param callback The callback function to call
12369 + * @param user_data Any additional user data to pass into the callback function */
12370 +extern int dwc_add_observer(void *observer, void *object, char *notification,
12371 + dwc_notifier_callback_t callback, void *user_data);
12372 +
12373 +/** Removes the specified observer from all notifications that it is currently
12374 + * observing. */
12375 +extern int dwc_remove_observer(void *observer);
12376 +
12377 +/** This function triggers a Notification. It should be called by the
12378 + * observable module, or any module or library which the observable module
12379 + * allows to trigger notification on it's behalf. Such as the dwc_cc_t.
12380 + *
12381 + * dwc_notify is a non-blocking function. Callbacks are scheduled called in
12382 + * their own process context for each trigger. Callbacks can be blocking.
12383 + * dwc_notify can be called from interrupt context if needed.
12384 + *
12385 + */
12386 +void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data);
12387 +
12388 +#ifdef __cplusplus
12389 +}
12390 +#endif
12391 +
12392 +#endif /* __DWC_NOTIFIER_H__ */
12393 diff --git a/drivers/usb/host/dwc_common_port/dwc_os.h b/drivers/usb/host/dwc_common_port/dwc_os.h
12394 new file mode 100644
12395 index 0000000..9ffe929
12396 --- /dev/null
12397 +++ b/drivers/usb/host/dwc_common_port/dwc_os.h
12398 @@ -0,0 +1,1260 @@
12399 +/* =========================================================================
12400 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_os.h $
12401 + * $Revision: #14 $
12402 + * $Date: 2010/11/04 $
12403 + * $Change: 1621695 $
12404 + *
12405 + * Synopsys Portability Library Software and documentation
12406 + * (hereinafter, "Software") is an Unsupported proprietary work of
12407 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
12408 + * between Synopsys and you.
12409 + *
12410 + * The Software IS NOT an item of Licensed Software or Licensed Product
12411 + * under any End User Software License Agreement or Agreement for
12412 + * Licensed Product with Synopsys or any supplement thereto. You are
12413 + * permitted to use and redistribute this Software in source and binary
12414 + * forms, with or without modification, provided that redistributions
12415 + * of source code must retain this notice. You may not view, use,
12416 + * disclose, copy or distribute this file or any information contained
12417 + * herein except pursuant to this license grant from Synopsys. If you
12418 + * do not agree with this notice, including the disclaimer below, then
12419 + * you are not authorized to use the Software.
12420 + *
12421 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
12422 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
12423 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12424 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
12425 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
12426 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
12427 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
12428 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
12429 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12430 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
12431 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
12432 + * DAMAGE.
12433 + * ========================================================================= */
12434 +#ifndef _DWC_OS_H_
12435 +#define _DWC_OS_H_
12436 +
12437 +#ifdef __cplusplus
12438 +extern "C" {
12439 +#endif
12440 +
12441 +/** @file
12442 + *
12443 + * DWC portability library, low level os-wrapper functions
12444 + *
12445 + */
12446 +
12447 +/* These basic types need to be defined by some OS header file or custom header
12448 + * file for your specific target architecture.
12449 + *
12450 + * uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t
12451 + *
12452 + * Any custom or alternate header file must be added and enabled here.
12453 + */
12454 +
12455 +#ifdef DWC_LINUX
12456 +# include <linux/types.h>
12457 +# ifdef CONFIG_DEBUG_MUTEXES
12458 +# include <linux/mutex.h>
12459 +# endif
12460 +# include <linux/errno.h>
12461 +# include <stdarg.h>
12462 +#endif
12463 +
12464 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12465 +# include <os_dep.h>
12466 +#endif
12467 +
12468 +
12469 +/** @name Primitive Types and Values */
12470 +
12471 +/** We define a boolean type for consistency. Can be either YES or NO */
12472 +typedef uint8_t dwc_bool_t;
12473 +#define YES 1
12474 +#define NO 0
12475 +
12476 +#ifdef DWC_LINUX
12477 +
12478 +/** @name Error Codes */
12479 +#define DWC_E_INVALID EINVAL
12480 +#define DWC_E_NO_MEMORY ENOMEM
12481 +#define DWC_E_NO_DEVICE ENODEV
12482 +#define DWC_E_NOT_SUPPORTED EOPNOTSUPP
12483 +#define DWC_E_TIMEOUT ETIMEDOUT
12484 +#define DWC_E_BUSY EBUSY
12485 +#define DWC_E_AGAIN EAGAIN
12486 +#define DWC_E_RESTART ERESTART
12487 +#define DWC_E_ABORT ECONNABORTED
12488 +#define DWC_E_SHUTDOWN ESHUTDOWN
12489 +#define DWC_E_NO_DATA ENODATA
12490 +#define DWC_E_DISCONNECT ECONNRESET
12491 +#define DWC_E_UNKNOWN EINVAL
12492 +#define DWC_E_NO_STREAM_RES ENOSR
12493 +#define DWC_E_COMMUNICATION ECOMM
12494 +#define DWC_E_OVERFLOW EOVERFLOW
12495 +#define DWC_E_PROTOCOL EPROTO
12496 +#define DWC_E_IN_PROGRESS EINPROGRESS
12497 +#define DWC_E_PIPE EPIPE
12498 +#define DWC_E_IO EIO
12499 +#define DWC_E_NO_SPACE ENOSPC
12500 +
12501 +#else
12502 +
12503 +/** @name Error Codes */
12504 +#define DWC_E_INVALID 1001
12505 +#define DWC_E_NO_MEMORY 1002
12506 +#define DWC_E_NO_DEVICE 1003
12507 +#define DWC_E_NOT_SUPPORTED 1004
12508 +#define DWC_E_TIMEOUT 1005
12509 +#define DWC_E_BUSY 1006
12510 +#define DWC_E_AGAIN 1007
12511 +#define DWC_E_RESTART 1008
12512 +#define DWC_E_ABORT 1009
12513 +#define DWC_E_SHUTDOWN 1010
12514 +#define DWC_E_NO_DATA 1011
12515 +#define DWC_E_DISCONNECT 2000
12516 +#define DWC_E_UNKNOWN 3000
12517 +#define DWC_E_NO_STREAM_RES 4001
12518 +#define DWC_E_COMMUNICATION 4002
12519 +#define DWC_E_OVERFLOW 4003
12520 +#define DWC_E_PROTOCOL 4004
12521 +#define DWC_E_IN_PROGRESS 4005
12522 +#define DWC_E_PIPE 4006
12523 +#define DWC_E_IO 4007
12524 +#define DWC_E_NO_SPACE 4008
12525 +
12526 +#endif
12527 +
12528 +
12529 +/** @name Tracing/Logging Functions
12530 + *
12531 + * These function provide the capability to add tracing, debugging, and error
12532 + * messages, as well exceptions as assertions. The WUDEV uses these
12533 + * extensively. These could be logged to the main console, the serial port, an
12534 + * internal buffer, etc. These functions could also be no-op if they are too
12535 + * expensive on your system. By default undefining the DEBUG macro already
12536 + * no-ops some of these functions. */
12537 +
12538 +/** Returns non-zero if in interrupt context. */
12539 +extern dwc_bool_t DWC_IN_IRQ(void);
12540 +#define dwc_in_irq DWC_IN_IRQ
12541 +
12542 +/** Returns "IRQ" if DWC_IN_IRQ is true. */
12543 +static inline char *dwc_irq(void) {
12544 + return DWC_IN_IRQ() ? "IRQ" : "";
12545 +}
12546 +
12547 +/** Returns non-zero if in bottom-half context. */
12548 +extern dwc_bool_t DWC_IN_BH(void);
12549 +#define dwc_in_bh DWC_IN_BH
12550 +
12551 +/** Returns "BH" if DWC_IN_BH is true. */
12552 +static inline char *dwc_bh(void) {
12553 + return DWC_IN_BH() ? "BH" : "";
12554 +}
12555 +
12556 +/**
12557 + * A vprintf() clone. Just call vprintf if you've got it.
12558 + */
12559 +extern void DWC_VPRINTF(char *format, va_list args);
12560 +#define dwc_vprintf DWC_VPRINTF
12561 +
12562 +/**
12563 + * A vsnprintf() clone. Just call vprintf if you've got it.
12564 + */
12565 +extern int DWC_VSNPRINTF(char *str, int size, char *format, va_list args);
12566 +#define dwc_vsnprintf DWC_VSNPRINTF
12567 +
12568 +/**
12569 + * printf() clone. Just call printf if you've go it.
12570 + */
12571 +extern void DWC_PRINTF(char *format, ...)
12572 +/* This provides compiler level static checking of the parameters if you're
12573 + * using GCC. */
12574 +#ifdef __GNUC__
12575 + __attribute__ ((format(printf, 1, 2)));
12576 +#else
12577 + ;
12578 +#endif
12579 +#define dwc_printf DWC_PRINTF
12580 +
12581 +/**
12582 + * sprintf() clone. Just call sprintf if you've got it.
12583 + */
12584 +extern int DWC_SPRINTF(char *string, char *format, ...)
12585 +#ifdef __GNUC__
12586 + __attribute__ ((format(printf, 2, 3)));
12587 +#else
12588 + ;
12589 +#endif
12590 +#define dwc_sprintf DWC_SPRINTF
12591 +
12592 +/**
12593 + * snprintf() clone. Just call snprintf if you've got it.
12594 + */
12595 +extern int DWC_SNPRINTF(char *string, int size, char *format, ...)
12596 +#ifdef __GNUC__
12597 + __attribute__ ((format(printf, 3, 4)));
12598 +#else
12599 + ;
12600 +#endif
12601 +#define dwc_snprintf DWC_SNPRINTF
12602 +
12603 +/**
12604 + * Prints a WARNING message. On systems that don't differentiate between
12605 + * warnings and regular log messages, just print it. Indicates that something
12606 + * may be wrong with the driver. Works like printf().
12607 + *
12608 + * Use the DWC_WARN macro to call this function.
12609 + */
12610 +extern void __DWC_WARN(char *format, ...)
12611 +#ifdef __GNUC__
12612 + __attribute__ ((format(printf, 1, 2)));
12613 +#else
12614 + ;
12615 +#endif
12616 +
12617 +/**
12618 + * Prints an error message. On systems that don't differentiate between errors
12619 + * and regular log messages, just print it. Indicates that something went wrong
12620 + * with the driver. Works like printf().
12621 + *
12622 + * Use the DWC_ERROR macro to call this function.
12623 + */
12624 +extern void __DWC_ERROR(char *format, ...)
12625 +#ifdef __GNUC__
12626 + __attribute__ ((format(printf, 1, 2)));
12627 +#else
12628 + ;
12629 +#endif
12630 +
12631 +/**
12632 + * Prints an exception error message and takes some user-defined action such as
12633 + * print out a backtrace or trigger a breakpoint. Indicates that something went
12634 + * abnormally wrong with the driver such as programmer error, or other
12635 + * exceptional condition. It should not be ignored so even on systems without
12636 + * printing capability, some action should be taken to notify the developer of
12637 + * it. Works like printf().
12638 + */
12639 +extern void DWC_EXCEPTION(char *format, ...)
12640 +#ifdef __GNUC__
12641 + __attribute__ ((format(printf, 1, 2)));
12642 +#else
12643 + ;
12644 +#endif
12645 +#define dwc_exception DWC_EXCEPTION
12646 +
12647 +#ifndef DWC_OTG_DEBUG_LEV
12648 +#define DWC_OTG_DEBUG_LEV 0
12649 +#endif
12650 +
12651 +#ifdef DEBUG
12652 +/**
12653 + * Prints out a debug message. Used for logging/trace messages.
12654 + *
12655 + * Use the DWC_DEBUG macro to call this function
12656 + */
12657 +extern void __DWC_DEBUG(char *format, ...)
12658 +#ifdef __GNUC__
12659 + __attribute__ ((format(printf, 1, 2)));
12660 +#else
12661 + ;
12662 +#endif
12663 +#else
12664 +#define __DWC_DEBUG printk
12665 +#endif
12666 +
12667 +/**
12668 + * Prints out a Debug message.
12669 + */
12670 +#define DWC_DEBUG(_format, _args...) __DWC_DEBUG("DEBUG:%s:%s: " _format "\n", \
12671 + __func__, dwc_irq(), ## _args)
12672 +#define dwc_debug DWC_DEBUG
12673 +/**
12674 + * Prints out a Debug message if enabled at compile time.
12675 + */
12676 +#if DWC_OTG_DEBUG_LEV > 0
12677 +#define DWC_DEBUGC(_format, _args...) DWC_DEBUG(_format, ##_args )
12678 +#else
12679 +#define DWC_DEBUGC(_format, _args...)
12680 +#endif
12681 +#define dwc_debugc DWC_DEBUGC
12682 +/**
12683 + * Prints out an informative message.
12684 + */
12685 +#define DWC_INFO(_format, _args...) DWC_PRINTF("INFO:%s: " _format "\n", \
12686 + dwc_irq(), ## _args)
12687 +#define dwc_info DWC_INFO
12688 +/**
12689 + * Prints out an informative message if enabled at compile time.
12690 + */
12691 +#if DWC_OTG_DEBUG_LEV > 1
12692 +#define DWC_INFOC(_format, _args...) DWC_INFO(_format, ##_args )
12693 +#else
12694 +#define DWC_INFOC(_format, _args...)
12695 +#endif
12696 +#define dwc_infoc DWC_INFOC
12697 +/**
12698 + * Prints out a warning message.
12699 + */
12700 +#define DWC_WARN(_format, _args...) __DWC_WARN("WARN:%s:%s:%d: " _format "\n", \
12701 + dwc_irq(), __func__, __LINE__, ## _args)
12702 +#define dwc_warn DWC_WARN
12703 +/**
12704 + * Prints out an error message.
12705 + */
12706 +#define DWC_ERROR(_format, _args...) __DWC_ERROR("ERROR:%s:%s:%d: " _format "\n", \
12707 + dwc_irq(), __func__, __LINE__, ## _args)
12708 +#define dwc_error DWC_ERROR
12709 +
12710 +#define DWC_PROTO_ERROR(_format, _args...) __DWC_WARN("ERROR:%s:%s:%d: " _format "\n", \
12711 + dwc_irq(), __func__, __LINE__, ## _args)
12712 +#define dwc_proto_error DWC_PROTO_ERROR
12713 +
12714 +#ifdef DEBUG
12715 +/** Prints out a exception error message if the _expr expression fails. Disabled
12716 + * if DEBUG is not enabled. */
12717 +#define DWC_ASSERT(_expr, _format, _args...) do { \
12718 + if (!(_expr)) { DWC_EXCEPTION("%s:%s:%d: " _format "\n", dwc_irq(), \
12719 + __FILE__, __LINE__, ## _args); } \
12720 + } while (0)
12721 +#else
12722 +#define DWC_ASSERT(_x...)
12723 +#endif
12724 +#define dwc_assert DWC_ASSERT
12725 +
12726 +
12727 +/** @name Byte Ordering
12728 + * The following functions are for conversions between processor's byte ordering
12729 + * and specific ordering you want.
12730 + */
12731 +
12732 +/** Converts 32 bit data in CPU byte ordering to little endian. */
12733 +extern uint32_t DWC_CPU_TO_LE32(uint32_t *p);
12734 +#define dwc_cpu_to_le32 DWC_CPU_TO_LE32
12735 +
12736 +/** Converts 32 bit data in CPU byte orderint to big endian. */
12737 +extern uint32_t DWC_CPU_TO_BE32(uint32_t *p);
12738 +#define dwc_cpu_to_be32 DWC_CPU_TO_BE32
12739 +
12740 +/** Converts 32 bit little endian data to CPU byte ordering. */
12741 +extern uint32_t DWC_LE32_TO_CPU(uint32_t *p);
12742 +#define dwc_le32_to_cpu DWC_LE32_TO_CPU
12743 +
12744 +/** Converts 32 bit big endian data to CPU byte ordering. */
12745 +extern uint32_t DWC_BE32_TO_CPU(uint32_t *p);
12746 +#define dwc_be32_to_cpu DWC_BE32_TO_CPU
12747 +
12748 +/** Converts 16 bit data in CPU byte ordering to little endian. */
12749 +extern uint16_t DWC_CPU_TO_LE16(uint16_t *p);
12750 +#define dwc_cpu_to_le16 DWC_CPU_TO_LE16
12751 +
12752 +/** Converts 16 bit data in CPU byte orderint to big endian. */
12753 +extern uint16_t DWC_CPU_TO_BE16(uint16_t *p);
12754 +#define dwc_cpu_to_be16 DWC_CPU_TO_BE16
12755 +
12756 +/** Converts 16 bit little endian data to CPU byte ordering. */
12757 +extern uint16_t DWC_LE16_TO_CPU(uint16_t *p);
12758 +#define dwc_le16_to_cpu DWC_LE16_TO_CPU
12759 +
12760 +/** Converts 16 bit bi endian data to CPU byte ordering. */
12761 +extern uint16_t DWC_BE16_TO_CPU(uint16_t *p);
12762 +#define dwc_be16_to_cpu DWC_BE16_TO_CPU
12763 +
12764 +
12765 +/** @name Register Read/Write
12766 + *
12767 + * The following six functions should be implemented to read/write registers of
12768 + * 32-bit and 64-bit sizes. All modules use this to read/write register values.
12769 + * The reg value is a pointer to the register calculated from the void *base
12770 + * variable passed into the driver when it is started. */
12771 +
12772 +#ifdef DWC_LINUX
12773 +/* Linux doesn't need any extra parameters for register read/write, so we
12774 + * just throw away the IO context parameter.
12775 + */
12776 +/** Reads the content of a 32-bit register. */
12777 +extern uint32_t DWC_READ_REG32(uint32_t volatile *reg);
12778 +#define dwc_read_reg32(_ctx_,_reg_) DWC_READ_REG32(_reg_)
12779 +
12780 +/** Reads the content of a 64-bit register. */
12781 +extern uint64_t DWC_READ_REG64(uint64_t volatile *reg);
12782 +#define dwc_read_reg64(_ctx_,_reg_) DWC_READ_REG64(_reg_)
12783 +
12784 +/** Writes to a 32-bit register. */
12785 +extern void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value);
12786 +#define dwc_write_reg32(_ctx_,_reg_,_val_) DWC_WRITE_REG32(_reg_, _val_)
12787 +
12788 +/** Writes to a 64-bit register. */
12789 +extern void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value);
12790 +#define dwc_write_reg64(_ctx_,_reg_,_val_) DWC_WRITE_REG64(_reg_, _val_)
12791 +
12792 +/**
12793 + * Modify bit values in a register. Using the
12794 + * algorithm: (reg_contents & ~clear_mask) | set_mask.
12795 + */
12796 +extern void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
12797 +#define dwc_modify_reg32(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG32(_reg_,_cmsk_,_smsk_)
12798 +extern void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
12799 +#define dwc_modify_reg64(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG64(_reg_,_cmsk_,_smsk_)
12800 +
12801 +#endif /* DWC_LINUX */
12802 +
12803 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12804 +typedef struct dwc_ioctx {
12805 + struct device *dev;
12806 + bus_space_tag_t iot;
12807 + bus_space_handle_t ioh;
12808 +} dwc_ioctx_t;
12809 +
12810 +/** BSD needs two extra parameters for register read/write, so we pass
12811 + * them in using the IO context parameter.
12812 + */
12813 +/** Reads the content of a 32-bit register. */
12814 +extern uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg);
12815 +#define dwc_read_reg32 DWC_READ_REG32
12816 +
12817 +/** Reads the content of a 64-bit register. */
12818 +extern uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg);
12819 +#define dwc_read_reg64 DWC_READ_REG64
12820 +
12821 +/** Writes to a 32-bit register. */
12822 +extern void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value);
12823 +#define dwc_write_reg32 DWC_WRITE_REG32
12824 +
12825 +/** Writes to a 64-bit register. */
12826 +extern void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value);
12827 +#define dwc_write_reg64 DWC_WRITE_REG64
12828 +
12829 +/**
12830 + * Modify bit values in a register. Using the
12831 + * algorithm: (reg_contents & ~clear_mask) | set_mask.
12832 + */
12833 +extern void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
12834 +#define dwc_modify_reg32 DWC_MODIFY_REG32
12835 +extern void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
12836 +#define dwc_modify_reg64 DWC_MODIFY_REG64
12837 +
12838 +#endif /* DWC_FREEBSD || DWC_NETBSD */
12839 +
12840 +/** @cond */
12841 +
12842 +/** @name Some convenience MACROS used internally. Define DWC_DEBUG_REGS to log the
12843 + * register writes. */
12844 +
12845 +#ifdef DWC_LINUX
12846 +
12847 +# ifdef DWC_DEBUG_REGS
12848 +
12849 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12850 +static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
12851 + return DWC_READ_REG32(&container->regs->_reg[num]); \
12852 +} \
12853 +static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
12854 + DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
12855 + &(((uint32_t*)container->regs->_reg)[num]), data); \
12856 + DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
12857 +}
12858 +
12859 +#define dwc_define_read_write_reg(_reg,_container_type) \
12860 +static inline uint32_t dwc_read_##_reg(_container_type *container) { \
12861 + return DWC_READ_REG32(&container->regs->_reg); \
12862 +} \
12863 +static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
12864 + DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
12865 + DWC_WRITE_REG32(&container->regs->_reg, data); \
12866 +}
12867 +
12868 +# else /* DWC_DEBUG_REGS */
12869 +
12870 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12871 +static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
12872 + return DWC_READ_REG32(&container->regs->_reg[num]); \
12873 +} \
12874 +static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
12875 + DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
12876 +}
12877 +
12878 +#define dwc_define_read_write_reg(_reg,_container_type) \
12879 +static inline uint32_t dwc_read_##_reg(_container_type *container) { \
12880 + return DWC_READ_REG32(&container->regs->_reg); \
12881 +} \
12882 +static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
12883 + DWC_WRITE_REG32(&container->regs->_reg, data); \
12884 +}
12885 +
12886 +# endif /* DWC_DEBUG_REGS */
12887 +
12888 +#endif /* DWC_LINUX */
12889 +
12890 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12891 +
12892 +# ifdef DWC_DEBUG_REGS
12893 +
12894 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12895 +static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
12896 + return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
12897 +} \
12898 +static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
12899 + DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
12900 + &(((uint32_t*)container->regs->_reg)[num]), data); \
12901 + DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
12902 +}
12903 +
12904 +#define dwc_define_read_write_reg(_reg,_container_type) \
12905 +static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
12906 + return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
12907 +} \
12908 +static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
12909 + DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
12910 + DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
12911 +}
12912 +
12913 +# else /* DWC_DEBUG_REGS */
12914 +
12915 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12916 +static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
12917 + return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
12918 +} \
12919 +static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
12920 + DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
12921 +}
12922 +
12923 +#define dwc_define_read_write_reg(_reg,_container_type) \
12924 +static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
12925 + return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
12926 +} \
12927 +static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
12928 + DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
12929 +}
12930 +
12931 +# endif /* DWC_DEBUG_REGS */
12932 +
12933 +#endif /* DWC_FREEBSD || DWC_NETBSD */
12934 +
12935 +/** @endcond */
12936 +
12937 +
12938 +#ifdef DWC_CRYPTOLIB
12939 +/** @name Crypto Functions
12940 + *
12941 + * These are the low-level cryptographic functions used by the driver. */
12942 +
12943 +/** Perform AES CBC */
12944 +extern int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out);
12945 +#define dwc_aes_cbc DWC_AES_CBC
12946 +
12947 +/** Fill the provided buffer with random bytes. These should be cryptographic grade random numbers. */
12948 +extern void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length);
12949 +#define dwc_random_bytes DWC_RANDOM_BYTES
12950 +
12951 +/** Perform the SHA-256 hash function */
12952 +extern int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out);
12953 +#define dwc_sha256 DWC_SHA256
12954 +
12955 +/** Calculated the HMAC-SHA256 */
12956 +extern int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t *out);
12957 +#define dwc_hmac_sha256 DWC_HMAC_SHA256
12958 +
12959 +#endif /* DWC_CRYPTOLIB */
12960 +
12961 +
12962 +/** @name Memory Allocation
12963 + *
12964 + * These function provide access to memory allocation. There are only 2 DMA
12965 + * functions and 3 Regular memory functions that need to be implemented. None
12966 + * of the memory debugging routines need to be implemented. The allocation
12967 + * routines all ZERO the contents of the memory.
12968 + *
12969 + * Defining DWC_DEBUG_MEMORY turns on memory debugging and statistic gathering.
12970 + * This checks for memory leaks, keeping track of alloc/free pairs. It also
12971 + * keeps track of how much memory the driver is using at any given time. */
12972 +
12973 +#define DWC_PAGE_SIZE 4096
12974 +#define DWC_PAGE_OFFSET(addr) (((uint32_t)addr) & 0xfff)
12975 +#define DWC_PAGE_ALIGNED(addr) ((((uint32_t)addr) & 0xfff) == 0)
12976 +
12977 +#define DWC_INVALID_DMA_ADDR 0x0
12978 +
12979 +#ifdef DWC_LINUX
12980 +/** Type for a DMA address */
12981 +typedef dma_addr_t dwc_dma_t;
12982 +#endif
12983 +
12984 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12985 +typedef bus_addr_t dwc_dma_t;
12986 +#endif
12987 +
12988 +#ifdef DWC_FREEBSD
12989 +typedef struct dwc_dmactx {
12990 + struct device *dev;
12991 + bus_dma_tag_t dma_tag;
12992 + bus_dmamap_t dma_map;
12993 + bus_addr_t dma_paddr;
12994 + void *dma_vaddr;
12995 +} dwc_dmactx_t;
12996 +#endif
12997 +
12998 +#ifdef DWC_NETBSD
12999 +typedef struct dwc_dmactx {
13000 + struct device *dev;
13001 + bus_dma_tag_t dma_tag;
13002 + bus_dmamap_t dma_map;
13003 + bus_dma_segment_t segs[1];
13004 + int nsegs;
13005 + bus_addr_t dma_paddr;
13006 + void *dma_vaddr;
13007 +} dwc_dmactx_t;
13008 +#endif
13009 +
13010 +/* @todo these functions will be added in the future */
13011 +#if 0
13012 +/**
13013 + * Creates a DMA pool from which you can allocate DMA buffers. Buffers
13014 + * allocated from this pool will be guaranteed to meet the size, alignment, and
13015 + * boundary requirements specified.
13016 + *
13017 + * @param[in] size Specifies the size of the buffers that will be allocated from
13018 + * this pool.
13019 + * @param[in] align Specifies the byte alignment requirements of the buffers
13020 + * allocated from this pool. Must be a power of 2.
13021 + * @param[in] boundary Specifies the N-byte boundary that buffers allocated from
13022 + * this pool must not cross.
13023 + *
13024 + * @returns A pointer to an internal opaque structure which is not to be
13025 + * accessed outside of these library functions. Use this handle to specify
13026 + * which pools to allocate/free DMA buffers from and also to destroy the pool,
13027 + * when you are done with it.
13028 + */
13029 +extern dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size, uint32_t align, uint32_t boundary);
13030 +
13031 +/**
13032 + * Destroy a DMA pool. All buffers allocated from that pool must be freed first.
13033 + */
13034 +extern void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool);
13035 +
13036 +/**
13037 + * Allocate a buffer from the specified DMA pool and zeros its contents.
13038 + */
13039 +extern void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr);
13040 +
13041 +/**
13042 + * Free a previously allocated buffer from the DMA pool.
13043 + */
13044 +extern void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr);
13045 +#endif
13046 +
13047 +/** Allocates a DMA capable buffer and zeroes its contents. */
13048 +extern void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
13049 +
13050 +/** Allocates a DMA capable buffer and zeroes its contents in atomic contest */
13051 +extern void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
13052 +
13053 +/** Frees a previously allocated buffer. */
13054 +extern void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr);
13055 +
13056 +/** Allocates a block of memory and zeroes its contents. */
13057 +extern void *__DWC_ALLOC(void *mem_ctx, uint32_t size);
13058 +
13059 +/** Allocates a block of memory and zeroes its contents, in an atomic manner
13060 + * which can be used inside interrupt context. The size should be sufficiently
13061 + * small, a few KB at most, such that failures are not likely to occur. Can just call
13062 + * __DWC_ALLOC if it is atomic. */
13063 +extern void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size);
13064 +
13065 +/** Frees a previously allocated buffer. */
13066 +extern void __DWC_FREE(void *mem_ctx, void *addr);
13067 +
13068 +#ifndef DWC_DEBUG_MEMORY
13069 +
13070 +#define DWC_ALLOC(_size_) __DWC_ALLOC(NULL, _size_)
13071 +#define DWC_ALLOC_ATOMIC(_size_) __DWC_ALLOC_ATOMIC(NULL, _size_)
13072 +#define DWC_FREE(_addr_) __DWC_FREE(NULL, _addr_)
13073 +
13074 +# ifdef DWC_LINUX
13075 +#define DWC_DMA_ALLOC(_size_,_dma_) __DWC_DMA_ALLOC(NULL, _size_, _dma_)
13076 +#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) __DWC_DMA_ALLOC_ATOMIC(NULL, _size_,_dma_)
13077 +#define DWC_DMA_FREE(_size_,_virt_,_dma_) __DWC_DMA_FREE(NULL, _size_, _virt_, _dma_)
13078 +# endif
13079 +
13080 +# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
13081 +#define DWC_DMA_ALLOC __DWC_DMA_ALLOC
13082 +#define DWC_DMA_FREE __DWC_DMA_FREE
13083 +# endif
13084 +extern void *dwc_dma_alloc_atomic_debug(uint32_t size, dwc_dma_t *dma_addr, char const *func, int line);
13085 +
13086 +#else /* DWC_DEBUG_MEMORY */
13087 +
13088 +extern void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line);
13089 +extern void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func, int line);
13090 +extern void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line);
13091 +extern void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
13092 + char const *func, int line);
13093 +extern void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
13094 + char const *func, int line);
13095 +extern void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
13096 + dwc_dma_t dma_addr, char const *func, int line);
13097 +
13098 +extern int dwc_memory_debug_start(void *mem_ctx);
13099 +extern void dwc_memory_debug_stop(void);
13100 +extern void dwc_memory_debug_report(void);
13101 +
13102 +#define DWC_ALLOC(_size_) dwc_alloc_debug(NULL, _size_, __func__, __LINE__)
13103 +#define DWC_ALLOC_ATOMIC(_size_) dwc_alloc_atomic_debug(NULL, _size_, \
13104 + __func__, __LINE__)
13105 +#define DWC_FREE(_addr_) dwc_free_debug(NULL, _addr_, __func__, __LINE__)
13106 +
13107 +# ifdef DWC_LINUX
13108 +#define DWC_DMA_ALLOC(_size_,_dma_) dwc_dma_alloc_debug(NULL, _size_, \
13109 + _dma_, __func__, __LINE__)
13110 +#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) dwc_dma_alloc_atomic_debug(NULL, _size_, \
13111 + _dma_, __func__, __LINE__)
13112 +#define DWC_DMA_FREE(_size_,_virt_,_dma_) dwc_dma_free_debug(NULL, _size_, \
13113 + _virt_, _dma_, __func__, __LINE__)
13114 +# endif
13115 +
13116 +# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
13117 +#define DWC_DMA_ALLOC(_ctx_,_size_,_dma_) dwc_dma_alloc_debug(_ctx_, _size_, \
13118 + _dma_, __func__, __LINE__)
13119 +#define DWC_DMA_FREE(_ctx_,_size_,_virt_,_dma_) dwc_dma_free_debug(_ctx_, _size_, \
13120 + _virt_, _dma_, __func__, __LINE__)
13121 +# endif
13122 +
13123 +#endif /* DWC_DEBUG_MEMORY */
13124 +
13125 +#define dwc_alloc(_ctx_,_size_) DWC_ALLOC(_size_)
13126 +#define dwc_alloc_atomic(_ctx_,_size_) DWC_ALLOC_ATOMIC(_size_)
13127 +#define dwc_free(_ctx_,_addr_) DWC_FREE(_addr_)
13128 +
13129 +#ifdef DWC_LINUX
13130 +/* Linux doesn't need any extra parameters for DMA buffer allocation, so we
13131 + * just throw away the DMA context parameter.
13132 + */
13133 +#define dwc_dma_alloc(_ctx_,_size_,_dma_) DWC_DMA_ALLOC(_size_, _dma_)
13134 +#define dwc_dma_alloc_atomic(_ctx_,_size_,_dma_) DWC_DMA_ALLOC_ATOMIC(_size_, _dma_)
13135 +#define dwc_dma_free(_ctx_,_size_,_virt_,_dma_) DWC_DMA_FREE(_size_, _virt_, _dma_)
13136 +#endif
13137 +
13138 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
13139 +/** BSD needs several extra parameters for DMA buffer allocation, so we pass
13140 + * them in using the DMA context parameter.
13141 + */
13142 +#define dwc_dma_alloc DWC_DMA_ALLOC
13143 +#define dwc_dma_free DWC_DMA_FREE
13144 +#endif
13145 +
13146 +
13147 +/** @name Memory and String Processing */
13148 +
13149 +/** memset() clone */
13150 +extern void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size);
13151 +#define dwc_memset DWC_MEMSET
13152 +
13153 +/** memcpy() clone */
13154 +extern void *DWC_MEMCPY(void *dest, void const *src, uint32_t size);
13155 +#define dwc_memcpy DWC_MEMCPY
13156 +
13157 +/** memmove() clone */
13158 +extern void *DWC_MEMMOVE(void *dest, void *src, uint32_t size);
13159 +#define dwc_memmove DWC_MEMMOVE
13160 +
13161 +/** memcmp() clone */
13162 +extern int DWC_MEMCMP(void *m1, void *m2, uint32_t size);
13163 +#define dwc_memcmp DWC_MEMCMP
13164 +
13165 +/** strcmp() clone */
13166 +extern int DWC_STRCMP(void *s1, void *s2);
13167 +#define dwc_strcmp DWC_STRCMP
13168 +
13169 +/** strncmp() clone */
13170 +extern int DWC_STRNCMP(void *s1, void *s2, uint32_t size);
13171 +#define dwc_strncmp DWC_STRNCMP
13172 +
13173 +/** strlen() clone, for NULL terminated ASCII strings */
13174 +extern int DWC_STRLEN(char const *str);
13175 +#define dwc_strlen DWC_STRLEN
13176 +
13177 +/** strcpy() clone, for NULL terminated ASCII strings */
13178 +extern char *DWC_STRCPY(char *to, const char *from);
13179 +#define dwc_strcpy DWC_STRCPY
13180 +
13181 +/** strdup() clone. If you wish to use memory allocation debugging, this
13182 + * implementation of strdup should use the DWC_* memory routines instead of
13183 + * calling a predefined strdup. Otherwise the memory allocated by this routine
13184 + * will not be seen by the debugging routines. */
13185 +extern char *DWC_STRDUP(char const *str);
13186 +#define dwc_strdup(_ctx_,_str_) DWC_STRDUP(_str_)
13187 +
13188 +/** NOT an atoi() clone. Read the description carefully. Returns an integer
13189 + * converted from the string str in base 10 unless the string begins with a "0x"
13190 + * in which case it is base 16. String must be a NULL terminated sequence of
13191 + * ASCII characters and may optionally begin with whitespace, a + or -, and a
13192 + * "0x" prefix if base 16. The remaining characters must be valid digits for
13193 + * the number and end with a NULL character. If any invalid characters are
13194 + * encountered or it returns with a negative error code and the results of the
13195 + * conversion are undefined. On sucess it returns 0. Overflow conditions are
13196 + * undefined. An example implementation using atoi() can be referenced from the
13197 + * Linux implementation. */
13198 +extern int DWC_ATOI(const char *str, int32_t *value);
13199 +#define dwc_atoi DWC_ATOI
13200 +
13201 +/** Same as above but for unsigned. */
13202 +extern int DWC_ATOUI(const char *str, uint32_t *value);
13203 +#define dwc_atoui DWC_ATOUI
13204 +
13205 +#ifdef DWC_UTFLIB
13206 +/** This routine returns a UTF16LE unicode encoded string from a UTF8 string. */
13207 +extern int DWC_UTF8_TO_UTF16LE(uint8_t const *utf8string, uint16_t *utf16string, unsigned len);
13208 +#define dwc_utf8_to_utf16le DWC_UTF8_TO_UTF16LE
13209 +#endif
13210 +
13211 +
13212 +/** @name Wait queues
13213 + *
13214 + * Wait queues provide a means of synchronizing between threads or processes. A
13215 + * process can block on a waitq if some condition is not true, waiting for it to
13216 + * become true. When the waitq is triggered all waiting process will get
13217 + * unblocked and the condition will be check again. Waitqs should be triggered
13218 + * every time a condition can potentially change.*/
13219 +struct dwc_waitq;
13220 +
13221 +/** Type for a waitq */
13222 +typedef struct dwc_waitq dwc_waitq_t;
13223 +
13224 +/** The type of waitq condition callback function. This is called every time
13225 + * condition is evaluated. */
13226 +typedef int (*dwc_waitq_condition_t)(void *data);
13227 +
13228 +/** Allocate a waitq */
13229 +extern dwc_waitq_t *DWC_WAITQ_ALLOC(void);
13230 +#define dwc_waitq_alloc(_ctx_) DWC_WAITQ_ALLOC()
13231 +
13232 +/** Free a waitq */
13233 +extern void DWC_WAITQ_FREE(dwc_waitq_t *wq);
13234 +#define dwc_waitq_free DWC_WAITQ_FREE
13235 +
13236 +/** Check the condition and if it is false, block on the waitq. When unblocked, check the
13237 + * condition again. The function returns when the condition becomes true. The return value
13238 + * is 0 on condition true, DWC_WAITQ_ABORTED on abort or killed, or DWC_WAITQ_UNKNOWN on error. */
13239 +extern int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data);
13240 +#define dwc_waitq_wait DWC_WAITQ_WAIT
13241 +
13242 +/** Check the condition and if it is false, block on the waitq. When unblocked,
13243 + * check the condition again. The function returns when the condition become
13244 + * true or the timeout has passed. The return value is 0 on condition true or
13245 + * DWC_TIMED_OUT on timeout, or DWC_WAITQ_ABORTED, or DWC_WAITQ_UNKNOWN on
13246 + * error. */
13247 +extern int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
13248 + void *data, int32_t msecs);
13249 +#define dwc_waitq_wait_timeout DWC_WAITQ_WAIT_TIMEOUT
13250 +
13251 +/** Trigger a waitq, unblocking all processes. This should be called whenever a condition
13252 + * has potentially changed. */
13253 +extern void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq);
13254 +#define dwc_waitq_trigger DWC_WAITQ_TRIGGER
13255 +
13256 +/** Unblock all processes waiting on the waitq with an ABORTED result. */
13257 +extern void DWC_WAITQ_ABORT(dwc_waitq_t *wq);
13258 +#define dwc_waitq_abort DWC_WAITQ_ABORT
13259 +
13260 +
13261 +/** @name Threads
13262 + *
13263 + * A thread must be explicitly stopped. It must check DWC_THREAD_SHOULD_STOP
13264 + * whenever it is woken up, and then return. The DWC_THREAD_STOP function
13265 + * returns the value from the thread.
13266 + */
13267 +
13268 +struct dwc_thread;
13269 +
13270 +/** Type for a thread */
13271 +typedef struct dwc_thread dwc_thread_t;
13272 +
13273 +/** The thread function */
13274 +typedef int (*dwc_thread_function_t)(void *data);
13275 +
13276 +/** Create a thread and start it running the thread_function. Returns a handle
13277 + * to the thread */
13278 +extern dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data);
13279 +#define dwc_thread_run(_ctx_,_func_,_name_,_data_) DWC_THREAD_RUN(_func_, _name_, _data_)
13280 +
13281 +/** Stops a thread. Return the value returned by the thread. Or will return
13282 + * DWC_ABORT if the thread never started. */
13283 +extern int DWC_THREAD_STOP(dwc_thread_t *thread);
13284 +#define dwc_thread_stop DWC_THREAD_STOP
13285 +
13286 +/** Signifies to the thread that it must stop. */
13287 +#ifdef DWC_LINUX
13288 +/* Linux doesn't need any parameters for kthread_should_stop() */
13289 +extern dwc_bool_t DWC_THREAD_SHOULD_STOP(void);
13290 +#define dwc_thread_should_stop(_thrd_) DWC_THREAD_SHOULD_STOP()
13291 +
13292 +/* No thread_exit function in Linux */
13293 +#define dwc_thread_exit(_thrd_)
13294 +#endif
13295 +
13296 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
13297 +/** BSD needs the thread pointer for kthread_suspend_check() */
13298 +extern dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread);
13299 +#define dwc_thread_should_stop DWC_THREAD_SHOULD_STOP
13300 +
13301 +/** The thread must call this to exit. */
13302 +extern void DWC_THREAD_EXIT(dwc_thread_t *thread);
13303 +#define dwc_thread_exit DWC_THREAD_EXIT
13304 +#endif
13305 +
13306 +
13307 +/** @name Work queues
13308 + *
13309 + * Workqs are used to queue a callback function to be called at some later time,
13310 + * in another thread. */
13311 +struct dwc_workq;
13312 +
13313 +/** Type for a workq */
13314 +typedef struct dwc_workq dwc_workq_t;
13315 +
13316 +/** The type of the callback function to be called. */
13317 +typedef void (*dwc_work_callback_t)(void *data);
13318 +
13319 +/** Allocate a workq */
13320 +extern dwc_workq_t *DWC_WORKQ_ALLOC(char *name);
13321 +#define dwc_workq_alloc(_ctx_,_name_) DWC_WORKQ_ALLOC(_name_)
13322 +
13323 +/** Free a workq. All work must be completed before being freed. */
13324 +extern void DWC_WORKQ_FREE(dwc_workq_t *workq);
13325 +#define dwc_workq_free DWC_WORKQ_FREE
13326 +
13327 +/** Schedule a callback on the workq, passing in data. The function will be
13328 + * scheduled at some later time. */
13329 +extern void DWC_WORKQ_SCHEDULE(dwc_workq_t *workq, dwc_work_callback_t cb,
13330 + void *data, char *format, ...)
13331 +#ifdef __GNUC__
13332 + __attribute__ ((format(printf, 4, 5)));
13333 +#else
13334 + ;
13335 +#endif
13336 +#define dwc_workq_schedule DWC_WORKQ_SCHEDULE
13337 +
13338 +/** Schedule a callback on the workq, that will be called until at least
13339 + * given number miliseconds have passed. */
13340 +extern void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *workq, dwc_work_callback_t cb,
13341 + void *data, uint32_t time, char *format, ...)
13342 +#ifdef __GNUC__
13343 + __attribute__ ((format(printf, 5, 6)));
13344 +#else
13345 + ;
13346 +#endif
13347 +#define dwc_workq_schedule_delayed DWC_WORKQ_SCHEDULE_DELAYED
13348 +
13349 +/** The number of processes in the workq */
13350 +extern int DWC_WORKQ_PENDING(dwc_workq_t *workq);
13351 +#define dwc_workq_pending DWC_WORKQ_PENDING
13352 +
13353 +/** Blocks until all the work in the workq is complete or timed out. Returns <
13354 + * 0 on timeout. */
13355 +extern int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout);
13356 +#define dwc_workq_wait_work_done DWC_WORKQ_WAIT_WORK_DONE
13357 +
13358 +
13359 +/** @name Tasklets
13360 + *
13361 + */
13362 +struct dwc_tasklet;
13363 +
13364 +/** Type for a tasklet */
13365 +typedef struct dwc_tasklet dwc_tasklet_t;
13366 +
13367 +/** The type of the callback function to be called */
13368 +typedef void (*dwc_tasklet_callback_t)(void *data);
13369 +
13370 +/** Allocates a tasklet */
13371 +extern dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data);
13372 +#define dwc_task_alloc(_ctx_,_name_,_cb_,_data_) DWC_TASK_ALLOC(_name_, _cb_, _data_)
13373 +
13374 +/** Frees a tasklet */
13375 +extern void DWC_TASK_FREE(dwc_tasklet_t *task);
13376 +#define dwc_task_free DWC_TASK_FREE
13377 +
13378 +/** Schedules a tasklet to run */
13379 +extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task);
13380 +#define dwc_task_schedule DWC_TASK_SCHEDULE
13381 +
13382 +
13383 +/** @name Timer
13384 + *
13385 + * Callbacks must be small and atomic.
13386 + */
13387 +struct dwc_timer;
13388 +
13389 +/** Type for a timer */
13390 +typedef struct dwc_timer dwc_timer_t;
13391 +
13392 +/** The type of the callback function to be called */
13393 +typedef void (*dwc_timer_callback_t)(void *data);
13394 +
13395 +/** Allocates a timer */
13396 +extern dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data);
13397 +#define dwc_timer_alloc(_ctx_,_name_,_cb_,_data_) DWC_TIMER_ALLOC(_name_,_cb_,_data_)
13398 +
13399 +/** Frees a timer */
13400 +extern void DWC_TIMER_FREE(dwc_timer_t *timer);
13401 +#define dwc_timer_free DWC_TIMER_FREE
13402 +
13403 +/** Schedules the timer to run at time ms from now. And will repeat at every
13404 + * repeat_interval msec therafter
13405 + *
13406 + * Modifies a timer that is still awaiting execution to a new expiration time.
13407 + * The mod_time is added to the old time. */
13408 +extern void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time);
13409 +#define dwc_timer_schedule DWC_TIMER_SCHEDULE
13410 +
13411 +/** Disables the timer from execution. */
13412 +extern void DWC_TIMER_CANCEL(dwc_timer_t *timer);
13413 +#define dwc_timer_cancel DWC_TIMER_CANCEL
13414 +
13415 +
13416 +/** @name Spinlocks
13417 + *
13418 + * These locks are used when the work between the lock/unlock is atomic and
13419 + * short. Interrupts are also disabled during the lock/unlock and thus they are
13420 + * suitable to lock between interrupt/non-interrupt context. They also lock
13421 + * between processes if you have multiple CPUs or Preemption. If you don't have
13422 + * multiple CPUS or Preemption, then the you can simply implement the
13423 + * DWC_SPINLOCK and DWC_SPINUNLOCK to disable and enable interrupts. Because
13424 + * the work between the lock/unlock is atomic, the process context will never
13425 + * change, and so you never have to lock between processes. */
13426 +
13427 +struct dwc_spinlock;
13428 +
13429 +/** Type for a spinlock */
13430 +typedef struct dwc_spinlock dwc_spinlock_t;
13431 +
13432 +/** Type for the 'flags' argument to spinlock funtions */
13433 +typedef unsigned long dwc_irqflags_t;
13434 +
13435 +/** Returns an initialized lock variable. This function should allocate and
13436 + * initialize the OS-specific data structure used for locking. This data
13437 + * structure is to be used for the DWC_LOCK and DWC_UNLOCK functions and should
13438 + * be freed by the DWC_FREE_LOCK when it is no longer used. */
13439 +extern dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void);
13440 +#define dwc_spinlock_alloc(_ctx_) DWC_SPINLOCK_ALLOC()
13441 +
13442 +/** Frees an initialized lock variable. */
13443 +extern void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock);
13444 +#define dwc_spinlock_free(_ctx_,_lock_) DWC_SPINLOCK_FREE(_lock_)
13445 +
13446 +/** Disables interrupts and blocks until it acquires the lock.
13447 + *
13448 + * @param lock Pointer to the spinlock.
13449 + * @param flags Unsigned long for irq flags storage.
13450 + */
13451 +extern void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags);
13452 +#define dwc_spinlock_irqsave DWC_SPINLOCK_IRQSAVE
13453 +
13454 +/** Re-enables the interrupt and releases the lock.
13455 + *
13456 + * @param lock Pointer to the spinlock.
13457 + * @param flags Unsigned long for irq flags storage. Must be the same as was
13458 + * passed into DWC_LOCK.
13459 + */
13460 +extern void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags);
13461 +#define dwc_spinunlock_irqrestore DWC_SPINUNLOCK_IRQRESTORE
13462 +
13463 +/** Blocks until it acquires the lock.
13464 + *
13465 + * @param lock Pointer to the spinlock.
13466 + */
13467 +extern void DWC_SPINLOCK(dwc_spinlock_t *lock);
13468 +#define dwc_spinlock DWC_SPINLOCK
13469 +
13470 +/** Releases the lock.
13471 + *
13472 + * @param lock Pointer to the spinlock.
13473 + */
13474 +extern void DWC_SPINUNLOCK(dwc_spinlock_t *lock);
13475 +#define dwc_spinunlock DWC_SPINUNLOCK
13476 +
13477 +
13478 +/** @name Mutexes
13479 + *
13480 + * Unlike spinlocks Mutexes lock only between processes and the work between the
13481 + * lock/unlock CAN block, therefore it CANNOT be called from interrupt context.
13482 + */
13483 +
13484 +struct dwc_mutex;
13485 +
13486 +/** Type for a mutex */
13487 +typedef struct dwc_mutex dwc_mutex_t;
13488 +
13489 +/* For Linux Mutex Debugging make it inline because the debugging routines use
13490 + * the symbol to determine recursive locking. This makes it falsely think
13491 + * recursive locking occurs. */
13492 +#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
13493 +#define DWC_MUTEX_ALLOC_LINUX_DEBUG(__mutexp) ({ \
13494 + __mutexp = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex)); \
13495 + mutex_init((struct mutex *)__mutexp); \
13496 +})
13497 +#endif
13498 +
13499 +/** Allocate a mutex */
13500 +extern dwc_mutex_t *DWC_MUTEX_ALLOC(void);
13501 +#define dwc_mutex_alloc(_ctx_) DWC_MUTEX_ALLOC()
13502 +
13503 +/* For memory leak debugging when using Linux Mutex Debugging */
13504 +#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
13505 +#define DWC_MUTEX_FREE(__mutexp) do { \
13506 + mutex_destroy((struct mutex *)__mutexp); \
13507 + DWC_FREE(__mutexp); \
13508 +} while(0)
13509 +#else
13510 +/** Free a mutex */
13511 +extern void DWC_MUTEX_FREE(dwc_mutex_t *mutex);
13512 +#define dwc_mutex_free(_ctx_,_mutex_) DWC_MUTEX_FREE(_mutex_)
13513 +#endif
13514 +
13515 +/** Lock a mutex */
13516 +extern void DWC_MUTEX_LOCK(dwc_mutex_t *mutex);
13517 +#define dwc_mutex_lock DWC_MUTEX_LOCK
13518 +
13519 +/** Non-blocking lock returns 1 on successful lock. */
13520 +extern int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex);
13521 +#define dwc_mutex_trylock DWC_MUTEX_TRYLOCK
13522 +
13523 +/** Unlock a mutex */
13524 +extern void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex);
13525 +#define dwc_mutex_unlock DWC_MUTEX_UNLOCK
13526 +
13527 +
13528 +/** @name Time */
13529 +
13530 +/** Microsecond delay.
13531 + *
13532 + * @param usecs Microseconds to delay.
13533 + */
13534 +extern void DWC_UDELAY(uint32_t usecs);
13535 +#define dwc_udelay DWC_UDELAY
13536 +
13537 +/** Millisecond delay.
13538 + *
13539 + * @param msecs Milliseconds to delay.
13540 + */
13541 +extern void DWC_MDELAY(uint32_t msecs);
13542 +#define dwc_mdelay DWC_MDELAY
13543 +
13544 +/** Non-busy waiting.
13545 + * Sleeps for specified number of milliseconds.
13546 + *
13547 + * @param msecs Milliseconds to sleep.
13548 + */
13549 +extern void DWC_MSLEEP(uint32_t msecs);
13550 +#define dwc_msleep DWC_MSLEEP
13551 +
13552 +/**
13553 + * Returns number of milliseconds since boot.
13554 + */
13555 +extern uint32_t DWC_TIME(void);
13556 +#define dwc_time DWC_TIME
13557 +
13558 +
13559 +
13560 +
13561 +/* @mainpage DWC Portability and Common Library
13562 + *
13563 + * This is the documentation for the DWC Portability and Common Library.
13564 + *
13565 + * @section intro Introduction
13566 + *
13567 + * The DWC Portability library consists of wrapper calls and data structures to
13568 + * all low-level functions which are typically provided by the OS. The WUDEV
13569 + * driver uses only these functions. In order to port the WUDEV driver, only
13570 + * the functions in this library need to be re-implemented, with the same
13571 + * behavior as documented here.
13572 + *
13573 + * The Common library consists of higher level functions, which rely only on
13574 + * calling the functions from the DWC Portability library. These common
13575 + * routines are shared across modules. Some of the common libraries need to be
13576 + * used directly by the driver programmer when porting WUDEV. Such as the
13577 + * parameter and notification libraries.
13578 + *
13579 + * @section low Portability Library OS Wrapper Functions
13580 + *
13581 + * Any function starting with DWC and in all CAPS is a low-level OS-wrapper that
13582 + * needs to be implemented when porting, for example DWC_MUTEX_ALLOC(). All of
13583 + * these functions are included in the dwc_os.h file.
13584 + *
13585 + * There are many functions here covering a wide array of OS services. Please
13586 + * see dwc_os.h for details, and implementation notes for each function.
13587 + *
13588 + * @section common Common Library Functions
13589 + *
13590 + * Any function starting with dwc and in all lowercase is a common library
13591 + * routine. These functions have a portable implementation and do not need to
13592 + * be reimplemented when porting. The common routines can be used by any
13593 + * driver, and some must be used by the end user to control the drivers. For
13594 + * example, you must use the Parameter common library in order to set the
13595 + * parameters in the WUDEV module.
13596 + *
13597 + * The common libraries consist of the following:
13598 + *
13599 + * - Connection Contexts - Used internally and can be used by end-user. See dwc_cc.h
13600 + * - Parameters - Used internally and can be used by end-user. See dwc_params.h
13601 + * - Notifications - Used internally and can be used by end-user. See dwc_notifier.h
13602 + * - Lists - Used internally and can be used by end-user. See dwc_list.h
13603 + * - Memory Debugging - Used internally and can be used by end-user. See dwc_os.h
13604 + * - Modpow - Used internally only. See dwc_modpow.h
13605 + * - DH - Used internally only. See dwc_dh.h
13606 + * - Crypto - Used internally only. See dwc_crypto.h
13607 + *
13608 + *
13609 + * @section prereq Prerequistes For dwc_os.h
13610 + * @subsection types Data Types
13611 + *
13612 + * The dwc_os.h file assumes that several low-level data types are pre defined for the
13613 + * compilation environment. These data types are:
13614 + *
13615 + * - uint8_t - unsigned 8-bit data type
13616 + * - int8_t - signed 8-bit data type
13617 + * - uint16_t - unsigned 16-bit data type
13618 + * - int16_t - signed 16-bit data type
13619 + * - uint32_t - unsigned 32-bit data type
13620 + * - int32_t - signed 32-bit data type
13621 + * - uint64_t - unsigned 64-bit data type
13622 + * - int64_t - signed 64-bit data type
13623 + *
13624 + * Ensure that these are defined before using dwc_os.h. The easiest way to do
13625 + * that is to modify the top of the file to include the appropriate header.
13626 + * This is already done for the Linux environment. If the DWC_LINUX macro is
13627 + * defined, the correct header will be added. A standard header <stdint.h> is
13628 + * also used for environments where standard C headers are available.
13629 + *
13630 + * @subsection stdarg Variable Arguments
13631 + *
13632 + * Variable arguments are provided by a standard C header <stdarg.h>. it is
13633 + * available in Both the Linux and ANSI C enviornment. An equivalent must be
13634 + * provided in your enviornment in order to use dwc_os.h with the debug and
13635 + * tracing message functionality.
13636 + *
13637 + * @subsection thread Threading
13638 + *
13639 + * WUDEV Core must be run on an operating system that provides for multiple
13640 + * threads/processes. Threading can be implemented in many ways, even in
13641 + * embedded systems without an operating system. At the bare minimum, the
13642 + * system should be able to start any number of processes at any time to handle
13643 + * special work. It need not be a pre-emptive system. Process context can
13644 + * change upon a call to a blocking function. The hardware interrupt context
13645 + * that calls the module's ISR() function must be differentiable from process
13646 + * context, even if your processes are impemented via a hardware interrupt.
13647 + * Further locking mechanism between process must exist (or be implemented), and
13648 + * process context must have a way to disable interrupts for a period of time to
13649 + * lock them out. If all of this exists, the functions in dwc_os.h related to
13650 + * threading should be able to be implemented with the defined behavior.
13651 + *
13652 + */
13653 +
13654 +#ifdef __cplusplus
13655 +}
13656 +#endif
13657 +
13658 +#endif /* _DWC_OS_H_ */
13659 diff --git a/drivers/usb/host/dwc_common_port/usb.h b/drivers/usb/host/dwc_common_port/usb.h
13660 new file mode 100644
13661 index 0000000..27bda82
13662 --- /dev/null
13663 +++ b/drivers/usb/host/dwc_common_port/usb.h
13664 @@ -0,0 +1,946 @@
13665 +/*
13666 + * Copyright (c) 1998 The NetBSD Foundation, Inc.
13667 + * All rights reserved.
13668 + *
13669 + * This code is derived from software contributed to The NetBSD Foundation
13670 + * by Lennart Augustsson (lennart@augustsson.net) at
13671 + * Carlstedt Research & Technology.
13672 + *
13673 + * Redistribution and use in source and binary forms, with or without
13674 + * modification, are permitted provided that the following conditions
13675 + * are met:
13676 + * 1. Redistributions of source code must retain the above copyright
13677 + * notice, this list of conditions and the following disclaimer.
13678 + * 2. Redistributions in binary form must reproduce the above copyright
13679 + * notice, this list of conditions and the following disclaimer in the
13680 + * documentation and/or other materials provided with the distribution.
13681 + * 3. All advertising materials mentioning features or use of this software
13682 + * must display the following acknowledgement:
13683 + * This product includes software developed by the NetBSD
13684 + * Foundation, Inc. and its contributors.
13685 + * 4. Neither the name of The NetBSD Foundation nor the names of its
13686 + * contributors may be used to endorse or promote products derived
13687 + * from this software without specific prior written permission.
13688 + *
13689 + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
13690 + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
13691 + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
13692 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
13693 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
13694 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
13695 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
13696 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
13697 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
13698 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
13699 + * POSSIBILITY OF SUCH DAMAGE.
13700 + */
13701 +
13702 +/* Modified by Synopsys, Inc, 12/12/2007 */
13703 +
13704 +
13705 +#ifndef _USB_H_
13706 +#define _USB_H_
13707 +
13708 +#ifdef __cplusplus
13709 +extern "C" {
13710 +#endif
13711 +
13712 +/*
13713 + * The USB records contain some unaligned little-endian word
13714 + * components. The U[SG]ETW macros take care of both the alignment
13715 + * and endian problem and should always be used to access non-byte
13716 + * values.
13717 + */
13718 +typedef u_int8_t uByte;
13719 +typedef u_int8_t uWord[2];
13720 +typedef u_int8_t uDWord[4];
13721 +
13722 +#define USETW2(w,h,l) ((w)[0] = (u_int8_t)(l), (w)[1] = (u_int8_t)(h))
13723 +#define UCONSTW(x) { (x) & 0xff, ((x) >> 8) & 0xff }
13724 +#define UCONSTDW(x) { (x) & 0xff, ((x) >> 8) & 0xff, \
13725 + ((x) >> 16) & 0xff, ((x) >> 24) & 0xff }
13726 +
13727 +#if 1
13728 +#define UGETW(w) ((w)[0] | ((w)[1] << 8))
13729 +#define USETW(w,v) ((w)[0] = (u_int8_t)(v), (w)[1] = (u_int8_t)((v) >> 8))
13730 +#define UGETDW(w) ((w)[0] | ((w)[1] << 8) | ((w)[2] << 16) | ((w)[3] << 24))
13731 +#define USETDW(w,v) ((w)[0] = (u_int8_t)(v), \
13732 + (w)[1] = (u_int8_t)((v) >> 8), \
13733 + (w)[2] = (u_int8_t)((v) >> 16), \
13734 + (w)[3] = (u_int8_t)((v) >> 24))
13735 +#else
13736 +/*
13737 + * On little-endian machines that can handle unanliged accesses
13738 + * (e.g. i386) these macros can be replaced by the following.
13739 + */
13740 +#define UGETW(w) (*(u_int16_t *)(w))
13741 +#define USETW(w,v) (*(u_int16_t *)(w) = (v))
13742 +#define UGETDW(w) (*(u_int32_t *)(w))
13743 +#define USETDW(w,v) (*(u_int32_t *)(w) = (v))
13744 +#endif
13745 +
13746 +/*
13747 + * Macros for accessing UAS IU fields, which are big-endian
13748 + */
13749 +#define IUSETW2(w,h,l) ((w)[0] = (u_int8_t)(h), (w)[1] = (u_int8_t)(l))
13750 +#define IUCONSTW(x) { ((x) >> 8) & 0xff, (x) & 0xff }
13751 +#define IUCONSTDW(x) { ((x) >> 24) & 0xff, ((x) >> 16) & 0xff, \
13752 + ((x) >> 8) & 0xff, (x) & 0xff }
13753 +#define IUGETW(w) (((w)[0] << 8) | (w)[1])
13754 +#define IUSETW(w,v) ((w)[0] = (u_int8_t)((v) >> 8), (w)[1] = (u_int8_t)(v))
13755 +#define IUGETDW(w) (((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3])
13756 +#define IUSETDW(w,v) ((w)[0] = (u_int8_t)((v) >> 24), \
13757 + (w)[1] = (u_int8_t)((v) >> 16), \
13758 + (w)[2] = (u_int8_t)((v) >> 8), \
13759 + (w)[3] = (u_int8_t)(v))
13760 +
13761 +#define UPACKED __attribute__((__packed__))
13762 +
13763 +typedef struct {
13764 + uByte bmRequestType;
13765 + uByte bRequest;
13766 + uWord wValue;
13767 + uWord wIndex;
13768 + uWord wLength;
13769 +} UPACKED usb_device_request_t;
13770 +
13771 +#define UT_GET_DIR(a) ((a) & 0x80)
13772 +#define UT_WRITE 0x00
13773 +#define UT_READ 0x80
13774 +
13775 +#define UT_GET_TYPE(a) ((a) & 0x60)
13776 +#define UT_STANDARD 0x00
13777 +#define UT_CLASS 0x20
13778 +#define UT_VENDOR 0x40
13779 +
13780 +#define UT_GET_RECIPIENT(a) ((a) & 0x1f)
13781 +#define UT_DEVICE 0x00
13782 +#define UT_INTERFACE 0x01
13783 +#define UT_ENDPOINT 0x02
13784 +#define UT_OTHER 0x03
13785 +
13786 +#define UT_READ_DEVICE (UT_READ | UT_STANDARD | UT_DEVICE)
13787 +#define UT_READ_INTERFACE (UT_READ | UT_STANDARD | UT_INTERFACE)
13788 +#define UT_READ_ENDPOINT (UT_READ | UT_STANDARD | UT_ENDPOINT)
13789 +#define UT_WRITE_DEVICE (UT_WRITE | UT_STANDARD | UT_DEVICE)
13790 +#define UT_WRITE_INTERFACE (UT_WRITE | UT_STANDARD | UT_INTERFACE)
13791 +#define UT_WRITE_ENDPOINT (UT_WRITE | UT_STANDARD | UT_ENDPOINT)
13792 +#define UT_READ_CLASS_DEVICE (UT_READ | UT_CLASS | UT_DEVICE)
13793 +#define UT_READ_CLASS_INTERFACE (UT_READ | UT_CLASS | UT_INTERFACE)
13794 +#define UT_READ_CLASS_OTHER (UT_READ | UT_CLASS | UT_OTHER)
13795 +#define UT_READ_CLASS_ENDPOINT (UT_READ | UT_CLASS | UT_ENDPOINT)
13796 +#define UT_WRITE_CLASS_DEVICE (UT_WRITE | UT_CLASS | UT_DEVICE)
13797 +#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE)
13798 +#define UT_WRITE_CLASS_OTHER (UT_WRITE | UT_CLASS | UT_OTHER)
13799 +#define UT_WRITE_CLASS_ENDPOINT (UT_WRITE | UT_CLASS | UT_ENDPOINT)
13800 +#define UT_READ_VENDOR_DEVICE (UT_READ | UT_VENDOR | UT_DEVICE)
13801 +#define UT_READ_VENDOR_INTERFACE (UT_READ | UT_VENDOR | UT_INTERFACE)
13802 +#define UT_READ_VENDOR_OTHER (UT_READ | UT_VENDOR | UT_OTHER)
13803 +#define UT_READ_VENDOR_ENDPOINT (UT_READ | UT_VENDOR | UT_ENDPOINT)
13804 +#define UT_WRITE_VENDOR_DEVICE (UT_WRITE | UT_VENDOR | UT_DEVICE)
13805 +#define UT_WRITE_VENDOR_INTERFACE (UT_WRITE | UT_VENDOR | UT_INTERFACE)
13806 +#define UT_WRITE_VENDOR_OTHER (UT_WRITE | UT_VENDOR | UT_OTHER)
13807 +#define UT_WRITE_VENDOR_ENDPOINT (UT_WRITE | UT_VENDOR | UT_ENDPOINT)
13808 +
13809 +/* Requests */
13810 +#define UR_GET_STATUS 0x00
13811 +#define USTAT_STANDARD_STATUS 0x00
13812 +#define WUSTAT_WUSB_FEATURE 0x01
13813 +#define WUSTAT_CHANNEL_INFO 0x02
13814 +#define WUSTAT_RECEIVED_DATA 0x03
13815 +#define WUSTAT_MAS_AVAILABILITY 0x04
13816 +#define WUSTAT_CURRENT_TRANSMIT_POWER 0x05
13817 +#define UR_CLEAR_FEATURE 0x01
13818 +#define UR_SET_FEATURE 0x03
13819 +#define UR_SET_AND_TEST_FEATURE 0x0c
13820 +#define UR_SET_ADDRESS 0x05
13821 +#define UR_GET_DESCRIPTOR 0x06
13822 +#define UDESC_DEVICE 0x01
13823 +#define UDESC_CONFIG 0x02
13824 +#define UDESC_STRING 0x03
13825 +#define UDESC_INTERFACE 0x04
13826 +#define UDESC_ENDPOINT 0x05
13827 +#define UDESC_SS_USB_COMPANION 0x30
13828 +#define UDESC_DEVICE_QUALIFIER 0x06
13829 +#define UDESC_OTHER_SPEED_CONFIGURATION 0x07
13830 +#define UDESC_INTERFACE_POWER 0x08
13831 +#define UDESC_OTG 0x09
13832 +#define WUDESC_SECURITY 0x0c
13833 +#define WUDESC_KEY 0x0d
13834 +#define WUD_GET_KEY_INDEX(_wValue_) ((_wValue_) & 0xf)
13835 +#define WUD_GET_KEY_TYPE(_wValue_) (((_wValue_) & 0x30) >> 4)
13836 +#define WUD_KEY_TYPE_ASSOC 0x01
13837 +#define WUD_KEY_TYPE_GTK 0x02
13838 +#define WUD_GET_KEY_ORIGIN(_wValue_) (((_wValue_) & 0x40) >> 6)
13839 +#define WUD_KEY_ORIGIN_HOST 0x00
13840 +#define WUD_KEY_ORIGIN_DEVICE 0x01
13841 +#define WUDESC_ENCRYPTION_TYPE 0x0e
13842 +#define WUDESC_BOS 0x0f
13843 +#define WUDESC_DEVICE_CAPABILITY 0x10
13844 +#define WUDESC_WIRELESS_ENDPOINT_COMPANION 0x11
13845 +#define UDESC_BOS 0x0f
13846 +#define UDESC_DEVICE_CAPABILITY 0x10
13847 +#define UDESC_CS_DEVICE 0x21 /* class specific */
13848 +#define UDESC_CS_CONFIG 0x22
13849 +#define UDESC_CS_STRING 0x23
13850 +#define UDESC_CS_INTERFACE 0x24
13851 +#define UDESC_CS_ENDPOINT 0x25
13852 +#define UDESC_HUB 0x29
13853 +#define UR_SET_DESCRIPTOR 0x07
13854 +#define UR_GET_CONFIG 0x08
13855 +#define UR_SET_CONFIG 0x09
13856 +#define UR_GET_INTERFACE 0x0a
13857 +#define UR_SET_INTERFACE 0x0b
13858 +#define UR_SYNCH_FRAME 0x0c
13859 +#define WUR_SET_ENCRYPTION 0x0d
13860 +#define WUR_GET_ENCRYPTION 0x0e
13861 +#define WUR_SET_HANDSHAKE 0x0f
13862 +#define WUR_GET_HANDSHAKE 0x10
13863 +#define WUR_SET_CONNECTION 0x11
13864 +#define WUR_SET_SECURITY_DATA 0x12
13865 +#define WUR_GET_SECURITY_DATA 0x13
13866 +#define WUR_SET_WUSB_DATA 0x14
13867 +#define WUDATA_DRPIE_INFO 0x01
13868 +#define WUDATA_TRANSMIT_DATA 0x02
13869 +#define WUDATA_TRANSMIT_PARAMS 0x03
13870 +#define WUDATA_RECEIVE_PARAMS 0x04
13871 +#define WUDATA_TRANSMIT_POWER 0x05
13872 +#define WUR_LOOPBACK_DATA_WRITE 0x15
13873 +#define WUR_LOOPBACK_DATA_READ 0x16
13874 +#define WUR_SET_INTERFACE_DS 0x17
13875 +
13876 +/* Feature numbers */
13877 +#define UF_ENDPOINT_HALT 0
13878 +#define UF_DEVICE_REMOTE_WAKEUP 1
13879 +#define UF_TEST_MODE 2
13880 +#define UF_DEVICE_B_HNP_ENABLE 3
13881 +#define UF_DEVICE_A_HNP_SUPPORT 4
13882 +#define UF_DEVICE_A_ALT_HNP_SUPPORT 5
13883 +#define WUF_WUSB 3
13884 +#define WUF_TX_DRPIE 0x0
13885 +#define WUF_DEV_XMIT_PACKET 0x1
13886 +#define WUF_COUNT_PACKETS 0x2
13887 +#define WUF_CAPTURE_PACKETS 0x3
13888 +#define UF_FUNCTION_SUSPEND 0
13889 +#define UF_U1_ENABLE 48
13890 +#define UF_U2_ENABLE 49
13891 +#define UF_LTM_ENABLE 50
13892 +
13893 +/* Class requests from the USB 2.0 hub spec, table 11-15 */
13894 +#define UCR_CLEAR_HUB_FEATURE (0x2000 | UR_CLEAR_FEATURE)
13895 +#define UCR_CLEAR_PORT_FEATURE (0x2300 | UR_CLEAR_FEATURE)
13896 +#define UCR_GET_HUB_DESCRIPTOR (0xa000 | UR_GET_DESCRIPTOR)
13897 +#define UCR_GET_HUB_STATUS (0xa000 | UR_GET_STATUS)
13898 +#define UCR_GET_PORT_STATUS (0xa300 | UR_GET_STATUS)
13899 +#define UCR_SET_HUB_FEATURE (0x2000 | UR_SET_FEATURE)
13900 +#define UCR_SET_PORT_FEATURE (0x2300 | UR_SET_FEATURE)
13901 +#define UCR_SET_AND_TEST_PORT_FEATURE (0xa300 | UR_SET_AND_TEST_FEATURE)
13902 +
13903 +#ifdef _MSC_VER
13904 +#include <pshpack1.h>
13905 +#endif
13906 +
13907 +typedef struct {
13908 + uByte bLength;
13909 + uByte bDescriptorType;
13910 + uByte bDescriptorSubtype;
13911 +} UPACKED usb_descriptor_t;
13912 +
13913 +typedef struct {
13914 + uByte bLength;
13915 + uByte bDescriptorType;
13916 +} UPACKED usb_descriptor_header_t;
13917 +
13918 +typedef struct {
13919 + uByte bLength;
13920 + uByte bDescriptorType;
13921 + uWord bcdUSB;
13922 +#define UD_USB_2_0 0x0200
13923 +#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
13924 + uByte bDeviceClass;
13925 + uByte bDeviceSubClass;
13926 + uByte bDeviceProtocol;
13927 + uByte bMaxPacketSize;
13928 + /* The fields below are not part of the initial descriptor. */
13929 + uWord idVendor;
13930 + uWord idProduct;
13931 + uWord bcdDevice;
13932 + uByte iManufacturer;
13933 + uByte iProduct;
13934 + uByte iSerialNumber;
13935 + uByte bNumConfigurations;
13936 +} UPACKED usb_device_descriptor_t;
13937 +#define USB_DEVICE_DESCRIPTOR_SIZE 18
13938 +
13939 +typedef struct {
13940 + uByte bLength;
13941 + uByte bDescriptorType;
13942 + uWord wTotalLength;
13943 + uByte bNumInterface;
13944 + uByte bConfigurationValue;
13945 + uByte iConfiguration;
13946 +#define UC_ATT_ONE (1 << 7) /* must be set */
13947 +#define UC_ATT_SELFPOWER (1 << 6) /* self powered */
13948 +#define UC_ATT_WAKEUP (1 << 5) /* can wakeup */
13949 +#define UC_ATT_BATTERY (1 << 4) /* battery powered */
13950 + uByte bmAttributes;
13951 +#define UC_BUS_POWERED 0x80
13952 +#define UC_SELF_POWERED 0x40
13953 +#define UC_REMOTE_WAKEUP 0x20
13954 + uByte bMaxPower; /* max current in 2 mA units */
13955 +#define UC_POWER_FACTOR 2
13956 +} UPACKED usb_config_descriptor_t;
13957 +#define USB_CONFIG_DESCRIPTOR_SIZE 9
13958 +
13959 +typedef struct {
13960 + uByte bLength;
13961 + uByte bDescriptorType;
13962 + uByte bInterfaceNumber;
13963 + uByte bAlternateSetting;
13964 + uByte bNumEndpoints;
13965 + uByte bInterfaceClass;
13966 + uByte bInterfaceSubClass;
13967 + uByte bInterfaceProtocol;
13968 + uByte iInterface;
13969 +} UPACKED usb_interface_descriptor_t;
13970 +#define USB_INTERFACE_DESCRIPTOR_SIZE 9
13971 +
13972 +typedef struct {
13973 + uByte bLength;
13974 + uByte bDescriptorType;
13975 + uByte bEndpointAddress;
13976 +#define UE_GET_DIR(a) ((a) & 0x80)
13977 +#define UE_SET_DIR(a,d) ((a) | (((d)&1) << 7))
13978 +#define UE_DIR_IN 0x80
13979 +#define UE_DIR_OUT 0x00
13980 +#define UE_ADDR 0x0f
13981 +#define UE_GET_ADDR(a) ((a) & UE_ADDR)
13982 + uByte bmAttributes;
13983 +#define UE_XFERTYPE 0x03
13984 +#define UE_CONTROL 0x00
13985 +#define UE_ISOCHRONOUS 0x01
13986 +#define UE_BULK 0x02
13987 +#define UE_INTERRUPT 0x03
13988 +#define UE_GET_XFERTYPE(a) ((a) & UE_XFERTYPE)
13989 +#define UE_ISO_TYPE 0x0c
13990 +#define UE_ISO_ASYNC 0x04
13991 +#define UE_ISO_ADAPT 0x08
13992 +#define UE_ISO_SYNC 0x0c
13993 +#define UE_GET_ISO_TYPE(a) ((a) & UE_ISO_TYPE)
13994 + uWord wMaxPacketSize;
13995 + uByte bInterval;
13996 +} UPACKED usb_endpoint_descriptor_t;
13997 +#define USB_ENDPOINT_DESCRIPTOR_SIZE 7
13998 +
13999 +typedef struct ss_endpoint_companion_descriptor {
14000 + uByte bLength;
14001 + uByte bDescriptorType;
14002 + uByte bMaxBurst;
14003 +#define USSE_GET_MAX_STREAMS(a) ((a) & 0x1f)
14004 +#define USSE_SET_MAX_STREAMS(a, b) ((a) | ((b) & 0x1f))
14005 +#define USSE_GET_MAX_PACKET_NUM(a) ((a) & 0x03)
14006 +#define USSE_SET_MAX_PACKET_NUM(a, b) ((a) | ((b) & 0x03))
14007 + uByte bmAttributes;
14008 + uWord wBytesPerInterval;
14009 +} UPACKED ss_endpoint_companion_descriptor_t;
14010 +#define USB_SS_ENDPOINT_COMPANION_DESCRIPTOR_SIZE 6
14011 +
14012 +typedef struct {
14013 + uByte bLength;
14014 + uByte bDescriptorType;
14015 + uWord bString[127];
14016 +} UPACKED usb_string_descriptor_t;
14017 +#define USB_MAX_STRING_LEN 128
14018 +#define USB_LANGUAGE_TABLE 0 /* # of the string language id table */
14019 +
14020 +/* Hub specific request */
14021 +#define UR_GET_BUS_STATE 0x02
14022 +#define UR_CLEAR_TT_BUFFER 0x08
14023 +#define UR_RESET_TT 0x09
14024 +#define UR_GET_TT_STATE 0x0a
14025 +#define UR_STOP_TT 0x0b
14026 +
14027 +/* Hub features */
14028 +#define UHF_C_HUB_LOCAL_POWER 0
14029 +#define UHF_C_HUB_OVER_CURRENT 1
14030 +#define UHF_PORT_CONNECTION 0
14031 +#define UHF_PORT_ENABLE 1
14032 +#define UHF_PORT_SUSPEND 2
14033 +#define UHF_PORT_OVER_CURRENT 3
14034 +#define UHF_PORT_RESET 4
14035 +#define UHF_PORT_L1 5
14036 +#define UHF_PORT_POWER 8
14037 +#define UHF_PORT_LOW_SPEED 9
14038 +#define UHF_PORT_HIGH_SPEED 10
14039 +#define UHF_C_PORT_CONNECTION 16
14040 +#define UHF_C_PORT_ENABLE 17
14041 +#define UHF_C_PORT_SUSPEND 18
14042 +#define UHF_C_PORT_OVER_CURRENT 19
14043 +#define UHF_C_PORT_RESET 20
14044 +#define UHF_C_PORT_L1 23
14045 +#define UHF_PORT_TEST 21
14046 +#define UHF_PORT_INDICATOR 22
14047 +
14048 +typedef struct {
14049 + uByte bDescLength;
14050 + uByte bDescriptorType;
14051 + uByte bNbrPorts;
14052 + uWord wHubCharacteristics;
14053 +#define UHD_PWR 0x0003
14054 +#define UHD_PWR_GANGED 0x0000
14055 +#define UHD_PWR_INDIVIDUAL 0x0001
14056 +#define UHD_PWR_NO_SWITCH 0x0002
14057 +#define UHD_COMPOUND 0x0004
14058 +#define UHD_OC 0x0018
14059 +#define UHD_OC_GLOBAL 0x0000
14060 +#define UHD_OC_INDIVIDUAL 0x0008
14061 +#define UHD_OC_NONE 0x0010
14062 +#define UHD_TT_THINK 0x0060
14063 +#define UHD_TT_THINK_8 0x0000
14064 +#define UHD_TT_THINK_16 0x0020
14065 +#define UHD_TT_THINK_24 0x0040
14066 +#define UHD_TT_THINK_32 0x0060
14067 +#define UHD_PORT_IND 0x0080
14068 + uByte bPwrOn2PwrGood; /* delay in 2 ms units */
14069 +#define UHD_PWRON_FACTOR 2
14070 + uByte bHubContrCurrent;
14071 + uByte DeviceRemovable[32]; /* max 255 ports */
14072 +#define UHD_NOT_REMOV(desc, i) \
14073 + (((desc)->DeviceRemovable[(i)/8] >> ((i) % 8)) & 1)
14074 + /* deprecated */ uByte PortPowerCtrlMask[1];
14075 +} UPACKED usb_hub_descriptor_t;
14076 +#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */
14077 +
14078 +typedef struct {
14079 + uByte bLength;
14080 + uByte bDescriptorType;
14081 + uWord bcdUSB;
14082 + uByte bDeviceClass;
14083 + uByte bDeviceSubClass;
14084 + uByte bDeviceProtocol;
14085 + uByte bMaxPacketSize0;
14086 + uByte bNumConfigurations;
14087 + uByte bReserved;
14088 +} UPACKED usb_device_qualifier_t;
14089 +#define USB_DEVICE_QUALIFIER_SIZE 10
14090 +
14091 +typedef struct {
14092 + uByte bLength;
14093 + uByte bDescriptorType;
14094 + uByte bmAttributes;
14095 +#define UOTG_SRP 0x01
14096 +#define UOTG_HNP 0x02
14097 +} UPACKED usb_otg_descriptor_t;
14098 +
14099 +/* OTG feature selectors */
14100 +#define UOTG_B_HNP_ENABLE 3
14101 +#define UOTG_A_HNP_SUPPORT 4
14102 +#define UOTG_A_ALT_HNP_SUPPORT 5
14103 +
14104 +typedef struct {
14105 + uWord wStatus;
14106 +/* Device status flags */
14107 +#define UDS_SELF_POWERED 0x0001
14108 +#define UDS_REMOTE_WAKEUP 0x0002
14109 +/* Endpoint status flags */
14110 +#define UES_HALT 0x0001
14111 +} UPACKED usb_status_t;
14112 +
14113 +typedef struct {
14114 + uWord wHubStatus;
14115 +#define UHS_LOCAL_POWER 0x0001
14116 +#define UHS_OVER_CURRENT 0x0002
14117 + uWord wHubChange;
14118 +} UPACKED usb_hub_status_t;
14119 +
14120 +typedef struct {
14121 + uWord wPortStatus;
14122 +#define UPS_CURRENT_CONNECT_STATUS 0x0001
14123 +#define UPS_PORT_ENABLED 0x0002
14124 +#define UPS_SUSPEND 0x0004
14125 +#define UPS_OVERCURRENT_INDICATOR 0x0008
14126 +#define UPS_RESET 0x0010
14127 +#define UPS_PORT_POWER 0x0100
14128 +#define UPS_LOW_SPEED 0x0200
14129 +#define UPS_HIGH_SPEED 0x0400
14130 +#define UPS_PORT_TEST 0x0800
14131 +#define UPS_PORT_INDICATOR 0x1000
14132 + uWord wPortChange;
14133 +#define UPS_C_CONNECT_STATUS 0x0001
14134 +#define UPS_C_PORT_ENABLED 0x0002
14135 +#define UPS_C_SUSPEND 0x0004
14136 +#define UPS_C_OVERCURRENT_INDICATOR 0x0008
14137 +#define UPS_C_PORT_RESET 0x0010
14138 +} UPACKED usb_port_status_t;
14139 +
14140 +#ifdef _MSC_VER
14141 +#include <poppack.h>
14142 +#endif
14143 +
14144 +/* Device class codes */
14145 +#define UDCLASS_IN_INTERFACE 0x00
14146 +#define UDCLASS_COMM 0x02
14147 +#define UDCLASS_HUB 0x09
14148 +#define UDSUBCLASS_HUB 0x00
14149 +#define UDPROTO_FSHUB 0x00
14150 +#define UDPROTO_HSHUBSTT 0x01
14151 +#define UDPROTO_HSHUBMTT 0x02
14152 +#define UDCLASS_DIAGNOSTIC 0xdc
14153 +#define UDCLASS_WIRELESS 0xe0
14154 +#define UDSUBCLASS_RF 0x01
14155 +#define UDPROTO_BLUETOOTH 0x01
14156 +#define UDCLASS_VENDOR 0xff
14157 +
14158 +/* Interface class codes */
14159 +#define UICLASS_UNSPEC 0x00
14160 +
14161 +#define UICLASS_AUDIO 0x01
14162 +#define UISUBCLASS_AUDIOCONTROL 1
14163 +#define UISUBCLASS_AUDIOSTREAM 2
14164 +#define UISUBCLASS_MIDISTREAM 3
14165 +
14166 +#define UICLASS_CDC 0x02 /* communication */
14167 +#define UISUBCLASS_DIRECT_LINE_CONTROL_MODEL 1
14168 +#define UISUBCLASS_ABSTRACT_CONTROL_MODEL 2
14169 +#define UISUBCLASS_TELEPHONE_CONTROL_MODEL 3
14170 +#define UISUBCLASS_MULTICHANNEL_CONTROL_MODEL 4
14171 +#define UISUBCLASS_CAPI_CONTROLMODEL 5
14172 +#define UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL 6
14173 +#define UISUBCLASS_ATM_NETWORKING_CONTROL_MODEL 7
14174 +#define UIPROTO_CDC_AT 1
14175 +
14176 +#define UICLASS_HID 0x03
14177 +#define UISUBCLASS_BOOT 1
14178 +#define UIPROTO_BOOT_KEYBOARD 1
14179 +
14180 +#define UICLASS_PHYSICAL 0x05
14181 +
14182 +#define UICLASS_IMAGE 0x06
14183 +
14184 +#define UICLASS_PRINTER 0x07
14185 +#define UISUBCLASS_PRINTER 1
14186 +#define UIPROTO_PRINTER_UNI 1
14187 +#define UIPROTO_PRINTER_BI 2
14188 +#define UIPROTO_PRINTER_1284 3
14189 +
14190 +#define UICLASS_MASS 0x08
14191 +#define UISUBCLASS_RBC 1
14192 +#define UISUBCLASS_SFF8020I 2
14193 +#define UISUBCLASS_QIC157 3
14194 +#define UISUBCLASS_UFI 4
14195 +#define UISUBCLASS_SFF8070I 5
14196 +#define UISUBCLASS_SCSI 6
14197 +#define UIPROTO_MASS_CBI_I 0
14198 +#define UIPROTO_MASS_CBI 1
14199 +#define UIPROTO_MASS_BBB_OLD 2 /* Not in the spec anymore */
14200 +#define UIPROTO_MASS_BBB 80 /* 'P' for the Iomega Zip drive */
14201 +
14202 +#define UICLASS_HUB 0x09
14203 +#define UISUBCLASS_HUB 0
14204 +#define UIPROTO_FSHUB 0
14205 +#define UIPROTO_HSHUBSTT 0 /* Yes, same as previous */
14206 +#define UIPROTO_HSHUBMTT 1
14207 +
14208 +#define UICLASS_CDC_DATA 0x0a
14209 +#define UISUBCLASS_DATA 0
14210 +#define UIPROTO_DATA_ISDNBRI 0x30 /* Physical iface */
14211 +#define UIPROTO_DATA_HDLC 0x31 /* HDLC */
14212 +#define UIPROTO_DATA_TRANSPARENT 0x32 /* Transparent */
14213 +#define UIPROTO_DATA_Q921M 0x50 /* Management for Q921 */
14214 +#define UIPROTO_DATA_Q921 0x51 /* Data for Q921 */
14215 +#define UIPROTO_DATA_Q921TM 0x52 /* TEI multiplexer for Q921 */
14216 +#define UIPROTO_DATA_V42BIS 0x90 /* Data compression */
14217 +#define UIPROTO_DATA_Q931 0x91 /* Euro-ISDN */
14218 +#define UIPROTO_DATA_V120 0x92 /* V.24 rate adaption */
14219 +#define UIPROTO_DATA_CAPI 0x93 /* CAPI 2.0 commands */
14220 +#define UIPROTO_DATA_HOST_BASED 0xfd /* Host based driver */
14221 +#define UIPROTO_DATA_PUF 0xfe /* see Prot. Unit Func. Desc.*/
14222 +#define UIPROTO_DATA_VENDOR 0xff /* Vendor specific */
14223 +
14224 +#define UICLASS_SMARTCARD 0x0b
14225 +
14226 +/*#define UICLASS_FIRM_UPD 0x0c*/
14227 +
14228 +#define UICLASS_SECURITY 0x0d
14229 +
14230 +#define UICLASS_DIAGNOSTIC 0xdc
14231 +
14232 +#define UICLASS_WIRELESS 0xe0
14233 +#define UISUBCLASS_RF 0x01
14234 +#define UIPROTO_BLUETOOTH 0x01
14235 +
14236 +#define UICLASS_APPL_SPEC 0xfe
14237 +#define UISUBCLASS_FIRMWARE_DOWNLOAD 1
14238 +#define UISUBCLASS_IRDA 2
14239 +#define UIPROTO_IRDA 0
14240 +
14241 +#define UICLASS_VENDOR 0xff
14242 +
14243 +#define USB_HUB_MAX_DEPTH 5
14244 +
14245 +/*
14246 + * Minimum time a device needs to be powered down to go through
14247 + * a power cycle. XXX Are these time in the spec?
14248 + */
14249 +#define USB_POWER_DOWN_TIME 200 /* ms */
14250 +#define USB_PORT_POWER_DOWN_TIME 100 /* ms */
14251 +
14252 +#if 0
14253 +/* These are the values from the spec. */
14254 +#define USB_PORT_RESET_DELAY 10 /* ms */
14255 +#define USB_PORT_ROOT_RESET_DELAY 50 /* ms */
14256 +#define USB_PORT_RESET_RECOVERY 10 /* ms */
14257 +#define USB_PORT_POWERUP_DELAY 100 /* ms */
14258 +#define USB_SET_ADDRESS_SETTLE 2 /* ms */
14259 +#define USB_RESUME_DELAY (20*5) /* ms */
14260 +#define USB_RESUME_WAIT 10 /* ms */
14261 +#define USB_RESUME_RECOVERY 10 /* ms */
14262 +#define USB_EXTRA_POWER_UP_TIME 0 /* ms */
14263 +#else
14264 +/* Allow for marginal (i.e. non-conforming) devices. */
14265 +#define USB_PORT_RESET_DELAY 50 /* ms */
14266 +#define USB_PORT_ROOT_RESET_DELAY 250 /* ms */
14267 +#define USB_PORT_RESET_RECOVERY 250 /* ms */
14268 +#define USB_PORT_POWERUP_DELAY 300 /* ms */
14269 +#define USB_SET_ADDRESS_SETTLE 10 /* ms */
14270 +#define USB_RESUME_DELAY (50*5) /* ms */
14271 +#define USB_RESUME_WAIT 50 /* ms */
14272 +#define USB_RESUME_RECOVERY 50 /* ms */
14273 +#define USB_EXTRA_POWER_UP_TIME 20 /* ms */
14274 +#endif
14275 +
14276 +#define USB_MIN_POWER 100 /* mA */
14277 +#define USB_MAX_POWER 500 /* mA */
14278 +
14279 +#define USB_BUS_RESET_DELAY 100 /* ms XXX?*/
14280 +
14281 +#define USB_UNCONFIG_NO 0
14282 +#define USB_UNCONFIG_INDEX (-1)
14283 +
14284 +/*** ioctl() related stuff ***/
14285 +
14286 +struct usb_ctl_request {
14287 + int ucr_addr;
14288 + usb_device_request_t ucr_request;
14289 + void *ucr_data;
14290 + int ucr_flags;
14291 +#define USBD_SHORT_XFER_OK 0x04 /* allow short reads */
14292 + int ucr_actlen; /* actual length transferred */
14293 +};
14294 +
14295 +struct usb_alt_interface {
14296 + int uai_config_index;
14297 + int uai_interface_index;
14298 + int uai_alt_no;
14299 +};
14300 +
14301 +#define USB_CURRENT_CONFIG_INDEX (-1)
14302 +#define USB_CURRENT_ALT_INDEX (-1)
14303 +
14304 +struct usb_config_desc {
14305 + int ucd_config_index;
14306 + usb_config_descriptor_t ucd_desc;
14307 +};
14308 +
14309 +struct usb_interface_desc {
14310 + int uid_config_index;
14311 + int uid_interface_index;
14312 + int uid_alt_index;
14313 + usb_interface_descriptor_t uid_desc;
14314 +};
14315 +
14316 +struct usb_endpoint_desc {
14317 + int ued_config_index;
14318 + int ued_interface_index;
14319 + int ued_alt_index;
14320 + int ued_endpoint_index;
14321 + usb_endpoint_descriptor_t ued_desc;
14322 +};
14323 +
14324 +struct usb_full_desc {
14325 + int ufd_config_index;
14326 + u_int ufd_size;
14327 + u_char *ufd_data;
14328 +};
14329 +
14330 +struct usb_string_desc {
14331 + int usd_string_index;
14332 + int usd_language_id;
14333 + usb_string_descriptor_t usd_desc;
14334 +};
14335 +
14336 +struct usb_ctl_report_desc {
14337 + int ucrd_size;
14338 + u_char ucrd_data[1024]; /* filled data size will vary */
14339 +};
14340 +
14341 +typedef struct { u_int32_t cookie; } usb_event_cookie_t;
14342 +
14343 +#define USB_MAX_DEVNAMES 4
14344 +#define USB_MAX_DEVNAMELEN 16
14345 +struct usb_device_info {
14346 + u_int8_t udi_bus;
14347 + u_int8_t udi_addr; /* device address */
14348 + usb_event_cookie_t udi_cookie;
14349 + char udi_product[USB_MAX_STRING_LEN];
14350 + char udi_vendor[USB_MAX_STRING_LEN];
14351 + char udi_release[8];
14352 + u_int16_t udi_productNo;
14353 + u_int16_t udi_vendorNo;
14354 + u_int16_t udi_releaseNo;
14355 + u_int8_t udi_class;
14356 + u_int8_t udi_subclass;
14357 + u_int8_t udi_protocol;
14358 + u_int8_t udi_config;
14359 + u_int8_t udi_speed;
14360 +#define USB_SPEED_UNKNOWN 0
14361 +#define USB_SPEED_LOW 1
14362 +#define USB_SPEED_FULL 2
14363 +#define USB_SPEED_HIGH 3
14364 +#define USB_SPEED_VARIABLE 4
14365 +#define USB_SPEED_SUPER 5
14366 + int udi_power; /* power consumption in mA, 0 if selfpowered */
14367 + int udi_nports;
14368 + char udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];
14369 + u_int8_t udi_ports[16];/* hub only: addresses of devices on ports */
14370 +#define USB_PORT_ENABLED 0xff
14371 +#define USB_PORT_SUSPENDED 0xfe
14372 +#define USB_PORT_POWERED 0xfd
14373 +#define USB_PORT_DISABLED 0xfc
14374 +};
14375 +
14376 +struct usb_ctl_report {
14377 + int ucr_report;
14378 + u_char ucr_data[1024]; /* filled data size will vary */
14379 +};
14380 +
14381 +struct usb_device_stats {
14382 + u_long uds_requests[4]; /* indexed by transfer type UE_* */
14383 +};
14384 +
14385 +#define WUSB_MIN_IE 0x80
14386 +#define WUSB_WCTA_IE 0x80
14387 +#define WUSB_WCONNECTACK_IE 0x81
14388 +#define WUSB_WHOSTINFO_IE 0x82
14389 +#define WUHI_GET_CA(_bmAttributes_) ((_bmAttributes_) & 0x3)
14390 +#define WUHI_CA_RECONN 0x00
14391 +#define WUHI_CA_LIMITED 0x01
14392 +#define WUHI_CA_ALL 0x03
14393 +#define WUHI_GET_MLSI(_bmAttributes_) (((_bmAttributes_) & 0x38) >> 3)
14394 +#define WUSB_WCHCHANGEANNOUNCE_IE 0x83
14395 +#define WUSB_WDEV_DISCONNECT_IE 0x84
14396 +#define WUSB_WHOST_DISCONNECT_IE 0x85
14397 +#define WUSB_WRELEASE_CHANNEL_IE 0x86
14398 +#define WUSB_WWORK_IE 0x87
14399 +#define WUSB_WCHANNEL_STOP_IE 0x88
14400 +#define WUSB_WDEV_KEEPALIVE_IE 0x89
14401 +#define WUSB_WISOCH_DISCARD_IE 0x8A
14402 +#define WUSB_WRESETDEVICE_IE 0x8B
14403 +#define WUSB_WXMIT_PACKET_ADJUST_IE 0x8C
14404 +#define WUSB_MAX_IE 0x8C
14405 +
14406 +/* Device Notification Types */
14407 +
14408 +#define WUSB_DN_MIN 0x01
14409 +#define WUSB_DN_CONNECT 0x01
14410 +# define WUSB_DA_OLDCONN 0x00
14411 +# define WUSB_DA_NEWCONN 0x01
14412 +# define WUSB_DA_SELF_BEACON 0x02
14413 +# define WUSB_DA_DIR_BEACON 0x04
14414 +# define WUSB_DA_NO_BEACON 0x06
14415 +#define WUSB_DN_DISCONNECT 0x02
14416 +#define WUSB_DN_EPRDY 0x03
14417 +#define WUSB_DN_MASAVAILCHANGED 0x04
14418 +#define WUSB_DN_REMOTEWAKEUP 0x05
14419 +#define WUSB_DN_SLEEP 0x06
14420 +#define WUSB_DN_ALIVE 0x07
14421 +#define WUSB_DN_MAX 0x07
14422 +
14423 +#ifdef _MSC_VER
14424 +#include <pshpack1.h>
14425 +#endif
14426 +
14427 +/* WUSB Handshake Data. Used during the SET/GET HANDSHAKE requests */
14428 +typedef struct wusb_hndshk_data {
14429 + uByte bMessageNumber;
14430 + uByte bStatus;
14431 + uByte tTKID[3];
14432 + uByte bReserved;
14433 + uByte CDID[16];
14434 + uByte Nonce[16];
14435 + uByte MIC[8];
14436 +} UPACKED wusb_hndshk_data_t;
14437 +#define WUSB_HANDSHAKE_LEN_FOR_MIC 38
14438 +
14439 +/* WUSB Connection Context */
14440 +typedef struct wusb_conn_context {
14441 + uByte CHID [16];
14442 + uByte CDID [16];
14443 + uByte CK [16];
14444 +} UPACKED wusb_conn_context_t;
14445 +
14446 +/* WUSB Security Descriptor */
14447 +typedef struct wusb_security_desc {
14448 + uByte bLength;
14449 + uByte bDescriptorType;
14450 + uWord wTotalLength;
14451 + uByte bNumEncryptionTypes;
14452 +} UPACKED wusb_security_desc_t;
14453 +
14454 +/* WUSB Encryption Type Descriptor */
14455 +typedef struct wusb_encrypt_type_desc {
14456 + uByte bLength;
14457 + uByte bDescriptorType;
14458 +
14459 + uByte bEncryptionType;
14460 +#define WUETD_UNSECURE 0
14461 +#define WUETD_WIRED 1
14462 +#define WUETD_CCM_1 2
14463 +#define WUETD_RSA_1 3
14464 +
14465 + uByte bEncryptionValue;
14466 + uByte bAuthKeyIndex;
14467 +} UPACKED wusb_encrypt_type_desc_t;
14468 +
14469 +/* WUSB Key Descriptor */
14470 +typedef struct wusb_key_desc {
14471 + uByte bLength;
14472 + uByte bDescriptorType;
14473 + uByte tTKID[3];
14474 + uByte bReserved;
14475 + uByte KeyData[1]; /* variable length */
14476 +} UPACKED wusb_key_desc_t;
14477 +
14478 +/* WUSB BOS Descriptor (Binary device Object Store) */
14479 +typedef struct wusb_bos_desc {
14480 + uByte bLength;
14481 + uByte bDescriptorType;
14482 + uWord wTotalLength;
14483 + uByte bNumDeviceCaps;
14484 +} UPACKED wusb_bos_desc_t;
14485 +
14486 +#define USB_DEVICE_CAPABILITY_20_EXTENSION 0x02
14487 +typedef struct usb_dev_cap_20_ext_desc {
14488 + uByte bLength;
14489 + uByte bDescriptorType;
14490 + uByte bDevCapabilityType;
14491 +#define USB_20_EXT_LPM 0x02
14492 + uDWord bmAttributes;
14493 +} UPACKED usb_dev_cap_20_ext_desc_t;
14494 +
14495 +#define USB_DEVICE_CAPABILITY_SS_USB 0x03
14496 +typedef struct usb_dev_cap_ss_usb {
14497 + uByte bLength;
14498 + uByte bDescriptorType;
14499 + uByte bDevCapabilityType;
14500 +#define USB_DC_SS_USB_LTM_CAPABLE 0x02
14501 + uByte bmAttributes;
14502 +#define USB_DC_SS_USB_SPEED_SUPPORT_LOW 0x01
14503 +#define USB_DC_SS_USB_SPEED_SUPPORT_FULL 0x02
14504 +#define USB_DC_SS_USB_SPEED_SUPPORT_HIGH 0x04
14505 +#define USB_DC_SS_USB_SPEED_SUPPORT_SS 0x08
14506 + uWord wSpeedsSupported;
14507 + uByte bFunctionalitySupport;
14508 + uByte bU1DevExitLat;
14509 + uWord wU2DevExitLat;
14510 +} UPACKED usb_dev_cap_ss_usb_t;
14511 +
14512 +#define USB_DEVICE_CAPABILITY_CONTAINER_ID 0x04
14513 +typedef struct usb_dev_cap_container_id {
14514 + uByte bLength;
14515 + uByte bDescriptorType;
14516 + uByte bDevCapabilityType;
14517 + uByte bReserved;
14518 + uByte containerID[16];
14519 +} UPACKED usb_dev_cap_container_id_t;
14520 +
14521 +/* Device Capability Type Codes */
14522 +#define WUSB_DEVICE_CAPABILITY_WIRELESS_USB 0x01
14523 +
14524 +/* Device Capability Descriptor */
14525 +typedef struct wusb_dev_cap_desc {
14526 + uByte bLength;
14527 + uByte bDescriptorType;
14528 + uByte bDevCapabilityType;
14529 + uByte caps[1]; /* Variable length */
14530 +} UPACKED wusb_dev_cap_desc_t;
14531 +
14532 +/* Device Capability Descriptor */
14533 +typedef struct wusb_dev_cap_uwb_desc {
14534 + uByte bLength;
14535 + uByte bDescriptorType;
14536 + uByte bDevCapabilityType;
14537 + uByte bmAttributes;
14538 + uWord wPHYRates; /* Bitmap */
14539 + uByte bmTFITXPowerInfo;
14540 + uByte bmFFITXPowerInfo;
14541 + uWord bmBandGroup;
14542 + uByte bReserved;
14543 +} UPACKED wusb_dev_cap_uwb_desc_t;
14544 +
14545 +/* Wireless USB Endpoint Companion Descriptor */
14546 +typedef struct wusb_endpoint_companion_desc {
14547 + uByte bLength;
14548 + uByte bDescriptorType;
14549 + uByte bMaxBurst;
14550 + uByte bMaxSequence;
14551 + uWord wMaxStreamDelay;
14552 + uWord wOverTheAirPacketSize;
14553 + uByte bOverTheAirInterval;
14554 + uByte bmCompAttributes;
14555 +} UPACKED wusb_endpoint_companion_desc_t;
14556 +
14557 +/* Wireless USB Numeric Association M1 Data Structure */
14558 +typedef struct wusb_m1_data {
14559 + uByte version;
14560 + uWord langId;
14561 + uByte deviceFriendlyNameLength;
14562 + uByte sha_256_m3[32];
14563 + uByte deviceFriendlyName[256];
14564 +} UPACKED wusb_m1_data_t;
14565 +
14566 +typedef struct wusb_m2_data {
14567 + uByte version;
14568 + uWord langId;
14569 + uByte hostFriendlyNameLength;
14570 + uByte pkh[384];
14571 + uByte hostFriendlyName[256];
14572 +} UPACKED wusb_m2_data_t;
14573 +
14574 +typedef struct wusb_m3_data {
14575 + uByte pkd[384];
14576 + uByte nd;
14577 +} UPACKED wusb_m3_data_t;
14578 +
14579 +typedef struct wusb_m4_data {
14580 + uDWord _attributeTypeIdAndLength_1;
14581 + uWord associationTypeId;
14582 +
14583 + uDWord _attributeTypeIdAndLength_2;
14584 + uWord associationSubTypeId;
14585 +
14586 + uDWord _attributeTypeIdAndLength_3;
14587 + uDWord length;
14588 +
14589 + uDWord _attributeTypeIdAndLength_4;
14590 + uDWord associationStatus;
14591 +
14592 + uDWord _attributeTypeIdAndLength_5;
14593 + uByte chid[16];
14594 +
14595 + uDWord _attributeTypeIdAndLength_6;
14596 + uByte cdid[16];
14597 +
14598 + uDWord _attributeTypeIdAndLength_7;
14599 + uByte bandGroups[2];
14600 +} UPACKED wusb_m4_data_t;
14601 +
14602 +#ifdef _MSC_VER
14603 +#include <poppack.h>
14604 +#endif
14605 +
14606 +#ifdef __cplusplus
14607 +}
14608 +#endif
14609 +
14610 +#endif /* _USB_H_ */
14611 diff --git a/drivers/usb/host/dwc_otg/Makefile b/drivers/usb/host/dwc_otg/Makefile
14612 new file mode 100644
14613 index 0000000..236c47c
14614 --- /dev/null
14615 +++ b/drivers/usb/host/dwc_otg/Makefile
14616 @@ -0,0 +1,80 @@
14617 +#
14618 +# Makefile for DWC_otg Highspeed USB controller driver
14619 +#
14620 +
14621 +ifneq ($(KERNELRELEASE),)
14622 +
14623 +# Use the BUS_INTERFACE variable to compile the software for either
14624 +# PCI(PCI_INTERFACE) or LM(LM_INTERFACE) bus.
14625 +ifeq ($(BUS_INTERFACE),)
14626 +# BUS_INTERFACE = -DPCI_INTERFACE
14627 +# BUS_INTERFACE = -DLM_INTERFACE
14628 + BUS_INTERFACE = -DPLATFORM_INTERFACE
14629 +endif
14630 +
14631 +#ccflags-y += -DDEBUG
14632 +#ccflags-y += -DDWC_OTG_DEBUGLEV=1 # reduce common debug msgs
14633 +
14634 +# Use one of the following flags to compile the software in host-only or
14635 +# device-only mode.
14636 +#ccflags-y += -DDWC_HOST_ONLY
14637 +#ccflags-y += -DDWC_DEVICE_ONLY
14638 +
14639 +ccflags-y += -Dlinux -DDWC_HS_ELECT_TST
14640 +#ccflags-y += -DDWC_EN_ISOC
14641 +ccflags-y += -I$(obj)/../dwc_common_port
14642 +#ccflags-y += -I$(PORTLIB)
14643 +ccflags-y += -DDWC_LINUX
14644 +ccflags-y += $(CFI)
14645 +ccflags-y += $(BUS_INTERFACE)
14646 +#ccflags-y += -DDWC_DEV_SRPCAP
14647 +
14648 +obj-$(CONFIG_USB_DWCOTG) += dwc_otg.o
14649 +
14650 +dwc_otg-objs := dwc_otg_driver.o dwc_otg_attr.o
14651 +dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o
14652 +dwc_otg-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o
14653 +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
14654 +dwc_otg-objs += dwc_otg_adp.o
14655 +ifneq ($(CFI),)
14656 +dwc_otg-objs += dwc_otg_cfi.o
14657 +endif
14658 +
14659 +kernrelwd := $(subst ., ,$(KERNELRELEASE))
14660 +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
14661 +
14662 +ifneq ($(kernrel3),2.6.20)
14663 +ccflags-y += $(CPPFLAGS)
14664 +endif
14665 +
14666 +else
14667 +
14668 +PWD := $(shell pwd)
14669 +PORTLIB := $(PWD)/../dwc_common_port
14670 +
14671 +# Command paths
14672 +CTAGS := $(CTAGS)
14673 +DOXYGEN := $(DOXYGEN)
14674 +
14675 +default: portlib
14676 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
14677 +
14678 +install: default
14679 + $(MAKE) -C$(KDIR) M=$(PORTLIB) modules_install
14680 + $(MAKE) -C$(KDIR) M=$(PWD) modules_install
14681 +
14682 +portlib:
14683 + $(MAKE) -C$(KDIR) M=$(PORTLIB) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
14684 + cp $(PORTLIB)/Module.symvers $(PWD)/
14685 +
14686 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
14687 + $(DOXYGEN) doc/doxygen.cfg
14688 +
14689 +tags: $(wildcard *.[hc])
14690 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
14691 +
14692 +
14693 +clean:
14694 + rm -rf *.o *.ko .*cmd *.mod.c .tmp_versions Module.symvers
14695 +
14696 +endif
14697 diff --git a/drivers/usb/host/dwc_otg/doc/doxygen.cfg b/drivers/usb/host/dwc_otg/doc/doxygen.cfg
14698 new file mode 100644
14699 index 0000000..712b057
14700 --- /dev/null
14701 +++ b/drivers/usb/host/dwc_otg/doc/doxygen.cfg
14702 @@ -0,0 +1,224 @@
14703 +# Doxyfile 1.3.9.1
14704 +
14705 +#---------------------------------------------------------------------------
14706 +# Project related configuration options
14707 +#---------------------------------------------------------------------------
14708 +PROJECT_NAME = "DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver"
14709 +PROJECT_NUMBER = v3.00a
14710 +OUTPUT_DIRECTORY = ./doc/
14711 +CREATE_SUBDIRS = NO
14712 +OUTPUT_LANGUAGE = English
14713 +BRIEF_MEMBER_DESC = YES
14714 +REPEAT_BRIEF = YES
14715 +ABBREVIATE_BRIEF = "The $name class" \
14716 + "The $name widget" \
14717 + "The $name file" \
14718 + is \
14719 + provides \
14720 + specifies \
14721 + contains \
14722 + represents \
14723 + a \
14724 + an \
14725 + the
14726 +ALWAYS_DETAILED_SEC = NO
14727 +INLINE_INHERITED_MEMB = NO
14728 +FULL_PATH_NAMES = NO
14729 +STRIP_FROM_PATH =
14730 +STRIP_FROM_INC_PATH =
14731 +SHORT_NAMES = NO
14732 +JAVADOC_AUTOBRIEF = YES
14733 +MULTILINE_CPP_IS_BRIEF = NO
14734 +INHERIT_DOCS = YES
14735 +DISTRIBUTE_GROUP_DOC = NO
14736 +TAB_SIZE = 8
14737 +ALIASES =
14738 +OPTIMIZE_OUTPUT_FOR_C = YES
14739 +OPTIMIZE_OUTPUT_JAVA = NO
14740 +SUBGROUPING = YES
14741 +#---------------------------------------------------------------------------
14742 +# Build related configuration options
14743 +#---------------------------------------------------------------------------
14744 +EXTRACT_ALL = NO
14745 +EXTRACT_PRIVATE = YES
14746 +EXTRACT_STATIC = YES
14747 +EXTRACT_LOCAL_CLASSES = YES
14748 +EXTRACT_LOCAL_METHODS = NO
14749 +HIDE_UNDOC_MEMBERS = NO
14750 +HIDE_UNDOC_CLASSES = NO
14751 +HIDE_FRIEND_COMPOUNDS = NO
14752 +HIDE_IN_BODY_DOCS = NO
14753 +INTERNAL_DOCS = NO
14754 +CASE_SENSE_NAMES = NO
14755 +HIDE_SCOPE_NAMES = NO
14756 +SHOW_INCLUDE_FILES = YES
14757 +INLINE_INFO = YES
14758 +SORT_MEMBER_DOCS = NO
14759 +SORT_BRIEF_DOCS = NO
14760 +SORT_BY_SCOPE_NAME = NO
14761 +GENERATE_TODOLIST = YES
14762 +GENERATE_TESTLIST = YES
14763 +GENERATE_BUGLIST = YES
14764 +GENERATE_DEPRECATEDLIST= YES
14765 +ENABLED_SECTIONS =
14766 +MAX_INITIALIZER_LINES = 30
14767 +SHOW_USED_FILES = YES
14768 +SHOW_DIRECTORIES = YES
14769 +#---------------------------------------------------------------------------
14770 +# configuration options related to warning and progress messages
14771 +#---------------------------------------------------------------------------
14772 +QUIET = YES
14773 +WARNINGS = YES
14774 +WARN_IF_UNDOCUMENTED = NO
14775 +WARN_IF_DOC_ERROR = YES
14776 +WARN_FORMAT = "$file:$line: $text"
14777 +WARN_LOGFILE =
14778 +#---------------------------------------------------------------------------
14779 +# configuration options related to the input files
14780 +#---------------------------------------------------------------------------
14781 +INPUT = .
14782 +FILE_PATTERNS = *.c \
14783 + *.h \
14784 + ./linux/*.c \
14785 + ./linux/*.h
14786 +RECURSIVE = NO
14787 +EXCLUDE = ./test/ \
14788 + ./dwc_otg/.AppleDouble/
14789 +EXCLUDE_SYMLINKS = YES
14790 +EXCLUDE_PATTERNS = *.mod.*
14791 +EXAMPLE_PATH =
14792 +EXAMPLE_PATTERNS = *
14793 +EXAMPLE_RECURSIVE = NO
14794 +IMAGE_PATH =
14795 +INPUT_FILTER =
14796 +FILTER_PATTERNS =
14797 +FILTER_SOURCE_FILES = NO
14798 +#---------------------------------------------------------------------------
14799 +# configuration options related to source browsing
14800 +#---------------------------------------------------------------------------
14801 +SOURCE_BROWSER = YES
14802 +INLINE_SOURCES = NO
14803 +STRIP_CODE_COMMENTS = YES
14804 +REFERENCED_BY_RELATION = NO
14805 +REFERENCES_RELATION = NO
14806 +VERBATIM_HEADERS = NO
14807 +#---------------------------------------------------------------------------
14808 +# configuration options related to the alphabetical class index
14809 +#---------------------------------------------------------------------------
14810 +ALPHABETICAL_INDEX = NO
14811 +COLS_IN_ALPHA_INDEX = 5
14812 +IGNORE_PREFIX =
14813 +#---------------------------------------------------------------------------
14814 +# configuration options related to the HTML output
14815 +#---------------------------------------------------------------------------
14816 +GENERATE_HTML = YES
14817 +HTML_OUTPUT = html
14818 +HTML_FILE_EXTENSION = .html
14819 +HTML_HEADER =
14820 +HTML_FOOTER =
14821 +HTML_STYLESHEET =
14822 +HTML_ALIGN_MEMBERS = YES
14823 +GENERATE_HTMLHELP = NO
14824 +CHM_FILE =
14825 +HHC_LOCATION =
14826 +GENERATE_CHI = NO
14827 +BINARY_TOC = NO
14828 +TOC_EXPAND = NO
14829 +DISABLE_INDEX = NO
14830 +ENUM_VALUES_PER_LINE = 4
14831 +GENERATE_TREEVIEW = YES
14832 +TREEVIEW_WIDTH = 250
14833 +#---------------------------------------------------------------------------
14834 +# configuration options related to the LaTeX output
14835 +#---------------------------------------------------------------------------
14836 +GENERATE_LATEX = NO
14837 +LATEX_OUTPUT = latex
14838 +LATEX_CMD_NAME = latex
14839 +MAKEINDEX_CMD_NAME = makeindex
14840 +COMPACT_LATEX = NO
14841 +PAPER_TYPE = a4wide
14842 +EXTRA_PACKAGES =
14843 +LATEX_HEADER =
14844 +PDF_HYPERLINKS = NO
14845 +USE_PDFLATEX = NO
14846 +LATEX_BATCHMODE = NO
14847 +LATEX_HIDE_INDICES = NO
14848 +#---------------------------------------------------------------------------
14849 +# configuration options related to the RTF output
14850 +#---------------------------------------------------------------------------
14851 +GENERATE_RTF = NO
14852 +RTF_OUTPUT = rtf
14853 +COMPACT_RTF = NO
14854 +RTF_HYPERLINKS = NO
14855 +RTF_STYLESHEET_FILE =
14856 +RTF_EXTENSIONS_FILE =
14857 +#---------------------------------------------------------------------------
14858 +# configuration options related to the man page output
14859 +#---------------------------------------------------------------------------
14860 +GENERATE_MAN = NO
14861 +MAN_OUTPUT = man
14862 +MAN_EXTENSION = .3
14863 +MAN_LINKS = NO
14864 +#---------------------------------------------------------------------------
14865 +# configuration options related to the XML output
14866 +#---------------------------------------------------------------------------
14867 +GENERATE_XML = NO
14868 +XML_OUTPUT = xml
14869 +XML_SCHEMA =
14870 +XML_DTD =
14871 +XML_PROGRAMLISTING = YES
14872 +#---------------------------------------------------------------------------
14873 +# configuration options for the AutoGen Definitions output
14874 +#---------------------------------------------------------------------------
14875 +GENERATE_AUTOGEN_DEF = NO
14876 +#---------------------------------------------------------------------------
14877 +# configuration options related to the Perl module output
14878 +#---------------------------------------------------------------------------
14879 +GENERATE_PERLMOD = NO
14880 +PERLMOD_LATEX = NO
14881 +PERLMOD_PRETTY = YES
14882 +PERLMOD_MAKEVAR_PREFIX =
14883 +#---------------------------------------------------------------------------
14884 +# Configuration options related to the preprocessor
14885 +#---------------------------------------------------------------------------
14886 +ENABLE_PREPROCESSING = YES
14887 +MACRO_EXPANSION = YES
14888 +EXPAND_ONLY_PREDEF = YES
14889 +SEARCH_INCLUDES = YES
14890 +INCLUDE_PATH =
14891 +INCLUDE_FILE_PATTERNS =
14892 +PREDEFINED = DEVICE_ATTR DWC_EN_ISOC
14893 +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
14894 +SKIP_FUNCTION_MACROS = NO
14895 +#---------------------------------------------------------------------------
14896 +# Configuration::additions related to external references
14897 +#---------------------------------------------------------------------------
14898 +TAGFILES =
14899 +GENERATE_TAGFILE =
14900 +ALLEXTERNALS = NO
14901 +EXTERNAL_GROUPS = YES
14902 +PERL_PATH = /usr/bin/perl
14903 +#---------------------------------------------------------------------------
14904 +# Configuration options related to the dot tool
14905 +#---------------------------------------------------------------------------
14906 +CLASS_DIAGRAMS = YES
14907 +HIDE_UNDOC_RELATIONS = YES
14908 +HAVE_DOT = NO
14909 +CLASS_GRAPH = YES
14910 +COLLABORATION_GRAPH = YES
14911 +UML_LOOK = NO
14912 +TEMPLATE_RELATIONS = NO
14913 +INCLUDE_GRAPH = YES
14914 +INCLUDED_BY_GRAPH = YES
14915 +CALL_GRAPH = NO
14916 +GRAPHICAL_HIERARCHY = YES
14917 +DOT_IMAGE_FORMAT = png
14918 +DOT_PATH =
14919 +DOTFILE_DIRS =
14920 +MAX_DOT_GRAPH_DEPTH = 1000
14921 +GENERATE_LEGEND = YES
14922 +DOT_CLEANUP = YES
14923 +#---------------------------------------------------------------------------
14924 +# Configuration::additions related to the search engine
14925 +#---------------------------------------------------------------------------
14926 +SEARCHENGINE = NO
14927 diff --git a/drivers/usb/host/dwc_otg/dummy_audio.c b/drivers/usb/host/dwc_otg/dummy_audio.c
14928 new file mode 100644
14929 index 0000000..225decf
14930 --- /dev/null
14931 +++ b/drivers/usb/host/dwc_otg/dummy_audio.c
14932 @@ -0,0 +1,1575 @@
14933 +/*
14934 + * zero.c -- Gadget Zero, for USB development
14935 + *
14936 + * Copyright (C) 2003-2004 David Brownell
14937 + * All rights reserved.
14938 + *
14939 + * Redistribution and use in source and binary forms, with or without
14940 + * modification, are permitted provided that the following conditions
14941 + * are met:
14942 + * 1. Redistributions of source code must retain the above copyright
14943 + * notice, this list of conditions, and the following disclaimer,
14944 + * without modification.
14945 + * 2. Redistributions in binary form must reproduce the above copyright
14946 + * notice, this list of conditions and the following disclaimer in the
14947 + * documentation and/or other materials provided with the distribution.
14948 + * 3. The names of the above-listed copyright holders may not be used
14949 + * to endorse or promote products derived from this software without
14950 + * specific prior written permission.
14951 + *
14952 + * ALTERNATIVELY, this software may be distributed under the terms of the
14953 + * GNU General Public License ("GPL") as published by the Free Software
14954 + * Foundation, either version 2 of that License or (at your option) any
14955 + * later version.
14956 + *
14957 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
14958 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
14959 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
14960 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
14961 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
14962 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
14963 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
14964 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
14965 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
14966 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
14967 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14968 + */
14969 +
14970 +
14971 +/*
14972 + * Gadget Zero only needs two bulk endpoints, and is an example of how you
14973 + * can write a hardware-agnostic gadget driver running inside a USB device.
14974 + *
14975 + * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
14976 + * affect most of the driver.
14977 + *
14978 + * Use it with the Linux host/master side "usbtest" driver to get a basic
14979 + * functional test of your device-side usb stack, or with "usb-skeleton".
14980 + *
14981 + * It supports two similar configurations. One sinks whatever the usb host
14982 + * writes, and in return sources zeroes. The other loops whatever the host
14983 + * writes back, so the host can read it. Module options include:
14984 + *
14985 + * buflen=N default N=4096, buffer size used
14986 + * qlen=N default N=32, how many buffers in the loopback queue
14987 + * loopdefault default false, list loopback config first
14988 + *
14989 + * Many drivers will only have one configuration, letting them be much
14990 + * simpler if they also don't support high speed operation (like this
14991 + * driver does).
14992 + */
14993 +
14994 +#include <linux/config.h>
14995 +#include <linux/module.h>
14996 +#include <linux/kernel.h>
14997 +#include <linux/delay.h>
14998 +#include <linux/ioport.h>
14999 +#include <linux/sched.h>
15000 +#include <linux/slab.h>
15001 +#include <linux/smp_lock.h>
15002 +#include <linux/errno.h>
15003 +#include <linux/init.h>
15004 +#include <linux/timer.h>
15005 +#include <linux/list.h>
15006 +#include <linux/interrupt.h>
15007 +#include <linux/uts.h>
15008 +#include <linux/version.h>
15009 +#include <linux/device.h>
15010 +#include <linux/moduleparam.h>
15011 +#include <linux/proc_fs.h>
15012 +
15013 +#include <asm/byteorder.h>
15014 +#include <asm/io.h>
15015 +#include <asm/irq.h>
15016 +#include <asm/system.h>
15017 +#include <asm/unaligned.h>
15018 +
15019 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
15020 +# include <linux/usb/ch9.h>
15021 +#else
15022 +# include <linux/usb_ch9.h>
15023 +#endif
15024 +
15025 +#include <linux/usb_gadget.h>
15026 +
15027 +
15028 +/*-------------------------------------------------------------------------*/
15029 +/*-------------------------------------------------------------------------*/
15030 +
15031 +
15032 +static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len)
15033 +{
15034 + int count = 0;
15035 + u8 c;
15036 + u16 uchar;
15037 +
15038 + /* this insists on correct encodings, though not minimal ones.
15039 + * BUT it currently rejects legit 4-byte UTF-8 code points,
15040 + * which need surrogate pairs. (Unicode 3.1 can use them.)
15041 + */
15042 + while (len != 0 && (c = (u8) *s++) != 0) {
15043 + if (unlikely(c & 0x80)) {
15044 + // 2-byte sequence:
15045 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
15046 + if ((c & 0xe0) == 0xc0) {
15047 + uchar = (c & 0x1f) << 6;
15048 +
15049 + c = (u8) *s++;
15050 + if ((c & 0xc0) != 0xc0)
15051 + goto fail;
15052 + c &= 0x3f;
15053 + uchar |= c;
15054 +
15055 + // 3-byte sequence (most CJKV characters):
15056 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
15057 + } else if ((c & 0xf0) == 0xe0) {
15058 + uchar = (c & 0x0f) << 12;
15059 +
15060 + c = (u8) *s++;
15061 + if ((c & 0xc0) != 0xc0)
15062 + goto fail;
15063 + c &= 0x3f;
15064 + uchar |= c << 6;
15065 +
15066 + c = (u8) *s++;
15067 + if ((c & 0xc0) != 0xc0)
15068 + goto fail;
15069 + c &= 0x3f;
15070 + uchar |= c;
15071 +
15072 + /* no bogus surrogates */
15073 + if (0xd800 <= uchar && uchar <= 0xdfff)
15074 + goto fail;
15075 +
15076 + // 4-byte sequence (surrogate pairs, currently rare):
15077 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
15078 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
15079 + // (uuuuu = wwww + 1)
15080 + // FIXME accept the surrogate code points (only)
15081 +
15082 + } else
15083 + goto fail;
15084 + } else
15085 + uchar = c;
15086 + put_unaligned (cpu_to_le16 (uchar), cp++);
15087 + count++;
15088 + len--;
15089 + }
15090 + return count;
15091 +fail:
15092 + return -1;
15093 +}
15094 +
15095 +
15096 +/**
15097 + * usb_gadget_get_string - fill out a string descriptor
15098 + * @table: of c strings encoded using UTF-8
15099 + * @id: string id, from low byte of wValue in get string descriptor
15100 + * @buf: at least 256 bytes
15101 + *
15102 + * Finds the UTF-8 string matching the ID, and converts it into a
15103 + * string descriptor in utf16-le.
15104 + * Returns length of descriptor (always even) or negative errno
15105 + *
15106 + * If your driver needs stings in multiple languages, you'll probably
15107 + * "switch (wIndex) { ... }" in your ep0 string descriptor logic,
15108 + * using this routine after choosing which set of UTF-8 strings to use.
15109 + * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
15110 + * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
15111 + * characters (which are also widely used in C strings).
15112 + */
15113 +int
15114 +usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
15115 +{
15116 + struct usb_string *s;
15117 + int len;
15118 +
15119 + /* descriptor 0 has the language id */
15120 + if (id == 0) {
15121 + buf [0] = 4;
15122 + buf [1] = USB_DT_STRING;
15123 + buf [2] = (u8) table->language;
15124 + buf [3] = (u8) (table->language >> 8);
15125 + return 4;
15126 + }
15127 + for (s = table->strings; s && s->s; s++)
15128 + if (s->id == id)
15129 + break;
15130 +
15131 + /* unrecognized: stall. */
15132 + if (!s || !s->s)
15133 + return -EINVAL;
15134 +
15135 + /* string descriptors have length, tag, then UTF16-LE text */
15136 + len = min ((size_t) 126, strlen (s->s));
15137 + memset (buf + 2, 0, 2 * len); /* zero all the bytes */
15138 + len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len);
15139 + if (len < 0)
15140 + return -EINVAL;
15141 + buf [0] = (len + 1) * 2;
15142 + buf [1] = USB_DT_STRING;
15143 + return buf [0];
15144 +}
15145 +
15146 +
15147 +/*-------------------------------------------------------------------------*/
15148 +/*-------------------------------------------------------------------------*/
15149 +
15150 +
15151 +/**
15152 + * usb_descriptor_fillbuf - fill buffer with descriptors
15153 + * @buf: Buffer to be filled
15154 + * @buflen: Size of buf
15155 + * @src: Array of descriptor pointers, terminated by null pointer.
15156 + *
15157 + * Copies descriptors into the buffer, returning the length or a
15158 + * negative error code if they can't all be copied. Useful when
15159 + * assembling descriptors for an associated set of interfaces used
15160 + * as part of configuring a composite device; or in other cases where
15161 + * sets of descriptors need to be marshaled.
15162 + */
15163 +int
15164 +usb_descriptor_fillbuf(void *buf, unsigned buflen,
15165 + const struct usb_descriptor_header **src)
15166 +{
15167 + u8 *dest = buf;
15168 +
15169 + if (!src)
15170 + return -EINVAL;
15171 +
15172 + /* fill buffer from src[] until null descriptor ptr */
15173 + for (; 0 != *src; src++) {
15174 + unsigned len = (*src)->bLength;
15175 +
15176 + if (len > buflen)
15177 + return -EINVAL;
15178 + memcpy(dest, *src, len);
15179 + buflen -= len;
15180 + dest += len;
15181 + }
15182 + return dest - (u8 *)buf;
15183 +}
15184 +
15185 +
15186 +/**
15187 + * usb_gadget_config_buf - builts a complete configuration descriptor
15188 + * @config: Header for the descriptor, including characteristics such
15189 + * as power requirements and number of interfaces.
15190 + * @desc: Null-terminated vector of pointers to the descriptors (interface,
15191 + * endpoint, etc) defining all functions in this device configuration.
15192 + * @buf: Buffer for the resulting configuration descriptor.
15193 + * @length: Length of buffer. If this is not big enough to hold the
15194 + * entire configuration descriptor, an error code will be returned.
15195 + *
15196 + * This copies descriptors into the response buffer, building a descriptor
15197 + * for that configuration. It returns the buffer length or a negative
15198 + * status code. The config.wTotalLength field is set to match the length
15199 + * of the result, but other descriptor fields (including power usage and
15200 + * interface count) must be set by the caller.
15201 + *
15202 + * Gadget drivers could use this when constructing a config descriptor
15203 + * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the
15204 + * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
15205 + */
15206 +int usb_gadget_config_buf(
15207 + const struct usb_config_descriptor *config,
15208 + void *buf,
15209 + unsigned length,
15210 + const struct usb_descriptor_header **desc
15211 +)
15212 +{
15213 + struct usb_config_descriptor *cp = buf;
15214 + int len;
15215 +
15216 + /* config descriptor first */
15217 + if (length < USB_DT_CONFIG_SIZE || !desc)
15218 + return -EINVAL;
15219 + *cp = *config;
15220 +
15221 + /* then interface/endpoint/class/vendor/... */
15222 + len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
15223 + length - USB_DT_CONFIG_SIZE, desc);
15224 + if (len < 0)
15225 + return len;
15226 + len += USB_DT_CONFIG_SIZE;
15227 + if (len > 0xffff)
15228 + return -EINVAL;
15229 +
15230 + /* patch up the config descriptor */
15231 + cp->bLength = USB_DT_CONFIG_SIZE;
15232 + cp->bDescriptorType = USB_DT_CONFIG;
15233 + cp->wTotalLength = cpu_to_le16(len);
15234 + cp->bmAttributes |= USB_CONFIG_ATT_ONE;
15235 + return len;
15236 +}
15237 +
15238 +/*-------------------------------------------------------------------------*/
15239 +/*-------------------------------------------------------------------------*/
15240 +
15241 +
15242 +#define RBUF_LEN (1024*1024)
15243 +static int rbuf_start;
15244 +static int rbuf_len;
15245 +static __u8 rbuf[RBUF_LEN];
15246 +
15247 +/*-------------------------------------------------------------------------*/
15248 +
15249 +#define DRIVER_VERSION "St Patrick's Day 2004"
15250 +
15251 +static const char shortname [] = "zero";
15252 +static const char longname [] = "YAMAHA YST-MS35D USB Speaker ";
15253 +
15254 +static const char source_sink [] = "source and sink data";
15255 +static const char loopback [] = "loop input to output";
15256 +
15257 +/*-------------------------------------------------------------------------*/
15258 +
15259 +/*
15260 + * driver assumes self-powered hardware, and
15261 + * has no way for users to trigger remote wakeup.
15262 + *
15263 + * this version autoconfigures as much as possible,
15264 + * which is reasonable for most "bulk-only" drivers.
15265 + */
15266 +static const char *EP_IN_NAME; /* source */
15267 +static const char *EP_OUT_NAME; /* sink */
15268 +
15269 +/*-------------------------------------------------------------------------*/
15270 +
15271 +/* big enough to hold our biggest descriptor */
15272 +#define USB_BUFSIZ 512
15273 +
15274 +struct zero_dev {
15275 + spinlock_t lock;
15276 + struct usb_gadget *gadget;
15277 + struct usb_request *req; /* for control responses */
15278 +
15279 + /* when configured, we have one of two configs:
15280 + * - source data (in to host) and sink it (out from host)
15281 + * - or loop it back (out from host back in to host)
15282 + */
15283 + u8 config;
15284 + struct usb_ep *in_ep, *out_ep;
15285 +
15286 + /* autoresume timer */
15287 + struct timer_list resume;
15288 +};
15289 +
15290 +#define xprintk(d,level,fmt,args...) \
15291 + dev_printk(level , &(d)->gadget->dev , fmt , ## args)
15292 +
15293 +#ifdef DEBUG
15294 +#define DBG(dev,fmt,args...) \
15295 + xprintk(dev , KERN_DEBUG , fmt , ## args)
15296 +#else
15297 +#define DBG(dev,fmt,args...) \
15298 + do { } while (0)
15299 +#endif /* DEBUG */
15300 +
15301 +#ifdef VERBOSE
15302 +#define VDBG DBG
15303 +#else
15304 +#define VDBG(dev,fmt,args...) \
15305 + do { } while (0)
15306 +#endif /* VERBOSE */
15307 +
15308 +#define ERROR(dev,fmt,args...) \
15309 + xprintk(dev , KERN_ERR , fmt , ## args)
15310 +#define WARN(dev,fmt,args...) \
15311 + xprintk(dev , KERN_WARNING , fmt , ## args)
15312 +#define INFO(dev,fmt,args...) \
15313 + xprintk(dev , KERN_INFO , fmt , ## args)
15314 +
15315 +/*-------------------------------------------------------------------------*/
15316 +
15317 +static unsigned buflen = 4096;
15318 +static unsigned qlen = 32;
15319 +static unsigned pattern = 0;
15320 +
15321 +module_param (buflen, uint, S_IRUGO|S_IWUSR);
15322 +module_param (qlen, uint, S_IRUGO|S_IWUSR);
15323 +module_param (pattern, uint, S_IRUGO|S_IWUSR);
15324 +
15325 +/*
15326 + * if it's nonzero, autoresume says how many seconds to wait
15327 + * before trying to wake up the host after suspend.
15328 + */
15329 +static unsigned autoresume = 0;
15330 +module_param (autoresume, uint, 0);
15331 +
15332 +/*
15333 + * Normally the "loopback" configuration is second (index 1) so
15334 + * it's not the default. Here's where to change that order, to
15335 + * work better with hosts where config changes are problematic.
15336 + * Or controllers (like superh) that only support one config.
15337 + */
15338 +static int loopdefault = 0;
15339 +
15340 +module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
15341 +
15342 +/*-------------------------------------------------------------------------*/
15343 +
15344 +/* Thanks to NetChip Technologies for donating this product ID.
15345 + *
15346 + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
15347 + * Instead: allocate your own, using normal USB-IF procedures.
15348 + */
15349 +#ifndef CONFIG_USB_ZERO_HNPTEST
15350 +#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
15351 +#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
15352 +#else
15353 +#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */
15354 +#define DRIVER_PRODUCT_NUM 0xbadd
15355 +#endif
15356 +
15357 +/*-------------------------------------------------------------------------*/
15358 +
15359 +/*
15360 + * DESCRIPTORS ... most are static, but strings and (full)
15361 + * configuration descriptors are built on demand.
15362 + */
15363 +
15364 +/*
15365 +#define STRING_MANUFACTURER 25
15366 +#define STRING_PRODUCT 42
15367 +#define STRING_SERIAL 101
15368 +*/
15369 +#define STRING_MANUFACTURER 1
15370 +#define STRING_PRODUCT 2
15371 +#define STRING_SERIAL 3
15372 +
15373 +#define STRING_SOURCE_SINK 250
15374 +#define STRING_LOOPBACK 251
15375 +
15376 +/*
15377 + * This device advertises two configurations; these numbers work
15378 + * on a pxa250 as well as more flexible hardware.
15379 + */
15380 +#define CONFIG_SOURCE_SINK 3
15381 +#define CONFIG_LOOPBACK 2
15382 +
15383 +/*
15384 +static struct usb_device_descriptor
15385 +device_desc = {
15386 + .bLength = sizeof device_desc,
15387 + .bDescriptorType = USB_DT_DEVICE,
15388 +
15389 + .bcdUSB = __constant_cpu_to_le16 (0x0200),
15390 + .bDeviceClass = USB_CLASS_VENDOR_SPEC,
15391 +
15392 + .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
15393 + .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
15394 + .iManufacturer = STRING_MANUFACTURER,
15395 + .iProduct = STRING_PRODUCT,
15396 + .iSerialNumber = STRING_SERIAL,
15397 + .bNumConfigurations = 2,
15398 +};
15399 +*/
15400 +static struct usb_device_descriptor
15401 +device_desc = {
15402 + .bLength = sizeof device_desc,
15403 + .bDescriptorType = USB_DT_DEVICE,
15404 + .bcdUSB = __constant_cpu_to_le16 (0x0100),
15405 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
15406 + .bDeviceSubClass = 0,
15407 + .bDeviceProtocol = 0,
15408 + .bMaxPacketSize0 = 64,
15409 + .bcdDevice = __constant_cpu_to_le16 (0x0100),
15410 + .idVendor = __constant_cpu_to_le16 (0x0499),
15411 + .idProduct = __constant_cpu_to_le16 (0x3002),
15412 + .iManufacturer = STRING_MANUFACTURER,
15413 + .iProduct = STRING_PRODUCT,
15414 + .iSerialNumber = STRING_SERIAL,
15415 + .bNumConfigurations = 1,
15416 +};
15417 +
15418 +static struct usb_config_descriptor
15419 +z_config = {
15420 + .bLength = sizeof z_config,
15421 + .bDescriptorType = USB_DT_CONFIG,
15422 +
15423 + /* compute wTotalLength on the fly */
15424 + .bNumInterfaces = 2,
15425 + .bConfigurationValue = 1,
15426 + .iConfiguration = 0,
15427 + .bmAttributes = 0x40,
15428 + .bMaxPower = 0, /* self-powered */
15429 +};
15430 +
15431 +
15432 +static struct usb_otg_descriptor
15433 +otg_descriptor = {
15434 + .bLength = sizeof otg_descriptor,
15435 + .bDescriptorType = USB_DT_OTG,
15436 +
15437 + .bmAttributes = USB_OTG_SRP,
15438 +};
15439 +
15440 +/* one interface in each configuration */
15441 +#ifdef CONFIG_USB_GADGET_DUALSPEED
15442 +
15443 +/*
15444 + * usb 2.0 devices need to expose both high speed and full speed
15445 + * descriptors, unless they only run at full speed.
15446 + *
15447 + * that means alternate endpoint descriptors (bigger packets)
15448 + * and a "device qualifier" ... plus more construction options
15449 + * for the config descriptor.
15450 + */
15451 +
15452 +static struct usb_qualifier_descriptor
15453 +dev_qualifier = {
15454 + .bLength = sizeof dev_qualifier,
15455 + .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
15456 +
15457 + .bcdUSB = __constant_cpu_to_le16 (0x0200),
15458 + .bDeviceClass = USB_CLASS_VENDOR_SPEC,
15459 +
15460 + .bNumConfigurations = 2,
15461 +};
15462 +
15463 +
15464 +struct usb_cs_as_general_descriptor {
15465 + __u8 bLength;
15466 + __u8 bDescriptorType;
15467 +
15468 + __u8 bDescriptorSubType;
15469 + __u8 bTerminalLink;
15470 + __u8 bDelay;
15471 + __u16 wFormatTag;
15472 +} __attribute__ ((packed));
15473 +
15474 +struct usb_cs_as_format_descriptor {
15475 + __u8 bLength;
15476 + __u8 bDescriptorType;
15477 +
15478 + __u8 bDescriptorSubType;
15479 + __u8 bFormatType;
15480 + __u8 bNrChannels;
15481 + __u8 bSubframeSize;
15482 + __u8 bBitResolution;
15483 + __u8 bSamfreqType;
15484 + __u8 tLowerSamFreq[3];
15485 + __u8 tUpperSamFreq[3];
15486 +} __attribute__ ((packed));
15487 +
15488 +static const struct usb_interface_descriptor
15489 +z_audio_control_if_desc = {
15490 + .bLength = sizeof z_audio_control_if_desc,
15491 + .bDescriptorType = USB_DT_INTERFACE,
15492 + .bInterfaceNumber = 0,
15493 + .bAlternateSetting = 0,
15494 + .bNumEndpoints = 0,
15495 + .bInterfaceClass = USB_CLASS_AUDIO,
15496 + .bInterfaceSubClass = 0x1,
15497 + .bInterfaceProtocol = 0,
15498 + .iInterface = 0,
15499 +};
15500 +
15501 +static const struct usb_interface_descriptor
15502 +z_audio_if_desc = {
15503 + .bLength = sizeof z_audio_if_desc,
15504 + .bDescriptorType = USB_DT_INTERFACE,
15505 + .bInterfaceNumber = 1,
15506 + .bAlternateSetting = 0,
15507 + .bNumEndpoints = 0,
15508 + .bInterfaceClass = USB_CLASS_AUDIO,
15509 + .bInterfaceSubClass = 0x2,
15510 + .bInterfaceProtocol = 0,
15511 + .iInterface = 0,
15512 +};
15513 +
15514 +static const struct usb_interface_descriptor
15515 +z_audio_if_desc2 = {
15516 + .bLength = sizeof z_audio_if_desc,
15517 + .bDescriptorType = USB_DT_INTERFACE,
15518 + .bInterfaceNumber = 1,
15519 + .bAlternateSetting = 1,
15520 + .bNumEndpoints = 1,
15521 + .bInterfaceClass = USB_CLASS_AUDIO,
15522 + .bInterfaceSubClass = 0x2,
15523 + .bInterfaceProtocol = 0,
15524 + .iInterface = 0,
15525 +};
15526 +
15527 +static const struct usb_cs_as_general_descriptor
15528 +z_audio_cs_as_if_desc = {
15529 + .bLength = 7,
15530 + .bDescriptorType = 0x24,
15531 +
15532 + .bDescriptorSubType = 0x01,
15533 + .bTerminalLink = 0x01,
15534 + .bDelay = 0x0,
15535 + .wFormatTag = __constant_cpu_to_le16 (0x0001)
15536 +};
15537 +
15538 +
15539 +static const struct usb_cs_as_format_descriptor
15540 +z_audio_cs_as_format_desc = {
15541 + .bLength = 0xe,
15542 + .bDescriptorType = 0x24,
15543 +
15544 + .bDescriptorSubType = 2,
15545 + .bFormatType = 1,
15546 + .bNrChannels = 1,
15547 + .bSubframeSize = 1,
15548 + .bBitResolution = 8,
15549 + .bSamfreqType = 0,
15550 + .tLowerSamFreq = {0x7e, 0x13, 0x00},
15551 + .tUpperSamFreq = {0xe2, 0xd6, 0x00},
15552 +};
15553 +
15554 +static const struct usb_endpoint_descriptor
15555 +z_iso_ep = {
15556 + .bLength = 0x09,
15557 + .bDescriptorType = 0x05,
15558 + .bEndpointAddress = 0x04,
15559 + .bmAttributes = 0x09,
15560 + .wMaxPacketSize = 0x0038,
15561 + .bInterval = 0x01,
15562 + .bRefresh = 0x00,
15563 + .bSynchAddress = 0x00,
15564 +};
15565 +
15566 +static char z_iso_ep2[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15567 +
15568 +// 9 bytes
15569 +static char z_ac_interface_header_desc[] =
15570 +{ 0x09, 0x24, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x01, 0x01 };
15571 +
15572 +// 12 bytes
15573 +static char z_0[] = {0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02,
15574 + 0x03, 0x00, 0x00, 0x00};
15575 +// 13 bytes
15576 +static char z_1[] = {0x0d, 0x24, 0x06, 0x02, 0x01, 0x02, 0x15, 0x00,
15577 + 0x02, 0x00, 0x02, 0x00, 0x00};
15578 +// 9 bytes
15579 +static char z_2[] = {0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x02,
15580 + 0x00};
15581 +
15582 +static char za_0[] = {0x09, 0x04, 0x01, 0x02, 0x01, 0x01, 0x02, 0x00,
15583 + 0x00};
15584 +
15585 +static char za_1[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15586 +
15587 +static char za_2[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x01, 0x08, 0x00,
15588 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15589 +
15590 +static char za_3[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
15591 + 0x00};
15592 +
15593 +static char za_4[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15594 +
15595 +static char za_5[] = {0x09, 0x04, 0x01, 0x03, 0x01, 0x01, 0x02, 0x00,
15596 + 0x00};
15597 +
15598 +static char za_6[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15599 +
15600 +static char za_7[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x00,
15601 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15602 +
15603 +static char za_8[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
15604 + 0x00};
15605 +
15606 +static char za_9[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15607 +
15608 +static char za_10[] = {0x09, 0x04, 0x01, 0x04, 0x01, 0x01, 0x02, 0x00,
15609 + 0x00};
15610 +
15611 +static char za_11[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15612 +
15613 +static char za_12[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x00,
15614 + 0x73, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15615 +
15616 +static char za_13[] = {0x09, 0x05, 0x04, 0x09, 0xe0, 0x00, 0x01, 0x00,
15617 + 0x00};
15618 +
15619 +static char za_14[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15620 +
15621 +static char za_15[] = {0x09, 0x04, 0x01, 0x05, 0x01, 0x01, 0x02, 0x00,
15622 + 0x00};
15623 +
15624 +static char za_16[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15625 +
15626 +static char za_17[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x03, 0x14, 0x00,
15627 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15628 +
15629 +static char za_18[] = {0x09, 0x05, 0x04, 0x09, 0xa8, 0x00, 0x01, 0x00,
15630 + 0x00};
15631 +
15632 +static char za_19[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15633 +
15634 +static char za_20[] = {0x09, 0x04, 0x01, 0x06, 0x01, 0x01, 0x02, 0x00,
15635 + 0x00};
15636 +
15637 +static char za_21[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15638 +
15639 +static char za_22[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x03, 0x14, 0x00,
15640 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15641 +
15642 +static char za_23[] = {0x09, 0x05, 0x04, 0x09, 0x50, 0x01, 0x01, 0x00,
15643 + 0x00};
15644 +
15645 +static char za_24[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15646 +
15647 +
15648 +
15649 +static const struct usb_descriptor_header *z_function [] = {
15650 + (struct usb_descriptor_header *) &z_audio_control_if_desc,
15651 + (struct usb_descriptor_header *) &z_ac_interface_header_desc,
15652 + (struct usb_descriptor_header *) &z_0,
15653 + (struct usb_descriptor_header *) &z_1,
15654 + (struct usb_descriptor_header *) &z_2,
15655 + (struct usb_descriptor_header *) &z_audio_if_desc,
15656 + (struct usb_descriptor_header *) &z_audio_if_desc2,
15657 + (struct usb_descriptor_header *) &z_audio_cs_as_if_desc,
15658 + (struct usb_descriptor_header *) &z_audio_cs_as_format_desc,
15659 + (struct usb_descriptor_header *) &z_iso_ep,
15660 + (struct usb_descriptor_header *) &z_iso_ep2,
15661 + (struct usb_descriptor_header *) &za_0,
15662 + (struct usb_descriptor_header *) &za_1,
15663 + (struct usb_descriptor_header *) &za_2,
15664 + (struct usb_descriptor_header *) &za_3,
15665 + (struct usb_descriptor_header *) &za_4,
15666 + (struct usb_descriptor_header *) &za_5,
15667 + (struct usb_descriptor_header *) &za_6,
15668 + (struct usb_descriptor_header *) &za_7,
15669 + (struct usb_descriptor_header *) &za_8,
15670 + (struct usb_descriptor_header *) &za_9,
15671 + (struct usb_descriptor_header *) &za_10,
15672 + (struct usb_descriptor_header *) &za_11,
15673 + (struct usb_descriptor_header *) &za_12,
15674 + (struct usb_descriptor_header *) &za_13,
15675 + (struct usb_descriptor_header *) &za_14,
15676 + (struct usb_descriptor_header *) &za_15,
15677 + (struct usb_descriptor_header *) &za_16,
15678 + (struct usb_descriptor_header *) &za_17,
15679 + (struct usb_descriptor_header *) &za_18,
15680 + (struct usb_descriptor_header *) &za_19,
15681 + (struct usb_descriptor_header *) &za_20,
15682 + (struct usb_descriptor_header *) &za_21,
15683 + (struct usb_descriptor_header *) &za_22,
15684 + (struct usb_descriptor_header *) &za_23,
15685 + (struct usb_descriptor_header *) &za_24,
15686 + NULL,
15687 +};
15688 +
15689 +/* maxpacket and other transfer characteristics vary by speed. */
15690 +#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
15691 +
15692 +#else
15693 +
15694 +/* if there's no high speed support, maxpacket doesn't change. */
15695 +#define ep_desc(g,hs,fs) fs
15696 +
15697 +#endif /* !CONFIG_USB_GADGET_DUALSPEED */
15698 +
15699 +static char manufacturer [40];
15700 +//static char serial [40];
15701 +static char serial [] = "Ser 00 em";
15702 +
15703 +/* static strings, in UTF-8 */
15704 +static struct usb_string strings [] = {
15705 + { STRING_MANUFACTURER, manufacturer, },
15706 + { STRING_PRODUCT, longname, },
15707 + { STRING_SERIAL, serial, },
15708 + { STRING_LOOPBACK, loopback, },
15709 + { STRING_SOURCE_SINK, source_sink, },
15710 + { } /* end of list */
15711 +};
15712 +
15713 +static struct usb_gadget_strings stringtab = {
15714 + .language = 0x0409, /* en-us */
15715 + .strings = strings,
15716 +};
15717 +
15718 +/*
15719 + * config descriptors are also handcrafted. these must agree with code
15720 + * that sets configurations, and with code managing interfaces and their
15721 + * altsettings. other complexity may come from:
15722 + *
15723 + * - high speed support, including "other speed config" rules
15724 + * - multiple configurations
15725 + * - interfaces with alternate settings
15726 + * - embedded class or vendor-specific descriptors
15727 + *
15728 + * this handles high speed, and has a second config that could as easily
15729 + * have been an alternate interface setting (on most hardware).
15730 + *
15731 + * NOTE: to demonstrate (and test) more USB capabilities, this driver
15732 + * should include an altsetting to test interrupt transfers, including
15733 + * high bandwidth modes at high speed. (Maybe work like Intel's test
15734 + * device?)
15735 + */
15736 +static int
15737 +config_buf (struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index)
15738 +{
15739 + int len;
15740 + const struct usb_descriptor_header **function;
15741 +
15742 + function = z_function;
15743 + len = usb_gadget_config_buf (&z_config, buf, USB_BUFSIZ, function);
15744 + if (len < 0)
15745 + return len;
15746 + ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
15747 + return len;
15748 +}
15749 +
15750 +/*-------------------------------------------------------------------------*/
15751 +
15752 +static struct usb_request *
15753 +alloc_ep_req (struct usb_ep *ep, unsigned length)
15754 +{
15755 + struct usb_request *req;
15756 +
15757 + req = usb_ep_alloc_request (ep, GFP_ATOMIC);
15758 + if (req) {
15759 + req->length = length;
15760 + req->buf = usb_ep_alloc_buffer (ep, length,
15761 + &req->dma, GFP_ATOMIC);
15762 + if (!req->buf) {
15763 + usb_ep_free_request (ep, req);
15764 + req = NULL;
15765 + }
15766 + }
15767 + return req;
15768 +}
15769 +
15770 +static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
15771 +{
15772 + if (req->buf)
15773 + usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
15774 + usb_ep_free_request (ep, req);
15775 +}
15776 +
15777 +/*-------------------------------------------------------------------------*/
15778 +
15779 +/* optionally require specific source/sink data patterns */
15780 +
15781 +static int
15782 +check_read_data (
15783 + struct zero_dev *dev,
15784 + struct usb_ep *ep,
15785 + struct usb_request *req
15786 +)
15787 +{
15788 + unsigned i;
15789 + u8 *buf = req->buf;
15790 +
15791 + for (i = 0; i < req->actual; i++, buf++) {
15792 + switch (pattern) {
15793 + /* all-zeroes has no synchronization issues */
15794 + case 0:
15795 + if (*buf == 0)
15796 + continue;
15797 + break;
15798 + /* mod63 stays in sync with short-terminated transfers,
15799 + * or otherwise when host and gadget agree on how large
15800 + * each usb transfer request should be. resync is done
15801 + * with set_interface or set_config.
15802 + */
15803 + case 1:
15804 + if (*buf == (u8)(i % 63))
15805 + continue;
15806 + break;
15807 + }
15808 + ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);
15809 + usb_ep_set_halt (ep);
15810 + return -EINVAL;
15811 + }
15812 + return 0;
15813 +}
15814 +
15815 +/*-------------------------------------------------------------------------*/
15816 +
15817 +static void zero_reset_config (struct zero_dev *dev)
15818 +{
15819 + if (dev->config == 0)
15820 + return;
15821 +
15822 + DBG (dev, "reset config\n");
15823 +
15824 + /* just disable endpoints, forcing completion of pending i/o.
15825 + * all our completion handlers free their requests in this case.
15826 + */
15827 + if (dev->in_ep) {
15828 + usb_ep_disable (dev->in_ep);
15829 + dev->in_ep = NULL;
15830 + }
15831 + if (dev->out_ep) {
15832 + usb_ep_disable (dev->out_ep);
15833 + dev->out_ep = NULL;
15834 + }
15835 + dev->config = 0;
15836 + del_timer (&dev->resume);
15837 +}
15838 +
15839 +#define _write(f, buf, sz) (f->f_op->write(f, buf, sz, &f->f_pos))
15840 +
15841 +static void
15842 +zero_isoc_complete (struct usb_ep *ep, struct usb_request *req)
15843 +{
15844 + struct zero_dev *dev = ep->driver_data;
15845 + int status = req->status;
15846 + int i, j;
15847 +
15848 + switch (status) {
15849 +
15850 + case 0: /* normal completion? */
15851 + //printk ("\nzero ---------------> isoc normal completion %d bytes\n", req->actual);
15852 + for (i=0, j=rbuf_start; i<req->actual; i++) {
15853 + //printk ("%02x ", ((__u8*)req->buf)[i]);
15854 + rbuf[j] = ((__u8*)req->buf)[i];
15855 + j++;
15856 + if (j >= RBUF_LEN) j=0;
15857 + }
15858 + rbuf_start = j;
15859 + //printk ("\n\n");
15860 +
15861 + if (rbuf_len < RBUF_LEN) {
15862 + rbuf_len += req->actual;
15863 + if (rbuf_len > RBUF_LEN) {
15864 + rbuf_len = RBUF_LEN;
15865 + }
15866 + }
15867 +
15868 + break;
15869 +
15870 + /* this endpoint is normally active while we're configured */
15871 + case -ECONNABORTED: /* hardware forced ep reset */
15872 + case -ECONNRESET: /* request dequeued */
15873 + case -ESHUTDOWN: /* disconnect from host */
15874 + VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
15875 + req->actual, req->length);
15876 + if (ep == dev->out_ep)
15877 + check_read_data (dev, ep, req);
15878 + free_ep_req (ep, req);
15879 + return;
15880 +
15881 + case -EOVERFLOW: /* buffer overrun on read means that
15882 + * we didn't provide a big enough
15883 + * buffer.
15884 + */
15885 + default:
15886 +#if 1
15887 + DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
15888 + status, req->actual, req->length);
15889 +#endif
15890 + case -EREMOTEIO: /* short read */
15891 + break;
15892 + }
15893 +
15894 + status = usb_ep_queue (ep, req, GFP_ATOMIC);
15895 + if (status) {
15896 + ERROR (dev, "kill %s: resubmit %d bytes --> %d\n",
15897 + ep->name, req->length, status);
15898 + usb_ep_set_halt (ep);
15899 + /* FIXME recover later ... somehow */
15900 + }
15901 +}
15902 +
15903 +static struct usb_request *
15904 +zero_start_isoc_ep (struct usb_ep *ep, int gfp_flags)
15905 +{
15906 + struct usb_request *req;
15907 + int status;
15908 +
15909 + req = alloc_ep_req (ep, 512);
15910 + if (!req)
15911 + return NULL;
15912 +
15913 + req->complete = zero_isoc_complete;
15914 +
15915 + status = usb_ep_queue (ep, req, gfp_flags);
15916 + if (status) {
15917 + struct zero_dev *dev = ep->driver_data;
15918 +
15919 + ERROR (dev, "start %s --> %d\n", ep->name, status);
15920 + free_ep_req (ep, req);
15921 + req = NULL;
15922 + }
15923 +
15924 + return req;
15925 +}
15926 +
15927 +/* change our operational config. this code must agree with the code
15928 + * that returns config descriptors, and altsetting code.
15929 + *
15930 + * it's also responsible for power management interactions. some
15931 + * configurations might not work with our current power sources.
15932 + *
15933 + * note that some device controller hardware will constrain what this
15934 + * code can do, perhaps by disallowing more than one configuration or
15935 + * by limiting configuration choices (like the pxa2xx).
15936 + */
15937 +static int
15938 +zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags)
15939 +{
15940 + int result = 0;
15941 + struct usb_gadget *gadget = dev->gadget;
15942 + const struct usb_endpoint_descriptor *d;
15943 + struct usb_ep *ep;
15944 +
15945 + if (number == dev->config)
15946 + return 0;
15947 +
15948 + zero_reset_config (dev);
15949 +
15950 + gadget_for_each_ep (ep, gadget) {
15951 +
15952 + if (strcmp (ep->name, "ep4") == 0) {
15953 +
15954 + d = (struct usb_endpoint_descripter *)&za_23; // isoc ep desc for audio i/f alt setting 6
15955 + result = usb_ep_enable (ep, d);
15956 +
15957 + if (result == 0) {
15958 + ep->driver_data = dev;
15959 + dev->in_ep = ep;
15960 +
15961 + if (zero_start_isoc_ep (ep, gfp_flags) != 0) {
15962 +
15963 + dev->in_ep = ep;
15964 + continue;
15965 + }
15966 +
15967 + usb_ep_disable (ep);
15968 + result = -EIO;
15969 + }
15970 + }
15971 +
15972 + }
15973 +
15974 + dev->config = number;
15975 + return result;
15976 +}
15977 +
15978 +/*-------------------------------------------------------------------------*/
15979 +
15980 +static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
15981 +{
15982 + if (req->status || req->actual != req->length)
15983 + DBG ((struct zero_dev *) ep->driver_data,
15984 + "setup complete --> %d, %d/%d\n",
15985 + req->status, req->actual, req->length);
15986 +}
15987 +
15988 +/*
15989 + * The setup() callback implements all the ep0 functionality that's
15990 + * not handled lower down, in hardware or the hardware driver (like
15991 + * device and endpoint feature flags, and their status). It's all
15992 + * housekeeping for the gadget function we're implementing. Most of
15993 + * the work is in config-specific setup.
15994 + */
15995 +static int
15996 +zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
15997 +{
15998 + struct zero_dev *dev = get_gadget_data (gadget);
15999 + struct usb_request *req = dev->req;
16000 + int value = -EOPNOTSUPP;
16001 +
16002 + /* usually this stores reply data in the pre-allocated ep0 buffer,
16003 + * but config change events will reconfigure hardware.
16004 + */
16005 + req->zero = 0;
16006 + switch (ctrl->bRequest) {
16007 +
16008 + case USB_REQ_GET_DESCRIPTOR:
16009 +
16010 + switch (ctrl->wValue >> 8) {
16011 +
16012 + case USB_DT_DEVICE:
16013 + value = min (ctrl->wLength, (u16) sizeof device_desc);
16014 + memcpy (req->buf, &device_desc, value);
16015 + break;
16016 +#ifdef CONFIG_USB_GADGET_DUALSPEED
16017 + case USB_DT_DEVICE_QUALIFIER:
16018 + if (!gadget->is_dualspeed)
16019 + break;
16020 + value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
16021 + memcpy (req->buf, &dev_qualifier, value);
16022 + break;
16023 +
16024 + case USB_DT_OTHER_SPEED_CONFIG:
16025 + if (!gadget->is_dualspeed)
16026 + break;
16027 + // FALLTHROUGH
16028 +#endif /* CONFIG_USB_GADGET_DUALSPEED */
16029 + case USB_DT_CONFIG:
16030 + value = config_buf (gadget, req->buf,
16031 + ctrl->wValue >> 8,
16032 + ctrl->wValue & 0xff);
16033 + if (value >= 0)
16034 + value = min (ctrl->wLength, (u16) value);
16035 + break;
16036 +
16037 + case USB_DT_STRING:
16038 + /* wIndex == language code.
16039 + * this driver only handles one language, you can
16040 + * add string tables for other languages, using
16041 + * any UTF-8 characters
16042 + */
16043 + value = usb_gadget_get_string (&stringtab,
16044 + ctrl->wValue & 0xff, req->buf);
16045 + if (value >= 0) {
16046 + value = min (ctrl->wLength, (u16) value);
16047 + }
16048 + break;
16049 + }
16050 + break;
16051 +
16052 + /* currently two configs, two speeds */
16053 + case USB_REQ_SET_CONFIGURATION:
16054 + if (ctrl->bRequestType != 0)
16055 + goto unknown;
16056 +
16057 + spin_lock (&dev->lock);
16058 + value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
16059 + spin_unlock (&dev->lock);
16060 + break;
16061 + case USB_REQ_GET_CONFIGURATION:
16062 + if (ctrl->bRequestType != USB_DIR_IN)
16063 + goto unknown;
16064 + *(u8 *)req->buf = dev->config;
16065 + value = min (ctrl->wLength, (u16) 1);
16066 + break;
16067 +
16068 + /* until we add altsetting support, or other interfaces,
16069 + * only 0/0 are possible. pxa2xx only supports 0/0 (poorly)
16070 + * and already killed pending endpoint I/O.
16071 + */
16072 + case USB_REQ_SET_INTERFACE:
16073 +
16074 + if (ctrl->bRequestType != USB_RECIP_INTERFACE)
16075 + goto unknown;
16076 + spin_lock (&dev->lock);
16077 + if (dev->config) {
16078 + u8 config = dev->config;
16079 +
16080 + /* resets interface configuration, forgets about
16081 + * previous transaction state (queued bufs, etc)
16082 + * and re-inits endpoint state (toggle etc)
16083 + * no response queued, just zero status == success.
16084 + * if we had more than one interface we couldn't
16085 + * use this "reset the config" shortcut.
16086 + */
16087 + zero_reset_config (dev);
16088 + zero_set_config (dev, config, GFP_ATOMIC);
16089 + value = 0;
16090 + }
16091 + spin_unlock (&dev->lock);
16092 + break;
16093 + case USB_REQ_GET_INTERFACE:
16094 + if ((ctrl->bRequestType == 0x21) && (ctrl->wIndex == 0x02)) {
16095 + value = ctrl->wLength;
16096 + break;
16097 + }
16098 + else {
16099 + if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
16100 + goto unknown;
16101 + if (!dev->config)
16102 + break;
16103 + if (ctrl->wIndex != 0) {
16104 + value = -EDOM;
16105 + break;
16106 + }
16107 + *(u8 *)req->buf = 0;
16108 + value = min (ctrl->wLength, (u16) 1);
16109 + }
16110 + break;
16111 +
16112 + /*
16113 + * These are the same vendor-specific requests supported by
16114 + * Intel's USB 2.0 compliance test devices. We exceed that
16115 + * device spec by allowing multiple-packet requests.
16116 + */
16117 + case 0x5b: /* control WRITE test -- fill the buffer */
16118 + if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
16119 + goto unknown;
16120 + if (ctrl->wValue || ctrl->wIndex)
16121 + break;
16122 + /* just read that many bytes into the buffer */
16123 + if (ctrl->wLength > USB_BUFSIZ)
16124 + break;
16125 + value = ctrl->wLength;
16126 + break;
16127 + case 0x5c: /* control READ test -- return the buffer */
16128 + if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
16129 + goto unknown;
16130 + if (ctrl->wValue || ctrl->wIndex)
16131 + break;
16132 + /* expect those bytes are still in the buffer; send back */
16133 + if (ctrl->wLength > USB_BUFSIZ
16134 + || ctrl->wLength != req->length)
16135 + break;
16136 + value = ctrl->wLength;
16137 + break;
16138 +
16139 + case 0x01: // SET_CUR
16140 + case 0x02:
16141 + case 0x03:
16142 + case 0x04:
16143 + case 0x05:
16144 + value = ctrl->wLength;
16145 + break;
16146 + case 0x81:
16147 + switch (ctrl->wValue) {
16148 + case 0x0201:
16149 + case 0x0202:
16150 + ((u8*)req->buf)[0] = 0x00;
16151 + ((u8*)req->buf)[1] = 0xe3;
16152 + break;
16153 + case 0x0300:
16154 + case 0x0500:
16155 + ((u8*)req->buf)[0] = 0x00;
16156 + break;
16157 + }
16158 + //((u8*)req->buf)[0] = 0x81;
16159 + //((u8*)req->buf)[1] = 0x81;
16160 + value = ctrl->wLength;
16161 + break;
16162 + case 0x82:
16163 + switch (ctrl->wValue) {
16164 + case 0x0201:
16165 + case 0x0202:
16166 + ((u8*)req->buf)[0] = 0x00;
16167 + ((u8*)req->buf)[1] = 0xc3;
16168 + break;
16169 + case 0x0300:
16170 + case 0x0500:
16171 + ((u8*)req->buf)[0] = 0x00;
16172 + break;
16173 + }
16174 + //((u8*)req->buf)[0] = 0x82;
16175 + //((u8*)req->buf)[1] = 0x82;
16176 + value = ctrl->wLength;
16177 + break;
16178 + case 0x83:
16179 + switch (ctrl->wValue) {
16180 + case 0x0201:
16181 + case 0x0202:
16182 + ((u8*)req->buf)[0] = 0x00;
16183 + ((u8*)req->buf)[1] = 0x00;
16184 + break;
16185 + case 0x0300:
16186 + ((u8*)req->buf)[0] = 0x60;
16187 + break;
16188 + case 0x0500:
16189 + ((u8*)req->buf)[0] = 0x18;
16190 + break;
16191 + }
16192 + //((u8*)req->buf)[0] = 0x83;
16193 + //((u8*)req->buf)[1] = 0x83;
16194 + value = ctrl->wLength;
16195 + break;
16196 + case 0x84:
16197 + switch (ctrl->wValue) {
16198 + case 0x0201:
16199 + case 0x0202:
16200 + ((u8*)req->buf)[0] = 0x00;
16201 + ((u8*)req->buf)[1] = 0x01;
16202 + break;
16203 + case 0x0300:
16204 + case 0x0500:
16205 + ((u8*)req->buf)[0] = 0x08;
16206 + break;
16207 + }
16208 + //((u8*)req->buf)[0] = 0x84;
16209 + //((u8*)req->buf)[1] = 0x84;
16210 + value = ctrl->wLength;
16211 + break;
16212 + case 0x85:
16213 + ((u8*)req->buf)[0] = 0x85;
16214 + ((u8*)req->buf)[1] = 0x85;
16215 + value = ctrl->wLength;
16216 + break;
16217 +
16218 +
16219 + default:
16220 +unknown:
16221 + printk("unknown control req%02x.%02x v%04x i%04x l%d\n",
16222 + ctrl->bRequestType, ctrl->bRequest,
16223 + ctrl->wValue, ctrl->wIndex, ctrl->wLength);
16224 + }
16225 +
16226 + /* respond with data transfer before status phase? */
16227 + if (value >= 0) {
16228 + req->length = value;
16229 + req->zero = value < ctrl->wLength
16230 + && (value % gadget->ep0->maxpacket) == 0;
16231 + value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
16232 + if (value < 0) {
16233 + DBG (dev, "ep_queue < 0 --> %d\n", value);
16234 + req->status = 0;
16235 + zero_setup_complete (gadget->ep0, req);
16236 + }
16237 + }
16238 +
16239 + /* device either stalls (value < 0) or reports success */
16240 + return value;
16241 +}
16242 +
16243 +static void
16244 +zero_disconnect (struct usb_gadget *gadget)
16245 +{
16246 + struct zero_dev *dev = get_gadget_data (gadget);
16247 + unsigned long flags;
16248 +
16249 + spin_lock_irqsave (&dev->lock, flags);
16250 + zero_reset_config (dev);
16251 +
16252 + /* a more significant application might have some non-usb
16253 + * activities to quiesce here, saving resources like power
16254 + * or pushing the notification up a network stack.
16255 + */
16256 + spin_unlock_irqrestore (&dev->lock, flags);
16257 +
16258 + /* next we may get setup() calls to enumerate new connections;
16259 + * or an unbind() during shutdown (including removing module).
16260 + */
16261 +}
16262 +
16263 +static void
16264 +zero_autoresume (unsigned long _dev)
16265 +{
16266 + struct zero_dev *dev = (struct zero_dev *) _dev;
16267 + int status;
16268 +
16269 + /* normally the host would be woken up for something
16270 + * more significant than just a timer firing...
16271 + */
16272 + if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
16273 + status = usb_gadget_wakeup (dev->gadget);
16274 + DBG (dev, "wakeup --> %d\n", status);
16275 + }
16276 +}
16277 +
16278 +/*-------------------------------------------------------------------------*/
16279 +
16280 +static void
16281 +zero_unbind (struct usb_gadget *gadget)
16282 +{
16283 + struct zero_dev *dev = get_gadget_data (gadget);
16284 +
16285 + DBG (dev, "unbind\n");
16286 +
16287 + /* we've already been disconnected ... no i/o is active */
16288 + if (dev->req)
16289 + free_ep_req (gadget->ep0, dev->req);
16290 + del_timer_sync (&dev->resume);
16291 + kfree (dev);
16292 + set_gadget_data (gadget, NULL);
16293 +}
16294 +
16295 +static int
16296 +zero_bind (struct usb_gadget *gadget)
16297 +{
16298 + struct zero_dev *dev;
16299 + //struct usb_ep *ep;
16300 +
16301 + printk("binding\n");
16302 + /*
16303 + * DRIVER POLICY CHOICE: you may want to do this differently.
16304 + * One thing to avoid is reusing a bcdDevice revision code
16305 + * with different host-visible configurations or behavior
16306 + * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc
16307 + */
16308 + //device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
16309 +
16310 +
16311 + /* ok, we made sense of the hardware ... */
16312 + dev = kmalloc (sizeof *dev, SLAB_KERNEL);
16313 + if (!dev)
16314 + return -ENOMEM;
16315 + memset (dev, 0, sizeof *dev);
16316 + spin_lock_init (&dev->lock);
16317 + dev->gadget = gadget;
16318 + set_gadget_data (gadget, dev);
16319 +
16320 + /* preallocate control response and buffer */
16321 + dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
16322 + if (!dev->req)
16323 + goto enomem;
16324 + dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
16325 + &dev->req->dma, GFP_KERNEL);
16326 + if (!dev->req->buf)
16327 + goto enomem;
16328 +
16329 + dev->req->complete = zero_setup_complete;
16330 +
16331 + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
16332 +
16333 +#ifdef CONFIG_USB_GADGET_DUALSPEED
16334 + /* assume ep0 uses the same value for both speeds ... */
16335 + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
16336 +
16337 + /* and that all endpoints are dual-speed */
16338 + //hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
16339 + //hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
16340 +#endif
16341 +
16342 + usb_gadget_set_selfpowered (gadget);
16343 +
16344 + init_timer (&dev->resume);
16345 + dev->resume.function = zero_autoresume;
16346 + dev->resume.data = (unsigned long) dev;
16347 +
16348 + gadget->ep0->driver_data = dev;
16349 +
16350 + INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
16351 + INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
16352 + EP_OUT_NAME, EP_IN_NAME);
16353 +
16354 + snprintf (manufacturer, sizeof manufacturer,
16355 + UTS_SYSNAME " " UTS_RELEASE " with %s",
16356 + gadget->name);
16357 +
16358 + return 0;
16359 +
16360 +enomem:
16361 + zero_unbind (gadget);
16362 + return -ENOMEM;
16363 +}
16364 +
16365 +/*-------------------------------------------------------------------------*/
16366 +
16367 +static void
16368 +zero_suspend (struct usb_gadget *gadget)
16369 +{
16370 + struct zero_dev *dev = get_gadget_data (gadget);
16371 +
16372 + if (gadget->speed == USB_SPEED_UNKNOWN)
16373 + return;
16374 +
16375 + if (autoresume) {
16376 + mod_timer (&dev->resume, jiffies + (HZ * autoresume));
16377 + DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
16378 + } else
16379 + DBG (dev, "suspend\n");
16380 +}
16381 +
16382 +static void
16383 +zero_resume (struct usb_gadget *gadget)
16384 +{
16385 + struct zero_dev *dev = get_gadget_data (gadget);
16386 +
16387 + DBG (dev, "resume\n");
16388 + del_timer (&dev->resume);
16389 +}
16390 +
16391 +
16392 +/*-------------------------------------------------------------------------*/
16393 +
16394 +static struct usb_gadget_driver zero_driver = {
16395 +#ifdef CONFIG_USB_GADGET_DUALSPEED
16396 + .speed = USB_SPEED_HIGH,
16397 +#else
16398 + .speed = USB_SPEED_FULL,
16399 +#endif
16400 + .function = (char *) longname,
16401 + .bind = zero_bind,
16402 + .unbind = zero_unbind,
16403 +
16404 + .setup = zero_setup,
16405 + .disconnect = zero_disconnect,
16406 +
16407 + .suspend = zero_suspend,
16408 + .resume = zero_resume,
16409 +
16410 + .driver = {
16411 + .name = (char *) shortname,
16412 + // .shutdown = ...
16413 + // .suspend = ...
16414 + // .resume = ...
16415 + },
16416 +};
16417 +
16418 +MODULE_AUTHOR ("David Brownell");
16419 +MODULE_LICENSE ("Dual BSD/GPL");
16420 +
16421 +static struct proc_dir_entry *pdir, *pfile;
16422 +
16423 +static int isoc_read_data (char *page, char **start,
16424 + off_t off, int count,
16425 + int *eof, void *data)
16426 +{
16427 + int i;
16428 + static int c = 0;
16429 + static int done = 0;
16430 + static int s = 0;
16431 +
16432 +/*
16433 + printk ("\ncount: %d\n", count);
16434 + printk ("rbuf_start: %d\n", rbuf_start);
16435 + printk ("rbuf_len: %d\n", rbuf_len);
16436 + printk ("off: %d\n", off);
16437 + printk ("start: %p\n\n", *start);
16438 +*/
16439 + if (done) {
16440 + c = 0;
16441 + done = 0;
16442 + *eof = 1;
16443 + return 0;
16444 + }
16445 +
16446 + if (c == 0) {
16447 + if (rbuf_len == RBUF_LEN)
16448 + s = rbuf_start;
16449 + else s = 0;
16450 + }
16451 +
16452 + for (i=0; i<count && c<rbuf_len; i++, c++) {
16453 + page[i] = rbuf[(c+s) % RBUF_LEN];
16454 + }
16455 + *start = page;
16456 +
16457 + if (c >= rbuf_len) {
16458 + *eof = 1;
16459 + done = 1;
16460 + }
16461 +
16462 +
16463 + return i;
16464 +}
16465 +
16466 +static int __init init (void)
16467 +{
16468 +
16469 + int retval = 0;
16470 +
16471 + pdir = proc_mkdir("isoc_test", NULL);
16472 + if(pdir == NULL) {
16473 + retval = -ENOMEM;
16474 + printk("Error creating dir\n");
16475 + goto done;
16476 + }
16477 + pdir->owner = THIS_MODULE;
16478 +
16479 + pfile = create_proc_read_entry("isoc_data",
16480 + 0444, pdir,
16481 + isoc_read_data,
16482 + NULL);
16483 + if (pfile == NULL) {
16484 + retval = -ENOMEM;
16485 + printk("Error creating file\n");
16486 + goto no_file;
16487 + }
16488 + pfile->owner = THIS_MODULE;
16489 +
16490 + return usb_gadget_register_driver (&zero_driver);
16491 +
16492 + no_file:
16493 + remove_proc_entry("isoc_data", NULL);
16494 + done:
16495 + return retval;
16496 +}
16497 +module_init (init);
16498 +
16499 +static void __exit cleanup (void)
16500 +{
16501 +
16502 + usb_gadget_unregister_driver (&zero_driver);
16503 +
16504 + remove_proc_entry("isoc_data", pdir);
16505 + remove_proc_entry("isoc_test", NULL);
16506 +}
16507 +module_exit (cleanup);
16508 diff --git a/drivers/usb/host/dwc_otg/dwc_cfi_common.h b/drivers/usb/host/dwc_otg/dwc_cfi_common.h
16509 new file mode 100644
16510 index 0000000..7770e20
16511 --- /dev/null
16512 +++ b/drivers/usb/host/dwc_otg/dwc_cfi_common.h
16513 @@ -0,0 +1,142 @@
16514 +/* ==========================================================================
16515 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
16516 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
16517 + * otherwise expressly agreed to in writing between Synopsys and you.
16518 + *
16519 + * The Software IS NOT an item of Licensed Software or Licensed Product under
16520 + * any End User Software License Agreement or Agreement for Licensed Product
16521 + * with Synopsys or any supplement thereto. You are permitted to use and
16522 + * redistribute this Software in source and binary forms, with or without
16523 + * modification, provided that redistributions of source code must retain this
16524 + * notice. You may not view, use, disclose, copy or distribute this file or
16525 + * any information contained herein except pursuant to this license grant from
16526 + * Synopsys. If you do not agree with this notice, including the disclaimer
16527 + * below, then you are not authorized to use the Software.
16528 + *
16529 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
16530 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16531 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16532 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
16533 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16534 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16535 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
16536 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16537 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16538 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
16539 + * DAMAGE.
16540 + * ========================================================================== */
16541 +
16542 +#if !defined(__DWC_CFI_COMMON_H__)
16543 +#define __DWC_CFI_COMMON_H__
16544 +
16545 +//#include <linux/types.h>
16546 +
16547 +/**
16548 + * @file
16549 + *
16550 + * This file contains the CFI specific common constants, interfaces
16551 + * (functions and macros) and structures for Linux. No PCD specific
16552 + * data structure or definition is to be included in this file.
16553 + *
16554 + */
16555 +
16556 +/** This is a request for all Core Features */
16557 +#define VEN_CORE_GET_FEATURES 0xB1
16558 +
16559 +/** This is a request to get the value of a specific Core Feature */
16560 +#define VEN_CORE_GET_FEATURE 0xB2
16561 +
16562 +/** This command allows the host to set the value of a specific Core Feature */
16563 +#define VEN_CORE_SET_FEATURE 0xB3
16564 +
16565 +/** This command allows the host to set the default values of
16566 + * either all or any specific Core Feature
16567 + */
16568 +#define VEN_CORE_RESET_FEATURES 0xB4
16569 +
16570 +/** This command forces the PCD to write the deferred values of a Core Features */
16571 +#define VEN_CORE_ACTIVATE_FEATURES 0xB5
16572 +
16573 +/** This request reads a DWORD value from a register at the specified offset */
16574 +#define VEN_CORE_READ_REGISTER 0xB6
16575 +
16576 +/** This request writes a DWORD value into a register at the specified offset */
16577 +#define VEN_CORE_WRITE_REGISTER 0xB7
16578 +
16579 +/** This structure is the header of the Core Features dataset returned to
16580 + * the Host
16581 + */
16582 +struct cfi_all_features_header {
16583 +/** The features header structure length is */
16584 +#define CFI_ALL_FEATURES_HDR_LEN 8
16585 + /**
16586 + * The total length of the features dataset returned to the Host
16587 + */
16588 + uint16_t wTotalLen;
16589 +
16590 + /**
16591 + * CFI version number inBinary-Coded Decimal (i.e., 1.00 is 100H).
16592 + * This field identifies the version of the CFI Specification with which
16593 + * the device is compliant.
16594 + */
16595 + uint16_t wVersion;
16596 +
16597 + /** The ID of the Core */
16598 + uint16_t wCoreID;
16599 +#define CFI_CORE_ID_UDC 1
16600 +#define CFI_CORE_ID_OTG 2
16601 +#define CFI_CORE_ID_WUDEV 3
16602 +
16603 + /** Number of features returned by VEN_CORE_GET_FEATURES request */
16604 + uint16_t wNumFeatures;
16605 +} UPACKED;
16606 +
16607 +typedef struct cfi_all_features_header cfi_all_features_header_t;
16608 +
16609 +/** This structure is a header of the Core Feature descriptor dataset returned to
16610 + * the Host after the VEN_CORE_GET_FEATURES request
16611 + */
16612 +struct cfi_feature_desc_header {
16613 +#define CFI_FEATURE_DESC_HDR_LEN 8
16614 +
16615 + /** The feature ID */
16616 + uint16_t wFeatureID;
16617 +
16618 + /** Length of this feature descriptor in bytes - including the
16619 + * length of the feature name string
16620 + */
16621 + uint16_t wLength;
16622 +
16623 + /** The data length of this feature in bytes */
16624 + uint16_t wDataLength;
16625 +
16626 + /**
16627 + * Attributes of this features
16628 + * D0: Access rights
16629 + * 0 - Read/Write
16630 + * 1 - Read only
16631 + */
16632 + uint8_t bmAttributes;
16633 +#define CFI_FEATURE_ATTR_RO 1
16634 +#define CFI_FEATURE_ATTR_RW 0
16635 +
16636 + /** Length of the feature name in bytes */
16637 + uint8_t bNameLen;
16638 +
16639 + /** The feature name buffer */
16640 + //uint8_t *name;
16641 +} UPACKED;
16642 +
16643 +typedef struct cfi_feature_desc_header cfi_feature_desc_header_t;
16644 +
16645 +/**
16646 + * This structure describes a NULL terminated string referenced by its id field.
16647 + * It is very similar to usb_string structure but has the id field type set to 16-bit.
16648 + */
16649 +struct cfi_string {
16650 + uint16_t id;
16651 + const uint8_t *s;
16652 +};
16653 +typedef struct cfi_string cfi_string_t;
16654 +
16655 +#endif
16656 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_adp.c b/drivers/usb/host/dwc_otg/dwc_otg_adp.c
16657 new file mode 100644
16658 index 0000000..ce0618d
16659 --- /dev/null
16660 +++ b/drivers/usb/host/dwc_otg/dwc_otg_adp.c
16661 @@ -0,0 +1,854 @@
16662 +/* ==========================================================================
16663 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.c $
16664 + * $Revision: #12 $
16665 + * $Date: 2011/10/26 $
16666 + * $Change: 1873028 $
16667 + *
16668 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
16669 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
16670 + * otherwise expressly agreed to in writing between Synopsys and you.
16671 + *
16672 + * The Software IS NOT an item of Licensed Software or Licensed Product under
16673 + * any End User Software License Agreement or Agreement for Licensed Product
16674 + * with Synopsys or any supplement thereto. You are permitted to use and
16675 + * redistribute this Software in source and binary forms, with or without
16676 + * modification, provided that redistributions of source code must retain this
16677 + * notice. You may not view, use, disclose, copy or distribute this file or
16678 + * any information contained herein except pursuant to this license grant from
16679 + * Synopsys. If you do not agree with this notice, including the disclaimer
16680 + * below, then you are not authorized to use the Software.
16681 + *
16682 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
16683 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16684 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16685 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
16686 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16687 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16688 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
16689 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16690 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16691 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
16692 + * DAMAGE.
16693 + * ========================================================================== */
16694 +
16695 +#include "dwc_os.h"
16696 +#include "dwc_otg_regs.h"
16697 +#include "dwc_otg_cil.h"
16698 +#include "dwc_otg_adp.h"
16699 +
16700 +/** @file
16701 + *
16702 + * This file contains the most of the Attach Detect Protocol implementation for
16703 + * the driver to support OTG Rev2.0.
16704 + *
16705 + */
16706 +
16707 +void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value)
16708 +{
16709 + adpctl_data_t adpctl;
16710 +
16711 + adpctl.d32 = value;
16712 + adpctl.b.ar = 0x2;
16713 +
16714 + DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
16715 +
16716 + while (adpctl.b.ar) {
16717 + adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
16718 + }
16719 +
16720 +}
16721 +
16722 +/**
16723 + * Function is called to read ADP registers
16724 + */
16725 +uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if)
16726 +{
16727 + adpctl_data_t adpctl;
16728 +
16729 + adpctl.d32 = 0;
16730 + adpctl.b.ar = 0x1;
16731 +
16732 + DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
16733 +
16734 + while (adpctl.b.ar) {
16735 + adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
16736 + }
16737 +
16738 + return adpctl.d32;
16739 +}
16740 +
16741 +/**
16742 + * Function is called to read ADPCTL register and filter Write-clear bits
16743 + */
16744 +uint32_t dwc_otg_adp_read_reg_filter(dwc_otg_core_if_t * core_if)
16745 +{
16746 + adpctl_data_t adpctl;
16747 +
16748 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16749 + adpctl.b.adp_tmout_int = 0;
16750 + adpctl.b.adp_prb_int = 0;
16751 + adpctl.b.adp_tmout_int = 0;
16752 +
16753 + return adpctl.d32;
16754 +}
16755 +
16756 +/**
16757 + * Function is called to write ADP registers
16758 + */
16759 +void dwc_otg_adp_modify_reg(dwc_otg_core_if_t * core_if, uint32_t clr,
16760 + uint32_t set)
16761 +{
16762 + dwc_otg_adp_write_reg(core_if,
16763 + (dwc_otg_adp_read_reg(core_if) & (~clr)) | set);
16764 +}
16765 +
16766 +static void adp_sense_timeout(void *ptr)
16767 +{
16768 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
16769 + core_if->adp.sense_timer_started = 0;
16770 + DWC_PRINTF("ADP SENSE TIMEOUT\n");
16771 + if (core_if->adp_enable) {
16772 + dwc_otg_adp_sense_stop(core_if);
16773 + dwc_otg_adp_probe_start(core_if);
16774 + }
16775 +}
16776 +
16777 +/**
16778 + * This function is called when the ADP vbus timer expires. Timeout is 1.1s.
16779 + */
16780 +static void adp_vbuson_timeout(void *ptr)
16781 +{
16782 + gpwrdn_data_t gpwrdn;
16783 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
16784 + hprt0_data_t hprt0 = {.d32 = 0 };
16785 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
16786 + DWC_PRINTF("%s: 1.1 seconds expire after turning on VBUS\n",__FUNCTION__);
16787 + if (core_if) {
16788 + core_if->adp.vbuson_timer_started = 0;
16789 + /* Turn off vbus */
16790 + hprt0.b.prtpwr = 1;
16791 + DWC_MODIFY_REG32(core_if->host_if->hprt0, hprt0.d32, 0);
16792 + gpwrdn.d32 = 0;
16793 +
16794 + /* Power off the core */
16795 + if (core_if->power_down == 2) {
16796 + /* Enable Wakeup Logic */
16797 +// gpwrdn.b.wkupactiv = 1;
16798 + gpwrdn.b.pmuactv = 0;
16799 + gpwrdn.b.pwrdnrstn = 1;
16800 + gpwrdn.b.pwrdnclmp = 1;
16801 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
16802 + gpwrdn.d32);
16803 +
16804 + /* Suspend the Phy Clock */
16805 + pcgcctl.b.stoppclk = 1;
16806 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
16807 +
16808 + /* Switch on VDD */
16809 +// gpwrdn.b.wkupactiv = 1;
16810 + gpwrdn.b.pmuactv = 1;
16811 + gpwrdn.b.pwrdnrstn = 1;
16812 + gpwrdn.b.pwrdnclmp = 1;
16813 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
16814 + gpwrdn.d32);
16815 + } else {
16816 + /* Enable Power Down Logic */
16817 + gpwrdn.b.pmuintsel = 1;
16818 + gpwrdn.b.pmuactv = 1;
16819 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16820 + }
16821 +
16822 + /* Power off the core */
16823 + if (core_if->power_down == 2) {
16824 + gpwrdn.d32 = 0;
16825 + gpwrdn.b.pwrdnswtch = 1;
16826 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn,
16827 + gpwrdn.d32, 0);
16828 + }
16829 +
16830 + /* Unmask SRP detected interrupt from Power Down Logic */
16831 + gpwrdn.d32 = 0;
16832 + gpwrdn.b.srp_det_msk = 1;
16833 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16834 +
16835 + dwc_otg_adp_probe_start(core_if);
16836 + dwc_otg_dump_global_registers(core_if);
16837 + dwc_otg_dump_host_registers(core_if);
16838 + }
16839 +
16840 +}
16841 +
16842 +/**
16843 + * Start the ADP Initial Probe timer to detect if Port Connected interrupt is
16844 + * not asserted within 1.1 seconds.
16845 + *
16846 + * @param core_if the pointer to core_if strucure.
16847 + */
16848 +void dwc_otg_adp_vbuson_timer_start(dwc_otg_core_if_t * core_if)
16849 +{
16850 + core_if->adp.vbuson_timer_started = 1;
16851 + if (core_if->adp.vbuson_timer)
16852 + {
16853 + DWC_PRINTF("SCHEDULING VBUSON TIMER\n");
16854 + /* 1.1 secs + 60ms necessary for cil_hcd_start*/
16855 + DWC_TIMER_SCHEDULE(core_if->adp.vbuson_timer, 1160);
16856 + } else {
16857 + DWC_WARN("VBUSON_TIMER = %p\n",core_if->adp.vbuson_timer);
16858 + }
16859 +}
16860 +
16861 +#if 0
16862 +/**
16863 + * Masks all DWC OTG core interrupts
16864 + *
16865 + */
16866 +static void mask_all_interrupts(dwc_otg_core_if_t * core_if)
16867 +{
16868 + int i;
16869 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
16870 +
16871 + /* Mask Host Interrupts */
16872 +
16873 + /* Clear and disable HCINTs */
16874 + for (i = 0; i < core_if->core_params->host_channels; i++) {
16875 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk, 0);
16876 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcint, 0xFFFFFFFF);
16877 +
16878 + }
16879 +
16880 + /* Clear and disable HAINT */
16881 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk, 0x0000);
16882 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haint, 0xFFFFFFFF);
16883 +
16884 + /* Mask Device Interrupts */
16885 + if (!core_if->multiproc_int_enable) {
16886 + /* Clear and disable IN Endpoint interrupts */
16887 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, 0);
16888 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
16889 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
16890 + diepint, 0xFFFFFFFF);
16891 + }
16892 +
16893 + /* Clear and disable OUT Endpoint interrupts */
16894 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, 0);
16895 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
16896 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
16897 + doepint, 0xFFFFFFFF);
16898 + }
16899 +
16900 + /* Clear and disable DAINT */
16901 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daint,
16902 + 0xFFFFFFFF);
16903 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, 0);
16904 + } else {
16905 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
16906 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
16907 + diepeachintmsk[i], 0);
16908 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
16909 + diepint, 0xFFFFFFFF);
16910 + }
16911 +
16912 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
16913 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
16914 + doepeachintmsk[i], 0);
16915 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
16916 + doepint, 0xFFFFFFFF);
16917 + }
16918 +
16919 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
16920 + 0);
16921 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachint,
16922 + 0xFFFFFFFF);
16923 +
16924 + }
16925 +
16926 + /* Disable interrupts */
16927 + ahbcfg.b.glblintrmsk = 1;
16928 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
16929 +
16930 + /* Disable all interrupts. */
16931 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
16932 +
16933 + /* Clear any pending interrupts */
16934 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
16935 +
16936 + /* Clear any pending OTG Interrupts */
16937 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, 0xFFFFFFFF);
16938 +}
16939 +
16940 +/**
16941 + * Unmask Port Connection Detected interrupt
16942 + *
16943 + */
16944 +static void unmask_conn_det_intr(dwc_otg_core_if_t * core_if)
16945 +{
16946 + gintmsk_data_t gintmsk = {.d32 = 0,.b.portintr = 1 };
16947 +
16948 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
16949 +}
16950 +#endif
16951 +
16952 +/**
16953 + * Starts the ADP Probing
16954 + *
16955 + * @param core_if the pointer to core_if structure.
16956 + */
16957 +uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if)
16958 +{
16959 +
16960 + adpctl_data_t adpctl = {.d32 = 0};
16961 + gpwrdn_data_t gpwrdn;
16962 +#if 0
16963 + adpctl_data_t adpctl_int = {.d32 = 0, .b.adp_prb_int = 1,
16964 + .b.adp_sns_int = 1, b.adp_tmout_int};
16965 +#endif
16966 + dwc_otg_disable_global_interrupts(core_if);
16967 + DWC_PRINTF("ADP Probe Start\n");
16968 + core_if->adp.probe_enabled = 1;
16969 +
16970 + adpctl.b.adpres = 1;
16971 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16972 +
16973 + while (adpctl.b.adpres) {
16974 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16975 + }
16976 +
16977 + adpctl.d32 = 0;
16978 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
16979 +
16980 + /* In Host mode unmask SRP detected interrupt */
16981 + gpwrdn.d32 = 0;
16982 + gpwrdn.b.sts_chngint_msk = 1;
16983 + if (!gpwrdn.b.idsts) {
16984 + gpwrdn.b.srp_det_msk = 1;
16985 + }
16986 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16987 +
16988 + adpctl.b.adp_tmout_int_msk = 1;
16989 + adpctl.b.adp_prb_int_msk = 1;
16990 + adpctl.b.prb_dschg = 1;
16991 + adpctl.b.prb_delta = 1;
16992 + adpctl.b.prb_per = 1;
16993 + adpctl.b.adpen = 1;
16994 + adpctl.b.enaprb = 1;
16995 +
16996 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16997 + DWC_PRINTF("ADP Probe Finish\n");
16998 + return 0;
16999 +}
17000 +
17001 +/**
17002 + * Starts the ADP Sense timer to detect if ADP Sense interrupt is not asserted
17003 + * within 3 seconds.
17004 + *
17005 + * @param core_if the pointer to core_if strucure.
17006 + */
17007 +void dwc_otg_adp_sense_timer_start(dwc_otg_core_if_t * core_if)
17008 +{
17009 + core_if->adp.sense_timer_started = 1;
17010 + DWC_TIMER_SCHEDULE(core_if->adp.sense_timer, 3000 /* 3 secs */ );
17011 +}
17012 +
17013 +/**
17014 + * Starts the ADP Sense
17015 + *
17016 + * @param core_if the pointer to core_if strucure.
17017 + */
17018 +uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if)
17019 +{
17020 + adpctl_data_t adpctl;
17021 +
17022 + DWC_PRINTF("ADP Sense Start\n");
17023 +
17024 + /* Unmask ADP sense interrupt and mask all other from the core */
17025 + adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
17026 + adpctl.b.adp_sns_int_msk = 1;
17027 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17028 + dwc_otg_disable_global_interrupts(core_if); // vahrama
17029 +
17030 + /* Set ADP reset bit*/
17031 + adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
17032 + adpctl.b.adpres = 1;
17033 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17034 +
17035 + while (adpctl.b.adpres) {
17036 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17037 + }
17038 +
17039 + adpctl.b.adpres = 0;
17040 + adpctl.b.adpen = 1;
17041 + adpctl.b.enasns = 1;
17042 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17043 +
17044 + dwc_otg_adp_sense_timer_start(core_if);
17045 +
17046 + return 0;
17047 +}
17048 +
17049 +/**
17050 + * Stops the ADP Probing
17051 + *
17052 + * @param core_if the pointer to core_if strucure.
17053 + */
17054 +uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if)
17055 +{
17056 +
17057 + adpctl_data_t adpctl;
17058 + DWC_PRINTF("Stop ADP probe\n");
17059 + core_if->adp.probe_enabled = 0;
17060 + core_if->adp.probe_counter = 0;
17061 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17062 +
17063 + adpctl.b.adpen = 0;
17064 + adpctl.b.adp_prb_int = 1;
17065 + adpctl.b.adp_tmout_int = 1;
17066 + adpctl.b.adp_sns_int = 1;
17067 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17068 +
17069 + return 0;
17070 +}
17071 +
17072 +/**
17073 + * Stops the ADP Sensing
17074 + *
17075 + * @param core_if the pointer to core_if strucure.
17076 + */
17077 +uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if)
17078 +{
17079 + adpctl_data_t adpctl;
17080 +
17081 + core_if->adp.sense_enabled = 0;
17082 +
17083 + adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
17084 + adpctl.b.enasns = 0;
17085 + adpctl.b.adp_sns_int = 1;
17086 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17087 +
17088 + return 0;
17089 +}
17090 +
17091 +/**
17092 + * Called to turn on the VBUS after initial ADP probe in host mode.
17093 + * If port power was already enabled in cil_hcd_start function then
17094 + * only schedule a timer.
17095 + *
17096 + * @param core_if the pointer to core_if structure.
17097 + */
17098 +void dwc_otg_adp_turnon_vbus(dwc_otg_core_if_t * core_if)
17099 +{
17100 + hprt0_data_t hprt0 = {.d32 = 0 };
17101 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
17102 + DWC_PRINTF("Turn on VBUS for 1.1s, port power is %d\n", hprt0.b.prtpwr);
17103 +
17104 + if (hprt0.b.prtpwr == 0) {
17105 + hprt0.b.prtpwr = 1;
17106 + //DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
17107 + }
17108 +
17109 + dwc_otg_adp_vbuson_timer_start(core_if);
17110 +}
17111 +
17112 +/**
17113 + * Called right after driver is loaded
17114 + * to perform initial actions for ADP
17115 + *
17116 + * @param core_if the pointer to core_if structure.
17117 + * @param is_host - flag for current mode of operation either from GINTSTS or GPWRDN
17118 + */
17119 +void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host)
17120 +{
17121 + gpwrdn_data_t gpwrdn;
17122 +
17123 + DWC_PRINTF("ADP Initial Start\n");
17124 + core_if->adp.adp_started = 1;
17125 +
17126 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
17127 + dwc_otg_disable_global_interrupts(core_if);
17128 + if (is_host) {
17129 + DWC_PRINTF("HOST MODE\n");
17130 + /* Enable Power Down Logic Interrupt*/
17131 + gpwrdn.d32 = 0;
17132 + gpwrdn.b.pmuintsel = 1;
17133 + gpwrdn.b.pmuactv = 1;
17134 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
17135 + /* Initialize first ADP probe to obtain Ramp Time value */
17136 + core_if->adp.initial_probe = 1;
17137 + dwc_otg_adp_probe_start(core_if);
17138 + } else {
17139 + gotgctl_data_t gotgctl;
17140 + gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
17141 + DWC_PRINTF("DEVICE MODE\n");
17142 + if (gotgctl.b.bsesvld == 0) {
17143 + /* Enable Power Down Logic Interrupt*/
17144 + gpwrdn.d32 = 0;
17145 + DWC_PRINTF("VBUS is not valid - start ADP probe\n");
17146 + gpwrdn.b.pmuintsel = 1;
17147 + gpwrdn.b.pmuactv = 1;
17148 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
17149 + core_if->adp.initial_probe = 1;
17150 + dwc_otg_adp_probe_start(core_if);
17151 + } else {
17152 + DWC_PRINTF("VBUS is valid - initialize core as a Device\n");
17153 + core_if->op_state = B_PERIPHERAL;
17154 + dwc_otg_core_init(core_if);
17155 + dwc_otg_enable_global_interrupts(core_if);
17156 + cil_pcd_start(core_if);
17157 + dwc_otg_dump_global_registers(core_if);
17158 + dwc_otg_dump_dev_registers(core_if);
17159 + }
17160 + }
17161 +}
17162 +
17163 +void dwc_otg_adp_init(dwc_otg_core_if_t * core_if)
17164 +{
17165 + core_if->adp.adp_started = 0;
17166 + core_if->adp.initial_probe = 0;
17167 + core_if->adp.probe_timer_values[0] = -1;
17168 + core_if->adp.probe_timer_values[1] = -1;
17169 + core_if->adp.probe_enabled = 0;
17170 + core_if->adp.sense_enabled = 0;
17171 + core_if->adp.sense_timer_started = 0;
17172 + core_if->adp.vbuson_timer_started = 0;
17173 + core_if->adp.probe_counter = 0;
17174 + core_if->adp.gpwrdn = 0;
17175 + core_if->adp.attached = DWC_OTG_ADP_UNKOWN;
17176 + /* Initialize timers */
17177 + core_if->adp.sense_timer =
17178 + DWC_TIMER_ALLOC("ADP SENSE TIMER", adp_sense_timeout, core_if);
17179 + core_if->adp.vbuson_timer =
17180 + DWC_TIMER_ALLOC("ADP VBUS ON TIMER", adp_vbuson_timeout, core_if);
17181 + if (!core_if->adp.sense_timer || !core_if->adp.vbuson_timer)
17182 + {
17183 + DWC_ERROR("Could not allocate memory for ADP timers\n");
17184 + }
17185 +}
17186 +
17187 +void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if)
17188 +{
17189 + gpwrdn_data_t gpwrdn = { .d32 = 0 };
17190 + gpwrdn.b.pmuintsel = 1;
17191 + gpwrdn.b.pmuactv = 1;
17192 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17193 +
17194 + if (core_if->adp.probe_enabled)
17195 + dwc_otg_adp_probe_stop(core_if);
17196 + if (core_if->adp.sense_enabled)
17197 + dwc_otg_adp_sense_stop(core_if);
17198 + if (core_if->adp.sense_timer_started)
17199 + DWC_TIMER_CANCEL(core_if->adp.sense_timer);
17200 + if (core_if->adp.vbuson_timer_started)
17201 + DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
17202 + DWC_TIMER_FREE(core_if->adp.sense_timer);
17203 + DWC_TIMER_FREE(core_if->adp.vbuson_timer);
17204 +}
17205 +
17206 +/////////////////////////////////////////////////////////////////////
17207 +////////////// ADP Interrupt Handlers ///////////////////////////////
17208 +/////////////////////////////////////////////////////////////////////
17209 +/**
17210 + * This function sets Ramp Timer values
17211 + */
17212 +static uint32_t set_timer_value(dwc_otg_core_if_t * core_if, uint32_t val)
17213 +{
17214 + if (core_if->adp.probe_timer_values[0] == -1) {
17215 + core_if->adp.probe_timer_values[0] = val;
17216 + core_if->adp.probe_timer_values[1] = -1;
17217 + return 1;
17218 + } else {
17219 + core_if->adp.probe_timer_values[1] =
17220 + core_if->adp.probe_timer_values[0];
17221 + core_if->adp.probe_timer_values[0] = val;
17222 + return 0;
17223 + }
17224 +}
17225 +
17226 +/**
17227 + * This function compares Ramp Timer values
17228 + */
17229 +static uint32_t compare_timer_values(dwc_otg_core_if_t * core_if)
17230 +{
17231 + uint32_t diff;
17232 + if (core_if->adp.probe_timer_values[0]>=core_if->adp.probe_timer_values[1])
17233 + diff = core_if->adp.probe_timer_values[0]-core_if->adp.probe_timer_values[1];
17234 + else
17235 + diff = core_if->adp.probe_timer_values[1]-core_if->adp.probe_timer_values[0];
17236 + if(diff < 2) {
17237 + return 0;
17238 + } else {
17239 + return 1;
17240 + }
17241 +}
17242 +
17243 +/**
17244 + * This function handles ADP Probe Interrupts
17245 + */
17246 +static int32_t dwc_otg_adp_handle_prb_intr(dwc_otg_core_if_t * core_if,
17247 + uint32_t val)
17248 +{
17249 + adpctl_data_t adpctl = {.d32 = 0 };
17250 + gpwrdn_data_t gpwrdn, temp;
17251 + adpctl.d32 = val;
17252 +
17253 + temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17254 + core_if->adp.probe_counter++;
17255 + core_if->adp.gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17256 + if (adpctl.b.rtim == 0 && !temp.b.idsts){
17257 + DWC_PRINTF("RTIM value is 0\n");
17258 + goto exit;
17259 + }
17260 + if (set_timer_value(core_if, adpctl.b.rtim) &&
17261 + core_if->adp.initial_probe) {
17262 + core_if->adp.initial_probe = 0;
17263 + dwc_otg_adp_probe_stop(core_if);
17264 + gpwrdn.d32 = 0;
17265 + gpwrdn.b.pmuactv = 1;
17266 + gpwrdn.b.pmuintsel = 1;
17267 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17268 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
17269 +
17270 + /* check which value is for device mode and which for Host mode */
17271 + if (!temp.b.idsts) { /* considered host mode value is 0 */
17272 + /*
17273 + * Turn on VBUS after initial ADP probe.
17274 + */
17275 + core_if->op_state = A_HOST;
17276 + dwc_otg_enable_global_interrupts(core_if);
17277 + DWC_SPINUNLOCK(core_if->lock);
17278 + cil_hcd_start(core_if);
17279 + dwc_otg_adp_turnon_vbus(core_if);
17280 + DWC_SPINLOCK(core_if->lock);
17281 + } else {
17282 + /*
17283 + * Initiate SRP after initial ADP probe.
17284 + */
17285 + dwc_otg_enable_global_interrupts(core_if);
17286 + dwc_otg_initiate_srp(core_if);
17287 + }
17288 + } else if (core_if->adp.probe_counter > 2){
17289 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17290 + if (compare_timer_values(core_if)) {
17291 + DWC_PRINTF("Difference in timer values !!! \n");
17292 +// core_if->adp.attached = DWC_OTG_ADP_ATTACHED;
17293 + dwc_otg_adp_probe_stop(core_if);
17294 +
17295 + /* Power on the core */
17296 + if (core_if->power_down == 2) {
17297 + gpwrdn.b.pwrdnswtch = 1;
17298 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17299 + gpwrdn, 0, gpwrdn.d32);
17300 + }
17301 +
17302 + /* check which value is for device mode and which for Host mode */
17303 + if (!temp.b.idsts) { /* considered host mode value is 0 */
17304 + /* Disable Interrupt from Power Down Logic */
17305 + gpwrdn.d32 = 0;
17306 + gpwrdn.b.pmuintsel = 1;
17307 + gpwrdn.b.pmuactv = 1;
17308 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17309 + gpwrdn, gpwrdn.d32, 0);
17310 +
17311 + /*
17312 + * Initialize the Core for Host mode.
17313 + */
17314 + core_if->op_state = A_HOST;
17315 + dwc_otg_core_init(core_if);
17316 + dwc_otg_enable_global_interrupts(core_if);
17317 + cil_hcd_start(core_if);
17318 + } else {
17319 + gotgctl_data_t gotgctl;
17320 + /* Mask SRP detected interrupt from Power Down Logic */
17321 + gpwrdn.d32 = 0;
17322 + gpwrdn.b.srp_det_msk = 1;
17323 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17324 + gpwrdn, gpwrdn.d32, 0);
17325 +
17326 + /* Disable Power Down Logic */
17327 + gpwrdn.d32 = 0;
17328 + gpwrdn.b.pmuintsel = 1;
17329 + gpwrdn.b.pmuactv = 1;
17330 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17331 + gpwrdn, gpwrdn.d32, 0);
17332 +
17333 + /*
17334 + * Initialize the Core for Device mode.
17335 + */
17336 + core_if->op_state = B_PERIPHERAL;
17337 + dwc_otg_core_init(core_if);
17338 + dwc_otg_enable_global_interrupts(core_if);
17339 + cil_pcd_start(core_if);
17340 +
17341 + gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
17342 + if (!gotgctl.b.bsesvld) {
17343 + dwc_otg_initiate_srp(core_if);
17344 + }
17345 + }
17346 + }
17347 + if (core_if->power_down == 2) {
17348 + if (gpwrdn.b.bsessvld) {
17349 + /* Mask SRP detected interrupt from Power Down Logic */
17350 + gpwrdn.d32 = 0;
17351 + gpwrdn.b.srp_det_msk = 1;
17352 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17353 +
17354 + /* Disable Power Down Logic */
17355 + gpwrdn.d32 = 0;
17356 + gpwrdn.b.pmuactv = 1;
17357 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17358 +
17359 + /*
17360 + * Initialize the Core for Device mode.
17361 + */
17362 + core_if->op_state = B_PERIPHERAL;
17363 + dwc_otg_core_init(core_if);
17364 + dwc_otg_enable_global_interrupts(core_if);
17365 + cil_pcd_start(core_if);
17366 + }
17367 + }
17368 + }
17369 +exit:
17370 + /* Clear interrupt */
17371 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17372 + adpctl.b.adp_prb_int = 1;
17373 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17374 +
17375 + return 0;
17376 +}
17377 +
17378 +/**
17379 + * This function hadles ADP Sense Interrupt
17380 + */
17381 +static int32_t dwc_otg_adp_handle_sns_intr(dwc_otg_core_if_t * core_if)
17382 +{
17383 + adpctl_data_t adpctl;
17384 + /* Stop ADP Sense timer */
17385 + DWC_TIMER_CANCEL(core_if->adp.sense_timer);
17386 +
17387 + /* Restart ADP Sense timer */
17388 + dwc_otg_adp_sense_timer_start(core_if);
17389 +
17390 + /* Clear interrupt */
17391 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17392 + adpctl.b.adp_sns_int = 1;
17393 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17394 +
17395 + return 0;
17396 +}
17397 +
17398 +/**
17399 + * This function handles ADP Probe Interrupts
17400 + */
17401 +static int32_t dwc_otg_adp_handle_prb_tmout_intr(dwc_otg_core_if_t * core_if,
17402 + uint32_t val)
17403 +{
17404 + adpctl_data_t adpctl = {.d32 = 0 };
17405 + adpctl.d32 = val;
17406 + set_timer_value(core_if, adpctl.b.rtim);
17407 +
17408 + /* Clear interrupt */
17409 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17410 + adpctl.b.adp_tmout_int = 1;
17411 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17412 +
17413 + return 0;
17414 +}
17415 +
17416 +/**
17417 + * ADP Interrupt handler.
17418 + *
17419 + */
17420 +int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if)
17421 +{
17422 + int retval = 0;
17423 + adpctl_data_t adpctl = {.d32 = 0};
17424 +
17425 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17426 + DWC_PRINTF("ADPCTL = %08x\n",adpctl.d32);
17427 +
17428 + if (adpctl.b.adp_sns_int & adpctl.b.adp_sns_int_msk) {
17429 + DWC_PRINTF("ADP Sense interrupt\n");
17430 + retval |= dwc_otg_adp_handle_sns_intr(core_if);
17431 + }
17432 + if (adpctl.b.adp_tmout_int & adpctl.b.adp_tmout_int_msk) {
17433 + DWC_PRINTF("ADP timeout interrupt\n");
17434 + retval |= dwc_otg_adp_handle_prb_tmout_intr(core_if, adpctl.d32);
17435 + }
17436 + if (adpctl.b.adp_prb_int & adpctl.b.adp_prb_int_msk) {
17437 + DWC_PRINTF("ADP Probe interrupt\n");
17438 + adpctl.b.adp_prb_int = 1;
17439 + retval |= dwc_otg_adp_handle_prb_intr(core_if, adpctl.d32);
17440 + }
17441 +
17442 +// dwc_otg_adp_modify_reg(core_if, adpctl.d32, 0);
17443 + //dwc_otg_adp_write_reg(core_if, adpctl.d32);
17444 + DWC_PRINTF("RETURN FROM ADP ISR\n");
17445 +
17446 + return retval;
17447 +}
17448 +
17449 +/**
17450 + *
17451 + * @param core_if Programming view of DWC_otg controller.
17452 + */
17453 +int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if)
17454 +{
17455 +
17456 +#ifndef DWC_HOST_ONLY
17457 + hprt0_data_t hprt0;
17458 + gpwrdn_data_t gpwrdn;
17459 + DWC_DEBUGPL(DBG_ANY, "++ Power Down Logic Session Request Interrupt++\n");
17460 +
17461 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17462 + /* check which value is for device mode and which for Host mode */
17463 + if (!gpwrdn.b.idsts) { /* considered host mode value is 0 */
17464 + DWC_PRINTF("SRP: Host mode\n");
17465 +
17466 + if (core_if->adp_enable) {
17467 + dwc_otg_adp_probe_stop(core_if);
17468 +
17469 + /* Power on the core */
17470 + if (core_if->power_down == 2) {
17471 + gpwrdn.b.pwrdnswtch = 1;
17472 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17473 + gpwrdn, 0, gpwrdn.d32);
17474 + }
17475 +
17476 + core_if->op_state = A_HOST;
17477 + dwc_otg_core_init(core_if);
17478 + dwc_otg_enable_global_interrupts(core_if);
17479 + cil_hcd_start(core_if);
17480 + }
17481 +
17482 + /* Turn on the port power bit. */
17483 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
17484 + hprt0.b.prtpwr = 1;
17485 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
17486 +
17487 + /* Start the Connection timer. So a message can be displayed
17488 + * if connect does not occur within 10 seconds. */
17489 + cil_hcd_session_start(core_if);
17490 + } else {
17491 + DWC_PRINTF("SRP: Device mode %s\n", __FUNCTION__);
17492 + if (core_if->adp_enable) {
17493 + dwc_otg_adp_probe_stop(core_if);
17494 +
17495 + /* Power on the core */
17496 + if (core_if->power_down == 2) {
17497 + gpwrdn.b.pwrdnswtch = 1;
17498 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17499 + gpwrdn, 0, gpwrdn.d32);
17500 + }
17501 +
17502 + gpwrdn.d32 = 0;
17503 + gpwrdn.b.pmuactv = 0;
17504 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
17505 + gpwrdn.d32);
17506 +
17507 + core_if->op_state = B_PERIPHERAL;
17508 + dwc_otg_core_init(core_if);
17509 + dwc_otg_enable_global_interrupts(core_if);
17510 + cil_pcd_start(core_if);
17511 + }
17512 + }
17513 +#endif
17514 + return 1;
17515 +}
17516 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_adp.h b/drivers/usb/host/dwc_otg/dwc_otg_adp.h
17517 new file mode 100644
17518 index 0000000..4110b25
17519 --- /dev/null
17520 +++ b/drivers/usb/host/dwc_otg/dwc_otg_adp.h
17521 @@ -0,0 +1,80 @@
17522 +/* ==========================================================================
17523 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.h $
17524 + * $Revision: #7 $
17525 + * $Date: 2011/10/24 $
17526 + * $Change: 1871159 $
17527 + *
17528 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
17529 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
17530 + * otherwise expressly agreed to in writing between Synopsys and you.
17531 + *
17532 + * The Software IS NOT an item of Licensed Software or Licensed Product under
17533 + * any End User Software License Agreement or Agreement for Licensed Product
17534 + * with Synopsys or any supplement thereto. You are permitted to use and
17535 + * redistribute this Software in source and binary forms, with or without
17536 + * modification, provided that redistributions of source code must retain this
17537 + * notice. You may not view, use, disclose, copy or distribute this file or
17538 + * any information contained herein except pursuant to this license grant from
17539 + * Synopsys. If you do not agree with this notice, including the disclaimer
17540 + * below, then you are not authorized to use the Software.
17541 + *
17542 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
17543 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17544 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17545 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
17546 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17547 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17548 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17549 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17550 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17551 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
17552 + * DAMAGE.
17553 + * ========================================================================== */
17554 +
17555 +#ifndef __DWC_OTG_ADP_H__
17556 +#define __DWC_OTG_ADP_H__
17557 +
17558 +/**
17559 + * @file
17560 + *
17561 + * This file contains the Attach Detect Protocol interfaces and defines
17562 + * (functions) and structures for Linux.
17563 + *
17564 + */
17565 +
17566 +#define DWC_OTG_ADP_UNATTACHED 0
17567 +#define DWC_OTG_ADP_ATTACHED 1
17568 +#define DWC_OTG_ADP_UNKOWN 2
17569 +
17570 +typedef struct dwc_otg_adp {
17571 + uint32_t adp_started;
17572 + uint32_t initial_probe;
17573 + int32_t probe_timer_values[2];
17574 + uint32_t probe_enabled;
17575 + uint32_t sense_enabled;
17576 + dwc_timer_t *sense_timer;
17577 + uint32_t sense_timer_started;
17578 + dwc_timer_t *vbuson_timer;
17579 + uint32_t vbuson_timer_started;
17580 + uint32_t attached;
17581 + uint32_t probe_counter;
17582 + uint32_t gpwrdn;
17583 +} dwc_otg_adp_t;
17584 +
17585 +/**
17586 + * Attach Detect Protocol functions
17587 + */
17588 +
17589 +extern void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value);
17590 +extern uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if);
17591 +extern uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if);
17592 +extern uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if);
17593 +extern uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if);
17594 +extern uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if);
17595 +extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
17596 +extern void dwc_otg_adp_init(dwc_otg_core_if_t * core_if);
17597 +extern void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if);
17598 +extern int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if);
17599 +extern int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if);
17600 +
17601 +#endif //__DWC_OTG_ADP_H__
17602 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_attr.c b/drivers/usb/host/dwc_otg/dwc_otg_attr.c
17603 new file mode 100644
17604 index 0000000..fab2961
17605 --- /dev/null
17606 +++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.c
17607 @@ -0,0 +1,1210 @@
17608 +/* ==========================================================================
17609 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.c $
17610 + * $Revision: #44 $
17611 + * $Date: 2010/11/29 $
17612 + * $Change: 1636033 $
17613 + *
17614 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
17615 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
17616 + * otherwise expressly agreed to in writing between Synopsys and you.
17617 + *
17618 + * The Software IS NOT an item of Licensed Software or Licensed Product under
17619 + * any End User Software License Agreement or Agreement for Licensed Product
17620 + * with Synopsys or any supplement thereto. You are permitted to use and
17621 + * redistribute this Software in source and binary forms, with or without
17622 + * modification, provided that redistributions of source code must retain this
17623 + * notice. You may not view, use, disclose, copy or distribute this file or
17624 + * any information contained herein except pursuant to this license grant from
17625 + * Synopsys. If you do not agree with this notice, including the disclaimer
17626 + * below, then you are not authorized to use the Software.
17627 + *
17628 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
17629 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17630 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17631 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
17632 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17633 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17634 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17635 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17636 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17637 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
17638 + * DAMAGE.
17639 + * ========================================================================== */
17640 +
17641 +/** @file
17642 + *
17643 + * The diagnostic interface will provide access to the controller for
17644 + * bringing up the hardware and testing. The Linux driver attributes
17645 + * feature will be used to provide the Linux Diagnostic
17646 + * Interface. These attributes are accessed through sysfs.
17647 + */
17648 +
17649 +/** @page "Linux Module Attributes"
17650 + *
17651 + * The Linux module attributes feature is used to provide the Linux
17652 + * Diagnostic Interface. These attributes are accessed through sysfs.
17653 + * The diagnostic interface will provide access to the controller for
17654 + * bringing up the hardware and testing.
17655 +
17656 + The following table shows the attributes.
17657 + <table>
17658 + <tr>
17659 + <td><b> Name</b></td>
17660 + <td><b> Description</b></td>
17661 + <td><b> Access</b></td>
17662 + </tr>
17663 +
17664 + <tr>
17665 + <td> mode </td>
17666 + <td> Returns the current mode: 0 for device mode, 1 for host mode</td>
17667 + <td> Read</td>
17668 + </tr>
17669 +
17670 + <tr>
17671 + <td> hnpcapable </td>
17672 + <td> Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register.
17673 + Read returns the current value.</td>
17674 + <td> Read/Write</td>
17675 + </tr>
17676 +
17677 + <tr>
17678 + <td> srpcapable </td>
17679 + <td> Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register.
17680 + Read returns the current value.</td>
17681 + <td> Read/Write</td>
17682 + </tr>
17683 +
17684 + <tr>
17685 + <td> hsic_connect </td>
17686 + <td> Gets or sets the "HSIC-Connect" bit in the GLPMCFG Register.
17687 + Read returns the current value.</td>
17688 + <td> Read/Write</td>
17689 + </tr>
17690 +
17691 + <tr>
17692 + <td> inv_sel_hsic </td>
17693 + <td> Gets or sets the "Invert Select HSIC" bit in the GLPMFG Register.
17694 + Read returns the current value.</td>
17695 + <td> Read/Write</td>
17696 + </tr>
17697 +
17698 + <tr>
17699 + <td> hnp </td>
17700 + <td> Initiates the Host Negotiation Protocol. Read returns the status.</td>
17701 + <td> Read/Write</td>
17702 + </tr>
17703 +
17704 + <tr>
17705 + <td> srp </td>
17706 + <td> Initiates the Session Request Protocol. Read returns the status.</td>
17707 + <td> Read/Write</td>
17708 + </tr>
17709 +
17710 + <tr>
17711 + <td> buspower </td>
17712 + <td> Gets or sets the Power State of the bus (0 - Off or 1 - On)</td>
17713 + <td> Read/Write</td>
17714 + </tr>
17715 +
17716 + <tr>
17717 + <td> bussuspend </td>
17718 + <td> Suspends the USB bus.</td>
17719 + <td> Read/Write</td>
17720 + </tr>
17721 +
17722 + <tr>
17723 + <td> busconnected </td>
17724 + <td> Gets the connection status of the bus</td>
17725 + <td> Read</td>
17726 + </tr>
17727 +
17728 + <tr>
17729 + <td> gotgctl </td>
17730 + <td> Gets or sets the Core Control Status Register.</td>
17731 + <td> Read/Write</td>
17732 + </tr>
17733 +
17734 + <tr>
17735 + <td> gusbcfg </td>
17736 + <td> Gets or sets the Core USB Configuration Register</td>
17737 + <td> Read/Write</td>
17738 + </tr>
17739 +
17740 + <tr>
17741 + <td> grxfsiz </td>
17742 + <td> Gets or sets the Receive FIFO Size Register</td>
17743 + <td> Read/Write</td>
17744 + </tr>
17745 +
17746 + <tr>
17747 + <td> gnptxfsiz </td>
17748 + <td> Gets or sets the non-periodic Transmit Size Register</td>
17749 + <td> Read/Write</td>
17750 + </tr>
17751 +
17752 + <tr>
17753 + <td> gpvndctl </td>
17754 + <td> Gets or sets the PHY Vendor Control Register</td>
17755 + <td> Read/Write</td>
17756 + </tr>
17757 +
17758 + <tr>
17759 + <td> ggpio </td>
17760 + <td> Gets the value in the lower 16-bits of the General Purpose IO Register
17761 + or sets the upper 16 bits.</td>
17762 + <td> Read/Write</td>
17763 + </tr>
17764 +
17765 + <tr>
17766 + <td> guid </td>
17767 + <td> Gets or sets the value of the User ID Register</td>
17768 + <td> Read/Write</td>
17769 + </tr>
17770 +
17771 + <tr>
17772 + <td> gsnpsid </td>
17773 + <td> Gets the value of the Synopsys ID Regester</td>
17774 + <td> Read</td>
17775 + </tr>
17776 +
17777 + <tr>
17778 + <td> devspeed </td>
17779 + <td> Gets or sets the device speed setting in the DCFG register</td>
17780 + <td> Read/Write</td>
17781 + </tr>
17782 +
17783 + <tr>
17784 + <td> enumspeed </td>
17785 + <td> Gets the device enumeration Speed.</td>
17786 + <td> Read</td>
17787 + </tr>
17788 +
17789 + <tr>
17790 + <td> hptxfsiz </td>
17791 + <td> Gets the value of the Host Periodic Transmit FIFO</td>
17792 + <td> Read</td>
17793 + </tr>
17794 +
17795 + <tr>
17796 + <td> hprt0 </td>
17797 + <td> Gets or sets the value in the Host Port Control and Status Register</td>
17798 + <td> Read/Write</td>
17799 + </tr>
17800 +
17801 + <tr>
17802 + <td> regoffset </td>
17803 + <td> Sets the register offset for the next Register Access</td>
17804 + <td> Read/Write</td>
17805 + </tr>
17806 +
17807 + <tr>
17808 + <td> regvalue </td>
17809 + <td> Gets or sets the value of the register at the offset in the regoffset attribute.</td>
17810 + <td> Read/Write</td>
17811 + </tr>
17812 +
17813 + <tr>
17814 + <td> remote_wakeup </td>
17815 + <td> On read, shows the status of Remote Wakeup. On write, initiates a remote
17816 + wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote
17817 + Wakeup signalling bit in the Device Control Register is set for 1
17818 + milli-second.</td>
17819 + <td> Read/Write</td>
17820 + </tr>
17821 +
17822 + <tr>
17823 + <td> rem_wakeup_pwrdn </td>
17824 + <td> On read, shows the status core - hibernated or not. On write, initiates
17825 + a remote wakeup of the device from Hibernation. </td>
17826 + <td> Read/Write</td>
17827 + </tr>
17828 +
17829 + <tr>
17830 + <td> mode_ch_tim_en </td>
17831 + <td> This bit is used to enable or disable the host core to wait for 200 PHY
17832 + clock cycles at the end of Resume to change the opmode signal to the PHY to 00
17833 + after Suspend or LPM. </td>
17834 + <td> Read/Write</td>
17835 + </tr>
17836 +
17837 + <tr>
17838 + <td> fr_interval </td>
17839 + <td> On read, shows the value of HFIR Frame Interval. On write, dynamically
17840 + reload HFIR register during runtime. The application can write a value to this
17841 + register only after the Port Enable bit of the Host Port Control and Status
17842 + register (HPRT.PrtEnaPort) has been set </td>
17843 + <td> Read/Write</td>
17844 + </tr>
17845 +
17846 + <tr>
17847 + <td> disconnect_us </td>
17848 + <td> On read, shows the status of disconnect_device_us. On write, sets disconnect_us
17849 + which causes soft disconnect for 100us. Applicable only for device mode of operation.</td>
17850 + <td> Read/Write</td>
17851 + </tr>
17852 +
17853 + <tr>
17854 + <td> regdump </td>
17855 + <td> Dumps the contents of core registers.</td>
17856 + <td> Read</td>
17857 + </tr>
17858 +
17859 + <tr>
17860 + <td> spramdump </td>
17861 + <td> Dumps the contents of core registers.</td>
17862 + <td> Read</td>
17863 + </tr>
17864 +
17865 + <tr>
17866 + <td> hcddump </td>
17867 + <td> Dumps the current HCD state.</td>
17868 + <td> Read</td>
17869 + </tr>
17870 +
17871 + <tr>
17872 + <td> hcd_frrem </td>
17873 + <td> Shows the average value of the Frame Remaining
17874 + field in the Host Frame Number/Frame Remaining register when an SOF interrupt
17875 + occurs. This can be used to determine the average interrupt latency. Also
17876 + shows the average Frame Remaining value for start_transfer and the "a" and
17877 + "b" sample points. The "a" and "b" sample points may be used during debugging
17878 + bto determine how long it takes to execute a section of the HCD code.</td>
17879 + <td> Read</td>
17880 + </tr>
17881 +
17882 + <tr>
17883 + <td> rd_reg_test </td>
17884 + <td> Displays the time required to read the GNPTXFSIZ register many times
17885 + (the output shows the number of times the register is read).
17886 + <td> Read</td>
17887 + </tr>
17888 +
17889 + <tr>
17890 + <td> wr_reg_test </td>
17891 + <td> Displays the time required to write the GNPTXFSIZ register many times
17892 + (the output shows the number of times the register is written).
17893 + <td> Read</td>
17894 + </tr>
17895 +
17896 + <tr>
17897 + <td> lpm_response </td>
17898 + <td> Gets or sets lpm_response mode. Applicable only in device mode.
17899 + <td> Write</td>
17900 + </tr>
17901 +
17902 + <tr>
17903 + <td> sleep_status </td>
17904 + <td> Shows sleep status of device.
17905 + <td> Read</td>
17906 + </tr>
17907 +
17908 + </table>
17909 +
17910 + Example usage:
17911 + To get the current mode:
17912 + cat /sys/devices/lm0/mode
17913 +
17914 + To power down the USB:
17915 + echo 0 > /sys/devices/lm0/buspower
17916 + */
17917 +
17918 +#include "dwc_otg_os_dep.h"
17919 +#include "dwc_os.h"
17920 +#include "dwc_otg_driver.h"
17921 +#include "dwc_otg_attr.h"
17922 +#include "dwc_otg_core_if.h"
17923 +#include "dwc_otg_pcd_if.h"
17924 +#include "dwc_otg_hcd_if.h"
17925 +
17926 +/*
17927 + * MACROs for defining sysfs attribute
17928 + */
17929 +#ifdef LM_INTERFACE
17930 +
17931 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17932 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17933 +{ \
17934 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17935 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17936 + uint32_t val; \
17937 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17938 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
17939 +}
17940 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17941 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17942 + const char *buf, size_t count) \
17943 +{ \
17944 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17945 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17946 + uint32_t set = simple_strtoul(buf, NULL, 16); \
17947 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
17948 + return count; \
17949 +}
17950 +
17951 +#elif defined(PCI_INTERFACE)
17952 +
17953 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17954 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17955 +{ \
17956 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17957 + uint32_t val; \
17958 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17959 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
17960 +}
17961 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17962 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17963 + const char *buf, size_t count) \
17964 +{ \
17965 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17966 + uint32_t set = simple_strtoul(buf, NULL, 16); \
17967 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
17968 + return count; \
17969 +}
17970 +
17971 +#elif defined(PLATFORM_INTERFACE)
17972 +
17973 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17974 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17975 +{ \
17976 + struct platform_device *platform_dev = \
17977 + container_of(_dev, struct platform_device, dev); \
17978 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17979 + uint32_t val; \
17980 + DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
17981 + __func__, _dev, platform_dev, otg_dev); \
17982 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17983 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
17984 +}
17985 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17986 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17987 + const char *buf, size_t count) \
17988 +{ \
17989 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
17990 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17991 + uint32_t set = simple_strtoul(buf, NULL, 16); \
17992 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
17993 + return count; \
17994 +}
17995 +#endif
17996 +
17997 +/*
17998 + * MACROs for defining sysfs attribute for 32-bit registers
17999 + */
18000 +#ifdef LM_INTERFACE
18001 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
18002 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
18003 +{ \
18004 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
18005 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
18006 + uint32_t val; \
18007 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
18008 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
18009 +}
18010 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
18011 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
18012 + const char *buf, size_t count) \
18013 +{ \
18014 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
18015 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
18016 + uint32_t val = simple_strtoul(buf, NULL, 16); \
18017 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
18018 + return count; \
18019 +}
18020 +#elif defined(PCI_INTERFACE)
18021 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
18022 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
18023 +{ \
18024 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
18025 + uint32_t val; \
18026 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
18027 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
18028 +}
18029 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
18030 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
18031 + const char *buf, size_t count) \
18032 +{ \
18033 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
18034 + uint32_t val = simple_strtoul(buf, NULL, 16); \
18035 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
18036 + return count; \
18037 +}
18038 +
18039 +#elif defined(PLATFORM_INTERFACE)
18040 +#include "dwc_otg_dbg.h"
18041 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
18042 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
18043 +{ \
18044 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
18045 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
18046 + uint32_t val; \
18047 + DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
18048 + __func__, _dev, platform_dev, otg_dev); \
18049 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
18050 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
18051 +}
18052 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
18053 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
18054 + const char *buf, size_t count) \
18055 +{ \
18056 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
18057 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
18058 + uint32_t val = simple_strtoul(buf, NULL, 16); \
18059 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
18060 + return count; \
18061 +}
18062 +
18063 +#endif
18064 +
18065 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_string_) \
18066 +DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
18067 +DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
18068 +DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
18069 +
18070 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_string_) \
18071 +DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
18072 +DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
18073 +
18074 +#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \
18075 +DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
18076 +DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
18077 +DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
18078 +
18079 +#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \
18080 +DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
18081 +DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
18082 +
18083 +/** @name Functions for Show/Store of Attributes */
18084 +/**@{*/
18085 +
18086 +/**
18087 + * Helper function returning the otg_device structure of the given device
18088 + */
18089 +static dwc_otg_device_t *dwc_otg_drvdev(struct device *_dev)
18090 +{
18091 + dwc_otg_device_t *otg_dev;
18092 + DWC_OTG_GETDRVDEV(otg_dev, _dev);
18093 + return otg_dev;
18094 +}
18095 +
18096 +/**
18097 + * Show the register offset of the Register Access.
18098 + */
18099 +static ssize_t regoffset_show(struct device *_dev,
18100 + struct device_attribute *attr, char *buf)
18101 +{
18102 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18103 + return snprintf(buf, sizeof("0xFFFFFFFF\n") + 1, "0x%08x\n",
18104 + otg_dev->os_dep.reg_offset);
18105 +}
18106 +
18107 +/**
18108 + * Set the register offset for the next Register Access Read/Write
18109 + */
18110 +static ssize_t regoffset_store(struct device *_dev,
18111 + struct device_attribute *attr,
18112 + const char *buf, size_t count)
18113 +{
18114 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18115 + uint32_t offset = simple_strtoul(buf, NULL, 16);
18116 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
18117 + if (offset < SZ_256K) {
18118 +#elif defined(PCI_INTERFACE)
18119 + if (offset < 0x00040000) {
18120 +#endif
18121 + otg_dev->os_dep.reg_offset = offset;
18122 + } else {
18123 + dev_err(_dev, "invalid offset\n");
18124 + }
18125 +
18126 + return count;
18127 +}
18128 +
18129 +DEVICE_ATTR(regoffset, S_IRUGO | S_IWUSR, regoffset_show, regoffset_store);
18130 +
18131 +/**
18132 + * Show the value of the register at the offset in the reg_offset
18133 + * attribute.
18134 + */
18135 +static ssize_t regvalue_show(struct device *_dev,
18136 + struct device_attribute *attr, char *buf)
18137 +{
18138 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18139 + uint32_t val;
18140 + volatile uint32_t *addr;
18141 +
18142 + if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
18143 + /* Calculate the address */
18144 + addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
18145 + (uint8_t *) otg_dev->os_dep.base);
18146 + val = DWC_READ_REG32(addr);
18147 + return snprintf(buf,
18148 + sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n") + 1,
18149 + "Reg@0x%06x = 0x%08x\n", otg_dev->os_dep.reg_offset,
18150 + val);
18151 + } else {
18152 + dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->os_dep.reg_offset);
18153 + return sprintf(buf, "invalid offset\n");
18154 + }
18155 +}
18156 +
18157 +/**
18158 + * Store the value in the register at the offset in the reg_offset
18159 + * attribute.
18160 + *
18161 + */
18162 +static ssize_t regvalue_store(struct device *_dev,
18163 + struct device_attribute *attr,
18164 + const char *buf, size_t count)
18165 +{
18166 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18167 + volatile uint32_t *addr;
18168 + uint32_t val = simple_strtoul(buf, NULL, 16);
18169 + //dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val);
18170 + if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
18171 + /* Calculate the address */
18172 + addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
18173 + (uint8_t *) otg_dev->os_dep.base);
18174 + DWC_WRITE_REG32(addr, val);
18175 + } else {
18176 + dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
18177 + otg_dev->os_dep.reg_offset);
18178 + }
18179 + return count;
18180 +}
18181 +
18182 +DEVICE_ATTR(regvalue, S_IRUGO | S_IWUSR, regvalue_show, regvalue_store);
18183 +
18184 +/*
18185 + * Attributes
18186 + */
18187 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode, "Mode");
18188 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable, "HNPCapable");
18189 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable, "SRPCapable");
18190 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hsic_connect, "HSIC Connect");
18191 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(inv_sel_hsic, "Invert Select HSIC");
18192 +
18193 +//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
18194 +//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
18195 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, "Bus Connected");
18196 +
18197 +DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl, 0, "GOTGCTL");
18198 +DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,
18199 + &(otg_dev->core_if->core_global_regs->gusbcfg),
18200 + "GUSBCFG");
18201 +DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,
18202 + &(otg_dev->core_if->core_global_regs->grxfsiz),
18203 + "GRXFSIZ");
18204 +DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,
18205 + &(otg_dev->core_if->core_global_regs->gnptxfsiz),
18206 + "GNPTXFSIZ");
18207 +DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,
18208 + &(otg_dev->core_if->core_global_regs->gpvndctl),
18209 + "GPVNDCTL");
18210 +DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,
18211 + &(otg_dev->core_if->core_global_regs->ggpio),
18212 + "GGPIO");
18213 +DWC_OTG_DEVICE_ATTR_REG32_RW(guid, &(otg_dev->core_if->core_global_regs->guid),
18214 + "GUID");
18215 +DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,
18216 + &(otg_dev->core_if->core_global_regs->gsnpsid),
18217 + "GSNPSID");
18218 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed, "Device Speed");
18219 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed, "Device Enumeration Speed");
18220 +
18221 +DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,
18222 + &(otg_dev->core_if->core_global_regs->hptxfsiz),
18223 + "HPTXFSIZ");
18224 +DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, otg_dev->core_if->host_if->hprt0, "HPRT0");
18225 +
18226 +/**
18227 + * @todo Add code to initiate the HNP.
18228 + */
18229 +/**
18230 + * Show the HNP status bit
18231 + */
18232 +static ssize_t hnp_show(struct device *_dev,
18233 + struct device_attribute *attr, char *buf)
18234 +{
18235 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18236 + return sprintf(buf, "HstNegScs = 0x%x\n",
18237 + dwc_otg_get_hnpstatus(otg_dev->core_if));
18238 +}
18239 +
18240 +/**
18241 + * Set the HNP Request bit
18242 + */
18243 +static ssize_t hnp_store(struct device *_dev,
18244 + struct device_attribute *attr,
18245 + const char *buf, size_t count)
18246 +{
18247 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18248 + uint32_t in = simple_strtoul(buf, NULL, 16);
18249 + dwc_otg_set_hnpreq(otg_dev->core_if, in);
18250 + return count;
18251 +}
18252 +
18253 +DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store);
18254 +
18255 +/**
18256 + * @todo Add code to initiate the SRP.
18257 + */
18258 +/**
18259 + * Show the SRP status bit
18260 + */
18261 +static ssize_t srp_show(struct device *_dev,
18262 + struct device_attribute *attr, char *buf)
18263 +{
18264 +#ifndef DWC_HOST_ONLY
18265 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18266 + return sprintf(buf, "SesReqScs = 0x%x\n",
18267 + dwc_otg_get_srpstatus(otg_dev->core_if));
18268 +#else
18269 + return sprintf(buf, "Host Only Mode!\n");
18270 +#endif
18271 +}
18272 +
18273 +/**
18274 + * Set the SRP Request bit
18275 + */
18276 +static ssize_t srp_store(struct device *_dev,
18277 + struct device_attribute *attr,
18278 + const char *buf, size_t count)
18279 +{
18280 +#ifndef DWC_HOST_ONLY
18281 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18282 + dwc_otg_pcd_initiate_srp(otg_dev->pcd);
18283 +#endif
18284 + return count;
18285 +}
18286 +
18287 +DEVICE_ATTR(srp, 0644, srp_show, srp_store);
18288 +
18289 +/**
18290 + * @todo Need to do more for power on/off?
18291 + */
18292 +/**
18293 + * Show the Bus Power status
18294 + */
18295 +static ssize_t buspower_show(struct device *_dev,
18296 + struct device_attribute *attr, char *buf)
18297 +{
18298 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18299 + return sprintf(buf, "Bus Power = 0x%x\n",
18300 + dwc_otg_get_prtpower(otg_dev->core_if));
18301 +}
18302 +
18303 +/**
18304 + * Set the Bus Power status
18305 + */
18306 +static ssize_t buspower_store(struct device *_dev,
18307 + struct device_attribute *attr,
18308 + const char *buf, size_t count)
18309 +{
18310 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18311 + uint32_t on = simple_strtoul(buf, NULL, 16);
18312 + dwc_otg_set_prtpower(otg_dev->core_if, on);
18313 + return count;
18314 +}
18315 +
18316 +DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store);
18317 +
18318 +/**
18319 + * @todo Need to do more for suspend?
18320 + */
18321 +/**
18322 + * Show the Bus Suspend status
18323 + */
18324 +static ssize_t bussuspend_show(struct device *_dev,
18325 + struct device_attribute *attr, char *buf)
18326 +{
18327 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18328 + return sprintf(buf, "Bus Suspend = 0x%x\n",
18329 + dwc_otg_get_prtsuspend(otg_dev->core_if));
18330 +}
18331 +
18332 +/**
18333 + * Set the Bus Suspend status
18334 + */
18335 +static ssize_t bussuspend_store(struct device *_dev,
18336 + struct device_attribute *attr,
18337 + const char *buf, size_t count)
18338 +{
18339 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18340 + uint32_t in = simple_strtoul(buf, NULL, 16);
18341 + dwc_otg_set_prtsuspend(otg_dev->core_if, in);
18342 + return count;
18343 +}
18344 +
18345 +DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store);
18346 +
18347 +/**
18348 + * Show the Mode Change Ready Timer status
18349 + */
18350 +static ssize_t mode_ch_tim_en_show(struct device *_dev,
18351 + struct device_attribute *attr, char *buf)
18352 +{
18353 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18354 + return sprintf(buf, "Mode Change Ready Timer Enable = 0x%x\n",
18355 + dwc_otg_get_mode_ch_tim(otg_dev->core_if));
18356 +}
18357 +
18358 +/**
18359 + * Set the Mode Change Ready Timer status
18360 + */
18361 +static ssize_t mode_ch_tim_en_store(struct device *_dev,
18362 + struct device_attribute *attr,
18363 + const char *buf, size_t count)
18364 +{
18365 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18366 + uint32_t in = simple_strtoul(buf, NULL, 16);
18367 + dwc_otg_set_mode_ch_tim(otg_dev->core_if, in);
18368 + return count;
18369 +}
18370 +
18371 +DEVICE_ATTR(mode_ch_tim_en, 0644, mode_ch_tim_en_show, mode_ch_tim_en_store);
18372 +
18373 +/**
18374 + * Show the value of HFIR Frame Interval bitfield
18375 + */
18376 +static ssize_t fr_interval_show(struct device *_dev,
18377 + struct device_attribute *attr, char *buf)
18378 +{
18379 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18380 + return sprintf(buf, "Frame Interval = 0x%x\n",
18381 + dwc_otg_get_fr_interval(otg_dev->core_if));
18382 +}
18383 +
18384 +/**
18385 + * Set the HFIR Frame Interval value
18386 + */
18387 +static ssize_t fr_interval_store(struct device *_dev,
18388 + struct device_attribute *attr,
18389 + const char *buf, size_t count)
18390 +{
18391 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18392 + uint32_t in = simple_strtoul(buf, NULL, 10);
18393 + dwc_otg_set_fr_interval(otg_dev->core_if, in);
18394 + return count;
18395 +}
18396 +
18397 +DEVICE_ATTR(fr_interval, 0644, fr_interval_show, fr_interval_store);
18398 +
18399 +/**
18400 + * Show the status of Remote Wakeup.
18401 + */
18402 +static ssize_t remote_wakeup_show(struct device *_dev,
18403 + struct device_attribute *attr, char *buf)
18404 +{
18405 +#ifndef DWC_HOST_ONLY
18406 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18407 +
18408 + return sprintf(buf,
18409 + "Remote Wakeup Sig = %d Enabled = %d LPM Remote Wakeup = %d\n",
18410 + dwc_otg_get_remotewakesig(otg_dev->core_if),
18411 + dwc_otg_pcd_get_rmwkup_enable(otg_dev->pcd),
18412 + dwc_otg_get_lpm_remotewakeenabled(otg_dev->core_if));
18413 +#else
18414 + return sprintf(buf, "Host Only Mode!\n");
18415 +#endif /* DWC_HOST_ONLY */
18416 +}
18417 +
18418 +/**
18419 + * Initiate a remote wakeup of the host. The Device control register
18420 + * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable
18421 + * flag is set.
18422 + *
18423 + */
18424 +static ssize_t remote_wakeup_store(struct device *_dev,
18425 + struct device_attribute *attr,
18426 + const char *buf, size_t count)
18427 +{
18428 +#ifndef DWC_HOST_ONLY
18429 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18430 + uint32_t val = simple_strtoul(buf, NULL, 16);
18431 +
18432 + if (val & 1) {
18433 + dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1);
18434 + } else {
18435 + dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0);
18436 + }
18437 +#endif /* DWC_HOST_ONLY */
18438 + return count;
18439 +}
18440 +
18441 +DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show,
18442 + remote_wakeup_store);
18443 +
18444 +/**
18445 + * Show the whether core is hibernated or not.
18446 + */
18447 +static ssize_t rem_wakeup_pwrdn_show(struct device *_dev,
18448 + struct device_attribute *attr, char *buf)
18449 +{
18450 +#ifndef DWC_HOST_ONLY
18451 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18452 +
18453 + if (dwc_otg_get_core_state(otg_dev->core_if)) {
18454 + DWC_PRINTF("Core is in hibernation\n");
18455 + } else {
18456 + DWC_PRINTF("Core is not in hibernation\n");
18457 + }
18458 +#endif /* DWC_HOST_ONLY */
18459 + return 0;
18460 +}
18461 +
18462 +extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
18463 + int rem_wakeup, int reset);
18464 +
18465 +/**
18466 + * Initiate a remote wakeup of the device to exit from hibernation.
18467 + */
18468 +static ssize_t rem_wakeup_pwrdn_store(struct device *_dev,
18469 + struct device_attribute *attr,
18470 + const char *buf, size_t count)
18471 +{
18472 +#ifndef DWC_HOST_ONLY
18473 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18474 + dwc_otg_device_hibernation_restore(otg_dev->core_if, 1, 0);
18475 +#endif
18476 + return count;
18477 +}
18478 +
18479 +DEVICE_ATTR(rem_wakeup_pwrdn, S_IRUGO | S_IWUSR, rem_wakeup_pwrdn_show,
18480 + rem_wakeup_pwrdn_store);
18481 +
18482 +static ssize_t disconnect_us(struct device *_dev,
18483 + struct device_attribute *attr,
18484 + const char *buf, size_t count)
18485 +{
18486 +
18487 +#ifndef DWC_HOST_ONLY
18488 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18489 + uint32_t val = simple_strtoul(buf, NULL, 16);
18490 + DWC_PRINTF("The Passed value is %04x\n", val);
18491 +
18492 + dwc_otg_pcd_disconnect_us(otg_dev->pcd, 50);
18493 +
18494 +#endif /* DWC_HOST_ONLY */
18495 + return count;
18496 +}
18497 +
18498 +DEVICE_ATTR(disconnect_us, S_IWUSR, 0, disconnect_us);
18499 +
18500 +/**
18501 + * Dump global registers and either host or device registers (depending on the
18502 + * current mode of the core).
18503 + */
18504 +static ssize_t regdump_show(struct device *_dev,
18505 + struct device_attribute *attr, char *buf)
18506 +{
18507 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18508 +
18509 + dwc_otg_dump_global_registers(otg_dev->core_if);
18510 + if (dwc_otg_is_host_mode(otg_dev->core_if)) {
18511 + dwc_otg_dump_host_registers(otg_dev->core_if);
18512 + } else {
18513 + dwc_otg_dump_dev_registers(otg_dev->core_if);
18514 +
18515 + }
18516 + return sprintf(buf, "Register Dump\n");
18517 +}
18518 +
18519 +DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0);
18520 +
18521 +/**
18522 + * Dump global registers and either host or device registers (depending on the
18523 + * current mode of the core).
18524 + */
18525 +static ssize_t spramdump_show(struct device *_dev,
18526 + struct device_attribute *attr, char *buf)
18527 +{
18528 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18529 +
18530 + dwc_otg_dump_spram(otg_dev->core_if);
18531 +
18532 + return sprintf(buf, "SPRAM Dump\n");
18533 +}
18534 +
18535 +DEVICE_ATTR(spramdump, S_IRUGO | S_IWUSR, spramdump_show, 0);
18536 +
18537 +/**
18538 + * Dump the current hcd state.
18539 + */
18540 +static ssize_t hcddump_show(struct device *_dev,
18541 + struct device_attribute *attr, char *buf)
18542 +{
18543 +#ifndef DWC_DEVICE_ONLY
18544 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18545 + dwc_otg_hcd_dump_state(otg_dev->hcd);
18546 +#endif /* DWC_DEVICE_ONLY */
18547 + return sprintf(buf, "HCD Dump\n");
18548 +}
18549 +
18550 +DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0);
18551 +
18552 +/**
18553 + * Dump the average frame remaining at SOF. This can be used to
18554 + * determine average interrupt latency. Frame remaining is also shown for
18555 + * start transfer and two additional sample points.
18556 + */
18557 +static ssize_t hcd_frrem_show(struct device *_dev,
18558 + struct device_attribute *attr, char *buf)
18559 +{
18560 +#ifndef DWC_DEVICE_ONLY
18561 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18562 +
18563 + dwc_otg_hcd_dump_frrem(otg_dev->hcd);
18564 +#endif /* DWC_DEVICE_ONLY */
18565 + return sprintf(buf, "HCD Dump Frame Remaining\n");
18566 +}
18567 +
18568 +DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0);
18569 +
18570 +/**
18571 + * Displays the time required to read the GNPTXFSIZ register many times (the
18572 + * output shows the number of times the register is read).
18573 + */
18574 +#define RW_REG_COUNT 10000000
18575 +#define MSEC_PER_JIFFIE 1000/HZ
18576 +static ssize_t rd_reg_test_show(struct device *_dev,
18577 + struct device_attribute *attr, char *buf)
18578 +{
18579 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18580 + int i;
18581 + int time;
18582 + int start_jiffies;
18583 +
18584 + printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
18585 + HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
18586 + start_jiffies = jiffies;
18587 + for (i = 0; i < RW_REG_COUNT; i++) {
18588 + dwc_otg_get_gnptxfsiz(otg_dev->core_if);
18589 + }
18590 + time = jiffies - start_jiffies;
18591 + return sprintf(buf,
18592 + "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
18593 + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
18594 +}
18595 +
18596 +DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0);
18597 +
18598 +/**
18599 + * Displays the time required to write the GNPTXFSIZ register many times (the
18600 + * output shows the number of times the register is written).
18601 + */
18602 +static ssize_t wr_reg_test_show(struct device *_dev,
18603 + struct device_attribute *attr, char *buf)
18604 +{
18605 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18606 + uint32_t reg_val;
18607 + int i;
18608 + int time;
18609 + int start_jiffies;
18610 +
18611 + printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
18612 + HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
18613 + reg_val = dwc_otg_get_gnptxfsiz(otg_dev->core_if);
18614 + start_jiffies = jiffies;
18615 + for (i = 0; i < RW_REG_COUNT; i++) {
18616 + dwc_otg_set_gnptxfsiz(otg_dev->core_if, reg_val);
18617 + }
18618 + time = jiffies - start_jiffies;
18619 + return sprintf(buf,
18620 + "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
18621 + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
18622 +}
18623 +
18624 +DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0);
18625 +
18626 +#ifdef CONFIG_USB_DWC_OTG_LPM
18627 +
18628 +/**
18629 +* Show the lpm_response attribute.
18630 +*/
18631 +static ssize_t lpmresp_show(struct device *_dev,
18632 + struct device_attribute *attr, char *buf)
18633 +{
18634 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18635 +
18636 + if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
18637 + return sprintf(buf, "** LPM is DISABLED **\n");
18638 +
18639 + if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
18640 + return sprintf(buf, "** Current mode is not device mode\n");
18641 + }
18642 + return sprintf(buf, "lpm_response = %d\n",
18643 + dwc_otg_get_lpmresponse(otg_dev->core_if));
18644 +}
18645 +
18646 +/**
18647 +* Store the lpm_response attribute.
18648 +*/
18649 +static ssize_t lpmresp_store(struct device *_dev,
18650 + struct device_attribute *attr,
18651 + const char *buf, size_t count)
18652 +{
18653 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18654 + uint32_t val = simple_strtoul(buf, NULL, 16);
18655 +
18656 + if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if)) {
18657 + return 0;
18658 + }
18659 +
18660 + if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
18661 + return 0;
18662 + }
18663 +
18664 + dwc_otg_set_lpmresponse(otg_dev->core_if, val);
18665 + return count;
18666 +}
18667 +
18668 +DEVICE_ATTR(lpm_response, S_IRUGO | S_IWUSR, lpmresp_show, lpmresp_store);
18669 +
18670 +/**
18671 +* Show the sleep_status attribute.
18672 +*/
18673 +static ssize_t sleepstatus_show(struct device *_dev,
18674 + struct device_attribute *attr, char *buf)
18675 +{
18676 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18677 + return sprintf(buf, "Sleep Status = %d\n",
18678 + dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if));
18679 +}
18680 +
18681 +/**
18682 + * Store the sleep_status attribure.
18683 + */
18684 +static ssize_t sleepstatus_store(struct device *_dev,
18685 + struct device_attribute *attr,
18686 + const char *buf, size_t count)
18687 +{
18688 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18689 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
18690 +
18691 + if (dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if)) {
18692 + if (dwc_otg_is_host_mode(core_if)) {
18693 +
18694 + DWC_PRINTF("Host initiated resume\n");
18695 + dwc_otg_set_prtresume(otg_dev->core_if, 1);
18696 + }
18697 + }
18698 +
18699 + return count;
18700 +}
18701 +
18702 +DEVICE_ATTR(sleep_status, S_IRUGO | S_IWUSR, sleepstatus_show,
18703 + sleepstatus_store);
18704 +
18705 +#endif /* CONFIG_USB_DWC_OTG_LPM_ENABLE */
18706 +
18707 +/**@}*/
18708 +
18709 +/**
18710 + * Create the device files
18711 + */
18712 +void dwc_otg_attr_create(
18713 +#ifdef LM_INTERFACE
18714 + struct lm_device *dev
18715 +#elif defined(PCI_INTERFACE)
18716 + struct pci_dev *dev
18717 +#elif defined(PLATFORM_INTERFACE)
18718 + struct platform_device *dev
18719 +#endif
18720 + )
18721 +{
18722 + int error;
18723 +
18724 + error = device_create_file(&dev->dev, &dev_attr_regoffset);
18725 + error = device_create_file(&dev->dev, &dev_attr_regvalue);
18726 + error = device_create_file(&dev->dev, &dev_attr_mode);
18727 + error = device_create_file(&dev->dev, &dev_attr_hnpcapable);
18728 + error = device_create_file(&dev->dev, &dev_attr_srpcapable);
18729 + error = device_create_file(&dev->dev, &dev_attr_hsic_connect);
18730 + error = device_create_file(&dev->dev, &dev_attr_inv_sel_hsic);
18731 + error = device_create_file(&dev->dev, &dev_attr_hnp);
18732 + error = device_create_file(&dev->dev, &dev_attr_srp);
18733 + error = device_create_file(&dev->dev, &dev_attr_buspower);
18734 + error = device_create_file(&dev->dev, &dev_attr_bussuspend);
18735 + error = device_create_file(&dev->dev, &dev_attr_mode_ch_tim_en);
18736 + error = device_create_file(&dev->dev, &dev_attr_fr_interval);
18737 + error = device_create_file(&dev->dev, &dev_attr_busconnected);
18738 + error = device_create_file(&dev->dev, &dev_attr_gotgctl);
18739 + error = device_create_file(&dev->dev, &dev_attr_gusbcfg);
18740 + error = device_create_file(&dev->dev, &dev_attr_grxfsiz);
18741 + error = device_create_file(&dev->dev, &dev_attr_gnptxfsiz);
18742 + error = device_create_file(&dev->dev, &dev_attr_gpvndctl);
18743 + error = device_create_file(&dev->dev, &dev_attr_ggpio);
18744 + error = device_create_file(&dev->dev, &dev_attr_guid);
18745 + error = device_create_file(&dev->dev, &dev_attr_gsnpsid);
18746 + error = device_create_file(&dev->dev, &dev_attr_devspeed);
18747 + error = device_create_file(&dev->dev, &dev_attr_enumspeed);
18748 + error = device_create_file(&dev->dev, &dev_attr_hptxfsiz);
18749 + error = device_create_file(&dev->dev, &dev_attr_hprt0);
18750 + error = device_create_file(&dev->dev, &dev_attr_remote_wakeup);
18751 + error = device_create_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
18752 + error = device_create_file(&dev->dev, &dev_attr_disconnect_us);
18753 + error = device_create_file(&dev->dev, &dev_attr_regdump);
18754 + error = device_create_file(&dev->dev, &dev_attr_spramdump);
18755 + error = device_create_file(&dev->dev, &dev_attr_hcddump);
18756 + error = device_create_file(&dev->dev, &dev_attr_hcd_frrem);
18757 + error = device_create_file(&dev->dev, &dev_attr_rd_reg_test);
18758 + error = device_create_file(&dev->dev, &dev_attr_wr_reg_test);
18759 +#ifdef CONFIG_USB_DWC_OTG_LPM
18760 + error = device_create_file(&dev->dev, &dev_attr_lpm_response);
18761 + error = device_create_file(&dev->dev, &dev_attr_sleep_status);
18762 +#endif
18763 +}
18764 +
18765 +/**
18766 + * Remove the device files
18767 + */
18768 +void dwc_otg_attr_remove(
18769 +#ifdef LM_INTERFACE
18770 + struct lm_device *dev
18771 +#elif defined(PCI_INTERFACE)
18772 + struct pci_dev *dev
18773 +#elif defined(PLATFORM_INTERFACE)
18774 + struct platform_device *dev
18775 +#endif
18776 + )
18777 +{
18778 + device_remove_file(&dev->dev, &dev_attr_regoffset);
18779 + device_remove_file(&dev->dev, &dev_attr_regvalue);
18780 + device_remove_file(&dev->dev, &dev_attr_mode);
18781 + device_remove_file(&dev->dev, &dev_attr_hnpcapable);
18782 + device_remove_file(&dev->dev, &dev_attr_srpcapable);
18783 + device_remove_file(&dev->dev, &dev_attr_hsic_connect);
18784 + device_remove_file(&dev->dev, &dev_attr_inv_sel_hsic);
18785 + device_remove_file(&dev->dev, &dev_attr_hnp);
18786 + device_remove_file(&dev->dev, &dev_attr_srp);
18787 + device_remove_file(&dev->dev, &dev_attr_buspower);
18788 + device_remove_file(&dev->dev, &dev_attr_bussuspend);
18789 + device_remove_file(&dev->dev, &dev_attr_mode_ch_tim_en);
18790 + device_remove_file(&dev->dev, &dev_attr_fr_interval);
18791 + device_remove_file(&dev->dev, &dev_attr_busconnected);
18792 + device_remove_file(&dev->dev, &dev_attr_gotgctl);
18793 + device_remove_file(&dev->dev, &dev_attr_gusbcfg);
18794 + device_remove_file(&dev->dev, &dev_attr_grxfsiz);
18795 + device_remove_file(&dev->dev, &dev_attr_gnptxfsiz);
18796 + device_remove_file(&dev->dev, &dev_attr_gpvndctl);
18797 + device_remove_file(&dev->dev, &dev_attr_ggpio);
18798 + device_remove_file(&dev->dev, &dev_attr_guid);
18799 + device_remove_file(&dev->dev, &dev_attr_gsnpsid);
18800 + device_remove_file(&dev->dev, &dev_attr_devspeed);
18801 + device_remove_file(&dev->dev, &dev_attr_enumspeed);
18802 + device_remove_file(&dev->dev, &dev_attr_hptxfsiz);
18803 + device_remove_file(&dev->dev, &dev_attr_hprt0);
18804 + device_remove_file(&dev->dev, &dev_attr_remote_wakeup);
18805 + device_remove_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
18806 + device_remove_file(&dev->dev, &dev_attr_disconnect_us);
18807 + device_remove_file(&dev->dev, &dev_attr_regdump);
18808 + device_remove_file(&dev->dev, &dev_attr_spramdump);
18809 + device_remove_file(&dev->dev, &dev_attr_hcddump);
18810 + device_remove_file(&dev->dev, &dev_attr_hcd_frrem);
18811 + device_remove_file(&dev->dev, &dev_attr_rd_reg_test);
18812 + device_remove_file(&dev->dev, &dev_attr_wr_reg_test);
18813 +#ifdef CONFIG_USB_DWC_OTG_LPM
18814 + device_remove_file(&dev->dev, &dev_attr_lpm_response);
18815 + device_remove_file(&dev->dev, &dev_attr_sleep_status);
18816 +#endif
18817 +}
18818 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_attr.h b/drivers/usb/host/dwc_otg/dwc_otg_attr.h
18819 new file mode 100644
18820 index 0000000..e10b67f
18821 --- /dev/null
18822 +++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.h
18823 @@ -0,0 +1,89 @@
18824 +/* ==========================================================================
18825 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.h $
18826 + * $Revision: #13 $
18827 + * $Date: 2010/06/21 $
18828 + * $Change: 1532021 $
18829 + *
18830 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
18831 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
18832 + * otherwise expressly agreed to in writing between Synopsys and you.
18833 + *
18834 + * The Software IS NOT an item of Licensed Software or Licensed Product under
18835 + * any End User Software License Agreement or Agreement for Licensed Product
18836 + * with Synopsys or any supplement thereto. You are permitted to use and
18837 + * redistribute this Software in source and binary forms, with or without
18838 + * modification, provided that redistributions of source code must retain this
18839 + * notice. You may not view, use, disclose, copy or distribute this file or
18840 + * any information contained herein except pursuant to this license grant from
18841 + * Synopsys. If you do not agree with this notice, including the disclaimer
18842 + * below, then you are not authorized to use the Software.
18843 + *
18844 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
18845 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18846 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18847 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
18848 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18849 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18850 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
18851 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18852 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18853 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
18854 + * DAMAGE.
18855 + * ========================================================================== */
18856 +
18857 +#if !defined(__DWC_OTG_ATTR_H__)
18858 +#define __DWC_OTG_ATTR_H__
18859 +
18860 +/** @file
18861 + * This file contains the interface to the Linux device attributes.
18862 + */
18863 +extern struct device_attribute dev_attr_regoffset;
18864 +extern struct device_attribute dev_attr_regvalue;
18865 +
18866 +extern struct device_attribute dev_attr_mode;
18867 +extern struct device_attribute dev_attr_hnpcapable;
18868 +extern struct device_attribute dev_attr_srpcapable;
18869 +extern struct device_attribute dev_attr_hnp;
18870 +extern struct device_attribute dev_attr_srp;
18871 +extern struct device_attribute dev_attr_buspower;
18872 +extern struct device_attribute dev_attr_bussuspend;
18873 +extern struct device_attribute dev_attr_mode_ch_tim_en;
18874 +extern struct device_attribute dev_attr_fr_interval;
18875 +extern struct device_attribute dev_attr_busconnected;
18876 +extern struct device_attribute dev_attr_gotgctl;
18877 +extern struct device_attribute dev_attr_gusbcfg;
18878 +extern struct device_attribute dev_attr_grxfsiz;
18879 +extern struct device_attribute dev_attr_gnptxfsiz;
18880 +extern struct device_attribute dev_attr_gpvndctl;
18881 +extern struct device_attribute dev_attr_ggpio;
18882 +extern struct device_attribute dev_attr_guid;
18883 +extern struct device_attribute dev_attr_gsnpsid;
18884 +extern struct device_attribute dev_attr_devspeed;
18885 +extern struct device_attribute dev_attr_enumspeed;
18886 +extern struct device_attribute dev_attr_hptxfsiz;
18887 +extern struct device_attribute dev_attr_hprt0;
18888 +#ifdef CONFIG_USB_DWC_OTG_LPM
18889 +extern struct device_attribute dev_attr_lpm_response;
18890 +extern struct device_attribute devi_attr_sleep_status;
18891 +#endif
18892 +
18893 +void dwc_otg_attr_create(
18894 +#ifdef LM_INTERFACE
18895 + struct lm_device *dev
18896 +#elif defined(PCI_INTERFACE)
18897 + struct pci_dev *dev
18898 +#elif defined(PLATFORM_INTERFACE)
18899 + struct platform_device *dev
18900 +#endif
18901 + );
18902 +
18903 +void dwc_otg_attr_remove(
18904 +#ifdef LM_INTERFACE
18905 + struct lm_device *dev
18906 +#elif defined(PCI_INTERFACE)
18907 + struct pci_dev *dev
18908 +#elif defined(PLATFORM_INTERFACE)
18909 + struct platform_device *dev
18910 +#endif
18911 + );
18912 +#endif
18913 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cfi.c b/drivers/usb/host/dwc_otg/dwc_otg_cfi.c
18914 new file mode 100644
18915 index 0000000..bbb3d32
18916 --- /dev/null
18917 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.c
18918 @@ -0,0 +1,1876 @@
18919 +/* ==========================================================================
18920 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
18921 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
18922 + * otherwise expressly agreed to in writing between Synopsys and you.
18923 + *
18924 + * The Software IS NOT an item of Licensed Software or Licensed Product under
18925 + * any End User Software License Agreement or Agreement for Licensed Product
18926 + * with Synopsys or any supplement thereto. You are permitted to use and
18927 + * redistribute this Software in source and binary forms, with or without
18928 + * modification, provided that redistributions of source code must retain this
18929 + * notice. You may not view, use, disclose, copy or distribute this file or
18930 + * any information contained herein except pursuant to this license grant from
18931 + * Synopsys. If you do not agree with this notice, including the disclaimer
18932 + * below, then you are not authorized to use the Software.
18933 + *
18934 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
18935 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18936 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18937 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
18938 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18939 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18940 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
18941 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18942 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18943 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
18944 + * DAMAGE.
18945 + * ========================================================================== */
18946 +
18947 +/** @file
18948 + *
18949 + * This file contains the most of the CFI(Core Feature Interface)
18950 + * implementation for the OTG.
18951 + */
18952 +
18953 +#ifdef DWC_UTE_CFI
18954 +
18955 +#include "dwc_otg_pcd.h"
18956 +#include "dwc_otg_cfi.h"
18957 +
18958 +/** This definition should actually migrate to the Portability Library */
18959 +#define DWC_CONSTANT_CPU_TO_LE16(x) (x)
18960 +
18961 +extern dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex);
18962 +
18963 +static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen);
18964 +static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
18965 + struct dwc_otg_pcd *pcd,
18966 + struct cfi_usb_ctrlrequest *ctrl_req);
18967 +static int cfi_set_feature_value(struct dwc_otg_pcd *pcd);
18968 +static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
18969 + struct cfi_usb_ctrlrequest *req);
18970 +static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
18971 + struct cfi_usb_ctrlrequest *req);
18972 +static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
18973 + struct cfi_usb_ctrlrequest *req);
18974 +static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
18975 + struct cfi_usb_ctrlrequest *req);
18976 +static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep);
18977 +
18978 +static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if);
18979 +static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue);
18980 +static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue);
18981 +
18982 +static uint8_t resize_fifos(dwc_otg_core_if_t * core_if);
18983 +
18984 +/** This is the header of the all features descriptor */
18985 +static cfi_all_features_header_t all_props_desc_header = {
18986 + .wVersion = DWC_CONSTANT_CPU_TO_LE16(0x100),
18987 + .wCoreID = DWC_CONSTANT_CPU_TO_LE16(CFI_CORE_ID_OTG),
18988 + .wNumFeatures = DWC_CONSTANT_CPU_TO_LE16(9),
18989 +};
18990 +
18991 +/** This is an array of statically allocated feature descriptors */
18992 +static cfi_feature_desc_header_t prop_descs[] = {
18993 +
18994 + /* FT_ID_DMA_MODE */
18995 + {
18996 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_MODE),
18997 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18998 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(1),
18999 + },
19000 +
19001 + /* FT_ID_DMA_BUFFER_SETUP */
19002 + {
19003 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFFER_SETUP),
19004 + .bmAttributes = CFI_FEATURE_ATTR_RW,
19005 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
19006 + },
19007 +
19008 + /* FT_ID_DMA_BUFF_ALIGN */
19009 + {
19010 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFF_ALIGN),
19011 + .bmAttributes = CFI_FEATURE_ATTR_RW,
19012 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
19013 + },
19014 +
19015 + /* FT_ID_DMA_CONCAT_SETUP */
19016 + {
19017 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CONCAT_SETUP),
19018 + .bmAttributes = CFI_FEATURE_ATTR_RW,
19019 + //.wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
19020 + },
19021 +
19022 + /* FT_ID_DMA_CIRCULAR */
19023 + {
19024 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CIRCULAR),
19025 + .bmAttributes = CFI_FEATURE_ATTR_RW,
19026 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
19027 + },
19028 +
19029 + /* FT_ID_THRESHOLD_SETUP */
19030 + {
19031 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_THRESHOLD_SETUP),
19032 + .bmAttributes = CFI_FEATURE_ATTR_RW,
19033 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
19034 + },
19035 +
19036 + /* FT_ID_DFIFO_DEPTH */
19037 + {
19038 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DFIFO_DEPTH),
19039 + .bmAttributes = CFI_FEATURE_ATTR_RO,
19040 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
19041 + },
19042 +
19043 + /* FT_ID_TX_FIFO_DEPTH */
19044 + {
19045 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_TX_FIFO_DEPTH),
19046 + .bmAttributes = CFI_FEATURE_ATTR_RW,
19047 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
19048 + },
19049 +
19050 + /* FT_ID_RX_FIFO_DEPTH */
19051 + {
19052 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_RX_FIFO_DEPTH),
19053 + .bmAttributes = CFI_FEATURE_ATTR_RW,
19054 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
19055 + }
19056 +};
19057 +
19058 +/** The table of feature names */
19059 +cfi_string_t prop_name_table[] = {
19060 + {FT_ID_DMA_MODE, "dma_mode"},
19061 + {FT_ID_DMA_BUFFER_SETUP, "buffer_setup"},
19062 + {FT_ID_DMA_BUFF_ALIGN, "buffer_align"},
19063 + {FT_ID_DMA_CONCAT_SETUP, "concat_setup"},
19064 + {FT_ID_DMA_CIRCULAR, "buffer_circular"},
19065 + {FT_ID_THRESHOLD_SETUP, "threshold_setup"},
19066 + {FT_ID_DFIFO_DEPTH, "dfifo_depth"},
19067 + {FT_ID_TX_FIFO_DEPTH, "txfifo_depth"},
19068 + {FT_ID_RX_FIFO_DEPTH, "rxfifo_depth"},
19069 + {}
19070 +};
19071 +
19072 +/************************************************************************/
19073 +
19074 +/**
19075 + * Returns the name of the feature by its ID
19076 + * or NULL if no featute ID matches.
19077 + *
19078 + */
19079 +const uint8_t *get_prop_name(uint16_t prop_id, int *len)
19080 +{
19081 + cfi_string_t *pstr;
19082 + *len = 0;
19083 +
19084 + for (pstr = prop_name_table; pstr && pstr->s; pstr++) {
19085 + if (pstr->id == prop_id) {
19086 + *len = DWC_STRLEN(pstr->s);
19087 + return pstr->s;
19088 + }
19089 + }
19090 + return NULL;
19091 +}
19092 +
19093 +/**
19094 + * This function handles all CFI specific control requests.
19095 + *
19096 + * Return a negative value to stall the DCE.
19097 + */
19098 +int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl)
19099 +{
19100 + int retval = 0;
19101 + dwc_otg_pcd_ep_t *ep = NULL;
19102 + cfiobject_t *cfi = pcd->cfi;
19103 + struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
19104 + uint16_t wLen = DWC_LE16_TO_CPU(&ctrl->wLength);
19105 + uint16_t wValue = DWC_LE16_TO_CPU(&ctrl->wValue);
19106 + uint16_t wIndex = DWC_LE16_TO_CPU(&ctrl->wIndex);
19107 + uint32_t regaddr = 0;
19108 + uint32_t regval = 0;
19109 +
19110 + /* Save this Control Request in the CFI object.
19111 + * The data field will be assigned in the data stage completion CB function.
19112 + */
19113 + cfi->ctrl_req = *ctrl;
19114 + cfi->ctrl_req.data = NULL;
19115 +
19116 + cfi->need_gadget_att = 0;
19117 + cfi->need_status_in_complete = 0;
19118 +
19119 + switch (ctrl->bRequest) {
19120 + case VEN_CORE_GET_FEATURES:
19121 + retval = cfi_core_features_buf(cfi->buf_in.buf, CFI_IN_BUF_LEN);
19122 + if (retval >= 0) {
19123 + //dump_msg(cfi->buf_in.buf, retval);
19124 + ep = &pcd->ep0;
19125 +
19126 + retval = min((uint16_t) retval, wLen);
19127 + /* Transfer this buffer to the host through the EP0-IN EP */
19128 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
19129 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
19130 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
19131 + ep->dwc_ep.xfer_len = retval;
19132 + ep->dwc_ep.xfer_count = 0;
19133 + ep->dwc_ep.sent_zlp = 0;
19134 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19135 +
19136 + pcd->ep0_pending = 1;
19137 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19138 + }
19139 + retval = 0;
19140 + break;
19141 +
19142 + case VEN_CORE_GET_FEATURE:
19143 + CFI_INFO("VEN_CORE_GET_FEATURE\n");
19144 + retval = cfi_get_feature_value(cfi->buf_in.buf, CFI_IN_BUF_LEN,
19145 + pcd, ctrl);
19146 + if (retval >= 0) {
19147 + ep = &pcd->ep0;
19148 +
19149 + retval = min((uint16_t) retval, wLen);
19150 + /* Transfer this buffer to the host through the EP0-IN EP */
19151 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
19152 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
19153 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
19154 + ep->dwc_ep.xfer_len = retval;
19155 + ep->dwc_ep.xfer_count = 0;
19156 + ep->dwc_ep.sent_zlp = 0;
19157 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19158 +
19159 + pcd->ep0_pending = 1;
19160 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19161 + }
19162 + CFI_INFO("VEN_CORE_GET_FEATURE=%d\n", retval);
19163 + dump_msg(cfi->buf_in.buf, retval);
19164 + break;
19165 +
19166 + case VEN_CORE_SET_FEATURE:
19167 + CFI_INFO("VEN_CORE_SET_FEATURE\n");
19168 + /* Set up an XFER to get the data stage of the control request,
19169 + * which is the new value of the feature to be modified.
19170 + */
19171 + ep = &pcd->ep0;
19172 + ep->dwc_ep.is_in = 0;
19173 + ep->dwc_ep.dma_addr = cfi->buf_out.addr;
19174 + ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
19175 + ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
19176 + ep->dwc_ep.xfer_len = wLen;
19177 + ep->dwc_ep.xfer_count = 0;
19178 + ep->dwc_ep.sent_zlp = 0;
19179 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19180 +
19181 + pcd->ep0_pending = 1;
19182 + /* Read the control write's data stage */
19183 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19184 + retval = 0;
19185 + break;
19186 +
19187 + case VEN_CORE_RESET_FEATURES:
19188 + CFI_INFO("VEN_CORE_RESET_FEATURES\n");
19189 + cfi->need_gadget_att = 1;
19190 + cfi->need_status_in_complete = 1;
19191 + retval = cfi_preproc_reset(pcd, ctrl);
19192 + CFI_INFO("VEN_CORE_RESET_FEATURES = (%d)\n", retval);
19193 + break;
19194 +
19195 + case VEN_CORE_ACTIVATE_FEATURES:
19196 + CFI_INFO("VEN_CORE_ACTIVATE_FEATURES\n");
19197 + break;
19198 +
19199 + case VEN_CORE_READ_REGISTER:
19200 + CFI_INFO("VEN_CORE_READ_REGISTER\n");
19201 + /* wValue optionally contains the HI WORD of the register offset and
19202 + * wIndex contains the LOW WORD of the register offset
19203 + */
19204 + if (wValue == 0) {
19205 + /* @TODO - MAS - fix the access to the base field */
19206 + regaddr = 0;
19207 + //regaddr = (uint32_t) pcd->otg_dev->os_dep.base;
19208 + //GET_CORE_IF(pcd)->co
19209 + regaddr |= wIndex;
19210 + } else {
19211 + regaddr = (wValue << 16) | wIndex;
19212 + }
19213 +
19214 + /* Read a 32-bit value of the memory at the regaddr */
19215 + regval = DWC_READ_REG32((uint32_t *) regaddr);
19216 +
19217 + ep = &pcd->ep0;
19218 + dwc_memcpy(cfi->buf_in.buf, &regval, sizeof(uint32_t));
19219 + ep->dwc_ep.is_in = 1;
19220 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
19221 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
19222 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
19223 + ep->dwc_ep.xfer_len = wLen;
19224 + ep->dwc_ep.xfer_count = 0;
19225 + ep->dwc_ep.sent_zlp = 0;
19226 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19227 +
19228 + pcd->ep0_pending = 1;
19229 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19230 + cfi->need_gadget_att = 0;
19231 + retval = 0;
19232 + break;
19233 +
19234 + case VEN_CORE_WRITE_REGISTER:
19235 + CFI_INFO("VEN_CORE_WRITE_REGISTER\n");
19236 + /* Set up an XFER to get the data stage of the control request,
19237 + * which is the new value of the register to be modified.
19238 + */
19239 + ep = &pcd->ep0;
19240 + ep->dwc_ep.is_in = 0;
19241 + ep->dwc_ep.dma_addr = cfi->buf_out.addr;
19242 + ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
19243 + ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
19244 + ep->dwc_ep.xfer_len = wLen;
19245 + ep->dwc_ep.xfer_count = 0;
19246 + ep->dwc_ep.sent_zlp = 0;
19247 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19248 +
19249 + pcd->ep0_pending = 1;
19250 + /* Read the control write's data stage */
19251 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19252 + retval = 0;
19253 + break;
19254 +
19255 + default:
19256 + retval = -DWC_E_NOT_SUPPORTED;
19257 + break;
19258 + }
19259 +
19260 + return retval;
19261 +}
19262 +
19263 +/**
19264 + * This function prepares the core features descriptors and copies its
19265 + * raw representation into the buffer <buf>.
19266 + *
19267 + * The buffer structure is as follows:
19268 + * all_features_header (8 bytes)
19269 + * features_#1 (8 bytes + feature name string length)
19270 + * features_#2 (8 bytes + feature name string length)
19271 + * .....
19272 + * features_#n - where n=the total count of feature descriptors
19273 + */
19274 +static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen)
19275 +{
19276 + cfi_feature_desc_header_t *prop_hdr = prop_descs;
19277 + cfi_feature_desc_header_t *prop;
19278 + cfi_all_features_header_t *all_props_hdr = &all_props_desc_header;
19279 + cfi_all_features_header_t *tmp;
19280 + uint8_t *tmpbuf = buf;
19281 + const uint8_t *pname = NULL;
19282 + int i, j, namelen = 0, totlen;
19283 +
19284 + /* Prepare and copy the core features into the buffer */
19285 + CFI_INFO("%s:\n", __func__);
19286 +
19287 + tmp = (cfi_all_features_header_t *) tmpbuf;
19288 + *tmp = *all_props_hdr;
19289 + tmpbuf += CFI_ALL_FEATURES_HDR_LEN;
19290 +
19291 + j = sizeof(prop_descs) / sizeof(cfi_all_features_header_t);
19292 + for (i = 0; i < j; i++, prop_hdr++) {
19293 + pname = get_prop_name(prop_hdr->wFeatureID, &namelen);
19294 + prop = (cfi_feature_desc_header_t *) tmpbuf;
19295 + *prop = *prop_hdr;
19296 +
19297 + prop->bNameLen = namelen;
19298 + prop->wLength =
19299 + DWC_CONSTANT_CPU_TO_LE16(CFI_FEATURE_DESC_HDR_LEN +
19300 + namelen);
19301 +
19302 + tmpbuf += CFI_FEATURE_DESC_HDR_LEN;
19303 + dwc_memcpy(tmpbuf, pname, namelen);
19304 + tmpbuf += namelen;
19305 + }
19306 +
19307 + totlen = tmpbuf - buf;
19308 +
19309 + if (totlen > 0) {
19310 + tmp = (cfi_all_features_header_t *) buf;
19311 + tmp->wTotalLen = DWC_CONSTANT_CPU_TO_LE16(totlen);
19312 + }
19313 +
19314 + return totlen;
19315 +}
19316 +
19317 +/**
19318 + * This function releases all the dynamic memory in the CFI object.
19319 + */
19320 +static void cfi_release(cfiobject_t * cfiobj)
19321 +{
19322 + cfi_ep_t *cfiep;
19323 + dwc_list_link_t *tmp;
19324 +
19325 + CFI_INFO("%s\n", __func__);
19326 +
19327 + if (cfiobj->buf_in.buf) {
19328 + DWC_DMA_FREE(CFI_IN_BUF_LEN, cfiobj->buf_in.buf,
19329 + cfiobj->buf_in.addr);
19330 + cfiobj->buf_in.buf = NULL;
19331 + }
19332 +
19333 + if (cfiobj->buf_out.buf) {
19334 + DWC_DMA_FREE(CFI_OUT_BUF_LEN, cfiobj->buf_out.buf,
19335 + cfiobj->buf_out.addr);
19336 + cfiobj->buf_out.buf = NULL;
19337 + }
19338 +
19339 + /* Free the Buffer Setup values for each EP */
19340 + //list_for_each_entry(cfiep, &cfiobj->active_eps, lh) {
19341 + DWC_LIST_FOREACH(tmp, &cfiobj->active_eps) {
19342 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19343 + cfi_free_ep_bs_dyn_data(cfiep);
19344 + }
19345 +}
19346 +
19347 +/**
19348 + * This function frees the dynamically allocated EP buffer setup data.
19349 + */
19350 +static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep)
19351 +{
19352 + if (cfiep->bm_sg) {
19353 + DWC_FREE(cfiep->bm_sg);
19354 + cfiep->bm_sg = NULL;
19355 + }
19356 +
19357 + if (cfiep->bm_align) {
19358 + DWC_FREE(cfiep->bm_align);
19359 + cfiep->bm_align = NULL;
19360 + }
19361 +
19362 + if (cfiep->bm_concat) {
19363 + if (NULL != cfiep->bm_concat->wTxBytes) {
19364 + DWC_FREE(cfiep->bm_concat->wTxBytes);
19365 + cfiep->bm_concat->wTxBytes = NULL;
19366 + }
19367 + DWC_FREE(cfiep->bm_concat);
19368 + cfiep->bm_concat = NULL;
19369 + }
19370 +}
19371 +
19372 +/**
19373 + * This function initializes the default values of the features
19374 + * for a specific endpoint and should be called only once when
19375 + * the EP is enabled first time.
19376 + */
19377 +static int cfi_ep_init_defaults(struct dwc_otg_pcd *pcd, cfi_ep_t * cfiep)
19378 +{
19379 + int retval = 0;
19380 +
19381 + cfiep->bm_sg = DWC_ALLOC(sizeof(ddma_sg_buffer_setup_t));
19382 + if (NULL == cfiep->bm_sg) {
19383 + CFI_INFO("Failed to allocate memory for SG feature value\n");
19384 + return -DWC_E_NO_MEMORY;
19385 + }
19386 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
19387 +
19388 + /* For the Concatenation feature's default value we do not allocate
19389 + * memory for the wTxBytes field - it will be done in the set_feature_value
19390 + * request handler.
19391 + */
19392 + cfiep->bm_concat = DWC_ALLOC(sizeof(ddma_concat_buffer_setup_t));
19393 + if (NULL == cfiep->bm_concat) {
19394 + CFI_INFO
19395 + ("Failed to allocate memory for CONCATENATION feature value\n");
19396 + DWC_FREE(cfiep->bm_sg);
19397 + return -DWC_E_NO_MEMORY;
19398 + }
19399 + dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
19400 +
19401 + cfiep->bm_align = DWC_ALLOC(sizeof(ddma_align_buffer_setup_t));
19402 + if (NULL == cfiep->bm_align) {
19403 + CFI_INFO
19404 + ("Failed to allocate memory for Alignment feature value\n");
19405 + DWC_FREE(cfiep->bm_sg);
19406 + DWC_FREE(cfiep->bm_concat);
19407 + return -DWC_E_NO_MEMORY;
19408 + }
19409 + dwc_memset(cfiep->bm_align, 0, sizeof(ddma_align_buffer_setup_t));
19410 +
19411 + return retval;
19412 +}
19413 +
19414 +/**
19415 + * The callback function that notifies the CFI on the activation of
19416 + * an endpoint in the PCD. The following steps are done in this function:
19417 + *
19418 + * Create a dynamically allocated cfi_ep_t object (a CFI wrapper to the PCD's
19419 + * active endpoint)
19420 + * Create MAX_DMA_DESCS_PER_EP count DMA Descriptors for the EP
19421 + * Set the Buffer Mode to standard
19422 + * Initialize the default values for all EP modes (SG, Circular, Concat, Align)
19423 + * Add the cfi_ep_t object to the list of active endpoints in the CFI object
19424 + */
19425 +static int cfi_ep_enable(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
19426 + struct dwc_otg_pcd_ep *ep)
19427 +{
19428 + cfi_ep_t *cfiep;
19429 + int retval = -DWC_E_NOT_SUPPORTED;
19430 +
19431 + CFI_INFO("%s: epname=%s; epnum=0x%02x\n", __func__,
19432 + "EP_" /*ep->ep.name */ , ep->desc->bEndpointAddress);
19433 + /* MAS - Check whether this endpoint already is in the list */
19434 + cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
19435 +
19436 + if (NULL == cfiep) {
19437 + /* Allocate a cfi_ep_t object */
19438 + cfiep = DWC_ALLOC(sizeof(cfi_ep_t));
19439 + if (NULL == cfiep) {
19440 + CFI_INFO
19441 + ("Unable to allocate memory for <cfiep> in function %s\n",
19442 + __func__);
19443 + return -DWC_E_NO_MEMORY;
19444 + }
19445 + dwc_memset(cfiep, 0, sizeof(cfi_ep_t));
19446 +
19447 + /* Save the dwc_otg_pcd_ep pointer in the cfiep object */
19448 + cfiep->ep = ep;
19449 +
19450 + /* Allocate the DMA Descriptors chain of MAX_DMA_DESCS_PER_EP count */
19451 + ep->dwc_ep.descs =
19452 + DWC_DMA_ALLOC(MAX_DMA_DESCS_PER_EP *
19453 + sizeof(dwc_otg_dma_desc_t),
19454 + &ep->dwc_ep.descs_dma_addr);
19455 +
19456 + if (NULL == ep->dwc_ep.descs) {
19457 + DWC_FREE(cfiep);
19458 + return -DWC_E_NO_MEMORY;
19459 + }
19460 +
19461 + DWC_LIST_INIT(&cfiep->lh);
19462 +
19463 + /* Set the buffer mode to BM_STANDARD. It will be modified
19464 + * when building descriptors for a specific buffer mode */
19465 + ep->dwc_ep.buff_mode = BM_STANDARD;
19466 +
19467 + /* Create and initialize the default values for this EP's Buffer modes */
19468 + if ((retval = cfi_ep_init_defaults(pcd, cfiep)) < 0)
19469 + return retval;
19470 +
19471 + /* Add the cfi_ep_t object to the CFI object's list of active endpoints */
19472 + DWC_LIST_INSERT_TAIL(&cfi->active_eps, &cfiep->lh);
19473 + retval = 0;
19474 + } else { /* The sought EP already is in the list */
19475 + CFI_INFO("%s: The sought EP already is in the list\n",
19476 + __func__);
19477 + }
19478 +
19479 + return retval;
19480 +}
19481 +
19482 +/**
19483 + * This function is called when the data stage of a 3-stage Control Write request
19484 + * is complete.
19485 + *
19486 + */
19487 +static int cfi_ctrl_write_complete(struct cfiobject *cfi,
19488 + struct dwc_otg_pcd *pcd)
19489 +{
19490 + uint32_t addr, reg_value;
19491 + uint16_t wIndex, wValue;
19492 + uint8_t bRequest;
19493 + uint8_t *buf = cfi->buf_out.buf;
19494 + //struct usb_ctrlrequest *ctrl_req = &cfi->ctrl_req_saved;
19495 + struct cfi_usb_ctrlrequest *ctrl_req = &cfi->ctrl_req;
19496 + int retval = -DWC_E_NOT_SUPPORTED;
19497 +
19498 + CFI_INFO("%s\n", __func__);
19499 +
19500 + bRequest = ctrl_req->bRequest;
19501 + wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
19502 + wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
19503 +
19504 + /*
19505 + * Save the pointer to the data stage in the ctrl_req's <data> field.
19506 + * The request should be already saved in the command stage by now.
19507 + */
19508 + ctrl_req->data = cfi->buf_out.buf;
19509 + cfi->need_status_in_complete = 0;
19510 + cfi->need_gadget_att = 0;
19511 +
19512 + switch (bRequest) {
19513 + case VEN_CORE_WRITE_REGISTER:
19514 + /* The buffer contains raw data of the new value for the register */
19515 + reg_value = *((uint32_t *) buf);
19516 + if (wValue == 0) {
19517 + addr = 0;
19518 + //addr = (uint32_t) pcd->otg_dev->os_dep.base;
19519 + addr += wIndex;
19520 + } else {
19521 + addr = (wValue << 16) | wIndex;
19522 + }
19523 +
19524 + //writel(reg_value, addr);
19525 +
19526 + retval = 0;
19527 + cfi->need_status_in_complete = 1;
19528 + break;
19529 +
19530 + case VEN_CORE_SET_FEATURE:
19531 + /* The buffer contains raw data of the new value of the feature */
19532 + retval = cfi_set_feature_value(pcd);
19533 + if (retval < 0)
19534 + return retval;
19535 +
19536 + cfi->need_status_in_complete = 1;
19537 + break;
19538 +
19539 + default:
19540 + break;
19541 + }
19542 +
19543 + return retval;
19544 +}
19545 +
19546 +/**
19547 + * This function builds the DMA descriptors for the SG buffer mode.
19548 + */
19549 +static void cfi_build_sg_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19550 + dwc_otg_pcd_request_t * req)
19551 +{
19552 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
19553 + ddma_sg_buffer_setup_t *sgval = cfiep->bm_sg;
19554 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
19555 + struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
19556 + dma_addr_t buff_addr = req->dma;
19557 + int i;
19558 + uint32_t txsize, off;
19559 +
19560 + txsize = sgval->wSize;
19561 + off = sgval->bOffset;
19562 +
19563 +// CFI_INFO("%s: %s TXSIZE=0x%08x; OFFSET=0x%08x\n",
19564 +// __func__, cfiep->ep->ep.name, txsize, off);
19565 +
19566 + for (i = 0; i < sgval->bCount; i++) {
19567 + desc->status.b.bs = BS_HOST_BUSY;
19568 + desc->buf = buff_addr;
19569 + desc->status.b.l = 0;
19570 + desc->status.b.ioc = 0;
19571 + desc->status.b.sp = 0;
19572 + desc->status.b.bytes = txsize;
19573 + desc->status.b.bs = BS_HOST_READY;
19574 +
19575 + /* Set the next address of the buffer */
19576 + buff_addr += txsize + off;
19577 + desc_last = desc;
19578 + desc++;
19579 + }
19580 +
19581 + /* Set the last, ioc and sp bits on the Last DMA Descriptor */
19582 + desc_last->status.b.l = 1;
19583 + desc_last->status.b.ioc = 1;
19584 + desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
19585 + /* Save the last DMA descriptor pointer */
19586 + cfiep->dma_desc_last = desc_last;
19587 + cfiep->desc_count = sgval->bCount;
19588 +}
19589 +
19590 +/**
19591 + * This function builds the DMA descriptors for the Concatenation buffer mode.
19592 + */
19593 +static void cfi_build_concat_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19594 + dwc_otg_pcd_request_t * req)
19595 +{
19596 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
19597 + ddma_concat_buffer_setup_t *concatval = cfiep->bm_concat;
19598 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
19599 + struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
19600 + dma_addr_t buff_addr = req->dma;
19601 + int i;
19602 + uint16_t *txsize;
19603 +
19604 + txsize = concatval->wTxBytes;
19605 +
19606 + for (i = 0; i < concatval->hdr.bDescCount; i++) {
19607 + desc->buf = buff_addr;
19608 + desc->status.b.bs = BS_HOST_BUSY;
19609 + desc->status.b.l = 0;
19610 + desc->status.b.ioc = 0;
19611 + desc->status.b.sp = 0;
19612 + desc->status.b.bytes = *txsize;
19613 + desc->status.b.bs = BS_HOST_READY;
19614 +
19615 + txsize++;
19616 + /* Set the next address of the buffer */
19617 + buff_addr += UGETW(ep->desc->wMaxPacketSize);
19618 + desc_last = desc;
19619 + desc++;
19620 + }
19621 +
19622 + /* Set the last, ioc and sp bits on the Last DMA Descriptor */
19623 + desc_last->status.b.l = 1;
19624 + desc_last->status.b.ioc = 1;
19625 + desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
19626 + cfiep->dma_desc_last = desc_last;
19627 + cfiep->desc_count = concatval->hdr.bDescCount;
19628 +}
19629 +
19630 +/**
19631 + * This function builds the DMA descriptors for the Circular buffer mode
19632 + */
19633 +static void cfi_build_circ_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19634 + dwc_otg_pcd_request_t * req)
19635 +{
19636 + /* @todo: MAS - add implementation when this feature needs to be tested */
19637 +}
19638 +
19639 +/**
19640 + * This function builds the DMA descriptors for the Alignment buffer mode
19641 + */
19642 +static void cfi_build_align_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19643 + dwc_otg_pcd_request_t * req)
19644 +{
19645 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
19646 + ddma_align_buffer_setup_t *alignval = cfiep->bm_align;
19647 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
19648 + dma_addr_t buff_addr = req->dma;
19649 +
19650 + desc->status.b.bs = BS_HOST_BUSY;
19651 + desc->status.b.l = 1;
19652 + desc->status.b.ioc = 1;
19653 + desc->status.b.sp = ep->dwc_ep.sent_zlp;
19654 + desc->status.b.bytes = req->length;
19655 + /* Adjust the buffer alignment */
19656 + desc->buf = (buff_addr + alignval->bAlign);
19657 + desc->status.b.bs = BS_HOST_READY;
19658 + cfiep->dma_desc_last = desc;
19659 + cfiep->desc_count = 1;
19660 +}
19661 +
19662 +/**
19663 + * This function builds the DMA descriptors chain for different modes of the
19664 + * buffer setup of an endpoint.
19665 + */
19666 +static void cfi_build_descriptors(struct cfiobject *cfi,
19667 + struct dwc_otg_pcd *pcd,
19668 + struct dwc_otg_pcd_ep *ep,
19669 + dwc_otg_pcd_request_t * req)
19670 +{
19671 + cfi_ep_t *cfiep;
19672 +
19673 + /* Get the cfiep by the dwc_otg_pcd_ep */
19674 + cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
19675 + if (NULL == cfiep) {
19676 + CFI_INFO("%s: Unable to find a matching active endpoint\n",
19677 + __func__);
19678 + return;
19679 + }
19680 +
19681 + cfiep->xfer_len = req->length;
19682 +
19683 + /* Iterate through all the DMA descriptors */
19684 + switch (cfiep->ep->dwc_ep.buff_mode) {
19685 + case BM_SG:
19686 + cfi_build_sg_descs(cfi, cfiep, req);
19687 + break;
19688 +
19689 + case BM_CONCAT:
19690 + cfi_build_concat_descs(cfi, cfiep, req);
19691 + break;
19692 +
19693 + case BM_CIRCULAR:
19694 + cfi_build_circ_descs(cfi, cfiep, req);
19695 + break;
19696 +
19697 + case BM_ALIGN:
19698 + cfi_build_align_descs(cfi, cfiep, req);
19699 + break;
19700 +
19701 + default:
19702 + break;
19703 + }
19704 +}
19705 +
19706 +/**
19707 + * Allocate DMA buffer for different Buffer modes.
19708 + */
19709 +static void *cfi_ep_alloc_buf(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
19710 + struct dwc_otg_pcd_ep *ep, dma_addr_t * dma,
19711 + unsigned size, gfp_t flags)
19712 +{
19713 + return DWC_DMA_ALLOC(size, dma);
19714 +}
19715 +
19716 +/**
19717 + * This function initializes the CFI object.
19718 + */
19719 +int init_cfi(cfiobject_t * cfiobj)
19720 +{
19721 + CFI_INFO("%s\n", __func__);
19722 +
19723 + /* Allocate a buffer for IN XFERs */
19724 + cfiobj->buf_in.buf =
19725 + DWC_DMA_ALLOC(CFI_IN_BUF_LEN, &cfiobj->buf_in.addr);
19726 + if (NULL == cfiobj->buf_in.buf) {
19727 + CFI_INFO("Unable to allocate buffer for INs\n");
19728 + return -DWC_E_NO_MEMORY;
19729 + }
19730 +
19731 + /* Allocate a buffer for OUT XFERs */
19732 + cfiobj->buf_out.buf =
19733 + DWC_DMA_ALLOC(CFI_OUT_BUF_LEN, &cfiobj->buf_out.addr);
19734 + if (NULL == cfiobj->buf_out.buf) {
19735 + CFI_INFO("Unable to allocate buffer for OUT\n");
19736 + return -DWC_E_NO_MEMORY;
19737 + }
19738 +
19739 + /* Initialize the callback function pointers */
19740 + cfiobj->ops.release = cfi_release;
19741 + cfiobj->ops.ep_enable = cfi_ep_enable;
19742 + cfiobj->ops.ctrl_write_complete = cfi_ctrl_write_complete;
19743 + cfiobj->ops.build_descriptors = cfi_build_descriptors;
19744 + cfiobj->ops.ep_alloc_buf = cfi_ep_alloc_buf;
19745 +
19746 + /* Initialize the list of active endpoints in the CFI object */
19747 + DWC_LIST_INIT(&cfiobj->active_eps);
19748 +
19749 + return 0;
19750 +}
19751 +
19752 +/**
19753 + * This function reads the required feature's current value into the buffer
19754 + *
19755 + * @retval: Returns negative as error, or the data length of the feature
19756 + */
19757 +static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
19758 + struct dwc_otg_pcd *pcd,
19759 + struct cfi_usb_ctrlrequest *ctrl_req)
19760 +{
19761 + int retval = -DWC_E_NOT_SUPPORTED;
19762 + struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
19763 + uint16_t dfifo, rxfifo, txfifo;
19764 +
19765 + switch (ctrl_req->wIndex) {
19766 + /* Whether the DDMA is enabled or not */
19767 + case FT_ID_DMA_MODE:
19768 + *buf = (coreif->dma_enable && coreif->dma_desc_enable) ? 1 : 0;
19769 + retval = 1;
19770 + break;
19771 +
19772 + case FT_ID_DMA_BUFFER_SETUP:
19773 + retval = cfi_ep_get_sg_val(buf, pcd, ctrl_req);
19774 + break;
19775 +
19776 + case FT_ID_DMA_BUFF_ALIGN:
19777 + retval = cfi_ep_get_align_val(buf, pcd, ctrl_req);
19778 + break;
19779 +
19780 + case FT_ID_DMA_CONCAT_SETUP:
19781 + retval = cfi_ep_get_concat_val(buf, pcd, ctrl_req);
19782 + break;
19783 +
19784 + case FT_ID_DMA_CIRCULAR:
19785 + CFI_INFO("GetFeature value (FT_ID_DMA_CIRCULAR)\n");
19786 + break;
19787 +
19788 + case FT_ID_THRESHOLD_SETUP:
19789 + CFI_INFO("GetFeature value (FT_ID_THRESHOLD_SETUP)\n");
19790 + break;
19791 +
19792 + case FT_ID_DFIFO_DEPTH:
19793 + dfifo = get_dfifo_size(coreif);
19794 + *((uint16_t *) buf) = dfifo;
19795 + retval = sizeof(uint16_t);
19796 + break;
19797 +
19798 + case FT_ID_TX_FIFO_DEPTH:
19799 + retval = get_txfifo_size(pcd, ctrl_req->wValue);
19800 + if (retval >= 0) {
19801 + txfifo = retval;
19802 + *((uint16_t *) buf) = txfifo;
19803 + retval = sizeof(uint16_t);
19804 + }
19805 + break;
19806 +
19807 + case FT_ID_RX_FIFO_DEPTH:
19808 + retval = get_rxfifo_size(coreif, ctrl_req->wValue);
19809 + if (retval >= 0) {
19810 + rxfifo = retval;
19811 + *((uint16_t *) buf) = rxfifo;
19812 + retval = sizeof(uint16_t);
19813 + }
19814 + break;
19815 + }
19816 +
19817 + return retval;
19818 +}
19819 +
19820 +/**
19821 + * This function resets the SG for the specified EP to its default value
19822 + */
19823 +static int cfi_reset_sg_val(cfi_ep_t * cfiep)
19824 +{
19825 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
19826 + return 0;
19827 +}
19828 +
19829 +/**
19830 + * This function resets the Alignment for the specified EP to its default value
19831 + */
19832 +static int cfi_reset_align_val(cfi_ep_t * cfiep)
19833 +{
19834 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
19835 + return 0;
19836 +}
19837 +
19838 +/**
19839 + * This function resets the Concatenation for the specified EP to its default value
19840 + * This function will also set the value of the wTxBytes field to NULL after
19841 + * freeing the memory previously allocated for this field.
19842 + */
19843 +static int cfi_reset_concat_val(cfi_ep_t * cfiep)
19844 +{
19845 + /* First we need to free the wTxBytes field */
19846 + if (cfiep->bm_concat->wTxBytes) {
19847 + DWC_FREE(cfiep->bm_concat->wTxBytes);
19848 + cfiep->bm_concat->wTxBytes = NULL;
19849 + }
19850 +
19851 + dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
19852 + return 0;
19853 +}
19854 +
19855 +/**
19856 + * This function resets all the buffer setups of the specified endpoint
19857 + */
19858 +static int cfi_ep_reset_all_setup_vals(cfi_ep_t * cfiep)
19859 +{
19860 + cfi_reset_sg_val(cfiep);
19861 + cfi_reset_align_val(cfiep);
19862 + cfi_reset_concat_val(cfiep);
19863 + return 0;
19864 +}
19865 +
19866 +static int cfi_handle_reset_fifo_val(struct dwc_otg_pcd *pcd, uint8_t ep_addr,
19867 + uint8_t rx_rst, uint8_t tx_rst)
19868 +{
19869 + int retval = -DWC_E_INVALID;
19870 + uint16_t tx_siz[15];
19871 + uint16_t rx_siz = 0;
19872 + dwc_otg_pcd_ep_t *ep = NULL;
19873 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
19874 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
19875 +
19876 + if (rx_rst) {
19877 + rx_siz = params->dev_rx_fifo_size;
19878 + params->dev_rx_fifo_size = GET_CORE_IF(pcd)->init_rxfsiz;
19879 + }
19880 +
19881 + if (tx_rst) {
19882 + if (ep_addr == 0) {
19883 + int i;
19884 +
19885 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
19886 + tx_siz[i] =
19887 + core_if->core_params->dev_tx_fifo_size[i];
19888 + core_if->core_params->dev_tx_fifo_size[i] =
19889 + core_if->init_txfsiz[i];
19890 + }
19891 + } else {
19892 +
19893 + ep = get_ep_by_addr(pcd, ep_addr);
19894 +
19895 + if (NULL == ep) {
19896 + CFI_INFO
19897 + ("%s: Unable to get the endpoint addr=0x%02x\n",
19898 + __func__, ep_addr);
19899 + return -DWC_E_INVALID;
19900 + }
19901 +
19902 + tx_siz[0] =
19903 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num -
19904 + 1];
19905 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] =
19906 + GET_CORE_IF(pcd)->init_txfsiz[ep->
19907 + dwc_ep.tx_fifo_num -
19908 + 1];
19909 + }
19910 + }
19911 +
19912 + if (resize_fifos(GET_CORE_IF(pcd))) {
19913 + retval = 0;
19914 + } else {
19915 + CFI_INFO
19916 + ("%s: Error resetting the feature Reset All(FIFO size)\n",
19917 + __func__);
19918 + if (rx_rst) {
19919 + params->dev_rx_fifo_size = rx_siz;
19920 + }
19921 +
19922 + if (tx_rst) {
19923 + if (ep_addr == 0) {
19924 + int i;
19925 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps;
19926 + i++) {
19927 + core_if->
19928 + core_params->dev_tx_fifo_size[i] =
19929 + tx_siz[i];
19930 + }
19931 + } else {
19932 + params->dev_tx_fifo_size[ep->
19933 + dwc_ep.tx_fifo_num -
19934 + 1] = tx_siz[0];
19935 + }
19936 + }
19937 + retval = -DWC_E_INVALID;
19938 + }
19939 + return retval;
19940 +}
19941 +
19942 +static int cfi_handle_reset_all(struct dwc_otg_pcd *pcd, uint8_t addr)
19943 +{
19944 + int retval = 0;
19945 + cfi_ep_t *cfiep;
19946 + cfiobject_t *cfi = pcd->cfi;
19947 + dwc_list_link_t *tmp;
19948 +
19949 + retval = cfi_handle_reset_fifo_val(pcd, addr, 1, 1);
19950 + if (retval < 0) {
19951 + return retval;
19952 + }
19953 +
19954 + /* If the EP address is known then reset the features for only that EP */
19955 + if (addr) {
19956 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
19957 + if (NULL == cfiep) {
19958 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
19959 + __func__, addr);
19960 + return -DWC_E_INVALID;
19961 + }
19962 + retval = cfi_ep_reset_all_setup_vals(cfiep);
19963 + cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
19964 + }
19965 + /* Otherwise (wValue == 0), reset all features of all EP's */
19966 + else {
19967 + /* Traverse all the active EP's and reset the feature(s) value(s) */
19968 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
19969 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
19970 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19971 + retval = cfi_ep_reset_all_setup_vals(cfiep);
19972 + cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
19973 + if (retval < 0) {
19974 + CFI_INFO
19975 + ("%s: Error resetting the feature Reset All\n",
19976 + __func__);
19977 + return retval;
19978 + }
19979 + }
19980 + }
19981 + return retval;
19982 +}
19983 +
19984 +static int cfi_handle_reset_dma_buff_setup(struct dwc_otg_pcd *pcd,
19985 + uint8_t addr)
19986 +{
19987 + int retval = 0;
19988 + cfi_ep_t *cfiep;
19989 + cfiobject_t *cfi = pcd->cfi;
19990 + dwc_list_link_t *tmp;
19991 +
19992 + /* If the EP address is known then reset the features for only that EP */
19993 + if (addr) {
19994 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
19995 + if (NULL == cfiep) {
19996 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
19997 + __func__, addr);
19998 + return -DWC_E_INVALID;
19999 + }
20000 + retval = cfi_reset_sg_val(cfiep);
20001 + }
20002 + /* Otherwise (wValue == 0), reset all features of all EP's */
20003 + else {
20004 + /* Traverse all the active EP's and reset the feature(s) value(s) */
20005 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
20006 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
20007 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
20008 + retval = cfi_reset_sg_val(cfiep);
20009 + if (retval < 0) {
20010 + CFI_INFO
20011 + ("%s: Error resetting the feature Buffer Setup\n",
20012 + __func__);
20013 + return retval;
20014 + }
20015 + }
20016 + }
20017 + return retval;
20018 +}
20019 +
20020 +static int cfi_handle_reset_concat_val(struct dwc_otg_pcd *pcd, uint8_t addr)
20021 +{
20022 + int retval = 0;
20023 + cfi_ep_t *cfiep;
20024 + cfiobject_t *cfi = pcd->cfi;
20025 + dwc_list_link_t *tmp;
20026 +
20027 + /* If the EP address is known then reset the features for only that EP */
20028 + if (addr) {
20029 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
20030 + if (NULL == cfiep) {
20031 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
20032 + __func__, addr);
20033 + return -DWC_E_INVALID;
20034 + }
20035 + retval = cfi_reset_concat_val(cfiep);
20036 + }
20037 + /* Otherwise (wValue == 0), reset all features of all EP's */
20038 + else {
20039 + /* Traverse all the active EP's and reset the feature(s) value(s) */
20040 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
20041 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
20042 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
20043 + retval = cfi_reset_concat_val(cfiep);
20044 + if (retval < 0) {
20045 + CFI_INFO
20046 + ("%s: Error resetting the feature Concatenation Value\n",
20047 + __func__);
20048 + return retval;
20049 + }
20050 + }
20051 + }
20052 + return retval;
20053 +}
20054 +
20055 +static int cfi_handle_reset_align_val(struct dwc_otg_pcd *pcd, uint8_t addr)
20056 +{
20057 + int retval = 0;
20058 + cfi_ep_t *cfiep;
20059 + cfiobject_t *cfi = pcd->cfi;
20060 + dwc_list_link_t *tmp;
20061 +
20062 + /* If the EP address is known then reset the features for only that EP */
20063 + if (addr) {
20064 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
20065 + if (NULL == cfiep) {
20066 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
20067 + __func__, addr);
20068 + return -DWC_E_INVALID;
20069 + }
20070 + retval = cfi_reset_align_val(cfiep);
20071 + }
20072 + /* Otherwise (wValue == 0), reset all features of all EP's */
20073 + else {
20074 + /* Traverse all the active EP's and reset the feature(s) value(s) */
20075 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
20076 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
20077 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
20078 + retval = cfi_reset_align_val(cfiep);
20079 + if (retval < 0) {
20080 + CFI_INFO
20081 + ("%s: Error resetting the feature Aliignment Value\n",
20082 + __func__);
20083 + return retval;
20084 + }
20085 + }
20086 + }
20087 + return retval;
20088 +
20089 +}
20090 +
20091 +static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
20092 + struct cfi_usb_ctrlrequest *req)
20093 +{
20094 + int retval = 0;
20095 +
20096 + switch (req->wIndex) {
20097 + case 0:
20098 + /* Reset all features */
20099 + retval = cfi_handle_reset_all(pcd, req->wValue & 0xff);
20100 + break;
20101 +
20102 + case FT_ID_DMA_BUFFER_SETUP:
20103 + /* Reset the SG buffer setup */
20104 + retval =
20105 + cfi_handle_reset_dma_buff_setup(pcd, req->wValue & 0xff);
20106 + break;
20107 +
20108 + case FT_ID_DMA_CONCAT_SETUP:
20109 + /* Reset the Concatenation buffer setup */
20110 + retval = cfi_handle_reset_concat_val(pcd, req->wValue & 0xff);
20111 + break;
20112 +
20113 + case FT_ID_DMA_BUFF_ALIGN:
20114 + /* Reset the Alignment buffer setup */
20115 + retval = cfi_handle_reset_align_val(pcd, req->wValue & 0xff);
20116 + break;
20117 +
20118 + case FT_ID_TX_FIFO_DEPTH:
20119 + retval =
20120 + cfi_handle_reset_fifo_val(pcd, req->wValue & 0xff, 0, 1);
20121 + pcd->cfi->need_gadget_att = 0;
20122 + break;
20123 +
20124 + case FT_ID_RX_FIFO_DEPTH:
20125 + retval = cfi_handle_reset_fifo_val(pcd, 0, 1, 0);
20126 + pcd->cfi->need_gadget_att = 0;
20127 + break;
20128 + default:
20129 + break;
20130 + }
20131 + return retval;
20132 +}
20133 +
20134 +/**
20135 + * This function sets a new value for the SG buffer setup.
20136 + */
20137 +static int cfi_ep_set_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
20138 +{
20139 + uint8_t inaddr, outaddr;
20140 + cfi_ep_t *epin, *epout;
20141 + ddma_sg_buffer_setup_t *psgval;
20142 + uint32_t desccount, size;
20143 +
20144 + CFI_INFO("%s\n", __func__);
20145 +
20146 + psgval = (ddma_sg_buffer_setup_t *) buf;
20147 + desccount = (uint32_t) psgval->bCount;
20148 + size = (uint32_t) psgval->wSize;
20149 +
20150 + /* Check the DMA descriptor count */
20151 + if ((desccount > MAX_DMA_DESCS_PER_EP) || (desccount == 0)) {
20152 + CFI_INFO
20153 + ("%s: The count of DMA Descriptors should be between 1 and %d\n",
20154 + __func__, MAX_DMA_DESCS_PER_EP);
20155 + return -DWC_E_INVALID;
20156 + }
20157 +
20158 + /* Check the DMA descriptor count */
20159 +
20160 + if (size == 0) {
20161 +
20162 + CFI_INFO("%s: The transfer size should be at least 1 byte\n",
20163 + __func__);
20164 +
20165 + return -DWC_E_INVALID;
20166 +
20167 + }
20168 +
20169 + inaddr = psgval->bInEndpointAddress;
20170 + outaddr = psgval->bOutEndpointAddress;
20171 +
20172 + epin = get_cfi_ep_by_addr(pcd->cfi, inaddr);
20173 + epout = get_cfi_ep_by_addr(pcd->cfi, outaddr);
20174 +
20175 + if (NULL == epin || NULL == epout) {
20176 + CFI_INFO
20177 + ("%s: Unable to get the endpoints inaddr=0x%02x outaddr=0x%02x\n",
20178 + __func__, inaddr, outaddr);
20179 + return -DWC_E_INVALID;
20180 + }
20181 +
20182 + epin->ep->dwc_ep.buff_mode = BM_SG;
20183 + dwc_memcpy(epin->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
20184 +
20185 + epout->ep->dwc_ep.buff_mode = BM_SG;
20186 + dwc_memcpy(epout->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
20187 +
20188 + return 0;
20189 +}
20190 +
20191 +/**
20192 + * This function sets a new value for the buffer Alignment setup.
20193 + */
20194 +static int cfi_ep_set_alignment_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
20195 +{
20196 + cfi_ep_t *ep;
20197 + uint8_t addr;
20198 + ddma_align_buffer_setup_t *palignval;
20199 +
20200 + palignval = (ddma_align_buffer_setup_t *) buf;
20201 + addr = palignval->bEndpointAddress;
20202 +
20203 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20204 +
20205 + if (NULL == ep) {
20206 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20207 + __func__, addr);
20208 + return -DWC_E_INVALID;
20209 + }
20210 +
20211 + ep->ep->dwc_ep.buff_mode = BM_ALIGN;
20212 + dwc_memcpy(ep->bm_align, palignval, sizeof(ddma_align_buffer_setup_t));
20213 +
20214 + return 0;
20215 +}
20216 +
20217 +/**
20218 + * This function sets a new value for the Concatenation buffer setup.
20219 + */
20220 +static int cfi_ep_set_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
20221 +{
20222 + uint8_t addr;
20223 + cfi_ep_t *ep;
20224 + struct _ddma_concat_buffer_setup_hdr *pConcatValHdr;
20225 + uint16_t *pVals;
20226 + uint32_t desccount;
20227 + int i;
20228 + uint16_t mps;
20229 +
20230 + pConcatValHdr = (struct _ddma_concat_buffer_setup_hdr *)buf;
20231 + desccount = (uint32_t) pConcatValHdr->bDescCount;
20232 + pVals = (uint16_t *) (buf + BS_CONCAT_VAL_HDR_LEN);
20233 +
20234 + /* Check the DMA descriptor count */
20235 + if (desccount > MAX_DMA_DESCS_PER_EP) {
20236 + CFI_INFO("%s: Maximum DMA Descriptor count should be %d\n",
20237 + __func__, MAX_DMA_DESCS_PER_EP);
20238 + return -DWC_E_INVALID;
20239 + }
20240 +
20241 + addr = pConcatValHdr->bEndpointAddress;
20242 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20243 + if (NULL == ep) {
20244 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20245 + __func__, addr);
20246 + return -DWC_E_INVALID;
20247 + }
20248 +
20249 + mps = UGETW(ep->ep->desc->wMaxPacketSize);
20250 +
20251 +#if 0
20252 + for (i = 0; i < desccount; i++) {
20253 + CFI_INFO("%s: wTxSize[%d]=0x%04x\n", __func__, i, pVals[i]);
20254 + }
20255 + CFI_INFO("%s: epname=%s; mps=%d\n", __func__, ep->ep->ep.name, mps);
20256 +#endif
20257 +
20258 + /* Check the wTxSizes to be less than or equal to the mps */
20259 + for (i = 0; i < desccount; i++) {
20260 + if (pVals[i] > mps) {
20261 + CFI_INFO
20262 + ("%s: ERROR - the wTxSize[%d] should be <= MPS (wTxSize=%d)\n",
20263 + __func__, i, pVals[i]);
20264 + return -DWC_E_INVALID;
20265 + }
20266 + }
20267 +
20268 + ep->ep->dwc_ep.buff_mode = BM_CONCAT;
20269 + dwc_memcpy(ep->bm_concat, pConcatValHdr, BS_CONCAT_VAL_HDR_LEN);
20270 +
20271 + /* Free the previously allocated storage for the wTxBytes */
20272 + if (ep->bm_concat->wTxBytes) {
20273 + DWC_FREE(ep->bm_concat->wTxBytes);
20274 + }
20275 +
20276 + /* Allocate a new storage for the wTxBytes field */
20277 + ep->bm_concat->wTxBytes =
20278 + DWC_ALLOC(sizeof(uint16_t) * pConcatValHdr->bDescCount);
20279 + if (NULL == ep->bm_concat->wTxBytes) {
20280 + CFI_INFO("%s: Unable to allocate memory\n", __func__);
20281 + return -DWC_E_NO_MEMORY;
20282 + }
20283 +
20284 + /* Copy the new values into the wTxBytes filed */
20285 + dwc_memcpy(ep->bm_concat->wTxBytes, buf + BS_CONCAT_VAL_HDR_LEN,
20286 + sizeof(uint16_t) * pConcatValHdr->bDescCount);
20287 +
20288 + return 0;
20289 +}
20290 +
20291 +/**
20292 + * This function calculates the total of all FIFO sizes
20293 + *
20294 + * @param core_if Programming view of DWC_otg controller
20295 + *
20296 + * @return The total of data FIFO sizes.
20297 + *
20298 + */
20299 +static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if)
20300 +{
20301 + dwc_otg_core_params_t *params = core_if->core_params;
20302 + uint16_t dfifo_total = 0;
20303 + int i;
20304 +
20305 + /* The shared RxFIFO size */
20306 + dfifo_total =
20307 + params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
20308 +
20309 + /* Add up each TxFIFO size to the total */
20310 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20311 + dfifo_total += params->dev_tx_fifo_size[i];
20312 + }
20313 +
20314 + return dfifo_total;
20315 +}
20316 +
20317 +/**
20318 + * This function returns Rx FIFO size
20319 + *
20320 + * @param core_if Programming view of DWC_otg controller
20321 + *
20322 + * @return The total of data FIFO sizes.
20323 + *
20324 + */
20325 +static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue)
20326 +{
20327 + switch (wValue >> 8) {
20328 + case 0:
20329 + return (core_if->pwron_rxfsiz <
20330 + 32768) ? core_if->pwron_rxfsiz : 32768;
20331 + break;
20332 + case 1:
20333 + return core_if->core_params->dev_rx_fifo_size;
20334 + break;
20335 + default:
20336 + return -DWC_E_INVALID;
20337 + break;
20338 + }
20339 +}
20340 +
20341 +/**
20342 + * This function returns Tx FIFO size for IN EP
20343 + *
20344 + * @param core_if Programming view of DWC_otg controller
20345 + *
20346 + * @return The total of data FIFO sizes.
20347 + *
20348 + */
20349 +static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue)
20350 +{
20351 + dwc_otg_pcd_ep_t *ep;
20352 +
20353 + ep = get_ep_by_addr(pcd, wValue & 0xff);
20354 +
20355 + if (NULL == ep) {
20356 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20357 + __func__, wValue & 0xff);
20358 + return -DWC_E_INVALID;
20359 + }
20360 +
20361 + if (!ep->dwc_ep.is_in) {
20362 + CFI_INFO
20363 + ("%s: No Tx FIFO assingned to the Out endpoint addr=0x%02x\n",
20364 + __func__, wValue & 0xff);
20365 + return -DWC_E_INVALID;
20366 + }
20367 +
20368 + switch (wValue >> 8) {
20369 + case 0:
20370 + return (GET_CORE_IF(pcd)->pwron_txfsiz
20371 + [ep->dwc_ep.tx_fifo_num - 1] <
20372 + 768) ? GET_CORE_IF(pcd)->pwron_txfsiz[ep->
20373 + dwc_ep.tx_fifo_num
20374 + - 1] : 32768;
20375 + break;
20376 + case 1:
20377 + return GET_CORE_IF(pcd)->core_params->
20378 + dev_tx_fifo_size[ep->dwc_ep.num - 1];
20379 + break;
20380 + default:
20381 + return -DWC_E_INVALID;
20382 + break;
20383 + }
20384 +}
20385 +
20386 +/**
20387 + * This function checks if the submitted combination of
20388 + * device mode FIFO sizes is possible or not.
20389 + *
20390 + * @param core_if Programming view of DWC_otg controller
20391 + *
20392 + * @return 1 if possible, 0 otherwise.
20393 + *
20394 + */
20395 +static uint8_t check_fifo_sizes(dwc_otg_core_if_t * core_if)
20396 +{
20397 + uint16_t dfifo_actual = 0;
20398 + dwc_otg_core_params_t *params = core_if->core_params;
20399 + uint16_t start_addr = 0;
20400 + int i;
20401 +
20402 + dfifo_actual =
20403 + params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
20404 +
20405 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20406 + dfifo_actual += params->dev_tx_fifo_size[i];
20407 + }
20408 +
20409 + if (dfifo_actual > core_if->total_fifo_size) {
20410 + return 0;
20411 + }
20412 +
20413 + if (params->dev_rx_fifo_size > 32768 || params->dev_rx_fifo_size < 16)
20414 + return 0;
20415 +
20416 + if (params->dev_nperio_tx_fifo_size > 32768
20417 + || params->dev_nperio_tx_fifo_size < 16)
20418 + return 0;
20419 +
20420 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20421 +
20422 + if (params->dev_tx_fifo_size[i] > 768
20423 + || params->dev_tx_fifo_size[i] < 4)
20424 + return 0;
20425 + }
20426 +
20427 + if (params->dev_rx_fifo_size > core_if->pwron_rxfsiz)
20428 + return 0;
20429 + start_addr = params->dev_rx_fifo_size;
20430 +
20431 + if (params->dev_nperio_tx_fifo_size > core_if->pwron_gnptxfsiz)
20432 + return 0;
20433 + start_addr += params->dev_nperio_tx_fifo_size;
20434 +
20435 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20436 +
20437 + if (params->dev_tx_fifo_size[i] > core_if->pwron_txfsiz[i])
20438 + return 0;
20439 + start_addr += params->dev_tx_fifo_size[i];
20440 + }
20441 +
20442 + return 1;
20443 +}
20444 +
20445 +/**
20446 + * This function resizes Device mode FIFOs
20447 + *
20448 + * @param core_if Programming view of DWC_otg controller
20449 + *
20450 + * @return 1 if successful, 0 otherwise
20451 + *
20452 + */
20453 +static uint8_t resize_fifos(dwc_otg_core_if_t * core_if)
20454 +{
20455 + int i = 0;
20456 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
20457 + dwc_otg_core_params_t *params = core_if->core_params;
20458 + uint32_t rx_fifo_size;
20459 + fifosize_data_t nptxfifosize;
20460 + fifosize_data_t txfifosize[15];
20461 +
20462 + uint32_t rx_fsz_bak;
20463 + uint32_t nptxfsz_bak;
20464 + uint32_t txfsz_bak[15];
20465 +
20466 + uint16_t start_address;
20467 + uint8_t retval = 1;
20468 +
20469 + if (!check_fifo_sizes(core_if)) {
20470 + return 0;
20471 + }
20472 +
20473 + /* Configure data FIFO sizes */
20474 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
20475 + rx_fsz_bak = DWC_READ_REG32(&global_regs->grxfsiz);
20476 + rx_fifo_size = params->dev_rx_fifo_size;
20477 + DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
20478 +
20479 + /*
20480 + * Tx FIFOs These FIFOs are numbered from 1 to 15.
20481 + * Indexes of the FIFO size module parameters in the
20482 + * dev_tx_fifo_size array and the FIFO size registers in
20483 + * the dtxfsiz array run from 0 to 14.
20484 + */
20485 +
20486 + /* Non-periodic Tx FIFO */
20487 + nptxfsz_bak = DWC_READ_REG32(&global_regs->gnptxfsiz);
20488 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
20489 + start_address = params->dev_rx_fifo_size;
20490 + nptxfifosize.b.startaddr = start_address;
20491 +
20492 + DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
20493 +
20494 + start_address += nptxfifosize.b.depth;
20495 +
20496 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20497 + txfsz_bak[i] = DWC_READ_REG32(&global_regs->dtxfsiz[i]);
20498 +
20499 + txfifosize[i].b.depth = params->dev_tx_fifo_size[i];
20500 + txfifosize[i].b.startaddr = start_address;
20501 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
20502 + txfifosize[i].d32);
20503 +
20504 + start_address += txfifosize[i].b.depth;
20505 + }
20506 +
20507 + /** Check if register values are set correctly */
20508 + if (rx_fifo_size != DWC_READ_REG32(&global_regs->grxfsiz)) {
20509 + retval = 0;
20510 + }
20511 +
20512 + if (nptxfifosize.d32 != DWC_READ_REG32(&global_regs->gnptxfsiz)) {
20513 + retval = 0;
20514 + }
20515 +
20516 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20517 + if (txfifosize[i].d32 !=
20518 + DWC_READ_REG32(&global_regs->dtxfsiz[i])) {
20519 + retval = 0;
20520 + }
20521 + }
20522 +
20523 + /** If register values are not set correctly, reset old values */
20524 + if (retval == 0) {
20525 + DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fsz_bak);
20526 +
20527 + /* Non-periodic Tx FIFO */
20528 + DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfsz_bak);
20529 +
20530 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20531 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
20532 + txfsz_bak[i]);
20533 + }
20534 + }
20535 + } else {
20536 + return 0;
20537 + }
20538 +
20539 + /* Flush the FIFOs */
20540 + dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */
20541 + dwc_otg_flush_rx_fifo(core_if);
20542 +
20543 + return retval;
20544 +}
20545 +
20546 +/**
20547 + * This function sets a new value for the buffer Alignment setup.
20548 + */
20549 +static int cfi_ep_set_tx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
20550 +{
20551 + int retval;
20552 + uint32_t fsiz;
20553 + uint16_t size;
20554 + uint16_t ep_addr;
20555 + dwc_otg_pcd_ep_t *ep;
20556 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
20557 + tx_fifo_size_setup_t *ptxfifoval;
20558 +
20559 + ptxfifoval = (tx_fifo_size_setup_t *) buf;
20560 + ep_addr = ptxfifoval->bEndpointAddress;
20561 + size = ptxfifoval->wDepth;
20562 +
20563 + ep = get_ep_by_addr(pcd, ep_addr);
20564 +
20565 + CFI_INFO
20566 + ("%s: Set Tx FIFO size: endpoint addr=0x%02x, depth=%d, FIFO Num=%d\n",
20567 + __func__, ep_addr, size, ep->dwc_ep.tx_fifo_num);
20568 +
20569 + if (NULL == ep) {
20570 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20571 + __func__, ep_addr);
20572 + return -DWC_E_INVALID;
20573 + }
20574 +
20575 + fsiz = params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1];
20576 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = size;
20577 +
20578 + if (resize_fifos(GET_CORE_IF(pcd))) {
20579 + retval = 0;
20580 + } else {
20581 + CFI_INFO
20582 + ("%s: Error setting the feature Tx FIFO Size for EP%d\n",
20583 + __func__, ep_addr);
20584 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = fsiz;
20585 + retval = -DWC_E_INVALID;
20586 + }
20587 +
20588 + return retval;
20589 +}
20590 +
20591 +/**
20592 + * This function sets a new value for the buffer Alignment setup.
20593 + */
20594 +static int cfi_set_rx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
20595 +{
20596 + int retval;
20597 + uint32_t fsiz;
20598 + uint16_t size;
20599 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
20600 + rx_fifo_size_setup_t *prxfifoval;
20601 +
20602 + prxfifoval = (rx_fifo_size_setup_t *) buf;
20603 + size = prxfifoval->wDepth;
20604 +
20605 + fsiz = params->dev_rx_fifo_size;
20606 + params->dev_rx_fifo_size = size;
20607 +
20608 + if (resize_fifos(GET_CORE_IF(pcd))) {
20609 + retval = 0;
20610 + } else {
20611 + CFI_INFO("%s: Error setting the feature Rx FIFO Size\n",
20612 + __func__);
20613 + params->dev_rx_fifo_size = fsiz;
20614 + retval = -DWC_E_INVALID;
20615 + }
20616 +
20617 + return retval;
20618 +}
20619 +
20620 +/**
20621 + * This function reads the SG of an EP's buffer setup into the buffer buf
20622 + */
20623 +static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
20624 + struct cfi_usb_ctrlrequest *req)
20625 +{
20626 + int retval = -DWC_E_INVALID;
20627 + uint8_t addr;
20628 + cfi_ep_t *ep;
20629 +
20630 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
20631 + addr = req->wValue & 0xFF;
20632 + if (addr == 0) /* The address should be non-zero */
20633 + return retval;
20634 +
20635 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20636 + if (NULL == ep) {
20637 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
20638 + __func__, addr);
20639 + return retval;
20640 + }
20641 +
20642 + dwc_memcpy(buf, ep->bm_sg, BS_SG_VAL_DESC_LEN);
20643 + retval = BS_SG_VAL_DESC_LEN;
20644 + return retval;
20645 +}
20646 +
20647 +/**
20648 + * This function reads the Concatenation value of an EP's buffer mode into
20649 + * the buffer buf
20650 + */
20651 +static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
20652 + struct cfi_usb_ctrlrequest *req)
20653 +{
20654 + int retval = -DWC_E_INVALID;
20655 + uint8_t addr;
20656 + cfi_ep_t *ep;
20657 + uint8_t desc_count;
20658 +
20659 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
20660 + addr = req->wValue & 0xFF;
20661 + if (addr == 0) /* The address should be non-zero */
20662 + return retval;
20663 +
20664 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20665 + if (NULL == ep) {
20666 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
20667 + __func__, addr);
20668 + return retval;
20669 + }
20670 +
20671 + /* Copy the header to the buffer */
20672 + dwc_memcpy(buf, ep->bm_concat, BS_CONCAT_VAL_HDR_LEN);
20673 + /* Advance the buffer pointer by the header size */
20674 + buf += BS_CONCAT_VAL_HDR_LEN;
20675 +
20676 + desc_count = ep->bm_concat->hdr.bDescCount;
20677 + /* Copy alll the wTxBytes to the buffer */
20678 + dwc_memcpy(buf, ep->bm_concat->wTxBytes, sizeof(uid16_t) * desc_count);
20679 +
20680 + retval = BS_CONCAT_VAL_HDR_LEN + sizeof(uid16_t) * desc_count;
20681 + return retval;
20682 +}
20683 +
20684 +/**
20685 + * This function reads the buffer Alignment value of an EP's buffer mode into
20686 + * the buffer buf
20687 + *
20688 + * @return The total number of bytes copied to the buffer or negative error code.
20689 + */
20690 +static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
20691 + struct cfi_usb_ctrlrequest *req)
20692 +{
20693 + int retval = -DWC_E_INVALID;
20694 + uint8_t addr;
20695 + cfi_ep_t *ep;
20696 +
20697 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
20698 + addr = req->wValue & 0xFF;
20699 + if (addr == 0) /* The address should be non-zero */
20700 + return retval;
20701 +
20702 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20703 + if (NULL == ep) {
20704 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
20705 + __func__, addr);
20706 + return retval;
20707 + }
20708 +
20709 + dwc_memcpy(buf, ep->bm_align, BS_ALIGN_VAL_HDR_LEN);
20710 + retval = BS_ALIGN_VAL_HDR_LEN;
20711 +
20712 + return retval;
20713 +}
20714 +
20715 +/**
20716 + * This function sets a new value for the specified feature
20717 + *
20718 + * @param pcd A pointer to the PCD object
20719 + *
20720 + * @return 0 if successful, negative error code otherwise to stall the DCE.
20721 + */
20722 +static int cfi_set_feature_value(struct dwc_otg_pcd *pcd)
20723 +{
20724 + int retval = -DWC_E_NOT_SUPPORTED;
20725 + uint16_t wIndex, wValue;
20726 + uint8_t bRequest;
20727 + struct dwc_otg_core_if *coreif;
20728 + cfiobject_t *cfi = pcd->cfi;
20729 + struct cfi_usb_ctrlrequest *ctrl_req;
20730 + uint8_t *buf;
20731 + ctrl_req = &cfi->ctrl_req;
20732 +
20733 + buf = pcd->cfi->ctrl_req.data;
20734 +
20735 + coreif = GET_CORE_IF(pcd);
20736 + bRequest = ctrl_req->bRequest;
20737 + wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
20738 + wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
20739 +
20740 + /* See which feature is to be modified */
20741 + switch (wIndex) {
20742 + case FT_ID_DMA_BUFFER_SETUP:
20743 + /* Modify the feature */
20744 + if ((retval = cfi_ep_set_sg_val(buf, pcd)) < 0)
20745 + return retval;
20746 +
20747 + /* And send this request to the gadget */
20748 + cfi->need_gadget_att = 1;
20749 + break;
20750 +
20751 + case FT_ID_DMA_BUFF_ALIGN:
20752 + if ((retval = cfi_ep_set_alignment_val(buf, pcd)) < 0)
20753 + return retval;
20754 + cfi->need_gadget_att = 1;
20755 + break;
20756 +
20757 + case FT_ID_DMA_CONCAT_SETUP:
20758 + /* Modify the feature */
20759 + if ((retval = cfi_ep_set_concat_val(buf, pcd)) < 0)
20760 + return retval;
20761 + cfi->need_gadget_att = 1;
20762 + break;
20763 +
20764 + case FT_ID_DMA_CIRCULAR:
20765 + CFI_INFO("FT_ID_DMA_CIRCULAR\n");
20766 + break;
20767 +
20768 + case FT_ID_THRESHOLD_SETUP:
20769 + CFI_INFO("FT_ID_THRESHOLD_SETUP\n");
20770 + break;
20771 +
20772 + case FT_ID_DFIFO_DEPTH:
20773 + CFI_INFO("FT_ID_DFIFO_DEPTH\n");
20774 + break;
20775 +
20776 + case FT_ID_TX_FIFO_DEPTH:
20777 + CFI_INFO("FT_ID_TX_FIFO_DEPTH\n");
20778 + if ((retval = cfi_ep_set_tx_fifo_val(buf, pcd)) < 0)
20779 + return retval;
20780 + cfi->need_gadget_att = 0;
20781 + break;
20782 +
20783 + case FT_ID_RX_FIFO_DEPTH:
20784 + CFI_INFO("FT_ID_RX_FIFO_DEPTH\n");
20785 + if ((retval = cfi_set_rx_fifo_val(buf, pcd)) < 0)
20786 + return retval;
20787 + cfi->need_gadget_att = 0;
20788 + break;
20789 + }
20790 +
20791 + return retval;
20792 +}
20793 +
20794 +#endif //DWC_UTE_CFI
20795 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cfi.h b/drivers/usb/host/dwc_otg/dwc_otg_cfi.h
20796 new file mode 100644
20797 index 0000000..55fd337
20798 --- /dev/null
20799 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.h
20800 @@ -0,0 +1,320 @@
20801 +/* ==========================================================================
20802 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
20803 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
20804 + * otherwise expressly agreed to in writing between Synopsys and you.
20805 + *
20806 + * The Software IS NOT an item of Licensed Software or Licensed Product under
20807 + * any End User Software License Agreement or Agreement for Licensed Product
20808 + * with Synopsys or any supplement thereto. You are permitted to use and
20809 + * redistribute this Software in source and binary forms, with or without
20810 + * modification, provided that redistributions of source code must retain this
20811 + * notice. You may not view, use, disclose, copy or distribute this file or
20812 + * any information contained herein except pursuant to this license grant from
20813 + * Synopsys. If you do not agree with this notice, including the disclaimer
20814 + * below, then you are not authorized to use the Software.
20815 + *
20816 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
20817 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20818 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20819 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
20820 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20821 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20822 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20823 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20824 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
20825 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
20826 + * DAMAGE.
20827 + * ========================================================================== */
20828 +
20829 +#if !defined(__DWC_OTG_CFI_H__)
20830 +#define __DWC_OTG_CFI_H__
20831 +
20832 +#include "dwc_otg_pcd.h"
20833 +#include "dwc_cfi_common.h"
20834 +
20835 +/**
20836 + * @file
20837 + * This file contains the CFI related OTG PCD specific common constants,
20838 + * interfaces(functions and macros) and data structures.The CFI Protocol is an
20839 + * optional interface for internal testing purposes that a DUT may implement to
20840 + * support testing of configurable features.
20841 + *
20842 + */
20843 +
20844 +struct dwc_otg_pcd;
20845 +struct dwc_otg_pcd_ep;
20846 +
20847 +/** OTG CFI Features (properties) ID constants */
20848 +/** This is a request for all Core Features */
20849 +#define FT_ID_DMA_MODE 0x0001
20850 +#define FT_ID_DMA_BUFFER_SETUP 0x0002
20851 +#define FT_ID_DMA_BUFF_ALIGN 0x0003
20852 +#define FT_ID_DMA_CONCAT_SETUP 0x0004
20853 +#define FT_ID_DMA_CIRCULAR 0x0005
20854 +#define FT_ID_THRESHOLD_SETUP 0x0006
20855 +#define FT_ID_DFIFO_DEPTH 0x0007
20856 +#define FT_ID_TX_FIFO_DEPTH 0x0008
20857 +#define FT_ID_RX_FIFO_DEPTH 0x0009
20858 +
20859 +/**********************************************************/
20860 +#define CFI_INFO_DEF
20861 +
20862 +#ifdef CFI_INFO_DEF
20863 +#define CFI_INFO(fmt...) DWC_PRINTF("CFI: " fmt);
20864 +#else
20865 +#define CFI_INFO(fmt...)
20866 +#endif
20867 +
20868 +#define min(x,y) ({ \
20869 + x < y ? x : y; })
20870 +
20871 +#define max(x,y) ({ \
20872 + x > y ? x : y; })
20873 +
20874 +/**
20875 + * Descriptor DMA SG Buffer setup structure (SG buffer). This structure is
20876 + * also used for setting up a buffer for Circular DDMA.
20877 + */
20878 +struct _ddma_sg_buffer_setup {
20879 +#define BS_SG_VAL_DESC_LEN 6
20880 + /* The OUT EP address */
20881 + uint8_t bOutEndpointAddress;
20882 + /* The IN EP address */
20883 + uint8_t bInEndpointAddress;
20884 + /* Number of bytes to put between transfer segments (must be DWORD boundaries) */
20885 + uint8_t bOffset;
20886 + /* The number of transfer segments (a DMA descriptors per each segment) */
20887 + uint8_t bCount;
20888 + /* Size (in byte) of each transfer segment */
20889 + uint16_t wSize;
20890 +} __attribute__ ((packed));
20891 +typedef struct _ddma_sg_buffer_setup ddma_sg_buffer_setup_t;
20892 +
20893 +/** Descriptor DMA Concatenation Buffer setup structure */
20894 +struct _ddma_concat_buffer_setup_hdr {
20895 +#define BS_CONCAT_VAL_HDR_LEN 4
20896 + /* The endpoint for which the buffer is to be set up */
20897 + uint8_t bEndpointAddress;
20898 + /* The count of descriptors to be used */
20899 + uint8_t bDescCount;
20900 + /* The total size of the transfer */
20901 + uint16_t wSize;
20902 +} __attribute__ ((packed));
20903 +typedef struct _ddma_concat_buffer_setup_hdr ddma_concat_buffer_setup_hdr_t;
20904 +
20905 +/** Descriptor DMA Concatenation Buffer setup structure */
20906 +struct _ddma_concat_buffer_setup {
20907 + /* The SG header */
20908 + ddma_concat_buffer_setup_hdr_t hdr;
20909 +
20910 + /* The XFER sizes pointer (allocated dynamically) */
20911 + uint16_t *wTxBytes;
20912 +} __attribute__ ((packed));
20913 +typedef struct _ddma_concat_buffer_setup ddma_concat_buffer_setup_t;
20914 +
20915 +/** Descriptor DMA Alignment Buffer setup structure */
20916 +struct _ddma_align_buffer_setup {
20917 +#define BS_ALIGN_VAL_HDR_LEN 2
20918 + uint8_t bEndpointAddress;
20919 + uint8_t bAlign;
20920 +} __attribute__ ((packed));
20921 +typedef struct _ddma_align_buffer_setup ddma_align_buffer_setup_t;
20922 +
20923 +/** Transmit FIFO Size setup structure */
20924 +struct _tx_fifo_size_setup {
20925 + uint8_t bEndpointAddress;
20926 + uint16_t wDepth;
20927 +} __attribute__ ((packed));
20928 +typedef struct _tx_fifo_size_setup tx_fifo_size_setup_t;
20929 +
20930 +/** Transmit FIFO Size setup structure */
20931 +struct _rx_fifo_size_setup {
20932 + uint16_t wDepth;
20933 +} __attribute__ ((packed));
20934 +typedef struct _rx_fifo_size_setup rx_fifo_size_setup_t;
20935 +
20936 +/**
20937 + * struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest
20938 + * This structure encapsulates the standard usb_ctrlrequest and adds a pointer
20939 + * to the data returned in the data stage of a 3-stage Control Write requests.
20940 + */
20941 +struct cfi_usb_ctrlrequest {
20942 + uint8_t bRequestType;
20943 + uint8_t bRequest;
20944 + uint16_t wValue;
20945 + uint16_t wIndex;
20946 + uint16_t wLength;
20947 + uint8_t *data;
20948 +} UPACKED;
20949 +
20950 +/*---------------------------------------------------------------------------*/
20951 +
20952 +/**
20953 + * The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures.
20954 + * This structure is used to store the buffer setup data for any
20955 + * enabled endpoint in the PCD.
20956 + */
20957 +struct cfi_ep {
20958 + /* Entry for the list container */
20959 + dwc_list_link_t lh;
20960 + /* Pointer to the active PCD endpoint structure */
20961 + struct dwc_otg_pcd_ep *ep;
20962 + /* The last descriptor in the chain of DMA descriptors of the endpoint */
20963 + struct dwc_otg_dma_desc *dma_desc_last;
20964 + /* The SG feature value */
20965 + ddma_sg_buffer_setup_t *bm_sg;
20966 + /* The Circular feature value */
20967 + ddma_sg_buffer_setup_t *bm_circ;
20968 + /* The Concatenation feature value */
20969 + ddma_concat_buffer_setup_t *bm_concat;
20970 + /* The Alignment feature value */
20971 + ddma_align_buffer_setup_t *bm_align;
20972 + /* XFER length */
20973 + uint32_t xfer_len;
20974 + /*
20975 + * Count of DMA descriptors currently used.
20976 + * The total should not exceed the MAX_DMA_DESCS_PER_EP value
20977 + * defined in the dwc_otg_cil.h
20978 + */
20979 + uint32_t desc_count;
20980 +};
20981 +typedef struct cfi_ep cfi_ep_t;
20982 +
20983 +typedef struct cfi_dma_buff {
20984 +#define CFI_IN_BUF_LEN 1024
20985 +#define CFI_OUT_BUF_LEN 1024
20986 + dma_addr_t addr;
20987 + uint8_t *buf;
20988 +} cfi_dma_buff_t;
20989 +
20990 +struct cfiobject;
20991 +
20992 +/**
20993 + * This is the interface for the CFI operations.
20994 + *
20995 + * @param ep_enable Called when any endpoint is enabled and activated.
20996 + * @param release Called when the CFI object is released and it needs to correctly
20997 + * deallocate the dynamic memory
20998 + * @param ctrl_write_complete Called when the data stage of the request is complete
20999 + */
21000 +typedef struct cfi_ops {
21001 + int (*ep_enable) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
21002 + struct dwc_otg_pcd_ep * ep);
21003 + void *(*ep_alloc_buf) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
21004 + struct dwc_otg_pcd_ep * ep, dma_addr_t * dma,
21005 + unsigned size, gfp_t flags);
21006 + void (*release) (struct cfiobject * cfi);
21007 + int (*ctrl_write_complete) (struct cfiobject * cfi,
21008 + struct dwc_otg_pcd * pcd);
21009 + void (*build_descriptors) (struct cfiobject * cfi,
21010 + struct dwc_otg_pcd * pcd,
21011 + struct dwc_otg_pcd_ep * ep,
21012 + dwc_otg_pcd_request_t * req);
21013 +} cfi_ops_t;
21014 +
21015 +struct cfiobject {
21016 + cfi_ops_t ops;
21017 + struct dwc_otg_pcd *pcd;
21018 + struct usb_gadget *gadget;
21019 +
21020 + /* Buffers used to send/receive CFI-related request data */
21021 + cfi_dma_buff_t buf_in;
21022 + cfi_dma_buff_t buf_out;
21023 +
21024 + /* CFI specific Control request wrapper */
21025 + struct cfi_usb_ctrlrequest ctrl_req;
21026 +
21027 + /* The list of active EP's in the PCD of type cfi_ep_t */
21028 + dwc_list_link_t active_eps;
21029 +
21030 + /* This flag shall control the propagation of a specific request
21031 + * to the gadget's processing routines.
21032 + * 0 - no gadget handling
21033 + * 1 - the gadget needs to know about this request (w/o completing a status
21034 + * phase - just return a 0 to the _setup callback)
21035 + */
21036 + uint8_t need_gadget_att;
21037 +
21038 + /* Flag indicating whether the status IN phase needs to be
21039 + * completed by the PCD
21040 + */
21041 + uint8_t need_status_in_complete;
21042 +};
21043 +typedef struct cfiobject cfiobject_t;
21044 +
21045 +#define DUMP_MSG
21046 +
21047 +#if defined(DUMP_MSG)
21048 +static inline void dump_msg(const u8 * buf, unsigned int length)
21049 +{
21050 + unsigned int start, num, i;
21051 + char line[52], *p;
21052 +
21053 + if (length >= 512)
21054 + return;
21055 +
21056 + start = 0;
21057 + while (length > 0) {
21058 + num = min(length, 16u);
21059 + p = line;
21060 + for (i = 0; i < num; ++i) {
21061 + if (i == 8)
21062 + *p++ = ' ';
21063 + DWC_SPRINTF(p, " %02x", buf[i]);
21064 + p += 3;
21065 + }
21066 + *p = 0;
21067 + DWC_DEBUG("%6x: %s\n", start, line);
21068 + buf += num;
21069 + start += num;
21070 + length -= num;
21071 + }
21072 +}
21073 +#else
21074 +static inline void dump_msg(const u8 * buf, unsigned int length)
21075 +{
21076 +}
21077 +#endif
21078 +
21079 +/**
21080 + * This function returns a pointer to cfi_ep_t object with the addr address.
21081 + */
21082 +static inline struct cfi_ep *get_cfi_ep_by_addr(struct cfiobject *cfi,
21083 + uint8_t addr)
21084 +{
21085 + struct cfi_ep *pcfiep;
21086 + dwc_list_link_t *tmp;
21087 +
21088 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
21089 + pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
21090 +
21091 + if (pcfiep->ep->desc->bEndpointAddress == addr) {
21092 + return pcfiep;
21093 + }
21094 + }
21095 +
21096 + return NULL;
21097 +}
21098 +
21099 +/**
21100 + * This function returns a pointer to cfi_ep_t object that matches
21101 + * the dwc_otg_pcd_ep object.
21102 + */
21103 +static inline struct cfi_ep *get_cfi_ep_by_pcd_ep(struct cfiobject *cfi,
21104 + struct dwc_otg_pcd_ep *ep)
21105 +{
21106 + struct cfi_ep *pcfiep = NULL;
21107 + dwc_list_link_t *tmp;
21108 +
21109 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
21110 + pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
21111 + if (pcfiep->ep == ep) {
21112 + return pcfiep;
21113 + }
21114 + }
21115 + return NULL;
21116 +}
21117 +
21118 +int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl);
21119 +
21120 +#endif /* (__DWC_OTG_CFI_H__) */
21121 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil.c b/drivers/usb/host/dwc_otg/dwc_otg_cil.c
21122 new file mode 100644
21123 index 0000000..6a32c5c
21124 --- /dev/null
21125 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.c
21126 @@ -0,0 +1,7151 @@
21127 +/* ==========================================================================
21128 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.c $
21129 + * $Revision: #191 $
21130 + * $Date: 2012/08/10 $
21131 + * $Change: 2047372 $
21132 + *
21133 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
21134 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
21135 + * otherwise expressly agreed to in writing between Synopsys and you.
21136 + *
21137 + * The Software IS NOT an item of Licensed Software or Licensed Product under
21138 + * any End User Software License Agreement or Agreement for Licensed Product
21139 + * with Synopsys or any supplement thereto. You are permitted to use and
21140 + * redistribute this Software in source and binary forms, with or without
21141 + * modification, provided that redistributions of source code must retain this
21142 + * notice. You may not view, use, disclose, copy or distribute this file or
21143 + * any information contained herein except pursuant to this license grant from
21144 + * Synopsys. If you do not agree with this notice, including the disclaimer
21145 + * below, then you are not authorized to use the Software.
21146 + *
21147 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
21148 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21149 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21150 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
21151 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21152 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21153 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21154 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21155 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21156 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
21157 + * DAMAGE.
21158 + * ========================================================================== */
21159 +
21160 +/** @file
21161 + *
21162 + * The Core Interface Layer provides basic services for accessing and
21163 + * managing the DWC_otg hardware. These services are used by both the
21164 + * Host Controller Driver and the Peripheral Controller Driver.
21165 + *
21166 + * The CIL manages the memory map for the core so that the HCD and PCD
21167 + * don't have to do this separately. It also handles basic tasks like
21168 + * reading/writing the registers and data FIFOs in the controller.
21169 + * Some of the data access functions provide encapsulation of several
21170 + * operations required to perform a task, such as writing multiple
21171 + * registers to start a transfer. Finally, the CIL performs basic
21172 + * services that are not specific to either the host or device modes
21173 + * of operation. These services include management of the OTG Host
21174 + * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A
21175 + * Diagnostic API is also provided to allow testing of the controller
21176 + * hardware.
21177 + *
21178 + * The Core Interface Layer has the following requirements:
21179 + * - Provides basic controller operations.
21180 + * - Minimal use of OS services.
21181 + * - The OS services used will be abstracted by using inline functions
21182 + * or macros.
21183 + *
21184 + */
21185 +
21186 +#include "dwc_os.h"
21187 +#include "dwc_otg_regs.h"
21188 +#include "dwc_otg_cil.h"
21189 +
21190 +static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if);
21191 +
21192 +/**
21193 + * This function is called to initialize the DWC_otg CSR data
21194 + * structures. The register addresses in the device and host
21195 + * structures are initialized from the base address supplied by the
21196 + * caller. The calling function must make the OS calls to get the
21197 + * base address of the DWC_otg controller registers. The core_params
21198 + * argument holds the parameters that specify how the core should be
21199 + * configured.
21200 + *
21201 + * @param reg_base_addr Base address of DWC_otg core registers
21202 + *
21203 + */
21204 +dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * reg_base_addr)
21205 +{
21206 + dwc_otg_core_if_t *core_if = 0;
21207 + dwc_otg_dev_if_t *dev_if = 0;
21208 + dwc_otg_host_if_t *host_if = 0;
21209 + uint8_t *reg_base = (uint8_t *) reg_base_addr;
21210 + int i = 0;
21211 +
21212 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, reg_base_addr);
21213 +
21214 + core_if = DWC_ALLOC(sizeof(dwc_otg_core_if_t));
21215 +
21216 + if (core_if == NULL) {
21217 + DWC_DEBUGPL(DBG_CIL,
21218 + "Allocation of dwc_otg_core_if_t failed\n");
21219 + return 0;
21220 + }
21221 + core_if->core_global_regs = (dwc_otg_core_global_regs_t *) reg_base;
21222 +
21223 + /*
21224 + * Allocate the Device Mode structures.
21225 + */
21226 + dev_if = DWC_ALLOC(sizeof(dwc_otg_dev_if_t));
21227 +
21228 + if (dev_if == NULL) {
21229 + DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n");
21230 + DWC_FREE(core_if);
21231 + return 0;
21232 + }
21233 +
21234 + dev_if->dev_global_regs =
21235 + (dwc_otg_device_global_regs_t *) (reg_base +
21236 + DWC_DEV_GLOBAL_REG_OFFSET);
21237 +
21238 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21239 + dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *)
21240 + (reg_base + DWC_DEV_IN_EP_REG_OFFSET +
21241 + (i * DWC_EP_REG_OFFSET));
21242 +
21243 + dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *)
21244 + (reg_base + DWC_DEV_OUT_EP_REG_OFFSET +
21245 + (i * DWC_EP_REG_OFFSET));
21246 + DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n",
21247 + i, &dev_if->in_ep_regs[i]->diepctl);
21248 + DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n",
21249 + i, &dev_if->out_ep_regs[i]->doepctl);
21250 + }
21251 +
21252 + dev_if->speed = 0; // unknown
21253 +
21254 + core_if->dev_if = dev_if;
21255 +
21256 + /*
21257 + * Allocate the Host Mode structures.
21258 + */
21259 + host_if = DWC_ALLOC(sizeof(dwc_otg_host_if_t));
21260 +
21261 + if (host_if == NULL) {
21262 + DWC_DEBUGPL(DBG_CIL,
21263 + "Allocation of dwc_otg_host_if_t failed\n");
21264 + DWC_FREE(dev_if);
21265 + DWC_FREE(core_if);
21266 + return 0;
21267 + }
21268 +
21269 + host_if->host_global_regs = (dwc_otg_host_global_regs_t *)
21270 + (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET);
21271 +
21272 + host_if->hprt0 =
21273 + (uint32_t *) (reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);
21274 +
21275 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21276 + host_if->hc_regs[i] = (dwc_otg_hc_regs_t *)
21277 + (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET +
21278 + (i * DWC_OTG_CHAN_REGS_OFFSET));
21279 + DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n",
21280 + i, &host_if->hc_regs[i]->hcchar);
21281 + }
21282 +
21283 + host_if->num_host_channels = MAX_EPS_CHANNELS;
21284 + core_if->host_if = host_if;
21285 +
21286 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21287 + core_if->data_fifo[i] =
21288 + (uint32_t *) (reg_base + DWC_OTG_DATA_FIFO_OFFSET +
21289 + (i * DWC_OTG_DATA_FIFO_SIZE));
21290 + DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08lx\n",
21291 + i, (unsigned long)core_if->data_fifo[i]);
21292 + }
21293 +
21294 + core_if->pcgcctl = (uint32_t *) (reg_base + DWC_OTG_PCGCCTL_OFFSET);
21295 +
21296 + /* Initiate lx_state to L3 disconnected state */
21297 + core_if->lx_state = DWC_OTG_L3;
21298 + /*
21299 + * Store the contents of the hardware configuration registers here for
21300 + * easy access later.
21301 + */
21302 + core_if->hwcfg1.d32 =
21303 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg1);
21304 + core_if->hwcfg2.d32 =
21305 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
21306 + core_if->hwcfg3.d32 =
21307 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg3);
21308 + core_if->hwcfg4.d32 =
21309 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
21310 +
21311 + /* Force host mode to get HPTXFSIZ exact power on value */
21312 + {
21313 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
21314 + gusbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
21315 + gusbcfg.b.force_host_mode = 1;
21316 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
21317 + dwc_mdelay(100);
21318 + core_if->hptxfsiz.d32 =
21319 + DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
21320 + gusbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
21321 + gusbcfg.b.force_host_mode = 0;
21322 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
21323 + dwc_mdelay(100);
21324 + }
21325 +
21326 + DWC_DEBUGPL(DBG_CILV, "hwcfg1=%08x\n", core_if->hwcfg1.d32);
21327 + DWC_DEBUGPL(DBG_CILV, "hwcfg2=%08x\n", core_if->hwcfg2.d32);
21328 + DWC_DEBUGPL(DBG_CILV, "hwcfg3=%08x\n", core_if->hwcfg3.d32);
21329 + DWC_DEBUGPL(DBG_CILV, "hwcfg4=%08x\n", core_if->hwcfg4.d32);
21330 +
21331 + core_if->hcfg.d32 =
21332 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
21333 + core_if->dcfg.d32 =
21334 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
21335 +
21336 + DWC_DEBUGPL(DBG_CILV, "hcfg=%08x\n", core_if->hcfg.d32);
21337 + DWC_DEBUGPL(DBG_CILV, "dcfg=%08x\n", core_if->dcfg.d32);
21338 +
21339 + DWC_DEBUGPL(DBG_CILV, "op_mode=%0x\n", core_if->hwcfg2.b.op_mode);
21340 + DWC_DEBUGPL(DBG_CILV, "arch=%0x\n", core_if->hwcfg2.b.architecture);
21341 + DWC_DEBUGPL(DBG_CILV, "num_dev_ep=%d\n", core_if->hwcfg2.b.num_dev_ep);
21342 + DWC_DEBUGPL(DBG_CILV, "num_host_chan=%d\n",
21343 + core_if->hwcfg2.b.num_host_chan);
21344 + DWC_DEBUGPL(DBG_CILV, "nonperio_tx_q_depth=0x%0x\n",
21345 + core_if->hwcfg2.b.nonperio_tx_q_depth);
21346 + DWC_DEBUGPL(DBG_CILV, "host_perio_tx_q_depth=0x%0x\n",
21347 + core_if->hwcfg2.b.host_perio_tx_q_depth);
21348 + DWC_DEBUGPL(DBG_CILV, "dev_token_q_depth=0x%0x\n",
21349 + core_if->hwcfg2.b.dev_token_q_depth);
21350 +
21351 + DWC_DEBUGPL(DBG_CILV, "Total FIFO SZ=%d\n",
21352 + core_if->hwcfg3.b.dfifo_depth);
21353 + DWC_DEBUGPL(DBG_CILV, "xfer_size_cntr_width=%0x\n",
21354 + core_if->hwcfg3.b.xfer_size_cntr_width);
21355 +
21356 + /*
21357 + * Set the SRP sucess bit for FS-I2c
21358 + */
21359 + core_if->srp_success = 0;
21360 + core_if->srp_timer_started = 0;
21361 +
21362 + /*
21363 + * Create new workqueue and init works
21364 + */
21365 + core_if->wq_otg = DWC_WORKQ_ALLOC("dwc_otg");
21366 + if (core_if->wq_otg == 0) {
21367 + DWC_WARN("DWC_WORKQ_ALLOC failed\n");
21368 + DWC_FREE(host_if);
21369 + DWC_FREE(dev_if);
21370 + DWC_FREE(core_if);
21371 + return 0;
21372 + }
21373 +
21374 + core_if->snpsid = DWC_READ_REG32(&core_if->core_global_regs->gsnpsid);
21375 +
21376 + DWC_PRINTF("Core Release: %x.%x%x%x\n",
21377 + (core_if->snpsid >> 12 & 0xF),
21378 + (core_if->snpsid >> 8 & 0xF),
21379 + (core_if->snpsid >> 4 & 0xF), (core_if->snpsid & 0xF));
21380 +
21381 + core_if->wkp_timer = DWC_TIMER_ALLOC("Wake Up Timer",
21382 + w_wakeup_detected, core_if);
21383 + if (core_if->wkp_timer == 0) {
21384 + DWC_WARN("DWC_TIMER_ALLOC failed\n");
21385 + DWC_FREE(host_if);
21386 + DWC_FREE(dev_if);
21387 + DWC_WORKQ_FREE(core_if->wq_otg);
21388 + DWC_FREE(core_if);
21389 + return 0;
21390 + }
21391 +
21392 + if (dwc_otg_setup_params(core_if)) {
21393 + DWC_WARN("Error while setting core params\n");
21394 + }
21395 +
21396 + core_if->hibernation_suspend = 0;
21397 +
21398 + /** ADP initialization */
21399 + dwc_otg_adp_init(core_if);
21400 +
21401 + return core_if;
21402 +}
21403 +
21404 +/**
21405 + * This function frees the structures allocated by dwc_otg_cil_init().
21406 + *
21407 + * @param core_if The core interface pointer returned from
21408 + * dwc_otg_cil_init().
21409 + *
21410 + */
21411 +void dwc_otg_cil_remove(dwc_otg_core_if_t * core_if)
21412 +{
21413 + dctl_data_t dctl = {.d32 = 0 };
21414 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
21415 +
21416 + /* Disable all interrupts */
21417 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 1, 0);
21418 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
21419 +
21420 + dctl.b.sftdiscon = 1;
21421 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
21422 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0,
21423 + dctl.d32);
21424 + }
21425 +
21426 + if (core_if->wq_otg) {
21427 + DWC_WORKQ_WAIT_WORK_DONE(core_if->wq_otg, 500);
21428 + DWC_WORKQ_FREE(core_if->wq_otg);
21429 + }
21430 + if (core_if->dev_if) {
21431 + DWC_FREE(core_if->dev_if);
21432 + }
21433 + if (core_if->host_if) {
21434 + DWC_FREE(core_if->host_if);
21435 + }
21436 +
21437 + /** Remove ADP Stuff */
21438 + dwc_otg_adp_remove(core_if);
21439 + if (core_if->core_params) {
21440 + DWC_FREE(core_if->core_params);
21441 + }
21442 + if (core_if->wkp_timer) {
21443 + DWC_TIMER_FREE(core_if->wkp_timer);
21444 + }
21445 + if (core_if->srp_timer) {
21446 + DWC_TIMER_FREE(core_if->srp_timer);
21447 + }
21448 + DWC_FREE(core_if);
21449 +}
21450 +
21451 +/**
21452 + * This function enables the controller's Global Interrupt in the AHB Config
21453 + * register.
21454 + *
21455 + * @param core_if Programming view of DWC_otg controller.
21456 + */
21457 +void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * core_if)
21458 +{
21459 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
21460 + ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */
21461 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32);
21462 +}
21463 +
21464 +/**
21465 + * This function disables the controller's Global Interrupt in the AHB Config
21466 + * register.
21467 + *
21468 + * @param core_if Programming view of DWC_otg controller.
21469 + */
21470 +void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * core_if)
21471 +{
21472 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
21473 + ahbcfg.b.glblintrmsk = 1; /* Disable interrupts */
21474 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
21475 +}
21476 +
21477 +/**
21478 + * This function initializes the commmon interrupts, used in both
21479 + * device and host modes.
21480 + *
21481 + * @param core_if Programming view of the DWC_otg controller
21482 + *
21483 + */
21484 +static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t * core_if)
21485 +{
21486 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
21487 + gintmsk_data_t intr_mask = {.d32 = 0 };
21488 +
21489 + /* Clear any pending OTG Interrupts */
21490 + DWC_WRITE_REG32(&global_regs->gotgint, 0xFFFFFFFF);
21491 +
21492 + /* Clear any pending interrupts */
21493 + DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
21494 +
21495 + /*
21496 + * Enable the interrupts in the GINTMSK.
21497 + */
21498 + intr_mask.b.modemismatch = 1;
21499 + intr_mask.b.otgintr = 1;
21500 +
21501 + if (!core_if->dma_enable) {
21502 + intr_mask.b.rxstsqlvl = 1;
21503 + }
21504 +
21505 + intr_mask.b.conidstschng = 1;
21506 + intr_mask.b.wkupintr = 1;
21507 + intr_mask.b.disconnect = 0;
21508 + intr_mask.b.usbsuspend = 1;
21509 + intr_mask.b.sessreqintr = 1;
21510 +#ifdef CONFIG_USB_DWC_OTG_LPM
21511 + if (core_if->core_params->lpm_enable) {
21512 + intr_mask.b.lpmtranrcvd = 1;
21513 + }
21514 +#endif
21515 + DWC_WRITE_REG32(&global_regs->gintmsk, intr_mask.d32);
21516 +}
21517 +
21518 +/*
21519 + * The restore operation is modified to support Synopsys Emulated Powerdown and
21520 + * Hibernation. This function is for exiting from Device mode hibernation by
21521 + * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
21522 + * @param core_if Programming view of DWC_otg controller.
21523 + * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
21524 + * @param reset - indicates whether resume is initiated by Reset.
21525 + */
21526 +int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
21527 + int rem_wakeup, int reset)
21528 +{
21529 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
21530 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
21531 + dctl_data_t dctl = {.d32 = 0 };
21532 +
21533 + int timeout = 2000;
21534 +
21535 + if (!core_if->hibernation_suspend) {
21536 + DWC_PRINTF("Already exited from Hibernation\n");
21537 + return 1;
21538 + }
21539 +
21540 + DWC_DEBUGPL(DBG_PCD, "%s called\n", __FUNCTION__);
21541 + /* Switch-on voltage to the core */
21542 + gpwrdn.b.pwrdnswtch = 1;
21543 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21544 + dwc_udelay(10);
21545 +
21546 + /* Reset core */
21547 + gpwrdn.d32 = 0;
21548 + gpwrdn.b.pwrdnrstn = 1;
21549 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21550 + dwc_udelay(10);
21551 +
21552 + /* Assert Restore signal */
21553 + gpwrdn.d32 = 0;
21554 + gpwrdn.b.restore = 1;
21555 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21556 + dwc_udelay(10);
21557 +
21558 + /* Disable power clamps */
21559 + gpwrdn.d32 = 0;
21560 + gpwrdn.b.pwrdnclmp = 1;
21561 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21562 +
21563 + if (rem_wakeup) {
21564 + dwc_udelay(70);
21565 + }
21566 +
21567 + /* Deassert Reset core */
21568 + gpwrdn.d32 = 0;
21569 + gpwrdn.b.pwrdnrstn = 1;
21570 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21571 + dwc_udelay(10);
21572 +
21573 + /* Disable PMU interrupt */
21574 + gpwrdn.d32 = 0;
21575 + gpwrdn.b.pmuintsel = 1;
21576 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21577 +
21578 + /* Mask interrupts from gpwrdn */
21579 + gpwrdn.d32 = 0;
21580 + gpwrdn.b.connect_det_msk = 1;
21581 + gpwrdn.b.srp_det_msk = 1;
21582 + gpwrdn.b.disconn_det_msk = 1;
21583 + gpwrdn.b.rst_det_msk = 1;
21584 + gpwrdn.b.lnstchng_msk = 1;
21585 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21586 +
21587 + /* Indicates that we are going out from hibernation */
21588 + core_if->hibernation_suspend = 0;
21589 +
21590 + /*
21591 + * Set Restore Essential Regs bit in PCGCCTL register, restore_mode = 1
21592 + * indicates restore from remote_wakeup
21593 + */
21594 + restore_essential_regs(core_if, rem_wakeup, 0);
21595 +
21596 + /*
21597 + * Wait a little for seeing new value of variable hibernation_suspend if
21598 + * Restore done interrupt received before polling
21599 + */
21600 + dwc_udelay(10);
21601 +
21602 + if (core_if->hibernation_suspend == 0) {
21603 + /*
21604 + * Wait For Restore_done Interrupt. This mechanism of polling the
21605 + * interrupt is introduced to avoid any possible race conditions
21606 + */
21607 + do {
21608 + gintsts_data_t gintsts;
21609 + gintsts.d32 =
21610 + DWC_READ_REG32(&core_if->core_global_regs->gintsts);
21611 + if (gintsts.b.restoredone) {
21612 + gintsts.d32 = 0;
21613 + gintsts.b.restoredone = 1;
21614 + DWC_WRITE_REG32(&core_if->core_global_regs->
21615 + gintsts, gintsts.d32);
21616 + DWC_PRINTF("Restore Done Interrupt seen\n");
21617 + break;
21618 + }
21619 + dwc_udelay(10);
21620 + } while (--timeout);
21621 + if (!timeout) {
21622 + DWC_PRINTF("Restore Done interrupt wasn't generated here\n");
21623 + }
21624 + }
21625 + /* Clear all pending interupts */
21626 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21627 +
21628 + /* De-assert Restore */
21629 + gpwrdn.d32 = 0;
21630 + gpwrdn.b.restore = 1;
21631 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21632 + dwc_udelay(10);
21633 +
21634 + if (!rem_wakeup) {
21635 + pcgcctl.d32 = 0;
21636 + pcgcctl.b.rstpdwnmodule = 1;
21637 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
21638 + }
21639 +
21640 + /* Restore GUSBCFG and DCFG */
21641 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
21642 + core_if->gr_backup->gusbcfg_local);
21643 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
21644 + core_if->dr_backup->dcfg);
21645 +
21646 + /* De-assert Wakeup Logic */
21647 + gpwrdn.d32 = 0;
21648 + gpwrdn.b.pmuactv = 1;
21649 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21650 + dwc_udelay(10);
21651 +
21652 + if (!rem_wakeup) {
21653 + /* Set Device programming done bit */
21654 + dctl.b.pwronprgdone = 1;
21655 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
21656 + } else {
21657 + /* Start Remote Wakeup Signaling */
21658 + dctl.d32 = core_if->dr_backup->dctl;
21659 + dctl.b.rmtwkupsig = 1;
21660 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
21661 + }
21662 +
21663 + dwc_mdelay(2);
21664 + /* Clear all pending interupts */
21665 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21666 +
21667 + /* Restore global registers */
21668 + dwc_otg_restore_global_regs(core_if);
21669 + /* Restore device global registers */
21670 + dwc_otg_restore_dev_regs(core_if, rem_wakeup);
21671 +
21672 + if (rem_wakeup) {
21673 + dwc_mdelay(7);
21674 + dctl.d32 = 0;
21675 + dctl.b.rmtwkupsig = 1;
21676 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
21677 + }
21678 +
21679 + core_if->hibernation_suspend = 0;
21680 + /* The core will be in ON STATE */
21681 + core_if->lx_state = DWC_OTG_L0;
21682 + DWC_PRINTF("Hibernation recovery completes here\n");
21683 +
21684 + return 1;
21685 +}
21686 +
21687 +/*
21688 + * The restore operation is modified to support Synopsys Emulated Powerdown and
21689 + * Hibernation. This function is for exiting from Host mode hibernation by
21690 + * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
21691 + * @param core_if Programming view of DWC_otg controller.
21692 + * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
21693 + * @param reset - indicates whether resume is initiated by Reset.
21694 + */
21695 +int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
21696 + int rem_wakeup, int reset)
21697 +{
21698 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
21699 + hprt0_data_t hprt0 = {.d32 = 0 };
21700 +
21701 + int timeout = 2000;
21702 +
21703 + DWC_DEBUGPL(DBG_HCD, "%s called\n", __FUNCTION__);
21704 + /* Switch-on voltage to the core */
21705 + gpwrdn.b.pwrdnswtch = 1;
21706 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21707 + dwc_udelay(10);
21708 +
21709 + /* Reset core */
21710 + gpwrdn.d32 = 0;
21711 + gpwrdn.b.pwrdnrstn = 1;
21712 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21713 + dwc_udelay(10);
21714 +
21715 + /* Assert Restore signal */
21716 + gpwrdn.d32 = 0;
21717 + gpwrdn.b.restore = 1;
21718 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21719 + dwc_udelay(10);
21720 +
21721 + /* Disable power clamps */
21722 + gpwrdn.d32 = 0;
21723 + gpwrdn.b.pwrdnclmp = 1;
21724 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21725 +
21726 + if (!rem_wakeup) {
21727 + dwc_udelay(50);
21728 + }
21729 +
21730 + /* Deassert Reset core */
21731 + gpwrdn.d32 = 0;
21732 + gpwrdn.b.pwrdnrstn = 1;
21733 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21734 + dwc_udelay(10);
21735 +
21736 + /* Disable PMU interrupt */
21737 + gpwrdn.d32 = 0;
21738 + gpwrdn.b.pmuintsel = 1;
21739 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21740 +
21741 + gpwrdn.d32 = 0;
21742 + gpwrdn.b.connect_det_msk = 1;
21743 + gpwrdn.b.srp_det_msk = 1;
21744 + gpwrdn.b.disconn_det_msk = 1;
21745 + gpwrdn.b.rst_det_msk = 1;
21746 + gpwrdn.b.lnstchng_msk = 1;
21747 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21748 +
21749 + /* Indicates that we are going out from hibernation */
21750 + core_if->hibernation_suspend = 0;
21751 +
21752 + /* Set Restore Essential Regs bit in PCGCCTL register */
21753 + restore_essential_regs(core_if, rem_wakeup, 1);
21754 +
21755 + /* Wait a little for seeing new value of variable hibernation_suspend if
21756 + * Restore done interrupt received before polling */
21757 + dwc_udelay(10);
21758 +
21759 + if (core_if->hibernation_suspend == 0) {
21760 + /* Wait For Restore_done Interrupt. This mechanism of polling the
21761 + * interrupt is introduced to avoid any possible race conditions
21762 + */
21763 + do {
21764 + gintsts_data_t gintsts;
21765 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
21766 + if (gintsts.b.restoredone) {
21767 + gintsts.d32 = 0;
21768 + gintsts.b.restoredone = 1;
21769 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
21770 + DWC_DEBUGPL(DBG_HCD,"Restore Done Interrupt seen\n");
21771 + break;
21772 + }
21773 + dwc_udelay(10);
21774 + } while (--timeout);
21775 + if (!timeout) {
21776 + DWC_WARN("Restore Done interrupt wasn't generated\n");
21777 + }
21778 + }
21779 +
21780 + /* Set the flag's value to 0 again after receiving restore done interrupt */
21781 + core_if->hibernation_suspend = 0;
21782 +
21783 + /* This step is not described in functional spec but if not wait for this
21784 + * delay, mismatch interrupts occurred because just after restore core is
21785 + * in Device mode(gintsts.curmode == 0) */
21786 + dwc_mdelay(100);
21787 +
21788 + /* Clear all pending interrupts */
21789 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21790 +
21791 + /* De-assert Restore */
21792 + gpwrdn.d32 = 0;
21793 + gpwrdn.b.restore = 1;
21794 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21795 + dwc_udelay(10);
21796 +
21797 + /* Restore GUSBCFG and HCFG */
21798 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
21799 + core_if->gr_backup->gusbcfg_local);
21800 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
21801 + core_if->hr_backup->hcfg_local);
21802 +
21803 + /* De-assert Wakeup Logic */
21804 + gpwrdn.d32 = 0;
21805 + gpwrdn.b.pmuactv = 1;
21806 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21807 + dwc_udelay(10);
21808 +
21809 + /* Start the Resume operation by programming HPRT0 */
21810 + hprt0.d32 = core_if->hr_backup->hprt0_local;
21811 + hprt0.b.prtpwr = 1;
21812 + hprt0.b.prtena = 0;
21813 + hprt0.b.prtsusp = 0;
21814 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21815 +
21816 + DWC_PRINTF("Resume Starts Now\n");
21817 + if (!reset) { // Indicates it is Resume Operation
21818 + hprt0.d32 = core_if->hr_backup->hprt0_local;
21819 + hprt0.b.prtres = 1;
21820 + hprt0.b.prtpwr = 1;
21821 + hprt0.b.prtena = 0;
21822 + hprt0.b.prtsusp = 0;
21823 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21824 +
21825 + if (!rem_wakeup)
21826 + hprt0.b.prtres = 0;
21827 + /* Wait for Resume time and then program HPRT again */
21828 + dwc_mdelay(100);
21829 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21830 +
21831 + } else { // Indicates it is Reset Operation
21832 + hprt0.d32 = core_if->hr_backup->hprt0_local;
21833 + hprt0.b.prtrst = 1;
21834 + hprt0.b.prtpwr = 1;
21835 + hprt0.b.prtena = 0;
21836 + hprt0.b.prtsusp = 0;
21837 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21838 + /* Wait for Reset time and then program HPRT again */
21839 + dwc_mdelay(60);
21840 + hprt0.b.prtrst = 0;
21841 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21842 + }
21843 + /* Clear all interrupt status */
21844 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
21845 + hprt0.b.prtconndet = 1;
21846 + hprt0.b.prtenchng = 1;
21847 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21848 +
21849 + /* Clear all pending interupts */
21850 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21851 +
21852 + /* Restore global registers */
21853 + dwc_otg_restore_global_regs(core_if);
21854 + /* Restore host global registers */
21855 + dwc_otg_restore_host_regs(core_if, reset);
21856 +
21857 + /* The core will be in ON STATE */
21858 + core_if->lx_state = DWC_OTG_L0;
21859 + DWC_PRINTF("Hibernation recovery is complete here\n");
21860 + return 0;
21861 +}
21862 +
21863 +/** Saves some register values into system memory. */
21864 +int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if)
21865 +{
21866 + struct dwc_otg_global_regs_backup *gr;
21867 + int i;
21868 +
21869 + gr = core_if->gr_backup;
21870 + if (!gr) {
21871 + gr = DWC_ALLOC(sizeof(*gr));
21872 + if (!gr) {
21873 + return -DWC_E_NO_MEMORY;
21874 + }
21875 + core_if->gr_backup = gr;
21876 + }
21877 +
21878 + gr->gotgctl_local = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
21879 + gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
21880 + gr->gahbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
21881 + gr->gusbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
21882 + gr->grxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
21883 + gr->gnptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
21884 + gr->hptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
21885 +#ifdef CONFIG_USB_DWC_OTG_LPM
21886 + gr->glpmcfg_local = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
21887 +#endif
21888 + gr->gi2cctl_local = DWC_READ_REG32(&core_if->core_global_regs->gi2cctl);
21889 + gr->pcgcctl_local = DWC_READ_REG32(core_if->pcgcctl);
21890 + gr->gdfifocfg_local =
21891 + DWC_READ_REG32(&core_if->core_global_regs->gdfifocfg);
21892 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21893 + gr->dtxfsiz_local[i] =
21894 + DWC_READ_REG32(&(core_if->core_global_regs->dtxfsiz[i]));
21895 + }
21896 +
21897 + DWC_DEBUGPL(DBG_ANY, "===========Backing Global registers==========\n");
21898 + DWC_DEBUGPL(DBG_ANY, "Backed up gotgctl = %08x\n", gr->gotgctl_local);
21899 + DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk = %08x\n", gr->gintmsk_local);
21900 + DWC_DEBUGPL(DBG_ANY, "Backed up gahbcfg = %08x\n", gr->gahbcfg_local);
21901 + DWC_DEBUGPL(DBG_ANY, "Backed up gusbcfg = %08x\n", gr->gusbcfg_local);
21902 + DWC_DEBUGPL(DBG_ANY, "Backed up grxfsiz = %08x\n", gr->grxfsiz_local);
21903 + DWC_DEBUGPL(DBG_ANY, "Backed up gnptxfsiz = %08x\n",
21904 + gr->gnptxfsiz_local);
21905 + DWC_DEBUGPL(DBG_ANY, "Backed up hptxfsiz = %08x\n",
21906 + gr->hptxfsiz_local);
21907 +#ifdef CONFIG_USB_DWC_OTG_LPM
21908 + DWC_DEBUGPL(DBG_ANY, "Backed up glpmcfg = %08x\n", gr->glpmcfg_local);
21909 +#endif
21910 + DWC_DEBUGPL(DBG_ANY, "Backed up gi2cctl = %08x\n", gr->gi2cctl_local);
21911 + DWC_DEBUGPL(DBG_ANY, "Backed up pcgcctl = %08x\n", gr->pcgcctl_local);
21912 + DWC_DEBUGPL(DBG_ANY,"Backed up gdfifocfg = %08x\n",gr->gdfifocfg_local);
21913 +
21914 + return 0;
21915 +}
21916 +
21917 +/** Saves GINTMSK register before setting the msk bits. */
21918 +int dwc_otg_save_gintmsk_reg(dwc_otg_core_if_t * core_if)
21919 +{
21920 + struct dwc_otg_global_regs_backup *gr;
21921 +
21922 + gr = core_if->gr_backup;
21923 + if (!gr) {
21924 + gr = DWC_ALLOC(sizeof(*gr));
21925 + if (!gr) {
21926 + return -DWC_E_NO_MEMORY;
21927 + }
21928 + core_if->gr_backup = gr;
21929 + }
21930 +
21931 + gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
21932 +
21933 + DWC_DEBUGPL(DBG_ANY,"=============Backing GINTMSK registers============\n");
21934 + DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk = %08x\n", gr->gintmsk_local);
21935 +
21936 + return 0;
21937 +}
21938 +
21939 +int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if)
21940 +{
21941 + struct dwc_otg_dev_regs_backup *dr;
21942 + int i;
21943 +
21944 + dr = core_if->dr_backup;
21945 + if (!dr) {
21946 + dr = DWC_ALLOC(sizeof(*dr));
21947 + if (!dr) {
21948 + return -DWC_E_NO_MEMORY;
21949 + }
21950 + core_if->dr_backup = dr;
21951 + }
21952 +
21953 + dr->dcfg = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
21954 + dr->dctl = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
21955 + dr->daintmsk =
21956 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
21957 + dr->diepmsk =
21958 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->diepmsk);
21959 + dr->doepmsk =
21960 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->doepmsk);
21961 +
21962 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
21963 + dr->diepctl[i] =
21964 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
21965 + dr->dieptsiz[i] =
21966 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz);
21967 + dr->diepdma[i] =
21968 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma);
21969 + }
21970 +
21971 + DWC_DEBUGPL(DBG_ANY,
21972 + "=============Backing Host registers==============\n");
21973 + DWC_DEBUGPL(DBG_ANY, "Backed up dcfg = %08x\n", dr->dcfg);
21974 + DWC_DEBUGPL(DBG_ANY, "Backed up dctl = %08x\n", dr->dctl);
21975 + DWC_DEBUGPL(DBG_ANY, "Backed up daintmsk = %08x\n",
21976 + dr->daintmsk);
21977 + DWC_DEBUGPL(DBG_ANY, "Backed up diepmsk = %08x\n", dr->diepmsk);
21978 + DWC_DEBUGPL(DBG_ANY, "Backed up doepmsk = %08x\n", dr->doepmsk);
21979 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
21980 + DWC_DEBUGPL(DBG_ANY, "Backed up diepctl[%d] = %08x\n", i,
21981 + dr->diepctl[i]);
21982 + DWC_DEBUGPL(DBG_ANY, "Backed up dieptsiz[%d] = %08x\n",
21983 + i, dr->dieptsiz[i]);
21984 + DWC_DEBUGPL(DBG_ANY, "Backed up diepdma[%d] = %08x\n", i,
21985 + dr->diepdma[i]);
21986 + }
21987 +
21988 + return 0;
21989 +}
21990 +
21991 +int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if)
21992 +{
21993 + struct dwc_otg_host_regs_backup *hr;
21994 + int i;
21995 +
21996 + hr = core_if->hr_backup;
21997 + if (!hr) {
21998 + hr = DWC_ALLOC(sizeof(*hr));
21999 + if (!hr) {
22000 + return -DWC_E_NO_MEMORY;
22001 + }
22002 + core_if->hr_backup = hr;
22003 + }
22004 +
22005 + hr->hcfg_local =
22006 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
22007 + hr->haintmsk_local =
22008 + DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk);
22009 + for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
22010 + hr->hcintmsk_local[i] =
22011 + DWC_READ_REG32(&core_if->host_if->hc_regs[i]->hcintmsk);
22012 + }
22013 + hr->hprt0_local = DWC_READ_REG32(core_if->host_if->hprt0);
22014 + hr->hfir_local =
22015 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
22016 +
22017 + DWC_DEBUGPL(DBG_ANY,
22018 + "=============Backing Host registers===============\n");
22019 + DWC_DEBUGPL(DBG_ANY, "Backed up hcfg = %08x\n",
22020 + hr->hcfg_local);
22021 + DWC_DEBUGPL(DBG_ANY, "Backed up haintmsk = %08x\n", hr->haintmsk_local);
22022 + for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
22023 + DWC_DEBUGPL(DBG_ANY, "Backed up hcintmsk[%02d]=%08x\n", i,
22024 + hr->hcintmsk_local[i]);
22025 + }
22026 + DWC_DEBUGPL(DBG_ANY, "Backed up hprt0 = %08x\n",
22027 + hr->hprt0_local);
22028 + DWC_DEBUGPL(DBG_ANY, "Backed up hfir = %08x\n",
22029 + hr->hfir_local);
22030 +
22031 + return 0;
22032 +}
22033 +
22034 +int dwc_otg_restore_global_regs(dwc_otg_core_if_t *core_if)
22035 +{
22036 + struct dwc_otg_global_regs_backup *gr;
22037 + int i;
22038 +
22039 + gr = core_if->gr_backup;
22040 + if (!gr) {
22041 + return -DWC_E_INVALID;
22042 + }
22043 +
22044 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, gr->gotgctl_local);
22045 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gr->gintmsk_local);
22046 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gr->gusbcfg_local);
22047 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gr->gahbcfg_local);
22048 + DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, gr->grxfsiz_local);
22049 + DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz,
22050 + gr->gnptxfsiz_local);
22051 + DWC_WRITE_REG32(&core_if->core_global_regs->hptxfsiz,
22052 + gr->hptxfsiz_local);
22053 + DWC_WRITE_REG32(&core_if->core_global_regs->gdfifocfg,
22054 + gr->gdfifocfg_local);
22055 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
22056 + DWC_WRITE_REG32(&core_if->core_global_regs->dtxfsiz[i],
22057 + gr->dtxfsiz_local[i]);
22058 + }
22059 +
22060 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
22061 + DWC_WRITE_REG32(core_if->host_if->hprt0, 0x0000100A);
22062 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg,
22063 + (gr->gahbcfg_local));
22064 + return 0;
22065 +}
22066 +
22067 +int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if, int rem_wakeup)
22068 +{
22069 + struct dwc_otg_dev_regs_backup *dr;
22070 + int i;
22071 +
22072 + dr = core_if->dr_backup;
22073 +
22074 + if (!dr) {
22075 + return -DWC_E_INVALID;
22076 + }
22077 +
22078 + if (!rem_wakeup) {
22079 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
22080 + dr->dctl);
22081 + }
22082 +
22083 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, dr->daintmsk);
22084 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, dr->diepmsk);
22085 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, dr->doepmsk);
22086 +
22087 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
22088 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz, dr->dieptsiz[i]);
22089 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma, dr->diepdma[i]);
22090 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl, dr->diepctl[i]);
22091 + }
22092 +
22093 + return 0;
22094 +}
22095 +
22096 +int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset)
22097 +{
22098 + struct dwc_otg_host_regs_backup *hr;
22099 + int i;
22100 + hr = core_if->hr_backup;
22101 +
22102 + if (!hr) {
22103 + return -DWC_E_INVALID;
22104 + }
22105 +
22106 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hr->hcfg_local);
22107 + //if (!reset)
22108 + //{
22109 + // DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hr->hfir_local);
22110 + //}
22111 +
22112 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk,
22113 + hr->haintmsk_local);
22114 + for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
22115 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk,
22116 + hr->hcintmsk_local[i]);
22117 + }
22118 +
22119 + return 0;
22120 +}
22121 +
22122 +int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if)
22123 +{
22124 + struct dwc_otg_global_regs_backup *gr;
22125 +
22126 + gr = core_if->gr_backup;
22127 +
22128 + /* Restore values for LPM and I2C */
22129 +#ifdef CONFIG_USB_DWC_OTG_LPM
22130 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, gr->glpmcfg_local);
22131 +#endif
22132 + DWC_WRITE_REG32(&core_if->core_global_regs->gi2cctl, gr->gi2cctl_local);
22133 +
22134 + return 0;
22135 +}
22136 +
22137 +int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode, int is_host)
22138 +{
22139 + struct dwc_otg_global_regs_backup *gr;
22140 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
22141 + gahbcfg_data_t gahbcfg = {.d32 = 0 };
22142 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
22143 + gintmsk_data_t gintmsk = {.d32 = 0 };
22144 +
22145 + /* Restore LPM and I2C registers */
22146 + restore_lpm_i2c_regs(core_if);
22147 +
22148 + /* Set PCGCCTL to 0 */
22149 + DWC_WRITE_REG32(core_if->pcgcctl, 0x00000000);
22150 +
22151 + gr = core_if->gr_backup;
22152 + /* Load restore values for [31:14] bits */
22153 + DWC_WRITE_REG32(core_if->pcgcctl,
22154 + ((gr->pcgcctl_local & 0xffffc000) | 0x00020000));
22155 +
22156 + /* Umnask global Interrupt in GAHBCFG and restore it */
22157 + gahbcfg.d32 = gr->gahbcfg_local;
22158 + gahbcfg.b.glblintrmsk = 1;
22159 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
22160 +
22161 + /* Clear all pending interupts */
22162 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
22163 +
22164 + /* Unmask restore done interrupt */
22165 + gintmsk.b.restoredone = 1;
22166 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
22167 +
22168 + /* Restore GUSBCFG and HCFG/DCFG */
22169 + gusbcfg.d32 = core_if->gr_backup->gusbcfg_local;
22170 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
22171 +
22172 + if (is_host) {
22173 + hcfg_data_t hcfg = {.d32 = 0 };
22174 + hcfg.d32 = core_if->hr_backup->hcfg_local;
22175 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
22176 + hcfg.d32);
22177 +
22178 + /* Load restore values for [31:14] bits */
22179 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22180 + pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
22181 +
22182 + if (rmode)
22183 + pcgcctl.b.restoremode = 1;
22184 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22185 + dwc_udelay(10);
22186 +
22187 + /* Load restore values for [31:14] bits and set EssRegRestored bit */
22188 + pcgcctl.d32 = gr->pcgcctl_local | 0xffffc000;
22189 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22190 + pcgcctl.b.ess_reg_restored = 1;
22191 + if (rmode)
22192 + pcgcctl.b.restoremode = 1;
22193 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22194 + } else {
22195 + dcfg_data_t dcfg = {.d32 = 0 };
22196 + dcfg.d32 = core_if->dr_backup->dcfg;
22197 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
22198 +
22199 + /* Load restore values for [31:14] bits */
22200 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22201 + pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
22202 + if (!rmode) {
22203 + pcgcctl.d32 |= 0x208;
22204 + }
22205 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22206 + dwc_udelay(10);
22207 +
22208 + /* Load restore values for [31:14] bits */
22209 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22210 + pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
22211 + pcgcctl.b.ess_reg_restored = 1;
22212 + if (!rmode)
22213 + pcgcctl.d32 |= 0x208;
22214 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22215 + }
22216 +
22217 + return 0;
22218 +}
22219 +
22220 +/**
22221 + * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY
22222 + * type.
22223 + */
22224 +static void init_fslspclksel(dwc_otg_core_if_t * core_if)
22225 +{
22226 + uint32_t val;
22227 + hcfg_data_t hcfg;
22228 +
22229 + if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
22230 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
22231 + (core_if->core_params->ulpi_fs_ls)) ||
22232 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
22233 + /* Full speed PHY */
22234 + val = DWC_HCFG_48_MHZ;
22235 + } else {
22236 + /* High speed PHY running at full speed or high speed */
22237 + val = DWC_HCFG_30_60_MHZ;
22238 + }
22239 +
22240 + DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val);
22241 + hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
22242 + hcfg.b.fslspclksel = val;
22243 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
22244 +}
22245 +
22246 +/**
22247 + * Initializes the DevSpd field of the DCFG register depending on the PHY type
22248 + * and the enumeration speed of the device.
22249 + */
22250 +static void init_devspd(dwc_otg_core_if_t * core_if)
22251 +{
22252 + uint32_t val;
22253 + dcfg_data_t dcfg;
22254 +
22255 + if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
22256 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
22257 + (core_if->core_params->ulpi_fs_ls)) ||
22258 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
22259 + /* Full speed PHY */
22260 + val = 0x3;
22261 + } else if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
22262 + /* High speed PHY running at full speed */
22263 + val = 0x1;
22264 + } else {
22265 + /* High speed PHY running at high speed */
22266 + val = 0x0;
22267 + }
22268 +
22269 + DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val);
22270 +
22271 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
22272 + dcfg.b.devspd = val;
22273 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
22274 +}
22275 +
22276 +/**
22277 + * This function calculates the number of IN EPS
22278 + * using GHWCFG1 and GHWCFG2 registers values
22279 + *
22280 + * @param core_if Programming view of the DWC_otg controller
22281 + */
22282 +static uint32_t calc_num_in_eps(dwc_otg_core_if_t * core_if)
22283 +{
22284 + uint32_t num_in_eps = 0;
22285 + uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
22286 + uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 3;
22287 + uint32_t num_tx_fifos = core_if->hwcfg4.b.num_in_eps;
22288 + int i;
22289 +
22290 + for (i = 0; i < num_eps; ++i) {
22291 + if (!(hwcfg1 & 0x1))
22292 + num_in_eps++;
22293 +
22294 + hwcfg1 >>= 2;
22295 + }
22296 +
22297 + if (core_if->hwcfg4.b.ded_fifo_en) {
22298 + num_in_eps =
22299 + (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps;
22300 + }
22301 +
22302 + return num_in_eps;
22303 +}
22304 +
22305 +/**
22306 + * This function calculates the number of OUT EPS
22307 + * using GHWCFG1 and GHWCFG2 registers values
22308 + *
22309 + * @param core_if Programming view of the DWC_otg controller
22310 + */
22311 +static uint32_t calc_num_out_eps(dwc_otg_core_if_t * core_if)
22312 +{
22313 + uint32_t num_out_eps = 0;
22314 + uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
22315 + uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 2;
22316 + int i;
22317 +
22318 + for (i = 0; i < num_eps; ++i) {
22319 + if (!(hwcfg1 & 0x1))
22320 + num_out_eps++;
22321 +
22322 + hwcfg1 >>= 2;
22323 + }
22324 + return num_out_eps;
22325 +}
22326 +
22327 +/**
22328 + * This function initializes the DWC_otg controller registers and
22329 + * prepares the core for device mode or host mode operation.
22330 + *
22331 + * @param core_if Programming view of the DWC_otg controller
22332 + *
22333 + */
22334 +void dwc_otg_core_init(dwc_otg_core_if_t * core_if)
22335 +{
22336 + int i = 0;
22337 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22338 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
22339 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
22340 + gusbcfg_data_t usbcfg = {.d32 = 0 };
22341 + gi2cctl_data_t i2cctl = {.d32 = 0 };
22342 +
22343 + DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p) regs at %p\n",
22344 + core_if, global_regs);
22345 +
22346 + /* Common Initialization */
22347 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22348 +
22349 + /* Program the ULPI External VBUS bit if needed */
22350 + usbcfg.b.ulpi_ext_vbus_drv =
22351 + (core_if->core_params->phy_ulpi_ext_vbus ==
22352 + DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0;
22353 +
22354 + /* Set external TS Dline pulsing */
22355 + usbcfg.b.term_sel_dl_pulse =
22356 + (core_if->core_params->ts_dline == 1) ? 1 : 0;
22357 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22358 +
22359 + /* Reset the Controller */
22360 + dwc_otg_core_reset(core_if);
22361 +
22362 + core_if->adp_enable = core_if->core_params->adp_supp_enable;
22363 + core_if->power_down = core_if->core_params->power_down;
22364 + core_if->otg_sts = 0;
22365 +
22366 + /* Initialize parameters from Hardware configuration registers. */
22367 + dev_if->num_in_eps = calc_num_in_eps(core_if);
22368 + dev_if->num_out_eps = calc_num_out_eps(core_if);
22369 +
22370 + DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",
22371 + core_if->hwcfg4.b.num_dev_perio_in_ep);
22372 +
22373 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
22374 + dev_if->perio_tx_fifo_size[i] =
22375 + DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
22376 + DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n",
22377 + i, dev_if->perio_tx_fifo_size[i]);
22378 + }
22379 +
22380 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
22381 + dev_if->tx_fifo_size[i] =
22382 + DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
22383 + DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n",
22384 + i, dev_if->tx_fifo_size[i]);
22385 + }
22386 +
22387 + core_if->total_fifo_size = core_if->hwcfg3.b.dfifo_depth;
22388 + core_if->rx_fifo_size = DWC_READ_REG32(&global_regs->grxfsiz);
22389 + core_if->nperio_tx_fifo_size =
22390 + DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16;
22391 +
22392 + DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", core_if->total_fifo_size);
22393 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", core_if->rx_fifo_size);
22394 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n",
22395 + core_if->nperio_tx_fifo_size);
22396 +
22397 + /* This programming sequence needs to happen in FS mode before any other
22398 + * programming occurs */
22399 + if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) &&
22400 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
22401 + /* If FS mode with FS PHY */
22402 +
22403 + /* core_init() is now called on every switch so only call the
22404 + * following for the first time through. */
22405 + if (!core_if->phy_init_done) {
22406 + core_if->phy_init_done = 1;
22407 + DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n");
22408 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22409 + usbcfg.b.physel = 1;
22410 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22411 +
22412 + /* Reset after a PHY select */
22413 + dwc_otg_core_reset(core_if);
22414 + }
22415 +
22416 + /* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also
22417 + * do this on HNP Dev/Host mode switches (done in dev_init and
22418 + * host_init). */
22419 + if (dwc_otg_is_host_mode(core_if)) {
22420 + init_fslspclksel(core_if);
22421 + } else {
22422 + init_devspd(core_if);
22423 + }
22424 +
22425 + if (core_if->core_params->i2c_enable) {
22426 + DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n");
22427 + /* Program GUSBCFG.OtgUtmifsSel to I2C */
22428 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22429 + usbcfg.b.otgutmifssel = 1;
22430 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22431 +
22432 + /* Program GI2CCTL.I2CEn */
22433 + i2cctl.d32 = DWC_READ_REG32(&global_regs->gi2cctl);
22434 + i2cctl.b.i2cdevaddr = 1;
22435 + i2cctl.b.i2cen = 0;
22436 + DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
22437 + i2cctl.b.i2cen = 1;
22438 + DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
22439 + }
22440 +
22441 + } /* endif speed == DWC_SPEED_PARAM_FULL */
22442 + else {
22443 + /* High speed PHY. */
22444 + if (!core_if->phy_init_done) {
22445 + core_if->phy_init_done = 1;
22446 + /* HS PHY parameters. These parameters are preserved
22447 + * during soft reset so only program the first time. Do
22448 + * a soft reset immediately after setting phyif. */
22449 +
22450 + if (core_if->core_params->phy_type == 2) {
22451 + /* ULPI interface */
22452 + usbcfg.b.ulpi_utmi_sel = 1;
22453 + usbcfg.b.phyif = 0;
22454 + usbcfg.b.ddrsel =
22455 + core_if->core_params->phy_ulpi_ddr;
22456 + } else if (core_if->core_params->phy_type == 1) {
22457 + /* UTMI+ interface */
22458 + usbcfg.b.ulpi_utmi_sel = 0;
22459 + if (core_if->core_params->phy_utmi_width == 16) {
22460 + usbcfg.b.phyif = 1;
22461 +
22462 + } else {
22463 + usbcfg.b.phyif = 0;
22464 + }
22465 + } else {
22466 + DWC_ERROR("FS PHY TYPE\n");
22467 + }
22468 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22469 + /* Reset after setting the PHY parameters */
22470 + dwc_otg_core_reset(core_if);
22471 + }
22472 + }
22473 +
22474 + if ((core_if->hwcfg2.b.hs_phy_type == 2) &&
22475 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
22476 + (core_if->core_params->ulpi_fs_ls)) {
22477 + DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n");
22478 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22479 + usbcfg.b.ulpi_fsls = 1;
22480 + usbcfg.b.ulpi_clk_sus_m = 1;
22481 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22482 + } else {
22483 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22484 + usbcfg.b.ulpi_fsls = 0;
22485 + usbcfg.b.ulpi_clk_sus_m = 0;
22486 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22487 + }
22488 +
22489 + /* Program the GAHBCFG Register. */
22490 + switch (core_if->hwcfg2.b.architecture) {
22491 +
22492 + case DWC_SLAVE_ONLY_ARCH:
22493 + DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n");
22494 + ahbcfg.b.nptxfemplvl_txfemplvl =
22495 + DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
22496 + ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
22497 + core_if->dma_enable = 0;
22498 + core_if->dma_desc_enable = 0;
22499 + break;
22500 +
22501 + case DWC_EXT_DMA_ARCH:
22502 + DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n");
22503 + {
22504 + uint8_t brst_sz = core_if->core_params->dma_burst_size;
22505 + ahbcfg.b.hburstlen = 0;
22506 + while (brst_sz > 1) {
22507 + ahbcfg.b.hburstlen++;
22508 + brst_sz >>= 1;
22509 + }
22510 + }
22511 + core_if->dma_enable = (core_if->core_params->dma_enable != 0);
22512 + core_if->dma_desc_enable =
22513 + (core_if->core_params->dma_desc_enable != 0);
22514 + break;
22515 +
22516 + case DWC_INT_DMA_ARCH:
22517 + DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n");
22518 + /* Old value was DWC_GAHBCFG_INT_DMA_BURST_INCR - done for
22519 + Host mode ISOC in issue fix - vahrama */
22520 + /* Broadcom had altered to (1<<3)|(0<<0) - WRESP=1, max 4 beats */
22521 + ahbcfg.b.hburstlen = (1<<3)|(0<<0);//DWC_GAHBCFG_INT_DMA_BURST_INCR4;
22522 + core_if->dma_enable = (core_if->core_params->dma_enable != 0);
22523 + core_if->dma_desc_enable =
22524 + (core_if->core_params->dma_desc_enable != 0);
22525 + break;
22526 +
22527 + }
22528 + if (core_if->dma_enable) {
22529 + if (core_if->dma_desc_enable) {
22530 + DWC_PRINTF("Using Descriptor DMA mode\n");
22531 + } else {
22532 + DWC_PRINTF("Using Buffer DMA mode\n");
22533 +
22534 + }
22535 + } else {
22536 + DWC_PRINTF("Using Slave mode\n");
22537 + core_if->dma_desc_enable = 0;
22538 + }
22539 +
22540 + if (core_if->core_params->ahb_single) {
22541 + ahbcfg.b.ahbsingle = 1;
22542 + }
22543 +
22544 + ahbcfg.b.dmaenable = core_if->dma_enable;
22545 + DWC_WRITE_REG32(&global_regs->gahbcfg, ahbcfg.d32);
22546 +
22547 + core_if->en_multiple_tx_fifo = core_if->hwcfg4.b.ded_fifo_en;
22548 +
22549 + core_if->pti_enh_enable = core_if->core_params->pti_enable != 0;
22550 + core_if->multiproc_int_enable = core_if->core_params->mpi_enable;
22551 + DWC_PRINTF("Periodic Transfer Interrupt Enhancement - %s\n",
22552 + ((core_if->pti_enh_enable) ? "enabled" : "disabled"));
22553 + DWC_PRINTF("Multiprocessor Interrupt Enhancement - %s\n",
22554 + ((core_if->multiproc_int_enable) ? "enabled" : "disabled"));
22555 +
22556 + /*
22557 + * Program the GUSBCFG register.
22558 + */
22559 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22560 +
22561 + switch (core_if->hwcfg2.b.op_mode) {
22562 + case DWC_MODE_HNP_SRP_CAPABLE:
22563 + usbcfg.b.hnpcap = (core_if->core_params->otg_cap ==
22564 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
22565 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22566 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22567 + break;
22568 +
22569 + case DWC_MODE_SRP_ONLY_CAPABLE:
22570 + usbcfg.b.hnpcap = 0;
22571 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22572 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22573 + break;
22574 +
22575 + case DWC_MODE_NO_HNP_SRP_CAPABLE:
22576 + usbcfg.b.hnpcap = 0;
22577 + usbcfg.b.srpcap = 0;
22578 + break;
22579 +
22580 + case DWC_MODE_SRP_CAPABLE_DEVICE:
22581 + usbcfg.b.hnpcap = 0;
22582 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22583 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22584 + break;
22585 +
22586 + case DWC_MODE_NO_SRP_CAPABLE_DEVICE:
22587 + usbcfg.b.hnpcap = 0;
22588 + usbcfg.b.srpcap = 0;
22589 + break;
22590 +
22591 + case DWC_MODE_SRP_CAPABLE_HOST:
22592 + usbcfg.b.hnpcap = 0;
22593 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22594 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22595 + break;
22596 +
22597 + case DWC_MODE_NO_SRP_CAPABLE_HOST:
22598 + usbcfg.b.hnpcap = 0;
22599 + usbcfg.b.srpcap = 0;
22600 + break;
22601 + }
22602 +
22603 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22604 +
22605 +#ifdef CONFIG_USB_DWC_OTG_LPM
22606 + if (core_if->core_params->lpm_enable) {
22607 + glpmcfg_data_t lpmcfg = {.d32 = 0 };
22608 +
22609 + /* To enable LPM support set lpm_cap_en bit */
22610 + lpmcfg.b.lpm_cap_en = 1;
22611 +
22612 + /* Make AppL1Res ACK */
22613 + lpmcfg.b.appl_resp = 1;
22614 +
22615 + /* Retry 3 times */
22616 + lpmcfg.b.retry_count = 3;
22617 +
22618 + DWC_MODIFY_REG32(&core_if->core_global_regs->glpmcfg,
22619 + 0, lpmcfg.d32);
22620 +
22621 + }
22622 +#endif
22623 + if (core_if->core_params->ic_usb_cap) {
22624 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
22625 + gusbcfg.b.ic_usb_cap = 1;
22626 + DWC_MODIFY_REG32(&core_if->core_global_regs->gusbcfg,
22627 + 0, gusbcfg.d32);
22628 + }
22629 + {
22630 + gotgctl_data_t gotgctl = {.d32 = 0 };
22631 + gotgctl.b.otgver = core_if->core_params->otg_ver;
22632 + DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl, 0,
22633 + gotgctl.d32);
22634 + /* Set OTG version supported */
22635 + core_if->otg_ver = core_if->core_params->otg_ver;
22636 + DWC_PRINTF("OTG VER PARAM: %d, OTG VER FLAG: %d\n",
22637 + core_if->core_params->otg_ver, core_if->otg_ver);
22638 + }
22639 +
22640 +
22641 + /* Enable common interrupts */
22642 + dwc_otg_enable_common_interrupts(core_if);
22643 +
22644 + /* Do device or host intialization based on mode during PCD
22645 + * and HCD initialization */
22646 + if (dwc_otg_is_host_mode(core_if)) {
22647 + DWC_DEBUGPL(DBG_ANY, "Host Mode\n");
22648 + core_if->op_state = A_HOST;
22649 + } else {
22650 + DWC_DEBUGPL(DBG_ANY, "Device Mode\n");
22651 + core_if->op_state = B_PERIPHERAL;
22652 +#ifdef DWC_DEVICE_ONLY
22653 + dwc_otg_core_dev_init(core_if);
22654 +#endif
22655 + }
22656 +}
22657 +
22658 +/**
22659 + * This function enables the Device mode interrupts.
22660 + *
22661 + * @param core_if Programming view of DWC_otg controller
22662 + */
22663 +void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * core_if)
22664 +{
22665 + gintmsk_data_t intr_mask = {.d32 = 0 };
22666 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22667 +
22668 + DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
22669 +
22670 + /* Disable all interrupts. */
22671 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
22672 +
22673 + /* Clear any pending interrupts */
22674 + DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
22675 +
22676 + /* Enable the common interrupts */
22677 + dwc_otg_enable_common_interrupts(core_if);
22678 +
22679 + /* Enable interrupts */
22680 + intr_mask.b.usbreset = 1;
22681 + intr_mask.b.enumdone = 1;
22682 + /* Disable Disconnect interrupt in Device mode */
22683 + intr_mask.b.disconnect = 0;
22684 +
22685 + if (!core_if->multiproc_int_enable) {
22686 + intr_mask.b.inepintr = 1;
22687 + intr_mask.b.outepintr = 1;
22688 + }
22689 +
22690 + intr_mask.b.erlysuspend = 1;
22691 +
22692 + if (core_if->en_multiple_tx_fifo == 0) {
22693 + intr_mask.b.epmismatch = 1;
22694 + }
22695 +
22696 + //intr_mask.b.incomplisoout = 1;
22697 + intr_mask.b.incomplisoin = 1;
22698 +
22699 +/* Enable the ignore frame number for ISOC xfers - MAS */
22700 +/* Disable to support high bandwith ISOC transfers - manukz */
22701 +#if 0
22702 +#ifdef DWC_UTE_PER_IO
22703 + if (core_if->dma_enable) {
22704 + if (core_if->dma_desc_enable) {
22705 + dctl_data_t dctl1 = {.d32 = 0 };
22706 + dctl1.b.ifrmnum = 1;
22707 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
22708 + dctl, 0, dctl1.d32);
22709 + DWC_DEBUG("----Enabled Ignore frame number (0x%08x)",
22710 + DWC_READ_REG32(&core_if->dev_if->
22711 + dev_global_regs->dctl));
22712 + }
22713 + }
22714 +#endif
22715 +#endif
22716 +#ifdef DWC_EN_ISOC
22717 + if (core_if->dma_enable) {
22718 + if (core_if->dma_desc_enable == 0) {
22719 + if (core_if->pti_enh_enable) {
22720 + dctl_data_t dctl = {.d32 = 0 };
22721 + dctl.b.ifrmnum = 1;
22722 + DWC_MODIFY_REG32(&core_if->
22723 + dev_if->dev_global_regs->dctl,
22724 + 0, dctl.d32);
22725 + } else {
22726 + intr_mask.b.incomplisoin = 1;
22727 + intr_mask.b.incomplisoout = 1;
22728 + }
22729 + }
22730 + } else {
22731 + intr_mask.b.incomplisoin = 1;
22732 + intr_mask.b.incomplisoout = 1;
22733 + }
22734 +#endif /* DWC_EN_ISOC */
22735 +
22736 + /** @todo NGS: Should this be a module parameter? */
22737 +#ifdef USE_PERIODIC_EP
22738 + intr_mask.b.isooutdrop = 1;
22739 + intr_mask.b.eopframe = 1;
22740 + intr_mask.b.incomplisoin = 1;
22741 + intr_mask.b.incomplisoout = 1;
22742 +#endif
22743 +
22744 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
22745 +
22746 + DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__,
22747 + DWC_READ_REG32(&global_regs->gintmsk));
22748 +}
22749 +
22750 +/**
22751 + * This function initializes the DWC_otg controller registers for
22752 + * device mode.
22753 + *
22754 + * @param core_if Programming view of DWC_otg controller
22755 + *
22756 + */
22757 +void dwc_otg_core_dev_init(dwc_otg_core_if_t * core_if)
22758 +{
22759 + int i;
22760 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22761 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
22762 + dwc_otg_core_params_t *params = core_if->core_params;
22763 + dcfg_data_t dcfg = {.d32 = 0 };
22764 + depctl_data_t diepctl = {.d32 = 0 };
22765 + grstctl_t resetctl = {.d32 = 0 };
22766 + uint32_t rx_fifo_size;
22767 + fifosize_data_t nptxfifosize;
22768 + fifosize_data_t txfifosize;
22769 + dthrctl_data_t dthrctl;
22770 + fifosize_data_t ptxfifosize;
22771 + uint16_t rxfsiz, nptxfsiz;
22772 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
22773 + hwcfg3_data_t hwcfg3 = {.d32 = 0 };
22774 +
22775 + /* Restart the Phy Clock */
22776 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
22777 +
22778 + /* Device configuration register */
22779 + init_devspd(core_if);
22780 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
22781 + dcfg.b.descdma = (core_if->dma_desc_enable) ? 1 : 0;
22782 + dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80;
22783 + /* Enable Device OUT NAK in case of DDMA mode*/
22784 + if (core_if->core_params->dev_out_nak) {
22785 + dcfg.b.endevoutnak = 1;
22786 + }
22787 +
22788 + if (core_if->core_params->cont_on_bna) {
22789 + dctl_data_t dctl = {.d32 = 0 };
22790 + dctl.b.encontonbna = 1;
22791 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
22792 + }
22793 +
22794 +
22795 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
22796 +
22797 + /* Configure data FIFO sizes */
22798 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
22799 + DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
22800 + core_if->total_fifo_size);
22801 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
22802 + params->dev_rx_fifo_size);
22803 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
22804 + params->dev_nperio_tx_fifo_size);
22805 +
22806 + /* Rx FIFO */
22807 + DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
22808 + DWC_READ_REG32(&global_regs->grxfsiz));
22809 +
22810 +#ifdef DWC_UTE_CFI
22811 + core_if->pwron_rxfsiz = DWC_READ_REG32(&global_regs->grxfsiz);
22812 + core_if->init_rxfsiz = params->dev_rx_fifo_size;
22813 +#endif
22814 + rx_fifo_size = params->dev_rx_fifo_size;
22815 + DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
22816 +
22817 + DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
22818 + DWC_READ_REG32(&global_regs->grxfsiz));
22819 +
22820 + /** Set Periodic Tx FIFO Mask all bits 0 */
22821 + core_if->p_tx_msk = 0;
22822 +
22823 + /** Set Tx FIFO Mask all bits 0 */
22824 + core_if->tx_msk = 0;
22825 +
22826 + if (core_if->en_multiple_tx_fifo == 0) {
22827 + /* Non-periodic Tx FIFO */
22828 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
22829 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22830 +
22831 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
22832 + nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
22833 +
22834 + DWC_WRITE_REG32(&global_regs->gnptxfsiz,
22835 + nptxfifosize.d32);
22836 +
22837 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
22838 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22839 +
22840 + /**@todo NGS: Fix Periodic FIFO Sizing! */
22841 + /*
22842 + * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15.
22843 + * Indexes of the FIFO size module parameters in the
22844 + * dev_perio_tx_fifo_size array and the FIFO size registers in
22845 + * the dptxfsiz array run from 0 to 14.
22846 + */
22847 + /** @todo Finish debug of this */
22848 + ptxfifosize.b.startaddr =
22849 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
22850 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
22851 + ptxfifosize.b.depth =
22852 + params->dev_perio_tx_fifo_size[i];
22853 + DWC_DEBUGPL(DBG_CIL,
22854 + "initial dtxfsiz[%d]=%08x\n", i,
22855 + DWC_READ_REG32(&global_regs->dtxfsiz
22856 + [i]));
22857 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
22858 + ptxfifosize.d32);
22859 + DWC_DEBUGPL(DBG_CIL, "new dtxfsiz[%d]=%08x\n",
22860 + i,
22861 + DWC_READ_REG32(&global_regs->dtxfsiz
22862 + [i]));
22863 + ptxfifosize.b.startaddr += ptxfifosize.b.depth;
22864 + }
22865 + } else {
22866 + /*
22867 + * Tx FIFOs These FIFOs are numbered from 1 to 15.
22868 + * Indexes of the FIFO size module parameters in the
22869 + * dev_tx_fifo_size array and the FIFO size registers in
22870 + * the dtxfsiz array run from 0 to 14.
22871 + */
22872 +
22873 + /* Non-periodic Tx FIFO */
22874 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
22875 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22876 +
22877 +#ifdef DWC_UTE_CFI
22878 + core_if->pwron_gnptxfsiz =
22879 + (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
22880 + core_if->init_gnptxfsiz =
22881 + params->dev_nperio_tx_fifo_size;
22882 +#endif
22883 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
22884 + nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
22885 +
22886 + DWC_WRITE_REG32(&global_regs->gnptxfsiz,
22887 + nptxfifosize.d32);
22888 +
22889 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
22890 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22891 +
22892 + txfifosize.b.startaddr =
22893 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
22894 +
22895 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
22896 +
22897 + txfifosize.b.depth =
22898 + params->dev_tx_fifo_size[i];
22899 +
22900 + DWC_DEBUGPL(DBG_CIL,
22901 + "initial dtxfsiz[%d]=%08x\n",
22902 + i,
22903 + DWC_READ_REG32(&global_regs->dtxfsiz
22904 + [i]));
22905 +
22906 +#ifdef DWC_UTE_CFI
22907 + core_if->pwron_txfsiz[i] =
22908 + (DWC_READ_REG32
22909 + (&global_regs->dtxfsiz[i]) >> 16);
22910 + core_if->init_txfsiz[i] =
22911 + params->dev_tx_fifo_size[i];
22912 +#endif
22913 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
22914 + txfifosize.d32);
22915 +
22916 + DWC_DEBUGPL(DBG_CIL,
22917 + "new dtxfsiz[%d]=%08x\n",
22918 + i,
22919 + DWC_READ_REG32(&global_regs->dtxfsiz
22920 + [i]));
22921 +
22922 + txfifosize.b.startaddr += txfifosize.b.depth;
22923 + }
22924 + if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
22925 + /* Calculating DFIFOCFG for Device mode to include RxFIFO and NPTXFIFO */
22926 + gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
22927 + hwcfg3.d32 = DWC_READ_REG32(&global_regs->ghwcfg3);
22928 + gdfifocfg.b.gdfifocfg = (DWC_READ_REG32(&global_regs->ghwcfg3) >> 16);
22929 + DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
22930 + rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
22931 + nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
22932 + gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz;
22933 + DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
22934 + }
22935 + }
22936 +
22937 + /* Flush the FIFOs */
22938 + dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */
22939 + dwc_otg_flush_rx_fifo(core_if);
22940 +
22941 + /* Flush the Learning Queue. */
22942 + resetctl.b.intknqflsh = 1;
22943 + DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
22944 +
22945 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
22946 + core_if->start_predict = 0;
22947 + for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) {
22948 + core_if->nextep_seq[i] = 0xff; // 0xff - EP not active
22949 + }
22950 + core_if->nextep_seq[0] = 0;
22951 + core_if->first_in_nextep_seq = 0;
22952 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
22953 + diepctl.b.nextep = 0;
22954 + DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
22955 +
22956 + /* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
22957 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
22958 + dcfg.b.epmscnt = 2;
22959 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
22960 +
22961 + DWC_DEBUGPL(DBG_CILV,"%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
22962 + __func__, core_if->first_in_nextep_seq);
22963 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
22964 + DWC_DEBUGPL(DBG_CILV, "%2d ", core_if->nextep_seq[i]);
22965 + }
22966 + DWC_DEBUGPL(DBG_CILV,"\n");
22967 + }
22968 +
22969 + /* Clear all pending Device Interrupts */
22970 + /** @todo - if the condition needed to be checked
22971 + * or in any case all pending interrutps should be cleared?
22972 + */
22973 + if (core_if->multiproc_int_enable) {
22974 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
22975 + DWC_WRITE_REG32(&dev_if->
22976 + dev_global_regs->diepeachintmsk[i], 0);
22977 + }
22978 + }
22979 +
22980 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
22981 + DWC_WRITE_REG32(&dev_if->
22982 + dev_global_regs->doepeachintmsk[i], 0);
22983 + }
22984 +
22985 + DWC_WRITE_REG32(&dev_if->dev_global_regs->deachint, 0xFFFFFFFF);
22986 + DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk, 0);
22987 + } else {
22988 + DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, 0);
22989 + DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, 0);
22990 + DWC_WRITE_REG32(&dev_if->dev_global_regs->daint, 0xFFFFFFFF);
22991 + DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk, 0);
22992 + }
22993 +
22994 + for (i = 0; i <= dev_if->num_in_eps; i++) {
22995 + depctl_data_t depctl;
22996 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
22997 + if (depctl.b.epena) {
22998 + depctl.d32 = 0;
22999 + depctl.b.epdis = 1;
23000 + depctl.b.snak = 1;
23001 + } else {
23002 + depctl.d32 = 0;
23003 + }
23004 +
23005 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
23006 +
23007 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, 0);
23008 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, 0);
23009 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepint, 0xFF);
23010 + }
23011 +
23012 + for (i = 0; i <= dev_if->num_out_eps; i++) {
23013 + depctl_data_t depctl;
23014 + depctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
23015 + if (depctl.b.epena) {
23016 + dctl_data_t dctl = {.d32 = 0 };
23017 + gintmsk_data_t gintsts = {.d32 = 0 };
23018 + doepint_data_t doepint = {.d32 = 0 };
23019 + dctl.b.sgoutnak = 1;
23020 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
23021 + do {
23022 + dwc_udelay(10);
23023 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
23024 + } while (!gintsts.b.goutnakeff);
23025 + gintsts.d32 = 0;
23026 + gintsts.b.goutnakeff = 1;
23027 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
23028 +
23029 + depctl.d32 = 0;
23030 + depctl.b.epdis = 1;
23031 + depctl.b.snak = 1;
23032 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepctl, depctl.d32);
23033 + do {
23034 + dwc_udelay(10);
23035 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
23036 + out_ep_regs[i]->doepint);
23037 + } while (!doepint.b.epdisabled);
23038 +
23039 + doepint.b.epdisabled = 1;
23040 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepint, doepint.d32);
23041 +
23042 + dctl.d32 = 0;
23043 + dctl.b.cgoutnak = 1;
23044 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
23045 + } else {
23046 + depctl.d32 = 0;
23047 + }
23048 +
23049 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, depctl.d32);
23050 +
23051 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doeptsiz, 0);
23052 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepdma, 0);
23053 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepint, 0xFF);
23054 + }
23055 +
23056 + if (core_if->en_multiple_tx_fifo && core_if->dma_enable) {
23057 + dev_if->non_iso_tx_thr_en = params->thr_ctl & 0x1;
23058 + dev_if->iso_tx_thr_en = (params->thr_ctl >> 1) & 0x1;
23059 + dev_if->rx_thr_en = (params->thr_ctl >> 2) & 0x1;
23060 +
23061 + dev_if->rx_thr_length = params->rx_thr_length;
23062 + dev_if->tx_thr_length = params->tx_thr_length;
23063 +
23064 + dev_if->setup_desc_index = 0;
23065 +
23066 + dthrctl.d32 = 0;
23067 + dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en;
23068 + dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en;
23069 + dthrctl.b.tx_thr_len = dev_if->tx_thr_length;
23070 + dthrctl.b.rx_thr_en = dev_if->rx_thr_en;
23071 + dthrctl.b.rx_thr_len = dev_if->rx_thr_length;
23072 + dthrctl.b.ahb_thr_ratio = params->ahb_thr_ratio;
23073 +
23074 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dtknqr3_dthrctl,
23075 + dthrctl.d32);
23076 +
23077 + DWC_DEBUGPL(DBG_CIL,
23078 + "Non ISO Tx Thr - %d\nISO Tx Thr - %d\nRx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n",
23079 + dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en,
23080 + dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len,
23081 + dthrctl.b.rx_thr_len);
23082 +
23083 + }
23084 +
23085 + dwc_otg_enable_device_interrupts(core_if);
23086 +
23087 + {
23088 + diepmsk_data_t msk = {.d32 = 0 };
23089 + msk.b.txfifoundrn = 1;
23090 + if (core_if->multiproc_int_enable) {
23091 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->
23092 + diepeachintmsk[0], msk.d32, msk.d32);
23093 + } else {
23094 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk,
23095 + msk.d32, msk.d32);
23096 + }
23097 + }
23098 +
23099 + if (core_if->multiproc_int_enable) {
23100 + /* Set NAK on Babble */
23101 + dctl_data_t dctl = {.d32 = 0 };
23102 + dctl.b.nakonbble = 1;
23103 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
23104 + }
23105 +
23106 + if (core_if->snpsid >= OTG_CORE_REV_2_94a) {
23107 + dctl_data_t dctl = {.d32 = 0 };
23108 + dctl.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
23109 + dctl.b.sftdiscon = 0;
23110 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl, dctl.d32);
23111 + }
23112 +}
23113 +
23114 +/**
23115 + * This function enables the Host mode interrupts.
23116 + *
23117 + * @param core_if Programming view of DWC_otg controller
23118 + */
23119 +void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * core_if)
23120 +{
23121 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
23122 + gintmsk_data_t intr_mask = {.d32 = 0 };
23123 +
23124 + DWC_DEBUGPL(DBG_CIL, "%s(%p)\n", __func__, core_if);
23125 +
23126 + /* Disable all interrupts. */
23127 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
23128 +
23129 + /* Clear any pending interrupts. */
23130 + DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
23131 +
23132 + /* Enable the common interrupts */
23133 + dwc_otg_enable_common_interrupts(core_if);
23134 +
23135 + /*
23136 + * Enable host mode interrupts without disturbing common
23137 + * interrupts.
23138 + */
23139 +
23140 + intr_mask.b.disconnect = 1;
23141 + intr_mask.b.portintr = 1;
23142 + intr_mask.b.hcintr = 1;
23143 +
23144 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
23145 +}
23146 +
23147 +/**
23148 + * This function disables the Host Mode interrupts.
23149 + *
23150 + * @param core_if Programming view of DWC_otg controller
23151 + */
23152 +void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * core_if)
23153 +{
23154 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
23155 + gintmsk_data_t intr_mask = {.d32 = 0 };
23156 +
23157 + DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__);
23158 +
23159 + /*
23160 + * Disable host mode interrupts without disturbing common
23161 + * interrupts.
23162 + */
23163 + intr_mask.b.sofintr = 1;
23164 + intr_mask.b.portintr = 1;
23165 + intr_mask.b.hcintr = 1;
23166 + intr_mask.b.ptxfempty = 1;
23167 + intr_mask.b.nptxfempty = 1;
23168 +
23169 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, 0);
23170 +}
23171 +
23172 +/**
23173 + * This function initializes the DWC_otg controller registers for
23174 + * host mode.
23175 + *
23176 + * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
23177 + * request queues. Host channels are reset to ensure that they are ready for
23178 + * performing transfers.
23179 + *
23180 + * @param core_if Programming view of DWC_otg controller
23181 + *
23182 + */
23183 +void dwc_otg_core_host_init(dwc_otg_core_if_t * core_if)
23184 +{
23185 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
23186 + dwc_otg_host_if_t *host_if = core_if->host_if;
23187 + dwc_otg_core_params_t *params = core_if->core_params;
23188 + hprt0_data_t hprt0 = {.d32 = 0 };
23189 + fifosize_data_t nptxfifosize;
23190 + fifosize_data_t ptxfifosize;
23191 + uint16_t rxfsiz, nptxfsiz, hptxfsiz;
23192 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
23193 + int i;
23194 + hcchar_data_t hcchar;
23195 + hcfg_data_t hcfg;
23196 + hfir_data_t hfir;
23197 + dwc_otg_hc_regs_t *hc_regs;
23198 + int num_channels;
23199 + gotgctl_data_t gotgctl = {.d32 = 0 };
23200 +
23201 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
23202 +
23203 + /* Restart the Phy Clock */
23204 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
23205 +
23206 + /* Initialize Host Configuration Register */
23207 + init_fslspclksel(core_if);
23208 + if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
23209 + hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
23210 + hcfg.b.fslssupp = 1;
23211 + DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
23212 +
23213 + }
23214 +
23215 + /* This bit allows dynamic reloading of the HFIR register
23216 + * during runtime. This bit needs to be programmed during
23217 + * initial configuration and its value must not be changed
23218 + * during runtime.*/
23219 + if (core_if->core_params->reload_ctl == 1) {
23220 + hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
23221 + hfir.b.hfirrldctrl = 1;
23222 + DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
23223 + }
23224 +
23225 + if (core_if->core_params->dma_desc_enable) {
23226 + uint8_t op_mode = core_if->hwcfg2.b.op_mode;
23227 + if (!
23228 + (core_if->hwcfg4.b.desc_dma
23229 + && (core_if->snpsid >= OTG_CORE_REV_2_90a)
23230 + && ((op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
23231 + || (op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
23232 + || (op_mode ==
23233 + DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG)
23234 + || (op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)
23235 + || (op_mode ==
23236 + DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST)))) {
23237 +
23238 + DWC_ERROR("Host can't operate in Descriptor DMA mode.\n"
23239 + "Either core version is below 2.90a or "
23240 + "GHWCFG2, GHWCFG4 registers' values do not allow Descriptor DMA in host mode.\n"
23241 + "To run the driver in Buffer DMA host mode set dma_desc_enable "
23242 + "module parameter to 0.\n");
23243 + return;
23244 + }
23245 + hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
23246 + hcfg.b.descdma = 1;
23247 + DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
23248 + }
23249 +
23250 + /* Configure data FIFO sizes */
23251 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
23252 + DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
23253 + core_if->total_fifo_size);
23254 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
23255 + params->host_rx_fifo_size);
23256 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
23257 + params->host_nperio_tx_fifo_size);
23258 + DWC_DEBUGPL(DBG_CIL, "P Tx FIFO Size=%d\n",
23259 + params->host_perio_tx_fifo_size);
23260 +
23261 + /* Rx FIFO */
23262 + DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
23263 + DWC_READ_REG32(&global_regs->grxfsiz));
23264 + DWC_WRITE_REG32(&global_regs->grxfsiz,
23265 + params->host_rx_fifo_size);
23266 + DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
23267 + DWC_READ_REG32(&global_regs->grxfsiz));
23268 +
23269 + /* Non-periodic Tx FIFO */
23270 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
23271 + DWC_READ_REG32(&global_regs->gnptxfsiz));
23272 + nptxfifosize.b.depth = params->host_nperio_tx_fifo_size;
23273 + nptxfifosize.b.startaddr = params->host_rx_fifo_size;
23274 + DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
23275 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
23276 + DWC_READ_REG32(&global_regs->gnptxfsiz));
23277 +
23278 + /* Periodic Tx FIFO */
23279 + DWC_DEBUGPL(DBG_CIL, "initial hptxfsiz=%08x\n",
23280 + DWC_READ_REG32(&global_regs->hptxfsiz));
23281 + ptxfifosize.b.depth = params->host_perio_tx_fifo_size;
23282 + ptxfifosize.b.startaddr =
23283 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
23284 + DWC_WRITE_REG32(&global_regs->hptxfsiz, ptxfifosize.d32);
23285 + DWC_DEBUGPL(DBG_CIL, "new hptxfsiz=%08x\n",
23286 + DWC_READ_REG32(&global_regs->hptxfsiz));
23287 +
23288 + if (core_if->en_multiple_tx_fifo
23289 + && core_if->snpsid <= OTG_CORE_REV_2_94a) {
23290 + /* Global DFIFOCFG calculation for Host mode - include RxFIFO, NPTXFIFO and HPTXFIFO */
23291 + gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
23292 + rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
23293 + nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
23294 + hptxfsiz = (DWC_READ_REG32(&global_regs->hptxfsiz) >> 16);
23295 + gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz + hptxfsiz;
23296 + DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
23297 + }
23298 + }
23299 +
23300 + /* TODO - check this */
23301 + /* Clear Host Set HNP Enable in the OTG Control Register */
23302 + gotgctl.b.hstsethnpen = 1;
23303 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
23304 + /* Make sure the FIFOs are flushed. */
23305 + dwc_otg_flush_tx_fifo(core_if, 0x10 /* all TX FIFOs */ );
23306 + dwc_otg_flush_rx_fifo(core_if);
23307 +
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 +
23312 + if (!core_if->core_params->dma_desc_enable) {
23313 + /* Flush out any leftover queued requests. */
23314 + num_channels = core_if->core_params->host_channels;
23315 +
23316 + for (i = 0; i < num_channels; i++) {
23317 + hc_regs = core_if->host_if->hc_regs[i];
23318 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23319 + hcchar.b.chen = 0;
23320 + hcchar.b.chdis = 1;
23321 + hcchar.b.epdir = 0;
23322 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23323 + }
23324 +
23325 + /* Halt all channels to put them into a known state. */
23326 + for (i = 0; i < num_channels; i++) {
23327 + int count = 0;
23328 + hc_regs = core_if->host_if->hc_regs[i];
23329 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23330 + hcchar.b.chen = 1;
23331 + hcchar.b.chdis = 1;
23332 + hcchar.b.epdir = 0;
23333 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23334 + DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d regs %p\n", __func__, i, hc_regs);
23335 + do {
23336 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23337 + if (++count > 1000) {
23338 + DWC_ERROR
23339 + ("%s: Unable to clear halt on channel %d (timeout HCCHAR 0x%X @%p)\n",
23340 + __func__, i, hcchar.d32, &hc_regs->hcchar);
23341 + break;
23342 + }
23343 + dwc_udelay(1);
23344 + } while (hcchar.b.chen);
23345 + }
23346 + }
23347 +
23348 + /* Turn on the vbus power. */
23349 + DWC_PRINTF("Init: Port Power? op_state=%d\n", core_if->op_state);
23350 + if (core_if->op_state == A_HOST) {
23351 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
23352 + DWC_PRINTF("Init: Power Port (%d)\n", hprt0.b.prtpwr);
23353 + if (hprt0.b.prtpwr == 0) {
23354 + hprt0.b.prtpwr = 1;
23355 + DWC_WRITE_REG32(host_if->hprt0, hprt0.d32);
23356 + }
23357 + }
23358 +
23359 + dwc_otg_enable_host_interrupts(core_if);
23360 +}
23361 +
23362 +/**
23363 + * Prepares a host channel for transferring packets to/from a specific
23364 + * endpoint. The HCCHARn register is set up with the characteristics specified
23365 + * in _hc. Host channel interrupts that may need to be serviced while this
23366 + * transfer is in progress are enabled.
23367 + *
23368 + * @param core_if Programming view of DWC_otg controller
23369 + * @param hc Information needed to initialize the host channel
23370 + */
23371 +void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23372 +{
23373 + uint32_t intr_enable;
23374 + hcintmsk_data_t hc_intr_mask;
23375 + gintmsk_data_t gintmsk = {.d32 = 0 };
23376 + hcchar_data_t hcchar;
23377 + hcsplt_data_t hcsplt;
23378 +
23379 + uint8_t hc_num = hc->hc_num;
23380 + dwc_otg_host_if_t *host_if = core_if->host_if;
23381 + dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num];
23382 +
23383 + /* Clear old interrupt conditions for this host channel. */
23384 + hc_intr_mask.d32 = 0xFFFFFFFF;
23385 + hc_intr_mask.b.reserved14_31 = 0;
23386 + DWC_WRITE_REG32(&hc_regs->hcint, hc_intr_mask.d32);
23387 +
23388 + /* Enable channel interrupts required for this transfer. */
23389 + hc_intr_mask.d32 = 0;
23390 + hc_intr_mask.b.chhltd = 1;
23391 + if (core_if->dma_enable) {
23392 + /* For Descriptor DMA mode core halts the channel on AHB error. Interrupt is not required */
23393 + if (!core_if->dma_desc_enable)
23394 + hc_intr_mask.b.ahberr = 1;
23395 + else {
23396 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
23397 + hc_intr_mask.b.xfercompl = 1;
23398 + }
23399 +
23400 + if (hc->error_state && !hc->do_split &&
23401 + hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
23402 + hc_intr_mask.b.ack = 1;
23403 + if (hc->ep_is_in) {
23404 + hc_intr_mask.b.datatglerr = 1;
23405 + if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
23406 + hc_intr_mask.b.nak = 1;
23407 + }
23408 + }
23409 + }
23410 + } else {
23411 + switch (hc->ep_type) {
23412 + case DWC_OTG_EP_TYPE_CONTROL:
23413 + case DWC_OTG_EP_TYPE_BULK:
23414 + hc_intr_mask.b.xfercompl = 1;
23415 + hc_intr_mask.b.stall = 1;
23416 + hc_intr_mask.b.xacterr = 1;
23417 + hc_intr_mask.b.datatglerr = 1;
23418 + if (hc->ep_is_in) {
23419 + hc_intr_mask.b.bblerr = 1;
23420 + } else {
23421 + hc_intr_mask.b.nak = 1;
23422 + hc_intr_mask.b.nyet = 1;
23423 + if (hc->do_ping) {
23424 + hc_intr_mask.b.ack = 1;
23425 + }
23426 + }
23427 +
23428 + if (hc->do_split) {
23429 + hc_intr_mask.b.nak = 1;
23430 + if (hc->complete_split) {
23431 + hc_intr_mask.b.nyet = 1;
23432 + } else {
23433 + hc_intr_mask.b.ack = 1;
23434 + }
23435 + }
23436 +
23437 + if (hc->error_state) {
23438 + hc_intr_mask.b.ack = 1;
23439 + }
23440 + break;
23441 + case DWC_OTG_EP_TYPE_INTR:
23442 + hc_intr_mask.b.xfercompl = 1;
23443 + hc_intr_mask.b.nak = 1;
23444 + hc_intr_mask.b.stall = 1;
23445 + hc_intr_mask.b.xacterr = 1;
23446 + hc_intr_mask.b.datatglerr = 1;
23447 + hc_intr_mask.b.frmovrun = 1;
23448 +
23449 + if (hc->ep_is_in) {
23450 + hc_intr_mask.b.bblerr = 1;
23451 + }
23452 + if (hc->error_state) {
23453 + hc_intr_mask.b.ack = 1;
23454 + }
23455 + if (hc->do_split) {
23456 + if (hc->complete_split) {
23457 + hc_intr_mask.b.nyet = 1;
23458 + } else {
23459 + hc_intr_mask.b.ack = 1;
23460 + }
23461 + }
23462 + break;
23463 + case DWC_OTG_EP_TYPE_ISOC:
23464 + hc_intr_mask.b.xfercompl = 1;
23465 + hc_intr_mask.b.frmovrun = 1;
23466 + hc_intr_mask.b.ack = 1;
23467 +
23468 + if (hc->ep_is_in) {
23469 + hc_intr_mask.b.xacterr = 1;
23470 + hc_intr_mask.b.bblerr = 1;
23471 + }
23472 + break;
23473 + }
23474 + }
23475 + DWC_WRITE_REG32(&hc_regs->hcintmsk, hc_intr_mask.d32);
23476 +
23477 + /* Enable the top level host channel interrupt. */
23478 + intr_enable = (1 << hc_num);
23479 + DWC_MODIFY_REG32(&host_if->host_global_regs->haintmsk, 0, intr_enable);
23480 +
23481 + /* Make sure host channel interrupts are enabled. */
23482 + gintmsk.b.hcintr = 1;
23483 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
23484 +
23485 + /*
23486 + * Program the HCCHARn register with the endpoint characteristics for
23487 + * the current transfer.
23488 + */
23489 + hcchar.d32 = 0;
23490 + hcchar.b.devaddr = hc->dev_addr;
23491 + hcchar.b.epnum = hc->ep_num;
23492 + hcchar.b.epdir = hc->ep_is_in;
23493 + hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
23494 + hcchar.b.eptype = hc->ep_type;
23495 + hcchar.b.mps = hc->max_packet;
23496 +
23497 + DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32);
23498 +
23499 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d, Dev Addr %d, EP #%d\n",
23500 + __func__, hc->hc_num, hcchar.b.devaddr, hcchar.b.epnum);
23501 + DWC_DEBUGPL(DBG_HCDV, " Is In %d, Is Low Speed %d, EP Type %d, "
23502 + "Max Pkt %d, Multi Cnt %d\n",
23503 + hcchar.b.epdir, hcchar.b.lspddev, hcchar.b.eptype,
23504 + hcchar.b.mps, hcchar.b.multicnt);
23505 +
23506 + /*
23507 + * Program the HCSPLIT register for SPLITs
23508 + */
23509 + hcsplt.d32 = 0;
23510 + if (hc->do_split) {
23511 + DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n",
23512 + hc->hc_num,
23513 + hc->complete_split ? "CSPLIT" : "SSPLIT");
23514 + hcsplt.b.compsplt = hc->complete_split;
23515 + hcsplt.b.xactpos = hc->xact_pos;
23516 + hcsplt.b.hubaddr = hc->hub_addr;
23517 + hcsplt.b.prtaddr = hc->port_addr;
23518 + DWC_DEBUGPL(DBG_HCDV, "\t comp split %d\n", hc->complete_split);
23519 + DWC_DEBUGPL(DBG_HCDV, "\t xact pos %d\n", hc->xact_pos);
23520 + DWC_DEBUGPL(DBG_HCDV, "\t hub addr %d\n", hc->hub_addr);
23521 + DWC_DEBUGPL(DBG_HCDV, "\t port addr %d\n", hc->port_addr);
23522 + DWC_DEBUGPL(DBG_HCDV, "\t is_in %d\n", hc->ep_is_in);
23523 + DWC_DEBUGPL(DBG_HCDV, "\t Max Pkt: %d\n", hcchar.b.mps);
23524 + DWC_DEBUGPL(DBG_HCDV, "\t xferlen: %d\n", hc->xfer_len);
23525 + }
23526 + DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32);
23527 +
23528 +}
23529 +
23530 +/**
23531 + * Attempts to halt a host channel. This function should only be called in
23532 + * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under
23533 + * normal circumstances in DMA mode, the controller halts the channel when the
23534 + * transfer is complete or a condition occurs that requires application
23535 + * intervention.
23536 + *
23537 + * In slave mode, checks for a free request queue entry, then sets the Channel
23538 + * Enable and Channel Disable bits of the Host Channel Characteristics
23539 + * register of the specified channel to intiate the halt. If there is no free
23540 + * request queue entry, sets only the Channel Disable bit of the HCCHARn
23541 + * register to flush requests for this channel. In the latter case, sets a
23542 + * flag to indicate that the host channel needs to be halted when a request
23543 + * queue slot is open.
23544 + *
23545 + * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
23546 + * HCCHARn register. The controller ensures there is space in the request
23547 + * queue before submitting the halt request.
23548 + *
23549 + * Some time may elapse before the core flushes any posted requests for this
23550 + * host channel and halts. The Channel Halted interrupt handler completes the
23551 + * deactivation of the host channel.
23552 + *
23553 + * @param core_if Controller register interface.
23554 + * @param hc Host channel to halt.
23555 + * @param halt_status Reason for halting the channel.
23556 + */
23557 +void dwc_otg_hc_halt(dwc_otg_core_if_t * core_if,
23558 + dwc_hc_t * hc, dwc_otg_halt_status_e halt_status)
23559 +{
23560 + gnptxsts_data_t nptxsts;
23561 + hptxsts_data_t hptxsts;
23562 + hcchar_data_t hcchar;
23563 + dwc_otg_hc_regs_t *hc_regs;
23564 + dwc_otg_core_global_regs_t *global_regs;
23565 + dwc_otg_host_global_regs_t *host_global_regs;
23566 +
23567 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23568 + global_regs = core_if->core_global_regs;
23569 + host_global_regs = core_if->host_if->host_global_regs;
23570 +
23571 + DWC_ASSERT(!(halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS),
23572 + "halt_status = %d\n", halt_status);
23573 +
23574 + if (halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
23575 + halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
23576 + /*
23577 + * Disable all channel interrupts except Ch Halted. The QTD
23578 + * and QH state associated with this transfer has been cleared
23579 + * (in the case of URB_DEQUEUE), so the channel needs to be
23580 + * shut down carefully to prevent crashes.
23581 + */
23582 + hcintmsk_data_t hcintmsk;
23583 + hcintmsk.d32 = 0;
23584 + hcintmsk.b.chhltd = 1;
23585 + DWC_WRITE_REG32(&hc_regs->hcintmsk, hcintmsk.d32);
23586 +
23587 + /*
23588 + * Make sure no other interrupts besides halt are currently
23589 + * pending. Handling another interrupt could cause a crash due
23590 + * to the QTD and QH state.
23591 + */
23592 + DWC_WRITE_REG32(&hc_regs->hcint, ~hcintmsk.d32);
23593 +
23594 + /*
23595 + * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
23596 + * even if the channel was already halted for some other
23597 + * reason.
23598 + */
23599 + hc->halt_status = halt_status;
23600 +
23601 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23602 + if (hcchar.b.chen == 0) {
23603 + /*
23604 + * The channel is either already halted or it hasn't
23605 + * started yet. In DMA mode, the transfer may halt if
23606 + * it finishes normally or a condition occurs that
23607 + * requires driver intervention. Don't want to halt
23608 + * the channel again. In either Slave or DMA mode,
23609 + * it's possible that the transfer has been assigned
23610 + * to a channel, but not started yet when an URB is
23611 + * dequeued. Don't want to halt a channel that hasn't
23612 + * started yet.
23613 + */
23614 + return;
23615 + }
23616 + }
23617 + if (hc->halt_pending) {
23618 + /*
23619 + * A halt has already been issued for this channel. This might
23620 + * happen when a transfer is aborted by a higher level in
23621 + * the stack.
23622 + */
23623 +#ifdef DEBUG
23624 + DWC_PRINTF
23625 + ("*** %s: Channel %d, _hc->halt_pending already set ***\n",
23626 + __func__, hc->hc_num);
23627 +
23628 +#endif
23629 + return;
23630 + }
23631 +
23632 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23633 +
23634 + /* No need to set the bit in DDMA for disabling the channel */
23635 + //TODO check it everywhere channel is disabled
23636 + if (!core_if->core_params->dma_desc_enable)
23637 + hcchar.b.chen = 1;
23638 + hcchar.b.chdis = 1;
23639 +
23640 + if (!core_if->dma_enable) {
23641 + /* Check for space in the request queue to issue the halt. */
23642 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
23643 + hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
23644 + nptxsts.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
23645 + if (nptxsts.b.nptxqspcavail == 0) {
23646 + hcchar.b.chen = 0;
23647 + }
23648 + } else {
23649 + hptxsts.d32 =
23650 + DWC_READ_REG32(&host_global_regs->hptxsts);
23651 + if ((hptxsts.b.ptxqspcavail == 0)
23652 + || (core_if->queuing_high_bandwidth)) {
23653 + hcchar.b.chen = 0;
23654 + }
23655 + }
23656 + }
23657 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23658 +
23659 + hc->halt_status = halt_status;
23660 +
23661 + if (hcchar.b.chen) {
23662 + hc->halt_pending = 1;
23663 + hc->halt_on_queue = 0;
23664 + } else {
23665 + hc->halt_on_queue = 1;
23666 + }
23667 +
23668 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23669 + DWC_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n", hcchar.d32);
23670 + DWC_DEBUGPL(DBG_HCDV, " halt_pending: %d\n", hc->halt_pending);
23671 + DWC_DEBUGPL(DBG_HCDV, " halt_on_queue: %d\n", hc->halt_on_queue);
23672 + DWC_DEBUGPL(DBG_HCDV, " halt_status: %d\n", hc->halt_status);
23673 +
23674 + return;
23675 +}
23676 +
23677 +/**
23678 + * Clears the transfer state for a host channel. This function is normally
23679 + * called after a transfer is done and the host channel is being released.
23680 + *
23681 + * @param core_if Programming view of DWC_otg controller.
23682 + * @param hc Identifies the host channel to clean up.
23683 + */
23684 +void dwc_otg_hc_cleanup(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23685 +{
23686 + dwc_otg_hc_regs_t *hc_regs;
23687 +
23688 + hc->xfer_started = 0;
23689 +
23690 + /*
23691 + * Clear channel interrupt enables and any unhandled channel interrupt
23692 + * conditions.
23693 + */
23694 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23695 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0);
23696 + DWC_WRITE_REG32(&hc_regs->hcint, 0xFFFFFFFF);
23697 +#ifdef DEBUG
23698 + DWC_TIMER_CANCEL(core_if->hc_xfer_timer[hc->hc_num]);
23699 +#endif
23700 +}
23701 +
23702 +/**
23703 + * Sets the channel property that indicates in which frame a periodic transfer
23704 + * should occur. This is always set to the _next_ frame. This function has no
23705 + * effect on non-periodic transfers.
23706 + *
23707 + * @param core_if Programming view of DWC_otg controller.
23708 + * @param hc Identifies the host channel to set up and its properties.
23709 + * @param hcchar Current value of the HCCHAR register for the specified host
23710 + * channel.
23711 + */
23712 +static inline void hc_set_even_odd_frame(dwc_otg_core_if_t * core_if,
23713 + dwc_hc_t * hc, hcchar_data_t * hcchar)
23714 +{
23715 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23716 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23717 + hfnum_data_t hfnum;
23718 + hfnum.d32 =
23719 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hfnum);
23720 +
23721 + /* 1 if _next_ frame is odd, 0 if it's even */
23722 + hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1;
23723 +#ifdef DEBUG
23724 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR && hc->do_split
23725 + && !hc->complete_split) {
23726 + switch (hfnum.b.frnum & 0x7) {
23727 + case 7:
23728 + core_if->hfnum_7_samples++;
23729 + core_if->hfnum_7_frrem_accum += hfnum.b.frrem;
23730 + break;
23731 + case 0:
23732 + core_if->hfnum_0_samples++;
23733 + core_if->hfnum_0_frrem_accum += hfnum.b.frrem;
23734 + break;
23735 + default:
23736 + core_if->hfnum_other_samples++;
23737 + core_if->hfnum_other_frrem_accum +=
23738 + hfnum.b.frrem;
23739 + break;
23740 + }
23741 + }
23742 +#endif
23743 + }
23744 +}
23745 +
23746 +#ifdef DEBUG
23747 +void hc_xfer_timeout(void *ptr)
23748 +{
23749 + hc_xfer_info_t *xfer_info = NULL;
23750 + int hc_num = 0;
23751 +
23752 + if (ptr)
23753 + xfer_info = (hc_xfer_info_t *) ptr;
23754 +
23755 + if (!xfer_info->hc) {
23756 + DWC_ERROR("xfer_info->hc = %p\n", xfer_info->hc);
23757 + return;
23758 + }
23759 +
23760 + hc_num = xfer_info->hc->hc_num;
23761 + DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num);
23762 + DWC_WARN(" start_hcchar_val 0x%08x\n",
23763 + xfer_info->core_if->start_hcchar_val[hc_num]);
23764 +}
23765 +#endif
23766 +
23767 +void ep_xfer_timeout(void *ptr)
23768 +{
23769 + ep_xfer_info_t *xfer_info = NULL;
23770 + int ep_num = 0;
23771 + dctl_data_t dctl = {.d32 = 0 };
23772 + gintsts_data_t gintsts = {.d32 = 0 };
23773 + gintmsk_data_t gintmsk = {.d32 = 0 };
23774 +
23775 + if (ptr)
23776 + xfer_info = (ep_xfer_info_t *) ptr;
23777 +
23778 + if (!xfer_info->ep) {
23779 + DWC_ERROR("xfer_info->ep = %p\n", xfer_info->ep);
23780 + return;
23781 + }
23782 +
23783 + ep_num = xfer_info->ep->num;
23784 + DWC_WARN("%s: timeout on endpoit %d\n", __func__, ep_num);
23785 + /* Put the sate to 2 as it was time outed */
23786 + xfer_info->state = 2;
23787 +
23788 + dctl.d32 =
23789 + DWC_READ_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl);
23790 + gintsts.d32 =
23791 + DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintsts);
23792 + gintmsk.d32 =
23793 + DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintmsk);
23794 +
23795 + if (!gintmsk.b.goutnakeff) {
23796 + /* Unmask it */
23797 + gintmsk.b.goutnakeff = 1;
23798 + DWC_WRITE_REG32(&xfer_info->core_if->core_global_regs->gintmsk,
23799 + gintmsk.d32);
23800 +
23801 + }
23802 +
23803 + if (!gintsts.b.goutnakeff) {
23804 + dctl.b.sgoutnak = 1;
23805 + }
23806 + DWC_WRITE_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl,
23807 + dctl.d32);
23808 +
23809 +}
23810 +
23811 +void set_pid_isoc(dwc_hc_t * hc)
23812 +{
23813 + /* Set up the initial PID for the transfer. */
23814 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH) {
23815 + if (hc->ep_is_in) {
23816 + if (hc->multi_count == 1) {
23817 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
23818 + } else if (hc->multi_count == 2) {
23819 + hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
23820 + } else {
23821 + hc->data_pid_start = DWC_OTG_HC_PID_DATA2;
23822 + }
23823 + } else {
23824 + if (hc->multi_count == 1) {
23825 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
23826 + } else {
23827 + hc->data_pid_start = DWC_OTG_HC_PID_MDATA;
23828 + }
23829 + }
23830 + } else {
23831 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
23832 + }
23833 +}
23834 +
23835 +/**
23836 + * This function does the setup for a data transfer for a host channel and
23837 + * starts the transfer. May be called in either Slave mode or DMA mode. In
23838 + * Slave mode, the caller must ensure that there is sufficient space in the
23839 + * request queue and Tx Data FIFO.
23840 + *
23841 + * For an OUT transfer in Slave mode, it loads a data packet into the
23842 + * appropriate FIFO. If necessary, additional data packets will be loaded in
23843 + * the Host ISR.
23844 + *
23845 + * For an IN transfer in Slave mode, a data packet is requested. The data
23846 + * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
23847 + * additional data packets are requested in the Host ISR.
23848 + *
23849 + * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
23850 + * register along with a packet count of 1 and the channel is enabled. This
23851 + * causes a single PING transaction to occur. Other fields in HCTSIZ are
23852 + * simply set to 0 since no data transfer occurs in this case.
23853 + *
23854 + * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
23855 + * all the information required to perform the subsequent data transfer. In
23856 + * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
23857 + * controller performs the entire PING protocol, then starts the data
23858 + * transfer.
23859 + *
23860 + * @param core_if Programming view of DWC_otg controller.
23861 + * @param hc Information needed to initialize the host channel. The xfer_len
23862 + * value may be reduced to accommodate the max widths of the XferSize and
23863 + * PktCnt fields in the HCTSIZn register. The multi_count value may be changed
23864 + * to reflect the final xfer_len value.
23865 + */
23866 +void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23867 +{
23868 + hcchar_data_t hcchar;
23869 + hctsiz_data_t hctsiz;
23870 + uint16_t num_packets;
23871 + uint32_t max_hc_xfer_size = core_if->core_params->max_transfer_size;
23872 + uint16_t max_hc_pkt_count = core_if->core_params->max_packet_count;
23873 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23874 +
23875 + hctsiz.d32 = 0;
23876 +
23877 + if (hc->do_ping) {
23878 + if (!core_if->dma_enable) {
23879 + dwc_otg_hc_do_ping(core_if, hc);
23880 + hc->xfer_started = 1;
23881 + return;
23882 + } else {
23883 + hctsiz.b.dopng = 1;
23884 + }
23885 + }
23886 +
23887 + if (hc->do_split) {
23888 + num_packets = 1;
23889 +
23890 + if (hc->complete_split && !hc->ep_is_in) {
23891 + /* For CSPLIT OUT Transfer, set the size to 0 so the
23892 + * core doesn't expect any data written to the FIFO */
23893 + hc->xfer_len = 0;
23894 + } else if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
23895 + hc->xfer_len = hc->max_packet;
23896 + } else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
23897 + hc->xfer_len = 188;
23898 + }
23899 +
23900 + hctsiz.b.xfersize = hc->xfer_len;
23901 + } else {
23902 + /*
23903 + * Ensure that the transfer length and packet count will fit
23904 + * in the widths allocated for them in the HCTSIZn register.
23905 + */
23906 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23907 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23908 + /*
23909 + * Make sure the transfer size is no larger than one
23910 + * (micro)frame's worth of data. (A check was done
23911 + * when the periodic transfer was accepted to ensure
23912 + * that a (micro)frame's worth of data can be
23913 + * programmed into a channel.)
23914 + */
23915 + uint32_t max_periodic_len =
23916 + hc->multi_count * hc->max_packet;
23917 + if (hc->xfer_len > max_periodic_len) {
23918 + hc->xfer_len = max_periodic_len;
23919 + } else {
23920 + }
23921 + } else if (hc->xfer_len > max_hc_xfer_size) {
23922 + /* Make sure that xfer_len is a multiple of max packet size. */
23923 + hc->xfer_len = max_hc_xfer_size - hc->max_packet + 1;
23924 + }
23925 +
23926 + if (hc->xfer_len > 0) {
23927 + num_packets =
23928 + (hc->xfer_len + hc->max_packet -
23929 + 1) / hc->max_packet;
23930 + if (num_packets > max_hc_pkt_count) {
23931 + num_packets = max_hc_pkt_count;
23932 + hc->xfer_len = num_packets * hc->max_packet;
23933 + }
23934 + } else {
23935 + /* Need 1 packet for transfer length of 0. */
23936 + num_packets = 1;
23937 + }
23938 +
23939 + if (hc->ep_is_in) {
23940 + /* Always program an integral # of max packets for IN transfers. */
23941 + hc->xfer_len = num_packets * hc->max_packet;
23942 + }
23943 +
23944 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23945 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23946 + /*
23947 + * Make sure that the multi_count field matches the
23948 + * actual transfer length.
23949 + */
23950 + hc->multi_count = num_packets;
23951 + }
23952 +
23953 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
23954 + set_pid_isoc(hc);
23955 +
23956 + hctsiz.b.xfersize = hc->xfer_len;
23957 + }
23958 +
23959 + hc->start_pkt_count = num_packets;
23960 + hctsiz.b.pktcnt = num_packets;
23961 + hctsiz.b.pid = hc->data_pid_start;
23962 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
23963 +
23964 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23965 + DWC_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize);
23966 + DWC_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n", hctsiz.b.pktcnt);
23967 + DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid);
23968 +
23969 + if (core_if->dma_enable) {
23970 + dwc_dma_t dma_addr;
23971 + if (hc->align_buff) {
23972 + dma_addr = hc->align_buff;
23973 + } else {
23974 + dma_addr = ((unsigned long)hc->xfer_buff & 0xffffffff);
23975 + }
23976 + DWC_WRITE_REG32(&hc_regs->hcdma, dma_addr);
23977 + }
23978 +
23979 + /* Start the split */
23980 + if (hc->do_split) {
23981 + hcsplt_data_t hcsplt;
23982 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
23983 + hcsplt.b.spltena = 1;
23984 + DWC_WRITE_REG32(&hc_regs->hcsplt, hcsplt.d32);
23985 + }
23986 +
23987 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23988 + hcchar.b.multicnt = hc->multi_count;
23989 + hc_set_even_odd_frame(core_if, hc, &hcchar);
23990 +#ifdef DEBUG
23991 + core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
23992 + if (hcchar.b.chdis) {
23993 + DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
23994 + __func__, hc->hc_num, hcchar.d32);
23995 + }
23996 +#endif
23997 +
23998 + /* Set host channel enable after all other setup is complete. */
23999 + hcchar.b.chen = 1;
24000 + hcchar.b.chdis = 0;
24001 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
24002 +
24003 + hc->xfer_started = 1;
24004 + hc->requests++;
24005 +
24006 + if (!core_if->dma_enable && !hc->ep_is_in && hc->xfer_len > 0) {
24007 + /* Load OUT packet into the appropriate Tx FIFO. */
24008 + dwc_otg_hc_write_packet(core_if, hc);
24009 + }
24010 +#ifdef DEBUG
24011 + if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
24012 + DWC_DEBUGPL(DBG_HCDV, "transfer %d from core_if %p\n",
24013 + hc->hc_num, core_if);//GRAYG
24014 + core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
24015 + core_if->hc_xfer_info[hc->hc_num].hc = hc;
24016 +
24017 + /* Start a timer for this transfer. */
24018 + DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
24019 + }
24020 +#endif
24021 +}
24022 +
24023 +/**
24024 + * This function does the setup for a data transfer for a host channel
24025 + * and starts the transfer in Descriptor DMA mode.
24026 + *
24027 + * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
24028 + * Sets PID and NTD values. For periodic transfers
24029 + * initializes SCHED_INFO field with micro-frame bitmap.
24030 + *
24031 + * Initializes HCDMA register with descriptor list address and CTD value
24032 + * then starts the transfer via enabling the channel.
24033 + *
24034 + * @param core_if Programming view of DWC_otg controller.
24035 + * @param hc Information needed to initialize the host channel.
24036 + */
24037 +void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
24038 +{
24039 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
24040 + hcchar_data_t hcchar;
24041 + hctsiz_data_t hctsiz;
24042 + hcdma_data_t hcdma;
24043 +
24044 + hctsiz.d32 = 0;
24045 +
24046 + if (hc->do_ping)
24047 + hctsiz.b_ddma.dopng = 1;
24048 +
24049 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
24050 + set_pid_isoc(hc);
24051 +
24052 + /* Packet Count and Xfer Size are not used in Descriptor DMA mode */
24053 + hctsiz.b_ddma.pid = hc->data_pid_start;
24054 + hctsiz.b_ddma.ntd = hc->ntd - 1; /* 0 - 1 descriptor, 1 - 2 descriptors, etc. */
24055 + hctsiz.b_ddma.schinfo = hc->schinfo; /* Non-zero only for high-speed interrupt endpoints */
24056 +
24057 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
24058 + DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid);
24059 + DWC_DEBUGPL(DBG_HCDV, " NTD: %d\n", hctsiz.b_ddma.ntd);
24060 +
24061 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
24062 +
24063 + hcdma.d32 = 0;
24064 + hcdma.b.dma_addr = ((uint32_t) hc->desc_list_addr) >> 11;
24065 +
24066 + /* Always start from first descriptor. */
24067 + hcdma.b.ctd = 0;
24068 + DWC_WRITE_REG32(&hc_regs->hcdma, hcdma.d32);
24069 +
24070 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
24071 + hcchar.b.multicnt = hc->multi_count;
24072 +
24073 +#ifdef DEBUG
24074 + core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
24075 + if (hcchar.b.chdis) {
24076 + DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
24077 + __func__, hc->hc_num, hcchar.d32);
24078 + }
24079 +#endif
24080 +
24081 + /* Set host channel enable after all other setup is complete. */
24082 + hcchar.b.chen = 1;
24083 + hcchar.b.chdis = 0;
24084 +
24085 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
24086 +
24087 + hc->xfer_started = 1;
24088 + hc->requests++;
24089 +
24090 +#ifdef DEBUG
24091 + if ((hc->ep_type != DWC_OTG_EP_TYPE_INTR)
24092 + && (hc->ep_type != DWC_OTG_EP_TYPE_ISOC)) {
24093 + DWC_DEBUGPL(DBG_HCDV, "DMA transfer %d from core_if %p\n",
24094 + hc->hc_num, core_if);//GRAYG
24095 + core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
24096 + core_if->hc_xfer_info[hc->hc_num].hc = hc;
24097 + /* Start a timer for this transfer. */
24098 + DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
24099 + }
24100 +#endif
24101 +
24102 +}
24103 +
24104 +/**
24105 + * This function continues a data transfer that was started by previous call
24106 + * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is
24107 + * sufficient space in the request queue and Tx Data FIFO. This function
24108 + * should only be called in Slave mode. In DMA mode, the controller acts
24109 + * autonomously to complete transfers programmed to a host channel.
24110 + *
24111 + * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
24112 + * if there is any data remaining to be queued. For an IN transfer, another
24113 + * data packet is always requested. For the SETUP phase of a control transfer,
24114 + * this function does nothing.
24115 + *
24116 + * @return 1 if a new request is queued, 0 if no more requests are required
24117 + * for this transfer.
24118 + */
24119 +int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
24120 +{
24121 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
24122 +
24123 + if (hc->do_split) {
24124 + /* SPLITs always queue just once per channel */
24125 + return 0;
24126 + } else if (hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
24127 + /* SETUPs are queued only once since they can't be NAKed. */
24128 + return 0;
24129 + } else if (hc->ep_is_in) {
24130 + /*
24131 + * Always queue another request for other IN transfers. If
24132 + * back-to-back INs are issued and NAKs are received for both,
24133 + * the driver may still be processing the first NAK when the
24134 + * second NAK is received. When the interrupt handler clears
24135 + * the NAK interrupt for the first NAK, the second NAK will
24136 + * not be seen. So we can't depend on the NAK interrupt
24137 + * handler to requeue a NAKed request. Instead, IN requests
24138 + * are issued each time this function is called. When the
24139 + * transfer completes, the extra requests for the channel will
24140 + * be flushed.
24141 + */
24142 + hcchar_data_t hcchar;
24143 + dwc_otg_hc_regs_t *hc_regs =
24144 + core_if->host_if->hc_regs[hc->hc_num];
24145 +
24146 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
24147 + hc_set_even_odd_frame(core_if, hc, &hcchar);
24148 + hcchar.b.chen = 1;
24149 + hcchar.b.chdis = 0;
24150 + DWC_DEBUGPL(DBG_HCDV, " IN xfer: hcchar = 0x%08x\n",
24151 + hcchar.d32);
24152 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
24153 + hc->requests++;
24154 + return 1;
24155 + } else {
24156 + /* OUT transfers. */
24157 + if (hc->xfer_count < hc->xfer_len) {
24158 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
24159 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
24160 + hcchar_data_t hcchar;
24161 + dwc_otg_hc_regs_t *hc_regs;
24162 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
24163 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
24164 + hc_set_even_odd_frame(core_if, hc, &hcchar);
24165 + }
24166 +
24167 + /* Load OUT packet into the appropriate Tx FIFO. */
24168 + dwc_otg_hc_write_packet(core_if, hc);
24169 + hc->requests++;
24170 + return 1;
24171 + } else {
24172 + return 0;
24173 + }
24174 + }
24175 +}
24176 +
24177 +/**
24178 + * Starts a PING transfer. This function should only be called in Slave mode.
24179 + * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled.
24180 + */
24181 +void dwc_otg_hc_do_ping(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
24182 +{
24183 + hcchar_data_t hcchar;
24184 + hctsiz_data_t hctsiz;
24185 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
24186 +
24187 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
24188 +
24189 + hctsiz.d32 = 0;
24190 + hctsiz.b.dopng = 1;
24191 + hctsiz.b.pktcnt = 1;
24192 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
24193 +
24194 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
24195 + hcchar.b.chen = 1;
24196 + hcchar.b.chdis = 0;
24197 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
24198 +}
24199 +
24200 +/*
24201 + * This function writes a packet into the Tx FIFO associated with the Host
24202 + * Channel. For a channel associated with a non-periodic EP, the non-periodic
24203 + * Tx FIFO is written. For a channel associated with a periodic EP, the
24204 + * periodic Tx FIFO is written. This function should only be called in Slave
24205 + * mode.
24206 + *
24207 + * Upon return the xfer_buff and xfer_count fields in _hc are incremented by
24208 + * then number of bytes written to the Tx FIFO.
24209 + */
24210 +void dwc_otg_hc_write_packet(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
24211 +{
24212 + uint32_t i;
24213 + uint32_t remaining_count;
24214 + uint32_t byte_count;
24215 + uint32_t dword_count;
24216 +
24217 + uint32_t *data_buff = (uint32_t *) (hc->xfer_buff);
24218 + uint32_t *data_fifo = core_if->data_fifo[hc->hc_num];
24219 +
24220 + remaining_count = hc->xfer_len - hc->xfer_count;
24221 + if (remaining_count > hc->max_packet) {
24222 + byte_count = hc->max_packet;
24223 + } else {
24224 + byte_count = remaining_count;
24225 + }
24226 +
24227 + dword_count = (byte_count + 3) / 4;
24228 +
24229 + if ((((unsigned long)data_buff) & 0x3) == 0) {
24230 + /* xfer_buff is DWORD aligned. */
24231 + for (i = 0; i < dword_count; i++, data_buff++) {
24232 + DWC_WRITE_REG32(data_fifo, *data_buff);
24233 + }
24234 + } else {
24235 + /* xfer_buff is not DWORD aligned. */
24236 + for (i = 0; i < dword_count; i++, data_buff++) {
24237 + uint32_t data;
24238 + data =
24239 + (data_buff[0] | data_buff[1] << 8 | data_buff[2] <<
24240 + 16 | data_buff[3] << 24);
24241 + DWC_WRITE_REG32(data_fifo, data);
24242 + }
24243 + }
24244 +
24245 + hc->xfer_count += byte_count;
24246 + hc->xfer_buff += byte_count;
24247 +}
24248 +
24249 +/**
24250 + * Gets the current USB frame number. This is the frame number from the last
24251 + * SOF packet.
24252 + */
24253 +uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * core_if)
24254 +{
24255 + dsts_data_t dsts;
24256 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
24257 +
24258 + /* read current frame/microframe number from DSTS register */
24259 + return dsts.b.soffn;
24260 +}
24261 +
24262 +/**
24263 + * Calculates and gets the frame Interval value of HFIR register according PHY
24264 + * type and speed.The application can modify a value of HFIR register only after
24265 + * the Port Enable bit of the Host Port Control and Status register
24266 + * (HPRT.PrtEnaPort) has been set.
24267 +*/
24268 +
24269 +uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if)
24270 +{
24271 + gusbcfg_data_t usbcfg;
24272 + hwcfg2_data_t hwcfg2;
24273 + hprt0_data_t hprt0;
24274 + int clock = 60; // default value
24275 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
24276 + hwcfg2.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
24277 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
24278 + if (!usbcfg.b.physel && usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
24279 + clock = 60;
24280 + if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 3)
24281 + clock = 48;
24282 + if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
24283 + !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
24284 + clock = 30;
24285 + if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
24286 + !usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
24287 + clock = 60;
24288 + if (usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
24289 + !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
24290 + clock = 48;
24291 + if (usbcfg.b.physel && !usbcfg.b.phyif && hwcfg2.b.fs_phy_type == 2)
24292 + clock = 48;
24293 + if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 1)
24294 + clock = 48;
24295 + if (hprt0.b.prtspd == 0)
24296 + /* High speed case */
24297 + return 125 * clock;
24298 + else
24299 + /* FS/LS case */
24300 + return 1000 * clock;
24301 +}
24302 +
24303 +/**
24304 + * This function reads a setup packet from the Rx FIFO into the destination
24305 + * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl)
24306 + * Interrupt routine when a SETUP packet has been received in Slave mode.
24307 + *
24308 + * @param core_if Programming view of DWC_otg controller.
24309 + * @param dest Destination buffer for packet data.
24310 + */
24311 +void dwc_otg_read_setup_packet(dwc_otg_core_if_t * core_if, uint32_t * dest)
24312 +{
24313 + device_grxsts_data_t status;
24314 + /* Get the 8 bytes of a setup transaction data */
24315 +
24316 + /* Pop 2 DWORDS off the receive data FIFO into memory */
24317 + dest[0] = DWC_READ_REG32(core_if->data_fifo[0]);
24318 + dest[1] = DWC_READ_REG32(core_if->data_fifo[0]);
24319 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
24320 + status.d32 =
24321 + DWC_READ_REG32(&core_if->core_global_regs->grxstsp);
24322 + DWC_DEBUGPL(DBG_ANY,
24323 + "EP:%d BCnt:%d " "pktsts:%x Frame:%d(0x%0x)\n",
24324 + status.b.epnum, status.b.bcnt, status.b.pktsts,
24325 + status.b.fn, status.b.fn);
24326 + }
24327 +}
24328 +
24329 +/**
24330 + * This function enables EP0 OUT to receive SETUP packets and configures EP0
24331 + * IN for transmitting packets. It is normally called when the
24332 + * "Enumeration Done" interrupt occurs.
24333 + *
24334 + * @param core_if Programming view of DWC_otg controller.
24335 + * @param ep The EP0 data.
24336 + */
24337 +void dwc_otg_ep0_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24338 +{
24339 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
24340 + dsts_data_t dsts;
24341 + depctl_data_t diepctl;
24342 + depctl_data_t doepctl;
24343 + dctl_data_t dctl = {.d32 = 0 };
24344 +
24345 + ep->stp_rollover = 0;
24346 + /* Read the Device Status and Endpoint 0 Control registers */
24347 + dsts.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dsts);
24348 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
24349 + doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
24350 +
24351 + /* Set the MPS of the IN EP based on the enumeration speed */
24352 + switch (dsts.b.enumspd) {
24353 + case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
24354 + case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
24355 + case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
24356 + diepctl.b.mps = DWC_DEP0CTL_MPS_64;
24357 + break;
24358 + case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
24359 + diepctl.b.mps = DWC_DEP0CTL_MPS_8;
24360 + break;
24361 + }
24362 +
24363 + DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
24364 +
24365 + /* Enable OUT EP for receive */
24366 + if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
24367 + doepctl.b.epena = 1;
24368 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
24369 + }
24370 +#ifdef VERBOSE
24371 + DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
24372 + DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
24373 + DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
24374 + DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
24375 +#endif
24376 + dctl.b.cgnpinnak = 1;
24377 +
24378 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
24379 + DWC_DEBUGPL(DBG_PCDV, "dctl=%0x\n",
24380 + DWC_READ_REG32(&dev_if->dev_global_regs->dctl));
24381 +
24382 +}
24383 +
24384 +/**
24385 + * This function activates an EP. The Device EP control register for
24386 + * the EP is configured as defined in the ep structure. Note: This
24387 + * function is not used for EP0.
24388 + *
24389 + * @param core_if Programming view of DWC_otg controller.
24390 + * @param ep The EP to activate.
24391 + */
24392 +void dwc_otg_ep_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24393 +{
24394 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
24395 + depctl_data_t depctl;
24396 + volatile uint32_t *addr;
24397 + daint_data_t daintmsk = {.d32 = 0 };
24398 + dcfg_data_t dcfg;
24399 + uint8_t i;
24400 +
24401 + DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, ep->num,
24402 + (ep->is_in ? "IN" : "OUT"));
24403 +
24404 +#ifdef DWC_UTE_PER_IO
24405 + ep->xiso_frame_num = 0xFFFFFFFF;
24406 + ep->xiso_active_xfers = 0;
24407 + ep->xiso_queued_xfers = 0;
24408 +#endif
24409 + /* Read DEPCTLn register */
24410 + if (ep->is_in == 1) {
24411 + addr = &dev_if->in_ep_regs[ep->num]->diepctl;
24412 + daintmsk.ep.in = 1 << ep->num;
24413 + } else {
24414 + addr = &dev_if->out_ep_regs[ep->num]->doepctl;
24415 + daintmsk.ep.out = 1 << ep->num;
24416 + }
24417 +
24418 + /* If the EP is already active don't change the EP Control
24419 + * register. */
24420 + depctl.d32 = DWC_READ_REG32(addr);
24421 + if (!depctl.b.usbactep) {
24422 + depctl.b.mps = ep->maxpacket;
24423 + depctl.b.eptype = ep->type;
24424 + depctl.b.txfnum = ep->tx_fifo_num;
24425 +
24426 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24427 + depctl.b.setd0pid = 1; // ???
24428 + } else {
24429 + depctl.b.setd0pid = 1;
24430 + }
24431 + depctl.b.usbactep = 1;
24432 +
24433 + /* Update nextep_seq array and EPMSCNT in DCFG*/
24434 + if (!(depctl.b.eptype & 1) && (ep->is_in == 1)) { // NP IN EP
24435 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
24436 + if (core_if->nextep_seq[i] == core_if->first_in_nextep_seq)
24437 + break;
24438 + }
24439 + core_if->nextep_seq[i] = ep->num;
24440 + core_if->nextep_seq[ep->num] = core_if->first_in_nextep_seq;
24441 + depctl.b.nextep = core_if->nextep_seq[ep->num];
24442 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
24443 + dcfg.b.epmscnt++;
24444 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
24445 +
24446 + DWC_DEBUGPL(DBG_PCDV,
24447 + "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
24448 + __func__, core_if->first_in_nextep_seq);
24449 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
24450 + DWC_DEBUGPL(DBG_PCDV, "%2d\n",
24451 + core_if->nextep_seq[i]);
24452 + }
24453 +
24454 + }
24455 +
24456 +
24457 + DWC_WRITE_REG32(addr, depctl.d32);
24458 + DWC_DEBUGPL(DBG_PCDV, "DEPCTL=%08x\n", DWC_READ_REG32(addr));
24459 + }
24460 +
24461 + /* Enable the Interrupt for this EP */
24462 + if (core_if->multiproc_int_enable) {
24463 + if (ep->is_in == 1) {
24464 + diepmsk_data_t diepmsk = {.d32 = 0 };
24465 + diepmsk.b.xfercompl = 1;
24466 + diepmsk.b.timeout = 1;
24467 + diepmsk.b.epdisabled = 1;
24468 + diepmsk.b.ahberr = 1;
24469 + diepmsk.b.intknepmis = 1;
24470 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
24471 + diepmsk.b.intknepmis = 0;
24472 + diepmsk.b.txfifoundrn = 1; //?????
24473 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24474 + diepmsk.b.nak = 1;
24475 + }
24476 +
24477 +
24478 +
24479 +/*
24480 + if (core_if->dma_desc_enable) {
24481 + diepmsk.b.bna = 1;
24482 + }
24483 +*/
24484 +/*
24485 + if (core_if->dma_enable) {
24486 + doepmsk.b.nak = 1;
24487 + }
24488 +*/
24489 + DWC_WRITE_REG32(&dev_if->dev_global_regs->
24490 + diepeachintmsk[ep->num], diepmsk.d32);
24491 +
24492 + } else {
24493 + doepmsk_data_t doepmsk = {.d32 = 0 };
24494 + doepmsk.b.xfercompl = 1;
24495 + doepmsk.b.ahberr = 1;
24496 + doepmsk.b.epdisabled = 1;
24497 + if (ep->type == DWC_OTG_EP_TYPE_ISOC)
24498 + doepmsk.b.outtknepdis = 1;
24499 +
24500 +/*
24501 +
24502 + if (core_if->dma_desc_enable) {
24503 + doepmsk.b.bna = 1;
24504 + }
24505 +*/
24506 +/*
24507 + doepmsk.b.babble = 1;
24508 + doepmsk.b.nyet = 1;
24509 + doepmsk.b.nak = 1;
24510 +*/
24511 + DWC_WRITE_REG32(&dev_if->dev_global_regs->
24512 + doepeachintmsk[ep->num], doepmsk.d32);
24513 + }
24514 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->deachintmsk,
24515 + 0, daintmsk.d32);
24516 + } else {
24517 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24518 + if (ep->is_in) {
24519 + diepmsk_data_t diepmsk = {.d32 = 0 };
24520 + diepmsk.b.nak = 1;
24521 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk, 0, diepmsk.d32);
24522 + } else {
24523 + doepmsk_data_t doepmsk = {.d32 = 0 };
24524 + doepmsk.b.outtknepdis = 1;
24525 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->doepmsk, 0, doepmsk.d32);
24526 + }
24527 + }
24528 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->daintmsk,
24529 + 0, daintmsk.d32);
24530 + }
24531 +
24532 + DWC_DEBUGPL(DBG_PCDV, "DAINTMSK=%0x\n",
24533 + DWC_READ_REG32(&dev_if->dev_global_regs->daintmsk));
24534 +
24535 + ep->stall_clear_flag = 0;
24536 +
24537 + return;
24538 +}
24539 +
24540 +/**
24541 + * This function deactivates an EP. This is done by clearing the USB Active
24542 + * EP bit in the Device EP control register. Note: This function is not used
24543 + * for EP0. EP0 cannot be deactivated.
24544 + *
24545 + * @param core_if Programming view of DWC_otg controller.
24546 + * @param ep The EP to deactivate.
24547 + */
24548 +void dwc_otg_ep_deactivate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24549 +{
24550 + depctl_data_t depctl = {.d32 = 0 };
24551 + volatile uint32_t *addr;
24552 + daint_data_t daintmsk = {.d32 = 0 };
24553 + dcfg_data_t dcfg;
24554 + uint8_t i = 0;
24555 +
24556 +#ifdef DWC_UTE_PER_IO
24557 + ep->xiso_frame_num = 0xFFFFFFFF;
24558 + ep->xiso_active_xfers = 0;
24559 + ep->xiso_queued_xfers = 0;
24560 +#endif
24561 +
24562 + /* Read DEPCTLn register */
24563 + if (ep->is_in == 1) {
24564 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
24565 + daintmsk.ep.in = 1 << ep->num;
24566 + } else {
24567 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
24568 + daintmsk.ep.out = 1 << ep->num;
24569 + }
24570 +
24571 + depctl.d32 = DWC_READ_REG32(addr);
24572 +
24573 + depctl.b.usbactep = 0;
24574 +
24575 + /* Update nextep_seq array and EPMSCNT in DCFG*/
24576 + if (!(depctl.b.eptype & 1) && ep->is_in == 1) { // NP EP IN
24577 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
24578 + if (core_if->nextep_seq[i] == ep->num)
24579 + break;
24580 + }
24581 + core_if->nextep_seq[i] = core_if->nextep_seq[ep->num];
24582 + if (core_if->first_in_nextep_seq == ep->num)
24583 + core_if->first_in_nextep_seq = i;
24584 + core_if->nextep_seq[ep->num] = 0xff;
24585 + depctl.b.nextep = 0;
24586 + dcfg.d32 =
24587 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
24588 + dcfg.b.epmscnt--;
24589 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
24590 + dcfg.d32);
24591 +
24592 + DWC_DEBUGPL(DBG_PCDV,
24593 + "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
24594 + __func__, core_if->first_in_nextep_seq);
24595 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
24596 + DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
24597 + }
24598 + }
24599 +
24600 + if (ep->is_in == 1)
24601 + depctl.b.txfnum = 0;
24602 +
24603 + if (core_if->dma_desc_enable)
24604 + depctl.b.epdis = 1;
24605 +
24606 + DWC_WRITE_REG32(addr, depctl.d32);
24607 + depctl.d32 = DWC_READ_REG32(addr);
24608 + if (core_if->dma_enable && ep->type == DWC_OTG_EP_TYPE_ISOC
24609 + && depctl.b.epena) {
24610 + depctl_data_t depctl = {.d32 = 0};
24611 + if (ep->is_in) {
24612 + diepint_data_t diepint = {.d32 = 0};
24613 +
24614 + depctl.b.snak = 1;
24615 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24616 + diepctl, depctl.d32);
24617 + do {
24618 + dwc_udelay(10);
24619 + diepint.d32 =
24620 + DWC_READ_REG32(&core_if->
24621 + dev_if->in_ep_regs[ep->num]->
24622 + diepint);
24623 + } while (!diepint.b.inepnakeff);
24624 + diepint.b.inepnakeff = 1;
24625 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24626 + diepint, diepint.d32);
24627 + depctl.d32 = 0;
24628 + depctl.b.epdis = 1;
24629 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24630 + diepctl, depctl.d32);
24631 + do {
24632 + dwc_udelay(10);
24633 + diepint.d32 =
24634 + DWC_READ_REG32(&core_if->
24635 + dev_if->in_ep_regs[ep->num]->
24636 + diepint);
24637 + } while (!diepint.b.epdisabled);
24638 + diepint.b.epdisabled = 1;
24639 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24640 + diepint, diepint.d32);
24641 + } else {
24642 + dctl_data_t dctl = {.d32 = 0};
24643 + gintmsk_data_t gintsts = {.d32 = 0};
24644 + doepint_data_t doepint = {.d32 = 0};
24645 + dctl.b.sgoutnak = 1;
24646 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
24647 + dctl, 0, dctl.d32);
24648 + do {
24649 + dwc_udelay(10);
24650 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
24651 + } while (!gintsts.b.goutnakeff);
24652 + gintsts.d32 = 0;
24653 + gintsts.b.goutnakeff = 1;
24654 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
24655 +
24656 + depctl.d32 = 0;
24657 + depctl.b.epdis = 1;
24658 + depctl.b.snak = 1;
24659 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepctl, depctl.d32);
24660 + do
24661 + {
24662 + dwc_udelay(10);
24663 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
24664 + out_ep_regs[ep->num]->doepint);
24665 + } while (!doepint.b.epdisabled);
24666 +
24667 + doepint.b.epdisabled = 1;
24668 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepint, doepint.d32);
24669 +
24670 + dctl.d32 = 0;
24671 + dctl.b.cgoutnak = 1;
24672 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
24673 + }
24674 + }
24675 +
24676 + /* Disable the Interrupt for this EP */
24677 + if (core_if->multiproc_int_enable) {
24678 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
24679 + daintmsk.d32, 0);
24680 +
24681 + if (ep->is_in == 1) {
24682 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
24683 + diepeachintmsk[ep->num], 0);
24684 + } else {
24685 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
24686 + doepeachintmsk[ep->num], 0);
24687 + }
24688 + } else {
24689 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->daintmsk,
24690 + daintmsk.d32, 0);
24691 + }
24692 +
24693 +}
24694 +
24695 +/**
24696 + * This function initializes dma descriptor chain.
24697 + *
24698 + * @param core_if Programming view of DWC_otg controller.
24699 + * @param ep The EP to start the transfer on.
24700 + */
24701 +static void init_dma_desc_chain(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24702 +{
24703 + dwc_otg_dev_dma_desc_t *dma_desc;
24704 + uint32_t offset;
24705 + uint32_t xfer_est;
24706 + int i;
24707 + unsigned maxxfer_local, total_len;
24708 +
24709 + if (!ep->is_in && ep->type == DWC_OTG_EP_TYPE_INTR &&
24710 + (ep->maxpacket%4)) {
24711 + maxxfer_local = ep->maxpacket;
24712 + total_len = ep->xfer_len;
24713 + } else {
24714 + maxxfer_local = ep->maxxfer;
24715 + total_len = ep->total_len;
24716 + }
24717 +
24718 + ep->desc_cnt = (total_len / maxxfer_local) +
24719 + ((total_len % maxxfer_local) ? 1 : 0);
24720 +
24721 + if (!ep->desc_cnt)
24722 + ep->desc_cnt = 1;
24723 +
24724 + if (ep->desc_cnt > MAX_DMA_DESC_CNT)
24725 + ep->desc_cnt = MAX_DMA_DESC_CNT;
24726 +
24727 + dma_desc = ep->desc_addr;
24728 + if (maxxfer_local == ep->maxpacket) {
24729 + if ((total_len % maxxfer_local) &&
24730 + (total_len/maxxfer_local < MAX_DMA_DESC_CNT)) {
24731 + xfer_est = (ep->desc_cnt - 1) * maxxfer_local +
24732 + (total_len % maxxfer_local);
24733 + } else
24734 + xfer_est = ep->desc_cnt * maxxfer_local;
24735 + } else
24736 + xfer_est = total_len;
24737 + offset = 0;
24738 + for (i = 0; i < ep->desc_cnt; ++i) {
24739 + /** DMA Descriptor Setup */
24740 + if (xfer_est > maxxfer_local) {
24741 + dma_desc->status.b.bs = BS_HOST_BUSY;
24742 + dma_desc->status.b.l = 0;
24743 + dma_desc->status.b.ioc = 0;
24744 + dma_desc->status.b.sp = 0;
24745 + dma_desc->status.b.bytes = maxxfer_local;
24746 + dma_desc->buf = ep->dma_addr + offset;
24747 + dma_desc->status.b.sts = 0;
24748 + dma_desc->status.b.bs = BS_HOST_READY;
24749 +
24750 + xfer_est -= maxxfer_local;
24751 + offset += maxxfer_local;
24752 + } else {
24753 + dma_desc->status.b.bs = BS_HOST_BUSY;
24754 + dma_desc->status.b.l = 1;
24755 + dma_desc->status.b.ioc = 1;
24756 + if (ep->is_in) {
24757 + dma_desc->status.b.sp =
24758 + (xfer_est %
24759 + ep->maxpacket) ? 1 : ((ep->
24760 + sent_zlp) ? 1 : 0);
24761 + dma_desc->status.b.bytes = xfer_est;
24762 + } else {
24763 + if (maxxfer_local == ep->maxpacket)
24764 + dma_desc->status.b.bytes = xfer_est;
24765 + else
24766 + dma_desc->status.b.bytes =
24767 + xfer_est + ((4 - (xfer_est & 0x3)) & 0x3);
24768 + }
24769 +
24770 + dma_desc->buf = ep->dma_addr + offset;
24771 + dma_desc->status.b.sts = 0;
24772 + dma_desc->status.b.bs = BS_HOST_READY;
24773 + }
24774 + dma_desc++;
24775 + }
24776 +}
24777 +/**
24778 + * This function is called when to write ISOC data into appropriate dedicated
24779 + * periodic FIFO.
24780 + */
24781 +static int32_t write_isoc_tx_fifo(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
24782 +{
24783 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
24784 + dwc_otg_dev_in_ep_regs_t *ep_regs;
24785 + dtxfsts_data_t txstatus = {.d32 = 0 };
24786 + uint32_t len = 0;
24787 + int epnum = dwc_ep->num;
24788 + int dwords;
24789 +
24790 + DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
24791 +
24792 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
24793 +
24794 + len = dwc_ep->xfer_len - dwc_ep->xfer_count;
24795 +
24796 + if (len > dwc_ep->maxpacket) {
24797 + len = dwc_ep->maxpacket;
24798 + }
24799 +
24800 + dwords = (len + 3) / 4;
24801 +
24802 + /* While there is space in the queue and space in the FIFO and
24803 + * More data to tranfer, Write packets to the Tx FIFO */
24804 + txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
24805 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
24806 +
24807 + while (txstatus.b.txfspcavail > dwords &&
24808 + dwc_ep->xfer_count < dwc_ep->xfer_len && dwc_ep->xfer_len != 0) {
24809 + /* Write the FIFO */
24810 + dwc_otg_ep_write_packet(core_if, dwc_ep, 0);
24811 +
24812 + len = dwc_ep->xfer_len - dwc_ep->xfer_count;
24813 + if (len > dwc_ep->maxpacket) {
24814 + len = dwc_ep->maxpacket;
24815 + }
24816 +
24817 + dwords = (len + 3) / 4;
24818 + txstatus.d32 =
24819 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
24820 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
24821 + txstatus.d32);
24822 + }
24823 +
24824 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
24825 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
24826 +
24827 + return 1;
24828 +}
24829 +/**
24830 + * This function does the setup for a data transfer for an EP and
24831 + * starts the transfer. For an IN transfer, the packets will be
24832 + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
24833 + * the packets are unloaded from the Rx FIFO in the ISR. the ISR.
24834 + *
24835 + * @param core_if Programming view of DWC_otg controller.
24836 + * @param ep The EP to start the transfer on.
24837 + */
24838 +
24839 +void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24840 +{
24841 + depctl_data_t depctl;
24842 + deptsiz_data_t deptsiz;
24843 + gintmsk_data_t intr_mask = {.d32 = 0 };
24844 +
24845 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
24846 + DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
24847 + "xfer_buff=%p start_xfer_buff=%p, total_len = %d\n",
24848 + ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
24849 + ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff,
24850 + ep->total_len);
24851 + /* IN endpoint */
24852 + if (ep->is_in == 1) {
24853 + dwc_otg_dev_in_ep_regs_t *in_regs =
24854 + core_if->dev_if->in_ep_regs[ep->num];
24855 +
24856 + gnptxsts_data_t gtxstatus;
24857 +
24858 + gtxstatus.d32 =
24859 + DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
24860 +
24861 + if (core_if->en_multiple_tx_fifo == 0
24862 + && gtxstatus.b.nptxqspcavail == 0 && !core_if->dma_enable) {
24863 +#ifdef DEBUG
24864 + DWC_PRINTF("TX Queue Full (0x%0x)\n", gtxstatus.d32);
24865 +#endif
24866 + return;
24867 + }
24868 +
24869 + depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
24870 + deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
24871 +
24872 + if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
24873 + ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
24874 + ep->maxxfer : (ep->total_len - ep->xfer_len);
24875 + else
24876 + ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len - ep->xfer_len)) ?
24877 + MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
24878 +
24879 +
24880 + /* Zero Length Packet? */
24881 + if ((ep->xfer_len - ep->xfer_count) == 0) {
24882 + deptsiz.b.xfersize = 0;
24883 + deptsiz.b.pktcnt = 1;
24884 + } else {
24885 + /* Program the transfer size and packet count
24886 + * as follows: xfersize = N * maxpacket +
24887 + * short_packet pktcnt = N + (short_packet
24888 + * exist ? 1 : 0)
24889 + */
24890 + deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
24891 + deptsiz.b.pktcnt =
24892 + (ep->xfer_len - ep->xfer_count - 1 +
24893 + ep->maxpacket) / ep->maxpacket;
24894 + if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
24895 + deptsiz.b.pktcnt = MAX_PKT_CNT;
24896 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
24897 + }
24898 + if (ep->type == DWC_OTG_EP_TYPE_ISOC)
24899 + deptsiz.b.mc = deptsiz.b.pktcnt;
24900 + }
24901 +
24902 + /* Write the DMA register */
24903 + if (core_if->dma_enable) {
24904 + if (core_if->dma_desc_enable == 0) {
24905 + if (ep->type != DWC_OTG_EP_TYPE_ISOC)
24906 + deptsiz.b.mc = 1;
24907 + DWC_WRITE_REG32(&in_regs->dieptsiz,
24908 + deptsiz.d32);
24909 + DWC_WRITE_REG32(&(in_regs->diepdma),
24910 + (uint32_t) ep->dma_addr);
24911 + } else {
24912 +#ifdef DWC_UTE_CFI
24913 + /* The descriptor chain should be already initialized by now */
24914 + if (ep->buff_mode != BM_STANDARD) {
24915 + DWC_WRITE_REG32(&in_regs->diepdma,
24916 + ep->descs_dma_addr);
24917 + } else {
24918 +#endif
24919 + init_dma_desc_chain(core_if, ep);
24920 + /** DIEPDMAn Register write */
24921 + DWC_WRITE_REG32(&in_regs->diepdma,
24922 + ep->dma_desc_addr);
24923 +#ifdef DWC_UTE_CFI
24924 + }
24925 +#endif
24926 + }
24927 + } else {
24928 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
24929 + if (ep->type != DWC_OTG_EP_TYPE_ISOC) {
24930 + /**
24931 + * Enable the Non-Periodic Tx FIFO empty interrupt,
24932 + * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
24933 + * the data will be written into the fifo by the ISR.
24934 + */
24935 + if (core_if->en_multiple_tx_fifo == 0) {
24936 + intr_mask.b.nptxfempty = 1;
24937 + DWC_MODIFY_REG32
24938 + (&core_if->core_global_regs->gintmsk,
24939 + intr_mask.d32, intr_mask.d32);
24940 + } else {
24941 + /* Enable the Tx FIFO Empty Interrupt for this EP */
24942 + if (ep->xfer_len > 0) {
24943 + uint32_t fifoemptymsk = 0;
24944 + fifoemptymsk = 1 << ep->num;
24945 + DWC_MODIFY_REG32
24946 + (&core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
24947 + 0, fifoemptymsk);
24948 +
24949 + }
24950 + }
24951 + } else {
24952 + write_isoc_tx_fifo(core_if, ep);
24953 + }
24954 + }
24955 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
24956 + depctl.b.nextep = core_if->nextep_seq[ep->num];
24957 +
24958 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24959 + dsts_data_t dsts = {.d32 = 0};
24960 + if (ep->bInterval == 1) {
24961 + dsts.d32 =
24962 + DWC_READ_REG32(&core_if->dev_if->
24963 + dev_global_regs->dsts);
24964 + ep->frame_num = dsts.b.soffn + ep->bInterval;
24965 + if (ep->frame_num > 0x3FFF) {
24966 + ep->frm_overrun = 1;
24967 + ep->frame_num &= 0x3FFF;
24968 + } else
24969 + ep->frm_overrun = 0;
24970 + if (ep->frame_num & 0x1) {
24971 + depctl.b.setd1pid = 1;
24972 + } else {
24973 + depctl.b.setd0pid = 1;
24974 + }
24975 + }
24976 + }
24977 + /* EP enable, IN data in FIFO */
24978 + depctl.b.cnak = 1;
24979 + depctl.b.epena = 1;
24980 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
24981 +
24982 + } else {
24983 + /* OUT endpoint */
24984 + dwc_otg_dev_out_ep_regs_t *out_regs =
24985 + core_if->dev_if->out_ep_regs[ep->num];
24986 +
24987 + depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
24988 + deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
24989 +
24990 + if (!core_if->dma_desc_enable) {
24991 + if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
24992 + ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
24993 + ep->maxxfer : (ep->total_len - ep->xfer_len);
24994 + else
24995 + ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len
24996 + - ep->xfer_len)) ? MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
24997 + }
24998 +
24999 + /* Program the transfer size and packet count as follows:
25000 + *
25001 + * pktcnt = N
25002 + * xfersize = N * maxpacket
25003 + */
25004 + if ((ep->xfer_len - ep->xfer_count) == 0) {
25005 + /* Zero Length Packet */
25006 + deptsiz.b.xfersize = ep->maxpacket;
25007 + deptsiz.b.pktcnt = 1;
25008 + } else {
25009 + deptsiz.b.pktcnt =
25010 + (ep->xfer_len - ep->xfer_count +
25011 + (ep->maxpacket - 1)) / ep->maxpacket;
25012 + if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
25013 + deptsiz.b.pktcnt = MAX_PKT_CNT;
25014 + }
25015 + if (!core_if->dma_desc_enable) {
25016 + ep->xfer_len =
25017 + deptsiz.b.pktcnt * ep->maxpacket + ep->xfer_count;
25018 + }
25019 + deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
25020 + }
25021 +
25022 + DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n",
25023 + ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt);
25024 +
25025 + if (core_if->dma_enable) {
25026 + if (!core_if->dma_desc_enable) {
25027 + DWC_WRITE_REG32(&out_regs->doeptsiz,
25028 + deptsiz.d32);
25029 +
25030 + DWC_WRITE_REG32(&(out_regs->doepdma),
25031 + (uint32_t) ep->dma_addr);
25032 + } else {
25033 +#ifdef DWC_UTE_CFI
25034 + /* The descriptor chain should be already initialized by now */
25035 + if (ep->buff_mode != BM_STANDARD) {
25036 + DWC_WRITE_REG32(&out_regs->doepdma,
25037 + ep->descs_dma_addr);
25038 + } else {
25039 +#endif
25040 + /** This is used for interrupt out transfers*/
25041 + if (!ep->xfer_len)
25042 + ep->xfer_len = ep->total_len;
25043 + init_dma_desc_chain(core_if, ep);
25044 +
25045 + if (core_if->core_params->dev_out_nak) {
25046 + if (ep->type == DWC_OTG_EP_TYPE_BULK) {
25047 + deptsiz.b.pktcnt = (ep->total_len +
25048 + (ep->maxpacket - 1)) / ep->maxpacket;
25049 + deptsiz.b.xfersize = ep->total_len;
25050 + /* Remember initial value of doeptsiz */
25051 + core_if->start_doeptsiz_val[ep->num] = deptsiz.d32;
25052 + DWC_WRITE_REG32(&out_regs->doeptsiz,
25053 + deptsiz.d32);
25054 + }
25055 + }
25056 + /** DOEPDMAn Register write */
25057 + DWC_WRITE_REG32(&out_regs->doepdma,
25058 + ep->dma_desc_addr);
25059 +#ifdef DWC_UTE_CFI
25060 + }
25061 +#endif
25062 + }
25063 + } else {
25064 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25065 + }
25066 +
25067 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
25068 + dsts_data_t dsts = {.d32 = 0};
25069 + if (ep->bInterval == 1) {
25070 + dsts.d32 =
25071 + DWC_READ_REG32(&core_if->dev_if->
25072 + dev_global_regs->dsts);
25073 + ep->frame_num = dsts.b.soffn + ep->bInterval;
25074 + if (ep->frame_num > 0x3FFF) {
25075 + ep->frm_overrun = 1;
25076 + ep->frame_num &= 0x3FFF;
25077 + } else
25078 + ep->frm_overrun = 0;
25079 +
25080 + if (ep->frame_num & 0x1) {
25081 + depctl.b.setd1pid = 1;
25082 + } else {
25083 + depctl.b.setd0pid = 1;
25084 + }
25085 + }
25086 + }
25087 +
25088 + /* EP enable */
25089 + depctl.b.cnak = 1;
25090 + depctl.b.epena = 1;
25091 +
25092 + DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
25093 +
25094 + DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n",
25095 + DWC_READ_REG32(&out_regs->doepctl),
25096 + DWC_READ_REG32(&out_regs->doeptsiz));
25097 + DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
25098 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
25099 + daintmsk),
25100 + DWC_READ_REG32(&core_if->core_global_regs->
25101 + gintmsk));
25102 +
25103 + /* Timer is scheduling only for out bulk transfers for
25104 + * "Device DDMA OUT NAK Enhancement" feature to inform user
25105 + * about received data payload in case of timeout
25106 + */
25107 + if (core_if->core_params->dev_out_nak) {
25108 + if (ep->type == DWC_OTG_EP_TYPE_BULK) {
25109 + core_if->ep_xfer_info[ep->num].core_if = core_if;
25110 + core_if->ep_xfer_info[ep->num].ep = ep;
25111 + core_if->ep_xfer_info[ep->num].state = 1;
25112 +
25113 + /* Start a timer for this transfer. */
25114 + DWC_TIMER_SCHEDULE(core_if->ep_xfer_timer[ep->num], 10000);
25115 + }
25116 + }
25117 + }
25118 +}
25119 +
25120 +/**
25121 + * This function setup a zero length transfer in Buffer DMA and
25122 + * Slave modes for usb requests with zero field set
25123 + *
25124 + * @param core_if Programming view of DWC_otg controller.
25125 + * @param ep The EP to start the transfer on.
25126 + *
25127 + */
25128 +void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25129 +{
25130 +
25131 + depctl_data_t depctl;
25132 + deptsiz_data_t deptsiz;
25133 + gintmsk_data_t intr_mask = {.d32 = 0 };
25134 +
25135 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
25136 + DWC_PRINTF("zero length transfer is called\n");
25137 +
25138 + /* IN endpoint */
25139 + if (ep->is_in == 1) {
25140 + dwc_otg_dev_in_ep_regs_t *in_regs =
25141 + core_if->dev_if->in_ep_regs[ep->num];
25142 +
25143 + depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
25144 + deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
25145 +
25146 + deptsiz.b.xfersize = 0;
25147 + deptsiz.b.pktcnt = 1;
25148 +
25149 + /* Write the DMA register */
25150 + if (core_if->dma_enable) {
25151 + if (core_if->dma_desc_enable == 0) {
25152 + deptsiz.b.mc = 1;
25153 + DWC_WRITE_REG32(&in_regs->dieptsiz,
25154 + deptsiz.d32);
25155 + DWC_WRITE_REG32(&(in_regs->diepdma),
25156 + (uint32_t) ep->dma_addr);
25157 + }
25158 + } else {
25159 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
25160 + /**
25161 + * Enable the Non-Periodic Tx FIFO empty interrupt,
25162 + * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
25163 + * the data will be written into the fifo by the ISR.
25164 + */
25165 + if (core_if->en_multiple_tx_fifo == 0) {
25166 + intr_mask.b.nptxfempty = 1;
25167 + DWC_MODIFY_REG32(&core_if->
25168 + core_global_regs->gintmsk,
25169 + intr_mask.d32, intr_mask.d32);
25170 + } else {
25171 + /* Enable the Tx FIFO Empty Interrupt for this EP */
25172 + if (ep->xfer_len > 0) {
25173 + uint32_t fifoemptymsk = 0;
25174 + fifoemptymsk = 1 << ep->num;
25175 + DWC_MODIFY_REG32(&core_if->
25176 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
25177 + 0, fifoemptymsk);
25178 + }
25179 + }
25180 + }
25181 +
25182 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
25183 + depctl.b.nextep = core_if->nextep_seq[ep->num];
25184 + /* EP enable, IN data in FIFO */
25185 + depctl.b.cnak = 1;
25186 + depctl.b.epena = 1;
25187 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
25188 +
25189 + } else {
25190 + /* OUT endpoint */
25191 + dwc_otg_dev_out_ep_regs_t *out_regs =
25192 + core_if->dev_if->out_ep_regs[ep->num];
25193 +
25194 + depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
25195 + deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
25196 +
25197 + /* Zero Length Packet */
25198 + deptsiz.b.xfersize = ep->maxpacket;
25199 + deptsiz.b.pktcnt = 1;
25200 +
25201 + if (core_if->dma_enable) {
25202 + if (!core_if->dma_desc_enable) {
25203 + DWC_WRITE_REG32(&out_regs->doeptsiz,
25204 + deptsiz.d32);
25205 +
25206 + DWC_WRITE_REG32(&(out_regs->doepdma),
25207 + (uint32_t) ep->dma_addr);
25208 + }
25209 + } else {
25210 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25211 + }
25212 +
25213 + /* EP enable */
25214 + depctl.b.cnak = 1;
25215 + depctl.b.epena = 1;
25216 +
25217 + DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
25218 +
25219 + }
25220 +}
25221 +
25222 +/**
25223 + * This function does the setup for a data transfer for EP0 and starts
25224 + * the transfer. For an IN transfer, the packets will be loaded into
25225 + * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are
25226 + * unloaded from the Rx FIFO in the ISR.
25227 + *
25228 + * @param core_if Programming view of DWC_otg controller.
25229 + * @param ep The EP0 data.
25230 + */
25231 +void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25232 +{
25233 + depctl_data_t depctl;
25234 + deptsiz0_data_t deptsiz;
25235 + gintmsk_data_t intr_mask = {.d32 = 0 };
25236 + dwc_otg_dev_dma_desc_t *dma_desc;
25237 +
25238 + DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
25239 + "xfer_buff=%p start_xfer_buff=%p \n",
25240 + ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
25241 + ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff);
25242 +
25243 + ep->total_len = ep->xfer_len;
25244 +
25245 + /* IN endpoint */
25246 + if (ep->is_in == 1) {
25247 + dwc_otg_dev_in_ep_regs_t *in_regs =
25248 + core_if->dev_if->in_ep_regs[0];
25249 +
25250 + gnptxsts_data_t gtxstatus;
25251 +
25252 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
25253 + depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
25254 + if (depctl.b.epena)
25255 + return;
25256 + }
25257 +
25258 + gtxstatus.d32 =
25259 + DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
25260 +
25261 + /* If dedicated FIFO every time flush fifo before enable ep*/
25262 + if (core_if->en_multiple_tx_fifo && core_if->snpsid >= OTG_CORE_REV_3_00a)
25263 + dwc_otg_flush_tx_fifo(core_if, ep->tx_fifo_num);
25264 +
25265 + if (core_if->en_multiple_tx_fifo == 0
25266 + && gtxstatus.b.nptxqspcavail == 0
25267 + && !core_if->dma_enable) {
25268 +#ifdef DEBUG
25269 + deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
25270 + DWC_DEBUGPL(DBG_PCD, "DIEPCTL0=%0x\n",
25271 + DWC_READ_REG32(&in_regs->diepctl));
25272 + DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n",
25273 + deptsiz.d32,
25274 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
25275 + DWC_PRINTF("TX Queue or FIFO Full (0x%0x)\n",
25276 + gtxstatus.d32);
25277 +#endif
25278 + return;
25279 + }
25280 +
25281 + depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
25282 + deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
25283 +
25284 + /* Zero Length Packet? */
25285 + if (ep->xfer_len == 0) {
25286 + deptsiz.b.xfersize = 0;
25287 + deptsiz.b.pktcnt = 1;
25288 + } else {
25289 + /* Program the transfer size and packet count
25290 + * as follows: xfersize = N * maxpacket +
25291 + * short_packet pktcnt = N + (short_packet
25292 + * exist ? 1 : 0)
25293 + */
25294 + if (ep->xfer_len > ep->maxpacket) {
25295 + ep->xfer_len = ep->maxpacket;
25296 + deptsiz.b.xfersize = ep->maxpacket;
25297 + } else {
25298 + deptsiz.b.xfersize = ep->xfer_len;
25299 + }
25300 + deptsiz.b.pktcnt = 1;
25301 +
25302 + }
25303 + DWC_DEBUGPL(DBG_PCDV,
25304 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
25305 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
25306 + deptsiz.d32);
25307 +
25308 + /* Write the DMA register */
25309 + if (core_if->dma_enable) {
25310 + if (core_if->dma_desc_enable == 0) {
25311 + DWC_WRITE_REG32(&in_regs->dieptsiz,
25312 + deptsiz.d32);
25313 +
25314 + DWC_WRITE_REG32(&(in_regs->diepdma),
25315 + (uint32_t) ep->dma_addr);
25316 + } else {
25317 + dma_desc = core_if->dev_if->in_desc_addr;
25318 +
25319 + /** DMA Descriptor Setup */
25320 + dma_desc->status.b.bs = BS_HOST_BUSY;
25321 + dma_desc->status.b.l = 1;
25322 + dma_desc->status.b.ioc = 1;
25323 + dma_desc->status.b.sp =
25324 + (ep->xfer_len == ep->maxpacket) ? 0 : 1;
25325 + dma_desc->status.b.bytes = ep->xfer_len;
25326 + dma_desc->buf = ep->dma_addr;
25327 + dma_desc->status.b.sts = 0;
25328 + dma_desc->status.b.bs = BS_HOST_READY;
25329 +
25330 + /** DIEPDMA0 Register write */
25331 + DWC_WRITE_REG32(&in_regs->diepdma,
25332 + core_if->
25333 + dev_if->dma_in_desc_addr);
25334 + }
25335 + } else {
25336 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
25337 + }
25338 +
25339 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
25340 + depctl.b.nextep = core_if->nextep_seq[ep->num];
25341 + /* EP enable, IN data in FIFO */
25342 + depctl.b.cnak = 1;
25343 + depctl.b.epena = 1;
25344 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
25345 +
25346 + /**
25347 + * Enable the Non-Periodic Tx FIFO empty interrupt, the
25348 + * data will be written into the fifo by the ISR.
25349 + */
25350 + if (!core_if->dma_enable) {
25351 + if (core_if->en_multiple_tx_fifo == 0) {
25352 + intr_mask.b.nptxfempty = 1;
25353 + DWC_MODIFY_REG32(&core_if->
25354 + core_global_regs->gintmsk,
25355 + intr_mask.d32, intr_mask.d32);
25356 + } else {
25357 + /* Enable the Tx FIFO Empty Interrupt for this EP */
25358 + if (ep->xfer_len > 0) {
25359 + uint32_t fifoemptymsk = 0;
25360 + fifoemptymsk |= 1 << ep->num;
25361 + DWC_MODIFY_REG32(&core_if->
25362 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
25363 + 0, fifoemptymsk);
25364 + }
25365 + }
25366 + }
25367 + } else {
25368 + /* OUT endpoint */
25369 + dwc_otg_dev_out_ep_regs_t *out_regs =
25370 + core_if->dev_if->out_ep_regs[0];
25371 +
25372 + depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
25373 + deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
25374 +
25375 + /* Program the transfer size and packet count as follows:
25376 + * xfersize = N * (maxpacket + 4 - (maxpacket % 4))
25377 + * pktcnt = N */
25378 + /* Zero Length Packet */
25379 + deptsiz.b.xfersize = ep->maxpacket;
25380 + deptsiz.b.pktcnt = 1;
25381 + if (core_if->snpsid >= OTG_CORE_REV_3_00a)
25382 + deptsiz.b.supcnt = 3;
25383 +
25384 + DWC_DEBUGPL(DBG_PCDV, "len=%d xfersize=%d pktcnt=%d\n",
25385 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt);
25386 +
25387 + if (core_if->dma_enable) {
25388 + if (!core_if->dma_desc_enable) {
25389 + DWC_WRITE_REG32(&out_regs->doeptsiz,
25390 + deptsiz.d32);
25391 +
25392 + DWC_WRITE_REG32(&(out_regs->doepdma),
25393 + (uint32_t) ep->dma_addr);
25394 + } else {
25395 + dma_desc = core_if->dev_if->out_desc_addr;
25396 +
25397 + /** DMA Descriptor Setup */
25398 + dma_desc->status.b.bs = BS_HOST_BUSY;
25399 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
25400 + dma_desc->status.b.mtrf = 0;
25401 + dma_desc->status.b.sr = 0;
25402 + }
25403 + dma_desc->status.b.l = 1;
25404 + dma_desc->status.b.ioc = 1;
25405 + dma_desc->status.b.bytes = ep->maxpacket;
25406 + dma_desc->buf = ep->dma_addr;
25407 + dma_desc->status.b.sts = 0;
25408 + dma_desc->status.b.bs = BS_HOST_READY;
25409 +
25410 + /** DOEPDMA0 Register write */
25411 + DWC_WRITE_REG32(&out_regs->doepdma,
25412 + core_if->dev_if->
25413 + dma_out_desc_addr);
25414 + }
25415 + } else {
25416 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25417 + }
25418 +
25419 + /* EP enable */
25420 + depctl.b.cnak = 1;
25421 + depctl.b.epena = 1;
25422 + DWC_WRITE_REG32(&(out_regs->doepctl), depctl.d32);
25423 + }
25424 +}
25425 +
25426 +/**
25427 + * This function continues control IN transfers started by
25428 + * dwc_otg_ep0_start_transfer, when the transfer does not fit in a
25429 + * single packet. NOTE: The DIEPCTL0/DOEPCTL0 registers only have one
25430 + * bit for the packet count.
25431 + *
25432 + * @param core_if Programming view of DWC_otg controller.
25433 + * @param ep The EP0 data.
25434 + */
25435 +void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25436 +{
25437 + depctl_data_t depctl;
25438 + deptsiz0_data_t deptsiz;
25439 + gintmsk_data_t intr_mask = {.d32 = 0 };
25440 + dwc_otg_dev_dma_desc_t *dma_desc;
25441 +
25442 + if (ep->is_in == 1) {
25443 + dwc_otg_dev_in_ep_regs_t *in_regs =
25444 + core_if->dev_if->in_ep_regs[0];
25445 + gnptxsts_data_t tx_status = {.d32 = 0 };
25446 +
25447 + tx_status.d32 =
25448 + DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
25449 + /** @todo Should there be check for room in the Tx
25450 + * Status Queue. If not remove the code above this comment. */
25451 +
25452 + depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
25453 + deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
25454 +
25455 + /* Program the transfer size and packet count
25456 + * as follows: xfersize = N * maxpacket +
25457 + * short_packet pktcnt = N + (short_packet
25458 + * exist ? 1 : 0)
25459 + */
25460 +
25461 + if (core_if->dma_desc_enable == 0) {
25462 + deptsiz.b.xfersize =
25463 + (ep->total_len - ep->xfer_count) >
25464 + ep->maxpacket ? ep->maxpacket : (ep->total_len -
25465 + ep->xfer_count);
25466 + deptsiz.b.pktcnt = 1;
25467 + if (core_if->dma_enable == 0) {
25468 + ep->xfer_len += deptsiz.b.xfersize;
25469 + } else {
25470 + ep->xfer_len = deptsiz.b.xfersize;
25471 + }
25472 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
25473 + } else {
25474 + ep->xfer_len =
25475 + (ep->total_len - ep->xfer_count) >
25476 + ep->maxpacket ? ep->maxpacket : (ep->total_len -
25477 + ep->xfer_count);
25478 +
25479 + dma_desc = core_if->dev_if->in_desc_addr;
25480 +
25481 + /** DMA Descriptor Setup */
25482 + dma_desc->status.b.bs = BS_HOST_BUSY;
25483 + dma_desc->status.b.l = 1;
25484 + dma_desc->status.b.ioc = 1;
25485 + dma_desc->status.b.sp =
25486 + (ep->xfer_len == ep->maxpacket) ? 0 : 1;
25487 + dma_desc->status.b.bytes = ep->xfer_len;
25488 + dma_desc->buf = ep->dma_addr;
25489 + dma_desc->status.b.sts = 0;
25490 + dma_desc->status.b.bs = BS_HOST_READY;
25491 +
25492 + /** DIEPDMA0 Register write */
25493 + DWC_WRITE_REG32(&in_regs->diepdma,
25494 + core_if->dev_if->dma_in_desc_addr);
25495 + }
25496 +
25497 + DWC_DEBUGPL(DBG_PCDV,
25498 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
25499 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
25500 + deptsiz.d32);
25501 +
25502 + /* Write the DMA register */
25503 + if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
25504 + if (core_if->dma_desc_enable == 0)
25505 + DWC_WRITE_REG32(&(in_regs->diepdma),
25506 + (uint32_t) ep->dma_addr);
25507 + }
25508 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
25509 + depctl.b.nextep = core_if->nextep_seq[ep->num];
25510 + /* EP enable, IN data in FIFO */
25511 + depctl.b.cnak = 1;
25512 + depctl.b.epena = 1;
25513 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
25514 +
25515 + /**
25516 + * Enable the Non-Periodic Tx FIFO empty interrupt, the
25517 + * data will be written into the fifo by the ISR.
25518 + */
25519 + if (!core_if->dma_enable) {
25520 + if (core_if->en_multiple_tx_fifo == 0) {
25521 + /* First clear it from GINTSTS */
25522 + intr_mask.b.nptxfempty = 1;
25523 + DWC_MODIFY_REG32(&core_if->
25524 + core_global_regs->gintmsk,
25525 + intr_mask.d32, intr_mask.d32);
25526 +
25527 + } else {
25528 + /* Enable the Tx FIFO Empty Interrupt for this EP */
25529 + if (ep->xfer_len > 0) {
25530 + uint32_t fifoemptymsk = 0;
25531 + fifoemptymsk |= 1 << ep->num;
25532 + DWC_MODIFY_REG32(&core_if->
25533 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
25534 + 0, fifoemptymsk);
25535 + }
25536 + }
25537 + }
25538 + } else {
25539 + dwc_otg_dev_out_ep_regs_t *out_regs =
25540 + core_if->dev_if->out_ep_regs[0];
25541 +
25542 + depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
25543 + deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
25544 +
25545 + /* Program the transfer size and packet count
25546 + * as follows: xfersize = N * maxpacket +
25547 + * short_packet pktcnt = N + (short_packet
25548 + * exist ? 1 : 0)
25549 + */
25550 + deptsiz.b.xfersize = ep->maxpacket;
25551 + deptsiz.b.pktcnt = 1;
25552 +
25553 + if (core_if->dma_desc_enable == 0) {
25554 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25555 + } else {
25556 + dma_desc = core_if->dev_if->out_desc_addr;
25557 +
25558 + /** DMA Descriptor Setup */
25559 + dma_desc->status.b.bs = BS_HOST_BUSY;
25560 + dma_desc->status.b.l = 1;
25561 + dma_desc->status.b.ioc = 1;
25562 + dma_desc->status.b.bytes = ep->maxpacket;
25563 + dma_desc->buf = ep->dma_addr;
25564 + dma_desc->status.b.sts = 0;
25565 + dma_desc->status.b.bs = BS_HOST_READY;
25566 +
25567 + /** DOEPDMA0 Register write */
25568 + DWC_WRITE_REG32(&out_regs->doepdma,
25569 + core_if->dev_if->dma_out_desc_addr);
25570 + }
25571 +
25572 + DWC_DEBUGPL(DBG_PCDV,
25573 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
25574 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
25575 + deptsiz.d32);
25576 +
25577 + /* Write the DMA register */
25578 + if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
25579 + if (core_if->dma_desc_enable == 0)
25580 + DWC_WRITE_REG32(&(out_regs->doepdma),
25581 + (uint32_t) ep->dma_addr);
25582 +
25583 + }
25584 +
25585 + /* EP enable, IN data in FIFO */
25586 + depctl.b.cnak = 1;
25587 + depctl.b.epena = 1;
25588 + DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
25589 +
25590 + }
25591 +}
25592 +
25593 +#ifdef DEBUG
25594 +void dump_msg(const u8 * buf, unsigned int length)
25595 +{
25596 + unsigned int start, num, i;
25597 + char line[52], *p;
25598 +
25599 + if (length >= 512)
25600 + return;
25601 + start = 0;
25602 + while (length > 0) {
25603 + num = length < 16u ? length : 16u;
25604 + p = line;
25605 + for (i = 0; i < num; ++i) {
25606 + if (i == 8)
25607 + *p++ = ' ';
25608 + DWC_SPRINTF(p, " %02x", buf[i]);
25609 + p += 3;
25610 + }
25611 + *p = 0;
25612 + DWC_PRINTF("%6x: %s\n", start, line);
25613 + buf += num;
25614 + start += num;
25615 + length -= num;
25616 + }
25617 +}
25618 +#else
25619 +static inline void dump_msg(const u8 * buf, unsigned int length)
25620 +{
25621 +}
25622 +#endif
25623 +
25624 +/**
25625 + * This function writes a packet into the Tx FIFO associated with the
25626 + * EP. For non-periodic EPs the non-periodic Tx FIFO is written. For
25627 + * periodic EPs the periodic Tx FIFO associated with the EP is written
25628 + * with all packets for the next micro-frame.
25629 + *
25630 + * @param core_if Programming view of DWC_otg controller.
25631 + * @param ep The EP to write packet for.
25632 + * @param dma Indicates if DMA is being used.
25633 + */
25634 +void dwc_otg_ep_write_packet(dwc_otg_core_if_t * core_if, dwc_ep_t * ep,
25635 + int dma)
25636 +{
25637 + /**
25638 + * The buffer is padded to DWORD on a per packet basis in
25639 + * slave/dma mode if the MPS is not DWORD aligned. The last
25640 + * packet, if short, is also padded to a multiple of DWORD.
25641 + *
25642 + * ep->xfer_buff always starts DWORD aligned in memory and is a
25643 + * multiple of DWORD in length
25644 + *
25645 + * ep->xfer_len can be any number of bytes
25646 + *
25647 + * ep->xfer_count is a multiple of ep->maxpacket until the last
25648 + * packet
25649 + *
25650 + * FIFO access is DWORD */
25651 +
25652 + uint32_t i;
25653 + uint32_t byte_count;
25654 + uint32_t dword_count;
25655 + uint32_t *fifo;
25656 + uint32_t *data_buff = (uint32_t *) ep->xfer_buff;
25657 +
25658 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, core_if,
25659 + ep);
25660 + if (ep->xfer_count >= ep->xfer_len) {
25661 + DWC_WARN("%s() No data for EP%d!!!\n", __func__, ep->num);
25662 + return;
25663 + }
25664 +
25665 + /* Find the byte length of the packet either short packet or MPS */
25666 + if ((ep->xfer_len - ep->xfer_count) < ep->maxpacket) {
25667 + byte_count = ep->xfer_len - ep->xfer_count;
25668 + } else {
25669 + byte_count = ep->maxpacket;
25670 + }
25671 +
25672 + /* Find the DWORD length, padded by extra bytes as neccessary if MPS
25673 + * is not a multiple of DWORD */
25674 + dword_count = (byte_count + 3) / 4;
25675 +
25676 +#ifdef VERBOSE
25677 + dump_msg(ep->xfer_buff, byte_count);
25678 +#endif
25679 +
25680 + /**@todo NGS Where are the Periodic Tx FIFO addresses
25681 + * intialized? What should this be? */
25682 +
25683 + fifo = core_if->data_fifo[ep->num];
25684 +
25685 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n",
25686 + fifo, data_buff, *data_buff, byte_count);
25687 +
25688 + if (!dma) {
25689 + for (i = 0; i < dword_count; i++, data_buff++) {
25690 + DWC_WRITE_REG32(fifo, *data_buff);
25691 + }
25692 + }
25693 +
25694 + ep->xfer_count += byte_count;
25695 + ep->xfer_buff += byte_count;
25696 + ep->dma_addr += byte_count;
25697 +}
25698 +
25699 +/**
25700 + * Set the EP STALL.
25701 + *
25702 + * @param core_if Programming view of DWC_otg controller.
25703 + * @param ep The EP to set the stall on.
25704 + */
25705 +void dwc_otg_ep_set_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25706 +{
25707 + depctl_data_t depctl;
25708 + volatile uint32_t *depctl_addr;
25709 +
25710 + DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
25711 + (ep->is_in ? "IN" : "OUT"));
25712 +
25713 + if (ep->is_in == 1) {
25714 + depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
25715 + depctl.d32 = DWC_READ_REG32(depctl_addr);
25716 +
25717 + /* set the disable and stall bits */
25718 + if (depctl.b.epena) {
25719 + depctl.b.epdis = 1;
25720 + }
25721 + depctl.b.stall = 1;
25722 + DWC_WRITE_REG32(depctl_addr, depctl.d32);
25723 + } else {
25724 + depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
25725 + depctl.d32 = DWC_READ_REG32(depctl_addr);
25726 +
25727 + /* set the stall bit */
25728 + depctl.b.stall = 1;
25729 + DWC_WRITE_REG32(depctl_addr, depctl.d32);
25730 + }
25731 +
25732 + DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
25733 +
25734 + return;
25735 +}
25736 +
25737 +/**
25738 + * Clear the EP STALL.
25739 + *
25740 + * @param core_if Programming view of DWC_otg controller.
25741 + * @param ep The EP to clear stall from.
25742 + */
25743 +void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25744 +{
25745 + depctl_data_t depctl;
25746 + volatile uint32_t *depctl_addr;
25747 +
25748 + DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
25749 + (ep->is_in ? "IN" : "OUT"));
25750 +
25751 + if (ep->is_in == 1) {
25752 + depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
25753 + } else {
25754 + depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
25755 + }
25756 +
25757 + depctl.d32 = DWC_READ_REG32(depctl_addr);
25758 +
25759 + /* clear the stall bits */
25760 + depctl.b.stall = 0;
25761 +
25762 + /*
25763 + * USB Spec 9.4.5: For endpoints using data toggle, regardless
25764 + * of whether an endpoint has the Halt feature set, a
25765 + * ClearFeature(ENDPOINT_HALT) request always results in the
25766 + * data toggle being reinitialized to DATA0.
25767 + */
25768 + if (ep->type == DWC_OTG_EP_TYPE_INTR ||
25769 + ep->type == DWC_OTG_EP_TYPE_BULK) {
25770 + depctl.b.setd0pid = 1; /* DATA0 */
25771 + }
25772 +
25773 + DWC_WRITE_REG32(depctl_addr, depctl.d32);
25774 + DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
25775 + return;
25776 +}
25777 +
25778 +/**
25779 + * This function reads a packet from the Rx FIFO into the destination
25780 + * buffer. To read SETUP data use dwc_otg_read_setup_packet.
25781 + *
25782 + * @param core_if Programming view of DWC_otg controller.
25783 + * @param dest Destination buffer for the packet.
25784 + * @param bytes Number of bytes to copy to the destination.
25785 + */
25786 +void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
25787 + uint8_t * dest, uint16_t bytes)
25788 +{
25789 + int i;
25790 + int word_count = (bytes + 3) / 4;
25791 +
25792 + volatile uint32_t *fifo = core_if->data_fifo[0];
25793 + uint32_t *data_buff = (uint32_t *) dest;
25794 +
25795 + /**
25796 + * @todo Account for the case where _dest is not dword aligned. This
25797 + * requires reading data from the FIFO into a uint32_t temp buffer,
25798 + * then moving it into the data buffer.
25799 + */
25800 +
25801 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__,
25802 + core_if, dest, bytes);
25803 +
25804 + for (i = 0; i < word_count; i++, data_buff++) {
25805 + *data_buff = DWC_READ_REG32(fifo);
25806 + }
25807 +
25808 + return;
25809 +}
25810 +
25811 +/**
25812 + * This functions reads the device registers and prints them
25813 + *
25814 + * @param core_if Programming view of DWC_otg controller.
25815 + */
25816 +void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * core_if)
25817 +{
25818 + int i;
25819 + volatile uint32_t *addr;
25820 +
25821 + DWC_PRINTF("Device Global Registers\n");
25822 + addr = &core_if->dev_if->dev_global_regs->dcfg;
25823 + DWC_PRINTF("DCFG @0x%08lX : 0x%08X\n",
25824 + (unsigned long)addr, DWC_READ_REG32(addr));
25825 + addr = &core_if->dev_if->dev_global_regs->dctl;
25826 + DWC_PRINTF("DCTL @0x%08lX : 0x%08X\n",
25827 + (unsigned long)addr, DWC_READ_REG32(addr));
25828 + addr = &core_if->dev_if->dev_global_regs->dsts;
25829 + DWC_PRINTF("DSTS @0x%08lX : 0x%08X\n",
25830 + (unsigned long)addr, DWC_READ_REG32(addr));
25831 + addr = &core_if->dev_if->dev_global_regs->diepmsk;
25832 + DWC_PRINTF("DIEPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25833 + DWC_READ_REG32(addr));
25834 + addr = &core_if->dev_if->dev_global_regs->doepmsk;
25835 + DWC_PRINTF("DOEPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25836 + DWC_READ_REG32(addr));
25837 + addr = &core_if->dev_if->dev_global_regs->daint;
25838 + DWC_PRINTF("DAINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
25839 + DWC_READ_REG32(addr));
25840 + addr = &core_if->dev_if->dev_global_regs->daintmsk;
25841 + DWC_PRINTF("DAINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25842 + DWC_READ_REG32(addr));
25843 + addr = &core_if->dev_if->dev_global_regs->dtknqr1;
25844 + DWC_PRINTF("DTKNQR1 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25845 + DWC_READ_REG32(addr));
25846 + if (core_if->hwcfg2.b.dev_token_q_depth > 6) {
25847 + addr = &core_if->dev_if->dev_global_regs->dtknqr2;
25848 + DWC_PRINTF("DTKNQR2 @0x%08lX : 0x%08X\n",
25849 + (unsigned long)addr, DWC_READ_REG32(addr));
25850 + }
25851 +
25852 + addr = &core_if->dev_if->dev_global_regs->dvbusdis;
25853 + DWC_PRINTF("DVBUSID @0x%08lX : 0x%08X\n", (unsigned long)addr,
25854 + DWC_READ_REG32(addr));
25855 +
25856 + addr = &core_if->dev_if->dev_global_regs->dvbuspulse;
25857 + DWC_PRINTF("DVBUSPULSE @0x%08lX : 0x%08X\n",
25858 + (unsigned long)addr, DWC_READ_REG32(addr));
25859 +
25860 + addr = &core_if->dev_if->dev_global_regs->dtknqr3_dthrctl;
25861 + DWC_PRINTF("DTKNQR3_DTHRCTL @0x%08lX : 0x%08X\n",
25862 + (unsigned long)addr, DWC_READ_REG32(addr));
25863 +
25864 + if (core_if->hwcfg2.b.dev_token_q_depth > 22) {
25865 + addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
25866 + DWC_PRINTF("DTKNQR4 @0x%08lX : 0x%08X\n",
25867 + (unsigned long)addr, DWC_READ_REG32(addr));
25868 + }
25869 +
25870 + addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
25871 + DWC_PRINTF("FIFOEMPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25872 + DWC_READ_REG32(addr));
25873 +
25874 + if (core_if->hwcfg2.b.multi_proc_int) {
25875 +
25876 + addr = &core_if->dev_if->dev_global_regs->deachint;
25877 + DWC_PRINTF("DEACHINT @0x%08lX : 0x%08X\n",
25878 + (unsigned long)addr, DWC_READ_REG32(addr));
25879 + addr = &core_if->dev_if->dev_global_regs->deachintmsk;
25880 + DWC_PRINTF("DEACHINTMSK @0x%08lX : 0x%08X\n",
25881 + (unsigned long)addr, DWC_READ_REG32(addr));
25882 +
25883 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
25884 + addr =
25885 + &core_if->dev_if->
25886 + dev_global_regs->diepeachintmsk[i];
25887 + DWC_PRINTF("DIEPEACHINTMSK[%d] @0x%08lX : 0x%08X\n",
25888 + i, (unsigned long)addr,
25889 + DWC_READ_REG32(addr));
25890 + }
25891 +
25892 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
25893 + addr =
25894 + &core_if->dev_if->
25895 + dev_global_regs->doepeachintmsk[i];
25896 + DWC_PRINTF("DOEPEACHINTMSK[%d] @0x%08lX : 0x%08X\n",
25897 + i, (unsigned long)addr,
25898 + DWC_READ_REG32(addr));
25899 + }
25900 + }
25901 +
25902 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
25903 + DWC_PRINTF("Device IN EP %d Registers\n", i);
25904 + addr = &core_if->dev_if->in_ep_regs[i]->diepctl;
25905 + DWC_PRINTF("DIEPCTL @0x%08lX : 0x%08X\n",
25906 + (unsigned long)addr, DWC_READ_REG32(addr));
25907 + addr = &core_if->dev_if->in_ep_regs[i]->diepint;
25908 + DWC_PRINTF("DIEPINT @0x%08lX : 0x%08X\n",
25909 + (unsigned long)addr, DWC_READ_REG32(addr));
25910 + addr = &core_if->dev_if->in_ep_regs[i]->dieptsiz;
25911 + DWC_PRINTF("DIETSIZ @0x%08lX : 0x%08X\n",
25912 + (unsigned long)addr, DWC_READ_REG32(addr));
25913 + addr = &core_if->dev_if->in_ep_regs[i]->diepdma;
25914 + DWC_PRINTF("DIEPDMA @0x%08lX : 0x%08X\n",
25915 + (unsigned long)addr, DWC_READ_REG32(addr));
25916 + addr = &core_if->dev_if->in_ep_regs[i]->dtxfsts;
25917 + DWC_PRINTF("DTXFSTS @0x%08lX : 0x%08X\n",
25918 + (unsigned long)addr, DWC_READ_REG32(addr));
25919 + addr = &core_if->dev_if->in_ep_regs[i]->diepdmab;
25920 + DWC_PRINTF("DIEPDMAB @0x%08lX : 0x%08X\n",
25921 + (unsigned long)addr, 0 /*DWC_READ_REG32(addr) */ );
25922 + }
25923 +
25924 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
25925 + DWC_PRINTF("Device OUT EP %d Registers\n", i);
25926 + addr = &core_if->dev_if->out_ep_regs[i]->doepctl;
25927 + DWC_PRINTF("DOEPCTL @0x%08lX : 0x%08X\n",
25928 + (unsigned long)addr, DWC_READ_REG32(addr));
25929 + addr = &core_if->dev_if->out_ep_regs[i]->doepint;
25930 + DWC_PRINTF("DOEPINT @0x%08lX : 0x%08X\n",
25931 + (unsigned long)addr, DWC_READ_REG32(addr));
25932 + addr = &core_if->dev_if->out_ep_regs[i]->doeptsiz;
25933 + DWC_PRINTF("DOETSIZ @0x%08lX : 0x%08X\n",
25934 + (unsigned long)addr, DWC_READ_REG32(addr));
25935 + addr = &core_if->dev_if->out_ep_regs[i]->doepdma;
25936 + DWC_PRINTF("DOEPDMA @0x%08lX : 0x%08X\n",
25937 + (unsigned long)addr, DWC_READ_REG32(addr));
25938 + if (core_if->dma_enable) { /* Don't access this register in SLAVE mode */
25939 + addr = &core_if->dev_if->out_ep_regs[i]->doepdmab;
25940 + DWC_PRINTF("DOEPDMAB @0x%08lX : 0x%08X\n",
25941 + (unsigned long)addr, DWC_READ_REG32(addr));
25942 + }
25943 +
25944 + }
25945 +}
25946 +
25947 +/**
25948 + * This functions reads the SPRAM and prints its content
25949 + *
25950 + * @param core_if Programming view of DWC_otg controller.
25951 + */
25952 +void dwc_otg_dump_spram(dwc_otg_core_if_t * core_if)
25953 +{
25954 + volatile uint8_t *addr, *start_addr, *end_addr;
25955 +
25956 + DWC_PRINTF("SPRAM Data:\n");
25957 + start_addr = (void *)core_if->core_global_regs;
25958 + DWC_PRINTF("Base Address: 0x%8lX\n", (unsigned long)start_addr);
25959 + start_addr += 0x00028000;
25960 + end_addr = (void *)core_if->core_global_regs;
25961 + end_addr += 0x000280e0;
25962 +
25963 + for (addr = start_addr; addr < end_addr; addr += 16) {
25964 + DWC_PRINTF
25965 + ("0x%8lX:\t%2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X\n",
25966 + (unsigned long)addr, addr[0], addr[1], addr[2], addr[3],
25967 + addr[4], addr[5], addr[6], addr[7], addr[8], addr[9],
25968 + addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]
25969 + );
25970 + }
25971 +
25972 + return;
25973 +}
25974 +
25975 +/**
25976 + * This function reads the host registers and prints them
25977 + *
25978 + * @param core_if Programming view of DWC_otg controller.
25979 + */
25980 +void dwc_otg_dump_host_registers(dwc_otg_core_if_t * core_if)
25981 +{
25982 + int i;
25983 + volatile uint32_t *addr;
25984 +
25985 + DWC_PRINTF("Host Global Registers\n");
25986 + addr = &core_if->host_if->host_global_regs->hcfg;
25987 + DWC_PRINTF("HCFG @0x%08lX : 0x%08X\n",
25988 + (unsigned long)addr, DWC_READ_REG32(addr));
25989 + addr = &core_if->host_if->host_global_regs->hfir;
25990 + DWC_PRINTF("HFIR @0x%08lX : 0x%08X\n",
25991 + (unsigned long)addr, DWC_READ_REG32(addr));
25992 + addr = &core_if->host_if->host_global_regs->hfnum;
25993 + DWC_PRINTF("HFNUM @0x%08lX : 0x%08X\n", (unsigned long)addr,
25994 + DWC_READ_REG32(addr));
25995 + addr = &core_if->host_if->host_global_regs->hptxsts;
25996 + DWC_PRINTF("HPTXSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
25997 + DWC_READ_REG32(addr));
25998 + addr = &core_if->host_if->host_global_regs->haint;
25999 + DWC_PRINTF("HAINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
26000 + DWC_READ_REG32(addr));
26001 + addr = &core_if->host_if->host_global_regs->haintmsk;
26002 + DWC_PRINTF("HAINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
26003 + DWC_READ_REG32(addr));
26004 + if (core_if->dma_desc_enable) {
26005 + addr = &core_if->host_if->host_global_regs->hflbaddr;
26006 + DWC_PRINTF("HFLBADDR @0x%08lX : 0x%08X\n",
26007 + (unsigned long)addr, DWC_READ_REG32(addr));
26008 + }
26009 +
26010 + addr = core_if->host_if->hprt0;
26011 + DWC_PRINTF("HPRT0 @0x%08lX : 0x%08X\n", (unsigned long)addr,
26012 + DWC_READ_REG32(addr));
26013 +
26014 + for (i = 0; i < core_if->core_params->host_channels; i++) {
26015 + DWC_PRINTF("Host Channel %d Specific Registers\n", i);
26016 + addr = &core_if->host_if->hc_regs[i]->hcchar;
26017 + DWC_PRINTF("HCCHAR @0x%08lX : 0x%08X\n",
26018 + (unsigned long)addr, DWC_READ_REG32(addr));
26019 + addr = &core_if->host_if->hc_regs[i]->hcsplt;
26020 + DWC_PRINTF("HCSPLT @0x%08lX : 0x%08X\n",
26021 + (unsigned long)addr, DWC_READ_REG32(addr));
26022 + addr = &core_if->host_if->hc_regs[i]->hcint;
26023 + DWC_PRINTF("HCINT @0x%08lX : 0x%08X\n",
26024 + (unsigned long)addr, DWC_READ_REG32(addr));
26025 + addr = &core_if->host_if->hc_regs[i]->hcintmsk;
26026 + DWC_PRINTF("HCINTMSK @0x%08lX : 0x%08X\n",
26027 + (unsigned long)addr, DWC_READ_REG32(addr));
26028 + addr = &core_if->host_if->hc_regs[i]->hctsiz;
26029 + DWC_PRINTF("HCTSIZ @0x%08lX : 0x%08X\n",
26030 + (unsigned long)addr, DWC_READ_REG32(addr));
26031 + addr = &core_if->host_if->hc_regs[i]->hcdma;
26032 + DWC_PRINTF("HCDMA @0x%08lX : 0x%08X\n",
26033 + (unsigned long)addr, DWC_READ_REG32(addr));
26034 + if (core_if->dma_desc_enable) {
26035 + addr = &core_if->host_if->hc_regs[i]->hcdmab;
26036 + DWC_PRINTF("HCDMAB @0x%08lX : 0x%08X\n",
26037 + (unsigned long)addr, DWC_READ_REG32(addr));
26038 + }
26039 +
26040 + }
26041 + return;
26042 +}
26043 +
26044 +/**
26045 + * This function reads the core global registers and prints them
26046 + *
26047 + * @param core_if Programming view of DWC_otg controller.
26048 + */
26049 +void dwc_otg_dump_global_registers(dwc_otg_core_if_t * core_if)
26050 +{
26051 + int i, ep_num;
26052 + volatile uint32_t *addr;
26053 + char *txfsiz;
26054 +
26055 + DWC_PRINTF("Core Global Registers\n");
26056 + addr = &core_if->core_global_regs->gotgctl;
26057 + DWC_PRINTF("GOTGCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
26058 + DWC_READ_REG32(addr));
26059 + addr = &core_if->core_global_regs->gotgint;
26060 + DWC_PRINTF("GOTGINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
26061 + DWC_READ_REG32(addr));
26062 + addr = &core_if->core_global_regs->gahbcfg;
26063 + DWC_PRINTF("GAHBCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
26064 + DWC_READ_REG32(addr));
26065 + addr = &core_if->core_global_regs->gusbcfg;
26066 + DWC_PRINTF("GUSBCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
26067 + DWC_READ_REG32(addr));
26068 + addr = &core_if->core_global_regs->grstctl;
26069 + DWC_PRINTF("GRSTCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
26070 + DWC_READ_REG32(addr));
26071 + addr = &core_if->core_global_regs->gintsts;
26072 + DWC_PRINTF("GINTSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
26073 + DWC_READ_REG32(addr));
26074 + addr = &core_if->core_global_regs->gintmsk;
26075 + DWC_PRINTF("GINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
26076 + DWC_READ_REG32(addr));
26077 + addr = &core_if->core_global_regs->grxstsr;
26078 + DWC_PRINTF("GRXSTSR @0x%08lX : 0x%08X\n", (unsigned long)addr,
26079 + DWC_READ_REG32(addr));
26080 + addr = &core_if->core_global_regs->grxfsiz;
26081 + DWC_PRINTF("GRXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
26082 + DWC_READ_REG32(addr));
26083 + addr = &core_if->core_global_regs->gnptxfsiz;
26084 + DWC_PRINTF("GNPTXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
26085 + DWC_READ_REG32(addr));
26086 + addr = &core_if->core_global_regs->gnptxsts;
26087 + DWC_PRINTF("GNPTXSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
26088 + DWC_READ_REG32(addr));
26089 + addr = &core_if->core_global_regs->gi2cctl;
26090 + DWC_PRINTF("GI2CCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
26091 + DWC_READ_REG32(addr));
26092 + addr = &core_if->core_global_regs->gpvndctl;
26093 + DWC_PRINTF("GPVNDCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
26094 + DWC_READ_REG32(addr));
26095 + addr = &core_if->core_global_regs->ggpio;
26096 + DWC_PRINTF("GGPIO @0x%08lX : 0x%08X\n", (unsigned long)addr,
26097 + DWC_READ_REG32(addr));
26098 + addr = &core_if->core_global_regs->guid;
26099 + DWC_PRINTF("GUID @0x%08lX : 0x%08X\n",
26100 + (unsigned long)addr, DWC_READ_REG32(addr));
26101 + addr = &core_if->core_global_regs->gsnpsid;
26102 + DWC_PRINTF("GSNPSID @0x%08lX : 0x%08X\n", (unsigned long)addr,
26103 + DWC_READ_REG32(addr));
26104 + addr = &core_if->core_global_regs->ghwcfg1;
26105 + DWC_PRINTF("GHWCFG1 @0x%08lX : 0x%08X\n", (unsigned long)addr,
26106 + DWC_READ_REG32(addr));
26107 + addr = &core_if->core_global_regs->ghwcfg2;
26108 + DWC_PRINTF("GHWCFG2 @0x%08lX : 0x%08X\n", (unsigned long)addr,
26109 + DWC_READ_REG32(addr));
26110 + addr = &core_if->core_global_regs->ghwcfg3;
26111 + DWC_PRINTF("GHWCFG3 @0x%08lX : 0x%08X\n", (unsigned long)addr,
26112 + DWC_READ_REG32(addr));
26113 + addr = &core_if->core_global_regs->ghwcfg4;
26114 + DWC_PRINTF("GHWCFG4 @0x%08lX : 0x%08X\n", (unsigned long)addr,
26115 + DWC_READ_REG32(addr));
26116 + addr = &core_if->core_global_regs->glpmcfg;
26117 + DWC_PRINTF("GLPMCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
26118 + DWC_READ_REG32(addr));
26119 + addr = &core_if->core_global_regs->gpwrdn;
26120 + DWC_PRINTF("GPWRDN @0x%08lX : 0x%08X\n", (unsigned long)addr,
26121 + DWC_READ_REG32(addr));
26122 + addr = &core_if->core_global_regs->gdfifocfg;
26123 + DWC_PRINTF("GDFIFOCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
26124 + DWC_READ_REG32(addr));
26125 + addr = &core_if->core_global_regs->adpctl;
26126 + DWC_PRINTF("ADPCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
26127 + dwc_otg_adp_read_reg(core_if));
26128 + addr = &core_if->core_global_regs->hptxfsiz;
26129 + DWC_PRINTF("HPTXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
26130 + DWC_READ_REG32(addr));
26131 +
26132 + if (core_if->en_multiple_tx_fifo == 0) {
26133 + ep_num = core_if->hwcfg4.b.num_dev_perio_in_ep;
26134 + txfsiz = "DPTXFSIZ";
26135 + } else {
26136 + ep_num = core_if->hwcfg4.b.num_in_eps;
26137 + txfsiz = "DIENPTXF";
26138 + }
26139 + for (i = 0; i < ep_num; i++) {
26140 + addr = &core_if->core_global_regs->dtxfsiz[i];
26141 + DWC_PRINTF("%s[%d] @0x%08lX : 0x%08X\n", txfsiz, i + 1,
26142 + (unsigned long)addr, DWC_READ_REG32(addr));
26143 + }
26144 + addr = core_if->pcgcctl;
26145 + DWC_PRINTF("PCGCCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
26146 + DWC_READ_REG32(addr));
26147 +}
26148 +
26149 +/**
26150 + * Flush a Tx FIFO.
26151 + *
26152 + * @param core_if Programming view of DWC_otg controller.
26153 + * @param num Tx FIFO to flush.
26154 + */
26155 +void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * core_if, const int num)
26156 +{
26157 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
26158 + volatile grstctl_t greset = {.d32 = 0 };
26159 + int count = 0;
26160 +
26161 + DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "Flush Tx FIFO %d\n", num);
26162 +
26163 + greset.b.txfflsh = 1;
26164 + greset.b.txfnum = num;
26165 + DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
26166 +
26167 + do {
26168 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26169 + if (++count > 10000) {
26170 + DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
26171 + __func__, greset.d32,
26172 + DWC_READ_REG32(&global_regs->gnptxsts));
26173 + break;
26174 + }
26175 + dwc_udelay(1);
26176 + } while (greset.b.txfflsh == 1);
26177 +
26178 + /* Wait for 3 PHY Clocks */
26179 + dwc_udelay(1);
26180 +}
26181 +
26182 +/**
26183 + * Flush Rx FIFO.
26184 + *
26185 + * @param core_if Programming view of DWC_otg controller.
26186 + */
26187 +void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * core_if)
26188 +{
26189 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
26190 + volatile grstctl_t greset = {.d32 = 0 };
26191 + int count = 0;
26192 +
26193 + DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "%s\n", __func__);
26194 + /*
26195 + *
26196 + */
26197 + greset.b.rxfflsh = 1;
26198 + DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
26199 +
26200 + do {
26201 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26202 + if (++count > 10000) {
26203 + DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__,
26204 + greset.d32);
26205 + break;
26206 + }
26207 + dwc_udelay(1);
26208 + } while (greset.b.rxfflsh == 1);
26209 +
26210 + /* Wait for 3 PHY Clocks */
26211 + dwc_udelay(1);
26212 +}
26213 +
26214 +/**
26215 + * Do core a soft reset of the core. Be careful with this because it
26216 + * resets all the internal state machines of the core.
26217 + */
26218 +void dwc_otg_core_reset(dwc_otg_core_if_t * core_if)
26219 +{
26220 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
26221 + volatile grstctl_t greset = {.d32 = 0 };
26222 + int count = 0;
26223 +
26224 + DWC_DEBUGPL(DBG_CILV, "%s\n", __func__);
26225 + /* Wait for AHB master IDLE state. */
26226 + do {
26227 + dwc_udelay(10);
26228 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26229 + if (++count > 100000) {
26230 + DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x\n", __func__,
26231 + greset.d32);
26232 + return;
26233 + }
26234 + }
26235 + while (greset.b.ahbidle == 0);
26236 +
26237 + /* Core Soft Reset */
26238 + count = 0;
26239 + greset.b.csftrst = 1;
26240 + DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
26241 + do {
26242 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26243 + if (++count > 10000) {
26244 + DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n",
26245 + __func__, greset.d32);
26246 + break;
26247 + }
26248 + dwc_udelay(1);
26249 + }
26250 + while (greset.b.csftrst == 1);
26251 +
26252 + /* Wait for 3 PHY Clocks */
26253 + dwc_mdelay(100);
26254 +}
26255 +
26256 +uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if)
26257 +{
26258 + return (dwc_otg_mode(_core_if) != DWC_HOST_MODE);
26259 +}
26260 +
26261 +uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if)
26262 +{
26263 + return (dwc_otg_mode(_core_if) == DWC_HOST_MODE);
26264 +}
26265 +
26266 +/**
26267 + * Register HCD callbacks. The callbacks are used to start and stop
26268 + * the HCD for interrupt processing.
26269 + *
26270 + * @param core_if Programming view of DWC_otg controller.
26271 + * @param cb the HCD callback structure.
26272 + * @param p pointer to be passed to callback function (usb_hcd*).
26273 + */
26274 +void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * core_if,
26275 + dwc_otg_cil_callbacks_t * cb, void *p)
26276 +{
26277 + core_if->hcd_cb = cb;
26278 + cb->p = p;
26279 +}
26280 +
26281 +/**
26282 + * Register PCD callbacks. The callbacks are used to start and stop
26283 + * the PCD for interrupt processing.
26284 + *
26285 + * @param core_if Programming view of DWC_otg controller.
26286 + * @param cb the PCD callback structure.
26287 + * @param p pointer to be passed to callback function (pcd*).
26288 + */
26289 +void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * core_if,
26290 + dwc_otg_cil_callbacks_t * cb, void *p)
26291 +{
26292 + core_if->pcd_cb = cb;
26293 + cb->p = p;
26294 +}
26295 +
26296 +#ifdef DWC_EN_ISOC
26297 +
26298 +/**
26299 + * This function writes isoc data per 1 (micro)frame into tx fifo
26300 + *
26301 + * @param core_if Programming view of DWC_otg controller.
26302 + * @param ep The EP to start the transfer on.
26303 + *
26304 + */
26305 +void write_isoc_frame_data(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
26306 +{
26307 + dwc_otg_dev_in_ep_regs_t *ep_regs;
26308 + dtxfsts_data_t txstatus = {.d32 = 0 };
26309 + uint32_t len = 0;
26310 + uint32_t dwords;
26311 +
26312 + ep->xfer_len = ep->data_per_frame;
26313 + ep->xfer_count = 0;
26314 +
26315 + ep_regs = core_if->dev_if->in_ep_regs[ep->num];
26316 +
26317 + len = ep->xfer_len - ep->xfer_count;
26318 +
26319 + if (len > ep->maxpacket) {
26320 + len = ep->maxpacket;
26321 + }
26322 +
26323 + dwords = (len + 3) / 4;
26324 +
26325 + /* While there is space in the queue and space in the FIFO and
26326 + * More data to tranfer, Write packets to the Tx FIFO */
26327 + txstatus.d32 =
26328 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dtxfsts);
26329 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", ep->num, txstatus.d32);
26330 +
26331 + while (txstatus.b.txfspcavail > dwords &&
26332 + ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) {
26333 + /* Write the FIFO */
26334 + dwc_otg_ep_write_packet(core_if, ep, 0);
26335 +
26336 + len = ep->xfer_len - ep->xfer_count;
26337 + if (len > ep->maxpacket) {
26338 + len = ep->maxpacket;
26339 + }
26340 +
26341 + dwords = (len + 3) / 4;
26342 + txstatus.d32 =
26343 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
26344 + dtxfsts);
26345 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", ep->num,
26346 + txstatus.d32);
26347 + }
26348 +}
26349 +
26350 +/**
26351 + * This function initializes a descriptor chain for Isochronous transfer
26352 + *
26353 + * @param core_if Programming view of DWC_otg controller.
26354 + * @param ep The EP to start the transfer on.
26355 + *
26356 + */
26357 +void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
26358 + dwc_ep_t * ep)
26359 +{
26360 + deptsiz_data_t deptsiz = {.d32 = 0 };
26361 + depctl_data_t depctl = {.d32 = 0 };
26362 + dsts_data_t dsts = {.d32 = 0 };
26363 + volatile uint32_t *addr;
26364 +
26365 + if (ep->is_in) {
26366 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
26367 + } else {
26368 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
26369 + }
26370 +
26371 + ep->xfer_len = ep->data_per_frame;
26372 + ep->xfer_count = 0;
26373 + ep->xfer_buff = ep->cur_pkt_addr;
26374 + ep->dma_addr = ep->cur_pkt_dma_addr;
26375 +
26376 + if (ep->is_in) {
26377 + /* Program the transfer size and packet count
26378 + * as follows: xfersize = N * maxpacket +
26379 + * short_packet pktcnt = N + (short_packet
26380 + * exist ? 1 : 0)
26381 + */
26382 + deptsiz.b.xfersize = ep->xfer_len;
26383 + deptsiz.b.pktcnt =
26384 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
26385 + deptsiz.b.mc = deptsiz.b.pktcnt;
26386 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dieptsiz,
26387 + deptsiz.d32);
26388 +
26389 + /* Write the DMA register */
26390 + if (core_if->dma_enable) {
26391 + DWC_WRITE_REG32(&
26392 + (core_if->dev_if->in_ep_regs[ep->num]->
26393 + diepdma), (uint32_t) ep->dma_addr);
26394 + }
26395 + } else {
26396 + deptsiz.b.pktcnt =
26397 + (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket;
26398 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
26399 +
26400 + DWC_WRITE_REG32(&core_if->dev_if->
26401 + out_ep_regs[ep->num]->doeptsiz, deptsiz.d32);
26402 +
26403 + if (core_if->dma_enable) {
26404 + DWC_WRITE_REG32(&
26405 + (core_if->dev_if->
26406 + out_ep_regs[ep->num]->doepdma),
26407 + (uint32_t) ep->dma_addr);
26408 + }
26409 + }
26410 +
26411 + /** Enable endpoint, clear nak */
26412 +
26413 + depctl.d32 = 0;
26414 + if (ep->bInterval == 1) {
26415 + dsts.d32 =
26416 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
26417 + ep->next_frame = dsts.b.soffn + ep->bInterval;
26418 +
26419 + if (ep->next_frame & 0x1) {
26420 + depctl.b.setd1pid = 1;
26421 + } else {
26422 + depctl.b.setd0pid = 1;
26423 + }
26424 + } else {
26425 + ep->next_frame += ep->bInterval;
26426 +
26427 + if (ep->next_frame & 0x1) {
26428 + depctl.b.setd1pid = 1;
26429 + } else {
26430 + depctl.b.setd0pid = 1;
26431 + }
26432 + }
26433 + depctl.b.epena = 1;
26434 + depctl.b.cnak = 1;
26435 +
26436 + DWC_MODIFY_REG32(addr, 0, depctl.d32);
26437 + depctl.d32 = DWC_READ_REG32(addr);
26438 +
26439 + if (ep->is_in && core_if->dma_enable == 0) {
26440 + write_isoc_frame_data(core_if, ep);
26441 + }
26442 +
26443 +}
26444 +#endif /* DWC_EN_ISOC */
26445 +
26446 +static void dwc_otg_set_uninitialized(int32_t * p, int size)
26447 +{
26448 + int i;
26449 + for (i = 0; i < size; i++) {
26450 + p[i] = -1;
26451 + }
26452 +}
26453 +
26454 +static int dwc_otg_param_initialized(int32_t val)
26455 +{
26456 + return val != -1;
26457 +}
26458 +
26459 +static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if)
26460 +{
26461 + int i;
26462 + core_if->core_params = DWC_ALLOC(sizeof(*core_if->core_params));
26463 + if (!core_if->core_params) {
26464 + return -DWC_E_NO_MEMORY;
26465 + }
26466 + dwc_otg_set_uninitialized((int32_t *) core_if->core_params,
26467 + sizeof(*core_if->core_params) /
26468 + sizeof(int32_t));
26469 + DWC_PRINTF("Setting default values for core params\n");
26470 + dwc_otg_set_param_otg_cap(core_if, dwc_param_otg_cap_default);
26471 + dwc_otg_set_param_dma_enable(core_if, dwc_param_dma_enable_default);
26472 + dwc_otg_set_param_dma_desc_enable(core_if,
26473 + dwc_param_dma_desc_enable_default);
26474 + dwc_otg_set_param_opt(core_if, dwc_param_opt_default);
26475 + dwc_otg_set_param_dma_burst_size(core_if,
26476 + dwc_param_dma_burst_size_default);
26477 + dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
26478 + dwc_param_host_support_fs_ls_low_power_default);
26479 + dwc_otg_set_param_enable_dynamic_fifo(core_if,
26480 + dwc_param_enable_dynamic_fifo_default);
26481 + dwc_otg_set_param_data_fifo_size(core_if,
26482 + dwc_param_data_fifo_size_default);
26483 + dwc_otg_set_param_dev_rx_fifo_size(core_if,
26484 + dwc_param_dev_rx_fifo_size_default);
26485 + dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
26486 + dwc_param_dev_nperio_tx_fifo_size_default);
26487 + dwc_otg_set_param_host_rx_fifo_size(core_if,
26488 + dwc_param_host_rx_fifo_size_default);
26489 + dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
26490 + dwc_param_host_nperio_tx_fifo_size_default);
26491 + dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
26492 + dwc_param_host_perio_tx_fifo_size_default);
26493 + dwc_otg_set_param_max_transfer_size(core_if,
26494 + dwc_param_max_transfer_size_default);
26495 + dwc_otg_set_param_max_packet_count(core_if,
26496 + dwc_param_max_packet_count_default);
26497 + dwc_otg_set_param_host_channels(core_if,
26498 + dwc_param_host_channels_default);
26499 + dwc_otg_set_param_dev_endpoints(core_if,
26500 + dwc_param_dev_endpoints_default);
26501 + dwc_otg_set_param_phy_type(core_if, dwc_param_phy_type_default);
26502 + dwc_otg_set_param_speed(core_if, dwc_param_speed_default);
26503 + dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
26504 + dwc_param_host_ls_low_power_phy_clk_default);
26505 + dwc_otg_set_param_phy_ulpi_ddr(core_if, dwc_param_phy_ulpi_ddr_default);
26506 + dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
26507 + dwc_param_phy_ulpi_ext_vbus_default);
26508 + dwc_otg_set_param_phy_utmi_width(core_if,
26509 + dwc_param_phy_utmi_width_default);
26510 + dwc_otg_set_param_ts_dline(core_if, dwc_param_ts_dline_default);
26511 + dwc_otg_set_param_i2c_enable(core_if, dwc_param_i2c_enable_default);
26512 + dwc_otg_set_param_ulpi_fs_ls(core_if, dwc_param_ulpi_fs_ls_default);
26513 + dwc_otg_set_param_en_multiple_tx_fifo(core_if,
26514 + dwc_param_en_multiple_tx_fifo_default);
26515 + for (i = 0; i < 15; i++) {
26516 + dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
26517 + dwc_param_dev_perio_tx_fifo_size_default,
26518 + i);
26519 + }
26520 +
26521 + for (i = 0; i < 15; i++) {
26522 + dwc_otg_set_param_dev_tx_fifo_size(core_if,
26523 + dwc_param_dev_tx_fifo_size_default,
26524 + i);
26525 + }
26526 + dwc_otg_set_param_thr_ctl(core_if, dwc_param_thr_ctl_default);
26527 + dwc_otg_set_param_mpi_enable(core_if, dwc_param_mpi_enable_default);
26528 + dwc_otg_set_param_pti_enable(core_if, dwc_param_pti_enable_default);
26529 + dwc_otg_set_param_lpm_enable(core_if, dwc_param_lpm_enable_default);
26530 + dwc_otg_set_param_ic_usb_cap(core_if, dwc_param_ic_usb_cap_default);
26531 + dwc_otg_set_param_tx_thr_length(core_if,
26532 + dwc_param_tx_thr_length_default);
26533 + dwc_otg_set_param_rx_thr_length(core_if,
26534 + dwc_param_rx_thr_length_default);
26535 + dwc_otg_set_param_ahb_thr_ratio(core_if,
26536 + dwc_param_ahb_thr_ratio_default);
26537 + dwc_otg_set_param_power_down(core_if, dwc_param_power_down_default);
26538 + dwc_otg_set_param_reload_ctl(core_if, dwc_param_reload_ctl_default);
26539 + dwc_otg_set_param_dev_out_nak(core_if, dwc_param_dev_out_nak_default);
26540 + dwc_otg_set_param_cont_on_bna(core_if, dwc_param_cont_on_bna_default);
26541 + dwc_otg_set_param_ahb_single(core_if, dwc_param_ahb_single_default);
26542 + dwc_otg_set_param_otg_ver(core_if, dwc_param_otg_ver_default);
26543 + dwc_otg_set_param_adp_enable(core_if, dwc_param_adp_enable_default);
26544 + DWC_PRINTF("Finished setting default values for core params\n");
26545 +
26546 + return 0;
26547 +}
26548 +
26549 +uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if)
26550 +{
26551 + return core_if->dma_enable;
26552 +}
26553 +
26554 +/* Checks if the parameter is outside of its valid range of values */
26555 +#define DWC_OTG_PARAM_TEST(_param_, _low_, _high_) \
26556 + (((_param_) < (_low_)) || \
26557 + ((_param_) > (_high_)))
26558 +
26559 +/* Parameter access functions */
26560 +int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val)
26561 +{
26562 + int valid;
26563 + int retval = 0;
26564 + if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
26565 + DWC_WARN("Wrong value for otg_cap parameter\n");
26566 + DWC_WARN("otg_cap parameter must be 0,1 or 2\n");
26567 + retval = -DWC_E_INVALID;
26568 + goto out;
26569 + }
26570 +
26571 + valid = 1;
26572 + switch (val) {
26573 + case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE:
26574 + if (core_if->hwcfg2.b.op_mode !=
26575 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
26576 + valid = 0;
26577 + break;
26578 + case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE:
26579 + if ((core_if->hwcfg2.b.op_mode !=
26580 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
26581 + && (core_if->hwcfg2.b.op_mode !=
26582 + DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
26583 + && (core_if->hwcfg2.b.op_mode !=
26584 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
26585 + && (core_if->hwcfg2.b.op_mode !=
26586 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) {
26587 + valid = 0;
26588 + }
26589 + break;
26590 + case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE:
26591 + /* always valid */
26592 + break;
26593 + }
26594 + if (!valid) {
26595 + if (dwc_otg_param_initialized(core_if->core_params->otg_cap)) {
26596 + DWC_ERROR
26597 + ("%d invalid for otg_cap paremter. Check HW configuration.\n",
26598 + val);
26599 + }
26600 + val =
26601 + (((core_if->hwcfg2.b.op_mode ==
26602 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
26603 + || (core_if->hwcfg2.b.op_mode ==
26604 + DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
26605 + || (core_if->hwcfg2.b.op_mode ==
26606 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
26607 + || (core_if->hwcfg2.b.op_mode ==
26608 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ?
26609 + DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE :
26610 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
26611 + retval = -DWC_E_INVALID;
26612 + }
26613 +
26614 + core_if->core_params->otg_cap = val;
26615 +out:
26616 + return retval;
26617 +}
26618 +
26619 +int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if)
26620 +{
26621 + return core_if->core_params->otg_cap;
26622 +}
26623 +
26624 +int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val)
26625 +{
26626 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26627 + DWC_WARN("Wrong value for opt parameter\n");
26628 + return -DWC_E_INVALID;
26629 + }
26630 + core_if->core_params->opt = val;
26631 + return 0;
26632 +}
26633 +
26634 +int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if)
26635 +{
26636 + return core_if->core_params->opt;
26637 +}
26638 +
26639 +int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if, int32_t val)
26640 +{
26641 + int retval = 0;
26642 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26643 + DWC_WARN("Wrong value for dma enable\n");
26644 + return -DWC_E_INVALID;
26645 + }
26646 +
26647 + if ((val == 1) && (core_if->hwcfg2.b.architecture == 0)) {
26648 + if (dwc_otg_param_initialized(core_if->core_params->dma_enable)) {
26649 + DWC_ERROR
26650 + ("%d invalid for dma_enable paremter. Check HW configuration.\n",
26651 + val);
26652 + }
26653 + val = 0;
26654 + retval = -DWC_E_INVALID;
26655 + }
26656 +
26657 + core_if->core_params->dma_enable = val;
26658 + if (val == 0) {
26659 + dwc_otg_set_param_dma_desc_enable(core_if, 0);
26660 + }
26661 + return retval;
26662 +}
26663 +
26664 +int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if)
26665 +{
26666 + return core_if->core_params->dma_enable;
26667 +}
26668 +
26669 +int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if, int32_t val)
26670 +{
26671 + int retval = 0;
26672 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26673 + DWC_WARN("Wrong value for dma_enable\n");
26674 + DWC_WARN("dma_desc_enable must be 0 or 1\n");
26675 + return -DWC_E_INVALID;
26676 + }
26677 +
26678 + if ((val == 1)
26679 + && ((dwc_otg_get_param_dma_enable(core_if) == 0)
26680 + || (core_if->hwcfg4.b.desc_dma == 0))) {
26681 + if (dwc_otg_param_initialized
26682 + (core_if->core_params->dma_desc_enable)) {
26683 + DWC_ERROR
26684 + ("%d invalid for dma_desc_enable paremter. Check HW configuration.\n",
26685 + val);
26686 + }
26687 + val = 0;
26688 + retval = -DWC_E_INVALID;
26689 + }
26690 + core_if->core_params->dma_desc_enable = val;
26691 + return retval;
26692 +}
26693 +
26694 +int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if)
26695 +{
26696 + return core_if->core_params->dma_desc_enable;
26697 +}
26698 +
26699 +int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t * core_if,
26700 + int32_t val)
26701 +{
26702 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26703 + DWC_WARN("Wrong value for host_support_fs_low_power\n");
26704 + DWC_WARN("host_support_fs_low_power must be 0 or 1\n");
26705 + return -DWC_E_INVALID;
26706 + }
26707 + core_if->core_params->host_support_fs_ls_low_power = val;
26708 + return 0;
26709 +}
26710 +
26711 +int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
26712 + core_if)
26713 +{
26714 + return core_if->core_params->host_support_fs_ls_low_power;
26715 +}
26716 +
26717 +int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
26718 + int32_t val)
26719 +{
26720 + int retval = 0;
26721 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26722 + DWC_WARN("Wrong value for enable_dynamic_fifo\n");
26723 + DWC_WARN("enable_dynamic_fifo must be 0 or 1\n");
26724 + return -DWC_E_INVALID;
26725 + }
26726 +
26727 + if ((val == 1) && (core_if->hwcfg2.b.dynamic_fifo == 0)) {
26728 + if (dwc_otg_param_initialized
26729 + (core_if->core_params->enable_dynamic_fifo)) {
26730 + DWC_ERROR
26731 + ("%d invalid for enable_dynamic_fifo paremter. Check HW configuration.\n",
26732 + val);
26733 + }
26734 + val = 0;
26735 + retval = -DWC_E_INVALID;
26736 + }
26737 + core_if->core_params->enable_dynamic_fifo = val;
26738 + return retval;
26739 +}
26740 +
26741 +int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if)
26742 +{
26743 + return core_if->core_params->enable_dynamic_fifo;
26744 +}
26745 +
26746 +int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
26747 +{
26748 + int retval = 0;
26749 + if (DWC_OTG_PARAM_TEST(val, 32, 32768)) {
26750 + DWC_WARN("Wrong value for data_fifo_size\n");
26751 + DWC_WARN("data_fifo_size must be 32-32768\n");
26752 + return -DWC_E_INVALID;
26753 + }
26754 +
26755 + if (val > core_if->hwcfg3.b.dfifo_depth) {
26756 + if (dwc_otg_param_initialized
26757 + (core_if->core_params->data_fifo_size)) {
26758 + DWC_ERROR
26759 + ("%d invalid for data_fifo_size parameter. Check HW configuration.\n",
26760 + val);
26761 + }
26762 + val = core_if->hwcfg3.b.dfifo_depth;
26763 + retval = -DWC_E_INVALID;
26764 + }
26765 +
26766 + core_if->core_params->data_fifo_size = val;
26767 + return retval;
26768 +}
26769 +
26770 +int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if)
26771 +{
26772 + return core_if->core_params->data_fifo_size;
26773 +}
26774 +
26775 +int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
26776 +{
26777 + int retval = 0;
26778 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26779 + DWC_WARN("Wrong value for dev_rx_fifo_size\n");
26780 + DWC_WARN("dev_rx_fifo_size must be 16-32768\n");
26781 + return -DWC_E_INVALID;
26782 + }
26783 +
26784 + if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
26785 + if (dwc_otg_param_initialized(core_if->core_params->dev_rx_fifo_size)) {
26786 + DWC_WARN("%d invalid for dev_rx_fifo_size parameter\n", val);
26787 + }
26788 + val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
26789 + retval = -DWC_E_INVALID;
26790 + }
26791 +
26792 + core_if->core_params->dev_rx_fifo_size = val;
26793 + return retval;
26794 +}
26795 +
26796 +int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if)
26797 +{
26798 + return core_if->core_params->dev_rx_fifo_size;
26799 +}
26800 +
26801 +int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26802 + int32_t val)
26803 +{
26804 + int retval = 0;
26805 +
26806 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26807 + DWC_WARN("Wrong value for dev_nperio_tx_fifo\n");
26808 + DWC_WARN("dev_nperio_tx_fifo must be 16-32768\n");
26809 + return -DWC_E_INVALID;
26810 + }
26811 +
26812 + if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
26813 + if (dwc_otg_param_initialized
26814 + (core_if->core_params->dev_nperio_tx_fifo_size)) {
26815 + DWC_ERROR
26816 + ("%d invalid for dev_nperio_tx_fifo_size. Check HW configuration.\n",
26817 + val);
26818 + }
26819 + val =
26820 + (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
26821 + 16);
26822 + retval = -DWC_E_INVALID;
26823 + }
26824 +
26825 + core_if->core_params->dev_nperio_tx_fifo_size = val;
26826 + return retval;
26827 +}
26828 +
26829 +int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
26830 +{
26831 + return core_if->core_params->dev_nperio_tx_fifo_size;
26832 +}
26833 +
26834 +int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
26835 + int32_t val)
26836 +{
26837 + int retval = 0;
26838 +
26839 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26840 + DWC_WARN("Wrong value for host_rx_fifo_size\n");
26841 + DWC_WARN("host_rx_fifo_size must be 16-32768\n");
26842 + return -DWC_E_INVALID;
26843 + }
26844 +
26845 + if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
26846 + if (dwc_otg_param_initialized
26847 + (core_if->core_params->host_rx_fifo_size)) {
26848 + DWC_ERROR
26849 + ("%d invalid for host_rx_fifo_size. Check HW configuration.\n",
26850 + val);
26851 + }
26852 + val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
26853 + retval = -DWC_E_INVALID;
26854 + }
26855 +
26856 + core_if->core_params->host_rx_fifo_size = val;
26857 + return retval;
26858 +
26859 +}
26860 +
26861 +int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if)
26862 +{
26863 + return core_if->core_params->host_rx_fifo_size;
26864 +}
26865 +
26866 +int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26867 + int32_t val)
26868 +{
26869 + int retval = 0;
26870 +
26871 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26872 + DWC_WARN("Wrong value for host_nperio_tx_fifo_size\n");
26873 + DWC_WARN("host_nperio_tx_fifo_size must be 16-32768\n");
26874 + return -DWC_E_INVALID;
26875 + }
26876 +
26877 + if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
26878 + if (dwc_otg_param_initialized
26879 + (core_if->core_params->host_nperio_tx_fifo_size)) {
26880 + DWC_ERROR
26881 + ("%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n",
26882 + val);
26883 + }
26884 + val =
26885 + (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
26886 + 16);
26887 + retval = -DWC_E_INVALID;
26888 + }
26889 +
26890 + core_if->core_params->host_nperio_tx_fifo_size = val;
26891 + return retval;
26892 +}
26893 +
26894 +int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
26895 +{
26896 + return core_if->core_params->host_nperio_tx_fifo_size;
26897 +}
26898 +
26899 +int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26900 + int32_t val)
26901 +{
26902 + int retval = 0;
26903 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26904 + DWC_WARN("Wrong value for host_perio_tx_fifo_size\n");
26905 + DWC_WARN("host_perio_tx_fifo_size must be 16-32768\n");
26906 + return -DWC_E_INVALID;
26907 + }
26908 +
26909 + if (val > ((core_if->hptxfsiz.d32) >> 16)) {
26910 + if (dwc_otg_param_initialized
26911 + (core_if->core_params->host_perio_tx_fifo_size)) {
26912 + DWC_ERROR
26913 + ("%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n",
26914 + val);
26915 + }
26916 + val = (core_if->hptxfsiz.d32) >> 16;
26917 + retval = -DWC_E_INVALID;
26918 + }
26919 +
26920 + core_if->core_params->host_perio_tx_fifo_size = val;
26921 + return retval;
26922 +}
26923 +
26924 +int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if)
26925 +{
26926 + return core_if->core_params->host_perio_tx_fifo_size;
26927 +}
26928 +
26929 +int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
26930 + int32_t val)
26931 +{
26932 + int retval = 0;
26933 +
26934 + if (DWC_OTG_PARAM_TEST(val, 2047, 524288)) {
26935 + DWC_WARN("Wrong value for max_transfer_size\n");
26936 + DWC_WARN("max_transfer_size must be 2047-524288\n");
26937 + return -DWC_E_INVALID;
26938 + }
26939 +
26940 + if (val >= (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))) {
26941 + if (dwc_otg_param_initialized
26942 + (core_if->core_params->max_transfer_size)) {
26943 + DWC_ERROR
26944 + ("%d invalid for max_transfer_size. Check HW configuration.\n",
26945 + val);
26946 + }
26947 + val =
26948 + ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 11)) -
26949 + 1);
26950 + retval = -DWC_E_INVALID;
26951 + }
26952 +
26953 + core_if->core_params->max_transfer_size = val;
26954 + return retval;
26955 +}
26956 +
26957 +int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if)
26958 +{
26959 + return core_if->core_params->max_transfer_size;
26960 +}
26961 +
26962 +int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if, int32_t val)
26963 +{
26964 + int retval = 0;
26965 +
26966 + if (DWC_OTG_PARAM_TEST(val, 15, 511)) {
26967 + DWC_WARN("Wrong value for max_packet_count\n");
26968 + DWC_WARN("max_packet_count must be 15-511\n");
26969 + return -DWC_E_INVALID;
26970 + }
26971 +
26972 + if (val > (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))) {
26973 + if (dwc_otg_param_initialized
26974 + (core_if->core_params->max_packet_count)) {
26975 + DWC_ERROR
26976 + ("%d invalid for max_packet_count. Check HW configuration.\n",
26977 + val);
26978 + }
26979 + val =
26980 + ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1);
26981 + retval = -DWC_E_INVALID;
26982 + }
26983 +
26984 + core_if->core_params->max_packet_count = val;
26985 + return retval;
26986 +}
26987 +
26988 +int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if)
26989 +{
26990 + return core_if->core_params->max_packet_count;
26991 +}
26992 +
26993 +int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if, int32_t val)
26994 +{
26995 + int retval = 0;
26996 +
26997 + if (DWC_OTG_PARAM_TEST(val, 1, 16)) {
26998 + DWC_WARN("Wrong value for host_channels\n");
26999 + DWC_WARN("host_channels must be 1-16\n");
27000 + return -DWC_E_INVALID;
27001 + }
27002 +
27003 + if (val > (core_if->hwcfg2.b.num_host_chan + 1)) {
27004 + if (dwc_otg_param_initialized
27005 + (core_if->core_params->host_channels)) {
27006 + DWC_ERROR
27007 + ("%d invalid for host_channels. Check HW configurations.\n",
27008 + val);
27009 + }
27010 + val = (core_if->hwcfg2.b.num_host_chan + 1);
27011 + retval = -DWC_E_INVALID;
27012 + }
27013 +
27014 + core_if->core_params->host_channels = val;
27015 + return retval;
27016 +}
27017 +
27018 +int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if)
27019 +{
27020 + return core_if->core_params->host_channels;
27021 +}
27022 +
27023 +int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if, int32_t val)
27024 +{
27025 + int retval = 0;
27026 +
27027 + if (DWC_OTG_PARAM_TEST(val, 1, 15)) {
27028 + DWC_WARN("Wrong value for dev_endpoints\n");
27029 + DWC_WARN("dev_endpoints must be 1-15\n");
27030 + return -DWC_E_INVALID;
27031 + }
27032 +
27033 + if (val > (core_if->hwcfg2.b.num_dev_ep)) {
27034 + if (dwc_otg_param_initialized
27035 + (core_if->core_params->dev_endpoints)) {
27036 + DWC_ERROR
27037 + ("%d invalid for dev_endpoints. Check HW configurations.\n",
27038 + val);
27039 + }
27040 + val = core_if->hwcfg2.b.num_dev_ep;
27041 + retval = -DWC_E_INVALID;
27042 + }
27043 +
27044 + core_if->core_params->dev_endpoints = val;
27045 + return retval;
27046 +}
27047 +
27048 +int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if)
27049 +{
27050 + return core_if->core_params->dev_endpoints;
27051 +}
27052 +
27053 +int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val)
27054 +{
27055 + int retval = 0;
27056 + int valid = 0;
27057 +
27058 + if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
27059 + DWC_WARN("Wrong value for phy_type\n");
27060 + DWC_WARN("phy_type must be 0,1 or 2\n");
27061 + return -DWC_E_INVALID;
27062 + }
27063 +#ifndef NO_FS_PHY_HW_CHECKS
27064 + if ((val == DWC_PHY_TYPE_PARAM_UTMI) &&
27065 + ((core_if->hwcfg2.b.hs_phy_type == 1) ||
27066 + (core_if->hwcfg2.b.hs_phy_type == 3))) {
27067 + valid = 1;
27068 + } else if ((val == DWC_PHY_TYPE_PARAM_ULPI) &&
27069 + ((core_if->hwcfg2.b.hs_phy_type == 2) ||
27070 + (core_if->hwcfg2.b.hs_phy_type == 3))) {
27071 + valid = 1;
27072 + } else if ((val == DWC_PHY_TYPE_PARAM_FS) &&
27073 + (core_if->hwcfg2.b.fs_phy_type == 1)) {
27074 + valid = 1;
27075 + }
27076 + if (!valid) {
27077 + if (dwc_otg_param_initialized(core_if->core_params->phy_type)) {
27078 + DWC_ERROR
27079 + ("%d invalid for phy_type. Check HW configurations.\n",
27080 + val);
27081 + }
27082 + if (core_if->hwcfg2.b.hs_phy_type) {
27083 + if ((core_if->hwcfg2.b.hs_phy_type == 3) ||
27084 + (core_if->hwcfg2.b.hs_phy_type == 1)) {
27085 + val = DWC_PHY_TYPE_PARAM_UTMI;
27086 + } else {
27087 + val = DWC_PHY_TYPE_PARAM_ULPI;
27088 + }
27089 + }
27090 + retval = -DWC_E_INVALID;
27091 + }
27092 +#endif
27093 + core_if->core_params->phy_type = val;
27094 + return retval;
27095 +}
27096 +
27097 +int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if)
27098 +{
27099 + return core_if->core_params->phy_type;
27100 +}
27101 +
27102 +int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val)
27103 +{
27104 + int retval = 0;
27105 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27106 + DWC_WARN("Wrong value for speed parameter\n");
27107 + DWC_WARN("max_speed parameter must be 0 or 1\n");
27108 + return -DWC_E_INVALID;
27109 + }
27110 + if ((val == 0)
27111 + && dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS) {
27112 + if (dwc_otg_param_initialized(core_if->core_params->speed)) {
27113 + DWC_ERROR
27114 + ("%d invalid for speed paremter. Check HW configuration.\n",
27115 + val);
27116 + }
27117 + val =
27118 + (dwc_otg_get_param_phy_type(core_if) ==
27119 + DWC_PHY_TYPE_PARAM_FS ? 1 : 0);
27120 + retval = -DWC_E_INVALID;
27121 + }
27122 + core_if->core_params->speed = val;
27123 + return retval;
27124 +}
27125 +
27126 +int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if)
27127 +{
27128 + return core_if->core_params->speed;
27129 +}
27130 +
27131 +int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if,
27132 + int32_t val)
27133 +{
27134 + int retval = 0;
27135 +
27136 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27137 + DWC_WARN
27138 + ("Wrong value for host_ls_low_power_phy_clk parameter\n");
27139 + DWC_WARN("host_ls_low_power_phy_clk must be 0 or 1\n");
27140 + return -DWC_E_INVALID;
27141 + }
27142 +
27143 + if ((val == DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ)
27144 + && (dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS)) {
27145 + if (dwc_otg_param_initialized
27146 + (core_if->core_params->host_ls_low_power_phy_clk)) {
27147 + DWC_ERROR
27148 + ("%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n",
27149 + val);
27150 + }
27151 + val =
27152 + (dwc_otg_get_param_phy_type(core_if) ==
27153 + DWC_PHY_TYPE_PARAM_FS) ?
27154 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ :
27155 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ;
27156 + retval = -DWC_E_INVALID;
27157 + }
27158 +
27159 + core_if->core_params->host_ls_low_power_phy_clk = val;
27160 + return retval;
27161 +}
27162 +
27163 +int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if)
27164 +{
27165 + return core_if->core_params->host_ls_low_power_phy_clk;
27166 +}
27167 +
27168 +int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if, int32_t val)
27169 +{
27170 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27171 + DWC_WARN("Wrong value for phy_ulpi_ddr\n");
27172 + DWC_WARN("phy_upli_ddr must be 0 or 1\n");
27173 + return -DWC_E_INVALID;
27174 + }
27175 +
27176 + core_if->core_params->phy_ulpi_ddr = val;
27177 + return 0;
27178 +}
27179 +
27180 +int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if)
27181 +{
27182 + return core_if->core_params->phy_ulpi_ddr;
27183 +}
27184 +
27185 +int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
27186 + int32_t val)
27187 +{
27188 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27189 + DWC_WARN("Wrong valaue for phy_ulpi_ext_vbus\n");
27190 + DWC_WARN("phy_ulpi_ext_vbus must be 0 or 1\n");
27191 + return -DWC_E_INVALID;
27192 + }
27193 +
27194 + core_if->core_params->phy_ulpi_ext_vbus = val;
27195 + return 0;
27196 +}
27197 +
27198 +int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if)
27199 +{
27200 + return core_if->core_params->phy_ulpi_ext_vbus;
27201 +}
27202 +
27203 +int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if, int32_t val)
27204 +{
27205 + if (DWC_OTG_PARAM_TEST(val, 8, 8) && DWC_OTG_PARAM_TEST(val, 16, 16)) {
27206 + DWC_WARN("Wrong valaue for phy_utmi_width\n");
27207 + DWC_WARN("phy_utmi_width must be 8 or 16\n");
27208 + return -DWC_E_INVALID;
27209 + }
27210 +
27211 + core_if->core_params->phy_utmi_width = val;
27212 + return 0;
27213 +}
27214 +
27215 +int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if)
27216 +{
27217 + return core_if->core_params->phy_utmi_width;
27218 +}
27219 +
27220 +int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if, int32_t val)
27221 +{
27222 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27223 + DWC_WARN("Wrong valaue for ulpi_fs_ls\n");
27224 + DWC_WARN("ulpi_fs_ls must be 0 or 1\n");
27225 + return -DWC_E_INVALID;
27226 + }
27227 +
27228 + core_if->core_params->ulpi_fs_ls = val;
27229 + return 0;
27230 +}
27231 +
27232 +int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if)
27233 +{
27234 + return core_if->core_params->ulpi_fs_ls;
27235 +}
27236 +
27237 +int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val)
27238 +{
27239 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27240 + DWC_WARN("Wrong valaue for ts_dline\n");
27241 + DWC_WARN("ts_dline must be 0 or 1\n");
27242 + return -DWC_E_INVALID;
27243 + }
27244 +
27245 + core_if->core_params->ts_dline = val;
27246 + return 0;
27247 +}
27248 +
27249 +int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if)
27250 +{
27251 + return core_if->core_params->ts_dline;
27252 +}
27253 +
27254 +int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if, int32_t val)
27255 +{
27256 + int retval = 0;
27257 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27258 + DWC_WARN("Wrong valaue for i2c_enable\n");
27259 + DWC_WARN("i2c_enable must be 0 or 1\n");
27260 + return -DWC_E_INVALID;
27261 + }
27262 +#ifndef NO_FS_PHY_HW_CHECK
27263 + if (val == 1 && core_if->hwcfg3.b.i2c == 0) {
27264 + if (dwc_otg_param_initialized(core_if->core_params->i2c_enable)) {
27265 + DWC_ERROR
27266 + ("%d invalid for i2c_enable. Check HW configuration.\n",
27267 + val);
27268 + }
27269 + val = 0;
27270 + retval = -DWC_E_INVALID;
27271 + }
27272 +#endif
27273 +
27274 + core_if->core_params->i2c_enable = val;
27275 + return retval;
27276 +}
27277 +
27278 +int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if)
27279 +{
27280 + return core_if->core_params->i2c_enable;
27281 +}
27282 +
27283 +int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
27284 + int32_t val, int fifo_num)
27285 +{
27286 + int retval = 0;
27287 +
27288 + if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
27289 + DWC_WARN("Wrong value for dev_perio_tx_fifo_size\n");
27290 + DWC_WARN("dev_perio_tx_fifo_size must be 4-768\n");
27291 + return -DWC_E_INVALID;
27292 + }
27293 +
27294 + if (val >
27295 + (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]))) {
27296 + if (dwc_otg_param_initialized
27297 + (core_if->core_params->dev_perio_tx_fifo_size[fifo_num])) {
27298 + DWC_ERROR
27299 + ("`%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n",
27300 + val, fifo_num);
27301 + }
27302 + val = (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]));
27303 + retval = -DWC_E_INVALID;
27304 + }
27305 +
27306 + core_if->core_params->dev_perio_tx_fifo_size[fifo_num] = val;
27307 + return retval;
27308 +}
27309 +
27310 +int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
27311 + int fifo_num)
27312 +{
27313 + return core_if->core_params->dev_perio_tx_fifo_size[fifo_num];
27314 +}
27315 +
27316 +int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
27317 + int32_t val)
27318 +{
27319 + int retval = 0;
27320 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27321 + DWC_WARN("Wrong valaue for en_multiple_tx_fifo,\n");
27322 + DWC_WARN("en_multiple_tx_fifo must be 0 or 1\n");
27323 + return -DWC_E_INVALID;
27324 + }
27325 +
27326 + if (val == 1 && core_if->hwcfg4.b.ded_fifo_en == 0) {
27327 + if (dwc_otg_param_initialized
27328 + (core_if->core_params->en_multiple_tx_fifo)) {
27329 + DWC_ERROR
27330 + ("%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n",
27331 + val);
27332 + }
27333 + val = 0;
27334 + retval = -DWC_E_INVALID;
27335 + }
27336 +
27337 + core_if->core_params->en_multiple_tx_fifo = val;
27338 + return retval;
27339 +}
27340 +
27341 +int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if)
27342 +{
27343 + return core_if->core_params->en_multiple_tx_fifo;
27344 +}
27345 +
27346 +int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val,
27347 + int fifo_num)
27348 +{
27349 + int retval = 0;
27350 +
27351 + if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
27352 + DWC_WARN("Wrong value for dev_tx_fifo_size\n");
27353 + DWC_WARN("dev_tx_fifo_size must be 4-768\n");
27354 + return -DWC_E_INVALID;
27355 + }
27356 +
27357 + if (val >
27358 + (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]))) {
27359 + if (dwc_otg_param_initialized
27360 + (core_if->core_params->dev_tx_fifo_size[fifo_num])) {
27361 + DWC_ERROR
27362 + ("`%d' invalid for parameter `dev_tx_fifo_size_%d'. Check HW configuration.\n",
27363 + val, fifo_num);
27364 + }
27365 + val = (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]));
27366 + retval = -DWC_E_INVALID;
27367 + }
27368 +
27369 + core_if->core_params->dev_tx_fifo_size[fifo_num] = val;
27370 + return retval;
27371 +}
27372 +
27373 +int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
27374 + int fifo_num)
27375 +{
27376 + return core_if->core_params->dev_tx_fifo_size[fifo_num];
27377 +}
27378 +
27379 +int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val)
27380 +{
27381 + int retval = 0;
27382 +
27383 + if (DWC_OTG_PARAM_TEST(val, 0, 7)) {
27384 + DWC_WARN("Wrong value for thr_ctl\n");
27385 + DWC_WARN("thr_ctl must be 0-7\n");
27386 + return -DWC_E_INVALID;
27387 + }
27388 +
27389 + if ((val != 0) &&
27390 + (!dwc_otg_get_param_dma_enable(core_if) ||
27391 + !core_if->hwcfg4.b.ded_fifo_en)) {
27392 + if (dwc_otg_param_initialized(core_if->core_params->thr_ctl)) {
27393 + DWC_ERROR
27394 + ("%d invalid for parameter thr_ctl. Check HW configuration.\n",
27395 + val);
27396 + }
27397 + val = 0;
27398 + retval = -DWC_E_INVALID;
27399 + }
27400 +
27401 + core_if->core_params->thr_ctl = val;
27402 + return retval;
27403 +}
27404 +
27405 +int32_t dwc_otg_get_param_thr_ctl(dwc_otg_core_if_t * core_if)
27406 +{
27407 + return core_if->core_params->thr_ctl;
27408 +}
27409 +
27410 +int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if, int32_t val)
27411 +{
27412 + int retval = 0;
27413 +
27414 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27415 + DWC_WARN("Wrong value for lpm_enable\n");
27416 + DWC_WARN("lpm_enable must be 0 or 1\n");
27417 + return -DWC_E_INVALID;
27418 + }
27419 +
27420 + if (val && !core_if->hwcfg3.b.otg_lpm_en) {
27421 + if (dwc_otg_param_initialized(core_if->core_params->lpm_enable)) {
27422 + DWC_ERROR
27423 + ("%d invalid for parameter lpm_enable. Check HW configuration.\n",
27424 + val);
27425 + }
27426 + val = 0;
27427 + retval = -DWC_E_INVALID;
27428 + }
27429 +
27430 + core_if->core_params->lpm_enable = val;
27431 + return retval;
27432 +}
27433 +
27434 +int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if)
27435 +{
27436 + return core_if->core_params->lpm_enable;
27437 +}
27438 +
27439 +int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
27440 +{
27441 + if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
27442 + DWC_WARN("Wrong valaue for tx_thr_length\n");
27443 + DWC_WARN("tx_thr_length must be 8 - 128\n");
27444 + return -DWC_E_INVALID;
27445 + }
27446 +
27447 + core_if->core_params->tx_thr_length = val;
27448 + return 0;
27449 +}
27450 +
27451 +int32_t dwc_otg_get_param_tx_thr_length(dwc_otg_core_if_t * core_if)
27452 +{
27453 + return core_if->core_params->tx_thr_length;
27454 +}
27455 +
27456 +int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
27457 +{
27458 + if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
27459 + DWC_WARN("Wrong valaue for rx_thr_length\n");
27460 + DWC_WARN("rx_thr_length must be 8 - 128\n");
27461 + return -DWC_E_INVALID;
27462 + }
27463 +
27464 + core_if->core_params->rx_thr_length = val;
27465 + return 0;
27466 +}
27467 +
27468 +int32_t dwc_otg_get_param_rx_thr_length(dwc_otg_core_if_t * core_if)
27469 +{
27470 + return core_if->core_params->rx_thr_length;
27471 +}
27472 +
27473 +int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if, int32_t val)
27474 +{
27475 + if (DWC_OTG_PARAM_TEST(val, 1, 1) &&
27476 + DWC_OTG_PARAM_TEST(val, 4, 4) &&
27477 + DWC_OTG_PARAM_TEST(val, 8, 8) &&
27478 + DWC_OTG_PARAM_TEST(val, 16, 16) &&
27479 + DWC_OTG_PARAM_TEST(val, 32, 32) &&
27480 + DWC_OTG_PARAM_TEST(val, 64, 64) &&
27481 + DWC_OTG_PARAM_TEST(val, 128, 128) &&
27482 + DWC_OTG_PARAM_TEST(val, 256, 256)) {
27483 + DWC_WARN("`%d' invalid for parameter `dma_burst_size'\n", val);
27484 + return -DWC_E_INVALID;
27485 + }
27486 + core_if->core_params->dma_burst_size = val;
27487 + return 0;
27488 +}
27489 +
27490 +int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if)
27491 +{
27492 + return core_if->core_params->dma_burst_size;
27493 +}
27494 +
27495 +int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if, int32_t val)
27496 +{
27497 + int retval = 0;
27498 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27499 + DWC_WARN("`%d' invalid for parameter `pti_enable'\n", val);
27500 + return -DWC_E_INVALID;
27501 + }
27502 + if (val && (core_if->snpsid < OTG_CORE_REV_2_72a)) {
27503 + if (dwc_otg_param_initialized(core_if->core_params->pti_enable)) {
27504 + DWC_ERROR
27505 + ("%d invalid for parameter pti_enable. Check HW configuration.\n",
27506 + val);
27507 + }
27508 + retval = -DWC_E_INVALID;
27509 + val = 0;
27510 + }
27511 + core_if->core_params->pti_enable = val;
27512 + return retval;
27513 +}
27514 +
27515 +int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if)
27516 +{
27517 + return core_if->core_params->pti_enable;
27518 +}
27519 +
27520 +int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if, int32_t val)
27521 +{
27522 + int retval = 0;
27523 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27524 + DWC_WARN("`%d' invalid for parameter `mpi_enable'\n", val);
27525 + return -DWC_E_INVALID;
27526 + }
27527 + if (val && (core_if->hwcfg2.b.multi_proc_int == 0)) {
27528 + if (dwc_otg_param_initialized(core_if->core_params->mpi_enable)) {
27529 + DWC_ERROR
27530 + ("%d invalid for parameter mpi_enable. Check HW configuration.\n",
27531 + val);
27532 + }
27533 + retval = -DWC_E_INVALID;
27534 + val = 0;
27535 + }
27536 + core_if->core_params->mpi_enable = val;
27537 + return retval;
27538 +}
27539 +
27540 +int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if)
27541 +{
27542 + return core_if->core_params->mpi_enable;
27543 +}
27544 +
27545 +int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if, int32_t val)
27546 +{
27547 + int retval = 0;
27548 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27549 + DWC_WARN("`%d' invalid for parameter `adp_enable'\n", val);
27550 + return -DWC_E_INVALID;
27551 + }
27552 + if (val && (core_if->hwcfg3.b.adp_supp == 0)) {
27553 + if (dwc_otg_param_initialized
27554 + (core_if->core_params->adp_supp_enable)) {
27555 + DWC_ERROR
27556 + ("%d invalid for parameter adp_enable. Check HW configuration.\n",
27557 + val);
27558 + }
27559 + retval = -DWC_E_INVALID;
27560 + val = 0;
27561 + }
27562 + core_if->core_params->adp_supp_enable = val;
27563 + /*Set OTG version 2.0 in case of enabling ADP*/
27564 + if (val)
27565 + dwc_otg_set_param_otg_ver(core_if, 1);
27566 +
27567 + return retval;
27568 +}
27569 +
27570 +int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if)
27571 +{
27572 + return core_if->core_params->adp_supp_enable;
27573 +}
27574 +
27575 +int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if, int32_t val)
27576 +{
27577 + int retval = 0;
27578 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27579 + DWC_WARN("`%d' invalid for parameter `ic_usb_cap'\n", val);
27580 + DWC_WARN("ic_usb_cap must be 0 or 1\n");
27581 + return -DWC_E_INVALID;
27582 + }
27583 +
27584 + if (val && (core_if->hwcfg2.b.otg_enable_ic_usb == 0)) {
27585 + if (dwc_otg_param_initialized(core_if->core_params->ic_usb_cap)) {
27586 + DWC_ERROR
27587 + ("%d invalid for parameter ic_usb_cap. Check HW configuration.\n",
27588 + val);
27589 + }
27590 + retval = -DWC_E_INVALID;
27591 + val = 0;
27592 + }
27593 + core_if->core_params->ic_usb_cap = val;
27594 + return retval;
27595 +}
27596 +
27597 +int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if)
27598 +{
27599 + return core_if->core_params->ic_usb_cap;
27600 +}
27601 +
27602 +int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if, int32_t val)
27603 +{
27604 + int retval = 0;
27605 + int valid = 1;
27606 +
27607 + if (DWC_OTG_PARAM_TEST(val, 0, 3)) {
27608 + DWC_WARN("`%d' invalid for parameter `ahb_thr_ratio'\n", val);
27609 + DWC_WARN("ahb_thr_ratio must be 0 - 3\n");
27610 + return -DWC_E_INVALID;
27611 + }
27612 +
27613 + if (val
27614 + && (core_if->snpsid < OTG_CORE_REV_2_81a
27615 + || !dwc_otg_get_param_thr_ctl(core_if))) {
27616 + valid = 0;
27617 + } else if (val
27618 + && ((dwc_otg_get_param_tx_thr_length(core_if) / (1 << val)) <
27619 + 4)) {
27620 + valid = 0;
27621 + }
27622 + if (valid == 0) {
27623 + if (dwc_otg_param_initialized
27624 + (core_if->core_params->ahb_thr_ratio)) {
27625 + DWC_ERROR
27626 + ("%d invalid for parameter ahb_thr_ratio. Check HW configuration.\n",
27627 + val);
27628 + }
27629 + retval = -DWC_E_INVALID;
27630 + val = 0;
27631 + }
27632 +
27633 + core_if->core_params->ahb_thr_ratio = val;
27634 + return retval;
27635 +}
27636 +
27637 +int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if)
27638 +{
27639 + return core_if->core_params->ahb_thr_ratio;
27640 +}
27641 +
27642 +int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if, int32_t val)
27643 +{
27644 + int retval = 0;
27645 + int valid = 1;
27646 + hwcfg4_data_t hwcfg4 = {.d32 = 0 };
27647 + hwcfg4.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
27648 +
27649 + if (DWC_OTG_PARAM_TEST(val, 0, 3)) {
27650 + DWC_WARN("`%d' invalid for parameter `power_down'\n", val);
27651 + DWC_WARN("power_down must be 0 - 2\n");
27652 + return -DWC_E_INVALID;
27653 + }
27654 +
27655 + if ((val == 2) && (core_if->snpsid < OTG_CORE_REV_2_91a)) {
27656 + valid = 0;
27657 + }
27658 + if ((val == 3)
27659 + && ((core_if->snpsid < OTG_CORE_REV_3_00a)
27660 + || (hwcfg4.b.xhiber == 0))) {
27661 + valid = 0;
27662 + }
27663 + if (valid == 0) {
27664 + if (dwc_otg_param_initialized(core_if->core_params->power_down)) {
27665 + DWC_ERROR
27666 + ("%d invalid for parameter power_down. Check HW configuration.\n",
27667 + val);
27668 + }
27669 + retval = -DWC_E_INVALID;
27670 + val = 0;
27671 + }
27672 + core_if->core_params->power_down = val;
27673 + return retval;
27674 +}
27675 +
27676 +int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if)
27677 +{
27678 + return core_if->core_params->power_down;
27679 +}
27680 +
27681 +int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if, int32_t val)
27682 +{
27683 + int retval = 0;
27684 + int valid = 1;
27685 +
27686 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27687 + DWC_WARN("`%d' invalid for parameter `reload_ctl'\n", val);
27688 + DWC_WARN("reload_ctl must be 0 or 1\n");
27689 + return -DWC_E_INVALID;
27690 + }
27691 +
27692 + if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_92a)) {
27693 + valid = 0;
27694 + }
27695 + if (valid == 0) {
27696 + if (dwc_otg_param_initialized(core_if->core_params->reload_ctl)) {
27697 + DWC_ERROR("%d invalid for parameter reload_ctl."
27698 + "Check HW configuration.\n", val);
27699 + }
27700 + retval = -DWC_E_INVALID;
27701 + val = 0;
27702 + }
27703 + core_if->core_params->reload_ctl = val;
27704 + return retval;
27705 +}
27706 +
27707 +int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if)
27708 +{
27709 + return core_if->core_params->reload_ctl;
27710 +}
27711 +
27712 +int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if, int32_t val)
27713 +{
27714 + int retval = 0;
27715 + int valid = 1;
27716 +
27717 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27718 + DWC_WARN("`%d' invalid for parameter `dev_out_nak'\n", val);
27719 + DWC_WARN("dev_out_nak must be 0 or 1\n");
27720 + return -DWC_E_INVALID;
27721 + }
27722 +
27723 + if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_93a) ||
27724 + !(core_if->core_params->dma_desc_enable))) {
27725 + valid = 0;
27726 + }
27727 + if (valid == 0) {
27728 + if (dwc_otg_param_initialized(core_if->core_params->dev_out_nak)) {
27729 + DWC_ERROR("%d invalid for parameter dev_out_nak."
27730 + "Check HW configuration.\n", val);
27731 + }
27732 + retval = -DWC_E_INVALID;
27733 + val = 0;
27734 + }
27735 + core_if->core_params->dev_out_nak = val;
27736 + return retval;
27737 +}
27738 +
27739 +int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if)
27740 +{
27741 + return core_if->core_params->dev_out_nak;
27742 +}
27743 +
27744 +int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if, int32_t val)
27745 +{
27746 + int retval = 0;
27747 + int valid = 1;
27748 +
27749 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27750 + DWC_WARN("`%d' invalid for parameter `cont_on_bna'\n", val);
27751 + DWC_WARN("cont_on_bna must be 0 or 1\n");
27752 + return -DWC_E_INVALID;
27753 + }
27754 +
27755 + if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_94a) ||
27756 + !(core_if->core_params->dma_desc_enable))) {
27757 + valid = 0;
27758 + }
27759 + if (valid == 0) {
27760 + if (dwc_otg_param_initialized(core_if->core_params->cont_on_bna)) {
27761 + DWC_ERROR("%d invalid for parameter cont_on_bna."
27762 + "Check HW configuration.\n", val);
27763 + }
27764 + retval = -DWC_E_INVALID;
27765 + val = 0;
27766 + }
27767 + core_if->core_params->cont_on_bna = val;
27768 + return retval;
27769 +}
27770 +
27771 +int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if)
27772 +{
27773 + return core_if->core_params->cont_on_bna;
27774 +}
27775 +
27776 +int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if, int32_t val)
27777 +{
27778 + int retval = 0;
27779 + int valid = 1;
27780 +
27781 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27782 + DWC_WARN("`%d' invalid for parameter `ahb_single'\n", val);
27783 + DWC_WARN("ahb_single must be 0 or 1\n");
27784 + return -DWC_E_INVALID;
27785 + }
27786 +
27787 + if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_94a)) {
27788 + valid = 0;
27789 + }
27790 + if (valid == 0) {
27791 + if (dwc_otg_param_initialized(core_if->core_params->ahb_single)) {
27792 + DWC_ERROR("%d invalid for parameter ahb_single."
27793 + "Check HW configuration.\n", val);
27794 + }
27795 + retval = -DWC_E_INVALID;
27796 + val = 0;
27797 + }
27798 + core_if->core_params->ahb_single = val;
27799 + return retval;
27800 +}
27801 +
27802 +int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if)
27803 +{
27804 + return core_if->core_params->ahb_single;
27805 +}
27806 +
27807 +int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val)
27808 +{
27809 + int retval = 0;
27810 +
27811 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27812 + DWC_WARN("`%d' invalid for parameter `otg_ver'\n", val);
27813 + DWC_WARN
27814 + ("otg_ver must be 0(for OTG 1.3 support) or 1(for OTG 2.0 support)\n");
27815 + return -DWC_E_INVALID;
27816 + }
27817 +
27818 + core_if->core_params->otg_ver = val;
27819 + return retval;
27820 +}
27821 +
27822 +int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if)
27823 +{
27824 + return core_if->core_params->otg_ver;
27825 +}
27826 +
27827 +uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if)
27828 +{
27829 + gotgctl_data_t otgctl;
27830 + otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27831 + return otgctl.b.hstnegscs;
27832 +}
27833 +
27834 +uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if)
27835 +{
27836 + gotgctl_data_t otgctl;
27837 + otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27838 + return otgctl.b.sesreqscs;
27839 +}
27840 +
27841 +void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val)
27842 +{
27843 + if(core_if->otg_ver == 0) {
27844 + gotgctl_data_t otgctl;
27845 + otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27846 + otgctl.b.hnpreq = val;
27847 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, otgctl.d32);
27848 + } else {
27849 + core_if->otg_sts = val;
27850 + }
27851 +}
27852 +
27853 +uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if)
27854 +{
27855 + return core_if->snpsid;
27856 +}
27857 +
27858 +uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if)
27859 +{
27860 + gintsts_data_t gintsts;
27861 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
27862 + return gintsts.b.curmode;
27863 +}
27864 +
27865 +uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if)
27866 +{
27867 + gusbcfg_data_t usbcfg;
27868 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27869 + return usbcfg.b.hnpcap;
27870 +}
27871 +
27872 +void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
27873 +{
27874 + gusbcfg_data_t usbcfg;
27875 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27876 + usbcfg.b.hnpcap = val;
27877 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
27878 +}
27879 +
27880 +uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if)
27881 +{
27882 + gusbcfg_data_t usbcfg;
27883 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27884 + return usbcfg.b.srpcap;
27885 +}
27886 +
27887 +void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
27888 +{
27889 + gusbcfg_data_t usbcfg;
27890 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27891 + usbcfg.b.srpcap = val;
27892 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
27893 +}
27894 +
27895 +uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if)
27896 +{
27897 + dcfg_data_t dcfg;
27898 + /* originally: dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg); */
27899 +
27900 + dcfg.d32 = -1; //GRAYG
27901 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)\n", __func__, core_if);
27902 + if (NULL == core_if)
27903 + DWC_ERROR("reg request with NULL core_if\n");
27904 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)\n", __func__,
27905 + core_if, core_if->dev_if);
27906 + if (NULL == core_if->dev_if)
27907 + DWC_ERROR("reg request with NULL dev_if\n");
27908 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)->"
27909 + "dev_global_regs(%p)\n", __func__,
27910 + core_if, core_if->dev_if,
27911 + core_if->dev_if->dev_global_regs);
27912 + if (NULL == core_if->dev_if->dev_global_regs)
27913 + DWC_ERROR("reg request with NULL dev_global_regs\n");
27914 + else {
27915 + DWC_DEBUGPL(DBG_CILV, "%s - &core_if(%p)->dev_if(%p)->"
27916 + "dev_global_regs(%p)->dcfg = %p\n", __func__,
27917 + core_if, core_if->dev_if,
27918 + core_if->dev_if->dev_global_regs,
27919 + &core_if->dev_if->dev_global_regs->dcfg);
27920 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
27921 + }
27922 + return dcfg.b.devspd;
27923 +}
27924 +
27925 +void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val)
27926 +{
27927 + dcfg_data_t dcfg;
27928 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
27929 + dcfg.b.devspd = val;
27930 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
27931 +}
27932 +
27933 +uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if)
27934 +{
27935 + hprt0_data_t hprt0;
27936 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
27937 + return hprt0.b.prtconnsts;
27938 +}
27939 +
27940 +uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if)
27941 +{
27942 + dsts_data_t dsts;
27943 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
27944 + return dsts.b.enumspd;
27945 +}
27946 +
27947 +uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if)
27948 +{
27949 + hprt0_data_t hprt0;
27950 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
27951 + return hprt0.b.prtpwr;
27952 +
27953 +}
27954 +
27955 +uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if)
27956 +{
27957 + return core_if->hibernation_suspend;
27958 +}
27959 +
27960 +void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val)
27961 +{
27962 + hprt0_data_t hprt0;
27963 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
27964 + hprt0.b.prtpwr = val;
27965 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
27966 +}
27967 +
27968 +uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if)
27969 +{
27970 + hprt0_data_t hprt0;
27971 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
27972 + return hprt0.b.prtsusp;
27973 +
27974 +}
27975 +
27976 +void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val)
27977 +{
27978 + hprt0_data_t hprt0;
27979 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
27980 + hprt0.b.prtsusp = val;
27981 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
27982 +}
27983 +
27984 +uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if)
27985 +{
27986 + hfir_data_t hfir;
27987 + hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
27988 + return hfir.b.frint;
27989 +
27990 +}
27991 +
27992 +void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val)
27993 +{
27994 + hfir_data_t hfir;
27995 + uint32_t fram_int;
27996 + fram_int = calc_frame_interval(core_if);
27997 + hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
27998 + if (!core_if->core_params->reload_ctl) {
27999 + DWC_WARN("\nCannot reload HFIR register.HFIR.HFIRRldCtrl bit is"
28000 + "not set to 1.\nShould load driver with reload_ctl=1"
28001 + " module parameter\n");
28002 + return;
28003 + }
28004 + switch (fram_int) {
28005 + case 3750:
28006 + if ((val < 3350) || (val > 4150)) {
28007 + DWC_WARN("HFIR interval for HS core and 30 MHz"
28008 + "clock freq should be from 3350 to 4150\n");
28009 + return;
28010 + }
28011 + break;
28012 + case 30000:
28013 + if ((val < 26820) || (val > 33180)) {
28014 + DWC_WARN("HFIR interval for FS/LS core and 30 MHz"
28015 + "clock freq should be from 26820 to 33180\n");
28016 + return;
28017 + }
28018 + break;
28019 + case 6000:
28020 + if ((val < 5360) || (val > 6640)) {
28021 + DWC_WARN("HFIR interval for HS core and 48 MHz"
28022 + "clock freq should be from 5360 to 6640\n");
28023 + return;
28024 + }
28025 + break;
28026 + case 48000:
28027 + if ((val < 42912) || (val > 53088)) {
28028 + DWC_WARN("HFIR interval for FS/LS core and 48 MHz"
28029 + "clock freq should be from 42912 to 53088\n");
28030 + return;
28031 + }
28032 + break;
28033 + case 7500:
28034 + if ((val < 6700) || (val > 8300)) {
28035 + DWC_WARN("HFIR interval for HS core and 60 MHz"
28036 + "clock freq should be from 6700 to 8300\n");
28037 + return;
28038 + }
28039 + break;
28040 + case 60000:
28041 + if ((val < 53640) || (val > 65536)) {
28042 + DWC_WARN("HFIR interval for FS/LS core and 60 MHz"
28043 + "clock freq should be from 53640 to 65536\n");
28044 + return;
28045 + }
28046 + break;
28047 + default:
28048 + DWC_WARN("Unknown frame interval\n");
28049 + return;
28050 + break;
28051 +
28052 + }
28053 + hfir.b.frint = val;
28054 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hfir.d32);
28055 +}
28056 +
28057 +uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if)
28058 +{
28059 + hcfg_data_t hcfg;
28060 + hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
28061 + return hcfg.b.modechtimen;
28062 +
28063 +}
28064 +
28065 +void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val)
28066 +{
28067 + hcfg_data_t hcfg;
28068 + hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
28069 + hcfg.b.modechtimen = val;
28070 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
28071 +}
28072 +
28073 +void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val)
28074 +{
28075 + hprt0_data_t hprt0;
28076 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
28077 + hprt0.b.prtres = val;
28078 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
28079 +}
28080 +
28081 +uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if)
28082 +{
28083 + dctl_data_t dctl;
28084 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
28085 + return dctl.b.rmtwkupsig;
28086 +}
28087 +
28088 +uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if)
28089 +{
28090 + glpmcfg_data_t lpmcfg;
28091 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28092 +
28093 + DWC_ASSERT(!
28094 + ((core_if->lx_state == DWC_OTG_L1) ^ lpmcfg.b.prt_sleep_sts),
28095 + "lx_state = %d, lmpcfg.prt_sleep_sts = %d\n",
28096 + core_if->lx_state, lpmcfg.b.prt_sleep_sts);
28097 +
28098 + return lpmcfg.b.prt_sleep_sts;
28099 +}
28100 +
28101 +uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if)
28102 +{
28103 + glpmcfg_data_t lpmcfg;
28104 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28105 + return lpmcfg.b.rem_wkup_en;
28106 +}
28107 +
28108 +uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if)
28109 +{
28110 + glpmcfg_data_t lpmcfg;
28111 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28112 + return lpmcfg.b.appl_resp;
28113 +}
28114 +
28115 +void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val)
28116 +{
28117 + glpmcfg_data_t lpmcfg;
28118 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28119 + lpmcfg.b.appl_resp = val;
28120 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
28121 +}
28122 +
28123 +uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if)
28124 +{
28125 + glpmcfg_data_t lpmcfg;
28126 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28127 + return lpmcfg.b.hsic_connect;
28128 +}
28129 +
28130 +void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val)
28131 +{
28132 + glpmcfg_data_t lpmcfg;
28133 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28134 + lpmcfg.b.hsic_connect = val;
28135 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
28136 +}
28137 +
28138 +uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if)
28139 +{
28140 + glpmcfg_data_t lpmcfg;
28141 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28142 + return lpmcfg.b.inv_sel_hsic;
28143 +
28144 +}
28145 +
28146 +void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val)
28147 +{
28148 + glpmcfg_data_t lpmcfg;
28149 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28150 + lpmcfg.b.inv_sel_hsic = val;
28151 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
28152 +}
28153 +
28154 +uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if)
28155 +{
28156 + return DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
28157 +}
28158 +
28159 +void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val)
28160 +{
28161 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, val);
28162 +}
28163 +
28164 +uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if)
28165 +{
28166 + return DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
28167 +}
28168 +
28169 +void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val)
28170 +{
28171 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, val);
28172 +}
28173 +
28174 +uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if)
28175 +{
28176 + return DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
28177 +}
28178 +
28179 +void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
28180 +{
28181 + DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, val);
28182 +}
28183 +
28184 +uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if)
28185 +{
28186 + return DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
28187 +}
28188 +
28189 +void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
28190 +{
28191 + DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz, val);
28192 +}
28193 +
28194 +uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if)
28195 +{
28196 + return DWC_READ_REG32(&core_if->core_global_regs->gpvndctl);
28197 +}
28198 +
28199 +void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val)
28200 +{
28201 + DWC_WRITE_REG32(&core_if->core_global_regs->gpvndctl, val);
28202 +}
28203 +
28204 +uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if)
28205 +{
28206 + return DWC_READ_REG32(&core_if->core_global_regs->ggpio);
28207 +}
28208 +
28209 +void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val)
28210 +{
28211 + DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, val);
28212 +}
28213 +
28214 +uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if)
28215 +{
28216 + return DWC_READ_REG32(core_if->host_if->hprt0);
28217 +
28218 +}
28219 +
28220 +void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val)
28221 +{
28222 + DWC_WRITE_REG32(core_if->host_if->hprt0, val);
28223 +}
28224 +
28225 +uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if)
28226 +{
28227 + return DWC_READ_REG32(&core_if->core_global_regs->guid);
28228 +}
28229 +
28230 +void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val)
28231 +{
28232 + DWC_WRITE_REG32(&core_if->core_global_regs->guid, val);
28233 +}
28234 +
28235 +uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if)
28236 +{
28237 + return DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
28238 +}
28239 +
28240 +uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if)
28241 +{
28242 + return ((core_if->otg_ver == 1) ? (uint16_t)0x0200 : (uint16_t)0x0103);
28243 +}
28244 +
28245 +/**
28246 + * Start the SRP timer to detect when the SRP does not complete within
28247 + * 6 seconds.
28248 + *
28249 + * @param core_if the pointer to core_if strucure.
28250 + */
28251 +void dwc_otg_pcd_start_srp_timer(dwc_otg_core_if_t * core_if)
28252 +{
28253 + core_if->srp_timer_started = 1;
28254 + DWC_TIMER_SCHEDULE(core_if->srp_timer, 6000 /* 6 secs */ );
28255 +}
28256 +
28257 +void dwc_otg_initiate_srp(dwc_otg_core_if_t * core_if)
28258 +{
28259 + uint32_t *addr = (uint32_t *) & (core_if->core_global_regs->gotgctl);
28260 + gotgctl_data_t mem;
28261 + gotgctl_data_t val;
28262 +
28263 + val.d32 = DWC_READ_REG32(addr);
28264 + if (val.b.sesreq) {
28265 + DWC_ERROR("Session Request Already active!\n");
28266 + return;
28267 + }
28268 +
28269 + DWC_INFO("Session Request Initated\n"); //NOTICE
28270 + mem.d32 = DWC_READ_REG32(addr);
28271 + mem.b.sesreq = 1;
28272 + DWC_WRITE_REG32(addr, mem.d32);
28273 +
28274 + /* Start the SRP timer */
28275 + dwc_otg_pcd_start_srp_timer(core_if);
28276 + return;
28277 +}
28278 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil.h b/drivers/usb/host/dwc_otg/dwc_otg_cil.h
28279 new file mode 100644
28280 index 0000000..79dbf83
28281 --- /dev/null
28282 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.h
28283 @@ -0,0 +1,1464 @@
28284 +/* ==========================================================================
28285 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.h $
28286 + * $Revision: #123 $
28287 + * $Date: 2012/08/10 $
28288 + * $Change: 2047372 $
28289 + *
28290 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
28291 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
28292 + * otherwise expressly agreed to in writing between Synopsys and you.
28293 + *
28294 + * The Software IS NOT an item of Licensed Software or Licensed Product under
28295 + * any End User Software License Agreement or Agreement for Licensed Product
28296 + * with Synopsys or any supplement thereto. You are permitted to use and
28297 + * redistribute this Software in source and binary forms, with or without
28298 + * modification, provided that redistributions of source code must retain this
28299 + * notice. You may not view, use, disclose, copy or distribute this file or
28300 + * any information contained herein except pursuant to this license grant from
28301 + * Synopsys. If you do not agree with this notice, including the disclaimer
28302 + * below, then you are not authorized to use the Software.
28303 + *
28304 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
28305 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28306 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28307 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
28308 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28309 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28310 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28311 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28312 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28313 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28314 + * DAMAGE.
28315 + * ========================================================================== */
28316 +
28317 +#if !defined(__DWC_CIL_H__)
28318 +#define __DWC_CIL_H__
28319 +
28320 +#include "dwc_list.h"
28321 +#include "dwc_otg_dbg.h"
28322 +#include "dwc_otg_regs.h"
28323 +
28324 +#include "dwc_otg_core_if.h"
28325 +#include "dwc_otg_adp.h"
28326 +
28327 +/**
28328 + * @file
28329 + * This file contains the interface to the Core Interface Layer.
28330 + */
28331 +
28332 +#ifdef DWC_UTE_CFI
28333 +
28334 +#define MAX_DMA_DESCS_PER_EP 256
28335 +
28336 +/**
28337 + * Enumeration for the data buffer mode
28338 + */
28339 +typedef enum _data_buffer_mode {
28340 + BM_STANDARD = 0, /* data buffer is in normal mode */
28341 + BM_SG = 1, /* data buffer uses the scatter/gather mode */
28342 + BM_CONCAT = 2, /* data buffer uses the concatenation mode */
28343 + BM_CIRCULAR = 3, /* data buffer uses the circular DMA mode */
28344 + BM_ALIGN = 4 /* data buffer is in buffer alignment mode */
28345 +} data_buffer_mode_e;
28346 +#endif //DWC_UTE_CFI
28347 +
28348 +/** Macros defined for DWC OTG HW Release version */
28349 +
28350 +#define OTG_CORE_REV_2_60a 0x4F54260A
28351 +#define OTG_CORE_REV_2_71a 0x4F54271A
28352 +#define OTG_CORE_REV_2_72a 0x4F54272A
28353 +#define OTG_CORE_REV_2_80a 0x4F54280A
28354 +#define OTG_CORE_REV_2_81a 0x4F54281A
28355 +#define OTG_CORE_REV_2_90a 0x4F54290A
28356 +#define OTG_CORE_REV_2_91a 0x4F54291A
28357 +#define OTG_CORE_REV_2_92a 0x4F54292A
28358 +#define OTG_CORE_REV_2_93a 0x4F54293A
28359 +#define OTG_CORE_REV_2_94a 0x4F54294A
28360 +#define OTG_CORE_REV_3_00a 0x4F54300A
28361 +
28362 +/**
28363 + * Information for each ISOC packet.
28364 + */
28365 +typedef struct iso_pkt_info {
28366 + uint32_t offset;
28367 + uint32_t length;
28368 + int32_t status;
28369 +} iso_pkt_info_t;
28370 +
28371 +/**
28372 + * The <code>dwc_ep</code> structure represents the state of a single
28373 + * endpoint when acting in device mode. It contains the data items
28374 + * needed for an endpoint to be activated and transfer packets.
28375 + */
28376 +typedef struct dwc_ep {
28377 + /** EP number used for register address lookup */
28378 + uint8_t num;
28379 + /** EP direction 0 = OUT */
28380 + unsigned is_in:1;
28381 + /** EP active. */
28382 + unsigned active:1;
28383 +
28384 + /**
28385 + * Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic
28386 + * Tx FIFO. If dedicated Tx FIFOs are enabled Tx FIFO # FOR IN EPs*/
28387 + unsigned tx_fifo_num:4;
28388 + /** EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR */
28389 + unsigned type:2;
28390 +#define DWC_OTG_EP_TYPE_CONTROL 0
28391 +#define DWC_OTG_EP_TYPE_ISOC 1
28392 +#define DWC_OTG_EP_TYPE_BULK 2
28393 +#define DWC_OTG_EP_TYPE_INTR 3
28394 +
28395 + /** DATA start PID for INTR and BULK EP */
28396 + unsigned data_pid_start:1;
28397 + /** Frame (even/odd) for ISOC EP */
28398 + unsigned even_odd_frame:1;
28399 + /** Max Packet bytes */
28400 + unsigned maxpacket:11;
28401 +
28402 + /** Max Transfer size */
28403 + uint32_t maxxfer;
28404 +
28405 + /** @name Transfer state */
28406 + /** @{ */
28407 +
28408 + /**
28409 + * Pointer to the beginning of the transfer buffer -- do not modify
28410 + * during transfer.
28411 + */
28412 +
28413 + dwc_dma_t dma_addr;
28414 +
28415 + dwc_dma_t dma_desc_addr;
28416 + dwc_otg_dev_dma_desc_t *desc_addr;
28417 +
28418 + uint8_t *start_xfer_buff;
28419 + /** pointer to the transfer buffer */
28420 + uint8_t *xfer_buff;
28421 + /** Number of bytes to transfer */
28422 + unsigned xfer_len:19;
28423 + /** Number of bytes transferred. */
28424 + unsigned xfer_count:19;
28425 + /** Sent ZLP */
28426 + unsigned sent_zlp:1;
28427 + /** Total len for control transfer */
28428 + unsigned total_len:19;
28429 +
28430 + /** stall clear flag */
28431 + unsigned stall_clear_flag:1;
28432 +
28433 + /** SETUP pkt cnt rollover flag for EP0 out*/
28434 + unsigned stp_rollover;
28435 +
28436 +#ifdef DWC_UTE_CFI
28437 + /* The buffer mode */
28438 + data_buffer_mode_e buff_mode;
28439 +
28440 + /* The chain of DMA descriptors.
28441 + * MAX_DMA_DESCS_PER_EP will be allocated for each active EP.
28442 + */
28443 + dwc_otg_dma_desc_t *descs;
28444 +
28445 + /* The DMA address of the descriptors chain start */
28446 + dma_addr_t descs_dma_addr;
28447 + /** This variable stores the length of the last enqueued request */
28448 + uint32_t cfi_req_len;
28449 +#endif //DWC_UTE_CFI
28450 +
28451 +/** Max DMA Descriptor count for any EP */
28452 +#define MAX_DMA_DESC_CNT 256
28453 + /** Allocated DMA Desc count */
28454 + uint32_t desc_cnt;
28455 +
28456 + /** bInterval */
28457 + uint32_t bInterval;
28458 + /** Next frame num to setup next ISOC transfer */
28459 + uint32_t frame_num;
28460 + /** Indicates SOF number overrun in DSTS */
28461 + uint8_t frm_overrun;
28462 +
28463 +#ifdef DWC_UTE_PER_IO
28464 + /** Next frame num for which will be setup DMA Desc */
28465 + uint32_t xiso_frame_num;
28466 + /** bInterval */
28467 + uint32_t xiso_bInterval;
28468 + /** Count of currently active transfers - shall be either 0 or 1 */
28469 + int xiso_active_xfers;
28470 + int xiso_queued_xfers;
28471 +#endif
28472 +#ifdef DWC_EN_ISOC
28473 + /**
28474 + * Variables specific for ISOC EPs
28475 + *
28476 + */
28477 + /** DMA addresses of ISOC buffers */
28478 + dwc_dma_t dma_addr0;
28479 + dwc_dma_t dma_addr1;
28480 +
28481 + dwc_dma_t iso_dma_desc_addr;
28482 + dwc_otg_dev_dma_desc_t *iso_desc_addr;
28483 +
28484 + /** pointer to the transfer buffers */
28485 + uint8_t *xfer_buff0;
28486 + uint8_t *xfer_buff1;
28487 +
28488 + /** number of ISOC Buffer is processing */
28489 + uint32_t proc_buf_num;
28490 + /** Interval of ISOC Buffer processing */
28491 + uint32_t buf_proc_intrvl;
28492 + /** Data size for regular frame */
28493 + uint32_t data_per_frame;
28494 +
28495 + /* todo - pattern data support is to be implemented in the future */
28496 + /** Data size for pattern frame */
28497 + uint32_t data_pattern_frame;
28498 + /** Frame number of pattern data */
28499 + uint32_t sync_frame;
28500 +
28501 + /** bInterval */
28502 + uint32_t bInterval;
28503 + /** ISO Packet number per frame */
28504 + uint32_t pkt_per_frm;
28505 + /** Next frame num for which will be setup DMA Desc */
28506 + uint32_t next_frame;
28507 + /** Number of packets per buffer processing */
28508 + uint32_t pkt_cnt;
28509 + /** Info for all isoc packets */
28510 + iso_pkt_info_t *pkt_info;
28511 + /** current pkt number */
28512 + uint32_t cur_pkt;
28513 + /** current pkt number */
28514 + uint8_t *cur_pkt_addr;
28515 + /** current pkt number */
28516 + uint32_t cur_pkt_dma_addr;
28517 +#endif /* DWC_EN_ISOC */
28518 +
28519 +/** @} */
28520 +} dwc_ep_t;
28521 +
28522 +/*
28523 + * Reasons for halting a host channel.
28524 + */
28525 +typedef enum dwc_otg_halt_status {
28526 + DWC_OTG_HC_XFER_NO_HALT_STATUS,
28527 + DWC_OTG_HC_XFER_COMPLETE,
28528 + DWC_OTG_HC_XFER_URB_COMPLETE,
28529 + DWC_OTG_HC_XFER_ACK,
28530 + DWC_OTG_HC_XFER_NAK,
28531 + DWC_OTG_HC_XFER_NYET,
28532 + DWC_OTG_HC_XFER_STALL,
28533 + DWC_OTG_HC_XFER_XACT_ERR,
28534 + DWC_OTG_HC_XFER_FRAME_OVERRUN,
28535 + DWC_OTG_HC_XFER_BABBLE_ERR,
28536 + DWC_OTG_HC_XFER_DATA_TOGGLE_ERR,
28537 + DWC_OTG_HC_XFER_AHB_ERR,
28538 + DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE,
28539 + DWC_OTG_HC_XFER_URB_DEQUEUE
28540 +} dwc_otg_halt_status_e;
28541 +
28542 +/**
28543 + * Host channel descriptor. This structure represents the state of a single
28544 + * host channel when acting in host mode. It contains the data items needed to
28545 + * transfer packets to an endpoint via a host channel.
28546 + */
28547 +typedef struct dwc_hc {
28548 + /** Host channel number used for register address lookup */
28549 + uint8_t hc_num;
28550 +
28551 + /** Device to access */
28552 + unsigned dev_addr:7;
28553 +
28554 + /** EP to access */
28555 + unsigned ep_num:4;
28556 +
28557 + /** EP direction. 0: OUT, 1: IN */
28558 + unsigned ep_is_in:1;
28559 +
28560 + /**
28561 + * EP speed.
28562 + * One of the following values:
28563 + * - DWC_OTG_EP_SPEED_LOW
28564 + * - DWC_OTG_EP_SPEED_FULL
28565 + * - DWC_OTG_EP_SPEED_HIGH
28566 + */
28567 + unsigned speed:2;
28568 +#define DWC_OTG_EP_SPEED_LOW 0
28569 +#define DWC_OTG_EP_SPEED_FULL 1
28570 +#define DWC_OTG_EP_SPEED_HIGH 2
28571 +
28572 + /**
28573 + * Endpoint type.
28574 + * One of the following values:
28575 + * - DWC_OTG_EP_TYPE_CONTROL: 0
28576 + * - DWC_OTG_EP_TYPE_ISOC: 1
28577 + * - DWC_OTG_EP_TYPE_BULK: 2
28578 + * - DWC_OTG_EP_TYPE_INTR: 3
28579 + */
28580 + unsigned ep_type:2;
28581 +
28582 + /** Max packet size in bytes */
28583 + unsigned max_packet:11;
28584 +
28585 + /**
28586 + * PID for initial transaction.
28587 + * 0: DATA0,<br>
28588 + * 1: DATA2,<br>
28589 + * 2: DATA1,<br>
28590 + * 3: MDATA (non-Control EP),
28591 + * SETUP (Control EP)
28592 + */
28593 + unsigned data_pid_start:2;
28594 +#define DWC_OTG_HC_PID_DATA0 0
28595 +#define DWC_OTG_HC_PID_DATA2 1
28596 +#define DWC_OTG_HC_PID_DATA1 2
28597 +#define DWC_OTG_HC_PID_MDATA 3
28598 +#define DWC_OTG_HC_PID_SETUP 3
28599 +
28600 + /** Number of periodic transactions per (micro)frame */
28601 + unsigned multi_count:2;
28602 +
28603 + /** @name Transfer State */
28604 + /** @{ */
28605 +
28606 + /** Pointer to the current transfer buffer position. */
28607 + uint8_t *xfer_buff;
28608 + /**
28609 + * In Buffer DMA mode this buffer will be used
28610 + * if xfer_buff is not DWORD aligned.
28611 + */
28612 + dwc_dma_t align_buff;
28613 + /** Total number of bytes to transfer. */
28614 + uint32_t xfer_len;
28615 + /** Number of bytes transferred so far. */
28616 + uint32_t xfer_count;
28617 + /** Packet count at start of transfer.*/
28618 + uint16_t start_pkt_count;
28619 +
28620 + /**
28621 + * Flag to indicate whether the transfer has been started. Set to 1 if
28622 + * it has been started, 0 otherwise.
28623 + */
28624 + uint8_t xfer_started;
28625 +
28626 + /**
28627 + * Set to 1 to indicate that a PING request should be issued on this
28628 + * channel. If 0, process normally.
28629 + */
28630 + uint8_t do_ping;
28631 +
28632 + /**
28633 + * Set to 1 to indicate that the error count for this transaction is
28634 + * non-zero. Set to 0 if the error count is 0.
28635 + */
28636 + uint8_t error_state;
28637 +
28638 + /**
28639 + * Set to 1 to indicate that this channel should be halted the next
28640 + * time a request is queued for the channel. This is necessary in
28641 + * slave mode if no request queue space is available when an attempt
28642 + * is made to halt the channel.
28643 + */
28644 + uint8_t halt_on_queue;
28645 +
28646 + /**
28647 + * Set to 1 if the host channel has been halted, but the core is not
28648 + * finished flushing queued requests. Otherwise 0.
28649 + */
28650 + uint8_t halt_pending;
28651 +
28652 + /**
28653 + * Reason for halting the host channel.
28654 + */
28655 + dwc_otg_halt_status_e halt_status;
28656 +
28657 + /*
28658 + * Split settings for the host channel
28659 + */
28660 + uint8_t do_split; /**< Enable split for the channel */
28661 + uint8_t complete_split; /**< Enable complete split */
28662 + uint8_t hub_addr; /**< Address of high speed hub */
28663 +
28664 + uint8_t port_addr; /**< Port of the low/full speed device */
28665 + /** Split transaction position
28666 + * One of the following values:
28667 + * - DWC_HCSPLIT_XACTPOS_MID
28668 + * - DWC_HCSPLIT_XACTPOS_BEGIN
28669 + * - DWC_HCSPLIT_XACTPOS_END
28670 + * - DWC_HCSPLIT_XACTPOS_ALL */
28671 + uint8_t xact_pos;
28672 +
28673 + /** Set when the host channel does a short read. */
28674 + uint8_t short_read;
28675 +
28676 + /**
28677 + * Number of requests issued for this channel since it was assigned to
28678 + * the current transfer (not counting PINGs).
28679 + */
28680 + uint8_t requests;
28681 +
28682 + /**
28683 + * Queue Head for the transfer being processed by this channel.
28684 + */
28685 + struct dwc_otg_qh *qh;
28686 +
28687 + /** @} */
28688 +
28689 + /** Entry in list of host channels. */
28690 + DWC_CIRCLEQ_ENTRY(dwc_hc) hc_list_entry;
28691 +
28692 + /** @name Descriptor DMA support */
28693 + /** @{ */
28694 +
28695 + /** Number of Transfer Descriptors */
28696 + uint16_t ntd;
28697 +
28698 + /** Descriptor List DMA address */
28699 + dwc_dma_t desc_list_addr;
28700 +
28701 + /** Scheduling micro-frame bitmap. */
28702 + uint8_t schinfo;
28703 +
28704 + /** @} */
28705 +} dwc_hc_t;
28706 +
28707 +/**
28708 + * The following parameters may be specified when starting the module. These
28709 + * parameters define how the DWC_otg controller should be configured.
28710 + */
28711 +typedef struct dwc_otg_core_params {
28712 + int32_t opt;
28713 +
28714 + /**
28715 + * Specifies the OTG capabilities. The driver will automatically
28716 + * detect the value for this parameter if none is specified.
28717 + * 0 - HNP and SRP capable (default)
28718 + * 1 - SRP Only capable
28719 + * 2 - No HNP/SRP capable
28720 + */
28721 + int32_t otg_cap;
28722 +
28723 + /**
28724 + * Specifies whether to use slave or DMA mode for accessing the data
28725 + * FIFOs. The driver will automatically detect the value for this
28726 + * parameter if none is specified.
28727 + * 0 - Slave
28728 + * 1 - DMA (default, if available)
28729 + */
28730 + int32_t dma_enable;
28731 +
28732 + /**
28733 + * When DMA mode is enabled specifies whether to use address DMA or DMA
28734 + * Descriptor mode for accessing the data FIFOs in device mode. The driver
28735 + * will automatically detect the value for this if none is specified.
28736 + * 0 - address DMA
28737 + * 1 - DMA Descriptor(default, if available)
28738 + */
28739 + int32_t dma_desc_enable;
28740 + /** The DMA Burst size (applicable only for External DMA
28741 + * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
28742 + */
28743 + int32_t dma_burst_size; /* Translate this to GAHBCFG values */
28744 +
28745 + /**
28746 + * Specifies the maximum speed of operation in host and device mode.
28747 + * The actual speed depends on the speed of the attached device and
28748 + * the value of phy_type. The actual speed depends on the speed of the
28749 + * attached device.
28750 + * 0 - High Speed (default)
28751 + * 1 - Full Speed
28752 + */
28753 + int32_t speed;
28754 + /** Specifies whether low power mode is supported when attached
28755 + * to a Full Speed or Low Speed device in host mode.
28756 + * 0 - Don't support low power mode (default)
28757 + * 1 - Support low power mode
28758 + */
28759 + int32_t host_support_fs_ls_low_power;
28760 +
28761 + /** Specifies the PHY clock rate in low power mode when connected to a
28762 + * Low Speed device in host mode. This parameter is applicable only if
28763 + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
28764 + * then defaults to 6 MHZ otherwise 48 MHZ.
28765 + *
28766 + * 0 - 48 MHz
28767 + * 1 - 6 MHz
28768 + */
28769 + int32_t host_ls_low_power_phy_clk;
28770 +
28771 + /**
28772 + * 0 - Use cC FIFO size parameters
28773 + * 1 - Allow dynamic FIFO sizing (default)
28774 + */
28775 + int32_t enable_dynamic_fifo;
28776 +
28777 + /** Total number of 4-byte words in the data FIFO memory. This
28778 + * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
28779 + * Tx FIFOs.
28780 + * 32 to 32768 (default 8192)
28781 + * Note: The total FIFO memory depth in the FPGA configuration is 8192.
28782 + */
28783 + int32_t data_fifo_size;
28784 +
28785 + /** Number of 4-byte words in the Rx FIFO in device mode when dynamic
28786 + * FIFO sizing is enabled.
28787 + * 16 to 32768 (default 1064)
28788 + */
28789 + int32_t dev_rx_fifo_size;
28790 +
28791 + /** Number of 4-byte words in the non-periodic Tx FIFO in device mode
28792 + * when dynamic FIFO sizing is enabled.
28793 + * 16 to 32768 (default 1024)
28794 + */
28795 + int32_t dev_nperio_tx_fifo_size;
28796 +
28797 + /** Number of 4-byte words in each of the periodic Tx FIFOs in device
28798 + * mode when dynamic FIFO sizing is enabled.
28799 + * 4 to 768 (default 256)
28800 + */
28801 + uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
28802 +
28803 + /** Number of 4-byte words in the Rx FIFO in host mode when dynamic
28804 + * FIFO sizing is enabled.
28805 + * 16 to 32768 (default 1024)
28806 + */
28807 + int32_t host_rx_fifo_size;
28808 +
28809 + /** Number of 4-byte words in the non-periodic Tx FIFO in host mode
28810 + * when Dynamic FIFO sizing is enabled in the core.
28811 + * 16 to 32768 (default 1024)
28812 + */
28813 + int32_t host_nperio_tx_fifo_size;
28814 +
28815 + /** Number of 4-byte words in the host periodic Tx FIFO when dynamic
28816 + * FIFO sizing is enabled.
28817 + * 16 to 32768 (default 1024)
28818 + */
28819 + int32_t host_perio_tx_fifo_size;
28820 +
28821 + /** The maximum transfer size supported in bytes.
28822 + * 2047 to 65,535 (default 65,535)
28823 + */
28824 + int32_t max_transfer_size;
28825 +
28826 + /** The maximum number of packets in a transfer.
28827 + * 15 to 511 (default 511)
28828 + */
28829 + int32_t max_packet_count;
28830 +
28831 + /** The number of host channel registers to use.
28832 + * 1 to 16 (default 12)
28833 + * Note: The FPGA configuration supports a maximum of 12 host channels.
28834 + */
28835 + int32_t host_channels;
28836 +
28837 + /** The number of endpoints in addition to EP0 available for device
28838 + * mode operations.
28839 + * 1 to 15 (default 6 IN and OUT)
28840 + * Note: The FPGA configuration supports a maximum of 6 IN and OUT
28841 + * endpoints in addition to EP0.
28842 + */
28843 + int32_t dev_endpoints;
28844 +
28845 + /**
28846 + * Specifies the type of PHY interface to use. By default, the driver
28847 + * will automatically detect the phy_type.
28848 + *
28849 + * 0 - Full Speed PHY
28850 + * 1 - UTMI+ (default)
28851 + * 2 - ULPI
28852 + */
28853 + int32_t phy_type;
28854 +
28855 + /**
28856 + * Specifies the UTMI+ Data Width. This parameter is
28857 + * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
28858 + * PHY_TYPE, this parameter indicates the data width between
28859 + * the MAC and the ULPI Wrapper.) Also, this parameter is
28860 + * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
28861 + * to "8 and 16 bits", meaning that the core has been
28862 + * configured to work at either data path width.
28863 + *
28864 + * 8 or 16 bits (default 16)
28865 + */
28866 + int32_t phy_utmi_width;
28867 +
28868 + /**
28869 + * Specifies whether the ULPI operates at double or single
28870 + * data rate. This parameter is only applicable if PHY_TYPE is
28871 + * ULPI.
28872 + *
28873 + * 0 - single data rate ULPI interface with 8 bit wide data
28874 + * bus (default)
28875 + * 1 - double data rate ULPI interface with 4 bit wide data
28876 + * bus
28877 + */
28878 + int32_t phy_ulpi_ddr;
28879 +
28880 + /**
28881 + * Specifies whether to use the internal or external supply to
28882 + * drive the vbus with a ULPI phy.
28883 + */
28884 + int32_t phy_ulpi_ext_vbus;
28885 +
28886 + /**
28887 + * Specifies whether to use the I2Cinterface for full speed PHY. This
28888 + * parameter is only applicable if PHY_TYPE is FS.
28889 + * 0 - No (default)
28890 + * 1 - Yes
28891 + */
28892 + int32_t i2c_enable;
28893 +
28894 + int32_t ulpi_fs_ls;
28895 +
28896 + int32_t ts_dline;
28897 +
28898 + /**
28899 + * Specifies whether dedicated transmit FIFOs are
28900 + * enabled for non periodic IN endpoints in device mode
28901 + * 0 - No
28902 + * 1 - Yes
28903 + */
28904 + int32_t en_multiple_tx_fifo;
28905 +
28906 + /** Number of 4-byte words in each of the Tx FIFOs in device
28907 + * mode when dynamic FIFO sizing is enabled.
28908 + * 4 to 768 (default 256)
28909 + */
28910 + uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
28911 +
28912 + /** Thresholding enable flag-
28913 + * bit 0 - enable non-ISO Tx thresholding
28914 + * bit 1 - enable ISO Tx thresholding
28915 + * bit 2 - enable Rx thresholding
28916 + */
28917 + uint32_t thr_ctl;
28918 +
28919 + /** Thresholding length for Tx
28920 + * FIFOs in 32 bit DWORDs
28921 + */
28922 + uint32_t tx_thr_length;
28923 +
28924 + /** Thresholding length for Rx
28925 + * FIFOs in 32 bit DWORDs
28926 + */
28927 + uint32_t rx_thr_length;
28928 +
28929 + /**
28930 + * Specifies whether LPM (Link Power Management) support is enabled
28931 + */
28932 + int32_t lpm_enable;
28933 +
28934 + /** Per Transfer Interrupt
28935 + * mode enable flag
28936 + * 1 - Enabled
28937 + * 0 - Disabled
28938 + */
28939 + int32_t pti_enable;
28940 +
28941 + /** Multi Processor Interrupt
28942 + * mode enable flag
28943 + * 1 - Enabled
28944 + * 0 - Disabled
28945 + */
28946 + int32_t mpi_enable;
28947 +
28948 + /** IS_USB Capability
28949 + * 1 - Enabled
28950 + * 0 - Disabled
28951 + */
28952 + int32_t ic_usb_cap;
28953 +
28954 + /** AHB Threshold Ratio
28955 + * 2'b00 AHB Threshold = MAC Threshold
28956 + * 2'b01 AHB Threshold = 1/2 MAC Threshold
28957 + * 2'b10 AHB Threshold = 1/4 MAC Threshold
28958 + * 2'b11 AHB Threshold = 1/8 MAC Threshold
28959 + */
28960 + int32_t ahb_thr_ratio;
28961 +
28962 + /** ADP Support
28963 + * 1 - Enabled
28964 + * 0 - Disabled
28965 + */
28966 + int32_t adp_supp_enable;
28967 +
28968 + /** HFIR Reload Control
28969 + * 0 - The HFIR cannot be reloaded dynamically.
28970 + * 1 - Allow dynamic reloading of the HFIR register during runtime.
28971 + */
28972 + int32_t reload_ctl;
28973 +
28974 + /** DCFG: Enable device Out NAK
28975 + * 0 - The core does not set NAK after Bulk Out transfer complete.
28976 + * 1 - The core sets NAK after Bulk OUT transfer complete.
28977 + */
28978 + int32_t dev_out_nak;
28979 +
28980 + /** DCFG: Enable Continue on BNA
28981 + * After receiving BNA interrupt the core disables the endpoint,when the
28982 + * endpoint is re-enabled by the application the core starts processing
28983 + * 0 - from the DOEPDMA descriptor
28984 + * 1 - from the descriptor which received the BNA.
28985 + */
28986 + int32_t cont_on_bna;
28987 +
28988 + /** GAHBCFG: AHB Single Support
28989 + * This bit when programmed supports SINGLE transfers for remainder
28990 + * data in a transfer for DMA mode of operation.
28991 + * 0 - in this case the remainder data will be sent using INCR burst size.
28992 + * 1 - in this case the remainder data will be sent using SINGLE burst size.
28993 + */
28994 + int32_t ahb_single;
28995 +
28996 + /** Core Power down mode
28997 + * 0 - No Power Down is enabled
28998 + * 1 - Reserved
28999 + * 2 - Complete Power Down (Hibernation)
29000 + */
29001 + int32_t power_down;
29002 +
29003 + /** OTG revision supported
29004 + * 0 - OTG 1.3 revision
29005 + * 1 - OTG 2.0 revision
29006 + */
29007 + int32_t otg_ver;
29008 +
29009 +} dwc_otg_core_params_t;
29010 +
29011 +#ifdef DEBUG
29012 +struct dwc_otg_core_if;
29013 +typedef struct hc_xfer_info {
29014 + struct dwc_otg_core_if *core_if;
29015 + dwc_hc_t *hc;
29016 +} hc_xfer_info_t;
29017 +#endif
29018 +
29019 +typedef struct ep_xfer_info {
29020 + struct dwc_otg_core_if *core_if;
29021 + dwc_ep_t *ep;
29022 + uint8_t state;
29023 +} ep_xfer_info_t;
29024 +/*
29025 + * Device States
29026 + */
29027 +typedef enum dwc_otg_lx_state {
29028 + /** On state */
29029 + DWC_OTG_L0,
29030 + /** LPM sleep state*/
29031 + DWC_OTG_L1,
29032 + /** USB suspend state*/
29033 + DWC_OTG_L2,
29034 + /** Off state*/
29035 + DWC_OTG_L3
29036 +} dwc_otg_lx_state_e;
29037 +
29038 +struct dwc_otg_global_regs_backup {
29039 + uint32_t gotgctl_local;
29040 + uint32_t gintmsk_local;
29041 + uint32_t gahbcfg_local;
29042 + uint32_t gusbcfg_local;
29043 + uint32_t grxfsiz_local;
29044 + uint32_t gnptxfsiz_local;
29045 +#ifdef CONFIG_USB_DWC_OTG_LPM
29046 + uint32_t glpmcfg_local;
29047 +#endif
29048 + uint32_t gi2cctl_local;
29049 + uint32_t hptxfsiz_local;
29050 + uint32_t pcgcctl_local;
29051 + uint32_t gdfifocfg_local;
29052 + uint32_t dtxfsiz_local[MAX_EPS_CHANNELS];
29053 + uint32_t gpwrdn_local;
29054 + uint32_t xhib_pcgcctl;
29055 + uint32_t xhib_gpwrdn;
29056 +};
29057 +
29058 +struct dwc_otg_host_regs_backup {
29059 + uint32_t hcfg_local;
29060 + uint32_t haintmsk_local;
29061 + uint32_t hcintmsk_local[MAX_EPS_CHANNELS];
29062 + uint32_t hprt0_local;
29063 + uint32_t hfir_local;
29064 +};
29065 +
29066 +struct dwc_otg_dev_regs_backup {
29067 + uint32_t dcfg;
29068 + uint32_t dctl;
29069 + uint32_t daintmsk;
29070 + uint32_t diepmsk;
29071 + uint32_t doepmsk;
29072 + uint32_t diepctl[MAX_EPS_CHANNELS];
29073 + uint32_t dieptsiz[MAX_EPS_CHANNELS];
29074 + uint32_t diepdma[MAX_EPS_CHANNELS];
29075 +};
29076 +/**
29077 + * The <code>dwc_otg_core_if</code> structure contains information needed to manage
29078 + * the DWC_otg controller acting in either host or device mode. It
29079 + * represents the programming view of the controller as a whole.
29080 + */
29081 +struct dwc_otg_core_if {
29082 + /** Parameters that define how the core should be configured.*/
29083 + dwc_otg_core_params_t *core_params;
29084 +
29085 + /** Core Global registers starting at offset 000h. */
29086 + dwc_otg_core_global_regs_t *core_global_regs;
29087 +
29088 + /** Device-specific information */
29089 + dwc_otg_dev_if_t *dev_if;
29090 + /** Host-specific information */
29091 + dwc_otg_host_if_t *host_if;
29092 +
29093 + /** Value from SNPSID register */
29094 + uint32_t snpsid;
29095 +
29096 + /*
29097 + * Set to 1 if the core PHY interface bits in USBCFG have been
29098 + * initialized.
29099 + */
29100 + uint8_t phy_init_done;
29101 +
29102 + /*
29103 + * SRP Success flag, set by srp success interrupt in FS I2C mode
29104 + */
29105 + uint8_t srp_success;
29106 + uint8_t srp_timer_started;
29107 + /** Timer for SRP. If it expires before SRP is successful
29108 + * clear the SRP. */
29109 + dwc_timer_t *srp_timer;
29110 +
29111 +#ifdef DWC_DEV_SRPCAP
29112 + /* This timer is needed to power on the hibernated host core if SRP is not
29113 + * initiated on connected SRP capable device for limited period of time
29114 + */
29115 + uint8_t pwron_timer_started;
29116 + dwc_timer_t *pwron_timer;
29117 +#endif
29118 + /* Common configuration information */
29119 + /** Power and Clock Gating Control Register */
29120 + volatile uint32_t *pcgcctl;
29121 +#define DWC_OTG_PCGCCTL_OFFSET 0xE00
29122 +
29123 + /** Push/pop addresses for endpoints or host channels.*/
29124 + uint32_t *data_fifo[MAX_EPS_CHANNELS];
29125 +#define DWC_OTG_DATA_FIFO_OFFSET 0x1000
29126 +#define DWC_OTG_DATA_FIFO_SIZE 0x1000
29127 +
29128 + /** Total RAM for FIFOs (Bytes) */
29129 + uint16_t total_fifo_size;
29130 + /** Size of Rx FIFO (Bytes) */
29131 + uint16_t rx_fifo_size;
29132 + /** Size of Non-periodic Tx FIFO (Bytes) */
29133 + uint16_t nperio_tx_fifo_size;
29134 +
29135 + /** 1 if DMA is enabled, 0 otherwise. */
29136 + uint8_t dma_enable;
29137 +
29138 + /** 1 if DMA descriptor is enabled, 0 otherwise. */
29139 + uint8_t dma_desc_enable;
29140 +
29141 + /** 1 if PTI Enhancement mode is enabled, 0 otherwise. */
29142 + uint8_t pti_enh_enable;
29143 +
29144 + /** 1 if MPI Enhancement mode is enabled, 0 otherwise. */
29145 + uint8_t multiproc_int_enable;
29146 +
29147 + /** 1 if dedicated Tx FIFOs are enabled, 0 otherwise. */
29148 + uint8_t en_multiple_tx_fifo;
29149 +
29150 + /** Set to 1 if multiple packets of a high-bandwidth transfer is in
29151 + * process of being queued */
29152 + uint8_t queuing_high_bandwidth;
29153 +
29154 + /** Hardware Configuration -- stored here for convenience.*/
29155 + hwcfg1_data_t hwcfg1;
29156 + hwcfg2_data_t hwcfg2;
29157 + hwcfg3_data_t hwcfg3;
29158 + hwcfg4_data_t hwcfg4;
29159 + fifosize_data_t hptxfsiz;
29160 +
29161 + /** Host and Device Configuration -- stored here for convenience.*/
29162 + hcfg_data_t hcfg;
29163 + dcfg_data_t dcfg;
29164 +
29165 + /** The operational State, during transations
29166 + * (a_host>>a_peripherial and b_device=>b_host) this may not
29167 + * match the core but allows the software to determine
29168 + * transitions.
29169 + */
29170 + uint8_t op_state;
29171 +
29172 + /**
29173 + * Set to 1 if the HCD needs to be restarted on a session request
29174 + * interrupt. This is required if no connector ID status change has
29175 + * occurred since the HCD was last disconnected.
29176 + */
29177 + uint8_t restart_hcd_on_session_req;
29178 +
29179 + /** HCD callbacks */
29180 + /** A-Device is a_host */
29181 +#define A_HOST (1)
29182 + /** A-Device is a_suspend */
29183 +#define A_SUSPEND (2)
29184 + /** A-Device is a_peripherial */
29185 +#define A_PERIPHERAL (3)
29186 + /** B-Device is operating as a Peripheral. */
29187 +#define B_PERIPHERAL (4)
29188 + /** B-Device is operating as a Host. */
29189 +#define B_HOST (5)
29190 +
29191 + /** HCD callbacks */
29192 + struct dwc_otg_cil_callbacks *hcd_cb;
29193 + /** PCD callbacks */
29194 + struct dwc_otg_cil_callbacks *pcd_cb;
29195 +
29196 + /** Device mode Periodic Tx FIFO Mask */
29197 + uint32_t p_tx_msk;
29198 + /** Device mode Periodic Tx FIFO Mask */
29199 + uint32_t tx_msk;
29200 +
29201 + /** Workqueue object used for handling several interrupts */
29202 + dwc_workq_t *wq_otg;
29203 +
29204 + /** Timer object used for handling "Wakeup Detected" Interrupt */
29205 + dwc_timer_t *wkp_timer;
29206 + /** This arrays used for debug purposes for DEV OUT NAK enhancement */
29207 + uint32_t start_doeptsiz_val[MAX_EPS_CHANNELS];
29208 + ep_xfer_info_t ep_xfer_info[MAX_EPS_CHANNELS];
29209 + dwc_timer_t *ep_xfer_timer[MAX_EPS_CHANNELS];
29210 +#ifdef DEBUG
29211 + uint32_t start_hcchar_val[MAX_EPS_CHANNELS];
29212 +
29213 + hc_xfer_info_t hc_xfer_info[MAX_EPS_CHANNELS];
29214 + dwc_timer_t *hc_xfer_timer[MAX_EPS_CHANNELS];
29215 +
29216 + uint32_t hfnum_7_samples;
29217 + uint64_t hfnum_7_frrem_accum;
29218 + uint32_t hfnum_0_samples;
29219 + uint64_t hfnum_0_frrem_accum;
29220 + uint32_t hfnum_other_samples;
29221 + uint64_t hfnum_other_frrem_accum;
29222 +#endif
29223 +
29224 +#ifdef DWC_UTE_CFI
29225 + uint16_t pwron_rxfsiz;
29226 + uint16_t pwron_gnptxfsiz;
29227 + uint16_t pwron_txfsiz[15];
29228 +
29229 + uint16_t init_rxfsiz;
29230 + uint16_t init_gnptxfsiz;
29231 + uint16_t init_txfsiz[15];
29232 +#endif
29233 +
29234 + /** Lx state of device */
29235 + dwc_otg_lx_state_e lx_state;
29236 +
29237 + /** Saved Core Global registers */
29238 + struct dwc_otg_global_regs_backup *gr_backup;
29239 + /** Saved Host registers */
29240 + struct dwc_otg_host_regs_backup *hr_backup;
29241 + /** Saved Device registers */
29242 + struct dwc_otg_dev_regs_backup *dr_backup;
29243 +
29244 + /** Power Down Enable */
29245 + uint32_t power_down;
29246 +
29247 + /** ADP support Enable */
29248 + uint32_t adp_enable;
29249 +
29250 + /** ADP structure object */
29251 + dwc_otg_adp_t adp;
29252 +
29253 + /** hibernation/suspend flag */
29254 + int hibernation_suspend;
29255 +
29256 + /** Device mode extended hibernation flag */
29257 + int xhib;
29258 +
29259 + /** OTG revision supported */
29260 + uint32_t otg_ver;
29261 +
29262 + /** OTG status flag used for HNP polling */
29263 + uint8_t otg_sts;
29264 +
29265 + /** Pointer to either hcd->lock or pcd->lock */
29266 + dwc_spinlock_t *lock;
29267 +
29268 + /** Start predict NextEP based on Learning Queue if equal 1,
29269 + * also used as counter of disabled NP IN EP's */
29270 + uint8_t start_predict;
29271 +
29272 + /** NextEp sequence, including EP0: nextep_seq[] = EP if non-periodic and
29273 + * active, 0xff otherwise */
29274 + uint8_t nextep_seq[MAX_EPS_CHANNELS];
29275 +
29276 + /** Index of fisrt EP in nextep_seq array which should be re-enabled **/
29277 + uint8_t first_in_nextep_seq;
29278 +
29279 + /** Frame number while entering to ISR - needed for ISOCs **/
29280 + uint32_t frame_num;
29281 +
29282 +};
29283 +
29284 +#ifdef DEBUG
29285 +/*
29286 + * This function is called when transfer is timed out.
29287 + */
29288 +extern void hc_xfer_timeout(void *ptr);
29289 +#endif
29290 +
29291 +/*
29292 + * This function is called when transfer is timed out on endpoint.
29293 + */
29294 +extern void ep_xfer_timeout(void *ptr);
29295 +
29296 +/*
29297 + * The following functions are functions for works
29298 + * using during handling some interrupts
29299 + */
29300 +extern void w_conn_id_status_change(void *p);
29301 +
29302 +extern void w_wakeup_detected(void *p);
29303 +
29304 +/** Saves global register values into system memory. */
29305 +extern int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if);
29306 +/** Saves device register values into system memory. */
29307 +extern int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if);
29308 +/** Saves host register values into system memory. */
29309 +extern int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if);
29310 +/** Restore global register values. */
29311 +extern int dwc_otg_restore_global_regs(dwc_otg_core_if_t * core_if);
29312 +/** Restore host register values. */
29313 +extern int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset);
29314 +/** Restore device register values. */
29315 +extern int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if,
29316 + int rem_wakeup);
29317 +extern int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if);
29318 +extern int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode,
29319 + int is_host);
29320 +
29321 +extern int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
29322 + int restore_mode, int reset);
29323 +extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
29324 + int rem_wakeup, int reset);
29325 +
29326 +/*
29327 + * The following functions support initialization of the CIL driver component
29328 + * and the DWC_otg controller.
29329 + */
29330 +extern void dwc_otg_core_host_init(dwc_otg_core_if_t * _core_if);
29331 +extern void dwc_otg_core_dev_init(dwc_otg_core_if_t * _core_if);
29332 +
29333 +/** @name Device CIL Functions
29334 + * The following functions support managing the DWC_otg controller in device
29335 + * mode.
29336 + */
29337 +/**@{*/
29338 +extern void dwc_otg_wakeup(dwc_otg_core_if_t * _core_if);
29339 +extern void dwc_otg_read_setup_packet(dwc_otg_core_if_t * _core_if,
29340 + uint32_t * _dest);
29341 +extern uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * _core_if);
29342 +extern void dwc_otg_ep0_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29343 +extern void dwc_otg_ep_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29344 +extern void dwc_otg_ep_deactivate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29345 +extern void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * _core_if,
29346 + dwc_ep_t * _ep);
29347 +extern void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * _core_if,
29348 + dwc_ep_t * _ep);
29349 +extern void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * _core_if,
29350 + dwc_ep_t * _ep);
29351 +extern void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * _core_if,
29352 + dwc_ep_t * _ep);
29353 +extern void dwc_otg_ep_write_packet(dwc_otg_core_if_t * _core_if,
29354 + dwc_ep_t * _ep, int _dma);
29355 +extern void dwc_otg_ep_set_stall(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29356 +extern void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * _core_if,
29357 + dwc_ep_t * _ep);
29358 +extern void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * _core_if);
29359 +
29360 +#ifdef DWC_EN_ISOC
29361 +extern void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
29362 + dwc_ep_t * ep);
29363 +extern void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
29364 + dwc_ep_t * ep);
29365 +#endif /* DWC_EN_ISOC */
29366 +/**@}*/
29367 +
29368 +/** @name Host CIL Functions
29369 + * The following functions support managing the DWC_otg controller in host
29370 + * mode.
29371 + */
29372 +/**@{*/
29373 +extern void dwc_otg_hc_init(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
29374 +extern void dwc_otg_hc_halt(dwc_otg_core_if_t * _core_if,
29375 + dwc_hc_t * _hc, dwc_otg_halt_status_e _halt_status);
29376 +extern void dwc_otg_hc_cleanup(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
29377 +extern void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * _core_if,
29378 + dwc_hc_t * _hc);
29379 +extern int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * _core_if,
29380 + dwc_hc_t * _hc);
29381 +extern void dwc_otg_hc_do_ping(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
29382 +extern void dwc_otg_hc_write_packet(dwc_otg_core_if_t * _core_if,
29383 + dwc_hc_t * _hc);
29384 +extern void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * _core_if);
29385 +extern void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * _core_if);
29386 +
29387 +extern void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if,
29388 + dwc_hc_t * hc);
29389 +
29390 +extern uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if);
29391 +
29392 +/* Macro used to clear one channel interrupt */
29393 +#define clear_hc_int(_hc_regs_, _intr_) \
29394 +do { \
29395 + hcint_data_t hcint_clear = {.d32 = 0}; \
29396 + hcint_clear.b._intr_ = 1; \
29397 + DWC_WRITE_REG32(&(_hc_regs_)->hcint, hcint_clear.d32); \
29398 +} while (0)
29399 +
29400 +/*
29401 + * Macro used to disable one channel interrupt. Channel interrupts are
29402 + * disabled when the channel is halted or released by the interrupt handler.
29403 + * There is no need to handle further interrupts of that type until the
29404 + * channel is re-assigned. In fact, subsequent handling may cause crashes
29405 + * because the channel structures are cleaned up when the channel is released.
29406 + */
29407 +#define disable_hc_int(_hc_regs_, _intr_) \
29408 +do { \
29409 + hcintmsk_data_t hcintmsk = {.d32 = 0}; \
29410 + hcintmsk.b._intr_ = 1; \
29411 + DWC_MODIFY_REG32(&(_hc_regs_)->hcintmsk, hcintmsk.d32, 0); \
29412 +} while (0)
29413 +
29414 +/**
29415 + * This function Reads HPRT0 in preparation to modify. It keeps the
29416 + * WC bits 0 so that if they are read as 1, they won't clear when you
29417 + * write it back
29418 + */
29419 +static inline uint32_t dwc_otg_read_hprt0(dwc_otg_core_if_t * _core_if)
29420 +{
29421 + hprt0_data_t hprt0;
29422 + hprt0.d32 = DWC_READ_REG32(_core_if->host_if->hprt0);
29423 + hprt0.b.prtena = 0;
29424 + hprt0.b.prtconndet = 0;
29425 + hprt0.b.prtenchng = 0;
29426 + hprt0.b.prtovrcurrchng = 0;
29427 + return hprt0.d32;
29428 +}
29429 +
29430 +/**@}*/
29431 +
29432 +/** @name Common CIL Functions
29433 + * The following functions support managing the DWC_otg controller in either
29434 + * device or host mode.
29435 + */
29436 +/**@{*/
29437 +
29438 +extern void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
29439 + uint8_t * dest, uint16_t bytes);
29440 +
29441 +extern void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * _core_if, const int _num);
29442 +extern void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * _core_if);
29443 +extern void dwc_otg_core_reset(dwc_otg_core_if_t * _core_if);
29444 +
29445 +/**
29446 + * This function returns the Core Interrupt register.
29447 + */
29448 +static inline uint32_t dwc_otg_read_core_intr(dwc_otg_core_if_t * core_if)
29449 +{
29450 + return (DWC_READ_REG32(&core_if->core_global_regs->gintsts) &
29451 + DWC_READ_REG32(&core_if->core_global_regs->gintmsk));
29452 +}
29453 +
29454 +/**
29455 + * This function returns the OTG Interrupt register.
29456 + */
29457 +static inline uint32_t dwc_otg_read_otg_intr(dwc_otg_core_if_t * core_if)
29458 +{
29459 + return (DWC_READ_REG32(&core_if->core_global_regs->gotgint));
29460 +}
29461 +
29462 +/**
29463 + * This function reads the Device All Endpoints Interrupt register and
29464 + * returns the IN endpoint interrupt bits.
29465 + */
29466 +static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(dwc_otg_core_if_t *
29467 + core_if)
29468 +{
29469 +
29470 + uint32_t v;
29471 +
29472 + if (core_if->multiproc_int_enable) {
29473 + v = DWC_READ_REG32(&core_if->dev_if->
29474 + dev_global_regs->deachint) &
29475 + DWC_READ_REG32(&core_if->
29476 + dev_if->dev_global_regs->deachintmsk);
29477 + } else {
29478 + v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
29479 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
29480 + }
29481 + return (v & 0xffff);
29482 +}
29483 +
29484 +/**
29485 + * This function reads the Device All Endpoints Interrupt register and
29486 + * returns the OUT endpoint interrupt bits.
29487 + */
29488 +static inline uint32_t dwc_otg_read_dev_all_out_ep_intr(dwc_otg_core_if_t *
29489 + core_if)
29490 +{
29491 + uint32_t v;
29492 +
29493 + if (core_if->multiproc_int_enable) {
29494 + v = DWC_READ_REG32(&core_if->dev_if->
29495 + dev_global_regs->deachint) &
29496 + DWC_READ_REG32(&core_if->
29497 + dev_if->dev_global_regs->deachintmsk);
29498 + } else {
29499 + v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
29500 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
29501 + }
29502 +
29503 + return ((v & 0xffff0000) >> 16);
29504 +}
29505 +
29506 +/**
29507 + * This function returns the Device IN EP Interrupt register
29508 + */
29509 +static inline uint32_t dwc_otg_read_dev_in_ep_intr(dwc_otg_core_if_t * core_if,
29510 + dwc_ep_t * ep)
29511 +{
29512 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
29513 + uint32_t v, msk, emp;
29514 +
29515 + if (core_if->multiproc_int_enable) {
29516 + msk =
29517 + DWC_READ_REG32(&dev_if->
29518 + dev_global_regs->diepeachintmsk[ep->num]);
29519 + emp =
29520 + DWC_READ_REG32(&dev_if->
29521 + dev_global_regs->dtknqr4_fifoemptymsk);
29522 + msk |= ((emp >> ep->num) & 0x1) << 7;
29523 + v = DWC_READ_REG32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
29524 + } else {
29525 + msk = DWC_READ_REG32(&dev_if->dev_global_regs->diepmsk);
29526 + emp =
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;
29531 + }
29532 +
29533 + return v;
29534 +}
29535 +
29536 +/**
29537 + * This function returns the Device OUT EP Interrupt register
29538 + */
29539 +static inline uint32_t dwc_otg_read_dev_out_ep_intr(dwc_otg_core_if_t *
29540 + _core_if, dwc_ep_t * _ep)
29541 +{
29542 + dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
29543 + uint32_t v;
29544 + doepmsk_data_t msk = {.d32 = 0 };
29545 +
29546 + if (_core_if->multiproc_int_enable) {
29547 + msk.d32 =
29548 + DWC_READ_REG32(&dev_if->
29549 + dev_global_regs->doepeachintmsk[_ep->num]);
29550 + if (_core_if->pti_enh_enable) {
29551 + msk.b.pktdrpsts = 1;
29552 + }
29553 + v = DWC_READ_REG32(&dev_if->
29554 + out_ep_regs[_ep->num]->doepint) & msk.d32;
29555 + } else {
29556 + msk.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->doepmsk);
29557 + if (_core_if->pti_enh_enable) {
29558 + msk.b.pktdrpsts = 1;
29559 + }
29560 + v = DWC_READ_REG32(&dev_if->
29561 + out_ep_regs[_ep->num]->doepint) & msk.d32;
29562 + }
29563 + return v;
29564 +}
29565 +
29566 +/**
29567 + * This function returns the Host All Channel Interrupt register
29568 + */
29569 +static inline uint32_t dwc_otg_read_host_all_channels_intr(dwc_otg_core_if_t *
29570 + _core_if)
29571 +{
29572 + return (DWC_READ_REG32(&_core_if->host_if->host_global_regs->haint));
29573 +}
29574 +
29575 +static inline uint32_t dwc_otg_read_host_channel_intr(dwc_otg_core_if_t *
29576 + _core_if, dwc_hc_t * _hc)
29577 +{
29578 + return (DWC_READ_REG32
29579 + (&_core_if->host_if->hc_regs[_hc->hc_num]->hcint));
29580 +}
29581 +
29582 +/**
29583 + * This function returns the mode of the operation, host or device.
29584 + *
29585 + * @return 0 - Device Mode, 1 - Host Mode
29586 + */
29587 +static inline uint32_t dwc_otg_mode(dwc_otg_core_if_t * _core_if)
29588 +{
29589 + return (DWC_READ_REG32(&_core_if->core_global_regs->gintsts) & 0x1);
29590 +}
29591 +
29592 +/**@}*/
29593 +
29594 +/**
29595 + * DWC_otg CIL callback structure. This structure allows the HCD and
29596 + * PCD to register functions used for starting and stopping the PCD
29597 + * and HCD for role change on for a DRD.
29598 + */
29599 +typedef struct dwc_otg_cil_callbacks {
29600 + /** Start function for role change */
29601 + int (*start) (void *_p);
29602 + /** Stop Function for role change */
29603 + int (*stop) (void *_p);
29604 + /** Disconnect Function for role change */
29605 + int (*disconnect) (void *_p);
29606 + /** Resume/Remote wakeup Function */
29607 + int (*resume_wakeup) (void *_p);
29608 + /** Suspend function */
29609 + int (*suspend) (void *_p);
29610 + /** Session Start (SRP) */
29611 + int (*session_start) (void *_p);
29612 +#ifdef CONFIG_USB_DWC_OTG_LPM
29613 + /** Sleep (switch to L0 state) */
29614 + int (*sleep) (void *_p);
29615 +#endif
29616 + /** Pointer passed to start() and stop() */
29617 + void *p;
29618 +} dwc_otg_cil_callbacks_t;
29619 +
29620 +extern void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * _core_if,
29621 + dwc_otg_cil_callbacks_t * _cb,
29622 + void *_p);
29623 +extern void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * _core_if,
29624 + dwc_otg_cil_callbacks_t * _cb,
29625 + void *_p);
29626 +
29627 +void dwc_otg_initiate_srp(dwc_otg_core_if_t * core_if);
29628 +
29629 +//////////////////////////////////////////////////////////////////////
29630 +/** Start the HCD. Helper function for using the HCD callbacks.
29631 + *
29632 + * @param core_if Programming view of DWC_otg controller.
29633 + */
29634 +static inline void cil_hcd_start(dwc_otg_core_if_t * core_if)
29635 +{
29636 + if (core_if->hcd_cb && core_if->hcd_cb->start) {
29637 + core_if->hcd_cb->start(core_if->hcd_cb->p);
29638 + }
29639 +}
29640 +
29641 +/** Stop the HCD. Helper function for using the HCD callbacks.
29642 + *
29643 + * @param core_if Programming view of DWC_otg controller.
29644 + */
29645 +static inline void cil_hcd_stop(dwc_otg_core_if_t * core_if)
29646 +{
29647 + if (core_if->hcd_cb && core_if->hcd_cb->stop) {
29648 + core_if->hcd_cb->stop(core_if->hcd_cb->p);
29649 + }
29650 +}
29651 +
29652 +/** Disconnect the HCD. Helper function for using the HCD callbacks.
29653 + *
29654 + * @param core_if Programming view of DWC_otg controller.
29655 + */
29656 +static inline void cil_hcd_disconnect(dwc_otg_core_if_t * core_if)
29657 +{
29658 + if (core_if->hcd_cb && core_if->hcd_cb->disconnect) {
29659 + core_if->hcd_cb->disconnect(core_if->hcd_cb->p);
29660 + }
29661 +}
29662 +
29663 +/** Inform the HCD the a New Session has begun. Helper function for
29664 + * using the HCD callbacks.
29665 + *
29666 + * @param core_if Programming view of DWC_otg controller.
29667 + */
29668 +static inline void cil_hcd_session_start(dwc_otg_core_if_t * core_if)
29669 +{
29670 + if (core_if->hcd_cb && core_if->hcd_cb->session_start) {
29671 + core_if->hcd_cb->session_start(core_if->hcd_cb->p);
29672 + }
29673 +}
29674 +
29675 +#ifdef CONFIG_USB_DWC_OTG_LPM
29676 +/**
29677 + * Inform the HCD about LPM sleep.
29678 + * Helper function for using the HCD callbacks.
29679 + *
29680 + * @param core_if Programming view of DWC_otg controller.
29681 + */
29682 +static inline void cil_hcd_sleep(dwc_otg_core_if_t * core_if)
29683 +{
29684 + if (core_if->hcd_cb && core_if->hcd_cb->sleep) {
29685 + core_if->hcd_cb->sleep(core_if->hcd_cb->p);
29686 + }
29687 +}
29688 +#endif
29689 +
29690 +/** Resume the HCD. Helper function for using the HCD callbacks.
29691 + *
29692 + * @param core_if Programming view of DWC_otg controller.
29693 + */
29694 +static inline void cil_hcd_resume(dwc_otg_core_if_t * core_if)
29695 +{
29696 + if (core_if->hcd_cb && core_if->hcd_cb->resume_wakeup) {
29697 + core_if->hcd_cb->resume_wakeup(core_if->hcd_cb->p);
29698 + }
29699 +}
29700 +
29701 +/** Start the PCD. Helper function for using the PCD callbacks.
29702 + *
29703 + * @param core_if Programming view of DWC_otg controller.
29704 + */
29705 +static inline void cil_pcd_start(dwc_otg_core_if_t * core_if)
29706 +{
29707 + if (core_if->pcd_cb && core_if->pcd_cb->start) {
29708 + core_if->pcd_cb->start(core_if->pcd_cb->p);
29709 + }
29710 +}
29711 +
29712 +/** Stop the PCD. Helper function for using the PCD callbacks.
29713 + *
29714 + * @param core_if Programming view of DWC_otg controller.
29715 + */
29716 +static inline void cil_pcd_stop(dwc_otg_core_if_t * core_if)
29717 +{
29718 + if (core_if->pcd_cb && core_if->pcd_cb->stop) {
29719 + core_if->pcd_cb->stop(core_if->pcd_cb->p);
29720 + }
29721 +}
29722 +
29723 +/** Suspend the PCD. Helper function for using the PCD callbacks.
29724 + *
29725 + * @param core_if Programming view of DWC_otg controller.
29726 + */
29727 +static inline void cil_pcd_suspend(dwc_otg_core_if_t * core_if)
29728 +{
29729 + if (core_if->pcd_cb && core_if->pcd_cb->suspend) {
29730 + core_if->pcd_cb->suspend(core_if->pcd_cb->p);
29731 + }
29732 +}
29733 +
29734 +/** Resume the PCD. Helper function for using the PCD callbacks.
29735 + *
29736 + * @param core_if Programming view of DWC_otg controller.
29737 + */
29738 +static inline void cil_pcd_resume(dwc_otg_core_if_t * core_if)
29739 +{
29740 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
29741 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
29742 + }
29743 +}
29744 +
29745 +//////////////////////////////////////////////////////////////////////
29746 +
29747 +#endif
29748 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
29749 new file mode 100644
29750 index 0000000..59fc862
29751 --- /dev/null
29752 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
29753 @@ -0,0 +1,1563 @@
29754 +/* ==========================================================================
29755 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil_intr.c $
29756 + * $Revision: #32 $
29757 + * $Date: 2012/08/10 $
29758 + * $Change: 2047372 $
29759 + *
29760 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
29761 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
29762 + * otherwise expressly agreed to in writing between Synopsys and you.
29763 + *
29764 + * The Software IS NOT an item of Licensed Software or Licensed Product under
29765 + * any End User Software License Agreement or Agreement for Licensed Product
29766 + * with Synopsys or any supplement thereto. You are permitted to use and
29767 + * redistribute this Software in source and binary forms, with or without
29768 + * modification, provided that redistributions of source code must retain this
29769 + * notice. You may not view, use, disclose, copy or distribute this file or
29770 + * any information contained herein except pursuant to this license grant from
29771 + * Synopsys. If you do not agree with this notice, including the disclaimer
29772 + * below, then you are not authorized to use the Software.
29773 + *
29774 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
29775 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29776 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29777 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
29778 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29779 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29780 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29781 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29782 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29783 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29784 + * DAMAGE.
29785 + * ========================================================================== */
29786 +
29787 +/** @file
29788 + *
29789 + * The Core Interface Layer provides basic services for accessing and
29790 + * managing the DWC_otg hardware. These services are used by both the
29791 + * Host Controller Driver and the Peripheral Controller Driver.
29792 + *
29793 + * This file contains the Common Interrupt handlers.
29794 + */
29795 +#include "dwc_os.h"
29796 +#include "dwc_otg_regs.h"
29797 +#include "dwc_otg_cil.h"
29798 +#include "dwc_otg_driver.h"
29799 +#include "dwc_otg_pcd.h"
29800 +#include "dwc_otg_hcd.h"
29801 +
29802 +#ifdef DEBUG
29803 +inline const char *op_state_str(dwc_otg_core_if_t * core_if)
29804 +{
29805 + return (core_if->op_state == A_HOST ? "a_host" :
29806 + (core_if->op_state == A_SUSPEND ? "a_suspend" :
29807 + (core_if->op_state == A_PERIPHERAL ? "a_peripheral" :
29808 + (core_if->op_state == B_PERIPHERAL ? "b_peripheral" :
29809 + (core_if->op_state == B_HOST ? "b_host" : "unknown")))));
29810 +}
29811 +#endif
29812 +
29813 +/** This function will log a debug message
29814 + *
29815 + * @param core_if Programming view of DWC_otg controller.
29816 + */
29817 +int32_t dwc_otg_handle_mode_mismatch_intr(dwc_otg_core_if_t * core_if)
29818 +{
29819 + gintsts_data_t gintsts;
29820 + DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
29821 + dwc_otg_mode(core_if) ? "Host" : "Device");
29822 +
29823 + /* Clear interrupt */
29824 + gintsts.d32 = 0;
29825 + gintsts.b.modemismatch = 1;
29826 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
29827 + return 1;
29828 +}
29829 +
29830 +/**
29831 + * This function handles the OTG Interrupts. It reads the OTG
29832 + * Interrupt Register (GOTGINT) to determine what interrupt has
29833 + * occurred.
29834 + *
29835 + * @param core_if Programming view of DWC_otg controller.
29836 + */
29837 +int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t * core_if)
29838 +{
29839 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
29840 + gotgint_data_t gotgint;
29841 + gotgctl_data_t gotgctl;
29842 + gintmsk_data_t gintmsk;
29843 + gpwrdn_data_t gpwrdn;
29844 +
29845 + gotgint.d32 = DWC_READ_REG32(&global_regs->gotgint);
29846 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29847 + DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
29848 + op_state_str(core_if));
29849 +
29850 + if (gotgint.b.sesenddet) {
29851 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29852 + "Session End Detected++ (%s)\n",
29853 + op_state_str(core_if));
29854 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29855 +
29856 + if (core_if->op_state == B_HOST) {
29857 + cil_pcd_start(core_if);
29858 + core_if->op_state = B_PERIPHERAL;
29859 + } else {
29860 + /* If not B_HOST and Device HNP still set. HNP
29861 + * Did not succeed!*/
29862 + if (gotgctl.b.devhnpen) {
29863 + DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
29864 + __DWC_ERROR("Device Not Connected/Responding!\n");
29865 + }
29866 +
29867 + /* If Session End Detected the B-Cable has
29868 + * been disconnected. */
29869 + /* Reset PCD and Gadget driver to a
29870 + * clean state. */
29871 + core_if->lx_state = DWC_OTG_L0;
29872 + DWC_SPINUNLOCK(core_if->lock);
29873 + cil_pcd_stop(core_if);
29874 + DWC_SPINLOCK(core_if->lock);
29875 +
29876 + if (core_if->adp_enable) {
29877 + if (core_if->power_down == 2) {
29878 + gpwrdn.d32 = 0;
29879 + gpwrdn.b.pwrdnswtch = 1;
29880 + DWC_MODIFY_REG32(&core_if->
29881 + core_global_regs->
29882 + gpwrdn, gpwrdn.d32, 0);
29883 + }
29884 +
29885 + gpwrdn.d32 = 0;
29886 + gpwrdn.b.pmuintsel = 1;
29887 + gpwrdn.b.pmuactv = 1;
29888 + DWC_MODIFY_REG32(&core_if->core_global_regs->
29889 + gpwrdn, 0, gpwrdn.d32);
29890 +
29891 + dwc_otg_adp_sense_start(core_if);
29892 + }
29893 + }
29894 +
29895 + gotgctl.d32 = 0;
29896 + gotgctl.b.devhnpen = 1;
29897 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
29898 + }
29899 + if (gotgint.b.sesreqsucstschng) {
29900 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29901 + "Session Reqeust Success Status Change++\n");
29902 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29903 + if (gotgctl.b.sesreqscs) {
29904 +
29905 + if ((core_if->core_params->phy_type ==
29906 + DWC_PHY_TYPE_PARAM_FS) && (core_if->core_params->i2c_enable)) {
29907 + core_if->srp_success = 1;
29908 + } else {
29909 + DWC_SPINUNLOCK(core_if->lock);
29910 + cil_pcd_resume(core_if);
29911 + DWC_SPINLOCK(core_if->lock);
29912 + /* Clear Session Request */
29913 + gotgctl.d32 = 0;
29914 + gotgctl.b.sesreq = 1;
29915 + DWC_MODIFY_REG32(&global_regs->gotgctl,
29916 + gotgctl.d32, 0);
29917 + }
29918 + }
29919 + }
29920 + if (gotgint.b.hstnegsucstschng) {
29921 + /* Print statements during the HNP interrupt handling
29922 + * can cause it to fail.*/
29923 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29924 + /* WA for 3.00a- HW is not setting cur_mode, even sometimes
29925 + * this does not help*/
29926 + if (core_if->snpsid >= OTG_CORE_REV_3_00a)
29927 + dwc_udelay(100);
29928 + if (gotgctl.b.hstnegscs) {
29929 + if (dwc_otg_is_host_mode(core_if)) {
29930 + core_if->op_state = B_HOST;
29931 + /*
29932 + * Need to disable SOF interrupt immediately.
29933 + * When switching from device to host, the PCD
29934 + * interrupt handler won't handle the
29935 + * interrupt if host mode is already set. The
29936 + * HCD interrupt handler won't get called if
29937 + * the HCD state is HALT. This means that the
29938 + * interrupt does not get handled and Linux
29939 + * complains loudly.
29940 + */
29941 + gintmsk.d32 = 0;
29942 + gintmsk.b.sofintr = 1;
29943 + DWC_MODIFY_REG32(&global_regs->gintmsk,
29944 + gintmsk.d32, 0);
29945 + /* Call callback function with spin lock released */
29946 + DWC_SPINUNLOCK(core_if->lock);
29947 + cil_pcd_stop(core_if);
29948 + /*
29949 + * Initialize the Core for Host mode.
29950 + */
29951 + cil_hcd_start(core_if);
29952 + DWC_SPINLOCK(core_if->lock);
29953 + core_if->op_state = B_HOST;
29954 + }
29955 + } else {
29956 + gotgctl.d32 = 0;
29957 + gotgctl.b.hnpreq = 1;
29958 + gotgctl.b.devhnpen = 1;
29959 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
29960 + DWC_DEBUGPL(DBG_ANY, "HNP Failed\n");
29961 + __DWC_ERROR("Device Not Connected/Responding\n");
29962 + }
29963 + }
29964 + if (gotgint.b.hstnegdet) {
29965 + /* The disconnect interrupt is set at the same time as
29966 + * Host Negotiation Detected. During the mode
29967 + * switch all interrupts are cleared so the disconnect
29968 + * interrupt handler will not get executed.
29969 + */
29970 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29971 + "Host Negotiation Detected++ (%s)\n",
29972 + (dwc_otg_is_host_mode(core_if) ? "Host" :
29973 + "Device"));
29974 + if (dwc_otg_is_device_mode(core_if)) {
29975 + DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
29976 + core_if->op_state);
29977 + DWC_SPINUNLOCK(core_if->lock);
29978 + cil_hcd_disconnect(core_if);
29979 + cil_pcd_start(core_if);
29980 + DWC_SPINLOCK(core_if->lock);
29981 + core_if->op_state = A_PERIPHERAL;
29982 + } else {
29983 + /*
29984 + * Need to disable SOF interrupt immediately. When
29985 + * switching from device to host, the PCD interrupt
29986 + * handler won't handle the interrupt if host mode is
29987 + * already set. The HCD interrupt handler won't get
29988 + * called if the HCD state is HALT. This means that
29989 + * the interrupt does not get handled and Linux
29990 + * complains loudly.
29991 + */
29992 + gintmsk.d32 = 0;
29993 + gintmsk.b.sofintr = 1;
29994 + DWC_MODIFY_REG32(&global_regs->gintmsk, gintmsk.d32, 0);
29995 + DWC_SPINUNLOCK(core_if->lock);
29996 + cil_pcd_stop(core_if);
29997 + cil_hcd_start(core_if);
29998 + DWC_SPINLOCK(core_if->lock);
29999 + core_if->op_state = A_HOST;
30000 + }
30001 + }
30002 + if (gotgint.b.adevtoutchng) {
30003 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
30004 + "A-Device Timeout Change++\n");
30005 + }
30006 + if (gotgint.b.debdone) {
30007 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n");
30008 + }
30009 +
30010 + /* Clear GOTGINT */
30011 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, gotgint.d32);
30012 +
30013 + return 1;
30014 +}
30015 +
30016 +void w_conn_id_status_change(void *p)
30017 +{
30018 + dwc_otg_core_if_t *core_if = p;
30019 + uint32_t count = 0;
30020 + gotgctl_data_t gotgctl = {.d32 = 0 };
30021 +
30022 + gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
30023 + DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
30024 + DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
30025 +
30026 + /* B-Device connector (Device Mode) */
30027 + if (gotgctl.b.conidsts) {
30028 + /* Wait for switch to device mode. */
30029 + while (!dwc_otg_is_device_mode(core_if)) {
30030 + DWC_PRINTF("Waiting for Peripheral Mode, Mode=%s\n",
30031 + (dwc_otg_is_host_mode(core_if) ? "Host" :
30032 + "Peripheral"));
30033 + dwc_mdelay(100);
30034 + if (++count > 10000)
30035 + break;
30036 + }
30037 + DWC_ASSERT(++count < 10000,
30038 + "Connection id status change timed out");
30039 + core_if->op_state = B_PERIPHERAL;
30040 + dwc_otg_core_init(core_if);
30041 + dwc_otg_enable_global_interrupts(core_if);
30042 + cil_pcd_start(core_if);
30043 + } else {
30044 + /* A-Device connector (Host Mode) */
30045 + while (!dwc_otg_is_host_mode(core_if)) {
30046 + DWC_PRINTF("Waiting for Host Mode, Mode=%s\n",
30047 + (dwc_otg_is_host_mode(core_if) ? "Host" :
30048 + "Peripheral"));
30049 + dwc_mdelay(100);
30050 + if (++count > 10000)
30051 + break;
30052 + }
30053 + DWC_ASSERT(++count < 10000,
30054 + "Connection id status change timed out");
30055 + core_if->op_state = A_HOST;
30056 + /*
30057 + * Initialize the Core for Host mode.
30058 + */
30059 + dwc_otg_core_init(core_if);
30060 + dwc_otg_enable_global_interrupts(core_if);
30061 + cil_hcd_start(core_if);
30062 + }
30063 +}
30064 +
30065 +/**
30066 + * This function handles the Connector ID Status Change Interrupt. It
30067 + * reads the OTG Interrupt Register (GOTCTL) to determine whether this
30068 + * is a Device to Host Mode transition or a Host Mode to Device
30069 + * Transition.
30070 + *
30071 + * This only occurs when the cable is connected/removed from the PHY
30072 + * connector.
30073 + *
30074 + * @param core_if Programming view of DWC_otg controller.
30075 + */
30076 +int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t * core_if)
30077 +{
30078 +
30079 + /*
30080 + * Need to disable SOF interrupt immediately. If switching from device
30081 + * to host, the PCD interrupt handler won't handle the interrupt if
30082 + * host mode is already set. The HCD interrupt handler won't get
30083 + * called if the HCD state is HALT. This means that the interrupt does
30084 + * not get handled and Linux complains loudly.
30085 + */
30086 + gintmsk_data_t gintmsk = {.d32 = 0 };
30087 + gintsts_data_t gintsts = {.d32 = 0 };
30088 +
30089 + gintmsk.b.sofintr = 1;
30090 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
30091 +
30092 + DWC_DEBUGPL(DBG_CIL,
30093 + " ++Connector ID Status Change Interrupt++ (%s)\n",
30094 + (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
30095 +
30096 + DWC_SPINUNLOCK(core_if->lock);
30097 +
30098 + /*
30099 + * Need to schedule a work, as there are possible DELAY function calls
30100 + * Release lock before scheduling workq as it holds spinlock during scheduling
30101 + */
30102 +
30103 + DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
30104 + core_if, "connection id status change");
30105 + DWC_SPINLOCK(core_if->lock);
30106 +
30107 + /* Set flag and clear interrupt */
30108 + gintsts.b.conidstschng = 1;
30109 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30110 +
30111 + return 1;
30112 +}
30113 +
30114 +/**
30115 + * This interrupt indicates that a device is initiating the Session
30116 + * Request Protocol to request the host to turn on bus power so a new
30117 + * session can begin. The handler responds by turning on bus power. If
30118 + * the DWC_otg controller is in low power mode, the handler brings the
30119 + * controller out of low power mode before turning on bus power.
30120 + *
30121 + * @param core_if Programming view of DWC_otg controller.
30122 + */
30123 +int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * core_if)
30124 +{
30125 + gintsts_data_t gintsts;
30126 +
30127 +#ifndef DWC_HOST_ONLY
30128 + DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
30129 +
30130 + if (dwc_otg_is_device_mode(core_if)) {
30131 + DWC_PRINTF("SRP: Device mode\n");
30132 + } else {
30133 + hprt0_data_t hprt0;
30134 + DWC_PRINTF("SRP: Host mode\n");
30135 +
30136 + /* Turn on the port power bit. */
30137 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
30138 + hprt0.b.prtpwr = 1;
30139 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
30140 +
30141 + /* Start the Connection timer. So a message can be displayed
30142 + * if connect does not occur within 10 seconds. */
30143 + cil_hcd_session_start(core_if);
30144 + }
30145 +#endif
30146 +
30147 + /* Clear interrupt */
30148 + gintsts.d32 = 0;
30149 + gintsts.b.sessreqintr = 1;
30150 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30151 +
30152 + return 1;
30153 +}
30154 +
30155 +void w_wakeup_detected(void *p)
30156 +{
30157 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) p;
30158 + /*
30159 + * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
30160 + * so that OPT tests pass with all PHYs).
30161 + */
30162 + hprt0_data_t hprt0 = {.d32 = 0 };
30163 +#if 0
30164 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30165 + /* Restart the Phy Clock */
30166 + pcgcctl.b.stoppclk = 1;
30167 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
30168 + dwc_udelay(10);
30169 +#endif //0
30170 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
30171 + DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
30172 +// dwc_mdelay(70);
30173 + hprt0.b.prtres = 0; /* Resume */
30174 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
30175 + DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
30176 + DWC_READ_REG32(core_if->host_if->hprt0));
30177 +
30178 + cil_hcd_resume(core_if);
30179 +
30180 + /** Change to L0 state*/
30181 + core_if->lx_state = DWC_OTG_L0;
30182 +}
30183 +
30184 +/**
30185 + * This interrupt indicates that the DWC_otg controller has detected a
30186 + * resume or remote wakeup sequence. If the DWC_otg controller is in
30187 + * low power mode, the handler must brings the controller out of low
30188 + * power mode. The controller automatically begins resume
30189 + * signaling. The handler schedules a time to stop resume signaling.
30190 + */
30191 +int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
30192 +{
30193 + gintsts_data_t gintsts;
30194 +
30195 + DWC_DEBUGPL(DBG_ANY,
30196 + "++Resume and Remote Wakeup Detected Interrupt++\n");
30197 +
30198 + DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);
30199 +
30200 + if (dwc_otg_is_device_mode(core_if)) {
30201 + dctl_data_t dctl = {.d32 = 0 };
30202 + DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
30203 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
30204 + dsts));
30205 + if (core_if->lx_state == DWC_OTG_L2) {
30206 +#ifdef PARTIAL_POWER_DOWN
30207 + if (core_if->hwcfg4.b.power_optimiz) {
30208 + pcgcctl_data_t power = {.d32 = 0 };
30209 +
30210 + power.d32 = DWC_READ_REG32(core_if->pcgcctl);
30211 + DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
30212 + power.d32);
30213 +
30214 + power.b.stoppclk = 0;
30215 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30216 +
30217 + power.b.pwrclmp = 0;
30218 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30219 +
30220 + power.b.rstpdwnmodule = 0;
30221 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30222 + }
30223 +#endif
30224 + /* Clear the Remote Wakeup Signaling */
30225 + dctl.b.rmtwkupsig = 1;
30226 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
30227 + dctl, dctl.d32, 0);
30228 +
30229 + DWC_SPINUNLOCK(core_if->lock);
30230 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
30231 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
30232 + }
30233 + DWC_SPINLOCK(core_if->lock);
30234 + } else {
30235 + glpmcfg_data_t lpmcfg;
30236 + lpmcfg.d32 =
30237 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
30238 + lpmcfg.b.hird_thres &= (~(1 << 4));
30239 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
30240 + lpmcfg.d32);
30241 + }
30242 + /** Change to L0 state*/
30243 + core_if->lx_state = DWC_OTG_L0;
30244 + } else {
30245 + if (core_if->lx_state != DWC_OTG_L1) {
30246 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30247 +
30248 + /* Restart the Phy Clock */
30249 + pcgcctl.b.stoppclk = 1;
30250 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
30251 + DWC_TIMER_SCHEDULE(core_if->wkp_timer, 71);
30252 + } else {
30253 + /** Change to L0 state*/
30254 + core_if->lx_state = DWC_OTG_L0;
30255 + }
30256 + }
30257 +
30258 + /* Clear interrupt */
30259 + gintsts.d32 = 0;
30260 + gintsts.b.wkupintr = 1;
30261 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30262 +
30263 + return 1;
30264 +}
30265 +
30266 +/**
30267 + * This interrupt indicates that the Wakeup Logic has detected a
30268 + * Device disconnect.
30269 + */
30270 +static int32_t dwc_otg_handle_pwrdn_disconnect_intr(dwc_otg_core_if_t *core_if)
30271 +{
30272 + gpwrdn_data_t gpwrdn = { .d32 = 0 };
30273 + gpwrdn_data_t gpwrdn_temp = { .d32 = 0 };
30274 + gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30275 +
30276 + DWC_PRINTF("%s called\n", __FUNCTION__);
30277 +
30278 + if (!core_if->hibernation_suspend) {
30279 + DWC_PRINTF("Already exited from Hibernation\n");
30280 + return 1;
30281 + }
30282 +
30283 + /* Switch on the voltage to the core */
30284 + gpwrdn.b.pwrdnswtch = 1;
30285 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30286 + dwc_udelay(10);
30287 +
30288 + /* Reset the core */
30289 + gpwrdn.d32 = 0;
30290 + gpwrdn.b.pwrdnrstn = 1;
30291 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30292 + dwc_udelay(10);
30293 +
30294 + /* Disable power clamps*/
30295 + gpwrdn.d32 = 0;
30296 + gpwrdn.b.pwrdnclmp = 1;
30297 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30298 +
30299 + /* Remove reset the core signal */
30300 + gpwrdn.d32 = 0;
30301 + gpwrdn.b.pwrdnrstn = 1;
30302 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30303 + dwc_udelay(10);
30304 +
30305 + /* Disable PMU interrupt */
30306 + gpwrdn.d32 = 0;
30307 + gpwrdn.b.pmuintsel = 1;
30308 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30309 +
30310 + core_if->hibernation_suspend = 0;
30311 +
30312 + /* Disable PMU */
30313 + gpwrdn.d32 = 0;
30314 + gpwrdn.b.pmuactv = 1;
30315 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30316 + dwc_udelay(10);
30317 +
30318 + if (gpwrdn_temp.b.idsts) {
30319 + core_if->op_state = B_PERIPHERAL;
30320 + dwc_otg_core_init(core_if);
30321 + dwc_otg_enable_global_interrupts(core_if);
30322 + cil_pcd_start(core_if);
30323 + } else {
30324 + core_if->op_state = A_HOST;
30325 + dwc_otg_core_init(core_if);
30326 + dwc_otg_enable_global_interrupts(core_if);
30327 + cil_hcd_start(core_if);
30328 + }
30329 +
30330 + return 1;
30331 +}
30332 +
30333 +/**
30334 + * This interrupt indicates that the Wakeup Logic has detected a
30335 + * remote wakeup sequence.
30336 + */
30337 +static int32_t dwc_otg_handle_pwrdn_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
30338 +{
30339 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30340 + DWC_DEBUGPL(DBG_ANY,
30341 + "++Powerdown Remote Wakeup Detected Interrupt++\n");
30342 +
30343 + if (!core_if->hibernation_suspend) {
30344 + DWC_PRINTF("Already exited from Hibernation\n");
30345 + return 1;
30346 + }
30347 +
30348 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30349 + if (gpwrdn.b.idsts) { // Device Mode
30350 + if ((core_if->power_down == 2)
30351 + && (core_if->hibernation_suspend == 1)) {
30352 + dwc_otg_device_hibernation_restore(core_if, 0, 0);
30353 + }
30354 + } else {
30355 + if ((core_if->power_down == 2)
30356 + && (core_if->hibernation_suspend == 1)) {
30357 + dwc_otg_host_hibernation_restore(core_if, 1, 0);
30358 + }
30359 + }
30360 + return 1;
30361 +}
30362 +
30363 +static int32_t dwc_otg_handle_pwrdn_idsts_change(dwc_otg_device_t *otg_dev)
30364 +{
30365 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30366 + gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
30367 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
30368 +
30369 + DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
30370 + gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30371 + if (core_if->power_down == 2) {
30372 + if (!core_if->hibernation_suspend) {
30373 + DWC_PRINTF("Already exited from Hibernation\n");
30374 + return 1;
30375 + }
30376 + DWC_DEBUGPL(DBG_ANY, "Exit from hibernation on ID sts change\n");
30377 + /* Switch on the voltage to the core */
30378 + gpwrdn.b.pwrdnswtch = 1;
30379 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30380 + dwc_udelay(10);
30381 +
30382 + /* Reset the core */
30383 + gpwrdn.d32 = 0;
30384 + gpwrdn.b.pwrdnrstn = 1;
30385 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30386 + dwc_udelay(10);
30387 +
30388 + /* Disable power clamps */
30389 + gpwrdn.d32 = 0;
30390 + gpwrdn.b.pwrdnclmp = 1;
30391 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30392 +
30393 + /* Remove reset the core signal */
30394 + gpwrdn.d32 = 0;
30395 + gpwrdn.b.pwrdnrstn = 1;
30396 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30397 + dwc_udelay(10);
30398 +
30399 + /* Disable PMU interrupt */
30400 + gpwrdn.d32 = 0;
30401 + gpwrdn.b.pmuintsel = 1;
30402 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30403 +
30404 + /*Indicates that we are exiting from hibernation */
30405 + core_if->hibernation_suspend = 0;
30406 +
30407 + /* Disable PMU */
30408 + gpwrdn.d32 = 0;
30409 + gpwrdn.b.pmuactv = 1;
30410 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30411 + dwc_udelay(10);
30412 +
30413 + gpwrdn.d32 = core_if->gr_backup->gpwrdn_local;
30414 + if (gpwrdn.b.dis_vbus == 1) {
30415 + gpwrdn.d32 = 0;
30416 + gpwrdn.b.dis_vbus = 1;
30417 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30418 + }
30419 +
30420 + if (gpwrdn_temp.b.idsts) {
30421 + core_if->op_state = B_PERIPHERAL;
30422 + dwc_otg_core_init(core_if);
30423 + dwc_otg_enable_global_interrupts(core_if);
30424 + cil_pcd_start(core_if);
30425 + } else {
30426 + core_if->op_state = A_HOST;
30427 + dwc_otg_core_init(core_if);
30428 + dwc_otg_enable_global_interrupts(core_if);
30429 + cil_hcd_start(core_if);
30430 + }
30431 + }
30432 +
30433 + if (core_if->adp_enable) {
30434 + uint8_t is_host = 0;
30435 + DWC_SPINUNLOCK(core_if->lock);
30436 + /* Change the core_if's lock to hcd/pcd lock depend on mode? */
30437 +#ifndef DWC_HOST_ONLY
30438 + if (gpwrdn_temp.b.idsts)
30439 + core_if->lock = otg_dev->pcd->lock;
30440 +#endif
30441 +#ifndef DWC_DEVICE_ONLY
30442 + if (!gpwrdn_temp.b.idsts) {
30443 + core_if->lock = otg_dev->hcd->lock;
30444 + is_host = 1;
30445 + }
30446 +#endif
30447 + DWC_PRINTF("RESTART ADP\n");
30448 + if (core_if->adp.probe_enabled)
30449 + dwc_otg_adp_probe_stop(core_if);
30450 + if (core_if->adp.sense_enabled)
30451 + dwc_otg_adp_sense_stop(core_if);
30452 + if (core_if->adp.sense_timer_started)
30453 + DWC_TIMER_CANCEL(core_if->adp.sense_timer);
30454 + if (core_if->adp.vbuson_timer_started)
30455 + DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
30456 + core_if->adp.probe_timer_values[0] = -1;
30457 + core_if->adp.probe_timer_values[1] = -1;
30458 + core_if->adp.sense_timer_started = 0;
30459 + core_if->adp.vbuson_timer_started = 0;
30460 + core_if->adp.probe_counter = 0;
30461 + core_if->adp.gpwrdn = 0;
30462 +
30463 + /* Disable PMU and restart ADP */
30464 + gpwrdn_temp.d32 = 0;
30465 + gpwrdn_temp.b.pmuactv = 1;
30466 + gpwrdn_temp.b.pmuintsel = 1;
30467 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30468 + DWC_PRINTF("Check point 1\n");
30469 + dwc_mdelay(110);
30470 + dwc_otg_adp_start(core_if, is_host);
30471 + DWC_SPINLOCK(core_if->lock);
30472 + }
30473 +
30474 +
30475 + return 1;
30476 +}
30477 +
30478 +static int32_t dwc_otg_handle_pwrdn_session_change(dwc_otg_core_if_t * core_if)
30479 +{
30480 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30481 + int32_t otg_cap_param = core_if->core_params->otg_cap;
30482 + DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
30483 +
30484 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30485 + if (core_if->power_down == 2) {
30486 + if (!core_if->hibernation_suspend) {
30487 + DWC_PRINTF("Already exited from Hibernation\n");
30488 + return 1;
30489 + }
30490 +
30491 + if ((otg_cap_param != DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
30492 + otg_cap_param != DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) &&
30493 + gpwrdn.b.bsessvld == 0) {
30494 + /* Save gpwrdn register for further usage if stschng interrupt */
30495 + core_if->gr_backup->gpwrdn_local =
30496 + DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30497 + /*Exit from ISR and wait for stschng interrupt with bsessvld = 1 */
30498 + return 1;
30499 + }
30500 +
30501 + /* Switch on the voltage to the core */
30502 + gpwrdn.d32 = 0;
30503 + gpwrdn.b.pwrdnswtch = 1;
30504 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30505 + dwc_udelay(10);
30506 +
30507 + /* Reset the core */
30508 + gpwrdn.d32 = 0;
30509 + gpwrdn.b.pwrdnrstn = 1;
30510 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30511 + dwc_udelay(10);
30512 +
30513 + /* Disable power clamps */
30514 + gpwrdn.d32 = 0;
30515 + gpwrdn.b.pwrdnclmp = 1;
30516 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30517 +
30518 + /* Remove reset the core signal */
30519 + gpwrdn.d32 = 0;
30520 + gpwrdn.b.pwrdnrstn = 1;
30521 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30522 + dwc_udelay(10);
30523 +
30524 + /* Disable PMU interrupt */
30525 + gpwrdn.d32 = 0;
30526 + gpwrdn.b.pmuintsel = 1;
30527 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30528 + dwc_udelay(10);
30529 +
30530 + /*Indicates that we are exiting from hibernation */
30531 + core_if->hibernation_suspend = 0;
30532 +
30533 + /* Disable PMU */
30534 + gpwrdn.d32 = 0;
30535 + gpwrdn.b.pmuactv = 1;
30536 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30537 + dwc_udelay(10);
30538 +
30539 + core_if->op_state = B_PERIPHERAL;
30540 + dwc_otg_core_init(core_if);
30541 + dwc_otg_enable_global_interrupts(core_if);
30542 + cil_pcd_start(core_if);
30543 +
30544 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
30545 + otg_cap_param == DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) {
30546 + /*
30547 + * Initiate SRP after initial ADP probe.
30548 + */
30549 + dwc_otg_initiate_srp(core_if);
30550 + }
30551 + }
30552 +
30553 + return 1;
30554 +}
30555 +/**
30556 + * This interrupt indicates that the Wakeup Logic has detected a
30557 + * status change either on IDDIG or BSessVld.
30558 + */
30559 +static uint32_t dwc_otg_handle_pwrdn_stschng_intr(dwc_otg_device_t *otg_dev)
30560 +{
30561 + int retval;
30562 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30563 + gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
30564 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
30565 +
30566 + DWC_PRINTF("%s called\n", __FUNCTION__);
30567 +
30568 + if (core_if->power_down == 2) {
30569 + if (core_if->hibernation_suspend <= 0) {
30570 + DWC_PRINTF("Already exited from Hibernation\n");
30571 + return 1;
30572 + } else
30573 + gpwrdn_temp.d32 = core_if->gr_backup->gpwrdn_local;
30574 +
30575 + } else {
30576 + gpwrdn_temp.d32 = core_if->adp.gpwrdn;
30577 + }
30578 +
30579 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30580 +
30581 + if (gpwrdn.b.idsts ^ gpwrdn_temp.b.idsts) {
30582 + retval = dwc_otg_handle_pwrdn_idsts_change(otg_dev);
30583 + } else if (gpwrdn.b.bsessvld ^ gpwrdn_temp.b.bsessvld) {
30584 + retval = dwc_otg_handle_pwrdn_session_change(core_if);
30585 + }
30586 +
30587 + return retval;
30588 +}
30589 +
30590 +/**
30591 + * This interrupt indicates that the Wakeup Logic has detected a
30592 + * SRP.
30593 + */
30594 +static int32_t dwc_otg_handle_pwrdn_srp_intr(dwc_otg_core_if_t * core_if)
30595 +{
30596 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30597 +
30598 + DWC_PRINTF("%s called\n", __FUNCTION__);
30599 +
30600 + if (!core_if->hibernation_suspend) {
30601 + DWC_PRINTF("Already exited from Hibernation\n");
30602 + return 1;
30603 + }
30604 +#ifdef DWC_DEV_SRPCAP
30605 + if (core_if->pwron_timer_started) {
30606 + core_if->pwron_timer_started = 0;
30607 + DWC_TIMER_CANCEL(core_if->pwron_timer);
30608 + }
30609 +#endif
30610 +
30611 + /* Switch on the voltage to the core */
30612 + gpwrdn.b.pwrdnswtch = 1;
30613 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30614 + dwc_udelay(10);
30615 +
30616 + /* Reset the core */
30617 + gpwrdn.d32 = 0;
30618 + gpwrdn.b.pwrdnrstn = 1;
30619 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30620 + dwc_udelay(10);
30621 +
30622 + /* Disable power clamps */
30623 + gpwrdn.d32 = 0;
30624 + gpwrdn.b.pwrdnclmp = 1;
30625 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30626 +
30627 + /* Remove reset the core signal */
30628 + gpwrdn.d32 = 0;
30629 + gpwrdn.b.pwrdnrstn = 1;
30630 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30631 + dwc_udelay(10);
30632 +
30633 + /* Disable PMU interrupt */
30634 + gpwrdn.d32 = 0;
30635 + gpwrdn.b.pmuintsel = 1;
30636 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30637 +
30638 + /* Indicates that we are exiting from hibernation */
30639 + core_if->hibernation_suspend = 0;
30640 +
30641 + /* Disable PMU */
30642 + gpwrdn.d32 = 0;
30643 + gpwrdn.b.pmuactv = 1;
30644 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30645 + dwc_udelay(10);
30646 +
30647 + /* Programm Disable VBUS to 0 */
30648 + gpwrdn.d32 = 0;
30649 + gpwrdn.b.dis_vbus = 1;
30650 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30651 +
30652 + /*Initialize the core as Host */
30653 + core_if->op_state = A_HOST;
30654 + dwc_otg_core_init(core_if);
30655 + dwc_otg_enable_global_interrupts(core_if);
30656 + cil_hcd_start(core_if);
30657 +
30658 + return 1;
30659 +}
30660 +
30661 +/** This interrupt indicates that restore command after Hibernation
30662 + * was completed by the core. */
30663 +int32_t dwc_otg_handle_restore_done_intr(dwc_otg_core_if_t * core_if)
30664 +{
30665 + pcgcctl_data_t pcgcctl;
30666 + DWC_DEBUGPL(DBG_ANY, "++Restore Done Interrupt++\n");
30667 +
30668 + //TODO De-assert restore signal. 8.a
30669 + pcgcctl.d32 = DWC_READ_REG32(core_if->pcgcctl);
30670 + if (pcgcctl.b.restoremode == 1) {
30671 + gintmsk_data_t gintmsk = {.d32 = 0 };
30672 + /*
30673 + * If restore mode is Remote Wakeup,
30674 + * unmask Remote Wakeup interrupt.
30675 + */
30676 + gintmsk.b.wkupintr = 1;
30677 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
30678 + 0, gintmsk.d32);
30679 + }
30680 +
30681 + return 1;
30682 +}
30683 +
30684 +/**
30685 + * This interrupt indicates that a device has been disconnected from
30686 + * the root port.
30687 + */
30688 +int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t * core_if)
30689 +{
30690 + gintsts_data_t gintsts;
30691 +
30692 + DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
30693 + (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"),
30694 + op_state_str(core_if));
30695 +
30696 +/** @todo Consolidate this if statement. */
30697 +#ifndef DWC_HOST_ONLY
30698 + if (core_if->op_state == B_HOST) {
30699 + /* If in device mode Disconnect and stop the HCD, then
30700 + * start the PCD. */
30701 + DWC_SPINUNLOCK(core_if->lock);
30702 + cil_hcd_disconnect(core_if);
30703 + cil_pcd_start(core_if);
30704 + DWC_SPINLOCK(core_if->lock);
30705 + core_if->op_state = B_PERIPHERAL;
30706 + } else if (dwc_otg_is_device_mode(core_if)) {
30707 + gotgctl_data_t gotgctl = {.d32 = 0 };
30708 + gotgctl.d32 =
30709 + DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
30710 + if (gotgctl.b.hstsethnpen == 1) {
30711 + /* Do nothing, if HNP in process the OTG
30712 + * interrupt "Host Negotiation Detected"
30713 + * interrupt will do the mode switch.
30714 + */
30715 + } else if (gotgctl.b.devhnpen == 0) {
30716 + /* If in device mode Disconnect and stop the HCD, then
30717 + * start the PCD. */
30718 + DWC_SPINUNLOCK(core_if->lock);
30719 + cil_hcd_disconnect(core_if);
30720 + cil_pcd_start(core_if);
30721 + DWC_SPINLOCK(core_if->lock);
30722 + core_if->op_state = B_PERIPHERAL;
30723 + } else {
30724 + DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
30725 + }
30726 + } else {
30727 + if (core_if->op_state == A_HOST) {
30728 + /* A-Cable still connected but device disconnected. */
30729 + cil_hcd_disconnect(core_if);
30730 + if (core_if->adp_enable) {
30731 + gpwrdn_data_t gpwrdn = { .d32 = 0 };
30732 + cil_hcd_stop(core_if);
30733 + /* Enable Power Down Logic */
30734 + gpwrdn.b.pmuintsel = 1;
30735 + gpwrdn.b.pmuactv = 1;
30736 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30737 + gpwrdn, 0, gpwrdn.d32);
30738 + dwc_otg_adp_probe_start(core_if);
30739 +
30740 + /* Power off the core */
30741 + if (core_if->power_down == 2) {
30742 + gpwrdn.d32 = 0;
30743 + gpwrdn.b.pwrdnswtch = 1;
30744 + DWC_MODIFY_REG32
30745 + (&core_if->core_global_regs->gpwrdn,
30746 + gpwrdn.d32, 0);
30747 + }
30748 + }
30749 + }
30750 + }
30751 +#endif
30752 + /* Change to L3(OFF) state */
30753 + core_if->lx_state = DWC_OTG_L3;
30754 +
30755 + gintsts.d32 = 0;
30756 + gintsts.b.disconnect = 1;
30757 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30758 + return 1;
30759 +}
30760 +
30761 +/**
30762 + * This interrupt indicates that SUSPEND state has been detected on
30763 + * the USB.
30764 + *
30765 + * For HNP the USB Suspend interrupt signals the change from
30766 + * "a_peripheral" to "a_host".
30767 + *
30768 + * When power management is enabled the core will be put in low power
30769 + * mode.
30770 + */
30771 +int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t * core_if)
30772 +{
30773 + dsts_data_t dsts;
30774 + gintsts_data_t gintsts;
30775 + dcfg_data_t dcfg;
30776 +
30777 + DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
30778 +
30779 + if (dwc_otg_is_device_mode(core_if)) {
30780 + /* Check the Device status register to determine if the Suspend
30781 + * state is active. */
30782 + dsts.d32 =
30783 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
30784 + DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
30785 + DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d "
30786 + "HWCFG4.power Optimize=%d\n",
30787 + dsts.b.suspsts, core_if->hwcfg4.b.power_optimiz);
30788 +
30789 +#ifdef PARTIAL_POWER_DOWN
30790 +/** @todo Add a module parameter for power management. */
30791 +
30792 + if (dsts.b.suspsts && core_if->hwcfg4.b.power_optimiz) {
30793 + pcgcctl_data_t power = {.d32 = 0 };
30794 + DWC_DEBUGPL(DBG_CIL, "suspend\n");
30795 +
30796 + power.b.pwrclmp = 1;
30797 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30798 +
30799 + power.b.rstpdwnmodule = 1;
30800 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
30801 +
30802 + power.b.stoppclk = 1;
30803 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
30804 +
30805 + } else {
30806 + DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
30807 + }
30808 +#endif
30809 + /* PCD callback for suspend. Release the lock inside of callback function */
30810 + cil_pcd_suspend(core_if);
30811 + if (core_if->power_down == 2)
30812 + {
30813 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
30814 + DWC_DEBUGPL(DBG_ANY,"lx_state = %08x\n",core_if->lx_state);
30815 + DWC_DEBUGPL(DBG_ANY," device address = %08d\n",dcfg.b.devaddr);
30816 +
30817 + if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
30818 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30819 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30820 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
30821 +
30822 + /* Change to L2(suspend) state */
30823 + core_if->lx_state = DWC_OTG_L2;
30824 +
30825 + /* Clear interrupt in gintsts */
30826 + gintsts.d32 = 0;
30827 + gintsts.b.usbsuspend = 1;
30828 + DWC_WRITE_REG32(&core_if->core_global_regs->
30829 + gintsts, gintsts.d32);
30830 + DWC_PRINTF("Start of hibernation completed\n");
30831 + dwc_otg_save_global_regs(core_if);
30832 + dwc_otg_save_dev_regs(core_if);
30833 +
30834 + gusbcfg.d32 =
30835 + DWC_READ_REG32(&core_if->core_global_regs->
30836 + gusbcfg);
30837 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
30838 + /* ULPI interface */
30839 + /* Suspend the Phy Clock */
30840 + pcgcctl.d32 = 0;
30841 + pcgcctl.b.stoppclk = 1;
30842 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
30843 + pcgcctl.d32);
30844 + dwc_udelay(10);
30845 + gpwrdn.b.pmuactv = 1;
30846 + DWC_MODIFY_REG32(&core_if->
30847 + core_global_regs->
30848 + gpwrdn, 0, gpwrdn.d32);
30849 + } else {
30850 + /* UTMI+ Interface */
30851 + gpwrdn.b.pmuactv = 1;
30852 + DWC_MODIFY_REG32(&core_if->
30853 + core_global_regs->
30854 + gpwrdn, 0, gpwrdn.d32);
30855 + dwc_udelay(10);
30856 + pcgcctl.b.stoppclk = 1;
30857 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
30858 + pcgcctl.d32);
30859 + dwc_udelay(10);
30860 + }
30861 +
30862 + /* Set flag to indicate that we are in hibernation */
30863 + core_if->hibernation_suspend = 1;
30864 + /* Enable interrupts from wake up logic */
30865 + gpwrdn.d32 = 0;
30866 + gpwrdn.b.pmuintsel = 1;
30867 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30868 + gpwrdn, 0, gpwrdn.d32);
30869 + dwc_udelay(10);
30870 +
30871 + /* Unmask device mode interrupts in GPWRDN */
30872 + gpwrdn.d32 = 0;
30873 + gpwrdn.b.rst_det_msk = 1;
30874 + gpwrdn.b.lnstchng_msk = 1;
30875 + gpwrdn.b.sts_chngint_msk = 1;
30876 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30877 + gpwrdn, 0, gpwrdn.d32);
30878 + dwc_udelay(10);
30879 +
30880 + /* Enable Power Down Clamp */
30881 + gpwrdn.d32 = 0;
30882 + gpwrdn.b.pwrdnclmp = 1;
30883 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30884 + gpwrdn, 0, gpwrdn.d32);
30885 + dwc_udelay(10);
30886 +
30887 + /* Switch off VDD */
30888 + gpwrdn.d32 = 0;
30889 + gpwrdn.b.pwrdnswtch = 1;
30890 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30891 + gpwrdn, 0, gpwrdn.d32);
30892 +
30893 + /* Save gpwrdn register for further usage if stschng interrupt */
30894 + core_if->gr_backup->gpwrdn_local =
30895 + DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30896 + DWC_PRINTF("Hibernation completed\n");
30897 +
30898 + return 1;
30899 + }
30900 + } else if (core_if->power_down == 3) {
30901 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30902 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
30903 + DWC_DEBUGPL(DBG_ANY, "lx_state = %08x\n",core_if->lx_state);
30904 + DWC_DEBUGPL(DBG_ANY, " device address = %08d\n",dcfg.b.devaddr);
30905 +
30906 + if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
30907 + DWC_DEBUGPL(DBG_ANY, "Start entering to extended hibernation\n");
30908 + core_if->xhib = 1;
30909 +
30910 + /* Clear interrupt in gintsts */
30911 + gintsts.d32 = 0;
30912 + gintsts.b.usbsuspend = 1;
30913 + DWC_WRITE_REG32(&core_if->core_global_regs->
30914 + gintsts, gintsts.d32);
30915 +
30916 + dwc_otg_save_global_regs(core_if);
30917 + dwc_otg_save_dev_regs(core_if);
30918 +
30919 + /* Wait for 10 PHY clocks */
30920 + dwc_udelay(10);
30921 +
30922 + /* Program GPIO register while entering to xHib */
30923 + DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x1);
30924 +
30925 + pcgcctl.b.enbl_extnd_hiber = 1;
30926 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30927 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30928 +
30929 + pcgcctl.d32 = 0;
30930 + pcgcctl.b.extnd_hiber_pwrclmp = 1;
30931 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30932 +
30933 + pcgcctl.d32 = 0;
30934 + pcgcctl.b.extnd_hiber_switch = 1;
30935 + core_if->gr_backup->xhib_gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30936 + core_if->gr_backup->xhib_pcgcctl = DWC_READ_REG32(core_if->pcgcctl) | pcgcctl.d32;
30937 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30938 +
30939 + DWC_DEBUGPL(DBG_ANY, "Finished entering to extended hibernation\n");
30940 +
30941 + return 1;
30942 + }
30943 + }
30944 + } else {
30945 + if (core_if->op_state == A_PERIPHERAL) {
30946 + DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n");
30947 + /* Clear the a_peripheral flag, back to a_host. */
30948 + DWC_SPINUNLOCK(core_if->lock);
30949 + cil_pcd_stop(core_if);
30950 + cil_hcd_start(core_if);
30951 + DWC_SPINLOCK(core_if->lock);
30952 + core_if->op_state = A_HOST;
30953 + }
30954 + }
30955 +
30956 + /* Change to L2(suspend) state */
30957 + core_if->lx_state = DWC_OTG_L2;
30958 +
30959 + /* Clear interrupt */
30960 + gintsts.d32 = 0;
30961 + gintsts.b.usbsuspend = 1;
30962 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30963 +
30964 + return 1;
30965 +}
30966 +
30967 +static int32_t dwc_otg_handle_xhib_exit_intr(dwc_otg_core_if_t * core_if)
30968 +{
30969 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30970 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30971 + gahbcfg_data_t gahbcfg = {.d32 = 0 };
30972 +
30973 + dwc_udelay(10);
30974 +
30975 + /* Program GPIO register while entering to xHib */
30976 + DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x0);
30977 +
30978 + pcgcctl.d32 = core_if->gr_backup->xhib_pcgcctl;
30979 + pcgcctl.b.extnd_hiber_pwrclmp = 0;
30980 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
30981 + dwc_udelay(10);
30982 +
30983 + gpwrdn.d32 = core_if->gr_backup->xhib_gpwrdn;
30984 + gpwrdn.b.restore = 1;
30985 + DWC_WRITE_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32);
30986 + dwc_udelay(10);
30987 +
30988 + restore_lpm_i2c_regs(core_if);
30989 +
30990 + pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
30991 + pcgcctl.b.max_xcvrselect = 1;
30992 + pcgcctl.b.ess_reg_restored = 0;
30993 + pcgcctl.b.extnd_hiber_switch = 0;
30994 + pcgcctl.b.extnd_hiber_pwrclmp = 0;
30995 + pcgcctl.b.enbl_extnd_hiber = 1;
30996 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
30997 +
30998 + gahbcfg.d32 = core_if->gr_backup->gahbcfg_local;
30999 + gahbcfg.b.glblintrmsk = 1;
31000 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
31001 +
31002 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
31003 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0x1 << 16);
31004 +
31005 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
31006 + core_if->gr_backup->gusbcfg_local);
31007 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
31008 + core_if->dr_backup->dcfg);
31009 +
31010 + pcgcctl.d32 = 0;
31011 + pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
31012 + pcgcctl.b.max_xcvrselect = 1;
31013 + pcgcctl.d32 |= 0x608;
31014 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
31015 + dwc_udelay(10);
31016 +
31017 + pcgcctl.d32 = 0;
31018 + pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
31019 + pcgcctl.b.max_xcvrselect = 1;
31020 + pcgcctl.b.ess_reg_restored = 1;
31021 + pcgcctl.b.enbl_extnd_hiber = 1;
31022 + pcgcctl.b.rstpdwnmodule = 1;
31023 + pcgcctl.b.restoremode = 1;
31024 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
31025 +
31026 + DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
31027 +
31028 + return 1;
31029 +}
31030 +
31031 +#ifdef CONFIG_USB_DWC_OTG_LPM
31032 +/**
31033 + * This function hadles LPM transaction received interrupt.
31034 + */
31035 +static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if)
31036 +{
31037 + glpmcfg_data_t lpmcfg;
31038 + gintsts_data_t gintsts;
31039 +
31040 + if (!core_if->core_params->lpm_enable) {
31041 + DWC_PRINTF("Unexpected LPM interrupt\n");
31042 + }
31043 +
31044 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
31045 + DWC_PRINTF("LPM config register = 0x%08x\n", lpmcfg.d32);
31046 +
31047 + if (dwc_otg_is_host_mode(core_if)) {
31048 + cil_hcd_sleep(core_if);
31049 + } else {
31050 + lpmcfg.b.hird_thres |= (1 << 4);
31051 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
31052 + lpmcfg.d32);
31053 + }
31054 +
31055 + /* Examine prt_sleep_sts after TL1TokenTetry period max (10 us) */
31056 + dwc_udelay(10);
31057 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
31058 + if (lpmcfg.b.prt_sleep_sts) {
31059 + /* Save the current state */
31060 + core_if->lx_state = DWC_OTG_L1;
31061 + }
31062 +
31063 + /* Clear interrupt */
31064 + gintsts.d32 = 0;
31065 + gintsts.b.lpmtranrcvd = 1;
31066 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
31067 + return 1;
31068 +}
31069 +#endif /* CONFIG_USB_DWC_OTG_LPM */
31070 +
31071 +/**
31072 + * This function returns the Core Interrupt register.
31073 + */
31074 +static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if)
31075 +{
31076 + gahbcfg_data_t gahbcfg = {.d32 = 0 };
31077 + gintsts_data_t gintsts;
31078 + gintmsk_data_t gintmsk;
31079 + gintmsk_data_t gintmsk_common = {.d32 = 0 };
31080 + gintmsk_common.b.wkupintr = 1;
31081 + gintmsk_common.b.sessreqintr = 1;
31082 + gintmsk_common.b.conidstschng = 1;
31083 + gintmsk_common.b.otgintr = 1;
31084 + gintmsk_common.b.modemismatch = 1;
31085 + gintmsk_common.b.disconnect = 1;
31086 + gintmsk_common.b.usbsuspend = 1;
31087 +#ifdef CONFIG_USB_DWC_OTG_LPM
31088 + gintmsk_common.b.lpmtranrcvd = 1;
31089 +#endif
31090 + gintmsk_common.b.restoredone = 1;
31091 + /** @todo: The port interrupt occurs while in device
31092 + * mode. Added code to CIL to clear the interrupt for now!
31093 + */
31094 + gintmsk_common.b.portintr = 1;
31095 +
31096 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
31097 + gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
31098 + gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
31099 +
31100 +#ifdef DEBUG
31101 + /* if any common interrupts set */
31102 + if (gintsts.d32 & gintmsk_common.d32) {
31103 + DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n",
31104 + gintsts.d32, gintmsk.d32);
31105 + }
31106 +#endif
31107 + if (gahbcfg.b.glblintrmsk)
31108 + return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
31109 + else
31110 + return 0;
31111 +
31112 +}
31113 +
31114 +/* MACRO for clearing interupt bits in GPWRDN register */
31115 +#define CLEAR_GPWRDN_INTR(__core_if,__intr) \
31116 +do { \
31117 + gpwrdn_data_t gpwrdn = {.d32=0}; \
31118 + gpwrdn.b.__intr = 1; \
31119 + DWC_MODIFY_REG32(&__core_if->core_global_regs->gpwrdn, \
31120 + 0, gpwrdn.d32); \
31121 +} while (0)
31122 +
31123 +/**
31124 + * Common interrupt handler.
31125 + *
31126 + * The common interrupts are those that occur in both Host and Device mode.
31127 + * This handler handles the following interrupts:
31128 + * - Mode Mismatch Interrupt
31129 + * - Disconnect Interrupt
31130 + * - OTG Interrupt
31131 + * - Connector ID Status Change Interrupt
31132 + * - Session Request Interrupt.
31133 + * - Resume / Remote Wakeup Detected Interrupt.
31134 + * - LPM Transaction Received Interrupt
31135 + * - ADP Transaction Received Interrupt
31136 + *
31137 + */
31138 +int32_t dwc_otg_handle_common_intr(void *dev)
31139 +{
31140 + int retval = 0;
31141 + gintsts_data_t gintsts;
31142 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
31143 + dwc_otg_device_t *otg_dev = dev;
31144 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
31145 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
31146 + if (dwc_otg_is_device_mode(core_if))
31147 + core_if->frame_num = dwc_otg_get_frame_number(core_if);
31148 +
31149 + if (core_if->lock)
31150 + DWC_SPINLOCK(core_if->lock);
31151 +
31152 + if (core_if->power_down == 3 && core_if->xhib == 1) {
31153 + DWC_DEBUGPL(DBG_ANY, "Exiting from xHIB state\n");
31154 + retval |= dwc_otg_handle_xhib_exit_intr(core_if);
31155 + core_if->xhib = 2;
31156 + if (core_if->lock)
31157 + DWC_SPINUNLOCK(core_if->lock);
31158 +
31159 + return retval;
31160 + }
31161 +
31162 + if (core_if->hibernation_suspend <= 0) {
31163 + gintsts.d32 = dwc_otg_read_common_intr(core_if);
31164 +
31165 + if (gintsts.b.modemismatch) {
31166 + retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
31167 + }
31168 + if (gintsts.b.otgintr) {
31169 + retval |= dwc_otg_handle_otg_intr(core_if);
31170 + }
31171 + if (gintsts.b.conidstschng) {
31172 + retval |=
31173 + dwc_otg_handle_conn_id_status_change_intr(core_if);
31174 + }
31175 + if (gintsts.b.disconnect) {
31176 + retval |= dwc_otg_handle_disconnect_intr(core_if);
31177 + }
31178 + if (gintsts.b.sessreqintr) {
31179 + retval |= dwc_otg_handle_session_req_intr(core_if);
31180 + }
31181 + if (gintsts.b.wkupintr) {
31182 + retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
31183 + }
31184 + if (gintsts.b.usbsuspend) {
31185 + retval |= dwc_otg_handle_usb_suspend_intr(core_if);
31186 + }
31187 +#ifdef CONFIG_USB_DWC_OTG_LPM
31188 + if (gintsts.b.lpmtranrcvd) {
31189 + retval |= dwc_otg_handle_lpm_intr(core_if);
31190 + }
31191 +#endif
31192 + if (gintsts.b.restoredone) {
31193 + gintsts.d32 = 0;
31194 + if (core_if->power_down == 2)
31195 + core_if->hibernation_suspend = -1;
31196 + else if (core_if->power_down == 3 && core_if->xhib == 2) {
31197 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
31198 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
31199 + dctl_data_t dctl = {.d32 = 0 };
31200 +
31201 + DWC_WRITE_REG32(&core_if->core_global_regs->
31202 + gintsts, 0xFFFFFFFF);
31203 +
31204 + DWC_DEBUGPL(DBG_ANY,
31205 + "RESTORE DONE generated\n");
31206 +
31207 + gpwrdn.b.restore = 1;
31208 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
31209 + dwc_udelay(10);
31210 +
31211 + pcgcctl.b.rstpdwnmodule = 1;
31212 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
31213 +
31214 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, core_if->gr_backup->gusbcfg_local);
31215 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, core_if->dr_backup->dcfg);
31216 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, core_if->dr_backup->dctl);
31217 + dwc_udelay(50);
31218 +
31219 + dctl.b.pwronprgdone = 1;
31220 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
31221 + dwc_udelay(10);
31222 +
31223 + dwc_otg_restore_global_regs(core_if);
31224 + dwc_otg_restore_dev_regs(core_if, 0);
31225 +
31226 + dctl.d32 = 0;
31227 + dctl.b.pwronprgdone = 1;
31228 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
31229 + dwc_udelay(10);
31230 +
31231 + pcgcctl.d32 = 0;
31232 + pcgcctl.b.enbl_extnd_hiber = 1;
31233 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
31234 +
31235 + /* The core will be in ON STATE */
31236 + core_if->lx_state = DWC_OTG_L0;
31237 + core_if->xhib = 0;
31238 +
31239 + DWC_SPINUNLOCK(core_if->lock);
31240 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
31241 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
31242 + }
31243 + DWC_SPINLOCK(core_if->lock);
31244 +
31245 + }
31246 +
31247 + gintsts.b.restoredone = 1;
31248 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
31249 + DWC_PRINTF(" --Restore done interrupt received-- \n");
31250 + retval |= 1;
31251 + }
31252 + if (gintsts.b.portintr && dwc_otg_is_device_mode(core_if)) {
31253 + /* The port interrupt occurs while in device mode with HPRT0
31254 + * Port Enable/Disable.
31255 + */
31256 + gintsts.d32 = 0;
31257 + gintsts.b.portintr = 1;
31258 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
31259 + retval |= 1;
31260 +
31261 + }
31262 + } else {
31263 + DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32);
31264 +
31265 + if (gpwrdn.b.disconn_det && gpwrdn.b.disconn_det_msk) {
31266 + CLEAR_GPWRDN_INTR(core_if, disconn_det);
31267 + if (gpwrdn.b.linestate == 0) {
31268 + dwc_otg_handle_pwrdn_disconnect_intr(core_if);
31269 + } else {
31270 + DWC_PRINTF("Disconnect detected while linestate is not 0\n");
31271 + }
31272 +
31273 + retval |= 1;
31274 + }
31275 + if (gpwrdn.b.lnstschng && gpwrdn.b.lnstchng_msk) {
31276 + CLEAR_GPWRDN_INTR(core_if, lnstschng);
31277 + /* remote wakeup from hibernation */
31278 + if (gpwrdn.b.linestate == 2 || gpwrdn.b.linestate == 1) {
31279 + dwc_otg_handle_pwrdn_wakeup_detected_intr(core_if);
31280 + } else {
31281 + DWC_PRINTF("gpwrdn.linestate = %d\n", gpwrdn.b.linestate);
31282 + }
31283 + retval |= 1;
31284 + }
31285 + if (gpwrdn.b.rst_det && gpwrdn.b.rst_det_msk) {
31286 + CLEAR_GPWRDN_INTR(core_if, rst_det);
31287 + if (gpwrdn.b.linestate == 0) {
31288 + DWC_PRINTF("Reset detected\n");
31289 + retval |= dwc_otg_device_hibernation_restore(core_if, 0, 1);
31290 + }
31291 + }
31292 + if (gpwrdn.b.srp_det && gpwrdn.b.srp_det_msk) {
31293 + CLEAR_GPWRDN_INTR(core_if, srp_det);
31294 + dwc_otg_handle_pwrdn_srp_intr(core_if);
31295 + retval |= 1;
31296 + }
31297 + }
31298 + /* Handle ADP interrupt here */
31299 + if (gpwrdn.b.adp_int) {
31300 + DWC_PRINTF("ADP interrupt\n");
31301 + CLEAR_GPWRDN_INTR(core_if, adp_int);
31302 + dwc_otg_adp_handle_intr(core_if);
31303 + retval |= 1;
31304 + }
31305 + if (gpwrdn.b.sts_chngint && gpwrdn.b.sts_chngint_msk) {
31306 + DWC_PRINTF("STS CHNG interrupt asserted\n");
31307 + CLEAR_GPWRDN_INTR(core_if, sts_chngint);
31308 + dwc_otg_handle_pwrdn_stschng_intr(otg_dev);
31309 +
31310 + retval |= 1;
31311 + }
31312 + if (core_if->lock)
31313 + DWC_SPINUNLOCK(core_if->lock);
31314 +
31315 + return retval;
31316 +}
31317 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_core_if.h b/drivers/usb/host/dwc_otg/dwc_otg_core_if.h
31318 new file mode 100644
31319 index 0000000..4138fd1
31320 --- /dev/null
31321 +++ b/drivers/usb/host/dwc_otg/dwc_otg_core_if.h
31322 @@ -0,0 +1,705 @@
31323 +/* ==========================================================================
31324 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_core_if.h $
31325 + * $Revision: #13 $
31326 + * $Date: 2012/08/10 $
31327 + * $Change: 2047372 $
31328 + *
31329 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
31330 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
31331 + * otherwise expressly agreed to in writing between Synopsys and you.
31332 + *
31333 + * The Software IS NOT an item of Licensed Software or Licensed Product under
31334 + * any End User Software License Agreement or Agreement for Licensed Product
31335 + * with Synopsys or any supplement thereto. You are permitted to use and
31336 + * redistribute this Software in source and binary forms, with or without
31337 + * modification, provided that redistributions of source code must retain this
31338 + * notice. You may not view, use, disclose, copy or distribute this file or
31339 + * any information contained herein except pursuant to this license grant from
31340 + * Synopsys. If you do not agree with this notice, including the disclaimer
31341 + * below, then you are not authorized to use the Software.
31342 + *
31343 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
31344 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31345 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31346 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
31347 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31348 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31349 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31350 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31351 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31352 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31353 + * DAMAGE.
31354 + * ========================================================================== */
31355 +#if !defined(__DWC_CORE_IF_H__)
31356 +#define __DWC_CORE_IF_H__
31357 +
31358 +#include "dwc_os.h"
31359 +
31360 +/** @file
31361 + * This file defines DWC_OTG Core API
31362 + */
31363 +
31364 +struct dwc_otg_core_if;
31365 +typedef struct dwc_otg_core_if dwc_otg_core_if_t;
31366 +
31367 +/** Maximum number of Periodic FIFOs */
31368 +#define MAX_PERIO_FIFOS 15
31369 +/** Maximum number of Periodic FIFOs */
31370 +#define MAX_TX_FIFOS 15
31371 +
31372 +/** Maximum number of Endpoints/HostChannels */
31373 +#define MAX_EPS_CHANNELS 16
31374 +
31375 +extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * _reg_base_addr);
31376 +extern void dwc_otg_core_init(dwc_otg_core_if_t * _core_if);
31377 +extern void dwc_otg_cil_remove(dwc_otg_core_if_t * _core_if);
31378 +
31379 +extern void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * _core_if);
31380 +extern void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * _core_if);
31381 +
31382 +extern uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if);
31383 +extern uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if);
31384 +
31385 +extern uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if);
31386 +
31387 +/** This function should be called on every hardware interrupt. */
31388 +extern int32_t dwc_otg_handle_common_intr(void *otg_dev);
31389 +
31390 +/** @name OTG Core Parameters */
31391 +/** @{ */
31392 +
31393 +/**
31394 + * Specifies the OTG capabilities. The driver will automatically
31395 + * detect the value for this parameter if none is specified.
31396 + * 0 - HNP and SRP capable (default)
31397 + * 1 - SRP Only capable
31398 + * 2 - No HNP/SRP capable
31399 + */
31400 +extern int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val);
31401 +extern int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if);
31402 +#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0
31403 +#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1
31404 +#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
31405 +#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE
31406 +
31407 +extern int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val);
31408 +extern int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if);
31409 +#define dwc_param_opt_default 1
31410 +
31411 +/**
31412 + * Specifies whether to use slave or DMA mode for accessing the data
31413 + * FIFOs. The driver will automatically detect the value for this
31414 + * parameter if none is specified.
31415 + * 0 - Slave
31416 + * 1 - DMA (default, if available)
31417 + */
31418 +extern int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if,
31419 + int32_t val);
31420 +extern int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if);
31421 +#define dwc_param_dma_enable_default 1
31422 +
31423 +/**
31424 + * When DMA mode is enabled specifies whether to use
31425 + * address DMA or DMA Descritor mode for accessing the data
31426 + * FIFOs in device mode. The driver will automatically detect
31427 + * the value for this parameter if none is specified.
31428 + * 0 - address DMA
31429 + * 1 - DMA Descriptor(default, if available)
31430 + */
31431 +extern int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if,
31432 + int32_t val);
31433 +extern int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if);
31434 +//#define dwc_param_dma_desc_enable_default 1
31435 +#define dwc_param_dma_desc_enable_default 0 // Broadcom BCM2708
31436 +
31437 +/** The DMA Burst size (applicable only for External DMA
31438 + * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
31439 + */
31440 +extern int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if,
31441 + int32_t val);
31442 +extern int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if);
31443 +#define dwc_param_dma_burst_size_default 32
31444 +
31445 +/**
31446 + * Specifies the maximum speed of operation in host and device mode.
31447 + * The actual speed depends on the speed of the attached device and
31448 + * the value of phy_type. The actual speed depends on the speed of the
31449 + * attached device.
31450 + * 0 - High Speed (default)
31451 + * 1 - Full Speed
31452 + */
31453 +extern int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val);
31454 +extern int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if);
31455 +#define dwc_param_speed_default 0
31456 +#define DWC_SPEED_PARAM_HIGH 0
31457 +#define DWC_SPEED_PARAM_FULL 1
31458 +
31459 +/** Specifies whether low power mode is supported when attached
31460 + * to a Full Speed or Low Speed device in host mode.
31461 + * 0 - Don't support low power mode (default)
31462 + * 1 - Support low power mode
31463 + */
31464 +extern int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
31465 + core_if, int32_t val);
31466 +extern int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t
31467 + * core_if);
31468 +#define dwc_param_host_support_fs_ls_low_power_default 0
31469 +
31470 +/** Specifies the PHY clock rate in low power mode when connected to a
31471 + * Low Speed device in host mode. This parameter is applicable only if
31472 + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
31473 + * then defaults to 6 MHZ otherwise 48 MHZ.
31474 + *
31475 + * 0 - 48 MHz
31476 + * 1 - 6 MHz
31477 + */
31478 +extern int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
31479 + core_if, int32_t val);
31480 +extern int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
31481 + core_if);
31482 +#define dwc_param_host_ls_low_power_phy_clk_default 0
31483 +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
31484 +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
31485 +
31486 +/**
31487 + * 0 - Use cC FIFO size parameters
31488 + * 1 - Allow dynamic FIFO sizing (default)
31489 + */
31490 +extern int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
31491 + int32_t val);
31492 +extern int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t *
31493 + core_if);
31494 +#define dwc_param_enable_dynamic_fifo_default 1
31495 +
31496 +/** Total number of 4-byte words in the data FIFO memory. This
31497 + * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
31498 + * Tx FIFOs.
31499 + * 32 to 32768 (default 8192)
31500 + * Note: The total FIFO memory depth in the FPGA configuration is 8192.
31501 + */
31502 +extern int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if,
31503 + int32_t val);
31504 +extern int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if);
31505 +//#define dwc_param_data_fifo_size_default 8192
31506 +#define dwc_param_data_fifo_size_default 0xFF0 // Broadcom BCM2708
31507 +
31508 +/** Number of 4-byte words in the Rx FIFO in device mode when dynamic
31509 + * FIFO sizing is enabled.
31510 + * 16 to 32768 (default 1064)
31511 + */
31512 +extern int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if,
31513 + int32_t val);
31514 +extern int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if);
31515 +#define dwc_param_dev_rx_fifo_size_default 1064
31516 +
31517 +/** Number of 4-byte words in the non-periodic Tx FIFO in device mode
31518 + * when dynamic FIFO sizing is enabled.
31519 + * 16 to 32768 (default 1024)
31520 + */
31521 +extern int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
31522 + core_if, int32_t val);
31523 +extern int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
31524 + core_if);
31525 +#define dwc_param_dev_nperio_tx_fifo_size_default 1024
31526 +
31527 +/** Number of 4-byte words in each of the periodic Tx FIFOs in device
31528 + * mode when dynamic FIFO sizing is enabled.
31529 + * 4 to 768 (default 256)
31530 + */
31531 +extern int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
31532 + int32_t val, int fifo_num);
31533 +extern int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t *
31534 + core_if, int fifo_num);
31535 +#define dwc_param_dev_perio_tx_fifo_size_default 256
31536 +
31537 +/** Number of 4-byte words in the Rx FIFO in host mode when dynamic
31538 + * FIFO sizing is enabled.
31539 + * 16 to 32768 (default 1024)
31540 + */
31541 +extern int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
31542 + int32_t val);
31543 +extern int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if);
31544 +//#define dwc_param_host_rx_fifo_size_default 1024
31545 +#define dwc_param_host_rx_fifo_size_default 774 // Broadcom BCM2708
31546 +
31547 +/** Number of 4-byte words in the non-periodic Tx FIFO in host mode
31548 + * when Dynamic FIFO sizing is enabled in the core.
31549 + * 16 to 32768 (default 1024)
31550 + */
31551 +extern int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
31552 + core_if, int32_t val);
31553 +extern int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
31554 + core_if);
31555 +//#define dwc_param_host_nperio_tx_fifo_size_default 1024
31556 +#define dwc_param_host_nperio_tx_fifo_size_default 0x100 // Broadcom BCM2708
31557 +
31558 +/** Number of 4-byte words in the host periodic Tx FIFO when dynamic
31559 + * FIFO sizing is enabled.
31560 + * 16 to 32768 (default 1024)
31561 + */
31562 +extern int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
31563 + core_if, int32_t val);
31564 +extern int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
31565 + core_if);
31566 +//#define dwc_param_host_perio_tx_fifo_size_default 1024
31567 +#define dwc_param_host_perio_tx_fifo_size_default 0x200 // Broadcom BCM2708
31568 +
31569 +/** The maximum transfer size supported in bytes.
31570 + * 2047 to 65,535 (default 65,535)
31571 + */
31572 +extern int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
31573 + int32_t val);
31574 +extern int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if);
31575 +#define dwc_param_max_transfer_size_default 65535
31576 +
31577 +/** The maximum number of packets in a transfer.
31578 + * 15 to 511 (default 511)
31579 + */
31580 +extern int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if,
31581 + int32_t val);
31582 +extern int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if);
31583 +#define dwc_param_max_packet_count_default 511
31584 +
31585 +/** The number of host channel registers to use.
31586 + * 1 to 16 (default 12)
31587 + * Note: The FPGA configuration supports a maximum of 12 host channels.
31588 + */
31589 +extern int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if,
31590 + int32_t val);
31591 +extern int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if);
31592 +//#define dwc_param_host_channels_default 12
31593 +#define dwc_param_host_channels_default 8 // Broadcom BCM2708
31594 +
31595 +/** The number of endpoints in addition to EP0 available for device
31596 + * mode operations.
31597 + * 1 to 15 (default 6 IN and OUT)
31598 + * Note: The FPGA configuration supports a maximum of 6 IN and OUT
31599 + * endpoints in addition to EP0.
31600 + */
31601 +extern int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if,
31602 + int32_t val);
31603 +extern int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if);
31604 +#define dwc_param_dev_endpoints_default 6
31605 +
31606 +/**
31607 + * Specifies the type of PHY interface to use. By default, the driver
31608 + * will automatically detect the phy_type.
31609 + *
31610 + * 0 - Full Speed PHY
31611 + * 1 - UTMI+ (default)
31612 + * 2 - ULPI
31613 + */
31614 +extern int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val);
31615 +extern int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if);
31616 +#define DWC_PHY_TYPE_PARAM_FS 0
31617 +#define DWC_PHY_TYPE_PARAM_UTMI 1
31618 +#define DWC_PHY_TYPE_PARAM_ULPI 2
31619 +#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI
31620 +
31621 +/**
31622 + * Specifies the UTMI+ Data Width. This parameter is
31623 + * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
31624 + * PHY_TYPE, this parameter indicates the data width between
31625 + * the MAC and the ULPI Wrapper.) Also, this parameter is
31626 + * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
31627 + * to "8 and 16 bits", meaning that the core has been
31628 + * configured to work at either data path width.
31629 + *
31630 + * 8 or 16 bits (default 16)
31631 + */
31632 +extern int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if,
31633 + int32_t val);
31634 +extern int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if);
31635 +//#define dwc_param_phy_utmi_width_default 16
31636 +#define dwc_param_phy_utmi_width_default 8 // Broadcom BCM2708
31637 +
31638 +/**
31639 + * Specifies whether the ULPI operates at double or single
31640 + * data rate. This parameter is only applicable if PHY_TYPE is
31641 + * ULPI.
31642 + *
31643 + * 0 - single data rate ULPI interface with 8 bit wide data
31644 + * bus (default)
31645 + * 1 - double data rate ULPI interface with 4 bit wide data
31646 + * bus
31647 + */
31648 +extern int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if,
31649 + int32_t val);
31650 +extern int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if);
31651 +#define dwc_param_phy_ulpi_ddr_default 0
31652 +
31653 +/**
31654 + * Specifies whether to use the internal or external supply to
31655 + * drive the vbus with a ULPI phy.
31656 + */
31657 +extern int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
31658 + int32_t val);
31659 +extern int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if);
31660 +#define DWC_PHY_ULPI_INTERNAL_VBUS 0
31661 +#define DWC_PHY_ULPI_EXTERNAL_VBUS 1
31662 +#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS
31663 +
31664 +/**
31665 + * Specifies whether to use the I2Cinterface for full speed PHY. This
31666 + * parameter is only applicable if PHY_TYPE is FS.
31667 + * 0 - No (default)
31668 + * 1 - Yes
31669 + */
31670 +extern int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if,
31671 + int32_t val);
31672 +extern int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if);
31673 +#define dwc_param_i2c_enable_default 0
31674 +
31675 +extern int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if,
31676 + int32_t val);
31677 +extern int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if);
31678 +#define dwc_param_ulpi_fs_ls_default 0
31679 +
31680 +extern int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val);
31681 +extern int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if);
31682 +#define dwc_param_ts_dline_default 0
31683 +
31684 +/**
31685 + * Specifies whether dedicated transmit FIFOs are
31686 + * enabled for non periodic IN endpoints in device mode
31687 + * 0 - No
31688 + * 1 - Yes
31689 + */
31690 +extern int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
31691 + int32_t val);
31692 +extern int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t *
31693 + core_if);
31694 +#define dwc_param_en_multiple_tx_fifo_default 1
31695 +
31696 +/** Number of 4-byte words in each of the Tx FIFOs in device
31697 + * mode when dynamic FIFO sizing is enabled.
31698 + * 4 to 768 (default 256)
31699 + */
31700 +extern int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
31701 + int fifo_num, int32_t val);
31702 +extern int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
31703 + int fifo_num);
31704 +#define dwc_param_dev_tx_fifo_size_default 768
31705 +
31706 +/** Thresholding enable flag-
31707 + * bit 0 - enable non-ISO Tx thresholding
31708 + * bit 1 - enable ISO Tx thresholding
31709 + * bit 2 - enable Rx thresholding
31710 + */
31711 +extern int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val);
31712 +extern int32_t dwc_otg_get_thr_ctl(dwc_otg_core_if_t * core_if, int fifo_num);
31713 +#define dwc_param_thr_ctl_default 0
31714 +
31715 +/** Thresholding length for Tx
31716 + * FIFOs in 32 bit DWORDs
31717 + */
31718 +extern int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if,
31719 + int32_t val);
31720 +extern int32_t dwc_otg_get_tx_thr_length(dwc_otg_core_if_t * core_if);
31721 +#define dwc_param_tx_thr_length_default 64
31722 +
31723 +/** Thresholding length for Rx
31724 + * FIFOs in 32 bit DWORDs
31725 + */
31726 +extern int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if,
31727 + int32_t val);
31728 +extern int32_t dwc_otg_get_rx_thr_length(dwc_otg_core_if_t * core_if);
31729 +#define dwc_param_rx_thr_length_default 64
31730 +
31731 +/**
31732 + * Specifies whether LPM (Link Power Management) support is enabled
31733 + */
31734 +extern int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if,
31735 + int32_t val);
31736 +extern int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if);
31737 +#define dwc_param_lpm_enable_default 1
31738 +
31739 +/**
31740 + * Specifies whether PTI enhancement is enabled
31741 + */
31742 +extern int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if,
31743 + int32_t val);
31744 +extern int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if);
31745 +#define dwc_param_pti_enable_default 0
31746 +
31747 +/**
31748 + * Specifies whether MPI enhancement is enabled
31749 + */
31750 +extern int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if,
31751 + int32_t val);
31752 +extern int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if);
31753 +#define dwc_param_mpi_enable_default 0
31754 +
31755 +/**
31756 + * Specifies whether ADP capability is enabled
31757 + */
31758 +extern int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if,
31759 + int32_t val);
31760 +extern int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if);
31761 +#define dwc_param_adp_enable_default 0
31762 +
31763 +/**
31764 + * Specifies whether IC_USB capability is enabled
31765 + */
31766 +
31767 +extern int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if,
31768 + int32_t val);
31769 +extern int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if);
31770 +#define dwc_param_ic_usb_cap_default 0
31771 +
31772 +extern int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if,
31773 + int32_t val);
31774 +extern int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if);
31775 +#define dwc_param_ahb_thr_ratio_default 0
31776 +
31777 +extern int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if,
31778 + int32_t val);
31779 +extern int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if);
31780 +#define dwc_param_power_down_default 0
31781 +
31782 +extern int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if,
31783 + int32_t val);
31784 +extern int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if);
31785 +#define dwc_param_reload_ctl_default 0
31786 +
31787 +extern int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if,
31788 + int32_t val);
31789 +extern int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if);
31790 +#define dwc_param_dev_out_nak_default 0
31791 +
31792 +extern int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if,
31793 + int32_t val);
31794 +extern int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if);
31795 +#define dwc_param_cont_on_bna_default 0
31796 +
31797 +extern int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if,
31798 + int32_t val);
31799 +extern int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if);
31800 +#define dwc_param_ahb_single_default 0
31801 +
31802 +extern int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val);
31803 +extern int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if);
31804 +#define dwc_param_otg_ver_default 0
31805 +
31806 +/** @} */
31807 +
31808 +/** @name Access to registers and bit-fields */
31809 +
31810 +/**
31811 + * Dump core registers and SPRAM
31812 + */
31813 +extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * _core_if);
31814 +extern void dwc_otg_dump_spram(dwc_otg_core_if_t * _core_if);
31815 +extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t * _core_if);
31816 +extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t * _core_if);
31817 +
31818 +/**
31819 + * Get host negotiation status.
31820 + */
31821 +extern uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if);
31822 +
31823 +/**
31824 + * Get srp status
31825 + */
31826 +extern uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if);
31827 +
31828 +/**
31829 + * Set hnpreq bit in the GOTGCTL register.
31830 + */
31831 +extern void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val);
31832 +
31833 +/**
31834 + * Get Content of SNPSID register.
31835 + */
31836 +extern uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if);
31837 +
31838 +/**
31839 + * Get current mode.
31840 + * Returns 0 if in device mode, and 1 if in host mode.
31841 + */
31842 +extern uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if);
31843 +
31844 +/**
31845 + * Get value of hnpcapable field in the GUSBCFG register
31846 + */
31847 +extern uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if);
31848 +/**
31849 + * Set value of hnpcapable field in the GUSBCFG register
31850 + */
31851 +extern void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
31852 +
31853 +/**
31854 + * Get value of srpcapable field in the GUSBCFG register
31855 + */
31856 +extern uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if);
31857 +/**
31858 + * Set value of srpcapable field in the GUSBCFG register
31859 + */
31860 +extern void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
31861 +
31862 +/**
31863 + * Get value of devspeed field in the DCFG register
31864 + */
31865 +extern uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if);
31866 +/**
31867 + * Set value of devspeed field in the DCFG register
31868 + */
31869 +extern void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val);
31870 +
31871 +/**
31872 + * Get the value of busconnected field from the HPRT0 register
31873 + */
31874 +extern uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if);
31875 +
31876 +/**
31877 + * Gets the device enumeration Speed.
31878 + */
31879 +extern uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if);
31880 +
31881 +/**
31882 + * Get value of prtpwr field from the HPRT0 register
31883 + */
31884 +extern uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if);
31885 +
31886 +/**
31887 + * Get value of flag indicating core state - hibernated or not
31888 + */
31889 +extern uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if);
31890 +
31891 +/**
31892 + * Set value of prtpwr field from the HPRT0 register
31893 + */
31894 +extern void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val);
31895 +
31896 +/**
31897 + * Get value of prtsusp field from the HPRT0 regsiter
31898 + */
31899 +extern uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if);
31900 +/**
31901 + * Set value of prtpwr field from the HPRT0 register
31902 + */
31903 +extern void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val);
31904 +
31905 +/**
31906 + * Get value of ModeChTimEn field from the HCFG regsiter
31907 + */
31908 +extern uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if);
31909 +/**
31910 + * Set value of ModeChTimEn field from the HCFG regsiter
31911 + */
31912 +extern void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val);
31913 +
31914 +/**
31915 + * Get value of Fram Interval field from the HFIR regsiter
31916 + */
31917 +extern uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if);
31918 +/**
31919 + * Set value of Frame Interval field from the HFIR regsiter
31920 + */
31921 +extern void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val);
31922 +
31923 +/**
31924 + * Set value of prtres field from the HPRT0 register
31925 + *FIXME Remove?
31926 + */
31927 +extern void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val);
31928 +
31929 +/**
31930 + * Get value of rmtwkupsig bit in DCTL register
31931 + */
31932 +extern uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if);
31933 +
31934 +/**
31935 + * Get value of prt_sleep_sts field from the GLPMCFG register
31936 + */
31937 +extern uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if);
31938 +
31939 +/**
31940 + * Get value of rem_wkup_en field from the GLPMCFG register
31941 + */
31942 +extern uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if);
31943 +
31944 +/**
31945 + * Get value of appl_resp field from the GLPMCFG register
31946 + */
31947 +extern uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if);
31948 +/**
31949 + * Set value of appl_resp field from the GLPMCFG register
31950 + */
31951 +extern void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val);
31952 +
31953 +/**
31954 + * Get value of hsic_connect field from the GLPMCFG register
31955 + */
31956 +extern uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if);
31957 +/**
31958 + * Set value of hsic_connect field from the GLPMCFG register
31959 + */
31960 +extern void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val);
31961 +
31962 +/**
31963 + * Get value of inv_sel_hsic field from the GLPMCFG register.
31964 + */
31965 +extern uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if);
31966 +/**
31967 + * Set value of inv_sel_hsic field from the GLPMFG register.
31968 + */
31969 +extern void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val);
31970 +
31971 +/*
31972 + * Some functions for accessing registers
31973 + */
31974 +
31975 +/**
31976 + * GOTGCTL register
31977 + */
31978 +extern uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if);
31979 +extern void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val);
31980 +
31981 +/**
31982 + * GUSBCFG register
31983 + */
31984 +extern uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if);
31985 +extern void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val);
31986 +
31987 +/**
31988 + * GRXFSIZ register
31989 + */
31990 +extern uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if);
31991 +extern void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
31992 +
31993 +/**
31994 + * GNPTXFSIZ register
31995 + */
31996 +extern uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if);
31997 +extern void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
31998 +
31999 +extern uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if);
32000 +extern void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val);
32001 +
32002 +/**
32003 + * GGPIO register
32004 + */
32005 +extern uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if);
32006 +extern void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val);
32007 +
32008 +/**
32009 + * GUID register
32010 + */
32011 +extern uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if);
32012 +extern void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val);
32013 +
32014 +/**
32015 + * HPRT0 register
32016 + */
32017 +extern uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if);
32018 +extern void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val);
32019 +
32020 +/**
32021 + * GHPTXFSIZE
32022 + */
32023 +extern uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if);
32024 +
32025 +/** @} */
32026 +
32027 +#endif /* __DWC_CORE_IF_H__ */
32028 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_dbg.h b/drivers/usb/host/dwc_otg/dwc_otg_dbg.h
32029 new file mode 100644
32030 index 0000000..8900318
32031 --- /dev/null
32032 +++ b/drivers/usb/host/dwc_otg/dwc_otg_dbg.h
32033 @@ -0,0 +1,116 @@
32034 +/* ==========================================================================
32035 + *
32036 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
32037 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
32038 + * otherwise expressly agreed to in writing between Synopsys and you.
32039 + *
32040 + * The Software IS NOT an item of Licensed Software or Licensed Product under
32041 + * any End User Software License Agreement or Agreement for Licensed Product
32042 + * with Synopsys or any supplement thereto. You are permitted to use and
32043 + * redistribute this Software in source and binary forms, with or without
32044 + * modification, provided that redistributions of source code must retain this
32045 + * notice. You may not view, use, disclose, copy or distribute this file or
32046 + * any information contained herein except pursuant to this license grant from
32047 + * Synopsys. If you do not agree with this notice, including the disclaimer
32048 + * below, then you are not authorized to use the Software.
32049 + *
32050 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
32051 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32052 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32053 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
32054 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32055 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32056 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32057 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32058 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32059 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32060 + * DAMAGE.
32061 + * ========================================================================== */
32062 +
32063 +#ifndef __DWC_OTG_DBG_H__
32064 +#define __DWC_OTG_DBG_H__
32065 +
32066 +/** @file
32067 + * This file defines debug levels.
32068 + * Debugging support vanishes in non-debug builds.
32069 + */
32070 +
32071 +/**
32072 + * The Debug Level bit-mask variable.
32073 + */
32074 +extern uint32_t g_dbg_lvl;
32075 +/**
32076 + * Set the Debug Level variable.
32077 + */
32078 +static inline uint32_t SET_DEBUG_LEVEL(const uint32_t new)
32079 +{
32080 + uint32_t old = g_dbg_lvl;
32081 + g_dbg_lvl = new;
32082 + return old;
32083 +}
32084 +
32085 +/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */
32086 +#define DBG_CIL (0x2)
32087 +/** When debug level has the DBG_CILV bit set, display CIL Verbose debug
32088 + * messages */
32089 +#define DBG_CILV (0x20)
32090 +/** When debug level has the DBG_PCD bit set, display PCD (Device) debug
32091 + * messages */
32092 +#define DBG_PCD (0x4)
32093 +/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug
32094 + * messages */
32095 +#define DBG_PCDV (0x40)
32096 +/** When debug level has the DBG_HCD bit set, display Host debug messages */
32097 +#define DBG_HCD (0x8)
32098 +/** When debug level has the DBG_HCDV bit set, display Verbose Host debug
32099 + * messages */
32100 +#define DBG_HCDV (0x80)
32101 +/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host
32102 + * mode. */
32103 +#define DBG_HCD_URB (0x800)
32104 +/** When debug level has the DBG_HCDI bit set, display host interrupt
32105 + * messages. */
32106 +#define DBG_HCDI (0x1000)
32107 +
32108 +/** When debug level has any bit set, display debug messages */
32109 +#define DBG_ANY (0xFF)
32110 +
32111 +/** All debug messages off */
32112 +#define DBG_OFF 0
32113 +
32114 +/** Prefix string for DWC_DEBUG print macros. */
32115 +#define USB_DWC "DWC_otg: "
32116 +
32117 +/**
32118 + * Print a debug message when the Global debug level variable contains
32119 + * the bit defined in <code>lvl</code>.
32120 + *
32121 + * @param[in] lvl - Debug level, use one of the DBG_ constants above.
32122 + * @param[in] x - like printf
32123 + *
32124 + * Example:<p>
32125 + * <code>
32126 + * DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr);
32127 + * </code>
32128 + * <br>
32129 + * results in:<br>
32130 + * <code>
32131 + * usb-DWC_otg: dwc_otg_cil_init(ca867000)
32132 + * </code>
32133 + */
32134 +#ifdef DEBUG
32135 +
32136 +# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)__DWC_DEBUG(USB_DWC x ); }while(0)
32137 +# define DWC_DEBUGP(x...) DWC_DEBUGPL(DBG_ANY, x )
32138 +
32139 +# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl)
32140 +
32141 +#else
32142 +
32143 +# define DWC_DEBUGPL(lvl, x...) do{}while(0)
32144 +# define DWC_DEBUGP(x...)
32145 +
32146 +# define CHK_DEBUG_LEVEL(level) (0)
32147 +
32148 +#endif /*DEBUG*/
32149 +#endif
32150 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
32151 new file mode 100644
32152 index 0000000..ac2c846
32153 --- /dev/null
32154 +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
32155 @@ -0,0 +1,1700 @@
32156 +/* ==========================================================================
32157 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.c $
32158 + * $Revision: #92 $
32159 + * $Date: 2012/08/10 $
32160 + * $Change: 2047372 $
32161 + *
32162 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
32163 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
32164 + * otherwise expressly agreed to in writing between Synopsys and you.
32165 + *
32166 + * The Software IS NOT an item of Licensed Software or Licensed Product under
32167 + * any End User Software License Agreement or Agreement for Licensed Product
32168 + * with Synopsys or any supplement thereto. You are permitted to use and
32169 + * redistribute this Software in source and binary forms, with or without
32170 + * modification, provided that redistributions of source code must retain this
32171 + * notice. You may not view, use, disclose, copy or distribute this file or
32172 + * any information contained herein except pursuant to this license grant from
32173 + * Synopsys. If you do not agree with this notice, including the disclaimer
32174 + * below, then you are not authorized to use the Software.
32175 + *
32176 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
32177 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32178 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32179 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
32180 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32181 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32182 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32183 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32184 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32185 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32186 + * DAMAGE.
32187 + * ========================================================================== */
32188 +
32189 +/** @file
32190 + * The dwc_otg_driver module provides the initialization and cleanup entry
32191 + * points for the DWC_otg driver. This module will be dynamically installed
32192 + * after Linux is booted using the insmod command. When the module is
32193 + * installed, the dwc_otg_driver_init function is called. When the module is
32194 + * removed (using rmmod), the dwc_otg_driver_cleanup function is called.
32195 + *
32196 + * This module also defines a data structure for the dwc_otg_driver, which is
32197 + * used in conjunction with the standard ARM lm_device structure. These
32198 + * structures allow the OTG driver to comply with the standard Linux driver
32199 + * model in which devices and drivers are registered with a bus driver. This
32200 + * has the benefit that Linux can expose attributes of the driver and device
32201 + * in its special sysfs file system. Users can then read or write files in
32202 + * this file system to perform diagnostics on the driver components or the
32203 + * device.
32204 + */
32205 +
32206 +#include "dwc_otg_os_dep.h"
32207 +#include "dwc_os.h"
32208 +#include "dwc_otg_dbg.h"
32209 +#include "dwc_otg_driver.h"
32210 +#include "dwc_otg_attr.h"
32211 +#include "dwc_otg_core_if.h"
32212 +#include "dwc_otg_pcd_if.h"
32213 +#include "dwc_otg_hcd_if.h"
32214 +
32215 +#define DWC_DRIVER_VERSION "3.00a 10-AUG-2012"
32216 +#define DWC_DRIVER_DESC "HS OTG USB Controller driver"
32217 +
32218 +bool microframe_schedule=true;
32219 +
32220 +static const char dwc_driver_name[] = "dwc_otg";
32221 +
32222 +extern int pcd_init(
32223 +#ifdef LM_INTERFACE
32224 + struct lm_device *_dev
32225 +#elif defined(PCI_INTERFACE)
32226 + struct pci_dev *_dev
32227 +#elif defined(PLATFORM_INTERFACE)
32228 + struct platform_device *dev
32229 +#endif
32230 + );
32231 +extern int hcd_init(
32232 +#ifdef LM_INTERFACE
32233 + struct lm_device *_dev
32234 +#elif defined(PCI_INTERFACE)
32235 + struct pci_dev *_dev
32236 +#elif defined(PLATFORM_INTERFACE)
32237 + struct platform_device *dev
32238 +#endif
32239 + );
32240 +
32241 +extern int pcd_remove(
32242 +#ifdef LM_INTERFACE
32243 + struct lm_device *_dev
32244 +#elif defined(PCI_INTERFACE)
32245 + struct pci_dev *_dev
32246 +#elif defined(PLATFORM_INTERFACE)
32247 + struct platform_device *_dev
32248 +#endif
32249 + );
32250 +
32251 +extern void hcd_remove(
32252 +#ifdef LM_INTERFACE
32253 + struct lm_device *_dev
32254 +#elif defined(PCI_INTERFACE)
32255 + struct pci_dev *_dev
32256 +#elif defined(PLATFORM_INTERFACE)
32257 + struct platform_device *_dev
32258 +#endif
32259 + );
32260 +
32261 +extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
32262 +
32263 +/*-------------------------------------------------------------------------*/
32264 +/* Encapsulate the module parameter settings */
32265 +
32266 +struct dwc_otg_driver_module_params {
32267 + int32_t opt;
32268 + int32_t otg_cap;
32269 + int32_t dma_enable;
32270 + int32_t dma_desc_enable;
32271 + int32_t dma_burst_size;
32272 + int32_t speed;
32273 + int32_t host_support_fs_ls_low_power;
32274 + int32_t host_ls_low_power_phy_clk;
32275 + int32_t enable_dynamic_fifo;
32276 + int32_t data_fifo_size;
32277 + int32_t dev_rx_fifo_size;
32278 + int32_t dev_nperio_tx_fifo_size;
32279 + uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
32280 + int32_t host_rx_fifo_size;
32281 + int32_t host_nperio_tx_fifo_size;
32282 + int32_t host_perio_tx_fifo_size;
32283 + int32_t max_transfer_size;
32284 + int32_t max_packet_count;
32285 + int32_t host_channels;
32286 + int32_t dev_endpoints;
32287 + int32_t phy_type;
32288 + int32_t phy_utmi_width;
32289 + int32_t phy_ulpi_ddr;
32290 + int32_t phy_ulpi_ext_vbus;
32291 + int32_t i2c_enable;
32292 + int32_t ulpi_fs_ls;
32293 + int32_t ts_dline;
32294 + int32_t en_multiple_tx_fifo;
32295 + uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
32296 + uint32_t thr_ctl;
32297 + uint32_t tx_thr_length;
32298 + uint32_t rx_thr_length;
32299 + int32_t pti_enable;
32300 + int32_t mpi_enable;
32301 + int32_t lpm_enable;
32302 + int32_t ic_usb_cap;
32303 + int32_t ahb_thr_ratio;
32304 + int32_t power_down;
32305 + int32_t reload_ctl;
32306 + int32_t dev_out_nak;
32307 + int32_t cont_on_bna;
32308 + int32_t ahb_single;
32309 + int32_t otg_ver;
32310 + int32_t adp_enable;
32311 +};
32312 +
32313 +static struct dwc_otg_driver_module_params dwc_otg_module_params = {
32314 + .opt = -1,
32315 + .otg_cap = -1,
32316 + .dma_enable = -1,
32317 + .dma_desc_enable = -1,
32318 + .dma_burst_size = -1,
32319 + .speed = -1,
32320 + .host_support_fs_ls_low_power = -1,
32321 + .host_ls_low_power_phy_clk = -1,
32322 + .enable_dynamic_fifo = -1,
32323 + .data_fifo_size = -1,
32324 + .dev_rx_fifo_size = -1,
32325 + .dev_nperio_tx_fifo_size = -1,
32326 + .dev_perio_tx_fifo_size = {
32327 + /* dev_perio_tx_fifo_size_1 */
32328 + -1,
32329 + -1,
32330 + -1,
32331 + -1,
32332 + -1,
32333 + -1,
32334 + -1,
32335 + -1,
32336 + -1,
32337 + -1,
32338 + -1,
32339 + -1,
32340 + -1,
32341 + -1,
32342 + -1
32343 + /* 15 */
32344 + },
32345 + .host_rx_fifo_size = -1,
32346 + .host_nperio_tx_fifo_size = -1,
32347 + .host_perio_tx_fifo_size = -1,
32348 + .max_transfer_size = -1,
32349 + .max_packet_count = -1,
32350 + .host_channels = -1,
32351 + .dev_endpoints = -1,
32352 + .phy_type = -1,
32353 + .phy_utmi_width = -1,
32354 + .phy_ulpi_ddr = -1,
32355 + .phy_ulpi_ext_vbus = -1,
32356 + .i2c_enable = -1,
32357 + .ulpi_fs_ls = -1,
32358 + .ts_dline = -1,
32359 + .en_multiple_tx_fifo = -1,
32360 + .dev_tx_fifo_size = {
32361 + /* dev_tx_fifo_size */
32362 + -1,
32363 + -1,
32364 + -1,
32365 + -1,
32366 + -1,
32367 + -1,
32368 + -1,
32369 + -1,
32370 + -1,
32371 + -1,
32372 + -1,
32373 + -1,
32374 + -1,
32375 + -1,
32376 + -1
32377 + /* 15 */
32378 + },
32379 + .thr_ctl = -1,
32380 + .tx_thr_length = -1,
32381 + .rx_thr_length = -1,
32382 + .pti_enable = -1,
32383 + .mpi_enable = -1,
32384 + .lpm_enable = 0,
32385 + .ic_usb_cap = -1,
32386 + .ahb_thr_ratio = -1,
32387 + .power_down = -1,
32388 + .reload_ctl = -1,
32389 + .dev_out_nak = -1,
32390 + .cont_on_bna = -1,
32391 + .ahb_single = -1,
32392 + .otg_ver = -1,
32393 + .adp_enable = -1,
32394 +};
32395 +
32396 +/**
32397 + * This function shows the Driver Version.
32398 + */
32399 +static ssize_t version_show(struct device_driver *dev, char *buf)
32400 +{
32401 + return snprintf(buf, sizeof(DWC_DRIVER_VERSION) + 2, "%s\n",
32402 + DWC_DRIVER_VERSION);
32403 +}
32404 +
32405 +static DRIVER_ATTR(version, S_IRUGO, version_show, NULL);
32406 +
32407 +/**
32408 + * Global Debug Level Mask.
32409 + */
32410 +uint32_t g_dbg_lvl = 0; /* OFF */
32411 +
32412 +/**
32413 + * This function shows the driver Debug Level.
32414 + */
32415 +static ssize_t dbg_level_show(struct device_driver *drv, char *buf)
32416 +{
32417 + return sprintf(buf, "0x%0x\n", g_dbg_lvl);
32418 +}
32419 +
32420 +/**
32421 + * This function stores the driver Debug Level.
32422 + */
32423 +static ssize_t dbg_level_store(struct device_driver *drv, const char *buf,
32424 + size_t count)
32425 +{
32426 + g_dbg_lvl = simple_strtoul(buf, NULL, 16);
32427 + return count;
32428 +}
32429 +
32430 +static DRIVER_ATTR(debuglevel, S_IRUGO | S_IWUSR, dbg_level_show,
32431 + dbg_level_store);
32432 +
32433 +/**
32434 + * This function is called during module intialization
32435 + * to pass module parameters to the DWC_OTG CORE.
32436 + */
32437 +static int set_parameters(dwc_otg_core_if_t * core_if)
32438 +{
32439 + int retval = 0;
32440 + int i;
32441 +
32442 + if (dwc_otg_module_params.otg_cap != -1) {
32443 + retval +=
32444 + dwc_otg_set_param_otg_cap(core_if,
32445 + dwc_otg_module_params.otg_cap);
32446 + }
32447 + if (dwc_otg_module_params.dma_enable != -1) {
32448 + retval +=
32449 + dwc_otg_set_param_dma_enable(core_if,
32450 + dwc_otg_module_params.
32451 + dma_enable);
32452 + }
32453 + if (dwc_otg_module_params.dma_desc_enable != -1) {
32454 + retval +=
32455 + dwc_otg_set_param_dma_desc_enable(core_if,
32456 + dwc_otg_module_params.
32457 + dma_desc_enable);
32458 + }
32459 + if (dwc_otg_module_params.opt != -1) {
32460 + retval +=
32461 + dwc_otg_set_param_opt(core_if, dwc_otg_module_params.opt);
32462 + }
32463 + if (dwc_otg_module_params.dma_burst_size != -1) {
32464 + retval +=
32465 + dwc_otg_set_param_dma_burst_size(core_if,
32466 + dwc_otg_module_params.
32467 + dma_burst_size);
32468 + }
32469 + if (dwc_otg_module_params.host_support_fs_ls_low_power != -1) {
32470 + retval +=
32471 + dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
32472 + dwc_otg_module_params.
32473 + host_support_fs_ls_low_power);
32474 + }
32475 + if (dwc_otg_module_params.enable_dynamic_fifo != -1) {
32476 + retval +=
32477 + dwc_otg_set_param_enable_dynamic_fifo(core_if,
32478 + dwc_otg_module_params.
32479 + enable_dynamic_fifo);
32480 + }
32481 + if (dwc_otg_module_params.data_fifo_size != -1) {
32482 + retval +=
32483 + dwc_otg_set_param_data_fifo_size(core_if,
32484 + dwc_otg_module_params.
32485 + data_fifo_size);
32486 + }
32487 + if (dwc_otg_module_params.dev_rx_fifo_size != -1) {
32488 + retval +=
32489 + dwc_otg_set_param_dev_rx_fifo_size(core_if,
32490 + dwc_otg_module_params.
32491 + dev_rx_fifo_size);
32492 + }
32493 + if (dwc_otg_module_params.dev_nperio_tx_fifo_size != -1) {
32494 + retval +=
32495 + dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
32496 + dwc_otg_module_params.
32497 + dev_nperio_tx_fifo_size);
32498 + }
32499 + if (dwc_otg_module_params.host_rx_fifo_size != -1) {
32500 + retval +=
32501 + dwc_otg_set_param_host_rx_fifo_size(core_if,
32502 + dwc_otg_module_params.host_rx_fifo_size);
32503 + }
32504 + if (dwc_otg_module_params.host_nperio_tx_fifo_size != -1) {
32505 + retval +=
32506 + dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
32507 + dwc_otg_module_params.
32508 + host_nperio_tx_fifo_size);
32509 + }
32510 + if (dwc_otg_module_params.host_perio_tx_fifo_size != -1) {
32511 + retval +=
32512 + dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
32513 + dwc_otg_module_params.
32514 + host_perio_tx_fifo_size);
32515 + }
32516 + if (dwc_otg_module_params.max_transfer_size != -1) {
32517 + retval +=
32518 + dwc_otg_set_param_max_transfer_size(core_if,
32519 + dwc_otg_module_params.
32520 + max_transfer_size);
32521 + }
32522 + if (dwc_otg_module_params.max_packet_count != -1) {
32523 + retval +=
32524 + dwc_otg_set_param_max_packet_count(core_if,
32525 + dwc_otg_module_params.
32526 + max_packet_count);
32527 + }
32528 + if (dwc_otg_module_params.host_channels != -1) {
32529 + retval +=
32530 + dwc_otg_set_param_host_channels(core_if,
32531 + dwc_otg_module_params.
32532 + host_channels);
32533 + }
32534 + if (dwc_otg_module_params.dev_endpoints != -1) {
32535 + retval +=
32536 + dwc_otg_set_param_dev_endpoints(core_if,
32537 + dwc_otg_module_params.
32538 + dev_endpoints);
32539 + }
32540 + if (dwc_otg_module_params.phy_type != -1) {
32541 + retval +=
32542 + dwc_otg_set_param_phy_type(core_if,
32543 + dwc_otg_module_params.phy_type);
32544 + }
32545 + if (dwc_otg_module_params.speed != -1) {
32546 + retval +=
32547 + dwc_otg_set_param_speed(core_if,
32548 + dwc_otg_module_params.speed);
32549 + }
32550 + if (dwc_otg_module_params.host_ls_low_power_phy_clk != -1) {
32551 + retval +=
32552 + dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
32553 + dwc_otg_module_params.
32554 + host_ls_low_power_phy_clk);
32555 + }
32556 + if (dwc_otg_module_params.phy_ulpi_ddr != -1) {
32557 + retval +=
32558 + dwc_otg_set_param_phy_ulpi_ddr(core_if,
32559 + dwc_otg_module_params.
32560 + phy_ulpi_ddr);
32561 + }
32562 + if (dwc_otg_module_params.phy_ulpi_ext_vbus != -1) {
32563 + retval +=
32564 + dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
32565 + dwc_otg_module_params.
32566 + phy_ulpi_ext_vbus);
32567 + }
32568 + if (dwc_otg_module_params.phy_utmi_width != -1) {
32569 + retval +=
32570 + dwc_otg_set_param_phy_utmi_width(core_if,
32571 + dwc_otg_module_params.
32572 + phy_utmi_width);
32573 + }
32574 + if (dwc_otg_module_params.ulpi_fs_ls != -1) {
32575 + retval +=
32576 + dwc_otg_set_param_ulpi_fs_ls(core_if,
32577 + dwc_otg_module_params.ulpi_fs_ls);
32578 + }
32579 + if (dwc_otg_module_params.ts_dline != -1) {
32580 + retval +=
32581 + dwc_otg_set_param_ts_dline(core_if,
32582 + dwc_otg_module_params.ts_dline);
32583 + }
32584 + if (dwc_otg_module_params.i2c_enable != -1) {
32585 + retval +=
32586 + dwc_otg_set_param_i2c_enable(core_if,
32587 + dwc_otg_module_params.
32588 + i2c_enable);
32589 + }
32590 + if (dwc_otg_module_params.en_multiple_tx_fifo != -1) {
32591 + retval +=
32592 + dwc_otg_set_param_en_multiple_tx_fifo(core_if,
32593 + dwc_otg_module_params.
32594 + en_multiple_tx_fifo);
32595 + }
32596 + for (i = 0; i < 15; i++) {
32597 + if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) {
32598 + retval +=
32599 + dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
32600 + dwc_otg_module_params.
32601 + dev_perio_tx_fifo_size
32602 + [i], i);
32603 + }
32604 + }
32605 +
32606 + for (i = 0; i < 15; i++) {
32607 + if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) {
32608 + retval += dwc_otg_set_param_dev_tx_fifo_size(core_if,
32609 + dwc_otg_module_params.
32610 + dev_tx_fifo_size
32611 + [i], i);
32612 + }
32613 + }
32614 + if (dwc_otg_module_params.thr_ctl != -1) {
32615 + retval +=
32616 + dwc_otg_set_param_thr_ctl(core_if,
32617 + dwc_otg_module_params.thr_ctl);
32618 + }
32619 + if (dwc_otg_module_params.mpi_enable != -1) {
32620 + retval +=
32621 + dwc_otg_set_param_mpi_enable(core_if,
32622 + dwc_otg_module_params.
32623 + mpi_enable);
32624 + }
32625 + if (dwc_otg_module_params.pti_enable != -1) {
32626 + retval +=
32627 + dwc_otg_set_param_pti_enable(core_if,
32628 + dwc_otg_module_params.
32629 + pti_enable);
32630 + }
32631 + if (dwc_otg_module_params.lpm_enable != -1) {
32632 + retval +=
32633 + dwc_otg_set_param_lpm_enable(core_if,
32634 + dwc_otg_module_params.
32635 + lpm_enable);
32636 + }
32637 + if (dwc_otg_module_params.ic_usb_cap != -1) {
32638 + retval +=
32639 + dwc_otg_set_param_ic_usb_cap(core_if,
32640 + dwc_otg_module_params.
32641 + ic_usb_cap);
32642 + }
32643 + if (dwc_otg_module_params.tx_thr_length != -1) {
32644 + retval +=
32645 + dwc_otg_set_param_tx_thr_length(core_if,
32646 + dwc_otg_module_params.tx_thr_length);
32647 + }
32648 + if (dwc_otg_module_params.rx_thr_length != -1) {
32649 + retval +=
32650 + dwc_otg_set_param_rx_thr_length(core_if,
32651 + dwc_otg_module_params.
32652 + rx_thr_length);
32653 + }
32654 + if (dwc_otg_module_params.ahb_thr_ratio != -1) {
32655 + retval +=
32656 + dwc_otg_set_param_ahb_thr_ratio(core_if,
32657 + dwc_otg_module_params.ahb_thr_ratio);
32658 + }
32659 + if (dwc_otg_module_params.power_down != -1) {
32660 + retval +=
32661 + dwc_otg_set_param_power_down(core_if,
32662 + dwc_otg_module_params.power_down);
32663 + }
32664 + if (dwc_otg_module_params.reload_ctl != -1) {
32665 + retval +=
32666 + dwc_otg_set_param_reload_ctl(core_if,
32667 + dwc_otg_module_params.reload_ctl);
32668 + }
32669 +
32670 + if (dwc_otg_module_params.dev_out_nak != -1) {
32671 + retval +=
32672 + dwc_otg_set_param_dev_out_nak(core_if,
32673 + dwc_otg_module_params.dev_out_nak);
32674 + }
32675 +
32676 + if (dwc_otg_module_params.cont_on_bna != -1) {
32677 + retval +=
32678 + dwc_otg_set_param_cont_on_bna(core_if,
32679 + dwc_otg_module_params.cont_on_bna);
32680 + }
32681 +
32682 + if (dwc_otg_module_params.ahb_single != -1) {
32683 + retval +=
32684 + dwc_otg_set_param_ahb_single(core_if,
32685 + dwc_otg_module_params.ahb_single);
32686 + }
32687 +
32688 + if (dwc_otg_module_params.otg_ver != -1) {
32689 + retval +=
32690 + dwc_otg_set_param_otg_ver(core_if,
32691 + dwc_otg_module_params.otg_ver);
32692 + }
32693 + if (dwc_otg_module_params.adp_enable != -1) {
32694 + retval +=
32695 + dwc_otg_set_param_adp_enable(core_if,
32696 + dwc_otg_module_params.
32697 + adp_enable);
32698 + }
32699 + return retval;
32700 +}
32701 +
32702 +/**
32703 + * This function is the top level interrupt handler for the Common
32704 + * (Device and host modes) interrupts.
32705 + */
32706 +static irqreturn_t dwc_otg_common_irq(int irq, void *dev)
32707 +{
32708 + int32_t retval = IRQ_NONE;
32709 +
32710 + retval = dwc_otg_handle_common_intr(dev);
32711 + if (retval != 0) {
32712 + S3C2410X_CLEAR_EINTPEND();
32713 + }
32714 + return IRQ_RETVAL(retval);
32715 +}
32716 +
32717 +/**
32718 + * This function is called when a lm_device is unregistered with the
32719 + * dwc_otg_driver. This happens, for example, when the rmmod command is
32720 + * executed. The device may or may not be electrically present. If it is
32721 + * present, the driver stops device processing. Any resources used on behalf
32722 + * of this device are freed.
32723 + *
32724 + * @param _dev
32725 + */
32726 +#ifdef LM_INTERFACE
32727 +#define REM_RETVAL(n)
32728 +static void dwc_otg_driver_remove( struct lm_device *_dev )
32729 +{ dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
32730 +#elif defined(PCI_INTERFACE)
32731 +#define REM_RETVAL(n)
32732 +static void dwc_otg_driver_remove( struct pci_dev *_dev )
32733 +{ dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
32734 +#elif defined(PLATFORM_INTERFACE)
32735 +#define REM_RETVAL(n) n
32736 +static int dwc_otg_driver_remove( struct platform_device *_dev )
32737 +{ dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
32738 +#endif
32739 +
32740 + DWC_DEBUGPL(DBG_ANY, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev);
32741 +
32742 + if (!otg_dev) {
32743 + /* Memory allocation for the dwc_otg_device failed. */
32744 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
32745 + return REM_RETVAL(-ENOMEM);
32746 + }
32747 +#ifndef DWC_DEVICE_ONLY
32748 + if (otg_dev->hcd) {
32749 + hcd_remove(_dev);
32750 + } else {
32751 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
32752 + return REM_RETVAL(-EINVAL);
32753 + }
32754 +#endif
32755 +
32756 +#ifndef DWC_HOST_ONLY
32757 + if (otg_dev->pcd) {
32758 + pcd_remove(_dev);
32759 + } else {
32760 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->pcd NULL!\n", __func__);
32761 + return REM_RETVAL(-EINVAL);
32762 + }
32763 +#endif
32764 + /*
32765 + * Free the IRQ
32766 + */
32767 + if (otg_dev->common_irq_installed) {
32768 +#ifdef PLATFORM_INTERFACE
32769 + free_irq(platform_get_irq(_dev, 0), otg_dev);
32770 +#else
32771 + free_irq(_dev->irq, otg_dev);
32772 +#endif
32773 + } else {
32774 + DWC_DEBUGPL(DBG_ANY, "%s: There is no installed irq!\n", __func__);
32775 + return REM_RETVAL(-ENXIO);
32776 + }
32777 +
32778 + if (otg_dev->core_if) {
32779 + dwc_otg_cil_remove(otg_dev->core_if);
32780 + } else {
32781 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->core_if NULL!\n", __func__);
32782 + return REM_RETVAL(-ENXIO);
32783 + }
32784 +
32785 + /*
32786 + * Remove the device attributes
32787 + */
32788 + dwc_otg_attr_remove(_dev);
32789 +
32790 + /*
32791 + * Return the memory.
32792 + */
32793 + if (otg_dev->os_dep.base) {
32794 + iounmap(otg_dev->os_dep.base);
32795 + }
32796 + DWC_FREE(otg_dev);
32797 +
32798 + /*
32799 + * Clear the drvdata pointer.
32800 + */
32801 +#ifdef LM_INTERFACE
32802 + lm_set_drvdata(_dev, 0);
32803 +#elif defined(PCI_INTERFACE)
32804 + release_mem_region(otg_dev->os_dep.rsrc_start,
32805 + otg_dev->os_dep.rsrc_len);
32806 + pci_set_drvdata(_dev, 0);
32807 +#elif defined(PLATFORM_INTERFACE)
32808 + platform_set_drvdata(_dev, 0);
32809 +#endif
32810 + return REM_RETVAL(0);
32811 +}
32812 +
32813 +/**
32814 + * This function is called when an lm_device is bound to a
32815 + * dwc_otg_driver. It creates the driver components required to
32816 + * control the device (CIL, HCD, and PCD) and it initializes the
32817 + * device. The driver components are stored in a dwc_otg_device
32818 + * structure. A reference to the dwc_otg_device is saved in the
32819 + * lm_device. This allows the driver to access the dwc_otg_device
32820 + * structure on subsequent calls to driver methods for this device.
32821 + *
32822 + * @param _dev Bus device
32823 + */
32824 +static int dwc_otg_driver_probe(
32825 +#ifdef LM_INTERFACE
32826 + struct lm_device *_dev
32827 +#elif defined(PCI_INTERFACE)
32828 + struct pci_dev *_dev,
32829 + const struct pci_device_id *id
32830 +#elif defined(PLATFORM_INTERFACE)
32831 + struct platform_device *_dev
32832 +#endif
32833 + )
32834 +{
32835 + int retval = 0;
32836 + dwc_otg_device_t *dwc_otg_device;
32837 + int devirq;
32838 +
32839 + dev_dbg(&_dev->dev, "dwc_otg_driver_probe(%p)\n", _dev);
32840 +#ifdef LM_INTERFACE
32841 + dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)_dev->resource.start);
32842 +#elif defined(PCI_INTERFACE)
32843 + if (!id) {
32844 + DWC_ERROR("Invalid pci_device_id %p", id);
32845 + return -EINVAL;
32846 + }
32847 +
32848 + if (!_dev || (pci_enable_device(_dev) < 0)) {
32849 + DWC_ERROR("Invalid pci_device %p", _dev);
32850 + return -ENODEV;
32851 + }
32852 + dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)pci_resource_start(_dev,0));
32853 + /* other stuff needed as well? */
32854 +
32855 +#elif defined(PLATFORM_INTERFACE)
32856 + dev_dbg(&_dev->dev, "start=0x%08x (len 0x%x)\n",
32857 + (unsigned)_dev->resource->start,
32858 + (unsigned)(_dev->resource->end - _dev->resource->start));
32859 +#endif
32860 +
32861 + dwc_otg_device = DWC_ALLOC(sizeof(dwc_otg_device_t));
32862 +
32863 + if (!dwc_otg_device) {
32864 + dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n");
32865 + return -ENOMEM;
32866 + }
32867 +
32868 + memset(dwc_otg_device, 0, sizeof(*dwc_otg_device));
32869 + dwc_otg_device->os_dep.reg_offset = 0xFFFFFFFF;
32870 +
32871 + /*
32872 + * Map the DWC_otg Core memory into virtual address space.
32873 + */
32874 +#ifdef LM_INTERFACE
32875 + dwc_otg_device->os_dep.base = ioremap(_dev->resource.start, SZ_256K);
32876 +
32877 + if (!dwc_otg_device->os_dep.base) {
32878 + dev_err(&_dev->dev, "ioremap() failed\n");
32879 + DWC_FREE(dwc_otg_device);
32880 + return -ENOMEM;
32881 + }
32882 + dev_dbg(&_dev->dev, "base=0x%08x\n",
32883 + (unsigned)dwc_otg_device->os_dep.base);
32884 +#elif defined(PCI_INTERFACE)
32885 + _dev->current_state = PCI_D0;
32886 + _dev->dev.power.power_state = PMSG_ON;
32887 +
32888 + if (!_dev->irq) {
32889 + DWC_ERROR("Found HC with no IRQ. Check BIOS/PCI %s setup!",
32890 + pci_name(_dev));
32891 + iounmap(dwc_otg_device->os_dep.base);
32892 + DWC_FREE(dwc_otg_device);
32893 + return -ENODEV;
32894 + }
32895 +
32896 + dwc_otg_device->os_dep.rsrc_start = pci_resource_start(_dev, 0);
32897 + dwc_otg_device->os_dep.rsrc_len = pci_resource_len(_dev, 0);
32898 + DWC_DEBUGPL(DBG_ANY, "PCI resource: start=%08x, len=%08x\n",
32899 + (unsigned)dwc_otg_device->os_dep.rsrc_start,
32900 + (unsigned)dwc_otg_device->os_dep.rsrc_len);
32901 + if (!request_mem_region
32902 + (dwc_otg_device->os_dep.rsrc_start, dwc_otg_device->os_dep.rsrc_len,
32903 + "dwc_otg")) {
32904 + dev_dbg(&_dev->dev, "error requesting memory\n");
32905 + iounmap(dwc_otg_device->os_dep.base);
32906 + DWC_FREE(dwc_otg_device);
32907 + return -EFAULT;
32908 + }
32909 +
32910 + dwc_otg_device->os_dep.base =
32911 + ioremap_nocache(dwc_otg_device->os_dep.rsrc_start,
32912 + dwc_otg_device->os_dep.rsrc_len);
32913 + if (dwc_otg_device->os_dep.base == NULL) {
32914 + dev_dbg(&_dev->dev, "error mapping memory\n");
32915 + release_mem_region(dwc_otg_device->os_dep.rsrc_start,
32916 + dwc_otg_device->os_dep.rsrc_len);
32917 + iounmap(dwc_otg_device->os_dep.base);
32918 + DWC_FREE(dwc_otg_device);
32919 + return -EFAULT;
32920 + }
32921 + dev_dbg(&_dev->dev, "base=0x%p (before adjust) \n",
32922 + dwc_otg_device->os_dep.base);
32923 + dwc_otg_device->os_dep.base = (char *)dwc_otg_device->os_dep.base;
32924 + dev_dbg(&_dev->dev, "base=0x%p (after adjust) \n",
32925 + dwc_otg_device->os_dep.base);
32926 + dev_dbg(&_dev->dev, "%s: mapped PA 0x%x to VA 0x%p\n", __func__,
32927 + (unsigned)dwc_otg_device->os_dep.rsrc_start,
32928 + dwc_otg_device->os_dep.base);
32929 +
32930 + pci_set_master(_dev);
32931 + pci_set_drvdata(_dev, dwc_otg_device);
32932 +#elif defined(PLATFORM_INTERFACE)
32933 + DWC_DEBUGPL(DBG_ANY,"Platform resource: start=%08x, len=%08x\n",
32934 + _dev->resource->start,
32935 + _dev->resource->end - _dev->resource->start + 1);
32936 +#if 1
32937 + if (!request_mem_region(_dev->resource->start,
32938 + _dev->resource->end - _dev->resource->start + 1,
32939 + "dwc_otg")) {
32940 + dev_dbg(&_dev->dev, "error reserving mapped memory\n");
32941 + retval = -EFAULT;
32942 + goto fail;
32943 + }
32944 +
32945 + dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource->start,
32946 + _dev->resource->end -
32947 + _dev->resource->start+1);
32948 +#else
32949 + {
32950 + struct map_desc desc = {
32951 + .virtual = IO_ADDRESS((unsigned)_dev->resource->start),
32952 + .pfn = __phys_to_pfn((unsigned)_dev->resource->start),
32953 + .length = SZ_128K,
32954 + .type = MT_DEVICE
32955 + };
32956 + iotable_init(&desc, 1);
32957 + dwc_otg_device->os_dep.base = (void *)desc.virtual;
32958 + }
32959 +#endif
32960 + if (!dwc_otg_device->os_dep.base) {
32961 + dev_err(&_dev->dev, "ioremap() failed\n");
32962 + retval = -ENOMEM;
32963 + goto fail;
32964 + }
32965 + dev_dbg(&_dev->dev, "base=0x%08x\n",
32966 + (unsigned)dwc_otg_device->os_dep.base);
32967 +#endif
32968 +
32969 + /*
32970 + * Initialize driver data to point to the global DWC_otg
32971 + * Device structure.
32972 + */
32973 +#ifdef LM_INTERFACE
32974 + lm_set_drvdata(_dev, dwc_otg_device);
32975 +#elif defined(PLATFORM_INTERFACE)
32976 + platform_set_drvdata(_dev, dwc_otg_device);
32977 +#endif
32978 + dev_dbg(&_dev->dev, "dwc_otg_device=0x%p\n", dwc_otg_device);
32979 +
32980 + dwc_otg_device->core_if = dwc_otg_cil_init(dwc_otg_device->os_dep.base);
32981 + DWC_DEBUGPL(DBG_HCDV, "probe of device %p given core_if %p\n",
32982 + dwc_otg_device, dwc_otg_device->core_if);//GRAYG
32983 +
32984 + if (!dwc_otg_device->core_if) {
32985 + dev_err(&_dev->dev, "CIL initialization failed!\n");
32986 + retval = -ENOMEM;
32987 + goto fail;
32988 + }
32989 +
32990 + dev_dbg(&_dev->dev, "Calling get_gsnpsid\n");
32991 + /*
32992 + * Attempt to ensure this device is really a DWC_otg Controller.
32993 + * Read and verify the SNPSID register contents. The value should be
32994 + * 0x45F42XXX or 0x45F42XXX, which corresponds to either "OT2" or "OTG3",
32995 + * as in "OTG version 2.XX" or "OTG version 3.XX".
32996 + */
32997 +
32998 + if (((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F542000) &&
32999 + ((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F543000)) {
33000 + dev_err(&_dev->dev, "Bad value for SNPSID: 0x%08x\n",
33001 + dwc_otg_get_gsnpsid(dwc_otg_device->core_if));
33002 + retval = -EINVAL;
33003 + goto fail;
33004 + }
33005 +
33006 + /*
33007 + * Validate parameter values.
33008 + */
33009 + dev_dbg(&_dev->dev, "Calling set_parameters\n");
33010 + if (set_parameters(dwc_otg_device->core_if)) {
33011 + retval = -EINVAL;
33012 + goto fail;
33013 + }
33014 +
33015 + /*
33016 + * Create Device Attributes in sysfs
33017 + */
33018 + dev_dbg(&_dev->dev, "Calling attr_create\n");
33019 + dwc_otg_attr_create(_dev);
33020 +
33021 + /*
33022 + * Disable the global interrupt until all the interrupt
33023 + * handlers are installed.
33024 + */
33025 + dev_dbg(&_dev->dev, "Calling disable_global_interrupts\n");
33026 + dwc_otg_disable_global_interrupts(dwc_otg_device->core_if);
33027 +
33028 + /*
33029 + * Install the interrupt handler for the common interrupts before
33030 + * enabling common interrupts in core_init below.
33031 + */
33032 +
33033 +#if defined(PLATFORM_INTERFACE)
33034 + devirq = platform_get_irq(_dev, 0);
33035 +#else
33036 + devirq = _dev->irq;
33037 +#endif
33038 + DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n",
33039 + devirq);
33040 + dev_dbg(&_dev->dev, "Calling request_irq(%d)\n", devirq);
33041 + retval = request_irq(devirq, dwc_otg_common_irq,
33042 + IRQF_SHARED,
33043 + "dwc_otg", dwc_otg_device);
33044 + if (retval) {
33045 + DWC_ERROR("request of irq%d failed\n", devirq);
33046 + retval = -EBUSY;
33047 + goto fail;
33048 + } else {
33049 + dwc_otg_device->common_irq_installed = 1;
33050 + }
33051 +
33052 +#ifndef IRQF_TRIGGER_LOW
33053 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
33054 + dev_dbg(&_dev->dev, "Calling set_irq_type\n");
33055 + set_irq_type(devirq,
33056 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
33057 + IRQT_LOW
33058 +#else
33059 + IRQ_TYPE_LEVEL_LOW
33060 +#endif
33061 + );
33062 +#endif
33063 +#endif /*IRQF_TRIGGER_LOW*/
33064 +
33065 + /*
33066 + * Initialize the DWC_otg core.
33067 + */
33068 + dev_dbg(&_dev->dev, "Calling dwc_otg_core_init\n");
33069 + dwc_otg_core_init(dwc_otg_device->core_if);
33070 +
33071 +#ifndef DWC_HOST_ONLY
33072 + /*
33073 + * Initialize the PCD
33074 + */
33075 + dev_dbg(&_dev->dev, "Calling pcd_init\n");
33076 + retval = pcd_init(_dev);
33077 + if (retval != 0) {
33078 + DWC_ERROR("pcd_init failed\n");
33079 + dwc_otg_device->pcd = NULL;
33080 + goto fail;
33081 + }
33082 +#endif
33083 +#ifndef DWC_DEVICE_ONLY
33084 + /*
33085 + * Initialize the HCD
33086 + */
33087 + dev_dbg(&_dev->dev, "Calling hcd_init\n");
33088 + retval = hcd_init(_dev);
33089 + if (retval != 0) {
33090 + DWC_ERROR("hcd_init failed\n");
33091 + dwc_otg_device->hcd = NULL;
33092 + goto fail;
33093 + }
33094 +#endif
33095 + /* Recover from drvdata having been overwritten by hcd_init() */
33096 +#ifdef LM_INTERFACE
33097 + lm_set_drvdata(_dev, dwc_otg_device);
33098 +#elif defined(PLATFORM_INTERFACE)
33099 + platform_set_drvdata(_dev, dwc_otg_device);
33100 +#elif defined(PCI_INTERFACE)
33101 + pci_set_drvdata(_dev, dwc_otg_device);
33102 + dwc_otg_device->os_dep.pcidev = _dev;
33103 +#endif
33104 +
33105 + /*
33106 + * Enable the global interrupt after all the interrupt
33107 + * handlers are installed if there is no ADP support else
33108 + * perform initial actions required for Internal ADP logic.
33109 + */
33110 + if (!dwc_otg_get_param_adp_enable(dwc_otg_device->core_if)) {
33111 + dev_dbg(&_dev->dev, "Calling enable_global_interrupts\n");
33112 + dwc_otg_enable_global_interrupts(dwc_otg_device->core_if);
33113 + dev_dbg(&_dev->dev, "Done\n");
33114 + } else
33115 + dwc_otg_adp_start(dwc_otg_device->core_if,
33116 + dwc_otg_is_host_mode(dwc_otg_device->core_if));
33117 +
33118 + return 0;
33119 +
33120 +fail:
33121 + dwc_otg_driver_remove(_dev);
33122 + return retval;
33123 +}
33124 +
33125 +/**
33126 + * This structure defines the methods to be called by a bus driver
33127 + * during the lifecycle of a device on that bus. Both drivers and
33128 + * devices are registered with a bus driver. The bus driver matches
33129 + * devices to drivers based on information in the device and driver
33130 + * structures.
33131 + *
33132 + * The probe function is called when the bus driver matches a device
33133 + * to this driver. The remove function is called when a device is
33134 + * unregistered with the bus driver.
33135 + */
33136 +#ifdef LM_INTERFACE
33137 +static struct lm_driver dwc_otg_driver = {
33138 + .drv = {.name = (char *)dwc_driver_name,},
33139 + .probe = dwc_otg_driver_probe,
33140 + .remove = dwc_otg_driver_remove,
33141 + // 'suspend' and 'resume' absent
33142 +};
33143 +#elif defined(PCI_INTERFACE)
33144 +static const struct pci_device_id pci_ids[] = { {
33145 + PCI_DEVICE(0x16c3, 0xabcd),
33146 + .driver_data =
33147 + (unsigned long)0xdeadbeef,
33148 + }, { /* end: all zeroes */ }
33149 +};
33150 +
33151 +MODULE_DEVICE_TABLE(pci, pci_ids);
33152 +
33153 +/* pci driver glue; this is a "new style" PCI driver module */
33154 +static struct pci_driver dwc_otg_driver = {
33155 + .name = "dwc_otg",
33156 + .id_table = pci_ids,
33157 +
33158 + .probe = dwc_otg_driver_probe,
33159 + .remove = dwc_otg_driver_remove,
33160 +
33161 + .driver = {
33162 + .name = (char *)dwc_driver_name,
33163 + },
33164 +};
33165 +#elif defined(PLATFORM_INTERFACE)
33166 +static struct platform_device_id platform_ids[] = {
33167 + {
33168 + .name = "bcm2708_usb",
33169 + .driver_data = (kernel_ulong_t) 0xdeadbeef,
33170 + },
33171 + { /* end: all zeroes */ }
33172 +};
33173 +MODULE_DEVICE_TABLE(platform, platform_ids);
33174 +
33175 +static struct platform_driver dwc_otg_driver = {
33176 + .driver = {
33177 + .name = (char *)dwc_driver_name,
33178 + },
33179 + .id_table = platform_ids,
33180 +
33181 + .probe = dwc_otg_driver_probe,
33182 + .remove = dwc_otg_driver_remove,
33183 + // no 'shutdown', 'suspend', 'resume', 'suspend_late' or 'resume_early'
33184 +};
33185 +#endif
33186 +
33187 +/**
33188 + * This function is called when the dwc_otg_driver is installed with the
33189 + * insmod command. It registers the dwc_otg_driver structure with the
33190 + * appropriate bus driver. This will cause the dwc_otg_driver_probe function
33191 + * to be called. In addition, the bus driver will automatically expose
33192 + * attributes defined for the device and driver in the special sysfs file
33193 + * system.
33194 + *
33195 + * @return
33196 + */
33197 +static int __init dwc_otg_driver_init(void)
33198 +{
33199 + int retval = 0;
33200 + int error;
33201 + struct device_driver *drv;
33202 + printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name,
33203 + DWC_DRIVER_VERSION,
33204 +#ifdef LM_INTERFACE
33205 + "logicmodule");
33206 + retval = lm_driver_register(&dwc_otg_driver);
33207 + drv = &dwc_otg_driver.drv;
33208 +#elif defined(PCI_INTERFACE)
33209 + "pci");
33210 + retval = pci_register_driver(&dwc_otg_driver);
33211 + drv = &dwc_otg_driver.driver;
33212 +#elif defined(PLATFORM_INTERFACE)
33213 + "platform");
33214 + retval = platform_driver_register(&dwc_otg_driver);
33215 + drv = &dwc_otg_driver.driver;
33216 +#endif
33217 + if (retval < 0) {
33218 + printk(KERN_ERR "%s retval=%d\n", __func__, retval);
33219 + return retval;
33220 + }
33221 +
33222 + error = driver_create_file(drv, &driver_attr_version);
33223 +#ifdef DEBUG
33224 + error = driver_create_file(drv, &driver_attr_debuglevel);
33225 +#endif
33226 + return retval;
33227 +}
33228 +
33229 +module_init(dwc_otg_driver_init);
33230 +
33231 +/**
33232 + * This function is called when the driver is removed from the kernel
33233 + * with the rmmod command. The driver unregisters itself with its bus
33234 + * driver.
33235 + *
33236 + */
33237 +static void __exit dwc_otg_driver_cleanup(void)
33238 +{
33239 + printk(KERN_DEBUG "dwc_otg_driver_cleanup()\n");
33240 +
33241 +#ifdef LM_INTERFACE
33242 + driver_remove_file(&dwc_otg_driver.drv, &driver_attr_debuglevel);
33243 + driver_remove_file(&dwc_otg_driver.drv, &driver_attr_version);
33244 + lm_driver_unregister(&dwc_otg_driver);
33245 +#elif defined(PCI_INTERFACE)
33246 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
33247 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
33248 + pci_unregister_driver(&dwc_otg_driver);
33249 +#elif defined(PLATFORM_INTERFACE)
33250 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
33251 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
33252 + platform_driver_unregister(&dwc_otg_driver);
33253 +#endif
33254 +
33255 + printk(KERN_INFO "%s module removed\n", dwc_driver_name);
33256 +}
33257 +
33258 +module_exit(dwc_otg_driver_cleanup);
33259 +
33260 +MODULE_DESCRIPTION(DWC_DRIVER_DESC);
33261 +MODULE_AUTHOR("Synopsys Inc.");
33262 +MODULE_LICENSE("GPL");
33263 +
33264 +module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444);
33265 +MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None");
33266 +module_param_named(opt, dwc_otg_module_params.opt, int, 0444);
33267 +MODULE_PARM_DESC(opt, "OPT Mode");
33268 +module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444);
33269 +MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled");
33270 +
33271 +module_param_named(dma_desc_enable, dwc_otg_module_params.dma_desc_enable, int,
33272 + 0444);
33273 +MODULE_PARM_DESC(dma_desc_enable,
33274 + "DMA Desc Mode 0=Address DMA 1=DMA Descriptor enabled");
33275 +
33276 +module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int,
33277 + 0444);
33278 +MODULE_PARM_DESC(dma_burst_size,
33279 + "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256");
33280 +module_param_named(speed, dwc_otg_module_params.speed, int, 0444);
33281 +MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed");
33282 +module_param_named(host_support_fs_ls_low_power,
33283 + dwc_otg_module_params.host_support_fs_ls_low_power, int,
33284 + 0444);
33285 +MODULE_PARM_DESC(host_support_fs_ls_low_power,
33286 + "Support Low Power w/FS or LS 0=Support 1=Don't Support");
33287 +module_param_named(host_ls_low_power_phy_clk,
33288 + dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444);
33289 +MODULE_PARM_DESC(host_ls_low_power_phy_clk,
33290 + "Low Speed Low Power Clock 0=48Mhz 1=6Mhz");
33291 +module_param_named(enable_dynamic_fifo,
33292 + dwc_otg_module_params.enable_dynamic_fifo, int, 0444);
33293 +MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing");
33294 +module_param_named(data_fifo_size, dwc_otg_module_params.data_fifo_size, int,
33295 + 0444);
33296 +MODULE_PARM_DESC(data_fifo_size,
33297 + "Total number of words in the data FIFO memory 32-32768");
33298 +module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size,
33299 + int, 0444);
33300 +MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
33301 +module_param_named(dev_nperio_tx_fifo_size,
33302 + dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444);
33303 +MODULE_PARM_DESC(dev_nperio_tx_fifo_size,
33304 + "Number of words in the non-periodic Tx FIFO 16-32768");
33305 +module_param_named(dev_perio_tx_fifo_size_1,
33306 + dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444);
33307 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_1,
33308 + "Number of words in the periodic Tx FIFO 4-768");
33309 +module_param_named(dev_perio_tx_fifo_size_2,
33310 + dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444);
33311 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_2,
33312 + "Number of words in the periodic Tx FIFO 4-768");
33313 +module_param_named(dev_perio_tx_fifo_size_3,
33314 + dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444);
33315 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_3,
33316 + "Number of words in the periodic Tx FIFO 4-768");
33317 +module_param_named(dev_perio_tx_fifo_size_4,
33318 + dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444);
33319 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_4,
33320 + "Number of words in the periodic Tx FIFO 4-768");
33321 +module_param_named(dev_perio_tx_fifo_size_5,
33322 + dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444);
33323 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_5,
33324 + "Number of words in the periodic Tx FIFO 4-768");
33325 +module_param_named(dev_perio_tx_fifo_size_6,
33326 + dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444);
33327 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_6,
33328 + "Number of words in the periodic Tx FIFO 4-768");
33329 +module_param_named(dev_perio_tx_fifo_size_7,
33330 + dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444);
33331 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_7,
33332 + "Number of words in the periodic Tx FIFO 4-768");
33333 +module_param_named(dev_perio_tx_fifo_size_8,
33334 + dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444);
33335 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_8,
33336 + "Number of words in the periodic Tx FIFO 4-768");
33337 +module_param_named(dev_perio_tx_fifo_size_9,
33338 + dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444);
33339 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_9,
33340 + "Number of words in the periodic Tx FIFO 4-768");
33341 +module_param_named(dev_perio_tx_fifo_size_10,
33342 + dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444);
33343 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_10,
33344 + "Number of words in the periodic Tx FIFO 4-768");
33345 +module_param_named(dev_perio_tx_fifo_size_11,
33346 + dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444);
33347 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_11,
33348 + "Number of words in the periodic Tx FIFO 4-768");
33349 +module_param_named(dev_perio_tx_fifo_size_12,
33350 + dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444);
33351 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_12,
33352 + "Number of words in the periodic Tx FIFO 4-768");
33353 +module_param_named(dev_perio_tx_fifo_size_13,
33354 + dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444);
33355 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_13,
33356 + "Number of words in the periodic Tx FIFO 4-768");
33357 +module_param_named(dev_perio_tx_fifo_size_14,
33358 + dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444);
33359 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_14,
33360 + "Number of words in the periodic Tx FIFO 4-768");
33361 +module_param_named(dev_perio_tx_fifo_size_15,
33362 + dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444);
33363 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_15,
33364 + "Number of words in the periodic Tx FIFO 4-768");
33365 +module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size,
33366 + int, 0444);
33367 +MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
33368 +module_param_named(host_nperio_tx_fifo_size,
33369 + dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444);
33370 +MODULE_PARM_DESC(host_nperio_tx_fifo_size,
33371 + "Number of words in the non-periodic Tx FIFO 16-32768");
33372 +module_param_named(host_perio_tx_fifo_size,
33373 + dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444);
33374 +MODULE_PARM_DESC(host_perio_tx_fifo_size,
33375 + "Number of words in the host periodic Tx FIFO 16-32768");
33376 +module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size,
33377 + int, 0444);
33378 +/** @todo Set the max to 512K, modify checks */
33379 +MODULE_PARM_DESC(max_transfer_size,
33380 + "The maximum transfer size supported in bytes 2047-65535");
33381 +module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count,
33382 + int, 0444);
33383 +MODULE_PARM_DESC(max_packet_count,
33384 + "The maximum number of packets in a transfer 15-511");
33385 +module_param_named(host_channels, dwc_otg_module_params.host_channels, int,
33386 + 0444);
33387 +MODULE_PARM_DESC(host_channels,
33388 + "The number of host channel registers to use 1-16");
33389 +module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int,
33390 + 0444);
33391 +MODULE_PARM_DESC(dev_endpoints,
33392 + "The number of endpoints in addition to EP0 available for device mode 1-15");
33393 +module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444);
33394 +MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI");
33395 +module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int,
33396 + 0444);
33397 +MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits");
33398 +module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444);
33399 +MODULE_PARM_DESC(phy_ulpi_ddr,
33400 + "ULPI at double or single data rate 0=Single 1=Double");
33401 +module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus,
33402 + int, 0444);
33403 +MODULE_PARM_DESC(phy_ulpi_ext_vbus,
33404 + "ULPI PHY using internal or external vbus 0=Internal");
33405 +module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444);
33406 +MODULE_PARM_DESC(i2c_enable, "FS PHY Interface");
33407 +module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444);
33408 +MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only");
33409 +module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444);
33410 +MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs");
33411 +module_param_named(debug, g_dbg_lvl, int, 0444);
33412 +MODULE_PARM_DESC(debug, "");
33413 +
33414 +module_param_named(en_multiple_tx_fifo,
33415 + dwc_otg_module_params.en_multiple_tx_fifo, int, 0444);
33416 +MODULE_PARM_DESC(en_multiple_tx_fifo,
33417 + "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled");
33418 +module_param_named(dev_tx_fifo_size_1,
33419 + dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444);
33420 +MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768");
33421 +module_param_named(dev_tx_fifo_size_2,
33422 + dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444);
33423 +MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768");
33424 +module_param_named(dev_tx_fifo_size_3,
33425 + dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444);
33426 +MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768");
33427 +module_param_named(dev_tx_fifo_size_4,
33428 + dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444);
33429 +MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768");
33430 +module_param_named(dev_tx_fifo_size_5,
33431 + dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444);
33432 +MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768");
33433 +module_param_named(dev_tx_fifo_size_6,
33434 + dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444);
33435 +MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768");
33436 +module_param_named(dev_tx_fifo_size_7,
33437 + dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444);
33438 +MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768");
33439 +module_param_named(dev_tx_fifo_size_8,
33440 + dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444);
33441 +MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768");
33442 +module_param_named(dev_tx_fifo_size_9,
33443 + dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444);
33444 +MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768");
33445 +module_param_named(dev_tx_fifo_size_10,
33446 + dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444);
33447 +MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768");
33448 +module_param_named(dev_tx_fifo_size_11,
33449 + dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444);
33450 +MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768");
33451 +module_param_named(dev_tx_fifo_size_12,
33452 + dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444);
33453 +MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768");
33454 +module_param_named(dev_tx_fifo_size_13,
33455 + dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444);
33456 +MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768");
33457 +module_param_named(dev_tx_fifo_size_14,
33458 + dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444);
33459 +MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768");
33460 +module_param_named(dev_tx_fifo_size_15,
33461 + dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444);
33462 +MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768");
33463 +
33464 +module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444);
33465 +MODULE_PARM_DESC(thr_ctl,
33466 + "Thresholding enable flag bit 0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled");
33467 +module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int,
33468 + 0444);
33469 +MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs");
33470 +module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int,
33471 + 0444);
33472 +MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs");
33473 +
33474 +module_param_named(pti_enable, dwc_otg_module_params.pti_enable, int, 0444);
33475 +module_param_named(mpi_enable, dwc_otg_module_params.mpi_enable, int, 0444);
33476 +module_param_named(lpm_enable, dwc_otg_module_params.lpm_enable, int, 0444);
33477 +MODULE_PARM_DESC(lpm_enable, "LPM Enable 0=LPM Disabled 1=LPM Enabled");
33478 +module_param_named(ic_usb_cap, dwc_otg_module_params.ic_usb_cap, int, 0444);
33479 +MODULE_PARM_DESC(ic_usb_cap,
33480 + "IC_USB Capability 0=IC_USB Disabled 1=IC_USB Enabled");
33481 +module_param_named(ahb_thr_ratio, dwc_otg_module_params.ahb_thr_ratio, int,
33482 + 0444);
33483 +MODULE_PARM_DESC(ahb_thr_ratio, "AHB Threshold Ratio");
33484 +module_param_named(power_down, dwc_otg_module_params.power_down, int, 0444);
33485 +MODULE_PARM_DESC(power_down, "Power Down Mode");
33486 +module_param_named(reload_ctl, dwc_otg_module_params.reload_ctl, int, 0444);
33487 +MODULE_PARM_DESC(reload_ctl, "HFIR Reload Control");
33488 +module_param_named(dev_out_nak, dwc_otg_module_params.dev_out_nak, int, 0444);
33489 +MODULE_PARM_DESC(dev_out_nak, "Enable Device OUT NAK");
33490 +module_param_named(cont_on_bna, dwc_otg_module_params.cont_on_bna, int, 0444);
33491 +MODULE_PARM_DESC(cont_on_bna, "Enable Enable Continue on BNA");
33492 +module_param_named(ahb_single, dwc_otg_module_params.ahb_single, int, 0444);
33493 +MODULE_PARM_DESC(ahb_single, "Enable AHB Single Support");
33494 +module_param_named(adp_enable, dwc_otg_module_params.adp_enable, int, 0444);
33495 +MODULE_PARM_DESC(adp_enable, "ADP Enable 0=ADP Disabled 1=ADP Enabled");
33496 +module_param_named(otg_ver, dwc_otg_module_params.otg_ver, int, 0444);
33497 +MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0");
33498 +module_param(microframe_schedule, bool, 0444);
33499 +MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler");
33500 +
33501 +/** @page "Module Parameters"
33502 + *
33503 + * The following parameters may be specified when starting the module.
33504 + * These parameters define how the DWC_otg controller should be
33505 + * configured. Parameter values are passed to the CIL initialization
33506 + * function dwc_otg_cil_init
33507 + *
33508 + * Example: <code>modprobe dwc_otg speed=1 otg_cap=1</code>
33509 + *
33510 +
33511 + <table>
33512 + <tr><td>Parameter Name</td><td>Meaning</td></tr>
33513 +
33514 + <tr>
33515 + <td>otg_cap</td>
33516 + <td>Specifies the OTG capabilities. The driver will automatically detect the
33517 + value for this parameter if none is specified.
33518 + - 0: HNP and SRP capable (default, if available)
33519 + - 1: SRP Only capable
33520 + - 2: No HNP/SRP capable
33521 + </td></tr>
33522 +
33523 + <tr>
33524 + <td>dma_enable</td>
33525 + <td>Specifies whether to use slave or DMA mode for accessing the data FIFOs.
33526 + The driver will automatically detect the value for this parameter if none is
33527 + specified.
33528 + - 0: Slave
33529 + - 1: DMA (default, if available)
33530 + </td></tr>
33531 +
33532 + <tr>
33533 + <td>dma_burst_size</td>
33534 + <td>The DMA Burst size (applicable only for External DMA Mode).
33535 + - Values: 1, 4, 8 16, 32, 64, 128, 256 (default 32)
33536 + </td></tr>
33537 +
33538 + <tr>
33539 + <td>speed</td>
33540 + <td>Specifies the maximum speed of operation in host and device mode. The
33541 + actual speed depends on the speed of the attached device and the value of
33542 + phy_type.
33543 + - 0: High Speed (default)
33544 + - 1: Full Speed
33545 + </td></tr>
33546 +
33547 + <tr>
33548 + <td>host_support_fs_ls_low_power</td>
33549 + <td>Specifies whether low power mode is supported when attached to a Full
33550 + Speed or Low Speed device in host mode.
33551 + - 0: Don't support low power mode (default)
33552 + - 1: Support low power mode
33553 + </td></tr>
33554 +
33555 + <tr>
33556 + <td>host_ls_low_power_phy_clk</td>
33557 + <td>Specifies the PHY clock rate in low power mode when connected to a Low
33558 + Speed device in host mode. This parameter is applicable only if
33559 + HOST_SUPPORT_FS_LS_LOW_POWER is enabled.
33560 + - 0: 48 MHz (default)
33561 + - 1: 6 MHz
33562 + </td></tr>
33563 +
33564 + <tr>
33565 + <td>enable_dynamic_fifo</td>
33566 + <td> Specifies whether FIFOs may be resized by the driver software.
33567 + - 0: Use cC FIFO size parameters
33568 + - 1: Allow dynamic FIFO sizing (default)
33569 + </td></tr>
33570 +
33571 + <tr>
33572 + <td>data_fifo_size</td>
33573 + <td>Total number of 4-byte words in the data FIFO memory. This memory
33574 + includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs.
33575 + - Values: 32 to 32768 (default 8192)
33576 +
33577 + Note: The total FIFO memory depth in the FPGA configuration is 8192.
33578 + </td></tr>
33579 +
33580 + <tr>
33581 + <td>dev_rx_fifo_size</td>
33582 + <td>Number of 4-byte words in the Rx FIFO in device mode when dynamic
33583 + FIFO sizing is enabled.
33584 + - Values: 16 to 32768 (default 1064)
33585 + </td></tr>
33586 +
33587 + <tr>
33588 + <td>dev_nperio_tx_fifo_size</td>
33589 + <td>Number of 4-byte words in the non-periodic Tx FIFO in device mode when
33590 + dynamic FIFO sizing is enabled.
33591 + - Values: 16 to 32768 (default 1024)
33592 + </td></tr>
33593 +
33594 + <tr>
33595 + <td>dev_perio_tx_fifo_size_n (n = 1 to 15)</td>
33596 + <td>Number of 4-byte words in each of the periodic Tx FIFOs in device mode
33597 + when dynamic FIFO sizing is enabled.
33598 + - Values: 4 to 768 (default 256)
33599 + </td></tr>
33600 +
33601 + <tr>
33602 + <td>host_rx_fifo_size</td>
33603 + <td>Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO
33604 + sizing is enabled.
33605 + - Values: 16 to 32768 (default 1024)
33606 + </td></tr>
33607 +
33608 + <tr>
33609 + <td>host_nperio_tx_fifo_size</td>
33610 + <td>Number of 4-byte words in the non-periodic Tx FIFO in host mode when
33611 + dynamic FIFO sizing is enabled in the core.
33612 + - Values: 16 to 32768 (default 1024)
33613 + </td></tr>
33614 +
33615 + <tr>
33616 + <td>host_perio_tx_fifo_size</td>
33617 + <td>Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO
33618 + sizing is enabled.
33619 + - Values: 16 to 32768 (default 1024)
33620 + </td></tr>
33621 +
33622 + <tr>
33623 + <td>max_transfer_size</td>
33624 + <td>The maximum transfer size supported in bytes.
33625 + - Values: 2047 to 65,535 (default 65,535)
33626 + </td></tr>
33627 +
33628 + <tr>
33629 + <td>max_packet_count</td>
33630 + <td>The maximum number of packets in a transfer.
33631 + - Values: 15 to 511 (default 511)
33632 + </td></tr>
33633 +
33634 + <tr>
33635 + <td>host_channels</td>
33636 + <td>The number of host channel registers to use.
33637 + - Values: 1 to 16 (default 12)
33638 +
33639 + Note: The FPGA configuration supports a maximum of 12 host channels.
33640 + </td></tr>
33641 +
33642 + <tr>
33643 + <td>dev_endpoints</td>
33644 + <td>The number of endpoints in addition to EP0 available for device mode
33645 + operations.
33646 + - Values: 1 to 15 (default 6 IN and OUT)
33647 +
33648 + Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in
33649 + addition to EP0.
33650 + </td></tr>
33651 +
33652 + <tr>
33653 + <td>phy_type</td>
33654 + <td>Specifies the type of PHY interface to use. By default, the driver will
33655 + automatically detect the phy_type.
33656 + - 0: Full Speed
33657 + - 1: UTMI+ (default, if available)
33658 + - 2: ULPI
33659 + </td></tr>
33660 +
33661 + <tr>
33662 + <td>phy_utmi_width</td>
33663 + <td>Specifies the UTMI+ Data Width. This parameter is applicable for a
33664 + phy_type of UTMI+. Also, this parameter is applicable only if the
33665 + OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the
33666 + core has been configured to work at either data path width.
33667 + - Values: 8 or 16 bits (default 16)
33668 + </td></tr>
33669 +
33670 + <tr>
33671 + <td>phy_ulpi_ddr</td>
33672 + <td>Specifies whether the ULPI operates at double or single data rate. This
33673 + parameter is only applicable if phy_type is ULPI.
33674 + - 0: single data rate ULPI interface with 8 bit wide data bus (default)
33675 + - 1: double data rate ULPI interface with 4 bit wide data bus
33676 + </td></tr>
33677 +
33678 + <tr>
33679 + <td>i2c_enable</td>
33680 + <td>Specifies whether to use the I2C interface for full speed PHY. This
33681 + parameter is only applicable if PHY_TYPE is FS.
33682 + - 0: Disabled (default)
33683 + - 1: Enabled
33684 + </td></tr>
33685 +
33686 + <tr>
33687 + <td>ulpi_fs_ls</td>
33688 + <td>Specifies whether to use ULPI FS/LS mode only.
33689 + - 0: Disabled (default)
33690 + - 1: Enabled
33691 + </td></tr>
33692 +
33693 + <tr>
33694 + <td>ts_dline</td>
33695 + <td>Specifies whether term select D-Line pulsing for all PHYs is enabled.
33696 + - 0: Disabled (default)
33697 + - 1: Enabled
33698 + </td></tr>
33699 +
33700 + <tr>
33701 + <td>en_multiple_tx_fifo</td>
33702 + <td>Specifies whether dedicatedto tx fifos are enabled for non periodic IN EPs.
33703 + The driver will automatically detect the value for this parameter if none is
33704 + specified.
33705 + - 0: Disabled
33706 + - 1: Enabled (default, if available)
33707 + </td></tr>
33708 +
33709 + <tr>
33710 + <td>dev_tx_fifo_size_n (n = 1 to 15)</td>
33711 + <td>Number of 4-byte words in each of the Tx FIFOs in device mode
33712 + when dynamic FIFO sizing is enabled.
33713 + - Values: 4 to 768 (default 256)
33714 + </td></tr>
33715 +
33716 + <tr>
33717 + <td>tx_thr_length</td>
33718 + <td>Transmit Threshold length in 32 bit double words
33719 + - Values: 8 to 128 (default 64)
33720 + </td></tr>
33721 +
33722 + <tr>
33723 + <td>rx_thr_length</td>
33724 + <td>Receive Threshold length in 32 bit double words
33725 + - Values: 8 to 128 (default 64)
33726 + </td></tr>
33727 +
33728 +<tr>
33729 + <td>thr_ctl</td>
33730 + <td>Specifies whether to enable Thresholding for Device mode. Bits 0, 1, 2 of
33731 + this parmater specifies if thresholding is enabled for non-Iso Tx, Iso Tx and
33732 + Rx transfers accordingly.
33733 + The driver will automatically detect the value for this parameter if none is
33734 + specified.
33735 + - Values: 0 to 7 (default 0)
33736 + Bit values indicate:
33737 + - 0: Thresholding disabled
33738 + - 1: Thresholding enabled
33739 + </td></tr>
33740 +
33741 +<tr>
33742 + <td>dma_desc_enable</td>
33743 + <td>Specifies whether to enable Descriptor DMA mode.
33744 + The driver will automatically detect the value for this parameter if none is
33745 + specified.
33746 + - 0: Descriptor DMA disabled
33747 + - 1: Descriptor DMA (default, if available)
33748 + </td></tr>
33749 +
33750 +<tr>
33751 + <td>mpi_enable</td>
33752 + <td>Specifies whether to enable MPI enhancement mode.
33753 + The driver will automatically detect the value for this parameter if none is
33754 + specified.
33755 + - 0: MPI disabled (default)
33756 + - 1: MPI enable
33757 + </td></tr>
33758 +
33759 +<tr>
33760 + <td>pti_enable</td>
33761 + <td>Specifies whether to enable PTI enhancement support.
33762 + The driver will automatically detect the value for this parameter if none is
33763 + specified.
33764 + - 0: PTI disabled (default)
33765 + - 1: PTI enable
33766 + </td></tr>
33767 +
33768 +<tr>
33769 + <td>lpm_enable</td>
33770 + <td>Specifies whether to enable LPM support.
33771 + The driver will automatically detect the value for this parameter if none is
33772 + specified.
33773 + - 0: LPM disabled
33774 + - 1: LPM enable (default, if available)
33775 + </td></tr>
33776 +
33777 +<tr>
33778 + <td>ic_usb_cap</td>
33779 + <td>Specifies whether to enable IC_USB capability.
33780 + The driver will automatically detect the value for this parameter if none is
33781 + specified.
33782 + - 0: IC_USB disabled (default, if available)
33783 + - 1: IC_USB enable
33784 + </td></tr>
33785 +
33786 +<tr>
33787 + <td>ahb_thr_ratio</td>
33788 + <td>Specifies AHB Threshold ratio.
33789 + - Values: 0 to 3 (default 0)
33790 + </td></tr>
33791 +
33792 +<tr>
33793 + <td>power_down</td>
33794 + <td>Specifies Power Down(Hibernation) Mode.
33795 + The driver will automatically detect the value for this parameter if none is
33796 + specified.
33797 + - 0: Power Down disabled (default)
33798 + - 2: Power Down enabled
33799 + </td></tr>
33800 +
33801 + <tr>
33802 + <td>reload_ctl</td>
33803 + <td>Specifies whether dynamic reloading of the HFIR register is allowed during
33804 + run time. The driver will automatically detect the value for this parameter if
33805 + none is specified. In case the HFIR value is reloaded when HFIR.RldCtrl == 1'b0
33806 + the core might misbehave.
33807 + - 0: Reload Control disabled (default)
33808 + - 1: Reload Control enabled
33809 + </td></tr>
33810 +
33811 + <tr>
33812 + <td>dev_out_nak</td>
33813 + <td>Specifies whether Device OUT NAK enhancement enabled or no.
33814 + The driver will automatically detect the value for this parameter if
33815 + none is specified. This parameter is valid only when OTG_EN_DESC_DMA == 1b1.
33816 + - 0: The core does not set NAK after Bulk OUT transfer complete (default)
33817 + - 1: The core sets NAK after Bulk OUT transfer complete
33818 + </td></tr>
33819 +
33820 + <tr>
33821 + <td>cont_on_bna</td>
33822 + <td>Specifies whether Enable Continue on BNA enabled or no.
33823 + After receiving BNA interrupt the core disables the endpoint,when the
33824 + endpoint is re-enabled by the application the
33825 + - 0: Core starts processing from the DOEPDMA descriptor (default)
33826 + - 1: Core starts processing from the descriptor which received the BNA.
33827 + This parameter is valid only when OTG_EN_DESC_DMA == 1b1.
33828 + </td></tr>
33829 +
33830 + <tr>
33831 + <td>ahb_single</td>
33832 + <td>This bit when programmed supports SINGLE transfers for remainder data
33833 + in a transfer for DMA mode of operation.
33834 + - 0: The remainder data will be sent using INCR burst size (default)
33835 + - 1: The remainder data will be sent using SINGLE burst size.
33836 + </td></tr>
33837 +
33838 +<tr>
33839 + <td>adp_enable</td>
33840 + <td>Specifies whether ADP feature is enabled.
33841 + The driver will automatically detect the value for this parameter if none is
33842 + specified.
33843 + - 0: ADP feature disabled (default)
33844 + - 1: ADP feature enabled
33845 + </td></tr>
33846 +
33847 + <tr>
33848 + <td>otg_ver</td>
33849 + <td>Specifies whether OTG is performing as USB OTG Revision 2.0 or Revision 1.3
33850 + USB OTG device.
33851 + - 0: OTG 2.0 support disabled (default)
33852 + - 1: OTG 2.0 support enabled
33853 + </td></tr>
33854 +
33855 +*/
33856 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.h b/drivers/usb/host/dwc_otg/dwc_otg_driver.h
33857 new file mode 100644
33858 index 0000000..6a8be63
33859 --- /dev/null
33860 +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.h
33861 @@ -0,0 +1,86 @@
33862 +/* ==========================================================================
33863 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.h $
33864 + * $Revision: #19 $
33865 + * $Date: 2010/11/15 $
33866 + * $Change: 1627671 $
33867 + *
33868 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
33869 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
33870 + * otherwise expressly agreed to in writing between Synopsys and you.
33871 + *
33872 + * The Software IS NOT an item of Licensed Software or Licensed Product under
33873 + * any End User Software License Agreement or Agreement for Licensed Product
33874 + * with Synopsys or any supplement thereto. You are permitted to use and
33875 + * redistribute this Software in source and binary forms, with or without
33876 + * modification, provided that redistributions of source code must retain this
33877 + * notice. You may not view, use, disclose, copy or distribute this file or
33878 + * any information contained herein except pursuant to this license grant from
33879 + * Synopsys. If you do not agree with this notice, including the disclaimer
33880 + * below, then you are not authorized to use the Software.
33881 + *
33882 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
33883 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33884 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33885 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
33886 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33887 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33888 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33889 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33890 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33891 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33892 + * DAMAGE.
33893 + * ========================================================================== */
33894 +
33895 +#ifndef __DWC_OTG_DRIVER_H__
33896 +#define __DWC_OTG_DRIVER_H__
33897 +
33898 +/** @file
33899 + * This file contains the interface to the Linux driver.
33900 + */
33901 +#include "dwc_otg_os_dep.h"
33902 +#include "dwc_otg_core_if.h"
33903 +
33904 +/* Type declarations */
33905 +struct dwc_otg_pcd;
33906 +struct dwc_otg_hcd;
33907 +
33908 +/**
33909 + * This structure is a wrapper that encapsulates the driver components used to
33910 + * manage a single DWC_otg controller.
33911 + */
33912 +typedef struct dwc_otg_device {
33913 + /** Structure containing OS-dependent stuff. KEEP THIS STRUCT AT THE
33914 + * VERY BEGINNING OF THE DEVICE STRUCT. OSes such as FreeBSD and NetBSD
33915 + * require this. */
33916 + struct os_dependent os_dep;
33917 +
33918 + /** Pointer to the core interface structure. */
33919 + dwc_otg_core_if_t *core_if;
33920 +
33921 + /** Pointer to the PCD structure. */
33922 + struct dwc_otg_pcd *pcd;
33923 +
33924 + /** Pointer to the HCD structure. */
33925 + struct dwc_otg_hcd *hcd;
33926 +
33927 + /** Flag to indicate whether the common IRQ handler is installed. */
33928 + uint8_t common_irq_installed;
33929 +
33930 +} dwc_otg_device_t;
33931 +
33932 +/*We must clear S3C24XX_EINTPEND external interrupt register
33933 + * because after clearing in this register trigerred IRQ from
33934 + * H/W core in kernel interrupt can be occured again before OTG
33935 + * handlers clear all IRQ sources of Core registers because of
33936 + * timing latencies and Low Level IRQ Type.
33937 + */
33938 +#ifdef CONFIG_MACH_IPMATE
33939 +#define S3C2410X_CLEAR_EINTPEND() \
33940 +do { \
33941 + __raw_writel(1UL << 11,S3C24XX_EINTPEND); \
33942 +} while (0)
33943 +#else
33944 +#define S3C2410X_CLEAR_EINTPEND() do { } while (0)
33945 +#endif
33946 +
33947 +#endif
33948 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
33949 new file mode 100644
33950 index 0000000..ab935c0
33951 --- /dev/null
33952 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
33953 @@ -0,0 +1,3473 @@
33954 +
33955 +/* ==========================================================================
33956 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $
33957 + * $Revision: #104 $
33958 + * $Date: 2011/10/24 $
33959 + * $Change: 1871159 $
33960 + *
33961 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
33962 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
33963 + * otherwise expressly agreed to in writing between Synopsys and you.
33964 + *
33965 + * The Software IS NOT an item of Licensed Software or Licensed Product under
33966 + * any End User Software License Agreement or Agreement for Licensed Product
33967 + * with Synopsys or any supplement thereto. You are permitted to use and
33968 + * redistribute this Software in source and binary forms, with or without
33969 + * modification, provided that redistributions of source code must retain this
33970 + * notice. You may not view, use, disclose, copy or distribute this file or
33971 + * any information contained herein except pursuant to this license grant from
33972 + * Synopsys. If you do not agree with this notice, including the disclaimer
33973 + * below, then you are not authorized to use the Software.
33974 + *
33975 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
33976 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33977 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33978 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
33979 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33980 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33981 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33982 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33983 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33984 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33985 + * DAMAGE.
33986 + * ========================================================================== */
33987 +#ifndef DWC_DEVICE_ONLY
33988 +
33989 +/** @file
33990 + * This file implements HCD Core. All code in this file is portable and doesn't
33991 + * use any OS specific functions.
33992 + * Interface provided by HCD Core is defined in <code><hcd_if.h></code>
33993 + * header file.
33994 + */
33995 +
33996 +#include "dwc_otg_hcd.h"
33997 +#include "dwc_otg_regs.h"
33998 +
33999 +extern bool microframe_schedule;
34000 +
34001 +//#define DEBUG_HOST_CHANNELS
34002 +#ifdef DEBUG_HOST_CHANNELS
34003 +static int last_sel_trans_num_per_scheduled = 0;
34004 +static int last_sel_trans_num_nonper_scheduled = 0;
34005 +static int last_sel_trans_num_avail_hc_at_start = 0;
34006 +static int last_sel_trans_num_avail_hc_at_end = 0;
34007 +#endif /* DEBUG_HOST_CHANNELS */
34008 +
34009 +dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
34010 +{
34011 + return DWC_ALLOC(sizeof(dwc_otg_hcd_t));
34012 +}
34013 +
34014 +/**
34015 + * Connection timeout function. An OTG host is required to display a
34016 + * message if the device does not connect within 10 seconds.
34017 + */
34018 +void dwc_otg_hcd_connect_timeout(void *ptr)
34019 +{
34020 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, ptr);
34021 + DWC_PRINTF("Connect Timeout\n");
34022 + __DWC_ERROR("Device Not Connected/Responding\n");
34023 +}
34024 +
34025 +#if defined(DEBUG)
34026 +static void dump_channel_info(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
34027 +{
34028 + if (qh->channel != NULL) {
34029 + dwc_hc_t *hc = qh->channel;
34030 + dwc_list_link_t *item;
34031 + dwc_otg_qh_t *qh_item;
34032 + int num_channels = hcd->core_if->core_params->host_channels;
34033 + int i;
34034 +
34035 + dwc_otg_hc_regs_t *hc_regs;
34036 + hcchar_data_t hcchar;
34037 + hcsplt_data_t hcsplt;
34038 + hctsiz_data_t hctsiz;
34039 + uint32_t hcdma;
34040 +
34041 + hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
34042 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
34043 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
34044 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
34045 + hcdma = DWC_READ_REG32(&hc_regs->hcdma);
34046 +
34047 + DWC_PRINTF(" Assigned to channel %p:\n", hc);
34048 + DWC_PRINTF(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32,
34049 + hcsplt.d32);
34050 + DWC_PRINTF(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32,
34051 + hcdma);
34052 + DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
34053 + hc->dev_addr, hc->ep_num, hc->ep_is_in);
34054 + DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
34055 + DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
34056 + DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
34057 + DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
34058 + DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
34059 + DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
34060 + DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
34061 + DWC_PRINTF(" qh: %p\n", hc->qh);
34062 + DWC_PRINTF(" NP inactive sched:\n");
34063 + DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_inactive) {
34064 + qh_item =
34065 + DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
34066 + DWC_PRINTF(" %p\n", qh_item);
34067 + }
34068 + DWC_PRINTF(" NP active sched:\n");
34069 + DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_active) {
34070 + qh_item =
34071 + DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
34072 + DWC_PRINTF(" %p\n", qh_item);
34073 + }
34074 + DWC_PRINTF(" Channels: \n");
34075 + for (i = 0; i < num_channels; i++) {
34076 + dwc_hc_t *hc = hcd->hc_ptr_array[i];
34077 + DWC_PRINTF(" %2d: %p\n", i, hc);
34078 + }
34079 + }
34080 +}
34081 +#else
34082 +#define dump_channel_info(hcd, qh)
34083 +#endif /* DEBUG */
34084 +
34085 +/**
34086 + * Work queue function for starting the HCD when A-Cable is connected.
34087 + * The hcd_start() must be called in a process context.
34088 + */
34089 +static void hcd_start_func(void *_vp)
34090 +{
34091 + dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) _vp;
34092 +
34093 + DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, hcd);
34094 + if (hcd) {
34095 + hcd->fops->start(hcd);
34096 + }
34097 +}
34098 +
34099 +static void del_xfer_timers(dwc_otg_hcd_t * hcd)
34100 +{
34101 +#ifdef DEBUG
34102 + int i;
34103 + int num_channels = hcd->core_if->core_params->host_channels;
34104 + for (i = 0; i < num_channels; i++) {
34105 + DWC_TIMER_CANCEL(hcd->core_if->hc_xfer_timer[i]);
34106 + }
34107 +#endif
34108 +}
34109 +
34110 +static void del_timers(dwc_otg_hcd_t * hcd)
34111 +{
34112 + del_xfer_timers(hcd);
34113 + DWC_TIMER_CANCEL(hcd->conn_timer);
34114 +}
34115 +
34116 +/**
34117 + * Processes all the URBs in a single list of QHs. Completes them with
34118 + * -ETIMEDOUT and frees the QTD.
34119 + */
34120 +static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
34121 +{
34122 + dwc_list_link_t *qh_item;
34123 + dwc_otg_qh_t *qh;
34124 + dwc_otg_qtd_t *qtd, *qtd_tmp;
34125 +
34126 + DWC_LIST_FOREACH(qh_item, qh_list) {
34127 + qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
34128 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
34129 + &qh->qtd_list, qtd_list_entry) {
34130 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
34131 + if (qtd->urb != NULL) {
34132 + hcd->fops->complete(hcd, qtd->urb->priv,
34133 + qtd->urb, -DWC_E_TIMEOUT);
34134 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
34135 + }
34136 +
34137 + }
34138 + }
34139 +}
34140 +
34141 +/**
34142 + * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic
34143 + * and periodic schedules. The QTD associated with each URB is removed from
34144 + * the schedule and freed. This function may be called when a disconnect is
34145 + * detected or when the HCD is being stopped.
34146 + */
34147 +static void kill_all_urbs(dwc_otg_hcd_t * hcd)
34148 +{
34149 + kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive);
34150 + kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active);
34151 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive);
34152 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready);
34153 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned);
34154 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued);
34155 +}
34156 +
34157 +/**
34158 + * Start the connection timer. An OTG host is required to display a
34159 + * message if the device does not connect within 10 seconds. The
34160 + * timer is deleted if a port connect interrupt occurs before the
34161 + * timer expires.
34162 + */
34163 +static void dwc_otg_hcd_start_connect_timer(dwc_otg_hcd_t * hcd)
34164 +{
34165 + DWC_TIMER_SCHEDULE(hcd->conn_timer, 10000 /* 10 secs */ );
34166 +}
34167 +
34168 +/**
34169 + * HCD Callback function for disconnect of the HCD.
34170 + *
34171 + * @param p void pointer to the <code>struct usb_hcd</code>
34172 + */
34173 +static int32_t dwc_otg_hcd_session_start_cb(void *p)
34174 +{
34175 + dwc_otg_hcd_t *dwc_otg_hcd;
34176 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
34177 + dwc_otg_hcd = p;
34178 + dwc_otg_hcd_start_connect_timer(dwc_otg_hcd);
34179 + return 1;
34180 +}
34181 +
34182 +/**
34183 + * HCD Callback function for starting the HCD when A-Cable is
34184 + * connected.
34185 + *
34186 + * @param p void pointer to the <code>struct usb_hcd</code>
34187 + */
34188 +static int32_t dwc_otg_hcd_start_cb(void *p)
34189 +{
34190 + dwc_otg_hcd_t *dwc_otg_hcd = p;
34191 + dwc_otg_core_if_t *core_if;
34192 + hprt0_data_t hprt0;
34193 +
34194 + core_if = dwc_otg_hcd->core_if;
34195 +
34196 + if (core_if->op_state == B_HOST) {
34197 + /*
34198 + * Reset the port. During a HNP mode switch the reset
34199 + * needs to occur within 1ms and have a duration of at
34200 + * least 50ms.
34201 + */
34202 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
34203 + hprt0.b.prtrst = 1;
34204 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
34205 + }
34206 + DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg,
34207 + hcd_start_func, dwc_otg_hcd, 50,
34208 + "start hcd");
34209 +
34210 + return 1;
34211 +}
34212 +
34213 +/**
34214 + * HCD Callback function for disconnect of the HCD.
34215 + *
34216 + * @param p void pointer to the <code>struct usb_hcd</code>
34217 + */
34218 +static int32_t dwc_otg_hcd_disconnect_cb(void *p)
34219 +{
34220 + gintsts_data_t intr;
34221 + dwc_otg_hcd_t *dwc_otg_hcd = p;
34222 +
34223 + /*
34224 + * Set status flags for the hub driver.
34225 + */
34226 + dwc_otg_hcd->flags.b.port_connect_status_change = 1;
34227 + dwc_otg_hcd->flags.b.port_connect_status = 0;
34228 +
34229 + /*
34230 + * Shutdown any transfers in process by clearing the Tx FIFO Empty
34231 + * interrupt mask and status bits and disabling subsequent host
34232 + * channel interrupts.
34233 + */
34234 + intr.d32 = 0;
34235 + intr.b.nptxfempty = 1;
34236 + intr.b.ptxfempty = 1;
34237 + intr.b.hcintr = 1;
34238 + DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk,
34239 + intr.d32, 0);
34240 + DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintsts,
34241 + intr.d32, 0);
34242 +
34243 + del_timers(dwc_otg_hcd);
34244 +
34245 + /*
34246 + * Turn off the vbus power only if the core has transitioned to device
34247 + * mode. If still in host mode, need to keep power on to detect a
34248 + * reconnection.
34249 + */
34250 + if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) {
34251 + if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) {
34252 + hprt0_data_t hprt0 = {.d32 = 0 };
34253 + DWC_PRINTF("Disconnect: PortPower off\n");
34254 + hprt0.b.prtpwr = 0;
34255 + DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0,
34256 + hprt0.d32);
34257 + }
34258 +
34259 + dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);
34260 + }
34261 +
34262 + /* Respond with an error status to all URBs in the schedule. */
34263 + kill_all_urbs(dwc_otg_hcd);
34264 +
34265 + if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
34266 + /* Clean up any host channels that were in use. */
34267 + int num_channels;
34268 + int i;
34269 + dwc_hc_t *channel;
34270 + dwc_otg_hc_regs_t *hc_regs;
34271 + hcchar_data_t hcchar;
34272 +
34273 + num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
34274 +
34275 + if (!dwc_otg_hcd->core_if->dma_enable) {
34276 + /* Flush out any channel requests in slave mode. */
34277 + for (i = 0; i < num_channels; i++) {
34278 + channel = dwc_otg_hcd->hc_ptr_array[i];
34279 + if (DWC_CIRCLEQ_EMPTY_ENTRY
34280 + (channel, hc_list_entry)) {
34281 + hc_regs =
34282 + dwc_otg_hcd->core_if->
34283 + host_if->hc_regs[i];
34284 + hcchar.d32 =
34285 + DWC_READ_REG32(&hc_regs->hcchar);
34286 + if (hcchar.b.chen) {
34287 + hcchar.b.chen = 0;
34288 + hcchar.b.chdis = 1;
34289 + hcchar.b.epdir = 0;
34290 + DWC_WRITE_REG32
34291 + (&hc_regs->hcchar,
34292 + hcchar.d32);
34293 + }
34294 + }
34295 + }
34296 + }
34297 +
34298 + for (i = 0; i < num_channels; i++) {
34299 + channel = dwc_otg_hcd->hc_ptr_array[i];
34300 + if (DWC_CIRCLEQ_EMPTY_ENTRY(channel, hc_list_entry)) {
34301 + hc_regs =
34302 + dwc_otg_hcd->core_if->host_if->hc_regs[i];
34303 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
34304 + if (hcchar.b.chen) {
34305 + /* Halt the channel. */
34306 + hcchar.b.chdis = 1;
34307 + DWC_WRITE_REG32(&hc_regs->hcchar,
34308 + hcchar.d32);
34309 + }
34310 +
34311 + dwc_otg_hc_cleanup(dwc_otg_hcd->core_if,
34312 + channel);
34313 + DWC_CIRCLEQ_INSERT_TAIL
34314 + (&dwc_otg_hcd->free_hc_list, channel,
34315 + hc_list_entry);
34316 + /*
34317 + * Added for Descriptor DMA to prevent channel double cleanup
34318 + * in release_channel_ddma(). Which called from ep_disable
34319 + * when device disconnect.
34320 + */
34321 + channel->qh = NULL;
34322 + }
34323 + }
34324 + }
34325 +
34326 + if (dwc_otg_hcd->fops->disconnect) {
34327 + dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
34328 + }
34329 +
34330 + return 1;
34331 +}
34332 +
34333 +/**
34334 + * HCD Callback function for stopping the HCD.
34335 + *
34336 + * @param p void pointer to the <code>struct usb_hcd</code>
34337 + */
34338 +static int32_t dwc_otg_hcd_stop_cb(void *p)
34339 +{
34340 + dwc_otg_hcd_t *dwc_otg_hcd = p;
34341 +
34342 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
34343 + dwc_otg_hcd_stop(dwc_otg_hcd);
34344 + return 1;
34345 +}
34346 +
34347 +#ifdef CONFIG_USB_DWC_OTG_LPM
34348 +/**
34349 + * HCD Callback function for sleep of HCD.
34350 + *
34351 + * @param p void pointer to the <code>struct usb_hcd</code>
34352 + */
34353 +static int dwc_otg_hcd_sleep_cb(void *p)
34354 +{
34355 + dwc_otg_hcd_t *hcd = p;
34356 +
34357 + dwc_otg_hcd_free_hc_from_lpm(hcd);
34358 +
34359 + return 0;
34360 +}
34361 +#endif
34362 +
34363 +/**
34364 + * HCD Callback function for Remote Wakeup.
34365 + *
34366 + * @param p void pointer to the <code>struct usb_hcd</code>
34367 + */
34368 +static int dwc_otg_hcd_rem_wakeup_cb(void *p)
34369 +{
34370 + dwc_otg_hcd_t *hcd = p;
34371 +
34372 + if (hcd->core_if->lx_state == DWC_OTG_L2) {
34373 + hcd->flags.b.port_suspend_change = 1;
34374 + }
34375 +#ifdef CONFIG_USB_DWC_OTG_LPM
34376 + else {
34377 + hcd->flags.b.port_l1_change = 1;
34378 + }
34379 +#endif
34380 + return 0;
34381 +}
34382 +
34383 +/**
34384 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
34385 + * stopped.
34386 + */
34387 +void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd)
34388 +{
34389 + hprt0_data_t hprt0 = {.d32 = 0 };
34390 +
34391 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
34392 +
34393 + /*
34394 + * The root hub should be disconnected before this function is called.
34395 + * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
34396 + * and the QH lists (via ..._hcd_endpoint_disable).
34397 + */
34398 +
34399 + /* Turn off all host-specific interrupts. */
34400 + dwc_otg_disable_host_interrupts(hcd->core_if);
34401 +
34402 + /* Turn off the vbus power */
34403 + DWC_PRINTF("PortPower off\n");
34404 + hprt0.b.prtpwr = 0;
34405 + DWC_WRITE_REG32(hcd->core_if->host_if->hprt0, hprt0.d32);
34406 + dwc_mdelay(1);
34407 +}
34408 +
34409 +int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
34410 + dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
34411 + int atomic_alloc)
34412 +{
34413 + dwc_irqflags_t flags;
34414 + int retval = 0;
34415 + dwc_otg_qtd_t *qtd;
34416 + gintmsk_data_t intr_mask = {.d32 = 0 };
34417 +
34418 +#ifdef DEBUG /* integrity checks (Broadcom) */
34419 + if (NULL == hcd->core_if) {
34420 + DWC_ERROR("**** DWC OTG HCD URB Enqueue - HCD has NULL core_if\n");
34421 + /* No longer connected. */
34422 + return -DWC_E_INVALID;
34423 + }
34424 +#endif
34425 + if (!hcd->flags.b.port_connect_status) {
34426 + /* No longer connected. */
34427 + DWC_ERROR("Not connected\n");
34428 + return -DWC_E_NO_DEVICE;
34429 + }
34430 +
34431 + qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc);
34432 + if (qtd == NULL) {
34433 + DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
34434 + return -DWC_E_NO_MEMORY;
34435 + }
34436 +#ifdef DEBUG /* integrity checks (Broadcom) */
34437 + if (qtd->urb == NULL) {
34438 + DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD with no URBs\n");
34439 + return -DWC_E_NO_MEMORY;
34440 + }
34441 + if (qtd->urb->priv == NULL) {
34442 + DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD URB with no URB handle\n");
34443 + return -DWC_E_NO_MEMORY;
34444 + }
34445 +#endif
34446 + retval =
34447 + dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
34448 + // creates a new queue in ep_handle if it doesn't exist already
34449 + if (retval < 0) {
34450 + DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
34451 + "Error status %d\n", retval);
34452 + dwc_otg_hcd_qtd_free(qtd);
34453 + } else {
34454 + qtd->qh = *ep_handle;
34455 + }
34456 + intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
34457 + if (!intr_mask.b.sofintr && retval == 0) {
34458 + dwc_otg_transaction_type_e tr_type;
34459 + if ((qtd->qh->ep_type == UE_BULK)
34460 + && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) {
34461 + /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
34462 + return 0;
34463 + }
34464 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34465 + tr_type = dwc_otg_hcd_select_transactions(hcd);
34466 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
34467 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
34468 + }
34469 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34470 + }
34471 +
34472 + return retval;
34473 +}
34474 +
34475 +int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
34476 + dwc_otg_hcd_urb_t * dwc_otg_urb)
34477 +{
34478 + dwc_otg_qh_t *qh;
34479 + dwc_otg_qtd_t *urb_qtd;
34480 +
34481 +#ifdef DEBUG /* integrity checks (Broadcom) */
34482 +
34483 + if (hcd == NULL) {
34484 + DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL HCD\n");
34485 + return -DWC_E_INVALID;
34486 + }
34487 + if (dwc_otg_urb == NULL) {
34488 + DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL URB\n");
34489 + return -DWC_E_INVALID;
34490 + }
34491 + if (dwc_otg_urb->qtd == NULL) {
34492 + DWC_ERROR("**** DWC OTG HCD URB Dequeue with NULL QTD\n");
34493 + return -DWC_E_INVALID;
34494 + }
34495 + urb_qtd = dwc_otg_urb->qtd;
34496 + if (urb_qtd->qh == NULL) {
34497 + DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n");
34498 + return -DWC_E_INVALID;
34499 + }
34500 +#else
34501 + urb_qtd = dwc_otg_urb->qtd;
34502 +#endif
34503 + qh = urb_qtd->qh;
34504 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
34505 + if (urb_qtd->in_process) {
34506 + dump_channel_info(hcd, qh);
34507 + }
34508 + }
34509 +#ifdef DEBUG /* integrity checks (Broadcom) */
34510 + if (hcd->core_if == NULL) {
34511 + DWC_ERROR("**** DWC OTG HCD URB Dequeue HCD has NULL core_if\n");
34512 + return -DWC_E_INVALID;
34513 + }
34514 +#endif
34515 + if (urb_qtd->in_process && qh->channel) {
34516 + /* The QTD is in process (it has been assigned to a channel). */
34517 + if (hcd->flags.b.port_connect_status) {
34518 + /*
34519 + * If still connected (i.e. in host mode), halt the
34520 + * channel so it can be used for other transfers. If
34521 + * no longer connected, the host registers can't be
34522 + * written to halt the channel since the core is in
34523 + * device mode.
34524 + */
34525 + dwc_otg_hc_halt(hcd->core_if, qh->channel,
34526 + DWC_OTG_HC_XFER_URB_DEQUEUE);
34527 + }
34528 + }
34529 +
34530 + /*
34531 + * Free the QTD and clean up the associated QH. Leave the QH in the
34532 + * schedule if it has any remaining QTDs.
34533 + */
34534 +
34535 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue - "
34536 + "delete %sQueue handler\n",
34537 + hcd->core_if->dma_desc_enable?"DMA ":"");
34538 + if (!hcd->core_if->dma_desc_enable) {
34539 + uint8_t b = urb_qtd->in_process;
34540 + dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
34541 + if (b) {
34542 + dwc_otg_hcd_qh_deactivate(hcd, qh, 0);
34543 + qh->channel = NULL;
34544 + } else if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
34545 + dwc_otg_hcd_qh_remove(hcd, qh);
34546 + }
34547 + } else {
34548 + dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
34549 + }
34550 + return 0;
34551 +}
34552 +
34553 +int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
34554 + int retry)
34555 +{
34556 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
34557 + int retval = 0;
34558 + dwc_irqflags_t flags;
34559 +
34560 + if (retry < 0) {
34561 + retval = -DWC_E_INVALID;
34562 + goto done;
34563 + }
34564 +
34565 + if (!qh) {
34566 + retval = -DWC_E_INVALID;
34567 + goto done;
34568 + }
34569 +
34570 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34571 +
34572 + while (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list) && retry) {
34573 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34574 + retry--;
34575 + dwc_msleep(5);
34576 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34577 + }
34578 +
34579 + dwc_otg_hcd_qh_remove(hcd, qh);
34580 +
34581 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34582 + /*
34583 + * Split dwc_otg_hcd_qh_remove_and_free() into qh_remove
34584 + * and qh_free to prevent stack dump on DWC_DMA_FREE() with
34585 + * irq_disabled (spinlock_irqsave) in dwc_otg_hcd_desc_list_free()
34586 + * and dwc_otg_hcd_frame_list_alloc().
34587 + */
34588 + dwc_otg_hcd_qh_free(hcd, qh);
34589 +
34590 +done:
34591 + return retval;
34592 +}
34593 +
34594 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
34595 +int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle)
34596 +{
34597 + int retval = 0;
34598 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
34599 + if (!qh)
34600 + return -DWC_E_INVALID;
34601 +
34602 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
34603 + return retval;
34604 +}
34605 +#endif
34606 +
34607 +/**
34608 + * HCD Callback structure for handling mode switching.
34609 + */
34610 +static dwc_otg_cil_callbacks_t hcd_cil_callbacks = {
34611 + .start = dwc_otg_hcd_start_cb,
34612 + .stop = dwc_otg_hcd_stop_cb,
34613 + .disconnect = dwc_otg_hcd_disconnect_cb,
34614 + .session_start = dwc_otg_hcd_session_start_cb,
34615 + .resume_wakeup = dwc_otg_hcd_rem_wakeup_cb,
34616 +#ifdef CONFIG_USB_DWC_OTG_LPM
34617 + .sleep = dwc_otg_hcd_sleep_cb,
34618 +#endif
34619 + .p = 0,
34620 +};
34621 +
34622 +/**
34623 + * Reset tasklet function
34624 + */
34625 +static void reset_tasklet_func(void *data)
34626 +{
34627 + dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data;
34628 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
34629 + hprt0_data_t hprt0;
34630 +
34631 + DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
34632 +
34633 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
34634 + hprt0.b.prtrst = 1;
34635 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
34636 + dwc_mdelay(60);
34637 +
34638 + hprt0.b.prtrst = 0;
34639 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
34640 + dwc_otg_hcd->flags.b.port_reset_change = 1;
34641 +}
34642 +
34643 +static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
34644 +{
34645 + dwc_list_link_t *item;
34646 + dwc_otg_qh_t *qh;
34647 + dwc_irqflags_t flags;
34648 +
34649 + if (!qh_list->next) {
34650 + /* The list hasn't been initialized yet. */
34651 + return;
34652 + }
34653 + /*
34654 + * Hold spinlock here. Not needed in that case if bellow
34655 + * function is being called from ISR
34656 + */
34657 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34658 + /* Ensure there are no QTDs or URBs left. */
34659 + kill_urbs_in_qh_list(hcd, qh_list);
34660 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34661 +
34662 + DWC_LIST_FOREACH(item, qh_list) {
34663 + qh = DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
34664 + dwc_otg_hcd_qh_remove_and_free(hcd, qh);
34665 + }
34666 +}
34667 +
34668 +/**
34669 + * Exit from Hibernation if Host did not detect SRP from connected SRP capable
34670 + * Device during SRP time by host power up.
34671 + */
34672 +void dwc_otg_hcd_power_up(void *ptr)
34673 +{
34674 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
34675 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
34676 +
34677 + DWC_PRINTF("%s called\n", __FUNCTION__);
34678 +
34679 + if (!core_if->hibernation_suspend) {
34680 + DWC_PRINTF("Already exited from Hibernation\n");
34681 + return;
34682 + }
34683 +
34684 + /* Switch on the voltage to the core */
34685 + gpwrdn.b.pwrdnswtch = 1;
34686 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34687 + dwc_udelay(10);
34688 +
34689 + /* Reset the core */
34690 + gpwrdn.d32 = 0;
34691 + gpwrdn.b.pwrdnrstn = 1;
34692 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34693 + dwc_udelay(10);
34694 +
34695 + /* Disable power clamps */
34696 + gpwrdn.d32 = 0;
34697 + gpwrdn.b.pwrdnclmp = 1;
34698 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34699 +
34700 + /* Remove reset the core signal */
34701 + gpwrdn.d32 = 0;
34702 + gpwrdn.b.pwrdnrstn = 1;
34703 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
34704 + dwc_udelay(10);
34705 +
34706 + /* Disable PMU interrupt */
34707 + gpwrdn.d32 = 0;
34708 + gpwrdn.b.pmuintsel = 1;
34709 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34710 +
34711 + core_if->hibernation_suspend = 0;
34712 +
34713 + /* Disable PMU */
34714 + gpwrdn.d32 = 0;
34715 + gpwrdn.b.pmuactv = 1;
34716 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34717 + dwc_udelay(10);
34718 +
34719 + /* Enable VBUS */
34720 + gpwrdn.d32 = 0;
34721 + gpwrdn.b.dis_vbus = 1;
34722 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34723 +
34724 + core_if->op_state = A_HOST;
34725 + dwc_otg_core_init(core_if);
34726 + dwc_otg_enable_global_interrupts(core_if);
34727 + cil_hcd_start(core_if);
34728 +}
34729 +
34730 +/**
34731 + * Frees secondary storage associated with the dwc_otg_hcd structure contained
34732 + * in the struct usb_hcd field.
34733 + */
34734 +static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)
34735 +{
34736 + int i;
34737 +
34738 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
34739 +
34740 + del_timers(dwc_otg_hcd);
34741 +
34742 + /* Free memory for QH/QTD lists */
34743 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
34744 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
34745 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
34746 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
34747 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
34748 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
34749 +
34750 + /* Free memory for the host channels. */
34751 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
34752 + dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i];
34753 +
34754 +#ifdef DEBUG
34755 + if (dwc_otg_hcd->core_if->hc_xfer_timer[i]) {
34756 + DWC_TIMER_FREE(dwc_otg_hcd->core_if->hc_xfer_timer[i]);
34757 + }
34758 +#endif
34759 + if (hc != NULL) {
34760 + DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n",
34761 + i, hc);
34762 + DWC_FREE(hc);
34763 + }
34764 + }
34765 +
34766 + if (dwc_otg_hcd->core_if->dma_enable) {
34767 + if (dwc_otg_hcd->status_buf_dma) {
34768 + DWC_DMA_FREE(DWC_OTG_HCD_STATUS_BUF_SIZE,
34769 + dwc_otg_hcd->status_buf,
34770 + dwc_otg_hcd->status_buf_dma);
34771 + }
34772 + } else if (dwc_otg_hcd->status_buf != NULL) {
34773 + DWC_FREE(dwc_otg_hcd->status_buf);
34774 + }
34775 + DWC_SPINLOCK_FREE(dwc_otg_hcd->lock);
34776 + /* Set core_if's lock pointer to NULL */
34777 + dwc_otg_hcd->core_if->lock = NULL;
34778 +
34779 + DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
34780 + DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
34781 +
34782 +#ifdef DWC_DEV_SRPCAP
34783 + if (dwc_otg_hcd->core_if->power_down == 2 &&
34784 + dwc_otg_hcd->core_if->pwron_timer) {
34785 + DWC_TIMER_FREE(dwc_otg_hcd->core_if->pwron_timer);
34786 + }
34787 +#endif
34788 + DWC_FREE(dwc_otg_hcd);
34789 +}
34790 +
34791 +int init_hcd_usecs(dwc_otg_hcd_t *_hcd);
34792 +
34793 +int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
34794 +{
34795 + int retval = 0;
34796 + int num_channels;
34797 + int i;
34798 + dwc_hc_t *channel;
34799 +
34800 + hcd->lock = DWC_SPINLOCK_ALLOC();
34801 + DWC_DEBUGPL(DBG_HCDV, "init of HCD %p given core_if %p\n",
34802 + hcd, core_if);
34803 + if (!hcd->lock) {
34804 + DWC_ERROR("Could not allocate lock for pcd");
34805 + DWC_FREE(hcd);
34806 + retval = -DWC_E_NO_MEMORY;
34807 + goto out;
34808 + }
34809 + hcd->core_if = core_if;
34810 +
34811 + /* Register the HCD CIL Callbacks */
34812 + dwc_otg_cil_register_hcd_callbacks(hcd->core_if,
34813 + &hcd_cil_callbacks, hcd);
34814 +
34815 + /* Initialize the non-periodic schedule. */
34816 + DWC_LIST_INIT(&hcd->non_periodic_sched_inactive);
34817 + DWC_LIST_INIT(&hcd->non_periodic_sched_active);
34818 +
34819 + /* Initialize the periodic schedule. */
34820 + DWC_LIST_INIT(&hcd->periodic_sched_inactive);
34821 + DWC_LIST_INIT(&hcd->periodic_sched_ready);
34822 + DWC_LIST_INIT(&hcd->periodic_sched_assigned);
34823 + DWC_LIST_INIT(&hcd->periodic_sched_queued);
34824 +
34825 + /*
34826 + * Create a host channel descriptor for each host channel implemented
34827 + * in the controller. Initialize the channel descriptor array.
34828 + */
34829 + DWC_CIRCLEQ_INIT(&hcd->free_hc_list);
34830 + num_channels = hcd->core_if->core_params->host_channels;
34831 + DWC_MEMSET(hcd->hc_ptr_array, 0, sizeof(hcd->hc_ptr_array));
34832 + for (i = 0; i < num_channels; i++) {
34833 + channel = DWC_ALLOC(sizeof(dwc_hc_t));
34834 + if (channel == NULL) {
34835 + retval = -DWC_E_NO_MEMORY;
34836 + DWC_ERROR("%s: host channel allocation failed\n",
34837 + __func__);
34838 + dwc_otg_hcd_free(hcd);
34839 + goto out;
34840 + }
34841 + channel->hc_num = i;
34842 + hcd->hc_ptr_array[i] = channel;
34843 +#ifdef DEBUG
34844 + hcd->core_if->hc_xfer_timer[i] =
34845 + DWC_TIMER_ALLOC("hc timer", hc_xfer_timeout,
34846 + &hcd->core_if->hc_xfer_info[i]);
34847 +#endif
34848 + DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i,
34849 + channel);
34850 + }
34851 +
34852 + /* Initialize the Connection timeout timer. */
34853 + hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer",
34854 + dwc_otg_hcd_connect_timeout, 0);
34855 +
34856 + printk(KERN_DEBUG "dwc_otg: Microframe scheduler %s\n", microframe_schedule ? "enabled":"disabled");
34857 + if (microframe_schedule)
34858 + init_hcd_usecs(hcd);
34859 +
34860 + /* Initialize reset tasklet. */
34861 + hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd);
34862 +#ifdef DWC_DEV_SRPCAP
34863 + if (hcd->core_if->power_down == 2) {
34864 + /* Initialize Power on timer for Host power up in case hibernation */
34865 + hcd->core_if->pwron_timer = DWC_TIMER_ALLOC("PWRON TIMER",
34866 + dwc_otg_hcd_power_up, core_if);
34867 + }
34868 +#endif
34869 +
34870 + /*
34871 + * Allocate space for storing data on status transactions. Normally no
34872 + * data is sent, but this space acts as a bit bucket. This must be
34873 + * done after usb_add_hcd since that function allocates the DMA buffer
34874 + * pool.
34875 + */
34876 + if (hcd->core_if->dma_enable) {
34877 + hcd->status_buf =
34878 + DWC_DMA_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE,
34879 + &hcd->status_buf_dma);
34880 + } else {
34881 + hcd->status_buf = DWC_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE);
34882 + }
34883 + if (!hcd->status_buf) {
34884 + retval = -DWC_E_NO_MEMORY;
34885 + DWC_ERROR("%s: status_buf allocation failed\n", __func__);
34886 + dwc_otg_hcd_free(hcd);
34887 + goto out;
34888 + }
34889 +
34890 + hcd->otg_port = 1;
34891 + hcd->frame_list = NULL;
34892 + hcd->frame_list_dma = 0;
34893 + hcd->periodic_qh_count = 0;
34894 +out:
34895 + return retval;
34896 +}
34897 +
34898 +void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd)
34899 +{
34900 + /* Turn off all host-specific interrupts. */
34901 + dwc_otg_disable_host_interrupts(hcd->core_if);
34902 +
34903 + dwc_otg_hcd_free(hcd);
34904 +}
34905 +
34906 +/**
34907 + * Initializes dynamic portions of the DWC_otg HCD state.
34908 + */
34909 +static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd)
34910 +{
34911 + int num_channels;
34912 + int i;
34913 + dwc_hc_t *channel;
34914 + dwc_hc_t *channel_tmp;
34915 +
34916 + hcd->flags.d32 = 0;
34917 +
34918 + hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
34919 + if (!microframe_schedule) {
34920 + hcd->non_periodic_channels = 0;
34921 + hcd->periodic_channels = 0;
34922 + } else {
34923 + hcd->available_host_channels = hcd->core_if->core_params->host_channels;
34924 + }
34925 + /*
34926 + * Put all channels in the free channel list and clean up channel
34927 + * states.
34928 + */
34929 + DWC_CIRCLEQ_FOREACH_SAFE(channel, channel_tmp,
34930 + &hcd->free_hc_list, hc_list_entry) {
34931 + DWC_CIRCLEQ_REMOVE(&hcd->free_hc_list, channel, hc_list_entry);
34932 + }
34933 +
34934 + num_channels = hcd->core_if->core_params->host_channels;
34935 + for (i = 0; i < num_channels; i++) {
34936 + channel = hcd->hc_ptr_array[i];
34937 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, channel,
34938 + hc_list_entry);
34939 + dwc_otg_hc_cleanup(hcd->core_if, channel);
34940 + }
34941 +
34942 + /* Initialize the DWC core for host mode operation. */
34943 + dwc_otg_core_host_init(hcd->core_if);
34944 +
34945 + /* Set core_if's lock pointer to the hcd->lock */
34946 + hcd->core_if->lock = hcd->lock;
34947 +}
34948 +
34949 +/**
34950 + * Assigns transactions from a QTD to a free host channel and initializes the
34951 + * host channel to perform the transactions. The host channel is removed from
34952 + * the free list.
34953 + *
34954 + * @param hcd The HCD state structure.
34955 + * @param qh Transactions from the first QTD for this QH are selected and
34956 + * assigned to a free host channel.
34957 + */
34958 +static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
34959 +{
34960 + dwc_hc_t *hc;
34961 + dwc_otg_qtd_t *qtd;
34962 + dwc_otg_hcd_urb_t *urb;
34963 + void* ptr = NULL;
34964 +
34965 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
34966 +
34967 + urb = qtd->urb;
34968 +
34969 + DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p) - urb %x, actual_length %d\n", __func__, hcd, qh, (unsigned int)urb, urb->actual_length);
34970 +
34971 + if (((urb->actual_length < 0) || (urb->actual_length > urb->length)) && !dwc_otg_hcd_is_pipe_in(&urb->pipe_info))
34972 + urb->actual_length = urb->length;
34973 +
34974 +
34975 + hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
34976 +
34977 + /* Remove the host channel from the free list. */
34978 + DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
34979 +
34980 + qh->channel = hc;
34981 +
34982 + qtd->in_process = 1;
34983 +
34984 + /*
34985 + * Use usb_pipedevice to determine device address. This address is
34986 + * 0 before the SET_ADDRESS command and the correct address afterward.
34987 + */
34988 + hc->dev_addr = dwc_otg_hcd_get_dev_addr(&urb->pipe_info);
34989 + hc->ep_num = dwc_otg_hcd_get_ep_num(&urb->pipe_info);
34990 + hc->speed = qh->dev_speed;
34991 + hc->max_packet = dwc_max_packet(qh->maxp);
34992 +
34993 + hc->xfer_started = 0;
34994 + hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
34995 + hc->error_state = (qtd->error_count > 0);
34996 + hc->halt_on_queue = 0;
34997 + hc->halt_pending = 0;
34998 + hc->requests = 0;
34999 +
35000 + /*
35001 + * The following values may be modified in the transfer type section
35002 + * below. The xfer_len value may be reduced when the transfer is
35003 + * started to accommodate the max widths of the XferSize and PktCnt
35004 + * fields in the HCTSIZn register.
35005 + */
35006 +
35007 + hc->ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0);
35008 + if (hc->ep_is_in) {
35009 + hc->do_ping = 0;
35010 + } else {
35011 + hc->do_ping = qh->ping_state;
35012 + }
35013 +
35014 + hc->data_pid_start = qh->data_toggle;
35015 + hc->multi_count = 1;
35016 +
35017 + if (hcd->core_if->dma_enable) {
35018 + hc->xfer_buff = (uint8_t *) urb->dma + urb->actual_length;
35019 +
35020 + /* For non-dword aligned case */
35021 + if (((unsigned long)hc->xfer_buff & 0x3)
35022 + && !hcd->core_if->dma_desc_enable) {
35023 + ptr = (uint8_t *) urb->buf + urb->actual_length;
35024 + }
35025 + } else {
35026 + hc->xfer_buff = (uint8_t *) urb->buf + urb->actual_length;
35027 + }
35028 + hc->xfer_len = urb->length - urb->actual_length;
35029 + hc->xfer_count = 0;
35030 +
35031 + /*
35032 + * Set the split attributes
35033 + */
35034 + hc->do_split = 0;
35035 + if (qh->do_split) {
35036 + uint32_t hub_addr, port_addr;
35037 + hc->do_split = 1;
35038 + hc->xact_pos = qtd->isoc_split_pos;
35039 + hc->complete_split = qtd->complete_split;
35040 + hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr);
35041 + hc->hub_addr = (uint8_t) hub_addr;
35042 + hc->port_addr = (uint8_t) port_addr;
35043 + }
35044 +
35045 + switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
35046 + case UE_CONTROL:
35047 + hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
35048 + switch (qtd->control_phase) {
35049 + case DWC_OTG_CONTROL_SETUP:
35050 + DWC_DEBUGPL(DBG_HCDV, " Control setup transaction\n");
35051 + hc->do_ping = 0;
35052 + hc->ep_is_in = 0;
35053 + hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
35054 + if (hcd->core_if->dma_enable) {
35055 + hc->xfer_buff = (uint8_t *) urb->setup_dma;
35056 + } else {
35057 + hc->xfer_buff = (uint8_t *) urb->setup_packet;
35058 + }
35059 + hc->xfer_len = 8;
35060 + ptr = NULL;
35061 + break;
35062 + case DWC_OTG_CONTROL_DATA:
35063 + DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n");
35064 + hc->data_pid_start = qtd->data_toggle;
35065 + break;
35066 + case DWC_OTG_CONTROL_STATUS:
35067 + /*
35068 + * Direction is opposite of data direction or IN if no
35069 + * data.
35070 + */
35071 + DWC_DEBUGPL(DBG_HCDV, " Control status transaction\n");
35072 + if (urb->length == 0) {
35073 + hc->ep_is_in = 1;
35074 + } else {
35075 + hc->ep_is_in =
35076 + dwc_otg_hcd_is_pipe_out(&urb->pipe_info);
35077 + }
35078 + if (hc->ep_is_in) {
35079 + hc->do_ping = 0;
35080 + }
35081 +
35082 + hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
35083 +
35084 + hc->xfer_len = 0;
35085 + if (hcd->core_if->dma_enable) {
35086 + hc->xfer_buff = (uint8_t *) hcd->status_buf_dma;
35087 + } else {
35088 + hc->xfer_buff = (uint8_t *) hcd->status_buf;
35089 + }
35090 + ptr = NULL;
35091 + break;
35092 + }
35093 + break;
35094 + case UE_BULK:
35095 + hc->ep_type = DWC_OTG_EP_TYPE_BULK;
35096 + break;
35097 + case UE_INTERRUPT:
35098 + hc->ep_type = DWC_OTG_EP_TYPE_INTR;
35099 + break;
35100 + case UE_ISOCHRONOUS:
35101 + {
35102 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
35103 +
35104 + hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
35105 +
35106 + if (hcd->core_if->dma_desc_enable)
35107 + break;
35108 +
35109 + frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
35110 +
35111 + frame_desc->status = 0;
35112 +
35113 + if (hcd->core_if->dma_enable) {
35114 + hc->xfer_buff = (uint8_t *) urb->dma;
35115 + } else {
35116 + hc->xfer_buff = (uint8_t *) urb->buf;
35117 + }
35118 + hc->xfer_buff +=
35119 + frame_desc->offset + qtd->isoc_split_offset;
35120 + hc->xfer_len =
35121 + frame_desc->length - qtd->isoc_split_offset;
35122 +
35123 + /* For non-dword aligned buffers */
35124 + if (((unsigned long)hc->xfer_buff & 0x3)
35125 + && hcd->core_if->dma_enable) {
35126 + ptr =
35127 + (uint8_t *) urb->buf + frame_desc->offset +
35128 + qtd->isoc_split_offset;
35129 + } else
35130 + ptr = NULL;
35131 +
35132 + if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
35133 + if (hc->xfer_len <= 188) {
35134 + hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
35135 + } else {
35136 + hc->xact_pos =
35137 + DWC_HCSPLIT_XACTPOS_BEGIN;
35138 + }
35139 + }
35140 + }
35141 + break;
35142 + }
35143 + /* non DWORD-aligned buffer case */
35144 + if (ptr) {
35145 + uint32_t buf_size;
35146 + if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
35147 + buf_size = hcd->core_if->core_params->max_transfer_size;
35148 + } else {
35149 + buf_size = 4096;
35150 + }
35151 + if (!qh->dw_align_buf) {
35152 + qh->dw_align_buf = DWC_DMA_ALLOC_ATOMIC(buf_size,
35153 + &qh->dw_align_buf_dma);
35154 + if (!qh->dw_align_buf) {
35155 + DWC_ERROR
35156 + ("%s: Failed to allocate memory to handle "
35157 + "non-dword aligned buffer case\n",
35158 + __func__);
35159 + return;
35160 + }
35161 + }
35162 + if (!hc->ep_is_in) {
35163 + dwc_memcpy(qh->dw_align_buf, ptr, hc->xfer_len);
35164 + }
35165 + hc->align_buff = qh->dw_align_buf_dma;
35166 + } else {
35167 + hc->align_buff = 0;
35168 + }
35169 +
35170 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
35171 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
35172 + /*
35173 + * This value may be modified when the transfer is started to
35174 + * reflect the actual transfer length.
35175 + */
35176 + hc->multi_count = dwc_hb_mult(qh->maxp);
35177 + }
35178 +
35179 + if (hcd->core_if->dma_desc_enable)
35180 + hc->desc_list_addr = qh->desc_list_dma;
35181 +
35182 + dwc_otg_hc_init(hcd->core_if, hc);
35183 + hc->qh = qh;
35184 +}
35185 +
35186 +/**
35187 + * This function selects transactions from the HCD transfer schedule and
35188 + * assigns them to available host channels. It is called from HCD interrupt
35189 + * handler functions.
35190 + *
35191 + * @param hcd The HCD state structure.
35192 + *
35193 + * @return The types of new transactions that were assigned to host channels.
35194 + */
35195 +dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
35196 +{
35197 + dwc_list_link_t *qh_ptr;
35198 + dwc_otg_qh_t *qh;
35199 + int num_channels;
35200 + dwc_irqflags_t flags;
35201 + dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
35202 + dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;
35203 +
35204 +#ifdef DEBUG_SOF
35205 + DWC_DEBUGPL(DBG_HCD, " Select Transactions\n");
35206 +#endif
35207 +
35208 +#ifdef DEBUG_HOST_CHANNELS
35209 + last_sel_trans_num_per_scheduled = 0;
35210 + last_sel_trans_num_nonper_scheduled = 0;
35211 + last_sel_trans_num_avail_hc_at_start = hcd->available_host_channels;
35212 +#endif /* DEBUG_HOST_CHANNELS */
35213 +
35214 + /* Process entries in the periodic ready list. */
35215 + qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready);
35216 +
35217 + while (qh_ptr != &hcd->periodic_sched_ready &&
35218 + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
35219 + if (microframe_schedule) {
35220 + // Make sure we leave one channel for non periodic transactions.
35221 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35222 + if (hcd->available_host_channels <= 1) {
35223 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35224 + break;
35225 + }
35226 + hcd->available_host_channels--;
35227 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35228 +#ifdef DEBUG_HOST_CHANNELS
35229 + last_sel_trans_num_per_scheduled++;
35230 +#endif /* DEBUG_HOST_CHANNELS */
35231 + }
35232 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
35233 + assign_and_init_hc(hcd, qh);
35234 +
35235 + /*
35236 + * Move the QH from the periodic ready schedule to the
35237 + * periodic assigned schedule.
35238 + */
35239 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
35240 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35241 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
35242 + &qh->qh_list_entry);
35243 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35244 +
35245 + ret_val = DWC_OTG_TRANSACTION_PERIODIC;
35246 + }
35247 +
35248 + /*
35249 + * Process entries in the inactive portion of the non-periodic
35250 + * schedule. Some free host channels may not be used if they are
35251 + * reserved for periodic transfers.
35252 + */
35253 + qh_ptr = hcd->non_periodic_sched_inactive.next;
35254 + num_channels = hcd->core_if->core_params->host_channels;
35255 + while (qh_ptr != &hcd->non_periodic_sched_inactive &&
35256 + (microframe_schedule || hcd->non_periodic_channels <
35257 + num_channels - hcd->periodic_channels) &&
35258 + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
35259 +
35260 + if (microframe_schedule) {
35261 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35262 + if (hcd->available_host_channels < 1) {
35263 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35264 + break;
35265 + }
35266 + hcd->available_host_channels--;
35267 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35268 +#ifdef DEBUG_HOST_CHANNELS
35269 + last_sel_trans_num_nonper_scheduled++;
35270 +#endif /* DEBUG_HOST_CHANNELS */
35271 + }
35272 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
35273 +
35274 + assign_and_init_hc(hcd, qh);
35275 +
35276 + /*
35277 + * Move the QH from the non-periodic inactive schedule to the
35278 + * non-periodic active schedule.
35279 + */
35280 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
35281 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35282 + DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active,
35283 + &qh->qh_list_entry);
35284 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35285 +
35286 + if (ret_val == DWC_OTG_TRANSACTION_NONE) {
35287 + ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
35288 + } else {
35289 + ret_val = DWC_OTG_TRANSACTION_ALL;
35290 + }
35291 +
35292 + if (!microframe_schedule)
35293 + hcd->non_periodic_channels++;
35294 + }
35295 +
35296 +#ifdef DEBUG_HOST_CHANNELS
35297 + last_sel_trans_num_avail_hc_at_end = hcd->available_host_channels;
35298 +#endif /* DEBUG_HOST_CHANNELS */
35299 +
35300 + DWC_SPINLOCK_FREE(channel_lock);
35301 + return ret_val;
35302 +}
35303 +
35304 +/**
35305 + * Attempts to queue a single transaction request for a host channel
35306 + * associated with either a periodic or non-periodic transfer. This function
35307 + * assumes that there is space available in the appropriate request queue. For
35308 + * an OUT transfer or SETUP transaction in Slave mode, it checks whether space
35309 + * is available in the appropriate Tx FIFO.
35310 + *
35311 + * @param hcd The HCD state structure.
35312 + * @param hc Host channel descriptor associated with either a periodic or
35313 + * non-periodic transfer.
35314 + * @param fifo_dwords_avail Number of DWORDs available in the periodic Tx
35315 + * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic
35316 + * transfers.
35317 + *
35318 + * @return 1 if a request is queued and more requests may be needed to
35319 + * complete the transfer, 0 if no more requests are required for this
35320 + * transfer, -1 if there is insufficient space in the Tx FIFO.
35321 + */
35322 +static int queue_transaction(dwc_otg_hcd_t * hcd,
35323 + dwc_hc_t * hc, uint16_t fifo_dwords_avail)
35324 +{
35325 + int retval;
35326 +
35327 + if (hcd->core_if->dma_enable) {
35328 + if (hcd->core_if->dma_desc_enable) {
35329 + if (!hc->xfer_started
35330 + || (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {
35331 + dwc_otg_hcd_start_xfer_ddma(hcd, hc->qh);
35332 + hc->qh->ping_state = 0;
35333 + }
35334 + } else if (!hc->xfer_started) {
35335 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35336 + hc->qh->ping_state = 0;
35337 + }
35338 + retval = 0;
35339 + } else if (hc->halt_pending) {
35340 + /* Don't queue a request if the channel has been halted. */
35341 + retval = 0;
35342 + } else if (hc->halt_on_queue) {
35343 + dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status);
35344 + retval = 0;
35345 + } else if (hc->do_ping) {
35346 + if (!hc->xfer_started) {
35347 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35348 + }
35349 + retval = 0;
35350 + } else if (!hc->ep_is_in || hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
35351 + if ((fifo_dwords_avail * 4) >= hc->max_packet) {
35352 + if (!hc->xfer_started) {
35353 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35354 + retval = 1;
35355 + } else {
35356 + retval =
35357 + dwc_otg_hc_continue_transfer(hcd->core_if,
35358 + hc);
35359 + }
35360 + } else {
35361 + retval = -1;
35362 + }
35363 + } else {
35364 + if (!hc->xfer_started) {
35365 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35366 + retval = 1;
35367 + } else {
35368 + retval = dwc_otg_hc_continue_transfer(hcd->core_if, hc);
35369 + }
35370 + }
35371 +
35372 + return retval;
35373 +}
35374 +
35375 +/**
35376 + * Processes periodic channels for the next frame and queues transactions for
35377 + * these channels to the DWC_otg controller. After queueing transactions, the
35378 + * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
35379 + * to queue as Periodic Tx FIFO or request queue space becomes available.
35380 + * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
35381 + */
35382 +static void process_periodic_channels(dwc_otg_hcd_t * hcd)
35383 +{
35384 + hptxsts_data_t tx_status;
35385 + dwc_list_link_t *qh_ptr;
35386 + dwc_otg_qh_t *qh;
35387 + int status;
35388 + int no_queue_space = 0;
35389 + int no_fifo_space = 0;
35390 +
35391 + dwc_otg_host_global_regs_t *host_regs;
35392 + host_regs = hcd->core_if->host_if->host_global_regs;
35393 +
35394 + DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n");
35395 +#ifdef DEBUG
35396 + tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
35397 + DWC_DEBUGPL(DBG_HCDV,
35398 + " P Tx Req Queue Space Avail (before queue): %d\n",
35399 + tx_status.b.ptxqspcavail);
35400 + DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (before queue): %d\n",
35401 + tx_status.b.ptxfspcavail);
35402 +#endif
35403 +
35404 + qh_ptr = hcd->periodic_sched_assigned.next;
35405 + while (qh_ptr != &hcd->periodic_sched_assigned) {
35406 + tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
35407 + if (tx_status.b.ptxqspcavail == 0) {
35408 + no_queue_space = 1;
35409 + break;
35410 + }
35411 +
35412 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
35413 +
35414 + /*
35415 + * Set a flag if we're queuing high-bandwidth in slave mode.
35416 + * The flag prevents any halts to get into the request queue in
35417 + * the middle of multiple high-bandwidth packets getting queued.
35418 + */
35419 + if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) {
35420 + hcd->core_if->queuing_high_bandwidth = 1;
35421 + }
35422 + status =
35423 + queue_transaction(hcd, qh->channel,
35424 + tx_status.b.ptxfspcavail);
35425 + if (status < 0) {
35426 + no_fifo_space = 1;
35427 + break;
35428 + }
35429 +
35430 + /*
35431 + * In Slave mode, stay on the current transfer until there is
35432 + * nothing more to do or the high-bandwidth request count is
35433 + * reached. In DMA mode, only need to queue one request. The
35434 + * controller automatically handles multiple packets for
35435 + * high-bandwidth transfers.
35436 + */
35437 + if (hcd->core_if->dma_enable || status == 0 ||
35438 + qh->channel->requests == qh->channel->multi_count) {
35439 + qh_ptr = qh_ptr->next;
35440 + /*
35441 + * Move the QH from the periodic assigned schedule to
35442 + * the periodic queued schedule.
35443 + */
35444 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_queued,
35445 + &qh->qh_list_entry);
35446 +
35447 + /* done queuing high bandwidth */
35448 + hcd->core_if->queuing_high_bandwidth = 0;
35449 + }
35450 + }
35451 +
35452 + if (!hcd->core_if->dma_enable) {
35453 + dwc_otg_core_global_regs_t *global_regs;
35454 + gintmsk_data_t intr_mask = {.d32 = 0 };
35455 +
35456 + global_regs = hcd->core_if->core_global_regs;
35457 + intr_mask.b.ptxfempty = 1;
35458 +#ifdef DEBUG
35459 + tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
35460 + DWC_DEBUGPL(DBG_HCDV,
35461 + " P Tx Req Queue Space Avail (after queue): %d\n",
35462 + tx_status.b.ptxqspcavail);
35463 + DWC_DEBUGPL(DBG_HCDV,
35464 + " P Tx FIFO Space Avail (after queue): %d\n",
35465 + tx_status.b.ptxfspcavail);
35466 +#endif
35467 + if (!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned) ||
35468 + no_queue_space || no_fifo_space) {
35469 + /*
35470 + * May need to queue more transactions as the request
35471 + * queue or Tx FIFO empties. Enable the periodic Tx
35472 + * FIFO empty interrupt. (Always use the half-empty
35473 + * level to ensure that new requests are loaded as
35474 + * soon as possible.)
35475 + */
35476 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
35477 + intr_mask.d32);
35478 + } else {
35479 + /*
35480 + * Disable the Tx FIFO empty interrupt since there are
35481 + * no more transactions that need to be queued right
35482 + * now. This function is called from interrupt
35483 + * handlers to queue more transactions as transfer
35484 + * states change.
35485 + */
35486 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
35487 + 0);
35488 + }
35489 + }
35490 +}
35491 +
35492 +/**
35493 + * Processes active non-periodic channels and queues transactions for these
35494 + * channels to the DWC_otg controller. After queueing transactions, the NP Tx
35495 + * FIFO Empty interrupt is enabled if there are more transactions to queue as
35496 + * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
35497 + * FIFO Empty interrupt is disabled.
35498 + */
35499 +static void process_non_periodic_channels(dwc_otg_hcd_t * hcd)
35500 +{
35501 + gnptxsts_data_t tx_status;
35502 + dwc_list_link_t *orig_qh_ptr;
35503 + dwc_otg_qh_t *qh;
35504 + int status;
35505 + int no_queue_space = 0;
35506 + int no_fifo_space = 0;
35507 + int more_to_do = 0;
35508 +
35509 + dwc_otg_core_global_regs_t *global_regs =
35510 + hcd->core_if->core_global_regs;
35511 +
35512 + DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n");
35513 +#ifdef DEBUG
35514 + tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
35515 + DWC_DEBUGPL(DBG_HCDV,
35516 + " NP Tx Req Queue Space Avail (before queue): %d\n",
35517 + tx_status.b.nptxqspcavail);
35518 + DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (before queue): %d\n",
35519 + tx_status.b.nptxfspcavail);
35520 +#endif
35521 + /*
35522 + * Keep track of the starting point. Skip over the start-of-list
35523 + * entry.
35524 + */
35525 + if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
35526 + hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
35527 + }
35528 + orig_qh_ptr = hcd->non_periodic_qh_ptr;
35529 +
35530 + /*
35531 + * Process once through the active list or until no more space is
35532 + * available in the request queue or the Tx FIFO.
35533 + */
35534 + do {
35535 + tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
35536 + if (!hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) {
35537 + no_queue_space = 1;
35538 + break;
35539 + }
35540 +
35541 + qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t,
35542 + qh_list_entry);
35543 + status =
35544 + queue_transaction(hcd, qh->channel,
35545 + tx_status.b.nptxfspcavail);
35546 +
35547 + if (status > 0) {
35548 + more_to_do = 1;
35549 + } else if (status < 0) {
35550 + no_fifo_space = 1;
35551 + break;
35552 + }
35553 +
35554 + /* Advance to next QH, skipping start-of-list entry. */
35555 + hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
35556 + if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
35557 + hcd->non_periodic_qh_ptr =
35558 + hcd->non_periodic_qh_ptr->next;
35559 + }
35560 +
35561 + } while (hcd->non_periodic_qh_ptr != orig_qh_ptr);
35562 +
35563 + if (!hcd->core_if->dma_enable) {
35564 + gintmsk_data_t intr_mask = {.d32 = 0 };
35565 + intr_mask.b.nptxfempty = 1;
35566 +
35567 +#ifdef DEBUG
35568 + tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
35569 + DWC_DEBUGPL(DBG_HCDV,
35570 + " NP Tx Req Queue Space Avail (after queue): %d\n",
35571 + tx_status.b.nptxqspcavail);
35572 + DWC_DEBUGPL(DBG_HCDV,
35573 + " NP Tx FIFO Space Avail (after queue): %d\n",
35574 + tx_status.b.nptxfspcavail);
35575 +#endif
35576 + if (more_to_do || no_queue_space || no_fifo_space) {
35577 + /*
35578 + * May need to queue more transactions as the request
35579 + * queue or Tx FIFO empties. Enable the non-periodic
35580 + * Tx FIFO empty interrupt. (Always use the half-empty
35581 + * level to ensure that new requests are loaded as
35582 + * soon as possible.)
35583 + */
35584 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
35585 + intr_mask.d32);
35586 + } else {
35587 + /*
35588 + * Disable the Tx FIFO empty interrupt since there are
35589 + * no more transactions that need to be queued right
35590 + * now. This function is called from interrupt
35591 + * handlers to queue more transactions as transfer
35592 + * states change.
35593 + */
35594 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
35595 + 0);
35596 + }
35597 + }
35598 +}
35599 +
35600 +/**
35601 + * This function processes the currently active host channels and queues
35602 + * transactions for these channels to the DWC_otg controller. It is called
35603 + * from HCD interrupt handler functions.
35604 + *
35605 + * @param hcd The HCD state structure.
35606 + * @param tr_type The type(s) of transactions to queue (non-periodic,
35607 + * periodic, or both).
35608 + */
35609 +void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
35610 + dwc_otg_transaction_type_e tr_type)
35611 +{
35612 +#ifdef DEBUG_SOF
35613 + DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n");
35614 +#endif
35615 + /* Process host channels associated with periodic transfers. */
35616 + if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
35617 + tr_type == DWC_OTG_TRANSACTION_ALL) &&
35618 + !DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) {
35619 +
35620 + process_periodic_channels(hcd);
35621 + }
35622 +
35623 + /* Process host channels associated with non-periodic transfers. */
35624 + if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
35625 + tr_type == DWC_OTG_TRANSACTION_ALL) {
35626 + if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) {
35627 + process_non_periodic_channels(hcd);
35628 + } else {
35629 + /*
35630 + * Ensure NP Tx FIFO empty interrupt is disabled when
35631 + * there are no non-periodic transfers to process.
35632 + */
35633 + gintmsk_data_t gintmsk = {.d32 = 0 };
35634 + gintmsk.b.nptxfempty = 1;
35635 + DWC_MODIFY_REG32(&hcd->core_if->
35636 + core_global_regs->gintmsk, gintmsk.d32,
35637 + 0);
35638 + }
35639 + }
35640 +}
35641 +
35642 +#ifdef DWC_HS_ELECT_TST
35643 +/*
35644 + * Quick and dirty hack to implement the HS Electrical Test
35645 + * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
35646 + *
35647 + * This code was copied from our userspace app "hset". It sends a
35648 + * Get Device Descriptor control sequence in two parts, first the
35649 + * Setup packet by itself, followed some time later by the In and
35650 + * Ack packets. Rather than trying to figure out how to add this
35651 + * functionality to the normal driver code, we just hijack the
35652 + * hardware, using these two function to drive the hardware
35653 + * directly.
35654 + */
35655 +
35656 +static dwc_otg_core_global_regs_t *global_regs;
35657 +static dwc_otg_host_global_regs_t *hc_global_regs;
35658 +static dwc_otg_hc_regs_t *hc_regs;
35659 +static uint32_t *data_fifo;
35660 +
35661 +static void do_setup(void)
35662 +{
35663 + gintsts_data_t gintsts;
35664 + hctsiz_data_t hctsiz;
35665 + hcchar_data_t hcchar;
35666 + haint_data_t haint;
35667 + hcint_data_t hcint;
35668 +
35669 + /* Enable HAINTs */
35670 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
35671 +
35672 + /* Enable HCINTs */
35673 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
35674 +
35675 + /* Read GINTSTS */
35676 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35677 +
35678 + /* Read HAINT */
35679 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35680 +
35681 + /* Read HCINT */
35682 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35683 +
35684 + /* Read HCCHAR */
35685 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35686 +
35687 + /* Clear HCINT */
35688 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35689 +
35690 + /* Clear HAINT */
35691 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35692 +
35693 + /* Clear GINTSTS */
35694 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35695 +
35696 + /* Read GINTSTS */
35697 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35698 +
35699 + /*
35700 + * Send Setup packet (Get Device Descriptor)
35701 + */
35702 +
35703 + /* Make sure channel is disabled */
35704 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35705 + if (hcchar.b.chen) {
35706 + hcchar.b.chdis = 1;
35707 +// hcchar.b.chen = 1;
35708 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35709 + //sleep(1);
35710 + dwc_mdelay(1000);
35711 +
35712 + /* Read GINTSTS */
35713 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35714 +
35715 + /* Read HAINT */
35716 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35717 +
35718 + /* Read HCINT */
35719 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35720 +
35721 + /* Read HCCHAR */
35722 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35723 +
35724 + /* Clear HCINT */
35725 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35726 +
35727 + /* Clear HAINT */
35728 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35729 +
35730 + /* Clear GINTSTS */
35731 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35732 +
35733 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35734 + }
35735 +
35736 + /* Set HCTSIZ */
35737 + hctsiz.d32 = 0;
35738 + hctsiz.b.xfersize = 8;
35739 + hctsiz.b.pktcnt = 1;
35740 + hctsiz.b.pid = DWC_OTG_HC_PID_SETUP;
35741 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
35742 +
35743 + /* Set HCCHAR */
35744 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35745 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
35746 + hcchar.b.epdir = 0;
35747 + hcchar.b.epnum = 0;
35748 + hcchar.b.mps = 8;
35749 + hcchar.b.chen = 1;
35750 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35751 +
35752 + /* Fill FIFO with Setup data for Get Device Descriptor */
35753 + data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
35754 + DWC_WRITE_REG32(data_fifo++, 0x01000680);
35755 + DWC_WRITE_REG32(data_fifo++, 0x00080000);
35756 +
35757 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35758 +
35759 + /* Wait for host channel interrupt */
35760 + do {
35761 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35762 + } while (gintsts.b.hcintr == 0);
35763 +
35764 + /* Disable HCINTs */
35765 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
35766 +
35767 + /* Disable HAINTs */
35768 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
35769 +
35770 + /* Read HAINT */
35771 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35772 +
35773 + /* Read HCINT */
35774 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35775 +
35776 + /* Read HCCHAR */
35777 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35778 +
35779 + /* Clear HCINT */
35780 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35781 +
35782 + /* Clear HAINT */
35783 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35784 +
35785 + /* Clear GINTSTS */
35786 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35787 +
35788 + /* Read GINTSTS */
35789 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35790 +}
35791 +
35792 +static void do_in_ack(void)
35793 +{
35794 + gintsts_data_t gintsts;
35795 + hctsiz_data_t hctsiz;
35796 + hcchar_data_t hcchar;
35797 + haint_data_t haint;
35798 + hcint_data_t hcint;
35799 + host_grxsts_data_t grxsts;
35800 +
35801 + /* Enable HAINTs */
35802 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
35803 +
35804 + /* Enable HCINTs */
35805 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
35806 +
35807 + /* Read GINTSTS */
35808 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35809 +
35810 + /* Read HAINT */
35811 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35812 +
35813 + /* Read HCINT */
35814 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35815 +
35816 + /* Read HCCHAR */
35817 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35818 +
35819 + /* Clear HCINT */
35820 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35821 +
35822 + /* Clear HAINT */
35823 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35824 +
35825 + /* Clear GINTSTS */
35826 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35827 +
35828 + /* Read GINTSTS */
35829 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35830 +
35831 + /*
35832 + * Receive Control In packet
35833 + */
35834 +
35835 + /* Make sure channel is disabled */
35836 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35837 + if (hcchar.b.chen) {
35838 + hcchar.b.chdis = 1;
35839 + hcchar.b.chen = 1;
35840 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35841 + //sleep(1);
35842 + dwc_mdelay(1000);
35843 +
35844 + /* Read GINTSTS */
35845 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35846 +
35847 + /* Read HAINT */
35848 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35849 +
35850 + /* Read HCINT */
35851 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35852 +
35853 + /* Read HCCHAR */
35854 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35855 +
35856 + /* Clear HCINT */
35857 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35858 +
35859 + /* Clear HAINT */
35860 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35861 +
35862 + /* Clear GINTSTS */
35863 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35864 +
35865 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35866 + }
35867 +
35868 + /* Set HCTSIZ */
35869 + hctsiz.d32 = 0;
35870 + hctsiz.b.xfersize = 8;
35871 + hctsiz.b.pktcnt = 1;
35872 + hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
35873 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
35874 +
35875 + /* Set HCCHAR */
35876 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35877 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
35878 + hcchar.b.epdir = 1;
35879 + hcchar.b.epnum = 0;
35880 + hcchar.b.mps = 8;
35881 + hcchar.b.chen = 1;
35882 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35883 +
35884 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35885 +
35886 + /* Wait for receive status queue interrupt */
35887 + do {
35888 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35889 + } while (gintsts.b.rxstsqlvl == 0);
35890 +
35891 + /* Read RXSTS */
35892 + grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
35893 +
35894 + /* Clear RXSTSQLVL in GINTSTS */
35895 + gintsts.d32 = 0;
35896 + gintsts.b.rxstsqlvl = 1;
35897 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35898 +
35899 + switch (grxsts.b.pktsts) {
35900 + case DWC_GRXSTS_PKTSTS_IN:
35901 + /* Read the data into the host buffer */
35902 + if (grxsts.b.bcnt > 0) {
35903 + int i;
35904 + int word_count = (grxsts.b.bcnt + 3) / 4;
35905 +
35906 + data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
35907 +
35908 + for (i = 0; i < word_count; i++) {
35909 + (void)DWC_READ_REG32(data_fifo++);
35910 + }
35911 + }
35912 + break;
35913 +
35914 + default:
35915 + break;
35916 + }
35917 +
35918 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35919 +
35920 + /* Wait for receive status queue interrupt */
35921 + do {
35922 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35923 + } while (gintsts.b.rxstsqlvl == 0);
35924 +
35925 + /* Read RXSTS */
35926 + grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
35927 +
35928 + /* Clear RXSTSQLVL in GINTSTS */
35929 + gintsts.d32 = 0;
35930 + gintsts.b.rxstsqlvl = 1;
35931 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35932 +
35933 + switch (grxsts.b.pktsts) {
35934 + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
35935 + break;
35936 +
35937 + default:
35938 + break;
35939 + }
35940 +
35941 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35942 +
35943 + /* Wait for host channel interrupt */
35944 + do {
35945 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35946 + } while (gintsts.b.hcintr == 0);
35947 +
35948 + /* Read HAINT */
35949 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35950 +
35951 + /* Read HCINT */
35952 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35953 +
35954 + /* Read HCCHAR */
35955 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35956 +
35957 + /* Clear HCINT */
35958 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35959 +
35960 + /* Clear HAINT */
35961 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35962 +
35963 + /* Clear GINTSTS */
35964 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35965 +
35966 + /* Read GINTSTS */
35967 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35968 +
35969 +// usleep(100000);
35970 +// mdelay(100);
35971 + dwc_mdelay(1);
35972 +
35973 + /*
35974 + * Send handshake packet
35975 + */
35976 +
35977 + /* Read HAINT */
35978 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35979 +
35980 + /* Read HCINT */
35981 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35982 +
35983 + /* Read HCCHAR */
35984 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35985 +
35986 + /* Clear HCINT */
35987 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35988 +
35989 + /* Clear HAINT */
35990 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35991 +
35992 + /* Clear GINTSTS */
35993 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35994 +
35995 + /* Read GINTSTS */
35996 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35997 +
35998 + /* Make sure channel is disabled */
35999 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
36000 + if (hcchar.b.chen) {
36001 + hcchar.b.chdis = 1;
36002 + hcchar.b.chen = 1;
36003 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
36004 + //sleep(1);
36005 + dwc_mdelay(1000);
36006 +
36007 + /* Read GINTSTS */
36008 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
36009 +
36010 + /* Read HAINT */
36011 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
36012 +
36013 + /* Read HCINT */
36014 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
36015 +
36016 + /* Read HCCHAR */
36017 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
36018 +
36019 + /* Clear HCINT */
36020 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
36021 +
36022 + /* Clear HAINT */
36023 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
36024 +
36025 + /* Clear GINTSTS */
36026 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
36027 +
36028 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
36029 + }
36030 +
36031 + /* Set HCTSIZ */
36032 + hctsiz.d32 = 0;
36033 + hctsiz.b.xfersize = 0;
36034 + hctsiz.b.pktcnt = 1;
36035 + hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
36036 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
36037 +
36038 + /* Set HCCHAR */
36039 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
36040 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
36041 + hcchar.b.epdir = 0;
36042 + hcchar.b.epnum = 0;
36043 + hcchar.b.mps = 8;
36044 + hcchar.b.chen = 1;
36045 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
36046 +
36047 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
36048 +
36049 + /* Wait for host channel interrupt */
36050 + do {
36051 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
36052 + } while (gintsts.b.hcintr == 0);
36053 +
36054 + /* Disable HCINTs */
36055 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
36056 +
36057 + /* Disable HAINTs */
36058 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
36059 +
36060 + /* Read HAINT */
36061 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
36062 +
36063 + /* Read HCINT */
36064 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
36065 +
36066 + /* Read HCCHAR */
36067 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
36068 +
36069 + /* Clear HCINT */
36070 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
36071 +
36072 + /* Clear HAINT */
36073 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
36074 +
36075 + /* Clear GINTSTS */
36076 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
36077 +
36078 + /* Read GINTSTS */
36079 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
36080 +}
36081 +#endif
36082 +
36083 +/** Handles hub class-specific requests. */
36084 +int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
36085 + uint16_t typeReq,
36086 + uint16_t wValue,
36087 + uint16_t wIndex, uint8_t * buf, uint16_t wLength)
36088 +{
36089 + int retval = 0;
36090 +
36091 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
36092 + usb_hub_descriptor_t *hub_desc;
36093 + hprt0_data_t hprt0 = {.d32 = 0 };
36094 +
36095 + uint32_t port_status;
36096 +
36097 + switch (typeReq) {
36098 + case UCR_CLEAR_HUB_FEATURE:
36099 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36100 + "ClearHubFeature 0x%x\n", wValue);
36101 + switch (wValue) {
36102 + case UHF_C_HUB_LOCAL_POWER:
36103 + case UHF_C_HUB_OVER_CURRENT:
36104 + /* Nothing required here */
36105 + break;
36106 + default:
36107 + retval = -DWC_E_INVALID;
36108 + DWC_ERROR("DWC OTG HCD - "
36109 + "ClearHubFeature request %xh unknown\n",
36110 + wValue);
36111 + }
36112 + break;
36113 + case UCR_CLEAR_PORT_FEATURE:
36114 +#ifdef CONFIG_USB_DWC_OTG_LPM
36115 + if (wValue != UHF_PORT_L1)
36116 +#endif
36117 + if (!wIndex || wIndex > 1)
36118 + goto error;
36119 +
36120 + switch (wValue) {
36121 + case UHF_PORT_ENABLE:
36122 + DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - "
36123 + "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
36124 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36125 + hprt0.b.prtena = 1;
36126 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36127 + break;
36128 + case UHF_PORT_SUSPEND:
36129 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36130 + "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
36131 +
36132 + if (core_if->power_down == 2) {
36133 + dwc_otg_host_hibernation_restore(core_if, 0, 0);
36134 + } else {
36135 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
36136 + dwc_mdelay(5);
36137 +
36138 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36139 + hprt0.b.prtres = 1;
36140 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36141 + hprt0.b.prtsusp = 0;
36142 + /* Clear Resume bit */
36143 + dwc_mdelay(100);
36144 + hprt0.b.prtres = 0;
36145 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36146 + }
36147 + break;
36148 +#ifdef CONFIG_USB_DWC_OTG_LPM
36149 + case UHF_PORT_L1:
36150 + {
36151 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36152 + glpmcfg_data_t lpmcfg = {.d32 = 0 };
36153 +
36154 + lpmcfg.d32 =
36155 + DWC_READ_REG32(&core_if->
36156 + core_global_regs->glpmcfg);
36157 + lpmcfg.b.en_utmi_sleep = 0;
36158 + lpmcfg.b.hird_thres &= (~(1 << 4));
36159 + lpmcfg.b.prt_sleep_sts = 1;
36160 + DWC_WRITE_REG32(&core_if->
36161 + core_global_regs->glpmcfg,
36162 + lpmcfg.d32);
36163 +
36164 + /* Clear Enbl_L1Gating bit. */
36165 + pcgcctl.b.enbl_sleep_gating = 1;
36166 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
36167 + 0);
36168 +
36169 + dwc_mdelay(5);
36170 +
36171 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36172 + hprt0.b.prtres = 1;
36173 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36174 + hprt0.d32);
36175 + /* This bit will be cleared in wakeup interrupt handle */
36176 + break;
36177 + }
36178 +#endif
36179 + case UHF_PORT_POWER:
36180 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36181 + "ClearPortFeature USB_PORT_FEAT_POWER\n");
36182 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36183 + hprt0.b.prtpwr = 0;
36184 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36185 + break;
36186 + case UHF_PORT_INDICATOR:
36187 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36188 + "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
36189 + /* Port inidicator not supported */
36190 + break;
36191 + case UHF_C_PORT_CONNECTION:
36192 + /* Clears drivers internal connect status change
36193 + * flag */
36194 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36195 + "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
36196 + dwc_otg_hcd->flags.b.port_connect_status_change = 0;
36197 + break;
36198 + case UHF_C_PORT_RESET:
36199 + /* Clears the driver's internal Port Reset Change
36200 + * flag */
36201 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36202 + "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
36203 + dwc_otg_hcd->flags.b.port_reset_change = 0;
36204 + break;
36205 + case UHF_C_PORT_ENABLE:
36206 + /* Clears the driver's internal Port
36207 + * Enable/Disable Change flag */
36208 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36209 + "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
36210 + dwc_otg_hcd->flags.b.port_enable_change = 0;
36211 + break;
36212 + case UHF_C_PORT_SUSPEND:
36213 + /* Clears the driver's internal Port Suspend
36214 + * Change flag, which is set when resume signaling on
36215 + * the host port is complete */
36216 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36217 + "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
36218 + dwc_otg_hcd->flags.b.port_suspend_change = 0;
36219 + break;
36220 +#ifdef CONFIG_USB_DWC_OTG_LPM
36221 + case UHF_C_PORT_L1:
36222 + dwc_otg_hcd->flags.b.port_l1_change = 0;
36223 + break;
36224 +#endif
36225 + case UHF_C_PORT_OVER_CURRENT:
36226 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36227 + "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
36228 + dwc_otg_hcd->flags.b.port_over_current_change = 0;
36229 + break;
36230 + default:
36231 + retval = -DWC_E_INVALID;
36232 + DWC_ERROR("DWC OTG HCD - "
36233 + "ClearPortFeature request %xh "
36234 + "unknown or unsupported\n", wValue);
36235 + }
36236 + break;
36237 + case UCR_GET_HUB_DESCRIPTOR:
36238 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36239 + "GetHubDescriptor\n");
36240 + hub_desc = (usb_hub_descriptor_t *) buf;
36241 + hub_desc->bDescLength = 9;
36242 + hub_desc->bDescriptorType = 0x29;
36243 + hub_desc->bNbrPorts = 1;
36244 + USETW(hub_desc->wHubCharacteristics, 0x08);
36245 + hub_desc->bPwrOn2PwrGood = 1;
36246 + hub_desc->bHubContrCurrent = 0;
36247 + hub_desc->DeviceRemovable[0] = 0;
36248 + hub_desc->DeviceRemovable[1] = 0xff;
36249 + break;
36250 + case UCR_GET_HUB_STATUS:
36251 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36252 + "GetHubStatus\n");
36253 + DWC_MEMSET(buf, 0, 4);
36254 + break;
36255 + case UCR_GET_PORT_STATUS:
36256 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36257 + "GetPortStatus wIndex = 0x%04x FLAGS=0x%08x\n",
36258 + wIndex, dwc_otg_hcd->flags.d32);
36259 + if (!wIndex || wIndex > 1)
36260 + goto error;
36261 +
36262 + port_status = 0;
36263 +
36264 + if (dwc_otg_hcd->flags.b.port_connect_status_change)
36265 + port_status |= (1 << UHF_C_PORT_CONNECTION);
36266 +
36267 + if (dwc_otg_hcd->flags.b.port_enable_change)
36268 + port_status |= (1 << UHF_C_PORT_ENABLE);
36269 +
36270 + if (dwc_otg_hcd->flags.b.port_suspend_change)
36271 + port_status |= (1 << UHF_C_PORT_SUSPEND);
36272 +
36273 + if (dwc_otg_hcd->flags.b.port_l1_change)
36274 + port_status |= (1 << UHF_C_PORT_L1);
36275 +
36276 + if (dwc_otg_hcd->flags.b.port_reset_change) {
36277 + port_status |= (1 << UHF_C_PORT_RESET);
36278 + }
36279 +
36280 + if (dwc_otg_hcd->flags.b.port_over_current_change) {
36281 + DWC_WARN("Overcurrent change detected\n");
36282 + port_status |= (1 << UHF_C_PORT_OVER_CURRENT);
36283 + }
36284 +
36285 + if (!dwc_otg_hcd->flags.b.port_connect_status) {
36286 + /*
36287 + * The port is disconnected, which means the core is
36288 + * either in device mode or it soon will be. Just
36289 + * return 0's for the remainder of the port status
36290 + * since the port register can't be read if the core
36291 + * is in device mode.
36292 + */
36293 + *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
36294 + break;
36295 + }
36296 +
36297 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
36298 + DWC_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32);
36299 +
36300 + if (hprt0.b.prtconnsts)
36301 + port_status |= (1 << UHF_PORT_CONNECTION);
36302 +
36303 + if (hprt0.b.prtena)
36304 + port_status |= (1 << UHF_PORT_ENABLE);
36305 +
36306 + if (hprt0.b.prtsusp)
36307 + port_status |= (1 << UHF_PORT_SUSPEND);
36308 +
36309 + if (hprt0.b.prtovrcurract)
36310 + port_status |= (1 << UHF_PORT_OVER_CURRENT);
36311 +
36312 + if (hprt0.b.prtrst)
36313 + port_status |= (1 << UHF_PORT_RESET);
36314 +
36315 + if (hprt0.b.prtpwr)
36316 + port_status |= (1 << UHF_PORT_POWER);
36317 +
36318 + if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
36319 + port_status |= (1 << UHF_PORT_HIGH_SPEED);
36320 + else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
36321 + port_status |= (1 << UHF_PORT_LOW_SPEED);
36322 +
36323 + if (hprt0.b.prttstctl)
36324 + port_status |= (1 << UHF_PORT_TEST);
36325 + if (dwc_otg_get_lpm_portsleepstatus(dwc_otg_hcd->core_if)) {
36326 + port_status |= (1 << UHF_PORT_L1);
36327 + }
36328 + /*
36329 + For Synopsys HW emulation of Power down wkup_control asserts the
36330 + hreset_n and prst_n on suspned. This causes the HPRT0 to be zero.
36331 + We intentionally tell the software that port is in L2Suspend state.
36332 + Only for STE.
36333 + */
36334 + if ((core_if->power_down == 2)
36335 + && (core_if->hibernation_suspend == 1)) {
36336 + port_status |= (1 << UHF_PORT_SUSPEND);
36337 + }
36338 + /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
36339 +
36340 + *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
36341 +
36342 + break;
36343 + case UCR_SET_HUB_FEATURE:
36344 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36345 + "SetHubFeature\n");
36346 + /* No HUB features supported */
36347 + break;
36348 + case UCR_SET_PORT_FEATURE:
36349 + if (wValue != UHF_PORT_TEST && (!wIndex || wIndex > 1))
36350 + goto error;
36351 +
36352 + if (!dwc_otg_hcd->flags.b.port_connect_status) {
36353 + /*
36354 + * The port is disconnected, which means the core is
36355 + * either in device mode or it soon will be. Just
36356 + * return without doing anything since the port
36357 + * register can't be written if the core is in device
36358 + * mode.
36359 + */
36360 + break;
36361 + }
36362 +
36363 + switch (wValue) {
36364 + case UHF_PORT_SUSPEND:
36365 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36366 + "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
36367 + if (dwc_otg_hcd_otg_port(dwc_otg_hcd) != wIndex) {
36368 + goto error;
36369 + }
36370 + if (core_if->power_down == 2) {
36371 + int timeout = 300;
36372 + dwc_irqflags_t flags;
36373 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36374 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
36375 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
36376 +#ifdef DWC_DEV_SRPCAP
36377 + int32_t otg_cap_param = core_if->core_params->otg_cap;
36378 +#endif
36379 + DWC_PRINTF("Preparing for complete power-off\n");
36380 +
36381 + /* Save registers before hibernation */
36382 + dwc_otg_save_global_regs(core_if);
36383 + dwc_otg_save_host_regs(core_if);
36384 +
36385 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36386 + hprt0.b.prtsusp = 1;
36387 + hprt0.b.prtena = 0;
36388 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36389 + /* Spin hprt0.b.prtsusp to became 1 */
36390 + do {
36391 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36392 + if (hprt0.b.prtsusp) {
36393 + break;
36394 + }
36395 + dwc_mdelay(1);
36396 + } while (--timeout);
36397 + if (!timeout) {
36398 + DWC_WARN("Suspend wasn't genereted\n");
36399 + }
36400 + dwc_udelay(10);
36401 +
36402 + /*
36403 + * We need to disable interrupts to prevent servicing of any IRQ
36404 + * during going to hibernation
36405 + */
36406 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
36407 + core_if->lx_state = DWC_OTG_L2;
36408 +#ifdef DWC_DEV_SRPCAP
36409 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36410 + hprt0.b.prtpwr = 0;
36411 + hprt0.b.prtena = 0;
36412 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36413 + hprt0.d32);
36414 +#endif
36415 + gusbcfg.d32 =
36416 + DWC_READ_REG32(&core_if->core_global_regs->
36417 + gusbcfg);
36418 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
36419 + /* ULPI interface */
36420 + /* Suspend the Phy Clock */
36421 + pcgcctl.d32 = 0;
36422 + pcgcctl.b.stoppclk = 1;
36423 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
36424 + pcgcctl.d32);
36425 + dwc_udelay(10);
36426 + gpwrdn.b.pmuactv = 1;
36427 + DWC_MODIFY_REG32(&core_if->
36428 + core_global_regs->
36429 + gpwrdn, 0, gpwrdn.d32);
36430 + } else {
36431 + /* UTMI+ Interface */
36432 + gpwrdn.b.pmuactv = 1;
36433 + DWC_MODIFY_REG32(&core_if->
36434 + core_global_regs->
36435 + gpwrdn, 0, gpwrdn.d32);
36436 + dwc_udelay(10);
36437 + pcgcctl.b.stoppclk = 1;
36438 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
36439 + dwc_udelay(10);
36440 + }
36441 +#ifdef DWC_DEV_SRPCAP
36442 + gpwrdn.d32 = 0;
36443 + gpwrdn.b.dis_vbus = 1;
36444 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36445 + gpwrdn, 0, gpwrdn.d32);
36446 +#endif
36447 + gpwrdn.d32 = 0;
36448 + gpwrdn.b.pmuintsel = 1;
36449 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36450 + gpwrdn, 0, gpwrdn.d32);
36451 + dwc_udelay(10);
36452 +
36453 + gpwrdn.d32 = 0;
36454 +#ifdef DWC_DEV_SRPCAP
36455 + gpwrdn.b.srp_det_msk = 1;
36456 +#endif
36457 + gpwrdn.b.disconn_det_msk = 1;
36458 + gpwrdn.b.lnstchng_msk = 1;
36459 + gpwrdn.b.sts_chngint_msk = 1;
36460 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36461 + gpwrdn, 0, gpwrdn.d32);
36462 + dwc_udelay(10);
36463 +
36464 + /* Enable Power Down Clamp and all interrupts in GPWRDN */
36465 + gpwrdn.d32 = 0;
36466 + gpwrdn.b.pwrdnclmp = 1;
36467 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36468 + gpwrdn, 0, gpwrdn.d32);
36469 + dwc_udelay(10);
36470 +
36471 + /* Switch off VDD */
36472 + gpwrdn.d32 = 0;
36473 + gpwrdn.b.pwrdnswtch = 1;
36474 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36475 + gpwrdn, 0, gpwrdn.d32);
36476 +
36477 +#ifdef DWC_DEV_SRPCAP
36478 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
36479 + {
36480 + core_if->pwron_timer_started = 1;
36481 + DWC_TIMER_SCHEDULE(core_if->pwron_timer, 6000 /* 6 secs */ );
36482 + }
36483 +#endif
36484 + /* Save gpwrdn register for further usage if stschng interrupt */
36485 + core_if->gr_backup->gpwrdn_local =
36486 + DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
36487 +
36488 + /* Set flag to indicate that we are in hibernation */
36489 + core_if->hibernation_suspend = 1;
36490 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock,flags);
36491 +
36492 + DWC_PRINTF("Host hibernation completed\n");
36493 + // Exit from case statement
36494 + break;
36495 +
36496 + }
36497 + if (dwc_otg_hcd_otg_port(dwc_otg_hcd) == wIndex &&
36498 + dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
36499 + gotgctl_data_t gotgctl = {.d32 = 0 };
36500 + gotgctl.b.hstsethnpen = 1;
36501 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36502 + gotgctl, 0, gotgctl.d32);
36503 + core_if->op_state = A_SUSPEND;
36504 + }
36505 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36506 + hprt0.b.prtsusp = 1;
36507 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36508 + {
36509 + dwc_irqflags_t flags;
36510 + /* Update lx_state */
36511 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
36512 + core_if->lx_state = DWC_OTG_L2;
36513 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
36514 + }
36515 + /* Suspend the Phy Clock */
36516 + {
36517 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36518 + pcgcctl.b.stoppclk = 1;
36519 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
36520 + pcgcctl.d32);
36521 + dwc_udelay(10);
36522 + }
36523 +
36524 + /* For HNP the bus must be suspended for at least 200ms. */
36525 + if (dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
36526 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36527 + pcgcctl.b.stoppclk = 1;
36528 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
36529 + dwc_mdelay(200);
36530 + }
36531 +
36532 + /** @todo - check how sw can wait for 1 sec to check asesvld??? */
36533 +#if 0 //vahrama !!!!!!!!!!!!!!!!!!
36534 + if (core_if->adp_enable) {
36535 + gotgctl_data_t gotgctl = {.d32 = 0 };
36536 + gpwrdn_data_t gpwrdn;
36537 +
36538 + while (gotgctl.b.asesvld == 1) {
36539 + gotgctl.d32 =
36540 + DWC_READ_REG32(&core_if->
36541 + core_global_regs->
36542 + gotgctl);
36543 + dwc_mdelay(100);
36544 + }
36545 +
36546 + /* Enable Power Down Logic */
36547 + gpwrdn.d32 = 0;
36548 + gpwrdn.b.pmuactv = 1;
36549 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36550 + gpwrdn, 0, gpwrdn.d32);
36551 +
36552 + /* Unmask SRP detected interrupt from Power Down Logic */
36553 + gpwrdn.d32 = 0;
36554 + gpwrdn.b.srp_det_msk = 1;
36555 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36556 + gpwrdn, 0, gpwrdn.d32);
36557 +
36558 + dwc_otg_adp_probe_start(core_if);
36559 + }
36560 +#endif
36561 + break;
36562 + case UHF_PORT_POWER:
36563 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36564 + "SetPortFeature - USB_PORT_FEAT_POWER\n");
36565 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36566 + hprt0.b.prtpwr = 1;
36567 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36568 + break;
36569 + case UHF_PORT_RESET:
36570 + if ((core_if->power_down == 2)
36571 + && (core_if->hibernation_suspend == 1)) {
36572 + /* If we are going to exit from Hibernated
36573 + * state via USB RESET.
36574 + */
36575 + dwc_otg_host_hibernation_restore(core_if, 0, 1);
36576 + } else {
36577 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36578 +
36579 + DWC_DEBUGPL(DBG_HCD,
36580 + "DWC OTG HCD HUB CONTROL - "
36581 + "SetPortFeature - USB_PORT_FEAT_RESET\n");
36582 + {
36583 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36584 + pcgcctl.b.enbl_sleep_gating = 1;
36585 + pcgcctl.b.stoppclk = 1;
36586 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
36587 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
36588 + }
36589 +#ifdef CONFIG_USB_DWC_OTG_LPM
36590 + {
36591 + glpmcfg_data_t lpmcfg;
36592 + lpmcfg.d32 =
36593 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
36594 + if (lpmcfg.b.prt_sleep_sts) {
36595 + lpmcfg.b.en_utmi_sleep = 0;
36596 + lpmcfg.b.hird_thres &= (~(1 << 4));
36597 + DWC_WRITE_REG32
36598 + (&core_if->core_global_regs->glpmcfg,
36599 + lpmcfg.d32);
36600 + dwc_mdelay(1);
36601 + }
36602 + }
36603 +#endif
36604 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36605 + /* Clear suspend bit if resetting from suspended state. */
36606 + hprt0.b.prtsusp = 0;
36607 + /* When B-Host the Port reset bit is set in
36608 + * the Start HCD Callback function, so that
36609 + * the reset is started within 1ms of the HNP
36610 + * success interrupt. */
36611 + if (!dwc_otg_hcd_is_b_host(dwc_otg_hcd)) {
36612 + hprt0.b.prtpwr = 1;
36613 + hprt0.b.prtrst = 1;
36614 + DWC_PRINTF("Indeed it is in host mode hprt0 = %08x\n",hprt0.d32);
36615 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36616 + hprt0.d32);
36617 + }
36618 + /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
36619 + dwc_mdelay(60);
36620 + hprt0.b.prtrst = 0;
36621 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36622 + core_if->lx_state = DWC_OTG_L0; /* Now back to the on state */
36623 + }
36624 + break;
36625 +#ifdef DWC_HS_ELECT_TST
36626 + case UHF_PORT_TEST:
36627 + {
36628 + uint32_t t;
36629 + gintmsk_data_t gintmsk;
36630 +
36631 + t = (wIndex >> 8); /* MSB wIndex USB */
36632 + DWC_DEBUGPL(DBG_HCD,
36633 + "DWC OTG HCD HUB CONTROL - "
36634 + "SetPortFeature - USB_PORT_FEAT_TEST %d\n",
36635 + t);
36636 + DWC_WARN("USB_PORT_FEAT_TEST %d\n", t);
36637 + if (t < 6) {
36638 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36639 + hprt0.b.prttstctl = t;
36640 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36641 + hprt0.d32);
36642 + } else {
36643 + /* Setup global vars with reg addresses (quick and
36644 + * dirty hack, should be cleaned up)
36645 + */
36646 + global_regs = core_if->core_global_regs;
36647 + hc_global_regs =
36648 + core_if->host_if->host_global_regs;
36649 + hc_regs =
36650 + (dwc_otg_hc_regs_t *) ((char *)
36651 + global_regs +
36652 + 0x500);
36653 + data_fifo =
36654 + (uint32_t *) ((char *)global_regs +
36655 + 0x1000);
36656 +
36657 + if (t == 6) { /* HS_HOST_PORT_SUSPEND_RESUME */
36658 + /* Save current interrupt mask */
36659 + gintmsk.d32 =
36660 + DWC_READ_REG32
36661 + (&global_regs->gintmsk);
36662 +
36663 + /* Disable all interrupts while we muck with
36664 + * the hardware directly
36665 + */
36666 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
36667 +
36668 + /* 15 second delay per the test spec */
36669 + dwc_mdelay(15000);
36670 +
36671 + /* Drive suspend on the root port */
36672 + hprt0.d32 =
36673 + dwc_otg_read_hprt0(core_if);
36674 + hprt0.b.prtsusp = 1;
36675 + hprt0.b.prtres = 0;
36676 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36677 +
36678 + /* 15 second delay per the test spec */
36679 + dwc_mdelay(15000);
36680 +
36681 + /* Drive resume on the root port */
36682 + hprt0.d32 =
36683 + dwc_otg_read_hprt0(core_if);
36684 + hprt0.b.prtsusp = 0;
36685 + hprt0.b.prtres = 1;
36686 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36687 + dwc_mdelay(100);
36688 +
36689 + /* Clear the resume bit */
36690 + hprt0.b.prtres = 0;
36691 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36692 +
36693 + /* Restore interrupts */
36694 + DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
36695 + } else if (t == 7) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
36696 + /* Save current interrupt mask */
36697 + gintmsk.d32 =
36698 + DWC_READ_REG32
36699 + (&global_regs->gintmsk);
36700 +
36701 + /* Disable all interrupts while we muck with
36702 + * the hardware directly
36703 + */
36704 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
36705 +
36706 + /* 15 second delay per the test spec */
36707 + dwc_mdelay(15000);
36708 +
36709 + /* Send the Setup packet */
36710 + do_setup();
36711 +
36712 + /* 15 second delay so nothing else happens for awhile */
36713 + dwc_mdelay(15000);
36714 +
36715 + /* Restore interrupts */
36716 + DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
36717 + } else if (t == 8) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
36718 + /* Save current interrupt mask */
36719 + gintmsk.d32 =
36720 + DWC_READ_REG32
36721 + (&global_regs->gintmsk);
36722 +
36723 + /* Disable all interrupts while we muck with
36724 + * the hardware directly
36725 + */
36726 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
36727 +
36728 + /* Send the Setup packet */
36729 + do_setup();
36730 +
36731 + /* 15 second delay so nothing else happens for awhile */
36732 + dwc_mdelay(15000);
36733 +
36734 + /* Send the In and Ack packets */
36735 + do_in_ack();
36736 +
36737 + /* 15 second delay so nothing else happens for awhile */
36738 + dwc_mdelay(15000);
36739 +
36740 + /* Restore interrupts */
36741 + DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
36742 + }
36743 + }
36744 + break;
36745 + }
36746 +#endif /* DWC_HS_ELECT_TST */
36747 +
36748 + case UHF_PORT_INDICATOR:
36749 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36750 + "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
36751 + /* Not supported */
36752 + break;
36753 + default:
36754 + retval = -DWC_E_INVALID;
36755 + DWC_ERROR("DWC OTG HCD - "
36756 + "SetPortFeature request %xh "
36757 + "unknown or unsupported\n", wValue);
36758 + break;
36759 + }
36760 + break;
36761 +#ifdef CONFIG_USB_DWC_OTG_LPM
36762 + case UCR_SET_AND_TEST_PORT_FEATURE:
36763 + if (wValue != UHF_PORT_L1) {
36764 + goto error;
36765 + }
36766 + {
36767 + int portnum, hird, devaddr, remwake;
36768 + glpmcfg_data_t lpmcfg;
36769 + uint32_t time_usecs;
36770 + gintsts_data_t gintsts;
36771 + gintmsk_data_t gintmsk;
36772 +
36773 + if (!dwc_otg_get_param_lpm_enable(core_if)) {
36774 + goto error;
36775 + }
36776 + if (wValue != UHF_PORT_L1 || wLength != 1) {
36777 + goto error;
36778 + }
36779 + /* Check if the port currently is in SLEEP state */
36780 + lpmcfg.d32 =
36781 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
36782 + if (lpmcfg.b.prt_sleep_sts) {
36783 + DWC_INFO("Port is already in sleep mode\n");
36784 + buf[0] = 0; /* Return success */
36785 + break;
36786 + }
36787 +
36788 + portnum = wIndex & 0xf;
36789 + hird = (wIndex >> 4) & 0xf;
36790 + devaddr = (wIndex >> 8) & 0x7f;
36791 + remwake = (wIndex >> 15);
36792 +
36793 + if (portnum != 1) {
36794 + retval = -DWC_E_INVALID;
36795 + DWC_WARN
36796 + ("Wrong port number(%d) in SetandTestPortFeature request\n",
36797 + portnum);
36798 + break;
36799 + }
36800 +
36801 + DWC_PRINTF
36802 + ("SetandTestPortFeature request: portnum = %d, hird = %d, devaddr = %d, rewake = %d\n",
36803 + portnum, hird, devaddr, remwake);
36804 + /* Disable LPM interrupt */
36805 + gintmsk.d32 = 0;
36806 + gintmsk.b.lpmtranrcvd = 1;
36807 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
36808 + gintmsk.d32, 0);
36809 +
36810 + if (dwc_otg_hcd_send_lpm
36811 + (dwc_otg_hcd, devaddr, hird, remwake)) {
36812 + retval = -DWC_E_INVALID;
36813 + break;
36814 + }
36815 +
36816 + time_usecs = 10 * (lpmcfg.b.retry_count + 1);
36817 + /* We will consider timeout if time_usecs microseconds pass,
36818 + * and we don't receive LPM transaction status.
36819 + * After receiving non-error responce(ACK/NYET/STALL) from device,
36820 + * core will set lpmtranrcvd bit.
36821 + */
36822 + do {
36823 + gintsts.d32 =
36824 + DWC_READ_REG32(&core_if->core_global_regs->gintsts);
36825 + if (gintsts.b.lpmtranrcvd) {
36826 + break;
36827 + }
36828 + dwc_udelay(1);
36829 + } while (--time_usecs);
36830 + /* lpm_int bit will be cleared in LPM interrupt handler */
36831 +
36832 + /* Now fill status
36833 + * 0x00 - Success
36834 + * 0x10 - NYET
36835 + * 0x11 - Timeout
36836 + */
36837 + if (!gintsts.b.lpmtranrcvd) {
36838 + buf[0] = 0x3; /* Completion code is Timeout */
36839 + dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd);
36840 + } else {
36841 + lpmcfg.d32 =
36842 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
36843 + if (lpmcfg.b.lpm_resp == 0x3) {
36844 + /* ACK responce from the device */
36845 + buf[0] = 0x00; /* Success */
36846 + } else if (lpmcfg.b.lpm_resp == 0x2) {
36847 + /* NYET responce from the device */
36848 + buf[0] = 0x2;
36849 + } else {
36850 + /* Otherwise responce with Timeout */
36851 + buf[0] = 0x3;
36852 + }
36853 + }
36854 + DWC_PRINTF("Device responce to LPM trans is %x\n",
36855 + lpmcfg.b.lpm_resp);
36856 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0,
36857 + gintmsk.d32);
36858 +
36859 + break;
36860 + }
36861 +#endif /* CONFIG_USB_DWC_OTG_LPM */
36862 + default:
36863 +error:
36864 + retval = -DWC_E_INVALID;
36865 + DWC_WARN("DWC OTG HCD - "
36866 + "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
36867 + typeReq, wIndex, wValue);
36868 + break;
36869 + }
36870 +
36871 + return retval;
36872 +}
36873 +
36874 +#ifdef CONFIG_USB_DWC_OTG_LPM
36875 +/** Returns index of host channel to perform LPM transaction. */
36876 +int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, uint8_t devaddr)
36877 +{
36878 + dwc_otg_core_if_t *core_if = hcd->core_if;
36879 + dwc_hc_t *hc;
36880 + hcchar_data_t hcchar;
36881 + gintmsk_data_t gintmsk = {.d32 = 0 };
36882 +
36883 + if (DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
36884 + DWC_PRINTF("No free channel to select for LPM transaction\n");
36885 + return -1;
36886 + }
36887 +
36888 + hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
36889 +
36890 + /* Mask host channel interrupts. */
36891 + gintmsk.b.hcintr = 1;
36892 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
36893 +
36894 + /* Fill fields that core needs for LPM transaction */
36895 + hcchar.b.devaddr = devaddr;
36896 + hcchar.b.epnum = 0;
36897 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
36898 + hcchar.b.mps = 64;
36899 + hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
36900 + hcchar.b.epdir = 0; /* OUT */
36901 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[hc->hc_num]->hcchar,
36902 + hcchar.d32);
36903 +
36904 + /* Remove the host channel from the free list. */
36905 + DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
36906 +
36907 + DWC_PRINTF("hcnum = %d devaddr = %d\n", hc->hc_num, devaddr);
36908 +
36909 + return hc->hc_num;
36910 +}
36911 +
36912 +/** Release hc after performing LPM transaction */
36913 +void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd)
36914 +{
36915 + dwc_hc_t *hc;
36916 + glpmcfg_data_t lpmcfg;
36917 + uint8_t hc_num;
36918 +
36919 + lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
36920 + hc_num = lpmcfg.b.lpm_chan_index;
36921 +
36922 + hc = hcd->hc_ptr_array[hc_num];
36923 +
36924 + DWC_PRINTF("Freeing channel %d after LPM\n", hc_num);
36925 + /* Return host channel to free list */
36926 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
36927 +}
36928 +
36929 +int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, uint8_t hird,
36930 + uint8_t bRemoteWake)
36931 +{
36932 + glpmcfg_data_t lpmcfg;
36933 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36934 + int channel;
36935 +
36936 + channel = dwc_otg_hcd_get_hc_for_lpm_tran(hcd, devaddr);
36937 + if (channel < 0) {
36938 + return channel;
36939 + }
36940 +
36941 + pcgcctl.b.enbl_sleep_gating = 1;
36942 + DWC_MODIFY_REG32(hcd->core_if->pcgcctl, 0, pcgcctl.d32);
36943 +
36944 + /* Read LPM config register */
36945 + lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
36946 +
36947 + /* Program LPM transaction fields */
36948 + lpmcfg.b.rem_wkup_en = bRemoteWake;
36949 + lpmcfg.b.hird = hird;
36950 + lpmcfg.b.hird_thres = 0x1c;
36951 + lpmcfg.b.lpm_chan_index = channel;
36952 + lpmcfg.b.en_utmi_sleep = 1;
36953 + /* Program LPM config register */
36954 + DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
36955 +
36956 + /* Send LPM transaction */
36957 + lpmcfg.b.send_lpm = 1;
36958 + DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
36959 +
36960 + return 0;
36961 +}
36962 +
36963 +#endif /* CONFIG_USB_DWC_OTG_LPM */
36964 +
36965 +int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port)
36966 +{
36967 + int retval;
36968 +
36969 + if (port != 1) {
36970 + return -DWC_E_INVALID;
36971 + }
36972 +
36973 + retval = (hcd->flags.b.port_connect_status_change ||
36974 + hcd->flags.b.port_reset_change ||
36975 + hcd->flags.b.port_enable_change ||
36976 + hcd->flags.b.port_suspend_change ||
36977 + hcd->flags.b.port_over_current_change);
36978 +#ifdef DEBUG
36979 + if (retval) {
36980 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:"
36981 + " Root port status changed\n");
36982 + DWC_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n",
36983 + hcd->flags.b.port_connect_status_change);
36984 + DWC_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n",
36985 + hcd->flags.b.port_reset_change);
36986 + DWC_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n",
36987 + hcd->flags.b.port_enable_change);
36988 + DWC_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n",
36989 + hcd->flags.b.port_suspend_change);
36990 + DWC_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n",
36991 + hcd->flags.b.port_over_current_change);
36992 + }
36993 +#endif
36994 + return retval;
36995 +}
36996 +
36997 +int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * dwc_otg_hcd)
36998 +{
36999 + hfnum_data_t hfnum;
37000 + hfnum.d32 =
37001 + DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->
37002 + hfnum);
37003 +
37004 +#ifdef DEBUG_SOF
37005 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n",
37006 + hfnum.b.frnum);
37007 +#endif
37008 + return hfnum.b.frnum;
37009 +}
37010 +
37011 +int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
37012 + struct dwc_otg_hcd_function_ops *fops)
37013 +{
37014 + int retval = 0;
37015 +
37016 + hcd->fops = fops;
37017 + if (!dwc_otg_is_device_mode(hcd->core_if) &&
37018 + (!hcd->core_if->adp_enable || hcd->core_if->adp.adp_started)) {
37019 + dwc_otg_hcd_reinit(hcd);
37020 + } else {
37021 + retval = -DWC_E_NO_DEVICE;
37022 + }
37023 +
37024 + return retval;
37025 +}
37026 +
37027 +void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd)
37028 +{
37029 + return hcd->priv;
37030 +}
37031 +
37032 +void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data)
37033 +{
37034 + hcd->priv = priv_data;
37035 +}
37036 +
37037 +uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd)
37038 +{
37039 + return hcd->otg_port;
37040 +}
37041 +
37042 +uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd)
37043 +{
37044 + uint32_t is_b_host;
37045 + if (hcd->core_if->op_state == B_HOST) {
37046 + is_b_host = 1;
37047 + } else {
37048 + is_b_host = 0;
37049 + }
37050 +
37051 + return is_b_host;
37052 +}
37053 +
37054 +dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
37055 + int iso_desc_count, int atomic_alloc)
37056 +{
37057 + dwc_otg_hcd_urb_t *dwc_otg_urb;
37058 + uint32_t size;
37059 +
37060 + size =
37061 + sizeof(*dwc_otg_urb) +
37062 + iso_desc_count * sizeof(struct dwc_otg_hcd_iso_packet_desc);
37063 + if (atomic_alloc)
37064 + dwc_otg_urb = DWC_ALLOC_ATOMIC(size);
37065 + else
37066 + dwc_otg_urb = DWC_ALLOC(size);
37067 +
37068 + if (NULL != dwc_otg_urb)
37069 + dwc_otg_urb->packet_count = iso_desc_count;
37070 + else {
37071 + dwc_otg_urb->packet_count = 0;
37072 + if (size != 0) {
37073 + DWC_ERROR("**** DWC OTG HCD URB alloc - "
37074 + "%salloc of %db failed\n",
37075 + atomic_alloc?"atomic ":"", size);
37076 + }
37077 + }
37078 +
37079 + return dwc_otg_urb;
37080 +}
37081 +
37082 +void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * dwc_otg_urb,
37083 + uint8_t dev_addr, uint8_t ep_num,
37084 + uint8_t ep_type, uint8_t ep_dir, uint16_t mps)
37085 +{
37086 + dwc_otg_hcd_fill_pipe(&dwc_otg_urb->pipe_info, dev_addr, ep_num,
37087 + ep_type, ep_dir, mps);
37088 +#if 0
37089 + DWC_PRINTF
37090 + ("addr = %d, ep_num = %d, ep_dir = 0x%x, ep_type = 0x%x, mps = %d\n",
37091 + dev_addr, ep_num, ep_dir, ep_type, mps);
37092 +#endif
37093 +}
37094 +
37095 +void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
37096 + void *urb_handle, void *buf, dwc_dma_t dma,
37097 + uint32_t buflen, void *setup_packet,
37098 + dwc_dma_t setup_dma, uint32_t flags,
37099 + uint16_t interval)
37100 +{
37101 + dwc_otg_urb->priv = urb_handle;
37102 + dwc_otg_urb->buf = buf;
37103 + dwc_otg_urb->dma = dma;
37104 + dwc_otg_urb->length = buflen;
37105 + dwc_otg_urb->setup_packet = setup_packet;
37106 + dwc_otg_urb->setup_dma = setup_dma;
37107 + dwc_otg_urb->flags = flags;
37108 + dwc_otg_urb->interval = interval;
37109 + dwc_otg_urb->status = -DWC_E_IN_PROGRESS;
37110 +}
37111 +
37112 +uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb)
37113 +{
37114 + return dwc_otg_urb->status;
37115 +}
37116 +
37117 +uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * dwc_otg_urb)
37118 +{
37119 + return dwc_otg_urb->actual_length;
37120 +}
37121 +
37122 +uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * dwc_otg_urb)
37123 +{
37124 + return dwc_otg_urb->error_count;
37125 +}
37126 +
37127 +void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
37128 + int desc_num, uint32_t offset,
37129 + uint32_t length)
37130 +{
37131 + dwc_otg_urb->iso_descs[desc_num].offset = offset;
37132 + dwc_otg_urb->iso_descs[desc_num].length = length;
37133 +}
37134 +
37135 +uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * dwc_otg_urb,
37136 + int desc_num)
37137 +{
37138 + return dwc_otg_urb->iso_descs[desc_num].status;
37139 +}
37140 +
37141 +uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
37142 + dwc_otg_urb, int desc_num)
37143 +{
37144 + return dwc_otg_urb->iso_descs[desc_num].actual_length;
37145 +}
37146 +
37147 +int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, void *ep_handle)
37148 +{
37149 + int allocated = 0;
37150 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
37151 +
37152 + if (qh) {
37153 + if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
37154 + allocated = 1;
37155 + }
37156 + }
37157 + return allocated;
37158 +}
37159 +
37160 +int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle)
37161 +{
37162 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
37163 + int freed = 0;
37164 + DWC_ASSERT(qh, "qh is not allocated\n");
37165 +
37166 + if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
37167 + freed = 1;
37168 + }
37169 +
37170 + return freed;
37171 +}
37172 +
37173 +uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, void *ep_handle)
37174 +{
37175 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
37176 + DWC_ASSERT(qh, "qh is not allocated\n");
37177 + return qh->usecs;
37178 +}
37179 +
37180 +void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd)
37181 +{
37182 +#ifdef DEBUG
37183 + int num_channels;
37184 + int i;
37185 + gnptxsts_data_t np_tx_status;
37186 + hptxsts_data_t p_tx_status;
37187 +
37188 + num_channels = hcd->core_if->core_params->host_channels;
37189 + DWC_PRINTF("\n");
37190 + DWC_PRINTF
37191 + ("************************************************************\n");
37192 + DWC_PRINTF("HCD State:\n");
37193 + DWC_PRINTF(" Num channels: %d\n", num_channels);
37194 + for (i = 0; i < num_channels; i++) {
37195 + dwc_hc_t *hc = hcd->hc_ptr_array[i];
37196 + DWC_PRINTF(" Channel %d:\n", i);
37197 + DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
37198 + hc->dev_addr, hc->ep_num, hc->ep_is_in);
37199 + DWC_PRINTF(" speed: %d\n", hc->speed);
37200 + DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
37201 + DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
37202 + DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
37203 + DWC_PRINTF(" multi_count: %d\n", hc->multi_count);
37204 + DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
37205 + DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
37206 + DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
37207 + DWC_PRINTF(" xfer_count: %d\n", hc->xfer_count);
37208 + DWC_PRINTF(" halt_on_queue: %d\n", hc->halt_on_queue);
37209 + DWC_PRINTF(" halt_pending: %d\n", hc->halt_pending);
37210 + DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
37211 + DWC_PRINTF(" do_split: %d\n", hc->do_split);
37212 + DWC_PRINTF(" complete_split: %d\n", hc->complete_split);
37213 + DWC_PRINTF(" hub_addr: %d\n", hc->hub_addr);
37214 + DWC_PRINTF(" port_addr: %d\n", hc->port_addr);
37215 + DWC_PRINTF(" xact_pos: %d\n", hc->xact_pos);
37216 + DWC_PRINTF(" requests: %d\n", hc->requests);
37217 + DWC_PRINTF(" qh: %p\n", hc->qh);
37218 + if (hc->xfer_started) {
37219 + hfnum_data_t hfnum;
37220 + hcchar_data_t hcchar;
37221 + hctsiz_data_t hctsiz;
37222 + hcint_data_t hcint;
37223 + hcintmsk_data_t hcintmsk;
37224 + hfnum.d32 =
37225 + DWC_READ_REG32(&hcd->core_if->
37226 + host_if->host_global_regs->hfnum);
37227 + hcchar.d32 =
37228 + DWC_READ_REG32(&hcd->core_if->host_if->
37229 + hc_regs[i]->hcchar);
37230 + hctsiz.d32 =
37231 + DWC_READ_REG32(&hcd->core_if->host_if->
37232 + hc_regs[i]->hctsiz);
37233 + hcint.d32 =
37234 + DWC_READ_REG32(&hcd->core_if->host_if->
37235 + hc_regs[i]->hcint);
37236 + hcintmsk.d32 =
37237 + DWC_READ_REG32(&hcd->core_if->host_if->
37238 + hc_regs[i]->hcintmsk);
37239 + DWC_PRINTF(" hfnum: 0x%08x\n", hfnum.d32);
37240 + DWC_PRINTF(" hcchar: 0x%08x\n", hcchar.d32);
37241 + DWC_PRINTF(" hctsiz: 0x%08x\n", hctsiz.d32);
37242 + DWC_PRINTF(" hcint: 0x%08x\n", hcint.d32);
37243 + DWC_PRINTF(" hcintmsk: 0x%08x\n", hcintmsk.d32);
37244 + }
37245 + if (hc->xfer_started && hc->qh) {
37246 + dwc_otg_qtd_t *qtd;
37247 + dwc_otg_hcd_urb_t *urb;
37248 +
37249 + DWC_CIRCLEQ_FOREACH(qtd, &hc->qh->qtd_list, qtd_list_entry) {
37250 + if (!qtd->in_process)
37251 + break;
37252 +
37253 + urb = qtd->urb;
37254 + DWC_PRINTF(" URB Info:\n");
37255 + DWC_PRINTF(" qtd: %p, urb: %p\n", qtd, urb);
37256 + if (urb) {
37257 + DWC_PRINTF(" Dev: %d, EP: %d %s\n",
37258 + dwc_otg_hcd_get_dev_addr(&urb->
37259 + pipe_info),
37260 + dwc_otg_hcd_get_ep_num(&urb->
37261 + pipe_info),
37262 + dwc_otg_hcd_is_pipe_in(&urb->
37263 + pipe_info) ?
37264 + "IN" : "OUT");
37265 + DWC_PRINTF(" Max packet size: %d\n",
37266 + dwc_otg_hcd_get_mps(&urb->
37267 + pipe_info));
37268 + DWC_PRINTF(" transfer_buffer: %p\n",
37269 + urb->buf);
37270 + DWC_PRINTF(" transfer_dma: %p\n",
37271 + (void *)urb->dma);
37272 + DWC_PRINTF(" transfer_buffer_length: %d\n",
37273 + urb->length);
37274 + DWC_PRINTF(" actual_length: %d\n",
37275 + urb->actual_length);
37276 + }
37277 + }
37278 + }
37279 + }
37280 + DWC_PRINTF(" non_periodic_channels: %d\n", hcd->non_periodic_channels);
37281 + DWC_PRINTF(" periodic_channels: %d\n", hcd->periodic_channels);
37282 + DWC_PRINTF(" periodic_usecs: %d\n", hcd->periodic_usecs);
37283 + np_tx_status.d32 =
37284 + DWC_READ_REG32(&hcd->core_if->core_global_regs->gnptxsts);
37285 + DWC_PRINTF(" NP Tx Req Queue Space Avail: %d\n",
37286 + np_tx_status.b.nptxqspcavail);
37287 + DWC_PRINTF(" NP Tx FIFO Space Avail: %d\n",
37288 + np_tx_status.b.nptxfspcavail);
37289 + p_tx_status.d32 =
37290 + DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hptxsts);
37291 + DWC_PRINTF(" P Tx Req Queue Space Avail: %d\n",
37292 + p_tx_status.b.ptxqspcavail);
37293 + DWC_PRINTF(" P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail);
37294 + dwc_otg_hcd_dump_frrem(hcd);
37295 + dwc_otg_dump_global_registers(hcd->core_if);
37296 + dwc_otg_dump_host_registers(hcd->core_if);
37297 + DWC_PRINTF
37298 + ("************************************************************\n");
37299 + DWC_PRINTF("\n");
37300 +#endif
37301 +}
37302 +
37303 +#ifdef DEBUG
37304 +void dwc_print_setup_data(uint8_t * setup)
37305 +{
37306 + int i;
37307 + if (CHK_DEBUG_LEVEL(DBG_HCD)) {
37308 + DWC_PRINTF("Setup Data = MSB ");
37309 + for (i = 7; i >= 0; i--)
37310 + DWC_PRINTF("%02x ", setup[i]);
37311 + DWC_PRINTF("\n");
37312 + DWC_PRINTF(" bmRequestType Tranfer = %s\n",
37313 + (setup[0] & 0x80) ? "Device-to-Host" :
37314 + "Host-to-Device");
37315 + DWC_PRINTF(" bmRequestType Type = ");
37316 + switch ((setup[0] & 0x60) >> 5) {
37317 + case 0:
37318 + DWC_PRINTF("Standard\n");
37319 + break;
37320 + case 1:
37321 + DWC_PRINTF("Class\n");
37322 + break;
37323 + case 2:
37324 + DWC_PRINTF("Vendor\n");
37325 + break;
37326 + case 3:
37327 + DWC_PRINTF("Reserved\n");
37328 + break;
37329 + }
37330 + DWC_PRINTF(" bmRequestType Recipient = ");
37331 + switch (setup[0] & 0x1f) {
37332 + case 0:
37333 + DWC_PRINTF("Device\n");
37334 + break;
37335 + case 1:
37336 + DWC_PRINTF("Interface\n");
37337 + break;
37338 + case 2:
37339 + DWC_PRINTF("Endpoint\n");
37340 + break;
37341 + case 3:
37342 + DWC_PRINTF("Other\n");
37343 + break;
37344 + default:
37345 + DWC_PRINTF("Reserved\n");
37346 + break;
37347 + }
37348 + DWC_PRINTF(" bRequest = 0x%0x\n", setup[1]);
37349 + DWC_PRINTF(" wValue = 0x%0x\n", *((uint16_t *) & setup[2]));
37350 + DWC_PRINTF(" wIndex = 0x%0x\n", *((uint16_t *) & setup[4]));
37351 + DWC_PRINTF(" wLength = 0x%0x\n\n", *((uint16_t *) & setup[6]));
37352 + }
37353 +}
37354 +#endif
37355 +
37356 +void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd)
37357 +{
37358 +#if 0
37359 + DWC_PRINTF("Frame remaining at SOF:\n");
37360 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37361 + hcd->frrem_samples, hcd->frrem_accum,
37362 + (hcd->frrem_samples > 0) ?
37363 + hcd->frrem_accum / hcd->frrem_samples : 0);
37364 +
37365 + DWC_PRINTF("\n");
37366 + DWC_PRINTF("Frame remaining at start_transfer (uframe 7):\n");
37367 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37368 + hcd->core_if->hfnum_7_samples,
37369 + hcd->core_if->hfnum_7_frrem_accum,
37370 + (hcd->core_if->hfnum_7_samples >
37371 + 0) ? hcd->core_if->hfnum_7_frrem_accum /
37372 + hcd->core_if->hfnum_7_samples : 0);
37373 + DWC_PRINTF("Frame remaining at start_transfer (uframe 0):\n");
37374 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37375 + hcd->core_if->hfnum_0_samples,
37376 + hcd->core_if->hfnum_0_frrem_accum,
37377 + (hcd->core_if->hfnum_0_samples >
37378 + 0) ? hcd->core_if->hfnum_0_frrem_accum /
37379 + hcd->core_if->hfnum_0_samples : 0);
37380 + DWC_PRINTF("Frame remaining at start_transfer (uframe 1-6):\n");
37381 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37382 + hcd->core_if->hfnum_other_samples,
37383 + hcd->core_if->hfnum_other_frrem_accum,
37384 + (hcd->core_if->hfnum_other_samples >
37385 + 0) ? hcd->core_if->hfnum_other_frrem_accum /
37386 + hcd->core_if->hfnum_other_samples : 0);
37387 +
37388 + DWC_PRINTF("\n");
37389 + DWC_PRINTF("Frame remaining at sample point A (uframe 7):\n");
37390 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37391 + hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a,
37392 + (hcd->hfnum_7_samples_a > 0) ?
37393 + hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0);
37394 + DWC_PRINTF("Frame remaining at sample point A (uframe 0):\n");
37395 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37396 + hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a,
37397 + (hcd->hfnum_0_samples_a > 0) ?
37398 + hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0);
37399 + DWC_PRINTF("Frame remaining at sample point A (uframe 1-6):\n");
37400 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37401 + hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a,
37402 + (hcd->hfnum_other_samples_a > 0) ?
37403 + hcd->hfnum_other_frrem_accum_a /
37404 + hcd->hfnum_other_samples_a : 0);
37405 +
37406 + DWC_PRINTF("\n");
37407 + DWC_PRINTF("Frame remaining at sample point B (uframe 7):\n");
37408 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37409 + hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b,
37410 + (hcd->hfnum_7_samples_b > 0) ?
37411 + hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0);
37412 + DWC_PRINTF("Frame remaining at sample point B (uframe 0):\n");
37413 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37414 + hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b,
37415 + (hcd->hfnum_0_samples_b > 0) ?
37416 + hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0);
37417 + DWC_PRINTF("Frame remaining at sample point B (uframe 1-6):\n");
37418 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37419 + hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b,
37420 + (hcd->hfnum_other_samples_b > 0) ?
37421 + hcd->hfnum_other_frrem_accum_b /
37422 + hcd->hfnum_other_samples_b : 0);
37423 +#endif
37424 +}
37425 +
37426 +#endif /* DWC_DEVICE_ONLY */
37427 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
37428 new file mode 100644
37429 index 0000000..bb4f67a
37430 --- /dev/null
37431 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
37432 @@ -0,0 +1,824 @@
37433 +/* ==========================================================================
37434 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.h $
37435 + * $Revision: #58 $
37436 + * $Date: 2011/09/15 $
37437 + * $Change: 1846647 $
37438 + *
37439 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
37440 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
37441 + * otherwise expressly agreed to in writing between Synopsys and you.
37442 + *
37443 + * The Software IS NOT an item of Licensed Software or Licensed Product under
37444 + * any End User Software License Agreement or Agreement for Licensed Product
37445 + * with Synopsys or any supplement thereto. You are permitted to use and
37446 + * redistribute this Software in source and binary forms, with or without
37447 + * modification, provided that redistributions of source code must retain this
37448 + * notice. You may not view, use, disclose, copy or distribute this file or
37449 + * any information contained herein except pursuant to this license grant from
37450 + * Synopsys. If you do not agree with this notice, including the disclaimer
37451 + * below, then you are not authorized to use the Software.
37452 + *
37453 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
37454 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37455 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37456 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
37457 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37458 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
37459 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
37460 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37461 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37462 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
37463 + * DAMAGE.
37464 + * ========================================================================== */
37465 +#ifndef DWC_DEVICE_ONLY
37466 +#ifndef __DWC_HCD_H__
37467 +#define __DWC_HCD_H__
37468 +
37469 +#include "dwc_otg_os_dep.h"
37470 +#include "usb.h"
37471 +#include "dwc_otg_hcd_if.h"
37472 +#include "dwc_otg_core_if.h"
37473 +#include "dwc_list.h"
37474 +#include "dwc_otg_cil.h"
37475 +
37476 +/**
37477 + * @file
37478 + *
37479 + * This file contains the structures, constants, and interfaces for
37480 + * the Host Contoller Driver (HCD).
37481 + *
37482 + * The Host Controller Driver (HCD) is responsible for translating requests
37483 + * from the USB Driver into the appropriate actions on the DWC_otg controller.
37484 + * It isolates the USBD from the specifics of the controller by providing an
37485 + * API to the USBD.
37486 + */
37487 +
37488 +struct dwc_otg_hcd_pipe_info {
37489 + uint8_t dev_addr;
37490 + uint8_t ep_num;
37491 + uint8_t pipe_type;
37492 + uint8_t pipe_dir;
37493 + uint16_t mps;
37494 +};
37495 +
37496 +struct dwc_otg_hcd_iso_packet_desc {
37497 + uint32_t offset;
37498 + uint32_t length;
37499 + uint32_t actual_length;
37500 + uint32_t status;
37501 +};
37502 +
37503 +struct dwc_otg_qtd;
37504 +
37505 +struct dwc_otg_hcd_urb {
37506 + void *priv;
37507 + struct dwc_otg_qtd *qtd;
37508 + void *buf;
37509 + dwc_dma_t dma;
37510 + void *setup_packet;
37511 + dwc_dma_t setup_dma;
37512 + uint32_t length;
37513 + uint32_t actual_length;
37514 + uint32_t status;
37515 + uint32_t error_count;
37516 + uint32_t packet_count;
37517 + uint32_t flags;
37518 + uint16_t interval;
37519 + struct dwc_otg_hcd_pipe_info pipe_info;
37520 + struct dwc_otg_hcd_iso_packet_desc iso_descs[0];
37521 +};
37522 +
37523 +static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe)
37524 +{
37525 + return pipe->ep_num;
37526 +}
37527 +
37528 +static inline uint8_t dwc_otg_hcd_get_pipe_type(struct dwc_otg_hcd_pipe_info
37529 + *pipe)
37530 +{
37531 + return pipe->pipe_type;
37532 +}
37533 +
37534 +static inline uint16_t dwc_otg_hcd_get_mps(struct dwc_otg_hcd_pipe_info *pipe)
37535 +{
37536 + return pipe->mps;
37537 +}
37538 +
37539 +static inline uint8_t dwc_otg_hcd_get_dev_addr(struct dwc_otg_hcd_pipe_info
37540 + *pipe)
37541 +{
37542 + return pipe->dev_addr;
37543 +}
37544 +
37545 +static inline uint8_t dwc_otg_hcd_is_pipe_isoc(struct dwc_otg_hcd_pipe_info
37546 + *pipe)
37547 +{
37548 + return (pipe->pipe_type == UE_ISOCHRONOUS);
37549 +}
37550 +
37551 +static inline uint8_t dwc_otg_hcd_is_pipe_int(struct dwc_otg_hcd_pipe_info
37552 + *pipe)
37553 +{
37554 + return (pipe->pipe_type == UE_INTERRUPT);
37555 +}
37556 +
37557 +static inline uint8_t dwc_otg_hcd_is_pipe_bulk(struct dwc_otg_hcd_pipe_info
37558 + *pipe)
37559 +{
37560 + return (pipe->pipe_type == UE_BULK);
37561 +}
37562 +
37563 +static inline uint8_t dwc_otg_hcd_is_pipe_control(struct dwc_otg_hcd_pipe_info
37564 + *pipe)
37565 +{
37566 + return (pipe->pipe_type == UE_CONTROL);
37567 +}
37568 +
37569 +static inline uint8_t dwc_otg_hcd_is_pipe_in(struct dwc_otg_hcd_pipe_info *pipe)
37570 +{
37571 + return (pipe->pipe_dir == UE_DIR_IN);
37572 +}
37573 +
37574 +static inline uint8_t dwc_otg_hcd_is_pipe_out(struct dwc_otg_hcd_pipe_info
37575 + *pipe)
37576 +{
37577 + return (!dwc_otg_hcd_is_pipe_in(pipe));
37578 +}
37579 +
37580 +static inline void dwc_otg_hcd_fill_pipe(struct dwc_otg_hcd_pipe_info *pipe,
37581 + uint8_t devaddr, uint8_t ep_num,
37582 + uint8_t pipe_type, uint8_t pipe_dir,
37583 + uint16_t mps)
37584 +{
37585 + pipe->dev_addr = devaddr;
37586 + pipe->ep_num = ep_num;
37587 + pipe->pipe_type = pipe_type;
37588 + pipe->pipe_dir = pipe_dir;
37589 + pipe->mps = mps;
37590 +}
37591 +
37592 +/**
37593 + * Phases for control transfers.
37594 + */
37595 +typedef enum dwc_otg_control_phase {
37596 + DWC_OTG_CONTROL_SETUP,
37597 + DWC_OTG_CONTROL_DATA,
37598 + DWC_OTG_CONTROL_STATUS
37599 +} dwc_otg_control_phase_e;
37600 +
37601 +/** Transaction types. */
37602 +typedef enum dwc_otg_transaction_type {
37603 + DWC_OTG_TRANSACTION_NONE,
37604 + DWC_OTG_TRANSACTION_PERIODIC,
37605 + DWC_OTG_TRANSACTION_NON_PERIODIC,
37606 + DWC_OTG_TRANSACTION_ALL
37607 +} dwc_otg_transaction_type_e;
37608 +
37609 +struct dwc_otg_qh;
37610 +
37611 +/**
37612 + * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
37613 + * interrupt, or isochronous transfer. A single QTD is created for each URB
37614 + * (of one of these types) submitted to the HCD. The transfer associated with
37615 + * a QTD may require one or multiple transactions.
37616 + *
37617 + * A QTD is linked to a Queue Head, which is entered in either the
37618 + * non-periodic or periodic schedule for execution. When a QTD is chosen for
37619 + * execution, some or all of its transactions may be executed. After
37620 + * execution, the state of the QTD is updated. The QTD may be retired if all
37621 + * its transactions are complete or if an error occurred. Otherwise, it
37622 + * remains in the schedule so more transactions can be executed later.
37623 + */
37624 +typedef struct dwc_otg_qtd {
37625 + /**
37626 + * Determines the PID of the next data packet for the data phase of
37627 + * control transfers. Ignored for other transfer types.<br>
37628 + * One of the following values:
37629 + * - DWC_OTG_HC_PID_DATA0
37630 + * - DWC_OTG_HC_PID_DATA1
37631 + */
37632 + uint8_t data_toggle;
37633 +
37634 + /** Current phase for control transfers (Setup, Data, or Status). */
37635 + dwc_otg_control_phase_e control_phase;
37636 +
37637 + /** Keep track of the current split type
37638 + * for FS/LS endpoints on a HS Hub */
37639 + uint8_t complete_split;
37640 +
37641 + /** How many bytes transferred during SSPLIT OUT */
37642 + uint32_t ssplit_out_xfer_count;
37643 +
37644 + /**
37645 + * Holds the number of bus errors that have occurred for a transaction
37646 + * within this transfer.
37647 + */
37648 + uint8_t error_count;
37649 +
37650 + /**
37651 + * Index of the next frame descriptor for an isochronous transfer. A
37652 + * frame descriptor describes the buffer position and length of the
37653 + * data to be transferred in the next scheduled (micro)frame of an
37654 + * isochronous transfer. It also holds status for that transaction.
37655 + * The frame index starts at 0.
37656 + */
37657 + uint16_t isoc_frame_index;
37658 +
37659 + /** Position of the ISOC split on full/low speed */
37660 + uint8_t isoc_split_pos;
37661 +
37662 + /** Position of the ISOC split in the buffer for the current frame */
37663 + uint16_t isoc_split_offset;
37664 +
37665 + /** URB for this transfer */
37666 + struct dwc_otg_hcd_urb *urb;
37667 +
37668 + struct dwc_otg_qh *qh;
37669 +
37670 + /** This list of QTDs */
37671 + DWC_CIRCLEQ_ENTRY(dwc_otg_qtd) qtd_list_entry;
37672 +
37673 + /** Indicates if this QTD is currently processed by HW. */
37674 + uint8_t in_process;
37675 +
37676 + /** Number of DMA descriptors for this QTD */
37677 + uint8_t n_desc;
37678 +
37679 + /**
37680 + * Last activated frame(packet) index.
37681 + * Used in Descriptor DMA mode only.
37682 + */
37683 + uint16_t isoc_frame_index_last;
37684 +
37685 +} dwc_otg_qtd_t;
37686 +
37687 +DWC_CIRCLEQ_HEAD(dwc_otg_qtd_list, dwc_otg_qtd);
37688 +
37689 +/**
37690 + * A Queue Head (QH) holds the static characteristics of an endpoint and
37691 + * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
37692 + * be entered in either the non-periodic or periodic schedule.
37693 + */
37694 +typedef struct dwc_otg_qh {
37695 + /**
37696 + * Endpoint type.
37697 + * One of the following values:
37698 + * - UE_CONTROL
37699 + * - UE_BULK
37700 + * - UE_INTERRUPT
37701 + * - UE_ISOCHRONOUS
37702 + */
37703 + uint8_t ep_type;
37704 + uint8_t ep_is_in;
37705 +
37706 + /** wMaxPacketSize Field of Endpoint Descriptor. */
37707 + uint16_t maxp;
37708 +
37709 + /**
37710 + * Device speed.
37711 + * One of the following values:
37712 + * - DWC_OTG_EP_SPEED_LOW
37713 + * - DWC_OTG_EP_SPEED_FULL
37714 + * - DWC_OTG_EP_SPEED_HIGH
37715 + */
37716 + uint8_t dev_speed;
37717 +
37718 + /**
37719 + * Determines the PID of the next data packet for non-control
37720 + * transfers. Ignored for control transfers.<br>
37721 + * One of the following values:
37722 + * - DWC_OTG_HC_PID_DATA0
37723 + * - DWC_OTG_HC_PID_DATA1
37724 + */
37725 + uint8_t data_toggle;
37726 +
37727 + /** Ping state if 1. */
37728 + uint8_t ping_state;
37729 +
37730 + /**
37731 + * List of QTDs for this QH.
37732 + */
37733 + struct dwc_otg_qtd_list qtd_list;
37734 +
37735 + /** Host channel currently processing transfers for this QH. */
37736 + struct dwc_hc *channel;
37737 +
37738 + /** Full/low speed endpoint on high-speed hub requires split. */
37739 + uint8_t do_split;
37740 +
37741 + /** @name Periodic schedule information */
37742 + /** @{ */
37743 +
37744 + /** Bandwidth in microseconds per (micro)frame. */
37745 + uint16_t usecs;
37746 +
37747 + /** Interval between transfers in (micro)frames. */
37748 + uint16_t interval;
37749 +
37750 + /**
37751 + * (micro)frame to initialize a periodic transfer. The transfer
37752 + * executes in the following (micro)frame.
37753 + */
37754 + uint16_t sched_frame;
37755 +
37756 + /** (micro)frame at which last start split was initialized. */
37757 + uint16_t start_split_frame;
37758 +
37759 + /** @} */
37760 +
37761 + /**
37762 + * Used instead of original buffer if
37763 + * it(physical address) is not dword-aligned.
37764 + */
37765 + uint8_t *dw_align_buf;
37766 + dwc_dma_t dw_align_buf_dma;
37767 +
37768 + /** Entry for QH in either the periodic or non-periodic schedule. */
37769 + dwc_list_link_t qh_list_entry;
37770 +
37771 + /** @name Descriptor DMA support */
37772 + /** @{ */
37773 +
37774 + /** Descriptor List. */
37775 + dwc_otg_host_dma_desc_t *desc_list;
37776 +
37777 + /** Descriptor List physical address. */
37778 + dwc_dma_t desc_list_dma;
37779 +
37780 + /**
37781 + * Xfer Bytes array.
37782 + * Each element corresponds to a descriptor and indicates
37783 + * original XferSize size value for the descriptor.
37784 + */
37785 + uint32_t *n_bytes;
37786 +
37787 + /** Actual number of transfer descriptors in a list. */
37788 + uint16_t ntd;
37789 +
37790 + /** First activated isochronous transfer descriptor index. */
37791 + uint8_t td_first;
37792 + /** Last activated isochronous transfer descriptor index. */
37793 + uint8_t td_last;
37794 +
37795 + /** @} */
37796 +
37797 +
37798 + uint16_t speed;
37799 + uint16_t frame_usecs[8];
37800 +} dwc_otg_qh_t;
37801 +
37802 +DWC_CIRCLEQ_HEAD(hc_list, dwc_hc);
37803 +
37804 +/**
37805 + * This structure holds the state of the HCD, including the non-periodic and
37806 + * periodic schedules.
37807 + */
37808 +struct dwc_otg_hcd {
37809 + /** The DWC otg device pointer */
37810 + struct dwc_otg_device *otg_dev;
37811 + /** DWC OTG Core Interface Layer */
37812 + dwc_otg_core_if_t *core_if;
37813 +
37814 + /** Function HCD driver callbacks */
37815 + struct dwc_otg_hcd_function_ops *fops;
37816 +
37817 + /** Internal DWC HCD Flags */
37818 + volatile union dwc_otg_hcd_internal_flags {
37819 + uint32_t d32;
37820 + struct {
37821 + unsigned port_connect_status_change:1;
37822 + unsigned port_connect_status:1;
37823 + unsigned port_reset_change:1;
37824 + unsigned port_enable_change:1;
37825 + unsigned port_suspend_change:1;
37826 + unsigned port_over_current_change:1;
37827 + unsigned port_l1_change:1;
37828 + unsigned reserved:26;
37829 + } b;
37830 + } flags;
37831 +
37832 + /**
37833 + * Inactive items in the non-periodic schedule. This is a list of
37834 + * Queue Heads. Transfers associated with these Queue Heads are not
37835 + * currently assigned to a host channel.
37836 + */
37837 + dwc_list_link_t non_periodic_sched_inactive;
37838 +
37839 + /**
37840 + * Active items in the non-periodic schedule. This is a list of
37841 + * Queue Heads. Transfers associated with these Queue Heads are
37842 + * currently assigned to a host channel.
37843 + */
37844 + dwc_list_link_t non_periodic_sched_active;
37845 +
37846 + /**
37847 + * Pointer to the next Queue Head to process in the active
37848 + * non-periodic schedule.
37849 + */
37850 + dwc_list_link_t *non_periodic_qh_ptr;
37851 +
37852 + /**
37853 + * Inactive items in the periodic schedule. This is a list of QHs for
37854 + * periodic transfers that are _not_ scheduled for the next frame.
37855 + * Each QH in the list has an interval counter that determines when it
37856 + * needs to be scheduled for execution. This scheduling mechanism
37857 + * allows only a simple calculation for periodic bandwidth used (i.e.
37858 + * must assume that all periodic transfers may need to execute in the
37859 + * same frame). However, it greatly simplifies scheduling and should
37860 + * be sufficient for the vast majority of OTG hosts, which need to
37861 + * connect to a small number of peripherals at one time.
37862 + *
37863 + * Items move from this list to periodic_sched_ready when the QH
37864 + * interval counter is 0 at SOF.
37865 + */
37866 + dwc_list_link_t periodic_sched_inactive;
37867 +
37868 + /**
37869 + * List of periodic QHs that are ready for execution in the next
37870 + * frame, but have not yet been assigned to host channels.
37871 + *
37872 + * Items move from this list to periodic_sched_assigned as host
37873 + * channels become available during the current frame.
37874 + */
37875 + dwc_list_link_t periodic_sched_ready;
37876 +
37877 + /**
37878 + * List of periodic QHs to be executed in the next frame that are
37879 + * assigned to host channels.
37880 + *
37881 + * Items move from this list to periodic_sched_queued as the
37882 + * transactions for the QH are queued to the DWC_otg controller.
37883 + */
37884 + dwc_list_link_t periodic_sched_assigned;
37885 +
37886 + /**
37887 + * List of periodic QHs that have been queued for execution.
37888 + *
37889 + * Items move from this list to either periodic_sched_inactive or
37890 + * periodic_sched_ready when the channel associated with the transfer
37891 + * is released. If the interval for the QH is 1, the item moves to
37892 + * periodic_sched_ready because it must be rescheduled for the next
37893 + * frame. Otherwise, the item moves to periodic_sched_inactive.
37894 + */
37895 + dwc_list_link_t periodic_sched_queued;
37896 +
37897 + /**
37898 + * Total bandwidth claimed so far for periodic transfers. This value
37899 + * is in microseconds per (micro)frame. The assumption is that all
37900 + * periodic transfers may occur in the same (micro)frame.
37901 + */
37902 + uint16_t periodic_usecs;
37903 +
37904 + /**
37905 + * Total bandwidth claimed so far for all periodic transfers
37906 + * in a frame.
37907 + * This will include a mixture of HS and FS transfers.
37908 + * Units are microseconds per (micro)frame.
37909 + * We have a budget per frame and have to schedule
37910 + * transactions accordingly.
37911 + * Watch out for the fact that things are actually scheduled for the
37912 + * "next frame".
37913 + */
37914 + uint16_t frame_usecs[8];
37915 +
37916 +
37917 + /**
37918 + * Frame number read from the core at SOF. The value ranges from 0 to
37919 + * DWC_HFNUM_MAX_FRNUM.
37920 + */
37921 + uint16_t frame_number;
37922 +
37923 + /**
37924 + * Count of periodic QHs, if using several eps. For SOF enable/disable.
37925 + */
37926 + uint16_t periodic_qh_count;
37927 +
37928 + /**
37929 + * Free host channels in the controller. This is a list of
37930 + * dwc_hc_t items.
37931 + */
37932 + struct hc_list free_hc_list;
37933 + /**
37934 + * Number of host channels assigned to periodic transfers. Currently
37935 + * assuming that there is a dedicated host channel for each periodic
37936 + * transaction and at least one host channel available for
37937 + * non-periodic transactions.
37938 + */
37939 + int periodic_channels; /* microframe_schedule==0 */
37940 +
37941 + /**
37942 + * Number of host channels assigned to non-periodic transfers.
37943 + */
37944 + int non_periodic_channels; /* microframe_schedule==0 */
37945 +
37946 + /**
37947 + * Number of host channels assigned to non-periodic transfers.
37948 + */
37949 + int available_host_channels;
37950 +
37951 + /**
37952 + * Array of pointers to the host channel descriptors. Allows accessing
37953 + * a host channel descriptor given the host channel number. This is
37954 + * useful in interrupt handlers.
37955 + */
37956 + struct dwc_hc *hc_ptr_array[MAX_EPS_CHANNELS];
37957 +
37958 + /**
37959 + * Buffer to use for any data received during the status phase of a
37960 + * control transfer. Normally no data is transferred during the status
37961 + * phase. This buffer is used as a bit bucket.
37962 + */
37963 + uint8_t *status_buf;
37964 +
37965 + /**
37966 + * DMA address for status_buf.
37967 + */
37968 + dma_addr_t status_buf_dma;
37969 +#define DWC_OTG_HCD_STATUS_BUF_SIZE 64
37970 +
37971 + /**
37972 + * Connection timer. An OTG host must display a message if the device
37973 + * does not connect. Started when the VBus power is turned on via
37974 + * sysfs attribute "buspower".
37975 + */
37976 + dwc_timer_t *conn_timer;
37977 +
37978 + /* Tasket to do a reset */
37979 + dwc_tasklet_t *reset_tasklet;
37980 +
37981 + /* */
37982 + dwc_spinlock_t *lock;
37983 +
37984 + /**
37985 + * Private data that could be used by OS wrapper.
37986 + */
37987 + void *priv;
37988 +
37989 + uint8_t otg_port;
37990 +
37991 + /** Frame List */
37992 + uint32_t *frame_list;
37993 +
37994 + /** Frame List DMA address */
37995 + dma_addr_t frame_list_dma;
37996 +
37997 +#ifdef DEBUG
37998 + uint32_t frrem_samples;
37999 + uint64_t frrem_accum;
38000 +
38001 + uint32_t hfnum_7_samples_a;
38002 + uint64_t hfnum_7_frrem_accum_a;
38003 + uint32_t hfnum_0_samples_a;
38004 + uint64_t hfnum_0_frrem_accum_a;
38005 + uint32_t hfnum_other_samples_a;
38006 + uint64_t hfnum_other_frrem_accum_a;
38007 +
38008 + uint32_t hfnum_7_samples_b;
38009 + uint64_t hfnum_7_frrem_accum_b;
38010 + uint32_t hfnum_0_samples_b;
38011 + uint64_t hfnum_0_frrem_accum_b;
38012 + uint32_t hfnum_other_samples_b;
38013 + uint64_t hfnum_other_frrem_accum_b;
38014 +#endif
38015 +};
38016 +
38017 +/** @name Transaction Execution Functions */
38018 +/** @{ */
38019 +extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t
38020 + * hcd);
38021 +extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
38022 + dwc_otg_transaction_type_e tr_type);
38023 +
38024 +/** @} */
38025 +
38026 +/** @name Interrupt Handler Functions */
38027 +/** @{ */
38028 +extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38029 +extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38030 +extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t *
38031 + dwc_otg_hcd);
38032 +extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t *
38033 + dwc_otg_hcd);
38034 +extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t *
38035 + dwc_otg_hcd);
38036 +extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t *
38037 + dwc_otg_hcd);
38038 +extern int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38039 +extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr(dwc_otg_hcd_t *
38040 + dwc_otg_hcd);
38041 +extern int32_t dwc_otg_hcd_handle_disconnect_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38042 +extern int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38043 +extern int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd,
38044 + uint32_t num);
38045 +extern int32_t dwc_otg_hcd_handle_session_req_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38046 +extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr(dwc_otg_hcd_t *
38047 + dwc_otg_hcd);
38048 +/** @} */
38049 +
38050 +/** @name Schedule Queue Functions */
38051 +/** @{ */
38052 +
38053 +/* Implemented in dwc_otg_hcd_queue.c */
38054 +extern dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
38055 + dwc_otg_hcd_urb_t * urb, int atomic_alloc);
38056 +extern void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38057 +extern int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38058 +extern void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38059 +extern void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
38060 + int sched_csplit);
38061 +
38062 +/** Remove and free a QH */
38063 +static inline void dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd_t * hcd,
38064 + dwc_otg_qh_t * qh)
38065 +{
38066 + dwc_irqflags_t flags;
38067 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
38068 + dwc_otg_hcd_qh_remove(hcd, qh);
38069 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
38070 + dwc_otg_hcd_qh_free(hcd, qh);
38071 +}
38072 +
38073 +/** Allocates memory for a QH structure.
38074 + * @return Returns the memory allocate or NULL on error. */
38075 +static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc(int atomic_alloc)
38076 +{
38077 + if (atomic_alloc)
38078 + return (dwc_otg_qh_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qh_t));
38079 + else
38080 + return (dwc_otg_qh_t *) DWC_ALLOC(sizeof(dwc_otg_qh_t));
38081 +}
38082 +
38083 +extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb,
38084 + int atomic_alloc);
38085 +extern void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb);
38086 +extern int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, dwc_otg_hcd_t * dwc_otg_hcd,
38087 + dwc_otg_qh_t ** qh, int atomic_alloc);
38088 +
38089 +/** Allocates memory for a QTD structure.
38090 + * @return Returns the memory allocate or NULL on error. */
38091 +static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc(int atomic_alloc)
38092 +{
38093 + if (atomic_alloc)
38094 + return (dwc_otg_qtd_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qtd_t));
38095 + else
38096 + return (dwc_otg_qtd_t *) DWC_ALLOC(sizeof(dwc_otg_qtd_t));
38097 +}
38098 +
38099 +/** Frees the memory for a QTD structure. QTD should already be removed from
38100 + * list.
38101 + * @param qtd QTD to free.*/
38102 +static inline void dwc_otg_hcd_qtd_free(dwc_otg_qtd_t * qtd)
38103 +{
38104 + DWC_FREE(qtd);
38105 +}
38106 +
38107 +/** Removes a QTD from list.
38108 + * @param hcd HCD instance.
38109 + * @param qtd QTD to remove from list.
38110 + * @param qh QTD belongs to.
38111 + */
38112 +static inline void dwc_otg_hcd_qtd_remove(dwc_otg_hcd_t * hcd,
38113 + dwc_otg_qtd_t * qtd,
38114 + dwc_otg_qh_t * qh)
38115 +{
38116 + DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
38117 +}
38118 +
38119 +/** Remove and free a QTD
38120 + * Need to disable IRQ and hold hcd lock while calling this function out of
38121 + * interrupt servicing chain */
38122 +static inline void dwc_otg_hcd_qtd_remove_and_free(dwc_otg_hcd_t * hcd,
38123 + dwc_otg_qtd_t * qtd,
38124 + dwc_otg_qh_t * qh)
38125 +{
38126 + dwc_otg_hcd_qtd_remove(hcd, qtd, qh);
38127 + dwc_otg_hcd_qtd_free(qtd);
38128 +}
38129 +
38130 +/** @} */
38131 +
38132 +/** @name Descriptor DMA Supporting Functions */
38133 +/** @{ */
38134 +
38135 +extern void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38136 +extern void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
38137 + dwc_hc_t * hc,
38138 + dwc_otg_hc_regs_t * hc_regs,
38139 + dwc_otg_halt_status_e halt_status);
38140 +
38141 +extern int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38142 +extern void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38143 +
38144 +/** @} */
38145 +
38146 +/** @name Internal Functions */
38147 +/** @{ */
38148 +dwc_otg_qh_t *dwc_urb_to_qh(dwc_otg_hcd_urb_t * urb);
38149 +/** @} */
38150 +
38151 +#ifdef CONFIG_USB_DWC_OTG_LPM
38152 +extern int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd,
38153 + uint8_t devaddr);
38154 +extern void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd);
38155 +#endif
38156 +
38157 +/** Gets the QH that contains the list_head */
38158 +#define dwc_list_to_qh(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qh_t, qh_list_entry)
38159 +
38160 +/** Gets the QTD that contains the list_head */
38161 +#define dwc_list_to_qtd(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qtd_t, qtd_list_entry)
38162 +
38163 +/** Check if QH is non-periodic */
38164 +#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == UE_BULK) || \
38165 + (_qh_ptr_->ep_type == UE_CONTROL))
38166 +
38167 +/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */
38168 +#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
38169 +
38170 +/** Packet size for any kind of endpoint descriptor */
38171 +#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
38172 +
38173 +/**
38174 + * Returns true if _frame1 is less than or equal to _frame2. The comparison is
38175 + * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the
38176 + * frame number when the max frame number is reached.
38177 + */
38178 +static inline int dwc_frame_num_le(uint16_t frame1, uint16_t frame2)
38179 +{
38180 + return ((frame2 - frame1) & DWC_HFNUM_MAX_FRNUM) <=
38181 + (DWC_HFNUM_MAX_FRNUM >> 1);
38182 +}
38183 +
38184 +/**
38185 + * Returns true if _frame1 is greater than _frame2. The comparison is done
38186 + * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
38187 + * number when the max frame number is reached.
38188 + */
38189 +static inline int dwc_frame_num_gt(uint16_t frame1, uint16_t frame2)
38190 +{
38191 + return (frame1 != frame2) &&
38192 + (((frame1 - frame2) & DWC_HFNUM_MAX_FRNUM) <
38193 + (DWC_HFNUM_MAX_FRNUM >> 1));
38194 +}
38195 +
38196 +/**
38197 + * Increments _frame by the amount specified by _inc. The addition is done
38198 + * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value.
38199 + */
38200 +static inline uint16_t dwc_frame_num_inc(uint16_t frame, uint16_t inc)
38201 +{
38202 + return (frame + inc) & DWC_HFNUM_MAX_FRNUM;
38203 +}
38204 +
38205 +static inline uint16_t dwc_full_frame_num(uint16_t frame)
38206 +{
38207 + return (frame & DWC_HFNUM_MAX_FRNUM) >> 3;
38208 +}
38209 +
38210 +static inline uint16_t dwc_micro_frame_num(uint16_t frame)
38211 +{
38212 + return frame & 0x7;
38213 +}
38214 +
38215 +void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
38216 + dwc_otg_hc_regs_t * hc_regs,
38217 + dwc_otg_qtd_t * qtd);
38218 +
38219 +#ifdef DEBUG
38220 +/**
38221 + * Macro to sample the remaining PHY clocks left in the current frame. This
38222 + * may be used during debugging to determine the average time it takes to
38223 + * execute sections of code. There are two possible sample points, "a" and
38224 + * "b", so the _letter argument must be one of these values.
38225 + *
38226 + * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
38227 + * example, "cat /sys/devices/lm0/hcd_frrem".
38228 + */
38229 +#define dwc_sample_frrem(_hcd, _qh, _letter) \
38230 +{ \
38231 + hfnum_data_t hfnum; \
38232 + dwc_otg_qtd_t *qtd; \
38233 + qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \
38234 + if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \
38235 + hfnum.d32 = DWC_READ_REG32(&_hcd->core_if->host_if->host_global_regs->hfnum); \
38236 + switch (hfnum.b.frnum & 0x7) { \
38237 + case 7: \
38238 + _hcd->hfnum_7_samples_##_letter++; \
38239 + _hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \
38240 + break; \
38241 + case 0: \
38242 + _hcd->hfnum_0_samples_##_letter++; \
38243 + _hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \
38244 + break; \
38245 + default: \
38246 + _hcd->hfnum_other_samples_##_letter++; \
38247 + _hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \
38248 + break; \
38249 + } \
38250 + } \
38251 +}
38252 +#else
38253 +#define dwc_sample_frrem(_hcd, _qh, _letter)
38254 +#endif
38255 +#endif
38256 +#endif /* DWC_DEVICE_ONLY */
38257 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
38258 new file mode 100644
38259 index 0000000..274967b
38260 --- /dev/null
38261 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
38262 @@ -0,0 +1,1133 @@
38263 +/*==========================================================================
38264 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_ddma.c $
38265 + * $Revision: #10 $
38266 + * $Date: 2011/10/20 $
38267 + * $Change: 1869464 $
38268 + *
38269 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
38270 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
38271 + * otherwise expressly agreed to in writing between Synopsys and you.
38272 + *
38273 + * The Software IS NOT an item of Licensed Software or Licensed Product under
38274 + * any End User Software License Agreement or Agreement for Licensed Product
38275 + * with Synopsys or any supplement thereto. You are permitted to use and
38276 + * redistribute this Software in source and binary forms, with or without
38277 + * modification, provided that redistributions of source code must retain this
38278 + * notice. You may not view, use, disclose, copy or distribute this file or
38279 + * any information contained herein except pursuant to this license grant from
38280 + * Synopsys. If you do not agree with this notice, including the disclaimer
38281 + * below, then you are not authorized to use the Software.
38282 + *
38283 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
38284 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38285 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38286 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
38287 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38288 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
38289 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38290 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38291 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38292 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
38293 + * DAMAGE.
38294 + * ========================================================================== */
38295 +#ifndef DWC_DEVICE_ONLY
38296 +
38297 +/** @file
38298 + * This file contains Descriptor DMA support implementation for host mode.
38299 + */
38300 +
38301 +#include "dwc_otg_hcd.h"
38302 +#include "dwc_otg_regs.h"
38303 +
38304 +extern bool microframe_schedule;
38305 +
38306 +static inline uint8_t frame_list_idx(uint16_t frame)
38307 +{
38308 + return (frame & (MAX_FRLIST_EN_NUM - 1));
38309 +}
38310 +
38311 +static inline uint16_t desclist_idx_inc(uint16_t idx, uint16_t inc, uint8_t speed)
38312 +{
38313 + return (idx + inc) &
38314 + (((speed ==
38315 + DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
38316 + MAX_DMA_DESC_NUM_GENERIC) - 1);
38317 +}
38318 +
38319 +static inline uint16_t desclist_idx_dec(uint16_t idx, uint16_t inc, uint8_t speed)
38320 +{
38321 + return (idx - inc) &
38322 + (((speed ==
38323 + DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
38324 + MAX_DMA_DESC_NUM_GENERIC) - 1);
38325 +}
38326 +
38327 +static inline uint16_t max_desc_num(dwc_otg_qh_t * qh)
38328 +{
38329 + return (((qh->ep_type == UE_ISOCHRONOUS)
38330 + && (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH))
38331 + ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC);
38332 +}
38333 +static inline uint16_t frame_incr_val(dwc_otg_qh_t * qh)
38334 +{
38335 + return ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH)
38336 + ? ((qh->interval + 8 - 1) / 8)
38337 + : qh->interval);
38338 +}
38339 +
38340 +static int desc_list_alloc(dwc_otg_qh_t * qh)
38341 +{
38342 + int retval = 0;
38343 +
38344 + qh->desc_list = (dwc_otg_host_dma_desc_t *)
38345 + DWC_DMA_ALLOC(sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh),
38346 + &qh->desc_list_dma);
38347 +
38348 + if (!qh->desc_list) {
38349 + retval = -DWC_E_NO_MEMORY;
38350 + DWC_ERROR("%s: DMA descriptor list allocation failed\n", __func__);
38351 +
38352 + }
38353 +
38354 + dwc_memset(qh->desc_list, 0x00,
38355 + sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
38356 +
38357 + qh->n_bytes =
38358 + (uint32_t *) DWC_ALLOC(sizeof(uint32_t) * max_desc_num(qh));
38359 +
38360 + if (!qh->n_bytes) {
38361 + retval = -DWC_E_NO_MEMORY;
38362 + DWC_ERROR
38363 + ("%s: Failed to allocate array for descriptors' size actual values\n",
38364 + __func__);
38365 +
38366 + }
38367 + return retval;
38368 +
38369 +}
38370 +
38371 +static void desc_list_free(dwc_otg_qh_t * qh)
38372 +{
38373 + if (qh->desc_list) {
38374 + DWC_DMA_FREE(max_desc_num(qh), qh->desc_list,
38375 + qh->desc_list_dma);
38376 + qh->desc_list = NULL;
38377 + }
38378 +
38379 + if (qh->n_bytes) {
38380 + DWC_FREE(qh->n_bytes);
38381 + qh->n_bytes = NULL;
38382 + }
38383 +}
38384 +
38385 +static int frame_list_alloc(dwc_otg_hcd_t * hcd)
38386 +{
38387 + int retval = 0;
38388 + if (hcd->frame_list)
38389 + return 0;
38390 +
38391 + hcd->frame_list = DWC_DMA_ALLOC(4 * MAX_FRLIST_EN_NUM,
38392 + &hcd->frame_list_dma);
38393 + if (!hcd->frame_list) {
38394 + retval = -DWC_E_NO_MEMORY;
38395 + DWC_ERROR("%s: Frame List allocation failed\n", __func__);
38396 + }
38397 +
38398 + dwc_memset(hcd->frame_list, 0x00, 4 * MAX_FRLIST_EN_NUM);
38399 +
38400 + return retval;
38401 +}
38402 +
38403 +static void frame_list_free(dwc_otg_hcd_t * hcd)
38404 +{
38405 + if (!hcd->frame_list)
38406 + return;
38407 +
38408 + DWC_DMA_FREE(4 * MAX_FRLIST_EN_NUM, hcd->frame_list, hcd->frame_list_dma);
38409 + hcd->frame_list = NULL;
38410 +}
38411 +
38412 +static void per_sched_enable(dwc_otg_hcd_t * hcd, uint16_t fr_list_en)
38413 +{
38414 +
38415 + hcfg_data_t hcfg;
38416 +
38417 + hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
38418 +
38419 + if (hcfg.b.perschedena) {
38420 + /* already enabled */
38421 + return;
38422 + }
38423 +
38424 + DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hflbaddr,
38425 + hcd->frame_list_dma);
38426 +
38427 + switch (fr_list_en) {
38428 + case 64:
38429 + hcfg.b.frlisten = 3;
38430 + break;
38431 + case 32:
38432 + hcfg.b.frlisten = 2;
38433 + break;
38434 + case 16:
38435 + hcfg.b.frlisten = 1;
38436 + break;
38437 + case 8:
38438 + hcfg.b.frlisten = 0;
38439 + break;
38440 + default:
38441 + break;
38442 + }
38443 +
38444 + hcfg.b.perschedena = 1;
38445 +
38446 + DWC_DEBUGPL(DBG_HCD, "Enabling Periodic schedule\n");
38447 + DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
38448 +
38449 +}
38450 +
38451 +static void per_sched_disable(dwc_otg_hcd_t * hcd)
38452 +{
38453 + hcfg_data_t hcfg;
38454 +
38455 + hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
38456 +
38457 + if (!hcfg.b.perschedena) {
38458 + /* already disabled */
38459 + return;
38460 + }
38461 + hcfg.b.perschedena = 0;
38462 +
38463 + DWC_DEBUGPL(DBG_HCD, "Disabling Periodic schedule\n");
38464 + DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
38465 +}
38466 +
38467 +/*
38468 + * Activates/Deactivates FrameList entries for the channel
38469 + * based on endpoint servicing period.
38470 + */
38471 +void update_frame_list(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t enable)
38472 +{
38473 + uint16_t i, j, inc;
38474 + dwc_hc_t *hc = NULL;
38475 +
38476 + if (!qh->channel) {
38477 + DWC_ERROR("qh->channel = %p", qh->channel);
38478 + return;
38479 + }
38480 +
38481 + if (!hcd) {
38482 + DWC_ERROR("------hcd = %p", hcd);
38483 + return;
38484 + }
38485 +
38486 + if (!hcd->frame_list) {
38487 + DWC_ERROR("-------hcd->frame_list = %p", hcd->frame_list);
38488 + return;
38489 + }
38490 +
38491 + hc = qh->channel;
38492 + inc = frame_incr_val(qh);
38493 + if (qh->ep_type == UE_ISOCHRONOUS)
38494 + i = frame_list_idx(qh->sched_frame);
38495 + else
38496 + i = 0;
38497 +
38498 + j = i;
38499 + do {
38500 + if (enable)
38501 + hcd->frame_list[j] |= (1 << hc->hc_num);
38502 + else
38503 + hcd->frame_list[j] &= ~(1 << hc->hc_num);
38504 + j = (j + inc) & (MAX_FRLIST_EN_NUM - 1);
38505 + }
38506 + while (j != i);
38507 + if (!enable)
38508 + return;
38509 + hc->schinfo = 0;
38510 + if (qh->channel->speed == DWC_OTG_EP_SPEED_HIGH) {
38511 + j = 1;
38512 + /* TODO - check this */
38513 + inc = (8 + qh->interval - 1) / qh->interval;
38514 + for (i = 0; i < inc; i++) {
38515 + hc->schinfo |= j;
38516 + j = j << qh->interval;
38517 + }
38518 + } else {
38519 + hc->schinfo = 0xff;
38520 + }
38521 +}
38522 +
38523 +#if 1
38524 +void dump_frame_list(dwc_otg_hcd_t * hcd)
38525 +{
38526 + int i = 0;
38527 + DWC_PRINTF("--FRAME LIST (hex) --\n");
38528 + for (i = 0; i < MAX_FRLIST_EN_NUM; i++) {
38529 + DWC_PRINTF("%x\t", hcd->frame_list[i]);
38530 + if (!(i % 8) && i)
38531 + DWC_PRINTF("\n");
38532 + }
38533 + DWC_PRINTF("\n----\n");
38534 +
38535 +}
38536 +#endif
38537 +
38538 +static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38539 +{
38540 + dwc_irqflags_t flags;
38541 + dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
38542 +
38543 + dwc_hc_t *hc = qh->channel;
38544 + if (dwc_qh_is_non_per(qh)) {
38545 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
38546 + if (!microframe_schedule)
38547 + hcd->non_periodic_channels--;
38548 + else
38549 + hcd->available_host_channels++;
38550 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
38551 + } else
38552 + update_frame_list(hcd, qh, 0);
38553 +
38554 + /*
38555 + * The condition is added to prevent double cleanup try in case of device
38556 + * disconnect. See channel cleanup in dwc_otg_hcd_disconnect_cb().
38557 + */
38558 + if (hc->qh) {
38559 + dwc_otg_hc_cleanup(hcd->core_if, hc);
38560 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
38561 + hc->qh = NULL;
38562 + }
38563 +
38564 + qh->channel = NULL;
38565 + qh->ntd = 0;
38566 +
38567 + if (qh->desc_list) {
38568 + dwc_memset(qh->desc_list, 0x00,
38569 + sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
38570 + }
38571 + DWC_SPINLOCK_FREE(channel_lock);
38572 +}
38573 +
38574 +/**
38575 + * Initializes a QH structure's Descriptor DMA related members.
38576 + * Allocates memory for descriptor list.
38577 + * On first periodic QH, allocates memory for FrameList
38578 + * and enables periodic scheduling.
38579 + *
38580 + * @param hcd The HCD state structure for the DWC OTG controller.
38581 + * @param qh The QH to init.
38582 + *
38583 + * @return 0 if successful, negative error code otherwise.
38584 + */
38585 +int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38586 +{
38587 + int retval = 0;
38588 +
38589 + if (qh->do_split) {
38590 + DWC_ERROR("SPLIT Transfers are not supported in Descriptor DMA.\n");
38591 + return -1;
38592 + }
38593 +
38594 + retval = desc_list_alloc(qh);
38595 +
38596 + if ((retval == 0)
38597 + && (qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)) {
38598 + if (!hcd->frame_list) {
38599 + retval = frame_list_alloc(hcd);
38600 + /* Enable periodic schedule on first periodic QH */
38601 + if (retval == 0)
38602 + per_sched_enable(hcd, MAX_FRLIST_EN_NUM);
38603 + }
38604 + }
38605 +
38606 + qh->ntd = 0;
38607 +
38608 + return retval;
38609 +}
38610 +
38611 +/**
38612 + * Frees descriptor list memory associated with the QH.
38613 + * If QH is periodic and the last, frees FrameList memory
38614 + * and disables periodic scheduling.
38615 + *
38616 + * @param hcd The HCD state structure for the DWC OTG controller.
38617 + * @param qh The QH to init.
38618 + */
38619 +void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38620 +{
38621 + desc_list_free(qh);
38622 +
38623 + /*
38624 + * Channel still assigned due to some reasons.
38625 + * Seen on Isoc URB dequeue. Channel halted but no subsequent
38626 + * ChHalted interrupt to release the channel. Afterwards
38627 + * when it comes here from endpoint disable routine
38628 + * channel remains assigned.
38629 + */
38630 + if (qh->channel)
38631 + release_channel_ddma(hcd, qh);
38632 +
38633 + if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)
38634 + && (microframe_schedule || !hcd->periodic_channels) && hcd->frame_list) {
38635 +
38636 + per_sched_disable(hcd);
38637 + frame_list_free(hcd);
38638 + }
38639 +}
38640 +
38641 +static uint8_t frame_to_desc_idx(dwc_otg_qh_t * qh, uint16_t frame_idx)
38642 +{
38643 + if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
38644 + /*
38645 + * Descriptor set(8 descriptors) index
38646 + * which is 8-aligned.
38647 + */
38648 + return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
38649 + } else {
38650 + return (frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1));
38651 + }
38652 +}
38653 +
38654 +/*
38655 + * Determine starting frame for Isochronous transfer.
38656 + * Few frames skipped to prevent race condition with HC.
38657 + */
38658 +static uint8_t calc_starting_frame(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
38659 + uint8_t * skip_frames)
38660 +{
38661 + uint16_t frame = 0;
38662 + hcd->frame_number = dwc_otg_hcd_get_frame_number(hcd);
38663 +
38664 + /* sched_frame is always frame number(not uFrame) both in FS and HS !! */
38665 +
38666 + /*
38667 + * skip_frames is used to limit activated descriptors number
38668 + * to avoid the situation when HC services the last activated
38669 + * descriptor firstly.
38670 + * Example for FS:
38671 + * Current frame is 1, scheduled frame is 3. Since HC always fetches the descriptor
38672 + * corresponding to curr_frame+1, the descriptor corresponding to frame 2
38673 + * will be fetched. If the number of descriptors is max=64 (or greather) the
38674 + * list will be fully programmed with Active descriptors and it is possible
38675 + * case(rare) that the latest descriptor(considering rollback) corresponding
38676 + * to frame 2 will be serviced first. HS case is more probable because, in fact,
38677 + * up to 11 uframes(16 in the code) may be skipped.
38678 + */
38679 + if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
38680 + /*
38681 + * Consider uframe counter also, to start xfer asap.
38682 + * If half of the frame elapsed skip 2 frames otherwise
38683 + * just 1 frame.
38684 + * Starting descriptor index must be 8-aligned, so
38685 + * if the current frame is near to complete the next one
38686 + * is skipped as well.
38687 + */
38688 +
38689 + if (dwc_micro_frame_num(hcd->frame_number) >= 5) {
38690 + *skip_frames = 2 * 8;
38691 + frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
38692 + } else {
38693 + *skip_frames = 1 * 8;
38694 + frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
38695 + }
38696 +
38697 + frame = dwc_full_frame_num(frame);
38698 + } else {
38699 + /*
38700 + * Two frames are skipped for FS - the current and the next.
38701 + * But for descriptor programming, 1 frame(descriptor) is enough,
38702 + * see example above.
38703 + */
38704 + *skip_frames = 1;
38705 + frame = dwc_frame_num_inc(hcd->frame_number, 2);
38706 + }
38707 +
38708 + return frame;
38709 +}
38710 +
38711 +/*
38712 + * Calculate initial descriptor index for isochronous transfer
38713 + * based on scheduled frame.
38714 + */
38715 +static uint8_t recalc_initial_desc_idx(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38716 +{
38717 + uint16_t frame = 0, fr_idx, fr_idx_tmp;
38718 + uint8_t skip_frames = 0;
38719 + /*
38720 + * With current ISOC processing algorithm the channel is being
38721 + * released when no more QTDs in the list(qh->ntd == 0).
38722 + * Thus this function is called only when qh->ntd == 0 and qh->channel == 0.
38723 + *
38724 + * So qh->channel != NULL branch is not used and just not removed from the
38725 + * source file. It is required for another possible approach which is,
38726 + * do not disable and release the channel when ISOC session completed,
38727 + * just move QH to inactive schedule until new QTD arrives.
38728 + * On new QTD, the QH moved back to 'ready' schedule,
38729 + * starting frame and therefore starting desc_index are recalculated.
38730 + * In this case channel is released only on ep_disable.
38731 + */
38732 +
38733 + /* Calculate starting descriptor index. For INTERRUPT endpoint it is always 0. */
38734 + if (qh->channel) {
38735 + frame = calc_starting_frame(hcd, qh, &skip_frames);
38736 + /*
38737 + * Calculate initial descriptor index based on FrameList current bitmap
38738 + * and servicing period.
38739 + */
38740 + fr_idx_tmp = frame_list_idx(frame);
38741 + fr_idx =
38742 + (MAX_FRLIST_EN_NUM + frame_list_idx(qh->sched_frame) -
38743 + fr_idx_tmp)
38744 + % frame_incr_val(qh);
38745 + fr_idx = (fr_idx + fr_idx_tmp) % MAX_FRLIST_EN_NUM;
38746 + } else {
38747 + qh->sched_frame = calc_starting_frame(hcd, qh, &skip_frames);
38748 + fr_idx = frame_list_idx(qh->sched_frame);
38749 + }
38750 +
38751 + qh->td_first = qh->td_last = frame_to_desc_idx(qh, fr_idx);
38752 +
38753 + return skip_frames;
38754 +}
38755 +
38756 +#define ISOC_URB_GIVEBACK_ASAP
38757 +
38758 +#define MAX_ISOC_XFER_SIZE_FS 1023
38759 +#define MAX_ISOC_XFER_SIZE_HS 3072
38760 +#define DESCNUM_THRESHOLD 4
38761 +
38762 +static void init_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
38763 + uint8_t skip_frames)
38764 +{
38765 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
38766 + dwc_otg_qtd_t *qtd;
38767 + dwc_otg_host_dma_desc_t *dma_desc;
38768 + uint16_t idx, inc, n_desc, ntd_max, max_xfer_size;
38769 +
38770 + idx = qh->td_last;
38771 + inc = qh->interval;
38772 + n_desc = 0;
38773 +
38774 + ntd_max = (max_desc_num(qh) + qh->interval - 1) / qh->interval;
38775 + if (skip_frames && !qh->channel)
38776 + ntd_max = ntd_max - skip_frames / qh->interval;
38777 +
38778 + max_xfer_size =
38779 + (qh->dev_speed ==
38780 + DWC_OTG_EP_SPEED_HIGH) ? MAX_ISOC_XFER_SIZE_HS :
38781 + MAX_ISOC_XFER_SIZE_FS;
38782 +
38783 + DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
38784 + while ((qh->ntd < ntd_max)
38785 + && (qtd->isoc_frame_index_last <
38786 + qtd->urb->packet_count)) {
38787 +
38788 + dma_desc = &qh->desc_list[idx];
38789 + dwc_memset(dma_desc, 0x00, sizeof(dwc_otg_host_dma_desc_t));
38790 +
38791 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
38792 +
38793 + if (frame_desc->length > max_xfer_size)
38794 + qh->n_bytes[idx] = max_xfer_size;
38795 + else
38796 + qh->n_bytes[idx] = frame_desc->length;
38797 + dma_desc->status.b_isoc.n_bytes = qh->n_bytes[idx];
38798 + dma_desc->status.b_isoc.a = 1;
38799 + dma_desc->status.b_isoc.sts = 0;
38800 +
38801 + dma_desc->buf = qtd->urb->dma + frame_desc->offset;
38802 +
38803 + qh->ntd++;
38804 +
38805 + qtd->isoc_frame_index_last++;
38806 +
38807 +#ifdef ISOC_URB_GIVEBACK_ASAP
38808 + /*
38809 + * Set IOC for each descriptor corresponding to the
38810 + * last frame of the URB.
38811 + */
38812 + if (qtd->isoc_frame_index_last ==
38813 + qtd->urb->packet_count)
38814 + dma_desc->status.b_isoc.ioc = 1;
38815 +
38816 +#endif
38817 + idx = desclist_idx_inc(idx, inc, qh->dev_speed);
38818 + n_desc++;
38819 +
38820 + }
38821 + qtd->in_process = 1;
38822 + }
38823 +
38824 + qh->td_last = idx;
38825 +
38826 +#ifdef ISOC_URB_GIVEBACK_ASAP
38827 + /* Set IOC for the last descriptor if descriptor list is full */
38828 + if (qh->ntd == ntd_max) {
38829 + idx = desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
38830 + qh->desc_list[idx].status.b_isoc.ioc = 1;
38831 + }
38832 +#else
38833 + /*
38834 + * Set IOC bit only for one descriptor.
38835 + * Always try to be ahead of HW processing,
38836 + * i.e. on IOC generation driver activates next descriptors but
38837 + * core continues to process descriptors followed the one with IOC set.
38838 + */
38839 +
38840 + if (n_desc > DESCNUM_THRESHOLD) {
38841 + /*
38842 + * Move IOC "up". Required even if there is only one QTD
38843 + * in the list, cause QTDs migth continue to be queued,
38844 + * but during the activation it was only one queued.
38845 + * Actually more than one QTD might be in the list if this function called
38846 + * from XferCompletion - QTDs was queued during HW processing of the previous
38847 + * descriptor chunk.
38848 + */
38849 + idx = dwc_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), qh->dev_speed);
38850 + } else {
38851 + /*
38852 + * Set the IOC for the latest descriptor
38853 + * if either number of descriptor is not greather than threshold
38854 + * or no more new descriptors activated.
38855 + */
38856 + idx = dwc_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
38857 + }
38858 +
38859 + qh->desc_list[idx].status.b_isoc.ioc = 1;
38860 +#endif
38861 +}
38862 +
38863 +static void init_non_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38864 +{
38865 +
38866 + dwc_hc_t *hc;
38867 + dwc_otg_host_dma_desc_t *dma_desc;
38868 + dwc_otg_qtd_t *qtd;
38869 + int num_packets, len, n_desc = 0;
38870 +
38871 + hc = qh->channel;
38872 +
38873 + /*
38874 + * Start with hc->xfer_buff initialized in
38875 + * assign_and_init_hc(), then if SG transfer consists of multiple URBs,
38876 + * this pointer re-assigned to the buffer of the currently processed QTD.
38877 + * For non-SG request there is always one QTD active.
38878 + */
38879 +
38880 + DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
38881 +
38882 + if (n_desc) {
38883 + /* SG request - more than 1 QTDs */
38884 + hc->xfer_buff = (uint8_t *)qtd->urb->dma + qtd->urb->actual_length;
38885 + hc->xfer_len = qtd->urb->length - qtd->urb->actual_length;
38886 + }
38887 +
38888 + qtd->n_desc = 0;
38889 +
38890 + do {
38891 + dma_desc = &qh->desc_list[n_desc];
38892 + len = hc->xfer_len;
38893 +
38894 + if (len > MAX_DMA_DESC_SIZE)
38895 + len = MAX_DMA_DESC_SIZE - hc->max_packet + 1;
38896 +
38897 + if (hc->ep_is_in) {
38898 + if (len > 0) {
38899 + num_packets = (len + hc->max_packet - 1) / hc->max_packet;
38900 + } else {
38901 + /* Need 1 packet for transfer length of 0. */
38902 + num_packets = 1;
38903 + }
38904 + /* Always program an integral # of max packets for IN transfers. */
38905 + len = num_packets * hc->max_packet;
38906 + }
38907 +
38908 + dma_desc->status.b.n_bytes = len;
38909 +
38910 + qh->n_bytes[n_desc] = len;
38911 +
38912 + if ((qh->ep_type == UE_CONTROL)
38913 + && (qtd->control_phase == DWC_OTG_CONTROL_SETUP))
38914 + dma_desc->status.b.sup = 1; /* Setup Packet */
38915 +
38916 + dma_desc->status.b.a = 1; /* Active descriptor */
38917 + dma_desc->status.b.sts = 0;
38918 +
38919 + dma_desc->buf =
38920 + ((unsigned long)hc->xfer_buff & 0xffffffff);
38921 +
38922 + /*
38923 + * Last descriptor(or single) of IN transfer
38924 + * with actual size less than MaxPacket.
38925 + */
38926 + if (len > hc->xfer_len) {
38927 + hc->xfer_len = 0;
38928 + } else {
38929 + hc->xfer_buff += len;
38930 + hc->xfer_len -= len;
38931 + }
38932 +
38933 + qtd->n_desc++;
38934 + n_desc++;
38935 + }
38936 + while ((hc->xfer_len > 0) && (n_desc != MAX_DMA_DESC_NUM_GENERIC));
38937 +
38938 +
38939 + qtd->in_process = 1;
38940 +
38941 + if (qh->ep_type == UE_CONTROL)
38942 + break;
38943 +
38944 + if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
38945 + break;
38946 + }
38947 +
38948 + if (n_desc) {
38949 + /* Request Transfer Complete interrupt for the last descriptor */
38950 + qh->desc_list[n_desc - 1].status.b.ioc = 1;
38951 + /* End of List indicator */
38952 + qh->desc_list[n_desc - 1].status.b.eol = 1;
38953 +
38954 + hc->ntd = n_desc;
38955 + }
38956 +}
38957 +
38958 +/**
38959 + * For Control and Bulk endpoints initializes descriptor list
38960 + * and starts the transfer.
38961 + *
38962 + * For Interrupt and Isochronous endpoints initializes descriptor list
38963 + * then updates FrameList, marking appropriate entries as active.
38964 + * In case of Isochronous, the starting descriptor index is calculated based
38965 + * on the scheduled frame, but only on the first transfer descriptor within a session.
38966 + * Then starts the transfer via enabling the channel.
38967 + * For Isochronous endpoint the channel is not halted on XferComplete
38968 + * interrupt so remains assigned to the endpoint(QH) until session is done.
38969 + *
38970 + * @param hcd The HCD state structure for the DWC OTG controller.
38971 + * @param qh The QH to init.
38972 + *
38973 + * @return 0 if successful, negative error code otherwise.
38974 + */
38975 +void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38976 +{
38977 + /* Channel is already assigned */
38978 + dwc_hc_t *hc = qh->channel;
38979 + uint8_t skip_frames = 0;
38980 +
38981 + switch (hc->ep_type) {
38982 + case DWC_OTG_EP_TYPE_CONTROL:
38983 + case DWC_OTG_EP_TYPE_BULK:
38984 + init_non_isoc_dma_desc(hcd, qh);
38985 +
38986 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
38987 + break;
38988 + case DWC_OTG_EP_TYPE_INTR:
38989 + init_non_isoc_dma_desc(hcd, qh);
38990 +
38991 + update_frame_list(hcd, qh, 1);
38992 +
38993 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
38994 + break;
38995 + case DWC_OTG_EP_TYPE_ISOC:
38996 +
38997 + if (!qh->ntd)
38998 + skip_frames = recalc_initial_desc_idx(hcd, qh);
38999 +
39000 + init_isoc_dma_desc(hcd, qh, skip_frames);
39001 +
39002 + if (!hc->xfer_started) {
39003 +
39004 + update_frame_list(hcd, qh, 1);
39005 +
39006 + /*
39007 + * Always set to max, instead of actual size.
39008 + * Otherwise ntd will be changed with
39009 + * channel being enabled. Not recommended.
39010 + *
39011 + */
39012 + hc->ntd = max_desc_num(qh);
39013 + /* Enable channel only once for ISOC */
39014 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
39015 + }
39016 +
39017 + break;
39018 + default:
39019 +
39020 + break;
39021 + }
39022 +}
39023 +
39024 +static void complete_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
39025 + dwc_hc_t * hc,
39026 + dwc_otg_hc_regs_t * hc_regs,
39027 + dwc_otg_halt_status_e halt_status)
39028 +{
39029 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
39030 + dwc_otg_qtd_t *qtd, *qtd_tmp;
39031 + dwc_otg_qh_t *qh;
39032 + dwc_otg_host_dma_desc_t *dma_desc;
39033 + uint16_t idx, remain;
39034 + uint8_t urb_compl;
39035 +
39036 + qh = hc->qh;
39037 + idx = qh->td_first;
39038 +
39039 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
39040 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry)
39041 + qtd->in_process = 0;
39042 + return;
39043 + } else if ((halt_status == DWC_OTG_HC_XFER_AHB_ERR) ||
39044 + (halt_status == DWC_OTG_HC_XFER_BABBLE_ERR)) {
39045 + /*
39046 + * Channel is halted in these error cases.
39047 + * Considered as serious issues.
39048 + * Complete all URBs marking all frames as failed,
39049 + * irrespective whether some of the descriptors(frames) succeeded or no.
39050 + * Pass error code to completion routine as well, to
39051 + * update urb->status, some of class drivers might use it to stop
39052 + * queing transfer requests.
39053 + */
39054 + int err = (halt_status == DWC_OTG_HC_XFER_AHB_ERR)
39055 + ? (-DWC_E_IO)
39056 + : (-DWC_E_OVERFLOW);
39057 +
39058 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
39059 + for (idx = 0; idx < qtd->urb->packet_count; idx++) {
39060 + frame_desc = &qtd->urb->iso_descs[idx];
39061 + frame_desc->status = err;
39062 + }
39063 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, err);
39064 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
39065 + }
39066 + return;
39067 + }
39068 +
39069 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
39070 +
39071 + if (!qtd->in_process)
39072 + break;
39073 +
39074 + urb_compl = 0;
39075 +
39076 + do {
39077 +
39078 + dma_desc = &qh->desc_list[idx];
39079 +
39080 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
39081 + remain = hc->ep_is_in ? dma_desc->status.b_isoc.n_bytes : 0;
39082 +
39083 + if (dma_desc->status.b_isoc.sts == DMA_DESC_STS_PKTERR) {
39084 + /*
39085 + * XactError or, unable to complete all the transactions
39086 + * in the scheduled micro-frame/frame,
39087 + * both indicated by DMA_DESC_STS_PKTERR.
39088 + */
39089 + qtd->urb->error_count++;
39090 + frame_desc->actual_length = qh->n_bytes[idx] - remain;
39091 + frame_desc->status = -DWC_E_PROTOCOL;
39092 + } else {
39093 + /* Success */
39094 +
39095 + frame_desc->actual_length = qh->n_bytes[idx] - remain;
39096 + frame_desc->status = 0;
39097 + }
39098 +
39099 + if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
39100 + /*
39101 + * urb->status is not used for isoc transfers here.
39102 + * The individual frame_desc status are used instead.
39103 + */
39104 +
39105 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
39106 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
39107 +
39108 + /*
39109 + * This check is necessary because urb_dequeue can be called
39110 + * from urb complete callback(sound driver example).
39111 + * All pending URBs are dequeued there, so no need for
39112 + * further processing.
39113 + */
39114 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
39115 + return;
39116 + }
39117 +
39118 + urb_compl = 1;
39119 +
39120 + }
39121 +
39122 + qh->ntd--;
39123 +
39124 + /* Stop if IOC requested descriptor reached */
39125 + if (dma_desc->status.b_isoc.ioc) {
39126 + idx = desclist_idx_inc(idx, qh->interval, hc->speed);
39127 + goto stop_scan;
39128 + }
39129 +
39130 + idx = desclist_idx_inc(idx, qh->interval, hc->speed);
39131 +
39132 + if (urb_compl)
39133 + break;
39134 + }
39135 + while (idx != qh->td_first);
39136 + }
39137 +stop_scan:
39138 + qh->td_first = idx;
39139 +}
39140 +
39141 +uint8_t update_non_isoc_urb_state_ddma(dwc_otg_hcd_t * hcd,
39142 + dwc_hc_t * hc,
39143 + dwc_otg_qtd_t * qtd,
39144 + dwc_otg_host_dma_desc_t * dma_desc,
39145 + dwc_otg_halt_status_e halt_status,
39146 + uint32_t n_bytes, uint8_t * xfer_done)
39147 +{
39148 +
39149 + uint16_t remain = hc->ep_is_in ? dma_desc->status.b.n_bytes : 0;
39150 + dwc_otg_hcd_urb_t *urb = qtd->urb;
39151 +
39152 + if (halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
39153 + urb->status = -DWC_E_IO;
39154 + return 1;
39155 + }
39156 + if (dma_desc->status.b.sts == DMA_DESC_STS_PKTERR) {
39157 + switch (halt_status) {
39158 + case DWC_OTG_HC_XFER_STALL:
39159 + urb->status = -DWC_E_PIPE;
39160 + break;
39161 + case DWC_OTG_HC_XFER_BABBLE_ERR:
39162 + urb->status = -DWC_E_OVERFLOW;
39163 + break;
39164 + case DWC_OTG_HC_XFER_XACT_ERR:
39165 + urb->status = -DWC_E_PROTOCOL;
39166 + break;
39167 + default:
39168 + DWC_ERROR("%s: Unhandled descriptor error status (%d)\n", __func__,
39169 + halt_status);
39170 + break;
39171 + }
39172 + return 1;
39173 + }
39174 +
39175 + if (dma_desc->status.b.a == 1) {
39176 + DWC_DEBUGPL(DBG_HCDV,
39177 + "Active descriptor encountered on channel %d\n",
39178 + hc->hc_num);
39179 + return 0;
39180 + }
39181 +
39182 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL) {
39183 + if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
39184 + urb->actual_length += n_bytes - remain;
39185 + if (remain || urb->actual_length == urb->length) {
39186 + /*
39187 + * For Control Data stage do not set urb->status=0 to prevent
39188 + * URB callback. Set it when Status phase done. See below.
39189 + */
39190 + *xfer_done = 1;
39191 + }
39192 +
39193 + } else if (qtd->control_phase == DWC_OTG_CONTROL_STATUS) {
39194 + urb->status = 0;
39195 + *xfer_done = 1;
39196 + }
39197 + /* No handling for SETUP stage */
39198 + } else {
39199 + /* BULK and INTR */
39200 + urb->actual_length += n_bytes - remain;
39201 + if (remain || urb->actual_length == urb->length) {
39202 + urb->status = 0;
39203 + *xfer_done = 1;
39204 + }
39205 + }
39206 +
39207 + return 0;
39208 +}
39209 +
39210 +static void complete_non_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
39211 + dwc_hc_t * hc,
39212 + dwc_otg_hc_regs_t * hc_regs,
39213 + dwc_otg_halt_status_e halt_status)
39214 +{
39215 + dwc_otg_hcd_urb_t *urb = NULL;
39216 + dwc_otg_qtd_t *qtd, *qtd_tmp;
39217 + dwc_otg_qh_t *qh;
39218 + dwc_otg_host_dma_desc_t *dma_desc;
39219 + uint32_t n_bytes, n_desc, i;
39220 + uint8_t failed = 0, xfer_done;
39221 +
39222 + n_desc = 0;
39223 +
39224 + qh = hc->qh;
39225 +
39226 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
39227 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
39228 + qtd->in_process = 0;
39229 + }
39230 + return;
39231 + }
39232 +
39233 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
39234 +
39235 + urb = qtd->urb;
39236 +
39237 + n_bytes = 0;
39238 + xfer_done = 0;
39239 +
39240 + for (i = 0; i < qtd->n_desc; i++) {
39241 + dma_desc = &qh->desc_list[n_desc];
39242 +
39243 + n_bytes = qh->n_bytes[n_desc];
39244 +
39245 + failed =
39246 + update_non_isoc_urb_state_ddma(hcd, hc, qtd,
39247 + dma_desc,
39248 + halt_status, n_bytes,
39249 + &xfer_done);
39250 +
39251 + if (failed
39252 + || (xfer_done
39253 + && (urb->status != -DWC_E_IN_PROGRESS))) {
39254 +
39255 + hcd->fops->complete(hcd, urb->priv, urb,
39256 + urb->status);
39257 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
39258 +
39259 + if (failed)
39260 + goto stop_scan;
39261 + } else if (qh->ep_type == UE_CONTROL) {
39262 + if (qtd->control_phase == DWC_OTG_CONTROL_SETUP) {
39263 + if (urb->length > 0) {
39264 + qtd->control_phase = DWC_OTG_CONTROL_DATA;
39265 + } else {
39266 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
39267 + }
39268 + DWC_DEBUGPL(DBG_HCDV, " Control setup transaction done\n");
39269 + } else if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
39270 + if (xfer_done) {
39271 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
39272 + DWC_DEBUGPL(DBG_HCDV, " Control data transfer done\n");
39273 + } else if (i + 1 == qtd->n_desc) {
39274 + /*
39275 + * Last descriptor for Control data stage which is
39276 + * not completed yet.
39277 + */
39278 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
39279 + }
39280 + }
39281 + }
39282 +
39283 + n_desc++;
39284 + }
39285 +
39286 + }
39287 +
39288 +stop_scan:
39289 +
39290 + if (qh->ep_type != UE_CONTROL) {
39291 + /*
39292 + * Resetting the data toggle for bulk
39293 + * and interrupt endpoints in case of stall. See handle_hc_stall_intr()
39294 + */
39295 + if (halt_status == DWC_OTG_HC_XFER_STALL)
39296 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
39297 + else
39298 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
39299 + }
39300 +
39301 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
39302 + hcint_data_t hcint;
39303 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
39304 + if (hcint.b.nyet) {
39305 + /*
39306 + * Got a NYET on the last transaction of the transfer. It
39307 + * means that the endpoint should be in the PING state at the
39308 + * beginning of the next transfer.
39309 + */
39310 + qh->ping_state = 1;
39311 + clear_hc_int(hc_regs, nyet);
39312 + }
39313 +
39314 + }
39315 +
39316 +}
39317 +
39318 +/**
39319 + * This function is called from interrupt handlers.
39320 + * Scans the descriptor list, updates URB's status and
39321 + * calls completion routine for the URB if it's done.
39322 + * Releases the channel to be used by other transfers.
39323 + * In case of Isochronous endpoint the channel is not halted until
39324 + * the end of the session, i.e. QTD list is empty.
39325 + * If periodic channel released the FrameList is updated accordingly.
39326 + *
39327 + * Calls transaction selection routines to activate pending transfers.
39328 + *
39329 + * @param hcd The HCD state structure for the DWC OTG controller.
39330 + * @param hc Host channel, the transfer is completed on.
39331 + * @param hc_regs Host channel registers.
39332 + * @param halt_status Reason the channel is being halted,
39333 + * or just XferComplete for isochronous transfer
39334 + */
39335 +void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
39336 + dwc_hc_t * hc,
39337 + dwc_otg_hc_regs_t * hc_regs,
39338 + dwc_otg_halt_status_e halt_status)
39339 +{
39340 + uint8_t continue_isoc_xfer = 0;
39341 + dwc_otg_transaction_type_e tr_type;
39342 + dwc_otg_qh_t *qh = hc->qh;
39343 +
39344 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
39345 +
39346 + complete_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
39347 +
39348 + /* Release the channel if halted or session completed */
39349 + if (halt_status != DWC_OTG_HC_XFER_COMPLETE ||
39350 + DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
39351 +
39352 + /* Halt the channel if session completed */
39353 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
39354 + dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
39355 + }
39356 +
39357 + release_channel_ddma(hcd, qh);
39358 + dwc_otg_hcd_qh_remove(hcd, qh);
39359 + } else {
39360 + /* Keep in assigned schedule to continue transfer */
39361 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
39362 + &qh->qh_list_entry);
39363 + continue_isoc_xfer = 1;
39364 +
39365 + }
39366 + /** @todo Consider the case when period exceeds FrameList size.
39367 + * Frame Rollover interrupt should be used.
39368 + */
39369 + } else {
39370 + /* Scan descriptor list to complete the URB(s), then release the channel */
39371 + complete_non_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
39372 +
39373 + release_channel_ddma(hcd, qh);
39374 + dwc_otg_hcd_qh_remove(hcd, qh);
39375 +
39376 + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
39377 + /* Add back to inactive non-periodic schedule on normal completion */
39378 + dwc_otg_hcd_qh_add(hcd, qh);
39379 + }
39380 +
39381 + }
39382 + tr_type = dwc_otg_hcd_select_transactions(hcd);
39383 + if (tr_type != DWC_OTG_TRANSACTION_NONE || continue_isoc_xfer) {
39384 + if (continue_isoc_xfer) {
39385 + if (tr_type == DWC_OTG_TRANSACTION_NONE) {
39386 + tr_type = DWC_OTG_TRANSACTION_PERIODIC;
39387 + } else if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC) {
39388 + tr_type = DWC_OTG_TRANSACTION_ALL;
39389 + }
39390 + }
39391 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
39392 + }
39393 +}
39394 +
39395 +#endif /* DWC_DEVICE_ONLY */
39396 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
39397 new file mode 100644
39398 index 0000000..4823167
39399 --- /dev/null
39400 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
39401 @@ -0,0 +1,412 @@
39402 +/* ==========================================================================
39403 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_if.h $
39404 + * $Revision: #12 $
39405 + * $Date: 2011/10/26 $
39406 + * $Change: 1873028 $
39407 + *
39408 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
39409 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
39410 + * otherwise expressly agreed to in writing between Synopsys and you.
39411 + *
39412 + * The Software IS NOT an item of Licensed Software or Licensed Product under
39413 + * any End User Software License Agreement or Agreement for Licensed Product
39414 + * with Synopsys or any supplement thereto. You are permitted to use and
39415 + * redistribute this Software in source and binary forms, with or without
39416 + * modification, provided that redistributions of source code must retain this
39417 + * notice. You may not view, use, disclose, copy or distribute this file or
39418 + * any information contained herein except pursuant to this license grant from
39419 + * Synopsys. If you do not agree with this notice, including the disclaimer
39420 + * below, then you are not authorized to use the Software.
39421 + *
39422 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
39423 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39424 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39425 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
39426 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39427 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39428 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39429 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39430 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39431 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
39432 + * DAMAGE.
39433 + * ========================================================================== */
39434 +#ifndef DWC_DEVICE_ONLY
39435 +#ifndef __DWC_HCD_IF_H__
39436 +#define __DWC_HCD_IF_H__
39437 +
39438 +#include "dwc_otg_core_if.h"
39439 +
39440 +/** @file
39441 + * This file defines DWC_OTG HCD Core API.
39442 + */
39443 +
39444 +struct dwc_otg_hcd;
39445 +typedef struct dwc_otg_hcd dwc_otg_hcd_t;
39446 +
39447 +struct dwc_otg_hcd_urb;
39448 +typedef struct dwc_otg_hcd_urb dwc_otg_hcd_urb_t;
39449 +
39450 +/** @name HCD Function Driver Callbacks */
39451 +/** @{ */
39452 +
39453 +/** This function is called whenever core switches to host mode. */
39454 +typedef int (*dwc_otg_hcd_start_cb_t) (dwc_otg_hcd_t * hcd);
39455 +
39456 +/** This function is called when device has been disconnected */
39457 +typedef int (*dwc_otg_hcd_disconnect_cb_t) (dwc_otg_hcd_t * hcd);
39458 +
39459 +/** Wrapper provides this function to HCD to core, so it can get hub information to which device is connected */
39460 +typedef int (*dwc_otg_hcd_hub_info_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
39461 + void *urb_handle,
39462 + uint32_t * hub_addr,
39463 + uint32_t * port_addr);
39464 +/** Via this function HCD core gets device speed */
39465 +typedef int (*dwc_otg_hcd_speed_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
39466 + void *urb_handle);
39467 +
39468 +/** This function is called when urb is completed */
39469 +typedef int (*dwc_otg_hcd_complete_urb_cb_t) (dwc_otg_hcd_t * hcd,
39470 + void *urb_handle,
39471 + dwc_otg_hcd_urb_t * dwc_otg_urb,
39472 + int32_t status);
39473 +
39474 +/** Via this function HCD core gets b_hnp_enable parameter */
39475 +typedef int (*dwc_otg_hcd_get_b_hnp_enable) (dwc_otg_hcd_t * hcd);
39476 +
39477 +struct dwc_otg_hcd_function_ops {
39478 + dwc_otg_hcd_start_cb_t start;
39479 + dwc_otg_hcd_disconnect_cb_t disconnect;
39480 + dwc_otg_hcd_hub_info_from_urb_cb_t hub_info;
39481 + dwc_otg_hcd_speed_from_urb_cb_t speed;
39482 + dwc_otg_hcd_complete_urb_cb_t complete;
39483 + dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable;
39484 +};
39485 +/** @} */
39486 +
39487 +/** @name HCD Core API */
39488 +/** @{ */
39489 +/** This function allocates dwc_otg_hcd structure and returns pointer on it. */
39490 +extern dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void);
39491 +
39492 +/** This function should be called to initiate HCD Core.
39493 + *
39494 + * @param hcd The HCD
39495 + * @param core_if The DWC_OTG Core
39496 + *
39497 + * Returns -DWC_E_NO_MEMORY if no enough memory.
39498 + * Returns 0 on success
39499 + */
39500 +extern int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if);
39501 +
39502 +/** Frees HCD
39503 + *
39504 + * @param hcd The HCD
39505 + */
39506 +extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd);
39507 +
39508 +/** This function should be called on every hardware interrupt.
39509 + *
39510 + * @param dwc_otg_hcd The HCD
39511 + *
39512 + * Returns non zero if interrupt is handled
39513 + * Return 0 if interrupt is not handled
39514 + */
39515 +extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
39516 +
39517 +/**
39518 + * Returns private data set by
39519 + * dwc_otg_hcd_set_priv_data function.
39520 + *
39521 + * @param hcd The HCD
39522 + */
39523 +extern void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd);
39524 +
39525 +/**
39526 + * Set private data.
39527 + *
39528 + * @param hcd The HCD
39529 + * @param priv_data pointer to be stored in private data
39530 + */
39531 +extern void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data);
39532 +
39533 +/**
39534 + * This function initializes the HCD Core.
39535 + *
39536 + * @param hcd The HCD
39537 + * @param fops The Function Driver Operations data structure containing pointers to all callbacks.
39538 + *
39539 + * Returns -DWC_E_NO_DEVICE if Core is currently is in device mode.
39540 + * Returns 0 on success
39541 + */
39542 +extern int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
39543 + struct dwc_otg_hcd_function_ops *fops);
39544 +
39545 +/**
39546 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
39547 + * stopped.
39548 + *
39549 + * @param hcd The HCD
39550 + */
39551 +extern void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd);
39552 +
39553 +/**
39554 + * Handles hub class-specific requests.
39555 + *
39556 + * @param dwc_otg_hcd The HCD
39557 + * @param typeReq Request Type
39558 + * @param wValue wValue from control request
39559 + * @param wIndex wIndex from control request
39560 + * @param buf data buffer
39561 + * @param wLength data buffer length
39562 + *
39563 + * Returns -DWC_E_INVALID if invalid argument is passed
39564 + * Returns 0 on success
39565 + */
39566 +extern int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
39567 + uint16_t typeReq, uint16_t wValue,
39568 + uint16_t wIndex, uint8_t * buf,
39569 + uint16_t wLength);
39570 +
39571 +/**
39572 + * Returns otg port number.
39573 + *
39574 + * @param hcd The HCD
39575 + */
39576 +extern uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd);
39577 +
39578 +/**
39579 + * Returns OTG version - either 1.3 or 2.0.
39580 + *
39581 + * @param core_if The core_if structure pointer
39582 + */
39583 +extern uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if);
39584 +
39585 +/**
39586 + * Returns 1 if currently core is acting as B host, and 0 otherwise.
39587 + *
39588 + * @param hcd The HCD
39589 + */
39590 +extern uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd);
39591 +
39592 +/**
39593 + * Returns current frame number.
39594 + *
39595 + * @param hcd The HCD
39596 + */
39597 +extern int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * hcd);
39598 +
39599 +/**
39600 + * Dumps hcd state.
39601 + *
39602 + * @param hcd The HCD
39603 + */
39604 +extern void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd);
39605 +
39606 +/**
39607 + * Dump the average frame remaining at SOF. This can be used to
39608 + * determine average interrupt latency. Frame remaining is also shown for
39609 + * start transfer and two additional sample points.
39610 + * Currently this function is not implemented.
39611 + *
39612 + * @param hcd The HCD
39613 + */
39614 +extern void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd);
39615 +
39616 +/**
39617 + * Sends LPM transaction to the local device.
39618 + *
39619 + * @param hcd The HCD
39620 + * @param devaddr Device Address
39621 + * @param hird Host initiated resume duration
39622 + * @param bRemoteWake Value of bRemoteWake field in LPM transaction
39623 + *
39624 + * Returns negative value if sending LPM transaction was not succeeded.
39625 + * Returns 0 on success.
39626 + */
39627 +extern int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr,
39628 + uint8_t hird, uint8_t bRemoteWake);
39629 +
39630 +/* URB interface */
39631 +
39632 +/**
39633 + * Allocates memory for dwc_otg_hcd_urb structure.
39634 + * Allocated memory should be freed by call of DWC_FREE.
39635 + *
39636 + * @param hcd The HCD
39637 + * @param iso_desc_count Count of ISOC descriptors
39638 + * @param atomic_alloc Specefies whether to perform atomic allocation.
39639 + */
39640 +extern dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
39641 + int iso_desc_count,
39642 + int atomic_alloc);
39643 +
39644 +/**
39645 + * Set pipe information in URB.
39646 + *
39647 + * @param hcd_urb DWC_OTG URB
39648 + * @param devaddr Device Address
39649 + * @param ep_num Endpoint Number
39650 + * @param ep_type Endpoint Type
39651 + * @param ep_dir Endpoint Direction
39652 + * @param mps Max Packet Size
39653 + */
39654 +extern void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * hcd_urb,
39655 + uint8_t devaddr, uint8_t ep_num,
39656 + uint8_t ep_type, uint8_t ep_dir,
39657 + uint16_t mps);
39658 +
39659 +/* Transfer flags */
39660 +#define URB_GIVEBACK_ASAP 0x1
39661 +#define URB_SEND_ZERO_PACKET 0x2
39662 +
39663 +/**
39664 + * Sets dwc_otg_hcd_urb parameters.
39665 + *
39666 + * @param urb DWC_OTG URB allocated by dwc_otg_hcd_urb_alloc function.
39667 + * @param urb_handle Unique handle for request, this will be passed back
39668 + * to function driver in completion callback.
39669 + * @param buf The buffer for the data
39670 + * @param dma The DMA buffer for the data
39671 + * @param buflen Transfer length
39672 + * @param sp Buffer for setup data
39673 + * @param sp_dma DMA address of setup data buffer
39674 + * @param flags Transfer flags
39675 + * @param interval Polling interval for interrupt or isochronous transfers.
39676 + */
39677 +extern void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * urb,
39678 + void *urb_handle, void *buf,
39679 + dwc_dma_t dma, uint32_t buflen, void *sp,
39680 + dwc_dma_t sp_dma, uint32_t flags,
39681 + uint16_t interval);
39682 +
39683 +/** Gets status from dwc_otg_hcd_urb
39684 + *
39685 + * @param dwc_otg_urb DWC_OTG URB
39686 + */
39687 +extern uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb);
39688 +
39689 +/** Gets actual length from dwc_otg_hcd_urb
39690 + *
39691 + * @param dwc_otg_urb DWC_OTG URB
39692 + */
39693 +extern uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t *
39694 + dwc_otg_urb);
39695 +
39696 +/** Gets error count from dwc_otg_hcd_urb. Only for ISOC URBs
39697 + *
39698 + * @param dwc_otg_urb DWC_OTG URB
39699 + */
39700 +extern uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t *
39701 + dwc_otg_urb);
39702 +
39703 +/** Set ISOC descriptor offset and length
39704 + *
39705 + * @param dwc_otg_urb DWC_OTG URB
39706 + * @param desc_num ISOC descriptor number
39707 + * @param offset Offset from beginig of buffer.
39708 + * @param length Transaction length
39709 + */
39710 +extern void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
39711 + int desc_num, uint32_t offset,
39712 + uint32_t length);
39713 +
39714 +/** Get status of ISOC descriptor, specified by desc_num
39715 + *
39716 + * @param dwc_otg_urb DWC_OTG URB
39717 + * @param desc_num ISOC descriptor number
39718 + */
39719 +extern uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t *
39720 + dwc_otg_urb, int desc_num);
39721 +
39722 +/** Get actual length of ISOC descriptor, specified by desc_num
39723 + *
39724 + * @param dwc_otg_urb DWC_OTG URB
39725 + * @param desc_num ISOC descriptor number
39726 + */
39727 +extern uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
39728 + dwc_otg_urb,
39729 + int desc_num);
39730 +
39731 +/** Queue URB. After transfer is completes, the complete callback will be called with the URB status
39732 + *
39733 + * @param dwc_otg_hcd The HCD
39734 + * @param dwc_otg_urb DWC_OTG URB
39735 + * @param ep_handle Out parameter for returning endpoint handle
39736 + * @param atomic_alloc Flag to do atomic allocation if needed
39737 + *
39738 + * Returns -DWC_E_NO_DEVICE if no device is connected.
39739 + * Returns -DWC_E_NO_MEMORY if there is no enough memory.
39740 + * Returns 0 on success.
39741 + */
39742 +extern int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * dwc_otg_hcd,
39743 + dwc_otg_hcd_urb_t * dwc_otg_urb,
39744 + void **ep_handle, int atomic_alloc);
39745 +
39746 +/** De-queue the specified URB
39747 + *
39748 + * @param dwc_otg_hcd The HCD
39749 + * @param dwc_otg_urb DWC_OTG URB
39750 + */
39751 +extern int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * dwc_otg_hcd,
39752 + dwc_otg_hcd_urb_t * dwc_otg_urb);
39753 +
39754 +/** Frees resources in the DWC_otg controller related to a given endpoint.
39755 + * Any URBs for the endpoint must already be dequeued.
39756 + *
39757 + * @param hcd The HCD
39758 + * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
39759 + * @param retry Number of retries if there are queued transfers.
39760 + *
39761 + * Returns -DWC_E_INVALID if invalid arguments are passed.
39762 + * Returns 0 on success
39763 + */
39764 +extern int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
39765 + int retry);
39766 +
39767 +/* Resets the data toggle in qh structure. This function can be called from
39768 + * usb_clear_halt routine.
39769 + *
39770 + * @param hcd The HCD
39771 + * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
39772 + *
39773 + * Returns -DWC_E_INVALID if invalid arguments are passed.
39774 + * Returns 0 on success
39775 + */
39776 +extern int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle);
39777 +
39778 +/** Returns 1 if status of specified port is changed and 0 otherwise.
39779 + *
39780 + * @param hcd The HCD
39781 + * @param port Port number
39782 + */
39783 +extern int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port);
39784 +
39785 +/** Call this function to check if bandwidth was allocated for specified endpoint.
39786 + * Only for ISOC and INTERRUPT endpoints.
39787 + *
39788 + * @param hcd The HCD
39789 + * @param ep_handle Endpoint handle
39790 + */
39791 +extern int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd,
39792 + void *ep_handle);
39793 +
39794 +/** Call this function to check if bandwidth was freed for specified endpoint.
39795 + *
39796 + * @param hcd The HCD
39797 + * @param ep_handle Endpoint handle
39798 + */
39799 +extern int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle);
39800 +
39801 +/** Returns bandwidth allocated for specified endpoint in microseconds.
39802 + * Only for ISOC and INTERRUPT endpoints.
39803 + *
39804 + * @param hcd The HCD
39805 + * @param ep_handle Endpoint handle
39806 + */
39807 +extern uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd,
39808 + void *ep_handle);
39809 +
39810 +/** @} */
39811 +
39812 +#endif /* __DWC_HCD_IF_H__ */
39813 +#endif /* DWC_DEVICE_ONLY */
39814 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
39815 new file mode 100644
39816 index 0000000..b41e164
39817 --- /dev/null
39818 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
39819 @@ -0,0 +1,2106 @@
39820 +/* ==========================================================================
39821 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_intr.c $
39822 + * $Revision: #89 $
39823 + * $Date: 2011/10/20 $
39824 + * $Change: 1869487 $
39825 + *
39826 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
39827 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
39828 + * otherwise expressly agreed to in writing between Synopsys and you.
39829 + *
39830 + * The Software IS NOT an item of Licensed Software or Licensed Product under
39831 + * any End User Software License Agreement or Agreement for Licensed Product
39832 + * with Synopsys or any supplement thereto. You are permitted to use and
39833 + * redistribute this Software in source and binary forms, with or without
39834 + * modification, provided that redistributions of source code must retain this
39835 + * notice. You may not view, use, disclose, copy or distribute this file or
39836 + * any information contained herein except pursuant to this license grant from
39837 + * Synopsys. If you do not agree with this notice, including the disclaimer
39838 + * below, then you are not authorized to use the Software.
39839 + *
39840 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
39841 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39842 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39843 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
39844 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39845 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39846 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39847 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39848 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39849 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
39850 + * DAMAGE.
39851 + * ========================================================================== */
39852 +#ifndef DWC_DEVICE_ONLY
39853 +
39854 +#include "dwc_otg_hcd.h"
39855 +#include "dwc_otg_regs.h"
39856 +
39857 +extern bool microframe_schedule;
39858 +
39859 +/** @file
39860 + * This file contains the implementation of the HCD Interrupt handlers.
39861 + */
39862 +
39863 +/** This function handles interrupts for the HCD. */
39864 +int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39865 +{
39866 + int retval = 0;
39867 +
39868 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
39869 + gintsts_data_t gintsts;
39870 +#ifdef DEBUG
39871 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
39872 +
39873 + //GRAYG: debugging
39874 + if (NULL == global_regs) {
39875 + DWC_DEBUGPL(DBG_HCD, "**** NULL regs: dwc_otg_hcd=%p "
39876 + "core_if=%p\n",
39877 + dwc_otg_hcd, global_regs);
39878 + return retval;
39879 + }
39880 +#endif
39881 +
39882 + /* Exit from ISR if core is hibernated */
39883 + if (core_if->hibernation_suspend == 1) {
39884 + return retval;
39885 + }
39886 + DWC_SPINLOCK(dwc_otg_hcd->lock);
39887 + /* Check if HOST Mode */
39888 + if (dwc_otg_is_host_mode(core_if)) {
39889 + gintsts.d32 = dwc_otg_read_core_intr(core_if);
39890 + if (!gintsts.d32) {
39891 + DWC_SPINUNLOCK(dwc_otg_hcd->lock);
39892 + return 0;
39893 + }
39894 +#ifdef DEBUG
39895 + /* Don't print debug message in the interrupt handler on SOF */
39896 +#ifndef DEBUG_SOF
39897 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39898 +#endif
39899 + DWC_DEBUGPL(DBG_HCDI, "\n");
39900 +#endif
39901 +
39902 +#ifdef DEBUG
39903 +#ifndef DEBUG_SOF
39904 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39905 +#endif
39906 + DWC_DEBUGPL(DBG_HCDI,
39907 + "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x core_if=%p\n",
39908 + gintsts.d32, core_if);
39909 +#endif
39910 +
39911 + if (gintsts.b.sofintr) {
39912 + retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd);
39913 + }
39914 + if (gintsts.b.rxstsqlvl) {
39915 + retval |=
39916 + dwc_otg_hcd_handle_rx_status_q_level_intr
39917 + (dwc_otg_hcd);
39918 + }
39919 + if (gintsts.b.nptxfempty) {
39920 + retval |=
39921 + dwc_otg_hcd_handle_np_tx_fifo_empty_intr
39922 + (dwc_otg_hcd);
39923 + }
39924 + if (gintsts.b.i2cintr) {
39925 + /** @todo Implement i2cintr handler. */
39926 + }
39927 + if (gintsts.b.portintr) {
39928 + retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd);
39929 + }
39930 + if (gintsts.b.hcintr) {
39931 + retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd);
39932 + }
39933 + if (gintsts.b.ptxfempty) {
39934 + retval |=
39935 + dwc_otg_hcd_handle_perio_tx_fifo_empty_intr
39936 + (dwc_otg_hcd);
39937 + }
39938 +#ifdef DEBUG
39939 +#ifndef DEBUG_SOF
39940 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39941 +#endif
39942 + {
39943 + DWC_DEBUGPL(DBG_HCDI,
39944 + "DWC OTG HCD Finished Servicing Interrupts\n");
39945 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n",
39946 + DWC_READ_REG32(&global_regs->gintsts));
39947 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n",
39948 + DWC_READ_REG32(&global_regs->gintmsk));
39949 + }
39950 +#endif
39951 +
39952 +#ifdef DEBUG
39953 +#ifndef DEBUG_SOF
39954 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39955 +#endif
39956 + DWC_DEBUGPL(DBG_HCDI, "\n");
39957 +#endif
39958 +
39959 + }
39960 + DWC_SPINUNLOCK(dwc_otg_hcd->lock);
39961 + return retval;
39962 +}
39963 +
39964 +#ifdef DWC_TRACK_MISSED_SOFS
39965 +#warning Compiling code to track missed SOFs
39966 +#define FRAME_NUM_ARRAY_SIZE 1000
39967 +/**
39968 + * This function is for debug only.
39969 + */
39970 +static inline void track_missed_sofs(uint16_t curr_frame_number)
39971 +{
39972 + static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE];
39973 + static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE];
39974 + static int frame_num_idx = 0;
39975 + static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM;
39976 + static int dumped_frame_num_array = 0;
39977 +
39978 + if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
39979 + if (((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) !=
39980 + curr_frame_number) {
39981 + frame_num_array[frame_num_idx] = curr_frame_number;
39982 + last_frame_num_array[frame_num_idx++] = last_frame_num;
39983 + }
39984 + } else if (!dumped_frame_num_array) {
39985 + int i;
39986 + DWC_PRINTF("Frame Last Frame\n");
39987 + DWC_PRINTF("----- ----------\n");
39988 + for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
39989 + DWC_PRINTF("0x%04x 0x%04x\n",
39990 + frame_num_array[i], last_frame_num_array[i]);
39991 + }
39992 + dumped_frame_num_array = 1;
39993 + }
39994 + last_frame_num = curr_frame_number;
39995 +}
39996 +#endif
39997 +
39998 +/**
39999 + * Handles the start-of-frame interrupt in host mode. Non-periodic
40000 + * transactions may be queued to the DWC_otg controller for the current
40001 + * (micro)frame. Periodic transactions may be queued to the controller for the
40002 + * next (micro)frame.
40003 + */
40004 +int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd)
40005 +{
40006 + hfnum_data_t hfnum;
40007 + dwc_list_link_t *qh_entry;
40008 + dwc_otg_qh_t *qh;
40009 + dwc_otg_transaction_type_e tr_type;
40010 + gintsts_data_t gintsts = {.d32 = 0 };
40011 +
40012 + hfnum.d32 =
40013 + DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum);
40014 +
40015 +#ifdef DEBUG_SOF
40016 + DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n");
40017 +#endif
40018 + hcd->frame_number = hfnum.b.frnum;
40019 +
40020 +#ifdef DEBUG
40021 + hcd->frrem_accum += hfnum.b.frrem;
40022 + hcd->frrem_samples++;
40023 +#endif
40024 +
40025 +#ifdef DWC_TRACK_MISSED_SOFS
40026 + track_missed_sofs(hcd->frame_number);
40027 +#endif
40028 + /* Determine whether any periodic QHs should be executed. */
40029 + qh_entry = DWC_LIST_FIRST(&hcd->periodic_sched_inactive);
40030 + while (qh_entry != &hcd->periodic_sched_inactive) {
40031 + qh = DWC_LIST_ENTRY(qh_entry, dwc_otg_qh_t, qh_list_entry);
40032 + qh_entry = qh_entry->next;
40033 + if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) {
40034 + /*
40035 + * Move QH to the ready list to be executed next
40036 + * (micro)frame.
40037 + */
40038 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
40039 + &qh->qh_list_entry);
40040 + }
40041 + }
40042 + tr_type = dwc_otg_hcd_select_transactions(hcd);
40043 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
40044 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
40045 + }
40046 +
40047 + /* Clear interrupt */
40048 + gintsts.b.sofintr = 1;
40049 + DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32);
40050 +
40051 + return 1;
40052 +}
40053 +
40054 +/** Handles the Rx Status Queue Level Interrupt, which indicates that there is at
40055 + * least one packet in the Rx FIFO. The packets are moved from the FIFO to
40056 + * memory if the DWC_otg controller is operating in Slave mode. */
40057 +int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * dwc_otg_hcd)
40058 +{
40059 + host_grxsts_data_t grxsts;
40060 + dwc_hc_t *hc = NULL;
40061 +
40062 + DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n");
40063 +
40064 + grxsts.d32 =
40065 + DWC_READ_REG32(&dwc_otg_hcd->core_if->core_global_regs->grxstsp);
40066 +
40067 + hc = dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum];
40068 + if (!hc) {
40069 + DWC_ERROR("Unable to get corresponding channel\n");
40070 + return 0;
40071 + }
40072 +
40073 + /* Packet Status */
40074 + DWC_DEBUGPL(DBG_HCDV, " Ch num = %d\n", grxsts.b.chnum);
40075 + DWC_DEBUGPL(DBG_HCDV, " Count = %d\n", grxsts.b.bcnt);
40076 + DWC_DEBUGPL(DBG_HCDV, " DPID = %d, hc.dpid = %d\n", grxsts.b.dpid,
40077 + hc->data_pid_start);
40078 + DWC_DEBUGPL(DBG_HCDV, " PStatus = %d\n", grxsts.b.pktsts);
40079 +
40080 + switch (grxsts.b.pktsts) {
40081 + case DWC_GRXSTS_PKTSTS_IN:
40082 + /* Read the data into the host buffer. */
40083 + if (grxsts.b.bcnt > 0) {
40084 + dwc_otg_read_packet(dwc_otg_hcd->core_if,
40085 + hc->xfer_buff, grxsts.b.bcnt);
40086 +
40087 + /* Update the HC fields for the next packet received. */
40088 + hc->xfer_count += grxsts.b.bcnt;
40089 + hc->xfer_buff += grxsts.b.bcnt;
40090 + }
40091 +
40092 + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
40093 + case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
40094 + case DWC_GRXSTS_PKTSTS_CH_HALTED:
40095 + /* Handled in interrupt, just ignore data */
40096 + break;
40097 + default:
40098 + DWC_ERROR("RX_STS_Q Interrupt: Unknown status %d\n",
40099 + grxsts.b.pktsts);
40100 + break;
40101 + }
40102 +
40103 + return 1;
40104 +}
40105 +
40106 +/** This interrupt occurs when the non-periodic Tx FIFO is half-empty. More
40107 + * data packets may be written to the FIFO for OUT transfers. More requests
40108 + * may be written to the non-periodic request queue for IN transfers. This
40109 + * interrupt is enabled only in Slave mode. */
40110 +int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
40111 +{
40112 + DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n");
40113 + dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
40114 + DWC_OTG_TRANSACTION_NON_PERIODIC);
40115 + return 1;
40116 +}
40117 +
40118 +/** This interrupt occurs when the periodic Tx FIFO is half-empty. More data
40119 + * packets may be written to the FIFO for OUT transfers. More requests may be
40120 + * written to the periodic request queue for IN transfers. This interrupt is
40121 + * enabled only in Slave mode. */
40122 +int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
40123 +{
40124 + DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n");
40125 + dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
40126 + DWC_OTG_TRANSACTION_PERIODIC);
40127 + return 1;
40128 +}
40129 +
40130 +/** There are multiple conditions that can cause a port interrupt. This function
40131 + * determines which interrupt conditions have occurred and handles them
40132 + * appropriately. */
40133 +int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd)
40134 +{
40135 + int retval = 0;
40136 + hprt0_data_t hprt0;
40137 + hprt0_data_t hprt0_modify;
40138 +
40139 + hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
40140 + hprt0_modify.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
40141 +
40142 + /* Clear appropriate bits in HPRT0 to clear the interrupt bit in
40143 + * GINTSTS */
40144 +
40145 + hprt0_modify.b.prtena = 0;
40146 + hprt0_modify.b.prtconndet = 0;
40147 + hprt0_modify.b.prtenchng = 0;
40148 + hprt0_modify.b.prtovrcurrchng = 0;
40149 +
40150 + /* Port Connect Detected
40151 + * Set flag and clear if detected */
40152 + if (dwc_otg_hcd->core_if->hibernation_suspend == 1) {
40153 + // Dont modify port status if we are in hibernation state
40154 + hprt0_modify.b.prtconndet = 1;
40155 + hprt0_modify.b.prtenchng = 1;
40156 + DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
40157 + hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
40158 + return retval;
40159 + }
40160 +
40161 + if (hprt0.b.prtconndet) {
40162 + /** @todo - check if steps performed in 'else' block should be perfromed regardles adp */
40163 + if (dwc_otg_hcd->core_if->adp_enable &&
40164 + dwc_otg_hcd->core_if->adp.vbuson_timer_started == 1) {
40165 + DWC_PRINTF("PORT CONNECT DETECTED ----------------\n");
40166 + DWC_TIMER_CANCEL(dwc_otg_hcd->core_if->adp.vbuson_timer);
40167 + dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
40168 + /* TODO - check if this is required, as
40169 + * host initialization was already performed
40170 + * after initial ADP probing
40171 + */
40172 + /*dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
40173 + dwc_otg_core_init(dwc_otg_hcd->core_if);
40174 + dwc_otg_enable_global_interrupts(dwc_otg_hcd->core_if);
40175 + cil_hcd_start(dwc_otg_hcd->core_if);*/
40176 + } else {
40177 +
40178 + DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x "
40179 + "Port Connect Detected--\n", hprt0.d32);
40180 + dwc_otg_hcd->flags.b.port_connect_status_change = 1;
40181 + dwc_otg_hcd->flags.b.port_connect_status = 1;
40182 + hprt0_modify.b.prtconndet = 1;
40183 +
40184 + /* B-Device has connected, Delete the connection timer. */
40185 + DWC_TIMER_CANCEL(dwc_otg_hcd->conn_timer);
40186 + }
40187 + /* The Hub driver asserts a reset when it sees port connect
40188 + * status change flag */
40189 + retval |= 1;
40190 + }
40191 +
40192 + /* Port Enable Changed
40193 + * Clear if detected - Set internal flag if disabled */
40194 + if (hprt0.b.prtenchng) {
40195 + DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
40196 + "Port Enable Changed--\n", hprt0.d32);
40197 + hprt0_modify.b.prtenchng = 1;
40198 + if (hprt0.b.prtena == 1) {
40199 + hfir_data_t hfir;
40200 + int do_reset = 0;
40201 + dwc_otg_core_params_t *params =
40202 + dwc_otg_hcd->core_if->core_params;
40203 + dwc_otg_core_global_regs_t *global_regs =
40204 + dwc_otg_hcd->core_if->core_global_regs;
40205 + dwc_otg_host_if_t *host_if =
40206 + dwc_otg_hcd->core_if->host_if;
40207 +
40208 + /* Every time when port enables calculate
40209 + * HFIR.FrInterval
40210 + */
40211 + hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
40212 + hfir.b.frint = calc_frame_interval(dwc_otg_hcd->core_if);
40213 + DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
40214 +
40215 + /* Check if we need to adjust the PHY clock speed for
40216 + * low power and adjust it */
40217 + if (params->host_support_fs_ls_low_power) {
40218 + gusbcfg_data_t usbcfg;
40219 +
40220 + usbcfg.d32 =
40221 + DWC_READ_REG32(&global_regs->gusbcfg);
40222 +
40223 + if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED
40224 + || hprt0.b.prtspd ==
40225 + DWC_HPRT0_PRTSPD_FULL_SPEED) {
40226 + /*
40227 + * Low power
40228 + */
40229 + hcfg_data_t hcfg;
40230 + if (usbcfg.b.phylpwrclksel == 0) {
40231 + /* Set PHY low power clock select for FS/LS devices */
40232 + usbcfg.b.phylpwrclksel = 1;
40233 + DWC_WRITE_REG32
40234 + (&global_regs->gusbcfg,
40235 + usbcfg.d32);
40236 + do_reset = 1;
40237 + }
40238 +
40239 + hcfg.d32 =
40240 + DWC_READ_REG32
40241 + (&host_if->host_global_regs->hcfg);
40242 +
40243 + if (hprt0.b.prtspd ==
40244 + DWC_HPRT0_PRTSPD_LOW_SPEED
40245 + && params->host_ls_low_power_phy_clk
40246 + ==
40247 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)
40248 + {
40249 + /* 6 MHZ */
40250 + DWC_DEBUGPL(DBG_CIL,
40251 + "FS_PHY programming HCFG to 6 MHz (Low Power)\n");
40252 + if (hcfg.b.fslspclksel !=
40253 + DWC_HCFG_6_MHZ) {
40254 + hcfg.b.fslspclksel =
40255 + DWC_HCFG_6_MHZ;
40256 + DWC_WRITE_REG32
40257 + (&host_if->host_global_regs->hcfg,
40258 + hcfg.d32);
40259 + do_reset = 1;
40260 + }
40261 + } else {
40262 + /* 48 MHZ */
40263 + DWC_DEBUGPL(DBG_CIL,
40264 + "FS_PHY programming HCFG to 48 MHz ()\n");
40265 + if (hcfg.b.fslspclksel !=
40266 + DWC_HCFG_48_MHZ) {
40267 + hcfg.b.fslspclksel =
40268 + DWC_HCFG_48_MHZ;
40269 + DWC_WRITE_REG32
40270 + (&host_if->host_global_regs->hcfg,
40271 + hcfg.d32);
40272 + do_reset = 1;
40273 + }
40274 + }
40275 + } else {
40276 + /*
40277 + * Not low power
40278 + */
40279 + if (usbcfg.b.phylpwrclksel == 1) {
40280 + usbcfg.b.phylpwrclksel = 0;
40281 + DWC_WRITE_REG32
40282 + (&global_regs->gusbcfg,
40283 + usbcfg.d32);
40284 + do_reset = 1;
40285 + }
40286 + }
40287 +
40288 + if (do_reset) {
40289 + DWC_TASK_SCHEDULE(dwc_otg_hcd->reset_tasklet);
40290 + }
40291 + }
40292 +
40293 + if (!do_reset) {
40294 + /* Port has been enabled set the reset change flag */
40295 + dwc_otg_hcd->flags.b.port_reset_change = 1;
40296 + }
40297 + } else {
40298 + dwc_otg_hcd->flags.b.port_enable_change = 1;
40299 + }
40300 + retval |= 1;
40301 + }
40302 +
40303 + /** Overcurrent Change Interrupt */
40304 + if (hprt0.b.prtovrcurrchng) {
40305 + DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
40306 + "Port Overcurrent Changed--\n", hprt0.d32);
40307 + dwc_otg_hcd->flags.b.port_over_current_change = 1;
40308 + hprt0_modify.b.prtovrcurrchng = 1;
40309 + retval |= 1;
40310 + }
40311 +
40312 + /* Clear Port Interrupts */
40313 + DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
40314 +
40315 + return retval;
40316 +}
40317 +
40318 +/** This interrupt indicates that one or more host channels has a pending
40319 + * interrupt. There are multiple conditions that can cause each host channel
40320 + * interrupt. This function determines which conditions have occurred for each
40321 + * host channel interrupt and handles them appropriately. */
40322 +int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd)
40323 +{
40324 + int i;
40325 + int retval = 0;
40326 + haint_data_t haint;
40327 +
40328 + /* Clear appropriate bits in HCINTn to clear the interrupt bit in
40329 + * GINTSTS */
40330 +
40331 + haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if);
40332 +
40333 + for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) {
40334 + if (haint.b2.chint & (1 << i)) {
40335 + retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i);
40336 + }
40337 + }
40338 +
40339 + return retval;
40340 +}
40341 +
40342 +/**
40343 + * Gets the actual length of a transfer after the transfer halts. _halt_status
40344 + * holds the reason for the halt.
40345 + *
40346 + * For IN transfers where halt_status is DWC_OTG_HC_XFER_COMPLETE,
40347 + * *short_read is set to 1 upon return if less than the requested
40348 + * number of bytes were transferred. Otherwise, *short_read is set to 0 upon
40349 + * return. short_read may also be NULL on entry, in which case it remains
40350 + * unchanged.
40351 + */
40352 +static uint32_t get_actual_xfer_length(dwc_hc_t * hc,
40353 + dwc_otg_hc_regs_t * hc_regs,
40354 + dwc_otg_qtd_t * qtd,
40355 + dwc_otg_halt_status_e halt_status,
40356 + int *short_read)
40357 +{
40358 + hctsiz_data_t hctsiz;
40359 + uint32_t length;
40360 +
40361 + if (short_read != NULL) {
40362 + *short_read = 0;
40363 + }
40364 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40365 +
40366 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
40367 + if (hc->ep_is_in) {
40368 + length = hc->xfer_len - hctsiz.b.xfersize;
40369 + if (short_read != NULL) {
40370 + *short_read = (hctsiz.b.xfersize != 0);
40371 + }
40372 + } else if (hc->qh->do_split) {
40373 + length = qtd->ssplit_out_xfer_count;
40374 + } else {
40375 + length = hc->xfer_len;
40376 + }
40377 + } else {
40378 + /*
40379 + * Must use the hctsiz.pktcnt field to determine how much data
40380 + * has been transferred. This field reflects the number of
40381 + * packets that have been transferred via the USB. This is
40382 + * always an integral number of packets if the transfer was
40383 + * halted before its normal completion. (Can't use the
40384 + * hctsiz.xfersize field because that reflects the number of
40385 + * bytes transferred via the AHB, not the USB).
40386 + */
40387 + length =
40388 + (hc->start_pkt_count - hctsiz.b.pktcnt) * hc->max_packet;
40389 + }
40390 +
40391 + return length;
40392 +}
40393 +
40394 +/**
40395 + * Updates the state of the URB after a Transfer Complete interrupt on the
40396 + * host channel. Updates the actual_length field of the URB based on the
40397 + * number of bytes transferred via the host channel. Sets the URB status
40398 + * if the data transfer is finished.
40399 + *
40400 + * @return 1 if the data transfer specified by the URB is completely finished,
40401 + * 0 otherwise.
40402 + */
40403 +static int update_urb_state_xfer_comp(dwc_hc_t * hc,
40404 + dwc_otg_hc_regs_t * hc_regs,
40405 + dwc_otg_hcd_urb_t * urb,
40406 + dwc_otg_qtd_t * qtd)
40407 +{
40408 + int xfer_done = 0;
40409 + int short_read = 0;
40410 +
40411 + int xfer_length;
40412 +
40413 + xfer_length = get_actual_xfer_length(hc, hc_regs, qtd,
40414 + DWC_OTG_HC_XFER_COMPLETE,
40415 + &short_read);
40416 +
40417 +
40418 + /* non DWORD-aligned buffer case handling. */
40419 + if (hc->align_buff && xfer_length && hc->ep_is_in) {
40420 + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
40421 + xfer_length);
40422 + }
40423 +
40424 + urb->actual_length += xfer_length;
40425 +
40426 + if (xfer_length && (hc->ep_type == DWC_OTG_EP_TYPE_BULK) &&
40427 + (urb->flags & URB_SEND_ZERO_PACKET)
40428 + && (urb->actual_length == urb->length)
40429 + && !(urb->length % hc->max_packet)) {
40430 + xfer_done = 0;
40431 + } else if (short_read || urb->actual_length >= urb->length) {
40432 + xfer_done = 1;
40433 + urb->status = 0;
40434 + }
40435 +
40436 +#ifdef DEBUG
40437 + {
40438 + hctsiz_data_t hctsiz;
40439 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40440 + DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
40441 + __func__, (hc->ep_is_in ? "IN" : "OUT"),
40442 + hc->hc_num);
40443 + DWC_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", hc->xfer_len);
40444 + DWC_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n",
40445 + hctsiz.b.xfersize);
40446 + DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n",
40447 + urb->length);
40448 + DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n",
40449 + urb->actual_length);
40450 + DWC_DEBUGPL(DBG_HCDV, " short_read %d, xfer_done %d\n",
40451 + short_read, xfer_done);
40452 + }
40453 +#endif
40454 +
40455 + return xfer_done;
40456 +}
40457 +
40458 +/*
40459 + * Save the starting data toggle for the next transfer. The data toggle is
40460 + * saved in the QH for non-control transfers and it's saved in the QTD for
40461 + * control transfers.
40462 + */
40463 +void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
40464 + dwc_otg_hc_regs_t * hc_regs, dwc_otg_qtd_t * qtd)
40465 +{
40466 + hctsiz_data_t hctsiz;
40467 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40468 +
40469 + if (hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) {
40470 + dwc_otg_qh_t *qh = hc->qh;
40471 + if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
40472 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
40473 + } else {
40474 + qh->data_toggle = DWC_OTG_HC_PID_DATA1;
40475 + }
40476 + } else {
40477 + if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
40478 + qtd->data_toggle = DWC_OTG_HC_PID_DATA0;
40479 + } else {
40480 + qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
40481 + }
40482 + }
40483 +}
40484 +
40485 +/**
40486 + * Updates the state of an Isochronous URB when the transfer is stopped for
40487 + * any reason. The fields of the current entry in the frame descriptor array
40488 + * are set based on the transfer state and the input _halt_status. Completes
40489 + * the Isochronous URB if all the URB frames have been completed.
40490 + *
40491 + * @return DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be
40492 + * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE.
40493 + */
40494 +static dwc_otg_halt_status_e
40495 +update_isoc_urb_state(dwc_otg_hcd_t * hcd,
40496 + dwc_hc_t * hc,
40497 + dwc_otg_hc_regs_t * hc_regs,
40498 + dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
40499 +{
40500 + dwc_otg_hcd_urb_t *urb = qtd->urb;
40501 + dwc_otg_halt_status_e ret_val = halt_status;
40502 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
40503 +
40504 + frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
40505 + switch (halt_status) {
40506 + case DWC_OTG_HC_XFER_COMPLETE:
40507 + frame_desc->status = 0;
40508 + frame_desc->actual_length =
40509 + get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
40510 +
40511 + /* non DWORD-aligned buffer case handling. */
40512 + if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
40513 + dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
40514 + hc->qh->dw_align_buf, frame_desc->actual_length);
40515 + }
40516 +
40517 + break;
40518 + case DWC_OTG_HC_XFER_FRAME_OVERRUN:
40519 + urb->error_count++;
40520 + if (hc->ep_is_in) {
40521 + frame_desc->status = -DWC_E_NO_STREAM_RES;
40522 + } else {
40523 + frame_desc->status = -DWC_E_COMMUNICATION;
40524 + }
40525 + frame_desc->actual_length = 0;
40526 + break;
40527 + case DWC_OTG_HC_XFER_BABBLE_ERR:
40528 + urb->error_count++;
40529 + frame_desc->status = -DWC_E_OVERFLOW;
40530 + /* Don't need to update actual_length in this case. */
40531 + break;
40532 + case DWC_OTG_HC_XFER_XACT_ERR:
40533 + urb->error_count++;
40534 + frame_desc->status = -DWC_E_PROTOCOL;
40535 + frame_desc->actual_length =
40536 + get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
40537 +
40538 + /* non DWORD-aligned buffer case handling. */
40539 + if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
40540 + dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
40541 + hc->qh->dw_align_buf, frame_desc->actual_length);
40542 + }
40543 + /* Skip whole frame */
40544 + if (hc->qh->do_split && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) &&
40545 + hc->ep_is_in && hcd->core_if->dma_enable) {
40546 + qtd->complete_split = 0;
40547 + qtd->isoc_split_offset = 0;
40548 + }
40549 +
40550 + break;
40551 + default:
40552 + DWC_ASSERT(1, "Unhandled _halt_status (%d)\n", halt_status);
40553 + break;
40554 + }
40555 + if (++qtd->isoc_frame_index == urb->packet_count) {
40556 + /*
40557 + * urb->status is not used for isoc transfers.
40558 + * The individual frame_desc statuses are used instead.
40559 + */
40560 + hcd->fops->complete(hcd, urb->priv, urb, 0);
40561 + ret_val = DWC_OTG_HC_XFER_URB_COMPLETE;
40562 + } else {
40563 + ret_val = DWC_OTG_HC_XFER_COMPLETE;
40564 + }
40565 + return ret_val;
40566 +}
40567 +
40568 +/**
40569 + * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic
40570 + * QHs, removes the QH from the active non-periodic schedule. If any QTDs are
40571 + * still linked to the QH, the QH is added to the end of the inactive
40572 + * non-periodic schedule. For periodic QHs, removes the QH from the periodic
40573 + * schedule if no more QTDs are linked to the QH.
40574 + */
40575 +static void deactivate_qh(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, int free_qtd)
40576 +{
40577 + int continue_split = 0;
40578 + dwc_otg_qtd_t *qtd;
40579 +
40580 + DWC_DEBUGPL(DBG_HCDV, " %s(%p,%p,%d)\n", __func__, hcd, qh, free_qtd);
40581 +
40582 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
40583 +
40584 + if (qtd->complete_split) {
40585 + continue_split = 1;
40586 + } else if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID ||
40587 + qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END) {
40588 + continue_split = 1;
40589 + }
40590 +
40591 + if (free_qtd) {
40592 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
40593 + continue_split = 0;
40594 + }
40595 +
40596 + qh->channel = NULL;
40597 + dwc_otg_hcd_qh_deactivate(hcd, qh, continue_split);
40598 +}
40599 +
40600 +/**
40601 + * Releases a host channel for use by other transfers. Attempts to select and
40602 + * queue more transactions since at least one host channel is available.
40603 + *
40604 + * @param hcd The HCD state structure.
40605 + * @param hc The host channel to release.
40606 + * @param qtd The QTD associated with the host channel. This QTD may be freed
40607 + * if the transfer is complete or an error has occurred.
40608 + * @param halt_status Reason the channel is being released. This status
40609 + * determines the actions taken by this function.
40610 + */
40611 +static void release_channel(dwc_otg_hcd_t * hcd,
40612 + dwc_hc_t * hc,
40613 + dwc_otg_qtd_t * qtd,
40614 + dwc_otg_halt_status_e halt_status)
40615 +{
40616 + dwc_otg_transaction_type_e tr_type;
40617 + int free_qtd;
40618 + dwc_irqflags_t flags;
40619 + dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
40620 +
40621 + DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n",
40622 + __func__, hc->hc_num, halt_status, hc->xfer_len);
40623 +
40624 + switch (halt_status) {
40625 + case DWC_OTG_HC_XFER_URB_COMPLETE:
40626 + free_qtd = 1;
40627 + break;
40628 + case DWC_OTG_HC_XFER_AHB_ERR:
40629 + case DWC_OTG_HC_XFER_STALL:
40630 + case DWC_OTG_HC_XFER_BABBLE_ERR:
40631 + free_qtd = 1;
40632 + break;
40633 + case DWC_OTG_HC_XFER_XACT_ERR:
40634 + if (qtd->error_count >= 3) {
40635 + DWC_DEBUGPL(DBG_HCDV,
40636 + " Complete URB with transaction error\n");
40637 + free_qtd = 1;
40638 + qtd->urb->status = -DWC_E_PROTOCOL;
40639 + hcd->fops->complete(hcd, qtd->urb->priv,
40640 + qtd->urb, -DWC_E_PROTOCOL);
40641 + } else {
40642 + free_qtd = 0;
40643 + }
40644 + break;
40645 + case DWC_OTG_HC_XFER_URB_DEQUEUE:
40646 + /*
40647 + * The QTD has already been removed and the QH has been
40648 + * deactivated. Don't want to do anything except release the
40649 + * host channel and try to queue more transfers.
40650 + */
40651 + goto cleanup;
40652 + case DWC_OTG_HC_XFER_NO_HALT_STATUS:
40653 + free_qtd = 0;
40654 + break;
40655 + case DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE:
40656 + DWC_DEBUGPL(DBG_HCDV,
40657 + " Complete URB with I/O error\n");
40658 + free_qtd = 1;
40659 + qtd->urb->status = -DWC_E_IO;
40660 + hcd->fops->complete(hcd, qtd->urb->priv,
40661 + qtd->urb, -DWC_E_IO);
40662 + break;
40663 + default:
40664 + free_qtd = 0;
40665 + break;
40666 + }
40667 +
40668 + deactivate_qh(hcd, hc->qh, free_qtd);
40669 +
40670 +cleanup:
40671 + /*
40672 + * Release the host channel for use by other transfers. The cleanup
40673 + * function clears the channel interrupt enables and conditions, so
40674 + * there's no need to clear the Channel Halted interrupt separately.
40675 + */
40676 + dwc_otg_hc_cleanup(hcd->core_if, hc);
40677 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
40678 +
40679 + if (!microframe_schedule) {
40680 + switch (hc->ep_type) {
40681 + case DWC_OTG_EP_TYPE_CONTROL:
40682 + case DWC_OTG_EP_TYPE_BULK:
40683 + hcd->non_periodic_channels--;
40684 + break;
40685 +
40686 + default:
40687 + /*
40688 + * Don't release reservations for periodic channels here.
40689 + * That's done when a periodic transfer is descheduled (i.e.
40690 + * when the QH is removed from the periodic schedule).
40691 + */
40692 + break;
40693 + }
40694 + } else {
40695 +
40696 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
40697 + hcd->available_host_channels++;
40698 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
40699 + }
40700 +
40701 + /* Try to queue more transfers now that there's a free channel. */
40702 + tr_type = dwc_otg_hcd_select_transactions(hcd);
40703 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
40704 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
40705 + }
40706 + DWC_SPINLOCK_FREE(channel_lock);
40707 +}
40708 +
40709 +/**
40710 + * Halts a host channel. If the channel cannot be halted immediately because
40711 + * the request queue is full, this function ensures that the FIFO empty
40712 + * interrupt for the appropriate queue is enabled so that the halt request can
40713 + * be queued when there is space in the request queue.
40714 + *
40715 + * This function may also be called in DMA mode. In that case, the channel is
40716 + * simply released since the core always halts the channel automatically in
40717 + * DMA mode.
40718 + */
40719 +static void halt_channel(dwc_otg_hcd_t * hcd,
40720 + dwc_hc_t * hc,
40721 + dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
40722 +{
40723 + if (hcd->core_if->dma_enable) {
40724 + release_channel(hcd, hc, qtd, halt_status);
40725 + return;
40726 + }
40727 +
40728 + /* Slave mode processing... */
40729 + dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
40730 +
40731 + if (hc->halt_on_queue) {
40732 + gintmsk_data_t gintmsk = {.d32 = 0 };
40733 + dwc_otg_core_global_regs_t *global_regs;
40734 + global_regs = hcd->core_if->core_global_regs;
40735 +
40736 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
40737 + hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
40738 + /*
40739 + * Make sure the Non-periodic Tx FIFO empty interrupt
40740 + * is enabled so that the non-periodic schedule will
40741 + * be processed.
40742 + */
40743 + gintmsk.b.nptxfempty = 1;
40744 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
40745 + } else {
40746 + /*
40747 + * Move the QH from the periodic queued schedule to
40748 + * the periodic assigned schedule. This allows the
40749 + * halt to be queued when the periodic schedule is
40750 + * processed.
40751 + */
40752 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
40753 + &hc->qh->qh_list_entry);
40754 +
40755 + /*
40756 + * Make sure the Periodic Tx FIFO Empty interrupt is
40757 + * enabled so that the periodic schedule will be
40758 + * processed.
40759 + */
40760 + gintmsk.b.ptxfempty = 1;
40761 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
40762 + }
40763 + }
40764 +}
40765 +
40766 +/**
40767 + * Performs common cleanup for non-periodic transfers after a Transfer
40768 + * Complete interrupt. This function should be called after any endpoint type
40769 + * specific handling is finished to release the host channel.
40770 + */
40771 +static void complete_non_periodic_xfer(dwc_otg_hcd_t * hcd,
40772 + dwc_hc_t * hc,
40773 + dwc_otg_hc_regs_t * hc_regs,
40774 + dwc_otg_qtd_t * qtd,
40775 + dwc_otg_halt_status_e halt_status)
40776 +{
40777 + hcint_data_t hcint;
40778 +
40779 + qtd->error_count = 0;
40780 +
40781 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
40782 + if (hcint.b.nyet) {
40783 + /*
40784 + * Got a NYET on the last transaction of the transfer. This
40785 + * means that the endpoint should be in the PING state at the
40786 + * beginning of the next transfer.
40787 + */
40788 + hc->qh->ping_state = 1;
40789 + clear_hc_int(hc_regs, nyet);
40790 + }
40791 +
40792 + /*
40793 + * Always halt and release the host channel to make it available for
40794 + * more transfers. There may still be more phases for a control
40795 + * transfer or more data packets for a bulk transfer at this point,
40796 + * but the host channel is still halted. A channel will be reassigned
40797 + * to the transfer when the non-periodic schedule is processed after
40798 + * the channel is released. This allows transactions to be queued
40799 + * properly via dwc_otg_hcd_queue_transactions, which also enables the
40800 + * Tx FIFO Empty interrupt if necessary.
40801 + */
40802 + if (hc->ep_is_in) {
40803 + /*
40804 + * IN transfers in Slave mode require an explicit disable to
40805 + * halt the channel. (In DMA mode, this call simply releases
40806 + * the channel.)
40807 + */
40808 + halt_channel(hcd, hc, qtd, halt_status);
40809 + } else {
40810 + /*
40811 + * The channel is automatically disabled by the core for OUT
40812 + * transfers in Slave mode.
40813 + */
40814 + release_channel(hcd, hc, qtd, halt_status);
40815 + }
40816 +}
40817 +
40818 +/**
40819 + * Performs common cleanup for periodic transfers after a Transfer Complete
40820 + * interrupt. This function should be called after any endpoint type specific
40821 + * handling is finished to release the host channel.
40822 + */
40823 +static void complete_periodic_xfer(dwc_otg_hcd_t * hcd,
40824 + dwc_hc_t * hc,
40825 + dwc_otg_hc_regs_t * hc_regs,
40826 + dwc_otg_qtd_t * qtd,
40827 + dwc_otg_halt_status_e halt_status)
40828 +{
40829 + hctsiz_data_t hctsiz;
40830 + qtd->error_count = 0;
40831 +
40832 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40833 + if (!hc->ep_is_in || hctsiz.b.pktcnt == 0) {
40834 + /* Core halts channel in these cases. */
40835 + release_channel(hcd, hc, qtd, halt_status);
40836 + } else {
40837 + /* Flush any outstanding requests from the Tx queue. */
40838 + halt_channel(hcd, hc, qtd, halt_status);
40839 + }
40840 +}
40841 +
40842 +static int32_t handle_xfercomp_isoc_split_in(dwc_otg_hcd_t * hcd,
40843 + dwc_hc_t * hc,
40844 + dwc_otg_hc_regs_t * hc_regs,
40845 + dwc_otg_qtd_t * qtd)
40846 +{
40847 + uint32_t len;
40848 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
40849 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
40850 +
40851 + len = get_actual_xfer_length(hc, hc_regs, qtd,
40852 + DWC_OTG_HC_XFER_COMPLETE, NULL);
40853 +
40854 + if (!len) {
40855 + qtd->complete_split = 0;
40856 + qtd->isoc_split_offset = 0;
40857 + return 0;
40858 + }
40859 + frame_desc->actual_length += len;
40860 +
40861 + if (hc->align_buff && len)
40862 + dwc_memcpy(qtd->urb->buf + frame_desc->offset +
40863 + qtd->isoc_split_offset, hc->qh->dw_align_buf, len);
40864 + qtd->isoc_split_offset += len;
40865 +
40866 + if (frame_desc->length == frame_desc->actual_length) {
40867 + frame_desc->status = 0;
40868 + qtd->isoc_frame_index++;
40869 + qtd->complete_split = 0;
40870 + qtd->isoc_split_offset = 0;
40871 + }
40872 +
40873 + if (qtd->isoc_frame_index == qtd->urb->packet_count) {
40874 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
40875 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
40876 + } else {
40877 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
40878 + }
40879 +
40880 + return 1; /* Indicates that channel released */
40881 +}
40882 +
40883 +/**
40884 + * Handles a host channel Transfer Complete interrupt. This handler may be
40885 + * called in either DMA mode or Slave mode.
40886 + */
40887 +static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t * hcd,
40888 + dwc_hc_t * hc,
40889 + dwc_otg_hc_regs_t * hc_regs,
40890 + dwc_otg_qtd_t * qtd)
40891 +{
40892 + int urb_xfer_done;
40893 + dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE;
40894 + dwc_otg_hcd_urb_t *urb = qtd->urb;
40895 + int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
40896 +
40897 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
40898 + "Transfer Complete--\n", hc->hc_num);
40899 +
40900 + if (hcd->core_if->dma_desc_enable) {
40901 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, halt_status);
40902 + if (pipe_type == UE_ISOCHRONOUS) {
40903 + /* Do not disable the interrupt, just clear it */
40904 + clear_hc_int(hc_regs, xfercomp);
40905 + return 1;
40906 + }
40907 + goto handle_xfercomp_done;
40908 + }
40909 +
40910 + /*
40911 + * Handle xfer complete on CSPLIT.
40912 + */
40913 +
40914 + if (hc->qh->do_split) {
40915 + if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hc->ep_is_in
40916 + && hcd->core_if->dma_enable) {
40917 + if (qtd->complete_split
40918 + && handle_xfercomp_isoc_split_in(hcd, hc, hc_regs,
40919 + qtd))
40920 + goto handle_xfercomp_done;
40921 + } else {
40922 + qtd->complete_split = 0;
40923 + }
40924 + }
40925 +
40926 + /* Update the QTD and URB states. */
40927 + switch (pipe_type) {
40928 + case UE_CONTROL:
40929 + switch (qtd->control_phase) {
40930 + case DWC_OTG_CONTROL_SETUP:
40931 + if (urb->length > 0) {
40932 + qtd->control_phase = DWC_OTG_CONTROL_DATA;
40933 + } else {
40934 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
40935 + }
40936 + DWC_DEBUGPL(DBG_HCDV,
40937 + " Control setup transaction done\n");
40938 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40939 + break;
40940 + case DWC_OTG_CONTROL_DATA:{
40941 + urb_xfer_done =
40942 + update_urb_state_xfer_comp(hc, hc_regs, urb,
40943 + qtd);
40944 + if (urb_xfer_done) {
40945 + qtd->control_phase =
40946 + DWC_OTG_CONTROL_STATUS;
40947 + DWC_DEBUGPL(DBG_HCDV,
40948 + " Control data transfer done\n");
40949 + } else {
40950 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
40951 + }
40952 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40953 + break;
40954 + }
40955 + case DWC_OTG_CONTROL_STATUS:
40956 + DWC_DEBUGPL(DBG_HCDV, " Control transfer complete\n");
40957 + if (urb->status == -DWC_E_IN_PROGRESS) {
40958 + urb->status = 0;
40959 + }
40960 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
40961 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
40962 + break;
40963 + }
40964 +
40965 + complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40966 + break;
40967 + case UE_BULK:
40968 + DWC_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n");
40969 + urb_xfer_done =
40970 + update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
40971 + if (urb_xfer_done) {
40972 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
40973 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
40974 + } else {
40975 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40976 + }
40977 +
40978 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
40979 + complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40980 + break;
40981 + case UE_INTERRUPT:
40982 + DWC_DEBUGPL(DBG_HCDV, " Interrupt transfer complete\n");
40983 + urb_xfer_done =
40984 + update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
40985 +
40986 + /*
40987 + * Interrupt URB is done on the first transfer complete
40988 + * interrupt.
40989 + */
40990 + if (urb_xfer_done) {
40991 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
40992 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
40993 + } else {
40994 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40995 + }
40996 +
40997 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
40998 + complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40999 + break;
41000 + case UE_ISOCHRONOUS:
41001 + DWC_DEBUGPL(DBG_HCDV, " Isochronous transfer complete\n");
41002 + if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) {
41003 + halt_status =
41004 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41005 + DWC_OTG_HC_XFER_COMPLETE);
41006 + }
41007 + complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
41008 + break;
41009 + }
41010 +
41011 +handle_xfercomp_done:
41012 + disable_hc_int(hc_regs, xfercompl);
41013 +
41014 + return 1;
41015 +}
41016 +
41017 +/**
41018 + * Handles a host channel STALL interrupt. This handler may be called in
41019 + * either DMA mode or Slave mode.
41020 + */
41021 +static int32_t handle_hc_stall_intr(dwc_otg_hcd_t * hcd,
41022 + dwc_hc_t * hc,
41023 + dwc_otg_hc_regs_t * hc_regs,
41024 + dwc_otg_qtd_t * qtd)
41025 +{
41026 + dwc_otg_hcd_urb_t *urb = qtd->urb;
41027 + int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
41028 +
41029 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
41030 + "STALL Received--\n", hc->hc_num);
41031 +
41032 + if (hcd->core_if->dma_desc_enable) {
41033 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_STALL);
41034 + goto handle_stall_done;
41035 + }
41036 +
41037 + if (pipe_type == UE_CONTROL) {
41038 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
41039 + }
41040 +
41041 + if (pipe_type == UE_BULK || pipe_type == UE_INTERRUPT) {
41042 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
41043 + /*
41044 + * USB protocol requires resetting the data toggle for bulk
41045 + * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
41046 + * setup command is issued to the endpoint. Anticipate the
41047 + * CLEAR_FEATURE command since a STALL has occurred and reset
41048 + * the data toggle now.
41049 + */
41050 + hc->qh->data_toggle = 0;
41051 + }
41052 +
41053 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_STALL);
41054 +
41055 +handle_stall_done:
41056 + disable_hc_int(hc_regs, stall);
41057 +
41058 + return 1;
41059 +}
41060 +
41061 +/*
41062 + * Updates the state of the URB when a transfer has been stopped due to an
41063 + * abnormal condition before the transfer completes. Modifies the
41064 + * actual_length field of the URB to reflect the number of bytes that have
41065 + * actually been transferred via the host channel.
41066 + */
41067 +static void update_urb_state_xfer_intr(dwc_hc_t * hc,
41068 + dwc_otg_hc_regs_t * hc_regs,
41069 + dwc_otg_hcd_urb_t * urb,
41070 + dwc_otg_qtd_t * qtd,
41071 + dwc_otg_halt_status_e halt_status)
41072 +{
41073 + uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd,
41074 + halt_status, NULL);
41075 + /* non DWORD-aligned buffer case handling. */
41076 + if (hc->align_buff && bytes_transferred && hc->ep_is_in) {
41077 + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
41078 + bytes_transferred);
41079 + }
41080 +
41081 + urb->actual_length += bytes_transferred;
41082 +
41083 +#ifdef DEBUG
41084 + {
41085 + hctsiz_data_t hctsiz;
41086 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
41087 + DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
41088 + __func__, (hc->ep_is_in ? "IN" : "OUT"),
41089 + hc->hc_num);
41090 + DWC_DEBUGPL(DBG_HCDV, " hc->start_pkt_count %d\n",
41091 + hc->start_pkt_count);
41092 + DWC_DEBUGPL(DBG_HCDV, " hctsiz.pktcnt %d\n", hctsiz.b.pktcnt);
41093 + DWC_DEBUGPL(DBG_HCDV, " hc->max_packet %d\n", hc->max_packet);
41094 + DWC_DEBUGPL(DBG_HCDV, " bytes_transferred %d\n",
41095 + bytes_transferred);
41096 + DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n",
41097 + urb->actual_length);
41098 + DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n",
41099 + urb->length);
41100 + }
41101 +#endif
41102 +}
41103 +
41104 +/**
41105 + * Handles a host channel NAK interrupt. This handler may be called in either
41106 + * DMA mode or Slave mode.
41107 + */
41108 +static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd,
41109 + dwc_hc_t * hc,
41110 + dwc_otg_hc_regs_t * hc_regs,
41111 + dwc_otg_qtd_t * qtd)
41112 +{
41113 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41114 + "NAK Received--\n", hc->hc_num);
41115 +
41116 + /*
41117 + * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
41118 + * interrupt. Re-start the SSPLIT transfer.
41119 + */
41120 + if (hc->do_split) {
41121 + if (hc->complete_split) {
41122 + qtd->error_count = 0;
41123 + }
41124 + qtd->complete_split = 0;
41125 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
41126 + goto handle_nak_done;
41127 + }
41128 +
41129 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
41130 + case UE_CONTROL:
41131 + case UE_BULK:
41132 + if (hcd->core_if->dma_enable && hc->ep_is_in) {
41133 + /*
41134 + * NAK interrupts are enabled on bulk/control IN
41135 + * transfers in DMA mode for the sole purpose of
41136 + * resetting the error count after a transaction error
41137 + * occurs. The core will continue transferring data.
41138 + */
41139 + qtd->error_count = 0;
41140 + goto handle_nak_done;
41141 + }
41142 +
41143 + /*
41144 + * NAK interrupts normally occur during OUT transfers in DMA
41145 + * or Slave mode. For IN transfers, more requests will be
41146 + * queued as request queue space is available.
41147 + */
41148 + qtd->error_count = 0;
41149 +
41150 + if (!hc->qh->ping_state) {
41151 + update_urb_state_xfer_intr(hc, hc_regs,
41152 + qtd->urb, qtd,
41153 + DWC_OTG_HC_XFER_NAK);
41154 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41155 +
41156 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH)
41157 + hc->qh->ping_state = 1;
41158 + }
41159 +
41160 + /*
41161 + * Halt the channel so the transfer can be re-started from
41162 + * the appropriate point or the PING protocol will
41163 + * start/continue.
41164 + */
41165 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
41166 + break;
41167 + case UE_INTERRUPT:
41168 + qtd->error_count = 0;
41169 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
41170 + break;
41171 + case UE_ISOCHRONOUS:
41172 + /* Should never get called for isochronous transfers. */
41173 + DWC_ASSERT(1, "NACK interrupt for ISOC transfer\n");
41174 + break;
41175 + }
41176 +
41177 +handle_nak_done:
41178 + disable_hc_int(hc_regs, nak);
41179 +
41180 + return 1;
41181 +}
41182 +
41183 +/**
41184 + * Handles a host channel ACK interrupt. This interrupt is enabled when
41185 + * performing the PING protocol in Slave mode, when errors occur during
41186 + * either Slave mode or DMA mode, and during Start Split transactions.
41187 + */
41188 +static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd,
41189 + dwc_hc_t * hc,
41190 + dwc_otg_hc_regs_t * hc_regs,
41191 + dwc_otg_qtd_t * qtd)
41192 +{
41193 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41194 + "ACK Received--\n", hc->hc_num);
41195 +
41196 + if (hc->do_split) {
41197 + /*
41198 + * Handle ACK on SSPLIT.
41199 + * ACK should not occur in CSPLIT.
41200 + */
41201 + if (!hc->ep_is_in && hc->data_pid_start != DWC_OTG_HC_PID_SETUP) {
41202 + qtd->ssplit_out_xfer_count = hc->xfer_len;
41203 + }
41204 + if (!(hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in)) {
41205 + /* Don't need complete for isochronous out transfers. */
41206 + qtd->complete_split = 1;
41207 + }
41208 +
41209 + /* ISOC OUT */
41210 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
41211 + switch (hc->xact_pos) {
41212 + case DWC_HCSPLIT_XACTPOS_ALL:
41213 + break;
41214 + case DWC_HCSPLIT_XACTPOS_END:
41215 + qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
41216 + qtd->isoc_split_offset = 0;
41217 + break;
41218 + case DWC_HCSPLIT_XACTPOS_BEGIN:
41219 + case DWC_HCSPLIT_XACTPOS_MID:
41220 + /*
41221 + * For BEGIN or MID, calculate the length for
41222 + * the next microframe to determine the correct
41223 + * SSPLIT token, either MID or END.
41224 + */
41225 + {
41226 + struct dwc_otg_hcd_iso_packet_desc
41227 + *frame_desc;
41228 +
41229 + frame_desc =
41230 + &qtd->urb->
41231 + iso_descs[qtd->isoc_frame_index];
41232 + qtd->isoc_split_offset += 188;
41233 +
41234 + if ((frame_desc->length -
41235 + qtd->isoc_split_offset) <= 188) {
41236 + qtd->isoc_split_pos =
41237 + DWC_HCSPLIT_XACTPOS_END;
41238 + } else {
41239 + qtd->isoc_split_pos =
41240 + DWC_HCSPLIT_XACTPOS_MID;
41241 + }
41242 +
41243 + }
41244 + break;
41245 + }
41246 + } else {
41247 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
41248 + }
41249 + } else {
41250 + qtd->error_count = 0;
41251 +
41252 + if (hc->qh->ping_state) {
41253 + hc->qh->ping_state = 0;
41254 + /*
41255 + * Halt the channel so the transfer can be re-started
41256 + * from the appropriate point. This only happens in
41257 + * Slave mode. In DMA mode, the ping_state is cleared
41258 + * when the transfer is started because the core
41259 + * automatically executes the PING, then the transfer.
41260 + */
41261 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
41262 + }
41263 + }
41264 +
41265 + /*
41266 + * If the ACK occurred when _not_ in the PING state, let the channel
41267 + * continue transferring data after clearing the error count.
41268 + */
41269 +
41270 + disable_hc_int(hc_regs, ack);
41271 +
41272 + return 1;
41273 +}
41274 +
41275 +/**
41276 + * Handles a host channel NYET interrupt. This interrupt should only occur on
41277 + * Bulk and Control OUT endpoints and for complete split transactions. If a
41278 + * NYET occurs at the same time as a Transfer Complete interrupt, it is
41279 + * handled in the xfercomp interrupt handler, not here. This handler may be
41280 + * called in either DMA mode or Slave mode.
41281 + */
41282 +static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd,
41283 + dwc_hc_t * hc,
41284 + dwc_otg_hc_regs_t * hc_regs,
41285 + dwc_otg_qtd_t * qtd)
41286 +{
41287 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41288 + "NYET Received--\n", hc->hc_num);
41289 +
41290 + /*
41291 + * NYET on CSPLIT
41292 + * re-do the CSPLIT immediately on non-periodic
41293 + */
41294 + if (hc->do_split && hc->complete_split) {
41295 + if (hc->ep_is_in && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
41296 + && hcd->core_if->dma_enable) {
41297 + qtd->complete_split = 0;
41298 + qtd->isoc_split_offset = 0;
41299 + if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
41300 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
41301 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
41302 + }
41303 + else
41304 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
41305 + goto handle_nyet_done;
41306 + }
41307 +
41308 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
41309 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
41310 + int frnum = dwc_otg_hcd_get_frame_number(hcd);
41311 +
41312 + if (dwc_full_frame_num(frnum) !=
41313 + dwc_full_frame_num(hc->qh->sched_frame)) {
41314 + /*
41315 + * No longer in the same full speed frame.
41316 + * Treat this as a transaction error.
41317 + */
41318 +#if 0
41319 + /** @todo Fix system performance so this can
41320 + * be treated as an error. Right now complete
41321 + * splits cannot be scheduled precisely enough
41322 + * due to other system activity, so this error
41323 + * occurs regularly in Slave mode.
41324 + */
41325 + qtd->error_count++;
41326 +#endif
41327 + qtd->complete_split = 0;
41328 + halt_channel(hcd, hc, qtd,
41329 + DWC_OTG_HC_XFER_XACT_ERR);
41330 + /** @todo add support for isoc release */
41331 + goto handle_nyet_done;
41332 + }
41333 + }
41334 +
41335 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
41336 + goto handle_nyet_done;
41337 + }
41338 +
41339 + hc->qh->ping_state = 1;
41340 + qtd->error_count = 0;
41341 +
41342 + update_urb_state_xfer_intr(hc, hc_regs, qtd->urb, qtd,
41343 + DWC_OTG_HC_XFER_NYET);
41344 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41345 +
41346 + /*
41347 + * Halt the channel and re-start the transfer so the PING
41348 + * protocol will start.
41349 + */
41350 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
41351 +
41352 +handle_nyet_done:
41353 + disable_hc_int(hc_regs, nyet);
41354 + return 1;
41355 +}
41356 +
41357 +/**
41358 + * Handles a host channel babble interrupt. This handler may be called in
41359 + * either DMA mode or Slave mode.
41360 + */
41361 +static int32_t handle_hc_babble_intr(dwc_otg_hcd_t * hcd,
41362 + dwc_hc_t * hc,
41363 + dwc_otg_hc_regs_t * hc_regs,
41364 + dwc_otg_qtd_t * qtd)
41365 +{
41366 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41367 + "Babble Error--\n", hc->hc_num);
41368 +
41369 + if (hcd->core_if->dma_desc_enable) {
41370 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41371 + DWC_OTG_HC_XFER_BABBLE_ERR);
41372 + goto handle_babble_done;
41373 + }
41374 +
41375 + if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
41376 + hcd->fops->complete(hcd, qtd->urb->priv,
41377 + qtd->urb, -DWC_E_OVERFLOW);
41378 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_BABBLE_ERR);
41379 + } else {
41380 + dwc_otg_halt_status_e halt_status;
41381 + halt_status = update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41382 + DWC_OTG_HC_XFER_BABBLE_ERR);
41383 + halt_channel(hcd, hc, qtd, halt_status);
41384 + }
41385 +
41386 +handle_babble_done:
41387 + disable_hc_int(hc_regs, bblerr);
41388 + return 1;
41389 +}
41390 +
41391 +/**
41392 + * Handles a host channel AHB error interrupt. This handler is only called in
41393 + * DMA mode.
41394 + */
41395 +static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t * hcd,
41396 + dwc_hc_t * hc,
41397 + dwc_otg_hc_regs_t * hc_regs,
41398 + dwc_otg_qtd_t * qtd)
41399 +{
41400 + hcchar_data_t hcchar;
41401 + hcsplt_data_t hcsplt;
41402 + hctsiz_data_t hctsiz;
41403 + uint32_t hcdma;
41404 + char *pipetype, *speed;
41405 +
41406 + dwc_otg_hcd_urb_t *urb = qtd->urb;
41407 +
41408 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41409 + "AHB Error--\n", hc->hc_num);
41410 +
41411 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
41412 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
41413 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
41414 + hcdma = DWC_READ_REG32(&hc_regs->hcdma);
41415 +
41416 + DWC_ERROR("AHB ERROR, Channel %d\n", hc->hc_num);
41417 + DWC_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);
41418 + DWC_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);
41419 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n");
41420 + DWC_ERROR(" Device address: %d\n",
41421 + dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
41422 + DWC_ERROR(" Endpoint: %d, %s\n",
41423 + dwc_otg_hcd_get_ep_num(&urb->pipe_info),
41424 + (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT"));
41425 +
41426 + switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
41427 + case UE_CONTROL:
41428 + pipetype = "CONTROL";
41429 + break;
41430 + case UE_BULK:
41431 + pipetype = "BULK";
41432 + break;
41433 + case UE_INTERRUPT:
41434 + pipetype = "INTERRUPT";
41435 + break;
41436 + case UE_ISOCHRONOUS:
41437 + pipetype = "ISOCHRONOUS";
41438 + break;
41439 + default:
41440 + pipetype = "UNKNOWN";
41441 + break;
41442 + }
41443 +
41444 + DWC_ERROR(" Endpoint type: %s\n", pipetype);
41445 +
41446 + switch (hc->speed) {
41447 + case DWC_OTG_EP_SPEED_HIGH:
41448 + speed = "HIGH";
41449 + break;
41450 + case DWC_OTG_EP_SPEED_FULL:
41451 + speed = "FULL";
41452 + break;
41453 + case DWC_OTG_EP_SPEED_LOW:
41454 + speed = "LOW";
41455 + break;
41456 + default:
41457 + speed = "UNKNOWN";
41458 + break;
41459 + };
41460 +
41461 + DWC_ERROR(" Speed: %s\n", speed);
41462 +
41463 + DWC_ERROR(" Max packet size: %d\n",
41464 + dwc_otg_hcd_get_mps(&urb->pipe_info));
41465 + DWC_ERROR(" Data buffer length: %d\n", urb->length);
41466 + DWC_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n",
41467 + urb->buf, (void *)urb->dma);
41468 + DWC_ERROR(" Setup buffer: %p, Setup DMA: %p\n",
41469 + urb->setup_packet, (void *)urb->setup_dma);
41470 + DWC_ERROR(" Interval: %d\n", urb->interval);
41471 +
41472 + /* Core haltes the channel for Descriptor DMA mode */
41473 + if (hcd->core_if->dma_desc_enable) {
41474 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41475 + DWC_OTG_HC_XFER_AHB_ERR);
41476 + goto handle_ahberr_done;
41477 + }
41478 +
41479 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_IO);
41480 +
41481 + /*
41482 + * Force a channel halt. Don't call halt_channel because that won't
41483 + * write to the HCCHARn register in DMA mode to force the halt.
41484 + */
41485 + dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_AHB_ERR);
41486 +handle_ahberr_done:
41487 + disable_hc_int(hc_regs, ahberr);
41488 + return 1;
41489 +}
41490 +
41491 +/**
41492 + * Handles a host channel transaction error interrupt. This handler may be
41493 + * called in either DMA mode or Slave mode.
41494 + */
41495 +static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t * hcd,
41496 + dwc_hc_t * hc,
41497 + dwc_otg_hc_regs_t * hc_regs,
41498 + dwc_otg_qtd_t * qtd)
41499 +{
41500 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41501 + "Transaction Error--\n", hc->hc_num);
41502 +
41503 + if (hcd->core_if->dma_desc_enable) {
41504 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41505 + DWC_OTG_HC_XFER_XACT_ERR);
41506 + goto handle_xacterr_done;
41507 + }
41508 +
41509 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
41510 + case UE_CONTROL:
41511 + case UE_BULK:
41512 + qtd->error_count++;
41513 + if (!hc->qh->ping_state) {
41514 +
41515 + update_urb_state_xfer_intr(hc, hc_regs,
41516 + qtd->urb, qtd,
41517 + DWC_OTG_HC_XFER_XACT_ERR);
41518 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41519 + if (!hc->ep_is_in && hc->speed == DWC_OTG_EP_SPEED_HIGH) {
41520 + hc->qh->ping_state = 1;
41521 + }
41522 + }
41523 +
41524 + /*
41525 + * Halt the channel so the transfer can be re-started from
41526 + * the appropriate point or the PING protocol will start.
41527 + */
41528 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
41529 + break;
41530 + case UE_INTERRUPT:
41531 + qtd->error_count++;
41532 + if (hc->do_split && hc->complete_split) {
41533 + qtd->complete_split = 0;
41534 + }
41535 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
41536 + break;
41537 + case UE_ISOCHRONOUS:
41538 + {
41539 + dwc_otg_halt_status_e halt_status;
41540 + halt_status =
41541 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41542 + DWC_OTG_HC_XFER_XACT_ERR);
41543 +
41544 + halt_channel(hcd, hc, qtd, halt_status);
41545 + }
41546 + break;
41547 + }
41548 +handle_xacterr_done:
41549 + disable_hc_int(hc_regs, xacterr);
41550 +
41551 + return 1;
41552 +}
41553 +
41554 +/**
41555 + * Handles a host channel frame overrun interrupt. This handler may be called
41556 + * in either DMA mode or Slave mode.
41557 + */
41558 +static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t * hcd,
41559 + dwc_hc_t * hc,
41560 + dwc_otg_hc_regs_t * hc_regs,
41561 + dwc_otg_qtd_t * qtd)
41562 +{
41563 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41564 + "Frame Overrun--\n", hc->hc_num);
41565 +
41566 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
41567 + case UE_CONTROL:
41568 + case UE_BULK:
41569 + break;
41570 + case UE_INTERRUPT:
41571 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN);
41572 + break;
41573 + case UE_ISOCHRONOUS:
41574 + {
41575 + dwc_otg_halt_status_e halt_status;
41576 + halt_status =
41577 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41578 + DWC_OTG_HC_XFER_FRAME_OVERRUN);
41579 +
41580 + halt_channel(hcd, hc, qtd, halt_status);
41581 + }
41582 + break;
41583 + }
41584 +
41585 + disable_hc_int(hc_regs, frmovrun);
41586 +
41587 + return 1;
41588 +}
41589 +
41590 +/**
41591 + * Handles a host channel data toggle error interrupt. This handler may be
41592 + * called in either DMA mode or Slave mode.
41593 + */
41594 +static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd,
41595 + dwc_hc_t * hc,
41596 + dwc_otg_hc_regs_t * hc_regs,
41597 + dwc_otg_qtd_t * qtd)
41598 +{
41599 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41600 + "Data Toggle Error--\n", hc->hc_num);
41601 +
41602 + if (hc->ep_is_in) {
41603 + qtd->error_count = 0;
41604 + } else {
41605 + DWC_ERROR("Data Toggle Error on OUT transfer,"
41606 + "channel %d\n", hc->hc_num);
41607 + }
41608 +
41609 + disable_hc_int(hc_regs, datatglerr);
41610 +
41611 + return 1;
41612 +}
41613 +
41614 +#ifdef DEBUG
41615 +/**
41616 + * This function is for debug only. It checks that a valid halt status is set
41617 + * and that HCCHARn.chdis is clear. If there's a problem, corrective action is
41618 + * taken and a warning is issued.
41619 + * @return 1 if halt status is ok, 0 otherwise.
41620 + */
41621 +static inline int halt_status_ok(dwc_otg_hcd_t * hcd,
41622 + dwc_hc_t * hc,
41623 + dwc_otg_hc_regs_t * hc_regs,
41624 + dwc_otg_qtd_t * qtd)
41625 +{
41626 + hcchar_data_t hcchar;
41627 + hctsiz_data_t hctsiz;
41628 + hcint_data_t hcint;
41629 + hcintmsk_data_t hcintmsk;
41630 + hcsplt_data_t hcsplt;
41631 +
41632 + if (hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) {
41633 + /*
41634 + * This code is here only as a check. This condition should
41635 + * never happen. Ignore the halt if it does occur.
41636 + */
41637 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
41638 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
41639 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
41640 + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
41641 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
41642 + DWC_WARN
41643 + ("%s: hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, "
41644 + "channel %d, hcchar 0x%08x, hctsiz 0x%08x, "
41645 + "hcint 0x%08x, hcintmsk 0x%08x, "
41646 + "hcsplt 0x%08x, qtd->complete_split %d\n", __func__,
41647 + hc->hc_num, hcchar.d32, hctsiz.d32, hcint.d32,
41648 + hcintmsk.d32, hcsplt.d32, qtd->complete_split);
41649 +
41650 + DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n",
41651 + __func__, hc->hc_num);
41652 + DWC_WARN("\n");
41653 + clear_hc_int(hc_regs, chhltd);
41654 + return 0;
41655 + }
41656 +
41657 + /*
41658 + * This code is here only as a check. hcchar.chdis should
41659 + * never be set when the halt interrupt occurs. Halt the
41660 + * channel again if it does occur.
41661 + */
41662 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
41663 + if (hcchar.b.chdis) {
41664 + DWC_WARN("%s: hcchar.chdis set unexpectedly, "
41665 + "hcchar 0x%08x, trying to halt again\n",
41666 + __func__, hcchar.d32);
41667 + clear_hc_int(hc_regs, chhltd);
41668 + hc->halt_pending = 0;
41669 + halt_channel(hcd, hc, qtd, hc->halt_status);
41670 + return 0;
41671 + }
41672 +
41673 + return 1;
41674 +}
41675 +#endif
41676 +
41677 +/**
41678 + * Handles a host Channel Halted interrupt in DMA mode. This handler
41679 + * determines the reason the channel halted and proceeds accordingly.
41680 + */
41681 +static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd,
41682 + dwc_hc_t * hc,
41683 + dwc_otg_hc_regs_t * hc_regs,
41684 + dwc_otg_qtd_t * qtd)
41685 +{
41686 + hcint_data_t hcint;
41687 + hcintmsk_data_t hcintmsk;
41688 + int out_nak_enh = 0;
41689 +
41690 + /* For core with OUT NAK enhancement, the flow for high-
41691 + * speed CONTROL/BULK OUT is handled a little differently.
41692 + */
41693 + if (hcd->core_if->snpsid >= OTG_CORE_REV_2_71a) {
41694 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH && !hc->ep_is_in &&
41695 + (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
41696 + hc->ep_type == DWC_OTG_EP_TYPE_BULK)) {
41697 + out_nak_enh = 1;
41698 + }
41699 + }
41700 +
41701 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
41702 + (hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR
41703 + && !hcd->core_if->dma_desc_enable)) {
41704 + /*
41705 + * Just release the channel. A dequeue can happen on a
41706 + * transfer timeout. In the case of an AHB Error, the channel
41707 + * was forced to halt because there's no way to gracefully
41708 + * recover.
41709 + */
41710 + if (hcd->core_if->dma_desc_enable)
41711 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41712 + hc->halt_status);
41713 + else
41714 + release_channel(hcd, hc, qtd, hc->halt_status);
41715 + return;
41716 + }
41717 +
41718 + /* Read the HCINTn register to determine the cause for the halt. */
41719 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
41720 + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
41721 +
41722 + if (hcint.b.xfercomp) {
41723 + /** @todo This is here because of a possible hardware bug. Spec
41724 + * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT
41725 + * interrupt w/ACK bit set should occur, but I only see the
41726 + * XFERCOMP bit, even with it masked out. This is a workaround
41727 + * for that behavior. Should fix this when hardware is fixed.
41728 + */
41729 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
41730 + handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
41731 + }
41732 + handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd);
41733 + } else if (hcint.b.stall) {
41734 + handle_hc_stall_intr(hcd, hc, hc_regs, qtd);
41735 + } else if (hcint.b.xacterr && !hcd->core_if->dma_desc_enable) {
41736 + if (out_nak_enh) {
41737 + if (hcint.b.nyet || hcint.b.nak || hcint.b.ack) {
41738 + DWC_DEBUGPL(DBG_HCD, "XactErr with NYET/NAK/ACK\n");
41739 + qtd->error_count = 0;
41740 + } else {
41741 + DWC_DEBUGPL(DBG_HCD, "XactErr without NYET/NAK/ACK\n");
41742 + }
41743 + }
41744 +
41745 + /*
41746 + * Must handle xacterr before nak or ack. Could get a xacterr
41747 + * at the same time as either of these on a BULK/CONTROL OUT
41748 + * that started with a PING. The xacterr takes precedence.
41749 + */
41750 + handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
41751 + } else if (hcint.b.xcs_xact && hcd->core_if->dma_desc_enable) {
41752 + handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
41753 + } else if (hcint.b.ahberr && hcd->core_if->dma_desc_enable) {
41754 + handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd);
41755 + } else if (hcint.b.bblerr) {
41756 + handle_hc_babble_intr(hcd, hc, hc_regs, qtd);
41757 + } else if (hcint.b.frmovrun) {
41758 + handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd);
41759 + } else if (!out_nak_enh) {
41760 + if (hcint.b.nyet) {
41761 + /*
41762 + * Must handle nyet before nak or ack. Could get a nyet at the
41763 + * same time as either of those on a BULK/CONTROL OUT that
41764 + * started with a PING. The nyet takes precedence.
41765 + */
41766 + handle_hc_nyet_intr(hcd, hc, hc_regs, qtd);
41767 + } else if (hcint.b.nak && !hcintmsk.b.nak) {
41768 + /*
41769 + * If nak is not masked, it's because a non-split IN transfer
41770 + * is in an error state. In that case, the nak is handled by
41771 + * the nak interrupt handler, not here. Handle nak here for
41772 + * BULK/CONTROL OUT transfers, which halt on a NAK to allow
41773 + * rewinding the buffer pointer.
41774 + */
41775 + handle_hc_nak_intr(hcd, hc, hc_regs, qtd);
41776 + } else if (hcint.b.ack && !hcintmsk.b.ack) {
41777 + /*
41778 + * If ack is not masked, it's because a non-split IN transfer
41779 + * is in an error state. In that case, the ack is handled by
41780 + * the ack interrupt handler, not here. Handle ack here for
41781 + * split transfers. Start splits halt on ACK.
41782 + */
41783 + handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
41784 + } else {
41785 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
41786 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
41787 + /*
41788 + * A periodic transfer halted with no other channel
41789 + * interrupts set. Assume it was halted by the core
41790 + * because it could not be completed in its scheduled
41791 + * (micro)frame.
41792 + */
41793 +#ifdef DEBUG
41794 + DWC_PRINTF
41795 + ("%s: Halt channel %d (assume incomplete periodic transfer)\n",
41796 + __func__, hc->hc_num);
41797 +#endif
41798 + halt_channel(hcd, hc, qtd,
41799 + DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE);
41800 + } else {
41801 + DWC_ERROR
41802 + ("%s: Channel %d, DMA Mode -- ChHltd set, but reason "
41803 + "for halting is unknown, hcint 0x%08x, intsts 0x%08x\n",
41804 + __func__, hc->hc_num, hcint.d32,
41805 + DWC_READ_REG32(&hcd->
41806 + core_if->core_global_regs->
41807 + gintsts));
41808 + }
41809 +
41810 + }
41811 + } else {
41812 + DWC_PRINTF("NYET/NAK/ACK/other in non-error case, 0x%08x\n",
41813 + hcint.d32);
41814 + }
41815 +}
41816 +
41817 +/**
41818 + * Handles a host channel Channel Halted interrupt.
41819 + *
41820 + * In slave mode, this handler is called only when the driver specifically
41821 + * requests a halt. This occurs during handling other host channel interrupts
41822 + * (e.g. nak, xacterr, stall, nyet, etc.).
41823 + *
41824 + * In DMA mode, this is the interrupt that occurs when the core has finished
41825 + * processing a transfer on a channel. Other host channel interrupts (except
41826 + * ahberr) are disabled in DMA mode.
41827 + */
41828 +static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd,
41829 + dwc_hc_t * hc,
41830 + dwc_otg_hc_regs_t * hc_regs,
41831 + dwc_otg_qtd_t * qtd)
41832 +{
41833 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41834 + "Channel Halted--\n", hc->hc_num);
41835 +
41836 + if (hcd->core_if->dma_enable) {
41837 + handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd);
41838 + } else {
41839 +#ifdef DEBUG
41840 + if (!halt_status_ok(hcd, hc, hc_regs, qtd)) {
41841 + return 1;
41842 + }
41843 +#endif
41844 + release_channel(hcd, hc, qtd, hc->halt_status);
41845 + }
41846 +
41847 + return 1;
41848 +}
41849 +
41850 +/** Handles interrupt for a specific Host Channel */
41851 +int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
41852 +{
41853 + int retval = 0;
41854 + hcint_data_t hcint;
41855 + hcintmsk_data_t hcintmsk;
41856 + dwc_hc_t *hc;
41857 + dwc_otg_hc_regs_t *hc_regs;
41858 + dwc_otg_qtd_t *qtd;
41859 +
41860 + DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", num);
41861 +
41862 + hc = dwc_otg_hcd->hc_ptr_array[num];
41863 + hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num];
41864 + qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
41865 +
41866 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
41867 + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
41868 + DWC_DEBUGPL(DBG_HCDV,
41869 + " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
41870 + hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));
41871 + hcint.d32 = hcint.d32 & hcintmsk.d32;
41872 +
41873 + if (!dwc_otg_hcd->core_if->dma_enable) {
41874 + if (hcint.b.chhltd && hcint.d32 != 0x2) {
41875 + hcint.b.chhltd = 0;
41876 + }
41877 + }
41878 +
41879 + if (hcint.b.xfercomp) {
41880 + retval |=
41881 + handle_hc_xfercomp_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41882 + /*
41883 + * If NYET occurred at same time as Xfer Complete, the NYET is
41884 + * handled by the Xfer Complete interrupt handler. Don't want
41885 + * to call the NYET interrupt handler in this case.
41886 + */
41887 + hcint.b.nyet = 0;
41888 + }
41889 + if (hcint.b.chhltd) {
41890 + retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41891 + }
41892 + if (hcint.b.ahberr) {
41893 + retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41894 + }
41895 + if (hcint.b.stall) {
41896 + retval |= handle_hc_stall_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41897 + }
41898 + if (hcint.b.nak) {
41899 + retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41900 + }
41901 + if (hcint.b.ack) {
41902 + retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41903 + }
41904 + if (hcint.b.nyet) {
41905 + retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41906 + }
41907 + if (hcint.b.xacterr) {
41908 + retval |= handle_hc_xacterr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41909 + }
41910 + if (hcint.b.bblerr) {
41911 + retval |= handle_hc_babble_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41912 + }
41913 + if (hcint.b.frmovrun) {
41914 + retval |=
41915 + handle_hc_frmovrun_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41916 + }
41917 + if (hcint.b.datatglerr) {
41918 + retval |=
41919 + handle_hc_datatglerr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41920 + }
41921 +
41922 + return retval;
41923 +}
41924 +
41925 +#endif /* DWC_DEVICE_ONLY */
41926 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
41927 new file mode 100644
41928 index 0000000..e4787f5
41929 --- /dev/null
41930 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
41931 @@ -0,0 +1,893 @@
41932 +/* ==========================================================================
41933 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $
41934 + * $Revision: #20 $
41935 + * $Date: 2011/10/26 $
41936 + * $Change: 1872981 $
41937 + *
41938 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
41939 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
41940 + * otherwise expressly agreed to in writing between Synopsys and you.
41941 + *
41942 + * The Software IS NOT an item of Licensed Software or Licensed Product under
41943 + * any End User Software License Agreement or Agreement for Licensed Product
41944 + * with Synopsys or any supplement thereto. You are permitted to use and
41945 + * redistribute this Software in source and binary forms, with or without
41946 + * modification, provided that redistributions of source code must retain this
41947 + * notice. You may not view, use, disclose, copy or distribute this file or
41948 + * any information contained herein except pursuant to this license grant from
41949 + * Synopsys. If you do not agree with this notice, including the disclaimer
41950 + * below, then you are not authorized to use the Software.
41951 + *
41952 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
41953 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41954 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41955 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
41956 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41957 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
41958 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
41959 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41960 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41961 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
41962 + * DAMAGE.
41963 + * ========================================================================== */
41964 +#ifndef DWC_DEVICE_ONLY
41965 +
41966 +/**
41967 + * @file
41968 + *
41969 + * This file contains the implementation of the HCD. In Linux, the HCD
41970 + * implements the hc_driver API.
41971 + */
41972 +#include <linux/kernel.h>
41973 +#include <linux/module.h>
41974 +#include <linux/moduleparam.h>
41975 +#include <linux/init.h>
41976 +#include <linux/device.h>
41977 +#include <linux/errno.h>
41978 +#include <linux/list.h>
41979 +#include <linux/interrupt.h>
41980 +#include <linux/string.h>
41981 +#include <linux/dma-mapping.h>
41982 +#include <linux/version.h>
41983 +#include <asm/io.h>
41984 +#include <linux/usb.h>
41985 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
41986 +#include <../drivers/usb/core/hcd.h>
41987 +#else
41988 +#include <linux/usb/hcd.h>
41989 +#endif
41990 +
41991 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
41992 +#define USB_URB_EP_LINKING 1
41993 +#else
41994 +#define USB_URB_EP_LINKING 0
41995 +#endif
41996 +
41997 +#include "dwc_otg_hcd_if.h"
41998 +#include "dwc_otg_dbg.h"
41999 +#include "dwc_otg_driver.h"
42000 +#include "dwc_otg_hcd.h"
42001 +/**
42002 + * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is
42003 + * qualified with its direction (possible 32 endpoints per device).
42004 + */
42005 +#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
42006 + ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
42007 +
42008 +static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
42009 +
42010 +/** @name Linux HC Driver API Functions */
42011 +/** @{ */
42012 +/* manage i/o requests, device state */
42013 +static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
42014 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42015 + struct usb_host_endpoint *ep,
42016 +#endif
42017 + struct urb *urb, gfp_t mem_flags);
42018 +
42019 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
42020 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42021 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
42022 +#endif
42023 +#else /* kernels at or post 2.6.30 */
42024 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd,
42025 + struct urb *urb, int status);
42026 +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) */
42027 +
42028 +static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
42029 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
42030 +static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
42031 +#endif
42032 +static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd);
42033 +extern int hcd_start(struct usb_hcd *hcd);
42034 +extern void hcd_stop(struct usb_hcd *hcd);
42035 +static int get_frame_number(struct usb_hcd *hcd);
42036 +extern int hub_status_data(struct usb_hcd *hcd, char *buf);
42037 +extern int hub_control(struct usb_hcd *hcd,
42038 + u16 typeReq,
42039 + u16 wValue, u16 wIndex, char *buf, u16 wLength);
42040 +
42041 +struct wrapper_priv_data {
42042 + dwc_otg_hcd_t *dwc_otg_hcd;
42043 +};
42044 +
42045 +/** @} */
42046 +
42047 +static struct hc_driver dwc_otg_hc_driver = {
42048 +
42049 + .description = dwc_otg_hcd_name,
42050 + .product_desc = "DWC OTG Controller",
42051 + .hcd_priv_size = sizeof(struct wrapper_priv_data),
42052 +
42053 + .irq = dwc_otg_hcd_irq,
42054 +
42055 + .flags = HCD_MEMORY | HCD_USB2,
42056 +
42057 + //.reset =
42058 + .start = hcd_start,
42059 + //.suspend =
42060 + //.resume =
42061 + .stop = hcd_stop,
42062 +
42063 + .urb_enqueue = dwc_otg_urb_enqueue,
42064 + .urb_dequeue = dwc_otg_urb_dequeue,
42065 + .endpoint_disable = endpoint_disable,
42066 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
42067 + .endpoint_reset = endpoint_reset,
42068 +#endif
42069 + .get_frame_number = get_frame_number,
42070 +
42071 + .hub_status_data = hub_status_data,
42072 + .hub_control = hub_control,
42073 + //.bus_suspend =
42074 + //.bus_resume =
42075 +};
42076 +
42077 +/** Gets the dwc_otg_hcd from a struct usb_hcd */
42078 +static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
42079 +{
42080 + struct wrapper_priv_data *p;
42081 + p = (struct wrapper_priv_data *)(hcd->hcd_priv);
42082 + return p->dwc_otg_hcd;
42083 +}
42084 +
42085 +/** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */
42086 +static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t * dwc_otg_hcd)
42087 +{
42088 + return dwc_otg_hcd_get_priv_data(dwc_otg_hcd);
42089 +}
42090 +
42091 +/** Gets the usb_host_endpoint associated with an URB. */
42092 +inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb)
42093 +{
42094 + struct usb_device *dev = urb->dev;
42095 + int ep_num = usb_pipeendpoint(urb->pipe);
42096 +
42097 + if (usb_pipein(urb->pipe))
42098 + return dev->ep_in[ep_num];
42099 + else
42100 + return dev->ep_out[ep_num];
42101 +}
42102 +
42103 +static int _disconnect(dwc_otg_hcd_t * hcd)
42104 +{
42105 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
42106 +
42107 + usb_hcd->self.is_b_host = 0;
42108 + return 0;
42109 +}
42110 +
42111 +static int _start(dwc_otg_hcd_t * hcd)
42112 +{
42113 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
42114 +
42115 + usb_hcd->self.is_b_host = dwc_otg_hcd_is_b_host(hcd);
42116 + hcd_start(usb_hcd);
42117 +
42118 + return 0;
42119 +}
42120 +
42121 +static int _hub_info(dwc_otg_hcd_t * hcd, void *urb_handle, uint32_t * hub_addr,
42122 + uint32_t * port_addr)
42123 +{
42124 + struct urb *urb = (struct urb *)urb_handle;
42125 + struct usb_bus *bus;
42126 +#if 1 //GRAYG - temporary
42127 + if (NULL == urb_handle)
42128 + DWC_ERROR("**** %s - NULL URB handle\n", __func__);//GRAYG
42129 + if (NULL == urb->dev)
42130 + DWC_ERROR("**** %s - URB has no device\n", __func__);//GRAYG
42131 + if (NULL == port_addr)
42132 + DWC_ERROR("**** %s - NULL port_address\n", __func__);//GRAYG
42133 +#endif
42134 + if (urb->dev->tt) {
42135 + if (NULL == urb->dev->tt->hub) {
42136 + DWC_ERROR("**** %s - (URB's transactor has no TT - giving no hub)\n",
42137 + __func__); //GRAYG
42138 + //*hub_addr = (u8)usb_pipedevice(urb->pipe); //GRAYG
42139 + *hub_addr = 0; //GRAYG
42140 + // we probably shouldn't have a transaction translator if
42141 + // there's no associated hub?
42142 + } else {
42143 + bus = hcd_to_bus(dwc_otg_hcd_to_hcd(hcd));
42144 + if (urb->dev->tt->hub == bus->root_hub)
42145 + *hub_addr = 0;
42146 + else
42147 + *hub_addr = urb->dev->tt->hub->devnum;
42148 + }
42149 + *port_addr = urb->dev->tt->multi ? urb->dev->ttport : 1;
42150 + } else {
42151 + *hub_addr = 0;
42152 + *port_addr = urb->dev->ttport;
42153 + }
42154 + return 0;
42155 +}
42156 +
42157 +static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle)
42158 +{
42159 + struct urb *urb = (struct urb *)urb_handle;
42160 + return urb->dev->speed;
42161 +}
42162 +
42163 +static int _get_b_hnp_enable(dwc_otg_hcd_t * hcd)
42164 +{
42165 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
42166 + return usb_hcd->self.b_hnp_enable;
42167 +}
42168 +
42169 +static void allocate_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
42170 + struct urb *urb)
42171 +{
42172 + hcd_to_bus(hcd)->bandwidth_allocated += bw / urb->interval;
42173 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42174 + hcd_to_bus(hcd)->bandwidth_isoc_reqs++;
42175 + } else {
42176 + hcd_to_bus(hcd)->bandwidth_int_reqs++;
42177 + }
42178 +}
42179 +
42180 +static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
42181 + struct urb *urb)
42182 +{
42183 + hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval;
42184 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42185 + hcd_to_bus(hcd)->bandwidth_isoc_reqs--;
42186 + } else {
42187 + hcd_to_bus(hcd)->bandwidth_int_reqs--;
42188 + }
42189 +}
42190 +
42191 +/**
42192 + * Sets the final status of an URB and returns it to the device driver. Any
42193 + * required cleanup of the URB is performed.
42194 + */
42195 +static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
42196 + dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
42197 +{
42198 + struct urb *urb = (struct urb *)urb_handle;
42199 +
42200 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42201 + DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
42202 + __func__, urb, usb_pipedevice(urb->pipe),
42203 + usb_pipeendpoint(urb->pipe),
42204 + usb_pipein(urb->pipe) ? "IN" : "OUT", status);
42205 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42206 + int i;
42207 + for (i = 0; i < urb->number_of_packets; i++) {
42208 + DWC_PRINTF(" ISO Desc %d status: %d\n",
42209 + i, urb->iso_frame_desc[i].status);
42210 + }
42211 + }
42212 + }
42213 +
42214 + urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
42215 + /* Convert status value. */
42216 + switch (status) {
42217 + case -DWC_E_PROTOCOL:
42218 + status = -EPROTO;
42219 + break;
42220 + case -DWC_E_IN_PROGRESS:
42221 + status = -EINPROGRESS;
42222 + break;
42223 + case -DWC_E_PIPE:
42224 + status = -EPIPE;
42225 + break;
42226 + case -DWC_E_IO:
42227 + status = -EIO;
42228 + break;
42229 + case -DWC_E_TIMEOUT:
42230 + status = -ETIMEDOUT;
42231 + break;
42232 + case -DWC_E_OVERFLOW:
42233 + status = -EOVERFLOW;
42234 + break;
42235 + default:
42236 + if (status) {
42237 + DWC_PRINTF("Uknown urb status %d\n", status);
42238 +
42239 + }
42240 + }
42241 +
42242 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42243 + int i;
42244 +
42245 + urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
42246 + for (i = 0; i < urb->number_of_packets; ++i) {
42247 + urb->iso_frame_desc[i].actual_length =
42248 + dwc_otg_hcd_urb_get_iso_desc_actual_length
42249 + (dwc_otg_urb, i);
42250 + urb->iso_frame_desc[i].status =
42251 + dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i);
42252 + }
42253 + }
42254 +
42255 + urb->status = status;
42256 + urb->hcpriv = NULL;
42257 + if (!status) {
42258 + if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
42259 + (urb->actual_length < urb->transfer_buffer_length)) {
42260 + urb->status = -EREMOTEIO;
42261 + }
42262 + }
42263 +
42264 + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
42265 + (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
42266 + struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
42267 + if (ep) {
42268 + free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
42269 + dwc_otg_hcd_get_ep_bandwidth(hcd,
42270 + ep->hcpriv),
42271 + urb);
42272 + }
42273 + }
42274 +
42275 + DWC_FREE(dwc_otg_urb);
42276 +
42277 +#if USB_URB_EP_LINKING
42278 + usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
42279 +#endif
42280 + DWC_SPINUNLOCK(hcd->lock);
42281 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42282 + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
42283 +#else
42284 + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status);
42285 +#endif
42286 + DWC_SPINLOCK(hcd->lock);
42287 +
42288 + return 0;
42289 +}
42290 +
42291 +static struct dwc_otg_hcd_function_ops hcd_fops = {
42292 + .start = _start,
42293 + .disconnect = _disconnect,
42294 + .hub_info = _hub_info,
42295 + .speed = _speed,
42296 + .complete = _complete,
42297 + .get_b_hnp_enable = _get_b_hnp_enable,
42298 +};
42299 +
42300 +/**
42301 + * Initializes the HCD. This function allocates memory for and initializes the
42302 + * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the
42303 + * USB bus with the core and calls the hc_driver->start() function. It returns
42304 + * a negative error on failure.
42305 + */
42306 +int hcd_init(dwc_bus_dev_t *_dev)
42307 +{
42308 + struct usb_hcd *hcd = NULL;
42309 + dwc_otg_hcd_t *dwc_otg_hcd = NULL;
42310 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
42311 + int retval = 0;
42312 + u64 dmamask;
42313 +
42314 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT otg_dev=%p\n", otg_dev);
42315 +
42316 + /* Set device flags indicating whether the HCD supports DMA. */
42317 + if (dwc_otg_is_dma_enable(otg_dev->core_if))
42318 + dmamask = DMA_BIT_MASK(32);
42319 + else
42320 + dmamask = 0;
42321 +
42322 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
42323 + dma_set_mask(&_dev->dev, dmamask);
42324 + dma_set_coherent_mask(&_dev->dev, dmamask);
42325 +#elif defined(PCI_INTERFACE)
42326 + pci_set_dma_mask(_dev, dmamask);
42327 + pci_set_consistent_dma_mask(_dev, dmamask);
42328 +#endif
42329 +
42330 + /*
42331 + * Allocate memory for the base HCD plus the DWC OTG HCD.
42332 + * Initialize the base HCD.
42333 + */
42334 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
42335 + hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, _dev->dev.bus_id);
42336 +#else
42337 + hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, dev_name(&_dev->dev));
42338 + hcd->has_tt = 1;
42339 +// hcd->uses_new_polling = 1;
42340 +// hcd->poll_rh = 0;
42341 +#endif
42342 + if (!hcd) {
42343 + retval = -ENOMEM;
42344 + goto error1;
42345 + }
42346 +
42347 + hcd->regs = otg_dev->os_dep.base;
42348 +
42349 + /* Initialize the DWC OTG HCD. */
42350 + dwc_otg_hcd = dwc_otg_hcd_alloc_hcd();
42351 + if (!dwc_otg_hcd) {
42352 + goto error2;
42353 + }
42354 + ((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd =
42355 + dwc_otg_hcd;
42356 + otg_dev->hcd = dwc_otg_hcd;
42357 +
42358 + if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) {
42359 + goto error2;
42360 + }
42361 +
42362 + otg_dev->hcd->otg_dev = otg_dev;
42363 + hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd);
42364 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel)
42365 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) //version field absent later
42366 + hcd->self.otg_version = dwc_otg_get_otg_version(otg_dev->core_if);
42367 +#endif
42368 + /* Don't support SG list at this point */
42369 + hcd->self.sg_tablesize = 0;
42370 +#endif
42371 + /*
42372 + * Finish generic HCD initialization and start the HCD. This function
42373 + * allocates the DMA buffer pool, registers the USB bus, requests the
42374 + * IRQ line, and calls hcd_start method.
42375 + */
42376 +#ifdef PLATFORM_INTERFACE
42377 + retval = usb_add_hcd(hcd, platform_get_irq(_dev, 0), IRQF_SHARED | IRQF_DISABLED);
42378 +#else
42379 + retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED);
42380 +#endif
42381 + if (retval < 0) {
42382 + goto error2;
42383 + }
42384 +
42385 + dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd);
42386 + return 0;
42387 +
42388 +error2:
42389 + usb_put_hcd(hcd);
42390 +error1:
42391 + return retval;
42392 +}
42393 +
42394 +/**
42395 + * Removes the HCD.
42396 + * Frees memory and resources associated with the HCD and deregisters the bus.
42397 + */
42398 +void hcd_remove(dwc_bus_dev_t *_dev)
42399 +{
42400 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
42401 + dwc_otg_hcd_t *dwc_otg_hcd;
42402 + struct usb_hcd *hcd;
42403 +
42404 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE otg_dev=%p\n", otg_dev);
42405 +
42406 + if (!otg_dev) {
42407 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
42408 + return;
42409 + }
42410 +
42411 + dwc_otg_hcd = otg_dev->hcd;
42412 +
42413 + if (!dwc_otg_hcd) {
42414 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
42415 + return;
42416 + }
42417 +
42418 + hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
42419 +
42420 + if (!hcd) {
42421 + DWC_DEBUGPL(DBG_ANY,
42422 + "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n",
42423 + __func__);
42424 + return;
42425 + }
42426 + usb_remove_hcd(hcd);
42427 + dwc_otg_hcd_set_priv_data(dwc_otg_hcd, NULL);
42428 + dwc_otg_hcd_remove(dwc_otg_hcd);
42429 + usb_put_hcd(hcd);
42430 +}
42431 +
42432 +/* =========================================================================
42433 + * Linux HC Driver Functions
42434 + * ========================================================================= */
42435 +
42436 +/** Initializes the DWC_otg controller and its root hub and prepares it for host
42437 + * mode operation. Activates the root port. Returns 0 on success and a negative
42438 + * error code on failure. */
42439 +int hcd_start(struct usb_hcd *hcd)
42440 +{
42441 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42442 + struct usb_bus *bus;
42443 +
42444 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
42445 + bus = hcd_to_bus(hcd);
42446 +
42447 + hcd->state = HC_STATE_RUNNING;
42448 + if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) {
42449 + return 0;
42450 + }
42451 +
42452 + /* Initialize and connect root hub if one is not already attached */
42453 + if (bus->root_hub) {
42454 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
42455 + /* Inform the HUB driver to resume. */
42456 + usb_hcd_resume_root_hub(hcd);
42457 + }
42458 +
42459 + return 0;
42460 +}
42461 +
42462 +/**
42463 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
42464 + * stopped.
42465 + */
42466 +void hcd_stop(struct usb_hcd *hcd)
42467 +{
42468 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42469 +
42470 + dwc_otg_hcd_stop(dwc_otg_hcd);
42471 +}
42472 +
42473 +/** Returns the current frame number. */
42474 +static int get_frame_number(struct usb_hcd *hcd)
42475 +{
42476 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42477 +
42478 + return dwc_otg_hcd_get_frame_number(dwc_otg_hcd);
42479 +}
42480 +
42481 +#ifdef DEBUG
42482 +static void dump_urb_info(struct urb *urb, char *fn_name)
42483 +{
42484 + DWC_PRINTF("%s, urb %p\n", fn_name, urb);
42485 + DWC_PRINTF(" Device address: %d\n", usb_pipedevice(urb->pipe));
42486 + DWC_PRINTF(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
42487 + (usb_pipein(urb->pipe) ? "IN" : "OUT"));
42488 + DWC_PRINTF(" Endpoint type: %s\n", ( {
42489 + char *pipetype;
42490 + switch (usb_pipetype(urb->pipe)) {
42491 +case PIPE_CONTROL:
42492 +pipetype = "CONTROL"; break; case PIPE_BULK:
42493 +pipetype = "BULK"; break; case PIPE_INTERRUPT:
42494 +pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS:
42495 +pipetype = "ISOCHRONOUS"; break; default:
42496 + pipetype = "UNKNOWN"; break;};
42497 + pipetype;}
42498 + )) ;
42499 + DWC_PRINTF(" Speed: %s\n", ( {
42500 + char *speed; switch (urb->dev->speed) {
42501 +case USB_SPEED_HIGH:
42502 +speed = "HIGH"; break; case USB_SPEED_FULL:
42503 +speed = "FULL"; break; case USB_SPEED_LOW:
42504 +speed = "LOW"; break; default:
42505 + speed = "UNKNOWN"; break;};
42506 + speed;}
42507 + )) ;
42508 + DWC_PRINTF(" Max packet size: %d\n",
42509 + usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
42510 + DWC_PRINTF(" Data buffer length: %d\n", urb->transfer_buffer_length);
42511 + DWC_PRINTF(" Transfer buffer: %p, Transfer DMA: %p\n",
42512 + urb->transfer_buffer, (void *)urb->transfer_dma);
42513 + DWC_PRINTF(" Setup buffer: %p, Setup DMA: %p\n",
42514 + urb->setup_packet, (void *)urb->setup_dma);
42515 + DWC_PRINTF(" Interval: %d\n", urb->interval);
42516 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42517 + int i;
42518 + for (i = 0; i < urb->number_of_packets; i++) {
42519 + DWC_PRINTF(" ISO Desc %d:\n", i);
42520 + DWC_PRINTF(" offset: %d, length %d\n",
42521 + urb->iso_frame_desc[i].offset,
42522 + urb->iso_frame_desc[i].length);
42523 + }
42524 + }
42525 +}
42526 +#endif
42527 +
42528 +/** Starts processing a USB transfer request specified by a USB Request Block
42529 + * (URB). mem_flags indicates the type of memory allocation to use while
42530 + * processing this URB. */
42531 +static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
42532 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42533 + struct usb_host_endpoint *ep,
42534 +#endif
42535 + struct urb *urb, gfp_t mem_flags)
42536 +{
42537 + int retval = 0;
42538 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
42539 + struct usb_host_endpoint *ep = urb->ep;
42540 +#endif
42541 +#if USB_URB_EP_LINKING
42542 + dwc_irqflags_t irqflags;
42543 +#endif
42544 + void **ref_ep_hcpriv = &ep->hcpriv;
42545 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42546 + dwc_otg_hcd_urb_t *dwc_otg_urb;
42547 + int i;
42548 + int alloc_bandwidth = 0;
42549 + uint8_t ep_type = 0;
42550 + uint32_t flags = 0;
42551 + void *buf;
42552 +
42553 +#ifdef DEBUG
42554 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42555 + dump_urb_info(urb, "dwc_otg_urb_enqueue");
42556 + }
42557 +#endif
42558 +
42559 + if (!urb->transfer_buffer && urb->transfer_buffer_length)
42560 + return -EINVAL;
42561 +
42562 + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
42563 + || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
42564 + if (!dwc_otg_hcd_is_bandwidth_allocated
42565 + (dwc_otg_hcd, ref_ep_hcpriv)) {
42566 + alloc_bandwidth = 1;
42567 + }
42568 + }
42569 +
42570 + switch (usb_pipetype(urb->pipe)) {
42571 + case PIPE_CONTROL:
42572 + ep_type = USB_ENDPOINT_XFER_CONTROL;
42573 + break;
42574 + case PIPE_ISOCHRONOUS:
42575 + ep_type = USB_ENDPOINT_XFER_ISOC;
42576 + break;
42577 + case PIPE_BULK:
42578 + ep_type = USB_ENDPOINT_XFER_BULK;
42579 + break;
42580 + case PIPE_INTERRUPT:
42581 + ep_type = USB_ENDPOINT_XFER_INT;
42582 + break;
42583 + default:
42584 + DWC_WARN("Wrong EP type - %d\n", usb_pipetype(urb->pipe));
42585 + }
42586 +
42587 + /* # of packets is often 0 - do we really need to call this then? */
42588 + dwc_otg_urb = dwc_otg_hcd_urb_alloc(dwc_otg_hcd,
42589 + urb->number_of_packets,
42590 + mem_flags == GFP_ATOMIC ? 1 : 0);
42591 +
42592 + if(dwc_otg_urb == NULL)
42593 + return -ENOMEM;
42594 +
42595 + urb->hcpriv = dwc_otg_urb;
42596 + if (!dwc_otg_urb && urb->number_of_packets)
42597 + return -ENOMEM;
42598 +
42599 + dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
42600 + usb_pipeendpoint(urb->pipe), ep_type,
42601 + usb_pipein(urb->pipe),
42602 + usb_maxpacket(urb->dev, urb->pipe,
42603 + !(usb_pipein(urb->pipe))));
42604 +
42605 + buf = urb->transfer_buffer;
42606 + if (hcd->self.uses_dma) {
42607 + /*
42608 + * Calculate virtual address from physical address,
42609 + * because some class driver may not fill transfer_buffer.
42610 + * In Buffer DMA mode virual address is used,
42611 + * when handling non DWORD aligned buffers.
42612 + */
42613 + //buf = phys_to_virt(urb->transfer_dma);
42614 + // DMA addresses are bus addresses not physical addresses!
42615 + buf = dma_to_virt(&urb->dev->dev, urb->transfer_dma);
42616 + }
42617 +
42618 + if (!(urb->transfer_flags & URB_NO_INTERRUPT))
42619 + flags |= URB_GIVEBACK_ASAP;
42620 + if (urb->transfer_flags & URB_ZERO_PACKET)
42621 + flags |= URB_SEND_ZERO_PACKET;
42622 +
42623 + dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf,
42624 + urb->transfer_dma,
42625 + urb->transfer_buffer_length,
42626 + urb->setup_packet,
42627 + urb->setup_dma, flags, urb->interval);
42628 +
42629 + for (i = 0; i < urb->number_of_packets; ++i) {
42630 + dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_urb, i,
42631 + urb->
42632 + iso_frame_desc[i].offset,
42633 + urb->
42634 + iso_frame_desc[i].length);
42635 + }
42636 +
42637 +#if USB_URB_EP_LINKING
42638 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
42639 + retval = usb_hcd_link_urb_to_ep(hcd, urb);
42640 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
42641 + if (0 == retval)
42642 +#endif
42643 + {
42644 + retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb,
42645 + /*(dwc_otg_qh_t **)*/
42646 + ref_ep_hcpriv,
42647 + mem_flags == GFP_ATOMIC ? 1 : 0);
42648 + if (0 == retval) {
42649 + if (alloc_bandwidth) {
42650 + allocate_bus_bandwidth(hcd,
42651 + dwc_otg_hcd_get_ep_bandwidth(
42652 + dwc_otg_hcd, *ref_ep_hcpriv),
42653 + urb);
42654 + }
42655 + } else {
42656 +#if USB_URB_EP_LINKING
42657 + dwc_irqflags_t irqflags;
42658 + DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval);
42659 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
42660 + usb_hcd_unlink_urb_from_ep(hcd, urb);
42661 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
42662 +#endif
42663 + if (retval == -DWC_E_NO_DEVICE) {
42664 + retval = -ENODEV;
42665 + }
42666 + }
42667 + }
42668 + return retval;
42669 +}
42670 +
42671 +/** Aborts/cancels a USB transfer request. Always returns 0 to indicate
42672 + * success. */
42673 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42674 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
42675 +#else
42676 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
42677 +#endif
42678 +{
42679 + dwc_irqflags_t flags;
42680 + dwc_otg_hcd_t *dwc_otg_hcd;
42681 + int rc;
42682 +
42683 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
42684 +
42685 + dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42686 +
42687 +#ifdef DEBUG
42688 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42689 + dump_urb_info(urb, "dwc_otg_urb_dequeue");
42690 + }
42691 +#endif
42692 +
42693 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
42694 + rc = usb_hcd_check_unlink_urb(hcd, urb, status);
42695 + if (0 == rc) {
42696 + if(urb->hcpriv != NULL) {
42697 + dwc_otg_hcd_urb_dequeue(dwc_otg_hcd,
42698 + (dwc_otg_hcd_urb_t *)urb->hcpriv);
42699 +
42700 + DWC_FREE(urb->hcpriv);
42701 + urb->hcpriv = NULL;
42702 + }
42703 + }
42704 +
42705 + if (0 == rc) {
42706 + /* Higher layer software sets URB status. */
42707 +#if USB_URB_EP_LINKING
42708 + usb_hcd_unlink_urb_from_ep(hcd, urb);
42709 +#endif
42710 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
42711 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42712 + usb_hcd_giveback_urb(hcd, urb);
42713 +#else
42714 + usb_hcd_giveback_urb(hcd, urb, status);
42715 +#endif
42716 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42717 + DWC_PRINTF("Called usb_hcd_giveback_urb() \n");
42718 + DWC_PRINTF(" 1urb->status = %d\n", urb->status);
42719 + }
42720 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue OK\n");
42721 + } else {
42722 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
42723 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue failed - rc %d\n",
42724 + rc);
42725 + }
42726 +
42727 + return rc;
42728 +}
42729 +
42730 +/* Frees resources in the DWC_otg controller related to a given endpoint. Also
42731 + * clears state in the HCD related to the endpoint. Any URBs for the endpoint
42732 + * must already be dequeued. */
42733 +static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
42734 +{
42735 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42736 +
42737 + DWC_DEBUGPL(DBG_HCD,
42738 + "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
42739 + "endpoint=%d\n", ep->desc.bEndpointAddress,
42740 + dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress));
42741 + dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250);
42742 + ep->hcpriv = NULL;
42743 +}
42744 +
42745 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
42746 +/* Resets endpoint specific parameter values, in current version used to reset
42747 + * the data toggle(as a WA). This function can be called from usb_clear_halt routine */
42748 +static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
42749 +{
42750 + dwc_irqflags_t flags;
42751 + struct usb_device *udev = NULL;
42752 + int epnum = usb_endpoint_num(&ep->desc);
42753 + int is_out = usb_endpoint_dir_out(&ep->desc);
42754 + int is_control = usb_endpoint_xfer_control(&ep->desc);
42755 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42756 + struct device *dev = DWC_OTG_OS_GETDEV(dwc_otg_hcd->otg_dev->os_dep);
42757 +
42758 + if (dev)
42759 + udev = to_usb_device(dev);
42760 + else
42761 + return;
42762 +
42763 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP RESET: Endpoint Num=0x%02d\n", epnum);
42764 +
42765 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
42766 + usb_settoggle(udev, epnum, is_out, 0);
42767 + if (is_control)
42768 + usb_settoggle(udev, epnum, !is_out, 0);
42769 +
42770 + if (ep->hcpriv) {
42771 + dwc_otg_hcd_endpoint_reset(dwc_otg_hcd, ep->hcpriv);
42772 + }
42773 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
42774 +}
42775 +#endif
42776 +
42777 +/** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
42778 + * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
42779 + * interrupt.
42780 + *
42781 + * This function is called by the USB core when an interrupt occurs */
42782 +static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd)
42783 +{
42784 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42785 + int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd);
42786 + if (retval != 0) {
42787 + S3C2410X_CLEAR_EINTPEND();
42788 + }
42789 + return IRQ_RETVAL(retval);
42790 +}
42791 +
42792 +/** Creates Status Change bitmap for the root hub and root port. The bitmap is
42793 + * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
42794 + * is the status change indicator for the single root port. Returns 1 if either
42795 + * change indicator is 1, otherwise returns 0. */
42796 +int hub_status_data(struct usb_hcd *hcd, char *buf)
42797 +{
42798 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42799 +
42800 + buf[0] = 0;
42801 + buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1;
42802 +
42803 + return (buf[0] != 0);
42804 +}
42805 +
42806 +/** Handles hub class-specific requests. */
42807 +int hub_control(struct usb_hcd *hcd,
42808 + u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
42809 +{
42810 + int retval;
42811 +
42812 + retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd),
42813 + typeReq, wValue, wIndex, buf, wLength);
42814 +
42815 + switch (retval) {
42816 + case -DWC_E_INVALID:
42817 + retval = -EINVAL;
42818 + break;
42819 + }
42820 +
42821 + return retval;
42822 +}
42823 +
42824 +#endif /* DWC_DEVICE_ONLY */
42825 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
42826 new file mode 100644
42827 index 0000000..9761566
42828 --- /dev/null
42829 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
42830 @@ -0,0 +1,922 @@
42831 +/* ==========================================================================
42832 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_queue.c $
42833 + * $Revision: #44 $
42834 + * $Date: 2011/10/26 $
42835 + * $Change: 1873028 $
42836 + *
42837 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
42838 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
42839 + * otherwise expressly agreed to in writing between Synopsys and you.
42840 + *
42841 + * The Software IS NOT an item of Licensed Software or Licensed Product under
42842 + * any End User Software License Agreement or Agreement for Licensed Product
42843 + * with Synopsys or any supplement thereto. You are permitted to use and
42844 + * redistribute this Software in source and binary forms, with or without
42845 + * modification, provided that redistributions of source code must retain this
42846 + * notice. You may not view, use, disclose, copy or distribute this file or
42847 + * any information contained herein except pursuant to this license grant from
42848 + * Synopsys. If you do not agree with this notice, including the disclaimer
42849 + * below, then you are not authorized to use the Software.
42850 + *
42851 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
42852 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42853 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42854 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
42855 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
42856 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
42857 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
42858 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42859 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42860 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
42861 + * DAMAGE.
42862 + * ========================================================================== */
42863 +#ifndef DWC_DEVICE_ONLY
42864 +
42865 +/**
42866 + * @file
42867 + *
42868 + * This file contains the functions to manage Queue Heads and Queue
42869 + * Transfer Descriptors.
42870 + */
42871 +
42872 +#include "dwc_otg_hcd.h"
42873 +#include "dwc_otg_regs.h"
42874 +
42875 +extern bool microframe_schedule;
42876 +
42877 +/**
42878 + * Free each QTD in the QH's QTD-list then free the QH. QH should already be
42879 + * removed from a list. QTD list should already be empty if called from URB
42880 + * Dequeue.
42881 + *
42882 + * @param hcd HCD instance.
42883 + * @param qh The QH to free.
42884 + */
42885 +void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
42886 +{
42887 + dwc_otg_qtd_t *qtd, *qtd_tmp;
42888 +
42889 + /* Free each QTD in the QTD list */
42890 + DWC_SPINLOCK(hcd->lock);
42891 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
42892 + DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
42893 + dwc_otg_hcd_qtd_free(qtd);
42894 + }
42895 +
42896 + if (hcd->core_if->dma_desc_enable) {
42897 + dwc_otg_hcd_qh_free_ddma(hcd, qh);
42898 + } else if (qh->dw_align_buf) {
42899 + uint32_t buf_size;
42900 + if (qh->ep_type == UE_ISOCHRONOUS) {
42901 + buf_size = 4096;
42902 + } else {
42903 + buf_size = hcd->core_if->core_params->max_transfer_size;
42904 + }
42905 + DWC_DMA_FREE(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma);
42906 + }
42907 +
42908 + DWC_FREE(qh);
42909 + DWC_SPINUNLOCK(hcd->lock);
42910 + return;
42911 +}
42912 +
42913 +#define BitStuffTime(bytecount) ((8 * 7* bytecount) / 6)
42914 +#define HS_HOST_DELAY 5 /* nanoseconds */
42915 +#define FS_LS_HOST_DELAY 1000 /* nanoseconds */
42916 +#define HUB_LS_SETUP 333 /* nanoseconds */
42917 +#define NS_TO_US(ns) ((ns + 500) / 1000)
42918 + /* convert & round nanoseconds to microseconds */
42919 +
42920 +static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, int bytecount)
42921 +{
42922 + unsigned long retval;
42923 +
42924 + switch (speed) {
42925 + case USB_SPEED_HIGH:
42926 + if (is_isoc) {
42927 + retval =
42928 + ((38 * 8 * 2083) +
42929 + (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
42930 + HS_HOST_DELAY;
42931 + } else {
42932 + retval =
42933 + ((55 * 8 * 2083) +
42934 + (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
42935 + HS_HOST_DELAY;
42936 + }
42937 + break;
42938 + case USB_SPEED_FULL:
42939 + if (is_isoc) {
42940 + retval =
42941 + (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
42942 + if (is_in) {
42943 + retval = 7268 + FS_LS_HOST_DELAY + retval;
42944 + } else {
42945 + retval = 6265 + FS_LS_HOST_DELAY + retval;
42946 + }
42947 + } else {
42948 + retval =
42949 + (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
42950 + retval = 9107 + FS_LS_HOST_DELAY + retval;
42951 + }
42952 + break;
42953 + case USB_SPEED_LOW:
42954 + if (is_in) {
42955 + retval =
42956 + (67667 * (31 + 10 * BitStuffTime(bytecount))) /
42957 + 1000;
42958 + retval =
42959 + 64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
42960 + retval;
42961 + } else {
42962 + retval =
42963 + (66700 * (31 + 10 * BitStuffTime(bytecount))) /
42964 + 1000;
42965 + retval =
42966 + 64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
42967 + retval;
42968 + }
42969 + break;
42970 + default:
42971 + DWC_WARN("Unknown device speed\n");
42972 + retval = -1;
42973 + }
42974 +
42975 + return NS_TO_US(retval);
42976 +}
42977 +
42978 +/**
42979 + * Initializes a QH structure.
42980 + *
42981 + * @param hcd The HCD state structure for the DWC OTG controller.
42982 + * @param qh The QH to init.
42983 + * @param urb Holds the information about the device/endpoint that we need
42984 + * to initialize the QH.
42985 + */
42986 +#define SCHEDULE_SLOP 10
42987 +void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
42988 +{
42989 + char *speed, *type;
42990 + int dev_speed;
42991 + uint32_t hub_addr, hub_port;
42992 +
42993 + dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
42994 +
42995 + /* Initialize QH */
42996 + qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
42997 + qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
42998 +
42999 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
43000 + qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info);
43001 + DWC_CIRCLEQ_INIT(&qh->qtd_list);
43002 + DWC_LIST_INIT(&qh->qh_list_entry);
43003 + qh->channel = NULL;
43004 +
43005 + /* FS/LS Enpoint on HS Hub
43006 + * NOT virtual root hub */
43007 + dev_speed = hcd->fops->speed(hcd, urb->priv);
43008 +
43009 + hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
43010 + qh->do_split = 0;
43011 + if (microframe_schedule)
43012 + qh->speed = dev_speed;
43013 +
43014 +
43015 + if (((dev_speed == USB_SPEED_LOW) ||
43016 + (dev_speed == USB_SPEED_FULL)) &&
43017 + (hub_addr != 0 && hub_addr != 1)) {
43018 + DWC_DEBUGPL(DBG_HCD,
43019 + "QH init: EP %d: TT found at hub addr %d, for port %d\n",
43020 + dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
43021 + hub_port);
43022 + qh->do_split = 1;
43023 + }
43024 +
43025 + if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
43026 + /* Compute scheduling parameters once and save them. */
43027 + hprt0_data_t hprt;
43028 +
43029 + /** @todo Account for split transfers in the bus time. */
43030 + int bytecount =
43031 + dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
43032 +
43033 + qh->usecs =
43034 + calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed),
43035 + qh->ep_is_in, (qh->ep_type == UE_ISOCHRONOUS),
43036 + bytecount);
43037 + /* Start in a slightly future (micro)frame. */
43038 + qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
43039 + SCHEDULE_SLOP);
43040 + qh->interval = urb->interval;
43041 +
43042 +#if 0
43043 + /* Increase interrupt polling rate for debugging. */
43044 + if (qh->ep_type == UE_INTERRUPT) {
43045 + qh->interval = 8;
43046 + }
43047 +#endif
43048 + hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
43049 + if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
43050 + ((dev_speed == USB_SPEED_LOW) ||
43051 + (dev_speed == USB_SPEED_FULL))) {
43052 + qh->interval *= 8;
43053 + qh->sched_frame |= 0x7;
43054 + qh->start_split_frame = qh->sched_frame;
43055 + }
43056 +
43057 + }
43058 +
43059 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
43060 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - qh = %p\n", qh);
43061 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Device Address = %d\n",
43062 + dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
43063 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Endpoint %d, %s\n",
43064 + dwc_otg_hcd_get_ep_num(&urb->pipe_info),
43065 + dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
43066 + switch (dev_speed) {
43067 + case USB_SPEED_LOW:
43068 + qh->dev_speed = DWC_OTG_EP_SPEED_LOW;
43069 + speed = "low";
43070 + break;
43071 + case USB_SPEED_FULL:
43072 + qh->dev_speed = DWC_OTG_EP_SPEED_FULL;
43073 + speed = "full";
43074 + break;
43075 + case USB_SPEED_HIGH:
43076 + qh->dev_speed = DWC_OTG_EP_SPEED_HIGH;
43077 + speed = "high";
43078 + break;
43079 + default:
43080 + speed = "?";
43081 + break;
43082 + }
43083 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Speed = %s\n", speed);
43084 +
43085 + switch (qh->ep_type) {
43086 + case UE_ISOCHRONOUS:
43087 + type = "isochronous";
43088 + break;
43089 + case UE_INTERRUPT:
43090 + type = "interrupt";
43091 + break;
43092 + case UE_CONTROL:
43093 + type = "control";
43094 + break;
43095 + case UE_BULK:
43096 + type = "bulk";
43097 + break;
43098 + default:
43099 + type = "?";
43100 + break;
43101 + }
43102 +
43103 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Type = %s\n", type);
43104 +
43105 +#ifdef DEBUG
43106 + if (qh->ep_type == UE_INTERRUPT) {
43107 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
43108 + qh->usecs);
43109 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
43110 + qh->interval);
43111 + }
43112 +#endif
43113 +
43114 +}
43115 +
43116 +/**
43117 + * This function allocates and initializes a QH.
43118 + *
43119 + * @param hcd The HCD state structure for the DWC OTG controller.
43120 + * @param urb Holds the information about the device/endpoint that we need
43121 + * to initialize the QH.
43122 + * @param atomic_alloc Flag to do atomic allocation if needed
43123 + *
43124 + * @return Returns pointer to the newly allocated QH, or NULL on error. */
43125 +dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
43126 + dwc_otg_hcd_urb_t * urb, int atomic_alloc)
43127 +{
43128 + dwc_otg_qh_t *qh;
43129 +
43130 + /* Allocate memory */
43131 + /** @todo add memflags argument */
43132 + qh = dwc_otg_hcd_qh_alloc(atomic_alloc);
43133 + if (qh == NULL) {
43134 + DWC_ERROR("qh allocation failed");
43135 + return NULL;
43136 + }
43137 +
43138 + qh_init(hcd, qh, urb);
43139 +
43140 + if (hcd->core_if->dma_desc_enable
43141 + && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) {
43142 + dwc_otg_hcd_qh_free(hcd, qh);
43143 + return NULL;
43144 + }
43145 +
43146 + return qh;
43147 +}
43148 +
43149 +/* microframe_schedule=0 start */
43150 +
43151 +/**
43152 + * Checks that a channel is available for a periodic transfer.
43153 + *
43154 + * @return 0 if successful, negative error code otherise.
43155 + */
43156 +static int periodic_channel_available(dwc_otg_hcd_t * hcd)
43157 +{
43158 + /*
43159 + * Currently assuming that there is a dedicated host channnel for each
43160 + * periodic transaction plus at least one host channel for
43161 + * non-periodic transactions.
43162 + */
43163 + int status;
43164 + int num_channels;
43165 +
43166 + num_channels = hcd->core_if->core_params->host_channels;
43167 + if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels)
43168 + && (hcd->periodic_channels < num_channels - 1)) {
43169 + status = 0;
43170 + } else {
43171 + DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
43172 + __func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels); //NOTICE
43173 + status = -DWC_E_NO_SPACE;
43174 + }
43175 +
43176 + return status;
43177 +}
43178 +
43179 +/**
43180 + * Checks that there is sufficient bandwidth for the specified QH in the
43181 + * periodic schedule. For simplicity, this calculation assumes that all the
43182 + * transfers in the periodic schedule may occur in the same (micro)frame.
43183 + *
43184 + * @param hcd The HCD state structure for the DWC OTG controller.
43185 + * @param qh QH containing periodic bandwidth required.
43186 + *
43187 + * @return 0 if successful, negative error code otherwise.
43188 + */
43189 +static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43190 +{
43191 + int status;
43192 + int16_t max_claimed_usecs;
43193 +
43194 + status = 0;
43195 +
43196 + if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) {
43197 + /*
43198 + * High speed mode.
43199 + * Max periodic usecs is 80% x 125 usec = 100 usec.
43200 + */
43201 +
43202 + max_claimed_usecs = 100 - qh->usecs;
43203 + } else {
43204 + /*
43205 + * Full speed mode.
43206 + * Max periodic usecs is 90% x 1000 usec = 900 usec.
43207 + */
43208 + max_claimed_usecs = 900 - qh->usecs;
43209 + }
43210 +
43211 + if (hcd->periodic_usecs > max_claimed_usecs) {
43212 + DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs); //NOTICE
43213 + status = -DWC_E_NO_SPACE;
43214 + }
43215 +
43216 + return status;
43217 +}
43218 +
43219 +/* microframe_schedule=0 end */
43220 +
43221 +/**
43222 + * Microframe scheduler
43223 + * track the total use in hcd->frame_usecs
43224 + * keep each qh use in qh->frame_usecs
43225 + * when surrendering the qh then donate the time back
43226 + */
43227 +const unsigned short max_uframe_usecs[]={ 100, 100, 100, 100, 100, 100, 30, 0 };
43228 +
43229 +/*
43230 + * called from dwc_otg_hcd.c:dwc_otg_hcd_init
43231 + */
43232 +int init_hcd_usecs(dwc_otg_hcd_t *_hcd)
43233 +{
43234 + int i;
43235 + for (i=0; i<8; i++) {
43236 + _hcd->frame_usecs[i] = max_uframe_usecs[i];
43237 + }
43238 + return 0;
43239 +}
43240 +
43241 +static int find_single_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
43242 +{
43243 + int i;
43244 + unsigned short utime;
43245 + int t_left;
43246 + int ret;
43247 + int done;
43248 +
43249 + ret = -1;
43250 + utime = _qh->usecs;
43251 + t_left = utime;
43252 + i = 0;
43253 + done = 0;
43254 + while (done == 0) {
43255 + /* At the start _hcd->frame_usecs[i] = max_uframe_usecs[i]; */
43256 + if (utime <= _hcd->frame_usecs[i]) {
43257 + _hcd->frame_usecs[i] -= utime;
43258 + _qh->frame_usecs[i] += utime;
43259 + t_left -= utime;
43260 + ret = i;
43261 + done = 1;
43262 + return ret;
43263 + } else {
43264 + i++;
43265 + if (i == 8) {
43266 + done = 1;
43267 + ret = -1;
43268 + }
43269 + }
43270 + }
43271 + return ret;
43272 + }
43273 +
43274 +/*
43275 + * use this for FS apps that can span multiple uframes
43276 + */
43277 +static int find_multi_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
43278 +{
43279 + int i;
43280 + int j;
43281 + unsigned short utime;
43282 + int t_left;
43283 + int ret;
43284 + int done;
43285 + unsigned short xtime;
43286 +
43287 + ret = -1;
43288 + utime = _qh->usecs;
43289 + t_left = utime;
43290 + i = 0;
43291 + done = 0;
43292 +loop:
43293 + while (done == 0) {
43294 + if(_hcd->frame_usecs[i] <= 0) {
43295 + i++;
43296 + if (i == 8) {
43297 + done = 1;
43298 + ret = -1;
43299 + }
43300 + goto loop;
43301 + }
43302 +
43303 + /*
43304 + * we need n consecutive slots
43305 + * so use j as a start slot j plus j+1 must be enough time (for now)
43306 + */
43307 + xtime= _hcd->frame_usecs[i];
43308 + for (j = i+1 ; j < 8 ; j++ ) {
43309 + /*
43310 + * if we add this frame remaining time to xtime we may
43311 + * be OK, if not we need to test j for a complete frame
43312 + */
43313 + if ((xtime+_hcd->frame_usecs[j]) < utime) {
43314 + if (_hcd->frame_usecs[j] < max_uframe_usecs[j]) {
43315 + j = 8;
43316 + ret = -1;
43317 + continue;
43318 + }
43319 + }
43320 + if (xtime >= utime) {
43321 + ret = i;
43322 + j = 8; /* stop loop with a good value ret */
43323 + continue;
43324 + }
43325 + /* add the frame time to x time */
43326 + xtime += _hcd->frame_usecs[j];
43327 + /* we must have a fully available next frame or break */
43328 + if ((xtime < utime)
43329 + && (_hcd->frame_usecs[j] == max_uframe_usecs[j])) {
43330 + ret = -1;
43331 + j = 8; /* stop loop with a bad value ret */
43332 + continue;
43333 + }
43334 + }
43335 + if (ret >= 0) {
43336 + t_left = utime;
43337 + for (j = i; (t_left>0) && (j < 8); j++ ) {
43338 + t_left -= _hcd->frame_usecs[j];
43339 + if ( t_left <= 0 ) {
43340 + _qh->frame_usecs[j] += _hcd->frame_usecs[j] + t_left;
43341 + _hcd->frame_usecs[j]= -t_left;
43342 + ret = i;
43343 + done = 1;
43344 + } else {
43345 + _qh->frame_usecs[j] += _hcd->frame_usecs[j];
43346 + _hcd->frame_usecs[j] = 0;
43347 + }
43348 + }
43349 + } else {
43350 + i++;
43351 + if (i == 8) {
43352 + done = 1;
43353 + ret = -1;
43354 + }
43355 + }
43356 + }
43357 + return ret;
43358 +}
43359 +
43360 +static int find_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
43361 +{
43362 + int ret;
43363 + ret = -1;
43364 +
43365 + if (_qh->speed == USB_SPEED_HIGH) {
43366 + /* if this is a hs transaction we need a full frame */
43367 + ret = find_single_uframe(_hcd, _qh);
43368 + } else {
43369 + /* if this is a fs transaction we may need a sequence of frames */
43370 + ret = find_multi_uframe(_hcd, _qh);
43371 + }
43372 + return ret;
43373 +}
43374 +
43375 +/**
43376 + * Checks that the max transfer size allowed in a host channel is large enough
43377 + * to handle the maximum data transfer in a single (micro)frame for a periodic
43378 + * transfer.
43379 + *
43380 + * @param hcd The HCD state structure for the DWC OTG controller.
43381 + * @param qh QH for a periodic endpoint.
43382 + *
43383 + * @return 0 if successful, negative error code otherwise.
43384 + */
43385 +static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43386 +{
43387 + int status;
43388 + uint32_t max_xfer_size;
43389 + uint32_t max_channel_xfer_size;
43390 +
43391 + status = 0;
43392 +
43393 + max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
43394 + max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
43395 +
43396 + if (max_xfer_size > max_channel_xfer_size) {
43397 + DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n",
43398 + __func__, max_xfer_size, max_channel_xfer_size); //NOTICE
43399 + status = -DWC_E_NO_SPACE;
43400 + }
43401 +
43402 + return status;
43403 +}
43404 +
43405 +/**
43406 + * Schedules an interrupt or isochronous transfer in the periodic schedule.
43407 + *
43408 + * @param hcd The HCD state structure for the DWC OTG controller.
43409 + * @param qh QH for the periodic transfer. The QH should already contain the
43410 + * scheduling information.
43411 + *
43412 + * @return 0 if successful, negative error code otherwise.
43413 + */
43414 +static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43415 +{
43416 + int status = 0;
43417 +
43418 + if (microframe_schedule) {
43419 + int frame;
43420 + status = find_uframe(hcd, qh);
43421 + frame = -1;
43422 + if (status == 0) {
43423 + frame = 7;
43424 + } else {
43425 + if (status > 0 )
43426 + frame = status-1;
43427 + }
43428 +
43429 + /* Set the new frame up */
43430 + if (frame > -1) {
43431 + qh->sched_frame &= ~0x7;
43432 + qh->sched_frame |= (frame & 7);
43433 + }
43434 +
43435 + if (status != -1)
43436 + status = 0;
43437 + } else {
43438 + status = periodic_channel_available(hcd);
43439 + if (status) {
43440 + DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__); //NOTICE
43441 + return status;
43442 + }
43443 +
43444 + status = check_periodic_bandwidth(hcd, qh);
43445 + }
43446 + if (status) {
43447 + DWC_INFO("%s: Insufficient periodic bandwidth for "
43448 + "periodic transfer.\n", __func__);
43449 + return status;
43450 + }
43451 + status = check_max_xfer_size(hcd, qh);
43452 + if (status) {
43453 + DWC_INFO("%s: Channel max transfer size too small "
43454 + "for periodic transfer.\n", __func__);
43455 + return status;
43456 + }
43457 +
43458 + if (hcd->core_if->dma_desc_enable) {
43459 + /* Don't rely on SOF and start in ready schedule */
43460 + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
43461 + }
43462 + else {
43463 + /* Always start in the inactive schedule. */
43464 + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
43465 + }
43466 +
43467 + if (!microframe_schedule) {
43468 + /* Reserve the periodic channel. */
43469 + hcd->periodic_channels++;
43470 + }
43471 +
43472 + /* Update claimed usecs per (micro)frame. */
43473 + hcd->periodic_usecs += qh->usecs;
43474 +
43475 + return status;
43476 +}
43477 +
43478 +/**
43479 + * This function adds a QH to either the non periodic or periodic schedule if
43480 + * it is not already in the schedule. If the QH is already in the schedule, no
43481 + * action is taken.
43482 + *
43483 + * @return 0 if successful, negative error code otherwise.
43484 + */
43485 +int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43486 +{
43487 + int status = 0;
43488 + gintmsk_data_t intr_mask = {.d32 = 0 };
43489 +
43490 + if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
43491 + /* QH already in a schedule. */
43492 + return status;
43493 + }
43494 +
43495 + /* Add the new QH to the appropriate schedule */
43496 + if (dwc_qh_is_non_per(qh)) {
43497 + /* Always start in the inactive schedule. */
43498 + DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
43499 + &qh->qh_list_entry);
43500 + } else {
43501 + status = schedule_periodic(hcd, qh);
43502 + if ( !hcd->periodic_qh_count ) {
43503 + intr_mask.b.sofintr = 1;
43504 + DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
43505 + intr_mask.d32, intr_mask.d32);
43506 + }
43507 + hcd->periodic_qh_count++;
43508 + }
43509 +
43510 + return status;
43511 +}
43512 +
43513 +/**
43514 + * Removes an interrupt or isochronous transfer from the periodic schedule.
43515 + *
43516 + * @param hcd The HCD state structure for the DWC OTG controller.
43517 + * @param qh QH for the periodic transfer.
43518 + */
43519 +static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43520 +{
43521 + int i;
43522 + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
43523 +
43524 + /* Update claimed usecs per (micro)frame. */
43525 + hcd->periodic_usecs -= qh->usecs;
43526 +
43527 + if (!microframe_schedule) {
43528 + /* Release the periodic channel reservation. */
43529 + hcd->periodic_channels--;
43530 + } else {
43531 + for (i = 0; i < 8; i++) {
43532 + hcd->frame_usecs[i] += qh->frame_usecs[i];
43533 + qh->frame_usecs[i] = 0;
43534 + }
43535 + }
43536 +}
43537 +
43538 +/**
43539 + * Removes a QH from either the non-periodic or periodic schedule. Memory is
43540 + * not freed.
43541 + *
43542 + * @param hcd The HCD state structure.
43543 + * @param qh QH to remove from schedule. */
43544 +void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43545 +{
43546 + gintmsk_data_t intr_mask = {.d32 = 0 };
43547 +
43548 + if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
43549 + /* QH is not in a schedule. */
43550 + return;
43551 + }
43552 +
43553 + if (dwc_qh_is_non_per(qh)) {
43554 + if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
43555 + hcd->non_periodic_qh_ptr =
43556 + hcd->non_periodic_qh_ptr->next;
43557 + }
43558 + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
43559 + } else {
43560 + deschedule_periodic(hcd, qh);
43561 + hcd->periodic_qh_count--;
43562 + if( !hcd->periodic_qh_count ) {
43563 + intr_mask.b.sofintr = 1;
43564 + DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
43565 + intr_mask.d32, 0);
43566 + }
43567 + }
43568 +}
43569 +
43570 +/**
43571 + * Deactivates a QH. For non-periodic QHs, removes the QH from the active
43572 + * non-periodic schedule. The QH is added to the inactive non-periodic
43573 + * schedule if any QTDs are still attached to the QH.
43574 + *
43575 + * For periodic QHs, the QH is removed from the periodic queued schedule. If
43576 + * there are any QTDs still attached to the QH, the QH is added to either the
43577 + * periodic inactive schedule or the periodic ready schedule and its next
43578 + * scheduled frame is calculated. The QH is placed in the ready schedule if
43579 + * the scheduled frame has been reached already. Otherwise it's placed in the
43580 + * inactive schedule. If there are no QTDs attached to the QH, the QH is
43581 + * completely removed from the periodic schedule.
43582 + */
43583 +void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
43584 + int sched_next_periodic_split)
43585 +{
43586 + if (dwc_qh_is_non_per(qh)) {
43587 + dwc_otg_hcd_qh_remove(hcd, qh);
43588 + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
43589 + /* Add back to inactive non-periodic schedule. */
43590 + dwc_otg_hcd_qh_add(hcd, qh);
43591 + }
43592 + } else {
43593 + uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);
43594 +
43595 + if (qh->do_split) {
43596 + /* Schedule the next continuing periodic split transfer */
43597 + if (sched_next_periodic_split) {
43598 +
43599 + qh->sched_frame = frame_number;
43600 + if (dwc_frame_num_le(frame_number,
43601 + dwc_frame_num_inc
43602 + (qh->start_split_frame,
43603 + 1))) {
43604 + /*
43605 + * Allow one frame to elapse after start
43606 + * split microframe before scheduling
43607 + * complete split, but DONT if we are
43608 + * doing the next start split in the
43609 + * same frame for an ISOC out.
43610 + */
43611 + if ((qh->ep_type != UE_ISOCHRONOUS) ||
43612 + (qh->ep_is_in != 0)) {
43613 + qh->sched_frame =
43614 + dwc_frame_num_inc(qh->sched_frame, 1);
43615 + }
43616 + }
43617 + } else {
43618 + qh->sched_frame =
43619 + dwc_frame_num_inc(qh->start_split_frame,
43620 + qh->interval);
43621 + if (dwc_frame_num_le
43622 + (qh->sched_frame, frame_number)) {
43623 + qh->sched_frame = frame_number;
43624 + }
43625 + qh->sched_frame |= 0x7;
43626 + qh->start_split_frame = qh->sched_frame;
43627 + }
43628 + } else {
43629 + qh->sched_frame =
43630 + dwc_frame_num_inc(qh->sched_frame, qh->interval);
43631 + if (dwc_frame_num_le(qh->sched_frame, frame_number)) {
43632 + qh->sched_frame = frame_number;
43633 + }
43634 + }
43635 +
43636 + if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
43637 + dwc_otg_hcd_qh_remove(hcd, qh);
43638 + } else {
43639 + /*
43640 + * Remove from periodic_sched_queued and move to
43641 + * appropriate queue.
43642 + */
43643 + if ((microframe_schedule && dwc_frame_num_le(qh->sched_frame, frame_number)) ||
43644 + (!microframe_schedule && qh->sched_frame == frame_number)) {
43645 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
43646 + &qh->qh_list_entry);
43647 + } else {
43648 + DWC_LIST_MOVE_HEAD
43649 + (&hcd->periodic_sched_inactive,
43650 + &qh->qh_list_entry);
43651 + }
43652 + }
43653 + }
43654 +}
43655 +
43656 +/**
43657 + * This function allocates and initializes a QTD.
43658 + *
43659 + * @param urb The URB to create a QTD from. Each URB-QTD pair will end up
43660 + * pointing to each other so each pair should have a unique correlation.
43661 + * @param atomic_alloc Flag to do atomic alloc if needed
43662 + *
43663 + * @return Returns pointer to the newly allocated QTD, or NULL on error. */
43664 +dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb, int atomic_alloc)
43665 +{
43666 + dwc_otg_qtd_t *qtd;
43667 +
43668 + qtd = dwc_otg_hcd_qtd_alloc(atomic_alloc);
43669 + if (qtd == NULL) {
43670 + return NULL;
43671 + }
43672 +
43673 + dwc_otg_hcd_qtd_init(qtd, urb);
43674 + return qtd;
43675 +}
43676 +
43677 +/**
43678 + * Initializes a QTD structure.
43679 + *
43680 + * @param qtd The QTD to initialize.
43681 + * @param urb The URB to use for initialization. */
43682 +void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
43683 +{
43684 + dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t));
43685 + qtd->urb = urb;
43686 + if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) {
43687 + /*
43688 + * The only time the QTD data toggle is used is on the data
43689 + * phase of control transfers. This phase always starts with
43690 + * DATA1.
43691 + */
43692 + qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
43693 + qtd->control_phase = DWC_OTG_CONTROL_SETUP;
43694 + }
43695 +
43696 + /* start split */
43697 + qtd->complete_split = 0;
43698 + qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
43699 + qtd->isoc_split_offset = 0;
43700 + qtd->in_process = 0;
43701 +
43702 + /* Store the qtd ptr in the urb to reference what QTD. */
43703 + urb->qtd = qtd;
43704 + return;
43705 +}
43706 +
43707 +/**
43708 + * This function adds a QTD to the QTD-list of a QH. It will find the correct
43709 + * QH to place the QTD into. If it does not find a QH, then it will create a
43710 + * new QH. If the QH to which the QTD is added is not currently scheduled, it
43711 + * is placed into the proper schedule based on its EP type.
43712 + *
43713 + * @param[in] qtd The QTD to add
43714 + * @param[in] hcd The DWC HCD structure
43715 + * @param[out] qh out parameter to return queue head
43716 + * @param atomic_alloc Flag to do atomic alloc if needed
43717 + *
43718 + * @return 0 if successful, negative error code otherwise.
43719 + */
43720 +int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
43721 + dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
43722 +{
43723 + int retval = 0;
43724 + dwc_irqflags_t flags;
43725 +
43726 + dwc_otg_hcd_urb_t *urb = qtd->urb;
43727 +
43728 + /*
43729 + * Get the QH which holds the QTD-list to insert to. Create QH if it
43730 + * doesn't exist.
43731 + */
43732 + if (*qh == NULL) {
43733 + *qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
43734 + if (*qh == NULL) {
43735 + retval = -1;
43736 + goto done;
43737 + }
43738 + }
43739 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
43740 + retval = dwc_otg_hcd_qh_add(hcd, *qh);
43741 + if (retval == 0) {
43742 + DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
43743 + qtd_list_entry);
43744 + }
43745 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
43746 +
43747 +done:
43748 +
43749 + return retval;
43750 +}
43751 +
43752 +#endif /* DWC_DEVICE_ONLY */
43753 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
43754 new file mode 100644
43755 index 0000000..e46d9bb
43756 --- /dev/null
43757 +++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
43758 @@ -0,0 +1,185 @@
43759 +#ifndef _DWC_OS_DEP_H_
43760 +#define _DWC_OS_DEP_H_
43761 +
43762 +/**
43763 + * @file
43764 + *
43765 + * This file contains OS dependent structures.
43766 + *
43767 + */
43768 +
43769 +#include <linux/kernel.h>
43770 +#include <linux/module.h>
43771 +#include <linux/moduleparam.h>
43772 +#include <linux/init.h>
43773 +#include <linux/device.h>
43774 +#include <linux/errno.h>
43775 +#include <linux/types.h>
43776 +#include <linux/slab.h>
43777 +#include <linux/list.h>
43778 +#include <linux/interrupt.h>
43779 +#include <linux/ctype.h>
43780 +#include <linux/string.h>
43781 +#include <linux/dma-mapping.h>
43782 +#include <linux/jiffies.h>
43783 +#include <linux/delay.h>
43784 +#include <linux/timer.h>
43785 +#include <linux/workqueue.h>
43786 +#include <linux/stat.h>
43787 +#include <linux/pci.h>
43788 +
43789 +#include <linux/version.h>
43790 +
43791 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
43792 +# include <linux/irq.h>
43793 +#endif
43794 +
43795 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
43796 +# include <linux/usb/ch9.h>
43797 +#else
43798 +# include <linux/usb_ch9.h>
43799 +#endif
43800 +
43801 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
43802 +# include <linux/usb/gadget.h>
43803 +#else
43804 +# include <linux/usb_gadget.h>
43805 +#endif
43806 +
43807 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
43808 +# include <asm/irq.h>
43809 +#endif
43810 +
43811 +#ifdef PCI_INTERFACE
43812 +# include <asm/io.h>
43813 +#endif
43814 +
43815 +#ifdef LM_INTERFACE
43816 +# include <asm/unaligned.h>
43817 +# include <asm/sizes.h>
43818 +# include <asm/param.h>
43819 +# include <asm/io.h>
43820 +# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
43821 +# include <asm/arch/hardware.h>
43822 +# include <asm/arch/lm.h>
43823 +# include <asm/arch/irqs.h>
43824 +# include <asm/arch/regs-irq.h>
43825 +# else
43826 +/* in 2.6.31, at least, we seem to have lost the generic LM infrastructure -
43827 + here we assume that the machine architecture provides definitions
43828 + in its own header
43829 +*/
43830 +# include <mach/lm.h>
43831 +# include <mach/hardware.h>
43832 +# endif
43833 +#endif
43834 +
43835 +#ifdef PLATFORM_INTERFACE
43836 +#include <linux/platform_device.h>
43837 +#include <asm/mach/map.h>
43838 +#endif
43839 +
43840 +/** The OS page size */
43841 +#define DWC_OS_PAGE_SIZE PAGE_SIZE
43842 +
43843 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
43844 +typedef int gfp_t;
43845 +#endif
43846 +
43847 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
43848 +# define IRQF_SHARED SA_SHIRQ
43849 +#endif
43850 +
43851 +typedef struct os_dependent {
43852 + /** Base address returned from ioremap() */
43853 + void *base;
43854 +
43855 + /** Register offset for Diagnostic API */
43856 + uint32_t reg_offset;
43857 +
43858 +#ifdef LM_INTERFACE
43859 + struct lm_device *lmdev;
43860 +#elif defined(PCI_INTERFACE)
43861 + struct pci_dev *pcidev;
43862 +
43863 + /** Start address of a PCI region */
43864 + resource_size_t rsrc_start;
43865 +
43866 + /** Length address of a PCI region */
43867 + resource_size_t rsrc_len;
43868 +#elif defined(PLATFORM_INTERFACE)
43869 + struct platform_device *platformdev;
43870 +#endif
43871 +
43872 +} os_dependent_t;
43873 +
43874 +#ifdef __cplusplus
43875 +}
43876 +#endif
43877 +
43878 +
43879 +
43880 +/* Type for the our device on the chosen bus */
43881 +#if defined(LM_INTERFACE)
43882 +typedef struct lm_device dwc_bus_dev_t;
43883 +#elif defined(PCI_INTERFACE)
43884 +typedef struct pci_dev dwc_bus_dev_t;
43885 +#elif defined(PLATFORM_INTERFACE)
43886 +typedef struct platform_device dwc_bus_dev_t;
43887 +#endif
43888 +
43889 +/* Helper macro to retrieve drvdata from the device on the chosen bus */
43890 +#if defined(LM_INTERFACE)
43891 +#define DWC_OTG_BUSDRVDATA(_dev) lm_get_drvdata(_dev)
43892 +#elif defined(PCI_INTERFACE)
43893 +#define DWC_OTG_BUSDRVDATA(_dev) pci_get_drvdata(_dev)
43894 +#elif defined(PLATFORM_INTERFACE)
43895 +#define DWC_OTG_BUSDRVDATA(_dev) platform_get_drvdata(_dev)
43896 +#endif
43897 +
43898 +/**
43899 + * Helper macro returning the otg_device structure of a given struct device
43900 + *
43901 + * c.f. static dwc_otg_device_t *dwc_otg_drvdev(struct device *_dev)
43902 + */
43903 +#ifdef LM_INTERFACE
43904 +#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
43905 + struct lm_device *lm_dev = \
43906 + container_of(_dev, struct lm_device, dev); \
43907 + _var = lm_get_drvdata(lm_dev); \
43908 + } while (0)
43909 +
43910 +#elif defined(PCI_INTERFACE)
43911 +#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
43912 + _var = dev_get_drvdata(_dev); \
43913 + } while (0)
43914 +
43915 +#elif defined(PLATFORM_INTERFACE)
43916 +#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
43917 + struct platform_device *platform_dev = \
43918 + container_of(_dev, struct platform_device, dev); \
43919 + _var = platform_get_drvdata(platform_dev); \
43920 + } while (0)
43921 +#endif
43922 +
43923 +
43924 +/**
43925 + * Helper macro returning the struct dev of the given struct os_dependent
43926 + *
43927 + * c.f. static struct device *dwc_otg_getdev(struct os_dependent *osdep)
43928 + */
43929 +#ifdef LM_INTERFACE
43930 +#define DWC_OTG_OS_GETDEV(_osdep) \
43931 + ((_osdep).lmdev == NULL? NULL: &(_osdep).lmdev->dev)
43932 +#elif defined(PCI_INTERFACE)
43933 +#define DWC_OTG_OS_GETDEV(_osdep) \
43934 + ((_osdep).pci_dev == NULL? NULL: &(_osdep).pci_dev->dev)
43935 +#elif defined(PLATFORM_INTERFACE)
43936 +#define DWC_OTG_OS_GETDEV(_osdep) \
43937 + ((_osdep).platformdev == NULL? NULL: &(_osdep).platformdev->dev)
43938 +#endif
43939 +
43940 +
43941 +
43942 +
43943 +#endif /* _DWC_OS_DEP_H_ */
43944 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd.c
43945 new file mode 100644
43946 index 0000000..40fb25c
43947 --- /dev/null
43948 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd.c
43949 @@ -0,0 +1,2708 @@
43950 +/* ==========================================================================
43951 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.c $
43952 + * $Revision: #101 $
43953 + * $Date: 2012/08/10 $
43954 + * $Change: 2047372 $
43955 + *
43956 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
43957 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
43958 + * otherwise expressly agreed to in writing between Synopsys and you.
43959 + *
43960 + * The Software IS NOT an item of Licensed Software or Licensed Product under
43961 + * any End User Software License Agreement or Agreement for Licensed Product
43962 + * with Synopsys or any supplement thereto. You are permitted to use and
43963 + * redistribute this Software in source and binary forms, with or without
43964 + * modification, provided that redistributions of source code must retain this
43965 + * notice. You may not view, use, disclose, copy or distribute this file or
43966 + * any information contained herein except pursuant to this license grant from
43967 + * Synopsys. If you do not agree with this notice, including the disclaimer
43968 + * below, then you are not authorized to use the Software.
43969 + *
43970 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
43971 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43972 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43973 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
43974 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
43975 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43976 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
43977 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43978 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43979 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
43980 + * DAMAGE.
43981 + * ========================================================================== */
43982 +#ifndef DWC_HOST_ONLY
43983 +
43984 +/** @file
43985 + * This file implements PCD Core. All code in this file is portable and doesn't
43986 + * use any OS specific functions.
43987 + * PCD Core provides Interface, defined in <code><dwc_otg_pcd_if.h></code>
43988 + * header file, which can be used to implement OS specific PCD interface.
43989 + *
43990 + * An important function of the PCD is managing interrupts generated
43991 + * by the DWC_otg controller. The implementation of the DWC_otg device
43992 + * mode interrupt service routines is in dwc_otg_pcd_intr.c.
43993 + *
43994 + * @todo Add Device Mode test modes (Test J mode, Test K mode, etc).
43995 + * @todo Does it work when the request size is greater than DEPTSIZ
43996 + * transfer size
43997 + *
43998 + */
43999 +
44000 +#include "dwc_otg_pcd.h"
44001 +
44002 +#ifdef DWC_UTE_CFI
44003 +#include "dwc_otg_cfi.h"
44004 +
44005 +extern int init_cfi(cfiobject_t * cfiobj);
44006 +#endif
44007 +
44008 +/**
44009 + * Choose endpoint from ep arrays using usb_ep structure.
44010 + */
44011 +static dwc_otg_pcd_ep_t *get_ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
44012 +{
44013 + int i;
44014 + if (pcd->ep0.priv == handle) {
44015 + return &pcd->ep0;
44016 + }
44017 + for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
44018 + if (pcd->in_ep[i].priv == handle)
44019 + return &pcd->in_ep[i];
44020 + if (pcd->out_ep[i].priv == handle)
44021 + return &pcd->out_ep[i];
44022 + }
44023 +
44024 + return NULL;
44025 +}
44026 +
44027 +/**
44028 + * This function completes a request. It call's the request call back.
44029 + */
44030 +void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req,
44031 + int32_t status)
44032 +{
44033 + unsigned stopped = ep->stopped;
44034 +
44035 + DWC_DEBUGPL(DBG_PCDV, "%s(ep %p req %p)\n", __func__, ep, req);
44036 + DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
44037 +
44038 + /* don't modify queue heads during completion callback */
44039 + ep->stopped = 1;
44040 + /* spin_unlock/spin_lock now done in fops->complete() */
44041 + ep->pcd->fops->complete(ep->pcd, ep->priv, req->priv, status,
44042 + req->actual);
44043 +
44044 + if (ep->pcd->request_pending > 0) {
44045 + --ep->pcd->request_pending;
44046 + }
44047 +
44048 + ep->stopped = stopped;
44049 + DWC_FREE(req);
44050 +}
44051 +
44052 +/**
44053 + * This function terminates all the requsts in the EP request queue.
44054 + */
44055 +void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep)
44056 +{
44057 + dwc_otg_pcd_request_t *req;
44058 +
44059 + ep->stopped = 1;
44060 +
44061 + /* called with irqs blocked?? */
44062 + while (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
44063 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
44064 + dwc_otg_request_done(ep, req, -DWC_E_SHUTDOWN);
44065 + }
44066 +}
44067 +
44068 +void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
44069 + const struct dwc_otg_pcd_function_ops *fops)
44070 +{
44071 + pcd->fops = fops;
44072 +}
44073 +
44074 +/**
44075 + * PCD Callback function for initializing the PCD when switching to
44076 + * device mode.
44077 + *
44078 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
44079 + */
44080 +static int32_t dwc_otg_pcd_start_cb(void *p)
44081 +{
44082 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
44083 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
44084 +
44085 + /*
44086 + * Initialized the Core for Device mode.
44087 + */
44088 + if (dwc_otg_is_device_mode(core_if)) {
44089 + dwc_otg_core_dev_init(core_if);
44090 + /* Set core_if's lock pointer to the pcd->lock */
44091 + core_if->lock = pcd->lock;
44092 + }
44093 + return 1;
44094 +}
44095 +
44096 +/** CFI-specific buffer allocation function for EP */
44097 +#ifdef DWC_UTE_CFI
44098 +uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
44099 + size_t buflen, int flags)
44100 +{
44101 + dwc_otg_pcd_ep_t *ep;
44102 + ep = get_ep_from_handle(pcd, pep);
44103 + if (!ep) {
44104 + DWC_WARN("bad ep\n");
44105 + return -DWC_E_INVALID;
44106 + }
44107 +
44108 + return pcd->cfi->ops.ep_alloc_buf(pcd->cfi, pcd, ep, addr, buflen,
44109 + flags);
44110 +}
44111 +#else
44112 +uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
44113 + size_t buflen, int flags);
44114 +#endif
44115 +
44116 +/**
44117 + * PCD Callback function for notifying the PCD when resuming from
44118 + * suspend.
44119 + *
44120 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
44121 + */
44122 +static int32_t dwc_otg_pcd_resume_cb(void *p)
44123 +{
44124 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
44125 +
44126 + if (pcd->fops->resume) {
44127 + pcd->fops->resume(pcd);
44128 + }
44129 +
44130 + /* Stop the SRP timeout timer. */
44131 + if ((GET_CORE_IF(pcd)->core_params->phy_type != DWC_PHY_TYPE_PARAM_FS)
44132 + || (!GET_CORE_IF(pcd)->core_params->i2c_enable)) {
44133 + if (GET_CORE_IF(pcd)->srp_timer_started) {
44134 + GET_CORE_IF(pcd)->srp_timer_started = 0;
44135 + DWC_TIMER_CANCEL(GET_CORE_IF(pcd)->srp_timer);
44136 + }
44137 + }
44138 + return 1;
44139 +}
44140 +
44141 +/**
44142 + * PCD Callback function for notifying the PCD device is suspended.
44143 + *
44144 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
44145 + */
44146 +static int32_t dwc_otg_pcd_suspend_cb(void *p)
44147 +{
44148 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
44149 +
44150 + if (pcd->fops->suspend) {
44151 + DWC_SPINUNLOCK(pcd->lock);
44152 + pcd->fops->suspend(pcd);
44153 + DWC_SPINLOCK(pcd->lock);
44154 + }
44155 +
44156 + return 1;
44157 +}
44158 +
44159 +/**
44160 + * PCD Callback function for stopping the PCD when switching to Host
44161 + * mode.
44162 + *
44163 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
44164 + */
44165 +static int32_t dwc_otg_pcd_stop_cb(void *p)
44166 +{
44167 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
44168 + extern void dwc_otg_pcd_stop(dwc_otg_pcd_t * _pcd);
44169 +
44170 + dwc_otg_pcd_stop(pcd);
44171 + return 1;
44172 +}
44173 +
44174 +/**
44175 + * PCD Callback structure for handling mode switching.
44176 + */
44177 +static dwc_otg_cil_callbacks_t pcd_callbacks = {
44178 + .start = dwc_otg_pcd_start_cb,
44179 + .stop = dwc_otg_pcd_stop_cb,
44180 + .suspend = dwc_otg_pcd_suspend_cb,
44181 + .resume_wakeup = dwc_otg_pcd_resume_cb,
44182 + .p = 0, /* Set at registration */
44183 +};
44184 +
44185 +/**
44186 + * This function allocates a DMA Descriptor chain for the Endpoint
44187 + * buffer to be used for a transfer to/from the specified endpoint.
44188 + */
44189 +dwc_otg_dev_dma_desc_t *dwc_otg_ep_alloc_desc_chain(dwc_dma_t * dma_desc_addr,
44190 + uint32_t count)
44191 +{
44192 + return DWC_DMA_ALLOC_ATOMIC(count * sizeof(dwc_otg_dev_dma_desc_t),
44193 + dma_desc_addr);
44194 +}
44195 +
44196 +/**
44197 + * This function frees a DMA Descriptor chain that was allocated by ep_alloc_desc.
44198 + */
44199 +void dwc_otg_ep_free_desc_chain(dwc_otg_dev_dma_desc_t * desc_addr,
44200 + uint32_t dma_desc_addr, uint32_t count)
44201 +{
44202 + DWC_DMA_FREE(count * sizeof(dwc_otg_dev_dma_desc_t), desc_addr,
44203 + dma_desc_addr);
44204 +}
44205 +
44206 +#ifdef DWC_EN_ISOC
44207 +
44208 +/**
44209 + * This function initializes a descriptor chain for Isochronous transfer
44210 + *
44211 + * @param core_if Programming view of DWC_otg controller.
44212 + * @param dwc_ep The EP to start the transfer on.
44213 + *
44214 + */
44215 +void dwc_otg_iso_ep_start_ddma_transfer(dwc_otg_core_if_t * core_if,
44216 + dwc_ep_t * dwc_ep)
44217 +{
44218 +
44219 + dsts_data_t dsts = {.d32 = 0 };
44220 + depctl_data_t depctl = {.d32 = 0 };
44221 + volatile uint32_t *addr;
44222 + int i, j;
44223 + uint32_t len;
44224 +
44225 + if (dwc_ep->is_in)
44226 + dwc_ep->desc_cnt = dwc_ep->buf_proc_intrvl / dwc_ep->bInterval;
44227 + else
44228 + dwc_ep->desc_cnt =
44229 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
44230 + dwc_ep->bInterval;
44231 +
44232 + /** Allocate descriptors for double buffering */
44233 + dwc_ep->iso_desc_addr =
44234 + dwc_otg_ep_alloc_desc_chain(&dwc_ep->iso_dma_desc_addr,
44235 + dwc_ep->desc_cnt * 2);
44236 + if (dwc_ep->desc_addr) {
44237 + DWC_WARN("%s, can't allocate DMA descriptor chain\n", __func__);
44238 + return;
44239 + }
44240 +
44241 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
44242 +
44243 + /** ISO OUT EP */
44244 + if (dwc_ep->is_in == 0) {
44245 + dev_dma_desc_sts_t sts = {.d32 = 0 };
44246 + dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
44247 + dma_addr_t dma_ad;
44248 + uint32_t data_per_desc;
44249 + dwc_otg_dev_out_ep_regs_t *out_regs =
44250 + core_if->dev_if->out_ep_regs[dwc_ep->num];
44251 + int offset;
44252 +
44253 + addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
44254 + dma_ad = (dma_addr_t) DWC_READ_REG32(&(out_regs->doepdma));
44255 +
44256 + /** Buffer 0 descriptors setup */
44257 + dma_ad = dwc_ep->dma_addr0;
44258 +
44259 + sts.b_iso_out.bs = BS_HOST_READY;
44260 + sts.b_iso_out.rxsts = 0;
44261 + sts.b_iso_out.l = 0;
44262 + sts.b_iso_out.sp = 0;
44263 + sts.b_iso_out.ioc = 0;
44264 + sts.b_iso_out.pid = 0;
44265 + sts.b_iso_out.framenum = 0;
44266 +
44267 + offset = 0;
44268 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
44269 + i += dwc_ep->pkt_per_frm) {
44270 +
44271 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
44272 + uint32_t len = (j + 1) * dwc_ep->maxpacket;
44273 + if (len > dwc_ep->data_per_frame)
44274 + data_per_desc =
44275 + dwc_ep->data_per_frame -
44276 + j * dwc_ep->maxpacket;
44277 + else
44278 + data_per_desc = dwc_ep->maxpacket;
44279 + len = data_per_desc % 4;
44280 + if (len)
44281 + data_per_desc += 4 - len;
44282 +
44283 + sts.b_iso_out.rxbytes = data_per_desc;
44284 + dma_desc->buf = dma_ad;
44285 + dma_desc->status.d32 = sts.d32;
44286 +
44287 + offset += data_per_desc;
44288 + dma_desc++;
44289 + dma_ad += data_per_desc;
44290 + }
44291 + }
44292 +
44293 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
44294 + uint32_t len = (j + 1) * dwc_ep->maxpacket;
44295 + if (len > dwc_ep->data_per_frame)
44296 + data_per_desc =
44297 + dwc_ep->data_per_frame -
44298 + j * dwc_ep->maxpacket;
44299 + else
44300 + data_per_desc = dwc_ep->maxpacket;
44301 + len = data_per_desc % 4;
44302 + if (len)
44303 + data_per_desc += 4 - len;
44304 + sts.b_iso_out.rxbytes = data_per_desc;
44305 + dma_desc->buf = dma_ad;
44306 + dma_desc->status.d32 = sts.d32;
44307 +
44308 + offset += data_per_desc;
44309 + dma_desc++;
44310 + dma_ad += data_per_desc;
44311 + }
44312 +
44313 + sts.b_iso_out.ioc = 1;
44314 + len = (j + 1) * dwc_ep->maxpacket;
44315 + if (len > dwc_ep->data_per_frame)
44316 + data_per_desc =
44317 + dwc_ep->data_per_frame - j * dwc_ep->maxpacket;
44318 + else
44319 + data_per_desc = dwc_ep->maxpacket;
44320 + len = data_per_desc % 4;
44321 + if (len)
44322 + data_per_desc += 4 - len;
44323 + sts.b_iso_out.rxbytes = data_per_desc;
44324 +
44325 + dma_desc->buf = dma_ad;
44326 + dma_desc->status.d32 = sts.d32;
44327 + dma_desc++;
44328 +
44329 + /** Buffer 1 descriptors setup */
44330 + sts.b_iso_out.ioc = 0;
44331 + dma_ad = dwc_ep->dma_addr1;
44332 +
44333 + offset = 0;
44334 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
44335 + i += dwc_ep->pkt_per_frm) {
44336 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
44337 + uint32_t len = (j + 1) * dwc_ep->maxpacket;
44338 + if (len > dwc_ep->data_per_frame)
44339 + data_per_desc =
44340 + dwc_ep->data_per_frame -
44341 + j * dwc_ep->maxpacket;
44342 + else
44343 + data_per_desc = dwc_ep->maxpacket;
44344 + len = data_per_desc % 4;
44345 + if (len)
44346 + data_per_desc += 4 - len;
44347 +
44348 + data_per_desc =
44349 + sts.b_iso_out.rxbytes = data_per_desc;
44350 + dma_desc->buf = dma_ad;
44351 + dma_desc->status.d32 = sts.d32;
44352 +
44353 + offset += data_per_desc;
44354 + dma_desc++;
44355 + dma_ad += data_per_desc;
44356 + }
44357 + }
44358 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
44359 + data_per_desc =
44360 + ((j + 1) * dwc_ep->maxpacket >
44361 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
44362 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
44363 + data_per_desc +=
44364 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
44365 + sts.b_iso_out.rxbytes = data_per_desc;
44366 + dma_desc->buf = dma_ad;
44367 + dma_desc->status.d32 = sts.d32;
44368 +
44369 + offset += data_per_desc;
44370 + dma_desc++;
44371 + dma_ad += data_per_desc;
44372 + }
44373 +
44374 + sts.b_iso_out.ioc = 1;
44375 + sts.b_iso_out.l = 1;
44376 + data_per_desc =
44377 + ((j + 1) * dwc_ep->maxpacket >
44378 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
44379 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
44380 + data_per_desc +=
44381 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
44382 + sts.b_iso_out.rxbytes = data_per_desc;
44383 +
44384 + dma_desc->buf = dma_ad;
44385 + dma_desc->status.d32 = sts.d32;
44386 +
44387 + dwc_ep->next_frame = 0;
44388 +
44389 + /** Write dma_ad into DOEPDMA register */
44390 + DWC_WRITE_REG32(&(out_regs->doepdma),
44391 + (uint32_t) dwc_ep->iso_dma_desc_addr);
44392 +
44393 + }
44394 + /** ISO IN EP */
44395 + else {
44396 + dev_dma_desc_sts_t sts = {.d32 = 0 };
44397 + dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
44398 + dma_addr_t dma_ad;
44399 + dwc_otg_dev_in_ep_regs_t *in_regs =
44400 + core_if->dev_if->in_ep_regs[dwc_ep->num];
44401 + unsigned int frmnumber;
44402 + fifosize_data_t txfifosize, rxfifosize;
44403 +
44404 + txfifosize.d32 =
44405 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[dwc_ep->num]->
44406 + dtxfsts);
44407 + rxfifosize.d32 =
44408 + DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
44409 +
44410 + addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
44411 +
44412 + dma_ad = dwc_ep->dma_addr0;
44413 +
44414 + dsts.d32 =
44415 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
44416 +
44417 + sts.b_iso_in.bs = BS_HOST_READY;
44418 + sts.b_iso_in.txsts = 0;
44419 + sts.b_iso_in.sp =
44420 + (dwc_ep->data_per_frame % dwc_ep->maxpacket) ? 1 : 0;
44421 + sts.b_iso_in.ioc = 0;
44422 + sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
44423 +
44424 + frmnumber = dwc_ep->next_frame;
44425 +
44426 + sts.b_iso_in.framenum = frmnumber;
44427 + sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
44428 + sts.b_iso_in.l = 0;
44429 +
44430 + /** Buffer 0 descriptors setup */
44431 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
44432 + dma_desc->buf = dma_ad;
44433 + dma_desc->status.d32 = sts.d32;
44434 + dma_desc++;
44435 +
44436 + dma_ad += dwc_ep->data_per_frame;
44437 + sts.b_iso_in.framenum += dwc_ep->bInterval;
44438 + }
44439 +
44440 + sts.b_iso_in.ioc = 1;
44441 + dma_desc->buf = dma_ad;
44442 + dma_desc->status.d32 = sts.d32;
44443 + ++dma_desc;
44444 +
44445 + /** Buffer 1 descriptors setup */
44446 + sts.b_iso_in.ioc = 0;
44447 + dma_ad = dwc_ep->dma_addr1;
44448 +
44449 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
44450 + i += dwc_ep->pkt_per_frm) {
44451 + dma_desc->buf = dma_ad;
44452 + dma_desc->status.d32 = sts.d32;
44453 + dma_desc++;
44454 +
44455 + dma_ad += dwc_ep->data_per_frame;
44456 + sts.b_iso_in.framenum += dwc_ep->bInterval;
44457 +
44458 + sts.b_iso_in.ioc = 0;
44459 + }
44460 + sts.b_iso_in.ioc = 1;
44461 + sts.b_iso_in.l = 1;
44462 +
44463 + dma_desc->buf = dma_ad;
44464 + dma_desc->status.d32 = sts.d32;
44465 +
44466 + dwc_ep->next_frame = sts.b_iso_in.framenum + dwc_ep->bInterval;
44467 +
44468 + /** Write dma_ad into diepdma register */
44469 + DWC_WRITE_REG32(&(in_regs->diepdma),
44470 + (uint32_t) dwc_ep->iso_dma_desc_addr);
44471 + }
44472 + /** Enable endpoint, clear nak */
44473 + depctl.d32 = 0;
44474 + depctl.b.epena = 1;
44475 + depctl.b.usbactep = 1;
44476 + depctl.b.cnak = 1;
44477 +
44478 + DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
44479 + depctl.d32 = DWC_READ_REG32(addr);
44480 +}
44481 +
44482 +/**
44483 + * This function initializes a descriptor chain for Isochronous transfer
44484 + *
44485 + * @param core_if Programming view of DWC_otg controller.
44486 + * @param ep The EP to start the transfer on.
44487 + *
44488 + */
44489 +void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
44490 + dwc_ep_t * ep)
44491 +{
44492 + depctl_data_t depctl = {.d32 = 0 };
44493 + volatile uint32_t *addr;
44494 +
44495 + if (ep->is_in) {
44496 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
44497 + } else {
44498 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
44499 + }
44500 +
44501 + if (core_if->dma_enable == 0 || core_if->dma_desc_enable != 0) {
44502 + return;
44503 + } else {
44504 + deptsiz_data_t deptsiz = {.d32 = 0 };
44505 +
44506 + ep->xfer_len =
44507 + ep->data_per_frame * ep->buf_proc_intrvl / ep->bInterval;
44508 + ep->pkt_cnt =
44509 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
44510 + ep->xfer_count = 0;
44511 + ep->xfer_buff =
44512 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
44513 + ep->dma_addr =
44514 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
44515 +
44516 + if (ep->is_in) {
44517 + /* Program the transfer size and packet count
44518 + * as follows: xfersize = N * maxpacket +
44519 + * short_packet pktcnt = N + (short_packet
44520 + * exist ? 1 : 0)
44521 + */
44522 + deptsiz.b.mc = ep->pkt_per_frm;
44523 + deptsiz.b.xfersize = ep->xfer_len;
44524 + deptsiz.b.pktcnt =
44525 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
44526 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
44527 + dieptsiz, deptsiz.d32);
44528 +
44529 + /* Write the DMA register */
44530 + DWC_WRITE_REG32(&
44531 + (core_if->dev_if->in_ep_regs[ep->num]->
44532 + diepdma), (uint32_t) ep->dma_addr);
44533 +
44534 + } else {
44535 + deptsiz.b.pktcnt =
44536 + (ep->xfer_len + (ep->maxpacket - 1)) /
44537 + ep->maxpacket;
44538 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
44539 +
44540 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->
44541 + doeptsiz, deptsiz.d32);
44542 +
44543 + /* Write the DMA register */
44544 + DWC_WRITE_REG32(&
44545 + (core_if->dev_if->out_ep_regs[ep->num]->
44546 + doepdma), (uint32_t) ep->dma_addr);
44547 +
44548 + }
44549 + /** Enable endpoint, clear nak */
44550 + depctl.d32 = 0;
44551 + depctl.b.epena = 1;
44552 + depctl.b.cnak = 1;
44553 +
44554 + DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
44555 + }
44556 +}
44557 +
44558 +/**
44559 + * This function does the setup for a data transfer for an EP and
44560 + * starts the transfer. For an IN transfer, the packets will be
44561 + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
44562 + * the packets are unloaded from the Rx FIFO in the ISR.
44563 + *
44564 + * @param core_if Programming view of DWC_otg controller.
44565 + * @param ep The EP to start the transfer on.
44566 + */
44567 +
44568 +static void dwc_otg_iso_ep_start_transfer(dwc_otg_core_if_t * core_if,
44569 + dwc_ep_t * ep)
44570 +{
44571 + if (core_if->dma_enable) {
44572 + if (core_if->dma_desc_enable) {
44573 + if (ep->is_in) {
44574 + ep->desc_cnt = ep->pkt_cnt / ep->pkt_per_frm;
44575 + } else {
44576 + ep->desc_cnt = ep->pkt_cnt;
44577 + }
44578 + dwc_otg_iso_ep_start_ddma_transfer(core_if, ep);
44579 + } else {
44580 + if (core_if->pti_enh_enable) {
44581 + dwc_otg_iso_ep_start_buf_transfer(core_if, ep);
44582 + } else {
44583 + ep->cur_pkt_addr =
44584 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->
44585 + xfer_buff0;
44586 + ep->cur_pkt_dma_addr =
44587 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->
44588 + dma_addr0;
44589 + dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
44590 + }
44591 + }
44592 + } else {
44593 + ep->cur_pkt_addr =
44594 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
44595 + ep->cur_pkt_dma_addr =
44596 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
44597 + dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
44598 + }
44599 +}
44600 +
44601 +/**
44602 + * This function stops transfer for an EP and
44603 + * resets the ep's variables.
44604 + *
44605 + * @param core_if Programming view of DWC_otg controller.
44606 + * @param ep The EP to start the transfer on.
44607 + */
44608 +
44609 +void dwc_otg_iso_ep_stop_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
44610 +{
44611 + depctl_data_t depctl = {.d32 = 0 };
44612 + volatile uint32_t *addr;
44613 +
44614 + if (ep->is_in == 1) {
44615 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
44616 + } else {
44617 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
44618 + }
44619 +
44620 + /* disable the ep */
44621 + depctl.d32 = DWC_READ_REG32(addr);
44622 +
44623 + depctl.b.epdis = 1;
44624 + depctl.b.snak = 1;
44625 +
44626 + DWC_WRITE_REG32(addr, depctl.d32);
44627 +
44628 + if (core_if->dma_desc_enable &&
44629 + ep->iso_desc_addr && ep->iso_dma_desc_addr) {
44630 + dwc_otg_ep_free_desc_chain(ep->iso_desc_addr,
44631 + ep->iso_dma_desc_addr,
44632 + ep->desc_cnt * 2);
44633 + }
44634 +
44635 + /* reset varibales */
44636 + ep->dma_addr0 = 0;
44637 + ep->dma_addr1 = 0;
44638 + ep->xfer_buff0 = 0;
44639 + ep->xfer_buff1 = 0;
44640 + ep->data_per_frame = 0;
44641 + ep->data_pattern_frame = 0;
44642 + ep->sync_frame = 0;
44643 + ep->buf_proc_intrvl = 0;
44644 + ep->bInterval = 0;
44645 + ep->proc_buf_num = 0;
44646 + ep->pkt_per_frm = 0;
44647 + ep->pkt_per_frm = 0;
44648 + ep->desc_cnt = 0;
44649 + ep->iso_desc_addr = 0;
44650 + ep->iso_dma_desc_addr = 0;
44651 +}
44652 +
44653 +int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
44654 + uint8_t * buf0, uint8_t * buf1, dwc_dma_t dma0,
44655 + dwc_dma_t dma1, int sync_frame, int dp_frame,
44656 + int data_per_frame, int start_frame,
44657 + int buf_proc_intrvl, void *req_handle,
44658 + int atomic_alloc)
44659 +{
44660 + dwc_otg_pcd_ep_t *ep;
44661 + dwc_irqflags_t flags = 0;
44662 + dwc_ep_t *dwc_ep;
44663 + int32_t frm_data;
44664 + dsts_data_t dsts;
44665 + dwc_otg_core_if_t *core_if;
44666 +
44667 + ep = get_ep_from_handle(pcd, ep_handle);
44668 +
44669 + if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
44670 + DWC_WARN("bad ep\n");
44671 + return -DWC_E_INVALID;
44672 + }
44673 +
44674 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
44675 + core_if = GET_CORE_IF(pcd);
44676 + dwc_ep = &ep->dwc_ep;
44677 +
44678 + if (ep->iso_req_handle) {
44679 + DWC_WARN("ISO request in progress\n");
44680 + }
44681 +
44682 + dwc_ep->dma_addr0 = dma0;
44683 + dwc_ep->dma_addr1 = dma1;
44684 +
44685 + dwc_ep->xfer_buff0 = buf0;
44686 + dwc_ep->xfer_buff1 = buf1;
44687 +
44688 + dwc_ep->data_per_frame = data_per_frame;
44689 +
44690 + /** @todo - pattern data support is to be implemented in the future */
44691 + dwc_ep->data_pattern_frame = dp_frame;
44692 + dwc_ep->sync_frame = sync_frame;
44693 +
44694 + dwc_ep->buf_proc_intrvl = buf_proc_intrvl;
44695 +
44696 + dwc_ep->bInterval = 1 << (ep->desc->bInterval - 1);
44697 +
44698 + dwc_ep->proc_buf_num = 0;
44699 +
44700 + dwc_ep->pkt_per_frm = 0;
44701 + frm_data = ep->dwc_ep.data_per_frame;
44702 + while (frm_data > 0) {
44703 + dwc_ep->pkt_per_frm++;
44704 + frm_data -= ep->dwc_ep.maxpacket;
44705 + }
44706 +
44707 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
44708 +
44709 + if (start_frame == -1) {
44710 + dwc_ep->next_frame = dsts.b.soffn + 1;
44711 + if (dwc_ep->bInterval != 1) {
44712 + dwc_ep->next_frame =
44713 + dwc_ep->next_frame + (dwc_ep->bInterval - 1 -
44714 + dwc_ep->next_frame %
44715 + dwc_ep->bInterval);
44716 + }
44717 + } else {
44718 + dwc_ep->next_frame = start_frame;
44719 + }
44720 +
44721 + if (!core_if->pti_enh_enable) {
44722 + dwc_ep->pkt_cnt =
44723 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
44724 + dwc_ep->bInterval;
44725 + } else {
44726 + dwc_ep->pkt_cnt =
44727 + (dwc_ep->data_per_frame *
44728 + (dwc_ep->buf_proc_intrvl / dwc_ep->bInterval)
44729 + - 1 + dwc_ep->maxpacket) / dwc_ep->maxpacket;
44730 + }
44731 +
44732 + if (core_if->dma_desc_enable) {
44733 + dwc_ep->desc_cnt =
44734 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
44735 + dwc_ep->bInterval;
44736 + }
44737 +
44738 + if (atomic_alloc) {
44739 + dwc_ep->pkt_info =
44740 + DWC_ALLOC_ATOMIC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
44741 + } else {
44742 + dwc_ep->pkt_info =
44743 + DWC_ALLOC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
44744 + }
44745 + if (!dwc_ep->pkt_info) {
44746 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44747 + return -DWC_E_NO_MEMORY;
44748 + }
44749 + if (core_if->pti_enh_enable) {
44750 + dwc_memset(dwc_ep->pkt_info, 0,
44751 + sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
44752 + }
44753 +
44754 + dwc_ep->cur_pkt = 0;
44755 + ep->iso_req_handle = req_handle;
44756 +
44757 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44758 + dwc_otg_iso_ep_start_transfer(core_if, dwc_ep);
44759 + return 0;
44760 +}
44761 +
44762 +int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
44763 + void *req_handle)
44764 +{
44765 + dwc_irqflags_t flags = 0;
44766 + dwc_otg_pcd_ep_t *ep;
44767 + dwc_ep_t *dwc_ep;
44768 +
44769 + ep = get_ep_from_handle(pcd, ep_handle);
44770 + if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
44771 + DWC_WARN("bad ep\n");
44772 + return -DWC_E_INVALID;
44773 + }
44774 + dwc_ep = &ep->dwc_ep;
44775 +
44776 + dwc_otg_iso_ep_stop_transfer(GET_CORE_IF(pcd), dwc_ep);
44777 +
44778 + DWC_FREE(dwc_ep->pkt_info);
44779 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
44780 + if (ep->iso_req_handle != req_handle) {
44781 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44782 + return -DWC_E_INVALID;
44783 + }
44784 +
44785 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44786 +
44787 + ep->iso_req_handle = 0;
44788 + return 0;
44789 +}
44790 +
44791 +/**
44792 + * This function is used for perodical data exchnage between PCD and gadget drivers.
44793 + * for Isochronous EPs
44794 + *
44795 + * - Every time a sync period completes this function is called to
44796 + * perform data exchange between PCD and gadget
44797 + */
44798 +void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
44799 + void *req_handle)
44800 +{
44801 + int i;
44802 + dwc_ep_t *dwc_ep;
44803 +
44804 + dwc_ep = &ep->dwc_ep;
44805 +
44806 + DWC_SPINUNLOCK(ep->pcd->lock);
44807 + pcd->fops->isoc_complete(pcd, ep->priv, ep->iso_req_handle,
44808 + dwc_ep->proc_buf_num ^ 0x1);
44809 + DWC_SPINLOCK(ep->pcd->lock);
44810 +
44811 + for (i = 0; i < dwc_ep->pkt_cnt; ++i) {
44812 + dwc_ep->pkt_info[i].status = 0;
44813 + dwc_ep->pkt_info[i].offset = 0;
44814 + dwc_ep->pkt_info[i].length = 0;
44815 + }
44816 +}
44817 +
44818 +int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd, void *ep_handle,
44819 + void *iso_req_handle)
44820 +{
44821 + dwc_otg_pcd_ep_t *ep;
44822 + dwc_ep_t *dwc_ep;
44823 +
44824 + ep = get_ep_from_handle(pcd, ep_handle);
44825 + if (!ep->desc || ep->dwc_ep.num == 0) {
44826 + DWC_WARN("bad ep\n");
44827 + return -DWC_E_INVALID;
44828 + }
44829 + dwc_ep = &ep->dwc_ep;
44830 +
44831 + return dwc_ep->pkt_cnt;
44832 +}
44833 +
44834 +void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd, void *ep_handle,
44835 + void *iso_req_handle, int packet,
44836 + int *status, int *actual, int *offset)
44837 +{
44838 + dwc_otg_pcd_ep_t *ep;
44839 + dwc_ep_t *dwc_ep;
44840 +
44841 + ep = get_ep_from_handle(pcd, ep_handle);
44842 + if (!ep)
44843 + DWC_WARN("bad ep\n");
44844 +
44845 + dwc_ep = &ep->dwc_ep;
44846 +
44847 + *status = dwc_ep->pkt_info[packet].status;
44848 + *actual = dwc_ep->pkt_info[packet].length;
44849 + *offset = dwc_ep->pkt_info[packet].offset;
44850 +}
44851 +
44852 +#endif /* DWC_EN_ISOC */
44853 +
44854 +static void dwc_otg_pcd_init_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * pcd_ep,
44855 + uint32_t is_in, uint32_t ep_num)
44856 +{
44857 + /* Init EP structure */
44858 + pcd_ep->desc = 0;
44859 + pcd_ep->pcd = pcd;
44860 + pcd_ep->stopped = 1;
44861 + pcd_ep->queue_sof = 0;
44862 +
44863 + /* Init DWC ep structure */
44864 + pcd_ep->dwc_ep.is_in = is_in;
44865 + pcd_ep->dwc_ep.num = ep_num;
44866 + pcd_ep->dwc_ep.active = 0;
44867 + pcd_ep->dwc_ep.tx_fifo_num = 0;
44868 + /* Control until ep is actvated */
44869 + pcd_ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
44870 + pcd_ep->dwc_ep.maxpacket = MAX_PACKET_SIZE;
44871 + pcd_ep->dwc_ep.dma_addr = 0;
44872 + pcd_ep->dwc_ep.start_xfer_buff = 0;
44873 + pcd_ep->dwc_ep.xfer_buff = 0;
44874 + pcd_ep->dwc_ep.xfer_len = 0;
44875 + pcd_ep->dwc_ep.xfer_count = 0;
44876 + pcd_ep->dwc_ep.sent_zlp = 0;
44877 + pcd_ep->dwc_ep.total_len = 0;
44878 + pcd_ep->dwc_ep.desc_addr = 0;
44879 + pcd_ep->dwc_ep.dma_desc_addr = 0;
44880 + DWC_CIRCLEQ_INIT(&pcd_ep->queue);
44881 +}
44882 +
44883 +/**
44884 + * Initialize ep's
44885 + */
44886 +static void dwc_otg_pcd_reinit(dwc_otg_pcd_t * pcd)
44887 +{
44888 + int i;
44889 + uint32_t hwcfg1;
44890 + dwc_otg_pcd_ep_t *ep;
44891 + int in_ep_cntr, out_ep_cntr;
44892 + uint32_t num_in_eps = (GET_CORE_IF(pcd))->dev_if->num_in_eps;
44893 + uint32_t num_out_eps = (GET_CORE_IF(pcd))->dev_if->num_out_eps;
44894 +
44895 + /**
44896 + * Initialize the EP0 structure.
44897 + */
44898 + ep = &pcd->ep0;
44899 + dwc_otg_pcd_init_ep(pcd, ep, 0, 0);
44900 +
44901 + in_ep_cntr = 0;
44902 + hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 3;
44903 + for (i = 1; in_ep_cntr < num_in_eps; i++) {
44904 + if ((hwcfg1 & 0x1) == 0) {
44905 + dwc_otg_pcd_ep_t *ep = &pcd->in_ep[in_ep_cntr];
44906 + in_ep_cntr++;
44907 + /**
44908 + * @todo NGS: Add direction to EP, based on contents
44909 + * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
44910 + * sprintf(";r
44911 + */
44912 + dwc_otg_pcd_init_ep(pcd, ep, 1 /* IN */ , i);
44913 +
44914 + DWC_CIRCLEQ_INIT(&ep->queue);
44915 + }
44916 + hwcfg1 >>= 2;
44917 + }
44918 +
44919 + out_ep_cntr = 0;
44920 + hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 2;
44921 + for (i = 1; out_ep_cntr < num_out_eps; i++) {
44922 + if ((hwcfg1 & 0x1) == 0) {
44923 + dwc_otg_pcd_ep_t *ep = &pcd->out_ep[out_ep_cntr];
44924 + out_ep_cntr++;
44925 + /**
44926 + * @todo NGS: Add direction to EP, based on contents
44927 + * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
44928 + * sprintf(";r
44929 + */
44930 + dwc_otg_pcd_init_ep(pcd, ep, 0 /* OUT */ , i);
44931 + DWC_CIRCLEQ_INIT(&ep->queue);
44932 + }
44933 + hwcfg1 >>= 2;
44934 + }
44935 +
44936 + pcd->ep0state = EP0_DISCONNECT;
44937 + pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE;
44938 + pcd->ep0.dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
44939 +}
44940 +
44941 +/**
44942 + * This function is called when the SRP timer expires. The SRP should
44943 + * complete within 6 seconds.
44944 + */
44945 +static void srp_timeout(void *ptr)
44946 +{
44947 + gotgctl_data_t gotgctl;
44948 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
44949 + volatile uint32_t *addr = &core_if->core_global_regs->gotgctl;
44950 +
44951 + gotgctl.d32 = DWC_READ_REG32(addr);
44952 +
44953 + core_if->srp_timer_started = 0;
44954 +
44955 + if (core_if->adp_enable) {
44956 + if (gotgctl.b.bsesvld == 0) {
44957 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
44958 + DWC_PRINTF("SRP Timeout BSESSVLD = 0\n");
44959 + /* Power off the core */
44960 + if (core_if->power_down == 2) {
44961 + gpwrdn.b.pwrdnswtch = 1;
44962 + DWC_MODIFY_REG32(&core_if->
44963 + core_global_regs->gpwrdn,
44964 + gpwrdn.d32, 0);
44965 + }
44966 +
44967 + gpwrdn.d32 = 0;
44968 + gpwrdn.b.pmuintsel = 1;
44969 + gpwrdn.b.pmuactv = 1;
44970 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
44971 + gpwrdn.d32);
44972 + dwc_otg_adp_probe_start(core_if);
44973 + } else {
44974 + DWC_PRINTF("SRP Timeout BSESSVLD = 1\n");
44975 + core_if->op_state = B_PERIPHERAL;
44976 + dwc_otg_core_init(core_if);
44977 + dwc_otg_enable_global_interrupts(core_if);
44978 + cil_pcd_start(core_if);
44979 + }
44980 + }
44981 +
44982 + if ((core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) &&
44983 + (core_if->core_params->i2c_enable)) {
44984 + DWC_PRINTF("SRP Timeout\n");
44985 +
44986 + if ((core_if->srp_success) && (gotgctl.b.bsesvld)) {
44987 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
44988 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
44989 + }
44990 +
44991 + /* Clear Session Request */
44992 + gotgctl.d32 = 0;
44993 + gotgctl.b.sesreq = 1;
44994 + DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl,
44995 + gotgctl.d32, 0);
44996 +
44997 + core_if->srp_success = 0;
44998 + } else {
44999 + __DWC_ERROR("Device not connected/responding\n");
45000 + gotgctl.b.sesreq = 0;
45001 + DWC_WRITE_REG32(addr, gotgctl.d32);
45002 + }
45003 + } else if (gotgctl.b.sesreq) {
45004 + DWC_PRINTF("SRP Timeout\n");
45005 +
45006 + __DWC_ERROR("Device not connected/responding\n");
45007 + gotgctl.b.sesreq = 0;
45008 + DWC_WRITE_REG32(addr, gotgctl.d32);
45009 + } else {
45010 + DWC_PRINTF(" SRP GOTGCTL=%0x\n", gotgctl.d32);
45011 + }
45012 +}
45013 +
45014 +/**
45015 + * Tasklet
45016 + *
45017 + */
45018 +extern void start_next_request(dwc_otg_pcd_ep_t * ep);
45019 +
45020 +static void start_xfer_tasklet_func(void *data)
45021 +{
45022 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
45023 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
45024 +
45025 + int i;
45026 + depctl_data_t diepctl;
45027 +
45028 + DWC_DEBUGPL(DBG_PCDV, "Start xfer tasklet\n");
45029 +
45030 + diepctl.d32 = DWC_READ_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl);
45031 +
45032 + if (pcd->ep0.queue_sof) {
45033 + pcd->ep0.queue_sof = 0;
45034 + start_next_request(&pcd->ep0);
45035 + // break;
45036 + }
45037 +
45038 + for (i = 0; i < core_if->dev_if->num_in_eps; i++) {
45039 + depctl_data_t diepctl;
45040 + diepctl.d32 =
45041 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
45042 +
45043 + if (pcd->in_ep[i].queue_sof) {
45044 + pcd->in_ep[i].queue_sof = 0;
45045 + start_next_request(&pcd->in_ep[i]);
45046 + // break;
45047 + }
45048 + }
45049 +
45050 + return;
45051 +}
45052 +
45053 +/**
45054 + * This function initialized the PCD portion of the driver.
45055 + *
45056 + */
45057 +dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if)
45058 +{
45059 + dwc_otg_pcd_t *pcd = NULL;
45060 + dwc_otg_dev_if_t *dev_if;
45061 + int i;
45062 +
45063 + /*
45064 + * Allocate PCD structure
45065 + */
45066 + pcd = DWC_ALLOC(sizeof(dwc_otg_pcd_t));
45067 +
45068 + if (pcd == NULL) {
45069 + return NULL;
45070 + }
45071 +
45072 + pcd->lock = DWC_SPINLOCK_ALLOC();
45073 + DWC_DEBUGPL(DBG_HCDV, "Init of PCD %p given core_if %p\n",
45074 + pcd, core_if);//GRAYG
45075 + if (!pcd->lock) {
45076 + DWC_ERROR("Could not allocate lock for pcd");
45077 + DWC_FREE(pcd);
45078 + return NULL;
45079 + }
45080 + /* Set core_if's lock pointer to hcd->lock */
45081 + core_if->lock = pcd->lock;
45082 + pcd->core_if = core_if;
45083 +
45084 + dev_if = core_if->dev_if;
45085 + dev_if->isoc_ep = NULL;
45086 +
45087 + if (core_if->hwcfg4.b.ded_fifo_en) {
45088 + DWC_PRINTF("Dedicated Tx FIFOs mode\n");
45089 + } else {
45090 + DWC_PRINTF("Shared Tx FIFO mode\n");
45091 + }
45092 +
45093 + /*
45094 + * Initialized the Core for Device mode here if there is nod ADP support.
45095 + * Otherwise it will be done later in dwc_otg_adp_start routine.
45096 + */
45097 + if (dwc_otg_is_device_mode(core_if) /*&& !core_if->adp_enable*/) {
45098 + dwc_otg_core_dev_init(core_if);
45099 + }
45100 +
45101 + /*
45102 + * Register the PCD Callbacks.
45103 + */
45104 + dwc_otg_cil_register_pcd_callbacks(core_if, &pcd_callbacks, pcd);
45105 +
45106 + /*
45107 + * Initialize the DMA buffer for SETUP packets
45108 + */
45109 + if (GET_CORE_IF(pcd)->dma_enable) {
45110 + pcd->setup_pkt =
45111 + DWC_DMA_ALLOC(sizeof(*pcd->setup_pkt) * 5,
45112 + &pcd->setup_pkt_dma_handle);
45113 + if (pcd->setup_pkt == NULL) {
45114 + DWC_FREE(pcd);
45115 + return NULL;
45116 + }
45117 +
45118 + pcd->status_buf =
45119 + DWC_DMA_ALLOC(sizeof(uint16_t),
45120 + &pcd->status_buf_dma_handle);
45121 + if (pcd->status_buf == NULL) {
45122 + DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
45123 + pcd->setup_pkt, pcd->setup_pkt_dma_handle);
45124 + DWC_FREE(pcd);
45125 + return NULL;
45126 + }
45127 +
45128 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45129 + dev_if->setup_desc_addr[0] =
45130 + dwc_otg_ep_alloc_desc_chain
45131 + (&dev_if->dma_setup_desc_addr[0], 1);
45132 + dev_if->setup_desc_addr[1] =
45133 + dwc_otg_ep_alloc_desc_chain
45134 + (&dev_if->dma_setup_desc_addr[1], 1);
45135 + dev_if->in_desc_addr =
45136 + dwc_otg_ep_alloc_desc_chain
45137 + (&dev_if->dma_in_desc_addr, 1);
45138 + dev_if->out_desc_addr =
45139 + dwc_otg_ep_alloc_desc_chain
45140 + (&dev_if->dma_out_desc_addr, 1);
45141 + pcd->data_terminated = 0;
45142 +
45143 + if (dev_if->setup_desc_addr[0] == 0
45144 + || dev_if->setup_desc_addr[1] == 0
45145 + || dev_if->in_desc_addr == 0
45146 + || dev_if->out_desc_addr == 0) {
45147 +
45148 + if (dev_if->out_desc_addr)
45149 + dwc_otg_ep_free_desc_chain
45150 + (dev_if->out_desc_addr,
45151 + dev_if->dma_out_desc_addr, 1);
45152 + if (dev_if->in_desc_addr)
45153 + dwc_otg_ep_free_desc_chain
45154 + (dev_if->in_desc_addr,
45155 + dev_if->dma_in_desc_addr, 1);
45156 + if (dev_if->setup_desc_addr[1])
45157 + dwc_otg_ep_free_desc_chain
45158 + (dev_if->setup_desc_addr[1],
45159 + dev_if->dma_setup_desc_addr[1], 1);
45160 + if (dev_if->setup_desc_addr[0])
45161 + dwc_otg_ep_free_desc_chain
45162 + (dev_if->setup_desc_addr[0],
45163 + dev_if->dma_setup_desc_addr[0], 1);
45164 +
45165 + DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
45166 + pcd->setup_pkt,
45167 + pcd->setup_pkt_dma_handle);
45168 + DWC_DMA_FREE(sizeof(*pcd->status_buf),
45169 + pcd->status_buf,
45170 + pcd->status_buf_dma_handle);
45171 +
45172 + DWC_FREE(pcd);
45173 +
45174 + return NULL;
45175 + }
45176 + }
45177 + } else {
45178 + pcd->setup_pkt = DWC_ALLOC(sizeof(*pcd->setup_pkt) * 5);
45179 + if (pcd->setup_pkt == NULL) {
45180 + DWC_FREE(pcd);
45181 + return NULL;
45182 + }
45183 +
45184 + pcd->status_buf = DWC_ALLOC(sizeof(uint16_t));
45185 + if (pcd->status_buf == NULL) {
45186 + DWC_FREE(pcd->setup_pkt);
45187 + DWC_FREE(pcd);
45188 + return NULL;
45189 + }
45190 + }
45191 +
45192 + dwc_otg_pcd_reinit(pcd);
45193 +
45194 + /* Allocate the cfi object for the PCD */
45195 +#ifdef DWC_UTE_CFI
45196 + pcd->cfi = DWC_ALLOC(sizeof(cfiobject_t));
45197 + if (NULL == pcd->cfi)
45198 + goto fail;
45199 + if (init_cfi(pcd->cfi)) {
45200 + CFI_INFO("%s: Failed to init the CFI object\n", __func__);
45201 + goto fail;
45202 + }
45203 +#endif
45204 +
45205 + /* Initialize tasklets */
45206 + pcd->start_xfer_tasklet = DWC_TASK_ALLOC("xfer_tasklet",
45207 + start_xfer_tasklet_func, pcd);
45208 + pcd->test_mode_tasklet = DWC_TASK_ALLOC("test_mode_tasklet",
45209 + do_test_mode, pcd);
45210 +
45211 + /* Initialize SRP timer */
45212 + core_if->srp_timer = DWC_TIMER_ALLOC("SRP TIMER", srp_timeout, core_if);
45213 +
45214 + if (core_if->core_params->dev_out_nak) {
45215 + /**
45216 + * Initialize xfer timeout timer. Implemented for
45217 + * 2.93a feature "Device DDMA OUT NAK Enhancement"
45218 + */
45219 + for(i = 0; i < MAX_EPS_CHANNELS; i++) {
45220 + pcd->core_if->ep_xfer_timer[i] =
45221 + DWC_TIMER_ALLOC("ep timer", ep_xfer_timeout,
45222 + &pcd->core_if->ep_xfer_info[i]);
45223 + }
45224 + }
45225 +
45226 + return pcd;
45227 +#ifdef DWC_UTE_CFI
45228 +fail:
45229 +#endif
45230 + if (pcd->setup_pkt)
45231 + DWC_FREE(pcd->setup_pkt);
45232 + if (pcd->status_buf)
45233 + DWC_FREE(pcd->status_buf);
45234 +#ifdef DWC_UTE_CFI
45235 + if (pcd->cfi)
45236 + DWC_FREE(pcd->cfi);
45237 +#endif
45238 + if (pcd)
45239 + DWC_FREE(pcd);
45240 + return NULL;
45241 +
45242 +}
45243 +
45244 +/**
45245 + * Remove PCD specific data
45246 + */
45247 +void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd)
45248 +{
45249 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
45250 + int i;
45251 + if (pcd->core_if->core_params->dev_out_nak) {
45252 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
45253 + DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[i]);
45254 + pcd->core_if->ep_xfer_info[i].state = 0;
45255 + }
45256 + }
45257 +
45258 + if (GET_CORE_IF(pcd)->dma_enable) {
45259 + DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5, pcd->setup_pkt,
45260 + pcd->setup_pkt_dma_handle);
45261 + DWC_DMA_FREE(sizeof(uint16_t), pcd->status_buf,
45262 + pcd->status_buf_dma_handle);
45263 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45264 + dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[0],
45265 + dev_if->dma_setup_desc_addr
45266 + [0], 1);
45267 + dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[1],
45268 + dev_if->dma_setup_desc_addr
45269 + [1], 1);
45270 + dwc_otg_ep_free_desc_chain(dev_if->in_desc_addr,
45271 + dev_if->dma_in_desc_addr, 1);
45272 + dwc_otg_ep_free_desc_chain(dev_if->out_desc_addr,
45273 + dev_if->dma_out_desc_addr,
45274 + 1);
45275 + }
45276 + } else {
45277 + DWC_FREE(pcd->setup_pkt);
45278 + DWC_FREE(pcd->status_buf);
45279 + }
45280 + DWC_SPINLOCK_FREE(pcd->lock);
45281 + /* Set core_if's lock pointer to NULL */
45282 + pcd->core_if->lock = NULL;
45283 +
45284 + DWC_TASK_FREE(pcd->start_xfer_tasklet);
45285 + DWC_TASK_FREE(pcd->test_mode_tasklet);
45286 + if (pcd->core_if->core_params->dev_out_nak) {
45287 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
45288 + if (pcd->core_if->ep_xfer_timer[i]) {
45289 + DWC_TIMER_FREE(pcd->core_if->ep_xfer_timer[i]);
45290 + }
45291 + }
45292 + }
45293 +
45294 +/* Release the CFI object's dynamic memory */
45295 +#ifdef DWC_UTE_CFI
45296 + if (pcd->cfi->ops.release) {
45297 + pcd->cfi->ops.release(pcd->cfi);
45298 + }
45299 +#endif
45300 +
45301 + DWC_FREE(pcd);
45302 +}
45303 +
45304 +/**
45305 + * Returns whether registered pcd is dual speed or not
45306 + */
45307 +uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd)
45308 +{
45309 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
45310 +
45311 + if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) ||
45312 + ((core_if->hwcfg2.b.hs_phy_type == 2) &&
45313 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
45314 + (core_if->core_params->ulpi_fs_ls))) {
45315 + return 0;
45316 + }
45317 +
45318 + return 1;
45319 +}
45320 +
45321 +/**
45322 + * Returns whether registered pcd is OTG capable or not
45323 + */
45324 +uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd)
45325 +{
45326 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
45327 + gusbcfg_data_t usbcfg = {.d32 = 0 };
45328 +
45329 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
45330 + if (!usbcfg.b.srpcap || !usbcfg.b.hnpcap) {
45331 + return 0;
45332 + }
45333 +
45334 + return 1;
45335 +}
45336 +
45337 +/**
45338 + * This function assigns periodic Tx FIFO to an periodic EP
45339 + * in shared Tx FIFO mode
45340 + */
45341 +static uint32_t assign_tx_fifo(dwc_otg_core_if_t * core_if)
45342 +{
45343 + uint32_t TxMsk = 1;
45344 + int i;
45345 +
45346 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; ++i) {
45347 + if ((TxMsk & core_if->tx_msk) == 0) {
45348 + core_if->tx_msk |= TxMsk;
45349 + return i + 1;
45350 + }
45351 + TxMsk <<= 1;
45352 + }
45353 + return 0;
45354 +}
45355 +
45356 +/**
45357 + * This function assigns periodic Tx FIFO to an periodic EP
45358 + * in shared Tx FIFO mode
45359 + */
45360 +static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t * core_if)
45361 +{
45362 + uint32_t PerTxMsk = 1;
45363 + int i;
45364 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; ++i) {
45365 + if ((PerTxMsk & core_if->p_tx_msk) == 0) {
45366 + core_if->p_tx_msk |= PerTxMsk;
45367 + return i + 1;
45368 + }
45369 + PerTxMsk <<= 1;
45370 + }
45371 + return 0;
45372 +}
45373 +
45374 +/**
45375 + * This function releases periodic Tx FIFO
45376 + * in shared Tx FIFO mode
45377 + */
45378 +static void release_perio_tx_fifo(dwc_otg_core_if_t * core_if,
45379 + uint32_t fifo_num)
45380 +{
45381 + core_if->p_tx_msk =
45382 + (core_if->p_tx_msk & (1 << (fifo_num - 1))) ^ core_if->p_tx_msk;
45383 +}
45384 +
45385 +/**
45386 + * This function releases periodic Tx FIFO
45387 + * in shared Tx FIFO mode
45388 + */
45389 +static void release_tx_fifo(dwc_otg_core_if_t * core_if, uint32_t fifo_num)
45390 +{
45391 + core_if->tx_msk =
45392 + (core_if->tx_msk & (1 << (fifo_num - 1))) ^ core_if->tx_msk;
45393 +}
45394 +
45395 +/**
45396 + * This function is being called from gadget
45397 + * to enable PCD endpoint.
45398 + */
45399 +int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
45400 + const uint8_t * ep_desc, void *usb_ep)
45401 +{
45402 + int num, dir;
45403 + dwc_otg_pcd_ep_t *ep = NULL;
45404 + const usb_endpoint_descriptor_t *desc;
45405 + dwc_irqflags_t flags;
45406 + fifosize_data_t dptxfsiz = {.d32 = 0 };
45407 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
45408 + gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
45409 + int retval = 0;
45410 + int i, epcount;
45411 +
45412 + desc = (const usb_endpoint_descriptor_t *)ep_desc;
45413 +
45414 + if (!desc) {
45415 + pcd->ep0.priv = usb_ep;
45416 + ep = &pcd->ep0;
45417 + retval = -DWC_E_INVALID;
45418 + goto out;
45419 + }
45420 +
45421 + num = UE_GET_ADDR(desc->bEndpointAddress);
45422 + dir = UE_GET_DIR(desc->bEndpointAddress);
45423 +
45424 + if (!desc->wMaxPacketSize) {
45425 + DWC_WARN("bad maxpacketsize\n");
45426 + retval = -DWC_E_INVALID;
45427 + goto out;
45428 + }
45429 +
45430 + if (dir == UE_DIR_IN) {
45431 + epcount = pcd->core_if->dev_if->num_in_eps;
45432 + for (i = 0; i < epcount; i++) {
45433 + if (num == pcd->in_ep[i].dwc_ep.num) {
45434 + ep = &pcd->in_ep[i];
45435 + break;
45436 + }
45437 + }
45438 + } else {
45439 + epcount = pcd->core_if->dev_if->num_out_eps;
45440 + for (i = 0; i < epcount; i++) {
45441 + if (num == pcd->out_ep[i].dwc_ep.num) {
45442 + ep = &pcd->out_ep[i];
45443 + break;
45444 + }
45445 + }
45446 + }
45447 +
45448 + if (!ep) {
45449 + DWC_WARN("bad address\n");
45450 + retval = -DWC_E_INVALID;
45451 + goto out;
45452 + }
45453 +
45454 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45455 +
45456 + ep->desc = desc;
45457 + ep->priv = usb_ep;
45458 +
45459 + /*
45460 + * Activate the EP
45461 + */
45462 + ep->stopped = 0;
45463 +
45464 + ep->dwc_ep.is_in = (dir == UE_DIR_IN);
45465 + ep->dwc_ep.maxpacket = UGETW(desc->wMaxPacketSize);
45466 +
45467 + ep->dwc_ep.type = desc->bmAttributes & UE_XFERTYPE;
45468 +
45469 + if (ep->dwc_ep.is_in) {
45470 + if (!GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45471 + ep->dwc_ep.tx_fifo_num = 0;
45472 +
45473 + if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
45474 + /*
45475 + * if ISOC EP then assign a Periodic Tx FIFO.
45476 + */
45477 + ep->dwc_ep.tx_fifo_num =
45478 + assign_perio_tx_fifo(GET_CORE_IF(pcd));
45479 + }
45480 + } else {
45481 + /*
45482 + * if Dedicated FIFOs mode is on then assign a Tx FIFO.
45483 + */
45484 + ep->dwc_ep.tx_fifo_num =
45485 + assign_tx_fifo(GET_CORE_IF(pcd));
45486 + }
45487 +
45488 + /* Calculating EP info controller base address */
45489 + if (ep->dwc_ep.tx_fifo_num
45490 + && GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45491 + gdfifocfg.d32 =
45492 + DWC_READ_REG32(&GET_CORE_IF(pcd)->
45493 + core_global_regs->gdfifocfg);
45494 + gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
45495 + dptxfsiz.d32 =
45496 + (DWC_READ_REG32
45497 + (&GET_CORE_IF(pcd)->core_global_regs->
45498 + dtxfsiz[ep->dwc_ep.tx_fifo_num - 1]) >> 16);
45499 + gdfifocfg.b.epinfobase =
45500 + gdfifocfgbase.d32 + dptxfsiz.d32;
45501 + if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) {
45502 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
45503 + core_global_regs->gdfifocfg,
45504 + gdfifocfg.d32);
45505 + }
45506 + }
45507 + }
45508 + /* Set initial data PID. */
45509 + if (ep->dwc_ep.type == UE_BULK) {
45510 + ep->dwc_ep.data_pid_start = 0;
45511 + }
45512 +
45513 + /* Alloc DMA Descriptors */
45514 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45515 +#ifndef DWC_UTE_PER_IO
45516 + if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
45517 +#endif
45518 + ep->dwc_ep.desc_addr =
45519 + dwc_otg_ep_alloc_desc_chain(&ep->
45520 + dwc_ep.dma_desc_addr,
45521 + MAX_DMA_DESC_CNT);
45522 + if (!ep->dwc_ep.desc_addr) {
45523 + DWC_WARN("%s, can't allocate DMA descriptor\n",
45524 + __func__);
45525 + retval = -DWC_E_SHUTDOWN;
45526 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45527 + goto out;
45528 + }
45529 +#ifndef DWC_UTE_PER_IO
45530 + }
45531 +#endif
45532 + }
45533 +
45534 + DWC_DEBUGPL(DBG_PCD, "Activate %s: type=%d, mps=%d desc=%p\n",
45535 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
45536 + ep->dwc_ep.type, ep->dwc_ep.maxpacket, ep->desc);
45537 +#ifdef DWC_UTE_PER_IO
45538 + ep->dwc_ep.xiso_bInterval = 1 << (ep->desc->bInterval - 1);
45539 +#endif
45540 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
45541 + ep->dwc_ep.bInterval = 1 << (ep->desc->bInterval - 1);
45542 + ep->dwc_ep.frame_num = 0xFFFFFFFF;
45543 + }
45544 +
45545 + dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
45546 +
45547 +#ifdef DWC_UTE_CFI
45548 + if (pcd->cfi->ops.ep_enable) {
45549 + pcd->cfi->ops.ep_enable(pcd->cfi, pcd, ep);
45550 + }
45551 +#endif
45552 +
45553 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45554 +
45555 +out:
45556 + return retval;
45557 +}
45558 +
45559 +/**
45560 + * This function is being called from gadget
45561 + * to disable PCD endpoint.
45562 + */
45563 +int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle)
45564 +{
45565 + dwc_otg_pcd_ep_t *ep;
45566 + dwc_irqflags_t flags;
45567 + dwc_otg_dev_dma_desc_t *desc_addr;
45568 + dwc_dma_t dma_desc_addr;
45569 + gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
45570 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
45571 + fifosize_data_t dptxfsiz = {.d32 = 0 };
45572 +
45573 + ep = get_ep_from_handle(pcd, ep_handle);
45574 +
45575 + if (!ep || !ep->desc) {
45576 + DWC_DEBUGPL(DBG_PCD, "bad ep address\n");
45577 + return -DWC_E_INVALID;
45578 + }
45579 +
45580 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45581 +
45582 + dwc_otg_request_nuke(ep);
45583 +
45584 + dwc_otg_ep_deactivate(GET_CORE_IF(pcd), &ep->dwc_ep);
45585 + if (pcd->core_if->core_params->dev_out_nak) {
45586 + DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[ep->dwc_ep.num]);
45587 + pcd->core_if->ep_xfer_info[ep->dwc_ep.num].state = 0;
45588 + }
45589 + ep->desc = NULL;
45590 + ep->stopped = 1;
45591 +
45592 + gdfifocfg.d32 =
45593 + DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg);
45594 + gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
45595 +
45596 + if (ep->dwc_ep.is_in) {
45597 + if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45598 + /* Flush the Tx FIFO */
45599 + dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd),
45600 + ep->dwc_ep.tx_fifo_num);
45601 + }
45602 + release_perio_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
45603 + release_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
45604 + if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45605 + /* Decreasing EPinfo Base Addr */
45606 + dptxfsiz.d32 =
45607 + (DWC_READ_REG32
45608 + (&GET_CORE_IF(pcd)->
45609 + core_global_regs->dtxfsiz[ep->dwc_ep.tx_fifo_num-1]) >> 16);
45610 + gdfifocfg.b.epinfobase = gdfifocfgbase.d32 - dptxfsiz.d32;
45611 + if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) {
45612 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg,
45613 + gdfifocfg.d32);
45614 + }
45615 + }
45616 + }
45617 +
45618 + /* Free DMA Descriptors */
45619 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45620 + if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
45621 + desc_addr = ep->dwc_ep.desc_addr;
45622 + dma_desc_addr = ep->dwc_ep.dma_desc_addr;
45623 +
45624 + /* Cannot call dma_free_coherent() with IRQs disabled */
45625 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45626 + dwc_otg_ep_free_desc_chain(desc_addr, dma_desc_addr,
45627 + MAX_DMA_DESC_CNT);
45628 +
45629 + goto out_unlocked;
45630 + }
45631 + }
45632 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45633 +
45634 +out_unlocked:
45635 + DWC_DEBUGPL(DBG_PCD, "%d %s disabled\n", ep->dwc_ep.num,
45636 + ep->dwc_ep.is_in ? "IN" : "OUT");
45637 + return 0;
45638 +
45639 +}
45640 +
45641 +/******************************************************************************/
45642 +#ifdef DWC_UTE_PER_IO
45643 +
45644 +/**
45645 + * Free the request and its extended parts
45646 + *
45647 + */
45648 +void dwc_pcd_xiso_ereq_free(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req)
45649 +{
45650 + DWC_FREE(req->ext_req.per_io_frame_descs);
45651 + DWC_FREE(req);
45652 +}
45653 +
45654 +/**
45655 + * Start the next request in the endpoint's queue.
45656 + *
45657 + */
45658 +int dwc_otg_pcd_xiso_start_next_request(dwc_otg_pcd_t * pcd,
45659 + dwc_otg_pcd_ep_t * ep)
45660 +{
45661 + int i;
45662 + dwc_otg_pcd_request_t *req = NULL;
45663 + dwc_ep_t *dwcep = NULL;
45664 + struct dwc_iso_xreq_port *ereq = NULL;
45665 + struct dwc_iso_pkt_desc_port *ddesc_iso;
45666 + uint16_t nat;
45667 + depctl_data_t diepctl;
45668 +
45669 + dwcep = &ep->dwc_ep;
45670 +
45671 + if (dwcep->xiso_active_xfers > 0) {
45672 +#if 0 //Disable this to decrease s/w overhead that is crucial for Isoc transfers
45673 + DWC_WARN("There are currently active transfers for EP%d \
45674 + (active=%d; queued=%d)", dwcep->num, dwcep->xiso_active_xfers,
45675 + dwcep->xiso_queued_xfers);
45676 +#endif
45677 + return 0;
45678 + }
45679 +
45680 + nat = UGETW(ep->desc->wMaxPacketSize);
45681 + nat = (nat >> 11) & 0x03;
45682 +
45683 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
45684 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
45685 + ereq = &req->ext_req;
45686 + ep->stopped = 0;
45687 +
45688 + /* Get the frame number */
45689 + dwcep->xiso_frame_num =
45690 + dwc_otg_get_frame_number(GET_CORE_IF(pcd));
45691 + DWC_DEBUG("FRM_NUM=%d", dwcep->xiso_frame_num);
45692 +
45693 + ddesc_iso = ereq->per_io_frame_descs;
45694 +
45695 + if (dwcep->is_in) {
45696 + /* Setup DMA Descriptor chain for IN Isoc request */
45697 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45698 + //if ((i % (nat + 1)) == 0)
45699 + if ( i > 0 )
45700 + dwcep->xiso_frame_num =
45701 + (dwcep->xiso_bInterval +
45702 + dwcep->xiso_frame_num) & 0x3FFF;
45703 + dwcep->desc_addr[i].buf =
45704 + req->dma + ddesc_iso[i].offset;
45705 + dwcep->desc_addr[i].status.b_iso_in.txbytes =
45706 + ddesc_iso[i].length;
45707 + dwcep->desc_addr[i].status.b_iso_in.framenum =
45708 + dwcep->xiso_frame_num;
45709 + dwcep->desc_addr[i].status.b_iso_in.bs =
45710 + BS_HOST_READY;
45711 + dwcep->desc_addr[i].status.b_iso_in.txsts = 0;
45712 + dwcep->desc_addr[i].status.b_iso_in.sp =
45713 + (ddesc_iso[i].length %
45714 + dwcep->maxpacket) ? 1 : 0;
45715 + dwcep->desc_addr[i].status.b_iso_in.ioc = 0;
45716 + dwcep->desc_addr[i].status.b_iso_in.pid = nat + 1;
45717 + dwcep->desc_addr[i].status.b_iso_in.l = 0;
45718 +
45719 + /* Process the last descriptor */
45720 + if (i == ereq->pio_pkt_count - 1) {
45721 + dwcep->desc_addr[i].status.b_iso_in.ioc = 1;
45722 + dwcep->desc_addr[i].status.b_iso_in.l = 1;
45723 + }
45724 + }
45725 +
45726 + /* Setup and start the transfer for this endpoint */
45727 + dwcep->xiso_active_xfers++;
45728 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->dev_if->
45729 + in_ep_regs[dwcep->num]->diepdma,
45730 + dwcep->dma_desc_addr);
45731 + diepctl.d32 = 0;
45732 + diepctl.b.epena = 1;
45733 + diepctl.b.cnak = 1;
45734 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if->
45735 + in_ep_regs[dwcep->num]->diepctl, 0,
45736 + diepctl.d32);
45737 + } else {
45738 + /* Setup DMA Descriptor chain for OUT Isoc request */
45739 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45740 + //if ((i % (nat + 1)) == 0)
45741 + dwcep->xiso_frame_num = (dwcep->xiso_bInterval +
45742 + dwcep->xiso_frame_num) & 0x3FFF;
45743 + dwcep->desc_addr[i].buf =
45744 + req->dma + ddesc_iso[i].offset;
45745 + dwcep->desc_addr[i].status.b_iso_out.rxbytes =
45746 + ddesc_iso[i].length;
45747 + dwcep->desc_addr[i].status.b_iso_out.framenum =
45748 + dwcep->xiso_frame_num;
45749 + dwcep->desc_addr[i].status.b_iso_out.bs =
45750 + BS_HOST_READY;
45751 + dwcep->desc_addr[i].status.b_iso_out.rxsts = 0;
45752 + dwcep->desc_addr[i].status.b_iso_out.sp =
45753 + (ddesc_iso[i].length %
45754 + dwcep->maxpacket) ? 1 : 0;
45755 + dwcep->desc_addr[i].status.b_iso_out.ioc = 0;
45756 + dwcep->desc_addr[i].status.b_iso_out.pid = nat + 1;
45757 + dwcep->desc_addr[i].status.b_iso_out.l = 0;
45758 +
45759 + /* Process the last descriptor */
45760 + if (i == ereq->pio_pkt_count - 1) {
45761 + dwcep->desc_addr[i].status.b_iso_out.ioc = 1;
45762 + dwcep->desc_addr[i].status.b_iso_out.l = 1;
45763 + }
45764 + }
45765 +
45766 + /* Setup and start the transfer for this endpoint */
45767 + dwcep->xiso_active_xfers++;
45768 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
45769 + dev_if->out_ep_regs[dwcep->num]->
45770 + doepdma, dwcep->dma_desc_addr);
45771 + diepctl.d32 = 0;
45772 + diepctl.b.epena = 1;
45773 + diepctl.b.cnak = 1;
45774 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
45775 + dev_if->out_ep_regs[dwcep->num]->
45776 + doepctl, 0, diepctl.d32);
45777 + }
45778 +
45779 + } else {
45780 + ep->stopped = 1;
45781 + }
45782 +
45783 + return 0;
45784 +}
45785 +
45786 +/**
45787 + * - Remove the request from the queue
45788 + */
45789 +void complete_xiso_ep(dwc_otg_pcd_ep_t * ep)
45790 +{
45791 + dwc_otg_pcd_request_t *req = NULL;
45792 + struct dwc_iso_xreq_port *ereq = NULL;
45793 + struct dwc_iso_pkt_desc_port *ddesc_iso = NULL;
45794 + dwc_ep_t *dwcep = NULL;
45795 + int i;
45796 +
45797 + //DWC_DEBUG();
45798 + dwcep = &ep->dwc_ep;
45799 +
45800 + /* Get the first pending request from the queue */
45801 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
45802 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
45803 + if (!req) {
45804 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
45805 + return;
45806 + }
45807 + dwcep->xiso_active_xfers--;
45808 + dwcep->xiso_queued_xfers--;
45809 + /* Remove this request from the queue */
45810 + DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
45811 + } else {
45812 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
45813 + return;
45814 + }
45815 +
45816 + ep->stopped = 1;
45817 + ereq = &req->ext_req;
45818 + ddesc_iso = ereq->per_io_frame_descs;
45819 +
45820 + if (dwcep->xiso_active_xfers < 0) {
45821 + DWC_WARN("EP#%d (xiso_active_xfers=%d)", dwcep->num,
45822 + dwcep->xiso_active_xfers);
45823 + }
45824 +
45825 + /* Fill the Isoc descs of portable extended req from dma descriptors */
45826 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45827 + if (dwcep->is_in) { /* IN endpoints */
45828 + ddesc_iso[i].actual_length = ddesc_iso[i].length -
45829 + dwcep->desc_addr[i].status.b_iso_in.txbytes;
45830 + ddesc_iso[i].status =
45831 + dwcep->desc_addr[i].status.b_iso_in.txsts;
45832 + } else { /* OUT endpoints */
45833 + ddesc_iso[i].actual_length = ddesc_iso[i].length -
45834 + dwcep->desc_addr[i].status.b_iso_out.rxbytes;
45835 + ddesc_iso[i].status =
45836 + dwcep->desc_addr[i].status.b_iso_out.rxsts;
45837 + }
45838 + }
45839 +
45840 + DWC_SPINUNLOCK(ep->pcd->lock);
45841 +
45842 + /* Call the completion function in the non-portable logic */
45843 + ep->pcd->fops->xisoc_complete(ep->pcd, ep->priv, req->priv, 0,
45844 + &req->ext_req);
45845 +
45846 + DWC_SPINLOCK(ep->pcd->lock);
45847 +
45848 + /* Free the request - specific freeing needed for extended request object */
45849 + dwc_pcd_xiso_ereq_free(ep, req);
45850 +
45851 + /* Start the next request */
45852 + dwc_otg_pcd_xiso_start_next_request(ep->pcd, ep);
45853 +
45854 + return;
45855 +}
45856 +
45857 +/**
45858 + * Create and initialize the Isoc pkt descriptors of the extended request.
45859 + *
45860 + */
45861 +static int dwc_otg_pcd_xiso_create_pkt_descs(dwc_otg_pcd_request_t * req,
45862 + void *ereq_nonport,
45863 + int atomic_alloc)
45864 +{
45865 + struct dwc_iso_xreq_port *ereq = NULL;
45866 + struct dwc_iso_xreq_port *req_mapped = NULL;
45867 + struct dwc_iso_pkt_desc_port *ipds = NULL; /* To be created in this function */
45868 + uint32_t pkt_count;
45869 + int i;
45870 +
45871 + ereq = &req->ext_req;
45872 + req_mapped = (struct dwc_iso_xreq_port *)ereq_nonport;
45873 + pkt_count = req_mapped->pio_pkt_count;
45874 +
45875 + /* Create the isoc descs */
45876 + if (atomic_alloc) {
45877 + ipds = DWC_ALLOC_ATOMIC(sizeof(*ipds) * pkt_count);
45878 + } else {
45879 + ipds = DWC_ALLOC(sizeof(*ipds) * pkt_count);
45880 + }
45881 +
45882 + if (!ipds) {
45883 + DWC_ERROR("Failed to allocate isoc descriptors");
45884 + return -DWC_E_NO_MEMORY;
45885 + }
45886 +
45887 + /* Initialize the extended request fields */
45888 + ereq->per_io_frame_descs = ipds;
45889 + ereq->error_count = 0;
45890 + ereq->pio_alloc_pkt_count = pkt_count;
45891 + ereq->pio_pkt_count = pkt_count;
45892 + ereq->tr_sub_flags = req_mapped->tr_sub_flags;
45893 +
45894 + /* Init the Isoc descriptors */
45895 + for (i = 0; i < pkt_count; i++) {
45896 + ipds[i].length = req_mapped->per_io_frame_descs[i].length;
45897 + ipds[i].offset = req_mapped->per_io_frame_descs[i].offset;
45898 + ipds[i].status = req_mapped->per_io_frame_descs[i].status; /* 0 */
45899 + ipds[i].actual_length =
45900 + req_mapped->per_io_frame_descs[i].actual_length;
45901 + }
45902 +
45903 + return 0;
45904 +}
45905 +
45906 +static void prn_ext_request(struct dwc_iso_xreq_port *ereq)
45907 +{
45908 + struct dwc_iso_pkt_desc_port *xfd = NULL;
45909 + int i;
45910 +
45911 + DWC_DEBUG("per_io_frame_descs=%p", ereq->per_io_frame_descs);
45912 + DWC_DEBUG("tr_sub_flags=%d", ereq->tr_sub_flags);
45913 + DWC_DEBUG("error_count=%d", ereq->error_count);
45914 + DWC_DEBUG("pio_alloc_pkt_count=%d", ereq->pio_alloc_pkt_count);
45915 + DWC_DEBUG("pio_pkt_count=%d", ereq->pio_pkt_count);
45916 + DWC_DEBUG("res=%d", ereq->res);
45917 +
45918 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45919 + xfd = &ereq->per_io_frame_descs[0];
45920 + DWC_DEBUG("FD #%d", i);
45921 +
45922 + DWC_DEBUG("xfd->actual_length=%d", xfd->actual_length);
45923 + DWC_DEBUG("xfd->length=%d", xfd->length);
45924 + DWC_DEBUG("xfd->offset=%d", xfd->offset);
45925 + DWC_DEBUG("xfd->status=%d", xfd->status);
45926 + }
45927 +}
45928 +
45929 +/**
45930 + *
45931 + */
45932 +int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
45933 + uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
45934 + int zero, void *req_handle, int atomic_alloc,
45935 + void *ereq_nonport)
45936 +{
45937 + dwc_otg_pcd_request_t *req = NULL;
45938 + dwc_otg_pcd_ep_t *ep;
45939 + dwc_irqflags_t flags;
45940 + int res;
45941 +
45942 + ep = get_ep_from_handle(pcd, ep_handle);
45943 + if (!ep) {
45944 + DWC_WARN("bad ep\n");
45945 + return -DWC_E_INVALID;
45946 + }
45947 +
45948 + /* We support this extension only for DDMA mode */
45949 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
45950 + if (!GET_CORE_IF(pcd)->dma_desc_enable)
45951 + return -DWC_E_INVALID;
45952 +
45953 + /* Create a dwc_otg_pcd_request_t object */
45954 + if (atomic_alloc) {
45955 + req = DWC_ALLOC_ATOMIC(sizeof(*req));
45956 + } else {
45957 + req = DWC_ALLOC(sizeof(*req));
45958 + }
45959 +
45960 + if (!req) {
45961 + return -DWC_E_NO_MEMORY;
45962 + }
45963 +
45964 + /* Create the Isoc descs for this request which shall be the exact match
45965 + * of the structure sent to us from the non-portable logic */
45966 + res =
45967 + dwc_otg_pcd_xiso_create_pkt_descs(req, ereq_nonport, atomic_alloc);
45968 + if (res) {
45969 + DWC_WARN("Failed to init the Isoc descriptors");
45970 + DWC_FREE(req);
45971 + return res;
45972 + }
45973 +
45974 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45975 +
45976 + DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
45977 + req->buf = buf;
45978 + req->dma = dma_buf;
45979 + req->length = buflen;
45980 + req->sent_zlp = zero;
45981 + req->priv = req_handle;
45982 +
45983 + //DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45984 + ep->dwc_ep.dma_addr = dma_buf;
45985 + ep->dwc_ep.start_xfer_buff = buf;
45986 + ep->dwc_ep.xfer_buff = buf;
45987 + ep->dwc_ep.xfer_len = 0;
45988 + ep->dwc_ep.xfer_count = 0;
45989 + ep->dwc_ep.sent_zlp = 0;
45990 + ep->dwc_ep.total_len = buflen;
45991 +
45992 + /* Add this request to the tail */
45993 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
45994 + ep->dwc_ep.xiso_queued_xfers++;
45995 +
45996 +//DWC_DEBUG("CP_0");
45997 +//DWC_DEBUG("req->ext_req.tr_sub_flags=%d", req->ext_req.tr_sub_flags);
45998 +//prn_ext_request((struct dwc_iso_xreq_port *) ereq_nonport);
45999 +//prn_ext_request(&req->ext_req);
46000 +
46001 + //DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46002 +
46003 + /* If the req->status == ASAP then check if there is any active transfer
46004 + * for this endpoint. If no active transfers, then get the first entry
46005 + * from the queue and start that transfer
46006 + */
46007 + if (req->ext_req.tr_sub_flags == DWC_EREQ_TF_ASAP) {
46008 + res = dwc_otg_pcd_xiso_start_next_request(pcd, ep);
46009 + if (res) {
46010 + DWC_WARN("Failed to start the next Isoc transfer");
46011 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46012 + DWC_FREE(req);
46013 + return res;
46014 + }
46015 + }
46016 +
46017 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46018 + return 0;
46019 +}
46020 +
46021 +#endif
46022 +/* END ifdef DWC_UTE_PER_IO ***************************************************/
46023 +int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
46024 + uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
46025 + int zero, void *req_handle, int atomic_alloc)
46026 +{
46027 + dwc_irqflags_t flags;
46028 + dwc_otg_pcd_request_t *req;
46029 + dwc_otg_pcd_ep_t *ep;
46030 + uint32_t max_transfer;
46031 +
46032 + ep = get_ep_from_handle(pcd, ep_handle);
46033 + if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
46034 + DWC_WARN("bad ep\n");
46035 + return -DWC_E_INVALID;
46036 + }
46037 +
46038 + if (atomic_alloc) {
46039 + req = DWC_ALLOC_ATOMIC(sizeof(*req));
46040 + } else {
46041 + req = DWC_ALLOC(sizeof(*req));
46042 + }
46043 +
46044 + if (!req) {
46045 + return -DWC_E_NO_MEMORY;
46046 + }
46047 + DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
46048 + if (!GET_CORE_IF(pcd)->core_params->opt) {
46049 + if (ep->dwc_ep.num != 0) {
46050 + DWC_ERROR("queue req %p, len %d buf %p\n",
46051 + req_handle, buflen, buf);
46052 + }
46053 + }
46054 +
46055 + req->buf = buf;
46056 + req->dma = dma_buf;
46057 + req->length = buflen;
46058 + req->sent_zlp = zero;
46059 + req->priv = req_handle;
46060 + req->dw_align_buf = NULL;
46061 + if ((dma_buf & 0x3) && GET_CORE_IF(pcd)->dma_enable
46062 + && !GET_CORE_IF(pcd)->dma_desc_enable)
46063 + req->dw_align_buf = DWC_DMA_ALLOC(buflen,
46064 + &req->dw_align_buf_dma);
46065 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46066 +
46067 + /*
46068 + * After adding request to the queue for IN ISOC wait for In Token Received
46069 + * when TX FIFO is empty interrupt and for OUT ISOC wait for OUT Token
46070 + * Received when EP is disabled interrupt to obtain starting microframe
46071 + * (odd/even) start transfer
46072 + */
46073 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
46074 + if (req != 0) {
46075 + depctl_data_t depctl = {.d32 =
46076 + DWC_READ_REG32(&pcd->core_if->dev_if->
46077 + in_ep_regs[ep->dwc_ep.num]->
46078 + diepctl) };
46079 + ++pcd->request_pending;
46080 +
46081 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
46082 + if (ep->dwc_ep.is_in) {
46083 + depctl.b.cnak = 1;
46084 + DWC_WRITE_REG32(&pcd->core_if->dev_if->
46085 + in_ep_regs[ep->dwc_ep.num]->
46086 + diepctl, depctl.d32);
46087 + }
46088 +
46089 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46090 + }
46091 + return 0;
46092 + }
46093 +
46094 + /*
46095 + * For EP0 IN without premature status, zlp is required?
46096 + */
46097 + if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) {
46098 + DWC_DEBUGPL(DBG_PCDV, "%d-OUT ZLP\n", ep->dwc_ep.num);
46099 + //_req->zero = 1;
46100 + }
46101 +
46102 + /* Start the transfer */
46103 + if (DWC_CIRCLEQ_EMPTY(&ep->queue) && !ep->stopped) {
46104 + /* EP0 Transfer? */
46105 + if (ep->dwc_ep.num == 0) {
46106 + switch (pcd->ep0state) {
46107 + case EP0_IN_DATA_PHASE:
46108 + DWC_DEBUGPL(DBG_PCD,
46109 + "%s ep0: EP0_IN_DATA_PHASE\n",
46110 + __func__);
46111 + break;
46112 +
46113 + case EP0_OUT_DATA_PHASE:
46114 + DWC_DEBUGPL(DBG_PCD,
46115 + "%s ep0: EP0_OUT_DATA_PHASE\n",
46116 + __func__);
46117 + if (pcd->request_config) {
46118 + /* Complete STATUS PHASE */
46119 + ep->dwc_ep.is_in = 1;
46120 + pcd->ep0state = EP0_IN_STATUS_PHASE;
46121 + }
46122 + break;
46123 +
46124 + case EP0_IN_STATUS_PHASE:
46125 + DWC_DEBUGPL(DBG_PCD,
46126 + "%s ep0: EP0_IN_STATUS_PHASE\n",
46127 + __func__);
46128 + break;
46129 +
46130 + default:
46131 + DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n",
46132 + pcd->ep0state);
46133 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46134 + return -DWC_E_SHUTDOWN;
46135 + }
46136 +
46137 + ep->dwc_ep.dma_addr = dma_buf;
46138 + ep->dwc_ep.start_xfer_buff = buf;
46139 + ep->dwc_ep.xfer_buff = buf;
46140 + ep->dwc_ep.xfer_len = buflen;
46141 + ep->dwc_ep.xfer_count = 0;
46142 + ep->dwc_ep.sent_zlp = 0;
46143 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
46144 +
46145 + if (zero) {
46146 + if ((ep->dwc_ep.xfer_len %
46147 + ep->dwc_ep.maxpacket == 0)
46148 + && (ep->dwc_ep.xfer_len != 0)) {
46149 + ep->dwc_ep.sent_zlp = 1;
46150 + }
46151 +
46152 + }
46153 +
46154 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
46155 + &ep->dwc_ep);
46156 + } // non-ep0 endpoints
46157 + else {
46158 +#ifdef DWC_UTE_CFI
46159 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
46160 + /* store the request length */
46161 + ep->dwc_ep.cfi_req_len = buflen;
46162 + pcd->cfi->ops.build_descriptors(pcd->cfi, pcd,
46163 + ep, req);
46164 + } else {
46165 +#endif
46166 + max_transfer =
46167 + GET_CORE_IF(ep->pcd)->core_params->
46168 + max_transfer_size;
46169 +
46170 + /* Setup and start the Transfer */
46171 + if (req->dw_align_buf){
46172 + if (ep->dwc_ep.is_in)
46173 + dwc_memcpy(req->dw_align_buf,
46174 + buf, buflen);
46175 + ep->dwc_ep.dma_addr =
46176 + req->dw_align_buf_dma;
46177 + ep->dwc_ep.start_xfer_buff =
46178 + req->dw_align_buf;
46179 + ep->dwc_ep.xfer_buff =
46180 + req->dw_align_buf;
46181 + } else {
46182 + ep->dwc_ep.dma_addr = dma_buf;
46183 + ep->dwc_ep.start_xfer_buff = buf;
46184 + ep->dwc_ep.xfer_buff = buf;
46185 + }
46186 + ep->dwc_ep.xfer_len = 0;
46187 + ep->dwc_ep.xfer_count = 0;
46188 + ep->dwc_ep.sent_zlp = 0;
46189 + ep->dwc_ep.total_len = buflen;
46190 +
46191 + ep->dwc_ep.maxxfer = max_transfer;
46192 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
46193 + uint32_t out_max_xfer =
46194 + DDMA_MAX_TRANSFER_SIZE -
46195 + (DDMA_MAX_TRANSFER_SIZE % 4);
46196 + if (ep->dwc_ep.is_in) {
46197 + if (ep->dwc_ep.maxxfer >
46198 + DDMA_MAX_TRANSFER_SIZE) {
46199 + ep->dwc_ep.maxxfer =
46200 + DDMA_MAX_TRANSFER_SIZE;
46201 + }
46202 + } else {
46203 + if (ep->dwc_ep.maxxfer >
46204 + out_max_xfer) {
46205 + ep->dwc_ep.maxxfer =
46206 + out_max_xfer;
46207 + }
46208 + }
46209 + }
46210 + if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
46211 + ep->dwc_ep.maxxfer -=
46212 + (ep->dwc_ep.maxxfer %
46213 + ep->dwc_ep.maxpacket);
46214 + }
46215 +
46216 + if (zero) {
46217 + if ((ep->dwc_ep.total_len %
46218 + ep->dwc_ep.maxpacket == 0)
46219 + && (ep->dwc_ep.total_len != 0)) {
46220 + ep->dwc_ep.sent_zlp = 1;
46221 + }
46222 + }
46223 +#ifdef DWC_UTE_CFI
46224 + }
46225 +#endif
46226 + dwc_otg_ep_start_transfer(GET_CORE_IF(pcd),
46227 + &ep->dwc_ep);
46228 + }
46229 + }
46230 +
46231 + if (req != 0) {
46232 + ++pcd->request_pending;
46233 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
46234 + if (ep->dwc_ep.is_in && ep->stopped
46235 + && !(GET_CORE_IF(pcd)->dma_enable)) {
46236 + /** @todo NGS Create a function for this. */
46237 + diepmsk_data_t diepmsk = {.d32 = 0 };
46238 + diepmsk.b.intktxfemp = 1;
46239 + if (GET_CORE_IF(pcd)->multiproc_int_enable) {
46240 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
46241 + dev_if->dev_global_regs->diepeachintmsk
46242 + [ep->dwc_ep.num], 0,
46243 + diepmsk.d32);
46244 + } else {
46245 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
46246 + dev_if->dev_global_regs->
46247 + diepmsk, 0, diepmsk.d32);
46248 + }
46249 +
46250 + }
46251 + }
46252 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46253 +
46254 + return 0;
46255 +}
46256 +
46257 +int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
46258 + void *req_handle)
46259 +{
46260 + dwc_irqflags_t flags;
46261 + dwc_otg_pcd_request_t *req;
46262 + dwc_otg_pcd_ep_t *ep;
46263 +
46264 + ep = get_ep_from_handle(pcd, ep_handle);
46265 + if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
46266 + DWC_WARN("bad argument\n");
46267 + return -DWC_E_INVALID;
46268 + }
46269 +
46270 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46271 +
46272 + /* make sure it's actually queued on this endpoint */
46273 + DWC_CIRCLEQ_FOREACH(req, &ep->queue, queue_entry) {
46274 + if (req->priv == (void *)req_handle) {
46275 + break;
46276 + }
46277 + }
46278 +
46279 + if (req->priv != (void *)req_handle) {
46280 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46281 + return -DWC_E_INVALID;
46282 + }
46283 +
46284 + if (!DWC_CIRCLEQ_EMPTY_ENTRY(req, queue_entry)) {
46285 + dwc_otg_request_done(ep, req, -DWC_E_RESTART);
46286 + } else {
46287 + req = NULL;
46288 + }
46289 +
46290 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46291 +
46292 + return req ? 0 : -DWC_E_SHUTDOWN;
46293 +
46294 +}
46295 +
46296 +/**
46297 + * dwc_otg_pcd_ep_wedge - sets the halt feature and ignores clear requests
46298 + *
46299 + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
46300 + * requests. If the gadget driver clears the halt status, it will
46301 + * automatically unwedge the endpoint.
46302 + *
46303 + * Returns zero on success, else negative DWC error code.
46304 + */
46305 +int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle)
46306 +{
46307 + dwc_otg_pcd_ep_t *ep;
46308 + dwc_irqflags_t flags;
46309 + int retval = 0;
46310 +
46311 + ep = get_ep_from_handle(pcd, ep_handle);
46312 +
46313 + if ((!ep->desc && ep != &pcd->ep0) ||
46314 + (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
46315 + DWC_WARN("%s, bad ep\n", __func__);
46316 + return -DWC_E_INVALID;
46317 + }
46318 +
46319 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46320 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
46321 + DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
46322 + ep->dwc_ep.is_in ? "IN" : "OUT");
46323 + retval = -DWC_E_AGAIN;
46324 + } else {
46325 + /* This code needs to be reviewed */
46326 + if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
46327 + dtxfsts_data_t txstatus;
46328 + fifosize_data_t txfifosize;
46329 +
46330 + txfifosize.d32 =
46331 + DWC_READ_REG32(&GET_CORE_IF(pcd)->
46332 + core_global_regs->dtxfsiz[ep->dwc_ep.
46333 + tx_fifo_num]);
46334 + txstatus.d32 =
46335 + DWC_READ_REG32(&GET_CORE_IF(pcd)->
46336 + dev_if->in_ep_regs[ep->dwc_ep.num]->
46337 + dtxfsts);
46338 +
46339 + if (txstatus.b.txfspcavail < txfifosize.b.depth) {
46340 + DWC_WARN("%s() Data In Tx Fifo\n", __func__);
46341 + retval = -DWC_E_AGAIN;
46342 + } else {
46343 + if (ep->dwc_ep.num == 0) {
46344 + pcd->ep0state = EP0_STALL;
46345 + }
46346 +
46347 + ep->stopped = 1;
46348 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
46349 + &ep->dwc_ep);
46350 + }
46351 + } else {
46352 + if (ep->dwc_ep.num == 0) {
46353 + pcd->ep0state = EP0_STALL;
46354 + }
46355 +
46356 + ep->stopped = 1;
46357 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
46358 + }
46359 + }
46360 +
46361 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46362 +
46363 + return retval;
46364 +}
46365 +
46366 +int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value)
46367 +{
46368 + dwc_otg_pcd_ep_t *ep;
46369 + dwc_irqflags_t flags;
46370 + int retval = 0;
46371 +
46372 + ep = get_ep_from_handle(pcd, ep_handle);
46373 +
46374 + if (!ep || (!ep->desc && ep != &pcd->ep0) ||
46375 + (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
46376 + DWC_WARN("%s, bad ep\n", __func__);
46377 + return -DWC_E_INVALID;
46378 + }
46379 +
46380 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46381 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
46382 + DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
46383 + ep->dwc_ep.is_in ? "IN" : "OUT");
46384 + retval = -DWC_E_AGAIN;
46385 + } else if (value == 0) {
46386 + dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
46387 + } else if (value == 1) {
46388 + if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
46389 + dtxfsts_data_t txstatus;
46390 + fifosize_data_t txfifosize;
46391 +
46392 + txfifosize.d32 =
46393 + DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->
46394 + dtxfsiz[ep->dwc_ep.tx_fifo_num]);
46395 + txstatus.d32 =
46396 + DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
46397 + in_ep_regs[ep->dwc_ep.num]->dtxfsts);
46398 +
46399 + if (txstatus.b.txfspcavail < txfifosize.b.depth) {
46400 + DWC_WARN("%s() Data In Tx Fifo\n", __func__);
46401 + retval = -DWC_E_AGAIN;
46402 + } else {
46403 + if (ep->dwc_ep.num == 0) {
46404 + pcd->ep0state = EP0_STALL;
46405 + }
46406 +
46407 + ep->stopped = 1;
46408 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
46409 + &ep->dwc_ep);
46410 + }
46411 + } else {
46412 + if (ep->dwc_ep.num == 0) {
46413 + pcd->ep0state = EP0_STALL;
46414 + }
46415 +
46416 + ep->stopped = 1;
46417 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
46418 + }
46419 + } else if (value == 2) {
46420 + ep->dwc_ep.stall_clear_flag = 0;
46421 + } else if (value == 3) {
46422 + ep->dwc_ep.stall_clear_flag = 1;
46423 + }
46424 +
46425 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46426 +
46427 + return retval;
46428 +}
46429 +
46430 +/**
46431 + * This function initiates remote wakeup of the host from suspend state.
46432 + */
46433 +void dwc_otg_pcd_rem_wkup_from_suspend(dwc_otg_pcd_t * pcd, int set)
46434 +{
46435 + dctl_data_t dctl = { 0 };
46436 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46437 + dsts_data_t dsts;
46438 +
46439 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
46440 + if (!dsts.b.suspsts) {
46441 + DWC_WARN("Remote wakeup while is not in suspend state\n");
46442 + }
46443 + /* Check if DEVICE_REMOTE_WAKEUP feature enabled */
46444 + if (pcd->remote_wakeup_enable) {
46445 + if (set) {
46446 +
46447 + if (core_if->adp_enable) {
46448 + gpwrdn_data_t gpwrdn;
46449 +
46450 + dwc_otg_adp_probe_stop(core_if);
46451 +
46452 + /* Mask SRP detected interrupt from Power Down Logic */
46453 + gpwrdn.d32 = 0;
46454 + gpwrdn.b.srp_det_msk = 1;
46455 + DWC_MODIFY_REG32(&core_if->
46456 + core_global_regs->gpwrdn,
46457 + gpwrdn.d32, 0);
46458 +
46459 + /* Disable Power Down Logic */
46460 + gpwrdn.d32 = 0;
46461 + gpwrdn.b.pmuactv = 1;
46462 + DWC_MODIFY_REG32(&core_if->
46463 + core_global_regs->gpwrdn,
46464 + gpwrdn.d32, 0);
46465 +
46466 + /*
46467 + * Initialize the Core for Device mode.
46468 + */
46469 + core_if->op_state = B_PERIPHERAL;
46470 + dwc_otg_core_init(core_if);
46471 + dwc_otg_enable_global_interrupts(core_if);
46472 + cil_pcd_start(core_if);
46473 +
46474 + dwc_otg_initiate_srp(core_if);
46475 + }
46476 +
46477 + dctl.b.rmtwkupsig = 1;
46478 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
46479 + dctl, 0, dctl.d32);
46480 + DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
46481 +
46482 + dwc_mdelay(2);
46483 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
46484 + dctl, dctl.d32, 0);
46485 + DWC_DEBUGPL(DBG_PCD, "Clear Remote Wakeup\n");
46486 + }
46487 + } else {
46488 + DWC_DEBUGPL(DBG_PCD, "Remote Wakeup is disabled\n");
46489 + }
46490 +}
46491 +
46492 +#ifdef CONFIG_USB_DWC_OTG_LPM
46493 +/**
46494 + * This function initiates remote wakeup of the host from L1 sleep state.
46495 + */
46496 +void dwc_otg_pcd_rem_wkup_from_sleep(dwc_otg_pcd_t * pcd, int set)
46497 +{
46498 + glpmcfg_data_t lpmcfg;
46499 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46500 +
46501 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
46502 +
46503 + /* Check if we are in L1 state */
46504 + if (!lpmcfg.b.prt_sleep_sts) {
46505 + DWC_DEBUGPL(DBG_PCD, "Device is not in sleep state\n");
46506 + return;
46507 + }
46508 +
46509 + /* Check if host allows remote wakeup */
46510 + if (!lpmcfg.b.rem_wkup_en) {
46511 + DWC_DEBUGPL(DBG_PCD, "Host does not allow remote wakeup\n");
46512 + return;
46513 + }
46514 +
46515 + /* Check if Resume OK */
46516 + if (!lpmcfg.b.sleep_state_resumeok) {
46517 + DWC_DEBUGPL(DBG_PCD, "Sleep state resume is not OK\n");
46518 + return;
46519 + }
46520 +
46521 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
46522 + lpmcfg.b.en_utmi_sleep = 0;
46523 + lpmcfg.b.hird_thres &= (~(1 << 4));
46524 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
46525 +
46526 + if (set) {
46527 + dctl_data_t dctl = {.d32 = 0 };
46528 + dctl.b.rmtwkupsig = 1;
46529 + /* Set RmtWkUpSig bit to start remote wakup signaling.
46530 + * Hardware will automatically clear this bit.
46531 + */
46532 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl,
46533 + 0, dctl.d32);
46534 + DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
46535 + }
46536 +
46537 +}
46538 +#endif
46539 +
46540 +/**
46541 + * Performs remote wakeup.
46542 + */
46543 +void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set)
46544 +{
46545 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46546 + dwc_irqflags_t flags;
46547 + if (dwc_otg_is_device_mode(core_if)) {
46548 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46549 +#ifdef CONFIG_USB_DWC_OTG_LPM
46550 + if (core_if->lx_state == DWC_OTG_L1) {
46551 + dwc_otg_pcd_rem_wkup_from_sleep(pcd, set);
46552 + } else {
46553 +#endif
46554 + dwc_otg_pcd_rem_wkup_from_suspend(pcd, set);
46555 +#ifdef CONFIG_USB_DWC_OTG_LPM
46556 + }
46557 +#endif
46558 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46559 + }
46560 + return;
46561 +}
46562 +
46563 +void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs)
46564 +{
46565 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46566 + dctl_data_t dctl = { 0 };
46567 +
46568 + if (dwc_otg_is_device_mode(core_if)) {
46569 + dctl.b.sftdiscon = 1;
46570 + DWC_PRINTF("Soft disconnect for %d useconds\n",no_of_usecs);
46571 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
46572 + dwc_udelay(no_of_usecs);
46573 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32,0);
46574 +
46575 + } else{
46576 + DWC_PRINTF("NOT SUPPORTED IN HOST MODE\n");
46577 + }
46578 + return;
46579 +
46580 +}
46581 +
46582 +int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd)
46583 +{
46584 + dsts_data_t dsts;
46585 + gotgctl_data_t gotgctl;
46586 +
46587 + /*
46588 + * This function starts the Protocol if no session is in progress. If
46589 + * a session is already in progress, but the device is suspended,
46590 + * remote wakeup signaling is started.
46591 + */
46592 +
46593 + /* Check if valid session */
46594 + gotgctl.d32 =
46595 + DWC_READ_REG32(&(GET_CORE_IF(pcd)->core_global_regs->gotgctl));
46596 + if (gotgctl.b.bsesvld) {
46597 + /* Check if suspend state */
46598 + dsts.d32 =
46599 + DWC_READ_REG32(&
46600 + (GET_CORE_IF(pcd)->dev_if->
46601 + dev_global_regs->dsts));
46602 + if (dsts.b.suspsts) {
46603 + dwc_otg_pcd_remote_wakeup(pcd, 1);
46604 + }
46605 + } else {
46606 + dwc_otg_pcd_initiate_srp(pcd);
46607 + }
46608 +
46609 + return 0;
46610 +
46611 +}
46612 +
46613 +/**
46614 + * Start the SRP timer to detect when the SRP does not complete within
46615 + * 6 seconds.
46616 + *
46617 + * @param pcd the pcd structure.
46618 + */
46619 +void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd)
46620 +{
46621 + dwc_irqflags_t flags;
46622 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46623 + dwc_otg_initiate_srp(GET_CORE_IF(pcd));
46624 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46625 +}
46626 +
46627 +int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd)
46628 +{
46629 + return dwc_otg_get_frame_number(GET_CORE_IF(pcd));
46630 +}
46631 +
46632 +int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd)
46633 +{
46634 + return GET_CORE_IF(pcd)->core_params->lpm_enable;
46635 +}
46636 +
46637 +uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd)
46638 +{
46639 + return pcd->b_hnp_enable;
46640 +}
46641 +
46642 +uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd)
46643 +{
46644 + return pcd->a_hnp_support;
46645 +}
46646 +
46647 +uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd)
46648 +{
46649 + return pcd->a_alt_hnp_support;
46650 +}
46651 +
46652 +int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd)
46653 +{
46654 + return pcd->remote_wakeup_enable;
46655 +}
46656 +
46657 +#endif /* DWC_HOST_ONLY */
46658 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd.h b/drivers/usb/host/dwc_otg/dwc_otg_pcd.h
46659 new file mode 100644
46660 index 0000000..8ef7ba6
46661 --- /dev/null
46662 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd.h
46663 @@ -0,0 +1,266 @@
46664 +/* ==========================================================================
46665 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.h $
46666 + * $Revision: #48 $
46667 + * $Date: 2012/08/10 $
46668 + * $Change: 2047372 $
46669 + *
46670 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
46671 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
46672 + * otherwise expressly agreed to in writing between Synopsys and you.
46673 + *
46674 + * The Software IS NOT an item of Licensed Software or Licensed Product under
46675 + * any End User Software License Agreement or Agreement for Licensed Product
46676 + * with Synopsys or any supplement thereto. You are permitted to use and
46677 + * redistribute this Software in source and binary forms, with or without
46678 + * modification, provided that redistributions of source code must retain this
46679 + * notice. You may not view, use, disclose, copy or distribute this file or
46680 + * any information contained herein except pursuant to this license grant from
46681 + * Synopsys. If you do not agree with this notice, including the disclaimer
46682 + * below, then you are not authorized to use the Software.
46683 + *
46684 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
46685 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46686 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46687 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
46688 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46689 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
46690 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
46691 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46692 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46693 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
46694 + * DAMAGE.
46695 + * ========================================================================== */
46696 +#ifndef DWC_HOST_ONLY
46697 +#if !defined(__DWC_PCD_H__)
46698 +#define __DWC_PCD_H__
46699 +
46700 +#include "dwc_otg_os_dep.h"
46701 +#include "usb.h"
46702 +#include "dwc_otg_cil.h"
46703 +#include "dwc_otg_pcd_if.h"
46704 +struct cfiobject;
46705 +
46706 +/**
46707 + * @file
46708 + *
46709 + * This file contains the structures, constants, and interfaces for
46710 + * the Perpherial Contoller Driver (PCD).
46711 + *
46712 + * The Peripheral Controller Driver (PCD) for Linux will implement the
46713 + * Gadget API, so that the existing Gadget drivers can be used. For
46714 + * the Mass Storage Function driver the File-backed USB Storage Gadget
46715 + * (FBS) driver will be used. The FBS driver supports the
46716 + * Control-Bulk (CB), Control-Bulk-Interrupt (CBI), and Bulk-Only
46717 + * transports.
46718 + *
46719 + */
46720 +
46721 +/** Invalid DMA Address */
46722 +#define DWC_DMA_ADDR_INVALID (~(dwc_dma_t)0)
46723 +
46724 +/** Max Transfer size for any EP */
46725 +#define DDMA_MAX_TRANSFER_SIZE 65535
46726 +
46727 +/**
46728 + * Get the pointer to the core_if from the pcd pointer.
46729 + */
46730 +#define GET_CORE_IF( _pcd ) (_pcd->core_if)
46731 +
46732 +/**
46733 + * States of EP0.
46734 + */
46735 +typedef enum ep0_state {
46736 + EP0_DISCONNECT, /* no host */
46737 + EP0_IDLE,
46738 + EP0_IN_DATA_PHASE,
46739 + EP0_OUT_DATA_PHASE,
46740 + EP0_IN_STATUS_PHASE,
46741 + EP0_OUT_STATUS_PHASE,
46742 + EP0_STALL,
46743 +} ep0state_e;
46744 +
46745 +/** Fordward declaration.*/
46746 +struct dwc_otg_pcd;
46747 +
46748 +/** DWC_otg iso request structure.
46749 + *
46750 + */
46751 +typedef struct usb_iso_request dwc_otg_pcd_iso_request_t;
46752 +
46753 +#ifdef DWC_UTE_PER_IO
46754 +
46755 +/**
46756 + * This shall be the exact analogy of the same type structure defined in the
46757 + * usb_gadget.h. Each descriptor contains
46758 + */
46759 +struct dwc_iso_pkt_desc_port {
46760 + uint32_t offset;
46761 + uint32_t length; /* expected length */
46762 + uint32_t actual_length;
46763 + uint32_t status;
46764 +};
46765 +
46766 +struct dwc_iso_xreq_port {
46767 + /** transfer/submission flag */
46768 + uint32_t tr_sub_flags;
46769 + /** Start the request ASAP */
46770 +#define DWC_EREQ_TF_ASAP 0x00000002
46771 + /** Just enqueue the request w/o initiating a transfer */
46772 +#define DWC_EREQ_TF_ENQUEUE 0x00000004
46773 +
46774 + /**
46775 + * count of ISO packets attached to this request - shall
46776 + * not exceed the pio_alloc_pkt_count
46777 + */
46778 + uint32_t pio_pkt_count;
46779 + /** count of ISO packets allocated for this request */
46780 + uint32_t pio_alloc_pkt_count;
46781 + /** number of ISO packet errors */
46782 + uint32_t error_count;
46783 + /** reserved for future extension */
46784 + uint32_t res;
46785 + /** Will be allocated and freed in the UTE gadget and based on the CFC value */
46786 + struct dwc_iso_pkt_desc_port *per_io_frame_descs;
46787 +};
46788 +#endif
46789 +/** DWC_otg request structure.
46790 + * This structure is a list of requests.
46791 + */
46792 +typedef struct dwc_otg_pcd_request {
46793 + void *priv;
46794 + void *buf;
46795 + dwc_dma_t dma;
46796 + uint32_t length;
46797 + uint32_t actual;
46798 + unsigned sent_zlp:1;
46799 + /**
46800 + * Used instead of original buffer if
46801 + * it(physical address) is not dword-aligned.
46802 + **/
46803 + uint8_t *dw_align_buf;
46804 + dwc_dma_t dw_align_buf_dma;
46805 +
46806 + DWC_CIRCLEQ_ENTRY(dwc_otg_pcd_request) queue_entry;
46807 +#ifdef DWC_UTE_PER_IO
46808 + struct dwc_iso_xreq_port ext_req;
46809 + //void *priv_ereq_nport; /* */
46810 +#endif
46811 +} dwc_otg_pcd_request_t;
46812 +
46813 +DWC_CIRCLEQ_HEAD(req_list, dwc_otg_pcd_request);
46814 +
46815 +/** PCD EP structure.
46816 + * This structure describes an EP, there is an array of EPs in the PCD
46817 + * structure.
46818 + */
46819 +typedef struct dwc_otg_pcd_ep {
46820 + /** USB EP Descriptor */
46821 + const usb_endpoint_descriptor_t *desc;
46822 +
46823 + /** queue of dwc_otg_pcd_requests. */
46824 + struct req_list queue;
46825 + unsigned stopped:1;
46826 + unsigned disabling:1;
46827 + unsigned dma:1;
46828 + unsigned queue_sof:1;
46829 +
46830 +#ifdef DWC_EN_ISOC
46831 + /** ISOC req handle passed */
46832 + void *iso_req_handle;
46833 +#endif //_EN_ISOC_
46834 +
46835 + /** DWC_otg ep data. */
46836 + dwc_ep_t dwc_ep;
46837 +
46838 + /** Pointer to PCD */
46839 + struct dwc_otg_pcd *pcd;
46840 +
46841 + void *priv;
46842 +} dwc_otg_pcd_ep_t;
46843 +
46844 +/** DWC_otg PCD Structure.
46845 + * This structure encapsulates the data for the dwc_otg PCD.
46846 + */
46847 +struct dwc_otg_pcd {
46848 + const struct dwc_otg_pcd_function_ops *fops;
46849 + /** The DWC otg device pointer */
46850 + struct dwc_otg_device *otg_dev;
46851 + /** Core Interface */
46852 + dwc_otg_core_if_t *core_if;
46853 + /** State of EP0 */
46854 + ep0state_e ep0state;
46855 + /** EP0 Request is pending */
46856 + unsigned ep0_pending:1;
46857 + /** Indicates when SET CONFIGURATION Request is in process */
46858 + unsigned request_config:1;
46859 + /** The state of the Remote Wakeup Enable. */
46860 + unsigned remote_wakeup_enable:1;
46861 + /** The state of the B-Device HNP Enable. */
46862 + unsigned b_hnp_enable:1;
46863 + /** The state of A-Device HNP Support. */
46864 + unsigned a_hnp_support:1;
46865 + /** The state of the A-Device Alt HNP support. */
46866 + unsigned a_alt_hnp_support:1;
46867 + /** Count of pending Requests */
46868 + unsigned request_pending;
46869 +
46870 + /** SETUP packet for EP0
46871 + * This structure is allocated as a DMA buffer on PCD initialization
46872 + * with enough space for up to 3 setup packets.
46873 + */
46874 + union {
46875 + usb_device_request_t req;
46876 + uint32_t d32[2];
46877 + } *setup_pkt;
46878 +
46879 + dwc_dma_t setup_pkt_dma_handle;
46880 +
46881 + /* Additional buffer and flag for CTRL_WR premature case */
46882 + uint8_t *backup_buf;
46883 + unsigned data_terminated;
46884 +
46885 + /** 2-byte dma buffer used to return status from GET_STATUS */
46886 + uint16_t *status_buf;
46887 + dwc_dma_t status_buf_dma_handle;
46888 +
46889 + /** EP0 */
46890 + dwc_otg_pcd_ep_t ep0;
46891 +
46892 + /** Array of IN EPs. */
46893 + dwc_otg_pcd_ep_t in_ep[MAX_EPS_CHANNELS - 1];
46894 + /** Array of OUT EPs. */
46895 + dwc_otg_pcd_ep_t out_ep[MAX_EPS_CHANNELS - 1];
46896 + /** number of valid EPs in the above array. */
46897 +// unsigned num_eps : 4;
46898 + dwc_spinlock_t *lock;
46899 +
46900 + /** Tasklet to defer starting of TEST mode transmissions until
46901 + * Status Phase has been completed.
46902 + */
46903 + dwc_tasklet_t *test_mode_tasklet;
46904 +
46905 + /** Tasklet to delay starting of xfer in DMA mode */
46906 + dwc_tasklet_t *start_xfer_tasklet;
46907 +
46908 + /** The test mode to enter when the tasklet is executed. */
46909 + unsigned test_mode;
46910 + /** The cfi_api structure that implements most of the CFI API
46911 + * and OTG specific core configuration functionality
46912 + */
46913 +#ifdef DWC_UTE_CFI
46914 + struct cfiobject *cfi;
46915 +#endif
46916 +
46917 +};
46918 +
46919 +//FIXME this functions should be static, and this prototypes should be removed
46920 +extern void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep);
46921 +extern void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep,
46922 + dwc_otg_pcd_request_t * req, int32_t status);
46923 +
46924 +void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
46925 + void *req_handle);
46926 +
46927 +extern void do_test_mode(void *data);
46928 +#endif
46929 +#endif /* DWC_HOST_ONLY */
46930 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h b/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
46931 new file mode 100644
46932 index 0000000..c8d2e0e
46933 --- /dev/null
46934 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
46935 @@ -0,0 +1,360 @@
46936 +/* ==========================================================================
46937 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_if.h $
46938 + * $Revision: #11 $
46939 + * $Date: 2011/10/26 $
46940 + * $Change: 1873028 $
46941 + *
46942 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
46943 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
46944 + * otherwise expressly agreed to in writing between Synopsys and you.
46945 + *
46946 + * The Software IS NOT an item of Licensed Software or Licensed Product under
46947 + * any End User Software License Agreement or Agreement for Licensed Product
46948 + * with Synopsys or any supplement thereto. You are permitted to use and
46949 + * redistribute this Software in source and binary forms, with or without
46950 + * modification, provided that redistributions of source code must retain this
46951 + * notice. You may not view, use, disclose, copy or distribute this file or
46952 + * any information contained herein except pursuant to this license grant from
46953 + * Synopsys. If you do not agree with this notice, including the disclaimer
46954 + * below, then you are not authorized to use the Software.
46955 + *
46956 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
46957 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46958 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46959 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
46960 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46961 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
46962 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
46963 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46964 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46965 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
46966 + * DAMAGE.
46967 + * ========================================================================== */
46968 +#ifndef DWC_HOST_ONLY
46969 +
46970 +#if !defined(__DWC_PCD_IF_H__)
46971 +#define __DWC_PCD_IF_H__
46972 +
46973 +//#include "dwc_os.h"
46974 +#include "dwc_otg_core_if.h"
46975 +
46976 +/** @file
46977 + * This file defines DWC_OTG PCD Core API.
46978 + */
46979 +
46980 +struct dwc_otg_pcd;
46981 +typedef struct dwc_otg_pcd dwc_otg_pcd_t;
46982 +
46983 +/** Maxpacket size for EP0 */
46984 +#define MAX_EP0_SIZE 64
46985 +/** Maxpacket size for any EP */
46986 +#define MAX_PACKET_SIZE 1024
46987 +
46988 +/** @name Function Driver Callbacks */
46989 +/** @{ */
46990 +
46991 +/** This function will be called whenever a previously queued request has
46992 + * completed. The status value will be set to -DWC_E_SHUTDOWN to indicated a
46993 + * failed or aborted transfer, or -DWC_E_RESTART to indicate the device was reset,
46994 + * or -DWC_E_TIMEOUT to indicate it timed out, or -DWC_E_INVALID to indicate invalid
46995 + * parameters. */
46996 +typedef int (*dwc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
46997 + void *req_handle, int32_t status,
46998 + uint32_t actual);
46999 +/**
47000 + * This function will be called whenever a previousle queued ISOC request has
47001 + * completed. Count of ISOC packets could be read using dwc_otg_pcd_get_iso_packet_count
47002 + * function.
47003 + * The status of each ISOC packet could be read using dwc_otg_pcd_get_iso_packet_*
47004 + * functions.
47005 + */
47006 +typedef int (*dwc_isoc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
47007 + void *req_handle, int proc_buf_num);
47008 +/** This function should handle any SETUP request that cannot be handled by the
47009 + * PCD Core. This includes most GET_DESCRIPTORs, SET_CONFIGS, Any
47010 + * class-specific requests, etc. The function must non-blocking.
47011 + *
47012 + * Returns 0 on success.
47013 + * Returns -DWC_E_NOT_SUPPORTED if the request is not supported.
47014 + * Returns -DWC_E_INVALID if the setup request had invalid parameters or bytes.
47015 + * Returns -DWC_E_SHUTDOWN on any other error. */
47016 +typedef int (*dwc_setup_cb_t) (dwc_otg_pcd_t * pcd, uint8_t * bytes);
47017 +/** This is called whenever the device has been disconnected. The function
47018 + * driver should take appropriate action to clean up all pending requests in the
47019 + * PCD Core, remove all endpoints (except ep0), and initialize back to reset
47020 + * state. */
47021 +typedef int (*dwc_disconnect_cb_t) (dwc_otg_pcd_t * pcd);
47022 +/** This function is called when device has been connected. */
47023 +typedef int (*dwc_connect_cb_t) (dwc_otg_pcd_t * pcd, int speed);
47024 +/** This function is called when device has been suspended */
47025 +typedef int (*dwc_suspend_cb_t) (dwc_otg_pcd_t * pcd);
47026 +/** This function is called when device has received LPM tokens, i.e.
47027 + * device has been sent to sleep state. */
47028 +typedef int (*dwc_sleep_cb_t) (dwc_otg_pcd_t * pcd);
47029 +/** This function is called when device has been resumed
47030 + * from suspend(L2) or L1 sleep state. */
47031 +typedef int (*dwc_resume_cb_t) (dwc_otg_pcd_t * pcd);
47032 +/** This function is called whenever hnp params has been changed.
47033 + * User can call get_b_hnp_enable, get_a_hnp_support, get_a_alt_hnp_support functions
47034 + * to get hnp parameters. */
47035 +typedef int (*dwc_hnp_params_changed_cb_t) (dwc_otg_pcd_t * pcd);
47036 +/** This function is called whenever USB RESET is detected. */
47037 +typedef int (*dwc_reset_cb_t) (dwc_otg_pcd_t * pcd);
47038 +
47039 +typedef int (*cfi_setup_cb_t) (dwc_otg_pcd_t * pcd, void *ctrl_req_bytes);
47040 +
47041 +/**
47042 + *
47043 + * @param ep_handle Void pointer to the usb_ep structure
47044 + * @param ereq_port Pointer to the extended request structure created in the
47045 + * portable part.
47046 + */
47047 +typedef int (*xiso_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
47048 + void *req_handle, int32_t status,
47049 + void *ereq_port);
47050 +/** Function Driver Ops Data Structure */
47051 +struct dwc_otg_pcd_function_ops {
47052 + dwc_connect_cb_t connect;
47053 + dwc_disconnect_cb_t disconnect;
47054 + dwc_setup_cb_t setup;
47055 + dwc_completion_cb_t complete;
47056 + dwc_isoc_completion_cb_t isoc_complete;
47057 + dwc_suspend_cb_t suspend;
47058 + dwc_sleep_cb_t sleep;
47059 + dwc_resume_cb_t resume;
47060 + dwc_reset_cb_t reset;
47061 + dwc_hnp_params_changed_cb_t hnp_changed;
47062 + cfi_setup_cb_t cfi_setup;
47063 +#ifdef DWC_UTE_PER_IO
47064 + xiso_completion_cb_t xisoc_complete;
47065 +#endif
47066 +};
47067 +/** @} */
47068 +
47069 +/** @name Function Driver Functions */
47070 +/** @{ */
47071 +
47072 +/** Call this function to get pointer on dwc_otg_pcd_t,
47073 + * this pointer will be used for all PCD API functions.
47074 + *
47075 + * @param core_if The DWC_OTG Core
47076 + */
47077 +extern dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if);
47078 +
47079 +/** Frees PCD allocated by dwc_otg_pcd_init
47080 + *
47081 + * @param pcd The PCD
47082 + */
47083 +extern void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd);
47084 +
47085 +/** Call this to bind the function driver to the PCD Core.
47086 + *
47087 + * @param pcd Pointer on dwc_otg_pcd_t returned by dwc_otg_pcd_init function.
47088 + * @param fops The Function Driver Ops data structure containing pointers to all callbacks.
47089 + */
47090 +extern void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
47091 + const struct dwc_otg_pcd_function_ops *fops);
47092 +
47093 +/** Enables an endpoint for use. This function enables an endpoint in
47094 + * the PCD. The endpoint is described by the ep_desc which has the
47095 + * same format as a USB ep descriptor. The ep_handle parameter is used to refer
47096 + * to the endpoint from other API functions and in callbacks. Normally this
47097 + * should be called after a SET_CONFIGURATION/SET_INTERFACE to configure the
47098 + * core for that interface.
47099 + *
47100 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47101 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
47102 + * Returns 0 on success.
47103 + *
47104 + * @param pcd The PCD
47105 + * @param ep_desc Endpoint descriptor
47106 + * @param usb_ep Handle on endpoint, that will be used to identify endpoint.
47107 + */
47108 +extern int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
47109 + const uint8_t * ep_desc, void *usb_ep);
47110 +
47111 +/** Disable the endpoint referenced by ep_handle.
47112 + *
47113 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47114 + * Returns -DWC_E_SHUTDOWN if any other error occurred.
47115 + * Returns 0 on success. */
47116 +extern int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle);
47117 +
47118 +/** Queue a data transfer request on the endpoint referenced by ep_handle.
47119 + * After the transfer is completes, the complete callback will be called with
47120 + * the request status.
47121 + *
47122 + * @param pcd The PCD
47123 + * @param ep_handle The handle of the endpoint
47124 + * @param buf The buffer for the data
47125 + * @param dma_buf The DMA buffer for the data
47126 + * @param buflen The length of the data transfer
47127 + * @param zero Specifies whether to send zero length last packet.
47128 + * @param req_handle Set this handle to any value to use to reference this
47129 + * request in the ep_dequeue function or from the complete callback
47130 + * @param atomic_alloc If driver need to perform atomic allocations
47131 + * for internal data structures.
47132 + *
47133 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47134 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
47135 + * Returns 0 on success. */
47136 +extern int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
47137 + uint8_t * buf, dwc_dma_t dma_buf,
47138 + uint32_t buflen, int zero, void *req_handle,
47139 + int atomic_alloc);
47140 +#ifdef DWC_UTE_PER_IO
47141 +/**
47142 + *
47143 + * @param ereq_nonport Pointer to the extended request part of the
47144 + * usb_request structure defined in usb_gadget.h file.
47145 + */
47146 +extern int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
47147 + uint8_t * buf, dwc_dma_t dma_buf,
47148 + uint32_t buflen, int zero,
47149 + void *req_handle, int atomic_alloc,
47150 + void *ereq_nonport);
47151 +
47152 +#endif
47153 +
47154 +/** De-queue the specified data transfer that has not yet completed.
47155 + *
47156 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47157 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
47158 + * Returns 0 on success. */
47159 +extern int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
47160 + void *req_handle);
47161 +
47162 +/** Halt (STALL) an endpoint or clear it.
47163 + *
47164 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47165 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
47166 + * Returns -DWC_E_AGAIN if the STALL cannot be sent and must be tried again later
47167 + * Returns 0 on success. */
47168 +extern int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value);
47169 +
47170 +/** This function */
47171 +extern int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle);
47172 +
47173 +/** This function should be called on every hardware interrupt */
47174 +extern int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd);
47175 +
47176 +/** This function returns current frame number */
47177 +extern int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd);
47178 +
47179 +/**
47180 + * Start isochronous transfers on the endpoint referenced by ep_handle.
47181 + * For isochronous transfers duble buffering is used.
47182 + * After processing each of buffers comlete callback will be called with
47183 + * status for each transaction.
47184 + *
47185 + * @param pcd The PCD
47186 + * @param ep_handle The handle of the endpoint
47187 + * @param buf0 The virtual address of first data buffer
47188 + * @param buf1 The virtual address of second data buffer
47189 + * @param dma0 The DMA address of first data buffer
47190 + * @param dma1 The DMA address of second data buffer
47191 + * @param sync_frame Data pattern frame number
47192 + * @param dp_frame Data size for pattern frame
47193 + * @param data_per_frame Data size for regular frame
47194 + * @param start_frame Frame number to start transfers, if -1 then start transfers ASAP.
47195 + * @param buf_proc_intrvl Interval of ISOC Buffer processing
47196 + * @param req_handle Handle of ISOC request
47197 + * @param atomic_alloc Specefies whether to perform atomic allocation for
47198 + * internal data structures.
47199 + *
47200 + * Returns -DWC_E_NO_MEMORY if there is no enough memory.
47201 + * Returns -DWC_E_INVALID if incorrect arguments are passed to the function.
47202 + * Returns -DW_E_SHUTDOWN for any other error.
47203 + * Returns 0 on success
47204 + */
47205 +extern int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
47206 + uint8_t * buf0, uint8_t * buf1,
47207 + dwc_dma_t dma0, dwc_dma_t dma1,
47208 + int sync_frame, int dp_frame,
47209 + int data_per_frame, int start_frame,
47210 + int buf_proc_intrvl, void *req_handle,
47211 + int atomic_alloc);
47212 +
47213 +/** Stop ISOC transfers on endpoint referenced by ep_handle.
47214 + *
47215 + * @param pcd The PCD
47216 + * @param ep_handle The handle of the endpoint
47217 + * @param req_handle Handle of ISOC request
47218 + *
47219 + * Returns -DWC_E_INVALID if incorrect arguments are passed to the function
47220 + * Returns 0 on success
47221 + */
47222 +int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
47223 + void *req_handle);
47224 +
47225 +/** Get ISOC packet status.
47226 + *
47227 + * @param pcd The PCD
47228 + * @param ep_handle The handle of the endpoint
47229 + * @param iso_req_handle Isochronoush request handle
47230 + * @param packet Number of packet
47231 + * @param status Out parameter for returning status
47232 + * @param actual Out parameter for returning actual length
47233 + * @param offset Out parameter for returning offset
47234 + *
47235 + */
47236 +extern void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd,
47237 + void *ep_handle,
47238 + void *iso_req_handle, int packet,
47239 + int *status, int *actual,
47240 + int *offset);
47241 +
47242 +/** Get ISOC packet count.
47243 + *
47244 + * @param pcd The PCD
47245 + * @param ep_handle The handle of the endpoint
47246 + * @param iso_req_handle
47247 + */
47248 +extern int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd,
47249 + void *ep_handle,
47250 + void *iso_req_handle);
47251 +
47252 +/** This function starts the SRP Protocol if no session is in progress. If
47253 + * a session is already in progress, but the device is suspended,
47254 + * remote wakeup signaling is started.
47255 + */
47256 +extern int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd);
47257 +
47258 +/** This function returns 1 if LPM support is enabled, and 0 otherwise. */
47259 +extern int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd);
47260 +
47261 +/** This function returns 1 if remote wakeup is allowed and 0, otherwise. */
47262 +extern int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd);
47263 +
47264 +/** Initiate SRP */
47265 +extern void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd);
47266 +
47267 +/** Starts remote wakeup signaling. */
47268 +extern void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set);
47269 +
47270 +/** Starts micorsecond soft disconnect. */
47271 +extern void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs);
47272 +/** This function returns whether device is dualspeed.*/
47273 +extern uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd);
47274 +
47275 +/** This function returns whether device is otg. */
47276 +extern uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd);
47277 +
47278 +/** These functions allow to get hnp parameters */
47279 +extern uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd);
47280 +extern uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd);
47281 +extern uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd);
47282 +
47283 +/** CFI specific Interface functions */
47284 +/** Allocate a cfi buffer */
47285 +extern uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep,
47286 + dwc_dma_t * addr, size_t buflen,
47287 + int flags);
47288 +
47289 +/******************************************************************************/
47290 +
47291 +/** @} */
47292 +
47293 +#endif /* __DWC_PCD_IF_H__ */
47294 +
47295 +#endif /* DWC_HOST_ONLY */
47296 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
47297 new file mode 100644
47298 index 0000000..1b1f83c
47299 --- /dev/null
47300 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
47301 @@ -0,0 +1,5147 @@
47302 +/* ==========================================================================
47303 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_intr.c $
47304 + * $Revision: #116 $
47305 + * $Date: 2012/08/10 $
47306 + * $Change: 2047372 $
47307 + *
47308 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
47309 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
47310 + * otherwise expressly agreed to in writing between Synopsys and you.
47311 + *
47312 + * The Software IS NOT an item of Licensed Software or Licensed Product under
47313 + * any End User Software License Agreement or Agreement for Licensed Product
47314 + * with Synopsys or any supplement thereto. You are permitted to use and
47315 + * redistribute this Software in source and binary forms, with or without
47316 + * modification, provided that redistributions of source code must retain this
47317 + * notice. You may not view, use, disclose, copy or distribute this file or
47318 + * any information contained herein except pursuant to this license grant from
47319 + * Synopsys. If you do not agree with this notice, including the disclaimer
47320 + * below, then you are not authorized to use the Software.
47321 + *
47322 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
47323 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47324 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47325 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
47326 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
47327 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
47328 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
47329 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47330 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47331 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
47332 + * DAMAGE.
47333 + * ========================================================================== */
47334 +#ifndef DWC_HOST_ONLY
47335 +
47336 +#include "dwc_otg_pcd.h"
47337 +
47338 +#ifdef DWC_UTE_CFI
47339 +#include "dwc_otg_cfi.h"
47340 +#endif
47341 +
47342 +#ifdef DWC_UTE_PER_IO
47343 +extern void complete_xiso_ep(dwc_otg_pcd_ep_t * ep);
47344 +#endif
47345 +//#define PRINT_CFI_DMA_DESCS
47346 +
47347 +#define DEBUG_EP0
47348 +
47349 +/**
47350 + * This function updates OTG.
47351 + */
47352 +static void dwc_otg_pcd_update_otg(dwc_otg_pcd_t * pcd, const unsigned reset)
47353 +{
47354 +
47355 + if (reset) {
47356 + pcd->b_hnp_enable = 0;
47357 + pcd->a_hnp_support = 0;
47358 + pcd->a_alt_hnp_support = 0;
47359 + }
47360 +
47361 + if (pcd->fops->hnp_changed) {
47362 + pcd->fops->hnp_changed(pcd);
47363 + }
47364 +}
47365 +
47366 +/** @file
47367 + * This file contains the implementation of the PCD Interrupt handlers.
47368 + *
47369 + * The PCD handles the device interrupts. Many conditions can cause a
47370 + * device interrupt. When an interrupt occurs, the device interrupt
47371 + * service routine determines the cause of the interrupt and
47372 + * dispatches handling to the appropriate function. These interrupt
47373 + * handling functions are described below.
47374 + * All interrupt registers are processed from LSB to MSB.
47375 + */
47376 +
47377 +/**
47378 + * This function prints the ep0 state for debug purposes.
47379 + */
47380 +static inline void print_ep0_state(dwc_otg_pcd_t * pcd)
47381 +{
47382 +#ifdef DEBUG
47383 + char str[40];
47384 +
47385 + switch (pcd->ep0state) {
47386 + case EP0_DISCONNECT:
47387 + dwc_strcpy(str, "EP0_DISCONNECT");
47388 + break;
47389 + case EP0_IDLE:
47390 + dwc_strcpy(str, "EP0_IDLE");
47391 + break;
47392 + case EP0_IN_DATA_PHASE:
47393 + dwc_strcpy(str, "EP0_IN_DATA_PHASE");
47394 + break;
47395 + case EP0_OUT_DATA_PHASE:
47396 + dwc_strcpy(str, "EP0_OUT_DATA_PHASE");
47397 + break;
47398 + case EP0_IN_STATUS_PHASE:
47399 + dwc_strcpy(str, "EP0_IN_STATUS_PHASE");
47400 + break;
47401 + case EP0_OUT_STATUS_PHASE:
47402 + dwc_strcpy(str, "EP0_OUT_STATUS_PHASE");
47403 + break;
47404 + case EP0_STALL:
47405 + dwc_strcpy(str, "EP0_STALL");
47406 + break;
47407 + default:
47408 + dwc_strcpy(str, "EP0_INVALID");
47409 + }
47410 +
47411 + DWC_DEBUGPL(DBG_ANY, "%s(%d)\n", str, pcd->ep0state);
47412 +#endif
47413 +}
47414 +
47415 +/**
47416 + * This function calculate the size of the payload in the memory
47417 + * for out endpoints and prints size for debug purposes(used in
47418 + * 2.93a DevOutNak feature).
47419 + */
47420 +static inline void print_memory_payload(dwc_otg_pcd_t * pcd, dwc_ep_t * ep)
47421 +{
47422 +#ifdef DEBUG
47423 + deptsiz_data_t deptsiz_init = {.d32 = 0 };
47424 + deptsiz_data_t deptsiz_updt = {.d32 = 0 };
47425 + int pack_num;
47426 + unsigned payload;
47427 +
47428 + deptsiz_init.d32 = pcd->core_if->start_doeptsiz_val[ep->num];
47429 + deptsiz_updt.d32 =
47430 + DWC_READ_REG32(&pcd->core_if->dev_if->
47431 + out_ep_regs[ep->num]->doeptsiz);
47432 + /* Payload will be */
47433 + payload = deptsiz_init.b.xfersize - deptsiz_updt.b.xfersize;
47434 + /* Packet count is decremented every time a packet
47435 + * is written to the RxFIFO not in to the external memory
47436 + * So, if payload == 0, then it means no packet was sent to ext memory*/
47437 + pack_num = (!payload) ? 0 : (deptsiz_init.b.pktcnt - deptsiz_updt.b.pktcnt);
47438 + DWC_DEBUGPL(DBG_PCDV,
47439 + "Payload for EP%d-%s\n",
47440 + ep->num, (ep->is_in ? "IN" : "OUT"));
47441 + DWC_DEBUGPL(DBG_PCDV,
47442 + "Number of transfered bytes = 0x%08x\n", payload);
47443 + DWC_DEBUGPL(DBG_PCDV,
47444 + "Number of transfered packets = %d\n", pack_num);
47445 +#endif
47446 +}
47447 +
47448 +
47449 +#ifdef DWC_UTE_CFI
47450 +static inline void print_desc(struct dwc_otg_dma_desc *ddesc,
47451 + const uint8_t * epname, int descnum)
47452 +{
47453 + CFI_INFO
47454 + ("%s DMA_DESC(%d) buf=0x%08x bytes=0x%04x; sp=0x%x; l=0x%x; sts=0x%02x; bs=0x%02x\n",
47455 + epname, descnum, ddesc->buf, ddesc->status.b.bytes,
47456 + ddesc->status.b.sp, ddesc->status.b.l, ddesc->status.b.sts,
47457 + ddesc->status.b.bs);
47458 +}
47459 +#endif
47460 +
47461 +/**
47462 + * This function returns pointer to in ep struct with number ep_num
47463 + */
47464 +static inline dwc_otg_pcd_ep_t *get_in_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
47465 +{
47466 + int i;
47467 + int num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
47468 + if (ep_num == 0) {
47469 + return &pcd->ep0;
47470 + } else {
47471 + for (i = 0; i < num_in_eps; ++i) {
47472 + if (pcd->in_ep[i].dwc_ep.num == ep_num)
47473 + return &pcd->in_ep[i];
47474 + }
47475 + return 0;
47476 + }
47477 +}
47478 +
47479 +/**
47480 + * This function returns pointer to out ep struct with number ep_num
47481 + */
47482 +static inline dwc_otg_pcd_ep_t *get_out_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
47483 +{
47484 + int i;
47485 + int num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
47486 + if (ep_num == 0) {
47487 + return &pcd->ep0;
47488 + } else {
47489 + for (i = 0; i < num_out_eps; ++i) {
47490 + if (pcd->out_ep[i].dwc_ep.num == ep_num)
47491 + return &pcd->out_ep[i];
47492 + }
47493 + return 0;
47494 + }
47495 +}
47496 +
47497 +/**
47498 + * This functions gets a pointer to an EP from the wIndex address
47499 + * value of the control request.
47500 + */
47501 +dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex)
47502 +{
47503 + dwc_otg_pcd_ep_t *ep;
47504 + uint32_t ep_num = UE_GET_ADDR(wIndex);
47505 +
47506 + if (ep_num == 0) {
47507 + ep = &pcd->ep0;
47508 + } else if (UE_GET_DIR(wIndex) == UE_DIR_IN) { /* in ep */
47509 + ep = &pcd->in_ep[ep_num - 1];
47510 + } else {
47511 + ep = &pcd->out_ep[ep_num - 1];
47512 + }
47513 +
47514 + return ep;
47515 +}
47516 +
47517 +/**
47518 + * This function checks the EP request queue, if the queue is not
47519 + * empty the next request is started.
47520 + */
47521 +void start_next_request(dwc_otg_pcd_ep_t * ep)
47522 +{
47523 + dwc_otg_pcd_request_t *req = 0;
47524 + uint32_t max_transfer =
47525 + GET_CORE_IF(ep->pcd)->core_params->max_transfer_size;
47526 +
47527 +#ifdef DWC_UTE_CFI
47528 + struct dwc_otg_pcd *pcd;
47529 + pcd = ep->pcd;
47530 +#endif
47531 +
47532 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
47533 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
47534 +
47535 +#ifdef DWC_UTE_CFI
47536 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
47537 + ep->dwc_ep.cfi_req_len = req->length;
47538 + pcd->cfi->ops.build_descriptors(pcd->cfi, pcd, ep, req);
47539 + } else {
47540 +#endif
47541 + /* Setup and start the Transfer */
47542 + if (req->dw_align_buf) {
47543 + ep->dwc_ep.dma_addr = req->dw_align_buf_dma;
47544 + ep->dwc_ep.start_xfer_buff = req->dw_align_buf;
47545 + ep->dwc_ep.xfer_buff = req->dw_align_buf;
47546 + } else {
47547 + ep->dwc_ep.dma_addr = req->dma;
47548 + ep->dwc_ep.start_xfer_buff = req->buf;
47549 + ep->dwc_ep.xfer_buff = req->buf;
47550 + }
47551 + ep->dwc_ep.sent_zlp = 0;
47552 + ep->dwc_ep.total_len = req->length;
47553 + ep->dwc_ep.xfer_len = 0;
47554 + ep->dwc_ep.xfer_count = 0;
47555 +
47556 + ep->dwc_ep.maxxfer = max_transfer;
47557 + if (GET_CORE_IF(ep->pcd)->dma_desc_enable) {
47558 + uint32_t out_max_xfer = DDMA_MAX_TRANSFER_SIZE
47559 + - (DDMA_MAX_TRANSFER_SIZE % 4);
47560 + if (ep->dwc_ep.is_in) {
47561 + if (ep->dwc_ep.maxxfer >
47562 + DDMA_MAX_TRANSFER_SIZE) {
47563 + ep->dwc_ep.maxxfer =
47564 + DDMA_MAX_TRANSFER_SIZE;
47565 + }
47566 + } else {
47567 + if (ep->dwc_ep.maxxfer > out_max_xfer) {
47568 + ep->dwc_ep.maxxfer =
47569 + out_max_xfer;
47570 + }
47571 + }
47572 + }
47573 + if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
47574 + ep->dwc_ep.maxxfer -=
47575 + (ep->dwc_ep.maxxfer % ep->dwc_ep.maxpacket);
47576 + }
47577 + if (req->sent_zlp) {
47578 + if ((ep->dwc_ep.total_len %
47579 + ep->dwc_ep.maxpacket == 0)
47580 + && (ep->dwc_ep.total_len != 0)) {
47581 + ep->dwc_ep.sent_zlp = 1;
47582 + }
47583 +
47584 + }
47585 +#ifdef DWC_UTE_CFI
47586 + }
47587 +#endif
47588 + dwc_otg_ep_start_transfer(GET_CORE_IF(ep->pcd), &ep->dwc_ep);
47589 + } else if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
47590 + DWC_PRINTF("There are no more ISOC requests \n");
47591 + ep->dwc_ep.frame_num = 0xFFFFFFFF;
47592 + }
47593 +}
47594 +
47595 +/**
47596 + * This function handles the SOF Interrupts. At this time the SOF
47597 + * Interrupt is disabled.
47598 + */
47599 +int32_t dwc_otg_pcd_handle_sof_intr(dwc_otg_pcd_t * pcd)
47600 +{
47601 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47602 +
47603 + gintsts_data_t gintsts;
47604 +
47605 + DWC_DEBUGPL(DBG_PCD, "SOF\n");
47606 +
47607 + /* Clear interrupt */
47608 + gintsts.d32 = 0;
47609 + gintsts.b.sofintr = 1;
47610 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
47611 +
47612 + return 1;
47613 +}
47614 +
47615 +/**
47616 + * This function handles the Rx Status Queue Level Interrupt, which
47617 + * indicates that there is a least one packet in the Rx FIFO. The
47618 + * packets are moved from the FIFO to memory, where they will be
47619 + * processed when the Endpoint Interrupt Register indicates Transfer
47620 + * Complete or SETUP Phase Done.
47621 + *
47622 + * Repeat the following until the Rx Status Queue is empty:
47623 + * -# Read the Receive Status Pop Register (GRXSTSP) to get Packet
47624 + * info
47625 + * -# If Receive FIFO is empty then skip to step Clear the interrupt
47626 + * and exit
47627 + * -# If SETUP Packet call dwc_otg_read_setup_packet to copy the
47628 + * SETUP data to the buffer
47629 + * -# If OUT Data Packet call dwc_otg_read_packet to copy the data
47630 + * to the destination buffer
47631 + */
47632 +int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(dwc_otg_pcd_t * pcd)
47633 +{
47634 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47635 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
47636 + gintmsk_data_t gintmask = {.d32 = 0 };
47637 + device_grxsts_data_t status;
47638 + dwc_otg_pcd_ep_t *ep;
47639 + gintsts_data_t gintsts;
47640 +#ifdef DEBUG
47641 + static char *dpid_str[] = { "D0", "D2", "D1", "MDATA" };
47642 +#endif
47643 +
47644 + //DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd);
47645 + /* Disable the Rx Status Queue Level interrupt */
47646 + gintmask.b.rxstsqlvl = 1;
47647 + DWC_MODIFY_REG32(&global_regs->gintmsk, gintmask.d32, 0);
47648 +
47649 + /* Get the Status from the top of the FIFO */
47650 + status.d32 = DWC_READ_REG32(&global_regs->grxstsp);
47651 +
47652 + DWC_DEBUGPL(DBG_PCD, "EP:%d BCnt:%d DPID:%s "
47653 + "pktsts:%x Frame:%d(0x%0x)\n",
47654 + status.b.epnum, status.b.bcnt,
47655 + dpid_str[status.b.dpid],
47656 + status.b.pktsts, status.b.fn, status.b.fn);
47657 + /* Get pointer to EP structure */
47658 + ep = get_out_ep(pcd, status.b.epnum);
47659 +
47660 + switch (status.b.pktsts) {
47661 + case DWC_DSTS_GOUT_NAK:
47662 + DWC_DEBUGPL(DBG_PCDV, "Global OUT NAK\n");
47663 + break;
47664 + case DWC_STS_DATA_UPDT:
47665 + DWC_DEBUGPL(DBG_PCDV, "OUT Data Packet\n");
47666 + if (status.b.bcnt && ep->dwc_ep.xfer_buff) {
47667 + /** @todo NGS Check for buffer overflow? */
47668 + dwc_otg_read_packet(core_if,
47669 + ep->dwc_ep.xfer_buff,
47670 + status.b.bcnt);
47671 + ep->dwc_ep.xfer_count += status.b.bcnt;
47672 + ep->dwc_ep.xfer_buff += status.b.bcnt;
47673 + }
47674 + break;
47675 + case DWC_STS_XFER_COMP:
47676 + DWC_DEBUGPL(DBG_PCDV, "OUT Complete\n");
47677 + break;
47678 + case DWC_DSTS_SETUP_COMP:
47679 +#ifdef DEBUG_EP0
47680 + DWC_DEBUGPL(DBG_PCDV, "Setup Complete\n");
47681 +#endif
47682 + break;
47683 + case DWC_DSTS_SETUP_UPDT:
47684 + dwc_otg_read_setup_packet(core_if, pcd->setup_pkt->d32);
47685 +#ifdef DEBUG_EP0
47686 + DWC_DEBUGPL(DBG_PCD,
47687 + "SETUP PKT: %02x.%02x v%04x i%04x l%04x\n",
47688 + pcd->setup_pkt->req.bmRequestType,
47689 + pcd->setup_pkt->req.bRequest,
47690 + UGETW(pcd->setup_pkt->req.wValue),
47691 + UGETW(pcd->setup_pkt->req.wIndex),
47692 + UGETW(pcd->setup_pkt->req.wLength));
47693 +#endif
47694 + ep->dwc_ep.xfer_count += status.b.bcnt;
47695 + break;
47696 + default:
47697 + DWC_DEBUGPL(DBG_PCDV, "Invalid Packet Status (0x%0x)\n",
47698 + status.b.pktsts);
47699 + break;
47700 + }
47701 +
47702 + /* Enable the Rx Status Queue Level interrupt */
47703 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmask.d32);
47704 + /* Clear interrupt */
47705 + gintsts.d32 = 0;
47706 + gintsts.b.rxstsqlvl = 1;
47707 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
47708 +
47709 + //DWC_DEBUGPL(DBG_PCDV, "EXIT: %s\n", __func__);
47710 + return 1;
47711 +}
47712 +
47713 +/**
47714 + * This function examines the Device IN Token Learning Queue to
47715 + * determine the EP number of the last IN token received. This
47716 + * implementation is for the Mass Storage device where there are only
47717 + * 2 IN EPs (Control-IN and BULK-IN).
47718 + *
47719 + * The EP numbers for the first six IN Tokens are in DTKNQR1 and there
47720 + * are 8 EP Numbers in each of the other possible DTKNQ Registers.
47721 + *
47722 + * @param core_if Programming view of DWC_otg controller.
47723 + *
47724 + */
47725 +static inline int get_ep_of_last_in_token(dwc_otg_core_if_t * core_if)
47726 +{
47727 + dwc_otg_device_global_regs_t *dev_global_regs =
47728 + core_if->dev_if->dev_global_regs;
47729 + const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
47730 + /* Number of Token Queue Registers */
47731 + const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
47732 + dtknq1_data_t dtknqr1;
47733 + uint32_t in_tkn_epnums[4];
47734 + int ndx = 0;
47735 + int i = 0;
47736 + volatile uint32_t *addr = &dev_global_regs->dtknqr1;
47737 + int epnum = 0;
47738 +
47739 + //DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
47740 +
47741 + /* Read the DTKNQ Registers */
47742 + for (i = 0; i < DTKNQ_REG_CNT; i++) {
47743 + in_tkn_epnums[i] = DWC_READ_REG32(addr);
47744 + DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
47745 + in_tkn_epnums[i]);
47746 + if (addr == &dev_global_regs->dvbusdis) {
47747 + addr = &dev_global_regs->dtknqr3_dthrctl;
47748 + } else {
47749 + ++addr;
47750 + }
47751 +
47752 + }
47753 +
47754 + /* Copy the DTKNQR1 data to the bit field. */
47755 + dtknqr1.d32 = in_tkn_epnums[0];
47756 + /* Get the EP numbers */
47757 + in_tkn_epnums[0] = dtknqr1.b.epnums0_5;
47758 + ndx = dtknqr1.b.intknwptr - 1;
47759 +
47760 + //DWC_DEBUGPL(DBG_PCDV,"ndx=%d\n",ndx);
47761 + if (ndx == -1) {
47762 + /** @todo Find a simpler way to calculate the max
47763 + * queue position.*/
47764 + int cnt = TOKEN_Q_DEPTH;
47765 + if (TOKEN_Q_DEPTH <= 6) {
47766 + cnt = TOKEN_Q_DEPTH - 1;
47767 + } else if (TOKEN_Q_DEPTH <= 14) {
47768 + cnt = TOKEN_Q_DEPTH - 7;
47769 + } else if (TOKEN_Q_DEPTH <= 22) {
47770 + cnt = TOKEN_Q_DEPTH - 15;
47771 + } else {
47772 + cnt = TOKEN_Q_DEPTH - 23;
47773 + }
47774 + epnum = (in_tkn_epnums[DTKNQ_REG_CNT - 1] >> (cnt * 4)) & 0xF;
47775 + } else {
47776 + if (ndx <= 5) {
47777 + epnum = (in_tkn_epnums[0] >> (ndx * 4)) & 0xF;
47778 + } else if (ndx <= 13) {
47779 + ndx -= 6;
47780 + epnum = (in_tkn_epnums[1] >> (ndx * 4)) & 0xF;
47781 + } else if (ndx <= 21) {
47782 + ndx -= 14;
47783 + epnum = (in_tkn_epnums[2] >> (ndx * 4)) & 0xF;
47784 + } else if (ndx <= 29) {
47785 + ndx -= 22;
47786 + epnum = (in_tkn_epnums[3] >> (ndx * 4)) & 0xF;
47787 + }
47788 + }
47789 + //DWC_DEBUGPL(DBG_PCD,"epnum=%d\n",epnum);
47790 + return epnum;
47791 +}
47792 +
47793 +/**
47794 + * This interrupt occurs when the non-periodic Tx FIFO is half-empty.
47795 + * The active request is checked for the next packet to be loaded into
47796 + * the non-periodic Tx FIFO.
47797 + */
47798 +int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(dwc_otg_pcd_t * pcd)
47799 +{
47800 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47801 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
47802 + dwc_otg_dev_in_ep_regs_t *ep_regs;
47803 + gnptxsts_data_t txstatus = {.d32 = 0 };
47804 + gintsts_data_t gintsts;
47805 +
47806 + int epnum = 0;
47807 + dwc_otg_pcd_ep_t *ep = 0;
47808 + uint32_t len = 0;
47809 + int dwords;
47810 +
47811 + /* Get the epnum from the IN Token Learning Queue. */
47812 + epnum = get_ep_of_last_in_token(core_if);
47813 + ep = get_in_ep(pcd, epnum);
47814 +
47815 + DWC_DEBUGPL(DBG_PCD, "NP TxFifo Empty: %d \n", epnum);
47816 +
47817 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
47818 +
47819 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47820 + if (len > ep->dwc_ep.maxpacket) {
47821 + len = ep->dwc_ep.maxpacket;
47822 + }
47823 + dwords = (len + 3) / 4;
47824 +
47825 + /* While there is space in the queue and space in the FIFO and
47826 + * More data to tranfer, Write packets to the Tx FIFO */
47827 + txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
47828 + DWC_DEBUGPL(DBG_PCDV, "b4 GNPTXSTS=0x%08x\n", txstatus.d32);
47829 +
47830 + while (txstatus.b.nptxqspcavail > 0 &&
47831 + txstatus.b.nptxfspcavail > dwords &&
47832 + ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len) {
47833 + /* Write the FIFO */
47834 + dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
47835 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47836 +
47837 + if (len > ep->dwc_ep.maxpacket) {
47838 + len = ep->dwc_ep.maxpacket;
47839 + }
47840 +
47841 + dwords = (len + 3) / 4;
47842 + txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
47843 + DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n", txstatus.d32);
47844 + }
47845 +
47846 + DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n",
47847 + DWC_READ_REG32(&global_regs->gnptxsts));
47848 +
47849 + /* Clear interrupt */
47850 + gintsts.d32 = 0;
47851 + gintsts.b.nptxfempty = 1;
47852 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
47853 +
47854 + return 1;
47855 +}
47856 +
47857 +/**
47858 + * This function is called when dedicated Tx FIFO Empty interrupt occurs.
47859 + * The active request is checked for the next packet to be loaded into
47860 + * apropriate Tx FIFO.
47861 + */
47862 +static int32_t write_empty_tx_fifo(dwc_otg_pcd_t * pcd, uint32_t epnum)
47863 +{
47864 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47865 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
47866 + dwc_otg_dev_in_ep_regs_t *ep_regs;
47867 + dtxfsts_data_t txstatus = {.d32 = 0 };
47868 + dwc_otg_pcd_ep_t *ep = 0;
47869 + uint32_t len = 0;
47870 + int dwords;
47871 +
47872 + ep = get_in_ep(pcd, epnum);
47873 +
47874 + DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
47875 +
47876 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
47877 +
47878 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47879 +
47880 + if (len > ep->dwc_ep.maxpacket) {
47881 + len = ep->dwc_ep.maxpacket;
47882 + }
47883 +
47884 + dwords = (len + 3) / 4;
47885 +
47886 + /* While there is space in the queue and space in the FIFO and
47887 + * More data to tranfer, Write packets to the Tx FIFO */
47888 + txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
47889 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
47890 +
47891 + while (txstatus.b.txfspcavail > dwords &&
47892 + ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len &&
47893 + ep->dwc_ep.xfer_len != 0) {
47894 + /* Write the FIFO */
47895 + dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
47896 +
47897 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47898 + if (len > ep->dwc_ep.maxpacket) {
47899 + len = ep->dwc_ep.maxpacket;
47900 + }
47901 +
47902 + dwords = (len + 3) / 4;
47903 + txstatus.d32 =
47904 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
47905 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
47906 + txstatus.d32);
47907 + }
47908 +
47909 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
47910 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
47911 +
47912 + return 1;
47913 +}
47914 +
47915 +/**
47916 + * This function is called when the Device is disconnected. It stops
47917 + * any active requests and informs the Gadget driver of the
47918 + * disconnect.
47919 + */
47920 +void dwc_otg_pcd_stop(dwc_otg_pcd_t * pcd)
47921 +{
47922 + int i, num_in_eps, num_out_eps;
47923 + dwc_otg_pcd_ep_t *ep;
47924 +
47925 + gintmsk_data_t intr_mask = {.d32 = 0 };
47926 +
47927 + DWC_SPINLOCK(pcd->lock);
47928 +
47929 + num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
47930 + num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
47931 +
47932 + DWC_DEBUGPL(DBG_PCDV, "%s() \n", __func__);
47933 + /* don't disconnect drivers more than once */
47934 + if (pcd->ep0state == EP0_DISCONNECT) {
47935 + DWC_DEBUGPL(DBG_ANY, "%s() Already Disconnected\n", __func__);
47936 + DWC_SPINUNLOCK(pcd->lock);
47937 + return;
47938 + }
47939 + pcd->ep0state = EP0_DISCONNECT;
47940 +
47941 + /* Reset the OTG state. */
47942 + dwc_otg_pcd_update_otg(pcd, 1);
47943 +
47944 + /* Disable the NP Tx Fifo Empty Interrupt. */
47945 + intr_mask.b.nptxfempty = 1;
47946 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
47947 + intr_mask.d32, 0);
47948 +
47949 + /* Flush the FIFOs */
47950 + /**@todo NGS Flush Periodic FIFOs */
47951 + dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), 0x10);
47952 + dwc_otg_flush_rx_fifo(GET_CORE_IF(pcd));
47953 +
47954 + /* prevent new request submissions, kill any outstanding requests */
47955 + ep = &pcd->ep0;
47956 + dwc_otg_request_nuke(ep);
47957 + /* prevent new request submissions, kill any outstanding requests */
47958 + for (i = 0; i < num_in_eps; i++) {
47959 + dwc_otg_pcd_ep_t *ep = &pcd->in_ep[i];
47960 + dwc_otg_request_nuke(ep);
47961 + }
47962 + /* prevent new request submissions, kill any outstanding requests */
47963 + for (i = 0; i < num_out_eps; i++) {
47964 + dwc_otg_pcd_ep_t *ep = &pcd->out_ep[i];
47965 + dwc_otg_request_nuke(ep);
47966 + }
47967 +
47968 + /* report disconnect; the driver is already quiesced */
47969 + if (pcd->fops->disconnect) {
47970 + DWC_SPINUNLOCK(pcd->lock);
47971 + pcd->fops->disconnect(pcd);
47972 + DWC_SPINLOCK(pcd->lock);
47973 + }
47974 + DWC_SPINUNLOCK(pcd->lock);
47975 +}
47976 +
47977 +/**
47978 + * This interrupt indicates that ...
47979 + */
47980 +int32_t dwc_otg_pcd_handle_i2c_intr(dwc_otg_pcd_t * pcd)
47981 +{
47982 + gintmsk_data_t intr_mask = {.d32 = 0 };
47983 + gintsts_data_t gintsts;
47984 +
47985 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "i2cintr");
47986 + intr_mask.b.i2cintr = 1;
47987 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
47988 + intr_mask.d32, 0);
47989 +
47990 + /* Clear interrupt */
47991 + gintsts.d32 = 0;
47992 + gintsts.b.i2cintr = 1;
47993 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
47994 + gintsts.d32);
47995 + return 1;
47996 +}
47997 +
47998 +/**
47999 + * This interrupt indicates that ...
48000 + */
48001 +int32_t dwc_otg_pcd_handle_early_suspend_intr(dwc_otg_pcd_t * pcd)
48002 +{
48003 + gintsts_data_t gintsts;
48004 +#if defined(VERBOSE)
48005 + DWC_PRINTF("Early Suspend Detected\n");
48006 +#endif
48007 +
48008 + /* Clear interrupt */
48009 + gintsts.d32 = 0;
48010 + gintsts.b.erlysuspend = 1;
48011 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48012 + gintsts.d32);
48013 + return 1;
48014 +}
48015 +
48016 +/**
48017 + * This function configures EPO to receive SETUP packets.
48018 + *
48019 + * @todo NGS: Update the comments from the HW FS.
48020 + *
48021 + * -# Program the following fields in the endpoint specific registers
48022 + * for Control OUT EP 0, in order to receive a setup packet
48023 + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
48024 + * setup packets)
48025 + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
48026 + * to back setup packets)
48027 + * - In DMA mode, DOEPDMA0 Register with a memory address to
48028 + * store any setup packets received
48029 + *
48030 + * @param core_if Programming view of DWC_otg controller.
48031 + * @param pcd Programming view of the PCD.
48032 + */
48033 +static inline void ep0_out_start(dwc_otg_core_if_t * core_if,
48034 + dwc_otg_pcd_t * pcd)
48035 +{
48036 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
48037 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
48038 + dwc_otg_dev_dma_desc_t *dma_desc;
48039 + depctl_data_t doepctl = {.d32 = 0 };
48040 +
48041 +#ifdef VERBOSE
48042 + DWC_DEBUGPL(DBG_PCDV, "%s() doepctl0=%0x\n", __func__,
48043 + DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
48044 +#endif
48045 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
48046 + doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
48047 + if (doepctl.b.epena) {
48048 + return;
48049 + }
48050 + }
48051 +
48052 + doeptsize0.b.supcnt = 3;
48053 + doeptsize0.b.pktcnt = 1;
48054 + doeptsize0.b.xfersize = 8 * 3;
48055 +
48056 + if (core_if->dma_enable) {
48057 + if (!core_if->dma_desc_enable) {
48058 + /** put here as for Hermes mode deptisz register should not be written */
48059 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
48060 + doeptsize0.d32);
48061 +
48062 + /** @todo dma needs to handle multiple setup packets (up to 3) */
48063 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
48064 + pcd->setup_pkt_dma_handle);
48065 + } else {
48066 + dev_if->setup_desc_index =
48067 + (dev_if->setup_desc_index + 1) & 1;
48068 + dma_desc =
48069 + dev_if->setup_desc_addr[dev_if->setup_desc_index];
48070 +
48071 + /** DMA Descriptor Setup */
48072 + dma_desc->status.b.bs = BS_HOST_BUSY;
48073 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
48074 + dma_desc->status.b.sr = 0;
48075 + dma_desc->status.b.mtrf = 0;
48076 + }
48077 + dma_desc->status.b.l = 1;
48078 + dma_desc->status.b.ioc = 1;
48079 + dma_desc->status.b.bytes = pcd->ep0.dwc_ep.maxpacket;
48080 + dma_desc->buf = pcd->setup_pkt_dma_handle;
48081 + dma_desc->status.b.sts = 0;
48082 + dma_desc->status.b.bs = BS_HOST_READY;
48083 +
48084 + /** DOEPDMA0 Register write */
48085 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
48086 + dev_if->dma_setup_desc_addr
48087 + [dev_if->setup_desc_index]);
48088 + }
48089 +
48090 + } else {
48091 + /** put here as for Hermes mode deptisz register should not be written */
48092 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
48093 + doeptsize0.d32);
48094 + }
48095 +
48096 + /** DOEPCTL0 Register write cnak will be set after setup interrupt */
48097 + doepctl.d32 = 0;
48098 + doepctl.b.epena = 1;
48099 + if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
48100 + doepctl.b.cnak = 1;
48101 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
48102 + } else {
48103 + DWC_MODIFY_REG32(&dev_if->out_ep_regs[0]->doepctl, 0, doepctl.d32);
48104 + }
48105 +
48106 +#ifdef VERBOSE
48107 + DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
48108 + DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
48109 + DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
48110 + DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
48111 +#endif
48112 +}
48113 +
48114 +/**
48115 + * This interrupt occurs when a USB Reset is detected. When the USB
48116 + * Reset Interrupt occurs the device state is set to DEFAULT and the
48117 + * EP0 state is set to IDLE.
48118 + * -# Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1)
48119 + * -# Unmask the following interrupt bits
48120 + * - DAINTMSK.INEP0 = 1 (Control 0 IN endpoint)
48121 + * - DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint)
48122 + * - DOEPMSK.SETUP = 1
48123 + * - DOEPMSK.XferCompl = 1
48124 + * - DIEPMSK.XferCompl = 1
48125 + * - DIEPMSK.TimeOut = 1
48126 + * -# Program the following fields in the endpoint specific registers
48127 + * for Control OUT EP 0, in order to receive a setup packet
48128 + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
48129 + * setup packets)
48130 + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
48131 + * to back setup packets)
48132 + * - In DMA mode, DOEPDMA0 Register with a memory address to
48133 + * store any setup packets received
48134 + * At this point, all the required initialization, except for enabling
48135 + * the control 0 OUT endpoint is done, for receiving SETUP packets.
48136 + */
48137 +int32_t dwc_otg_pcd_handle_usb_reset_intr(dwc_otg_pcd_t * pcd)
48138 +{
48139 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48140 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
48141 + depctl_data_t doepctl = {.d32 = 0 };
48142 + depctl_data_t diepctl = {.d32 = 0 };
48143 + daint_data_t daintmsk = {.d32 = 0 };
48144 + doepmsk_data_t doepmsk = {.d32 = 0 };
48145 + diepmsk_data_t diepmsk = {.d32 = 0 };
48146 + dcfg_data_t dcfg = {.d32 = 0 };
48147 + grstctl_t resetctl = {.d32 = 0 };
48148 + dctl_data_t dctl = {.d32 = 0 };
48149 + int i = 0;
48150 + gintsts_data_t gintsts;
48151 + pcgcctl_data_t power = {.d32 = 0 };
48152 +
48153 + power.d32 = DWC_READ_REG32(core_if->pcgcctl);
48154 + if (power.b.stoppclk) {
48155 + power.d32 = 0;
48156 + power.b.stoppclk = 1;
48157 + DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
48158 +
48159 + power.b.pwrclmp = 1;
48160 + DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
48161 +
48162 + power.b.rstpdwnmodule = 1;
48163 + DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
48164 + }
48165 +
48166 + core_if->lx_state = DWC_OTG_L0;
48167 +
48168 + DWC_PRINTF("USB RESET\n");
48169 +#ifdef DWC_EN_ISOC
48170 + for (i = 1; i < 16; ++i) {
48171 + dwc_otg_pcd_ep_t *ep;
48172 + dwc_ep_t *dwc_ep;
48173 + ep = get_in_ep(pcd, i);
48174 + if (ep != 0) {
48175 + dwc_ep = &ep->dwc_ep;
48176 + dwc_ep->next_frame = 0xffffffff;
48177 + }
48178 + }
48179 +#endif /* DWC_EN_ISOC */
48180 +
48181 + /* reset the HNP settings */
48182 + dwc_otg_pcd_update_otg(pcd, 1);
48183 +
48184 + /* Clear the Remote Wakeup Signalling */
48185 + dctl.b.rmtwkupsig = 1;
48186 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
48187 +
48188 + /* Set NAK for all OUT EPs */
48189 + doepctl.b.snak = 1;
48190 + for (i = 0; i <= dev_if->num_out_eps; i++) {
48191 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
48192 + }
48193 +
48194 + /* Flush the NP Tx FIFO */
48195 + dwc_otg_flush_tx_fifo(core_if, 0x10);
48196 + /* Flush the Learning Queue */
48197 + resetctl.b.intknqflsh = 1;
48198 + DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
48199 +
48200 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
48201 + core_if->start_predict = 0;
48202 + for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) {
48203 + core_if->nextep_seq[i] = 0xff; // 0xff - EP not active
48204 + }
48205 + core_if->nextep_seq[0] = 0;
48206 + core_if->first_in_nextep_seq = 0;
48207 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
48208 + diepctl.b.nextep = 0;
48209 + DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
48210 +
48211 + /* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
48212 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
48213 + dcfg.b.epmscnt = 2;
48214 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
48215 +
48216 + DWC_DEBUGPL(DBG_PCDV,
48217 + "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
48218 + __func__, core_if->first_in_nextep_seq);
48219 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
48220 + DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
48221 + }
48222 + }
48223 +
48224 + if (core_if->multiproc_int_enable) {
48225 + daintmsk.b.inep0 = 1;
48226 + daintmsk.b.outep0 = 1;
48227 + DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk,
48228 + daintmsk.d32);
48229 +
48230 + doepmsk.b.setup = 1;
48231 + doepmsk.b.xfercompl = 1;
48232 + doepmsk.b.ahberr = 1;
48233 + doepmsk.b.epdisabled = 1;
48234 +
48235 + if ((core_if->dma_desc_enable) ||
48236 + (core_if->dma_enable
48237 + && core_if->snpsid >= OTG_CORE_REV_3_00a)) {
48238 + doepmsk.b.stsphsercvd = 1;
48239 + }
48240 + if (core_if->dma_desc_enable)
48241 + doepmsk.b.bna = 1;
48242 +/*
48243 + doepmsk.b.babble = 1;
48244 + doepmsk.b.nyet = 1;
48245 +
48246 + if (core_if->dma_enable) {
48247 + doepmsk.b.nak = 1;
48248 + }
48249 +*/
48250 + DWC_WRITE_REG32(&dev_if->dev_global_regs->doepeachintmsk[0],
48251 + doepmsk.d32);
48252 +
48253 + diepmsk.b.xfercompl = 1;
48254 + diepmsk.b.timeout = 1;
48255 + diepmsk.b.epdisabled = 1;
48256 + diepmsk.b.ahberr = 1;
48257 + diepmsk.b.intknepmis = 1;
48258 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
48259 + diepmsk.b.intknepmis = 0;
48260 +
48261 +/* if (core_if->dma_desc_enable) {
48262 + diepmsk.b.bna = 1;
48263 + }
48264 +*/
48265 +/*
48266 + if (core_if->dma_enable) {
48267 + diepmsk.b.nak = 1;
48268 + }
48269 +*/
48270 + DWC_WRITE_REG32(&dev_if->dev_global_regs->diepeachintmsk[0],
48271 + diepmsk.d32);
48272 + } else {
48273 + daintmsk.b.inep0 = 1;
48274 + daintmsk.b.outep0 = 1;
48275 + DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk,
48276 + daintmsk.d32);
48277 +
48278 + doepmsk.b.setup = 1;
48279 + doepmsk.b.xfercompl = 1;
48280 + doepmsk.b.ahberr = 1;
48281 + doepmsk.b.epdisabled = 1;
48282 +
48283 + if ((core_if->dma_desc_enable) ||
48284 + (core_if->dma_enable
48285 + && core_if->snpsid >= OTG_CORE_REV_3_00a)) {
48286 + doepmsk.b.stsphsercvd = 1;
48287 + }
48288 + if (core_if->dma_desc_enable)
48289 + doepmsk.b.bna = 1;
48290 + DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, doepmsk.d32);
48291 +
48292 + diepmsk.b.xfercompl = 1;
48293 + diepmsk.b.timeout = 1;
48294 + diepmsk.b.epdisabled = 1;
48295 + diepmsk.b.ahberr = 1;
48296 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
48297 + diepmsk.b.intknepmis = 0;
48298 +/*
48299 + if (core_if->dma_desc_enable) {
48300 + diepmsk.b.bna = 1;
48301 + }
48302 +*/
48303 +
48304 + DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, diepmsk.d32);
48305 + }
48306 +
48307 + /* Reset Device Address */
48308 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
48309 + dcfg.b.devaddr = 0;
48310 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
48311 +
48312 + /* setup EP0 to receive SETUP packets */
48313 + if (core_if->snpsid <= OTG_CORE_REV_2_94a)
48314 + ep0_out_start(core_if, pcd);
48315 +
48316 + /* Clear interrupt */
48317 + gintsts.d32 = 0;
48318 + gintsts.b.usbreset = 1;
48319 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
48320 +
48321 + return 1;
48322 +}
48323 +
48324 +/**
48325 + * Get the device speed from the device status register and convert it
48326 + * to USB speed constant.
48327 + *
48328 + * @param core_if Programming view of DWC_otg controller.
48329 + */
48330 +static int get_device_speed(dwc_otg_core_if_t * core_if)
48331 +{
48332 + dsts_data_t dsts;
48333 + int speed = 0;
48334 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
48335 +
48336 + switch (dsts.b.enumspd) {
48337 + case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
48338 + speed = USB_SPEED_HIGH;
48339 + break;
48340 + case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
48341 + case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
48342 + speed = USB_SPEED_FULL;
48343 + break;
48344 +
48345 + case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
48346 + speed = USB_SPEED_LOW;
48347 + break;
48348 + }
48349 +
48350 + return speed;
48351 +}
48352 +
48353 +/**
48354 + * Read the device status register and set the device speed in the
48355 + * data structure.
48356 + * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate.
48357 + */
48358 +int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t * pcd)
48359 +{
48360 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48361 + gintsts_data_t gintsts;
48362 + gusbcfg_data_t gusbcfg;
48363 + dwc_otg_core_global_regs_t *global_regs =
48364 + GET_CORE_IF(pcd)->core_global_regs;
48365 + uint8_t utmi16b, utmi8b;
48366 + int speed;
48367 + DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n");
48368 +
48369 + if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_2_60a) {
48370 + utmi16b = 6; //vahrama old value was 6;
48371 + utmi8b = 9;
48372 + } else {
48373 + utmi16b = 4;
48374 + utmi8b = 8;
48375 + }
48376 + dwc_otg_ep0_activate(GET_CORE_IF(pcd), &ep0->dwc_ep);
48377 + if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a) {
48378 + ep0_out_start(GET_CORE_IF(pcd), pcd);
48379 + }
48380 +
48381 +#ifdef DEBUG_EP0
48382 + print_ep0_state(pcd);
48383 +#endif
48384 +
48385 + if (pcd->ep0state == EP0_DISCONNECT) {
48386 + pcd->ep0state = EP0_IDLE;
48387 + } else if (pcd->ep0state == EP0_STALL) {
48388 + pcd->ep0state = EP0_IDLE;
48389 + }
48390 +
48391 + pcd->ep0state = EP0_IDLE;
48392 +
48393 + ep0->stopped = 0;
48394 +
48395 + speed = get_device_speed(GET_CORE_IF(pcd));
48396 + pcd->fops->connect(pcd, speed);
48397 +
48398 + /* Set USB turnaround time based on device speed and PHY interface. */
48399 + gusbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
48400 + if (speed == USB_SPEED_HIGH) {
48401 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
48402 + DWC_HWCFG2_HS_PHY_TYPE_ULPI) {
48403 + /* ULPI interface */
48404 + gusbcfg.b.usbtrdtim = 9;
48405 + }
48406 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
48407 + DWC_HWCFG2_HS_PHY_TYPE_UTMI) {
48408 + /* UTMI+ interface */
48409 + if (GET_CORE_IF(pcd)->hwcfg4.b.utmi_phy_data_width == 0) {
48410 + gusbcfg.b.usbtrdtim = utmi8b;
48411 + } else if (GET_CORE_IF(pcd)->hwcfg4.
48412 + b.utmi_phy_data_width == 1) {
48413 + gusbcfg.b.usbtrdtim = utmi16b;
48414 + } else if (GET_CORE_IF(pcd)->
48415 + core_params->phy_utmi_width == 8) {
48416 + gusbcfg.b.usbtrdtim = utmi8b;
48417 + } else {
48418 + gusbcfg.b.usbtrdtim = utmi16b;
48419 + }
48420 + }
48421 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
48422 + DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) {
48423 + /* UTMI+ OR ULPI interface */
48424 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
48425 + /* ULPI interface */
48426 + gusbcfg.b.usbtrdtim = 9;
48427 + } else {
48428 + /* UTMI+ interface */
48429 + if (GET_CORE_IF(pcd)->
48430 + core_params->phy_utmi_width == 16) {
48431 + gusbcfg.b.usbtrdtim = utmi16b;
48432 + } else {
48433 + gusbcfg.b.usbtrdtim = utmi8b;
48434 + }
48435 + }
48436 + }
48437 + } else {
48438 + /* Full or low speed */
48439 + gusbcfg.b.usbtrdtim = 9;
48440 + }
48441 + DWC_WRITE_REG32(&global_regs->gusbcfg, gusbcfg.d32);
48442 +
48443 + /* Clear interrupt */
48444 + gintsts.d32 = 0;
48445 + gintsts.b.enumdone = 1;
48446 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48447 + gintsts.d32);
48448 + return 1;
48449 +}
48450 +
48451 +/**
48452 + * This interrupt indicates that the ISO OUT Packet was dropped due to
48453 + * Rx FIFO full or Rx Status Queue Full. If this interrupt occurs
48454 + * read all the data from the Rx FIFO.
48455 + */
48456 +int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr(dwc_otg_pcd_t * pcd)
48457 +{
48458 + gintmsk_data_t intr_mask = {.d32 = 0 };
48459 + gintsts_data_t gintsts;
48460 +
48461 + DWC_WARN("INTERRUPT Handler not implemented for %s\n",
48462 + "ISOC Out Dropped");
48463 +
48464 + intr_mask.b.isooutdrop = 1;
48465 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
48466 + intr_mask.d32, 0);
48467 +
48468 + /* Clear interrupt */
48469 + gintsts.d32 = 0;
48470 + gintsts.b.isooutdrop = 1;
48471 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48472 + gintsts.d32);
48473 +
48474 + return 1;
48475 +}
48476 +
48477 +/**
48478 + * This interrupt indicates the end of the portion of the micro-frame
48479 + * for periodic transactions. If there is a periodic transaction for
48480 + * the next frame, load the packets into the EP periodic Tx FIFO.
48481 + */
48482 +int32_t dwc_otg_pcd_handle_end_periodic_frame_intr(dwc_otg_pcd_t * pcd)
48483 +{
48484 + gintmsk_data_t intr_mask = {.d32 = 0 };
48485 + gintsts_data_t gintsts;
48486 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "EOP");
48487 +
48488 + intr_mask.b.eopframe = 1;
48489 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
48490 + intr_mask.d32, 0);
48491 +
48492 + /* Clear interrupt */
48493 + gintsts.d32 = 0;
48494 + gintsts.b.eopframe = 1;
48495 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48496 + gintsts.d32);
48497 +
48498 + return 1;
48499 +}
48500 +
48501 +/**
48502 + * This interrupt indicates that EP of the packet on the top of the
48503 + * non-periodic Tx FIFO does not match EP of the IN Token received.
48504 + *
48505 + * The "Device IN Token Queue" Registers are read to determine the
48506 + * order the IN Tokens have been received. The non-periodic Tx FIFO
48507 + * is flushed, so it can be reloaded in the order seen in the IN Token
48508 + * Queue.
48509 + */
48510 +int32_t dwc_otg_pcd_handle_ep_mismatch_intr(dwc_otg_pcd_t * pcd)
48511 +{
48512 + gintsts_data_t gintsts;
48513 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48514 + dctl_data_t dctl;
48515 + gintmsk_data_t intr_mask = {.d32 = 0 };
48516 +
48517 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable) {
48518 + core_if->start_predict = 1;
48519 +
48520 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
48521 +
48522 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
48523 + if (!gintsts.b.ginnakeff) {
48524 + /* Disable EP Mismatch interrupt */
48525 + intr_mask.d32 = 0;
48526 + intr_mask.b.epmismatch = 1;
48527 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
48528 + /* Enable the Global IN NAK Effective Interrupt */
48529 + intr_mask.d32 = 0;
48530 + intr_mask.b.ginnakeff = 1;
48531 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
48532 + /* Set the global non-periodic IN NAK handshake */
48533 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
48534 + dctl.b.sgnpinnak = 1;
48535 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
48536 + } else {
48537 + DWC_PRINTF("gintsts.b.ginnakeff = 1! dctl.b.sgnpinnak not set\n");
48538 + }
48539 + /* Disabling of all EP's will be done in dwc_otg_pcd_handle_in_nak_effective()
48540 + * handler after Global IN NAK Effective interrupt will be asserted */
48541 + }
48542 + /* Clear interrupt */
48543 + gintsts.d32 = 0;
48544 + gintsts.b.epmismatch = 1;
48545 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
48546 +
48547 + return 1;
48548 +}
48549 +
48550 +/**
48551 + * This interrupt is valid only in DMA mode. This interrupt indicates that the
48552 + * core has stopped fetching data for IN endpoints due to the unavailability of
48553 + * TxFIFO space or Request Queue space. This interrupt is used by the
48554 + * application for an endpoint mismatch algorithm.
48555 + *
48556 + * @param pcd The PCD
48557 + */
48558 +int32_t dwc_otg_pcd_handle_ep_fetsusp_intr(dwc_otg_pcd_t * pcd)
48559 +{
48560 + gintsts_data_t gintsts;
48561 + gintmsk_data_t gintmsk_data;
48562 + dctl_data_t dctl;
48563 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48564 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
48565 +
48566 + /* Clear the global non-periodic IN NAK handshake */
48567 + dctl.d32 = 0;
48568 + dctl.b.cgnpinnak = 1;
48569 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
48570 +
48571 + /* Mask GINTSTS.FETSUSP interrupt */
48572 + gintmsk_data.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
48573 + gintmsk_data.b.fetsusp = 0;
48574 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk_data.d32);
48575 +
48576 + /* Clear interrupt */
48577 + gintsts.d32 = 0;
48578 + gintsts.b.fetsusp = 1;
48579 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
48580 +
48581 + return 1;
48582 +}
48583 +/**
48584 + * This funcion stalls EP0.
48585 + */
48586 +static inline void ep0_do_stall(dwc_otg_pcd_t * pcd, const int err_val)
48587 +{
48588 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48589 + usb_device_request_t *ctrl = &pcd->setup_pkt->req;
48590 + DWC_WARN("req %02x.%02x protocol STALL; err %d\n",
48591 + ctrl->bmRequestType, ctrl->bRequest, err_val);
48592 +
48593 + ep0->dwc_ep.is_in = 1;
48594 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep0->dwc_ep);
48595 + pcd->ep0.stopped = 1;
48596 + pcd->ep0state = EP0_IDLE;
48597 + ep0_out_start(GET_CORE_IF(pcd), pcd);
48598 +}
48599 +
48600 +/**
48601 + * This functions delegates the setup command to the gadget driver.
48602 + */
48603 +static inline void do_gadget_setup(dwc_otg_pcd_t * pcd,
48604 + usb_device_request_t * ctrl)
48605 +{
48606 + int ret = 0;
48607 + DWC_SPINUNLOCK(pcd->lock);
48608 + ret = pcd->fops->setup(pcd, (uint8_t *) ctrl);
48609 + DWC_SPINLOCK(pcd->lock);
48610 + if (ret < 0) {
48611 + ep0_do_stall(pcd, ret);
48612 + }
48613 +
48614 + /** @todo This is a g_file_storage gadget driver specific
48615 + * workaround: a DELAYED_STATUS result from the fsg_setup
48616 + * routine will result in the gadget queueing a EP0 IN status
48617 + * phase for a two-stage control transfer. Exactly the same as
48618 + * a SET_CONFIGURATION/SET_INTERFACE except that this is a class
48619 + * specific request. Need a generic way to know when the gadget
48620 + * driver will queue the status phase. Can we assume when we
48621 + * call the gadget driver setup() function that it will always
48622 + * queue and require the following flag? Need to look into
48623 + * this.
48624 + */
48625 +
48626 + if (ret == 256 + 999) {
48627 + pcd->request_config = 1;
48628 + }
48629 +}
48630 +
48631 +#ifdef DWC_UTE_CFI
48632 +/**
48633 + * This functions delegates the CFI setup commands to the gadget driver.
48634 + * This function will return a negative value to indicate a failure.
48635 + */
48636 +static inline int cfi_gadget_setup(dwc_otg_pcd_t * pcd,
48637 + struct cfi_usb_ctrlrequest *ctrl_req)
48638 +{
48639 + int ret = 0;
48640 +
48641 + if (pcd->fops && pcd->fops->cfi_setup) {
48642 + DWC_SPINUNLOCK(pcd->lock);
48643 + ret = pcd->fops->cfi_setup(pcd, ctrl_req);
48644 + DWC_SPINLOCK(pcd->lock);
48645 + if (ret < 0) {
48646 + ep0_do_stall(pcd, ret);
48647 + return ret;
48648 + }
48649 + }
48650 +
48651 + return ret;
48652 +}
48653 +#endif
48654 +
48655 +/**
48656 + * This function starts the Zero-Length Packet for the IN status phase
48657 + * of a 2 stage control transfer.
48658 + */
48659 +static inline void do_setup_in_status_phase(dwc_otg_pcd_t * pcd)
48660 +{
48661 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48662 + if (pcd->ep0state == EP0_STALL) {
48663 + return;
48664 + }
48665 +
48666 + pcd->ep0state = EP0_IN_STATUS_PHASE;
48667 +
48668 + /* Prepare for more SETUP Packets */
48669 + DWC_DEBUGPL(DBG_PCD, "EP0 IN ZLP\n");
48670 + if ((GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a)
48671 + && (pcd->core_if->dma_desc_enable)
48672 + && (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len)) {
48673 + DWC_DEBUGPL(DBG_PCDV,
48674 + "Data terminated wait next packet in out_desc_addr\n");
48675 + pcd->backup_buf = phys_to_virt(ep0->dwc_ep.dma_addr);
48676 + pcd->data_terminated = 1;
48677 + }
48678 + ep0->dwc_ep.xfer_len = 0;
48679 + ep0->dwc_ep.xfer_count = 0;
48680 + ep0->dwc_ep.is_in = 1;
48681 + ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
48682 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
48683 +
48684 + /* Prepare for more SETUP Packets */
48685 + //ep0_out_start(GET_CORE_IF(pcd), pcd);
48686 +}
48687 +
48688 +/**
48689 + * This function starts the Zero-Length Packet for the OUT status phase
48690 + * of a 2 stage control transfer.
48691 + */
48692 +static inline void do_setup_out_status_phase(dwc_otg_pcd_t * pcd)
48693 +{
48694 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48695 + if (pcd->ep0state == EP0_STALL) {
48696 + DWC_DEBUGPL(DBG_PCD, "EP0 STALLED\n");
48697 + return;
48698 + }
48699 + pcd->ep0state = EP0_OUT_STATUS_PHASE;
48700 +
48701 + DWC_DEBUGPL(DBG_PCD, "EP0 OUT ZLP\n");
48702 + ep0->dwc_ep.xfer_len = 0;
48703 + ep0->dwc_ep.xfer_count = 0;
48704 + ep0->dwc_ep.is_in = 0;
48705 + ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
48706 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
48707 +
48708 + /* Prepare for more SETUP Packets */
48709 + if (GET_CORE_IF(pcd)->dma_enable == 0) {
48710 + ep0_out_start(GET_CORE_IF(pcd), pcd);
48711 + }
48712 +}
48713 +
48714 +/**
48715 + * Clear the EP halt (STALL) and if pending requests start the
48716 + * transfer.
48717 + */
48718 +static inline void pcd_clear_halt(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
48719 +{
48720 + if (ep->dwc_ep.stall_clear_flag == 0)
48721 + dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
48722 +
48723 + /* Reactive the EP */
48724 + dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
48725 + if (ep->stopped) {
48726 + ep->stopped = 0;
48727 + /* If there is a request in the EP queue start it */
48728 +
48729 + /** @todo FIXME: this causes an EP mismatch in DMA mode.
48730 + * epmismatch not yet implemented. */
48731 +
48732 + /*
48733 + * Above fixme is solved by implmenting a tasklet to call the
48734 + * start_next_request(), outside of interrupt context at some
48735 + * time after the current time, after a clear-halt setup packet.
48736 + * Still need to implement ep mismatch in the future if a gadget
48737 + * ever uses more than one endpoint at once
48738 + */
48739 + ep->queue_sof = 1;
48740 + DWC_TASK_SCHEDULE(pcd->start_xfer_tasklet);
48741 + }
48742 + /* Start Control Status Phase */
48743 + do_setup_in_status_phase(pcd);
48744 +}
48745 +
48746 +/**
48747 + * This function is called when the SET_FEATURE TEST_MODE Setup packet
48748 + * is sent from the host. The Device Control register is written with
48749 + * the Test Mode bits set to the specified Test Mode. This is done as
48750 + * a tasklet so that the "Status" phase of the control transfer
48751 + * completes before transmitting the TEST packets.
48752 + *
48753 + * @todo This has not been tested since the tasklet struct was put
48754 + * into the PCD struct!
48755 + *
48756 + */
48757 +void do_test_mode(void *data)
48758 +{
48759 + dctl_data_t dctl;
48760 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
48761 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48762 + int test_mode = pcd->test_mode;
48763 +
48764 +// DWC_WARN("%s() has not been tested since being rewritten!\n", __func__);
48765 +
48766 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
48767 + switch (test_mode) {
48768 + case 1: // TEST_J
48769 + dctl.b.tstctl = 1;
48770 + break;
48771 +
48772 + case 2: // TEST_K
48773 + dctl.b.tstctl = 2;
48774 + break;
48775 +
48776 + case 3: // TEST_SE0_NAK
48777 + dctl.b.tstctl = 3;
48778 + break;
48779 +
48780 + case 4: // TEST_PACKET
48781 + dctl.b.tstctl = 4;
48782 + break;
48783 +
48784 + case 5: // TEST_FORCE_ENABLE
48785 + dctl.b.tstctl = 5;
48786 + break;
48787 + }
48788 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
48789 +}
48790 +
48791 +/**
48792 + * This function process the GET_STATUS Setup Commands.
48793 + */
48794 +static inline void do_get_status(dwc_otg_pcd_t * pcd)
48795 +{
48796 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48797 + dwc_otg_pcd_ep_t *ep;
48798 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48799 + uint16_t *status = pcd->status_buf;
48800 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48801 +
48802 +#ifdef DEBUG_EP0
48803 + DWC_DEBUGPL(DBG_PCD,
48804 + "GET_STATUS %02x.%02x v%04x i%04x l%04x\n",
48805 + ctrl.bmRequestType, ctrl.bRequest,
48806 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
48807 + UGETW(ctrl.wLength));
48808 +#endif
48809 +
48810 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
48811 + case UT_DEVICE:
48812 + if(UGETW(ctrl.wIndex) == 0xF000) { /* OTG Status selector */
48813 + DWC_PRINTF("wIndex - %d\n", UGETW(ctrl.wIndex));
48814 + DWC_PRINTF("OTG VERSION - %d\n", core_if->otg_ver);
48815 + DWC_PRINTF("OTG CAP - %d, %d\n",
48816 + core_if->core_params->otg_cap,
48817 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
48818 + if (core_if->otg_ver == 1
48819 + && core_if->core_params->otg_cap ==
48820 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48821 + uint8_t *otgsts = (uint8_t*)pcd->status_buf;
48822 + *otgsts = (core_if->otg_sts & 0x1);
48823 + pcd->ep0_pending = 1;
48824 + ep0->dwc_ep.start_xfer_buff =
48825 + (uint8_t *) otgsts;
48826 + ep0->dwc_ep.xfer_buff = (uint8_t *) otgsts;
48827 + ep0->dwc_ep.dma_addr =
48828 + pcd->status_buf_dma_handle;
48829 + ep0->dwc_ep.xfer_len = 1;
48830 + ep0->dwc_ep.xfer_count = 0;
48831 + ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
48832 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
48833 + &ep0->dwc_ep);
48834 + return;
48835 + } else {
48836 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48837 + return;
48838 + }
48839 + break;
48840 + } else {
48841 + *status = 0x1; /* Self powered */
48842 + *status |= pcd->remote_wakeup_enable << 1;
48843 + break;
48844 + }
48845 + case UT_INTERFACE:
48846 + *status = 0;
48847 + break;
48848 +
48849 + case UT_ENDPOINT:
48850 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
48851 + if (ep == 0 || UGETW(ctrl.wLength) > 2) {
48852 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48853 + return;
48854 + }
48855 + /** @todo check for EP stall */
48856 + *status = ep->stopped;
48857 + break;
48858 + }
48859 + pcd->ep0_pending = 1;
48860 + ep0->dwc_ep.start_xfer_buff = (uint8_t *) status;
48861 + ep0->dwc_ep.xfer_buff = (uint8_t *) status;
48862 + ep0->dwc_ep.dma_addr = pcd->status_buf_dma_handle;
48863 + ep0->dwc_ep.xfer_len = 2;
48864 + ep0->dwc_ep.xfer_count = 0;
48865 + ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
48866 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
48867 +}
48868 +
48869 +/**
48870 + * This function process the SET_FEATURE Setup Commands.
48871 + */
48872 +static inline void do_set_feature(dwc_otg_pcd_t * pcd)
48873 +{
48874 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48875 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
48876 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48877 + dwc_otg_pcd_ep_t *ep = 0;
48878 + int32_t otg_cap_param = core_if->core_params->otg_cap;
48879 + gotgctl_data_t gotgctl = {.d32 = 0 };
48880 +
48881 + DWC_DEBUGPL(DBG_PCD, "SET_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
48882 + ctrl.bmRequestType, ctrl.bRequest,
48883 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
48884 + UGETW(ctrl.wLength));
48885 + DWC_DEBUGPL(DBG_PCD, "otg_cap=%d\n", otg_cap_param);
48886 +
48887 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
48888 + case UT_DEVICE:
48889 + switch (UGETW(ctrl.wValue)) {
48890 + case UF_DEVICE_REMOTE_WAKEUP:
48891 + pcd->remote_wakeup_enable = 1;
48892 + break;
48893 +
48894 + case UF_TEST_MODE:
48895 + /* Setup the Test Mode tasklet to do the Test
48896 + * Packet generation after the SETUP Status
48897 + * phase has completed. */
48898 +
48899 + /** @todo This has not been tested since the
48900 + * tasklet struct was put into the PCD
48901 + * struct! */
48902 + pcd->test_mode = UGETW(ctrl.wIndex) >> 8;
48903 + DWC_TASK_SCHEDULE(pcd->test_mode_tasklet);
48904 + break;
48905 +
48906 + case UF_DEVICE_B_HNP_ENABLE:
48907 + DWC_DEBUGPL(DBG_PCDV,
48908 + "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
48909 +
48910 + /* dev may initiate HNP */
48911 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48912 + pcd->b_hnp_enable = 1;
48913 + dwc_otg_pcd_update_otg(pcd, 0);
48914 + DWC_DEBUGPL(DBG_PCD, "Request B HNP\n");
48915 + /**@todo Is the gotgctl.devhnpen cleared
48916 + * by a USB Reset? */
48917 + gotgctl.b.devhnpen = 1;
48918 + gotgctl.b.hnpreq = 1;
48919 + DWC_WRITE_REG32(&global_regs->gotgctl,
48920 + gotgctl.d32);
48921 + } else {
48922 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48923 + return;
48924 + }
48925 + break;
48926 +
48927 + case UF_DEVICE_A_HNP_SUPPORT:
48928 + /* RH port supports HNP */
48929 + DWC_DEBUGPL(DBG_PCDV,
48930 + "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n");
48931 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48932 + pcd->a_hnp_support = 1;
48933 + dwc_otg_pcd_update_otg(pcd, 0);
48934 + } else {
48935 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48936 + return;
48937 + }
48938 + break;
48939 +
48940 + case UF_DEVICE_A_ALT_HNP_SUPPORT:
48941 + /* other RH port does */
48942 + DWC_DEBUGPL(DBG_PCDV,
48943 + "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
48944 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48945 + pcd->a_alt_hnp_support = 1;
48946 + dwc_otg_pcd_update_otg(pcd, 0);
48947 + } else {
48948 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48949 + return;
48950 + }
48951 + break;
48952 +
48953 + default:
48954 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48955 + return;
48956 +
48957 + }
48958 + do_setup_in_status_phase(pcd);
48959 + break;
48960 +
48961 + case UT_INTERFACE:
48962 + do_gadget_setup(pcd, &ctrl);
48963 + break;
48964 +
48965 + case UT_ENDPOINT:
48966 + if (UGETW(ctrl.wValue) == UF_ENDPOINT_HALT) {
48967 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
48968 + if (ep == 0) {
48969 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48970 + return;
48971 + }
48972 + ep->stopped = 1;
48973 + dwc_otg_ep_set_stall(core_if, &ep->dwc_ep);
48974 + }
48975 + do_setup_in_status_phase(pcd);
48976 + break;
48977 + }
48978 +}
48979 +
48980 +/**
48981 + * This function process the CLEAR_FEATURE Setup Commands.
48982 + */
48983 +static inline void do_clear_feature(dwc_otg_pcd_t * pcd)
48984 +{
48985 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48986 + dwc_otg_pcd_ep_t *ep = 0;
48987 +
48988 + DWC_DEBUGPL(DBG_PCD,
48989 + "CLEAR_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
48990 + ctrl.bmRequestType, ctrl.bRequest,
48991 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
48992 + UGETW(ctrl.wLength));
48993 +
48994 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
48995 + case UT_DEVICE:
48996 + switch (UGETW(ctrl.wValue)) {
48997 + case UF_DEVICE_REMOTE_WAKEUP:
48998 + pcd->remote_wakeup_enable = 0;
48999 + break;
49000 +
49001 + case UF_TEST_MODE:
49002 + /** @todo Add CLEAR_FEATURE for TEST modes. */
49003 + break;
49004 +
49005 + default:
49006 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
49007 + return;
49008 + }
49009 + do_setup_in_status_phase(pcd);
49010 + break;
49011 +
49012 + case UT_ENDPOINT:
49013 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
49014 + if (ep == 0) {
49015 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
49016 + return;
49017 + }
49018 +
49019 + pcd_clear_halt(pcd, ep);
49020 +
49021 + break;
49022 + }
49023 +}
49024 +
49025 +/**
49026 + * This function process the SET_ADDRESS Setup Commands.
49027 + */
49028 +static inline void do_set_address(dwc_otg_pcd_t * pcd)
49029 +{
49030 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
49031 + usb_device_request_t ctrl = pcd->setup_pkt->req;
49032 +
49033 + if (ctrl.bmRequestType == UT_DEVICE) {
49034 + dcfg_data_t dcfg = {.d32 = 0 };
49035 +
49036 +#ifdef DEBUG_EP0
49037 +// DWC_DEBUGPL(DBG_PCDV, "SET_ADDRESS:%d\n", ctrl.wValue);
49038 +#endif
49039 + dcfg.b.devaddr = UGETW(ctrl.wValue);
49040 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dcfg, 0, dcfg.d32);
49041 + do_setup_in_status_phase(pcd);
49042 + }
49043 +}
49044 +
49045 +/**
49046 + * This function processes SETUP commands. In Linux, the USB Command
49047 + * processing is done in two places - the first being the PCD and the
49048 + * second in the Gadget Driver (for example, the File-Backed Storage
49049 + * Gadget Driver).
49050 + *
49051 + * <table>
49052 + * <tr><td>Command </td><td>Driver </td><td>Description</td></tr>
49053 + *
49054 + * <tr><td>GET_STATUS </td><td>PCD </td><td>Command is processed as
49055 + * defined in chapter 9 of the USB 2.0 Specification chapter 9
49056 + * </td></tr>
49057 + *
49058 + * <tr><td>CLEAR_FEATURE </td><td>PCD </td><td>The Device and Endpoint
49059 + * requests are the ENDPOINT_HALT feature is procesed, all others the
49060 + * interface requests are ignored.</td></tr>
49061 + *
49062 + * <tr><td>SET_FEATURE </td><td>PCD </td><td>The Device and Endpoint
49063 + * requests are processed by the PCD. Interface requests are passed
49064 + * to the Gadget Driver.</td></tr>
49065 + *
49066 + * <tr><td>SET_ADDRESS </td><td>PCD </td><td>Program the DCFG reg,
49067 + * with device address received </td></tr>
49068 + *
49069 + * <tr><td>GET_DESCRIPTOR </td><td>Gadget Driver </td><td>Return the
49070 + * requested descriptor</td></tr>
49071 + *
49072 + * <tr><td>SET_DESCRIPTOR </td><td>Gadget Driver </td><td>Optional -
49073 + * not implemented by any of the existing Gadget Drivers.</td></tr>
49074 + *
49075 + * <tr><td>SET_CONFIGURATION </td><td>Gadget Driver </td><td>Disable
49076 + * all EPs and enable EPs for new configuration.</td></tr>
49077 + *
49078 + * <tr><td>GET_CONFIGURATION </td><td>Gadget Driver </td><td>Return
49079 + * the current configuration</td></tr>
49080 + *
49081 + * <tr><td>SET_INTERFACE </td><td>Gadget Driver </td><td>Disable all
49082 + * EPs and enable EPs for new configuration.</td></tr>
49083 + *
49084 + * <tr><td>GET_INTERFACE </td><td>Gadget Driver </td><td>Return the
49085 + * current interface.</td></tr>
49086 + *
49087 + * <tr><td>SYNC_FRAME </td><td>PCD </td><td>Display debug
49088 + * message.</td></tr>
49089 + * </table>
49090 + *
49091 + * When the SETUP Phase Done interrupt occurs, the PCD SETUP commands are
49092 + * processed by pcd_setup. Calling the Function Driver's setup function from
49093 + * pcd_setup processes the gadget SETUP commands.
49094 + */
49095 +static inline void pcd_setup(dwc_otg_pcd_t * pcd)
49096 +{
49097 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
49098 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
49099 + usb_device_request_t ctrl = pcd->setup_pkt->req;
49100 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
49101 +
49102 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
49103 +
49104 +#ifdef DWC_UTE_CFI
49105 + int retval = 0;
49106 + struct cfi_usb_ctrlrequest cfi_req;
49107 +#endif
49108 +
49109 + doeptsize0.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doeptsiz);
49110 +
49111 + /** In BDMA more then 1 setup packet is not supported till 3.00a */
49112 + if (core_if->dma_enable && core_if->dma_desc_enable == 0
49113 + && (doeptsize0.b.supcnt < 2)
49114 + && (core_if->snpsid < OTG_CORE_REV_2_94a)) {
49115 + DWC_ERROR
49116 + ("\n\n----------- CANNOT handle > 1 setup packet in DMA mode\n\n");
49117 + }
49118 + if ((core_if->snpsid >= OTG_CORE_REV_3_00a)
49119 + && (core_if->dma_enable == 1) && (core_if->dma_desc_enable == 0)) {
49120 + ctrl =
49121 + (pcd->setup_pkt +
49122 + (3 - doeptsize0.b.supcnt - 1 +
49123 + ep0->dwc_ep.stp_rollover))->req;
49124 + }
49125 +#ifdef DEBUG_EP0
49126 + DWC_DEBUGPL(DBG_PCD, "SETUP %02x.%02x v%04x i%04x l%04x\n",
49127 + ctrl.bmRequestType, ctrl.bRequest,
49128 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
49129 + UGETW(ctrl.wLength));
49130 +#endif
49131 +
49132 + /* Clean up the request queue */
49133 + dwc_otg_request_nuke(ep0);
49134 + ep0->stopped = 0;
49135 +
49136 + if (ctrl.bmRequestType & UE_DIR_IN) {
49137 + ep0->dwc_ep.is_in = 1;
49138 + pcd->ep0state = EP0_IN_DATA_PHASE;
49139 + } else {
49140 + ep0->dwc_ep.is_in = 0;
49141 + pcd->ep0state = EP0_OUT_DATA_PHASE;
49142 + }
49143 +
49144 + if (UGETW(ctrl.wLength) == 0) {
49145 + ep0->dwc_ep.is_in = 1;
49146 + pcd->ep0state = EP0_IN_STATUS_PHASE;
49147 + }
49148 +
49149 + if (UT_GET_TYPE(ctrl.bmRequestType) != UT_STANDARD) {
49150 +
49151 +#ifdef DWC_UTE_CFI
49152 + DWC_MEMCPY(&cfi_req, &ctrl, sizeof(usb_device_request_t));
49153 +
49154 + //printk(KERN_ALERT "CFI: req_type=0x%02x; req=0x%02x\n",
49155 + ctrl.bRequestType, ctrl.bRequest);
49156 + if (UT_GET_TYPE(cfi_req.bRequestType) == UT_VENDOR) {
49157 + if (cfi_req.bRequest > 0xB0 && cfi_req.bRequest < 0xBF) {
49158 + retval = cfi_setup(pcd, &cfi_req);
49159 + if (retval < 0) {
49160 + ep0_do_stall(pcd, retval);
49161 + pcd->ep0_pending = 0;
49162 + return;
49163 + }
49164 +
49165 + /* if need gadget setup then call it and check the retval */
49166 + if (pcd->cfi->need_gadget_att) {
49167 + retval =
49168 + cfi_gadget_setup(pcd,
49169 + &pcd->
49170 + cfi->ctrl_req);
49171 + if (retval < 0) {
49172 + pcd->ep0_pending = 0;
49173 + return;
49174 + }
49175 + }
49176 +
49177 + if (pcd->cfi->need_status_in_complete) {
49178 + do_setup_in_status_phase(pcd);
49179 + }
49180 + return;
49181 + }
49182 + }
49183 +#endif
49184 +
49185 + /* handle non-standard (class/vendor) requests in the gadget driver */
49186 + do_gadget_setup(pcd, &ctrl);
49187 + return;
49188 + }
49189 +
49190 + /** @todo NGS: Handle bad setup packet? */
49191 +
49192 +///////////////////////////////////////////
49193 +//// --- Standard Request handling --- ////
49194 +
49195 + switch (ctrl.bRequest) {
49196 + case UR_GET_STATUS:
49197 + do_get_status(pcd);
49198 + break;
49199 +
49200 + case UR_CLEAR_FEATURE:
49201 + do_clear_feature(pcd);
49202 + break;
49203 +
49204 + case UR_SET_FEATURE:
49205 + do_set_feature(pcd);
49206 + break;
49207 +
49208 + case UR_SET_ADDRESS:
49209 + do_set_address(pcd);
49210 + break;
49211 +
49212 + case UR_SET_INTERFACE:
49213 + case UR_SET_CONFIG:
49214 +// _pcd->request_config = 1; /* Configuration changed */
49215 + do_gadget_setup(pcd, &ctrl);
49216 + break;
49217 +
49218 + case UR_SYNCH_FRAME:
49219 + do_gadget_setup(pcd, &ctrl);
49220 + break;
49221 +
49222 + default:
49223 + /* Call the Gadget Driver's setup functions */
49224 + do_gadget_setup(pcd, &ctrl);
49225 + break;
49226 + }
49227 +}
49228 +
49229 +/**
49230 + * This function completes the ep0 control transfer.
49231 + */
49232 +static int32_t ep0_complete_request(dwc_otg_pcd_ep_t * ep)
49233 +{
49234 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
49235 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
49236 + dwc_otg_dev_in_ep_regs_t *in_ep_regs =
49237 + dev_if->in_ep_regs[ep->dwc_ep.num];
49238 +#ifdef DEBUG_EP0
49239 + dwc_otg_dev_out_ep_regs_t *out_ep_regs =
49240 + dev_if->out_ep_regs[ep->dwc_ep.num];
49241 +#endif
49242 + deptsiz0_data_t deptsiz;
49243 + dev_dma_desc_sts_t desc_sts;
49244 + dwc_otg_pcd_request_t *req;
49245 + int is_last = 0;
49246 + dwc_otg_pcd_t *pcd = ep->pcd;
49247 +
49248 +#ifdef DWC_UTE_CFI
49249 + struct cfi_usb_ctrlrequest *ctrlreq;
49250 + int retval = -DWC_E_NOT_SUPPORTED;
49251 +#endif
49252 +
49253 + desc_sts.b.bytes = 0;
49254 +
49255 + if (pcd->ep0_pending && DWC_CIRCLEQ_EMPTY(&ep->queue)) {
49256 + if (ep->dwc_ep.is_in) {
49257 +#ifdef DEBUG_EP0
49258 + DWC_DEBUGPL(DBG_PCDV, "Do setup OUT status phase\n");
49259 +#endif
49260 + do_setup_out_status_phase(pcd);
49261 + } else {
49262 +#ifdef DEBUG_EP0
49263 + DWC_DEBUGPL(DBG_PCDV, "Do setup IN status phase\n");
49264 +#endif
49265 +
49266 +#ifdef DWC_UTE_CFI
49267 + ctrlreq = &pcd->cfi->ctrl_req;
49268 +
49269 + if (UT_GET_TYPE(ctrlreq->bRequestType) == UT_VENDOR) {
49270 + if (ctrlreq->bRequest > 0xB0
49271 + && ctrlreq->bRequest < 0xBF) {
49272 +
49273 + /* Return if the PCD failed to handle the request */
49274 + if ((retval =
49275 + pcd->cfi->ops.
49276 + ctrl_write_complete(pcd->cfi,
49277 + pcd)) < 0) {
49278 + CFI_INFO
49279 + ("ERROR setting a new value in the PCD(%d)\n",
49280 + retval);
49281 + ep0_do_stall(pcd, retval);
49282 + pcd->ep0_pending = 0;
49283 + return 0;
49284 + }
49285 +
49286 + /* If the gadget needs to be notified on the request */
49287 + if (pcd->cfi->need_gadget_att == 1) {
49288 + //retval = do_gadget_setup(pcd, &pcd->cfi->ctrl_req);
49289 + retval =
49290 + cfi_gadget_setup(pcd,
49291 + &pcd->cfi->
49292 + ctrl_req);
49293 +
49294 + /* Return from the function if the gadget failed to process
49295 + * the request properly - this should never happen !!!
49296 + */
49297 + if (retval < 0) {
49298 + CFI_INFO
49299 + ("ERROR setting a new value in the gadget(%d)\n",
49300 + retval);
49301 + pcd->ep0_pending = 0;
49302 + return 0;
49303 + }
49304 + }
49305 +
49306 + CFI_INFO("%s: RETVAL=%d\n", __func__,
49307 + retval);
49308 + /* If we hit here then the PCD and the gadget has properly
49309 + * handled the request - so send the ZLP IN to the host.
49310 + */
49311 + /* @todo: MAS - decide whether we need to start the setup
49312 + * stage based on the need_setup value of the cfi object
49313 + */
49314 + do_setup_in_status_phase(pcd);
49315 + pcd->ep0_pending = 0;
49316 + return 1;
49317 + }
49318 + }
49319 +#endif
49320 +
49321 + do_setup_in_status_phase(pcd);
49322 + }
49323 + pcd->ep0_pending = 0;
49324 + return 1;
49325 + }
49326 +
49327 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
49328 + return 0;
49329 + }
49330 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
49331 +
49332 + if (pcd->ep0state == EP0_OUT_STATUS_PHASE
49333 + || pcd->ep0state == EP0_IN_STATUS_PHASE) {
49334 + is_last = 1;
49335 + } else if (ep->dwc_ep.is_in) {
49336 + deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
49337 + if (core_if->dma_desc_enable != 0)
49338 + desc_sts = dev_if->in_desc_addr->status;
49339 +#ifdef DEBUG_EP0
49340 + DWC_DEBUGPL(DBG_PCDV, "%d len=%d xfersize=%d pktcnt=%d\n",
49341 + ep->dwc_ep.num, ep->dwc_ep.xfer_len,
49342 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49343 +#endif
49344 +
49345 + if (((core_if->dma_desc_enable == 0)
49346 + && (deptsiz.b.xfersize == 0))
49347 + || ((core_if->dma_desc_enable != 0)
49348 + && (desc_sts.b.bytes == 0))) {
49349 + req->actual = ep->dwc_ep.xfer_count;
49350 + /* Is a Zero Len Packet needed? */
49351 + if (req->sent_zlp) {
49352 +#ifdef DEBUG_EP0
49353 + DWC_DEBUGPL(DBG_PCD, "Setup Rx ZLP\n");
49354 +#endif
49355 + req->sent_zlp = 0;
49356 + }
49357 + do_setup_out_status_phase(pcd);
49358 + }
49359 + } else {
49360 + /* ep0-OUT */
49361 +#ifdef DEBUG_EP0
49362 + deptsiz.d32 = DWC_READ_REG32(&out_ep_regs->doeptsiz);
49363 + DWC_DEBUGPL(DBG_PCDV, "%d len=%d xsize=%d pktcnt=%d\n",
49364 + ep->dwc_ep.num, ep->dwc_ep.xfer_len,
49365 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49366 +#endif
49367 + req->actual = ep->dwc_ep.xfer_count;
49368 +
49369 + /* Is a Zero Len Packet needed? */
49370 + if (req->sent_zlp) {
49371 +#ifdef DEBUG_EP0
49372 + DWC_DEBUGPL(DBG_PCDV, "Setup Tx ZLP\n");
49373 +#endif
49374 + req->sent_zlp = 0;
49375 + }
49376 + /* For older cores do setup in status phase in Slave/BDMA modes,
49377 + * starting from 3.00 do that only in slave, and for DMA modes
49378 + * just re-enable ep 0 OUT here*/
49379 + if (core_if->dma_enable == 0
49380 + || (core_if->dma_desc_enable == 0
49381 + && core_if->snpsid <= OTG_CORE_REV_2_94a)) {
49382 + do_setup_in_status_phase(pcd);
49383 + } else if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
49384 + DWC_DEBUGPL(DBG_PCDV,
49385 + "Enable out ep before in status phase\n");
49386 + ep0_out_start(core_if, pcd);
49387 + }
49388 + }
49389 +
49390 + /* Complete the request */
49391 + if (is_last) {
49392 + dwc_otg_request_done(ep, req, 0);
49393 + ep->dwc_ep.start_xfer_buff = 0;
49394 + ep->dwc_ep.xfer_buff = 0;
49395 + ep->dwc_ep.xfer_len = 0;
49396 + return 1;
49397 + }
49398 + return 0;
49399 +}
49400 +
49401 +#ifdef DWC_UTE_CFI
49402 +/**
49403 + * This function calculates traverses all the CFI DMA descriptors and
49404 + * and accumulates the bytes that are left to be transfered.
49405 + *
49406 + * @return The total bytes left to transfered, or a negative value as failure
49407 + */
49408 +static inline int cfi_calc_desc_residue(dwc_otg_pcd_ep_t * ep)
49409 +{
49410 + int32_t ret = 0;
49411 + int i;
49412 + struct dwc_otg_dma_desc *ddesc = NULL;
49413 + struct cfi_ep *cfiep;
49414 +
49415 + /* See if the pcd_ep has its respective cfi_ep mapped */
49416 + cfiep = get_cfi_ep_by_pcd_ep(ep->pcd->cfi, ep);
49417 + if (!cfiep) {
49418 + CFI_INFO("%s: Failed to find ep\n", __func__);
49419 + return -1;
49420 + }
49421 +
49422 + ddesc = ep->dwc_ep.descs;
49423 +
49424 + for (i = 0; (i < cfiep->desc_count) && (i < MAX_DMA_DESCS_PER_EP); i++) {
49425 +
49426 +#if defined(PRINT_CFI_DMA_DESCS)
49427 + print_desc(ddesc, ep->ep.name, i);
49428 +#endif
49429 + ret += ddesc->status.b.bytes;
49430 + ddesc++;
49431 + }
49432 +
49433 + if (ret)
49434 + CFI_INFO("!!!!!!!!!! WARNING (%s) - residue=%d\n", __func__,
49435 + ret);
49436 +
49437 + return ret;
49438 +}
49439 +#endif
49440 +
49441 +/**
49442 + * This function completes the request for the EP. If there are
49443 + * additional requests for the EP in the queue they will be started.
49444 + */
49445 +static void complete_ep(dwc_otg_pcd_ep_t * ep)
49446 +{
49447 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
49448 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
49449 + dwc_otg_dev_in_ep_regs_t *in_ep_regs =
49450 + dev_if->in_ep_regs[ep->dwc_ep.num];
49451 + deptsiz_data_t deptsiz;
49452 + dev_dma_desc_sts_t desc_sts;
49453 + dwc_otg_pcd_request_t *req = 0;
49454 + dwc_otg_dev_dma_desc_t *dma_desc;
49455 + uint32_t byte_count = 0;
49456 + int is_last = 0;
49457 + int i;
49458 +
49459 + DWC_DEBUGPL(DBG_PCDV, "%s() %d-%s\n", __func__, ep->dwc_ep.num,
49460 + (ep->dwc_ep.is_in ? "IN" : "OUT"));
49461 +
49462 + /* Get any pending requests */
49463 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
49464 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
49465 + if (!req) {
49466 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
49467 + return;
49468 + }
49469 + } else {
49470 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
49471 + return;
49472 + }
49473 +
49474 + DWC_DEBUGPL(DBG_PCD, "Requests %d\n", ep->pcd->request_pending);
49475 +
49476 + if (ep->dwc_ep.is_in) {
49477 + deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
49478 +
49479 + if (core_if->dma_enable) {
49480 + if (core_if->dma_desc_enable == 0) {
49481 + if (deptsiz.b.xfersize == 0
49482 + && deptsiz.b.pktcnt == 0) {
49483 + byte_count =
49484 + ep->dwc_ep.xfer_len -
49485 + ep->dwc_ep.xfer_count;
49486 +
49487 + ep->dwc_ep.xfer_buff += byte_count;
49488 + ep->dwc_ep.dma_addr += byte_count;
49489 + ep->dwc_ep.xfer_count += byte_count;
49490 +
49491 + DWC_DEBUGPL(DBG_PCDV,
49492 + "%d-%s len=%d xfersize=%d pktcnt=%d\n",
49493 + ep->dwc_ep.num,
49494 + (ep->dwc_ep.
49495 + is_in ? "IN" : "OUT"),
49496 + ep->dwc_ep.xfer_len,
49497 + deptsiz.b.xfersize,
49498 + deptsiz.b.pktcnt);
49499 +
49500 + if (ep->dwc_ep.xfer_len <
49501 + ep->dwc_ep.total_len) {
49502 + dwc_otg_ep_start_transfer
49503 + (core_if, &ep->dwc_ep);
49504 + } else if (ep->dwc_ep.sent_zlp) {
49505 + /*
49506 + * This fragment of code should initiate 0
49507 + * length transfer in case if it is queued
49508 + * a transfer with size divisible to EPs max
49509 + * packet size and with usb_request zero field
49510 + * is set, which means that after data is transfered,
49511 + * it is also should be transfered
49512 + * a 0 length packet at the end. For Slave and
49513 + * Buffer DMA modes in this case SW has
49514 + * to initiate 2 transfers one with transfer size,
49515 + * and the second with 0 size. For Descriptor
49516 + * DMA mode SW is able to initiate a transfer,
49517 + * which will handle all the packets including
49518 + * the last 0 length.
49519 + */
49520 + ep->dwc_ep.sent_zlp = 0;
49521 + dwc_otg_ep_start_zl_transfer
49522 + (core_if, &ep->dwc_ep);
49523 + } else {
49524 + is_last = 1;
49525 + }
49526 + } else {
49527 + if (ep->dwc_ep.type ==
49528 + DWC_OTG_EP_TYPE_ISOC) {
49529 + req->actual = 0;
49530 + dwc_otg_request_done(ep, req, 0);
49531 +
49532 + ep->dwc_ep.start_xfer_buff = 0;
49533 + ep->dwc_ep.xfer_buff = 0;
49534 + ep->dwc_ep.xfer_len = 0;
49535 +
49536 + /* If there is a request in the queue start it. */
49537 + start_next_request(ep);
49538 + } else
49539 + DWC_WARN
49540 + ("Incomplete transfer (%d - %s [siz=%d pkt=%d])\n",
49541 + ep->dwc_ep.num,
49542 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
49543 + deptsiz.b.xfersize,
49544 + deptsiz.b.pktcnt);
49545 + }
49546 + } else {
49547 + dma_desc = ep->dwc_ep.desc_addr;
49548 + byte_count = 0;
49549 + ep->dwc_ep.sent_zlp = 0;
49550 +
49551 +#ifdef DWC_UTE_CFI
49552 + CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
49553 + ep->dwc_ep.buff_mode);
49554 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
49555 + int residue;
49556 +
49557 + residue = cfi_calc_desc_residue(ep);
49558 + if (residue < 0)
49559 + return;
49560 +
49561 + byte_count = residue;
49562 + } else {
49563 +#endif
49564 + for (i = 0; i < ep->dwc_ep.desc_cnt;
49565 + ++i) {
49566 + desc_sts = dma_desc->status;
49567 + byte_count += desc_sts.b.bytes;
49568 + dma_desc++;
49569 + }
49570 +#ifdef DWC_UTE_CFI
49571 + }
49572 +#endif
49573 + if (byte_count == 0) {
49574 + ep->dwc_ep.xfer_count =
49575 + ep->dwc_ep.total_len;
49576 + is_last = 1;
49577 + } else {
49578 + DWC_WARN("Incomplete transfer\n");
49579 + }
49580 + }
49581 + } else {
49582 + if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0) {
49583 + DWC_DEBUGPL(DBG_PCDV,
49584 + "%d-%s len=%d xfersize=%d pktcnt=%d\n",
49585 + ep->dwc_ep.num,
49586 + ep->dwc_ep.is_in ? "IN" : "OUT",
49587 + ep->dwc_ep.xfer_len,
49588 + deptsiz.b.xfersize,
49589 + deptsiz.b.pktcnt);
49590 +
49591 + /* Check if the whole transfer was completed,
49592 + * if no, setup transfer for next portion of data
49593 + */
49594 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
49595 + dwc_otg_ep_start_transfer(core_if,
49596 + &ep->dwc_ep);
49597 + } else if (ep->dwc_ep.sent_zlp) {
49598 + /*
49599 + * This fragment of code should initiate 0
49600 + * length trasfer in case if it is queued
49601 + * a trasfer with size divisible to EPs max
49602 + * packet size and with usb_request zero field
49603 + * is set, which means that after data is transfered,
49604 + * it is also should be transfered
49605 + * a 0 length packet at the end. For Slave and
49606 + * Buffer DMA modes in this case SW has
49607 + * to initiate 2 transfers one with transfer size,
49608 + * and the second with 0 size. For Desriptor
49609 + * DMA mode SW is able to initiate a transfer,
49610 + * which will handle all the packets including
49611 + * the last 0 legth.
49612 + */
49613 + ep->dwc_ep.sent_zlp = 0;
49614 + dwc_otg_ep_start_zl_transfer(core_if,
49615 + &ep->dwc_ep);
49616 + } else {
49617 + is_last = 1;
49618 + }
49619 + } else {
49620 + DWC_WARN
49621 + ("Incomplete transfer (%d-%s [siz=%d pkt=%d])\n",
49622 + ep->dwc_ep.num,
49623 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
49624 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49625 + }
49626 + }
49627 + } else {
49628 + dwc_otg_dev_out_ep_regs_t *out_ep_regs =
49629 + dev_if->out_ep_regs[ep->dwc_ep.num];
49630 + desc_sts.d32 = 0;
49631 + if (core_if->dma_enable) {
49632 + if (core_if->dma_desc_enable) {
49633 + dma_desc = ep->dwc_ep.desc_addr;
49634 + byte_count = 0;
49635 + ep->dwc_ep.sent_zlp = 0;
49636 +
49637 +#ifdef DWC_UTE_CFI
49638 + CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
49639 + ep->dwc_ep.buff_mode);
49640 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
49641 + int residue;
49642 + residue = cfi_calc_desc_residue(ep);
49643 + if (residue < 0)
49644 + return;
49645 + byte_count = residue;
49646 + } else {
49647 +#endif
49648 +
49649 + for (i = 0; i < ep->dwc_ep.desc_cnt;
49650 + ++i) {
49651 + desc_sts = dma_desc->status;
49652 + byte_count += desc_sts.b.bytes;
49653 + dma_desc++;
49654 + }
49655 +
49656 +#ifdef DWC_UTE_CFI
49657 + }
49658 +#endif
49659 + /* Checking for interrupt Out transfers with not
49660 + * dword aligned mps sizes
49661 + */
49662 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_INTR &&
49663 + (ep->dwc_ep.maxpacket%4)) {
49664 + ep->dwc_ep.xfer_count =
49665 + ep->dwc_ep.total_len - byte_count;
49666 + if ((ep->dwc_ep.xfer_len %
49667 + ep->dwc_ep.maxpacket)
49668 + && (ep->dwc_ep.xfer_len /
49669 + ep->dwc_ep.maxpacket <
49670 + MAX_DMA_DESC_CNT))
49671 + ep->dwc_ep.xfer_len -=
49672 + (ep->dwc_ep.desc_cnt -
49673 + 1) * ep->dwc_ep.maxpacket +
49674 + ep->dwc_ep.xfer_len %
49675 + ep->dwc_ep.maxpacket;
49676 + else
49677 + ep->dwc_ep.xfer_len -=
49678 + ep->dwc_ep.desc_cnt *
49679 + ep->dwc_ep.maxpacket;
49680 + if (ep->dwc_ep.xfer_len > 0) {
49681 + dwc_otg_ep_start_transfer
49682 + (core_if, &ep->dwc_ep);
49683 + } else {
49684 + is_last = 1;
49685 + }
49686 + } else {
49687 + ep->dwc_ep.xfer_count =
49688 + ep->dwc_ep.total_len - byte_count +
49689 + ((4 -
49690 + (ep->dwc_ep.
49691 + total_len & 0x3)) & 0x3);
49692 + is_last = 1;
49693 + }
49694 + } else {
49695 + deptsiz.d32 = 0;
49696 + deptsiz.d32 =
49697 + DWC_READ_REG32(&out_ep_regs->doeptsiz);
49698 +
49699 + byte_count = (ep->dwc_ep.xfer_len -
49700 + ep->dwc_ep.xfer_count -
49701 + deptsiz.b.xfersize);
49702 + ep->dwc_ep.xfer_buff += byte_count;
49703 + ep->dwc_ep.dma_addr += byte_count;
49704 + ep->dwc_ep.xfer_count += byte_count;
49705 +
49706 + /* Check if the whole transfer was completed,
49707 + * if no, setup transfer for next portion of data
49708 + */
49709 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
49710 + dwc_otg_ep_start_transfer(core_if,
49711 + &ep->dwc_ep);
49712 + } else if (ep->dwc_ep.sent_zlp) {
49713 + /*
49714 + * This fragment of code should initiate 0
49715 + * length trasfer in case if it is queued
49716 + * a trasfer with size divisible to EPs max
49717 + * packet size and with usb_request zero field
49718 + * is set, which means that after data is transfered,
49719 + * it is also should be transfered
49720 + * a 0 length packet at the end. For Slave and
49721 + * Buffer DMA modes in this case SW has
49722 + * to initiate 2 transfers one with transfer size,
49723 + * and the second with 0 size. For Desriptor
49724 + * DMA mode SW is able to initiate a transfer,
49725 + * which will handle all the packets including
49726 + * the last 0 legth.
49727 + */
49728 + ep->dwc_ep.sent_zlp = 0;
49729 + dwc_otg_ep_start_zl_transfer(core_if,
49730 + &ep->dwc_ep);
49731 + } else {
49732 + is_last = 1;
49733 + }
49734 + }
49735 + } else {
49736 + /* Check if the whole transfer was completed,
49737 + * if no, setup transfer for next portion of data
49738 + */
49739 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
49740 + dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
49741 + } else if (ep->dwc_ep.sent_zlp) {
49742 + /*
49743 + * This fragment of code should initiate 0
49744 + * length transfer in case if it is queued
49745 + * a transfer with size divisible to EPs max
49746 + * packet size and with usb_request zero field
49747 + * is set, which means that after data is transfered,
49748 + * it is also should be transfered
49749 + * a 0 length packet at the end. For Slave and
49750 + * Buffer DMA modes in this case SW has
49751 + * to initiate 2 transfers one with transfer size,
49752 + * and the second with 0 size. For Descriptor
49753 + * DMA mode SW is able to initiate a transfer,
49754 + * which will handle all the packets including
49755 + * the last 0 length.
49756 + */
49757 + ep->dwc_ep.sent_zlp = 0;
49758 + dwc_otg_ep_start_zl_transfer(core_if,
49759 + &ep->dwc_ep);
49760 + } else {
49761 + is_last = 1;
49762 + }
49763 + }
49764 +
49765 + DWC_DEBUGPL(DBG_PCDV,
49766 + "addr %p, %d-%s len=%d cnt=%d xsize=%d pktcnt=%d\n",
49767 + &out_ep_regs->doeptsiz, ep->dwc_ep.num,
49768 + ep->dwc_ep.is_in ? "IN" : "OUT",
49769 + ep->dwc_ep.xfer_len, ep->dwc_ep.xfer_count,
49770 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49771 + }
49772 +
49773 + /* Complete the request */
49774 + if (is_last) {
49775 +#ifdef DWC_UTE_CFI
49776 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
49777 + req->actual = ep->dwc_ep.cfi_req_len - byte_count;
49778 + } else {
49779 +#endif
49780 + req->actual = ep->dwc_ep.xfer_count;
49781 +#ifdef DWC_UTE_CFI
49782 + }
49783 +#endif
49784 + if (req->dw_align_buf) {
49785 + if (!ep->dwc_ep.is_in) {
49786 + dwc_memcpy(req->buf, req->dw_align_buf, req->length);
49787 + }
49788 + DWC_DMA_FREE(req->length, req->dw_align_buf,
49789 + req->dw_align_buf_dma);
49790 + }
49791 +
49792 + dwc_otg_request_done(ep, req, 0);
49793 +
49794 + ep->dwc_ep.start_xfer_buff = 0;
49795 + ep->dwc_ep.xfer_buff = 0;
49796 + ep->dwc_ep.xfer_len = 0;
49797 +
49798 + /* If there is a request in the queue start it. */
49799 + start_next_request(ep);
49800 + }
49801 +}
49802 +
49803 +#ifdef DWC_EN_ISOC
49804 +
49805 +/**
49806 + * This function BNA interrupt for Isochronous EPs
49807 + *
49808 + */
49809 +static void dwc_otg_pcd_handle_iso_bna(dwc_otg_pcd_ep_t * ep)
49810 +{
49811 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
49812 + volatile uint32_t *addr;
49813 + depctl_data_t depctl = {.d32 = 0 };
49814 + dwc_otg_pcd_t *pcd = ep->pcd;
49815 + dwc_otg_dev_dma_desc_t *dma_desc;
49816 + int i;
49817 +
49818 + dma_desc =
49819 + dwc_ep->iso_desc_addr + dwc_ep->desc_cnt * (dwc_ep->proc_buf_num);
49820 +
49821 + if (dwc_ep->is_in) {
49822 + dev_dma_desc_sts_t sts = {.d32 = 0 };
49823 + for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
49824 + sts.d32 = dma_desc->status.d32;
49825 + sts.b_iso_in.bs = BS_HOST_READY;
49826 + dma_desc->status.d32 = sts.d32;
49827 + }
49828 + } else {
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_out.bs = BS_HOST_READY;
49833 + dma_desc->status.d32 = sts.d32;
49834 + }
49835 + }
49836 +
49837 + if (dwc_ep->is_in == 0) {
49838 + addr =
49839 + &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->
49840 + num]->doepctl;
49841 + } else {
49842 + addr =
49843 + &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
49844 + }
49845 + depctl.b.epena = 1;
49846 + DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
49847 +}
49848 +
49849 +/**
49850 + * This function sets latest iso packet information(non-PTI mode)
49851 + *
49852 + * @param core_if Programming view of DWC_otg controller.
49853 + * @param ep The EP to start the transfer on.
49854 + *
49855 + */
49856 +void set_current_pkt_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
49857 +{
49858 + deptsiz_data_t deptsiz = {.d32 = 0 };
49859 + dma_addr_t dma_addr;
49860 + uint32_t offset;
49861 +
49862 + if (ep->proc_buf_num)
49863 + dma_addr = ep->dma_addr1;
49864 + else
49865 + dma_addr = ep->dma_addr0;
49866 +
49867 + if (ep->is_in) {
49868 + deptsiz.d32 =
49869 + DWC_READ_REG32(&core_if->dev_if->
49870 + in_ep_regs[ep->num]->dieptsiz);
49871 + offset = ep->data_per_frame;
49872 + } else {
49873 + deptsiz.d32 =
49874 + DWC_READ_REG32(&core_if->dev_if->
49875 + out_ep_regs[ep->num]->doeptsiz);
49876 + offset =
49877 + ep->data_per_frame +
49878 + (0x4 & (0x4 - (ep->data_per_frame & 0x3)));
49879 + }
49880 +
49881 + if (!deptsiz.b.xfersize) {
49882 + ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
49883 + ep->pkt_info[ep->cur_pkt].offset =
49884 + ep->cur_pkt_dma_addr - dma_addr;
49885 + ep->pkt_info[ep->cur_pkt].status = 0;
49886 + } else {
49887 + ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
49888 + ep->pkt_info[ep->cur_pkt].offset =
49889 + ep->cur_pkt_dma_addr - dma_addr;
49890 + ep->pkt_info[ep->cur_pkt].status = -DWC_E_NO_DATA;
49891 + }
49892 + ep->cur_pkt_addr += offset;
49893 + ep->cur_pkt_dma_addr += offset;
49894 + ep->cur_pkt++;
49895 +}
49896 +
49897 +/**
49898 + * This function sets latest iso packet information(DDMA mode)
49899 + *
49900 + * @param core_if Programming view of DWC_otg controller.
49901 + * @param dwc_ep The EP to start the transfer on.
49902 + *
49903 + */
49904 +static void set_ddma_iso_pkts_info(dwc_otg_core_if_t * core_if,
49905 + dwc_ep_t * dwc_ep)
49906 +{
49907 + dwc_otg_dev_dma_desc_t *dma_desc;
49908 + dev_dma_desc_sts_t sts = {.d32 = 0 };
49909 + iso_pkt_info_t *iso_packet;
49910 + uint32_t data_per_desc;
49911 + uint32_t offset;
49912 + int i, j;
49913 +
49914 + iso_packet = dwc_ep->pkt_info;
49915 +
49916 + /** Reinit closed DMA Descriptors*/
49917 + /** ISO OUT EP */
49918 + if (dwc_ep->is_in == 0) {
49919 + dma_desc =
49920 + dwc_ep->iso_desc_addr +
49921 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
49922 + offset = 0;
49923 +
49924 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
49925 + i += dwc_ep->pkt_per_frm) {
49926 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
49927 + data_per_desc =
49928 + ((j + 1) * dwc_ep->maxpacket >
49929 + dwc_ep->
49930 + data_per_frame) ? dwc_ep->data_per_frame -
49931 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
49932 + data_per_desc +=
49933 + (data_per_desc % 4) ? (4 -
49934 + data_per_desc %
49935 + 4) : 0;
49936 +
49937 + sts.d32 = dma_desc->status.d32;
49938 +
49939 + /* Write status in iso_packet_decsriptor */
49940 + iso_packet->status =
49941 + sts.b_iso_out.rxsts +
49942 + (sts.b_iso_out.bs ^ BS_DMA_DONE);
49943 + if (iso_packet->status) {
49944 + iso_packet->status = -DWC_E_NO_DATA;
49945 + }
49946 +
49947 + /* Received data length */
49948 + if (!sts.b_iso_out.rxbytes) {
49949 + iso_packet->length =
49950 + data_per_desc -
49951 + sts.b_iso_out.rxbytes;
49952 + } else {
49953 + iso_packet->length =
49954 + data_per_desc -
49955 + sts.b_iso_out.rxbytes + (4 -
49956 + dwc_ep->data_per_frame
49957 + % 4);
49958 + }
49959 +
49960 + iso_packet->offset = offset;
49961 +
49962 + offset += data_per_desc;
49963 + dma_desc++;
49964 + iso_packet++;
49965 + }
49966 + }
49967 +
49968 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
49969 + data_per_desc =
49970 + ((j + 1) * dwc_ep->maxpacket >
49971 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
49972 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
49973 + data_per_desc +=
49974 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
49975 +
49976 + sts.d32 = dma_desc->status.d32;
49977 +
49978 + /* Write status in iso_packet_decsriptor */
49979 + iso_packet->status =
49980 + sts.b_iso_out.rxsts +
49981 + (sts.b_iso_out.bs ^ BS_DMA_DONE);
49982 + if (iso_packet->status) {
49983 + iso_packet->status = -DWC_E_NO_DATA;
49984 + }
49985 +
49986 + /* Received data length */
49987 + iso_packet->length =
49988 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
49989 +
49990 + iso_packet->offset = offset;
49991 +
49992 + offset += data_per_desc;
49993 + iso_packet++;
49994 + dma_desc++;
49995 + }
49996 +
49997 + sts.d32 = dma_desc->status.d32;
49998 +
49999 + /* Write status in iso_packet_decsriptor */
50000 + iso_packet->status =
50001 + sts.b_iso_out.rxsts + (sts.b_iso_out.bs ^ BS_DMA_DONE);
50002 + if (iso_packet->status) {
50003 + iso_packet->status = -DWC_E_NO_DATA;
50004 + }
50005 + /* Received data length */
50006 + if (!sts.b_iso_out.rxbytes) {
50007 + iso_packet->length =
50008 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
50009 + } else {
50010 + iso_packet->length =
50011 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes +
50012 + (4 - dwc_ep->data_per_frame % 4);
50013 + }
50014 +
50015 + iso_packet->offset = offset;
50016 + } else {
50017 +/** ISO IN EP */
50018 +
50019 + dma_desc =
50020 + dwc_ep->iso_desc_addr +
50021 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
50022 +
50023 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
50024 + sts.d32 = dma_desc->status.d32;
50025 +
50026 + /* Write status in iso packet descriptor */
50027 + iso_packet->status =
50028 + sts.b_iso_in.txsts +
50029 + (sts.b_iso_in.bs ^ BS_DMA_DONE);
50030 + if (iso_packet->status != 0) {
50031 + iso_packet->status = -DWC_E_NO_DATA;
50032 +
50033 + }
50034 + /* Bytes has been transfered */
50035 + iso_packet->length =
50036 + dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
50037 +
50038 + dma_desc++;
50039 + iso_packet++;
50040 + }
50041 +
50042 + sts.d32 = dma_desc->status.d32;
50043 + while (sts.b_iso_in.bs == BS_DMA_BUSY) {
50044 + sts.d32 = dma_desc->status.d32;
50045 + }
50046 +
50047 + /* Write status in iso packet descriptor ??? do be done with ERROR codes */
50048 + iso_packet->status =
50049 + sts.b_iso_in.txsts + (sts.b_iso_in.bs ^ BS_DMA_DONE);
50050 + if (iso_packet->status != 0) {
50051 + iso_packet->status = -DWC_E_NO_DATA;
50052 + }
50053 +
50054 + /* Bytes has been transfered */
50055 + iso_packet->length =
50056 + dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
50057 + }
50058 +}
50059 +
50060 +/**
50061 + * This function reinitialize DMA Descriptors for Isochronous transfer
50062 + *
50063 + * @param core_if Programming view of DWC_otg controller.
50064 + * @param dwc_ep The EP to start the transfer on.
50065 + *
50066 + */
50067 +static void reinit_ddma_iso_xfer(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
50068 +{
50069 + int i, j;
50070 + dwc_otg_dev_dma_desc_t *dma_desc;
50071 + dma_addr_t dma_ad;
50072 + volatile uint32_t *addr;
50073 + dev_dma_desc_sts_t sts = {.d32 = 0 };
50074 + uint32_t data_per_desc;
50075 +
50076 + if (dwc_ep->is_in == 0) {
50077 + addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
50078 + } else {
50079 + addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
50080 + }
50081 +
50082 + if (dwc_ep->proc_buf_num == 0) {
50083 + /** Buffer 0 descriptors setup */
50084 + dma_ad = dwc_ep->dma_addr0;
50085 + } else {
50086 + /** Buffer 1 descriptors setup */
50087 + dma_ad = dwc_ep->dma_addr1;
50088 + }
50089 +
50090 + /** Reinit closed DMA Descriptors*/
50091 + /** ISO OUT EP */
50092 + if (dwc_ep->is_in == 0) {
50093 + dma_desc =
50094 + dwc_ep->iso_desc_addr +
50095 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
50096 +
50097 + sts.b_iso_out.bs = BS_HOST_READY;
50098 + sts.b_iso_out.rxsts = 0;
50099 + sts.b_iso_out.l = 0;
50100 + sts.b_iso_out.sp = 0;
50101 + sts.b_iso_out.ioc = 0;
50102 + sts.b_iso_out.pid = 0;
50103 + sts.b_iso_out.framenum = 0;
50104 +
50105 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
50106 + i += dwc_ep->pkt_per_frm) {
50107 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
50108 + data_per_desc =
50109 + ((j + 1) * dwc_ep->maxpacket >
50110 + dwc_ep->
50111 + data_per_frame) ? dwc_ep->data_per_frame -
50112 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
50113 + data_per_desc +=
50114 + (data_per_desc % 4) ? (4 -
50115 + data_per_desc %
50116 + 4) : 0;
50117 + sts.b_iso_out.rxbytes = data_per_desc;
50118 + dma_desc->buf = dma_ad;
50119 + dma_desc->status.d32 = sts.d32;
50120 +
50121 + dma_ad += data_per_desc;
50122 + dma_desc++;
50123 + }
50124 + }
50125 +
50126 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
50127 +
50128 + data_per_desc =
50129 + ((j + 1) * dwc_ep->maxpacket >
50130 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
50131 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
50132 + data_per_desc +=
50133 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
50134 + sts.b_iso_out.rxbytes = data_per_desc;
50135 +
50136 + dma_desc->buf = dma_ad;
50137 + dma_desc->status.d32 = sts.d32;
50138 +
50139 + dma_desc++;
50140 + dma_ad += data_per_desc;
50141 + }
50142 +
50143 + sts.b_iso_out.ioc = 1;
50144 + sts.b_iso_out.l = dwc_ep->proc_buf_num;
50145 +
50146 + data_per_desc =
50147 + ((j + 1) * dwc_ep->maxpacket >
50148 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
50149 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
50150 + data_per_desc +=
50151 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
50152 + sts.b_iso_out.rxbytes = data_per_desc;
50153 +
50154 + dma_desc->buf = dma_ad;
50155 + dma_desc->status.d32 = sts.d32;
50156 + } else {
50157 +/** ISO IN EP */
50158 +
50159 + dma_desc =
50160 + dwc_ep->iso_desc_addr +
50161 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
50162 +
50163 + sts.b_iso_in.bs = BS_HOST_READY;
50164 + sts.b_iso_in.txsts = 0;
50165 + sts.b_iso_in.sp = 0;
50166 + sts.b_iso_in.ioc = 0;
50167 + sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
50168 + sts.b_iso_in.framenum = dwc_ep->next_frame;
50169 + sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
50170 + sts.b_iso_in.l = 0;
50171 +
50172 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
50173 + dma_desc->buf = dma_ad;
50174 + dma_desc->status.d32 = sts.d32;
50175 +
50176 + sts.b_iso_in.framenum += dwc_ep->bInterval;
50177 + dma_ad += dwc_ep->data_per_frame;
50178 + dma_desc++;
50179 + }
50180 +
50181 + sts.b_iso_in.ioc = 1;
50182 + sts.b_iso_in.l = dwc_ep->proc_buf_num;
50183 +
50184 + dma_desc->buf = dma_ad;
50185 + dma_desc->status.d32 = sts.d32;
50186 +
50187 + dwc_ep->next_frame =
50188 + sts.b_iso_in.framenum + dwc_ep->bInterval * 1;
50189 + }
50190 + dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
50191 +}
50192 +
50193 +/**
50194 + * This function is to handle Iso EP transfer complete interrupt
50195 + * in case Iso out packet was dropped
50196 + *
50197 + * @param core_if Programming view of DWC_otg controller.
50198 + * @param dwc_ep The EP for wihich transfer complete was asserted
50199 + *
50200 + */
50201 +static uint32_t handle_iso_out_pkt_dropped(dwc_otg_core_if_t * core_if,
50202 + dwc_ep_t * dwc_ep)
50203 +{
50204 + uint32_t dma_addr;
50205 + uint32_t drp_pkt;
50206 + uint32_t drp_pkt_cnt;
50207 + deptsiz_data_t deptsiz = {.d32 = 0 };
50208 + depctl_data_t depctl = {.d32 = 0 };
50209 + int i;
50210 +
50211 + deptsiz.d32 =
50212 + DWC_READ_REG32(&core_if->dev_if->
50213 + out_ep_regs[dwc_ep->num]->doeptsiz);
50214 +
50215 + drp_pkt = dwc_ep->pkt_cnt - deptsiz.b.pktcnt;
50216 + drp_pkt_cnt = dwc_ep->pkt_per_frm - (drp_pkt % dwc_ep->pkt_per_frm);
50217 +
50218 + /* Setting dropped packets status */
50219 + for (i = 0; i < drp_pkt_cnt; ++i) {
50220 + dwc_ep->pkt_info[drp_pkt].status = -DWC_E_NO_DATA;
50221 + drp_pkt++;
50222 + deptsiz.b.pktcnt--;
50223 + }
50224 +
50225 + if (deptsiz.b.pktcnt > 0) {
50226 + deptsiz.b.xfersize =
50227 + dwc_ep->xfer_len - (dwc_ep->pkt_cnt -
50228 + deptsiz.b.pktcnt) * dwc_ep->maxpacket;
50229 + } else {
50230 + deptsiz.b.xfersize = 0;
50231 + deptsiz.b.pktcnt = 0;
50232 + }
50233 +
50234 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz,
50235 + deptsiz.d32);
50236 +
50237 + if (deptsiz.b.pktcnt > 0) {
50238 + if (dwc_ep->proc_buf_num) {
50239 + dma_addr =
50240 + dwc_ep->dma_addr1 + dwc_ep->xfer_len -
50241 + deptsiz.b.xfersize;
50242 + } else {
50243 + dma_addr =
50244 + dwc_ep->dma_addr0 + dwc_ep->xfer_len -
50245 + deptsiz.b.xfersize;;
50246 + }
50247 +
50248 + DWC_WRITE_REG32(&core_if->dev_if->
50249 + out_ep_regs[dwc_ep->num]->doepdma, dma_addr);
50250 +
50251 + /** Re-enable endpoint, clear nak */
50252 + depctl.d32 = 0;
50253 + depctl.b.epena = 1;
50254 + depctl.b.cnak = 1;
50255 +
50256 + DWC_MODIFY_REG32(&core_if->dev_if->
50257 + out_ep_regs[dwc_ep->num]->doepctl, depctl.d32,
50258 + depctl.d32);
50259 + return 0;
50260 + } else {
50261 + return 1;
50262 + }
50263 +}
50264 +
50265 +/**
50266 + * This function sets iso packets information(PTI mode)
50267 + *
50268 + * @param core_if Programming view of DWC_otg controller.
50269 + * @param ep The EP to start the transfer on.
50270 + *
50271 + */
50272 +static uint32_t set_iso_pkts_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
50273 +{
50274 + int i, j;
50275 + dma_addr_t dma_ad;
50276 + iso_pkt_info_t *packet_info = ep->pkt_info;
50277 + uint32_t offset;
50278 + uint32_t frame_data;
50279 + deptsiz_data_t deptsiz;
50280 +
50281 + if (ep->proc_buf_num == 0) {
50282 + /** Buffer 0 descriptors setup */
50283 + dma_ad = ep->dma_addr0;
50284 + } else {
50285 + /** Buffer 1 descriptors setup */
50286 + dma_ad = ep->dma_addr1;
50287 + }
50288 +
50289 + if (ep->is_in) {
50290 + deptsiz.d32 =
50291 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
50292 + dieptsiz);
50293 + } else {
50294 + deptsiz.d32 =
50295 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[ep->num]->
50296 + doeptsiz);
50297 + }
50298 +
50299 + if (!deptsiz.b.xfersize) {
50300 + offset = 0;
50301 + for (i = 0; i < ep->pkt_cnt; i += ep->pkt_per_frm) {
50302 + frame_data = ep->data_per_frame;
50303 + for (j = 0; j < ep->pkt_per_frm; ++j) {
50304 +
50305 + /* Packet status - is not set as initially
50306 + * it is set to 0 and if packet was sent
50307 + successfully, status field will remain 0*/
50308 +
50309 + /* Bytes has been transfered */
50310 + packet_info->length =
50311 + (ep->maxpacket <
50312 + frame_data) ? ep->maxpacket : frame_data;
50313 +
50314 + /* Received packet offset */
50315 + packet_info->offset = offset;
50316 + offset += packet_info->length;
50317 + frame_data -= packet_info->length;
50318 +
50319 + packet_info++;
50320 + }
50321 + }
50322 + return 1;
50323 + } else {
50324 + /* This is a workaround for in case of Transfer Complete with
50325 + * PktDrpSts interrupts merging - in this case Transfer complete
50326 + * interrupt for Isoc Out Endpoint is asserted without PktDrpSts
50327 + * set and with DOEPTSIZ register non zero. Investigations showed,
50328 + * that this happens when Out packet is dropped, but because of
50329 + * interrupts merging during first interrupt handling PktDrpSts
50330 + * bit is cleared and for next merged interrupts it is not reset.
50331 + * In this case SW hadles the interrupt as if PktDrpSts bit is set.
50332 + */
50333 + if (ep->is_in) {
50334 + return 1;
50335 + } else {
50336 + return handle_iso_out_pkt_dropped(core_if, ep);
50337 + }
50338 + }
50339 +}
50340 +
50341 +/**
50342 + * This function is to handle Iso EP transfer complete interrupt
50343 + *
50344 + * @param pcd The PCD
50345 + * @param ep The EP for which transfer complete was asserted
50346 + *
50347 + */
50348 +static void complete_iso_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
50349 +{
50350 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
50351 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
50352 + uint8_t is_last = 0;
50353 +
50354 + if (ep->dwc_ep.next_frame == 0xffffffff) {
50355 + DWC_WARN("Next frame is not set!\n");
50356 + return;
50357 + }
50358 +
50359 + if (core_if->dma_enable) {
50360 + if (core_if->dma_desc_enable) {
50361 + set_ddma_iso_pkts_info(core_if, dwc_ep);
50362 + reinit_ddma_iso_xfer(core_if, dwc_ep);
50363 + is_last = 1;
50364 + } else {
50365 + if (core_if->pti_enh_enable) {
50366 + if (set_iso_pkts_info(core_if, dwc_ep)) {
50367 + dwc_ep->proc_buf_num =
50368 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
50369 + dwc_otg_iso_ep_start_buf_transfer
50370 + (core_if, dwc_ep);
50371 + is_last = 1;
50372 + }
50373 + } else {
50374 + set_current_pkt_info(core_if, dwc_ep);
50375 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
50376 + is_last = 1;
50377 + dwc_ep->cur_pkt = 0;
50378 + dwc_ep->proc_buf_num =
50379 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
50380 + if (dwc_ep->proc_buf_num) {
50381 + dwc_ep->cur_pkt_addr =
50382 + dwc_ep->xfer_buff1;
50383 + dwc_ep->cur_pkt_dma_addr =
50384 + dwc_ep->dma_addr1;
50385 + } else {
50386 + dwc_ep->cur_pkt_addr =
50387 + dwc_ep->xfer_buff0;
50388 + dwc_ep->cur_pkt_dma_addr =
50389 + dwc_ep->dma_addr0;
50390 + }
50391 +
50392 + }
50393 + dwc_otg_iso_ep_start_frm_transfer(core_if,
50394 + dwc_ep);
50395 + }
50396 + }
50397 + } else {
50398 + set_current_pkt_info(core_if, dwc_ep);
50399 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
50400 + is_last = 1;
50401 + dwc_ep->cur_pkt = 0;
50402 + dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
50403 + if (dwc_ep->proc_buf_num) {
50404 + dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff1;
50405 + dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr1;
50406 + } else {
50407 + dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff0;
50408 + dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr0;
50409 + }
50410 +
50411 + }
50412 + dwc_otg_iso_ep_start_frm_transfer(core_if, dwc_ep);
50413 + }
50414 + if (is_last)
50415 + dwc_otg_iso_buffer_done(pcd, ep, ep->iso_req_handle);
50416 +}
50417 +#endif /* DWC_EN_ISOC */
50418 +
50419 +/**
50420 + * This function handle BNA interrupt for Non Isochronous EPs
50421 + *
50422 + */
50423 +static void dwc_otg_pcd_handle_noniso_bna(dwc_otg_pcd_ep_t * ep)
50424 +{
50425 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
50426 + volatile uint32_t *addr;
50427 + depctl_data_t depctl = {.d32 = 0 };
50428 + dwc_otg_pcd_t *pcd = ep->pcd;
50429 + dwc_otg_dev_dma_desc_t *dma_desc;
50430 + dev_dma_desc_sts_t sts = {.d32 = 0 };
50431 + dwc_otg_core_if_t *core_if = ep->pcd->core_if;
50432 + int i, start;
50433 +
50434 + if (!dwc_ep->desc_cnt)
50435 + DWC_WARN("Ep%d %s Descriptor count = %d \n", dwc_ep->num,
50436 + (dwc_ep->is_in ? "IN" : "OUT"), dwc_ep->desc_cnt);
50437 +
50438 + if (core_if->core_params->cont_on_bna && !dwc_ep->is_in
50439 + && dwc_ep->type != DWC_OTG_EP_TYPE_CONTROL) {
50440 + uint32_t doepdma;
50441 + dwc_otg_dev_out_ep_regs_t *out_regs =
50442 + core_if->dev_if->out_ep_regs[dwc_ep->num];
50443 + doepdma = DWC_READ_REG32(&(out_regs->doepdma));
50444 + start = (doepdma - dwc_ep->dma_desc_addr)/sizeof(dwc_otg_dev_dma_desc_t);
50445 + dma_desc = &(dwc_ep->desc_addr[start]);
50446 + } else {
50447 + start = 0;
50448 + dma_desc = dwc_ep->desc_addr;
50449 + }
50450 +
50451 +
50452 + for (i = start; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
50453 + sts.d32 = dma_desc->status.d32;
50454 + sts.b.bs = BS_HOST_READY;
50455 + dma_desc->status.d32 = sts.d32;
50456 + }
50457 +
50458 + if (dwc_ep->is_in == 0) {
50459 + addr =
50460 + &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->num]->
50461 + doepctl;
50462 + } else {
50463 + addr =
50464 + &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
50465 + }
50466 + depctl.b.epena = 1;
50467 + depctl.b.cnak = 1;
50468 + DWC_MODIFY_REG32(addr, 0, depctl.d32);
50469 +}
50470 +
50471 +/**
50472 + * This function handles EP0 Control transfers.
50473 + *
50474 + * The state of the control transfers are tracked in
50475 + * <code>ep0state</code>.
50476 + */
50477 +static void handle_ep0(dwc_otg_pcd_t * pcd)
50478 +{
50479 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
50480 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
50481 + dev_dma_desc_sts_t desc_sts;
50482 + deptsiz0_data_t deptsiz;
50483 + uint32_t byte_count;
50484 +
50485 +#ifdef DEBUG_EP0
50486 + DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
50487 + print_ep0_state(pcd);
50488 +#endif
50489 +
50490 +// DWC_PRINTF("HANDLE EP0\n");
50491 +
50492 + switch (pcd->ep0state) {
50493 + case EP0_DISCONNECT:
50494 + break;
50495 +
50496 + case EP0_IDLE:
50497 + pcd->request_config = 0;
50498 +
50499 + pcd_setup(pcd);
50500 + break;
50501 +
50502 + case EP0_IN_DATA_PHASE:
50503 +#ifdef DEBUG_EP0
50504 + DWC_DEBUGPL(DBG_PCD, "DATA_IN EP%d-%s: type=%d, mps=%d\n",
50505 + ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
50506 + ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
50507 +#endif
50508 +
50509 + if (core_if->dma_enable != 0) {
50510 + /*
50511 + * For EP0 we can only program 1 packet at a time so we
50512 + * need to do the make calculations after each complete.
50513 + * Call write_packet to make the calculations, as in
50514 + * slave mode, and use those values to determine if we
50515 + * can complete.
50516 + */
50517 + if (core_if->dma_desc_enable == 0) {
50518 + deptsiz.d32 =
50519 + DWC_READ_REG32(&core_if->
50520 + dev_if->in_ep_regs[0]->
50521 + dieptsiz);
50522 + byte_count =
50523 + ep0->dwc_ep.xfer_len - deptsiz.b.xfersize;
50524 + } else {
50525 + desc_sts =
50526 + core_if->dev_if->in_desc_addr->status;
50527 + byte_count =
50528 + ep0->dwc_ep.xfer_len - desc_sts.b.bytes;
50529 + }
50530 + ep0->dwc_ep.xfer_count += byte_count;
50531 + ep0->dwc_ep.xfer_buff += byte_count;
50532 + ep0->dwc_ep.dma_addr += byte_count;
50533 + }
50534 + if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
50535 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50536 + &ep0->dwc_ep);
50537 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
50538 + } else if (ep0->dwc_ep.sent_zlp) {
50539 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50540 + &ep0->dwc_ep);
50541 + ep0->dwc_ep.sent_zlp = 0;
50542 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n");
50543 + } else {
50544 + ep0_complete_request(ep0);
50545 + DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
50546 + }
50547 + break;
50548 + case EP0_OUT_DATA_PHASE:
50549 +#ifdef DEBUG_EP0
50550 + DWC_DEBUGPL(DBG_PCD, "DATA_OUT EP%d-%s: type=%d, mps=%d\n",
50551 + ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
50552 + ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
50553 +#endif
50554 + if (core_if->dma_enable != 0) {
50555 + if (core_if->dma_desc_enable == 0) {
50556 + deptsiz.d32 =
50557 + DWC_READ_REG32(&core_if->
50558 + dev_if->out_ep_regs[0]->
50559 + doeptsiz);
50560 + byte_count =
50561 + ep0->dwc_ep.maxpacket - deptsiz.b.xfersize;
50562 + } else {
50563 + desc_sts =
50564 + core_if->dev_if->out_desc_addr->status;
50565 + byte_count =
50566 + ep0->dwc_ep.maxpacket - desc_sts.b.bytes;
50567 + }
50568 + ep0->dwc_ep.xfer_count += byte_count;
50569 + ep0->dwc_ep.xfer_buff += byte_count;
50570 + ep0->dwc_ep.dma_addr += byte_count;
50571 + }
50572 + if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
50573 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50574 + &ep0->dwc_ep);
50575 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
50576 + } else if (ep0->dwc_ep.sent_zlp) {
50577 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50578 + &ep0->dwc_ep);
50579 + ep0->dwc_ep.sent_zlp = 0;
50580 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n");
50581 + } else {
50582 + ep0_complete_request(ep0);
50583 + DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
50584 + }
50585 + break;
50586 +
50587 + case EP0_IN_STATUS_PHASE:
50588 + case EP0_OUT_STATUS_PHASE:
50589 + DWC_DEBUGPL(DBG_PCD, "CASE: EP0_STATUS\n");
50590 + ep0_complete_request(ep0);
50591 + pcd->ep0state = EP0_IDLE;
50592 + ep0->stopped = 1;
50593 + ep0->dwc_ep.is_in = 0; /* OUT for next SETUP */
50594 +
50595 + /* Prepare for more SETUP Packets */
50596 + if (core_if->dma_enable) {
50597 + ep0_out_start(core_if, pcd);
50598 + }
50599 + break;
50600 +
50601 + case EP0_STALL:
50602 + DWC_ERROR("EP0 STALLed, should not get here pcd_setup()\n");
50603 + break;
50604 + }
50605 +#ifdef DEBUG_EP0
50606 + print_ep0_state(pcd);
50607 +#endif
50608 +}
50609 +
50610 +/**
50611 + * Restart transfer
50612 + */
50613 +static void restart_transfer(dwc_otg_pcd_t * pcd, const uint32_t epnum)
50614 +{
50615 + dwc_otg_core_if_t *core_if;
50616 + dwc_otg_dev_if_t *dev_if;
50617 + deptsiz_data_t dieptsiz = {.d32 = 0 };
50618 + dwc_otg_pcd_ep_t *ep;
50619 +
50620 + ep = get_in_ep(pcd, epnum);
50621 +
50622 +#ifdef DWC_EN_ISOC
50623 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
50624 + return;
50625 + }
50626 +#endif /* DWC_EN_ISOC */
50627 +
50628 + core_if = GET_CORE_IF(pcd);
50629 + dev_if = core_if->dev_if;
50630 +
50631 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
50632 +
50633 + DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x xfer_len=%0x"
50634 + " stopped=%d\n", ep->dwc_ep.xfer_buff,
50635 + ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len, ep->stopped);
50636 + /*
50637 + * If xfersize is 0 and pktcnt in not 0, resend the last packet.
50638 + */
50639 + if (dieptsiz.b.pktcnt && dieptsiz.b.xfersize == 0 &&
50640 + ep->dwc_ep.start_xfer_buff != 0) {
50641 + if (ep->dwc_ep.total_len <= ep->dwc_ep.maxpacket) {
50642 + ep->dwc_ep.xfer_count = 0;
50643 + ep->dwc_ep.xfer_buff = ep->dwc_ep.start_xfer_buff;
50644 + ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
50645 + } else {
50646 + ep->dwc_ep.xfer_count -= ep->dwc_ep.maxpacket;
50647 + /* convert packet size to dwords. */
50648 + ep->dwc_ep.xfer_buff -= ep->dwc_ep.maxpacket;
50649 + ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
50650 + }
50651 + ep->stopped = 0;
50652 + DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x "
50653 + "xfer_len=%0x stopped=%d\n",
50654 + ep->dwc_ep.xfer_buff,
50655 + ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len,
50656 + ep->stopped);
50657 + if (epnum == 0) {
50658 + dwc_otg_ep0_start_transfer(core_if, &ep->dwc_ep);
50659 + } else {
50660 + dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
50661 + }
50662 + }
50663 +}
50664 +
50665 +/*
50666 + * This function create new nextep sequnce based on Learn Queue.
50667 + *
50668 + * @param core_if Programming view of DWC_otg controller
50669 + */
50670 +void predict_nextep_seq( dwc_otg_core_if_t * core_if)
50671 +{
50672 + dwc_otg_device_global_regs_t *dev_global_regs =
50673 + core_if->dev_if->dev_global_regs;
50674 + const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
50675 + /* Number of Token Queue Registers */
50676 + const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
50677 + dtknq1_data_t dtknqr1;
50678 + uint32_t in_tkn_epnums[4];
50679 + uint8_t seqnum[MAX_EPS_CHANNELS];
50680 + uint8_t intkn_seq[TOKEN_Q_DEPTH];
50681 + grstctl_t resetctl = {.d32 = 0 };
50682 + uint8_t temp;
50683 + int ndx = 0;
50684 + int start = 0;
50685 + int end = 0;
50686 + int sort_done = 0;
50687 + int i = 0;
50688 + volatile uint32_t *addr = &dev_global_regs->dtknqr1;
50689 +
50690 +
50691 + DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
50692 +
50693 + /* Read the DTKNQ Registers */
50694 + for (i = 0; i < DTKNQ_REG_CNT; i++) {
50695 + in_tkn_epnums[i] = DWC_READ_REG32(addr);
50696 + DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
50697 + in_tkn_epnums[i]);
50698 + if (addr == &dev_global_regs->dvbusdis) {
50699 + addr = &dev_global_regs->dtknqr3_dthrctl;
50700 + } else {
50701 + ++addr;
50702 + }
50703 +
50704 + }
50705 +
50706 + /* Copy the DTKNQR1 data to the bit field. */
50707 + dtknqr1.d32 = in_tkn_epnums[0];
50708 + if (dtknqr1.b.wrap_bit) {
50709 + ndx = dtknqr1.b.intknwptr;
50710 + end = ndx -1;
50711 + if (end < 0)
50712 + end = TOKEN_Q_DEPTH -1;
50713 + } else {
50714 + ndx = 0;
50715 + end = dtknqr1.b.intknwptr -1;
50716 + if (end < 0)
50717 + end = 0;
50718 + }
50719 + start = ndx;
50720 +
50721 + /* Fill seqnum[] by initial values: EP number + 31 */
50722 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
50723 + seqnum[i] = i +31;
50724 + }
50725 +
50726 + /* Fill intkn_seq[] from in_tkn_epnums[0] */
50727 + for (i=0; i < 6; i++)
50728 + intkn_seq[i] = (in_tkn_epnums[0] >> ((7-i) * 4)) & 0xf;
50729 +
50730 + if (TOKEN_Q_DEPTH > 6) {
50731 + /* Fill intkn_seq[] from in_tkn_epnums[1] */
50732 + for (i=6; i < 14; i++)
50733 + intkn_seq[i] =
50734 + (in_tkn_epnums[1] >> ((7 - (i - 6)) * 4)) & 0xf;
50735 + }
50736 +
50737 + if (TOKEN_Q_DEPTH > 14) {
50738 + /* Fill intkn_seq[] from in_tkn_epnums[1] */
50739 + for (i=14; i < 22; i++)
50740 + intkn_seq[i] =
50741 + (in_tkn_epnums[2] >> ((7 - (i - 14)) * 4)) & 0xf;
50742 + }
50743 +
50744 + if (TOKEN_Q_DEPTH > 22) {
50745 + /* Fill intkn_seq[] from in_tkn_epnums[1] */
50746 + for (i=22; i < 30; i++)
50747 + intkn_seq[i] =
50748 + (in_tkn_epnums[3] >> ((7 - (i - 22)) * 4)) & 0xf;
50749 + }
50750 +
50751 + DWC_DEBUGPL(DBG_PCDV, "%s start=%d end=%d intkn_seq[]:\n", __func__,
50752 + start, end);
50753 + for (i=0; i<TOKEN_Q_DEPTH; i++)
50754 + DWC_DEBUGPL(DBG_PCDV,"%d\n", intkn_seq[i]);
50755 +
50756 + /* Update seqnum based on intkn_seq[] */
50757 + i = 0;
50758 + do {
50759 + seqnum[intkn_seq[ndx]] = i;
50760 + ndx++;
50761 + i++;
50762 + if (ndx == TOKEN_Q_DEPTH)
50763 + ndx = 0;
50764 + } while ( i < TOKEN_Q_DEPTH );
50765 +
50766 + /* Mark non active EP's in seqnum[] by 0xff */
50767 + for (i=0; i<=core_if->dev_if->num_in_eps; i++) {
50768 + if (core_if->nextep_seq[i] == 0xff )
50769 + seqnum[i] = 0xff;
50770 + }
50771 +
50772 + /* Sort seqnum[] */
50773 + sort_done = 0;
50774 + while (!sort_done) {
50775 + sort_done = 1;
50776 + for (i=0; i<core_if->dev_if->num_in_eps; i++) {
50777 + if (seqnum[i] > seqnum[i+1]) {
50778 + temp = seqnum[i];
50779 + seqnum[i] = seqnum[i+1];
50780 + seqnum[i+1] = temp;
50781 + sort_done = 0;
50782 + }
50783 + }
50784 + }
50785 +
50786 + ndx = start + seqnum[0];
50787 + if (ndx >= TOKEN_Q_DEPTH)
50788 + ndx = ndx % TOKEN_Q_DEPTH;
50789 + core_if->first_in_nextep_seq = intkn_seq[ndx];
50790 +
50791 + /* Update seqnum[] by EP numbers */
50792 + for (i=0; i<=core_if->dev_if->num_in_eps; i++) {
50793 + ndx = start + i;
50794 + if (seqnum[i] < 31) {
50795 + ndx = start + seqnum[i];
50796 + if (ndx >= TOKEN_Q_DEPTH)
50797 + ndx = ndx % TOKEN_Q_DEPTH;
50798 + seqnum[i] = intkn_seq[ndx];
50799 + } else {
50800 + if (seqnum[i] < 0xff) {
50801 + seqnum[i] = seqnum[i] - 31;
50802 + } else {
50803 + break;
50804 + }
50805 + }
50806 + }
50807 +
50808 + /* Update nextep_seq[] based on seqnum[] */
50809 + for (i=0; i<core_if->dev_if->num_in_eps; i++) {
50810 + if (seqnum[i] != 0xff) {
50811 + if (seqnum[i+1] != 0xff) {
50812 + core_if->nextep_seq[seqnum[i]] = seqnum[i+1];
50813 + } else {
50814 + core_if->nextep_seq[seqnum[i]] = core_if->first_in_nextep_seq;
50815 + break;
50816 + }
50817 + } else {
50818 + break;
50819 + }
50820 + }
50821 +
50822 + DWC_DEBUGPL(DBG_PCDV, "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
50823 + __func__, core_if->first_in_nextep_seq);
50824 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
50825 + DWC_DEBUGPL(DBG_PCDV,"%2d\n", core_if->nextep_seq[i]);
50826 + }
50827 +
50828 + /* Flush the Learning Queue */
50829 + resetctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->grstctl);
50830 + resetctl.b.intknqflsh = 1;
50831 + DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
50832 +
50833 +
50834 +}
50835 +
50836 +/**
50837 + * handle the IN EP disable interrupt.
50838 + */
50839 +static inline void handle_in_ep_disable_intr(dwc_otg_pcd_t * pcd,
50840 + const uint32_t epnum)
50841 +{
50842 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
50843 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
50844 + deptsiz_data_t dieptsiz = {.d32 = 0 };
50845 + dctl_data_t dctl = {.d32 = 0 };
50846 + dwc_otg_pcd_ep_t *ep;
50847 + dwc_ep_t *dwc_ep;
50848 + gintmsk_data_t gintmsk_data;
50849 + depctl_data_t depctl;
50850 + uint32_t diepdma;
50851 + uint32_t remain_to_transfer = 0;
50852 + uint8_t i;
50853 + uint32_t xfer_size;
50854 +
50855 + ep = get_in_ep(pcd, epnum);
50856 + dwc_ep = &ep->dwc_ep;
50857 +
50858 + if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
50859 + dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
50860 + complete_ep(ep);
50861 + return;
50862 + }
50863 +
50864 + DWC_DEBUGPL(DBG_PCD, "diepctl%d=%0x\n", epnum,
50865 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl));
50866 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
50867 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
50868 +
50869 + DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
50870 + dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
50871 +
50872 + if ((core_if->start_predict == 0) || (depctl.b.eptype & 1)) {
50873 + if (ep->stopped) {
50874 + if (core_if->en_multiple_tx_fifo)
50875 + /* Flush the Tx FIFO */
50876 + dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
50877 + /* Clear the Global IN NP NAK */
50878 + dctl.d32 = 0;
50879 + dctl.b.cgnpinnak = 1;
50880 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
50881 + /* Restart the transaction */
50882 + if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
50883 + restart_transfer(pcd, epnum);
50884 + }
50885 + } else {
50886 + /* Restart the transaction */
50887 + if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
50888 + restart_transfer(pcd, epnum);
50889 + }
50890 + DWC_DEBUGPL(DBG_ANY, "STOPPED!!!\n");
50891 + }
50892 + return;
50893 + }
50894 +
50895 + if (core_if->start_predict > 2) { // NP IN EP
50896 + core_if->start_predict--;
50897 + return;
50898 + }
50899 +
50900 + core_if->start_predict--;
50901 +
50902 + if (core_if->start_predict == 1) { // All NP IN Ep's disabled now
50903 +
50904 + predict_nextep_seq(core_if);
50905 +
50906 + /* Update all active IN EP's NextEP field based of nextep_seq[] */
50907 + for ( i = 0; i <= core_if->dev_if->num_in_eps; i++) {
50908 + depctl.d32 =
50909 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50910 + if (core_if->nextep_seq[i] != 0xff) { // Active NP IN EP
50911 + depctl.b.nextep = core_if->nextep_seq[i];
50912 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
50913 + }
50914 + }
50915 + /* Flush Shared NP TxFIFO */
50916 + dwc_otg_flush_tx_fifo(core_if, 0);
50917 + /* Rewind buffers */
50918 + if (!core_if->dma_desc_enable) {
50919 + i = core_if->first_in_nextep_seq;
50920 + do {
50921 + ep = get_in_ep(pcd, i);
50922 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
50923 + xfer_size = ep->dwc_ep.total_len - ep->dwc_ep.xfer_count;
50924 + if (xfer_size > ep->dwc_ep.maxxfer)
50925 + xfer_size = ep->dwc_ep.maxxfer;
50926 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50927 + if (dieptsiz.b.pktcnt != 0) {
50928 + if (xfer_size == 0) {
50929 + remain_to_transfer = 0;
50930 + } else {
50931 + if ((xfer_size % ep->dwc_ep.maxpacket) == 0) {
50932 + remain_to_transfer =
50933 + dieptsiz.b.pktcnt * ep->dwc_ep.maxpacket;
50934 + } else {
50935 + remain_to_transfer = ((dieptsiz.b.pktcnt -1) * ep->dwc_ep.maxpacket)
50936 + + (xfer_size % ep->dwc_ep.maxpacket);
50937 + }
50938 + }
50939 + diepdma = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepdma);
50940 + dieptsiz.b.xfersize = remain_to_transfer;
50941 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, dieptsiz.d32);
50942 + diepdma = ep->dwc_ep.dma_addr + (xfer_size - remain_to_transfer);
50943 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, diepdma);
50944 + }
50945 + i = core_if->nextep_seq[i];
50946 + } while (i != core_if->first_in_nextep_seq);
50947 + } else { // dma_desc_enable
50948 + DWC_PRINTF("%s Learning Queue not supported in DDMA\n", __func__);
50949 + }
50950 +
50951 + /* Restart transfers in predicted sequences */
50952 + i = core_if->first_in_nextep_seq;
50953 + do {
50954 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
50955 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50956 + if (dieptsiz.b.pktcnt != 0) {
50957 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50958 + depctl.b.epena = 1;
50959 + depctl.b.cnak = 1;
50960 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
50961 + }
50962 + i = core_if->nextep_seq[i];
50963 + } while (i != core_if->first_in_nextep_seq);
50964 +
50965 + /* Clear the global non-periodic IN NAK handshake */
50966 + dctl.d32 = 0;
50967 + dctl.b.cgnpinnak = 1;
50968 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
50969 +
50970 + /* Unmask EP Mismatch interrupt */
50971 + gintmsk_data.d32 = 0;
50972 + gintmsk_data.b.epmismatch = 1;
50973 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk_data.d32);
50974 +
50975 + core_if->start_predict = 0;
50976 +
50977 + }
50978 +}
50979 +
50980 +/**
50981 + * Handler for the IN EP timeout handshake interrupt.
50982 + */
50983 +static inline void handle_in_ep_timeout_intr(dwc_otg_pcd_t * pcd,
50984 + const uint32_t epnum)
50985 +{
50986 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
50987 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
50988 +
50989 +#ifdef DEBUG
50990 + deptsiz_data_t dieptsiz = {.d32 = 0 };
50991 + uint32_t num = 0;
50992 +#endif
50993 + dctl_data_t dctl = {.d32 = 0 };
50994 + dwc_otg_pcd_ep_t *ep;
50995 +
50996 + gintmsk_data_t intr_mask = {.d32 = 0 };
50997 +
50998 + ep = get_in_ep(pcd, epnum);
50999 +
51000 + /* Disable the NP Tx Fifo Empty Interrrupt */
51001 + if (!core_if->dma_enable) {
51002 + intr_mask.b.nptxfempty = 1;
51003 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
51004 + intr_mask.d32, 0);
51005 + }
51006 + /** @todo NGS Check EP type.
51007 + * Implement for Periodic EPs */
51008 + /*
51009 + * Non-periodic EP
51010 + */
51011 + /* Enable the Global IN NAK Effective Interrupt */
51012 + intr_mask.b.ginnakeff = 1;
51013 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
51014 +
51015 + /* Set Global IN NAK */
51016 + dctl.b.sgnpinnak = 1;
51017 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
51018 +
51019 + ep->stopped = 1;
51020 +
51021 +#ifdef DEBUG
51022 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[num]->dieptsiz);
51023 + DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
51024 + dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
51025 +#endif
51026 +
51027 +#ifdef DISABLE_PERIODIC_EP
51028 + /*
51029 + * Set the NAK bit for this EP to
51030 + * start the disable process.
51031 + */
51032 + diepctl.d32 = 0;
51033 + diepctl.b.snak = 1;
51034 + DWC_MODIFY_REG32(&dev_if->in_ep_regs[num]->diepctl, diepctl.d32,
51035 + diepctl.d32);
51036 + ep->disabling = 1;
51037 + ep->stopped = 1;
51038 +#endif
51039 +}
51040 +
51041 +/**
51042 + * Handler for the IN EP NAK interrupt.
51043 + */
51044 +static inline int32_t handle_in_ep_nak_intr(dwc_otg_pcd_t * pcd,
51045 + const uint32_t epnum)
51046 +{
51047 + /** @todo implement ISR */
51048 + dwc_otg_core_if_t *core_if;
51049 + diepmsk_data_t intr_mask = {.d32 = 0 };
51050 +
51051 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "IN EP NAK");
51052 + core_if = GET_CORE_IF(pcd);
51053 + intr_mask.b.nak = 1;
51054 +
51055 + if (core_if->multiproc_int_enable) {
51056 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
51057 + diepeachintmsk[epnum], intr_mask.d32, 0);
51058 + } else {
51059 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->diepmsk,
51060 + intr_mask.d32, 0);
51061 + }
51062 +
51063 + return 1;
51064 +}
51065 +
51066 +/**
51067 + * Handler for the OUT EP Babble interrupt.
51068 + */
51069 +static inline int32_t handle_out_ep_babble_intr(dwc_otg_pcd_t * pcd,
51070 + const uint32_t epnum)
51071 +{
51072 + /** @todo implement ISR */
51073 + dwc_otg_core_if_t *core_if;
51074 + doepmsk_data_t intr_mask = {.d32 = 0 };
51075 +
51076 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
51077 + "OUT EP Babble");
51078 + core_if = GET_CORE_IF(pcd);
51079 + intr_mask.b.babble = 1;
51080 +
51081 + if (core_if->multiproc_int_enable) {
51082 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
51083 + doepeachintmsk[epnum], intr_mask.d32, 0);
51084 + } else {
51085 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
51086 + intr_mask.d32, 0);
51087 + }
51088 +
51089 + return 1;
51090 +}
51091 +
51092 +/**
51093 + * Handler for the OUT EP NAK interrupt.
51094 + */
51095 +static inline int32_t handle_out_ep_nak_intr(dwc_otg_pcd_t * pcd,
51096 + const uint32_t epnum)
51097 +{
51098 + /** @todo implement ISR */
51099 + dwc_otg_core_if_t *core_if;
51100 + doepmsk_data_t intr_mask = {.d32 = 0 };
51101 +
51102 + DWC_DEBUGPL(DBG_ANY, "INTERRUPT Handler not implemented for %s\n", "OUT EP NAK");
51103 + core_if = GET_CORE_IF(pcd);
51104 + intr_mask.b.nak = 1;
51105 +
51106 + if (core_if->multiproc_int_enable) {
51107 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
51108 + doepeachintmsk[epnum], intr_mask.d32, 0);
51109 + } else {
51110 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
51111 + intr_mask.d32, 0);
51112 + }
51113 +
51114 + return 1;
51115 +}
51116 +
51117 +/**
51118 + * Handler for the OUT EP NYET interrupt.
51119 + */
51120 +static inline int32_t handle_out_ep_nyet_intr(dwc_otg_pcd_t * pcd,
51121 + const uint32_t epnum)
51122 +{
51123 + /** @todo implement ISR */
51124 + dwc_otg_core_if_t *core_if;
51125 + doepmsk_data_t intr_mask = {.d32 = 0 };
51126 +
51127 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NYET");
51128 + core_if = GET_CORE_IF(pcd);
51129 + intr_mask.b.nyet = 1;
51130 +
51131 + if (core_if->multiproc_int_enable) {
51132 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
51133 + doepeachintmsk[epnum], intr_mask.d32, 0);
51134 + } else {
51135 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
51136 + intr_mask.d32, 0);
51137 + }
51138 +
51139 + return 1;
51140 +}
51141 +
51142 +/**
51143 + * This interrupt indicates that an IN EP has a pending Interrupt.
51144 + * The sequence for handling the IN EP interrupt is shown below:
51145 + * -# Read the Device All Endpoint Interrupt register
51146 + * -# Repeat the following for each IN EP interrupt bit set (from
51147 + * LSB to MSB).
51148 + * -# Read the Device Endpoint Interrupt (DIEPINTn) register
51149 + * -# If "Transfer Complete" call the request complete function
51150 + * -# If "Endpoint Disabled" complete the EP disable procedure.
51151 + * -# If "AHB Error Interrupt" log error
51152 + * -# If "Time-out Handshake" log error
51153 + * -# If "IN Token Received when TxFIFO Empty" write packet to Tx
51154 + * FIFO.
51155 + * -# If "IN Token EP Mismatch" (disable, this is handled by EP
51156 + * Mismatch Interrupt)
51157 + */
51158 +static int32_t dwc_otg_pcd_handle_in_ep_intr(dwc_otg_pcd_t * pcd)
51159 +{
51160 +#define CLEAR_IN_EP_INTR(__core_if,__epnum,__intr) \
51161 +do { \
51162 + diepint_data_t diepint = {.d32=0}; \
51163 + diepint.b.__intr = 1; \
51164 + DWC_WRITE_REG32(&__core_if->dev_if->in_ep_regs[__epnum]->diepint, \
51165 + diepint.d32); \
51166 +} while (0)
51167 +
51168 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
51169 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
51170 + diepint_data_t diepint = {.d32 = 0 };
51171 + depctl_data_t depctl = {.d32 = 0 };
51172 + uint32_t ep_intr;
51173 + uint32_t epnum = 0;
51174 + dwc_otg_pcd_ep_t *ep;
51175 + dwc_ep_t *dwc_ep;
51176 + gintmsk_data_t intr_mask = {.d32 = 0 };
51177 +
51178 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, pcd);
51179 +
51180 + /* Read in the device interrupt bits */
51181 + ep_intr = dwc_otg_read_dev_all_in_ep_intr(core_if);
51182 +
51183 + /* Service the Device IN interrupts for each endpoint */
51184 + while (ep_intr) {
51185 + if (ep_intr & 0x1) {
51186 + uint32_t empty_msk;
51187 + /* Get EP pointer */
51188 + ep = get_in_ep(pcd, epnum);
51189 + dwc_ep = &ep->dwc_ep;
51190 +
51191 + depctl.d32 =
51192 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
51193 + empty_msk =
51194 + DWC_READ_REG32(&dev_if->
51195 + dev_global_regs->dtknqr4_fifoemptymsk);
51196 +
51197 + DWC_DEBUGPL(DBG_PCDV,
51198 + "IN EP INTERRUPT - %d\nepmty_msk - %8x diepctl - %8x\n",
51199 + epnum, empty_msk, depctl.d32);
51200 +
51201 + DWC_DEBUGPL(DBG_PCD,
51202 + "EP%d-%s: type=%d, mps=%d\n",
51203 + dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
51204 + dwc_ep->type, dwc_ep->maxpacket);
51205 +
51206 + diepint.d32 =
51207 + dwc_otg_read_dev_in_ep_intr(core_if, dwc_ep);
51208 +
51209 + DWC_DEBUGPL(DBG_PCDV,
51210 + "EP %d Interrupt Register - 0x%x\n", epnum,
51211 + diepint.d32);
51212 + /* Transfer complete */
51213 + if (diepint.b.xfercompl) {
51214 + /* Disable the NP Tx FIFO Empty
51215 + * Interrupt */
51216 + if (core_if->en_multiple_tx_fifo == 0) {
51217 + intr_mask.b.nptxfempty = 1;
51218 + DWC_MODIFY_REG32
51219 + (&core_if->core_global_regs->gintmsk,
51220 + intr_mask.d32, 0);
51221 + } else {
51222 + /* Disable the Tx FIFO Empty Interrupt for this EP */
51223 + uint32_t fifoemptymsk =
51224 + 0x1 << dwc_ep->num;
51225 + DWC_MODIFY_REG32(&core_if->
51226 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
51227 + fifoemptymsk, 0);
51228 + }
51229 + /* Clear the bit in DIEPINTn for this interrupt */
51230 + CLEAR_IN_EP_INTR(core_if, epnum, xfercompl);
51231 +
51232 + /* Complete the transfer */
51233 + if (epnum == 0) {
51234 + handle_ep0(pcd);
51235 + }
51236 +#ifdef DWC_EN_ISOC
51237 + else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51238 + if (!ep->stopped)
51239 + complete_iso_ep(pcd, ep);
51240 + }
51241 +#endif /* DWC_EN_ISOC */
51242 +#ifdef DWC_UTE_PER_IO
51243 + else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51244 + if (!ep->stopped)
51245 + complete_xiso_ep(ep);
51246 + }
51247 +#endif /* DWC_UTE_PER_IO */
51248 + else {
51249 + if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC &&
51250 + dwc_ep->bInterval > 1) {
51251 + dwc_ep->frame_num += dwc_ep->bInterval;
51252 + if (dwc_ep->frame_num > 0x3FFF)
51253 + {
51254 + dwc_ep->frm_overrun = 1;
51255 + dwc_ep->frame_num &= 0x3FFF;
51256 + } else
51257 + dwc_ep->frm_overrun = 0;
51258 + }
51259 + complete_ep(ep);
51260 + if(diepint.b.nak)
51261 + CLEAR_IN_EP_INTR(core_if, epnum, nak);
51262 + }
51263 + }
51264 + /* Endpoint disable */
51265 + if (diepint.b.epdisabled) {
51266 + DWC_DEBUGPL(DBG_ANY, "EP%d IN disabled\n",
51267 + epnum);
51268 + handle_in_ep_disable_intr(pcd, epnum);
51269 +
51270 + /* Clear the bit in DIEPINTn for this interrupt */
51271 + CLEAR_IN_EP_INTR(core_if, epnum, epdisabled);
51272 + }
51273 + /* AHB Error */
51274 + if (diepint.b.ahberr) {
51275 + DWC_ERROR("EP%d IN AHB Error\n", epnum);
51276 + /* Clear the bit in DIEPINTn for this interrupt */
51277 + CLEAR_IN_EP_INTR(core_if, epnum, ahberr);
51278 + }
51279 + /* TimeOUT Handshake (non-ISOC IN EPs) */
51280 + if (diepint.b.timeout) {
51281 + DWC_ERROR("EP%d IN Time-out\n", epnum);
51282 + handle_in_ep_timeout_intr(pcd, epnum);
51283 +
51284 + CLEAR_IN_EP_INTR(core_if, epnum, timeout);
51285 + }
51286 + /** IN Token received with TxF Empty */
51287 + if (diepint.b.intktxfemp) {
51288 + DWC_DEBUGPL(DBG_ANY,
51289 + "EP%d IN TKN TxFifo Empty\n",
51290 + epnum);
51291 + if (!ep->stopped && epnum != 0) {
51292 +
51293 + diepmsk_data_t diepmsk = {.d32 = 0 };
51294 + diepmsk.b.intktxfemp = 1;
51295 +
51296 + if (core_if->multiproc_int_enable) {
51297 + DWC_MODIFY_REG32
51298 + (&dev_if->dev_global_regs->diepeachintmsk
51299 + [epnum], diepmsk.d32, 0);
51300 + } else {
51301 + DWC_MODIFY_REG32
51302 + (&dev_if->dev_global_regs->diepmsk,
51303 + diepmsk.d32, 0);
51304 + }
51305 + } else if (core_if->dma_desc_enable
51306 + && epnum == 0
51307 + && pcd->ep0state ==
51308 + EP0_OUT_STATUS_PHASE) {
51309 + // EP0 IN set STALL
51310 + depctl.d32 =
51311 + DWC_READ_REG32(&dev_if->in_ep_regs
51312 + [epnum]->diepctl);
51313 +
51314 + /* set the disable and stall bits */
51315 + if (depctl.b.epena) {
51316 + depctl.b.epdis = 1;
51317 + }
51318 + depctl.b.stall = 1;
51319 + DWC_WRITE_REG32(&dev_if->in_ep_regs
51320 + [epnum]->diepctl,
51321 + depctl.d32);
51322 + }
51323 + CLEAR_IN_EP_INTR(core_if, epnum, intktxfemp);
51324 + }
51325 + /** IN Token Received with EP mismatch */
51326 + if (diepint.b.intknepmis) {
51327 + DWC_DEBUGPL(DBG_ANY,
51328 + "EP%d IN TKN EP Mismatch\n", epnum);
51329 + CLEAR_IN_EP_INTR(core_if, epnum, intknepmis);
51330 + }
51331 + /** IN Endpoint NAK Effective */
51332 + if (diepint.b.inepnakeff) {
51333 + DWC_DEBUGPL(DBG_ANY,
51334 + "EP%d IN EP NAK Effective\n",
51335 + epnum);
51336 + /* Periodic EP */
51337 + if (ep->disabling) {
51338 + depctl.d32 = 0;
51339 + depctl.b.snak = 1;
51340 + depctl.b.epdis = 1;
51341 + DWC_MODIFY_REG32(&dev_if->in_ep_regs
51342 + [epnum]->diepctl,
51343 + depctl.d32,
51344 + depctl.d32);
51345 + }
51346 + CLEAR_IN_EP_INTR(core_if, epnum, inepnakeff);
51347 +
51348 + }
51349 +
51350 + /** IN EP Tx FIFO Empty Intr */
51351 + if (diepint.b.emptyintr) {
51352 + DWC_DEBUGPL(DBG_ANY,
51353 + "EP%d Tx FIFO Empty Intr \n",
51354 + epnum);
51355 + write_empty_tx_fifo(pcd, epnum);
51356 +
51357 + CLEAR_IN_EP_INTR(core_if, epnum, emptyintr);
51358 +
51359 + }
51360 +
51361 + /** IN EP BNA Intr */
51362 + if (diepint.b.bna) {
51363 + CLEAR_IN_EP_INTR(core_if, epnum, bna);
51364 + if (core_if->dma_desc_enable) {
51365 +#ifdef DWC_EN_ISOC
51366 + if (dwc_ep->type ==
51367 + DWC_OTG_EP_TYPE_ISOC) {
51368 + /*
51369 + * This checking is performed to prevent first "false" BNA
51370 + * handling occuring right after reconnect
51371 + */
51372 + if (dwc_ep->next_frame !=
51373 + 0xffffffff)
51374 + dwc_otg_pcd_handle_iso_bna(ep);
51375 + } else
51376 +#endif /* DWC_EN_ISOC */
51377 + {
51378 + dwc_otg_pcd_handle_noniso_bna(ep);
51379 + }
51380 + }
51381 + }
51382 + /* NAK Interrutp */
51383 + if (diepint.b.nak) {
51384 + DWC_DEBUGPL(DBG_ANY, "EP%d IN NAK Interrupt\n",
51385 + epnum);
51386 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
51387 + depctl_data_t depctl;
51388 + if (ep->dwc_ep.frame_num == 0xFFFFFFFF) {
51389 + ep->dwc_ep.frame_num = core_if->frame_num;
51390 + if (ep->dwc_ep.bInterval > 1) {
51391 + depctl.d32 = 0;
51392 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
51393 + if (ep->dwc_ep.frame_num & 0x1) {
51394 + depctl.b.setd1pid = 1;
51395 + depctl.b.setd0pid = 0;
51396 + } else {
51397 + depctl.b.setd0pid = 1;
51398 + depctl.b.setd1pid = 0;
51399 + }
51400 + DWC_WRITE_REG32(&dev_if->in_ep_regs[epnum]->diepctl, depctl.d32);
51401 + }
51402 + start_next_request(ep);
51403 + }
51404 + ep->dwc_ep.frame_num += ep->dwc_ep.bInterval;
51405 + if (dwc_ep->frame_num > 0x3FFF) {
51406 + dwc_ep->frm_overrun = 1;
51407 + dwc_ep->frame_num &= 0x3FFF;
51408 + } else
51409 + dwc_ep->frm_overrun = 0;
51410 + }
51411 +
51412 + CLEAR_IN_EP_INTR(core_if, epnum, nak);
51413 + }
51414 + }
51415 + epnum++;
51416 + ep_intr >>= 1;
51417 + }
51418 +
51419 + return 1;
51420 +#undef CLEAR_IN_EP_INTR
51421 +}
51422 +
51423 +/**
51424 + * This interrupt indicates that an OUT EP has a pending Interrupt.
51425 + * The sequence for handling the OUT EP interrupt is shown below:
51426 + * -# Read the Device All Endpoint Interrupt register
51427 + * -# Repeat the following for each OUT EP interrupt bit set (from
51428 + * LSB to MSB).
51429 + * -# Read the Device Endpoint Interrupt (DOEPINTn) register
51430 + * -# If "Transfer Complete" call the request complete function
51431 + * -# If "Endpoint Disabled" complete the EP disable procedure.
51432 + * -# If "AHB Error Interrupt" log error
51433 + * -# If "Setup Phase Done" process Setup Packet (See Standard USB
51434 + * Command Processing)
51435 + */
51436 +static int32_t dwc_otg_pcd_handle_out_ep_intr(dwc_otg_pcd_t * pcd)
51437 +{
51438 +#define CLEAR_OUT_EP_INTR(__core_if,__epnum,__intr) \
51439 +do { \
51440 + doepint_data_t doepint = {.d32=0}; \
51441 + doepint.b.__intr = 1; \
51442 + DWC_WRITE_REG32(&__core_if->dev_if->out_ep_regs[__epnum]->doepint, \
51443 + doepint.d32); \
51444 +} while (0)
51445 +
51446 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
51447 + uint32_t ep_intr;
51448 + doepint_data_t doepint = {.d32 = 0 };
51449 + uint32_t epnum = 0;
51450 + dwc_otg_pcd_ep_t *ep;
51451 + dwc_ep_t *dwc_ep;
51452 + dctl_data_t dctl = {.d32 = 0 };
51453 + gintmsk_data_t gintmsk = {.d32 = 0 };
51454 +
51455 +
51456 + DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
51457 +
51458 + /* Read in the device interrupt bits */
51459 + ep_intr = dwc_otg_read_dev_all_out_ep_intr(core_if);
51460 +
51461 + while (ep_intr) {
51462 + if (ep_intr & 0x1) {
51463 + /* Get EP pointer */
51464 + ep = get_out_ep(pcd, epnum);
51465 + dwc_ep = &ep->dwc_ep;
51466 +
51467 +#ifdef VERBOSE
51468 + DWC_DEBUGPL(DBG_PCDV,
51469 + "EP%d-%s: type=%d, mps=%d\n",
51470 + dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
51471 + dwc_ep->type, dwc_ep->maxpacket);
51472 +#endif
51473 + doepint.d32 =
51474 + dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep);
51475 + /* Moved this interrupt upper due to core deffect of asserting
51476 + * OUT EP 0 xfercompl along with stsphsrcvd in BDMA */
51477 + if (doepint.b.stsphsercvd) {
51478 + deptsiz0_data_t deptsiz;
51479 + CLEAR_OUT_EP_INTR(core_if, epnum, stsphsercvd);
51480 + deptsiz.d32 =
51481 + DWC_READ_REG32(&core_if->dev_if->
51482 + out_ep_regs[0]->doeptsiz);
51483 + if (core_if->snpsid >= OTG_CORE_REV_3_00a
51484 + && core_if->dma_enable
51485 + && core_if->dma_desc_enable == 0
51486 + && doepint.b.xfercompl
51487 + && deptsiz.b.xfersize == 24) {
51488 + CLEAR_OUT_EP_INTR(core_if, epnum,
51489 + xfercompl);
51490 + doepint.b.xfercompl = 0;
51491 + ep0_out_start(core_if, pcd);
51492 + }
51493 + if ((core_if->dma_desc_enable) ||
51494 + (core_if->dma_enable
51495 + && core_if->snpsid >=
51496 + OTG_CORE_REV_3_00a)) {
51497 + do_setup_in_status_phase(pcd);
51498 + }
51499 + }
51500 + /* Transfer complete */
51501 + if (doepint.b.xfercompl) {
51502 +
51503 + if (epnum == 0) {
51504 + /* Clear the bit in DOEPINTn for this interrupt */
51505 + CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
51506 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
51507 + DWC_DEBUGPL(DBG_PCDV, "DOEPINT=%x doepint=%x\n",
51508 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepint),
51509 + doepint.d32);
51510 + DWC_DEBUGPL(DBG_PCDV, "DOEPCTL=%x \n",
51511 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepctl));
51512 +
51513 + if (core_if->snpsid >= OTG_CORE_REV_3_00a
51514 + && core_if->dma_enable == 0) {
51515 + doepint_data_t doepint;
51516 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51517 + out_ep_regs[0]->doepint);
51518 + if (pcd->ep0state == EP0_IDLE && doepint.b.sr) {
51519 + CLEAR_OUT_EP_INTR(core_if, epnum, sr);
51520 + goto exit_xfercompl;
51521 + }
51522 + }
51523 + /* In case of DDMA look at SR bit to go to the Data Stage */
51524 + if (core_if->dma_desc_enable) {
51525 + dev_dma_desc_sts_t status = {.d32 = 0};
51526 + if (pcd->ep0state == EP0_IDLE) {
51527 + status.d32 = core_if->dev_if->setup_desc_addr[core_if->
51528 + dev_if->setup_desc_index]->status.d32;
51529 + if(pcd->data_terminated) {
51530 + pcd->data_terminated = 0;
51531 + status.d32 = core_if->dev_if->out_desc_addr->status.d32;
51532 + dwc_memcpy(&pcd->setup_pkt->req, pcd->backup_buf, 8);
51533 + }
51534 + if (status.b.sr) {
51535 + if (doepint.b.setup) {
51536 + DWC_DEBUGPL(DBG_PCDV, "DMA DESC EP0_IDLE SR=1 setup=1\n");
51537 + /* Already started data stage, clear setup */
51538 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51539 + doepint.b.setup = 0;
51540 + handle_ep0(pcd);
51541 + /* Prepare for more setup packets */
51542 + if (pcd->ep0state == EP0_IN_STATUS_PHASE ||
51543 + pcd->ep0state == EP0_IN_DATA_PHASE) {
51544 + ep0_out_start(core_if, pcd);
51545 + }
51546 +
51547 + goto exit_xfercompl;
51548 + } else {
51549 + /* Prepare for more setup packets */
51550 + DWC_DEBUGPL(DBG_PCDV,
51551 + "EP0_IDLE SR=1 setup=0 new setup comes\n");
51552 + ep0_out_start(core_if, pcd);
51553 + }
51554 + }
51555 + } else {
51556 + dwc_otg_pcd_request_t *req;
51557 + dev_dma_desc_sts_t status = {.d32 = 0};
51558 + diepint_data_t diepint0;
51559 + diepint0.d32 = DWC_READ_REG32(&core_if->dev_if->
51560 + in_ep_regs[0]->diepint);
51561 +
51562 + if (pcd->ep0state == EP0_STALL || pcd->ep0state == EP0_DISCONNECT) {
51563 + DWC_ERROR("EP0 is stalled/disconnected\n");
51564 + }
51565 +
51566 + /* Clear IN xfercompl if set */
51567 + if (diepint0.b.xfercompl && (pcd->ep0state == EP0_IN_STATUS_PHASE
51568 + || pcd->ep0state == EP0_IN_DATA_PHASE)) {
51569 + DWC_WRITE_REG32(&core_if->dev_if->
51570 + in_ep_regs[0]->diepint, diepint0.d32);
51571 + }
51572 +
51573 + status.d32 = core_if->dev_if->setup_desc_addr[core_if->
51574 + dev_if->setup_desc_index]->status.d32;
51575 +
51576 + if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len
51577 + && (pcd->ep0state == EP0_OUT_DATA_PHASE))
51578 + status.d32 = core_if->dev_if->out_desc_addr->status.d32;
51579 + if (pcd->ep0state == EP0_OUT_STATUS_PHASE)
51580 + status.d32 = status.d32 = core_if->dev_if->
51581 + out_desc_addr->status.d32;
51582 +
51583 + if (status.b.sr) {
51584 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
51585 + DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n");
51586 + } else {
51587 + DWC_DEBUGPL(DBG_PCDV, "complete req!!\n");
51588 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
51589 + if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len &&
51590 + pcd->ep0state == EP0_OUT_DATA_PHASE) {
51591 + /* Read arrived setup packet from req->buf */
51592 + dwc_memcpy(&pcd->setup_pkt->req,
51593 + req->buf + ep->dwc_ep.xfer_count, 8);
51594 + }
51595 + req->actual = ep->dwc_ep.xfer_count;
51596 + dwc_otg_request_done(ep, req, -ECONNRESET);
51597 + ep->dwc_ep.start_xfer_buff = 0;
51598 + ep->dwc_ep.xfer_buff = 0;
51599 + ep->dwc_ep.xfer_len = 0;
51600 + }
51601 + pcd->ep0state = EP0_IDLE;
51602 + if (doepint.b.setup) {
51603 + DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n");
51604 + /* Data stage started, clear setup */
51605 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51606 + doepint.b.setup = 0;
51607 + handle_ep0(pcd);
51608 + /* Prepare for setup packets if ep0in was enabled*/
51609 + if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
51610 + ep0_out_start(core_if, pcd);
51611 + }
51612 +
51613 + goto exit_xfercompl;
51614 + } else {
51615 + /* Prepare for more setup packets */
51616 + DWC_DEBUGPL(DBG_PCDV,
51617 + "EP0_IDLE SR=1 setup=0 new setup comes 2\n");
51618 + ep0_out_start(core_if, pcd);
51619 + }
51620 + }
51621 + }
51622 + }
51623 + if (core_if->snpsid >= OTG_CORE_REV_2_94a && core_if->dma_enable
51624 + && core_if->dma_desc_enable == 0) {
51625 + doepint_data_t doepint_temp = {.d32 = 0};
51626 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
51627 + doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if->
51628 + out_ep_regs[ep->dwc_ep.num]->doepint);
51629 + doeptsize0.d32 = DWC_READ_REG32(&core_if->dev_if->
51630 + out_ep_regs[ep->dwc_ep.num]->doeptsiz);
51631 + if (pcd->ep0state == EP0_IDLE) {
51632 + if (doepint_temp.b.sr) {
51633 + CLEAR_OUT_EP_INTR(core_if, epnum, sr);
51634 + }
51635 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51636 + out_ep_regs[0]->doepint);
51637 + if (doeptsize0.b.supcnt == 3) {
51638 + DWC_DEBUGPL(DBG_ANY, "Rolling over!!!!!!!\n");
51639 + ep->dwc_ep.stp_rollover = 1;
51640 + }
51641 + if (doepint.b.setup) {
51642 +retry:
51643 + /* Already started data stage, clear setup */
51644 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51645 + doepint.b.setup = 0;
51646 + handle_ep0(pcd);
51647 + ep->dwc_ep.stp_rollover = 0;
51648 + /* Prepare for more setup packets */
51649 + if (pcd->ep0state == EP0_IN_STATUS_PHASE ||
51650 + pcd->ep0state == EP0_IN_DATA_PHASE) {
51651 + ep0_out_start(core_if, pcd);
51652 + }
51653 + goto exit_xfercompl;
51654 + } else {
51655 + /* Prepare for more setup packets */
51656 + DWC_DEBUGPL(DBG_ANY,
51657 + "EP0_IDLE SR=1 setup=0 new setup comes\n");
51658 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51659 + out_ep_regs[0]->doepint);
51660 + if(doepint.b.setup)
51661 + goto retry;
51662 + ep0_out_start(core_if, pcd);
51663 + }
51664 + } else {
51665 + dwc_otg_pcd_request_t *req;
51666 + diepint_data_t diepint0 = {.d32 = 0};
51667 + doepint_data_t doepint_temp = {.d32 = 0};
51668 + depctl_data_t diepctl0;
51669 + diepint0.d32 = DWC_READ_REG32(&core_if->dev_if->
51670 + in_ep_regs[0]->diepint);
51671 + diepctl0.d32 = DWC_READ_REG32(&core_if->dev_if->
51672 + in_ep_regs[0]->diepctl);
51673 +
51674 + if (pcd->ep0state == EP0_IN_DATA_PHASE
51675 + || pcd->ep0state == EP0_IN_STATUS_PHASE) {
51676 + if (diepint0.b.xfercompl) {
51677 + DWC_WRITE_REG32(&core_if->dev_if->
51678 + in_ep_regs[0]->diepint, diepint0.d32);
51679 + }
51680 + if (diepctl0.b.epena) {
51681 + diepint_data_t diepint = {.d32 = 0};
51682 + diepctl0.b.snak = 1;
51683 + DWC_WRITE_REG32(&core_if->dev_if->
51684 + in_ep_regs[0]->diepctl, diepctl0.d32);
51685 + do {
51686 + dwc_udelay(10);
51687 + diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51688 + in_ep_regs[0]->diepint);
51689 + } while (!diepint.b.inepnakeff);
51690 + diepint.b.inepnakeff = 1;
51691 + DWC_WRITE_REG32(&core_if->dev_if->
51692 + in_ep_regs[0]->diepint, diepint.d32);
51693 + diepctl0.d32 = 0;
51694 + diepctl0.b.epdis = 1;
51695 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl,
51696 + diepctl0.d32);
51697 + do {
51698 + dwc_udelay(10);
51699 + diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51700 + in_ep_regs[0]->diepint);
51701 + } while (!diepint.b.epdisabled);
51702 + diepint.b.epdisabled = 1;
51703 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepint,
51704 + diepint.d32);
51705 + }
51706 + }
51707 + doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if->
51708 + out_ep_regs[ep->dwc_ep.num]->doepint);
51709 + if (doepint_temp.b.sr) {
51710 + CLEAR_OUT_EP_INTR(core_if, epnum, sr);
51711 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
51712 + DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n");
51713 + } else {
51714 + DWC_DEBUGPL(DBG_PCDV, "complete req!!\n");
51715 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
51716 + if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len &&
51717 + pcd->ep0state == EP0_OUT_DATA_PHASE) {
51718 + /* Read arrived setup packet from req->buf */
51719 + dwc_memcpy(&pcd->setup_pkt->req,
51720 + req->buf + ep->dwc_ep.xfer_count, 8);
51721 + }
51722 + req->actual = ep->dwc_ep.xfer_count;
51723 + dwc_otg_request_done(ep, req, -ECONNRESET);
51724 + ep->dwc_ep.start_xfer_buff = 0;
51725 + ep->dwc_ep.xfer_buff = 0;
51726 + ep->dwc_ep.xfer_len = 0;
51727 + }
51728 + pcd->ep0state = EP0_IDLE;
51729 + if (doepint.b.setup) {
51730 + DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n");
51731 + /* Data stage started, clear setup */
51732 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51733 + doepint.b.setup = 0;
51734 + handle_ep0(pcd);
51735 + /* Prepare for setup packets if ep0in was enabled*/
51736 + if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
51737 + ep0_out_start(core_if, pcd);
51738 + }
51739 + goto exit_xfercompl;
51740 + } else {
51741 + /* Prepare for more setup packets */
51742 + DWC_DEBUGPL(DBG_PCDV,
51743 + "EP0_IDLE SR=1 setup=0 new setup comes 2\n");
51744 + ep0_out_start(core_if, pcd);
51745 + }
51746 + }
51747 + }
51748 + }
51749 + if (core_if->dma_enable == 0 || pcd->ep0state != EP0_IDLE)
51750 + handle_ep0(pcd);
51751 +exit_xfercompl:
51752 + DWC_DEBUGPL(DBG_PCDV, "DOEPINT=%x doepint=%x\n",
51753 + dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep), doepint.d32);
51754 + } else {
51755 + if (core_if->dma_desc_enable == 0
51756 + || pcd->ep0state != EP0_IDLE)
51757 + handle_ep0(pcd);
51758 + }
51759 +#ifdef DWC_EN_ISOC
51760 + } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51761 + if (doepint.b.pktdrpsts == 0) {
51762 + /* Clear the bit in DOEPINTn for this interrupt */
51763 + CLEAR_OUT_EP_INTR(core_if,
51764 + epnum,
51765 + xfercompl);
51766 + complete_iso_ep(pcd, ep);
51767 + } else {
51768 +
51769 + doepint_data_t doepint = {.d32 = 0 };
51770 + doepint.b.xfercompl = 1;
51771 + doepint.b.pktdrpsts = 1;
51772 + DWC_WRITE_REG32
51773 + (&core_if->dev_if->out_ep_regs
51774 + [epnum]->doepint,
51775 + doepint.d32);
51776 + if (handle_iso_out_pkt_dropped
51777 + (core_if, dwc_ep)) {
51778 + complete_iso_ep(pcd,
51779 + ep);
51780 + }
51781 + }
51782 +#endif /* DWC_EN_ISOC */
51783 +#ifdef DWC_UTE_PER_IO
51784 + } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51785 + CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
51786 + if (!ep->stopped)
51787 + complete_xiso_ep(ep);
51788 +#endif /* DWC_UTE_PER_IO */
51789 + } else {
51790 + /* Clear the bit in DOEPINTn for this interrupt */
51791 + CLEAR_OUT_EP_INTR(core_if, epnum,
51792 + xfercompl);
51793 +
51794 + if (core_if->core_params->dev_out_nak) {
51795 + DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[epnum]);
51796 + pcd->core_if->ep_xfer_info[epnum].state = 0;
51797 +#ifdef DEBUG
51798 + print_memory_payload(pcd, dwc_ep);
51799 +#endif
51800 + }
51801 + complete_ep(ep);
51802 + }
51803 +
51804 + }
51805 +
51806 + /* Endpoint disable */
51807 + if (doepint.b.epdisabled) {
51808 +
51809 + /* Clear the bit in DOEPINTn for this interrupt */
51810 + CLEAR_OUT_EP_INTR(core_if, epnum, epdisabled);
51811 + if (core_if->core_params->dev_out_nak) {
51812 +#ifdef DEBUG
51813 + print_memory_payload(pcd, dwc_ep);
51814 +#endif
51815 + /* In case of timeout condition */
51816 + if (core_if->ep_xfer_info[epnum].state == 2) {
51817 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
51818 + dev_global_regs->dctl);
51819 + dctl.b.cgoutnak = 1;
51820 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
51821 + dctl.d32);
51822 + /* Unmask goutnakeff interrupt which was masked
51823 + * during handle nak out interrupt */
51824 + gintmsk.b.goutnakeff = 1;
51825 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
51826 + 0, gintmsk.d32);
51827 +
51828 + complete_ep(ep);
51829 + }
51830 + }
51831 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
51832 + {
51833 + dctl_data_t dctl;
51834 + gintmsk_data_t intr_mask = {.d32 = 0};
51835 + dwc_otg_pcd_request_t *req = 0;
51836 +
51837 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
51838 + dev_global_regs->dctl);
51839 + dctl.b.cgoutnak = 1;
51840 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
51841 + dctl.d32);
51842 +
51843 + intr_mask.d32 = 0;
51844 + intr_mask.b.incomplisoout = 1;
51845 +
51846 + /* Get any pending requests */
51847 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
51848 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
51849 + if (!req) {
51850 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
51851 + } else {
51852 + dwc_otg_request_done(ep, req, 0);
51853 + start_next_request(ep);
51854 + }
51855 + } else {
51856 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
51857 + }
51858 + }
51859 + }
51860 + /* AHB Error */
51861 + if (doepint.b.ahberr) {
51862 + DWC_ERROR("EP%d OUT AHB Error\n", epnum);
51863 + DWC_ERROR("EP%d DEPDMA=0x%08x \n",
51864 + epnum, core_if->dev_if->out_ep_regs[epnum]->doepdma);
51865 + CLEAR_OUT_EP_INTR(core_if, epnum, ahberr);
51866 + }
51867 + /* Setup Phase Done (contorl EPs) */
51868 + if (doepint.b.setup) {
51869 +#ifdef DEBUG_EP0
51870 + DWC_DEBUGPL(DBG_PCD, "EP%d SETUP Done\n", epnum);
51871 +#endif
51872 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51873 +
51874 + handle_ep0(pcd);
51875 + }
51876 +
51877 + /** OUT EP BNA Intr */
51878 + if (doepint.b.bna) {
51879 + CLEAR_OUT_EP_INTR(core_if, epnum, bna);
51880 + if (core_if->dma_desc_enable) {
51881 +#ifdef DWC_EN_ISOC
51882 + if (dwc_ep->type ==
51883 + DWC_OTG_EP_TYPE_ISOC) {
51884 + /*
51885 + * This checking is performed to prevent first "false" BNA
51886 + * handling occuring right after reconnect
51887 + */
51888 + if (dwc_ep->next_frame !=
51889 + 0xffffffff)
51890 + dwc_otg_pcd_handle_iso_bna(ep);
51891 + } else
51892 +#endif /* DWC_EN_ISOC */
51893 + {
51894 + dwc_otg_pcd_handle_noniso_bna(ep);
51895 + }
51896 + }
51897 + }
51898 + /* Babble Interrupt */
51899 + if (doepint.b.babble) {
51900 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT Babble\n",
51901 + epnum);
51902 + handle_out_ep_babble_intr(pcd, epnum);
51903 +
51904 + CLEAR_OUT_EP_INTR(core_if, epnum, babble);
51905 + }
51906 + if (doepint.b.outtknepdis) {
51907 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT Token received when EP is \
51908 + disabled\n",epnum);
51909 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
51910 + doepmsk_data_t doepmsk = {.d32 = 0};
51911 + ep->dwc_ep.frame_num = core_if->frame_num;
51912 + if (ep->dwc_ep.bInterval > 1) {
51913 + depctl_data_t depctl;
51914 + depctl.d32 = DWC_READ_REG32(&core_if->dev_if->
51915 + out_ep_regs[epnum]->doepctl);
51916 + if (ep->dwc_ep.frame_num & 0x1) {
51917 + depctl.b.setd1pid = 1;
51918 + depctl.b.setd0pid = 0;
51919 + } else {
51920 + depctl.b.setd0pid = 1;
51921 + depctl.b.setd1pid = 0;
51922 + }
51923 + DWC_WRITE_REG32(&core_if->dev_if->
51924 + out_ep_regs[epnum]->doepctl, depctl.d32);
51925 + }
51926 + start_next_request(ep);
51927 + doepmsk.b.outtknepdis = 1;
51928 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
51929 + doepmsk.d32, 0);
51930 + }
51931 + CLEAR_OUT_EP_INTR(core_if, epnum, outtknepdis);
51932 + }
51933 +
51934 + /* NAK Interrutp */
51935 + if (doepint.b.nak) {
51936 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT NAK\n", epnum);
51937 + handle_out_ep_nak_intr(pcd, epnum);
51938 +
51939 + CLEAR_OUT_EP_INTR(core_if, epnum, nak);
51940 + }
51941 + /* NYET Interrutp */
51942 + if (doepint.b.nyet) {
51943 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT NYET\n", epnum);
51944 + handle_out_ep_nyet_intr(pcd, epnum);
51945 +
51946 + CLEAR_OUT_EP_INTR(core_if, epnum, nyet);
51947 + }
51948 + }
51949 +
51950 + epnum++;
51951 + ep_intr >>= 1;
51952 + }
51953 +
51954 + return 1;
51955 +
51956 +#undef CLEAR_OUT_EP_INTR
51957 +}
51958 +static int drop_transfer(uint32_t trgt_fr, uint32_t curr_fr, uint8_t frm_overrun)
51959 +{
51960 + int retval = 0;
51961 + if(!frm_overrun && curr_fr >= trgt_fr)
51962 + retval = 1;
51963 + else if (frm_overrun
51964 + && (curr_fr >= trgt_fr && ((curr_fr - trgt_fr) < 0x3FFF / 2)))
51965 + retval = 1;
51966 + return retval;
51967 +}
51968 +/**
51969 + * Incomplete ISO IN Transfer Interrupt.
51970 + * This interrupt indicates one of the following conditions occurred
51971 + * while transmitting an ISOC transaction.
51972 + * - Corrupted IN Token for ISOC EP.
51973 + * - Packet not complete in FIFO.
51974 + * The follow actions will be taken:
51975 + * -# Determine the EP
51976 + * -# Set incomplete flag in dwc_ep structure
51977 + * -# Disable EP; when "Endpoint Disabled" interrupt is received
51978 + * Flush FIFO
51979 + */
51980 +int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr(dwc_otg_pcd_t * pcd)
51981 +{
51982 + gintsts_data_t gintsts;
51983 +
51984 +#ifdef DWC_EN_ISOC
51985 + dwc_otg_dev_if_t *dev_if;
51986 + deptsiz_data_t deptsiz = {.d32 = 0 };
51987 + depctl_data_t depctl = {.d32 = 0 };
51988 + dsts_data_t dsts = {.d32 = 0 };
51989 + dwc_ep_t *dwc_ep;
51990 + int i;
51991 +
51992 + dev_if = GET_CORE_IF(pcd)->dev_if;
51993 +
51994 + for (i = 1; i <= dev_if->num_in_eps; ++i) {
51995 + dwc_ep = &pcd->in_ep[i].dwc_ep;
51996 + if (dwc_ep->active && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51997 + deptsiz.d32 =
51998 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
51999 + depctl.d32 =
52000 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
52001 +
52002 + if (depctl.b.epdis && deptsiz.d32) {
52003 + set_current_pkt_info(GET_CORE_IF(pcd), dwc_ep);
52004 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
52005 + dwc_ep->cur_pkt = 0;
52006 + dwc_ep->proc_buf_num =
52007 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
52008 +
52009 + if (dwc_ep->proc_buf_num) {
52010 + dwc_ep->cur_pkt_addr =
52011 + dwc_ep->xfer_buff1;
52012 + dwc_ep->cur_pkt_dma_addr =
52013 + dwc_ep->dma_addr1;
52014 + } else {
52015 + dwc_ep->cur_pkt_addr =
52016 + dwc_ep->xfer_buff0;
52017 + dwc_ep->cur_pkt_dma_addr =
52018 + dwc_ep->dma_addr0;
52019 + }
52020 +
52021 + }
52022 +
52023 + dsts.d32 =
52024 + DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
52025 + dev_global_regs->dsts);
52026 + dwc_ep->next_frame = dsts.b.soffn;
52027 +
52028 + dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
52029 + (pcd),
52030 + dwc_ep);
52031 + }
52032 + }
52033 + }
52034 +
52035 +#else
52036 + depctl_data_t depctl = {.d32 = 0 };
52037 + dwc_ep_t *dwc_ep;
52038 + dwc_otg_dev_if_t *dev_if;
52039 + int i;
52040 + dev_if = GET_CORE_IF(pcd)->dev_if;
52041 +
52042 + DWC_DEBUGPL(DBG_PCD,"Incomplete ISO IN \n");
52043 +
52044 + for (i = 1; i <= dev_if->num_in_eps; ++i) {
52045 + dwc_ep = &pcd->in_ep[i-1].dwc_ep;
52046 + depctl.d32 =
52047 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
52048 + if (depctl.b.epena && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
52049 + if (drop_transfer(dwc_ep->frame_num, GET_CORE_IF(pcd)->frame_num,
52050 + dwc_ep->frm_overrun))
52051 + {
52052 + depctl.d32 =
52053 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
52054 + depctl.b.snak = 1;
52055 + depctl.b.epdis = 1;
52056 + DWC_MODIFY_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32, depctl.d32);
52057 + }
52058 + }
52059 + }
52060 +
52061 + /*intr_mask.b.incomplisoin = 1;
52062 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
52063 + intr_mask.d32, 0); */
52064 +#endif //DWC_EN_ISOC
52065 +
52066 + /* Clear interrupt */
52067 + gintsts.d32 = 0;
52068 + gintsts.b.incomplisoin = 1;
52069 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52070 + gintsts.d32);
52071 +
52072 + return 1;
52073 +}
52074 +
52075 +/**
52076 + * Incomplete ISO OUT Transfer Interrupt.
52077 + *
52078 + * This interrupt indicates that the core has dropped an ISO OUT
52079 + * packet. The following conditions can be the cause:
52080 + * - FIFO Full, the entire packet would not fit in the FIFO.
52081 + * - CRC Error
52082 + * - Corrupted Token
52083 + * The follow actions will be taken:
52084 + * -# Determine the EP
52085 + * -# Set incomplete flag in dwc_ep structure
52086 + * -# Read any data from the FIFO
52087 + * -# Disable EP. When "Endpoint Disabled" interrupt is received
52088 + * re-enable EP.
52089 + */
52090 +int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr(dwc_otg_pcd_t * pcd)
52091 +{
52092 +
52093 + gintsts_data_t gintsts;
52094 +
52095 +#ifdef DWC_EN_ISOC
52096 + dwc_otg_dev_if_t *dev_if;
52097 + deptsiz_data_t deptsiz = {.d32 = 0 };
52098 + depctl_data_t depctl = {.d32 = 0 };
52099 + dsts_data_t dsts = {.d32 = 0 };
52100 + dwc_ep_t *dwc_ep;
52101 + int i;
52102 +
52103 + dev_if = GET_CORE_IF(pcd)->dev_if;
52104 +
52105 + for (i = 1; i <= dev_if->num_out_eps; ++i) {
52106 + dwc_ep = &pcd->in_ep[i].dwc_ep;
52107 + if (pcd->out_ep[i].dwc_ep.active &&
52108 + pcd->out_ep[i].dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
52109 + deptsiz.d32 =
52110 + DWC_READ_REG32(&dev_if->out_ep_regs[i]->doeptsiz);
52111 + depctl.d32 =
52112 + DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
52113 +
52114 + if (depctl.b.epdis && deptsiz.d32) {
52115 + set_current_pkt_info(GET_CORE_IF(pcd),
52116 + &pcd->out_ep[i].dwc_ep);
52117 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
52118 + dwc_ep->cur_pkt = 0;
52119 + dwc_ep->proc_buf_num =
52120 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
52121 +
52122 + if (dwc_ep->proc_buf_num) {
52123 + dwc_ep->cur_pkt_addr =
52124 + dwc_ep->xfer_buff1;
52125 + dwc_ep->cur_pkt_dma_addr =
52126 + dwc_ep->dma_addr1;
52127 + } else {
52128 + dwc_ep->cur_pkt_addr =
52129 + dwc_ep->xfer_buff0;
52130 + dwc_ep->cur_pkt_dma_addr =
52131 + dwc_ep->dma_addr0;
52132 + }
52133 +
52134 + }
52135 +
52136 + dsts.d32 =
52137 + DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
52138 + dev_global_regs->dsts);
52139 + dwc_ep->next_frame = dsts.b.soffn;
52140 +
52141 + dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
52142 + (pcd),
52143 + dwc_ep);
52144 + }
52145 + }
52146 + }
52147 +#else
52148 + /** @todo implement ISR */
52149 + gintmsk_data_t intr_mask = {.d32 = 0 };
52150 + dwc_otg_core_if_t *core_if;
52151 + deptsiz_data_t deptsiz = {.d32 = 0 };
52152 + depctl_data_t depctl = {.d32 = 0 };
52153 + dctl_data_t dctl = {.d32 = 0 };
52154 + dwc_ep_t *dwc_ep = NULL;
52155 + int i;
52156 + core_if = GET_CORE_IF(pcd);
52157 +
52158 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
52159 + dwc_ep = &pcd->out_ep[i].dwc_ep;
52160 + depctl.d32 =
52161 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
52162 + if (depctl.b.epena && depctl.b.dpid == (core_if->frame_num & 0x1)) {
52163 + core_if->dev_if->isoc_ep = dwc_ep;
52164 + deptsiz.d32 =
52165 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz);
52166 + break;
52167 + }
52168 + }
52169 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
52170 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
52171 + intr_mask.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
52172 +
52173 + if (!intr_mask.b.goutnakeff) {
52174 + /* Unmask it */
52175 + intr_mask.b.goutnakeff = 1;
52176 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32);
52177 + }
52178 + if (!gintsts.b.goutnakeff) {
52179 + dctl.b.sgoutnak = 1;
52180 + }
52181 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
52182 +
52183 + depctl.d32 = DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
52184 + if (depctl.b.epena) {
52185 + depctl.b.epdis = 1;
52186 + depctl.b.snak = 1;
52187 + }
52188 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl, depctl.d32);
52189 +
52190 + intr_mask.d32 = 0;
52191 + intr_mask.b.incomplisoout = 1;
52192 +
52193 +#endif /* DWC_EN_ISOC */
52194 +
52195 + /* Clear interrupt */
52196 + gintsts.d32 = 0;
52197 + gintsts.b.incomplisoout = 1;
52198 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52199 + gintsts.d32);
52200 +
52201 + return 1;
52202 +}
52203 +
52204 +/**
52205 + * This function handles the Global IN NAK Effective interrupt.
52206 + *
52207 + */
52208 +int32_t dwc_otg_pcd_handle_in_nak_effective(dwc_otg_pcd_t * pcd)
52209 +{
52210 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
52211 + depctl_data_t diepctl = {.d32 = 0 };
52212 + gintmsk_data_t intr_mask = {.d32 = 0 };
52213 + gintsts_data_t gintsts;
52214 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
52215 + int i;
52216 +
52217 + DWC_DEBUGPL(DBG_PCD, "Global IN NAK Effective\n");
52218 +
52219 + /* Disable all active IN EPs */
52220 + for (i = 0; i <= dev_if->num_in_eps; i++) {
52221 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
52222 + if (!(diepctl.b.eptype & 1) && diepctl.b.epena) {
52223 + if (core_if->start_predict > 0)
52224 + core_if->start_predict++;
52225 + diepctl.b.epdis = 1;
52226 + diepctl.b.snak = 1;
52227 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, diepctl.d32);
52228 + }
52229 + }
52230 +
52231 +
52232 + /* Disable the Global IN NAK Effective Interrupt */
52233 + intr_mask.b.ginnakeff = 1;
52234 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
52235 + intr_mask.d32, 0);
52236 +
52237 + /* Clear interrupt */
52238 + gintsts.d32 = 0;
52239 + gintsts.b.ginnakeff = 1;
52240 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52241 + gintsts.d32);
52242 +
52243 + return 1;
52244 +}
52245 +
52246 +/**
52247 + * OUT NAK Effective.
52248 + *
52249 + */
52250 +int32_t dwc_otg_pcd_handle_out_nak_effective(dwc_otg_pcd_t * pcd)
52251 +{
52252 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
52253 + gintmsk_data_t intr_mask = {.d32 = 0 };
52254 + gintsts_data_t gintsts;
52255 + depctl_data_t doepctl;
52256 + int i;
52257 +
52258 + /* Disable the Global OUT NAK Effective Interrupt */
52259 + intr_mask.b.goutnakeff = 1;
52260 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
52261 + intr_mask.d32, 0);
52262 +
52263 + /* If DEV OUT NAK enabled*/
52264 + if (pcd->core_if->core_params->dev_out_nak) {
52265 + /* Run over all out endpoints to determine the ep number on
52266 + * which the timeout has happened
52267 + */
52268 + for (i = 0; i <= dev_if->num_out_eps; i++) {
52269 + if ( pcd->core_if->ep_xfer_info[i].state == 2 )
52270 + break;
52271 + }
52272 + if (i > dev_if->num_out_eps) {
52273 + dctl_data_t dctl;
52274 + dctl.d32 =
52275 + DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
52276 + dctl.b.cgoutnak = 1;
52277 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl,
52278 + dctl.d32);
52279 + goto out;
52280 + }
52281 +
52282 + /* Disable the endpoint */
52283 + doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
52284 + if (doepctl.b.epena) {
52285 + doepctl.b.epdis = 1;
52286 + doepctl.b.snak = 1;
52287 + }
52288 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
52289 + return 1;
52290 + }
52291 + /* We come here from Incomplete ISO OUT handler */
52292 + if (dev_if->isoc_ep) {
52293 + dwc_ep_t *dwc_ep = (dwc_ep_t *)dev_if->isoc_ep;
52294 + uint32_t epnum = dwc_ep->num;
52295 + doepint_data_t doepint;
52296 + doepint.d32 =
52297 + DWC_READ_REG32(&dev_if->out_ep_regs[dwc_ep->num]->doepint);
52298 + dev_if->isoc_ep = NULL;
52299 + doepctl.d32 =
52300 + DWC_READ_REG32(&dev_if->out_ep_regs[epnum]->doepctl);
52301 + DWC_PRINTF("Before disable DOEPCTL = %08x\n", doepctl.d32);
52302 + if (doepctl.b.epena) {
52303 + doepctl.b.epdis = 1;
52304 + doepctl.b.snak = 1;
52305 + }
52306 + DWC_WRITE_REG32(&dev_if->out_ep_regs[epnum]->doepctl,
52307 + doepctl.d32);
52308 + return 1;
52309 + } else
52310 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
52311 + "Global OUT NAK Effective\n");
52312 +
52313 +out:
52314 + /* Clear interrupt */
52315 + gintsts.d32 = 0;
52316 + gintsts.b.goutnakeff = 1;
52317 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52318 + gintsts.d32);
52319 +
52320 + return 1;
52321 +}
52322 +
52323 +/**
52324 + * PCD interrupt handler.
52325 + *
52326 + * The PCD handles the device interrupts. Many conditions can cause a
52327 + * device interrupt. When an interrupt occurs, the device interrupt
52328 + * service routine determines the cause of the interrupt and
52329 + * dispatches handling to the appropriate function. These interrupt
52330 + * handling functions are described below.
52331 + *
52332 + * All interrupt registers are processed from LSB to MSB.
52333 + *
52334 + */
52335 +int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd)
52336 +{
52337 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
52338 +#ifdef VERBOSE
52339 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
52340 +#endif
52341 + gintsts_data_t gintr_status;
52342 + int32_t retval = 0;
52343 +
52344 + /* Exit from ISR if core is hibernated */
52345 + if (core_if->hibernation_suspend == 1) {
52346 + return retval;
52347 + }
52348 +#ifdef VERBOSE
52349 + DWC_DEBUGPL(DBG_ANY, "%s() gintsts=%08x gintmsk=%08x\n",
52350 + __func__,
52351 + DWC_READ_REG32(&global_regs->gintsts),
52352 + DWC_READ_REG32(&global_regs->gintmsk));
52353 +#endif
52354 +
52355 + if (dwc_otg_is_device_mode(core_if)) {
52356 + DWC_SPINLOCK(pcd->lock);
52357 +#ifdef VERBOSE
52358 + DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%08x gintmsk=%08x\n",
52359 + __func__,
52360 + DWC_READ_REG32(&global_regs->gintsts),
52361 + DWC_READ_REG32(&global_regs->gintmsk));
52362 +#endif
52363 +
52364 + gintr_status.d32 = dwc_otg_read_core_intr(core_if);
52365 +
52366 + DWC_DEBUGPL(DBG_PCDV, "%s: gintsts&gintmsk=%08x\n",
52367 + __func__, gintr_status.d32);
52368 +
52369 + if (gintr_status.b.sofintr) {
52370 + retval |= dwc_otg_pcd_handle_sof_intr(pcd);
52371 + }
52372 + if (gintr_status.b.rxstsqlvl) {
52373 + retval |=
52374 + dwc_otg_pcd_handle_rx_status_q_level_intr(pcd);
52375 + }
52376 + if (gintr_status.b.nptxfempty) {
52377 + retval |= dwc_otg_pcd_handle_np_tx_fifo_empty_intr(pcd);
52378 + }
52379 + if (gintr_status.b.goutnakeff) {
52380 + retval |= dwc_otg_pcd_handle_out_nak_effective(pcd);
52381 + }
52382 + if (gintr_status.b.i2cintr) {
52383 + retval |= dwc_otg_pcd_handle_i2c_intr(pcd);
52384 + }
52385 + if (gintr_status.b.erlysuspend) {
52386 + retval |= dwc_otg_pcd_handle_early_suspend_intr(pcd);
52387 + }
52388 + if (gintr_status.b.usbreset) {
52389 + retval |= dwc_otg_pcd_handle_usb_reset_intr(pcd);
52390 + }
52391 + if (gintr_status.b.enumdone) {
52392 + retval |= dwc_otg_pcd_handle_enum_done_intr(pcd);
52393 + }
52394 + if (gintr_status.b.isooutdrop) {
52395 + retval |=
52396 + dwc_otg_pcd_handle_isoc_out_packet_dropped_intr
52397 + (pcd);
52398 + }
52399 + if (gintr_status.b.eopframe) {
52400 + retval |=
52401 + dwc_otg_pcd_handle_end_periodic_frame_intr(pcd);
52402 + }
52403 + if (gintr_status.b.inepint) {
52404 + if (!core_if->multiproc_int_enable) {
52405 + retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
52406 + }
52407 + }
52408 + if (gintr_status.b.outepintr) {
52409 + if (!core_if->multiproc_int_enable) {
52410 + retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
52411 + }
52412 + }
52413 + if (gintr_status.b.epmismatch) {
52414 + retval |= dwc_otg_pcd_handle_ep_mismatch_intr(pcd);
52415 + }
52416 + if (gintr_status.b.fetsusp) {
52417 + retval |= dwc_otg_pcd_handle_ep_fetsusp_intr(pcd);
52418 + }
52419 + if (gintr_status.b.ginnakeff) {
52420 + retval |= dwc_otg_pcd_handle_in_nak_effective(pcd);
52421 + }
52422 + if (gintr_status.b.incomplisoin) {
52423 + retval |=
52424 + dwc_otg_pcd_handle_incomplete_isoc_in_intr(pcd);
52425 + }
52426 + if (gintr_status.b.incomplisoout) {
52427 + retval |=
52428 + dwc_otg_pcd_handle_incomplete_isoc_out_intr(pcd);
52429 + }
52430 +
52431 + /* In MPI mode Device Endpoints interrupts are asserted
52432 + * without setting outepintr and inepint bits set, so these
52433 + * Interrupt handlers are called without checking these bit-fields
52434 + */
52435 + if (core_if->multiproc_int_enable) {
52436 + retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
52437 + retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
52438 + }
52439 +#ifdef VERBOSE
52440 + DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%0x\n", __func__,
52441 + DWC_READ_REG32(&global_regs->gintsts));
52442 +#endif
52443 + DWC_SPINUNLOCK(pcd->lock);
52444 + }
52445 + return retval;
52446 +}
52447 +
52448 +#endif /* DWC_HOST_ONLY */
52449 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
52450 new file mode 100644
52451 index 0000000..5d310df
52452 --- /dev/null
52453 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
52454 @@ -0,0 +1,1358 @@
52455 + /* ==========================================================================
52456 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_linux.c $
52457 + * $Revision: #21 $
52458 + * $Date: 2012/08/10 $
52459 + * $Change: 2047372 $
52460 + *
52461 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
52462 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
52463 + * otherwise expressly agreed to in writing between Synopsys and you.
52464 + *
52465 + * The Software IS NOT an item of Licensed Software or Licensed Product under
52466 + * any End User Software License Agreement or Agreement for Licensed Product
52467 + * with Synopsys or any supplement thereto. You are permitted to use and
52468 + * redistribute this Software in source and binary forms, with or without
52469 + * modification, provided that redistributions of source code must retain this
52470 + * notice. You may not view, use, disclose, copy or distribute this file or
52471 + * any information contained herein except pursuant to this license grant from
52472 + * Synopsys. If you do not agree with this notice, including the disclaimer
52473 + * below, then you are not authorized to use the Software.
52474 + *
52475 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
52476 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52477 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52478 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
52479 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
52480 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
52481 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
52482 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52483 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52484 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
52485 + * DAMAGE.
52486 + * ========================================================================== */
52487 +#ifndef DWC_HOST_ONLY
52488 +
52489 +/** @file
52490 + * This file implements the Peripheral Controller Driver.
52491 + *
52492 + * The Peripheral Controller Driver (PCD) is responsible for
52493 + * translating requests from the Function Driver into the appropriate
52494 + * actions on the DWC_otg controller. It isolates the Function Driver
52495 + * from the specifics of the controller by providing an API to the
52496 + * Function Driver.
52497 + *
52498 + * The Peripheral Controller Driver for Linux will implement the
52499 + * Gadget API, so that the existing Gadget drivers can be used.
52500 + * (Gadget Driver is the Linux terminology for a Function Driver.)
52501 + *
52502 + * The Linux Gadget API is defined in the header file
52503 + * <code><linux/usb_gadget.h></code>. The USB EP operations API is
52504 + * defined in the structure <code>usb_ep_ops</code> and the USB
52505 + * Controller API is defined in the structure
52506 + * <code>usb_gadget_ops</code>.
52507 + *
52508 + */
52509 +
52510 +#include "dwc_otg_os_dep.h"
52511 +#include "dwc_otg_pcd_if.h"
52512 +#include "dwc_otg_pcd.h"
52513 +#include "dwc_otg_driver.h"
52514 +#include "dwc_otg_dbg.h"
52515 +
52516 +static struct gadget_wrapper {
52517 + dwc_otg_pcd_t *pcd;
52518 +
52519 + struct usb_gadget gadget;
52520 + struct usb_gadget_driver *driver;
52521 +
52522 + struct usb_ep ep0;
52523 + struct usb_ep in_ep[16];
52524 + struct usb_ep out_ep[16];
52525 +
52526 +} *gadget_wrapper;
52527 +
52528 +/* Display the contents of the buffer */
52529 +extern void dump_msg(const u8 * buf, unsigned int length);
52530 +/**
52531 + * Get the dwc_otg_pcd_ep_t* from usb_ep* pointer - NULL in case
52532 + * if the endpoint is not found
52533 + */
52534 +static struct dwc_otg_pcd_ep *ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
52535 +{
52536 + int i;
52537 + if (pcd->ep0.priv == handle) {
52538 + return &pcd->ep0;
52539 + }
52540 +
52541 + for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
52542 + if (pcd->in_ep[i].priv == handle)
52543 + return &pcd->in_ep[i];
52544 + if (pcd->out_ep[i].priv == handle)
52545 + return &pcd->out_ep[i];
52546 + }
52547 +
52548 + return NULL;
52549 +}
52550 +
52551 +/* USB Endpoint Operations */
52552 +/*
52553 + * The following sections briefly describe the behavior of the Gadget
52554 + * API endpoint operations implemented in the DWC_otg driver
52555 + * software. Detailed descriptions of the generic behavior of each of
52556 + * these functions can be found in the Linux header file
52557 + * include/linux/usb_gadget.h.
52558 + *
52559 + * The Gadget API provides wrapper functions for each of the function
52560 + * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper
52561 + * function, which then calls the underlying PCD function. The
52562 + * following sections are named according to the wrapper
52563 + * functions. Within each section, the corresponding DWC_otg PCD
52564 + * function name is specified.
52565 + *
52566 + */
52567 +
52568 +/**
52569 + * This function is called by the Gadget Driver for each EP to be
52570 + * configured for the current configuration (SET_CONFIGURATION).
52571 + *
52572 + * This function initializes the dwc_otg_ep_t data structure, and then
52573 + * calls dwc_otg_ep_activate.
52574 + */
52575 +static int ep_enable(struct usb_ep *usb_ep,
52576 + const struct usb_endpoint_descriptor *ep_desc)
52577 +{
52578 + int retval;
52579 +
52580 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, ep_desc);
52581 +
52582 + if (!usb_ep || !ep_desc || ep_desc->bDescriptorType != USB_DT_ENDPOINT) {
52583 + DWC_WARN("%s, bad ep or descriptor\n", __func__);
52584 + return -EINVAL;
52585 + }
52586 + if (usb_ep == &gadget_wrapper->ep0) {
52587 + DWC_WARN("%s, bad ep(0)\n", __func__);
52588 + return -EINVAL;
52589 + }
52590 +
52591 + /* Check FIFO size? */
52592 + if (!ep_desc->wMaxPacketSize) {
52593 + DWC_WARN("%s, bad %s maxpacket\n", __func__, usb_ep->name);
52594 + return -ERANGE;
52595 + }
52596 +
52597 + if (!gadget_wrapper->driver ||
52598 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52599 + DWC_WARN("%s, bogus device state\n", __func__);
52600 + return -ESHUTDOWN;
52601 + }
52602 +
52603 + /* Delete after check - MAS */
52604 +#if 0
52605 + nat = (uint32_t) ep_desc->wMaxPacketSize;
52606 + printk(KERN_ALERT "%s: nat (before) =%d\n", __func__, nat);
52607 + nat = (nat >> 11) & 0x03;
52608 + printk(KERN_ALERT "%s: nat (after) =%d\n", __func__, nat);
52609 +#endif
52610 + retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd,
52611 + (const uint8_t *)ep_desc,
52612 + (void *)usb_ep);
52613 + if (retval) {
52614 + DWC_WARN("dwc_otg_pcd_ep_enable failed\n");
52615 + return -EINVAL;
52616 + }
52617 +
52618 + usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize);
52619 +
52620 + return 0;
52621 +}
52622 +
52623 +/**
52624 + * This function is called when an EP is disabled due to disconnect or
52625 + * change in configuration. Any pending requests will terminate with a
52626 + * status of -ESHUTDOWN.
52627 + *
52628 + * This function modifies the dwc_otg_ep_t data structure for this EP,
52629 + * and then calls dwc_otg_ep_deactivate.
52630 + */
52631 +static int ep_disable(struct usb_ep *usb_ep)
52632 +{
52633 + int retval;
52634 +
52635 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, usb_ep);
52636 + if (!usb_ep) {
52637 + DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__,
52638 + usb_ep ? usb_ep->name : NULL);
52639 + return -EINVAL;
52640 + }
52641 +
52642 + retval = dwc_otg_pcd_ep_disable(gadget_wrapper->pcd, usb_ep);
52643 + if (retval) {
52644 + retval = -EINVAL;
52645 + }
52646 +
52647 + return retval;
52648 +}
52649 +
52650 +/**
52651 + * This function allocates a request object to use with the specified
52652 + * endpoint.
52653 + *
52654 + * @param ep The endpoint to be used with with the request
52655 + * @param gfp_flags the GFP_* flags to use.
52656 + */
52657 +static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep,
52658 + gfp_t gfp_flags)
52659 +{
52660 + struct usb_request *usb_req;
52661 +
52662 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags);
52663 + if (0 == ep) {
52664 + DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
52665 + return 0;
52666 + }
52667 + usb_req = kmalloc(sizeof(*usb_req), gfp_flags);
52668 + if (0 == usb_req) {
52669 + DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n");
52670 + return 0;
52671 + }
52672 + memset(usb_req, 0, sizeof(*usb_req));
52673 + usb_req->dma = DWC_DMA_ADDR_INVALID;
52674 +
52675 + return usb_req;
52676 +}
52677 +
52678 +/**
52679 + * This function frees a request object.
52680 + *
52681 + * @param ep The endpoint associated with the request
52682 + * @param req The request being freed
52683 + */
52684 +static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req)
52685 +{
52686 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req);
52687 +
52688 + if (0 == ep || 0 == req) {
52689 + DWC_WARN("%s() %s\n", __func__,
52690 + "Invalid ep or req argument!\n");
52691 + return;
52692 + }
52693 +
52694 + kfree(req);
52695 +}
52696 +
52697 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
52698 +/**
52699 + * This function allocates an I/O buffer to be used for a transfer
52700 + * to/from the specified endpoint.
52701 + *
52702 + * @param usb_ep The endpoint to be used with with the request
52703 + * @param bytes The desired number of bytes for the buffer
52704 + * @param dma Pointer to the buffer's DMA address; must be valid
52705 + * @param gfp_flags the GFP_* flags to use.
52706 + * @return address of a new buffer or null is buffer could not be allocated.
52707 + */
52708 +static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *usb_ep, unsigned bytes,
52709 + dma_addr_t * dma, gfp_t gfp_flags)
52710 +{
52711 + void *buf;
52712 + dwc_otg_pcd_t *pcd = 0;
52713 +
52714 + pcd = gadget_wrapper->pcd;
52715 +
52716 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d,%p,%0x)\n", __func__, usb_ep, bytes,
52717 + dma, gfp_flags);
52718 +
52719 + /* Check dword alignment */
52720 + if ((bytes & 0x3UL) != 0) {
52721 + DWC_WARN("%s() Buffer size is not a multiple of"
52722 + "DWORD size (%d)", __func__, bytes);
52723 + }
52724 +
52725 + buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags);
52726 +
52727 + /* Check dword alignment */
52728 + if (((int)buf & 0x3UL) != 0) {
52729 + DWC_WARN("%s() Buffer is not DWORD aligned (%p)",
52730 + __func__, buf);
52731 + }
52732 +
52733 + return buf;
52734 +}
52735 +
52736 +/**
52737 + * This function frees an I/O buffer that was allocated by alloc_buffer.
52738 + *
52739 + * @param usb_ep the endpoint associated with the buffer
52740 + * @param buf address of the buffer
52741 + * @param dma The buffer's DMA address
52742 + * @param bytes The number of bytes of the buffer
52743 + */
52744 +static void dwc_otg_pcd_free_buffer(struct usb_ep *usb_ep, void *buf,
52745 + dma_addr_t dma, unsigned bytes)
52746 +{
52747 + dwc_otg_pcd_t *pcd = 0;
52748 +
52749 + pcd = gadget_wrapper->pcd;
52750 +
52751 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%0x,%d)\n", __func__, buf, dma, bytes);
52752 +
52753 + dma_free_coherent(NULL, bytes, buf, dma);
52754 +}
52755 +#endif
52756 +
52757 +/**
52758 + * This function is used to submit an I/O Request to an EP.
52759 + *
52760 + * - When the request completes the request's completion callback
52761 + * is called to return the request to the driver.
52762 + * - An EP, except control EPs, may have multiple requests
52763 + * pending.
52764 + * - Once submitted the request cannot be examined or modified.
52765 + * - Each request is turned into one or more packets.
52766 + * - A BULK EP can queue any amount of data; the transfer is
52767 + * packetized.
52768 + * - Zero length Packets are specified with the request 'zero'
52769 + * flag.
52770 + */
52771 +static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
52772 + gfp_t gfp_flags)
52773 +{
52774 + dwc_otg_pcd_t *pcd;
52775 + struct dwc_otg_pcd_ep *ep = NULL;
52776 + int retval = 0, is_isoc_ep = 0;
52777 + dma_addr_t dma_addr = DWC_DMA_ADDR_INVALID;
52778 +
52779 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n",
52780 + __func__, usb_ep, usb_req, gfp_flags);
52781 +
52782 + if (!usb_req || !usb_req->complete || !usb_req->buf) {
52783 + DWC_WARN("bad params\n");
52784 + return -EINVAL;
52785 + }
52786 +
52787 + if (!usb_ep) {
52788 + DWC_WARN("bad ep\n");
52789 + return -EINVAL;
52790 + }
52791 +
52792 + pcd = gadget_wrapper->pcd;
52793 + if (!gadget_wrapper->driver ||
52794 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52795 + DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
52796 + gadget_wrapper->gadget.speed);
52797 + DWC_WARN("bogus device state\n");
52798 + return -ESHUTDOWN;
52799 + }
52800 +
52801 + DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
52802 + usb_ep->name, usb_req, usb_req->length, usb_req->buf);
52803 +
52804 + usb_req->status = -EINPROGRESS;
52805 + usb_req->actual = 0;
52806 +
52807 + ep = ep_from_handle(pcd, usb_ep);
52808 + if (ep == NULL)
52809 + is_isoc_ep = 0;
52810 + else
52811 + is_isoc_ep = (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) ? 1 : 0;
52812 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
52813 + dma_addr = usb_req->dma;
52814 +#else
52815 + if (GET_CORE_IF(pcd)->dma_enable) {
52816 + dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev;
52817 + struct device *dev = NULL;
52818 +
52819 + if (otg_dev != NULL)
52820 + dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep);
52821 +
52822 + if (usb_req->length != 0 &&
52823 + usb_req->dma == DWC_DMA_ADDR_INVALID) {
52824 + dma_addr = dma_map_single(dev, usb_req->buf,
52825 + usb_req->length,
52826 + ep->dwc_ep.is_in ?
52827 + DMA_TO_DEVICE:
52828 + DMA_FROM_DEVICE);
52829 + }
52830 + }
52831 +#endif
52832 +
52833 +#ifdef DWC_UTE_PER_IO
52834 + if (is_isoc_ep == 1) {
52835 + retval = dwc_otg_pcd_xiso_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
52836 + usb_req->length, usb_req->zero, usb_req,
52837 + gfp_flags == GFP_ATOMIC ? 1 : 0, &usb_req->ext_req);
52838 + if (retval)
52839 + return -EINVAL;
52840 +
52841 + return 0;
52842 + }
52843 +#endif
52844 + retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
52845 + usb_req->length, usb_req->zero, usb_req,
52846 + gfp_flags == GFP_ATOMIC ? 1 : 0);
52847 + if (retval) {
52848 + return -EINVAL;
52849 + }
52850 +
52851 + return 0;
52852 +}
52853 +
52854 +/**
52855 + * This function cancels an I/O request from an EP.
52856 + */
52857 +static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
52858 +{
52859 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req);
52860 +
52861 + if (!usb_ep || !usb_req) {
52862 + DWC_WARN("bad argument\n");
52863 + return -EINVAL;
52864 + }
52865 + if (!gadget_wrapper->driver ||
52866 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52867 + DWC_WARN("bogus device state\n");
52868 + return -ESHUTDOWN;
52869 + }
52870 + if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) {
52871 + return -EINVAL;
52872 + }
52873 +
52874 + return 0;
52875 +}
52876 +
52877 +/**
52878 + * usb_ep_set_halt stalls an endpoint.
52879 + *
52880 + * usb_ep_clear_halt clears an endpoint halt and resets its data
52881 + * toggle.
52882 + *
52883 + * Both of these functions are implemented with the same underlying
52884 + * function. The behavior depends on the value argument.
52885 + *
52886 + * @param[in] usb_ep the Endpoint to halt or clear halt.
52887 + * @param[in] value
52888 + * - 0 means clear_halt.
52889 + * - 1 means set_halt,
52890 + * - 2 means clear stall lock flag.
52891 + * - 3 means set stall lock flag.
52892 + */
52893 +static int ep_halt(struct usb_ep *usb_ep, int value)
52894 +{
52895 + int retval = 0;
52896 +
52897 + DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value);
52898 +
52899 + if (!usb_ep) {
52900 + DWC_WARN("bad ep\n");
52901 + return -EINVAL;
52902 + }
52903 +
52904 + retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value);
52905 + if (retval == -DWC_E_AGAIN) {
52906 + return -EAGAIN;
52907 + } else if (retval) {
52908 + retval = -EINVAL;
52909 + }
52910 +
52911 + return retval;
52912 +}
52913 +
52914 +//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
52915 +#if 0
52916 +/**
52917 + * ep_wedge: sets the halt feature and ignores clear requests
52918 + *
52919 + * @usb_ep: the endpoint being wedged
52920 + *
52921 + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
52922 + * requests. If the gadget driver clears the halt status, it will
52923 + * automatically unwedge the endpoint.
52924 + *
52925 + * Returns zero on success, else negative errno. *
52926 + * Check usb_ep_set_wedge() at "usb_gadget.h" for details
52927 + */
52928 +static int ep_wedge(struct usb_ep *usb_ep)
52929 +{
52930 + int retval = 0;
52931 +
52932 + DWC_DEBUGPL(DBG_PCD, "WEDGE %s\n", usb_ep->name);
52933 +
52934 + if (!usb_ep) {
52935 + DWC_WARN("bad ep\n");
52936 + return -EINVAL;
52937 + }
52938 +
52939 + retval = dwc_otg_pcd_ep_wedge(gadget_wrapper->pcd, usb_ep);
52940 + if (retval == -DWC_E_AGAIN) {
52941 + retval = -EAGAIN;
52942 + } else if (retval) {
52943 + retval = -EINVAL;
52944 + }
52945 +
52946 + return retval;
52947 +}
52948 +#endif
52949 +
52950 +#ifdef DWC_EN_ISOC
52951 +/**
52952 + * This function is used to submit an ISOC Transfer Request to an EP.
52953 + *
52954 + * - Every time a sync period completes the request's completion callback
52955 + * is called to provide data to the gadget driver.
52956 + * - Once submitted the request cannot be modified.
52957 + * - Each request is turned into periodic data packets untill ISO
52958 + * Transfer is stopped..
52959 + */
52960 +static int iso_ep_start(struct usb_ep *usb_ep, struct usb_iso_request *req,
52961 + gfp_t gfp_flags)
52962 +{
52963 + int retval = 0;
52964 +
52965 + if (!req || !req->process_buffer || !req->buf0 || !req->buf1) {
52966 + DWC_WARN("bad params\n");
52967 + return -EINVAL;
52968 + }
52969 +
52970 + if (!usb_ep) {
52971 + DWC_PRINTF("bad params\n");
52972 + return -EINVAL;
52973 + }
52974 +
52975 + req->status = -EINPROGRESS;
52976 +
52977 + retval =
52978 + dwc_otg_pcd_iso_ep_start(gadget_wrapper->pcd, usb_ep, req->buf0,
52979 + req->buf1, req->dma0, req->dma1,
52980 + req->sync_frame, req->data_pattern_frame,
52981 + req->data_per_frame,
52982 + req->
52983 + flags & USB_REQ_ISO_ASAP ? -1 :
52984 + req->start_frame, req->buf_proc_intrvl,
52985 + req, gfp_flags == GFP_ATOMIC ? 1 : 0);
52986 +
52987 + if (retval) {
52988 + return -EINVAL;
52989 + }
52990 +
52991 + return retval;
52992 +}
52993 +
52994 +/**
52995 + * This function stops ISO EP Periodic Data Transfer.
52996 + */
52997 +static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req)
52998 +{
52999 + int retval = 0;
53000 + if (!usb_ep) {
53001 + DWC_WARN("bad ep\n");
53002 + }
53003 +
53004 + if (!gadget_wrapper->driver ||
53005 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
53006 + DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
53007 + gadget_wrapper->gadget.speed);
53008 + DWC_WARN("bogus device state\n");
53009 + }
53010 +
53011 + dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req);
53012 + if (retval) {
53013 + retval = -EINVAL;
53014 + }
53015 +
53016 + return retval;
53017 +}
53018 +
53019 +static struct usb_iso_request *alloc_iso_request(struct usb_ep *ep,
53020 + int packets, gfp_t gfp_flags)
53021 +{
53022 + struct usb_iso_request *pReq = NULL;
53023 + uint32_t req_size;
53024 +
53025 + req_size = sizeof(struct usb_iso_request);
53026 + req_size +=
53027 + (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor)));
53028 +
53029 + pReq = kmalloc(req_size, gfp_flags);
53030 + if (!pReq) {
53031 + DWC_WARN("Can't allocate Iso Request\n");
53032 + return 0;
53033 + }
53034 + pReq->iso_packet_desc0 = (void *)(pReq + 1);
53035 +
53036 + pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets;
53037 +
53038 + return pReq;
53039 +}
53040 +
53041 +static void free_iso_request(struct usb_ep *ep, struct usb_iso_request *req)
53042 +{
53043 + kfree(req);
53044 +}
53045 +
53046 +static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = {
53047 + .ep_ops = {
53048 + .enable = ep_enable,
53049 + .disable = ep_disable,
53050 +
53051 + .alloc_request = dwc_otg_pcd_alloc_request,
53052 + .free_request = dwc_otg_pcd_free_request,
53053 +
53054 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
53055 + .alloc_buffer = dwc_otg_pcd_alloc_buffer,
53056 + .free_buffer = dwc_otg_pcd_free_buffer,
53057 +#endif
53058 +
53059 + .queue = ep_queue,
53060 + .dequeue = ep_dequeue,
53061 +
53062 + .set_halt = ep_halt,
53063 + .fifo_status = 0,
53064 + .fifo_flush = 0,
53065 + },
53066 + .iso_ep_start = iso_ep_start,
53067 + .iso_ep_stop = iso_ep_stop,
53068 + .alloc_iso_request = alloc_iso_request,
53069 + .free_iso_request = free_iso_request,
53070 +};
53071 +
53072 +#else
53073 +
53074 + int (*enable) (struct usb_ep *ep,
53075 + const struct usb_endpoint_descriptor *desc);
53076 + int (*disable) (struct usb_ep *ep);
53077 +
53078 + struct usb_request *(*alloc_request) (struct usb_ep *ep,
53079 + gfp_t gfp_flags);
53080 + void (*free_request) (struct usb_ep *ep, struct usb_request *req);
53081 +
53082 + int (*queue) (struct usb_ep *ep, struct usb_request *req,
53083 + gfp_t gfp_flags);
53084 + int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
53085 +
53086 + int (*set_halt) (struct usb_ep *ep, int value);
53087 + int (*set_wedge) (struct usb_ep *ep);
53088 +
53089 + int (*fifo_status) (struct usb_ep *ep);
53090 + void (*fifo_flush) (struct usb_ep *ep);
53091 +static struct usb_ep_ops dwc_otg_pcd_ep_ops = {
53092 + .enable = ep_enable,
53093 + .disable = ep_disable,
53094 +
53095 + .alloc_request = dwc_otg_pcd_alloc_request,
53096 + .free_request = dwc_otg_pcd_free_request,
53097 +
53098 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
53099 + .alloc_buffer = dwc_otg_pcd_alloc_buffer,
53100 + .free_buffer = dwc_otg_pcd_free_buffer,
53101 +#else
53102 + /* .set_wedge = ep_wedge, */
53103 + .set_wedge = NULL, /* uses set_halt instead */
53104 +#endif
53105 +
53106 + .queue = ep_queue,
53107 + .dequeue = ep_dequeue,
53108 +
53109 + .set_halt = ep_halt,
53110 + .fifo_status = 0,
53111 + .fifo_flush = 0,
53112 +
53113 +};
53114 +
53115 +#endif /* _EN_ISOC_ */
53116 +/* Gadget Operations */
53117 +/**
53118 + * The following gadget operations will be implemented in the DWC_otg
53119 + * PCD. Functions in the API that are not described below are not
53120 + * implemented.
53121 + *
53122 + * The Gadget API provides wrapper functions for each of the function
53123 + * pointers defined in usb_gadget_ops. The Gadget Driver calls the
53124 + * wrapper function, which then calls the underlying PCD function. The
53125 + * following sections are named according to the wrapper functions
53126 + * (except for ioctl, which doesn't have a wrapper function). Within
53127 + * each section, the corresponding DWC_otg PCD function name is
53128 + * specified.
53129 + *
53130 + */
53131 +
53132 +/**
53133 + *Gets the USB Frame number of the last SOF.
53134 + */
53135 +static int get_frame_number(struct usb_gadget *gadget)
53136 +{
53137 + struct gadget_wrapper *d;
53138 +
53139 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
53140 +
53141 + if (gadget == 0) {
53142 + return -ENODEV;
53143 + }
53144 +
53145 + d = container_of(gadget, struct gadget_wrapper, gadget);
53146 + return dwc_otg_pcd_get_frame_number(d->pcd);
53147 +}
53148 +
53149 +#ifdef CONFIG_USB_DWC_OTG_LPM
53150 +static int test_lpm_enabled(struct usb_gadget *gadget)
53151 +{
53152 + struct gadget_wrapper *d;
53153 +
53154 + d = container_of(gadget, struct gadget_wrapper, gadget);
53155 +
53156 + return dwc_otg_pcd_is_lpm_enabled(d->pcd);
53157 +}
53158 +#endif
53159 +
53160 +/**
53161 + * Initiates Session Request Protocol (SRP) to wakeup the host if no
53162 + * session is in progress. If a session is already in progress, but
53163 + * the device is suspended, remote wakeup signaling is started.
53164 + *
53165 + */
53166 +static int wakeup(struct usb_gadget *gadget)
53167 +{
53168 + struct gadget_wrapper *d;
53169 +
53170 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
53171 +
53172 + if (gadget == 0) {
53173 + return -ENODEV;
53174 + } else {
53175 + d = container_of(gadget, struct gadget_wrapper, gadget);
53176 + }
53177 + dwc_otg_pcd_wakeup(d->pcd);
53178 + return 0;
53179 +}
53180 +
53181 +static const struct usb_gadget_ops dwc_otg_pcd_ops = {
53182 + .get_frame = get_frame_number,
53183 + .wakeup = wakeup,
53184 +#ifdef CONFIG_USB_DWC_OTG_LPM
53185 + .lpm_support = test_lpm_enabled,
53186 +#endif
53187 + // current versions must always be self-powered
53188 +};
53189 +
53190 +static int _setup(dwc_otg_pcd_t * pcd, uint8_t * bytes)
53191 +{
53192 + int retval = -DWC_E_NOT_SUPPORTED;
53193 + if (gadget_wrapper->driver && gadget_wrapper->driver->setup) {
53194 + retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget,
53195 + (struct usb_ctrlrequest
53196 + *)bytes);
53197 + }
53198 +
53199 + if (retval == -ENOTSUPP) {
53200 + retval = -DWC_E_NOT_SUPPORTED;
53201 + } else if (retval < 0) {
53202 + retval = -DWC_E_INVALID;
53203 + }
53204 +
53205 + return retval;
53206 +}
53207 +
53208 +#ifdef DWC_EN_ISOC
53209 +static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
53210 + void *req_handle, int proc_buf_num)
53211 +{
53212 + int i, packet_count;
53213 + struct usb_gadget_iso_packet_descriptor *iso_packet = 0;
53214 + struct usb_iso_request *iso_req = req_handle;
53215 +
53216 + if (proc_buf_num) {
53217 + iso_packet = iso_req->iso_packet_desc1;
53218 + } else {
53219 + iso_packet = iso_req->iso_packet_desc0;
53220 + }
53221 + packet_count =
53222 + dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle);
53223 + for (i = 0; i < packet_count; ++i) {
53224 + int status;
53225 + int actual;
53226 + int offset;
53227 + dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle,
53228 + i, &status, &actual, &offset);
53229 + switch (status) {
53230 + case -DWC_E_NO_DATA:
53231 + status = -ENODATA;
53232 + break;
53233 + default:
53234 + if (status) {
53235 + DWC_PRINTF("unknown status in isoc packet\n");
53236 + }
53237 +
53238 + }
53239 + iso_packet[i].status = status;
53240 + iso_packet[i].offset = offset;
53241 + iso_packet[i].actual_length = actual;
53242 + }
53243 +
53244 + iso_req->status = 0;
53245 + iso_req->process_buffer(ep_handle, iso_req);
53246 +
53247 + return 0;
53248 +}
53249 +#endif /* DWC_EN_ISOC */
53250 +
53251 +#ifdef DWC_UTE_PER_IO
53252 +/**
53253 + * Copy the contents of the extended request to the Linux usb_request's
53254 + * extended part and call the gadget's completion.
53255 + *
53256 + * @param pcd Pointer to the pcd structure
53257 + * @param ep_handle Void pointer to the usb_ep structure
53258 + * @param req_handle Void pointer to the usb_request structure
53259 + * @param status Request status returned from the portable logic
53260 + * @param ereq_port Void pointer to the extended request structure
53261 + * created in the the portable part that contains the
53262 + * results of the processed iso packets.
53263 + */
53264 +static int _xisoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
53265 + void *req_handle, int32_t status, void *ereq_port)
53266 +{
53267 + struct dwc_ute_iso_req_ext *ereqorg = NULL;
53268 + struct dwc_iso_xreq_port *ereqport = NULL;
53269 + struct dwc_ute_iso_packet_descriptor *desc_org = NULL;
53270 + int i;
53271 + struct usb_request *req;
53272 + //struct dwc_ute_iso_packet_descriptor *
53273 + //int status = 0;
53274 +
53275 + req = (struct usb_request *)req_handle;
53276 + ereqorg = &req->ext_req;
53277 + ereqport = (struct dwc_iso_xreq_port *)ereq_port;
53278 + desc_org = ereqorg->per_io_frame_descs;
53279 +
53280 + if (req && req->complete) {
53281 + /* Copy the request data from the portable logic to our request */
53282 + for (i = 0; i < ereqport->pio_pkt_count; i++) {
53283 + desc_org[i].actual_length =
53284 + ereqport->per_io_frame_descs[i].actual_length;
53285 + desc_org[i].status =
53286 + ereqport->per_io_frame_descs[i].status;
53287 + }
53288 +
53289 + switch (status) {
53290 + case -DWC_E_SHUTDOWN:
53291 + req->status = -ESHUTDOWN;
53292 + break;
53293 + case -DWC_E_RESTART:
53294 + req->status = -ECONNRESET;
53295 + break;
53296 + case -DWC_E_INVALID:
53297 + req->status = -EINVAL;
53298 + break;
53299 + case -DWC_E_TIMEOUT:
53300 + req->status = -ETIMEDOUT;
53301 + break;
53302 + default:
53303 + req->status = status;
53304 + }
53305 +
53306 + /* And call the gadget's completion */
53307 + req->complete(ep_handle, req);
53308 + }
53309 +
53310 + return 0;
53311 +}
53312 +#endif /* DWC_UTE_PER_IO */
53313 +
53314 +static int _complete(dwc_otg_pcd_t * pcd, void *ep_handle,
53315 + void *req_handle, int32_t status, uint32_t actual)
53316 +{
53317 + struct usb_request *req = (struct usb_request *)req_handle;
53318 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
53319 + struct dwc_otg_pcd_ep *ep = NULL;
53320 +#endif
53321 +
53322 + if (req && req->complete) {
53323 + switch (status) {
53324 + case -DWC_E_SHUTDOWN:
53325 + req->status = -ESHUTDOWN;
53326 + break;
53327 + case -DWC_E_RESTART:
53328 + req->status = -ECONNRESET;
53329 + break;
53330 + case -DWC_E_INVALID:
53331 + req->status = -EINVAL;
53332 + break;
53333 + case -DWC_E_TIMEOUT:
53334 + req->status = -ETIMEDOUT;
53335 + break;
53336 + default:
53337 + req->status = status;
53338 +
53339 + }
53340 +
53341 + req->actual = actual;
53342 + DWC_SPINUNLOCK(pcd->lock);
53343 + req->complete(ep_handle, req);
53344 + DWC_SPINLOCK(pcd->lock);
53345 + }
53346 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
53347 + ep = ep_from_handle(pcd, ep_handle);
53348 + if (GET_CORE_IF(pcd)->dma_enable) {
53349 + if (req->length != 0) {
53350 + dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev;
53351 + struct device *dev = NULL;
53352 +
53353 + if (otg_dev != NULL)
53354 + dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep);
53355 +
53356 + dma_unmap_single(dev, req->dma, req->length,
53357 + ep->dwc_ep.is_in ?
53358 + DMA_TO_DEVICE: DMA_FROM_DEVICE);
53359 + }
53360 + }
53361 +#endif
53362 +
53363 + return 0;
53364 +}
53365 +
53366 +static int _connect(dwc_otg_pcd_t * pcd, int speed)
53367 +{
53368 + gadget_wrapper->gadget.speed = speed;
53369 + return 0;
53370 +}
53371 +
53372 +static int _disconnect(dwc_otg_pcd_t * pcd)
53373 +{
53374 + if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) {
53375 + gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget);
53376 + }
53377 + return 0;
53378 +}
53379 +
53380 +static int _resume(dwc_otg_pcd_t * pcd)
53381 +{
53382 + if (gadget_wrapper->driver && gadget_wrapper->driver->resume) {
53383 + gadget_wrapper->driver->resume(&gadget_wrapper->gadget);
53384 + }
53385 +
53386 + return 0;
53387 +}
53388 +
53389 +static int _suspend(dwc_otg_pcd_t * pcd)
53390 +{
53391 + if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) {
53392 + gadget_wrapper->driver->suspend(&gadget_wrapper->gadget);
53393 + }
53394 + return 0;
53395 +}
53396 +
53397 +/**
53398 + * This function updates the otg values in the gadget structure.
53399 + */
53400 +static int _hnp_changed(dwc_otg_pcd_t * pcd)
53401 +{
53402 +
53403 + if (!gadget_wrapper->gadget.is_otg)
53404 + return 0;
53405 +
53406 + gadget_wrapper->gadget.b_hnp_enable = get_b_hnp_enable(pcd);
53407 + gadget_wrapper->gadget.a_hnp_support = get_a_hnp_support(pcd);
53408 + gadget_wrapper->gadget.a_alt_hnp_support = get_a_alt_hnp_support(pcd);
53409 + return 0;
53410 +}
53411 +
53412 +static int _reset(dwc_otg_pcd_t * pcd)
53413 +{
53414 + return 0;
53415 +}
53416 +
53417 +#ifdef DWC_UTE_CFI
53418 +static int _cfi_setup(dwc_otg_pcd_t * pcd, void *cfi_req)
53419 +{
53420 + int retval = -DWC_E_INVALID;
53421 + if (gadget_wrapper->driver->cfi_feature_setup) {
53422 + retval =
53423 + gadget_wrapper->driver->
53424 + cfi_feature_setup(&gadget_wrapper->gadget,
53425 + (struct cfi_usb_ctrlrequest *)cfi_req);
53426 + }
53427 +
53428 + return retval;
53429 +}
53430 +#endif
53431 +
53432 +static const struct dwc_otg_pcd_function_ops fops = {
53433 + .complete = _complete,
53434 +#ifdef DWC_EN_ISOC
53435 + .isoc_complete = _isoc_complete,
53436 +#endif
53437 + .setup = _setup,
53438 + .disconnect = _disconnect,
53439 + .connect = _connect,
53440 + .resume = _resume,
53441 + .suspend = _suspend,
53442 + .hnp_changed = _hnp_changed,
53443 + .reset = _reset,
53444 +#ifdef DWC_UTE_CFI
53445 + .cfi_setup = _cfi_setup,
53446 +#endif
53447 +#ifdef DWC_UTE_PER_IO
53448 + .xisoc_complete = _xisoc_complete,
53449 +#endif
53450 +};
53451 +
53452 +/**
53453 + * This function is the top level PCD interrupt handler.
53454 + */
53455 +static irqreturn_t dwc_otg_pcd_irq(int irq, void *dev)
53456 +{
53457 + dwc_otg_pcd_t *pcd = dev;
53458 + int32_t retval = IRQ_NONE;
53459 +
53460 + retval = dwc_otg_pcd_handle_intr(pcd);
53461 + if (retval != 0) {
53462 + S3C2410X_CLEAR_EINTPEND();
53463 + }
53464 + return IRQ_RETVAL(retval);
53465 +}
53466 +
53467 +/**
53468 + * This function initialized the usb_ep structures to there default
53469 + * state.
53470 + *
53471 + * @param d Pointer on gadget_wrapper.
53472 + */
53473 +void gadget_add_eps(struct gadget_wrapper *d)
53474 +{
53475 + static const char *names[] = {
53476 +
53477 + "ep0",
53478 + "ep1in",
53479 + "ep2in",
53480 + "ep3in",
53481 + "ep4in",
53482 + "ep5in",
53483 + "ep6in",
53484 + "ep7in",
53485 + "ep8in",
53486 + "ep9in",
53487 + "ep10in",
53488 + "ep11in",
53489 + "ep12in",
53490 + "ep13in",
53491 + "ep14in",
53492 + "ep15in",
53493 + "ep1out",
53494 + "ep2out",
53495 + "ep3out",
53496 + "ep4out",
53497 + "ep5out",
53498 + "ep6out",
53499 + "ep7out",
53500 + "ep8out",
53501 + "ep9out",
53502 + "ep10out",
53503 + "ep11out",
53504 + "ep12out",
53505 + "ep13out",
53506 + "ep14out",
53507 + "ep15out"
53508 + };
53509 +
53510 + int i;
53511 + struct usb_ep *ep;
53512 + int8_t dev_endpoints;
53513 +
53514 + DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__);
53515 +
53516 + INIT_LIST_HEAD(&d->gadget.ep_list);
53517 + d->gadget.ep0 = &d->ep0;
53518 + d->gadget.speed = USB_SPEED_UNKNOWN;
53519 +
53520 + INIT_LIST_HEAD(&d->gadget.ep0->ep_list);
53521 +
53522 + /**
53523 + * Initialize the EP0 structure.
53524 + */
53525 + ep = &d->ep0;
53526 +
53527 + /* Init the usb_ep structure. */
53528 + ep->name = names[0];
53529 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
53530 +
53531 + /**
53532 + * @todo NGS: What should the max packet size be set to
53533 + * here? Before EP type is set?
53534 + */
53535 + ep->maxpacket = MAX_PACKET_SIZE;
53536 + dwc_otg_pcd_ep_enable(d->pcd, NULL, ep);
53537 +
53538 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
53539 +
53540 + /**
53541 + * Initialize the EP structures.
53542 + */
53543 + dev_endpoints = d->pcd->core_if->dev_if->num_in_eps;
53544 +
53545 + for (i = 0; i < dev_endpoints; i++) {
53546 + ep = &d->in_ep[i];
53547 +
53548 + /* Init the usb_ep structure. */
53549 + ep->name = names[d->pcd->in_ep[i].dwc_ep.num];
53550 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
53551 +
53552 + /**
53553 + * @todo NGS: What should the max packet size be set to
53554 + * here? Before EP type is set?
53555 + */
53556 + ep->maxpacket = MAX_PACKET_SIZE;
53557 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
53558 + }
53559 +
53560 + dev_endpoints = d->pcd->core_if->dev_if->num_out_eps;
53561 +
53562 + for (i = 0; i < dev_endpoints; i++) {
53563 + ep = &d->out_ep[i];
53564 +
53565 + /* Init the usb_ep structure. */
53566 + ep->name = names[15 + d->pcd->out_ep[i].dwc_ep.num];
53567 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
53568 +
53569 + /**
53570 + * @todo NGS: What should the max packet size be set to
53571 + * here? Before EP type is set?
53572 + */
53573 + ep->maxpacket = MAX_PACKET_SIZE;
53574 +
53575 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
53576 + }
53577 +
53578 + /* remove ep0 from the list. There is a ep0 pointer. */
53579 + list_del_init(&d->ep0.ep_list);
53580 +
53581 + d->ep0.maxpacket = MAX_EP0_SIZE;
53582 +}
53583 +
53584 +/**
53585 + * This function releases the Gadget device.
53586 + * required by device_unregister().
53587 + *
53588 + * @todo Should this do something? Should it free the PCD?
53589 + */
53590 +static void dwc_otg_pcd_gadget_release(struct device *dev)
53591 +{
53592 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
53593 +}
53594 +
53595 +static struct gadget_wrapper *alloc_wrapper(dwc_bus_dev_t *_dev)
53596 +{
53597 + static char pcd_name[] = "dwc_otg_pcd";
53598 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
53599 + struct gadget_wrapper *d;
53600 + int retval;
53601 +
53602 + d = DWC_ALLOC(sizeof(*d));
53603 + if (d == NULL) {
53604 + return NULL;
53605 + }
53606 +
53607 + memset(d, 0, sizeof(*d));
53608 +
53609 + d->gadget.name = pcd_name;
53610 + d->pcd = otg_dev->pcd;
53611 +
53612 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
53613 + strcpy(d->gadget.dev.bus_id, "gadget");
53614 +#else
53615 + dev_set_name(&d->gadget.dev, "%s", "gadget");
53616 +#endif
53617 +
53618 + d->gadget.dev.parent = &_dev->dev;
53619 + d->gadget.dev.release = dwc_otg_pcd_gadget_release;
53620 + d->gadget.ops = &dwc_otg_pcd_ops;
53621 + d->gadget.max_speed = dwc_otg_pcd_is_dualspeed(otg_dev->pcd) ? USB_SPEED_HIGH:USB_SPEED_FULL;
53622 + d->gadget.is_otg = dwc_otg_pcd_is_otg(otg_dev->pcd);
53623 +
53624 + d->driver = 0;
53625 + /* Register the gadget device */
53626 + retval = device_register(&d->gadget.dev);
53627 + if (retval != 0) {
53628 + DWC_ERROR("device_register failed\n");
53629 + DWC_FREE(d);
53630 + return NULL;
53631 + }
53632 +
53633 + return d;
53634 +}
53635 +
53636 +static void free_wrapper(struct gadget_wrapper *d)
53637 +{
53638 + if (d->driver) {
53639 + /* should have been done already by driver model core */
53640 + DWC_WARN("driver '%s' is still registered\n",
53641 + d->driver->driver.name);
53642 + usb_gadget_unregister_driver(d->driver);
53643 + }
53644 +
53645 + device_unregister(&d->gadget.dev);
53646 + DWC_FREE(d);
53647 +}
53648 +
53649 +/**
53650 + * This function initialized the PCD portion of the driver.
53651 + *
53652 + */
53653 +int pcd_init(dwc_bus_dev_t *_dev)
53654 +{
53655 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
53656 + int retval = 0;
53657 +
53658 + DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev=%p\n", __func__, _dev, otg_dev);
53659 +
53660 + otg_dev->pcd = dwc_otg_pcd_init(otg_dev->core_if);
53661 +
53662 + if (!otg_dev->pcd) {
53663 + DWC_ERROR("dwc_otg_pcd_init failed\n");
53664 + return -ENOMEM;
53665 + }
53666 +
53667 + otg_dev->pcd->otg_dev = otg_dev;
53668 + gadget_wrapper = alloc_wrapper(_dev);
53669 +
53670 + /*
53671 + * Initialize EP structures
53672 + */
53673 + gadget_add_eps(gadget_wrapper);
53674 + /*
53675 + * Setup interupt handler
53676 + */
53677 +#ifdef PLATFORM_INTERFACE
53678 + DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
53679 + platform_get_irq(_dev, 0));
53680 + retval = request_irq(platform_get_irq(_dev, 0), dwc_otg_pcd_irq,
53681 + IRQF_SHARED, gadget_wrapper->gadget.name,
53682 + otg_dev->pcd);
53683 + if (retval != 0) {
53684 + DWC_ERROR("request of irq%d failed\n",
53685 + platform_get_irq(_dev, 0));
53686 + free_wrapper(gadget_wrapper);
53687 + return -EBUSY;
53688 + }
53689 +#else
53690 + DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
53691 + _dev->irq);
53692 + retval = request_irq(_dev->irq, dwc_otg_pcd_irq,
53693 + IRQF_SHARED | IRQF_DISABLED,
53694 + gadget_wrapper->gadget.name, otg_dev->pcd);
53695 + if (retval != 0) {
53696 + DWC_ERROR("request of irq%d failed\n", _dev->irq);
53697 + free_wrapper(gadget_wrapper);
53698 + return -EBUSY;
53699 + }
53700 +#endif
53701 +
53702 + dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
53703 +
53704 + return retval;
53705 +}
53706 +
53707 +/**
53708 + * Cleanup the PCD.
53709 + */
53710 +void pcd_remove(dwc_bus_dev_t *_dev)
53711 +{
53712 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
53713 + dwc_otg_pcd_t *pcd = otg_dev->pcd;
53714 +
53715 + DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev);
53716 +
53717 + /*
53718 + * Free the IRQ
53719 + */
53720 +#ifdef PLATFORM_INTERFACE
53721 + free_irq(platform_get_irq(_dev, 0), pcd);
53722 +#else
53723 + free_irq(_dev->irq, pcd);
53724 +#endif
53725 + dwc_otg_pcd_remove(otg_dev->pcd);
53726 + free_wrapper(gadget_wrapper);
53727 + otg_dev->pcd = 0;
53728 +}
53729 +
53730 +/**
53731 + * This function registers a gadget driver with the PCD.
53732 + *
53733 + * When a driver is successfully registered, it will receive control
53734 + * requests including set_configuration(), which enables non-control
53735 + * requests. then usb traffic follows until a disconnect is reported.
53736 + * then a host may connect again, or the driver might get unbound.
53737 + *
53738 + * @param driver The driver being registered
53739 + * @param bind The bind function of gadget driver
53740 + */
53741 +
53742 +int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
53743 +{
53744 + int retval;
53745 +
53746 + DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n",
53747 + driver->driver.name);
53748 +
53749 + if (!driver || driver->max_speed == USB_SPEED_UNKNOWN ||
53750 + !driver->bind ||
53751 + !driver->unbind || !driver->disconnect || !driver->setup) {
53752 + DWC_DEBUGPL(DBG_PCDV, "EINVAL\n");
53753 + return -EINVAL;
53754 + }
53755 + if (gadget_wrapper == 0) {
53756 + DWC_DEBUGPL(DBG_PCDV, "ENODEV\n");
53757 + return -ENODEV;
53758 + }
53759 + if (gadget_wrapper->driver != 0) {
53760 + DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", gadget_wrapper->driver);
53761 + return -EBUSY;
53762 + }
53763 +
53764 + /* hook up the driver */
53765 + gadget_wrapper->driver = driver;
53766 + gadget_wrapper->gadget.dev.driver = &driver->driver;
53767 +
53768 + DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", driver->driver.name);
53769 + retval = driver->bind(&gadget_wrapper->gadget, gadget_wrapper->driver);
53770 + if (retval) {
53771 + DWC_ERROR("bind to driver %s --> error %d\n",
53772 + driver->driver.name, retval);
53773 + gadget_wrapper->driver = 0;
53774 + gadget_wrapper->gadget.dev.driver = 0;
53775 + return retval;
53776 + }
53777 + DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n",
53778 + driver->driver.name);
53779 + return 0;
53780 +}
53781 +EXPORT_SYMBOL(usb_gadget_probe_driver);
53782 +
53783 +/**
53784 + * This function unregisters a gadget driver
53785 + *
53786 + * @param driver The driver being unregistered
53787 + */
53788 +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
53789 +{
53790 + //DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver);
53791 +
53792 + if (gadget_wrapper == 0) {
53793 + DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__,
53794 + -ENODEV);
53795 + return -ENODEV;
53796 + }
53797 + if (driver == 0 || driver != gadget_wrapper->driver) {
53798 + DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__,
53799 + -EINVAL);
53800 + return -EINVAL;
53801 + }
53802 +
53803 + driver->unbind(&gadget_wrapper->gadget);
53804 + gadget_wrapper->driver = 0;
53805 +
53806 + DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", driver->driver.name);
53807 + return 0;
53808 +}
53809 +
53810 +EXPORT_SYMBOL(usb_gadget_unregister_driver);
53811 +
53812 +#endif /* DWC_HOST_ONLY */
53813 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_regs.h b/drivers/usb/host/dwc_otg/dwc_otg_regs.h
53814 new file mode 100644
53815 index 0000000..8e0e7b5
53816 --- /dev/null
53817 +++ b/drivers/usb/host/dwc_otg/dwc_otg_regs.h
53818 @@ -0,0 +1,2550 @@
53819 +/* ==========================================================================
53820 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_regs.h $
53821 + * $Revision: #98 $
53822 + * $Date: 2012/08/10 $
53823 + * $Change: 2047372 $
53824 + *
53825 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
53826 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
53827 + * otherwise expressly agreed to in writing between Synopsys and you.
53828 + *
53829 + * The Software IS NOT an item of Licensed Software or Licensed Product under
53830 + * any End User Software License Agreement or Agreement for Licensed Product
53831 + * with Synopsys or any supplement thereto. You are permitted to use and
53832 + * redistribute this Software in source and binary forms, with or without
53833 + * modification, provided that redistributions of source code must retain this
53834 + * notice. You may not view, use, disclose, copy or distribute this file or
53835 + * any information contained herein except pursuant to this license grant from
53836 + * Synopsys. If you do not agree with this notice, including the disclaimer
53837 + * below, then you are not authorized to use the Software.
53838 + *
53839 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
53840 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53841 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53842 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
53843 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
53844 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
53845 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
53846 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53847 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53848 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
53849 + * DAMAGE.
53850 + * ========================================================================== */
53851 +
53852 +#ifndef __DWC_OTG_REGS_H__
53853 +#define __DWC_OTG_REGS_H__
53854 +
53855 +#include "dwc_otg_core_if.h"
53856 +
53857 +/**
53858 + * @file
53859 + *
53860 + * This file contains the data structures for accessing the DWC_otg core registers.
53861 + *
53862 + * The application interfaces with the HS OTG core by reading from and
53863 + * writing to the Control and Status Register (CSR) space through the
53864 + * AHB Slave interface. These registers are 32 bits wide, and the
53865 + * addresses are 32-bit-block aligned.
53866 + * CSRs are classified as follows:
53867 + * - Core Global Registers
53868 + * - Device Mode Registers
53869 + * - Device Global Registers
53870 + * - Device Endpoint Specific Registers
53871 + * - Host Mode Registers
53872 + * - Host Global Registers
53873 + * - Host Port CSRs
53874 + * - Host Channel Specific Registers
53875 + *
53876 + * Only the Core Global registers can be accessed in both Device and
53877 + * Host modes. When the HS OTG core is operating in one mode, either
53878 + * Device or Host, the application must not access registers from the
53879 + * other mode. When the core switches from one mode to another, the
53880 + * registers in the new mode of operation must be reprogrammed as they
53881 + * would be after a power-on reset.
53882 + */
53883 +
53884 +/****************************************************************************/
53885 +/** DWC_otg Core registers .
53886 + * The dwc_otg_core_global_regs structure defines the size
53887 + * and relative field offsets for the Core Global registers.
53888 + */
53889 +typedef struct dwc_otg_core_global_regs {
53890 + /** OTG Control and Status Register. <i>Offset: 000h</i> */
53891 + volatile uint32_t gotgctl;
53892 + /** OTG Interrupt Register. <i>Offset: 004h</i> */
53893 + volatile uint32_t gotgint;
53894 + /**Core AHB Configuration Register. <i>Offset: 008h</i> */
53895 + volatile uint32_t gahbcfg;
53896 +
53897 +#define DWC_GLBINTRMASK 0x0001
53898 +#define DWC_DMAENABLE 0x0020
53899 +#define DWC_NPTXEMPTYLVL_EMPTY 0x0080
53900 +#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000
53901 +#define DWC_PTXEMPTYLVL_EMPTY 0x0100
53902 +#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000
53903 +
53904 + /**Core USB Configuration Register. <i>Offset: 00Ch</i> */
53905 + volatile uint32_t gusbcfg;
53906 + /**Core Reset Register. <i>Offset: 010h</i> */
53907 + volatile uint32_t grstctl;
53908 + /**Core Interrupt Register. <i>Offset: 014h</i> */
53909 + volatile uint32_t gintsts;
53910 + /**Core Interrupt Mask Register. <i>Offset: 018h</i> */
53911 + volatile uint32_t gintmsk;
53912 + /**Receive Status Queue Read Register (Read Only). <i>Offset: 01Ch</i> */
53913 + volatile uint32_t grxstsr;
53914 + /**Receive Status Queue Read & POP Register (Read Only). <i>Offset: 020h</i>*/
53915 + volatile uint32_t grxstsp;
53916 + /**Receive FIFO Size Register. <i>Offset: 024h</i> */
53917 + volatile uint32_t grxfsiz;
53918 + /**Non Periodic Transmit FIFO Size Register. <i>Offset: 028h</i> */
53919 + volatile uint32_t gnptxfsiz;
53920 + /**Non Periodic Transmit FIFO/Queue Status Register (Read
53921 + * Only). <i>Offset: 02Ch</i> */
53922 + volatile uint32_t gnptxsts;
53923 + /**I2C Access Register. <i>Offset: 030h</i> */
53924 + volatile uint32_t gi2cctl;
53925 + /**PHY Vendor Control Register. <i>Offset: 034h</i> */
53926 + volatile uint32_t gpvndctl;
53927 + /**General Purpose Input/Output Register. <i>Offset: 038h</i> */
53928 + volatile uint32_t ggpio;
53929 + /**User ID Register. <i>Offset: 03Ch</i> */
53930 + volatile uint32_t guid;
53931 + /**Synopsys ID Register (Read Only). <i>Offset: 040h</i> */
53932 + volatile uint32_t gsnpsid;
53933 + /**User HW Config1 Register (Read Only). <i>Offset: 044h</i> */
53934 + volatile uint32_t ghwcfg1;
53935 + /**User HW Config2 Register (Read Only). <i>Offset: 048h</i> */
53936 + volatile uint32_t ghwcfg2;
53937 +#define DWC_SLAVE_ONLY_ARCH 0
53938 +#define DWC_EXT_DMA_ARCH 1
53939 +#define DWC_INT_DMA_ARCH 2
53940 +
53941 +#define DWC_MODE_HNP_SRP_CAPABLE 0
53942 +#define DWC_MODE_SRP_ONLY_CAPABLE 1
53943 +#define DWC_MODE_NO_HNP_SRP_CAPABLE 2
53944 +#define DWC_MODE_SRP_CAPABLE_DEVICE 3
53945 +#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4
53946 +#define DWC_MODE_SRP_CAPABLE_HOST 5
53947 +#define DWC_MODE_NO_SRP_CAPABLE_HOST 6
53948 +
53949 + /**User HW Config3 Register (Read Only). <i>Offset: 04Ch</i> */
53950 + volatile uint32_t ghwcfg3;
53951 + /**User HW Config4 Register (Read Only). <i>Offset: 050h</i>*/
53952 + volatile uint32_t ghwcfg4;
53953 + /** Core LPM Configuration register <i>Offset: 054h</i>*/
53954 + volatile uint32_t glpmcfg;
53955 + /** Global PowerDn Register <i>Offset: 058h</i> */
53956 + volatile uint32_t gpwrdn;
53957 + /** Global DFIFO SW Config Register <i>Offset: 05Ch</i> */
53958 + volatile uint32_t gdfifocfg;
53959 + /** ADP Control Register <i>Offset: 060h</i> */
53960 + volatile uint32_t adpctl;
53961 + /** Reserved <i>Offset: 064h-0FFh</i> */
53962 + volatile uint32_t reserved39[39];
53963 + /** Host Periodic Transmit FIFO Size Register. <i>Offset: 100h</i> */
53964 + volatile uint32_t hptxfsiz;
53965 + /** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled,
53966 + otherwise Device Transmit FIFO#n Register.
53967 + * <i>Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15).</i> */
53968 + volatile uint32_t dtxfsiz[15];
53969 +} dwc_otg_core_global_regs_t;
53970 +
53971 +/**
53972 + * This union represents the bit fields of the Core OTG Control
53973 + * and Status Register (GOTGCTL). Set the bits using the bit
53974 + * fields then write the <i>d32</i> value to the register.
53975 + */
53976 +typedef union gotgctl_data {
53977 + /** raw register data */
53978 + uint32_t d32;
53979 + /** register bits */
53980 + struct {
53981 + unsigned sesreqscs:1;
53982 + unsigned sesreq:1;
53983 + unsigned vbvalidoven:1;
53984 + unsigned vbvalidovval:1;
53985 + unsigned avalidoven:1;
53986 + unsigned avalidovval:1;
53987 + unsigned bvalidoven:1;
53988 + unsigned bvalidovval:1;
53989 + unsigned hstnegscs:1;
53990 + unsigned hnpreq:1;
53991 + unsigned hstsethnpen:1;
53992 + unsigned devhnpen:1;
53993 + unsigned reserved12_15:4;
53994 + unsigned conidsts:1;
53995 + unsigned dbnctime:1;
53996 + unsigned asesvld:1;
53997 + unsigned bsesvld:1;
53998 + unsigned otgver:1;
53999 + unsigned reserved1:1;
54000 + unsigned multvalidbc:5;
54001 + unsigned chirpen:1;
54002 + unsigned reserved28_31:4;
54003 + } b;
54004 +} gotgctl_data_t;
54005 +
54006 +/**
54007 + * This union represents the bit fields of the Core OTG Interrupt Register
54008 + * (GOTGINT). Set/clear the bits using the bit fields then write the <i>d32</i>
54009 + * value to the register.
54010 + */
54011 +typedef union gotgint_data {
54012 + /** raw register data */
54013 + uint32_t d32;
54014 + /** register bits */
54015 + struct {
54016 + /** Current Mode */
54017 + unsigned reserved0_1:2;
54018 +
54019 + /** Session End Detected */
54020 + unsigned sesenddet:1;
54021 +
54022 + unsigned reserved3_7:5;
54023 +
54024 + /** Session Request Success Status Change */
54025 + unsigned sesreqsucstschng:1;
54026 + /** Host Negotiation Success Status Change */
54027 + unsigned hstnegsucstschng:1;
54028 +
54029 + unsigned reserved10_16:7;
54030 +
54031 + /** Host Negotiation Detected */
54032 + unsigned hstnegdet:1;
54033 + /** A-Device Timeout Change */
54034 + unsigned adevtoutchng:1;
54035 + /** Debounce Done */
54036 + unsigned debdone:1;
54037 + /** Multi-Valued input changed */
54038 + unsigned mvic:1;
54039 +
54040 + unsigned reserved31_21:11;
54041 +
54042 + } b;
54043 +} gotgint_data_t;
54044 +
54045 +/**
54046 + * This union represents the bit fields of the Core AHB Configuration
54047 + * Register (GAHBCFG). Set/clear the bits using the bit fields then
54048 + * write the <i>d32</i> value to the register.
54049 + */
54050 +typedef union gahbcfg_data {
54051 + /** raw register data */
54052 + uint32_t d32;
54053 + /** register bits */
54054 + struct {
54055 + unsigned glblintrmsk:1;
54056 +#define DWC_GAHBCFG_GLBINT_ENABLE 1
54057 +
54058 + unsigned hburstlen:4;
54059 +#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE 0
54060 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR 1
54061 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR4 3
54062 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR8 5
54063 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR16 7
54064 +
54065 + unsigned dmaenable:1;
54066 +#define DWC_GAHBCFG_DMAENABLE 1
54067 + unsigned reserved:1;
54068 + unsigned nptxfemplvl_txfemplvl:1;
54069 + unsigned ptxfemplvl:1;
54070 +#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY 1
54071 +#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0
54072 + unsigned reserved9_20:12;
54073 + unsigned remmemsupp:1;
54074 + unsigned notialldmawrit:1;
54075 + unsigned ahbsingle:1;
54076 + unsigned reserved24_31:8;
54077 + } b;
54078 +} gahbcfg_data_t;
54079 +
54080 +/**
54081 + * This union represents the bit fields of the Core USB Configuration
54082 + * Register (GUSBCFG). Set the bits using the bit fields then write
54083 + * the <i>d32</i> value to the register.
54084 + */
54085 +typedef union gusbcfg_data {
54086 + /** raw register data */
54087 + uint32_t d32;
54088 + /** register bits */
54089 + struct {
54090 + unsigned toutcal:3;
54091 + unsigned phyif:1;
54092 + unsigned ulpi_utmi_sel:1;
54093 + unsigned fsintf:1;
54094 + unsigned physel:1;
54095 + unsigned ddrsel:1;
54096 + unsigned srpcap:1;
54097 + unsigned hnpcap:1;
54098 + unsigned usbtrdtim:4;
54099 + unsigned reserved1:1;
54100 + unsigned phylpwrclksel:1;
54101 + unsigned otgutmifssel:1;
54102 + unsigned ulpi_fsls:1;
54103 + unsigned ulpi_auto_res:1;
54104 + unsigned ulpi_clk_sus_m:1;
54105 + unsigned ulpi_ext_vbus_drv:1;
54106 + unsigned ulpi_int_vbus_indicator:1;
54107 + unsigned term_sel_dl_pulse:1;
54108 + unsigned indicator_complement:1;
54109 + unsigned indicator_pass_through:1;
54110 + unsigned ulpi_int_prot_dis:1;
54111 + unsigned ic_usb_cap:1;
54112 + unsigned ic_traffic_pull_remove:1;
54113 + unsigned tx_end_delay:1;
54114 + unsigned force_host_mode:1;
54115 + unsigned force_dev_mode:1;
54116 + unsigned reserved31:1;
54117 + } b;
54118 +} gusbcfg_data_t;
54119 +
54120 +/**
54121 + * This union represents the bit fields of the Core Reset Register
54122 + * (GRSTCTL). Set/clear the bits using the bit fields then write the
54123 + * <i>d32</i> value to the register.
54124 + */
54125 +typedef union grstctl_data {
54126 + /** raw register data */
54127 + uint32_t d32;
54128 + /** register bits */
54129 + struct {
54130 + /** Core Soft Reset (CSftRst) (Device and Host)
54131 + *
54132 + * The application can flush the control logic in the
54133 + * entire core using this bit. This bit resets the
54134 + * pipelines in the AHB Clock domain as well as the
54135 + * PHY Clock domain.
54136 + *
54137 + * The state machines are reset to an IDLE state, the
54138 + * control bits in the CSRs are cleared, all the
54139 + * transmit FIFOs and the receive FIFO are flushed.
54140 + *
54141 + * The status mask bits that control the generation of
54142 + * the interrupt, are cleared, to clear the
54143 + * interrupt. The interrupt status bits are not
54144 + * cleared, so the application can get the status of
54145 + * any events that occurred in the core after it has
54146 + * set this bit.
54147 + *
54148 + * Any transactions on the AHB are terminated as soon
54149 + * as possible following the protocol. Any
54150 + * transactions on the USB are terminated immediately.
54151 + *
54152 + * The configuration settings in the CSRs are
54153 + * unchanged, so the software doesn't have to
54154 + * reprogram these registers (Device
54155 + * Configuration/Host Configuration/Core System
54156 + * Configuration/Core PHY Configuration).
54157 + *
54158 + * The application can write to this bit, any time it
54159 + * wants to reset the core. This is a self clearing
54160 + * bit and the core clears this bit after all the
54161 + * necessary logic is reset in the core, which may
54162 + * take several clocks, depending on the current state
54163 + * of the core.
54164 + */
54165 + unsigned csftrst:1;
54166 + /** Hclk Soft Reset
54167 + *
54168 + * The application uses this bit to reset the control logic in
54169 + * the AHB clock domain. Only AHB clock domain pipelines are
54170 + * reset.
54171 + */
54172 + unsigned hsftrst:1;
54173 + /** Host Frame Counter Reset (Host Only)<br>
54174 + *
54175 + * The application can reset the (micro)frame number
54176 + * counter inside the core, using this bit. When the
54177 + * (micro)frame counter is reset, the subsequent SOF
54178 + * sent out by the core, will have a (micro)frame
54179 + * number of 0.
54180 + */
54181 + unsigned hstfrm:1;
54182 + /** In Token Sequence Learning Queue Flush
54183 + * (INTknQFlsh) (Device Only)
54184 + */
54185 + unsigned intknqflsh:1;
54186 + /** RxFIFO Flush (RxFFlsh) (Device and Host)
54187 + *
54188 + * The application can flush the entire Receive FIFO
54189 + * using this bit. The application must first
54190 + * ensure that the core is not in the middle of a
54191 + * transaction. The application should write into
54192 + * this bit, only after making sure that neither the
54193 + * DMA engine is reading from the RxFIFO nor the MAC
54194 + * is writing the data in to the FIFO. The
54195 + * application should wait until the bit is cleared
54196 + * before performing any other operations. This bit
54197 + * will takes 8 clocks (slowest of PHY or AHB clock)
54198 + * to clear.
54199 + */
54200 + unsigned rxfflsh:1;
54201 + /** TxFIFO Flush (TxFFlsh) (Device and Host).
54202 + *
54203 + * This bit is used to selectively flush a single or
54204 + * all transmit FIFOs. The application must first
54205 + * ensure that the core is not in the middle of a
54206 + * transaction. The application should write into
54207 + * this bit, only after making sure that neither the
54208 + * DMA engine is writing into the TxFIFO nor the MAC
54209 + * is reading the data out of the FIFO. The
54210 + * application should wait until the core clears this
54211 + * bit, before performing any operations. This bit
54212 + * will takes 8 clocks (slowest of PHY or AHB clock)
54213 + * to clear.
54214 + */
54215 + unsigned txfflsh:1;
54216 +
54217 + /** TxFIFO Number (TxFNum) (Device and Host).
54218 + *
54219 + * This is the FIFO number which needs to be flushed,
54220 + * using the TxFIFO Flush bit. This field should not
54221 + * be changed until the TxFIFO Flush bit is cleared by
54222 + * the core.
54223 + * - 0x0 : Non Periodic TxFIFO Flush
54224 + * - 0x1 : Periodic TxFIFO #1 Flush in device mode
54225 + * or Periodic TxFIFO in host mode
54226 + * - 0x2 : Periodic TxFIFO #2 Flush in device mode.
54227 + * - ...
54228 + * - 0xF : Periodic TxFIFO #15 Flush in device mode
54229 + * - 0x10: Flush all the Transmit NonPeriodic and
54230 + * Transmit Periodic FIFOs in the core
54231 + */
54232 + unsigned txfnum:5;
54233 + /** Reserved */
54234 + unsigned reserved11_29:19;
54235 + /** DMA Request Signal. Indicated DMA request is in
54236 + * probress. Used for debug purpose. */
54237 + unsigned dmareq:1;
54238 + /** AHB Master Idle. Indicates the AHB Master State
54239 + * Machine is in IDLE condition. */
54240 + unsigned ahbidle:1;
54241 + } b;
54242 +} grstctl_t;
54243 +
54244 +/**
54245 + * This union represents the bit fields of the Core Interrupt Mask
54246 + * Register (GINTMSK). Set/clear the bits using the bit fields then
54247 + * write the <i>d32</i> value to the register.
54248 + */
54249 +typedef union gintmsk_data {
54250 + /** raw register data */
54251 + uint32_t d32;
54252 + /** register bits */
54253 + struct {
54254 + unsigned reserved0:1;
54255 + unsigned modemismatch:1;
54256 + unsigned otgintr:1;
54257 + unsigned sofintr:1;
54258 + unsigned rxstsqlvl:1;
54259 + unsigned nptxfempty:1;
54260 + unsigned ginnakeff:1;
54261 + unsigned goutnakeff:1;
54262 + unsigned ulpickint:1;
54263 + unsigned i2cintr:1;
54264 + unsigned erlysuspend:1;
54265 + unsigned usbsuspend:1;
54266 + unsigned usbreset:1;
54267 + unsigned enumdone:1;
54268 + unsigned isooutdrop:1;
54269 + unsigned eopframe:1;
54270 + unsigned restoredone:1;
54271 + unsigned epmismatch:1;
54272 + unsigned inepintr:1;
54273 + unsigned outepintr:1;
54274 + unsigned incomplisoin:1;
54275 + unsigned incomplisoout:1;
54276 + unsigned fetsusp:1;
54277 + unsigned resetdet:1;
54278 + unsigned portintr:1;
54279 + unsigned hcintr:1;
54280 + unsigned ptxfempty:1;
54281 + unsigned lpmtranrcvd:1;
54282 + unsigned conidstschng:1;
54283 + unsigned disconnect:1;
54284 + unsigned sessreqintr:1;
54285 + unsigned wkupintr:1;
54286 + } b;
54287 +} gintmsk_data_t;
54288 +/**
54289 + * This union represents the bit fields of the Core Interrupt Register
54290 + * (GINTSTS). Set/clear the bits using the bit fields then write the
54291 + * <i>d32</i> value to the register.
54292 + */
54293 +typedef union gintsts_data {
54294 + /** raw register data */
54295 + uint32_t d32;
54296 +#define DWC_SOF_INTR_MASK 0x0008
54297 + /** register bits */
54298 + struct {
54299 +#define DWC_HOST_MODE 1
54300 + unsigned curmode:1;
54301 + unsigned modemismatch:1;
54302 + unsigned otgintr:1;
54303 + unsigned sofintr:1;
54304 + unsigned rxstsqlvl:1;
54305 + unsigned nptxfempty:1;
54306 + unsigned ginnakeff:1;
54307 + unsigned goutnakeff:1;
54308 + unsigned ulpickint:1;
54309 + unsigned i2cintr:1;
54310 + unsigned erlysuspend:1;
54311 + unsigned usbsuspend:1;
54312 + unsigned usbreset:1;
54313 + unsigned enumdone:1;
54314 + unsigned isooutdrop:1;
54315 + unsigned eopframe:1;
54316 + unsigned restoredone:1;
54317 + unsigned epmismatch:1;
54318 + unsigned inepint:1;
54319 + unsigned outepintr:1;
54320 + unsigned incomplisoin:1;
54321 + unsigned incomplisoout:1;
54322 + unsigned fetsusp:1;
54323 + unsigned resetdet:1;
54324 + unsigned portintr:1;
54325 + unsigned hcintr:1;
54326 + unsigned ptxfempty:1;
54327 + unsigned lpmtranrcvd:1;
54328 + unsigned conidstschng:1;
54329 + unsigned disconnect:1;
54330 + unsigned sessreqintr:1;
54331 + unsigned wkupintr:1;
54332 + } b;
54333 +} gintsts_data_t;
54334 +
54335 +/**
54336 + * This union represents the bit fields in the Device Receive Status Read and
54337 + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
54338 + * element then read out the bits using the <i>b</i>it elements.
54339 + */
54340 +typedef union device_grxsts_data {
54341 + /** raw register data */
54342 + uint32_t d32;
54343 + /** register bits */
54344 + struct {
54345 + unsigned epnum:4;
54346 + unsigned bcnt:11;
54347 + unsigned dpid:2;
54348 +
54349 +#define DWC_STS_DATA_UPDT 0x2 // OUT Data Packet
54350 +#define DWC_STS_XFER_COMP 0x3 // OUT Data Transfer Complete
54351 +
54352 +#define DWC_DSTS_GOUT_NAK 0x1 // Global OUT NAK
54353 +#define DWC_DSTS_SETUP_COMP 0x4 // Setup Phase Complete
54354 +#define DWC_DSTS_SETUP_UPDT 0x6 // SETUP Packet
54355 + unsigned pktsts:4;
54356 + unsigned fn:4;
54357 + unsigned reserved25_31:7;
54358 + } b;
54359 +} device_grxsts_data_t;
54360 +
54361 +/**
54362 + * This union represents the bit fields in the Host Receive Status Read and
54363 + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
54364 + * element then read out the bits using the <i>b</i>it elements.
54365 + */
54366 +typedef union host_grxsts_data {
54367 + /** raw register data */
54368 + uint32_t d32;
54369 + /** register bits */
54370 + struct {
54371 + unsigned chnum:4;
54372 + unsigned bcnt:11;
54373 + unsigned dpid:2;
54374 +
54375 + unsigned pktsts:4;
54376 +#define DWC_GRXSTS_PKTSTS_IN 0x2
54377 +#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP 0x3
54378 +#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5
54379 +#define DWC_GRXSTS_PKTSTS_CH_HALTED 0x7
54380 +
54381 + unsigned reserved21_31:11;
54382 + } b;
54383 +} host_grxsts_data_t;
54384 +
54385 +/**
54386 + * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ,
54387 + * GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). Read the register into the <i>d32</i> element
54388 + * then read out the bits using the <i>b</i>it elements.
54389 + */
54390 +typedef union fifosize_data {
54391 + /** raw register data */
54392 + uint32_t d32;
54393 + /** register bits */
54394 + struct {
54395 + unsigned startaddr:16;
54396 + unsigned depth:16;
54397 + } b;
54398 +} fifosize_data_t;
54399 +
54400 +/**
54401 + * This union represents the bit fields in the Non-Periodic Transmit
54402 + * FIFO/Queue Status Register (GNPTXSTS). Read the register into the
54403 + * <i>d32</i> element then read out the bits using the <i>b</i>it
54404 + * elements.
54405 + */
54406 +typedef union gnptxsts_data {
54407 + /** raw register data */
54408 + uint32_t d32;
54409 + /** register bits */
54410 + struct {
54411 + unsigned nptxfspcavail:16;
54412 + unsigned nptxqspcavail:8;
54413 + /** Top of the Non-Periodic Transmit Request Queue
54414 + * - bit 24 - Terminate (Last entry for the selected
54415 + * channel/EP)
54416 + * - bits 26:25 - Token Type
54417 + * - 2'b00 - IN/OUT
54418 + * - 2'b01 - Zero Length OUT
54419 + * - 2'b10 - PING/Complete Split
54420 + * - 2'b11 - Channel Halt
54421 + * - bits 30:27 - Channel/EP Number
54422 + */
54423 + unsigned nptxqtop_terminate:1;
54424 + unsigned nptxqtop_token:2;
54425 + unsigned nptxqtop_chnep:4;
54426 + unsigned reserved:1;
54427 + } b;
54428 +} gnptxsts_data_t;
54429 +
54430 +/**
54431 + * This union represents the bit fields in the Transmit
54432 + * FIFO Status Register (DTXFSTS). Read the register into the
54433 + * <i>d32</i> element then read out the bits using the <i>b</i>it
54434 + * elements.
54435 + */
54436 +typedef union dtxfsts_data {
54437 + /** raw register data */
54438 + uint32_t d32;
54439 + /** register bits */
54440 + struct {
54441 + unsigned txfspcavail:16;
54442 + unsigned reserved:16;
54443 + } b;
54444 +} dtxfsts_data_t;
54445 +
54446 +/**
54447 + * This union represents the bit fields in the I2C Control Register
54448 + * (I2CCTL). Read the register into the <i>d32</i> element then read out the
54449 + * bits using the <i>b</i>it elements.
54450 + */
54451 +typedef union gi2cctl_data {
54452 + /** raw register data */
54453 + uint32_t d32;
54454 + /** register bits */
54455 + struct {
54456 + unsigned rwdata:8;
54457 + unsigned regaddr:8;
54458 + unsigned addr:7;
54459 + unsigned i2cen:1;
54460 + unsigned ack:1;
54461 + unsigned i2csuspctl:1;
54462 + unsigned i2cdevaddr:2;
54463 + unsigned i2cdatse0:1;
54464 + unsigned reserved:1;
54465 + unsigned rw:1;
54466 + unsigned bsydne:1;
54467 + } b;
54468 +} gi2cctl_data_t;
54469 +
54470 +/**
54471 + * This union represents the bit fields in the PHY Vendor Control Register
54472 + * (GPVNDCTL). Read the register into the <i>d32</i> element then read out the
54473 + * bits using the <i>b</i>it elements.
54474 + */
54475 +typedef union gpvndctl_data {
54476 + /** raw register data */
54477 + uint32_t d32;
54478 + /** register bits */
54479 + struct {
54480 + unsigned regdata:8;
54481 + unsigned vctrl:8;
54482 + unsigned regaddr16_21:6;
54483 + unsigned regwr:1;
54484 + unsigned reserved23_24:2;
54485 + unsigned newregreq:1;
54486 + unsigned vstsbsy:1;
54487 + unsigned vstsdone:1;
54488 + unsigned reserved28_30:3;
54489 + unsigned disulpidrvr:1;
54490 + } b;
54491 +} gpvndctl_data_t;
54492 +
54493 +/**
54494 + * This union represents the bit fields in the General Purpose
54495 + * Input/Output Register (GGPIO).
54496 + * Read the register into the <i>d32</i> element then read out the
54497 + * bits using the <i>b</i>it elements.
54498 + */
54499 +typedef union ggpio_data {
54500 + /** raw register data */
54501 + uint32_t d32;
54502 + /** register bits */
54503 + struct {
54504 + unsigned gpi:16;
54505 + unsigned gpo:16;
54506 + } b;
54507 +} ggpio_data_t;
54508 +
54509 +/**
54510 + * This union represents the bit fields in the User ID Register
54511 + * (GUID). Read the register into the <i>d32</i> element then read out the
54512 + * bits using the <i>b</i>it elements.
54513 + */
54514 +typedef union guid_data {
54515 + /** raw register data */
54516 + uint32_t d32;
54517 + /** register bits */
54518 + struct {
54519 + unsigned rwdata:32;
54520 + } b;
54521 +} guid_data_t;
54522 +
54523 +/**
54524 + * This union represents the bit fields in the Synopsys ID Register
54525 + * (GSNPSID). Read the register into the <i>d32</i> element then read out the
54526 + * bits using the <i>b</i>it elements.
54527 + */
54528 +typedef union gsnpsid_data {
54529 + /** raw register data */
54530 + uint32_t d32;
54531 + /** register bits */
54532 + struct {
54533 + unsigned rwdata:32;
54534 + } b;
54535 +} gsnpsid_data_t;
54536 +
54537 +/**
54538 + * This union represents the bit fields in the User HW Config1
54539 + * Register. Read the register into the <i>d32</i> element then read
54540 + * out the bits using the <i>b</i>it elements.
54541 + */
54542 +typedef union hwcfg1_data {
54543 + /** raw register data */
54544 + uint32_t d32;
54545 + /** register bits */
54546 + struct {
54547 + unsigned ep_dir0:2;
54548 + unsigned ep_dir1:2;
54549 + unsigned ep_dir2:2;
54550 + unsigned ep_dir3:2;
54551 + unsigned ep_dir4:2;
54552 + unsigned ep_dir5:2;
54553 + unsigned ep_dir6:2;
54554 + unsigned ep_dir7:2;
54555 + unsigned ep_dir8:2;
54556 + unsigned ep_dir9:2;
54557 + unsigned ep_dir10:2;
54558 + unsigned ep_dir11:2;
54559 + unsigned ep_dir12:2;
54560 + unsigned ep_dir13:2;
54561 + unsigned ep_dir14:2;
54562 + unsigned ep_dir15:2;
54563 + } b;
54564 +} hwcfg1_data_t;
54565 +
54566 +/**
54567 + * This union represents the bit fields in the User HW Config2
54568 + * Register. Read the register into the <i>d32</i> element then read
54569 + * out the bits using the <i>b</i>it elements.
54570 + */
54571 +typedef union hwcfg2_data {
54572 + /** raw register data */
54573 + uint32_t d32;
54574 + /** register bits */
54575 + struct {
54576 + /* GHWCFG2 */
54577 + unsigned op_mode:3;
54578 +#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0
54579 +#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1
54580 +#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2
54581 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3
54582 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4
54583 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5
54584 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6
54585 +
54586 + unsigned architecture:2;
54587 + unsigned point2point:1;
54588 + unsigned hs_phy_type:2;
54589 +#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
54590 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1
54591 +#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2
54592 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
54593 +
54594 + unsigned fs_phy_type:2;
54595 + unsigned num_dev_ep:4;
54596 + unsigned num_host_chan:4;
54597 + unsigned perio_ep_supported:1;
54598 + unsigned dynamic_fifo:1;
54599 + unsigned multi_proc_int:1;
54600 + unsigned reserved21:1;
54601 + unsigned nonperio_tx_q_depth:2;
54602 + unsigned host_perio_tx_q_depth:2;
54603 + unsigned dev_token_q_depth:5;
54604 + unsigned otg_enable_ic_usb:1;
54605 + } b;
54606 +} hwcfg2_data_t;
54607 +
54608 +/**
54609 + * This union represents the bit fields in the User HW Config3
54610 + * Register. Read the register into the <i>d32</i> element then read
54611 + * out the bits using the <i>b</i>it elements.
54612 + */
54613 +typedef union hwcfg3_data {
54614 + /** raw register data */
54615 + uint32_t d32;
54616 + /** register bits */
54617 + struct {
54618 + /* GHWCFG3 */
54619 + unsigned xfer_size_cntr_width:4;
54620 + unsigned packet_size_cntr_width:3;
54621 + unsigned otg_func:1;
54622 + unsigned i2c:1;
54623 + unsigned vendor_ctrl_if:1;
54624 + unsigned optional_features:1;
54625 + unsigned synch_reset_type:1;
54626 + unsigned adp_supp:1;
54627 + unsigned otg_enable_hsic:1;
54628 + unsigned bc_support:1;
54629 + unsigned otg_lpm_en:1;
54630 + unsigned dfifo_depth:16;
54631 + } b;
54632 +} hwcfg3_data_t;
54633 +
54634 +/**
54635 + * This union represents the bit fields in the User HW Config4
54636 + * Register. Read the register into the <i>d32</i> element then read
54637 + * out the bits using the <i>b</i>it elements.
54638 + */
54639 +typedef union hwcfg4_data {
54640 + /** raw register data */
54641 + uint32_t d32;
54642 + /** register bits */
54643 + struct {
54644 + unsigned num_dev_perio_in_ep:4;
54645 + unsigned power_optimiz:1;
54646 + unsigned min_ahb_freq:1;
54647 + unsigned hiber:1;
54648 + unsigned xhiber:1;
54649 + unsigned reserved:6;
54650 + unsigned utmi_phy_data_width:2;
54651 + unsigned num_dev_mode_ctrl_ep:4;
54652 + unsigned iddig_filt_en:1;
54653 + unsigned vbus_valid_filt_en:1;
54654 + unsigned a_valid_filt_en:1;
54655 + unsigned b_valid_filt_en:1;
54656 + unsigned session_end_filt_en:1;
54657 + unsigned ded_fifo_en:1;
54658 + unsigned num_in_eps:4;
54659 + unsigned desc_dma:1;
54660 + unsigned desc_dma_dyn:1;
54661 + } b;
54662 +} hwcfg4_data_t;
54663 +
54664 +/**
54665 + * This union represents the bit fields of the Core LPM Configuration
54666 + * Register (GLPMCFG). Set the bits using bit fields then write
54667 + * the <i>d32</i> value to the register.
54668 + */
54669 +typedef union glpmctl_data {
54670 + /** raw register data */
54671 + uint32_t d32;
54672 + /** register bits */
54673 + struct {
54674 + /** LPM-Capable (LPMCap) (Device and Host)
54675 + * The application uses this bit to control
54676 + * the DWC_otg core LPM capabilities.
54677 + */
54678 + unsigned lpm_cap_en:1;
54679 + /** LPM response programmed by application (AppL1Res) (Device)
54680 + * Handshake response to LPM token pre-programmed
54681 + * by device application software.
54682 + */
54683 + unsigned appl_resp:1;
54684 + /** Host Initiated Resume Duration (HIRD) (Device and Host)
54685 + * In Host mode this field indicates the value of HIRD
54686 + * to be sent in an LPM transaction.
54687 + * In Device mode this field is updated with the
54688 + * Received LPM Token HIRD bmAttribute
54689 + * when an ACK/NYET/STALL response is sent
54690 + * to an LPM transaction.
54691 + */
54692 + unsigned hird:4;
54693 + /** RemoteWakeEnable (bRemoteWake) (Device and Host)
54694 + * In Host mode this bit indicates the value of remote
54695 + * wake up to be sent in wIndex field of LPM transaction.
54696 + * In Device mode this field is updated with the
54697 + * Received LPM Token bRemoteWake bmAttribute
54698 + * when an ACK/NYET/STALL response is sent
54699 + * to an LPM transaction.
54700 + */
54701 + unsigned rem_wkup_en:1;
54702 + /** Enable utmi_sleep_n (EnblSlpM) (Device and Host)
54703 + * The application uses this bit to control
54704 + * the utmi_sleep_n assertion to the PHY when in L1 state.
54705 + */
54706 + unsigned en_utmi_sleep:1;
54707 + /** HIRD Threshold (HIRD_Thres) (Device and Host)
54708 + */
54709 + unsigned hird_thres:5;
54710 + /** LPM Response (CoreL1Res) (Device and Host)
54711 + * In Host mode this bit contains handsake response to
54712 + * LPM transaction.
54713 + * In Device mode the response of the core to
54714 + * LPM transaction received is reflected in these two bits.
54715 + - 0x0 : ERROR (No handshake response)
54716 + - 0x1 : STALL
54717 + - 0x2 : NYET
54718 + - 0x3 : ACK
54719 + */
54720 + unsigned lpm_resp:2;
54721 + /** Port Sleep Status (SlpSts) (Device and Host)
54722 + * This bit is set as long as a Sleep condition
54723 + * is present on the USB bus.
54724 + */
54725 + unsigned prt_sleep_sts:1;
54726 + /** Sleep State Resume OK (L1ResumeOK) (Device and Host)
54727 + * Indicates that the application or host
54728 + * can start resume from Sleep state.
54729 + */
54730 + unsigned sleep_state_resumeok:1;
54731 + /** LPM channel Index (LPM_Chnl_Indx) (Host)
54732 + * The channel number on which the LPM transaction
54733 + * has to be applied while sending
54734 + * an LPM transaction to the local device.
54735 + */
54736 + unsigned lpm_chan_index:4;
54737 + /** LPM Retry Count (LPM_Retry_Cnt) (Host)
54738 + * Number host retries that would be performed
54739 + * if the device response was not valid response.
54740 + */
54741 + unsigned retry_count:3;
54742 + /** Send LPM Transaction (SndLPM) (Host)
54743 + * When set by application software,
54744 + * an LPM transaction containing two tokens
54745 + * is sent.
54746 + */
54747 + unsigned send_lpm:1;
54748 + /** LPM Retry status (LPM_RetryCnt_Sts) (Host)
54749 + * Number of LPM Host Retries still remaining
54750 + * to be transmitted for the current LPM sequence
54751 + */
54752 + unsigned retry_count_sts:3;
54753 + unsigned reserved28_29:2;
54754 + /** In host mode once this bit is set, the host
54755 + * configures to drive the HSIC Idle state on the bus.
54756 + * It then waits for the device to initiate the Connect sequence.
54757 + * In device mode once this bit is set, the device waits for
54758 + * the HSIC Idle line state on the bus. Upon receving the Idle
54759 + * line state, it initiates the HSIC Connect sequence.
54760 + */
54761 + unsigned hsic_connect:1;
54762 + /** This bit overrides and functionally inverts
54763 + * the if_select_hsic input port signal.
54764 + */
54765 + unsigned inv_sel_hsic:1;
54766 + } b;
54767 +} glpmcfg_data_t;
54768 +
54769 +/**
54770 + * This union represents the bit fields of the Core ADP Timer, Control and
54771 + * Status Register (ADPTIMCTLSTS). Set the bits using bit fields then write
54772 + * the <i>d32</i> value to the register.
54773 + */
54774 +typedef union adpctl_data {
54775 + /** raw register data */
54776 + uint32_t d32;
54777 + /** register bits */
54778 + struct {
54779 + /** Probe Discharge (PRB_DSCHG)
54780 + * These bits set the times for TADP_DSCHG.
54781 + * These bits are defined as follows:
54782 + * 2'b00 - 4 msec
54783 + * 2'b01 - 8 msec
54784 + * 2'b10 - 16 msec
54785 + * 2'b11 - 32 msec
54786 + */
54787 + unsigned prb_dschg:2;
54788 + /** Probe Delta (PRB_DELTA)
54789 + * These bits set the resolution for RTIM value.
54790 + * The bits are defined in units of 32 kHz clock cycles as follows:
54791 + * 2'b00 - 1 cycles
54792 + * 2'b01 - 2 cycles
54793 + * 2'b10 - 3 cycles
54794 + * 2'b11 - 4 cycles
54795 + * For example if this value is chosen to 2'b01, it means that RTIM
54796 + * increments for every 3(three) 32Khz clock cycles.
54797 + */
54798 + unsigned prb_delta:2;
54799 + /** Probe Period (PRB_PER)
54800 + * These bits sets the TADP_PRD as shown in Figure 4 as follows:
54801 + * 2'b00 - 0.625 to 0.925 sec (typical 0.775 sec)
54802 + * 2'b01 - 1.25 to 1.85 sec (typical 1.55 sec)
54803 + * 2'b10 - 1.9 to 2.6 sec (typical 2.275 sec)
54804 + * 2'b11 - Reserved
54805 + */
54806 + unsigned prb_per:2;
54807 + /** These bits capture the latest time it took for VBUS to ramp from
54808 + * VADP_SINK to VADP_PRB.
54809 + * 0x000 - 1 cycles
54810 + * 0x001 - 2 cycles
54811 + * 0x002 - 3 cycles
54812 + * etc
54813 + * 0x7FF - 2048 cycles
54814 + * A time of 1024 cycles at 32 kHz corresponds to a time of 32 msec.
54815 + */
54816 + unsigned rtim:11;
54817 + /** Enable Probe (EnaPrb)
54818 + * When programmed to 1'b1, the core performs a probe operation.
54819 + * This bit is valid only if OTG_Ver = 1'b1.
54820 + */
54821 + unsigned enaprb:1;
54822 + /** Enable Sense (EnaSns)
54823 + * When programmed to 1'b1, the core performs a Sense operation.
54824 + * This bit is valid only if OTG_Ver = 1'b1.
54825 + */
54826 + unsigned enasns:1;
54827 + /** ADP Reset (ADPRes)
54828 + * When set, ADP controller is reset.
54829 + * This bit is valid only if OTG_Ver = 1'b1.
54830 + */
54831 + unsigned adpres:1;
54832 + /** ADP Enable (ADPEn)
54833 + * When set, the core performs either ADP probing or sensing
54834 + * based on EnaPrb or EnaSns.
54835 + * This bit is valid only if OTG_Ver = 1'b1.
54836 + */
54837 + unsigned adpen:1;
54838 + /** ADP Probe Interrupt (ADP_PRB_INT)
54839 + * When this bit is set, it means that the VBUS
54840 + * voltage is greater than VADP_PRB or VADP_PRB is reached.
54841 + * This bit is valid only if OTG_Ver = 1'b1.
54842 + */
54843 + unsigned adp_prb_int:1;
54844 + /**
54845 + * ADP Sense Interrupt (ADP_SNS_INT)
54846 + * When this bit is set, it means that the VBUS voltage is greater than
54847 + * VADP_SNS value or VADP_SNS is reached.
54848 + * This bit is valid only if OTG_Ver = 1'b1.
54849 + */
54850 + unsigned adp_sns_int:1;
54851 + /** ADP Tomeout Interrupt (ADP_TMOUT_INT)
54852 + * This bit is relevant only for an ADP probe.
54853 + * When this bit is set, it means that the ramp time has
54854 + * completed ie ADPCTL.RTIM has reached its terminal value
54855 + * of 0x7FF. This is a debug feature that allows software
54856 + * to read the ramp time after each cycle.
54857 + * This bit is valid only if OTG_Ver = 1'b1.
54858 + */
54859 + unsigned adp_tmout_int:1;
54860 + /** ADP Probe Interrupt Mask (ADP_PRB_INT_MSK)
54861 + * When this bit is set, it unmasks the interrupt due to ADP_PRB_INT.
54862 + * This bit is valid only if OTG_Ver = 1'b1.
54863 + */
54864 + unsigned adp_prb_int_msk:1;
54865 + /** ADP Sense Interrupt Mask (ADP_SNS_INT_MSK)
54866 + * When this bit is set, it unmasks the interrupt due to ADP_SNS_INT.
54867 + * This bit is valid only if OTG_Ver = 1'b1.
54868 + */
54869 + unsigned adp_sns_int_msk:1;
54870 + /** ADP Timoeout Interrupt Mask (ADP_TMOUT_MSK)
54871 + * When this bit is set, it unmasks the interrupt due to ADP_TMOUT_INT.
54872 + * This bit is valid only if OTG_Ver = 1'b1.
54873 + */
54874 + unsigned adp_tmout_int_msk:1;
54875 + /** Access Request
54876 + * 2'b00 - Read/Write Valid (updated by the core)
54877 + * 2'b01 - Read
54878 + * 2'b00 - Write
54879 + * 2'b00 - Reserved
54880 + */
54881 + unsigned ar:2;
54882 + /** Reserved */
54883 + unsigned reserved29_31:3;
54884 + } b;
54885 +} adpctl_data_t;
54886 +
54887 +////////////////////////////////////////////
54888 +// Device Registers
54889 +/**
54890 + * Device Global Registers. <i>Offsets 800h-BFFh</i>
54891 + *
54892 + * The following structures define the size and relative field offsets
54893 + * for the Device Mode Registers.
54894 + *
54895 + * <i>These registers are visible only in Device mode and must not be
54896 + * accessed in Host mode, as the results are unknown.</i>
54897 + */
54898 +typedef struct dwc_otg_dev_global_regs {
54899 + /** Device Configuration Register. <i>Offset 800h</i> */
54900 + volatile uint32_t dcfg;
54901 + /** Device Control Register. <i>Offset: 804h</i> */
54902 + volatile uint32_t dctl;
54903 + /** Device Status Register (Read Only). <i>Offset: 808h</i> */
54904 + volatile uint32_t dsts;
54905 + /** Reserved. <i>Offset: 80Ch</i> */
54906 + uint32_t unused;
54907 + /** Device IN Endpoint Common Interrupt Mask
54908 + * Register. <i>Offset: 810h</i> */
54909 + volatile uint32_t diepmsk;
54910 + /** Device OUT Endpoint Common Interrupt Mask
54911 + * Register. <i>Offset: 814h</i> */
54912 + volatile uint32_t doepmsk;
54913 + /** Device All Endpoints Interrupt Register. <i>Offset: 818h</i> */
54914 + volatile uint32_t daint;
54915 + /** Device All Endpoints Interrupt Mask Register. <i>Offset:
54916 + * 81Ch</i> */
54917 + volatile uint32_t daintmsk;
54918 + /** Device IN Token Queue Read Register-1 (Read Only).
54919 + * <i>Offset: 820h</i> */
54920 + volatile uint32_t dtknqr1;
54921 + /** Device IN Token Queue Read Register-2 (Read Only).
54922 + * <i>Offset: 824h</i> */
54923 + volatile uint32_t dtknqr2;
54924 + /** Device VBUS discharge Register. <i>Offset: 828h</i> */
54925 + volatile uint32_t dvbusdis;
54926 + /** Device VBUS Pulse Register. <i>Offset: 82Ch</i> */
54927 + volatile uint32_t dvbuspulse;
54928 + /** Device IN Token Queue Read Register-3 (Read Only). /
54929 + * Device Thresholding control register (Read/Write)
54930 + * <i>Offset: 830h</i> */
54931 + volatile uint32_t dtknqr3_dthrctl;
54932 + /** Device IN Token Queue Read Register-4 (Read Only). /
54933 + * Device IN EPs empty Inr. Mask Register (Read/Write)
54934 + * <i>Offset: 834h</i> */
54935 + volatile uint32_t dtknqr4_fifoemptymsk;
54936 + /** Device Each Endpoint Interrupt Register (Read Only). /
54937 + * <i>Offset: 838h</i> */
54938 + volatile uint32_t deachint;
54939 + /** Device Each Endpoint Interrupt mask Register (Read/Write). /
54940 + * <i>Offset: 83Ch</i> */
54941 + volatile uint32_t deachintmsk;
54942 + /** Device Each In Endpoint Interrupt mask Register (Read/Write). /
54943 + * <i>Offset: 840h</i> */
54944 + volatile uint32_t diepeachintmsk[MAX_EPS_CHANNELS];
54945 + /** Device Each Out Endpoint Interrupt mask Register (Read/Write). /
54946 + * <i>Offset: 880h</i> */
54947 + volatile uint32_t doepeachintmsk[MAX_EPS_CHANNELS];
54948 +} dwc_otg_device_global_regs_t;
54949 +
54950 +/**
54951 + * This union represents the bit fields in the Device Configuration
54952 + * Register. Read the register into the <i>d32</i> member then
54953 + * set/clear the bits using the <i>b</i>it elements. Write the
54954 + * <i>d32</i> member to the dcfg register.
54955 + */
54956 +typedef union dcfg_data {
54957 + /** raw register data */
54958 + uint32_t d32;
54959 + /** register bits */
54960 + struct {
54961 + /** Device Speed */
54962 + unsigned devspd:2;
54963 + /** Non Zero Length Status OUT Handshake */
54964 + unsigned nzstsouthshk:1;
54965 +#define DWC_DCFG_SEND_STALL 1
54966 +
54967 + unsigned ena32khzs:1;
54968 + /** Device Addresses */
54969 + unsigned devaddr:7;
54970 + /** Periodic Frame Interval */
54971 + unsigned perfrint:2;
54972 +#define DWC_DCFG_FRAME_INTERVAL_80 0
54973 +#define DWC_DCFG_FRAME_INTERVAL_85 1
54974 +#define DWC_DCFG_FRAME_INTERVAL_90 2
54975 +#define DWC_DCFG_FRAME_INTERVAL_95 3
54976 +
54977 + /** Enable Device OUT NAK for bulk in DDMA mode */
54978 + unsigned endevoutnak:1;
54979 +
54980 + unsigned reserved14_17:4;
54981 + /** In Endpoint Mis-match count */
54982 + unsigned epmscnt:5;
54983 + /** Enable Descriptor DMA in Device mode */
54984 + unsigned descdma:1;
54985 + unsigned perschintvl:2;
54986 + unsigned resvalid:6;
54987 + } b;
54988 +} dcfg_data_t;
54989 +
54990 +/**
54991 + * This union represents the bit fields in the Device Control
54992 + * Register. Read the register into the <i>d32</i> member then
54993 + * set/clear the bits using the <i>b</i>it elements.
54994 + */
54995 +typedef union dctl_data {
54996 + /** raw register data */
54997 + uint32_t d32;
54998 + /** register bits */
54999 + struct {
55000 + /** Remote Wakeup */
55001 + unsigned rmtwkupsig:1;
55002 + /** Soft Disconnect */
55003 + unsigned sftdiscon:1;
55004 + /** Global Non-Periodic IN NAK Status */
55005 + unsigned gnpinnaksts:1;
55006 + /** Global OUT NAK Status */
55007 + unsigned goutnaksts:1;
55008 + /** Test Control */
55009 + unsigned tstctl:3;
55010 + /** Set Global Non-Periodic IN NAK */
55011 + unsigned sgnpinnak:1;
55012 + /** Clear Global Non-Periodic IN NAK */
55013 + unsigned cgnpinnak:1;
55014 + /** Set Global OUT NAK */
55015 + unsigned sgoutnak:1;
55016 + /** Clear Global OUT NAK */
55017 + unsigned cgoutnak:1;
55018 + /** Power-On Programming Done */
55019 + unsigned pwronprgdone:1;
55020 + /** Reserved */
55021 + unsigned reserved:1;
55022 + /** Global Multi Count */
55023 + unsigned gmc:2;
55024 + /** Ignore Frame Number for ISOC EPs */
55025 + unsigned ifrmnum:1;
55026 + /** NAK on Babble */
55027 + unsigned nakonbble:1;
55028 + /** Enable Continue on BNA */
55029 + unsigned encontonbna:1;
55030 +
55031 + unsigned reserved18_31:14;
55032 + } b;
55033 +} dctl_data_t;
55034 +
55035 +/**
55036 + * This union represents the bit fields in the Device Status
55037 + * Register. Read the register into the <i>d32</i> member then
55038 + * set/clear the bits using the <i>b</i>it elements.
55039 + */
55040 +typedef union dsts_data {
55041 + /** raw register data */
55042 + uint32_t d32;
55043 + /** register bits */
55044 + struct {
55045 + /** Suspend Status */
55046 + unsigned suspsts:1;
55047 + /** Enumerated Speed */
55048 + unsigned enumspd:2;
55049 +#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0
55050 +#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1
55051 +#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2
55052 +#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3
55053 + /** Erratic Error */
55054 + unsigned errticerr:1;
55055 + unsigned reserved4_7:4;
55056 + /** Frame or Microframe Number of the received SOF */
55057 + unsigned soffn:14;
55058 + unsigned reserved22_31:10;
55059 + } b;
55060 +} dsts_data_t;
55061 +
55062 +/**
55063 + * This union represents the bit fields in the Device IN EP Interrupt
55064 + * Register and the Device IN EP Common Mask Register.
55065 + *
55066 + * - Read the register into the <i>d32</i> member then set/clear the
55067 + * bits using the <i>b</i>it elements.
55068 + */
55069 +typedef union diepint_data {
55070 + /** raw register data */
55071 + uint32_t d32;
55072 + /** register bits */
55073 + struct {
55074 + /** Transfer complete mask */
55075 + unsigned xfercompl:1;
55076 + /** Endpoint disable mask */
55077 + unsigned epdisabled:1;
55078 + /** AHB Error mask */
55079 + unsigned ahberr:1;
55080 + /** TimeOUT Handshake mask (non-ISOC EPs) */
55081 + unsigned timeout:1;
55082 + /** IN Token received with TxF Empty mask */
55083 + unsigned intktxfemp:1;
55084 + /** IN Token Received with EP mismatch mask */
55085 + unsigned intknepmis:1;
55086 + /** IN Endpoint NAK Effective mask */
55087 + unsigned inepnakeff:1;
55088 + /** Reserved */
55089 + unsigned emptyintr:1;
55090 +
55091 + unsigned txfifoundrn:1;
55092 +
55093 + /** BNA Interrupt mask */
55094 + unsigned bna:1;
55095 +
55096 + unsigned reserved10_12:3;
55097 + /** BNA Interrupt mask */
55098 + unsigned nak:1;
55099 +
55100 + unsigned reserved14_31:18;
55101 + } b;
55102 +} diepint_data_t;
55103 +
55104 +/**
55105 + * This union represents the bit fields in the Device IN EP
55106 + * Common/Dedicated Interrupt Mask Register.
55107 + */
55108 +typedef union diepint_data diepmsk_data_t;
55109 +
55110 +/**
55111 + * This union represents the bit fields in the Device OUT EP Interrupt
55112 + * Registerand Device OUT EP Common Interrupt Mask Register.
55113 + *
55114 + * - Read the register into the <i>d32</i> member then set/clear the
55115 + * bits using the <i>b</i>it elements.
55116 + */
55117 +typedef union doepint_data {
55118 + /** raw register data */
55119 + uint32_t d32;
55120 + /** register bits */
55121 + struct {
55122 + /** Transfer complete */
55123 + unsigned xfercompl:1;
55124 + /** Endpoint disable */
55125 + unsigned epdisabled:1;
55126 + /** AHB Error */
55127 + unsigned ahberr:1;
55128 + /** Setup Phase Done (contorl EPs) */
55129 + unsigned setup:1;
55130 + /** OUT Token Received when Endpoint Disabled */
55131 + unsigned outtknepdis:1;
55132 +
55133 + unsigned stsphsercvd:1;
55134 + /** Back-to-Back SETUP Packets Received */
55135 + unsigned back2backsetup:1;
55136 +
55137 + unsigned reserved7:1;
55138 + /** OUT packet Error */
55139 + unsigned outpkterr:1;
55140 + /** BNA Interrupt */
55141 + unsigned bna:1;
55142 +
55143 + unsigned reserved10:1;
55144 + /** Packet Drop Status */
55145 + unsigned pktdrpsts:1;
55146 + /** Babble Interrupt */
55147 + unsigned babble:1;
55148 + /** NAK Interrupt */
55149 + unsigned nak:1;
55150 + /** NYET Interrupt */
55151 + unsigned nyet:1;
55152 + /** Bit indicating setup packet received */
55153 + unsigned sr:1;
55154 +
55155 + unsigned reserved16_31:16;
55156 + } b;
55157 +} doepint_data_t;
55158 +
55159 +/**
55160 + * This union represents the bit fields in the Device OUT EP
55161 + * Common/Dedicated Interrupt Mask Register.
55162 + */
55163 +typedef union doepint_data doepmsk_data_t;
55164 +
55165 +/**
55166 + * This union represents the bit fields in the Device All EP Interrupt
55167 + * and Mask Registers.
55168 + * - Read the register into the <i>d32</i> member then set/clear the
55169 + * bits using the <i>b</i>it elements.
55170 + */
55171 +typedef union daint_data {
55172 + /** raw register data */
55173 + uint32_t d32;
55174 + /** register bits */
55175 + struct {
55176 + /** IN Endpoint bits */
55177 + unsigned in:16;
55178 + /** OUT Endpoint bits */
55179 + unsigned out:16;
55180 + } ep;
55181 + struct {
55182 + /** IN Endpoint bits */
55183 + unsigned inep0:1;
55184 + unsigned inep1:1;
55185 + unsigned inep2:1;
55186 + unsigned inep3:1;
55187 + unsigned inep4:1;
55188 + unsigned inep5:1;
55189 + unsigned inep6:1;
55190 + unsigned inep7:1;
55191 + unsigned inep8:1;
55192 + unsigned inep9:1;
55193 + unsigned inep10:1;
55194 + unsigned inep11:1;
55195 + unsigned inep12:1;
55196 + unsigned inep13:1;
55197 + unsigned inep14:1;
55198 + unsigned inep15:1;
55199 + /** OUT Endpoint bits */
55200 + unsigned outep0:1;
55201 + unsigned outep1:1;
55202 + unsigned outep2:1;
55203 + unsigned outep3:1;
55204 + unsigned outep4:1;
55205 + unsigned outep5:1;
55206 + unsigned outep6:1;
55207 + unsigned outep7:1;
55208 + unsigned outep8:1;
55209 + unsigned outep9:1;
55210 + unsigned outep10:1;
55211 + unsigned outep11:1;
55212 + unsigned outep12:1;
55213 + unsigned outep13:1;
55214 + unsigned outep14:1;
55215 + unsigned outep15:1;
55216 + } b;
55217 +} daint_data_t;
55218 +
55219 +/**
55220 + * This union represents the bit fields in the Device IN Token Queue
55221 + * Read Registers.
55222 + * - Read the register into the <i>d32</i> member.
55223 + * - READ-ONLY Register
55224 + */
55225 +typedef union dtknq1_data {
55226 + /** raw register data */
55227 + uint32_t d32;
55228 + /** register bits */
55229 + struct {
55230 + /** In Token Queue Write Pointer */
55231 + unsigned intknwptr:5;
55232 + /** Reserved */
55233 + unsigned reserved05_06:2;
55234 + /** write pointer has wrapped. */
55235 + unsigned wrap_bit:1;
55236 + /** EP Numbers of IN Tokens 0 ... 4 */
55237 + unsigned epnums0_5:24;
55238 + } b;
55239 +} dtknq1_data_t;
55240 +
55241 +/**
55242 + * This union represents Threshold control Register
55243 + * - Read and write the register into the <i>d32</i> member.
55244 + * - READ-WRITABLE Register
55245 + */
55246 +typedef union dthrctl_data {
55247 + /** raw register data */
55248 + uint32_t d32;
55249 + /** register bits */
55250 + struct {
55251 + /** non ISO Tx Thr. Enable */
55252 + unsigned non_iso_thr_en:1;
55253 + /** ISO Tx Thr. Enable */
55254 + unsigned iso_thr_en:1;
55255 + /** Tx Thr. Length */
55256 + unsigned tx_thr_len:9;
55257 + /** AHB Threshold ratio */
55258 + unsigned ahb_thr_ratio:2;
55259 + /** Reserved */
55260 + unsigned reserved13_15:3;
55261 + /** Rx Thr. Enable */
55262 + unsigned rx_thr_en:1;
55263 + /** Rx Thr. Length */
55264 + unsigned rx_thr_len:9;
55265 + unsigned reserved26:1;
55266 + /** Arbiter Parking Enable*/
55267 + unsigned arbprken:1;
55268 + /** Reserved */
55269 + unsigned reserved28_31:4;
55270 + } b;
55271 +} dthrctl_data_t;
55272 +
55273 +/**
55274 + * Device Logical IN Endpoint-Specific Registers. <i>Offsets
55275 + * 900h-AFCh</i>
55276 + *
55277 + * There will be one set of endpoint registers per logical endpoint
55278 + * implemented.
55279 + *
55280 + * <i>These registers are visible only in Device mode and must not be
55281 + * accessed in Host mode, as the results are unknown.</i>
55282 + */
55283 +typedef struct dwc_otg_dev_in_ep_regs {
55284 + /** Device IN Endpoint Control Register. <i>Offset:900h +
55285 + * (ep_num * 20h) + 00h</i> */
55286 + volatile uint32_t diepctl;
55287 + /** Reserved. <i>Offset:900h + (ep_num * 20h) + 04h</i> */
55288 + uint32_t reserved04;
55289 + /** Device IN Endpoint Interrupt Register. <i>Offset:900h +
55290 + * (ep_num * 20h) + 08h</i> */
55291 + volatile uint32_t diepint;
55292 + /** Reserved. <i>Offset:900h + (ep_num * 20h) + 0Ch</i> */
55293 + uint32_t reserved0C;
55294 + /** Device IN Endpoint Transfer Size
55295 + * Register. <i>Offset:900h + (ep_num * 20h) + 10h</i> */
55296 + volatile uint32_t dieptsiz;
55297 + /** Device IN Endpoint DMA Address Register. <i>Offset:900h +
55298 + * (ep_num * 20h) + 14h</i> */
55299 + volatile uint32_t diepdma;
55300 + /** Device IN Endpoint Transmit FIFO Status Register. <i>Offset:900h +
55301 + * (ep_num * 20h) + 18h</i> */
55302 + volatile uint32_t dtxfsts;
55303 + /** Device IN Endpoint DMA Buffer Register. <i>Offset:900h +
55304 + * (ep_num * 20h) + 1Ch</i> */
55305 + volatile uint32_t diepdmab;
55306 +} dwc_otg_dev_in_ep_regs_t;
55307 +
55308 +/**
55309 + * Device Logical OUT Endpoint-Specific Registers. <i>Offsets:
55310 + * B00h-CFCh</i>
55311 + *
55312 + * There will be one set of endpoint registers per logical endpoint
55313 + * implemented.
55314 + *
55315 + * <i>These registers are visible only in Device mode and must not be
55316 + * accessed in Host mode, as the results are unknown.</i>
55317 + */
55318 +typedef struct dwc_otg_dev_out_ep_regs {
55319 + /** Device OUT Endpoint Control Register. <i>Offset:B00h +
55320 + * (ep_num * 20h) + 00h</i> */
55321 + volatile uint32_t doepctl;
55322 + /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 04h</i> */
55323 + uint32_t reserved04;
55324 + /** Device OUT Endpoint Interrupt Register. <i>Offset:B00h +
55325 + * (ep_num * 20h) + 08h</i> */
55326 + volatile uint32_t doepint;
55327 + /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 0Ch</i> */
55328 + uint32_t reserved0C;
55329 + /** Device OUT Endpoint Transfer Size Register. <i>Offset:
55330 + * B00h + (ep_num * 20h) + 10h</i> */
55331 + volatile uint32_t doeptsiz;
55332 + /** Device OUT Endpoint DMA Address Register. <i>Offset:B00h
55333 + * + (ep_num * 20h) + 14h</i> */
55334 + volatile uint32_t doepdma;
55335 + /** Reserved. <i>Offset:B00h + * (ep_num * 20h) + 18h</i> */
55336 + uint32_t unused;
55337 + /** Device OUT Endpoint DMA Buffer Register. <i>Offset:B00h
55338 + * + (ep_num * 20h) + 1Ch</i> */
55339 + uint32_t doepdmab;
55340 +} dwc_otg_dev_out_ep_regs_t;
55341 +
55342 +/**
55343 + * This union represents the bit fields in the Device EP Control
55344 + * Register. Read the register into the <i>d32</i> member then
55345 + * set/clear the bits using the <i>b</i>it elements.
55346 + */
55347 +typedef union depctl_data {
55348 + /** raw register data */
55349 + uint32_t d32;
55350 + /** register bits */
55351 + struct {
55352 + /** Maximum Packet Size
55353 + * IN/OUT EPn
55354 + * IN/OUT EP0 - 2 bits
55355 + * 2'b00: 64 Bytes
55356 + * 2'b01: 32
55357 + * 2'b10: 16
55358 + * 2'b11: 8 */
55359 + unsigned mps:11;
55360 +#define DWC_DEP0CTL_MPS_64 0
55361 +#define DWC_DEP0CTL_MPS_32 1
55362 +#define DWC_DEP0CTL_MPS_16 2
55363 +#define DWC_DEP0CTL_MPS_8 3
55364 +
55365 + /** Next Endpoint
55366 + * IN EPn/IN EP0
55367 + * OUT EPn/OUT EP0 - reserved */
55368 + unsigned nextep:4;
55369 +
55370 + /** USB Active Endpoint */
55371 + unsigned usbactep:1;
55372 +
55373 + /** Endpoint DPID (INTR/Bulk IN and OUT endpoints)
55374 + * This field contains the PID of the packet going to
55375 + * be received or transmitted on this endpoint. The
55376 + * application should program the PID of the first
55377 + * packet going to be received or transmitted on this
55378 + * endpoint , after the endpoint is
55379 + * activated. Application use the SetD1PID and
55380 + * SetD0PID fields of this register to program either
55381 + * D0 or D1 PID.
55382 + *
55383 + * The encoding for this field is
55384 + * - 0: D0
55385 + * - 1: D1
55386 + */
55387 + unsigned dpid:1;
55388 +
55389 + /** NAK Status */
55390 + unsigned naksts:1;
55391 +
55392 + /** Endpoint Type
55393 + * 2'b00: Control
55394 + * 2'b01: Isochronous
55395 + * 2'b10: Bulk
55396 + * 2'b11: Interrupt */
55397 + unsigned eptype:2;
55398 +
55399 + /** Snoop Mode
55400 + * OUT EPn/OUT EP0
55401 + * IN EPn/IN EP0 - reserved */
55402 + unsigned snp:1;
55403 +
55404 + /** Stall Handshake */
55405 + unsigned stall:1;
55406 +
55407 + /** Tx Fifo Number
55408 + * IN EPn/IN EP0
55409 + * OUT EPn/OUT EP0 - reserved */
55410 + unsigned txfnum:4;
55411 +
55412 + /** Clear NAK */
55413 + unsigned cnak:1;
55414 + /** Set NAK */
55415 + unsigned snak:1;
55416 + /** Set DATA0 PID (INTR/Bulk IN and OUT endpoints)
55417 + * Writing to this field sets the Endpoint DPID (DPID)
55418 + * field in this register to DATA0. Set Even
55419 + * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints)
55420 + * Writing to this field sets the Even/Odd
55421 + * (micro)frame (EO_FrNum) field to even (micro)
55422 + * frame.
55423 + */
55424 + unsigned setd0pid:1;
55425 + /** Set DATA1 PID (INTR/Bulk IN and OUT endpoints)
55426 + * Writing to this field sets the Endpoint DPID (DPID)
55427 + * field in this register to DATA1 Set Odd
55428 + * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints)
55429 + * Writing to this field sets the Even/Odd
55430 + * (micro)frame (EO_FrNum) field to odd (micro) frame.
55431 + */
55432 + unsigned setd1pid:1;
55433 +
55434 + /** Endpoint Disable */
55435 + unsigned epdis:1;
55436 + /** Endpoint Enable */
55437 + unsigned epena:1;
55438 + } b;
55439 +} depctl_data_t;
55440 +
55441 +/**
55442 + * This union represents the bit fields in the Device EP Transfer
55443 + * Size Register. Read the register into the <i>d32</i> member then
55444 + * set/clear the bits using the <i>b</i>it elements.
55445 + */
55446 +typedef union deptsiz_data {
55447 + /** raw register data */
55448 + uint32_t d32;
55449 + /** register bits */
55450 + struct {
55451 + /** Transfer size */
55452 + unsigned xfersize:19;
55453 +/** Max packet count for EP (pow(2,10)-1) */
55454 +#define MAX_PKT_CNT 1023
55455 + /** Packet Count */
55456 + unsigned pktcnt:10;
55457 + /** Multi Count - Periodic IN endpoints */
55458 + unsigned mc:2;
55459 + unsigned reserved:1;
55460 + } b;
55461 +} deptsiz_data_t;
55462 +
55463 +/**
55464 + * This union represents the bit fields in the Device EP 0 Transfer
55465 + * Size Register. Read the register into the <i>d32</i> member then
55466 + * set/clear the bits using the <i>b</i>it elements.
55467 + */
55468 +typedef union deptsiz0_data {
55469 + /** raw register data */
55470 + uint32_t d32;
55471 + /** register bits */
55472 + struct {
55473 + /** Transfer size */
55474 + unsigned xfersize:7;
55475 + /** Reserved */
55476 + unsigned reserved7_18:12;
55477 + /** Packet Count */
55478 + unsigned pktcnt:2;
55479 + /** Reserved */
55480 + unsigned reserved21_28:8;
55481 + /**Setup Packet Count (DOEPTSIZ0 Only) */
55482 + unsigned supcnt:2;
55483 + unsigned reserved31;
55484 + } b;
55485 +} deptsiz0_data_t;
55486 +
55487 +/////////////////////////////////////////////////
55488 +// DMA Descriptor Specific Structures
55489 +//
55490 +
55491 +/** Buffer status definitions */
55492 +
55493 +#define BS_HOST_READY 0x0
55494 +#define BS_DMA_BUSY 0x1
55495 +#define BS_DMA_DONE 0x2
55496 +#define BS_HOST_BUSY 0x3
55497 +
55498 +/** Receive/Transmit status definitions */
55499 +
55500 +#define RTS_SUCCESS 0x0
55501 +#define RTS_BUFFLUSH 0x1
55502 +#define RTS_RESERVED 0x2
55503 +#define RTS_BUFERR 0x3
55504 +
55505 +/**
55506 + * This union represents the bit fields in the DMA Descriptor
55507 + * status quadlet. Read the quadlet into the <i>d32</i> member then
55508 + * set/clear the bits using the <i>b</i>it, <i>b_iso_out</i> and
55509 + * <i>b_iso_in</i> elements.
55510 + */
55511 +typedef union dev_dma_desc_sts {
55512 + /** raw register data */
55513 + uint32_t d32;
55514 + /** quadlet bits */
55515 + struct {
55516 + /** Received number of bytes */
55517 + unsigned bytes:16;
55518 + /** NAK bit - only for OUT EPs */
55519 + unsigned nak:1;
55520 + unsigned reserved17_22:6;
55521 + /** Multiple Transfer - only for OUT EPs */
55522 + unsigned mtrf:1;
55523 + /** Setup Packet received - only for OUT EPs */
55524 + unsigned sr:1;
55525 + /** Interrupt On Complete */
55526 + unsigned ioc:1;
55527 + /** Short Packet */
55528 + unsigned sp:1;
55529 + /** Last */
55530 + unsigned l:1;
55531 + /** Receive Status */
55532 + unsigned sts:2;
55533 + /** Buffer Status */
55534 + unsigned bs:2;
55535 + } b;
55536 +
55537 +//#ifdef DWC_EN_ISOC
55538 + /** iso out quadlet bits */
55539 + struct {
55540 + /** Received number of bytes */
55541 + unsigned rxbytes:11;
55542 +
55543 + unsigned reserved11:1;
55544 + /** Frame Number */
55545 + unsigned framenum:11;
55546 + /** Received ISO Data PID */
55547 + unsigned pid:2;
55548 + /** Interrupt On Complete */
55549 + unsigned ioc:1;
55550 + /** Short Packet */
55551 + unsigned sp:1;
55552 + /** Last */
55553 + unsigned l:1;
55554 + /** Receive Status */
55555 + unsigned rxsts:2;
55556 + /** Buffer Status */
55557 + unsigned bs:2;
55558 + } b_iso_out;
55559 +
55560 + /** iso in quadlet bits */
55561 + struct {
55562 + /** Transmited number of bytes */
55563 + unsigned txbytes:12;
55564 + /** Frame Number */
55565 + unsigned framenum:11;
55566 + /** Transmited ISO Data PID */
55567 + unsigned pid:2;
55568 + /** Interrupt On Complete */
55569 + unsigned ioc:1;
55570 + /** Short Packet */
55571 + unsigned sp:1;
55572 + /** Last */
55573 + unsigned l:1;
55574 + /** Transmit Status */
55575 + unsigned txsts:2;
55576 + /** Buffer Status */
55577 + unsigned bs:2;
55578 + } b_iso_in;
55579 +//#endif /* DWC_EN_ISOC */
55580 +} dev_dma_desc_sts_t;
55581 +
55582 +/**
55583 + * DMA Descriptor structure
55584 + *
55585 + * DMA Descriptor structure contains two quadlets:
55586 + * Status quadlet and Data buffer pointer.
55587 + */
55588 +typedef struct dwc_otg_dev_dma_desc {
55589 + /** DMA Descriptor status quadlet */
55590 + dev_dma_desc_sts_t status;
55591 + /** DMA Descriptor data buffer pointer */
55592 + uint32_t buf;
55593 +} dwc_otg_dev_dma_desc_t;
55594 +
55595 +/**
55596 + * The dwc_otg_dev_if structure contains information needed to manage
55597 + * the DWC_otg controller acting in device mode. It represents the
55598 + * programming view of the device-specific aspects of the controller.
55599 + */
55600 +typedef struct dwc_otg_dev_if {
55601 + /** Pointer to device Global registers.
55602 + * Device Global Registers starting at offset 800h
55603 + */
55604 + dwc_otg_device_global_regs_t *dev_global_regs;
55605 +#define DWC_DEV_GLOBAL_REG_OFFSET 0x800
55606 +
55607 + /**
55608 + * Device Logical IN Endpoint-Specific Registers 900h-AFCh
55609 + */
55610 + dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS];
55611 +#define DWC_DEV_IN_EP_REG_OFFSET 0x900
55612 +#define DWC_EP_REG_OFFSET 0x20
55613 +
55614 + /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */
55615 + dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS];
55616 +#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00
55617 +
55618 + /* Device configuration information */
55619 + uint8_t speed; /**< Device Speed 0: Unknown, 1: LS, 2:FS, 3: HS */
55620 + uint8_t num_in_eps; /**< Number # of Tx EP range: 0-15 exept ep0 */
55621 + uint8_t num_out_eps; /**< Number # of Rx EP range: 0-15 exept ep 0*/
55622 +
55623 + /** Size of periodic FIFOs (Bytes) */
55624 + uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS];
55625 +
55626 + /** Size of Tx FIFOs (Bytes) */
55627 + uint16_t tx_fifo_size[MAX_TX_FIFOS];
55628 +
55629 + /** Thresholding enable flags and length varaiables **/
55630 + uint16_t rx_thr_en;
55631 + uint16_t iso_tx_thr_en;
55632 + uint16_t non_iso_tx_thr_en;
55633 +
55634 + uint16_t rx_thr_length;
55635 + uint16_t tx_thr_length;
55636 +
55637 + /**
55638 + * Pointers to the DMA Descriptors for EP0 Control
55639 + * transfers (virtual and physical)
55640 + */
55641 +
55642 + /** 2 descriptors for SETUP packets */
55643 + dwc_dma_t dma_setup_desc_addr[2];
55644 + dwc_otg_dev_dma_desc_t *setup_desc_addr[2];
55645 +
55646 + /** Pointer to Descriptor with latest SETUP packet */
55647 + dwc_otg_dev_dma_desc_t *psetup;
55648 +
55649 + /** Index of current SETUP handler descriptor */
55650 + uint32_t setup_desc_index;
55651 +
55652 + /** Descriptor for Data In or Status In phases */
55653 + dwc_dma_t dma_in_desc_addr;
55654 + dwc_otg_dev_dma_desc_t *in_desc_addr;
55655 +
55656 + /** Descriptor for Data Out or Status Out phases */
55657 + dwc_dma_t dma_out_desc_addr;
55658 + dwc_otg_dev_dma_desc_t *out_desc_addr;
55659 +
55660 + /** Setup Packet Detected - if set clear NAK when queueing */
55661 + uint32_t spd;
55662 + /** Isoc ep pointer on which incomplete happens */
55663 + void *isoc_ep;
55664 +
55665 +} dwc_otg_dev_if_t;
55666 +
55667 +/////////////////////////////////////////////////
55668 +// Host Mode Register Structures
55669 +//
55670 +/**
55671 + * The Host Global Registers structure defines the size and relative
55672 + * field offsets for the Host Mode Global Registers. Host Global
55673 + * Registers offsets 400h-7FFh.
55674 +*/
55675 +typedef struct dwc_otg_host_global_regs {
55676 + /** Host Configuration Register. <i>Offset: 400h</i> */
55677 + volatile uint32_t hcfg;
55678 + /** Host Frame Interval Register. <i>Offset: 404h</i> */
55679 + volatile uint32_t hfir;
55680 + /** Host Frame Number / Frame Remaining Register. <i>Offset: 408h</i> */
55681 + volatile uint32_t hfnum;
55682 + /** Reserved. <i>Offset: 40Ch</i> */
55683 + uint32_t reserved40C;
55684 + /** Host Periodic Transmit FIFO/ Queue Status Register. <i>Offset: 410h</i> */
55685 + volatile uint32_t hptxsts;
55686 + /** Host All Channels Interrupt Register. <i>Offset: 414h</i> */
55687 + volatile uint32_t haint;
55688 + /** Host All Channels Interrupt Mask Register. <i>Offset: 418h</i> */
55689 + volatile uint32_t haintmsk;
55690 + /** Host Frame List Base Address Register . <i>Offset: 41Ch</i> */
55691 + volatile uint32_t hflbaddr;
55692 +} dwc_otg_host_global_regs_t;
55693 +
55694 +/**
55695 + * This union represents the bit fields in the Host Configuration Register.
55696 + * Read the register into the <i>d32</i> member then set/clear the bits using
55697 + * the <i>b</i>it elements. Write the <i>d32</i> member to the hcfg register.
55698 + */
55699 +typedef union hcfg_data {
55700 + /** raw register data */
55701 + uint32_t d32;
55702 +
55703 + /** register bits */
55704 + struct {
55705 + /** FS/LS Phy Clock Select */
55706 + unsigned fslspclksel:2;
55707 +#define DWC_HCFG_30_60_MHZ 0
55708 +#define DWC_HCFG_48_MHZ 1
55709 +#define DWC_HCFG_6_MHZ 2
55710 +
55711 + /** FS/LS Only Support */
55712 + unsigned fslssupp:1;
55713 + unsigned reserved3_6:4;
55714 + /** Enable 32-KHz Suspend Mode */
55715 + unsigned ena32khzs:1;
55716 + /** Resume Validation Periiod */
55717 + unsigned resvalid:8;
55718 + unsigned reserved16_22:7;
55719 + /** Enable Scatter/gather DMA in Host mode */
55720 + unsigned descdma:1;
55721 + /** Frame List Entries */
55722 + unsigned frlisten:2;
55723 + /** Enable Periodic Scheduling */
55724 + unsigned perschedena:1;
55725 + unsigned reserved27_30:4;
55726 + unsigned modechtimen:1;
55727 + } b;
55728 +} hcfg_data_t;
55729 +
55730 +/**
55731 + * This union represents the bit fields in the Host Frame Remaing/Number
55732 + * Register.
55733 + */
55734 +typedef union hfir_data {
55735 + /** raw register data */
55736 + uint32_t d32;
55737 +
55738 + /** register bits */
55739 + struct {
55740 + unsigned frint:16;
55741 + unsigned hfirrldctrl:1;
55742 + unsigned reserved:15;
55743 + } b;
55744 +} hfir_data_t;
55745 +
55746 +/**
55747 + * This union represents the bit fields in the Host Frame Remaing/Number
55748 + * Register.
55749 + */
55750 +typedef union hfnum_data {
55751 + /** raw register data */
55752 + uint32_t d32;
55753 +
55754 + /** register bits */
55755 + struct {
55756 + unsigned frnum:16;
55757 +#define DWC_HFNUM_MAX_FRNUM 0x3FFF
55758 + unsigned frrem:16;
55759 + } b;
55760 +} hfnum_data_t;
55761 +
55762 +typedef union hptxsts_data {
55763 + /** raw register data */
55764 + uint32_t d32;
55765 +
55766 + /** register bits */
55767 + struct {
55768 + unsigned ptxfspcavail:16;
55769 + unsigned ptxqspcavail:8;
55770 + /** Top of the Periodic Transmit Request Queue
55771 + * - bit 24 - Terminate (last entry for the selected channel)
55772 + * - bits 26:25 - Token Type
55773 + * - 2'b00 - Zero length
55774 + * - 2'b01 - Ping
55775 + * - 2'b10 - Disable
55776 + * - bits 30:27 - Channel Number
55777 + * - bit 31 - Odd/even microframe
55778 + */
55779 + unsigned ptxqtop_terminate:1;
55780 + unsigned ptxqtop_token:2;
55781 + unsigned ptxqtop_chnum:4;
55782 + unsigned ptxqtop_odd:1;
55783 + } b;
55784 +} hptxsts_data_t;
55785 +
55786 +/**
55787 + * This union represents the bit fields in the Host Port Control and Status
55788 + * Register. Read the register into the <i>d32</i> member then set/clear the
55789 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
55790 + * hprt0 register.
55791 + */
55792 +typedef union hprt0_data {
55793 + /** raw register data */
55794 + uint32_t d32;
55795 + /** register bits */
55796 + struct {
55797 + unsigned prtconnsts:1;
55798 + unsigned prtconndet:1;
55799 + unsigned prtena:1;
55800 + unsigned prtenchng:1;
55801 + unsigned prtovrcurract:1;
55802 + unsigned prtovrcurrchng:1;
55803 + unsigned prtres:1;
55804 + unsigned prtsusp:1;
55805 + unsigned prtrst:1;
55806 + unsigned reserved9:1;
55807 + unsigned prtlnsts:2;
55808 + unsigned prtpwr:1;
55809 + unsigned prttstctl:4;
55810 + unsigned prtspd:2;
55811 +#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0
55812 +#define DWC_HPRT0_PRTSPD_FULL_SPEED 1
55813 +#define DWC_HPRT0_PRTSPD_LOW_SPEED 2
55814 + unsigned reserved19_31:13;
55815 + } b;
55816 +} hprt0_data_t;
55817 +
55818 +/**
55819 + * This union represents the bit fields in the Host All Interrupt
55820 + * Register.
55821 + */
55822 +typedef union haint_data {
55823 + /** raw register data */
55824 + uint32_t d32;
55825 + /** register bits */
55826 + struct {
55827 + unsigned ch0:1;
55828 + unsigned ch1:1;
55829 + unsigned ch2:1;
55830 + unsigned ch3:1;
55831 + unsigned ch4:1;
55832 + unsigned ch5:1;
55833 + unsigned ch6:1;
55834 + unsigned ch7:1;
55835 + unsigned ch8:1;
55836 + unsigned ch9:1;
55837 + unsigned ch10:1;
55838 + unsigned ch11:1;
55839 + unsigned ch12:1;
55840 + unsigned ch13:1;
55841 + unsigned ch14:1;
55842 + unsigned ch15:1;
55843 + unsigned reserved:16;
55844 + } b;
55845 +
55846 + struct {
55847 + unsigned chint:16;
55848 + unsigned reserved:16;
55849 + } b2;
55850 +} haint_data_t;
55851 +
55852 +/**
55853 + * This union represents the bit fields in the Host All Interrupt
55854 + * Register.
55855 + */
55856 +typedef union haintmsk_data {
55857 + /** raw register data */
55858 + uint32_t d32;
55859 + /** register bits */
55860 + struct {
55861 + unsigned ch0:1;
55862 + unsigned ch1:1;
55863 + unsigned ch2:1;
55864 + unsigned ch3:1;
55865 + unsigned ch4:1;
55866 + unsigned ch5:1;
55867 + unsigned ch6:1;
55868 + unsigned ch7:1;
55869 + unsigned ch8:1;
55870 + unsigned ch9:1;
55871 + unsigned ch10:1;
55872 + unsigned ch11:1;
55873 + unsigned ch12:1;
55874 + unsigned ch13:1;
55875 + unsigned ch14:1;
55876 + unsigned ch15:1;
55877 + unsigned reserved:16;
55878 + } b;
55879 +
55880 + struct {
55881 + unsigned chint:16;
55882 + unsigned reserved:16;
55883 + } b2;
55884 +} haintmsk_data_t;
55885 +
55886 +/**
55887 + * Host Channel Specific Registers. <i>500h-5FCh</i>
55888 + */
55889 +typedef struct dwc_otg_hc_regs {
55890 + /** Host Channel 0 Characteristic Register. <i>Offset: 500h + (chan_num * 20h) + 00h</i> */
55891 + volatile uint32_t hcchar;
55892 + /** Host Channel 0 Split Control Register. <i>Offset: 500h + (chan_num * 20h) + 04h</i> */
55893 + volatile uint32_t hcsplt;
55894 + /** Host Channel 0 Interrupt Register. <i>Offset: 500h + (chan_num * 20h) + 08h</i> */
55895 + volatile uint32_t hcint;
55896 + /** Host Channel 0 Interrupt Mask Register. <i>Offset: 500h + (chan_num * 20h) + 0Ch</i> */
55897 + volatile uint32_t hcintmsk;
55898 + /** Host Channel 0 Transfer Size Register. <i>Offset: 500h + (chan_num * 20h) + 10h</i> */
55899 + volatile uint32_t hctsiz;
55900 + /** Host Channel 0 DMA Address Register. <i>Offset: 500h + (chan_num * 20h) + 14h</i> */
55901 + volatile uint32_t hcdma;
55902 + volatile uint32_t reserved;
55903 + /** Host Channel 0 DMA Buffer Address Register. <i>Offset: 500h + (chan_num * 20h) + 1Ch</i> */
55904 + volatile uint32_t hcdmab;
55905 +} dwc_otg_hc_regs_t;
55906 +
55907 +/**
55908 + * This union represents the bit fields in the Host Channel Characteristics
55909 + * Register. Read the register into the <i>d32</i> member then set/clear the
55910 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
55911 + * hcchar register.
55912 + */
55913 +typedef union hcchar_data {
55914 + /** raw register data */
55915 + uint32_t d32;
55916 +
55917 + /** register bits */
55918 + struct {
55919 + /** Maximum packet size in bytes */
55920 + unsigned mps:11;
55921 +
55922 + /** Endpoint number */
55923 + unsigned epnum:4;
55924 +
55925 + /** 0: OUT, 1: IN */
55926 + unsigned epdir:1;
55927 +
55928 + unsigned reserved:1;
55929 +
55930 + /** 0: Full/high speed device, 1: Low speed device */
55931 + unsigned lspddev:1;
55932 +
55933 + /** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */
55934 + unsigned eptype:2;
55935 +
55936 + /** Packets per frame for periodic transfers. 0 is reserved. */
55937 + unsigned multicnt:2;
55938 +
55939 + /** Device address */
55940 + unsigned devaddr:7;
55941 +
55942 + /**
55943 + * Frame to transmit periodic transaction.
55944 + * 0: even, 1: odd
55945 + */
55946 + unsigned oddfrm:1;
55947 +
55948 + /** Channel disable */
55949 + unsigned chdis:1;
55950 +
55951 + /** Channel enable */
55952 + unsigned chen:1;
55953 + } b;
55954 +} hcchar_data_t;
55955 +
55956 +typedef union hcsplt_data {
55957 + /** raw register data */
55958 + uint32_t d32;
55959 +
55960 + /** register bits */
55961 + struct {
55962 + /** Port Address */
55963 + unsigned prtaddr:7;
55964 +
55965 + /** Hub Address */
55966 + unsigned hubaddr:7;
55967 +
55968 + /** Transaction Position */
55969 + unsigned xactpos:2;
55970 +#define DWC_HCSPLIT_XACTPOS_MID 0
55971 +#define DWC_HCSPLIT_XACTPOS_END 1
55972 +#define DWC_HCSPLIT_XACTPOS_BEGIN 2
55973 +#define DWC_HCSPLIT_XACTPOS_ALL 3
55974 +
55975 + /** Do Complete Split */
55976 + unsigned compsplt:1;
55977 +
55978 + /** Reserved */
55979 + unsigned reserved:14;
55980 +
55981 + /** Split Enble */
55982 + unsigned spltena:1;
55983 + } b;
55984 +} hcsplt_data_t;
55985 +
55986 +/**
55987 + * This union represents the bit fields in the Host All Interrupt
55988 + * Register.
55989 + */
55990 +typedef union hcint_data {
55991 + /** raw register data */
55992 + uint32_t d32;
55993 + /** register bits */
55994 + struct {
55995 + /** Transfer Complete */
55996 + unsigned xfercomp:1;
55997 + /** Channel Halted */
55998 + unsigned chhltd:1;
55999 + /** AHB Error */
56000 + unsigned ahberr:1;
56001 + /** STALL Response Received */
56002 + unsigned stall:1;
56003 + /** NAK Response Received */
56004 + unsigned nak:1;
56005 + /** ACK Response Received */
56006 + unsigned ack:1;
56007 + /** NYET Response Received */
56008 + unsigned nyet:1;
56009 + /** Transaction Err */
56010 + unsigned xacterr:1;
56011 + /** Babble Error */
56012 + unsigned bblerr:1;
56013 + /** Frame Overrun */
56014 + unsigned frmovrun:1;
56015 + /** Data Toggle Error */
56016 + unsigned datatglerr:1;
56017 + /** Buffer Not Available (only for DDMA mode) */
56018 + unsigned bna:1;
56019 + /** Exessive transaction error (only for DDMA mode) */
56020 + unsigned xcs_xact:1;
56021 + /** Frame List Rollover interrupt */
56022 + unsigned frm_list_roll:1;
56023 + /** Reserved */
56024 + unsigned reserved14_31:18;
56025 + } b;
56026 +} hcint_data_t;
56027 +
56028 +/**
56029 + * This union represents the bit fields in the Host Channel Interrupt Mask
56030 + * Register. Read the register into the <i>d32</i> member then set/clear the
56031 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
56032 + * hcintmsk register.
56033 + */
56034 +typedef union hcintmsk_data {
56035 + /** raw register data */
56036 + uint32_t d32;
56037 +
56038 + /** register bits */
56039 + struct {
56040 + unsigned xfercompl:1;
56041 + unsigned chhltd:1;
56042 + unsigned ahberr:1;
56043 + unsigned stall:1;
56044 + unsigned nak:1;
56045 + unsigned ack:1;
56046 + unsigned nyet:1;
56047 + unsigned xacterr:1;
56048 + unsigned bblerr:1;
56049 + unsigned frmovrun:1;
56050 + unsigned datatglerr:1;
56051 + unsigned bna:1;
56052 + unsigned xcs_xact:1;
56053 + unsigned frm_list_roll:1;
56054 + unsigned reserved14_31:18;
56055 + } b;
56056 +} hcintmsk_data_t;
56057 +
56058 +/**
56059 + * This union represents the bit fields in the Host Channel Transfer Size
56060 + * Register. Read the register into the <i>d32</i> member then set/clear the
56061 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
56062 + * hcchar register.
56063 + */
56064 +
56065 +typedef union hctsiz_data {
56066 + /** raw register data */
56067 + uint32_t d32;
56068 +
56069 + /** register bits */
56070 + struct {
56071 + /** Total transfer size in bytes */
56072 + unsigned xfersize:19;
56073 +
56074 + /** Data packets to transfer */
56075 + unsigned pktcnt:10;
56076 +
56077 + /**
56078 + * Packet ID for next data packet
56079 + * 0: DATA0
56080 + * 1: DATA2
56081 + * 2: DATA1
56082 + * 3: MDATA (non-Control), SETUP (Control)
56083 + */
56084 + unsigned pid:2;
56085 +#define DWC_HCTSIZ_DATA0 0
56086 +#define DWC_HCTSIZ_DATA1 2
56087 +#define DWC_HCTSIZ_DATA2 1
56088 +#define DWC_HCTSIZ_MDATA 3
56089 +#define DWC_HCTSIZ_SETUP 3
56090 +
56091 + /** Do PING protocol when 1 */
56092 + unsigned dopng:1;
56093 + } b;
56094 +
56095 + /** register bits */
56096 + struct {
56097 + /** Scheduling information */
56098 + unsigned schinfo:8;
56099 +
56100 + /** Number of transfer descriptors.
56101 + * Max value:
56102 + * 64 in general,
56103 + * 256 only for HS isochronous endpoint.
56104 + */
56105 + unsigned ntd:8;
56106 +
56107 + /** Data packets to transfer */
56108 + unsigned reserved16_28:13;
56109 +
56110 + /**
56111 + * Packet ID for next data packet
56112 + * 0: DATA0
56113 + * 1: DATA2
56114 + * 2: DATA1
56115 + * 3: MDATA (non-Control)
56116 + */
56117 + unsigned pid:2;
56118 +
56119 + /** Do PING protocol when 1 */
56120 + unsigned dopng:1;
56121 + } b_ddma;
56122 +} hctsiz_data_t;
56123 +
56124 +/**
56125 + * This union represents the bit fields in the Host DMA Address
56126 + * Register used in Descriptor DMA mode.
56127 + */
56128 +typedef union hcdma_data {
56129 + /** raw register data */
56130 + uint32_t d32;
56131 + /** register bits */
56132 + struct {
56133 + unsigned reserved0_2:3;
56134 + /** Current Transfer Descriptor. Not used for ISOC */
56135 + unsigned ctd:8;
56136 + /** Start Address of Descriptor List */
56137 + unsigned dma_addr:21;
56138 + } b;
56139 +} hcdma_data_t;
56140 +
56141 +/**
56142 + * This union represents the bit fields in the DMA Descriptor
56143 + * status quadlet for host mode. Read the quadlet into the <i>d32</i> member then
56144 + * set/clear the bits using the <i>b</i>it elements.
56145 + */
56146 +typedef union host_dma_desc_sts {
56147 + /** raw register data */
56148 + uint32_t d32;
56149 + /** quadlet bits */
56150 +
56151 + /* for non-isochronous */
56152 + struct {
56153 + /** Number of bytes */
56154 + unsigned n_bytes:17;
56155 + /** QTD offset to jump when Short Packet received - only for IN EPs */
56156 + unsigned qtd_offset:6;
56157 + /**
56158 + * Set to request the core to jump to alternate QTD if
56159 + * Short Packet received - only for IN EPs
56160 + */
56161 + unsigned a_qtd:1;
56162 + /**
56163 + * Setup Packet bit. When set indicates that buffer contains
56164 + * setup packet.
56165 + */
56166 + unsigned sup:1;
56167 + /** Interrupt On Complete */
56168 + unsigned ioc:1;
56169 + /** End of List */
56170 + unsigned eol:1;
56171 + unsigned reserved27:1;
56172 + /** Rx/Tx Status */
56173 + unsigned sts:2;
56174 +#define DMA_DESC_STS_PKTERR 1
56175 + unsigned reserved30:1;
56176 + /** Active Bit */
56177 + unsigned a:1;
56178 + } b;
56179 + /* for isochronous */
56180 + struct {
56181 + /** Number of bytes */
56182 + unsigned n_bytes:12;
56183 + unsigned reserved12_24:13;
56184 + /** Interrupt On Complete */
56185 + unsigned ioc:1;
56186 + unsigned reserved26_27:2;
56187 + /** Rx/Tx Status */
56188 + unsigned sts:2;
56189 + unsigned reserved30:1;
56190 + /** Active Bit */
56191 + unsigned a:1;
56192 + } b_isoc;
56193 +} host_dma_desc_sts_t;
56194 +
56195 +#define MAX_DMA_DESC_SIZE 131071
56196 +#define MAX_DMA_DESC_NUM_GENERIC 64
56197 +#define MAX_DMA_DESC_NUM_HS_ISOC 256
56198 +#define MAX_FRLIST_EN_NUM 64
56199 +/**
56200 + * Host-mode DMA Descriptor structure
56201 + *
56202 + * DMA Descriptor structure contains two quadlets:
56203 + * Status quadlet and Data buffer pointer.
56204 + */
56205 +typedef struct dwc_otg_host_dma_desc {
56206 + /** DMA Descriptor status quadlet */
56207 + host_dma_desc_sts_t status;
56208 + /** DMA Descriptor data buffer pointer */
56209 + uint32_t buf;
56210 +} dwc_otg_host_dma_desc_t;
56211 +
56212 +/** OTG Host Interface Structure.
56213 + *
56214 + * The OTG Host Interface Structure structure contains information
56215 + * needed to manage the DWC_otg controller acting in host mode. It
56216 + * represents the programming view of the host-specific aspects of the
56217 + * controller.
56218 + */
56219 +typedef struct dwc_otg_host_if {
56220 + /** Host Global Registers starting at offset 400h.*/
56221 + dwc_otg_host_global_regs_t *host_global_regs;
56222 +#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400
56223 +
56224 + /** Host Port 0 Control and Status Register */
56225 + volatile uint32_t *hprt0;
56226 +#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440
56227 +
56228 + /** Host Channel Specific Registers at offsets 500h-5FCh. */
56229 + dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS];
56230 +#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500
56231 +#define DWC_OTG_CHAN_REGS_OFFSET 0x20
56232 +
56233 + /* Host configuration information */
56234 + /** Number of Host Channels (range: 1-16) */
56235 + uint8_t num_host_channels;
56236 + /** Periodic EPs supported (0: no, 1: yes) */
56237 + uint8_t perio_eps_supported;
56238 + /** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */
56239 + uint16_t perio_tx_fifo_size;
56240 +
56241 +} dwc_otg_host_if_t;
56242 +
56243 +/**
56244 + * This union represents the bit fields in the Power and Clock Gating Control
56245 + * Register. Read the register into the <i>d32</i> member then set/clear the
56246 + * bits using the <i>b</i>it elements.
56247 + */
56248 +typedef union pcgcctl_data {
56249 + /** raw register data */
56250 + uint32_t d32;
56251 +
56252 + /** register bits */
56253 + struct {
56254 + /** Stop Pclk */
56255 + unsigned stoppclk:1;
56256 + /** Gate Hclk */
56257 + unsigned gatehclk:1;
56258 + /** Power Clamp */
56259 + unsigned pwrclmp:1;
56260 + /** Reset Power Down Modules */
56261 + unsigned rstpdwnmodule:1;
56262 + /** Reserved */
56263 + unsigned reserved:1;
56264 + /** Enable Sleep Clock Gating (Enbl_L1Gating) */
56265 + unsigned enbl_sleep_gating:1;
56266 + /** PHY In Sleep (PhySleep) */
56267 + unsigned phy_in_sleep:1;
56268 + /** Deep Sleep*/
56269 + unsigned deep_sleep:1;
56270 + unsigned resetaftsusp:1;
56271 + unsigned restoremode:1;
56272 + unsigned enbl_extnd_hiber:1;
56273 + unsigned extnd_hiber_pwrclmp:1;
56274 + unsigned extnd_hiber_switch:1;
56275 + unsigned ess_reg_restored:1;
56276 + unsigned prt_clk_sel:2;
56277 + unsigned port_power:1;
56278 + unsigned max_xcvrselect:2;
56279 + unsigned max_termsel:1;
56280 + unsigned mac_dev_addr:7;
56281 + unsigned p2hd_dev_enum_spd:2;
56282 + unsigned p2hd_prt_spd:2;
56283 + unsigned if_dev_mode:1;
56284 + } b;
56285 +} pcgcctl_data_t;
56286 +
56287 +/**
56288 + * This union represents the bit fields in the Global Data FIFO Software
56289 + * Configuration Register. Read the register into the <i>d32</i> member then
56290 + * set/clear the bits using the <i>b</i>it elements.
56291 + */
56292 +typedef union gdfifocfg_data {
56293 + /* raw register data */
56294 + uint32_t d32;
56295 + /** register bits */
56296 + struct {
56297 + /** OTG Data FIFO depth */
56298 + unsigned gdfifocfg:16;
56299 + /** Start address of EP info controller */
56300 + unsigned epinfobase:16;
56301 + } b;
56302 +} gdfifocfg_data_t;
56303 +
56304 +/**
56305 + * This union represents the bit fields in the Global Power Down Register
56306 + * Register. Read the register into the <i>d32</i> member then set/clear the
56307 + * bits using the <i>b</i>it elements.
56308 + */
56309 +typedef union gpwrdn_data {
56310 + /* raw register data */
56311 + uint32_t d32;
56312 +
56313 + /** register bits */
56314 + struct {
56315 + /** PMU Interrupt Select */
56316 + unsigned pmuintsel:1;
56317 + /** PMU Active */
56318 + unsigned pmuactv:1;
56319 + /** Restore */
56320 + unsigned restore:1;
56321 + /** Power Down Clamp */
56322 + unsigned pwrdnclmp:1;
56323 + /** Power Down Reset */
56324 + unsigned pwrdnrstn:1;
56325 + /** Power Down Switch */
56326 + unsigned pwrdnswtch:1;
56327 + /** Disable VBUS */
56328 + unsigned dis_vbus:1;
56329 + /** Line State Change */
56330 + unsigned lnstschng:1;
56331 + /** Line state change mask */
56332 + unsigned lnstchng_msk:1;
56333 + /** Reset Detected */
56334 + unsigned rst_det:1;
56335 + /** Reset Detect mask */
56336 + unsigned rst_det_msk:1;
56337 + /** Disconnect Detected */
56338 + unsigned disconn_det:1;
56339 + /** Disconnect Detect mask */
56340 + unsigned disconn_det_msk:1;
56341 + /** Connect Detected*/
56342 + unsigned connect_det:1;
56343 + /** Connect Detected Mask*/
56344 + unsigned connect_det_msk:1;
56345 + /** SRP Detected */
56346 + unsigned srp_det:1;
56347 + /** SRP Detect mask */
56348 + unsigned srp_det_msk:1;
56349 + /** Status Change Interrupt */
56350 + unsigned sts_chngint:1;
56351 + /** Status Change Interrupt Mask */
56352 + unsigned sts_chngint_msk:1;
56353 + /** Line State */
56354 + unsigned linestate:2;
56355 + /** Indicates current mode(status of IDDIG signal) */
56356 + unsigned idsts:1;
56357 + /** B Session Valid signal status*/
56358 + unsigned bsessvld:1;
56359 + /** ADP Event Detected */
56360 + unsigned adp_int:1;
56361 + /** Multi Valued ID pin */
56362 + unsigned mult_val_id_bc:5;
56363 + /** Reserved 24_31 */
56364 + unsigned reserved29_31:3;
56365 + } b;
56366 +} gpwrdn_data_t;
56367 +
56368 +#endif
56369 diff --git a/drivers/usb/host/dwc_otg/test/Makefile b/drivers/usb/host/dwc_otg/test/Makefile
56370 new file mode 100644
56371 index 0000000..fc45375
56372 --- /dev/null
56373 +++ b/drivers/usb/host/dwc_otg/test/Makefile
56374 @@ -0,0 +1,16 @@
56375 +
56376 +PERL=/usr/bin/perl
56377 +PL_TESTS=test_sysfs.pl test_mod_param.pl
56378 +
56379 +.PHONY : test
56380 +test : perl_tests
56381 +
56382 +perl_tests :
56383 + @echo
56384 + @echo Running perl tests
56385 + @for test in $(PL_TESTS); do \
56386 + if $(PERL) ./$$test ; then \
56387 + echo "=======> $$test, PASSED" ; \
56388 + else echo "=======> $$test, FAILED" ; \
56389 + fi \
56390 + done
56391 diff --git a/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm b/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
56392 new file mode 100644
56393 index 0000000..85e55fd
56394 --- /dev/null
56395 +++ b/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
56396 @@ -0,0 +1,337 @@
56397 +package dwc_otg_test;
56398 +
56399 +use strict;
56400 +use Exporter ();
56401 +
56402 +use vars qw(@ISA @EXPORT
56403 +$sysfsdir $paramdir $errors $params
56404 +);
56405 +
56406 +@ISA = qw(Exporter);
56407 +
56408 +#
56409 +# Globals
56410 +#
56411 +$sysfsdir = "/sys/devices/lm0";
56412 +$paramdir = "/sys/module/dwc_otg";
56413 +$errors = 0;
56414 +
56415 +$params = [
56416 + {
56417 + NAME => "otg_cap",
56418 + DEFAULT => 0,
56419 + ENUM => [],
56420 + LOW => 0,
56421 + HIGH => 2
56422 + },
56423 + {
56424 + NAME => "dma_enable",
56425 + DEFAULT => 0,
56426 + ENUM => [],
56427 + LOW => 0,
56428 + HIGH => 1
56429 + },
56430 + {
56431 + NAME => "dma_burst_size",
56432 + DEFAULT => 32,
56433 + ENUM => [1, 4, 8, 16, 32, 64, 128, 256],
56434 + LOW => 1,
56435 + HIGH => 256
56436 + },
56437 + {
56438 + NAME => "host_speed",
56439 + DEFAULT => 0,
56440 + ENUM => [],
56441 + LOW => 0,
56442 + HIGH => 1
56443 + },
56444 + {
56445 + NAME => "host_support_fs_ls_low_power",
56446 + DEFAULT => 0,
56447 + ENUM => [],
56448 + LOW => 0,
56449 + HIGH => 1
56450 + },
56451 + {
56452 + NAME => "host_ls_low_power_phy_clk",
56453 + DEFAULT => 0,
56454 + ENUM => [],
56455 + LOW => 0,
56456 + HIGH => 1
56457 + },
56458 + {
56459 + NAME => "dev_speed",
56460 + DEFAULT => 0,
56461 + ENUM => [],
56462 + LOW => 0,
56463 + HIGH => 1
56464 + },
56465 + {
56466 + NAME => "enable_dynamic_fifo",
56467 + DEFAULT => 1,
56468 + ENUM => [],
56469 + LOW => 0,
56470 + HIGH => 1
56471 + },
56472 + {
56473 + NAME => "data_fifo_size",
56474 + DEFAULT => 8192,
56475 + ENUM => [],
56476 + LOW => 32,
56477 + HIGH => 32768
56478 + },
56479 + {
56480 + NAME => "dev_rx_fifo_size",
56481 + DEFAULT => 1064,
56482 + ENUM => [],
56483 + LOW => 16,
56484 + HIGH => 32768
56485 + },
56486 + {
56487 + NAME => "dev_nperio_tx_fifo_size",
56488 + DEFAULT => 1024,
56489 + ENUM => [],
56490 + LOW => 16,
56491 + HIGH => 32768
56492 + },
56493 + {
56494 + NAME => "dev_perio_tx_fifo_size_1",
56495 + DEFAULT => 256,
56496 + ENUM => [],
56497 + LOW => 4,
56498 + HIGH => 768
56499 + },
56500 + {
56501 + NAME => "dev_perio_tx_fifo_size_2",
56502 + DEFAULT => 256,
56503 + ENUM => [],
56504 + LOW => 4,
56505 + HIGH => 768
56506 + },
56507 + {
56508 + NAME => "dev_perio_tx_fifo_size_3",
56509 + DEFAULT => 256,
56510 + ENUM => [],
56511 + LOW => 4,
56512 + HIGH => 768
56513 + },
56514 + {
56515 + NAME => "dev_perio_tx_fifo_size_4",
56516 + DEFAULT => 256,
56517 + ENUM => [],
56518 + LOW => 4,
56519 + HIGH => 768
56520 + },
56521 + {
56522 + NAME => "dev_perio_tx_fifo_size_5",
56523 + DEFAULT => 256,
56524 + ENUM => [],
56525 + LOW => 4,
56526 + HIGH => 768
56527 + },
56528 + {
56529 + NAME => "dev_perio_tx_fifo_size_6",
56530 + DEFAULT => 256,
56531 + ENUM => [],
56532 + LOW => 4,
56533 + HIGH => 768
56534 + },
56535 + {
56536 + NAME => "dev_perio_tx_fifo_size_7",
56537 + DEFAULT => 256,
56538 + ENUM => [],
56539 + LOW => 4,
56540 + HIGH => 768
56541 + },
56542 + {
56543 + NAME => "dev_perio_tx_fifo_size_8",
56544 + DEFAULT => 256,
56545 + ENUM => [],
56546 + LOW => 4,
56547 + HIGH => 768
56548 + },
56549 + {
56550 + NAME => "dev_perio_tx_fifo_size_9",
56551 + DEFAULT => 256,
56552 + ENUM => [],
56553 + LOW => 4,
56554 + HIGH => 768
56555 + },
56556 + {
56557 + NAME => "dev_perio_tx_fifo_size_10",
56558 + DEFAULT => 256,
56559 + ENUM => [],
56560 + LOW => 4,
56561 + HIGH => 768
56562 + },
56563 + {
56564 + NAME => "dev_perio_tx_fifo_size_11",
56565 + DEFAULT => 256,
56566 + ENUM => [],
56567 + LOW => 4,
56568 + HIGH => 768
56569 + },
56570 + {
56571 + NAME => "dev_perio_tx_fifo_size_12",
56572 + DEFAULT => 256,
56573 + ENUM => [],
56574 + LOW => 4,
56575 + HIGH => 768
56576 + },
56577 + {
56578 + NAME => "dev_perio_tx_fifo_size_13",
56579 + DEFAULT => 256,
56580 + ENUM => [],
56581 + LOW => 4,
56582 + HIGH => 768
56583 + },
56584 + {
56585 + NAME => "dev_perio_tx_fifo_size_14",
56586 + DEFAULT => 256,
56587 + ENUM => [],
56588 + LOW => 4,
56589 + HIGH => 768
56590 + },
56591 + {
56592 + NAME => "dev_perio_tx_fifo_size_15",
56593 + DEFAULT => 256,
56594 + ENUM => [],
56595 + LOW => 4,
56596 + HIGH => 768
56597 + },
56598 + {
56599 + NAME => "host_rx_fifo_size",
56600 + DEFAULT => 1024,
56601 + ENUM => [],
56602 + LOW => 16,
56603 + HIGH => 32768
56604 + },
56605 + {
56606 + NAME => "host_nperio_tx_fifo_size",
56607 + DEFAULT => 1024,
56608 + ENUM => [],
56609 + LOW => 16,
56610 + HIGH => 32768
56611 + },
56612 + {
56613 + NAME => "host_perio_tx_fifo_size",
56614 + DEFAULT => 1024,
56615 + ENUM => [],
56616 + LOW => 16,
56617 + HIGH => 32768
56618 + },
56619 + {
56620 + NAME => "max_transfer_size",
56621 + DEFAULT => 65535,
56622 + ENUM => [],
56623 + LOW => 2047,
56624 + HIGH => 65535
56625 + },
56626 + {
56627 + NAME => "max_packet_count",
56628 + DEFAULT => 511,
56629 + ENUM => [],
56630 + LOW => 15,
56631 + HIGH => 511
56632 + },
56633 + {
56634 + NAME => "host_channels",
56635 + DEFAULT => 12,
56636 + ENUM => [],
56637 + LOW => 1,
56638 + HIGH => 16
56639 + },
56640 + {
56641 + NAME => "dev_endpoints",
56642 + DEFAULT => 6,
56643 + ENUM => [],
56644 + LOW => 1,
56645 + HIGH => 15
56646 + },
56647 + {
56648 + NAME => "phy_type",
56649 + DEFAULT => 1,
56650 + ENUM => [],
56651 + LOW => 0,
56652 + HIGH => 2
56653 + },
56654 + {
56655 + NAME => "phy_utmi_width",
56656 + DEFAULT => 16,
56657 + ENUM => [8, 16],
56658 + LOW => 8,
56659 + HIGH => 16
56660 + },
56661 + {
56662 + NAME => "phy_ulpi_ddr",
56663 + DEFAULT => 0,
56664 + ENUM => [],
56665 + LOW => 0,
56666 + HIGH => 1
56667 + },
56668 + ];
56669 +
56670 +
56671 +#
56672 +#
56673 +sub check_arch {
56674 + $_ = `uname -m`;
56675 + chomp;
56676 + unless (m/armv4tl/) {
56677 + warn "# \n# Can't execute on $_. Run on integrator platform.\n# \n";
56678 + return 0;
56679 + }
56680 + return 1;
56681 +}
56682 +
56683 +#
56684 +#
56685 +sub load_module {
56686 + my $params = shift;
56687 + print "\nRemoving Module\n";
56688 + system "rmmod dwc_otg";
56689 + print "Loading Module\n";
56690 + if ($params ne "") {
56691 + print "Module Parameters: $params\n";
56692 + }
56693 + if (system("modprobe dwc_otg $params")) {
56694 + warn "Unable to load module\n";
56695 + return 0;
56696 + }
56697 + return 1;
56698 +}
56699 +
56700 +#
56701 +#
56702 +sub test_status {
56703 + my $arg = shift;
56704 +
56705 + print "\n";
56706 +
56707 + if (defined $arg) {
56708 + warn "WARNING: $arg\n";
56709 + }
56710 +
56711 + if ($errors > 0) {
56712 + warn "TEST FAILED with $errors errors\n";
56713 + return 0;
56714 + } else {
56715 + print "TEST PASSED\n";
56716 + return 0 if (defined $arg);
56717 + }
56718 + return 1;
56719 +}
56720 +
56721 +#
56722 +#
56723 +@EXPORT = qw(
56724 +$sysfsdir
56725 +$paramdir
56726 +$params
56727 +$errors
56728 +check_arch
56729 +load_module
56730 +test_status
56731 +);
56732 +
56733 +1;
56734 diff --git a/drivers/usb/host/dwc_otg/test/test_mod_param.pl b/drivers/usb/host/dwc_otg/test/test_mod_param.pl
56735 new file mode 100644
56736 index 0000000..dc3820d
56737 --- /dev/null
56738 +++ b/drivers/usb/host/dwc_otg/test/test_mod_param.pl
56739 @@ -0,0 +1,133 @@
56740 +#!/usr/bin/perl -w
56741 +#
56742 +# Run this program on the integrator.
56743 +#
56744 +# - Tests module parameter default values.
56745 +# - Tests setting of valid module parameter values via modprobe.
56746 +# - Tests invalid module parameter values.
56747 +# -----------------------------------------------------------------------------
56748 +use strict;
56749 +use dwc_otg_test;
56750 +
56751 +check_arch() or die;
56752 +
56753 +#
56754 +#
56755 +sub test {
56756 + my ($param,$expected) = @_;
56757 + my $value = get($param);
56758 +
56759 + if ($value == $expected) {
56760 + print "$param = $value, okay\n";
56761 + }
56762 +
56763 + else {
56764 + warn "ERROR: value of $param != $expected, $value\n";
56765 + $errors ++;
56766 + }
56767 +}
56768 +
56769 +#
56770 +#
56771 +sub get {
56772 + my $param = shift;
56773 + my $tmp = `cat $paramdir/$param`;
56774 + chomp $tmp;
56775 + return $tmp;
56776 +}
56777 +
56778 +#
56779 +#
56780 +sub test_main {
56781 +
56782 + print "\nTesting Module Parameters\n";
56783 +
56784 + load_module("") or die;
56785 +
56786 + # Test initial values
56787 + print "\nTesting Default Values\n";
56788 + foreach (@{$params}) {
56789 + test ($_->{NAME}, $_->{DEFAULT});
56790 + }
56791 +
56792 + # Test low value
56793 + print "\nTesting Low Value\n";
56794 + my $cmd_params = "";
56795 + foreach (@{$params}) {
56796 + $cmd_params = $cmd_params . "$_->{NAME}=$_->{LOW} ";
56797 + }
56798 + load_module($cmd_params) or die;
56799 +
56800 + foreach (@{$params}) {
56801 + test ($_->{NAME}, $_->{LOW});
56802 + }
56803 +
56804 + # Test high value
56805 + print "\nTesting High Value\n";
56806 + $cmd_params = "";
56807 + foreach (@{$params}) {
56808 + $cmd_params = $cmd_params . "$_->{NAME}=$_->{HIGH} ";
56809 + }
56810 + load_module($cmd_params) or die;
56811 +
56812 + foreach (@{$params}) {
56813 + test ($_->{NAME}, $_->{HIGH});
56814 + }
56815 +
56816 + # Test Enum
56817 + print "\nTesting Enumerated\n";
56818 + foreach (@{$params}) {
56819 + if (defined $_->{ENUM}) {
56820 + my $value;
56821 + foreach $value (@{$_->{ENUM}}) {
56822 + $cmd_params = "$_->{NAME}=$value";
56823 + load_module($cmd_params) or die;
56824 + test ($_->{NAME}, $value);
56825 + }
56826 + }
56827 + }
56828 +
56829 + # Test Invalid Values
56830 + print "\nTesting Invalid Values\n";
56831 + $cmd_params = "";
56832 + foreach (@{$params}) {
56833 + $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{LOW}-1;
56834 + }
56835 + load_module($cmd_params) or die;
56836 +
56837 + foreach (@{$params}) {
56838 + test ($_->{NAME}, $_->{DEFAULT});
56839 + }
56840 +
56841 + $cmd_params = "";
56842 + foreach (@{$params}) {
56843 + $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{HIGH}+1;
56844 + }
56845 + load_module($cmd_params) or die;
56846 +
56847 + foreach (@{$params}) {
56848 + test ($_->{NAME}, $_->{DEFAULT});
56849 + }
56850 +
56851 + print "\nTesting Enumerated\n";
56852 + foreach (@{$params}) {
56853 + if (defined $_->{ENUM}) {
56854 + my $value;
56855 + foreach $value (@{$_->{ENUM}}) {
56856 + $value = $value + 1;
56857 + $cmd_params = "$_->{NAME}=$value";
56858 + load_module($cmd_params) or die;
56859 + test ($_->{NAME}, $_->{DEFAULT});
56860 + $value = $value - 2;
56861 + $cmd_params = "$_->{NAME}=$value";
56862 + load_module($cmd_params) or die;
56863 + test ($_->{NAME}, $_->{DEFAULT});
56864 + }
56865 + }
56866 + }
56867 +
56868 + test_status() or die;
56869 +}
56870 +
56871 +test_main();
56872 +0;
56873 diff --git a/drivers/usb/host/dwc_otg/test/test_sysfs.pl b/drivers/usb/host/dwc_otg/test/test_sysfs.pl
56874 new file mode 100644
56875 index 0000000..cdc9963
56876 --- /dev/null
56877 +++ b/drivers/usb/host/dwc_otg/test/test_sysfs.pl
56878 @@ -0,0 +1,193 @@
56879 +#!/usr/bin/perl -w
56880 +#
56881 +# Run this program on the integrator
56882 +# - Tests select sysfs attributes.
56883 +# - Todo ... test more attributes, hnp/srp, buspower/bussuspend, etc.
56884 +# -----------------------------------------------------------------------------
56885 +use strict;
56886 +use dwc_otg_test;
56887 +
56888 +check_arch() or die;
56889 +
56890 +#
56891 +#
56892 +sub test {
56893 + my ($attr,$expected) = @_;
56894 + my $string = get($attr);
56895 +
56896 + if ($string eq $expected) {
56897 + printf("$attr = $string, okay\n");
56898 + }
56899 + else {
56900 + warn "ERROR: value of $attr != $expected, $string\n";
56901 + $errors ++;
56902 + }
56903 +}
56904 +
56905 +#
56906 +#
56907 +sub set {
56908 + my ($reg, $value) = @_;
56909 + system "echo $value > $sysfsdir/$reg";
56910 +}
56911 +
56912 +#
56913 +#
56914 +sub get {
56915 + my $attr = shift;
56916 + my $string = `cat $sysfsdir/$attr`;
56917 + chomp $string;
56918 + if ($string =~ m/\s\=\s/) {
56919 + my $tmp;
56920 + ($tmp, $string) = split /\s=\s/, $string;
56921 + }
56922 + return $string;
56923 +}
56924 +
56925 +#
56926 +#
56927 +sub test_main {
56928 + print("\nTesting Sysfs Attributes\n");
56929 +
56930 + load_module("") or die;
56931 +
56932 + # Test initial values of regoffset/regvalue/guid/gsnpsid
56933 + print("\nTesting Default Values\n");
56934 +
56935 + test("regoffset", "0xffffffff");
56936 + test("regvalue", "invalid offset");
56937 + test("guid", "0x12345678"); # this will fail if it has been changed
56938 + test("gsnpsid", "0x4f54200a");
56939 +
56940 + # Test operation of regoffset/regvalue
56941 + print("\nTesting regoffset\n");
56942 + set('regoffset', '5a5a5a5a');
56943 + test("regoffset", "0xffffffff");
56944 +
56945 + set('regoffset', '0');
56946 + test("regoffset", "0x00000000");
56947 +
56948 + set('regoffset', '40000');
56949 + test("regoffset", "0x00000000");
56950 +
56951 + set('regoffset', '3ffff');
56952 + test("regoffset", "0x0003ffff");
56953 +
56954 + set('regoffset', '1');
56955 + test("regoffset", "0x00000001");
56956 +
56957 + print("\nTesting regvalue\n");
56958 + set('regoffset', '3c');
56959 + test("regvalue", "0x12345678");
56960 + set('regvalue', '5a5a5a5a');
56961 + test("regvalue", "0x5a5a5a5a");
56962 + set('regvalue','a5a5a5a5');
56963 + test("regvalue", "0xa5a5a5a5");
56964 + set('guid','12345678');
56965 +
56966 + # Test HNP Capable
56967 + print("\nTesting HNP Capable bit\n");
56968 + set('hnpcapable', '1');
56969 + test("hnpcapable", "0x1");
56970 + set('hnpcapable','0');
56971 + test("hnpcapable", "0x0");
56972 +
56973 + set('regoffset','0c');
56974 +
56975 + my $old = get('gusbcfg');
56976 + print("setting hnpcapable\n");
56977 + set('hnpcapable', '1');
56978 + test("hnpcapable", "0x1");
56979 + test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<9)));
56980 + test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<9)));
56981 +
56982 + $old = get('gusbcfg');
56983 + print("clearing hnpcapable\n");
56984 + set('hnpcapable', '0');
56985 + test("hnpcapable", "0x0");
56986 + test ('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<9)));
56987 + test ('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<9)));
56988 +
56989 + # Test SRP Capable
56990 + print("\nTesting SRP Capable bit\n");
56991 + set('srpcapable', '1');
56992 + test("srpcapable", "0x1");
56993 + set('srpcapable','0');
56994 + test("srpcapable", "0x0");
56995 +
56996 + set('regoffset','0c');
56997 +
56998 + $old = get('gusbcfg');
56999 + print("setting srpcapable\n");
57000 + set('srpcapable', '1');
57001 + test("srpcapable", "0x1");
57002 + test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<8)));
57003 + test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<8)));
57004 +
57005 + $old = get('gusbcfg');
57006 + print("clearing srpcapable\n");
57007 + set('srpcapable', '0');
57008 + test("srpcapable", "0x0");
57009 + test('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<8)));
57010 + test('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<8)));
57011 +
57012 + # Test GGPIO
57013 + print("\nTesting GGPIO\n");
57014 + set('ggpio','5a5a5a5a');
57015 + test('ggpio','0x5a5a0000');
57016 + set('ggpio','a5a5a5a5');
57017 + test('ggpio','0xa5a50000');
57018 + set('ggpio','11110000');
57019 + test('ggpio','0x11110000');
57020 + set('ggpio','00001111');
57021 + test('ggpio','0x00000000');
57022 +
57023 + # Test DEVSPEED
57024 + print("\nTesting DEVSPEED\n");
57025 + set('regoffset','800');
57026 + $old = get('regvalue');
57027 + set('devspeed','0');
57028 + test('devspeed','0x0');
57029 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
57030 + set('devspeed','1');
57031 + test('devspeed','0x1');
57032 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
57033 + set('devspeed','2');
57034 + test('devspeed','0x2');
57035 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 2));
57036 + set('devspeed','3');
57037 + test('devspeed','0x3');
57038 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 3));
57039 + set('devspeed','4');
57040 + test('devspeed','0x0');
57041 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
57042 + set('devspeed','5');
57043 + test('devspeed','0x1');
57044 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
57045 +
57046 +
57047 + # mode Returns the current mode:0 for device mode1 for host mode Read
57048 + # hnp Initiate the Host Negotiation Protocol. Read returns the status. Read/Write
57049 + # srp Initiate the Session Request Protocol. Read returns the status. Read/Write
57050 + # buspower Get or Set the Power State of the bus (0 - Off or 1 - On) Read/Write
57051 + # bussuspend Suspend the USB bus. Read/Write
57052 + # busconnected Get the connection status of the bus Read
57053 +
57054 + # gotgctl Get or set the Core Control Status Register. Read/Write
57055 + ## gusbcfg Get or set the Core USB Configuration Register Read/Write
57056 + # grxfsiz Get or set the Receive FIFO Size Register Read/Write
57057 + # gnptxfsiz Get or set the non-periodic Transmit Size Register Read/Write
57058 + # gpvndctl Get or set the PHY Vendor Control Register Read/Write
57059 + ## ggpio Get the value in the lower 16-bits of the General Purpose IO Register or Set the upper 16 bits. Read/Write
57060 + ## guid Get or set the value of the User ID Register Read/Write
57061 + ## gsnpsid Get the value of the Synopsys ID Regester Read
57062 + ## devspeed Get or set the device speed setting in the DCFG register Read/Write
57063 + # enumspeed Gets the device enumeration Speed. Read
57064 + # hptxfsiz Get the value of the Host Periodic Transmit FIFO Read
57065 + # hprt0 Get or Set the value in the Host Port Control and Status Register Read/Write
57066 +
57067 + test_status("TEST NYI") or die;
57068 +}
57069 +
57070 +test_main();
57071 +0;
57072 --
57073 1.9.1
57074