kernel: update 3.10 to 3.10.2
[openwrt/openwrt.git] / target / linux / brcm2708 / patches-3.10 / 001-Add-dwc_otg-driver.patch
1 --- a/drivers/usb/core/generic.c
2 +++ b/drivers/usb/core/generic.c
3 @@ -152,6 +152,7 @@ int usb_choose_configuration(struct usb_
4 dev_warn(&udev->dev,
5 "no configuration chosen from %d choice%s\n",
6 num_configs, plural(num_configs));
7 + dev_warn(&udev->dev, "No support over %dmA\n", udev->bus_mA);
8 }
9 return i;
10 }
11 --- a/drivers/usb/core/message.c
12 +++ b/drivers/usb/core/message.c
13 @@ -1875,6 +1875,85 @@ free_interfaces:
14 if (cp->string == NULL &&
15 !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
16 cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
17 +/* Uncomment this define to enable the HS Electrical Test support */
18 +#define DWC_HS_ELECT_TST 1
19 +#ifdef DWC_HS_ELECT_TST
20 + /* Here we implement the HS Electrical Test support. The
21 + * tester uses a vendor ID of 0x1A0A to indicate we should
22 + * run a special test sequence. The product ID tells us
23 + * which sequence to run. We invoke the test sequence by
24 + * sending a non-standard SetFeature command to our root
25 + * hub port. Our dwc_otg_hcd_hub_control() routine will
26 + * recognize the command and perform the desired test
27 + * sequence.
28 + */
29 + if (dev->descriptor.idVendor == 0x1A0A) {
30 + /* HSOTG Electrical Test */
31 + dev_warn(&dev->dev, "VID from HSOTG Electrical Test Fixture\n");
32 +
33 + if (dev->bus && dev->bus->root_hub) {
34 + struct usb_device *hdev = dev->bus->root_hub;
35 + dev_warn(&dev->dev, "Got PID 0x%x\n", dev->descriptor.idProduct);
36 +
37 + switch (dev->descriptor.idProduct) {
38 + case 0x0101: /* TEST_SE0_NAK */
39 + dev_warn(&dev->dev, "TEST_SE0_NAK\n");
40 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
41 + USB_REQ_SET_FEATURE, USB_RT_PORT,
42 + USB_PORT_FEAT_TEST, 0x300, NULL, 0, HZ);
43 + break;
44 +
45 + case 0x0102: /* TEST_J */
46 + dev_warn(&dev->dev, "TEST_J\n");
47 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
48 + USB_REQ_SET_FEATURE, USB_RT_PORT,
49 + USB_PORT_FEAT_TEST, 0x100, NULL, 0, HZ);
50 + break;
51 +
52 + case 0x0103: /* TEST_K */
53 + dev_warn(&dev->dev, "TEST_K\n");
54 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
55 + USB_REQ_SET_FEATURE, USB_RT_PORT,
56 + USB_PORT_FEAT_TEST, 0x200, NULL, 0, HZ);
57 + break;
58 +
59 + case 0x0104: /* TEST_PACKET */
60 + dev_warn(&dev->dev, "TEST_PACKET\n");
61 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
62 + USB_REQ_SET_FEATURE, USB_RT_PORT,
63 + USB_PORT_FEAT_TEST, 0x400, NULL, 0, HZ);
64 + break;
65 +
66 + case 0x0105: /* TEST_FORCE_ENABLE */
67 + dev_warn(&dev->dev, "TEST_FORCE_ENABLE\n");
68 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
69 + USB_REQ_SET_FEATURE, USB_RT_PORT,
70 + USB_PORT_FEAT_TEST, 0x500, NULL, 0, HZ);
71 + break;
72 +
73 + case 0x0106: /* HS_HOST_PORT_SUSPEND_RESUME */
74 + dev_warn(&dev->dev, "HS_HOST_PORT_SUSPEND_RESUME\n");
75 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
76 + USB_REQ_SET_FEATURE, USB_RT_PORT,
77 + USB_PORT_FEAT_TEST, 0x600, NULL, 0, 40 * HZ);
78 + break;
79 +
80 + case 0x0107: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
81 + dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup\n");
82 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
83 + USB_REQ_SET_FEATURE, USB_RT_PORT,
84 + USB_PORT_FEAT_TEST, 0x700, NULL, 0, 40 * HZ);
85 + break;
86 +
87 + case 0x0108: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
88 + dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute\n");
89 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
90 + USB_REQ_SET_FEATURE, USB_RT_PORT,
91 + USB_PORT_FEAT_TEST, 0x800, NULL, 0, 40 * HZ);
92 + }
93 + }
94 + }
95 +#endif /* DWC_HS_ELECT_TST */
96
97 /* Now that the interfaces are installed, re-enable LPM. */
98 usb_unlocked_enable_lpm(dev);
99 --- a/drivers/usb/core/otg_whitelist.h
100 +++ b/drivers/usb/core/otg_whitelist.h
101 @@ -19,33 +19,82 @@
102 static struct usb_device_id whitelist_table [] = {
103
104 /* hubs are optional in OTG, but very handy ... */
105 +#define CERT_WITHOUT_HUBS
106 +#if defined(CERT_WITHOUT_HUBS)
107 +{ USB_DEVICE( 0x0000, 0x0000 ), }, /* Root HUB Only*/
108 +#else
109 { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
110 { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
111 +{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 2), },
112 +#endif
113
114 #ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */
115 /* FIXME actually, printers are NOT supposed to use device classes;
116 * they're supposed to use interface classes...
117 */
118 -{ USB_DEVICE_INFO(7, 1, 1) },
119 -{ USB_DEVICE_INFO(7, 1, 2) },
120 -{ USB_DEVICE_INFO(7, 1, 3) },
121 +//{ USB_DEVICE_INFO(7, 1, 1) },
122 +//{ USB_DEVICE_INFO(7, 1, 2) },
123 +//{ USB_DEVICE_INFO(7, 1, 3) },
124 #endif
125
126 #ifdef CONFIG_USB_NET_CDCETHER
127 /* Linux-USB CDC Ethernet gadget */
128 -{ USB_DEVICE(0x0525, 0xa4a1), },
129 +//{ USB_DEVICE(0x0525, 0xa4a1), },
130 /* Linux-USB CDC Ethernet + RNDIS gadget */
131 -{ USB_DEVICE(0x0525, 0xa4a2), },
132 +//{ USB_DEVICE(0x0525, 0xa4a2), },
133 #endif
134
135 #if defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE)
136 /* gadget zero, for testing */
137 -{ USB_DEVICE(0x0525, 0xa4a0), },
138 +//{ USB_DEVICE(0x0525, 0xa4a0), },
139 #endif
140 +
141 +/* OPT Tester */
142 +{ USB_DEVICE( 0x1a0a, 0x0101 ), }, /* TEST_SE0_NAK */
143 +{ USB_DEVICE( 0x1a0a, 0x0102 ), }, /* Test_J */
144 +{ USB_DEVICE( 0x1a0a, 0x0103 ), }, /* Test_K */
145 +{ USB_DEVICE( 0x1a0a, 0x0104 ), }, /* Test_PACKET */
146 +{ USB_DEVICE( 0x1a0a, 0x0105 ), }, /* Test_FORCE_ENABLE */
147 +{ USB_DEVICE( 0x1a0a, 0x0106 ), }, /* HS_PORT_SUSPEND_RESUME */
148 +{ USB_DEVICE( 0x1a0a, 0x0107 ), }, /* SINGLE_STEP_GET_DESCRIPTOR setup */
149 +{ USB_DEVICE( 0x1a0a, 0x0108 ), }, /* SINGLE_STEP_GET_DESCRIPTOR execute */
150 +
151 +/* Sony cameras */
152 +{ USB_DEVICE_VER(0x054c,0x0010,0x0410, 0x0500), },
153 +
154 +/* Memory Devices */
155 +//{ USB_DEVICE( 0x0781, 0x5150 ), }, /* SanDisk */
156 +//{ USB_DEVICE( 0x05DC, 0x0080 ), }, /* Lexar */
157 +//{ USB_DEVICE( 0x4146, 0x9281 ), }, /* IOMEGA */
158 +//{ USB_DEVICE( 0x067b, 0x2507 ), }, /* Hammer 20GB External HD */
159 +{ USB_DEVICE( 0x0EA0, 0x2168 ), }, /* Ours Technology Inc. (BUFFALO ClipDrive)*/
160 +//{ USB_DEVICE( 0x0457, 0x0150 ), }, /* Silicon Integrated Systems Corp. */
161 +
162 +/* HP Printers */
163 +//{ USB_DEVICE( 0x03F0, 0x1102 ), }, /* HP Photosmart 245 */
164 +//{ USB_DEVICE( 0x03F0, 0x1302 ), }, /* HP Photosmart 370 Series */
165 +
166 +/* Speakers */
167 +//{ USB_DEVICE( 0x0499, 0x3002 ), }, /* YAMAHA YST-MS35D USB Speakers */
168 +//{ USB_DEVICE( 0x0672, 0x1041 ), }, /* Labtec USB Headset */
169
170 { } /* Terminating entry */
171 };
172
173 +static inline void report_errors(struct usb_device *dev)
174 +{
175 + /* OTG MESSAGE: report errors here, customize to match your product */
176 + dev_info(&dev->dev, "device Vendor:%04x Product:%04x is not supported\n",
177 + le16_to_cpu(dev->descriptor.idVendor),
178 + le16_to_cpu(dev->descriptor.idProduct));
179 + if (USB_CLASS_HUB == dev->descriptor.bDeviceClass){
180 + dev_printk(KERN_CRIT, &dev->dev, "Unsupported Hub Topology\n");
181 + } else {
182 + dev_printk(KERN_CRIT, &dev->dev, "Attached Device is not Supported\n");
183 + }
184 +}
185 +
186 +
187 static int is_targeted(struct usb_device *dev)
188 {
189 struct usb_device_id *id = whitelist_table;
190 @@ -55,58 +104,83 @@ static int is_targeted(struct usb_device
191 return 1;
192
193 /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */
194 - if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
195 - le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
196 - return 0;
197 + if (dev->descriptor.idVendor == 0x1a0a &&
198 + dev->descriptor.idProduct == 0xbadd) {
199 + return 0;
200 + } else if (!enable_whitelist) {
201 + return 1;
202 + } else {
203
204 - /* NOTE: can't use usb_match_id() since interface caches
205 - * aren't set up yet. this is cut/paste from that code.
206 - */
207 - for (id = whitelist_table; id->match_flags; id++) {
208 - if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
209 - id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
210 - continue;
211 -
212 - if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
213 - id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
214 - continue;
215 -
216 - /* No need to test id->bcdDevice_lo != 0, since 0 is never
217 - greater than any unsigned number. */
218 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
219 - (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
220 - continue;
221 -
222 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
223 - (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
224 - continue;
225 -
226 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
227 - (id->bDeviceClass != dev->descriptor.bDeviceClass))
228 - continue;
229 -
230 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
231 - (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
232 - continue;
233 -
234 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
235 - (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
236 - continue;
237 +#ifdef DEBUG
238 + dev_dbg(&dev->dev, "device V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
239 + dev->descriptor.idVendor,
240 + dev->descriptor.idProduct,
241 + dev->descriptor.bDeviceClass,
242 + dev->descriptor.bDeviceSubClass,
243 + dev->descriptor.bDeviceProtocol);
244 +#endif
245
246 return 1;
247 + /* NOTE: can't use usb_match_id() since interface caches
248 + * aren't set up yet. this is cut/paste from that code.
249 + */
250 + for (id = whitelist_table; id->match_flags; id++) {
251 +#ifdef DEBUG
252 + dev_dbg(&dev->dev,
253 + "ID: V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
254 + id->idVendor,
255 + id->idProduct,
256 + id->bDeviceClass,
257 + id->bDeviceSubClass,
258 + id->bDeviceProtocol);
259 +#endif
260 +
261 + if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
262 + id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
263 + continue;
264 +
265 + if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
266 + id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
267 + continue;
268 +
269 + /* No need to test id->bcdDevice_lo != 0, since 0 is never
270 + greater than any unsigned number. */
271 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
272 + (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
273 + continue;
274 +
275 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
276 + (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
277 + continue;
278 +
279 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
280 + (id->bDeviceClass != dev->descriptor.bDeviceClass))
281 + continue;
282 +
283 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
284 + (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
285 + continue;
286 +
287 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
288 + (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
289 + continue;
290 +
291 + return 1;
292 + }
293 }
294
295 /* add other match criteria here ... */
296
297 -
298 - /* OTG MESSAGE: report errors here, customize to match your product */
299 - dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
300 - le16_to_cpu(dev->descriptor.idVendor),
301 - le16_to_cpu(dev->descriptor.idProduct));
302 #ifdef CONFIG_USB_OTG_WHITELIST
303 + report_errors(dev);
304 return 0;
305 #else
306 - return 1;
307 + if (enable_whitelist) {
308 + report_errors(dev);
309 + return 0;
310 + } else {
311 + return 1;
312 + }
313 #endif
314 }
315
316 --- /dev/null
317 +++ b/drivers/usb/gadget/file_storage.c
318 @@ -0,0 +1,3676 @@
319 +/*
320 + * file_storage.c -- File-backed USB Storage Gadget, for USB development
321 + *
322 + * Copyright (C) 2003-2008 Alan Stern
323 + * All rights reserved.
324 + *
325 + * Redistribution and use in source and binary forms, with or without
326 + * modification, are permitted provided that the following conditions
327 + * are met:
328 + * 1. Redistributions of source code must retain the above copyright
329 + * notice, this list of conditions, and the following disclaimer,
330 + * without modification.
331 + * 2. Redistributions in binary form must reproduce the above copyright
332 + * notice, this list of conditions and the following disclaimer in the
333 + * documentation and/or other materials provided with the distribution.
334 + * 3. The names of the above-listed copyright holders may not be used
335 + * to endorse or promote products derived from this software without
336 + * specific prior written permission.
337 + *
338 + * ALTERNATIVELY, this software may be distributed under the terms of the
339 + * GNU General Public License ("GPL") as published by the Free Software
340 + * Foundation, either version 2 of that License or (at your option) any
341 + * later version.
342 + *
343 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
344 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
345 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
346 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
347 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
348 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
349 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
350 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
351 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
352 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
353 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
354 + */
355 +
356 +
357 +/*
358 + * The File-backed Storage Gadget acts as a USB Mass Storage device,
359 + * appearing to the host as a disk drive or as a CD-ROM drive. In addition
360 + * to providing an example of a genuinely useful gadget driver for a USB
361 + * device, it also illustrates a technique of double-buffering for increased
362 + * throughput. Last but not least, it gives an easy way to probe the
363 + * behavior of the Mass Storage drivers in a USB host.
364 + *
365 + * Backing storage is provided by a regular file or a block device, specified
366 + * by the "file" module parameter. Access can be limited to read-only by
367 + * setting the optional "ro" module parameter. (For CD-ROM emulation,
368 + * access is always read-only.) The gadget will indicate that it has
369 + * removable media if the optional "removable" module parameter is set.
370 + *
371 + * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI),
372 + * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected
373 + * by the optional "transport" module parameter. It also supports the
374 + * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03),
375 + * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by
376 + * the optional "protocol" module parameter. In addition, the default
377 + * Vendor ID, Product ID, release number and serial number can be overridden.
378 + *
379 + * There is support for multiple logical units (LUNs), each of which has
380 + * its own backing file. The number of LUNs can be set using the optional
381 + * "luns" module parameter (anywhere from 1 to 8), and the corresponding
382 + * files are specified using comma-separated lists for "file" and "ro".
383 + * The default number of LUNs is taken from the number of "file" elements;
384 + * it is 1 if "file" is not given. If "removable" is not set then a backing
385 + * file must be specified for each LUN. If it is set, then an unspecified
386 + * or empty backing filename means the LUN's medium is not loaded. Ideally
387 + * each LUN would be settable independently as a disk drive or a CD-ROM
388 + * drive, but currently all LUNs have to be the same type. The CD-ROM
389 + * emulation includes a single data track and no audio tracks; hence there
390 + * need be only one backing file per LUN.
391 + *
392 + * Requirements are modest; only a bulk-in and a bulk-out endpoint are
393 + * needed (an interrupt-out endpoint is also needed for CBI). The memory
394 + * requirement amounts to two 16K buffers, size configurable by a parameter.
395 + * Support is included for both full-speed and high-speed operation.
396 + *
397 + * Note that the driver is slightly non-portable in that it assumes a
398 + * single memory/DMA buffer will be useable for bulk-in, bulk-out, and
399 + * interrupt-in endpoints. With most device controllers this isn't an
400 + * issue, but there may be some with hardware restrictions that prevent
401 + * a buffer from being used by more than one endpoint.
402 + *
403 + * Module options:
404 + *
405 + * file=filename[,filename...]
406 + * Required if "removable" is not set, names of
407 + * the files or block devices used for
408 + * backing storage
409 + * serial=HHHH... Required serial number (string of hex chars)
410 + * ro=b[,b...] Default false, booleans for read-only access
411 + * removable Default false, boolean for removable media
412 + * luns=N Default N = number of filenames, number of
413 + * LUNs to support
414 + * nofua=b[,b...] Default false, booleans for ignore FUA flag
415 + * in SCSI WRITE(10,12) commands
416 + * stall Default determined according to the type of
417 + * USB device controller (usually true),
418 + * boolean to permit the driver to halt
419 + * bulk endpoints
420 + * cdrom Default false, boolean for whether to emulate
421 + * a CD-ROM drive
422 + * transport=XXX Default BBB, transport name (CB, CBI, or BBB)
423 + * protocol=YYY Default SCSI, protocol name (RBC, 8020 or
424 + * ATAPI, QIC, UFI, 8070, or SCSI;
425 + * also 1 - 6)
426 + * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID
427 + * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID
428 + * release=0xRRRR Override the USB release number (bcdDevice)
429 + * buflen=N Default N=16384, buffer size used (will be
430 + * rounded down to a multiple of
431 + * PAGE_CACHE_SIZE)
432 + *
433 + * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro",
434 + * "removable", "luns", "nofua", "stall", and "cdrom" options are available;
435 + * default values are used for everything else.
436 + *
437 + * The pathnames of the backing files and the ro settings are available in
438 + * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of
439 + * the gadget's sysfs directory. If the "removable" option is set, writing to
440 + * these files will simulate ejecting/loading the medium (writing an empty
441 + * line means eject) and adjusting a write-enable tab. Changes to the ro
442 + * setting are not allowed when the medium is loaded or if CD-ROM emulation
443 + * is being used.
444 + *
445 + * This gadget driver is heavily based on "Gadget Zero" by David Brownell.
446 + * The driver's SCSI command interface was based on the "Information
447 + * technology - Small Computer System Interface - 2" document from
448 + * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at
449 + * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception
450 + * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the
451 + * "Universal Serial Bus Mass Storage Class UFI Command Specification"
452 + * document, Revision 1.0, December 14, 1998, available at
453 + * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
454 + */
455 +
456 +
457 +/*
458 + * Driver Design
459 + *
460 + * The FSG driver is fairly straightforward. There is a main kernel
461 + * thread that handles most of the work. Interrupt routines field
462 + * callbacks from the controller driver: bulk- and interrupt-request
463 + * completion notifications, endpoint-0 events, and disconnect events.
464 + * Completion events are passed to the main thread by wakeup calls. Many
465 + * ep0 requests are handled at interrupt time, but SetInterface,
466 + * SetConfiguration, and device reset requests are forwarded to the
467 + * thread in the form of "exceptions" using SIGUSR1 signals (since they
468 + * should interrupt any ongoing file I/O operations).
469 + *
470 + * The thread's main routine implements the standard command/data/status
471 + * parts of a SCSI interaction. It and its subroutines are full of tests
472 + * for pending signals/exceptions -- all this polling is necessary since
473 + * the kernel has no setjmp/longjmp equivalents. (Maybe this is an
474 + * indication that the driver really wants to be running in userspace.)
475 + * An important point is that so long as the thread is alive it keeps an
476 + * open reference to the backing file. This will prevent unmounting
477 + * the backing file's underlying filesystem and could cause problems
478 + * during system shutdown, for example. To prevent such problems, the
479 + * thread catches INT, TERM, and KILL signals and converts them into
480 + * an EXIT exception.
481 + *
482 + * In normal operation the main thread is started during the gadget's
483 + * fsg_bind() callback and stopped during fsg_unbind(). But it can also
484 + * exit when it receives a signal, and there's no point leaving the
485 + * gadget running when the thread is dead. So just before the thread
486 + * exits, it deregisters the gadget driver. This makes things a little
487 + * tricky: The driver is deregistered at two places, and the exiting
488 + * thread can indirectly call fsg_unbind() which in turn can tell the
489 + * thread to exit. The first problem is resolved through the use of the
490 + * REGISTERED atomic bitflag; the driver will only be deregistered once.
491 + * The second problem is resolved by having fsg_unbind() check
492 + * fsg->state; it won't try to stop the thread if the state is already
493 + * FSG_STATE_TERMINATED.
494 + *
495 + * To provide maximum throughput, the driver uses a circular pipeline of
496 + * buffer heads (struct fsg_buffhd). In principle the pipeline can be
497 + * arbitrarily long; in practice the benefits don't justify having more
498 + * than 2 stages (i.e., double buffering). But it helps to think of the
499 + * pipeline as being a long one. Each buffer head contains a bulk-in and
500 + * a bulk-out request pointer (since the buffer can be used for both
501 + * output and input -- directions always are given from the host's
502 + * point of view) as well as a pointer to the buffer and various state
503 + * variables.
504 + *
505 + * Use of the pipeline follows a simple protocol. There is a variable
506 + * (fsg->next_buffhd_to_fill) that points to the next buffer head to use.
507 + * At any time that buffer head may still be in use from an earlier
508 + * request, so each buffer head has a state variable indicating whether
509 + * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the
510 + * buffer head to be EMPTY, filling the buffer either by file I/O or by
511 + * USB I/O (during which the buffer head is BUSY), and marking the buffer
512 + * head FULL when the I/O is complete. Then the buffer will be emptied
513 + * (again possibly by USB I/O, during which it is marked BUSY) and
514 + * finally marked EMPTY again (possibly by a completion routine).
515 + *
516 + * A module parameter tells the driver to avoid stalling the bulk
517 + * endpoints wherever the transport specification allows. This is
518 + * necessary for some UDCs like the SuperH, which cannot reliably clear a
519 + * halt on a bulk endpoint. However, under certain circumstances the
520 + * Bulk-only specification requires a stall. In such cases the driver
521 + * will halt the endpoint and set a flag indicating that it should clear
522 + * the halt in software during the next device reset. Hopefully this
523 + * will permit everything to work correctly. Furthermore, although the
524 + * specification allows the bulk-out endpoint to halt when the host sends
525 + * too much data, implementing this would cause an unavoidable race.
526 + * The driver will always use the "no-stall" approach for OUT transfers.
527 + *
528 + * One subtle point concerns sending status-stage responses for ep0
529 + * requests. Some of these requests, such as device reset, can involve
530 + * interrupting an ongoing file I/O operation, which might take an
531 + * arbitrarily long time. During that delay the host might give up on
532 + * the original ep0 request and issue a new one. When that happens the
533 + * driver should not notify the host about completion of the original
534 + * request, as the host will no longer be waiting for it. So the driver
535 + * assigns to each ep0 request a unique tag, and it keeps track of the
536 + * tag value of the request associated with a long-running exception
537 + * (device-reset, interface-change, or configuration-change). When the
538 + * exception handler is finished, the status-stage response is submitted
539 + * only if the current ep0 request tag is equal to the exception request
540 + * tag. Thus only the most recently received ep0 request will get a
541 + * status-stage response.
542 + *
543 + * Warning: This driver source file is too long. It ought to be split up
544 + * into a header file plus about 3 separate .c files, to handle the details
545 + * of the Gadget, USB Mass Storage, and SCSI protocols.
546 + */
547 +
548 +
549 +/* #define VERBOSE_DEBUG */
550 +/* #define DUMP_MSGS */
551 +
552 +
553 +#include <linux/blkdev.h>
554 +#include <linux/completion.h>
555 +#include <linux/dcache.h>
556 +#include <linux/delay.h>
557 +#include <linux/device.h>
558 +#include <linux/fcntl.h>
559 +#include <linux/file.h>
560 +#include <linux/fs.h>
561 +#include <linux/kref.h>
562 +#include <linux/kthread.h>
563 +#include <linux/limits.h>
564 +#include <linux/module.h>
565 +#include <linux/rwsem.h>
566 +#include <linux/slab.h>
567 +#include <linux/spinlock.h>
568 +#include <linux/string.h>
569 +#include <linux/freezer.h>
570 +#include <linux/utsname.h>
571 +
572 +#include <linux/usb/ch9.h>
573 +#include <linux/usb/gadget.h>
574 +
575 +#include "gadget_chips.h"
576 +
577 +
578 +
579 +/*
580 + * Kbuild is not very cooperative with respect to linking separately
581 + * compiled library objects into one module. So for now we won't use
582 + * separate compilation ... ensuring init/exit sections work to shrink
583 + * the runtime footprint, and giving us at least some parts of what
584 + * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
585 + */
586 +#include "usbstring.c"
587 +#include "config.c"
588 +#include "epautoconf.c"
589 +
590 +/*-------------------------------------------------------------------------*/
591 +
592 +#define DRIVER_DESC "File-backed Storage Gadget"
593 +#define DRIVER_NAME "g_file_storage"
594 +#define DRIVER_VERSION "1 September 2010"
595 +
596 +static char fsg_string_manufacturer[64];
597 +static const char fsg_string_product[] = DRIVER_DESC;
598 +static const char fsg_string_config[] = "Self-powered";
599 +static const char fsg_string_interface[] = "Mass Storage";
600 +
601 +
602 +#include "storage_common.c"
603 +
604 +
605 +MODULE_DESCRIPTION(DRIVER_DESC);
606 +MODULE_AUTHOR("Alan Stern");
607 +MODULE_LICENSE("Dual BSD/GPL");
608 +
609 +/*
610 + * This driver assumes self-powered hardware and has no way for users to
611 + * trigger remote wakeup. It uses autoconfiguration to select endpoints
612 + * and endpoint addresses.
613 + */
614 +
615 +
616 +/*-------------------------------------------------------------------------*/
617 +
618 +
619 +/* Encapsulate the module parameter settings */
620 +
621 +static struct {
622 + char *file[FSG_MAX_LUNS];
623 + char *serial;
624 + bool ro[FSG_MAX_LUNS];
625 + bool nofua[FSG_MAX_LUNS];
626 + unsigned int num_filenames;
627 + unsigned int num_ros;
628 + unsigned int num_nofuas;
629 + unsigned int nluns;
630 +
631 + bool removable;
632 + bool can_stall;
633 + bool cdrom;
634 +
635 + char *transport_parm;
636 + char *protocol_parm;
637 + unsigned short vendor;
638 + unsigned short product;
639 + unsigned short release;
640 + unsigned int buflen;
641 +
642 + int transport_type;
643 + char *transport_name;
644 + int protocol_type;
645 + char *protocol_name;
646 +
647 +} mod_data = { // Default values
648 + .transport_parm = "BBB",
649 + .protocol_parm = "SCSI",
650 + .removable = 0,
651 + .can_stall = 1,
652 + .cdrom = 0,
653 + .vendor = FSG_VENDOR_ID,
654 + .product = FSG_PRODUCT_ID,
655 + .release = 0xffff, // Use controller chip type
656 + .buflen = 16384,
657 + };
658 +
659 +
660 +module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames,
661 + S_IRUGO);
662 +MODULE_PARM_DESC(file, "names of backing files or devices");
663 +
664 +module_param_named(serial, mod_data.serial, charp, S_IRUGO);
665 +MODULE_PARM_DESC(serial, "USB serial number");
666 +
667 +module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
668 +MODULE_PARM_DESC(ro, "true to force read-only");
669 +
670 +module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas,
671 + S_IRUGO);
672 +MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit");
673 +
674 +module_param_named(luns, mod_data.nluns, uint, S_IRUGO);
675 +MODULE_PARM_DESC(luns, "number of LUNs");
676 +
677 +module_param_named(removable, mod_data.removable, bool, S_IRUGO);
678 +MODULE_PARM_DESC(removable, "true to simulate removable media");
679 +
680 +module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
681 +MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
682 +
683 +module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
684 +MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
685 +
686 +/* In the non-TEST version, only the module parameters listed above
687 + * are available. */
688 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
689 +
690 +module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO);
691 +MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)");
692 +
693 +module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO);
694 +MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, "
695 + "8070, or SCSI)");
696 +
697 +module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO);
698 +MODULE_PARM_DESC(vendor, "USB Vendor ID");
699 +
700 +module_param_named(product, mod_data.product, ushort, S_IRUGO);
701 +MODULE_PARM_DESC(product, "USB Product ID");
702 +
703 +module_param_named(release, mod_data.release, ushort, S_IRUGO);
704 +MODULE_PARM_DESC(release, "USB release number");
705 +
706 +module_param_named(buflen, mod_data.buflen, uint, S_IRUGO);
707 +MODULE_PARM_DESC(buflen, "I/O buffer size");
708 +
709 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
710 +
711 +
712 +/*
713 + * These definitions will permit the compiler to avoid generating code for
714 + * parts of the driver that aren't used in the non-TEST version. Even gcc
715 + * can recognize when a test of a constant expression yields a dead code
716 + * path.
717 + */
718 +
719 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
720 +
721 +#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK)
722 +#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI)
723 +#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI)
724 +
725 +#else
726 +
727 +#define transport_is_bbb() 1
728 +#define transport_is_cbi() 0
729 +#define protocol_is_scsi() 1
730 +
731 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
732 +
733 +
734 +/*-------------------------------------------------------------------------*/
735 +
736 +
737 +struct fsg_dev {
738 + /* lock protects: state, all the req_busy's, and cbbuf_cmnd */
739 + spinlock_t lock;
740 + struct usb_gadget *gadget;
741 +
742 + /* filesem protects: backing files in use */
743 + struct rw_semaphore filesem;
744 +
745 + /* reference counting: wait until all LUNs are released */
746 + struct kref ref;
747 +
748 + struct usb_ep *ep0; // Handy copy of gadget->ep0
749 + struct usb_request *ep0req; // For control responses
750 + unsigned int ep0_req_tag;
751 + const char *ep0req_name;
752 +
753 + struct usb_request *intreq; // For interrupt responses
754 + int intreq_busy;
755 + struct fsg_buffhd *intr_buffhd;
756 +
757 + unsigned int bulk_out_maxpacket;
758 + enum fsg_state state; // For exception handling
759 + unsigned int exception_req_tag;
760 +
761 + u8 config, new_config;
762 +
763 + unsigned int running : 1;
764 + unsigned int bulk_in_enabled : 1;
765 + unsigned int bulk_out_enabled : 1;
766 + unsigned int intr_in_enabled : 1;
767 + unsigned int phase_error : 1;
768 + unsigned int short_packet_received : 1;
769 + unsigned int bad_lun_okay : 1;
770 +
771 + unsigned long atomic_bitflags;
772 +#define REGISTERED 0
773 +#define IGNORE_BULK_OUT 1
774 +#define SUSPENDED 2
775 +
776 + struct usb_ep *bulk_in;
777 + struct usb_ep *bulk_out;
778 + struct usb_ep *intr_in;
779 +
780 + struct fsg_buffhd *next_buffhd_to_fill;
781 + struct fsg_buffhd *next_buffhd_to_drain;
782 +
783 + int thread_wakeup_needed;
784 + struct completion thread_notifier;
785 + struct task_struct *thread_task;
786 +
787 + int cmnd_size;
788 + u8 cmnd[MAX_COMMAND_SIZE];
789 + enum data_direction data_dir;
790 + u32 data_size;
791 + u32 data_size_from_cmnd;
792 + u32 tag;
793 + unsigned int lun;
794 + u32 residue;
795 + u32 usb_amount_left;
796 +
797 + /* The CB protocol offers no way for a host to know when a command
798 + * has completed. As a result the next command may arrive early,
799 + * and we will still have to handle it. For that reason we need
800 + * a buffer to store new commands when using CB (or CBI, which
801 + * does not oblige a host to wait for command completion either). */
802 + int cbbuf_cmnd_size;
803 + u8 cbbuf_cmnd[MAX_COMMAND_SIZE];
804 +
805 + unsigned int nluns;
806 + struct fsg_lun *luns;
807 + struct fsg_lun *curlun;
808 + /* Must be the last entry */
809 + struct fsg_buffhd buffhds[];
810 +};
811 +
812 +typedef void (*fsg_routine_t)(struct fsg_dev *);
813 +
814 +static int exception_in_progress(struct fsg_dev *fsg)
815 +{
816 + return (fsg->state > FSG_STATE_IDLE);
817 +}
818 +
819 +/* Make bulk-out requests be divisible by the maxpacket size */
820 +static void set_bulk_out_req_length(struct fsg_dev *fsg,
821 + struct fsg_buffhd *bh, unsigned int length)
822 +{
823 + unsigned int rem;
824 +
825 + bh->bulk_out_intended_length = length;
826 + rem = length % fsg->bulk_out_maxpacket;
827 + if (rem > 0)
828 + length += fsg->bulk_out_maxpacket - rem;
829 + bh->outreq->length = length;
830 +}
831 +
832 +static struct fsg_dev *the_fsg;
833 +static struct usb_gadget_driver fsg_driver;
834 +
835 +
836 +/*-------------------------------------------------------------------------*/
837 +
838 +static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
839 +{
840 + const char *name;
841 +
842 + if (ep == fsg->bulk_in)
843 + name = "bulk-in";
844 + else if (ep == fsg->bulk_out)
845 + name = "bulk-out";
846 + else
847 + name = ep->name;
848 + DBG(fsg, "%s set halt\n", name);
849 + return usb_ep_set_halt(ep);
850 +}
851 +
852 +
853 +/*-------------------------------------------------------------------------*/
854 +
855 +/*
856 + * DESCRIPTORS ... most are static, but strings and (full) configuration
857 + * descriptors are built on demand. Also the (static) config and interface
858 + * descriptors are adjusted during fsg_bind().
859 + */
860 +
861 +/* There is only one configuration. */
862 +#define CONFIG_VALUE 1
863 +
864 +static struct usb_device_descriptor
865 +device_desc = {
866 + .bLength = sizeof device_desc,
867 + .bDescriptorType = USB_DT_DEVICE,
868 +
869 + .bcdUSB = cpu_to_le16(0x0200),
870 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
871 +
872 + /* The next three values can be overridden by module parameters */
873 + .idVendor = cpu_to_le16(FSG_VENDOR_ID),
874 + .idProduct = cpu_to_le16(FSG_PRODUCT_ID),
875 + .bcdDevice = cpu_to_le16(0xffff),
876 +
877 + .iManufacturer = FSG_STRING_MANUFACTURER,
878 + .iProduct = FSG_STRING_PRODUCT,
879 + .iSerialNumber = FSG_STRING_SERIAL,
880 + .bNumConfigurations = 1,
881 +};
882 +
883 +static struct usb_config_descriptor
884 +config_desc = {
885 + .bLength = sizeof config_desc,
886 + .bDescriptorType = USB_DT_CONFIG,
887 +
888 + /* wTotalLength computed by usb_gadget_config_buf() */
889 + .bNumInterfaces = 1,
890 + .bConfigurationValue = CONFIG_VALUE,
891 + .iConfiguration = FSG_STRING_CONFIG,
892 + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
893 + .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
894 +};
895 +
896 +
897 +static struct usb_qualifier_descriptor
898 +dev_qualifier = {
899 + .bLength = sizeof dev_qualifier,
900 + .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
901 +
902 + .bcdUSB = cpu_to_le16(0x0200),
903 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
904 +
905 + .bNumConfigurations = 1,
906 +};
907 +
908 +static int populate_bos(struct fsg_dev *fsg, u8 *buf)
909 +{
910 + memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE);
911 + buf += USB_DT_BOS_SIZE;
912 +
913 + memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE);
914 + buf += USB_DT_USB_EXT_CAP_SIZE;
915 +
916 + memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE);
917 +
918 + return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE
919 + + USB_DT_USB_EXT_CAP_SIZE;
920 +}
921 +
922 +/*
923 + * Config descriptors must agree with the code that sets configurations
924 + * and with code managing interfaces and their altsettings. They must
925 + * also handle different speeds and other-speed requests.
926 + */
927 +static int populate_config_buf(struct usb_gadget *gadget,
928 + u8 *buf, u8 type, unsigned index)
929 +{
930 + enum usb_device_speed speed = gadget->speed;
931 + int len;
932 + const struct usb_descriptor_header **function;
933 +
934 + if (index > 0)
935 + return -EINVAL;
936 +
937 + if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
938 + speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
939 + function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH
940 + ? (const struct usb_descriptor_header **)fsg_hs_function
941 + : (const struct usb_descriptor_header **)fsg_fs_function;
942 +
943 + /* for now, don't advertise srp-only devices */
944 + if (!gadget_is_otg(gadget))
945 + function++;
946 +
947 + len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
948 + ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
949 + return len;
950 +}
951 +
952 +
953 +/*-------------------------------------------------------------------------*/
954 +
955 +/* These routines may be called in process context or in_irq */
956 +
957 +/* Caller must hold fsg->lock */
958 +static void wakeup_thread(struct fsg_dev *fsg)
959 +{
960 + /* Tell the main thread that something has happened */
961 + fsg->thread_wakeup_needed = 1;
962 + if (fsg->thread_task)
963 + wake_up_process(fsg->thread_task);
964 +}
965 +
966 +
967 +static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
968 +{
969 + unsigned long flags;
970 +
971 + /* Do nothing if a higher-priority exception is already in progress.
972 + * If a lower-or-equal priority exception is in progress, preempt it
973 + * and notify the main thread by sending it a signal. */
974 + spin_lock_irqsave(&fsg->lock, flags);
975 + if (fsg->state <= new_state) {
976 + fsg->exception_req_tag = fsg->ep0_req_tag;
977 + fsg->state = new_state;
978 + if (fsg->thread_task)
979 + send_sig_info(SIGUSR1, SEND_SIG_FORCED,
980 + fsg->thread_task);
981 + }
982 + spin_unlock_irqrestore(&fsg->lock, flags);
983 +}
984 +
985 +
986 +/*-------------------------------------------------------------------------*/
987 +
988 +/* The disconnect callback and ep0 routines. These always run in_irq,
989 + * except that ep0_queue() is called in the main thread to acknowledge
990 + * completion of various requests: set config, set interface, and
991 + * Bulk-only device reset. */
992 +
993 +static void fsg_disconnect(struct usb_gadget *gadget)
994 +{
995 + struct fsg_dev *fsg = get_gadget_data(gadget);
996 +
997 + DBG(fsg, "disconnect or port reset\n");
998 + raise_exception(fsg, FSG_STATE_DISCONNECT);
999 +}
1000 +
1001 +
1002 +static int ep0_queue(struct fsg_dev *fsg)
1003 +{
1004 + int rc;
1005 +
1006 + rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC);
1007 + if (rc != 0 && rc != -ESHUTDOWN) {
1008 +
1009 + /* We can't do much more than wait for a reset */
1010 + WARNING(fsg, "error in submission: %s --> %d\n",
1011 + fsg->ep0->name, rc);
1012 + }
1013 + return rc;
1014 +}
1015 +
1016 +static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
1017 +{
1018 + struct fsg_dev *fsg = ep->driver_data;
1019 +
1020 + if (req->actual > 0)
1021 + dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
1022 + if (req->status || req->actual != req->length)
1023 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1024 + req->status, req->actual, req->length);
1025 + if (req->status == -ECONNRESET) // Request was cancelled
1026 + usb_ep_fifo_flush(ep);
1027 +
1028 + if (req->status == 0 && req->context)
1029 + ((fsg_routine_t) (req->context))(fsg);
1030 +}
1031 +
1032 +
1033 +/*-------------------------------------------------------------------------*/
1034 +
1035 +/* Bulk and interrupt endpoint completion handlers.
1036 + * These always run in_irq. */
1037 +
1038 +static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
1039 +{
1040 + struct fsg_dev *fsg = ep->driver_data;
1041 + struct fsg_buffhd *bh = req->context;
1042 +
1043 + if (req->status || req->actual != req->length)
1044 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1045 + req->status, req->actual, req->length);
1046 + if (req->status == -ECONNRESET) // Request was cancelled
1047 + usb_ep_fifo_flush(ep);
1048 +
1049 + /* Hold the lock while we update the request and buffer states */
1050 + smp_wmb();
1051 + spin_lock(&fsg->lock);
1052 + bh->inreq_busy = 0;
1053 + bh->state = BUF_STATE_EMPTY;
1054 + wakeup_thread(fsg);
1055 + spin_unlock(&fsg->lock);
1056 +}
1057 +
1058 +static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
1059 +{
1060 + struct fsg_dev *fsg = ep->driver_data;
1061 + struct fsg_buffhd *bh = req->context;
1062 +
1063 + dump_msg(fsg, "bulk-out", req->buf, req->actual);
1064 + if (req->status || req->actual != bh->bulk_out_intended_length)
1065 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1066 + req->status, req->actual,
1067 + bh->bulk_out_intended_length);
1068 + if (req->status == -ECONNRESET) // Request was cancelled
1069 + usb_ep_fifo_flush(ep);
1070 +
1071 + /* Hold the lock while we update the request and buffer states */
1072 + smp_wmb();
1073 + spin_lock(&fsg->lock);
1074 + bh->outreq_busy = 0;
1075 + bh->state = BUF_STATE_FULL;
1076 + wakeup_thread(fsg);
1077 + spin_unlock(&fsg->lock);
1078 +}
1079 +
1080 +
1081 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
1082 +static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
1083 +{
1084 + struct fsg_dev *fsg = ep->driver_data;
1085 + struct fsg_buffhd *bh = req->context;
1086 +
1087 + if (req->status || req->actual != req->length)
1088 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1089 + req->status, req->actual, req->length);
1090 + if (req->status == -ECONNRESET) // Request was cancelled
1091 + usb_ep_fifo_flush(ep);
1092 +
1093 + /* Hold the lock while we update the request and buffer states */
1094 + smp_wmb();
1095 + spin_lock(&fsg->lock);
1096 + fsg->intreq_busy = 0;
1097 + bh->state = BUF_STATE_EMPTY;
1098 + wakeup_thread(fsg);
1099 + spin_unlock(&fsg->lock);
1100 +}
1101 +
1102 +#else
1103 +static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
1104 +{}
1105 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
1106 +
1107 +
1108 +/*-------------------------------------------------------------------------*/
1109 +
1110 +/* Ep0 class-specific handlers. These always run in_irq. */
1111 +
1112 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
1113 +static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
1114 +{
1115 + struct usb_request *req = fsg->ep0req;
1116 + static u8 cbi_reset_cmnd[6] = {
1117 + SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff};
1118 +
1119 + /* Error in command transfer? */
1120 + if (req->status || req->length != req->actual ||
1121 + req->actual < 6 || req->actual > MAX_COMMAND_SIZE) {
1122 +
1123 + /* Not all controllers allow a protocol stall after
1124 + * receiving control-out data, but we'll try anyway. */
1125 + fsg_set_halt(fsg, fsg->ep0);
1126 + return; // Wait for reset
1127 + }
1128 +
1129 + /* Is it the special reset command? */
1130 + if (req->actual >= sizeof cbi_reset_cmnd &&
1131 + memcmp(req->buf, cbi_reset_cmnd,
1132 + sizeof cbi_reset_cmnd) == 0) {
1133 +
1134 + /* Raise an exception to stop the current operation
1135 + * and reinitialize our state. */
1136 + DBG(fsg, "cbi reset request\n");
1137 + raise_exception(fsg, FSG_STATE_RESET);
1138 + return;
1139 + }
1140 +
1141 + VDBG(fsg, "CB[I] accept device-specific command\n");
1142 + spin_lock(&fsg->lock);
1143 +
1144 + /* Save the command for later */
1145 + if (fsg->cbbuf_cmnd_size)
1146 + WARNING(fsg, "CB[I] overwriting previous command\n");
1147 + fsg->cbbuf_cmnd_size = req->actual;
1148 + memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size);
1149 +
1150 + wakeup_thread(fsg);
1151 + spin_unlock(&fsg->lock);
1152 +}
1153 +
1154 +#else
1155 +static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
1156 +{}
1157 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
1158 +
1159 +
1160 +static int class_setup_req(struct fsg_dev *fsg,
1161 + const struct usb_ctrlrequest *ctrl)
1162 +{
1163 + struct usb_request *req = fsg->ep0req;
1164 + int value = -EOPNOTSUPP;
1165 + u16 w_index = le16_to_cpu(ctrl->wIndex);
1166 + u16 w_value = le16_to_cpu(ctrl->wValue);
1167 + u16 w_length = le16_to_cpu(ctrl->wLength);
1168 +
1169 + if (!fsg->config)
1170 + return value;
1171 +
1172 + /* Handle Bulk-only class-specific requests */
1173 + if (transport_is_bbb()) {
1174 + switch (ctrl->bRequest) {
1175 +
1176 + case US_BULK_RESET_REQUEST:
1177 + if (ctrl->bRequestType != (USB_DIR_OUT |
1178 + USB_TYPE_CLASS | USB_RECIP_INTERFACE))
1179 + break;
1180 + if (w_index != 0 || w_value != 0 || w_length != 0) {
1181 + value = -EDOM;
1182 + break;
1183 + }
1184 +
1185 + /* Raise an exception to stop the current operation
1186 + * and reinitialize our state. */
1187 + DBG(fsg, "bulk reset request\n");
1188 + raise_exception(fsg, FSG_STATE_RESET);
1189 + value = DELAYED_STATUS;
1190 + break;
1191 +
1192 + case US_BULK_GET_MAX_LUN:
1193 + if (ctrl->bRequestType != (USB_DIR_IN |
1194 + USB_TYPE_CLASS | USB_RECIP_INTERFACE))
1195 + break;
1196 + if (w_index != 0 || w_value != 0 || w_length != 1) {
1197 + value = -EDOM;
1198 + break;
1199 + }
1200 + VDBG(fsg, "get max LUN\n");
1201 + *(u8 *) req->buf = fsg->nluns - 1;
1202 + value = 1;
1203 + break;
1204 + }
1205 + }
1206 +
1207 + /* Handle CBI class-specific requests */
1208 + else {
1209 + switch (ctrl->bRequest) {
1210 +
1211 + case USB_CBI_ADSC_REQUEST:
1212 + if (ctrl->bRequestType != (USB_DIR_OUT |
1213 + USB_TYPE_CLASS | USB_RECIP_INTERFACE))
1214 + break;
1215 + if (w_index != 0 || w_value != 0) {
1216 + value = -EDOM;
1217 + break;
1218 + }
1219 + if (w_length > MAX_COMMAND_SIZE) {
1220 + value = -EOVERFLOW;
1221 + break;
1222 + }
1223 + value = w_length;
1224 + fsg->ep0req->context = received_cbi_adsc;
1225 + break;
1226 + }
1227 + }
1228 +
1229 + if (value == -EOPNOTSUPP)
1230 + VDBG(fsg,
1231 + "unknown class-specific control req "
1232 + "%02x.%02x v%04x i%04x l%u\n",
1233 + ctrl->bRequestType, ctrl->bRequest,
1234 + le16_to_cpu(ctrl->wValue), w_index, w_length);
1235 + return value;
1236 +}
1237 +
1238 +
1239 +/*-------------------------------------------------------------------------*/
1240 +
1241 +/* Ep0 standard request handlers. These always run in_irq. */
1242 +
1243 +static int standard_setup_req(struct fsg_dev *fsg,
1244 + const struct usb_ctrlrequest *ctrl)
1245 +{
1246 + struct usb_request *req = fsg->ep0req;
1247 + int value = -EOPNOTSUPP;
1248 + u16 w_index = le16_to_cpu(ctrl->wIndex);
1249 + u16 w_value = le16_to_cpu(ctrl->wValue);
1250 +
1251 + /* Usually this just stores reply data in the pre-allocated ep0 buffer,
1252 + * but config change events will also reconfigure hardware. */
1253 + switch (ctrl->bRequest) {
1254 +
1255 + case USB_REQ_GET_DESCRIPTOR:
1256 + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
1257 + USB_RECIP_DEVICE))
1258 + break;
1259 + switch (w_value >> 8) {
1260 +
1261 + case USB_DT_DEVICE:
1262 + VDBG(fsg, "get device descriptor\n");
1263 + device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
1264 + value = sizeof device_desc;
1265 + memcpy(req->buf, &device_desc, value);
1266 + break;
1267 + case USB_DT_DEVICE_QUALIFIER:
1268 + VDBG(fsg, "get device qualifier\n");
1269 + if (!gadget_is_dualspeed(fsg->gadget) ||
1270 + fsg->gadget->speed == USB_SPEED_SUPER)
1271 + break;
1272 + /*
1273 + * Assume ep0 uses the same maxpacket value for both
1274 + * speeds
1275 + */
1276 + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
1277 + value = sizeof dev_qualifier;
1278 + memcpy(req->buf, &dev_qualifier, value);
1279 + break;
1280 +
1281 + case USB_DT_OTHER_SPEED_CONFIG:
1282 + VDBG(fsg, "get other-speed config descriptor\n");
1283 + if (!gadget_is_dualspeed(fsg->gadget) ||
1284 + fsg->gadget->speed == USB_SPEED_SUPER)
1285 + break;
1286 + goto get_config;
1287 + case USB_DT_CONFIG:
1288 + VDBG(fsg, "get configuration descriptor\n");
1289 +get_config:
1290 + value = populate_config_buf(fsg->gadget,
1291 + req->buf,
1292 + w_value >> 8,
1293 + w_value & 0xff);
1294 + break;
1295 +
1296 + case USB_DT_STRING:
1297 + VDBG(fsg, "get string descriptor\n");
1298 +
1299 + /* wIndex == language code */
1300 + value = usb_gadget_get_string(&fsg_stringtab,
1301 + w_value & 0xff, req->buf);
1302 + break;
1303 +
1304 + case USB_DT_BOS:
1305 + VDBG(fsg, "get bos descriptor\n");
1306 +
1307 + if (gadget_is_superspeed(fsg->gadget))
1308 + value = populate_bos(fsg, req->buf);
1309 + break;
1310 + }
1311 +
1312 + break;
1313 +
1314 + /* One config, two speeds */
1315 + case USB_REQ_SET_CONFIGURATION:
1316 + if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
1317 + USB_RECIP_DEVICE))
1318 + break;
1319 + VDBG(fsg, "set configuration\n");
1320 + if (w_value == CONFIG_VALUE || w_value == 0) {
1321 + fsg->new_config = w_value;
1322 +
1323 + /* Raise an exception to wipe out previous transaction
1324 + * state (queued bufs, etc) and set the new config. */
1325 + raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
1326 + value = DELAYED_STATUS;
1327 + }
1328 + break;
1329 + case USB_REQ_GET_CONFIGURATION:
1330 + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
1331 + USB_RECIP_DEVICE))
1332 + break;
1333 + VDBG(fsg, "get configuration\n");
1334 + *(u8 *) req->buf = fsg->config;
1335 + value = 1;
1336 + break;
1337 +
1338 + case USB_REQ_SET_INTERFACE:
1339 + if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD |
1340 + USB_RECIP_INTERFACE))
1341 + break;
1342 + if (fsg->config && w_index == 0) {
1343 +
1344 + /* Raise an exception to wipe out previous transaction
1345 + * state (queued bufs, etc) and install the new
1346 + * interface altsetting. */
1347 + raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE);
1348 + value = DELAYED_STATUS;
1349 + }
1350 + break;
1351 + case USB_REQ_GET_INTERFACE:
1352 + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
1353 + USB_RECIP_INTERFACE))
1354 + break;
1355 + if (!fsg->config)
1356 + break;
1357 + if (w_index != 0) {
1358 + value = -EDOM;
1359 + break;
1360 + }
1361 + VDBG(fsg, "get interface\n");
1362 + *(u8 *) req->buf = 0;
1363 + value = 1;
1364 + break;
1365 +
1366 + default:
1367 + VDBG(fsg,
1368 + "unknown control req %02x.%02x v%04x i%04x l%u\n",
1369 + ctrl->bRequestType, ctrl->bRequest,
1370 + w_value, w_index, le16_to_cpu(ctrl->wLength));
1371 + }
1372 +
1373 + return value;
1374 +}
1375 +
1376 +
1377 +static int fsg_setup(struct usb_gadget *gadget,
1378 + const struct usb_ctrlrequest *ctrl)
1379 +{
1380 + struct fsg_dev *fsg = get_gadget_data(gadget);
1381 + int rc;
1382 + int w_length = le16_to_cpu(ctrl->wLength);
1383 +
1384 + ++fsg->ep0_req_tag; // Record arrival of a new request
1385 + fsg->ep0req->context = NULL;
1386 + fsg->ep0req->length = 0;
1387 + dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
1388 +
1389 + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
1390 + rc = class_setup_req(fsg, ctrl);
1391 + else
1392 + rc = standard_setup_req(fsg, ctrl);
1393 +
1394 + /* Respond with data/status or defer until later? */
1395 + if (rc >= 0 && rc != DELAYED_STATUS) {
1396 + rc = min(rc, w_length);
1397 + fsg->ep0req->length = rc;
1398 + fsg->ep0req->zero = rc < w_length;
1399 + fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
1400 + "ep0-in" : "ep0-out");
1401 + rc = ep0_queue(fsg);
1402 + }
1403 +
1404 + /* Device either stalls (rc < 0) or reports success */
1405 + return rc;
1406 +}
1407 +
1408 +
1409 +/*-------------------------------------------------------------------------*/
1410 +
1411 +/* All the following routines run in process context */
1412 +
1413 +
1414 +/* Use this for bulk or interrupt transfers, not ep0 */
1415 +static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
1416 + struct usb_request *req, int *pbusy,
1417 + enum fsg_buffer_state *state)
1418 +{
1419 + int rc;
1420 +
1421 + if (ep == fsg->bulk_in)
1422 + dump_msg(fsg, "bulk-in", req->buf, req->length);
1423 + else if (ep == fsg->intr_in)
1424 + dump_msg(fsg, "intr-in", req->buf, req->length);
1425 +
1426 + spin_lock_irq(&fsg->lock);
1427 + *pbusy = 1;
1428 + *state = BUF_STATE_BUSY;
1429 + spin_unlock_irq(&fsg->lock);
1430 + rc = usb_ep_queue(ep, req, GFP_KERNEL);
1431 + if (rc != 0) {
1432 + *pbusy = 0;
1433 + *state = BUF_STATE_EMPTY;
1434 +
1435 + /* We can't do much more than wait for a reset */
1436 +
1437 + /* Note: currently the net2280 driver fails zero-length
1438 + * submissions if DMA is enabled. */
1439 + if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP &&
1440 + req->length == 0))
1441 + WARNING(fsg, "error in submission: %s --> %d\n",
1442 + ep->name, rc);
1443 + }
1444 +}
1445 +
1446 +
1447 +static int sleep_thread(struct fsg_dev *fsg)
1448 +{
1449 + int rc = 0;
1450 +
1451 + /* Wait until a signal arrives or we are woken up */
1452 + for (;;) {
1453 + try_to_freeze();
1454 + set_current_state(TASK_INTERRUPTIBLE);
1455 + if (signal_pending(current)) {
1456 + rc = -EINTR;
1457 + break;
1458 + }
1459 + if (fsg->thread_wakeup_needed)
1460 + break;
1461 + schedule();
1462 + }
1463 + __set_current_state(TASK_RUNNING);
1464 + fsg->thread_wakeup_needed = 0;
1465 + return rc;
1466 +}
1467 +
1468 +
1469 +/*-------------------------------------------------------------------------*/
1470 +
1471 +static int do_read(struct fsg_dev *fsg)
1472 +{
1473 + struct fsg_lun *curlun = fsg->curlun;
1474 + u32 lba;
1475 + struct fsg_buffhd *bh;
1476 + int rc;
1477 + u32 amount_left;
1478 + loff_t file_offset, file_offset_tmp;
1479 + unsigned int amount;
1480 + ssize_t nread;
1481 +
1482 + /* Get the starting Logical Block Address and check that it's
1483 + * not too big */
1484 + if (fsg->cmnd[0] == READ_6)
1485 + lba = get_unaligned_be24(&fsg->cmnd[1]);
1486 + else {
1487 + lba = get_unaligned_be32(&fsg->cmnd[2]);
1488 +
1489 + /* We allow DPO (Disable Page Out = don't save data in the
1490 + * cache) and FUA (Force Unit Access = don't read from the
1491 + * cache), but we don't implement them. */
1492 + if ((fsg->cmnd[1] & ~0x18) != 0) {
1493 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1494 + return -EINVAL;
1495 + }
1496 + }
1497 + if (lba >= curlun->num_sectors) {
1498 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1499 + return -EINVAL;
1500 + }
1501 + file_offset = ((loff_t) lba) << curlun->blkbits;
1502 +
1503 + /* Carry out the file reads */
1504 + amount_left = fsg->data_size_from_cmnd;
1505 + if (unlikely(amount_left == 0))
1506 + return -EIO; // No default reply
1507 +
1508 + for (;;) {
1509 +
1510 + /* Figure out how much we need to read:
1511 + * Try to read the remaining amount.
1512 + * But don't read more than the buffer size.
1513 + * And don't try to read past the end of the file.
1514 + */
1515 + amount = min((unsigned int) amount_left, mod_data.buflen);
1516 + amount = min((loff_t) amount,
1517 + curlun->file_length - file_offset);
1518 +
1519 + /* Wait for the next buffer to become available */
1520 + bh = fsg->next_buffhd_to_fill;
1521 + while (bh->state != BUF_STATE_EMPTY) {
1522 + rc = sleep_thread(fsg);
1523 + if (rc)
1524 + return rc;
1525 + }
1526 +
1527 + /* If we were asked to read past the end of file,
1528 + * end with an empty buffer. */
1529 + if (amount == 0) {
1530 + curlun->sense_data =
1531 + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1532 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1533 + curlun->info_valid = 1;
1534 + bh->inreq->length = 0;
1535 + bh->state = BUF_STATE_FULL;
1536 + break;
1537 + }
1538 +
1539 + /* Perform the read */
1540 + file_offset_tmp = file_offset;
1541 + nread = vfs_read(curlun->filp,
1542 + (char __user *) bh->buf,
1543 + amount, &file_offset_tmp);
1544 + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
1545 + (unsigned long long) file_offset,
1546 + (int) nread);
1547 + if (signal_pending(current))
1548 + return -EINTR;
1549 +
1550 + if (nread < 0) {
1551 + LDBG(curlun, "error in file read: %d\n",
1552 + (int) nread);
1553 + nread = 0;
1554 + } else if (nread < amount) {
1555 + LDBG(curlun, "partial file read: %d/%u\n",
1556 + (int) nread, amount);
1557 + nread = round_down(nread, curlun->blksize);
1558 + }
1559 + file_offset += nread;
1560 + amount_left -= nread;
1561 + fsg->residue -= nread;
1562 +
1563 + /* Except at the end of the transfer, nread will be
1564 + * equal to the buffer size, which is divisible by the
1565 + * bulk-in maxpacket size.
1566 + */
1567 + bh->inreq->length = nread;
1568 + bh->state = BUF_STATE_FULL;
1569 +
1570 + /* If an error occurred, report it and its position */
1571 + if (nread < amount) {
1572 + curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
1573 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1574 + curlun->info_valid = 1;
1575 + break;
1576 + }
1577 +
1578 + if (amount_left == 0)
1579 + break; // No more left to read
1580 +
1581 + /* Send this buffer and go read some more */
1582 + bh->inreq->zero = 0;
1583 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
1584 + &bh->inreq_busy, &bh->state);
1585 + fsg->next_buffhd_to_fill = bh->next;
1586 + }
1587 +
1588 + return -EIO; // No default reply
1589 +}
1590 +
1591 +
1592 +/*-------------------------------------------------------------------------*/
1593 +
1594 +static int do_write(struct fsg_dev *fsg)
1595 +{
1596 + struct fsg_lun *curlun = fsg->curlun;
1597 + u32 lba;
1598 + struct fsg_buffhd *bh;
1599 + int get_some_more;
1600 + u32 amount_left_to_req, amount_left_to_write;
1601 + loff_t usb_offset, file_offset, file_offset_tmp;
1602 + unsigned int amount;
1603 + ssize_t nwritten;
1604 + int rc;
1605 +
1606 + if (curlun->ro) {
1607 + curlun->sense_data = SS_WRITE_PROTECTED;
1608 + return -EINVAL;
1609 + }
1610 + spin_lock(&curlun->filp->f_lock);
1611 + curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait
1612 + spin_unlock(&curlun->filp->f_lock);
1613 +
1614 + /* Get the starting Logical Block Address and check that it's
1615 + * not too big */
1616 + if (fsg->cmnd[0] == WRITE_6)
1617 + lba = get_unaligned_be24(&fsg->cmnd[1]);
1618 + else {
1619 + lba = get_unaligned_be32(&fsg->cmnd[2]);
1620 +
1621 + /* We allow DPO (Disable Page Out = don't save data in the
1622 + * cache) and FUA (Force Unit Access = write directly to the
1623 + * medium). We don't implement DPO; we implement FUA by
1624 + * performing synchronous output. */
1625 + if ((fsg->cmnd[1] & ~0x18) != 0) {
1626 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1627 + return -EINVAL;
1628 + }
1629 + /* FUA */
1630 + if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) {
1631 + spin_lock(&curlun->filp->f_lock);
1632 + curlun->filp->f_flags |= O_DSYNC;
1633 + spin_unlock(&curlun->filp->f_lock);
1634 + }
1635 + }
1636 + if (lba >= curlun->num_sectors) {
1637 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1638 + return -EINVAL;
1639 + }
1640 +
1641 + /* Carry out the file writes */
1642 + get_some_more = 1;
1643 + file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
1644 + amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
1645 +
1646 + while (amount_left_to_write > 0) {
1647 +
1648 + /* Queue a request for more data from the host */
1649 + bh = fsg->next_buffhd_to_fill;
1650 + if (bh->state == BUF_STATE_EMPTY && get_some_more) {
1651 +
1652 + /* Figure out how much we want to get:
1653 + * Try to get the remaining amount,
1654 + * but not more than the buffer size.
1655 + */
1656 + amount = min(amount_left_to_req, mod_data.buflen);
1657 +
1658 + /* Beyond the end of the backing file? */
1659 + if (usb_offset >= curlun->file_length) {
1660 + get_some_more = 0;
1661 + curlun->sense_data =
1662 + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1663 + curlun->sense_data_info = usb_offset >> curlun->blkbits;
1664 + curlun->info_valid = 1;
1665 + continue;
1666 + }
1667 +
1668 + /* Get the next buffer */
1669 + usb_offset += amount;
1670 + fsg->usb_amount_left -= amount;
1671 + amount_left_to_req -= amount;
1672 + if (amount_left_to_req == 0)
1673 + get_some_more = 0;
1674 +
1675 + /* Except at the end of the transfer, amount will be
1676 + * equal to the buffer size, which is divisible by
1677 + * the bulk-out maxpacket size.
1678 + */
1679 + set_bulk_out_req_length(fsg, bh, amount);
1680 + start_transfer(fsg, fsg->bulk_out, bh->outreq,
1681 + &bh->outreq_busy, &bh->state);
1682 + fsg->next_buffhd_to_fill = bh->next;
1683 + continue;
1684 + }
1685 +
1686 + /* Write the received data to the backing file */
1687 + bh = fsg->next_buffhd_to_drain;
1688 + if (bh->state == BUF_STATE_EMPTY && !get_some_more)
1689 + break; // We stopped early
1690 + if (bh->state == BUF_STATE_FULL) {
1691 + smp_rmb();
1692 + fsg->next_buffhd_to_drain = bh->next;
1693 + bh->state = BUF_STATE_EMPTY;
1694 +
1695 + /* Did something go wrong with the transfer? */
1696 + if (bh->outreq->status != 0) {
1697 + curlun->sense_data = SS_COMMUNICATION_FAILURE;
1698 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1699 + curlun->info_valid = 1;
1700 + break;
1701 + }
1702 +
1703 + amount = bh->outreq->actual;
1704 + if (curlun->file_length - file_offset < amount) {
1705 + LERROR(curlun,
1706 + "write %u @ %llu beyond end %llu\n",
1707 + amount, (unsigned long long) file_offset,
1708 + (unsigned long long) curlun->file_length);
1709 + amount = curlun->file_length - file_offset;
1710 + }
1711 +
1712 + /* Don't accept excess data. The spec doesn't say
1713 + * what to do in this case. We'll ignore the error.
1714 + */
1715 + amount = min(amount, bh->bulk_out_intended_length);
1716 +
1717 + /* Don't write a partial block */
1718 + amount = round_down(amount, curlun->blksize);
1719 + if (amount == 0)
1720 + goto empty_write;
1721 +
1722 + /* Perform the write */
1723 + file_offset_tmp = file_offset;
1724 + nwritten = vfs_write(curlun->filp,
1725 + (char __user *) bh->buf,
1726 + amount, &file_offset_tmp);
1727 + VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
1728 + (unsigned long long) file_offset,
1729 + (int) nwritten);
1730 + if (signal_pending(current))
1731 + return -EINTR; // Interrupted!
1732 +
1733 + if (nwritten < 0) {
1734 + LDBG(curlun, "error in file write: %d\n",
1735 + (int) nwritten);
1736 + nwritten = 0;
1737 + } else if (nwritten < amount) {
1738 + LDBG(curlun, "partial file write: %d/%u\n",
1739 + (int) nwritten, amount);
1740 + nwritten = round_down(nwritten, curlun->blksize);
1741 + }
1742 + file_offset += nwritten;
1743 + amount_left_to_write -= nwritten;
1744 + fsg->residue -= nwritten;
1745 +
1746 + /* If an error occurred, report it and its position */
1747 + if (nwritten < amount) {
1748 + curlun->sense_data = SS_WRITE_ERROR;
1749 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1750 + curlun->info_valid = 1;
1751 + break;
1752 + }
1753 +
1754 + empty_write:
1755 + /* Did the host decide to stop early? */
1756 + if (bh->outreq->actual < bh->bulk_out_intended_length) {
1757 + fsg->short_packet_received = 1;
1758 + break;
1759 + }
1760 + continue;
1761 + }
1762 +
1763 + /* Wait for something to happen */
1764 + rc = sleep_thread(fsg);
1765 + if (rc)
1766 + return rc;
1767 + }
1768 +
1769 + return -EIO; // No default reply
1770 +}
1771 +
1772 +
1773 +/*-------------------------------------------------------------------------*/
1774 +
1775 +static int do_synchronize_cache(struct fsg_dev *fsg)
1776 +{
1777 + struct fsg_lun *curlun = fsg->curlun;
1778 + int rc;
1779 +
1780 + /* We ignore the requested LBA and write out all file's
1781 + * dirty data buffers. */
1782 + rc = fsg_lun_fsync_sub(curlun);
1783 + if (rc)
1784 + curlun->sense_data = SS_WRITE_ERROR;
1785 + return 0;
1786 +}
1787 +
1788 +
1789 +/*-------------------------------------------------------------------------*/
1790 +
1791 +static void invalidate_sub(struct fsg_lun *curlun)
1792 +{
1793 + struct file *filp = curlun->filp;
1794 + struct inode *inode = filp->f_path.dentry->d_inode;
1795 + unsigned long rc;
1796 +
1797 + rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
1798 + VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
1799 +}
1800 +
1801 +static int do_verify(struct fsg_dev *fsg)
1802 +{
1803 + struct fsg_lun *curlun = fsg->curlun;
1804 + u32 lba;
1805 + u32 verification_length;
1806 + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
1807 + loff_t file_offset, file_offset_tmp;
1808 + u32 amount_left;
1809 + unsigned int amount;
1810 + ssize_t nread;
1811 +
1812 + /* Get the starting Logical Block Address and check that it's
1813 + * not too big */
1814 + lba = get_unaligned_be32(&fsg->cmnd[2]);
1815 + if (lba >= curlun->num_sectors) {
1816 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1817 + return -EINVAL;
1818 + }
1819 +
1820 + /* We allow DPO (Disable Page Out = don't save data in the
1821 + * cache) but we don't implement it. */
1822 + if ((fsg->cmnd[1] & ~0x10) != 0) {
1823 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1824 + return -EINVAL;
1825 + }
1826 +
1827 + verification_length = get_unaligned_be16(&fsg->cmnd[7]);
1828 + if (unlikely(verification_length == 0))
1829 + return -EIO; // No default reply
1830 +
1831 + /* Prepare to carry out the file verify */
1832 + amount_left = verification_length << curlun->blkbits;
1833 + file_offset = ((loff_t) lba) << curlun->blkbits;
1834 +
1835 + /* Write out all the dirty buffers before invalidating them */
1836 + fsg_lun_fsync_sub(curlun);
1837 + if (signal_pending(current))
1838 + return -EINTR;
1839 +
1840 + invalidate_sub(curlun);
1841 + if (signal_pending(current))
1842 + return -EINTR;
1843 +
1844 + /* Just try to read the requested blocks */
1845 + while (amount_left > 0) {
1846 +
1847 + /* Figure out how much we need to read:
1848 + * Try to read the remaining amount, but not more than
1849 + * the buffer size.
1850 + * And don't try to read past the end of the file.
1851 + */
1852 + amount = min((unsigned int) amount_left, mod_data.buflen);
1853 + amount = min((loff_t) amount,
1854 + curlun->file_length - file_offset);
1855 + if (amount == 0) {
1856 + curlun->sense_data =
1857 + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1858 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1859 + curlun->info_valid = 1;
1860 + break;
1861 + }
1862 +
1863 + /* Perform the read */
1864 + file_offset_tmp = file_offset;
1865 + nread = vfs_read(curlun->filp,
1866 + (char __user *) bh->buf,
1867 + amount, &file_offset_tmp);
1868 + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
1869 + (unsigned long long) file_offset,
1870 + (int) nread);
1871 + if (signal_pending(current))
1872 + return -EINTR;
1873 +
1874 + if (nread < 0) {
1875 + LDBG(curlun, "error in file verify: %d\n",
1876 + (int) nread);
1877 + nread = 0;
1878 + } else if (nread < amount) {
1879 + LDBG(curlun, "partial file verify: %d/%u\n",
1880 + (int) nread, amount);
1881 + nread = round_down(nread, curlun->blksize);
1882 + }
1883 + if (nread == 0) {
1884 + curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
1885 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1886 + curlun->info_valid = 1;
1887 + break;
1888 + }
1889 + file_offset += nread;
1890 + amount_left -= nread;
1891 + }
1892 + return 0;
1893 +}
1894 +
1895 +
1896 +/*-------------------------------------------------------------------------*/
1897 +
1898 +static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
1899 +{
1900 + u8 *buf = (u8 *) bh->buf;
1901 +
1902 + static char vendor_id[] = "Linux ";
1903 + static char product_disk_id[] = "File-Stor Gadget";
1904 + static char product_cdrom_id[] = "File-CD Gadget ";
1905 +
1906 + if (!fsg->curlun) { // Unsupported LUNs are okay
1907 + fsg->bad_lun_okay = 1;
1908 + memset(buf, 0, 36);
1909 + buf[0] = 0x7f; // Unsupported, no device-type
1910 + buf[4] = 31; // Additional length
1911 + return 36;
1912 + }
1913 +
1914 + memset(buf, 0, 8);
1915 + buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK);
1916 + if (mod_data.removable)
1917 + buf[1] = 0x80;
1918 + buf[2] = 2; // ANSI SCSI level 2
1919 + buf[3] = 2; // SCSI-2 INQUIRY data format
1920 + buf[4] = 31; // Additional length
1921 + // No special options
1922 + sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
1923 + (mod_data.cdrom ? product_cdrom_id :
1924 + product_disk_id),
1925 + mod_data.release);
1926 + return 36;
1927 +}
1928 +
1929 +
1930 +static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
1931 +{
1932 + struct fsg_lun *curlun = fsg->curlun;
1933 + u8 *buf = (u8 *) bh->buf;
1934 + u32 sd, sdinfo;
1935 + int valid;
1936 +
1937 + /*
1938 + * From the SCSI-2 spec., section 7.9 (Unit attention condition):
1939 + *
1940 + * If a REQUEST SENSE command is received from an initiator
1941 + * with a pending unit attention condition (before the target
1942 + * generates the contingent allegiance condition), then the
1943 + * target shall either:
1944 + * a) report any pending sense data and preserve the unit
1945 + * attention condition on the logical unit, or,
1946 + * b) report the unit attention condition, may discard any
1947 + * pending sense data, and clear the unit attention
1948 + * condition on the logical unit for that initiator.
1949 + *
1950 + * FSG normally uses option a); enable this code to use option b).
1951 + */
1952 +#if 0
1953 + if (curlun && curlun->unit_attention_data != SS_NO_SENSE) {
1954 + curlun->sense_data = curlun->unit_attention_data;
1955 + curlun->unit_attention_data = SS_NO_SENSE;
1956 + }
1957 +#endif
1958 +
1959 + if (!curlun) { // Unsupported LUNs are okay
1960 + fsg->bad_lun_okay = 1;
1961 + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
1962 + sdinfo = 0;
1963 + valid = 0;
1964 + } else {
1965 + sd = curlun->sense_data;
1966 + sdinfo = curlun->sense_data_info;
1967 + valid = curlun->info_valid << 7;
1968 + curlun->sense_data = SS_NO_SENSE;
1969 + curlun->sense_data_info = 0;
1970 + curlun->info_valid = 0;
1971 + }
1972 +
1973 + memset(buf, 0, 18);
1974 + buf[0] = valid | 0x70; // Valid, current error
1975 + buf[2] = SK(sd);
1976 + put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */
1977 + buf[7] = 18 - 8; // Additional sense length
1978 + buf[12] = ASC(sd);
1979 + buf[13] = ASCQ(sd);
1980 + return 18;
1981 +}
1982 +
1983 +
1984 +static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
1985 +{
1986 + struct fsg_lun *curlun = fsg->curlun;
1987 + u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
1988 + int pmi = fsg->cmnd[8];
1989 + u8 *buf = (u8 *) bh->buf;
1990 +
1991 + /* Check the PMI and LBA fields */
1992 + if (pmi > 1 || (pmi == 0 && lba != 0)) {
1993 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1994 + return -EINVAL;
1995 + }
1996 +
1997 + put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
1998 + /* Max logical block */
1999 + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
2000 + return 8;
2001 +}
2002 +
2003 +
2004 +static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2005 +{
2006 + struct fsg_lun *curlun = fsg->curlun;
2007 + int msf = fsg->cmnd[1] & 0x02;
2008 + u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
2009 + u8 *buf = (u8 *) bh->buf;
2010 +
2011 + if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */
2012 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2013 + return -EINVAL;
2014 + }
2015 + if (lba >= curlun->num_sectors) {
2016 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
2017 + return -EINVAL;
2018 + }
2019 +
2020 + memset(buf, 0, 8);
2021 + buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */
2022 + store_cdrom_address(&buf[4], msf, lba);
2023 + return 8;
2024 +}
2025 +
2026 +
2027 +static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2028 +{
2029 + struct fsg_lun *curlun = fsg->curlun;
2030 + int msf = fsg->cmnd[1] & 0x02;
2031 + int start_track = fsg->cmnd[6];
2032 + u8 *buf = (u8 *) bh->buf;
2033 +
2034 + if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
2035 + start_track > 1) {
2036 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2037 + return -EINVAL;
2038 + }
2039 +
2040 + memset(buf, 0, 20);
2041 + buf[1] = (20-2); /* TOC data length */
2042 + buf[2] = 1; /* First track number */
2043 + buf[3] = 1; /* Last track number */
2044 + buf[5] = 0x16; /* Data track, copying allowed */
2045 + buf[6] = 0x01; /* Only track is number 1 */
2046 + store_cdrom_address(&buf[8], msf, 0);
2047 +
2048 + buf[13] = 0x16; /* Lead-out track is data */
2049 + buf[14] = 0xAA; /* Lead-out track number */
2050 + store_cdrom_address(&buf[16], msf, curlun->num_sectors);
2051 + return 20;
2052 +}
2053 +
2054 +
2055 +static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2056 +{
2057 + struct fsg_lun *curlun = fsg->curlun;
2058 + int mscmnd = fsg->cmnd[0];
2059 + u8 *buf = (u8 *) bh->buf;
2060 + u8 *buf0 = buf;
2061 + int pc, page_code;
2062 + int changeable_values, all_pages;
2063 + int valid_page = 0;
2064 + int len, limit;
2065 +
2066 + if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD
2067 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2068 + return -EINVAL;
2069 + }
2070 + pc = fsg->cmnd[2] >> 6;
2071 + page_code = fsg->cmnd[2] & 0x3f;
2072 + if (pc == 3) {
2073 + curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
2074 + return -EINVAL;
2075 + }
2076 + changeable_values = (pc == 1);
2077 + all_pages = (page_code == 0x3f);
2078 +
2079 + /* Write the mode parameter header. Fixed values are: default
2080 + * medium type, no cache control (DPOFUA), and no block descriptors.
2081 + * The only variable value is the WriteProtect bit. We will fill in
2082 + * the mode data length later. */
2083 + memset(buf, 0, 8);
2084 + if (mscmnd == MODE_SENSE) {
2085 + buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
2086 + buf += 4;
2087 + limit = 255;
2088 + } else { // MODE_SENSE_10
2089 + buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
2090 + buf += 8;
2091 + limit = 65535; // Should really be mod_data.buflen
2092 + }
2093 +
2094 + /* No block descriptors */
2095 +
2096 + /* The mode pages, in numerical order. The only page we support
2097 + * is the Caching page. */
2098 + if (page_code == 0x08 || all_pages) {
2099 + valid_page = 1;
2100 + buf[0] = 0x08; // Page code
2101 + buf[1] = 10; // Page length
2102 + memset(buf+2, 0, 10); // None of the fields are changeable
2103 +
2104 + if (!changeable_values) {
2105 + buf[2] = 0x04; // Write cache enable,
2106 + // Read cache not disabled
2107 + // No cache retention priorities
2108 + put_unaligned_be16(0xffff, &buf[4]);
2109 + /* Don't disable prefetch */
2110 + /* Minimum prefetch = 0 */
2111 + put_unaligned_be16(0xffff, &buf[8]);
2112 + /* Maximum prefetch */
2113 + put_unaligned_be16(0xffff, &buf[10]);
2114 + /* Maximum prefetch ceiling */
2115 + }
2116 + buf += 12;
2117 + }
2118 +
2119 + /* Check that a valid page was requested and the mode data length
2120 + * isn't too long. */
2121 + len = buf - buf0;
2122 + if (!valid_page || len > limit) {
2123 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2124 + return -EINVAL;
2125 + }
2126 +
2127 + /* Store the mode data length */
2128 + if (mscmnd == MODE_SENSE)
2129 + buf0[0] = len - 1;
2130 + else
2131 + put_unaligned_be16(len - 2, buf0);
2132 + return len;
2133 +}
2134 +
2135 +
2136 +static int do_start_stop(struct fsg_dev *fsg)
2137 +{
2138 + struct fsg_lun *curlun = fsg->curlun;
2139 + int loej, start;
2140 +
2141 + if (!mod_data.removable) {
2142 + curlun->sense_data = SS_INVALID_COMMAND;
2143 + return -EINVAL;
2144 + }
2145 +
2146 + // int immed = fsg->cmnd[1] & 0x01;
2147 + loej = fsg->cmnd[4] & 0x02;
2148 + start = fsg->cmnd[4] & 0x01;
2149 +
2150 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
2151 + if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed
2152 + (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start
2153 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2154 + return -EINVAL;
2155 + }
2156 +
2157 + if (!start) {
2158 +
2159 + /* Are we allowed to unload the media? */
2160 + if (curlun->prevent_medium_removal) {
2161 + LDBG(curlun, "unload attempt prevented\n");
2162 + curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
2163 + return -EINVAL;
2164 + }
2165 + if (loej) { // Simulate an unload/eject
2166 + up_read(&fsg->filesem);
2167 + down_write(&fsg->filesem);
2168 + fsg_lun_close(curlun);
2169 + up_write(&fsg->filesem);
2170 + down_read(&fsg->filesem);
2171 + }
2172 + } else {
2173 +
2174 + /* Our emulation doesn't support mounting; the medium is
2175 + * available for use as soon as it is loaded. */
2176 + if (!fsg_lun_is_open(curlun)) {
2177 + curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
2178 + return -EINVAL;
2179 + }
2180 + }
2181 +#endif
2182 + return 0;
2183 +}
2184 +
2185 +
2186 +static int do_prevent_allow(struct fsg_dev *fsg)
2187 +{
2188 + struct fsg_lun *curlun = fsg->curlun;
2189 + int prevent;
2190 +
2191 + if (!mod_data.removable) {
2192 + curlun->sense_data = SS_INVALID_COMMAND;
2193 + return -EINVAL;
2194 + }
2195 +
2196 + prevent = fsg->cmnd[4] & 0x01;
2197 + if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent
2198 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2199 + return -EINVAL;
2200 + }
2201 +
2202 + if (curlun->prevent_medium_removal && !prevent)
2203 + fsg_lun_fsync_sub(curlun);
2204 + curlun->prevent_medium_removal = prevent;
2205 + return 0;
2206 +}
2207 +
2208 +
2209 +static int do_read_format_capacities(struct fsg_dev *fsg,
2210 + struct fsg_buffhd *bh)
2211 +{
2212 + struct fsg_lun *curlun = fsg->curlun;
2213 + u8 *buf = (u8 *) bh->buf;
2214 +
2215 + buf[0] = buf[1] = buf[2] = 0;
2216 + buf[3] = 8; // Only the Current/Maximum Capacity Descriptor
2217 + buf += 4;
2218 +
2219 + put_unaligned_be32(curlun->num_sectors, &buf[0]);
2220 + /* Number of blocks */
2221 + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
2222 + buf[4] = 0x02; /* Current capacity */
2223 + return 12;
2224 +}
2225 +
2226 +
2227 +static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2228 +{
2229 + struct fsg_lun *curlun = fsg->curlun;
2230 +
2231 + /* We don't support MODE SELECT */
2232 + curlun->sense_data = SS_INVALID_COMMAND;
2233 + return -EINVAL;
2234 +}
2235 +
2236 +
2237 +/*-------------------------------------------------------------------------*/
2238 +
2239 +static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
2240 +{
2241 + int rc;
2242 +
2243 + rc = fsg_set_halt(fsg, fsg->bulk_in);
2244 + if (rc == -EAGAIN)
2245 + VDBG(fsg, "delayed bulk-in endpoint halt\n");
2246 + while (rc != 0) {
2247 + if (rc != -EAGAIN) {
2248 + WARNING(fsg, "usb_ep_set_halt -> %d\n", rc);
2249 + rc = 0;
2250 + break;
2251 + }
2252 +
2253 + /* Wait for a short time and then try again */
2254 + if (msleep_interruptible(100) != 0)
2255 + return -EINTR;
2256 + rc = usb_ep_set_halt(fsg->bulk_in);
2257 + }
2258 + return rc;
2259 +}
2260 +
2261 +static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
2262 +{
2263 + int rc;
2264 +
2265 + DBG(fsg, "bulk-in set wedge\n");
2266 + rc = usb_ep_set_wedge(fsg->bulk_in);
2267 + if (rc == -EAGAIN)
2268 + VDBG(fsg, "delayed bulk-in endpoint wedge\n");
2269 + while (rc != 0) {
2270 + if (rc != -EAGAIN) {
2271 + WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc);
2272 + rc = 0;
2273 + break;
2274 + }
2275 +
2276 + /* Wait for a short time and then try again */
2277 + if (msleep_interruptible(100) != 0)
2278 + return -EINTR;
2279 + rc = usb_ep_set_wedge(fsg->bulk_in);
2280 + }
2281 + return rc;
2282 +}
2283 +
2284 +static int throw_away_data(struct fsg_dev *fsg)
2285 +{
2286 + struct fsg_buffhd *bh;
2287 + u32 amount;
2288 + int rc;
2289 +
2290 + while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY ||
2291 + fsg->usb_amount_left > 0) {
2292 +
2293 + /* Throw away the data in a filled buffer */
2294 + if (bh->state == BUF_STATE_FULL) {
2295 + smp_rmb();
2296 + bh->state = BUF_STATE_EMPTY;
2297 + fsg->next_buffhd_to_drain = bh->next;
2298 +
2299 + /* A short packet or an error ends everything */
2300 + if (bh->outreq->actual < bh->bulk_out_intended_length ||
2301 + bh->outreq->status != 0) {
2302 + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
2303 + return -EINTR;
2304 + }
2305 + continue;
2306 + }
2307 +
2308 + /* Try to submit another request if we need one */
2309 + bh = fsg->next_buffhd_to_fill;
2310 + if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) {
2311 + amount = min(fsg->usb_amount_left,
2312 + (u32) mod_data.buflen);
2313 +
2314 + /* Except at the end of the transfer, amount will be
2315 + * equal to the buffer size, which is divisible by
2316 + * the bulk-out maxpacket size.
2317 + */
2318 + set_bulk_out_req_length(fsg, bh, amount);
2319 + start_transfer(fsg, fsg->bulk_out, bh->outreq,
2320 + &bh->outreq_busy, &bh->state);
2321 + fsg->next_buffhd_to_fill = bh->next;
2322 + fsg->usb_amount_left -= amount;
2323 + continue;
2324 + }
2325 +
2326 + /* Otherwise wait for something to happen */
2327 + rc = sleep_thread(fsg);
2328 + if (rc)
2329 + return rc;
2330 + }
2331 + return 0;
2332 +}
2333 +
2334 +
2335 +static int finish_reply(struct fsg_dev *fsg)
2336 +{
2337 + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
2338 + int rc = 0;
2339 +
2340 + switch (fsg->data_dir) {
2341 + case DATA_DIR_NONE:
2342 + break; // Nothing to send
2343 +
2344 + /* If we don't know whether the host wants to read or write,
2345 + * this must be CB or CBI with an unknown command. We mustn't
2346 + * try to send or receive any data. So stall both bulk pipes
2347 + * if we can and wait for a reset. */
2348 + case DATA_DIR_UNKNOWN:
2349 + if (mod_data.can_stall) {
2350 + fsg_set_halt(fsg, fsg->bulk_out);
2351 + rc = halt_bulk_in_endpoint(fsg);
2352 + }
2353 + break;
2354 +
2355 + /* All but the last buffer of data must have already been sent */
2356 + case DATA_DIR_TO_HOST:
2357 + if (fsg->data_size == 0)
2358 + ; // Nothing to send
2359 +
2360 + /* If there's no residue, simply send the last buffer */
2361 + else if (fsg->residue == 0) {
2362 + bh->inreq->zero = 0;
2363 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2364 + &bh->inreq_busy, &bh->state);
2365 + fsg->next_buffhd_to_fill = bh->next;
2366 + }
2367 +
2368 + /* There is a residue. For CB and CBI, simply mark the end
2369 + * of the data with a short packet. However, if we are
2370 + * allowed to stall, there was no data at all (residue ==
2371 + * data_size), and the command failed (invalid LUN or
2372 + * sense data is set), then halt the bulk-in endpoint
2373 + * instead. */
2374 + else if (!transport_is_bbb()) {
2375 + if (mod_data.can_stall &&
2376 + fsg->residue == fsg->data_size &&
2377 + (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) {
2378 + bh->state = BUF_STATE_EMPTY;
2379 + rc = halt_bulk_in_endpoint(fsg);
2380 + } else {
2381 + bh->inreq->zero = 1;
2382 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2383 + &bh->inreq_busy, &bh->state);
2384 + fsg->next_buffhd_to_fill = bh->next;
2385 + }
2386 + }
2387 +
2388 + /*
2389 + * For Bulk-only, mark the end of the data with a short
2390 + * packet. If we are allowed to stall, halt the bulk-in
2391 + * endpoint. (Note: This violates the Bulk-Only Transport
2392 + * specification, which requires us to pad the data if we
2393 + * don't halt the endpoint. Presumably nobody will mind.)
2394 + */
2395 + else {
2396 + bh->inreq->zero = 1;
2397 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2398 + &bh->inreq_busy, &bh->state);
2399 + fsg->next_buffhd_to_fill = bh->next;
2400 + if (mod_data.can_stall)
2401 + rc = halt_bulk_in_endpoint(fsg);
2402 + }
2403 + break;
2404 +
2405 + /* We have processed all we want from the data the host has sent.
2406 + * There may still be outstanding bulk-out requests. */
2407 + case DATA_DIR_FROM_HOST:
2408 + if (fsg->residue == 0)
2409 + ; // Nothing to receive
2410 +
2411 + /* Did the host stop sending unexpectedly early? */
2412 + else if (fsg->short_packet_received) {
2413 + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
2414 + rc = -EINTR;
2415 + }
2416 +
2417 + /* We haven't processed all the incoming data. Even though
2418 + * we may be allowed to stall, doing so would cause a race.
2419 + * The controller may already have ACK'ed all the remaining
2420 + * bulk-out packets, in which case the host wouldn't see a
2421 + * STALL. Not realizing the endpoint was halted, it wouldn't
2422 + * clear the halt -- leading to problems later on. */
2423 +#if 0
2424 + else if (mod_data.can_stall) {
2425 + fsg_set_halt(fsg, fsg->bulk_out);
2426 + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
2427 + rc = -EINTR;
2428 + }
2429 +#endif
2430 +
2431 + /* We can't stall. Read in the excess data and throw it
2432 + * all away. */
2433 + else
2434 + rc = throw_away_data(fsg);
2435 + break;
2436 + }
2437 + return rc;
2438 +}
2439 +
2440 +
2441 +static int send_status(struct fsg_dev *fsg)
2442 +{
2443 + struct fsg_lun *curlun = fsg->curlun;
2444 + struct fsg_buffhd *bh;
2445 + int rc;
2446 + u8 status = US_BULK_STAT_OK;
2447 + u32 sd, sdinfo = 0;
2448 +
2449 + /* Wait for the next buffer to become available */
2450 + bh = fsg->next_buffhd_to_fill;
2451 + while (bh->state != BUF_STATE_EMPTY) {
2452 + rc = sleep_thread(fsg);
2453 + if (rc)
2454 + return rc;
2455 + }
2456 +
2457 + if (curlun) {
2458 + sd = curlun->sense_data;
2459 + sdinfo = curlun->sense_data_info;
2460 + } else if (fsg->bad_lun_okay)
2461 + sd = SS_NO_SENSE;
2462 + else
2463 + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
2464 +
2465 + if (fsg->phase_error) {
2466 + DBG(fsg, "sending phase-error status\n");
2467 + status = US_BULK_STAT_PHASE;
2468 + sd = SS_INVALID_COMMAND;
2469 + } else if (sd != SS_NO_SENSE) {
2470 + DBG(fsg, "sending command-failure status\n");
2471 + status = US_BULK_STAT_FAIL;
2472 + VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
2473 + " info x%x\n",
2474 + SK(sd), ASC(sd), ASCQ(sd), sdinfo);
2475 + }
2476 +
2477 + if (transport_is_bbb()) {
2478 + struct bulk_cs_wrap *csw = bh->buf;
2479 +
2480 + /* Store and send the Bulk-only CSW */
2481 + csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
2482 + csw->Tag = fsg->tag;
2483 + csw->Residue = cpu_to_le32(fsg->residue);
2484 + csw->Status = status;
2485 +
2486 + bh->inreq->length = US_BULK_CS_WRAP_LEN;
2487 + bh->inreq->zero = 0;
2488 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2489 + &bh->inreq_busy, &bh->state);
2490 +
2491 + } else if (mod_data.transport_type == USB_PR_CB) {
2492 +
2493 + /* Control-Bulk transport has no status phase! */
2494 + return 0;
2495 +
2496 + } else { // USB_PR_CBI
2497 + struct interrupt_data *buf = bh->buf;
2498 +
2499 + /* Store and send the Interrupt data. UFI sends the ASC
2500 + * and ASCQ bytes. Everything else sends a Type (which
2501 + * is always 0) and the status Value. */
2502 + if (mod_data.protocol_type == USB_SC_UFI) {
2503 + buf->bType = ASC(sd);
2504 + buf->bValue = ASCQ(sd);
2505 + } else {
2506 + buf->bType = 0;
2507 + buf->bValue = status;
2508 + }
2509 + fsg->intreq->length = CBI_INTERRUPT_DATA_LEN;
2510 +
2511 + fsg->intr_buffhd = bh; // Point to the right buffhd
2512 + fsg->intreq->buf = bh->inreq->buf;
2513 + fsg->intreq->context = bh;
2514 + start_transfer(fsg, fsg->intr_in, fsg->intreq,
2515 + &fsg->intreq_busy, &bh->state);
2516 + }
2517 +
2518 + fsg->next_buffhd_to_fill = bh->next;
2519 + return 0;
2520 +}
2521 +
2522 +
2523 +/*-------------------------------------------------------------------------*/
2524 +
2525 +/* Check whether the command is properly formed and whether its data size
2526 + * and direction agree with the values we already have. */
2527 +static int check_command(struct fsg_dev *fsg, int cmnd_size,
2528 + enum data_direction data_dir, unsigned int mask,
2529 + int needs_medium, const char *name)
2530 +{
2531 + int i;
2532 + int lun = fsg->cmnd[1] >> 5;
2533 + static const char dirletter[4] = {'u', 'o', 'i', 'n'};
2534 + char hdlen[20];
2535 + struct fsg_lun *curlun;
2536 +
2537 + /* Adjust the expected cmnd_size for protocol encapsulation padding.
2538 + * Transparent SCSI doesn't pad. */
2539 + if (protocol_is_scsi())
2540 + ;
2541 +
2542 + /* There's some disagreement as to whether RBC pads commands or not.
2543 + * We'll play it safe and accept either form. */
2544 + else if (mod_data.protocol_type == USB_SC_RBC) {
2545 + if (fsg->cmnd_size == 12)
2546 + cmnd_size = 12;
2547 +
2548 + /* All the other protocols pad to 12 bytes */
2549 + } else
2550 + cmnd_size = 12;
2551 +
2552 + hdlen[0] = 0;
2553 + if (fsg->data_dir != DATA_DIR_UNKNOWN)
2554 + sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir],
2555 + fsg->data_size);
2556 + VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n",
2557 + name, cmnd_size, dirletter[(int) data_dir],
2558 + fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen);
2559 +
2560 + /* We can't reply at all until we know the correct data direction
2561 + * and size. */
2562 + if (fsg->data_size_from_cmnd == 0)
2563 + data_dir = DATA_DIR_NONE;
2564 + if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI
2565 + fsg->data_dir = data_dir;
2566 + fsg->data_size = fsg->data_size_from_cmnd;
2567 +
2568 + } else { // Bulk-only
2569 + if (fsg->data_size < fsg->data_size_from_cmnd) {
2570 +
2571 + /* Host data size < Device data size is a phase error.
2572 + * Carry out the command, but only transfer as much
2573 + * as we are allowed. */
2574 + fsg->data_size_from_cmnd = fsg->data_size;
2575 + fsg->phase_error = 1;
2576 + }
2577 + }
2578 + fsg->residue = fsg->usb_amount_left = fsg->data_size;
2579 +
2580 + /* Conflicting data directions is a phase error */
2581 + if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) {
2582 + fsg->phase_error = 1;
2583 + return -EINVAL;
2584 + }
2585 +
2586 + /* Verify the length of the command itself */
2587 + if (cmnd_size != fsg->cmnd_size) {
2588 +
2589 + /* Special case workaround: There are plenty of buggy SCSI
2590 + * implementations. Many have issues with cbw->Length
2591 + * field passing a wrong command size. For those cases we
2592 + * always try to work around the problem by using the length
2593 + * sent by the host side provided it is at least as large
2594 + * as the correct command length.
2595 + * Examples of such cases would be MS-Windows, which issues
2596 + * REQUEST SENSE with cbw->Length == 12 where it should
2597 + * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and
2598 + * REQUEST SENSE with cbw->Length == 10 where it should
2599 + * be 6 as well.
2600 + */
2601 + if (cmnd_size <= fsg->cmnd_size) {
2602 + DBG(fsg, "%s is buggy! Expected length %d "
2603 + "but we got %d\n", name,
2604 + cmnd_size, fsg->cmnd_size);
2605 + cmnd_size = fsg->cmnd_size;
2606 + } else {
2607 + fsg->phase_error = 1;
2608 + return -EINVAL;
2609 + }
2610 + }
2611 +
2612 + /* Check that the LUN values are consistent */
2613 + if (transport_is_bbb()) {
2614 + if (fsg->lun != lun)
2615 + DBG(fsg, "using LUN %d from CBW, "
2616 + "not LUN %d from CDB\n",
2617 + fsg->lun, lun);
2618 + }
2619 +
2620 + /* Check the LUN */
2621 + curlun = fsg->curlun;
2622 + if (curlun) {
2623 + if (fsg->cmnd[0] != REQUEST_SENSE) {
2624 + curlun->sense_data = SS_NO_SENSE;
2625 + curlun->sense_data_info = 0;
2626 + curlun->info_valid = 0;
2627 + }
2628 + } else {
2629 + fsg->bad_lun_okay = 0;
2630 +
2631 + /* INQUIRY and REQUEST SENSE commands are explicitly allowed
2632 + * to use unsupported LUNs; all others may not. */
2633 + if (fsg->cmnd[0] != INQUIRY &&
2634 + fsg->cmnd[0] != REQUEST_SENSE) {
2635 + DBG(fsg, "unsupported LUN %d\n", fsg->lun);
2636 + return -EINVAL;
2637 + }
2638 + }
2639 +
2640 + /* If a unit attention condition exists, only INQUIRY and
2641 + * REQUEST SENSE commands are allowed; anything else must fail. */
2642 + if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
2643 + fsg->cmnd[0] != INQUIRY &&
2644 + fsg->cmnd[0] != REQUEST_SENSE) {
2645 + curlun->sense_data = curlun->unit_attention_data;
2646 + curlun->unit_attention_data = SS_NO_SENSE;
2647 + return -EINVAL;
2648 + }
2649 +
2650 + /* Check that only command bytes listed in the mask are non-zero */
2651 + fsg->cmnd[1] &= 0x1f; // Mask away the LUN
2652 + for (i = 1; i < cmnd_size; ++i) {
2653 + if (fsg->cmnd[i] && !(mask & (1 << i))) {
2654 + if (curlun)
2655 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2656 + return -EINVAL;
2657 + }
2658 + }
2659 +
2660 + /* If the medium isn't mounted and the command needs to access
2661 + * it, return an error. */
2662 + if (curlun && !fsg_lun_is_open(curlun) && needs_medium) {
2663 + curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
2664 + return -EINVAL;
2665 + }
2666 +
2667 + return 0;
2668 +}
2669 +
2670 +/* wrapper of check_command for data size in blocks handling */
2671 +static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size,
2672 + enum data_direction data_dir, unsigned int mask,
2673 + int needs_medium, const char *name)
2674 +{
2675 + if (fsg->curlun)
2676 + fsg->data_size_from_cmnd <<= fsg->curlun->blkbits;
2677 + return check_command(fsg, cmnd_size, data_dir,
2678 + mask, needs_medium, name);
2679 +}
2680 +
2681 +static int do_scsi_command(struct fsg_dev *fsg)
2682 +{
2683 + struct fsg_buffhd *bh;
2684 + int rc;
2685 + int reply = -EINVAL;
2686 + int i;
2687 + static char unknown[16];
2688 +
2689 + dump_cdb(fsg);
2690 +
2691 + /* Wait for the next buffer to become available for data or status */
2692 + bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
2693 + while (bh->state != BUF_STATE_EMPTY) {
2694 + rc = sleep_thread(fsg);
2695 + if (rc)
2696 + return rc;
2697 + }
2698 + fsg->phase_error = 0;
2699 + fsg->short_packet_received = 0;
2700 +
2701 + down_read(&fsg->filesem); // We're using the backing file
2702 + switch (fsg->cmnd[0]) {
2703 +
2704 + case INQUIRY:
2705 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2706 + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
2707 + (1<<4), 0,
2708 + "INQUIRY")) == 0)
2709 + reply = do_inquiry(fsg, bh);
2710 + break;
2711 +
2712 + case MODE_SELECT:
2713 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2714 + if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
2715 + (1<<1) | (1<<4), 0,
2716 + "MODE SELECT(6)")) == 0)
2717 + reply = do_mode_select(fsg, bh);
2718 + break;
2719 +
2720 + case MODE_SELECT_10:
2721 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2722 + if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
2723 + (1<<1) | (3<<7), 0,
2724 + "MODE SELECT(10)")) == 0)
2725 + reply = do_mode_select(fsg, bh);
2726 + break;
2727 +
2728 + case MODE_SENSE:
2729 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2730 + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
2731 + (1<<1) | (1<<2) | (1<<4), 0,
2732 + "MODE SENSE(6)")) == 0)
2733 + reply = do_mode_sense(fsg, bh);
2734 + break;
2735 +
2736 + case MODE_SENSE_10:
2737 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2738 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2739 + (1<<1) | (1<<2) | (3<<7), 0,
2740 + "MODE SENSE(10)")) == 0)
2741 + reply = do_mode_sense(fsg, bh);
2742 + break;
2743 +
2744 + case ALLOW_MEDIUM_REMOVAL:
2745 + fsg->data_size_from_cmnd = 0;
2746 + if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
2747 + (1<<4), 0,
2748 + "PREVENT-ALLOW MEDIUM REMOVAL")) == 0)
2749 + reply = do_prevent_allow(fsg);
2750 + break;
2751 +
2752 + case READ_6:
2753 + i = fsg->cmnd[4];
2754 + fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
2755 + if ((reply = check_command_size_in_blocks(fsg, 6,
2756 + DATA_DIR_TO_HOST,
2757 + (7<<1) | (1<<4), 1,
2758 + "READ(6)")) == 0)
2759 + reply = do_read(fsg);
2760 + break;
2761 +
2762 + case READ_10:
2763 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2764 + if ((reply = check_command_size_in_blocks(fsg, 10,
2765 + DATA_DIR_TO_HOST,
2766 + (1<<1) | (0xf<<2) | (3<<7), 1,
2767 + "READ(10)")) == 0)
2768 + reply = do_read(fsg);
2769 + break;
2770 +
2771 + case READ_12:
2772 + fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
2773 + if ((reply = check_command_size_in_blocks(fsg, 12,
2774 + DATA_DIR_TO_HOST,
2775 + (1<<1) | (0xf<<2) | (0xf<<6), 1,
2776 + "READ(12)")) == 0)
2777 + reply = do_read(fsg);
2778 + break;
2779 +
2780 + case READ_CAPACITY:
2781 + fsg->data_size_from_cmnd = 8;
2782 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2783 + (0xf<<2) | (1<<8), 1,
2784 + "READ CAPACITY")) == 0)
2785 + reply = do_read_capacity(fsg, bh);
2786 + break;
2787 +
2788 + case READ_HEADER:
2789 + if (!mod_data.cdrom)
2790 + goto unknown_cmnd;
2791 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2792 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2793 + (3<<7) | (0x1f<<1), 1,
2794 + "READ HEADER")) == 0)
2795 + reply = do_read_header(fsg, bh);
2796 + break;
2797 +
2798 + case READ_TOC:
2799 + if (!mod_data.cdrom)
2800 + goto unknown_cmnd;
2801 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2802 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2803 + (7<<6) | (1<<1), 1,
2804 + "READ TOC")) == 0)
2805 + reply = do_read_toc(fsg, bh);
2806 + break;
2807 +
2808 + case READ_FORMAT_CAPACITIES:
2809 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2810 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2811 + (3<<7), 1,
2812 + "READ FORMAT CAPACITIES")) == 0)
2813 + reply = do_read_format_capacities(fsg, bh);
2814 + break;
2815 +
2816 + case REQUEST_SENSE:
2817 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2818 + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
2819 + (1<<4), 0,
2820 + "REQUEST SENSE")) == 0)
2821 + reply = do_request_sense(fsg, bh);
2822 + break;
2823 +
2824 + case START_STOP:
2825 + fsg->data_size_from_cmnd = 0;
2826 + if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
2827 + (1<<1) | (1<<4), 0,
2828 + "START-STOP UNIT")) == 0)
2829 + reply = do_start_stop(fsg);
2830 + break;
2831 +
2832 + case SYNCHRONIZE_CACHE:
2833 + fsg->data_size_from_cmnd = 0;
2834 + if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
2835 + (0xf<<2) | (3<<7), 1,
2836 + "SYNCHRONIZE CACHE")) == 0)
2837 + reply = do_synchronize_cache(fsg);
2838 + break;
2839 +
2840 + case TEST_UNIT_READY:
2841 + fsg->data_size_from_cmnd = 0;
2842 + reply = check_command(fsg, 6, DATA_DIR_NONE,
2843 + 0, 1,
2844 + "TEST UNIT READY");
2845 + break;
2846 +
2847 + /* Although optional, this command is used by MS-Windows. We
2848 + * support a minimal version: BytChk must be 0. */
2849 + case VERIFY:
2850 + fsg->data_size_from_cmnd = 0;
2851 + if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
2852 + (1<<1) | (0xf<<2) | (3<<7), 1,
2853 + "VERIFY")) == 0)
2854 + reply = do_verify(fsg);
2855 + break;
2856 +
2857 + case WRITE_6:
2858 + i = fsg->cmnd[4];
2859 + fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
2860 + if ((reply = check_command_size_in_blocks(fsg, 6,
2861 + DATA_DIR_FROM_HOST,
2862 + (7<<1) | (1<<4), 1,
2863 + "WRITE(6)")) == 0)
2864 + reply = do_write(fsg);
2865 + break;
2866 +
2867 + case WRITE_10:
2868 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2869 + if ((reply = check_command_size_in_blocks(fsg, 10,
2870 + DATA_DIR_FROM_HOST,
2871 + (1<<1) | (0xf<<2) | (3<<7), 1,
2872 + "WRITE(10)")) == 0)
2873 + reply = do_write(fsg);
2874 + break;
2875 +
2876 + case WRITE_12:
2877 + fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
2878 + if ((reply = check_command_size_in_blocks(fsg, 12,
2879 + DATA_DIR_FROM_HOST,
2880 + (1<<1) | (0xf<<2) | (0xf<<6), 1,
2881 + "WRITE(12)")) == 0)
2882 + reply = do_write(fsg);
2883 + break;
2884 +
2885 + /* Some mandatory commands that we recognize but don't implement.
2886 + * They don't mean much in this setting. It's left as an exercise
2887 + * for anyone interested to implement RESERVE and RELEASE in terms
2888 + * of Posix locks. */
2889 + case FORMAT_UNIT:
2890 + case RELEASE:
2891 + case RESERVE:
2892 + case SEND_DIAGNOSTIC:
2893 + // Fall through
2894 +
2895 + default:
2896 + unknown_cmnd:
2897 + fsg->data_size_from_cmnd = 0;
2898 + sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]);
2899 + if ((reply = check_command(fsg, fsg->cmnd_size,
2900 + DATA_DIR_UNKNOWN, ~0, 0, unknown)) == 0) {
2901 + fsg->curlun->sense_data = SS_INVALID_COMMAND;
2902 + reply = -EINVAL;
2903 + }
2904 + break;
2905 + }
2906 + up_read(&fsg->filesem);
2907 +
2908 + if (reply == -EINTR || signal_pending(current))
2909 + return -EINTR;
2910 +
2911 + /* Set up the single reply buffer for finish_reply() */
2912 + if (reply == -EINVAL)
2913 + reply = 0; // Error reply length
2914 + if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) {
2915 + reply = min((u32) reply, fsg->data_size_from_cmnd);
2916 + bh->inreq->length = reply;
2917 + bh->state = BUF_STATE_FULL;
2918 + fsg->residue -= reply;
2919 + } // Otherwise it's already set
2920 +
2921 + return 0;
2922 +}
2923 +
2924 +
2925 +/*-------------------------------------------------------------------------*/
2926 +
2927 +static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2928 +{
2929 + struct usb_request *req = bh->outreq;
2930 + struct bulk_cb_wrap *cbw = req->buf;
2931 +
2932 + /* Was this a real packet? Should it be ignored? */
2933 + if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
2934 + return -EINVAL;
2935 +
2936 + /* Is the CBW valid? */
2937 + if (req->actual != US_BULK_CB_WRAP_LEN ||
2938 + cbw->Signature != cpu_to_le32(
2939 + US_BULK_CB_SIGN)) {
2940 + DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
2941 + req->actual,
2942 + le32_to_cpu(cbw->Signature));
2943 +
2944 + /* The Bulk-only spec says we MUST stall the IN endpoint
2945 + * (6.6.1), so it's unavoidable. It also says we must
2946 + * retain this state until the next reset, but there's
2947 + * no way to tell the controller driver it should ignore
2948 + * Clear-Feature(HALT) requests.
2949 + *
2950 + * We aren't required to halt the OUT endpoint; instead
2951 + * we can simply accept and discard any data received
2952 + * until the next reset. */
2953 + wedge_bulk_in_endpoint(fsg);
2954 + set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
2955 + return -EINVAL;
2956 + }
2957 +
2958 + /* Is the CBW meaningful? */
2959 + if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
2960 + cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
2961 + DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
2962 + "cmdlen %u\n",
2963 + cbw->Lun, cbw->Flags, cbw->Length);
2964 +
2965 + /* We can do anything we want here, so let's stall the
2966 + * bulk pipes if we are allowed to. */
2967 + if (mod_data.can_stall) {
2968 + fsg_set_halt(fsg, fsg->bulk_out);
2969 + halt_bulk_in_endpoint(fsg);
2970 + }
2971 + return -EINVAL;
2972 + }
2973 +
2974 + /* Save the command for later */
2975 + fsg->cmnd_size = cbw->Length;
2976 + memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size);
2977 + if (cbw->Flags & US_BULK_FLAG_IN)
2978 + fsg->data_dir = DATA_DIR_TO_HOST;
2979 + else
2980 + fsg->data_dir = DATA_DIR_FROM_HOST;
2981 + fsg->data_size = le32_to_cpu(cbw->DataTransferLength);
2982 + if (fsg->data_size == 0)
2983 + fsg->data_dir = DATA_DIR_NONE;
2984 + fsg->lun = cbw->Lun;
2985 + fsg->tag = cbw->Tag;
2986 + return 0;
2987 +}
2988 +
2989 +
2990 +static int get_next_command(struct fsg_dev *fsg)
2991 +{
2992 + struct fsg_buffhd *bh;
2993 + int rc = 0;
2994 +
2995 + if (transport_is_bbb()) {
2996 +
2997 + /* Wait for the next buffer to become available */
2998 + bh = fsg->next_buffhd_to_fill;
2999 + while (bh->state != BUF_STATE_EMPTY) {
3000 + rc = sleep_thread(fsg);
3001 + if (rc)
3002 + return rc;
3003 + }
3004 +
3005 + /* Queue a request to read a Bulk-only CBW */
3006 + set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN);
3007 + start_transfer(fsg, fsg->bulk_out, bh->outreq,
3008 + &bh->outreq_busy, &bh->state);
3009 +
3010 + /* We will drain the buffer in software, which means we
3011 + * can reuse it for the next filling. No need to advance
3012 + * next_buffhd_to_fill. */
3013 +
3014 + /* Wait for the CBW to arrive */
3015 + while (bh->state != BUF_STATE_FULL) {
3016 + rc = sleep_thread(fsg);
3017 + if (rc)
3018 + return rc;
3019 + }
3020 + smp_rmb();
3021 + rc = received_cbw(fsg, bh);
3022 + bh->state = BUF_STATE_EMPTY;
3023 +
3024 + } else { // USB_PR_CB or USB_PR_CBI
3025 +
3026 + /* Wait for the next command to arrive */
3027 + while (fsg->cbbuf_cmnd_size == 0) {
3028 + rc = sleep_thread(fsg);
3029 + if (rc)
3030 + return rc;
3031 + }
3032 +
3033 + /* Is the previous status interrupt request still busy?
3034 + * The host is allowed to skip reading the status,
3035 + * so we must cancel it. */
3036 + if (fsg->intreq_busy)
3037 + usb_ep_dequeue(fsg->intr_in, fsg->intreq);
3038 +
3039 + /* Copy the command and mark the buffer empty */
3040 + fsg->data_dir = DATA_DIR_UNKNOWN;
3041 + spin_lock_irq(&fsg->lock);
3042 + fsg->cmnd_size = fsg->cbbuf_cmnd_size;
3043 + memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size);
3044 + fsg->cbbuf_cmnd_size = 0;
3045 + spin_unlock_irq(&fsg->lock);
3046 +
3047 + /* Use LUN from the command */
3048 + fsg->lun = fsg->cmnd[1] >> 5;
3049 + }
3050 +
3051 + /* Update current lun */
3052 + if (fsg->lun >= 0 && fsg->lun < fsg->nluns)
3053 + fsg->curlun = &fsg->luns[fsg->lun];
3054 + else
3055 + fsg->curlun = NULL;
3056 +
3057 + return rc;
3058 +}
3059 +
3060 +
3061 +/*-------------------------------------------------------------------------*/
3062 +
3063 +static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,
3064 + const struct usb_endpoint_descriptor *d)
3065 +{
3066 + int rc;
3067 +
3068 + ep->driver_data = fsg;
3069 + ep->desc = d;
3070 + rc = usb_ep_enable(ep);
3071 + if (rc)
3072 + ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
3073 + return rc;
3074 +}
3075 +
3076 +static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep,
3077 + struct usb_request **preq)
3078 +{
3079 + *preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
3080 + if (*preq)
3081 + return 0;
3082 + ERROR(fsg, "can't allocate request for %s\n", ep->name);
3083 + return -ENOMEM;
3084 +}
3085 +
3086 +/*
3087 + * Reset interface setting and re-init endpoint state (toggle etc).
3088 + * Call with altsetting < 0 to disable the interface. The only other
3089 + * available altsetting is 0, which enables the interface.
3090 + */
3091 +static int do_set_interface(struct fsg_dev *fsg, int altsetting)
3092 +{
3093 + int rc = 0;
3094 + int i;
3095 + const struct usb_endpoint_descriptor *d;
3096 +
3097 + if (fsg->running)
3098 + DBG(fsg, "reset interface\n");
3099 +
3100 +reset:
3101 + /* Deallocate the requests */
3102 + for (i = 0; i < fsg_num_buffers; ++i) {
3103 + struct fsg_buffhd *bh = &fsg->buffhds[i];
3104 +
3105 + if (bh->inreq) {
3106 + usb_ep_free_request(fsg->bulk_in, bh->inreq);
3107 + bh->inreq = NULL;
3108 + }
3109 + if (bh->outreq) {
3110 + usb_ep_free_request(fsg->bulk_out, bh->outreq);
3111 + bh->outreq = NULL;
3112 + }
3113 + }
3114 + if (fsg->intreq) {
3115 + usb_ep_free_request(fsg->intr_in, fsg->intreq);
3116 + fsg->intreq = NULL;
3117 + }
3118 +
3119 + /* Disable the endpoints */
3120 + if (fsg->bulk_in_enabled) {
3121 + usb_ep_disable(fsg->bulk_in);
3122 + fsg->bulk_in_enabled = 0;
3123 + }
3124 + if (fsg->bulk_out_enabled) {
3125 + usb_ep_disable(fsg->bulk_out);
3126 + fsg->bulk_out_enabled = 0;
3127 + }
3128 + if (fsg->intr_in_enabled) {
3129 + usb_ep_disable(fsg->intr_in);
3130 + fsg->intr_in_enabled = 0;
3131 + }
3132 +
3133 + fsg->running = 0;
3134 + if (altsetting < 0 || rc != 0)
3135 + return rc;
3136 +
3137 + DBG(fsg, "set interface %d\n", altsetting);
3138 +
3139 + /* Enable the endpoints */
3140 + d = fsg_ep_desc(fsg->gadget,
3141 + &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc,
3142 + &fsg_ss_bulk_in_desc);
3143 + if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
3144 + goto reset;
3145 + fsg->bulk_in_enabled = 1;
3146 +
3147 + d = fsg_ep_desc(fsg->gadget,
3148 + &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc,
3149 + &fsg_ss_bulk_out_desc);
3150 + if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
3151 + goto reset;
3152 + fsg->bulk_out_enabled = 1;
3153 + fsg->bulk_out_maxpacket = usb_endpoint_maxp(d);
3154 + clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
3155 +
3156 + if (transport_is_cbi()) {
3157 + d = fsg_ep_desc(fsg->gadget,
3158 + &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc,
3159 + &fsg_ss_intr_in_desc);
3160 + if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
3161 + goto reset;
3162 + fsg->intr_in_enabled = 1;
3163 + }
3164 +
3165 + /* Allocate the requests */
3166 + for (i = 0; i < fsg_num_buffers; ++i) {
3167 + struct fsg_buffhd *bh = &fsg->buffhds[i];
3168 +
3169 + if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0)
3170 + goto reset;
3171 + if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0)
3172 + goto reset;
3173 + bh->inreq->buf = bh->outreq->buf = bh->buf;
3174 + bh->inreq->context = bh->outreq->context = bh;
3175 + bh->inreq->complete = bulk_in_complete;
3176 + bh->outreq->complete = bulk_out_complete;
3177 + }
3178 + if (transport_is_cbi()) {
3179 + if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0)
3180 + goto reset;
3181 + fsg->intreq->complete = intr_in_complete;
3182 + }
3183 +
3184 + fsg->running = 1;
3185 + for (i = 0; i < fsg->nluns; ++i)
3186 + fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
3187 + return rc;
3188 +}
3189 +
3190 +
3191 +/*
3192 + * Change our operational configuration. This code must agree with the code
3193 + * that returns config descriptors, and with interface altsetting code.
3194 + *
3195 + * It's also responsible for power management interactions. Some
3196 + * configurations might not work with our current power sources.
3197 + * For now we just assume the gadget is always self-powered.
3198 + */
3199 +static int do_set_config(struct fsg_dev *fsg, u8 new_config)
3200 +{
3201 + int rc = 0;
3202 +
3203 + /* Disable the single interface */
3204 + if (fsg->config != 0) {
3205 + DBG(fsg, "reset config\n");
3206 + fsg->config = 0;
3207 + rc = do_set_interface(fsg, -1);
3208 + }
3209 +
3210 + /* Enable the interface */
3211 + if (new_config != 0) {
3212 + fsg->config = new_config;
3213 + if ((rc = do_set_interface(fsg, 0)) != 0)
3214 + fsg->config = 0; // Reset on errors
3215 + else
3216 + INFO(fsg, "%s config #%d\n",
3217 + usb_speed_string(fsg->gadget->speed),
3218 + fsg->config);
3219 + }
3220 + return rc;
3221 +}
3222 +
3223 +
3224 +/*-------------------------------------------------------------------------*/
3225 +
3226 +static void handle_exception(struct fsg_dev *fsg)
3227 +{
3228 + siginfo_t info;
3229 + int sig;
3230 + int i;
3231 + int num_active;
3232 + struct fsg_buffhd *bh;
3233 + enum fsg_state old_state;
3234 + u8 new_config;
3235 + struct fsg_lun *curlun;
3236 + unsigned int exception_req_tag;
3237 + int rc;
3238 +
3239 + /* Clear the existing signals. Anything but SIGUSR1 is converted
3240 + * into a high-priority EXIT exception. */
3241 + for (;;) {
3242 + sig = dequeue_signal_lock(current, &current->blocked, &info);
3243 + if (!sig)
3244 + break;
3245 + if (sig != SIGUSR1) {
3246 + if (fsg->state < FSG_STATE_EXIT)
3247 + DBG(fsg, "Main thread exiting on signal\n");
3248 + raise_exception(fsg, FSG_STATE_EXIT);
3249 + }
3250 + }
3251 +
3252 + /* Cancel all the pending transfers */
3253 + if (fsg->intreq_busy)
3254 + usb_ep_dequeue(fsg->intr_in, fsg->intreq);
3255 + for (i = 0; i < fsg_num_buffers; ++i) {
3256 + bh = &fsg->buffhds[i];
3257 + if (bh->inreq_busy)
3258 + usb_ep_dequeue(fsg->bulk_in, bh->inreq);
3259 + if (bh->outreq_busy)
3260 + usb_ep_dequeue(fsg->bulk_out, bh->outreq);
3261 + }
3262 +
3263 + /* Wait until everything is idle */
3264 + for (;;) {
3265 + num_active = fsg->intreq_busy;
3266 + for (i = 0; i < fsg_num_buffers; ++i) {
3267 + bh = &fsg->buffhds[i];
3268 + num_active += bh->inreq_busy + bh->outreq_busy;
3269 + }
3270 + if (num_active == 0)
3271 + break;
3272 + if (sleep_thread(fsg))
3273 + return;
3274 + }
3275 +
3276 + /* Clear out the controller's fifos */
3277 + if (fsg->bulk_in_enabled)
3278 + usb_ep_fifo_flush(fsg->bulk_in);
3279 + if (fsg->bulk_out_enabled)
3280 + usb_ep_fifo_flush(fsg->bulk_out);
3281 + if (fsg->intr_in_enabled)
3282 + usb_ep_fifo_flush(fsg->intr_in);
3283 +
3284 + /* Reset the I/O buffer states and pointers, the SCSI
3285 + * state, and the exception. Then invoke the handler. */
3286 + spin_lock_irq(&fsg->lock);
3287 +
3288 + for (i = 0; i < fsg_num_buffers; ++i) {
3289 + bh = &fsg->buffhds[i];
3290 + bh->state = BUF_STATE_EMPTY;
3291 + }
3292 + fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain =
3293 + &fsg->buffhds[0];
3294 +
3295 + exception_req_tag = fsg->exception_req_tag;
3296 + new_config = fsg->new_config;
3297 + old_state = fsg->state;
3298 +
3299 + if (old_state == FSG_STATE_ABORT_BULK_OUT)
3300 + fsg->state = FSG_STATE_STATUS_PHASE;
3301 + else {
3302 + for (i = 0; i < fsg->nluns; ++i) {
3303 + curlun = &fsg->luns[i];
3304 + curlun->prevent_medium_removal = 0;
3305 + curlun->sense_data = curlun->unit_attention_data =
3306 + SS_NO_SENSE;
3307 + curlun->sense_data_info = 0;
3308 + curlun->info_valid = 0;
3309 + }
3310 + fsg->state = FSG_STATE_IDLE;
3311 + }
3312 + spin_unlock_irq(&fsg->lock);
3313 +
3314 + /* Carry out any extra actions required for the exception */
3315 + switch (old_state) {
3316 + default:
3317 + break;
3318 +
3319 + case FSG_STATE_ABORT_BULK_OUT:
3320 + send_status(fsg);
3321 + spin_lock_irq(&fsg->lock);
3322 + if (fsg->state == FSG_STATE_STATUS_PHASE)
3323 + fsg->state = FSG_STATE_IDLE;
3324 + spin_unlock_irq(&fsg->lock);
3325 + break;
3326 +
3327 + case FSG_STATE_RESET:
3328 + /* In case we were forced against our will to halt a
3329 + * bulk endpoint, clear the halt now. (The SuperH UDC
3330 + * requires this.) */
3331 + if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
3332 + usb_ep_clear_halt(fsg->bulk_in);
3333 +
3334 + if (transport_is_bbb()) {
3335 + if (fsg->ep0_req_tag == exception_req_tag)
3336 + ep0_queue(fsg); // Complete the status stage
3337 +
3338 + } else if (transport_is_cbi())
3339 + send_status(fsg); // Status by interrupt pipe
3340 +
3341 + /* Technically this should go here, but it would only be
3342 + * a waste of time. Ditto for the INTERFACE_CHANGE and
3343 + * CONFIG_CHANGE cases. */
3344 + // for (i = 0; i < fsg->nluns; ++i)
3345 + // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
3346 + break;
3347 +
3348 + case FSG_STATE_INTERFACE_CHANGE:
3349 + rc = do_set_interface(fsg, 0);
3350 + if (fsg->ep0_req_tag != exception_req_tag)
3351 + break;
3352 + if (rc != 0) // STALL on errors
3353 + fsg_set_halt(fsg, fsg->ep0);
3354 + else // Complete the status stage
3355 + ep0_queue(fsg);
3356 + break;
3357 +
3358 + case FSG_STATE_CONFIG_CHANGE:
3359 + rc = do_set_config(fsg, new_config);
3360 + if (fsg->ep0_req_tag != exception_req_tag)
3361 + break;
3362 + if (rc != 0) // STALL on errors
3363 + fsg_set_halt(fsg, fsg->ep0);
3364 + else // Complete the status stage
3365 + ep0_queue(fsg);
3366 + break;
3367 +
3368 + case FSG_STATE_DISCONNECT:
3369 + for (i = 0; i < fsg->nluns; ++i)
3370 + fsg_lun_fsync_sub(fsg->luns + i);
3371 + do_set_config(fsg, 0); // Unconfigured state
3372 + break;
3373 +
3374 + case FSG_STATE_EXIT:
3375 + case FSG_STATE_TERMINATED:
3376 + do_set_config(fsg, 0); // Free resources
3377 + spin_lock_irq(&fsg->lock);
3378 + fsg->state = FSG_STATE_TERMINATED; // Stop the thread
3379 + spin_unlock_irq(&fsg->lock);
3380 + break;
3381 + }
3382 +}
3383 +
3384 +
3385 +/*-------------------------------------------------------------------------*/
3386 +
3387 +static int fsg_main_thread(void *fsg_)
3388 +{
3389 + struct fsg_dev *fsg = fsg_;
3390 +
3391 + /* Allow the thread to be killed by a signal, but set the signal mask
3392 + * to block everything but INT, TERM, KILL, and USR1. */
3393 + allow_signal(SIGINT);
3394 + allow_signal(SIGTERM);
3395 + allow_signal(SIGKILL);
3396 + allow_signal(SIGUSR1);
3397 +
3398 + /* Allow the thread to be frozen */
3399 + set_freezable();
3400 +
3401 + /* Arrange for userspace references to be interpreted as kernel
3402 + * pointers. That way we can pass a kernel pointer to a routine
3403 + * that expects a __user pointer and it will work okay. */
3404 + set_fs(get_ds());
3405 +
3406 + /* The main loop */
3407 + while (fsg->state != FSG_STATE_TERMINATED) {
3408 + if (exception_in_progress(fsg) || signal_pending(current)) {
3409 + handle_exception(fsg);
3410 + continue;
3411 + }
3412 +
3413 + if (!fsg->running) {
3414 + sleep_thread(fsg);
3415 + continue;
3416 + }
3417 +
3418 + if (get_next_command(fsg))
3419 + continue;
3420 +
3421 + spin_lock_irq(&fsg->lock);
3422 + if (!exception_in_progress(fsg))
3423 + fsg->state = FSG_STATE_DATA_PHASE;
3424 + spin_unlock_irq(&fsg->lock);
3425 +
3426 + if (do_scsi_command(fsg) || finish_reply(fsg))
3427 + continue;
3428 +
3429 + spin_lock_irq(&fsg->lock);
3430 + if (!exception_in_progress(fsg))
3431 + fsg->state = FSG_STATE_STATUS_PHASE;
3432 + spin_unlock_irq(&fsg->lock);
3433 +
3434 + if (send_status(fsg))
3435 + continue;
3436 +
3437 + spin_lock_irq(&fsg->lock);
3438 + if (!exception_in_progress(fsg))
3439 + fsg->state = FSG_STATE_IDLE;
3440 + spin_unlock_irq(&fsg->lock);
3441 + }
3442 +
3443 + spin_lock_irq(&fsg->lock);
3444 + fsg->thread_task = NULL;
3445 + spin_unlock_irq(&fsg->lock);
3446 +
3447 + /* If we are exiting because of a signal, unregister the
3448 + * gadget driver. */
3449 + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
3450 + usb_gadget_unregister_driver(&fsg_driver);
3451 +
3452 + /* Let the unbind and cleanup routines know the thread has exited */
3453 + complete_and_exit(&fsg->thread_notifier, 0);
3454 +}
3455 +
3456 +
3457 +/*-------------------------------------------------------------------------*/
3458 +
3459 +
3460 +/* The write permissions and store_xxx pointers are set in fsg_bind() */
3461 +static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL);
3462 +static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL);
3463 +static DEVICE_ATTR(file, 0444, fsg_show_file, NULL);
3464 +
3465 +
3466 +/*-------------------------------------------------------------------------*/
3467 +
3468 +static void fsg_release(struct kref *ref)
3469 +{
3470 + struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref);
3471 +
3472 + kfree(fsg->luns);
3473 + kfree(fsg);
3474 +}
3475 +
3476 +static void lun_release(struct device *dev)
3477 +{
3478 + struct rw_semaphore *filesem = dev_get_drvdata(dev);
3479 + struct fsg_dev *fsg =
3480 + container_of(filesem, struct fsg_dev, filesem);
3481 +
3482 + kref_put(&fsg->ref, fsg_release);
3483 +}
3484 +
3485 +static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
3486 +{
3487 + struct fsg_dev *fsg = get_gadget_data(gadget);
3488 + int i;
3489 + struct fsg_lun *curlun;
3490 + struct usb_request *req = fsg->ep0req;
3491 +
3492 + DBG(fsg, "unbind\n");
3493 + clear_bit(REGISTERED, &fsg->atomic_bitflags);
3494 +
3495 + /* If the thread isn't already dead, tell it to exit now */
3496 + if (fsg->state != FSG_STATE_TERMINATED) {
3497 + raise_exception(fsg, FSG_STATE_EXIT);
3498 + wait_for_completion(&fsg->thread_notifier);
3499 +
3500 + /* The cleanup routine waits for this completion also */
3501 + complete(&fsg->thread_notifier);
3502 + }
3503 +
3504 + /* Unregister the sysfs attribute files and the LUNs */
3505 + for (i = 0; i < fsg->nluns; ++i) {
3506 + curlun = &fsg->luns[i];
3507 + if (curlun->registered) {
3508 + device_remove_file(&curlun->dev, &dev_attr_nofua);
3509 + device_remove_file(&curlun->dev, &dev_attr_ro);
3510 + device_remove_file(&curlun->dev, &dev_attr_file);
3511 + fsg_lun_close(curlun);
3512 + device_unregister(&curlun->dev);
3513 + curlun->registered = 0;
3514 + }
3515 + }
3516 +
3517 + /* Free the data buffers */
3518 + for (i = 0; i < fsg_num_buffers; ++i)
3519 + kfree(fsg->buffhds[i].buf);
3520 +
3521 + /* Free the request and buffer for endpoint 0 */
3522 + if (req) {
3523 + kfree(req->buf);
3524 + usb_ep_free_request(fsg->ep0, req);
3525 + }
3526 +
3527 + set_gadget_data(gadget, NULL);
3528 +}
3529 +
3530 +
3531 +static int __init check_parameters(struct fsg_dev *fsg)
3532 +{
3533 + int prot;
3534 + int gcnum;
3535 +
3536 + /* Store the default values */
3537 + mod_data.transport_type = USB_PR_BULK;
3538 + mod_data.transport_name = "Bulk-only";
3539 + mod_data.protocol_type = USB_SC_SCSI;
3540 + mod_data.protocol_name = "Transparent SCSI";
3541 +
3542 + /* Some peripheral controllers are known not to be able to
3543 + * halt bulk endpoints correctly. If one of them is present,
3544 + * disable stalls.
3545 + */
3546 + if (gadget_is_at91(fsg->gadget))
3547 + mod_data.can_stall = 0;
3548 +
3549 + if (mod_data.release == 0xffff) { // Parameter wasn't set
3550 + gcnum = usb_gadget_controller_number(fsg->gadget);
3551 + if (gcnum >= 0)
3552 + mod_data.release = 0x0300 + gcnum;
3553 + else {
3554 + WARNING(fsg, "controller '%s' not recognized\n",
3555 + fsg->gadget->name);
3556 + mod_data.release = 0x0399;
3557 + }
3558 + }
3559 +
3560 + prot = simple_strtol(mod_data.protocol_parm, NULL, 0);
3561 +
3562 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
3563 + if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) {
3564 + ; // Use default setting
3565 + } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) {
3566 + mod_data.transport_type = USB_PR_CB;
3567 + mod_data.transport_name = "Control-Bulk";
3568 + } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) {
3569 + mod_data.transport_type = USB_PR_CBI;
3570 + mod_data.transport_name = "Control-Bulk-Interrupt";
3571 + } else {
3572 + ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm);
3573 + return -EINVAL;
3574 + }
3575 +
3576 + if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 ||
3577 + prot == USB_SC_SCSI) {
3578 + ; // Use default setting
3579 + } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 ||
3580 + prot == USB_SC_RBC) {
3581 + mod_data.protocol_type = USB_SC_RBC;
3582 + mod_data.protocol_name = "RBC";
3583 + } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 ||
3584 + strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 ||
3585 + prot == USB_SC_8020) {
3586 + mod_data.protocol_type = USB_SC_8020;
3587 + mod_data.protocol_name = "8020i (ATAPI)";
3588 + } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 ||
3589 + prot == USB_SC_QIC) {
3590 + mod_data.protocol_type = USB_SC_QIC;
3591 + mod_data.protocol_name = "QIC-157";
3592 + } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 ||
3593 + prot == USB_SC_UFI) {
3594 + mod_data.protocol_type = USB_SC_UFI;
3595 + mod_data.protocol_name = "UFI";
3596 + } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 ||
3597 + prot == USB_SC_8070) {
3598 + mod_data.protocol_type = USB_SC_8070;
3599 + mod_data.protocol_name = "8070i";
3600 + } else {
3601 + ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm);
3602 + return -EINVAL;
3603 + }
3604 +
3605 + mod_data.buflen &= PAGE_CACHE_MASK;
3606 + if (mod_data.buflen <= 0) {
3607 + ERROR(fsg, "invalid buflen\n");
3608 + return -ETOOSMALL;
3609 + }
3610 +
3611 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
3612 +
3613 + /* Serial string handling.
3614 + * On a real device, the serial string would be loaded
3615 + * from permanent storage. */
3616 + if (mod_data.serial) {
3617 + const char *ch;
3618 + unsigned len = 0;
3619 +
3620 + /* Sanity check :
3621 + * The CB[I] specification limits the serial string to
3622 + * 12 uppercase hexadecimal characters.
3623 + * BBB need at least 12 uppercase hexadecimal characters,
3624 + * with a maximum of 126. */
3625 + for (ch = mod_data.serial; *ch; ++ch) {
3626 + ++len;
3627 + if ((*ch < '0' || *ch > '9') &&
3628 + (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */
3629 + WARNING(fsg,
3630 + "Invalid serial string character: %c\n",
3631 + *ch);
3632 + goto no_serial;
3633 + }
3634 + }
3635 + if (len > 126 ||
3636 + (mod_data.transport_type == USB_PR_BULK && len < 12) ||
3637 + (mod_data.transport_type != USB_PR_BULK && len > 12)) {
3638 + WARNING(fsg, "Invalid serial string length!\n");
3639 + goto no_serial;
3640 + }
3641 + fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial;
3642 + } else {
3643 + WARNING(fsg, "No serial-number string provided!\n");
3644 + no_serial:
3645 + device_desc.iSerialNumber = 0;
3646 + }
3647 +
3648 + return 0;
3649 +}
3650 +
3651 +
3652 +static int __init fsg_bind(struct usb_gadget *gadget)
3653 +{
3654 + struct fsg_dev *fsg = the_fsg;
3655 + int rc;
3656 + int i;
3657 + struct fsg_lun *curlun;
3658 + struct usb_ep *ep;
3659 + struct usb_request *req;
3660 + char *pathbuf, *p;
3661 +
3662 + fsg->gadget = gadget;
3663 + set_gadget_data(gadget, fsg);
3664 + fsg->ep0 = gadget->ep0;
3665 + fsg->ep0->driver_data = fsg;
3666 +
3667 + if ((rc = check_parameters(fsg)) != 0)
3668 + goto out;
3669 +
3670 + if (mod_data.removable) { // Enable the store_xxx attributes
3671 + dev_attr_file.attr.mode = 0644;
3672 + dev_attr_file.store = fsg_store_file;
3673 + if (!mod_data.cdrom) {
3674 + dev_attr_ro.attr.mode = 0644;
3675 + dev_attr_ro.store = fsg_store_ro;
3676 + }
3677 + }
3678 +
3679 + /* Only for removable media? */
3680 + dev_attr_nofua.attr.mode = 0644;
3681 + dev_attr_nofua.store = fsg_store_nofua;
3682 +
3683 + /* Find out how many LUNs there should be */
3684 + i = mod_data.nluns;
3685 + if (i == 0)
3686 + i = max(mod_data.num_filenames, 1u);
3687 + if (i > FSG_MAX_LUNS) {
3688 + ERROR(fsg, "invalid number of LUNs: %d\n", i);
3689 + rc = -EINVAL;
3690 + goto out;
3691 + }
3692 +
3693 + /* Create the LUNs, open their backing files, and register the
3694 + * LUN devices in sysfs. */
3695 + fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL);
3696 + if (!fsg->luns) {
3697 + rc = -ENOMEM;
3698 + goto out;
3699 + }
3700 + fsg->nluns = i;
3701 +
3702 + for (i = 0; i < fsg->nluns; ++i) {
3703 + curlun = &fsg->luns[i];
3704 + curlun->cdrom = !!mod_data.cdrom;
3705 + curlun->ro = mod_data.cdrom || mod_data.ro[i];
3706 + curlun->initially_ro = curlun->ro;
3707 + curlun->removable = mod_data.removable;
3708 + curlun->nofua = mod_data.nofua[i];
3709 + curlun->dev.release = lun_release;
3710 + curlun->dev.parent = &gadget->dev;
3711 + curlun->dev.driver = &fsg_driver.driver;
3712 + dev_set_drvdata(&curlun->dev, &fsg->filesem);
3713 + dev_set_name(&curlun->dev,"%s-lun%d",
3714 + dev_name(&gadget->dev), i);
3715 +
3716 + kref_get(&fsg->ref);
3717 + rc = device_register(&curlun->dev);
3718 + if (rc) {
3719 + INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
3720 + put_device(&curlun->dev);
3721 + goto out;
3722 + }
3723 + curlun->registered = 1;
3724 +
3725 + rc = device_create_file(&curlun->dev, &dev_attr_ro);
3726 + if (rc)
3727 + goto out;
3728 + rc = device_create_file(&curlun->dev, &dev_attr_nofua);
3729 + if (rc)
3730 + goto out;
3731 + rc = device_create_file(&curlun->dev, &dev_attr_file);
3732 + if (rc)
3733 + goto out;
3734 +
3735 + if (mod_data.file[i] && *mod_data.file[i]) {
3736 + rc = fsg_lun_open(curlun, mod_data.file[i]);
3737 + if (rc)
3738 + goto out;
3739 + } else if (!mod_data.removable) {
3740 + ERROR(fsg, "no file given for LUN%d\n", i);
3741 + rc = -EINVAL;
3742 + goto out;
3743 + }
3744 + }
3745 +
3746 + /* Find all the endpoints we will use */
3747 + usb_ep_autoconfig_reset(gadget);
3748 + ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
3749 + if (!ep)
3750 + goto autoconf_fail;
3751 + ep->driver_data = fsg; // claim the endpoint
3752 + fsg->bulk_in = ep;
3753 +
3754 + ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
3755 + if (!ep)
3756 + goto autoconf_fail;
3757 + ep->driver_data = fsg; // claim the endpoint
3758 + fsg->bulk_out = ep;
3759 +
3760 + if (transport_is_cbi()) {
3761 + ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc);
3762 + if (!ep)
3763 + goto autoconf_fail;
3764 + ep->driver_data = fsg; // claim the endpoint
3765 + fsg->intr_in = ep;
3766 + }
3767 +
3768 + /* Fix up the descriptors */
3769 + device_desc.idVendor = cpu_to_le16(mod_data.vendor);
3770 + device_desc.idProduct = cpu_to_le16(mod_data.product);
3771 + device_desc.bcdDevice = cpu_to_le16(mod_data.release);
3772 +
3773 + i = (transport_is_cbi() ? 3 : 2); // Number of endpoints
3774 + fsg_intf_desc.bNumEndpoints = i;
3775 + fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type;
3776 + fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type;
3777 + fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
3778 +
3779 + if (gadget_is_dualspeed(gadget)) {
3780 + fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
3781 +
3782 + /* Assume endpoint addresses are the same for both speeds */
3783 + fsg_hs_bulk_in_desc.bEndpointAddress =
3784 + fsg_fs_bulk_in_desc.bEndpointAddress;
3785 + fsg_hs_bulk_out_desc.bEndpointAddress =
3786 + fsg_fs_bulk_out_desc.bEndpointAddress;
3787 + fsg_hs_intr_in_desc.bEndpointAddress =
3788 + fsg_fs_intr_in_desc.bEndpointAddress;
3789 + }
3790 +
3791 + if (gadget_is_superspeed(gadget)) {
3792 + unsigned max_burst;
3793 +
3794 + fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL;
3795 +
3796 + /* Calculate bMaxBurst, we know packet size is 1024 */
3797 + max_burst = min_t(unsigned, mod_data.buflen / 1024, 15);
3798 +
3799 + /* Assume endpoint addresses are the same for both speeds */
3800 + fsg_ss_bulk_in_desc.bEndpointAddress =
3801 + fsg_fs_bulk_in_desc.bEndpointAddress;
3802 + fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
3803 +
3804 + fsg_ss_bulk_out_desc.bEndpointAddress =
3805 + fsg_fs_bulk_out_desc.bEndpointAddress;
3806 + fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
3807 + }
3808 +
3809 + if (gadget_is_otg(gadget))
3810 + fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
3811 +
3812 + rc = -ENOMEM;
3813 +
3814 + /* Allocate the request and buffer for endpoint 0 */
3815 + fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
3816 + if (!req)
3817 + goto out;
3818 + req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL);
3819 + if (!req->buf)
3820 + goto out;
3821 + req->complete = ep0_complete;
3822 +
3823 + /* Allocate the data buffers */
3824 + for (i = 0; i < fsg_num_buffers; ++i) {
3825 + struct fsg_buffhd *bh = &fsg->buffhds[i];
3826 +
3827 + /* Allocate for the bulk-in endpoint. We assume that
3828 + * the buffer will also work with the bulk-out (and
3829 + * interrupt-in) endpoint. */
3830 + bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL);
3831 + if (!bh->buf)
3832 + goto out;
3833 + bh->next = bh + 1;
3834 + }
3835 + fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0];
3836 +
3837 + /* This should reflect the actual gadget power source */
3838 + usb_gadget_set_selfpowered(gadget);
3839 +
3840 + snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer,
3841 + "%s %s with %s",
3842 + init_utsname()->sysname, init_utsname()->release,
3843 + gadget->name);
3844 +
3845 + fsg->thread_task = kthread_create(fsg_main_thread, fsg,
3846 + "file-storage-gadget");
3847 + if (IS_ERR(fsg->thread_task)) {
3848 + rc = PTR_ERR(fsg->thread_task);
3849 + goto out;
3850 + }
3851 +
3852 + INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
3853 + INFO(fsg, "NOTE: This driver is deprecated. "
3854 + "Consider using g_mass_storage instead.\n");
3855 + INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
3856 +
3857 + pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
3858 + for (i = 0; i < fsg->nluns; ++i) {
3859 + curlun = &fsg->luns[i];
3860 + if (fsg_lun_is_open(curlun)) {
3861 + p = NULL;
3862 + if (pathbuf) {
3863 + p = d_path(&curlun->filp->f_path,
3864 + pathbuf, PATH_MAX);
3865 + if (IS_ERR(p))
3866 + p = NULL;
3867 + }
3868 + LINFO(curlun, "ro=%d, nofua=%d, file: %s\n",
3869 + curlun->ro, curlun->nofua, (p ? p : "(error)"));
3870 + }
3871 + }
3872 + kfree(pathbuf);
3873 +
3874 + DBG(fsg, "transport=%s (x%02x)\n",
3875 + mod_data.transport_name, mod_data.transport_type);
3876 + DBG(fsg, "protocol=%s (x%02x)\n",
3877 + mod_data.protocol_name, mod_data.protocol_type);
3878 + DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n",
3879 + mod_data.vendor, mod_data.product, mod_data.release);
3880 + DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n",
3881 + mod_data.removable, mod_data.can_stall,
3882 + mod_data.cdrom, mod_data.buflen);
3883 + DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
3884 +
3885 + set_bit(REGISTERED, &fsg->atomic_bitflags);
3886 +
3887 + /* Tell the thread to start working */
3888 + wake_up_process(fsg->thread_task);
3889 + return 0;
3890 +
3891 +autoconf_fail:
3892 + ERROR(fsg, "unable to autoconfigure all endpoints\n");
3893 + rc = -ENOTSUPP;
3894 +
3895 +out:
3896 + fsg->state = FSG_STATE_TERMINATED; // The thread is dead
3897 + fsg_unbind(gadget);
3898 + complete(&fsg->thread_notifier);
3899 + return rc;
3900 +}
3901 +
3902 +
3903 +/*-------------------------------------------------------------------------*/
3904 +
3905 +static void fsg_suspend(struct usb_gadget *gadget)
3906 +{
3907 + struct fsg_dev *fsg = get_gadget_data(gadget);
3908 +
3909 + DBG(fsg, "suspend\n");
3910 + set_bit(SUSPENDED, &fsg->atomic_bitflags);
3911 +}
3912 +
3913 +static void fsg_resume(struct usb_gadget *gadget)
3914 +{
3915 + struct fsg_dev *fsg = get_gadget_data(gadget);
3916 +
3917 + DBG(fsg, "resume\n");
3918 + clear_bit(SUSPENDED, &fsg->atomic_bitflags);
3919 +}
3920 +
3921 +
3922 +/*-------------------------------------------------------------------------*/
3923 +
3924 +static struct usb_gadget_driver fsg_driver = {
3925 + .max_speed = USB_SPEED_SUPER,
3926 + .function = (char *) fsg_string_product,
3927 + .unbind = fsg_unbind,
3928 + .disconnect = fsg_disconnect,
3929 + .setup = fsg_setup,
3930 + .suspend = fsg_suspend,
3931 + .resume = fsg_resume,
3932 +
3933 + .driver = {
3934 + .name = DRIVER_NAME,
3935 + .owner = THIS_MODULE,
3936 + // .release = ...
3937 + // .suspend = ...
3938 + // .resume = ...
3939 + },
3940 +};
3941 +
3942 +
3943 +static int __init fsg_alloc(void)
3944 +{
3945 + struct fsg_dev *fsg;
3946 +
3947 + fsg = kzalloc(sizeof *fsg +
3948 + fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL);
3949 +
3950 + if (!fsg)
3951 + return -ENOMEM;
3952 + spin_lock_init(&fsg->lock);
3953 + init_rwsem(&fsg->filesem);
3954 + kref_init(&fsg->ref);
3955 + init_completion(&fsg->thread_notifier);
3956 +
3957 + the_fsg = fsg;
3958 + return 0;
3959 +}
3960 +
3961 +
3962 +static int __init fsg_init(void)
3963 +{
3964 + int rc;
3965 + struct fsg_dev *fsg;
3966 +
3967 + rc = fsg_num_buffers_validate();
3968 + if (rc != 0)
3969 + return rc;
3970 +
3971 + if ((rc = fsg_alloc()) != 0)
3972 + return rc;
3973 + fsg = the_fsg;
3974 + if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0)
3975 + kref_put(&fsg->ref, fsg_release);
3976 + return rc;
3977 +}
3978 +module_init(fsg_init);
3979 +
3980 +
3981 +static void __exit fsg_cleanup(void)
3982 +{
3983 + struct fsg_dev *fsg = the_fsg;
3984 +
3985 + /* Unregister the driver iff the thread hasn't already done so */
3986 + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
3987 + usb_gadget_unregister_driver(&fsg_driver);
3988 +
3989 + /* Wait for the thread to finish up */
3990 + wait_for_completion(&fsg->thread_notifier);
3991 +
3992 + kref_put(&fsg->ref, fsg_release);
3993 +}
3994 +module_exit(fsg_cleanup);
3995 --- /dev/null
3996 +++ b/drivers/usb/host/dwc_common_port/changes.txt
3997 @@ -0,0 +1,174 @@
3998 +
3999 +dwc_read_reg32() and friends now take an additional parameter, a pointer to an
4000 +IO context struct. The IO context struct should live in an os-dependent struct
4001 +in your driver. As an example, the dwc_usb3 driver has an os-dependent struct
4002 +named 'os_dep' embedded in the main device struct. So there these calls look
4003 +like this:
4004 +
4005 + dwc_read_reg32(&usb3_dev->os_dep.ioctx, &pcd->dev_global_regs->dcfg);
4006 +
4007 + dwc_write_reg32(&usb3_dev->os_dep.ioctx,
4008 + &pcd->dev_global_regs->dcfg, 0);
4009 +
4010 +Note that for the existing Linux driver ports, it is not necessary to actually
4011 +define the 'ioctx' member in the os-dependent struct. Since Linux does not
4012 +require an IO context, its macros for dwc_read_reg32() and friends do not
4013 +use the context pointer, so it is optimized away by the compiler. But it is
4014 +necessary to add the pointer parameter to all of the call sites, to be ready
4015 +for any future ports (such as FreeBSD) which do require an IO context.
4016 +
4017 +
4018 +Similarly, dwc_alloc(), dwc_alloc_atomic(), dwc_strdup(), and dwc_free() now
4019 +take an additional parameter, a pointer to a memory context. Examples:
4020 +
4021 + addr = dwc_alloc(&usb3_dev->os_dep.memctx, size);
4022 +
4023 + dwc_free(&usb3_dev->os_dep.memctx, addr);
4024 +
4025 +Again, for the Linux ports, it is not necessary to actually define the memctx
4026 +member, but it is necessary to add the pointer parameter to all of the call
4027 +sites.
4028 +
4029 +
4030 +Same for dwc_dma_alloc() and dwc_dma_free(). Examples:
4031 +
4032 + virt_addr = dwc_dma_alloc(&usb3_dev->os_dep.dmactx, size, &phys_addr);
4033 +
4034 + dwc_dma_free(&usb3_dev->os_dep.dmactx, size, virt_addr, phys_addr);
4035 +
4036 +
4037 +Same for dwc_mutex_alloc() and dwc_mutex_free(). Examples:
4038 +
4039 + mutex = dwc_mutex_alloc(&usb3_dev->os_dep.mtxctx);
4040 +
4041 + dwc_mutex_free(&usb3_dev->os_dep.mtxctx, mutex);
4042 +
4043 +
4044 +Same for dwc_spinlock_alloc() and dwc_spinlock_free(). Examples:
4045 +
4046 + lock = dwc_spinlock_alloc(&usb3_dev->osdep.splctx);
4047 +
4048 + dwc_spinlock_free(&usb3_dev->osdep.splctx, lock);
4049 +
4050 +
4051 +Same for dwc_timer_alloc(). Example:
4052 +
4053 + timer = dwc_timer_alloc(&usb3_dev->os_dep.tmrctx, "dwc_usb3_tmr1",
4054 + cb_func, cb_data);
4055 +
4056 +
4057 +Same for dwc_waitq_alloc(). Example:
4058 +
4059 + waitq = dwc_waitq_alloc(&usb3_dev->os_dep.wtqctx);
4060 +
4061 +
4062 +Same for dwc_thread_run(). Example:
4063 +
4064 + thread = dwc_thread_run(&usb3_dev->os_dep.thdctx, func,
4065 + "dwc_usb3_thd1", data);
4066 +
4067 +
4068 +Same for dwc_workq_alloc(). Example:
4069 +
4070 + workq = dwc_workq_alloc(&usb3_dev->osdep.wkqctx, "dwc_usb3_wkq1");
4071 +
4072 +
4073 +Same for dwc_task_alloc(). Example:
4074 +
4075 + task = dwc_task_alloc(&usb3_dev->os_dep.tskctx, "dwc_usb3_tsk1",
4076 + cb_func, cb_data);
4077 +
4078 +
4079 +In addition to the context pointer additions, a few core functions have had
4080 +other changes made to their parameters:
4081 +
4082 +The 'flags' parameter to dwc_spinlock_irqsave() and dwc_spinunlock_irqrestore()
4083 +has been changed from a uint64_t to a dwc_irqflags_t.
4084 +
4085 +dwc_thread_should_stop() now takes a 'dwc_thread_t *' parameter, because the
4086 +FreeBSD equivalent of that function requires it.
4087 +
4088 +And, in addition to the context pointer, dwc_task_alloc() also adds a
4089 +'char *name' parameter, to be consistent with dwc_thread_run() and
4090 +dwc_workq_alloc(), and because the FreeBSD equivalent of that function
4091 +requires a unique name.
4092 +
4093 +
4094 +Here is a complete list of the core functions that now take a pointer to a
4095 +context as their first parameter:
4096 +
4097 + dwc_read_reg32
4098 + dwc_read_reg64
4099 + dwc_write_reg32
4100 + dwc_write_reg64
4101 + dwc_modify_reg32
4102 + dwc_modify_reg64
4103 + dwc_alloc
4104 + dwc_alloc_atomic
4105 + dwc_strdup
4106 + dwc_free
4107 + dwc_dma_alloc
4108 + dwc_dma_free
4109 + dwc_mutex_alloc
4110 + dwc_mutex_free
4111 + dwc_spinlock_alloc
4112 + dwc_spinlock_free
4113 + dwc_timer_alloc
4114 + dwc_waitq_alloc
4115 + dwc_thread_run
4116 + dwc_workq_alloc
4117 + dwc_task_alloc Also adds a 'char *name' as its 2nd parameter
4118 +
4119 +And here are the core functions that have other changes to their parameters:
4120 +
4121 + dwc_spinlock_irqsave 'flags' param is now a 'dwc_irqflags_t *'
4122 + dwc_spinunlock_irqrestore 'flags' param is now a 'dwc_irqflags_t'
4123 + dwc_thread_should_stop Adds a 'dwc_thread_t *' parameter
4124 +
4125 +
4126 +
4127 +The changes to the core functions also require some of the other library
4128 +functions to change:
4129 +
4130 + dwc_cc_if_alloc() and dwc_cc_if_free() now take a 'void *memctx'
4131 + (for memory allocation) as the 1st param and a 'void *mtxctx'
4132 + (for mutex allocation) as the 2nd param.
4133 +
4134 + dwc_cc_clear(), dwc_cc_add(), dwc_cc_change(), dwc_cc_remove(),
4135 + dwc_cc_data_for_save(), and dwc_cc_restore_from_data() now take a
4136 + 'void *memctx' as the 1st param.
4137 +
4138 + dwc_dh_modpow(), dwc_dh_pk(), and dwc_dh_derive_keys() now take a
4139 + 'void *memctx' as the 1st param.
4140 +
4141 + dwc_modpow() now takes a 'void *memctx' as the 1st param.
4142 +
4143 + dwc_alloc_notification_manager() now takes a 'void *memctx' as the
4144 + 1st param and a 'void *wkqctx' (for work queue allocation) as the 2nd
4145 + param, and also now returns an integer value that is non-zero if
4146 + allocation of its data structures or work queue fails.
4147 +
4148 + dwc_register_notifier() now takes a 'void *memctx' as the 1st param.
4149 +
4150 + dwc_memory_debug_start() now takes a 'void *mem_ctx' as the first
4151 + param, and also now returns an integer value that is non-zero if
4152 + allocation of its data structures fails.
4153 +
4154 +
4155 +
4156 +Other miscellaneous changes:
4157 +
4158 +The DEBUG_MEMORY and DEBUG_REGS #define's have been renamed to
4159 +DWC_DEBUG_MEMORY and DWC_DEBUG_REGS.
4160 +
4161 +The following #define's have been added to allow selectively compiling library
4162 +features:
4163 +
4164 + DWC_CCLIB
4165 + DWC_CRYPTOLIB
4166 + DWC_NOTIFYLIB
4167 + DWC_UTFLIB
4168 +
4169 +A DWC_LIBMODULE #define has also been added. If this is not defined, then the
4170 +module code in dwc_common_linux.c is not compiled in. This allows linking the
4171 +library code directly into a driver module, instead of as a standalone module.
4172 --- /dev/null
4173 +++ b/drivers/usb/host/dwc_common_port/doc/doxygen.cfg
4174 @@ -0,0 +1,270 @@
4175 +# Doxyfile 1.4.5
4176 +
4177 +#---------------------------------------------------------------------------
4178 +# Project related configuration options
4179 +#---------------------------------------------------------------------------
4180 +PROJECT_NAME = "Synopsys DWC Portability and Common Library for UWB"
4181 +PROJECT_NUMBER =
4182 +OUTPUT_DIRECTORY = doc
4183 +CREATE_SUBDIRS = NO
4184 +OUTPUT_LANGUAGE = English
4185 +BRIEF_MEMBER_DESC = YES
4186 +REPEAT_BRIEF = YES
4187 +ABBREVIATE_BRIEF = "The $name class" \
4188 + "The $name widget" \
4189 + "The $name file" \
4190 + is \
4191 + provides \
4192 + specifies \
4193 + contains \
4194 + represents \
4195 + a \
4196 + an \
4197 + the
4198 +ALWAYS_DETAILED_SEC = YES
4199 +INLINE_INHERITED_MEMB = NO
4200 +FULL_PATH_NAMES = NO
4201 +STRIP_FROM_PATH = ..
4202 +STRIP_FROM_INC_PATH =
4203 +SHORT_NAMES = NO
4204 +JAVADOC_AUTOBRIEF = YES
4205 +MULTILINE_CPP_IS_BRIEF = NO
4206 +DETAILS_AT_TOP = YES
4207 +INHERIT_DOCS = YES
4208 +SEPARATE_MEMBER_PAGES = NO
4209 +TAB_SIZE = 8
4210 +ALIASES =
4211 +OPTIMIZE_OUTPUT_FOR_C = YES
4212 +OPTIMIZE_OUTPUT_JAVA = NO
4213 +BUILTIN_STL_SUPPORT = NO
4214 +DISTRIBUTE_GROUP_DOC = NO
4215 +SUBGROUPING = NO
4216 +#---------------------------------------------------------------------------
4217 +# Build related configuration options
4218 +#---------------------------------------------------------------------------
4219 +EXTRACT_ALL = NO
4220 +EXTRACT_PRIVATE = NO
4221 +EXTRACT_STATIC = YES
4222 +EXTRACT_LOCAL_CLASSES = NO
4223 +EXTRACT_LOCAL_METHODS = NO
4224 +HIDE_UNDOC_MEMBERS = NO
4225 +HIDE_UNDOC_CLASSES = NO
4226 +HIDE_FRIEND_COMPOUNDS = NO
4227 +HIDE_IN_BODY_DOCS = NO
4228 +INTERNAL_DOCS = NO
4229 +CASE_SENSE_NAMES = YES
4230 +HIDE_SCOPE_NAMES = NO
4231 +SHOW_INCLUDE_FILES = NO
4232 +INLINE_INFO = YES
4233 +SORT_MEMBER_DOCS = NO
4234 +SORT_BRIEF_DOCS = NO
4235 +SORT_BY_SCOPE_NAME = NO
4236 +GENERATE_TODOLIST = YES
4237 +GENERATE_TESTLIST = YES
4238 +GENERATE_BUGLIST = YES
4239 +GENERATE_DEPRECATEDLIST= YES
4240 +ENABLED_SECTIONS =
4241 +MAX_INITIALIZER_LINES = 30
4242 +SHOW_USED_FILES = YES
4243 +SHOW_DIRECTORIES = YES
4244 +FILE_VERSION_FILTER =
4245 +#---------------------------------------------------------------------------
4246 +# configuration options related to warning and progress messages
4247 +#---------------------------------------------------------------------------
4248 +QUIET = YES
4249 +WARNINGS = YES
4250 +WARN_IF_UNDOCUMENTED = NO
4251 +WARN_IF_DOC_ERROR = YES
4252 +WARN_NO_PARAMDOC = YES
4253 +WARN_FORMAT = "$file:$line: $text"
4254 +WARN_LOGFILE =
4255 +#---------------------------------------------------------------------------
4256 +# configuration options related to the input files
4257 +#---------------------------------------------------------------------------
4258 +INPUT = .
4259 +FILE_PATTERNS = *.c \
4260 + *.cc \
4261 + *.cxx \
4262 + *.cpp \
4263 + *.c++ \
4264 + *.d \
4265 + *.java \
4266 + *.ii \
4267 + *.ixx \
4268 + *.ipp \
4269 + *.i++ \
4270 + *.inl \
4271 + *.h \
4272 + *.hh \
4273 + *.hxx \
4274 + *.hpp \
4275 + *.h++ \
4276 + *.idl \
4277 + *.odl \
4278 + *.cs \
4279 + *.php \
4280 + *.php3 \
4281 + *.inc \
4282 + *.m \
4283 + *.mm \
4284 + *.dox \
4285 + *.py \
4286 + *.C \
4287 + *.CC \
4288 + *.C++ \
4289 + *.II \
4290 + *.I++ \
4291 + *.H \
4292 + *.HH \
4293 + *.H++ \
4294 + *.CS \
4295 + *.PHP \
4296 + *.PHP3 \
4297 + *.M \
4298 + *.MM \
4299 + *.PY
4300 +RECURSIVE = NO
4301 +EXCLUDE =
4302 +EXCLUDE_SYMLINKS = NO
4303 +EXCLUDE_PATTERNS =
4304 +EXAMPLE_PATH =
4305 +EXAMPLE_PATTERNS = *
4306 +EXAMPLE_RECURSIVE = NO
4307 +IMAGE_PATH =
4308 +INPUT_FILTER =
4309 +FILTER_PATTERNS =
4310 +FILTER_SOURCE_FILES = NO
4311 +#---------------------------------------------------------------------------
4312 +# configuration options related to source browsing
4313 +#---------------------------------------------------------------------------
4314 +SOURCE_BROWSER = NO
4315 +INLINE_SOURCES = NO
4316 +STRIP_CODE_COMMENTS = YES
4317 +REFERENCED_BY_RELATION = YES
4318 +REFERENCES_RELATION = YES
4319 +USE_HTAGS = NO
4320 +VERBATIM_HEADERS = NO
4321 +#---------------------------------------------------------------------------
4322 +# configuration options related to the alphabetical class index
4323 +#---------------------------------------------------------------------------
4324 +ALPHABETICAL_INDEX = NO
4325 +COLS_IN_ALPHA_INDEX = 5
4326 +IGNORE_PREFIX =
4327 +#---------------------------------------------------------------------------
4328 +# configuration options related to the HTML output
4329 +#---------------------------------------------------------------------------
4330 +GENERATE_HTML = YES
4331 +HTML_OUTPUT = html
4332 +HTML_FILE_EXTENSION = .html
4333 +HTML_HEADER =
4334 +HTML_FOOTER =
4335 +HTML_STYLESHEET =
4336 +HTML_ALIGN_MEMBERS = YES
4337 +GENERATE_HTMLHELP = NO
4338 +CHM_FILE =
4339 +HHC_LOCATION =
4340 +GENERATE_CHI = NO
4341 +BINARY_TOC = NO
4342 +TOC_EXPAND = NO
4343 +DISABLE_INDEX = NO
4344 +ENUM_VALUES_PER_LINE = 4
4345 +GENERATE_TREEVIEW = YES
4346 +TREEVIEW_WIDTH = 250
4347 +#---------------------------------------------------------------------------
4348 +# configuration options related to the LaTeX output
4349 +#---------------------------------------------------------------------------
4350 +GENERATE_LATEX = NO
4351 +LATEX_OUTPUT = latex
4352 +LATEX_CMD_NAME = latex
4353 +MAKEINDEX_CMD_NAME = makeindex
4354 +COMPACT_LATEX = NO
4355 +PAPER_TYPE = a4wide
4356 +EXTRA_PACKAGES =
4357 +LATEX_HEADER =
4358 +PDF_HYPERLINKS = NO
4359 +USE_PDFLATEX = NO
4360 +LATEX_BATCHMODE = NO
4361 +LATEX_HIDE_INDICES = NO
4362 +#---------------------------------------------------------------------------
4363 +# configuration options related to the RTF output
4364 +#---------------------------------------------------------------------------
4365 +GENERATE_RTF = NO
4366 +RTF_OUTPUT = rtf
4367 +COMPACT_RTF = NO
4368 +RTF_HYPERLINKS = NO
4369 +RTF_STYLESHEET_FILE =
4370 +RTF_EXTENSIONS_FILE =
4371 +#---------------------------------------------------------------------------
4372 +# configuration options related to the man page output
4373 +#---------------------------------------------------------------------------
4374 +GENERATE_MAN = NO
4375 +MAN_OUTPUT = man
4376 +MAN_EXTENSION = .3
4377 +MAN_LINKS = NO
4378 +#---------------------------------------------------------------------------
4379 +# configuration options related to the XML output
4380 +#---------------------------------------------------------------------------
4381 +GENERATE_XML = NO
4382 +XML_OUTPUT = xml
4383 +XML_SCHEMA =
4384 +XML_DTD =
4385 +XML_PROGRAMLISTING = YES
4386 +#---------------------------------------------------------------------------
4387 +# configuration options for the AutoGen Definitions output
4388 +#---------------------------------------------------------------------------
4389 +GENERATE_AUTOGEN_DEF = NO
4390 +#---------------------------------------------------------------------------
4391 +# configuration options related to the Perl module output
4392 +#---------------------------------------------------------------------------
4393 +GENERATE_PERLMOD = NO
4394 +PERLMOD_LATEX = NO
4395 +PERLMOD_PRETTY = YES
4396 +PERLMOD_MAKEVAR_PREFIX =
4397 +#---------------------------------------------------------------------------
4398 +# Configuration options related to the preprocessor
4399 +#---------------------------------------------------------------------------
4400 +ENABLE_PREPROCESSING = YES
4401 +MACRO_EXPANSION = NO
4402 +EXPAND_ONLY_PREDEF = NO
4403 +SEARCH_INCLUDES = YES
4404 +INCLUDE_PATH =
4405 +INCLUDE_FILE_PATTERNS =
4406 +PREDEFINED = DEBUG DEBUG_MEMORY
4407 +EXPAND_AS_DEFINED =
4408 +SKIP_FUNCTION_MACROS = YES
4409 +#---------------------------------------------------------------------------
4410 +# Configuration::additions related to external references
4411 +#---------------------------------------------------------------------------
4412 +TAGFILES =
4413 +GENERATE_TAGFILE =
4414 +ALLEXTERNALS = NO
4415 +EXTERNAL_GROUPS = YES
4416 +PERL_PATH = /usr/bin/perl
4417 +#---------------------------------------------------------------------------
4418 +# Configuration options related to the dot tool
4419 +#---------------------------------------------------------------------------
4420 +CLASS_DIAGRAMS = YES
4421 +HIDE_UNDOC_RELATIONS = YES
4422 +HAVE_DOT = NO
4423 +CLASS_GRAPH = YES
4424 +COLLABORATION_GRAPH = YES
4425 +GROUP_GRAPHS = YES
4426 +UML_LOOK = NO
4427 +TEMPLATE_RELATIONS = NO
4428 +INCLUDE_GRAPH = NO
4429 +INCLUDED_BY_GRAPH = YES
4430 +CALL_GRAPH = NO
4431 +GRAPHICAL_HIERARCHY = YES
4432 +DIRECTORY_GRAPH = YES
4433 +DOT_IMAGE_FORMAT = png
4434 +DOT_PATH =
4435 +DOTFILE_DIRS =
4436 +MAX_DOT_GRAPH_DEPTH = 1000
4437 +DOT_TRANSPARENT = NO
4438 +DOT_MULTI_TARGETS = NO
4439 +GENERATE_LEGEND = YES
4440 +DOT_CLEANUP = YES
4441 +#---------------------------------------------------------------------------
4442 +# Configuration::additions related to the search engine
4443 +#---------------------------------------------------------------------------
4444 +SEARCHENGINE = NO
4445 --- /dev/null
4446 +++ b/drivers/usb/host/dwc_common_port/dwc_cc.c
4447 @@ -0,0 +1,532 @@
4448 +/* =========================================================================
4449 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.c $
4450 + * $Revision: #4 $
4451 + * $Date: 2010/11/04 $
4452 + * $Change: 1621692 $
4453 + *
4454 + * Synopsys Portability Library Software and documentation
4455 + * (hereinafter, "Software") is an Unsupported proprietary work of
4456 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
4457 + * between Synopsys and you.
4458 + *
4459 + * The Software IS NOT an item of Licensed Software or Licensed Product
4460 + * under any End User Software License Agreement or Agreement for
4461 + * Licensed Product with Synopsys or any supplement thereto. You are
4462 + * permitted to use and redistribute this Software in source and binary
4463 + * forms, with or without modification, provided that redistributions
4464 + * of source code must retain this notice. You may not view, use,
4465 + * disclose, copy or distribute this file or any information contained
4466 + * herein except pursuant to this license grant from Synopsys. If you
4467 + * do not agree with this notice, including the disclaimer below, then
4468 + * you are not authorized to use the Software.
4469 + *
4470 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
4471 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4472 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
4473 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
4474 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
4475 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
4476 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
4477 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
4478 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4479 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
4480 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
4481 + * DAMAGE.
4482 + * ========================================================================= */
4483 +#ifdef DWC_CCLIB
4484 +
4485 +#include "dwc_cc.h"
4486 +
4487 +typedef struct dwc_cc
4488 +{
4489 + uint32_t uid;
4490 + uint8_t chid[16];
4491 + uint8_t cdid[16];
4492 + uint8_t ck[16];
4493 + uint8_t *name;
4494 + uint8_t length;
4495 + DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry;
4496 +} dwc_cc_t;
4497 +
4498 +DWC_CIRCLEQ_HEAD(context_list, dwc_cc);
4499 +
4500 +/** The main structure for CC management. */
4501 +struct dwc_cc_if
4502 +{
4503 + dwc_mutex_t *mutex;
4504 + char *filename;
4505 +
4506 + unsigned is_host:1;
4507 +
4508 + dwc_notifier_t *notifier;
4509 +
4510 + struct context_list list;
4511 +};
4512 +
4513 +#ifdef DEBUG
4514 +static inline void dump_bytes(char *name, uint8_t *bytes, int len)
4515 +{
4516 + int i;
4517 + DWC_PRINTF("%s: ", name);
4518 + for (i=0; i<len; i++) {
4519 + DWC_PRINTF("%02x ", bytes[i]);
4520 + }
4521 + DWC_PRINTF("\n");
4522 +}
4523 +#else
4524 +#define dump_bytes(x...)
4525 +#endif
4526 +
4527 +static dwc_cc_t *alloc_cc(void *mem_ctx, uint8_t *name, uint32_t length)
4528 +{
4529 + dwc_cc_t *cc = dwc_alloc(mem_ctx, sizeof(dwc_cc_t));
4530 + if (!cc) {
4531 + return NULL;
4532 + }
4533 + DWC_MEMSET(cc, 0, sizeof(dwc_cc_t));
4534 +
4535 + if (name) {
4536 + cc->length = length;
4537 + cc->name = dwc_alloc(mem_ctx, length);
4538 + if (!cc->name) {
4539 + dwc_free(mem_ctx, cc);
4540 + return NULL;
4541 + }
4542 +
4543 + DWC_MEMCPY(cc->name, name, length);
4544 + }
4545 +
4546 + return cc;
4547 +}
4548 +
4549 +static void free_cc(void *mem_ctx, dwc_cc_t *cc)
4550 +{
4551 + if (cc->name) {
4552 + dwc_free(mem_ctx, cc->name);
4553 + }
4554 + dwc_free(mem_ctx, cc);
4555 +}
4556 +
4557 +static uint32_t next_uid(dwc_cc_if_t *cc_if)
4558 +{
4559 + uint32_t uid = 0;
4560 + dwc_cc_t *cc;
4561 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4562 + if (cc->uid > uid) {
4563 + uid = cc->uid;
4564 + }
4565 + }
4566 +
4567 + if (uid == 0) {
4568 + uid = 255;
4569 + }
4570 +
4571 + return uid + 1;
4572 +}
4573 +
4574 +static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid)
4575 +{
4576 + dwc_cc_t *cc;
4577 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4578 + if (cc->uid == uid) {
4579 + return cc;
4580 + }
4581 + }
4582 + return NULL;
4583 +}
4584 +
4585 +static unsigned int cc_data_size(dwc_cc_if_t *cc_if)
4586 +{
4587 + unsigned int size = 0;
4588 + dwc_cc_t *cc;
4589 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4590 + size += (48 + 1);
4591 + if (cc->name) {
4592 + size += cc->length;
4593 + }
4594 + }
4595 + return size;
4596 +}
4597 +
4598 +static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
4599 +{
4600 + uint32_t uid = 0;
4601 + dwc_cc_t *cc;
4602 +
4603 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4604 + if (DWC_MEMCMP(cc->chid, chid, 16) == 0) {
4605 + uid = cc->uid;
4606 + break;
4607 + }
4608 + }
4609 + return uid;
4610 +}
4611 +static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
4612 +{
4613 + uint32_t uid = 0;
4614 + dwc_cc_t *cc;
4615 +
4616 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4617 + if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) {
4618 + uid = cc->uid;
4619 + break;
4620 + }
4621 + }
4622 + return uid;
4623 +}
4624 +
4625 +/* Internal cc_add */
4626 +static int32_t cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
4627 + uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
4628 +{
4629 + dwc_cc_t *cc;
4630 + uint32_t uid;
4631 +
4632 + if (cc_if->is_host) {
4633 + uid = cc_match_cdid(cc_if, cdid);
4634 + }
4635 + else {
4636 + uid = cc_match_chid(cc_if, chid);
4637 + }
4638 +
4639 + if (uid) {
4640 + DWC_DEBUGC("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length);
4641 + cc = cc_find(cc_if, uid);
4642 + }
4643 + else {
4644 + cc = alloc_cc(mem_ctx, name, length);
4645 + cc->uid = next_uid(cc_if);
4646 + DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry);
4647 + }
4648 +
4649 + DWC_MEMCPY(&(cc->chid[0]), chid, 16);
4650 + DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
4651 + DWC_MEMCPY(&(cc->ck[0]), ck, 16);
4652 +
4653 + DWC_DEBUGC("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length);
4654 + dump_bytes("CHID", cc->chid, 16);
4655 + dump_bytes("CDID", cc->cdid, 16);
4656 + dump_bytes("CK", cc->ck, 16);
4657 + return cc->uid;
4658 +}
4659 +
4660 +/* Internal cc_clear */
4661 +static void cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
4662 +{
4663 + while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) {
4664 + dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list);
4665 + DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
4666 + free_cc(mem_ctx, cc);
4667 + }
4668 +}
4669 +
4670 +dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
4671 + dwc_notifier_t *notifier, unsigned is_host)
4672 +{
4673 + dwc_cc_if_t *cc_if = NULL;
4674 +
4675 + /* Allocate a common_cc_if structure */
4676 + cc_if = dwc_alloc(mem_ctx, sizeof(dwc_cc_if_t));
4677 +
4678 + if (!cc_if)
4679 + return NULL;
4680 +
4681 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
4682 + DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex);
4683 +#else
4684 + cc_if->mutex = dwc_mutex_alloc(mtx_ctx);
4685 +#endif
4686 + if (!cc_if->mutex) {
4687 + dwc_free(mem_ctx, cc_if);
4688 + return NULL;
4689 + }
4690 +
4691 + DWC_CIRCLEQ_INIT(&cc_if->list);
4692 + cc_if->is_host = is_host;
4693 + cc_if->notifier = notifier;
4694 + return cc_if;
4695 +}
4696 +
4697 +void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if)
4698 +{
4699 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
4700 + DWC_MUTEX_FREE(cc_if->mutex);
4701 +#else
4702 + dwc_mutex_free(mtx_ctx, cc_if->mutex);
4703 +#endif
4704 + cc_clear(mem_ctx, cc_if);
4705 + dwc_free(mem_ctx, cc_if);
4706 +}
4707 +
4708 +static void cc_changed(dwc_cc_if_t *cc_if)
4709 +{
4710 + if (cc_if->notifier) {
4711 + dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if);
4712 + }
4713 +}
4714 +
4715 +void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
4716 +{
4717 + DWC_MUTEX_LOCK(cc_if->mutex);
4718 + cc_clear(mem_ctx, cc_if);
4719 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4720 + cc_changed(cc_if);
4721 +}
4722 +
4723 +int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
4724 + uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
4725 +{
4726 + uint32_t uid;
4727 +
4728 + DWC_MUTEX_LOCK(cc_if->mutex);
4729 + uid = cc_add(mem_ctx, cc_if, chid, cdid, ck, name, length);
4730 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4731 + cc_changed(cc_if);
4732 +
4733 + return uid;
4734 +}
4735 +
4736 +void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid,
4737 + uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
4738 +{
4739 + dwc_cc_t* cc;
4740 +
4741 + DWC_DEBUGC("Change connection context %d", id);
4742 +
4743 + DWC_MUTEX_LOCK(cc_if->mutex);
4744 + cc = cc_find(cc_if, id);
4745 + if (!cc) {
4746 + DWC_ERROR("Uid %d not found in cc list\n", id);
4747 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4748 + return;
4749 + }
4750 +
4751 + if (chid) {
4752 + DWC_MEMCPY(&(cc->chid[0]), chid, 16);
4753 + }
4754 + if (cdid) {
4755 + DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
4756 + }
4757 + if (ck) {
4758 + DWC_MEMCPY(&(cc->ck[0]), ck, 16);
4759 + }
4760 +
4761 + if (name) {
4762 + if (cc->name) {
4763 + dwc_free(mem_ctx, cc->name);
4764 + }
4765 + cc->name = dwc_alloc(mem_ctx, length);
4766 + if (!cc->name) {
4767 + DWC_ERROR("Out of memory in dwc_cc_change()\n");
4768 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4769 + return;
4770 + }
4771 + cc->length = length;
4772 + DWC_MEMCPY(cc->name, name, length);
4773 + }
4774 +
4775 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4776 +
4777 + cc_changed(cc_if);
4778 +
4779 + DWC_DEBUGC("Changed connection context id=%d\n", id);
4780 + dump_bytes("New CHID", cc->chid, 16);
4781 + dump_bytes("New CDID", cc->cdid, 16);
4782 + dump_bytes("New CK", cc->ck, 16);
4783 +}
4784 +
4785 +void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id)
4786 +{
4787 + dwc_cc_t *cc;
4788 +
4789 + DWC_DEBUGC("Removing connection context %d", id);
4790 +
4791 + DWC_MUTEX_LOCK(cc_if->mutex);
4792 + cc = cc_find(cc_if, id);
4793 + if (!cc) {
4794 + DWC_ERROR("Uid %d not found in cc list\n", id);
4795 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4796 + return;
4797 + }
4798 +
4799 + DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
4800 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4801 + free_cc(mem_ctx, cc);
4802 +
4803 + cc_changed(cc_if);
4804 +}
4805 +
4806 +uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, unsigned int *length)
4807 +{
4808 + uint8_t *buf, *x;
4809 + uint8_t zero = 0;
4810 + dwc_cc_t *cc;
4811 +
4812 + DWC_MUTEX_LOCK(cc_if->mutex);
4813 + *length = cc_data_size(cc_if);
4814 + if (!(*length)) {
4815 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4816 + return NULL;
4817 + }
4818 +
4819 + DWC_DEBUGC("Creating data for saving (length=%d)", *length);
4820 +
4821 + buf = dwc_alloc(mem_ctx, *length);
4822 + if (!buf) {
4823 + *length = 0;
4824 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4825 + return NULL;
4826 + }
4827 +
4828 + x = buf;
4829 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4830 + DWC_MEMCPY(x, cc->chid, 16);
4831 + x += 16;
4832 + DWC_MEMCPY(x, cc->cdid, 16);
4833 + x += 16;
4834 + DWC_MEMCPY(x, cc->ck, 16);
4835 + x += 16;
4836 + if (cc->name) {
4837 + DWC_MEMCPY(x, &cc->length, 1);
4838 + x += 1;
4839 + DWC_MEMCPY(x, cc->name, cc->length);
4840 + x += cc->length;
4841 + }
4842 + else {
4843 + DWC_MEMCPY(x, &zero, 1);
4844 + x += 1;
4845 + }
4846 + }
4847 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4848 +
4849 + return buf;
4850 +}
4851 +
4852 +void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length)
4853 +{
4854 + uint8_t name_length;
4855 + uint8_t *name;
4856 + uint8_t *chid;
4857 + uint8_t *cdid;
4858 + uint8_t *ck;
4859 + uint32_t i = 0;
4860 +
4861 + DWC_MUTEX_LOCK(cc_if->mutex);
4862 + cc_clear(mem_ctx, cc_if);
4863 +
4864 + while (i < length) {
4865 + chid = &data[i];
4866 + i += 16;
4867 + cdid = &data[i];
4868 + i += 16;
4869 + ck = &data[i];
4870 + i += 16;
4871 +
4872 + name_length = data[i];
4873 + i ++;
4874 +
4875 + if (name_length) {
4876 + name = &data[i];
4877 + i += name_length;
4878 + }
4879 + else {
4880 + name = NULL;
4881 + }
4882 +
4883 + /* check to see if we haven't overflown the buffer */
4884 + if (i > length) {
4885 + DWC_ERROR("Data format error while attempting to load CCs "
4886 + "(nlen=%d, iter=%d, buflen=%d).\n", name_length, i, length);
4887 + break;
4888 + }
4889 +
4890 + cc_add(mem_ctx, cc_if, chid, cdid, ck, name, name_length);
4891 + }
4892 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4893 +
4894 + cc_changed(cc_if);
4895 +}
4896 +
4897 +uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
4898 +{
4899 + uint32_t uid = 0;
4900 +
4901 + DWC_MUTEX_LOCK(cc_if->mutex);
4902 + uid = cc_match_chid(cc_if, chid);
4903 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4904 + return uid;
4905 +}
4906 +uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
4907 +{
4908 + uint32_t uid = 0;
4909 +
4910 + DWC_MUTEX_LOCK(cc_if->mutex);
4911 + uid = cc_match_cdid(cc_if, cdid);
4912 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4913 + return uid;
4914 +}
4915 +
4916 +uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id)
4917 +{
4918 + uint8_t *ck = NULL;
4919 + dwc_cc_t *cc;
4920 +
4921 + DWC_MUTEX_LOCK(cc_if->mutex);
4922 + cc = cc_find(cc_if, id);
4923 + if (cc) {
4924 + ck = cc->ck;
4925 + }
4926 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4927 +
4928 + return ck;
4929 +
4930 +}
4931 +
4932 +uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id)
4933 +{
4934 + uint8_t *retval = NULL;
4935 + dwc_cc_t *cc;
4936 +
4937 + DWC_MUTEX_LOCK(cc_if->mutex);
4938 + cc = cc_find(cc_if, id);
4939 + if (cc) {
4940 + retval = cc->chid;
4941 + }
4942 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4943 +
4944 + return retval;
4945 +}
4946 +
4947 +uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id)
4948 +{
4949 + uint8_t *retval = NULL;
4950 + dwc_cc_t *cc;
4951 +
4952 + DWC_MUTEX_LOCK(cc_if->mutex);
4953 + cc = cc_find(cc_if, id);
4954 + if (cc) {
4955 + retval = cc->cdid;
4956 + }
4957 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4958 +
4959 + return retval;
4960 +}
4961 +
4962 +uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length)
4963 +{
4964 + uint8_t *retval = NULL;
4965 + dwc_cc_t *cc;
4966 +
4967 + DWC_MUTEX_LOCK(cc_if->mutex);
4968 + *length = 0;
4969 + cc = cc_find(cc_if, id);
4970 + if (cc) {
4971 + *length = cc->length;
4972 + retval = cc->name;
4973 + }
4974 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4975 +
4976 + return retval;
4977 +}
4978 +
4979 +#endif /* DWC_CCLIB */
4980 --- /dev/null
4981 +++ b/drivers/usb/host/dwc_common_port/dwc_cc.h
4982 @@ -0,0 +1,225 @@
4983 +/* =========================================================================
4984 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.h $
4985 + * $Revision: #4 $
4986 + * $Date: 2010/09/28 $
4987 + * $Change: 1596182 $
4988 + *
4989 + * Synopsys Portability Library Software and documentation
4990 + * (hereinafter, "Software") is an Unsupported proprietary work of
4991 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
4992 + * between Synopsys and you.
4993 + *
4994 + * The Software IS NOT an item of Licensed Software or Licensed Product
4995 + * under any End User Software License Agreement or Agreement for
4996 + * Licensed Product with Synopsys or any supplement thereto. You are
4997 + * permitted to use and redistribute this Software in source and binary
4998 + * forms, with or without modification, provided that redistributions
4999 + * of source code must retain this notice. You may not view, use,
5000 + * disclose, copy or distribute this file or any information contained
5001 + * herein except pursuant to this license grant from Synopsys. If you
5002 + * do not agree with this notice, including the disclaimer below, then
5003 + * you are not authorized to use the Software.
5004 + *
5005 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
5006 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5007 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
5008 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
5009 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
5010 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
5011 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
5012 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
5013 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5014 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
5015 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
5016 + * DAMAGE.
5017 + * ========================================================================= */
5018 +#ifndef _DWC_CC_H_
5019 +#define _DWC_CC_H_
5020 +
5021 +#ifdef __cplusplus
5022 +extern "C" {
5023 +#endif
5024 +
5025 +/** @file
5026 + *
5027 + * This file defines the Context Context library.
5028 + *
5029 + * The main data structure is dwc_cc_if_t which is returned by either the
5030 + * dwc_cc_if_alloc function or returned by the module to the user via a provided
5031 + * function. The data structure is opaque and should only be manipulated via the
5032 + * functions provied in this API.
5033 + *
5034 + * It manages a list of connection contexts and operations can be performed to
5035 + * add, remove, query, search, and change, those contexts. Additionally,
5036 + * a dwc_notifier_t object can be requested from the manager so that
5037 + * the user can be notified whenever the context list has changed.
5038 + */
5039 +
5040 +#include "dwc_os.h"
5041 +#include "dwc_list.h"
5042 +#include "dwc_notifier.h"
5043 +
5044 +
5045 +/* Notifications */
5046 +#define DWC_CC_LIST_CHANGED_NOTIFICATION "DWC_CC_LIST_CHANGED_NOTIFICATION"
5047 +
5048 +struct dwc_cc_if;
5049 +typedef struct dwc_cc_if dwc_cc_if_t;
5050 +
5051 +
5052 +/** @name Connection Context Operations */
5053 +/** @{ */
5054 +
5055 +/** This function allocates memory for a dwc_cc_if_t structure, initializes
5056 + * fields to default values, and returns a pointer to the structure or NULL on
5057 + * error. */
5058 +extern dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
5059 + dwc_notifier_t *notifier, unsigned is_host);
5060 +
5061 +/** Frees the memory for the specified CC structure allocated from
5062 + * dwc_cc_if_alloc(). */
5063 +extern void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if);
5064 +
5065 +/** Removes all contexts from the connection context list */
5066 +extern void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if);
5067 +
5068 +/** Adds a connection context (CHID, CK, CDID, Name) to the connection context list.
5069 + * If a CHID already exists, the CK and name are overwritten. Statistics are
5070 + * not overwritten.
5071 + *
5072 + * @param cc_if The cc_if structure.
5073 + * @param chid A pointer to the 16-byte CHID. This value will be copied.
5074 + * @param ck A pointer to the 16-byte CK. This value will be copied.
5075 + * @param cdid A pointer to the 16-byte CDID. This value will be copied.
5076 + * @param name An optional host friendly name as defined in the association model
5077 + * spec. Must be a UTF16-LE unicode string. Can be NULL to indicated no name.
5078 + * @param length The length othe unicode string.
5079 + * @return A unique identifier used to refer to this context that is valid for
5080 + * as long as this context is still in the list. */
5081 +extern int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
5082 + uint8_t *cdid, uint8_t *ck, uint8_t *name,
5083 + uint8_t length);
5084 +
5085 +/** Changes the CHID, CK, CDID, or Name values of a connection context in the
5086 + * list, preserving any accumulated statistics. This would typically be called
5087 + * if the host decideds to change the context with a SET_CONNECTION request.
5088 + *
5089 + * @param cc_if The cc_if structure.
5090 + * @param id The identifier of the connection context.
5091 + * @param chid A pointer to the 16-byte CHID. This value will be copied. NULL
5092 + * indicates no change.
5093 + * @param cdid A pointer to the 16-byte CDID. This value will be copied. NULL
5094 + * indicates no change.
5095 + * @param ck A pointer to the 16-byte CK. This value will be copied. NULL
5096 + * indicates no change.
5097 + * @param name Host friendly name UTF16-LE. NULL indicates no change.
5098 + * @param length Length of name. */
5099 +extern void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id,
5100 + uint8_t *chid, uint8_t *cdid, uint8_t *ck,
5101 + uint8_t *name, uint8_t length);
5102 +
5103 +/** Remove the specified connection context.
5104 + * @param cc_if The cc_if structure.
5105 + * @param id The identifier of the connection context to remove. */
5106 +extern void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id);
5107 +
5108 +/** Get a binary block of data for the connection context list and attributes.
5109 + * This data can be used by the OS specific driver to save the connection
5110 + * context list into non-volatile memory.
5111 + *
5112 + * @param cc_if The cc_if structure.
5113 + * @param length Return the length of the data buffer.
5114 + * @return A pointer to the data buffer. The memory for this buffer should be
5115 + * freed with DWC_FREE() after use. */
5116 +extern uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if,
5117 + unsigned int *length);
5118 +
5119 +/** Restore the connection context list from the binary data that was previously
5120 + * returned from a call to dwc_cc_data_for_save. This can be used by the OS specific
5121 + * driver to load a connection context list from non-volatile memory.
5122 + *
5123 + * @param cc_if The cc_if structure.
5124 + * @param data The data bytes as returned from dwc_cc_data_for_save.
5125 + * @param length The length of the data. */
5126 +extern void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if,
5127 + uint8_t *data, unsigned int length);
5128 +
5129 +/** Find the connection context from the specified CHID.
5130 + *
5131 + * @param cc_if The cc_if structure.
5132 + * @param chid A pointer to the CHID data.
5133 + * @return A non-zero identifier of the connection context if the CHID matches.
5134 + * Otherwise returns 0. */
5135 +extern uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid);
5136 +
5137 +/** Find the connection context from the specified CDID.
5138 + *
5139 + * @param cc_if The cc_if structure.
5140 + * @param cdid A pointer to the CDID data.
5141 + * @return A non-zero identifier of the connection context if the CHID matches.
5142 + * Otherwise returns 0. */
5143 +extern uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid);
5144 +
5145 +/** Retrieve the CK from the specified connection context.
5146 + *
5147 + * @param cc_if The cc_if structure.
5148 + * @param id The identifier of the connection context.
5149 + * @return A pointer to the CK data. The memory does not need to be freed. */
5150 +extern uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id);
5151 +
5152 +/** Retrieve the CHID from the specified connection context.
5153 + *
5154 + * @param cc_if The cc_if structure.
5155 + * @param id The identifier of the connection context.
5156 + * @return A pointer to the CHID data. The memory does not need to be freed. */
5157 +extern uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id);
5158 +
5159 +/** Retrieve the CDID from the specified connection context.
5160 + *
5161 + * @param cc_if The cc_if structure.
5162 + * @param id The identifier of the connection context.
5163 + * @return A pointer to the CDID data. The memory does not need to be freed. */
5164 +extern uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id);
5165 +
5166 +extern uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length);
5167 +
5168 +/** Checks a buffer for non-zero.
5169 + * @param id A pointer to a 16 byte buffer.
5170 + * @return true if the 16 byte value is non-zero. */
5171 +static inline unsigned dwc_assoc_is_not_zero_id(uint8_t *id) {
5172 + int i;
5173 + for (i=0; i<16; i++) {
5174 + if (id[i]) return 1;
5175 + }
5176 + return 0;
5177 +}
5178 +
5179 +/** Checks a buffer for zero.
5180 + * @param id A pointer to a 16 byte buffer.
5181 + * @return true if the 16 byte value is zero. */
5182 +static inline unsigned dwc_assoc_is_zero_id(uint8_t *id) {
5183 + return !dwc_assoc_is_not_zero_id(id);
5184 +}
5185 +
5186 +/** Prints an ASCII representation for the 16-byte chid, cdid, or ck, into
5187 + * buffer. */
5188 +static inline int dwc_print_id_string(char *buffer, uint8_t *id) {
5189 + char *ptr = buffer;
5190 + int i;
5191 + for (i=0; i<16; i++) {
5192 + ptr += DWC_SPRINTF(ptr, "%02x", id[i]);
5193 + if (i < 15) {
5194 + ptr += DWC_SPRINTF(ptr, " ");
5195 + }
5196 + }
5197 + return ptr - buffer;
5198 +}
5199 +
5200 +/** @} */
5201 +
5202 +#ifdef __cplusplus
5203 +}
5204 +#endif
5205 +
5206 +#endif /* _DWC_CC_H_ */
5207 +
5208 --- /dev/null
5209 +++ b/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
5210 @@ -0,0 +1,1308 @@
5211 +#include "dwc_os.h"
5212 +#include "dwc_list.h"
5213 +
5214 +#ifdef DWC_CCLIB
5215 +# include "dwc_cc.h"
5216 +#endif
5217 +
5218 +#ifdef DWC_CRYPTOLIB
5219 +# include "dwc_modpow.h"
5220 +# include "dwc_dh.h"
5221 +# include "dwc_crypto.h"
5222 +#endif
5223 +
5224 +#ifdef DWC_NOTIFYLIB
5225 +# include "dwc_notifier.h"
5226 +#endif
5227 +
5228 +/* OS-Level Implementations */
5229 +
5230 +/* This is the FreeBSD 7.0 kernel implementation of the DWC platform library. */
5231 +
5232 +
5233 +/* MISC */
5234 +
5235 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
5236 +{
5237 + return memset(dest, byte, size);
5238 +}
5239 +
5240 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
5241 +{
5242 + return memcpy(dest, src, size);
5243 +}
5244 +
5245 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
5246 +{
5247 + bcopy(src, dest, size);
5248 + return dest;
5249 +}
5250 +
5251 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
5252 +{
5253 + return memcmp(m1, m2, size);
5254 +}
5255 +
5256 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
5257 +{
5258 + return strncmp(s1, s2, size);
5259 +}
5260 +
5261 +int DWC_STRCMP(void *s1, void *s2)
5262 +{
5263 + return strcmp(s1, s2);
5264 +}
5265 +
5266 +int DWC_STRLEN(char const *str)
5267 +{
5268 + return strlen(str);
5269 +}
5270 +
5271 +char *DWC_STRCPY(char *to, char const *from)
5272 +{
5273 + return strcpy(to, from);
5274 +}
5275 +
5276 +char *DWC_STRDUP(char const *str)
5277 +{
5278 + int len = DWC_STRLEN(str) + 1;
5279 + char *new = DWC_ALLOC_ATOMIC(len);
5280 +
5281 + if (!new) {
5282 + return NULL;
5283 + }
5284 +
5285 + DWC_MEMCPY(new, str, len);
5286 + return new;
5287 +}
5288 +
5289 +int DWC_ATOI(char *str, int32_t *value)
5290 +{
5291 + char *end = NULL;
5292 +
5293 + *value = strtol(str, &end, 0);
5294 + if (*end == '\0') {
5295 + return 0;
5296 + }
5297 +
5298 + return -1;
5299 +}
5300 +
5301 +int DWC_ATOUI(char *str, uint32_t *value)
5302 +{
5303 + char *end = NULL;
5304 +
5305 + *value = strtoul(str, &end, 0);
5306 + if (*end == '\0') {
5307 + return 0;
5308 + }
5309 +
5310 + return -1;
5311 +}
5312 +
5313 +
5314 +#ifdef DWC_UTFLIB
5315 +/* From usbstring.c */
5316 +
5317 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
5318 +{
5319 + int count = 0;
5320 + u8 c;
5321 + u16 uchar;
5322 +
5323 + /* this insists on correct encodings, though not minimal ones.
5324 + * BUT it currently rejects legit 4-byte UTF-8 code points,
5325 + * which need surrogate pairs. (Unicode 3.1 can use them.)
5326 + */
5327 + while (len != 0 && (c = (u8) *s++) != 0) {
5328 + if (unlikely(c & 0x80)) {
5329 + // 2-byte sequence:
5330 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
5331 + if ((c & 0xe0) == 0xc0) {
5332 + uchar = (c & 0x1f) << 6;
5333 +
5334 + c = (u8) *s++;
5335 + if ((c & 0xc0) != 0xc0)
5336 + goto fail;
5337 + c &= 0x3f;
5338 + uchar |= c;
5339 +
5340 + // 3-byte sequence (most CJKV characters):
5341 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
5342 + } else if ((c & 0xf0) == 0xe0) {
5343 + uchar = (c & 0x0f) << 12;
5344 +
5345 + c = (u8) *s++;
5346 + if ((c & 0xc0) != 0xc0)
5347 + goto fail;
5348 + c &= 0x3f;
5349 + uchar |= c << 6;
5350 +
5351 + c = (u8) *s++;
5352 + if ((c & 0xc0) != 0xc0)
5353 + goto fail;
5354 + c &= 0x3f;
5355 + uchar |= c;
5356 +
5357 + /* no bogus surrogates */
5358 + if (0xd800 <= uchar && uchar <= 0xdfff)
5359 + goto fail;
5360 +
5361 + // 4-byte sequence (surrogate pairs, currently rare):
5362 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
5363 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
5364 + // (uuuuu = wwww + 1)
5365 + // FIXME accept the surrogate code points (only)
5366 + } else
5367 + goto fail;
5368 + } else
5369 + uchar = c;
5370 + put_unaligned (cpu_to_le16 (uchar), cp++);
5371 + count++;
5372 + len--;
5373 + }
5374 + return count;
5375 +fail:
5376 + return -1;
5377 +}
5378 +
5379 +#endif /* DWC_UTFLIB */
5380 +
5381 +
5382 +/* dwc_debug.h */
5383 +
5384 +dwc_bool_t DWC_IN_IRQ(void)
5385 +{
5386 +// return in_irq();
5387 + return 0;
5388 +}
5389 +
5390 +dwc_bool_t DWC_IN_BH(void)
5391 +{
5392 +// return in_softirq();
5393 + return 0;
5394 +}
5395 +
5396 +void DWC_VPRINTF(char *format, va_list args)
5397 +{
5398 + vprintf(format, args);
5399 +}
5400 +
5401 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
5402 +{
5403 + return vsnprintf(str, size, format, args);
5404 +}
5405 +
5406 +void DWC_PRINTF(char *format, ...)
5407 +{
5408 + va_list args;
5409 +
5410 + va_start(args, format);
5411 + DWC_VPRINTF(format, args);
5412 + va_end(args);
5413 +}
5414 +
5415 +int DWC_SPRINTF(char *buffer, char *format, ...)
5416 +{
5417 + int retval;
5418 + va_list args;
5419 +
5420 + va_start(args, format);
5421 + retval = vsprintf(buffer, format, args);
5422 + va_end(args);
5423 + return retval;
5424 +}
5425 +
5426 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
5427 +{
5428 + int retval;
5429 + va_list args;
5430 +
5431 + va_start(args, format);
5432 + retval = vsnprintf(buffer, size, format, args);
5433 + va_end(args);
5434 + return retval;
5435 +}
5436 +
5437 +void __DWC_WARN(char *format, ...)
5438 +{
5439 + va_list args;
5440 +
5441 + va_start(args, format);
5442 + DWC_VPRINTF(format, args);
5443 + va_end(args);
5444 +}
5445 +
5446 +void __DWC_ERROR(char *format, ...)
5447 +{
5448 + va_list args;
5449 +
5450 + va_start(args, format);
5451 + DWC_VPRINTF(format, args);
5452 + va_end(args);
5453 +}
5454 +
5455 +void DWC_EXCEPTION(char *format, ...)
5456 +{
5457 + va_list args;
5458 +
5459 + va_start(args, format);
5460 + DWC_VPRINTF(format, args);
5461 + va_end(args);
5462 +// BUG_ON(1); ???
5463 +}
5464 +
5465 +#ifdef DEBUG
5466 +void __DWC_DEBUG(char *format, ...)
5467 +{
5468 + va_list args;
5469 +
5470 + va_start(args, format);
5471 + DWC_VPRINTF(format, args);
5472 + va_end(args);
5473 +}
5474 +#endif
5475 +
5476 +
5477 +/* dwc_mem.h */
5478 +
5479 +#if 0
5480 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
5481 + uint32_t align,
5482 + uint32_t alloc)
5483 +{
5484 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
5485 + size, align, alloc);
5486 + return (dwc_pool_t *)pool;
5487 +}
5488 +
5489 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
5490 +{
5491 + dma_pool_destroy((struct dma_pool *)pool);
5492 +}
5493 +
5494 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
5495 +{
5496 +// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
5497 + return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
5498 +}
5499 +
5500 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
5501 +{
5502 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
5503 + memset(..);
5504 +}
5505 +
5506 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
5507 +{
5508 + dma_pool_free(pool, vaddr, daddr);
5509 +}
5510 +#endif
5511 +
5512 +static void dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
5513 +{
5514 + if (error)
5515 + return;
5516 + *(bus_addr_t *)arg = segs[0].ds_addr;
5517 +}
5518 +
5519 +void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
5520 +{
5521 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
5522 + int error;
5523 +
5524 + error = bus_dma_tag_create(
5525 +#if __FreeBSD_version >= 700000
5526 + bus_get_dma_tag(dma->dev), /* parent */
5527 +#else
5528 + NULL, /* parent */
5529 +#endif
5530 + 4, 0, /* alignment, bounds */
5531 + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
5532 + BUS_SPACE_MAXADDR, /* highaddr */
5533 + NULL, NULL, /* filter, filterarg */
5534 + size, /* maxsize */
5535 + 1, /* nsegments */
5536 + size, /* maxsegsize */
5537 + 0, /* flags */
5538 + NULL, /* lockfunc */
5539 + NULL, /* lockarg */
5540 + &dma->dma_tag);
5541 + if (error) {
5542 + device_printf(dma->dev, "%s: bus_dma_tag_create failed: %d\n",
5543 + __func__, error);
5544 + goto fail_0;
5545 + }
5546 +
5547 + error = bus_dmamem_alloc(dma->dma_tag, &dma->dma_vaddr,
5548 + BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dma->dma_map);
5549 + if (error) {
5550 + device_printf(dma->dev, "%s: bus_dmamem_alloc(%ju) failed: %d\n",
5551 + __func__, (uintmax_t)size, error);
5552 + goto fail_1;
5553 + }
5554 +
5555 + dma->dma_paddr = 0;
5556 + error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, size,
5557 + dmamap_cb, &dma->dma_paddr, BUS_DMA_NOWAIT);
5558 + if (error || dma->dma_paddr == 0) {
5559 + device_printf(dma->dev, "%s: bus_dmamap_load failed: %d\n",
5560 + __func__, error);
5561 + goto fail_2;
5562 + }
5563 +
5564 + *dma_addr = dma->dma_paddr;
5565 + return dma->dma_vaddr;
5566 +
5567 +fail_2:
5568 + bus_dmamap_unload(dma->dma_tag, dma->dma_map);
5569 +fail_1:
5570 + bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
5571 + bus_dma_tag_destroy(dma->dma_tag);
5572 +fail_0:
5573 + dma->dma_map = NULL;
5574 + dma->dma_tag = NULL;
5575 +
5576 + return NULL;
5577 +}
5578 +
5579 +void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
5580 +{
5581 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
5582 +
5583 + if (dma->dma_tag == NULL)
5584 + return;
5585 + if (dma->dma_map != NULL) {
5586 + bus_dmamap_sync(dma->dma_tag, dma->dma_map,
5587 + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
5588 + bus_dmamap_unload(dma->dma_tag, dma->dma_map);
5589 + bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
5590 + dma->dma_map = NULL;
5591 + }
5592 +
5593 + bus_dma_tag_destroy(dma->dma_tag);
5594 + dma->dma_tag = NULL;
5595 +}
5596 +
5597 +void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
5598 +{
5599 + return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
5600 +}
5601 +
5602 +void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
5603 +{
5604 + return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
5605 +}
5606 +
5607 +void __DWC_FREE(void *mem_ctx, void *addr)
5608 +{
5609 + free(addr, M_DEVBUF);
5610 +}
5611 +
5612 +
5613 +#ifdef DWC_CRYPTOLIB
5614 +/* dwc_crypto.h */
5615 +
5616 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
5617 +{
5618 + get_random_bytes(buffer, length);
5619 +}
5620 +
5621 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
5622 +{
5623 + struct crypto_blkcipher *tfm;
5624 + struct blkcipher_desc desc;
5625 + struct scatterlist sgd;
5626 + struct scatterlist sgs;
5627 +
5628 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
5629 + if (tfm == NULL) {
5630 + printk("failed to load transform for aes CBC\n");
5631 + return -1;
5632 + }
5633 +
5634 + crypto_blkcipher_setkey(tfm, key, keylen);
5635 + crypto_blkcipher_set_iv(tfm, iv, 16);
5636 +
5637 + sg_init_one(&sgd, out, messagelen);
5638 + sg_init_one(&sgs, message, messagelen);
5639 +
5640 + desc.tfm = tfm;
5641 + desc.flags = 0;
5642 +
5643 + if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
5644 + crypto_free_blkcipher(tfm);
5645 + DWC_ERROR("AES CBC encryption failed");
5646 + return -1;
5647 + }
5648 +
5649 + crypto_free_blkcipher(tfm);
5650 + return 0;
5651 +}
5652 +
5653 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
5654 +{
5655 + struct crypto_hash *tfm;
5656 + struct hash_desc desc;
5657 + struct scatterlist sg;
5658 +
5659 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
5660 + if (IS_ERR(tfm)) {
5661 + DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
5662 + return 0;
5663 + }
5664 + desc.tfm = tfm;
5665 + desc.flags = 0;
5666 +
5667 + sg_init_one(&sg, message, len);
5668 + crypto_hash_digest(&desc, &sg, len, out);
5669 + crypto_free_hash(tfm);
5670 +
5671 + return 1;
5672 +}
5673 +
5674 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
5675 + uint8_t *key, uint32_t keylen, uint8_t *out)
5676 +{
5677 + struct crypto_hash *tfm;
5678 + struct hash_desc desc;
5679 + struct scatterlist sg;
5680 +
5681 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
5682 + if (IS_ERR(tfm)) {
5683 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
5684 + return 0;
5685 + }
5686 + desc.tfm = tfm;
5687 + desc.flags = 0;
5688 +
5689 + sg_init_one(&sg, message, messagelen);
5690 + crypto_hash_setkey(tfm, key, keylen);
5691 + crypto_hash_digest(&desc, &sg, messagelen, out);
5692 + crypto_free_hash(tfm);
5693 +
5694 + return 1;
5695 +}
5696 +
5697 +#endif /* DWC_CRYPTOLIB */
5698 +
5699 +
5700 +/* Byte Ordering Conversions */
5701 +
5702 +uint32_t DWC_CPU_TO_LE32(uint32_t *p)
5703 +{
5704 +#ifdef __LITTLE_ENDIAN
5705 + return *p;
5706 +#else
5707 + uint8_t *u_p = (uint8_t *)p;
5708 +
5709 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
5710 +#endif
5711 +}
5712 +
5713 +uint32_t DWC_CPU_TO_BE32(uint32_t *p)
5714 +{
5715 +#ifdef __BIG_ENDIAN
5716 + return *p;
5717 +#else
5718 + uint8_t *u_p = (uint8_t *)p;
5719 +
5720 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
5721 +#endif
5722 +}
5723 +
5724 +uint32_t DWC_LE32_TO_CPU(uint32_t *p)
5725 +{
5726 +#ifdef __LITTLE_ENDIAN
5727 + return *p;
5728 +#else
5729 + uint8_t *u_p = (uint8_t *)p;
5730 +
5731 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
5732 +#endif
5733 +}
5734 +
5735 +uint32_t DWC_BE32_TO_CPU(uint32_t *p)
5736 +{
5737 +#ifdef __BIG_ENDIAN
5738 + return *p;
5739 +#else
5740 + uint8_t *u_p = (uint8_t *)p;
5741 +
5742 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
5743 +#endif
5744 +}
5745 +
5746 +uint16_t DWC_CPU_TO_LE16(uint16_t *p)
5747 +{
5748 +#ifdef __LITTLE_ENDIAN
5749 + return *p;
5750 +#else
5751 + uint8_t *u_p = (uint8_t *)p;
5752 + return (u_p[1] | (u_p[0] << 8));
5753 +#endif
5754 +}
5755 +
5756 +uint16_t DWC_CPU_TO_BE16(uint16_t *p)
5757 +{
5758 +#ifdef __BIG_ENDIAN
5759 + return *p;
5760 +#else
5761 + uint8_t *u_p = (uint8_t *)p;
5762 + return (u_p[1] | (u_p[0] << 8));
5763 +#endif
5764 +}
5765 +
5766 +uint16_t DWC_LE16_TO_CPU(uint16_t *p)
5767 +{
5768 +#ifdef __LITTLE_ENDIAN
5769 + return *p;
5770 +#else
5771 + uint8_t *u_p = (uint8_t *)p;
5772 + return (u_p[1] | (u_p[0] << 8));
5773 +#endif
5774 +}
5775 +
5776 +uint16_t DWC_BE16_TO_CPU(uint16_t *p)
5777 +{
5778 +#ifdef __BIG_ENDIAN
5779 + return *p;
5780 +#else
5781 + uint8_t *u_p = (uint8_t *)p;
5782 + return (u_p[1] | (u_p[0] << 8));
5783 +#endif
5784 +}
5785 +
5786 +
5787 +/* Registers */
5788 +
5789 +uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
5790 +{
5791 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
5792 + bus_size_t ior = (bus_size_t)reg;
5793 +
5794 + return bus_space_read_4(io->iot, io->ioh, ior);
5795 +}
5796 +
5797 +#if 0
5798 +uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
5799 +{
5800 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
5801 + bus_size_t ior = (bus_size_t)reg;
5802 +
5803 + return bus_space_read_8(io->iot, io->ioh, ior);
5804 +}
5805 +#endif
5806 +
5807 +void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
5808 +{
5809 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
5810 + bus_size_t ior = (bus_size_t)reg;
5811 +
5812 + bus_space_write_4(io->iot, io->ioh, ior, value);
5813 +}
5814 +
5815 +#if 0
5816 +void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
5817 +{
5818 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
5819 + bus_size_t ior = (bus_size_t)reg;
5820 +
5821 + bus_space_write_8(io->iot, io->ioh, ior, value);
5822 +}
5823 +#endif
5824 +
5825 +void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
5826 + uint32_t set_mask)
5827 +{
5828 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
5829 + bus_size_t ior = (bus_size_t)reg;
5830 +
5831 + bus_space_write_4(io->iot, io->ioh, ior,
5832 + (bus_space_read_4(io->iot, io->ioh, ior) &
5833 + ~clear_mask) | set_mask);
5834 +}
5835 +
5836 +#if 0
5837 +void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
5838 + uint64_t set_mask)
5839 +{
5840 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
5841 + bus_size_t ior = (bus_size_t)reg;
5842 +
5843 + bus_space_write_8(io->iot, io->ioh, ior,
5844 + (bus_space_read_8(io->iot, io->ioh, ior) &
5845 + ~clear_mask) | set_mask);
5846 +}
5847 +#endif
5848 +
5849 +
5850 +/* Locking */
5851 +
5852 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
5853 +{
5854 + struct mtx *sl = DWC_ALLOC(sizeof(*sl));
5855 +
5856 + if (!sl) {
5857 + DWC_ERROR("Cannot allocate memory for spinlock");
5858 + return NULL;
5859 + }
5860 +
5861 + mtx_init(sl, "dw3spn", NULL, MTX_SPIN);
5862 + return (dwc_spinlock_t *)sl;
5863 +}
5864 +
5865 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
5866 +{
5867 + struct mtx *sl = (struct mtx *)lock;
5868 +
5869 + mtx_destroy(sl);
5870 + DWC_FREE(sl);
5871 +}
5872 +
5873 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
5874 +{
5875 + mtx_lock_spin((struct mtx *)lock); // ???
5876 +}
5877 +
5878 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
5879 +{
5880 + mtx_unlock_spin((struct mtx *)lock); // ???
5881 +}
5882 +
5883 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
5884 +{
5885 + mtx_lock_spin((struct mtx *)lock);
5886 +}
5887 +
5888 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
5889 +{
5890 + mtx_unlock_spin((struct mtx *)lock);
5891 +}
5892 +
5893 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
5894 +{
5895 + struct mtx *m;
5896 + dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mtx));
5897 +
5898 + if (!mutex) {
5899 + DWC_ERROR("Cannot allocate memory for mutex");
5900 + return NULL;
5901 + }
5902 +
5903 + m = (struct mtx *)mutex;
5904 + mtx_init(m, "dw3mtx", NULL, MTX_DEF);
5905 + return mutex;
5906 +}
5907 +
5908 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
5909 +#else
5910 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
5911 +{
5912 + mtx_destroy((struct mtx *)mutex);
5913 + DWC_FREE(mutex);
5914 +}
5915 +#endif
5916 +
5917 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
5918 +{
5919 + struct mtx *m = (struct mtx *)mutex;
5920 +
5921 + mtx_lock(m);
5922 +}
5923 +
5924 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
5925 +{
5926 + struct mtx *m = (struct mtx *)mutex;
5927 +
5928 + return mtx_trylock(m);
5929 +}
5930 +
5931 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
5932 +{
5933 + struct mtx *m = (struct mtx *)mutex;
5934 +
5935 + mtx_unlock(m);
5936 +}
5937 +
5938 +
5939 +/* Timing */
5940 +
5941 +void DWC_UDELAY(uint32_t usecs)
5942 +{
5943 + DELAY(usecs);
5944 +}
5945 +
5946 +void DWC_MDELAY(uint32_t msecs)
5947 +{
5948 + do {
5949 + DELAY(1000);
5950 + } while (--msecs);
5951 +}
5952 +
5953 +void DWC_MSLEEP(uint32_t msecs)
5954 +{
5955 + struct timeval tv;
5956 +
5957 + tv.tv_sec = msecs / 1000;
5958 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
5959 + pause("dw3slp", tvtohz(&tv));
5960 +}
5961 +
5962 +uint32_t DWC_TIME(void)
5963 +{
5964 + struct timeval tv;
5965 +
5966 + microuptime(&tv); // or getmicrouptime? (less precise, but faster)
5967 + return tv.tv_sec * 1000 + tv.tv_usec / 1000;
5968 +}
5969 +
5970 +
5971 +/* Timers */
5972 +
5973 +struct dwc_timer {
5974 + struct callout t;
5975 + char *name;
5976 + dwc_spinlock_t *lock;
5977 + dwc_timer_callback_t cb;
5978 + void *data;
5979 +};
5980 +
5981 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
5982 +{
5983 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
5984 +
5985 + if (!t) {
5986 + DWC_ERROR("Cannot allocate memory for timer");
5987 + return NULL;
5988 + }
5989 +
5990 + callout_init(&t->t, 1);
5991 +
5992 + t->name = DWC_STRDUP(name);
5993 + if (!t->name) {
5994 + DWC_ERROR("Cannot allocate memory for timer->name");
5995 + goto no_name;
5996 + }
5997 +
5998 + t->lock = DWC_SPINLOCK_ALLOC();
5999 + if (!t->lock) {
6000 + DWC_ERROR("Cannot allocate memory for lock");
6001 + goto no_lock;
6002 + }
6003 +
6004 + t->cb = cb;
6005 + t->data = data;
6006 +
6007 + return t;
6008 +
6009 + no_lock:
6010 + DWC_FREE(t->name);
6011 + no_name:
6012 + DWC_FREE(t);
6013 +
6014 + return NULL;
6015 +}
6016 +
6017 +void DWC_TIMER_FREE(dwc_timer_t *timer)
6018 +{
6019 + callout_stop(&timer->t);
6020 + DWC_SPINLOCK_FREE(timer->lock);
6021 + DWC_FREE(timer->name);
6022 + DWC_FREE(timer);
6023 +}
6024 +
6025 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
6026 +{
6027 + struct timeval tv;
6028 +
6029 + tv.tv_sec = time / 1000;
6030 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
6031 + callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
6032 +}
6033 +
6034 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
6035 +{
6036 + callout_stop(&timer->t);
6037 +}
6038 +
6039 +
6040 +/* Wait Queues */
6041 +
6042 +struct dwc_waitq {
6043 + struct mtx lock;
6044 + int abort;
6045 +};
6046 +
6047 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
6048 +{
6049 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
6050 +
6051 + if (!wq) {
6052 + DWC_ERROR("Cannot allocate memory for waitqueue");
6053 + return NULL;
6054 + }
6055 +
6056 + mtx_init(&wq->lock, "dw3wtq", NULL, MTX_DEF);
6057 + wq->abort = 0;
6058 +
6059 + return wq;
6060 +}
6061 +
6062 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
6063 +{
6064 + mtx_destroy(&wq->lock);
6065 + DWC_FREE(wq);
6066 +}
6067 +
6068 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
6069 +{
6070 +// intrmask_t ipl;
6071 + int result = 0;
6072 +
6073 + mtx_lock(&wq->lock);
6074 +// ipl = splbio();
6075 +
6076 + /* Skip the sleep if already aborted or triggered */
6077 + if (!wq->abort && !cond(data)) {
6078 +// splx(ipl);
6079 + result = msleep(wq, &wq->lock, PCATCH, "dw3wat", 0); // infinite timeout
6080 +// ipl = splbio();
6081 + }
6082 +
6083 + if (result == ERESTART) { // signaled - restart
6084 + result = -DWC_E_RESTART;
6085 +
6086 + } else if (result == EINTR) { // signaled - interrupt
6087 + result = -DWC_E_ABORT;
6088 +
6089 + } else if (wq->abort) {
6090 + result = -DWC_E_ABORT;
6091 +
6092 + } else {
6093 + result = 0;
6094 + }
6095 +
6096 + wq->abort = 0;
6097 +// splx(ipl);
6098 + mtx_unlock(&wq->lock);
6099 + return result;
6100 +}
6101 +
6102 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
6103 + void *data, int32_t msecs)
6104 +{
6105 + struct timeval tv, tv1, tv2;
6106 +// intrmask_t ipl;
6107 + int result = 0;
6108 +
6109 + tv.tv_sec = msecs / 1000;
6110 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
6111 +
6112 + mtx_lock(&wq->lock);
6113 +// ipl = splbio();
6114 +
6115 + /* Skip the sleep if already aborted or triggered */
6116 + if (!wq->abort && !cond(data)) {
6117 +// splx(ipl);
6118 + getmicrouptime(&tv1);
6119 + result = msleep(wq, &wq->lock, PCATCH, "dw3wto", tvtohz(&tv));
6120 + getmicrouptime(&tv2);
6121 +// ipl = splbio();
6122 + }
6123 +
6124 + if (result == 0) { // awoken
6125 + if (wq->abort) {
6126 + result = -DWC_E_ABORT;
6127 + } else {
6128 + tv2.tv_usec -= tv1.tv_usec;
6129 + if (tv2.tv_usec < 0) {
6130 + tv2.tv_usec += 1000000;
6131 + tv2.tv_sec--;
6132 + }
6133 +
6134 + tv2.tv_sec -= tv1.tv_sec;
6135 + result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
6136 + result = msecs - result;
6137 + if (result <= 0)
6138 + result = 1;
6139 + }
6140 + } else if (result == ERESTART) { // signaled - restart
6141 + result = -DWC_E_RESTART;
6142 +
6143 + } else if (result == EINTR) { // signaled - interrupt
6144 + result = -DWC_E_ABORT;
6145 +
6146 + } else { // timed out
6147 + result = -DWC_E_TIMEOUT;
6148 + }
6149 +
6150 + wq->abort = 0;
6151 +// splx(ipl);
6152 + mtx_unlock(&wq->lock);
6153 + return result;
6154 +}
6155 +
6156 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
6157 +{
6158 + wakeup(wq);
6159 +}
6160 +
6161 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
6162 +{
6163 +// intrmask_t ipl;
6164 +
6165 + mtx_lock(&wq->lock);
6166 +// ipl = splbio();
6167 + wq->abort = 1;
6168 + wakeup(wq);
6169 +// splx(ipl);
6170 + mtx_unlock(&wq->lock);
6171 +}
6172 +
6173 +
6174 +/* Threading */
6175 +
6176 +struct dwc_thread {
6177 + struct proc *proc;
6178 + int abort;
6179 +};
6180 +
6181 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
6182 +{
6183 + int retval;
6184 + dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
6185 +
6186 + if (!thread) {
6187 + return NULL;
6188 + }
6189 +
6190 + thread->abort = 0;
6191 + retval = kthread_create((void (*)(void *))func, data, &thread->proc,
6192 + RFPROC | RFNOWAIT, 0, "%s", name);
6193 + if (retval) {
6194 + DWC_FREE(thread);
6195 + return NULL;
6196 + }
6197 +
6198 + return thread;
6199 +}
6200 +
6201 +int DWC_THREAD_STOP(dwc_thread_t *thread)
6202 +{
6203 + int retval;
6204 +
6205 + thread->abort = 1;
6206 + retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
6207 +
6208 + if (retval == 0) {
6209 + /* DWC_THREAD_EXIT() will free the thread struct */
6210 + return 0;
6211 + }
6212 +
6213 + /* NOTE: We leak the thread struct if thread doesn't die */
6214 +
6215 + if (retval == EWOULDBLOCK) {
6216 + return -DWC_E_TIMEOUT;
6217 + }
6218 +
6219 + return -DWC_E_UNKNOWN;
6220 +}
6221 +
6222 +dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
6223 +{
6224 + return thread->abort;
6225 +}
6226 +
6227 +void DWC_THREAD_EXIT(dwc_thread_t *thread)
6228 +{
6229 + wakeup(&thread->abort);
6230 + DWC_FREE(thread);
6231 + kthread_exit(0);
6232 +}
6233 +
6234 +
6235 +/* tasklets
6236 + - Runs in interrupt context (cannot sleep)
6237 + - Each tasklet runs on a single CPU [ How can we ensure this on FreeBSD? Does it matter? ]
6238 + - Different tasklets can be running simultaneously on different CPUs [ shouldn't matter ]
6239 + */
6240 +struct dwc_tasklet {
6241 + struct task t;
6242 + dwc_tasklet_callback_t cb;
6243 + void *data;
6244 +};
6245 +
6246 +static void tasklet_callback(void *data, int pending) // what to do with pending ???
6247 +{
6248 + dwc_tasklet_t *task = (dwc_tasklet_t *)data;
6249 +
6250 + task->cb(task->data);
6251 +}
6252 +
6253 +dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
6254 +{
6255 + dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
6256 +
6257 + if (task) {
6258 + task->cb = cb;
6259 + task->data = data;
6260 + TASK_INIT(&task->t, 0, tasklet_callback, task);
6261 + } else {
6262 + DWC_ERROR("Cannot allocate memory for tasklet");
6263 + }
6264 +
6265 + return task;
6266 +}
6267 +
6268 +void DWC_TASK_FREE(dwc_tasklet_t *task)
6269 +{
6270 + taskqueue_drain(taskqueue_fast, &task->t); // ???
6271 + DWC_FREE(task);
6272 +}
6273 +
6274 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
6275 +{
6276 + /* Uses predefined system queue */
6277 + taskqueue_enqueue_fast(taskqueue_fast, &task->t);
6278 +}
6279 +
6280 +
6281 +/* workqueues
6282 + - Runs in process context (can sleep)
6283 + */
6284 +typedef struct work_container {
6285 + dwc_work_callback_t cb;
6286 + void *data;
6287 + dwc_workq_t *wq;
6288 + char *name;
6289 + int hz;
6290 +
6291 +#ifdef DEBUG
6292 + DWC_CIRCLEQ_ENTRY(work_container) entry;
6293 +#endif
6294 + struct task task;
6295 +} work_container_t;
6296 +
6297 +#ifdef DEBUG
6298 +DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
6299 +#endif
6300 +
6301 +struct dwc_workq {
6302 + struct taskqueue *taskq;
6303 + dwc_spinlock_t *lock;
6304 + dwc_waitq_t *waitq;
6305 + int pending;
6306 +
6307 +#ifdef DEBUG
6308 + struct work_container_queue entries;
6309 +#endif
6310 +};
6311 +
6312 +static void do_work(void *data, int pending) // what to do with pending ???
6313 +{
6314 + work_container_t *container = (work_container_t *)data;
6315 + dwc_workq_t *wq = container->wq;
6316 + dwc_irqflags_t flags;
6317 +
6318 + if (container->hz) {
6319 + pause("dw3wrk", container->hz);
6320 + }
6321 +
6322 + container->cb(container->data);
6323 + DWC_DEBUG("Work done: %s, container=%p", container->name, container);
6324 +
6325 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6326 +
6327 +#ifdef DEBUG
6328 + DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
6329 +#endif
6330 + if (container->name)
6331 + DWC_FREE(container->name);
6332 + DWC_FREE(container);
6333 + wq->pending--;
6334 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6335 + DWC_WAITQ_TRIGGER(wq->waitq);
6336 +}
6337 +
6338 +static int work_done(void *data)
6339 +{
6340 + dwc_workq_t *workq = (dwc_workq_t *)data;
6341 +
6342 + return workq->pending == 0;
6343 +}
6344 +
6345 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
6346 +{
6347 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
6348 +}
6349 +
6350 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
6351 +{
6352 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
6353 +
6354 + if (!wq) {
6355 + DWC_ERROR("Cannot allocate memory for workqueue");
6356 + return NULL;
6357 + }
6358 +
6359 + wq->taskq = taskqueue_create(name, M_NOWAIT, taskqueue_thread_enqueue, &wq->taskq);
6360 + if (!wq->taskq) {
6361 + DWC_ERROR("Cannot allocate memory for taskqueue");
6362 + goto no_taskq;
6363 + }
6364 +
6365 + wq->pending = 0;
6366 +
6367 + wq->lock = DWC_SPINLOCK_ALLOC();
6368 + if (!wq->lock) {
6369 + DWC_ERROR("Cannot allocate memory for spinlock");
6370 + goto no_lock;
6371 + }
6372 +
6373 + wq->waitq = DWC_WAITQ_ALLOC();
6374 + if (!wq->waitq) {
6375 + DWC_ERROR("Cannot allocate memory for waitqueue");
6376 + goto no_waitq;
6377 + }
6378 +
6379 + taskqueue_start_threads(&wq->taskq, 1, PWAIT, "%s taskq", "dw3tsk");
6380 +
6381 +#ifdef DEBUG
6382 + DWC_CIRCLEQ_INIT(&wq->entries);
6383 +#endif
6384 + return wq;
6385 +
6386 + no_waitq:
6387 + DWC_SPINLOCK_FREE(wq->lock);
6388 + no_lock:
6389 + taskqueue_free(wq->taskq);
6390 + no_taskq:
6391 + DWC_FREE(wq);
6392 +
6393 + return NULL;
6394 +}
6395 +
6396 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
6397 +{
6398 +#ifdef DEBUG
6399 + dwc_irqflags_t flags;
6400 +
6401 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6402 +
6403 + if (wq->pending != 0) {
6404 + struct work_container *container;
6405 +
6406 + DWC_ERROR("Destroying work queue with pending work");
6407 +
6408 + DWC_CIRCLEQ_FOREACH(container, &wq->entries, entry) {
6409 + DWC_ERROR("Work %s still pending", container->name);
6410 + }
6411 + }
6412 +
6413 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6414 +#endif
6415 + DWC_WAITQ_FREE(wq->waitq);
6416 + DWC_SPINLOCK_FREE(wq->lock);
6417 + taskqueue_free(wq->taskq);
6418 + DWC_FREE(wq);
6419 +}
6420 +
6421 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
6422 + char *format, ...)
6423 +{
6424 + dwc_irqflags_t flags;
6425 + work_container_t *container;
6426 + static char name[128];
6427 + va_list args;
6428 +
6429 + va_start(args, format);
6430 + DWC_VSNPRINTF(name, 128, format, args);
6431 + va_end(args);
6432 +
6433 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6434 + wq->pending++;
6435 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6436 + DWC_WAITQ_TRIGGER(wq->waitq);
6437 +
6438 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
6439 + if (!container) {
6440 + DWC_ERROR("Cannot allocate memory for container");
6441 + return;
6442 + }
6443 +
6444 + container->name = DWC_STRDUP(name);
6445 + if (!container->name) {
6446 + DWC_ERROR("Cannot allocate memory for container->name");
6447 + DWC_FREE(container);
6448 + return;
6449 + }
6450 +
6451 + container->cb = cb;
6452 + container->data = data;
6453 + container->wq = wq;
6454 + container->hz = 0;
6455 +
6456 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
6457 +
6458 + TASK_INIT(&container->task, 0, do_work, container);
6459 +
6460 +#ifdef DEBUG
6461 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
6462 +#endif
6463 + taskqueue_enqueue_fast(wq->taskq, &container->task);
6464 +}
6465 +
6466 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
6467 + void *data, uint32_t time, char *format, ...)
6468 +{
6469 + dwc_irqflags_t flags;
6470 + work_container_t *container;
6471 + static char name[128];
6472 + struct timeval tv;
6473 + va_list args;
6474 +
6475 + va_start(args, format);
6476 + DWC_VSNPRINTF(name, 128, format, args);
6477 + va_end(args);
6478 +
6479 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6480 + wq->pending++;
6481 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6482 + DWC_WAITQ_TRIGGER(wq->waitq);
6483 +
6484 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
6485 + if (!container) {
6486 + DWC_ERROR("Cannot allocate memory for container");
6487 + return;
6488 + }
6489 +
6490 + container->name = DWC_STRDUP(name);
6491 + if (!container->name) {
6492 + DWC_ERROR("Cannot allocate memory for container->name");
6493 + DWC_FREE(container);
6494 + return;
6495 + }
6496 +
6497 + container->cb = cb;
6498 + container->data = data;
6499 + container->wq = wq;
6500 +
6501 + tv.tv_sec = time / 1000;
6502 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
6503 + container->hz = tvtohz(&tv);
6504 +
6505 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
6506 +
6507 + TASK_INIT(&container->task, 0, do_work, container);
6508 +
6509 +#ifdef DEBUG
6510 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
6511 +#endif
6512 + taskqueue_enqueue_fast(wq->taskq, &container->task);
6513 +}
6514 +
6515 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
6516 +{
6517 + return wq->pending;
6518 +}
6519 --- /dev/null
6520 +++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
6521 @@ -0,0 +1,1426 @@
6522 +#include <linux/kernel.h>
6523 +#include <linux/init.h>
6524 +#include <linux/module.h>
6525 +#include <linux/kthread.h>
6526 +
6527 +#ifdef DWC_CCLIB
6528 +# include "dwc_cc.h"
6529 +#endif
6530 +
6531 +#ifdef DWC_CRYPTOLIB
6532 +# include "dwc_modpow.h"
6533 +# include "dwc_dh.h"
6534 +# include "dwc_crypto.h"
6535 +#endif
6536 +
6537 +#ifdef DWC_NOTIFYLIB
6538 +# include "dwc_notifier.h"
6539 +#endif
6540 +
6541 +/* OS-Level Implementations */
6542 +
6543 +/* This is the Linux kernel implementation of the DWC platform library. */
6544 +#include <linux/moduleparam.h>
6545 +#include <linux/ctype.h>
6546 +#include <linux/crypto.h>
6547 +#include <linux/delay.h>
6548 +#include <linux/device.h>
6549 +#include <linux/dma-mapping.h>
6550 +#include <linux/cdev.h>
6551 +#include <linux/errno.h>
6552 +#include <linux/interrupt.h>
6553 +#include <linux/jiffies.h>
6554 +#include <linux/list.h>
6555 +#include <linux/pci.h>
6556 +#include <linux/random.h>
6557 +#include <linux/scatterlist.h>
6558 +#include <linux/slab.h>
6559 +#include <linux/stat.h>
6560 +#include <linux/string.h>
6561 +#include <linux/timer.h>
6562 +#include <linux/usb.h>
6563 +
6564 +#include <linux/version.h>
6565 +
6566 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
6567 +# include <linux/usb/gadget.h>
6568 +#else
6569 +# include <linux/usb_gadget.h>
6570 +#endif
6571 +
6572 +#include <asm/io.h>
6573 +#include <asm/page.h>
6574 +#include <asm/uaccess.h>
6575 +#include <asm/unaligned.h>
6576 +
6577 +#include "dwc_os.h"
6578 +#include "dwc_list.h"
6579 +
6580 +
6581 +/* MISC */
6582 +
6583 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
6584 +{
6585 + return memset(dest, byte, size);
6586 +}
6587 +
6588 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
6589 +{
6590 + return memcpy(dest, src, size);
6591 +}
6592 +
6593 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
6594 +{
6595 + return memmove(dest, src, size);
6596 +}
6597 +
6598 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
6599 +{
6600 + return memcmp(m1, m2, size);
6601 +}
6602 +
6603 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
6604 +{
6605 + return strncmp(s1, s2, size);
6606 +}
6607 +
6608 +int DWC_STRCMP(void *s1, void *s2)
6609 +{
6610 + return strcmp(s1, s2);
6611 +}
6612 +
6613 +int DWC_STRLEN(char const *str)
6614 +{
6615 + return strlen(str);
6616 +}
6617 +
6618 +char *DWC_STRCPY(char *to, char const *from)
6619 +{
6620 + return strcpy(to, from);
6621 +}
6622 +
6623 +char *DWC_STRDUP(char const *str)
6624 +{
6625 + int len = DWC_STRLEN(str) + 1;
6626 + char *new = DWC_ALLOC_ATOMIC(len);
6627 +
6628 + if (!new) {
6629 + return NULL;
6630 + }
6631 +
6632 + DWC_MEMCPY(new, str, len);
6633 + return new;
6634 +}
6635 +
6636 +int DWC_ATOI(const char *str, int32_t *value)
6637 +{
6638 + char *end = NULL;
6639 +
6640 + *value = simple_strtol(str, &end, 0);
6641 + if (*end == '\0') {
6642 + return 0;
6643 + }
6644 +
6645 + return -1;
6646 +}
6647 +
6648 +int DWC_ATOUI(const char *str, uint32_t *value)
6649 +{
6650 + char *end = NULL;
6651 +
6652 + *value = simple_strtoul(str, &end, 0);
6653 + if (*end == '\0') {
6654 + return 0;
6655 + }
6656 +
6657 + return -1;
6658 +}
6659 +
6660 +
6661 +#ifdef DWC_UTFLIB
6662 +/* From usbstring.c */
6663 +
6664 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
6665 +{
6666 + int count = 0;
6667 + u8 c;
6668 + u16 uchar;
6669 +
6670 + /* this insists on correct encodings, though not minimal ones.
6671 + * BUT it currently rejects legit 4-byte UTF-8 code points,
6672 + * which need surrogate pairs. (Unicode 3.1 can use them.)
6673 + */
6674 + while (len != 0 && (c = (u8) *s++) != 0) {
6675 + if (unlikely(c & 0x80)) {
6676 + // 2-byte sequence:
6677 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
6678 + if ((c & 0xe0) == 0xc0) {
6679 + uchar = (c & 0x1f) << 6;
6680 +
6681 + c = (u8) *s++;
6682 + if ((c & 0xc0) != 0xc0)
6683 + goto fail;
6684 + c &= 0x3f;
6685 + uchar |= c;
6686 +
6687 + // 3-byte sequence (most CJKV characters):
6688 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
6689 + } else if ((c & 0xf0) == 0xe0) {
6690 + uchar = (c & 0x0f) << 12;
6691 +
6692 + c = (u8) *s++;
6693 + if ((c & 0xc0) != 0xc0)
6694 + goto fail;
6695 + c &= 0x3f;
6696 + uchar |= c << 6;
6697 +
6698 + c = (u8) *s++;
6699 + if ((c & 0xc0) != 0xc0)
6700 + goto fail;
6701 + c &= 0x3f;
6702 + uchar |= c;
6703 +
6704 + /* no bogus surrogates */
6705 + if (0xd800 <= uchar && uchar <= 0xdfff)
6706 + goto fail;
6707 +
6708 + // 4-byte sequence (surrogate pairs, currently rare):
6709 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
6710 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
6711 + // (uuuuu = wwww + 1)
6712 + // FIXME accept the surrogate code points (only)
6713 + } else
6714 + goto fail;
6715 + } else
6716 + uchar = c;
6717 + put_unaligned (cpu_to_le16 (uchar), cp++);
6718 + count++;
6719 + len--;
6720 + }
6721 + return count;
6722 +fail:
6723 + return -1;
6724 +}
6725 +#endif /* DWC_UTFLIB */
6726 +
6727 +
6728 +/* dwc_debug.h */
6729 +
6730 +dwc_bool_t DWC_IN_IRQ(void)
6731 +{
6732 + return in_irq();
6733 +}
6734 +
6735 +dwc_bool_t DWC_IN_BH(void)
6736 +{
6737 + return in_softirq();
6738 +}
6739 +
6740 +void DWC_VPRINTF(char *format, va_list args)
6741 +{
6742 + vprintk(format, args);
6743 +}
6744 +
6745 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
6746 +{
6747 + return vsnprintf(str, size, format, args);
6748 +}
6749 +
6750 +void DWC_PRINTF(char *format, ...)
6751 +{
6752 + va_list args;
6753 +
6754 + va_start(args, format);
6755 + DWC_VPRINTF(format, args);
6756 + va_end(args);
6757 +}
6758 +
6759 +int DWC_SPRINTF(char *buffer, char *format, ...)
6760 +{
6761 + int retval;
6762 + va_list args;
6763 +
6764 + va_start(args, format);
6765 + retval = vsprintf(buffer, format, args);
6766 + va_end(args);
6767 + return retval;
6768 +}
6769 +
6770 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
6771 +{
6772 + int retval;
6773 + va_list args;
6774 +
6775 + va_start(args, format);
6776 + retval = vsnprintf(buffer, size, format, args);
6777 + va_end(args);
6778 + return retval;
6779 +}
6780 +
6781 +void __DWC_WARN(char *format, ...)
6782 +{
6783 + va_list args;
6784 +
6785 + va_start(args, format);
6786 + DWC_PRINTF(KERN_WARNING);
6787 + DWC_VPRINTF(format, args);
6788 + va_end(args);
6789 +}
6790 +
6791 +void __DWC_ERROR(char *format, ...)
6792 +{
6793 + va_list args;
6794 +
6795 + va_start(args, format);
6796 + DWC_PRINTF(KERN_ERR);
6797 + DWC_VPRINTF(format, args);
6798 + va_end(args);
6799 +}
6800 +
6801 +void DWC_EXCEPTION(char *format, ...)
6802 +{
6803 + va_list args;
6804 +
6805 + va_start(args, format);
6806 + DWC_PRINTF(KERN_ERR);
6807 + DWC_VPRINTF(format, args);
6808 + va_end(args);
6809 + BUG_ON(1);
6810 +}
6811 +
6812 +#ifdef DEBUG
6813 +void __DWC_DEBUG(char *format, ...)
6814 +{
6815 + va_list args;
6816 +
6817 + va_start(args, format);
6818 + DWC_PRINTF(KERN_DEBUG);
6819 + DWC_VPRINTF(format, args);
6820 + va_end(args);
6821 +}
6822 +#endif
6823 +
6824 +
6825 +/* dwc_mem.h */
6826 +
6827 +#if 0
6828 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
6829 + uint32_t align,
6830 + uint32_t alloc)
6831 +{
6832 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
6833 + size, align, alloc);
6834 + return (dwc_pool_t *)pool;
6835 +}
6836 +
6837 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
6838 +{
6839 + dma_pool_destroy((struct dma_pool *)pool);
6840 +}
6841 +
6842 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
6843 +{
6844 + return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
6845 +}
6846 +
6847 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
6848 +{
6849 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
6850 + memset(..);
6851 +}
6852 +
6853 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
6854 +{
6855 + dma_pool_free(pool, vaddr, daddr);
6856 +}
6857 +#endif
6858 +
6859 +void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
6860 +{
6861 +#ifdef xxCOSIM /* Only works for 32-bit cosim */
6862 + void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL);
6863 +#else
6864 + void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL | GFP_DMA32);
6865 +#endif
6866 + if (!buf) {
6867 + return NULL;
6868 + }
6869 +
6870 + memset(buf, 0, (size_t)size);
6871 + return buf;
6872 +}
6873 +
6874 +void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
6875 +{
6876 + void *buf = dma_alloc_coherent(NULL, (size_t)size, dma_addr, GFP_ATOMIC);
6877 + if (!buf) {
6878 + return NULL;
6879 + }
6880 + memset(buf, 0, (size_t)size);
6881 + return buf;
6882 +}
6883 +
6884 +void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
6885 +{
6886 + dma_free_coherent(dma_ctx, size, virt_addr, dma_addr);
6887 +}
6888 +
6889 +void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
6890 +{
6891 + return kzalloc(size, GFP_KERNEL);
6892 +}
6893 +
6894 +void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
6895 +{
6896 + return kzalloc(size, GFP_ATOMIC);
6897 +}
6898 +
6899 +void __DWC_FREE(void *mem_ctx, void *addr)
6900 +{
6901 + kfree(addr);
6902 +}
6903 +
6904 +
6905 +#ifdef DWC_CRYPTOLIB
6906 +/* dwc_crypto.h */
6907 +
6908 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
6909 +{
6910 + get_random_bytes(buffer, length);
6911 +}
6912 +
6913 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
6914 +{
6915 + struct crypto_blkcipher *tfm;
6916 + struct blkcipher_desc desc;
6917 + struct scatterlist sgd;
6918 + struct scatterlist sgs;
6919 +
6920 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
6921 + if (tfm == NULL) {
6922 + printk("failed to load transform for aes CBC\n");
6923 + return -1;
6924 + }
6925 +
6926 + crypto_blkcipher_setkey(tfm, key, keylen);
6927 + crypto_blkcipher_set_iv(tfm, iv, 16);
6928 +
6929 + sg_init_one(&sgd, out, messagelen);
6930 + sg_init_one(&sgs, message, messagelen);
6931 +
6932 + desc.tfm = tfm;
6933 + desc.flags = 0;
6934 +
6935 + if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
6936 + crypto_free_blkcipher(tfm);
6937 + DWC_ERROR("AES CBC encryption failed");
6938 + return -1;
6939 + }
6940 +
6941 + crypto_free_blkcipher(tfm);
6942 + return 0;
6943 +}
6944 +
6945 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
6946 +{
6947 + struct crypto_hash *tfm;
6948 + struct hash_desc desc;
6949 + struct scatterlist sg;
6950 +
6951 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
6952 + if (IS_ERR(tfm)) {
6953 + DWC_ERROR("Failed to load transform for sha256: %ld\n", PTR_ERR(tfm));
6954 + return 0;
6955 + }
6956 + desc.tfm = tfm;
6957 + desc.flags = 0;
6958 +
6959 + sg_init_one(&sg, message, len);
6960 + crypto_hash_digest(&desc, &sg, len, out);
6961 + crypto_free_hash(tfm);
6962 +
6963 + return 1;
6964 +}
6965 +
6966 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
6967 + uint8_t *key, uint32_t keylen, uint8_t *out)
6968 +{
6969 + struct crypto_hash *tfm;
6970 + struct hash_desc desc;
6971 + struct scatterlist sg;
6972 +
6973 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
6974 + if (IS_ERR(tfm)) {
6975 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld\n", PTR_ERR(tfm));
6976 + return 0;
6977 + }
6978 + desc.tfm = tfm;
6979 + desc.flags = 0;
6980 +
6981 + sg_init_one(&sg, message, messagelen);
6982 + crypto_hash_setkey(tfm, key, keylen);
6983 + crypto_hash_digest(&desc, &sg, messagelen, out);
6984 + crypto_free_hash(tfm);
6985 +
6986 + return 1;
6987 +}
6988 +#endif /* DWC_CRYPTOLIB */
6989 +
6990 +
6991 +/* Byte Ordering Conversions */
6992 +
6993 +uint32_t DWC_CPU_TO_LE32(uint32_t *p)
6994 +{
6995 +#ifdef __LITTLE_ENDIAN
6996 + return *p;
6997 +#else
6998 + uint8_t *u_p = (uint8_t *)p;
6999 +
7000 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7001 +#endif
7002 +}
7003 +
7004 +uint32_t DWC_CPU_TO_BE32(uint32_t *p)
7005 +{
7006 +#ifdef __BIG_ENDIAN
7007 + return *p;
7008 +#else
7009 + uint8_t *u_p = (uint8_t *)p;
7010 +
7011 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7012 +#endif
7013 +}
7014 +
7015 +uint32_t DWC_LE32_TO_CPU(uint32_t *p)
7016 +{
7017 +#ifdef __LITTLE_ENDIAN
7018 + return *p;
7019 +#else
7020 + uint8_t *u_p = (uint8_t *)p;
7021 +
7022 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7023 +#endif
7024 +}
7025 +
7026 +uint32_t DWC_BE32_TO_CPU(uint32_t *p)
7027 +{
7028 +#ifdef __BIG_ENDIAN
7029 + return *p;
7030 +#else
7031 + uint8_t *u_p = (uint8_t *)p;
7032 +
7033 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7034 +#endif
7035 +}
7036 +
7037 +uint16_t DWC_CPU_TO_LE16(uint16_t *p)
7038 +{
7039 +#ifdef __LITTLE_ENDIAN
7040 + return *p;
7041 +#else
7042 + uint8_t *u_p = (uint8_t *)p;
7043 + return (u_p[1] | (u_p[0] << 8));
7044 +#endif
7045 +}
7046 +
7047 +uint16_t DWC_CPU_TO_BE16(uint16_t *p)
7048 +{
7049 +#ifdef __BIG_ENDIAN
7050 + return *p;
7051 +#else
7052 + uint8_t *u_p = (uint8_t *)p;
7053 + return (u_p[1] | (u_p[0] << 8));
7054 +#endif
7055 +}
7056 +
7057 +uint16_t DWC_LE16_TO_CPU(uint16_t *p)
7058 +{
7059 +#ifdef __LITTLE_ENDIAN
7060 + return *p;
7061 +#else
7062 + uint8_t *u_p = (uint8_t *)p;
7063 + return (u_p[1] | (u_p[0] << 8));
7064 +#endif
7065 +}
7066 +
7067 +uint16_t DWC_BE16_TO_CPU(uint16_t *p)
7068 +{
7069 +#ifdef __BIG_ENDIAN
7070 + return *p;
7071 +#else
7072 + uint8_t *u_p = (uint8_t *)p;
7073 + return (u_p[1] | (u_p[0] << 8));
7074 +#endif
7075 +}
7076 +
7077 +
7078 +/* Registers */
7079 +
7080 +uint32_t DWC_READ_REG32(uint32_t volatile *reg)
7081 +{
7082 + return readl(reg);
7083 +}
7084 +
7085 +#if 0
7086 +uint64_t DWC_READ_REG64(uint64_t volatile *reg)
7087 +{
7088 +}
7089 +#endif
7090 +
7091 +void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value)
7092 +{
7093 + writel(value, reg);
7094 +}
7095 +
7096 +#if 0
7097 +void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value)
7098 +{
7099 +}
7100 +#endif
7101 +
7102 +void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask)
7103 +{
7104 + writel((readl(reg) & ~clear_mask) | set_mask, reg);
7105 +}
7106 +
7107 +#if 0
7108 +void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask)
7109 +{
7110 +}
7111 +#endif
7112 +
7113 +
7114 +/* Locking */
7115 +
7116 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
7117 +{
7118 + spinlock_t *sl = (spinlock_t *)1;
7119 +
7120 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7121 + sl = DWC_ALLOC(sizeof(*sl));
7122 + if (!sl) {
7123 + DWC_ERROR("Cannot allocate memory for spinlock\n");
7124 + return NULL;
7125 + }
7126 +
7127 + spin_lock_init(sl);
7128 +#endif
7129 + return (dwc_spinlock_t *)sl;
7130 +}
7131 +
7132 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
7133 +{
7134 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7135 + DWC_FREE(lock);
7136 +#endif
7137 +}
7138 +
7139 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
7140 +{
7141 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7142 + spin_lock((spinlock_t *)lock);
7143 +#endif
7144 +}
7145 +
7146 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
7147 +{
7148 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7149 + spin_unlock((spinlock_t *)lock);
7150 +#endif
7151 +}
7152 +
7153 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
7154 +{
7155 + dwc_irqflags_t f;
7156 +
7157 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7158 + spin_lock_irqsave((spinlock_t *)lock, f);
7159 +#else
7160 + local_irq_save(f);
7161 +#endif
7162 + *flags = f;
7163 +}
7164 +
7165 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
7166 +{
7167 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7168 + spin_unlock_irqrestore((spinlock_t *)lock, flags);
7169 +#else
7170 + local_irq_restore(flags);
7171 +#endif
7172 +}
7173 +
7174 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
7175 +{
7176 + struct mutex *m;
7177 + dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex));
7178 +
7179 + if (!mutex) {
7180 + DWC_ERROR("Cannot allocate memory for mutex\n");
7181 + return NULL;
7182 + }
7183 +
7184 + m = (struct mutex *)mutex;
7185 + mutex_init(m);
7186 + return mutex;
7187 +}
7188 +
7189 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
7190 +#else
7191 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
7192 +{
7193 + mutex_destroy((struct mutex *)mutex);
7194 + DWC_FREE(mutex);
7195 +}
7196 +#endif
7197 +
7198 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
7199 +{
7200 + struct mutex *m = (struct mutex *)mutex;
7201 + mutex_lock(m);
7202 +}
7203 +
7204 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
7205 +{
7206 + struct mutex *m = (struct mutex *)mutex;
7207 + return mutex_trylock(m);
7208 +}
7209 +
7210 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
7211 +{
7212 + struct mutex *m = (struct mutex *)mutex;
7213 + mutex_unlock(m);
7214 +}
7215 +
7216 +
7217 +/* Timing */
7218 +
7219 +void DWC_UDELAY(uint32_t usecs)
7220 +{
7221 + udelay(usecs);
7222 +}
7223 +
7224 +void DWC_MDELAY(uint32_t msecs)
7225 +{
7226 + mdelay(msecs);
7227 +}
7228 +
7229 +void DWC_MSLEEP(uint32_t msecs)
7230 +{
7231 + msleep(msecs);
7232 +}
7233 +
7234 +uint32_t DWC_TIME(void)
7235 +{
7236 + return jiffies_to_msecs(jiffies);
7237 +}
7238 +
7239 +
7240 +/* Timers */
7241 +
7242 +struct dwc_timer {
7243 + struct timer_list *t;
7244 + char *name;
7245 + dwc_timer_callback_t cb;
7246 + void *data;
7247 + uint8_t scheduled;
7248 + dwc_spinlock_t *lock;
7249 +};
7250 +
7251 +static void timer_callback(unsigned long data)
7252 +{
7253 + dwc_timer_t *timer = (dwc_timer_t *)data;
7254 + dwc_irqflags_t flags;
7255 +
7256 + DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
7257 + timer->scheduled = 0;
7258 + DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
7259 + DWC_DEBUGC("Timer %s callback", timer->name);
7260 + timer->cb(timer->data);
7261 +}
7262 +
7263 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
7264 +{
7265 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
7266 +
7267 + if (!t) {
7268 + DWC_ERROR("Cannot allocate memory for timer");
7269 + return NULL;
7270 + }
7271 +
7272 + t->t = DWC_ALLOC(sizeof(*t->t));
7273 + if (!t->t) {
7274 + DWC_ERROR("Cannot allocate memory for timer->t");
7275 + goto no_timer;
7276 + }
7277 +
7278 + t->name = DWC_STRDUP(name);
7279 + if (!t->name) {
7280 + DWC_ERROR("Cannot allocate memory for timer->name");
7281 + goto no_name;
7282 + }
7283 +
7284 + t->lock = DWC_SPINLOCK_ALLOC();
7285 + if (!t->lock) {
7286 + DWC_ERROR("Cannot allocate memory for lock");
7287 + goto no_lock;
7288 + }
7289 +
7290 + t->scheduled = 0;
7291 + t->t->base = &boot_tvec_bases;
7292 + t->t->expires = jiffies;
7293 + setup_timer(t->t, timer_callback, (unsigned long)t);
7294 +
7295 + t->cb = cb;
7296 + t->data = data;
7297 +
7298 + return t;
7299 +
7300 + no_lock:
7301 + DWC_FREE(t->name);
7302 + no_name:
7303 + DWC_FREE(t->t);
7304 + no_timer:
7305 + DWC_FREE(t);
7306 + return NULL;
7307 +}
7308 +
7309 +void DWC_TIMER_FREE(dwc_timer_t *timer)
7310 +{
7311 + dwc_irqflags_t flags;
7312 +
7313 + DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
7314 +
7315 + if (timer->scheduled) {
7316 + del_timer(timer->t);
7317 + timer->scheduled = 0;
7318 + }
7319 +
7320 + DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
7321 + DWC_SPINLOCK_FREE(timer->lock);
7322 + DWC_FREE(timer->t);
7323 + DWC_FREE(timer->name);
7324 + DWC_FREE(timer);
7325 +}
7326 +
7327 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
7328 +{
7329 + dwc_irqflags_t flags;
7330 +
7331 + DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
7332 +
7333 + if (!timer->scheduled) {
7334 + timer->scheduled = 1;
7335 + DWC_DEBUGC("Scheduling timer %s to expire in +%d msec", timer->name, time);
7336 + timer->t->expires = jiffies + msecs_to_jiffies(time);
7337 + add_timer(timer->t);
7338 + } else {
7339 + DWC_DEBUGC("Modifying timer %s to expire in +%d msec", timer->name, time);
7340 + mod_timer(timer->t, jiffies + msecs_to_jiffies(time));
7341 + }
7342 +
7343 + DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
7344 +}
7345 +
7346 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
7347 +{
7348 + del_timer(timer->t);
7349 +}
7350 +
7351 +
7352 +/* Wait Queues */
7353 +
7354 +struct dwc_waitq {
7355 + wait_queue_head_t queue;
7356 + int abort;
7357 +};
7358 +
7359 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
7360 +{
7361 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
7362 +
7363 + if (!wq) {
7364 + DWC_ERROR("Cannot allocate memory for waitqueue\n");
7365 + return NULL;
7366 + }
7367 +
7368 + init_waitqueue_head(&wq->queue);
7369 + wq->abort = 0;
7370 + return wq;
7371 +}
7372 +
7373 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
7374 +{
7375 + DWC_FREE(wq);
7376 +}
7377 +
7378 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
7379 +{
7380 + int result = wait_event_interruptible(wq->queue,
7381 + cond(data) || wq->abort);
7382 + if (result == -ERESTARTSYS) {
7383 + wq->abort = 0;
7384 + return -DWC_E_RESTART;
7385 + }
7386 +
7387 + if (wq->abort == 1) {
7388 + wq->abort = 0;
7389 + return -DWC_E_ABORT;
7390 + }
7391 +
7392 + wq->abort = 0;
7393 +
7394 + if (result == 0) {
7395 + return 0;
7396 + }
7397 +
7398 + return -DWC_E_UNKNOWN;
7399 +}
7400 +
7401 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
7402 + void *data, int32_t msecs)
7403 +{
7404 + int32_t tmsecs;
7405 + int result = wait_event_interruptible_timeout(wq->queue,
7406 + cond(data) || wq->abort,
7407 + msecs_to_jiffies(msecs));
7408 + if (result == -ERESTARTSYS) {
7409 + wq->abort = 0;
7410 + return -DWC_E_RESTART;
7411 + }
7412 +
7413 + if (wq->abort == 1) {
7414 + wq->abort = 0;
7415 + return -DWC_E_ABORT;
7416 + }
7417 +
7418 + wq->abort = 0;
7419 +
7420 + if (result > 0) {
7421 + tmsecs = jiffies_to_msecs(result);
7422 + if (!tmsecs) {
7423 + return 1;
7424 + }
7425 +
7426 + return tmsecs;
7427 + }
7428 +
7429 + if (result == 0) {
7430 + return -DWC_E_TIMEOUT;
7431 + }
7432 +
7433 + return -DWC_E_UNKNOWN;
7434 +}
7435 +
7436 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
7437 +{
7438 + wq->abort = 0;
7439 + wake_up_interruptible(&wq->queue);
7440 +}
7441 +
7442 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
7443 +{
7444 + wq->abort = 1;
7445 + wake_up_interruptible(&wq->queue);
7446 +}
7447 +
7448 +
7449 +/* Threading */
7450 +
7451 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
7452 +{
7453 + struct task_struct *thread = kthread_run(func, data, name);
7454 +
7455 + if (thread == ERR_PTR(-ENOMEM)) {
7456 + return NULL;
7457 + }
7458 +
7459 + return (dwc_thread_t *)thread;
7460 +}
7461 +
7462 +int DWC_THREAD_STOP(dwc_thread_t *thread)
7463 +{
7464 + return kthread_stop((struct task_struct *)thread);
7465 +}
7466 +
7467 +dwc_bool_t DWC_THREAD_SHOULD_STOP(void)
7468 +{
7469 + return kthread_should_stop();
7470 +}
7471 +
7472 +
7473 +/* tasklets
7474 + - run in interrupt context (cannot sleep)
7475 + - each tasklet runs on a single CPU
7476 + - different tasklets can be running simultaneously on different CPUs
7477 + */
7478 +struct dwc_tasklet {
7479 + struct tasklet_struct t;
7480 + dwc_tasklet_callback_t cb;
7481 + void *data;
7482 +};
7483 +
7484 +static void tasklet_callback(unsigned long data)
7485 +{
7486 + dwc_tasklet_t *t = (dwc_tasklet_t *)data;
7487 + t->cb(t->data);
7488 +}
7489 +
7490 +dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
7491 +{
7492 + dwc_tasklet_t *t = DWC_ALLOC(sizeof(*t));
7493 +
7494 + if (t) {
7495 + t->cb = cb;
7496 + t->data = data;
7497 + tasklet_init(&t->t, tasklet_callback, (unsigned long)t);
7498 + } else {
7499 + DWC_ERROR("Cannot allocate memory for tasklet\n");
7500 + }
7501 +
7502 + return t;
7503 +}
7504 +
7505 +void DWC_TASK_FREE(dwc_tasklet_t *task)
7506 +{
7507 + DWC_FREE(task);
7508 +}
7509 +
7510 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
7511 +{
7512 + tasklet_schedule(&task->t);
7513 +}
7514 +
7515 +void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task)
7516 +{
7517 + tasklet_hi_schedule(&task->t);
7518 +}
7519 +
7520 +
7521 +/* workqueues
7522 + - run in process context (can sleep)
7523 + */
7524 +typedef struct work_container {
7525 + dwc_work_callback_t cb;
7526 + void *data;
7527 + dwc_workq_t *wq;
7528 + char *name;
7529 +
7530 +#ifdef DEBUG
7531 + DWC_CIRCLEQ_ENTRY(work_container) entry;
7532 +#endif
7533 + struct delayed_work work;
7534 +} work_container_t;
7535 +
7536 +#ifdef DEBUG
7537 +DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
7538 +#endif
7539 +
7540 +struct dwc_workq {
7541 + struct workqueue_struct *wq;
7542 + dwc_spinlock_t *lock;
7543 + dwc_waitq_t *waitq;
7544 + int pending;
7545 +
7546 +#ifdef DEBUG
7547 + struct work_container_queue entries;
7548 +#endif
7549 +};
7550 +
7551 +static void do_work(struct work_struct *work)
7552 +{
7553 + dwc_irqflags_t flags;
7554 + struct delayed_work *dw = container_of(work, struct delayed_work, work);
7555 + work_container_t *container = container_of(dw, struct work_container, work);
7556 + dwc_workq_t *wq = container->wq;
7557 +
7558 + container->cb(container->data);
7559 +
7560 +#ifdef DEBUG
7561 + DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
7562 +#endif
7563 + DWC_DEBUGC("Work done: %s, container=%p", container->name, container);
7564 + if (container->name) {
7565 + DWC_FREE(container->name);
7566 + }
7567 + DWC_FREE(container);
7568 +
7569 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
7570 + wq->pending--;
7571 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
7572 + DWC_WAITQ_TRIGGER(wq->waitq);
7573 +}
7574 +
7575 +static int work_done(void *data)
7576 +{
7577 + dwc_workq_t *workq = (dwc_workq_t *)data;
7578 + return workq->pending == 0;
7579 +}
7580 +
7581 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
7582 +{
7583 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
7584 +}
7585 +
7586 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
7587 +{
7588 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
7589 +
7590 + if (!wq) {
7591 + return NULL;
7592 + }
7593 +
7594 + wq->wq = create_singlethread_workqueue(name);
7595 + if (!wq->wq) {
7596 + goto no_wq;
7597 + }
7598 +
7599 + wq->pending = 0;
7600 +
7601 + wq->lock = DWC_SPINLOCK_ALLOC();
7602 + if (!wq->lock) {
7603 + goto no_lock;
7604 + }
7605 +
7606 + wq->waitq = DWC_WAITQ_ALLOC();
7607 + if (!wq->waitq) {
7608 + goto no_waitq;
7609 + }
7610 +
7611 +#ifdef DEBUG
7612 + DWC_CIRCLEQ_INIT(&wq->entries);
7613 +#endif
7614 + return wq;
7615 +
7616 + no_waitq:
7617 + DWC_SPINLOCK_FREE(wq->lock);
7618 + no_lock:
7619 + destroy_workqueue(wq->wq);
7620 + no_wq:
7621 + DWC_FREE(wq);
7622 +
7623 + return NULL;
7624 +}
7625 +
7626 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
7627 +{
7628 +#ifdef DEBUG
7629 + if (wq->pending != 0) {
7630 + struct work_container *wc;
7631 + DWC_ERROR("Destroying work queue with pending work");
7632 + DWC_CIRCLEQ_FOREACH(wc, &wq->entries, entry) {
7633 + DWC_ERROR("Work %s still pending", wc->name);
7634 + }
7635 + }
7636 +#endif
7637 + destroy_workqueue(wq->wq);
7638 + DWC_SPINLOCK_FREE(wq->lock);
7639 + DWC_WAITQ_FREE(wq->waitq);
7640 + DWC_FREE(wq);
7641 +}
7642 +
7643 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
7644 + char *format, ...)
7645 +{
7646 + dwc_irqflags_t flags;
7647 + work_container_t *container;
7648 + static char name[128];
7649 + va_list args;
7650 +
7651 + va_start(args, format);
7652 + DWC_VSNPRINTF(name, 128, format, args);
7653 + va_end(args);
7654 +
7655 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
7656 + wq->pending++;
7657 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
7658 + DWC_WAITQ_TRIGGER(wq->waitq);
7659 +
7660 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
7661 + if (!container) {
7662 + DWC_ERROR("Cannot allocate memory for container\n");
7663 + return;
7664 + }
7665 +
7666 + container->name = DWC_STRDUP(name);
7667 + if (!container->name) {
7668 + DWC_ERROR("Cannot allocate memory for container->name\n");
7669 + DWC_FREE(container);
7670 + return;
7671 + }
7672 +
7673 + container->cb = cb;
7674 + container->data = data;
7675 + container->wq = wq;
7676 + DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
7677 + INIT_WORK(&container->work.work, do_work);
7678 +
7679 +#ifdef DEBUG
7680 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
7681 +#endif
7682 + queue_work(wq->wq, &container->work.work);
7683 +}
7684 +
7685 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
7686 + void *data, uint32_t time, char *format, ...)
7687 +{
7688 + dwc_irqflags_t flags;
7689 + work_container_t *container;
7690 + static char name[128];
7691 + va_list args;
7692 +
7693 + va_start(args, format);
7694 + DWC_VSNPRINTF(name, 128, format, args);
7695 + va_end(args);
7696 +
7697 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
7698 + wq->pending++;
7699 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
7700 + DWC_WAITQ_TRIGGER(wq->waitq);
7701 +
7702 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
7703 + if (!container) {
7704 + DWC_ERROR("Cannot allocate memory for container\n");
7705 + return;
7706 + }
7707 +
7708 + container->name = DWC_STRDUP(name);
7709 + if (!container->name) {
7710 + DWC_ERROR("Cannot allocate memory for container->name\n");
7711 + DWC_FREE(container);
7712 + return;
7713 + }
7714 +
7715 + container->cb = cb;
7716 + container->data = data;
7717 + container->wq = wq;
7718 + DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
7719 + INIT_DELAYED_WORK(&container->work, do_work);
7720 +
7721 +#ifdef DEBUG
7722 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
7723 +#endif
7724 + queue_delayed_work(wq->wq, &container->work, msecs_to_jiffies(time));
7725 +}
7726 +
7727 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
7728 +{
7729 + return wq->pending;
7730 +}
7731 +
7732 +
7733 +#ifdef DWC_LIBMODULE
7734 +
7735 +#ifdef DWC_CCLIB
7736 +/* CC */
7737 +EXPORT_SYMBOL(dwc_cc_if_alloc);
7738 +EXPORT_SYMBOL(dwc_cc_if_free);
7739 +EXPORT_SYMBOL(dwc_cc_clear);
7740 +EXPORT_SYMBOL(dwc_cc_add);
7741 +EXPORT_SYMBOL(dwc_cc_remove);
7742 +EXPORT_SYMBOL(dwc_cc_change);
7743 +EXPORT_SYMBOL(dwc_cc_data_for_save);
7744 +EXPORT_SYMBOL(dwc_cc_restore_from_data);
7745 +EXPORT_SYMBOL(dwc_cc_match_chid);
7746 +EXPORT_SYMBOL(dwc_cc_match_cdid);
7747 +EXPORT_SYMBOL(dwc_cc_ck);
7748 +EXPORT_SYMBOL(dwc_cc_chid);
7749 +EXPORT_SYMBOL(dwc_cc_cdid);
7750 +EXPORT_SYMBOL(dwc_cc_name);
7751 +#endif /* DWC_CCLIB */
7752 +
7753 +#ifdef DWC_CRYPTOLIB
7754 +# ifndef CONFIG_MACH_IPMATE
7755 +/* Modpow */
7756 +EXPORT_SYMBOL(dwc_modpow);
7757 +
7758 +/* DH */
7759 +EXPORT_SYMBOL(dwc_dh_modpow);
7760 +EXPORT_SYMBOL(dwc_dh_derive_keys);
7761 +EXPORT_SYMBOL(dwc_dh_pk);
7762 +# endif /* CONFIG_MACH_IPMATE */
7763 +
7764 +/* Crypto */
7765 +EXPORT_SYMBOL(dwc_wusb_aes_encrypt);
7766 +EXPORT_SYMBOL(dwc_wusb_cmf);
7767 +EXPORT_SYMBOL(dwc_wusb_prf);
7768 +EXPORT_SYMBOL(dwc_wusb_fill_ccm_nonce);
7769 +EXPORT_SYMBOL(dwc_wusb_gen_nonce);
7770 +EXPORT_SYMBOL(dwc_wusb_gen_key);
7771 +EXPORT_SYMBOL(dwc_wusb_gen_mic);
7772 +#endif /* DWC_CRYPTOLIB */
7773 +
7774 +/* Notification */
7775 +#ifdef DWC_NOTIFYLIB
7776 +EXPORT_SYMBOL(dwc_alloc_notification_manager);
7777 +EXPORT_SYMBOL(dwc_free_notification_manager);
7778 +EXPORT_SYMBOL(dwc_register_notifier);
7779 +EXPORT_SYMBOL(dwc_unregister_notifier);
7780 +EXPORT_SYMBOL(dwc_add_observer);
7781 +EXPORT_SYMBOL(dwc_remove_observer);
7782 +EXPORT_SYMBOL(dwc_notify);
7783 +#endif
7784 +
7785 +/* Memory Debugging Routines */
7786 +#ifdef DWC_DEBUG_MEMORY
7787 +EXPORT_SYMBOL(dwc_alloc_debug);
7788 +EXPORT_SYMBOL(dwc_alloc_atomic_debug);
7789 +EXPORT_SYMBOL(dwc_free_debug);
7790 +EXPORT_SYMBOL(dwc_dma_alloc_debug);
7791 +EXPORT_SYMBOL(dwc_dma_free_debug);
7792 +#endif
7793 +
7794 +EXPORT_SYMBOL(DWC_MEMSET);
7795 +EXPORT_SYMBOL(DWC_MEMCPY);
7796 +EXPORT_SYMBOL(DWC_MEMMOVE);
7797 +EXPORT_SYMBOL(DWC_MEMCMP);
7798 +EXPORT_SYMBOL(DWC_STRNCMP);
7799 +EXPORT_SYMBOL(DWC_STRCMP);
7800 +EXPORT_SYMBOL(DWC_STRLEN);
7801 +EXPORT_SYMBOL(DWC_STRCPY);
7802 +EXPORT_SYMBOL(DWC_STRDUP);
7803 +EXPORT_SYMBOL(DWC_ATOI);
7804 +EXPORT_SYMBOL(DWC_ATOUI);
7805 +
7806 +#ifdef DWC_UTFLIB
7807 +EXPORT_SYMBOL(DWC_UTF8_TO_UTF16LE);
7808 +#endif /* DWC_UTFLIB */
7809 +
7810 +EXPORT_SYMBOL(DWC_IN_IRQ);
7811 +EXPORT_SYMBOL(DWC_IN_BH);
7812 +EXPORT_SYMBOL(DWC_VPRINTF);
7813 +EXPORT_SYMBOL(DWC_VSNPRINTF);
7814 +EXPORT_SYMBOL(DWC_PRINTF);
7815 +EXPORT_SYMBOL(DWC_SPRINTF);
7816 +EXPORT_SYMBOL(DWC_SNPRINTF);
7817 +EXPORT_SYMBOL(__DWC_WARN);
7818 +EXPORT_SYMBOL(__DWC_ERROR);
7819 +EXPORT_SYMBOL(DWC_EXCEPTION);
7820 +
7821 +#ifdef DEBUG
7822 +EXPORT_SYMBOL(__DWC_DEBUG);
7823 +#endif
7824 +
7825 +EXPORT_SYMBOL(__DWC_DMA_ALLOC);
7826 +EXPORT_SYMBOL(__DWC_DMA_ALLOC_ATOMIC);
7827 +EXPORT_SYMBOL(__DWC_DMA_FREE);
7828 +EXPORT_SYMBOL(__DWC_ALLOC);
7829 +EXPORT_SYMBOL(__DWC_ALLOC_ATOMIC);
7830 +EXPORT_SYMBOL(__DWC_FREE);
7831 +
7832 +#ifdef DWC_CRYPTOLIB
7833 +EXPORT_SYMBOL(DWC_RANDOM_BYTES);
7834 +EXPORT_SYMBOL(DWC_AES_CBC);
7835 +EXPORT_SYMBOL(DWC_SHA256);
7836 +EXPORT_SYMBOL(DWC_HMAC_SHA256);
7837 +#endif
7838 +
7839 +EXPORT_SYMBOL(DWC_CPU_TO_LE32);
7840 +EXPORT_SYMBOL(DWC_CPU_TO_BE32);
7841 +EXPORT_SYMBOL(DWC_LE32_TO_CPU);
7842 +EXPORT_SYMBOL(DWC_BE32_TO_CPU);
7843 +EXPORT_SYMBOL(DWC_CPU_TO_LE16);
7844 +EXPORT_SYMBOL(DWC_CPU_TO_BE16);
7845 +EXPORT_SYMBOL(DWC_LE16_TO_CPU);
7846 +EXPORT_SYMBOL(DWC_BE16_TO_CPU);
7847 +EXPORT_SYMBOL(DWC_READ_REG32);
7848 +EXPORT_SYMBOL(DWC_WRITE_REG32);
7849 +EXPORT_SYMBOL(DWC_MODIFY_REG32);
7850 +
7851 +#if 0
7852 +EXPORT_SYMBOL(DWC_READ_REG64);
7853 +EXPORT_SYMBOL(DWC_WRITE_REG64);
7854 +EXPORT_SYMBOL(DWC_MODIFY_REG64);
7855 +#endif
7856 +
7857 +EXPORT_SYMBOL(DWC_SPINLOCK_ALLOC);
7858 +EXPORT_SYMBOL(DWC_SPINLOCK_FREE);
7859 +EXPORT_SYMBOL(DWC_SPINLOCK);
7860 +EXPORT_SYMBOL(DWC_SPINUNLOCK);
7861 +EXPORT_SYMBOL(DWC_SPINLOCK_IRQSAVE);
7862 +EXPORT_SYMBOL(DWC_SPINUNLOCK_IRQRESTORE);
7863 +EXPORT_SYMBOL(DWC_MUTEX_ALLOC);
7864 +
7865 +#if (!defined(DWC_LINUX) || !defined(CONFIG_DEBUG_MUTEXES))
7866 +EXPORT_SYMBOL(DWC_MUTEX_FREE);
7867 +#endif
7868 +
7869 +EXPORT_SYMBOL(DWC_MUTEX_LOCK);
7870 +EXPORT_SYMBOL(DWC_MUTEX_TRYLOCK);
7871 +EXPORT_SYMBOL(DWC_MUTEX_UNLOCK);
7872 +EXPORT_SYMBOL(DWC_UDELAY);
7873 +EXPORT_SYMBOL(DWC_MDELAY);
7874 +EXPORT_SYMBOL(DWC_MSLEEP);
7875 +EXPORT_SYMBOL(DWC_TIME);
7876 +EXPORT_SYMBOL(DWC_TIMER_ALLOC);
7877 +EXPORT_SYMBOL(DWC_TIMER_FREE);
7878 +EXPORT_SYMBOL(DWC_TIMER_SCHEDULE);
7879 +EXPORT_SYMBOL(DWC_TIMER_CANCEL);
7880 +EXPORT_SYMBOL(DWC_WAITQ_ALLOC);
7881 +EXPORT_SYMBOL(DWC_WAITQ_FREE);
7882 +EXPORT_SYMBOL(DWC_WAITQ_WAIT);
7883 +EXPORT_SYMBOL(DWC_WAITQ_WAIT_TIMEOUT);
7884 +EXPORT_SYMBOL(DWC_WAITQ_TRIGGER);
7885 +EXPORT_SYMBOL(DWC_WAITQ_ABORT);
7886 +EXPORT_SYMBOL(DWC_THREAD_RUN);
7887 +EXPORT_SYMBOL(DWC_THREAD_STOP);
7888 +EXPORT_SYMBOL(DWC_THREAD_SHOULD_STOP);
7889 +EXPORT_SYMBOL(DWC_TASK_ALLOC);
7890 +EXPORT_SYMBOL(DWC_TASK_FREE);
7891 +EXPORT_SYMBOL(DWC_TASK_SCHEDULE);
7892 +EXPORT_SYMBOL(DWC_WORKQ_WAIT_WORK_DONE);
7893 +EXPORT_SYMBOL(DWC_WORKQ_ALLOC);
7894 +EXPORT_SYMBOL(DWC_WORKQ_FREE);
7895 +EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE);
7896 +EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE_DELAYED);
7897 +EXPORT_SYMBOL(DWC_WORKQ_PENDING);
7898 +
7899 +static int dwc_common_port_init_module(void)
7900 +{
7901 + int result = 0;
7902 +
7903 + printk(KERN_DEBUG "Module dwc_common_port init\n" );
7904 +
7905 +#ifdef DWC_DEBUG_MEMORY
7906 + result = dwc_memory_debug_start(NULL);
7907 + if (result) {
7908 + printk(KERN_ERR
7909 + "dwc_memory_debug_start() failed with error %d\n",
7910 + result);
7911 + return result;
7912 + }
7913 +#endif
7914 +
7915 +#ifdef DWC_NOTIFYLIB
7916 + result = dwc_alloc_notification_manager(NULL, NULL);
7917 + if (result) {
7918 + printk(KERN_ERR
7919 + "dwc_alloc_notification_manager() failed with error %d\n",
7920 + result);
7921 + return result;
7922 + }
7923 +#endif
7924 + return result;
7925 +}
7926 +
7927 +static void dwc_common_port_exit_module(void)
7928 +{
7929 + printk(KERN_DEBUG "Module dwc_common_port exit\n" );
7930 +
7931 +#ifdef DWC_NOTIFYLIB
7932 + dwc_free_notification_manager();
7933 +#endif
7934 +
7935 +#ifdef DWC_DEBUG_MEMORY
7936 + dwc_memory_debug_stop();
7937 +#endif
7938 +}
7939 +
7940 +module_init(dwc_common_port_init_module);
7941 +module_exit(dwc_common_port_exit_module);
7942 +
7943 +MODULE_DESCRIPTION("DWC Common Library - Portable version");
7944 +MODULE_AUTHOR("Synopsys Inc.");
7945 +MODULE_LICENSE ("GPL");
7946 +
7947 +#endif /* DWC_LIBMODULE */
7948 --- /dev/null
7949 +++ b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
7950 @@ -0,0 +1,1275 @@
7951 +#include "dwc_os.h"
7952 +#include "dwc_list.h"
7953 +
7954 +#ifdef DWC_CCLIB
7955 +# include "dwc_cc.h"
7956 +#endif
7957 +
7958 +#ifdef DWC_CRYPTOLIB
7959 +# include "dwc_modpow.h"
7960 +# include "dwc_dh.h"
7961 +# include "dwc_crypto.h"
7962 +#endif
7963 +
7964 +#ifdef DWC_NOTIFYLIB
7965 +# include "dwc_notifier.h"
7966 +#endif
7967 +
7968 +/* OS-Level Implementations */
7969 +
7970 +/* This is the NetBSD 4.0.1 kernel implementation of the DWC platform library. */
7971 +
7972 +
7973 +/* MISC */
7974 +
7975 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
7976 +{
7977 + return memset(dest, byte, size);
7978 +}
7979 +
7980 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
7981 +{
7982 + return memcpy(dest, src, size);
7983 +}
7984 +
7985 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
7986 +{
7987 + bcopy(src, dest, size);
7988 + return dest;
7989 +}
7990 +
7991 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
7992 +{
7993 + return memcmp(m1, m2, size);
7994 +}
7995 +
7996 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
7997 +{
7998 + return strncmp(s1, s2, size);
7999 +}
8000 +
8001 +int DWC_STRCMP(void *s1, void *s2)
8002 +{
8003 + return strcmp(s1, s2);
8004 +}
8005 +
8006 +int DWC_STRLEN(char const *str)
8007 +{
8008 + return strlen(str);
8009 +}
8010 +
8011 +char *DWC_STRCPY(char *to, char const *from)
8012 +{
8013 + return strcpy(to, from);
8014 +}
8015 +
8016 +char *DWC_STRDUP(char const *str)
8017 +{
8018 + int len = DWC_STRLEN(str) + 1;
8019 + char *new = DWC_ALLOC_ATOMIC(len);
8020 +
8021 + if (!new) {
8022 + return NULL;
8023 + }
8024 +
8025 + DWC_MEMCPY(new, str, len);
8026 + return new;
8027 +}
8028 +
8029 +int DWC_ATOI(char *str, int32_t *value)
8030 +{
8031 + char *end = NULL;
8032 +
8033 + /* NetBSD doesn't have 'strtol' in the kernel, but 'strtoul'
8034 + * should be equivalent on 2's complement machines
8035 + */
8036 + *value = strtoul(str, &end, 0);
8037 + if (*end == '\0') {
8038 + return 0;
8039 + }
8040 +
8041 + return -1;
8042 +}
8043 +
8044 +int DWC_ATOUI(char *str, uint32_t *value)
8045 +{
8046 + char *end = NULL;
8047 +
8048 + *value = strtoul(str, &end, 0);
8049 + if (*end == '\0') {
8050 + return 0;
8051 + }
8052 +
8053 + return -1;
8054 +}
8055 +
8056 +
8057 +#ifdef DWC_UTFLIB
8058 +/* From usbstring.c */
8059 +
8060 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
8061 +{
8062 + int count = 0;
8063 + u8 c;
8064 + u16 uchar;
8065 +
8066 + /* this insists on correct encodings, though not minimal ones.
8067 + * BUT it currently rejects legit 4-byte UTF-8 code points,
8068 + * which need surrogate pairs. (Unicode 3.1 can use them.)
8069 + */
8070 + while (len != 0 && (c = (u8) *s++) != 0) {
8071 + if (unlikely(c & 0x80)) {
8072 + // 2-byte sequence:
8073 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
8074 + if ((c & 0xe0) == 0xc0) {
8075 + uchar = (c & 0x1f) << 6;
8076 +
8077 + c = (u8) *s++;
8078 + if ((c & 0xc0) != 0xc0)
8079 + goto fail;
8080 + c &= 0x3f;
8081 + uchar |= c;
8082 +
8083 + // 3-byte sequence (most CJKV characters):
8084 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
8085 + } else if ((c & 0xf0) == 0xe0) {
8086 + uchar = (c & 0x0f) << 12;
8087 +
8088 + c = (u8) *s++;
8089 + if ((c & 0xc0) != 0xc0)
8090 + goto fail;
8091 + c &= 0x3f;
8092 + uchar |= c << 6;
8093 +
8094 + c = (u8) *s++;
8095 + if ((c & 0xc0) != 0xc0)
8096 + goto fail;
8097 + c &= 0x3f;
8098 + uchar |= c;
8099 +
8100 + /* no bogus surrogates */
8101 + if (0xd800 <= uchar && uchar <= 0xdfff)
8102 + goto fail;
8103 +
8104 + // 4-byte sequence (surrogate pairs, currently rare):
8105 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
8106 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
8107 + // (uuuuu = wwww + 1)
8108 + // FIXME accept the surrogate code points (only)
8109 + } else
8110 + goto fail;
8111 + } else
8112 + uchar = c;
8113 + put_unaligned (cpu_to_le16 (uchar), cp++);
8114 + count++;
8115 + len--;
8116 + }
8117 + return count;
8118 +fail:
8119 + return -1;
8120 +}
8121 +
8122 +#endif /* DWC_UTFLIB */
8123 +
8124 +
8125 +/* dwc_debug.h */
8126 +
8127 +dwc_bool_t DWC_IN_IRQ(void)
8128 +{
8129 +// return in_irq();
8130 + return 0;
8131 +}
8132 +
8133 +dwc_bool_t DWC_IN_BH(void)
8134 +{
8135 +// return in_softirq();
8136 + return 0;
8137 +}
8138 +
8139 +void DWC_VPRINTF(char *format, va_list args)
8140 +{
8141 + vprintf(format, args);
8142 +}
8143 +
8144 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
8145 +{
8146 + return vsnprintf(str, size, format, args);
8147 +}
8148 +
8149 +void DWC_PRINTF(char *format, ...)
8150 +{
8151 + va_list args;
8152 +
8153 + va_start(args, format);
8154 + DWC_VPRINTF(format, args);
8155 + va_end(args);
8156 +}
8157 +
8158 +int DWC_SPRINTF(char *buffer, char *format, ...)
8159 +{
8160 + int retval;
8161 + va_list args;
8162 +
8163 + va_start(args, format);
8164 + retval = vsprintf(buffer, format, args);
8165 + va_end(args);
8166 + return retval;
8167 +}
8168 +
8169 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
8170 +{
8171 + int retval;
8172 + va_list args;
8173 +
8174 + va_start(args, format);
8175 + retval = vsnprintf(buffer, size, format, args);
8176 + va_end(args);
8177 + return retval;
8178 +}
8179 +
8180 +void __DWC_WARN(char *format, ...)
8181 +{
8182 + va_list args;
8183 +
8184 + va_start(args, format);
8185 + DWC_VPRINTF(format, args);
8186 + va_end(args);
8187 +}
8188 +
8189 +void __DWC_ERROR(char *format, ...)
8190 +{
8191 + va_list args;
8192 +
8193 + va_start(args, format);
8194 + DWC_VPRINTF(format, args);
8195 + va_end(args);
8196 +}
8197 +
8198 +void DWC_EXCEPTION(char *format, ...)
8199 +{
8200 + va_list args;
8201 +
8202 + va_start(args, format);
8203 + DWC_VPRINTF(format, args);
8204 + va_end(args);
8205 +// BUG_ON(1); ???
8206 +}
8207 +
8208 +#ifdef DEBUG
8209 +void __DWC_DEBUG(char *format, ...)
8210 +{
8211 + va_list args;
8212 +
8213 + va_start(args, format);
8214 + DWC_VPRINTF(format, args);
8215 + va_end(args);
8216 +}
8217 +#endif
8218 +
8219 +
8220 +/* dwc_mem.h */
8221 +
8222 +#if 0
8223 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
8224 + uint32_t align,
8225 + uint32_t alloc)
8226 +{
8227 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
8228 + size, align, alloc);
8229 + return (dwc_pool_t *)pool;
8230 +}
8231 +
8232 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
8233 +{
8234 + dma_pool_destroy((struct dma_pool *)pool);
8235 +}
8236 +
8237 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
8238 +{
8239 +// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
8240 + return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
8241 +}
8242 +
8243 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
8244 +{
8245 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
8246 + memset(..);
8247 +}
8248 +
8249 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
8250 +{
8251 + dma_pool_free(pool, vaddr, daddr);
8252 +}
8253 +#endif
8254 +
8255 +void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
8256 +{
8257 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
8258 + int error;
8259 +
8260 + error = bus_dmamem_alloc(dma->dma_tag, size, 1, size, dma->segs,
8261 + sizeof(dma->segs) / sizeof(dma->segs[0]),
8262 + &dma->nsegs, BUS_DMA_NOWAIT);
8263 + if (error) {
8264 + printf("%s: bus_dmamem_alloc(%ju) failed: %d\n", __func__,
8265 + (uintmax_t)size, error);
8266 + goto fail_0;
8267 + }
8268 +
8269 + error = bus_dmamem_map(dma->dma_tag, dma->segs, dma->nsegs, size,
8270 + (caddr_t *)&dma->dma_vaddr,
8271 + BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
8272 + if (error) {
8273 + printf("%s: bus_dmamem_map failed: %d\n", __func__, error);
8274 + goto fail_1;
8275 + }
8276 +
8277 + error = bus_dmamap_create(dma->dma_tag, size, 1, size, 0,
8278 + BUS_DMA_NOWAIT, &dma->dma_map);
8279 + if (error) {
8280 + printf("%s: bus_dmamap_create failed: %d\n", __func__, error);
8281 + goto fail_2;
8282 + }
8283 +
8284 + error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,
8285 + size, NULL, BUS_DMA_NOWAIT);
8286 + if (error) {
8287 + printf("%s: bus_dmamap_load failed: %d\n", __func__, error);
8288 + goto fail_3;
8289 + }
8290 +
8291 + dma->dma_paddr = (bus_addr_t)dma->segs[0].ds_addr;
8292 + *dma_addr = dma->dma_paddr;
8293 + return dma->dma_vaddr;
8294 +
8295 +fail_3:
8296 + bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
8297 +fail_2:
8298 + bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
8299 +fail_1:
8300 + bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
8301 +fail_0:
8302 + dma->dma_map = NULL;
8303 + dma->dma_vaddr = NULL;
8304 + dma->nsegs = 0;
8305 +
8306 + return NULL;
8307 +}
8308 +
8309 +void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
8310 +{
8311 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
8312 +
8313 + if (dma->dma_map != NULL) {
8314 + bus_dmamap_sync(dma->dma_tag, dma->dma_map, 0, size,
8315 + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
8316 + bus_dmamap_unload(dma->dma_tag, dma->dma_map);
8317 + bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
8318 + bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
8319 + bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
8320 + dma->dma_paddr = 0;
8321 + dma->dma_map = NULL;
8322 + dma->dma_vaddr = NULL;
8323 + dma->nsegs = 0;
8324 + }
8325 +}
8326 +
8327 +void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
8328 +{
8329 + return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
8330 +}
8331 +
8332 +void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
8333 +{
8334 + return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
8335 +}
8336 +
8337 +void __DWC_FREE(void *mem_ctx, void *addr)
8338 +{
8339 + free(addr, M_DEVBUF);
8340 +}
8341 +
8342 +
8343 +#ifdef DWC_CRYPTOLIB
8344 +/* dwc_crypto.h */
8345 +
8346 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
8347 +{
8348 + get_random_bytes(buffer, length);
8349 +}
8350 +
8351 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
8352 +{
8353 + struct crypto_blkcipher *tfm;
8354 + struct blkcipher_desc desc;
8355 + struct scatterlist sgd;
8356 + struct scatterlist sgs;
8357 +
8358 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
8359 + if (tfm == NULL) {
8360 + printk("failed to load transform for aes CBC\n");
8361 + return -1;
8362 + }
8363 +
8364 + crypto_blkcipher_setkey(tfm, key, keylen);
8365 + crypto_blkcipher_set_iv(tfm, iv, 16);
8366 +
8367 + sg_init_one(&sgd, out, messagelen);
8368 + sg_init_one(&sgs, message, messagelen);
8369 +
8370 + desc.tfm = tfm;
8371 + desc.flags = 0;
8372 +
8373 + if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
8374 + crypto_free_blkcipher(tfm);
8375 + DWC_ERROR("AES CBC encryption failed");
8376 + return -1;
8377 + }
8378 +
8379 + crypto_free_blkcipher(tfm);
8380 + return 0;
8381 +}
8382 +
8383 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
8384 +{
8385 + struct crypto_hash *tfm;
8386 + struct hash_desc desc;
8387 + struct scatterlist sg;
8388 +
8389 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
8390 + if (IS_ERR(tfm)) {
8391 + DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
8392 + return 0;
8393 + }
8394 + desc.tfm = tfm;
8395 + desc.flags = 0;
8396 +
8397 + sg_init_one(&sg, message, len);
8398 + crypto_hash_digest(&desc, &sg, len, out);
8399 + crypto_free_hash(tfm);
8400 +
8401 + return 1;
8402 +}
8403 +
8404 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
8405 + uint8_t *key, uint32_t keylen, uint8_t *out)
8406 +{
8407 + struct crypto_hash *tfm;
8408 + struct hash_desc desc;
8409 + struct scatterlist sg;
8410 +
8411 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
8412 + if (IS_ERR(tfm)) {
8413 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
8414 + return 0;
8415 + }
8416 + desc.tfm = tfm;
8417 + desc.flags = 0;
8418 +
8419 + sg_init_one(&sg, message, messagelen);
8420 + crypto_hash_setkey(tfm, key, keylen);
8421 + crypto_hash_digest(&desc, &sg, messagelen, out);
8422 + crypto_free_hash(tfm);
8423 +
8424 + return 1;
8425 +}
8426 +
8427 +#endif /* DWC_CRYPTOLIB */
8428 +
8429 +
8430 +/* Byte Ordering Conversions */
8431 +
8432 +uint32_t DWC_CPU_TO_LE32(uint32_t *p)
8433 +{
8434 +#ifdef __LITTLE_ENDIAN
8435 + return *p;
8436 +#else
8437 + uint8_t *u_p = (uint8_t *)p;
8438 +
8439 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8440 +#endif
8441 +}
8442 +
8443 +uint32_t DWC_CPU_TO_BE32(uint32_t *p)
8444 +{
8445 +#ifdef __BIG_ENDIAN
8446 + return *p;
8447 +#else
8448 + uint8_t *u_p = (uint8_t *)p;
8449 +
8450 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8451 +#endif
8452 +}
8453 +
8454 +uint32_t DWC_LE32_TO_CPU(uint32_t *p)
8455 +{
8456 +#ifdef __LITTLE_ENDIAN
8457 + return *p;
8458 +#else
8459 + uint8_t *u_p = (uint8_t *)p;
8460 +
8461 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8462 +#endif
8463 +}
8464 +
8465 +uint32_t DWC_BE32_TO_CPU(uint32_t *p)
8466 +{
8467 +#ifdef __BIG_ENDIAN
8468 + return *p;
8469 +#else
8470 + uint8_t *u_p = (uint8_t *)p;
8471 +
8472 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8473 +#endif
8474 +}
8475 +
8476 +uint16_t DWC_CPU_TO_LE16(uint16_t *p)
8477 +{
8478 +#ifdef __LITTLE_ENDIAN
8479 + return *p;
8480 +#else
8481 + uint8_t *u_p = (uint8_t *)p;
8482 + return (u_p[1] | (u_p[0] << 8));
8483 +#endif
8484 +}
8485 +
8486 +uint16_t DWC_CPU_TO_BE16(uint16_t *p)
8487 +{
8488 +#ifdef __BIG_ENDIAN
8489 + return *p;
8490 +#else
8491 + uint8_t *u_p = (uint8_t *)p;
8492 + return (u_p[1] | (u_p[0] << 8));
8493 +#endif
8494 +}
8495 +
8496 +uint16_t DWC_LE16_TO_CPU(uint16_t *p)
8497 +{
8498 +#ifdef __LITTLE_ENDIAN
8499 + return *p;
8500 +#else
8501 + uint8_t *u_p = (uint8_t *)p;
8502 + return (u_p[1] | (u_p[0] << 8));
8503 +#endif
8504 +}
8505 +
8506 +uint16_t DWC_BE16_TO_CPU(uint16_t *p)
8507 +{
8508 +#ifdef __BIG_ENDIAN
8509 + return *p;
8510 +#else
8511 + uint8_t *u_p = (uint8_t *)p;
8512 + return (u_p[1] | (u_p[0] << 8));
8513 +#endif
8514 +}
8515 +
8516 +
8517 +/* Registers */
8518 +
8519 +uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
8520 +{
8521 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8522 + bus_size_t ior = (bus_size_t)reg;
8523 +
8524 + return bus_space_read_4(io->iot, io->ioh, ior);
8525 +}
8526 +
8527 +#if 0
8528 +uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
8529 +{
8530 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8531 + bus_size_t ior = (bus_size_t)reg;
8532 +
8533 + return bus_space_read_8(io->iot, io->ioh, ior);
8534 +}
8535 +#endif
8536 +
8537 +void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
8538 +{
8539 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8540 + bus_size_t ior = (bus_size_t)reg;
8541 +
8542 + bus_space_write_4(io->iot, io->ioh, ior, value);
8543 +}
8544 +
8545 +#if 0
8546 +void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
8547 +{
8548 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8549 + bus_size_t ior = (bus_size_t)reg;
8550 +
8551 + bus_space_write_8(io->iot, io->ioh, ior, value);
8552 +}
8553 +#endif
8554 +
8555 +void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
8556 + uint32_t set_mask)
8557 +{
8558 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8559 + bus_size_t ior = (bus_size_t)reg;
8560 +
8561 + bus_space_write_4(io->iot, io->ioh, ior,
8562 + (bus_space_read_4(io->iot, io->ioh, ior) &
8563 + ~clear_mask) | set_mask);
8564 +}
8565 +
8566 +#if 0
8567 +void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
8568 + uint64_t set_mask)
8569 +{
8570 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8571 + bus_size_t ior = (bus_size_t)reg;
8572 +
8573 + bus_space_write_8(io->iot, io->ioh, ior,
8574 + (bus_space_read_8(io->iot, io->ioh, ior) &
8575 + ~clear_mask) | set_mask);
8576 +}
8577 +#endif
8578 +
8579 +
8580 +/* Locking */
8581 +
8582 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
8583 +{
8584 + struct simplelock *sl = DWC_ALLOC(sizeof(*sl));
8585 +
8586 + if (!sl) {
8587 + DWC_ERROR("Cannot allocate memory for spinlock");
8588 + return NULL;
8589 + }
8590 +
8591 + simple_lock_init(sl);
8592 + return (dwc_spinlock_t *)sl;
8593 +}
8594 +
8595 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
8596 +{
8597 + struct simplelock *sl = (struct simplelock *)lock;
8598 +
8599 + DWC_FREE(sl);
8600 +}
8601 +
8602 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
8603 +{
8604 + simple_lock((struct simplelock *)lock);
8605 +}
8606 +
8607 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
8608 +{
8609 + simple_unlock((struct simplelock *)lock);
8610 +}
8611 +
8612 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
8613 +{
8614 + simple_lock((struct simplelock *)lock);
8615 + *flags = splbio();
8616 +}
8617 +
8618 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
8619 +{
8620 + splx(flags);
8621 + simple_unlock((struct simplelock *)lock);
8622 +}
8623 +
8624 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
8625 +{
8626 + dwc_mutex_t *mutex = DWC_ALLOC(sizeof(struct lock));
8627 +
8628 + if (!mutex) {
8629 + DWC_ERROR("Cannot allocate memory for mutex");
8630 + return NULL;
8631 + }
8632 +
8633 + lockinit((struct lock *)mutex, 0, "dw3mtx", 0, 0);
8634 + return mutex;
8635 +}
8636 +
8637 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
8638 +#else
8639 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
8640 +{
8641 + DWC_FREE(mutex);
8642 +}
8643 +#endif
8644 +
8645 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
8646 +{
8647 + lockmgr((struct lock *)mutex, LK_EXCLUSIVE, NULL);
8648 +}
8649 +
8650 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
8651 +{
8652 + int status;
8653 +
8654 + status = lockmgr((struct lock *)mutex, LK_EXCLUSIVE | LK_NOWAIT, NULL);
8655 + return status == 0;
8656 +}
8657 +
8658 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
8659 +{
8660 + lockmgr((struct lock *)mutex, LK_RELEASE, NULL);
8661 +}
8662 +
8663 +
8664 +/* Timing */
8665 +
8666 +void DWC_UDELAY(uint32_t usecs)
8667 +{
8668 + DELAY(usecs);
8669 +}
8670 +
8671 +void DWC_MDELAY(uint32_t msecs)
8672 +{
8673 + do {
8674 + DELAY(1000);
8675 + } while (--msecs);
8676 +}
8677 +
8678 +void DWC_MSLEEP(uint32_t msecs)
8679 +{
8680 + struct timeval tv;
8681 +
8682 + tv.tv_sec = msecs / 1000;
8683 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
8684 + tsleep(&tv, 0, "dw3slp", tvtohz(&tv));
8685 +}
8686 +
8687 +uint32_t DWC_TIME(void)
8688 +{
8689 + struct timeval tv;
8690 +
8691 + microuptime(&tv); // or getmicrouptime? (less precise, but faster)
8692 + return tv.tv_sec * 1000 + tv.tv_usec / 1000;
8693 +}
8694 +
8695 +
8696 +/* Timers */
8697 +
8698 +struct dwc_timer {
8699 + struct callout t;
8700 + char *name;
8701 + dwc_spinlock_t *lock;
8702 + dwc_timer_callback_t cb;
8703 + void *data;
8704 +};
8705 +
8706 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
8707 +{
8708 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
8709 +
8710 + if (!t) {
8711 + DWC_ERROR("Cannot allocate memory for timer");
8712 + return NULL;
8713 + }
8714 +
8715 + callout_init(&t->t);
8716 +
8717 + t->name = DWC_STRDUP(name);
8718 + if (!t->name) {
8719 + DWC_ERROR("Cannot allocate memory for timer->name");
8720 + goto no_name;
8721 + }
8722 +
8723 + t->lock = DWC_SPINLOCK_ALLOC();
8724 + if (!t->lock) {
8725 + DWC_ERROR("Cannot allocate memory for timer->lock");
8726 + goto no_lock;
8727 + }
8728 +
8729 + t->cb = cb;
8730 + t->data = data;
8731 +
8732 + return t;
8733 +
8734 + no_lock:
8735 + DWC_FREE(t->name);
8736 + no_name:
8737 + DWC_FREE(t);
8738 +
8739 + return NULL;
8740 +}
8741 +
8742 +void DWC_TIMER_FREE(dwc_timer_t *timer)
8743 +{
8744 + callout_stop(&timer->t);
8745 + DWC_SPINLOCK_FREE(timer->lock);
8746 + DWC_FREE(timer->name);
8747 + DWC_FREE(timer);
8748 +}
8749 +
8750 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
8751 +{
8752 + struct timeval tv;
8753 +
8754 + tv.tv_sec = time / 1000;
8755 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
8756 + callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
8757 +}
8758 +
8759 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
8760 +{
8761 + callout_stop(&timer->t);
8762 +}
8763 +
8764 +
8765 +/* Wait Queues */
8766 +
8767 +struct dwc_waitq {
8768 + struct simplelock lock;
8769 + int abort;
8770 +};
8771 +
8772 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
8773 +{
8774 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
8775 +
8776 + if (!wq) {
8777 + DWC_ERROR("Cannot allocate memory for waitqueue");
8778 + return NULL;
8779 + }
8780 +
8781 + simple_lock_init(&wq->lock);
8782 + wq->abort = 0;
8783 +
8784 + return wq;
8785 +}
8786 +
8787 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
8788 +{
8789 + DWC_FREE(wq);
8790 +}
8791 +
8792 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
8793 +{
8794 + int ipl;
8795 + int result = 0;
8796 +
8797 + simple_lock(&wq->lock);
8798 + ipl = splbio();
8799 +
8800 + /* Skip the sleep if already aborted or triggered */
8801 + if (!wq->abort && !cond(data)) {
8802 + splx(ipl);
8803 + result = ltsleep(wq, PCATCH, "dw3wat", 0, &wq->lock); // infinite timeout
8804 + ipl = splbio();
8805 + }
8806 +
8807 + if (result == 0) { // awoken
8808 + if (wq->abort) {
8809 + wq->abort = 0;
8810 + result = -DWC_E_ABORT;
8811 + } else {
8812 + result = 0;
8813 + }
8814 +
8815 + splx(ipl);
8816 + simple_unlock(&wq->lock);
8817 + } else {
8818 + wq->abort = 0;
8819 + splx(ipl);
8820 + simple_unlock(&wq->lock);
8821 +
8822 + if (result == ERESTART) { // signaled - restart
8823 + result = -DWC_E_RESTART;
8824 + } else { // signaled - must be EINTR
8825 + result = -DWC_E_ABORT;
8826 + }
8827 + }
8828 +
8829 + return result;
8830 +}
8831 +
8832 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
8833 + void *data, int32_t msecs)
8834 +{
8835 + struct timeval tv, tv1, tv2;
8836 + int ipl;
8837 + int result = 0;
8838 +
8839 + tv.tv_sec = msecs / 1000;
8840 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
8841 +
8842 + simple_lock(&wq->lock);
8843 + ipl = splbio();
8844 +
8845 + /* Skip the sleep if already aborted or triggered */
8846 + if (!wq->abort && !cond(data)) {
8847 + splx(ipl);
8848 + getmicrouptime(&tv1);
8849 + result = ltsleep(wq, PCATCH, "dw3wto", tvtohz(&tv), &wq->lock);
8850 + getmicrouptime(&tv2);
8851 + ipl = splbio();
8852 + }
8853 +
8854 + if (result == 0) { // awoken
8855 + if (wq->abort) {
8856 + wq->abort = 0;
8857 + splx(ipl);
8858 + simple_unlock(&wq->lock);
8859 + result = -DWC_E_ABORT;
8860 + } else {
8861 + splx(ipl);
8862 + simple_unlock(&wq->lock);
8863 +
8864 + tv2.tv_usec -= tv1.tv_usec;
8865 + if (tv2.tv_usec < 0) {
8866 + tv2.tv_usec += 1000000;
8867 + tv2.tv_sec--;
8868 + }
8869 +
8870 + tv2.tv_sec -= tv1.tv_sec;
8871 + result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
8872 + result = msecs - result;
8873 + if (result <= 0)
8874 + result = 1;
8875 + }
8876 + } else {
8877 + wq->abort = 0;
8878 + splx(ipl);
8879 + simple_unlock(&wq->lock);
8880 +
8881 + if (result == ERESTART) { // signaled - restart
8882 + result = -DWC_E_RESTART;
8883 +
8884 + } else if (result == EINTR) { // signaled - interrupt
8885 + result = -DWC_E_ABORT;
8886 +
8887 + } else { // timed out
8888 + result = -DWC_E_TIMEOUT;
8889 + }
8890 + }
8891 +
8892 + return result;
8893 +}
8894 +
8895 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
8896 +{
8897 + wakeup(wq);
8898 +}
8899 +
8900 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
8901 +{
8902 + int ipl;
8903 +
8904 + simple_lock(&wq->lock);
8905 + ipl = splbio();
8906 + wq->abort = 1;
8907 + wakeup(wq);
8908 + splx(ipl);
8909 + simple_unlock(&wq->lock);
8910 +}
8911 +
8912 +
8913 +/* Threading */
8914 +
8915 +struct dwc_thread {
8916 + struct proc *proc;
8917 + int abort;
8918 +};
8919 +
8920 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
8921 +{
8922 + int retval;
8923 + dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
8924 +
8925 + if (!thread) {
8926 + return NULL;
8927 + }
8928 +
8929 + thread->abort = 0;
8930 + retval = kthread_create1((void (*)(void *))func, data, &thread->proc,
8931 + "%s", name);
8932 + if (retval) {
8933 + DWC_FREE(thread);
8934 + return NULL;
8935 + }
8936 +
8937 + return thread;
8938 +}
8939 +
8940 +int DWC_THREAD_STOP(dwc_thread_t *thread)
8941 +{
8942 + int retval;
8943 +
8944 + thread->abort = 1;
8945 + retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
8946 +
8947 + if (retval == 0) {
8948 + /* DWC_THREAD_EXIT() will free the thread struct */
8949 + return 0;
8950 + }
8951 +
8952 + /* NOTE: We leak the thread struct if thread doesn't die */
8953 +
8954 + if (retval == EWOULDBLOCK) {
8955 + return -DWC_E_TIMEOUT;
8956 + }
8957 +
8958 + return -DWC_E_UNKNOWN;
8959 +}
8960 +
8961 +dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
8962 +{
8963 + return thread->abort;
8964 +}
8965 +
8966 +void DWC_THREAD_EXIT(dwc_thread_t *thread)
8967 +{
8968 + wakeup(&thread->abort);
8969 + DWC_FREE(thread);
8970 + kthread_exit(0);
8971 +}
8972 +
8973 +/* tasklets
8974 + - Runs in interrupt context (cannot sleep)
8975 + - Each tasklet runs on a single CPU
8976 + - Different tasklets can be running simultaneously on different CPUs
8977 + [ On NetBSD there is no corresponding mechanism, drivers don't have bottom-
8978 + halves. So we just call the callback directly from DWC_TASK_SCHEDULE() ]
8979 + */
8980 +struct dwc_tasklet {
8981 + dwc_tasklet_callback_t cb;
8982 + void *data;
8983 +};
8984 +
8985 +static void tasklet_callback(void *data)
8986 +{
8987 + dwc_tasklet_t *task = (dwc_tasklet_t *)data;
8988 +
8989 + task->cb(task->data);
8990 +}
8991 +
8992 +dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
8993 +{
8994 + dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
8995 +
8996 + if (task) {
8997 + task->cb = cb;
8998 + task->data = data;
8999 + } else {
9000 + DWC_ERROR("Cannot allocate memory for tasklet");
9001 + }
9002 +
9003 + return task;
9004 +}
9005 +
9006 +void DWC_TASK_FREE(dwc_tasklet_t *task)
9007 +{
9008 + DWC_FREE(task);
9009 +}
9010 +
9011 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
9012 +{
9013 + tasklet_callback(task);
9014 +}
9015 +
9016 +
9017 +/* workqueues
9018 + - Runs in process context (can sleep)
9019 + */
9020 +typedef struct work_container {
9021 + dwc_work_callback_t cb;
9022 + void *data;
9023 + dwc_workq_t *wq;
9024 + char *name;
9025 + int hz;
9026 + struct work task;
9027 +} work_container_t;
9028 +
9029 +struct dwc_workq {
9030 + struct workqueue *taskq;
9031 + dwc_spinlock_t *lock;
9032 + dwc_waitq_t *waitq;
9033 + int pending;
9034 + struct work_container *container;
9035 +};
9036 +
9037 +static void do_work(struct work *task, void *data)
9038 +{
9039 + dwc_workq_t *wq = (dwc_workq_t *)data;
9040 + work_container_t *container = wq->container;
9041 + dwc_irqflags_t flags;
9042 +
9043 + if (container->hz) {
9044 + tsleep(container, 0, "dw3wrk", container->hz);
9045 + }
9046 +
9047 + container->cb(container->data);
9048 + DWC_DEBUG("Work done: %s, container=%p", container->name, container);
9049 +
9050 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9051 + if (container->name)
9052 + DWC_FREE(container->name);
9053 + DWC_FREE(container);
9054 + wq->pending--;
9055 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9056 + DWC_WAITQ_TRIGGER(wq->waitq);
9057 +}
9058 +
9059 +static int work_done(void *data)
9060 +{
9061 + dwc_workq_t *workq = (dwc_workq_t *)data;
9062 +
9063 + return workq->pending == 0;
9064 +}
9065 +
9066 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
9067 +{
9068 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
9069 +}
9070 +
9071 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
9072 +{
9073 + int result;
9074 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
9075 +
9076 + if (!wq) {
9077 + DWC_ERROR("Cannot allocate memory for workqueue");
9078 + return NULL;
9079 + }
9080 +
9081 + result = workqueue_create(&wq->taskq, name, do_work, wq, 0 /*PWAIT*/,
9082 + IPL_BIO, 0);
9083 + if (result) {
9084 + DWC_ERROR("Cannot create workqueue");
9085 + goto no_taskq;
9086 + }
9087 +
9088 + wq->pending = 0;
9089 +
9090 + wq->lock = DWC_SPINLOCK_ALLOC();
9091 + if (!wq->lock) {
9092 + DWC_ERROR("Cannot allocate memory for spinlock");
9093 + goto no_lock;
9094 + }
9095 +
9096 + wq->waitq = DWC_WAITQ_ALLOC();
9097 + if (!wq->waitq) {
9098 + DWC_ERROR("Cannot allocate memory for waitqueue");
9099 + goto no_waitq;
9100 + }
9101 +
9102 + return wq;
9103 +
9104 + no_waitq:
9105 + DWC_SPINLOCK_FREE(wq->lock);
9106 + no_lock:
9107 + workqueue_destroy(wq->taskq);
9108 + no_taskq:
9109 + DWC_FREE(wq);
9110 +
9111 + return NULL;
9112 +}
9113 +
9114 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
9115 +{
9116 +#ifdef DEBUG
9117 + dwc_irqflags_t flags;
9118 +
9119 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9120 +
9121 + if (wq->pending != 0) {
9122 + struct work_container *container = wq->container;
9123 +
9124 + DWC_ERROR("Destroying work queue with pending work");
9125 +
9126 + if (container && container->name) {
9127 + DWC_ERROR("Work %s still pending", container->name);
9128 + }
9129 + }
9130 +
9131 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9132 +#endif
9133 + DWC_WAITQ_FREE(wq->waitq);
9134 + DWC_SPINLOCK_FREE(wq->lock);
9135 + workqueue_destroy(wq->taskq);
9136 + DWC_FREE(wq);
9137 +}
9138 +
9139 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
9140 + char *format, ...)
9141 +{
9142 + dwc_irqflags_t flags;
9143 + work_container_t *container;
9144 + static char name[128];
9145 + va_list args;
9146 +
9147 + va_start(args, format);
9148 + DWC_VSNPRINTF(name, 128, format, args);
9149 + va_end(args);
9150 +
9151 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9152 + wq->pending++;
9153 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9154 + DWC_WAITQ_TRIGGER(wq->waitq);
9155 +
9156 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
9157 + if (!container) {
9158 + DWC_ERROR("Cannot allocate memory for container");
9159 + return;
9160 + }
9161 +
9162 + container->name = DWC_STRDUP(name);
9163 + if (!container->name) {
9164 + DWC_ERROR("Cannot allocate memory for container->name");
9165 + DWC_FREE(container);
9166 + return;
9167 + }
9168 +
9169 + container->cb = cb;
9170 + container->data = data;
9171 + container->wq = wq;
9172 + container->hz = 0;
9173 + wq->container = container;
9174 +
9175 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
9176 + workqueue_enqueue(wq->taskq, &container->task);
9177 +}
9178 +
9179 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
9180 + void *data, uint32_t time, char *format, ...)
9181 +{
9182 + dwc_irqflags_t flags;
9183 + work_container_t *container;
9184 + static char name[128];
9185 + struct timeval tv;
9186 + va_list args;
9187 +
9188 + va_start(args, format);
9189 + DWC_VSNPRINTF(name, 128, format, args);
9190 + va_end(args);
9191 +
9192 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9193 + wq->pending++;
9194 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9195 + DWC_WAITQ_TRIGGER(wq->waitq);
9196 +
9197 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
9198 + if (!container) {
9199 + DWC_ERROR("Cannot allocate memory for container");
9200 + return;
9201 + }
9202 +
9203 + container->name = DWC_STRDUP(name);
9204 + if (!container->name) {
9205 + DWC_ERROR("Cannot allocate memory for container->name");
9206 + DWC_FREE(container);
9207 + return;
9208 + }
9209 +
9210 + container->cb = cb;
9211 + container->data = data;
9212 + container->wq = wq;
9213 + tv.tv_sec = time / 1000;
9214 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
9215 + container->hz = tvtohz(&tv);
9216 + wq->container = container;
9217 +
9218 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
9219 + workqueue_enqueue(wq->taskq, &container->task);
9220 +}
9221 +
9222 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
9223 +{
9224 + return wq->pending;
9225 +}
9226 --- /dev/null
9227 +++ b/drivers/usb/host/dwc_common_port/dwc_crypto.c
9228 @@ -0,0 +1,308 @@
9229 +/* =========================================================================
9230 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.c $
9231 + * $Revision: #5 $
9232 + * $Date: 2010/09/28 $
9233 + * $Change: 1596182 $
9234 + *
9235 + * Synopsys Portability Library Software and documentation
9236 + * (hereinafter, "Software") is an Unsupported proprietary work of
9237 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
9238 + * between Synopsys and you.
9239 + *
9240 + * The Software IS NOT an item of Licensed Software or Licensed Product
9241 + * under any End User Software License Agreement or Agreement for
9242 + * Licensed Product with Synopsys or any supplement thereto. You are
9243 + * permitted to use and redistribute this Software in source and binary
9244 + * forms, with or without modification, provided that redistributions
9245 + * of source code must retain this notice. You may not view, use,
9246 + * disclose, copy or distribute this file or any information contained
9247 + * herein except pursuant to this license grant from Synopsys. If you
9248 + * do not agree with this notice, including the disclaimer below, then
9249 + * you are not authorized to use the Software.
9250 + *
9251 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
9252 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9253 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
9254 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
9255 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
9256 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
9257 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
9258 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
9259 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9260 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
9261 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9262 + * DAMAGE.
9263 + * ========================================================================= */
9264 +
9265 +/** @file
9266 + * This file contains the WUSB cryptographic routines.
9267 + */
9268 +
9269 +#ifdef DWC_CRYPTOLIB
9270 +
9271 +#include "dwc_crypto.h"
9272 +#include "usb.h"
9273 +
9274 +#ifdef DEBUG
9275 +static inline void dump_bytes(char *name, uint8_t *bytes, int len)
9276 +{
9277 + int i;
9278 + DWC_PRINTF("%s: ", name);
9279 + for (i=0; i<len; i++) {
9280 + DWC_PRINTF("%02x ", bytes[i]);
9281 + }
9282 + DWC_PRINTF("\n");
9283 +}
9284 +#else
9285 +#define dump_bytes(x...)
9286 +#endif
9287 +
9288 +/* Display a block */
9289 +void show_block(const u8 *blk, const char *prefix, const char *suffix, int a)
9290 +{
9291 +#ifdef DWC_DEBUG_CRYPTO
9292 + int i, blksize = 16;
9293 +
9294 + DWC_DEBUG("%s", prefix);
9295 +
9296 + if (suffix == NULL) {
9297 + suffix = "\n";
9298 + blksize = a;
9299 + }
9300 +
9301 + for (i = 0; i < blksize; i++)
9302 + DWC_PRINT("%02x%s", *blk++, ((i & 3) == 3) ? " " : " ");
9303 + DWC_PRINT(suffix);
9304 +#endif
9305 +}
9306 +
9307 +/**
9308 + * Encrypts an array of bytes using the AES encryption engine.
9309 + * If <code>dst</code> == <code>src</code>, then the bytes will be encrypted
9310 + * in-place.
9311 + *
9312 + * @return 0 on success, negative error code on error.
9313 + */
9314 +int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst)
9315 +{
9316 + u8 block_t[16];
9317 + DWC_MEMSET(block_t, 0, 16);
9318 +
9319 + return DWC_AES_CBC(src, 16, key, 16, block_t, dst);
9320 +}
9321 +
9322 +/**
9323 + * The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec.
9324 + * This function takes a data string and returns the encrypted CBC
9325 + * Counter-mode MIC.
9326 + *
9327 + * @param key The 128-bit symmetric key.
9328 + * @param nonce The CCM nonce.
9329 + * @param label The unique 14-byte ASCII text label.
9330 + * @param bytes The byte array to be encrypted.
9331 + * @param len Length of the byte array.
9332 + * @param result Byte array to receive the 8-byte encrypted MIC.
9333 + */
9334 +void dwc_wusb_cmf(u8 *key, u8 *nonce,
9335 + char *label, u8 *bytes, int len, u8 *result)
9336 +{
9337 + u8 block_m[16];
9338 + u8 block_x[16];
9339 + u8 block_t[8];
9340 + int idx, blkNum;
9341 + u16 la = (u16)(len + 14);
9342 +
9343 + /* Set the AES-128 key */
9344 + //dwc_aes_setkey(tfm, key, 16);
9345 +
9346 + /* Fill block B0 from flags = 0x59, N, and l(m) = 0 */
9347 + block_m[0] = 0x59;
9348 + for (idx = 0; idx < 13; idx++)
9349 + block_m[idx + 1] = nonce[idx];
9350 + block_m[14] = 0;
9351 + block_m[15] = 0;
9352 +
9353 + /* Produce the CBC IV */
9354 + dwc_wusb_aes_encrypt(block_m, key, block_x);
9355 + show_block(block_m, "CBC IV in: ", "\n", 0);
9356 + show_block(block_x, "CBC IV out:", "\n", 0);
9357 +
9358 + /* Fill block B1 from l(a) = Blen + 14, and A */
9359 + block_x[0] ^= (u8)(la >> 8);
9360 + block_x[1] ^= (u8)la;
9361 + for (idx = 0; idx < 14; idx++)
9362 + block_x[idx + 2] ^= label[idx];
9363 + show_block(block_x, "After xor: ", "b1\n", 16);
9364 +
9365 + dwc_wusb_aes_encrypt(block_x, key, block_x);
9366 + show_block(block_x, "After AES: ", "b1\n", 16);
9367 +
9368 + idx = 0;
9369 + blkNum = 0;
9370 +
9371 + /* Fill remaining blocks with B */
9372 + while (len-- > 0) {
9373 + block_x[idx] ^= *bytes++;
9374 + if (++idx >= 16) {
9375 + idx = 0;
9376 + show_block(block_x, "After xor: ", "\n", blkNum);
9377 + dwc_wusb_aes_encrypt(block_x, key, block_x);
9378 + show_block(block_x, "After AES: ", "\n", blkNum);
9379 + blkNum++;
9380 + }
9381 + }
9382 +
9383 + /* Handle partial last block */
9384 + if (idx > 0) {
9385 + show_block(block_x, "After xor: ", "\n", blkNum);
9386 + dwc_wusb_aes_encrypt(block_x, key, block_x);
9387 + show_block(block_x, "After AES: ", "\n", blkNum);
9388 + }
9389 +
9390 + /* Save the MIC tag */
9391 + DWC_MEMCPY(block_t, block_x, 8);
9392 + show_block(block_t, "MIC tag : ", NULL, 8);
9393 +
9394 + /* Fill block A0 from flags = 0x01, N, and counter = 0 */
9395 + block_m[0] = 0x01;
9396 + block_m[14] = 0;
9397 + block_m[15] = 0;
9398 +
9399 + /* Encrypt the counter */
9400 + dwc_wusb_aes_encrypt(block_m, key, block_x);
9401 + show_block(block_x, "CTR[MIC] : ", NULL, 8);
9402 +
9403 + /* XOR with MIC tag */
9404 + for (idx = 0; idx < 8; idx++) {
9405 + block_t[idx] ^= block_x[idx];
9406 + }
9407 +
9408 + /* Return result to caller */
9409 + DWC_MEMCPY(result, block_t, 8);
9410 + show_block(result, "CCM-MIC : ", NULL, 8);
9411 +
9412 +}
9413 +
9414 +/**
9415 + * The PRF function described in section 6.5 of the WUSB spec. This function
9416 + * concatenates MIC values returned from dwc_cmf() to create a value of
9417 + * the requested length.
9418 + *
9419 + * @param prf_len Length of the PRF function in bits (64, 128, or 256).
9420 + * @param key, nonce, label, bytes, len Same as for dwc_cmf().
9421 + * @param result Byte array to receive the result.
9422 + */
9423 +void dwc_wusb_prf(int prf_len, u8 *key,
9424 + u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
9425 +{
9426 + int i;
9427 +
9428 + nonce[0] = 0;
9429 + for (i = 0; i < prf_len >> 6; i++, nonce[0]++) {
9430 + dwc_wusb_cmf(key, nonce, label, bytes, len, result);
9431 + result += 8;
9432 + }
9433 +}
9434 +
9435 +/**
9436 + * Fills in CCM Nonce per the WUSB spec.
9437 + *
9438 + * @param[in] haddr Host address.
9439 + * @param[in] daddr Device address.
9440 + * @param[in] tkid Session Key(PTK) identifier.
9441 + * @param[out] nonce Pointer to where the CCM Nonce output is to be written.
9442 + */
9443 +void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
9444 + uint8_t *nonce)
9445 +{
9446 +
9447 + DWC_DEBUG("%s %x %x\n", __func__, daddr, haddr);
9448 +
9449 + DWC_MEMSET(&nonce[0], 0, 16);
9450 +
9451 + DWC_MEMCPY(&nonce[6], tkid, 3);
9452 + nonce[9] = daddr & 0xFF;
9453 + nonce[10] = (daddr >> 8) & 0xFF;
9454 + nonce[11] = haddr & 0xFF;
9455 + nonce[12] = (haddr >> 8) & 0xFF;
9456 +
9457 + dump_bytes("CCM nonce", nonce, 16);
9458 +}
9459 +
9460 +/**
9461 + * Generates a 16-byte cryptographic-grade random number for the Host/Device
9462 + * Nonce.
9463 + */
9464 +void dwc_wusb_gen_nonce(uint16_t addr, uint8_t *nonce)
9465 +{
9466 + uint8_t inonce[16];
9467 + uint32_t temp[4];
9468 +
9469 + /* Fill in the Nonce */
9470 + DWC_MEMSET(&inonce[0], 0, sizeof(inonce));
9471 + inonce[9] = addr & 0xFF;
9472 + inonce[10] = (addr >> 8) & 0xFF;
9473 + inonce[11] = inonce[9];
9474 + inonce[12] = inonce[10];
9475 +
9476 + /* Collect "randomness samples" */
9477 + DWC_RANDOM_BYTES((uint8_t *)temp, 16);
9478 +
9479 + dwc_wusb_prf_128((uint8_t *)temp, nonce,
9480 + "Random Numbers", (uint8_t *)temp, sizeof(temp),
9481 + nonce);
9482 +}
9483 +
9484 +/**
9485 + * Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the
9486 + * WUSB spec.
9487 + *
9488 + * @param[in] ccm_nonce Pointer to CCM Nonce.
9489 + * @param[in] mk Master Key to derive the session from
9490 + * @param[in] hnonce Pointer to Host Nonce.
9491 + * @param[in] dnonce Pointer to Device Nonce.
9492 + * @param[out] kck Pointer to where the KCK output is to be written.
9493 + * @param[out] ptk Pointer to where the PTK output is to be written.
9494 + */
9495 +void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce,
9496 + uint8_t *dnonce, uint8_t *kck, uint8_t *ptk)
9497 +{
9498 + uint8_t idata[32];
9499 + uint8_t odata[32];
9500 +
9501 + dump_bytes("ck", mk, 16);
9502 + dump_bytes("hnonce", hnonce, 16);
9503 + dump_bytes("dnonce", dnonce, 16);
9504 +
9505 + /* The data is the HNonce and DNonce concatenated */
9506 + DWC_MEMCPY(&idata[0], hnonce, 16);
9507 + DWC_MEMCPY(&idata[16], dnonce, 16);
9508 +
9509 + dwc_wusb_prf_256(mk, ccm_nonce, "Pair-wise keys", idata, 32, odata);
9510 +
9511 + /* Low 16 bytes of the result is the KCK, high 16 is the PTK */
9512 + DWC_MEMCPY(kck, &odata[0], 16);
9513 + DWC_MEMCPY(ptk, &odata[16], 16);
9514 +
9515 + dump_bytes("kck", kck, 16);
9516 + dump_bytes("ptk", ptk, 16);
9517 +}
9518 +
9519 +/**
9520 + * Generates the Message Integrity Code over the Handshake data per the
9521 + * WUSB spec.
9522 + *
9523 + * @param ccm_nonce Pointer to CCM Nonce.
9524 + * @param kck Pointer to Key Confirmation Key.
9525 + * @param data Pointer to Handshake data to be checked.
9526 + * @param mic Pointer to where the MIC output is to be written.
9527 + */
9528 +void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t *kck,
9529 + uint8_t *data, uint8_t *mic)
9530 +{
9531 +
9532 + dwc_wusb_prf_64(kck, ccm_nonce, "out-of-bandMIC",
9533 + data, WUSB_HANDSHAKE_LEN_FOR_MIC, mic);
9534 +}
9535 +
9536 +#endif /* DWC_CRYPTOLIB */
9537 --- /dev/null
9538 +++ b/drivers/usb/host/dwc_common_port/dwc_crypto.h
9539 @@ -0,0 +1,111 @@
9540 +/* =========================================================================
9541 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.h $
9542 + * $Revision: #3 $
9543 + * $Date: 2010/09/28 $
9544 + * $Change: 1596182 $
9545 + *
9546 + * Synopsys Portability Library Software and documentation
9547 + * (hereinafter, "Software") is an Unsupported proprietary work of
9548 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
9549 + * between Synopsys and you.
9550 + *
9551 + * The Software IS NOT an item of Licensed Software or Licensed Product
9552 + * under any End User Software License Agreement or Agreement for
9553 + * Licensed Product with Synopsys or any supplement thereto. You are
9554 + * permitted to use and redistribute this Software in source and binary
9555 + * forms, with or without modification, provided that redistributions
9556 + * of source code must retain this notice. You may not view, use,
9557 + * disclose, copy or distribute this file or any information contained
9558 + * herein except pursuant to this license grant from Synopsys. If you
9559 + * do not agree with this notice, including the disclaimer below, then
9560 + * you are not authorized to use the Software.
9561 + *
9562 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
9563 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9564 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
9565 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
9566 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
9567 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
9568 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
9569 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
9570 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9571 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
9572 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9573 + * DAMAGE.
9574 + * ========================================================================= */
9575 +
9576 +#ifndef _DWC_CRYPTO_H_
9577 +#define _DWC_CRYPTO_H_
9578 +
9579 +#ifdef __cplusplus
9580 +extern "C" {
9581 +#endif
9582 +
9583 +/** @file
9584 + *
9585 + * This file contains declarations for the WUSB Cryptographic routines as
9586 + * defined in the WUSB spec. They are only to be used internally by the DWC UWB
9587 + * modules.
9588 + */
9589 +
9590 +#include "dwc_os.h"
9591 +
9592 +int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst);
9593 +
9594 +void dwc_wusb_cmf(u8 *key, u8 *nonce,
9595 + char *label, u8 *bytes, int len, u8 *result);
9596 +void dwc_wusb_prf(int prf_len, u8 *key,
9597 + u8 *nonce, char *label, u8 *bytes, int len, u8 *result);
9598 +
9599 +/**
9600 + * The PRF-64 function described in section 6.5 of the WUSB spec.
9601 + *
9602 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
9603 + */
9604 +static inline void dwc_wusb_prf_64(u8 *key, u8 *nonce,
9605 + char *label, u8 *bytes, int len, u8 *result)
9606 +{
9607 + dwc_wusb_prf(64, key, nonce, label, bytes, len, result);
9608 +}
9609 +
9610 +/**
9611 + * The PRF-128 function described in section 6.5 of the WUSB spec.
9612 + *
9613 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
9614 + */
9615 +static inline void dwc_wusb_prf_128(u8 *key, u8 *nonce,
9616 + char *label, u8 *bytes, int len, u8 *result)
9617 +{
9618 + dwc_wusb_prf(128, key, nonce, label, bytes, len, result);
9619 +}
9620 +
9621 +/**
9622 + * The PRF-256 function described in section 6.5 of the WUSB spec.
9623 + *
9624 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
9625 + */
9626 +static inline void dwc_wusb_prf_256(u8 *key, u8 *nonce,
9627 + char *label, u8 *bytes, int len, u8 *result)
9628 +{
9629 + dwc_wusb_prf(256, key, nonce, label, bytes, len, result);
9630 +}
9631 +
9632 +
9633 +void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
9634 + uint8_t *nonce);
9635 +void dwc_wusb_gen_nonce(uint16_t addr,
9636 + uint8_t *nonce);
9637 +
9638 +void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk,
9639 + uint8_t *hnonce, uint8_t *dnonce,
9640 + uint8_t *kck, uint8_t *ptk);
9641 +
9642 +
9643 +void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t
9644 + *kck, uint8_t *data, uint8_t *mic);
9645 +
9646 +#ifdef __cplusplus
9647 +}
9648 +#endif
9649 +
9650 +#endif /* _DWC_CRYPTO_H_ */
9651 --- /dev/null
9652 +++ b/drivers/usb/host/dwc_common_port/dwc_dh.c
9653 @@ -0,0 +1,291 @@
9654 +/* =========================================================================
9655 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.c $
9656 + * $Revision: #3 $
9657 + * $Date: 2010/09/28 $
9658 + * $Change: 1596182 $
9659 + *
9660 + * Synopsys Portability Library Software and documentation
9661 + * (hereinafter, "Software") is an Unsupported proprietary work of
9662 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
9663 + * between Synopsys and you.
9664 + *
9665 + * The Software IS NOT an item of Licensed Software or Licensed Product
9666 + * under any End User Software License Agreement or Agreement for
9667 + * Licensed Product with Synopsys or any supplement thereto. You are
9668 + * permitted to use and redistribute this Software in source and binary
9669 + * forms, with or without modification, provided that redistributions
9670 + * of source code must retain this notice. You may not view, use,
9671 + * disclose, copy or distribute this file or any information contained
9672 + * herein except pursuant to this license grant from Synopsys. If you
9673 + * do not agree with this notice, including the disclaimer below, then
9674 + * you are not authorized to use the Software.
9675 + *
9676 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
9677 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9678 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
9679 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
9680 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
9681 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
9682 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
9683 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
9684 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9685 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
9686 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9687 + * DAMAGE.
9688 + * ========================================================================= */
9689 +#ifdef DWC_CRYPTOLIB
9690 +
9691 +#ifndef CONFIG_MACH_IPMATE
9692 +
9693 +#include "dwc_dh.h"
9694 +#include "dwc_modpow.h"
9695 +
9696 +#ifdef DEBUG
9697 +/* This function prints out a buffer in the format described in the Association
9698 + * Model specification. */
9699 +static void dh_dump(char *str, void *_num, int len)
9700 +{
9701 + uint8_t *num = _num;
9702 + int i;
9703 + DWC_PRINTF("%s\n", str);
9704 + for (i = 0; i < len; i ++) {
9705 + DWC_PRINTF("%02x", num[i]);
9706 + if (((i + 1) % 2) == 0) DWC_PRINTF(" ");
9707 + if (((i + 1) % 26) == 0) DWC_PRINTF("\n");
9708 + }
9709 +
9710 + DWC_PRINTF("\n");
9711 +}
9712 +#else
9713 +#define dh_dump(_x...) do {; } while(0)
9714 +#endif
9715 +
9716 +/* Constant g value */
9717 +static __u32 dh_g[] = {
9718 + 0x02000000,
9719 +};
9720 +
9721 +/* Constant p value */
9722 +static __u32 dh_p[] = {
9723 + 0xFFFFFFFF, 0xFFFFFFFF, 0xA2DA0FC9, 0x34C26821, 0x8B62C6C4, 0xD11CDC80, 0x084E0229, 0x74CC678A,
9724 + 0xA6BE0B02, 0x229B133B, 0x79084A51, 0xDD04348E, 0xB31995EF, 0x1B433ACD, 0x6D0A2B30, 0x37145FF2,
9725 + 0x6D35E14F, 0x45C2516D, 0x76B585E4, 0xC67E5E62, 0xE9424CF4, 0x6BED37A6, 0xB65CFF0B, 0xEDB706F4,
9726 + 0xFB6B38EE, 0xA59F895A, 0x11249FAE, 0xE61F4B7C, 0x51662849, 0x3D5BE4EC, 0xB87C00C2, 0x05BF63A1,
9727 + 0x3648DA98, 0x9AD3551C, 0xA83F1669, 0x5FCF24FD, 0x235D6583, 0x96ADA3DC, 0x56F3621C, 0xBB528520,
9728 + 0x0729D59E, 0x6D969670, 0x4E350C67, 0x0498BC4A, 0x086C74F1, 0x7C2118CA, 0x465E9032, 0x3BCE362E,
9729 + 0x2C779EE3, 0x03860E18, 0xA283279B, 0x8FA207EC, 0xF05DC5B5, 0xC9524C6F, 0xF6CB2BDE, 0x18175895,
9730 + 0x7C499539, 0xE56A95EA, 0x1826D215, 0x1005FA98, 0x5A8E7215, 0x2DC4AA8A, 0x0D1733AD, 0x337A5004,
9731 + 0xAB2155A8, 0x64BA1CDF, 0x0485FBEC, 0x0AEFDB58, 0x5771EA8A, 0x7D0C065D, 0x850F97B3, 0xC7E4E1A6,
9732 + 0x8CAEF5AB, 0xD73309DB, 0xE0948C1E, 0x9D61254A, 0x26D2E3CE, 0x6BEED21A, 0x06FA2FF1, 0x64088AD9,
9733 + 0x730276D8, 0x646AC83E, 0x182B1F52, 0x0C207B17, 0x5717E1BB, 0x6C5D617A, 0xC0880977, 0xE246D9BA,
9734 + 0xA04FE208, 0x31ABE574, 0xFC5BDB43, 0x8E10FDE0, 0x20D1824B, 0xCAD23AA9, 0xFFFFFFFF, 0xFFFFFFFF,
9735 +};
9736 +
9737 +static void dh_swap_bytes(void *_in, void *_out, uint32_t len)
9738 +{
9739 + uint8_t *in = _in;
9740 + uint8_t *out = _out;
9741 + int i;
9742 + for (i=0; i<len; i++) {
9743 + out[i] = in[len-1-i];
9744 + }
9745 +}
9746 +
9747 +/* Computes the modular exponentiation (num^exp % mod). num, exp, and mod are
9748 + * big endian numbers of size len, in bytes. Each len value must be a multiple
9749 + * of 4. */
9750 +int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
9751 + void *exp, uint32_t exp_len,
9752 + void *mod, uint32_t mod_len,
9753 + void *out)
9754 +{
9755 + /* modpow() takes little endian numbers. AM uses big-endian. This
9756 + * function swaps bytes of numbers before passing onto modpow. */
9757 +
9758 + int retval = 0;
9759 + uint32_t *result;
9760 +
9761 + uint32_t *bignum_num = dwc_alloc(mem_ctx, num_len + 4);
9762 + uint32_t *bignum_exp = dwc_alloc(mem_ctx, exp_len + 4);
9763 + uint32_t *bignum_mod = dwc_alloc(mem_ctx, mod_len + 4);
9764 +
9765 + dh_swap_bytes(num, &bignum_num[1], num_len);
9766 + bignum_num[0] = num_len / 4;
9767 +
9768 + dh_swap_bytes(exp, &bignum_exp[1], exp_len);
9769 + bignum_exp[0] = exp_len / 4;
9770 +
9771 + dh_swap_bytes(mod, &bignum_mod[1], mod_len);
9772 + bignum_mod[0] = mod_len / 4;
9773 +
9774 + result = dwc_modpow(mem_ctx, bignum_num, bignum_exp, bignum_mod);
9775 + if (!result) {
9776 + retval = -1;
9777 + goto dh_modpow_nomem;
9778 + }
9779 +
9780 + dh_swap_bytes(&result[1], out, result[0] * 4);
9781 + dwc_free(mem_ctx, result);
9782 +
9783 + dh_modpow_nomem:
9784 + dwc_free(mem_ctx, bignum_num);
9785 + dwc_free(mem_ctx, bignum_exp);
9786 + dwc_free(mem_ctx, bignum_mod);
9787 + return retval;
9788 +}
9789 +
9790 +
9791 +int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pk, uint8_t *hash)
9792 +{
9793 + int retval;
9794 + uint8_t m3[385];
9795 +
9796 +#ifndef DH_TEST_VECTORS
9797 + DWC_RANDOM_BYTES(exp, 32);
9798 +#endif
9799 +
9800 + /* Compute the pkd */
9801 + if ((retval = dwc_dh_modpow(mem_ctx, dh_g, 4,
9802 + exp, 32,
9803 + dh_p, 384, pk))) {
9804 + return retval;
9805 + }
9806 +
9807 + m3[384] = nd;
9808 + DWC_MEMCPY(&m3[0], pk, 384);
9809 + DWC_SHA256(m3, 385, hash);
9810 +
9811 + dh_dump("PK", pk, 384);
9812 + dh_dump("SHA-256(M3)", hash, 32);
9813 + return 0;
9814 +}
9815 +
9816 +int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
9817 + uint8_t *exp, int is_host,
9818 + char *dd, uint8_t *ck, uint8_t *kdk)
9819 +{
9820 + int retval;
9821 + uint8_t mv[784];
9822 + uint8_t sha_result[32];
9823 + uint8_t dhkey[384];
9824 + uint8_t shared_secret[384];
9825 + char *message;
9826 + uint32_t vd;
9827 +
9828 + uint8_t *pk;
9829 +
9830 + if (is_host) {
9831 + pk = pkd;
9832 + }
9833 + else {
9834 + pk = pkh;
9835 + }
9836 +
9837 + if ((retval = dwc_dh_modpow(mem_ctx, pk, 384,
9838 + exp, 32,
9839 + dh_p, 384, shared_secret))) {
9840 + return retval;
9841 + }
9842 + dh_dump("Shared Secret", shared_secret, 384);
9843 +
9844 + DWC_SHA256(shared_secret, 384, dhkey);
9845 + dh_dump("DHKEY", dhkey, 384);
9846 +
9847 + DWC_MEMCPY(&mv[0], pkd, 384);
9848 + DWC_MEMCPY(&mv[384], pkh, 384);
9849 + DWC_MEMCPY(&mv[768], "displayed digest", 16);
9850 + dh_dump("MV", mv, 784);
9851 +
9852 + DWC_SHA256(mv, 784, sha_result);
9853 + dh_dump("SHA-256(MV)", sha_result, 32);
9854 + dh_dump("First 32-bits of SHA-256(MV)", sha_result, 4);
9855 +
9856 + dh_swap_bytes(sha_result, &vd, 4);
9857 +#ifdef DEBUG
9858 + DWC_PRINTF("Vd (decimal) = %d\n", vd);
9859 +#endif
9860 +
9861 + switch (nd) {
9862 + case 2:
9863 + vd = vd % 100;
9864 + DWC_SPRINTF(dd, "%02d", vd);
9865 + break;
9866 + case 3:
9867 + vd = vd % 1000;
9868 + DWC_SPRINTF(dd, "%03d", vd);
9869 + break;
9870 + case 4:
9871 + vd = vd % 10000;
9872 + DWC_SPRINTF(dd, "%04d", vd);
9873 + break;
9874 + }
9875 +#ifdef DEBUG
9876 + DWC_PRINTF("Display Digits: %s\n", dd);
9877 +#endif
9878 +
9879 + message = "connection key";
9880 + DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
9881 + dh_dump("HMAC(SHA-256, DHKey, connection key)", sha_result, 32);
9882 + DWC_MEMCPY(ck, sha_result, 16);
9883 +
9884 + message = "key derivation key";
9885 + DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
9886 + dh_dump("HMAC(SHA-256, DHKey, key derivation key)", sha_result, 32);
9887 + DWC_MEMCPY(kdk, sha_result, 32);
9888 +
9889 + return 0;
9890 +}
9891 +
9892 +
9893 +#ifdef DH_TEST_VECTORS
9894 +
9895 +static __u8 dh_a[] = {
9896 + 0x44, 0x00, 0x51, 0xd6,
9897 + 0xf0, 0xb5, 0x5e, 0xa9,
9898 + 0x67, 0xab, 0x31, 0xc6,
9899 + 0x8a, 0x8b, 0x5e, 0x37,
9900 + 0xd9, 0x10, 0xda, 0xe0,
9901 + 0xe2, 0xd4, 0x59, 0xa4,
9902 + 0x86, 0x45, 0x9c, 0xaa,
9903 + 0xdf, 0x36, 0x75, 0x16,
9904 +};
9905 +
9906 +static __u8 dh_b[] = {
9907 + 0x5d, 0xae, 0xc7, 0x86,
9908 + 0x79, 0x80, 0xa3, 0x24,
9909 + 0x8c, 0xe3, 0x57, 0x8f,
9910 + 0xc7, 0x5f, 0x1b, 0x0f,
9911 + 0x2d, 0xf8, 0x9d, 0x30,
9912 + 0x6f, 0xa4, 0x52, 0xcd,
9913 + 0xe0, 0x7a, 0x04, 0x8a,
9914 + 0xde, 0xd9, 0x26, 0x56,
9915 +};
9916 +
9917 +void dwc_run_dh_test_vectors(void *mem_ctx)
9918 +{
9919 + uint8_t pkd[384];
9920 + uint8_t pkh[384];
9921 + uint8_t hashd[32];
9922 + uint8_t hashh[32];
9923 + uint8_t ck[16];
9924 + uint8_t kdk[32];
9925 + char dd[5];
9926 +
9927 + DWC_PRINTF("\n\n\nDH_TEST_VECTORS\n\n");
9928 +
9929 + /* compute the PKd and SHA-256(PKd || Nd) */
9930 + DWC_PRINTF("Computing PKd\n");
9931 + dwc_dh_pk(mem_ctx, 2, dh_a, pkd, hashd);
9932 +
9933 + /* compute the PKd and SHA-256(PKh || Nd) */
9934 + DWC_PRINTF("Computing PKh\n");
9935 + dwc_dh_pk(mem_ctx, 2, dh_b, pkh, hashh);
9936 +
9937 + /* compute the dhkey */
9938 + dwc_dh_derive_keys(mem_ctx, 2, pkh, pkd, dh_a, 0, dd, ck, kdk);
9939 +}
9940 +#endif /* DH_TEST_VECTORS */
9941 +
9942 +#endif /* !CONFIG_MACH_IPMATE */
9943 +
9944 +#endif /* DWC_CRYPTOLIB */
9945 --- /dev/null
9946 +++ b/drivers/usb/host/dwc_common_port/dwc_dh.h
9947 @@ -0,0 +1,106 @@
9948 +/* =========================================================================
9949 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.h $
9950 + * $Revision: #4 $
9951 + * $Date: 2010/09/28 $
9952 + * $Change: 1596182 $
9953 + *
9954 + * Synopsys Portability Library Software and documentation
9955 + * (hereinafter, "Software") is an Unsupported proprietary work of
9956 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
9957 + * between Synopsys and you.
9958 + *
9959 + * The Software IS NOT an item of Licensed Software or Licensed Product
9960 + * under any End User Software License Agreement or Agreement for
9961 + * Licensed Product with Synopsys or any supplement thereto. You are
9962 + * permitted to use and redistribute this Software in source and binary
9963 + * forms, with or without modification, provided that redistributions
9964 + * of source code must retain this notice. You may not view, use,
9965 + * disclose, copy or distribute this file or any information contained
9966 + * herein except pursuant to this license grant from Synopsys. If you
9967 + * do not agree with this notice, including the disclaimer below, then
9968 + * you are not authorized to use the Software.
9969 + *
9970 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
9971 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9972 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
9973 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
9974 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
9975 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
9976 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
9977 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
9978 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9979 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
9980 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9981 + * DAMAGE.
9982 + * ========================================================================= */
9983 +#ifndef _DWC_DH_H_
9984 +#define _DWC_DH_H_
9985 +
9986 +#ifdef __cplusplus
9987 +extern "C" {
9988 +#endif
9989 +
9990 +#include "dwc_os.h"
9991 +
9992 +/** @file
9993 + *
9994 + * This file defines the common functions on device and host for performing
9995 + * numeric association as defined in the WUSB spec. They are only to be
9996 + * used internally by the DWC UWB modules. */
9997 +
9998 +extern int dwc_dh_sha256(uint8_t *message, uint32_t len, uint8_t *out);
9999 +extern int dwc_dh_hmac_sha256(uint8_t *message, uint32_t messagelen,
10000 + uint8_t *key, uint32_t keylen,
10001 + uint8_t *out);
10002 +extern int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
10003 + void *exp, uint32_t exp_len,
10004 + void *mod, uint32_t mod_len,
10005 + void *out);
10006 +
10007 +/** Computes PKD or PKH, and SHA-256(PKd || Nd)
10008 + *
10009 + * PK = g^exp mod p.
10010 + *
10011 + * Input:
10012 + * Nd = Number of digits on the device.
10013 + *
10014 + * Output:
10015 + * exp = A 32-byte buffer to be filled with a randomly generated number.
10016 + * used as either A or B.
10017 + * pk = A 384-byte buffer to be filled with the PKH or PKD.
10018 + * hash = A 32-byte buffer to be filled with SHA-256(PK || ND).
10019 + */
10020 +extern int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pkd, uint8_t *hash);
10021 +
10022 +/** Computes the DHKEY, and VD.
10023 + *
10024 + * If called from host, then it will comput DHKEY=PKD^exp % p.
10025 + * If called from device, then it will comput DHKEY=PKH^exp % p.
10026 + *
10027 + * Input:
10028 + * pkd = The PKD value.
10029 + * pkh = The PKH value.
10030 + * exp = The A value (if device) or B value (if host) generated in dwc_wudev_dh_pk.
10031 + * is_host = Set to non zero if a WUSB host is calling this function.
10032 + *
10033 + * Output:
10034 +
10035 + * dd = A pointer to an buffer to be set to the displayed digits string to be shown
10036 + * to the user. This buffer should be at 5 bytes long to hold 4 digits plus a
10037 + * null termination character. This buffer can be used directly for display.
10038 + * ck = A 16-byte buffer to be filled with the CK.
10039 + * kdk = A 32-byte buffer to be filled with the KDK.
10040 + */
10041 +extern int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
10042 + uint8_t *exp, int is_host,
10043 + char *dd, uint8_t *ck, uint8_t *kdk);
10044 +
10045 +#ifdef DH_TEST_VECTORS
10046 +extern void dwc_run_dh_test_vectors(void);
10047 +#endif
10048 +
10049 +#ifdef __cplusplus
10050 +}
10051 +#endif
10052 +
10053 +#endif /* _DWC_DH_H_ */
10054 --- /dev/null
10055 +++ b/drivers/usb/host/dwc_common_port/dwc_list.h
10056 @@ -0,0 +1,594 @@
10057 +/* $OpenBSD: queue.h,v 1.26 2004/05/04 16:59:32 grange Exp $ */
10058 +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
10059 +
10060 +/*
10061 + * Copyright (c) 1991, 1993
10062 + * The Regents of the University of California. All rights reserved.
10063 + *
10064 + * Redistribution and use in source and binary forms, with or without
10065 + * modification, are permitted provided that the following conditions
10066 + * are met:
10067 + * 1. Redistributions of source code must retain the above copyright
10068 + * notice, this list of conditions and the following disclaimer.
10069 + * 2. Redistributions in binary form must reproduce the above copyright
10070 + * notice, this list of conditions and the following disclaimer in the
10071 + * documentation and/or other materials provided with the distribution.
10072 + * 3. Neither the name of the University nor the names of its contributors
10073 + * may be used to endorse or promote products derived from this software
10074 + * without specific prior written permission.
10075 + *
10076 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
10077 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10078 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10079 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
10080 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10081 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10082 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10083 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10084 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10085 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10086 + * SUCH DAMAGE.
10087 + *
10088 + * @(#)queue.h 8.5 (Berkeley) 8/20/94
10089 + */
10090 +
10091 +#ifndef _DWC_LIST_H_
10092 +#define _DWC_LIST_H_
10093 +
10094 +#ifdef __cplusplus
10095 +extern "C" {
10096 +#endif
10097 +
10098 +/** @file
10099 + *
10100 + * This file defines linked list operations. It is derived from BSD with
10101 + * only the MACRO names being prefixed with DWC_. This is because a few of
10102 + * these names conflict with those on Linux. For documentation on use, see the
10103 + * inline comments in the source code. The original license for this source
10104 + * code applies and is preserved in the dwc_list.h source file.
10105 + */
10106 +
10107 +/*
10108 + * This file defines five types of data structures: singly-linked lists,
10109 + * lists, simple queues, tail queues, and circular queues.
10110 + *
10111 + *
10112 + * A singly-linked list is headed by a single forward pointer. The elements
10113 + * are singly linked for minimum space and pointer manipulation overhead at
10114 + * the expense of O(n) removal for arbitrary elements. New elements can be
10115 + * added to the list after an existing element or at the head of the list.
10116 + * Elements being removed from the head of the list should use the explicit
10117 + * macro for this purpose for optimum efficiency. A singly-linked list may
10118 + * only be traversed in the forward direction. Singly-linked lists are ideal
10119 + * for applications with large datasets and few or no removals or for
10120 + * implementing a LIFO queue.
10121 + *
10122 + * A list is headed by a single forward pointer (or an array of forward
10123 + * pointers for a hash table header). The elements are doubly linked
10124 + * so that an arbitrary element can be removed without a need to
10125 + * traverse the list. New elements can be added to the list before
10126 + * or after an existing element or at the head of the list. A list
10127 + * may only be traversed in the forward direction.
10128 + *
10129 + * A simple queue is headed by a pair of pointers, one the head of the
10130 + * list and the other to the tail of the list. The elements are singly
10131 + * linked to save space, so elements can only be removed from the
10132 + * head of the list. New elements can be added to the list before or after
10133 + * an existing element, at the head of the list, or at the end of the
10134 + * list. A simple queue may only be traversed in the forward direction.
10135 + *
10136 + * A tail queue is headed by a pair of pointers, one to the head of the
10137 + * list and the other to the tail of the list. The elements are doubly
10138 + * linked so that an arbitrary element can be removed without a need to
10139 + * traverse the list. New elements can be added to the list before or
10140 + * after an existing element, at the head of the list, or at the end of
10141 + * the list. A tail queue may be traversed in either direction.
10142 + *
10143 + * A circle queue is headed by a pair of pointers, one to the head of the
10144 + * list and the other to the tail of the list. The elements are doubly
10145 + * linked so that an arbitrary element can be removed without a need to
10146 + * traverse the list. New elements can be added to the list before or after
10147 + * an existing element, at the head of the list, or at the end of the list.
10148 + * A circle queue may be traversed in either direction, but has a more
10149 + * complex end of list detection.
10150 + *
10151 + * For details on the use of these macros, see the queue(3) manual page.
10152 + */
10153 +
10154 +/*
10155 + * Double-linked List.
10156 + */
10157 +
10158 +typedef struct dwc_list_link {
10159 + struct dwc_list_link *next;
10160 + struct dwc_list_link *prev;
10161 +} dwc_list_link_t;
10162 +
10163 +#define DWC_LIST_INIT(link) do { \
10164 + (link)->next = (link); \
10165 + (link)->prev = (link); \
10166 +} while (0)
10167 +
10168 +#define DWC_LIST_FIRST(link) ((link)->next)
10169 +#define DWC_LIST_LAST(link) ((link)->prev)
10170 +#define DWC_LIST_END(link) (link)
10171 +#define DWC_LIST_NEXT(link) ((link)->next)
10172 +#define DWC_LIST_PREV(link) ((link)->prev)
10173 +#define DWC_LIST_EMPTY(link) \
10174 + (DWC_LIST_FIRST(link) == DWC_LIST_END(link))
10175 +#define DWC_LIST_ENTRY(link, type, field) \
10176 + (type *)((uint8_t *)(link) - (size_t)(&((type *)0)->field))
10177 +
10178 +#if 0
10179 +#define DWC_LIST_INSERT_HEAD(list, link) do { \
10180 + (link)->next = (list)->next; \
10181 + (link)->prev = (list); \
10182 + (list)->next->prev = (link); \
10183 + (list)->next = (link); \
10184 +} while (0)
10185 +
10186 +#define DWC_LIST_INSERT_TAIL(list, link) do { \
10187 + (link)->next = (list); \
10188 + (link)->prev = (list)->prev; \
10189 + (list)->prev->next = (link); \
10190 + (list)->prev = (link); \
10191 +} while (0)
10192 +#else
10193 +#define DWC_LIST_INSERT_HEAD(list, link) do { \
10194 + dwc_list_link_t *__next__ = (list)->next; \
10195 + __next__->prev = (link); \
10196 + (link)->next = __next__; \
10197 + (link)->prev = (list); \
10198 + (list)->next = (link); \
10199 +} while (0)
10200 +
10201 +#define DWC_LIST_INSERT_TAIL(list, link) do { \
10202 + dwc_list_link_t *__prev__ = (list)->prev; \
10203 + (list)->prev = (link); \
10204 + (link)->next = (list); \
10205 + (link)->prev = __prev__; \
10206 + __prev__->next = (link); \
10207 +} while (0)
10208 +#endif
10209 +
10210 +#if 0
10211 +static inline void __list_add(struct list_head *new,
10212 + struct list_head *prev,
10213 + struct list_head *next)
10214 +{
10215 + next->prev = new;
10216 + new->next = next;
10217 + new->prev = prev;
10218 + prev->next = new;
10219 +}
10220 +
10221 +static inline void list_add(struct list_head *new, struct list_head *head)
10222 +{
10223 + __list_add(new, head, head->next);
10224 +}
10225 +
10226 +static inline void list_add_tail(struct list_head *new, struct list_head *head)
10227 +{
10228 + __list_add(new, head->prev, head);
10229 +}
10230 +
10231 +static inline void __list_del(struct list_head * prev, struct list_head * next)
10232 +{
10233 + next->prev = prev;
10234 + prev->next = next;
10235 +}
10236 +
10237 +static inline void list_del(struct list_head *entry)
10238 +{
10239 + __list_del(entry->prev, entry->next);
10240 + entry->next = LIST_POISON1;
10241 + entry->prev = LIST_POISON2;
10242 +}
10243 +#endif
10244 +
10245 +#define DWC_LIST_REMOVE(link) do { \
10246 + (link)->next->prev = (link)->prev; \
10247 + (link)->prev->next = (link)->next; \
10248 +} while (0)
10249 +
10250 +#define DWC_LIST_REMOVE_INIT(link) do { \
10251 + DWC_LIST_REMOVE(link); \
10252 + DWC_LIST_INIT(link); \
10253 +} while (0)
10254 +
10255 +#define DWC_LIST_MOVE_HEAD(list, link) do { \
10256 + DWC_LIST_REMOVE(link); \
10257 + DWC_LIST_INSERT_HEAD(list, link); \
10258 +} while (0)
10259 +
10260 +#define DWC_LIST_MOVE_TAIL(list, link) do { \
10261 + DWC_LIST_REMOVE(link); \
10262 + DWC_LIST_INSERT_TAIL(list, link); \
10263 +} while (0)
10264 +
10265 +#define DWC_LIST_FOREACH(var, list) \
10266 + for((var) = DWC_LIST_FIRST(list); \
10267 + (var) != DWC_LIST_END(list); \
10268 + (var) = DWC_LIST_NEXT(var))
10269 +
10270 +#define DWC_LIST_FOREACH_SAFE(var, var2, list) \
10271 + for((var) = DWC_LIST_FIRST(list), (var2) = DWC_LIST_NEXT(var); \
10272 + (var) != DWC_LIST_END(list); \
10273 + (var) = (var2), (var2) = DWC_LIST_NEXT(var2))
10274 +
10275 +#define DWC_LIST_FOREACH_REVERSE(var, list) \
10276 + for((var) = DWC_LIST_LAST(list); \
10277 + (var) != DWC_LIST_END(list); \
10278 + (var) = DWC_LIST_PREV(var))
10279 +
10280 +/*
10281 + * Singly-linked List definitions.
10282 + */
10283 +#define DWC_SLIST_HEAD(name, type) \
10284 +struct name { \
10285 + struct type *slh_first; /* first element */ \
10286 +}
10287 +
10288 +#define DWC_SLIST_HEAD_INITIALIZER(head) \
10289 + { NULL }
10290 +
10291 +#define DWC_SLIST_ENTRY(type) \
10292 +struct { \
10293 + struct type *sle_next; /* next element */ \
10294 +}
10295 +
10296 +/*
10297 + * Singly-linked List access methods.
10298 + */
10299 +#define DWC_SLIST_FIRST(head) ((head)->slh_first)
10300 +#define DWC_SLIST_END(head) NULL
10301 +#define DWC_SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
10302 +#define DWC_SLIST_NEXT(elm, field) ((elm)->field.sle_next)
10303 +
10304 +#define DWC_SLIST_FOREACH(var, head, field) \
10305 + for((var) = SLIST_FIRST(head); \
10306 + (var) != SLIST_END(head); \
10307 + (var) = SLIST_NEXT(var, field))
10308 +
10309 +#define DWC_SLIST_FOREACH_PREVPTR(var, varp, head, field) \
10310 + for((varp) = &SLIST_FIRST((head)); \
10311 + ((var) = *(varp)) != SLIST_END(head); \
10312 + (varp) = &SLIST_NEXT((var), field))
10313 +
10314 +/*
10315 + * Singly-linked List functions.
10316 + */
10317 +#define DWC_SLIST_INIT(head) { \
10318 + SLIST_FIRST(head) = SLIST_END(head); \
10319 +}
10320 +
10321 +#define DWC_SLIST_INSERT_AFTER(slistelm, elm, field) do { \
10322 + (elm)->field.sle_next = (slistelm)->field.sle_next; \
10323 + (slistelm)->field.sle_next = (elm); \
10324 +} while (0)
10325 +
10326 +#define DWC_SLIST_INSERT_HEAD(head, elm, field) do { \
10327 + (elm)->field.sle_next = (head)->slh_first; \
10328 + (head)->slh_first = (elm); \
10329 +} while (0)
10330 +
10331 +#define DWC_SLIST_REMOVE_NEXT(head, elm, field) do { \
10332 + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
10333 +} while (0)
10334 +
10335 +#define DWC_SLIST_REMOVE_HEAD(head, field) do { \
10336 + (head)->slh_first = (head)->slh_first->field.sle_next; \
10337 +} while (0)
10338 +
10339 +#define DWC_SLIST_REMOVE(head, elm, type, field) do { \
10340 + if ((head)->slh_first == (elm)) { \
10341 + SLIST_REMOVE_HEAD((head), field); \
10342 + } \
10343 + else { \
10344 + struct type *curelm = (head)->slh_first; \
10345 + while( curelm->field.sle_next != (elm) ) \
10346 + curelm = curelm->field.sle_next; \
10347 + curelm->field.sle_next = \
10348 + curelm->field.sle_next->field.sle_next; \
10349 + } \
10350 +} while (0)
10351 +
10352 +/*
10353 + * Simple queue definitions.
10354 + */
10355 +#define DWC_SIMPLEQ_HEAD(name, type) \
10356 +struct name { \
10357 + struct type *sqh_first; /* first element */ \
10358 + struct type **sqh_last; /* addr of last next element */ \
10359 +}
10360 +
10361 +#define DWC_SIMPLEQ_HEAD_INITIALIZER(head) \
10362 + { NULL, &(head).sqh_first }
10363 +
10364 +#define DWC_SIMPLEQ_ENTRY(type) \
10365 +struct { \
10366 + struct type *sqe_next; /* next element */ \
10367 +}
10368 +
10369 +/*
10370 + * Simple queue access methods.
10371 + */
10372 +#define DWC_SIMPLEQ_FIRST(head) ((head)->sqh_first)
10373 +#define DWC_SIMPLEQ_END(head) NULL
10374 +#define DWC_SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
10375 +#define DWC_SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
10376 +
10377 +#define DWC_SIMPLEQ_FOREACH(var, head, field) \
10378 + for((var) = SIMPLEQ_FIRST(head); \
10379 + (var) != SIMPLEQ_END(head); \
10380 + (var) = SIMPLEQ_NEXT(var, field))
10381 +
10382 +/*
10383 + * Simple queue functions.
10384 + */
10385 +#define DWC_SIMPLEQ_INIT(head) do { \
10386 + (head)->sqh_first = NULL; \
10387 + (head)->sqh_last = &(head)->sqh_first; \
10388 +} while (0)
10389 +
10390 +#define DWC_SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
10391 + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
10392 + (head)->sqh_last = &(elm)->field.sqe_next; \
10393 + (head)->sqh_first = (elm); \
10394 +} while (0)
10395 +
10396 +#define DWC_SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
10397 + (elm)->field.sqe_next = NULL; \
10398 + *(head)->sqh_last = (elm); \
10399 + (head)->sqh_last = &(elm)->field.sqe_next; \
10400 +} while (0)
10401 +
10402 +#define DWC_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
10403 + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
10404 + (head)->sqh_last = &(elm)->field.sqe_next; \
10405 + (listelm)->field.sqe_next = (elm); \
10406 +} while (0)
10407 +
10408 +#define DWC_SIMPLEQ_REMOVE_HEAD(head, field) do { \
10409 + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
10410 + (head)->sqh_last = &(head)->sqh_first; \
10411 +} while (0)
10412 +
10413 +/*
10414 + * Tail queue definitions.
10415 + */
10416 +#define DWC_TAILQ_HEAD(name, type) \
10417 +struct name { \
10418 + struct type *tqh_first; /* first element */ \
10419 + struct type **tqh_last; /* addr of last next element */ \
10420 +}
10421 +
10422 +#define DWC_TAILQ_HEAD_INITIALIZER(head) \
10423 + { NULL, &(head).tqh_first }
10424 +
10425 +#define DWC_TAILQ_ENTRY(type) \
10426 +struct { \
10427 + struct type *tqe_next; /* next element */ \
10428 + struct type **tqe_prev; /* address of previous next element */ \
10429 +}
10430 +
10431 +/*
10432 + * tail queue access methods
10433 + */
10434 +#define DWC_TAILQ_FIRST(head) ((head)->tqh_first)
10435 +#define DWC_TAILQ_END(head) NULL
10436 +#define DWC_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
10437 +#define DWC_TAILQ_LAST(head, headname) \
10438 + (*(((struct headname *)((head)->tqh_last))->tqh_last))
10439 +/* XXX */
10440 +#define DWC_TAILQ_PREV(elm, headname, field) \
10441 + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
10442 +#define DWC_TAILQ_EMPTY(head) \
10443 + (DWC_TAILQ_FIRST(head) == DWC_TAILQ_END(head))
10444 +
10445 +#define DWC_TAILQ_FOREACH(var, head, field) \
10446 + for ((var) = DWC_TAILQ_FIRST(head); \
10447 + (var) != DWC_TAILQ_END(head); \
10448 + (var) = DWC_TAILQ_NEXT(var, field))
10449 +
10450 +#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
10451 + for ((var) = DWC_TAILQ_LAST(head, headname); \
10452 + (var) != DWC_TAILQ_END(head); \
10453 + (var) = DWC_TAILQ_PREV(var, headname, field))
10454 +
10455 +/*
10456 + * Tail queue functions.
10457 + */
10458 +#define DWC_TAILQ_INIT(head) do { \
10459 + (head)->tqh_first = NULL; \
10460 + (head)->tqh_last = &(head)->tqh_first; \
10461 +} while (0)
10462 +
10463 +#define DWC_TAILQ_INSERT_HEAD(head, elm, field) do { \
10464 + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
10465 + (head)->tqh_first->field.tqe_prev = \
10466 + &(elm)->field.tqe_next; \
10467 + else \
10468 + (head)->tqh_last = &(elm)->field.tqe_next; \
10469 + (head)->tqh_first = (elm); \
10470 + (elm)->field.tqe_prev = &(head)->tqh_first; \
10471 +} while (0)
10472 +
10473 +#define DWC_TAILQ_INSERT_TAIL(head, elm, field) do { \
10474 + (elm)->field.tqe_next = NULL; \
10475 + (elm)->field.tqe_prev = (head)->tqh_last; \
10476 + *(head)->tqh_last = (elm); \
10477 + (head)->tqh_last = &(elm)->field.tqe_next; \
10478 +} while (0)
10479 +
10480 +#define DWC_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
10481 + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
10482 + (elm)->field.tqe_next->field.tqe_prev = \
10483 + &(elm)->field.tqe_next; \
10484 + else \
10485 + (head)->tqh_last = &(elm)->field.tqe_next; \
10486 + (listelm)->field.tqe_next = (elm); \
10487 + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
10488 +} while (0)
10489 +
10490 +#define DWC_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
10491 + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
10492 + (elm)->field.tqe_next = (listelm); \
10493 + *(listelm)->field.tqe_prev = (elm); \
10494 + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
10495 +} while (0)
10496 +
10497 +#define DWC_TAILQ_REMOVE(head, elm, field) do { \
10498 + if (((elm)->field.tqe_next) != NULL) \
10499 + (elm)->field.tqe_next->field.tqe_prev = \
10500 + (elm)->field.tqe_prev; \
10501 + else \
10502 + (head)->tqh_last = (elm)->field.tqe_prev; \
10503 + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
10504 +} while (0)
10505 +
10506 +#define DWC_TAILQ_REPLACE(head, elm, elm2, field) do { \
10507 + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
10508 + (elm2)->field.tqe_next->field.tqe_prev = \
10509 + &(elm2)->field.tqe_next; \
10510 + else \
10511 + (head)->tqh_last = &(elm2)->field.tqe_next; \
10512 + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
10513 + *(elm2)->field.tqe_prev = (elm2); \
10514 +} while (0)
10515 +
10516 +/*
10517 + * Circular queue definitions.
10518 + */
10519 +#define DWC_CIRCLEQ_HEAD(name, type) \
10520 +struct name { \
10521 + struct type *cqh_first; /* first element */ \
10522 + struct type *cqh_last; /* last element */ \
10523 +}
10524 +
10525 +#define DWC_CIRCLEQ_HEAD_INITIALIZER(head) \
10526 + { DWC_CIRCLEQ_END(&head), DWC_CIRCLEQ_END(&head) }
10527 +
10528 +#define DWC_CIRCLEQ_ENTRY(type) \
10529 +struct { \
10530 + struct type *cqe_next; /* next element */ \
10531 + struct type *cqe_prev; /* previous element */ \
10532 +}
10533 +
10534 +/*
10535 + * Circular queue access methods
10536 + */
10537 +#define DWC_CIRCLEQ_FIRST(head) ((head)->cqh_first)
10538 +#define DWC_CIRCLEQ_LAST(head) ((head)->cqh_last)
10539 +#define DWC_CIRCLEQ_END(head) ((void *)(head))
10540 +#define DWC_CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
10541 +#define DWC_CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
10542 +#define DWC_CIRCLEQ_EMPTY(head) \
10543 + (DWC_CIRCLEQ_FIRST(head) == DWC_CIRCLEQ_END(head))
10544 +
10545 +#define DWC_CIRCLEQ_EMPTY_ENTRY(elm, field) (((elm)->field.cqe_next == NULL) && ((elm)->field.cqe_prev == NULL))
10546 +
10547 +#define DWC_CIRCLEQ_FOREACH(var, head, field) \
10548 + for((var) = DWC_CIRCLEQ_FIRST(head); \
10549 + (var) != DWC_CIRCLEQ_END(head); \
10550 + (var) = DWC_CIRCLEQ_NEXT(var, field))
10551 +
10552 +#define DWC_CIRCLEQ_FOREACH_SAFE(var, var2, head, field) \
10553 + for((var) = DWC_CIRCLEQ_FIRST(head), var2 = DWC_CIRCLEQ_NEXT(var, field); \
10554 + (var) != DWC_CIRCLEQ_END(head); \
10555 + (var) = var2, var2 = DWC_CIRCLEQ_NEXT(var, field))
10556 +
10557 +#define DWC_CIRCLEQ_FOREACH_REVERSE(var, head, field) \
10558 + for((var) = DWC_CIRCLEQ_LAST(head); \
10559 + (var) != DWC_CIRCLEQ_END(head); \
10560 + (var) = DWC_CIRCLEQ_PREV(var, field))
10561 +
10562 +/*
10563 + * Circular queue functions.
10564 + */
10565 +#define DWC_CIRCLEQ_INIT(head) do { \
10566 + (head)->cqh_first = DWC_CIRCLEQ_END(head); \
10567 + (head)->cqh_last = DWC_CIRCLEQ_END(head); \
10568 +} while (0)
10569 +
10570 +#define DWC_CIRCLEQ_INIT_ENTRY(elm, field) do { \
10571 + (elm)->field.cqe_next = NULL; \
10572 + (elm)->field.cqe_prev = NULL; \
10573 +} while (0)
10574 +
10575 +#define DWC_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
10576 + (elm)->field.cqe_next = (listelm)->field.cqe_next; \
10577 + (elm)->field.cqe_prev = (listelm); \
10578 + if ((listelm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
10579 + (head)->cqh_last = (elm); \
10580 + else \
10581 + (listelm)->field.cqe_next->field.cqe_prev = (elm); \
10582 + (listelm)->field.cqe_next = (elm); \
10583 +} while (0)
10584 +
10585 +#define DWC_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
10586 + (elm)->field.cqe_next = (listelm); \
10587 + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
10588 + if ((listelm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
10589 + (head)->cqh_first = (elm); \
10590 + else \
10591 + (listelm)->field.cqe_prev->field.cqe_next = (elm); \
10592 + (listelm)->field.cqe_prev = (elm); \
10593 +} while (0)
10594 +
10595 +#define DWC_CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
10596 + (elm)->field.cqe_next = (head)->cqh_first; \
10597 + (elm)->field.cqe_prev = DWC_CIRCLEQ_END(head); \
10598 + if ((head)->cqh_last == DWC_CIRCLEQ_END(head)) \
10599 + (head)->cqh_last = (elm); \
10600 + else \
10601 + (head)->cqh_first->field.cqe_prev = (elm); \
10602 + (head)->cqh_first = (elm); \
10603 +} while (0)
10604 +
10605 +#define DWC_CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
10606 + (elm)->field.cqe_next = DWC_CIRCLEQ_END(head); \
10607 + (elm)->field.cqe_prev = (head)->cqh_last; \
10608 + if ((head)->cqh_first == DWC_CIRCLEQ_END(head)) \
10609 + (head)->cqh_first = (elm); \
10610 + else \
10611 + (head)->cqh_last->field.cqe_next = (elm); \
10612 + (head)->cqh_last = (elm); \
10613 +} while (0)
10614 +
10615 +#define DWC_CIRCLEQ_REMOVE(head, elm, field) do { \
10616 + if ((elm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
10617 + (head)->cqh_last = (elm)->field.cqe_prev; \
10618 + else \
10619 + (elm)->field.cqe_next->field.cqe_prev = \
10620 + (elm)->field.cqe_prev; \
10621 + if ((elm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
10622 + (head)->cqh_first = (elm)->field.cqe_next; \
10623 + else \
10624 + (elm)->field.cqe_prev->field.cqe_next = \
10625 + (elm)->field.cqe_next; \
10626 +} while (0)
10627 +
10628 +#define DWC_CIRCLEQ_REMOVE_INIT(head, elm, field) do { \
10629 + DWC_CIRCLEQ_REMOVE(head, elm, field); \
10630 + DWC_CIRCLEQ_INIT_ENTRY(elm, field); \
10631 +} while (0)
10632 +
10633 +#define DWC_CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
10634 + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
10635 + DWC_CIRCLEQ_END(head)) \
10636 + (head).cqh_last = (elm2); \
10637 + else \
10638 + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
10639 + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
10640 + DWC_CIRCLEQ_END(head)) \
10641 + (head).cqh_first = (elm2); \
10642 + else \
10643 + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
10644 +} while (0)
10645 +
10646 +#ifdef __cplusplus
10647 +}
10648 +#endif
10649 +
10650 +#endif /* _DWC_LIST_H_ */
10651 --- /dev/null
10652 +++ b/drivers/usb/host/dwc_common_port/dwc_mem.c
10653 @@ -0,0 +1,245 @@
10654 +/* Memory Debugging */
10655 +#ifdef DWC_DEBUG_MEMORY
10656 +
10657 +#include "dwc_os.h"
10658 +#include "dwc_list.h"
10659 +
10660 +struct allocation {
10661 + void *addr;
10662 + void *ctx;
10663 + char *func;
10664 + int line;
10665 + uint32_t size;
10666 + int dma;
10667 + DWC_CIRCLEQ_ENTRY(allocation) entry;
10668 +};
10669 +
10670 +DWC_CIRCLEQ_HEAD(allocation_queue, allocation);
10671 +
10672 +struct allocation_manager {
10673 + void *mem_ctx;
10674 + struct allocation_queue allocations;
10675 +
10676 + /* statistics */
10677 + int num;
10678 + int num_freed;
10679 + int num_active;
10680 + uint32_t total;
10681 + uint32_t cur;
10682 + uint32_t max;
10683 +};
10684 +
10685 +static struct allocation_manager *manager = NULL;
10686 +
10687 +static int add_allocation(void *ctx, uint32_t size, char const *func, int line, void *addr,
10688 + int dma)
10689 +{
10690 + struct allocation *a;
10691 +
10692 + DWC_ASSERT(manager != NULL, "manager not allocated");
10693 +
10694 + a = __DWC_ALLOC_ATOMIC(manager->mem_ctx, sizeof(*a));
10695 + if (!a) {
10696 + return -DWC_E_NO_MEMORY;
10697 + }
10698 +
10699 + a->func = __DWC_ALLOC_ATOMIC(manager->mem_ctx, DWC_STRLEN(func) + 1);
10700 + if (!a->func) {
10701 + __DWC_FREE(manager->mem_ctx, a);
10702 + return -DWC_E_NO_MEMORY;
10703 + }
10704 +
10705 + DWC_MEMCPY(a->func, func, DWC_STRLEN(func) + 1);
10706 + a->addr = addr;
10707 + a->ctx = ctx;
10708 + a->line = line;
10709 + a->size = size;
10710 + a->dma = dma;
10711 + DWC_CIRCLEQ_INSERT_TAIL(&manager->allocations, a, entry);
10712 +
10713 + /* Update stats */
10714 + manager->num++;
10715 + manager->num_active++;
10716 + manager->total += size;
10717 + manager->cur += size;
10718 +
10719 + if (manager->max < manager->cur) {
10720 + manager->max = manager->cur;
10721 + }
10722 +
10723 + return 0;
10724 +}
10725 +
10726 +static struct allocation *find_allocation(void *ctx, void *addr)
10727 +{
10728 + struct allocation *a;
10729 +
10730 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
10731 + if (a->ctx == ctx && a->addr == addr) {
10732 + return a;
10733 + }
10734 + }
10735 +
10736 + return NULL;
10737 +}
10738 +
10739 +static void free_allocation(void *ctx, void *addr, char const *func, int line)
10740 +{
10741 + struct allocation *a = find_allocation(ctx, addr);
10742 +
10743 + if (!a) {
10744 + DWC_ASSERT(0,
10745 + "Free of address %p that was never allocated or already freed %s:%d",
10746 + addr, func, line);
10747 + return;
10748 + }
10749 +
10750 + DWC_CIRCLEQ_REMOVE(&manager->allocations, a, entry);
10751 +
10752 + manager->num_active--;
10753 + manager->num_freed++;
10754 + manager->cur -= a->size;
10755 + __DWC_FREE(manager->mem_ctx, a->func);
10756 + __DWC_FREE(manager->mem_ctx, a);
10757 +}
10758 +
10759 +int dwc_memory_debug_start(void *mem_ctx)
10760 +{
10761 + DWC_ASSERT(manager == NULL, "Memory debugging has already started\n");
10762 +
10763 + if (manager) {
10764 + return -DWC_E_BUSY;
10765 + }
10766 +
10767 + manager = __DWC_ALLOC(mem_ctx, sizeof(*manager));
10768 + if (!manager) {
10769 + return -DWC_E_NO_MEMORY;
10770 + }
10771 +
10772 + DWC_CIRCLEQ_INIT(&manager->allocations);
10773 + manager->mem_ctx = mem_ctx;
10774 + manager->num = 0;
10775 + manager->num_freed = 0;
10776 + manager->num_active = 0;
10777 + manager->total = 0;
10778 + manager->cur = 0;
10779 + manager->max = 0;
10780 +
10781 + return 0;
10782 +}
10783 +
10784 +void dwc_memory_debug_stop(void)
10785 +{
10786 + struct allocation *a;
10787 +
10788 + dwc_memory_debug_report();
10789 +
10790 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
10791 + DWC_ERROR("Memory leaked from %s:%d\n", a->func, a->line);
10792 + free_allocation(a->ctx, a->addr, NULL, -1);
10793 + }
10794 +
10795 + __DWC_FREE(manager->mem_ctx, manager);
10796 +}
10797 +
10798 +void dwc_memory_debug_report(void)
10799 +{
10800 + struct allocation *a;
10801 +
10802 + DWC_PRINTF("\n\n\n----------------- Memory Debugging Report -----------------\n\n");
10803 + DWC_PRINTF("Num Allocations = %d\n", manager->num);
10804 + DWC_PRINTF("Freed = %d\n", manager->num_freed);
10805 + DWC_PRINTF("Active = %d\n", manager->num_active);
10806 + DWC_PRINTF("Current Memory Used = %d\n", manager->cur);
10807 + DWC_PRINTF("Total Memory Used = %d\n", manager->total);
10808 + DWC_PRINTF("Maximum Memory Used at Once = %d\n", manager->max);
10809 + DWC_PRINTF("Unfreed allocations:\n");
10810 +
10811 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
10812 + DWC_PRINTF(" addr=%p, size=%d from %s:%d, DMA=%d\n",
10813 + a->addr, a->size, a->func, a->line, a->dma);
10814 + }
10815 +}
10816 +
10817 +/* The replacement functions */
10818 +void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line)
10819 +{
10820 + void *addr = __DWC_ALLOC(mem_ctx, size);
10821 +
10822 + if (!addr) {
10823 + return NULL;
10824 + }
10825 +
10826 + if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
10827 + __DWC_FREE(mem_ctx, addr);
10828 + return NULL;
10829 + }
10830 +
10831 + return addr;
10832 +}
10833 +
10834 +void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func,
10835 + int line)
10836 +{
10837 + void *addr = __DWC_ALLOC_ATOMIC(mem_ctx, size);
10838 +
10839 + if (!addr) {
10840 + return NULL;
10841 + }
10842 +
10843 + if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
10844 + __DWC_FREE(mem_ctx, addr);
10845 + return NULL;
10846 + }
10847 +
10848 + return addr;
10849 +}
10850 +
10851 +void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line)
10852 +{
10853 + free_allocation(mem_ctx, addr, func, line);
10854 + __DWC_FREE(mem_ctx, addr);
10855 +}
10856 +
10857 +void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
10858 + char const *func, int line)
10859 +{
10860 + void *addr = __DWC_DMA_ALLOC(dma_ctx, size, dma_addr);
10861 +
10862 + if (!addr) {
10863 + return NULL;
10864 + }
10865 +
10866 + if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
10867 + __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
10868 + return NULL;
10869 + }
10870 +
10871 + return addr;
10872 +}
10873 +
10874 +void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size,
10875 + dwc_dma_t *dma_addr, char const *func, int line)
10876 +{
10877 + void *addr = __DWC_DMA_ALLOC_ATOMIC(dma_ctx, size, dma_addr);
10878 +
10879 + if (!addr) {
10880 + return NULL;
10881 + }
10882 +
10883 + if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
10884 + __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
10885 + return NULL;
10886 + }
10887 +
10888 + return addr;
10889 +}
10890 +
10891 +void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
10892 + dwc_dma_t dma_addr, char const *func, int line)
10893 +{
10894 + free_allocation(dma_ctx, virt_addr, func, line);
10895 + __DWC_DMA_FREE(dma_ctx, size, virt_addr, dma_addr);
10896 +}
10897 +
10898 +#endif /* DWC_DEBUG_MEMORY */
10899 --- /dev/null
10900 +++ b/drivers/usb/host/dwc_common_port/dwc_modpow.c
10901 @@ -0,0 +1,636 @@
10902 +/* Bignum routines adapted from PUTTY sources. PuTTY copyright notice follows.
10903 + *
10904 + * PuTTY is copyright 1997-2007 Simon Tatham.
10905 + *
10906 + * Portions copyright Robert de Bath, Joris van Rantwijk, Delian
10907 + * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
10908 + * Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
10909 + * Kuhn, and CORE SDI S.A.
10910 + *
10911 + * Permission is hereby granted, free of charge, to any person
10912 + * obtaining a copy of this software and associated documentation files
10913 + * (the "Software"), to deal in the Software without restriction,
10914 + * including without limitation the rights to use, copy, modify, merge,
10915 + * publish, distribute, sublicense, and/or sell copies of the Software,
10916 + * and to permit persons to whom the Software is furnished to do so,
10917 + * subject to the following conditions:
10918 + *
10919 + * The above copyright notice and this permission notice shall be
10920 + * included in all copies or substantial portions of the Software.
10921 +
10922 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
10923 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10924 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
10925 + * NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
10926 + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
10927 + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
10928 + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10929 + *
10930 + */
10931 +#ifdef DWC_CRYPTOLIB
10932 +
10933 +#ifndef CONFIG_MACH_IPMATE
10934 +
10935 +#include "dwc_modpow.h"
10936 +
10937 +#define BIGNUM_INT_MASK 0xFFFFFFFFUL
10938 +#define BIGNUM_TOP_BIT 0x80000000UL
10939 +#define BIGNUM_INT_BITS 32
10940 +
10941 +
10942 +static void *snmalloc(void *mem_ctx, size_t n, size_t size)
10943 +{
10944 + void *p;
10945 + size *= n;
10946 + if (size == 0) size = 1;
10947 + p = dwc_alloc(mem_ctx, size);
10948 + return p;
10949 +}
10950 +
10951 +#define snewn(ctx, n, type) ((type *)snmalloc((ctx), (n), sizeof(type)))
10952 +#define sfree dwc_free
10953 +
10954 +/*
10955 + * Usage notes:
10956 + * * Do not call the DIVMOD_WORD macro with expressions such as array
10957 + * subscripts, as some implementations object to this (see below).
10958 + * * Note that none of the division methods below will cope if the
10959 + * quotient won't fit into BIGNUM_INT_BITS. Callers should be careful
10960 + * to avoid this case.
10961 + * If this condition occurs, in the case of the x86 DIV instruction,
10962 + * an overflow exception will occur, which (according to a correspondent)
10963 + * will manifest on Windows as something like
10964 + * 0xC0000095: Integer overflow
10965 + * The C variant won't give the right answer, either.
10966 + */
10967 +
10968 +#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
10969 +
10970 +#if defined __GNUC__ && defined __i386__
10971 +#define DIVMOD_WORD(q, r, hi, lo, w) \
10972 + __asm__("div %2" : \
10973 + "=d" (r), "=a" (q) : \
10974 + "r" (w), "d" (hi), "a" (lo))
10975 +#else
10976 +#define DIVMOD_WORD(q, r, hi, lo, w) do { \
10977 + BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
10978 + q = n / w; \
10979 + r = n % w; \
10980 +} while (0)
10981 +#endif
10982 +
10983 +// q = n / w;
10984 +// r = n % w;
10985 +
10986 +#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
10987 +
10988 +#define BIGNUM_INTERNAL
10989 +
10990 +static Bignum newbn(void *mem_ctx, int length)
10991 +{
10992 + Bignum b = snewn(mem_ctx, length + 1, BignumInt);
10993 + //if (!b)
10994 + //abort(); /* FIXME */
10995 + DWC_MEMSET(b, 0, (length + 1) * sizeof(*b));
10996 + b[0] = length;
10997 + return b;
10998 +}
10999 +
11000 +void freebn(void *mem_ctx, Bignum b)
11001 +{
11002 + /*
11003 + * Burn the evidence, just in case.
11004 + */
11005 + DWC_MEMSET(b, 0, sizeof(b[0]) * (b[0] + 1));
11006 + sfree(mem_ctx, b);
11007 +}
11008 +
11009 +/*
11010 + * Compute c = a * b.
11011 + * Input is in the first len words of a and b.
11012 + * Result is returned in the first 2*len words of c.
11013 + */
11014 +static void internal_mul(BignumInt *a, BignumInt *b,
11015 + BignumInt *c, int len)
11016 +{
11017 + int i, j;
11018 + BignumDblInt t;
11019 +
11020 + for (j = 0; j < 2 * len; j++)
11021 + c[j] = 0;
11022 +
11023 + for (i = len - 1; i >= 0; i--) {
11024 + t = 0;
11025 + for (j = len - 1; j >= 0; j--) {
11026 + t += MUL_WORD(a[i], (BignumDblInt) b[j]);
11027 + t += (BignumDblInt) c[i + j + 1];
11028 + c[i + j + 1] = (BignumInt) t;
11029 + t = t >> BIGNUM_INT_BITS;
11030 + }
11031 + c[i] = (BignumInt) t;
11032 + }
11033 +}
11034 +
11035 +static void internal_add_shifted(BignumInt *number,
11036 + unsigned n, int shift)
11037 +{
11038 + int word = 1 + (shift / BIGNUM_INT_BITS);
11039 + int bshift = shift % BIGNUM_INT_BITS;
11040 + BignumDblInt addend;
11041 +
11042 + addend = (BignumDblInt)n << bshift;
11043 +
11044 + while (addend) {
11045 + addend += number[word];
11046 + number[word] = (BignumInt) addend & BIGNUM_INT_MASK;
11047 + addend >>= BIGNUM_INT_BITS;
11048 + word++;
11049 + }
11050 +}
11051 +
11052 +/*
11053 + * Compute a = a % m.
11054 + * Input in first alen words of a and first mlen words of m.
11055 + * Output in first alen words of a
11056 + * (of which first alen-mlen words will be zero).
11057 + * The MSW of m MUST have its high bit set.
11058 + * Quotient is accumulated in the `quotient' array, which is a Bignum
11059 + * rather than the internal bigendian format. Quotient parts are shifted
11060 + * left by `qshift' before adding into quot.
11061 + */
11062 +static void internal_mod(BignumInt *a, int alen,
11063 + BignumInt *m, int mlen,
11064 + BignumInt *quot, int qshift)
11065 +{
11066 + BignumInt m0, m1;
11067 + unsigned int h;
11068 + int i, k;
11069 +
11070 + m0 = m[0];
11071 + if (mlen > 1)
11072 + m1 = m[1];
11073 + else
11074 + m1 = 0;
11075 +
11076 + for (i = 0; i <= alen - mlen; i++) {
11077 + BignumDblInt t;
11078 + unsigned int q, r, c, ai1;
11079 +
11080 + if (i == 0) {
11081 + h = 0;
11082 + } else {
11083 + h = a[i - 1];
11084 + a[i - 1] = 0;
11085 + }
11086 +
11087 + if (i == alen - 1)
11088 + ai1 = 0;
11089 + else
11090 + ai1 = a[i + 1];
11091 +
11092 + /* Find q = h:a[i] / m0 */
11093 + if (h >= m0) {
11094 + /*
11095 + * Special case.
11096 + *
11097 + * To illustrate it, suppose a BignumInt is 8 bits, and
11098 + * we are dividing (say) A1:23:45:67 by A1:B2:C3. Then
11099 + * our initial division will be 0xA123 / 0xA1, which
11100 + * will give a quotient of 0x100 and a divide overflow.
11101 + * However, the invariants in this division algorithm
11102 + * are not violated, since the full number A1:23:... is
11103 + * _less_ than the quotient prefix A1:B2:... and so the
11104 + * following correction loop would have sorted it out.
11105 + *
11106 + * In this situation we set q to be the largest
11107 + * quotient we _can_ stomach (0xFF, of course).
11108 + */
11109 + q = BIGNUM_INT_MASK;
11110 + } else {
11111 + /* Macro doesn't want an array subscript expression passed
11112 + * into it (see definition), so use a temporary. */
11113 + BignumInt tmplo = a[i];
11114 + DIVMOD_WORD(q, r, h, tmplo, m0);
11115 +
11116 + /* Refine our estimate of q by looking at
11117 + h:a[i]:a[i+1] / m0:m1 */
11118 + t = MUL_WORD(m1, q);
11119 + if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) {
11120 + q--;
11121 + t -= m1;
11122 + r = (r + m0) & BIGNUM_INT_MASK; /* overflow? */
11123 + if (r >= (BignumDblInt) m0 &&
11124 + t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--;
11125 + }
11126 + }
11127 +
11128 + /* Subtract q * m from a[i...] */
11129 + c = 0;
11130 + for (k = mlen - 1; k >= 0; k--) {
11131 + t = MUL_WORD(q, m[k]);
11132 + t += c;
11133 + c = (unsigned)(t >> BIGNUM_INT_BITS);
11134 + if ((BignumInt) t > a[i + k])
11135 + c++;
11136 + a[i + k] -= (BignumInt) t;
11137 + }
11138 +
11139 + /* Add back m in case of borrow */
11140 + if (c != h) {
11141 + t = 0;
11142 + for (k = mlen - 1; k >= 0; k--) {
11143 + t += m[k];
11144 + t += a[i + k];
11145 + a[i + k] = (BignumInt) t;
11146 + t = t >> BIGNUM_INT_BITS;
11147 + }
11148 + q--;
11149 + }
11150 + if (quot)
11151 + internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i));
11152 + }
11153 +}
11154 +
11155 +/*
11156 + * Compute p % mod.
11157 + * The most significant word of mod MUST be non-zero.
11158 + * We assume that the result array is the same size as the mod array.
11159 + * We optionally write out a quotient if `quotient' is non-NULL.
11160 + * We can avoid writing out the result if `result' is NULL.
11161 + */
11162 +void bigdivmod(void *mem_ctx, Bignum p, Bignum mod, Bignum result, Bignum quotient)
11163 +{
11164 + BignumInt *n, *m;
11165 + int mshift;
11166 + int plen, mlen, i, j;
11167 +
11168 + /* Allocate m of size mlen, copy mod to m */
11169 + /* We use big endian internally */
11170 + mlen = mod[0];
11171 + m = snewn(mem_ctx, mlen, BignumInt);
11172 + //if (!m)
11173 + //abort(); /* FIXME */
11174 + for (j = 0; j < mlen; j++)
11175 + m[j] = mod[mod[0] - j];
11176 +
11177 + /* Shift m left to make msb bit set */
11178 + for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++)
11179 + if ((m[0] << mshift) & BIGNUM_TOP_BIT)
11180 + break;
11181 + if (mshift) {
11182 + for (i = 0; i < mlen - 1; i++)
11183 + m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift));
11184 + m[mlen - 1] = m[mlen - 1] << mshift;
11185 + }
11186 +
11187 + plen = p[0];
11188 + /* Ensure plen > mlen */
11189 + if (plen <= mlen)
11190 + plen = mlen + 1;
11191 +
11192 + /* Allocate n of size plen, copy p to n */
11193 + n = snewn(mem_ctx, plen, BignumInt);
11194 + //if (!n)
11195 + //abort(); /* FIXME */
11196 + for (j = 0; j < plen; j++)
11197 + n[j] = 0;
11198 + for (j = 1; j <= (int)p[0]; j++)
11199 + n[plen - j] = p[j];
11200 +
11201 + /* Main computation */
11202 + internal_mod(n, plen, m, mlen, quotient, mshift);
11203 +
11204 + /* Fixup result in case the modulus was shifted */
11205 + if (mshift) {
11206 + for (i = plen - mlen - 1; i < plen - 1; i++)
11207 + n[i] = (n[i] << mshift) | (n[i + 1] >> (BIGNUM_INT_BITS - mshift));
11208 + n[plen - 1] = n[plen - 1] << mshift;
11209 + internal_mod(n, plen, m, mlen, quotient, 0);
11210 + for (i = plen - 1; i >= plen - mlen; i--)
11211 + n[i] = (n[i] >> mshift) | (n[i - 1] << (BIGNUM_INT_BITS - mshift));
11212 + }
11213 +
11214 + /* Copy result to buffer */
11215 + if (result) {
11216 + for (i = 1; i <= (int)result[0]; i++) {
11217 + int j = plen - i;
11218 + result[i] = j >= 0 ? n[j] : 0;
11219 + }
11220 + }
11221 +
11222 + /* Free temporary arrays */
11223 + for (i = 0; i < mlen; i++)
11224 + m[i] = 0;
11225 + sfree(mem_ctx, m);
11226 + for (i = 0; i < plen; i++)
11227 + n[i] = 0;
11228 + sfree(mem_ctx, n);
11229 +}
11230 +
11231 +/*
11232 + * Simple remainder.
11233 + */
11234 +Bignum bigmod(void *mem_ctx, Bignum a, Bignum b)
11235 +{
11236 + Bignum r = newbn(mem_ctx, b[0]);
11237 + bigdivmod(mem_ctx, a, b, r, NULL);
11238 + return r;
11239 +}
11240 +
11241 +/*
11242 + * Compute (base ^ exp) % mod.
11243 + */
11244 +Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod)
11245 +{
11246 + BignumInt *a, *b, *n, *m;
11247 + int mshift;
11248 + int mlen, i, j;
11249 + Bignum base, result;
11250 +
11251 + /*
11252 + * The most significant word of mod needs to be non-zero. It
11253 + * should already be, but let's make sure.
11254 + */
11255 + //assert(mod[mod[0]] != 0);
11256 +
11257 + /*
11258 + * Make sure the base is smaller than the modulus, by reducing
11259 + * it modulo the modulus if not.
11260 + */
11261 + base = bigmod(mem_ctx, base_in, mod);
11262 +
11263 + /* Allocate m of size mlen, copy mod to m */
11264 + /* We use big endian internally */
11265 + mlen = mod[0];
11266 + m = snewn(mem_ctx, mlen, BignumInt);
11267 + //if (!m)
11268 + //abort(); /* FIXME */
11269 + for (j = 0; j < mlen; j++)
11270 + m[j] = mod[mod[0] - j];
11271 +
11272 + /* Shift m left to make msb bit set */
11273 + for (mshift = 0; mshift < BIGNUM_INT_BITS - 1; mshift++)
11274 + if ((m[0] << mshift) & BIGNUM_TOP_BIT)
11275 + break;
11276 + if (mshift) {
11277 + for (i = 0; i < mlen - 1; i++)
11278 + m[i] =
11279 + (m[i] << mshift) | (m[i + 1] >>
11280 + (BIGNUM_INT_BITS - mshift));
11281 + m[mlen - 1] = m[mlen - 1] << mshift;
11282 + }
11283 +
11284 + /* Allocate n of size mlen, copy base to n */
11285 + n = snewn(mem_ctx, mlen, BignumInt);
11286 + //if (!n)
11287 + //abort(); /* FIXME */
11288 + i = mlen - base[0];
11289 + for (j = 0; j < i; j++)
11290 + n[j] = 0;
11291 + for (j = 0; j < base[0]; j++)
11292 + n[i + j] = base[base[0] - j];
11293 +
11294 + /* Allocate a and b of size 2*mlen. Set a = 1 */
11295 + a = snewn(mem_ctx, 2 * mlen, BignumInt);
11296 + //if (!a)
11297 + //abort(); /* FIXME */
11298 + b = snewn(mem_ctx, 2 * mlen, BignumInt);
11299 + //if (!b)
11300 + //abort(); /* FIXME */
11301 + for (i = 0; i < 2 * mlen; i++)
11302 + a[i] = 0;
11303 + a[2 * mlen - 1] = 1;
11304 +
11305 + /* Skip leading zero bits of exp. */
11306 + i = 0;
11307 + j = BIGNUM_INT_BITS - 1;
11308 + while (i < exp[0] && (exp[exp[0] - i] & (1 << j)) == 0) {
11309 + j--;
11310 + if (j < 0) {
11311 + i++;
11312 + j = BIGNUM_INT_BITS - 1;
11313 + }
11314 + }
11315 +
11316 + /* Main computation */
11317 + while (i < exp[0]) {
11318 + while (j >= 0) {
11319 + internal_mul(a + mlen, a + mlen, b, mlen);
11320 + internal_mod(b, mlen * 2, m, mlen, NULL, 0);
11321 + if ((exp[exp[0] - i] & (1 << j)) != 0) {
11322 + internal_mul(b + mlen, n, a, mlen);
11323 + internal_mod(a, mlen * 2, m, mlen, NULL, 0);
11324 + } else {
11325 + BignumInt *t;
11326 + t = a;
11327 + a = b;
11328 + b = t;
11329 + }
11330 + j--;
11331 + }
11332 + i++;
11333 + j = BIGNUM_INT_BITS - 1;
11334 + }
11335 +
11336 + /* Fixup result in case the modulus was shifted */
11337 + if (mshift) {
11338 + for (i = mlen - 1; i < 2 * mlen - 1; i++)
11339 + a[i] =
11340 + (a[i] << mshift) | (a[i + 1] >>
11341 + (BIGNUM_INT_BITS - mshift));
11342 + a[2 * mlen - 1] = a[2 * mlen - 1] << mshift;
11343 + internal_mod(a, mlen * 2, m, mlen, NULL, 0);
11344 + for (i = 2 * mlen - 1; i >= mlen; i--)
11345 + a[i] =
11346 + (a[i] >> mshift) | (a[i - 1] <<
11347 + (BIGNUM_INT_BITS - mshift));
11348 + }
11349 +
11350 + /* Copy result to buffer */
11351 + result = newbn(mem_ctx, mod[0]);
11352 + for (i = 0; i < mlen; i++)
11353 + result[result[0] - i] = a[i + mlen];
11354 + while (result[0] > 1 && result[result[0]] == 0)
11355 + result[0]--;
11356 +
11357 + /* Free temporary arrays */
11358 + for (i = 0; i < 2 * mlen; i++)
11359 + a[i] = 0;
11360 + sfree(mem_ctx, a);
11361 + for (i = 0; i < 2 * mlen; i++)
11362 + b[i] = 0;
11363 + sfree(mem_ctx, b);
11364 + for (i = 0; i < mlen; i++)
11365 + m[i] = 0;
11366 + sfree(mem_ctx, m);
11367 + for (i = 0; i < mlen; i++)
11368 + n[i] = 0;
11369 + sfree(mem_ctx, n);
11370 +
11371 + freebn(mem_ctx, base);
11372 +
11373 + return result;
11374 +}
11375 +
11376 +
11377 +#ifdef UNITTEST
11378 +
11379 +static __u32 dh_p[] = {
11380 + 96,
11381 + 0xFFFFFFFF,
11382 + 0xFFFFFFFF,
11383 + 0xA93AD2CA,
11384 + 0x4B82D120,
11385 + 0xE0FD108E,
11386 + 0x43DB5BFC,
11387 + 0x74E5AB31,
11388 + 0x08E24FA0,
11389 + 0xBAD946E2,
11390 + 0x770988C0,
11391 + 0x7A615D6C,
11392 + 0xBBE11757,
11393 + 0x177B200C,
11394 + 0x521F2B18,
11395 + 0x3EC86A64,
11396 + 0xD8760273,
11397 + 0xD98A0864,
11398 + 0xF12FFA06,
11399 + 0x1AD2EE6B,
11400 + 0xCEE3D226,
11401 + 0x4A25619D,
11402 + 0x1E8C94E0,
11403 + 0xDB0933D7,
11404 + 0xABF5AE8C,
11405 + 0xA6E1E4C7,
11406 + 0xB3970F85,
11407 + 0x5D060C7D,
11408 + 0x8AEA7157,
11409 + 0x58DBEF0A,
11410 + 0xECFB8504,
11411 + 0xDF1CBA64,
11412 + 0xA85521AB,
11413 + 0x04507A33,
11414 + 0xAD33170D,
11415 + 0x8AAAC42D,
11416 + 0x15728E5A,
11417 + 0x98FA0510,
11418 + 0x15D22618,
11419 + 0xEA956AE5,
11420 + 0x3995497C,
11421 + 0x95581718,
11422 + 0xDE2BCBF6,
11423 + 0x6F4C52C9,
11424 + 0xB5C55DF0,
11425 + 0xEC07A28F,
11426 + 0x9B2783A2,
11427 + 0x180E8603,
11428 + 0xE39E772C,
11429 + 0x2E36CE3B,
11430 + 0x32905E46,
11431 + 0xCA18217C,
11432 + 0xF1746C08,
11433 + 0x4ABC9804,
11434 + 0x670C354E,
11435 + 0x7096966D,
11436 + 0x9ED52907,
11437 + 0x208552BB,
11438 + 0x1C62F356,
11439 + 0xDCA3AD96,
11440 + 0x83655D23,
11441 + 0xFD24CF5F,
11442 + 0x69163FA8,
11443 + 0x1C55D39A,
11444 + 0x98DA4836,
11445 + 0xA163BF05,
11446 + 0xC2007CB8,
11447 + 0xECE45B3D,
11448 + 0x49286651,
11449 + 0x7C4B1FE6,
11450 + 0xAE9F2411,
11451 + 0x5A899FA5,
11452 + 0xEE386BFB,
11453 + 0xF406B7ED,
11454 + 0x0BFF5CB6,
11455 + 0xA637ED6B,
11456 + 0xF44C42E9,
11457 + 0x625E7EC6,
11458 + 0xE485B576,
11459 + 0x6D51C245,
11460 + 0x4FE1356D,
11461 + 0xF25F1437,
11462 + 0x302B0A6D,
11463 + 0xCD3A431B,
11464 + 0xEF9519B3,
11465 + 0x8E3404DD,
11466 + 0x514A0879,
11467 + 0x3B139B22,
11468 + 0x020BBEA6,
11469 + 0x8A67CC74,
11470 + 0x29024E08,
11471 + 0x80DC1CD1,
11472 + 0xC4C6628B,
11473 + 0x2168C234,
11474 + 0xC90FDAA2,
11475 + 0xFFFFFFFF,
11476 + 0xFFFFFFFF,
11477 +};
11478 +
11479 +static __u32 dh_a[] = {
11480 + 8,
11481 + 0xdf367516,
11482 + 0x86459caa,
11483 + 0xe2d459a4,
11484 + 0xd910dae0,
11485 + 0x8a8b5e37,
11486 + 0x67ab31c6,
11487 + 0xf0b55ea9,
11488 + 0x440051d6,
11489 +};
11490 +
11491 +static __u32 dh_b[] = {
11492 + 8,
11493 + 0xded92656,
11494 + 0xe07a048a,
11495 + 0x6fa452cd,
11496 + 0x2df89d30,
11497 + 0xc75f1b0f,
11498 + 0x8ce3578f,
11499 + 0x7980a324,
11500 + 0x5daec786,
11501 +};
11502 +
11503 +static __u32 dh_g[] = {
11504 + 1,
11505 + 2,
11506 +};
11507 +
11508 +int main(void)
11509 +{
11510 + int i;
11511 + __u32 *k;
11512 + k = dwc_modpow(NULL, dh_g, dh_a, dh_p);
11513 +
11514 + printf("\n\n");
11515 + for (i=0; i<k[0]; i++) {
11516 + __u32 word32 = k[k[0] - i];
11517 + __u16 l = word32 & 0xffff;
11518 + __u16 m = (word32 & 0xffff0000) >> 16;
11519 + printf("%04x %04x ", m, l);
11520 + if (!((i + 1)%13)) printf("\n");
11521 + }
11522 + printf("\n\n");
11523 +
11524 + if ((k[0] == 0x60) && (k[1] == 0x28e490e5) && (k[0x60] == 0x5a0d3d4e)) {
11525 + printf("PASS\n\n");
11526 + }
11527 + else {
11528 + printf("FAIL\n\n");
11529 + }
11530 +
11531 +}
11532 +
11533 +#endif /* UNITTEST */
11534 +
11535 +#endif /* CONFIG_MACH_IPMATE */
11536 +
11537 +#endif /*DWC_CRYPTOLIB */
11538 --- /dev/null
11539 +++ b/drivers/usb/host/dwc_common_port/dwc_modpow.h
11540 @@ -0,0 +1,34 @@
11541 +/*
11542 + * dwc_modpow.h
11543 + * See dwc_modpow.c for license and changes
11544 + */
11545 +#ifndef _DWC_MODPOW_H
11546 +#define _DWC_MODPOW_H
11547 +
11548 +#ifdef __cplusplus
11549 +extern "C" {
11550 +#endif
11551 +
11552 +#include "dwc_os.h"
11553 +
11554 +/** @file
11555 + *
11556 + * This file defines the module exponentiation function which is only used
11557 + * internally by the DWC UWB modules for calculation of PKs during numeric
11558 + * association. The routine is taken from the PUTTY, an open source terminal
11559 + * emulator. The PUTTY License is preserved in the dwc_modpow.c file.
11560 + *
11561 + */
11562 +
11563 +typedef uint32_t BignumInt;
11564 +typedef uint64_t BignumDblInt;
11565 +typedef BignumInt *Bignum;
11566 +
11567 +/* Compute modular exponentiaion */
11568 +extern Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod);
11569 +
11570 +#ifdef __cplusplus
11571 +}
11572 +#endif
11573 +
11574 +#endif /* _LINUX_BIGNUM_H */
11575 --- /dev/null
11576 +++ b/drivers/usb/host/dwc_common_port/dwc_notifier.c
11577 @@ -0,0 +1,319 @@
11578 +#ifdef DWC_NOTIFYLIB
11579 +
11580 +#include "dwc_notifier.h"
11581 +#include "dwc_list.h"
11582 +
11583 +typedef struct dwc_observer {
11584 + void *observer;
11585 + dwc_notifier_callback_t callback;
11586 + void *data;
11587 + char *notification;
11588 + DWC_CIRCLEQ_ENTRY(dwc_observer) list_entry;
11589 +} observer_t;
11590 +
11591 +DWC_CIRCLEQ_HEAD(observer_queue, dwc_observer);
11592 +
11593 +typedef struct dwc_notifier {
11594 + void *mem_ctx;
11595 + void *object;
11596 + struct observer_queue observers;
11597 + DWC_CIRCLEQ_ENTRY(dwc_notifier) list_entry;
11598 +} notifier_t;
11599 +
11600 +DWC_CIRCLEQ_HEAD(notifier_queue, dwc_notifier);
11601 +
11602 +typedef struct manager {
11603 + void *mem_ctx;
11604 + void *wkq_ctx;
11605 + dwc_workq_t *wq;
11606 +// dwc_mutex_t *mutex;
11607 + struct notifier_queue notifiers;
11608 +} manager_t;
11609 +
11610 +static manager_t *manager = NULL;
11611 +
11612 +static int create_manager(void *mem_ctx, void *wkq_ctx)
11613 +{
11614 + manager = dwc_alloc(mem_ctx, sizeof(manager_t));
11615 + if (!manager) {
11616 + return -DWC_E_NO_MEMORY;
11617 + }
11618 +
11619 + DWC_CIRCLEQ_INIT(&manager->notifiers);
11620 +
11621 + manager->wq = dwc_workq_alloc(wkq_ctx, "DWC Notification WorkQ");
11622 + if (!manager->wq) {
11623 + return -DWC_E_NO_MEMORY;
11624 + }
11625 +
11626 + return 0;
11627 +}
11628 +
11629 +static void free_manager(void)
11630 +{
11631 + dwc_workq_free(manager->wq);
11632 +
11633 + /* All notifiers must have unregistered themselves before this module
11634 + * can be removed. Hitting this assertion indicates a programmer
11635 + * error. */
11636 + DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&manager->notifiers),
11637 + "Notification manager being freed before all notifiers have been removed");
11638 + dwc_free(manager->mem_ctx, manager);
11639 +}
11640 +
11641 +#ifdef DEBUG
11642 +static void dump_manager(void)
11643 +{
11644 + notifier_t *n;
11645 + observer_t *o;
11646 +
11647 + DWC_ASSERT(manager, "Notification manager not found");
11648 +
11649 + DWC_DEBUG("List of all notifiers and observers:\n");
11650 + DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
11651 + DWC_DEBUG("Notifier %p has observers:\n", n->object);
11652 + DWC_CIRCLEQ_FOREACH(o, &n->observers, list_entry) {
11653 + DWC_DEBUG(" %p watching %s\n", o->observer, o->notification);
11654 + }
11655 + }
11656 +}
11657 +#else
11658 +#define dump_manager(...)
11659 +#endif
11660 +
11661 +static observer_t *alloc_observer(void *mem_ctx, void *observer, char *notification,
11662 + dwc_notifier_callback_t callback, void *data)
11663 +{
11664 + observer_t *new_observer = dwc_alloc(mem_ctx, sizeof(observer_t));
11665 +
11666 + if (!new_observer) {
11667 + return NULL;
11668 + }
11669 +
11670 + DWC_CIRCLEQ_INIT_ENTRY(new_observer, list_entry);
11671 + new_observer->observer = observer;
11672 + new_observer->notification = notification;
11673 + new_observer->callback = callback;
11674 + new_observer->data = data;
11675 + return new_observer;
11676 +}
11677 +
11678 +static void free_observer(void *mem_ctx, observer_t *observer)
11679 +{
11680 + dwc_free(mem_ctx, observer);
11681 +}
11682 +
11683 +static notifier_t *alloc_notifier(void *mem_ctx, void *object)
11684 +{
11685 + notifier_t *notifier;
11686 +
11687 + if (!object) {
11688 + return NULL;
11689 + }
11690 +
11691 + notifier = dwc_alloc(mem_ctx, sizeof(notifier_t));
11692 + if (!notifier) {
11693 + return NULL;
11694 + }
11695 +
11696 + DWC_CIRCLEQ_INIT(&notifier->observers);
11697 + DWC_CIRCLEQ_INIT_ENTRY(notifier, list_entry);
11698 +
11699 + notifier->mem_ctx = mem_ctx;
11700 + notifier->object = object;
11701 + return notifier;
11702 +}
11703 +
11704 +static void free_notifier(notifier_t *notifier)
11705 +{
11706 + observer_t *observer;
11707 +
11708 + DWC_CIRCLEQ_FOREACH(observer, &notifier->observers, list_entry) {
11709 + free_observer(notifier->mem_ctx, observer);
11710 + }
11711 +
11712 + dwc_free(notifier->mem_ctx, notifier);
11713 +}
11714 +
11715 +static notifier_t *find_notifier(void *object)
11716 +{
11717 + notifier_t *notifier;
11718 +
11719 + DWC_ASSERT(manager, "Notification manager not found");
11720 +
11721 + if (!object) {
11722 + return NULL;
11723 + }
11724 +
11725 + DWC_CIRCLEQ_FOREACH(notifier, &manager->notifiers, list_entry) {
11726 + if (notifier->object == object) {
11727 + return notifier;
11728 + }
11729 + }
11730 +
11731 + return NULL;
11732 +}
11733 +
11734 +int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx)
11735 +{
11736 + return create_manager(mem_ctx, wkq_ctx);
11737 +}
11738 +
11739 +void dwc_free_notification_manager(void)
11740 +{
11741 + free_manager();
11742 +}
11743 +
11744 +dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object)
11745 +{
11746 + notifier_t *notifier;
11747 +
11748 + DWC_ASSERT(manager, "Notification manager not found");
11749 +
11750 + notifier = find_notifier(object);
11751 + if (notifier) {
11752 + DWC_ERROR("Notifier %p is already registered\n", object);
11753 + return NULL;
11754 + }
11755 +
11756 + notifier = alloc_notifier(mem_ctx, object);
11757 + if (!notifier) {
11758 + return NULL;
11759 + }
11760 +
11761 + DWC_CIRCLEQ_INSERT_TAIL(&manager->notifiers, notifier, list_entry);
11762 +
11763 + DWC_INFO("Notifier %p registered", object);
11764 + dump_manager();
11765 +
11766 + return notifier;
11767 +}
11768 +
11769 +void dwc_unregister_notifier(dwc_notifier_t *notifier)
11770 +{
11771 + DWC_ASSERT(manager, "Notification manager not found");
11772 +
11773 + if (!DWC_CIRCLEQ_EMPTY(&notifier->observers)) {
11774 + observer_t *o;
11775 +
11776 + DWC_ERROR("Notifier %p has active observers when removing\n", notifier->object);
11777 + DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
11778 + DWC_DEBUGC(" %p watching %s\n", o->observer, o->notification);
11779 + }
11780 +
11781 + DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&notifier->observers),
11782 + "Notifier %p has active observers when removing", notifier);
11783 + }
11784 +
11785 + DWC_CIRCLEQ_REMOVE_INIT(&manager->notifiers, notifier, list_entry);
11786 + free_notifier(notifier);
11787 +
11788 + DWC_INFO("Notifier unregistered");
11789 + dump_manager();
11790 +}
11791 +
11792 +/* Add an observer to observe the notifier for a particular state, event, or notification. */
11793 +int dwc_add_observer(void *observer, void *object, char *notification,
11794 + dwc_notifier_callback_t callback, void *data)
11795 +{
11796 + notifier_t *notifier = find_notifier(object);
11797 + observer_t *new_observer;
11798 +
11799 + if (!notifier) {
11800 + DWC_ERROR("Notifier %p is not found when adding observer\n", object);
11801 + return -DWC_E_INVALID;
11802 + }
11803 +
11804 + new_observer = alloc_observer(notifier->mem_ctx, observer, notification, callback, data);
11805 + if (!new_observer) {
11806 + return -DWC_E_NO_MEMORY;
11807 + }
11808 +
11809 + DWC_CIRCLEQ_INSERT_TAIL(&notifier->observers, new_observer, list_entry);
11810 +
11811 + DWC_INFO("Added observer %p to notifier %p observing notification %s, callback=%p, data=%p",
11812 + observer, object, notification, callback, data);
11813 +
11814 + dump_manager();
11815 + return 0;
11816 +}
11817 +
11818 +int dwc_remove_observer(void *observer)
11819 +{
11820 + notifier_t *n;
11821 +
11822 + DWC_ASSERT(manager, "Notification manager not found");
11823 +
11824 + DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
11825 + observer_t *o;
11826 + observer_t *o2;
11827 +
11828 + DWC_CIRCLEQ_FOREACH_SAFE(o, o2, &n->observers, list_entry) {
11829 + if (o->observer == observer) {
11830 + DWC_CIRCLEQ_REMOVE_INIT(&n->observers, o, list_entry);
11831 + DWC_INFO("Removing observer %p from notifier %p watching notification %s:",
11832 + o->observer, n->object, o->notification);
11833 + free_observer(n->mem_ctx, o);
11834 + }
11835 + }
11836 + }
11837 +
11838 + dump_manager();
11839 + return 0;
11840 +}
11841 +
11842 +typedef struct callback_data {
11843 + void *mem_ctx;
11844 + dwc_notifier_callback_t cb;
11845 + void *observer;
11846 + void *data;
11847 + void *object;
11848 + char *notification;
11849 + void *notification_data;
11850 +} cb_data_t;
11851 +
11852 +static void cb_task(void *data)
11853 +{
11854 + cb_data_t *cb = (cb_data_t *)data;
11855 +
11856 + cb->cb(cb->object, cb->notification, cb->observer, cb->notification_data, cb->data);
11857 + dwc_free(cb->mem_ctx, cb);
11858 +}
11859 +
11860 +void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data)
11861 +{
11862 + observer_t *o;
11863 +
11864 + DWC_ASSERT(manager, "Notification manager not found");
11865 +
11866 + DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
11867 + int len = DWC_STRLEN(notification);
11868 +
11869 + if (DWC_STRLEN(o->notification) != len) {
11870 + continue;
11871 + }
11872 +
11873 + if (DWC_STRNCMP(o->notification, notification, len) == 0) {
11874 + cb_data_t *cb_data = dwc_alloc(notifier->mem_ctx, sizeof(cb_data_t));
11875 +
11876 + if (!cb_data) {
11877 + DWC_ERROR("Failed to allocate callback data\n");
11878 + return;
11879 + }
11880 +
11881 + cb_data->mem_ctx = notifier->mem_ctx;
11882 + cb_data->cb = o->callback;
11883 + cb_data->observer = o->observer;
11884 + cb_data->data = o->data;
11885 + cb_data->object = notifier->object;
11886 + cb_data->notification = notification;
11887 + cb_data->notification_data = notification_data;
11888 + DWC_DEBUGC("Observer found %p for notification %s\n", o->observer, notification);
11889 + DWC_WORKQ_SCHEDULE(manager->wq, cb_task, cb_data,
11890 + "Notify callback from %p for Notification %s, to observer %p",
11891 + cb_data->object, notification, cb_data->observer);
11892 + }
11893 + }
11894 +}
11895 +
11896 +#endif /* DWC_NOTIFYLIB */
11897 --- /dev/null
11898 +++ b/drivers/usb/host/dwc_common_port/dwc_notifier.h
11899 @@ -0,0 +1,122 @@
11900 +
11901 +#ifndef __DWC_NOTIFIER_H__
11902 +#define __DWC_NOTIFIER_H__
11903 +
11904 +#ifdef __cplusplus
11905 +extern "C" {
11906 +#endif
11907 +
11908 +#include "dwc_os.h"
11909 +
11910 +/** @file
11911 + *
11912 + * A simple implementation of the Observer pattern. Any "module" can
11913 + * register as an observer or notifier. The notion of "module" is abstract and
11914 + * can mean anything used to identify either an observer or notifier. Usually
11915 + * it will be a pointer to a data structure which contains some state, ie an
11916 + * object.
11917 + *
11918 + * Before any notifiers can be added, the global notification manager must be
11919 + * brought up with dwc_alloc_notification_manager().
11920 + * dwc_free_notification_manager() will bring it down and free all resources.
11921 + * These would typically be called upon module load and unload. The
11922 + * notification manager is a single global instance that handles all registered
11923 + * observable modules and observers so this should be done only once.
11924 + *
11925 + * A module can be observable by using Notifications to publicize some general
11926 + * information about it's state or operation. It does not care who listens, or
11927 + * even if anyone listens, or what they do with the information. The observable
11928 + * modules do not need to know any information about it's observers or their
11929 + * interface, or their state or data.
11930 + *
11931 + * Any module can register to emit Notifications. It should publish a list of
11932 + * notifications that it can emit and their behavior, such as when they will get
11933 + * triggered, and what information will be provided to the observer. Then it
11934 + * should register itself as an observable module. See dwc_register_notifier().
11935 + *
11936 + * Any module can observe any observable, registered module, provided it has a
11937 + * handle to the other module and knows what notifications to observe. See
11938 + * dwc_add_observer().
11939 + *
11940 + * A function of type dwc_notifier_callback_t is called whenever a notification
11941 + * is triggered with one or more observers observing it. This function is
11942 + * called in it's own process so it may sleep or block if needed. It is
11943 + * guaranteed to be called sometime after the notification has occurred and will
11944 + * be called once per each time the notification is triggered. It will NOT be
11945 + * called in the same process context used to trigger the notification.
11946 + *
11947 + * @section Limitiations
11948 + *
11949 + * Keep in mind that Notifications that can be triggered in rapid sucession may
11950 + * schedule too many processes too handle. Be aware of this limitation when
11951 + * designing to use notifications, and only add notifications for appropriate
11952 + * observable information.
11953 + *
11954 + * Also Notification callbacks are not synchronous. If you need to synchronize
11955 + * the behavior between module/observer you must use other means. And perhaps
11956 + * that will mean Notifications are not the proper solution.
11957 + */
11958 +
11959 +struct dwc_notifier;
11960 +typedef struct dwc_notifier dwc_notifier_t;
11961 +
11962 +/** The callback function must be of this type.
11963 + *
11964 + * @param object This is the object that is being observed.
11965 + * @param notification This is the notification that was triggered.
11966 + * @param observer This is the observer
11967 + * @param notification_data This is notification-specific data that the notifier
11968 + * has included in this notification. The value of this should be published in
11969 + * the documentation of the observable module with the notifications.
11970 + * @param user_data This is any custom data that the observer provided when
11971 + * adding itself as an observer to the notification. */
11972 +typedef void (*dwc_notifier_callback_t)(void *object, char *notification, void *observer,
11973 + void *notification_data, void *user_data);
11974 +
11975 +/** Brings up the notification manager. */
11976 +extern int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx);
11977 +/** Brings down the notification manager. */
11978 +extern void dwc_free_notification_manager(void);
11979 +
11980 +/** This function registers an observable module. A dwc_notifier_t object is
11981 + * returned to the observable module. This is an opaque object that is used by
11982 + * the observable module to trigger notifications. This object should only be
11983 + * accessible to functions that are authorized to trigger notifications for this
11984 + * module. Observers do not need this object. */
11985 +extern dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object);
11986 +
11987 +/** This function unregisters an observable module. All observers have to be
11988 + * removed prior to unregistration. */
11989 +extern void dwc_unregister_notifier(dwc_notifier_t *notifier);
11990 +
11991 +/** Add a module as an observer to the observable module. The observable module
11992 + * needs to have previously registered with the notification manager.
11993 + *
11994 + * @param observer The observer module
11995 + * @param object The module to observe
11996 + * @param notification The notification to observe
11997 + * @param callback The callback function to call
11998 + * @param user_data Any additional user data to pass into the callback function */
11999 +extern int dwc_add_observer(void *observer, void *object, char *notification,
12000 + dwc_notifier_callback_t callback, void *user_data);
12001 +
12002 +/** Removes the specified observer from all notifications that it is currently
12003 + * observing. */
12004 +extern int dwc_remove_observer(void *observer);
12005 +
12006 +/** This function triggers a Notification. It should be called by the
12007 + * observable module, or any module or library which the observable module
12008 + * allows to trigger notification on it's behalf. Such as the dwc_cc_t.
12009 + *
12010 + * dwc_notify is a non-blocking function. Callbacks are scheduled called in
12011 + * their own process context for each trigger. Callbacks can be blocking.
12012 + * dwc_notify can be called from interrupt context if needed.
12013 + *
12014 + */
12015 +void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data);
12016 +
12017 +#ifdef __cplusplus
12018 +}
12019 +#endif
12020 +
12021 +#endif /* __DWC_NOTIFIER_H__ */
12022 --- /dev/null
12023 +++ b/drivers/usb/host/dwc_common_port/dwc_os.h
12024 @@ -0,0 +1,1262 @@
12025 +/* =========================================================================
12026 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_os.h $
12027 + * $Revision: #14 $
12028 + * $Date: 2010/11/04 $
12029 + * $Change: 1621695 $
12030 + *
12031 + * Synopsys Portability Library Software and documentation
12032 + * (hereinafter, "Software") is an Unsupported proprietary work of
12033 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
12034 + * between Synopsys and you.
12035 + *
12036 + * The Software IS NOT an item of Licensed Software or Licensed Product
12037 + * under any End User Software License Agreement or Agreement for
12038 + * Licensed Product with Synopsys or any supplement thereto. You are
12039 + * permitted to use and redistribute this Software in source and binary
12040 + * forms, with or without modification, provided that redistributions
12041 + * of source code must retain this notice. You may not view, use,
12042 + * disclose, copy or distribute this file or any information contained
12043 + * herein except pursuant to this license grant from Synopsys. If you
12044 + * do not agree with this notice, including the disclaimer below, then
12045 + * you are not authorized to use the Software.
12046 + *
12047 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
12048 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
12049 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12050 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
12051 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
12052 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
12053 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
12054 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
12055 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12056 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
12057 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
12058 + * DAMAGE.
12059 + * ========================================================================= */
12060 +#ifndef _DWC_OS_H_
12061 +#define _DWC_OS_H_
12062 +
12063 +#ifdef __cplusplus
12064 +extern "C" {
12065 +#endif
12066 +
12067 +/** @file
12068 + *
12069 + * DWC portability library, low level os-wrapper functions
12070 + *
12071 + */
12072 +
12073 +/* These basic types need to be defined by some OS header file or custom header
12074 + * file for your specific target architecture.
12075 + *
12076 + * uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t
12077 + *
12078 + * Any custom or alternate header file must be added and enabled here.
12079 + */
12080 +
12081 +#ifdef DWC_LINUX
12082 +# include <linux/types.h>
12083 +# ifdef CONFIG_DEBUG_MUTEXES
12084 +# include <linux/mutex.h>
12085 +# endif
12086 +# include <linux/errno.h>
12087 +# include <stdarg.h>
12088 +#endif
12089 +
12090 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12091 +# include <os_dep.h>
12092 +#endif
12093 +
12094 +
12095 +/** @name Primitive Types and Values */
12096 +
12097 +/** We define a boolean type for consistency. Can be either YES or NO */
12098 +typedef uint8_t dwc_bool_t;
12099 +#define YES 1
12100 +#define NO 0
12101 +
12102 +#ifdef DWC_LINUX
12103 +
12104 +/** @name Error Codes */
12105 +#define DWC_E_INVALID EINVAL
12106 +#define DWC_E_NO_MEMORY ENOMEM
12107 +#define DWC_E_NO_DEVICE ENODEV
12108 +#define DWC_E_NOT_SUPPORTED EOPNOTSUPP
12109 +#define DWC_E_TIMEOUT ETIMEDOUT
12110 +#define DWC_E_BUSY EBUSY
12111 +#define DWC_E_AGAIN EAGAIN
12112 +#define DWC_E_RESTART ERESTART
12113 +#define DWC_E_ABORT ECONNABORTED
12114 +#define DWC_E_SHUTDOWN ESHUTDOWN
12115 +#define DWC_E_NO_DATA ENODATA
12116 +#define DWC_E_DISCONNECT ECONNRESET
12117 +#define DWC_E_UNKNOWN EINVAL
12118 +#define DWC_E_NO_STREAM_RES ENOSR
12119 +#define DWC_E_COMMUNICATION ECOMM
12120 +#define DWC_E_OVERFLOW EOVERFLOW
12121 +#define DWC_E_PROTOCOL EPROTO
12122 +#define DWC_E_IN_PROGRESS EINPROGRESS
12123 +#define DWC_E_PIPE EPIPE
12124 +#define DWC_E_IO EIO
12125 +#define DWC_E_NO_SPACE ENOSPC
12126 +
12127 +#else
12128 +
12129 +/** @name Error Codes */
12130 +#define DWC_E_INVALID 1001
12131 +#define DWC_E_NO_MEMORY 1002
12132 +#define DWC_E_NO_DEVICE 1003
12133 +#define DWC_E_NOT_SUPPORTED 1004
12134 +#define DWC_E_TIMEOUT 1005
12135 +#define DWC_E_BUSY 1006
12136 +#define DWC_E_AGAIN 1007
12137 +#define DWC_E_RESTART 1008
12138 +#define DWC_E_ABORT 1009
12139 +#define DWC_E_SHUTDOWN 1010
12140 +#define DWC_E_NO_DATA 1011
12141 +#define DWC_E_DISCONNECT 2000
12142 +#define DWC_E_UNKNOWN 3000
12143 +#define DWC_E_NO_STREAM_RES 4001
12144 +#define DWC_E_COMMUNICATION 4002
12145 +#define DWC_E_OVERFLOW 4003
12146 +#define DWC_E_PROTOCOL 4004
12147 +#define DWC_E_IN_PROGRESS 4005
12148 +#define DWC_E_PIPE 4006
12149 +#define DWC_E_IO 4007
12150 +#define DWC_E_NO_SPACE 4008
12151 +
12152 +#endif
12153 +
12154 +
12155 +/** @name Tracing/Logging Functions
12156 + *
12157 + * These function provide the capability to add tracing, debugging, and error
12158 + * messages, as well exceptions as assertions. The WUDEV uses these
12159 + * extensively. These could be logged to the main console, the serial port, an
12160 + * internal buffer, etc. These functions could also be no-op if they are too
12161 + * expensive on your system. By default undefining the DEBUG macro already
12162 + * no-ops some of these functions. */
12163 +
12164 +/** Returns non-zero if in interrupt context. */
12165 +extern dwc_bool_t DWC_IN_IRQ(void);
12166 +#define dwc_in_irq DWC_IN_IRQ
12167 +
12168 +/** Returns "IRQ" if DWC_IN_IRQ is true. */
12169 +static inline char *dwc_irq(void) {
12170 + return DWC_IN_IRQ() ? "IRQ" : "";
12171 +}
12172 +
12173 +/** Returns non-zero if in bottom-half context. */
12174 +extern dwc_bool_t DWC_IN_BH(void);
12175 +#define dwc_in_bh DWC_IN_BH
12176 +
12177 +/** Returns "BH" if DWC_IN_BH is true. */
12178 +static inline char *dwc_bh(void) {
12179 + return DWC_IN_BH() ? "BH" : "";
12180 +}
12181 +
12182 +/**
12183 + * A vprintf() clone. Just call vprintf if you've got it.
12184 + */
12185 +extern void DWC_VPRINTF(char *format, va_list args);
12186 +#define dwc_vprintf DWC_VPRINTF
12187 +
12188 +/**
12189 + * A vsnprintf() clone. Just call vprintf if you've got it.
12190 + */
12191 +extern int DWC_VSNPRINTF(char *str, int size, char *format, va_list args);
12192 +#define dwc_vsnprintf DWC_VSNPRINTF
12193 +
12194 +/**
12195 + * printf() clone. Just call printf if you've go it.
12196 + */
12197 +extern void DWC_PRINTF(char *format, ...)
12198 +/* This provides compiler level static checking of the parameters if you're
12199 + * using GCC. */
12200 +#ifdef __GNUC__
12201 + __attribute__ ((format(printf, 1, 2)));
12202 +#else
12203 + ;
12204 +#endif
12205 +#define dwc_printf DWC_PRINTF
12206 +
12207 +/**
12208 + * sprintf() clone. Just call sprintf if you've got it.
12209 + */
12210 +extern int DWC_SPRINTF(char *string, char *format, ...)
12211 +#ifdef __GNUC__
12212 + __attribute__ ((format(printf, 2, 3)));
12213 +#else
12214 + ;
12215 +#endif
12216 +#define dwc_sprintf DWC_SPRINTF
12217 +
12218 +/**
12219 + * snprintf() clone. Just call snprintf if you've got it.
12220 + */
12221 +extern int DWC_SNPRINTF(char *string, int size, char *format, ...)
12222 +#ifdef __GNUC__
12223 + __attribute__ ((format(printf, 3, 4)));
12224 +#else
12225 + ;
12226 +#endif
12227 +#define dwc_snprintf DWC_SNPRINTF
12228 +
12229 +/**
12230 + * Prints a WARNING message. On systems that don't differentiate between
12231 + * warnings and regular log messages, just print it. Indicates that something
12232 + * may be wrong with the driver. Works like printf().
12233 + *
12234 + * Use the DWC_WARN macro to call this function.
12235 + */
12236 +extern void __DWC_WARN(char *format, ...)
12237 +#ifdef __GNUC__
12238 + __attribute__ ((format(printf, 1, 2)));
12239 +#else
12240 + ;
12241 +#endif
12242 +
12243 +/**
12244 + * Prints an error message. On systems that don't differentiate between errors
12245 + * and regular log messages, just print it. Indicates that something went wrong
12246 + * with the driver. Works like printf().
12247 + *
12248 + * Use the DWC_ERROR macro to call this function.
12249 + */
12250 +extern void __DWC_ERROR(char *format, ...)
12251 +#ifdef __GNUC__
12252 + __attribute__ ((format(printf, 1, 2)));
12253 +#else
12254 + ;
12255 +#endif
12256 +
12257 +/**
12258 + * Prints an exception error message and takes some user-defined action such as
12259 + * print out a backtrace or trigger a breakpoint. Indicates that something went
12260 + * abnormally wrong with the driver such as programmer error, or other
12261 + * exceptional condition. It should not be ignored so even on systems without
12262 + * printing capability, some action should be taken to notify the developer of
12263 + * it. Works like printf().
12264 + */
12265 +extern void DWC_EXCEPTION(char *format, ...)
12266 +#ifdef __GNUC__
12267 + __attribute__ ((format(printf, 1, 2)));
12268 +#else
12269 + ;
12270 +#endif
12271 +#define dwc_exception DWC_EXCEPTION
12272 +
12273 +#ifndef DWC_OTG_DEBUG_LEV
12274 +#define DWC_OTG_DEBUG_LEV 0
12275 +#endif
12276 +
12277 +#ifdef DEBUG
12278 +/**
12279 + * Prints out a debug message. Used for logging/trace messages.
12280 + *
12281 + * Use the DWC_DEBUG macro to call this function
12282 + */
12283 +extern void __DWC_DEBUG(char *format, ...)
12284 +#ifdef __GNUC__
12285 + __attribute__ ((format(printf, 1, 2)));
12286 +#else
12287 + ;
12288 +#endif
12289 +#else
12290 +#define __DWC_DEBUG printk
12291 +#endif
12292 +
12293 +/**
12294 + * Prints out a Debug message.
12295 + */
12296 +#define DWC_DEBUG(_format, _args...) __DWC_DEBUG("DEBUG:%s:%s: " _format "\n", \
12297 + __func__, dwc_irq(), ## _args)
12298 +#define dwc_debug DWC_DEBUG
12299 +/**
12300 + * Prints out a Debug message if enabled at compile time.
12301 + */
12302 +#if DWC_OTG_DEBUG_LEV > 0
12303 +#define DWC_DEBUGC(_format, _args...) DWC_DEBUG(_format, ##_args )
12304 +#else
12305 +#define DWC_DEBUGC(_format, _args...)
12306 +#endif
12307 +#define dwc_debugc DWC_DEBUGC
12308 +/**
12309 + * Prints out an informative message.
12310 + */
12311 +#define DWC_INFO(_format, _args...) DWC_PRINTF("INFO:%s: " _format "\n", \
12312 + dwc_irq(), ## _args)
12313 +#define dwc_info DWC_INFO
12314 +/**
12315 + * Prints out an informative message if enabled at compile time.
12316 + */
12317 +#if DWC_OTG_DEBUG_LEV > 1
12318 +#define DWC_INFOC(_format, _args...) DWC_INFO(_format, ##_args )
12319 +#else
12320 +#define DWC_INFOC(_format, _args...)
12321 +#endif
12322 +#define dwc_infoc DWC_INFOC
12323 +/**
12324 + * Prints out a warning message.
12325 + */
12326 +#define DWC_WARN(_format, _args...) __DWC_WARN("WARN:%s:%s:%d: " _format "\n", \
12327 + dwc_irq(), __func__, __LINE__, ## _args)
12328 +#define dwc_warn DWC_WARN
12329 +/**
12330 + * Prints out an error message.
12331 + */
12332 +#define DWC_ERROR(_format, _args...) __DWC_ERROR("ERROR:%s:%s:%d: " _format "\n", \
12333 + dwc_irq(), __func__, __LINE__, ## _args)
12334 +#define dwc_error DWC_ERROR
12335 +
12336 +#define DWC_PROTO_ERROR(_format, _args...) __DWC_WARN("ERROR:%s:%s:%d: " _format "\n", \
12337 + dwc_irq(), __func__, __LINE__, ## _args)
12338 +#define dwc_proto_error DWC_PROTO_ERROR
12339 +
12340 +#ifdef DEBUG
12341 +/** Prints out a exception error message if the _expr expression fails. Disabled
12342 + * if DEBUG is not enabled. */
12343 +#define DWC_ASSERT(_expr, _format, _args...) do { \
12344 + if (!(_expr)) { DWC_EXCEPTION("%s:%s:%d: " _format "\n", dwc_irq(), \
12345 + __FILE__, __LINE__, ## _args); } \
12346 + } while (0)
12347 +#else
12348 +#define DWC_ASSERT(_x...)
12349 +#endif
12350 +#define dwc_assert DWC_ASSERT
12351 +
12352 +
12353 +/** @name Byte Ordering
12354 + * The following functions are for conversions between processor's byte ordering
12355 + * and specific ordering you want.
12356 + */
12357 +
12358 +/** Converts 32 bit data in CPU byte ordering to little endian. */
12359 +extern uint32_t DWC_CPU_TO_LE32(uint32_t *p);
12360 +#define dwc_cpu_to_le32 DWC_CPU_TO_LE32
12361 +
12362 +/** Converts 32 bit data in CPU byte orderint to big endian. */
12363 +extern uint32_t DWC_CPU_TO_BE32(uint32_t *p);
12364 +#define dwc_cpu_to_be32 DWC_CPU_TO_BE32
12365 +
12366 +/** Converts 32 bit little endian data to CPU byte ordering. */
12367 +extern uint32_t DWC_LE32_TO_CPU(uint32_t *p);
12368 +#define dwc_le32_to_cpu DWC_LE32_TO_CPU
12369 +
12370 +/** Converts 32 bit big endian data to CPU byte ordering. */
12371 +extern uint32_t DWC_BE32_TO_CPU(uint32_t *p);
12372 +#define dwc_be32_to_cpu DWC_BE32_TO_CPU
12373 +
12374 +/** Converts 16 bit data in CPU byte ordering to little endian. */
12375 +extern uint16_t DWC_CPU_TO_LE16(uint16_t *p);
12376 +#define dwc_cpu_to_le16 DWC_CPU_TO_LE16
12377 +
12378 +/** Converts 16 bit data in CPU byte orderint to big endian. */
12379 +extern uint16_t DWC_CPU_TO_BE16(uint16_t *p);
12380 +#define dwc_cpu_to_be16 DWC_CPU_TO_BE16
12381 +
12382 +/** Converts 16 bit little endian data to CPU byte ordering. */
12383 +extern uint16_t DWC_LE16_TO_CPU(uint16_t *p);
12384 +#define dwc_le16_to_cpu DWC_LE16_TO_CPU
12385 +
12386 +/** Converts 16 bit bi endian data to CPU byte ordering. */
12387 +extern uint16_t DWC_BE16_TO_CPU(uint16_t *p);
12388 +#define dwc_be16_to_cpu DWC_BE16_TO_CPU
12389 +
12390 +
12391 +/** @name Register Read/Write
12392 + *
12393 + * The following six functions should be implemented to read/write registers of
12394 + * 32-bit and 64-bit sizes. All modules use this to read/write register values.
12395 + * The reg value is a pointer to the register calculated from the void *base
12396 + * variable passed into the driver when it is started. */
12397 +
12398 +#ifdef DWC_LINUX
12399 +/* Linux doesn't need any extra parameters for register read/write, so we
12400 + * just throw away the IO context parameter.
12401 + */
12402 +/** Reads the content of a 32-bit register. */
12403 +extern uint32_t DWC_READ_REG32(uint32_t volatile *reg);
12404 +#define dwc_read_reg32(_ctx_,_reg_) DWC_READ_REG32(_reg_)
12405 +
12406 +/** Reads the content of a 64-bit register. */
12407 +extern uint64_t DWC_READ_REG64(uint64_t volatile *reg);
12408 +#define dwc_read_reg64(_ctx_,_reg_) DWC_READ_REG64(_reg_)
12409 +
12410 +/** Writes to a 32-bit register. */
12411 +extern void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value);
12412 +#define dwc_write_reg32(_ctx_,_reg_,_val_) DWC_WRITE_REG32(_reg_, _val_)
12413 +
12414 +/** Writes to a 64-bit register. */
12415 +extern void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value);
12416 +#define dwc_write_reg64(_ctx_,_reg_,_val_) DWC_WRITE_REG64(_reg_, _val_)
12417 +
12418 +/**
12419 + * Modify bit values in a register. Using the
12420 + * algorithm: (reg_contents & ~clear_mask) | set_mask.
12421 + */
12422 +extern void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
12423 +#define dwc_modify_reg32(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG32(_reg_,_cmsk_,_smsk_)
12424 +extern void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
12425 +#define dwc_modify_reg64(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG64(_reg_,_cmsk_,_smsk_)
12426 +
12427 +#endif /* DWC_LINUX */
12428 +
12429 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12430 +typedef struct dwc_ioctx {
12431 + struct device *dev;
12432 + bus_space_tag_t iot;
12433 + bus_space_handle_t ioh;
12434 +} dwc_ioctx_t;
12435 +
12436 +/** BSD needs two extra parameters for register read/write, so we pass
12437 + * them in using the IO context parameter.
12438 + */
12439 +/** Reads the content of a 32-bit register. */
12440 +extern uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg);
12441 +#define dwc_read_reg32 DWC_READ_REG32
12442 +
12443 +/** Reads the content of a 64-bit register. */
12444 +extern uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg);
12445 +#define dwc_read_reg64 DWC_READ_REG64
12446 +
12447 +/** Writes to a 32-bit register. */
12448 +extern void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value);
12449 +#define dwc_write_reg32 DWC_WRITE_REG32
12450 +
12451 +/** Writes to a 64-bit register. */
12452 +extern void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value);
12453 +#define dwc_write_reg64 DWC_WRITE_REG64
12454 +
12455 +/**
12456 + * Modify bit values in a register. Using the
12457 + * algorithm: (reg_contents & ~clear_mask) | set_mask.
12458 + */
12459 +extern void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
12460 +#define dwc_modify_reg32 DWC_MODIFY_REG32
12461 +extern void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
12462 +#define dwc_modify_reg64 DWC_MODIFY_REG64
12463 +
12464 +#endif /* DWC_FREEBSD || DWC_NETBSD */
12465 +
12466 +/** @cond */
12467 +
12468 +/** @name Some convenience MACROS used internally. Define DWC_DEBUG_REGS to log the
12469 + * register writes. */
12470 +
12471 +#ifdef DWC_LINUX
12472 +
12473 +# ifdef DWC_DEBUG_REGS
12474 +
12475 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12476 +static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
12477 + return DWC_READ_REG32(&container->regs->_reg[num]); \
12478 +} \
12479 +static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
12480 + DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
12481 + &(((uint32_t*)container->regs->_reg)[num]), data); \
12482 + DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
12483 +}
12484 +
12485 +#define dwc_define_read_write_reg(_reg,_container_type) \
12486 +static inline uint32_t dwc_read_##_reg(_container_type *container) { \
12487 + return DWC_READ_REG32(&container->regs->_reg); \
12488 +} \
12489 +static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
12490 + DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
12491 + DWC_WRITE_REG32(&container->regs->_reg, data); \
12492 +}
12493 +
12494 +# else /* DWC_DEBUG_REGS */
12495 +
12496 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12497 +static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
12498 + return DWC_READ_REG32(&container->regs->_reg[num]); \
12499 +} \
12500 +static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
12501 + DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
12502 +}
12503 +
12504 +#define dwc_define_read_write_reg(_reg,_container_type) \
12505 +static inline uint32_t dwc_read_##_reg(_container_type *container) { \
12506 + return DWC_READ_REG32(&container->regs->_reg); \
12507 +} \
12508 +static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
12509 + DWC_WRITE_REG32(&container->regs->_reg, data); \
12510 +}
12511 +
12512 +# endif /* DWC_DEBUG_REGS */
12513 +
12514 +#endif /* DWC_LINUX */
12515 +
12516 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12517 +
12518 +# ifdef DWC_DEBUG_REGS
12519 +
12520 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12521 +static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
12522 + return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
12523 +} \
12524 +static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
12525 + DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
12526 + &(((uint32_t*)container->regs->_reg)[num]), data); \
12527 + DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
12528 +}
12529 +
12530 +#define dwc_define_read_write_reg(_reg,_container_type) \
12531 +static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
12532 + return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
12533 +} \
12534 +static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
12535 + DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
12536 + DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
12537 +}
12538 +
12539 +# else /* DWC_DEBUG_REGS */
12540 +
12541 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12542 +static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
12543 + return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
12544 +} \
12545 +static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
12546 + DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
12547 +}
12548 +
12549 +#define dwc_define_read_write_reg(_reg,_container_type) \
12550 +static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
12551 + return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
12552 +} \
12553 +static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
12554 + DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
12555 +}
12556 +
12557 +# endif /* DWC_DEBUG_REGS */
12558 +
12559 +#endif /* DWC_FREEBSD || DWC_NETBSD */
12560 +
12561 +/** @endcond */
12562 +
12563 +
12564 +#ifdef DWC_CRYPTOLIB
12565 +/** @name Crypto Functions
12566 + *
12567 + * These are the low-level cryptographic functions used by the driver. */
12568 +
12569 +/** Perform AES CBC */
12570 +extern int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out);
12571 +#define dwc_aes_cbc DWC_AES_CBC
12572 +
12573 +/** Fill the provided buffer with random bytes. These should be cryptographic grade random numbers. */
12574 +extern void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length);
12575 +#define dwc_random_bytes DWC_RANDOM_BYTES
12576 +
12577 +/** Perform the SHA-256 hash function */
12578 +extern int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out);
12579 +#define dwc_sha256 DWC_SHA256
12580 +
12581 +/** Calculated the HMAC-SHA256 */
12582 +extern int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t *out);
12583 +#define dwc_hmac_sha256 DWC_HMAC_SHA256
12584 +
12585 +#endif /* DWC_CRYPTOLIB */
12586 +
12587 +
12588 +/** @name Memory Allocation
12589 + *
12590 + * These function provide access to memory allocation. There are only 2 DMA
12591 + * functions and 3 Regular memory functions that need to be implemented. None
12592 + * of the memory debugging routines need to be implemented. The allocation
12593 + * routines all ZERO the contents of the memory.
12594 + *
12595 + * Defining DWC_DEBUG_MEMORY turns on memory debugging and statistic gathering.
12596 + * This checks for memory leaks, keeping track of alloc/free pairs. It also
12597 + * keeps track of how much memory the driver is using at any given time. */
12598 +
12599 +#define DWC_PAGE_SIZE 4096
12600 +#define DWC_PAGE_OFFSET(addr) (((uint32_t)addr) & 0xfff)
12601 +#define DWC_PAGE_ALIGNED(addr) ((((uint32_t)addr) & 0xfff) == 0)
12602 +
12603 +#define DWC_INVALID_DMA_ADDR 0x0
12604 +
12605 +#ifdef DWC_LINUX
12606 +/** Type for a DMA address */
12607 +typedef dma_addr_t dwc_dma_t;
12608 +#endif
12609 +
12610 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12611 +typedef bus_addr_t dwc_dma_t;
12612 +#endif
12613 +
12614 +#ifdef DWC_FREEBSD
12615 +typedef struct dwc_dmactx {
12616 + struct device *dev;
12617 + bus_dma_tag_t dma_tag;
12618 + bus_dmamap_t dma_map;
12619 + bus_addr_t dma_paddr;
12620 + void *dma_vaddr;
12621 +} dwc_dmactx_t;
12622 +#endif
12623 +
12624 +#ifdef DWC_NETBSD
12625 +typedef struct dwc_dmactx {
12626 + struct device *dev;
12627 + bus_dma_tag_t dma_tag;
12628 + bus_dmamap_t dma_map;
12629 + bus_dma_segment_t segs[1];
12630 + int nsegs;
12631 + bus_addr_t dma_paddr;
12632 + void *dma_vaddr;
12633 +} dwc_dmactx_t;
12634 +#endif
12635 +
12636 +/* @todo these functions will be added in the future */
12637 +#if 0
12638 +/**
12639 + * Creates a DMA pool from which you can allocate DMA buffers. Buffers
12640 + * allocated from this pool will be guaranteed to meet the size, alignment, and
12641 + * boundary requirements specified.
12642 + *
12643 + * @param[in] size Specifies the size of the buffers that will be allocated from
12644 + * this pool.
12645 + * @param[in] align Specifies the byte alignment requirements of the buffers
12646 + * allocated from this pool. Must be a power of 2.
12647 + * @param[in] boundary Specifies the N-byte boundary that buffers allocated from
12648 + * this pool must not cross.
12649 + *
12650 + * @returns A pointer to an internal opaque structure which is not to be
12651 + * accessed outside of these library functions. Use this handle to specify
12652 + * which pools to allocate/free DMA buffers from and also to destroy the pool,
12653 + * when you are done with it.
12654 + */
12655 +extern dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size, uint32_t align, uint32_t boundary);
12656 +
12657 +/**
12658 + * Destroy a DMA pool. All buffers allocated from that pool must be freed first.
12659 + */
12660 +extern void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool);
12661 +
12662 +/**
12663 + * Allocate a buffer from the specified DMA pool and zeros its contents.
12664 + */
12665 +extern void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr);
12666 +
12667 +/**
12668 + * Free a previously allocated buffer from the DMA pool.
12669 + */
12670 +extern void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr);
12671 +#endif
12672 +
12673 +/** Allocates a DMA capable buffer and zeroes its contents. */
12674 +extern void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
12675 +
12676 +/** Allocates a DMA capable buffer and zeroes its contents in atomic contest */
12677 +extern void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
12678 +
12679 +/** Frees a previously allocated buffer. */
12680 +extern void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr);
12681 +
12682 +/** Allocates a block of memory and zeroes its contents. */
12683 +extern void *__DWC_ALLOC(void *mem_ctx, uint32_t size);
12684 +
12685 +/** Allocates a block of memory and zeroes its contents, in an atomic manner
12686 + * which can be used inside interrupt context. The size should be sufficiently
12687 + * small, a few KB at most, such that failures are not likely to occur. Can just call
12688 + * __DWC_ALLOC if it is atomic. */
12689 +extern void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size);
12690 +
12691 +/** Frees a previously allocated buffer. */
12692 +extern void __DWC_FREE(void *mem_ctx, void *addr);
12693 +
12694 +#ifndef DWC_DEBUG_MEMORY
12695 +
12696 +#define DWC_ALLOC(_size_) __DWC_ALLOC(NULL, _size_)
12697 +#define DWC_ALLOC_ATOMIC(_size_) __DWC_ALLOC_ATOMIC(NULL, _size_)
12698 +#define DWC_FREE(_addr_) __DWC_FREE(NULL, _addr_)
12699 +
12700 +# ifdef DWC_LINUX
12701 +#define DWC_DMA_ALLOC(_size_,_dma_) __DWC_DMA_ALLOC(NULL, _size_, _dma_)
12702 +#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) __DWC_DMA_ALLOC_ATOMIC(NULL, _size_,_dma_)
12703 +#define DWC_DMA_FREE(_size_,_virt_,_dma_) __DWC_DMA_FREE(NULL, _size_, _virt_, _dma_)
12704 +# endif
12705 +
12706 +# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12707 +#define DWC_DMA_ALLOC __DWC_DMA_ALLOC
12708 +#define DWC_DMA_FREE __DWC_DMA_FREE
12709 +# endif
12710 +extern void *dwc_dma_alloc_atomic_debug(uint32_t size, dwc_dma_t *dma_addr, char const *func, int line);
12711 +
12712 +#else /* DWC_DEBUG_MEMORY */
12713 +
12714 +extern void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line);
12715 +extern void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func, int line);
12716 +extern void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line);
12717 +extern void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
12718 + char const *func, int line);
12719 +extern void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
12720 + char const *func, int line);
12721 +extern void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
12722 + dwc_dma_t dma_addr, char const *func, int line);
12723 +
12724 +extern int dwc_memory_debug_start(void *mem_ctx);
12725 +extern void dwc_memory_debug_stop(void);
12726 +extern void dwc_memory_debug_report(void);
12727 +
12728 +#define DWC_ALLOC(_size_) dwc_alloc_debug(NULL, _size_, __func__, __LINE__)
12729 +#define DWC_ALLOC_ATOMIC(_size_) dwc_alloc_atomic_debug(NULL, _size_, \
12730 + __func__, __LINE__)
12731 +#define DWC_FREE(_addr_) dwc_free_debug(NULL, _addr_, __func__, __LINE__)
12732 +
12733 +# ifdef DWC_LINUX
12734 +#define DWC_DMA_ALLOC(_size_,_dma_) dwc_dma_alloc_debug(NULL, _size_, \
12735 + _dma_, __func__, __LINE__)
12736 +#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) dwc_dma_alloc_atomic_debug(NULL, _size_, \
12737 + _dma_, __func__, __LINE__)
12738 +#define DWC_DMA_FREE(_size_,_virt_,_dma_) dwc_dma_free_debug(NULL, _size_, \
12739 + _virt_, _dma_, __func__, __LINE__)
12740 +# endif
12741 +
12742 +# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12743 +#define DWC_DMA_ALLOC(_ctx_,_size_,_dma_) dwc_dma_alloc_debug(_ctx_, _size_, \
12744 + _dma_, __func__, __LINE__)
12745 +#define DWC_DMA_FREE(_ctx_,_size_,_virt_,_dma_) dwc_dma_free_debug(_ctx_, _size_, \
12746 + _virt_, _dma_, __func__, __LINE__)
12747 +# endif
12748 +
12749 +#endif /* DWC_DEBUG_MEMORY */
12750 +
12751 +#define dwc_alloc(_ctx_,_size_) DWC_ALLOC(_size_)
12752 +#define dwc_alloc_atomic(_ctx_,_size_) DWC_ALLOC_ATOMIC(_size_)
12753 +#define dwc_free(_ctx_,_addr_) DWC_FREE(_addr_)
12754 +
12755 +#ifdef DWC_LINUX
12756 +/* Linux doesn't need any extra parameters for DMA buffer allocation, so we
12757 + * just throw away the DMA context parameter.
12758 + */
12759 +#define dwc_dma_alloc(_ctx_,_size_,_dma_) DWC_DMA_ALLOC(_size_, _dma_)
12760 +#define dwc_dma_alloc_atomic(_ctx_,_size_,_dma_) DWC_DMA_ALLOC_ATOMIC(_size_, _dma_)
12761 +#define dwc_dma_free(_ctx_,_size_,_virt_,_dma_) DWC_DMA_FREE(_size_, _virt_, _dma_)
12762 +#endif
12763 +
12764 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12765 +/** BSD needs several extra parameters for DMA buffer allocation, so we pass
12766 + * them in using the DMA context parameter.
12767 + */
12768 +#define dwc_dma_alloc DWC_DMA_ALLOC
12769 +#define dwc_dma_free DWC_DMA_FREE
12770 +#endif
12771 +
12772 +
12773 +/** @name Memory and String Processing */
12774 +
12775 +/** memset() clone */
12776 +extern void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size);
12777 +#define dwc_memset DWC_MEMSET
12778 +
12779 +/** memcpy() clone */
12780 +extern void *DWC_MEMCPY(void *dest, void const *src, uint32_t size);
12781 +#define dwc_memcpy DWC_MEMCPY
12782 +
12783 +/** memmove() clone */
12784 +extern void *DWC_MEMMOVE(void *dest, void *src, uint32_t size);
12785 +#define dwc_memmove DWC_MEMMOVE
12786 +
12787 +/** memcmp() clone */
12788 +extern int DWC_MEMCMP(void *m1, void *m2, uint32_t size);
12789 +#define dwc_memcmp DWC_MEMCMP
12790 +
12791 +/** strcmp() clone */
12792 +extern int DWC_STRCMP(void *s1, void *s2);
12793 +#define dwc_strcmp DWC_STRCMP
12794 +
12795 +/** strncmp() clone */
12796 +extern int DWC_STRNCMP(void *s1, void *s2, uint32_t size);
12797 +#define dwc_strncmp DWC_STRNCMP
12798 +
12799 +/** strlen() clone, for NULL terminated ASCII strings */
12800 +extern int DWC_STRLEN(char const *str);
12801 +#define dwc_strlen DWC_STRLEN
12802 +
12803 +/** strcpy() clone, for NULL terminated ASCII strings */
12804 +extern char *DWC_STRCPY(char *to, const char *from);
12805 +#define dwc_strcpy DWC_STRCPY
12806 +
12807 +/** strdup() clone. If you wish to use memory allocation debugging, this
12808 + * implementation of strdup should use the DWC_* memory routines instead of
12809 + * calling a predefined strdup. Otherwise the memory allocated by this routine
12810 + * will not be seen by the debugging routines. */
12811 +extern char *DWC_STRDUP(char const *str);
12812 +#define dwc_strdup(_ctx_,_str_) DWC_STRDUP(_str_)
12813 +
12814 +/** NOT an atoi() clone. Read the description carefully. Returns an integer
12815 + * converted from the string str in base 10 unless the string begins with a "0x"
12816 + * in which case it is base 16. String must be a NULL terminated sequence of
12817 + * ASCII characters and may optionally begin with whitespace, a + or -, and a
12818 + * "0x" prefix if base 16. The remaining characters must be valid digits for
12819 + * the number and end with a NULL character. If any invalid characters are
12820 + * encountered or it returns with a negative error code and the results of the
12821 + * conversion are undefined. On sucess it returns 0. Overflow conditions are
12822 + * undefined. An example implementation using atoi() can be referenced from the
12823 + * Linux implementation. */
12824 +extern int DWC_ATOI(const char *str, int32_t *value);
12825 +#define dwc_atoi DWC_ATOI
12826 +
12827 +/** Same as above but for unsigned. */
12828 +extern int DWC_ATOUI(const char *str, uint32_t *value);
12829 +#define dwc_atoui DWC_ATOUI
12830 +
12831 +#ifdef DWC_UTFLIB
12832 +/** This routine returns a UTF16LE unicode encoded string from a UTF8 string. */
12833 +extern int DWC_UTF8_TO_UTF16LE(uint8_t const *utf8string, uint16_t *utf16string, unsigned len);
12834 +#define dwc_utf8_to_utf16le DWC_UTF8_TO_UTF16LE
12835 +#endif
12836 +
12837 +
12838 +/** @name Wait queues
12839 + *
12840 + * Wait queues provide a means of synchronizing between threads or processes. A
12841 + * process can block on a waitq if some condition is not true, waiting for it to
12842 + * become true. When the waitq is triggered all waiting process will get
12843 + * unblocked and the condition will be check again. Waitqs should be triggered
12844 + * every time a condition can potentially change.*/
12845 +struct dwc_waitq;
12846 +
12847 +/** Type for a waitq */
12848 +typedef struct dwc_waitq dwc_waitq_t;
12849 +
12850 +/** The type of waitq condition callback function. This is called every time
12851 + * condition is evaluated. */
12852 +typedef int (*dwc_waitq_condition_t)(void *data);
12853 +
12854 +/** Allocate a waitq */
12855 +extern dwc_waitq_t *DWC_WAITQ_ALLOC(void);
12856 +#define dwc_waitq_alloc(_ctx_) DWC_WAITQ_ALLOC()
12857 +
12858 +/** Free a waitq */
12859 +extern void DWC_WAITQ_FREE(dwc_waitq_t *wq);
12860 +#define dwc_waitq_free DWC_WAITQ_FREE
12861 +
12862 +/** Check the condition and if it is false, block on the waitq. When unblocked, check the
12863 + * condition again. The function returns when the condition becomes true. The return value
12864 + * is 0 on condition true, DWC_WAITQ_ABORTED on abort or killed, or DWC_WAITQ_UNKNOWN on error. */
12865 +extern int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data);
12866 +#define dwc_waitq_wait DWC_WAITQ_WAIT
12867 +
12868 +/** Check the condition and if it is false, block on the waitq. When unblocked,
12869 + * check the condition again. The function returns when the condition become
12870 + * true or the timeout has passed. The return value is 0 on condition true or
12871 + * DWC_TIMED_OUT on timeout, or DWC_WAITQ_ABORTED, or DWC_WAITQ_UNKNOWN on
12872 + * error. */
12873 +extern int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
12874 + void *data, int32_t msecs);
12875 +#define dwc_waitq_wait_timeout DWC_WAITQ_WAIT_TIMEOUT
12876 +
12877 +/** Trigger a waitq, unblocking all processes. This should be called whenever a condition
12878 + * has potentially changed. */
12879 +extern void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq);
12880 +#define dwc_waitq_trigger DWC_WAITQ_TRIGGER
12881 +
12882 +/** Unblock all processes waiting on the waitq with an ABORTED result. */
12883 +extern void DWC_WAITQ_ABORT(dwc_waitq_t *wq);
12884 +#define dwc_waitq_abort DWC_WAITQ_ABORT
12885 +
12886 +
12887 +/** @name Threads
12888 + *
12889 + * A thread must be explicitly stopped. It must check DWC_THREAD_SHOULD_STOP
12890 + * whenever it is woken up, and then return. The DWC_THREAD_STOP function
12891 + * returns the value from the thread.
12892 + */
12893 +
12894 +struct dwc_thread;
12895 +
12896 +/** Type for a thread */
12897 +typedef struct dwc_thread dwc_thread_t;
12898 +
12899 +/** The thread function */
12900 +typedef int (*dwc_thread_function_t)(void *data);
12901 +
12902 +/** Create a thread and start it running the thread_function. Returns a handle
12903 + * to the thread */
12904 +extern dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data);
12905 +#define dwc_thread_run(_ctx_,_func_,_name_,_data_) DWC_THREAD_RUN(_func_, _name_, _data_)
12906 +
12907 +/** Stops a thread. Return the value returned by the thread. Or will return
12908 + * DWC_ABORT if the thread never started. */
12909 +extern int DWC_THREAD_STOP(dwc_thread_t *thread);
12910 +#define dwc_thread_stop DWC_THREAD_STOP
12911 +
12912 +/** Signifies to the thread that it must stop. */
12913 +#ifdef DWC_LINUX
12914 +/* Linux doesn't need any parameters for kthread_should_stop() */
12915 +extern dwc_bool_t DWC_THREAD_SHOULD_STOP(void);
12916 +#define dwc_thread_should_stop(_thrd_) DWC_THREAD_SHOULD_STOP()
12917 +
12918 +/* No thread_exit function in Linux */
12919 +#define dwc_thread_exit(_thrd_)
12920 +#endif
12921 +
12922 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12923 +/** BSD needs the thread pointer for kthread_suspend_check() */
12924 +extern dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread);
12925 +#define dwc_thread_should_stop DWC_THREAD_SHOULD_STOP
12926 +
12927 +/** The thread must call this to exit. */
12928 +extern void DWC_THREAD_EXIT(dwc_thread_t *thread);
12929 +#define dwc_thread_exit DWC_THREAD_EXIT
12930 +#endif
12931 +
12932 +
12933 +/** @name Work queues
12934 + *
12935 + * Workqs are used to queue a callback function to be called at some later time,
12936 + * in another thread. */
12937 +struct dwc_workq;
12938 +
12939 +/** Type for a workq */
12940 +typedef struct dwc_workq dwc_workq_t;
12941 +
12942 +/** The type of the callback function to be called. */
12943 +typedef void (*dwc_work_callback_t)(void *data);
12944 +
12945 +/** Allocate a workq */
12946 +extern dwc_workq_t *DWC_WORKQ_ALLOC(char *name);
12947 +#define dwc_workq_alloc(_ctx_,_name_) DWC_WORKQ_ALLOC(_name_)
12948 +
12949 +/** Free a workq. All work must be completed before being freed. */
12950 +extern void DWC_WORKQ_FREE(dwc_workq_t *workq);
12951 +#define dwc_workq_free DWC_WORKQ_FREE
12952 +
12953 +/** Schedule a callback on the workq, passing in data. The function will be
12954 + * scheduled at some later time. */
12955 +extern void DWC_WORKQ_SCHEDULE(dwc_workq_t *workq, dwc_work_callback_t cb,
12956 + void *data, char *format, ...)
12957 +#ifdef __GNUC__
12958 + __attribute__ ((format(printf, 4, 5)));
12959 +#else
12960 + ;
12961 +#endif
12962 +#define dwc_workq_schedule DWC_WORKQ_SCHEDULE
12963 +
12964 +/** Schedule a callback on the workq, that will be called until at least
12965 + * given number miliseconds have passed. */
12966 +extern void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *workq, dwc_work_callback_t cb,
12967 + void *data, uint32_t time, char *format, ...)
12968 +#ifdef __GNUC__
12969 + __attribute__ ((format(printf, 5, 6)));
12970 +#else
12971 + ;
12972 +#endif
12973 +#define dwc_workq_schedule_delayed DWC_WORKQ_SCHEDULE_DELAYED
12974 +
12975 +/** The number of processes in the workq */
12976 +extern int DWC_WORKQ_PENDING(dwc_workq_t *workq);
12977 +#define dwc_workq_pending DWC_WORKQ_PENDING
12978 +
12979 +/** Blocks until all the work in the workq is complete or timed out. Returns <
12980 + * 0 on timeout. */
12981 +extern int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout);
12982 +#define dwc_workq_wait_work_done DWC_WORKQ_WAIT_WORK_DONE
12983 +
12984 +
12985 +/** @name Tasklets
12986 + *
12987 + */
12988 +struct dwc_tasklet;
12989 +
12990 +/** Type for a tasklet */
12991 +typedef struct dwc_tasklet dwc_tasklet_t;
12992 +
12993 +/** The type of the callback function to be called */
12994 +typedef void (*dwc_tasklet_callback_t)(void *data);
12995 +
12996 +/** Allocates a tasklet */
12997 +extern dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data);
12998 +#define dwc_task_alloc(_ctx_,_name_,_cb_,_data_) DWC_TASK_ALLOC(_name_, _cb_, _data_)
12999 +
13000 +/** Frees a tasklet */
13001 +extern void DWC_TASK_FREE(dwc_tasklet_t *task);
13002 +#define dwc_task_free DWC_TASK_FREE
13003 +
13004 +/** Schedules a tasklet to run */
13005 +extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task);
13006 +#define dwc_task_schedule DWC_TASK_SCHEDULE
13007 +
13008 +extern void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task);
13009 +#define dwc_task_hi_schedule DWC_TASK_HI_SCHEDULE
13010 +
13011 +/** @name Timer
13012 + *
13013 + * Callbacks must be small and atomic.
13014 + */
13015 +struct dwc_timer;
13016 +
13017 +/** Type for a timer */
13018 +typedef struct dwc_timer dwc_timer_t;
13019 +
13020 +/** The type of the callback function to be called */
13021 +typedef void (*dwc_timer_callback_t)(void *data);
13022 +
13023 +/** Allocates a timer */
13024 +extern dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data);
13025 +#define dwc_timer_alloc(_ctx_,_name_,_cb_,_data_) DWC_TIMER_ALLOC(_name_,_cb_,_data_)
13026 +
13027 +/** Frees a timer */
13028 +extern void DWC_TIMER_FREE(dwc_timer_t *timer);
13029 +#define dwc_timer_free DWC_TIMER_FREE
13030 +
13031 +/** Schedules the timer to run at time ms from now. And will repeat at every
13032 + * repeat_interval msec therafter
13033 + *
13034 + * Modifies a timer that is still awaiting execution to a new expiration time.
13035 + * The mod_time is added to the old time. */
13036 +extern void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time);
13037 +#define dwc_timer_schedule DWC_TIMER_SCHEDULE
13038 +
13039 +/** Disables the timer from execution. */
13040 +extern void DWC_TIMER_CANCEL(dwc_timer_t *timer);
13041 +#define dwc_timer_cancel DWC_TIMER_CANCEL
13042 +
13043 +
13044 +/** @name Spinlocks
13045 + *
13046 + * These locks are used when the work between the lock/unlock is atomic and
13047 + * short. Interrupts are also disabled during the lock/unlock and thus they are
13048 + * suitable to lock between interrupt/non-interrupt context. They also lock
13049 + * between processes if you have multiple CPUs or Preemption. If you don't have
13050 + * multiple CPUS or Preemption, then the you can simply implement the
13051 + * DWC_SPINLOCK and DWC_SPINUNLOCK to disable and enable interrupts. Because
13052 + * the work between the lock/unlock is atomic, the process context will never
13053 + * change, and so you never have to lock between processes. */
13054 +
13055 +struct dwc_spinlock;
13056 +
13057 +/** Type for a spinlock */
13058 +typedef struct dwc_spinlock dwc_spinlock_t;
13059 +
13060 +/** Type for the 'flags' argument to spinlock funtions */
13061 +typedef unsigned long dwc_irqflags_t;
13062 +
13063 +/** Returns an initialized lock variable. This function should allocate and
13064 + * initialize the OS-specific data structure used for locking. This data
13065 + * structure is to be used for the DWC_LOCK and DWC_UNLOCK functions and should
13066 + * be freed by the DWC_FREE_LOCK when it is no longer used. */
13067 +extern dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void);
13068 +#define dwc_spinlock_alloc(_ctx_) DWC_SPINLOCK_ALLOC()
13069 +
13070 +/** Frees an initialized lock variable. */
13071 +extern void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock);
13072 +#define dwc_spinlock_free(_ctx_,_lock_) DWC_SPINLOCK_FREE(_lock_)
13073 +
13074 +/** Disables interrupts and blocks until it acquires the lock.
13075 + *
13076 + * @param lock Pointer to the spinlock.
13077 + * @param flags Unsigned long for irq flags storage.
13078 + */
13079 +extern void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags);
13080 +#define dwc_spinlock_irqsave DWC_SPINLOCK_IRQSAVE
13081 +
13082 +/** Re-enables the interrupt and releases the lock.
13083 + *
13084 + * @param lock Pointer to the spinlock.
13085 + * @param flags Unsigned long for irq flags storage. Must be the same as was
13086 + * passed into DWC_LOCK.
13087 + */
13088 +extern void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags);
13089 +#define dwc_spinunlock_irqrestore DWC_SPINUNLOCK_IRQRESTORE
13090 +
13091 +/** Blocks until it acquires the lock.
13092 + *
13093 + * @param lock Pointer to the spinlock.
13094 + */
13095 +extern void DWC_SPINLOCK(dwc_spinlock_t *lock);
13096 +#define dwc_spinlock DWC_SPINLOCK
13097 +
13098 +/** Releases the lock.
13099 + *
13100 + * @param lock Pointer to the spinlock.
13101 + */
13102 +extern void DWC_SPINUNLOCK(dwc_spinlock_t *lock);
13103 +#define dwc_spinunlock DWC_SPINUNLOCK
13104 +
13105 +
13106 +/** @name Mutexes
13107 + *
13108 + * Unlike spinlocks Mutexes lock only between processes and the work between the
13109 + * lock/unlock CAN block, therefore it CANNOT be called from interrupt context.
13110 + */
13111 +
13112 +struct dwc_mutex;
13113 +
13114 +/** Type for a mutex */
13115 +typedef struct dwc_mutex dwc_mutex_t;
13116 +
13117 +/* For Linux Mutex Debugging make it inline because the debugging routines use
13118 + * the symbol to determine recursive locking. This makes it falsely think
13119 + * recursive locking occurs. */
13120 +#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
13121 +#define DWC_MUTEX_ALLOC_LINUX_DEBUG(__mutexp) ({ \
13122 + __mutexp = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex)); \
13123 + mutex_init((struct mutex *)__mutexp); \
13124 +})
13125 +#endif
13126 +
13127 +/** Allocate a mutex */
13128 +extern dwc_mutex_t *DWC_MUTEX_ALLOC(void);
13129 +#define dwc_mutex_alloc(_ctx_) DWC_MUTEX_ALLOC()
13130 +
13131 +/* For memory leak debugging when using Linux Mutex Debugging */
13132 +#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
13133 +#define DWC_MUTEX_FREE(__mutexp) do { \
13134 + mutex_destroy((struct mutex *)__mutexp); \
13135 + DWC_FREE(__mutexp); \
13136 +} while(0)
13137 +#else
13138 +/** Free a mutex */
13139 +extern void DWC_MUTEX_FREE(dwc_mutex_t *mutex);
13140 +#define dwc_mutex_free(_ctx_,_mutex_) DWC_MUTEX_FREE(_mutex_)
13141 +#endif
13142 +
13143 +/** Lock a mutex */
13144 +extern void DWC_MUTEX_LOCK(dwc_mutex_t *mutex);
13145 +#define dwc_mutex_lock DWC_MUTEX_LOCK
13146 +
13147 +/** Non-blocking lock returns 1 on successful lock. */
13148 +extern int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex);
13149 +#define dwc_mutex_trylock DWC_MUTEX_TRYLOCK
13150 +
13151 +/** Unlock a mutex */
13152 +extern void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex);
13153 +#define dwc_mutex_unlock DWC_MUTEX_UNLOCK
13154 +
13155 +
13156 +/** @name Time */
13157 +
13158 +/** Microsecond delay.
13159 + *
13160 + * @param usecs Microseconds to delay.
13161 + */
13162 +extern void DWC_UDELAY(uint32_t usecs);
13163 +#define dwc_udelay DWC_UDELAY
13164 +
13165 +/** Millisecond delay.
13166 + *
13167 + * @param msecs Milliseconds to delay.
13168 + */
13169 +extern void DWC_MDELAY(uint32_t msecs);
13170 +#define dwc_mdelay DWC_MDELAY
13171 +
13172 +/** Non-busy waiting.
13173 + * Sleeps for specified number of milliseconds.
13174 + *
13175 + * @param msecs Milliseconds to sleep.
13176 + */
13177 +extern void DWC_MSLEEP(uint32_t msecs);
13178 +#define dwc_msleep DWC_MSLEEP
13179 +
13180 +/**
13181 + * Returns number of milliseconds since boot.
13182 + */
13183 +extern uint32_t DWC_TIME(void);
13184 +#define dwc_time DWC_TIME
13185 +
13186 +
13187 +
13188 +
13189 +/* @mainpage DWC Portability and Common Library
13190 + *
13191 + * This is the documentation for the DWC Portability and Common Library.
13192 + *
13193 + * @section intro Introduction
13194 + *
13195 + * The DWC Portability library consists of wrapper calls and data structures to
13196 + * all low-level functions which are typically provided by the OS. The WUDEV
13197 + * driver uses only these functions. In order to port the WUDEV driver, only
13198 + * the functions in this library need to be re-implemented, with the same
13199 + * behavior as documented here.
13200 + *
13201 + * The Common library consists of higher level functions, which rely only on
13202 + * calling the functions from the DWC Portability library. These common
13203 + * routines are shared across modules. Some of the common libraries need to be
13204 + * used directly by the driver programmer when porting WUDEV. Such as the
13205 + * parameter and notification libraries.
13206 + *
13207 + * @section low Portability Library OS Wrapper Functions
13208 + *
13209 + * Any function starting with DWC and in all CAPS is a low-level OS-wrapper that
13210 + * needs to be implemented when porting, for example DWC_MUTEX_ALLOC(). All of
13211 + * these functions are included in the dwc_os.h file.
13212 + *
13213 + * There are many functions here covering a wide array of OS services. Please
13214 + * see dwc_os.h for details, and implementation notes for each function.
13215 + *
13216 + * @section common Common Library Functions
13217 + *
13218 + * Any function starting with dwc and in all lowercase is a common library
13219 + * routine. These functions have a portable implementation and do not need to
13220 + * be reimplemented when porting. The common routines can be used by any
13221 + * driver, and some must be used by the end user to control the drivers. For
13222 + * example, you must use the Parameter common library in order to set the
13223 + * parameters in the WUDEV module.
13224 + *
13225 + * The common libraries consist of the following:
13226 + *
13227 + * - Connection Contexts - Used internally and can be used by end-user. See dwc_cc.h
13228 + * - Parameters - Used internally and can be used by end-user. See dwc_params.h
13229 + * - Notifications - Used internally and can be used by end-user. See dwc_notifier.h
13230 + * - Lists - Used internally and can be used by end-user. See dwc_list.h
13231 + * - Memory Debugging - Used internally and can be used by end-user. See dwc_os.h
13232 + * - Modpow - Used internally only. See dwc_modpow.h
13233 + * - DH - Used internally only. See dwc_dh.h
13234 + * - Crypto - Used internally only. See dwc_crypto.h
13235 + *
13236 + *
13237 + * @section prereq Prerequistes For dwc_os.h
13238 + * @subsection types Data Types
13239 + *
13240 + * The dwc_os.h file assumes that several low-level data types are pre defined for the
13241 + * compilation environment. These data types are:
13242 + *
13243 + * - uint8_t - unsigned 8-bit data type
13244 + * - int8_t - signed 8-bit data type
13245 + * - uint16_t - unsigned 16-bit data type
13246 + * - int16_t - signed 16-bit data type
13247 + * - uint32_t - unsigned 32-bit data type
13248 + * - int32_t - signed 32-bit data type
13249 + * - uint64_t - unsigned 64-bit data type
13250 + * - int64_t - signed 64-bit data type
13251 + *
13252 + * Ensure that these are defined before using dwc_os.h. The easiest way to do
13253 + * that is to modify the top of the file to include the appropriate header.
13254 + * This is already done for the Linux environment. If the DWC_LINUX macro is
13255 + * defined, the correct header will be added. A standard header <stdint.h> is
13256 + * also used for environments where standard C headers are available.
13257 + *
13258 + * @subsection stdarg Variable Arguments
13259 + *
13260 + * Variable arguments are provided by a standard C header <stdarg.h>. it is
13261 + * available in Both the Linux and ANSI C enviornment. An equivalent must be
13262 + * provided in your enviornment in order to use dwc_os.h with the debug and
13263 + * tracing message functionality.
13264 + *
13265 + * @subsection thread Threading
13266 + *
13267 + * WUDEV Core must be run on an operating system that provides for multiple
13268 + * threads/processes. Threading can be implemented in many ways, even in
13269 + * embedded systems without an operating system. At the bare minimum, the
13270 + * system should be able to start any number of processes at any time to handle
13271 + * special work. It need not be a pre-emptive system. Process context can
13272 + * change upon a call to a blocking function. The hardware interrupt context
13273 + * that calls the module's ISR() function must be differentiable from process
13274 + * context, even if your processes are impemented via a hardware interrupt.
13275 + * Further locking mechanism between process must exist (or be implemented), and
13276 + * process context must have a way to disable interrupts for a period of time to
13277 + * lock them out. If all of this exists, the functions in dwc_os.h related to
13278 + * threading should be able to be implemented with the defined behavior.
13279 + *
13280 + */
13281 +
13282 +#ifdef __cplusplus
13283 +}
13284 +#endif
13285 +
13286 +#endif /* _DWC_OS_H_ */
13287 --- /dev/null
13288 +++ b/drivers/usb/host/dwc_common_port/Makefile
13289 @@ -0,0 +1,58 @@
13290 +#
13291 +# Makefile for DWC_common library
13292 +#
13293 +
13294 +ifneq ($(KERNELRELEASE),)
13295 +
13296 +EXTRA_CFLAGS += -DDWC_LINUX
13297 +#EXTRA_CFLAGS += -DDEBUG
13298 +#EXTRA_CFLAGS += -DDWC_DEBUG_REGS
13299 +#EXTRA_CFLAGS += -DDWC_DEBUG_MEMORY
13300 +
13301 +EXTRA_CFLAGS += -DDWC_LIBMODULE
13302 +EXTRA_CFLAGS += -DDWC_CCLIB
13303 +#EXTRA_CFLAGS += -DDWC_CRYPTOLIB
13304 +EXTRA_CFLAGS += -DDWC_NOTIFYLIB
13305 +EXTRA_CFLAGS += -DDWC_UTFLIB
13306 +
13307 +obj-$(CONFIG_USB_DWCOTG) += dwc_common_port_lib.o
13308 +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
13309 + dwc_crypto.o dwc_notifier.o \
13310 + dwc_common_linux.o dwc_mem.o
13311 +
13312 +kernrelwd := $(subst ., ,$(KERNELRELEASE))
13313 +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
13314 +
13315 +ifneq ($(kernrel3),2.6.20)
13316 +# grayg - I only know that we use EXTRA_CFLAGS in 2.6.31 actually
13317 +EXTRA_CFLAGS += $(CPPFLAGS)
13318 +endif
13319 +
13320 +else
13321 +
13322 +#ifeq ($(KDIR),)
13323 +#$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
13324 +#endif
13325 +
13326 +ifeq ($(ARCH),)
13327 +$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
13328 + cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
13329 +endif
13330 +
13331 +ifeq ($(DOXYGEN),)
13332 +DOXYGEN := doxygen
13333 +endif
13334 +
13335 +default:
13336 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
13337 +
13338 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
13339 + $(DOXYGEN) doc/doxygen.cfg
13340 +
13341 +tags: $(wildcard *.[hc])
13342 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
13343 +
13344 +endif
13345 +
13346 +clean:
13347 + rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
13348 --- /dev/null
13349 +++ b/drivers/usb/host/dwc_common_port/Makefile.fbsd
13350 @@ -0,0 +1,17 @@
13351 +CFLAGS += -I/sys/i386/compile/GENERIC -I/sys/i386/include -I/usr/include
13352 +CFLAGS += -DDWC_FREEBSD
13353 +CFLAGS += -DDEBUG
13354 +#CFLAGS += -DDWC_DEBUG_REGS
13355 +#CFLAGS += -DDWC_DEBUG_MEMORY
13356 +
13357 +#CFLAGS += -DDWC_LIBMODULE
13358 +#CFLAGS += -DDWC_CCLIB
13359 +#CFLAGS += -DDWC_CRYPTOLIB
13360 +#CFLAGS += -DDWC_NOTIFYLIB
13361 +#CFLAGS += -DDWC_UTFLIB
13362 +
13363 +KMOD = dwc_common_port_lib
13364 +SRCS = dwc_cc.c dwc_modpow.c dwc_dh.c dwc_crypto.c dwc_notifier.c \
13365 + dwc_common_fbsd.c dwc_mem.c
13366 +
13367 +.include <bsd.kmod.mk>
13368 --- /dev/null
13369 +++ b/drivers/usb/host/dwc_common_port/Makefile.linux
13370 @@ -0,0 +1,49 @@
13371 +#
13372 +# Makefile for DWC_common library
13373 +#
13374 +ifneq ($(KERNELRELEASE),)
13375 +
13376 +EXTRA_CFLAGS += -DDWC_LINUX
13377 +#EXTRA_CFLAGS += -DDEBUG
13378 +#EXTRA_CFLAGS += -DDWC_DEBUG_REGS
13379 +#EXTRA_CFLAGS += -DDWC_DEBUG_MEMORY
13380 +
13381 +EXTRA_CFLAGS += -DDWC_LIBMODULE
13382 +EXTRA_CFLAGS += -DDWC_CCLIB
13383 +EXTRA_CFLAGS += -DDWC_CRYPTOLIB
13384 +EXTRA_CFLAGS += -DDWC_NOTIFYLIB
13385 +EXTRA_CFLAGS += -DDWC_UTFLIB
13386 +
13387 +obj-m := dwc_common_port_lib.o
13388 +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
13389 + dwc_crypto.o dwc_notifier.o \
13390 + dwc_common_linux.o dwc_mem.o
13391 +
13392 +else
13393 +
13394 +ifeq ($(KDIR),)
13395 +$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
13396 +endif
13397 +
13398 +ifeq ($(ARCH),)
13399 +$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
13400 + cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
13401 +endif
13402 +
13403 +ifeq ($(DOXYGEN),)
13404 +DOXYGEN := doxygen
13405 +endif
13406 +
13407 +default:
13408 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
13409 +
13410 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
13411 + $(DOXYGEN) doc/doxygen.cfg
13412 +
13413 +tags: $(wildcard *.[hc])
13414 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
13415 +
13416 +endif
13417 +
13418 +clean:
13419 + rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
13420 --- /dev/null
13421 +++ b/drivers/usb/host/dwc_common_port/usb.h
13422 @@ -0,0 +1,946 @@
13423 +/*
13424 + * Copyright (c) 1998 The NetBSD Foundation, Inc.
13425 + * All rights reserved.
13426 + *
13427 + * This code is derived from software contributed to The NetBSD Foundation
13428 + * by Lennart Augustsson (lennart@augustsson.net) at
13429 + * Carlstedt Research & Technology.
13430 + *
13431 + * Redistribution and use in source and binary forms, with or without
13432 + * modification, are permitted provided that the following conditions
13433 + * are met:
13434 + * 1. Redistributions of source code must retain the above copyright
13435 + * notice, this list of conditions and the following disclaimer.
13436 + * 2. Redistributions in binary form must reproduce the above copyright
13437 + * notice, this list of conditions and the following disclaimer in the
13438 + * documentation and/or other materials provided with the distribution.
13439 + * 3. All advertising materials mentioning features or use of this software
13440 + * must display the following acknowledgement:
13441 + * This product includes software developed by the NetBSD
13442 + * Foundation, Inc. and its contributors.
13443 + * 4. Neither the name of The NetBSD Foundation nor the names of its
13444 + * contributors may be used to endorse or promote products derived
13445 + * from this software without specific prior written permission.
13446 + *
13447 + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
13448 + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
13449 + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
13450 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
13451 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
13452 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
13453 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
13454 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
13455 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
13456 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
13457 + * POSSIBILITY OF SUCH DAMAGE.
13458 + */
13459 +
13460 +/* Modified by Synopsys, Inc, 12/12/2007 */
13461 +
13462 +
13463 +#ifndef _USB_H_
13464 +#define _USB_H_
13465 +
13466 +#ifdef __cplusplus
13467 +extern "C" {
13468 +#endif
13469 +
13470 +/*
13471 + * The USB records contain some unaligned little-endian word
13472 + * components. The U[SG]ETW macros take care of both the alignment
13473 + * and endian problem and should always be used to access non-byte
13474 + * values.
13475 + */
13476 +typedef u_int8_t uByte;
13477 +typedef u_int8_t uWord[2];
13478 +typedef u_int8_t uDWord[4];
13479 +
13480 +#define USETW2(w,h,l) ((w)[0] = (u_int8_t)(l), (w)[1] = (u_int8_t)(h))
13481 +#define UCONSTW(x) { (x) & 0xff, ((x) >> 8) & 0xff }
13482 +#define UCONSTDW(x) { (x) & 0xff, ((x) >> 8) & 0xff, \
13483 + ((x) >> 16) & 0xff, ((x) >> 24) & 0xff }
13484 +
13485 +#if 1
13486 +#define UGETW(w) ((w)[0] | ((w)[1] << 8))
13487 +#define USETW(w,v) ((w)[0] = (u_int8_t)(v), (w)[1] = (u_int8_t)((v) >> 8))
13488 +#define UGETDW(w) ((w)[0] | ((w)[1] << 8) | ((w)[2] << 16) | ((w)[3] << 24))
13489 +#define USETDW(w,v) ((w)[0] = (u_int8_t)(v), \
13490 + (w)[1] = (u_int8_t)((v) >> 8), \
13491 + (w)[2] = (u_int8_t)((v) >> 16), \
13492 + (w)[3] = (u_int8_t)((v) >> 24))
13493 +#else
13494 +/*
13495 + * On little-endian machines that can handle unanliged accesses
13496 + * (e.g. i386) these macros can be replaced by the following.
13497 + */
13498 +#define UGETW(w) (*(u_int16_t *)(w))
13499 +#define USETW(w,v) (*(u_int16_t *)(w) = (v))
13500 +#define UGETDW(w) (*(u_int32_t *)(w))
13501 +#define USETDW(w,v) (*(u_int32_t *)(w) = (v))
13502 +#endif
13503 +
13504 +/*
13505 + * Macros for accessing UAS IU fields, which are big-endian
13506 + */
13507 +#define IUSETW2(w,h,l) ((w)[0] = (u_int8_t)(h), (w)[1] = (u_int8_t)(l))
13508 +#define IUCONSTW(x) { ((x) >> 8) & 0xff, (x) & 0xff }
13509 +#define IUCONSTDW(x) { ((x) >> 24) & 0xff, ((x) >> 16) & 0xff, \
13510 + ((x) >> 8) & 0xff, (x) & 0xff }
13511 +#define IUGETW(w) (((w)[0] << 8) | (w)[1])
13512 +#define IUSETW(w,v) ((w)[0] = (u_int8_t)((v) >> 8), (w)[1] = (u_int8_t)(v))
13513 +#define IUGETDW(w) (((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3])
13514 +#define IUSETDW(w,v) ((w)[0] = (u_int8_t)((v) >> 24), \
13515 + (w)[1] = (u_int8_t)((v) >> 16), \
13516 + (w)[2] = (u_int8_t)((v) >> 8), \
13517 + (w)[3] = (u_int8_t)(v))
13518 +
13519 +#define UPACKED __attribute__((__packed__))
13520 +
13521 +typedef struct {
13522 + uByte bmRequestType;
13523 + uByte bRequest;
13524 + uWord wValue;
13525 + uWord wIndex;
13526 + uWord wLength;
13527 +} UPACKED usb_device_request_t;
13528 +
13529 +#define UT_GET_DIR(a) ((a) & 0x80)
13530 +#define UT_WRITE 0x00
13531 +#define UT_READ 0x80
13532 +
13533 +#define UT_GET_TYPE(a) ((a) & 0x60)
13534 +#define UT_STANDARD 0x00
13535 +#define UT_CLASS 0x20
13536 +#define UT_VENDOR 0x40
13537 +
13538 +#define UT_GET_RECIPIENT(a) ((a) & 0x1f)
13539 +#define UT_DEVICE 0x00
13540 +#define UT_INTERFACE 0x01
13541 +#define UT_ENDPOINT 0x02
13542 +#define UT_OTHER 0x03
13543 +
13544 +#define UT_READ_DEVICE (UT_READ | UT_STANDARD | UT_DEVICE)
13545 +#define UT_READ_INTERFACE (UT_READ | UT_STANDARD | UT_INTERFACE)
13546 +#define UT_READ_ENDPOINT (UT_READ | UT_STANDARD | UT_ENDPOINT)
13547 +#define UT_WRITE_DEVICE (UT_WRITE | UT_STANDARD | UT_DEVICE)
13548 +#define UT_WRITE_INTERFACE (UT_WRITE | UT_STANDARD | UT_INTERFACE)
13549 +#define UT_WRITE_ENDPOINT (UT_WRITE | UT_STANDARD | UT_ENDPOINT)
13550 +#define UT_READ_CLASS_DEVICE (UT_READ | UT_CLASS | UT_DEVICE)
13551 +#define UT_READ_CLASS_INTERFACE (UT_READ | UT_CLASS | UT_INTERFACE)
13552 +#define UT_READ_CLASS_OTHER (UT_READ | UT_CLASS | UT_OTHER)
13553 +#define UT_READ_CLASS_ENDPOINT (UT_READ | UT_CLASS | UT_ENDPOINT)
13554 +#define UT_WRITE_CLASS_DEVICE (UT_WRITE | UT_CLASS | UT_DEVICE)
13555 +#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE)
13556 +#define UT_WRITE_CLASS_OTHER (UT_WRITE | UT_CLASS | UT_OTHER)
13557 +#define UT_WRITE_CLASS_ENDPOINT (UT_WRITE | UT_CLASS | UT_ENDPOINT)
13558 +#define UT_READ_VENDOR_DEVICE (UT_READ | UT_VENDOR | UT_DEVICE)
13559 +#define UT_READ_VENDOR_INTERFACE (UT_READ | UT_VENDOR | UT_INTERFACE)
13560 +#define UT_READ_VENDOR_OTHER (UT_READ | UT_VENDOR | UT_OTHER)
13561 +#define UT_READ_VENDOR_ENDPOINT (UT_READ | UT_VENDOR | UT_ENDPOINT)
13562 +#define UT_WRITE_VENDOR_DEVICE (UT_WRITE | UT_VENDOR | UT_DEVICE)
13563 +#define UT_WRITE_VENDOR_INTERFACE (UT_WRITE | UT_VENDOR | UT_INTERFACE)
13564 +#define UT_WRITE_VENDOR_OTHER (UT_WRITE | UT_VENDOR | UT_OTHER)
13565 +#define UT_WRITE_VENDOR_ENDPOINT (UT_WRITE | UT_VENDOR | UT_ENDPOINT)
13566 +
13567 +/* Requests */
13568 +#define UR_GET_STATUS 0x00
13569 +#define USTAT_STANDARD_STATUS 0x00
13570 +#define WUSTAT_WUSB_FEATURE 0x01
13571 +#define WUSTAT_CHANNEL_INFO 0x02
13572 +#define WUSTAT_RECEIVED_DATA 0x03
13573 +#define WUSTAT_MAS_AVAILABILITY 0x04
13574 +#define WUSTAT_CURRENT_TRANSMIT_POWER 0x05
13575 +#define UR_CLEAR_FEATURE 0x01
13576 +#define UR_SET_FEATURE 0x03
13577 +#define UR_SET_AND_TEST_FEATURE 0x0c
13578 +#define UR_SET_ADDRESS 0x05
13579 +#define UR_GET_DESCRIPTOR 0x06
13580 +#define UDESC_DEVICE 0x01
13581 +#define UDESC_CONFIG 0x02
13582 +#define UDESC_STRING 0x03
13583 +#define UDESC_INTERFACE 0x04
13584 +#define UDESC_ENDPOINT 0x05
13585 +#define UDESC_SS_USB_COMPANION 0x30
13586 +#define UDESC_DEVICE_QUALIFIER 0x06
13587 +#define UDESC_OTHER_SPEED_CONFIGURATION 0x07
13588 +#define UDESC_INTERFACE_POWER 0x08
13589 +#define UDESC_OTG 0x09
13590 +#define WUDESC_SECURITY 0x0c
13591 +#define WUDESC_KEY 0x0d
13592 +#define WUD_GET_KEY_INDEX(_wValue_) ((_wValue_) & 0xf)
13593 +#define WUD_GET_KEY_TYPE(_wValue_) (((_wValue_) & 0x30) >> 4)
13594 +#define WUD_KEY_TYPE_ASSOC 0x01
13595 +#define WUD_KEY_TYPE_GTK 0x02
13596 +#define WUD_GET_KEY_ORIGIN(_wValue_) (((_wValue_) & 0x40) >> 6)
13597 +#define WUD_KEY_ORIGIN_HOST 0x00
13598 +#define WUD_KEY_ORIGIN_DEVICE 0x01
13599 +#define WUDESC_ENCRYPTION_TYPE 0x0e
13600 +#define WUDESC_BOS 0x0f
13601 +#define WUDESC_DEVICE_CAPABILITY 0x10
13602 +#define WUDESC_WIRELESS_ENDPOINT_COMPANION 0x11
13603 +#define UDESC_BOS 0x0f
13604 +#define UDESC_DEVICE_CAPABILITY 0x10
13605 +#define UDESC_CS_DEVICE 0x21 /* class specific */
13606 +#define UDESC_CS_CONFIG 0x22
13607 +#define UDESC_CS_STRING 0x23
13608 +#define UDESC_CS_INTERFACE 0x24
13609 +#define UDESC_CS_ENDPOINT 0x25
13610 +#define UDESC_HUB 0x29
13611 +#define UR_SET_DESCRIPTOR 0x07
13612 +#define UR_GET_CONFIG 0x08
13613 +#define UR_SET_CONFIG 0x09
13614 +#define UR_GET_INTERFACE 0x0a
13615 +#define UR_SET_INTERFACE 0x0b
13616 +#define UR_SYNCH_FRAME 0x0c
13617 +#define WUR_SET_ENCRYPTION 0x0d
13618 +#define WUR_GET_ENCRYPTION 0x0e
13619 +#define WUR_SET_HANDSHAKE 0x0f
13620 +#define WUR_GET_HANDSHAKE 0x10
13621 +#define WUR_SET_CONNECTION 0x11
13622 +#define WUR_SET_SECURITY_DATA 0x12
13623 +#define WUR_GET_SECURITY_DATA 0x13
13624 +#define WUR_SET_WUSB_DATA 0x14
13625 +#define WUDATA_DRPIE_INFO 0x01
13626 +#define WUDATA_TRANSMIT_DATA 0x02
13627 +#define WUDATA_TRANSMIT_PARAMS 0x03
13628 +#define WUDATA_RECEIVE_PARAMS 0x04
13629 +#define WUDATA_TRANSMIT_POWER 0x05
13630 +#define WUR_LOOPBACK_DATA_WRITE 0x15
13631 +#define WUR_LOOPBACK_DATA_READ 0x16
13632 +#define WUR_SET_INTERFACE_DS 0x17
13633 +
13634 +/* Feature numbers */
13635 +#define UF_ENDPOINT_HALT 0
13636 +#define UF_DEVICE_REMOTE_WAKEUP 1
13637 +#define UF_TEST_MODE 2
13638 +#define UF_DEVICE_B_HNP_ENABLE 3
13639 +#define UF_DEVICE_A_HNP_SUPPORT 4
13640 +#define UF_DEVICE_A_ALT_HNP_SUPPORT 5
13641 +#define WUF_WUSB 3
13642 +#define WUF_TX_DRPIE 0x0
13643 +#define WUF_DEV_XMIT_PACKET 0x1
13644 +#define WUF_COUNT_PACKETS 0x2
13645 +#define WUF_CAPTURE_PACKETS 0x3
13646 +#define UF_FUNCTION_SUSPEND 0
13647 +#define UF_U1_ENABLE 48
13648 +#define UF_U2_ENABLE 49
13649 +#define UF_LTM_ENABLE 50
13650 +
13651 +/* Class requests from the USB 2.0 hub spec, table 11-15 */
13652 +#define UCR_CLEAR_HUB_FEATURE (0x2000 | UR_CLEAR_FEATURE)
13653 +#define UCR_CLEAR_PORT_FEATURE (0x2300 | UR_CLEAR_FEATURE)
13654 +#define UCR_GET_HUB_DESCRIPTOR (0xa000 | UR_GET_DESCRIPTOR)
13655 +#define UCR_GET_HUB_STATUS (0xa000 | UR_GET_STATUS)
13656 +#define UCR_GET_PORT_STATUS (0xa300 | UR_GET_STATUS)
13657 +#define UCR_SET_HUB_FEATURE (0x2000 | UR_SET_FEATURE)
13658 +#define UCR_SET_PORT_FEATURE (0x2300 | UR_SET_FEATURE)
13659 +#define UCR_SET_AND_TEST_PORT_FEATURE (0xa300 | UR_SET_AND_TEST_FEATURE)
13660 +
13661 +#ifdef _MSC_VER
13662 +#include <pshpack1.h>
13663 +#endif
13664 +
13665 +typedef struct {
13666 + uByte bLength;
13667 + uByte bDescriptorType;
13668 + uByte bDescriptorSubtype;
13669 +} UPACKED usb_descriptor_t;
13670 +
13671 +typedef struct {
13672 + uByte bLength;
13673 + uByte bDescriptorType;
13674 +} UPACKED usb_descriptor_header_t;
13675 +
13676 +typedef struct {
13677 + uByte bLength;
13678 + uByte bDescriptorType;
13679 + uWord bcdUSB;
13680 +#define UD_USB_2_0 0x0200
13681 +#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
13682 + uByte bDeviceClass;
13683 + uByte bDeviceSubClass;
13684 + uByte bDeviceProtocol;
13685 + uByte bMaxPacketSize;
13686 + /* The fields below are not part of the initial descriptor. */
13687 + uWord idVendor;
13688 + uWord idProduct;
13689 + uWord bcdDevice;
13690 + uByte iManufacturer;
13691 + uByte iProduct;
13692 + uByte iSerialNumber;
13693 + uByte bNumConfigurations;
13694 +} UPACKED usb_device_descriptor_t;
13695 +#define USB_DEVICE_DESCRIPTOR_SIZE 18
13696 +
13697 +typedef struct {
13698 + uByte bLength;
13699 + uByte bDescriptorType;
13700 + uWord wTotalLength;
13701 + uByte bNumInterface;
13702 + uByte bConfigurationValue;
13703 + uByte iConfiguration;
13704 +#define UC_ATT_ONE (1 << 7) /* must be set */
13705 +#define UC_ATT_SELFPOWER (1 << 6) /* self powered */
13706 +#define UC_ATT_WAKEUP (1 << 5) /* can wakeup */
13707 +#define UC_ATT_BATTERY (1 << 4) /* battery powered */
13708 + uByte bmAttributes;
13709 +#define UC_BUS_POWERED 0x80
13710 +#define UC_SELF_POWERED 0x40
13711 +#define UC_REMOTE_WAKEUP 0x20
13712 + uByte bMaxPower; /* max current in 2 mA units */
13713 +#define UC_POWER_FACTOR 2
13714 +} UPACKED usb_config_descriptor_t;
13715 +#define USB_CONFIG_DESCRIPTOR_SIZE 9
13716 +
13717 +typedef struct {
13718 + uByte bLength;
13719 + uByte bDescriptorType;
13720 + uByte bInterfaceNumber;
13721 + uByte bAlternateSetting;
13722 + uByte bNumEndpoints;
13723 + uByte bInterfaceClass;
13724 + uByte bInterfaceSubClass;
13725 + uByte bInterfaceProtocol;
13726 + uByte iInterface;
13727 +} UPACKED usb_interface_descriptor_t;
13728 +#define USB_INTERFACE_DESCRIPTOR_SIZE 9
13729 +
13730 +typedef struct {
13731 + uByte bLength;
13732 + uByte bDescriptorType;
13733 + uByte bEndpointAddress;
13734 +#define UE_GET_DIR(a) ((a) & 0x80)
13735 +#define UE_SET_DIR(a,d) ((a) | (((d)&1) << 7))
13736 +#define UE_DIR_IN 0x80
13737 +#define UE_DIR_OUT 0x00
13738 +#define UE_ADDR 0x0f
13739 +#define UE_GET_ADDR(a) ((a) & UE_ADDR)
13740 + uByte bmAttributes;
13741 +#define UE_XFERTYPE 0x03
13742 +#define UE_CONTROL 0x00
13743 +#define UE_ISOCHRONOUS 0x01
13744 +#define UE_BULK 0x02
13745 +#define UE_INTERRUPT 0x03
13746 +#define UE_GET_XFERTYPE(a) ((a) & UE_XFERTYPE)
13747 +#define UE_ISO_TYPE 0x0c
13748 +#define UE_ISO_ASYNC 0x04
13749 +#define UE_ISO_ADAPT 0x08
13750 +#define UE_ISO_SYNC 0x0c
13751 +#define UE_GET_ISO_TYPE(a) ((a) & UE_ISO_TYPE)
13752 + uWord wMaxPacketSize;
13753 + uByte bInterval;
13754 +} UPACKED usb_endpoint_descriptor_t;
13755 +#define USB_ENDPOINT_DESCRIPTOR_SIZE 7
13756 +
13757 +typedef struct ss_endpoint_companion_descriptor {
13758 + uByte bLength;
13759 + uByte bDescriptorType;
13760 + uByte bMaxBurst;
13761 +#define USSE_GET_MAX_STREAMS(a) ((a) & 0x1f)
13762 +#define USSE_SET_MAX_STREAMS(a, b) ((a) | ((b) & 0x1f))
13763 +#define USSE_GET_MAX_PACKET_NUM(a) ((a) & 0x03)
13764 +#define USSE_SET_MAX_PACKET_NUM(a, b) ((a) | ((b) & 0x03))
13765 + uByte bmAttributes;
13766 + uWord wBytesPerInterval;
13767 +} UPACKED ss_endpoint_companion_descriptor_t;
13768 +#define USB_SS_ENDPOINT_COMPANION_DESCRIPTOR_SIZE 6
13769 +
13770 +typedef struct {
13771 + uByte bLength;
13772 + uByte bDescriptorType;
13773 + uWord bString[127];
13774 +} UPACKED usb_string_descriptor_t;
13775 +#define USB_MAX_STRING_LEN 128
13776 +#define USB_LANGUAGE_TABLE 0 /* # of the string language id table */
13777 +
13778 +/* Hub specific request */
13779 +#define UR_GET_BUS_STATE 0x02
13780 +#define UR_CLEAR_TT_BUFFER 0x08
13781 +#define UR_RESET_TT 0x09
13782 +#define UR_GET_TT_STATE 0x0a
13783 +#define UR_STOP_TT 0x0b
13784 +
13785 +/* Hub features */
13786 +#define UHF_C_HUB_LOCAL_POWER 0
13787 +#define UHF_C_HUB_OVER_CURRENT 1
13788 +#define UHF_PORT_CONNECTION 0
13789 +#define UHF_PORT_ENABLE 1
13790 +#define UHF_PORT_SUSPEND 2
13791 +#define UHF_PORT_OVER_CURRENT 3
13792 +#define UHF_PORT_RESET 4
13793 +#define UHF_PORT_L1 5
13794 +#define UHF_PORT_POWER 8
13795 +#define UHF_PORT_LOW_SPEED 9
13796 +#define UHF_PORT_HIGH_SPEED 10
13797 +#define UHF_C_PORT_CONNECTION 16
13798 +#define UHF_C_PORT_ENABLE 17
13799 +#define UHF_C_PORT_SUSPEND 18
13800 +#define UHF_C_PORT_OVER_CURRENT 19
13801 +#define UHF_C_PORT_RESET 20
13802 +#define UHF_C_PORT_L1 23
13803 +#define UHF_PORT_TEST 21
13804 +#define UHF_PORT_INDICATOR 22
13805 +
13806 +typedef struct {
13807 + uByte bDescLength;
13808 + uByte bDescriptorType;
13809 + uByte bNbrPorts;
13810 + uWord wHubCharacteristics;
13811 +#define UHD_PWR 0x0003
13812 +#define UHD_PWR_GANGED 0x0000
13813 +#define UHD_PWR_INDIVIDUAL 0x0001
13814 +#define UHD_PWR_NO_SWITCH 0x0002
13815 +#define UHD_COMPOUND 0x0004
13816 +#define UHD_OC 0x0018
13817 +#define UHD_OC_GLOBAL 0x0000
13818 +#define UHD_OC_INDIVIDUAL 0x0008
13819 +#define UHD_OC_NONE 0x0010
13820 +#define UHD_TT_THINK 0x0060
13821 +#define UHD_TT_THINK_8 0x0000
13822 +#define UHD_TT_THINK_16 0x0020
13823 +#define UHD_TT_THINK_24 0x0040
13824 +#define UHD_TT_THINK_32 0x0060
13825 +#define UHD_PORT_IND 0x0080
13826 + uByte bPwrOn2PwrGood; /* delay in 2 ms units */
13827 +#define UHD_PWRON_FACTOR 2
13828 + uByte bHubContrCurrent;
13829 + uByte DeviceRemovable[32]; /* max 255 ports */
13830 +#define UHD_NOT_REMOV(desc, i) \
13831 + (((desc)->DeviceRemovable[(i)/8] >> ((i) % 8)) & 1)
13832 + /* deprecated */ uByte PortPowerCtrlMask[1];
13833 +} UPACKED usb_hub_descriptor_t;
13834 +#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */
13835 +
13836 +typedef struct {
13837 + uByte bLength;
13838 + uByte bDescriptorType;
13839 + uWord bcdUSB;
13840 + uByte bDeviceClass;
13841 + uByte bDeviceSubClass;
13842 + uByte bDeviceProtocol;
13843 + uByte bMaxPacketSize0;
13844 + uByte bNumConfigurations;
13845 + uByte bReserved;
13846 +} UPACKED usb_device_qualifier_t;
13847 +#define USB_DEVICE_QUALIFIER_SIZE 10
13848 +
13849 +typedef struct {
13850 + uByte bLength;
13851 + uByte bDescriptorType;
13852 + uByte bmAttributes;
13853 +#define UOTG_SRP 0x01
13854 +#define UOTG_HNP 0x02
13855 +} UPACKED usb_otg_descriptor_t;
13856 +
13857 +/* OTG feature selectors */
13858 +#define UOTG_B_HNP_ENABLE 3
13859 +#define UOTG_A_HNP_SUPPORT 4
13860 +#define UOTG_A_ALT_HNP_SUPPORT 5
13861 +
13862 +typedef struct {
13863 + uWord wStatus;
13864 +/* Device status flags */
13865 +#define UDS_SELF_POWERED 0x0001
13866 +#define UDS_REMOTE_WAKEUP 0x0002
13867 +/* Endpoint status flags */
13868 +#define UES_HALT 0x0001
13869 +} UPACKED usb_status_t;
13870 +
13871 +typedef struct {
13872 + uWord wHubStatus;
13873 +#define UHS_LOCAL_POWER 0x0001
13874 +#define UHS_OVER_CURRENT 0x0002
13875 + uWord wHubChange;
13876 +} UPACKED usb_hub_status_t;
13877 +
13878 +typedef struct {
13879 + uWord wPortStatus;
13880 +#define UPS_CURRENT_CONNECT_STATUS 0x0001
13881 +#define UPS_PORT_ENABLED 0x0002
13882 +#define UPS_SUSPEND 0x0004
13883 +#define UPS_OVERCURRENT_INDICATOR 0x0008
13884 +#define UPS_RESET 0x0010
13885 +#define UPS_PORT_POWER 0x0100
13886 +#define UPS_LOW_SPEED 0x0200
13887 +#define UPS_HIGH_SPEED 0x0400
13888 +#define UPS_PORT_TEST 0x0800
13889 +#define UPS_PORT_INDICATOR 0x1000
13890 + uWord wPortChange;
13891 +#define UPS_C_CONNECT_STATUS 0x0001
13892 +#define UPS_C_PORT_ENABLED 0x0002
13893 +#define UPS_C_SUSPEND 0x0004
13894 +#define UPS_C_OVERCURRENT_INDICATOR 0x0008
13895 +#define UPS_C_PORT_RESET 0x0010
13896 +} UPACKED usb_port_status_t;
13897 +
13898 +#ifdef _MSC_VER
13899 +#include <poppack.h>
13900 +#endif
13901 +
13902 +/* Device class codes */
13903 +#define UDCLASS_IN_INTERFACE 0x00
13904 +#define UDCLASS_COMM 0x02
13905 +#define UDCLASS_HUB 0x09
13906 +#define UDSUBCLASS_HUB 0x00
13907 +#define UDPROTO_FSHUB 0x00
13908 +#define UDPROTO_HSHUBSTT 0x01
13909 +#define UDPROTO_HSHUBMTT 0x02
13910 +#define UDCLASS_DIAGNOSTIC 0xdc
13911 +#define UDCLASS_WIRELESS 0xe0
13912 +#define UDSUBCLASS_RF 0x01
13913 +#define UDPROTO_BLUETOOTH 0x01
13914 +#define UDCLASS_VENDOR 0xff
13915 +
13916 +/* Interface class codes */
13917 +#define UICLASS_UNSPEC 0x00
13918 +
13919 +#define UICLASS_AUDIO 0x01
13920 +#define UISUBCLASS_AUDIOCONTROL 1
13921 +#define UISUBCLASS_AUDIOSTREAM 2
13922 +#define UISUBCLASS_MIDISTREAM 3
13923 +
13924 +#define UICLASS_CDC 0x02 /* communication */
13925 +#define UISUBCLASS_DIRECT_LINE_CONTROL_MODEL 1
13926 +#define UISUBCLASS_ABSTRACT_CONTROL_MODEL 2
13927 +#define UISUBCLASS_TELEPHONE_CONTROL_MODEL 3
13928 +#define UISUBCLASS_MULTICHANNEL_CONTROL_MODEL 4
13929 +#define UISUBCLASS_CAPI_CONTROLMODEL 5
13930 +#define UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL 6
13931 +#define UISUBCLASS_ATM_NETWORKING_CONTROL_MODEL 7
13932 +#define UIPROTO_CDC_AT 1
13933 +
13934 +#define UICLASS_HID 0x03
13935 +#define UISUBCLASS_BOOT 1
13936 +#define UIPROTO_BOOT_KEYBOARD 1
13937 +
13938 +#define UICLASS_PHYSICAL 0x05
13939 +
13940 +#define UICLASS_IMAGE 0x06
13941 +
13942 +#define UICLASS_PRINTER 0x07
13943 +#define UISUBCLASS_PRINTER 1
13944 +#define UIPROTO_PRINTER_UNI 1
13945 +#define UIPROTO_PRINTER_BI 2
13946 +#define UIPROTO_PRINTER_1284 3
13947 +
13948 +#define UICLASS_MASS 0x08
13949 +#define UISUBCLASS_RBC 1
13950 +#define UISUBCLASS_SFF8020I 2
13951 +#define UISUBCLASS_QIC157 3
13952 +#define UISUBCLASS_UFI 4
13953 +#define UISUBCLASS_SFF8070I 5
13954 +#define UISUBCLASS_SCSI 6
13955 +#define UIPROTO_MASS_CBI_I 0
13956 +#define UIPROTO_MASS_CBI 1
13957 +#define UIPROTO_MASS_BBB_OLD 2 /* Not in the spec anymore */
13958 +#define UIPROTO_MASS_BBB 80 /* 'P' for the Iomega Zip drive */
13959 +
13960 +#define UICLASS_HUB 0x09
13961 +#define UISUBCLASS_HUB 0
13962 +#define UIPROTO_FSHUB 0
13963 +#define UIPROTO_HSHUBSTT 0 /* Yes, same as previous */
13964 +#define UIPROTO_HSHUBMTT 1
13965 +
13966 +#define UICLASS_CDC_DATA 0x0a
13967 +#define UISUBCLASS_DATA 0
13968 +#define UIPROTO_DATA_ISDNBRI 0x30 /* Physical iface */
13969 +#define UIPROTO_DATA_HDLC 0x31 /* HDLC */
13970 +#define UIPROTO_DATA_TRANSPARENT 0x32 /* Transparent */
13971 +#define UIPROTO_DATA_Q921M 0x50 /* Management for Q921 */
13972 +#define UIPROTO_DATA_Q921 0x51 /* Data for Q921 */
13973 +#define UIPROTO_DATA_Q921TM 0x52 /* TEI multiplexer for Q921 */
13974 +#define UIPROTO_DATA_V42BIS 0x90 /* Data compression */
13975 +#define UIPROTO_DATA_Q931 0x91 /* Euro-ISDN */
13976 +#define UIPROTO_DATA_V120 0x92 /* V.24 rate adaption */
13977 +#define UIPROTO_DATA_CAPI 0x93 /* CAPI 2.0 commands */
13978 +#define UIPROTO_DATA_HOST_BASED 0xfd /* Host based driver */
13979 +#define UIPROTO_DATA_PUF 0xfe /* see Prot. Unit Func. Desc.*/
13980 +#define UIPROTO_DATA_VENDOR 0xff /* Vendor specific */
13981 +
13982 +#define UICLASS_SMARTCARD 0x0b
13983 +
13984 +/*#define UICLASS_FIRM_UPD 0x0c*/
13985 +
13986 +#define UICLASS_SECURITY 0x0d
13987 +
13988 +#define UICLASS_DIAGNOSTIC 0xdc
13989 +
13990 +#define UICLASS_WIRELESS 0xe0
13991 +#define UISUBCLASS_RF 0x01
13992 +#define UIPROTO_BLUETOOTH 0x01
13993 +
13994 +#define UICLASS_APPL_SPEC 0xfe
13995 +#define UISUBCLASS_FIRMWARE_DOWNLOAD 1
13996 +#define UISUBCLASS_IRDA 2
13997 +#define UIPROTO_IRDA 0
13998 +
13999 +#define UICLASS_VENDOR 0xff
14000 +
14001 +#define USB_HUB_MAX_DEPTH 5
14002 +
14003 +/*
14004 + * Minimum time a device needs to be powered down to go through
14005 + * a power cycle. XXX Are these time in the spec?
14006 + */
14007 +#define USB_POWER_DOWN_TIME 200 /* ms */
14008 +#define USB_PORT_POWER_DOWN_TIME 100 /* ms */
14009 +
14010 +#if 0
14011 +/* These are the values from the spec. */
14012 +#define USB_PORT_RESET_DELAY 10 /* ms */
14013 +#define USB_PORT_ROOT_RESET_DELAY 50 /* ms */
14014 +#define USB_PORT_RESET_RECOVERY 10 /* ms */
14015 +#define USB_PORT_POWERUP_DELAY 100 /* ms */
14016 +#define USB_SET_ADDRESS_SETTLE 2 /* ms */
14017 +#define USB_RESUME_DELAY (20*5) /* ms */
14018 +#define USB_RESUME_WAIT 10 /* ms */
14019 +#define USB_RESUME_RECOVERY 10 /* ms */
14020 +#define USB_EXTRA_POWER_UP_TIME 0 /* ms */
14021 +#else
14022 +/* Allow for marginal (i.e. non-conforming) devices. */
14023 +#define USB_PORT_RESET_DELAY 50 /* ms */
14024 +#define USB_PORT_ROOT_RESET_DELAY 250 /* ms */
14025 +#define USB_PORT_RESET_RECOVERY 250 /* ms */
14026 +#define USB_PORT_POWERUP_DELAY 300 /* ms */
14027 +#define USB_SET_ADDRESS_SETTLE 10 /* ms */
14028 +#define USB_RESUME_DELAY (50*5) /* ms */
14029 +#define USB_RESUME_WAIT 50 /* ms */
14030 +#define USB_RESUME_RECOVERY 50 /* ms */
14031 +#define USB_EXTRA_POWER_UP_TIME 20 /* ms */
14032 +#endif
14033 +
14034 +#define USB_MIN_POWER 100 /* mA */
14035 +#define USB_MAX_POWER 500 /* mA */
14036 +
14037 +#define USB_BUS_RESET_DELAY 100 /* ms XXX?*/
14038 +
14039 +#define USB_UNCONFIG_NO 0
14040 +#define USB_UNCONFIG_INDEX (-1)
14041 +
14042 +/*** ioctl() related stuff ***/
14043 +
14044 +struct usb_ctl_request {
14045 + int ucr_addr;
14046 + usb_device_request_t ucr_request;
14047 + void *ucr_data;
14048 + int ucr_flags;
14049 +#define USBD_SHORT_XFER_OK 0x04 /* allow short reads */
14050 + int ucr_actlen; /* actual length transferred */
14051 +};
14052 +
14053 +struct usb_alt_interface {
14054 + int uai_config_index;
14055 + int uai_interface_index;
14056 + int uai_alt_no;
14057 +};
14058 +
14059 +#define USB_CURRENT_CONFIG_INDEX (-1)
14060 +#define USB_CURRENT_ALT_INDEX (-1)
14061 +
14062 +struct usb_config_desc {
14063 + int ucd_config_index;
14064 + usb_config_descriptor_t ucd_desc;
14065 +};
14066 +
14067 +struct usb_interface_desc {
14068 + int uid_config_index;
14069 + int uid_interface_index;
14070 + int uid_alt_index;
14071 + usb_interface_descriptor_t uid_desc;
14072 +};
14073 +
14074 +struct usb_endpoint_desc {
14075 + int ued_config_index;
14076 + int ued_interface_index;
14077 + int ued_alt_index;
14078 + int ued_endpoint_index;
14079 + usb_endpoint_descriptor_t ued_desc;
14080 +};
14081 +
14082 +struct usb_full_desc {
14083 + int ufd_config_index;
14084 + u_int ufd_size;
14085 + u_char *ufd_data;
14086 +};
14087 +
14088 +struct usb_string_desc {
14089 + int usd_string_index;
14090 + int usd_language_id;
14091 + usb_string_descriptor_t usd_desc;
14092 +};
14093 +
14094 +struct usb_ctl_report_desc {
14095 + int ucrd_size;
14096 + u_char ucrd_data[1024]; /* filled data size will vary */
14097 +};
14098 +
14099 +typedef struct { u_int32_t cookie; } usb_event_cookie_t;
14100 +
14101 +#define USB_MAX_DEVNAMES 4
14102 +#define USB_MAX_DEVNAMELEN 16
14103 +struct usb_device_info {
14104 + u_int8_t udi_bus;
14105 + u_int8_t udi_addr; /* device address */
14106 + usb_event_cookie_t udi_cookie;
14107 + char udi_product[USB_MAX_STRING_LEN];
14108 + char udi_vendor[USB_MAX_STRING_LEN];
14109 + char udi_release[8];
14110 + u_int16_t udi_productNo;
14111 + u_int16_t udi_vendorNo;
14112 + u_int16_t udi_releaseNo;
14113 + u_int8_t udi_class;
14114 + u_int8_t udi_subclass;
14115 + u_int8_t udi_protocol;
14116 + u_int8_t udi_config;
14117 + u_int8_t udi_speed;
14118 +#define USB_SPEED_UNKNOWN 0
14119 +#define USB_SPEED_LOW 1
14120 +#define USB_SPEED_FULL 2
14121 +#define USB_SPEED_HIGH 3
14122 +#define USB_SPEED_VARIABLE 4
14123 +#define USB_SPEED_SUPER 5
14124 + int udi_power; /* power consumption in mA, 0 if selfpowered */
14125 + int udi_nports;
14126 + char udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];
14127 + u_int8_t udi_ports[16];/* hub only: addresses of devices on ports */
14128 +#define USB_PORT_ENABLED 0xff
14129 +#define USB_PORT_SUSPENDED 0xfe
14130 +#define USB_PORT_POWERED 0xfd
14131 +#define USB_PORT_DISABLED 0xfc
14132 +};
14133 +
14134 +struct usb_ctl_report {
14135 + int ucr_report;
14136 + u_char ucr_data[1024]; /* filled data size will vary */
14137 +};
14138 +
14139 +struct usb_device_stats {
14140 + u_long uds_requests[4]; /* indexed by transfer type UE_* */
14141 +};
14142 +
14143 +#define WUSB_MIN_IE 0x80
14144 +#define WUSB_WCTA_IE 0x80
14145 +#define WUSB_WCONNECTACK_IE 0x81
14146 +#define WUSB_WHOSTINFO_IE 0x82
14147 +#define WUHI_GET_CA(_bmAttributes_) ((_bmAttributes_) & 0x3)
14148 +#define WUHI_CA_RECONN 0x00
14149 +#define WUHI_CA_LIMITED 0x01
14150 +#define WUHI_CA_ALL 0x03
14151 +#define WUHI_GET_MLSI(_bmAttributes_) (((_bmAttributes_) & 0x38) >> 3)
14152 +#define WUSB_WCHCHANGEANNOUNCE_IE 0x83
14153 +#define WUSB_WDEV_DISCONNECT_IE 0x84
14154 +#define WUSB_WHOST_DISCONNECT_IE 0x85
14155 +#define WUSB_WRELEASE_CHANNEL_IE 0x86
14156 +#define WUSB_WWORK_IE 0x87
14157 +#define WUSB_WCHANNEL_STOP_IE 0x88
14158 +#define WUSB_WDEV_KEEPALIVE_IE 0x89
14159 +#define WUSB_WISOCH_DISCARD_IE 0x8A
14160 +#define WUSB_WRESETDEVICE_IE 0x8B
14161 +#define WUSB_WXMIT_PACKET_ADJUST_IE 0x8C
14162 +#define WUSB_MAX_IE 0x8C
14163 +
14164 +/* Device Notification Types */
14165 +
14166 +#define WUSB_DN_MIN 0x01
14167 +#define WUSB_DN_CONNECT 0x01
14168 +# define WUSB_DA_OLDCONN 0x00
14169 +# define WUSB_DA_NEWCONN 0x01
14170 +# define WUSB_DA_SELF_BEACON 0x02
14171 +# define WUSB_DA_DIR_BEACON 0x04
14172 +# define WUSB_DA_NO_BEACON 0x06
14173 +#define WUSB_DN_DISCONNECT 0x02
14174 +#define WUSB_DN_EPRDY 0x03
14175 +#define WUSB_DN_MASAVAILCHANGED 0x04
14176 +#define WUSB_DN_REMOTEWAKEUP 0x05
14177 +#define WUSB_DN_SLEEP 0x06
14178 +#define WUSB_DN_ALIVE 0x07
14179 +#define WUSB_DN_MAX 0x07
14180 +
14181 +#ifdef _MSC_VER
14182 +#include <pshpack1.h>
14183 +#endif
14184 +
14185 +/* WUSB Handshake Data. Used during the SET/GET HANDSHAKE requests */
14186 +typedef struct wusb_hndshk_data {
14187 + uByte bMessageNumber;
14188 + uByte bStatus;
14189 + uByte tTKID[3];
14190 + uByte bReserved;
14191 + uByte CDID[16];
14192 + uByte Nonce[16];
14193 + uByte MIC[8];
14194 +} UPACKED wusb_hndshk_data_t;
14195 +#define WUSB_HANDSHAKE_LEN_FOR_MIC 38
14196 +
14197 +/* WUSB Connection Context */
14198 +typedef struct wusb_conn_context {
14199 + uByte CHID [16];
14200 + uByte CDID [16];
14201 + uByte CK [16];
14202 +} UPACKED wusb_conn_context_t;
14203 +
14204 +/* WUSB Security Descriptor */
14205 +typedef struct wusb_security_desc {
14206 + uByte bLength;
14207 + uByte bDescriptorType;
14208 + uWord wTotalLength;
14209 + uByte bNumEncryptionTypes;
14210 +} UPACKED wusb_security_desc_t;
14211 +
14212 +/* WUSB Encryption Type Descriptor */
14213 +typedef struct wusb_encrypt_type_desc {
14214 + uByte bLength;
14215 + uByte bDescriptorType;
14216 +
14217 + uByte bEncryptionType;
14218 +#define WUETD_UNSECURE 0
14219 +#define WUETD_WIRED 1
14220 +#define WUETD_CCM_1 2
14221 +#define WUETD_RSA_1 3
14222 +
14223 + uByte bEncryptionValue;
14224 + uByte bAuthKeyIndex;
14225 +} UPACKED wusb_encrypt_type_desc_t;
14226 +
14227 +/* WUSB Key Descriptor */
14228 +typedef struct wusb_key_desc {
14229 + uByte bLength;
14230 + uByte bDescriptorType;
14231 + uByte tTKID[3];
14232 + uByte bReserved;
14233 + uByte KeyData[1]; /* variable length */
14234 +} UPACKED wusb_key_desc_t;
14235 +
14236 +/* WUSB BOS Descriptor (Binary device Object Store) */
14237 +typedef struct wusb_bos_desc {
14238 + uByte bLength;
14239 + uByte bDescriptorType;
14240 + uWord wTotalLength;
14241 + uByte bNumDeviceCaps;
14242 +} UPACKED wusb_bos_desc_t;
14243 +
14244 +#define USB_DEVICE_CAPABILITY_20_EXTENSION 0x02
14245 +typedef struct usb_dev_cap_20_ext_desc {
14246 + uByte bLength;
14247 + uByte bDescriptorType;
14248 + uByte bDevCapabilityType;
14249 +#define USB_20_EXT_LPM 0x02
14250 + uDWord bmAttributes;
14251 +} UPACKED usb_dev_cap_20_ext_desc_t;
14252 +
14253 +#define USB_DEVICE_CAPABILITY_SS_USB 0x03
14254 +typedef struct usb_dev_cap_ss_usb {
14255 + uByte bLength;
14256 + uByte bDescriptorType;
14257 + uByte bDevCapabilityType;
14258 +#define USB_DC_SS_USB_LTM_CAPABLE 0x02
14259 + uByte bmAttributes;
14260 +#define USB_DC_SS_USB_SPEED_SUPPORT_LOW 0x01
14261 +#define USB_DC_SS_USB_SPEED_SUPPORT_FULL 0x02
14262 +#define USB_DC_SS_USB_SPEED_SUPPORT_HIGH 0x04
14263 +#define USB_DC_SS_USB_SPEED_SUPPORT_SS 0x08
14264 + uWord wSpeedsSupported;
14265 + uByte bFunctionalitySupport;
14266 + uByte bU1DevExitLat;
14267 + uWord wU2DevExitLat;
14268 +} UPACKED usb_dev_cap_ss_usb_t;
14269 +
14270 +#define USB_DEVICE_CAPABILITY_CONTAINER_ID 0x04
14271 +typedef struct usb_dev_cap_container_id {
14272 + uByte bLength;
14273 + uByte bDescriptorType;
14274 + uByte bDevCapabilityType;
14275 + uByte bReserved;
14276 + uByte containerID[16];
14277 +} UPACKED usb_dev_cap_container_id_t;
14278 +
14279 +/* Device Capability Type Codes */
14280 +#define WUSB_DEVICE_CAPABILITY_WIRELESS_USB 0x01
14281 +
14282 +/* Device Capability Descriptor */
14283 +typedef struct wusb_dev_cap_desc {
14284 + uByte bLength;
14285 + uByte bDescriptorType;
14286 + uByte bDevCapabilityType;
14287 + uByte caps[1]; /* Variable length */
14288 +} UPACKED wusb_dev_cap_desc_t;
14289 +
14290 +/* Device Capability Descriptor */
14291 +typedef struct wusb_dev_cap_uwb_desc {
14292 + uByte bLength;
14293 + uByte bDescriptorType;
14294 + uByte bDevCapabilityType;
14295 + uByte bmAttributes;
14296 + uWord wPHYRates; /* Bitmap */
14297 + uByte bmTFITXPowerInfo;
14298 + uByte bmFFITXPowerInfo;
14299 + uWord bmBandGroup;
14300 + uByte bReserved;
14301 +} UPACKED wusb_dev_cap_uwb_desc_t;
14302 +
14303 +/* Wireless USB Endpoint Companion Descriptor */
14304 +typedef struct wusb_endpoint_companion_desc {
14305 + uByte bLength;
14306 + uByte bDescriptorType;
14307 + uByte bMaxBurst;
14308 + uByte bMaxSequence;
14309 + uWord wMaxStreamDelay;
14310 + uWord wOverTheAirPacketSize;
14311 + uByte bOverTheAirInterval;
14312 + uByte bmCompAttributes;
14313 +} UPACKED wusb_endpoint_companion_desc_t;
14314 +
14315 +/* Wireless USB Numeric Association M1 Data Structure */
14316 +typedef struct wusb_m1_data {
14317 + uByte version;
14318 + uWord langId;
14319 + uByte deviceFriendlyNameLength;
14320 + uByte sha_256_m3[32];
14321 + uByte deviceFriendlyName[256];
14322 +} UPACKED wusb_m1_data_t;
14323 +
14324 +typedef struct wusb_m2_data {
14325 + uByte version;
14326 + uWord langId;
14327 + uByte hostFriendlyNameLength;
14328 + uByte pkh[384];
14329 + uByte hostFriendlyName[256];
14330 +} UPACKED wusb_m2_data_t;
14331 +
14332 +typedef struct wusb_m3_data {
14333 + uByte pkd[384];
14334 + uByte nd;
14335 +} UPACKED wusb_m3_data_t;
14336 +
14337 +typedef struct wusb_m4_data {
14338 + uDWord _attributeTypeIdAndLength_1;
14339 + uWord associationTypeId;
14340 +
14341 + uDWord _attributeTypeIdAndLength_2;
14342 + uWord associationSubTypeId;
14343 +
14344 + uDWord _attributeTypeIdAndLength_3;
14345 + uDWord length;
14346 +
14347 + uDWord _attributeTypeIdAndLength_4;
14348 + uDWord associationStatus;
14349 +
14350 + uDWord _attributeTypeIdAndLength_5;
14351 + uByte chid[16];
14352 +
14353 + uDWord _attributeTypeIdAndLength_6;
14354 + uByte cdid[16];
14355 +
14356 + uDWord _attributeTypeIdAndLength_7;
14357 + uByte bandGroups[2];
14358 +} UPACKED wusb_m4_data_t;
14359 +
14360 +#ifdef _MSC_VER
14361 +#include <poppack.h>
14362 +#endif
14363 +
14364 +#ifdef __cplusplus
14365 +}
14366 +#endif
14367 +
14368 +#endif /* _USB_H_ */
14369 --- /dev/null
14370 +++ b/drivers/usb/host/dwc_otg/doc/doxygen.cfg
14371 @@ -0,0 +1,224 @@
14372 +# Doxyfile 1.3.9.1
14373 +
14374 +#---------------------------------------------------------------------------
14375 +# Project related configuration options
14376 +#---------------------------------------------------------------------------
14377 +PROJECT_NAME = "DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver"
14378 +PROJECT_NUMBER = v3.00a
14379 +OUTPUT_DIRECTORY = ./doc/
14380 +CREATE_SUBDIRS = NO
14381 +OUTPUT_LANGUAGE = English
14382 +BRIEF_MEMBER_DESC = YES
14383 +REPEAT_BRIEF = YES
14384 +ABBREVIATE_BRIEF = "The $name class" \
14385 + "The $name widget" \
14386 + "The $name file" \
14387 + is \
14388 + provides \
14389 + specifies \
14390 + contains \
14391 + represents \
14392 + a \
14393 + an \
14394 + the
14395 +ALWAYS_DETAILED_SEC = NO
14396 +INLINE_INHERITED_MEMB = NO
14397 +FULL_PATH_NAMES = NO
14398 +STRIP_FROM_PATH =
14399 +STRIP_FROM_INC_PATH =
14400 +SHORT_NAMES = NO
14401 +JAVADOC_AUTOBRIEF = YES
14402 +MULTILINE_CPP_IS_BRIEF = NO
14403 +INHERIT_DOCS = YES
14404 +DISTRIBUTE_GROUP_DOC = NO
14405 +TAB_SIZE = 8
14406 +ALIASES =
14407 +OPTIMIZE_OUTPUT_FOR_C = YES
14408 +OPTIMIZE_OUTPUT_JAVA = NO
14409 +SUBGROUPING = YES
14410 +#---------------------------------------------------------------------------
14411 +# Build related configuration options
14412 +#---------------------------------------------------------------------------
14413 +EXTRACT_ALL = NO
14414 +EXTRACT_PRIVATE = YES
14415 +EXTRACT_STATIC = YES
14416 +EXTRACT_LOCAL_CLASSES = YES
14417 +EXTRACT_LOCAL_METHODS = NO
14418 +HIDE_UNDOC_MEMBERS = NO
14419 +HIDE_UNDOC_CLASSES = NO
14420 +HIDE_FRIEND_COMPOUNDS = NO
14421 +HIDE_IN_BODY_DOCS = NO
14422 +INTERNAL_DOCS = NO
14423 +CASE_SENSE_NAMES = NO
14424 +HIDE_SCOPE_NAMES = NO
14425 +SHOW_INCLUDE_FILES = YES
14426 +INLINE_INFO = YES
14427 +SORT_MEMBER_DOCS = NO
14428 +SORT_BRIEF_DOCS = NO
14429 +SORT_BY_SCOPE_NAME = NO
14430 +GENERATE_TODOLIST = YES
14431 +GENERATE_TESTLIST = YES
14432 +GENERATE_BUGLIST = YES
14433 +GENERATE_DEPRECATEDLIST= YES
14434 +ENABLED_SECTIONS =
14435 +MAX_INITIALIZER_LINES = 30
14436 +SHOW_USED_FILES = YES
14437 +SHOW_DIRECTORIES = YES
14438 +#---------------------------------------------------------------------------
14439 +# configuration options related to warning and progress messages
14440 +#---------------------------------------------------------------------------
14441 +QUIET = YES
14442 +WARNINGS = YES
14443 +WARN_IF_UNDOCUMENTED = NO
14444 +WARN_IF_DOC_ERROR = YES
14445 +WARN_FORMAT = "$file:$line: $text"
14446 +WARN_LOGFILE =
14447 +#---------------------------------------------------------------------------
14448 +# configuration options related to the input files
14449 +#---------------------------------------------------------------------------
14450 +INPUT = .
14451 +FILE_PATTERNS = *.c \
14452 + *.h \
14453 + ./linux/*.c \
14454 + ./linux/*.h
14455 +RECURSIVE = NO
14456 +EXCLUDE = ./test/ \
14457 + ./dwc_otg/.AppleDouble/
14458 +EXCLUDE_SYMLINKS = YES
14459 +EXCLUDE_PATTERNS = *.mod.*
14460 +EXAMPLE_PATH =
14461 +EXAMPLE_PATTERNS = *
14462 +EXAMPLE_RECURSIVE = NO
14463 +IMAGE_PATH =
14464 +INPUT_FILTER =
14465 +FILTER_PATTERNS =
14466 +FILTER_SOURCE_FILES = NO
14467 +#---------------------------------------------------------------------------
14468 +# configuration options related to source browsing
14469 +#---------------------------------------------------------------------------
14470 +SOURCE_BROWSER = YES
14471 +INLINE_SOURCES = NO
14472 +STRIP_CODE_COMMENTS = YES
14473 +REFERENCED_BY_RELATION = NO
14474 +REFERENCES_RELATION = NO
14475 +VERBATIM_HEADERS = NO
14476 +#---------------------------------------------------------------------------
14477 +# configuration options related to the alphabetical class index
14478 +#---------------------------------------------------------------------------
14479 +ALPHABETICAL_INDEX = NO
14480 +COLS_IN_ALPHA_INDEX = 5
14481 +IGNORE_PREFIX =
14482 +#---------------------------------------------------------------------------
14483 +# configuration options related to the HTML output
14484 +#---------------------------------------------------------------------------
14485 +GENERATE_HTML = YES
14486 +HTML_OUTPUT = html
14487 +HTML_FILE_EXTENSION = .html
14488 +HTML_HEADER =
14489 +HTML_FOOTER =
14490 +HTML_STYLESHEET =
14491 +HTML_ALIGN_MEMBERS = YES
14492 +GENERATE_HTMLHELP = NO
14493 +CHM_FILE =
14494 +HHC_LOCATION =
14495 +GENERATE_CHI = NO
14496 +BINARY_TOC = NO
14497 +TOC_EXPAND = NO
14498 +DISABLE_INDEX = NO
14499 +ENUM_VALUES_PER_LINE = 4
14500 +GENERATE_TREEVIEW = YES
14501 +TREEVIEW_WIDTH = 250
14502 +#---------------------------------------------------------------------------
14503 +# configuration options related to the LaTeX output
14504 +#---------------------------------------------------------------------------
14505 +GENERATE_LATEX = NO
14506 +LATEX_OUTPUT = latex
14507 +LATEX_CMD_NAME = latex
14508 +MAKEINDEX_CMD_NAME = makeindex
14509 +COMPACT_LATEX = NO
14510 +PAPER_TYPE = a4wide
14511 +EXTRA_PACKAGES =
14512 +LATEX_HEADER =
14513 +PDF_HYPERLINKS = NO
14514 +USE_PDFLATEX = NO
14515 +LATEX_BATCHMODE = NO
14516 +LATEX_HIDE_INDICES = NO
14517 +#---------------------------------------------------------------------------
14518 +# configuration options related to the RTF output
14519 +#---------------------------------------------------------------------------
14520 +GENERATE_RTF = NO
14521 +RTF_OUTPUT = rtf
14522 +COMPACT_RTF = NO
14523 +RTF_HYPERLINKS = NO
14524 +RTF_STYLESHEET_FILE =
14525 +RTF_EXTENSIONS_FILE =
14526 +#---------------------------------------------------------------------------
14527 +# configuration options related to the man page output
14528 +#---------------------------------------------------------------------------
14529 +GENERATE_MAN = NO
14530 +MAN_OUTPUT = man
14531 +MAN_EXTENSION = .3
14532 +MAN_LINKS = NO
14533 +#---------------------------------------------------------------------------
14534 +# configuration options related to the XML output
14535 +#---------------------------------------------------------------------------
14536 +GENERATE_XML = NO
14537 +XML_OUTPUT = xml
14538 +XML_SCHEMA =
14539 +XML_DTD =
14540 +XML_PROGRAMLISTING = YES
14541 +#---------------------------------------------------------------------------
14542 +# configuration options for the AutoGen Definitions output
14543 +#---------------------------------------------------------------------------
14544 +GENERATE_AUTOGEN_DEF = NO
14545 +#---------------------------------------------------------------------------
14546 +# configuration options related to the Perl module output
14547 +#---------------------------------------------------------------------------
14548 +GENERATE_PERLMOD = NO
14549 +PERLMOD_LATEX = NO
14550 +PERLMOD_PRETTY = YES
14551 +PERLMOD_MAKEVAR_PREFIX =
14552 +#---------------------------------------------------------------------------
14553 +# Configuration options related to the preprocessor
14554 +#---------------------------------------------------------------------------
14555 +ENABLE_PREPROCESSING = YES
14556 +MACRO_EXPANSION = YES
14557 +EXPAND_ONLY_PREDEF = YES
14558 +SEARCH_INCLUDES = YES
14559 +INCLUDE_PATH =
14560 +INCLUDE_FILE_PATTERNS =
14561 +PREDEFINED = DEVICE_ATTR DWC_EN_ISOC
14562 +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
14563 +SKIP_FUNCTION_MACROS = NO
14564 +#---------------------------------------------------------------------------
14565 +# Configuration::additions related to external references
14566 +#---------------------------------------------------------------------------
14567 +TAGFILES =
14568 +GENERATE_TAGFILE =
14569 +ALLEXTERNALS = NO
14570 +EXTERNAL_GROUPS = YES
14571 +PERL_PATH = /usr/bin/perl
14572 +#---------------------------------------------------------------------------
14573 +# Configuration options related to the dot tool
14574 +#---------------------------------------------------------------------------
14575 +CLASS_DIAGRAMS = YES
14576 +HIDE_UNDOC_RELATIONS = YES
14577 +HAVE_DOT = NO
14578 +CLASS_GRAPH = YES
14579 +COLLABORATION_GRAPH = YES
14580 +UML_LOOK = NO
14581 +TEMPLATE_RELATIONS = NO
14582 +INCLUDE_GRAPH = YES
14583 +INCLUDED_BY_GRAPH = YES
14584 +CALL_GRAPH = NO
14585 +GRAPHICAL_HIERARCHY = YES
14586 +DOT_IMAGE_FORMAT = png
14587 +DOT_PATH =
14588 +DOTFILE_DIRS =
14589 +MAX_DOT_GRAPH_DEPTH = 1000
14590 +GENERATE_LEGEND = YES
14591 +DOT_CLEANUP = YES
14592 +#---------------------------------------------------------------------------
14593 +# Configuration::additions related to the search engine
14594 +#---------------------------------------------------------------------------
14595 +SEARCHENGINE = NO
14596 --- /dev/null
14597 +++ b/drivers/usb/host/dwc_otg/dummy_audio.c
14598 @@ -0,0 +1,1575 @@
14599 +/*
14600 + * zero.c -- Gadget Zero, for USB development
14601 + *
14602 + * Copyright (C) 2003-2004 David Brownell
14603 + * All rights reserved.
14604 + *
14605 + * Redistribution and use in source and binary forms, with or without
14606 + * modification, are permitted provided that the following conditions
14607 + * are met:
14608 + * 1. Redistributions of source code must retain the above copyright
14609 + * notice, this list of conditions, and the following disclaimer,
14610 + * without modification.
14611 + * 2. Redistributions in binary form must reproduce the above copyright
14612 + * notice, this list of conditions and the following disclaimer in the
14613 + * documentation and/or other materials provided with the distribution.
14614 + * 3. The names of the above-listed copyright holders may not be used
14615 + * to endorse or promote products derived from this software without
14616 + * specific prior written permission.
14617 + *
14618 + * ALTERNATIVELY, this software may be distributed under the terms of the
14619 + * GNU General Public License ("GPL") as published by the Free Software
14620 + * Foundation, either version 2 of that License or (at your option) any
14621 + * later version.
14622 + *
14623 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
14624 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
14625 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
14626 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
14627 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
14628 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
14629 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
14630 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
14631 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
14632 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
14633 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14634 + */
14635 +
14636 +
14637 +/*
14638 + * Gadget Zero only needs two bulk endpoints, and is an example of how you
14639 + * can write a hardware-agnostic gadget driver running inside a USB device.
14640 + *
14641 + * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
14642 + * affect most of the driver.
14643 + *
14644 + * Use it with the Linux host/master side "usbtest" driver to get a basic
14645 + * functional test of your device-side usb stack, or with "usb-skeleton".
14646 + *
14647 + * It supports two similar configurations. One sinks whatever the usb host
14648 + * writes, and in return sources zeroes. The other loops whatever the host
14649 + * writes back, so the host can read it. Module options include:
14650 + *
14651 + * buflen=N default N=4096, buffer size used
14652 + * qlen=N default N=32, how many buffers in the loopback queue
14653 + * loopdefault default false, list loopback config first
14654 + *
14655 + * Many drivers will only have one configuration, letting them be much
14656 + * simpler if they also don't support high speed operation (like this
14657 + * driver does).
14658 + */
14659 +
14660 +#include <linux/config.h>
14661 +#include <linux/module.h>
14662 +#include <linux/kernel.h>
14663 +#include <linux/delay.h>
14664 +#include <linux/ioport.h>
14665 +#include <linux/sched.h>
14666 +#include <linux/slab.h>
14667 +#include <linux/smp_lock.h>
14668 +#include <linux/errno.h>
14669 +#include <linux/init.h>
14670 +#include <linux/timer.h>
14671 +#include <linux/list.h>
14672 +#include <linux/interrupt.h>
14673 +#include <linux/uts.h>
14674 +#include <linux/version.h>
14675 +#include <linux/device.h>
14676 +#include <linux/moduleparam.h>
14677 +#include <linux/proc_fs.h>
14678 +
14679 +#include <asm/byteorder.h>
14680 +#include <asm/io.h>
14681 +#include <asm/irq.h>
14682 +#include <asm/system.h>
14683 +#include <asm/unaligned.h>
14684 +
14685 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
14686 +# include <linux/usb/ch9.h>
14687 +#else
14688 +# include <linux/usb_ch9.h>
14689 +#endif
14690 +
14691 +#include <linux/usb_gadget.h>
14692 +
14693 +
14694 +/*-------------------------------------------------------------------------*/
14695 +/*-------------------------------------------------------------------------*/
14696 +
14697 +
14698 +static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len)
14699 +{
14700 + int count = 0;
14701 + u8 c;
14702 + u16 uchar;
14703 +
14704 + /* this insists on correct encodings, though not minimal ones.
14705 + * BUT it currently rejects legit 4-byte UTF-8 code points,
14706 + * which need surrogate pairs. (Unicode 3.1 can use them.)
14707 + */
14708 + while (len != 0 && (c = (u8) *s++) != 0) {
14709 + if (unlikely(c & 0x80)) {
14710 + // 2-byte sequence:
14711 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
14712 + if ((c & 0xe0) == 0xc0) {
14713 + uchar = (c & 0x1f) << 6;
14714 +
14715 + c = (u8) *s++;
14716 + if ((c & 0xc0) != 0xc0)
14717 + goto fail;
14718 + c &= 0x3f;
14719 + uchar |= c;
14720 +
14721 + // 3-byte sequence (most CJKV characters):
14722 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
14723 + } else if ((c & 0xf0) == 0xe0) {
14724 + uchar = (c & 0x0f) << 12;
14725 +
14726 + c = (u8) *s++;
14727 + if ((c & 0xc0) != 0xc0)
14728 + goto fail;
14729 + c &= 0x3f;
14730 + uchar |= c << 6;
14731 +
14732 + c = (u8) *s++;
14733 + if ((c & 0xc0) != 0xc0)
14734 + goto fail;
14735 + c &= 0x3f;
14736 + uchar |= c;
14737 +
14738 + /* no bogus surrogates */
14739 + if (0xd800 <= uchar && uchar <= 0xdfff)
14740 + goto fail;
14741 +
14742 + // 4-byte sequence (surrogate pairs, currently rare):
14743 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
14744 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
14745 + // (uuuuu = wwww + 1)
14746 + // FIXME accept the surrogate code points (only)
14747 +
14748 + } else
14749 + goto fail;
14750 + } else
14751 + uchar = c;
14752 + put_unaligned (cpu_to_le16 (uchar), cp++);
14753 + count++;
14754 + len--;
14755 + }
14756 + return count;
14757 +fail:
14758 + return -1;
14759 +}
14760 +
14761 +
14762 +/**
14763 + * usb_gadget_get_string - fill out a string descriptor
14764 + * @table: of c strings encoded using UTF-8
14765 + * @id: string id, from low byte of wValue in get string descriptor
14766 + * @buf: at least 256 bytes
14767 + *
14768 + * Finds the UTF-8 string matching the ID, and converts it into a
14769 + * string descriptor in utf16-le.
14770 + * Returns length of descriptor (always even) or negative errno
14771 + *
14772 + * If your driver needs stings in multiple languages, you'll probably
14773 + * "switch (wIndex) { ... }" in your ep0 string descriptor logic,
14774 + * using this routine after choosing which set of UTF-8 strings to use.
14775 + * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
14776 + * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
14777 + * characters (which are also widely used in C strings).
14778 + */
14779 +int
14780 +usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
14781 +{
14782 + struct usb_string *s;
14783 + int len;
14784 +
14785 + /* descriptor 0 has the language id */
14786 + if (id == 0) {
14787 + buf [0] = 4;
14788 + buf [1] = USB_DT_STRING;
14789 + buf [2] = (u8) table->language;
14790 + buf [3] = (u8) (table->language >> 8);
14791 + return 4;
14792 + }
14793 + for (s = table->strings; s && s->s; s++)
14794 + if (s->id == id)
14795 + break;
14796 +
14797 + /* unrecognized: stall. */
14798 + if (!s || !s->s)
14799 + return -EINVAL;
14800 +
14801 + /* string descriptors have length, tag, then UTF16-LE text */
14802 + len = min ((size_t) 126, strlen (s->s));
14803 + memset (buf + 2, 0, 2 * len); /* zero all the bytes */
14804 + len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len);
14805 + if (len < 0)
14806 + return -EINVAL;
14807 + buf [0] = (len + 1) * 2;
14808 + buf [1] = USB_DT_STRING;
14809 + return buf [0];
14810 +}
14811 +
14812 +
14813 +/*-------------------------------------------------------------------------*/
14814 +/*-------------------------------------------------------------------------*/
14815 +
14816 +
14817 +/**
14818 + * usb_descriptor_fillbuf - fill buffer with descriptors
14819 + * @buf: Buffer to be filled
14820 + * @buflen: Size of buf
14821 + * @src: Array of descriptor pointers, terminated by null pointer.
14822 + *
14823 + * Copies descriptors into the buffer, returning the length or a
14824 + * negative error code if they can't all be copied. Useful when
14825 + * assembling descriptors for an associated set of interfaces used
14826 + * as part of configuring a composite device; or in other cases where
14827 + * sets of descriptors need to be marshaled.
14828 + */
14829 +int
14830 +usb_descriptor_fillbuf(void *buf, unsigned buflen,
14831 + const struct usb_descriptor_header **src)
14832 +{
14833 + u8 *dest = buf;
14834 +
14835 + if (!src)
14836 + return -EINVAL;
14837 +
14838 + /* fill buffer from src[] until null descriptor ptr */
14839 + for (; 0 != *src; src++) {
14840 + unsigned len = (*src)->bLength;
14841 +
14842 + if (len > buflen)
14843 + return -EINVAL;
14844 + memcpy(dest, *src, len);
14845 + buflen -= len;
14846 + dest += len;
14847 + }
14848 + return dest - (u8 *)buf;
14849 +}
14850 +
14851 +
14852 +/**
14853 + * usb_gadget_config_buf - builts a complete configuration descriptor
14854 + * @config: Header for the descriptor, including characteristics such
14855 + * as power requirements and number of interfaces.
14856 + * @desc: Null-terminated vector of pointers to the descriptors (interface,
14857 + * endpoint, etc) defining all functions in this device configuration.
14858 + * @buf: Buffer for the resulting configuration descriptor.
14859 + * @length: Length of buffer. If this is not big enough to hold the
14860 + * entire configuration descriptor, an error code will be returned.
14861 + *
14862 + * This copies descriptors into the response buffer, building a descriptor
14863 + * for that configuration. It returns the buffer length or a negative
14864 + * status code. The config.wTotalLength field is set to match the length
14865 + * of the result, but other descriptor fields (including power usage and
14866 + * interface count) must be set by the caller.
14867 + *
14868 + * Gadget drivers could use this when constructing a config descriptor
14869 + * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the
14870 + * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
14871 + */
14872 +int usb_gadget_config_buf(
14873 + const struct usb_config_descriptor *config,
14874 + void *buf,
14875 + unsigned length,
14876 + const struct usb_descriptor_header **desc
14877 +)
14878 +{
14879 + struct usb_config_descriptor *cp = buf;
14880 + int len;
14881 +
14882 + /* config descriptor first */
14883 + if (length < USB_DT_CONFIG_SIZE || !desc)
14884 + return -EINVAL;
14885 + *cp = *config;
14886 +
14887 + /* then interface/endpoint/class/vendor/... */
14888 + len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
14889 + length - USB_DT_CONFIG_SIZE, desc);
14890 + if (len < 0)
14891 + return len;
14892 + len += USB_DT_CONFIG_SIZE;
14893 + if (len > 0xffff)
14894 + return -EINVAL;
14895 +
14896 + /* patch up the config descriptor */
14897 + cp->bLength = USB_DT_CONFIG_SIZE;
14898 + cp->bDescriptorType = USB_DT_CONFIG;
14899 + cp->wTotalLength = cpu_to_le16(len);
14900 + cp->bmAttributes |= USB_CONFIG_ATT_ONE;
14901 + return len;
14902 +}
14903 +
14904 +/*-------------------------------------------------------------------------*/
14905 +/*-------------------------------------------------------------------------*/
14906 +
14907 +
14908 +#define RBUF_LEN (1024*1024)
14909 +static int rbuf_start;
14910 +static int rbuf_len;
14911 +static __u8 rbuf[RBUF_LEN];
14912 +
14913 +/*-------------------------------------------------------------------------*/
14914 +
14915 +#define DRIVER_VERSION "St Patrick's Day 2004"
14916 +
14917 +static const char shortname [] = "zero";
14918 +static const char longname [] = "YAMAHA YST-MS35D USB Speaker ";
14919 +
14920 +static const char source_sink [] = "source and sink data";
14921 +static const char loopback [] = "loop input to output";
14922 +
14923 +/*-------------------------------------------------------------------------*/
14924 +
14925 +/*
14926 + * driver assumes self-powered hardware, and
14927 + * has no way for users to trigger remote wakeup.
14928 + *
14929 + * this version autoconfigures as much as possible,
14930 + * which is reasonable for most "bulk-only" drivers.
14931 + */
14932 +static const char *EP_IN_NAME; /* source */
14933 +static const char *EP_OUT_NAME; /* sink */
14934 +
14935 +/*-------------------------------------------------------------------------*/
14936 +
14937 +/* big enough to hold our biggest descriptor */
14938 +#define USB_BUFSIZ 512
14939 +
14940 +struct zero_dev {
14941 + spinlock_t lock;
14942 + struct usb_gadget *gadget;
14943 + struct usb_request *req; /* for control responses */
14944 +
14945 + /* when configured, we have one of two configs:
14946 + * - source data (in to host) and sink it (out from host)
14947 + * - or loop it back (out from host back in to host)
14948 + */
14949 + u8 config;
14950 + struct usb_ep *in_ep, *out_ep;
14951 +
14952 + /* autoresume timer */
14953 + struct timer_list resume;
14954 +};
14955 +
14956 +#define xprintk(d,level,fmt,args...) \
14957 + dev_printk(level , &(d)->gadget->dev , fmt , ## args)
14958 +
14959 +#ifdef DEBUG
14960 +#define DBG(dev,fmt,args...) \
14961 + xprintk(dev , KERN_DEBUG , fmt , ## args)
14962 +#else
14963 +#define DBG(dev,fmt,args...) \
14964 + do { } while (0)
14965 +#endif /* DEBUG */
14966 +
14967 +#ifdef VERBOSE
14968 +#define VDBG DBG
14969 +#else
14970 +#define VDBG(dev,fmt,args...) \
14971 + do { } while (0)
14972 +#endif /* VERBOSE */
14973 +
14974 +#define ERROR(dev,fmt,args...) \
14975 + xprintk(dev , KERN_ERR , fmt , ## args)
14976 +#define WARN(dev,fmt,args...) \
14977 + xprintk(dev , KERN_WARNING , fmt , ## args)
14978 +#define INFO(dev,fmt,args...) \
14979 + xprintk(dev , KERN_INFO , fmt , ## args)
14980 +
14981 +/*-------------------------------------------------------------------------*/
14982 +
14983 +static unsigned buflen = 4096;
14984 +static unsigned qlen = 32;
14985 +static unsigned pattern = 0;
14986 +
14987 +module_param (buflen, uint, S_IRUGO|S_IWUSR);
14988 +module_param (qlen, uint, S_IRUGO|S_IWUSR);
14989 +module_param (pattern, uint, S_IRUGO|S_IWUSR);
14990 +
14991 +/*
14992 + * if it's nonzero, autoresume says how many seconds to wait
14993 + * before trying to wake up the host after suspend.
14994 + */
14995 +static unsigned autoresume = 0;
14996 +module_param (autoresume, uint, 0);
14997 +
14998 +/*
14999 + * Normally the "loopback" configuration is second (index 1) so
15000 + * it's not the default. Here's where to change that order, to
15001 + * work better with hosts where config changes are problematic.
15002 + * Or controllers (like superh) that only support one config.
15003 + */
15004 +static int loopdefault = 0;
15005 +
15006 +module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
15007 +
15008 +/*-------------------------------------------------------------------------*/
15009 +
15010 +/* Thanks to NetChip Technologies for donating this product ID.
15011 + *
15012 + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
15013 + * Instead: allocate your own, using normal USB-IF procedures.
15014 + */
15015 +#ifndef CONFIG_USB_ZERO_HNPTEST
15016 +#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
15017 +#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
15018 +#else
15019 +#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */
15020 +#define DRIVER_PRODUCT_NUM 0xbadd
15021 +#endif
15022 +
15023 +/*-------------------------------------------------------------------------*/
15024 +
15025 +/*
15026 + * DESCRIPTORS ... most are static, but strings and (full)
15027 + * configuration descriptors are built on demand.
15028 + */
15029 +
15030 +/*
15031 +#define STRING_MANUFACTURER 25
15032 +#define STRING_PRODUCT 42
15033 +#define STRING_SERIAL 101
15034 +*/
15035 +#define STRING_MANUFACTURER 1
15036 +#define STRING_PRODUCT 2
15037 +#define STRING_SERIAL 3
15038 +
15039 +#define STRING_SOURCE_SINK 250
15040 +#define STRING_LOOPBACK 251
15041 +
15042 +/*
15043 + * This device advertises two configurations; these numbers work
15044 + * on a pxa250 as well as more flexible hardware.
15045 + */
15046 +#define CONFIG_SOURCE_SINK 3
15047 +#define CONFIG_LOOPBACK 2
15048 +
15049 +/*
15050 +static struct usb_device_descriptor
15051 +device_desc = {
15052 + .bLength = sizeof device_desc,
15053 + .bDescriptorType = USB_DT_DEVICE,
15054 +
15055 + .bcdUSB = __constant_cpu_to_le16 (0x0200),
15056 + .bDeviceClass = USB_CLASS_VENDOR_SPEC,
15057 +
15058 + .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
15059 + .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
15060 + .iManufacturer = STRING_MANUFACTURER,
15061 + .iProduct = STRING_PRODUCT,
15062 + .iSerialNumber = STRING_SERIAL,
15063 + .bNumConfigurations = 2,
15064 +};
15065 +*/
15066 +static struct usb_device_descriptor
15067 +device_desc = {
15068 + .bLength = sizeof device_desc,
15069 + .bDescriptorType = USB_DT_DEVICE,
15070 + .bcdUSB = __constant_cpu_to_le16 (0x0100),
15071 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
15072 + .bDeviceSubClass = 0,
15073 + .bDeviceProtocol = 0,
15074 + .bMaxPacketSize0 = 64,
15075 + .bcdDevice = __constant_cpu_to_le16 (0x0100),
15076 + .idVendor = __constant_cpu_to_le16 (0x0499),
15077 + .idProduct = __constant_cpu_to_le16 (0x3002),
15078 + .iManufacturer = STRING_MANUFACTURER,
15079 + .iProduct = STRING_PRODUCT,
15080 + .iSerialNumber = STRING_SERIAL,
15081 + .bNumConfigurations = 1,
15082 +};
15083 +
15084 +static struct usb_config_descriptor
15085 +z_config = {
15086 + .bLength = sizeof z_config,
15087 + .bDescriptorType = USB_DT_CONFIG,
15088 +
15089 + /* compute wTotalLength on the fly */
15090 + .bNumInterfaces = 2,
15091 + .bConfigurationValue = 1,
15092 + .iConfiguration = 0,
15093 + .bmAttributes = 0x40,
15094 + .bMaxPower = 0, /* self-powered */
15095 +};
15096 +
15097 +
15098 +static struct usb_otg_descriptor
15099 +otg_descriptor = {
15100 + .bLength = sizeof otg_descriptor,
15101 + .bDescriptorType = USB_DT_OTG,
15102 +
15103 + .bmAttributes = USB_OTG_SRP,
15104 +};
15105 +
15106 +/* one interface in each configuration */
15107 +#ifdef CONFIG_USB_GADGET_DUALSPEED
15108 +
15109 +/*
15110 + * usb 2.0 devices need to expose both high speed and full speed
15111 + * descriptors, unless they only run at full speed.
15112 + *
15113 + * that means alternate endpoint descriptors (bigger packets)
15114 + * and a "device qualifier" ... plus more construction options
15115 + * for the config descriptor.
15116 + */
15117 +
15118 +static struct usb_qualifier_descriptor
15119 +dev_qualifier = {
15120 + .bLength = sizeof dev_qualifier,
15121 + .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
15122 +
15123 + .bcdUSB = __constant_cpu_to_le16 (0x0200),
15124 + .bDeviceClass = USB_CLASS_VENDOR_SPEC,
15125 +
15126 + .bNumConfigurations = 2,
15127 +};
15128 +
15129 +
15130 +struct usb_cs_as_general_descriptor {
15131 + __u8 bLength;
15132 + __u8 bDescriptorType;
15133 +
15134 + __u8 bDescriptorSubType;
15135 + __u8 bTerminalLink;
15136 + __u8 bDelay;
15137 + __u16 wFormatTag;
15138 +} __attribute__ ((packed));
15139 +
15140 +struct usb_cs_as_format_descriptor {
15141 + __u8 bLength;
15142 + __u8 bDescriptorType;
15143 +
15144 + __u8 bDescriptorSubType;
15145 + __u8 bFormatType;
15146 + __u8 bNrChannels;
15147 + __u8 bSubframeSize;
15148 + __u8 bBitResolution;
15149 + __u8 bSamfreqType;
15150 + __u8 tLowerSamFreq[3];
15151 + __u8 tUpperSamFreq[3];
15152 +} __attribute__ ((packed));
15153 +
15154 +static const struct usb_interface_descriptor
15155 +z_audio_control_if_desc = {
15156 + .bLength = sizeof z_audio_control_if_desc,
15157 + .bDescriptorType = USB_DT_INTERFACE,
15158 + .bInterfaceNumber = 0,
15159 + .bAlternateSetting = 0,
15160 + .bNumEndpoints = 0,
15161 + .bInterfaceClass = USB_CLASS_AUDIO,
15162 + .bInterfaceSubClass = 0x1,
15163 + .bInterfaceProtocol = 0,
15164 + .iInterface = 0,
15165 +};
15166 +
15167 +static const struct usb_interface_descriptor
15168 +z_audio_if_desc = {
15169 + .bLength = sizeof z_audio_if_desc,
15170 + .bDescriptorType = USB_DT_INTERFACE,
15171 + .bInterfaceNumber = 1,
15172 + .bAlternateSetting = 0,
15173 + .bNumEndpoints = 0,
15174 + .bInterfaceClass = USB_CLASS_AUDIO,
15175 + .bInterfaceSubClass = 0x2,
15176 + .bInterfaceProtocol = 0,
15177 + .iInterface = 0,
15178 +};
15179 +
15180 +static const struct usb_interface_descriptor
15181 +z_audio_if_desc2 = {
15182 + .bLength = sizeof z_audio_if_desc,
15183 + .bDescriptorType = USB_DT_INTERFACE,
15184 + .bInterfaceNumber = 1,
15185 + .bAlternateSetting = 1,
15186 + .bNumEndpoints = 1,
15187 + .bInterfaceClass = USB_CLASS_AUDIO,
15188 + .bInterfaceSubClass = 0x2,
15189 + .bInterfaceProtocol = 0,
15190 + .iInterface = 0,
15191 +};
15192 +
15193 +static const struct usb_cs_as_general_descriptor
15194 +z_audio_cs_as_if_desc = {
15195 + .bLength = 7,
15196 + .bDescriptorType = 0x24,
15197 +
15198 + .bDescriptorSubType = 0x01,
15199 + .bTerminalLink = 0x01,
15200 + .bDelay = 0x0,
15201 + .wFormatTag = __constant_cpu_to_le16 (0x0001)
15202 +};
15203 +
15204 +
15205 +static const struct usb_cs_as_format_descriptor
15206 +z_audio_cs_as_format_desc = {
15207 + .bLength = 0xe,
15208 + .bDescriptorType = 0x24,
15209 +
15210 + .bDescriptorSubType = 2,
15211 + .bFormatType = 1,
15212 + .bNrChannels = 1,
15213 + .bSubframeSize = 1,
15214 + .bBitResolution = 8,
15215 + .bSamfreqType = 0,
15216 + .tLowerSamFreq = {0x7e, 0x13, 0x00},
15217 + .tUpperSamFreq = {0xe2, 0xd6, 0x00},
15218 +};
15219 +
15220 +static const struct usb_endpoint_descriptor
15221 +z_iso_ep = {
15222 + .bLength = 0x09,
15223 + .bDescriptorType = 0x05,
15224 + .bEndpointAddress = 0x04,
15225 + .bmAttributes = 0x09,
15226 + .wMaxPacketSize = 0x0038,
15227 + .bInterval = 0x01,
15228 + .bRefresh = 0x00,
15229 + .bSynchAddress = 0x00,
15230 +};
15231 +
15232 +static char z_iso_ep2[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15233 +
15234 +// 9 bytes
15235 +static char z_ac_interface_header_desc[] =
15236 +{ 0x09, 0x24, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x01, 0x01 };
15237 +
15238 +// 12 bytes
15239 +static char z_0[] = {0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02,
15240 + 0x03, 0x00, 0x00, 0x00};
15241 +// 13 bytes
15242 +static char z_1[] = {0x0d, 0x24, 0x06, 0x02, 0x01, 0x02, 0x15, 0x00,
15243 + 0x02, 0x00, 0x02, 0x00, 0x00};
15244 +// 9 bytes
15245 +static char z_2[] = {0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x02,
15246 + 0x00};
15247 +
15248 +static char za_0[] = {0x09, 0x04, 0x01, 0x02, 0x01, 0x01, 0x02, 0x00,
15249 + 0x00};
15250 +
15251 +static char za_1[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15252 +
15253 +static char za_2[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x01, 0x08, 0x00,
15254 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15255 +
15256 +static char za_3[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
15257 + 0x00};
15258 +
15259 +static char za_4[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15260 +
15261 +static char za_5[] = {0x09, 0x04, 0x01, 0x03, 0x01, 0x01, 0x02, 0x00,
15262 + 0x00};
15263 +
15264 +static char za_6[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15265 +
15266 +static char za_7[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x00,
15267 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15268 +
15269 +static char za_8[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
15270 + 0x00};
15271 +
15272 +static char za_9[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15273 +
15274 +static char za_10[] = {0x09, 0x04, 0x01, 0x04, 0x01, 0x01, 0x02, 0x00,
15275 + 0x00};
15276 +
15277 +static char za_11[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15278 +
15279 +static char za_12[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x00,
15280 + 0x73, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15281 +
15282 +static char za_13[] = {0x09, 0x05, 0x04, 0x09, 0xe0, 0x00, 0x01, 0x00,
15283 + 0x00};
15284 +
15285 +static char za_14[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15286 +
15287 +static char za_15[] = {0x09, 0x04, 0x01, 0x05, 0x01, 0x01, 0x02, 0x00,
15288 + 0x00};
15289 +
15290 +static char za_16[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15291 +
15292 +static char za_17[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x03, 0x14, 0x00,
15293 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15294 +
15295 +static char za_18[] = {0x09, 0x05, 0x04, 0x09, 0xa8, 0x00, 0x01, 0x00,
15296 + 0x00};
15297 +
15298 +static char za_19[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15299 +
15300 +static char za_20[] = {0x09, 0x04, 0x01, 0x06, 0x01, 0x01, 0x02, 0x00,
15301 + 0x00};
15302 +
15303 +static char za_21[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15304 +
15305 +static char za_22[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x03, 0x14, 0x00,
15306 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15307 +
15308 +static char za_23[] = {0x09, 0x05, 0x04, 0x09, 0x50, 0x01, 0x01, 0x00,
15309 + 0x00};
15310 +
15311 +static char za_24[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15312 +
15313 +
15314 +
15315 +static const struct usb_descriptor_header *z_function [] = {
15316 + (struct usb_descriptor_header *) &z_audio_control_if_desc,
15317 + (struct usb_descriptor_header *) &z_ac_interface_header_desc,
15318 + (struct usb_descriptor_header *) &z_0,
15319 + (struct usb_descriptor_header *) &z_1,
15320 + (struct usb_descriptor_header *) &z_2,
15321 + (struct usb_descriptor_header *) &z_audio_if_desc,
15322 + (struct usb_descriptor_header *) &z_audio_if_desc2,
15323 + (struct usb_descriptor_header *) &z_audio_cs_as_if_desc,
15324 + (struct usb_descriptor_header *) &z_audio_cs_as_format_desc,
15325 + (struct usb_descriptor_header *) &z_iso_ep,
15326 + (struct usb_descriptor_header *) &z_iso_ep2,
15327 + (struct usb_descriptor_header *) &za_0,
15328 + (struct usb_descriptor_header *) &za_1,
15329 + (struct usb_descriptor_header *) &za_2,
15330 + (struct usb_descriptor_header *) &za_3,
15331 + (struct usb_descriptor_header *) &za_4,
15332 + (struct usb_descriptor_header *) &za_5,
15333 + (struct usb_descriptor_header *) &za_6,
15334 + (struct usb_descriptor_header *) &za_7,
15335 + (struct usb_descriptor_header *) &za_8,
15336 + (struct usb_descriptor_header *) &za_9,
15337 + (struct usb_descriptor_header *) &za_10,
15338 + (struct usb_descriptor_header *) &za_11,
15339 + (struct usb_descriptor_header *) &za_12,
15340 + (struct usb_descriptor_header *) &za_13,
15341 + (struct usb_descriptor_header *) &za_14,
15342 + (struct usb_descriptor_header *) &za_15,
15343 + (struct usb_descriptor_header *) &za_16,
15344 + (struct usb_descriptor_header *) &za_17,
15345 + (struct usb_descriptor_header *) &za_18,
15346 + (struct usb_descriptor_header *) &za_19,
15347 + (struct usb_descriptor_header *) &za_20,
15348 + (struct usb_descriptor_header *) &za_21,
15349 + (struct usb_descriptor_header *) &za_22,
15350 + (struct usb_descriptor_header *) &za_23,
15351 + (struct usb_descriptor_header *) &za_24,
15352 + NULL,
15353 +};
15354 +
15355 +/* maxpacket and other transfer characteristics vary by speed. */
15356 +#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
15357 +
15358 +#else
15359 +
15360 +/* if there's no high speed support, maxpacket doesn't change. */
15361 +#define ep_desc(g,hs,fs) fs
15362 +
15363 +#endif /* !CONFIG_USB_GADGET_DUALSPEED */
15364 +
15365 +static char manufacturer [40];
15366 +//static char serial [40];
15367 +static char serial [] = "Ser 00 em";
15368 +
15369 +/* static strings, in UTF-8 */
15370 +static struct usb_string strings [] = {
15371 + { STRING_MANUFACTURER, manufacturer, },
15372 + { STRING_PRODUCT, longname, },
15373 + { STRING_SERIAL, serial, },
15374 + { STRING_LOOPBACK, loopback, },
15375 + { STRING_SOURCE_SINK, source_sink, },
15376 + { } /* end of list */
15377 +};
15378 +
15379 +static struct usb_gadget_strings stringtab = {
15380 + .language = 0x0409, /* en-us */
15381 + .strings = strings,
15382 +};
15383 +
15384 +/*
15385 + * config descriptors are also handcrafted. these must agree with code
15386 + * that sets configurations, and with code managing interfaces and their
15387 + * altsettings. other complexity may come from:
15388 + *
15389 + * - high speed support, including "other speed config" rules
15390 + * - multiple configurations
15391 + * - interfaces with alternate settings
15392 + * - embedded class or vendor-specific descriptors
15393 + *
15394 + * this handles high speed, and has a second config that could as easily
15395 + * have been an alternate interface setting (on most hardware).
15396 + *
15397 + * NOTE: to demonstrate (and test) more USB capabilities, this driver
15398 + * should include an altsetting to test interrupt transfers, including
15399 + * high bandwidth modes at high speed. (Maybe work like Intel's test
15400 + * device?)
15401 + */
15402 +static int
15403 +config_buf (struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index)
15404 +{
15405 + int len;
15406 + const struct usb_descriptor_header **function;
15407 +
15408 + function = z_function;
15409 + len = usb_gadget_config_buf (&z_config, buf, USB_BUFSIZ, function);
15410 + if (len < 0)
15411 + return len;
15412 + ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
15413 + return len;
15414 +}
15415 +
15416 +/*-------------------------------------------------------------------------*/
15417 +
15418 +static struct usb_request *
15419 +alloc_ep_req (struct usb_ep *ep, unsigned length)
15420 +{
15421 + struct usb_request *req;
15422 +
15423 + req = usb_ep_alloc_request (ep, GFP_ATOMIC);
15424 + if (req) {
15425 + req->length = length;
15426 + req->buf = usb_ep_alloc_buffer (ep, length,
15427 + &req->dma, GFP_ATOMIC);
15428 + if (!req->buf) {
15429 + usb_ep_free_request (ep, req);
15430 + req = NULL;
15431 + }
15432 + }
15433 + return req;
15434 +}
15435 +
15436 +static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
15437 +{
15438 + if (req->buf)
15439 + usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
15440 + usb_ep_free_request (ep, req);
15441 +}
15442 +
15443 +/*-------------------------------------------------------------------------*/
15444 +
15445 +/* optionally require specific source/sink data patterns */
15446 +
15447 +static int
15448 +check_read_data (
15449 + struct zero_dev *dev,
15450 + struct usb_ep *ep,
15451 + struct usb_request *req
15452 +)
15453 +{
15454 + unsigned i;
15455 + u8 *buf = req->buf;
15456 +
15457 + for (i = 0; i < req->actual; i++, buf++) {
15458 + switch (pattern) {
15459 + /* all-zeroes has no synchronization issues */
15460 + case 0:
15461 + if (*buf == 0)
15462 + continue;
15463 + break;
15464 + /* mod63 stays in sync with short-terminated transfers,
15465 + * or otherwise when host and gadget agree on how large
15466 + * each usb transfer request should be. resync is done
15467 + * with set_interface or set_config.
15468 + */
15469 + case 1:
15470 + if (*buf == (u8)(i % 63))
15471 + continue;
15472 + break;
15473 + }
15474 + ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);
15475 + usb_ep_set_halt (ep);
15476 + return -EINVAL;
15477 + }
15478 + return 0;
15479 +}
15480 +
15481 +/*-------------------------------------------------------------------------*/
15482 +
15483 +static void zero_reset_config (struct zero_dev *dev)
15484 +{
15485 + if (dev->config == 0)
15486 + return;
15487 +
15488 + DBG (dev, "reset config\n");
15489 +
15490 + /* just disable endpoints, forcing completion of pending i/o.
15491 + * all our completion handlers free their requests in this case.
15492 + */
15493 + if (dev->in_ep) {
15494 + usb_ep_disable (dev->in_ep);
15495 + dev->in_ep = NULL;
15496 + }
15497 + if (dev->out_ep) {
15498 + usb_ep_disable (dev->out_ep);
15499 + dev->out_ep = NULL;
15500 + }
15501 + dev->config = 0;
15502 + del_timer (&dev->resume);
15503 +}
15504 +
15505 +#define _write(f, buf, sz) (f->f_op->write(f, buf, sz, &f->f_pos))
15506 +
15507 +static void
15508 +zero_isoc_complete (struct usb_ep *ep, struct usb_request *req)
15509 +{
15510 + struct zero_dev *dev = ep->driver_data;
15511 + int status = req->status;
15512 + int i, j;
15513 +
15514 + switch (status) {
15515 +
15516 + case 0: /* normal completion? */
15517 + //printk ("\nzero ---------------> isoc normal completion %d bytes\n", req->actual);
15518 + for (i=0, j=rbuf_start; i<req->actual; i++) {
15519 + //printk ("%02x ", ((__u8*)req->buf)[i]);
15520 + rbuf[j] = ((__u8*)req->buf)[i];
15521 + j++;
15522 + if (j >= RBUF_LEN) j=0;
15523 + }
15524 + rbuf_start = j;
15525 + //printk ("\n\n");
15526 +
15527 + if (rbuf_len < RBUF_LEN) {
15528 + rbuf_len += req->actual;
15529 + if (rbuf_len > RBUF_LEN) {
15530 + rbuf_len = RBUF_LEN;
15531 + }
15532 + }
15533 +
15534 + break;
15535 +
15536 + /* this endpoint is normally active while we're configured */
15537 + case -ECONNABORTED: /* hardware forced ep reset */
15538 + case -ECONNRESET: /* request dequeued */
15539 + case -ESHUTDOWN: /* disconnect from host */
15540 + VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
15541 + req->actual, req->length);
15542 + if (ep == dev->out_ep)
15543 + check_read_data (dev, ep, req);
15544 + free_ep_req (ep, req);
15545 + return;
15546 +
15547 + case -EOVERFLOW: /* buffer overrun on read means that
15548 + * we didn't provide a big enough
15549 + * buffer.
15550 + */
15551 + default:
15552 +#if 1
15553 + DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
15554 + status, req->actual, req->length);
15555 +#endif
15556 + case -EREMOTEIO: /* short read */
15557 + break;
15558 + }
15559 +
15560 + status = usb_ep_queue (ep, req, GFP_ATOMIC);
15561 + if (status) {
15562 + ERROR (dev, "kill %s: resubmit %d bytes --> %d\n",
15563 + ep->name, req->length, status);
15564 + usb_ep_set_halt (ep);
15565 + /* FIXME recover later ... somehow */
15566 + }
15567 +}
15568 +
15569 +static struct usb_request *
15570 +zero_start_isoc_ep (struct usb_ep *ep, int gfp_flags)
15571 +{
15572 + struct usb_request *req;
15573 + int status;
15574 +
15575 + req = alloc_ep_req (ep, 512);
15576 + if (!req)
15577 + return NULL;
15578 +
15579 + req->complete = zero_isoc_complete;
15580 +
15581 + status = usb_ep_queue (ep, req, gfp_flags);
15582 + if (status) {
15583 + struct zero_dev *dev = ep->driver_data;
15584 +
15585 + ERROR (dev, "start %s --> %d\n", ep->name, status);
15586 + free_ep_req (ep, req);
15587 + req = NULL;
15588 + }
15589 +
15590 + return req;
15591 +}
15592 +
15593 +/* change our operational config. this code must agree with the code
15594 + * that returns config descriptors, and altsetting code.
15595 + *
15596 + * it's also responsible for power management interactions. some
15597 + * configurations might not work with our current power sources.
15598 + *
15599 + * note that some device controller hardware will constrain what this
15600 + * code can do, perhaps by disallowing more than one configuration or
15601 + * by limiting configuration choices (like the pxa2xx).
15602 + */
15603 +static int
15604 +zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags)
15605 +{
15606 + int result = 0;
15607 + struct usb_gadget *gadget = dev->gadget;
15608 + const struct usb_endpoint_descriptor *d;
15609 + struct usb_ep *ep;
15610 +
15611 + if (number == dev->config)
15612 + return 0;
15613 +
15614 + zero_reset_config (dev);
15615 +
15616 + gadget_for_each_ep (ep, gadget) {
15617 +
15618 + if (strcmp (ep->name, "ep4") == 0) {
15619 +
15620 + d = (struct usb_endpoint_descripter *)&za_23; // isoc ep desc for audio i/f alt setting 6
15621 + result = usb_ep_enable (ep, d);
15622 +
15623 + if (result == 0) {
15624 + ep->driver_data = dev;
15625 + dev->in_ep = ep;
15626 +
15627 + if (zero_start_isoc_ep (ep, gfp_flags) != 0) {
15628 +
15629 + dev->in_ep = ep;
15630 + continue;
15631 + }
15632 +
15633 + usb_ep_disable (ep);
15634 + result = -EIO;
15635 + }
15636 + }
15637 +
15638 + }
15639 +
15640 + dev->config = number;
15641 + return result;
15642 +}
15643 +
15644 +/*-------------------------------------------------------------------------*/
15645 +
15646 +static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
15647 +{
15648 + if (req->status || req->actual != req->length)
15649 + DBG ((struct zero_dev *) ep->driver_data,
15650 + "setup complete --> %d, %d/%d\n",
15651 + req->status, req->actual, req->length);
15652 +}
15653 +
15654 +/*
15655 + * The setup() callback implements all the ep0 functionality that's
15656 + * not handled lower down, in hardware or the hardware driver (like
15657 + * device and endpoint feature flags, and their status). It's all
15658 + * housekeeping for the gadget function we're implementing. Most of
15659 + * the work is in config-specific setup.
15660 + */
15661 +static int
15662 +zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
15663 +{
15664 + struct zero_dev *dev = get_gadget_data (gadget);
15665 + struct usb_request *req = dev->req;
15666 + int value = -EOPNOTSUPP;
15667 +
15668 + /* usually this stores reply data in the pre-allocated ep0 buffer,
15669 + * but config change events will reconfigure hardware.
15670 + */
15671 + req->zero = 0;
15672 + switch (ctrl->bRequest) {
15673 +
15674 + case USB_REQ_GET_DESCRIPTOR:
15675 +
15676 + switch (ctrl->wValue >> 8) {
15677 +
15678 + case USB_DT_DEVICE:
15679 + value = min (ctrl->wLength, (u16) sizeof device_desc);
15680 + memcpy (req->buf, &device_desc, value);
15681 + break;
15682 +#ifdef CONFIG_USB_GADGET_DUALSPEED
15683 + case USB_DT_DEVICE_QUALIFIER:
15684 + if (!gadget->is_dualspeed)
15685 + break;
15686 + value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
15687 + memcpy (req->buf, &dev_qualifier, value);
15688 + break;
15689 +
15690 + case USB_DT_OTHER_SPEED_CONFIG:
15691 + if (!gadget->is_dualspeed)
15692 + break;
15693 + // FALLTHROUGH
15694 +#endif /* CONFIG_USB_GADGET_DUALSPEED */
15695 + case USB_DT_CONFIG:
15696 + value = config_buf (gadget, req->buf,
15697 + ctrl->wValue >> 8,
15698 + ctrl->wValue & 0xff);
15699 + if (value >= 0)
15700 + value = min (ctrl->wLength, (u16) value);
15701 + break;
15702 +
15703 + case USB_DT_STRING:
15704 + /* wIndex == language code.
15705 + * this driver only handles one language, you can
15706 + * add string tables for other languages, using
15707 + * any UTF-8 characters
15708 + */
15709 + value = usb_gadget_get_string (&stringtab,
15710 + ctrl->wValue & 0xff, req->buf);
15711 + if (value >= 0) {
15712 + value = min (ctrl->wLength, (u16) value);
15713 + }
15714 + break;
15715 + }
15716 + break;
15717 +
15718 + /* currently two configs, two speeds */
15719 + case USB_REQ_SET_CONFIGURATION:
15720 + if (ctrl->bRequestType != 0)
15721 + goto unknown;
15722 +
15723 + spin_lock (&dev->lock);
15724 + value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
15725 + spin_unlock (&dev->lock);
15726 + break;
15727 + case USB_REQ_GET_CONFIGURATION:
15728 + if (ctrl->bRequestType != USB_DIR_IN)
15729 + goto unknown;
15730 + *(u8 *)req->buf = dev->config;
15731 + value = min (ctrl->wLength, (u16) 1);
15732 + break;
15733 +
15734 + /* until we add altsetting support, or other interfaces,
15735 + * only 0/0 are possible. pxa2xx only supports 0/0 (poorly)
15736 + * and already killed pending endpoint I/O.
15737 + */
15738 + case USB_REQ_SET_INTERFACE:
15739 +
15740 + if (ctrl->bRequestType != USB_RECIP_INTERFACE)
15741 + goto unknown;
15742 + spin_lock (&dev->lock);
15743 + if (dev->config) {
15744 + u8 config = dev->config;
15745 +
15746 + /* resets interface configuration, forgets about
15747 + * previous transaction state (queued bufs, etc)
15748 + * and re-inits endpoint state (toggle etc)
15749 + * no response queued, just zero status == success.
15750 + * if we had more than one interface we couldn't
15751 + * use this "reset the config" shortcut.
15752 + */
15753 + zero_reset_config (dev);
15754 + zero_set_config (dev, config, GFP_ATOMIC);
15755 + value = 0;
15756 + }
15757 + spin_unlock (&dev->lock);
15758 + break;
15759 + case USB_REQ_GET_INTERFACE:
15760 + if ((ctrl->bRequestType == 0x21) && (ctrl->wIndex == 0x02)) {
15761 + value = ctrl->wLength;
15762 + break;
15763 + }
15764 + else {
15765 + if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
15766 + goto unknown;
15767 + if (!dev->config)
15768 + break;
15769 + if (ctrl->wIndex != 0) {
15770 + value = -EDOM;
15771 + break;
15772 + }
15773 + *(u8 *)req->buf = 0;
15774 + value = min (ctrl->wLength, (u16) 1);
15775 + }
15776 + break;
15777 +
15778 + /*
15779 + * These are the same vendor-specific requests supported by
15780 + * Intel's USB 2.0 compliance test devices. We exceed that
15781 + * device spec by allowing multiple-packet requests.
15782 + */
15783 + case 0x5b: /* control WRITE test -- fill the buffer */
15784 + if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
15785 + goto unknown;
15786 + if (ctrl->wValue || ctrl->wIndex)
15787 + break;
15788 + /* just read that many bytes into the buffer */
15789 + if (ctrl->wLength > USB_BUFSIZ)
15790 + break;
15791 + value = ctrl->wLength;
15792 + break;
15793 + case 0x5c: /* control READ test -- return the buffer */
15794 + if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
15795 + goto unknown;
15796 + if (ctrl->wValue || ctrl->wIndex)
15797 + break;
15798 + /* expect those bytes are still in the buffer; send back */
15799 + if (ctrl->wLength > USB_BUFSIZ
15800 + || ctrl->wLength != req->length)
15801 + break;
15802 + value = ctrl->wLength;
15803 + break;
15804 +
15805 + case 0x01: // SET_CUR
15806 + case 0x02:
15807 + case 0x03:
15808 + case 0x04:
15809 + case 0x05:
15810 + value = ctrl->wLength;
15811 + break;
15812 + case 0x81:
15813 + switch (ctrl->wValue) {
15814 + case 0x0201:
15815 + case 0x0202:
15816 + ((u8*)req->buf)[0] = 0x00;
15817 + ((u8*)req->buf)[1] = 0xe3;
15818 + break;
15819 + case 0x0300:
15820 + case 0x0500:
15821 + ((u8*)req->buf)[0] = 0x00;
15822 + break;
15823 + }
15824 + //((u8*)req->buf)[0] = 0x81;
15825 + //((u8*)req->buf)[1] = 0x81;
15826 + value = ctrl->wLength;
15827 + break;
15828 + case 0x82:
15829 + switch (ctrl->wValue) {
15830 + case 0x0201:
15831 + case 0x0202:
15832 + ((u8*)req->buf)[0] = 0x00;
15833 + ((u8*)req->buf)[1] = 0xc3;
15834 + break;
15835 + case 0x0300:
15836 + case 0x0500:
15837 + ((u8*)req->buf)[0] = 0x00;
15838 + break;
15839 + }
15840 + //((u8*)req->buf)[0] = 0x82;
15841 + //((u8*)req->buf)[1] = 0x82;
15842 + value = ctrl->wLength;
15843 + break;
15844 + case 0x83:
15845 + switch (ctrl->wValue) {
15846 + case 0x0201:
15847 + case 0x0202:
15848 + ((u8*)req->buf)[0] = 0x00;
15849 + ((u8*)req->buf)[1] = 0x00;
15850 + break;
15851 + case 0x0300:
15852 + ((u8*)req->buf)[0] = 0x60;
15853 + break;
15854 + case 0x0500:
15855 + ((u8*)req->buf)[0] = 0x18;
15856 + break;
15857 + }
15858 + //((u8*)req->buf)[0] = 0x83;
15859 + //((u8*)req->buf)[1] = 0x83;
15860 + value = ctrl->wLength;
15861 + break;
15862 + case 0x84:
15863 + switch (ctrl->wValue) {
15864 + case 0x0201:
15865 + case 0x0202:
15866 + ((u8*)req->buf)[0] = 0x00;
15867 + ((u8*)req->buf)[1] = 0x01;
15868 + break;
15869 + case 0x0300:
15870 + case 0x0500:
15871 + ((u8*)req->buf)[0] = 0x08;
15872 + break;
15873 + }
15874 + //((u8*)req->buf)[0] = 0x84;
15875 + //((u8*)req->buf)[1] = 0x84;
15876 + value = ctrl->wLength;
15877 + break;
15878 + case 0x85:
15879 + ((u8*)req->buf)[0] = 0x85;
15880 + ((u8*)req->buf)[1] = 0x85;
15881 + value = ctrl->wLength;
15882 + break;
15883 +
15884 +
15885 + default:
15886 +unknown:
15887 + printk("unknown control req%02x.%02x v%04x i%04x l%d\n",
15888 + ctrl->bRequestType, ctrl->bRequest,
15889 + ctrl->wValue, ctrl->wIndex, ctrl->wLength);
15890 + }
15891 +
15892 + /* respond with data transfer before status phase? */
15893 + if (value >= 0) {
15894 + req->length = value;
15895 + req->zero = value < ctrl->wLength
15896 + && (value % gadget->ep0->maxpacket) == 0;
15897 + value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
15898 + if (value < 0) {
15899 + DBG (dev, "ep_queue < 0 --> %d\n", value);
15900 + req->status = 0;
15901 + zero_setup_complete (gadget->ep0, req);
15902 + }
15903 + }
15904 +
15905 + /* device either stalls (value < 0) or reports success */
15906 + return value;
15907 +}
15908 +
15909 +static void
15910 +zero_disconnect (struct usb_gadget *gadget)
15911 +{
15912 + struct zero_dev *dev = get_gadget_data (gadget);
15913 + unsigned long flags;
15914 +
15915 + spin_lock_irqsave (&dev->lock, flags);
15916 + zero_reset_config (dev);
15917 +
15918 + /* a more significant application might have some non-usb
15919 + * activities to quiesce here, saving resources like power
15920 + * or pushing the notification up a network stack.
15921 + */
15922 + spin_unlock_irqrestore (&dev->lock, flags);
15923 +
15924 + /* next we may get setup() calls to enumerate new connections;
15925 + * or an unbind() during shutdown (including removing module).
15926 + */
15927 +}
15928 +
15929 +static void
15930 +zero_autoresume (unsigned long _dev)
15931 +{
15932 + struct zero_dev *dev = (struct zero_dev *) _dev;
15933 + int status;
15934 +
15935 + /* normally the host would be woken up for something
15936 + * more significant than just a timer firing...
15937 + */
15938 + if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
15939 + status = usb_gadget_wakeup (dev->gadget);
15940 + DBG (dev, "wakeup --> %d\n", status);
15941 + }
15942 +}
15943 +
15944 +/*-------------------------------------------------------------------------*/
15945 +
15946 +static void
15947 +zero_unbind (struct usb_gadget *gadget)
15948 +{
15949 + struct zero_dev *dev = get_gadget_data (gadget);
15950 +
15951 + DBG (dev, "unbind\n");
15952 +
15953 + /* we've already been disconnected ... no i/o is active */
15954 + if (dev->req)
15955 + free_ep_req (gadget->ep0, dev->req);
15956 + del_timer_sync (&dev->resume);
15957 + kfree (dev);
15958 + set_gadget_data (gadget, NULL);
15959 +}
15960 +
15961 +static int
15962 +zero_bind (struct usb_gadget *gadget)
15963 +{
15964 + struct zero_dev *dev;
15965 + //struct usb_ep *ep;
15966 +
15967 + printk("binding\n");
15968 + /*
15969 + * DRIVER POLICY CHOICE: you may want to do this differently.
15970 + * One thing to avoid is reusing a bcdDevice revision code
15971 + * with different host-visible configurations or behavior
15972 + * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc
15973 + */
15974 + //device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
15975 +
15976 +
15977 + /* ok, we made sense of the hardware ... */
15978 + dev = kmalloc (sizeof *dev, SLAB_KERNEL);
15979 + if (!dev)
15980 + return -ENOMEM;
15981 + memset (dev, 0, sizeof *dev);
15982 + spin_lock_init (&dev->lock);
15983 + dev->gadget = gadget;
15984 + set_gadget_data (gadget, dev);
15985 +
15986 + /* preallocate control response and buffer */
15987 + dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
15988 + if (!dev->req)
15989 + goto enomem;
15990 + dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
15991 + &dev->req->dma, GFP_KERNEL);
15992 + if (!dev->req->buf)
15993 + goto enomem;
15994 +
15995 + dev->req->complete = zero_setup_complete;
15996 +
15997 + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
15998 +
15999 +#ifdef CONFIG_USB_GADGET_DUALSPEED
16000 + /* assume ep0 uses the same value for both speeds ... */
16001 + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
16002 +
16003 + /* and that all endpoints are dual-speed */
16004 + //hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
16005 + //hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
16006 +#endif
16007 +
16008 + usb_gadget_set_selfpowered (gadget);
16009 +
16010 + init_timer (&dev->resume);
16011 + dev->resume.function = zero_autoresume;
16012 + dev->resume.data = (unsigned long) dev;
16013 +
16014 + gadget->ep0->driver_data = dev;
16015 +
16016 + INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
16017 + INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
16018 + EP_OUT_NAME, EP_IN_NAME);
16019 +
16020 + snprintf (manufacturer, sizeof manufacturer,
16021 + UTS_SYSNAME " " UTS_RELEASE " with %s",
16022 + gadget->name);
16023 +
16024 + return 0;
16025 +
16026 +enomem:
16027 + zero_unbind (gadget);
16028 + return -ENOMEM;
16029 +}
16030 +
16031 +/*-------------------------------------------------------------------------*/
16032 +
16033 +static void
16034 +zero_suspend (struct usb_gadget *gadget)
16035 +{
16036 + struct zero_dev *dev = get_gadget_data (gadget);
16037 +
16038 + if (gadget->speed == USB_SPEED_UNKNOWN)
16039 + return;
16040 +
16041 + if (autoresume) {
16042 + mod_timer (&dev->resume, jiffies + (HZ * autoresume));
16043 + DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
16044 + } else
16045 + DBG (dev, "suspend\n");
16046 +}
16047 +
16048 +static void
16049 +zero_resume (struct usb_gadget *gadget)
16050 +{
16051 + struct zero_dev *dev = get_gadget_data (gadget);
16052 +
16053 + DBG (dev, "resume\n");
16054 + del_timer (&dev->resume);
16055 +}
16056 +
16057 +
16058 +/*-------------------------------------------------------------------------*/
16059 +
16060 +static struct usb_gadget_driver zero_driver = {
16061 +#ifdef CONFIG_USB_GADGET_DUALSPEED
16062 + .speed = USB_SPEED_HIGH,
16063 +#else
16064 + .speed = USB_SPEED_FULL,
16065 +#endif
16066 + .function = (char *) longname,
16067 + .bind = zero_bind,
16068 + .unbind = zero_unbind,
16069 +
16070 + .setup = zero_setup,
16071 + .disconnect = zero_disconnect,
16072 +
16073 + .suspend = zero_suspend,
16074 + .resume = zero_resume,
16075 +
16076 + .driver = {
16077 + .name = (char *) shortname,
16078 + // .shutdown = ...
16079 + // .suspend = ...
16080 + // .resume = ...
16081 + },
16082 +};
16083 +
16084 +MODULE_AUTHOR ("David Brownell");
16085 +MODULE_LICENSE ("Dual BSD/GPL");
16086 +
16087 +static struct proc_dir_entry *pdir, *pfile;
16088 +
16089 +static int isoc_read_data (char *page, char **start,
16090 + off_t off, int count,
16091 + int *eof, void *data)
16092 +{
16093 + int i;
16094 + static int c = 0;
16095 + static int done = 0;
16096 + static int s = 0;
16097 +
16098 +/*
16099 + printk ("\ncount: %d\n", count);
16100 + printk ("rbuf_start: %d\n", rbuf_start);
16101 + printk ("rbuf_len: %d\n", rbuf_len);
16102 + printk ("off: %d\n", off);
16103 + printk ("start: %p\n\n", *start);
16104 +*/
16105 + if (done) {
16106 + c = 0;
16107 + done = 0;
16108 + *eof = 1;
16109 + return 0;
16110 + }
16111 +
16112 + if (c == 0) {
16113 + if (rbuf_len == RBUF_LEN)
16114 + s = rbuf_start;
16115 + else s = 0;
16116 + }
16117 +
16118 + for (i=0; i<count && c<rbuf_len; i++, c++) {
16119 + page[i] = rbuf[(c+s) % RBUF_LEN];
16120 + }
16121 + *start = page;
16122 +
16123 + if (c >= rbuf_len) {
16124 + *eof = 1;
16125 + done = 1;
16126 + }
16127 +
16128 +
16129 + return i;
16130 +}
16131 +
16132 +static int __init init (void)
16133 +{
16134 +
16135 + int retval = 0;
16136 +
16137 + pdir = proc_mkdir("isoc_test", NULL);
16138 + if(pdir == NULL) {
16139 + retval = -ENOMEM;
16140 + printk("Error creating dir\n");
16141 + goto done;
16142 + }
16143 + pdir->owner = THIS_MODULE;
16144 +
16145 + pfile = create_proc_read_entry("isoc_data",
16146 + 0444, pdir,
16147 + isoc_read_data,
16148 + NULL);
16149 + if (pfile == NULL) {
16150 + retval = -ENOMEM;
16151 + printk("Error creating file\n");
16152 + goto no_file;
16153 + }
16154 + pfile->owner = THIS_MODULE;
16155 +
16156 + return usb_gadget_register_driver (&zero_driver);
16157 +
16158 + no_file:
16159 + remove_proc_entry("isoc_data", NULL);
16160 + done:
16161 + return retval;
16162 +}
16163 +module_init (init);
16164 +
16165 +static void __exit cleanup (void)
16166 +{
16167 +
16168 + usb_gadget_unregister_driver (&zero_driver);
16169 +
16170 + remove_proc_entry("isoc_data", pdir);
16171 + remove_proc_entry("isoc_test", NULL);
16172 +}
16173 +module_exit (cleanup);
16174 --- /dev/null
16175 +++ b/drivers/usb/host/dwc_otg/dwc_cfi_common.h
16176 @@ -0,0 +1,142 @@
16177 +/* ==========================================================================
16178 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
16179 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
16180 + * otherwise expressly agreed to in writing between Synopsys and you.
16181 + *
16182 + * The Software IS NOT an item of Licensed Software or Licensed Product under
16183 + * any End User Software License Agreement or Agreement for Licensed Product
16184 + * with Synopsys or any supplement thereto. You are permitted to use and
16185 + * redistribute this Software in source and binary forms, with or without
16186 + * modification, provided that redistributions of source code must retain this
16187 + * notice. You may not view, use, disclose, copy or distribute this file or
16188 + * any information contained herein except pursuant to this license grant from
16189 + * Synopsys. If you do not agree with this notice, including the disclaimer
16190 + * below, then you are not authorized to use the Software.
16191 + *
16192 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
16193 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16194 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16195 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
16196 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16197 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16198 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
16199 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16200 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16201 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
16202 + * DAMAGE.
16203 + * ========================================================================== */
16204 +
16205 +#if !defined(__DWC_CFI_COMMON_H__)
16206 +#define __DWC_CFI_COMMON_H__
16207 +
16208 +//#include <linux/types.h>
16209 +
16210 +/**
16211 + * @file
16212 + *
16213 + * This file contains the CFI specific common constants, interfaces
16214 + * (functions and macros) and structures for Linux. No PCD specific
16215 + * data structure or definition is to be included in this file.
16216 + *
16217 + */
16218 +
16219 +/** This is a request for all Core Features */
16220 +#define VEN_CORE_GET_FEATURES 0xB1
16221 +
16222 +/** This is a request to get the value of a specific Core Feature */
16223 +#define VEN_CORE_GET_FEATURE 0xB2
16224 +
16225 +/** This command allows the host to set the value of a specific Core Feature */
16226 +#define VEN_CORE_SET_FEATURE 0xB3
16227 +
16228 +/** This command allows the host to set the default values of
16229 + * either all or any specific Core Feature
16230 + */
16231 +#define VEN_CORE_RESET_FEATURES 0xB4
16232 +
16233 +/** This command forces the PCD to write the deferred values of a Core Features */
16234 +#define VEN_CORE_ACTIVATE_FEATURES 0xB5
16235 +
16236 +/** This request reads a DWORD value from a register at the specified offset */
16237 +#define VEN_CORE_READ_REGISTER 0xB6
16238 +
16239 +/** This request writes a DWORD value into a register at the specified offset */
16240 +#define VEN_CORE_WRITE_REGISTER 0xB7
16241 +
16242 +/** This structure is the header of the Core Features dataset returned to
16243 + * the Host
16244 + */
16245 +struct cfi_all_features_header {
16246 +/** The features header structure length is */
16247 +#define CFI_ALL_FEATURES_HDR_LEN 8
16248 + /**
16249 + * The total length of the features dataset returned to the Host
16250 + */
16251 + uint16_t wTotalLen;
16252 +
16253 + /**
16254 + * CFI version number inBinary-Coded Decimal (i.e., 1.00 is 100H).
16255 + * This field identifies the version of the CFI Specification with which
16256 + * the device is compliant.
16257 + */
16258 + uint16_t wVersion;
16259 +
16260 + /** The ID of the Core */
16261 + uint16_t wCoreID;
16262 +#define CFI_CORE_ID_UDC 1
16263 +#define CFI_CORE_ID_OTG 2
16264 +#define CFI_CORE_ID_WUDEV 3
16265 +
16266 + /** Number of features returned by VEN_CORE_GET_FEATURES request */
16267 + uint16_t wNumFeatures;
16268 +} UPACKED;
16269 +
16270 +typedef struct cfi_all_features_header cfi_all_features_header_t;
16271 +
16272 +/** This structure is a header of the Core Feature descriptor dataset returned to
16273 + * the Host after the VEN_CORE_GET_FEATURES request
16274 + */
16275 +struct cfi_feature_desc_header {
16276 +#define CFI_FEATURE_DESC_HDR_LEN 8
16277 +
16278 + /** The feature ID */
16279 + uint16_t wFeatureID;
16280 +
16281 + /** Length of this feature descriptor in bytes - including the
16282 + * length of the feature name string
16283 + */
16284 + uint16_t wLength;
16285 +
16286 + /** The data length of this feature in bytes */
16287 + uint16_t wDataLength;
16288 +
16289 + /**
16290 + * Attributes of this features
16291 + * D0: Access rights
16292 + * 0 - Read/Write
16293 + * 1 - Read only
16294 + */
16295 + uint8_t bmAttributes;
16296 +#define CFI_FEATURE_ATTR_RO 1
16297 +#define CFI_FEATURE_ATTR_RW 0
16298 +
16299 + /** Length of the feature name in bytes */
16300 + uint8_t bNameLen;
16301 +
16302 + /** The feature name buffer */
16303 + //uint8_t *name;
16304 +} UPACKED;
16305 +
16306 +typedef struct cfi_feature_desc_header cfi_feature_desc_header_t;
16307 +
16308 +/**
16309 + * This structure describes a NULL terminated string referenced by its id field.
16310 + * It is very similar to usb_string structure but has the id field type set to 16-bit.
16311 + */
16312 +struct cfi_string {
16313 + uint16_t id;
16314 + const uint8_t *s;
16315 +};
16316 +typedef struct cfi_string cfi_string_t;
16317 +
16318 +#endif
16319 --- /dev/null
16320 +++ b/drivers/usb/host/dwc_otg/dwc_otg_adp.c
16321 @@ -0,0 +1,854 @@
16322 +/* ==========================================================================
16323 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.c $
16324 + * $Revision: #12 $
16325 + * $Date: 2011/10/26 $
16326 + * $Change: 1873028 $
16327 + *
16328 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
16329 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
16330 + * otherwise expressly agreed to in writing between Synopsys and you.
16331 + *
16332 + * The Software IS NOT an item of Licensed Software or Licensed Product under
16333 + * any End User Software License Agreement or Agreement for Licensed Product
16334 + * with Synopsys or any supplement thereto. You are permitted to use and
16335 + * redistribute this Software in source and binary forms, with or without
16336 + * modification, provided that redistributions of source code must retain this
16337 + * notice. You may not view, use, disclose, copy or distribute this file or
16338 + * any information contained herein except pursuant to this license grant from
16339 + * Synopsys. If you do not agree with this notice, including the disclaimer
16340 + * below, then you are not authorized to use the Software.
16341 + *
16342 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
16343 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16344 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16345 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
16346 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16347 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16348 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
16349 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16350 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16351 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
16352 + * DAMAGE.
16353 + * ========================================================================== */
16354 +
16355 +#include "dwc_os.h"
16356 +#include "dwc_otg_regs.h"
16357 +#include "dwc_otg_cil.h"
16358 +#include "dwc_otg_adp.h"
16359 +
16360 +/** @file
16361 + *
16362 + * This file contains the most of the Attach Detect Protocol implementation for
16363 + * the driver to support OTG Rev2.0.
16364 + *
16365 + */
16366 +
16367 +void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value)
16368 +{
16369 + adpctl_data_t adpctl;
16370 +
16371 + adpctl.d32 = value;
16372 + adpctl.b.ar = 0x2;
16373 +
16374 + DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
16375 +
16376 + while (adpctl.b.ar) {
16377 + adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
16378 + }
16379 +
16380 +}
16381 +
16382 +/**
16383 + * Function is called to read ADP registers
16384 + */
16385 +uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if)
16386 +{
16387 + adpctl_data_t adpctl;
16388 +
16389 + adpctl.d32 = 0;
16390 + adpctl.b.ar = 0x1;
16391 +
16392 + DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
16393 +
16394 + while (adpctl.b.ar) {
16395 + adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
16396 + }
16397 +
16398 + return adpctl.d32;
16399 +}
16400 +
16401 +/**
16402 + * Function is called to read ADPCTL register and filter Write-clear bits
16403 + */
16404 +uint32_t dwc_otg_adp_read_reg_filter(dwc_otg_core_if_t * core_if)
16405 +{
16406 + adpctl_data_t adpctl;
16407 +
16408 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16409 + adpctl.b.adp_tmout_int = 0;
16410 + adpctl.b.adp_prb_int = 0;
16411 + adpctl.b.adp_tmout_int = 0;
16412 +
16413 + return adpctl.d32;
16414 +}
16415 +
16416 +/**
16417 + * Function is called to write ADP registers
16418 + */
16419 +void dwc_otg_adp_modify_reg(dwc_otg_core_if_t * core_if, uint32_t clr,
16420 + uint32_t set)
16421 +{
16422 + dwc_otg_adp_write_reg(core_if,
16423 + (dwc_otg_adp_read_reg(core_if) & (~clr)) | set);
16424 +}
16425 +
16426 +static void adp_sense_timeout(void *ptr)
16427 +{
16428 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
16429 + core_if->adp.sense_timer_started = 0;
16430 + DWC_PRINTF("ADP SENSE TIMEOUT\n");
16431 + if (core_if->adp_enable) {
16432 + dwc_otg_adp_sense_stop(core_if);
16433 + dwc_otg_adp_probe_start(core_if);
16434 + }
16435 +}
16436 +
16437 +/**
16438 + * This function is called when the ADP vbus timer expires. Timeout is 1.1s.
16439 + */
16440 +static void adp_vbuson_timeout(void *ptr)
16441 +{
16442 + gpwrdn_data_t gpwrdn;
16443 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
16444 + hprt0_data_t hprt0 = {.d32 = 0 };
16445 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
16446 + DWC_PRINTF("%s: 1.1 seconds expire after turning on VBUS\n",__FUNCTION__);
16447 + if (core_if) {
16448 + core_if->adp.vbuson_timer_started = 0;
16449 + /* Turn off vbus */
16450 + hprt0.b.prtpwr = 1;
16451 + DWC_MODIFY_REG32(core_if->host_if->hprt0, hprt0.d32, 0);
16452 + gpwrdn.d32 = 0;
16453 +
16454 + /* Power off the core */
16455 + if (core_if->power_down == 2) {
16456 + /* Enable Wakeup Logic */
16457 +// gpwrdn.b.wkupactiv = 1;
16458 + gpwrdn.b.pmuactv = 0;
16459 + gpwrdn.b.pwrdnrstn = 1;
16460 + gpwrdn.b.pwrdnclmp = 1;
16461 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
16462 + gpwrdn.d32);
16463 +
16464 + /* Suspend the Phy Clock */
16465 + pcgcctl.b.stoppclk = 1;
16466 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
16467 +
16468 + /* Switch on VDD */
16469 +// gpwrdn.b.wkupactiv = 1;
16470 + gpwrdn.b.pmuactv = 1;
16471 + gpwrdn.b.pwrdnrstn = 1;
16472 + gpwrdn.b.pwrdnclmp = 1;
16473 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
16474 + gpwrdn.d32);
16475 + } else {
16476 + /* Enable Power Down Logic */
16477 + gpwrdn.b.pmuintsel = 1;
16478 + gpwrdn.b.pmuactv = 1;
16479 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16480 + }
16481 +
16482 + /* Power off the core */
16483 + if (core_if->power_down == 2) {
16484 + gpwrdn.d32 = 0;
16485 + gpwrdn.b.pwrdnswtch = 1;
16486 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn,
16487 + gpwrdn.d32, 0);
16488 + }
16489 +
16490 + /* Unmask SRP detected interrupt from Power Down Logic */
16491 + gpwrdn.d32 = 0;
16492 + gpwrdn.b.srp_det_msk = 1;
16493 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16494 +
16495 + dwc_otg_adp_probe_start(core_if);
16496 + dwc_otg_dump_global_registers(core_if);
16497 + dwc_otg_dump_host_registers(core_if);
16498 + }
16499 +
16500 +}
16501 +
16502 +/**
16503 + * Start the ADP Initial Probe timer to detect if Port Connected interrupt is
16504 + * not asserted within 1.1 seconds.
16505 + *
16506 + * @param core_if the pointer to core_if strucure.
16507 + */
16508 +void dwc_otg_adp_vbuson_timer_start(dwc_otg_core_if_t * core_if)
16509 +{
16510 + core_if->adp.vbuson_timer_started = 1;
16511 + if (core_if->adp.vbuson_timer)
16512 + {
16513 + DWC_PRINTF("SCHEDULING VBUSON TIMER\n");
16514 + /* 1.1 secs + 60ms necessary for cil_hcd_start*/
16515 + DWC_TIMER_SCHEDULE(core_if->adp.vbuson_timer, 1160);
16516 + } else {
16517 + DWC_WARN("VBUSON_TIMER = %p\n",core_if->adp.vbuson_timer);
16518 + }
16519 +}
16520 +
16521 +#if 0
16522 +/**
16523 + * Masks all DWC OTG core interrupts
16524 + *
16525 + */
16526 +static void mask_all_interrupts(dwc_otg_core_if_t * core_if)
16527 +{
16528 + int i;
16529 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
16530 +
16531 + /* Mask Host Interrupts */
16532 +
16533 + /* Clear and disable HCINTs */
16534 + for (i = 0; i < core_if->core_params->host_channels; i++) {
16535 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk, 0);
16536 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcint, 0xFFFFFFFF);
16537 +
16538 + }
16539 +
16540 + /* Clear and disable HAINT */
16541 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk, 0x0000);
16542 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haint, 0xFFFFFFFF);
16543 +
16544 + /* Mask Device Interrupts */
16545 + if (!core_if->multiproc_int_enable) {
16546 + /* Clear and disable IN Endpoint interrupts */
16547 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, 0);
16548 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
16549 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
16550 + diepint, 0xFFFFFFFF);
16551 + }
16552 +
16553 + /* Clear and disable OUT Endpoint interrupts */
16554 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, 0);
16555 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
16556 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
16557 + doepint, 0xFFFFFFFF);
16558 + }
16559 +
16560 + /* Clear and disable DAINT */
16561 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daint,
16562 + 0xFFFFFFFF);
16563 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, 0);
16564 + } else {
16565 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
16566 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
16567 + diepeachintmsk[i], 0);
16568 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
16569 + diepint, 0xFFFFFFFF);
16570 + }
16571 +
16572 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
16573 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
16574 + doepeachintmsk[i], 0);
16575 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
16576 + doepint, 0xFFFFFFFF);
16577 + }
16578 +
16579 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
16580 + 0);
16581 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachint,
16582 + 0xFFFFFFFF);
16583 +
16584 + }
16585 +
16586 + /* Disable interrupts */
16587 + ahbcfg.b.glblintrmsk = 1;
16588 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
16589 +
16590 + /* Disable all interrupts. */
16591 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
16592 +
16593 + /* Clear any pending interrupts */
16594 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
16595 +
16596 + /* Clear any pending OTG Interrupts */
16597 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, 0xFFFFFFFF);
16598 +}
16599 +
16600 +/**
16601 + * Unmask Port Connection Detected interrupt
16602 + *
16603 + */
16604 +static void unmask_conn_det_intr(dwc_otg_core_if_t * core_if)
16605 +{
16606 + gintmsk_data_t gintmsk = {.d32 = 0,.b.portintr = 1 };
16607 +
16608 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
16609 +}
16610 +#endif
16611 +
16612 +/**
16613 + * Starts the ADP Probing
16614 + *
16615 + * @param core_if the pointer to core_if structure.
16616 + */
16617 +uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if)
16618 +{
16619 +
16620 + adpctl_data_t adpctl = {.d32 = 0};
16621 + gpwrdn_data_t gpwrdn;
16622 +#if 0
16623 + adpctl_data_t adpctl_int = {.d32 = 0, .b.adp_prb_int = 1,
16624 + .b.adp_sns_int = 1, b.adp_tmout_int};
16625 +#endif
16626 + dwc_otg_disable_global_interrupts(core_if);
16627 + DWC_PRINTF("ADP Probe Start\n");
16628 + core_if->adp.probe_enabled = 1;
16629 +
16630 + adpctl.b.adpres = 1;
16631 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16632 +
16633 + while (adpctl.b.adpres) {
16634 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16635 + }
16636 +
16637 + adpctl.d32 = 0;
16638 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
16639 +
16640 + /* In Host mode unmask SRP detected interrupt */
16641 + gpwrdn.d32 = 0;
16642 + gpwrdn.b.sts_chngint_msk = 1;
16643 + if (!gpwrdn.b.idsts) {
16644 + gpwrdn.b.srp_det_msk = 1;
16645 + }
16646 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16647 +
16648 + adpctl.b.adp_tmout_int_msk = 1;
16649 + adpctl.b.adp_prb_int_msk = 1;
16650 + adpctl.b.prb_dschg = 1;
16651 + adpctl.b.prb_delta = 1;
16652 + adpctl.b.prb_per = 1;
16653 + adpctl.b.adpen = 1;
16654 + adpctl.b.enaprb = 1;
16655 +
16656 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16657 + DWC_PRINTF("ADP Probe Finish\n");
16658 + return 0;
16659 +}
16660 +
16661 +/**
16662 + * Starts the ADP Sense timer to detect if ADP Sense interrupt is not asserted
16663 + * within 3 seconds.
16664 + *
16665 + * @param core_if the pointer to core_if strucure.
16666 + */
16667 +void dwc_otg_adp_sense_timer_start(dwc_otg_core_if_t * core_if)
16668 +{
16669 + core_if->adp.sense_timer_started = 1;
16670 + DWC_TIMER_SCHEDULE(core_if->adp.sense_timer, 3000 /* 3 secs */ );
16671 +}
16672 +
16673 +/**
16674 + * Starts the ADP Sense
16675 + *
16676 + * @param core_if the pointer to core_if strucure.
16677 + */
16678 +uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if)
16679 +{
16680 + adpctl_data_t adpctl;
16681 +
16682 + DWC_PRINTF("ADP Sense Start\n");
16683 +
16684 + /* Unmask ADP sense interrupt and mask all other from the core */
16685 + adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
16686 + adpctl.b.adp_sns_int_msk = 1;
16687 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16688 + dwc_otg_disable_global_interrupts(core_if); // vahrama
16689 +
16690 + /* Set ADP reset bit*/
16691 + adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
16692 + adpctl.b.adpres = 1;
16693 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16694 +
16695 + while (adpctl.b.adpres) {
16696 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16697 + }
16698 +
16699 + adpctl.b.adpres = 0;
16700 + adpctl.b.adpen = 1;
16701 + adpctl.b.enasns = 1;
16702 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16703 +
16704 + dwc_otg_adp_sense_timer_start(core_if);
16705 +
16706 + return 0;
16707 +}
16708 +
16709 +/**
16710 + * Stops the ADP Probing
16711 + *
16712 + * @param core_if the pointer to core_if strucure.
16713 + */
16714 +uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if)
16715 +{
16716 +
16717 + adpctl_data_t adpctl;
16718 + DWC_PRINTF("Stop ADP probe\n");
16719 + core_if->adp.probe_enabled = 0;
16720 + core_if->adp.probe_counter = 0;
16721 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16722 +
16723 + adpctl.b.adpen = 0;
16724 + adpctl.b.adp_prb_int = 1;
16725 + adpctl.b.adp_tmout_int = 1;
16726 + adpctl.b.adp_sns_int = 1;
16727 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16728 +
16729 + return 0;
16730 +}
16731 +
16732 +/**
16733 + * Stops the ADP Sensing
16734 + *
16735 + * @param core_if the pointer to core_if strucure.
16736 + */
16737 +uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if)
16738 +{
16739 + adpctl_data_t adpctl;
16740 +
16741 + core_if->adp.sense_enabled = 0;
16742 +
16743 + adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
16744 + adpctl.b.enasns = 0;
16745 + adpctl.b.adp_sns_int = 1;
16746 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16747 +
16748 + return 0;
16749 +}
16750 +
16751 +/**
16752 + * Called to turn on the VBUS after initial ADP probe in host mode.
16753 + * If port power was already enabled in cil_hcd_start function then
16754 + * only schedule a timer.
16755 + *
16756 + * @param core_if the pointer to core_if structure.
16757 + */
16758 +void dwc_otg_adp_turnon_vbus(dwc_otg_core_if_t * core_if)
16759 +{
16760 + hprt0_data_t hprt0 = {.d32 = 0 };
16761 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
16762 + DWC_PRINTF("Turn on VBUS for 1.1s, port power is %d\n", hprt0.b.prtpwr);
16763 +
16764 + if (hprt0.b.prtpwr == 0) {
16765 + hprt0.b.prtpwr = 1;
16766 + //DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
16767 + }
16768 +
16769 + dwc_otg_adp_vbuson_timer_start(core_if);
16770 +}
16771 +
16772 +/**
16773 + * Called right after driver is loaded
16774 + * to perform initial actions for ADP
16775 + *
16776 + * @param core_if the pointer to core_if structure.
16777 + * @param is_host - flag for current mode of operation either from GINTSTS or GPWRDN
16778 + */
16779 +void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host)
16780 +{
16781 + gpwrdn_data_t gpwrdn;
16782 +
16783 + DWC_PRINTF("ADP Initial Start\n");
16784 + core_if->adp.adp_started = 1;
16785 +
16786 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
16787 + dwc_otg_disable_global_interrupts(core_if);
16788 + if (is_host) {
16789 + DWC_PRINTF("HOST MODE\n");
16790 + /* Enable Power Down Logic Interrupt*/
16791 + gpwrdn.d32 = 0;
16792 + gpwrdn.b.pmuintsel = 1;
16793 + gpwrdn.b.pmuactv = 1;
16794 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16795 + /* Initialize first ADP probe to obtain Ramp Time value */
16796 + core_if->adp.initial_probe = 1;
16797 + dwc_otg_adp_probe_start(core_if);
16798 + } else {
16799 + gotgctl_data_t gotgctl;
16800 + gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
16801 + DWC_PRINTF("DEVICE MODE\n");
16802 + if (gotgctl.b.bsesvld == 0) {
16803 + /* Enable Power Down Logic Interrupt*/
16804 + gpwrdn.d32 = 0;
16805 + DWC_PRINTF("VBUS is not valid - start ADP probe\n");
16806 + gpwrdn.b.pmuintsel = 1;
16807 + gpwrdn.b.pmuactv = 1;
16808 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16809 + core_if->adp.initial_probe = 1;
16810 + dwc_otg_adp_probe_start(core_if);
16811 + } else {
16812 + DWC_PRINTF("VBUS is valid - initialize core as a Device\n");
16813 + core_if->op_state = B_PERIPHERAL;
16814 + dwc_otg_core_init(core_if);
16815 + dwc_otg_enable_global_interrupts(core_if);
16816 + cil_pcd_start(core_if);
16817 + dwc_otg_dump_global_registers(core_if);
16818 + dwc_otg_dump_dev_registers(core_if);
16819 + }
16820 + }
16821 +}
16822 +
16823 +void dwc_otg_adp_init(dwc_otg_core_if_t * core_if)
16824 +{
16825 + core_if->adp.adp_started = 0;
16826 + core_if->adp.initial_probe = 0;
16827 + core_if->adp.probe_timer_values[0] = -1;
16828 + core_if->adp.probe_timer_values[1] = -1;
16829 + core_if->adp.probe_enabled = 0;
16830 + core_if->adp.sense_enabled = 0;
16831 + core_if->adp.sense_timer_started = 0;
16832 + core_if->adp.vbuson_timer_started = 0;
16833 + core_if->adp.probe_counter = 0;
16834 + core_if->adp.gpwrdn = 0;
16835 + core_if->adp.attached = DWC_OTG_ADP_UNKOWN;
16836 + /* Initialize timers */
16837 + core_if->adp.sense_timer =
16838 + DWC_TIMER_ALLOC("ADP SENSE TIMER", adp_sense_timeout, core_if);
16839 + core_if->adp.vbuson_timer =
16840 + DWC_TIMER_ALLOC("ADP VBUS ON TIMER", adp_vbuson_timeout, core_if);
16841 + if (!core_if->adp.sense_timer || !core_if->adp.vbuson_timer)
16842 + {
16843 + DWC_ERROR("Could not allocate memory for ADP timers\n");
16844 + }
16845 +}
16846 +
16847 +void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if)
16848 +{
16849 + gpwrdn_data_t gpwrdn = { .d32 = 0 };
16850 + gpwrdn.b.pmuintsel = 1;
16851 + gpwrdn.b.pmuactv = 1;
16852 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
16853 +
16854 + if (core_if->adp.probe_enabled)
16855 + dwc_otg_adp_probe_stop(core_if);
16856 + if (core_if->adp.sense_enabled)
16857 + dwc_otg_adp_sense_stop(core_if);
16858 + if (core_if->adp.sense_timer_started)
16859 + DWC_TIMER_CANCEL(core_if->adp.sense_timer);
16860 + if (core_if->adp.vbuson_timer_started)
16861 + DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
16862 + DWC_TIMER_FREE(core_if->adp.sense_timer);
16863 + DWC_TIMER_FREE(core_if->adp.vbuson_timer);
16864 +}
16865 +
16866 +/////////////////////////////////////////////////////////////////////
16867 +////////////// ADP Interrupt Handlers ///////////////////////////////
16868 +/////////////////////////////////////////////////////////////////////
16869 +/**
16870 + * This function sets Ramp Timer values
16871 + */
16872 +static uint32_t set_timer_value(dwc_otg_core_if_t * core_if, uint32_t val)
16873 +{
16874 + if (core_if->adp.probe_timer_values[0] == -1) {
16875 + core_if->adp.probe_timer_values[0] = val;
16876 + core_if->adp.probe_timer_values[1] = -1;
16877 + return 1;
16878 + } else {
16879 + core_if->adp.probe_timer_values[1] =
16880 + core_if->adp.probe_timer_values[0];
16881 + core_if->adp.probe_timer_values[0] = val;
16882 + return 0;
16883 + }
16884 +}
16885 +
16886 +/**
16887 + * This function compares Ramp Timer values
16888 + */
16889 +static uint32_t compare_timer_values(dwc_otg_core_if_t * core_if)
16890 +{
16891 + uint32_t diff;
16892 + if (core_if->adp.probe_timer_values[0]>=core_if->adp.probe_timer_values[1])
16893 + diff = core_if->adp.probe_timer_values[0]-core_if->adp.probe_timer_values[1];
16894 + else
16895 + diff = core_if->adp.probe_timer_values[1]-core_if->adp.probe_timer_values[0];
16896 + if(diff < 2) {
16897 + return 0;
16898 + } else {
16899 + return 1;
16900 + }
16901 +}
16902 +
16903 +/**
16904 + * This function handles ADP Probe Interrupts
16905 + */
16906 +static int32_t dwc_otg_adp_handle_prb_intr(dwc_otg_core_if_t * core_if,
16907 + uint32_t val)
16908 +{
16909 + adpctl_data_t adpctl = {.d32 = 0 };
16910 + gpwrdn_data_t gpwrdn, temp;
16911 + adpctl.d32 = val;
16912 +
16913 + temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
16914 + core_if->adp.probe_counter++;
16915 + core_if->adp.gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
16916 + if (adpctl.b.rtim == 0 && !temp.b.idsts){
16917 + DWC_PRINTF("RTIM value is 0\n");
16918 + goto exit;
16919 + }
16920 + if (set_timer_value(core_if, adpctl.b.rtim) &&
16921 + core_if->adp.initial_probe) {
16922 + core_if->adp.initial_probe = 0;
16923 + dwc_otg_adp_probe_stop(core_if);
16924 + gpwrdn.d32 = 0;
16925 + gpwrdn.b.pmuactv = 1;
16926 + gpwrdn.b.pmuintsel = 1;
16927 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
16928 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
16929 +
16930 + /* check which value is for device mode and which for Host mode */
16931 + if (!temp.b.idsts) { /* considered host mode value is 0 */
16932 + /*
16933 + * Turn on VBUS after initial ADP probe.
16934 + */
16935 + core_if->op_state = A_HOST;
16936 + dwc_otg_enable_global_interrupts(core_if);
16937 + DWC_SPINUNLOCK(core_if->lock);
16938 + cil_hcd_start(core_if);
16939 + dwc_otg_adp_turnon_vbus(core_if);
16940 + DWC_SPINLOCK(core_if->lock);
16941 + } else {
16942 + /*
16943 + * Initiate SRP after initial ADP probe.
16944 + */
16945 + dwc_otg_enable_global_interrupts(core_if);
16946 + dwc_otg_initiate_srp(core_if);
16947 + }
16948 + } else if (core_if->adp.probe_counter > 2){
16949 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
16950 + if (compare_timer_values(core_if)) {
16951 + DWC_PRINTF("Difference in timer values !!! \n");
16952 +// core_if->adp.attached = DWC_OTG_ADP_ATTACHED;
16953 + dwc_otg_adp_probe_stop(core_if);
16954 +
16955 + /* Power on the core */
16956 + if (core_if->power_down == 2) {
16957 + gpwrdn.b.pwrdnswtch = 1;
16958 + DWC_MODIFY_REG32(&core_if->core_global_regs->
16959 + gpwrdn, 0, gpwrdn.d32);
16960 + }
16961 +
16962 + /* check which value is for device mode and which for Host mode */
16963 + if (!temp.b.idsts) { /* considered host mode value is 0 */
16964 + /* Disable Interrupt from Power Down Logic */
16965 + gpwrdn.d32 = 0;
16966 + gpwrdn.b.pmuintsel = 1;
16967 + gpwrdn.b.pmuactv = 1;
16968 + DWC_MODIFY_REG32(&core_if->core_global_regs->
16969 + gpwrdn, gpwrdn.d32, 0);
16970 +
16971 + /*
16972 + * Initialize the Core for Host mode.
16973 + */
16974 + core_if->op_state = A_HOST;
16975 + dwc_otg_core_init(core_if);
16976 + dwc_otg_enable_global_interrupts(core_if);
16977 + cil_hcd_start(core_if);
16978 + } else {
16979 + gotgctl_data_t gotgctl;
16980 + /* Mask SRP detected interrupt from Power Down Logic */
16981 + gpwrdn.d32 = 0;
16982 + gpwrdn.b.srp_det_msk = 1;
16983 + DWC_MODIFY_REG32(&core_if->core_global_regs->
16984 + gpwrdn, gpwrdn.d32, 0);
16985 +
16986 + /* Disable Power Down Logic */
16987 + gpwrdn.d32 = 0;
16988 + gpwrdn.b.pmuintsel = 1;
16989 + gpwrdn.b.pmuactv = 1;
16990 + DWC_MODIFY_REG32(&core_if->core_global_regs->
16991 + gpwrdn, gpwrdn.d32, 0);
16992 +
16993 + /*
16994 + * Initialize the Core for Device mode.
16995 + */
16996 + core_if->op_state = B_PERIPHERAL;
16997 + dwc_otg_core_init(core_if);
16998 + dwc_otg_enable_global_interrupts(core_if);
16999 + cil_pcd_start(core_if);
17000 +
17001 + gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
17002 + if (!gotgctl.b.bsesvld) {
17003 + dwc_otg_initiate_srp(core_if);
17004 + }
17005 + }
17006 + }
17007 + if (core_if->power_down == 2) {
17008 + if (gpwrdn.b.bsessvld) {
17009 + /* Mask SRP detected interrupt from Power Down Logic */
17010 + gpwrdn.d32 = 0;
17011 + gpwrdn.b.srp_det_msk = 1;
17012 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17013 +
17014 + /* Disable Power Down Logic */
17015 + gpwrdn.d32 = 0;
17016 + gpwrdn.b.pmuactv = 1;
17017 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17018 +
17019 + /*
17020 + * Initialize the Core for Device mode.
17021 + */
17022 + core_if->op_state = B_PERIPHERAL;
17023 + dwc_otg_core_init(core_if);
17024 + dwc_otg_enable_global_interrupts(core_if);
17025 + cil_pcd_start(core_if);
17026 + }
17027 + }
17028 + }
17029 +exit:
17030 + /* Clear interrupt */
17031 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17032 + adpctl.b.adp_prb_int = 1;
17033 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17034 +
17035 + return 0;
17036 +}
17037 +
17038 +/**
17039 + * This function hadles ADP Sense Interrupt
17040 + */
17041 +static int32_t dwc_otg_adp_handle_sns_intr(dwc_otg_core_if_t * core_if)
17042 +{
17043 + adpctl_data_t adpctl;
17044 + /* Stop ADP Sense timer */
17045 + DWC_TIMER_CANCEL(core_if->adp.sense_timer);
17046 +
17047 + /* Restart ADP Sense timer */
17048 + dwc_otg_adp_sense_timer_start(core_if);
17049 +
17050 + /* Clear interrupt */
17051 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17052 + adpctl.b.adp_sns_int = 1;
17053 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17054 +
17055 + return 0;
17056 +}
17057 +
17058 +/**
17059 + * This function handles ADP Probe Interrupts
17060 + */
17061 +static int32_t dwc_otg_adp_handle_prb_tmout_intr(dwc_otg_core_if_t * core_if,
17062 + uint32_t val)
17063 +{
17064 + adpctl_data_t adpctl = {.d32 = 0 };
17065 + adpctl.d32 = val;
17066 + set_timer_value(core_if, adpctl.b.rtim);
17067 +
17068 + /* Clear interrupt */
17069 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17070 + adpctl.b.adp_tmout_int = 1;
17071 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17072 +
17073 + return 0;
17074 +}
17075 +
17076 +/**
17077 + * ADP Interrupt handler.
17078 + *
17079 + */
17080 +int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if)
17081 +{
17082 + int retval = 0;
17083 + adpctl_data_t adpctl = {.d32 = 0};
17084 +
17085 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17086 + DWC_PRINTF("ADPCTL = %08x\n",adpctl.d32);
17087 +
17088 + if (adpctl.b.adp_sns_int & adpctl.b.adp_sns_int_msk) {
17089 + DWC_PRINTF("ADP Sense interrupt\n");
17090 + retval |= dwc_otg_adp_handle_sns_intr(core_if);
17091 + }
17092 + if (adpctl.b.adp_tmout_int & adpctl.b.adp_tmout_int_msk) {
17093 + DWC_PRINTF("ADP timeout interrupt\n");
17094 + retval |= dwc_otg_adp_handle_prb_tmout_intr(core_if, adpctl.d32);
17095 + }
17096 + if (adpctl.b.adp_prb_int & adpctl.b.adp_prb_int_msk) {
17097 + DWC_PRINTF("ADP Probe interrupt\n");
17098 + adpctl.b.adp_prb_int = 1;
17099 + retval |= dwc_otg_adp_handle_prb_intr(core_if, adpctl.d32);
17100 + }
17101 +
17102 +// dwc_otg_adp_modify_reg(core_if, adpctl.d32, 0);
17103 + //dwc_otg_adp_write_reg(core_if, adpctl.d32);
17104 + DWC_PRINTF("RETURN FROM ADP ISR\n");
17105 +
17106 + return retval;
17107 +}
17108 +
17109 +/**
17110 + *
17111 + * @param core_if Programming view of DWC_otg controller.
17112 + */
17113 +int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if)
17114 +{
17115 +
17116 +#ifndef DWC_HOST_ONLY
17117 + hprt0_data_t hprt0;
17118 + gpwrdn_data_t gpwrdn;
17119 + DWC_DEBUGPL(DBG_ANY, "++ Power Down Logic Session Request Interrupt++\n");
17120 +
17121 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17122 + /* check which value is for device mode and which for Host mode */
17123 + if (!gpwrdn.b.idsts) { /* considered host mode value is 0 */
17124 + DWC_PRINTF("SRP: Host mode\n");
17125 +
17126 + if (core_if->adp_enable) {
17127 + dwc_otg_adp_probe_stop(core_if);
17128 +
17129 + /* Power on the core */
17130 + if (core_if->power_down == 2) {
17131 + gpwrdn.b.pwrdnswtch = 1;
17132 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17133 + gpwrdn, 0, gpwrdn.d32);
17134 + }
17135 +
17136 + core_if->op_state = A_HOST;
17137 + dwc_otg_core_init(core_if);
17138 + dwc_otg_enable_global_interrupts(core_if);
17139 + cil_hcd_start(core_if);
17140 + }
17141 +
17142 + /* Turn on the port power bit. */
17143 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
17144 + hprt0.b.prtpwr = 1;
17145 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
17146 +
17147 + /* Start the Connection timer. So a message can be displayed
17148 + * if connect does not occur within 10 seconds. */
17149 + cil_hcd_session_start(core_if);
17150 + } else {
17151 + DWC_PRINTF("SRP: Device mode %s\n", __FUNCTION__);
17152 + if (core_if->adp_enable) {
17153 + dwc_otg_adp_probe_stop(core_if);
17154 +
17155 + /* Power on the core */
17156 + if (core_if->power_down == 2) {
17157 + gpwrdn.b.pwrdnswtch = 1;
17158 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17159 + gpwrdn, 0, gpwrdn.d32);
17160 + }
17161 +
17162 + gpwrdn.d32 = 0;
17163 + gpwrdn.b.pmuactv = 0;
17164 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
17165 + gpwrdn.d32);
17166 +
17167 + core_if->op_state = B_PERIPHERAL;
17168 + dwc_otg_core_init(core_if);
17169 + dwc_otg_enable_global_interrupts(core_if);
17170 + cil_pcd_start(core_if);
17171 + }
17172 + }
17173 +#endif
17174 + return 1;
17175 +}
17176 --- /dev/null
17177 +++ b/drivers/usb/host/dwc_otg/dwc_otg_adp.h
17178 @@ -0,0 +1,80 @@
17179 +/* ==========================================================================
17180 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.h $
17181 + * $Revision: #7 $
17182 + * $Date: 2011/10/24 $
17183 + * $Change: 1871159 $
17184 + *
17185 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
17186 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
17187 + * otherwise expressly agreed to in writing between Synopsys and you.
17188 + *
17189 + * The Software IS NOT an item of Licensed Software or Licensed Product under
17190 + * any End User Software License Agreement or Agreement for Licensed Product
17191 + * with Synopsys or any supplement thereto. You are permitted to use and
17192 + * redistribute this Software in source and binary forms, with or without
17193 + * modification, provided that redistributions of source code must retain this
17194 + * notice. You may not view, use, disclose, copy or distribute this file or
17195 + * any information contained herein except pursuant to this license grant from
17196 + * Synopsys. If you do not agree with this notice, including the disclaimer
17197 + * below, then you are not authorized to use the Software.
17198 + *
17199 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
17200 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17201 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17202 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
17203 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17204 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17205 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17206 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17207 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17208 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
17209 + * DAMAGE.
17210 + * ========================================================================== */
17211 +
17212 +#ifndef __DWC_OTG_ADP_H__
17213 +#define __DWC_OTG_ADP_H__
17214 +
17215 +/**
17216 + * @file
17217 + *
17218 + * This file contains the Attach Detect Protocol interfaces and defines
17219 + * (functions) and structures for Linux.
17220 + *
17221 + */
17222 +
17223 +#define DWC_OTG_ADP_UNATTACHED 0
17224 +#define DWC_OTG_ADP_ATTACHED 1
17225 +#define DWC_OTG_ADP_UNKOWN 2
17226 +
17227 +typedef struct dwc_otg_adp {
17228 + uint32_t adp_started;
17229 + uint32_t initial_probe;
17230 + int32_t probe_timer_values[2];
17231 + uint32_t probe_enabled;
17232 + uint32_t sense_enabled;
17233 + dwc_timer_t *sense_timer;
17234 + uint32_t sense_timer_started;
17235 + dwc_timer_t *vbuson_timer;
17236 + uint32_t vbuson_timer_started;
17237 + uint32_t attached;
17238 + uint32_t probe_counter;
17239 + uint32_t gpwrdn;
17240 +} dwc_otg_adp_t;
17241 +
17242 +/**
17243 + * Attach Detect Protocol functions
17244 + */
17245 +
17246 +extern void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value);
17247 +extern uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if);
17248 +extern uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if);
17249 +extern uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if);
17250 +extern uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if);
17251 +extern uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if);
17252 +extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
17253 +extern void dwc_otg_adp_init(dwc_otg_core_if_t * core_if);
17254 +extern void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if);
17255 +extern int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if);
17256 +extern int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if);
17257 +
17258 +#endif //__DWC_OTG_ADP_H__
17259 --- /dev/null
17260 +++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.c
17261 @@ -0,0 +1,1210 @@
17262 +/* ==========================================================================
17263 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.c $
17264 + * $Revision: #44 $
17265 + * $Date: 2010/11/29 $
17266 + * $Change: 1636033 $
17267 + *
17268 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
17269 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
17270 + * otherwise expressly agreed to in writing between Synopsys and you.
17271 + *
17272 + * The Software IS NOT an item of Licensed Software or Licensed Product under
17273 + * any End User Software License Agreement or Agreement for Licensed Product
17274 + * with Synopsys or any supplement thereto. You are permitted to use and
17275 + * redistribute this Software in source and binary forms, with or without
17276 + * modification, provided that redistributions of source code must retain this
17277 + * notice. You may not view, use, disclose, copy or distribute this file or
17278 + * any information contained herein except pursuant to this license grant from
17279 + * Synopsys. If you do not agree with this notice, including the disclaimer
17280 + * below, then you are not authorized to use the Software.
17281 + *
17282 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
17283 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17284 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17285 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
17286 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17287 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17288 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17289 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17290 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17291 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
17292 + * DAMAGE.
17293 + * ========================================================================== */
17294 +
17295 +/** @file
17296 + *
17297 + * The diagnostic interface will provide access to the controller for
17298 + * bringing up the hardware and testing. The Linux driver attributes
17299 + * feature will be used to provide the Linux Diagnostic
17300 + * Interface. These attributes are accessed through sysfs.
17301 + */
17302 +
17303 +/** @page "Linux Module Attributes"
17304 + *
17305 + * The Linux module attributes feature is used to provide the Linux
17306 + * Diagnostic Interface. These attributes are accessed through sysfs.
17307 + * The diagnostic interface will provide access to the controller for
17308 + * bringing up the hardware and testing.
17309 +
17310 + The following table shows the attributes.
17311 + <table>
17312 + <tr>
17313 + <td><b> Name</b></td>
17314 + <td><b> Description</b></td>
17315 + <td><b> Access</b></td>
17316 + </tr>
17317 +
17318 + <tr>
17319 + <td> mode </td>
17320 + <td> Returns the current mode: 0 for device mode, 1 for host mode</td>
17321 + <td> Read</td>
17322 + </tr>
17323 +
17324 + <tr>
17325 + <td> hnpcapable </td>
17326 + <td> Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register.
17327 + Read returns the current value.</td>
17328 + <td> Read/Write</td>
17329 + </tr>
17330 +
17331 + <tr>
17332 + <td> srpcapable </td>
17333 + <td> Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register.
17334 + Read returns the current value.</td>
17335 + <td> Read/Write</td>
17336 + </tr>
17337 +
17338 + <tr>
17339 + <td> hsic_connect </td>
17340 + <td> Gets or sets the "HSIC-Connect" bit in the GLPMCFG Register.
17341 + Read returns the current value.</td>
17342 + <td> Read/Write</td>
17343 + </tr>
17344 +
17345 + <tr>
17346 + <td> inv_sel_hsic </td>
17347 + <td> Gets or sets the "Invert Select HSIC" bit in the GLPMFG Register.
17348 + Read returns the current value.</td>
17349 + <td> Read/Write</td>
17350 + </tr>
17351 +
17352 + <tr>
17353 + <td> hnp </td>
17354 + <td> Initiates the Host Negotiation Protocol. Read returns the status.</td>
17355 + <td> Read/Write</td>
17356 + </tr>
17357 +
17358 + <tr>
17359 + <td> srp </td>
17360 + <td> Initiates the Session Request Protocol. Read returns the status.</td>
17361 + <td> Read/Write</td>
17362 + </tr>
17363 +
17364 + <tr>
17365 + <td> buspower </td>
17366 + <td> Gets or sets the Power State of the bus (0 - Off or 1 - On)</td>
17367 + <td> Read/Write</td>
17368 + </tr>
17369 +
17370 + <tr>
17371 + <td> bussuspend </td>
17372 + <td> Suspends the USB bus.</td>
17373 + <td> Read/Write</td>
17374 + </tr>
17375 +
17376 + <tr>
17377 + <td> busconnected </td>
17378 + <td> Gets the connection status of the bus</td>
17379 + <td> Read</td>
17380 + </tr>
17381 +
17382 + <tr>
17383 + <td> gotgctl </td>
17384 + <td> Gets or sets the Core Control Status Register.</td>
17385 + <td> Read/Write</td>
17386 + </tr>
17387 +
17388 + <tr>
17389 + <td> gusbcfg </td>
17390 + <td> Gets or sets the Core USB Configuration Register</td>
17391 + <td> Read/Write</td>
17392 + </tr>
17393 +
17394 + <tr>
17395 + <td> grxfsiz </td>
17396 + <td> Gets or sets the Receive FIFO Size Register</td>
17397 + <td> Read/Write</td>
17398 + </tr>
17399 +
17400 + <tr>
17401 + <td> gnptxfsiz </td>
17402 + <td> Gets or sets the non-periodic Transmit Size Register</td>
17403 + <td> Read/Write</td>
17404 + </tr>
17405 +
17406 + <tr>
17407 + <td> gpvndctl </td>
17408 + <td> Gets or sets the PHY Vendor Control Register</td>
17409 + <td> Read/Write</td>
17410 + </tr>
17411 +
17412 + <tr>
17413 + <td> ggpio </td>
17414 + <td> Gets the value in the lower 16-bits of the General Purpose IO Register
17415 + or sets the upper 16 bits.</td>
17416 + <td> Read/Write</td>
17417 + </tr>
17418 +
17419 + <tr>
17420 + <td> guid </td>
17421 + <td> Gets or sets the value of the User ID Register</td>
17422 + <td> Read/Write</td>
17423 + </tr>
17424 +
17425 + <tr>
17426 + <td> gsnpsid </td>
17427 + <td> Gets the value of the Synopsys ID Regester</td>
17428 + <td> Read</td>
17429 + </tr>
17430 +
17431 + <tr>
17432 + <td> devspeed </td>
17433 + <td> Gets or sets the device speed setting in the DCFG register</td>
17434 + <td> Read/Write</td>
17435 + </tr>
17436 +
17437 + <tr>
17438 + <td> enumspeed </td>
17439 + <td> Gets the device enumeration Speed.</td>
17440 + <td> Read</td>
17441 + </tr>
17442 +
17443 + <tr>
17444 + <td> hptxfsiz </td>
17445 + <td> Gets the value of the Host Periodic Transmit FIFO</td>
17446 + <td> Read</td>
17447 + </tr>
17448 +
17449 + <tr>
17450 + <td> hprt0 </td>
17451 + <td> Gets or sets the value in the Host Port Control and Status Register</td>
17452 + <td> Read/Write</td>
17453 + </tr>
17454 +
17455 + <tr>
17456 + <td> regoffset </td>
17457 + <td> Sets the register offset for the next Register Access</td>
17458 + <td> Read/Write</td>
17459 + </tr>
17460 +
17461 + <tr>
17462 + <td> regvalue </td>
17463 + <td> Gets or sets the value of the register at the offset in the regoffset attribute.</td>
17464 + <td> Read/Write</td>
17465 + </tr>
17466 +
17467 + <tr>
17468 + <td> remote_wakeup </td>
17469 + <td> On read, shows the status of Remote Wakeup. On write, initiates a remote
17470 + wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote
17471 + Wakeup signalling bit in the Device Control Register is set for 1
17472 + milli-second.</td>
17473 + <td> Read/Write</td>
17474 + </tr>
17475 +
17476 + <tr>
17477 + <td> rem_wakeup_pwrdn </td>
17478 + <td> On read, shows the status core - hibernated or not. On write, initiates
17479 + a remote wakeup of the device from Hibernation. </td>
17480 + <td> Read/Write</td>
17481 + </tr>
17482 +
17483 + <tr>
17484 + <td> mode_ch_tim_en </td>
17485 + <td> This bit is used to enable or disable the host core to wait for 200 PHY
17486 + clock cycles at the end of Resume to change the opmode signal to the PHY to 00
17487 + after Suspend or LPM. </td>
17488 + <td> Read/Write</td>
17489 + </tr>
17490 +
17491 + <tr>
17492 + <td> fr_interval </td>
17493 + <td> On read, shows the value of HFIR Frame Interval. On write, dynamically
17494 + reload HFIR register during runtime. The application can write a value to this
17495 + register only after the Port Enable bit of the Host Port Control and Status
17496 + register (HPRT.PrtEnaPort) has been set </td>
17497 + <td> Read/Write</td>
17498 + </tr>
17499 +
17500 + <tr>
17501 + <td> disconnect_us </td>
17502 + <td> On read, shows the status of disconnect_device_us. On write, sets disconnect_us
17503 + which causes soft disconnect for 100us. Applicable only for device mode of operation.</td>
17504 + <td> Read/Write</td>
17505 + </tr>
17506 +
17507 + <tr>
17508 + <td> regdump </td>
17509 + <td> Dumps the contents of core registers.</td>
17510 + <td> Read</td>
17511 + </tr>
17512 +
17513 + <tr>
17514 + <td> spramdump </td>
17515 + <td> Dumps the contents of core registers.</td>
17516 + <td> Read</td>
17517 + </tr>
17518 +
17519 + <tr>
17520 + <td> hcddump </td>
17521 + <td> Dumps the current HCD state.</td>
17522 + <td> Read</td>
17523 + </tr>
17524 +
17525 + <tr>
17526 + <td> hcd_frrem </td>
17527 + <td> Shows the average value of the Frame Remaining
17528 + field in the Host Frame Number/Frame Remaining register when an SOF interrupt
17529 + occurs. This can be used to determine the average interrupt latency. Also
17530 + shows the average Frame Remaining value for start_transfer and the "a" and
17531 + "b" sample points. The "a" and "b" sample points may be used during debugging
17532 + bto determine how long it takes to execute a section of the HCD code.</td>
17533 + <td> Read</td>
17534 + </tr>
17535 +
17536 + <tr>
17537 + <td> rd_reg_test </td>
17538 + <td> Displays the time required to read the GNPTXFSIZ register many times
17539 + (the output shows the number of times the register is read).
17540 + <td> Read</td>
17541 + </tr>
17542 +
17543 + <tr>
17544 + <td> wr_reg_test </td>
17545 + <td> Displays the time required to write the GNPTXFSIZ register many times
17546 + (the output shows the number of times the register is written).
17547 + <td> Read</td>
17548 + </tr>
17549 +
17550 + <tr>
17551 + <td> lpm_response </td>
17552 + <td> Gets or sets lpm_response mode. Applicable only in device mode.
17553 + <td> Write</td>
17554 + </tr>
17555 +
17556 + <tr>
17557 + <td> sleep_status </td>
17558 + <td> Shows sleep status of device.
17559 + <td> Read</td>
17560 + </tr>
17561 +
17562 + </table>
17563 +
17564 + Example usage:
17565 + To get the current mode:
17566 + cat /sys/devices/lm0/mode
17567 +
17568 + To power down the USB:
17569 + echo 0 > /sys/devices/lm0/buspower
17570 + */
17571 +
17572 +#include "dwc_otg_os_dep.h"
17573 +#include "dwc_os.h"
17574 +#include "dwc_otg_driver.h"
17575 +#include "dwc_otg_attr.h"
17576 +#include "dwc_otg_core_if.h"
17577 +#include "dwc_otg_pcd_if.h"
17578 +#include "dwc_otg_hcd_if.h"
17579 +
17580 +/*
17581 + * MACROs for defining sysfs attribute
17582 + */
17583 +#ifdef LM_INTERFACE
17584 +
17585 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17586 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17587 +{ \
17588 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17589 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17590 + uint32_t val; \
17591 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17592 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
17593 +}
17594 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17595 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17596 + const char *buf, size_t count) \
17597 +{ \
17598 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17599 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17600 + uint32_t set = simple_strtoul(buf, NULL, 16); \
17601 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
17602 + return count; \
17603 +}
17604 +
17605 +#elif defined(PCI_INTERFACE)
17606 +
17607 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17608 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17609 +{ \
17610 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17611 + uint32_t val; \
17612 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17613 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
17614 +}
17615 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17616 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17617 + const char *buf, size_t count) \
17618 +{ \
17619 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17620 + uint32_t set = simple_strtoul(buf, NULL, 16); \
17621 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
17622 + return count; \
17623 +}
17624 +
17625 +#elif defined(PLATFORM_INTERFACE)
17626 +
17627 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17628 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17629 +{ \
17630 + struct platform_device *platform_dev = \
17631 + container_of(_dev, struct platform_device, dev); \
17632 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17633 + uint32_t val; \
17634 + DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
17635 + __func__, _dev, platform_dev, otg_dev); \
17636 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17637 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
17638 +}
17639 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17640 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17641 + const char *buf, size_t count) \
17642 +{ \
17643 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
17644 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17645 + uint32_t set = simple_strtoul(buf, NULL, 16); \
17646 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
17647 + return count; \
17648 +}
17649 +#endif
17650 +
17651 +/*
17652 + * MACROs for defining sysfs attribute for 32-bit registers
17653 + */
17654 +#ifdef LM_INTERFACE
17655 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
17656 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17657 +{ \
17658 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17659 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17660 + uint32_t val; \
17661 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17662 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
17663 +}
17664 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
17665 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17666 + const char *buf, size_t count) \
17667 +{ \
17668 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17669 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17670 + uint32_t val = simple_strtoul(buf, NULL, 16); \
17671 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
17672 + return count; \
17673 +}
17674 +#elif defined(PCI_INTERFACE)
17675 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
17676 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17677 +{ \
17678 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17679 + uint32_t val; \
17680 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17681 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
17682 +}
17683 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
17684 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17685 + const char *buf, size_t count) \
17686 +{ \
17687 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17688 + uint32_t val = simple_strtoul(buf, NULL, 16); \
17689 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
17690 + return count; \
17691 +}
17692 +
17693 +#elif defined(PLATFORM_INTERFACE)
17694 +#include "dwc_otg_dbg.h"
17695 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
17696 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17697 +{ \
17698 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
17699 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17700 + uint32_t val; \
17701 + DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
17702 + __func__, _dev, platform_dev, otg_dev); \
17703 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17704 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
17705 +}
17706 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
17707 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17708 + const char *buf, size_t count) \
17709 +{ \
17710 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
17711 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17712 + uint32_t val = simple_strtoul(buf, NULL, 16); \
17713 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
17714 + return count; \
17715 +}
17716 +
17717 +#endif
17718 +
17719 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_string_) \
17720 +DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17721 +DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17722 +DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
17723 +
17724 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_string_) \
17725 +DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17726 +DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
17727 +
17728 +#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \
17729 +DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
17730 +DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
17731 +DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
17732 +
17733 +#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \
17734 +DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
17735 +DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
17736 +
17737 +/** @name Functions for Show/Store of Attributes */
17738 +/**@{*/
17739 +
17740 +/**
17741 + * Helper function returning the otg_device structure of the given device
17742 + */
17743 +static dwc_otg_device_t *dwc_otg_drvdev(struct device *_dev)
17744 +{
17745 + dwc_otg_device_t *otg_dev;
17746 + DWC_OTG_GETDRVDEV(otg_dev, _dev);
17747 + return otg_dev;
17748 +}
17749 +
17750 +/**
17751 + * Show the register offset of the Register Access.
17752 + */
17753 +static ssize_t regoffset_show(struct device *_dev,
17754 + struct device_attribute *attr, char *buf)
17755 +{
17756 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
17757 + return snprintf(buf, sizeof("0xFFFFFFFF\n") + 1, "0x%08x\n",
17758 + otg_dev->os_dep.reg_offset);
17759 +}
17760 +
17761 +/**
17762 + * Set the register offset for the next Register Access Read/Write
17763 + */
17764 +static ssize_t regoffset_store(struct device *_dev,
17765 + struct device_attribute *attr,
17766 + const char *buf, size_t count)
17767 +{
17768 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
17769 + uint32_t offset = simple_strtoul(buf, NULL, 16);
17770 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
17771 + if (offset < SZ_256K) {
17772 +#elif defined(PCI_INTERFACE)
17773 + if (offset < 0x00040000) {
17774 +#endif
17775 + otg_dev->os_dep.reg_offset = offset;
17776 + } else {
17777 + dev_err(_dev, "invalid offset\n");
17778 + }
17779 +
17780 + return count;
17781 +}
17782 +
17783 +DEVICE_ATTR(regoffset, S_IRUGO | S_IWUSR, regoffset_show, regoffset_store);
17784 +
17785 +/**
17786 + * Show the value of the register at the offset in the reg_offset
17787 + * attribute.
17788 + */
17789 +static ssize_t regvalue_show(struct device *_dev,
17790 + struct device_attribute *attr, char *buf)
17791 +{
17792 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
17793 + uint32_t val;
17794 + volatile uint32_t *addr;
17795 +
17796 + if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
17797 + /* Calculate the address */
17798 + addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
17799 + (uint8_t *) otg_dev->os_dep.base);
17800 + val = DWC_READ_REG32(addr);
17801 + return snprintf(buf,
17802 + sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n") + 1,
17803 + "Reg@0x%06x = 0x%08x\n", otg_dev->os_dep.reg_offset,
17804 + val);
17805 + } else {
17806 + dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->os_dep.reg_offset);
17807 + return sprintf(buf, "invalid offset\n");
17808 + }
17809 +}
17810 +
17811 +/**
17812 + * Store the value in the register at the offset in the reg_offset
17813 + * attribute.
17814 + *
17815 + */
17816 +static ssize_t regvalue_store(struct device *_dev,
17817 + struct device_attribute *attr,
17818 + const char *buf, size_t count)
17819 +{
17820 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
17821 + volatile uint32_t *addr;
17822 + uint32_t val = simple_strtoul(buf, NULL, 16);
17823 + //dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val);
17824 + if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
17825 + /* Calculate the address */
17826 + addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
17827 + (uint8_t *) otg_dev->os_dep.base);
17828 + DWC_WRITE_REG32(addr, val);
17829 + } else {
17830 + dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
17831 + otg_dev->os_dep.reg_offset);
17832 + }
17833 + return count;
17834 +}
17835 +
17836 +DEVICE_ATTR(regvalue, S_IRUGO | S_IWUSR, regvalue_show, regvalue_store);
17837 +
17838 +/*
17839 + * Attributes
17840 + */
17841 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode, "Mode");
17842 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable, "HNPCapable");
17843 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable, "SRPCapable");
17844 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hsic_connect, "HSIC Connect");
17845 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(inv_sel_hsic, "Invert Select HSIC");
17846 +
17847 +//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
17848 +//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
17849 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, "Bus Connected");
17850 +
17851 +DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl, 0, "GOTGCTL");
17852 +DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,
17853 + &(otg_dev->core_if->core_global_regs->gusbcfg),
17854 + "GUSBCFG");
17855 +DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,
17856 + &(otg_dev->core_if->core_global_regs->grxfsiz),
17857 + "GRXFSIZ");
17858 +DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,
17859 + &(otg_dev->core_if->core_global_regs->gnptxfsiz),
17860 + "GNPTXFSIZ");
17861 +DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,
17862 + &(otg_dev->core_if->core_global_regs->gpvndctl),
17863 + "GPVNDCTL");
17864 +DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,
17865 + &(otg_dev->core_if->core_global_regs->ggpio),
17866 + "GGPIO");
17867 +DWC_OTG_DEVICE_ATTR_REG32_RW(guid, &(otg_dev->core_if->core_global_regs->guid),
17868 + "GUID");
17869 +DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,
17870 + &(otg_dev->core_if->core_global_regs->gsnpsid),
17871 + "GSNPSID");
17872 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed, "Device Speed");
17873 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed, "Device Enumeration Speed");
17874 +
17875 +DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,
17876 + &(otg_dev->core_if->core_global_regs->hptxfsiz),
17877 + "HPTXFSIZ");
17878 +DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, otg_dev->core_if->host_if->hprt0, "HPRT0");
17879 +
17880 +/**
17881 + * @todo Add code to initiate the HNP.
17882 + */
17883 +/**
17884 + * Show the HNP status bit
17885 + */
17886 +static ssize_t hnp_show(struct device *_dev,
17887 + struct device_attribute *attr, char *buf)
17888 +{
17889 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
17890 + return sprintf(buf, "HstNegScs = 0x%x\n",
17891 + dwc_otg_get_hnpstatus(otg_dev->core_if));
17892 +}
17893 +
17894 +/**
17895 + * Set the HNP Request bit
17896 + */
17897 +static ssize_t hnp_store(struct device *_dev,
17898 + struct device_attribute *attr,
17899 + const char *buf, size_t count)
17900 +{
17901 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
17902 + uint32_t in = simple_strtoul(buf, NULL, 16);
17903 + dwc_otg_set_hnpreq(otg_dev->core_if, in);
17904 + return count;
17905 +}
17906 +
17907 +DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store);
17908 +
17909 +/**
17910 + * @todo Add code to initiate the SRP.
17911 + */
17912 +/**
17913 + * Show the SRP status bit
17914 + */
17915 +static ssize_t srp_show(struct device *_dev,
17916 + struct device_attribute *attr, char *buf)
17917 +{
17918 +#ifndef DWC_HOST_ONLY
17919 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
17920 + return sprintf(buf, "SesReqScs = 0x%x\n",
17921 + dwc_otg_get_srpstatus(otg_dev->core_if));
17922 +#else
17923 + return sprintf(buf, "Host Only Mode!\n");
17924 +#endif
17925 +}
17926 +
17927 +/**
17928 + * Set the SRP Request bit
17929 + */
17930 +static ssize_t srp_store(struct device *_dev,
17931 + struct device_attribute *attr,
17932 + const char *buf, size_t count)
17933 +{
17934 +#ifndef DWC_HOST_ONLY
17935 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
17936 + dwc_otg_pcd_initiate_srp(otg_dev->pcd);
17937 +#endif
17938 + return count;
17939 +}
17940 +
17941 +DEVICE_ATTR(srp, 0644, srp_show, srp_store);
17942 +
17943 +/**
17944 + * @todo Need to do more for power on/off?
17945 + */
17946 +/**
17947 + * Show the Bus Power status
17948 + */
17949 +static ssize_t buspower_show(struct device *_dev,
17950 + struct device_attribute *attr, char *buf)
17951 +{
17952 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
17953 + return sprintf(buf, "Bus Power = 0x%x\n",
17954 + dwc_otg_get_prtpower(otg_dev->core_if));
17955 +}
17956 +
17957 +/**
17958 + * Set the Bus Power status
17959 + */
17960 +static ssize_t buspower_store(struct device *_dev,
17961 + struct device_attribute *attr,
17962 + const char *buf, size_t count)
17963 +{
17964 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
17965 + uint32_t on = simple_strtoul(buf, NULL, 16);
17966 + dwc_otg_set_prtpower(otg_dev->core_if, on);
17967 + return count;
17968 +}
17969 +
17970 +DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store);
17971 +
17972 +/**
17973 + * @todo Need to do more for suspend?
17974 + */
17975 +/**
17976 + * Show the Bus Suspend status
17977 + */
17978 +static ssize_t bussuspend_show(struct device *_dev,
17979 + struct device_attribute *attr, char *buf)
17980 +{
17981 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
17982 + return sprintf(buf, "Bus Suspend = 0x%x\n",
17983 + dwc_otg_get_prtsuspend(otg_dev->core_if));
17984 +}
17985 +
17986 +/**
17987 + * Set the Bus Suspend status
17988 + */
17989 +static ssize_t bussuspend_store(struct device *_dev,
17990 + struct device_attribute *attr,
17991 + const char *buf, size_t count)
17992 +{
17993 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
17994 + uint32_t in = simple_strtoul(buf, NULL, 16);
17995 + dwc_otg_set_prtsuspend(otg_dev->core_if, in);
17996 + return count;
17997 +}
17998 +
17999 +DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store);
18000 +
18001 +/**
18002 + * Show the Mode Change Ready Timer status
18003 + */
18004 +static ssize_t mode_ch_tim_en_show(struct device *_dev,
18005 + struct device_attribute *attr, char *buf)
18006 +{
18007 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18008 + return sprintf(buf, "Mode Change Ready Timer Enable = 0x%x\n",
18009 + dwc_otg_get_mode_ch_tim(otg_dev->core_if));
18010 +}
18011 +
18012 +/**
18013 + * Set the Mode Change Ready Timer status
18014 + */
18015 +static ssize_t mode_ch_tim_en_store(struct device *_dev,
18016 + struct device_attribute *attr,
18017 + const char *buf, size_t count)
18018 +{
18019 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18020 + uint32_t in = simple_strtoul(buf, NULL, 16);
18021 + dwc_otg_set_mode_ch_tim(otg_dev->core_if, in);
18022 + return count;
18023 +}
18024 +
18025 +DEVICE_ATTR(mode_ch_tim_en, 0644, mode_ch_tim_en_show, mode_ch_tim_en_store);
18026 +
18027 +/**
18028 + * Show the value of HFIR Frame Interval bitfield
18029 + */
18030 +static ssize_t fr_interval_show(struct device *_dev,
18031 + struct device_attribute *attr, char *buf)
18032 +{
18033 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18034 + return sprintf(buf, "Frame Interval = 0x%x\n",
18035 + dwc_otg_get_fr_interval(otg_dev->core_if));
18036 +}
18037 +
18038 +/**
18039 + * Set the HFIR Frame Interval value
18040 + */
18041 +static ssize_t fr_interval_store(struct device *_dev,
18042 + struct device_attribute *attr,
18043 + const char *buf, size_t count)
18044 +{
18045 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18046 + uint32_t in = simple_strtoul(buf, NULL, 10);
18047 + dwc_otg_set_fr_interval(otg_dev->core_if, in);
18048 + return count;
18049 +}
18050 +
18051 +DEVICE_ATTR(fr_interval, 0644, fr_interval_show, fr_interval_store);
18052 +
18053 +/**
18054 + * Show the status of Remote Wakeup.
18055 + */
18056 +static ssize_t remote_wakeup_show(struct device *_dev,
18057 + struct device_attribute *attr, char *buf)
18058 +{
18059 +#ifndef DWC_HOST_ONLY
18060 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18061 +
18062 + return sprintf(buf,
18063 + "Remote Wakeup Sig = %d Enabled = %d LPM Remote Wakeup = %d\n",
18064 + dwc_otg_get_remotewakesig(otg_dev->core_if),
18065 + dwc_otg_pcd_get_rmwkup_enable(otg_dev->pcd),
18066 + dwc_otg_get_lpm_remotewakeenabled(otg_dev->core_if));
18067 +#else
18068 + return sprintf(buf, "Host Only Mode!\n");
18069 +#endif /* DWC_HOST_ONLY */
18070 +}
18071 +
18072 +/**
18073 + * Initiate a remote wakeup of the host. The Device control register
18074 + * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable
18075 + * flag is set.
18076 + *
18077 + */
18078 +static ssize_t remote_wakeup_store(struct device *_dev,
18079 + struct device_attribute *attr,
18080 + const char *buf, size_t count)
18081 +{
18082 +#ifndef DWC_HOST_ONLY
18083 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18084 + uint32_t val = simple_strtoul(buf, NULL, 16);
18085 +
18086 + if (val & 1) {
18087 + dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1);
18088 + } else {
18089 + dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0);
18090 + }
18091 +#endif /* DWC_HOST_ONLY */
18092 + return count;
18093 +}
18094 +
18095 +DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show,
18096 + remote_wakeup_store);
18097 +
18098 +/**
18099 + * Show the whether core is hibernated or not.
18100 + */
18101 +static ssize_t rem_wakeup_pwrdn_show(struct device *_dev,
18102 + struct device_attribute *attr, char *buf)
18103 +{
18104 +#ifndef DWC_HOST_ONLY
18105 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18106 +
18107 + if (dwc_otg_get_core_state(otg_dev->core_if)) {
18108 + DWC_PRINTF("Core is in hibernation\n");
18109 + } else {
18110 + DWC_PRINTF("Core is not in hibernation\n");
18111 + }
18112 +#endif /* DWC_HOST_ONLY */
18113 + return 0;
18114 +}
18115 +
18116 +extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
18117 + int rem_wakeup, int reset);
18118 +
18119 +/**
18120 + * Initiate a remote wakeup of the device to exit from hibernation.
18121 + */
18122 +static ssize_t rem_wakeup_pwrdn_store(struct device *_dev,
18123 + struct device_attribute *attr,
18124 + const char *buf, size_t count)
18125 +{
18126 +#ifndef DWC_HOST_ONLY
18127 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18128 + dwc_otg_device_hibernation_restore(otg_dev->core_if, 1, 0);
18129 +#endif
18130 + return count;
18131 +}
18132 +
18133 +DEVICE_ATTR(rem_wakeup_pwrdn, S_IRUGO | S_IWUSR, rem_wakeup_pwrdn_show,
18134 + rem_wakeup_pwrdn_store);
18135 +
18136 +static ssize_t disconnect_us(struct device *_dev,
18137 + struct device_attribute *attr,
18138 + const char *buf, size_t count)
18139 +{
18140 +
18141 +#ifndef DWC_HOST_ONLY
18142 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18143 + uint32_t val = simple_strtoul(buf, NULL, 16);
18144 + DWC_PRINTF("The Passed value is %04x\n", val);
18145 +
18146 + dwc_otg_pcd_disconnect_us(otg_dev->pcd, 50);
18147 +
18148 +#endif /* DWC_HOST_ONLY */
18149 + return count;
18150 +}
18151 +
18152 +DEVICE_ATTR(disconnect_us, S_IWUSR, 0, disconnect_us);
18153 +
18154 +/**
18155 + * Dump global registers and either host or device registers (depending on the
18156 + * current mode of the core).
18157 + */
18158 +static ssize_t regdump_show(struct device *_dev,
18159 + struct device_attribute *attr, char *buf)
18160 +{
18161 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18162 +
18163 + dwc_otg_dump_global_registers(otg_dev->core_if);
18164 + if (dwc_otg_is_host_mode(otg_dev->core_if)) {
18165 + dwc_otg_dump_host_registers(otg_dev->core_if);
18166 + } else {
18167 + dwc_otg_dump_dev_registers(otg_dev->core_if);
18168 +
18169 + }
18170 + return sprintf(buf, "Register Dump\n");
18171 +}
18172 +
18173 +DEVICE_ATTR(regdump, S_IRUGO, regdump_show, 0);
18174 +
18175 +/**
18176 + * Dump global registers and either host or device registers (depending on the
18177 + * current mode of the core).
18178 + */
18179 +static ssize_t spramdump_show(struct device *_dev,
18180 + struct device_attribute *attr, char *buf)
18181 +{
18182 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18183 +
18184 + dwc_otg_dump_spram(otg_dev->core_if);
18185 +
18186 + return sprintf(buf, "SPRAM Dump\n");
18187 +}
18188 +
18189 +DEVICE_ATTR(spramdump, S_IRUGO, spramdump_show, 0);
18190 +
18191 +/**
18192 + * Dump the current hcd state.
18193 + */
18194 +static ssize_t hcddump_show(struct device *_dev,
18195 + struct device_attribute *attr, char *buf)
18196 +{
18197 +#ifndef DWC_DEVICE_ONLY
18198 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18199 + dwc_otg_hcd_dump_state(otg_dev->hcd);
18200 +#endif /* DWC_DEVICE_ONLY */
18201 + return sprintf(buf, "HCD Dump\n");
18202 +}
18203 +
18204 +DEVICE_ATTR(hcddump, S_IRUGO, hcddump_show, 0);
18205 +
18206 +/**
18207 + * Dump the average frame remaining at SOF. This can be used to
18208 + * determine average interrupt latency. Frame remaining is also shown for
18209 + * start transfer and two additional sample points.
18210 + */
18211 +static ssize_t hcd_frrem_show(struct device *_dev,
18212 + struct device_attribute *attr, char *buf)
18213 +{
18214 +#ifndef DWC_DEVICE_ONLY
18215 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18216 +
18217 + dwc_otg_hcd_dump_frrem(otg_dev->hcd);
18218 +#endif /* DWC_DEVICE_ONLY */
18219 + return sprintf(buf, "HCD Dump Frame Remaining\n");
18220 +}
18221 +
18222 +DEVICE_ATTR(hcd_frrem, S_IRUGO, hcd_frrem_show, 0);
18223 +
18224 +/**
18225 + * Displays the time required to read the GNPTXFSIZ register many times (the
18226 + * output shows the number of times the register is read).
18227 + */
18228 +#define RW_REG_COUNT 10000000
18229 +#define MSEC_PER_JIFFIE 1000/HZ
18230 +static ssize_t rd_reg_test_show(struct device *_dev,
18231 + struct device_attribute *attr, char *buf)
18232 +{
18233 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18234 + int i;
18235 + int time;
18236 + int start_jiffies;
18237 +
18238 + printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
18239 + HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
18240 + start_jiffies = jiffies;
18241 + for (i = 0; i < RW_REG_COUNT; i++) {
18242 + dwc_otg_get_gnptxfsiz(otg_dev->core_if);
18243 + }
18244 + time = jiffies - start_jiffies;
18245 + return sprintf(buf,
18246 + "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
18247 + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
18248 +}
18249 +
18250 +DEVICE_ATTR(rd_reg_test, S_IRUGO, rd_reg_test_show, 0);
18251 +
18252 +/**
18253 + * Displays the time required to write the GNPTXFSIZ register many times (the
18254 + * output shows the number of times the register is written).
18255 + */
18256 +static ssize_t wr_reg_test_show(struct device *_dev,
18257 + struct device_attribute *attr, char *buf)
18258 +{
18259 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18260 + uint32_t reg_val;
18261 + int i;
18262 + int time;
18263 + int start_jiffies;
18264 +
18265 + printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
18266 + HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
18267 + reg_val = dwc_otg_get_gnptxfsiz(otg_dev->core_if);
18268 + start_jiffies = jiffies;
18269 + for (i = 0; i < RW_REG_COUNT; i++) {
18270 + dwc_otg_set_gnptxfsiz(otg_dev->core_if, reg_val);
18271 + }
18272 + time = jiffies - start_jiffies;
18273 + return sprintf(buf,
18274 + "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
18275 + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
18276 +}
18277 +
18278 +DEVICE_ATTR(wr_reg_test, S_IRUGO, wr_reg_test_show, 0);
18279 +
18280 +#ifdef CONFIG_USB_DWC_OTG_LPM
18281 +
18282 +/**
18283 +* Show the lpm_response attribute.
18284 +*/
18285 +static ssize_t lpmresp_show(struct device *_dev,
18286 + struct device_attribute *attr, char *buf)
18287 +{
18288 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18289 +
18290 + if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
18291 + return sprintf(buf, "** LPM is DISABLED **\n");
18292 +
18293 + if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
18294 + return sprintf(buf, "** Current mode is not device mode\n");
18295 + }
18296 + return sprintf(buf, "lpm_response = %d\n",
18297 + dwc_otg_get_lpmresponse(otg_dev->core_if));
18298 +}
18299 +
18300 +/**
18301 +* Store the lpm_response attribute.
18302 +*/
18303 +static ssize_t lpmresp_store(struct device *_dev,
18304 + struct device_attribute *attr,
18305 + const char *buf, size_t count)
18306 +{
18307 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18308 + uint32_t val = simple_strtoul(buf, NULL, 16);
18309 +
18310 + if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if)) {
18311 + return 0;
18312 + }
18313 +
18314 + if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
18315 + return 0;
18316 + }
18317 +
18318 + dwc_otg_set_lpmresponse(otg_dev->core_if, val);
18319 + return count;
18320 +}
18321 +
18322 +DEVICE_ATTR(lpm_response, S_IRUGO | S_IWUSR, lpmresp_show, lpmresp_store);
18323 +
18324 +/**
18325 +* Show the sleep_status attribute.
18326 +*/
18327 +static ssize_t sleepstatus_show(struct device *_dev,
18328 + struct device_attribute *attr, char *buf)
18329 +{
18330 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18331 + return sprintf(buf, "Sleep Status = %d\n",
18332 + dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if));
18333 +}
18334 +
18335 +/**
18336 + * Store the sleep_status attribure.
18337 + */
18338 +static ssize_t sleepstatus_store(struct device *_dev,
18339 + struct device_attribute *attr,
18340 + const char *buf, size_t count)
18341 +{
18342 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18343 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
18344 +
18345 + if (dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if)) {
18346 + if (dwc_otg_is_host_mode(core_if)) {
18347 +
18348 + DWC_PRINTF("Host initiated resume\n");
18349 + dwc_otg_set_prtresume(otg_dev->core_if, 1);
18350 + }
18351 + }
18352 +
18353 + return count;
18354 +}
18355 +
18356 +DEVICE_ATTR(sleep_status, S_IRUGO | S_IWUSR, sleepstatus_show,
18357 + sleepstatus_store);
18358 +
18359 +#endif /* CONFIG_USB_DWC_OTG_LPM_ENABLE */
18360 +
18361 +/**@}*/
18362 +
18363 +/**
18364 + * Create the device files
18365 + */
18366 +void dwc_otg_attr_create(
18367 +#ifdef LM_INTERFACE
18368 + struct lm_device *dev
18369 +#elif defined(PCI_INTERFACE)
18370 + struct pci_dev *dev
18371 +#elif defined(PLATFORM_INTERFACE)
18372 + struct platform_device *dev
18373 +#endif
18374 + )
18375 +{
18376 + int error;
18377 +
18378 + error = device_create_file(&dev->dev, &dev_attr_regoffset);
18379 + error = device_create_file(&dev->dev, &dev_attr_regvalue);
18380 + error = device_create_file(&dev->dev, &dev_attr_mode);
18381 + error = device_create_file(&dev->dev, &dev_attr_hnpcapable);
18382 + error = device_create_file(&dev->dev, &dev_attr_srpcapable);
18383 + error = device_create_file(&dev->dev, &dev_attr_hsic_connect);
18384 + error = device_create_file(&dev->dev, &dev_attr_inv_sel_hsic);
18385 + error = device_create_file(&dev->dev, &dev_attr_hnp);
18386 + error = device_create_file(&dev->dev, &dev_attr_srp);
18387 + error = device_create_file(&dev->dev, &dev_attr_buspower);
18388 + error = device_create_file(&dev->dev, &dev_attr_bussuspend);
18389 + error = device_create_file(&dev->dev, &dev_attr_mode_ch_tim_en);
18390 + error = device_create_file(&dev->dev, &dev_attr_fr_interval);
18391 + error = device_create_file(&dev->dev, &dev_attr_busconnected);
18392 + error = device_create_file(&dev->dev, &dev_attr_gotgctl);
18393 + error = device_create_file(&dev->dev, &dev_attr_gusbcfg);
18394 + error = device_create_file(&dev->dev, &dev_attr_grxfsiz);
18395 + error = device_create_file(&dev->dev, &dev_attr_gnptxfsiz);
18396 + error = device_create_file(&dev->dev, &dev_attr_gpvndctl);
18397 + error = device_create_file(&dev->dev, &dev_attr_ggpio);
18398 + error = device_create_file(&dev->dev, &dev_attr_guid);
18399 + error = device_create_file(&dev->dev, &dev_attr_gsnpsid);
18400 + error = device_create_file(&dev->dev, &dev_attr_devspeed);
18401 + error = device_create_file(&dev->dev, &dev_attr_enumspeed);
18402 + error = device_create_file(&dev->dev, &dev_attr_hptxfsiz);
18403 + error = device_create_file(&dev->dev, &dev_attr_hprt0);
18404 + error = device_create_file(&dev->dev, &dev_attr_remote_wakeup);
18405 + error = device_create_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
18406 + error = device_create_file(&dev->dev, &dev_attr_disconnect_us);
18407 + error = device_create_file(&dev->dev, &dev_attr_regdump);
18408 + error = device_create_file(&dev->dev, &dev_attr_spramdump);
18409 + error = device_create_file(&dev->dev, &dev_attr_hcddump);
18410 + error = device_create_file(&dev->dev, &dev_attr_hcd_frrem);
18411 + error = device_create_file(&dev->dev, &dev_attr_rd_reg_test);
18412 + error = device_create_file(&dev->dev, &dev_attr_wr_reg_test);
18413 +#ifdef CONFIG_USB_DWC_OTG_LPM
18414 + error = device_create_file(&dev->dev, &dev_attr_lpm_response);
18415 + error = device_create_file(&dev->dev, &dev_attr_sleep_status);
18416 +#endif
18417 +}
18418 +
18419 +/**
18420 + * Remove the device files
18421 + */
18422 +void dwc_otg_attr_remove(
18423 +#ifdef LM_INTERFACE
18424 + struct lm_device *dev
18425 +#elif defined(PCI_INTERFACE)
18426 + struct pci_dev *dev
18427 +#elif defined(PLATFORM_INTERFACE)
18428 + struct platform_device *dev
18429 +#endif
18430 + )
18431 +{
18432 + device_remove_file(&dev->dev, &dev_attr_regoffset);
18433 + device_remove_file(&dev->dev, &dev_attr_regvalue);
18434 + device_remove_file(&dev->dev, &dev_attr_mode);
18435 + device_remove_file(&dev->dev, &dev_attr_hnpcapable);
18436 + device_remove_file(&dev->dev, &dev_attr_srpcapable);
18437 + device_remove_file(&dev->dev, &dev_attr_hsic_connect);
18438 + device_remove_file(&dev->dev, &dev_attr_inv_sel_hsic);
18439 + device_remove_file(&dev->dev, &dev_attr_hnp);
18440 + device_remove_file(&dev->dev, &dev_attr_srp);
18441 + device_remove_file(&dev->dev, &dev_attr_buspower);
18442 + device_remove_file(&dev->dev, &dev_attr_bussuspend);
18443 + device_remove_file(&dev->dev, &dev_attr_mode_ch_tim_en);
18444 + device_remove_file(&dev->dev, &dev_attr_fr_interval);
18445 + device_remove_file(&dev->dev, &dev_attr_busconnected);
18446 + device_remove_file(&dev->dev, &dev_attr_gotgctl);
18447 + device_remove_file(&dev->dev, &dev_attr_gusbcfg);
18448 + device_remove_file(&dev->dev, &dev_attr_grxfsiz);
18449 + device_remove_file(&dev->dev, &dev_attr_gnptxfsiz);
18450 + device_remove_file(&dev->dev, &dev_attr_gpvndctl);
18451 + device_remove_file(&dev->dev, &dev_attr_ggpio);
18452 + device_remove_file(&dev->dev, &dev_attr_guid);
18453 + device_remove_file(&dev->dev, &dev_attr_gsnpsid);
18454 + device_remove_file(&dev->dev, &dev_attr_devspeed);
18455 + device_remove_file(&dev->dev, &dev_attr_enumspeed);
18456 + device_remove_file(&dev->dev, &dev_attr_hptxfsiz);
18457 + device_remove_file(&dev->dev, &dev_attr_hprt0);
18458 + device_remove_file(&dev->dev, &dev_attr_remote_wakeup);
18459 + device_remove_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
18460 + device_remove_file(&dev->dev, &dev_attr_disconnect_us);
18461 + device_remove_file(&dev->dev, &dev_attr_regdump);
18462 + device_remove_file(&dev->dev, &dev_attr_spramdump);
18463 + device_remove_file(&dev->dev, &dev_attr_hcddump);
18464 + device_remove_file(&dev->dev, &dev_attr_hcd_frrem);
18465 + device_remove_file(&dev->dev, &dev_attr_rd_reg_test);
18466 + device_remove_file(&dev->dev, &dev_attr_wr_reg_test);
18467 +#ifdef CONFIG_USB_DWC_OTG_LPM
18468 + device_remove_file(&dev->dev, &dev_attr_lpm_response);
18469 + device_remove_file(&dev->dev, &dev_attr_sleep_status);
18470 +#endif
18471 +}
18472 --- /dev/null
18473 +++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.h
18474 @@ -0,0 +1,89 @@
18475 +/* ==========================================================================
18476 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.h $
18477 + * $Revision: #13 $
18478 + * $Date: 2010/06/21 $
18479 + * $Change: 1532021 $
18480 + *
18481 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
18482 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
18483 + * otherwise expressly agreed to in writing between Synopsys and you.
18484 + *
18485 + * The Software IS NOT an item of Licensed Software or Licensed Product under
18486 + * any End User Software License Agreement or Agreement for Licensed Product
18487 + * with Synopsys or any supplement thereto. You are permitted to use and
18488 + * redistribute this Software in source and binary forms, with or without
18489 + * modification, provided that redistributions of source code must retain this
18490 + * notice. You may not view, use, disclose, copy or distribute this file or
18491 + * any information contained herein except pursuant to this license grant from
18492 + * Synopsys. If you do not agree with this notice, including the disclaimer
18493 + * below, then you are not authorized to use the Software.
18494 + *
18495 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
18496 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18497 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18498 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
18499 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18500 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18501 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
18502 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18503 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18504 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
18505 + * DAMAGE.
18506 + * ========================================================================== */
18507 +
18508 +#if !defined(__DWC_OTG_ATTR_H__)
18509 +#define __DWC_OTG_ATTR_H__
18510 +
18511 +/** @file
18512 + * This file contains the interface to the Linux device attributes.
18513 + */
18514 +extern struct device_attribute dev_attr_regoffset;
18515 +extern struct device_attribute dev_attr_regvalue;
18516 +
18517 +extern struct device_attribute dev_attr_mode;
18518 +extern struct device_attribute dev_attr_hnpcapable;
18519 +extern struct device_attribute dev_attr_srpcapable;
18520 +extern struct device_attribute dev_attr_hnp;
18521 +extern struct device_attribute dev_attr_srp;
18522 +extern struct device_attribute dev_attr_buspower;
18523 +extern struct device_attribute dev_attr_bussuspend;
18524 +extern struct device_attribute dev_attr_mode_ch_tim_en;
18525 +extern struct device_attribute dev_attr_fr_interval;
18526 +extern struct device_attribute dev_attr_busconnected;
18527 +extern struct device_attribute dev_attr_gotgctl;
18528 +extern struct device_attribute dev_attr_gusbcfg;
18529 +extern struct device_attribute dev_attr_grxfsiz;
18530 +extern struct device_attribute dev_attr_gnptxfsiz;
18531 +extern struct device_attribute dev_attr_gpvndctl;
18532 +extern struct device_attribute dev_attr_ggpio;
18533 +extern struct device_attribute dev_attr_guid;
18534 +extern struct device_attribute dev_attr_gsnpsid;
18535 +extern struct device_attribute dev_attr_devspeed;
18536 +extern struct device_attribute dev_attr_enumspeed;
18537 +extern struct device_attribute dev_attr_hptxfsiz;
18538 +extern struct device_attribute dev_attr_hprt0;
18539 +#ifdef CONFIG_USB_DWC_OTG_LPM
18540 +extern struct device_attribute dev_attr_lpm_response;
18541 +extern struct device_attribute devi_attr_sleep_status;
18542 +#endif
18543 +
18544 +void dwc_otg_attr_create(
18545 +#ifdef LM_INTERFACE
18546 + struct lm_device *dev
18547 +#elif defined(PCI_INTERFACE)
18548 + struct pci_dev *dev
18549 +#elif defined(PLATFORM_INTERFACE)
18550 + struct platform_device *dev
18551 +#endif
18552 + );
18553 +
18554 +void dwc_otg_attr_remove(
18555 +#ifdef LM_INTERFACE
18556 + struct lm_device *dev
18557 +#elif defined(PCI_INTERFACE)
18558 + struct pci_dev *dev
18559 +#elif defined(PLATFORM_INTERFACE)
18560 + struct platform_device *dev
18561 +#endif
18562 + );
18563 +#endif
18564 --- /dev/null
18565 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.c
18566 @@ -0,0 +1,1876 @@
18567 +/* ==========================================================================
18568 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
18569 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
18570 + * otherwise expressly agreed to in writing between Synopsys and you.
18571 + *
18572 + * The Software IS NOT an item of Licensed Software or Licensed Product under
18573 + * any End User Software License Agreement or Agreement for Licensed Product
18574 + * with Synopsys or any supplement thereto. You are permitted to use and
18575 + * redistribute this Software in source and binary forms, with or without
18576 + * modification, provided that redistributions of source code must retain this
18577 + * notice. You may not view, use, disclose, copy or distribute this file or
18578 + * any information contained herein except pursuant to this license grant from
18579 + * Synopsys. If you do not agree with this notice, including the disclaimer
18580 + * below, then you are not authorized to use the Software.
18581 + *
18582 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
18583 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18584 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18585 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
18586 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18587 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18588 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
18589 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18590 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18591 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
18592 + * DAMAGE.
18593 + * ========================================================================== */
18594 +
18595 +/** @file
18596 + *
18597 + * This file contains the most of the CFI(Core Feature Interface)
18598 + * implementation for the OTG.
18599 + */
18600 +
18601 +#ifdef DWC_UTE_CFI
18602 +
18603 +#include "dwc_otg_pcd.h"
18604 +#include "dwc_otg_cfi.h"
18605 +
18606 +/** This definition should actually migrate to the Portability Library */
18607 +#define DWC_CONSTANT_CPU_TO_LE16(x) (x)
18608 +
18609 +extern dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex);
18610 +
18611 +static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen);
18612 +static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
18613 + struct dwc_otg_pcd *pcd,
18614 + struct cfi_usb_ctrlrequest *ctrl_req);
18615 +static int cfi_set_feature_value(struct dwc_otg_pcd *pcd);
18616 +static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
18617 + struct cfi_usb_ctrlrequest *req);
18618 +static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
18619 + struct cfi_usb_ctrlrequest *req);
18620 +static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
18621 + struct cfi_usb_ctrlrequest *req);
18622 +static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
18623 + struct cfi_usb_ctrlrequest *req);
18624 +static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep);
18625 +
18626 +static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if);
18627 +static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue);
18628 +static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue);
18629 +
18630 +static uint8_t resize_fifos(dwc_otg_core_if_t * core_if);
18631 +
18632 +/** This is the header of the all features descriptor */
18633 +static cfi_all_features_header_t all_props_desc_header = {
18634 + .wVersion = DWC_CONSTANT_CPU_TO_LE16(0x100),
18635 + .wCoreID = DWC_CONSTANT_CPU_TO_LE16(CFI_CORE_ID_OTG),
18636 + .wNumFeatures = DWC_CONSTANT_CPU_TO_LE16(9),
18637 +};
18638 +
18639 +/** This is an array of statically allocated feature descriptors */
18640 +static cfi_feature_desc_header_t prop_descs[] = {
18641 +
18642 + /* FT_ID_DMA_MODE */
18643 + {
18644 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_MODE),
18645 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18646 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(1),
18647 + },
18648 +
18649 + /* FT_ID_DMA_BUFFER_SETUP */
18650 + {
18651 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFFER_SETUP),
18652 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18653 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
18654 + },
18655 +
18656 + /* FT_ID_DMA_BUFF_ALIGN */
18657 + {
18658 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFF_ALIGN),
18659 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18660 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
18661 + },
18662 +
18663 + /* FT_ID_DMA_CONCAT_SETUP */
18664 + {
18665 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CONCAT_SETUP),
18666 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18667 + //.wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
18668 + },
18669 +
18670 + /* FT_ID_DMA_CIRCULAR */
18671 + {
18672 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CIRCULAR),
18673 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18674 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
18675 + },
18676 +
18677 + /* FT_ID_THRESHOLD_SETUP */
18678 + {
18679 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_THRESHOLD_SETUP),
18680 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18681 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
18682 + },
18683 +
18684 + /* FT_ID_DFIFO_DEPTH */
18685 + {
18686 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DFIFO_DEPTH),
18687 + .bmAttributes = CFI_FEATURE_ATTR_RO,
18688 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
18689 + },
18690 +
18691 + /* FT_ID_TX_FIFO_DEPTH */
18692 + {
18693 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_TX_FIFO_DEPTH),
18694 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18695 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
18696 + },
18697 +
18698 + /* FT_ID_RX_FIFO_DEPTH */
18699 + {
18700 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_RX_FIFO_DEPTH),
18701 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18702 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
18703 + }
18704 +};
18705 +
18706 +/** The table of feature names */
18707 +cfi_string_t prop_name_table[] = {
18708 + {FT_ID_DMA_MODE, "dma_mode"},
18709 + {FT_ID_DMA_BUFFER_SETUP, "buffer_setup"},
18710 + {FT_ID_DMA_BUFF_ALIGN, "buffer_align"},
18711 + {FT_ID_DMA_CONCAT_SETUP, "concat_setup"},
18712 + {FT_ID_DMA_CIRCULAR, "buffer_circular"},
18713 + {FT_ID_THRESHOLD_SETUP, "threshold_setup"},
18714 + {FT_ID_DFIFO_DEPTH, "dfifo_depth"},
18715 + {FT_ID_TX_FIFO_DEPTH, "txfifo_depth"},
18716 + {FT_ID_RX_FIFO_DEPTH, "rxfifo_depth"},
18717 + {}
18718 +};
18719 +
18720 +/************************************************************************/
18721 +
18722 +/**
18723 + * Returns the name of the feature by its ID
18724 + * or NULL if no featute ID matches.
18725 + *
18726 + */
18727 +const uint8_t *get_prop_name(uint16_t prop_id, int *len)
18728 +{
18729 + cfi_string_t *pstr;
18730 + *len = 0;
18731 +
18732 + for (pstr = prop_name_table; pstr && pstr->s; pstr++) {
18733 + if (pstr->id == prop_id) {
18734 + *len = DWC_STRLEN(pstr->s);
18735 + return pstr->s;
18736 + }
18737 + }
18738 + return NULL;
18739 +}
18740 +
18741 +/**
18742 + * This function handles all CFI specific control requests.
18743 + *
18744 + * Return a negative value to stall the DCE.
18745 + */
18746 +int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl)
18747 +{
18748 + int retval = 0;
18749 + dwc_otg_pcd_ep_t *ep = NULL;
18750 + cfiobject_t *cfi = pcd->cfi;
18751 + struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
18752 + uint16_t wLen = DWC_LE16_TO_CPU(&ctrl->wLength);
18753 + uint16_t wValue = DWC_LE16_TO_CPU(&ctrl->wValue);
18754 + uint16_t wIndex = DWC_LE16_TO_CPU(&ctrl->wIndex);
18755 + uint32_t regaddr = 0;
18756 + uint32_t regval = 0;
18757 +
18758 + /* Save this Control Request in the CFI object.
18759 + * The data field will be assigned in the data stage completion CB function.
18760 + */
18761 + cfi->ctrl_req = *ctrl;
18762 + cfi->ctrl_req.data = NULL;
18763 +
18764 + cfi->need_gadget_att = 0;
18765 + cfi->need_status_in_complete = 0;
18766 +
18767 + switch (ctrl->bRequest) {
18768 + case VEN_CORE_GET_FEATURES:
18769 + retval = cfi_core_features_buf(cfi->buf_in.buf, CFI_IN_BUF_LEN);
18770 + if (retval >= 0) {
18771 + //dump_msg(cfi->buf_in.buf, retval);
18772 + ep = &pcd->ep0;
18773 +
18774 + retval = min((uint16_t) retval, wLen);
18775 + /* Transfer this buffer to the host through the EP0-IN EP */
18776 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
18777 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
18778 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
18779 + ep->dwc_ep.xfer_len = retval;
18780 + ep->dwc_ep.xfer_count = 0;
18781 + ep->dwc_ep.sent_zlp = 0;
18782 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
18783 +
18784 + pcd->ep0_pending = 1;
18785 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
18786 + }
18787 + retval = 0;
18788 + break;
18789 +
18790 + case VEN_CORE_GET_FEATURE:
18791 + CFI_INFO("VEN_CORE_GET_FEATURE\n");
18792 + retval = cfi_get_feature_value(cfi->buf_in.buf, CFI_IN_BUF_LEN,
18793 + pcd, ctrl);
18794 + if (retval >= 0) {
18795 + ep = &pcd->ep0;
18796 +
18797 + retval = min((uint16_t) retval, wLen);
18798 + /* Transfer this buffer to the host through the EP0-IN EP */
18799 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
18800 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
18801 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
18802 + ep->dwc_ep.xfer_len = retval;
18803 + ep->dwc_ep.xfer_count = 0;
18804 + ep->dwc_ep.sent_zlp = 0;
18805 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
18806 +
18807 + pcd->ep0_pending = 1;
18808 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
18809 + }
18810 + CFI_INFO("VEN_CORE_GET_FEATURE=%d\n", retval);
18811 + dump_msg(cfi->buf_in.buf, retval);
18812 + break;
18813 +
18814 + case VEN_CORE_SET_FEATURE:
18815 + CFI_INFO("VEN_CORE_SET_FEATURE\n");
18816 + /* Set up an XFER to get the data stage of the control request,
18817 + * which is the new value of the feature to be modified.
18818 + */
18819 + ep = &pcd->ep0;
18820 + ep->dwc_ep.is_in = 0;
18821 + ep->dwc_ep.dma_addr = cfi->buf_out.addr;
18822 + ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
18823 + ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
18824 + ep->dwc_ep.xfer_len = wLen;
18825 + ep->dwc_ep.xfer_count = 0;
18826 + ep->dwc_ep.sent_zlp = 0;
18827 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
18828 +
18829 + pcd->ep0_pending = 1;
18830 + /* Read the control write's data stage */
18831 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
18832 + retval = 0;
18833 + break;
18834 +
18835 + case VEN_CORE_RESET_FEATURES:
18836 + CFI_INFO("VEN_CORE_RESET_FEATURES\n");
18837 + cfi->need_gadget_att = 1;
18838 + cfi->need_status_in_complete = 1;
18839 + retval = cfi_preproc_reset(pcd, ctrl);
18840 + CFI_INFO("VEN_CORE_RESET_FEATURES = (%d)\n", retval);
18841 + break;
18842 +
18843 + case VEN_CORE_ACTIVATE_FEATURES:
18844 + CFI_INFO("VEN_CORE_ACTIVATE_FEATURES\n");
18845 + break;
18846 +
18847 + case VEN_CORE_READ_REGISTER:
18848 + CFI_INFO("VEN_CORE_READ_REGISTER\n");
18849 + /* wValue optionally contains the HI WORD of the register offset and
18850 + * wIndex contains the LOW WORD of the register offset
18851 + */
18852 + if (wValue == 0) {
18853 + /* @TODO - MAS - fix the access to the base field */
18854 + regaddr = 0;
18855 + //regaddr = (uint32_t) pcd->otg_dev->os_dep.base;
18856 + //GET_CORE_IF(pcd)->co
18857 + regaddr |= wIndex;
18858 + } else {
18859 + regaddr = (wValue << 16) | wIndex;
18860 + }
18861 +
18862 + /* Read a 32-bit value of the memory at the regaddr */
18863 + regval = DWC_READ_REG32((uint32_t *) regaddr);
18864 +
18865 + ep = &pcd->ep0;
18866 + dwc_memcpy(cfi->buf_in.buf, &regval, sizeof(uint32_t));
18867 + ep->dwc_ep.is_in = 1;
18868 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
18869 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
18870 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
18871 + ep->dwc_ep.xfer_len = wLen;
18872 + ep->dwc_ep.xfer_count = 0;
18873 + ep->dwc_ep.sent_zlp = 0;
18874 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
18875 +
18876 + pcd->ep0_pending = 1;
18877 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
18878 + cfi->need_gadget_att = 0;
18879 + retval = 0;
18880 + break;
18881 +
18882 + case VEN_CORE_WRITE_REGISTER:
18883 + CFI_INFO("VEN_CORE_WRITE_REGISTER\n");
18884 + /* Set up an XFER to get the data stage of the control request,
18885 + * which is the new value of the register to be modified.
18886 + */
18887 + ep = &pcd->ep0;
18888 + ep->dwc_ep.is_in = 0;
18889 + ep->dwc_ep.dma_addr = cfi->buf_out.addr;
18890 + ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
18891 + ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
18892 + ep->dwc_ep.xfer_len = wLen;
18893 + ep->dwc_ep.xfer_count = 0;
18894 + ep->dwc_ep.sent_zlp = 0;
18895 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
18896 +
18897 + pcd->ep0_pending = 1;
18898 + /* Read the control write's data stage */
18899 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
18900 + retval = 0;
18901 + break;
18902 +
18903 + default:
18904 + retval = -DWC_E_NOT_SUPPORTED;
18905 + break;
18906 + }
18907 +
18908 + return retval;
18909 +}
18910 +
18911 +/**
18912 + * This function prepares the core features descriptors and copies its
18913 + * raw representation into the buffer <buf>.
18914 + *
18915 + * The buffer structure is as follows:
18916 + * all_features_header (8 bytes)
18917 + * features_#1 (8 bytes + feature name string length)
18918 + * features_#2 (8 bytes + feature name string length)
18919 + * .....
18920 + * features_#n - where n=the total count of feature descriptors
18921 + */
18922 +static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen)
18923 +{
18924 + cfi_feature_desc_header_t *prop_hdr = prop_descs;
18925 + cfi_feature_desc_header_t *prop;
18926 + cfi_all_features_header_t *all_props_hdr = &all_props_desc_header;
18927 + cfi_all_features_header_t *tmp;
18928 + uint8_t *tmpbuf = buf;
18929 + const uint8_t *pname = NULL;
18930 + int i, j, namelen = 0, totlen;
18931 +
18932 + /* Prepare and copy the core features into the buffer */
18933 + CFI_INFO("%s:\n", __func__);
18934 +
18935 + tmp = (cfi_all_features_header_t *) tmpbuf;
18936 + *tmp = *all_props_hdr;
18937 + tmpbuf += CFI_ALL_FEATURES_HDR_LEN;
18938 +
18939 + j = sizeof(prop_descs) / sizeof(cfi_all_features_header_t);
18940 + for (i = 0; i < j; i++, prop_hdr++) {
18941 + pname = get_prop_name(prop_hdr->wFeatureID, &namelen);
18942 + prop = (cfi_feature_desc_header_t *) tmpbuf;
18943 + *prop = *prop_hdr;
18944 +
18945 + prop->bNameLen = namelen;
18946 + prop->wLength =
18947 + DWC_CONSTANT_CPU_TO_LE16(CFI_FEATURE_DESC_HDR_LEN +
18948 + namelen);
18949 +
18950 + tmpbuf += CFI_FEATURE_DESC_HDR_LEN;
18951 + dwc_memcpy(tmpbuf, pname, namelen);
18952 + tmpbuf += namelen;
18953 + }
18954 +
18955 + totlen = tmpbuf - buf;
18956 +
18957 + if (totlen > 0) {
18958 + tmp = (cfi_all_features_header_t *) buf;
18959 + tmp->wTotalLen = DWC_CONSTANT_CPU_TO_LE16(totlen);
18960 + }
18961 +
18962 + return totlen;
18963 +}
18964 +
18965 +/**
18966 + * This function releases all the dynamic memory in the CFI object.
18967 + */
18968 +static void cfi_release(cfiobject_t * cfiobj)
18969 +{
18970 + cfi_ep_t *cfiep;
18971 + dwc_list_link_t *tmp;
18972 +
18973 + CFI_INFO("%s\n", __func__);
18974 +
18975 + if (cfiobj->buf_in.buf) {
18976 + DWC_DMA_FREE(CFI_IN_BUF_LEN, cfiobj->buf_in.buf,
18977 + cfiobj->buf_in.addr);
18978 + cfiobj->buf_in.buf = NULL;
18979 + }
18980 +
18981 + if (cfiobj->buf_out.buf) {
18982 + DWC_DMA_FREE(CFI_OUT_BUF_LEN, cfiobj->buf_out.buf,
18983 + cfiobj->buf_out.addr);
18984 + cfiobj->buf_out.buf = NULL;
18985 + }
18986 +
18987 + /* Free the Buffer Setup values for each EP */
18988 + //list_for_each_entry(cfiep, &cfiobj->active_eps, lh) {
18989 + DWC_LIST_FOREACH(tmp, &cfiobj->active_eps) {
18990 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
18991 + cfi_free_ep_bs_dyn_data(cfiep);
18992 + }
18993 +}
18994 +
18995 +/**
18996 + * This function frees the dynamically allocated EP buffer setup data.
18997 + */
18998 +static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep)
18999 +{
19000 + if (cfiep->bm_sg) {
19001 + DWC_FREE(cfiep->bm_sg);
19002 + cfiep->bm_sg = NULL;
19003 + }
19004 +
19005 + if (cfiep->bm_align) {
19006 + DWC_FREE(cfiep->bm_align);
19007 + cfiep->bm_align = NULL;
19008 + }
19009 +
19010 + if (cfiep->bm_concat) {
19011 + if (NULL != cfiep->bm_concat->wTxBytes) {
19012 + DWC_FREE(cfiep->bm_concat->wTxBytes);
19013 + cfiep->bm_concat->wTxBytes = NULL;
19014 + }
19015 + DWC_FREE(cfiep->bm_concat);
19016 + cfiep->bm_concat = NULL;
19017 + }
19018 +}
19019 +
19020 +/**
19021 + * This function initializes the default values of the features
19022 + * for a specific endpoint and should be called only once when
19023 + * the EP is enabled first time.
19024 + */
19025 +static int cfi_ep_init_defaults(struct dwc_otg_pcd *pcd, cfi_ep_t * cfiep)
19026 +{
19027 + int retval = 0;
19028 +
19029 + cfiep->bm_sg = DWC_ALLOC(sizeof(ddma_sg_buffer_setup_t));
19030 + if (NULL == cfiep->bm_sg) {
19031 + CFI_INFO("Failed to allocate memory for SG feature value\n");
19032 + return -DWC_E_NO_MEMORY;
19033 + }
19034 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
19035 +
19036 + /* For the Concatenation feature's default value we do not allocate
19037 + * memory for the wTxBytes field - it will be done in the set_feature_value
19038 + * request handler.
19039 + */
19040 + cfiep->bm_concat = DWC_ALLOC(sizeof(ddma_concat_buffer_setup_t));
19041 + if (NULL == cfiep->bm_concat) {
19042 + CFI_INFO
19043 + ("Failed to allocate memory for CONCATENATION feature value\n");
19044 + DWC_FREE(cfiep->bm_sg);
19045 + return -DWC_E_NO_MEMORY;
19046 + }
19047 + dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
19048 +
19049 + cfiep->bm_align = DWC_ALLOC(sizeof(ddma_align_buffer_setup_t));
19050 + if (NULL == cfiep->bm_align) {
19051 + CFI_INFO
19052 + ("Failed to allocate memory for Alignment feature value\n");
19053 + DWC_FREE(cfiep->bm_sg);
19054 + DWC_FREE(cfiep->bm_concat);
19055 + return -DWC_E_NO_MEMORY;
19056 + }
19057 + dwc_memset(cfiep->bm_align, 0, sizeof(ddma_align_buffer_setup_t));
19058 +
19059 + return retval;
19060 +}
19061 +
19062 +/**
19063 + * The callback function that notifies the CFI on the activation of
19064 + * an endpoint in the PCD. The following steps are done in this function:
19065 + *
19066 + * Create a dynamically allocated cfi_ep_t object (a CFI wrapper to the PCD's
19067 + * active endpoint)
19068 + * Create MAX_DMA_DESCS_PER_EP count DMA Descriptors for the EP
19069 + * Set the Buffer Mode to standard
19070 + * Initialize the default values for all EP modes (SG, Circular, Concat, Align)
19071 + * Add the cfi_ep_t object to the list of active endpoints in the CFI object
19072 + */
19073 +static int cfi_ep_enable(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
19074 + struct dwc_otg_pcd_ep *ep)
19075 +{
19076 + cfi_ep_t *cfiep;
19077 + int retval = -DWC_E_NOT_SUPPORTED;
19078 +
19079 + CFI_INFO("%s: epname=%s; epnum=0x%02x\n", __func__,
19080 + "EP_" /*ep->ep.name */ , ep->desc->bEndpointAddress);
19081 + /* MAS - Check whether this endpoint already is in the list */
19082 + cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
19083 +
19084 + if (NULL == cfiep) {
19085 + /* Allocate a cfi_ep_t object */
19086 + cfiep = DWC_ALLOC(sizeof(cfi_ep_t));
19087 + if (NULL == cfiep) {
19088 + CFI_INFO
19089 + ("Unable to allocate memory for <cfiep> in function %s\n",
19090 + __func__);
19091 + return -DWC_E_NO_MEMORY;
19092 + }
19093 + dwc_memset(cfiep, 0, sizeof(cfi_ep_t));
19094 +
19095 + /* Save the dwc_otg_pcd_ep pointer in the cfiep object */
19096 + cfiep->ep = ep;
19097 +
19098 + /* Allocate the DMA Descriptors chain of MAX_DMA_DESCS_PER_EP count */
19099 + ep->dwc_ep.descs =
19100 + DWC_DMA_ALLOC(MAX_DMA_DESCS_PER_EP *
19101 + sizeof(dwc_otg_dma_desc_t),
19102 + &ep->dwc_ep.descs_dma_addr);
19103 +
19104 + if (NULL == ep->dwc_ep.descs) {
19105 + DWC_FREE(cfiep);
19106 + return -DWC_E_NO_MEMORY;
19107 + }
19108 +
19109 + DWC_LIST_INIT(&cfiep->lh);
19110 +
19111 + /* Set the buffer mode to BM_STANDARD. It will be modified
19112 + * when building descriptors for a specific buffer mode */
19113 + ep->dwc_ep.buff_mode = BM_STANDARD;
19114 +
19115 + /* Create and initialize the default values for this EP's Buffer modes */
19116 + if ((retval = cfi_ep_init_defaults(pcd, cfiep)) < 0)
19117 + return retval;
19118 +
19119 + /* Add the cfi_ep_t object to the CFI object's list of active endpoints */
19120 + DWC_LIST_INSERT_TAIL(&cfi->active_eps, &cfiep->lh);
19121 + retval = 0;
19122 + } else { /* The sought EP already is in the list */
19123 + CFI_INFO("%s: The sought EP already is in the list\n",
19124 + __func__);
19125 + }
19126 +
19127 + return retval;
19128 +}
19129 +
19130 +/**
19131 + * This function is called when the data stage of a 3-stage Control Write request
19132 + * is complete.
19133 + *
19134 + */
19135 +static int cfi_ctrl_write_complete(struct cfiobject *cfi,
19136 + struct dwc_otg_pcd *pcd)
19137 +{
19138 + uint32_t addr, reg_value;
19139 + uint16_t wIndex, wValue;
19140 + uint8_t bRequest;
19141 + uint8_t *buf = cfi->buf_out.buf;
19142 + //struct usb_ctrlrequest *ctrl_req = &cfi->ctrl_req_saved;
19143 + struct cfi_usb_ctrlrequest *ctrl_req = &cfi->ctrl_req;
19144 + int retval = -DWC_E_NOT_SUPPORTED;
19145 +
19146 + CFI_INFO("%s\n", __func__);
19147 +
19148 + bRequest = ctrl_req->bRequest;
19149 + wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
19150 + wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
19151 +
19152 + /*
19153 + * Save the pointer to the data stage in the ctrl_req's <data> field.
19154 + * The request should be already saved in the command stage by now.
19155 + */
19156 + ctrl_req->data = cfi->buf_out.buf;
19157 + cfi->need_status_in_complete = 0;
19158 + cfi->need_gadget_att = 0;
19159 +
19160 + switch (bRequest) {
19161 + case VEN_CORE_WRITE_REGISTER:
19162 + /* The buffer contains raw data of the new value for the register */
19163 + reg_value = *((uint32_t *) buf);
19164 + if (wValue == 0) {
19165 + addr = 0;
19166 + //addr = (uint32_t) pcd->otg_dev->os_dep.base;
19167 + addr += wIndex;
19168 + } else {
19169 + addr = (wValue << 16) | wIndex;
19170 + }
19171 +
19172 + //writel(reg_value, addr);
19173 +
19174 + retval = 0;
19175 + cfi->need_status_in_complete = 1;
19176 + break;
19177 +
19178 + case VEN_CORE_SET_FEATURE:
19179 + /* The buffer contains raw data of the new value of the feature */
19180 + retval = cfi_set_feature_value(pcd);
19181 + if (retval < 0)
19182 + return retval;
19183 +
19184 + cfi->need_status_in_complete = 1;
19185 + break;
19186 +
19187 + default:
19188 + break;
19189 + }
19190 +
19191 + return retval;
19192 +}
19193 +
19194 +/**
19195 + * This function builds the DMA descriptors for the SG buffer mode.
19196 + */
19197 +static void cfi_build_sg_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19198 + dwc_otg_pcd_request_t * req)
19199 +{
19200 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
19201 + ddma_sg_buffer_setup_t *sgval = cfiep->bm_sg;
19202 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
19203 + struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
19204 + dma_addr_t buff_addr = req->dma;
19205 + int i;
19206 + uint32_t txsize, off;
19207 +
19208 + txsize = sgval->wSize;
19209 + off = sgval->bOffset;
19210 +
19211 +// CFI_INFO("%s: %s TXSIZE=0x%08x; OFFSET=0x%08x\n",
19212 +// __func__, cfiep->ep->ep.name, txsize, off);
19213 +
19214 + for (i = 0; i < sgval->bCount; i++) {
19215 + desc->status.b.bs = BS_HOST_BUSY;
19216 + desc->buf = buff_addr;
19217 + desc->status.b.l = 0;
19218 + desc->status.b.ioc = 0;
19219 + desc->status.b.sp = 0;
19220 + desc->status.b.bytes = txsize;
19221 + desc->status.b.bs = BS_HOST_READY;
19222 +
19223 + /* Set the next address of the buffer */
19224 + buff_addr += txsize + off;
19225 + desc_last = desc;
19226 + desc++;
19227 + }
19228 +
19229 + /* Set the last, ioc and sp bits on the Last DMA Descriptor */
19230 + desc_last->status.b.l = 1;
19231 + desc_last->status.b.ioc = 1;
19232 + desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
19233 + /* Save the last DMA descriptor pointer */
19234 + cfiep->dma_desc_last = desc_last;
19235 + cfiep->desc_count = sgval->bCount;
19236 +}
19237 +
19238 +/**
19239 + * This function builds the DMA descriptors for the Concatenation buffer mode.
19240 + */
19241 +static void cfi_build_concat_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19242 + dwc_otg_pcd_request_t * req)
19243 +{
19244 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
19245 + ddma_concat_buffer_setup_t *concatval = cfiep->bm_concat;
19246 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
19247 + struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
19248 + dma_addr_t buff_addr = req->dma;
19249 + int i;
19250 + uint16_t *txsize;
19251 +
19252 + txsize = concatval->wTxBytes;
19253 +
19254 + for (i = 0; i < concatval->hdr.bDescCount; i++) {
19255 + desc->buf = buff_addr;
19256 + desc->status.b.bs = BS_HOST_BUSY;
19257 + desc->status.b.l = 0;
19258 + desc->status.b.ioc = 0;
19259 + desc->status.b.sp = 0;
19260 + desc->status.b.bytes = *txsize;
19261 + desc->status.b.bs = BS_HOST_READY;
19262 +
19263 + txsize++;
19264 + /* Set the next address of the buffer */
19265 + buff_addr += UGETW(ep->desc->wMaxPacketSize);
19266 + desc_last = desc;
19267 + desc++;
19268 + }
19269 +
19270 + /* Set the last, ioc and sp bits on the Last DMA Descriptor */
19271 + desc_last->status.b.l = 1;
19272 + desc_last->status.b.ioc = 1;
19273 + desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
19274 + cfiep->dma_desc_last = desc_last;
19275 + cfiep->desc_count = concatval->hdr.bDescCount;
19276 +}
19277 +
19278 +/**
19279 + * This function builds the DMA descriptors for the Circular buffer mode
19280 + */
19281 +static void cfi_build_circ_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19282 + dwc_otg_pcd_request_t * req)
19283 +{
19284 + /* @todo: MAS - add implementation when this feature needs to be tested */
19285 +}
19286 +
19287 +/**
19288 + * This function builds the DMA descriptors for the Alignment buffer mode
19289 + */
19290 +static void cfi_build_align_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19291 + dwc_otg_pcd_request_t * req)
19292 +{
19293 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
19294 + ddma_align_buffer_setup_t *alignval = cfiep->bm_align;
19295 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
19296 + dma_addr_t buff_addr = req->dma;
19297 +
19298 + desc->status.b.bs = BS_HOST_BUSY;
19299 + desc->status.b.l = 1;
19300 + desc->status.b.ioc = 1;
19301 + desc->status.b.sp = ep->dwc_ep.sent_zlp;
19302 + desc->status.b.bytes = req->length;
19303 + /* Adjust the buffer alignment */
19304 + desc->buf = (buff_addr + alignval->bAlign);
19305 + desc->status.b.bs = BS_HOST_READY;
19306 + cfiep->dma_desc_last = desc;
19307 + cfiep->desc_count = 1;
19308 +}
19309 +
19310 +/**
19311 + * This function builds the DMA descriptors chain for different modes of the
19312 + * buffer setup of an endpoint.
19313 + */
19314 +static void cfi_build_descriptors(struct cfiobject *cfi,
19315 + struct dwc_otg_pcd *pcd,
19316 + struct dwc_otg_pcd_ep *ep,
19317 + dwc_otg_pcd_request_t * req)
19318 +{
19319 + cfi_ep_t *cfiep;
19320 +
19321 + /* Get the cfiep by the dwc_otg_pcd_ep */
19322 + cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
19323 + if (NULL == cfiep) {
19324 + CFI_INFO("%s: Unable to find a matching active endpoint\n",
19325 + __func__);
19326 + return;
19327 + }
19328 +
19329 + cfiep->xfer_len = req->length;
19330 +
19331 + /* Iterate through all the DMA descriptors */
19332 + switch (cfiep->ep->dwc_ep.buff_mode) {
19333 + case BM_SG:
19334 + cfi_build_sg_descs(cfi, cfiep, req);
19335 + break;
19336 +
19337 + case BM_CONCAT:
19338 + cfi_build_concat_descs(cfi, cfiep, req);
19339 + break;
19340 +
19341 + case BM_CIRCULAR:
19342 + cfi_build_circ_descs(cfi, cfiep, req);
19343 + break;
19344 +
19345 + case BM_ALIGN:
19346 + cfi_build_align_descs(cfi, cfiep, req);
19347 + break;
19348 +
19349 + default:
19350 + break;
19351 + }
19352 +}
19353 +
19354 +/**
19355 + * Allocate DMA buffer for different Buffer modes.
19356 + */
19357 +static void *cfi_ep_alloc_buf(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
19358 + struct dwc_otg_pcd_ep *ep, dma_addr_t * dma,
19359 + unsigned size, gfp_t flags)
19360 +{
19361 + return DWC_DMA_ALLOC(size, dma);
19362 +}
19363 +
19364 +/**
19365 + * This function initializes the CFI object.
19366 + */
19367 +int init_cfi(cfiobject_t * cfiobj)
19368 +{
19369 + CFI_INFO("%s\n", __func__);
19370 +
19371 + /* Allocate a buffer for IN XFERs */
19372 + cfiobj->buf_in.buf =
19373 + DWC_DMA_ALLOC(CFI_IN_BUF_LEN, &cfiobj->buf_in.addr);
19374 + if (NULL == cfiobj->buf_in.buf) {
19375 + CFI_INFO("Unable to allocate buffer for INs\n");
19376 + return -DWC_E_NO_MEMORY;
19377 + }
19378 +
19379 + /* Allocate a buffer for OUT XFERs */
19380 + cfiobj->buf_out.buf =
19381 + DWC_DMA_ALLOC(CFI_OUT_BUF_LEN, &cfiobj->buf_out.addr);
19382 + if (NULL == cfiobj->buf_out.buf) {
19383 + CFI_INFO("Unable to allocate buffer for OUT\n");
19384 + return -DWC_E_NO_MEMORY;
19385 + }
19386 +
19387 + /* Initialize the callback function pointers */
19388 + cfiobj->ops.release = cfi_release;
19389 + cfiobj->ops.ep_enable = cfi_ep_enable;
19390 + cfiobj->ops.ctrl_write_complete = cfi_ctrl_write_complete;
19391 + cfiobj->ops.build_descriptors = cfi_build_descriptors;
19392 + cfiobj->ops.ep_alloc_buf = cfi_ep_alloc_buf;
19393 +
19394 + /* Initialize the list of active endpoints in the CFI object */
19395 + DWC_LIST_INIT(&cfiobj->active_eps);
19396 +
19397 + return 0;
19398 +}
19399 +
19400 +/**
19401 + * This function reads the required feature's current value into the buffer
19402 + *
19403 + * @retval: Returns negative as error, or the data length of the feature
19404 + */
19405 +static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
19406 + struct dwc_otg_pcd *pcd,
19407 + struct cfi_usb_ctrlrequest *ctrl_req)
19408 +{
19409 + int retval = -DWC_E_NOT_SUPPORTED;
19410 + struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
19411 + uint16_t dfifo, rxfifo, txfifo;
19412 +
19413 + switch (ctrl_req->wIndex) {
19414 + /* Whether the DDMA is enabled or not */
19415 + case FT_ID_DMA_MODE:
19416 + *buf = (coreif->dma_enable && coreif->dma_desc_enable) ? 1 : 0;
19417 + retval = 1;
19418 + break;
19419 +
19420 + case FT_ID_DMA_BUFFER_SETUP:
19421 + retval = cfi_ep_get_sg_val(buf, pcd, ctrl_req);
19422 + break;
19423 +
19424 + case FT_ID_DMA_BUFF_ALIGN:
19425 + retval = cfi_ep_get_align_val(buf, pcd, ctrl_req);
19426 + break;
19427 +
19428 + case FT_ID_DMA_CONCAT_SETUP:
19429 + retval = cfi_ep_get_concat_val(buf, pcd, ctrl_req);
19430 + break;
19431 +
19432 + case FT_ID_DMA_CIRCULAR:
19433 + CFI_INFO("GetFeature value (FT_ID_DMA_CIRCULAR)\n");
19434 + break;
19435 +
19436 + case FT_ID_THRESHOLD_SETUP:
19437 + CFI_INFO("GetFeature value (FT_ID_THRESHOLD_SETUP)\n");
19438 + break;
19439 +
19440 + case FT_ID_DFIFO_DEPTH:
19441 + dfifo = get_dfifo_size(coreif);
19442 + *((uint16_t *) buf) = dfifo;
19443 + retval = sizeof(uint16_t);
19444 + break;
19445 +
19446 + case FT_ID_TX_FIFO_DEPTH:
19447 + retval = get_txfifo_size(pcd, ctrl_req->wValue);
19448 + if (retval >= 0) {
19449 + txfifo = retval;
19450 + *((uint16_t *) buf) = txfifo;
19451 + retval = sizeof(uint16_t);
19452 + }
19453 + break;
19454 +
19455 + case FT_ID_RX_FIFO_DEPTH:
19456 + retval = get_rxfifo_size(coreif, ctrl_req->wValue);
19457 + if (retval >= 0) {
19458 + rxfifo = retval;
19459 + *((uint16_t *) buf) = rxfifo;
19460 + retval = sizeof(uint16_t);
19461 + }
19462 + break;
19463 + }
19464 +
19465 + return retval;
19466 +}
19467 +
19468 +/**
19469 + * This function resets the SG for the specified EP to its default value
19470 + */
19471 +static int cfi_reset_sg_val(cfi_ep_t * cfiep)
19472 +{
19473 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
19474 + return 0;
19475 +}
19476 +
19477 +/**
19478 + * This function resets the Alignment for the specified EP to its default value
19479 + */
19480 +static int cfi_reset_align_val(cfi_ep_t * cfiep)
19481 +{
19482 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
19483 + return 0;
19484 +}
19485 +
19486 +/**
19487 + * This function resets the Concatenation for the specified EP to its default value
19488 + * This function will also set the value of the wTxBytes field to NULL after
19489 + * freeing the memory previously allocated for this field.
19490 + */
19491 +static int cfi_reset_concat_val(cfi_ep_t * cfiep)
19492 +{
19493 + /* First we need to free the wTxBytes field */
19494 + if (cfiep->bm_concat->wTxBytes) {
19495 + DWC_FREE(cfiep->bm_concat->wTxBytes);
19496 + cfiep->bm_concat->wTxBytes = NULL;
19497 + }
19498 +
19499 + dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
19500 + return 0;
19501 +}
19502 +
19503 +/**
19504 + * This function resets all the buffer setups of the specified endpoint
19505 + */
19506 +static int cfi_ep_reset_all_setup_vals(cfi_ep_t * cfiep)
19507 +{
19508 + cfi_reset_sg_val(cfiep);
19509 + cfi_reset_align_val(cfiep);
19510 + cfi_reset_concat_val(cfiep);
19511 + return 0;
19512 +}
19513 +
19514 +static int cfi_handle_reset_fifo_val(struct dwc_otg_pcd *pcd, uint8_t ep_addr,
19515 + uint8_t rx_rst, uint8_t tx_rst)
19516 +{
19517 + int retval = -DWC_E_INVALID;
19518 + uint16_t tx_siz[15];
19519 + uint16_t rx_siz = 0;
19520 + dwc_otg_pcd_ep_t *ep = NULL;
19521 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
19522 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
19523 +
19524 + if (rx_rst) {
19525 + rx_siz = params->dev_rx_fifo_size;
19526 + params->dev_rx_fifo_size = GET_CORE_IF(pcd)->init_rxfsiz;
19527 + }
19528 +
19529 + if (tx_rst) {
19530 + if (ep_addr == 0) {
19531 + int i;
19532 +
19533 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
19534 + tx_siz[i] =
19535 + core_if->core_params->dev_tx_fifo_size[i];
19536 + core_if->core_params->dev_tx_fifo_size[i] =
19537 + core_if->init_txfsiz[i];
19538 + }
19539 + } else {
19540 +
19541 + ep = get_ep_by_addr(pcd, ep_addr);
19542 +
19543 + if (NULL == ep) {
19544 + CFI_INFO
19545 + ("%s: Unable to get the endpoint addr=0x%02x\n",
19546 + __func__, ep_addr);
19547 + return -DWC_E_INVALID;
19548 + }
19549 +
19550 + tx_siz[0] =
19551 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num -
19552 + 1];
19553 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] =
19554 + GET_CORE_IF(pcd)->init_txfsiz[ep->
19555 + dwc_ep.tx_fifo_num -
19556 + 1];
19557 + }
19558 + }
19559 +
19560 + if (resize_fifos(GET_CORE_IF(pcd))) {
19561 + retval = 0;
19562 + } else {
19563 + CFI_INFO
19564 + ("%s: Error resetting the feature Reset All(FIFO size)\n",
19565 + __func__);
19566 + if (rx_rst) {
19567 + params->dev_rx_fifo_size = rx_siz;
19568 + }
19569 +
19570 + if (tx_rst) {
19571 + if (ep_addr == 0) {
19572 + int i;
19573 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps;
19574 + i++) {
19575 + core_if->
19576 + core_params->dev_tx_fifo_size[i] =
19577 + tx_siz[i];
19578 + }
19579 + } else {
19580 + params->dev_tx_fifo_size[ep->
19581 + dwc_ep.tx_fifo_num -
19582 + 1] = tx_siz[0];
19583 + }
19584 + }
19585 + retval = -DWC_E_INVALID;
19586 + }
19587 + return retval;
19588 +}
19589 +
19590 +static int cfi_handle_reset_all(struct dwc_otg_pcd *pcd, uint8_t addr)
19591 +{
19592 + int retval = 0;
19593 + cfi_ep_t *cfiep;
19594 + cfiobject_t *cfi = pcd->cfi;
19595 + dwc_list_link_t *tmp;
19596 +
19597 + retval = cfi_handle_reset_fifo_val(pcd, addr, 1, 1);
19598 + if (retval < 0) {
19599 + return retval;
19600 + }
19601 +
19602 + /* If the EP address is known then reset the features for only that EP */
19603 + if (addr) {
19604 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
19605 + if (NULL == cfiep) {
19606 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
19607 + __func__, addr);
19608 + return -DWC_E_INVALID;
19609 + }
19610 + retval = cfi_ep_reset_all_setup_vals(cfiep);
19611 + cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
19612 + }
19613 + /* Otherwise (wValue == 0), reset all features of all EP's */
19614 + else {
19615 + /* Traverse all the active EP's and reset the feature(s) value(s) */
19616 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
19617 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
19618 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19619 + retval = cfi_ep_reset_all_setup_vals(cfiep);
19620 + cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
19621 + if (retval < 0) {
19622 + CFI_INFO
19623 + ("%s: Error resetting the feature Reset All\n",
19624 + __func__);
19625 + return retval;
19626 + }
19627 + }
19628 + }
19629 + return retval;
19630 +}
19631 +
19632 +static int cfi_handle_reset_dma_buff_setup(struct dwc_otg_pcd *pcd,
19633 + uint8_t addr)
19634 +{
19635 + int retval = 0;
19636 + cfi_ep_t *cfiep;
19637 + cfiobject_t *cfi = pcd->cfi;
19638 + dwc_list_link_t *tmp;
19639 +
19640 + /* If the EP address is known then reset the features for only that EP */
19641 + if (addr) {
19642 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
19643 + if (NULL == cfiep) {
19644 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
19645 + __func__, addr);
19646 + return -DWC_E_INVALID;
19647 + }
19648 + retval = cfi_reset_sg_val(cfiep);
19649 + }
19650 + /* Otherwise (wValue == 0), reset all features of all EP's */
19651 + else {
19652 + /* Traverse all the active EP's and reset the feature(s) value(s) */
19653 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
19654 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
19655 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19656 + retval = cfi_reset_sg_val(cfiep);
19657 + if (retval < 0) {
19658 + CFI_INFO
19659 + ("%s: Error resetting the feature Buffer Setup\n",
19660 + __func__);
19661 + return retval;
19662 + }
19663 + }
19664 + }
19665 + return retval;
19666 +}
19667 +
19668 +static int cfi_handle_reset_concat_val(struct dwc_otg_pcd *pcd, uint8_t addr)
19669 +{
19670 + int retval = 0;
19671 + cfi_ep_t *cfiep;
19672 + cfiobject_t *cfi = pcd->cfi;
19673 + dwc_list_link_t *tmp;
19674 +
19675 + /* If the EP address is known then reset the features for only that EP */
19676 + if (addr) {
19677 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
19678 + if (NULL == cfiep) {
19679 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
19680 + __func__, addr);
19681 + return -DWC_E_INVALID;
19682 + }
19683 + retval = cfi_reset_concat_val(cfiep);
19684 + }
19685 + /* Otherwise (wValue == 0), reset all features of all EP's */
19686 + else {
19687 + /* Traverse all the active EP's and reset the feature(s) value(s) */
19688 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
19689 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
19690 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19691 + retval = cfi_reset_concat_val(cfiep);
19692 + if (retval < 0) {
19693 + CFI_INFO
19694 + ("%s: Error resetting the feature Concatenation Value\n",
19695 + __func__);
19696 + return retval;
19697 + }
19698 + }
19699 + }
19700 + return retval;
19701 +}
19702 +
19703 +static int cfi_handle_reset_align_val(struct dwc_otg_pcd *pcd, uint8_t addr)
19704 +{
19705 + int retval = 0;
19706 + cfi_ep_t *cfiep;
19707 + cfiobject_t *cfi = pcd->cfi;
19708 + dwc_list_link_t *tmp;
19709 +
19710 + /* If the EP address is known then reset the features for only that EP */
19711 + if (addr) {
19712 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
19713 + if (NULL == cfiep) {
19714 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
19715 + __func__, addr);
19716 + return -DWC_E_INVALID;
19717 + }
19718 + retval = cfi_reset_align_val(cfiep);
19719 + }
19720 + /* Otherwise (wValue == 0), reset all features of all EP's */
19721 + else {
19722 + /* Traverse all the active EP's and reset the feature(s) value(s) */
19723 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
19724 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
19725 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19726 + retval = cfi_reset_align_val(cfiep);
19727 + if (retval < 0) {
19728 + CFI_INFO
19729 + ("%s: Error resetting the feature Aliignment Value\n",
19730 + __func__);
19731 + return retval;
19732 + }
19733 + }
19734 + }
19735 + return retval;
19736 +
19737 +}
19738 +
19739 +static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
19740 + struct cfi_usb_ctrlrequest *req)
19741 +{
19742 + int retval = 0;
19743 +
19744 + switch (req->wIndex) {
19745 + case 0:
19746 + /* Reset all features */
19747 + retval = cfi_handle_reset_all(pcd, req->wValue & 0xff);
19748 + break;
19749 +
19750 + case FT_ID_DMA_BUFFER_SETUP:
19751 + /* Reset the SG buffer setup */
19752 + retval =
19753 + cfi_handle_reset_dma_buff_setup(pcd, req->wValue & 0xff);
19754 + break;
19755 +
19756 + case FT_ID_DMA_CONCAT_SETUP:
19757 + /* Reset the Concatenation buffer setup */
19758 + retval = cfi_handle_reset_concat_val(pcd, req->wValue & 0xff);
19759 + break;
19760 +
19761 + case FT_ID_DMA_BUFF_ALIGN:
19762 + /* Reset the Alignment buffer setup */
19763 + retval = cfi_handle_reset_align_val(pcd, req->wValue & 0xff);
19764 + break;
19765 +
19766 + case FT_ID_TX_FIFO_DEPTH:
19767 + retval =
19768 + cfi_handle_reset_fifo_val(pcd, req->wValue & 0xff, 0, 1);
19769 + pcd->cfi->need_gadget_att = 0;
19770 + break;
19771 +
19772 + case FT_ID_RX_FIFO_DEPTH:
19773 + retval = cfi_handle_reset_fifo_val(pcd, 0, 1, 0);
19774 + pcd->cfi->need_gadget_att = 0;
19775 + break;
19776 + default:
19777 + break;
19778 + }
19779 + return retval;
19780 +}
19781 +
19782 +/**
19783 + * This function sets a new value for the SG buffer setup.
19784 + */
19785 +static int cfi_ep_set_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
19786 +{
19787 + uint8_t inaddr, outaddr;
19788 + cfi_ep_t *epin, *epout;
19789 + ddma_sg_buffer_setup_t *psgval;
19790 + uint32_t desccount, size;
19791 +
19792 + CFI_INFO("%s\n", __func__);
19793 +
19794 + psgval = (ddma_sg_buffer_setup_t *) buf;
19795 + desccount = (uint32_t) psgval->bCount;
19796 + size = (uint32_t) psgval->wSize;
19797 +
19798 + /* Check the DMA descriptor count */
19799 + if ((desccount > MAX_DMA_DESCS_PER_EP) || (desccount == 0)) {
19800 + CFI_INFO
19801 + ("%s: The count of DMA Descriptors should be between 1 and %d\n",
19802 + __func__, MAX_DMA_DESCS_PER_EP);
19803 + return -DWC_E_INVALID;
19804 + }
19805 +
19806 + /* Check the DMA descriptor count */
19807 +
19808 + if (size == 0) {
19809 +
19810 + CFI_INFO("%s: The transfer size should be at least 1 byte\n",
19811 + __func__);
19812 +
19813 + return -DWC_E_INVALID;
19814 +
19815 + }
19816 +
19817 + inaddr = psgval->bInEndpointAddress;
19818 + outaddr = psgval->bOutEndpointAddress;
19819 +
19820 + epin = get_cfi_ep_by_addr(pcd->cfi, inaddr);
19821 + epout = get_cfi_ep_by_addr(pcd->cfi, outaddr);
19822 +
19823 + if (NULL == epin || NULL == epout) {
19824 + CFI_INFO
19825 + ("%s: Unable to get the endpoints inaddr=0x%02x outaddr=0x%02x\n",
19826 + __func__, inaddr, outaddr);
19827 + return -DWC_E_INVALID;
19828 + }
19829 +
19830 + epin->ep->dwc_ep.buff_mode = BM_SG;
19831 + dwc_memcpy(epin->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
19832 +
19833 + epout->ep->dwc_ep.buff_mode = BM_SG;
19834 + dwc_memcpy(epout->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
19835 +
19836 + return 0;
19837 +}
19838 +
19839 +/**
19840 + * This function sets a new value for the buffer Alignment setup.
19841 + */
19842 +static int cfi_ep_set_alignment_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
19843 +{
19844 + cfi_ep_t *ep;
19845 + uint8_t addr;
19846 + ddma_align_buffer_setup_t *palignval;
19847 +
19848 + palignval = (ddma_align_buffer_setup_t *) buf;
19849 + addr = palignval->bEndpointAddress;
19850 +
19851 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
19852 +
19853 + if (NULL == ep) {
19854 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
19855 + __func__, addr);
19856 + return -DWC_E_INVALID;
19857 + }
19858 +
19859 + ep->ep->dwc_ep.buff_mode = BM_ALIGN;
19860 + dwc_memcpy(ep->bm_align, palignval, sizeof(ddma_align_buffer_setup_t));
19861 +
19862 + return 0;
19863 +}
19864 +
19865 +/**
19866 + * This function sets a new value for the Concatenation buffer setup.
19867 + */
19868 +static int cfi_ep_set_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
19869 +{
19870 + uint8_t addr;
19871 + cfi_ep_t *ep;
19872 + struct _ddma_concat_buffer_setup_hdr *pConcatValHdr;
19873 + uint16_t *pVals;
19874 + uint32_t desccount;
19875 + int i;
19876 + uint16_t mps;
19877 +
19878 + pConcatValHdr = (struct _ddma_concat_buffer_setup_hdr *)buf;
19879 + desccount = (uint32_t) pConcatValHdr->bDescCount;
19880 + pVals = (uint16_t *) (buf + BS_CONCAT_VAL_HDR_LEN);
19881 +
19882 + /* Check the DMA descriptor count */
19883 + if (desccount > MAX_DMA_DESCS_PER_EP) {
19884 + CFI_INFO("%s: Maximum DMA Descriptor count should be %d\n",
19885 + __func__, MAX_DMA_DESCS_PER_EP);
19886 + return -DWC_E_INVALID;
19887 + }
19888 +
19889 + addr = pConcatValHdr->bEndpointAddress;
19890 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
19891 + if (NULL == ep) {
19892 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
19893 + __func__, addr);
19894 + return -DWC_E_INVALID;
19895 + }
19896 +
19897 + mps = UGETW(ep->ep->desc->wMaxPacketSize);
19898 +
19899 +#if 0
19900 + for (i = 0; i < desccount; i++) {
19901 + CFI_INFO("%s: wTxSize[%d]=0x%04x\n", __func__, i, pVals[i]);
19902 + }
19903 + CFI_INFO("%s: epname=%s; mps=%d\n", __func__, ep->ep->ep.name, mps);
19904 +#endif
19905 +
19906 + /* Check the wTxSizes to be less than or equal to the mps */
19907 + for (i = 0; i < desccount; i++) {
19908 + if (pVals[i] > mps) {
19909 + CFI_INFO
19910 + ("%s: ERROR - the wTxSize[%d] should be <= MPS (wTxSize=%d)\n",
19911 + __func__, i, pVals[i]);
19912 + return -DWC_E_INVALID;
19913 + }
19914 + }
19915 +
19916 + ep->ep->dwc_ep.buff_mode = BM_CONCAT;
19917 + dwc_memcpy(ep->bm_concat, pConcatValHdr, BS_CONCAT_VAL_HDR_LEN);
19918 +
19919 + /* Free the previously allocated storage for the wTxBytes */
19920 + if (ep->bm_concat->wTxBytes) {
19921 + DWC_FREE(ep->bm_concat->wTxBytes);
19922 + }
19923 +
19924 + /* Allocate a new storage for the wTxBytes field */
19925 + ep->bm_concat->wTxBytes =
19926 + DWC_ALLOC(sizeof(uint16_t) * pConcatValHdr->bDescCount);
19927 + if (NULL == ep->bm_concat->wTxBytes) {
19928 + CFI_INFO("%s: Unable to allocate memory\n", __func__);
19929 + return -DWC_E_NO_MEMORY;
19930 + }
19931 +
19932 + /* Copy the new values into the wTxBytes filed */
19933 + dwc_memcpy(ep->bm_concat->wTxBytes, buf + BS_CONCAT_VAL_HDR_LEN,
19934 + sizeof(uint16_t) * pConcatValHdr->bDescCount);
19935 +
19936 + return 0;
19937 +}
19938 +
19939 +/**
19940 + * This function calculates the total of all FIFO sizes
19941 + *
19942 + * @param core_if Programming view of DWC_otg controller
19943 + *
19944 + * @return The total of data FIFO sizes.
19945 + *
19946 + */
19947 +static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if)
19948 +{
19949 + dwc_otg_core_params_t *params = core_if->core_params;
19950 + uint16_t dfifo_total = 0;
19951 + int i;
19952 +
19953 + /* The shared RxFIFO size */
19954 + dfifo_total =
19955 + params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
19956 +
19957 + /* Add up each TxFIFO size to the total */
19958 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
19959 + dfifo_total += params->dev_tx_fifo_size[i];
19960 + }
19961 +
19962 + return dfifo_total;
19963 +}
19964 +
19965 +/**
19966 + * This function returns Rx FIFO size
19967 + *
19968 + * @param core_if Programming view of DWC_otg controller
19969 + *
19970 + * @return The total of data FIFO sizes.
19971 + *
19972 + */
19973 +static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue)
19974 +{
19975 + switch (wValue >> 8) {
19976 + case 0:
19977 + return (core_if->pwron_rxfsiz <
19978 + 32768) ? core_if->pwron_rxfsiz : 32768;
19979 + break;
19980 + case 1:
19981 + return core_if->core_params->dev_rx_fifo_size;
19982 + break;
19983 + default:
19984 + return -DWC_E_INVALID;
19985 + break;
19986 + }
19987 +}
19988 +
19989 +/**
19990 + * This function returns Tx FIFO size for IN EP
19991 + *
19992 + * @param core_if Programming view of DWC_otg controller
19993 + *
19994 + * @return The total of data FIFO sizes.
19995 + *
19996 + */
19997 +static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue)
19998 +{
19999 + dwc_otg_pcd_ep_t *ep;
20000 +
20001 + ep = get_ep_by_addr(pcd, wValue & 0xff);
20002 +
20003 + if (NULL == ep) {
20004 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20005 + __func__, wValue & 0xff);
20006 + return -DWC_E_INVALID;
20007 + }
20008 +
20009 + if (!ep->dwc_ep.is_in) {
20010 + CFI_INFO
20011 + ("%s: No Tx FIFO assingned to the Out endpoint addr=0x%02x\n",
20012 + __func__, wValue & 0xff);
20013 + return -DWC_E_INVALID;
20014 + }
20015 +
20016 + switch (wValue >> 8) {
20017 + case 0:
20018 + return (GET_CORE_IF(pcd)->pwron_txfsiz
20019 + [ep->dwc_ep.tx_fifo_num - 1] <
20020 + 768) ? GET_CORE_IF(pcd)->pwron_txfsiz[ep->
20021 + dwc_ep.tx_fifo_num
20022 + - 1] : 32768;
20023 + break;
20024 + case 1:
20025 + return GET_CORE_IF(pcd)->core_params->
20026 + dev_tx_fifo_size[ep->dwc_ep.num - 1];
20027 + break;
20028 + default:
20029 + return -DWC_E_INVALID;
20030 + break;
20031 + }
20032 +}
20033 +
20034 +/**
20035 + * This function checks if the submitted combination of
20036 + * device mode FIFO sizes is possible or not.
20037 + *
20038 + * @param core_if Programming view of DWC_otg controller
20039 + *
20040 + * @return 1 if possible, 0 otherwise.
20041 + *
20042 + */
20043 +static uint8_t check_fifo_sizes(dwc_otg_core_if_t * core_if)
20044 +{
20045 + uint16_t dfifo_actual = 0;
20046 + dwc_otg_core_params_t *params = core_if->core_params;
20047 + uint16_t start_addr = 0;
20048 + int i;
20049 +
20050 + dfifo_actual =
20051 + params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
20052 +
20053 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20054 + dfifo_actual += params->dev_tx_fifo_size[i];
20055 + }
20056 +
20057 + if (dfifo_actual > core_if->total_fifo_size) {
20058 + return 0;
20059 + }
20060 +
20061 + if (params->dev_rx_fifo_size > 32768 || params->dev_rx_fifo_size < 16)
20062 + return 0;
20063 +
20064 + if (params->dev_nperio_tx_fifo_size > 32768
20065 + || params->dev_nperio_tx_fifo_size < 16)
20066 + return 0;
20067 +
20068 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20069 +
20070 + if (params->dev_tx_fifo_size[i] > 768
20071 + || params->dev_tx_fifo_size[i] < 4)
20072 + return 0;
20073 + }
20074 +
20075 + if (params->dev_rx_fifo_size > core_if->pwron_rxfsiz)
20076 + return 0;
20077 + start_addr = params->dev_rx_fifo_size;
20078 +
20079 + if (params->dev_nperio_tx_fifo_size > core_if->pwron_gnptxfsiz)
20080 + return 0;
20081 + start_addr += params->dev_nperio_tx_fifo_size;
20082 +
20083 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20084 +
20085 + if (params->dev_tx_fifo_size[i] > core_if->pwron_txfsiz[i])
20086 + return 0;
20087 + start_addr += params->dev_tx_fifo_size[i];
20088 + }
20089 +
20090 + return 1;
20091 +}
20092 +
20093 +/**
20094 + * This function resizes Device mode FIFOs
20095 + *
20096 + * @param core_if Programming view of DWC_otg controller
20097 + *
20098 + * @return 1 if successful, 0 otherwise
20099 + *
20100 + */
20101 +static uint8_t resize_fifos(dwc_otg_core_if_t * core_if)
20102 +{
20103 + int i = 0;
20104 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
20105 + dwc_otg_core_params_t *params = core_if->core_params;
20106 + uint32_t rx_fifo_size;
20107 + fifosize_data_t nptxfifosize;
20108 + fifosize_data_t txfifosize[15];
20109 +
20110 + uint32_t rx_fsz_bak;
20111 + uint32_t nptxfsz_bak;
20112 + uint32_t txfsz_bak[15];
20113 +
20114 + uint16_t start_address;
20115 + uint8_t retval = 1;
20116 +
20117 + if (!check_fifo_sizes(core_if)) {
20118 + return 0;
20119 + }
20120 +
20121 + /* Configure data FIFO sizes */
20122 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
20123 + rx_fsz_bak = DWC_READ_REG32(&global_regs->grxfsiz);
20124 + rx_fifo_size = params->dev_rx_fifo_size;
20125 + DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
20126 +
20127 + /*
20128 + * Tx FIFOs These FIFOs are numbered from 1 to 15.
20129 + * Indexes of the FIFO size module parameters in the
20130 + * dev_tx_fifo_size array and the FIFO size registers in
20131 + * the dtxfsiz array run from 0 to 14.
20132 + */
20133 +
20134 + /* Non-periodic Tx FIFO */
20135 + nptxfsz_bak = DWC_READ_REG32(&global_regs->gnptxfsiz);
20136 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
20137 + start_address = params->dev_rx_fifo_size;
20138 + nptxfifosize.b.startaddr = start_address;
20139 +
20140 + DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
20141 +
20142 + start_address += nptxfifosize.b.depth;
20143 +
20144 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20145 + txfsz_bak[i] = DWC_READ_REG32(&global_regs->dtxfsiz[i]);
20146 +
20147 + txfifosize[i].b.depth = params->dev_tx_fifo_size[i];
20148 + txfifosize[i].b.startaddr = start_address;
20149 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
20150 + txfifosize[i].d32);
20151 +
20152 + start_address += txfifosize[i].b.depth;
20153 + }
20154 +
20155 + /** Check if register values are set correctly */
20156 + if (rx_fifo_size != DWC_READ_REG32(&global_regs->grxfsiz)) {
20157 + retval = 0;
20158 + }
20159 +
20160 + if (nptxfifosize.d32 != DWC_READ_REG32(&global_regs->gnptxfsiz)) {
20161 + retval = 0;
20162 + }
20163 +
20164 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20165 + if (txfifosize[i].d32 !=
20166 + DWC_READ_REG32(&global_regs->dtxfsiz[i])) {
20167 + retval = 0;
20168 + }
20169 + }
20170 +
20171 + /** If register values are not set correctly, reset old values */
20172 + if (retval == 0) {
20173 + DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fsz_bak);
20174 +
20175 + /* Non-periodic Tx FIFO */
20176 + DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfsz_bak);
20177 +
20178 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20179 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
20180 + txfsz_bak[i]);
20181 + }
20182 + }
20183 + } else {
20184 + return 0;
20185 + }
20186 +
20187 + /* Flush the FIFOs */
20188 + dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */
20189 + dwc_otg_flush_rx_fifo(core_if);
20190 +
20191 + return retval;
20192 +}
20193 +
20194 +/**
20195 + * This function sets a new value for the buffer Alignment setup.
20196 + */
20197 +static int cfi_ep_set_tx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
20198 +{
20199 + int retval;
20200 + uint32_t fsiz;
20201 + uint16_t size;
20202 + uint16_t ep_addr;
20203 + dwc_otg_pcd_ep_t *ep;
20204 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
20205 + tx_fifo_size_setup_t *ptxfifoval;
20206 +
20207 + ptxfifoval = (tx_fifo_size_setup_t *) buf;
20208 + ep_addr = ptxfifoval->bEndpointAddress;
20209 + size = ptxfifoval->wDepth;
20210 +
20211 + ep = get_ep_by_addr(pcd, ep_addr);
20212 +
20213 + CFI_INFO
20214 + ("%s: Set Tx FIFO size: endpoint addr=0x%02x, depth=%d, FIFO Num=%d\n",
20215 + __func__, ep_addr, size, ep->dwc_ep.tx_fifo_num);
20216 +
20217 + if (NULL == ep) {
20218 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20219 + __func__, ep_addr);
20220 + return -DWC_E_INVALID;
20221 + }
20222 +
20223 + fsiz = params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1];
20224 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = size;
20225 +
20226 + if (resize_fifos(GET_CORE_IF(pcd))) {
20227 + retval = 0;
20228 + } else {
20229 + CFI_INFO
20230 + ("%s: Error setting the feature Tx FIFO Size for EP%d\n",
20231 + __func__, ep_addr);
20232 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = fsiz;
20233 + retval = -DWC_E_INVALID;
20234 + }
20235 +
20236 + return retval;
20237 +}
20238 +
20239 +/**
20240 + * This function sets a new value for the buffer Alignment setup.
20241 + */
20242 +static int cfi_set_rx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
20243 +{
20244 + int retval;
20245 + uint32_t fsiz;
20246 + uint16_t size;
20247 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
20248 + rx_fifo_size_setup_t *prxfifoval;
20249 +
20250 + prxfifoval = (rx_fifo_size_setup_t *) buf;
20251 + size = prxfifoval->wDepth;
20252 +
20253 + fsiz = params->dev_rx_fifo_size;
20254 + params->dev_rx_fifo_size = size;
20255 +
20256 + if (resize_fifos(GET_CORE_IF(pcd))) {
20257 + retval = 0;
20258 + } else {
20259 + CFI_INFO("%s: Error setting the feature Rx FIFO Size\n",
20260 + __func__);
20261 + params->dev_rx_fifo_size = fsiz;
20262 + retval = -DWC_E_INVALID;
20263 + }
20264 +
20265 + return retval;
20266 +}
20267 +
20268 +/**
20269 + * This function reads the SG of an EP's buffer setup into the buffer buf
20270 + */
20271 +static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
20272 + struct cfi_usb_ctrlrequest *req)
20273 +{
20274 + int retval = -DWC_E_INVALID;
20275 + uint8_t addr;
20276 + cfi_ep_t *ep;
20277 +
20278 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
20279 + addr = req->wValue & 0xFF;
20280 + if (addr == 0) /* The address should be non-zero */
20281 + return retval;
20282 +
20283 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20284 + if (NULL == ep) {
20285 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
20286 + __func__, addr);
20287 + return retval;
20288 + }
20289 +
20290 + dwc_memcpy(buf, ep->bm_sg, BS_SG_VAL_DESC_LEN);
20291 + retval = BS_SG_VAL_DESC_LEN;
20292 + return retval;
20293 +}
20294 +
20295 +/**
20296 + * This function reads the Concatenation value of an EP's buffer mode into
20297 + * the buffer buf
20298 + */
20299 +static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
20300 + struct cfi_usb_ctrlrequest *req)
20301 +{
20302 + int retval = -DWC_E_INVALID;
20303 + uint8_t addr;
20304 + cfi_ep_t *ep;
20305 + uint8_t desc_count;
20306 +
20307 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
20308 + addr = req->wValue & 0xFF;
20309 + if (addr == 0) /* The address should be non-zero */
20310 + return retval;
20311 +
20312 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20313 + if (NULL == ep) {
20314 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
20315 + __func__, addr);
20316 + return retval;
20317 + }
20318 +
20319 + /* Copy the header to the buffer */
20320 + dwc_memcpy(buf, ep->bm_concat, BS_CONCAT_VAL_HDR_LEN);
20321 + /* Advance the buffer pointer by the header size */
20322 + buf += BS_CONCAT_VAL_HDR_LEN;
20323 +
20324 + desc_count = ep->bm_concat->hdr.bDescCount;
20325 + /* Copy alll the wTxBytes to the buffer */
20326 + dwc_memcpy(buf, ep->bm_concat->wTxBytes, sizeof(uid16_t) * desc_count);
20327 +
20328 + retval = BS_CONCAT_VAL_HDR_LEN + sizeof(uid16_t) * desc_count;
20329 + return retval;
20330 +}
20331 +
20332 +/**
20333 + * This function reads the buffer Alignment value of an EP's buffer mode into
20334 + * the buffer buf
20335 + *
20336 + * @return The total number of bytes copied to the buffer or negative error code.
20337 + */
20338 +static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
20339 + struct cfi_usb_ctrlrequest *req)
20340 +{
20341 + int retval = -DWC_E_INVALID;
20342 + uint8_t addr;
20343 + cfi_ep_t *ep;
20344 +
20345 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
20346 + addr = req->wValue & 0xFF;
20347 + if (addr == 0) /* The address should be non-zero */
20348 + return retval;
20349 +
20350 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20351 + if (NULL == ep) {
20352 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
20353 + __func__, addr);
20354 + return retval;
20355 + }
20356 +
20357 + dwc_memcpy(buf, ep->bm_align, BS_ALIGN_VAL_HDR_LEN);
20358 + retval = BS_ALIGN_VAL_HDR_LEN;
20359 +
20360 + return retval;
20361 +}
20362 +
20363 +/**
20364 + * This function sets a new value for the specified feature
20365 + *
20366 + * @param pcd A pointer to the PCD object
20367 + *
20368 + * @return 0 if successful, negative error code otherwise to stall the DCE.
20369 + */
20370 +static int cfi_set_feature_value(struct dwc_otg_pcd *pcd)
20371 +{
20372 + int retval = -DWC_E_NOT_SUPPORTED;
20373 + uint16_t wIndex, wValue;
20374 + uint8_t bRequest;
20375 + struct dwc_otg_core_if *coreif;
20376 + cfiobject_t *cfi = pcd->cfi;
20377 + struct cfi_usb_ctrlrequest *ctrl_req;
20378 + uint8_t *buf;
20379 + ctrl_req = &cfi->ctrl_req;
20380 +
20381 + buf = pcd->cfi->ctrl_req.data;
20382 +
20383 + coreif = GET_CORE_IF(pcd);
20384 + bRequest = ctrl_req->bRequest;
20385 + wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
20386 + wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
20387 +
20388 + /* See which feature is to be modified */
20389 + switch (wIndex) {
20390 + case FT_ID_DMA_BUFFER_SETUP:
20391 + /* Modify the feature */
20392 + if ((retval = cfi_ep_set_sg_val(buf, pcd)) < 0)
20393 + return retval;
20394 +
20395 + /* And send this request to the gadget */
20396 + cfi->need_gadget_att = 1;
20397 + break;
20398 +
20399 + case FT_ID_DMA_BUFF_ALIGN:
20400 + if ((retval = cfi_ep_set_alignment_val(buf, pcd)) < 0)
20401 + return retval;
20402 + cfi->need_gadget_att = 1;
20403 + break;
20404 +
20405 + case FT_ID_DMA_CONCAT_SETUP:
20406 + /* Modify the feature */
20407 + if ((retval = cfi_ep_set_concat_val(buf, pcd)) < 0)
20408 + return retval;
20409 + cfi->need_gadget_att = 1;
20410 + break;
20411 +
20412 + case FT_ID_DMA_CIRCULAR:
20413 + CFI_INFO("FT_ID_DMA_CIRCULAR\n");
20414 + break;
20415 +
20416 + case FT_ID_THRESHOLD_SETUP:
20417 + CFI_INFO("FT_ID_THRESHOLD_SETUP\n");
20418 + break;
20419 +
20420 + case FT_ID_DFIFO_DEPTH:
20421 + CFI_INFO("FT_ID_DFIFO_DEPTH\n");
20422 + break;
20423 +
20424 + case FT_ID_TX_FIFO_DEPTH:
20425 + CFI_INFO("FT_ID_TX_FIFO_DEPTH\n");
20426 + if ((retval = cfi_ep_set_tx_fifo_val(buf, pcd)) < 0)
20427 + return retval;
20428 + cfi->need_gadget_att = 0;
20429 + break;
20430 +
20431 + case FT_ID_RX_FIFO_DEPTH:
20432 + CFI_INFO("FT_ID_RX_FIFO_DEPTH\n");
20433 + if ((retval = cfi_set_rx_fifo_val(buf, pcd)) < 0)
20434 + return retval;
20435 + cfi->need_gadget_att = 0;
20436 + break;
20437 + }
20438 +
20439 + return retval;
20440 +}
20441 +
20442 +#endif //DWC_UTE_CFI
20443 --- /dev/null
20444 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.h
20445 @@ -0,0 +1,320 @@
20446 +/* ==========================================================================
20447 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
20448 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
20449 + * otherwise expressly agreed to in writing between Synopsys and you.
20450 + *
20451 + * The Software IS NOT an item of Licensed Software or Licensed Product under
20452 + * any End User Software License Agreement or Agreement for Licensed Product
20453 + * with Synopsys or any supplement thereto. You are permitted to use and
20454 + * redistribute this Software in source and binary forms, with or without
20455 + * modification, provided that redistributions of source code must retain this
20456 + * notice. You may not view, use, disclose, copy or distribute this file or
20457 + * any information contained herein except pursuant to this license grant from
20458 + * Synopsys. If you do not agree with this notice, including the disclaimer
20459 + * below, then you are not authorized to use the Software.
20460 + *
20461 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
20462 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20463 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20464 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
20465 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20466 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20467 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20468 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20469 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
20470 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
20471 + * DAMAGE.
20472 + * ========================================================================== */
20473 +
20474 +#if !defined(__DWC_OTG_CFI_H__)
20475 +#define __DWC_OTG_CFI_H__
20476 +
20477 +#include "dwc_otg_pcd.h"
20478 +#include "dwc_cfi_common.h"
20479 +
20480 +/**
20481 + * @file
20482 + * This file contains the CFI related OTG PCD specific common constants,
20483 + * interfaces(functions and macros) and data structures.The CFI Protocol is an
20484 + * optional interface for internal testing purposes that a DUT may implement to
20485 + * support testing of configurable features.
20486 + *
20487 + */
20488 +
20489 +struct dwc_otg_pcd;
20490 +struct dwc_otg_pcd_ep;
20491 +
20492 +/** OTG CFI Features (properties) ID constants */
20493 +/** This is a request for all Core Features */
20494 +#define FT_ID_DMA_MODE 0x0001
20495 +#define FT_ID_DMA_BUFFER_SETUP 0x0002
20496 +#define FT_ID_DMA_BUFF_ALIGN 0x0003
20497 +#define FT_ID_DMA_CONCAT_SETUP 0x0004
20498 +#define FT_ID_DMA_CIRCULAR 0x0005
20499 +#define FT_ID_THRESHOLD_SETUP 0x0006
20500 +#define FT_ID_DFIFO_DEPTH 0x0007
20501 +#define FT_ID_TX_FIFO_DEPTH 0x0008
20502 +#define FT_ID_RX_FIFO_DEPTH 0x0009
20503 +
20504 +/**********************************************************/
20505 +#define CFI_INFO_DEF
20506 +
20507 +#ifdef CFI_INFO_DEF
20508 +#define CFI_INFO(fmt...) DWC_PRINTF("CFI: " fmt);
20509 +#else
20510 +#define CFI_INFO(fmt...)
20511 +#endif
20512 +
20513 +#define min(x,y) ({ \
20514 + x < y ? x : y; })
20515 +
20516 +#define max(x,y) ({ \
20517 + x > y ? x : y; })
20518 +
20519 +/**
20520 + * Descriptor DMA SG Buffer setup structure (SG buffer). This structure is
20521 + * also used for setting up a buffer for Circular DDMA.
20522 + */
20523 +struct _ddma_sg_buffer_setup {
20524 +#define BS_SG_VAL_DESC_LEN 6
20525 + /* The OUT EP address */
20526 + uint8_t bOutEndpointAddress;
20527 + /* The IN EP address */
20528 + uint8_t bInEndpointAddress;
20529 + /* Number of bytes to put between transfer segments (must be DWORD boundaries) */
20530 + uint8_t bOffset;
20531 + /* The number of transfer segments (a DMA descriptors per each segment) */
20532 + uint8_t bCount;
20533 + /* Size (in byte) of each transfer segment */
20534 + uint16_t wSize;
20535 +} __attribute__ ((packed));
20536 +typedef struct _ddma_sg_buffer_setup ddma_sg_buffer_setup_t;
20537 +
20538 +/** Descriptor DMA Concatenation Buffer setup structure */
20539 +struct _ddma_concat_buffer_setup_hdr {
20540 +#define BS_CONCAT_VAL_HDR_LEN 4
20541 + /* The endpoint for which the buffer is to be set up */
20542 + uint8_t bEndpointAddress;
20543 + /* The count of descriptors to be used */
20544 + uint8_t bDescCount;
20545 + /* The total size of the transfer */
20546 + uint16_t wSize;
20547 +} __attribute__ ((packed));
20548 +typedef struct _ddma_concat_buffer_setup_hdr ddma_concat_buffer_setup_hdr_t;
20549 +
20550 +/** Descriptor DMA Concatenation Buffer setup structure */
20551 +struct _ddma_concat_buffer_setup {
20552 + /* The SG header */
20553 + ddma_concat_buffer_setup_hdr_t hdr;
20554 +
20555 + /* The XFER sizes pointer (allocated dynamically) */
20556 + uint16_t *wTxBytes;
20557 +} __attribute__ ((packed));
20558 +typedef struct _ddma_concat_buffer_setup ddma_concat_buffer_setup_t;
20559 +
20560 +/** Descriptor DMA Alignment Buffer setup structure */
20561 +struct _ddma_align_buffer_setup {
20562 +#define BS_ALIGN_VAL_HDR_LEN 2
20563 + uint8_t bEndpointAddress;
20564 + uint8_t bAlign;
20565 +} __attribute__ ((packed));
20566 +typedef struct _ddma_align_buffer_setup ddma_align_buffer_setup_t;
20567 +
20568 +/** Transmit FIFO Size setup structure */
20569 +struct _tx_fifo_size_setup {
20570 + uint8_t bEndpointAddress;
20571 + uint16_t wDepth;
20572 +} __attribute__ ((packed));
20573 +typedef struct _tx_fifo_size_setup tx_fifo_size_setup_t;
20574 +
20575 +/** Transmit FIFO Size setup structure */
20576 +struct _rx_fifo_size_setup {
20577 + uint16_t wDepth;
20578 +} __attribute__ ((packed));
20579 +typedef struct _rx_fifo_size_setup rx_fifo_size_setup_t;
20580 +
20581 +/**
20582 + * struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest
20583 + * This structure encapsulates the standard usb_ctrlrequest and adds a pointer
20584 + * to the data returned in the data stage of a 3-stage Control Write requests.
20585 + */
20586 +struct cfi_usb_ctrlrequest {
20587 + uint8_t bRequestType;
20588 + uint8_t bRequest;
20589 + uint16_t wValue;
20590 + uint16_t wIndex;
20591 + uint16_t wLength;
20592 + uint8_t *data;
20593 +} UPACKED;
20594 +
20595 +/*---------------------------------------------------------------------------*/
20596 +
20597 +/**
20598 + * The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures.
20599 + * This structure is used to store the buffer setup data for any
20600 + * enabled endpoint in the PCD.
20601 + */
20602 +struct cfi_ep {
20603 + /* Entry for the list container */
20604 + dwc_list_link_t lh;
20605 + /* Pointer to the active PCD endpoint structure */
20606 + struct dwc_otg_pcd_ep *ep;
20607 + /* The last descriptor in the chain of DMA descriptors of the endpoint */
20608 + struct dwc_otg_dma_desc *dma_desc_last;
20609 + /* The SG feature value */
20610 + ddma_sg_buffer_setup_t *bm_sg;
20611 + /* The Circular feature value */
20612 + ddma_sg_buffer_setup_t *bm_circ;
20613 + /* The Concatenation feature value */
20614 + ddma_concat_buffer_setup_t *bm_concat;
20615 + /* The Alignment feature value */
20616 + ddma_align_buffer_setup_t *bm_align;
20617 + /* XFER length */
20618 + uint32_t xfer_len;
20619 + /*
20620 + * Count of DMA descriptors currently used.
20621 + * The total should not exceed the MAX_DMA_DESCS_PER_EP value
20622 + * defined in the dwc_otg_cil.h
20623 + */
20624 + uint32_t desc_count;
20625 +};
20626 +typedef struct cfi_ep cfi_ep_t;
20627 +
20628 +typedef struct cfi_dma_buff {
20629 +#define CFI_IN_BUF_LEN 1024
20630 +#define CFI_OUT_BUF_LEN 1024
20631 + dma_addr_t addr;
20632 + uint8_t *buf;
20633 +} cfi_dma_buff_t;
20634 +
20635 +struct cfiobject;
20636 +
20637 +/**
20638 + * This is the interface for the CFI operations.
20639 + *
20640 + * @param ep_enable Called when any endpoint is enabled and activated.
20641 + * @param release Called when the CFI object is released and it needs to correctly
20642 + * deallocate the dynamic memory
20643 + * @param ctrl_write_complete Called when the data stage of the request is complete
20644 + */
20645 +typedef struct cfi_ops {
20646 + int (*ep_enable) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
20647 + struct dwc_otg_pcd_ep * ep);
20648 + void *(*ep_alloc_buf) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
20649 + struct dwc_otg_pcd_ep * ep, dma_addr_t * dma,
20650 + unsigned size, gfp_t flags);
20651 + void (*release) (struct cfiobject * cfi);
20652 + int (*ctrl_write_complete) (struct cfiobject * cfi,
20653 + struct dwc_otg_pcd * pcd);
20654 + void (*build_descriptors) (struct cfiobject * cfi,
20655 + struct dwc_otg_pcd * pcd,
20656 + struct dwc_otg_pcd_ep * ep,
20657 + dwc_otg_pcd_request_t * req);
20658 +} cfi_ops_t;
20659 +
20660 +struct cfiobject {
20661 + cfi_ops_t ops;
20662 + struct dwc_otg_pcd *pcd;
20663 + struct usb_gadget *gadget;
20664 +
20665 + /* Buffers used to send/receive CFI-related request data */
20666 + cfi_dma_buff_t buf_in;
20667 + cfi_dma_buff_t buf_out;
20668 +
20669 + /* CFI specific Control request wrapper */
20670 + struct cfi_usb_ctrlrequest ctrl_req;
20671 +
20672 + /* The list of active EP's in the PCD of type cfi_ep_t */
20673 + dwc_list_link_t active_eps;
20674 +
20675 + /* This flag shall control the propagation of a specific request
20676 + * to the gadget's processing routines.
20677 + * 0 - no gadget handling
20678 + * 1 - the gadget needs to know about this request (w/o completing a status
20679 + * phase - just return a 0 to the _setup callback)
20680 + */
20681 + uint8_t need_gadget_att;
20682 +
20683 + /* Flag indicating whether the status IN phase needs to be
20684 + * completed by the PCD
20685 + */
20686 + uint8_t need_status_in_complete;
20687 +};
20688 +typedef struct cfiobject cfiobject_t;
20689 +
20690 +#define DUMP_MSG
20691 +
20692 +#if defined(DUMP_MSG)
20693 +static inline void dump_msg(const u8 * buf, unsigned int length)
20694 +{
20695 + unsigned int start, num, i;
20696 + char line[52], *p;
20697 +
20698 + if (length >= 512)
20699 + return;
20700 +
20701 + start = 0;
20702 + while (length > 0) {
20703 + num = min(length, 16u);
20704 + p = line;
20705 + for (i = 0; i < num; ++i) {
20706 + if (i == 8)
20707 + *p++ = ' ';
20708 + DWC_SPRINTF(p, " %02x", buf[i]);
20709 + p += 3;
20710 + }
20711 + *p = 0;
20712 + DWC_DEBUG("%6x: %s\n", start, line);
20713 + buf += num;
20714 + start += num;
20715 + length -= num;
20716 + }
20717 +}
20718 +#else
20719 +static inline void dump_msg(const u8 * buf, unsigned int length)
20720 +{
20721 +}
20722 +#endif
20723 +
20724 +/**
20725 + * This function returns a pointer to cfi_ep_t object with the addr address.
20726 + */
20727 +static inline struct cfi_ep *get_cfi_ep_by_addr(struct cfiobject *cfi,
20728 + uint8_t addr)
20729 +{
20730 + struct cfi_ep *pcfiep;
20731 + dwc_list_link_t *tmp;
20732 +
20733 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
20734 + pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
20735 +
20736 + if (pcfiep->ep->desc->bEndpointAddress == addr) {
20737 + return pcfiep;
20738 + }
20739 + }
20740 +
20741 + return NULL;
20742 +}
20743 +
20744 +/**
20745 + * This function returns a pointer to cfi_ep_t object that matches
20746 + * the dwc_otg_pcd_ep object.
20747 + */
20748 +static inline struct cfi_ep *get_cfi_ep_by_pcd_ep(struct cfiobject *cfi,
20749 + struct dwc_otg_pcd_ep *ep)
20750 +{
20751 + struct cfi_ep *pcfiep = NULL;
20752 + dwc_list_link_t *tmp;
20753 +
20754 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
20755 + pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
20756 + if (pcfiep->ep == ep) {
20757 + return pcfiep;
20758 + }
20759 + }
20760 + return NULL;
20761 +}
20762 +
20763 +int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl);
20764 +
20765 +#endif /* (__DWC_OTG_CFI_H__) */
20766 --- /dev/null
20767 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.c
20768 @@ -0,0 +1,7151 @@
20769 +/* ==========================================================================
20770 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.c $
20771 + * $Revision: #191 $
20772 + * $Date: 2012/08/10 $
20773 + * $Change: 2047372 $
20774 + *
20775 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
20776 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
20777 + * otherwise expressly agreed to in writing between Synopsys and you.
20778 + *
20779 + * The Software IS NOT an item of Licensed Software or Licensed Product under
20780 + * any End User Software License Agreement or Agreement for Licensed Product
20781 + * with Synopsys or any supplement thereto. You are permitted to use and
20782 + * redistribute this Software in source and binary forms, with or without
20783 + * modification, provided that redistributions of source code must retain this
20784 + * notice. You may not view, use, disclose, copy or distribute this file or
20785 + * any information contained herein except pursuant to this license grant from
20786 + * Synopsys. If you do not agree with this notice, including the disclaimer
20787 + * below, then you are not authorized to use the Software.
20788 + *
20789 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
20790 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20791 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20792 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
20793 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20794 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20795 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20796 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20797 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
20798 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
20799 + * DAMAGE.
20800 + * ========================================================================== */
20801 +
20802 +/** @file
20803 + *
20804 + * The Core Interface Layer provides basic services for accessing and
20805 + * managing the DWC_otg hardware. These services are used by both the
20806 + * Host Controller Driver and the Peripheral Controller Driver.
20807 + *
20808 + * The CIL manages the memory map for the core so that the HCD and PCD
20809 + * don't have to do this separately. It also handles basic tasks like
20810 + * reading/writing the registers and data FIFOs in the controller.
20811 + * Some of the data access functions provide encapsulation of several
20812 + * operations required to perform a task, such as writing multiple
20813 + * registers to start a transfer. Finally, the CIL performs basic
20814 + * services that are not specific to either the host or device modes
20815 + * of operation. These services include management of the OTG Host
20816 + * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A
20817 + * Diagnostic API is also provided to allow testing of the controller
20818 + * hardware.
20819 + *
20820 + * The Core Interface Layer has the following requirements:
20821 + * - Provides basic controller operations.
20822 + * - Minimal use of OS services.
20823 + * - The OS services used will be abstracted by using inline functions
20824 + * or macros.
20825 + *
20826 + */
20827 +
20828 +#include "dwc_os.h"
20829 +#include "dwc_otg_regs.h"
20830 +#include "dwc_otg_cil.h"
20831 +
20832 +static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if);
20833 +
20834 +/**
20835 + * This function is called to initialize the DWC_otg CSR data
20836 + * structures. The register addresses in the device and host
20837 + * structures are initialized from the base address supplied by the
20838 + * caller. The calling function must make the OS calls to get the
20839 + * base address of the DWC_otg controller registers. The core_params
20840 + * argument holds the parameters that specify how the core should be
20841 + * configured.
20842 + *
20843 + * @param reg_base_addr Base address of DWC_otg core registers
20844 + *
20845 + */
20846 +dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * reg_base_addr)
20847 +{
20848 + dwc_otg_core_if_t *core_if = 0;
20849 + dwc_otg_dev_if_t *dev_if = 0;
20850 + dwc_otg_host_if_t *host_if = 0;
20851 + uint8_t *reg_base = (uint8_t *) reg_base_addr;
20852 + int i = 0;
20853 +
20854 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, reg_base_addr);
20855 +
20856 + core_if = DWC_ALLOC(sizeof(dwc_otg_core_if_t));
20857 +
20858 + if (core_if == NULL) {
20859 + DWC_DEBUGPL(DBG_CIL,
20860 + "Allocation of dwc_otg_core_if_t failed\n");
20861 + return 0;
20862 + }
20863 + core_if->core_global_regs = (dwc_otg_core_global_regs_t *) reg_base;
20864 +
20865 + /*
20866 + * Allocate the Device Mode structures.
20867 + */
20868 + dev_if = DWC_ALLOC(sizeof(dwc_otg_dev_if_t));
20869 +
20870 + if (dev_if == NULL) {
20871 + DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n");
20872 + DWC_FREE(core_if);
20873 + return 0;
20874 + }
20875 +
20876 + dev_if->dev_global_regs =
20877 + (dwc_otg_device_global_regs_t *) (reg_base +
20878 + DWC_DEV_GLOBAL_REG_OFFSET);
20879 +
20880 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
20881 + dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *)
20882 + (reg_base + DWC_DEV_IN_EP_REG_OFFSET +
20883 + (i * DWC_EP_REG_OFFSET));
20884 +
20885 + dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *)
20886 + (reg_base + DWC_DEV_OUT_EP_REG_OFFSET +
20887 + (i * DWC_EP_REG_OFFSET));
20888 + DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n",
20889 + i, &dev_if->in_ep_regs[i]->diepctl);
20890 + DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n",
20891 + i, &dev_if->out_ep_regs[i]->doepctl);
20892 + }
20893 +
20894 + dev_if->speed = 0; // unknown
20895 +
20896 + core_if->dev_if = dev_if;
20897 +
20898 + /*
20899 + * Allocate the Host Mode structures.
20900 + */
20901 + host_if = DWC_ALLOC(sizeof(dwc_otg_host_if_t));
20902 +
20903 + if (host_if == NULL) {
20904 + DWC_DEBUGPL(DBG_CIL,
20905 + "Allocation of dwc_otg_host_if_t failed\n");
20906 + DWC_FREE(dev_if);
20907 + DWC_FREE(core_if);
20908 + return 0;
20909 + }
20910 +
20911 + host_if->host_global_regs = (dwc_otg_host_global_regs_t *)
20912 + (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET);
20913 +
20914 + host_if->hprt0 =
20915 + (uint32_t *) (reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);
20916 +
20917 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
20918 + host_if->hc_regs[i] = (dwc_otg_hc_regs_t *)
20919 + (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET +
20920 + (i * DWC_OTG_CHAN_REGS_OFFSET));
20921 + DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n",
20922 + i, &host_if->hc_regs[i]->hcchar);
20923 + }
20924 +
20925 + host_if->num_host_channels = MAX_EPS_CHANNELS;
20926 + core_if->host_if = host_if;
20927 +
20928 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
20929 + core_if->data_fifo[i] =
20930 + (uint32_t *) (reg_base + DWC_OTG_DATA_FIFO_OFFSET +
20931 + (i * DWC_OTG_DATA_FIFO_SIZE));
20932 + DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08lx\n",
20933 + i, (unsigned long)core_if->data_fifo[i]);
20934 + }
20935 +
20936 + core_if->pcgcctl = (uint32_t *) (reg_base + DWC_OTG_PCGCCTL_OFFSET);
20937 +
20938 + /* Initiate lx_state to L3 disconnected state */
20939 + core_if->lx_state = DWC_OTG_L3;
20940 + /*
20941 + * Store the contents of the hardware configuration registers here for
20942 + * easy access later.
20943 + */
20944 + core_if->hwcfg1.d32 =
20945 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg1);
20946 + core_if->hwcfg2.d32 =
20947 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
20948 + core_if->hwcfg3.d32 =
20949 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg3);
20950 + core_if->hwcfg4.d32 =
20951 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
20952 +
20953 + /* Force host mode to get HPTXFSIZ exact power on value */
20954 + {
20955 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
20956 + gusbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
20957 + gusbcfg.b.force_host_mode = 1;
20958 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
20959 + dwc_mdelay(100);
20960 + core_if->hptxfsiz.d32 =
20961 + DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
20962 + gusbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
20963 + gusbcfg.b.force_host_mode = 0;
20964 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
20965 + dwc_mdelay(100);
20966 + }
20967 +
20968 + DWC_DEBUGPL(DBG_CILV, "hwcfg1=%08x\n", core_if->hwcfg1.d32);
20969 + DWC_DEBUGPL(DBG_CILV, "hwcfg2=%08x\n", core_if->hwcfg2.d32);
20970 + DWC_DEBUGPL(DBG_CILV, "hwcfg3=%08x\n", core_if->hwcfg3.d32);
20971 + DWC_DEBUGPL(DBG_CILV, "hwcfg4=%08x\n", core_if->hwcfg4.d32);
20972 +
20973 + core_if->hcfg.d32 =
20974 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
20975 + core_if->dcfg.d32 =
20976 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
20977 +
20978 + DWC_DEBUGPL(DBG_CILV, "hcfg=%08x\n", core_if->hcfg.d32);
20979 + DWC_DEBUGPL(DBG_CILV, "dcfg=%08x\n", core_if->dcfg.d32);
20980 +
20981 + DWC_DEBUGPL(DBG_CILV, "op_mode=%0x\n", core_if->hwcfg2.b.op_mode);
20982 + DWC_DEBUGPL(DBG_CILV, "arch=%0x\n", core_if->hwcfg2.b.architecture);
20983 + DWC_DEBUGPL(DBG_CILV, "num_dev_ep=%d\n", core_if->hwcfg2.b.num_dev_ep);
20984 + DWC_DEBUGPL(DBG_CILV, "num_host_chan=%d\n",
20985 + core_if->hwcfg2.b.num_host_chan);
20986 + DWC_DEBUGPL(DBG_CILV, "nonperio_tx_q_depth=0x%0x\n",
20987 + core_if->hwcfg2.b.nonperio_tx_q_depth);
20988 + DWC_DEBUGPL(DBG_CILV, "host_perio_tx_q_depth=0x%0x\n",
20989 + core_if->hwcfg2.b.host_perio_tx_q_depth);
20990 + DWC_DEBUGPL(DBG_CILV, "dev_token_q_depth=0x%0x\n",
20991 + core_if->hwcfg2.b.dev_token_q_depth);
20992 +
20993 + DWC_DEBUGPL(DBG_CILV, "Total FIFO SZ=%d\n",
20994 + core_if->hwcfg3.b.dfifo_depth);
20995 + DWC_DEBUGPL(DBG_CILV, "xfer_size_cntr_width=%0x\n",
20996 + core_if->hwcfg3.b.xfer_size_cntr_width);
20997 +
20998 + /*
20999 + * Set the SRP sucess bit for FS-I2c
21000 + */
21001 + core_if->srp_success = 0;
21002 + core_if->srp_timer_started = 0;
21003 +
21004 + /*
21005 + * Create new workqueue and init works
21006 + */
21007 + core_if->wq_otg = DWC_WORKQ_ALLOC("dwc_otg");
21008 + if (core_if->wq_otg == 0) {
21009 + DWC_WARN("DWC_WORKQ_ALLOC failed\n");
21010 + DWC_FREE(host_if);
21011 + DWC_FREE(dev_if);
21012 + DWC_FREE(core_if);
21013 + return 0;
21014 + }
21015 +
21016 + core_if->snpsid = DWC_READ_REG32(&core_if->core_global_regs->gsnpsid);
21017 +
21018 + DWC_PRINTF("Core Release: %x.%x%x%x\n",
21019 + (core_if->snpsid >> 12 & 0xF),
21020 + (core_if->snpsid >> 8 & 0xF),
21021 + (core_if->snpsid >> 4 & 0xF), (core_if->snpsid & 0xF));
21022 +
21023 + core_if->wkp_timer = DWC_TIMER_ALLOC("Wake Up Timer",
21024 + w_wakeup_detected, core_if);
21025 + if (core_if->wkp_timer == 0) {
21026 + DWC_WARN("DWC_TIMER_ALLOC failed\n");
21027 + DWC_FREE(host_if);
21028 + DWC_FREE(dev_if);
21029 + DWC_WORKQ_FREE(core_if->wq_otg);
21030 + DWC_FREE(core_if);
21031 + return 0;
21032 + }
21033 +
21034 + if (dwc_otg_setup_params(core_if)) {
21035 + DWC_WARN("Error while setting core params\n");
21036 + }
21037 +
21038 + core_if->hibernation_suspend = 0;
21039 +
21040 + /** ADP initialization */
21041 + dwc_otg_adp_init(core_if);
21042 +
21043 + return core_if;
21044 +}
21045 +
21046 +/**
21047 + * This function frees the structures allocated by dwc_otg_cil_init().
21048 + *
21049 + * @param core_if The core interface pointer returned from
21050 + * dwc_otg_cil_init().
21051 + *
21052 + */
21053 +void dwc_otg_cil_remove(dwc_otg_core_if_t * core_if)
21054 +{
21055 + dctl_data_t dctl = {.d32 = 0 };
21056 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
21057 +
21058 + /* Disable all interrupts */
21059 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 1, 0);
21060 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
21061 +
21062 + dctl.b.sftdiscon = 1;
21063 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
21064 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0,
21065 + dctl.d32);
21066 + }
21067 +
21068 + if (core_if->wq_otg) {
21069 + DWC_WORKQ_WAIT_WORK_DONE(core_if->wq_otg, 500);
21070 + DWC_WORKQ_FREE(core_if->wq_otg);
21071 + }
21072 + if (core_if->dev_if) {
21073 + DWC_FREE(core_if->dev_if);
21074 + }
21075 + if (core_if->host_if) {
21076 + DWC_FREE(core_if->host_if);
21077 + }
21078 +
21079 + /** Remove ADP Stuff */
21080 + dwc_otg_adp_remove(core_if);
21081 + if (core_if->core_params) {
21082 + DWC_FREE(core_if->core_params);
21083 + }
21084 + if (core_if->wkp_timer) {
21085 + DWC_TIMER_FREE(core_if->wkp_timer);
21086 + }
21087 + if (core_if->srp_timer) {
21088 + DWC_TIMER_FREE(core_if->srp_timer);
21089 + }
21090 + DWC_FREE(core_if);
21091 +}
21092 +
21093 +/**
21094 + * This function enables the controller's Global Interrupt in the AHB Config
21095 + * register.
21096 + *
21097 + * @param core_if Programming view of DWC_otg controller.
21098 + */
21099 +void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * core_if)
21100 +{
21101 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
21102 + ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */
21103 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32);
21104 +}
21105 +
21106 +/**
21107 + * This function disables the controller's Global Interrupt in the AHB Config
21108 + * register.
21109 + *
21110 + * @param core_if Programming view of DWC_otg controller.
21111 + */
21112 +void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * core_if)
21113 +{
21114 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
21115 + ahbcfg.b.glblintrmsk = 1; /* Disable interrupts */
21116 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
21117 +}
21118 +
21119 +/**
21120 + * This function initializes the commmon interrupts, used in both
21121 + * device and host modes.
21122 + *
21123 + * @param core_if Programming view of the DWC_otg controller
21124 + *
21125 + */
21126 +static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t * core_if)
21127 +{
21128 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
21129 + gintmsk_data_t intr_mask = {.d32 = 0 };
21130 +
21131 + /* Clear any pending OTG Interrupts */
21132 + DWC_WRITE_REG32(&global_regs->gotgint, 0xFFFFFFFF);
21133 +
21134 + /* Clear any pending interrupts */
21135 + DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
21136 +
21137 + /*
21138 + * Enable the interrupts in the GINTMSK.
21139 + */
21140 + intr_mask.b.modemismatch = 1;
21141 + intr_mask.b.otgintr = 1;
21142 +
21143 + if (!core_if->dma_enable) {
21144 + intr_mask.b.rxstsqlvl = 1;
21145 + }
21146 +
21147 + intr_mask.b.conidstschng = 1;
21148 + intr_mask.b.wkupintr = 1;
21149 + intr_mask.b.disconnect = 0;
21150 + intr_mask.b.usbsuspend = 1;
21151 + intr_mask.b.sessreqintr = 1;
21152 +#ifdef CONFIG_USB_DWC_OTG_LPM
21153 + if (core_if->core_params->lpm_enable) {
21154 + intr_mask.b.lpmtranrcvd = 1;
21155 + }
21156 +#endif
21157 + DWC_WRITE_REG32(&global_regs->gintmsk, intr_mask.d32);
21158 +}
21159 +
21160 +/*
21161 + * The restore operation is modified to support Synopsys Emulated Powerdown and
21162 + * Hibernation. This function is for exiting from Device mode hibernation by
21163 + * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
21164 + * @param core_if Programming view of DWC_otg controller.
21165 + * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
21166 + * @param reset - indicates whether resume is initiated by Reset.
21167 + */
21168 +int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
21169 + int rem_wakeup, int reset)
21170 +{
21171 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
21172 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
21173 + dctl_data_t dctl = {.d32 = 0 };
21174 +
21175 + int timeout = 2000;
21176 +
21177 + if (!core_if->hibernation_suspend) {
21178 + DWC_PRINTF("Already exited from Hibernation\n");
21179 + return 1;
21180 + }
21181 +
21182 + DWC_DEBUGPL(DBG_PCD, "%s called\n", __FUNCTION__);
21183 + /* Switch-on voltage to the core */
21184 + gpwrdn.b.pwrdnswtch = 1;
21185 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21186 + dwc_udelay(10);
21187 +
21188 + /* Reset core */
21189 + gpwrdn.d32 = 0;
21190 + gpwrdn.b.pwrdnrstn = 1;
21191 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21192 + dwc_udelay(10);
21193 +
21194 + /* Assert Restore signal */
21195 + gpwrdn.d32 = 0;
21196 + gpwrdn.b.restore = 1;
21197 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21198 + dwc_udelay(10);
21199 +
21200 + /* Disable power clamps */
21201 + gpwrdn.d32 = 0;
21202 + gpwrdn.b.pwrdnclmp = 1;
21203 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21204 +
21205 + if (rem_wakeup) {
21206 + dwc_udelay(70);
21207 + }
21208 +
21209 + /* Deassert Reset core */
21210 + gpwrdn.d32 = 0;
21211 + gpwrdn.b.pwrdnrstn = 1;
21212 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21213 + dwc_udelay(10);
21214 +
21215 + /* Disable PMU interrupt */
21216 + gpwrdn.d32 = 0;
21217 + gpwrdn.b.pmuintsel = 1;
21218 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21219 +
21220 + /* Mask interrupts from gpwrdn */
21221 + gpwrdn.d32 = 0;
21222 + gpwrdn.b.connect_det_msk = 1;
21223 + gpwrdn.b.srp_det_msk = 1;
21224 + gpwrdn.b.disconn_det_msk = 1;
21225 + gpwrdn.b.rst_det_msk = 1;
21226 + gpwrdn.b.lnstchng_msk = 1;
21227 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21228 +
21229 + /* Indicates that we are going out from hibernation */
21230 + core_if->hibernation_suspend = 0;
21231 +
21232 + /*
21233 + * Set Restore Essential Regs bit in PCGCCTL register, restore_mode = 1
21234 + * indicates restore from remote_wakeup
21235 + */
21236 + restore_essential_regs(core_if, rem_wakeup, 0);
21237 +
21238 + /*
21239 + * Wait a little for seeing new value of variable hibernation_suspend if
21240 + * Restore done interrupt received before polling
21241 + */
21242 + dwc_udelay(10);
21243 +
21244 + if (core_if->hibernation_suspend == 0) {
21245 + /*
21246 + * Wait For Restore_done Interrupt. This mechanism of polling the
21247 + * interrupt is introduced to avoid any possible race conditions
21248 + */
21249 + do {
21250 + gintsts_data_t gintsts;
21251 + gintsts.d32 =
21252 + DWC_READ_REG32(&core_if->core_global_regs->gintsts);
21253 + if (gintsts.b.restoredone) {
21254 + gintsts.d32 = 0;
21255 + gintsts.b.restoredone = 1;
21256 + DWC_WRITE_REG32(&core_if->core_global_regs->
21257 + gintsts, gintsts.d32);
21258 + DWC_PRINTF("Restore Done Interrupt seen\n");
21259 + break;
21260 + }
21261 + dwc_udelay(10);
21262 + } while (--timeout);
21263 + if (!timeout) {
21264 + DWC_PRINTF("Restore Done interrupt wasn't generated here\n");
21265 + }
21266 + }
21267 + /* Clear all pending interupts */
21268 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21269 +
21270 + /* De-assert Restore */
21271 + gpwrdn.d32 = 0;
21272 + gpwrdn.b.restore = 1;
21273 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21274 + dwc_udelay(10);
21275 +
21276 + if (!rem_wakeup) {
21277 + pcgcctl.d32 = 0;
21278 + pcgcctl.b.rstpdwnmodule = 1;
21279 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
21280 + }
21281 +
21282 + /* Restore GUSBCFG and DCFG */
21283 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
21284 + core_if->gr_backup->gusbcfg_local);
21285 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
21286 + core_if->dr_backup->dcfg);
21287 +
21288 + /* De-assert Wakeup Logic */
21289 + gpwrdn.d32 = 0;
21290 + gpwrdn.b.pmuactv = 1;
21291 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21292 + dwc_udelay(10);
21293 +
21294 + if (!rem_wakeup) {
21295 + /* Set Device programming done bit */
21296 + dctl.b.pwronprgdone = 1;
21297 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
21298 + } else {
21299 + /* Start Remote Wakeup Signaling */
21300 + dctl.d32 = core_if->dr_backup->dctl;
21301 + dctl.b.rmtwkupsig = 1;
21302 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
21303 + }
21304 +
21305 + dwc_mdelay(2);
21306 + /* Clear all pending interupts */
21307 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21308 +
21309 + /* Restore global registers */
21310 + dwc_otg_restore_global_regs(core_if);
21311 + /* Restore device global registers */
21312 + dwc_otg_restore_dev_regs(core_if, rem_wakeup);
21313 +
21314 + if (rem_wakeup) {
21315 + dwc_mdelay(7);
21316 + dctl.d32 = 0;
21317 + dctl.b.rmtwkupsig = 1;
21318 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
21319 + }
21320 +
21321 + core_if->hibernation_suspend = 0;
21322 + /* The core will be in ON STATE */
21323 + core_if->lx_state = DWC_OTG_L0;
21324 + DWC_PRINTF("Hibernation recovery completes here\n");
21325 +
21326 + return 1;
21327 +}
21328 +
21329 +/*
21330 + * The restore operation is modified to support Synopsys Emulated Powerdown and
21331 + * Hibernation. This function is for exiting from Host mode hibernation by
21332 + * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
21333 + * @param core_if Programming view of DWC_otg controller.
21334 + * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
21335 + * @param reset - indicates whether resume is initiated by Reset.
21336 + */
21337 +int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
21338 + int rem_wakeup, int reset)
21339 +{
21340 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
21341 + hprt0_data_t hprt0 = {.d32 = 0 };
21342 +
21343 + int timeout = 2000;
21344 +
21345 + DWC_DEBUGPL(DBG_HCD, "%s called\n", __FUNCTION__);
21346 + /* Switch-on voltage to the core */
21347 + gpwrdn.b.pwrdnswtch = 1;
21348 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21349 + dwc_udelay(10);
21350 +
21351 + /* Reset core */
21352 + gpwrdn.d32 = 0;
21353 + gpwrdn.b.pwrdnrstn = 1;
21354 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21355 + dwc_udelay(10);
21356 +
21357 + /* Assert Restore signal */
21358 + gpwrdn.d32 = 0;
21359 + gpwrdn.b.restore = 1;
21360 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21361 + dwc_udelay(10);
21362 +
21363 + /* Disable power clamps */
21364 + gpwrdn.d32 = 0;
21365 + gpwrdn.b.pwrdnclmp = 1;
21366 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21367 +
21368 + if (!rem_wakeup) {
21369 + dwc_udelay(50);
21370 + }
21371 +
21372 + /* Deassert Reset core */
21373 + gpwrdn.d32 = 0;
21374 + gpwrdn.b.pwrdnrstn = 1;
21375 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21376 + dwc_udelay(10);
21377 +
21378 + /* Disable PMU interrupt */
21379 + gpwrdn.d32 = 0;
21380 + gpwrdn.b.pmuintsel = 1;
21381 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21382 +
21383 + gpwrdn.d32 = 0;
21384 + gpwrdn.b.connect_det_msk = 1;
21385 + gpwrdn.b.srp_det_msk = 1;
21386 + gpwrdn.b.disconn_det_msk = 1;
21387 + gpwrdn.b.rst_det_msk = 1;
21388 + gpwrdn.b.lnstchng_msk = 1;
21389 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21390 +
21391 + /* Indicates that we are going out from hibernation */
21392 + core_if->hibernation_suspend = 0;
21393 +
21394 + /* Set Restore Essential Regs bit in PCGCCTL register */
21395 + restore_essential_regs(core_if, rem_wakeup, 1);
21396 +
21397 + /* Wait a little for seeing new value of variable hibernation_suspend if
21398 + * Restore done interrupt received before polling */
21399 + dwc_udelay(10);
21400 +
21401 + if (core_if->hibernation_suspend == 0) {
21402 + /* Wait For Restore_done Interrupt. This mechanism of polling the
21403 + * interrupt is introduced to avoid any possible race conditions
21404 + */
21405 + do {
21406 + gintsts_data_t gintsts;
21407 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
21408 + if (gintsts.b.restoredone) {
21409 + gintsts.d32 = 0;
21410 + gintsts.b.restoredone = 1;
21411 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
21412 + DWC_DEBUGPL(DBG_HCD,"Restore Done Interrupt seen\n");
21413 + break;
21414 + }
21415 + dwc_udelay(10);
21416 + } while (--timeout);
21417 + if (!timeout) {
21418 + DWC_WARN("Restore Done interrupt wasn't generated\n");
21419 + }
21420 + }
21421 +
21422 + /* Set the flag's value to 0 again after receiving restore done interrupt */
21423 + core_if->hibernation_suspend = 0;
21424 +
21425 + /* This step is not described in functional spec but if not wait for this
21426 + * delay, mismatch interrupts occurred because just after restore core is
21427 + * in Device mode(gintsts.curmode == 0) */
21428 + dwc_mdelay(100);
21429 +
21430 + /* Clear all pending interrupts */
21431 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21432 +
21433 + /* De-assert Restore */
21434 + gpwrdn.d32 = 0;
21435 + gpwrdn.b.restore = 1;
21436 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21437 + dwc_udelay(10);
21438 +
21439 + /* Restore GUSBCFG and HCFG */
21440 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
21441 + core_if->gr_backup->gusbcfg_local);
21442 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
21443 + core_if->hr_backup->hcfg_local);
21444 +
21445 + /* De-assert Wakeup Logic */
21446 + gpwrdn.d32 = 0;
21447 + gpwrdn.b.pmuactv = 1;
21448 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21449 + dwc_udelay(10);
21450 +
21451 + /* Start the Resume operation by programming HPRT0 */
21452 + hprt0.d32 = core_if->hr_backup->hprt0_local;
21453 + hprt0.b.prtpwr = 1;
21454 + hprt0.b.prtena = 0;
21455 + hprt0.b.prtsusp = 0;
21456 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21457 +
21458 + DWC_PRINTF("Resume Starts Now\n");
21459 + if (!reset) { // Indicates it is Resume Operation
21460 + hprt0.d32 = core_if->hr_backup->hprt0_local;
21461 + hprt0.b.prtres = 1;
21462 + hprt0.b.prtpwr = 1;
21463 + hprt0.b.prtena = 0;
21464 + hprt0.b.prtsusp = 0;
21465 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21466 +
21467 + if (!rem_wakeup)
21468 + hprt0.b.prtres = 0;
21469 + /* Wait for Resume time and then program HPRT again */
21470 + dwc_mdelay(100);
21471 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21472 +
21473 + } else { // Indicates it is Reset Operation
21474 + hprt0.d32 = core_if->hr_backup->hprt0_local;
21475 + hprt0.b.prtrst = 1;
21476 + hprt0.b.prtpwr = 1;
21477 + hprt0.b.prtena = 0;
21478 + hprt0.b.prtsusp = 0;
21479 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21480 + /* Wait for Reset time and then program HPRT again */
21481 + dwc_mdelay(60);
21482 + hprt0.b.prtrst = 0;
21483 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21484 + }
21485 + /* Clear all interrupt status */
21486 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
21487 + hprt0.b.prtconndet = 1;
21488 + hprt0.b.prtenchng = 1;
21489 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21490 +
21491 + /* Clear all pending interupts */
21492 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21493 +
21494 + /* Restore global registers */
21495 + dwc_otg_restore_global_regs(core_if);
21496 + /* Restore host global registers */
21497 + dwc_otg_restore_host_regs(core_if, reset);
21498 +
21499 + /* The core will be in ON STATE */
21500 + core_if->lx_state = DWC_OTG_L0;
21501 + DWC_PRINTF("Hibernation recovery is complete here\n");
21502 + return 0;
21503 +}
21504 +
21505 +/** Saves some register values into system memory. */
21506 +int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if)
21507 +{
21508 + struct dwc_otg_global_regs_backup *gr;
21509 + int i;
21510 +
21511 + gr = core_if->gr_backup;
21512 + if (!gr) {
21513 + gr = DWC_ALLOC(sizeof(*gr));
21514 + if (!gr) {
21515 + return -DWC_E_NO_MEMORY;
21516 + }
21517 + core_if->gr_backup = gr;
21518 + }
21519 +
21520 + gr->gotgctl_local = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
21521 + gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
21522 + gr->gahbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
21523 + gr->gusbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
21524 + gr->grxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
21525 + gr->gnptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
21526 + gr->hptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
21527 +#ifdef CONFIG_USB_DWC_OTG_LPM
21528 + gr->glpmcfg_local = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
21529 +#endif
21530 + gr->gi2cctl_local = DWC_READ_REG32(&core_if->core_global_regs->gi2cctl);
21531 + gr->pcgcctl_local = DWC_READ_REG32(core_if->pcgcctl);
21532 + gr->gdfifocfg_local =
21533 + DWC_READ_REG32(&core_if->core_global_regs->gdfifocfg);
21534 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21535 + gr->dtxfsiz_local[i] =
21536 + DWC_READ_REG32(&(core_if->core_global_regs->dtxfsiz[i]));
21537 + }
21538 +
21539 + DWC_DEBUGPL(DBG_ANY, "===========Backing Global registers==========\n");
21540 + DWC_DEBUGPL(DBG_ANY, "Backed up gotgctl = %08x\n", gr->gotgctl_local);
21541 + DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk = %08x\n", gr->gintmsk_local);
21542 + DWC_DEBUGPL(DBG_ANY, "Backed up gahbcfg = %08x\n", gr->gahbcfg_local);
21543 + DWC_DEBUGPL(DBG_ANY, "Backed up gusbcfg = %08x\n", gr->gusbcfg_local);
21544 + DWC_DEBUGPL(DBG_ANY, "Backed up grxfsiz = %08x\n", gr->grxfsiz_local);
21545 + DWC_DEBUGPL(DBG_ANY, "Backed up gnptxfsiz = %08x\n",
21546 + gr->gnptxfsiz_local);
21547 + DWC_DEBUGPL(DBG_ANY, "Backed up hptxfsiz = %08x\n",
21548 + gr->hptxfsiz_local);
21549 +#ifdef CONFIG_USB_DWC_OTG_LPM
21550 + DWC_DEBUGPL(DBG_ANY, "Backed up glpmcfg = %08x\n", gr->glpmcfg_local);
21551 +#endif
21552 + DWC_DEBUGPL(DBG_ANY, "Backed up gi2cctl = %08x\n", gr->gi2cctl_local);
21553 + DWC_DEBUGPL(DBG_ANY, "Backed up pcgcctl = %08x\n", gr->pcgcctl_local);
21554 + DWC_DEBUGPL(DBG_ANY,"Backed up gdfifocfg = %08x\n",gr->gdfifocfg_local);
21555 +
21556 + return 0;
21557 +}
21558 +
21559 +/** Saves GINTMSK register before setting the msk bits. */
21560 +int dwc_otg_save_gintmsk_reg(dwc_otg_core_if_t * core_if)
21561 +{
21562 + struct dwc_otg_global_regs_backup *gr;
21563 +
21564 + gr = core_if->gr_backup;
21565 + if (!gr) {
21566 + gr = DWC_ALLOC(sizeof(*gr));
21567 + if (!gr) {
21568 + return -DWC_E_NO_MEMORY;
21569 + }
21570 + core_if->gr_backup = gr;
21571 + }
21572 +
21573 + gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
21574 +
21575 + DWC_DEBUGPL(DBG_ANY,"=============Backing GINTMSK registers============\n");
21576 + DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk = %08x\n", gr->gintmsk_local);
21577 +
21578 + return 0;
21579 +}
21580 +
21581 +int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if)
21582 +{
21583 + struct dwc_otg_dev_regs_backup *dr;
21584 + int i;
21585 +
21586 + dr = core_if->dr_backup;
21587 + if (!dr) {
21588 + dr = DWC_ALLOC(sizeof(*dr));
21589 + if (!dr) {
21590 + return -DWC_E_NO_MEMORY;
21591 + }
21592 + core_if->dr_backup = dr;
21593 + }
21594 +
21595 + dr->dcfg = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
21596 + dr->dctl = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
21597 + dr->daintmsk =
21598 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
21599 + dr->diepmsk =
21600 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->diepmsk);
21601 + dr->doepmsk =
21602 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->doepmsk);
21603 +
21604 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
21605 + dr->diepctl[i] =
21606 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
21607 + dr->dieptsiz[i] =
21608 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz);
21609 + dr->diepdma[i] =
21610 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma);
21611 + }
21612 +
21613 + DWC_DEBUGPL(DBG_ANY,
21614 + "=============Backing Host registers==============\n");
21615 + DWC_DEBUGPL(DBG_ANY, "Backed up dcfg = %08x\n", dr->dcfg);
21616 + DWC_DEBUGPL(DBG_ANY, "Backed up dctl = %08x\n", dr->dctl);
21617 + DWC_DEBUGPL(DBG_ANY, "Backed up daintmsk = %08x\n",
21618 + dr->daintmsk);
21619 + DWC_DEBUGPL(DBG_ANY, "Backed up diepmsk = %08x\n", dr->diepmsk);
21620 + DWC_DEBUGPL(DBG_ANY, "Backed up doepmsk = %08x\n", dr->doepmsk);
21621 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
21622 + DWC_DEBUGPL(DBG_ANY, "Backed up diepctl[%d] = %08x\n", i,
21623 + dr->diepctl[i]);
21624 + DWC_DEBUGPL(DBG_ANY, "Backed up dieptsiz[%d] = %08x\n",
21625 + i, dr->dieptsiz[i]);
21626 + DWC_DEBUGPL(DBG_ANY, "Backed up diepdma[%d] = %08x\n", i,
21627 + dr->diepdma[i]);
21628 + }
21629 +
21630 + return 0;
21631 +}
21632 +
21633 +int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if)
21634 +{
21635 + struct dwc_otg_host_regs_backup *hr;
21636 + int i;
21637 +
21638 + hr = core_if->hr_backup;
21639 + if (!hr) {
21640 + hr = DWC_ALLOC(sizeof(*hr));
21641 + if (!hr) {
21642 + return -DWC_E_NO_MEMORY;
21643 + }
21644 + core_if->hr_backup = hr;
21645 + }
21646 +
21647 + hr->hcfg_local =
21648 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
21649 + hr->haintmsk_local =
21650 + DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk);
21651 + for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
21652 + hr->hcintmsk_local[i] =
21653 + DWC_READ_REG32(&core_if->host_if->hc_regs[i]->hcintmsk);
21654 + }
21655 + hr->hprt0_local = DWC_READ_REG32(core_if->host_if->hprt0);
21656 + hr->hfir_local =
21657 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
21658 +
21659 + DWC_DEBUGPL(DBG_ANY,
21660 + "=============Backing Host registers===============\n");
21661 + DWC_DEBUGPL(DBG_ANY, "Backed up hcfg = %08x\n",
21662 + hr->hcfg_local);
21663 + DWC_DEBUGPL(DBG_ANY, "Backed up haintmsk = %08x\n", hr->haintmsk_local);
21664 + for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
21665 + DWC_DEBUGPL(DBG_ANY, "Backed up hcintmsk[%02d]=%08x\n", i,
21666 + hr->hcintmsk_local[i]);
21667 + }
21668 + DWC_DEBUGPL(DBG_ANY, "Backed up hprt0 = %08x\n",
21669 + hr->hprt0_local);
21670 + DWC_DEBUGPL(DBG_ANY, "Backed up hfir = %08x\n",
21671 + hr->hfir_local);
21672 +
21673 + return 0;
21674 +}
21675 +
21676 +int dwc_otg_restore_global_regs(dwc_otg_core_if_t *core_if)
21677 +{
21678 + struct dwc_otg_global_regs_backup *gr;
21679 + int i;
21680 +
21681 + gr = core_if->gr_backup;
21682 + if (!gr) {
21683 + return -DWC_E_INVALID;
21684 + }
21685 +
21686 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, gr->gotgctl_local);
21687 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gr->gintmsk_local);
21688 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gr->gusbcfg_local);
21689 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gr->gahbcfg_local);
21690 + DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, gr->grxfsiz_local);
21691 + DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz,
21692 + gr->gnptxfsiz_local);
21693 + DWC_WRITE_REG32(&core_if->core_global_regs->hptxfsiz,
21694 + gr->hptxfsiz_local);
21695 + DWC_WRITE_REG32(&core_if->core_global_regs->gdfifocfg,
21696 + gr->gdfifocfg_local);
21697 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21698 + DWC_WRITE_REG32(&core_if->core_global_regs->dtxfsiz[i],
21699 + gr->dtxfsiz_local[i]);
21700 + }
21701 +
21702 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21703 + DWC_WRITE_REG32(core_if->host_if->hprt0, 0x0000100A);
21704 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg,
21705 + (gr->gahbcfg_local));
21706 + return 0;
21707 +}
21708 +
21709 +int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if, int rem_wakeup)
21710 +{
21711 + struct dwc_otg_dev_regs_backup *dr;
21712 + int i;
21713 +
21714 + dr = core_if->dr_backup;
21715 +
21716 + if (!dr) {
21717 + return -DWC_E_INVALID;
21718 + }
21719 +
21720 + if (!rem_wakeup) {
21721 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
21722 + dr->dctl);
21723 + }
21724 +
21725 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, dr->daintmsk);
21726 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, dr->diepmsk);
21727 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, dr->doepmsk);
21728 +
21729 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
21730 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz, dr->dieptsiz[i]);
21731 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma, dr->diepdma[i]);
21732 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl, dr->diepctl[i]);
21733 + }
21734 +
21735 + return 0;
21736 +}
21737 +
21738 +int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset)
21739 +{
21740 + struct dwc_otg_host_regs_backup *hr;
21741 + int i;
21742 + hr = core_if->hr_backup;
21743 +
21744 + if (!hr) {
21745 + return -DWC_E_INVALID;
21746 + }
21747 +
21748 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hr->hcfg_local);
21749 + //if (!reset)
21750 + //{
21751 + // DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hr->hfir_local);
21752 + //}
21753 +
21754 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk,
21755 + hr->haintmsk_local);
21756 + for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
21757 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk,
21758 + hr->hcintmsk_local[i]);
21759 + }
21760 +
21761 + return 0;
21762 +}
21763 +
21764 +int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if)
21765 +{
21766 + struct dwc_otg_global_regs_backup *gr;
21767 +
21768 + gr = core_if->gr_backup;
21769 +
21770 + /* Restore values for LPM and I2C */
21771 +#ifdef CONFIG_USB_DWC_OTG_LPM
21772 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, gr->glpmcfg_local);
21773 +#endif
21774 + DWC_WRITE_REG32(&core_if->core_global_regs->gi2cctl, gr->gi2cctl_local);
21775 +
21776 + return 0;
21777 +}
21778 +
21779 +int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode, int is_host)
21780 +{
21781 + struct dwc_otg_global_regs_backup *gr;
21782 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
21783 + gahbcfg_data_t gahbcfg = {.d32 = 0 };
21784 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
21785 + gintmsk_data_t gintmsk = {.d32 = 0 };
21786 +
21787 + /* Restore LPM and I2C registers */
21788 + restore_lpm_i2c_regs(core_if);
21789 +
21790 + /* Set PCGCCTL to 0 */
21791 + DWC_WRITE_REG32(core_if->pcgcctl, 0x00000000);
21792 +
21793 + gr = core_if->gr_backup;
21794 + /* Load restore values for [31:14] bits */
21795 + DWC_WRITE_REG32(core_if->pcgcctl,
21796 + ((gr->pcgcctl_local & 0xffffc000) | 0x00020000));
21797 +
21798 + /* Umnask global Interrupt in GAHBCFG and restore it */
21799 + gahbcfg.d32 = gr->gahbcfg_local;
21800 + gahbcfg.b.glblintrmsk = 1;
21801 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
21802 +
21803 + /* Clear all pending interupts */
21804 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21805 +
21806 + /* Unmask restore done interrupt */
21807 + gintmsk.b.restoredone = 1;
21808 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
21809 +
21810 + /* Restore GUSBCFG and HCFG/DCFG */
21811 + gusbcfg.d32 = core_if->gr_backup->gusbcfg_local;
21812 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
21813 +
21814 + if (is_host) {
21815 + hcfg_data_t hcfg = {.d32 = 0 };
21816 + hcfg.d32 = core_if->hr_backup->hcfg_local;
21817 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
21818 + hcfg.d32);
21819 +
21820 + /* Load restore values for [31:14] bits */
21821 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
21822 + pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
21823 +
21824 + if (rmode)
21825 + pcgcctl.b.restoremode = 1;
21826 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
21827 + dwc_udelay(10);
21828 +
21829 + /* Load restore values for [31:14] bits and set EssRegRestored bit */
21830 + pcgcctl.d32 = gr->pcgcctl_local | 0xffffc000;
21831 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
21832 + pcgcctl.b.ess_reg_restored = 1;
21833 + if (rmode)
21834 + pcgcctl.b.restoremode = 1;
21835 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
21836 + } else {
21837 + dcfg_data_t dcfg = {.d32 = 0 };
21838 + dcfg.d32 = core_if->dr_backup->dcfg;
21839 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
21840 +
21841 + /* Load restore values for [31:14] bits */
21842 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
21843 + pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
21844 + if (!rmode) {
21845 + pcgcctl.d32 |= 0x208;
21846 + }
21847 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
21848 + dwc_udelay(10);
21849 +
21850 + /* Load restore values for [31:14] bits */
21851 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
21852 + pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
21853 + pcgcctl.b.ess_reg_restored = 1;
21854 + if (!rmode)
21855 + pcgcctl.d32 |= 0x208;
21856 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
21857 + }
21858 +
21859 + return 0;
21860 +}
21861 +
21862 +/**
21863 + * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY
21864 + * type.
21865 + */
21866 +static void init_fslspclksel(dwc_otg_core_if_t * core_if)
21867 +{
21868 + uint32_t val;
21869 + hcfg_data_t hcfg;
21870 +
21871 + if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
21872 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
21873 + (core_if->core_params->ulpi_fs_ls)) ||
21874 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
21875 + /* Full speed PHY */
21876 + val = DWC_HCFG_48_MHZ;
21877 + } else {
21878 + /* High speed PHY running at full speed or high speed */
21879 + val = DWC_HCFG_30_60_MHZ;
21880 + }
21881 +
21882 + DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val);
21883 + hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
21884 + hcfg.b.fslspclksel = val;
21885 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
21886 +}
21887 +
21888 +/**
21889 + * Initializes the DevSpd field of the DCFG register depending on the PHY type
21890 + * and the enumeration speed of the device.
21891 + */
21892 +static void init_devspd(dwc_otg_core_if_t * core_if)
21893 +{
21894 + uint32_t val;
21895 + dcfg_data_t dcfg;
21896 +
21897 + if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
21898 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
21899 + (core_if->core_params->ulpi_fs_ls)) ||
21900 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
21901 + /* Full speed PHY */
21902 + val = 0x3;
21903 + } else if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
21904 + /* High speed PHY running at full speed */
21905 + val = 0x1;
21906 + } else {
21907 + /* High speed PHY running at high speed */
21908 + val = 0x0;
21909 + }
21910 +
21911 + DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val);
21912 +
21913 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
21914 + dcfg.b.devspd = val;
21915 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
21916 +}
21917 +
21918 +/**
21919 + * This function calculates the number of IN EPS
21920 + * using GHWCFG1 and GHWCFG2 registers values
21921 + *
21922 + * @param core_if Programming view of the DWC_otg controller
21923 + */
21924 +static uint32_t calc_num_in_eps(dwc_otg_core_if_t * core_if)
21925 +{
21926 + uint32_t num_in_eps = 0;
21927 + uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
21928 + uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 3;
21929 + uint32_t num_tx_fifos = core_if->hwcfg4.b.num_in_eps;
21930 + int i;
21931 +
21932 + for (i = 0; i < num_eps; ++i) {
21933 + if (!(hwcfg1 & 0x1))
21934 + num_in_eps++;
21935 +
21936 + hwcfg1 >>= 2;
21937 + }
21938 +
21939 + if (core_if->hwcfg4.b.ded_fifo_en) {
21940 + num_in_eps =
21941 + (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps;
21942 + }
21943 +
21944 + return num_in_eps;
21945 +}
21946 +
21947 +/**
21948 + * This function calculates the number of OUT EPS
21949 + * using GHWCFG1 and GHWCFG2 registers values
21950 + *
21951 + * @param core_if Programming view of the DWC_otg controller
21952 + */
21953 +static uint32_t calc_num_out_eps(dwc_otg_core_if_t * core_if)
21954 +{
21955 + uint32_t num_out_eps = 0;
21956 + uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
21957 + uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 2;
21958 + int i;
21959 +
21960 + for (i = 0; i < num_eps; ++i) {
21961 + if (!(hwcfg1 & 0x1))
21962 + num_out_eps++;
21963 +
21964 + hwcfg1 >>= 2;
21965 + }
21966 + return num_out_eps;
21967 +}
21968 +
21969 +/**
21970 + * This function initializes the DWC_otg controller registers and
21971 + * prepares the core for device mode or host mode operation.
21972 + *
21973 + * @param core_if Programming view of the DWC_otg controller
21974 + *
21975 + */
21976 +void dwc_otg_core_init(dwc_otg_core_if_t * core_if)
21977 +{
21978 + int i = 0;
21979 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
21980 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
21981 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
21982 + gusbcfg_data_t usbcfg = {.d32 = 0 };
21983 + gi2cctl_data_t i2cctl = {.d32 = 0 };
21984 +
21985 + DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p) regs at %p\n",
21986 + core_if, global_regs);
21987 +
21988 + /* Common Initialization */
21989 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
21990 +
21991 + /* Program the ULPI External VBUS bit if needed */
21992 + usbcfg.b.ulpi_ext_vbus_drv =
21993 + (core_if->core_params->phy_ulpi_ext_vbus ==
21994 + DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0;
21995 +
21996 + /* Set external TS Dline pulsing */
21997 + usbcfg.b.term_sel_dl_pulse =
21998 + (core_if->core_params->ts_dline == 1) ? 1 : 0;
21999 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22000 +
22001 + /* Reset the Controller */
22002 + dwc_otg_core_reset(core_if);
22003 +
22004 + core_if->adp_enable = core_if->core_params->adp_supp_enable;
22005 + core_if->power_down = core_if->core_params->power_down;
22006 + core_if->otg_sts = 0;
22007 +
22008 + /* Initialize parameters from Hardware configuration registers. */
22009 + dev_if->num_in_eps = calc_num_in_eps(core_if);
22010 + dev_if->num_out_eps = calc_num_out_eps(core_if);
22011 +
22012 + DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",
22013 + core_if->hwcfg4.b.num_dev_perio_in_ep);
22014 +
22015 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
22016 + dev_if->perio_tx_fifo_size[i] =
22017 + DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
22018 + DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n",
22019 + i, dev_if->perio_tx_fifo_size[i]);
22020 + }
22021 +
22022 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
22023 + dev_if->tx_fifo_size[i] =
22024 + DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
22025 + DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n",
22026 + i, dev_if->tx_fifo_size[i]);
22027 + }
22028 +
22029 + core_if->total_fifo_size = core_if->hwcfg3.b.dfifo_depth;
22030 + core_if->rx_fifo_size = DWC_READ_REG32(&global_regs->grxfsiz);
22031 + core_if->nperio_tx_fifo_size =
22032 + DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16;
22033 +
22034 + DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", core_if->total_fifo_size);
22035 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", core_if->rx_fifo_size);
22036 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n",
22037 + core_if->nperio_tx_fifo_size);
22038 +
22039 + /* This programming sequence needs to happen in FS mode before any other
22040 + * programming occurs */
22041 + if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) &&
22042 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
22043 + /* If FS mode with FS PHY */
22044 +
22045 + /* core_init() is now called on every switch so only call the
22046 + * following for the first time through. */
22047 + if (!core_if->phy_init_done) {
22048 + core_if->phy_init_done = 1;
22049 + DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n");
22050 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22051 + usbcfg.b.physel = 1;
22052 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22053 +
22054 + /* Reset after a PHY select */
22055 + dwc_otg_core_reset(core_if);
22056 + }
22057 +
22058 + /* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also
22059 + * do this on HNP Dev/Host mode switches (done in dev_init and
22060 + * host_init). */
22061 + if (dwc_otg_is_host_mode(core_if)) {
22062 + init_fslspclksel(core_if);
22063 + } else {
22064 + init_devspd(core_if);
22065 + }
22066 +
22067 + if (core_if->core_params->i2c_enable) {
22068 + DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n");
22069 + /* Program GUSBCFG.OtgUtmifsSel to I2C */
22070 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22071 + usbcfg.b.otgutmifssel = 1;
22072 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22073 +
22074 + /* Program GI2CCTL.I2CEn */
22075 + i2cctl.d32 = DWC_READ_REG32(&global_regs->gi2cctl);
22076 + i2cctl.b.i2cdevaddr = 1;
22077 + i2cctl.b.i2cen = 0;
22078 + DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
22079 + i2cctl.b.i2cen = 1;
22080 + DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
22081 + }
22082 +
22083 + } /* endif speed == DWC_SPEED_PARAM_FULL */
22084 + else {
22085 + /* High speed PHY. */
22086 + if (!core_if->phy_init_done) {
22087 + core_if->phy_init_done = 1;
22088 + /* HS PHY parameters. These parameters are preserved
22089 + * during soft reset so only program the first time. Do
22090 + * a soft reset immediately after setting phyif. */
22091 +
22092 + if (core_if->core_params->phy_type == 2) {
22093 + /* ULPI interface */
22094 + usbcfg.b.ulpi_utmi_sel = 1;
22095 + usbcfg.b.phyif = 0;
22096 + usbcfg.b.ddrsel =
22097 + core_if->core_params->phy_ulpi_ddr;
22098 + } else if (core_if->core_params->phy_type == 1) {
22099 + /* UTMI+ interface */
22100 + usbcfg.b.ulpi_utmi_sel = 0;
22101 + if (core_if->core_params->phy_utmi_width == 16) {
22102 + usbcfg.b.phyif = 1;
22103 +
22104 + } else {
22105 + usbcfg.b.phyif = 0;
22106 + }
22107 + } else {
22108 + DWC_ERROR("FS PHY TYPE\n");
22109 + }
22110 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22111 + /* Reset after setting the PHY parameters */
22112 + dwc_otg_core_reset(core_if);
22113 + }
22114 + }
22115 +
22116 + if ((core_if->hwcfg2.b.hs_phy_type == 2) &&
22117 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
22118 + (core_if->core_params->ulpi_fs_ls)) {
22119 + DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n");
22120 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22121 + usbcfg.b.ulpi_fsls = 1;
22122 + usbcfg.b.ulpi_clk_sus_m = 1;
22123 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22124 + } else {
22125 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22126 + usbcfg.b.ulpi_fsls = 0;
22127 + usbcfg.b.ulpi_clk_sus_m = 0;
22128 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22129 + }
22130 +
22131 + /* Program the GAHBCFG Register. */
22132 + switch (core_if->hwcfg2.b.architecture) {
22133 +
22134 + case DWC_SLAVE_ONLY_ARCH:
22135 + DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n");
22136 + ahbcfg.b.nptxfemplvl_txfemplvl =
22137 + DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
22138 + ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
22139 + core_if->dma_enable = 0;
22140 + core_if->dma_desc_enable = 0;
22141 + break;
22142 +
22143 + case DWC_EXT_DMA_ARCH:
22144 + DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n");
22145 + {
22146 + uint8_t brst_sz = core_if->core_params->dma_burst_size;
22147 + ahbcfg.b.hburstlen = 0;
22148 + while (brst_sz > 1) {
22149 + ahbcfg.b.hburstlen++;
22150 + brst_sz >>= 1;
22151 + }
22152 + }
22153 + core_if->dma_enable = (core_if->core_params->dma_enable != 0);
22154 + core_if->dma_desc_enable =
22155 + (core_if->core_params->dma_desc_enable != 0);
22156 + break;
22157 +
22158 + case DWC_INT_DMA_ARCH:
22159 + DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n");
22160 + /* Old value was DWC_GAHBCFG_INT_DMA_BURST_INCR - done for
22161 + Host mode ISOC in issue fix - vahrama */
22162 + /* Broadcom had altered to (1<<3)|(0<<0) - WRESP=1, max 4 beats */
22163 + ahbcfg.b.hburstlen = (1<<3)|(0<<0);//DWC_GAHBCFG_INT_DMA_BURST_INCR4;
22164 + core_if->dma_enable = (core_if->core_params->dma_enable != 0);
22165 + core_if->dma_desc_enable =
22166 + (core_if->core_params->dma_desc_enable != 0);
22167 + break;
22168 +
22169 + }
22170 + if (core_if->dma_enable) {
22171 + if (core_if->dma_desc_enable) {
22172 + DWC_PRINTF("Using Descriptor DMA mode\n");
22173 + } else {
22174 + DWC_PRINTF("Using Buffer DMA mode\n");
22175 +
22176 + }
22177 + } else {
22178 + DWC_PRINTF("Using Slave mode\n");
22179 + core_if->dma_desc_enable = 0;
22180 + }
22181 +
22182 + if (core_if->core_params->ahb_single) {
22183 + ahbcfg.b.ahbsingle = 1;
22184 + }
22185 +
22186 + ahbcfg.b.dmaenable = core_if->dma_enable;
22187 + DWC_WRITE_REG32(&global_regs->gahbcfg, ahbcfg.d32);
22188 +
22189 + core_if->en_multiple_tx_fifo = core_if->hwcfg4.b.ded_fifo_en;
22190 +
22191 + core_if->pti_enh_enable = core_if->core_params->pti_enable != 0;
22192 + core_if->multiproc_int_enable = core_if->core_params->mpi_enable;
22193 + DWC_PRINTF("Periodic Transfer Interrupt Enhancement - %s\n",
22194 + ((core_if->pti_enh_enable) ? "enabled" : "disabled"));
22195 + DWC_PRINTF("Multiprocessor Interrupt Enhancement - %s\n",
22196 + ((core_if->multiproc_int_enable) ? "enabled" : "disabled"));
22197 +
22198 + /*
22199 + * Program the GUSBCFG register.
22200 + */
22201 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22202 +
22203 + switch (core_if->hwcfg2.b.op_mode) {
22204 + case DWC_MODE_HNP_SRP_CAPABLE:
22205 + usbcfg.b.hnpcap = (core_if->core_params->otg_cap ==
22206 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
22207 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22208 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22209 + break;
22210 +
22211 + case DWC_MODE_SRP_ONLY_CAPABLE:
22212 + usbcfg.b.hnpcap = 0;
22213 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22214 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22215 + break;
22216 +
22217 + case DWC_MODE_NO_HNP_SRP_CAPABLE:
22218 + usbcfg.b.hnpcap = 0;
22219 + usbcfg.b.srpcap = 0;
22220 + break;
22221 +
22222 + case DWC_MODE_SRP_CAPABLE_DEVICE:
22223 + usbcfg.b.hnpcap = 0;
22224 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22225 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22226 + break;
22227 +
22228 + case DWC_MODE_NO_SRP_CAPABLE_DEVICE:
22229 + usbcfg.b.hnpcap = 0;
22230 + usbcfg.b.srpcap = 0;
22231 + break;
22232 +
22233 + case DWC_MODE_SRP_CAPABLE_HOST:
22234 + usbcfg.b.hnpcap = 0;
22235 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22236 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22237 + break;
22238 +
22239 + case DWC_MODE_NO_SRP_CAPABLE_HOST:
22240 + usbcfg.b.hnpcap = 0;
22241 + usbcfg.b.srpcap = 0;
22242 + break;
22243 + }
22244 +
22245 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22246 +
22247 +#ifdef CONFIG_USB_DWC_OTG_LPM
22248 + if (core_if->core_params->lpm_enable) {
22249 + glpmcfg_data_t lpmcfg = {.d32 = 0 };
22250 +
22251 + /* To enable LPM support set lpm_cap_en bit */
22252 + lpmcfg.b.lpm_cap_en = 1;
22253 +
22254 + /* Make AppL1Res ACK */
22255 + lpmcfg.b.appl_resp = 1;
22256 +
22257 + /* Retry 3 times */
22258 + lpmcfg.b.retry_count = 3;
22259 +
22260 + DWC_MODIFY_REG32(&core_if->core_global_regs->glpmcfg,
22261 + 0, lpmcfg.d32);
22262 +
22263 + }
22264 +#endif
22265 + if (core_if->core_params->ic_usb_cap) {
22266 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
22267 + gusbcfg.b.ic_usb_cap = 1;
22268 + DWC_MODIFY_REG32(&core_if->core_global_regs->gusbcfg,
22269 + 0, gusbcfg.d32);
22270 + }
22271 + {
22272 + gotgctl_data_t gotgctl = {.d32 = 0 };
22273 + gotgctl.b.otgver = core_if->core_params->otg_ver;
22274 + DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl, 0,
22275 + gotgctl.d32);
22276 + /* Set OTG version supported */
22277 + core_if->otg_ver = core_if->core_params->otg_ver;
22278 + DWC_PRINTF("OTG VER PARAM: %d, OTG VER FLAG: %d\n",
22279 + core_if->core_params->otg_ver, core_if->otg_ver);
22280 + }
22281 +
22282 +
22283 + /* Enable common interrupts */
22284 + dwc_otg_enable_common_interrupts(core_if);
22285 +
22286 + /* Do device or host intialization based on mode during PCD
22287 + * and HCD initialization */
22288 + if (dwc_otg_is_host_mode(core_if)) {
22289 + DWC_DEBUGPL(DBG_ANY, "Host Mode\n");
22290 + core_if->op_state = A_HOST;
22291 + } else {
22292 + DWC_DEBUGPL(DBG_ANY, "Device Mode\n");
22293 + core_if->op_state = B_PERIPHERAL;
22294 +#ifdef DWC_DEVICE_ONLY
22295 + dwc_otg_core_dev_init(core_if);
22296 +#endif
22297 + }
22298 +}
22299 +
22300 +/**
22301 + * This function enables the Device mode interrupts.
22302 + *
22303 + * @param core_if Programming view of DWC_otg controller
22304 + */
22305 +void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * core_if)
22306 +{
22307 + gintmsk_data_t intr_mask = {.d32 = 0 };
22308 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22309 +
22310 + DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
22311 +
22312 + /* Disable all interrupts. */
22313 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
22314 +
22315 + /* Clear any pending interrupts */
22316 + DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
22317 +
22318 + /* Enable the common interrupts */
22319 + dwc_otg_enable_common_interrupts(core_if);
22320 +
22321 + /* Enable interrupts */
22322 + intr_mask.b.usbreset = 1;
22323 + intr_mask.b.enumdone = 1;
22324 + /* Disable Disconnect interrupt in Device mode */
22325 + intr_mask.b.disconnect = 0;
22326 +
22327 + if (!core_if->multiproc_int_enable) {
22328 + intr_mask.b.inepintr = 1;
22329 + intr_mask.b.outepintr = 1;
22330 + }
22331 +
22332 + intr_mask.b.erlysuspend = 1;
22333 +
22334 + if (core_if->en_multiple_tx_fifo == 0) {
22335 + intr_mask.b.epmismatch = 1;
22336 + }
22337 +
22338 + //intr_mask.b.incomplisoout = 1;
22339 + intr_mask.b.incomplisoin = 1;
22340 +
22341 +/* Enable the ignore frame number for ISOC xfers - MAS */
22342 +/* Disable to support high bandwith ISOC transfers - manukz */
22343 +#if 0
22344 +#ifdef DWC_UTE_PER_IO
22345 + if (core_if->dma_enable) {
22346 + if (core_if->dma_desc_enable) {
22347 + dctl_data_t dctl1 = {.d32 = 0 };
22348 + dctl1.b.ifrmnum = 1;
22349 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
22350 + dctl, 0, dctl1.d32);
22351 + DWC_DEBUG("----Enabled Ignore frame number (0x%08x)",
22352 + DWC_READ_REG32(&core_if->dev_if->
22353 + dev_global_regs->dctl));
22354 + }
22355 + }
22356 +#endif
22357 +#endif
22358 +#ifdef DWC_EN_ISOC
22359 + if (core_if->dma_enable) {
22360 + if (core_if->dma_desc_enable == 0) {
22361 + if (core_if->pti_enh_enable) {
22362 + dctl_data_t dctl = {.d32 = 0 };
22363 + dctl.b.ifrmnum = 1;
22364 + DWC_MODIFY_REG32(&core_if->
22365 + dev_if->dev_global_regs->dctl,
22366 + 0, dctl.d32);
22367 + } else {
22368 + intr_mask.b.incomplisoin = 1;
22369 + intr_mask.b.incomplisoout = 1;
22370 + }
22371 + }
22372 + } else {
22373 + intr_mask.b.incomplisoin = 1;
22374 + intr_mask.b.incomplisoout = 1;
22375 + }
22376 +#endif /* DWC_EN_ISOC */
22377 +
22378 + /** @todo NGS: Should this be a module parameter? */
22379 +#ifdef USE_PERIODIC_EP
22380 + intr_mask.b.isooutdrop = 1;
22381 + intr_mask.b.eopframe = 1;
22382 + intr_mask.b.incomplisoin = 1;
22383 + intr_mask.b.incomplisoout = 1;
22384 +#endif
22385 +
22386 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
22387 +
22388 + DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__,
22389 + DWC_READ_REG32(&global_regs->gintmsk));
22390 +}
22391 +
22392 +/**
22393 + * This function initializes the DWC_otg controller registers for
22394 + * device mode.
22395 + *
22396 + * @param core_if Programming view of DWC_otg controller
22397 + *
22398 + */
22399 +void dwc_otg_core_dev_init(dwc_otg_core_if_t * core_if)
22400 +{
22401 + int i;
22402 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22403 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
22404 + dwc_otg_core_params_t *params = core_if->core_params;
22405 + dcfg_data_t dcfg = {.d32 = 0 };
22406 + depctl_data_t diepctl = {.d32 = 0 };
22407 + grstctl_t resetctl = {.d32 = 0 };
22408 + uint32_t rx_fifo_size;
22409 + fifosize_data_t nptxfifosize;
22410 + fifosize_data_t txfifosize;
22411 + dthrctl_data_t dthrctl;
22412 + fifosize_data_t ptxfifosize;
22413 + uint16_t rxfsiz, nptxfsiz;
22414 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
22415 + hwcfg3_data_t hwcfg3 = {.d32 = 0 };
22416 +
22417 + /* Restart the Phy Clock */
22418 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
22419 +
22420 + /* Device configuration register */
22421 + init_devspd(core_if);
22422 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
22423 + dcfg.b.descdma = (core_if->dma_desc_enable) ? 1 : 0;
22424 + dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80;
22425 + /* Enable Device OUT NAK in case of DDMA mode*/
22426 + if (core_if->core_params->dev_out_nak) {
22427 + dcfg.b.endevoutnak = 1;
22428 + }
22429 +
22430 + if (core_if->core_params->cont_on_bna) {
22431 + dctl_data_t dctl = {.d32 = 0 };
22432 + dctl.b.encontonbna = 1;
22433 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
22434 + }
22435 +
22436 +
22437 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
22438 +
22439 + /* Configure data FIFO sizes */
22440 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
22441 + DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
22442 + core_if->total_fifo_size);
22443 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
22444 + params->dev_rx_fifo_size);
22445 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
22446 + params->dev_nperio_tx_fifo_size);
22447 +
22448 + /* Rx FIFO */
22449 + DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
22450 + DWC_READ_REG32(&global_regs->grxfsiz));
22451 +
22452 +#ifdef DWC_UTE_CFI
22453 + core_if->pwron_rxfsiz = DWC_READ_REG32(&global_regs->grxfsiz);
22454 + core_if->init_rxfsiz = params->dev_rx_fifo_size;
22455 +#endif
22456 + rx_fifo_size = params->dev_rx_fifo_size;
22457 + DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
22458 +
22459 + DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
22460 + DWC_READ_REG32(&global_regs->grxfsiz));
22461 +
22462 + /** Set Periodic Tx FIFO Mask all bits 0 */
22463 + core_if->p_tx_msk = 0;
22464 +
22465 + /** Set Tx FIFO Mask all bits 0 */
22466 + core_if->tx_msk = 0;
22467 +
22468 + if (core_if->en_multiple_tx_fifo == 0) {
22469 + /* Non-periodic Tx FIFO */
22470 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
22471 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22472 +
22473 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
22474 + nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
22475 +
22476 + DWC_WRITE_REG32(&global_regs->gnptxfsiz,
22477 + nptxfifosize.d32);
22478 +
22479 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
22480 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22481 +
22482 + /**@todo NGS: Fix Periodic FIFO Sizing! */
22483 + /*
22484 + * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15.
22485 + * Indexes of the FIFO size module parameters in the
22486 + * dev_perio_tx_fifo_size array and the FIFO size registers in
22487 + * the dptxfsiz array run from 0 to 14.
22488 + */
22489 + /** @todo Finish debug of this */
22490 + ptxfifosize.b.startaddr =
22491 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
22492 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
22493 + ptxfifosize.b.depth =
22494 + params->dev_perio_tx_fifo_size[i];
22495 + DWC_DEBUGPL(DBG_CIL,
22496 + "initial dtxfsiz[%d]=%08x\n", i,
22497 + DWC_READ_REG32(&global_regs->dtxfsiz
22498 + [i]));
22499 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
22500 + ptxfifosize.d32);
22501 + DWC_DEBUGPL(DBG_CIL, "new dtxfsiz[%d]=%08x\n",
22502 + i,
22503 + DWC_READ_REG32(&global_regs->dtxfsiz
22504 + [i]));
22505 + ptxfifosize.b.startaddr += ptxfifosize.b.depth;
22506 + }
22507 + } else {
22508 + /*
22509 + * Tx FIFOs These FIFOs are numbered from 1 to 15.
22510 + * Indexes of the FIFO size module parameters in the
22511 + * dev_tx_fifo_size array and the FIFO size registers in
22512 + * the dtxfsiz array run from 0 to 14.
22513 + */
22514 +
22515 + /* Non-periodic Tx FIFO */
22516 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
22517 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22518 +
22519 +#ifdef DWC_UTE_CFI
22520 + core_if->pwron_gnptxfsiz =
22521 + (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
22522 + core_if->init_gnptxfsiz =
22523 + params->dev_nperio_tx_fifo_size;
22524 +#endif
22525 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
22526 + nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
22527 +
22528 + DWC_WRITE_REG32(&global_regs->gnptxfsiz,
22529 + nptxfifosize.d32);
22530 +
22531 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
22532 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22533 +
22534 + txfifosize.b.startaddr =
22535 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
22536 +
22537 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
22538 +
22539 + txfifosize.b.depth =
22540 + params->dev_tx_fifo_size[i];
22541 +
22542 + DWC_DEBUGPL(DBG_CIL,
22543 + "initial dtxfsiz[%d]=%08x\n",
22544 + i,
22545 + DWC_READ_REG32(&global_regs->dtxfsiz
22546 + [i]));
22547 +
22548 +#ifdef DWC_UTE_CFI
22549 + core_if->pwron_txfsiz[i] =
22550 + (DWC_READ_REG32
22551 + (&global_regs->dtxfsiz[i]) >> 16);
22552 + core_if->init_txfsiz[i] =
22553 + params->dev_tx_fifo_size[i];
22554 +#endif
22555 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
22556 + txfifosize.d32);
22557 +
22558 + DWC_DEBUGPL(DBG_CIL,
22559 + "new dtxfsiz[%d]=%08x\n",
22560 + i,
22561 + DWC_READ_REG32(&global_regs->dtxfsiz
22562 + [i]));
22563 +
22564 + txfifosize.b.startaddr += txfifosize.b.depth;
22565 + }
22566 + if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
22567 + /* Calculating DFIFOCFG for Device mode to include RxFIFO and NPTXFIFO */
22568 + gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
22569 + hwcfg3.d32 = DWC_READ_REG32(&global_regs->ghwcfg3);
22570 + gdfifocfg.b.gdfifocfg = (DWC_READ_REG32(&global_regs->ghwcfg3) >> 16);
22571 + DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
22572 + rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
22573 + nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
22574 + gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz;
22575 + DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
22576 + }
22577 + }
22578 +
22579 + /* Flush the FIFOs */
22580 + dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */
22581 + dwc_otg_flush_rx_fifo(core_if);
22582 +
22583 + /* Flush the Learning Queue. */
22584 + resetctl.b.intknqflsh = 1;
22585 + DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
22586 +
22587 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
22588 + core_if->start_predict = 0;
22589 + for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) {
22590 + core_if->nextep_seq[i] = 0xff; // 0xff - EP not active
22591 + }
22592 + core_if->nextep_seq[0] = 0;
22593 + core_if->first_in_nextep_seq = 0;
22594 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
22595 + diepctl.b.nextep = 0;
22596 + DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
22597 +
22598 + /* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
22599 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
22600 + dcfg.b.epmscnt = 2;
22601 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
22602 +
22603 + DWC_DEBUGPL(DBG_CILV,"%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
22604 + __func__, core_if->first_in_nextep_seq);
22605 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
22606 + DWC_DEBUGPL(DBG_CILV, "%2d ", core_if->nextep_seq[i]);
22607 + }
22608 + DWC_DEBUGPL(DBG_CILV,"\n");
22609 + }
22610 +
22611 + /* Clear all pending Device Interrupts */
22612 + /** @todo - if the condition needed to be checked
22613 + * or in any case all pending interrutps should be cleared?
22614 + */
22615 + if (core_if->multiproc_int_enable) {
22616 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
22617 + DWC_WRITE_REG32(&dev_if->
22618 + dev_global_regs->diepeachintmsk[i], 0);
22619 + }
22620 + }
22621 +
22622 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
22623 + DWC_WRITE_REG32(&dev_if->
22624 + dev_global_regs->doepeachintmsk[i], 0);
22625 + }
22626 +
22627 + DWC_WRITE_REG32(&dev_if->dev_global_regs->deachint, 0xFFFFFFFF);
22628 + DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk, 0);
22629 + } else {
22630 + DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, 0);
22631 + DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, 0);
22632 + DWC_WRITE_REG32(&dev_if->dev_global_regs->daint, 0xFFFFFFFF);
22633 + DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk, 0);
22634 + }
22635 +
22636 + for (i = 0; i <= dev_if->num_in_eps; i++) {
22637 + depctl_data_t depctl;
22638 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
22639 + if (depctl.b.epena) {
22640 + depctl.d32 = 0;
22641 + depctl.b.epdis = 1;
22642 + depctl.b.snak = 1;
22643 + } else {
22644 + depctl.d32 = 0;
22645 + }
22646 +
22647 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
22648 +
22649 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, 0);
22650 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, 0);
22651 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepint, 0xFF);
22652 + }
22653 +
22654 + for (i = 0; i <= dev_if->num_out_eps; i++) {
22655 + depctl_data_t depctl;
22656 + depctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
22657 + if (depctl.b.epena) {
22658 + dctl_data_t dctl = {.d32 = 0 };
22659 + gintmsk_data_t gintsts = {.d32 = 0 };
22660 + doepint_data_t doepint = {.d32 = 0 };
22661 + dctl.b.sgoutnak = 1;
22662 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
22663 + do {
22664 + dwc_udelay(10);
22665 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
22666 + } while (!gintsts.b.goutnakeff);
22667 + gintsts.d32 = 0;
22668 + gintsts.b.goutnakeff = 1;
22669 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
22670 +
22671 + depctl.d32 = 0;
22672 + depctl.b.epdis = 1;
22673 + depctl.b.snak = 1;
22674 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepctl, depctl.d32);
22675 + do {
22676 + dwc_udelay(10);
22677 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
22678 + out_ep_regs[i]->doepint);
22679 + } while (!doepint.b.epdisabled);
22680 +
22681 + doepint.b.epdisabled = 1;
22682 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepint, doepint.d32);
22683 +
22684 + dctl.d32 = 0;
22685 + dctl.b.cgoutnak = 1;
22686 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
22687 + } else {
22688 + depctl.d32 = 0;
22689 + }
22690 +
22691 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, depctl.d32);
22692 +
22693 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doeptsiz, 0);
22694 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepdma, 0);
22695 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepint, 0xFF);
22696 + }
22697 +
22698 + if (core_if->en_multiple_tx_fifo && core_if->dma_enable) {
22699 + dev_if->non_iso_tx_thr_en = params->thr_ctl & 0x1;
22700 + dev_if->iso_tx_thr_en = (params->thr_ctl >> 1) & 0x1;
22701 + dev_if->rx_thr_en = (params->thr_ctl >> 2) & 0x1;
22702 +
22703 + dev_if->rx_thr_length = params->rx_thr_length;
22704 + dev_if->tx_thr_length = params->tx_thr_length;
22705 +
22706 + dev_if->setup_desc_index = 0;
22707 +
22708 + dthrctl.d32 = 0;
22709 + dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en;
22710 + dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en;
22711 + dthrctl.b.tx_thr_len = dev_if->tx_thr_length;
22712 + dthrctl.b.rx_thr_en = dev_if->rx_thr_en;
22713 + dthrctl.b.rx_thr_len = dev_if->rx_thr_length;
22714 + dthrctl.b.ahb_thr_ratio = params->ahb_thr_ratio;
22715 +
22716 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dtknqr3_dthrctl,
22717 + dthrctl.d32);
22718 +
22719 + DWC_DEBUGPL(DBG_CIL,
22720 + "Non ISO Tx Thr - %d\nISO Tx Thr - %d\nRx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n",
22721 + dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en,
22722 + dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len,
22723 + dthrctl.b.rx_thr_len);
22724 +
22725 + }
22726 +
22727 + dwc_otg_enable_device_interrupts(core_if);
22728 +
22729 + {
22730 + diepmsk_data_t msk = {.d32 = 0 };
22731 + msk.b.txfifoundrn = 1;
22732 + if (core_if->multiproc_int_enable) {
22733 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->
22734 + diepeachintmsk[0], msk.d32, msk.d32);
22735 + } else {
22736 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk,
22737 + msk.d32, msk.d32);
22738 + }
22739 + }
22740 +
22741 + if (core_if->multiproc_int_enable) {
22742 + /* Set NAK on Babble */
22743 + dctl_data_t dctl = {.d32 = 0 };
22744 + dctl.b.nakonbble = 1;
22745 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
22746 + }
22747 +
22748 + if (core_if->snpsid >= OTG_CORE_REV_2_94a) {
22749 + dctl_data_t dctl = {.d32 = 0 };
22750 + dctl.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
22751 + dctl.b.sftdiscon = 0;
22752 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl, dctl.d32);
22753 + }
22754 +}
22755 +
22756 +/**
22757 + * This function enables the Host mode interrupts.
22758 + *
22759 + * @param core_if Programming view of DWC_otg controller
22760 + */
22761 +void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * core_if)
22762 +{
22763 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22764 + gintmsk_data_t intr_mask = {.d32 = 0 };
22765 +
22766 + DWC_DEBUGPL(DBG_CIL, "%s(%p)\n", __func__, core_if);
22767 +
22768 + /* Disable all interrupts. */
22769 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
22770 +
22771 + /* Clear any pending interrupts. */
22772 + DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
22773 +
22774 + /* Enable the common interrupts */
22775 + dwc_otg_enable_common_interrupts(core_if);
22776 +
22777 + /*
22778 + * Enable host mode interrupts without disturbing common
22779 + * interrupts.
22780 + */
22781 +
22782 + intr_mask.b.disconnect = 1;
22783 + intr_mask.b.portintr = 1;
22784 + intr_mask.b.hcintr = 1;
22785 +
22786 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
22787 +}
22788 +
22789 +/**
22790 + * This function disables the Host Mode interrupts.
22791 + *
22792 + * @param core_if Programming view of DWC_otg controller
22793 + */
22794 +void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * core_if)
22795 +{
22796 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22797 + gintmsk_data_t intr_mask = {.d32 = 0 };
22798 +
22799 + DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__);
22800 +
22801 + /*
22802 + * Disable host mode interrupts without disturbing common
22803 + * interrupts.
22804 + */
22805 + intr_mask.b.sofintr = 1;
22806 + intr_mask.b.portintr = 1;
22807 + intr_mask.b.hcintr = 1;
22808 + intr_mask.b.ptxfempty = 1;
22809 + intr_mask.b.nptxfempty = 1;
22810 +
22811 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, 0);
22812 +}
22813 +
22814 +/**
22815 + * This function initializes the DWC_otg controller registers for
22816 + * host mode.
22817 + *
22818 + * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
22819 + * request queues. Host channels are reset to ensure that they are ready for
22820 + * performing transfers.
22821 + *
22822 + * @param core_if Programming view of DWC_otg controller
22823 + *
22824 + */
22825 +void dwc_otg_core_host_init(dwc_otg_core_if_t * core_if)
22826 +{
22827 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22828 + dwc_otg_host_if_t *host_if = core_if->host_if;
22829 + dwc_otg_core_params_t *params = core_if->core_params;
22830 + hprt0_data_t hprt0 = {.d32 = 0 };
22831 + fifosize_data_t nptxfifosize;
22832 + fifosize_data_t ptxfifosize;
22833 + uint16_t rxfsiz, nptxfsiz, hptxfsiz;
22834 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
22835 + int i;
22836 + hcchar_data_t hcchar;
22837 + hcfg_data_t hcfg;
22838 + hfir_data_t hfir;
22839 + dwc_otg_hc_regs_t *hc_regs;
22840 + int num_channels;
22841 + gotgctl_data_t gotgctl = {.d32 = 0 };
22842 +
22843 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
22844 +
22845 + /* Restart the Phy Clock */
22846 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
22847 +
22848 + /* Initialize Host Configuration Register */
22849 + init_fslspclksel(core_if);
22850 + if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
22851 + hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
22852 + hcfg.b.fslssupp = 1;
22853 + DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
22854 +
22855 + }
22856 +
22857 + /* This bit allows dynamic reloading of the HFIR register
22858 + * during runtime. This bit needs to be programmed during
22859 + * initial configuration and its value must not be changed
22860 + * during runtime.*/
22861 + if (core_if->core_params->reload_ctl == 1) {
22862 + hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
22863 + hfir.b.hfirrldctrl = 1;
22864 + DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
22865 + }
22866 +
22867 + if (core_if->core_params->dma_desc_enable) {
22868 + uint8_t op_mode = core_if->hwcfg2.b.op_mode;
22869 + if (!
22870 + (core_if->hwcfg4.b.desc_dma
22871 + && (core_if->snpsid >= OTG_CORE_REV_2_90a)
22872 + && ((op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
22873 + || (op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
22874 + || (op_mode ==
22875 + DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG)
22876 + || (op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)
22877 + || (op_mode ==
22878 + DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST)))) {
22879 +
22880 + DWC_ERROR("Host can't operate in Descriptor DMA mode.\n"
22881 + "Either core version is below 2.90a or "
22882 + "GHWCFG2, GHWCFG4 registers' values do not allow Descriptor DMA in host mode.\n"
22883 + "To run the driver in Buffer DMA host mode set dma_desc_enable "
22884 + "module parameter to 0.\n");
22885 + return;
22886 + }
22887 + hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
22888 + hcfg.b.descdma = 1;
22889 + DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
22890 + }
22891 +
22892 + /* Configure data FIFO sizes */
22893 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
22894 + DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
22895 + core_if->total_fifo_size);
22896 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
22897 + params->host_rx_fifo_size);
22898 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
22899 + params->host_nperio_tx_fifo_size);
22900 + DWC_DEBUGPL(DBG_CIL, "P Tx FIFO Size=%d\n",
22901 + params->host_perio_tx_fifo_size);
22902 +
22903 + /* Rx FIFO */
22904 + DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
22905 + DWC_READ_REG32(&global_regs->grxfsiz));
22906 + DWC_WRITE_REG32(&global_regs->grxfsiz,
22907 + params->host_rx_fifo_size);
22908 + DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
22909 + DWC_READ_REG32(&global_regs->grxfsiz));
22910 +
22911 + /* Non-periodic Tx FIFO */
22912 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
22913 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22914 + nptxfifosize.b.depth = params->host_nperio_tx_fifo_size;
22915 + nptxfifosize.b.startaddr = params->host_rx_fifo_size;
22916 + DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
22917 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
22918 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22919 +
22920 + /* Periodic Tx FIFO */
22921 + DWC_DEBUGPL(DBG_CIL, "initial hptxfsiz=%08x\n",
22922 + DWC_READ_REG32(&global_regs->hptxfsiz));
22923 + ptxfifosize.b.depth = params->host_perio_tx_fifo_size;
22924 + ptxfifosize.b.startaddr =
22925 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
22926 + DWC_WRITE_REG32(&global_regs->hptxfsiz, ptxfifosize.d32);
22927 + DWC_DEBUGPL(DBG_CIL, "new hptxfsiz=%08x\n",
22928 + DWC_READ_REG32(&global_regs->hptxfsiz));
22929 +
22930 + if (core_if->en_multiple_tx_fifo
22931 + && core_if->snpsid <= OTG_CORE_REV_2_94a) {
22932 + /* Global DFIFOCFG calculation for Host mode - include RxFIFO, NPTXFIFO and HPTXFIFO */
22933 + gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
22934 + rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
22935 + nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
22936 + hptxfsiz = (DWC_READ_REG32(&global_regs->hptxfsiz) >> 16);
22937 + gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz + hptxfsiz;
22938 + DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
22939 + }
22940 + }
22941 +
22942 + /* TODO - check this */
22943 + /* Clear Host Set HNP Enable in the OTG Control Register */
22944 + gotgctl.b.hstsethnpen = 1;
22945 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
22946 + /* Make sure the FIFOs are flushed. */
22947 + dwc_otg_flush_tx_fifo(core_if, 0x10 /* all TX FIFOs */ );
22948 + dwc_otg_flush_rx_fifo(core_if);
22949 +
22950 + /* Clear Host Set HNP Enable in the OTG Control Register */
22951 + gotgctl.b.hstsethnpen = 1;
22952 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
22953 +
22954 + if (!core_if->core_params->dma_desc_enable) {
22955 + /* Flush out any leftover queued requests. */
22956 + num_channels = core_if->core_params->host_channels;
22957 +
22958 + for (i = 0; i < num_channels; i++) {
22959 + hc_regs = core_if->host_if->hc_regs[i];
22960 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
22961 + hcchar.b.chen = 0;
22962 + hcchar.b.chdis = 1;
22963 + hcchar.b.epdir = 0;
22964 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
22965 + }
22966 +
22967 + /* Halt all channels to put them into a known state. */
22968 + for (i = 0; i < num_channels; i++) {
22969 + int count = 0;
22970 + hc_regs = core_if->host_if->hc_regs[i];
22971 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
22972 + hcchar.b.chen = 1;
22973 + hcchar.b.chdis = 1;
22974 + hcchar.b.epdir = 0;
22975 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
22976 + DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d regs %p\n", __func__, i, hc_regs);
22977 + do {
22978 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
22979 + if (++count > 1000) {
22980 + DWC_ERROR
22981 + ("%s: Unable to clear halt on channel %d (timeout HCCHAR 0x%X @%p)\n",
22982 + __func__, i, hcchar.d32, &hc_regs->hcchar);
22983 + break;
22984 + }
22985 + dwc_udelay(1);
22986 + } while (hcchar.b.chen);
22987 + }
22988 + }
22989 +
22990 + /* Turn on the vbus power. */
22991 + DWC_PRINTF("Init: Port Power? op_state=%d\n", core_if->op_state);
22992 + if (core_if->op_state == A_HOST) {
22993 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
22994 + DWC_PRINTF("Init: Power Port (%d)\n", hprt0.b.prtpwr);
22995 + if (hprt0.b.prtpwr == 0) {
22996 + hprt0.b.prtpwr = 1;
22997 + DWC_WRITE_REG32(host_if->hprt0, hprt0.d32);
22998 + }
22999 + }
23000 +
23001 + dwc_otg_enable_host_interrupts(core_if);
23002 +}
23003 +
23004 +/**
23005 + * Prepares a host channel for transferring packets to/from a specific
23006 + * endpoint. The HCCHARn register is set up with the characteristics specified
23007 + * in _hc. Host channel interrupts that may need to be serviced while this
23008 + * transfer is in progress are enabled.
23009 + *
23010 + * @param core_if Programming view of DWC_otg controller
23011 + * @param hc Information needed to initialize the host channel
23012 + */
23013 +void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23014 +{
23015 + uint32_t intr_enable;
23016 + hcintmsk_data_t hc_intr_mask;
23017 + gintmsk_data_t gintmsk = {.d32 = 0 };
23018 + hcchar_data_t hcchar;
23019 + hcsplt_data_t hcsplt;
23020 +
23021 + uint8_t hc_num = hc->hc_num;
23022 + dwc_otg_host_if_t *host_if = core_if->host_if;
23023 + dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num];
23024 +
23025 + /* Clear old interrupt conditions for this host channel. */
23026 + hc_intr_mask.d32 = 0xFFFFFFFF;
23027 + hc_intr_mask.b.reserved14_31 = 0;
23028 + DWC_WRITE_REG32(&hc_regs->hcint, hc_intr_mask.d32);
23029 +
23030 + /* Enable channel interrupts required for this transfer. */
23031 + hc_intr_mask.d32 = 0;
23032 + hc_intr_mask.b.chhltd = 1;
23033 + if (core_if->dma_enable) {
23034 + /* For Descriptor DMA mode core halts the channel on AHB error. Interrupt is not required */
23035 + if (!core_if->dma_desc_enable)
23036 + hc_intr_mask.b.ahberr = 1;
23037 + else {
23038 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
23039 + hc_intr_mask.b.xfercompl = 1;
23040 + }
23041 +
23042 + if (hc->error_state && !hc->do_split &&
23043 + hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
23044 + hc_intr_mask.b.ack = 1;
23045 + if (hc->ep_is_in) {
23046 + hc_intr_mask.b.datatglerr = 1;
23047 + if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
23048 + hc_intr_mask.b.nak = 1;
23049 + }
23050 + }
23051 + }
23052 + } else {
23053 + switch (hc->ep_type) {
23054 + case DWC_OTG_EP_TYPE_CONTROL:
23055 + case DWC_OTG_EP_TYPE_BULK:
23056 + hc_intr_mask.b.xfercompl = 1;
23057 + hc_intr_mask.b.stall = 1;
23058 + hc_intr_mask.b.xacterr = 1;
23059 + hc_intr_mask.b.datatglerr = 1;
23060 + if (hc->ep_is_in) {
23061 + hc_intr_mask.b.bblerr = 1;
23062 + } else {
23063 + hc_intr_mask.b.nak = 1;
23064 + hc_intr_mask.b.nyet = 1;
23065 + if (hc->do_ping) {
23066 + hc_intr_mask.b.ack = 1;
23067 + }
23068 + }
23069 +
23070 + if (hc->do_split) {
23071 + hc_intr_mask.b.nak = 1;
23072 + if (hc->complete_split) {
23073 + hc_intr_mask.b.nyet = 1;
23074 + } else {
23075 + hc_intr_mask.b.ack = 1;
23076 + }
23077 + }
23078 +
23079 + if (hc->error_state) {
23080 + hc_intr_mask.b.ack = 1;
23081 + }
23082 + break;
23083 + case DWC_OTG_EP_TYPE_INTR:
23084 + hc_intr_mask.b.xfercompl = 1;
23085 + hc_intr_mask.b.nak = 1;
23086 + hc_intr_mask.b.stall = 1;
23087 + hc_intr_mask.b.xacterr = 1;
23088 + hc_intr_mask.b.datatglerr = 1;
23089 + hc_intr_mask.b.frmovrun = 1;
23090 +
23091 + if (hc->ep_is_in) {
23092 + hc_intr_mask.b.bblerr = 1;
23093 + }
23094 + if (hc->error_state) {
23095 + hc_intr_mask.b.ack = 1;
23096 + }
23097 + if (hc->do_split) {
23098 + if (hc->complete_split) {
23099 + hc_intr_mask.b.nyet = 1;
23100 + } else {
23101 + hc_intr_mask.b.ack = 1;
23102 + }
23103 + }
23104 + break;
23105 + case DWC_OTG_EP_TYPE_ISOC:
23106 + hc_intr_mask.b.xfercompl = 1;
23107 + hc_intr_mask.b.frmovrun = 1;
23108 + hc_intr_mask.b.ack = 1;
23109 +
23110 + if (hc->ep_is_in) {
23111 + hc_intr_mask.b.xacterr = 1;
23112 + hc_intr_mask.b.bblerr = 1;
23113 + }
23114 + break;
23115 + }
23116 + }
23117 + DWC_WRITE_REG32(&hc_regs->hcintmsk, hc_intr_mask.d32);
23118 +
23119 + /* Enable the top level host channel interrupt. */
23120 + intr_enable = (1 << hc_num);
23121 + DWC_MODIFY_REG32(&host_if->host_global_regs->haintmsk, 0, intr_enable);
23122 +
23123 + /* Make sure host channel interrupts are enabled. */
23124 + gintmsk.b.hcintr = 1;
23125 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
23126 +
23127 + /*
23128 + * Program the HCCHARn register with the endpoint characteristics for
23129 + * the current transfer.
23130 + */
23131 + hcchar.d32 = 0;
23132 + hcchar.b.devaddr = hc->dev_addr;
23133 + hcchar.b.epnum = hc->ep_num;
23134 + hcchar.b.epdir = hc->ep_is_in;
23135 + hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
23136 + hcchar.b.eptype = hc->ep_type;
23137 + hcchar.b.mps = hc->max_packet;
23138 +
23139 + DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32);
23140 +
23141 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d, Dev Addr %d, EP #%d\n",
23142 + __func__, hc->hc_num, hcchar.b.devaddr, hcchar.b.epnum);
23143 + DWC_DEBUGPL(DBG_HCDV, " Is In %d, Is Low Speed %d, EP Type %d, "
23144 + "Max Pkt %d, Multi Cnt %d\n",
23145 + hcchar.b.epdir, hcchar.b.lspddev, hcchar.b.eptype,
23146 + hcchar.b.mps, hcchar.b.multicnt);
23147 +
23148 + /*
23149 + * Program the HCSPLIT register for SPLITs
23150 + */
23151 + hcsplt.d32 = 0;
23152 + if (hc->do_split) {
23153 + DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n",
23154 + hc->hc_num,
23155 + hc->complete_split ? "CSPLIT" : "SSPLIT");
23156 + hcsplt.b.compsplt = hc->complete_split;
23157 + hcsplt.b.xactpos = hc->xact_pos;
23158 + hcsplt.b.hubaddr = hc->hub_addr;
23159 + hcsplt.b.prtaddr = hc->port_addr;
23160 + DWC_DEBUGPL(DBG_HCDV, "\t comp split %d\n", hc->complete_split);
23161 + DWC_DEBUGPL(DBG_HCDV, "\t xact pos %d\n", hc->xact_pos);
23162 + DWC_DEBUGPL(DBG_HCDV, "\t hub addr %d\n", hc->hub_addr);
23163 + DWC_DEBUGPL(DBG_HCDV, "\t port addr %d\n", hc->port_addr);
23164 + DWC_DEBUGPL(DBG_HCDV, "\t is_in %d\n", hc->ep_is_in);
23165 + DWC_DEBUGPL(DBG_HCDV, "\t Max Pkt: %d\n", hcchar.b.mps);
23166 + DWC_DEBUGPL(DBG_HCDV, "\t xferlen: %d\n", hc->xfer_len);
23167 + }
23168 + DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32);
23169 +
23170 +}
23171 +
23172 +/**
23173 + * Attempts to halt a host channel. This function should only be called in
23174 + * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under
23175 + * normal circumstances in DMA mode, the controller halts the channel when the
23176 + * transfer is complete or a condition occurs that requires application
23177 + * intervention.
23178 + *
23179 + * In slave mode, checks for a free request queue entry, then sets the Channel
23180 + * Enable and Channel Disable bits of the Host Channel Characteristics
23181 + * register of the specified channel to intiate the halt. If there is no free
23182 + * request queue entry, sets only the Channel Disable bit of the HCCHARn
23183 + * register to flush requests for this channel. In the latter case, sets a
23184 + * flag to indicate that the host channel needs to be halted when a request
23185 + * queue slot is open.
23186 + *
23187 + * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
23188 + * HCCHARn register. The controller ensures there is space in the request
23189 + * queue before submitting the halt request.
23190 + *
23191 + * Some time may elapse before the core flushes any posted requests for this
23192 + * host channel and halts. The Channel Halted interrupt handler completes the
23193 + * deactivation of the host channel.
23194 + *
23195 + * @param core_if Controller register interface.
23196 + * @param hc Host channel to halt.
23197 + * @param halt_status Reason for halting the channel.
23198 + */
23199 +void dwc_otg_hc_halt(dwc_otg_core_if_t * core_if,
23200 + dwc_hc_t * hc, dwc_otg_halt_status_e halt_status)
23201 +{
23202 + gnptxsts_data_t nptxsts;
23203 + hptxsts_data_t hptxsts;
23204 + hcchar_data_t hcchar;
23205 + dwc_otg_hc_regs_t *hc_regs;
23206 + dwc_otg_core_global_regs_t *global_regs;
23207 + dwc_otg_host_global_regs_t *host_global_regs;
23208 +
23209 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23210 + global_regs = core_if->core_global_regs;
23211 + host_global_regs = core_if->host_if->host_global_regs;
23212 +
23213 + DWC_ASSERT(!(halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS),
23214 + "halt_status = %d\n", halt_status);
23215 +
23216 + if (halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
23217 + halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
23218 + /*
23219 + * Disable all channel interrupts except Ch Halted. The QTD
23220 + * and QH state associated with this transfer has been cleared
23221 + * (in the case of URB_DEQUEUE), so the channel needs to be
23222 + * shut down carefully to prevent crashes.
23223 + */
23224 + hcintmsk_data_t hcintmsk;
23225 + hcintmsk.d32 = 0;
23226 + hcintmsk.b.chhltd = 1;
23227 + DWC_WRITE_REG32(&hc_regs->hcintmsk, hcintmsk.d32);
23228 +
23229 + /*
23230 + * Make sure no other interrupts besides halt are currently
23231 + * pending. Handling another interrupt could cause a crash due
23232 + * to the QTD and QH state.
23233 + */
23234 + DWC_WRITE_REG32(&hc_regs->hcint, ~hcintmsk.d32);
23235 +
23236 + /*
23237 + * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
23238 + * even if the channel was already halted for some other
23239 + * reason.
23240 + */
23241 + hc->halt_status = halt_status;
23242 +
23243 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23244 + if (hcchar.b.chen == 0) {
23245 + /*
23246 + * The channel is either already halted or it hasn't
23247 + * started yet. In DMA mode, the transfer may halt if
23248 + * it finishes normally or a condition occurs that
23249 + * requires driver intervention. Don't want to halt
23250 + * the channel again. In either Slave or DMA mode,
23251 + * it's possible that the transfer has been assigned
23252 + * to a channel, but not started yet when an URB is
23253 + * dequeued. Don't want to halt a channel that hasn't
23254 + * started yet.
23255 + */
23256 + return;
23257 + }
23258 + }
23259 + if (hc->halt_pending) {
23260 + /*
23261 + * A halt has already been issued for this channel. This might
23262 + * happen when a transfer is aborted by a higher level in
23263 + * the stack.
23264 + */
23265 +#ifdef DEBUG
23266 + DWC_PRINTF
23267 + ("*** %s: Channel %d, _hc->halt_pending already set ***\n",
23268 + __func__, hc->hc_num);
23269 +
23270 +#endif
23271 + return;
23272 + }
23273 +
23274 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23275 +
23276 + /* No need to set the bit in DDMA for disabling the channel */
23277 + //TODO check it everywhere channel is disabled
23278 + if (!core_if->core_params->dma_desc_enable)
23279 + hcchar.b.chen = 1;
23280 + hcchar.b.chdis = 1;
23281 +
23282 + if (!core_if->dma_enable) {
23283 + /* Check for space in the request queue to issue the halt. */
23284 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
23285 + hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
23286 + nptxsts.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
23287 + if (nptxsts.b.nptxqspcavail == 0) {
23288 + hcchar.b.chen = 0;
23289 + }
23290 + } else {
23291 + hptxsts.d32 =
23292 + DWC_READ_REG32(&host_global_regs->hptxsts);
23293 + if ((hptxsts.b.ptxqspcavail == 0)
23294 + || (core_if->queuing_high_bandwidth)) {
23295 + hcchar.b.chen = 0;
23296 + }
23297 + }
23298 + }
23299 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23300 +
23301 + hc->halt_status = halt_status;
23302 +
23303 + if (hcchar.b.chen) {
23304 + hc->halt_pending = 1;
23305 + hc->halt_on_queue = 0;
23306 + } else {
23307 + hc->halt_on_queue = 1;
23308 + }
23309 +
23310 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23311 + DWC_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n", hcchar.d32);
23312 + DWC_DEBUGPL(DBG_HCDV, " halt_pending: %d\n", hc->halt_pending);
23313 + DWC_DEBUGPL(DBG_HCDV, " halt_on_queue: %d\n", hc->halt_on_queue);
23314 + DWC_DEBUGPL(DBG_HCDV, " halt_status: %d\n", hc->halt_status);
23315 +
23316 + return;
23317 +}
23318 +
23319 +/**
23320 + * Clears the transfer state for a host channel. This function is normally
23321 + * called after a transfer is done and the host channel is being released.
23322 + *
23323 + * @param core_if Programming view of DWC_otg controller.
23324 + * @param hc Identifies the host channel to clean up.
23325 + */
23326 +void dwc_otg_hc_cleanup(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23327 +{
23328 + dwc_otg_hc_regs_t *hc_regs;
23329 +
23330 + hc->xfer_started = 0;
23331 +
23332 + /*
23333 + * Clear channel interrupt enables and any unhandled channel interrupt
23334 + * conditions.
23335 + */
23336 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23337 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0);
23338 + DWC_WRITE_REG32(&hc_regs->hcint, 0xFFFFFFFF);
23339 +#ifdef DEBUG
23340 + DWC_TIMER_CANCEL(core_if->hc_xfer_timer[hc->hc_num]);
23341 +#endif
23342 +}
23343 +
23344 +/**
23345 + * Sets the channel property that indicates in which frame a periodic transfer
23346 + * should occur. This is always set to the _next_ frame. This function has no
23347 + * effect on non-periodic transfers.
23348 + *
23349 + * @param core_if Programming view of DWC_otg controller.
23350 + * @param hc Identifies the host channel to set up and its properties.
23351 + * @param hcchar Current value of the HCCHAR register for the specified host
23352 + * channel.
23353 + */
23354 +static inline void hc_set_even_odd_frame(dwc_otg_core_if_t * core_if,
23355 + dwc_hc_t * hc, hcchar_data_t * hcchar)
23356 +{
23357 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23358 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23359 + hfnum_data_t hfnum;
23360 + hfnum.d32 =
23361 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hfnum);
23362 +
23363 + /* 1 if _next_ frame is odd, 0 if it's even */
23364 + hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1;
23365 +#ifdef DEBUG
23366 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR && hc->do_split
23367 + && !hc->complete_split) {
23368 + switch (hfnum.b.frnum & 0x7) {
23369 + case 7:
23370 + core_if->hfnum_7_samples++;
23371 + core_if->hfnum_7_frrem_accum += hfnum.b.frrem;
23372 + break;
23373 + case 0:
23374 + core_if->hfnum_0_samples++;
23375 + core_if->hfnum_0_frrem_accum += hfnum.b.frrem;
23376 + break;
23377 + default:
23378 + core_if->hfnum_other_samples++;
23379 + core_if->hfnum_other_frrem_accum +=
23380 + hfnum.b.frrem;
23381 + break;
23382 + }
23383 + }
23384 +#endif
23385 + }
23386 +}
23387 +
23388 +#ifdef DEBUG
23389 +void hc_xfer_timeout(void *ptr)
23390 +{
23391 + hc_xfer_info_t *xfer_info = NULL;
23392 + int hc_num = 0;
23393 +
23394 + if (ptr)
23395 + xfer_info = (hc_xfer_info_t *) ptr;
23396 +
23397 + if (!xfer_info->hc) {
23398 + DWC_ERROR("xfer_info->hc = %p\n", xfer_info->hc);
23399 + return;
23400 + }
23401 +
23402 + hc_num = xfer_info->hc->hc_num;
23403 + DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num);
23404 + DWC_WARN(" start_hcchar_val 0x%08x\n",
23405 + xfer_info->core_if->start_hcchar_val[hc_num]);
23406 +}
23407 +#endif
23408 +
23409 +void ep_xfer_timeout(void *ptr)
23410 +{
23411 + ep_xfer_info_t *xfer_info = NULL;
23412 + int ep_num = 0;
23413 + dctl_data_t dctl = {.d32 = 0 };
23414 + gintsts_data_t gintsts = {.d32 = 0 };
23415 + gintmsk_data_t gintmsk = {.d32 = 0 };
23416 +
23417 + if (ptr)
23418 + xfer_info = (ep_xfer_info_t *) ptr;
23419 +
23420 + if (!xfer_info->ep) {
23421 + DWC_ERROR("xfer_info->ep = %p\n", xfer_info->ep);
23422 + return;
23423 + }
23424 +
23425 + ep_num = xfer_info->ep->num;
23426 + DWC_WARN("%s: timeout on endpoit %d\n", __func__, ep_num);
23427 + /* Put the sate to 2 as it was time outed */
23428 + xfer_info->state = 2;
23429 +
23430 + dctl.d32 =
23431 + DWC_READ_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl);
23432 + gintsts.d32 =
23433 + DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintsts);
23434 + gintmsk.d32 =
23435 + DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintmsk);
23436 +
23437 + if (!gintmsk.b.goutnakeff) {
23438 + /* Unmask it */
23439 + gintmsk.b.goutnakeff = 1;
23440 + DWC_WRITE_REG32(&xfer_info->core_if->core_global_regs->gintmsk,
23441 + gintmsk.d32);
23442 +
23443 + }
23444 +
23445 + if (!gintsts.b.goutnakeff) {
23446 + dctl.b.sgoutnak = 1;
23447 + }
23448 + DWC_WRITE_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl,
23449 + dctl.d32);
23450 +
23451 +}
23452 +
23453 +void set_pid_isoc(dwc_hc_t * hc)
23454 +{
23455 + /* Set up the initial PID for the transfer. */
23456 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH) {
23457 + if (hc->ep_is_in) {
23458 + if (hc->multi_count == 1) {
23459 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
23460 + } else if (hc->multi_count == 2) {
23461 + hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
23462 + } else {
23463 + hc->data_pid_start = DWC_OTG_HC_PID_DATA2;
23464 + }
23465 + } else {
23466 + if (hc->multi_count == 1) {
23467 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
23468 + } else {
23469 + hc->data_pid_start = DWC_OTG_HC_PID_MDATA;
23470 + }
23471 + }
23472 + } else {
23473 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
23474 + }
23475 +}
23476 +
23477 +/**
23478 + * This function does the setup for a data transfer for a host channel and
23479 + * starts the transfer. May be called in either Slave mode or DMA mode. In
23480 + * Slave mode, the caller must ensure that there is sufficient space in the
23481 + * request queue and Tx Data FIFO.
23482 + *
23483 + * For an OUT transfer in Slave mode, it loads a data packet into the
23484 + * appropriate FIFO. If necessary, additional data packets will be loaded in
23485 + * the Host ISR.
23486 + *
23487 + * For an IN transfer in Slave mode, a data packet is requested. The data
23488 + * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
23489 + * additional data packets are requested in the Host ISR.
23490 + *
23491 + * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
23492 + * register along with a packet count of 1 and the channel is enabled. This
23493 + * causes a single PING transaction to occur. Other fields in HCTSIZ are
23494 + * simply set to 0 since no data transfer occurs in this case.
23495 + *
23496 + * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
23497 + * all the information required to perform the subsequent data transfer. In
23498 + * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
23499 + * controller performs the entire PING protocol, then starts the data
23500 + * transfer.
23501 + *
23502 + * @param core_if Programming view of DWC_otg controller.
23503 + * @param hc Information needed to initialize the host channel. The xfer_len
23504 + * value may be reduced to accommodate the max widths of the XferSize and
23505 + * PktCnt fields in the HCTSIZn register. The multi_count value may be changed
23506 + * to reflect the final xfer_len value.
23507 + */
23508 +void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23509 +{
23510 + hcchar_data_t hcchar;
23511 + hctsiz_data_t hctsiz;
23512 + uint16_t num_packets;
23513 + uint32_t max_hc_xfer_size = core_if->core_params->max_transfer_size;
23514 + uint16_t max_hc_pkt_count = core_if->core_params->max_packet_count;
23515 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23516 +
23517 + hctsiz.d32 = 0;
23518 +
23519 + if (hc->do_ping) {
23520 + if (!core_if->dma_enable) {
23521 + dwc_otg_hc_do_ping(core_if, hc);
23522 + hc->xfer_started = 1;
23523 + return;
23524 + } else {
23525 + hctsiz.b.dopng = 1;
23526 + }
23527 + }
23528 +
23529 + if (hc->do_split) {
23530 + num_packets = 1;
23531 +
23532 + if (hc->complete_split && !hc->ep_is_in) {
23533 + /* For CSPLIT OUT Transfer, set the size to 0 so the
23534 + * core doesn't expect any data written to the FIFO */
23535 + hc->xfer_len = 0;
23536 + } else if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
23537 + hc->xfer_len = hc->max_packet;
23538 + } else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
23539 + hc->xfer_len = 188;
23540 + }
23541 +
23542 + hctsiz.b.xfersize = hc->xfer_len;
23543 + } else {
23544 + /*
23545 + * Ensure that the transfer length and packet count will fit
23546 + * in the widths allocated for them in the HCTSIZn register.
23547 + */
23548 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23549 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23550 + /*
23551 + * Make sure the transfer size is no larger than one
23552 + * (micro)frame's worth of data. (A check was done
23553 + * when the periodic transfer was accepted to ensure
23554 + * that a (micro)frame's worth of data can be
23555 + * programmed into a channel.)
23556 + */
23557 + uint32_t max_periodic_len =
23558 + hc->multi_count * hc->max_packet;
23559 + if (hc->xfer_len > max_periodic_len) {
23560 + hc->xfer_len = max_periodic_len;
23561 + } else {
23562 + }
23563 + } else if (hc->xfer_len > max_hc_xfer_size) {
23564 + /* Make sure that xfer_len is a multiple of max packet size. */
23565 + hc->xfer_len = max_hc_xfer_size - hc->max_packet + 1;
23566 + }
23567 +
23568 + if (hc->xfer_len > 0) {
23569 + num_packets =
23570 + (hc->xfer_len + hc->max_packet -
23571 + 1) / hc->max_packet;
23572 + if (num_packets > max_hc_pkt_count) {
23573 + num_packets = max_hc_pkt_count;
23574 + hc->xfer_len = num_packets * hc->max_packet;
23575 + }
23576 + } else {
23577 + /* Need 1 packet for transfer length of 0. */
23578 + num_packets = 1;
23579 + }
23580 +
23581 + if (hc->ep_is_in) {
23582 + /* Always program an integral # of max packets for IN transfers. */
23583 + hc->xfer_len = num_packets * hc->max_packet;
23584 + }
23585 +
23586 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23587 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23588 + /*
23589 + * Make sure that the multi_count field matches the
23590 + * actual transfer length.
23591 + */
23592 + hc->multi_count = num_packets;
23593 + }
23594 +
23595 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
23596 + set_pid_isoc(hc);
23597 +
23598 + hctsiz.b.xfersize = hc->xfer_len;
23599 + }
23600 +
23601 + hc->start_pkt_count = num_packets;
23602 + hctsiz.b.pktcnt = num_packets;
23603 + hctsiz.b.pid = hc->data_pid_start;
23604 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
23605 +
23606 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23607 + DWC_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize);
23608 + DWC_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n", hctsiz.b.pktcnt);
23609 + DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid);
23610 +
23611 + if (core_if->dma_enable) {
23612 + dwc_dma_t dma_addr;
23613 + if (hc->align_buff) {
23614 + dma_addr = hc->align_buff;
23615 + } else {
23616 + dma_addr = ((unsigned long)hc->xfer_buff & 0xffffffff);
23617 + }
23618 + DWC_WRITE_REG32(&hc_regs->hcdma, dma_addr);
23619 + }
23620 +
23621 + /* Start the split */
23622 + if (hc->do_split) {
23623 + hcsplt_data_t hcsplt;
23624 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
23625 + hcsplt.b.spltena = 1;
23626 + DWC_WRITE_REG32(&hc_regs->hcsplt, hcsplt.d32);
23627 + }
23628 +
23629 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23630 + hcchar.b.multicnt = hc->multi_count;
23631 + hc_set_even_odd_frame(core_if, hc, &hcchar);
23632 +#ifdef DEBUG
23633 + core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
23634 + if (hcchar.b.chdis) {
23635 + DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
23636 + __func__, hc->hc_num, hcchar.d32);
23637 + }
23638 +#endif
23639 +
23640 + /* Set host channel enable after all other setup is complete. */
23641 + hcchar.b.chen = 1;
23642 + hcchar.b.chdis = 0;
23643 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23644 +
23645 + hc->xfer_started = 1;
23646 + hc->requests++;
23647 +
23648 + if (!core_if->dma_enable && !hc->ep_is_in && hc->xfer_len > 0) {
23649 + /* Load OUT packet into the appropriate Tx FIFO. */
23650 + dwc_otg_hc_write_packet(core_if, hc);
23651 + }
23652 +#ifdef DEBUG
23653 + if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
23654 + DWC_DEBUGPL(DBG_HCDV, "transfer %d from core_if %p\n",
23655 + hc->hc_num, core_if);//GRAYG
23656 + core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
23657 + core_if->hc_xfer_info[hc->hc_num].hc = hc;
23658 +
23659 + /* Start a timer for this transfer. */
23660 + DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
23661 + }
23662 +#endif
23663 +}
23664 +
23665 +/**
23666 + * This function does the setup for a data transfer for a host channel
23667 + * and starts the transfer in Descriptor DMA mode.
23668 + *
23669 + * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
23670 + * Sets PID and NTD values. For periodic transfers
23671 + * initializes SCHED_INFO field with micro-frame bitmap.
23672 + *
23673 + * Initializes HCDMA register with descriptor list address and CTD value
23674 + * then starts the transfer via enabling the channel.
23675 + *
23676 + * @param core_if Programming view of DWC_otg controller.
23677 + * @param hc Information needed to initialize the host channel.
23678 + */
23679 +void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23680 +{
23681 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23682 + hcchar_data_t hcchar;
23683 + hctsiz_data_t hctsiz;
23684 + hcdma_data_t hcdma;
23685 +
23686 + hctsiz.d32 = 0;
23687 +
23688 + if (hc->do_ping)
23689 + hctsiz.b_ddma.dopng = 1;
23690 +
23691 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
23692 + set_pid_isoc(hc);
23693 +
23694 + /* Packet Count and Xfer Size are not used in Descriptor DMA mode */
23695 + hctsiz.b_ddma.pid = hc->data_pid_start;
23696 + hctsiz.b_ddma.ntd = hc->ntd - 1; /* 0 - 1 descriptor, 1 - 2 descriptors, etc. */
23697 + hctsiz.b_ddma.schinfo = hc->schinfo; /* Non-zero only for high-speed interrupt endpoints */
23698 +
23699 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23700 + DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid);
23701 + DWC_DEBUGPL(DBG_HCDV, " NTD: %d\n", hctsiz.b_ddma.ntd);
23702 +
23703 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
23704 +
23705 + hcdma.d32 = 0;
23706 + hcdma.b.dma_addr = ((uint32_t) hc->desc_list_addr) >> 11;
23707 +
23708 + /* Always start from first descriptor. */
23709 + hcdma.b.ctd = 0;
23710 + DWC_WRITE_REG32(&hc_regs->hcdma, hcdma.d32);
23711 +
23712 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23713 + hcchar.b.multicnt = hc->multi_count;
23714 +
23715 +#ifdef DEBUG
23716 + core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
23717 + if (hcchar.b.chdis) {
23718 + DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
23719 + __func__, hc->hc_num, hcchar.d32);
23720 + }
23721 +#endif
23722 +
23723 + /* Set host channel enable after all other setup is complete. */
23724 + hcchar.b.chen = 1;
23725 + hcchar.b.chdis = 0;
23726 +
23727 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23728 +
23729 + hc->xfer_started = 1;
23730 + hc->requests++;
23731 +
23732 +#ifdef DEBUG
23733 + if ((hc->ep_type != DWC_OTG_EP_TYPE_INTR)
23734 + && (hc->ep_type != DWC_OTG_EP_TYPE_ISOC)) {
23735 + DWC_DEBUGPL(DBG_HCDV, "DMA transfer %d from core_if %p\n",
23736 + hc->hc_num, core_if);//GRAYG
23737 + core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
23738 + core_if->hc_xfer_info[hc->hc_num].hc = hc;
23739 + /* Start a timer for this transfer. */
23740 + DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
23741 + }
23742 +#endif
23743 +
23744 +}
23745 +
23746 +/**
23747 + * This function continues a data transfer that was started by previous call
23748 + * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is
23749 + * sufficient space in the request queue and Tx Data FIFO. This function
23750 + * should only be called in Slave mode. In DMA mode, the controller acts
23751 + * autonomously to complete transfers programmed to a host channel.
23752 + *
23753 + * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
23754 + * if there is any data remaining to be queued. For an IN transfer, another
23755 + * data packet is always requested. For the SETUP phase of a control transfer,
23756 + * this function does nothing.
23757 + *
23758 + * @return 1 if a new request is queued, 0 if no more requests are required
23759 + * for this transfer.
23760 + */
23761 +int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23762 +{
23763 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23764 +
23765 + if (hc->do_split) {
23766 + /* SPLITs always queue just once per channel */
23767 + return 0;
23768 + } else if (hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
23769 + /* SETUPs are queued only once since they can't be NAKed. */
23770 + return 0;
23771 + } else if (hc->ep_is_in) {
23772 + /*
23773 + * Always queue another request for other IN transfers. If
23774 + * back-to-back INs are issued and NAKs are received for both,
23775 + * the driver may still be processing the first NAK when the
23776 + * second NAK is received. When the interrupt handler clears
23777 + * the NAK interrupt for the first NAK, the second NAK will
23778 + * not be seen. So we can't depend on the NAK interrupt
23779 + * handler to requeue a NAKed request. Instead, IN requests
23780 + * are issued each time this function is called. When the
23781 + * transfer completes, the extra requests for the channel will
23782 + * be flushed.
23783 + */
23784 + hcchar_data_t hcchar;
23785 + dwc_otg_hc_regs_t *hc_regs =
23786 + core_if->host_if->hc_regs[hc->hc_num];
23787 +
23788 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23789 + hc_set_even_odd_frame(core_if, hc, &hcchar);
23790 + hcchar.b.chen = 1;
23791 + hcchar.b.chdis = 0;
23792 + DWC_DEBUGPL(DBG_HCDV, " IN xfer: hcchar = 0x%08x\n",
23793 + hcchar.d32);
23794 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23795 + hc->requests++;
23796 + return 1;
23797 + } else {
23798 + /* OUT transfers. */
23799 + if (hc->xfer_count < hc->xfer_len) {
23800 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23801 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23802 + hcchar_data_t hcchar;
23803 + dwc_otg_hc_regs_t *hc_regs;
23804 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23805 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23806 + hc_set_even_odd_frame(core_if, hc, &hcchar);
23807 + }
23808 +
23809 + /* Load OUT packet into the appropriate Tx FIFO. */
23810 + dwc_otg_hc_write_packet(core_if, hc);
23811 + hc->requests++;
23812 + return 1;
23813 + } else {
23814 + return 0;
23815 + }
23816 + }
23817 +}
23818 +
23819 +/**
23820 + * Starts a PING transfer. This function should only be called in Slave mode.
23821 + * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled.
23822 + */
23823 +void dwc_otg_hc_do_ping(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23824 +{
23825 + hcchar_data_t hcchar;
23826 + hctsiz_data_t hctsiz;
23827 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23828 +
23829 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23830 +
23831 + hctsiz.d32 = 0;
23832 + hctsiz.b.dopng = 1;
23833 + hctsiz.b.pktcnt = 1;
23834 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
23835 +
23836 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23837 + hcchar.b.chen = 1;
23838 + hcchar.b.chdis = 0;
23839 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23840 +}
23841 +
23842 +/*
23843 + * This function writes a packet into the Tx FIFO associated with the Host
23844 + * Channel. For a channel associated with a non-periodic EP, the non-periodic
23845 + * Tx FIFO is written. For a channel associated with a periodic EP, the
23846 + * periodic Tx FIFO is written. This function should only be called in Slave
23847 + * mode.
23848 + *
23849 + * Upon return the xfer_buff and xfer_count fields in _hc are incremented by
23850 + * then number of bytes written to the Tx FIFO.
23851 + */
23852 +void dwc_otg_hc_write_packet(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23853 +{
23854 + uint32_t i;
23855 + uint32_t remaining_count;
23856 + uint32_t byte_count;
23857 + uint32_t dword_count;
23858 +
23859 + uint32_t *data_buff = (uint32_t *) (hc->xfer_buff);
23860 + uint32_t *data_fifo = core_if->data_fifo[hc->hc_num];
23861 +
23862 + remaining_count = hc->xfer_len - hc->xfer_count;
23863 + if (remaining_count > hc->max_packet) {
23864 + byte_count = hc->max_packet;
23865 + } else {
23866 + byte_count = remaining_count;
23867 + }
23868 +
23869 + dword_count = (byte_count + 3) / 4;
23870 +
23871 + if ((((unsigned long)data_buff) & 0x3) == 0) {
23872 + /* xfer_buff is DWORD aligned. */
23873 + for (i = 0; i < dword_count; i++, data_buff++) {
23874 + DWC_WRITE_REG32(data_fifo, *data_buff);
23875 + }
23876 + } else {
23877 + /* xfer_buff is not DWORD aligned. */
23878 + for (i = 0; i < dword_count; i++, data_buff++) {
23879 + uint32_t data;
23880 + data =
23881 + (data_buff[0] | data_buff[1] << 8 | data_buff[2] <<
23882 + 16 | data_buff[3] << 24);
23883 + DWC_WRITE_REG32(data_fifo, data);
23884 + }
23885 + }
23886 +
23887 + hc->xfer_count += byte_count;
23888 + hc->xfer_buff += byte_count;
23889 +}
23890 +
23891 +/**
23892 + * Gets the current USB frame number. This is the frame number from the last
23893 + * SOF packet.
23894 + */
23895 +uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * core_if)
23896 +{
23897 + dsts_data_t dsts;
23898 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
23899 +
23900 + /* read current frame/microframe number from DSTS register */
23901 + return dsts.b.soffn;
23902 +}
23903 +
23904 +/**
23905 + * Calculates and gets the frame Interval value of HFIR register according PHY
23906 + * type and speed.The application can modify a value of HFIR register only after
23907 + * the Port Enable bit of the Host Port Control and Status register
23908 + * (HPRT.PrtEnaPort) has been set.
23909 +*/
23910 +
23911 +uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if)
23912 +{
23913 + gusbcfg_data_t usbcfg;
23914 + hwcfg2_data_t hwcfg2;
23915 + hprt0_data_t hprt0;
23916 + int clock = 60; // default value
23917 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
23918 + hwcfg2.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
23919 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
23920 + if (!usbcfg.b.physel && usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
23921 + clock = 60;
23922 + if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 3)
23923 + clock = 48;
23924 + if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
23925 + !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
23926 + clock = 30;
23927 + if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
23928 + !usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
23929 + clock = 60;
23930 + if (usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
23931 + !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
23932 + clock = 48;
23933 + if (usbcfg.b.physel && !usbcfg.b.phyif && hwcfg2.b.fs_phy_type == 2)
23934 + clock = 48;
23935 + if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 1)
23936 + clock = 48;
23937 + if (hprt0.b.prtspd == 0)
23938 + /* High speed case */
23939 + return 125 * clock;
23940 + else
23941 + /* FS/LS case */
23942 + return 1000 * clock;
23943 +}
23944 +
23945 +/**
23946 + * This function reads a setup packet from the Rx FIFO into the destination
23947 + * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl)
23948 + * Interrupt routine when a SETUP packet has been received in Slave mode.
23949 + *
23950 + * @param core_if Programming view of DWC_otg controller.
23951 + * @param dest Destination buffer for packet data.
23952 + */
23953 +void dwc_otg_read_setup_packet(dwc_otg_core_if_t * core_if, uint32_t * dest)
23954 +{
23955 + device_grxsts_data_t status;
23956 + /* Get the 8 bytes of a setup transaction data */
23957 +
23958 + /* Pop 2 DWORDS off the receive data FIFO into memory */
23959 + dest[0] = DWC_READ_REG32(core_if->data_fifo[0]);
23960 + dest[1] = DWC_READ_REG32(core_if->data_fifo[0]);
23961 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
23962 + status.d32 =
23963 + DWC_READ_REG32(&core_if->core_global_regs->grxstsp);
23964 + DWC_DEBUGPL(DBG_ANY,
23965 + "EP:%d BCnt:%d " "pktsts:%x Frame:%d(0x%0x)\n",
23966 + status.b.epnum, status.b.bcnt, status.b.pktsts,
23967 + status.b.fn, status.b.fn);
23968 + }
23969 +}
23970 +
23971 +/**
23972 + * This function enables EP0 OUT to receive SETUP packets and configures EP0
23973 + * IN for transmitting packets. It is normally called when the
23974 + * "Enumeration Done" interrupt occurs.
23975 + *
23976 + * @param core_if Programming view of DWC_otg controller.
23977 + * @param ep The EP0 data.
23978 + */
23979 +void dwc_otg_ep0_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
23980 +{
23981 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
23982 + dsts_data_t dsts;
23983 + depctl_data_t diepctl;
23984 + depctl_data_t doepctl;
23985 + dctl_data_t dctl = {.d32 = 0 };
23986 +
23987 + ep->stp_rollover = 0;
23988 + /* Read the Device Status and Endpoint 0 Control registers */
23989 + dsts.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dsts);
23990 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
23991 + doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
23992 +
23993 + /* Set the MPS of the IN EP based on the enumeration speed */
23994 + switch (dsts.b.enumspd) {
23995 + case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
23996 + case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
23997 + case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
23998 + diepctl.b.mps = DWC_DEP0CTL_MPS_64;
23999 + break;
24000 + case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
24001 + diepctl.b.mps = DWC_DEP0CTL_MPS_8;
24002 + break;
24003 + }
24004 +
24005 + DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
24006 +
24007 + /* Enable OUT EP for receive */
24008 + if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
24009 + doepctl.b.epena = 1;
24010 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
24011 + }
24012 +#ifdef VERBOSE
24013 + DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
24014 + DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
24015 + DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
24016 + DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
24017 +#endif
24018 + dctl.b.cgnpinnak = 1;
24019 +
24020 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
24021 + DWC_DEBUGPL(DBG_PCDV, "dctl=%0x\n",
24022 + DWC_READ_REG32(&dev_if->dev_global_regs->dctl));
24023 +
24024 +}
24025 +
24026 +/**
24027 + * This function activates an EP. The Device EP control register for
24028 + * the EP is configured as defined in the ep structure. Note: This
24029 + * function is not used for EP0.
24030 + *
24031 + * @param core_if Programming view of DWC_otg controller.
24032 + * @param ep The EP to activate.
24033 + */
24034 +void dwc_otg_ep_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24035 +{
24036 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
24037 + depctl_data_t depctl;
24038 + volatile uint32_t *addr;
24039 + daint_data_t daintmsk = {.d32 = 0 };
24040 + dcfg_data_t dcfg;
24041 + uint8_t i;
24042 +
24043 + DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, ep->num,
24044 + (ep->is_in ? "IN" : "OUT"));
24045 +
24046 +#ifdef DWC_UTE_PER_IO
24047 + ep->xiso_frame_num = 0xFFFFFFFF;
24048 + ep->xiso_active_xfers = 0;
24049 + ep->xiso_queued_xfers = 0;
24050 +#endif
24051 + /* Read DEPCTLn register */
24052 + if (ep->is_in == 1) {
24053 + addr = &dev_if->in_ep_regs[ep->num]->diepctl;
24054 + daintmsk.ep.in = 1 << ep->num;
24055 + } else {
24056 + addr = &dev_if->out_ep_regs[ep->num]->doepctl;
24057 + daintmsk.ep.out = 1 << ep->num;
24058 + }
24059 +
24060 + /* If the EP is already active don't change the EP Control
24061 + * register. */
24062 + depctl.d32 = DWC_READ_REG32(addr);
24063 + if (!depctl.b.usbactep) {
24064 + depctl.b.mps = ep->maxpacket;
24065 + depctl.b.eptype = ep->type;
24066 + depctl.b.txfnum = ep->tx_fifo_num;
24067 +
24068 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24069 + depctl.b.setd0pid = 1; // ???
24070 + } else {
24071 + depctl.b.setd0pid = 1;
24072 + }
24073 + depctl.b.usbactep = 1;
24074 +
24075 + /* Update nextep_seq array and EPMSCNT in DCFG*/
24076 + if (!(depctl.b.eptype & 1) && (ep->is_in == 1)) { // NP IN EP
24077 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
24078 + if (core_if->nextep_seq[i] == core_if->first_in_nextep_seq)
24079 + break;
24080 + }
24081 + core_if->nextep_seq[i] = ep->num;
24082 + core_if->nextep_seq[ep->num] = core_if->first_in_nextep_seq;
24083 + depctl.b.nextep = core_if->nextep_seq[ep->num];
24084 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
24085 + dcfg.b.epmscnt++;
24086 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
24087 +
24088 + DWC_DEBUGPL(DBG_PCDV,
24089 + "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
24090 + __func__, core_if->first_in_nextep_seq);
24091 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
24092 + DWC_DEBUGPL(DBG_PCDV, "%2d\n",
24093 + core_if->nextep_seq[i]);
24094 + }
24095 +
24096 + }
24097 +
24098 +
24099 + DWC_WRITE_REG32(addr, depctl.d32);
24100 + DWC_DEBUGPL(DBG_PCDV, "DEPCTL=%08x\n", DWC_READ_REG32(addr));
24101 + }
24102 +
24103 + /* Enable the Interrupt for this EP */
24104 + if (core_if->multiproc_int_enable) {
24105 + if (ep->is_in == 1) {
24106 + diepmsk_data_t diepmsk = {.d32 = 0 };
24107 + diepmsk.b.xfercompl = 1;
24108 + diepmsk.b.timeout = 1;
24109 + diepmsk.b.epdisabled = 1;
24110 + diepmsk.b.ahberr = 1;
24111 + diepmsk.b.intknepmis = 1;
24112 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
24113 + diepmsk.b.intknepmis = 0;
24114 + diepmsk.b.txfifoundrn = 1; //?????
24115 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24116 + diepmsk.b.nak = 1;
24117 + }
24118 +
24119 +
24120 +
24121 +/*
24122 + if (core_if->dma_desc_enable) {
24123 + diepmsk.b.bna = 1;
24124 + }
24125 +*/
24126 +/*
24127 + if (core_if->dma_enable) {
24128 + doepmsk.b.nak = 1;
24129 + }
24130 +*/
24131 + DWC_WRITE_REG32(&dev_if->dev_global_regs->
24132 + diepeachintmsk[ep->num], diepmsk.d32);
24133 +
24134 + } else {
24135 + doepmsk_data_t doepmsk = {.d32 = 0 };
24136 + doepmsk.b.xfercompl = 1;
24137 + doepmsk.b.ahberr = 1;
24138 + doepmsk.b.epdisabled = 1;
24139 + if (ep->type == DWC_OTG_EP_TYPE_ISOC)
24140 + doepmsk.b.outtknepdis = 1;
24141 +
24142 +/*
24143 +
24144 + if (core_if->dma_desc_enable) {
24145 + doepmsk.b.bna = 1;
24146 + }
24147 +*/
24148 +/*
24149 + doepmsk.b.babble = 1;
24150 + doepmsk.b.nyet = 1;
24151 + doepmsk.b.nak = 1;
24152 +*/
24153 + DWC_WRITE_REG32(&dev_if->dev_global_regs->
24154 + doepeachintmsk[ep->num], doepmsk.d32);
24155 + }
24156 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->deachintmsk,
24157 + 0, daintmsk.d32);
24158 + } else {
24159 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24160 + if (ep->is_in) {
24161 + diepmsk_data_t diepmsk = {.d32 = 0 };
24162 + diepmsk.b.nak = 1;
24163 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk, 0, diepmsk.d32);
24164 + } else {
24165 + doepmsk_data_t doepmsk = {.d32 = 0 };
24166 + doepmsk.b.outtknepdis = 1;
24167 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->doepmsk, 0, doepmsk.d32);
24168 + }
24169 + }
24170 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->daintmsk,
24171 + 0, daintmsk.d32);
24172 + }
24173 +
24174 + DWC_DEBUGPL(DBG_PCDV, "DAINTMSK=%0x\n",
24175 + DWC_READ_REG32(&dev_if->dev_global_regs->daintmsk));
24176 +
24177 + ep->stall_clear_flag = 0;
24178 +
24179 + return;
24180 +}
24181 +
24182 +/**
24183 + * This function deactivates an EP. This is done by clearing the USB Active
24184 + * EP bit in the Device EP control register. Note: This function is not used
24185 + * for EP0. EP0 cannot be deactivated.
24186 + *
24187 + * @param core_if Programming view of DWC_otg controller.
24188 + * @param ep The EP to deactivate.
24189 + */
24190 +void dwc_otg_ep_deactivate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24191 +{
24192 + depctl_data_t depctl = {.d32 = 0 };
24193 + volatile uint32_t *addr;
24194 + daint_data_t daintmsk = {.d32 = 0 };
24195 + dcfg_data_t dcfg;
24196 + uint8_t i = 0;
24197 +
24198 +#ifdef DWC_UTE_PER_IO
24199 + ep->xiso_frame_num = 0xFFFFFFFF;
24200 + ep->xiso_active_xfers = 0;
24201 + ep->xiso_queued_xfers = 0;
24202 +#endif
24203 +
24204 + /* Read DEPCTLn register */
24205 + if (ep->is_in == 1) {
24206 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
24207 + daintmsk.ep.in = 1 << ep->num;
24208 + } else {
24209 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
24210 + daintmsk.ep.out = 1 << ep->num;
24211 + }
24212 +
24213 + depctl.d32 = DWC_READ_REG32(addr);
24214 +
24215 + depctl.b.usbactep = 0;
24216 +
24217 + /* Update nextep_seq array and EPMSCNT in DCFG*/
24218 + if (!(depctl.b.eptype & 1) && ep->is_in == 1) { // NP EP IN
24219 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
24220 + if (core_if->nextep_seq[i] == ep->num)
24221 + break;
24222 + }
24223 + core_if->nextep_seq[i] = core_if->nextep_seq[ep->num];
24224 + if (core_if->first_in_nextep_seq == ep->num)
24225 + core_if->first_in_nextep_seq = i;
24226 + core_if->nextep_seq[ep->num] = 0xff;
24227 + depctl.b.nextep = 0;
24228 + dcfg.d32 =
24229 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
24230 + dcfg.b.epmscnt--;
24231 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
24232 + dcfg.d32);
24233 +
24234 + DWC_DEBUGPL(DBG_PCDV,
24235 + "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
24236 + __func__, core_if->first_in_nextep_seq);
24237 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
24238 + DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
24239 + }
24240 + }
24241 +
24242 + if (ep->is_in == 1)
24243 + depctl.b.txfnum = 0;
24244 +
24245 + if (core_if->dma_desc_enable)
24246 + depctl.b.epdis = 1;
24247 +
24248 + DWC_WRITE_REG32(addr, depctl.d32);
24249 + depctl.d32 = DWC_READ_REG32(addr);
24250 + if (core_if->dma_enable && ep->type == DWC_OTG_EP_TYPE_ISOC
24251 + && depctl.b.epena) {
24252 + depctl_data_t depctl = {.d32 = 0};
24253 + if (ep->is_in) {
24254 + diepint_data_t diepint = {.d32 = 0};
24255 +
24256 + depctl.b.snak = 1;
24257 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24258 + diepctl, depctl.d32);
24259 + do {
24260 + dwc_udelay(10);
24261 + diepint.d32 =
24262 + DWC_READ_REG32(&core_if->
24263 + dev_if->in_ep_regs[ep->num]->
24264 + diepint);
24265 + } while (!diepint.b.inepnakeff);
24266 + diepint.b.inepnakeff = 1;
24267 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24268 + diepint, diepint.d32);
24269 + depctl.d32 = 0;
24270 + depctl.b.epdis = 1;
24271 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24272 + diepctl, depctl.d32);
24273 + do {
24274 + dwc_udelay(10);
24275 + diepint.d32 =
24276 + DWC_READ_REG32(&core_if->
24277 + dev_if->in_ep_regs[ep->num]->
24278 + diepint);
24279 + } while (!diepint.b.epdisabled);
24280 + diepint.b.epdisabled = 1;
24281 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24282 + diepint, diepint.d32);
24283 + } else {
24284 + dctl_data_t dctl = {.d32 = 0};
24285 + gintmsk_data_t gintsts = {.d32 = 0};
24286 + doepint_data_t doepint = {.d32 = 0};
24287 + dctl.b.sgoutnak = 1;
24288 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
24289 + dctl, 0, dctl.d32);
24290 + do {
24291 + dwc_udelay(10);
24292 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
24293 + } while (!gintsts.b.goutnakeff);
24294 + gintsts.d32 = 0;
24295 + gintsts.b.goutnakeff = 1;
24296 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
24297 +
24298 + depctl.d32 = 0;
24299 + depctl.b.epdis = 1;
24300 + depctl.b.snak = 1;
24301 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepctl, depctl.d32);
24302 + do
24303 + {
24304 + dwc_udelay(10);
24305 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
24306 + out_ep_regs[ep->num]->doepint);
24307 + } while (!doepint.b.epdisabled);
24308 +
24309 + doepint.b.epdisabled = 1;
24310 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepint, doepint.d32);
24311 +
24312 + dctl.d32 = 0;
24313 + dctl.b.cgoutnak = 1;
24314 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
24315 + }
24316 + }
24317 +
24318 + /* Disable the Interrupt for this EP */
24319 + if (core_if->multiproc_int_enable) {
24320 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
24321 + daintmsk.d32, 0);
24322 +
24323 + if (ep->is_in == 1) {
24324 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
24325 + diepeachintmsk[ep->num], 0);
24326 + } else {
24327 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
24328 + doepeachintmsk[ep->num], 0);
24329 + }
24330 + } else {
24331 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->daintmsk,
24332 + daintmsk.d32, 0);
24333 + }
24334 +
24335 +}
24336 +
24337 +/**
24338 + * This function initializes dma descriptor chain.
24339 + *
24340 + * @param core_if Programming view of DWC_otg controller.
24341 + * @param ep The EP to start the transfer on.
24342 + */
24343 +static void init_dma_desc_chain(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24344 +{
24345 + dwc_otg_dev_dma_desc_t *dma_desc;
24346 + uint32_t offset;
24347 + uint32_t xfer_est;
24348 + int i;
24349 + unsigned maxxfer_local, total_len;
24350 +
24351 + if (!ep->is_in && ep->type == DWC_OTG_EP_TYPE_INTR &&
24352 + (ep->maxpacket%4)) {
24353 + maxxfer_local = ep->maxpacket;
24354 + total_len = ep->xfer_len;
24355 + } else {
24356 + maxxfer_local = ep->maxxfer;
24357 + total_len = ep->total_len;
24358 + }
24359 +
24360 + ep->desc_cnt = (total_len / maxxfer_local) +
24361 + ((total_len % maxxfer_local) ? 1 : 0);
24362 +
24363 + if (!ep->desc_cnt)
24364 + ep->desc_cnt = 1;
24365 +
24366 + if (ep->desc_cnt > MAX_DMA_DESC_CNT)
24367 + ep->desc_cnt = MAX_DMA_DESC_CNT;
24368 +
24369 + dma_desc = ep->desc_addr;
24370 + if (maxxfer_local == ep->maxpacket) {
24371 + if ((total_len % maxxfer_local) &&
24372 + (total_len/maxxfer_local < MAX_DMA_DESC_CNT)) {
24373 + xfer_est = (ep->desc_cnt - 1) * maxxfer_local +
24374 + (total_len % maxxfer_local);
24375 + } else
24376 + xfer_est = ep->desc_cnt * maxxfer_local;
24377 + } else
24378 + xfer_est = total_len;
24379 + offset = 0;
24380 + for (i = 0; i < ep->desc_cnt; ++i) {
24381 + /** DMA Descriptor Setup */
24382 + if (xfer_est > maxxfer_local) {
24383 + dma_desc->status.b.bs = BS_HOST_BUSY;
24384 + dma_desc->status.b.l = 0;
24385 + dma_desc->status.b.ioc = 0;
24386 + dma_desc->status.b.sp = 0;
24387 + dma_desc->status.b.bytes = maxxfer_local;
24388 + dma_desc->buf = ep->dma_addr + offset;
24389 + dma_desc->status.b.sts = 0;
24390 + dma_desc->status.b.bs = BS_HOST_READY;
24391 +
24392 + xfer_est -= maxxfer_local;
24393 + offset += maxxfer_local;
24394 + } else {
24395 + dma_desc->status.b.bs = BS_HOST_BUSY;
24396 + dma_desc->status.b.l = 1;
24397 + dma_desc->status.b.ioc = 1;
24398 + if (ep->is_in) {
24399 + dma_desc->status.b.sp =
24400 + (xfer_est %
24401 + ep->maxpacket) ? 1 : ((ep->
24402 + sent_zlp) ? 1 : 0);
24403 + dma_desc->status.b.bytes = xfer_est;
24404 + } else {
24405 + if (maxxfer_local == ep->maxpacket)
24406 + dma_desc->status.b.bytes = xfer_est;
24407 + else
24408 + dma_desc->status.b.bytes =
24409 + xfer_est + ((4 - (xfer_est & 0x3)) & 0x3);
24410 + }
24411 +
24412 + dma_desc->buf = ep->dma_addr + offset;
24413 + dma_desc->status.b.sts = 0;
24414 + dma_desc->status.b.bs = BS_HOST_READY;
24415 + }
24416 + dma_desc++;
24417 + }
24418 +}
24419 +/**
24420 + * This function is called when to write ISOC data into appropriate dedicated
24421 + * periodic FIFO.
24422 + */
24423 +static int32_t write_isoc_tx_fifo(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
24424 +{
24425 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
24426 + dwc_otg_dev_in_ep_regs_t *ep_regs;
24427 + dtxfsts_data_t txstatus = {.d32 = 0 };
24428 + uint32_t len = 0;
24429 + int epnum = dwc_ep->num;
24430 + int dwords;
24431 +
24432 + DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
24433 +
24434 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
24435 +
24436 + len = dwc_ep->xfer_len - dwc_ep->xfer_count;
24437 +
24438 + if (len > dwc_ep->maxpacket) {
24439 + len = dwc_ep->maxpacket;
24440 + }
24441 +
24442 + dwords = (len + 3) / 4;
24443 +
24444 + /* While there is space in the queue and space in the FIFO and
24445 + * More data to tranfer, Write packets to the Tx FIFO */
24446 + txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
24447 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
24448 +
24449 + while (txstatus.b.txfspcavail > dwords &&
24450 + dwc_ep->xfer_count < dwc_ep->xfer_len && dwc_ep->xfer_len != 0) {
24451 + /* Write the FIFO */
24452 + dwc_otg_ep_write_packet(core_if, dwc_ep, 0);
24453 +
24454 + len = dwc_ep->xfer_len - dwc_ep->xfer_count;
24455 + if (len > dwc_ep->maxpacket) {
24456 + len = dwc_ep->maxpacket;
24457 + }
24458 +
24459 + dwords = (len + 3) / 4;
24460 + txstatus.d32 =
24461 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
24462 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
24463 + txstatus.d32);
24464 + }
24465 +
24466 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
24467 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
24468 +
24469 + return 1;
24470 +}
24471 +/**
24472 + * This function does the setup for a data transfer for an EP and
24473 + * starts the transfer. For an IN transfer, the packets will be
24474 + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
24475 + * the packets are unloaded from the Rx FIFO in the ISR. the ISR.
24476 + *
24477 + * @param core_if Programming view of DWC_otg controller.
24478 + * @param ep The EP to start the transfer on.
24479 + */
24480 +
24481 +void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24482 +{
24483 + depctl_data_t depctl;
24484 + deptsiz_data_t deptsiz;
24485 + gintmsk_data_t intr_mask = {.d32 = 0 };
24486 +
24487 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
24488 + DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
24489 + "xfer_buff=%p start_xfer_buff=%p, total_len = %d\n",
24490 + ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
24491 + ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff,
24492 + ep->total_len);
24493 + /* IN endpoint */
24494 + if (ep->is_in == 1) {
24495 + dwc_otg_dev_in_ep_regs_t *in_regs =
24496 + core_if->dev_if->in_ep_regs[ep->num];
24497 +
24498 + gnptxsts_data_t gtxstatus;
24499 +
24500 + gtxstatus.d32 =
24501 + DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
24502 +
24503 + if (core_if->en_multiple_tx_fifo == 0
24504 + && gtxstatus.b.nptxqspcavail == 0 && !core_if->dma_enable) {
24505 +#ifdef DEBUG
24506 + DWC_PRINTF("TX Queue Full (0x%0x)\n", gtxstatus.d32);
24507 +#endif
24508 + return;
24509 + }
24510 +
24511 + depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
24512 + deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
24513 +
24514 + if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
24515 + ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
24516 + ep->maxxfer : (ep->total_len - ep->xfer_len);
24517 + else
24518 + ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len - ep->xfer_len)) ?
24519 + MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
24520 +
24521 +
24522 + /* Zero Length Packet? */
24523 + if ((ep->xfer_len - ep->xfer_count) == 0) {
24524 + deptsiz.b.xfersize = 0;
24525 + deptsiz.b.pktcnt = 1;
24526 + } else {
24527 + /* Program the transfer size and packet count
24528 + * as follows: xfersize = N * maxpacket +
24529 + * short_packet pktcnt = N + (short_packet
24530 + * exist ? 1 : 0)
24531 + */
24532 + deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
24533 + deptsiz.b.pktcnt =
24534 + (ep->xfer_len - ep->xfer_count - 1 +
24535 + ep->maxpacket) / ep->maxpacket;
24536 + if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
24537 + deptsiz.b.pktcnt = MAX_PKT_CNT;
24538 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
24539 + }
24540 + if (ep->type == DWC_OTG_EP_TYPE_ISOC)
24541 + deptsiz.b.mc = deptsiz.b.pktcnt;
24542 + }
24543 +
24544 + /* Write the DMA register */
24545 + if (core_if->dma_enable) {
24546 + if (core_if->dma_desc_enable == 0) {
24547 + if (ep->type != DWC_OTG_EP_TYPE_ISOC)
24548 + deptsiz.b.mc = 1;
24549 + DWC_WRITE_REG32(&in_regs->dieptsiz,
24550 + deptsiz.d32);
24551 + DWC_WRITE_REG32(&(in_regs->diepdma),
24552 + (uint32_t) ep->dma_addr);
24553 + } else {
24554 +#ifdef DWC_UTE_CFI
24555 + /* The descriptor chain should be already initialized by now */
24556 + if (ep->buff_mode != BM_STANDARD) {
24557 + DWC_WRITE_REG32(&in_regs->diepdma,
24558 + ep->descs_dma_addr);
24559 + } else {
24560 +#endif
24561 + init_dma_desc_chain(core_if, ep);
24562 + /** DIEPDMAn Register write */
24563 + DWC_WRITE_REG32(&in_regs->diepdma,
24564 + ep->dma_desc_addr);
24565 +#ifdef DWC_UTE_CFI
24566 + }
24567 +#endif
24568 + }
24569 + } else {
24570 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
24571 + if (ep->type != DWC_OTG_EP_TYPE_ISOC) {
24572 + /**
24573 + * Enable the Non-Periodic Tx FIFO empty interrupt,
24574 + * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
24575 + * the data will be written into the fifo by the ISR.
24576 + */
24577 + if (core_if->en_multiple_tx_fifo == 0) {
24578 + intr_mask.b.nptxfempty = 1;
24579 + DWC_MODIFY_REG32
24580 + (&core_if->core_global_regs->gintmsk,
24581 + intr_mask.d32, intr_mask.d32);
24582 + } else {
24583 + /* Enable the Tx FIFO Empty Interrupt for this EP */
24584 + if (ep->xfer_len > 0) {
24585 + uint32_t fifoemptymsk = 0;
24586 + fifoemptymsk = 1 << ep->num;
24587 + DWC_MODIFY_REG32
24588 + (&core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
24589 + 0, fifoemptymsk);
24590 +
24591 + }
24592 + }
24593 + } else {
24594 + write_isoc_tx_fifo(core_if, ep);
24595 + }
24596 + }
24597 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
24598 + depctl.b.nextep = core_if->nextep_seq[ep->num];
24599 +
24600 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24601 + dsts_data_t dsts = {.d32 = 0};
24602 + if (ep->bInterval == 1) {
24603 + dsts.d32 =
24604 + DWC_READ_REG32(&core_if->dev_if->
24605 + dev_global_regs->dsts);
24606 + ep->frame_num = dsts.b.soffn + ep->bInterval;
24607 + if (ep->frame_num > 0x3FFF) {
24608 + ep->frm_overrun = 1;
24609 + ep->frame_num &= 0x3FFF;
24610 + } else
24611 + ep->frm_overrun = 0;
24612 + if (ep->frame_num & 0x1) {
24613 + depctl.b.setd1pid = 1;
24614 + } else {
24615 + depctl.b.setd0pid = 1;
24616 + }
24617 + }
24618 + }
24619 + /* EP enable, IN data in FIFO */
24620 + depctl.b.cnak = 1;
24621 + depctl.b.epena = 1;
24622 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
24623 +
24624 + } else {
24625 + /* OUT endpoint */
24626 + dwc_otg_dev_out_ep_regs_t *out_regs =
24627 + core_if->dev_if->out_ep_regs[ep->num];
24628 +
24629 + depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
24630 + deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
24631 +
24632 + if (!core_if->dma_desc_enable) {
24633 + if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
24634 + ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
24635 + ep->maxxfer : (ep->total_len - ep->xfer_len);
24636 + else
24637 + ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len
24638 + - ep->xfer_len)) ? MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
24639 + }
24640 +
24641 + /* Program the transfer size and packet count as follows:
24642 + *
24643 + * pktcnt = N
24644 + * xfersize = N * maxpacket
24645 + */
24646 + if ((ep->xfer_len - ep->xfer_count) == 0) {
24647 + /* Zero Length Packet */
24648 + deptsiz.b.xfersize = ep->maxpacket;
24649 + deptsiz.b.pktcnt = 1;
24650 + } else {
24651 + deptsiz.b.pktcnt =
24652 + (ep->xfer_len - ep->xfer_count +
24653 + (ep->maxpacket - 1)) / ep->maxpacket;
24654 + if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
24655 + deptsiz.b.pktcnt = MAX_PKT_CNT;
24656 + }
24657 + if (!core_if->dma_desc_enable) {
24658 + ep->xfer_len =
24659 + deptsiz.b.pktcnt * ep->maxpacket + ep->xfer_count;
24660 + }
24661 + deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
24662 + }
24663 +
24664 + DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n",
24665 + ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt);
24666 +
24667 + if (core_if->dma_enable) {
24668 + if (!core_if->dma_desc_enable) {
24669 + DWC_WRITE_REG32(&out_regs->doeptsiz,
24670 + deptsiz.d32);
24671 +
24672 + DWC_WRITE_REG32(&(out_regs->doepdma),
24673 + (uint32_t) ep->dma_addr);
24674 + } else {
24675 +#ifdef DWC_UTE_CFI
24676 + /* The descriptor chain should be already initialized by now */
24677 + if (ep->buff_mode != BM_STANDARD) {
24678 + DWC_WRITE_REG32(&out_regs->doepdma,
24679 + ep->descs_dma_addr);
24680 + } else {
24681 +#endif
24682 + /** This is used for interrupt out transfers*/
24683 + if (!ep->xfer_len)
24684 + ep->xfer_len = ep->total_len;
24685 + init_dma_desc_chain(core_if, ep);
24686 +
24687 + if (core_if->core_params->dev_out_nak) {
24688 + if (ep->type == DWC_OTG_EP_TYPE_BULK) {
24689 + deptsiz.b.pktcnt = (ep->total_len +
24690 + (ep->maxpacket - 1)) / ep->maxpacket;
24691 + deptsiz.b.xfersize = ep->total_len;
24692 + /* Remember initial value of doeptsiz */
24693 + core_if->start_doeptsiz_val[ep->num] = deptsiz.d32;
24694 + DWC_WRITE_REG32(&out_regs->doeptsiz,
24695 + deptsiz.d32);
24696 + }
24697 + }
24698 + /** DOEPDMAn Register write */
24699 + DWC_WRITE_REG32(&out_regs->doepdma,
24700 + ep->dma_desc_addr);
24701 +#ifdef DWC_UTE_CFI
24702 + }
24703 +#endif
24704 + }
24705 + } else {
24706 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
24707 + }
24708 +
24709 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24710 + dsts_data_t dsts = {.d32 = 0};
24711 + if (ep->bInterval == 1) {
24712 + dsts.d32 =
24713 + DWC_READ_REG32(&core_if->dev_if->
24714 + dev_global_regs->dsts);
24715 + ep->frame_num = dsts.b.soffn + ep->bInterval;
24716 + if (ep->frame_num > 0x3FFF) {
24717 + ep->frm_overrun = 1;
24718 + ep->frame_num &= 0x3FFF;
24719 + } else
24720 + ep->frm_overrun = 0;
24721 +
24722 + if (ep->frame_num & 0x1) {
24723 + depctl.b.setd1pid = 1;
24724 + } else {
24725 + depctl.b.setd0pid = 1;
24726 + }
24727 + }
24728 + }
24729 +
24730 + /* EP enable */
24731 + depctl.b.cnak = 1;
24732 + depctl.b.epena = 1;
24733 +
24734 + DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
24735 +
24736 + DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n",
24737 + DWC_READ_REG32(&out_regs->doepctl),
24738 + DWC_READ_REG32(&out_regs->doeptsiz));
24739 + DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
24740 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
24741 + daintmsk),
24742 + DWC_READ_REG32(&core_if->core_global_regs->
24743 + gintmsk));
24744 +
24745 + /* Timer is scheduling only for out bulk transfers for
24746 + * "Device DDMA OUT NAK Enhancement" feature to inform user
24747 + * about received data payload in case of timeout
24748 + */
24749 + if (core_if->core_params->dev_out_nak) {
24750 + if (ep->type == DWC_OTG_EP_TYPE_BULK) {
24751 + core_if->ep_xfer_info[ep->num].core_if = core_if;
24752 + core_if->ep_xfer_info[ep->num].ep = ep;
24753 + core_if->ep_xfer_info[ep->num].state = 1;
24754 +
24755 + /* Start a timer for this transfer. */
24756 + DWC_TIMER_SCHEDULE(core_if->ep_xfer_timer[ep->num], 10000);
24757 + }
24758 + }
24759 + }
24760 +}
24761 +
24762 +/**
24763 + * This function setup a zero length transfer in Buffer DMA and
24764 + * Slave modes for usb requests with zero field set
24765 + *
24766 + * @param core_if Programming view of DWC_otg controller.
24767 + * @param ep The EP to start the transfer on.
24768 + *
24769 + */
24770 +void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24771 +{
24772 +
24773 + depctl_data_t depctl;
24774 + deptsiz_data_t deptsiz;
24775 + gintmsk_data_t intr_mask = {.d32 = 0 };
24776 +
24777 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
24778 + DWC_PRINTF("zero length transfer is called\n");
24779 +
24780 + /* IN endpoint */
24781 + if (ep->is_in == 1) {
24782 + dwc_otg_dev_in_ep_regs_t *in_regs =
24783 + core_if->dev_if->in_ep_regs[ep->num];
24784 +
24785 + depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
24786 + deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
24787 +
24788 + deptsiz.b.xfersize = 0;
24789 + deptsiz.b.pktcnt = 1;
24790 +
24791 + /* Write the DMA register */
24792 + if (core_if->dma_enable) {
24793 + if (core_if->dma_desc_enable == 0) {
24794 + deptsiz.b.mc = 1;
24795 + DWC_WRITE_REG32(&in_regs->dieptsiz,
24796 + deptsiz.d32);
24797 + DWC_WRITE_REG32(&(in_regs->diepdma),
24798 + (uint32_t) ep->dma_addr);
24799 + }
24800 + } else {
24801 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
24802 + /**
24803 + * Enable the Non-Periodic Tx FIFO empty interrupt,
24804 + * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
24805 + * the data will be written into the fifo by the ISR.
24806 + */
24807 + if (core_if->en_multiple_tx_fifo == 0) {
24808 + intr_mask.b.nptxfempty = 1;
24809 + DWC_MODIFY_REG32(&core_if->
24810 + core_global_regs->gintmsk,
24811 + intr_mask.d32, intr_mask.d32);
24812 + } else {
24813 + /* Enable the Tx FIFO Empty Interrupt for this EP */
24814 + if (ep->xfer_len > 0) {
24815 + uint32_t fifoemptymsk = 0;
24816 + fifoemptymsk = 1 << ep->num;
24817 + DWC_MODIFY_REG32(&core_if->
24818 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
24819 + 0, fifoemptymsk);
24820 + }
24821 + }
24822 + }
24823 +
24824 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
24825 + depctl.b.nextep = core_if->nextep_seq[ep->num];
24826 + /* EP enable, IN data in FIFO */
24827 + depctl.b.cnak = 1;
24828 + depctl.b.epena = 1;
24829 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
24830 +
24831 + } else {
24832 + /* OUT endpoint */
24833 + dwc_otg_dev_out_ep_regs_t *out_regs =
24834 + core_if->dev_if->out_ep_regs[ep->num];
24835 +
24836 + depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
24837 + deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
24838 +
24839 + /* Zero Length Packet */
24840 + deptsiz.b.xfersize = ep->maxpacket;
24841 + deptsiz.b.pktcnt = 1;
24842 +
24843 + if (core_if->dma_enable) {
24844 + if (!core_if->dma_desc_enable) {
24845 + DWC_WRITE_REG32(&out_regs->doeptsiz,
24846 + deptsiz.d32);
24847 +
24848 + DWC_WRITE_REG32(&(out_regs->doepdma),
24849 + (uint32_t) ep->dma_addr);
24850 + }
24851 + } else {
24852 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
24853 + }
24854 +
24855 + /* EP enable */
24856 + depctl.b.cnak = 1;
24857 + depctl.b.epena = 1;
24858 +
24859 + DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
24860 +
24861 + }
24862 +}
24863 +
24864 +/**
24865 + * This function does the setup for a data transfer for EP0 and starts
24866 + * the transfer. For an IN transfer, the packets will be loaded into
24867 + * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are
24868 + * unloaded from the Rx FIFO in the ISR.
24869 + *
24870 + * @param core_if Programming view of DWC_otg controller.
24871 + * @param ep The EP0 data.
24872 + */
24873 +void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24874 +{
24875 + depctl_data_t depctl;
24876 + deptsiz0_data_t deptsiz;
24877 + gintmsk_data_t intr_mask = {.d32 = 0 };
24878 + dwc_otg_dev_dma_desc_t *dma_desc;
24879 +
24880 + DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
24881 + "xfer_buff=%p start_xfer_buff=%p \n",
24882 + ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
24883 + ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff);
24884 +
24885 + ep->total_len = ep->xfer_len;
24886 +
24887 + /* IN endpoint */
24888 + if (ep->is_in == 1) {
24889 + dwc_otg_dev_in_ep_regs_t *in_regs =
24890 + core_if->dev_if->in_ep_regs[0];
24891 +
24892 + gnptxsts_data_t gtxstatus;
24893 +
24894 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
24895 + depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
24896 + if (depctl.b.epena)
24897 + return;
24898 + }
24899 +
24900 + gtxstatus.d32 =
24901 + DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
24902 +
24903 + /* If dedicated FIFO every time flush fifo before enable ep*/
24904 + if (core_if->en_multiple_tx_fifo && core_if->snpsid >= OTG_CORE_REV_3_00a)
24905 + dwc_otg_flush_tx_fifo(core_if, ep->tx_fifo_num);
24906 +
24907 + if (core_if->en_multiple_tx_fifo == 0
24908 + && gtxstatus.b.nptxqspcavail == 0
24909 + && !core_if->dma_enable) {
24910 +#ifdef DEBUG
24911 + deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
24912 + DWC_DEBUGPL(DBG_PCD, "DIEPCTL0=%0x\n",
24913 + DWC_READ_REG32(&in_regs->diepctl));
24914 + DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n",
24915 + deptsiz.d32,
24916 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
24917 + DWC_PRINTF("TX Queue or FIFO Full (0x%0x)\n",
24918 + gtxstatus.d32);
24919 +#endif
24920 + return;
24921 + }
24922 +
24923 + depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
24924 + deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
24925 +
24926 + /* Zero Length Packet? */
24927 + if (ep->xfer_len == 0) {
24928 + deptsiz.b.xfersize = 0;
24929 + deptsiz.b.pktcnt = 1;
24930 + } else {
24931 + /* Program the transfer size and packet count
24932 + * as follows: xfersize = N * maxpacket +
24933 + * short_packet pktcnt = N + (short_packet
24934 + * exist ? 1 : 0)
24935 + */
24936 + if (ep->xfer_len > ep->maxpacket) {
24937 + ep->xfer_len = ep->maxpacket;
24938 + deptsiz.b.xfersize = ep->maxpacket;
24939 + } else {
24940 + deptsiz.b.xfersize = ep->xfer_len;
24941 + }
24942 + deptsiz.b.pktcnt = 1;
24943 +
24944 + }
24945 + DWC_DEBUGPL(DBG_PCDV,
24946 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
24947 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
24948 + deptsiz.d32);
24949 +
24950 + /* Write the DMA register */
24951 + if (core_if->dma_enable) {
24952 + if (core_if->dma_desc_enable == 0) {
24953 + DWC_WRITE_REG32(&in_regs->dieptsiz,
24954 + deptsiz.d32);
24955 +
24956 + DWC_WRITE_REG32(&(in_regs->diepdma),
24957 + (uint32_t) ep->dma_addr);
24958 + } else {
24959 + dma_desc = core_if->dev_if->in_desc_addr;
24960 +
24961 + /** DMA Descriptor Setup */
24962 + dma_desc->status.b.bs = BS_HOST_BUSY;
24963 + dma_desc->status.b.l = 1;
24964 + dma_desc->status.b.ioc = 1;
24965 + dma_desc->status.b.sp =
24966 + (ep->xfer_len == ep->maxpacket) ? 0 : 1;
24967 + dma_desc->status.b.bytes = ep->xfer_len;
24968 + dma_desc->buf = ep->dma_addr;
24969 + dma_desc->status.b.sts = 0;
24970 + dma_desc->status.b.bs = BS_HOST_READY;
24971 +
24972 + /** DIEPDMA0 Register write */
24973 + DWC_WRITE_REG32(&in_regs->diepdma,
24974 + core_if->
24975 + dev_if->dma_in_desc_addr);
24976 + }
24977 + } else {
24978 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
24979 + }
24980 +
24981 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
24982 + depctl.b.nextep = core_if->nextep_seq[ep->num];
24983 + /* EP enable, IN data in FIFO */
24984 + depctl.b.cnak = 1;
24985 + depctl.b.epena = 1;
24986 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
24987 +
24988 + /**
24989 + * Enable the Non-Periodic Tx FIFO empty interrupt, the
24990 + * data will be written into the fifo by the ISR.
24991 + */
24992 + if (!core_if->dma_enable) {
24993 + if (core_if->en_multiple_tx_fifo == 0) {
24994 + intr_mask.b.nptxfempty = 1;
24995 + DWC_MODIFY_REG32(&core_if->
24996 + core_global_regs->gintmsk,
24997 + intr_mask.d32, intr_mask.d32);
24998 + } else {
24999 + /* Enable the Tx FIFO Empty Interrupt for this EP */
25000 + if (ep->xfer_len > 0) {
25001 + uint32_t fifoemptymsk = 0;
25002 + fifoemptymsk |= 1 << ep->num;
25003 + DWC_MODIFY_REG32(&core_if->
25004 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
25005 + 0, fifoemptymsk);
25006 + }
25007 + }
25008 + }
25009 + } else {
25010 + /* OUT endpoint */
25011 + dwc_otg_dev_out_ep_regs_t *out_regs =
25012 + core_if->dev_if->out_ep_regs[0];
25013 +
25014 + depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
25015 + deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
25016 +
25017 + /* Program the transfer size and packet count as follows:
25018 + * xfersize = N * (maxpacket + 4 - (maxpacket % 4))
25019 + * pktcnt = N */
25020 + /* Zero Length Packet */
25021 + deptsiz.b.xfersize = ep->maxpacket;
25022 + deptsiz.b.pktcnt = 1;
25023 + if (core_if->snpsid >= OTG_CORE_REV_3_00a)
25024 + deptsiz.b.supcnt = 3;
25025 +
25026 + DWC_DEBUGPL(DBG_PCDV, "len=%d xfersize=%d pktcnt=%d\n",
25027 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt);
25028 +
25029 + if (core_if->dma_enable) {
25030 + if (!core_if->dma_desc_enable) {
25031 + DWC_WRITE_REG32(&out_regs->doeptsiz,
25032 + deptsiz.d32);
25033 +
25034 + DWC_WRITE_REG32(&(out_regs->doepdma),
25035 + (uint32_t) ep->dma_addr);
25036 + } else {
25037 + dma_desc = core_if->dev_if->out_desc_addr;
25038 +
25039 + /** DMA Descriptor Setup */
25040 + dma_desc->status.b.bs = BS_HOST_BUSY;
25041 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
25042 + dma_desc->status.b.mtrf = 0;
25043 + dma_desc->status.b.sr = 0;
25044 + }
25045 + dma_desc->status.b.l = 1;
25046 + dma_desc->status.b.ioc = 1;
25047 + dma_desc->status.b.bytes = ep->maxpacket;
25048 + dma_desc->buf = ep->dma_addr;
25049 + dma_desc->status.b.sts = 0;
25050 + dma_desc->status.b.bs = BS_HOST_READY;
25051 +
25052 + /** DOEPDMA0 Register write */
25053 + DWC_WRITE_REG32(&out_regs->doepdma,
25054 + core_if->dev_if->
25055 + dma_out_desc_addr);
25056 + }
25057 + } else {
25058 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25059 + }
25060 +
25061 + /* EP enable */
25062 + depctl.b.cnak = 1;
25063 + depctl.b.epena = 1;
25064 + DWC_WRITE_REG32(&(out_regs->doepctl), depctl.d32);
25065 + }
25066 +}
25067 +
25068 +/**
25069 + * This function continues control IN transfers started by
25070 + * dwc_otg_ep0_start_transfer, when the transfer does not fit in a
25071 + * single packet. NOTE: The DIEPCTL0/DOEPCTL0 registers only have one
25072 + * bit for the packet count.
25073 + *
25074 + * @param core_if Programming view of DWC_otg controller.
25075 + * @param ep The EP0 data.
25076 + */
25077 +void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25078 +{
25079 + depctl_data_t depctl;
25080 + deptsiz0_data_t deptsiz;
25081 + gintmsk_data_t intr_mask = {.d32 = 0 };
25082 + dwc_otg_dev_dma_desc_t *dma_desc;
25083 +
25084 + if (ep->is_in == 1) {
25085 + dwc_otg_dev_in_ep_regs_t *in_regs =
25086 + core_if->dev_if->in_ep_regs[0];
25087 + gnptxsts_data_t tx_status = {.d32 = 0 };
25088 +
25089 + tx_status.d32 =
25090 + DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
25091 + /** @todo Should there be check for room in the Tx
25092 + * Status Queue. If not remove the code above this comment. */
25093 +
25094 + depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
25095 + deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
25096 +
25097 + /* Program the transfer size and packet count
25098 + * as follows: xfersize = N * maxpacket +
25099 + * short_packet pktcnt = N + (short_packet
25100 + * exist ? 1 : 0)
25101 + */
25102 +
25103 + if (core_if->dma_desc_enable == 0) {
25104 + deptsiz.b.xfersize =
25105 + (ep->total_len - ep->xfer_count) >
25106 + ep->maxpacket ? ep->maxpacket : (ep->total_len -
25107 + ep->xfer_count);
25108 + deptsiz.b.pktcnt = 1;
25109 + if (core_if->dma_enable == 0) {
25110 + ep->xfer_len += deptsiz.b.xfersize;
25111 + } else {
25112 + ep->xfer_len = deptsiz.b.xfersize;
25113 + }
25114 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
25115 + } else {
25116 + ep->xfer_len =
25117 + (ep->total_len - ep->xfer_count) >
25118 + ep->maxpacket ? ep->maxpacket : (ep->total_len -
25119 + ep->xfer_count);
25120 +
25121 + dma_desc = core_if->dev_if->in_desc_addr;
25122 +
25123 + /** DMA Descriptor Setup */
25124 + dma_desc->status.b.bs = BS_HOST_BUSY;
25125 + dma_desc->status.b.l = 1;
25126 + dma_desc->status.b.ioc = 1;
25127 + dma_desc->status.b.sp =
25128 + (ep->xfer_len == ep->maxpacket) ? 0 : 1;
25129 + dma_desc->status.b.bytes = ep->xfer_len;
25130 + dma_desc->buf = ep->dma_addr;
25131 + dma_desc->status.b.sts = 0;
25132 + dma_desc->status.b.bs = BS_HOST_READY;
25133 +
25134 + /** DIEPDMA0 Register write */
25135 + DWC_WRITE_REG32(&in_regs->diepdma,
25136 + core_if->dev_if->dma_in_desc_addr);
25137 + }
25138 +
25139 + DWC_DEBUGPL(DBG_PCDV,
25140 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
25141 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
25142 + deptsiz.d32);
25143 +
25144 + /* Write the DMA register */
25145 + if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
25146 + if (core_if->dma_desc_enable == 0)
25147 + DWC_WRITE_REG32(&(in_regs->diepdma),
25148 + (uint32_t) ep->dma_addr);
25149 + }
25150 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
25151 + depctl.b.nextep = core_if->nextep_seq[ep->num];
25152 + /* EP enable, IN data in FIFO */
25153 + depctl.b.cnak = 1;
25154 + depctl.b.epena = 1;
25155 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
25156 +
25157 + /**
25158 + * Enable the Non-Periodic Tx FIFO empty interrupt, the
25159 + * data will be written into the fifo by the ISR.
25160 + */
25161 + if (!core_if->dma_enable) {
25162 + if (core_if->en_multiple_tx_fifo == 0) {
25163 + /* First clear it from GINTSTS */
25164 + intr_mask.b.nptxfempty = 1;
25165 + DWC_MODIFY_REG32(&core_if->
25166 + core_global_regs->gintmsk,
25167 + intr_mask.d32, intr_mask.d32);
25168 +
25169 + } else {
25170 + /* Enable the Tx FIFO Empty Interrupt for this EP */
25171 + if (ep->xfer_len > 0) {
25172 + uint32_t fifoemptymsk = 0;
25173 + fifoemptymsk |= 1 << ep->num;
25174 + DWC_MODIFY_REG32(&core_if->
25175 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
25176 + 0, fifoemptymsk);
25177 + }
25178 + }
25179 + }
25180 + } else {
25181 + dwc_otg_dev_out_ep_regs_t *out_regs =
25182 + core_if->dev_if->out_ep_regs[0];
25183 +
25184 + depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
25185 + deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
25186 +
25187 + /* Program the transfer size and packet count
25188 + * as follows: xfersize = N * maxpacket +
25189 + * short_packet pktcnt = N + (short_packet
25190 + * exist ? 1 : 0)
25191 + */
25192 + deptsiz.b.xfersize = ep->maxpacket;
25193 + deptsiz.b.pktcnt = 1;
25194 +
25195 + if (core_if->dma_desc_enable == 0) {
25196 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25197 + } else {
25198 + dma_desc = core_if->dev_if->out_desc_addr;
25199 +
25200 + /** DMA Descriptor Setup */
25201 + dma_desc->status.b.bs = BS_HOST_BUSY;
25202 + dma_desc->status.b.l = 1;
25203 + dma_desc->status.b.ioc = 1;
25204 + dma_desc->status.b.bytes = ep->maxpacket;
25205 + dma_desc->buf = ep->dma_addr;
25206 + dma_desc->status.b.sts = 0;
25207 + dma_desc->status.b.bs = BS_HOST_READY;
25208 +
25209 + /** DOEPDMA0 Register write */
25210 + DWC_WRITE_REG32(&out_regs->doepdma,
25211 + core_if->dev_if->dma_out_desc_addr);
25212 + }
25213 +
25214 + DWC_DEBUGPL(DBG_PCDV,
25215 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
25216 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
25217 + deptsiz.d32);
25218 +
25219 + /* Write the DMA register */
25220 + if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
25221 + if (core_if->dma_desc_enable == 0)
25222 + DWC_WRITE_REG32(&(out_regs->doepdma),
25223 + (uint32_t) ep->dma_addr);
25224 +
25225 + }
25226 +
25227 + /* EP enable, IN data in FIFO */
25228 + depctl.b.cnak = 1;
25229 + depctl.b.epena = 1;
25230 + DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
25231 +
25232 + }
25233 +}
25234 +
25235 +#ifdef DEBUG
25236 +void dump_msg(const u8 * buf, unsigned int length)
25237 +{
25238 + unsigned int start, num, i;
25239 + char line[52], *p;
25240 +
25241 + if (length >= 512)
25242 + return;
25243 + start = 0;
25244 + while (length > 0) {
25245 + num = length < 16u ? length : 16u;
25246 + p = line;
25247 + for (i = 0; i < num; ++i) {
25248 + if (i == 8)
25249 + *p++ = ' ';
25250 + DWC_SPRINTF(p, " %02x", buf[i]);
25251 + p += 3;
25252 + }
25253 + *p = 0;
25254 + DWC_PRINTF("%6x: %s\n", start, line);
25255 + buf += num;
25256 + start += num;
25257 + length -= num;
25258 + }
25259 +}
25260 +#else
25261 +static inline void dump_msg(const u8 * buf, unsigned int length)
25262 +{
25263 +}
25264 +#endif
25265 +
25266 +/**
25267 + * This function writes a packet into the Tx FIFO associated with the
25268 + * EP. For non-periodic EPs the non-periodic Tx FIFO is written. For
25269 + * periodic EPs the periodic Tx FIFO associated with the EP is written
25270 + * with all packets for the next micro-frame.
25271 + *
25272 + * @param core_if Programming view of DWC_otg controller.
25273 + * @param ep The EP to write packet for.
25274 + * @param dma Indicates if DMA is being used.
25275 + */
25276 +void dwc_otg_ep_write_packet(dwc_otg_core_if_t * core_if, dwc_ep_t * ep,
25277 + int dma)
25278 +{
25279 + /**
25280 + * The buffer is padded to DWORD on a per packet basis in
25281 + * slave/dma mode if the MPS is not DWORD aligned. The last
25282 + * packet, if short, is also padded to a multiple of DWORD.
25283 + *
25284 + * ep->xfer_buff always starts DWORD aligned in memory and is a
25285 + * multiple of DWORD in length
25286 + *
25287 + * ep->xfer_len can be any number of bytes
25288 + *
25289 + * ep->xfer_count is a multiple of ep->maxpacket until the last
25290 + * packet
25291 + *
25292 + * FIFO access is DWORD */
25293 +
25294 + uint32_t i;
25295 + uint32_t byte_count;
25296 + uint32_t dword_count;
25297 + uint32_t *fifo;
25298 + uint32_t *data_buff = (uint32_t *) ep->xfer_buff;
25299 +
25300 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, core_if,
25301 + ep);
25302 + if (ep->xfer_count >= ep->xfer_len) {
25303 + DWC_WARN("%s() No data for EP%d!!!\n", __func__, ep->num);
25304 + return;
25305 + }
25306 +
25307 + /* Find the byte length of the packet either short packet or MPS */
25308 + if ((ep->xfer_len - ep->xfer_count) < ep->maxpacket) {
25309 + byte_count = ep->xfer_len - ep->xfer_count;
25310 + } else {
25311 + byte_count = ep->maxpacket;
25312 + }
25313 +
25314 + /* Find the DWORD length, padded by extra bytes as neccessary if MPS
25315 + * is not a multiple of DWORD */
25316 + dword_count = (byte_count + 3) / 4;
25317 +
25318 +#ifdef VERBOSE
25319 + dump_msg(ep->xfer_buff, byte_count);
25320 +#endif
25321 +
25322 + /**@todo NGS Where are the Periodic Tx FIFO addresses
25323 + * intialized? What should this be? */
25324 +
25325 + fifo = core_if->data_fifo[ep->num];
25326 +
25327 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n",
25328 + fifo, data_buff, *data_buff, byte_count);
25329 +
25330 + if (!dma) {
25331 + for (i = 0; i < dword_count; i++, data_buff++) {
25332 + DWC_WRITE_REG32(fifo, *data_buff);
25333 + }
25334 + }
25335 +
25336 + ep->xfer_count += byte_count;
25337 + ep->xfer_buff += byte_count;
25338 + ep->dma_addr += byte_count;
25339 +}
25340 +
25341 +/**
25342 + * Set the EP STALL.
25343 + *
25344 + * @param core_if Programming view of DWC_otg controller.
25345 + * @param ep The EP to set the stall on.
25346 + */
25347 +void dwc_otg_ep_set_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25348 +{
25349 + depctl_data_t depctl;
25350 + volatile uint32_t *depctl_addr;
25351 +
25352 + DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
25353 + (ep->is_in ? "IN" : "OUT"));
25354 +
25355 + if (ep->is_in == 1) {
25356 + depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
25357 + depctl.d32 = DWC_READ_REG32(depctl_addr);
25358 +
25359 + /* set the disable and stall bits */
25360 + if (depctl.b.epena) {
25361 + depctl.b.epdis = 1;
25362 + }
25363 + depctl.b.stall = 1;
25364 + DWC_WRITE_REG32(depctl_addr, depctl.d32);
25365 + } else {
25366 + depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
25367 + depctl.d32 = DWC_READ_REG32(depctl_addr);
25368 +
25369 + /* set the stall bit */
25370 + depctl.b.stall = 1;
25371 + DWC_WRITE_REG32(depctl_addr, depctl.d32);
25372 + }
25373 +
25374 + DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
25375 +
25376 + return;
25377 +}
25378 +
25379 +/**
25380 + * Clear the EP STALL.
25381 + *
25382 + * @param core_if Programming view of DWC_otg controller.
25383 + * @param ep The EP to clear stall from.
25384 + */
25385 +void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25386 +{
25387 + depctl_data_t depctl;
25388 + volatile uint32_t *depctl_addr;
25389 +
25390 + DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
25391 + (ep->is_in ? "IN" : "OUT"));
25392 +
25393 + if (ep->is_in == 1) {
25394 + depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
25395 + } else {
25396 + depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
25397 + }
25398 +
25399 + depctl.d32 = DWC_READ_REG32(depctl_addr);
25400 +
25401 + /* clear the stall bits */
25402 + depctl.b.stall = 0;
25403 +
25404 + /*
25405 + * USB Spec 9.4.5: For endpoints using data toggle, regardless
25406 + * of whether an endpoint has the Halt feature set, a
25407 + * ClearFeature(ENDPOINT_HALT) request always results in the
25408 + * data toggle being reinitialized to DATA0.
25409 + */
25410 + if (ep->type == DWC_OTG_EP_TYPE_INTR ||
25411 + ep->type == DWC_OTG_EP_TYPE_BULK) {
25412 + depctl.b.setd0pid = 1; /* DATA0 */
25413 + }
25414 +
25415 + DWC_WRITE_REG32(depctl_addr, depctl.d32);
25416 + DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
25417 + return;
25418 +}
25419 +
25420 +/**
25421 + * This function reads a packet from the Rx FIFO into the destination
25422 + * buffer. To read SETUP data use dwc_otg_read_setup_packet.
25423 + *
25424 + * @param core_if Programming view of DWC_otg controller.
25425 + * @param dest Destination buffer for the packet.
25426 + * @param bytes Number of bytes to copy to the destination.
25427 + */
25428 +void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
25429 + uint8_t * dest, uint16_t bytes)
25430 +{
25431 + int i;
25432 + int word_count = (bytes + 3) / 4;
25433 +
25434 + volatile uint32_t *fifo = core_if->data_fifo[0];
25435 + uint32_t *data_buff = (uint32_t *) dest;
25436 +
25437 + /**
25438 + * @todo Account for the case where _dest is not dword aligned. This
25439 + * requires reading data from the FIFO into a uint32_t temp buffer,
25440 + * then moving it into the data buffer.
25441 + */
25442 +
25443 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__,
25444 + core_if, dest, bytes);
25445 +
25446 + for (i = 0; i < word_count; i++, data_buff++) {
25447 + *data_buff = DWC_READ_REG32(fifo);
25448 + }
25449 +
25450 + return;
25451 +}
25452 +
25453 +/**
25454 + * This functions reads the device registers and prints them
25455 + *
25456 + * @param core_if Programming view of DWC_otg controller.
25457 + */
25458 +void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * core_if)
25459 +{
25460 + int i;
25461 + volatile uint32_t *addr;
25462 +
25463 + DWC_PRINTF("Device Global Registers\n");
25464 + addr = &core_if->dev_if->dev_global_regs->dcfg;
25465 + DWC_PRINTF("DCFG @0x%08lX : 0x%08X\n",
25466 + (unsigned long)addr, DWC_READ_REG32(addr));
25467 + addr = &core_if->dev_if->dev_global_regs->dctl;
25468 + DWC_PRINTF("DCTL @0x%08lX : 0x%08X\n",
25469 + (unsigned long)addr, DWC_READ_REG32(addr));
25470 + addr = &core_if->dev_if->dev_global_regs->dsts;
25471 + DWC_PRINTF("DSTS @0x%08lX : 0x%08X\n",
25472 + (unsigned long)addr, DWC_READ_REG32(addr));
25473 + addr = &core_if->dev_if->dev_global_regs->diepmsk;
25474 + DWC_PRINTF("DIEPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25475 + DWC_READ_REG32(addr));
25476 + addr = &core_if->dev_if->dev_global_regs->doepmsk;
25477 + DWC_PRINTF("DOEPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25478 + DWC_READ_REG32(addr));
25479 + addr = &core_if->dev_if->dev_global_regs->daint;
25480 + DWC_PRINTF("DAINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
25481 + DWC_READ_REG32(addr));
25482 + addr = &core_if->dev_if->dev_global_regs->daintmsk;
25483 + DWC_PRINTF("DAINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25484 + DWC_READ_REG32(addr));
25485 + addr = &core_if->dev_if->dev_global_regs->dtknqr1;
25486 + DWC_PRINTF("DTKNQR1 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25487 + DWC_READ_REG32(addr));
25488 + if (core_if->hwcfg2.b.dev_token_q_depth > 6) {
25489 + addr = &core_if->dev_if->dev_global_regs->dtknqr2;
25490 + DWC_PRINTF("DTKNQR2 @0x%08lX : 0x%08X\n",
25491 + (unsigned long)addr, DWC_READ_REG32(addr));
25492 + }
25493 +
25494 + addr = &core_if->dev_if->dev_global_regs->dvbusdis;
25495 + DWC_PRINTF("DVBUSID @0x%08lX : 0x%08X\n", (unsigned long)addr,
25496 + DWC_READ_REG32(addr));
25497 +
25498 + addr = &core_if->dev_if->dev_global_regs->dvbuspulse;
25499 + DWC_PRINTF("DVBUSPULSE @0x%08lX : 0x%08X\n",
25500 + (unsigned long)addr, DWC_READ_REG32(addr));
25501 +
25502 + addr = &core_if->dev_if->dev_global_regs->dtknqr3_dthrctl;
25503 + DWC_PRINTF("DTKNQR3_DTHRCTL @0x%08lX : 0x%08X\n",
25504 + (unsigned long)addr, DWC_READ_REG32(addr));
25505 +
25506 + if (core_if->hwcfg2.b.dev_token_q_depth > 22) {
25507 + addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
25508 + DWC_PRINTF("DTKNQR4 @0x%08lX : 0x%08X\n",
25509 + (unsigned long)addr, DWC_READ_REG32(addr));
25510 + }
25511 +
25512 + addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
25513 + DWC_PRINTF("FIFOEMPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25514 + DWC_READ_REG32(addr));
25515 +
25516 + if (core_if->hwcfg2.b.multi_proc_int) {
25517 +
25518 + addr = &core_if->dev_if->dev_global_regs->deachint;
25519 + DWC_PRINTF("DEACHINT @0x%08lX : 0x%08X\n",
25520 + (unsigned long)addr, DWC_READ_REG32(addr));
25521 + addr = &core_if->dev_if->dev_global_regs->deachintmsk;
25522 + DWC_PRINTF("DEACHINTMSK @0x%08lX : 0x%08X\n",
25523 + (unsigned long)addr, DWC_READ_REG32(addr));
25524 +
25525 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
25526 + addr =
25527 + &core_if->dev_if->
25528 + dev_global_regs->diepeachintmsk[i];
25529 + DWC_PRINTF("DIEPEACHINTMSK[%d] @0x%08lX : 0x%08X\n",
25530 + i, (unsigned long)addr,
25531 + DWC_READ_REG32(addr));
25532 + }
25533 +
25534 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
25535 + addr =
25536 + &core_if->dev_if->
25537 + dev_global_regs->doepeachintmsk[i];
25538 + DWC_PRINTF("DOEPEACHINTMSK[%d] @0x%08lX : 0x%08X\n",
25539 + i, (unsigned long)addr,
25540 + DWC_READ_REG32(addr));
25541 + }
25542 + }
25543 +
25544 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
25545 + DWC_PRINTF("Device IN EP %d Registers\n", i);
25546 + addr = &core_if->dev_if->in_ep_regs[i]->diepctl;
25547 + DWC_PRINTF("DIEPCTL @0x%08lX : 0x%08X\n",
25548 + (unsigned long)addr, DWC_READ_REG32(addr));
25549 + addr = &core_if->dev_if->in_ep_regs[i]->diepint;
25550 + DWC_PRINTF("DIEPINT @0x%08lX : 0x%08X\n",
25551 + (unsigned long)addr, DWC_READ_REG32(addr));
25552 + addr = &core_if->dev_if->in_ep_regs[i]->dieptsiz;
25553 + DWC_PRINTF("DIETSIZ @0x%08lX : 0x%08X\n",
25554 + (unsigned long)addr, DWC_READ_REG32(addr));
25555 + addr = &core_if->dev_if->in_ep_regs[i]->diepdma;
25556 + DWC_PRINTF("DIEPDMA @0x%08lX : 0x%08X\n",
25557 + (unsigned long)addr, DWC_READ_REG32(addr));
25558 + addr = &core_if->dev_if->in_ep_regs[i]->dtxfsts;
25559 + DWC_PRINTF("DTXFSTS @0x%08lX : 0x%08X\n",
25560 + (unsigned long)addr, DWC_READ_REG32(addr));
25561 + addr = &core_if->dev_if->in_ep_regs[i]->diepdmab;
25562 + DWC_PRINTF("DIEPDMAB @0x%08lX : 0x%08X\n",
25563 + (unsigned long)addr, 0 /*DWC_READ_REG32(addr) */ );
25564 + }
25565 +
25566 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
25567 + DWC_PRINTF("Device OUT EP %d Registers\n", i);
25568 + addr = &core_if->dev_if->out_ep_regs[i]->doepctl;
25569 + DWC_PRINTF("DOEPCTL @0x%08lX : 0x%08X\n",
25570 + (unsigned long)addr, DWC_READ_REG32(addr));
25571 + addr = &core_if->dev_if->out_ep_regs[i]->doepint;
25572 + DWC_PRINTF("DOEPINT @0x%08lX : 0x%08X\n",
25573 + (unsigned long)addr, DWC_READ_REG32(addr));
25574 + addr = &core_if->dev_if->out_ep_regs[i]->doeptsiz;
25575 + DWC_PRINTF("DOETSIZ @0x%08lX : 0x%08X\n",
25576 + (unsigned long)addr, DWC_READ_REG32(addr));
25577 + addr = &core_if->dev_if->out_ep_regs[i]->doepdma;
25578 + DWC_PRINTF("DOEPDMA @0x%08lX : 0x%08X\n",
25579 + (unsigned long)addr, DWC_READ_REG32(addr));
25580 + if (core_if->dma_enable) { /* Don't access this register in SLAVE mode */
25581 + addr = &core_if->dev_if->out_ep_regs[i]->doepdmab;
25582 + DWC_PRINTF("DOEPDMAB @0x%08lX : 0x%08X\n",
25583 + (unsigned long)addr, DWC_READ_REG32(addr));
25584 + }
25585 +
25586 + }
25587 +}
25588 +
25589 +/**
25590 + * This functions reads the SPRAM and prints its content
25591 + *
25592 + * @param core_if Programming view of DWC_otg controller.
25593 + */
25594 +void dwc_otg_dump_spram(dwc_otg_core_if_t * core_if)
25595 +{
25596 + volatile uint8_t *addr, *start_addr, *end_addr;
25597 +
25598 + DWC_PRINTF("SPRAM Data:\n");
25599 + start_addr = (void *)core_if->core_global_regs;
25600 + DWC_PRINTF("Base Address: 0x%8lX\n", (unsigned long)start_addr);
25601 + start_addr += 0x00028000;
25602 + end_addr = (void *)core_if->core_global_regs;
25603 + end_addr += 0x000280e0;
25604 +
25605 + for (addr = start_addr; addr < end_addr; addr += 16) {
25606 + DWC_PRINTF
25607 + ("0x%8lX:\t%2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X\n",
25608 + (unsigned long)addr, addr[0], addr[1], addr[2], addr[3],
25609 + addr[4], addr[5], addr[6], addr[7], addr[8], addr[9],
25610 + addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]
25611 + );
25612 + }
25613 +
25614 + return;
25615 +}
25616 +
25617 +/**
25618 + * This function reads the host registers and prints them
25619 + *
25620 + * @param core_if Programming view of DWC_otg controller.
25621 + */
25622 +void dwc_otg_dump_host_registers(dwc_otg_core_if_t * core_if)
25623 +{
25624 + int i;
25625 + volatile uint32_t *addr;
25626 +
25627 + DWC_PRINTF("Host Global Registers\n");
25628 + addr = &core_if->host_if->host_global_regs->hcfg;
25629 + DWC_PRINTF("HCFG @0x%08lX : 0x%08X\n",
25630 + (unsigned long)addr, DWC_READ_REG32(addr));
25631 + addr = &core_if->host_if->host_global_regs->hfir;
25632 + DWC_PRINTF("HFIR @0x%08lX : 0x%08X\n",
25633 + (unsigned long)addr, DWC_READ_REG32(addr));
25634 + addr = &core_if->host_if->host_global_regs->hfnum;
25635 + DWC_PRINTF("HFNUM @0x%08lX : 0x%08X\n", (unsigned long)addr,
25636 + DWC_READ_REG32(addr));
25637 + addr = &core_if->host_if->host_global_regs->hptxsts;
25638 + DWC_PRINTF("HPTXSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
25639 + DWC_READ_REG32(addr));
25640 + addr = &core_if->host_if->host_global_regs->haint;
25641 + DWC_PRINTF("HAINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
25642 + DWC_READ_REG32(addr));
25643 + addr = &core_if->host_if->host_global_regs->haintmsk;
25644 + DWC_PRINTF("HAINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25645 + DWC_READ_REG32(addr));
25646 + if (core_if->dma_desc_enable) {
25647 + addr = &core_if->host_if->host_global_regs->hflbaddr;
25648 + DWC_PRINTF("HFLBADDR @0x%08lX : 0x%08X\n",
25649 + (unsigned long)addr, DWC_READ_REG32(addr));
25650 + }
25651 +
25652 + addr = core_if->host_if->hprt0;
25653 + DWC_PRINTF("HPRT0 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25654 + DWC_READ_REG32(addr));
25655 +
25656 + for (i = 0; i < core_if->core_params->host_channels; i++) {
25657 + DWC_PRINTF("Host Channel %d Specific Registers\n", i);
25658 + addr = &core_if->host_if->hc_regs[i]->hcchar;
25659 + DWC_PRINTF("HCCHAR @0x%08lX : 0x%08X\n",
25660 + (unsigned long)addr, DWC_READ_REG32(addr));
25661 + addr = &core_if->host_if->hc_regs[i]->hcsplt;
25662 + DWC_PRINTF("HCSPLT @0x%08lX : 0x%08X\n",
25663 + (unsigned long)addr, DWC_READ_REG32(addr));
25664 + addr = &core_if->host_if->hc_regs[i]->hcint;
25665 + DWC_PRINTF("HCINT @0x%08lX : 0x%08X\n",
25666 + (unsigned long)addr, DWC_READ_REG32(addr));
25667 + addr = &core_if->host_if->hc_regs[i]->hcintmsk;
25668 + DWC_PRINTF("HCINTMSK @0x%08lX : 0x%08X\n",
25669 + (unsigned long)addr, DWC_READ_REG32(addr));
25670 + addr = &core_if->host_if->hc_regs[i]->hctsiz;
25671 + DWC_PRINTF("HCTSIZ @0x%08lX : 0x%08X\n",
25672 + (unsigned long)addr, DWC_READ_REG32(addr));
25673 + addr = &core_if->host_if->hc_regs[i]->hcdma;
25674 + DWC_PRINTF("HCDMA @0x%08lX : 0x%08X\n",
25675 + (unsigned long)addr, DWC_READ_REG32(addr));
25676 + if (core_if->dma_desc_enable) {
25677 + addr = &core_if->host_if->hc_regs[i]->hcdmab;
25678 + DWC_PRINTF("HCDMAB @0x%08lX : 0x%08X\n",
25679 + (unsigned long)addr, DWC_READ_REG32(addr));
25680 + }
25681 +
25682 + }
25683 + return;
25684 +}
25685 +
25686 +/**
25687 + * This function reads the core global registers and prints them
25688 + *
25689 + * @param core_if Programming view of DWC_otg controller.
25690 + */
25691 +void dwc_otg_dump_global_registers(dwc_otg_core_if_t * core_if)
25692 +{
25693 + int i, ep_num;
25694 + volatile uint32_t *addr;
25695 + char *txfsiz;
25696 +
25697 + DWC_PRINTF("Core Global Registers\n");
25698 + addr = &core_if->core_global_regs->gotgctl;
25699 + DWC_PRINTF("GOTGCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
25700 + DWC_READ_REG32(addr));
25701 + addr = &core_if->core_global_regs->gotgint;
25702 + DWC_PRINTF("GOTGINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
25703 + DWC_READ_REG32(addr));
25704 + addr = &core_if->core_global_regs->gahbcfg;
25705 + DWC_PRINTF("GAHBCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
25706 + DWC_READ_REG32(addr));
25707 + addr = &core_if->core_global_regs->gusbcfg;
25708 + DWC_PRINTF("GUSBCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
25709 + DWC_READ_REG32(addr));
25710 + addr = &core_if->core_global_regs->grstctl;
25711 + DWC_PRINTF("GRSTCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
25712 + DWC_READ_REG32(addr));
25713 + addr = &core_if->core_global_regs->gintsts;
25714 + DWC_PRINTF("GINTSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
25715 + DWC_READ_REG32(addr));
25716 + addr = &core_if->core_global_regs->gintmsk;
25717 + DWC_PRINTF("GINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25718 + DWC_READ_REG32(addr));
25719 + addr = &core_if->core_global_regs->grxstsr;
25720 + DWC_PRINTF("GRXSTSR @0x%08lX : 0x%08X\n", (unsigned long)addr,
25721 + DWC_READ_REG32(addr));
25722 + addr = &core_if->core_global_regs->grxfsiz;
25723 + DWC_PRINTF("GRXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
25724 + DWC_READ_REG32(addr));
25725 + addr = &core_if->core_global_regs->gnptxfsiz;
25726 + DWC_PRINTF("GNPTXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
25727 + DWC_READ_REG32(addr));
25728 + addr = &core_if->core_global_regs->gnptxsts;
25729 + DWC_PRINTF("GNPTXSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
25730 + DWC_READ_REG32(addr));
25731 + addr = &core_if->core_global_regs->gi2cctl;
25732 + DWC_PRINTF("GI2CCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
25733 + DWC_READ_REG32(addr));
25734 + addr = &core_if->core_global_regs->gpvndctl;
25735 + DWC_PRINTF("GPVNDCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
25736 + DWC_READ_REG32(addr));
25737 + addr = &core_if->core_global_regs->ggpio;
25738 + DWC_PRINTF("GGPIO @0x%08lX : 0x%08X\n", (unsigned long)addr,
25739 + DWC_READ_REG32(addr));
25740 + addr = &core_if->core_global_regs->guid;
25741 + DWC_PRINTF("GUID @0x%08lX : 0x%08X\n",
25742 + (unsigned long)addr, DWC_READ_REG32(addr));
25743 + addr = &core_if->core_global_regs->gsnpsid;
25744 + DWC_PRINTF("GSNPSID @0x%08lX : 0x%08X\n", (unsigned long)addr,
25745 + DWC_READ_REG32(addr));
25746 + addr = &core_if->core_global_regs->ghwcfg1;
25747 + DWC_PRINTF("GHWCFG1 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25748 + DWC_READ_REG32(addr));
25749 + addr = &core_if->core_global_regs->ghwcfg2;
25750 + DWC_PRINTF("GHWCFG2 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25751 + DWC_READ_REG32(addr));
25752 + addr = &core_if->core_global_regs->ghwcfg3;
25753 + DWC_PRINTF("GHWCFG3 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25754 + DWC_READ_REG32(addr));
25755 + addr = &core_if->core_global_regs->ghwcfg4;
25756 + DWC_PRINTF("GHWCFG4 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25757 + DWC_READ_REG32(addr));
25758 + addr = &core_if->core_global_regs->glpmcfg;
25759 + DWC_PRINTF("GLPMCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
25760 + DWC_READ_REG32(addr));
25761 + addr = &core_if->core_global_regs->gpwrdn;
25762 + DWC_PRINTF("GPWRDN @0x%08lX : 0x%08X\n", (unsigned long)addr,
25763 + DWC_READ_REG32(addr));
25764 + addr = &core_if->core_global_regs->gdfifocfg;
25765 + DWC_PRINTF("GDFIFOCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
25766 + DWC_READ_REG32(addr));
25767 + addr = &core_if->core_global_regs->adpctl;
25768 + DWC_PRINTF("ADPCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
25769 + dwc_otg_adp_read_reg(core_if));
25770 + addr = &core_if->core_global_regs->hptxfsiz;
25771 + DWC_PRINTF("HPTXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
25772 + DWC_READ_REG32(addr));
25773 +
25774 + if (core_if->en_multiple_tx_fifo == 0) {
25775 + ep_num = core_if->hwcfg4.b.num_dev_perio_in_ep;
25776 + txfsiz = "DPTXFSIZ";
25777 + } else {
25778 + ep_num = core_if->hwcfg4.b.num_in_eps;
25779 + txfsiz = "DIENPTXF";
25780 + }
25781 + for (i = 0; i < ep_num; i++) {
25782 + addr = &core_if->core_global_regs->dtxfsiz[i];
25783 + DWC_PRINTF("%s[%d] @0x%08lX : 0x%08X\n", txfsiz, i + 1,
25784 + (unsigned long)addr, DWC_READ_REG32(addr));
25785 + }
25786 + addr = core_if->pcgcctl;
25787 + DWC_PRINTF("PCGCCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
25788 + DWC_READ_REG32(addr));
25789 +}
25790 +
25791 +/**
25792 + * Flush a Tx FIFO.
25793 + *
25794 + * @param core_if Programming view of DWC_otg controller.
25795 + * @param num Tx FIFO to flush.
25796 + */
25797 +void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * core_if, const int num)
25798 +{
25799 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
25800 + volatile grstctl_t greset = {.d32 = 0 };
25801 + int count = 0;
25802 +
25803 + DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "Flush Tx FIFO %d\n", num);
25804 +
25805 + greset.b.txfflsh = 1;
25806 + greset.b.txfnum = num;
25807 + DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
25808 +
25809 + do {
25810 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
25811 + if (++count > 10000) {
25812 + DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
25813 + __func__, greset.d32,
25814 + DWC_READ_REG32(&global_regs->gnptxsts));
25815 + break;
25816 + }
25817 + dwc_udelay(1);
25818 + } while (greset.b.txfflsh == 1);
25819 +
25820 + /* Wait for 3 PHY Clocks */
25821 + dwc_udelay(1);
25822 +}
25823 +
25824 +/**
25825 + * Flush Rx FIFO.
25826 + *
25827 + * @param core_if Programming view of DWC_otg controller.
25828 + */
25829 +void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * core_if)
25830 +{
25831 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
25832 + volatile grstctl_t greset = {.d32 = 0 };
25833 + int count = 0;
25834 +
25835 + DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "%s\n", __func__);
25836 + /*
25837 + *
25838 + */
25839 + greset.b.rxfflsh = 1;
25840 + DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
25841 +
25842 + do {
25843 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
25844 + if (++count > 10000) {
25845 + DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__,
25846 + greset.d32);
25847 + break;
25848 + }
25849 + dwc_udelay(1);
25850 + } while (greset.b.rxfflsh == 1);
25851 +
25852 + /* Wait for 3 PHY Clocks */
25853 + dwc_udelay(1);
25854 +}
25855 +
25856 +/**
25857 + * Do core a soft reset of the core. Be careful with this because it
25858 + * resets all the internal state machines of the core.
25859 + */
25860 +void dwc_otg_core_reset(dwc_otg_core_if_t * core_if)
25861 +{
25862 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
25863 + volatile grstctl_t greset = {.d32 = 0 };
25864 + int count = 0;
25865 +
25866 + DWC_DEBUGPL(DBG_CILV, "%s\n", __func__);
25867 + /* Wait for AHB master IDLE state. */
25868 + do {
25869 + dwc_udelay(10);
25870 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
25871 + if (++count > 100000) {
25872 + DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x\n", __func__,
25873 + greset.d32);
25874 + return;
25875 + }
25876 + }
25877 + while (greset.b.ahbidle == 0);
25878 +
25879 + /* Core Soft Reset */
25880 + count = 0;
25881 + greset.b.csftrst = 1;
25882 + DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
25883 + do {
25884 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
25885 + if (++count > 10000) {
25886 + DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n",
25887 + __func__, greset.d32);
25888 + break;
25889 + }
25890 + dwc_udelay(1);
25891 + }
25892 + while (greset.b.csftrst == 1);
25893 +
25894 + /* Wait for 3 PHY Clocks */
25895 + dwc_mdelay(100);
25896 +}
25897 +
25898 +uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if)
25899 +{
25900 + return (dwc_otg_mode(_core_if) != DWC_HOST_MODE);
25901 +}
25902 +
25903 +uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if)
25904 +{
25905 + return (dwc_otg_mode(_core_if) == DWC_HOST_MODE);
25906 +}
25907 +
25908 +/**
25909 + * Register HCD callbacks. The callbacks are used to start and stop
25910 + * the HCD for interrupt processing.
25911 + *
25912 + * @param core_if Programming view of DWC_otg controller.
25913 + * @param cb the HCD callback structure.
25914 + * @param p pointer to be passed to callback function (usb_hcd*).
25915 + */
25916 +void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * core_if,
25917 + dwc_otg_cil_callbacks_t * cb, void *p)
25918 +{
25919 + core_if->hcd_cb = cb;
25920 + cb->p = p;
25921 +}
25922 +
25923 +/**
25924 + * Register PCD callbacks. The callbacks are used to start and stop
25925 + * the PCD for interrupt processing.
25926 + *
25927 + * @param core_if Programming view of DWC_otg controller.
25928 + * @param cb the PCD callback structure.
25929 + * @param p pointer to be passed to callback function (pcd*).
25930 + */
25931 +void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * core_if,
25932 + dwc_otg_cil_callbacks_t * cb, void *p)
25933 +{
25934 + core_if->pcd_cb = cb;
25935 + cb->p = p;
25936 +}
25937 +
25938 +#ifdef DWC_EN_ISOC
25939 +
25940 +/**
25941 + * This function writes isoc data per 1 (micro)frame into tx fifo
25942 + *
25943 + * @param core_if Programming view of DWC_otg controller.
25944 + * @param ep The EP to start the transfer on.
25945 + *
25946 + */
25947 +void write_isoc_frame_data(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25948 +{
25949 + dwc_otg_dev_in_ep_regs_t *ep_regs;
25950 + dtxfsts_data_t txstatus = {.d32 = 0 };
25951 + uint32_t len = 0;
25952 + uint32_t dwords;
25953 +
25954 + ep->xfer_len = ep->data_per_frame;
25955 + ep->xfer_count = 0;
25956 +
25957 + ep_regs = core_if->dev_if->in_ep_regs[ep->num];
25958 +
25959 + len = ep->xfer_len - ep->xfer_count;
25960 +
25961 + if (len > ep->maxpacket) {
25962 + len = ep->maxpacket;
25963 + }
25964 +
25965 + dwords = (len + 3) / 4;
25966 +
25967 + /* While there is space in the queue and space in the FIFO and
25968 + * More data to tranfer, Write packets to the Tx FIFO */
25969 + txstatus.d32 =
25970 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dtxfsts);
25971 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", ep->num, txstatus.d32);
25972 +
25973 + while (txstatus.b.txfspcavail > dwords &&
25974 + ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) {
25975 + /* Write the FIFO */
25976 + dwc_otg_ep_write_packet(core_if, ep, 0);
25977 +
25978 + len = ep->xfer_len - ep->xfer_count;
25979 + if (len > ep->maxpacket) {
25980 + len = ep->maxpacket;
25981 + }
25982 +
25983 + dwords = (len + 3) / 4;
25984 + txstatus.d32 =
25985 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
25986 + dtxfsts);
25987 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", ep->num,
25988 + txstatus.d32);
25989 + }
25990 +}
25991 +
25992 +/**
25993 + * This function initializes a descriptor chain for Isochronous transfer
25994 + *
25995 + * @param core_if Programming view of DWC_otg controller.
25996 + * @param ep The EP to start the transfer on.
25997 + *
25998 + */
25999 +void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
26000 + dwc_ep_t * ep)
26001 +{
26002 + deptsiz_data_t deptsiz = {.d32 = 0 };
26003 + depctl_data_t depctl = {.d32 = 0 };
26004 + dsts_data_t dsts = {.d32 = 0 };
26005 + volatile uint32_t *addr;
26006 +
26007 + if (ep->is_in) {
26008 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
26009 + } else {
26010 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
26011 + }
26012 +
26013 + ep->xfer_len = ep->data_per_frame;
26014 + ep->xfer_count = 0;
26015 + ep->xfer_buff = ep->cur_pkt_addr;
26016 + ep->dma_addr = ep->cur_pkt_dma_addr;
26017 +
26018 + if (ep->is_in) {
26019 + /* Program the transfer size and packet count
26020 + * as follows: xfersize = N * maxpacket +
26021 + * short_packet pktcnt = N + (short_packet
26022 + * exist ? 1 : 0)
26023 + */
26024 + deptsiz.b.xfersize = ep->xfer_len;
26025 + deptsiz.b.pktcnt =
26026 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
26027 + deptsiz.b.mc = deptsiz.b.pktcnt;
26028 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dieptsiz,
26029 + deptsiz.d32);
26030 +
26031 + /* Write the DMA register */
26032 + if (core_if->dma_enable) {
26033 + DWC_WRITE_REG32(&
26034 + (core_if->dev_if->in_ep_regs[ep->num]->
26035 + diepdma), (uint32_t) ep->dma_addr);
26036 + }
26037 + } else {
26038 + deptsiz.b.pktcnt =
26039 + (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket;
26040 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
26041 +
26042 + DWC_WRITE_REG32(&core_if->dev_if->
26043 + out_ep_regs[ep->num]->doeptsiz, deptsiz.d32);
26044 +
26045 + if (core_if->dma_enable) {
26046 + DWC_WRITE_REG32(&
26047 + (core_if->dev_if->
26048 + out_ep_regs[ep->num]->doepdma),
26049 + (uint32_t) ep->dma_addr);
26050 + }
26051 + }
26052 +
26053 + /** Enable endpoint, clear nak */
26054 +
26055 + depctl.d32 = 0;
26056 + if (ep->bInterval == 1) {
26057 + dsts.d32 =
26058 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
26059 + ep->next_frame = dsts.b.soffn + ep->bInterval;
26060 +
26061 + if (ep->next_frame & 0x1) {
26062 + depctl.b.setd1pid = 1;
26063 + } else {
26064 + depctl.b.setd0pid = 1;
26065 + }
26066 + } else {
26067 + ep->next_frame += ep->bInterval;
26068 +
26069 + if (ep->next_frame & 0x1) {
26070 + depctl.b.setd1pid = 1;
26071 + } else {
26072 + depctl.b.setd0pid = 1;
26073 + }
26074 + }
26075 + depctl.b.epena = 1;
26076 + depctl.b.cnak = 1;
26077 +
26078 + DWC_MODIFY_REG32(addr, 0, depctl.d32);
26079 + depctl.d32 = DWC_READ_REG32(addr);
26080 +
26081 + if (ep->is_in && core_if->dma_enable == 0) {
26082 + write_isoc_frame_data(core_if, ep);
26083 + }
26084 +
26085 +}
26086 +#endif /* DWC_EN_ISOC */
26087 +
26088 +static void dwc_otg_set_uninitialized(int32_t * p, int size)
26089 +{
26090 + int i;
26091 + for (i = 0; i < size; i++) {
26092 + p[i] = -1;
26093 + }
26094 +}
26095 +
26096 +static int dwc_otg_param_initialized(int32_t val)
26097 +{
26098 + return val != -1;
26099 +}
26100 +
26101 +static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if)
26102 +{
26103 + int i;
26104 + core_if->core_params = DWC_ALLOC(sizeof(*core_if->core_params));
26105 + if (!core_if->core_params) {
26106 + return -DWC_E_NO_MEMORY;
26107 + }
26108 + dwc_otg_set_uninitialized((int32_t *) core_if->core_params,
26109 + sizeof(*core_if->core_params) /
26110 + sizeof(int32_t));
26111 + DWC_PRINTF("Setting default values for core params\n");
26112 + dwc_otg_set_param_otg_cap(core_if, dwc_param_otg_cap_default);
26113 + dwc_otg_set_param_dma_enable(core_if, dwc_param_dma_enable_default);
26114 + dwc_otg_set_param_dma_desc_enable(core_if,
26115 + dwc_param_dma_desc_enable_default);
26116 + dwc_otg_set_param_opt(core_if, dwc_param_opt_default);
26117 + dwc_otg_set_param_dma_burst_size(core_if,
26118 + dwc_param_dma_burst_size_default);
26119 + dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
26120 + dwc_param_host_support_fs_ls_low_power_default);
26121 + dwc_otg_set_param_enable_dynamic_fifo(core_if,
26122 + dwc_param_enable_dynamic_fifo_default);
26123 + dwc_otg_set_param_data_fifo_size(core_if,
26124 + dwc_param_data_fifo_size_default);
26125 + dwc_otg_set_param_dev_rx_fifo_size(core_if,
26126 + dwc_param_dev_rx_fifo_size_default);
26127 + dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
26128 + dwc_param_dev_nperio_tx_fifo_size_default);
26129 + dwc_otg_set_param_host_rx_fifo_size(core_if,
26130 + dwc_param_host_rx_fifo_size_default);
26131 + dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
26132 + dwc_param_host_nperio_tx_fifo_size_default);
26133 + dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
26134 + dwc_param_host_perio_tx_fifo_size_default);
26135 + dwc_otg_set_param_max_transfer_size(core_if,
26136 + dwc_param_max_transfer_size_default);
26137 + dwc_otg_set_param_max_packet_count(core_if,
26138 + dwc_param_max_packet_count_default);
26139 + dwc_otg_set_param_host_channels(core_if,
26140 + dwc_param_host_channels_default);
26141 + dwc_otg_set_param_dev_endpoints(core_if,
26142 + dwc_param_dev_endpoints_default);
26143 + dwc_otg_set_param_phy_type(core_if, dwc_param_phy_type_default);
26144 + dwc_otg_set_param_speed(core_if, dwc_param_speed_default);
26145 + dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
26146 + dwc_param_host_ls_low_power_phy_clk_default);
26147 + dwc_otg_set_param_phy_ulpi_ddr(core_if, dwc_param_phy_ulpi_ddr_default);
26148 + dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
26149 + dwc_param_phy_ulpi_ext_vbus_default);
26150 + dwc_otg_set_param_phy_utmi_width(core_if,
26151 + dwc_param_phy_utmi_width_default);
26152 + dwc_otg_set_param_ts_dline(core_if, dwc_param_ts_dline_default);
26153 + dwc_otg_set_param_i2c_enable(core_if, dwc_param_i2c_enable_default);
26154 + dwc_otg_set_param_ulpi_fs_ls(core_if, dwc_param_ulpi_fs_ls_default);
26155 + dwc_otg_set_param_en_multiple_tx_fifo(core_if,
26156 + dwc_param_en_multiple_tx_fifo_default);
26157 + for (i = 0; i < 15; i++) {
26158 + dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
26159 + dwc_param_dev_perio_tx_fifo_size_default,
26160 + i);
26161 + }
26162 +
26163 + for (i = 0; i < 15; i++) {
26164 + dwc_otg_set_param_dev_tx_fifo_size(core_if,
26165 + dwc_param_dev_tx_fifo_size_default,
26166 + i);
26167 + }
26168 + dwc_otg_set_param_thr_ctl(core_if, dwc_param_thr_ctl_default);
26169 + dwc_otg_set_param_mpi_enable(core_if, dwc_param_mpi_enable_default);
26170 + dwc_otg_set_param_pti_enable(core_if, dwc_param_pti_enable_default);
26171 + dwc_otg_set_param_lpm_enable(core_if, dwc_param_lpm_enable_default);
26172 + dwc_otg_set_param_ic_usb_cap(core_if, dwc_param_ic_usb_cap_default);
26173 + dwc_otg_set_param_tx_thr_length(core_if,
26174 + dwc_param_tx_thr_length_default);
26175 + dwc_otg_set_param_rx_thr_length(core_if,
26176 + dwc_param_rx_thr_length_default);
26177 + dwc_otg_set_param_ahb_thr_ratio(core_if,
26178 + dwc_param_ahb_thr_ratio_default);
26179 + dwc_otg_set_param_power_down(core_if, dwc_param_power_down_default);
26180 + dwc_otg_set_param_reload_ctl(core_if, dwc_param_reload_ctl_default);
26181 + dwc_otg_set_param_dev_out_nak(core_if, dwc_param_dev_out_nak_default);
26182 + dwc_otg_set_param_cont_on_bna(core_if, dwc_param_cont_on_bna_default);
26183 + dwc_otg_set_param_ahb_single(core_if, dwc_param_ahb_single_default);
26184 + dwc_otg_set_param_otg_ver(core_if, dwc_param_otg_ver_default);
26185 + dwc_otg_set_param_adp_enable(core_if, dwc_param_adp_enable_default);
26186 + DWC_PRINTF("Finished setting default values for core params\n");
26187 +
26188 + return 0;
26189 +}
26190 +
26191 +uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if)
26192 +{
26193 + return core_if->dma_enable;
26194 +}
26195 +
26196 +/* Checks if the parameter is outside of its valid range of values */
26197 +#define DWC_OTG_PARAM_TEST(_param_, _low_, _high_) \
26198 + (((_param_) < (_low_)) || \
26199 + ((_param_) > (_high_)))
26200 +
26201 +/* Parameter access functions */
26202 +int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val)
26203 +{
26204 + int valid;
26205 + int retval = 0;
26206 + if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
26207 + DWC_WARN("Wrong value for otg_cap parameter\n");
26208 + DWC_WARN("otg_cap parameter must be 0,1 or 2\n");
26209 + retval = -DWC_E_INVALID;
26210 + goto out;
26211 + }
26212 +
26213 + valid = 1;
26214 + switch (val) {
26215 + case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE:
26216 + if (core_if->hwcfg2.b.op_mode !=
26217 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
26218 + valid = 0;
26219 + break;
26220 + case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE:
26221 + if ((core_if->hwcfg2.b.op_mode !=
26222 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
26223 + && (core_if->hwcfg2.b.op_mode !=
26224 + DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
26225 + && (core_if->hwcfg2.b.op_mode !=
26226 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
26227 + && (core_if->hwcfg2.b.op_mode !=
26228 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) {
26229 + valid = 0;
26230 + }
26231 + break;
26232 + case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE:
26233 + /* always valid */
26234 + break;
26235 + }
26236 + if (!valid) {
26237 + if (dwc_otg_param_initialized(core_if->core_params->otg_cap)) {
26238 + DWC_ERROR
26239 + ("%d invalid for otg_cap paremter. Check HW configuration.\n",
26240 + val);
26241 + }
26242 + val =
26243 + (((core_if->hwcfg2.b.op_mode ==
26244 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
26245 + || (core_if->hwcfg2.b.op_mode ==
26246 + DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
26247 + || (core_if->hwcfg2.b.op_mode ==
26248 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
26249 + || (core_if->hwcfg2.b.op_mode ==
26250 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ?
26251 + DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE :
26252 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
26253 + retval = -DWC_E_INVALID;
26254 + }
26255 +
26256 + core_if->core_params->otg_cap = val;
26257 +out:
26258 + return retval;
26259 +}
26260 +
26261 +int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if)
26262 +{
26263 + return core_if->core_params->otg_cap;
26264 +}
26265 +
26266 +int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val)
26267 +{
26268 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26269 + DWC_WARN("Wrong value for opt parameter\n");
26270 + return -DWC_E_INVALID;
26271 + }
26272 + core_if->core_params->opt = val;
26273 + return 0;
26274 +}
26275 +
26276 +int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if)
26277 +{
26278 + return core_if->core_params->opt;
26279 +}
26280 +
26281 +int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if, int32_t val)
26282 +{
26283 + int retval = 0;
26284 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26285 + DWC_WARN("Wrong value for dma enable\n");
26286 + return -DWC_E_INVALID;
26287 + }
26288 +
26289 + if ((val == 1) && (core_if->hwcfg2.b.architecture == 0)) {
26290 + if (dwc_otg_param_initialized(core_if->core_params->dma_enable)) {
26291 + DWC_ERROR
26292 + ("%d invalid for dma_enable paremter. Check HW configuration.\n",
26293 + val);
26294 + }
26295 + val = 0;
26296 + retval = -DWC_E_INVALID;
26297 + }
26298 +
26299 + core_if->core_params->dma_enable = val;
26300 + if (val == 0) {
26301 + dwc_otg_set_param_dma_desc_enable(core_if, 0);
26302 + }
26303 + return retval;
26304 +}
26305 +
26306 +int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if)
26307 +{
26308 + return core_if->core_params->dma_enable;
26309 +}
26310 +
26311 +int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if, int32_t val)
26312 +{
26313 + int retval = 0;
26314 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26315 + DWC_WARN("Wrong value for dma_enable\n");
26316 + DWC_WARN("dma_desc_enable must be 0 or 1\n");
26317 + return -DWC_E_INVALID;
26318 + }
26319 +
26320 + if ((val == 1)
26321 + && ((dwc_otg_get_param_dma_enable(core_if) == 0)
26322 + || (core_if->hwcfg4.b.desc_dma == 0))) {
26323 + if (dwc_otg_param_initialized
26324 + (core_if->core_params->dma_desc_enable)) {
26325 + DWC_ERROR
26326 + ("%d invalid for dma_desc_enable paremter. Check HW configuration.\n",
26327 + val);
26328 + }
26329 + val = 0;
26330 + retval = -DWC_E_INVALID;
26331 + }
26332 + core_if->core_params->dma_desc_enable = val;
26333 + return retval;
26334 +}
26335 +
26336 +int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if)
26337 +{
26338 + return core_if->core_params->dma_desc_enable;
26339 +}
26340 +
26341 +int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t * core_if,
26342 + int32_t val)
26343 +{
26344 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26345 + DWC_WARN("Wrong value for host_support_fs_low_power\n");
26346 + DWC_WARN("host_support_fs_low_power must be 0 or 1\n");
26347 + return -DWC_E_INVALID;
26348 + }
26349 + core_if->core_params->host_support_fs_ls_low_power = val;
26350 + return 0;
26351 +}
26352 +
26353 +int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
26354 + core_if)
26355 +{
26356 + return core_if->core_params->host_support_fs_ls_low_power;
26357 +}
26358 +
26359 +int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
26360 + int32_t val)
26361 +{
26362 + int retval = 0;
26363 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26364 + DWC_WARN("Wrong value for enable_dynamic_fifo\n");
26365 + DWC_WARN("enable_dynamic_fifo must be 0 or 1\n");
26366 + return -DWC_E_INVALID;
26367 + }
26368 +
26369 + if ((val == 1) && (core_if->hwcfg2.b.dynamic_fifo == 0)) {
26370 + if (dwc_otg_param_initialized
26371 + (core_if->core_params->enable_dynamic_fifo)) {
26372 + DWC_ERROR
26373 + ("%d invalid for enable_dynamic_fifo paremter. Check HW configuration.\n",
26374 + val);
26375 + }
26376 + val = 0;
26377 + retval = -DWC_E_INVALID;
26378 + }
26379 + core_if->core_params->enable_dynamic_fifo = val;
26380 + return retval;
26381 +}
26382 +
26383 +int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if)
26384 +{
26385 + return core_if->core_params->enable_dynamic_fifo;
26386 +}
26387 +
26388 +int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
26389 +{
26390 + int retval = 0;
26391 + if (DWC_OTG_PARAM_TEST(val, 32, 32768)) {
26392 + DWC_WARN("Wrong value for data_fifo_size\n");
26393 + DWC_WARN("data_fifo_size must be 32-32768\n");
26394 + return -DWC_E_INVALID;
26395 + }
26396 +
26397 + if (val > core_if->hwcfg3.b.dfifo_depth) {
26398 + if (dwc_otg_param_initialized
26399 + (core_if->core_params->data_fifo_size)) {
26400 + DWC_ERROR
26401 + ("%d invalid for data_fifo_size parameter. Check HW configuration.\n",
26402 + val);
26403 + }
26404 + val = core_if->hwcfg3.b.dfifo_depth;
26405 + retval = -DWC_E_INVALID;
26406 + }
26407 +
26408 + core_if->core_params->data_fifo_size = val;
26409 + return retval;
26410 +}
26411 +
26412 +int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if)
26413 +{
26414 + return core_if->core_params->data_fifo_size;
26415 +}
26416 +
26417 +int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
26418 +{
26419 + int retval = 0;
26420 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26421 + DWC_WARN("Wrong value for dev_rx_fifo_size\n");
26422 + DWC_WARN("dev_rx_fifo_size must be 16-32768\n");
26423 + return -DWC_E_INVALID;
26424 + }
26425 +
26426 + if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
26427 + if (dwc_otg_param_initialized(core_if->core_params->dev_rx_fifo_size)) {
26428 + DWC_WARN("%d invalid for dev_rx_fifo_size parameter\n", val);
26429 + }
26430 + val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
26431 + retval = -DWC_E_INVALID;
26432 + }
26433 +
26434 + core_if->core_params->dev_rx_fifo_size = val;
26435 + return retval;
26436 +}
26437 +
26438 +int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if)
26439 +{
26440 + return core_if->core_params->dev_rx_fifo_size;
26441 +}
26442 +
26443 +int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26444 + int32_t val)
26445 +{
26446 + int retval = 0;
26447 +
26448 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26449 + DWC_WARN("Wrong value for dev_nperio_tx_fifo\n");
26450 + DWC_WARN("dev_nperio_tx_fifo must be 16-32768\n");
26451 + return -DWC_E_INVALID;
26452 + }
26453 +
26454 + if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
26455 + if (dwc_otg_param_initialized
26456 + (core_if->core_params->dev_nperio_tx_fifo_size)) {
26457 + DWC_ERROR
26458 + ("%d invalid for dev_nperio_tx_fifo_size. Check HW configuration.\n",
26459 + val);
26460 + }
26461 + val =
26462 + (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
26463 + 16);
26464 + retval = -DWC_E_INVALID;
26465 + }
26466 +
26467 + core_if->core_params->dev_nperio_tx_fifo_size = val;
26468 + return retval;
26469 +}
26470 +
26471 +int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
26472 +{
26473 + return core_if->core_params->dev_nperio_tx_fifo_size;
26474 +}
26475 +
26476 +int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
26477 + int32_t val)
26478 +{
26479 + int retval = 0;
26480 +
26481 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26482 + DWC_WARN("Wrong value for host_rx_fifo_size\n");
26483 + DWC_WARN("host_rx_fifo_size must be 16-32768\n");
26484 + return -DWC_E_INVALID;
26485 + }
26486 +
26487 + if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
26488 + if (dwc_otg_param_initialized
26489 + (core_if->core_params->host_rx_fifo_size)) {
26490 + DWC_ERROR
26491 + ("%d invalid for host_rx_fifo_size. Check HW configuration.\n",
26492 + val);
26493 + }
26494 + val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
26495 + retval = -DWC_E_INVALID;
26496 + }
26497 +
26498 + core_if->core_params->host_rx_fifo_size = val;
26499 + return retval;
26500 +
26501 +}
26502 +
26503 +int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if)
26504 +{
26505 + return core_if->core_params->host_rx_fifo_size;
26506 +}
26507 +
26508 +int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26509 + int32_t val)
26510 +{
26511 + int retval = 0;
26512 +
26513 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26514 + DWC_WARN("Wrong value for host_nperio_tx_fifo_size\n");
26515 + DWC_WARN("host_nperio_tx_fifo_size must be 16-32768\n");
26516 + return -DWC_E_INVALID;
26517 + }
26518 +
26519 + if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
26520 + if (dwc_otg_param_initialized
26521 + (core_if->core_params->host_nperio_tx_fifo_size)) {
26522 + DWC_ERROR
26523 + ("%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n",
26524 + val);
26525 + }
26526 + val =
26527 + (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
26528 + 16);
26529 + retval = -DWC_E_INVALID;
26530 + }
26531 +
26532 + core_if->core_params->host_nperio_tx_fifo_size = val;
26533 + return retval;
26534 +}
26535 +
26536 +int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
26537 +{
26538 + return core_if->core_params->host_nperio_tx_fifo_size;
26539 +}
26540 +
26541 +int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26542 + int32_t val)
26543 +{
26544 + int retval = 0;
26545 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26546 + DWC_WARN("Wrong value for host_perio_tx_fifo_size\n");
26547 + DWC_WARN("host_perio_tx_fifo_size must be 16-32768\n");
26548 + return -DWC_E_INVALID;
26549 + }
26550 +
26551 + if (val > ((core_if->hptxfsiz.d32) >> 16)) {
26552 + if (dwc_otg_param_initialized
26553 + (core_if->core_params->host_perio_tx_fifo_size)) {
26554 + DWC_ERROR
26555 + ("%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n",
26556 + val);
26557 + }
26558 + val = (core_if->hptxfsiz.d32) >> 16;
26559 + retval = -DWC_E_INVALID;
26560 + }
26561 +
26562 + core_if->core_params->host_perio_tx_fifo_size = val;
26563 + return retval;
26564 +}
26565 +
26566 +int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if)
26567 +{
26568 + return core_if->core_params->host_perio_tx_fifo_size;
26569 +}
26570 +
26571 +int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
26572 + int32_t val)
26573 +{
26574 + int retval = 0;
26575 +
26576 + if (DWC_OTG_PARAM_TEST(val, 2047, 524288)) {
26577 + DWC_WARN("Wrong value for max_transfer_size\n");
26578 + DWC_WARN("max_transfer_size must be 2047-524288\n");
26579 + return -DWC_E_INVALID;
26580 + }
26581 +
26582 + if (val >= (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))) {
26583 + if (dwc_otg_param_initialized
26584 + (core_if->core_params->max_transfer_size)) {
26585 + DWC_ERROR
26586 + ("%d invalid for max_transfer_size. Check HW configuration.\n",
26587 + val);
26588 + }
26589 + val =
26590 + ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 11)) -
26591 + 1);
26592 + retval = -DWC_E_INVALID;
26593 + }
26594 +
26595 + core_if->core_params->max_transfer_size = val;
26596 + return retval;
26597 +}
26598 +
26599 +int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if)
26600 +{
26601 + return core_if->core_params->max_transfer_size;
26602 +}
26603 +
26604 +int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if, int32_t val)
26605 +{
26606 + int retval = 0;
26607 +
26608 + if (DWC_OTG_PARAM_TEST(val, 15, 511)) {
26609 + DWC_WARN("Wrong value for max_packet_count\n");
26610 + DWC_WARN("max_packet_count must be 15-511\n");
26611 + return -DWC_E_INVALID;
26612 + }
26613 +
26614 + if (val > (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))) {
26615 + if (dwc_otg_param_initialized
26616 + (core_if->core_params->max_packet_count)) {
26617 + DWC_ERROR
26618 + ("%d invalid for max_packet_count. Check HW configuration.\n",
26619 + val);
26620 + }
26621 + val =
26622 + ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1);
26623 + retval = -DWC_E_INVALID;
26624 + }
26625 +
26626 + core_if->core_params->max_packet_count = val;
26627 + return retval;
26628 +}
26629 +
26630 +int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if)
26631 +{
26632 + return core_if->core_params->max_packet_count;
26633 +}
26634 +
26635 +int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if, int32_t val)
26636 +{
26637 + int retval = 0;
26638 +
26639 + if (DWC_OTG_PARAM_TEST(val, 1, 16)) {
26640 + DWC_WARN("Wrong value for host_channels\n");
26641 + DWC_WARN("host_channels must be 1-16\n");
26642 + return -DWC_E_INVALID;
26643 + }
26644 +
26645 + if (val > (core_if->hwcfg2.b.num_host_chan + 1)) {
26646 + if (dwc_otg_param_initialized
26647 + (core_if->core_params->host_channels)) {
26648 + DWC_ERROR
26649 + ("%d invalid for host_channels. Check HW configurations.\n",
26650 + val);
26651 + }
26652 + val = (core_if->hwcfg2.b.num_host_chan + 1);
26653 + retval = -DWC_E_INVALID;
26654 + }
26655 +
26656 + core_if->core_params->host_channels = val;
26657 + return retval;
26658 +}
26659 +
26660 +int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if)
26661 +{
26662 + return core_if->core_params->host_channels;
26663 +}
26664 +
26665 +int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if, int32_t val)
26666 +{
26667 + int retval = 0;
26668 +
26669 + if (DWC_OTG_PARAM_TEST(val, 1, 15)) {
26670 + DWC_WARN("Wrong value for dev_endpoints\n");
26671 + DWC_WARN("dev_endpoints must be 1-15\n");
26672 + return -DWC_E_INVALID;
26673 + }
26674 +
26675 + if (val > (core_if->hwcfg2.b.num_dev_ep)) {
26676 + if (dwc_otg_param_initialized
26677 + (core_if->core_params->dev_endpoints)) {
26678 + DWC_ERROR
26679 + ("%d invalid for dev_endpoints. Check HW configurations.\n",
26680 + val);
26681 + }
26682 + val = core_if->hwcfg2.b.num_dev_ep;
26683 + retval = -DWC_E_INVALID;
26684 + }
26685 +
26686 + core_if->core_params->dev_endpoints = val;
26687 + return retval;
26688 +}
26689 +
26690 +int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if)
26691 +{
26692 + return core_if->core_params->dev_endpoints;
26693 +}
26694 +
26695 +int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val)
26696 +{
26697 + int retval = 0;
26698 + int valid = 0;
26699 +
26700 + if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
26701 + DWC_WARN("Wrong value for phy_type\n");
26702 + DWC_WARN("phy_type must be 0,1 or 2\n");
26703 + return -DWC_E_INVALID;
26704 + }
26705 +#ifndef NO_FS_PHY_HW_CHECKS
26706 + if ((val == DWC_PHY_TYPE_PARAM_UTMI) &&
26707 + ((core_if->hwcfg2.b.hs_phy_type == 1) ||
26708 + (core_if->hwcfg2.b.hs_phy_type == 3))) {
26709 + valid = 1;
26710 + } else if ((val == DWC_PHY_TYPE_PARAM_ULPI) &&
26711 + ((core_if->hwcfg2.b.hs_phy_type == 2) ||
26712 + (core_if->hwcfg2.b.hs_phy_type == 3))) {
26713 + valid = 1;
26714 + } else if ((val == DWC_PHY_TYPE_PARAM_FS) &&
26715 + (core_if->hwcfg2.b.fs_phy_type == 1)) {
26716 + valid = 1;
26717 + }
26718 + if (!valid) {
26719 + if (dwc_otg_param_initialized(core_if->core_params->phy_type)) {
26720 + DWC_ERROR
26721 + ("%d invalid for phy_type. Check HW configurations.\n",
26722 + val);
26723 + }
26724 + if (core_if->hwcfg2.b.hs_phy_type) {
26725 + if ((core_if->hwcfg2.b.hs_phy_type == 3) ||
26726 + (core_if->hwcfg2.b.hs_phy_type == 1)) {
26727 + val = DWC_PHY_TYPE_PARAM_UTMI;
26728 + } else {
26729 + val = DWC_PHY_TYPE_PARAM_ULPI;
26730 + }
26731 + }
26732 + retval = -DWC_E_INVALID;
26733 + }
26734 +#endif
26735 + core_if->core_params->phy_type = val;
26736 + return retval;
26737 +}
26738 +
26739 +int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if)
26740 +{
26741 + return core_if->core_params->phy_type;
26742 +}
26743 +
26744 +int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val)
26745 +{
26746 + int retval = 0;
26747 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26748 + DWC_WARN("Wrong value for speed parameter\n");
26749 + DWC_WARN("max_speed parameter must be 0 or 1\n");
26750 + return -DWC_E_INVALID;
26751 + }
26752 + if ((val == 0)
26753 + && dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS) {
26754 + if (dwc_otg_param_initialized(core_if->core_params->speed)) {
26755 + DWC_ERROR
26756 + ("%d invalid for speed paremter. Check HW configuration.\n",
26757 + val);
26758 + }
26759 + val =
26760 + (dwc_otg_get_param_phy_type(core_if) ==
26761 + DWC_PHY_TYPE_PARAM_FS ? 1 : 0);
26762 + retval = -DWC_E_INVALID;
26763 + }
26764 + core_if->core_params->speed = val;
26765 + return retval;
26766 +}
26767 +
26768 +int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if)
26769 +{
26770 + return core_if->core_params->speed;
26771 +}
26772 +
26773 +int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if,
26774 + int32_t val)
26775 +{
26776 + int retval = 0;
26777 +
26778 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26779 + DWC_WARN
26780 + ("Wrong value for host_ls_low_power_phy_clk parameter\n");
26781 + DWC_WARN("host_ls_low_power_phy_clk must be 0 or 1\n");
26782 + return -DWC_E_INVALID;
26783 + }
26784 +
26785 + if ((val == DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ)
26786 + && (dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS)) {
26787 + if (dwc_otg_param_initialized
26788 + (core_if->core_params->host_ls_low_power_phy_clk)) {
26789 + DWC_ERROR
26790 + ("%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n",
26791 + val);
26792 + }
26793 + val =
26794 + (dwc_otg_get_param_phy_type(core_if) ==
26795 + DWC_PHY_TYPE_PARAM_FS) ?
26796 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ :
26797 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ;
26798 + retval = -DWC_E_INVALID;
26799 + }
26800 +
26801 + core_if->core_params->host_ls_low_power_phy_clk = val;
26802 + return retval;
26803 +}
26804 +
26805 +int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if)
26806 +{
26807 + return core_if->core_params->host_ls_low_power_phy_clk;
26808 +}
26809 +
26810 +int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if, int32_t val)
26811 +{
26812 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26813 + DWC_WARN("Wrong value for phy_ulpi_ddr\n");
26814 + DWC_WARN("phy_upli_ddr must be 0 or 1\n");
26815 + return -DWC_E_INVALID;
26816 + }
26817 +
26818 + core_if->core_params->phy_ulpi_ddr = val;
26819 + return 0;
26820 +}
26821 +
26822 +int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if)
26823 +{
26824 + return core_if->core_params->phy_ulpi_ddr;
26825 +}
26826 +
26827 +int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
26828 + int32_t val)
26829 +{
26830 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26831 + DWC_WARN("Wrong valaue for phy_ulpi_ext_vbus\n");
26832 + DWC_WARN("phy_ulpi_ext_vbus must be 0 or 1\n");
26833 + return -DWC_E_INVALID;
26834 + }
26835 +
26836 + core_if->core_params->phy_ulpi_ext_vbus = val;
26837 + return 0;
26838 +}
26839 +
26840 +int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if)
26841 +{
26842 + return core_if->core_params->phy_ulpi_ext_vbus;
26843 +}
26844 +
26845 +int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if, int32_t val)
26846 +{
26847 + if (DWC_OTG_PARAM_TEST(val, 8, 8) && DWC_OTG_PARAM_TEST(val, 16, 16)) {
26848 + DWC_WARN("Wrong valaue for phy_utmi_width\n");
26849 + DWC_WARN("phy_utmi_width must be 8 or 16\n");
26850 + return -DWC_E_INVALID;
26851 + }
26852 +
26853 + core_if->core_params->phy_utmi_width = val;
26854 + return 0;
26855 +}
26856 +
26857 +int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if)
26858 +{
26859 + return core_if->core_params->phy_utmi_width;
26860 +}
26861 +
26862 +int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if, int32_t val)
26863 +{
26864 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26865 + DWC_WARN("Wrong valaue for ulpi_fs_ls\n");
26866 + DWC_WARN("ulpi_fs_ls must be 0 or 1\n");
26867 + return -DWC_E_INVALID;
26868 + }
26869 +
26870 + core_if->core_params->ulpi_fs_ls = val;
26871 + return 0;
26872 +}
26873 +
26874 +int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if)
26875 +{
26876 + return core_if->core_params->ulpi_fs_ls;
26877 +}
26878 +
26879 +int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val)
26880 +{
26881 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26882 + DWC_WARN("Wrong valaue for ts_dline\n");
26883 + DWC_WARN("ts_dline must be 0 or 1\n");
26884 + return -DWC_E_INVALID;
26885 + }
26886 +
26887 + core_if->core_params->ts_dline = val;
26888 + return 0;
26889 +}
26890 +
26891 +int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if)
26892 +{
26893 + return core_if->core_params->ts_dline;
26894 +}
26895 +
26896 +int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if, int32_t val)
26897 +{
26898 + int retval = 0;
26899 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26900 + DWC_WARN("Wrong valaue for i2c_enable\n");
26901 + DWC_WARN("i2c_enable must be 0 or 1\n");
26902 + return -DWC_E_INVALID;
26903 + }
26904 +#ifndef NO_FS_PHY_HW_CHECK
26905 + if (val == 1 && core_if->hwcfg3.b.i2c == 0) {
26906 + if (dwc_otg_param_initialized(core_if->core_params->i2c_enable)) {
26907 + DWC_ERROR
26908 + ("%d invalid for i2c_enable. Check HW configuration.\n",
26909 + val);
26910 + }
26911 + val = 0;
26912 + retval = -DWC_E_INVALID;
26913 + }
26914 +#endif
26915 +
26916 + core_if->core_params->i2c_enable = val;
26917 + return retval;
26918 +}
26919 +
26920 +int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if)
26921 +{
26922 + return core_if->core_params->i2c_enable;
26923 +}
26924 +
26925 +int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26926 + int32_t val, int fifo_num)
26927 +{
26928 + int retval = 0;
26929 +
26930 + if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
26931 + DWC_WARN("Wrong value for dev_perio_tx_fifo_size\n");
26932 + DWC_WARN("dev_perio_tx_fifo_size must be 4-768\n");
26933 + return -DWC_E_INVALID;
26934 + }
26935 +
26936 + if (val >
26937 + (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]))) {
26938 + if (dwc_otg_param_initialized
26939 + (core_if->core_params->dev_perio_tx_fifo_size[fifo_num])) {
26940 + DWC_ERROR
26941 + ("`%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n",
26942 + val, fifo_num);
26943 + }
26944 + val = (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]));
26945 + retval = -DWC_E_INVALID;
26946 + }
26947 +
26948 + core_if->core_params->dev_perio_tx_fifo_size[fifo_num] = val;
26949 + return retval;
26950 +}
26951 +
26952 +int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26953 + int fifo_num)
26954 +{
26955 + return core_if->core_params->dev_perio_tx_fifo_size[fifo_num];
26956 +}
26957 +
26958 +int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
26959 + int32_t val)
26960 +{
26961 + int retval = 0;
26962 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26963 + DWC_WARN("Wrong valaue for en_multiple_tx_fifo,\n");
26964 + DWC_WARN("en_multiple_tx_fifo must be 0 or 1\n");
26965 + return -DWC_E_INVALID;
26966 + }
26967 +
26968 + if (val == 1 && core_if->hwcfg4.b.ded_fifo_en == 0) {
26969 + if (dwc_otg_param_initialized
26970 + (core_if->core_params->en_multiple_tx_fifo)) {
26971 + DWC_ERROR
26972 + ("%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n",
26973 + val);
26974 + }
26975 + val = 0;
26976 + retval = -DWC_E_INVALID;
26977 + }
26978 +
26979 + core_if->core_params->en_multiple_tx_fifo = val;
26980 + return retval;
26981 +}
26982 +
26983 +int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if)
26984 +{
26985 + return core_if->core_params->en_multiple_tx_fifo;
26986 +}
26987 +
26988 +int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val,
26989 + int fifo_num)
26990 +{
26991 + int retval = 0;
26992 +
26993 + if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
26994 + DWC_WARN("Wrong value for dev_tx_fifo_size\n");
26995 + DWC_WARN("dev_tx_fifo_size must be 4-768\n");
26996 + return -DWC_E_INVALID;
26997 + }
26998 +
26999 + if (val >
27000 + (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]))) {
27001 + if (dwc_otg_param_initialized
27002 + (core_if->core_params->dev_tx_fifo_size[fifo_num])) {
27003 + DWC_ERROR
27004 + ("`%d' invalid for parameter `dev_tx_fifo_size_%d'. Check HW configuration.\n",
27005 + val, fifo_num);
27006 + }
27007 + val = (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]));
27008 + retval = -DWC_E_INVALID;
27009 + }
27010 +
27011 + core_if->core_params->dev_tx_fifo_size[fifo_num] = val;
27012 + return retval;
27013 +}
27014 +
27015 +int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
27016 + int fifo_num)
27017 +{
27018 + return core_if->core_params->dev_tx_fifo_size[fifo_num];
27019 +}
27020 +
27021 +int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val)
27022 +{
27023 + int retval = 0;
27024 +
27025 + if (DWC_OTG_PARAM_TEST(val, 0, 7)) {
27026 + DWC_WARN("Wrong value for thr_ctl\n");
27027 + DWC_WARN("thr_ctl must be 0-7\n");
27028 + return -DWC_E_INVALID;
27029 + }
27030 +
27031 + if ((val != 0) &&
27032 + (!dwc_otg_get_param_dma_enable(core_if) ||
27033 + !core_if->hwcfg4.b.ded_fifo_en)) {
27034 + if (dwc_otg_param_initialized(core_if->core_params->thr_ctl)) {
27035 + DWC_ERROR
27036 + ("%d invalid for parameter thr_ctl. Check HW configuration.\n",
27037 + val);
27038 + }
27039 + val = 0;
27040 + retval = -DWC_E_INVALID;
27041 + }
27042 +
27043 + core_if->core_params->thr_ctl = val;
27044 + return retval;
27045 +}
27046 +
27047 +int32_t dwc_otg_get_param_thr_ctl(dwc_otg_core_if_t * core_if)
27048 +{
27049 + return core_if->core_params->thr_ctl;
27050 +}
27051 +
27052 +int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if, int32_t val)
27053 +{
27054 + int retval = 0;
27055 +
27056 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27057 + DWC_WARN("Wrong value for lpm_enable\n");
27058 + DWC_WARN("lpm_enable must be 0 or 1\n");
27059 + return -DWC_E_INVALID;
27060 + }
27061 +
27062 + if (val && !core_if->hwcfg3.b.otg_lpm_en) {
27063 + if (dwc_otg_param_initialized(core_if->core_params->lpm_enable)) {
27064 + DWC_ERROR
27065 + ("%d invalid for parameter lpm_enable. Check HW configuration.\n",
27066 + val);
27067 + }
27068 + val = 0;
27069 + retval = -DWC_E_INVALID;
27070 + }
27071 +
27072 + core_if->core_params->lpm_enable = val;
27073 + return retval;
27074 +}
27075 +
27076 +int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if)
27077 +{
27078 + return core_if->core_params->lpm_enable;
27079 +}
27080 +
27081 +int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
27082 +{
27083 + if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
27084 + DWC_WARN("Wrong valaue for tx_thr_length\n");
27085 + DWC_WARN("tx_thr_length must be 8 - 128\n");
27086 + return -DWC_E_INVALID;
27087 + }
27088 +
27089 + core_if->core_params->tx_thr_length = val;
27090 + return 0;
27091 +}
27092 +
27093 +int32_t dwc_otg_get_param_tx_thr_length(dwc_otg_core_if_t * core_if)
27094 +{
27095 + return core_if->core_params->tx_thr_length;
27096 +}
27097 +
27098 +int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
27099 +{
27100 + if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
27101 + DWC_WARN("Wrong valaue for rx_thr_length\n");
27102 + DWC_WARN("rx_thr_length must be 8 - 128\n");
27103 + return -DWC_E_INVALID;
27104 + }
27105 +
27106 + core_if->core_params->rx_thr_length = val;
27107 + return 0;
27108 +}
27109 +
27110 +int32_t dwc_otg_get_param_rx_thr_length(dwc_otg_core_if_t * core_if)
27111 +{
27112 + return core_if->core_params->rx_thr_length;
27113 +}
27114 +
27115 +int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if, int32_t val)
27116 +{
27117 + if (DWC_OTG_PARAM_TEST(val, 1, 1) &&
27118 + DWC_OTG_PARAM_TEST(val, 4, 4) &&
27119 + DWC_OTG_PARAM_TEST(val, 8, 8) &&
27120 + DWC_OTG_PARAM_TEST(val, 16, 16) &&
27121 + DWC_OTG_PARAM_TEST(val, 32, 32) &&
27122 + DWC_OTG_PARAM_TEST(val, 64, 64) &&
27123 + DWC_OTG_PARAM_TEST(val, 128, 128) &&
27124 + DWC_OTG_PARAM_TEST(val, 256, 256)) {
27125 + DWC_WARN("`%d' invalid for parameter `dma_burst_size'\n", val);
27126 + return -DWC_E_INVALID;
27127 + }
27128 + core_if->core_params->dma_burst_size = val;
27129 + return 0;
27130 +}
27131 +
27132 +int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if)
27133 +{
27134 + return core_if->core_params->dma_burst_size;
27135 +}
27136 +
27137 +int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if, int32_t val)
27138 +{
27139 + int retval = 0;
27140 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27141 + DWC_WARN("`%d' invalid for parameter `pti_enable'\n", val);
27142 + return -DWC_E_INVALID;
27143 + }
27144 + if (val && (core_if->snpsid < OTG_CORE_REV_2_72a)) {
27145 + if (dwc_otg_param_initialized(core_if->core_params->pti_enable)) {
27146 + DWC_ERROR
27147 + ("%d invalid for parameter pti_enable. Check HW configuration.\n",
27148 + val);
27149 + }
27150 + retval = -DWC_E_INVALID;
27151 + val = 0;
27152 + }
27153 + core_if->core_params->pti_enable = val;
27154 + return retval;
27155 +}
27156 +
27157 +int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if)
27158 +{
27159 + return core_if->core_params->pti_enable;
27160 +}
27161 +
27162 +int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if, int32_t val)
27163 +{
27164 + int retval = 0;
27165 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27166 + DWC_WARN("`%d' invalid for parameter `mpi_enable'\n", val);
27167 + return -DWC_E_INVALID;
27168 + }
27169 + if (val && (core_if->hwcfg2.b.multi_proc_int == 0)) {
27170 + if (dwc_otg_param_initialized(core_if->core_params->mpi_enable)) {
27171 + DWC_ERROR
27172 + ("%d invalid for parameter mpi_enable. Check HW configuration.\n",
27173 + val);
27174 + }
27175 + retval = -DWC_E_INVALID;
27176 + val = 0;
27177 + }
27178 + core_if->core_params->mpi_enable = val;
27179 + return retval;
27180 +}
27181 +
27182 +int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if)
27183 +{
27184 + return core_if->core_params->mpi_enable;
27185 +}
27186 +
27187 +int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if, int32_t val)
27188 +{
27189 + int retval = 0;
27190 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27191 + DWC_WARN("`%d' invalid for parameter `adp_enable'\n", val);
27192 + return -DWC_E_INVALID;
27193 + }
27194 + if (val && (core_if->hwcfg3.b.adp_supp == 0)) {
27195 + if (dwc_otg_param_initialized
27196 + (core_if->core_params->adp_supp_enable)) {
27197 + DWC_ERROR
27198 + ("%d invalid for parameter adp_enable. Check HW configuration.\n",
27199 + val);
27200 + }
27201 + retval = -DWC_E_INVALID;
27202 + val = 0;
27203 + }
27204 + core_if->core_params->adp_supp_enable = val;
27205 + /*Set OTG version 2.0 in case of enabling ADP*/
27206 + if (val)
27207 + dwc_otg_set_param_otg_ver(core_if, 1);
27208 +
27209 + return retval;
27210 +}
27211 +
27212 +int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if)
27213 +{
27214 + return core_if->core_params->adp_supp_enable;
27215 +}
27216 +
27217 +int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if, int32_t val)
27218 +{
27219 + int retval = 0;
27220 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27221 + DWC_WARN("`%d' invalid for parameter `ic_usb_cap'\n", val);
27222 + DWC_WARN("ic_usb_cap must be 0 or 1\n");
27223 + return -DWC_E_INVALID;
27224 + }
27225 +
27226 + if (val && (core_if->hwcfg2.b.otg_enable_ic_usb == 0)) {
27227 + if (dwc_otg_param_initialized(core_if->core_params->ic_usb_cap)) {
27228 + DWC_ERROR
27229 + ("%d invalid for parameter ic_usb_cap. Check HW configuration.\n",
27230 + val);
27231 + }
27232 + retval = -DWC_E_INVALID;
27233 + val = 0;
27234 + }
27235 + core_if->core_params->ic_usb_cap = val;
27236 + return retval;
27237 +}
27238 +
27239 +int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if)
27240 +{
27241 + return core_if->core_params->ic_usb_cap;
27242 +}
27243 +
27244 +int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if, int32_t val)
27245 +{
27246 + int retval = 0;
27247 + int valid = 1;
27248 +
27249 + if (DWC_OTG_PARAM_TEST(val, 0, 3)) {
27250 + DWC_WARN("`%d' invalid for parameter `ahb_thr_ratio'\n", val);
27251 + DWC_WARN("ahb_thr_ratio must be 0 - 3\n");
27252 + return -DWC_E_INVALID;
27253 + }
27254 +
27255 + if (val
27256 + && (core_if->snpsid < OTG_CORE_REV_2_81a
27257 + || !dwc_otg_get_param_thr_ctl(core_if))) {
27258 + valid = 0;
27259 + } else if (val
27260 + && ((dwc_otg_get_param_tx_thr_length(core_if) / (1 << val)) <
27261 + 4)) {
27262 + valid = 0;
27263 + }
27264 + if (valid == 0) {
27265 + if (dwc_otg_param_initialized
27266 + (core_if->core_params->ahb_thr_ratio)) {
27267 + DWC_ERROR
27268 + ("%d invalid for parameter ahb_thr_ratio. Check HW configuration.\n",
27269 + val);
27270 + }
27271 + retval = -DWC_E_INVALID;
27272 + val = 0;
27273 + }
27274 +
27275 + core_if->core_params->ahb_thr_ratio = val;
27276 + return retval;
27277 +}
27278 +
27279 +int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if)
27280 +{
27281 + return core_if->core_params->ahb_thr_ratio;
27282 +}
27283 +
27284 +int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if, int32_t val)
27285 +{
27286 + int retval = 0;
27287 + int valid = 1;
27288 + hwcfg4_data_t hwcfg4 = {.d32 = 0 };
27289 + hwcfg4.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
27290 +
27291 + if (DWC_OTG_PARAM_TEST(val, 0, 3)) {
27292 + DWC_WARN("`%d' invalid for parameter `power_down'\n", val);
27293 + DWC_WARN("power_down must be 0 - 2\n");
27294 + return -DWC_E_INVALID;
27295 + }
27296 +
27297 + if ((val == 2) && (core_if->snpsid < OTG_CORE_REV_2_91a)) {
27298 + valid = 0;
27299 + }
27300 + if ((val == 3)
27301 + && ((core_if->snpsid < OTG_CORE_REV_3_00a)
27302 + || (hwcfg4.b.xhiber == 0))) {
27303 + valid = 0;
27304 + }
27305 + if (valid == 0) {
27306 + if (dwc_otg_param_initialized(core_if->core_params->power_down)) {
27307 + DWC_ERROR
27308 + ("%d invalid for parameter power_down. Check HW configuration.\n",
27309 + val);
27310 + }
27311 + retval = -DWC_E_INVALID;
27312 + val = 0;
27313 + }
27314 + core_if->core_params->power_down = val;
27315 + return retval;
27316 +}
27317 +
27318 +int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if)
27319 +{
27320 + return core_if->core_params->power_down;
27321 +}
27322 +
27323 +int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if, int32_t val)
27324 +{
27325 + int retval = 0;
27326 + int valid = 1;
27327 +
27328 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27329 + DWC_WARN("`%d' invalid for parameter `reload_ctl'\n", val);
27330 + DWC_WARN("reload_ctl must be 0 or 1\n");
27331 + return -DWC_E_INVALID;
27332 + }
27333 +
27334 + if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_92a)) {
27335 + valid = 0;
27336 + }
27337 + if (valid == 0) {
27338 + if (dwc_otg_param_initialized(core_if->core_params->reload_ctl)) {
27339 + DWC_ERROR("%d invalid for parameter reload_ctl."
27340 + "Check HW configuration.\n", val);
27341 + }
27342 + retval = -DWC_E_INVALID;
27343 + val = 0;
27344 + }
27345 + core_if->core_params->reload_ctl = val;
27346 + return retval;
27347 +}
27348 +
27349 +int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if)
27350 +{
27351 + return core_if->core_params->reload_ctl;
27352 +}
27353 +
27354 +int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if, int32_t val)
27355 +{
27356 + int retval = 0;
27357 + int valid = 1;
27358 +
27359 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27360 + DWC_WARN("`%d' invalid for parameter `dev_out_nak'\n", val);
27361 + DWC_WARN("dev_out_nak must be 0 or 1\n");
27362 + return -DWC_E_INVALID;
27363 + }
27364 +
27365 + if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_93a) ||
27366 + !(core_if->core_params->dma_desc_enable))) {
27367 + valid = 0;
27368 + }
27369 + if (valid == 0) {
27370 + if (dwc_otg_param_initialized(core_if->core_params->dev_out_nak)) {
27371 + DWC_ERROR("%d invalid for parameter dev_out_nak."
27372 + "Check HW configuration.\n", val);
27373 + }
27374 + retval = -DWC_E_INVALID;
27375 + val = 0;
27376 + }
27377 + core_if->core_params->dev_out_nak = val;
27378 + return retval;
27379 +}
27380 +
27381 +int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if)
27382 +{
27383 + return core_if->core_params->dev_out_nak;
27384 +}
27385 +
27386 +int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if, int32_t val)
27387 +{
27388 + int retval = 0;
27389 + int valid = 1;
27390 +
27391 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27392 + DWC_WARN("`%d' invalid for parameter `cont_on_bna'\n", val);
27393 + DWC_WARN("cont_on_bna must be 0 or 1\n");
27394 + return -DWC_E_INVALID;
27395 + }
27396 +
27397 + if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_94a) ||
27398 + !(core_if->core_params->dma_desc_enable))) {
27399 + valid = 0;
27400 + }
27401 + if (valid == 0) {
27402 + if (dwc_otg_param_initialized(core_if->core_params->cont_on_bna)) {
27403 + DWC_ERROR("%d invalid for parameter cont_on_bna."
27404 + "Check HW configuration.\n", val);
27405 + }
27406 + retval = -DWC_E_INVALID;
27407 + val = 0;
27408 + }
27409 + core_if->core_params->cont_on_bna = val;
27410 + return retval;
27411 +}
27412 +
27413 +int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if)
27414 +{
27415 + return core_if->core_params->cont_on_bna;
27416 +}
27417 +
27418 +int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if, int32_t val)
27419 +{
27420 + int retval = 0;
27421 + int valid = 1;
27422 +
27423 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27424 + DWC_WARN("`%d' invalid for parameter `ahb_single'\n", val);
27425 + DWC_WARN("ahb_single must be 0 or 1\n");
27426 + return -DWC_E_INVALID;
27427 + }
27428 +
27429 + if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_94a)) {
27430 + valid = 0;
27431 + }
27432 + if (valid == 0) {
27433 + if (dwc_otg_param_initialized(core_if->core_params->ahb_single)) {
27434 + DWC_ERROR("%d invalid for parameter ahb_single."
27435 + "Check HW configuration.\n", val);
27436 + }
27437 + retval = -DWC_E_INVALID;
27438 + val = 0;
27439 + }
27440 + core_if->core_params->ahb_single = val;
27441 + return retval;
27442 +}
27443 +
27444 +int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if)
27445 +{
27446 + return core_if->core_params->ahb_single;
27447 +}
27448 +
27449 +int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val)
27450 +{
27451 + int retval = 0;
27452 +
27453 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27454 + DWC_WARN("`%d' invalid for parameter `otg_ver'\n", val);
27455 + DWC_WARN
27456 + ("otg_ver must be 0(for OTG 1.3 support) or 1(for OTG 2.0 support)\n");
27457 + return -DWC_E_INVALID;
27458 + }
27459 +
27460 + core_if->core_params->otg_ver = val;
27461 + return retval;
27462 +}
27463 +
27464 +int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if)
27465 +{
27466 + return core_if->core_params->otg_ver;
27467 +}
27468 +
27469 +uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if)
27470 +{
27471 + gotgctl_data_t otgctl;
27472 + otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27473 + return otgctl.b.hstnegscs;
27474 +}
27475 +
27476 +uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if)
27477 +{
27478 + gotgctl_data_t otgctl;
27479 + otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27480 + return otgctl.b.sesreqscs;
27481 +}
27482 +
27483 +void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val)
27484 +{
27485 + if(core_if->otg_ver == 0) {
27486 + gotgctl_data_t otgctl;
27487 + otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27488 + otgctl.b.hnpreq = val;
27489 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, otgctl.d32);
27490 + } else {
27491 + core_if->otg_sts = val;
27492 + }
27493 +}
27494 +
27495 +uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if)
27496 +{
27497 + return core_if->snpsid;
27498 +}
27499 +
27500 +uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if)
27501 +{
27502 + gintsts_data_t gintsts;
27503 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
27504 + return gintsts.b.curmode;
27505 +}
27506 +
27507 +uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if)
27508 +{
27509 + gusbcfg_data_t usbcfg;
27510 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27511 + return usbcfg.b.hnpcap;
27512 +}
27513 +
27514 +void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
27515 +{
27516 + gusbcfg_data_t usbcfg;
27517 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27518 + usbcfg.b.hnpcap = val;
27519 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
27520 +}
27521 +
27522 +uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if)
27523 +{
27524 + gusbcfg_data_t usbcfg;
27525 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27526 + return usbcfg.b.srpcap;
27527 +}
27528 +
27529 +void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
27530 +{
27531 + gusbcfg_data_t usbcfg;
27532 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27533 + usbcfg.b.srpcap = val;
27534 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
27535 +}
27536 +
27537 +uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if)
27538 +{
27539 + dcfg_data_t dcfg;
27540 + /* originally: dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg); */
27541 +
27542 + dcfg.d32 = -1; //GRAYG
27543 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)\n", __func__, core_if);
27544 + if (NULL == core_if)
27545 + DWC_ERROR("reg request with NULL core_if\n");
27546 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)\n", __func__,
27547 + core_if, core_if->dev_if);
27548 + if (NULL == core_if->dev_if)
27549 + DWC_ERROR("reg request with NULL dev_if\n");
27550 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)->"
27551 + "dev_global_regs(%p)\n", __func__,
27552 + core_if, core_if->dev_if,
27553 + core_if->dev_if->dev_global_regs);
27554 + if (NULL == core_if->dev_if->dev_global_regs)
27555 + DWC_ERROR("reg request with NULL dev_global_regs\n");
27556 + else {
27557 + DWC_DEBUGPL(DBG_CILV, "%s - &core_if(%p)->dev_if(%p)->"
27558 + "dev_global_regs(%p)->dcfg = %p\n", __func__,
27559 + core_if, core_if->dev_if,
27560 + core_if->dev_if->dev_global_regs,
27561 + &core_if->dev_if->dev_global_regs->dcfg);
27562 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
27563 + }
27564 + return dcfg.b.devspd;
27565 +}
27566 +
27567 +void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val)
27568 +{
27569 + dcfg_data_t dcfg;
27570 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
27571 + dcfg.b.devspd = val;
27572 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
27573 +}
27574 +
27575 +uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if)
27576 +{
27577 + hprt0_data_t hprt0;
27578 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
27579 + return hprt0.b.prtconnsts;
27580 +}
27581 +
27582 +uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if)
27583 +{
27584 + dsts_data_t dsts;
27585 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
27586 + return dsts.b.enumspd;
27587 +}
27588 +
27589 +uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if)
27590 +{
27591 + hprt0_data_t hprt0;
27592 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
27593 + return hprt0.b.prtpwr;
27594 +
27595 +}
27596 +
27597 +uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if)
27598 +{
27599 + return core_if->hibernation_suspend;
27600 +}
27601 +
27602 +void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val)
27603 +{
27604 + hprt0_data_t hprt0;
27605 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
27606 + hprt0.b.prtpwr = val;
27607 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
27608 +}
27609 +
27610 +uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if)
27611 +{
27612 + hprt0_data_t hprt0;
27613 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
27614 + return hprt0.b.prtsusp;
27615 +
27616 +}
27617 +
27618 +void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val)
27619 +{
27620 + hprt0_data_t hprt0;
27621 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
27622 + hprt0.b.prtsusp = val;
27623 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
27624 +}
27625 +
27626 +uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if)
27627 +{
27628 + hfir_data_t hfir;
27629 + hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
27630 + return hfir.b.frint;
27631 +
27632 +}
27633 +
27634 +void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val)
27635 +{
27636 + hfir_data_t hfir;
27637 + uint32_t fram_int;
27638 + fram_int = calc_frame_interval(core_if);
27639 + hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
27640 + if (!core_if->core_params->reload_ctl) {
27641 + DWC_WARN("\nCannot reload HFIR register.HFIR.HFIRRldCtrl bit is"
27642 + "not set to 1.\nShould load driver with reload_ctl=1"
27643 + " module parameter\n");
27644 + return;
27645 + }
27646 + switch (fram_int) {
27647 + case 3750:
27648 + if ((val < 3350) || (val > 4150)) {
27649 + DWC_WARN("HFIR interval for HS core and 30 MHz"
27650 + "clock freq should be from 3350 to 4150\n");
27651 + return;
27652 + }
27653 + break;
27654 + case 30000:
27655 + if ((val < 26820) || (val > 33180)) {
27656 + DWC_WARN("HFIR interval for FS/LS core and 30 MHz"
27657 + "clock freq should be from 26820 to 33180\n");
27658 + return;
27659 + }
27660 + break;
27661 + case 6000:
27662 + if ((val < 5360) || (val > 6640)) {
27663 + DWC_WARN("HFIR interval for HS core and 48 MHz"
27664 + "clock freq should be from 5360 to 6640\n");
27665 + return;
27666 + }
27667 + break;
27668 + case 48000:
27669 + if ((val < 42912) || (val > 53088)) {
27670 + DWC_WARN("HFIR interval for FS/LS core and 48 MHz"
27671 + "clock freq should be from 42912 to 53088\n");
27672 + return;
27673 + }
27674 + break;
27675 + case 7500:
27676 + if ((val < 6700) || (val > 8300)) {
27677 + DWC_WARN("HFIR interval for HS core and 60 MHz"
27678 + "clock freq should be from 6700 to 8300\n");
27679 + return;
27680 + }
27681 + break;
27682 + case 60000:
27683 + if ((val < 53640) || (val > 65536)) {
27684 + DWC_WARN("HFIR interval for FS/LS core and 60 MHz"
27685 + "clock freq should be from 53640 to 65536\n");
27686 + return;
27687 + }
27688 + break;
27689 + default:
27690 + DWC_WARN("Unknown frame interval\n");
27691 + return;
27692 + break;
27693 +
27694 + }
27695 + hfir.b.frint = val;
27696 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hfir.d32);
27697 +}
27698 +
27699 +uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if)
27700 +{
27701 + hcfg_data_t hcfg;
27702 + hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
27703 + return hcfg.b.modechtimen;
27704 +
27705 +}
27706 +
27707 +void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val)
27708 +{
27709 + hcfg_data_t hcfg;
27710 + hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
27711 + hcfg.b.modechtimen = val;
27712 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
27713 +}
27714 +
27715 +void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val)
27716 +{
27717 + hprt0_data_t hprt0;
27718 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
27719 + hprt0.b.prtres = val;
27720 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
27721 +}
27722 +
27723 +uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if)
27724 +{
27725 + dctl_data_t dctl;
27726 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
27727 + return dctl.b.rmtwkupsig;
27728 +}
27729 +
27730 +uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if)
27731 +{
27732 + glpmcfg_data_t lpmcfg;
27733 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27734 +
27735 + DWC_ASSERT(!
27736 + ((core_if->lx_state == DWC_OTG_L1) ^ lpmcfg.b.prt_sleep_sts),
27737 + "lx_state = %d, lmpcfg.prt_sleep_sts = %d\n",
27738 + core_if->lx_state, lpmcfg.b.prt_sleep_sts);
27739 +
27740 + return lpmcfg.b.prt_sleep_sts;
27741 +}
27742 +
27743 +uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if)
27744 +{
27745 + glpmcfg_data_t lpmcfg;
27746 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27747 + return lpmcfg.b.rem_wkup_en;
27748 +}
27749 +
27750 +uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if)
27751 +{
27752 + glpmcfg_data_t lpmcfg;
27753 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27754 + return lpmcfg.b.appl_resp;
27755 +}
27756 +
27757 +void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val)
27758 +{
27759 + glpmcfg_data_t lpmcfg;
27760 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27761 + lpmcfg.b.appl_resp = val;
27762 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
27763 +}
27764 +
27765 +uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if)
27766 +{
27767 + glpmcfg_data_t lpmcfg;
27768 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27769 + return lpmcfg.b.hsic_connect;
27770 +}
27771 +
27772 +void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val)
27773 +{
27774 + glpmcfg_data_t lpmcfg;
27775 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27776 + lpmcfg.b.hsic_connect = val;
27777 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
27778 +}
27779 +
27780 +uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if)
27781 +{
27782 + glpmcfg_data_t lpmcfg;
27783 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27784 + return lpmcfg.b.inv_sel_hsic;
27785 +
27786 +}
27787 +
27788 +void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val)
27789 +{
27790 + glpmcfg_data_t lpmcfg;
27791 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27792 + lpmcfg.b.inv_sel_hsic = val;
27793 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
27794 +}
27795 +
27796 +uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if)
27797 +{
27798 + return DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27799 +}
27800 +
27801 +void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val)
27802 +{
27803 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, val);
27804 +}
27805 +
27806 +uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if)
27807 +{
27808 + return DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27809 +}
27810 +
27811 +void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val)
27812 +{
27813 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, val);
27814 +}
27815 +
27816 +uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if)
27817 +{
27818 + return DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
27819 +}
27820 +
27821 +void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
27822 +{
27823 + DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, val);
27824 +}
27825 +
27826 +uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if)
27827 +{
27828 + return DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
27829 +}
27830 +
27831 +void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
27832 +{
27833 + DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz, val);
27834 +}
27835 +
27836 +uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if)
27837 +{
27838 + return DWC_READ_REG32(&core_if->core_global_regs->gpvndctl);
27839 +}
27840 +
27841 +void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val)
27842 +{
27843 + DWC_WRITE_REG32(&core_if->core_global_regs->gpvndctl, val);
27844 +}
27845 +
27846 +uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if)
27847 +{
27848 + return DWC_READ_REG32(&core_if->core_global_regs->ggpio);
27849 +}
27850 +
27851 +void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val)
27852 +{
27853 + DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, val);
27854 +}
27855 +
27856 +uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if)
27857 +{
27858 + return DWC_READ_REG32(core_if->host_if->hprt0);
27859 +
27860 +}
27861 +
27862 +void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val)
27863 +{
27864 + DWC_WRITE_REG32(core_if->host_if->hprt0, val);
27865 +}
27866 +
27867 +uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if)
27868 +{
27869 + return DWC_READ_REG32(&core_if->core_global_regs->guid);
27870 +}
27871 +
27872 +void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val)
27873 +{
27874 + DWC_WRITE_REG32(&core_if->core_global_regs->guid, val);
27875 +}
27876 +
27877 +uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if)
27878 +{
27879 + return DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
27880 +}
27881 +
27882 +uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if)
27883 +{
27884 + return ((core_if->otg_ver == 1) ? (uint16_t)0x0200 : (uint16_t)0x0103);
27885 +}
27886 +
27887 +/**
27888 + * Start the SRP timer to detect when the SRP does not complete within
27889 + * 6 seconds.
27890 + *
27891 + * @param core_if the pointer to core_if strucure.
27892 + */
27893 +void dwc_otg_pcd_start_srp_timer(dwc_otg_core_if_t * core_if)
27894 +{
27895 + core_if->srp_timer_started = 1;
27896 + DWC_TIMER_SCHEDULE(core_if->srp_timer, 6000 /* 6 secs */ );
27897 +}
27898 +
27899 +void dwc_otg_initiate_srp(dwc_otg_core_if_t * core_if)
27900 +{
27901 + uint32_t *addr = (uint32_t *) & (core_if->core_global_regs->gotgctl);
27902 + gotgctl_data_t mem;
27903 + gotgctl_data_t val;
27904 +
27905 + val.d32 = DWC_READ_REG32(addr);
27906 + if (val.b.sesreq) {
27907 + DWC_ERROR("Session Request Already active!\n");
27908 + return;
27909 + }
27910 +
27911 + DWC_INFO("Session Request Initated\n"); //NOTICE
27912 + mem.d32 = DWC_READ_REG32(addr);
27913 + mem.b.sesreq = 1;
27914 + DWC_WRITE_REG32(addr, mem.d32);
27915 +
27916 + /* Start the SRP timer */
27917 + dwc_otg_pcd_start_srp_timer(core_if);
27918 + return;
27919 +}
27920 --- /dev/null
27921 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.h
27922 @@ -0,0 +1,1464 @@
27923 +/* ==========================================================================
27924 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.h $
27925 + * $Revision: #123 $
27926 + * $Date: 2012/08/10 $
27927 + * $Change: 2047372 $
27928 + *
27929 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
27930 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
27931 + * otherwise expressly agreed to in writing between Synopsys and you.
27932 + *
27933 + * The Software IS NOT an item of Licensed Software or Licensed Product under
27934 + * any End User Software License Agreement or Agreement for Licensed Product
27935 + * with Synopsys or any supplement thereto. You are permitted to use and
27936 + * redistribute this Software in source and binary forms, with or without
27937 + * modification, provided that redistributions of source code must retain this
27938 + * notice. You may not view, use, disclose, copy or distribute this file or
27939 + * any information contained herein except pursuant to this license grant from
27940 + * Synopsys. If you do not agree with this notice, including the disclaimer
27941 + * below, then you are not authorized to use the Software.
27942 + *
27943 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
27944 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27945 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27946 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
27947 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27948 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27949 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27950 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27951 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27952 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
27953 + * DAMAGE.
27954 + * ========================================================================== */
27955 +
27956 +#if !defined(__DWC_CIL_H__)
27957 +#define __DWC_CIL_H__
27958 +
27959 +#include "dwc_list.h"
27960 +#include "dwc_otg_dbg.h"
27961 +#include "dwc_otg_regs.h"
27962 +
27963 +#include "dwc_otg_core_if.h"
27964 +#include "dwc_otg_adp.h"
27965 +
27966 +/**
27967 + * @file
27968 + * This file contains the interface to the Core Interface Layer.
27969 + */
27970 +
27971 +#ifdef DWC_UTE_CFI
27972 +
27973 +#define MAX_DMA_DESCS_PER_EP 256
27974 +
27975 +/**
27976 + * Enumeration for the data buffer mode
27977 + */
27978 +typedef enum _data_buffer_mode {
27979 + BM_STANDARD = 0, /* data buffer is in normal mode */
27980 + BM_SG = 1, /* data buffer uses the scatter/gather mode */
27981 + BM_CONCAT = 2, /* data buffer uses the concatenation mode */
27982 + BM_CIRCULAR = 3, /* data buffer uses the circular DMA mode */
27983 + BM_ALIGN = 4 /* data buffer is in buffer alignment mode */
27984 +} data_buffer_mode_e;
27985 +#endif //DWC_UTE_CFI
27986 +
27987 +/** Macros defined for DWC OTG HW Release version */
27988 +
27989 +#define OTG_CORE_REV_2_60a 0x4F54260A
27990 +#define OTG_CORE_REV_2_71a 0x4F54271A
27991 +#define OTG_CORE_REV_2_72a 0x4F54272A
27992 +#define OTG_CORE_REV_2_80a 0x4F54280A
27993 +#define OTG_CORE_REV_2_81a 0x4F54281A
27994 +#define OTG_CORE_REV_2_90a 0x4F54290A
27995 +#define OTG_CORE_REV_2_91a 0x4F54291A
27996 +#define OTG_CORE_REV_2_92a 0x4F54292A
27997 +#define OTG_CORE_REV_2_93a 0x4F54293A
27998 +#define OTG_CORE_REV_2_94a 0x4F54294A
27999 +#define OTG_CORE_REV_3_00a 0x4F54300A
28000 +
28001 +/**
28002 + * Information for each ISOC packet.
28003 + */
28004 +typedef struct iso_pkt_info {
28005 + uint32_t offset;
28006 + uint32_t length;
28007 + int32_t status;
28008 +} iso_pkt_info_t;
28009 +
28010 +/**
28011 + * The <code>dwc_ep</code> structure represents the state of a single
28012 + * endpoint when acting in device mode. It contains the data items
28013 + * needed for an endpoint to be activated and transfer packets.
28014 + */
28015 +typedef struct dwc_ep {
28016 + /** EP number used for register address lookup */
28017 + uint8_t num;
28018 + /** EP direction 0 = OUT */
28019 + unsigned is_in:1;
28020 + /** EP active. */
28021 + unsigned active:1;
28022 +
28023 + /**
28024 + * Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic
28025 + * Tx FIFO. If dedicated Tx FIFOs are enabled Tx FIFO # FOR IN EPs*/
28026 + unsigned tx_fifo_num:4;
28027 + /** EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR */
28028 + unsigned type:2;
28029 +#define DWC_OTG_EP_TYPE_CONTROL 0
28030 +#define DWC_OTG_EP_TYPE_ISOC 1
28031 +#define DWC_OTG_EP_TYPE_BULK 2
28032 +#define DWC_OTG_EP_TYPE_INTR 3
28033 +
28034 + /** DATA start PID for INTR and BULK EP */
28035 + unsigned data_pid_start:1;
28036 + /** Frame (even/odd) for ISOC EP */
28037 + unsigned even_odd_frame:1;
28038 + /** Max Packet bytes */
28039 + unsigned maxpacket:11;
28040 +
28041 + /** Max Transfer size */
28042 + uint32_t maxxfer;
28043 +
28044 + /** @name Transfer state */
28045 + /** @{ */
28046 +
28047 + /**
28048 + * Pointer to the beginning of the transfer buffer -- do not modify
28049 + * during transfer.
28050 + */
28051 +
28052 + dwc_dma_t dma_addr;
28053 +
28054 + dwc_dma_t dma_desc_addr;
28055 + dwc_otg_dev_dma_desc_t *desc_addr;
28056 +
28057 + uint8_t *start_xfer_buff;
28058 + /** pointer to the transfer buffer */
28059 + uint8_t *xfer_buff;
28060 + /** Number of bytes to transfer */
28061 + unsigned xfer_len:19;
28062 + /** Number of bytes transferred. */
28063 + unsigned xfer_count:19;
28064 + /** Sent ZLP */
28065 + unsigned sent_zlp:1;
28066 + /** Total len for control transfer */
28067 + unsigned total_len:19;
28068 +
28069 + /** stall clear flag */
28070 + unsigned stall_clear_flag:1;
28071 +
28072 + /** SETUP pkt cnt rollover flag for EP0 out*/
28073 + unsigned stp_rollover;
28074 +
28075 +#ifdef DWC_UTE_CFI
28076 + /* The buffer mode */
28077 + data_buffer_mode_e buff_mode;
28078 +
28079 + /* The chain of DMA descriptors.
28080 + * MAX_DMA_DESCS_PER_EP will be allocated for each active EP.
28081 + */
28082 + dwc_otg_dma_desc_t *descs;
28083 +
28084 + /* The DMA address of the descriptors chain start */
28085 + dma_addr_t descs_dma_addr;
28086 + /** This variable stores the length of the last enqueued request */
28087 + uint32_t cfi_req_len;
28088 +#endif //DWC_UTE_CFI
28089 +
28090 +/** Max DMA Descriptor count for any EP */
28091 +#define MAX_DMA_DESC_CNT 256
28092 + /** Allocated DMA Desc count */
28093 + uint32_t desc_cnt;
28094 +
28095 + /** bInterval */
28096 + uint32_t bInterval;
28097 + /** Next frame num to setup next ISOC transfer */
28098 + uint32_t frame_num;
28099 + /** Indicates SOF number overrun in DSTS */
28100 + uint8_t frm_overrun;
28101 +
28102 +#ifdef DWC_UTE_PER_IO
28103 + /** Next frame num for which will be setup DMA Desc */
28104 + uint32_t xiso_frame_num;
28105 + /** bInterval */
28106 + uint32_t xiso_bInterval;
28107 + /** Count of currently active transfers - shall be either 0 or 1 */
28108 + int xiso_active_xfers;
28109 + int xiso_queued_xfers;
28110 +#endif
28111 +#ifdef DWC_EN_ISOC
28112 + /**
28113 + * Variables specific for ISOC EPs
28114 + *
28115 + */
28116 + /** DMA addresses of ISOC buffers */
28117 + dwc_dma_t dma_addr0;
28118 + dwc_dma_t dma_addr1;
28119 +
28120 + dwc_dma_t iso_dma_desc_addr;
28121 + dwc_otg_dev_dma_desc_t *iso_desc_addr;
28122 +
28123 + /** pointer to the transfer buffers */
28124 + uint8_t *xfer_buff0;
28125 + uint8_t *xfer_buff1;
28126 +
28127 + /** number of ISOC Buffer is processing */
28128 + uint32_t proc_buf_num;
28129 + /** Interval of ISOC Buffer processing */
28130 + uint32_t buf_proc_intrvl;
28131 + /** Data size for regular frame */
28132 + uint32_t data_per_frame;
28133 +
28134 + /* todo - pattern data support is to be implemented in the future */
28135 + /** Data size for pattern frame */
28136 + uint32_t data_pattern_frame;
28137 + /** Frame number of pattern data */
28138 + uint32_t sync_frame;
28139 +
28140 + /** bInterval */
28141 + uint32_t bInterval;
28142 + /** ISO Packet number per frame */
28143 + uint32_t pkt_per_frm;
28144 + /** Next frame num for which will be setup DMA Desc */
28145 + uint32_t next_frame;
28146 + /** Number of packets per buffer processing */
28147 + uint32_t pkt_cnt;
28148 + /** Info for all isoc packets */
28149 + iso_pkt_info_t *pkt_info;
28150 + /** current pkt number */
28151 + uint32_t cur_pkt;
28152 + /** current pkt number */
28153 + uint8_t *cur_pkt_addr;
28154 + /** current pkt number */
28155 + uint32_t cur_pkt_dma_addr;
28156 +#endif /* DWC_EN_ISOC */
28157 +
28158 +/** @} */
28159 +} dwc_ep_t;
28160 +
28161 +/*
28162 + * Reasons for halting a host channel.
28163 + */
28164 +typedef enum dwc_otg_halt_status {
28165 + DWC_OTG_HC_XFER_NO_HALT_STATUS,
28166 + DWC_OTG_HC_XFER_COMPLETE,
28167 + DWC_OTG_HC_XFER_URB_COMPLETE,
28168 + DWC_OTG_HC_XFER_ACK,
28169 + DWC_OTG_HC_XFER_NAK,
28170 + DWC_OTG_HC_XFER_NYET,
28171 + DWC_OTG_HC_XFER_STALL,
28172 + DWC_OTG_HC_XFER_XACT_ERR,
28173 + DWC_OTG_HC_XFER_FRAME_OVERRUN,
28174 + DWC_OTG_HC_XFER_BABBLE_ERR,
28175 + DWC_OTG_HC_XFER_DATA_TOGGLE_ERR,
28176 + DWC_OTG_HC_XFER_AHB_ERR,
28177 + DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE,
28178 + DWC_OTG_HC_XFER_URB_DEQUEUE
28179 +} dwc_otg_halt_status_e;
28180 +
28181 +/**
28182 + * Host channel descriptor. This structure represents the state of a single
28183 + * host channel when acting in host mode. It contains the data items needed to
28184 + * transfer packets to an endpoint via a host channel.
28185 + */
28186 +typedef struct dwc_hc {
28187 + /** Host channel number used for register address lookup */
28188 + uint8_t hc_num;
28189 +
28190 + /** Device to access */
28191 + unsigned dev_addr:7;
28192 +
28193 + /** EP to access */
28194 + unsigned ep_num:4;
28195 +
28196 + /** EP direction. 0: OUT, 1: IN */
28197 + unsigned ep_is_in:1;
28198 +
28199 + /**
28200 + * EP speed.
28201 + * One of the following values:
28202 + * - DWC_OTG_EP_SPEED_LOW
28203 + * - DWC_OTG_EP_SPEED_FULL
28204 + * - DWC_OTG_EP_SPEED_HIGH
28205 + */
28206 + unsigned speed:2;
28207 +#define DWC_OTG_EP_SPEED_LOW 0
28208 +#define DWC_OTG_EP_SPEED_FULL 1
28209 +#define DWC_OTG_EP_SPEED_HIGH 2
28210 +
28211 + /**
28212 + * Endpoint type.
28213 + * One of the following values:
28214 + * - DWC_OTG_EP_TYPE_CONTROL: 0
28215 + * - DWC_OTG_EP_TYPE_ISOC: 1
28216 + * - DWC_OTG_EP_TYPE_BULK: 2
28217 + * - DWC_OTG_EP_TYPE_INTR: 3
28218 + */
28219 + unsigned ep_type:2;
28220 +
28221 + /** Max packet size in bytes */
28222 + unsigned max_packet:11;
28223 +
28224 + /**
28225 + * PID for initial transaction.
28226 + * 0: DATA0,<br>
28227 + * 1: DATA2,<br>
28228 + * 2: DATA1,<br>
28229 + * 3: MDATA (non-Control EP),
28230 + * SETUP (Control EP)
28231 + */
28232 + unsigned data_pid_start:2;
28233 +#define DWC_OTG_HC_PID_DATA0 0
28234 +#define DWC_OTG_HC_PID_DATA2 1
28235 +#define DWC_OTG_HC_PID_DATA1 2
28236 +#define DWC_OTG_HC_PID_MDATA 3
28237 +#define DWC_OTG_HC_PID_SETUP 3
28238 +
28239 + /** Number of periodic transactions per (micro)frame */
28240 + unsigned multi_count:2;
28241 +
28242 + /** @name Transfer State */
28243 + /** @{ */
28244 +
28245 + /** Pointer to the current transfer buffer position. */
28246 + uint8_t *xfer_buff;
28247 + /**
28248 + * In Buffer DMA mode this buffer will be used
28249 + * if xfer_buff is not DWORD aligned.
28250 + */
28251 + dwc_dma_t align_buff;
28252 + /** Total number of bytes to transfer. */
28253 + uint32_t xfer_len;
28254 + /** Number of bytes transferred so far. */
28255 + uint32_t xfer_count;
28256 + /** Packet count at start of transfer.*/
28257 + uint16_t start_pkt_count;
28258 +
28259 + /**
28260 + * Flag to indicate whether the transfer has been started. Set to 1 if
28261 + * it has been started, 0 otherwise.
28262 + */
28263 + uint8_t xfer_started;
28264 +
28265 + /**
28266 + * Set to 1 to indicate that a PING request should be issued on this
28267 + * channel. If 0, process normally.
28268 + */
28269 + uint8_t do_ping;
28270 +
28271 + /**
28272 + * Set to 1 to indicate that the error count for this transaction is
28273 + * non-zero. Set to 0 if the error count is 0.
28274 + */
28275 + uint8_t error_state;
28276 +
28277 + /**
28278 + * Set to 1 to indicate that this channel should be halted the next
28279 + * time a request is queued for the channel. This is necessary in
28280 + * slave mode if no request queue space is available when an attempt
28281 + * is made to halt the channel.
28282 + */
28283 + uint8_t halt_on_queue;
28284 +
28285 + /**
28286 + * Set to 1 if the host channel has been halted, but the core is not
28287 + * finished flushing queued requests. Otherwise 0.
28288 + */
28289 + uint8_t halt_pending;
28290 +
28291 + /**
28292 + * Reason for halting the host channel.
28293 + */
28294 + dwc_otg_halt_status_e halt_status;
28295 +
28296 + /*
28297 + * Split settings for the host channel
28298 + */
28299 + uint8_t do_split; /**< Enable split for the channel */
28300 + uint8_t complete_split; /**< Enable complete split */
28301 + uint8_t hub_addr; /**< Address of high speed hub */
28302 +
28303 + uint8_t port_addr; /**< Port of the low/full speed device */
28304 + /** Split transaction position
28305 + * One of the following values:
28306 + * - DWC_HCSPLIT_XACTPOS_MID
28307 + * - DWC_HCSPLIT_XACTPOS_BEGIN
28308 + * - DWC_HCSPLIT_XACTPOS_END
28309 + * - DWC_HCSPLIT_XACTPOS_ALL */
28310 + uint8_t xact_pos;
28311 +
28312 + /** Set when the host channel does a short read. */
28313 + uint8_t short_read;
28314 +
28315 + /**
28316 + * Number of requests issued for this channel since it was assigned to
28317 + * the current transfer (not counting PINGs).
28318 + */
28319 + uint8_t requests;
28320 +
28321 + /**
28322 + * Queue Head for the transfer being processed by this channel.
28323 + */
28324 + struct dwc_otg_qh *qh;
28325 +
28326 + /** @} */
28327 +
28328 + /** Entry in list of host channels. */
28329 + DWC_CIRCLEQ_ENTRY(dwc_hc) hc_list_entry;
28330 +
28331 + /** @name Descriptor DMA support */
28332 + /** @{ */
28333 +
28334 + /** Number of Transfer Descriptors */
28335 + uint16_t ntd;
28336 +
28337 + /** Descriptor List DMA address */
28338 + dwc_dma_t desc_list_addr;
28339 +
28340 + /** Scheduling micro-frame bitmap. */
28341 + uint8_t schinfo;
28342 +
28343 + /** @} */
28344 +} dwc_hc_t;
28345 +
28346 +/**
28347 + * The following parameters may be specified when starting the module. These
28348 + * parameters define how the DWC_otg controller should be configured.
28349 + */
28350 +typedef struct dwc_otg_core_params {
28351 + int32_t opt;
28352 +
28353 + /**
28354 + * Specifies the OTG capabilities. The driver will automatically
28355 + * detect the value for this parameter if none is specified.
28356 + * 0 - HNP and SRP capable (default)
28357 + * 1 - SRP Only capable
28358 + * 2 - No HNP/SRP capable
28359 + */
28360 + int32_t otg_cap;
28361 +
28362 + /**
28363 + * Specifies whether to use slave or DMA mode for accessing the data
28364 + * FIFOs. The driver will automatically detect the value for this
28365 + * parameter if none is specified.
28366 + * 0 - Slave
28367 + * 1 - DMA (default, if available)
28368 + */
28369 + int32_t dma_enable;
28370 +
28371 + /**
28372 + * When DMA mode is enabled specifies whether to use address DMA or DMA
28373 + * Descriptor mode for accessing the data FIFOs in device mode. The driver
28374 + * will automatically detect the value for this if none is specified.
28375 + * 0 - address DMA
28376 + * 1 - DMA Descriptor(default, if available)
28377 + */
28378 + int32_t dma_desc_enable;
28379 + /** The DMA Burst size (applicable only for External DMA
28380 + * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
28381 + */
28382 + int32_t dma_burst_size; /* Translate this to GAHBCFG values */
28383 +
28384 + /**
28385 + * Specifies the maximum speed of operation in host and device mode.
28386 + * The actual speed depends on the speed of the attached device and
28387 + * the value of phy_type. The actual speed depends on the speed of the
28388 + * attached device.
28389 + * 0 - High Speed (default)
28390 + * 1 - Full Speed
28391 + */
28392 + int32_t speed;
28393 + /** Specifies whether low power mode is supported when attached
28394 + * to a Full Speed or Low Speed device in host mode.
28395 + * 0 - Don't support low power mode (default)
28396 + * 1 - Support low power mode
28397 + */
28398 + int32_t host_support_fs_ls_low_power;
28399 +
28400 + /** Specifies the PHY clock rate in low power mode when connected to a
28401 + * Low Speed device in host mode. This parameter is applicable only if
28402 + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
28403 + * then defaults to 6 MHZ otherwise 48 MHZ.
28404 + *
28405 + * 0 - 48 MHz
28406 + * 1 - 6 MHz
28407 + */
28408 + int32_t host_ls_low_power_phy_clk;
28409 +
28410 + /**
28411 + * 0 - Use cC FIFO size parameters
28412 + * 1 - Allow dynamic FIFO sizing (default)
28413 + */
28414 + int32_t enable_dynamic_fifo;
28415 +
28416 + /** Total number of 4-byte words in the data FIFO memory. This
28417 + * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
28418 + * Tx FIFOs.
28419 + * 32 to 32768 (default 8192)
28420 + * Note: The total FIFO memory depth in the FPGA configuration is 8192.
28421 + */
28422 + int32_t data_fifo_size;
28423 +
28424 + /** Number of 4-byte words in the Rx FIFO in device mode when dynamic
28425 + * FIFO sizing is enabled.
28426 + * 16 to 32768 (default 1064)
28427 + */
28428 + int32_t dev_rx_fifo_size;
28429 +
28430 + /** Number of 4-byte words in the non-periodic Tx FIFO in device mode
28431 + * when dynamic FIFO sizing is enabled.
28432 + * 16 to 32768 (default 1024)
28433 + */
28434 + int32_t dev_nperio_tx_fifo_size;
28435 +
28436 + /** Number of 4-byte words in each of the periodic Tx FIFOs in device
28437 + * mode when dynamic FIFO sizing is enabled.
28438 + * 4 to 768 (default 256)
28439 + */
28440 + uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
28441 +
28442 + /** Number of 4-byte words in the Rx FIFO in host mode when dynamic
28443 + * FIFO sizing is enabled.
28444 + * 16 to 32768 (default 1024)
28445 + */
28446 + int32_t host_rx_fifo_size;
28447 +
28448 + /** Number of 4-byte words in the non-periodic Tx FIFO in host mode
28449 + * when Dynamic FIFO sizing is enabled in the core.
28450 + * 16 to 32768 (default 1024)
28451 + */
28452 + int32_t host_nperio_tx_fifo_size;
28453 +
28454 + /** Number of 4-byte words in the host periodic Tx FIFO when dynamic
28455 + * FIFO sizing is enabled.
28456 + * 16 to 32768 (default 1024)
28457 + */
28458 + int32_t host_perio_tx_fifo_size;
28459 +
28460 + /** The maximum transfer size supported in bytes.
28461 + * 2047 to 65,535 (default 65,535)
28462 + */
28463 + int32_t max_transfer_size;
28464 +
28465 + /** The maximum number of packets in a transfer.
28466 + * 15 to 511 (default 511)
28467 + */
28468 + int32_t max_packet_count;
28469 +
28470 + /** The number of host channel registers to use.
28471 + * 1 to 16 (default 12)
28472 + * Note: The FPGA configuration supports a maximum of 12 host channels.
28473 + */
28474 + int32_t host_channels;
28475 +
28476 + /** The number of endpoints in addition to EP0 available for device
28477 + * mode operations.
28478 + * 1 to 15 (default 6 IN and OUT)
28479 + * Note: The FPGA configuration supports a maximum of 6 IN and OUT
28480 + * endpoints in addition to EP0.
28481 + */
28482 + int32_t dev_endpoints;
28483 +
28484 + /**
28485 + * Specifies the type of PHY interface to use. By default, the driver
28486 + * will automatically detect the phy_type.
28487 + *
28488 + * 0 - Full Speed PHY
28489 + * 1 - UTMI+ (default)
28490 + * 2 - ULPI
28491 + */
28492 + int32_t phy_type;
28493 +
28494 + /**
28495 + * Specifies the UTMI+ Data Width. This parameter is
28496 + * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
28497 + * PHY_TYPE, this parameter indicates the data width between
28498 + * the MAC and the ULPI Wrapper.) Also, this parameter is
28499 + * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
28500 + * to "8 and 16 bits", meaning that the core has been
28501 + * configured to work at either data path width.
28502 + *
28503 + * 8 or 16 bits (default 16)
28504 + */
28505 + int32_t phy_utmi_width;
28506 +
28507 + /**
28508 + * Specifies whether the ULPI operates at double or single
28509 + * data rate. This parameter is only applicable if PHY_TYPE is
28510 + * ULPI.
28511 + *
28512 + * 0 - single data rate ULPI interface with 8 bit wide data
28513 + * bus (default)
28514 + * 1 - double data rate ULPI interface with 4 bit wide data
28515 + * bus
28516 + */
28517 + int32_t phy_ulpi_ddr;
28518 +
28519 + /**
28520 + * Specifies whether to use the internal or external supply to
28521 + * drive the vbus with a ULPI phy.
28522 + */
28523 + int32_t phy_ulpi_ext_vbus;
28524 +
28525 + /**
28526 + * Specifies whether to use the I2Cinterface for full speed PHY. This
28527 + * parameter is only applicable if PHY_TYPE is FS.
28528 + * 0 - No (default)
28529 + * 1 - Yes
28530 + */
28531 + int32_t i2c_enable;
28532 +
28533 + int32_t ulpi_fs_ls;
28534 +
28535 + int32_t ts_dline;
28536 +
28537 + /**
28538 + * Specifies whether dedicated transmit FIFOs are
28539 + * enabled for non periodic IN endpoints in device mode
28540 + * 0 - No
28541 + * 1 - Yes
28542 + */
28543 + int32_t en_multiple_tx_fifo;
28544 +
28545 + /** Number of 4-byte words in each of the Tx FIFOs in device
28546 + * mode when dynamic FIFO sizing is enabled.
28547 + * 4 to 768 (default 256)
28548 + */
28549 + uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
28550 +
28551 + /** Thresholding enable flag-
28552 + * bit 0 - enable non-ISO Tx thresholding
28553 + * bit 1 - enable ISO Tx thresholding
28554 + * bit 2 - enable Rx thresholding
28555 + */
28556 + uint32_t thr_ctl;
28557 +
28558 + /** Thresholding length for Tx
28559 + * FIFOs in 32 bit DWORDs
28560 + */
28561 + uint32_t tx_thr_length;
28562 +
28563 + /** Thresholding length for Rx
28564 + * FIFOs in 32 bit DWORDs
28565 + */
28566 + uint32_t rx_thr_length;
28567 +
28568 + /**
28569 + * Specifies whether LPM (Link Power Management) support is enabled
28570 + */
28571 + int32_t lpm_enable;
28572 +
28573 + /** Per Transfer Interrupt
28574 + * mode enable flag
28575 + * 1 - Enabled
28576 + * 0 - Disabled
28577 + */
28578 + int32_t pti_enable;
28579 +
28580 + /** Multi Processor Interrupt
28581 + * mode enable flag
28582 + * 1 - Enabled
28583 + * 0 - Disabled
28584 + */
28585 + int32_t mpi_enable;
28586 +
28587 + /** IS_USB Capability
28588 + * 1 - Enabled
28589 + * 0 - Disabled
28590 + */
28591 + int32_t ic_usb_cap;
28592 +
28593 + /** AHB Threshold Ratio
28594 + * 2'b00 AHB Threshold = MAC Threshold
28595 + * 2'b01 AHB Threshold = 1/2 MAC Threshold
28596 + * 2'b10 AHB Threshold = 1/4 MAC Threshold
28597 + * 2'b11 AHB Threshold = 1/8 MAC Threshold
28598 + */
28599 + int32_t ahb_thr_ratio;
28600 +
28601 + /** ADP Support
28602 + * 1 - Enabled
28603 + * 0 - Disabled
28604 + */
28605 + int32_t adp_supp_enable;
28606 +
28607 + /** HFIR Reload Control
28608 + * 0 - The HFIR cannot be reloaded dynamically.
28609 + * 1 - Allow dynamic reloading of the HFIR register during runtime.
28610 + */
28611 + int32_t reload_ctl;
28612 +
28613 + /** DCFG: Enable device Out NAK
28614 + * 0 - The core does not set NAK after Bulk Out transfer complete.
28615 + * 1 - The core sets NAK after Bulk OUT transfer complete.
28616 + */
28617 + int32_t dev_out_nak;
28618 +
28619 + /** DCFG: Enable Continue on BNA
28620 + * After receiving BNA interrupt the core disables the endpoint,when the
28621 + * endpoint is re-enabled by the application the core starts processing
28622 + * 0 - from the DOEPDMA descriptor
28623 + * 1 - from the descriptor which received the BNA.
28624 + */
28625 + int32_t cont_on_bna;
28626 +
28627 + /** GAHBCFG: AHB Single Support
28628 + * This bit when programmed supports SINGLE transfers for remainder
28629 + * data in a transfer for DMA mode of operation.
28630 + * 0 - in this case the remainder data will be sent using INCR burst size.
28631 + * 1 - in this case the remainder data will be sent using SINGLE burst size.
28632 + */
28633 + int32_t ahb_single;
28634 +
28635 + /** Core Power down mode
28636 + * 0 - No Power Down is enabled
28637 + * 1 - Reserved
28638 + * 2 - Complete Power Down (Hibernation)
28639 + */
28640 + int32_t power_down;
28641 +
28642 + /** OTG revision supported
28643 + * 0 - OTG 1.3 revision
28644 + * 1 - OTG 2.0 revision
28645 + */
28646 + int32_t otg_ver;
28647 +
28648 +} dwc_otg_core_params_t;
28649 +
28650 +#ifdef DEBUG
28651 +struct dwc_otg_core_if;
28652 +typedef struct hc_xfer_info {
28653 + struct dwc_otg_core_if *core_if;
28654 + dwc_hc_t *hc;
28655 +} hc_xfer_info_t;
28656 +#endif
28657 +
28658 +typedef struct ep_xfer_info {
28659 + struct dwc_otg_core_if *core_if;
28660 + dwc_ep_t *ep;
28661 + uint8_t state;
28662 +} ep_xfer_info_t;
28663 +/*
28664 + * Device States
28665 + */
28666 +typedef enum dwc_otg_lx_state {
28667 + /** On state */
28668 + DWC_OTG_L0,
28669 + /** LPM sleep state*/
28670 + DWC_OTG_L1,
28671 + /** USB suspend state*/
28672 + DWC_OTG_L2,
28673 + /** Off state*/
28674 + DWC_OTG_L3
28675 +} dwc_otg_lx_state_e;
28676 +
28677 +struct dwc_otg_global_regs_backup {
28678 + uint32_t gotgctl_local;
28679 + uint32_t gintmsk_local;
28680 + uint32_t gahbcfg_local;
28681 + uint32_t gusbcfg_local;
28682 + uint32_t grxfsiz_local;
28683 + uint32_t gnptxfsiz_local;
28684 +#ifdef CONFIG_USB_DWC_OTG_LPM
28685 + uint32_t glpmcfg_local;
28686 +#endif
28687 + uint32_t gi2cctl_local;
28688 + uint32_t hptxfsiz_local;
28689 + uint32_t pcgcctl_local;
28690 + uint32_t gdfifocfg_local;
28691 + uint32_t dtxfsiz_local[MAX_EPS_CHANNELS];
28692 + uint32_t gpwrdn_local;
28693 + uint32_t xhib_pcgcctl;
28694 + uint32_t xhib_gpwrdn;
28695 +};
28696 +
28697 +struct dwc_otg_host_regs_backup {
28698 + uint32_t hcfg_local;
28699 + uint32_t haintmsk_local;
28700 + uint32_t hcintmsk_local[MAX_EPS_CHANNELS];
28701 + uint32_t hprt0_local;
28702 + uint32_t hfir_local;
28703 +};
28704 +
28705 +struct dwc_otg_dev_regs_backup {
28706 + uint32_t dcfg;
28707 + uint32_t dctl;
28708 + uint32_t daintmsk;
28709 + uint32_t diepmsk;
28710 + uint32_t doepmsk;
28711 + uint32_t diepctl[MAX_EPS_CHANNELS];
28712 + uint32_t dieptsiz[MAX_EPS_CHANNELS];
28713 + uint32_t diepdma[MAX_EPS_CHANNELS];
28714 +};
28715 +/**
28716 + * The <code>dwc_otg_core_if</code> structure contains information needed to manage
28717 + * the DWC_otg controller acting in either host or device mode. It
28718 + * represents the programming view of the controller as a whole.
28719 + */
28720 +struct dwc_otg_core_if {
28721 + /** Parameters that define how the core should be configured.*/
28722 + dwc_otg_core_params_t *core_params;
28723 +
28724 + /** Core Global registers starting at offset 000h. */
28725 + dwc_otg_core_global_regs_t *core_global_regs;
28726 +
28727 + /** Device-specific information */
28728 + dwc_otg_dev_if_t *dev_if;
28729 + /** Host-specific information */
28730 + dwc_otg_host_if_t *host_if;
28731 +
28732 + /** Value from SNPSID register */
28733 + uint32_t snpsid;
28734 +
28735 + /*
28736 + * Set to 1 if the core PHY interface bits in USBCFG have been
28737 + * initialized.
28738 + */
28739 + uint8_t phy_init_done;
28740 +
28741 + /*
28742 + * SRP Success flag, set by srp success interrupt in FS I2C mode
28743 + */
28744 + uint8_t srp_success;
28745 + uint8_t srp_timer_started;
28746 + /** Timer for SRP. If it expires before SRP is successful
28747 + * clear the SRP. */
28748 + dwc_timer_t *srp_timer;
28749 +
28750 +#ifdef DWC_DEV_SRPCAP
28751 + /* This timer is needed to power on the hibernated host core if SRP is not
28752 + * initiated on connected SRP capable device for limited period of time
28753 + */
28754 + uint8_t pwron_timer_started;
28755 + dwc_timer_t *pwron_timer;
28756 +#endif
28757 + /* Common configuration information */
28758 + /** Power and Clock Gating Control Register */
28759 + volatile uint32_t *pcgcctl;
28760 +#define DWC_OTG_PCGCCTL_OFFSET 0xE00
28761 +
28762 + /** Push/pop addresses for endpoints or host channels.*/
28763 + uint32_t *data_fifo[MAX_EPS_CHANNELS];
28764 +#define DWC_OTG_DATA_FIFO_OFFSET 0x1000
28765 +#define DWC_OTG_DATA_FIFO_SIZE 0x1000
28766 +
28767 + /** Total RAM for FIFOs (Bytes) */
28768 + uint16_t total_fifo_size;
28769 + /** Size of Rx FIFO (Bytes) */
28770 + uint16_t rx_fifo_size;
28771 + /** Size of Non-periodic Tx FIFO (Bytes) */
28772 + uint16_t nperio_tx_fifo_size;
28773 +
28774 + /** 1 if DMA is enabled, 0 otherwise. */
28775 + uint8_t dma_enable;
28776 +
28777 + /** 1 if DMA descriptor is enabled, 0 otherwise. */
28778 + uint8_t dma_desc_enable;
28779 +
28780 + /** 1 if PTI Enhancement mode is enabled, 0 otherwise. */
28781 + uint8_t pti_enh_enable;
28782 +
28783 + /** 1 if MPI Enhancement mode is enabled, 0 otherwise. */
28784 + uint8_t multiproc_int_enable;
28785 +
28786 + /** 1 if dedicated Tx FIFOs are enabled, 0 otherwise. */
28787 + uint8_t en_multiple_tx_fifo;
28788 +
28789 + /** Set to 1 if multiple packets of a high-bandwidth transfer is in
28790 + * process of being queued */
28791 + uint8_t queuing_high_bandwidth;
28792 +
28793 + /** Hardware Configuration -- stored here for convenience.*/
28794 + hwcfg1_data_t hwcfg1;
28795 + hwcfg2_data_t hwcfg2;
28796 + hwcfg3_data_t hwcfg3;
28797 + hwcfg4_data_t hwcfg4;
28798 + fifosize_data_t hptxfsiz;
28799 +
28800 + /** Host and Device Configuration -- stored here for convenience.*/
28801 + hcfg_data_t hcfg;
28802 + dcfg_data_t dcfg;
28803 +
28804 + /** The operational State, during transations
28805 + * (a_host>>a_peripherial and b_device=>b_host) this may not
28806 + * match the core but allows the software to determine
28807 + * transitions.
28808 + */
28809 + uint8_t op_state;
28810 +
28811 + /**
28812 + * Set to 1 if the HCD needs to be restarted on a session request
28813 + * interrupt. This is required if no connector ID status change has
28814 + * occurred since the HCD was last disconnected.
28815 + */
28816 + uint8_t restart_hcd_on_session_req;
28817 +
28818 + /** HCD callbacks */
28819 + /** A-Device is a_host */
28820 +#define A_HOST (1)
28821 + /** A-Device is a_suspend */
28822 +#define A_SUSPEND (2)
28823 + /** A-Device is a_peripherial */
28824 +#define A_PERIPHERAL (3)
28825 + /** B-Device is operating as a Peripheral. */
28826 +#define B_PERIPHERAL (4)
28827 + /** B-Device is operating as a Host. */
28828 +#define B_HOST (5)
28829 +
28830 + /** HCD callbacks */
28831 + struct dwc_otg_cil_callbacks *hcd_cb;
28832 + /** PCD callbacks */
28833 + struct dwc_otg_cil_callbacks *pcd_cb;
28834 +
28835 + /** Device mode Periodic Tx FIFO Mask */
28836 + uint32_t p_tx_msk;
28837 + /** Device mode Periodic Tx FIFO Mask */
28838 + uint32_t tx_msk;
28839 +
28840 + /** Workqueue object used for handling several interrupts */
28841 + dwc_workq_t *wq_otg;
28842 +
28843 + /** Timer object used for handling "Wakeup Detected" Interrupt */
28844 + dwc_timer_t *wkp_timer;
28845 + /** This arrays used for debug purposes for DEV OUT NAK enhancement */
28846 + uint32_t start_doeptsiz_val[MAX_EPS_CHANNELS];
28847 + ep_xfer_info_t ep_xfer_info[MAX_EPS_CHANNELS];
28848 + dwc_timer_t *ep_xfer_timer[MAX_EPS_CHANNELS];
28849 +#ifdef DEBUG
28850 + uint32_t start_hcchar_val[MAX_EPS_CHANNELS];
28851 +
28852 + hc_xfer_info_t hc_xfer_info[MAX_EPS_CHANNELS];
28853 + dwc_timer_t *hc_xfer_timer[MAX_EPS_CHANNELS];
28854 +
28855 + uint32_t hfnum_7_samples;
28856 + uint64_t hfnum_7_frrem_accum;
28857 + uint32_t hfnum_0_samples;
28858 + uint64_t hfnum_0_frrem_accum;
28859 + uint32_t hfnum_other_samples;
28860 + uint64_t hfnum_other_frrem_accum;
28861 +#endif
28862 +
28863 +#ifdef DWC_UTE_CFI
28864 + uint16_t pwron_rxfsiz;
28865 + uint16_t pwron_gnptxfsiz;
28866 + uint16_t pwron_txfsiz[15];
28867 +
28868 + uint16_t init_rxfsiz;
28869 + uint16_t init_gnptxfsiz;
28870 + uint16_t init_txfsiz[15];
28871 +#endif
28872 +
28873 + /** Lx state of device */
28874 + dwc_otg_lx_state_e lx_state;
28875 +
28876 + /** Saved Core Global registers */
28877 + struct dwc_otg_global_regs_backup *gr_backup;
28878 + /** Saved Host registers */
28879 + struct dwc_otg_host_regs_backup *hr_backup;
28880 + /** Saved Device registers */
28881 + struct dwc_otg_dev_regs_backup *dr_backup;
28882 +
28883 + /** Power Down Enable */
28884 + uint32_t power_down;
28885 +
28886 + /** ADP support Enable */
28887 + uint32_t adp_enable;
28888 +
28889 + /** ADP structure object */
28890 + dwc_otg_adp_t adp;
28891 +
28892 + /** hibernation/suspend flag */
28893 + int hibernation_suspend;
28894 +
28895 + /** Device mode extended hibernation flag */
28896 + int xhib;
28897 +
28898 + /** OTG revision supported */
28899 + uint32_t otg_ver;
28900 +
28901 + /** OTG status flag used for HNP polling */
28902 + uint8_t otg_sts;
28903 +
28904 + /** Pointer to either hcd->lock or pcd->lock */
28905 + dwc_spinlock_t *lock;
28906 +
28907 + /** Start predict NextEP based on Learning Queue if equal 1,
28908 + * also used as counter of disabled NP IN EP's */
28909 + uint8_t start_predict;
28910 +
28911 + /** NextEp sequence, including EP0: nextep_seq[] = EP if non-periodic and
28912 + * active, 0xff otherwise */
28913 + uint8_t nextep_seq[MAX_EPS_CHANNELS];
28914 +
28915 + /** Index of fisrt EP in nextep_seq array which should be re-enabled **/
28916 + uint8_t first_in_nextep_seq;
28917 +
28918 + /** Frame number while entering to ISR - needed for ISOCs **/
28919 + uint32_t frame_num;
28920 +
28921 +};
28922 +
28923 +#ifdef DEBUG
28924 +/*
28925 + * This function is called when transfer is timed out.
28926 + */
28927 +extern void hc_xfer_timeout(void *ptr);
28928 +#endif
28929 +
28930 +/*
28931 + * This function is called when transfer is timed out on endpoint.
28932 + */
28933 +extern void ep_xfer_timeout(void *ptr);
28934 +
28935 +/*
28936 + * The following functions are functions for works
28937 + * using during handling some interrupts
28938 + */
28939 +extern void w_conn_id_status_change(void *p);
28940 +
28941 +extern void w_wakeup_detected(void *p);
28942 +
28943 +/** Saves global register values into system memory. */
28944 +extern int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if);
28945 +/** Saves device register values into system memory. */
28946 +extern int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if);
28947 +/** Saves host register values into system memory. */
28948 +extern int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if);
28949 +/** Restore global register values. */
28950 +extern int dwc_otg_restore_global_regs(dwc_otg_core_if_t * core_if);
28951 +/** Restore host register values. */
28952 +extern int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset);
28953 +/** Restore device register values. */
28954 +extern int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if,
28955 + int rem_wakeup);
28956 +extern int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if);
28957 +extern int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode,
28958 + int is_host);
28959 +
28960 +extern int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
28961 + int restore_mode, int reset);
28962 +extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
28963 + int rem_wakeup, int reset);
28964 +
28965 +/*
28966 + * The following functions support initialization of the CIL driver component
28967 + * and the DWC_otg controller.
28968 + */
28969 +extern void dwc_otg_core_host_init(dwc_otg_core_if_t * _core_if);
28970 +extern void dwc_otg_core_dev_init(dwc_otg_core_if_t * _core_if);
28971 +
28972 +/** @name Device CIL Functions
28973 + * The following functions support managing the DWC_otg controller in device
28974 + * mode.
28975 + */
28976 +/**@{*/
28977 +extern void dwc_otg_wakeup(dwc_otg_core_if_t * _core_if);
28978 +extern void dwc_otg_read_setup_packet(dwc_otg_core_if_t * _core_if,
28979 + uint32_t * _dest);
28980 +extern uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * _core_if);
28981 +extern void dwc_otg_ep0_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
28982 +extern void dwc_otg_ep_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
28983 +extern void dwc_otg_ep_deactivate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
28984 +extern void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * _core_if,
28985 + dwc_ep_t * _ep);
28986 +extern void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * _core_if,
28987 + dwc_ep_t * _ep);
28988 +extern void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * _core_if,
28989 + dwc_ep_t * _ep);
28990 +extern void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * _core_if,
28991 + dwc_ep_t * _ep);
28992 +extern void dwc_otg_ep_write_packet(dwc_otg_core_if_t * _core_if,
28993 + dwc_ep_t * _ep, int _dma);
28994 +extern void dwc_otg_ep_set_stall(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
28995 +extern void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * _core_if,
28996 + dwc_ep_t * _ep);
28997 +extern void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * _core_if);
28998 +
28999 +#ifdef DWC_EN_ISOC
29000 +extern void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
29001 + dwc_ep_t * ep);
29002 +extern void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
29003 + dwc_ep_t * ep);
29004 +#endif /* DWC_EN_ISOC */
29005 +/**@}*/
29006 +
29007 +/** @name Host CIL Functions
29008 + * The following functions support managing the DWC_otg controller in host
29009 + * mode.
29010 + */
29011 +/**@{*/
29012 +extern void dwc_otg_hc_init(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
29013 +extern void dwc_otg_hc_halt(dwc_otg_core_if_t * _core_if,
29014 + dwc_hc_t * _hc, dwc_otg_halt_status_e _halt_status);
29015 +extern void dwc_otg_hc_cleanup(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
29016 +extern void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * _core_if,
29017 + dwc_hc_t * _hc);
29018 +extern int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * _core_if,
29019 + dwc_hc_t * _hc);
29020 +extern void dwc_otg_hc_do_ping(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
29021 +extern void dwc_otg_hc_write_packet(dwc_otg_core_if_t * _core_if,
29022 + dwc_hc_t * _hc);
29023 +extern void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * _core_if);
29024 +extern void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * _core_if);
29025 +
29026 +extern void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if,
29027 + dwc_hc_t * hc);
29028 +
29029 +extern uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if);
29030 +
29031 +/* Macro used to clear one channel interrupt */
29032 +#define clear_hc_int(_hc_regs_, _intr_) \
29033 +do { \
29034 + hcint_data_t hcint_clear = {.d32 = 0}; \
29035 + hcint_clear.b._intr_ = 1; \
29036 + DWC_WRITE_REG32(&(_hc_regs_)->hcint, hcint_clear.d32); \
29037 +} while (0)
29038 +
29039 +/*
29040 + * Macro used to disable one channel interrupt. Channel interrupts are
29041 + * disabled when the channel is halted or released by the interrupt handler.
29042 + * There is no need to handle further interrupts of that type until the
29043 + * channel is re-assigned. In fact, subsequent handling may cause crashes
29044 + * because the channel structures are cleaned up when the channel is released.
29045 + */
29046 +#define disable_hc_int(_hc_regs_, _intr_) \
29047 +do { \
29048 + hcintmsk_data_t hcintmsk = {.d32 = 0}; \
29049 + hcintmsk.b._intr_ = 1; \
29050 + DWC_MODIFY_REG32(&(_hc_regs_)->hcintmsk, hcintmsk.d32, 0); \
29051 +} while (0)
29052 +
29053 +/**
29054 + * This function Reads HPRT0 in preparation to modify. It keeps the
29055 + * WC bits 0 so that if they are read as 1, they won't clear when you
29056 + * write it back
29057 + */
29058 +static inline uint32_t dwc_otg_read_hprt0(dwc_otg_core_if_t * _core_if)
29059 +{
29060 + hprt0_data_t hprt0;
29061 + hprt0.d32 = DWC_READ_REG32(_core_if->host_if->hprt0);
29062 + hprt0.b.prtena = 0;
29063 + hprt0.b.prtconndet = 0;
29064 + hprt0.b.prtenchng = 0;
29065 + hprt0.b.prtovrcurrchng = 0;
29066 + return hprt0.d32;
29067 +}
29068 +
29069 +/**@}*/
29070 +
29071 +/** @name Common CIL Functions
29072 + * The following functions support managing the DWC_otg controller in either
29073 + * device or host mode.
29074 + */
29075 +/**@{*/
29076 +
29077 +extern void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
29078 + uint8_t * dest, uint16_t bytes);
29079 +
29080 +extern void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * _core_if, const int _num);
29081 +extern void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * _core_if);
29082 +extern void dwc_otg_core_reset(dwc_otg_core_if_t * _core_if);
29083 +
29084 +/**
29085 + * This function returns the Core Interrupt register.
29086 + */
29087 +static inline uint32_t dwc_otg_read_core_intr(dwc_otg_core_if_t * core_if)
29088 +{
29089 + return (DWC_READ_REG32(&core_if->core_global_regs->gintsts) &
29090 + DWC_READ_REG32(&core_if->core_global_regs->gintmsk));
29091 +}
29092 +
29093 +/**
29094 + * This function returns the OTG Interrupt register.
29095 + */
29096 +static inline uint32_t dwc_otg_read_otg_intr(dwc_otg_core_if_t * core_if)
29097 +{
29098 + return (DWC_READ_REG32(&core_if->core_global_regs->gotgint));
29099 +}
29100 +
29101 +/**
29102 + * This function reads the Device All Endpoints Interrupt register and
29103 + * returns the IN endpoint interrupt bits.
29104 + */
29105 +static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(dwc_otg_core_if_t *
29106 + core_if)
29107 +{
29108 +
29109 + uint32_t v;
29110 +
29111 + if (core_if->multiproc_int_enable) {
29112 + v = DWC_READ_REG32(&core_if->dev_if->
29113 + dev_global_regs->deachint) &
29114 + DWC_READ_REG32(&core_if->
29115 + dev_if->dev_global_regs->deachintmsk);
29116 + } else {
29117 + v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
29118 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
29119 + }
29120 + return (v & 0xffff);
29121 +}
29122 +
29123 +/**
29124 + * This function reads the Device All Endpoints Interrupt register and
29125 + * returns the OUT endpoint interrupt bits.
29126 + */
29127 +static inline uint32_t dwc_otg_read_dev_all_out_ep_intr(dwc_otg_core_if_t *
29128 + core_if)
29129 +{
29130 + uint32_t v;
29131 +
29132 + if (core_if->multiproc_int_enable) {
29133 + v = DWC_READ_REG32(&core_if->dev_if->
29134 + dev_global_regs->deachint) &
29135 + DWC_READ_REG32(&core_if->
29136 + dev_if->dev_global_regs->deachintmsk);
29137 + } else {
29138 + v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
29139 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
29140 + }
29141 +
29142 + return ((v & 0xffff0000) >> 16);
29143 +}
29144 +
29145 +/**
29146 + * This function returns the Device IN EP Interrupt register
29147 + */
29148 +static inline uint32_t dwc_otg_read_dev_in_ep_intr(dwc_otg_core_if_t * core_if,
29149 + dwc_ep_t * ep)
29150 +{
29151 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
29152 + uint32_t v, msk, emp;
29153 +
29154 + if (core_if->multiproc_int_enable) {
29155 + msk =
29156 + DWC_READ_REG32(&dev_if->
29157 + dev_global_regs->diepeachintmsk[ep->num]);
29158 + emp =
29159 + DWC_READ_REG32(&dev_if->
29160 + dev_global_regs->dtknqr4_fifoemptymsk);
29161 + msk |= ((emp >> ep->num) & 0x1) << 7;
29162 + v = DWC_READ_REG32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
29163 + } else {
29164 + msk = DWC_READ_REG32(&dev_if->dev_global_regs->diepmsk);
29165 + emp =
29166 + DWC_READ_REG32(&dev_if->
29167 + dev_global_regs->dtknqr4_fifoemptymsk);
29168 + msk |= ((emp >> ep->num) & 0x1) << 7;
29169 + v = DWC_READ_REG32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
29170 + }
29171 +
29172 + return v;
29173 +}
29174 +
29175 +/**
29176 + * This function returns the Device OUT EP Interrupt register
29177 + */
29178 +static inline uint32_t dwc_otg_read_dev_out_ep_intr(dwc_otg_core_if_t *
29179 + _core_if, dwc_ep_t * _ep)
29180 +{
29181 + dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
29182 + uint32_t v;
29183 + doepmsk_data_t msk = {.d32 = 0 };
29184 +
29185 + if (_core_if->multiproc_int_enable) {
29186 + msk.d32 =
29187 + DWC_READ_REG32(&dev_if->
29188 + dev_global_regs->doepeachintmsk[_ep->num]);
29189 + if (_core_if->pti_enh_enable) {
29190 + msk.b.pktdrpsts = 1;
29191 + }
29192 + v = DWC_READ_REG32(&dev_if->
29193 + out_ep_regs[_ep->num]->doepint) & msk.d32;
29194 + } else {
29195 + msk.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->doepmsk);
29196 + if (_core_if->pti_enh_enable) {
29197 + msk.b.pktdrpsts = 1;
29198 + }
29199 + v = DWC_READ_REG32(&dev_if->
29200 + out_ep_regs[_ep->num]->doepint) & msk.d32;
29201 + }
29202 + return v;
29203 +}
29204 +
29205 +/**
29206 + * This function returns the Host All Channel Interrupt register
29207 + */
29208 +static inline uint32_t dwc_otg_read_host_all_channels_intr(dwc_otg_core_if_t *
29209 + _core_if)
29210 +{
29211 + return (DWC_READ_REG32(&_core_if->host_if->host_global_regs->haint));
29212 +}
29213 +
29214 +static inline uint32_t dwc_otg_read_host_channel_intr(dwc_otg_core_if_t *
29215 + _core_if, dwc_hc_t * _hc)
29216 +{
29217 + return (DWC_READ_REG32
29218 + (&_core_if->host_if->hc_regs[_hc->hc_num]->hcint));
29219 +}
29220 +
29221 +/**
29222 + * This function returns the mode of the operation, host or device.
29223 + *
29224 + * @return 0 - Device Mode, 1 - Host Mode
29225 + */
29226 +static inline uint32_t dwc_otg_mode(dwc_otg_core_if_t * _core_if)
29227 +{
29228 + return (DWC_READ_REG32(&_core_if->core_global_regs->gintsts) & 0x1);
29229 +}
29230 +
29231 +/**@}*/
29232 +
29233 +/**
29234 + * DWC_otg CIL callback structure. This structure allows the HCD and
29235 + * PCD to register functions used for starting and stopping the PCD
29236 + * and HCD for role change on for a DRD.
29237 + */
29238 +typedef struct dwc_otg_cil_callbacks {
29239 + /** Start function for role change */
29240 + int (*start) (void *_p);
29241 + /** Stop Function for role change */
29242 + int (*stop) (void *_p);
29243 + /** Disconnect Function for role change */
29244 + int (*disconnect) (void *_p);
29245 + /** Resume/Remote wakeup Function */
29246 + int (*resume_wakeup) (void *_p);
29247 + /** Suspend function */
29248 + int (*suspend) (void *_p);
29249 + /** Session Start (SRP) */
29250 + int (*session_start) (void *_p);
29251 +#ifdef CONFIG_USB_DWC_OTG_LPM
29252 + /** Sleep (switch to L0 state) */
29253 + int (*sleep) (void *_p);
29254 +#endif
29255 + /** Pointer passed to start() and stop() */
29256 + void *p;
29257 +} dwc_otg_cil_callbacks_t;
29258 +
29259 +extern void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * _core_if,
29260 + dwc_otg_cil_callbacks_t * _cb,
29261 + void *_p);
29262 +extern void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * _core_if,
29263 + dwc_otg_cil_callbacks_t * _cb,
29264 + void *_p);
29265 +
29266 +void dwc_otg_initiate_srp(dwc_otg_core_if_t * core_if);
29267 +
29268 +//////////////////////////////////////////////////////////////////////
29269 +/** Start the HCD. Helper function for using the HCD callbacks.
29270 + *
29271 + * @param core_if Programming view of DWC_otg controller.
29272 + */
29273 +static inline void cil_hcd_start(dwc_otg_core_if_t * core_if)
29274 +{
29275 + if (core_if->hcd_cb && core_if->hcd_cb->start) {
29276 + core_if->hcd_cb->start(core_if->hcd_cb->p);
29277 + }
29278 +}
29279 +
29280 +/** Stop the HCD. Helper function for using the HCD callbacks.
29281 + *
29282 + * @param core_if Programming view of DWC_otg controller.
29283 + */
29284 +static inline void cil_hcd_stop(dwc_otg_core_if_t * core_if)
29285 +{
29286 + if (core_if->hcd_cb && core_if->hcd_cb->stop) {
29287 + core_if->hcd_cb->stop(core_if->hcd_cb->p);
29288 + }
29289 +}
29290 +
29291 +/** Disconnect the HCD. Helper function for using the HCD callbacks.
29292 + *
29293 + * @param core_if Programming view of DWC_otg controller.
29294 + */
29295 +static inline void cil_hcd_disconnect(dwc_otg_core_if_t * core_if)
29296 +{
29297 + if (core_if->hcd_cb && core_if->hcd_cb->disconnect) {
29298 + core_if->hcd_cb->disconnect(core_if->hcd_cb->p);
29299 + }
29300 +}
29301 +
29302 +/** Inform the HCD the a New Session has begun. Helper function for
29303 + * using the HCD callbacks.
29304 + *
29305 + * @param core_if Programming view of DWC_otg controller.
29306 + */
29307 +static inline void cil_hcd_session_start(dwc_otg_core_if_t * core_if)
29308 +{
29309 + if (core_if->hcd_cb && core_if->hcd_cb->session_start) {
29310 + core_if->hcd_cb->session_start(core_if->hcd_cb->p);
29311 + }
29312 +}
29313 +
29314 +#ifdef CONFIG_USB_DWC_OTG_LPM
29315 +/**
29316 + * Inform the HCD about LPM sleep.
29317 + * Helper function for using the HCD callbacks.
29318 + *
29319 + * @param core_if Programming view of DWC_otg controller.
29320 + */
29321 +static inline void cil_hcd_sleep(dwc_otg_core_if_t * core_if)
29322 +{
29323 + if (core_if->hcd_cb && core_if->hcd_cb->sleep) {
29324 + core_if->hcd_cb->sleep(core_if->hcd_cb->p);
29325 + }
29326 +}
29327 +#endif
29328 +
29329 +/** Resume the HCD. Helper function for using the HCD callbacks.
29330 + *
29331 + * @param core_if Programming view of DWC_otg controller.
29332 + */
29333 +static inline void cil_hcd_resume(dwc_otg_core_if_t * core_if)
29334 +{
29335 + if (core_if->hcd_cb && core_if->hcd_cb->resume_wakeup) {
29336 + core_if->hcd_cb->resume_wakeup(core_if->hcd_cb->p);
29337 + }
29338 +}
29339 +
29340 +/** Start the PCD. Helper function for using the PCD callbacks.
29341 + *
29342 + * @param core_if Programming view of DWC_otg controller.
29343 + */
29344 +static inline void cil_pcd_start(dwc_otg_core_if_t * core_if)
29345 +{
29346 + if (core_if->pcd_cb && core_if->pcd_cb->start) {
29347 + core_if->pcd_cb->start(core_if->pcd_cb->p);
29348 + }
29349 +}
29350 +
29351 +/** Stop the PCD. Helper function for using the PCD callbacks.
29352 + *
29353 + * @param core_if Programming view of DWC_otg controller.
29354 + */
29355 +static inline void cil_pcd_stop(dwc_otg_core_if_t * core_if)
29356 +{
29357 + if (core_if->pcd_cb && core_if->pcd_cb->stop) {
29358 + core_if->pcd_cb->stop(core_if->pcd_cb->p);
29359 + }
29360 +}
29361 +
29362 +/** Suspend the PCD. Helper function for using the PCD callbacks.
29363 + *
29364 + * @param core_if Programming view of DWC_otg controller.
29365 + */
29366 +static inline void cil_pcd_suspend(dwc_otg_core_if_t * core_if)
29367 +{
29368 + if (core_if->pcd_cb && core_if->pcd_cb->suspend) {
29369 + core_if->pcd_cb->suspend(core_if->pcd_cb->p);
29370 + }
29371 +}
29372 +
29373 +/** Resume the PCD. Helper function for using the PCD callbacks.
29374 + *
29375 + * @param core_if Programming view of DWC_otg controller.
29376 + */
29377 +static inline void cil_pcd_resume(dwc_otg_core_if_t * core_if)
29378 +{
29379 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
29380 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
29381 + }
29382 +}
29383 +
29384 +//////////////////////////////////////////////////////////////////////
29385 +
29386 +#endif
29387 --- /dev/null
29388 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
29389 @@ -0,0 +1,1571 @@
29390 +/* ==========================================================================
29391 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil_intr.c $
29392 + * $Revision: #32 $
29393 + * $Date: 2012/08/10 $
29394 + * $Change: 2047372 $
29395 + *
29396 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
29397 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
29398 + * otherwise expressly agreed to in writing between Synopsys and you.
29399 + *
29400 + * The Software IS NOT an item of Licensed Software or Licensed Product under
29401 + * any End User Software License Agreement or Agreement for Licensed Product
29402 + * with Synopsys or any supplement thereto. You are permitted to use and
29403 + * redistribute this Software in source and binary forms, with or without
29404 + * modification, provided that redistributions of source code must retain this
29405 + * notice. You may not view, use, disclose, copy or distribute this file or
29406 + * any information contained herein except pursuant to this license grant from
29407 + * Synopsys. If you do not agree with this notice, including the disclaimer
29408 + * below, then you are not authorized to use the Software.
29409 + *
29410 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
29411 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29412 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29413 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
29414 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29415 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29416 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29417 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29418 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29419 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29420 + * DAMAGE.
29421 + * ========================================================================== */
29422 +
29423 +/** @file
29424 + *
29425 + * The Core Interface Layer provides basic services for accessing and
29426 + * managing the DWC_otg hardware. These services are used by both the
29427 + * Host Controller Driver and the Peripheral Controller Driver.
29428 + *
29429 + * This file contains the Common Interrupt handlers.
29430 + */
29431 +#include "dwc_os.h"
29432 +#include "dwc_otg_regs.h"
29433 +#include "dwc_otg_cil.h"
29434 +#include "dwc_otg_driver.h"
29435 +#include "dwc_otg_pcd.h"
29436 +#include "dwc_otg_hcd.h"
29437 +#include "dwc_otg_mphi_fix.h"
29438 +
29439 +extern bool fiq_fix_enable;
29440 +
29441 +#ifdef DEBUG
29442 +inline const char *op_state_str(dwc_otg_core_if_t * core_if)
29443 +{
29444 + return (core_if->op_state == A_HOST ? "a_host" :
29445 + (core_if->op_state == A_SUSPEND ? "a_suspend" :
29446 + (core_if->op_state == A_PERIPHERAL ? "a_peripheral" :
29447 + (core_if->op_state == B_PERIPHERAL ? "b_peripheral" :
29448 + (core_if->op_state == B_HOST ? "b_host" : "unknown")))));
29449 +}
29450 +#endif
29451 +
29452 +/** This function will log a debug message
29453 + *
29454 + * @param core_if Programming view of DWC_otg controller.
29455 + */
29456 +int32_t dwc_otg_handle_mode_mismatch_intr(dwc_otg_core_if_t * core_if)
29457 +{
29458 + gintsts_data_t gintsts;
29459 + DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
29460 + dwc_otg_mode(core_if) ? "Host" : "Device");
29461 +
29462 + /* Clear interrupt */
29463 + gintsts.d32 = 0;
29464 + gintsts.b.modemismatch = 1;
29465 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
29466 + return 1;
29467 +}
29468 +
29469 +/**
29470 + * This function handles the OTG Interrupts. It reads the OTG
29471 + * Interrupt Register (GOTGINT) to determine what interrupt has
29472 + * occurred.
29473 + *
29474 + * @param core_if Programming view of DWC_otg controller.
29475 + */
29476 +int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t * core_if)
29477 +{
29478 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
29479 + gotgint_data_t gotgint;
29480 + gotgctl_data_t gotgctl;
29481 + gintmsk_data_t gintmsk;
29482 + gpwrdn_data_t gpwrdn;
29483 +
29484 + gotgint.d32 = DWC_READ_REG32(&global_regs->gotgint);
29485 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29486 + DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
29487 + op_state_str(core_if));
29488 +
29489 + if (gotgint.b.sesenddet) {
29490 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29491 + "Session End Detected++ (%s)\n",
29492 + op_state_str(core_if));
29493 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29494 +
29495 + if (core_if->op_state == B_HOST) {
29496 + cil_pcd_start(core_if);
29497 + core_if->op_state = B_PERIPHERAL;
29498 + } else {
29499 + /* If not B_HOST and Device HNP still set. HNP
29500 + * Did not succeed!*/
29501 + if (gotgctl.b.devhnpen) {
29502 + DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
29503 + __DWC_ERROR("Device Not Connected/Responding!\n");
29504 + }
29505 +
29506 + /* If Session End Detected the B-Cable has
29507 + * been disconnected. */
29508 + /* Reset PCD and Gadget driver to a
29509 + * clean state. */
29510 + core_if->lx_state = DWC_OTG_L0;
29511 + DWC_SPINUNLOCK(core_if->lock);
29512 + cil_pcd_stop(core_if);
29513 + DWC_SPINLOCK(core_if->lock);
29514 +
29515 + if (core_if->adp_enable) {
29516 + if (core_if->power_down == 2) {
29517 + gpwrdn.d32 = 0;
29518 + gpwrdn.b.pwrdnswtch = 1;
29519 + DWC_MODIFY_REG32(&core_if->
29520 + core_global_regs->
29521 + gpwrdn, gpwrdn.d32, 0);
29522 + }
29523 +
29524 + gpwrdn.d32 = 0;
29525 + gpwrdn.b.pmuintsel = 1;
29526 + gpwrdn.b.pmuactv = 1;
29527 + DWC_MODIFY_REG32(&core_if->core_global_regs->
29528 + gpwrdn, 0, gpwrdn.d32);
29529 +
29530 + dwc_otg_adp_sense_start(core_if);
29531 + }
29532 + }
29533 +
29534 + gotgctl.d32 = 0;
29535 + gotgctl.b.devhnpen = 1;
29536 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
29537 + }
29538 + if (gotgint.b.sesreqsucstschng) {
29539 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29540 + "Session Reqeust Success Status Change++\n");
29541 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29542 + if (gotgctl.b.sesreqscs) {
29543 +
29544 + if ((core_if->core_params->phy_type ==
29545 + DWC_PHY_TYPE_PARAM_FS) && (core_if->core_params->i2c_enable)) {
29546 + core_if->srp_success = 1;
29547 + } else {
29548 + DWC_SPINUNLOCK(core_if->lock);
29549 + cil_pcd_resume(core_if);
29550 + DWC_SPINLOCK(core_if->lock);
29551 + /* Clear Session Request */
29552 + gotgctl.d32 = 0;
29553 + gotgctl.b.sesreq = 1;
29554 + DWC_MODIFY_REG32(&global_regs->gotgctl,
29555 + gotgctl.d32, 0);
29556 + }
29557 + }
29558 + }
29559 + if (gotgint.b.hstnegsucstschng) {
29560 + /* Print statements during the HNP interrupt handling
29561 + * can cause it to fail.*/
29562 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29563 + /* WA for 3.00a- HW is not setting cur_mode, even sometimes
29564 + * this does not help*/
29565 + if (core_if->snpsid >= OTG_CORE_REV_3_00a)
29566 + dwc_udelay(100);
29567 + if (gotgctl.b.hstnegscs) {
29568 + if (dwc_otg_is_host_mode(core_if)) {
29569 + core_if->op_state = B_HOST;
29570 + /*
29571 + * Need to disable SOF interrupt immediately.
29572 + * When switching from device to host, the PCD
29573 + * interrupt handler won't handle the
29574 + * interrupt if host mode is already set. The
29575 + * HCD interrupt handler won't get called if
29576 + * the HCD state is HALT. This means that the
29577 + * interrupt does not get handled and Linux
29578 + * complains loudly.
29579 + */
29580 + gintmsk.d32 = 0;
29581 + gintmsk.b.sofintr = 1;
29582 + DWC_MODIFY_REG32(&global_regs->gintmsk,
29583 + gintmsk.d32, 0);
29584 + /* Call callback function with spin lock released */
29585 + DWC_SPINUNLOCK(core_if->lock);
29586 + cil_pcd_stop(core_if);
29587 + /*
29588 + * Initialize the Core for Host mode.
29589 + */
29590 + cil_hcd_start(core_if);
29591 + DWC_SPINLOCK(core_if->lock);
29592 + core_if->op_state = B_HOST;
29593 + }
29594 + } else {
29595 + gotgctl.d32 = 0;
29596 + gotgctl.b.hnpreq = 1;
29597 + gotgctl.b.devhnpen = 1;
29598 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
29599 + DWC_DEBUGPL(DBG_ANY, "HNP Failed\n");
29600 + __DWC_ERROR("Device Not Connected/Responding\n");
29601 + }
29602 + }
29603 + if (gotgint.b.hstnegdet) {
29604 + /* The disconnect interrupt is set at the same time as
29605 + * Host Negotiation Detected. During the mode
29606 + * switch all interrupts are cleared so the disconnect
29607 + * interrupt handler will not get executed.
29608 + */
29609 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29610 + "Host Negotiation Detected++ (%s)\n",
29611 + (dwc_otg_is_host_mode(core_if) ? "Host" :
29612 + "Device"));
29613 + if (dwc_otg_is_device_mode(core_if)) {
29614 + DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
29615 + core_if->op_state);
29616 + DWC_SPINUNLOCK(core_if->lock);
29617 + cil_hcd_disconnect(core_if);
29618 + cil_pcd_start(core_if);
29619 + DWC_SPINLOCK(core_if->lock);
29620 + core_if->op_state = A_PERIPHERAL;
29621 + } else {
29622 + /*
29623 + * Need to disable SOF interrupt immediately. When
29624 + * switching from device to host, the PCD interrupt
29625 + * handler won't handle the interrupt if host mode is
29626 + * already set. The HCD interrupt handler won't get
29627 + * called if the HCD state is HALT. This means that
29628 + * the interrupt does not get handled and Linux
29629 + * complains loudly.
29630 + */
29631 + gintmsk.d32 = 0;
29632 + gintmsk.b.sofintr = 1;
29633 + DWC_MODIFY_REG32(&global_regs->gintmsk, gintmsk.d32, 0);
29634 + DWC_SPINUNLOCK(core_if->lock);
29635 + cil_pcd_stop(core_if);
29636 + cil_hcd_start(core_if);
29637 + DWC_SPINLOCK(core_if->lock);
29638 + core_if->op_state = A_HOST;
29639 + }
29640 + }
29641 + if (gotgint.b.adevtoutchng) {
29642 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29643 + "A-Device Timeout Change++\n");
29644 + }
29645 + if (gotgint.b.debdone) {
29646 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n");
29647 + }
29648 +
29649 + /* Clear GOTGINT */
29650 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, gotgint.d32);
29651 +
29652 + return 1;
29653 +}
29654 +
29655 +void w_conn_id_status_change(void *p)
29656 +{
29657 + dwc_otg_core_if_t *core_if = p;
29658 + uint32_t count = 0;
29659 + gotgctl_data_t gotgctl = {.d32 = 0 };
29660 +
29661 + gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
29662 + DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
29663 + DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
29664 +
29665 + /* B-Device connector (Device Mode) */
29666 + if (gotgctl.b.conidsts) {
29667 + /* Wait for switch to device mode. */
29668 + while (!dwc_otg_is_device_mode(core_if)) {
29669 + DWC_PRINTF("Waiting for Peripheral Mode, Mode=%s\n",
29670 + (dwc_otg_is_host_mode(core_if) ? "Host" :
29671 + "Peripheral"));
29672 + dwc_mdelay(100);
29673 + if (++count > 10000)
29674 + break;
29675 + }
29676 + DWC_ASSERT(++count < 10000,
29677 + "Connection id status change timed out");
29678 + core_if->op_state = B_PERIPHERAL;
29679 + dwc_otg_core_init(core_if);
29680 + dwc_otg_enable_global_interrupts(core_if);
29681 + cil_pcd_start(core_if);
29682 + } else {
29683 + /* A-Device connector (Host Mode) */
29684 + while (!dwc_otg_is_host_mode(core_if)) {
29685 + DWC_PRINTF("Waiting for Host Mode, Mode=%s\n",
29686 + (dwc_otg_is_host_mode(core_if) ? "Host" :
29687 + "Peripheral"));
29688 + dwc_mdelay(100);
29689 + if (++count > 10000)
29690 + break;
29691 + }
29692 + DWC_ASSERT(++count < 10000,
29693 + "Connection id status change timed out");
29694 + core_if->op_state = A_HOST;
29695 + /*
29696 + * Initialize the Core for Host mode.
29697 + */
29698 + dwc_otg_core_init(core_if);
29699 + dwc_otg_enable_global_interrupts(core_if);
29700 + cil_hcd_start(core_if);
29701 + }
29702 +}
29703 +
29704 +/**
29705 + * This function handles the Connector ID Status Change Interrupt. It
29706 + * reads the OTG Interrupt Register (GOTCTL) to determine whether this
29707 + * is a Device to Host Mode transition or a Host Mode to Device
29708 + * Transition.
29709 + *
29710 + * This only occurs when the cable is connected/removed from the PHY
29711 + * connector.
29712 + *
29713 + * @param core_if Programming view of DWC_otg controller.
29714 + */
29715 +int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t * core_if)
29716 +{
29717 +
29718 + /*
29719 + * Need to disable SOF interrupt immediately. If switching from device
29720 + * to host, the PCD interrupt handler won't handle the interrupt if
29721 + * host mode is already set. The HCD interrupt handler won't get
29722 + * called if the HCD state is HALT. This means that the interrupt does
29723 + * not get handled and Linux complains loudly.
29724 + */
29725 + gintmsk_data_t gintmsk = {.d32 = 0 };
29726 + gintsts_data_t gintsts = {.d32 = 0 };
29727 +
29728 + gintmsk.b.sofintr = 1;
29729 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
29730 +
29731 + DWC_DEBUGPL(DBG_CIL,
29732 + " ++Connector ID Status Change Interrupt++ (%s)\n",
29733 + (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
29734 +
29735 + DWC_SPINUNLOCK(core_if->lock);
29736 +
29737 + /*
29738 + * Need to schedule a work, as there are possible DELAY function calls
29739 + * Release lock before scheduling workq as it holds spinlock during scheduling
29740 + */
29741 +
29742 + DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
29743 + core_if, "connection id status change");
29744 + DWC_SPINLOCK(core_if->lock);
29745 +
29746 + /* Set flag and clear interrupt */
29747 + gintsts.b.conidstschng = 1;
29748 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
29749 +
29750 + return 1;
29751 +}
29752 +
29753 +/**
29754 + * This interrupt indicates that a device is initiating the Session
29755 + * Request Protocol to request the host to turn on bus power so a new
29756 + * session can begin. The handler responds by turning on bus power. If
29757 + * the DWC_otg controller is in low power mode, the handler brings the
29758 + * controller out of low power mode before turning on bus power.
29759 + *
29760 + * @param core_if Programming view of DWC_otg controller.
29761 + */
29762 +int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * core_if)
29763 +{
29764 + gintsts_data_t gintsts;
29765 +
29766 +#ifndef DWC_HOST_ONLY
29767 + DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
29768 +
29769 + if (dwc_otg_is_device_mode(core_if)) {
29770 + DWC_PRINTF("SRP: Device mode\n");
29771 + } else {
29772 + hprt0_data_t hprt0;
29773 + DWC_PRINTF("SRP: Host mode\n");
29774 +
29775 + /* Turn on the port power bit. */
29776 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
29777 + hprt0.b.prtpwr = 1;
29778 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
29779 +
29780 + /* Start the Connection timer. So a message can be displayed
29781 + * if connect does not occur within 10 seconds. */
29782 + cil_hcd_session_start(core_if);
29783 + }
29784 +#endif
29785 +
29786 + /* Clear interrupt */
29787 + gintsts.d32 = 0;
29788 + gintsts.b.sessreqintr = 1;
29789 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
29790 +
29791 + return 1;
29792 +}
29793 +
29794 +void w_wakeup_detected(void *p)
29795 +{
29796 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) p;
29797 + /*
29798 + * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
29799 + * so that OPT tests pass with all PHYs).
29800 + */
29801 + hprt0_data_t hprt0 = {.d32 = 0 };
29802 +#if 0
29803 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
29804 + /* Restart the Phy Clock */
29805 + pcgcctl.b.stoppclk = 1;
29806 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
29807 + dwc_udelay(10);
29808 +#endif //0
29809 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
29810 + DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
29811 +// dwc_mdelay(70);
29812 + hprt0.b.prtres = 0; /* Resume */
29813 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
29814 + DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
29815 + DWC_READ_REG32(core_if->host_if->hprt0));
29816 +
29817 + cil_hcd_resume(core_if);
29818 +
29819 + /** Change to L0 state*/
29820 + core_if->lx_state = DWC_OTG_L0;
29821 +}
29822 +
29823 +/**
29824 + * This interrupt indicates that the DWC_otg controller has detected a
29825 + * resume or remote wakeup sequence. If the DWC_otg controller is in
29826 + * low power mode, the handler must brings the controller out of low
29827 + * power mode. The controller automatically begins resume
29828 + * signaling. The handler schedules a time to stop resume signaling.
29829 + */
29830 +int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
29831 +{
29832 + gintsts_data_t gintsts;
29833 +
29834 + DWC_DEBUGPL(DBG_ANY,
29835 + "++Resume and Remote Wakeup Detected Interrupt++\n");
29836 +
29837 + DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);
29838 +
29839 + if (dwc_otg_is_device_mode(core_if)) {
29840 + dctl_data_t dctl = {.d32 = 0 };
29841 + DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
29842 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
29843 + dsts));
29844 + if (core_if->lx_state == DWC_OTG_L2) {
29845 +#ifdef PARTIAL_POWER_DOWN
29846 + if (core_if->hwcfg4.b.power_optimiz) {
29847 + pcgcctl_data_t power = {.d32 = 0 };
29848 +
29849 + power.d32 = DWC_READ_REG32(core_if->pcgcctl);
29850 + DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
29851 + power.d32);
29852 +
29853 + power.b.stoppclk = 0;
29854 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
29855 +
29856 + power.b.pwrclmp = 0;
29857 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
29858 +
29859 + power.b.rstpdwnmodule = 0;
29860 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
29861 + }
29862 +#endif
29863 + /* Clear the Remote Wakeup Signaling */
29864 + dctl.b.rmtwkupsig = 1;
29865 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
29866 + dctl, dctl.d32, 0);
29867 +
29868 + DWC_SPINUNLOCK(core_if->lock);
29869 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
29870 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
29871 + }
29872 + DWC_SPINLOCK(core_if->lock);
29873 + } else {
29874 + glpmcfg_data_t lpmcfg;
29875 + lpmcfg.d32 =
29876 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
29877 + lpmcfg.b.hird_thres &= (~(1 << 4));
29878 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
29879 + lpmcfg.d32);
29880 + }
29881 + /** Change to L0 state*/
29882 + core_if->lx_state = DWC_OTG_L0;
29883 + } else {
29884 + if (core_if->lx_state != DWC_OTG_L1) {
29885 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
29886 +
29887 + /* Restart the Phy Clock */
29888 + pcgcctl.b.stoppclk = 1;
29889 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
29890 + DWC_TIMER_SCHEDULE(core_if->wkp_timer, 71);
29891 + } else {
29892 + /** Change to L0 state*/
29893 + core_if->lx_state = DWC_OTG_L0;
29894 + }
29895 + }
29896 +
29897 + /* Clear interrupt */
29898 + gintsts.d32 = 0;
29899 + gintsts.b.wkupintr = 1;
29900 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
29901 +
29902 + return 1;
29903 +}
29904 +
29905 +/**
29906 + * This interrupt indicates that the Wakeup Logic has detected a
29907 + * Device disconnect.
29908 + */
29909 +static int32_t dwc_otg_handle_pwrdn_disconnect_intr(dwc_otg_core_if_t *core_if)
29910 +{
29911 + gpwrdn_data_t gpwrdn = { .d32 = 0 };
29912 + gpwrdn_data_t gpwrdn_temp = { .d32 = 0 };
29913 + gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
29914 +
29915 + DWC_PRINTF("%s called\n", __FUNCTION__);
29916 +
29917 + if (!core_if->hibernation_suspend) {
29918 + DWC_PRINTF("Already exited from Hibernation\n");
29919 + return 1;
29920 + }
29921 +
29922 + /* Switch on the voltage to the core */
29923 + gpwrdn.b.pwrdnswtch = 1;
29924 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
29925 + dwc_udelay(10);
29926 +
29927 + /* Reset the core */
29928 + gpwrdn.d32 = 0;
29929 + gpwrdn.b.pwrdnrstn = 1;
29930 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
29931 + dwc_udelay(10);
29932 +
29933 + /* Disable power clamps*/
29934 + gpwrdn.d32 = 0;
29935 + gpwrdn.b.pwrdnclmp = 1;
29936 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
29937 +
29938 + /* Remove reset the core signal */
29939 + gpwrdn.d32 = 0;
29940 + gpwrdn.b.pwrdnrstn = 1;
29941 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
29942 + dwc_udelay(10);
29943 +
29944 + /* Disable PMU interrupt */
29945 + gpwrdn.d32 = 0;
29946 + gpwrdn.b.pmuintsel = 1;
29947 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
29948 +
29949 + core_if->hibernation_suspend = 0;
29950 +
29951 + /* Disable PMU */
29952 + gpwrdn.d32 = 0;
29953 + gpwrdn.b.pmuactv = 1;
29954 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
29955 + dwc_udelay(10);
29956 +
29957 + if (gpwrdn_temp.b.idsts) {
29958 + core_if->op_state = B_PERIPHERAL;
29959 + dwc_otg_core_init(core_if);
29960 + dwc_otg_enable_global_interrupts(core_if);
29961 + cil_pcd_start(core_if);
29962 + } else {
29963 + core_if->op_state = A_HOST;
29964 + dwc_otg_core_init(core_if);
29965 + dwc_otg_enable_global_interrupts(core_if);
29966 + cil_hcd_start(core_if);
29967 + }
29968 +
29969 + return 1;
29970 +}
29971 +
29972 +/**
29973 + * This interrupt indicates that the Wakeup Logic has detected a
29974 + * remote wakeup sequence.
29975 + */
29976 +static int32_t dwc_otg_handle_pwrdn_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
29977 +{
29978 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
29979 + DWC_DEBUGPL(DBG_ANY,
29980 + "++Powerdown Remote Wakeup Detected Interrupt++\n");
29981 +
29982 + if (!core_if->hibernation_suspend) {
29983 + DWC_PRINTF("Already exited from Hibernation\n");
29984 + return 1;
29985 + }
29986 +
29987 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
29988 + if (gpwrdn.b.idsts) { // Device Mode
29989 + if ((core_if->power_down == 2)
29990 + && (core_if->hibernation_suspend == 1)) {
29991 + dwc_otg_device_hibernation_restore(core_if, 0, 0);
29992 + }
29993 + } else {
29994 + if ((core_if->power_down == 2)
29995 + && (core_if->hibernation_suspend == 1)) {
29996 + dwc_otg_host_hibernation_restore(core_if, 1, 0);
29997 + }
29998 + }
29999 + return 1;
30000 +}
30001 +
30002 +static int32_t dwc_otg_handle_pwrdn_idsts_change(dwc_otg_device_t *otg_dev)
30003 +{
30004 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30005 + gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
30006 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
30007 +
30008 + DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
30009 + gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30010 + if (core_if->power_down == 2) {
30011 + if (!core_if->hibernation_suspend) {
30012 + DWC_PRINTF("Already exited from Hibernation\n");
30013 + return 1;
30014 + }
30015 + DWC_DEBUGPL(DBG_ANY, "Exit from hibernation on ID sts change\n");
30016 + /* Switch on the voltage to the core */
30017 + gpwrdn.b.pwrdnswtch = 1;
30018 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30019 + dwc_udelay(10);
30020 +
30021 + /* Reset the core */
30022 + gpwrdn.d32 = 0;
30023 + gpwrdn.b.pwrdnrstn = 1;
30024 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30025 + dwc_udelay(10);
30026 +
30027 + /* Disable power clamps */
30028 + gpwrdn.d32 = 0;
30029 + gpwrdn.b.pwrdnclmp = 1;
30030 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30031 +
30032 + /* Remove reset the core signal */
30033 + gpwrdn.d32 = 0;
30034 + gpwrdn.b.pwrdnrstn = 1;
30035 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30036 + dwc_udelay(10);
30037 +
30038 + /* Disable PMU interrupt */
30039 + gpwrdn.d32 = 0;
30040 + gpwrdn.b.pmuintsel = 1;
30041 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30042 +
30043 + /*Indicates that we are exiting from hibernation */
30044 + core_if->hibernation_suspend = 0;
30045 +
30046 + /* Disable PMU */
30047 + gpwrdn.d32 = 0;
30048 + gpwrdn.b.pmuactv = 1;
30049 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30050 + dwc_udelay(10);
30051 +
30052 + gpwrdn.d32 = core_if->gr_backup->gpwrdn_local;
30053 + if (gpwrdn.b.dis_vbus == 1) {
30054 + gpwrdn.d32 = 0;
30055 + gpwrdn.b.dis_vbus = 1;
30056 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30057 + }
30058 +
30059 + if (gpwrdn_temp.b.idsts) {
30060 + core_if->op_state = B_PERIPHERAL;
30061 + dwc_otg_core_init(core_if);
30062 + dwc_otg_enable_global_interrupts(core_if);
30063 + cil_pcd_start(core_if);
30064 + } else {
30065 + core_if->op_state = A_HOST;
30066 + dwc_otg_core_init(core_if);
30067 + dwc_otg_enable_global_interrupts(core_if);
30068 + cil_hcd_start(core_if);
30069 + }
30070 + }
30071 +
30072 + if (core_if->adp_enable) {
30073 + uint8_t is_host = 0;
30074 + DWC_SPINUNLOCK(core_if->lock);
30075 + /* Change the core_if's lock to hcd/pcd lock depend on mode? */
30076 +#ifndef DWC_HOST_ONLY
30077 + if (gpwrdn_temp.b.idsts)
30078 + core_if->lock = otg_dev->pcd->lock;
30079 +#endif
30080 +#ifndef DWC_DEVICE_ONLY
30081 + if (!gpwrdn_temp.b.idsts) {
30082 + core_if->lock = otg_dev->hcd->lock;
30083 + is_host = 1;
30084 + }
30085 +#endif
30086 + DWC_PRINTF("RESTART ADP\n");
30087 + if (core_if->adp.probe_enabled)
30088 + dwc_otg_adp_probe_stop(core_if);
30089 + if (core_if->adp.sense_enabled)
30090 + dwc_otg_adp_sense_stop(core_if);
30091 + if (core_if->adp.sense_timer_started)
30092 + DWC_TIMER_CANCEL(core_if->adp.sense_timer);
30093 + if (core_if->adp.vbuson_timer_started)
30094 + DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
30095 + core_if->adp.probe_timer_values[0] = -1;
30096 + core_if->adp.probe_timer_values[1] = -1;
30097 + core_if->adp.sense_timer_started = 0;
30098 + core_if->adp.vbuson_timer_started = 0;
30099 + core_if->adp.probe_counter = 0;
30100 + core_if->adp.gpwrdn = 0;
30101 +
30102 + /* Disable PMU and restart ADP */
30103 + gpwrdn_temp.d32 = 0;
30104 + gpwrdn_temp.b.pmuactv = 1;
30105 + gpwrdn_temp.b.pmuintsel = 1;
30106 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30107 + DWC_PRINTF("Check point 1\n");
30108 + dwc_mdelay(110);
30109 + dwc_otg_adp_start(core_if, is_host);
30110 + DWC_SPINLOCK(core_if->lock);
30111 + }
30112 +
30113 +
30114 + return 1;
30115 +}
30116 +
30117 +static int32_t dwc_otg_handle_pwrdn_session_change(dwc_otg_core_if_t * core_if)
30118 +{
30119 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30120 + int32_t otg_cap_param = core_if->core_params->otg_cap;
30121 + DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
30122 +
30123 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30124 + if (core_if->power_down == 2) {
30125 + if (!core_if->hibernation_suspend) {
30126 + DWC_PRINTF("Already exited from Hibernation\n");
30127 + return 1;
30128 + }
30129 +
30130 + if ((otg_cap_param != DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
30131 + otg_cap_param != DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) &&
30132 + gpwrdn.b.bsessvld == 0) {
30133 + /* Save gpwrdn register for further usage if stschng interrupt */
30134 + core_if->gr_backup->gpwrdn_local =
30135 + DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30136 + /*Exit from ISR and wait for stschng interrupt with bsessvld = 1 */
30137 + return 1;
30138 + }
30139 +
30140 + /* Switch on the voltage to the core */
30141 + gpwrdn.d32 = 0;
30142 + gpwrdn.b.pwrdnswtch = 1;
30143 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30144 + dwc_udelay(10);
30145 +
30146 + /* Reset the core */
30147 + gpwrdn.d32 = 0;
30148 + gpwrdn.b.pwrdnrstn = 1;
30149 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30150 + dwc_udelay(10);
30151 +
30152 + /* Disable power clamps */
30153 + gpwrdn.d32 = 0;
30154 + gpwrdn.b.pwrdnclmp = 1;
30155 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30156 +
30157 + /* Remove reset the core signal */
30158 + gpwrdn.d32 = 0;
30159 + gpwrdn.b.pwrdnrstn = 1;
30160 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30161 + dwc_udelay(10);
30162 +
30163 + /* Disable PMU interrupt */
30164 + gpwrdn.d32 = 0;
30165 + gpwrdn.b.pmuintsel = 1;
30166 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30167 + dwc_udelay(10);
30168 +
30169 + /*Indicates that we are exiting from hibernation */
30170 + core_if->hibernation_suspend = 0;
30171 +
30172 + /* Disable PMU */
30173 + gpwrdn.d32 = 0;
30174 + gpwrdn.b.pmuactv = 1;
30175 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30176 + dwc_udelay(10);
30177 +
30178 + core_if->op_state = B_PERIPHERAL;
30179 + dwc_otg_core_init(core_if);
30180 + dwc_otg_enable_global_interrupts(core_if);
30181 + cil_pcd_start(core_if);
30182 +
30183 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
30184 + otg_cap_param == DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) {
30185 + /*
30186 + * Initiate SRP after initial ADP probe.
30187 + */
30188 + dwc_otg_initiate_srp(core_if);
30189 + }
30190 + }
30191 +
30192 + return 1;
30193 +}
30194 +/**
30195 + * This interrupt indicates that the Wakeup Logic has detected a
30196 + * status change either on IDDIG or BSessVld.
30197 + */
30198 +static uint32_t dwc_otg_handle_pwrdn_stschng_intr(dwc_otg_device_t *otg_dev)
30199 +{
30200 + int retval;
30201 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30202 + gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
30203 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
30204 +
30205 + DWC_PRINTF("%s called\n", __FUNCTION__);
30206 +
30207 + if (core_if->power_down == 2) {
30208 + if (core_if->hibernation_suspend <= 0) {
30209 + DWC_PRINTF("Already exited from Hibernation\n");
30210 + return 1;
30211 + } else
30212 + gpwrdn_temp.d32 = core_if->gr_backup->gpwrdn_local;
30213 +
30214 + } else {
30215 + gpwrdn_temp.d32 = core_if->adp.gpwrdn;
30216 + }
30217 +
30218 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30219 +
30220 + if (gpwrdn.b.idsts ^ gpwrdn_temp.b.idsts) {
30221 + retval = dwc_otg_handle_pwrdn_idsts_change(otg_dev);
30222 + } else if (gpwrdn.b.bsessvld ^ gpwrdn_temp.b.bsessvld) {
30223 + retval = dwc_otg_handle_pwrdn_session_change(core_if);
30224 + }
30225 +
30226 + return retval;
30227 +}
30228 +
30229 +/**
30230 + * This interrupt indicates that the Wakeup Logic has detected a
30231 + * SRP.
30232 + */
30233 +static int32_t dwc_otg_handle_pwrdn_srp_intr(dwc_otg_core_if_t * core_if)
30234 +{
30235 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30236 +
30237 + DWC_PRINTF("%s called\n", __FUNCTION__);
30238 +
30239 + if (!core_if->hibernation_suspend) {
30240 + DWC_PRINTF("Already exited from Hibernation\n");
30241 + return 1;
30242 + }
30243 +#ifdef DWC_DEV_SRPCAP
30244 + if (core_if->pwron_timer_started) {
30245 + core_if->pwron_timer_started = 0;
30246 + DWC_TIMER_CANCEL(core_if->pwron_timer);
30247 + }
30248 +#endif
30249 +
30250 + /* Switch on the voltage to the core */
30251 + gpwrdn.b.pwrdnswtch = 1;
30252 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30253 + dwc_udelay(10);
30254 +
30255 + /* Reset the core */
30256 + gpwrdn.d32 = 0;
30257 + gpwrdn.b.pwrdnrstn = 1;
30258 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30259 + dwc_udelay(10);
30260 +
30261 + /* Disable power clamps */
30262 + gpwrdn.d32 = 0;
30263 + gpwrdn.b.pwrdnclmp = 1;
30264 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30265 +
30266 + /* Remove reset the core signal */
30267 + gpwrdn.d32 = 0;
30268 + gpwrdn.b.pwrdnrstn = 1;
30269 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30270 + dwc_udelay(10);
30271 +
30272 + /* Disable PMU interrupt */
30273 + gpwrdn.d32 = 0;
30274 + gpwrdn.b.pmuintsel = 1;
30275 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30276 +
30277 + /* Indicates that we are exiting from hibernation */
30278 + core_if->hibernation_suspend = 0;
30279 +
30280 + /* Disable PMU */
30281 + gpwrdn.d32 = 0;
30282 + gpwrdn.b.pmuactv = 1;
30283 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30284 + dwc_udelay(10);
30285 +
30286 + /* Programm Disable VBUS to 0 */
30287 + gpwrdn.d32 = 0;
30288 + gpwrdn.b.dis_vbus = 1;
30289 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30290 +
30291 + /*Initialize the core as Host */
30292 + core_if->op_state = A_HOST;
30293 + dwc_otg_core_init(core_if);
30294 + dwc_otg_enable_global_interrupts(core_if);
30295 + cil_hcd_start(core_if);
30296 +
30297 + return 1;
30298 +}
30299 +
30300 +/** This interrupt indicates that restore command after Hibernation
30301 + * was completed by the core. */
30302 +int32_t dwc_otg_handle_restore_done_intr(dwc_otg_core_if_t * core_if)
30303 +{
30304 + pcgcctl_data_t pcgcctl;
30305 + DWC_DEBUGPL(DBG_ANY, "++Restore Done Interrupt++\n");
30306 +
30307 + //TODO De-assert restore signal. 8.a
30308 + pcgcctl.d32 = DWC_READ_REG32(core_if->pcgcctl);
30309 + if (pcgcctl.b.restoremode == 1) {
30310 + gintmsk_data_t gintmsk = {.d32 = 0 };
30311 + /*
30312 + * If restore mode is Remote Wakeup,
30313 + * unmask Remote Wakeup interrupt.
30314 + */
30315 + gintmsk.b.wkupintr = 1;
30316 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
30317 + 0, gintmsk.d32);
30318 + }
30319 +
30320 + return 1;
30321 +}
30322 +
30323 +/**
30324 + * This interrupt indicates that a device has been disconnected from
30325 + * the root port.
30326 + */
30327 +int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t * core_if)
30328 +{
30329 + gintsts_data_t gintsts;
30330 +
30331 + DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
30332 + (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"),
30333 + op_state_str(core_if));
30334 +
30335 +/** @todo Consolidate this if statement. */
30336 +#ifndef DWC_HOST_ONLY
30337 + if (core_if->op_state == B_HOST) {
30338 + /* If in device mode Disconnect and stop the HCD, then
30339 + * start the PCD. */
30340 + DWC_SPINUNLOCK(core_if->lock);
30341 + cil_hcd_disconnect(core_if);
30342 + cil_pcd_start(core_if);
30343 + DWC_SPINLOCK(core_if->lock);
30344 + core_if->op_state = B_PERIPHERAL;
30345 + } else if (dwc_otg_is_device_mode(core_if)) {
30346 + gotgctl_data_t gotgctl = {.d32 = 0 };
30347 + gotgctl.d32 =
30348 + DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
30349 + if (gotgctl.b.hstsethnpen == 1) {
30350 + /* Do nothing, if HNP in process the OTG
30351 + * interrupt "Host Negotiation Detected"
30352 + * interrupt will do the mode switch.
30353 + */
30354 + } else if (gotgctl.b.devhnpen == 0) {
30355 + /* If in device mode Disconnect and stop the HCD, then
30356 + * start the PCD. */
30357 + DWC_SPINUNLOCK(core_if->lock);
30358 + cil_hcd_disconnect(core_if);
30359 + cil_pcd_start(core_if);
30360 + DWC_SPINLOCK(core_if->lock);
30361 + core_if->op_state = B_PERIPHERAL;
30362 + } else {
30363 + DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
30364 + }
30365 + } else {
30366 + if (core_if->op_state == A_HOST) {
30367 + /* A-Cable still connected but device disconnected. */
30368 + cil_hcd_disconnect(core_if);
30369 + if (core_if->adp_enable) {
30370 + gpwrdn_data_t gpwrdn = { .d32 = 0 };
30371 + cil_hcd_stop(core_if);
30372 + /* Enable Power Down Logic */
30373 + gpwrdn.b.pmuintsel = 1;
30374 + gpwrdn.b.pmuactv = 1;
30375 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30376 + gpwrdn, 0, gpwrdn.d32);
30377 + dwc_otg_adp_probe_start(core_if);
30378 +
30379 + /* Power off the core */
30380 + if (core_if->power_down == 2) {
30381 + gpwrdn.d32 = 0;
30382 + gpwrdn.b.pwrdnswtch = 1;
30383 + DWC_MODIFY_REG32
30384 + (&core_if->core_global_regs->gpwrdn,
30385 + gpwrdn.d32, 0);
30386 + }
30387 + }
30388 + }
30389 + }
30390 +#endif
30391 + /* Change to L3(OFF) state */
30392 + core_if->lx_state = DWC_OTG_L3;
30393 +
30394 + gintsts.d32 = 0;
30395 + gintsts.b.disconnect = 1;
30396 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30397 + return 1;
30398 +}
30399 +
30400 +/**
30401 + * This interrupt indicates that SUSPEND state has been detected on
30402 + * the USB.
30403 + *
30404 + * For HNP the USB Suspend interrupt signals the change from
30405 + * "a_peripheral" to "a_host".
30406 + *
30407 + * When power management is enabled the core will be put in low power
30408 + * mode.
30409 + */
30410 +int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t * core_if)
30411 +{
30412 + dsts_data_t dsts;
30413 + gintsts_data_t gintsts;
30414 + dcfg_data_t dcfg;
30415 +
30416 + DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
30417 +
30418 + if (dwc_otg_is_device_mode(core_if)) {
30419 + /* Check the Device status register to determine if the Suspend
30420 + * state is active. */
30421 + dsts.d32 =
30422 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
30423 + DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
30424 + DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d "
30425 + "HWCFG4.power Optimize=%d\n",
30426 + dsts.b.suspsts, core_if->hwcfg4.b.power_optimiz);
30427 +
30428 +#ifdef PARTIAL_POWER_DOWN
30429 +/** @todo Add a module parameter for power management. */
30430 +
30431 + if (dsts.b.suspsts && core_if->hwcfg4.b.power_optimiz) {
30432 + pcgcctl_data_t power = {.d32 = 0 };
30433 + DWC_DEBUGPL(DBG_CIL, "suspend\n");
30434 +
30435 + power.b.pwrclmp = 1;
30436 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30437 +
30438 + power.b.rstpdwnmodule = 1;
30439 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
30440 +
30441 + power.b.stoppclk = 1;
30442 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
30443 +
30444 + } else {
30445 + DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
30446 + }
30447 +#endif
30448 + /* PCD callback for suspend. Release the lock inside of callback function */
30449 + cil_pcd_suspend(core_if);
30450 + if (core_if->power_down == 2)
30451 + {
30452 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
30453 + DWC_DEBUGPL(DBG_ANY,"lx_state = %08x\n",core_if->lx_state);
30454 + DWC_DEBUGPL(DBG_ANY," device address = %08d\n",dcfg.b.devaddr);
30455 +
30456 + if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
30457 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30458 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30459 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
30460 +
30461 + /* Change to L2(suspend) state */
30462 + core_if->lx_state = DWC_OTG_L2;
30463 +
30464 + /* Clear interrupt in gintsts */
30465 + gintsts.d32 = 0;
30466 + gintsts.b.usbsuspend = 1;
30467 + DWC_WRITE_REG32(&core_if->core_global_regs->
30468 + gintsts, gintsts.d32);
30469 + DWC_PRINTF("Start of hibernation completed\n");
30470 + dwc_otg_save_global_regs(core_if);
30471 + dwc_otg_save_dev_regs(core_if);
30472 +
30473 + gusbcfg.d32 =
30474 + DWC_READ_REG32(&core_if->core_global_regs->
30475 + gusbcfg);
30476 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
30477 + /* ULPI interface */
30478 + /* Suspend the Phy Clock */
30479 + pcgcctl.d32 = 0;
30480 + pcgcctl.b.stoppclk = 1;
30481 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
30482 + pcgcctl.d32);
30483 + dwc_udelay(10);
30484 + gpwrdn.b.pmuactv = 1;
30485 + DWC_MODIFY_REG32(&core_if->
30486 + core_global_regs->
30487 + gpwrdn, 0, gpwrdn.d32);
30488 + } else {
30489 + /* UTMI+ Interface */
30490 + gpwrdn.b.pmuactv = 1;
30491 + DWC_MODIFY_REG32(&core_if->
30492 + core_global_regs->
30493 + gpwrdn, 0, gpwrdn.d32);
30494 + dwc_udelay(10);
30495 + pcgcctl.b.stoppclk = 1;
30496 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
30497 + pcgcctl.d32);
30498 + dwc_udelay(10);
30499 + }
30500 +
30501 + /* Set flag to indicate that we are in hibernation */
30502 + core_if->hibernation_suspend = 1;
30503 + /* Enable interrupts from wake up logic */
30504 + gpwrdn.d32 = 0;
30505 + gpwrdn.b.pmuintsel = 1;
30506 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30507 + gpwrdn, 0, gpwrdn.d32);
30508 + dwc_udelay(10);
30509 +
30510 + /* Unmask device mode interrupts in GPWRDN */
30511 + gpwrdn.d32 = 0;
30512 + gpwrdn.b.rst_det_msk = 1;
30513 + gpwrdn.b.lnstchng_msk = 1;
30514 + gpwrdn.b.sts_chngint_msk = 1;
30515 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30516 + gpwrdn, 0, gpwrdn.d32);
30517 + dwc_udelay(10);
30518 +
30519 + /* Enable Power Down Clamp */
30520 + gpwrdn.d32 = 0;
30521 + gpwrdn.b.pwrdnclmp = 1;
30522 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30523 + gpwrdn, 0, gpwrdn.d32);
30524 + dwc_udelay(10);
30525 +
30526 + /* Switch off VDD */
30527 + gpwrdn.d32 = 0;
30528 + gpwrdn.b.pwrdnswtch = 1;
30529 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30530 + gpwrdn, 0, gpwrdn.d32);
30531 +
30532 + /* Save gpwrdn register for further usage if stschng interrupt */
30533 + core_if->gr_backup->gpwrdn_local =
30534 + DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30535 + DWC_PRINTF("Hibernation completed\n");
30536 +
30537 + return 1;
30538 + }
30539 + } else if (core_if->power_down == 3) {
30540 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30541 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
30542 + DWC_DEBUGPL(DBG_ANY, "lx_state = %08x\n",core_if->lx_state);
30543 + DWC_DEBUGPL(DBG_ANY, " device address = %08d\n",dcfg.b.devaddr);
30544 +
30545 + if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
30546 + DWC_DEBUGPL(DBG_ANY, "Start entering to extended hibernation\n");
30547 + core_if->xhib = 1;
30548 +
30549 + /* Clear interrupt in gintsts */
30550 + gintsts.d32 = 0;
30551 + gintsts.b.usbsuspend = 1;
30552 + DWC_WRITE_REG32(&core_if->core_global_regs->
30553 + gintsts, gintsts.d32);
30554 +
30555 + dwc_otg_save_global_regs(core_if);
30556 + dwc_otg_save_dev_regs(core_if);
30557 +
30558 + /* Wait for 10 PHY clocks */
30559 + dwc_udelay(10);
30560 +
30561 + /* Program GPIO register while entering to xHib */
30562 + DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x1);
30563 +
30564 + pcgcctl.b.enbl_extnd_hiber = 1;
30565 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30566 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30567 +
30568 + pcgcctl.d32 = 0;
30569 + pcgcctl.b.extnd_hiber_pwrclmp = 1;
30570 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30571 +
30572 + pcgcctl.d32 = 0;
30573 + pcgcctl.b.extnd_hiber_switch = 1;
30574 + core_if->gr_backup->xhib_gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30575 + core_if->gr_backup->xhib_pcgcctl = DWC_READ_REG32(core_if->pcgcctl) | pcgcctl.d32;
30576 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30577 +
30578 + DWC_DEBUGPL(DBG_ANY, "Finished entering to extended hibernation\n");
30579 +
30580 + return 1;
30581 + }
30582 + }
30583 + } else {
30584 + if (core_if->op_state == A_PERIPHERAL) {
30585 + DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n");
30586 + /* Clear the a_peripheral flag, back to a_host. */
30587 + DWC_SPINUNLOCK(core_if->lock);
30588 + cil_pcd_stop(core_if);
30589 + cil_hcd_start(core_if);
30590 + DWC_SPINLOCK(core_if->lock);
30591 + core_if->op_state = A_HOST;
30592 + }
30593 + }
30594 +
30595 + /* Change to L2(suspend) state */
30596 + core_if->lx_state = DWC_OTG_L2;
30597 +
30598 + /* Clear interrupt */
30599 + gintsts.d32 = 0;
30600 + gintsts.b.usbsuspend = 1;
30601 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30602 +
30603 + return 1;
30604 +}
30605 +
30606 +static int32_t dwc_otg_handle_xhib_exit_intr(dwc_otg_core_if_t * core_if)
30607 +{
30608 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30609 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30610 + gahbcfg_data_t gahbcfg = {.d32 = 0 };
30611 +
30612 + dwc_udelay(10);
30613 +
30614 + /* Program GPIO register while entering to xHib */
30615 + DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x0);
30616 +
30617 + pcgcctl.d32 = core_if->gr_backup->xhib_pcgcctl;
30618 + pcgcctl.b.extnd_hiber_pwrclmp = 0;
30619 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
30620 + dwc_udelay(10);
30621 +
30622 + gpwrdn.d32 = core_if->gr_backup->xhib_gpwrdn;
30623 + gpwrdn.b.restore = 1;
30624 + DWC_WRITE_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32);
30625 + dwc_udelay(10);
30626 +
30627 + restore_lpm_i2c_regs(core_if);
30628 +
30629 + pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
30630 + pcgcctl.b.max_xcvrselect = 1;
30631 + pcgcctl.b.ess_reg_restored = 0;
30632 + pcgcctl.b.extnd_hiber_switch = 0;
30633 + pcgcctl.b.extnd_hiber_pwrclmp = 0;
30634 + pcgcctl.b.enbl_extnd_hiber = 1;
30635 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
30636 +
30637 + gahbcfg.d32 = core_if->gr_backup->gahbcfg_local;
30638 + gahbcfg.b.glblintrmsk = 1;
30639 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
30640 +
30641 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
30642 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0x1 << 16);
30643 +
30644 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
30645 + core_if->gr_backup->gusbcfg_local);
30646 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
30647 + core_if->dr_backup->dcfg);
30648 +
30649 + pcgcctl.d32 = 0;
30650 + pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
30651 + pcgcctl.b.max_xcvrselect = 1;
30652 + pcgcctl.d32 |= 0x608;
30653 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
30654 + dwc_udelay(10);
30655 +
30656 + pcgcctl.d32 = 0;
30657 + pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
30658 + pcgcctl.b.max_xcvrselect = 1;
30659 + pcgcctl.b.ess_reg_restored = 1;
30660 + pcgcctl.b.enbl_extnd_hiber = 1;
30661 + pcgcctl.b.rstpdwnmodule = 1;
30662 + pcgcctl.b.restoremode = 1;
30663 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
30664 +
30665 + DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
30666 +
30667 + return 1;
30668 +}
30669 +
30670 +#ifdef CONFIG_USB_DWC_OTG_LPM
30671 +/**
30672 + * This function hadles LPM transaction received interrupt.
30673 + */
30674 +static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if)
30675 +{
30676 + glpmcfg_data_t lpmcfg;
30677 + gintsts_data_t gintsts;
30678 +
30679 + if (!core_if->core_params->lpm_enable) {
30680 + DWC_PRINTF("Unexpected LPM interrupt\n");
30681 + }
30682 +
30683 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
30684 + DWC_PRINTF("LPM config register = 0x%08x\n", lpmcfg.d32);
30685 +
30686 + if (dwc_otg_is_host_mode(core_if)) {
30687 + cil_hcd_sleep(core_if);
30688 + } else {
30689 + lpmcfg.b.hird_thres |= (1 << 4);
30690 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
30691 + lpmcfg.d32);
30692 + }
30693 +
30694 + /* Examine prt_sleep_sts after TL1TokenTetry period max (10 us) */
30695 + dwc_udelay(10);
30696 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
30697 + if (lpmcfg.b.prt_sleep_sts) {
30698 + /* Save the current state */
30699 + core_if->lx_state = DWC_OTG_L1;
30700 + }
30701 +
30702 + /* Clear interrupt */
30703 + gintsts.d32 = 0;
30704 + gintsts.b.lpmtranrcvd = 1;
30705 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30706 + return 1;
30707 +}
30708 +#endif /* CONFIG_USB_DWC_OTG_LPM */
30709 +
30710 +/**
30711 + * This function returns the Core Interrupt register.
30712 + */
30713 +static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if)
30714 +{
30715 + gahbcfg_data_t gahbcfg = {.d32 = 0 };
30716 + gintsts_data_t gintsts;
30717 + gintmsk_data_t gintmsk;
30718 + gintmsk_data_t gintmsk_common = {.d32 = 0 };
30719 + gintmsk_common.b.wkupintr = 1;
30720 + gintmsk_common.b.sessreqintr = 1;
30721 + gintmsk_common.b.conidstschng = 1;
30722 + gintmsk_common.b.otgintr = 1;
30723 + gintmsk_common.b.modemismatch = 1;
30724 + gintmsk_common.b.disconnect = 1;
30725 + gintmsk_common.b.usbsuspend = 1;
30726 +#ifdef CONFIG_USB_DWC_OTG_LPM
30727 + gintmsk_common.b.lpmtranrcvd = 1;
30728 +#endif
30729 + gintmsk_common.b.restoredone = 1;
30730 + /** @todo: The port interrupt occurs while in device
30731 + * mode. Added code to CIL to clear the interrupt for now!
30732 + */
30733 + gintmsk_common.b.portintr = 1;
30734 +
30735 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
30736 + gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
30737 + gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
30738 +
30739 +#ifdef DEBUG
30740 + /* if any common interrupts set */
30741 + if (gintsts.d32 & gintmsk_common.d32) {
30742 + DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n",
30743 + gintsts.d32, gintmsk.d32);
30744 + }
30745 +#endif
30746 + if (!fiq_fix_enable){
30747 + if (gahbcfg.b.glblintrmsk)
30748 + return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
30749 + else
30750 + return 0;
30751 + }
30752 + else {
30753 + return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
30754 + }
30755 +
30756 +}
30757 +
30758 +/* MACRO for clearing interupt bits in GPWRDN register */
30759 +#define CLEAR_GPWRDN_INTR(__core_if,__intr) \
30760 +do { \
30761 + gpwrdn_data_t gpwrdn = {.d32=0}; \
30762 + gpwrdn.b.__intr = 1; \
30763 + DWC_MODIFY_REG32(&__core_if->core_global_regs->gpwrdn, \
30764 + 0, gpwrdn.d32); \
30765 +} while (0)
30766 +
30767 +/**
30768 + * Common interrupt handler.
30769 + *
30770 + * The common interrupts are those that occur in both Host and Device mode.
30771 + * This handler handles the following interrupts:
30772 + * - Mode Mismatch Interrupt
30773 + * - Disconnect Interrupt
30774 + * - OTG Interrupt
30775 + * - Connector ID Status Change Interrupt
30776 + * - Session Request Interrupt.
30777 + * - Resume / Remote Wakeup Detected Interrupt.
30778 + * - LPM Transaction Received Interrupt
30779 + * - ADP Transaction Received Interrupt
30780 + *
30781 + */
30782 +int32_t dwc_otg_handle_common_intr(void *dev)
30783 +{
30784 + int retval = 0;
30785 + gintsts_data_t gintsts;
30786 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30787 + dwc_otg_device_t *otg_dev = dev;
30788 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
30789 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30790 + if (dwc_otg_is_device_mode(core_if))
30791 + core_if->frame_num = dwc_otg_get_frame_number(core_if);
30792 +
30793 + if (core_if->lock)
30794 + DWC_SPINLOCK(core_if->lock);
30795 +
30796 + if (core_if->power_down == 3 && core_if->xhib == 1) {
30797 + DWC_DEBUGPL(DBG_ANY, "Exiting from xHIB state\n");
30798 + retval |= dwc_otg_handle_xhib_exit_intr(core_if);
30799 + core_if->xhib = 2;
30800 + if (core_if->lock)
30801 + DWC_SPINUNLOCK(core_if->lock);
30802 +
30803 + return retval;
30804 + }
30805 +
30806 + if (core_if->hibernation_suspend <= 0) {
30807 + gintsts.d32 = dwc_otg_read_common_intr(core_if);
30808 +
30809 + if (gintsts.b.modemismatch) {
30810 + retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
30811 + }
30812 + if (gintsts.b.otgintr) {
30813 + retval |= dwc_otg_handle_otg_intr(core_if);
30814 + }
30815 + if (gintsts.b.conidstschng) {
30816 + retval |=
30817 + dwc_otg_handle_conn_id_status_change_intr(core_if);
30818 + }
30819 + if (gintsts.b.disconnect) {
30820 + retval |= dwc_otg_handle_disconnect_intr(core_if);
30821 + }
30822 + if (gintsts.b.sessreqintr) {
30823 + retval |= dwc_otg_handle_session_req_intr(core_if);
30824 + }
30825 + if (gintsts.b.wkupintr) {
30826 + retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
30827 + }
30828 + if (gintsts.b.usbsuspend) {
30829 + retval |= dwc_otg_handle_usb_suspend_intr(core_if);
30830 + }
30831 +#ifdef CONFIG_USB_DWC_OTG_LPM
30832 + if (gintsts.b.lpmtranrcvd) {
30833 + retval |= dwc_otg_handle_lpm_intr(core_if);
30834 + }
30835 +#endif
30836 + if (gintsts.b.restoredone) {
30837 + gintsts.d32 = 0;
30838 + if (core_if->power_down == 2)
30839 + core_if->hibernation_suspend = -1;
30840 + else if (core_if->power_down == 3 && core_if->xhib == 2) {
30841 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30842 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30843 + dctl_data_t dctl = {.d32 = 0 };
30844 +
30845 + DWC_WRITE_REG32(&core_if->core_global_regs->
30846 + gintsts, 0xFFFFFFFF);
30847 +
30848 + DWC_DEBUGPL(DBG_ANY,
30849 + "RESTORE DONE generated\n");
30850 +
30851 + gpwrdn.b.restore = 1;
30852 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30853 + dwc_udelay(10);
30854 +
30855 + pcgcctl.b.rstpdwnmodule = 1;
30856 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
30857 +
30858 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, core_if->gr_backup->gusbcfg_local);
30859 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, core_if->dr_backup->dcfg);
30860 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, core_if->dr_backup->dctl);
30861 + dwc_udelay(50);
30862 +
30863 + dctl.b.pwronprgdone = 1;
30864 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
30865 + dwc_udelay(10);
30866 +
30867 + dwc_otg_restore_global_regs(core_if);
30868 + dwc_otg_restore_dev_regs(core_if, 0);
30869 +
30870 + dctl.d32 = 0;
30871 + dctl.b.pwronprgdone = 1;
30872 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
30873 + dwc_udelay(10);
30874 +
30875 + pcgcctl.d32 = 0;
30876 + pcgcctl.b.enbl_extnd_hiber = 1;
30877 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
30878 +
30879 + /* The core will be in ON STATE */
30880 + core_if->lx_state = DWC_OTG_L0;
30881 + core_if->xhib = 0;
30882 +
30883 + DWC_SPINUNLOCK(core_if->lock);
30884 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
30885 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
30886 + }
30887 + DWC_SPINLOCK(core_if->lock);
30888 +
30889 + }
30890 +
30891 + gintsts.b.restoredone = 1;
30892 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
30893 + DWC_PRINTF(" --Restore done interrupt received-- \n");
30894 + retval |= 1;
30895 + }
30896 + if (gintsts.b.portintr && dwc_otg_is_device_mode(core_if)) {
30897 + /* The port interrupt occurs while in device mode with HPRT0
30898 + * Port Enable/Disable.
30899 + */
30900 + gintsts.d32 = 0;
30901 + gintsts.b.portintr = 1;
30902 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
30903 + retval |= 1;
30904 +
30905 + }
30906 + } else {
30907 + DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32);
30908 +
30909 + if (gpwrdn.b.disconn_det && gpwrdn.b.disconn_det_msk) {
30910 + CLEAR_GPWRDN_INTR(core_if, disconn_det);
30911 + if (gpwrdn.b.linestate == 0) {
30912 + dwc_otg_handle_pwrdn_disconnect_intr(core_if);
30913 + } else {
30914 + DWC_PRINTF("Disconnect detected while linestate is not 0\n");
30915 + }
30916 +
30917 + retval |= 1;
30918 + }
30919 + if (gpwrdn.b.lnstschng && gpwrdn.b.lnstchng_msk) {
30920 + CLEAR_GPWRDN_INTR(core_if, lnstschng);
30921 + /* remote wakeup from hibernation */
30922 + if (gpwrdn.b.linestate == 2 || gpwrdn.b.linestate == 1) {
30923 + dwc_otg_handle_pwrdn_wakeup_detected_intr(core_if);
30924 + } else {
30925 + DWC_PRINTF("gpwrdn.linestate = %d\n", gpwrdn.b.linestate);
30926 + }
30927 + retval |= 1;
30928 + }
30929 + if (gpwrdn.b.rst_det && gpwrdn.b.rst_det_msk) {
30930 + CLEAR_GPWRDN_INTR(core_if, rst_det);
30931 + if (gpwrdn.b.linestate == 0) {
30932 + DWC_PRINTF("Reset detected\n");
30933 + retval |= dwc_otg_device_hibernation_restore(core_if, 0, 1);
30934 + }
30935 + }
30936 + if (gpwrdn.b.srp_det && gpwrdn.b.srp_det_msk) {
30937 + CLEAR_GPWRDN_INTR(core_if, srp_det);
30938 + dwc_otg_handle_pwrdn_srp_intr(core_if);
30939 + retval |= 1;
30940 + }
30941 + }
30942 + /* Handle ADP interrupt here */
30943 + if (gpwrdn.b.adp_int) {
30944 + DWC_PRINTF("ADP interrupt\n");
30945 + CLEAR_GPWRDN_INTR(core_if, adp_int);
30946 + dwc_otg_adp_handle_intr(core_if);
30947 + retval |= 1;
30948 + }
30949 + if (gpwrdn.b.sts_chngint && gpwrdn.b.sts_chngint_msk) {
30950 + DWC_PRINTF("STS CHNG interrupt asserted\n");
30951 + CLEAR_GPWRDN_INTR(core_if, sts_chngint);
30952 + dwc_otg_handle_pwrdn_stschng_intr(otg_dev);
30953 +
30954 + retval |= 1;
30955 + }
30956 + if (core_if->lock)
30957 + DWC_SPINUNLOCK(core_if->lock);
30958 +
30959 + return retval;
30960 +}
30961 --- /dev/null
30962 +++ b/drivers/usb/host/dwc_otg/dwc_otg_core_if.h
30963 @@ -0,0 +1,705 @@
30964 +/* ==========================================================================
30965 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_core_if.h $
30966 + * $Revision: #13 $
30967 + * $Date: 2012/08/10 $
30968 + * $Change: 2047372 $
30969 + *
30970 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
30971 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
30972 + * otherwise expressly agreed to in writing between Synopsys and you.
30973 + *
30974 + * The Software IS NOT an item of Licensed Software or Licensed Product under
30975 + * any End User Software License Agreement or Agreement for Licensed Product
30976 + * with Synopsys or any supplement thereto. You are permitted to use and
30977 + * redistribute this Software in source and binary forms, with or without
30978 + * modification, provided that redistributions of source code must retain this
30979 + * notice. You may not view, use, disclose, copy or distribute this file or
30980 + * any information contained herein except pursuant to this license grant from
30981 + * Synopsys. If you do not agree with this notice, including the disclaimer
30982 + * below, then you are not authorized to use the Software.
30983 + *
30984 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
30985 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30986 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30987 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
30988 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30989 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30990 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30991 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30992 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30993 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30994 + * DAMAGE.
30995 + * ========================================================================== */
30996 +#if !defined(__DWC_CORE_IF_H__)
30997 +#define __DWC_CORE_IF_H__
30998 +
30999 +#include "dwc_os.h"
31000 +
31001 +/** @file
31002 + * This file defines DWC_OTG Core API
31003 + */
31004 +
31005 +struct dwc_otg_core_if;
31006 +typedef struct dwc_otg_core_if dwc_otg_core_if_t;
31007 +
31008 +/** Maximum number of Periodic FIFOs */
31009 +#define MAX_PERIO_FIFOS 15
31010 +/** Maximum number of Periodic FIFOs */
31011 +#define MAX_TX_FIFOS 15
31012 +
31013 +/** Maximum number of Endpoints/HostChannels */
31014 +#define MAX_EPS_CHANNELS 16
31015 +
31016 +extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * _reg_base_addr);
31017 +extern void dwc_otg_core_init(dwc_otg_core_if_t * _core_if);
31018 +extern void dwc_otg_cil_remove(dwc_otg_core_if_t * _core_if);
31019 +
31020 +extern void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * _core_if);
31021 +extern void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * _core_if);
31022 +
31023 +extern uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if);
31024 +extern uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if);
31025 +
31026 +extern uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if);
31027 +
31028 +/** This function should be called on every hardware interrupt. */
31029 +extern int32_t dwc_otg_handle_common_intr(void *otg_dev);
31030 +
31031 +/** @name OTG Core Parameters */
31032 +/** @{ */
31033 +
31034 +/**
31035 + * Specifies the OTG capabilities. The driver will automatically
31036 + * detect the value for this parameter if none is specified.
31037 + * 0 - HNP and SRP capable (default)
31038 + * 1 - SRP Only capable
31039 + * 2 - No HNP/SRP capable
31040 + */
31041 +extern int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val);
31042 +extern int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if);
31043 +#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0
31044 +#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1
31045 +#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
31046 +#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE
31047 +
31048 +extern int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val);
31049 +extern int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if);
31050 +#define dwc_param_opt_default 1
31051 +
31052 +/**
31053 + * Specifies whether to use slave or DMA mode for accessing the data
31054 + * FIFOs. The driver will automatically detect the value for this
31055 + * parameter if none is specified.
31056 + * 0 - Slave
31057 + * 1 - DMA (default, if available)
31058 + */
31059 +extern int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if,
31060 + int32_t val);
31061 +extern int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if);
31062 +#define dwc_param_dma_enable_default 1
31063 +
31064 +/**
31065 + * When DMA mode is enabled specifies whether to use
31066 + * address DMA or DMA Descritor mode for accessing the data
31067 + * FIFOs in device mode. The driver will automatically detect
31068 + * the value for this parameter if none is specified.
31069 + * 0 - address DMA
31070 + * 1 - DMA Descriptor(default, if available)
31071 + */
31072 +extern int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if,
31073 + int32_t val);
31074 +extern int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if);
31075 +//#define dwc_param_dma_desc_enable_default 1
31076 +#define dwc_param_dma_desc_enable_default 0 // Broadcom BCM2708
31077 +
31078 +/** The DMA Burst size (applicable only for External DMA
31079 + * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
31080 + */
31081 +extern int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if,
31082 + int32_t val);
31083 +extern int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if);
31084 +#define dwc_param_dma_burst_size_default 32
31085 +
31086 +/**
31087 + * Specifies the maximum speed of operation in host and device mode.
31088 + * The actual speed depends on the speed of the attached device and
31089 + * the value of phy_type. The actual speed depends on the speed of the
31090 + * attached device.
31091 + * 0 - High Speed (default)
31092 + * 1 - Full Speed
31093 + */
31094 +extern int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val);
31095 +extern int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if);
31096 +#define dwc_param_speed_default 0
31097 +#define DWC_SPEED_PARAM_HIGH 0
31098 +#define DWC_SPEED_PARAM_FULL 1
31099 +
31100 +/** Specifies whether low power mode is supported when attached
31101 + * to a Full Speed or Low Speed device in host mode.
31102 + * 0 - Don't support low power mode (default)
31103 + * 1 - Support low power mode
31104 + */
31105 +extern int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
31106 + core_if, int32_t val);
31107 +extern int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t
31108 + * core_if);
31109 +#define dwc_param_host_support_fs_ls_low_power_default 0
31110 +
31111 +/** Specifies the PHY clock rate in low power mode when connected to a
31112 + * Low Speed device in host mode. This parameter is applicable only if
31113 + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
31114 + * then defaults to 6 MHZ otherwise 48 MHZ.
31115 + *
31116 + * 0 - 48 MHz
31117 + * 1 - 6 MHz
31118 + */
31119 +extern int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
31120 + core_if, int32_t val);
31121 +extern int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
31122 + core_if);
31123 +#define dwc_param_host_ls_low_power_phy_clk_default 0
31124 +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
31125 +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
31126 +
31127 +/**
31128 + * 0 - Use cC FIFO size parameters
31129 + * 1 - Allow dynamic FIFO sizing (default)
31130 + */
31131 +extern int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
31132 + int32_t val);
31133 +extern int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t *
31134 + core_if);
31135 +#define dwc_param_enable_dynamic_fifo_default 1
31136 +
31137 +/** Total number of 4-byte words in the data FIFO memory. This
31138 + * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
31139 + * Tx FIFOs.
31140 + * 32 to 32768 (default 8192)
31141 + * Note: The total FIFO memory depth in the FPGA configuration is 8192.
31142 + */
31143 +extern int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if,
31144 + int32_t val);
31145 +extern int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if);
31146 +//#define dwc_param_data_fifo_size_default 8192
31147 +#define dwc_param_data_fifo_size_default 0xFF0 // Broadcom BCM2708
31148 +
31149 +/** Number of 4-byte words in the Rx FIFO in device mode when dynamic
31150 + * FIFO sizing is enabled.
31151 + * 16 to 32768 (default 1064)
31152 + */
31153 +extern int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if,
31154 + int32_t val);
31155 +extern int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if);
31156 +#define dwc_param_dev_rx_fifo_size_default 1064
31157 +
31158 +/** Number of 4-byte words in the non-periodic Tx FIFO in device mode
31159 + * when dynamic FIFO sizing is enabled.
31160 + * 16 to 32768 (default 1024)
31161 + */
31162 +extern int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
31163 + core_if, int32_t val);
31164 +extern int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
31165 + core_if);
31166 +#define dwc_param_dev_nperio_tx_fifo_size_default 1024
31167 +
31168 +/** Number of 4-byte words in each of the periodic Tx FIFOs in device
31169 + * mode when dynamic FIFO sizing is enabled.
31170 + * 4 to 768 (default 256)
31171 + */
31172 +extern int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
31173 + int32_t val, int fifo_num);
31174 +extern int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t *
31175 + core_if, int fifo_num);
31176 +#define dwc_param_dev_perio_tx_fifo_size_default 256
31177 +
31178 +/** Number of 4-byte words in the Rx FIFO in host mode when dynamic
31179 + * FIFO sizing is enabled.
31180 + * 16 to 32768 (default 1024)
31181 + */
31182 +extern int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
31183 + int32_t val);
31184 +extern int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if);
31185 +//#define dwc_param_host_rx_fifo_size_default 1024
31186 +#define dwc_param_host_rx_fifo_size_default 774 // Broadcom BCM2708
31187 +
31188 +/** Number of 4-byte words in the non-periodic Tx FIFO in host mode
31189 + * when Dynamic FIFO sizing is enabled in the core.
31190 + * 16 to 32768 (default 1024)
31191 + */
31192 +extern int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
31193 + core_if, int32_t val);
31194 +extern int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
31195 + core_if);
31196 +//#define dwc_param_host_nperio_tx_fifo_size_default 1024
31197 +#define dwc_param_host_nperio_tx_fifo_size_default 0x100 // Broadcom BCM2708
31198 +
31199 +/** Number of 4-byte words in the host periodic Tx FIFO when dynamic
31200 + * FIFO sizing is enabled.
31201 + * 16 to 32768 (default 1024)
31202 + */
31203 +extern int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
31204 + core_if, int32_t val);
31205 +extern int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
31206 + core_if);
31207 +//#define dwc_param_host_perio_tx_fifo_size_default 1024
31208 +#define dwc_param_host_perio_tx_fifo_size_default 0x200 // Broadcom BCM2708
31209 +
31210 +/** The maximum transfer size supported in bytes.
31211 + * 2047 to 65,535 (default 65,535)
31212 + */
31213 +extern int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
31214 + int32_t val);
31215 +extern int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if);
31216 +#define dwc_param_max_transfer_size_default 65535
31217 +
31218 +/** The maximum number of packets in a transfer.
31219 + * 15 to 511 (default 511)
31220 + */
31221 +extern int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if,
31222 + int32_t val);
31223 +extern int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if);
31224 +#define dwc_param_max_packet_count_default 511
31225 +
31226 +/** The number of host channel registers to use.
31227 + * 1 to 16 (default 12)
31228 + * Note: The FPGA configuration supports a maximum of 12 host channels.
31229 + */
31230 +extern int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if,
31231 + int32_t val);
31232 +extern int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if);
31233 +//#define dwc_param_host_channels_default 12
31234 +#define dwc_param_host_channels_default 8 // Broadcom BCM2708
31235 +
31236 +/** The number of endpoints in addition to EP0 available for device
31237 + * mode operations.
31238 + * 1 to 15 (default 6 IN and OUT)
31239 + * Note: The FPGA configuration supports a maximum of 6 IN and OUT
31240 + * endpoints in addition to EP0.
31241 + */
31242 +extern int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if,
31243 + int32_t val);
31244 +extern int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if);
31245 +#define dwc_param_dev_endpoints_default 6
31246 +
31247 +/**
31248 + * Specifies the type of PHY interface to use. By default, the driver
31249 + * will automatically detect the phy_type.
31250 + *
31251 + * 0 - Full Speed PHY
31252 + * 1 - UTMI+ (default)
31253 + * 2 - ULPI
31254 + */
31255 +extern int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val);
31256 +extern int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if);
31257 +#define DWC_PHY_TYPE_PARAM_FS 0
31258 +#define DWC_PHY_TYPE_PARAM_UTMI 1
31259 +#define DWC_PHY_TYPE_PARAM_ULPI 2
31260 +#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI
31261 +
31262 +/**
31263 + * Specifies the UTMI+ Data Width. This parameter is
31264 + * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
31265 + * PHY_TYPE, this parameter indicates the data width between
31266 + * the MAC and the ULPI Wrapper.) Also, this parameter is
31267 + * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
31268 + * to "8 and 16 bits", meaning that the core has been
31269 + * configured to work at either data path width.
31270 + *
31271 + * 8 or 16 bits (default 16)
31272 + */
31273 +extern int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if,
31274 + int32_t val);
31275 +extern int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if);
31276 +//#define dwc_param_phy_utmi_width_default 16
31277 +#define dwc_param_phy_utmi_width_default 8 // Broadcom BCM2708
31278 +
31279 +/**
31280 + * Specifies whether the ULPI operates at double or single
31281 + * data rate. This parameter is only applicable if PHY_TYPE is
31282 + * ULPI.
31283 + *
31284 + * 0 - single data rate ULPI interface with 8 bit wide data
31285 + * bus (default)
31286 + * 1 - double data rate ULPI interface with 4 bit wide data
31287 + * bus
31288 + */
31289 +extern int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if,
31290 + int32_t val);
31291 +extern int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if);
31292 +#define dwc_param_phy_ulpi_ddr_default 0
31293 +
31294 +/**
31295 + * Specifies whether to use the internal or external supply to
31296 + * drive the vbus with a ULPI phy.
31297 + */
31298 +extern int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
31299 + int32_t val);
31300 +extern int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if);
31301 +#define DWC_PHY_ULPI_INTERNAL_VBUS 0
31302 +#define DWC_PHY_ULPI_EXTERNAL_VBUS 1
31303 +#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS
31304 +
31305 +/**
31306 + * Specifies whether to use the I2Cinterface for full speed PHY. This
31307 + * parameter is only applicable if PHY_TYPE is FS.
31308 + * 0 - No (default)
31309 + * 1 - Yes
31310 + */
31311 +extern int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if,
31312 + int32_t val);
31313 +extern int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if);
31314 +#define dwc_param_i2c_enable_default 0
31315 +
31316 +extern int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if,
31317 + int32_t val);
31318 +extern int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if);
31319 +#define dwc_param_ulpi_fs_ls_default 0
31320 +
31321 +extern int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val);
31322 +extern int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if);
31323 +#define dwc_param_ts_dline_default 0
31324 +
31325 +/**
31326 + * Specifies whether dedicated transmit FIFOs are
31327 + * enabled for non periodic IN endpoints in device mode
31328 + * 0 - No
31329 + * 1 - Yes
31330 + */
31331 +extern int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
31332 + int32_t val);
31333 +extern int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t *
31334 + core_if);
31335 +#define dwc_param_en_multiple_tx_fifo_default 1
31336 +
31337 +/** Number of 4-byte words in each of the Tx FIFOs in device
31338 + * mode when dynamic FIFO sizing is enabled.
31339 + * 4 to 768 (default 256)
31340 + */
31341 +extern int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
31342 + int fifo_num, int32_t val);
31343 +extern int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
31344 + int fifo_num);
31345 +#define dwc_param_dev_tx_fifo_size_default 768
31346 +
31347 +/** Thresholding enable flag-
31348 + * bit 0 - enable non-ISO Tx thresholding
31349 + * bit 1 - enable ISO Tx thresholding
31350 + * bit 2 - enable Rx thresholding
31351 + */
31352 +extern int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val);
31353 +extern int32_t dwc_otg_get_thr_ctl(dwc_otg_core_if_t * core_if, int fifo_num);
31354 +#define dwc_param_thr_ctl_default 0
31355 +
31356 +/** Thresholding length for Tx
31357 + * FIFOs in 32 bit DWORDs
31358 + */
31359 +extern int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if,
31360 + int32_t val);
31361 +extern int32_t dwc_otg_get_tx_thr_length(dwc_otg_core_if_t * core_if);
31362 +#define dwc_param_tx_thr_length_default 64
31363 +
31364 +/** Thresholding length for Rx
31365 + * FIFOs in 32 bit DWORDs
31366 + */
31367 +extern int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if,
31368 + int32_t val);
31369 +extern int32_t dwc_otg_get_rx_thr_length(dwc_otg_core_if_t * core_if);
31370 +#define dwc_param_rx_thr_length_default 64
31371 +
31372 +/**
31373 + * Specifies whether LPM (Link Power Management) support is enabled
31374 + */
31375 +extern int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if,
31376 + int32_t val);
31377 +extern int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if);
31378 +#define dwc_param_lpm_enable_default 1
31379 +
31380 +/**
31381 + * Specifies whether PTI enhancement is enabled
31382 + */
31383 +extern int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if,
31384 + int32_t val);
31385 +extern int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if);
31386 +#define dwc_param_pti_enable_default 0
31387 +
31388 +/**
31389 + * Specifies whether MPI enhancement is enabled
31390 + */
31391 +extern int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if,
31392 + int32_t val);
31393 +extern int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if);
31394 +#define dwc_param_mpi_enable_default 0
31395 +
31396 +/**
31397 + * Specifies whether ADP capability is enabled
31398 + */
31399 +extern int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if,
31400 + int32_t val);
31401 +extern int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if);
31402 +#define dwc_param_adp_enable_default 0
31403 +
31404 +/**
31405 + * Specifies whether IC_USB capability is enabled
31406 + */
31407 +
31408 +extern int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if,
31409 + int32_t val);
31410 +extern int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if);
31411 +#define dwc_param_ic_usb_cap_default 0
31412 +
31413 +extern int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if,
31414 + int32_t val);
31415 +extern int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if);
31416 +#define dwc_param_ahb_thr_ratio_default 0
31417 +
31418 +extern int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if,
31419 + int32_t val);
31420 +extern int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if);
31421 +#define dwc_param_power_down_default 0
31422 +
31423 +extern int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if,
31424 + int32_t val);
31425 +extern int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if);
31426 +#define dwc_param_reload_ctl_default 0
31427 +
31428 +extern int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if,
31429 + int32_t val);
31430 +extern int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if);
31431 +#define dwc_param_dev_out_nak_default 0
31432 +
31433 +extern int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if,
31434 + int32_t val);
31435 +extern int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if);
31436 +#define dwc_param_cont_on_bna_default 0
31437 +
31438 +extern int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if,
31439 + int32_t val);
31440 +extern int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if);
31441 +#define dwc_param_ahb_single_default 0
31442 +
31443 +extern int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val);
31444 +extern int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if);
31445 +#define dwc_param_otg_ver_default 0
31446 +
31447 +/** @} */
31448 +
31449 +/** @name Access to registers and bit-fields */
31450 +
31451 +/**
31452 + * Dump core registers and SPRAM
31453 + */
31454 +extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * _core_if);
31455 +extern void dwc_otg_dump_spram(dwc_otg_core_if_t * _core_if);
31456 +extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t * _core_if);
31457 +extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t * _core_if);
31458 +
31459 +/**
31460 + * Get host negotiation status.
31461 + */
31462 +extern uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if);
31463 +
31464 +/**
31465 + * Get srp status
31466 + */
31467 +extern uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if);
31468 +
31469 +/**
31470 + * Set hnpreq bit in the GOTGCTL register.
31471 + */
31472 +extern void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val);
31473 +
31474 +/**
31475 + * Get Content of SNPSID register.
31476 + */
31477 +extern uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if);
31478 +
31479 +/**
31480 + * Get current mode.
31481 + * Returns 0 if in device mode, and 1 if in host mode.
31482 + */
31483 +extern uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if);
31484 +
31485 +/**
31486 + * Get value of hnpcapable field in the GUSBCFG register
31487 + */
31488 +extern uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if);
31489 +/**
31490 + * Set value of hnpcapable field in the GUSBCFG register
31491 + */
31492 +extern void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
31493 +
31494 +/**
31495 + * Get value of srpcapable field in the GUSBCFG register
31496 + */
31497 +extern uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if);
31498 +/**
31499 + * Set value of srpcapable field in the GUSBCFG register
31500 + */
31501 +extern void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
31502 +
31503 +/**
31504 + * Get value of devspeed field in the DCFG register
31505 + */
31506 +extern uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if);
31507 +/**
31508 + * Set value of devspeed field in the DCFG register
31509 + */
31510 +extern void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val);
31511 +
31512 +/**
31513 + * Get the value of busconnected field from the HPRT0 register
31514 + */
31515 +extern uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if);
31516 +
31517 +/**
31518 + * Gets the device enumeration Speed.
31519 + */
31520 +extern uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if);
31521 +
31522 +/**
31523 + * Get value of prtpwr field from the HPRT0 register
31524 + */
31525 +extern uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if);
31526 +
31527 +/**
31528 + * Get value of flag indicating core state - hibernated or not
31529 + */
31530 +extern uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if);
31531 +
31532 +/**
31533 + * Set value of prtpwr field from the HPRT0 register
31534 + */
31535 +extern void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val);
31536 +
31537 +/**
31538 + * Get value of prtsusp field from the HPRT0 regsiter
31539 + */
31540 +extern uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if);
31541 +/**
31542 + * Set value of prtpwr field from the HPRT0 register
31543 + */
31544 +extern void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val);
31545 +
31546 +/**
31547 + * Get value of ModeChTimEn field from the HCFG regsiter
31548 + */
31549 +extern uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if);
31550 +/**
31551 + * Set value of ModeChTimEn field from the HCFG regsiter
31552 + */
31553 +extern void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val);
31554 +
31555 +/**
31556 + * Get value of Fram Interval field from the HFIR regsiter
31557 + */
31558 +extern uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if);
31559 +/**
31560 + * Set value of Frame Interval field from the HFIR regsiter
31561 + */
31562 +extern void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val);
31563 +
31564 +/**
31565 + * Set value of prtres field from the HPRT0 register
31566 + *FIXME Remove?
31567 + */
31568 +extern void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val);
31569 +
31570 +/**
31571 + * Get value of rmtwkupsig bit in DCTL register
31572 + */
31573 +extern uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if);
31574 +
31575 +/**
31576 + * Get value of prt_sleep_sts field from the GLPMCFG register
31577 + */
31578 +extern uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if);
31579 +
31580 +/**
31581 + * Get value of rem_wkup_en field from the GLPMCFG register
31582 + */
31583 +extern uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if);
31584 +
31585 +/**
31586 + * Get value of appl_resp field from the GLPMCFG register
31587 + */
31588 +extern uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if);
31589 +/**
31590 + * Set value of appl_resp field from the GLPMCFG register
31591 + */
31592 +extern void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val);
31593 +
31594 +/**
31595 + * Get value of hsic_connect field from the GLPMCFG register
31596 + */
31597 +extern uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if);
31598 +/**
31599 + * Set value of hsic_connect field from the GLPMCFG register
31600 + */
31601 +extern void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val);
31602 +
31603 +/**
31604 + * Get value of inv_sel_hsic field from the GLPMCFG register.
31605 + */
31606 +extern uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if);
31607 +/**
31608 + * Set value of inv_sel_hsic field from the GLPMFG register.
31609 + */
31610 +extern void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val);
31611 +
31612 +/*
31613 + * Some functions for accessing registers
31614 + */
31615 +
31616 +/**
31617 + * GOTGCTL register
31618 + */
31619 +extern uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if);
31620 +extern void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val);
31621 +
31622 +/**
31623 + * GUSBCFG register
31624 + */
31625 +extern uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if);
31626 +extern void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val);
31627 +
31628 +/**
31629 + * GRXFSIZ register
31630 + */
31631 +extern uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if);
31632 +extern void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
31633 +
31634 +/**
31635 + * GNPTXFSIZ register
31636 + */
31637 +extern uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if);
31638 +extern void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
31639 +
31640 +extern uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if);
31641 +extern void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val);
31642 +
31643 +/**
31644 + * GGPIO register
31645 + */
31646 +extern uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if);
31647 +extern void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val);
31648 +
31649 +/**
31650 + * GUID register
31651 + */
31652 +extern uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if);
31653 +extern void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val);
31654 +
31655 +/**
31656 + * HPRT0 register
31657 + */
31658 +extern uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if);
31659 +extern void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val);
31660 +
31661 +/**
31662 + * GHPTXFSIZE
31663 + */
31664 +extern uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if);
31665 +
31666 +/** @} */
31667 +
31668 +#endif /* __DWC_CORE_IF_H__ */
31669 --- /dev/null
31670 +++ b/drivers/usb/host/dwc_otg/dwc_otg_dbg.h
31671 @@ -0,0 +1,117 @@
31672 +/* ==========================================================================
31673 + *
31674 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
31675 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
31676 + * otherwise expressly agreed to in writing between Synopsys and you.
31677 + *
31678 + * The Software IS NOT an item of Licensed Software or Licensed Product under
31679 + * any End User Software License Agreement or Agreement for Licensed Product
31680 + * with Synopsys or any supplement thereto. You are permitted to use and
31681 + * redistribute this Software in source and binary forms, with or without
31682 + * modification, provided that redistributions of source code must retain this
31683 + * notice. You may not view, use, disclose, copy or distribute this file or
31684 + * any information contained herein except pursuant to this license grant from
31685 + * Synopsys. If you do not agree with this notice, including the disclaimer
31686 + * below, then you are not authorized to use the Software.
31687 + *
31688 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
31689 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31690 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31691 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
31692 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31693 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31694 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31695 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31696 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31697 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31698 + * DAMAGE.
31699 + * ========================================================================== */
31700 +
31701 +#ifndef __DWC_OTG_DBG_H__
31702 +#define __DWC_OTG_DBG_H__
31703 +
31704 +/** @file
31705 + * This file defines debug levels.
31706 + * Debugging support vanishes in non-debug builds.
31707 + */
31708 +
31709 +/**
31710 + * The Debug Level bit-mask variable.
31711 + */
31712 +extern uint32_t g_dbg_lvl;
31713 +/**
31714 + * Set the Debug Level variable.
31715 + */
31716 +static inline uint32_t SET_DEBUG_LEVEL(const uint32_t new)
31717 +{
31718 + uint32_t old = g_dbg_lvl;
31719 + g_dbg_lvl = new;
31720 + return old;
31721 +}
31722 +
31723 +#define DBG_USER (0x1)
31724 +/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */
31725 +#define DBG_CIL (0x2)
31726 +/** When debug level has the DBG_CILV bit set, display CIL Verbose debug
31727 + * messages */
31728 +#define DBG_CILV (0x20)
31729 +/** When debug level has the DBG_PCD bit set, display PCD (Device) debug
31730 + * messages */
31731 +#define DBG_PCD (0x4)
31732 +/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug
31733 + * messages */
31734 +#define DBG_PCDV (0x40)
31735 +/** When debug level has the DBG_HCD bit set, display Host debug messages */
31736 +#define DBG_HCD (0x8)
31737 +/** When debug level has the DBG_HCDV bit set, display Verbose Host debug
31738 + * messages */
31739 +#define DBG_HCDV (0x80)
31740 +/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host
31741 + * mode. */
31742 +#define DBG_HCD_URB (0x800)
31743 +/** When debug level has the DBG_HCDI bit set, display host interrupt
31744 + * messages. */
31745 +#define DBG_HCDI (0x1000)
31746 +
31747 +/** When debug level has any bit set, display debug messages */
31748 +#define DBG_ANY (0xFF)
31749 +
31750 +/** All debug messages off */
31751 +#define DBG_OFF 0
31752 +
31753 +/** Prefix string for DWC_DEBUG print macros. */
31754 +#define USB_DWC "DWC_otg: "
31755 +
31756 +/**
31757 + * Print a debug message when the Global debug level variable contains
31758 + * the bit defined in <code>lvl</code>.
31759 + *
31760 + * @param[in] lvl - Debug level, use one of the DBG_ constants above.
31761 + * @param[in] x - like printf
31762 + *
31763 + * Example:<p>
31764 + * <code>
31765 + * DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr);
31766 + * </code>
31767 + * <br>
31768 + * results in:<br>
31769 + * <code>
31770 + * usb-DWC_otg: dwc_otg_cil_init(ca867000)
31771 + * </code>
31772 + */
31773 +#ifdef DEBUG
31774 +
31775 +# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)__DWC_DEBUG(USB_DWC x ); }while(0)
31776 +# define DWC_DEBUGP(x...) DWC_DEBUGPL(DBG_ANY, x )
31777 +
31778 +# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl)
31779 +
31780 +#else
31781 +
31782 +# define DWC_DEBUGPL(lvl, x...) do{}while(0)
31783 +# define DWC_DEBUGP(x...)
31784 +
31785 +# define CHK_DEBUG_LEVEL(level) (0)
31786 +
31787 +#endif /*DEBUG*/
31788 +#endif
31789 --- /dev/null
31790 +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
31791 @@ -0,0 +1,1732 @@
31792 +/* ==========================================================================
31793 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.c $
31794 + * $Revision: #92 $
31795 + * $Date: 2012/08/10 $
31796 + * $Change: 2047372 $
31797 + *
31798 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
31799 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
31800 + * otherwise expressly agreed to in writing between Synopsys and you.
31801 + *
31802 + * The Software IS NOT an item of Licensed Software or Licensed Product under
31803 + * any End User Software License Agreement or Agreement for Licensed Product
31804 + * with Synopsys or any supplement thereto. You are permitted to use and
31805 + * redistribute this Software in source and binary forms, with or without
31806 + * modification, provided that redistributions of source code must retain this
31807 + * notice. You may not view, use, disclose, copy or distribute this file or
31808 + * any information contained herein except pursuant to this license grant from
31809 + * Synopsys. If you do not agree with this notice, including the disclaimer
31810 + * below, then you are not authorized to use the Software.
31811 + *
31812 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
31813 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31814 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31815 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
31816 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31817 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31818 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31819 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31820 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31821 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31822 + * DAMAGE.
31823 + * ========================================================================== */
31824 +
31825 +/** @file
31826 + * The dwc_otg_driver module provides the initialization and cleanup entry
31827 + * points for the DWC_otg driver. This module will be dynamically installed
31828 + * after Linux is booted using the insmod command. When the module is
31829 + * installed, the dwc_otg_driver_init function is called. When the module is
31830 + * removed (using rmmod), the dwc_otg_driver_cleanup function is called.
31831 + *
31832 + * This module also defines a data structure for the dwc_otg_driver, which is
31833 + * used in conjunction with the standard ARM lm_device structure. These
31834 + * structures allow the OTG driver to comply with the standard Linux driver
31835 + * model in which devices and drivers are registered with a bus driver. This
31836 + * has the benefit that Linux can expose attributes of the driver and device
31837 + * in its special sysfs file system. Users can then read or write files in
31838 + * this file system to perform diagnostics on the driver components or the
31839 + * device.
31840 + */
31841 +
31842 +#include "dwc_otg_os_dep.h"
31843 +#include "dwc_os.h"
31844 +#include "dwc_otg_dbg.h"
31845 +#include "dwc_otg_driver.h"
31846 +#include "dwc_otg_attr.h"
31847 +#include "dwc_otg_core_if.h"
31848 +#include "dwc_otg_pcd_if.h"
31849 +#include "dwc_otg_hcd_if.h"
31850 +
31851 +#define DWC_DRIVER_VERSION "3.00a 10-AUG-2012"
31852 +#define DWC_DRIVER_DESC "HS OTG USB Controller driver"
31853 +
31854 +bool microframe_schedule=true;
31855 +
31856 +static const char dwc_driver_name[] = "dwc_otg";
31857 +
31858 +extern void* dummy_send;
31859 +
31860 +extern int pcd_init(
31861 +#ifdef LM_INTERFACE
31862 + struct lm_device *_dev
31863 +#elif defined(PCI_INTERFACE)
31864 + struct pci_dev *_dev
31865 +#elif defined(PLATFORM_INTERFACE)
31866 + struct platform_device *dev
31867 +#endif
31868 + );
31869 +extern int hcd_init(
31870 +#ifdef LM_INTERFACE
31871 + struct lm_device *_dev
31872 +#elif defined(PCI_INTERFACE)
31873 + struct pci_dev *_dev
31874 +#elif defined(PLATFORM_INTERFACE)
31875 + struct platform_device *dev
31876 +#endif
31877 + );
31878 +
31879 +extern int pcd_remove(
31880 +#ifdef LM_INTERFACE
31881 + struct lm_device *_dev
31882 +#elif defined(PCI_INTERFACE)
31883 + struct pci_dev *_dev
31884 +#elif defined(PLATFORM_INTERFACE)
31885 + struct platform_device *_dev
31886 +#endif
31887 + );
31888 +
31889 +extern void hcd_remove(
31890 +#ifdef LM_INTERFACE
31891 + struct lm_device *_dev
31892 +#elif defined(PCI_INTERFACE)
31893 + struct pci_dev *_dev
31894 +#elif defined(PLATFORM_INTERFACE)
31895 + struct platform_device *_dev
31896 +#endif
31897 + );
31898 +
31899 +extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
31900 +
31901 +/*-------------------------------------------------------------------------*/
31902 +/* Encapsulate the module parameter settings */
31903 +
31904 +struct dwc_otg_driver_module_params {
31905 + int32_t opt;
31906 + int32_t otg_cap;
31907 + int32_t dma_enable;
31908 + int32_t dma_desc_enable;
31909 + int32_t dma_burst_size;
31910 + int32_t speed;
31911 + int32_t host_support_fs_ls_low_power;
31912 + int32_t host_ls_low_power_phy_clk;
31913 + int32_t enable_dynamic_fifo;
31914 + int32_t data_fifo_size;
31915 + int32_t dev_rx_fifo_size;
31916 + int32_t dev_nperio_tx_fifo_size;
31917 + uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
31918 + int32_t host_rx_fifo_size;
31919 + int32_t host_nperio_tx_fifo_size;
31920 + int32_t host_perio_tx_fifo_size;
31921 + int32_t max_transfer_size;
31922 + int32_t max_packet_count;
31923 + int32_t host_channels;
31924 + int32_t dev_endpoints;
31925 + int32_t phy_type;
31926 + int32_t phy_utmi_width;
31927 + int32_t phy_ulpi_ddr;
31928 + int32_t phy_ulpi_ext_vbus;
31929 + int32_t i2c_enable;
31930 + int32_t ulpi_fs_ls;
31931 + int32_t ts_dline;
31932 + int32_t en_multiple_tx_fifo;
31933 + uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
31934 + uint32_t thr_ctl;
31935 + uint32_t tx_thr_length;
31936 + uint32_t rx_thr_length;
31937 + int32_t pti_enable;
31938 + int32_t mpi_enable;
31939 + int32_t lpm_enable;
31940 + int32_t ic_usb_cap;
31941 + int32_t ahb_thr_ratio;
31942 + int32_t power_down;
31943 + int32_t reload_ctl;
31944 + int32_t dev_out_nak;
31945 + int32_t cont_on_bna;
31946 + int32_t ahb_single;
31947 + int32_t otg_ver;
31948 + int32_t adp_enable;
31949 +};
31950 +
31951 +static struct dwc_otg_driver_module_params dwc_otg_module_params = {
31952 + .opt = -1,
31953 + .otg_cap = -1,
31954 + .dma_enable = -1,
31955 + .dma_desc_enable = -1,
31956 + .dma_burst_size = -1,
31957 + .speed = -1,
31958 + .host_support_fs_ls_low_power = -1,
31959 + .host_ls_low_power_phy_clk = -1,
31960 + .enable_dynamic_fifo = -1,
31961 + .data_fifo_size = -1,
31962 + .dev_rx_fifo_size = -1,
31963 + .dev_nperio_tx_fifo_size = -1,
31964 + .dev_perio_tx_fifo_size = {
31965 + /* dev_perio_tx_fifo_size_1 */
31966 + -1,
31967 + -1,
31968 + -1,
31969 + -1,
31970 + -1,
31971 + -1,
31972 + -1,
31973 + -1,
31974 + -1,
31975 + -1,
31976 + -1,
31977 + -1,
31978 + -1,
31979 + -1,
31980 + -1
31981 + /* 15 */
31982 + },
31983 + .host_rx_fifo_size = -1,
31984 + .host_nperio_tx_fifo_size = -1,
31985 + .host_perio_tx_fifo_size = -1,
31986 + .max_transfer_size = -1,
31987 + .max_packet_count = -1,
31988 + .host_channels = -1,
31989 + .dev_endpoints = -1,
31990 + .phy_type = -1,
31991 + .phy_utmi_width = -1,
31992 + .phy_ulpi_ddr = -1,
31993 + .phy_ulpi_ext_vbus = -1,
31994 + .i2c_enable = -1,
31995 + .ulpi_fs_ls = -1,
31996 + .ts_dline = -1,
31997 + .en_multiple_tx_fifo = -1,
31998 + .dev_tx_fifo_size = {
31999 + /* dev_tx_fifo_size */
32000 + -1,
32001 + -1,
32002 + -1,
32003 + -1,
32004 + -1,
32005 + -1,
32006 + -1,
32007 + -1,
32008 + -1,
32009 + -1,
32010 + -1,
32011 + -1,
32012 + -1,
32013 + -1,
32014 + -1
32015 + /* 15 */
32016 + },
32017 + .thr_ctl = -1,
32018 + .tx_thr_length = -1,
32019 + .rx_thr_length = -1,
32020 + .pti_enable = -1,
32021 + .mpi_enable = -1,
32022 + .lpm_enable = 0,
32023 + .ic_usb_cap = -1,
32024 + .ahb_thr_ratio = -1,
32025 + .power_down = -1,
32026 + .reload_ctl = -1,
32027 + .dev_out_nak = -1,
32028 + .cont_on_bna = -1,
32029 + .ahb_single = -1,
32030 + .otg_ver = -1,
32031 + .adp_enable = -1,
32032 +};
32033 +
32034 +//Global variable to switch the fiq fix on or off (declared in bcm2708.c)
32035 +extern bool fiq_fix_enable;
32036 +
32037 +//Global variable to switch the nak holdoff on or off
32038 +bool nak_holdoff_enable = true;
32039 +
32040 +
32041 +/**
32042 + * This function shows the Driver Version.
32043 + */
32044 +static ssize_t version_show(struct device_driver *dev, char *buf)
32045 +{
32046 + return snprintf(buf, sizeof(DWC_DRIVER_VERSION) + 2, "%s\n",
32047 + DWC_DRIVER_VERSION);
32048 +}
32049 +
32050 +static DRIVER_ATTR(version, S_IRUGO, version_show, NULL);
32051 +
32052 +/**
32053 + * Global Debug Level Mask.
32054 + */
32055 +uint32_t g_dbg_lvl = 0; /* OFF */
32056 +
32057 +/**
32058 + * This function shows the driver Debug Level.
32059 + */
32060 +static ssize_t dbg_level_show(struct device_driver *drv, char *buf)
32061 +{
32062 + return sprintf(buf, "0x%0x\n", g_dbg_lvl);
32063 +}
32064 +
32065 +/**
32066 + * This function stores the driver Debug Level.
32067 + */
32068 +static ssize_t dbg_level_store(struct device_driver *drv, const char *buf,
32069 + size_t count)
32070 +{
32071 + g_dbg_lvl = simple_strtoul(buf, NULL, 16);
32072 + return count;
32073 +}
32074 +
32075 +static DRIVER_ATTR(debuglevel, S_IRUGO | S_IWUSR, dbg_level_show,
32076 + dbg_level_store);
32077 +
32078 +/**
32079 + * This function is called during module intialization
32080 + * to pass module parameters to the DWC_OTG CORE.
32081 + */
32082 +static int set_parameters(dwc_otg_core_if_t * core_if)
32083 +{
32084 + int retval = 0;
32085 + int i;
32086 +
32087 + if (dwc_otg_module_params.otg_cap != -1) {
32088 + retval +=
32089 + dwc_otg_set_param_otg_cap(core_if,
32090 + dwc_otg_module_params.otg_cap);
32091 + }
32092 + if (dwc_otg_module_params.dma_enable != -1) {
32093 + retval +=
32094 + dwc_otg_set_param_dma_enable(core_if,
32095 + dwc_otg_module_params.
32096 + dma_enable);
32097 + }
32098 + if (dwc_otg_module_params.dma_desc_enable != -1) {
32099 + retval +=
32100 + dwc_otg_set_param_dma_desc_enable(core_if,
32101 + dwc_otg_module_params.
32102 + dma_desc_enable);
32103 + }
32104 + if (dwc_otg_module_params.opt != -1) {
32105 + retval +=
32106 + dwc_otg_set_param_opt(core_if, dwc_otg_module_params.opt);
32107 + }
32108 + if (dwc_otg_module_params.dma_burst_size != -1) {
32109 + retval +=
32110 + dwc_otg_set_param_dma_burst_size(core_if,
32111 + dwc_otg_module_params.
32112 + dma_burst_size);
32113 + }
32114 + if (dwc_otg_module_params.host_support_fs_ls_low_power != -1) {
32115 + retval +=
32116 + dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
32117 + dwc_otg_module_params.
32118 + host_support_fs_ls_low_power);
32119 + }
32120 + if (dwc_otg_module_params.enable_dynamic_fifo != -1) {
32121 + retval +=
32122 + dwc_otg_set_param_enable_dynamic_fifo(core_if,
32123 + dwc_otg_module_params.
32124 + enable_dynamic_fifo);
32125 + }
32126 + if (dwc_otg_module_params.data_fifo_size != -1) {
32127 + retval +=
32128 + dwc_otg_set_param_data_fifo_size(core_if,
32129 + dwc_otg_module_params.
32130 + data_fifo_size);
32131 + }
32132 + if (dwc_otg_module_params.dev_rx_fifo_size != -1) {
32133 + retval +=
32134 + dwc_otg_set_param_dev_rx_fifo_size(core_if,
32135 + dwc_otg_module_params.
32136 + dev_rx_fifo_size);
32137 + }
32138 + if (dwc_otg_module_params.dev_nperio_tx_fifo_size != -1) {
32139 + retval +=
32140 + dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
32141 + dwc_otg_module_params.
32142 + dev_nperio_tx_fifo_size);
32143 + }
32144 + if (dwc_otg_module_params.host_rx_fifo_size != -1) {
32145 + retval +=
32146 + dwc_otg_set_param_host_rx_fifo_size(core_if,
32147 + dwc_otg_module_params.host_rx_fifo_size);
32148 + }
32149 + if (dwc_otg_module_params.host_nperio_tx_fifo_size != -1) {
32150 + retval +=
32151 + dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
32152 + dwc_otg_module_params.
32153 + host_nperio_tx_fifo_size);
32154 + }
32155 + if (dwc_otg_module_params.host_perio_tx_fifo_size != -1) {
32156 + retval +=
32157 + dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
32158 + dwc_otg_module_params.
32159 + host_perio_tx_fifo_size);
32160 + }
32161 + if (dwc_otg_module_params.max_transfer_size != -1) {
32162 + retval +=
32163 + dwc_otg_set_param_max_transfer_size(core_if,
32164 + dwc_otg_module_params.
32165 + max_transfer_size);
32166 + }
32167 + if (dwc_otg_module_params.max_packet_count != -1) {
32168 + retval +=
32169 + dwc_otg_set_param_max_packet_count(core_if,
32170 + dwc_otg_module_params.
32171 + max_packet_count);
32172 + }
32173 + if (dwc_otg_module_params.host_channels != -1) {
32174 + retval +=
32175 + dwc_otg_set_param_host_channels(core_if,
32176 + dwc_otg_module_params.
32177 + host_channels);
32178 + }
32179 + if (dwc_otg_module_params.dev_endpoints != -1) {
32180 + retval +=
32181 + dwc_otg_set_param_dev_endpoints(core_if,
32182 + dwc_otg_module_params.
32183 + dev_endpoints);
32184 + }
32185 + if (dwc_otg_module_params.phy_type != -1) {
32186 + retval +=
32187 + dwc_otg_set_param_phy_type(core_if,
32188 + dwc_otg_module_params.phy_type);
32189 + }
32190 + if (dwc_otg_module_params.speed != -1) {
32191 + retval +=
32192 + dwc_otg_set_param_speed(core_if,
32193 + dwc_otg_module_params.speed);
32194 + }
32195 + if (dwc_otg_module_params.host_ls_low_power_phy_clk != -1) {
32196 + retval +=
32197 + dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
32198 + dwc_otg_module_params.
32199 + host_ls_low_power_phy_clk);
32200 + }
32201 + if (dwc_otg_module_params.phy_ulpi_ddr != -1) {
32202 + retval +=
32203 + dwc_otg_set_param_phy_ulpi_ddr(core_if,
32204 + dwc_otg_module_params.
32205 + phy_ulpi_ddr);
32206 + }
32207 + if (dwc_otg_module_params.phy_ulpi_ext_vbus != -1) {
32208 + retval +=
32209 + dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
32210 + dwc_otg_module_params.
32211 + phy_ulpi_ext_vbus);
32212 + }
32213 + if (dwc_otg_module_params.phy_utmi_width != -1) {
32214 + retval +=
32215 + dwc_otg_set_param_phy_utmi_width(core_if,
32216 + dwc_otg_module_params.
32217 + phy_utmi_width);
32218 + }
32219 + if (dwc_otg_module_params.ulpi_fs_ls != -1) {
32220 + retval +=
32221 + dwc_otg_set_param_ulpi_fs_ls(core_if,
32222 + dwc_otg_module_params.ulpi_fs_ls);
32223 + }
32224 + if (dwc_otg_module_params.ts_dline != -1) {
32225 + retval +=
32226 + dwc_otg_set_param_ts_dline(core_if,
32227 + dwc_otg_module_params.ts_dline);
32228 + }
32229 + if (dwc_otg_module_params.i2c_enable != -1) {
32230 + retval +=
32231 + dwc_otg_set_param_i2c_enable(core_if,
32232 + dwc_otg_module_params.
32233 + i2c_enable);
32234 + }
32235 + if (dwc_otg_module_params.en_multiple_tx_fifo != -1) {
32236 + retval +=
32237 + dwc_otg_set_param_en_multiple_tx_fifo(core_if,
32238 + dwc_otg_module_params.
32239 + en_multiple_tx_fifo);
32240 + }
32241 + for (i = 0; i < 15; i++) {
32242 + if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) {
32243 + retval +=
32244 + dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
32245 + dwc_otg_module_params.
32246 + dev_perio_tx_fifo_size
32247 + [i], i);
32248 + }
32249 + }
32250 +
32251 + for (i = 0; i < 15; i++) {
32252 + if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) {
32253 + retval += dwc_otg_set_param_dev_tx_fifo_size(core_if,
32254 + dwc_otg_module_params.
32255 + dev_tx_fifo_size
32256 + [i], i);
32257 + }
32258 + }
32259 + if (dwc_otg_module_params.thr_ctl != -1) {
32260 + retval +=
32261 + dwc_otg_set_param_thr_ctl(core_if,
32262 + dwc_otg_module_params.thr_ctl);
32263 + }
32264 + if (dwc_otg_module_params.mpi_enable != -1) {
32265 + retval +=
32266 + dwc_otg_set_param_mpi_enable(core_if,
32267 + dwc_otg_module_params.
32268 + mpi_enable);
32269 + }
32270 + if (dwc_otg_module_params.pti_enable != -1) {
32271 + retval +=
32272 + dwc_otg_set_param_pti_enable(core_if,
32273 + dwc_otg_module_params.
32274 + pti_enable);
32275 + }
32276 + if (dwc_otg_module_params.lpm_enable != -1) {
32277 + retval +=
32278 + dwc_otg_set_param_lpm_enable(core_if,
32279 + dwc_otg_module_params.
32280 + lpm_enable);
32281 + }
32282 + if (dwc_otg_module_params.ic_usb_cap != -1) {
32283 + retval +=
32284 + dwc_otg_set_param_ic_usb_cap(core_if,
32285 + dwc_otg_module_params.
32286 + ic_usb_cap);
32287 + }
32288 + if (dwc_otg_module_params.tx_thr_length != -1) {
32289 + retval +=
32290 + dwc_otg_set_param_tx_thr_length(core_if,
32291 + dwc_otg_module_params.tx_thr_length);
32292 + }
32293 + if (dwc_otg_module_params.rx_thr_length != -1) {
32294 + retval +=
32295 + dwc_otg_set_param_rx_thr_length(core_if,
32296 + dwc_otg_module_params.
32297 + rx_thr_length);
32298 + }
32299 + if (dwc_otg_module_params.ahb_thr_ratio != -1) {
32300 + retval +=
32301 + dwc_otg_set_param_ahb_thr_ratio(core_if,
32302 + dwc_otg_module_params.ahb_thr_ratio);
32303 + }
32304 + if (dwc_otg_module_params.power_down != -1) {
32305 + retval +=
32306 + dwc_otg_set_param_power_down(core_if,
32307 + dwc_otg_module_params.power_down);
32308 + }
32309 + if (dwc_otg_module_params.reload_ctl != -1) {
32310 + retval +=
32311 + dwc_otg_set_param_reload_ctl(core_if,
32312 + dwc_otg_module_params.reload_ctl);
32313 + }
32314 +
32315 + if (dwc_otg_module_params.dev_out_nak != -1) {
32316 + retval +=
32317 + dwc_otg_set_param_dev_out_nak(core_if,
32318 + dwc_otg_module_params.dev_out_nak);
32319 + }
32320 +
32321 + if (dwc_otg_module_params.cont_on_bna != -1) {
32322 + retval +=
32323 + dwc_otg_set_param_cont_on_bna(core_if,
32324 + dwc_otg_module_params.cont_on_bna);
32325 + }
32326 +
32327 + if (dwc_otg_module_params.ahb_single != -1) {
32328 + retval +=
32329 + dwc_otg_set_param_ahb_single(core_if,
32330 + dwc_otg_module_params.ahb_single);
32331 + }
32332 +
32333 + if (dwc_otg_module_params.otg_ver != -1) {
32334 + retval +=
32335 + dwc_otg_set_param_otg_ver(core_if,
32336 + dwc_otg_module_params.otg_ver);
32337 + }
32338 + if (dwc_otg_module_params.adp_enable != -1) {
32339 + retval +=
32340 + dwc_otg_set_param_adp_enable(core_if,
32341 + dwc_otg_module_params.
32342 + adp_enable);
32343 + }
32344 + return retval;
32345 +}
32346 +
32347 +/**
32348 + * This function is the top level interrupt handler for the Common
32349 + * (Device and host modes) interrupts.
32350 + */
32351 +static irqreturn_t dwc_otg_common_irq(int irq, void *dev)
32352 +{
32353 + int32_t retval = IRQ_NONE;
32354 +
32355 + retval = dwc_otg_handle_common_intr(dev);
32356 + if (retval != 0) {
32357 + S3C2410X_CLEAR_EINTPEND();
32358 + }
32359 + return IRQ_RETVAL(retval);
32360 +}
32361 +
32362 +/**
32363 + * This function is called when a lm_device is unregistered with the
32364 + * dwc_otg_driver. This happens, for example, when the rmmod command is
32365 + * executed. The device may or may not be electrically present. If it is
32366 + * present, the driver stops device processing. Any resources used on behalf
32367 + * of this device are freed.
32368 + *
32369 + * @param _dev
32370 + */
32371 +#ifdef LM_INTERFACE
32372 +#define REM_RETVAL(n)
32373 +static void dwc_otg_driver_remove( struct lm_device *_dev )
32374 +{ dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
32375 +#elif defined(PCI_INTERFACE)
32376 +#define REM_RETVAL(n)
32377 +static void dwc_otg_driver_remove( struct pci_dev *_dev )
32378 +{ dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
32379 +#elif defined(PLATFORM_INTERFACE)
32380 +#define REM_RETVAL(n) n
32381 +static int dwc_otg_driver_remove( struct platform_device *_dev )
32382 +{ dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
32383 +#endif
32384 +
32385 + DWC_DEBUGPL(DBG_ANY, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev);
32386 +
32387 + if (!otg_dev) {
32388 + /* Memory allocation for the dwc_otg_device failed. */
32389 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
32390 + return REM_RETVAL(-ENOMEM);
32391 + }
32392 +#ifndef DWC_DEVICE_ONLY
32393 + if (otg_dev->hcd) {
32394 + hcd_remove(_dev);
32395 + } else {
32396 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
32397 + return REM_RETVAL(-EINVAL);
32398 + }
32399 +#endif
32400 +
32401 +#ifndef DWC_HOST_ONLY
32402 + if (otg_dev->pcd) {
32403 + pcd_remove(_dev);
32404 + } else {
32405 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->pcd NULL!\n", __func__);
32406 + return REM_RETVAL(-EINVAL);
32407 + }
32408 +#endif
32409 + /*
32410 + * Free the IRQ
32411 + */
32412 + if (otg_dev->common_irq_installed) {
32413 +#ifdef PLATFORM_INTERFACE
32414 + free_irq(platform_get_irq(_dev, 0), otg_dev);
32415 +#else
32416 + free_irq(_dev->irq, otg_dev);
32417 +#endif
32418 + } else {
32419 + DWC_DEBUGPL(DBG_ANY, "%s: There is no installed irq!\n", __func__);
32420 + return REM_RETVAL(-ENXIO);
32421 + }
32422 +
32423 + if (otg_dev->core_if) {
32424 + dwc_otg_cil_remove(otg_dev->core_if);
32425 + } else {
32426 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->core_if NULL!\n", __func__);
32427 + return REM_RETVAL(-ENXIO);
32428 + }
32429 +
32430 + /*
32431 + * Remove the device attributes
32432 + */
32433 + dwc_otg_attr_remove(_dev);
32434 +
32435 + /*
32436 + * Return the memory.
32437 + */
32438 + if (otg_dev->os_dep.base) {
32439 + iounmap(otg_dev->os_dep.base);
32440 + }
32441 + DWC_FREE(otg_dev);
32442 +
32443 + /*
32444 + * Clear the drvdata pointer.
32445 + */
32446 +#ifdef LM_INTERFACE
32447 + lm_set_drvdata(_dev, 0);
32448 +#elif defined(PCI_INTERFACE)
32449 + release_mem_region(otg_dev->os_dep.rsrc_start,
32450 + otg_dev->os_dep.rsrc_len);
32451 + pci_set_drvdata(_dev, 0);
32452 +#elif defined(PLATFORM_INTERFACE)
32453 + platform_set_drvdata(_dev, 0);
32454 +#endif
32455 + return REM_RETVAL(0);
32456 +}
32457 +
32458 +/**
32459 + * This function is called when an lm_device is bound to a
32460 + * dwc_otg_driver. It creates the driver components required to
32461 + * control the device (CIL, HCD, and PCD) and it initializes the
32462 + * device. The driver components are stored in a dwc_otg_device
32463 + * structure. A reference to the dwc_otg_device is saved in the
32464 + * lm_device. This allows the driver to access the dwc_otg_device
32465 + * structure on subsequent calls to driver methods for this device.
32466 + *
32467 + * @param _dev Bus device
32468 + */
32469 +static int dwc_otg_driver_probe(
32470 +#ifdef LM_INTERFACE
32471 + struct lm_device *_dev
32472 +#elif defined(PCI_INTERFACE)
32473 + struct pci_dev *_dev,
32474 + const struct pci_device_id *id
32475 +#elif defined(PLATFORM_INTERFACE)
32476 + struct platform_device *_dev
32477 +#endif
32478 + )
32479 +{
32480 + int retval = 0;
32481 + dwc_otg_device_t *dwc_otg_device;
32482 + int devirq;
32483 +
32484 + dev_dbg(&_dev->dev, "dwc_otg_driver_probe(%p)\n", _dev);
32485 +#ifdef LM_INTERFACE
32486 + dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)_dev->resource.start);
32487 +#elif defined(PCI_INTERFACE)
32488 + if (!id) {
32489 + DWC_ERROR("Invalid pci_device_id %p", id);
32490 + return -EINVAL;
32491 + }
32492 +
32493 + if (!_dev || (pci_enable_device(_dev) < 0)) {
32494 + DWC_ERROR("Invalid pci_device %p", _dev);
32495 + return -ENODEV;
32496 + }
32497 + dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)pci_resource_start(_dev,0));
32498 + /* other stuff needed as well? */
32499 +
32500 +#elif defined(PLATFORM_INTERFACE)
32501 + dev_dbg(&_dev->dev, "start=0x%08x (len 0x%x)\n",
32502 + (unsigned)_dev->resource->start,
32503 + (unsigned)(_dev->resource->end - _dev->resource->start));
32504 +#endif
32505 +
32506 + dwc_otg_device = DWC_ALLOC(sizeof(dwc_otg_device_t));
32507 +
32508 + if (!dwc_otg_device) {
32509 + dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n");
32510 + return -ENOMEM;
32511 + }
32512 +
32513 + memset(dwc_otg_device, 0, sizeof(*dwc_otg_device));
32514 + dwc_otg_device->os_dep.reg_offset = 0xFFFFFFFF;
32515 +
32516 + /*
32517 + * Map the DWC_otg Core memory into virtual address space.
32518 + */
32519 +#ifdef LM_INTERFACE
32520 + dwc_otg_device->os_dep.base = ioremap(_dev->resource.start, SZ_256K);
32521 +
32522 + if (!dwc_otg_device->os_dep.base) {
32523 + dev_err(&_dev->dev, "ioremap() failed\n");
32524 + DWC_FREE(dwc_otg_device);
32525 + return -ENOMEM;
32526 + }
32527 + dev_dbg(&_dev->dev, "base=0x%08x\n",
32528 + (unsigned)dwc_otg_device->os_dep.base);
32529 +#elif defined(PCI_INTERFACE)
32530 + _dev->current_state = PCI_D0;
32531 + _dev->dev.power.power_state = PMSG_ON;
32532 +
32533 + if (!_dev->irq) {
32534 + DWC_ERROR("Found HC with no IRQ. Check BIOS/PCI %s setup!",
32535 + pci_name(_dev));
32536 + iounmap(dwc_otg_device->os_dep.base);
32537 + DWC_FREE(dwc_otg_device);
32538 + return -ENODEV;
32539 + }
32540 +
32541 + dwc_otg_device->os_dep.rsrc_start = pci_resource_start(_dev, 0);
32542 + dwc_otg_device->os_dep.rsrc_len = pci_resource_len(_dev, 0);
32543 + DWC_DEBUGPL(DBG_ANY, "PCI resource: start=%08x, len=%08x\n",
32544 + (unsigned)dwc_otg_device->os_dep.rsrc_start,
32545 + (unsigned)dwc_otg_device->os_dep.rsrc_len);
32546 + if (!request_mem_region
32547 + (dwc_otg_device->os_dep.rsrc_start, dwc_otg_device->os_dep.rsrc_len,
32548 + "dwc_otg")) {
32549 + dev_dbg(&_dev->dev, "error requesting memory\n");
32550 + iounmap(dwc_otg_device->os_dep.base);
32551 + DWC_FREE(dwc_otg_device);
32552 + return -EFAULT;
32553 + }
32554 +
32555 + dwc_otg_device->os_dep.base =
32556 + ioremap_nocache(dwc_otg_device->os_dep.rsrc_start,
32557 + dwc_otg_device->os_dep.rsrc_len);
32558 + if (dwc_otg_device->os_dep.base == NULL) {
32559 + dev_dbg(&_dev->dev, "error mapping memory\n");
32560 + release_mem_region(dwc_otg_device->os_dep.rsrc_start,
32561 + dwc_otg_device->os_dep.rsrc_len);
32562 + iounmap(dwc_otg_device->os_dep.base);
32563 + DWC_FREE(dwc_otg_device);
32564 + return -EFAULT;
32565 + }
32566 + dev_dbg(&_dev->dev, "base=0x%p (before adjust) \n",
32567 + dwc_otg_device->os_dep.base);
32568 + dwc_otg_device->os_dep.base = (char *)dwc_otg_device->os_dep.base;
32569 + dev_dbg(&_dev->dev, "base=0x%p (after adjust) \n",
32570 + dwc_otg_device->os_dep.base);
32571 + dev_dbg(&_dev->dev, "%s: mapped PA 0x%x to VA 0x%p\n", __func__,
32572 + (unsigned)dwc_otg_device->os_dep.rsrc_start,
32573 + dwc_otg_device->os_dep.base);
32574 +
32575 + pci_set_master(_dev);
32576 + pci_set_drvdata(_dev, dwc_otg_device);
32577 +#elif defined(PLATFORM_INTERFACE)
32578 + DWC_DEBUGPL(DBG_ANY,"Platform resource: start=%08x, len=%08x\n",
32579 + _dev->resource->start,
32580 + _dev->resource->end - _dev->resource->start + 1);
32581 +#if 1
32582 + if (!request_mem_region(_dev->resource[0].start,
32583 + _dev->resource[0].end - _dev->resource[0].start + 1,
32584 + "dwc_otg")) {
32585 + dev_dbg(&_dev->dev, "error reserving mapped memory\n");
32586 + retval = -EFAULT;
32587 + goto fail;
32588 + }
32589 +
32590 + dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource[0].start,
32591 + _dev->resource[0].end -
32592 + _dev->resource[0].start+1);
32593 + if (fiq_fix_enable)
32594 + {
32595 + if (!request_mem_region(_dev->resource[1].start,
32596 + _dev->resource[1].end - _dev->resource[1].start + 1,
32597 + "dwc_otg")) {
32598 + dev_dbg(&_dev->dev, "error reserving mapped memory\n");
32599 + retval = -EFAULT;
32600 + goto fail;
32601 + }
32602 +
32603 + dwc_otg_device->os_dep.mphi_base = ioremap_nocache(_dev->resource[1].start,
32604 + _dev->resource[1].end -
32605 + _dev->resource[1].start + 1);
32606 + dummy_send = (void *) kmalloc(16, GFP_ATOMIC);
32607 + }
32608 +
32609 +#else
32610 + {
32611 + struct map_desc desc = {
32612 + .virtual = IO_ADDRESS((unsigned)_dev->resource->start),
32613 + .pfn = __phys_to_pfn((unsigned)_dev->resource->start),
32614 + .length = SZ_128K,
32615 + .type = MT_DEVICE
32616 + };
32617 + iotable_init(&desc, 1);
32618 + dwc_otg_device->os_dep.base = (void *)desc.virtual;
32619 + }
32620 +#endif
32621 + if (!dwc_otg_device->os_dep.base) {
32622 + dev_err(&_dev->dev, "ioremap() failed\n");
32623 + retval = -ENOMEM;
32624 + goto fail;
32625 + }
32626 + dev_dbg(&_dev->dev, "base=0x%08x\n",
32627 + (unsigned)dwc_otg_device->os_dep.base);
32628 +#endif
32629 +
32630 + /*
32631 + * Initialize driver data to point to the global DWC_otg
32632 + * Device structure.
32633 + */
32634 +#ifdef LM_INTERFACE
32635 + lm_set_drvdata(_dev, dwc_otg_device);
32636 +#elif defined(PLATFORM_INTERFACE)
32637 + platform_set_drvdata(_dev, dwc_otg_device);
32638 +#endif
32639 + dev_dbg(&_dev->dev, "dwc_otg_device=0x%p\n", dwc_otg_device);
32640 +
32641 + dwc_otg_device->core_if = dwc_otg_cil_init(dwc_otg_device->os_dep.base);
32642 + DWC_DEBUGPL(DBG_HCDV, "probe of device %p given core_if %p\n",
32643 + dwc_otg_device, dwc_otg_device->core_if);//GRAYG
32644 +
32645 + if (!dwc_otg_device->core_if) {
32646 + dev_err(&_dev->dev, "CIL initialization failed!\n");
32647 + retval = -ENOMEM;
32648 + goto fail;
32649 + }
32650 +
32651 + dev_dbg(&_dev->dev, "Calling get_gsnpsid\n");
32652 + /*
32653 + * Attempt to ensure this device is really a DWC_otg Controller.
32654 + * Read and verify the SNPSID register contents. The value should be
32655 + * 0x45F42XXX or 0x45F42XXX, which corresponds to either "OT2" or "OTG3",
32656 + * as in "OTG version 2.XX" or "OTG version 3.XX".
32657 + */
32658 +
32659 + if (((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F542000) &&
32660 + ((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F543000)) {
32661 + dev_err(&_dev->dev, "Bad value for SNPSID: 0x%08x\n",
32662 + dwc_otg_get_gsnpsid(dwc_otg_device->core_if));
32663 + retval = -EINVAL;
32664 + goto fail;
32665 + }
32666 +
32667 + /*
32668 + * Validate parameter values.
32669 + */
32670 + dev_dbg(&_dev->dev, "Calling set_parameters\n");
32671 + if (set_parameters(dwc_otg_device->core_if)) {
32672 + retval = -EINVAL;
32673 + goto fail;
32674 + }
32675 +
32676 + /*
32677 + * Create Device Attributes in sysfs
32678 + */
32679 + dev_dbg(&_dev->dev, "Calling attr_create\n");
32680 + dwc_otg_attr_create(_dev);
32681 +
32682 + /*
32683 + * Disable the global interrupt until all the interrupt
32684 + * handlers are installed.
32685 + */
32686 + dev_dbg(&_dev->dev, "Calling disable_global_interrupts\n");
32687 + dwc_otg_disable_global_interrupts(dwc_otg_device->core_if);
32688 +
32689 + /*
32690 + * Install the interrupt handler for the common interrupts before
32691 + * enabling common interrupts in core_init below.
32692 + */
32693 +
32694 +#if defined(PLATFORM_INTERFACE)
32695 + devirq = platform_get_irq(_dev, 0);
32696 +#else
32697 + devirq = _dev->irq;
32698 +#endif
32699 + DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n",
32700 + devirq);
32701 + dev_dbg(&_dev->dev, "Calling request_irq(%d)\n", devirq);
32702 + retval = request_irq(devirq, dwc_otg_common_irq,
32703 + IRQF_SHARED,
32704 + "dwc_otg", dwc_otg_device);
32705 + if (retval) {
32706 + DWC_ERROR("request of irq%d failed\n", devirq);
32707 + retval = -EBUSY;
32708 + goto fail;
32709 + } else {
32710 + dwc_otg_device->common_irq_installed = 1;
32711 + }
32712 +
32713 +#ifndef IRQF_TRIGGER_LOW
32714 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
32715 + dev_dbg(&_dev->dev, "Calling set_irq_type\n");
32716 + set_irq_type(devirq,
32717 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
32718 + IRQT_LOW
32719 +#else
32720 + IRQ_TYPE_LEVEL_LOW
32721 +#endif
32722 + );
32723 +#endif
32724 +#endif /*IRQF_TRIGGER_LOW*/
32725 +
32726 + /*
32727 + * Initialize the DWC_otg core.
32728 + */
32729 + dev_dbg(&_dev->dev, "Calling dwc_otg_core_init\n");
32730 + dwc_otg_core_init(dwc_otg_device->core_if);
32731 +
32732 +#ifndef DWC_HOST_ONLY
32733 + /*
32734 + * Initialize the PCD
32735 + */
32736 + dev_dbg(&_dev->dev, "Calling pcd_init\n");
32737 + retval = pcd_init(_dev);
32738 + if (retval != 0) {
32739 + DWC_ERROR("pcd_init failed\n");
32740 + dwc_otg_device->pcd = NULL;
32741 + goto fail;
32742 + }
32743 +#endif
32744 +#ifndef DWC_DEVICE_ONLY
32745 + /*
32746 + * Initialize the HCD
32747 + */
32748 + dev_dbg(&_dev->dev, "Calling hcd_init\n");
32749 + retval = hcd_init(_dev);
32750 + if (retval != 0) {
32751 + DWC_ERROR("hcd_init failed\n");
32752 + dwc_otg_device->hcd = NULL;
32753 + goto fail;
32754 + }
32755 +#endif
32756 + /* Recover from drvdata having been overwritten by hcd_init() */
32757 +#ifdef LM_INTERFACE
32758 + lm_set_drvdata(_dev, dwc_otg_device);
32759 +#elif defined(PLATFORM_INTERFACE)
32760 + platform_set_drvdata(_dev, dwc_otg_device);
32761 +#elif defined(PCI_INTERFACE)
32762 + pci_set_drvdata(_dev, dwc_otg_device);
32763 + dwc_otg_device->os_dep.pcidev = _dev;
32764 +#endif
32765 +
32766 + /*
32767 + * Enable the global interrupt after all the interrupt
32768 + * handlers are installed if there is no ADP support else
32769 + * perform initial actions required for Internal ADP logic.
32770 + */
32771 + if (!dwc_otg_get_param_adp_enable(dwc_otg_device->core_if)) {
32772 + dev_dbg(&_dev->dev, "Calling enable_global_interrupts\n");
32773 + dwc_otg_enable_global_interrupts(dwc_otg_device->core_if);
32774 + dev_dbg(&_dev->dev, "Done\n");
32775 + } else
32776 + dwc_otg_adp_start(dwc_otg_device->core_if,
32777 + dwc_otg_is_host_mode(dwc_otg_device->core_if));
32778 +
32779 + return 0;
32780 +
32781 +fail:
32782 + dwc_otg_driver_remove(_dev);
32783 + return retval;
32784 +}
32785 +
32786 +/**
32787 + * This structure defines the methods to be called by a bus driver
32788 + * during the lifecycle of a device on that bus. Both drivers and
32789 + * devices are registered with a bus driver. The bus driver matches
32790 + * devices to drivers based on information in the device and driver
32791 + * structures.
32792 + *
32793 + * The probe function is called when the bus driver matches a device
32794 + * to this driver. The remove function is called when a device is
32795 + * unregistered with the bus driver.
32796 + */
32797 +#ifdef LM_INTERFACE
32798 +static struct lm_driver dwc_otg_driver = {
32799 + .drv = {.name = (char *)dwc_driver_name,},
32800 + .probe = dwc_otg_driver_probe,
32801 + .remove = dwc_otg_driver_remove,
32802 + // 'suspend' and 'resume' absent
32803 +};
32804 +#elif defined(PCI_INTERFACE)
32805 +static const struct pci_device_id pci_ids[] = { {
32806 + PCI_DEVICE(0x16c3, 0xabcd),
32807 + .driver_data =
32808 + (unsigned long)0xdeadbeef,
32809 + }, { /* end: all zeroes */ }
32810 +};
32811 +
32812 +MODULE_DEVICE_TABLE(pci, pci_ids);
32813 +
32814 +/* pci driver glue; this is a "new style" PCI driver module */
32815 +static struct pci_driver dwc_otg_driver = {
32816 + .name = "dwc_otg",
32817 + .id_table = pci_ids,
32818 +
32819 + .probe = dwc_otg_driver_probe,
32820 + .remove = dwc_otg_driver_remove,
32821 +
32822 + .driver = {
32823 + .name = (char *)dwc_driver_name,
32824 + },
32825 +};
32826 +#elif defined(PLATFORM_INTERFACE)
32827 +static struct platform_device_id platform_ids[] = {
32828 + {
32829 + .name = "bcm2708_usb",
32830 + .driver_data = (kernel_ulong_t) 0xdeadbeef,
32831 + },
32832 + { /* end: all zeroes */ }
32833 +};
32834 +MODULE_DEVICE_TABLE(platform, platform_ids);
32835 +
32836 +static struct platform_driver dwc_otg_driver = {
32837 + .driver = {
32838 + .name = (char *)dwc_driver_name,
32839 + },
32840 + .id_table = platform_ids,
32841 +
32842 + .probe = dwc_otg_driver_probe,
32843 + .remove = dwc_otg_driver_remove,
32844 + // no 'shutdown', 'suspend', 'resume', 'suspend_late' or 'resume_early'
32845 +};
32846 +#endif
32847 +
32848 +/**
32849 + * This function is called when the dwc_otg_driver is installed with the
32850 + * insmod command. It registers the dwc_otg_driver structure with the
32851 + * appropriate bus driver. This will cause the dwc_otg_driver_probe function
32852 + * to be called. In addition, the bus driver will automatically expose
32853 + * attributes defined for the device and driver in the special sysfs file
32854 + * system.
32855 + *
32856 + * @return
32857 + */
32858 +static int __init dwc_otg_driver_init(void)
32859 +{
32860 + int retval = 0;
32861 + int error;
32862 + struct device_driver *drv;
32863 + printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name,
32864 + DWC_DRIVER_VERSION,
32865 +#ifdef LM_INTERFACE
32866 + "logicmodule");
32867 + retval = lm_driver_register(&dwc_otg_driver);
32868 + drv = &dwc_otg_driver.drv;
32869 +#elif defined(PCI_INTERFACE)
32870 + "pci");
32871 + retval = pci_register_driver(&dwc_otg_driver);
32872 + drv = &dwc_otg_driver.driver;
32873 +#elif defined(PLATFORM_INTERFACE)
32874 + "platform");
32875 + retval = platform_driver_register(&dwc_otg_driver);
32876 + drv = &dwc_otg_driver.driver;
32877 +#endif
32878 + if (retval < 0) {
32879 + printk(KERN_ERR "%s retval=%d\n", __func__, retval);
32880 + return retval;
32881 + }
32882 + printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_fix_enable ? "enabled":"disabled");
32883 + printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff_enable ? "enabled":"disabled");
32884 +
32885 + error = driver_create_file(drv, &driver_attr_version);
32886 +#ifdef DEBUG
32887 + error = driver_create_file(drv, &driver_attr_debuglevel);
32888 +#endif
32889 + return retval;
32890 +}
32891 +
32892 +module_init(dwc_otg_driver_init);
32893 +
32894 +/**
32895 + * This function is called when the driver is removed from the kernel
32896 + * with the rmmod command. The driver unregisters itself with its bus
32897 + * driver.
32898 + *
32899 + */
32900 +static void __exit dwc_otg_driver_cleanup(void)
32901 +{
32902 + printk(KERN_DEBUG "dwc_otg_driver_cleanup()\n");
32903 +
32904 +#ifdef LM_INTERFACE
32905 + driver_remove_file(&dwc_otg_driver.drv, &driver_attr_debuglevel);
32906 + driver_remove_file(&dwc_otg_driver.drv, &driver_attr_version);
32907 + lm_driver_unregister(&dwc_otg_driver);
32908 +#elif defined(PCI_INTERFACE)
32909 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
32910 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
32911 + pci_unregister_driver(&dwc_otg_driver);
32912 +#elif defined(PLATFORM_INTERFACE)
32913 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
32914 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
32915 + platform_driver_unregister(&dwc_otg_driver);
32916 +#endif
32917 +
32918 + printk(KERN_INFO "%s module removed\n", dwc_driver_name);
32919 +}
32920 +
32921 +module_exit(dwc_otg_driver_cleanup);
32922 +
32923 +MODULE_DESCRIPTION(DWC_DRIVER_DESC);
32924 +MODULE_AUTHOR("Synopsys Inc.");
32925 +MODULE_LICENSE("GPL");
32926 +
32927 +module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444);
32928 +MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None");
32929 +module_param_named(opt, dwc_otg_module_params.opt, int, 0444);
32930 +MODULE_PARM_DESC(opt, "OPT Mode");
32931 +module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444);
32932 +MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled");
32933 +
32934 +module_param_named(dma_desc_enable, dwc_otg_module_params.dma_desc_enable, int,
32935 + 0444);
32936 +MODULE_PARM_DESC(dma_desc_enable,
32937 + "DMA Desc Mode 0=Address DMA 1=DMA Descriptor enabled");
32938 +
32939 +module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int,
32940 + 0444);
32941 +MODULE_PARM_DESC(dma_burst_size,
32942 + "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256");
32943 +module_param_named(speed, dwc_otg_module_params.speed, int, 0444);
32944 +MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed");
32945 +module_param_named(host_support_fs_ls_low_power,
32946 + dwc_otg_module_params.host_support_fs_ls_low_power, int,
32947 + 0444);
32948 +MODULE_PARM_DESC(host_support_fs_ls_low_power,
32949 + "Support Low Power w/FS or LS 0=Support 1=Don't Support");
32950 +module_param_named(host_ls_low_power_phy_clk,
32951 + dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444);
32952 +MODULE_PARM_DESC(host_ls_low_power_phy_clk,
32953 + "Low Speed Low Power Clock 0=48Mhz 1=6Mhz");
32954 +module_param_named(enable_dynamic_fifo,
32955 + dwc_otg_module_params.enable_dynamic_fifo, int, 0444);
32956 +MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing");
32957 +module_param_named(data_fifo_size, dwc_otg_module_params.data_fifo_size, int,
32958 + 0444);
32959 +MODULE_PARM_DESC(data_fifo_size,
32960 + "Total number of words in the data FIFO memory 32-32768");
32961 +module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size,
32962 + int, 0444);
32963 +MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
32964 +module_param_named(dev_nperio_tx_fifo_size,
32965 + dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444);
32966 +MODULE_PARM_DESC(dev_nperio_tx_fifo_size,
32967 + "Number of words in the non-periodic Tx FIFO 16-32768");
32968 +module_param_named(dev_perio_tx_fifo_size_1,
32969 + dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444);
32970 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_1,
32971 + "Number of words in the periodic Tx FIFO 4-768");
32972 +module_param_named(dev_perio_tx_fifo_size_2,
32973 + dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444);
32974 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_2,
32975 + "Number of words in the periodic Tx FIFO 4-768");
32976 +module_param_named(dev_perio_tx_fifo_size_3,
32977 + dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444);
32978 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_3,
32979 + "Number of words in the periodic Tx FIFO 4-768");
32980 +module_param_named(dev_perio_tx_fifo_size_4,
32981 + dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444);
32982 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_4,
32983 + "Number of words in the periodic Tx FIFO 4-768");
32984 +module_param_named(dev_perio_tx_fifo_size_5,
32985 + dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444);
32986 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_5,
32987 + "Number of words in the periodic Tx FIFO 4-768");
32988 +module_param_named(dev_perio_tx_fifo_size_6,
32989 + dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444);
32990 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_6,
32991 + "Number of words in the periodic Tx FIFO 4-768");
32992 +module_param_named(dev_perio_tx_fifo_size_7,
32993 + dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444);
32994 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_7,
32995 + "Number of words in the periodic Tx FIFO 4-768");
32996 +module_param_named(dev_perio_tx_fifo_size_8,
32997 + dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444);
32998 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_8,
32999 + "Number of words in the periodic Tx FIFO 4-768");
33000 +module_param_named(dev_perio_tx_fifo_size_9,
33001 + dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444);
33002 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_9,
33003 + "Number of words in the periodic Tx FIFO 4-768");
33004 +module_param_named(dev_perio_tx_fifo_size_10,
33005 + dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444);
33006 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_10,
33007 + "Number of words in the periodic Tx FIFO 4-768");
33008 +module_param_named(dev_perio_tx_fifo_size_11,
33009 + dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444);
33010 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_11,
33011 + "Number of words in the periodic Tx FIFO 4-768");
33012 +module_param_named(dev_perio_tx_fifo_size_12,
33013 + dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444);
33014 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_12,
33015 + "Number of words in the periodic Tx FIFO 4-768");
33016 +module_param_named(dev_perio_tx_fifo_size_13,
33017 + dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444);
33018 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_13,
33019 + "Number of words in the periodic Tx FIFO 4-768");
33020 +module_param_named(dev_perio_tx_fifo_size_14,
33021 + dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444);
33022 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_14,
33023 + "Number of words in the periodic Tx FIFO 4-768");
33024 +module_param_named(dev_perio_tx_fifo_size_15,
33025 + dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444);
33026 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_15,
33027 + "Number of words in the periodic Tx FIFO 4-768");
33028 +module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size,
33029 + int, 0444);
33030 +MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
33031 +module_param_named(host_nperio_tx_fifo_size,
33032 + dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444);
33033 +MODULE_PARM_DESC(host_nperio_tx_fifo_size,
33034 + "Number of words in the non-periodic Tx FIFO 16-32768");
33035 +module_param_named(host_perio_tx_fifo_size,
33036 + dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444);
33037 +MODULE_PARM_DESC(host_perio_tx_fifo_size,
33038 + "Number of words in the host periodic Tx FIFO 16-32768");
33039 +module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size,
33040 + int, 0444);
33041 +/** @todo Set the max to 512K, modify checks */
33042 +MODULE_PARM_DESC(max_transfer_size,
33043 + "The maximum transfer size supported in bytes 2047-65535");
33044 +module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count,
33045 + int, 0444);
33046 +MODULE_PARM_DESC(max_packet_count,
33047 + "The maximum number of packets in a transfer 15-511");
33048 +module_param_named(host_channels, dwc_otg_module_params.host_channels, int,
33049 + 0444);
33050 +MODULE_PARM_DESC(host_channels,
33051 + "The number of host channel registers to use 1-16");
33052 +module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int,
33053 + 0444);
33054 +MODULE_PARM_DESC(dev_endpoints,
33055 + "The number of endpoints in addition to EP0 available for device mode 1-15");
33056 +module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444);
33057 +MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI");
33058 +module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int,
33059 + 0444);
33060 +MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits");
33061 +module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444);
33062 +MODULE_PARM_DESC(phy_ulpi_ddr,
33063 + "ULPI at double or single data rate 0=Single 1=Double");
33064 +module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus,
33065 + int, 0444);
33066 +MODULE_PARM_DESC(phy_ulpi_ext_vbus,
33067 + "ULPI PHY using internal or external vbus 0=Internal");
33068 +module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444);
33069 +MODULE_PARM_DESC(i2c_enable, "FS PHY Interface");
33070 +module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444);
33071 +MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only");
33072 +module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444);
33073 +MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs");
33074 +module_param_named(debug, g_dbg_lvl, int, 0444);
33075 +MODULE_PARM_DESC(debug, "");
33076 +
33077 +module_param_named(en_multiple_tx_fifo,
33078 + dwc_otg_module_params.en_multiple_tx_fifo, int, 0444);
33079 +MODULE_PARM_DESC(en_multiple_tx_fifo,
33080 + "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled");
33081 +module_param_named(dev_tx_fifo_size_1,
33082 + dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444);
33083 +MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768");
33084 +module_param_named(dev_tx_fifo_size_2,
33085 + dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444);
33086 +MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768");
33087 +module_param_named(dev_tx_fifo_size_3,
33088 + dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444);
33089 +MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768");
33090 +module_param_named(dev_tx_fifo_size_4,
33091 + dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444);
33092 +MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768");
33093 +module_param_named(dev_tx_fifo_size_5,
33094 + dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444);
33095 +MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768");
33096 +module_param_named(dev_tx_fifo_size_6,
33097 + dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444);
33098 +MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768");
33099 +module_param_named(dev_tx_fifo_size_7,
33100 + dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444);
33101 +MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768");
33102 +module_param_named(dev_tx_fifo_size_8,
33103 + dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444);
33104 +MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768");
33105 +module_param_named(dev_tx_fifo_size_9,
33106 + dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444);
33107 +MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768");
33108 +module_param_named(dev_tx_fifo_size_10,
33109 + dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444);
33110 +MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768");
33111 +module_param_named(dev_tx_fifo_size_11,
33112 + dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444);
33113 +MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768");
33114 +module_param_named(dev_tx_fifo_size_12,
33115 + dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444);
33116 +MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768");
33117 +module_param_named(dev_tx_fifo_size_13,
33118 + dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444);
33119 +MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768");
33120 +module_param_named(dev_tx_fifo_size_14,
33121 + dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444);
33122 +MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768");
33123 +module_param_named(dev_tx_fifo_size_15,
33124 + dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444);
33125 +MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768");
33126 +
33127 +module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444);
33128 +MODULE_PARM_DESC(thr_ctl,
33129 + "Thresholding enable flag bit 0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled");
33130 +module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int,
33131 + 0444);
33132 +MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs");
33133 +module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int,
33134 + 0444);
33135 +MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs");
33136 +
33137 +module_param_named(pti_enable, dwc_otg_module_params.pti_enable, int, 0444);
33138 +module_param_named(mpi_enable, dwc_otg_module_params.mpi_enable, int, 0444);
33139 +module_param_named(lpm_enable, dwc_otg_module_params.lpm_enable, int, 0444);
33140 +MODULE_PARM_DESC(lpm_enable, "LPM Enable 0=LPM Disabled 1=LPM Enabled");
33141 +module_param_named(ic_usb_cap, dwc_otg_module_params.ic_usb_cap, int, 0444);
33142 +MODULE_PARM_DESC(ic_usb_cap,
33143 + "IC_USB Capability 0=IC_USB Disabled 1=IC_USB Enabled");
33144 +module_param_named(ahb_thr_ratio, dwc_otg_module_params.ahb_thr_ratio, int,
33145 + 0444);
33146 +MODULE_PARM_DESC(ahb_thr_ratio, "AHB Threshold Ratio");
33147 +module_param_named(power_down, dwc_otg_module_params.power_down, int, 0444);
33148 +MODULE_PARM_DESC(power_down, "Power Down Mode");
33149 +module_param_named(reload_ctl, dwc_otg_module_params.reload_ctl, int, 0444);
33150 +MODULE_PARM_DESC(reload_ctl, "HFIR Reload Control");
33151 +module_param_named(dev_out_nak, dwc_otg_module_params.dev_out_nak, int, 0444);
33152 +MODULE_PARM_DESC(dev_out_nak, "Enable Device OUT NAK");
33153 +module_param_named(cont_on_bna, dwc_otg_module_params.cont_on_bna, int, 0444);
33154 +MODULE_PARM_DESC(cont_on_bna, "Enable Enable Continue on BNA");
33155 +module_param_named(ahb_single, dwc_otg_module_params.ahb_single, int, 0444);
33156 +MODULE_PARM_DESC(ahb_single, "Enable AHB Single Support");
33157 +module_param_named(adp_enable, dwc_otg_module_params.adp_enable, int, 0444);
33158 +MODULE_PARM_DESC(adp_enable, "ADP Enable 0=ADP Disabled 1=ADP Enabled");
33159 +module_param_named(otg_ver, dwc_otg_module_params.otg_ver, int, 0444);
33160 +MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0");
33161 +module_param(microframe_schedule, bool, 0444);
33162 +MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler");
33163 +
33164 +module_param(fiq_fix_enable, bool, 0444);
33165 +MODULE_PARM_DESC(fiq_fix_enable, "Enable the fiq fix");
33166 +module_param(nak_holdoff_enable, bool, 0444);
33167 +MODULE_PARM_DESC(nak_holdoff_enable, "Enable the NAK holdoff");
33168 +
33169 +/** @page "Module Parameters"
33170 + *
33171 + * The following parameters may be specified when starting the module.
33172 + * These parameters define how the DWC_otg controller should be
33173 + * configured. Parameter values are passed to the CIL initialization
33174 + * function dwc_otg_cil_init
33175 + *
33176 + * Example: <code>modprobe dwc_otg speed=1 otg_cap=1</code>
33177 + *
33178 +
33179 + <table>
33180 + <tr><td>Parameter Name</td><td>Meaning</td></tr>
33181 +
33182 + <tr>
33183 + <td>otg_cap</td>
33184 + <td>Specifies the OTG capabilities. The driver will automatically detect the
33185 + value for this parameter if none is specified.
33186 + - 0: HNP and SRP capable (default, if available)
33187 + - 1: SRP Only capable
33188 + - 2: No HNP/SRP capable
33189 + </td></tr>
33190 +
33191 + <tr>
33192 + <td>dma_enable</td>
33193 + <td>Specifies whether to use slave or DMA mode for accessing the data FIFOs.
33194 + The driver will automatically detect the value for this parameter if none is
33195 + specified.
33196 + - 0: Slave
33197 + - 1: DMA (default, if available)
33198 + </td></tr>
33199 +
33200 + <tr>
33201 + <td>dma_burst_size</td>
33202 + <td>The DMA Burst size (applicable only for External DMA Mode).
33203 + - Values: 1, 4, 8 16, 32, 64, 128, 256 (default 32)
33204 + </td></tr>
33205 +
33206 + <tr>
33207 + <td>speed</td>
33208 + <td>Specifies the maximum speed of operation in host and device mode. The
33209 + actual speed depends on the speed of the attached device and the value of
33210 + phy_type.
33211 + - 0: High Speed (default)
33212 + - 1: Full Speed
33213 + </td></tr>
33214 +
33215 + <tr>
33216 + <td>host_support_fs_ls_low_power</td>
33217 + <td>Specifies whether low power mode is supported when attached to a Full
33218 + Speed or Low Speed device in host mode.
33219 + - 0: Don't support low power mode (default)
33220 + - 1: Support low power mode
33221 + </td></tr>
33222 +
33223 + <tr>
33224 + <td>host_ls_low_power_phy_clk</td>
33225 + <td>Specifies the PHY clock rate in low power mode when connected to a Low
33226 + Speed device in host mode. This parameter is applicable only if
33227 + HOST_SUPPORT_FS_LS_LOW_POWER is enabled.
33228 + - 0: 48 MHz (default)
33229 + - 1: 6 MHz
33230 + </td></tr>
33231 +
33232 + <tr>
33233 + <td>enable_dynamic_fifo</td>
33234 + <td> Specifies whether FIFOs may be resized by the driver software.
33235 + - 0: Use cC FIFO size parameters
33236 + - 1: Allow dynamic FIFO sizing (default)
33237 + </td></tr>
33238 +
33239 + <tr>
33240 + <td>data_fifo_size</td>
33241 + <td>Total number of 4-byte words in the data FIFO memory. This memory
33242 + includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs.
33243 + - Values: 32 to 32768 (default 8192)
33244 +
33245 + Note: The total FIFO memory depth in the FPGA configuration is 8192.
33246 + </td></tr>
33247 +
33248 + <tr>
33249 + <td>dev_rx_fifo_size</td>
33250 + <td>Number of 4-byte words in the Rx FIFO in device mode when dynamic
33251 + FIFO sizing is enabled.
33252 + - Values: 16 to 32768 (default 1064)
33253 + </td></tr>
33254 +
33255 + <tr>
33256 + <td>dev_nperio_tx_fifo_size</td>
33257 + <td>Number of 4-byte words in the non-periodic Tx FIFO in device mode when
33258 + dynamic FIFO sizing is enabled.
33259 + - Values: 16 to 32768 (default 1024)
33260 + </td></tr>
33261 +
33262 + <tr>
33263 + <td>dev_perio_tx_fifo_size_n (n = 1 to 15)</td>
33264 + <td>Number of 4-byte words in each of the periodic Tx FIFOs in device mode
33265 + when dynamic FIFO sizing is enabled.
33266 + - Values: 4 to 768 (default 256)
33267 + </td></tr>
33268 +
33269 + <tr>
33270 + <td>host_rx_fifo_size</td>
33271 + <td>Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO
33272 + sizing is enabled.
33273 + - Values: 16 to 32768 (default 1024)
33274 + </td></tr>
33275 +
33276 + <tr>
33277 + <td>host_nperio_tx_fifo_size</td>
33278 + <td>Number of 4-byte words in the non-periodic Tx FIFO in host mode when
33279 + dynamic FIFO sizing is enabled in the core.
33280 + - Values: 16 to 32768 (default 1024)
33281 + </td></tr>
33282 +
33283 + <tr>
33284 + <td>host_perio_tx_fifo_size</td>
33285 + <td>Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO
33286 + sizing is enabled.
33287 + - Values: 16 to 32768 (default 1024)
33288 + </td></tr>
33289 +
33290 + <tr>
33291 + <td>max_transfer_size</td>
33292 + <td>The maximum transfer size supported in bytes.
33293 + - Values: 2047 to 65,535 (default 65,535)
33294 + </td></tr>
33295 +
33296 + <tr>
33297 + <td>max_packet_count</td>
33298 + <td>The maximum number of packets in a transfer.
33299 + - Values: 15 to 511 (default 511)
33300 + </td></tr>
33301 +
33302 + <tr>
33303 + <td>host_channels</td>
33304 + <td>The number of host channel registers to use.
33305 + - Values: 1 to 16 (default 12)
33306 +
33307 + Note: The FPGA configuration supports a maximum of 12 host channels.
33308 + </td></tr>
33309 +
33310 + <tr>
33311 + <td>dev_endpoints</td>
33312 + <td>The number of endpoints in addition to EP0 available for device mode
33313 + operations.
33314 + - Values: 1 to 15 (default 6 IN and OUT)
33315 +
33316 + Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in
33317 + addition to EP0.
33318 + </td></tr>
33319 +
33320 + <tr>
33321 + <td>phy_type</td>
33322 + <td>Specifies the type of PHY interface to use. By default, the driver will
33323 + automatically detect the phy_type.
33324 + - 0: Full Speed
33325 + - 1: UTMI+ (default, if available)
33326 + - 2: ULPI
33327 + </td></tr>
33328 +
33329 + <tr>
33330 + <td>phy_utmi_width</td>
33331 + <td>Specifies the UTMI+ Data Width. This parameter is applicable for a
33332 + phy_type of UTMI+. Also, this parameter is applicable only if the
33333 + OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the
33334 + core has been configured to work at either data path width.
33335 + - Values: 8 or 16 bits (default 16)
33336 + </td></tr>
33337 +
33338 + <tr>
33339 + <td>phy_ulpi_ddr</td>
33340 + <td>Specifies whether the ULPI operates at double or single data rate. This
33341 + parameter is only applicable if phy_type is ULPI.
33342 + - 0: single data rate ULPI interface with 8 bit wide data bus (default)
33343 + - 1: double data rate ULPI interface with 4 bit wide data bus
33344 + </td></tr>
33345 +
33346 + <tr>
33347 + <td>i2c_enable</td>
33348 + <td>Specifies whether to use the I2C interface for full speed PHY. This
33349 + parameter is only applicable if PHY_TYPE is FS.
33350 + - 0: Disabled (default)
33351 + - 1: Enabled
33352 + </td></tr>
33353 +
33354 + <tr>
33355 + <td>ulpi_fs_ls</td>
33356 + <td>Specifies whether to use ULPI FS/LS mode only.
33357 + - 0: Disabled (default)
33358 + - 1: Enabled
33359 + </td></tr>
33360 +
33361 + <tr>
33362 + <td>ts_dline</td>
33363 + <td>Specifies whether term select D-Line pulsing for all PHYs is enabled.
33364 + - 0: Disabled (default)
33365 + - 1: Enabled
33366 + </td></tr>
33367 +
33368 + <tr>
33369 + <td>en_multiple_tx_fifo</td>
33370 + <td>Specifies whether dedicatedto tx fifos are enabled for non periodic IN EPs.
33371 + The driver will automatically detect the value for this parameter if none is
33372 + specified.
33373 + - 0: Disabled
33374 + - 1: Enabled (default, if available)
33375 + </td></tr>
33376 +
33377 + <tr>
33378 + <td>dev_tx_fifo_size_n (n = 1 to 15)</td>
33379 + <td>Number of 4-byte words in each of the Tx FIFOs in device mode
33380 + when dynamic FIFO sizing is enabled.
33381 + - Values: 4 to 768 (default 256)
33382 + </td></tr>
33383 +
33384 + <tr>
33385 + <td>tx_thr_length</td>
33386 + <td>Transmit Threshold length in 32 bit double words
33387 + - Values: 8 to 128 (default 64)
33388 + </td></tr>
33389 +
33390 + <tr>
33391 + <td>rx_thr_length</td>
33392 + <td>Receive Threshold length in 32 bit double words
33393 + - Values: 8 to 128 (default 64)
33394 + </td></tr>
33395 +
33396 +<tr>
33397 + <td>thr_ctl</td>
33398 + <td>Specifies whether to enable Thresholding for Device mode. Bits 0, 1, 2 of
33399 + this parmater specifies if thresholding is enabled for non-Iso Tx, Iso Tx and
33400 + Rx transfers accordingly.
33401 + The driver will automatically detect the value for this parameter if none is
33402 + specified.
33403 + - Values: 0 to 7 (default 0)
33404 + Bit values indicate:
33405 + - 0: Thresholding disabled
33406 + - 1: Thresholding enabled
33407 + </td></tr>
33408 +
33409 +<tr>
33410 + <td>dma_desc_enable</td>
33411 + <td>Specifies whether to enable Descriptor DMA mode.
33412 + The driver will automatically detect the value for this parameter if none is
33413 + specified.
33414 + - 0: Descriptor DMA disabled
33415 + - 1: Descriptor DMA (default, if available)
33416 + </td></tr>
33417 +
33418 +<tr>
33419 + <td>mpi_enable</td>
33420 + <td>Specifies whether to enable MPI enhancement mode.
33421 + The driver will automatically detect the value for this parameter if none is
33422 + specified.
33423 + - 0: MPI disabled (default)
33424 + - 1: MPI enable
33425 + </td></tr>
33426 +
33427 +<tr>
33428 + <td>pti_enable</td>
33429 + <td>Specifies whether to enable PTI enhancement support.
33430 + The driver will automatically detect the value for this parameter if none is
33431 + specified.
33432 + - 0: PTI disabled (default)
33433 + - 1: PTI enable
33434 + </td></tr>
33435 +
33436 +<tr>
33437 + <td>lpm_enable</td>
33438 + <td>Specifies whether to enable LPM support.
33439 + The driver will automatically detect the value for this parameter if none is
33440 + specified.
33441 + - 0: LPM disabled
33442 + - 1: LPM enable (default, if available)
33443 + </td></tr>
33444 +
33445 +<tr>
33446 + <td>ic_usb_cap</td>
33447 + <td>Specifies whether to enable IC_USB capability.
33448 + The driver will automatically detect the value for this parameter if none is
33449 + specified.
33450 + - 0: IC_USB disabled (default, if available)
33451 + - 1: IC_USB enable
33452 + </td></tr>
33453 +
33454 +<tr>
33455 + <td>ahb_thr_ratio</td>
33456 + <td>Specifies AHB Threshold ratio.
33457 + - Values: 0 to 3 (default 0)
33458 + </td></tr>
33459 +
33460 +<tr>
33461 + <td>power_down</td>
33462 + <td>Specifies Power Down(Hibernation) Mode.
33463 + The driver will automatically detect the value for this parameter if none is
33464 + specified.
33465 + - 0: Power Down disabled (default)
33466 + - 2: Power Down enabled
33467 + </td></tr>
33468 +
33469 + <tr>
33470 + <td>reload_ctl</td>
33471 + <td>Specifies whether dynamic reloading of the HFIR register is allowed during
33472 + run time. The driver will automatically detect the value for this parameter if
33473 + none is specified. In case the HFIR value is reloaded when HFIR.RldCtrl == 1'b0
33474 + the core might misbehave.
33475 + - 0: Reload Control disabled (default)
33476 + - 1: Reload Control enabled
33477 + </td></tr>
33478 +
33479 + <tr>
33480 + <td>dev_out_nak</td>
33481 + <td>Specifies whether Device OUT NAK enhancement enabled or no.
33482 + The driver will automatically detect the value for this parameter if
33483 + none is specified. This parameter is valid only when OTG_EN_DESC_DMA == 1b1.
33484 + - 0: The core does not set NAK after Bulk OUT transfer complete (default)
33485 + - 1: The core sets NAK after Bulk OUT transfer complete
33486 + </td></tr>
33487 +
33488 + <tr>
33489 + <td>cont_on_bna</td>
33490 + <td>Specifies whether Enable Continue on BNA enabled or no.
33491 + After receiving BNA interrupt the core disables the endpoint,when the
33492 + endpoint is re-enabled by the application the
33493 + - 0: Core starts processing from the DOEPDMA descriptor (default)
33494 + - 1: Core starts processing from the descriptor which received the BNA.
33495 + This parameter is valid only when OTG_EN_DESC_DMA == 1b1.
33496 + </td></tr>
33497 +
33498 + <tr>
33499 + <td>ahb_single</td>
33500 + <td>This bit when programmed supports SINGLE transfers for remainder data
33501 + in a transfer for DMA mode of operation.
33502 + - 0: The remainder data will be sent using INCR burst size (default)
33503 + - 1: The remainder data will be sent using SINGLE burst size.
33504 + </td></tr>
33505 +
33506 +<tr>
33507 + <td>adp_enable</td>
33508 + <td>Specifies whether ADP feature is enabled.
33509 + The driver will automatically detect the value for this parameter if none is
33510 + specified.
33511 + - 0: ADP feature disabled (default)
33512 + - 1: ADP feature enabled
33513 + </td></tr>
33514 +
33515 + <tr>
33516 + <td>otg_ver</td>
33517 + <td>Specifies whether OTG is performing as USB OTG Revision 2.0 or Revision 1.3
33518 + USB OTG device.
33519 + - 0: OTG 2.0 support disabled (default)
33520 + - 1: OTG 2.0 support enabled
33521 + </td></tr>
33522 +
33523 +*/
33524 --- /dev/null
33525 +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.h
33526 @@ -0,0 +1,86 @@
33527 +/* ==========================================================================
33528 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.h $
33529 + * $Revision: #19 $
33530 + * $Date: 2010/11/15 $
33531 + * $Change: 1627671 $
33532 + *
33533 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
33534 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
33535 + * otherwise expressly agreed to in writing between Synopsys and you.
33536 + *
33537 + * The Software IS NOT an item of Licensed Software or Licensed Product under
33538 + * any End User Software License Agreement or Agreement for Licensed Product
33539 + * with Synopsys or any supplement thereto. You are permitted to use and
33540 + * redistribute this Software in source and binary forms, with or without
33541 + * modification, provided that redistributions of source code must retain this
33542 + * notice. You may not view, use, disclose, copy or distribute this file or
33543 + * any information contained herein except pursuant to this license grant from
33544 + * Synopsys. If you do not agree with this notice, including the disclaimer
33545 + * below, then you are not authorized to use the Software.
33546 + *
33547 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
33548 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33549 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33550 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
33551 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33552 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33553 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33554 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33555 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33556 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33557 + * DAMAGE.
33558 + * ========================================================================== */
33559 +
33560 +#ifndef __DWC_OTG_DRIVER_H__
33561 +#define __DWC_OTG_DRIVER_H__
33562 +
33563 +/** @file
33564 + * This file contains the interface to the Linux driver.
33565 + */
33566 +#include "dwc_otg_os_dep.h"
33567 +#include "dwc_otg_core_if.h"
33568 +
33569 +/* Type declarations */
33570 +struct dwc_otg_pcd;
33571 +struct dwc_otg_hcd;
33572 +
33573 +/**
33574 + * This structure is a wrapper that encapsulates the driver components used to
33575 + * manage a single DWC_otg controller.
33576 + */
33577 +typedef struct dwc_otg_device {
33578 + /** Structure containing OS-dependent stuff. KEEP THIS STRUCT AT THE
33579 + * VERY BEGINNING OF THE DEVICE STRUCT. OSes such as FreeBSD and NetBSD
33580 + * require this. */
33581 + struct os_dependent os_dep;
33582 +
33583 + /** Pointer to the core interface structure. */
33584 + dwc_otg_core_if_t *core_if;
33585 +
33586 + /** Pointer to the PCD structure. */
33587 + struct dwc_otg_pcd *pcd;
33588 +
33589 + /** Pointer to the HCD structure. */
33590 + struct dwc_otg_hcd *hcd;
33591 +
33592 + /** Flag to indicate whether the common IRQ handler is installed. */
33593 + uint8_t common_irq_installed;
33594 +
33595 +} dwc_otg_device_t;
33596 +
33597 +/*We must clear S3C24XX_EINTPEND external interrupt register
33598 + * because after clearing in this register trigerred IRQ from
33599 + * H/W core in kernel interrupt can be occured again before OTG
33600 + * handlers clear all IRQ sources of Core registers because of
33601 + * timing latencies and Low Level IRQ Type.
33602 + */
33603 +#ifdef CONFIG_MACH_IPMATE
33604 +#define S3C2410X_CLEAR_EINTPEND() \
33605 +do { \
33606 + __raw_writel(1UL << 11,S3C24XX_EINTPEND); \
33607 +} while (0)
33608 +#else
33609 +#define S3C2410X_CLEAR_EINTPEND() do { } while (0)
33610 +#endif
33611 +
33612 +#endif
33613 --- /dev/null
33614 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
33615 @@ -0,0 +1,3533 @@
33616 +
33617 +/* ==========================================================================
33618 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $
33619 + * $Revision: #104 $
33620 + * $Date: 2011/10/24 $
33621 + * $Change: 1871159 $
33622 + *
33623 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
33624 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
33625 + * otherwise expressly agreed to in writing between Synopsys and you.
33626 + *
33627 + * The Software IS NOT an item of Licensed Software or Licensed Product under
33628 + * any End User Software License Agreement or Agreement for Licensed Product
33629 + * with Synopsys or any supplement thereto. You are permitted to use and
33630 + * redistribute this Software in source and binary forms, with or without
33631 + * modification, provided that redistributions of source code must retain this
33632 + * notice. You may not view, use, disclose, copy or distribute this file or
33633 + * any information contained herein except pursuant to this license grant from
33634 + * Synopsys. If you do not agree with this notice, including the disclaimer
33635 + * below, then you are not authorized to use the Software.
33636 + *
33637 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
33638 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33639 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33640 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
33641 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33642 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33643 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33644 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33645 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33646 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33647 + * DAMAGE.
33648 + * ========================================================================== */
33649 +#ifndef DWC_DEVICE_ONLY
33650 +
33651 +/** @file
33652 + * This file implements HCD Core. All code in this file is portable and doesn't
33653 + * use any OS specific functions.
33654 + * Interface provided by HCD Core is defined in <code><hcd_if.h></code>
33655 + * header file.
33656 + */
33657 +
33658 +#include <linux/usb.h>
33659 +#include <linux/usb/hcd.h>
33660 +
33661 +#include "dwc_otg_hcd.h"
33662 +#include "dwc_otg_regs.h"
33663 +
33664 +extern bool microframe_schedule, nak_holdoff_enable;
33665 +
33666 +//#define DEBUG_HOST_CHANNELS
33667 +#ifdef DEBUG_HOST_CHANNELS
33668 +static int last_sel_trans_num_per_scheduled = 0;
33669 +static int last_sel_trans_num_nonper_scheduled = 0;
33670 +static int last_sel_trans_num_avail_hc_at_start = 0;
33671 +static int last_sel_trans_num_avail_hc_at_end = 0;
33672 +#endif /* DEBUG_HOST_CHANNELS */
33673 +
33674 +extern int g_next_sched_frame, g_np_count, g_np_sent;
33675 +
33676 +dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
33677 +{
33678 + return DWC_ALLOC(sizeof(dwc_otg_hcd_t));
33679 +}
33680 +
33681 +/**
33682 + * Connection timeout function. An OTG host is required to display a
33683 + * message if the device does not connect within 10 seconds.
33684 + */
33685 +void dwc_otg_hcd_connect_timeout(void *ptr)
33686 +{
33687 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, ptr);
33688 + DWC_PRINTF("Connect Timeout\n");
33689 + __DWC_ERROR("Device Not Connected/Responding\n");
33690 +}
33691 +
33692 +#if defined(DEBUG)
33693 +static void dump_channel_info(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
33694 +{
33695 + if (qh->channel != NULL) {
33696 + dwc_hc_t *hc = qh->channel;
33697 + dwc_list_link_t *item;
33698 + dwc_otg_qh_t *qh_item;
33699 + int num_channels = hcd->core_if->core_params->host_channels;
33700 + int i;
33701 +
33702 + dwc_otg_hc_regs_t *hc_regs;
33703 + hcchar_data_t hcchar;
33704 + hcsplt_data_t hcsplt;
33705 + hctsiz_data_t hctsiz;
33706 + uint32_t hcdma;
33707 +
33708 + hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
33709 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
33710 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
33711 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
33712 + hcdma = DWC_READ_REG32(&hc_regs->hcdma);
33713 +
33714 + DWC_PRINTF(" Assigned to channel %p:\n", hc);
33715 + DWC_PRINTF(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32,
33716 + hcsplt.d32);
33717 + DWC_PRINTF(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32,
33718 + hcdma);
33719 + DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
33720 + hc->dev_addr, hc->ep_num, hc->ep_is_in);
33721 + DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
33722 + DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
33723 + DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
33724 + DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
33725 + DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
33726 + DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
33727 + DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
33728 + DWC_PRINTF(" qh: %p\n", hc->qh);
33729 + DWC_PRINTF(" NP inactive sched:\n");
33730 + DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_inactive) {
33731 + qh_item =
33732 + DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
33733 + DWC_PRINTF(" %p\n", qh_item);
33734 + }
33735 + DWC_PRINTF(" NP active sched:\n");
33736 + DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_active) {
33737 + qh_item =
33738 + DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
33739 + DWC_PRINTF(" %p\n", qh_item);
33740 + }
33741 + DWC_PRINTF(" Channels: \n");
33742 + for (i = 0; i < num_channels; i++) {
33743 + dwc_hc_t *hc = hcd->hc_ptr_array[i];
33744 + DWC_PRINTF(" %2d: %p\n", i, hc);
33745 + }
33746 + }
33747 +}
33748 +#else
33749 +#define dump_channel_info(hcd, qh)
33750 +#endif /* DEBUG */
33751 +
33752 +/**
33753 + * Work queue function for starting the HCD when A-Cable is connected.
33754 + * The hcd_start() must be called in a process context.
33755 + */
33756 +static void hcd_start_func(void *_vp)
33757 +{
33758 + dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) _vp;
33759 +
33760 + DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, hcd);
33761 + if (hcd) {
33762 + hcd->fops->start(hcd);
33763 + }
33764 +}
33765 +
33766 +static void del_xfer_timers(dwc_otg_hcd_t * hcd)
33767 +{
33768 +#ifdef DEBUG
33769 + int i;
33770 + int num_channels = hcd->core_if->core_params->host_channels;
33771 + for (i = 0; i < num_channels; i++) {
33772 + DWC_TIMER_CANCEL(hcd->core_if->hc_xfer_timer[i]);
33773 + }
33774 +#endif
33775 +}
33776 +
33777 +static void del_timers(dwc_otg_hcd_t * hcd)
33778 +{
33779 + del_xfer_timers(hcd);
33780 + DWC_TIMER_CANCEL(hcd->conn_timer);
33781 +}
33782 +
33783 +/**
33784 + * Processes all the URBs in a single list of QHs. Completes them with
33785 + * -ETIMEDOUT and frees the QTD.
33786 + */
33787 +static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
33788 +{
33789 + dwc_list_link_t *qh_item;
33790 + dwc_otg_qh_t *qh;
33791 + dwc_otg_qtd_t *qtd, *qtd_tmp;
33792 +
33793 + DWC_LIST_FOREACH(qh_item, qh_list) {
33794 + qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
33795 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
33796 + &qh->qtd_list, qtd_list_entry) {
33797 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
33798 + if (qtd->urb != NULL) {
33799 + hcd->fops->complete(hcd, qtd->urb->priv,
33800 + qtd->urb, -DWC_E_TIMEOUT);
33801 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
33802 + }
33803 +
33804 + }
33805 + }
33806 +}
33807 +
33808 +/**
33809 + * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic
33810 + * and periodic schedules. The QTD associated with each URB is removed from
33811 + * the schedule and freed. This function may be called when a disconnect is
33812 + * detected or when the HCD is being stopped.
33813 + */
33814 +static void kill_all_urbs(dwc_otg_hcd_t * hcd)
33815 +{
33816 + kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive);
33817 + kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active);
33818 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive);
33819 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready);
33820 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned);
33821 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued);
33822 +}
33823 +
33824 +/**
33825 + * Start the connection timer. An OTG host is required to display a
33826 + * message if the device does not connect within 10 seconds. The
33827 + * timer is deleted if a port connect interrupt occurs before the
33828 + * timer expires.
33829 + */
33830 +static void dwc_otg_hcd_start_connect_timer(dwc_otg_hcd_t * hcd)
33831 +{
33832 + DWC_TIMER_SCHEDULE(hcd->conn_timer, 10000 /* 10 secs */ );
33833 +}
33834 +
33835 +/**
33836 + * HCD Callback function for disconnect of the HCD.
33837 + *
33838 + * @param p void pointer to the <code>struct usb_hcd</code>
33839 + */
33840 +static int32_t dwc_otg_hcd_session_start_cb(void *p)
33841 +{
33842 + dwc_otg_hcd_t *dwc_otg_hcd;
33843 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
33844 + dwc_otg_hcd = p;
33845 + dwc_otg_hcd_start_connect_timer(dwc_otg_hcd);
33846 + return 1;
33847 +}
33848 +
33849 +/**
33850 + * HCD Callback function for starting the HCD when A-Cable is
33851 + * connected.
33852 + *
33853 + * @param p void pointer to the <code>struct usb_hcd</code>
33854 + */
33855 +static int32_t dwc_otg_hcd_start_cb(void *p)
33856 +{
33857 + dwc_otg_hcd_t *dwc_otg_hcd = p;
33858 + dwc_otg_core_if_t *core_if;
33859 + hprt0_data_t hprt0;
33860 +
33861 + core_if = dwc_otg_hcd->core_if;
33862 +
33863 + if (core_if->op_state == B_HOST) {
33864 + /*
33865 + * Reset the port. During a HNP mode switch the reset
33866 + * needs to occur within 1ms and have a duration of at
33867 + * least 50ms.
33868 + */
33869 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
33870 + hprt0.b.prtrst = 1;
33871 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
33872 + }
33873 + DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg,
33874 + hcd_start_func, dwc_otg_hcd, 50,
33875 + "start hcd");
33876 +
33877 + return 1;
33878 +}
33879 +
33880 +/**
33881 + * HCD Callback function for disconnect of the HCD.
33882 + *
33883 + * @param p void pointer to the <code>struct usb_hcd</code>
33884 + */
33885 +static int32_t dwc_otg_hcd_disconnect_cb(void *p)
33886 +{
33887 + gintsts_data_t intr;
33888 + dwc_otg_hcd_t *dwc_otg_hcd = p;
33889 +
33890 + /*
33891 + * Set status flags for the hub driver.
33892 + */
33893 + dwc_otg_hcd->flags.b.port_connect_status_change = 1;
33894 + dwc_otg_hcd->flags.b.port_connect_status = 0;
33895 +
33896 + /*
33897 + * Shutdown any transfers in process by clearing the Tx FIFO Empty
33898 + * interrupt mask and status bits and disabling subsequent host
33899 + * channel interrupts.
33900 + */
33901 + intr.d32 = 0;
33902 + intr.b.nptxfempty = 1;
33903 + intr.b.ptxfempty = 1;
33904 + intr.b.hcintr = 1;
33905 + DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk,
33906 + intr.d32, 0);
33907 + DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintsts,
33908 + intr.d32, 0);
33909 +
33910 + del_timers(dwc_otg_hcd);
33911 +
33912 + /*
33913 + * Turn off the vbus power only if the core has transitioned to device
33914 + * mode. If still in host mode, need to keep power on to detect a
33915 + * reconnection.
33916 + */
33917 + if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) {
33918 + if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) {
33919 + hprt0_data_t hprt0 = {.d32 = 0 };
33920 + DWC_PRINTF("Disconnect: PortPower off\n");
33921 + hprt0.b.prtpwr = 0;
33922 + DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0,
33923 + hprt0.d32);
33924 + }
33925 +
33926 + dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);
33927 + }
33928 +
33929 + /* Respond with an error status to all URBs in the schedule. */
33930 + kill_all_urbs(dwc_otg_hcd);
33931 +
33932 + if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
33933 + /* Clean up any host channels that were in use. */
33934 + int num_channels;
33935 + int i;
33936 + dwc_hc_t *channel;
33937 + dwc_otg_hc_regs_t *hc_regs;
33938 + hcchar_data_t hcchar;
33939 +
33940 + num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
33941 +
33942 + if (!dwc_otg_hcd->core_if->dma_enable) {
33943 + /* Flush out any channel requests in slave mode. */
33944 + for (i = 0; i < num_channels; i++) {
33945 + channel = dwc_otg_hcd->hc_ptr_array[i];
33946 + if (DWC_CIRCLEQ_EMPTY_ENTRY
33947 + (channel, hc_list_entry)) {
33948 + hc_regs =
33949 + dwc_otg_hcd->core_if->
33950 + host_if->hc_regs[i];
33951 + hcchar.d32 =
33952 + DWC_READ_REG32(&hc_regs->hcchar);
33953 + if (hcchar.b.chen) {
33954 + hcchar.b.chen = 0;
33955 + hcchar.b.chdis = 1;
33956 + hcchar.b.epdir = 0;
33957 + DWC_WRITE_REG32
33958 + (&hc_regs->hcchar,
33959 + hcchar.d32);
33960 + }
33961 + }
33962 + }
33963 + }
33964 +
33965 + for (i = 0; i < num_channels; i++) {
33966 + channel = dwc_otg_hcd->hc_ptr_array[i];
33967 + if (DWC_CIRCLEQ_EMPTY_ENTRY(channel, hc_list_entry)) {
33968 + hc_regs =
33969 + dwc_otg_hcd->core_if->host_if->hc_regs[i];
33970 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
33971 + if (hcchar.b.chen) {
33972 + /* Halt the channel. */
33973 + hcchar.b.chdis = 1;
33974 + DWC_WRITE_REG32(&hc_regs->hcchar,
33975 + hcchar.d32);
33976 + }
33977 +
33978 + dwc_otg_hc_cleanup(dwc_otg_hcd->core_if,
33979 + channel);
33980 + DWC_CIRCLEQ_INSERT_TAIL
33981 + (&dwc_otg_hcd->free_hc_list, channel,
33982 + hc_list_entry);
33983 + /*
33984 + * Added for Descriptor DMA to prevent channel double cleanup
33985 + * in release_channel_ddma(). Which called from ep_disable
33986 + * when device disconnect.
33987 + */
33988 + channel->qh = NULL;
33989 + }
33990 + }
33991 + }
33992 +
33993 + if (dwc_otg_hcd->fops->disconnect) {
33994 + dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
33995 + }
33996 +
33997 + return 1;
33998 +}
33999 +
34000 +/**
34001 + * HCD Callback function for stopping the HCD.
34002 + *
34003 + * @param p void pointer to the <code>struct usb_hcd</code>
34004 + */
34005 +static int32_t dwc_otg_hcd_stop_cb(void *p)
34006 +{
34007 + dwc_otg_hcd_t *dwc_otg_hcd = p;
34008 +
34009 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
34010 + dwc_otg_hcd_stop(dwc_otg_hcd);
34011 + return 1;
34012 +}
34013 +
34014 +#ifdef CONFIG_USB_DWC_OTG_LPM
34015 +/**
34016 + * HCD Callback function for sleep of HCD.
34017 + *
34018 + * @param p void pointer to the <code>struct usb_hcd</code>
34019 + */
34020 +static int dwc_otg_hcd_sleep_cb(void *p)
34021 +{
34022 + dwc_otg_hcd_t *hcd = p;
34023 +
34024 + dwc_otg_hcd_free_hc_from_lpm(hcd);
34025 +
34026 + return 0;
34027 +}
34028 +#endif
34029 +
34030 +
34031 +/**
34032 + * HCD Callback function for Remote Wakeup.
34033 + *
34034 + * @param p void pointer to the <code>struct usb_hcd</code>
34035 + */
34036 +static int dwc_otg_hcd_rem_wakeup_cb(void *p)
34037 +{
34038 + dwc_otg_hcd_t *hcd = p;
34039 +
34040 + if (hcd->core_if->lx_state == DWC_OTG_L2) {
34041 + hcd->flags.b.port_suspend_change = 1;
34042 + }
34043 +#ifdef CONFIG_USB_DWC_OTG_LPM
34044 + else {
34045 + hcd->flags.b.port_l1_change = 1;
34046 + }
34047 +#endif
34048 + return 0;
34049 +}
34050 +
34051 +/**
34052 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
34053 + * stopped.
34054 + */
34055 +void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd)
34056 +{
34057 + hprt0_data_t hprt0 = {.d32 = 0 };
34058 +
34059 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
34060 +
34061 + /*
34062 + * The root hub should be disconnected before this function is called.
34063 + * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
34064 + * and the QH lists (via ..._hcd_endpoint_disable).
34065 + */
34066 +
34067 + /* Turn off all host-specific interrupts. */
34068 + dwc_otg_disable_host_interrupts(hcd->core_if);
34069 +
34070 + /* Turn off the vbus power */
34071 + DWC_PRINTF("PortPower off\n");
34072 + hprt0.b.prtpwr = 0;
34073 + DWC_WRITE_REG32(hcd->core_if->host_if->hprt0, hprt0.d32);
34074 + dwc_mdelay(1);
34075 +}
34076 +
34077 +int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
34078 + dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
34079 + int atomic_alloc)
34080 +{
34081 + dwc_irqflags_t flags;
34082 + int retval = 0;
34083 + uint8_t needs_scheduling = 0;
34084 + dwc_otg_transaction_type_e tr_type;
34085 + dwc_otg_qtd_t *qtd;
34086 + gintmsk_data_t intr_mask = {.d32 = 0 };
34087 +
34088 +#ifdef DEBUG /* integrity checks (Broadcom) */
34089 + if (NULL == hcd->core_if) {
34090 + DWC_ERROR("**** DWC OTG HCD URB Enqueue - HCD has NULL core_if\n");
34091 + /* No longer connected. */
34092 + return -DWC_E_INVALID;
34093 + }
34094 +#endif
34095 + if (!hcd->flags.b.port_connect_status) {
34096 + /* No longer connected. */
34097 + DWC_ERROR("Not connected\n");
34098 + return -DWC_E_NO_DEVICE;
34099 + }
34100 +
34101 + qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc);
34102 + if (qtd == NULL) {
34103 + DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
34104 + return -DWC_E_NO_MEMORY;
34105 + }
34106 +#ifdef DEBUG /* integrity checks (Broadcom) */
34107 + if (qtd->urb == NULL) {
34108 + DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD with no URBs\n");
34109 + return -DWC_E_NO_MEMORY;
34110 + }
34111 + if (qtd->urb->priv == NULL) {
34112 + DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD URB with no URB handle\n");
34113 + return -DWC_E_NO_MEMORY;
34114 + }
34115 +#endif
34116 + intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
34117 + if(!intr_mask.b.sofintr) needs_scheduling = 1;
34118 + if((((dwc_otg_qh_t *)ep_handle)->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP))
34119 + /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
34120 + needs_scheduling = 0;
34121 +
34122 + retval = dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
34123 + // creates a new queue in ep_handle if it doesn't exist already
34124 + if (retval < 0) {
34125 + DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
34126 + "Error status %d\n", retval);
34127 + dwc_otg_hcd_qtd_free(qtd);
34128 + return retval;
34129 + }
34130 +
34131 + if(needs_scheduling) {
34132 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34133 + tr_type = dwc_otg_hcd_select_transactions(hcd);
34134 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
34135 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
34136 + }
34137 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34138 + }
34139 + return retval;
34140 +}
34141 +
34142 +int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
34143 + dwc_otg_hcd_urb_t * dwc_otg_urb)
34144 +{
34145 + dwc_otg_qh_t *qh;
34146 + dwc_otg_qtd_t *urb_qtd;
34147 + BUG_ON(!hcd);
34148 + BUG_ON(!dwc_otg_urb);
34149 +
34150 +#ifdef DEBUG /* integrity checks (Broadcom) */
34151 +
34152 + if (hcd == NULL) {
34153 + DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL HCD\n");
34154 + return -DWC_E_INVALID;
34155 + }
34156 + if (dwc_otg_urb == NULL) {
34157 + DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL URB\n");
34158 + return -DWC_E_INVALID;
34159 + }
34160 + if (dwc_otg_urb->qtd == NULL) {
34161 + DWC_ERROR("**** DWC OTG HCD URB Dequeue with NULL QTD\n");
34162 + return -DWC_E_INVALID;
34163 + }
34164 + urb_qtd = dwc_otg_urb->qtd;
34165 + BUG_ON(!urb_qtd);
34166 + if (urb_qtd->qh == NULL) {
34167 + DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n");
34168 + return -DWC_E_INVALID;
34169 + }
34170 +#else
34171 + urb_qtd = dwc_otg_urb->qtd;
34172 + BUG_ON(!urb_qtd);
34173 +#endif
34174 + qh = urb_qtd->qh;
34175 + BUG_ON(!qh);
34176 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
34177 + if (urb_qtd->in_process) {
34178 + dump_channel_info(hcd, qh);
34179 + }
34180 + }
34181 +#ifdef DEBUG /* integrity checks (Broadcom) */
34182 + if (hcd->core_if == NULL) {
34183 + DWC_ERROR("**** DWC OTG HCD URB Dequeue HCD has NULL core_if\n");
34184 + return -DWC_E_INVALID;
34185 + }
34186 +#endif
34187 + if (urb_qtd->in_process && qh->channel) {
34188 + /* The QTD is in process (it has been assigned to a channel). */
34189 + if (hcd->flags.b.port_connect_status) {
34190 + /*
34191 + * If still connected (i.e. in host mode), halt the
34192 + * channel so it can be used for other transfers. If
34193 + * no longer connected, the host registers can't be
34194 + * written to halt the channel since the core is in
34195 + * device mode.
34196 + */
34197 + dwc_otg_hc_halt(hcd->core_if, qh->channel,
34198 + DWC_OTG_HC_XFER_URB_DEQUEUE);
34199 + }
34200 + }
34201 +
34202 + /*
34203 + * Free the QTD and clean up the associated QH. Leave the QH in the
34204 + * schedule if it has any remaining QTDs.
34205 + */
34206 +
34207 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue - "
34208 + "delete %sQueue handler\n",
34209 + hcd->core_if->dma_desc_enable?"DMA ":"");
34210 + if (!hcd->core_if->dma_desc_enable) {
34211 + uint8_t b = urb_qtd->in_process;
34212 + dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
34213 + if (b) {
34214 + dwc_otg_hcd_qh_deactivate(hcd, qh, 0);
34215 + qh->channel = NULL;
34216 + } else if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
34217 + dwc_otg_hcd_qh_remove(hcd, qh);
34218 + }
34219 + } else {
34220 + dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
34221 + }
34222 + return 0;
34223 +}
34224 +
34225 +int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
34226 + int retry)
34227 +{
34228 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
34229 + int retval = 0;
34230 + dwc_irqflags_t flags;
34231 +
34232 + if (retry < 0) {
34233 + retval = -DWC_E_INVALID;
34234 + goto done;
34235 + }
34236 +
34237 + if (!qh) {
34238 + retval = -DWC_E_INVALID;
34239 + goto done;
34240 + }
34241 +
34242 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34243 +
34244 + while (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list) && retry) {
34245 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34246 + retry--;
34247 + dwc_msleep(5);
34248 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34249 + }
34250 +
34251 + dwc_otg_hcd_qh_remove(hcd, qh);
34252 +
34253 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34254 + /*
34255 + * Split dwc_otg_hcd_qh_remove_and_free() into qh_remove
34256 + * and qh_free to prevent stack dump on DWC_DMA_FREE() with
34257 + * irq_disabled (spinlock_irqsave) in dwc_otg_hcd_desc_list_free()
34258 + * and dwc_otg_hcd_frame_list_alloc().
34259 + */
34260 + dwc_otg_hcd_qh_free(hcd, qh);
34261 +
34262 +done:
34263 + return retval;
34264 +}
34265 +
34266 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
34267 +int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle)
34268 +{
34269 + int retval = 0;
34270 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
34271 + if (!qh)
34272 + return -DWC_E_INVALID;
34273 +
34274 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
34275 + return retval;
34276 +}
34277 +#endif
34278 +
34279 +/**
34280 + * HCD Callback structure for handling mode switching.
34281 + */
34282 +static dwc_otg_cil_callbacks_t hcd_cil_callbacks = {
34283 + .start = dwc_otg_hcd_start_cb,
34284 + .stop = dwc_otg_hcd_stop_cb,
34285 + .disconnect = dwc_otg_hcd_disconnect_cb,
34286 + .session_start = dwc_otg_hcd_session_start_cb,
34287 + .resume_wakeup = dwc_otg_hcd_rem_wakeup_cb,
34288 +#ifdef CONFIG_USB_DWC_OTG_LPM
34289 + .sleep = dwc_otg_hcd_sleep_cb,
34290 +#endif
34291 + .p = 0,
34292 +};
34293 +
34294 +/**
34295 + * Reset tasklet function
34296 + */
34297 +static void reset_tasklet_func(void *data)
34298 +{
34299 + dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data;
34300 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
34301 + hprt0_data_t hprt0;
34302 +
34303 + DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
34304 +
34305 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
34306 + hprt0.b.prtrst = 1;
34307 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
34308 + dwc_mdelay(60);
34309 +
34310 + hprt0.b.prtrst = 0;
34311 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
34312 + dwc_otg_hcd->flags.b.port_reset_change = 1;
34313 +}
34314 +
34315 +static void completion_tasklet_func(void *ptr)
34316 +{
34317 + dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) ptr;
34318 + struct urb *urb;
34319 + urb_tq_entry_t *item;
34320 + dwc_irqflags_t flags;
34321 +
34322 + /* This could just be spin_lock_irq */
34323 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34324 + while (!DWC_TAILQ_EMPTY(&hcd->completed_urb_list)) {
34325 + item = DWC_TAILQ_FIRST(&hcd->completed_urb_list);
34326 + urb = item->urb;
34327 + DWC_TAILQ_REMOVE(&hcd->completed_urb_list, item,
34328 + urb_tq_entries);
34329 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34330 + DWC_FREE(item);
34331 +
34332 + usb_hcd_giveback_urb(hcd->priv, urb, urb->status);
34333 +
34334 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34335 + }
34336 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34337 + return;
34338 +}
34339 +
34340 +static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
34341 +{
34342 + dwc_list_link_t *item;
34343 + dwc_otg_qh_t *qh;
34344 + dwc_irqflags_t flags;
34345 +
34346 + if (!qh_list->next) {
34347 + /* The list hasn't been initialized yet. */
34348 + return;
34349 + }
34350 + /*
34351 + * Hold spinlock here. Not needed in that case if bellow
34352 + * function is being called from ISR
34353 + */
34354 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34355 + /* Ensure there are no QTDs or URBs left. */
34356 + kill_urbs_in_qh_list(hcd, qh_list);
34357 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34358 +
34359 + DWC_LIST_FOREACH(item, qh_list) {
34360 + qh = DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
34361 + dwc_otg_hcd_qh_remove_and_free(hcd, qh);
34362 + }
34363 +}
34364 +
34365 +/**
34366 + * Exit from Hibernation if Host did not detect SRP from connected SRP capable
34367 + * Device during SRP time by host power up.
34368 + */
34369 +void dwc_otg_hcd_power_up(void *ptr)
34370 +{
34371 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
34372 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
34373 +
34374 + DWC_PRINTF("%s called\n", __FUNCTION__);
34375 +
34376 + if (!core_if->hibernation_suspend) {
34377 + DWC_PRINTF("Already exited from Hibernation\n");
34378 + return;
34379 + }
34380 +
34381 + /* Switch on the voltage to the core */
34382 + gpwrdn.b.pwrdnswtch = 1;
34383 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34384 + dwc_udelay(10);
34385 +
34386 + /* Reset the core */
34387 + gpwrdn.d32 = 0;
34388 + gpwrdn.b.pwrdnrstn = 1;
34389 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34390 + dwc_udelay(10);
34391 +
34392 + /* Disable power clamps */
34393 + gpwrdn.d32 = 0;
34394 + gpwrdn.b.pwrdnclmp = 1;
34395 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34396 +
34397 + /* Remove reset the core signal */
34398 + gpwrdn.d32 = 0;
34399 + gpwrdn.b.pwrdnrstn = 1;
34400 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
34401 + dwc_udelay(10);
34402 +
34403 + /* Disable PMU interrupt */
34404 + gpwrdn.d32 = 0;
34405 + gpwrdn.b.pmuintsel = 1;
34406 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34407 +
34408 + core_if->hibernation_suspend = 0;
34409 +
34410 + /* Disable PMU */
34411 + gpwrdn.d32 = 0;
34412 + gpwrdn.b.pmuactv = 1;
34413 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34414 + dwc_udelay(10);
34415 +
34416 + /* Enable VBUS */
34417 + gpwrdn.d32 = 0;
34418 + gpwrdn.b.dis_vbus = 1;
34419 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34420 +
34421 + core_if->op_state = A_HOST;
34422 + dwc_otg_core_init(core_if);
34423 + dwc_otg_enable_global_interrupts(core_if);
34424 + cil_hcd_start(core_if);
34425 +}
34426 +
34427 +/**
34428 + * Frees secondary storage associated with the dwc_otg_hcd structure contained
34429 + * in the struct usb_hcd field.
34430 + */
34431 +static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)
34432 +{
34433 + int i;
34434 +
34435 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
34436 +
34437 + del_timers(dwc_otg_hcd);
34438 +
34439 + /* Free memory for QH/QTD lists */
34440 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
34441 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
34442 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
34443 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
34444 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
34445 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
34446 +
34447 + /* Free memory for the host channels. */
34448 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
34449 + dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i];
34450 +
34451 +#ifdef DEBUG
34452 + if (dwc_otg_hcd->core_if->hc_xfer_timer[i]) {
34453 + DWC_TIMER_FREE(dwc_otg_hcd->core_if->hc_xfer_timer[i]);
34454 + }
34455 +#endif
34456 + if (hc != NULL) {
34457 + DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n",
34458 + i, hc);
34459 + DWC_FREE(hc);
34460 + }
34461 + }
34462 +
34463 + if (dwc_otg_hcd->core_if->dma_enable) {
34464 + if (dwc_otg_hcd->status_buf_dma) {
34465 + DWC_DMA_FREE(DWC_OTG_HCD_STATUS_BUF_SIZE,
34466 + dwc_otg_hcd->status_buf,
34467 + dwc_otg_hcd->status_buf_dma);
34468 + }
34469 + } else if (dwc_otg_hcd->status_buf != NULL) {
34470 + DWC_FREE(dwc_otg_hcd->status_buf);
34471 + }
34472 + DWC_SPINLOCK_FREE(dwc_otg_hcd->channel_lock);
34473 + DWC_SPINLOCK_FREE(dwc_otg_hcd->lock);
34474 + /* Set core_if's lock pointer to NULL */
34475 + dwc_otg_hcd->core_if->lock = NULL;
34476 +
34477 + DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
34478 + DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
34479 + DWC_TASK_FREE(dwc_otg_hcd->completion_tasklet);
34480 +
34481 +#ifdef DWC_DEV_SRPCAP
34482 + if (dwc_otg_hcd->core_if->power_down == 2 &&
34483 + dwc_otg_hcd->core_if->pwron_timer) {
34484 + DWC_TIMER_FREE(dwc_otg_hcd->core_if->pwron_timer);
34485 + }
34486 +#endif
34487 + DWC_FREE(dwc_otg_hcd);
34488 +}
34489 +
34490 +int init_hcd_usecs(dwc_otg_hcd_t *_hcd);
34491 +
34492 +int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
34493 +{
34494 + int retval = 0;
34495 + int num_channels;
34496 + int i;
34497 + dwc_hc_t *channel;
34498 +
34499 + hcd->lock = DWC_SPINLOCK_ALLOC();
34500 + hcd->channel_lock = DWC_SPINLOCK_ALLOC();
34501 + DWC_DEBUGPL(DBG_HCDV, "init of HCD %p given core_if %p\n",
34502 + hcd, core_if);
34503 + if (!hcd->lock) {
34504 + DWC_ERROR("Could not allocate lock for pcd");
34505 + DWC_FREE(hcd);
34506 + retval = -DWC_E_NO_MEMORY;
34507 + goto out;
34508 + }
34509 + hcd->core_if = core_if;
34510 +
34511 + /* Register the HCD CIL Callbacks */
34512 + dwc_otg_cil_register_hcd_callbacks(hcd->core_if,
34513 + &hcd_cil_callbacks, hcd);
34514 +
34515 + /* Initialize the non-periodic schedule. */
34516 + DWC_LIST_INIT(&hcd->non_periodic_sched_inactive);
34517 + DWC_LIST_INIT(&hcd->non_periodic_sched_active);
34518 +
34519 + /* Initialize the periodic schedule. */
34520 + DWC_LIST_INIT(&hcd->periodic_sched_inactive);
34521 + DWC_LIST_INIT(&hcd->periodic_sched_ready);
34522 + DWC_LIST_INIT(&hcd->periodic_sched_assigned);
34523 + DWC_LIST_INIT(&hcd->periodic_sched_queued);
34524 + DWC_TAILQ_INIT(&hcd->completed_urb_list);
34525 + /*
34526 + * Create a host channel descriptor for each host channel implemented
34527 + * in the controller. Initialize the channel descriptor array.
34528 + */
34529 + DWC_CIRCLEQ_INIT(&hcd->free_hc_list);
34530 + num_channels = hcd->core_if->core_params->host_channels;
34531 + DWC_MEMSET(hcd->hc_ptr_array, 0, sizeof(hcd->hc_ptr_array));
34532 + for (i = 0; i < num_channels; i++) {
34533 + channel = DWC_ALLOC(sizeof(dwc_hc_t));
34534 + if (channel == NULL) {
34535 + retval = -DWC_E_NO_MEMORY;
34536 + DWC_ERROR("%s: host channel allocation failed\n",
34537 + __func__);
34538 + dwc_otg_hcd_free(hcd);
34539 + goto out;
34540 + }
34541 + channel->hc_num = i;
34542 + hcd->hc_ptr_array[i] = channel;
34543 +#ifdef DEBUG
34544 + hcd->core_if->hc_xfer_timer[i] =
34545 + DWC_TIMER_ALLOC("hc timer", hc_xfer_timeout,
34546 + &hcd->core_if->hc_xfer_info[i]);
34547 +#endif
34548 + DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i,
34549 + channel);
34550 + }
34551 +
34552 + /* Initialize the Connection timeout timer. */
34553 + hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer",
34554 + dwc_otg_hcd_connect_timeout, 0);
34555 +
34556 + printk(KERN_DEBUG "dwc_otg: Microframe scheduler %s\n", microframe_schedule ? "enabled":"disabled");
34557 + if (microframe_schedule)
34558 + init_hcd_usecs(hcd);
34559 +
34560 + /* Initialize reset tasklet. */
34561 + hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd);
34562 +
34563 + hcd->completion_tasklet = DWC_TASK_ALLOC("completion_tasklet",
34564 + completion_tasklet_func, hcd);
34565 +#ifdef DWC_DEV_SRPCAP
34566 + if (hcd->core_if->power_down == 2) {
34567 + /* Initialize Power on timer for Host power up in case hibernation */
34568 + hcd->core_if->pwron_timer = DWC_TIMER_ALLOC("PWRON TIMER",
34569 + dwc_otg_hcd_power_up, core_if);
34570 + }
34571 +#endif
34572 +
34573 + /*
34574 + * Allocate space for storing data on status transactions. Normally no
34575 + * data is sent, but this space acts as a bit bucket. This must be
34576 + * done after usb_add_hcd since that function allocates the DMA buffer
34577 + * pool.
34578 + */
34579 + if (hcd->core_if->dma_enable) {
34580 + hcd->status_buf =
34581 + DWC_DMA_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE,
34582 + &hcd->status_buf_dma);
34583 + } else {
34584 + hcd->status_buf = DWC_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE);
34585 + }
34586 + if (!hcd->status_buf) {
34587 + retval = -DWC_E_NO_MEMORY;
34588 + DWC_ERROR("%s: status_buf allocation failed\n", __func__);
34589 + dwc_otg_hcd_free(hcd);
34590 + goto out;
34591 + }
34592 +
34593 + hcd->otg_port = 1;
34594 + hcd->frame_list = NULL;
34595 + hcd->frame_list_dma = 0;
34596 + hcd->periodic_qh_count = 0;
34597 +out:
34598 + return retval;
34599 +}
34600 +
34601 +void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd)
34602 +{
34603 + /* Turn off all host-specific interrupts. */
34604 + dwc_otg_disable_host_interrupts(hcd->core_if);
34605 +
34606 + dwc_otg_hcd_free(hcd);
34607 +}
34608 +
34609 +/**
34610 + * Initializes dynamic portions of the DWC_otg HCD state.
34611 + */
34612 +static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd)
34613 +{
34614 + int num_channels;
34615 + int i;
34616 + dwc_hc_t *channel;
34617 + dwc_hc_t *channel_tmp;
34618 +
34619 + hcd->flags.d32 = 0;
34620 +
34621 + hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
34622 + if (!microframe_schedule) {
34623 + hcd->non_periodic_channels = 0;
34624 + hcd->periodic_channels = 0;
34625 + } else {
34626 + hcd->available_host_channels = hcd->core_if->core_params->host_channels;
34627 + }
34628 + /*
34629 + * Put all channels in the free channel list and clean up channel
34630 + * states.
34631 + */
34632 + DWC_CIRCLEQ_FOREACH_SAFE(channel, channel_tmp,
34633 + &hcd->free_hc_list, hc_list_entry) {
34634 + DWC_CIRCLEQ_REMOVE(&hcd->free_hc_list, channel, hc_list_entry);
34635 + }
34636 +
34637 + num_channels = hcd->core_if->core_params->host_channels;
34638 + for (i = 0; i < num_channels; i++) {
34639 + channel = hcd->hc_ptr_array[i];
34640 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, channel,
34641 + hc_list_entry);
34642 + dwc_otg_hc_cleanup(hcd->core_if, channel);
34643 + }
34644 +
34645 + /* Initialize the DWC core for host mode operation. */
34646 + dwc_otg_core_host_init(hcd->core_if);
34647 +
34648 + /* Set core_if's lock pointer to the hcd->lock */
34649 + hcd->core_if->lock = hcd->lock;
34650 +}
34651 +
34652 +/**
34653 + * Assigns transactions from a QTD to a free host channel and initializes the
34654 + * host channel to perform the transactions. The host channel is removed from
34655 + * the free list.
34656 + *
34657 + * @param hcd The HCD state structure.
34658 + * @param qh Transactions from the first QTD for this QH are selected and
34659 + * assigned to a free host channel.
34660 + */
34661 +static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
34662 +{
34663 + dwc_hc_t *hc;
34664 + dwc_otg_qtd_t *qtd;
34665 + dwc_otg_hcd_urb_t *urb;
34666 + void* ptr = NULL;
34667 +
34668 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
34669 +
34670 + urb = qtd->urb;
34671 +
34672 + DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p) - urb %x, actual_length %d\n", __func__, hcd, qh, (unsigned int)urb, urb->actual_length);
34673 +
34674 + if (((urb->actual_length < 0) || (urb->actual_length > urb->length)) && !dwc_otg_hcd_is_pipe_in(&urb->pipe_info))
34675 + urb->actual_length = urb->length;
34676 +
34677 +
34678 + hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
34679 +
34680 + /* Remove the host channel from the free list. */
34681 + DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
34682 +
34683 + qh->channel = hc;
34684 +
34685 + qtd->in_process = 1;
34686 +
34687 + /*
34688 + * Use usb_pipedevice to determine device address. This address is
34689 + * 0 before the SET_ADDRESS command and the correct address afterward.
34690 + */
34691 + hc->dev_addr = dwc_otg_hcd_get_dev_addr(&urb->pipe_info);
34692 + hc->ep_num = dwc_otg_hcd_get_ep_num(&urb->pipe_info);
34693 + hc->speed = qh->dev_speed;
34694 + hc->max_packet = dwc_max_packet(qh->maxp);
34695 +
34696 + hc->xfer_started = 0;
34697 + hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
34698 + hc->error_state = (qtd->error_count > 0);
34699 + hc->halt_on_queue = 0;
34700 + hc->halt_pending = 0;
34701 + hc->requests = 0;
34702 +
34703 + /*
34704 + * The following values may be modified in the transfer type section
34705 + * below. The xfer_len value may be reduced when the transfer is
34706 + * started to accommodate the max widths of the XferSize and PktCnt
34707 + * fields in the HCTSIZn register.
34708 + */
34709 +
34710 + hc->ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0);
34711 + if (hc->ep_is_in) {
34712 + hc->do_ping = 0;
34713 + } else {
34714 + hc->do_ping = qh->ping_state;
34715 + }
34716 +
34717 + hc->data_pid_start = qh->data_toggle;
34718 + hc->multi_count = 1;
34719 +
34720 + if (hcd->core_if->dma_enable) {
34721 + hc->xfer_buff = (uint8_t *) urb->dma + urb->actual_length;
34722 +
34723 + /* For non-dword aligned case */
34724 + if (((unsigned long)hc->xfer_buff & 0x3)
34725 + && !hcd->core_if->dma_desc_enable) {
34726 + ptr = (uint8_t *) urb->buf + urb->actual_length;
34727 + }
34728 + } else {
34729 + hc->xfer_buff = (uint8_t *) urb->buf + urb->actual_length;
34730 + }
34731 + hc->xfer_len = urb->length - urb->actual_length;
34732 + hc->xfer_count = 0;
34733 +
34734 + /*
34735 + * Set the split attributes
34736 + */
34737 + hc->do_split = 0;
34738 + if (qh->do_split) {
34739 + uint32_t hub_addr, port_addr;
34740 + hc->do_split = 1;
34741 + hc->xact_pos = qtd->isoc_split_pos;
34742 + hc->complete_split = qtd->complete_split;
34743 + hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr);
34744 + hc->hub_addr = (uint8_t) hub_addr;
34745 + hc->port_addr = (uint8_t) port_addr;
34746 + }
34747 +
34748 + switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
34749 + case UE_CONTROL:
34750 + hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
34751 + switch (qtd->control_phase) {
34752 + case DWC_OTG_CONTROL_SETUP:
34753 + DWC_DEBUGPL(DBG_HCDV, " Control setup transaction\n");
34754 + hc->do_ping = 0;
34755 + hc->ep_is_in = 0;
34756 + hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
34757 + if (hcd->core_if->dma_enable) {
34758 + hc->xfer_buff = (uint8_t *) urb->setup_dma;
34759 + } else {
34760 + hc->xfer_buff = (uint8_t *) urb->setup_packet;
34761 + }
34762 + hc->xfer_len = 8;
34763 + ptr = NULL;
34764 + break;
34765 + case DWC_OTG_CONTROL_DATA:
34766 + DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n");
34767 + hc->data_pid_start = qtd->data_toggle;
34768 + break;
34769 + case DWC_OTG_CONTROL_STATUS:
34770 + /*
34771 + * Direction is opposite of data direction or IN if no
34772 + * data.
34773 + */
34774 + DWC_DEBUGPL(DBG_HCDV, " Control status transaction\n");
34775 + if (urb->length == 0) {
34776 + hc->ep_is_in = 1;
34777 + } else {
34778 + hc->ep_is_in =
34779 + dwc_otg_hcd_is_pipe_out(&urb->pipe_info);
34780 + }
34781 + if (hc->ep_is_in) {
34782 + hc->do_ping = 0;
34783 + }
34784 +
34785 + hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
34786 +
34787 + hc->xfer_len = 0;
34788 + if (hcd->core_if->dma_enable) {
34789 + hc->xfer_buff = (uint8_t *) hcd->status_buf_dma;
34790 + } else {
34791 + hc->xfer_buff = (uint8_t *) hcd->status_buf;
34792 + }
34793 + ptr = NULL;
34794 + break;
34795 + }
34796 + break;
34797 + case UE_BULK:
34798 + hc->ep_type = DWC_OTG_EP_TYPE_BULK;
34799 + break;
34800 + case UE_INTERRUPT:
34801 + hc->ep_type = DWC_OTG_EP_TYPE_INTR;
34802 + break;
34803 + case UE_ISOCHRONOUS:
34804 + {
34805 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
34806 +
34807 + hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
34808 +
34809 + if (hcd->core_if->dma_desc_enable)
34810 + break;
34811 +
34812 + frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
34813 +
34814 + frame_desc->status = 0;
34815 +
34816 + if (hcd->core_if->dma_enable) {
34817 + hc->xfer_buff = (uint8_t *) urb->dma;
34818 + } else {
34819 + hc->xfer_buff = (uint8_t *) urb->buf;
34820 + }
34821 + hc->xfer_buff +=
34822 + frame_desc->offset + qtd->isoc_split_offset;
34823 + hc->xfer_len =
34824 + frame_desc->length - qtd->isoc_split_offset;
34825 +
34826 + /* For non-dword aligned buffers */
34827 + if (((unsigned long)hc->xfer_buff & 0x3)
34828 + && hcd->core_if->dma_enable) {
34829 + ptr =
34830 + (uint8_t *) urb->buf + frame_desc->offset +
34831 + qtd->isoc_split_offset;
34832 + } else
34833 + ptr = NULL;
34834 +
34835 + if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
34836 + if (hc->xfer_len <= 188) {
34837 + hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
34838 + } else {
34839 + hc->xact_pos =
34840 + DWC_HCSPLIT_XACTPOS_BEGIN;
34841 + }
34842 + }
34843 + }
34844 + break;
34845 + }
34846 + /* non DWORD-aligned buffer case */
34847 + if (ptr) {
34848 + uint32_t buf_size;
34849 + if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
34850 + buf_size = hcd->core_if->core_params->max_transfer_size;
34851 + } else {
34852 + buf_size = 4096;
34853 + }
34854 + if (!qh->dw_align_buf) {
34855 + qh->dw_align_buf = DWC_DMA_ALLOC_ATOMIC(buf_size,
34856 + &qh->dw_align_buf_dma);
34857 + if (!qh->dw_align_buf) {
34858 + DWC_ERROR
34859 + ("%s: Failed to allocate memory to handle "
34860 + "non-dword aligned buffer case\n",
34861 + __func__);
34862 + return;
34863 + }
34864 + }
34865 + if (!hc->ep_is_in) {
34866 + dwc_memcpy(qh->dw_align_buf, ptr, hc->xfer_len);
34867 + }
34868 + hc->align_buff = qh->dw_align_buf_dma;
34869 + } else {
34870 + hc->align_buff = 0;
34871 + }
34872 +
34873 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
34874 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
34875 + /*
34876 + * This value may be modified when the transfer is started to
34877 + * reflect the actual transfer length.
34878 + */
34879 + hc->multi_count = dwc_hb_mult(qh->maxp);
34880 + }
34881 +
34882 + if (hcd->core_if->dma_desc_enable)
34883 + hc->desc_list_addr = qh->desc_list_dma;
34884 +
34885 + dwc_otg_hc_init(hcd->core_if, hc);
34886 + hc->qh = qh;
34887 +}
34888 +
34889 +/**
34890 + * This function selects transactions from the HCD transfer schedule and
34891 + * assigns them to available host channels. It is called from HCD interrupt
34892 + * handler functions.
34893 + *
34894 + * @param hcd The HCD state structure.
34895 + *
34896 + * @return The types of new transactions that were assigned to host channels.
34897 + */
34898 +dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
34899 +{
34900 + dwc_list_link_t *qh_ptr;
34901 + dwc_otg_qh_t *qh;
34902 + int num_channels;
34903 + dwc_irqflags_t flags;
34904 + dwc_spinlock_t *channel_lock = hcd->channel_lock;
34905 + dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;
34906 +
34907 +#ifdef DEBUG_SOF
34908 + DWC_DEBUGPL(DBG_HCD, " Select Transactions\n");
34909 +#endif
34910 +
34911 +#ifdef DEBUG_HOST_CHANNELS
34912 + last_sel_trans_num_per_scheduled = 0;
34913 + last_sel_trans_num_nonper_scheduled = 0;
34914 + last_sel_trans_num_avail_hc_at_start = hcd->available_host_channels;
34915 +#endif /* DEBUG_HOST_CHANNELS */
34916 +
34917 + /* Process entries in the periodic ready list. */
34918 + qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready);
34919 +
34920 + while (qh_ptr != &hcd->periodic_sched_ready &&
34921 + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
34922 + if (microframe_schedule) {
34923 + // Make sure we leave one channel for non periodic transactions.
34924 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
34925 + if (hcd->available_host_channels <= 1) {
34926 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
34927 + break;
34928 + }
34929 + hcd->available_host_channels--;
34930 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
34931 +#ifdef DEBUG_HOST_CHANNELS
34932 + last_sel_trans_num_per_scheduled++;
34933 +#endif /* DEBUG_HOST_CHANNELS */
34934 + }
34935 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
34936 + assign_and_init_hc(hcd, qh);
34937 +
34938 + /*
34939 + * Move the QH from the periodic ready schedule to the
34940 + * periodic assigned schedule.
34941 + */
34942 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
34943 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
34944 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
34945 + &qh->qh_list_entry);
34946 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
34947 +
34948 + ret_val = DWC_OTG_TRANSACTION_PERIODIC;
34949 + }
34950 +
34951 + /*
34952 + * Process entries in the inactive portion of the non-periodic
34953 + * schedule. Some free host channels may not be used if they are
34954 + * reserved for periodic transfers.
34955 + */
34956 + qh_ptr = hcd->non_periodic_sched_inactive.next;
34957 + num_channels = hcd->core_if->core_params->host_channels;
34958 + while (qh_ptr != &hcd->non_periodic_sched_inactive &&
34959 + (microframe_schedule || hcd->non_periodic_channels <
34960 + num_channels - hcd->periodic_channels) &&
34961 + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
34962 +
34963 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
34964 +
34965 + /*
34966 + * Check to see if this is a NAK'd retransmit, in which case ignore for retransmission
34967 + * we hold off on bulk retransmissions to reduce NAK interrupt overhead for full-speed
34968 + * cheeky devices that just hold off using NAKs
34969 + */
34970 + if (nak_holdoff_enable && qh->do_split) {
34971 + if (qh->nak_frame != 0xffff &&
34972 + dwc_full_frame_num(qh->nak_frame) ==
34973 + dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) {
34974 + /*
34975 + * Revisit: Need to avoid trampling on periodic scheduling.
34976 + * Currently we are safe because g_np_count != g_np_sent whenever we hit this,
34977 + * but if this behaviour is changed then periodic endpoints will get a slower
34978 + * polling rate.
34979 + */
34980 + g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM;
34981 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
34982 + continue;
34983 + } else {
34984 + qh->nak_frame = 0xffff;
34985 + }
34986 + }
34987 + if (microframe_schedule) {
34988 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
34989 + if (hcd->available_host_channels < 1) {
34990 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
34991 + break;
34992 + }
34993 + hcd->available_host_channels--;
34994 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
34995 +#ifdef DEBUG_HOST_CHANNELS
34996 + last_sel_trans_num_nonper_scheduled++;
34997 +#endif /* DEBUG_HOST_CHANNELS */
34998 + }
34999 +
35000 + assign_and_init_hc(hcd, qh);
35001 +
35002 + /*
35003 + * Move the QH from the non-periodic inactive schedule to the
35004 + * non-periodic active schedule.
35005 + */
35006 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
35007 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35008 + DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active,
35009 + &qh->qh_list_entry);
35010 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35011 +
35012 + g_np_sent++;
35013 +
35014 + if (ret_val == DWC_OTG_TRANSACTION_NONE) {
35015 + ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
35016 + } else {
35017 + ret_val = DWC_OTG_TRANSACTION_ALL;
35018 + }
35019 +
35020 + if (!microframe_schedule)
35021 + hcd->non_periodic_channels++;
35022 + }
35023 +
35024 +#ifdef DEBUG_HOST_CHANNELS
35025 + last_sel_trans_num_avail_hc_at_end = hcd->available_host_channels;
35026 +#endif /* DEBUG_HOST_CHANNELS */
35027 + return ret_val;
35028 +}
35029 +
35030 +/**
35031 + * Attempts to queue a single transaction request for a host channel
35032 + * associated with either a periodic or non-periodic transfer. This function
35033 + * assumes that there is space available in the appropriate request queue. For
35034 + * an OUT transfer or SETUP transaction in Slave mode, it checks whether space
35035 + * is available in the appropriate Tx FIFO.
35036 + *
35037 + * @param hcd The HCD state structure.
35038 + * @param hc Host channel descriptor associated with either a periodic or
35039 + * non-periodic transfer.
35040 + * @param fifo_dwords_avail Number of DWORDs available in the periodic Tx
35041 + * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic
35042 + * transfers.
35043 + *
35044 + * @return 1 if a request is queued and more requests may be needed to
35045 + * complete the transfer, 0 if no more requests are required for this
35046 + * transfer, -1 if there is insufficient space in the Tx FIFO.
35047 + */
35048 +static int queue_transaction(dwc_otg_hcd_t * hcd,
35049 + dwc_hc_t * hc, uint16_t fifo_dwords_avail)
35050 +{
35051 + int retval;
35052 +
35053 + if (hcd->core_if->dma_enable) {
35054 + if (hcd->core_if->dma_desc_enable) {
35055 + if (!hc->xfer_started
35056 + || (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {
35057 + dwc_otg_hcd_start_xfer_ddma(hcd, hc->qh);
35058 + hc->qh->ping_state = 0;
35059 + }
35060 + } else if (!hc->xfer_started) {
35061 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35062 + hc->qh->ping_state = 0;
35063 + }
35064 + retval = 0;
35065 + } else if (hc->halt_pending) {
35066 + /* Don't queue a request if the channel has been halted. */
35067 + retval = 0;
35068 + } else if (hc->halt_on_queue) {
35069 + dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status);
35070 + retval = 0;
35071 + } else if (hc->do_ping) {
35072 + if (!hc->xfer_started) {
35073 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35074 + }
35075 + retval = 0;
35076 + } else if (!hc->ep_is_in || hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
35077 + if ((fifo_dwords_avail * 4) >= hc->max_packet) {
35078 + if (!hc->xfer_started) {
35079 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35080 + retval = 1;
35081 + } else {
35082 + retval =
35083 + dwc_otg_hc_continue_transfer(hcd->core_if,
35084 + hc);
35085 + }
35086 + } else {
35087 + retval = -1;
35088 + }
35089 + } else {
35090 + if (!hc->xfer_started) {
35091 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35092 + retval = 1;
35093 + } else {
35094 + retval = dwc_otg_hc_continue_transfer(hcd->core_if, hc);
35095 + }
35096 + }
35097 +
35098 + return retval;
35099 +}
35100 +
35101 +/**
35102 + * Processes periodic channels for the next frame and queues transactions for
35103 + * these channels to the DWC_otg controller. After queueing transactions, the
35104 + * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
35105 + * to queue as Periodic Tx FIFO or request queue space becomes available.
35106 + * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
35107 + */
35108 +static void process_periodic_channels(dwc_otg_hcd_t * hcd)
35109 +{
35110 + hptxsts_data_t tx_status;
35111 + dwc_list_link_t *qh_ptr;
35112 + dwc_otg_qh_t *qh;
35113 + int status;
35114 + int no_queue_space = 0;
35115 + int no_fifo_space = 0;
35116 +
35117 + dwc_otg_host_global_regs_t *host_regs;
35118 + host_regs = hcd->core_if->host_if->host_global_regs;
35119 +
35120 + DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n");
35121 +#ifdef DEBUG
35122 + tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
35123 + DWC_DEBUGPL(DBG_HCDV,
35124 + " P Tx Req Queue Space Avail (before queue): %d\n",
35125 + tx_status.b.ptxqspcavail);
35126 + DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (before queue): %d\n",
35127 + tx_status.b.ptxfspcavail);
35128 +#endif
35129 +
35130 + qh_ptr = hcd->periodic_sched_assigned.next;
35131 + while (qh_ptr != &hcd->periodic_sched_assigned) {
35132 + tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
35133 + if (tx_status.b.ptxqspcavail == 0) {
35134 + no_queue_space = 1;
35135 + break;
35136 + }
35137 +
35138 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
35139 +
35140 + /*
35141 + * Set a flag if we're queuing high-bandwidth in slave mode.
35142 + * The flag prevents any halts to get into the request queue in
35143 + * the middle of multiple high-bandwidth packets getting queued.
35144 + */
35145 + if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) {
35146 + hcd->core_if->queuing_high_bandwidth = 1;
35147 + }
35148 + status =
35149 + queue_transaction(hcd, qh->channel,
35150 + tx_status.b.ptxfspcavail);
35151 + if (status < 0) {
35152 + no_fifo_space = 1;
35153 + break;
35154 + }
35155 +
35156 + /*
35157 + * In Slave mode, stay on the current transfer until there is
35158 + * nothing more to do or the high-bandwidth request count is
35159 + * reached. In DMA mode, only need to queue one request. The
35160 + * controller automatically handles multiple packets for
35161 + * high-bandwidth transfers.
35162 + */
35163 + if (hcd->core_if->dma_enable || status == 0 ||
35164 + qh->channel->requests == qh->channel->multi_count) {
35165 + qh_ptr = qh_ptr->next;
35166 + /*
35167 + * Move the QH from the periodic assigned schedule to
35168 + * the periodic queued schedule.
35169 + */
35170 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_queued,
35171 + &qh->qh_list_entry);
35172 +
35173 + /* done queuing high bandwidth */
35174 + hcd->core_if->queuing_high_bandwidth = 0;
35175 + }
35176 + }
35177 +
35178 + if (!hcd->core_if->dma_enable) {
35179 + dwc_otg_core_global_regs_t *global_regs;
35180 + gintmsk_data_t intr_mask = {.d32 = 0 };
35181 +
35182 + global_regs = hcd->core_if->core_global_regs;
35183 + intr_mask.b.ptxfempty = 1;
35184 +#ifdef DEBUG
35185 + tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
35186 + DWC_DEBUGPL(DBG_HCDV,
35187 + " P Tx Req Queue Space Avail (after queue): %d\n",
35188 + tx_status.b.ptxqspcavail);
35189 + DWC_DEBUGPL(DBG_HCDV,
35190 + " P Tx FIFO Space Avail (after queue): %d\n",
35191 + tx_status.b.ptxfspcavail);
35192 +#endif
35193 + if (!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned) ||
35194 + no_queue_space || no_fifo_space) {
35195 + /*
35196 + * May need to queue more transactions as the request
35197 + * queue or Tx FIFO empties. Enable the periodic Tx
35198 + * FIFO empty interrupt. (Always use the half-empty
35199 + * level to ensure that new requests are loaded as
35200 + * soon as possible.)
35201 + */
35202 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
35203 + intr_mask.d32);
35204 + } else {
35205 + /*
35206 + * Disable the Tx FIFO empty interrupt since there are
35207 + * no more transactions that need to be queued right
35208 + * now. This function is called from interrupt
35209 + * handlers to queue more transactions as transfer
35210 + * states change.
35211 + */
35212 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
35213 + 0);
35214 + }
35215 + }
35216 +}
35217 +
35218 +/**
35219 + * Processes active non-periodic channels and queues transactions for these
35220 + * channels to the DWC_otg controller. After queueing transactions, the NP Tx
35221 + * FIFO Empty interrupt is enabled if there are more transactions to queue as
35222 + * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
35223 + * FIFO Empty interrupt is disabled.
35224 + */
35225 +static void process_non_periodic_channels(dwc_otg_hcd_t * hcd)
35226 +{
35227 + gnptxsts_data_t tx_status;
35228 + dwc_list_link_t *orig_qh_ptr;
35229 + dwc_otg_qh_t *qh;
35230 + int status;
35231 + int no_queue_space = 0;
35232 + int no_fifo_space = 0;
35233 + int more_to_do = 0;
35234 +
35235 + dwc_otg_core_global_regs_t *global_regs =
35236 + hcd->core_if->core_global_regs;
35237 +
35238 + DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n");
35239 +#ifdef DEBUG
35240 + tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
35241 + DWC_DEBUGPL(DBG_HCDV,
35242 + " NP Tx Req Queue Space Avail (before queue): %d\n",
35243 + tx_status.b.nptxqspcavail);
35244 + DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (before queue): %d\n",
35245 + tx_status.b.nptxfspcavail);
35246 +#endif
35247 + /*
35248 + * Keep track of the starting point. Skip over the start-of-list
35249 + * entry.
35250 + */
35251 + if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
35252 + hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
35253 + }
35254 + orig_qh_ptr = hcd->non_periodic_qh_ptr;
35255 +
35256 + /*
35257 + * Process once through the active list or until no more space is
35258 + * available in the request queue or the Tx FIFO.
35259 + */
35260 + do {
35261 + tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
35262 + if (!hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) {
35263 + no_queue_space = 1;
35264 + break;
35265 + }
35266 +
35267 + qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t,
35268 + qh_list_entry);
35269 + status =
35270 + queue_transaction(hcd, qh->channel,
35271 + tx_status.b.nptxfspcavail);
35272 +
35273 + if (status > 0) {
35274 + more_to_do = 1;
35275 + } else if (status < 0) {
35276 + no_fifo_space = 1;
35277 + break;
35278 + }
35279 +
35280 + /* Advance to next QH, skipping start-of-list entry. */
35281 + hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
35282 + if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
35283 + hcd->non_periodic_qh_ptr =
35284 + hcd->non_periodic_qh_ptr->next;
35285 + }
35286 +
35287 + } while (hcd->non_periodic_qh_ptr != orig_qh_ptr);
35288 +
35289 + if (!hcd->core_if->dma_enable) {
35290 + gintmsk_data_t intr_mask = {.d32 = 0 };
35291 + intr_mask.b.nptxfempty = 1;
35292 +
35293 +#ifdef DEBUG
35294 + tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
35295 + DWC_DEBUGPL(DBG_HCDV,
35296 + " NP Tx Req Queue Space Avail (after queue): %d\n",
35297 + tx_status.b.nptxqspcavail);
35298 + DWC_DEBUGPL(DBG_HCDV,
35299 + " NP Tx FIFO Space Avail (after queue): %d\n",
35300 + tx_status.b.nptxfspcavail);
35301 +#endif
35302 + if (more_to_do || no_queue_space || no_fifo_space) {
35303 + /*
35304 + * May need to queue more transactions as the request
35305 + * queue or Tx FIFO empties. Enable the non-periodic
35306 + * Tx FIFO empty interrupt. (Always use the half-empty
35307 + * level to ensure that new requests are loaded as
35308 + * soon as possible.)
35309 + */
35310 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
35311 + intr_mask.d32);
35312 + } else {
35313 + /*
35314 + * Disable the Tx FIFO empty interrupt since there are
35315 + * no more transactions that need to be queued right
35316 + * now. This function is called from interrupt
35317 + * handlers to queue more transactions as transfer
35318 + * states change.
35319 + */
35320 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
35321 + 0);
35322 + }
35323 + }
35324 +}
35325 +
35326 +/**
35327 + * This function processes the currently active host channels and queues
35328 + * transactions for these channels to the DWC_otg controller. It is called
35329 + * from HCD interrupt handler functions.
35330 + *
35331 + * @param hcd The HCD state structure.
35332 + * @param tr_type The type(s) of transactions to queue (non-periodic,
35333 + * periodic, or both).
35334 + */
35335 +void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
35336 + dwc_otg_transaction_type_e tr_type)
35337 +{
35338 +#ifdef DEBUG_SOF
35339 + DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n");
35340 +#endif
35341 + /* Process host channels associated with periodic transfers. */
35342 + if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
35343 + tr_type == DWC_OTG_TRANSACTION_ALL) &&
35344 + !DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) {
35345 +
35346 + process_periodic_channels(hcd);
35347 + }
35348 +
35349 + /* Process host channels associated with non-periodic transfers. */
35350 + if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
35351 + tr_type == DWC_OTG_TRANSACTION_ALL) {
35352 + if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) {
35353 + process_non_periodic_channels(hcd);
35354 + } else {
35355 + /*
35356 + * Ensure NP Tx FIFO empty interrupt is disabled when
35357 + * there are no non-periodic transfers to process.
35358 + */
35359 + gintmsk_data_t gintmsk = {.d32 = 0 };
35360 + gintmsk.b.nptxfempty = 1;
35361 + DWC_MODIFY_REG32(&hcd->core_if->
35362 + core_global_regs->gintmsk, gintmsk.d32,
35363 + 0);
35364 + }
35365 + }
35366 +}
35367 +
35368 +#ifdef DWC_HS_ELECT_TST
35369 +/*
35370 + * Quick and dirty hack to implement the HS Electrical Test
35371 + * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
35372 + *
35373 + * This code was copied from our userspace app "hset". It sends a
35374 + * Get Device Descriptor control sequence in two parts, first the
35375 + * Setup packet by itself, followed some time later by the In and
35376 + * Ack packets. Rather than trying to figure out how to add this
35377 + * functionality to the normal driver code, we just hijack the
35378 + * hardware, using these two function to drive the hardware
35379 + * directly.
35380 + */
35381 +
35382 +static dwc_otg_core_global_regs_t *global_regs;
35383 +static dwc_otg_host_global_regs_t *hc_global_regs;
35384 +static dwc_otg_hc_regs_t *hc_regs;
35385 +static uint32_t *data_fifo;
35386 +
35387 +static void do_setup(void)
35388 +{
35389 + gintsts_data_t gintsts;
35390 + hctsiz_data_t hctsiz;
35391 + hcchar_data_t hcchar;
35392 + haint_data_t haint;
35393 + hcint_data_t hcint;
35394 +
35395 + /* Enable HAINTs */
35396 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
35397 +
35398 + /* Enable HCINTs */
35399 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
35400 +
35401 + /* Read GINTSTS */
35402 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35403 +
35404 + /* Read HAINT */
35405 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35406 +
35407 + /* Read HCINT */
35408 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35409 +
35410 + /* Read HCCHAR */
35411 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35412 +
35413 + /* Clear HCINT */
35414 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35415 +
35416 + /* Clear HAINT */
35417 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35418 +
35419 + /* Clear GINTSTS */
35420 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35421 +
35422 + /* Read GINTSTS */
35423 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35424 +
35425 + /*
35426 + * Send Setup packet (Get Device Descriptor)
35427 + */
35428 +
35429 + /* Make sure channel is disabled */
35430 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35431 + if (hcchar.b.chen) {
35432 + hcchar.b.chdis = 1;
35433 +// hcchar.b.chen = 1;
35434 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35435 + //sleep(1);
35436 + dwc_mdelay(1000);
35437 +
35438 + /* Read GINTSTS */
35439 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35440 +
35441 + /* Read HAINT */
35442 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35443 +
35444 + /* Read HCINT */
35445 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35446 +
35447 + /* Read HCCHAR */
35448 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35449 +
35450 + /* Clear HCINT */
35451 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35452 +
35453 + /* Clear HAINT */
35454 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35455 +
35456 + /* Clear GINTSTS */
35457 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35458 +
35459 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35460 + }
35461 +
35462 + /* Set HCTSIZ */
35463 + hctsiz.d32 = 0;
35464 + hctsiz.b.xfersize = 8;
35465 + hctsiz.b.pktcnt = 1;
35466 + hctsiz.b.pid = DWC_OTG_HC_PID_SETUP;
35467 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
35468 +
35469 + /* Set HCCHAR */
35470 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35471 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
35472 + hcchar.b.epdir = 0;
35473 + hcchar.b.epnum = 0;
35474 + hcchar.b.mps = 8;
35475 + hcchar.b.chen = 1;
35476 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35477 +
35478 + /* Fill FIFO with Setup data for Get Device Descriptor */
35479 + data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
35480 + DWC_WRITE_REG32(data_fifo++, 0x01000680);
35481 + DWC_WRITE_REG32(data_fifo++, 0x00080000);
35482 +
35483 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35484 +
35485 + /* Wait for host channel interrupt */
35486 + do {
35487 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35488 + } while (gintsts.b.hcintr == 0);
35489 +
35490 + /* Disable HCINTs */
35491 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
35492 +
35493 + /* Disable HAINTs */
35494 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
35495 +
35496 + /* Read HAINT */
35497 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35498 +
35499 + /* Read HCINT */
35500 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35501 +
35502 + /* Read HCCHAR */
35503 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35504 +
35505 + /* Clear HCINT */
35506 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35507 +
35508 + /* Clear HAINT */
35509 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35510 +
35511 + /* Clear GINTSTS */
35512 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35513 +
35514 + /* Read GINTSTS */
35515 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35516 +}
35517 +
35518 +static void do_in_ack(void)
35519 +{
35520 + gintsts_data_t gintsts;
35521 + hctsiz_data_t hctsiz;
35522 + hcchar_data_t hcchar;
35523 + haint_data_t haint;
35524 + hcint_data_t hcint;
35525 + host_grxsts_data_t grxsts;
35526 +
35527 + /* Enable HAINTs */
35528 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
35529 +
35530 + /* Enable HCINTs */
35531 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
35532 +
35533 + /* Read GINTSTS */
35534 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35535 +
35536 + /* Read HAINT */
35537 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35538 +
35539 + /* Read HCINT */
35540 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35541 +
35542 + /* Read HCCHAR */
35543 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35544 +
35545 + /* Clear HCINT */
35546 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35547 +
35548 + /* Clear HAINT */
35549 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35550 +
35551 + /* Clear GINTSTS */
35552 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35553 +
35554 + /* Read GINTSTS */
35555 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35556 +
35557 + /*
35558 + * Receive Control In packet
35559 + */
35560 +
35561 + /* Make sure channel is disabled */
35562 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35563 + if (hcchar.b.chen) {
35564 + hcchar.b.chdis = 1;
35565 + hcchar.b.chen = 1;
35566 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35567 + //sleep(1);
35568 + dwc_mdelay(1000);
35569 +
35570 + /* Read GINTSTS */
35571 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35572 +
35573 + /* Read HAINT */
35574 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35575 +
35576 + /* Read HCINT */
35577 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35578 +
35579 + /* Read HCCHAR */
35580 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35581 +
35582 + /* Clear HCINT */
35583 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35584 +
35585 + /* Clear HAINT */
35586 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35587 +
35588 + /* Clear GINTSTS */
35589 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35590 +
35591 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35592 + }
35593 +
35594 + /* Set HCTSIZ */
35595 + hctsiz.d32 = 0;
35596 + hctsiz.b.xfersize = 8;
35597 + hctsiz.b.pktcnt = 1;
35598 + hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
35599 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
35600 +
35601 + /* Set HCCHAR */
35602 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35603 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
35604 + hcchar.b.epdir = 1;
35605 + hcchar.b.epnum = 0;
35606 + hcchar.b.mps = 8;
35607 + hcchar.b.chen = 1;
35608 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35609 +
35610 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35611 +
35612 + /* Wait for receive status queue interrupt */
35613 + do {
35614 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35615 + } while (gintsts.b.rxstsqlvl == 0);
35616 +
35617 + /* Read RXSTS */
35618 + grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
35619 +
35620 + /* Clear RXSTSQLVL in GINTSTS */
35621 + gintsts.d32 = 0;
35622 + gintsts.b.rxstsqlvl = 1;
35623 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35624 +
35625 + switch (grxsts.b.pktsts) {
35626 + case DWC_GRXSTS_PKTSTS_IN:
35627 + /* Read the data into the host buffer */
35628 + if (grxsts.b.bcnt > 0) {
35629 + int i;
35630 + int word_count = (grxsts.b.bcnt + 3) / 4;
35631 +
35632 + data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
35633 +
35634 + for (i = 0; i < word_count; i++) {
35635 + (void)DWC_READ_REG32(data_fifo++);
35636 + }
35637 + }
35638 + break;
35639 +
35640 + default:
35641 + break;
35642 + }
35643 +
35644 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35645 +
35646 + /* Wait for receive status queue interrupt */
35647 + do {
35648 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35649 + } while (gintsts.b.rxstsqlvl == 0);
35650 +
35651 + /* Read RXSTS */
35652 + grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
35653 +
35654 + /* Clear RXSTSQLVL in GINTSTS */
35655 + gintsts.d32 = 0;
35656 + gintsts.b.rxstsqlvl = 1;
35657 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35658 +
35659 + switch (grxsts.b.pktsts) {
35660 + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
35661 + break;
35662 +
35663 + default:
35664 + break;
35665 + }
35666 +
35667 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35668 +
35669 + /* Wait for host channel interrupt */
35670 + do {
35671 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35672 + } while (gintsts.b.hcintr == 0);
35673 +
35674 + /* Read HAINT */
35675 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35676 +
35677 + /* Read HCINT */
35678 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35679 +
35680 + /* Read HCCHAR */
35681 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35682 +
35683 + /* Clear HCINT */
35684 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35685 +
35686 + /* Clear HAINT */
35687 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35688 +
35689 + /* Clear GINTSTS */
35690 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35691 +
35692 + /* Read GINTSTS */
35693 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35694 +
35695 +// usleep(100000);
35696 +// mdelay(100);
35697 + dwc_mdelay(1);
35698 +
35699 + /*
35700 + * Send handshake packet
35701 + */
35702 +
35703 + /* Read HAINT */
35704 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35705 +
35706 + /* Read HCINT */
35707 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35708 +
35709 + /* Read HCCHAR */
35710 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35711 +
35712 + /* Clear HCINT */
35713 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35714 +
35715 + /* Clear HAINT */
35716 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35717 +
35718 + /* Clear GINTSTS */
35719 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35720 +
35721 + /* Read GINTSTS */
35722 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35723 +
35724 + /* Make sure channel is disabled */
35725 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35726 + if (hcchar.b.chen) {
35727 + hcchar.b.chdis = 1;
35728 + hcchar.b.chen = 1;
35729 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35730 + //sleep(1);
35731 + dwc_mdelay(1000);
35732 +
35733 + /* Read GINTSTS */
35734 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35735 +
35736 + /* Read HAINT */
35737 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35738 +
35739 + /* Read HCINT */
35740 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35741 +
35742 + /* Read HCCHAR */
35743 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35744 +
35745 + /* Clear HCINT */
35746 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35747 +
35748 + /* Clear HAINT */
35749 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35750 +
35751 + /* Clear GINTSTS */
35752 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35753 +
35754 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35755 + }
35756 +
35757 + /* Set HCTSIZ */
35758 + hctsiz.d32 = 0;
35759 + hctsiz.b.xfersize = 0;
35760 + hctsiz.b.pktcnt = 1;
35761 + hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
35762 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
35763 +
35764 + /* Set HCCHAR */
35765 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35766 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
35767 + hcchar.b.epdir = 0;
35768 + hcchar.b.epnum = 0;
35769 + hcchar.b.mps = 8;
35770 + hcchar.b.chen = 1;
35771 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35772 +
35773 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35774 +
35775 + /* Wait for host channel interrupt */
35776 + do {
35777 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35778 + } while (gintsts.b.hcintr == 0);
35779 +
35780 + /* Disable HCINTs */
35781 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
35782 +
35783 + /* Disable HAINTs */
35784 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
35785 +
35786 + /* Read HAINT */
35787 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35788 +
35789 + /* Read HCINT */
35790 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35791 +
35792 + /* Read HCCHAR */
35793 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35794 +
35795 + /* Clear HCINT */
35796 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35797 +
35798 + /* Clear HAINT */
35799 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35800 +
35801 + /* Clear GINTSTS */
35802 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35803 +
35804 + /* Read GINTSTS */
35805 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35806 +}
35807 +#endif
35808 +
35809 +/** Handles hub class-specific requests. */
35810 +int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
35811 + uint16_t typeReq,
35812 + uint16_t wValue,
35813 + uint16_t wIndex, uint8_t * buf, uint16_t wLength)
35814 +{
35815 + int retval = 0;
35816 +
35817 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
35818 + usb_hub_descriptor_t *hub_desc;
35819 + hprt0_data_t hprt0 = {.d32 = 0 };
35820 +
35821 + uint32_t port_status;
35822 +
35823 + switch (typeReq) {
35824 + case UCR_CLEAR_HUB_FEATURE:
35825 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
35826 + "ClearHubFeature 0x%x\n", wValue);
35827 + switch (wValue) {
35828 + case UHF_C_HUB_LOCAL_POWER:
35829 + case UHF_C_HUB_OVER_CURRENT:
35830 + /* Nothing required here */
35831 + break;
35832 + default:
35833 + retval = -DWC_E_INVALID;
35834 + DWC_ERROR("DWC OTG HCD - "
35835 + "ClearHubFeature request %xh unknown\n",
35836 + wValue);
35837 + }
35838 + break;
35839 + case UCR_CLEAR_PORT_FEATURE:
35840 +#ifdef CONFIG_USB_DWC_OTG_LPM
35841 + if (wValue != UHF_PORT_L1)
35842 +#endif
35843 + if (!wIndex || wIndex > 1)
35844 + goto error;
35845 +
35846 + switch (wValue) {
35847 + case UHF_PORT_ENABLE:
35848 + DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - "
35849 + "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
35850 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
35851 + hprt0.b.prtena = 1;
35852 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
35853 + break;
35854 + case UHF_PORT_SUSPEND:
35855 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
35856 + "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
35857 +
35858 + if (core_if->power_down == 2) {
35859 + dwc_otg_host_hibernation_restore(core_if, 0, 0);
35860 + } else {
35861 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
35862 + dwc_mdelay(5);
35863 +
35864 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
35865 + hprt0.b.prtres = 1;
35866 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
35867 + hprt0.b.prtsusp = 0;
35868 + /* Clear Resume bit */
35869 + dwc_mdelay(100);
35870 + hprt0.b.prtres = 0;
35871 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
35872 + }
35873 + break;
35874 +#ifdef CONFIG_USB_DWC_OTG_LPM
35875 + case UHF_PORT_L1:
35876 + {
35877 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
35878 + glpmcfg_data_t lpmcfg = {.d32 = 0 };
35879 +
35880 + lpmcfg.d32 =
35881 + DWC_READ_REG32(&core_if->
35882 + core_global_regs->glpmcfg);
35883 + lpmcfg.b.en_utmi_sleep = 0;
35884 + lpmcfg.b.hird_thres &= (~(1 << 4));
35885 + lpmcfg.b.prt_sleep_sts = 1;
35886 + DWC_WRITE_REG32(&core_if->
35887 + core_global_regs->glpmcfg,
35888 + lpmcfg.d32);
35889 +
35890 + /* Clear Enbl_L1Gating bit. */
35891 + pcgcctl.b.enbl_sleep_gating = 1;
35892 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
35893 + 0);
35894 +
35895 + dwc_mdelay(5);
35896 +
35897 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
35898 + hprt0.b.prtres = 1;
35899 + DWC_WRITE_REG32(core_if->host_if->hprt0,
35900 + hprt0.d32);
35901 + /* This bit will be cleared in wakeup interrupt handle */
35902 + break;
35903 + }
35904 +#endif
35905 + case UHF_PORT_POWER:
35906 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
35907 + "ClearPortFeature USB_PORT_FEAT_POWER\n");
35908 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
35909 + hprt0.b.prtpwr = 0;
35910 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
35911 + break;
35912 + case UHF_PORT_INDICATOR:
35913 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
35914 + "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
35915 + /* Port inidicator not supported */
35916 + break;
35917 + case UHF_C_PORT_CONNECTION:
35918 + /* Clears drivers internal connect status change
35919 + * flag */
35920 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
35921 + "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
35922 + dwc_otg_hcd->flags.b.port_connect_status_change = 0;
35923 + break;
35924 + case UHF_C_PORT_RESET:
35925 + /* Clears the driver's internal Port Reset Change
35926 + * flag */
35927 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
35928 + "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
35929 + dwc_otg_hcd->flags.b.port_reset_change = 0;
35930 + break;
35931 + case UHF_C_PORT_ENABLE:
35932 + /* Clears the driver's internal Port
35933 + * Enable/Disable Change flag */
35934 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
35935 + "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
35936 + dwc_otg_hcd->flags.b.port_enable_change = 0;
35937 + break;
35938 + case UHF_C_PORT_SUSPEND:
35939 + /* Clears the driver's internal Port Suspend
35940 + * Change flag, which is set when resume signaling on
35941 + * the host port is complete */
35942 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
35943 + "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
35944 + dwc_otg_hcd->flags.b.port_suspend_change = 0;
35945 + break;
35946 +#ifdef CONFIG_USB_DWC_OTG_LPM
35947 + case UHF_C_PORT_L1:
35948 + dwc_otg_hcd->flags.b.port_l1_change = 0;
35949 + break;
35950 +#endif
35951 + case UHF_C_PORT_OVER_CURRENT:
35952 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
35953 + "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
35954 + dwc_otg_hcd->flags.b.port_over_current_change = 0;
35955 + break;
35956 + default:
35957 + retval = -DWC_E_INVALID;
35958 + DWC_ERROR("DWC OTG HCD - "
35959 + "ClearPortFeature request %xh "
35960 + "unknown or unsupported\n", wValue);
35961 + }
35962 + break;
35963 + case UCR_GET_HUB_DESCRIPTOR:
35964 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
35965 + "GetHubDescriptor\n");
35966 + hub_desc = (usb_hub_descriptor_t *) buf;
35967 + hub_desc->bDescLength = 9;
35968 + hub_desc->bDescriptorType = 0x29;
35969 + hub_desc->bNbrPorts = 1;
35970 + USETW(hub_desc->wHubCharacteristics, 0x08);
35971 + hub_desc->bPwrOn2PwrGood = 1;
35972 + hub_desc->bHubContrCurrent = 0;
35973 + hub_desc->DeviceRemovable[0] = 0;
35974 + hub_desc->DeviceRemovable[1] = 0xff;
35975 + break;
35976 + case UCR_GET_HUB_STATUS:
35977 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
35978 + "GetHubStatus\n");
35979 + DWC_MEMSET(buf, 0, 4);
35980 + break;
35981 + case UCR_GET_PORT_STATUS:
35982 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
35983 + "GetPortStatus wIndex = 0x%04x FLAGS=0x%08x\n",
35984 + wIndex, dwc_otg_hcd->flags.d32);
35985 + if (!wIndex || wIndex > 1)
35986 + goto error;
35987 +
35988 + port_status = 0;
35989 +
35990 + if (dwc_otg_hcd->flags.b.port_connect_status_change)
35991 + port_status |= (1 << UHF_C_PORT_CONNECTION);
35992 +
35993 + if (dwc_otg_hcd->flags.b.port_enable_change)
35994 + port_status |= (1 << UHF_C_PORT_ENABLE);
35995 +
35996 + if (dwc_otg_hcd->flags.b.port_suspend_change)
35997 + port_status |= (1 << UHF_C_PORT_SUSPEND);
35998 +
35999 + if (dwc_otg_hcd->flags.b.port_l1_change)
36000 + port_status |= (1 << UHF_C_PORT_L1);
36001 +
36002 + if (dwc_otg_hcd->flags.b.port_reset_change) {
36003 + port_status |= (1 << UHF_C_PORT_RESET);
36004 + }
36005 +
36006 + if (dwc_otg_hcd->flags.b.port_over_current_change) {
36007 + DWC_WARN("Overcurrent change detected\n");
36008 + port_status |= (1 << UHF_C_PORT_OVER_CURRENT);
36009 + }
36010 +
36011 + if (!dwc_otg_hcd->flags.b.port_connect_status) {
36012 + /*
36013 + * The port is disconnected, which means the core is
36014 + * either in device mode or it soon will be. Just
36015 + * return 0's for the remainder of the port status
36016 + * since the port register can't be read if the core
36017 + * is in device mode.
36018 + */
36019 + *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
36020 + break;
36021 + }
36022 +
36023 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
36024 + DWC_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32);
36025 +
36026 + if (hprt0.b.prtconnsts)
36027 + port_status |= (1 << UHF_PORT_CONNECTION);
36028 +
36029 + if (hprt0.b.prtena)
36030 + port_status |= (1 << UHF_PORT_ENABLE);
36031 +
36032 + if (hprt0.b.prtsusp)
36033 + port_status |= (1 << UHF_PORT_SUSPEND);
36034 +
36035 + if (hprt0.b.prtovrcurract)
36036 + port_status |= (1 << UHF_PORT_OVER_CURRENT);
36037 +
36038 + if (hprt0.b.prtrst)
36039 + port_status |= (1 << UHF_PORT_RESET);
36040 +
36041 + if (hprt0.b.prtpwr)
36042 + port_status |= (1 << UHF_PORT_POWER);
36043 +
36044 + if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
36045 + port_status |= (1 << UHF_PORT_HIGH_SPEED);
36046 + else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
36047 + port_status |= (1 << UHF_PORT_LOW_SPEED);
36048 +
36049 + if (hprt0.b.prttstctl)
36050 + port_status |= (1 << UHF_PORT_TEST);
36051 + if (dwc_otg_get_lpm_portsleepstatus(dwc_otg_hcd->core_if)) {
36052 + port_status |= (1 << UHF_PORT_L1);
36053 + }
36054 + /*
36055 + For Synopsys HW emulation of Power down wkup_control asserts the
36056 + hreset_n and prst_n on suspned. This causes the HPRT0 to be zero.
36057 + We intentionally tell the software that port is in L2Suspend state.
36058 + Only for STE.
36059 + */
36060 + if ((core_if->power_down == 2)
36061 + && (core_if->hibernation_suspend == 1)) {
36062 + port_status |= (1 << UHF_PORT_SUSPEND);
36063 + }
36064 + /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
36065 +
36066 + *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
36067 +
36068 + break;
36069 + case UCR_SET_HUB_FEATURE:
36070 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36071 + "SetHubFeature\n");
36072 + /* No HUB features supported */
36073 + break;
36074 + case UCR_SET_PORT_FEATURE:
36075 + if (wValue != UHF_PORT_TEST && (!wIndex || wIndex > 1))
36076 + goto error;
36077 +
36078 + if (!dwc_otg_hcd->flags.b.port_connect_status) {
36079 + /*
36080 + * The port is disconnected, which means the core is
36081 + * either in device mode or it soon will be. Just
36082 + * return without doing anything since the port
36083 + * register can't be written if the core is in device
36084 + * mode.
36085 + */
36086 + break;
36087 + }
36088 +
36089 + switch (wValue) {
36090 + case UHF_PORT_SUSPEND:
36091 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36092 + "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
36093 + if (dwc_otg_hcd_otg_port(dwc_otg_hcd) != wIndex) {
36094 + goto error;
36095 + }
36096 + if (core_if->power_down == 2) {
36097 + int timeout = 300;
36098 + dwc_irqflags_t flags;
36099 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36100 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
36101 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
36102 +#ifdef DWC_DEV_SRPCAP
36103 + int32_t otg_cap_param = core_if->core_params->otg_cap;
36104 +#endif
36105 + DWC_PRINTF("Preparing for complete power-off\n");
36106 +
36107 + /* Save registers before hibernation */
36108 + dwc_otg_save_global_regs(core_if);
36109 + dwc_otg_save_host_regs(core_if);
36110 +
36111 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36112 + hprt0.b.prtsusp = 1;
36113 + hprt0.b.prtena = 0;
36114 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36115 + /* Spin hprt0.b.prtsusp to became 1 */
36116 + do {
36117 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36118 + if (hprt0.b.prtsusp) {
36119 + break;
36120 + }
36121 + dwc_mdelay(1);
36122 + } while (--timeout);
36123 + if (!timeout) {
36124 + DWC_WARN("Suspend wasn't genereted\n");
36125 + }
36126 + dwc_udelay(10);
36127 +
36128 + /*
36129 + * We need to disable interrupts to prevent servicing of any IRQ
36130 + * during going to hibernation
36131 + */
36132 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
36133 + core_if->lx_state = DWC_OTG_L2;
36134 +#ifdef DWC_DEV_SRPCAP
36135 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36136 + hprt0.b.prtpwr = 0;
36137 + hprt0.b.prtena = 0;
36138 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36139 + hprt0.d32);
36140 +#endif
36141 + gusbcfg.d32 =
36142 + DWC_READ_REG32(&core_if->core_global_regs->
36143 + gusbcfg);
36144 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
36145 + /* ULPI interface */
36146 + /* Suspend the Phy Clock */
36147 + pcgcctl.d32 = 0;
36148 + pcgcctl.b.stoppclk = 1;
36149 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
36150 + pcgcctl.d32);
36151 + dwc_udelay(10);
36152 + gpwrdn.b.pmuactv = 1;
36153 + DWC_MODIFY_REG32(&core_if->
36154 + core_global_regs->
36155 + gpwrdn, 0, gpwrdn.d32);
36156 + } else {
36157 + /* UTMI+ Interface */
36158 + gpwrdn.b.pmuactv = 1;
36159 + DWC_MODIFY_REG32(&core_if->
36160 + core_global_regs->
36161 + gpwrdn, 0, gpwrdn.d32);
36162 + dwc_udelay(10);
36163 + pcgcctl.b.stoppclk = 1;
36164 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
36165 + dwc_udelay(10);
36166 + }
36167 +#ifdef DWC_DEV_SRPCAP
36168 + gpwrdn.d32 = 0;
36169 + gpwrdn.b.dis_vbus = 1;
36170 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36171 + gpwrdn, 0, gpwrdn.d32);
36172 +#endif
36173 + gpwrdn.d32 = 0;
36174 + gpwrdn.b.pmuintsel = 1;
36175 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36176 + gpwrdn, 0, gpwrdn.d32);
36177 + dwc_udelay(10);
36178 +
36179 + gpwrdn.d32 = 0;
36180 +#ifdef DWC_DEV_SRPCAP
36181 + gpwrdn.b.srp_det_msk = 1;
36182 +#endif
36183 + gpwrdn.b.disconn_det_msk = 1;
36184 + gpwrdn.b.lnstchng_msk = 1;
36185 + gpwrdn.b.sts_chngint_msk = 1;
36186 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36187 + gpwrdn, 0, gpwrdn.d32);
36188 + dwc_udelay(10);
36189 +
36190 + /* Enable Power Down Clamp and all interrupts in GPWRDN */
36191 + gpwrdn.d32 = 0;
36192 + gpwrdn.b.pwrdnclmp = 1;
36193 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36194 + gpwrdn, 0, gpwrdn.d32);
36195 + dwc_udelay(10);
36196 +
36197 + /* Switch off VDD */
36198 + gpwrdn.d32 = 0;
36199 + gpwrdn.b.pwrdnswtch = 1;
36200 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36201 + gpwrdn, 0, gpwrdn.d32);
36202 +
36203 +#ifdef DWC_DEV_SRPCAP
36204 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
36205 + {
36206 + core_if->pwron_timer_started = 1;
36207 + DWC_TIMER_SCHEDULE(core_if->pwron_timer, 6000 /* 6 secs */ );
36208 + }
36209 +#endif
36210 + /* Save gpwrdn register for further usage if stschng interrupt */
36211 + core_if->gr_backup->gpwrdn_local =
36212 + DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
36213 +
36214 + /* Set flag to indicate that we are in hibernation */
36215 + core_if->hibernation_suspend = 1;
36216 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock,flags);
36217 +
36218 + DWC_PRINTF("Host hibernation completed\n");
36219 + // Exit from case statement
36220 + break;
36221 +
36222 + }
36223 + if (dwc_otg_hcd_otg_port(dwc_otg_hcd) == wIndex &&
36224 + dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
36225 + gotgctl_data_t gotgctl = {.d32 = 0 };
36226 + gotgctl.b.hstsethnpen = 1;
36227 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36228 + gotgctl, 0, gotgctl.d32);
36229 + core_if->op_state = A_SUSPEND;
36230 + }
36231 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36232 + hprt0.b.prtsusp = 1;
36233 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36234 + {
36235 + dwc_irqflags_t flags;
36236 + /* Update lx_state */
36237 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
36238 + core_if->lx_state = DWC_OTG_L2;
36239 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
36240 + }
36241 + /* Suspend the Phy Clock */
36242 + {
36243 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36244 + pcgcctl.b.stoppclk = 1;
36245 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
36246 + pcgcctl.d32);
36247 + dwc_udelay(10);
36248 + }
36249 +
36250 + /* For HNP the bus must be suspended for at least 200ms. */
36251 + if (dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
36252 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36253 + pcgcctl.b.stoppclk = 1;
36254 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
36255 + dwc_mdelay(200);
36256 + }
36257 +
36258 + /** @todo - check how sw can wait for 1 sec to check asesvld??? */
36259 +#if 0 //vahrama !!!!!!!!!!!!!!!!!!
36260 + if (core_if->adp_enable) {
36261 + gotgctl_data_t gotgctl = {.d32 = 0 };
36262 + gpwrdn_data_t gpwrdn;
36263 +
36264 + while (gotgctl.b.asesvld == 1) {
36265 + gotgctl.d32 =
36266 + DWC_READ_REG32(&core_if->
36267 + core_global_regs->
36268 + gotgctl);
36269 + dwc_mdelay(100);
36270 + }
36271 +
36272 + /* Enable Power Down Logic */
36273 + gpwrdn.d32 = 0;
36274 + gpwrdn.b.pmuactv = 1;
36275 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36276 + gpwrdn, 0, gpwrdn.d32);
36277 +
36278 + /* Unmask SRP detected interrupt from Power Down Logic */
36279 + gpwrdn.d32 = 0;
36280 + gpwrdn.b.srp_det_msk = 1;
36281 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36282 + gpwrdn, 0, gpwrdn.d32);
36283 +
36284 + dwc_otg_adp_probe_start(core_if);
36285 + }
36286 +#endif
36287 + break;
36288 + case UHF_PORT_POWER:
36289 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36290 + "SetPortFeature - USB_PORT_FEAT_POWER\n");
36291 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36292 + hprt0.b.prtpwr = 1;
36293 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36294 + break;
36295 + case UHF_PORT_RESET:
36296 + if ((core_if->power_down == 2)
36297 + && (core_if->hibernation_suspend == 1)) {
36298 + /* If we are going to exit from Hibernated
36299 + * state via USB RESET.
36300 + */
36301 + dwc_otg_host_hibernation_restore(core_if, 0, 1);
36302 + } else {
36303 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36304 +
36305 + DWC_DEBUGPL(DBG_HCD,
36306 + "DWC OTG HCD HUB CONTROL - "
36307 + "SetPortFeature - USB_PORT_FEAT_RESET\n");
36308 + {
36309 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36310 + pcgcctl.b.enbl_sleep_gating = 1;
36311 + pcgcctl.b.stoppclk = 1;
36312 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
36313 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
36314 + }
36315 +#ifdef CONFIG_USB_DWC_OTG_LPM
36316 + {
36317 + glpmcfg_data_t lpmcfg;
36318 + lpmcfg.d32 =
36319 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
36320 + if (lpmcfg.b.prt_sleep_sts) {
36321 + lpmcfg.b.en_utmi_sleep = 0;
36322 + lpmcfg.b.hird_thres &= (~(1 << 4));
36323 + DWC_WRITE_REG32
36324 + (&core_if->core_global_regs->glpmcfg,
36325 + lpmcfg.d32);
36326 + dwc_mdelay(1);
36327 + }
36328 + }
36329 +#endif
36330 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36331 + /* Clear suspend bit if resetting from suspended state. */
36332 + hprt0.b.prtsusp = 0;
36333 + /* When B-Host the Port reset bit is set in
36334 + * the Start HCD Callback function, so that
36335 + * the reset is started within 1ms of the HNP
36336 + * success interrupt. */
36337 + if (!dwc_otg_hcd_is_b_host(dwc_otg_hcd)) {
36338 + hprt0.b.prtpwr = 1;
36339 + hprt0.b.prtrst = 1;
36340 + DWC_PRINTF("Indeed it is in host mode hprt0 = %08x\n",hprt0.d32);
36341 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36342 + hprt0.d32);
36343 + }
36344 + /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
36345 + dwc_mdelay(60);
36346 + hprt0.b.prtrst = 0;
36347 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36348 + core_if->lx_state = DWC_OTG_L0; /* Now back to the on state */
36349 + }
36350 + break;
36351 +#ifdef DWC_HS_ELECT_TST
36352 + case UHF_PORT_TEST:
36353 + {
36354 + uint32_t t;
36355 + gintmsk_data_t gintmsk;
36356 +
36357 + t = (wIndex >> 8); /* MSB wIndex USB */
36358 + DWC_DEBUGPL(DBG_HCD,
36359 + "DWC OTG HCD HUB CONTROL - "
36360 + "SetPortFeature - USB_PORT_FEAT_TEST %d\n",
36361 + t);
36362 + DWC_WARN("USB_PORT_FEAT_TEST %d\n", t);
36363 + if (t < 6) {
36364 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36365 + hprt0.b.prttstctl = t;
36366 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36367 + hprt0.d32);
36368 + } else {
36369 + /* Setup global vars with reg addresses (quick and
36370 + * dirty hack, should be cleaned up)
36371 + */
36372 + global_regs = core_if->core_global_regs;
36373 + hc_global_regs =
36374 + core_if->host_if->host_global_regs;
36375 + hc_regs =
36376 + (dwc_otg_hc_regs_t *) ((char *)
36377 + global_regs +
36378 + 0x500);
36379 + data_fifo =
36380 + (uint32_t *) ((char *)global_regs +
36381 + 0x1000);
36382 +
36383 + if (t == 6) { /* HS_HOST_PORT_SUSPEND_RESUME */
36384 + /* Save current interrupt mask */
36385 + gintmsk.d32 =
36386 + DWC_READ_REG32
36387 + (&global_regs->gintmsk);
36388 +
36389 + /* Disable all interrupts while we muck with
36390 + * the hardware directly
36391 + */
36392 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
36393 +
36394 + /* 15 second delay per the test spec */
36395 + dwc_mdelay(15000);
36396 +
36397 + /* Drive suspend on the root port */
36398 + hprt0.d32 =
36399 + dwc_otg_read_hprt0(core_if);
36400 + hprt0.b.prtsusp = 1;
36401 + hprt0.b.prtres = 0;
36402 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36403 +
36404 + /* 15 second delay per the test spec */
36405 + dwc_mdelay(15000);
36406 +
36407 + /* Drive resume on the root port */
36408 + hprt0.d32 =
36409 + dwc_otg_read_hprt0(core_if);
36410 + hprt0.b.prtsusp = 0;
36411 + hprt0.b.prtres = 1;
36412 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36413 + dwc_mdelay(100);
36414 +
36415 + /* Clear the resume bit */
36416 + hprt0.b.prtres = 0;
36417 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36418 +
36419 + /* Restore interrupts */
36420 + DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
36421 + } else if (t == 7) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
36422 + /* Save current interrupt mask */
36423 + gintmsk.d32 =
36424 + DWC_READ_REG32
36425 + (&global_regs->gintmsk);
36426 +
36427 + /* Disable all interrupts while we muck with
36428 + * the hardware directly
36429 + */
36430 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
36431 +
36432 + /* 15 second delay per the test spec */
36433 + dwc_mdelay(15000);
36434 +
36435 + /* Send the Setup packet */
36436 + do_setup();
36437 +
36438 + /* 15 second delay so nothing else happens for awhile */
36439 + dwc_mdelay(15000);
36440 +
36441 + /* Restore interrupts */
36442 + DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
36443 + } else if (t == 8) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
36444 + /* Save current interrupt mask */
36445 + gintmsk.d32 =
36446 + DWC_READ_REG32
36447 + (&global_regs->gintmsk);
36448 +
36449 + /* Disable all interrupts while we muck with
36450 + * the hardware directly
36451 + */
36452 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
36453 +
36454 + /* Send the Setup packet */
36455 + do_setup();
36456 +
36457 + /* 15 second delay so nothing else happens for awhile */
36458 + dwc_mdelay(15000);
36459 +
36460 + /* Send the In and Ack packets */
36461 + do_in_ack();
36462 +
36463 + /* 15 second delay so nothing else happens for awhile */
36464 + dwc_mdelay(15000);
36465 +
36466 + /* Restore interrupts */
36467 + DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
36468 + }
36469 + }
36470 + break;
36471 + }
36472 +#endif /* DWC_HS_ELECT_TST */
36473 +
36474 + case UHF_PORT_INDICATOR:
36475 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36476 + "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
36477 + /* Not supported */
36478 + break;
36479 + default:
36480 + retval = -DWC_E_INVALID;
36481 + DWC_ERROR("DWC OTG HCD - "
36482 + "SetPortFeature request %xh "
36483 + "unknown or unsupported\n", wValue);
36484 + break;
36485 + }
36486 + break;
36487 +#ifdef CONFIG_USB_DWC_OTG_LPM
36488 + case UCR_SET_AND_TEST_PORT_FEATURE:
36489 + if (wValue != UHF_PORT_L1) {
36490 + goto error;
36491 + }
36492 + {
36493 + int portnum, hird, devaddr, remwake;
36494 + glpmcfg_data_t lpmcfg;
36495 + uint32_t time_usecs;
36496 + gintsts_data_t gintsts;
36497 + gintmsk_data_t gintmsk;
36498 +
36499 + if (!dwc_otg_get_param_lpm_enable(core_if)) {
36500 + goto error;
36501 + }
36502 + if (wValue != UHF_PORT_L1 || wLength != 1) {
36503 + goto error;
36504 + }
36505 + /* Check if the port currently is in SLEEP state */
36506 + lpmcfg.d32 =
36507 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
36508 + if (lpmcfg.b.prt_sleep_sts) {
36509 + DWC_INFO("Port is already in sleep mode\n");
36510 + buf[0] = 0; /* Return success */
36511 + break;
36512 + }
36513 +
36514 + portnum = wIndex & 0xf;
36515 + hird = (wIndex >> 4) & 0xf;
36516 + devaddr = (wIndex >> 8) & 0x7f;
36517 + remwake = (wIndex >> 15);
36518 +
36519 + if (portnum != 1) {
36520 + retval = -DWC_E_INVALID;
36521 + DWC_WARN
36522 + ("Wrong port number(%d) in SetandTestPortFeature request\n",
36523 + portnum);
36524 + break;
36525 + }
36526 +
36527 + DWC_PRINTF
36528 + ("SetandTestPortFeature request: portnum = %d, hird = %d, devaddr = %d, rewake = %d\n",
36529 + portnum, hird, devaddr, remwake);
36530 + /* Disable LPM interrupt */
36531 + gintmsk.d32 = 0;
36532 + gintmsk.b.lpmtranrcvd = 1;
36533 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
36534 + gintmsk.d32, 0);
36535 +
36536 + if (dwc_otg_hcd_send_lpm
36537 + (dwc_otg_hcd, devaddr, hird, remwake)) {
36538 + retval = -DWC_E_INVALID;
36539 + break;
36540 + }
36541 +
36542 + time_usecs = 10 * (lpmcfg.b.retry_count + 1);
36543 + /* We will consider timeout if time_usecs microseconds pass,
36544 + * and we don't receive LPM transaction status.
36545 + * After receiving non-error responce(ACK/NYET/STALL) from device,
36546 + * core will set lpmtranrcvd bit.
36547 + */
36548 + do {
36549 + gintsts.d32 =
36550 + DWC_READ_REG32(&core_if->core_global_regs->gintsts);
36551 + if (gintsts.b.lpmtranrcvd) {
36552 + break;
36553 + }
36554 + dwc_udelay(1);
36555 + } while (--time_usecs);
36556 + /* lpm_int bit will be cleared in LPM interrupt handler */
36557 +
36558 + /* Now fill status
36559 + * 0x00 - Success
36560 + * 0x10 - NYET
36561 + * 0x11 - Timeout
36562 + */
36563 + if (!gintsts.b.lpmtranrcvd) {
36564 + buf[0] = 0x3; /* Completion code is Timeout */
36565 + dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd);
36566 + } else {
36567 + lpmcfg.d32 =
36568 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
36569 + if (lpmcfg.b.lpm_resp == 0x3) {
36570 + /* ACK responce from the device */
36571 + buf[0] = 0x00; /* Success */
36572 + } else if (lpmcfg.b.lpm_resp == 0x2) {
36573 + /* NYET responce from the device */
36574 + buf[0] = 0x2;
36575 + } else {
36576 + /* Otherwise responce with Timeout */
36577 + buf[0] = 0x3;
36578 + }
36579 + }
36580 + DWC_PRINTF("Device responce to LPM trans is %x\n",
36581 + lpmcfg.b.lpm_resp);
36582 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0,
36583 + gintmsk.d32);
36584 +
36585 + break;
36586 + }
36587 +#endif /* CONFIG_USB_DWC_OTG_LPM */
36588 + default:
36589 +error:
36590 + retval = -DWC_E_INVALID;
36591 + DWC_WARN("DWC OTG HCD - "
36592 + "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
36593 + typeReq, wIndex, wValue);
36594 + break;
36595 + }
36596 +
36597 + return retval;
36598 +}
36599 +
36600 +#ifdef CONFIG_USB_DWC_OTG_LPM
36601 +/** Returns index of host channel to perform LPM transaction. */
36602 +int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, uint8_t devaddr)
36603 +{
36604 + dwc_otg_core_if_t *core_if = hcd->core_if;
36605 + dwc_hc_t *hc;
36606 + hcchar_data_t hcchar;
36607 + gintmsk_data_t gintmsk = {.d32 = 0 };
36608 +
36609 + if (DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
36610 + DWC_PRINTF("No free channel to select for LPM transaction\n");
36611 + return -1;
36612 + }
36613 +
36614 + hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
36615 +
36616 + /* Mask host channel interrupts. */
36617 + gintmsk.b.hcintr = 1;
36618 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
36619 +
36620 + /* Fill fields that core needs for LPM transaction */
36621 + hcchar.b.devaddr = devaddr;
36622 + hcchar.b.epnum = 0;
36623 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
36624 + hcchar.b.mps = 64;
36625 + hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
36626 + hcchar.b.epdir = 0; /* OUT */
36627 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[hc->hc_num]->hcchar,
36628 + hcchar.d32);
36629 +
36630 + /* Remove the host channel from the free list. */
36631 + DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
36632 +
36633 + DWC_PRINTF("hcnum = %d devaddr = %d\n", hc->hc_num, devaddr);
36634 +
36635 + return hc->hc_num;
36636 +}
36637 +
36638 +/** Release hc after performing LPM transaction */
36639 +void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd)
36640 +{
36641 + dwc_hc_t *hc;
36642 + glpmcfg_data_t lpmcfg;
36643 + uint8_t hc_num;
36644 +
36645 + lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
36646 + hc_num = lpmcfg.b.lpm_chan_index;
36647 +
36648 + hc = hcd->hc_ptr_array[hc_num];
36649 +
36650 + DWC_PRINTF("Freeing channel %d after LPM\n", hc_num);
36651 + /* Return host channel to free list */
36652 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
36653 +}
36654 +
36655 +int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, uint8_t hird,
36656 + uint8_t bRemoteWake)
36657 +{
36658 + glpmcfg_data_t lpmcfg;
36659 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36660 + int channel;
36661 +
36662 + channel = dwc_otg_hcd_get_hc_for_lpm_tran(hcd, devaddr);
36663 + if (channel < 0) {
36664 + return channel;
36665 + }
36666 +
36667 + pcgcctl.b.enbl_sleep_gating = 1;
36668 + DWC_MODIFY_REG32(hcd->core_if->pcgcctl, 0, pcgcctl.d32);
36669 +
36670 + /* Read LPM config register */
36671 + lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
36672 +
36673 + /* Program LPM transaction fields */
36674 + lpmcfg.b.rem_wkup_en = bRemoteWake;
36675 + lpmcfg.b.hird = hird;
36676 + lpmcfg.b.hird_thres = 0x1c;
36677 + lpmcfg.b.lpm_chan_index = channel;
36678 + lpmcfg.b.en_utmi_sleep = 1;
36679 + /* Program LPM config register */
36680 + DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
36681 +
36682 + /* Send LPM transaction */
36683 + lpmcfg.b.send_lpm = 1;
36684 + DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
36685 +
36686 + return 0;
36687 +}
36688 +
36689 +#endif /* CONFIG_USB_DWC_OTG_LPM */
36690 +
36691 +int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port)
36692 +{
36693 + int retval;
36694 +
36695 + if (port != 1) {
36696 + return -DWC_E_INVALID;
36697 + }
36698 +
36699 + retval = (hcd->flags.b.port_connect_status_change ||
36700 + hcd->flags.b.port_reset_change ||
36701 + hcd->flags.b.port_enable_change ||
36702 + hcd->flags.b.port_suspend_change ||
36703 + hcd->flags.b.port_over_current_change);
36704 +#ifdef DEBUG
36705 + if (retval) {
36706 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:"
36707 + " Root port status changed\n");
36708 + DWC_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n",
36709 + hcd->flags.b.port_connect_status_change);
36710 + DWC_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n",
36711 + hcd->flags.b.port_reset_change);
36712 + DWC_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n",
36713 + hcd->flags.b.port_enable_change);
36714 + DWC_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n",
36715 + hcd->flags.b.port_suspend_change);
36716 + DWC_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n",
36717 + hcd->flags.b.port_over_current_change);
36718 + }
36719 +#endif
36720 + return retval;
36721 +}
36722 +
36723 +int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * dwc_otg_hcd)
36724 +{
36725 + hfnum_data_t hfnum;
36726 + hfnum.d32 =
36727 + DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->
36728 + hfnum);
36729 +
36730 +#ifdef DEBUG_SOF
36731 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n",
36732 + hfnum.b.frnum);
36733 +#endif
36734 + return hfnum.b.frnum;
36735 +}
36736 +
36737 +int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
36738 + struct dwc_otg_hcd_function_ops *fops)
36739 +{
36740 + int retval = 0;
36741 +
36742 + hcd->fops = fops;
36743 + if (!dwc_otg_is_device_mode(hcd->core_if) &&
36744 + (!hcd->core_if->adp_enable || hcd->core_if->adp.adp_started)) {
36745 + dwc_otg_hcd_reinit(hcd);
36746 + } else {
36747 + retval = -DWC_E_NO_DEVICE;
36748 + }
36749 +
36750 + return retval;
36751 +}
36752 +
36753 +void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd)
36754 +{
36755 + return hcd->priv;
36756 +}
36757 +
36758 +void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data)
36759 +{
36760 + hcd->priv = priv_data;
36761 +}
36762 +
36763 +uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd)
36764 +{
36765 + return hcd->otg_port;
36766 +}
36767 +
36768 +uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd)
36769 +{
36770 + uint32_t is_b_host;
36771 + if (hcd->core_if->op_state == B_HOST) {
36772 + is_b_host = 1;
36773 + } else {
36774 + is_b_host = 0;
36775 + }
36776 +
36777 + return is_b_host;
36778 +}
36779 +
36780 +dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
36781 + int iso_desc_count, int atomic_alloc)
36782 +{
36783 + dwc_otg_hcd_urb_t *dwc_otg_urb;
36784 + uint32_t size;
36785 +
36786 + size =
36787 + sizeof(*dwc_otg_urb) +
36788 + iso_desc_count * sizeof(struct dwc_otg_hcd_iso_packet_desc);
36789 + if (atomic_alloc)
36790 + dwc_otg_urb = DWC_ALLOC_ATOMIC(size);
36791 + else
36792 + dwc_otg_urb = DWC_ALLOC(size);
36793 +
36794 + if (dwc_otg_urb)
36795 + dwc_otg_urb->packet_count = iso_desc_count;
36796 + else {
36797 + DWC_ERROR("**** DWC OTG HCD URB alloc - "
36798 + "%salloc of %db failed\n",
36799 + atomic_alloc?"atomic ":"", size);
36800 + }
36801 + return dwc_otg_urb;
36802 +}
36803 +
36804 +void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * dwc_otg_urb,
36805 + uint8_t dev_addr, uint8_t ep_num,
36806 + uint8_t ep_type, uint8_t ep_dir, uint16_t mps)
36807 +{
36808 + dwc_otg_hcd_fill_pipe(&dwc_otg_urb->pipe_info, dev_addr, ep_num,
36809 + ep_type, ep_dir, mps);
36810 +#if 0
36811 + DWC_PRINTF
36812 + ("addr = %d, ep_num = %d, ep_dir = 0x%x, ep_type = 0x%x, mps = %d\n",
36813 + dev_addr, ep_num, ep_dir, ep_type, mps);
36814 +#endif
36815 +}
36816 +
36817 +void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
36818 + void *urb_handle, void *buf, dwc_dma_t dma,
36819 + uint32_t buflen, void *setup_packet,
36820 + dwc_dma_t setup_dma, uint32_t flags,
36821 + uint16_t interval)
36822 +{
36823 + dwc_otg_urb->priv = urb_handle;
36824 + dwc_otg_urb->buf = buf;
36825 + dwc_otg_urb->dma = dma;
36826 + dwc_otg_urb->length = buflen;
36827 + dwc_otg_urb->setup_packet = setup_packet;
36828 + dwc_otg_urb->setup_dma = setup_dma;
36829 + dwc_otg_urb->flags = flags;
36830 + dwc_otg_urb->interval = interval;
36831 + dwc_otg_urb->status = -DWC_E_IN_PROGRESS;
36832 +}
36833 +
36834 +uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb)
36835 +{
36836 + return dwc_otg_urb->status;
36837 +}
36838 +
36839 +uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * dwc_otg_urb)
36840 +{
36841 + return dwc_otg_urb->actual_length;
36842 +}
36843 +
36844 +uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * dwc_otg_urb)
36845 +{
36846 + return dwc_otg_urb->error_count;
36847 +}
36848 +
36849 +void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
36850 + int desc_num, uint32_t offset,
36851 + uint32_t length)
36852 +{
36853 + dwc_otg_urb->iso_descs[desc_num].offset = offset;
36854 + dwc_otg_urb->iso_descs[desc_num].length = length;
36855 +}
36856 +
36857 +uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * dwc_otg_urb,
36858 + int desc_num)
36859 +{
36860 + return dwc_otg_urb->iso_descs[desc_num].status;
36861 +}
36862 +
36863 +uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
36864 + dwc_otg_urb, int desc_num)
36865 +{
36866 + return dwc_otg_urb->iso_descs[desc_num].actual_length;
36867 +}
36868 +
36869 +int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, void *ep_handle)
36870 +{
36871 + int allocated = 0;
36872 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
36873 +
36874 + if (qh) {
36875 + if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
36876 + allocated = 1;
36877 + }
36878 + }
36879 + return allocated;
36880 +}
36881 +
36882 +int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle)
36883 +{
36884 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
36885 + int freed = 0;
36886 + DWC_ASSERT(qh, "qh is not allocated\n");
36887 +
36888 + if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
36889 + freed = 1;
36890 + }
36891 +
36892 + return freed;
36893 +}
36894 +
36895 +uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, void *ep_handle)
36896 +{
36897 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
36898 + DWC_ASSERT(qh, "qh is not allocated\n");
36899 + return qh->usecs;
36900 +}
36901 +
36902 +void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd)
36903 +{
36904 +#ifdef DEBUG
36905 + int num_channels;
36906 + int i;
36907 + gnptxsts_data_t np_tx_status;
36908 + hptxsts_data_t p_tx_status;
36909 +
36910 + num_channels = hcd->core_if->core_params->host_channels;
36911 + DWC_PRINTF("\n");
36912 + DWC_PRINTF
36913 + ("************************************************************\n");
36914 + DWC_PRINTF("HCD State:\n");
36915 + DWC_PRINTF(" Num channels: %d\n", num_channels);
36916 + for (i = 0; i < num_channels; i++) {
36917 + dwc_hc_t *hc = hcd->hc_ptr_array[i];
36918 + DWC_PRINTF(" Channel %d:\n", i);
36919 + DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
36920 + hc->dev_addr, hc->ep_num, hc->ep_is_in);
36921 + DWC_PRINTF(" speed: %d\n", hc->speed);
36922 + DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
36923 + DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
36924 + DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
36925 + DWC_PRINTF(" multi_count: %d\n", hc->multi_count);
36926 + DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
36927 + DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
36928 + DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
36929 + DWC_PRINTF(" xfer_count: %d\n", hc->xfer_count);
36930 + DWC_PRINTF(" halt_on_queue: %d\n", hc->halt_on_queue);
36931 + DWC_PRINTF(" halt_pending: %d\n", hc->halt_pending);
36932 + DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
36933 + DWC_PRINTF(" do_split: %d\n", hc->do_split);
36934 + DWC_PRINTF(" complete_split: %d\n", hc->complete_split);
36935 + DWC_PRINTF(" hub_addr: %d\n", hc->hub_addr);
36936 + DWC_PRINTF(" port_addr: %d\n", hc->port_addr);
36937 + DWC_PRINTF(" xact_pos: %d\n", hc->xact_pos);
36938 + DWC_PRINTF(" requests: %d\n", hc->requests);
36939 + DWC_PRINTF(" qh: %p\n", hc->qh);
36940 + if (hc->xfer_started) {
36941 + hfnum_data_t hfnum;
36942 + hcchar_data_t hcchar;
36943 + hctsiz_data_t hctsiz;
36944 + hcint_data_t hcint;
36945 + hcintmsk_data_t hcintmsk;
36946 + hfnum.d32 =
36947 + DWC_READ_REG32(&hcd->core_if->
36948 + host_if->host_global_regs->hfnum);
36949 + hcchar.d32 =
36950 + DWC_READ_REG32(&hcd->core_if->host_if->
36951 + hc_regs[i]->hcchar);
36952 + hctsiz.d32 =
36953 + DWC_READ_REG32(&hcd->core_if->host_if->
36954 + hc_regs[i]->hctsiz);
36955 + hcint.d32 =
36956 + DWC_READ_REG32(&hcd->core_if->host_if->
36957 + hc_regs[i]->hcint);
36958 + hcintmsk.d32 =
36959 + DWC_READ_REG32(&hcd->core_if->host_if->
36960 + hc_regs[i]->hcintmsk);
36961 + DWC_PRINTF(" hfnum: 0x%08x\n", hfnum.d32);
36962 + DWC_PRINTF(" hcchar: 0x%08x\n", hcchar.d32);
36963 + DWC_PRINTF(" hctsiz: 0x%08x\n", hctsiz.d32);
36964 + DWC_PRINTF(" hcint: 0x%08x\n", hcint.d32);
36965 + DWC_PRINTF(" hcintmsk: 0x%08x\n", hcintmsk.d32);
36966 + }
36967 + if (hc->xfer_started && hc->qh) {
36968 + dwc_otg_qtd_t *qtd;
36969 + dwc_otg_hcd_urb_t *urb;
36970 +
36971 + DWC_CIRCLEQ_FOREACH(qtd, &hc->qh->qtd_list, qtd_list_entry) {
36972 + if (!qtd->in_process)
36973 + break;
36974 +
36975 + urb = qtd->urb;
36976 + DWC_PRINTF(" URB Info:\n");
36977 + DWC_PRINTF(" qtd: %p, urb: %p\n", qtd, urb);
36978 + if (urb) {
36979 + DWC_PRINTF(" Dev: %d, EP: %d %s\n",
36980 + dwc_otg_hcd_get_dev_addr(&urb->
36981 + pipe_info),
36982 + dwc_otg_hcd_get_ep_num(&urb->
36983 + pipe_info),
36984 + dwc_otg_hcd_is_pipe_in(&urb->
36985 + pipe_info) ?
36986 + "IN" : "OUT");
36987 + DWC_PRINTF(" Max packet size: %d\n",
36988 + dwc_otg_hcd_get_mps(&urb->
36989 + pipe_info));
36990 + DWC_PRINTF(" transfer_buffer: %p\n",
36991 + urb->buf);
36992 + DWC_PRINTF(" transfer_dma: %p\n",
36993 + (void *)urb->dma);
36994 + DWC_PRINTF(" transfer_buffer_length: %d\n",
36995 + urb->length);
36996 + DWC_PRINTF(" actual_length: %d\n",
36997 + urb->actual_length);
36998 + }
36999 + }
37000 + }
37001 + }
37002 + DWC_PRINTF(" non_periodic_channels: %d\n", hcd->non_periodic_channels);
37003 + DWC_PRINTF(" periodic_channels: %d\n", hcd->periodic_channels);
37004 + DWC_PRINTF(" periodic_usecs: %d\n", hcd->periodic_usecs);
37005 + np_tx_status.d32 =
37006 + DWC_READ_REG32(&hcd->core_if->core_global_regs->gnptxsts);
37007 + DWC_PRINTF(" NP Tx Req Queue Space Avail: %d\n",
37008 + np_tx_status.b.nptxqspcavail);
37009 + DWC_PRINTF(" NP Tx FIFO Space Avail: %d\n",
37010 + np_tx_status.b.nptxfspcavail);
37011 + p_tx_status.d32 =
37012 + DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hptxsts);
37013 + DWC_PRINTF(" P Tx Req Queue Space Avail: %d\n",
37014 + p_tx_status.b.ptxqspcavail);
37015 + DWC_PRINTF(" P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail);
37016 + dwc_otg_hcd_dump_frrem(hcd);
37017 + dwc_otg_dump_global_registers(hcd->core_if);
37018 + dwc_otg_dump_host_registers(hcd->core_if);
37019 + DWC_PRINTF
37020 + ("************************************************************\n");
37021 + DWC_PRINTF("\n");
37022 +#endif
37023 +}
37024 +
37025 +#ifdef DEBUG
37026 +void dwc_print_setup_data(uint8_t * setup)
37027 +{
37028 + int i;
37029 + if (CHK_DEBUG_LEVEL(DBG_HCD)) {
37030 + DWC_PRINTF("Setup Data = MSB ");
37031 + for (i = 7; i >= 0; i--)
37032 + DWC_PRINTF("%02x ", setup[i]);
37033 + DWC_PRINTF("\n");
37034 + DWC_PRINTF(" bmRequestType Tranfer = %s\n",
37035 + (setup[0] & 0x80) ? "Device-to-Host" :
37036 + "Host-to-Device");
37037 + DWC_PRINTF(" bmRequestType Type = ");
37038 + switch ((setup[0] & 0x60) >> 5) {
37039 + case 0:
37040 + DWC_PRINTF("Standard\n");
37041 + break;
37042 + case 1:
37043 + DWC_PRINTF("Class\n");
37044 + break;
37045 + case 2:
37046 + DWC_PRINTF("Vendor\n");
37047 + break;
37048 + case 3:
37049 + DWC_PRINTF("Reserved\n");
37050 + break;
37051 + }
37052 + DWC_PRINTF(" bmRequestType Recipient = ");
37053 + switch (setup[0] & 0x1f) {
37054 + case 0:
37055 + DWC_PRINTF("Device\n");
37056 + break;
37057 + case 1:
37058 + DWC_PRINTF("Interface\n");
37059 + break;
37060 + case 2:
37061 + DWC_PRINTF("Endpoint\n");
37062 + break;
37063 + case 3:
37064 + DWC_PRINTF("Other\n");
37065 + break;
37066 + default:
37067 + DWC_PRINTF("Reserved\n");
37068 + break;
37069 + }
37070 + DWC_PRINTF(" bRequest = 0x%0x\n", setup[1]);
37071 + DWC_PRINTF(" wValue = 0x%0x\n", *((uint16_t *) & setup[2]));
37072 + DWC_PRINTF(" wIndex = 0x%0x\n", *((uint16_t *) & setup[4]));
37073 + DWC_PRINTF(" wLength = 0x%0x\n\n", *((uint16_t *) & setup[6]));
37074 + }
37075 +}
37076 +#endif
37077 +
37078 +void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd)
37079 +{
37080 +#if 0
37081 + DWC_PRINTF("Frame remaining at SOF:\n");
37082 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37083 + hcd->frrem_samples, hcd->frrem_accum,
37084 + (hcd->frrem_samples > 0) ?
37085 + hcd->frrem_accum / hcd->frrem_samples : 0);
37086 +
37087 + DWC_PRINTF("\n");
37088 + DWC_PRINTF("Frame remaining at start_transfer (uframe 7):\n");
37089 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37090 + hcd->core_if->hfnum_7_samples,
37091 + hcd->core_if->hfnum_7_frrem_accum,
37092 + (hcd->core_if->hfnum_7_samples >
37093 + 0) ? hcd->core_if->hfnum_7_frrem_accum /
37094 + hcd->core_if->hfnum_7_samples : 0);
37095 + DWC_PRINTF("Frame remaining at start_transfer (uframe 0):\n");
37096 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37097 + hcd->core_if->hfnum_0_samples,
37098 + hcd->core_if->hfnum_0_frrem_accum,
37099 + (hcd->core_if->hfnum_0_samples >
37100 + 0) ? hcd->core_if->hfnum_0_frrem_accum /
37101 + hcd->core_if->hfnum_0_samples : 0);
37102 + DWC_PRINTF("Frame remaining at start_transfer (uframe 1-6):\n");
37103 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37104 + hcd->core_if->hfnum_other_samples,
37105 + hcd->core_if->hfnum_other_frrem_accum,
37106 + (hcd->core_if->hfnum_other_samples >
37107 + 0) ? hcd->core_if->hfnum_other_frrem_accum /
37108 + hcd->core_if->hfnum_other_samples : 0);
37109 +
37110 + DWC_PRINTF("\n");
37111 + DWC_PRINTF("Frame remaining at sample point A (uframe 7):\n");
37112 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37113 + hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a,
37114 + (hcd->hfnum_7_samples_a > 0) ?
37115 + hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0);
37116 + DWC_PRINTF("Frame remaining at sample point A (uframe 0):\n");
37117 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37118 + hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a,
37119 + (hcd->hfnum_0_samples_a > 0) ?
37120 + hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0);
37121 + DWC_PRINTF("Frame remaining at sample point A (uframe 1-6):\n");
37122 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37123 + hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a,
37124 + (hcd->hfnum_other_samples_a > 0) ?
37125 + hcd->hfnum_other_frrem_accum_a /
37126 + hcd->hfnum_other_samples_a : 0);
37127 +
37128 + DWC_PRINTF("\n");
37129 + DWC_PRINTF("Frame remaining at sample point B (uframe 7):\n");
37130 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37131 + hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b,
37132 + (hcd->hfnum_7_samples_b > 0) ?
37133 + hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0);
37134 + DWC_PRINTF("Frame remaining at sample point B (uframe 0):\n");
37135 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37136 + hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b,
37137 + (hcd->hfnum_0_samples_b > 0) ?
37138 + hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0);
37139 + DWC_PRINTF("Frame remaining at sample point B (uframe 1-6):\n");
37140 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37141 + hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b,
37142 + (hcd->hfnum_other_samples_b > 0) ?
37143 + hcd->hfnum_other_frrem_accum_b /
37144 + hcd->hfnum_other_samples_b : 0);
37145 +#endif
37146 +}
37147 +
37148 +#endif /* DWC_DEVICE_ONLY */
37149 --- /dev/null
37150 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
37151 @@ -0,0 +1,1132 @@
37152 +/*==========================================================================
37153 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_ddma.c $
37154 + * $Revision: #10 $
37155 + * $Date: 2011/10/20 $
37156 + * $Change: 1869464 $
37157 + *
37158 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
37159 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
37160 + * otherwise expressly agreed to in writing between Synopsys and you.
37161 + *
37162 + * The Software IS NOT an item of Licensed Software or Licensed Product under
37163 + * any End User Software License Agreement or Agreement for Licensed Product
37164 + * with Synopsys or any supplement thereto. You are permitted to use and
37165 + * redistribute this Software in source and binary forms, with or without
37166 + * modification, provided that redistributions of source code must retain this
37167 + * notice. You may not view, use, disclose, copy or distribute this file or
37168 + * any information contained herein except pursuant to this license grant from
37169 + * Synopsys. If you do not agree with this notice, including the disclaimer
37170 + * below, then you are not authorized to use the Software.
37171 + *
37172 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
37173 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37174 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37175 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
37176 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37177 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
37178 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
37179 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37180 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37181 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
37182 + * DAMAGE.
37183 + * ========================================================================== */
37184 +#ifndef DWC_DEVICE_ONLY
37185 +
37186 +/** @file
37187 + * This file contains Descriptor DMA support implementation for host mode.
37188 + */
37189 +
37190 +#include "dwc_otg_hcd.h"
37191 +#include "dwc_otg_regs.h"
37192 +
37193 +extern bool microframe_schedule;
37194 +
37195 +static inline uint8_t frame_list_idx(uint16_t frame)
37196 +{
37197 + return (frame & (MAX_FRLIST_EN_NUM - 1));
37198 +}
37199 +
37200 +static inline uint16_t desclist_idx_inc(uint16_t idx, uint16_t inc, uint8_t speed)
37201 +{
37202 + return (idx + inc) &
37203 + (((speed ==
37204 + DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
37205 + MAX_DMA_DESC_NUM_GENERIC) - 1);
37206 +}
37207 +
37208 +static inline uint16_t desclist_idx_dec(uint16_t idx, uint16_t inc, uint8_t speed)
37209 +{
37210 + return (idx - inc) &
37211 + (((speed ==
37212 + DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
37213 + MAX_DMA_DESC_NUM_GENERIC) - 1);
37214 +}
37215 +
37216 +static inline uint16_t max_desc_num(dwc_otg_qh_t * qh)
37217 +{
37218 + return (((qh->ep_type == UE_ISOCHRONOUS)
37219 + && (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH))
37220 + ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC);
37221 +}
37222 +static inline uint16_t frame_incr_val(dwc_otg_qh_t * qh)
37223 +{
37224 + return ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH)
37225 + ? ((qh->interval + 8 - 1) / 8)
37226 + : qh->interval);
37227 +}
37228 +
37229 +static int desc_list_alloc(dwc_otg_qh_t * qh)
37230 +{
37231 + int retval = 0;
37232 +
37233 + qh->desc_list = (dwc_otg_host_dma_desc_t *)
37234 + DWC_DMA_ALLOC(sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh),
37235 + &qh->desc_list_dma);
37236 +
37237 + if (!qh->desc_list) {
37238 + retval = -DWC_E_NO_MEMORY;
37239 + DWC_ERROR("%s: DMA descriptor list allocation failed\n", __func__);
37240 +
37241 + }
37242 +
37243 + dwc_memset(qh->desc_list, 0x00,
37244 + sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
37245 +
37246 + qh->n_bytes =
37247 + (uint32_t *) DWC_ALLOC(sizeof(uint32_t) * max_desc_num(qh));
37248 +
37249 + if (!qh->n_bytes) {
37250 + retval = -DWC_E_NO_MEMORY;
37251 + DWC_ERROR
37252 + ("%s: Failed to allocate array for descriptors' size actual values\n",
37253 + __func__);
37254 +
37255 + }
37256 + return retval;
37257 +
37258 +}
37259 +
37260 +static void desc_list_free(dwc_otg_qh_t * qh)
37261 +{
37262 + if (qh->desc_list) {
37263 + DWC_DMA_FREE(max_desc_num(qh), qh->desc_list,
37264 + qh->desc_list_dma);
37265 + qh->desc_list = NULL;
37266 + }
37267 +
37268 + if (qh->n_bytes) {
37269 + DWC_FREE(qh->n_bytes);
37270 + qh->n_bytes = NULL;
37271 + }
37272 +}
37273 +
37274 +static int frame_list_alloc(dwc_otg_hcd_t * hcd)
37275 +{
37276 + int retval = 0;
37277 + if (hcd->frame_list)
37278 + return 0;
37279 +
37280 + hcd->frame_list = DWC_DMA_ALLOC(4 * MAX_FRLIST_EN_NUM,
37281 + &hcd->frame_list_dma);
37282 + if (!hcd->frame_list) {
37283 + retval = -DWC_E_NO_MEMORY;
37284 + DWC_ERROR("%s: Frame List allocation failed\n", __func__);
37285 + }
37286 +
37287 + dwc_memset(hcd->frame_list, 0x00, 4 * MAX_FRLIST_EN_NUM);
37288 +
37289 + return retval;
37290 +}
37291 +
37292 +static void frame_list_free(dwc_otg_hcd_t * hcd)
37293 +{
37294 + if (!hcd->frame_list)
37295 + return;
37296 +
37297 + DWC_DMA_FREE(4 * MAX_FRLIST_EN_NUM, hcd->frame_list, hcd->frame_list_dma);
37298 + hcd->frame_list = NULL;
37299 +}
37300 +
37301 +static void per_sched_enable(dwc_otg_hcd_t * hcd, uint16_t fr_list_en)
37302 +{
37303 +
37304 + hcfg_data_t hcfg;
37305 +
37306 + hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
37307 +
37308 + if (hcfg.b.perschedena) {
37309 + /* already enabled */
37310 + return;
37311 + }
37312 +
37313 + DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hflbaddr,
37314 + hcd->frame_list_dma);
37315 +
37316 + switch (fr_list_en) {
37317 + case 64:
37318 + hcfg.b.frlisten = 3;
37319 + break;
37320 + case 32:
37321 + hcfg.b.frlisten = 2;
37322 + break;
37323 + case 16:
37324 + hcfg.b.frlisten = 1;
37325 + break;
37326 + case 8:
37327 + hcfg.b.frlisten = 0;
37328 + break;
37329 + default:
37330 + break;
37331 + }
37332 +
37333 + hcfg.b.perschedena = 1;
37334 +
37335 + DWC_DEBUGPL(DBG_HCD, "Enabling Periodic schedule\n");
37336 + DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
37337 +
37338 +}
37339 +
37340 +static void per_sched_disable(dwc_otg_hcd_t * hcd)
37341 +{
37342 + hcfg_data_t hcfg;
37343 +
37344 + hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
37345 +
37346 + if (!hcfg.b.perschedena) {
37347 + /* already disabled */
37348 + return;
37349 + }
37350 + hcfg.b.perschedena = 0;
37351 +
37352 + DWC_DEBUGPL(DBG_HCD, "Disabling Periodic schedule\n");
37353 + DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
37354 +}
37355 +
37356 +/*
37357 + * Activates/Deactivates FrameList entries for the channel
37358 + * based on endpoint servicing period.
37359 + */
37360 +void update_frame_list(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t enable)
37361 +{
37362 + uint16_t i, j, inc;
37363 + dwc_hc_t *hc = NULL;
37364 +
37365 + if (!qh->channel) {
37366 + DWC_ERROR("qh->channel = %p", qh->channel);
37367 + return;
37368 + }
37369 +
37370 + if (!hcd) {
37371 + DWC_ERROR("------hcd = %p", hcd);
37372 + return;
37373 + }
37374 +
37375 + if (!hcd->frame_list) {
37376 + DWC_ERROR("-------hcd->frame_list = %p", hcd->frame_list);
37377 + return;
37378 + }
37379 +
37380 + hc = qh->channel;
37381 + inc = frame_incr_val(qh);
37382 + if (qh->ep_type == UE_ISOCHRONOUS)
37383 + i = frame_list_idx(qh->sched_frame);
37384 + else
37385 + i = 0;
37386 +
37387 + j = i;
37388 + do {
37389 + if (enable)
37390 + hcd->frame_list[j] |= (1 << hc->hc_num);
37391 + else
37392 + hcd->frame_list[j] &= ~(1 << hc->hc_num);
37393 + j = (j + inc) & (MAX_FRLIST_EN_NUM - 1);
37394 + }
37395 + while (j != i);
37396 + if (!enable)
37397 + return;
37398 + hc->schinfo = 0;
37399 + if (qh->channel->speed == DWC_OTG_EP_SPEED_HIGH) {
37400 + j = 1;
37401 + /* TODO - check this */
37402 + inc = (8 + qh->interval - 1) / qh->interval;
37403 + for (i = 0; i < inc; i++) {
37404 + hc->schinfo |= j;
37405 + j = j << qh->interval;
37406 + }
37407 + } else {
37408 + hc->schinfo = 0xff;
37409 + }
37410 +}
37411 +
37412 +#if 1
37413 +void dump_frame_list(dwc_otg_hcd_t * hcd)
37414 +{
37415 + int i = 0;
37416 + DWC_PRINTF("--FRAME LIST (hex) --\n");
37417 + for (i = 0; i < MAX_FRLIST_EN_NUM; i++) {
37418 + DWC_PRINTF("%x\t", hcd->frame_list[i]);
37419 + if (!(i % 8) && i)
37420 + DWC_PRINTF("\n");
37421 + }
37422 + DWC_PRINTF("\n----\n");
37423 +
37424 +}
37425 +#endif
37426 +
37427 +static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
37428 +{
37429 + dwc_irqflags_t flags;
37430 + dwc_spinlock_t *channel_lock = hcd->channel_lock;
37431 +
37432 + dwc_hc_t *hc = qh->channel;
37433 + if (dwc_qh_is_non_per(qh)) {
37434 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
37435 + if (!microframe_schedule)
37436 + hcd->non_periodic_channels--;
37437 + else
37438 + hcd->available_host_channels++;
37439 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
37440 + } else
37441 + update_frame_list(hcd, qh, 0);
37442 +
37443 + /*
37444 + * The condition is added to prevent double cleanup try in case of device
37445 + * disconnect. See channel cleanup in dwc_otg_hcd_disconnect_cb().
37446 + */
37447 + if (hc->qh) {
37448 + dwc_otg_hc_cleanup(hcd->core_if, hc);
37449 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
37450 + hc->qh = NULL;
37451 + }
37452 +
37453 + qh->channel = NULL;
37454 + qh->ntd = 0;
37455 +
37456 + if (qh->desc_list) {
37457 + dwc_memset(qh->desc_list, 0x00,
37458 + sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
37459 + }
37460 +}
37461 +
37462 +/**
37463 + * Initializes a QH structure's Descriptor DMA related members.
37464 + * Allocates memory for descriptor list.
37465 + * On first periodic QH, allocates memory for FrameList
37466 + * and enables periodic scheduling.
37467 + *
37468 + * @param hcd The HCD state structure for the DWC OTG controller.
37469 + * @param qh The QH to init.
37470 + *
37471 + * @return 0 if successful, negative error code otherwise.
37472 + */
37473 +int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
37474 +{
37475 + int retval = 0;
37476 +
37477 + if (qh->do_split) {
37478 + DWC_ERROR("SPLIT Transfers are not supported in Descriptor DMA.\n");
37479 + return -1;
37480 + }
37481 +
37482 + retval = desc_list_alloc(qh);
37483 +
37484 + if ((retval == 0)
37485 + && (qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)) {
37486 + if (!hcd->frame_list) {
37487 + retval = frame_list_alloc(hcd);
37488 + /* Enable periodic schedule on first periodic QH */
37489 + if (retval == 0)
37490 + per_sched_enable(hcd, MAX_FRLIST_EN_NUM);
37491 + }
37492 + }
37493 +
37494 + qh->ntd = 0;
37495 +
37496 + return retval;
37497 +}
37498 +
37499 +/**
37500 + * Frees descriptor list memory associated with the QH.
37501 + * If QH is periodic and the last, frees FrameList memory
37502 + * and disables periodic scheduling.
37503 + *
37504 + * @param hcd The HCD state structure for the DWC OTG controller.
37505 + * @param qh The QH to init.
37506 + */
37507 +void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
37508 +{
37509 + desc_list_free(qh);
37510 +
37511 + /*
37512 + * Channel still assigned due to some reasons.
37513 + * Seen on Isoc URB dequeue. Channel halted but no subsequent
37514 + * ChHalted interrupt to release the channel. Afterwards
37515 + * when it comes here from endpoint disable routine
37516 + * channel remains assigned.
37517 + */
37518 + if (qh->channel)
37519 + release_channel_ddma(hcd, qh);
37520 +
37521 + if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)
37522 + && (microframe_schedule || !hcd->periodic_channels) && hcd->frame_list) {
37523 +
37524 + per_sched_disable(hcd);
37525 + frame_list_free(hcd);
37526 + }
37527 +}
37528 +
37529 +static uint8_t frame_to_desc_idx(dwc_otg_qh_t * qh, uint16_t frame_idx)
37530 +{
37531 + if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
37532 + /*
37533 + * Descriptor set(8 descriptors) index
37534 + * which is 8-aligned.
37535 + */
37536 + return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
37537 + } else {
37538 + return (frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1));
37539 + }
37540 +}
37541 +
37542 +/*
37543 + * Determine starting frame for Isochronous transfer.
37544 + * Few frames skipped to prevent race condition with HC.
37545 + */
37546 +static uint8_t calc_starting_frame(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
37547 + uint8_t * skip_frames)
37548 +{
37549 + uint16_t frame = 0;
37550 + hcd->frame_number = dwc_otg_hcd_get_frame_number(hcd);
37551 +
37552 + /* sched_frame is always frame number(not uFrame) both in FS and HS !! */
37553 +
37554 + /*
37555 + * skip_frames is used to limit activated descriptors number
37556 + * to avoid the situation when HC services the last activated
37557 + * descriptor firstly.
37558 + * Example for FS:
37559 + * Current frame is 1, scheduled frame is 3. Since HC always fetches the descriptor
37560 + * corresponding to curr_frame+1, the descriptor corresponding to frame 2
37561 + * will be fetched. If the number of descriptors is max=64 (or greather) the
37562 + * list will be fully programmed with Active descriptors and it is possible
37563 + * case(rare) that the latest descriptor(considering rollback) corresponding
37564 + * to frame 2 will be serviced first. HS case is more probable because, in fact,
37565 + * up to 11 uframes(16 in the code) may be skipped.
37566 + */
37567 + if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
37568 + /*
37569 + * Consider uframe counter also, to start xfer asap.
37570 + * If half of the frame elapsed skip 2 frames otherwise
37571 + * just 1 frame.
37572 + * Starting descriptor index must be 8-aligned, so
37573 + * if the current frame is near to complete the next one
37574 + * is skipped as well.
37575 + */
37576 +
37577 + if (dwc_micro_frame_num(hcd->frame_number) >= 5) {
37578 + *skip_frames = 2 * 8;
37579 + frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
37580 + } else {
37581 + *skip_frames = 1 * 8;
37582 + frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
37583 + }
37584 +
37585 + frame = dwc_full_frame_num(frame);
37586 + } else {
37587 + /*
37588 + * Two frames are skipped for FS - the current and the next.
37589 + * But for descriptor programming, 1 frame(descriptor) is enough,
37590 + * see example above.
37591 + */
37592 + *skip_frames = 1;
37593 + frame = dwc_frame_num_inc(hcd->frame_number, 2);
37594 + }
37595 +
37596 + return frame;
37597 +}
37598 +
37599 +/*
37600 + * Calculate initial descriptor index for isochronous transfer
37601 + * based on scheduled frame.
37602 + */
37603 +static uint8_t recalc_initial_desc_idx(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
37604 +{
37605 + uint16_t frame = 0, fr_idx, fr_idx_tmp;
37606 + uint8_t skip_frames = 0;
37607 + /*
37608 + * With current ISOC processing algorithm the channel is being
37609 + * released when no more QTDs in the list(qh->ntd == 0).
37610 + * Thus this function is called only when qh->ntd == 0 and qh->channel == 0.
37611 + *
37612 + * So qh->channel != NULL branch is not used and just not removed from the
37613 + * source file. It is required for another possible approach which is,
37614 + * do not disable and release the channel when ISOC session completed,
37615 + * just move QH to inactive schedule until new QTD arrives.
37616 + * On new QTD, the QH moved back to 'ready' schedule,
37617 + * starting frame and therefore starting desc_index are recalculated.
37618 + * In this case channel is released only on ep_disable.
37619 + */
37620 +
37621 + /* Calculate starting descriptor index. For INTERRUPT endpoint it is always 0. */
37622 + if (qh->channel) {
37623 + frame = calc_starting_frame(hcd, qh, &skip_frames);
37624 + /*
37625 + * Calculate initial descriptor index based on FrameList current bitmap
37626 + * and servicing period.
37627 + */
37628 + fr_idx_tmp = frame_list_idx(frame);
37629 + fr_idx =
37630 + (MAX_FRLIST_EN_NUM + frame_list_idx(qh->sched_frame) -
37631 + fr_idx_tmp)
37632 + % frame_incr_val(qh);
37633 + fr_idx = (fr_idx + fr_idx_tmp) % MAX_FRLIST_EN_NUM;
37634 + } else {
37635 + qh->sched_frame = calc_starting_frame(hcd, qh, &skip_frames);
37636 + fr_idx = frame_list_idx(qh->sched_frame);
37637 + }
37638 +
37639 + qh->td_first = qh->td_last = frame_to_desc_idx(qh, fr_idx);
37640 +
37641 + return skip_frames;
37642 +}
37643 +
37644 +#define ISOC_URB_GIVEBACK_ASAP
37645 +
37646 +#define MAX_ISOC_XFER_SIZE_FS 1023
37647 +#define MAX_ISOC_XFER_SIZE_HS 3072
37648 +#define DESCNUM_THRESHOLD 4
37649 +
37650 +static void init_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
37651 + uint8_t skip_frames)
37652 +{
37653 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
37654 + dwc_otg_qtd_t *qtd;
37655 + dwc_otg_host_dma_desc_t *dma_desc;
37656 + uint16_t idx, inc, n_desc, ntd_max, max_xfer_size;
37657 +
37658 + idx = qh->td_last;
37659 + inc = qh->interval;
37660 + n_desc = 0;
37661 +
37662 + ntd_max = (max_desc_num(qh) + qh->interval - 1) / qh->interval;
37663 + if (skip_frames && !qh->channel)
37664 + ntd_max = ntd_max - skip_frames / qh->interval;
37665 +
37666 + max_xfer_size =
37667 + (qh->dev_speed ==
37668 + DWC_OTG_EP_SPEED_HIGH) ? MAX_ISOC_XFER_SIZE_HS :
37669 + MAX_ISOC_XFER_SIZE_FS;
37670 +
37671 + DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
37672 + while ((qh->ntd < ntd_max)
37673 + && (qtd->isoc_frame_index_last <
37674 + qtd->urb->packet_count)) {
37675 +
37676 + dma_desc = &qh->desc_list[idx];
37677 + dwc_memset(dma_desc, 0x00, sizeof(dwc_otg_host_dma_desc_t));
37678 +
37679 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
37680 +
37681 + if (frame_desc->length > max_xfer_size)
37682 + qh->n_bytes[idx] = max_xfer_size;
37683 + else
37684 + qh->n_bytes[idx] = frame_desc->length;
37685 + dma_desc->status.b_isoc.n_bytes = qh->n_bytes[idx];
37686 + dma_desc->status.b_isoc.a = 1;
37687 + dma_desc->status.b_isoc.sts = 0;
37688 +
37689 + dma_desc->buf = qtd->urb->dma + frame_desc->offset;
37690 +
37691 + qh->ntd++;
37692 +
37693 + qtd->isoc_frame_index_last++;
37694 +
37695 +#ifdef ISOC_URB_GIVEBACK_ASAP
37696 + /*
37697 + * Set IOC for each descriptor corresponding to the
37698 + * last frame of the URB.
37699 + */
37700 + if (qtd->isoc_frame_index_last ==
37701 + qtd->urb->packet_count)
37702 + dma_desc->status.b_isoc.ioc = 1;
37703 +
37704 +#endif
37705 + idx = desclist_idx_inc(idx, inc, qh->dev_speed);
37706 + n_desc++;
37707 +
37708 + }
37709 + qtd->in_process = 1;
37710 + }
37711 +
37712 + qh->td_last = idx;
37713 +
37714 +#ifdef ISOC_URB_GIVEBACK_ASAP
37715 + /* Set IOC for the last descriptor if descriptor list is full */
37716 + if (qh->ntd == ntd_max) {
37717 + idx = desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
37718 + qh->desc_list[idx].status.b_isoc.ioc = 1;
37719 + }
37720 +#else
37721 + /*
37722 + * Set IOC bit only for one descriptor.
37723 + * Always try to be ahead of HW processing,
37724 + * i.e. on IOC generation driver activates next descriptors but
37725 + * core continues to process descriptors followed the one with IOC set.
37726 + */
37727 +
37728 + if (n_desc > DESCNUM_THRESHOLD) {
37729 + /*
37730 + * Move IOC "up". Required even if there is only one QTD
37731 + * in the list, cause QTDs migth continue to be queued,
37732 + * but during the activation it was only one queued.
37733 + * Actually more than one QTD might be in the list if this function called
37734 + * from XferCompletion - QTDs was queued during HW processing of the previous
37735 + * descriptor chunk.
37736 + */
37737 + idx = dwc_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), qh->dev_speed);
37738 + } else {
37739 + /*
37740 + * Set the IOC for the latest descriptor
37741 + * if either number of descriptor is not greather than threshold
37742 + * or no more new descriptors activated.
37743 + */
37744 + idx = dwc_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
37745 + }
37746 +
37747 + qh->desc_list[idx].status.b_isoc.ioc = 1;
37748 +#endif
37749 +}
37750 +
37751 +static void init_non_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
37752 +{
37753 +
37754 + dwc_hc_t *hc;
37755 + dwc_otg_host_dma_desc_t *dma_desc;
37756 + dwc_otg_qtd_t *qtd;
37757 + int num_packets, len, n_desc = 0;
37758 +
37759 + hc = qh->channel;
37760 +
37761 + /*
37762 + * Start with hc->xfer_buff initialized in
37763 + * assign_and_init_hc(), then if SG transfer consists of multiple URBs,
37764 + * this pointer re-assigned to the buffer of the currently processed QTD.
37765 + * For non-SG request there is always one QTD active.
37766 + */
37767 +
37768 + DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
37769 +
37770 + if (n_desc) {
37771 + /* SG request - more than 1 QTDs */
37772 + hc->xfer_buff = (uint8_t *)qtd->urb->dma + qtd->urb->actual_length;
37773 + hc->xfer_len = qtd->urb->length - qtd->urb->actual_length;
37774 + }
37775 +
37776 + qtd->n_desc = 0;
37777 +
37778 + do {
37779 + dma_desc = &qh->desc_list[n_desc];
37780 + len = hc->xfer_len;
37781 +
37782 + if (len > MAX_DMA_DESC_SIZE)
37783 + len = MAX_DMA_DESC_SIZE - hc->max_packet + 1;
37784 +
37785 + if (hc->ep_is_in) {
37786 + if (len > 0) {
37787 + num_packets = (len + hc->max_packet - 1) / hc->max_packet;
37788 + } else {
37789 + /* Need 1 packet for transfer length of 0. */
37790 + num_packets = 1;
37791 + }
37792 + /* Always program an integral # of max packets for IN transfers. */
37793 + len = num_packets * hc->max_packet;
37794 + }
37795 +
37796 + dma_desc->status.b.n_bytes = len;
37797 +
37798 + qh->n_bytes[n_desc] = len;
37799 +
37800 + if ((qh->ep_type == UE_CONTROL)
37801 + && (qtd->control_phase == DWC_OTG_CONTROL_SETUP))
37802 + dma_desc->status.b.sup = 1; /* Setup Packet */
37803 +
37804 + dma_desc->status.b.a = 1; /* Active descriptor */
37805 + dma_desc->status.b.sts = 0;
37806 +
37807 + dma_desc->buf =
37808 + ((unsigned long)hc->xfer_buff & 0xffffffff);
37809 +
37810 + /*
37811 + * Last descriptor(or single) of IN transfer
37812 + * with actual size less than MaxPacket.
37813 + */
37814 + if (len > hc->xfer_len) {
37815 + hc->xfer_len = 0;
37816 + } else {
37817 + hc->xfer_buff += len;
37818 + hc->xfer_len -= len;
37819 + }
37820 +
37821 + qtd->n_desc++;
37822 + n_desc++;
37823 + }
37824 + while ((hc->xfer_len > 0) && (n_desc != MAX_DMA_DESC_NUM_GENERIC));
37825 +
37826 +
37827 + qtd->in_process = 1;
37828 +
37829 + if (qh->ep_type == UE_CONTROL)
37830 + break;
37831 +
37832 + if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
37833 + break;
37834 + }
37835 +
37836 + if (n_desc) {
37837 + /* Request Transfer Complete interrupt for the last descriptor */
37838 + qh->desc_list[n_desc - 1].status.b.ioc = 1;
37839 + /* End of List indicator */
37840 + qh->desc_list[n_desc - 1].status.b.eol = 1;
37841 +
37842 + hc->ntd = n_desc;
37843 + }
37844 +}
37845 +
37846 +/**
37847 + * For Control and Bulk endpoints initializes descriptor list
37848 + * and starts the transfer.
37849 + *
37850 + * For Interrupt and Isochronous endpoints initializes descriptor list
37851 + * then updates FrameList, marking appropriate entries as active.
37852 + * In case of Isochronous, the starting descriptor index is calculated based
37853 + * on the scheduled frame, but only on the first transfer descriptor within a session.
37854 + * Then starts the transfer via enabling the channel.
37855 + * For Isochronous endpoint the channel is not halted on XferComplete
37856 + * interrupt so remains assigned to the endpoint(QH) until session is done.
37857 + *
37858 + * @param hcd The HCD state structure for the DWC OTG controller.
37859 + * @param qh The QH to init.
37860 + *
37861 + * @return 0 if successful, negative error code otherwise.
37862 + */
37863 +void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
37864 +{
37865 + /* Channel is already assigned */
37866 + dwc_hc_t *hc = qh->channel;
37867 + uint8_t skip_frames = 0;
37868 +
37869 + switch (hc->ep_type) {
37870 + case DWC_OTG_EP_TYPE_CONTROL:
37871 + case DWC_OTG_EP_TYPE_BULK:
37872 + init_non_isoc_dma_desc(hcd, qh);
37873 +
37874 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
37875 + break;
37876 + case DWC_OTG_EP_TYPE_INTR:
37877 + init_non_isoc_dma_desc(hcd, qh);
37878 +
37879 + update_frame_list(hcd, qh, 1);
37880 +
37881 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
37882 + break;
37883 + case DWC_OTG_EP_TYPE_ISOC:
37884 +
37885 + if (!qh->ntd)
37886 + skip_frames = recalc_initial_desc_idx(hcd, qh);
37887 +
37888 + init_isoc_dma_desc(hcd, qh, skip_frames);
37889 +
37890 + if (!hc->xfer_started) {
37891 +
37892 + update_frame_list(hcd, qh, 1);
37893 +
37894 + /*
37895 + * Always set to max, instead of actual size.
37896 + * Otherwise ntd will be changed with
37897 + * channel being enabled. Not recommended.
37898 + *
37899 + */
37900 + hc->ntd = max_desc_num(qh);
37901 + /* Enable channel only once for ISOC */
37902 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
37903 + }
37904 +
37905 + break;
37906 + default:
37907 +
37908 + break;
37909 + }
37910 +}
37911 +
37912 +static void complete_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
37913 + dwc_hc_t * hc,
37914 + dwc_otg_hc_regs_t * hc_regs,
37915 + dwc_otg_halt_status_e halt_status)
37916 +{
37917 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
37918 + dwc_otg_qtd_t *qtd, *qtd_tmp;
37919 + dwc_otg_qh_t *qh;
37920 + dwc_otg_host_dma_desc_t *dma_desc;
37921 + uint16_t idx, remain;
37922 + uint8_t urb_compl;
37923 +
37924 + qh = hc->qh;
37925 + idx = qh->td_first;
37926 +
37927 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
37928 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry)
37929 + qtd->in_process = 0;
37930 + return;
37931 + } else if ((halt_status == DWC_OTG_HC_XFER_AHB_ERR) ||
37932 + (halt_status == DWC_OTG_HC_XFER_BABBLE_ERR)) {
37933 + /*
37934 + * Channel is halted in these error cases.
37935 + * Considered as serious issues.
37936 + * Complete all URBs marking all frames as failed,
37937 + * irrespective whether some of the descriptors(frames) succeeded or no.
37938 + * Pass error code to completion routine as well, to
37939 + * update urb->status, some of class drivers might use it to stop
37940 + * queing transfer requests.
37941 + */
37942 + int err = (halt_status == DWC_OTG_HC_XFER_AHB_ERR)
37943 + ? (-DWC_E_IO)
37944 + : (-DWC_E_OVERFLOW);
37945 +
37946 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
37947 + for (idx = 0; idx < qtd->urb->packet_count; idx++) {
37948 + frame_desc = &qtd->urb->iso_descs[idx];
37949 + frame_desc->status = err;
37950 + }
37951 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, err);
37952 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
37953 + }
37954 + return;
37955 + }
37956 +
37957 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
37958 +
37959 + if (!qtd->in_process)
37960 + break;
37961 +
37962 + urb_compl = 0;
37963 +
37964 + do {
37965 +
37966 + dma_desc = &qh->desc_list[idx];
37967 +
37968 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
37969 + remain = hc->ep_is_in ? dma_desc->status.b_isoc.n_bytes : 0;
37970 +
37971 + if (dma_desc->status.b_isoc.sts == DMA_DESC_STS_PKTERR) {
37972 + /*
37973 + * XactError or, unable to complete all the transactions
37974 + * in the scheduled micro-frame/frame,
37975 + * both indicated by DMA_DESC_STS_PKTERR.
37976 + */
37977 + qtd->urb->error_count++;
37978 + frame_desc->actual_length = qh->n_bytes[idx] - remain;
37979 + frame_desc->status = -DWC_E_PROTOCOL;
37980 + } else {
37981 + /* Success */
37982 +
37983 + frame_desc->actual_length = qh->n_bytes[idx] - remain;
37984 + frame_desc->status = 0;
37985 + }
37986 +
37987 + if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
37988 + /*
37989 + * urb->status is not used for isoc transfers here.
37990 + * The individual frame_desc status are used instead.
37991 + */
37992 +
37993 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
37994 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
37995 +
37996 + /*
37997 + * This check is necessary because urb_dequeue can be called
37998 + * from urb complete callback(sound driver example).
37999 + * All pending URBs are dequeued there, so no need for
38000 + * further processing.
38001 + */
38002 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
38003 + return;
38004 + }
38005 +
38006 + urb_compl = 1;
38007 +
38008 + }
38009 +
38010 + qh->ntd--;
38011 +
38012 + /* Stop if IOC requested descriptor reached */
38013 + if (dma_desc->status.b_isoc.ioc) {
38014 + idx = desclist_idx_inc(idx, qh->interval, hc->speed);
38015 + goto stop_scan;
38016 + }
38017 +
38018 + idx = desclist_idx_inc(idx, qh->interval, hc->speed);
38019 +
38020 + if (urb_compl)
38021 + break;
38022 + }
38023 + while (idx != qh->td_first);
38024 + }
38025 +stop_scan:
38026 + qh->td_first = idx;
38027 +}
38028 +
38029 +uint8_t update_non_isoc_urb_state_ddma(dwc_otg_hcd_t * hcd,
38030 + dwc_hc_t * hc,
38031 + dwc_otg_qtd_t * qtd,
38032 + dwc_otg_host_dma_desc_t * dma_desc,
38033 + dwc_otg_halt_status_e halt_status,
38034 + uint32_t n_bytes, uint8_t * xfer_done)
38035 +{
38036 +
38037 + uint16_t remain = hc->ep_is_in ? dma_desc->status.b.n_bytes : 0;
38038 + dwc_otg_hcd_urb_t *urb = qtd->urb;
38039 +
38040 + if (halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
38041 + urb->status = -DWC_E_IO;
38042 + return 1;
38043 + }
38044 + if (dma_desc->status.b.sts == DMA_DESC_STS_PKTERR) {
38045 + switch (halt_status) {
38046 + case DWC_OTG_HC_XFER_STALL:
38047 + urb->status = -DWC_E_PIPE;
38048 + break;
38049 + case DWC_OTG_HC_XFER_BABBLE_ERR:
38050 + urb->status = -DWC_E_OVERFLOW;
38051 + break;
38052 + case DWC_OTG_HC_XFER_XACT_ERR:
38053 + urb->status = -DWC_E_PROTOCOL;
38054 + break;
38055 + default:
38056 + DWC_ERROR("%s: Unhandled descriptor error status (%d)\n", __func__,
38057 + halt_status);
38058 + break;
38059 + }
38060 + return 1;
38061 + }
38062 +
38063 + if (dma_desc->status.b.a == 1) {
38064 + DWC_DEBUGPL(DBG_HCDV,
38065 + "Active descriptor encountered on channel %d\n",
38066 + hc->hc_num);
38067 + return 0;
38068 + }
38069 +
38070 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL) {
38071 + if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
38072 + urb->actual_length += n_bytes - remain;
38073 + if (remain || urb->actual_length == urb->length) {
38074 + /*
38075 + * For Control Data stage do not set urb->status=0 to prevent
38076 + * URB callback. Set it when Status phase done. See below.
38077 + */
38078 + *xfer_done = 1;
38079 + }
38080 +
38081 + } else if (qtd->control_phase == DWC_OTG_CONTROL_STATUS) {
38082 + urb->status = 0;
38083 + *xfer_done = 1;
38084 + }
38085 + /* No handling for SETUP stage */
38086 + } else {
38087 + /* BULK and INTR */
38088 + urb->actual_length += n_bytes - remain;
38089 + if (remain || urb->actual_length == urb->length) {
38090 + urb->status = 0;
38091 + *xfer_done = 1;
38092 + }
38093 + }
38094 +
38095 + return 0;
38096 +}
38097 +
38098 +static void complete_non_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
38099 + dwc_hc_t * hc,
38100 + dwc_otg_hc_regs_t * hc_regs,
38101 + dwc_otg_halt_status_e halt_status)
38102 +{
38103 + dwc_otg_hcd_urb_t *urb = NULL;
38104 + dwc_otg_qtd_t *qtd, *qtd_tmp;
38105 + dwc_otg_qh_t *qh;
38106 + dwc_otg_host_dma_desc_t *dma_desc;
38107 + uint32_t n_bytes, n_desc, i;
38108 + uint8_t failed = 0, xfer_done;
38109 +
38110 + n_desc = 0;
38111 +
38112 + qh = hc->qh;
38113 +
38114 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
38115 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
38116 + qtd->in_process = 0;
38117 + }
38118 + return;
38119 + }
38120 +
38121 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
38122 +
38123 + urb = qtd->urb;
38124 +
38125 + n_bytes = 0;
38126 + xfer_done = 0;
38127 +
38128 + for (i = 0; i < qtd->n_desc; i++) {
38129 + dma_desc = &qh->desc_list[n_desc];
38130 +
38131 + n_bytes = qh->n_bytes[n_desc];
38132 +
38133 + failed =
38134 + update_non_isoc_urb_state_ddma(hcd, hc, qtd,
38135 + dma_desc,
38136 + halt_status, n_bytes,
38137 + &xfer_done);
38138 +
38139 + if (failed
38140 + || (xfer_done
38141 + && (urb->status != -DWC_E_IN_PROGRESS))) {
38142 +
38143 + hcd->fops->complete(hcd, urb->priv, urb,
38144 + urb->status);
38145 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
38146 +
38147 + if (failed)
38148 + goto stop_scan;
38149 + } else if (qh->ep_type == UE_CONTROL) {
38150 + if (qtd->control_phase == DWC_OTG_CONTROL_SETUP) {
38151 + if (urb->length > 0) {
38152 + qtd->control_phase = DWC_OTG_CONTROL_DATA;
38153 + } else {
38154 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
38155 + }
38156 + DWC_DEBUGPL(DBG_HCDV, " Control setup transaction done\n");
38157 + } else if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
38158 + if (xfer_done) {
38159 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
38160 + DWC_DEBUGPL(DBG_HCDV, " Control data transfer done\n");
38161 + } else if (i + 1 == qtd->n_desc) {
38162 + /*
38163 + * Last descriptor for Control data stage which is
38164 + * not completed yet.
38165 + */
38166 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
38167 + }
38168 + }
38169 + }
38170 +
38171 + n_desc++;
38172 + }
38173 +
38174 + }
38175 +
38176 +stop_scan:
38177 +
38178 + if (qh->ep_type != UE_CONTROL) {
38179 + /*
38180 + * Resetting the data toggle for bulk
38181 + * and interrupt endpoints in case of stall. See handle_hc_stall_intr()
38182 + */
38183 + if (halt_status == DWC_OTG_HC_XFER_STALL)
38184 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
38185 + else
38186 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
38187 + }
38188 +
38189 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
38190 + hcint_data_t hcint;
38191 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
38192 + if (hcint.b.nyet) {
38193 + /*
38194 + * Got a NYET on the last transaction of the transfer. It
38195 + * means that the endpoint should be in the PING state at the
38196 + * beginning of the next transfer.
38197 + */
38198 + qh->ping_state = 1;
38199 + clear_hc_int(hc_regs, nyet);
38200 + }
38201 +
38202 + }
38203 +
38204 +}
38205 +
38206 +/**
38207 + * This function is called from interrupt handlers.
38208 + * Scans the descriptor list, updates URB's status and
38209 + * calls completion routine for the URB if it's done.
38210 + * Releases the channel to be used by other transfers.
38211 + * In case of Isochronous endpoint the channel is not halted until
38212 + * the end of the session, i.e. QTD list is empty.
38213 + * If periodic channel released the FrameList is updated accordingly.
38214 + *
38215 + * Calls transaction selection routines to activate pending transfers.
38216 + *
38217 + * @param hcd The HCD state structure for the DWC OTG controller.
38218 + * @param hc Host channel, the transfer is completed on.
38219 + * @param hc_regs Host channel registers.
38220 + * @param halt_status Reason the channel is being halted,
38221 + * or just XferComplete for isochronous transfer
38222 + */
38223 +void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
38224 + dwc_hc_t * hc,
38225 + dwc_otg_hc_regs_t * hc_regs,
38226 + dwc_otg_halt_status_e halt_status)
38227 +{
38228 + uint8_t continue_isoc_xfer = 0;
38229 + dwc_otg_transaction_type_e tr_type;
38230 + dwc_otg_qh_t *qh = hc->qh;
38231 +
38232 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
38233 +
38234 + complete_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
38235 +
38236 + /* Release the channel if halted or session completed */
38237 + if (halt_status != DWC_OTG_HC_XFER_COMPLETE ||
38238 + DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
38239 +
38240 + /* Halt the channel if session completed */
38241 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
38242 + dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
38243 + }
38244 +
38245 + release_channel_ddma(hcd, qh);
38246 + dwc_otg_hcd_qh_remove(hcd, qh);
38247 + } else {
38248 + /* Keep in assigned schedule to continue transfer */
38249 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
38250 + &qh->qh_list_entry);
38251 + continue_isoc_xfer = 1;
38252 +
38253 + }
38254 + /** @todo Consider the case when period exceeds FrameList size.
38255 + * Frame Rollover interrupt should be used.
38256 + */
38257 + } else {
38258 + /* Scan descriptor list to complete the URB(s), then release the channel */
38259 + complete_non_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
38260 +
38261 + release_channel_ddma(hcd, qh);
38262 + dwc_otg_hcd_qh_remove(hcd, qh);
38263 +
38264 + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
38265 + /* Add back to inactive non-periodic schedule on normal completion */
38266 + dwc_otg_hcd_qh_add(hcd, qh);
38267 + }
38268 +
38269 + }
38270 + tr_type = dwc_otg_hcd_select_transactions(hcd);
38271 + if (tr_type != DWC_OTG_TRANSACTION_NONE || continue_isoc_xfer) {
38272 + if (continue_isoc_xfer) {
38273 + if (tr_type == DWC_OTG_TRANSACTION_NONE) {
38274 + tr_type = DWC_OTG_TRANSACTION_PERIODIC;
38275 + } else if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC) {
38276 + tr_type = DWC_OTG_TRANSACTION_ALL;
38277 + }
38278 + }
38279 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
38280 + }
38281 +}
38282 +
38283 +#endif /* DWC_DEVICE_ONLY */
38284 --- /dev/null
38285 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
38286 @@ -0,0 +1,839 @@
38287 +/* ==========================================================================
38288 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.h $
38289 + * $Revision: #58 $
38290 + * $Date: 2011/09/15 $
38291 + * $Change: 1846647 $
38292 + *
38293 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
38294 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
38295 + * otherwise expressly agreed to in writing between Synopsys and you.
38296 + *
38297 + * The Software IS NOT an item of Licensed Software or Licensed Product under
38298 + * any End User Software License Agreement or Agreement for Licensed Product
38299 + * with Synopsys or any supplement thereto. You are permitted to use and
38300 + * redistribute this Software in source and binary forms, with or without
38301 + * modification, provided that redistributions of source code must retain this
38302 + * notice. You may not view, use, disclose, copy or distribute this file or
38303 + * any information contained herein except pursuant to this license grant from
38304 + * Synopsys. If you do not agree with this notice, including the disclaimer
38305 + * below, then you are not authorized to use the Software.
38306 + *
38307 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
38308 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38309 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38310 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
38311 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38312 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
38313 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38314 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38315 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38316 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
38317 + * DAMAGE.
38318 + * ========================================================================== */
38319 +#ifndef DWC_DEVICE_ONLY
38320 +#ifndef __DWC_HCD_H__
38321 +#define __DWC_HCD_H__
38322 +
38323 +#include "dwc_otg_os_dep.h"
38324 +#include "usb.h"
38325 +#include "dwc_otg_hcd_if.h"
38326 +#include "dwc_otg_core_if.h"
38327 +#include "dwc_list.h"
38328 +#include "dwc_otg_cil.h"
38329 +
38330 +/**
38331 + * @file
38332 + *
38333 + * This file contains the structures, constants, and interfaces for
38334 + * the Host Contoller Driver (HCD).
38335 + *
38336 + * The Host Controller Driver (HCD) is responsible for translating requests
38337 + * from the USB Driver into the appropriate actions on the DWC_otg controller.
38338 + * It isolates the USBD from the specifics of the controller by providing an
38339 + * API to the USBD.
38340 + */
38341 +
38342 +struct dwc_otg_hcd_pipe_info {
38343 + uint8_t dev_addr;
38344 + uint8_t ep_num;
38345 + uint8_t pipe_type;
38346 + uint8_t pipe_dir;
38347 + uint16_t mps;
38348 +};
38349 +
38350 +struct dwc_otg_hcd_iso_packet_desc {
38351 + uint32_t offset;
38352 + uint32_t length;
38353 + uint32_t actual_length;
38354 + uint32_t status;
38355 +};
38356 +
38357 +struct dwc_otg_qtd;
38358 +
38359 +struct dwc_otg_hcd_urb {
38360 + void *priv;
38361 + struct dwc_otg_qtd *qtd;
38362 + void *buf;
38363 + dwc_dma_t dma;
38364 + void *setup_packet;
38365 + dwc_dma_t setup_dma;
38366 + uint32_t length;
38367 + uint32_t actual_length;
38368 + uint32_t status;
38369 + uint32_t error_count;
38370 + uint32_t packet_count;
38371 + uint32_t flags;
38372 + uint16_t interval;
38373 + struct dwc_otg_hcd_pipe_info pipe_info;
38374 + struct dwc_otg_hcd_iso_packet_desc iso_descs[0];
38375 +};
38376 +
38377 +static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe)
38378 +{
38379 + return pipe->ep_num;
38380 +}
38381 +
38382 +static inline uint8_t dwc_otg_hcd_get_pipe_type(struct dwc_otg_hcd_pipe_info
38383 + *pipe)
38384 +{
38385 + return pipe->pipe_type;
38386 +}
38387 +
38388 +static inline uint16_t dwc_otg_hcd_get_mps(struct dwc_otg_hcd_pipe_info *pipe)
38389 +{
38390 + return pipe->mps;
38391 +}
38392 +
38393 +static inline uint8_t dwc_otg_hcd_get_dev_addr(struct dwc_otg_hcd_pipe_info
38394 + *pipe)
38395 +{
38396 + return pipe->dev_addr;
38397 +}
38398 +
38399 +static inline uint8_t dwc_otg_hcd_is_pipe_isoc(struct dwc_otg_hcd_pipe_info
38400 + *pipe)
38401 +{
38402 + return (pipe->pipe_type == UE_ISOCHRONOUS);
38403 +}
38404 +
38405 +static inline uint8_t dwc_otg_hcd_is_pipe_int(struct dwc_otg_hcd_pipe_info
38406 + *pipe)
38407 +{
38408 + return (pipe->pipe_type == UE_INTERRUPT);
38409 +}
38410 +
38411 +static inline uint8_t dwc_otg_hcd_is_pipe_bulk(struct dwc_otg_hcd_pipe_info
38412 + *pipe)
38413 +{
38414 + return (pipe->pipe_type == UE_BULK);
38415 +}
38416 +
38417 +static inline uint8_t dwc_otg_hcd_is_pipe_control(struct dwc_otg_hcd_pipe_info
38418 + *pipe)
38419 +{
38420 + return (pipe->pipe_type == UE_CONTROL);
38421 +}
38422 +
38423 +static inline uint8_t dwc_otg_hcd_is_pipe_in(struct dwc_otg_hcd_pipe_info *pipe)
38424 +{
38425 + return (pipe->pipe_dir == UE_DIR_IN);
38426 +}
38427 +
38428 +static inline uint8_t dwc_otg_hcd_is_pipe_out(struct dwc_otg_hcd_pipe_info
38429 + *pipe)
38430 +{
38431 + return (!dwc_otg_hcd_is_pipe_in(pipe));
38432 +}
38433 +
38434 +static inline void dwc_otg_hcd_fill_pipe(struct dwc_otg_hcd_pipe_info *pipe,
38435 + uint8_t devaddr, uint8_t ep_num,
38436 + uint8_t pipe_type, uint8_t pipe_dir,
38437 + uint16_t mps)
38438 +{
38439 + pipe->dev_addr = devaddr;
38440 + pipe->ep_num = ep_num;
38441 + pipe->pipe_type = pipe_type;
38442 + pipe->pipe_dir = pipe_dir;
38443 + pipe->mps = mps;
38444 +}
38445 +
38446 +/**
38447 + * Phases for control transfers.
38448 + */
38449 +typedef enum dwc_otg_control_phase {
38450 + DWC_OTG_CONTROL_SETUP,
38451 + DWC_OTG_CONTROL_DATA,
38452 + DWC_OTG_CONTROL_STATUS
38453 +} dwc_otg_control_phase_e;
38454 +
38455 +/** Transaction types. */
38456 +typedef enum dwc_otg_transaction_type {
38457 + DWC_OTG_TRANSACTION_NONE,
38458 + DWC_OTG_TRANSACTION_PERIODIC,
38459 + DWC_OTG_TRANSACTION_NON_PERIODIC,
38460 + DWC_OTG_TRANSACTION_ALL
38461 +} dwc_otg_transaction_type_e;
38462 +
38463 +struct dwc_otg_qh;
38464 +
38465 +/**
38466 + * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
38467 + * interrupt, or isochronous transfer. A single QTD is created for each URB
38468 + * (of one of these types) submitted to the HCD. The transfer associated with
38469 + * a QTD may require one or multiple transactions.
38470 + *
38471 + * A QTD is linked to a Queue Head, which is entered in either the
38472 + * non-periodic or periodic schedule for execution. When a QTD is chosen for
38473 + * execution, some or all of its transactions may be executed. After
38474 + * execution, the state of the QTD is updated. The QTD may be retired if all
38475 + * its transactions are complete or if an error occurred. Otherwise, it
38476 + * remains in the schedule so more transactions can be executed later.
38477 + */
38478 +typedef struct dwc_otg_qtd {
38479 + /**
38480 + * Determines the PID of the next data packet for the data phase of
38481 + * control transfers. Ignored for other transfer types.<br>
38482 + * One of the following values:
38483 + * - DWC_OTG_HC_PID_DATA0
38484 + * - DWC_OTG_HC_PID_DATA1
38485 + */
38486 + uint8_t data_toggle;
38487 +
38488 + /** Current phase for control transfers (Setup, Data, or Status). */
38489 + dwc_otg_control_phase_e control_phase;
38490 +
38491 + /** Keep track of the current split type
38492 + * for FS/LS endpoints on a HS Hub */
38493 + uint8_t complete_split;
38494 +
38495 + /** How many bytes transferred during SSPLIT OUT */
38496 + uint32_t ssplit_out_xfer_count;
38497 +
38498 + /**
38499 + * Holds the number of bus errors that have occurred for a transaction
38500 + * within this transfer.
38501 + */
38502 + uint8_t error_count;
38503 +
38504 + /**
38505 + * Index of the next frame descriptor for an isochronous transfer. A
38506 + * frame descriptor describes the buffer position and length of the
38507 + * data to be transferred in the next scheduled (micro)frame of an
38508 + * isochronous transfer. It also holds status for that transaction.
38509 + * The frame index starts at 0.
38510 + */
38511 + uint16_t isoc_frame_index;
38512 +
38513 + /** Position of the ISOC split on full/low speed */
38514 + uint8_t isoc_split_pos;
38515 +
38516 + /** Position of the ISOC split in the buffer for the current frame */
38517 + uint16_t isoc_split_offset;
38518 +
38519 + /** URB for this transfer */
38520 + struct dwc_otg_hcd_urb *urb;
38521 +
38522 + struct dwc_otg_qh *qh;
38523 +
38524 + /** This list of QTDs */
38525 + DWC_CIRCLEQ_ENTRY(dwc_otg_qtd) qtd_list_entry;
38526 +
38527 + /** Indicates if this QTD is currently processed by HW. */
38528 + uint8_t in_process;
38529 +
38530 + /** Number of DMA descriptors for this QTD */
38531 + uint8_t n_desc;
38532 +
38533 + /**
38534 + * Last activated frame(packet) index.
38535 + * Used in Descriptor DMA mode only.
38536 + */
38537 + uint16_t isoc_frame_index_last;
38538 +
38539 +} dwc_otg_qtd_t;
38540 +
38541 +DWC_CIRCLEQ_HEAD(dwc_otg_qtd_list, dwc_otg_qtd);
38542 +
38543 +/**
38544 + * A Queue Head (QH) holds the static characteristics of an endpoint and
38545 + * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
38546 + * be entered in either the non-periodic or periodic schedule.
38547 + */
38548 +typedef struct dwc_otg_qh {
38549 + /**
38550 + * Endpoint type.
38551 + * One of the following values:
38552 + * - UE_CONTROL
38553 + * - UE_BULK
38554 + * - UE_INTERRUPT
38555 + * - UE_ISOCHRONOUS
38556 + */
38557 + uint8_t ep_type;
38558 + uint8_t ep_is_in;
38559 +
38560 + /** wMaxPacketSize Field of Endpoint Descriptor. */
38561 + uint16_t maxp;
38562 +
38563 + /**
38564 + * Device speed.
38565 + * One of the following values:
38566 + * - DWC_OTG_EP_SPEED_LOW
38567 + * - DWC_OTG_EP_SPEED_FULL
38568 + * - DWC_OTG_EP_SPEED_HIGH
38569 + */
38570 + uint8_t dev_speed;
38571 +
38572 + /**
38573 + * Determines the PID of the next data packet for non-control
38574 + * transfers. Ignored for control transfers.<br>
38575 + * One of the following values:
38576 + * - DWC_OTG_HC_PID_DATA0
38577 + * - DWC_OTG_HC_PID_DATA1
38578 + */
38579 + uint8_t data_toggle;
38580 +
38581 + /** Ping state if 1. */
38582 + uint8_t ping_state;
38583 +
38584 + /**
38585 + * List of QTDs for this QH.
38586 + */
38587 + struct dwc_otg_qtd_list qtd_list;
38588 +
38589 + /** Host channel currently processing transfers for this QH. */
38590 + struct dwc_hc *channel;
38591 +
38592 + /** Full/low speed endpoint on high-speed hub requires split. */
38593 + uint8_t do_split;
38594 +
38595 + /** @name Periodic schedule information */
38596 + /** @{ */
38597 +
38598 + /** Bandwidth in microseconds per (micro)frame. */
38599 + uint16_t usecs;
38600 +
38601 + /** Interval between transfers in (micro)frames. */
38602 + uint16_t interval;
38603 +
38604 + /**
38605 + * (micro)frame to initialize a periodic transfer. The transfer
38606 + * executes in the following (micro)frame.
38607 + */
38608 + uint16_t sched_frame;
38609 +
38610 + /*
38611 + ** Frame a NAK was received on this queue head, used to minimise NAK retransmission
38612 + */
38613 + uint16_t nak_frame;
38614 +
38615 + /** (micro)frame at which last start split was initialized. */
38616 + uint16_t start_split_frame;
38617 +
38618 + /** @} */
38619 +
38620 + /**
38621 + * Used instead of original buffer if
38622 + * it(physical address) is not dword-aligned.
38623 + */
38624 + uint8_t *dw_align_buf;
38625 + dwc_dma_t dw_align_buf_dma;
38626 +
38627 + /** Entry for QH in either the periodic or non-periodic schedule. */
38628 + dwc_list_link_t qh_list_entry;
38629 +
38630 + /** @name Descriptor DMA support */
38631 + /** @{ */
38632 +
38633 + /** Descriptor List. */
38634 + dwc_otg_host_dma_desc_t *desc_list;
38635 +
38636 + /** Descriptor List physical address. */
38637 + dwc_dma_t desc_list_dma;
38638 +
38639 + /**
38640 + * Xfer Bytes array.
38641 + * Each element corresponds to a descriptor and indicates
38642 + * original XferSize size value for the descriptor.
38643 + */
38644 + uint32_t *n_bytes;
38645 +
38646 + /** Actual number of transfer descriptors in a list. */
38647 + uint16_t ntd;
38648 +
38649 + /** First activated isochronous transfer descriptor index. */
38650 + uint8_t td_first;
38651 + /** Last activated isochronous transfer descriptor index. */
38652 + uint8_t td_last;
38653 +
38654 + /** @} */
38655 +
38656 +
38657 + uint16_t speed;
38658 + uint16_t frame_usecs[8];
38659 +} dwc_otg_qh_t;
38660 +
38661 +DWC_CIRCLEQ_HEAD(hc_list, dwc_hc);
38662 +
38663 +typedef struct urb_tq_entry {
38664 + struct urb *urb;
38665 + DWC_TAILQ_ENTRY(urb_tq_entry) urb_tq_entries;
38666 +} urb_tq_entry_t;
38667 +
38668 +DWC_TAILQ_HEAD(urb_list, urb_tq_entry);
38669 +
38670 +/**
38671 + * This structure holds the state of the HCD, including the non-periodic and
38672 + * periodic schedules.
38673 + */
38674 +struct dwc_otg_hcd {
38675 + /** The DWC otg device pointer */
38676 + struct dwc_otg_device *otg_dev;
38677 + /** DWC OTG Core Interface Layer */
38678 + dwc_otg_core_if_t *core_if;
38679 +
38680 + /** Function HCD driver callbacks */
38681 + struct dwc_otg_hcd_function_ops *fops;
38682 +
38683 + /** Internal DWC HCD Flags */
38684 + volatile union dwc_otg_hcd_internal_flags {
38685 + uint32_t d32;
38686 + struct {
38687 + unsigned port_connect_status_change:1;
38688 + unsigned port_connect_status:1;
38689 + unsigned port_reset_change:1;
38690 + unsigned port_enable_change:1;
38691 + unsigned port_suspend_change:1;
38692 + unsigned port_over_current_change:1;
38693 + unsigned port_l1_change:1;
38694 + unsigned reserved:26;
38695 + } b;
38696 + } flags;
38697 +
38698 + /**
38699 + * Inactive items in the non-periodic schedule. This is a list of
38700 + * Queue Heads. Transfers associated with these Queue Heads are not
38701 + * currently assigned to a host channel.
38702 + */
38703 + dwc_list_link_t non_periodic_sched_inactive;
38704 +
38705 + /**
38706 + * Active items in the non-periodic schedule. This is a list of
38707 + * Queue Heads. Transfers associated with these Queue Heads are
38708 + * currently assigned to a host channel.
38709 + */
38710 + dwc_list_link_t non_periodic_sched_active;
38711 +
38712 + /**
38713 + * Pointer to the next Queue Head to process in the active
38714 + * non-periodic schedule.
38715 + */
38716 + dwc_list_link_t *non_periodic_qh_ptr;
38717 +
38718 + /**
38719 + * Inactive items in the periodic schedule. This is a list of QHs for
38720 + * periodic transfers that are _not_ scheduled for the next frame.
38721 + * Each QH in the list has an interval counter that determines when it
38722 + * needs to be scheduled for execution. This scheduling mechanism
38723 + * allows only a simple calculation for periodic bandwidth used (i.e.
38724 + * must assume that all periodic transfers may need to execute in the
38725 + * same frame). However, it greatly simplifies scheduling and should
38726 + * be sufficient for the vast majority of OTG hosts, which need to
38727 + * connect to a small number of peripherals at one time.
38728 + *
38729 + * Items move from this list to periodic_sched_ready when the QH
38730 + * interval counter is 0 at SOF.
38731 + */
38732 + dwc_list_link_t periodic_sched_inactive;
38733 +
38734 + /**
38735 + * List of periodic QHs that are ready for execution in the next
38736 + * frame, but have not yet been assigned to host channels.
38737 + *
38738 + * Items move from this list to periodic_sched_assigned as host
38739 + * channels become available during the current frame.
38740 + */
38741 + dwc_list_link_t periodic_sched_ready;
38742 +
38743 + /**
38744 + * List of periodic QHs to be executed in the next frame that are
38745 + * assigned to host channels.
38746 + *
38747 + * Items move from this list to periodic_sched_queued as the
38748 + * transactions for the QH are queued to the DWC_otg controller.
38749 + */
38750 + dwc_list_link_t periodic_sched_assigned;
38751 +
38752 + /**
38753 + * List of periodic QHs that have been queued for execution.
38754 + *
38755 + * Items move from this list to either periodic_sched_inactive or
38756 + * periodic_sched_ready when the channel associated with the transfer
38757 + * is released. If the interval for the QH is 1, the item moves to
38758 + * periodic_sched_ready because it must be rescheduled for the next
38759 + * frame. Otherwise, the item moves to periodic_sched_inactive.
38760 + */
38761 + dwc_list_link_t periodic_sched_queued;
38762 +
38763 + /**
38764 + * Total bandwidth claimed so far for periodic transfers. This value
38765 + * is in microseconds per (micro)frame. The assumption is that all
38766 + * periodic transfers may occur in the same (micro)frame.
38767 + */
38768 + uint16_t periodic_usecs;
38769 +
38770 + /**
38771 + * Total bandwidth claimed so far for all periodic transfers
38772 + * in a frame.
38773 + * This will include a mixture of HS and FS transfers.
38774 + * Units are microseconds per (micro)frame.
38775 + * We have a budget per frame and have to schedule
38776 + * transactions accordingly.
38777 + * Watch out for the fact that things are actually scheduled for the
38778 + * "next frame".
38779 + */
38780 + uint16_t frame_usecs[8];
38781 +
38782 +
38783 + /**
38784 + * Frame number read from the core at SOF. The value ranges from 0 to
38785 + * DWC_HFNUM_MAX_FRNUM.
38786 + */
38787 + uint16_t frame_number;
38788 +
38789 + /**
38790 + * Count of periodic QHs, if using several eps. For SOF enable/disable.
38791 + */
38792 + uint16_t periodic_qh_count;
38793 +
38794 + /**
38795 + * Free host channels in the controller. This is a list of
38796 + * dwc_hc_t items.
38797 + */
38798 + struct hc_list free_hc_list;
38799 + /**
38800 + * Number of host channels assigned to periodic transfers. Currently
38801 + * assuming that there is a dedicated host channel for each periodic
38802 + * transaction and at least one host channel available for
38803 + * non-periodic transactions.
38804 + */
38805 + int periodic_channels; /* microframe_schedule==0 */
38806 +
38807 + /**
38808 + * Number of host channels assigned to non-periodic transfers.
38809 + */
38810 + int non_periodic_channels; /* microframe_schedule==0 */
38811 +
38812 + /**
38813 + * Number of host channels assigned to non-periodic transfers.
38814 + */
38815 + int available_host_channels;
38816 +
38817 + /**
38818 + * Array of pointers to the host channel descriptors. Allows accessing
38819 + * a host channel descriptor given the host channel number. This is
38820 + * useful in interrupt handlers.
38821 + */
38822 + struct dwc_hc *hc_ptr_array[MAX_EPS_CHANNELS];
38823 +
38824 + /**
38825 + * Buffer to use for any data received during the status phase of a
38826 + * control transfer. Normally no data is transferred during the status
38827 + * phase. This buffer is used as a bit bucket.
38828 + */
38829 + uint8_t *status_buf;
38830 +
38831 + /**
38832 + * DMA address for status_buf.
38833 + */
38834 + dma_addr_t status_buf_dma;
38835 +#define DWC_OTG_HCD_STATUS_BUF_SIZE 64
38836 +
38837 + /**
38838 + * Connection timer. An OTG host must display a message if the device
38839 + * does not connect. Started when the VBus power is turned on via
38840 + * sysfs attribute "buspower".
38841 + */
38842 + dwc_timer_t *conn_timer;
38843 +
38844 + /* Tasket to do a reset */
38845 + dwc_tasklet_t *reset_tasklet;
38846 +
38847 + dwc_tasklet_t *completion_tasklet;
38848 + struct urb_list completed_urb_list;
38849 +
38850 + /* */
38851 + dwc_spinlock_t *lock;
38852 + dwc_spinlock_t *channel_lock;
38853 + /**
38854 + * Private data that could be used by OS wrapper.
38855 + */
38856 + void *priv;
38857 +
38858 + uint8_t otg_port;
38859 +
38860 + /** Frame List */
38861 + uint32_t *frame_list;
38862 +
38863 + /** Frame List DMA address */
38864 + dma_addr_t frame_list_dma;
38865 +
38866 +#ifdef DEBUG
38867 + uint32_t frrem_samples;
38868 + uint64_t frrem_accum;
38869 +
38870 + uint32_t hfnum_7_samples_a;
38871 + uint64_t hfnum_7_frrem_accum_a;
38872 + uint32_t hfnum_0_samples_a;
38873 + uint64_t hfnum_0_frrem_accum_a;
38874 + uint32_t hfnum_other_samples_a;
38875 + uint64_t hfnum_other_frrem_accum_a;
38876 +
38877 + uint32_t hfnum_7_samples_b;
38878 + uint64_t hfnum_7_frrem_accum_b;
38879 + uint32_t hfnum_0_samples_b;
38880 + uint64_t hfnum_0_frrem_accum_b;
38881 + uint32_t hfnum_other_samples_b;
38882 + uint64_t hfnum_other_frrem_accum_b;
38883 +#endif
38884 +};
38885 +
38886 +/** @name Transaction Execution Functions */
38887 +/** @{ */
38888 +extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t
38889 + * hcd);
38890 +extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
38891 + dwc_otg_transaction_type_e tr_type);
38892 +
38893 +/** @} */
38894 +
38895 +/** @name Interrupt Handler Functions */
38896 +/** @{ */
38897 +extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38898 +extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd, int32_t);
38899 +extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t *
38900 + dwc_otg_hcd);
38901 +extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t *
38902 + dwc_otg_hcd);
38903 +extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t *
38904 + dwc_otg_hcd);
38905 +extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t *
38906 + dwc_otg_hcd);
38907 +extern int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38908 +extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr(dwc_otg_hcd_t *
38909 + dwc_otg_hcd);
38910 +extern int32_t dwc_otg_hcd_handle_disconnect_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38911 +extern int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38912 +extern int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd,
38913 + uint32_t num);
38914 +extern int32_t dwc_otg_hcd_handle_session_req_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38915 +extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr(dwc_otg_hcd_t *
38916 + dwc_otg_hcd);
38917 +/** @} */
38918 +
38919 +/** @name Schedule Queue Functions */
38920 +/** @{ */
38921 +
38922 +/* Implemented in dwc_otg_hcd_queue.c */
38923 +extern dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
38924 + dwc_otg_hcd_urb_t * urb, int atomic_alloc);
38925 +extern void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38926 +extern int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38927 +extern void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38928 +extern void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
38929 + int sched_csplit);
38930 +
38931 +/** Remove and free a QH */
38932 +static inline void dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd_t * hcd,
38933 + dwc_otg_qh_t * qh)
38934 +{
38935 + dwc_irqflags_t flags;
38936 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
38937 + dwc_otg_hcd_qh_remove(hcd, qh);
38938 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
38939 + dwc_otg_hcd_qh_free(hcd, qh);
38940 +}
38941 +
38942 +/** Allocates memory for a QH structure.
38943 + * @return Returns the memory allocate or NULL on error. */
38944 +static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc(int atomic_alloc)
38945 +{
38946 + if (atomic_alloc)
38947 + return (dwc_otg_qh_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qh_t));
38948 + else
38949 + return (dwc_otg_qh_t *) DWC_ALLOC(sizeof(dwc_otg_qh_t));
38950 +}
38951 +
38952 +extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb,
38953 + int atomic_alloc);
38954 +extern void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb);
38955 +extern int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, dwc_otg_hcd_t * dwc_otg_hcd,
38956 + dwc_otg_qh_t ** qh, int atomic_alloc);
38957 +
38958 +/** Allocates memory for a QTD structure.
38959 + * @return Returns the memory allocate or NULL on error. */
38960 +static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc(int atomic_alloc)
38961 +{
38962 + if (atomic_alloc)
38963 + return (dwc_otg_qtd_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qtd_t));
38964 + else
38965 + return (dwc_otg_qtd_t *) DWC_ALLOC(sizeof(dwc_otg_qtd_t));
38966 +}
38967 +
38968 +/** Frees the memory for a QTD structure. QTD should already be removed from
38969 + * list.
38970 + * @param qtd QTD to free.*/
38971 +static inline void dwc_otg_hcd_qtd_free(dwc_otg_qtd_t * qtd)
38972 +{
38973 + DWC_FREE(qtd);
38974 +}
38975 +
38976 +/** Removes a QTD from list.
38977 + * @param hcd HCD instance.
38978 + * @param qtd QTD to remove from list.
38979 + * @param qh QTD belongs to.
38980 + */
38981 +static inline void dwc_otg_hcd_qtd_remove(dwc_otg_hcd_t * hcd,
38982 + dwc_otg_qtd_t * qtd,
38983 + dwc_otg_qh_t * qh)
38984 +{
38985 + DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
38986 +}
38987 +
38988 +/** Remove and free a QTD
38989 + * Need to disable IRQ and hold hcd lock while calling this function out of
38990 + * interrupt servicing chain */
38991 +static inline void dwc_otg_hcd_qtd_remove_and_free(dwc_otg_hcd_t * hcd,
38992 + dwc_otg_qtd_t * qtd,
38993 + dwc_otg_qh_t * qh)
38994 +{
38995 + dwc_otg_hcd_qtd_remove(hcd, qtd, qh);
38996 + dwc_otg_hcd_qtd_free(qtd);
38997 +}
38998 +
38999 +/** @} */
39000 +
39001 +/** @name Descriptor DMA Supporting Functions */
39002 +/** @{ */
39003 +
39004 +extern void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
39005 +extern void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
39006 + dwc_hc_t * hc,
39007 + dwc_otg_hc_regs_t * hc_regs,
39008 + dwc_otg_halt_status_e halt_status);
39009 +
39010 +extern int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
39011 +extern void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
39012 +
39013 +/** @} */
39014 +
39015 +/** @name Internal Functions */
39016 +/** @{ */
39017 +dwc_otg_qh_t *dwc_urb_to_qh(dwc_otg_hcd_urb_t * urb);
39018 +/** @} */
39019 +
39020 +#ifdef CONFIG_USB_DWC_OTG_LPM
39021 +extern int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd,
39022 + uint8_t devaddr);
39023 +extern void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd);
39024 +#endif
39025 +
39026 +/** Gets the QH that contains the list_head */
39027 +#define dwc_list_to_qh(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qh_t, qh_list_entry)
39028 +
39029 +/** Gets the QTD that contains the list_head */
39030 +#define dwc_list_to_qtd(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qtd_t, qtd_list_entry)
39031 +
39032 +/** Check if QH is non-periodic */
39033 +#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == UE_BULK) || \
39034 + (_qh_ptr_->ep_type == UE_CONTROL))
39035 +
39036 +/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */
39037 +#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
39038 +
39039 +/** Packet size for any kind of endpoint descriptor */
39040 +#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
39041 +
39042 +/**
39043 + * Returns true if _frame1 is less than or equal to _frame2. The comparison is
39044 + * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the
39045 + * frame number when the max frame number is reached.
39046 + */
39047 +static inline int dwc_frame_num_le(uint16_t frame1, uint16_t frame2)
39048 +{
39049 + return ((frame2 - frame1) & DWC_HFNUM_MAX_FRNUM) <=
39050 + (DWC_HFNUM_MAX_FRNUM >> 1);
39051 +}
39052 +
39053 +/**
39054 + * Returns true if _frame1 is greater than _frame2. The comparison is done
39055 + * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
39056 + * number when the max frame number is reached.
39057 + */
39058 +static inline int dwc_frame_num_gt(uint16_t frame1, uint16_t frame2)
39059 +{
39060 + return (frame1 != frame2) &&
39061 + (((frame1 - frame2) & DWC_HFNUM_MAX_FRNUM) <
39062 + (DWC_HFNUM_MAX_FRNUM >> 1));
39063 +}
39064 +
39065 +/**
39066 + * Increments _frame by the amount specified by _inc. The addition is done
39067 + * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value.
39068 + */
39069 +static inline uint16_t dwc_frame_num_inc(uint16_t frame, uint16_t inc)
39070 +{
39071 + return (frame + inc) & DWC_HFNUM_MAX_FRNUM;
39072 +}
39073 +
39074 +static inline uint16_t dwc_full_frame_num(uint16_t frame)
39075 +{
39076 + return (frame & DWC_HFNUM_MAX_FRNUM) >> 3;
39077 +}
39078 +
39079 +static inline uint16_t dwc_micro_frame_num(uint16_t frame)
39080 +{
39081 + return frame & 0x7;
39082 +}
39083 +
39084 +void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
39085 + dwc_otg_hc_regs_t * hc_regs,
39086 + dwc_otg_qtd_t * qtd);
39087 +
39088 +#ifdef DEBUG
39089 +/**
39090 + * Macro to sample the remaining PHY clocks left in the current frame. This
39091 + * may be used during debugging to determine the average time it takes to
39092 + * execute sections of code. There are two possible sample points, "a" and
39093 + * "b", so the _letter argument must be one of these values.
39094 + *
39095 + * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
39096 + * example, "cat /sys/devices/lm0/hcd_frrem".
39097 + */
39098 +#define dwc_sample_frrem(_hcd, _qh, _letter) \
39099 +{ \
39100 + hfnum_data_t hfnum; \
39101 + dwc_otg_qtd_t *qtd; \
39102 + qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \
39103 + if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \
39104 + hfnum.d32 = DWC_READ_REG32(&_hcd->core_if->host_if->host_global_regs->hfnum); \
39105 + switch (hfnum.b.frnum & 0x7) { \
39106 + case 7: \
39107 + _hcd->hfnum_7_samples_##_letter++; \
39108 + _hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \
39109 + break; \
39110 + case 0: \
39111 + _hcd->hfnum_0_samples_##_letter++; \
39112 + _hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \
39113 + break; \
39114 + default: \
39115 + _hcd->hfnum_other_samples_##_letter++; \
39116 + _hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \
39117 + break; \
39118 + } \
39119 + } \
39120 +}
39121 +#else
39122 +#define dwc_sample_frrem(_hcd, _qh, _letter)
39123 +#endif
39124 +#endif
39125 +#endif /* DWC_DEVICE_ONLY */
39126 --- /dev/null
39127 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
39128 @@ -0,0 +1,417 @@
39129 +/* ==========================================================================
39130 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_if.h $
39131 + * $Revision: #12 $
39132 + * $Date: 2011/10/26 $
39133 + * $Change: 1873028 $
39134 + *
39135 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
39136 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
39137 + * otherwise expressly agreed to in writing between Synopsys and you.
39138 + *
39139 + * The Software IS NOT an item of Licensed Software or Licensed Product under
39140 + * any End User Software License Agreement or Agreement for Licensed Product
39141 + * with Synopsys or any supplement thereto. You are permitted to use and
39142 + * redistribute this Software in source and binary forms, with or without
39143 + * modification, provided that redistributions of source code must retain this
39144 + * notice. You may not view, use, disclose, copy or distribute this file or
39145 + * any information contained herein except pursuant to this license grant from
39146 + * Synopsys. If you do not agree with this notice, including the disclaimer
39147 + * below, then you are not authorized to use the Software.
39148 + *
39149 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
39150 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39151 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39152 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
39153 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39154 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39155 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39156 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39157 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39158 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
39159 + * DAMAGE.
39160 + * ========================================================================== */
39161 +#ifndef DWC_DEVICE_ONLY
39162 +#ifndef __DWC_HCD_IF_H__
39163 +#define __DWC_HCD_IF_H__
39164 +
39165 +#include "dwc_otg_core_if.h"
39166 +
39167 +/** @file
39168 + * This file defines DWC_OTG HCD Core API.
39169 + */
39170 +
39171 +struct dwc_otg_hcd;
39172 +typedef struct dwc_otg_hcd dwc_otg_hcd_t;
39173 +
39174 +struct dwc_otg_hcd_urb;
39175 +typedef struct dwc_otg_hcd_urb dwc_otg_hcd_urb_t;
39176 +
39177 +/** @name HCD Function Driver Callbacks */
39178 +/** @{ */
39179 +
39180 +/** This function is called whenever core switches to host mode. */
39181 +typedef int (*dwc_otg_hcd_start_cb_t) (dwc_otg_hcd_t * hcd);
39182 +
39183 +/** This function is called when device has been disconnected */
39184 +typedef int (*dwc_otg_hcd_disconnect_cb_t) (dwc_otg_hcd_t * hcd);
39185 +
39186 +/** Wrapper provides this function to HCD to core, so it can get hub information to which device is connected */
39187 +typedef int (*dwc_otg_hcd_hub_info_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
39188 + void *urb_handle,
39189 + uint32_t * hub_addr,
39190 + uint32_t * port_addr);
39191 +/** Via this function HCD core gets device speed */
39192 +typedef int (*dwc_otg_hcd_speed_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
39193 + void *urb_handle);
39194 +
39195 +/** This function is called when urb is completed */
39196 +typedef int (*dwc_otg_hcd_complete_urb_cb_t) (dwc_otg_hcd_t * hcd,
39197 + void *urb_handle,
39198 + dwc_otg_hcd_urb_t * dwc_otg_urb,
39199 + int32_t status);
39200 +
39201 +/** Via this function HCD core gets b_hnp_enable parameter */
39202 +typedef int (*dwc_otg_hcd_get_b_hnp_enable) (dwc_otg_hcd_t * hcd);
39203 +
39204 +struct dwc_otg_hcd_function_ops {
39205 + dwc_otg_hcd_start_cb_t start;
39206 + dwc_otg_hcd_disconnect_cb_t disconnect;
39207 + dwc_otg_hcd_hub_info_from_urb_cb_t hub_info;
39208 + dwc_otg_hcd_speed_from_urb_cb_t speed;
39209 + dwc_otg_hcd_complete_urb_cb_t complete;
39210 + dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable;
39211 +};
39212 +/** @} */
39213 +
39214 +/** @name HCD Core API */
39215 +/** @{ */
39216 +/** This function allocates dwc_otg_hcd structure and returns pointer on it. */
39217 +extern dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void);
39218 +
39219 +/** This function should be called to initiate HCD Core.
39220 + *
39221 + * @param hcd The HCD
39222 + * @param core_if The DWC_OTG Core
39223 + *
39224 + * Returns -DWC_E_NO_MEMORY if no enough memory.
39225 + * Returns 0 on success
39226 + */
39227 +extern int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if);
39228 +
39229 +/** Frees HCD
39230 + *
39231 + * @param hcd The HCD
39232 + */
39233 +extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd);
39234 +
39235 +/** This function should be called on every hardware interrupt.
39236 + *
39237 + * @param dwc_otg_hcd The HCD
39238 + *
39239 + * Returns non zero if interrupt is handled
39240 + * Return 0 if interrupt is not handled
39241 + */
39242 +extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
39243 +
39244 +/** This function is used to handle the fast interrupt
39245 + *
39246 + */
39247 +extern void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void);
39248 +
39249 +/**
39250 + * Returns private data set by
39251 + * dwc_otg_hcd_set_priv_data function.
39252 + *
39253 + * @param hcd The HCD
39254 + */
39255 +extern void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd);
39256 +
39257 +/**
39258 + * Set private data.
39259 + *
39260 + * @param hcd The HCD
39261 + * @param priv_data pointer to be stored in private data
39262 + */
39263 +extern void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data);
39264 +
39265 +/**
39266 + * This function initializes the HCD Core.
39267 + *
39268 + * @param hcd The HCD
39269 + * @param fops The Function Driver Operations data structure containing pointers to all callbacks.
39270 + *
39271 + * Returns -DWC_E_NO_DEVICE if Core is currently is in device mode.
39272 + * Returns 0 on success
39273 + */
39274 +extern int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
39275 + struct dwc_otg_hcd_function_ops *fops);
39276 +
39277 +/**
39278 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
39279 + * stopped.
39280 + *
39281 + * @param hcd The HCD
39282 + */
39283 +extern void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd);
39284 +
39285 +/**
39286 + * Handles hub class-specific requests.
39287 + *
39288 + * @param dwc_otg_hcd The HCD
39289 + * @param typeReq Request Type
39290 + * @param wValue wValue from control request
39291 + * @param wIndex wIndex from control request
39292 + * @param buf data buffer
39293 + * @param wLength data buffer length
39294 + *
39295 + * Returns -DWC_E_INVALID if invalid argument is passed
39296 + * Returns 0 on success
39297 + */
39298 +extern int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
39299 + uint16_t typeReq, uint16_t wValue,
39300 + uint16_t wIndex, uint8_t * buf,
39301 + uint16_t wLength);
39302 +
39303 +/**
39304 + * Returns otg port number.
39305 + *
39306 + * @param hcd The HCD
39307 + */
39308 +extern uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd);
39309 +
39310 +/**
39311 + * Returns OTG version - either 1.3 or 2.0.
39312 + *
39313 + * @param core_if The core_if structure pointer
39314 + */
39315 +extern uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if);
39316 +
39317 +/**
39318 + * Returns 1 if currently core is acting as B host, and 0 otherwise.
39319 + *
39320 + * @param hcd The HCD
39321 + */
39322 +extern uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd);
39323 +
39324 +/**
39325 + * Returns current frame number.
39326 + *
39327 + * @param hcd The HCD
39328 + */
39329 +extern int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * hcd);
39330 +
39331 +/**
39332 + * Dumps hcd state.
39333 + *
39334 + * @param hcd The HCD
39335 + */
39336 +extern void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd);
39337 +
39338 +/**
39339 + * Dump the average frame remaining at SOF. This can be used to
39340 + * determine average interrupt latency. Frame remaining is also shown for
39341 + * start transfer and two additional sample points.
39342 + * Currently this function is not implemented.
39343 + *
39344 + * @param hcd The HCD
39345 + */
39346 +extern void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd);
39347 +
39348 +/**
39349 + * Sends LPM transaction to the local device.
39350 + *
39351 + * @param hcd The HCD
39352 + * @param devaddr Device Address
39353 + * @param hird Host initiated resume duration
39354 + * @param bRemoteWake Value of bRemoteWake field in LPM transaction
39355 + *
39356 + * Returns negative value if sending LPM transaction was not succeeded.
39357 + * Returns 0 on success.
39358 + */
39359 +extern int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr,
39360 + uint8_t hird, uint8_t bRemoteWake);
39361 +
39362 +/* URB interface */
39363 +
39364 +/**
39365 + * Allocates memory for dwc_otg_hcd_urb structure.
39366 + * Allocated memory should be freed by call of DWC_FREE.
39367 + *
39368 + * @param hcd The HCD
39369 + * @param iso_desc_count Count of ISOC descriptors
39370 + * @param atomic_alloc Specefies whether to perform atomic allocation.
39371 + */
39372 +extern dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
39373 + int iso_desc_count,
39374 + int atomic_alloc);
39375 +
39376 +/**
39377 + * Set pipe information in URB.
39378 + *
39379 + * @param hcd_urb DWC_OTG URB
39380 + * @param devaddr Device Address
39381 + * @param ep_num Endpoint Number
39382 + * @param ep_type Endpoint Type
39383 + * @param ep_dir Endpoint Direction
39384 + * @param mps Max Packet Size
39385 + */
39386 +extern void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * hcd_urb,
39387 + uint8_t devaddr, uint8_t ep_num,
39388 + uint8_t ep_type, uint8_t ep_dir,
39389 + uint16_t mps);
39390 +
39391 +/* Transfer flags */
39392 +#define URB_GIVEBACK_ASAP 0x1
39393 +#define URB_SEND_ZERO_PACKET 0x2
39394 +
39395 +/**
39396 + * Sets dwc_otg_hcd_urb parameters.
39397 + *
39398 + * @param urb DWC_OTG URB allocated by dwc_otg_hcd_urb_alloc function.
39399 + * @param urb_handle Unique handle for request, this will be passed back
39400 + * to function driver in completion callback.
39401 + * @param buf The buffer for the data
39402 + * @param dma The DMA buffer for the data
39403 + * @param buflen Transfer length
39404 + * @param sp Buffer for setup data
39405 + * @param sp_dma DMA address of setup data buffer
39406 + * @param flags Transfer flags
39407 + * @param interval Polling interval for interrupt or isochronous transfers.
39408 + */
39409 +extern void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * urb,
39410 + void *urb_handle, void *buf,
39411 + dwc_dma_t dma, uint32_t buflen, void *sp,
39412 + dwc_dma_t sp_dma, uint32_t flags,
39413 + uint16_t interval);
39414 +
39415 +/** Gets status from dwc_otg_hcd_urb
39416 + *
39417 + * @param dwc_otg_urb DWC_OTG URB
39418 + */
39419 +extern uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb);
39420 +
39421 +/** Gets actual length from dwc_otg_hcd_urb
39422 + *
39423 + * @param dwc_otg_urb DWC_OTG URB
39424 + */
39425 +extern uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t *
39426 + dwc_otg_urb);
39427 +
39428 +/** Gets error count from dwc_otg_hcd_urb. Only for ISOC URBs
39429 + *
39430 + * @param dwc_otg_urb DWC_OTG URB
39431 + */
39432 +extern uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t *
39433 + dwc_otg_urb);
39434 +
39435 +/** Set ISOC descriptor offset and length
39436 + *
39437 + * @param dwc_otg_urb DWC_OTG URB
39438 + * @param desc_num ISOC descriptor number
39439 + * @param offset Offset from beginig of buffer.
39440 + * @param length Transaction length
39441 + */
39442 +extern void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
39443 + int desc_num, uint32_t offset,
39444 + uint32_t length);
39445 +
39446 +/** Get status of ISOC descriptor, specified by desc_num
39447 + *
39448 + * @param dwc_otg_urb DWC_OTG URB
39449 + * @param desc_num ISOC descriptor number
39450 + */
39451 +extern uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t *
39452 + dwc_otg_urb, int desc_num);
39453 +
39454 +/** Get actual length of ISOC descriptor, specified by desc_num
39455 + *
39456 + * @param dwc_otg_urb DWC_OTG URB
39457 + * @param desc_num ISOC descriptor number
39458 + */
39459 +extern uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
39460 + dwc_otg_urb,
39461 + int desc_num);
39462 +
39463 +/** Queue URB. After transfer is completes, the complete callback will be called with the URB status
39464 + *
39465 + * @param dwc_otg_hcd The HCD
39466 + * @param dwc_otg_urb DWC_OTG URB
39467 + * @param ep_handle Out parameter for returning endpoint handle
39468 + * @param atomic_alloc Flag to do atomic allocation if needed
39469 + *
39470 + * Returns -DWC_E_NO_DEVICE if no device is connected.
39471 + * Returns -DWC_E_NO_MEMORY if there is no enough memory.
39472 + * Returns 0 on success.
39473 + */
39474 +extern int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * dwc_otg_hcd,
39475 + dwc_otg_hcd_urb_t * dwc_otg_urb,
39476 + void **ep_handle, int atomic_alloc);
39477 +
39478 +/** De-queue the specified URB
39479 + *
39480 + * @param dwc_otg_hcd The HCD
39481 + * @param dwc_otg_urb DWC_OTG URB
39482 + */
39483 +extern int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * dwc_otg_hcd,
39484 + dwc_otg_hcd_urb_t * dwc_otg_urb);
39485 +
39486 +/** Frees resources in the DWC_otg controller related to a given endpoint.
39487 + * Any URBs for the endpoint must already be dequeued.
39488 + *
39489 + * @param hcd The HCD
39490 + * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
39491 + * @param retry Number of retries if there are queued transfers.
39492 + *
39493 + * Returns -DWC_E_INVALID if invalid arguments are passed.
39494 + * Returns 0 on success
39495 + */
39496 +extern int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
39497 + int retry);
39498 +
39499 +/* Resets the data toggle in qh structure. This function can be called from
39500 + * usb_clear_halt routine.
39501 + *
39502 + * @param hcd The HCD
39503 + * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
39504 + *
39505 + * Returns -DWC_E_INVALID if invalid arguments are passed.
39506 + * Returns 0 on success
39507 + */
39508 +extern int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle);
39509 +
39510 +/** Returns 1 if status of specified port is changed and 0 otherwise.
39511 + *
39512 + * @param hcd The HCD
39513 + * @param port Port number
39514 + */
39515 +extern int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port);
39516 +
39517 +/** Call this function to check if bandwidth was allocated for specified endpoint.
39518 + * Only for ISOC and INTERRUPT endpoints.
39519 + *
39520 + * @param hcd The HCD
39521 + * @param ep_handle Endpoint handle
39522 + */
39523 +extern int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd,
39524 + void *ep_handle);
39525 +
39526 +/** Call this function to check if bandwidth was freed for specified endpoint.
39527 + *
39528 + * @param hcd The HCD
39529 + * @param ep_handle Endpoint handle
39530 + */
39531 +extern int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle);
39532 +
39533 +/** Returns bandwidth allocated for specified endpoint in microseconds.
39534 + * Only for ISOC and INTERRUPT endpoints.
39535 + *
39536 + * @param hcd The HCD
39537 + * @param ep_handle Endpoint handle
39538 + */
39539 +extern uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd,
39540 + void *ep_handle);
39541 +
39542 +/** @} */
39543 +
39544 +#endif /* __DWC_HCD_IF_H__ */
39545 +#endif /* DWC_DEVICE_ONLY */
39546 --- /dev/null
39547 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
39548 @@ -0,0 +1,2258 @@
39549 +/* ==========================================================================
39550 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_intr.c $
39551 + * $Revision: #89 $
39552 + * $Date: 2011/10/20 $
39553 + * $Change: 1869487 $
39554 + *
39555 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
39556 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
39557 + * otherwise expressly agreed to in writing between Synopsys and you.
39558 + *
39559 + * The Software IS NOT an item of Licensed Software or Licensed Product under
39560 + * any End User Software License Agreement or Agreement for Licensed Product
39561 + * with Synopsys or any supplement thereto. You are permitted to use and
39562 + * redistribute this Software in source and binary forms, with or without
39563 + * modification, provided that redistributions of source code must retain this
39564 + * notice. You may not view, use, disclose, copy or distribute this file or
39565 + * any information contained herein except pursuant to this license grant from
39566 + * Synopsys. If you do not agree with this notice, including the disclaimer
39567 + * below, then you are not authorized to use the Software.
39568 + *
39569 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
39570 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39571 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39572 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
39573 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39574 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39575 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39576 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39577 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39578 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
39579 + * DAMAGE.
39580 + * ========================================================================== */
39581 +#ifndef DWC_DEVICE_ONLY
39582 +
39583 +#include "dwc_otg_hcd.h"
39584 +#include "dwc_otg_regs.h"
39585 +#include "dwc_otg_mphi_fix.h"
39586 +
39587 +#include <linux/jiffies.h>
39588 +#include <mach/hardware.h>
39589 +
39590 +
39591 +extern bool microframe_schedule;
39592 +
39593 +/** @file
39594 + * This file contains the implementation of the HCD Interrupt handlers.
39595 + */
39596 +
39597 +/*
39598 + * Some globals to communicate between the FIQ and INTERRUPT
39599 + */
39600 +
39601 +void * dummy_send;
39602 +mphi_regs_t c_mphi_regs;
39603 +int fiq_done, int_done;
39604 +int g_next_sched_frame, g_np_count, g_np_sent, g_work_expected;
39605 +static int mphi_int_count = 0 ;
39606 +
39607 +extern bool fiq_fix_enable, nak_holdoff_enable;
39608 +
39609 +hcchar_data_t nak_hcchar;
39610 +hctsiz_data_t nak_hctsiz;
39611 +hcsplt_data_t nak_hcsplt;
39612 +int nak_count;
39613 +
39614 +void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void)
39615 +{
39616 + gintsts_data_t gintsts;
39617 + hfnum_data_t hfnum;
39618 +
39619 + /* entry takes care to store registers we will be treading on here */
39620 + asm __volatile__ (
39621 + "mov ip, sp ;"
39622 + /* stash FIQ and normal regs */
39623 + "stmdb sp!, {r0-r12, lr};"
39624 + /* !! THIS SETS THE FRAME, adjust to > sizeof locals */
39625 + "sub fp, ip, #256 ;"
39626 + );
39627 +
39628 + fiq_done++;
39629 + gintsts.d32 = FIQ_READ_IO_ADDRESS(USB_BASE + 0x14) & FIQ_READ_IO_ADDRESS(USB_BASE + 0x18);
39630 + hfnum.d32 = FIQ_READ_IO_ADDRESS(USB_BASE + 0x408);
39631 +
39632 + if(gintsts.d32)
39633 + {
39634 + if(gintsts.b.sofintr && g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum))
39635 + {
39636 + /*
39637 + * If np_count != np_sent that means we need to queue non-periodic (bulk) packets this packet
39638 + * g_next_sched_frame is the next frame we have periodic packets for
39639 + *
39640 + * if neither of these are required for this frame then just clear the interrupt
39641 + */
39642 + gintsts.d32 = 0;
39643 + gintsts.b.sofintr = 1;
39644 + FIQ_WRITE_IO_ADDRESS((USB_BASE + 0x14), gintsts.d32);
39645 +
39646 + g_work_expected = 0;
39647 + }
39648 + else
39649 + {
39650 + g_work_expected = 1;
39651 + /* To enable the MPHI interrupt (INT 32)
39652 + */
39653 + FIQ_WRITE( c_mphi_regs.outdda, (int) dummy_send);
39654 + FIQ_WRITE( c_mphi_regs.outddb, (1 << 29));
39655 +
39656 + mphi_int_count++;
39657 + /* Clear the USB global interrupt so we don't just sit in the FIQ */
39658 + FIQ_MODIFY_IO_ADDRESS((USB_BASE + 0x8),1,0);
39659 +
39660 + }
39661 + }
39662 + mb();
39663 +
39664 + /* exit back to normal mode restoring everything */
39665 + asm __volatile__ (
39666 + /* return FIQ regs back to pristine state
39667 + * and get normal regs back
39668 + */
39669 + "ldmia sp!, {r0-r12, lr};"
39670 +
39671 + /* return */
39672 + "subs pc, lr, #4;"
39673 + );
39674 +}
39675 +
39676 +/** This function handles interrupts for the HCD. */
39677 +int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39678 +{
39679 + int retval = 0;
39680 + static int last_time;
39681 +
39682 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
39683 + gintsts_data_t gintsts;
39684 + hfnum_data_t hfnum;
39685 +
39686 +#ifdef DEBUG
39687 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
39688 +
39689 +#endif
39690 +
39691 + /* Exit from ISR if core is hibernated */
39692 + if (core_if->hibernation_suspend == 1) {
39693 + goto exit_handler_routine;
39694 + }
39695 + DWC_SPINLOCK(dwc_otg_hcd->lock);
39696 + /* Check if HOST Mode */
39697 + if (dwc_otg_is_host_mode(core_if)) {
39698 + gintsts.d32 = dwc_otg_read_core_intr(core_if);
39699 + if (!gintsts.d32) {
39700 + goto exit_handler_routine;
39701 + }
39702 +#ifdef DEBUG
39703 + /* Don't print debug message in the interrupt handler on SOF */
39704 +#ifndef DEBUG_SOF
39705 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39706 +#endif
39707 + DWC_DEBUGPL(DBG_HCDI, "\n");
39708 +#endif
39709 +
39710 +#ifdef DEBUG
39711 +#ifndef DEBUG_SOF
39712 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39713 +#endif
39714 + DWC_DEBUGPL(DBG_HCDI,
39715 + "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x core_if=%p\n",
39716 + gintsts.d32, core_if);
39717 +#endif
39718 + hfnum.d32 = DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->hfnum);
39719 + if (gintsts.b.sofintr && g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum))
39720 + {
39721 + /* Note, we should never get here if the FIQ is doing it's job properly*/
39722 + retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd, g_work_expected);
39723 + }
39724 + else if (gintsts.b.sofintr) {
39725 + retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd, g_work_expected);
39726 + }
39727 + if (gintsts.b.rxstsqlvl) {
39728 + retval |=
39729 + dwc_otg_hcd_handle_rx_status_q_level_intr
39730 + (dwc_otg_hcd);
39731 + }
39732 + if (gintsts.b.nptxfempty) {
39733 + retval |=
39734 + dwc_otg_hcd_handle_np_tx_fifo_empty_intr
39735 + (dwc_otg_hcd);
39736 + }
39737 + if (gintsts.b.i2cintr) {
39738 + /** @todo Implement i2cintr handler. */
39739 + }
39740 + if (gintsts.b.portintr) {
39741 + retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd);
39742 + }
39743 + if (gintsts.b.hcintr) {
39744 + retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd);
39745 + }
39746 + if (gintsts.b.ptxfempty) {
39747 + retval |=
39748 + dwc_otg_hcd_handle_perio_tx_fifo_empty_intr
39749 + (dwc_otg_hcd);
39750 + }
39751 +#ifdef DEBUG
39752 +#ifndef DEBUG_SOF
39753 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39754 +#endif
39755 + {
39756 + DWC_DEBUGPL(DBG_HCDI,
39757 + "DWC OTG HCD Finished Servicing Interrupts\n");
39758 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n",
39759 + DWC_READ_REG32(&global_regs->gintsts));
39760 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n",
39761 + DWC_READ_REG32(&global_regs->gintmsk));
39762 + }
39763 +#endif
39764 +
39765 +#ifdef DEBUG
39766 +#ifndef DEBUG_SOF
39767 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39768 +#endif
39769 + DWC_DEBUGPL(DBG_HCDI, "\n");
39770 +#endif
39771 +
39772 + }
39773 +
39774 +exit_handler_routine:
39775 +
39776 + if (fiq_fix_enable)
39777 + {
39778 + /* Clear the MPHI interrupt */
39779 + DWC_WRITE_REG32(c_mphi_regs.intstat, (1<<16));
39780 + if (mphi_int_count >= 60)
39781 + {
39782 + DWC_WRITE_REG32(c_mphi_regs.ctrl, ((1<<31) + (1<<16)));
39783 + while(!(DWC_READ_REG32(c_mphi_regs.ctrl) & (1 << 17)))
39784 + ;
39785 + DWC_WRITE_REG32(c_mphi_regs.ctrl, (1<<31));
39786 + mphi_int_count = 0;
39787 + }
39788 + int_done++;
39789 + if((jiffies / HZ) > last_time)
39790 + {
39791 + /* Once a second output the fiq and irq numbers, useful for debug */
39792 + last_time = jiffies / HZ;
39793 + DWC_DEBUGPL(DBG_USER, "int_done = %d fiq_done = %d\n", int_done, fiq_done);
39794 + }
39795 +
39796 + /* Re-Enable FIQ interrupt from USB peripheral */
39797 + DWC_MODIFY_REG32((uint32_t *)IO_ADDRESS(USB_BASE + 0x8), 0 , 1);
39798 + }
39799 +
39800 + DWC_SPINUNLOCK(dwc_otg_hcd->lock);
39801 + return retval;
39802 +}
39803 +
39804 +#ifdef DWC_TRACK_MISSED_SOFS
39805 +
39806 +#warning Compiling code to track missed SOFs
39807 +#define FRAME_NUM_ARRAY_SIZE 1000
39808 +/**
39809 + * This function is for debug only.
39810 + */
39811 +static inline void track_missed_sofs(uint16_t curr_frame_number)
39812 +{
39813 + static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE];
39814 + static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE];
39815 + static int frame_num_idx = 0;
39816 + static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM;
39817 + static int dumped_frame_num_array = 0;
39818 +
39819 + if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
39820 + if (((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) !=
39821 + curr_frame_number) {
39822 + frame_num_array[frame_num_idx] = curr_frame_number;
39823 + last_frame_num_array[frame_num_idx++] = last_frame_num;
39824 + }
39825 + } else if (!dumped_frame_num_array) {
39826 + int i;
39827 + DWC_PRINTF("Frame Last Frame\n");
39828 + DWC_PRINTF("----- ----------\n");
39829 + for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
39830 + DWC_PRINTF("0x%04x 0x%04x\n",
39831 + frame_num_array[i], last_frame_num_array[i]);
39832 + }
39833 + dumped_frame_num_array = 1;
39834 + }
39835 + last_frame_num = curr_frame_number;
39836 +}
39837 +#endif
39838 +
39839 +/**
39840 + * Handles the start-of-frame interrupt in host mode. Non-periodic
39841 + * transactions may be queued to the DWC_otg controller for the current
39842 + * (micro)frame. Periodic transactions may be queued to the controller for the
39843 + * next (micro)frame.
39844 + */
39845 +int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd, int32_t work_expected)
39846 +{
39847 + hfnum_data_t hfnum;
39848 + dwc_list_link_t *qh_entry;
39849 + dwc_otg_qh_t *qh;
39850 + dwc_otg_transaction_type_e tr_type;
39851 + gintsts_data_t gintsts = {.d32 = 0 };
39852 + int did_something = 0;
39853 + int32_t next_sched_frame = -1;
39854 +
39855 + hfnum.d32 =
39856 + DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum);
39857 +
39858 +#ifdef DEBUG_SOF
39859 + DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n");
39860 +#endif
39861 + hcd->frame_number = hfnum.b.frnum;
39862 +
39863 +#ifdef DEBUG
39864 + hcd->frrem_accum += hfnum.b.frrem;
39865 + hcd->frrem_samples++;
39866 +#endif
39867 +
39868 +#ifdef DWC_TRACK_MISSED_SOFS
39869 + track_missed_sofs(hcd->frame_number);
39870 +#endif
39871 + /* Determine whether any periodic QHs should be executed. */
39872 + qh_entry = DWC_LIST_FIRST(&hcd->periodic_sched_inactive);
39873 + while (qh_entry != &hcd->periodic_sched_inactive) {
39874 + qh = DWC_LIST_ENTRY(qh_entry, dwc_otg_qh_t, qh_list_entry);
39875 + qh_entry = qh_entry->next;
39876 + if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) {
39877 + /*
39878 + * Move QH to the ready list to be executed next
39879 + * (micro)frame.
39880 + */
39881 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
39882 + &qh->qh_list_entry);
39883 +
39884 + did_something = 1;
39885 + }
39886 + else
39887 + {
39888 + if(next_sched_frame < 0 || dwc_frame_num_le(qh->sched_frame, next_sched_frame))
39889 + {
39890 + next_sched_frame = qh->sched_frame;
39891 + }
39892 + }
39893 + }
39894 +
39895 + g_next_sched_frame = next_sched_frame;
39896 +
39897 + tr_type = dwc_otg_hcd_select_transactions(hcd);
39898 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
39899 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
39900 + did_something = 1;
39901 + }
39902 + if(work_expected && !did_something)
39903 + DWC_DEBUGPL(DBG_USER, "Nothing to do !! frame = %x, g_next_sched_frame = %x\n", (int) hfnum.b.frnum, g_next_sched_frame);
39904 + if(!work_expected && did_something)
39905 + DWC_DEBUGPL(DBG_USER, "Unexpected work done !! frame = %x, g_next_sched_frame = %x\n", (int) hfnum.b.frnum, g_next_sched_frame);
39906 +
39907 +
39908 + /* Clear interrupt */
39909 + gintsts.b.sofintr = 1;
39910 + DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32);
39911 +
39912 + return 1;
39913 +}
39914 +
39915 +/** Handles the Rx Status Queue Level Interrupt, which indicates that there is at
39916 + * least one packet in the Rx FIFO. The packets are moved from the FIFO to
39917 + * memory if the DWC_otg controller is operating in Slave mode. */
39918 +int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39919 +{
39920 + host_grxsts_data_t grxsts;
39921 + dwc_hc_t *hc = NULL;
39922 +
39923 + DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n");
39924 +
39925 + grxsts.d32 =
39926 + DWC_READ_REG32(&dwc_otg_hcd->core_if->core_global_regs->grxstsp);
39927 +
39928 + hc = dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum];
39929 + if (!hc) {
39930 + DWC_ERROR("Unable to get corresponding channel\n");
39931 + return 0;
39932 + }
39933 +
39934 + /* Packet Status */
39935 + DWC_DEBUGPL(DBG_HCDV, " Ch num = %d\n", grxsts.b.chnum);
39936 + DWC_DEBUGPL(DBG_HCDV, " Count = %d\n", grxsts.b.bcnt);
39937 + DWC_DEBUGPL(DBG_HCDV, " DPID = %d, hc.dpid = %d\n", grxsts.b.dpid,
39938 + hc->data_pid_start);
39939 + DWC_DEBUGPL(DBG_HCDV, " PStatus = %d\n", grxsts.b.pktsts);
39940 +
39941 + switch (grxsts.b.pktsts) {
39942 + case DWC_GRXSTS_PKTSTS_IN:
39943 + /* Read the data into the host buffer. */
39944 + if (grxsts.b.bcnt > 0) {
39945 + dwc_otg_read_packet(dwc_otg_hcd->core_if,
39946 + hc->xfer_buff, grxsts.b.bcnt);
39947 +
39948 + /* Update the HC fields for the next packet received. */
39949 + hc->xfer_count += grxsts.b.bcnt;
39950 + hc->xfer_buff += grxsts.b.bcnt;
39951 + }
39952 +
39953 + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
39954 + case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
39955 + case DWC_GRXSTS_PKTSTS_CH_HALTED:
39956 + /* Handled in interrupt, just ignore data */
39957 + break;
39958 + default:
39959 + DWC_ERROR("RX_STS_Q Interrupt: Unknown status %d\n",
39960 + grxsts.b.pktsts);
39961 + break;
39962 + }
39963 +
39964 + return 1;
39965 +}
39966 +
39967 +/** This interrupt occurs when the non-periodic Tx FIFO is half-empty. More
39968 + * data packets may be written to the FIFO for OUT transfers. More requests
39969 + * may be written to the non-periodic request queue for IN transfers. This
39970 + * interrupt is enabled only in Slave mode. */
39971 +int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39972 +{
39973 + DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n");
39974 + dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
39975 + DWC_OTG_TRANSACTION_NON_PERIODIC);
39976 + return 1;
39977 +}
39978 +
39979 +/** This interrupt occurs when the periodic Tx FIFO is half-empty. More data
39980 + * packets may be written to the FIFO for OUT transfers. More requests may be
39981 + * written to the periodic request queue for IN transfers. This interrupt is
39982 + * enabled only in Slave mode. */
39983 +int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39984 +{
39985 + DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n");
39986 + dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
39987 + DWC_OTG_TRANSACTION_PERIODIC);
39988 + return 1;
39989 +}
39990 +
39991 +/** There are multiple conditions that can cause a port interrupt. This function
39992 + * determines which interrupt conditions have occurred and handles them
39993 + * appropriately. */
39994 +int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39995 +{
39996 + int retval = 0;
39997 + hprt0_data_t hprt0;
39998 + hprt0_data_t hprt0_modify;
39999 +
40000 + hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
40001 + hprt0_modify.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
40002 +
40003 + /* Clear appropriate bits in HPRT0 to clear the interrupt bit in
40004 + * GINTSTS */
40005 +
40006 + hprt0_modify.b.prtena = 0;
40007 + hprt0_modify.b.prtconndet = 0;
40008 + hprt0_modify.b.prtenchng = 0;
40009 + hprt0_modify.b.prtovrcurrchng = 0;
40010 +
40011 + /* Port Connect Detected
40012 + * Set flag and clear if detected */
40013 + if (dwc_otg_hcd->core_if->hibernation_suspend == 1) {
40014 + // Dont modify port status if we are in hibernation state
40015 + hprt0_modify.b.prtconndet = 1;
40016 + hprt0_modify.b.prtenchng = 1;
40017 + DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
40018 + hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
40019 + return retval;
40020 + }
40021 +
40022 + if (hprt0.b.prtconndet) {
40023 + /** @todo - check if steps performed in 'else' block should be perfromed regardles adp */
40024 + if (dwc_otg_hcd->core_if->adp_enable &&
40025 + dwc_otg_hcd->core_if->adp.vbuson_timer_started == 1) {
40026 + DWC_PRINTF("PORT CONNECT DETECTED ----------------\n");
40027 + DWC_TIMER_CANCEL(dwc_otg_hcd->core_if->adp.vbuson_timer);
40028 + dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
40029 + /* TODO - check if this is required, as
40030 + * host initialization was already performed
40031 + * after initial ADP probing
40032 + */
40033 + /*dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
40034 + dwc_otg_core_init(dwc_otg_hcd->core_if);
40035 + dwc_otg_enable_global_interrupts(dwc_otg_hcd->core_if);
40036 + cil_hcd_start(dwc_otg_hcd->core_if);*/
40037 + } else {
40038 +
40039 + DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x "
40040 + "Port Connect Detected--\n", hprt0.d32);
40041 + dwc_otg_hcd->flags.b.port_connect_status_change = 1;
40042 + dwc_otg_hcd->flags.b.port_connect_status = 1;
40043 + hprt0_modify.b.prtconndet = 1;
40044 +
40045 + /* B-Device has connected, Delete the connection timer. */
40046 + DWC_TIMER_CANCEL(dwc_otg_hcd->conn_timer);
40047 + }
40048 + /* The Hub driver asserts a reset when it sees port connect
40049 + * status change flag */
40050 + retval |= 1;
40051 + }
40052 +
40053 + /* Port Enable Changed
40054 + * Clear if detected - Set internal flag if disabled */
40055 + if (hprt0.b.prtenchng) {
40056 + DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
40057 + "Port Enable Changed--\n", hprt0.d32);
40058 + hprt0_modify.b.prtenchng = 1;
40059 + if (hprt0.b.prtena == 1) {
40060 + hfir_data_t hfir;
40061 + int do_reset = 0;
40062 + dwc_otg_core_params_t *params =
40063 + dwc_otg_hcd->core_if->core_params;
40064 + dwc_otg_core_global_regs_t *global_regs =
40065 + dwc_otg_hcd->core_if->core_global_regs;
40066 + dwc_otg_host_if_t *host_if =
40067 + dwc_otg_hcd->core_if->host_if;
40068 +
40069 + /* Every time when port enables calculate
40070 + * HFIR.FrInterval
40071 + */
40072 + hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
40073 + hfir.b.frint = calc_frame_interval(dwc_otg_hcd->core_if);
40074 + DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
40075 +
40076 + /* Check if we need to adjust the PHY clock speed for
40077 + * low power and adjust it */
40078 + if (params->host_support_fs_ls_low_power) {
40079 + gusbcfg_data_t usbcfg;
40080 +
40081 + usbcfg.d32 =
40082 + DWC_READ_REG32(&global_regs->gusbcfg);
40083 +
40084 + if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED
40085 + || hprt0.b.prtspd ==
40086 + DWC_HPRT0_PRTSPD_FULL_SPEED) {
40087 + /*
40088 + * Low power
40089 + */
40090 + hcfg_data_t hcfg;
40091 + if (usbcfg.b.phylpwrclksel == 0) {
40092 + /* Set PHY low power clock select for FS/LS devices */
40093 + usbcfg.b.phylpwrclksel = 1;
40094 + DWC_WRITE_REG32
40095 + (&global_regs->gusbcfg,
40096 + usbcfg.d32);
40097 + do_reset = 1;
40098 + }
40099 +
40100 + hcfg.d32 =
40101 + DWC_READ_REG32
40102 + (&host_if->host_global_regs->hcfg);
40103 +
40104 + if (hprt0.b.prtspd ==
40105 + DWC_HPRT0_PRTSPD_LOW_SPEED
40106 + && params->host_ls_low_power_phy_clk
40107 + ==
40108 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)
40109 + {
40110 + /* 6 MHZ */
40111 + DWC_DEBUGPL(DBG_CIL,
40112 + "FS_PHY programming HCFG to 6 MHz (Low Power)\n");
40113 + if (hcfg.b.fslspclksel !=
40114 + DWC_HCFG_6_MHZ) {
40115 + hcfg.b.fslspclksel =
40116 + DWC_HCFG_6_MHZ;
40117 + DWC_WRITE_REG32
40118 + (&host_if->host_global_regs->hcfg,
40119 + hcfg.d32);
40120 + do_reset = 1;
40121 + }
40122 + } else {
40123 + /* 48 MHZ */
40124 + DWC_DEBUGPL(DBG_CIL,
40125 + "FS_PHY programming HCFG to 48 MHz ()\n");
40126 + if (hcfg.b.fslspclksel !=
40127 + DWC_HCFG_48_MHZ) {
40128 + hcfg.b.fslspclksel =
40129 + DWC_HCFG_48_MHZ;
40130 + DWC_WRITE_REG32
40131 + (&host_if->host_global_regs->hcfg,
40132 + hcfg.d32);
40133 + do_reset = 1;
40134 + }
40135 + }
40136 + } else {
40137 + /*
40138 + * Not low power
40139 + */
40140 + if (usbcfg.b.phylpwrclksel == 1) {
40141 + usbcfg.b.phylpwrclksel = 0;
40142 + DWC_WRITE_REG32
40143 + (&global_regs->gusbcfg,
40144 + usbcfg.d32);
40145 + do_reset = 1;
40146 + }
40147 + }
40148 +
40149 + if (do_reset) {
40150 + DWC_TASK_SCHEDULE(dwc_otg_hcd->reset_tasklet);
40151 + }
40152 + }
40153 +
40154 + if (!do_reset) {
40155 + /* Port has been enabled set the reset change flag */
40156 + dwc_otg_hcd->flags.b.port_reset_change = 1;
40157 + }
40158 + } else {
40159 + dwc_otg_hcd->flags.b.port_enable_change = 1;
40160 + }
40161 + retval |= 1;
40162 + }
40163 +
40164 + /** Overcurrent Change Interrupt */
40165 + if (hprt0.b.prtovrcurrchng) {
40166 + DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
40167 + "Port Overcurrent Changed--\n", hprt0.d32);
40168 + dwc_otg_hcd->flags.b.port_over_current_change = 1;
40169 + hprt0_modify.b.prtovrcurrchng = 1;
40170 + retval |= 1;
40171 + }
40172 +
40173 + /* Clear Port Interrupts */
40174 + DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
40175 +
40176 + return retval;
40177 +}
40178 +
40179 +/** This interrupt indicates that one or more host channels has a pending
40180 + * interrupt. There are multiple conditions that can cause each host channel
40181 + * interrupt. This function determines which conditions have occurred for each
40182 + * host channel interrupt and handles them appropriately. */
40183 +int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd)
40184 +{
40185 + int i;
40186 + int retval = 0;
40187 + haint_data_t haint;
40188 +
40189 + /* Clear appropriate bits in HCINTn to clear the interrupt bit in
40190 + * GINTSTS */
40191 +
40192 + haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if);
40193 +
40194 + for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) {
40195 + if (haint.b2.chint & (1 << i)) {
40196 + retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i);
40197 + }
40198 + }
40199 +
40200 + return retval;
40201 +}
40202 +
40203 +/**
40204 + * Gets the actual length of a transfer after the transfer halts. _halt_status
40205 + * holds the reason for the halt.
40206 + *
40207 + * For IN transfers where halt_status is DWC_OTG_HC_XFER_COMPLETE,
40208 + * *short_read is set to 1 upon return if less than the requested
40209 + * number of bytes were transferred. Otherwise, *short_read is set to 0 upon
40210 + * return. short_read may also be NULL on entry, in which case it remains
40211 + * unchanged.
40212 + */
40213 +static uint32_t get_actual_xfer_length(dwc_hc_t * hc,
40214 + dwc_otg_hc_regs_t * hc_regs,
40215 + dwc_otg_qtd_t * qtd,
40216 + dwc_otg_halt_status_e halt_status,
40217 + int *short_read)
40218 +{
40219 + hctsiz_data_t hctsiz;
40220 + uint32_t length;
40221 +
40222 + if (short_read != NULL) {
40223 + *short_read = 0;
40224 + }
40225 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40226 +
40227 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
40228 + if (hc->ep_is_in) {
40229 + length = hc->xfer_len - hctsiz.b.xfersize;
40230 + if (short_read != NULL) {
40231 + *short_read = (hctsiz.b.xfersize != 0);
40232 + }
40233 + } else if (hc->qh->do_split) {
40234 + length = qtd->ssplit_out_xfer_count;
40235 + } else {
40236 + length = hc->xfer_len;
40237 + }
40238 + } else {
40239 + /*
40240 + * Must use the hctsiz.pktcnt field to determine how much data
40241 + * has been transferred. This field reflects the number of
40242 + * packets that have been transferred via the USB. This is
40243 + * always an integral number of packets if the transfer was
40244 + * halted before its normal completion. (Can't use the
40245 + * hctsiz.xfersize field because that reflects the number of
40246 + * bytes transferred via the AHB, not the USB).
40247 + */
40248 + length =
40249 + (hc->start_pkt_count - hctsiz.b.pktcnt) * hc->max_packet;
40250 + }
40251 +
40252 + return length;
40253 +}
40254 +
40255 +/**
40256 + * Updates the state of the URB after a Transfer Complete interrupt on the
40257 + * host channel. Updates the actual_length field of the URB based on the
40258 + * number of bytes transferred via the host channel. Sets the URB status
40259 + * if the data transfer is finished.
40260 + *
40261 + * @return 1 if the data transfer specified by the URB is completely finished,
40262 + * 0 otherwise.
40263 + */
40264 +static int update_urb_state_xfer_comp(dwc_hc_t * hc,
40265 + dwc_otg_hc_regs_t * hc_regs,
40266 + dwc_otg_hcd_urb_t * urb,
40267 + dwc_otg_qtd_t * qtd)
40268 +{
40269 + int xfer_done = 0;
40270 + int short_read = 0;
40271 +
40272 + int xfer_length;
40273 +
40274 + xfer_length = get_actual_xfer_length(hc, hc_regs, qtd,
40275 + DWC_OTG_HC_XFER_COMPLETE,
40276 + &short_read);
40277 +
40278 +
40279 + /* non DWORD-aligned buffer case handling. */
40280 + if (hc->align_buff && xfer_length && hc->ep_is_in) {
40281 + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
40282 + xfer_length);
40283 + }
40284 +
40285 + urb->actual_length += xfer_length;
40286 +
40287 + if (xfer_length && (hc->ep_type == DWC_OTG_EP_TYPE_BULK) &&
40288 + (urb->flags & URB_SEND_ZERO_PACKET)
40289 + && (urb->actual_length == urb->length)
40290 + && !(urb->length % hc->max_packet)) {
40291 + xfer_done = 0;
40292 + } else if (short_read || urb->actual_length >= urb->length) {
40293 + xfer_done = 1;
40294 + urb->status = 0;
40295 + }
40296 +
40297 +#ifdef DEBUG
40298 + {
40299 + hctsiz_data_t hctsiz;
40300 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40301 + DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
40302 + __func__, (hc->ep_is_in ? "IN" : "OUT"),
40303 + hc->hc_num);
40304 + DWC_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", hc->xfer_len);
40305 + DWC_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n",
40306 + hctsiz.b.xfersize);
40307 + DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n",
40308 + urb->length);
40309 + DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n",
40310 + urb->actual_length);
40311 + DWC_DEBUGPL(DBG_HCDV, " short_read %d, xfer_done %d\n",
40312 + short_read, xfer_done);
40313 + }
40314 +#endif
40315 +
40316 + return xfer_done;
40317 +}
40318 +
40319 +/*
40320 + * Save the starting data toggle for the next transfer. The data toggle is
40321 + * saved in the QH for non-control transfers and it's saved in the QTD for
40322 + * control transfers.
40323 + */
40324 +void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
40325 + dwc_otg_hc_regs_t * hc_regs, dwc_otg_qtd_t * qtd)
40326 +{
40327 + hctsiz_data_t hctsiz;
40328 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40329 +
40330 + if (hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) {
40331 + dwc_otg_qh_t *qh = hc->qh;
40332 + if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
40333 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
40334 + } else {
40335 + qh->data_toggle = DWC_OTG_HC_PID_DATA1;
40336 + }
40337 + } else {
40338 + if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
40339 + qtd->data_toggle = DWC_OTG_HC_PID_DATA0;
40340 + } else {
40341 + qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
40342 + }
40343 + }
40344 +}
40345 +
40346 +/**
40347 + * Updates the state of an Isochronous URB when the transfer is stopped for
40348 + * any reason. The fields of the current entry in the frame descriptor array
40349 + * are set based on the transfer state and the input _halt_status. Completes
40350 + * the Isochronous URB if all the URB frames have been completed.
40351 + *
40352 + * @return DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be
40353 + * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE.
40354 + */
40355 +static dwc_otg_halt_status_e
40356 +update_isoc_urb_state(dwc_otg_hcd_t * hcd,
40357 + dwc_hc_t * hc,
40358 + dwc_otg_hc_regs_t * hc_regs,
40359 + dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
40360 +{
40361 + dwc_otg_hcd_urb_t *urb = qtd->urb;
40362 + dwc_otg_halt_status_e ret_val = halt_status;
40363 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
40364 +
40365 + frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
40366 + switch (halt_status) {
40367 + case DWC_OTG_HC_XFER_COMPLETE:
40368 + frame_desc->status = 0;
40369 + frame_desc->actual_length =
40370 + get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
40371 +
40372 + /* non DWORD-aligned buffer case handling. */
40373 + if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
40374 + dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
40375 + hc->qh->dw_align_buf, frame_desc->actual_length);
40376 + }
40377 +
40378 + break;
40379 + case DWC_OTG_HC_XFER_FRAME_OVERRUN:
40380 + urb->error_count++;
40381 + if (hc->ep_is_in) {
40382 + frame_desc->status = -DWC_E_NO_STREAM_RES;
40383 + } else {
40384 + frame_desc->status = -DWC_E_COMMUNICATION;
40385 + }
40386 + frame_desc->actual_length = 0;
40387 + break;
40388 + case DWC_OTG_HC_XFER_BABBLE_ERR:
40389 + urb->error_count++;
40390 + frame_desc->status = -DWC_E_OVERFLOW;
40391 + /* Don't need to update actual_length in this case. */
40392 + break;
40393 + case DWC_OTG_HC_XFER_XACT_ERR:
40394 + urb->error_count++;
40395 + frame_desc->status = -DWC_E_PROTOCOL;
40396 + frame_desc->actual_length =
40397 + get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
40398 +
40399 + /* non DWORD-aligned buffer case handling. */
40400 + if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
40401 + dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
40402 + hc->qh->dw_align_buf, frame_desc->actual_length);
40403 + }
40404 + /* Skip whole frame */
40405 + if (hc->qh->do_split && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) &&
40406 + hc->ep_is_in && hcd->core_if->dma_enable) {
40407 + qtd->complete_split = 0;
40408 + qtd->isoc_split_offset = 0;
40409 + }
40410 +
40411 + break;
40412 + default:
40413 + DWC_ASSERT(1, "Unhandled _halt_status (%d)\n", halt_status);
40414 + break;
40415 + }
40416 + if (++qtd->isoc_frame_index == urb->packet_count) {
40417 + /*
40418 + * urb->status is not used for isoc transfers.
40419 + * The individual frame_desc statuses are used instead.
40420 + */
40421 + hcd->fops->complete(hcd, urb->priv, urb, 0);
40422 + ret_val = DWC_OTG_HC_XFER_URB_COMPLETE;
40423 + } else {
40424 + ret_val = DWC_OTG_HC_XFER_COMPLETE;
40425 + }
40426 + return ret_val;
40427 +}
40428 +
40429 +/**
40430 + * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic
40431 + * QHs, removes the QH from the active non-periodic schedule. If any QTDs are
40432 + * still linked to the QH, the QH is added to the end of the inactive
40433 + * non-periodic schedule. For periodic QHs, removes the QH from the periodic
40434 + * schedule if no more QTDs are linked to the QH.
40435 + */
40436 +static void deactivate_qh(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, int free_qtd)
40437 +{
40438 + int continue_split = 0;
40439 + dwc_otg_qtd_t *qtd;
40440 +
40441 + DWC_DEBUGPL(DBG_HCDV, " %s(%p,%p,%d)\n", __func__, hcd, qh, free_qtd);
40442 +
40443 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
40444 +
40445 + if (qtd->complete_split) {
40446 + continue_split = 1;
40447 + } else if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID ||
40448 + qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END) {
40449 + continue_split = 1;
40450 + }
40451 +
40452 + if (free_qtd) {
40453 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
40454 + continue_split = 0;
40455 + }
40456 +
40457 + qh->channel = NULL;
40458 + dwc_otg_hcd_qh_deactivate(hcd, qh, continue_split);
40459 +}
40460 +
40461 +/**
40462 + * Releases a host channel for use by other transfers. Attempts to select and
40463 + * queue more transactions since at least one host channel is available.
40464 + *
40465 + * @param hcd The HCD state structure.
40466 + * @param hc The host channel to release.
40467 + * @param qtd The QTD associated with the host channel. This QTD may be freed
40468 + * if the transfer is complete or an error has occurred.
40469 + * @param halt_status Reason the channel is being released. This status
40470 + * determines the actions taken by this function.
40471 + */
40472 +static void release_channel(dwc_otg_hcd_t * hcd,
40473 + dwc_hc_t * hc,
40474 + dwc_otg_qtd_t * qtd,
40475 + dwc_otg_halt_status_e halt_status)
40476 +{
40477 + dwc_otg_transaction_type_e tr_type;
40478 + int free_qtd;
40479 + dwc_irqflags_t flags;
40480 + dwc_spinlock_t *channel_lock = hcd->channel_lock;
40481 +
40482 + DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n",
40483 + __func__, hc->hc_num, halt_status, hc->xfer_len);
40484 +
40485 + switch (halt_status) {
40486 + case DWC_OTG_HC_XFER_URB_COMPLETE:
40487 + free_qtd = 1;
40488 + break;
40489 + case DWC_OTG_HC_XFER_AHB_ERR:
40490 + case DWC_OTG_HC_XFER_STALL:
40491 + case DWC_OTG_HC_XFER_BABBLE_ERR:
40492 + free_qtd = 1;
40493 + break;
40494 + case DWC_OTG_HC_XFER_XACT_ERR:
40495 + if (qtd->error_count >= 3) {
40496 + DWC_DEBUGPL(DBG_HCDV,
40497 + " Complete URB with transaction error\n");
40498 + free_qtd = 1;
40499 + qtd->urb->status = -DWC_E_PROTOCOL;
40500 + hcd->fops->complete(hcd, qtd->urb->priv,
40501 + qtd->urb, -DWC_E_PROTOCOL);
40502 + } else {
40503 + free_qtd = 0;
40504 + }
40505 + break;
40506 + case DWC_OTG_HC_XFER_URB_DEQUEUE:
40507 + /*
40508 + * The QTD has already been removed and the QH has been
40509 + * deactivated. Don't want to do anything except release the
40510 + * host channel and try to queue more transfers.
40511 + */
40512 + goto cleanup;
40513 + case DWC_OTG_HC_XFER_NO_HALT_STATUS:
40514 + free_qtd = 0;
40515 + break;
40516 + case DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE:
40517 + DWC_DEBUGPL(DBG_HCDV,
40518 + " Complete URB with I/O error\n");
40519 + free_qtd = 1;
40520 + qtd->urb->status = -DWC_E_IO;
40521 + hcd->fops->complete(hcd, qtd->urb->priv,
40522 + qtd->urb, -DWC_E_IO);
40523 + break;
40524 + default:
40525 + free_qtd = 0;
40526 + break;
40527 + }
40528 +
40529 + deactivate_qh(hcd, hc->qh, free_qtd);
40530 +
40531 +cleanup:
40532 + /*
40533 + * Release the host channel for use by other transfers. The cleanup
40534 + * function clears the channel interrupt enables and conditions, so
40535 + * there's no need to clear the Channel Halted interrupt separately.
40536 + */
40537 + dwc_otg_hc_cleanup(hcd->core_if, hc);
40538 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
40539 +
40540 + if (!microframe_schedule) {
40541 + switch (hc->ep_type) {
40542 + case DWC_OTG_EP_TYPE_CONTROL:
40543 + case DWC_OTG_EP_TYPE_BULK:
40544 + hcd->non_periodic_channels--;
40545 + break;
40546 +
40547 + default:
40548 + /*
40549 + * Don't release reservations for periodic channels here.
40550 + * That's done when a periodic transfer is descheduled (i.e.
40551 + * when the QH is removed from the periodic schedule).
40552 + */
40553 + break;
40554 + }
40555 + } else {
40556 +
40557 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
40558 + hcd->available_host_channels++;
40559 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
40560 + }
40561 +
40562 + /* Try to queue more transfers now that there's a free channel. */
40563 + tr_type = dwc_otg_hcd_select_transactions(hcd);
40564 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
40565 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
40566 + }
40567 +}
40568 +
40569 +/**
40570 + * Halts a host channel. If the channel cannot be halted immediately because
40571 + * the request queue is full, this function ensures that the FIFO empty
40572 + * interrupt for the appropriate queue is enabled so that the halt request can
40573 + * be queued when there is space in the request queue.
40574 + *
40575 + * This function may also be called in DMA mode. In that case, the channel is
40576 + * simply released since the core always halts the channel automatically in
40577 + * DMA mode.
40578 + */
40579 +static void halt_channel(dwc_otg_hcd_t * hcd,
40580 + dwc_hc_t * hc,
40581 + dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
40582 +{
40583 + if (hcd->core_if->dma_enable) {
40584 + release_channel(hcd, hc, qtd, halt_status);
40585 + return;
40586 + }
40587 +
40588 + /* Slave mode processing... */
40589 + dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
40590 +
40591 + if (hc->halt_on_queue) {
40592 + gintmsk_data_t gintmsk = {.d32 = 0 };
40593 + dwc_otg_core_global_regs_t *global_regs;
40594 + global_regs = hcd->core_if->core_global_regs;
40595 +
40596 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
40597 + hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
40598 + /*
40599 + * Make sure the Non-periodic Tx FIFO empty interrupt
40600 + * is enabled so that the non-periodic schedule will
40601 + * be processed.
40602 + */
40603 + gintmsk.b.nptxfempty = 1;
40604 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
40605 + } else {
40606 + /*
40607 + * Move the QH from the periodic queued schedule to
40608 + * the periodic assigned schedule. This allows the
40609 + * halt to be queued when the periodic schedule is
40610 + * processed.
40611 + */
40612 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
40613 + &hc->qh->qh_list_entry);
40614 +
40615 + /*
40616 + * Make sure the Periodic Tx FIFO Empty interrupt is
40617 + * enabled so that the periodic schedule will be
40618 + * processed.
40619 + */
40620 + gintmsk.b.ptxfempty = 1;
40621 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
40622 + }
40623 + }
40624 +}
40625 +
40626 +/**
40627 + * Performs common cleanup for non-periodic transfers after a Transfer
40628 + * Complete interrupt. This function should be called after any endpoint type
40629 + * specific handling is finished to release the host channel.
40630 + */
40631 +static void complete_non_periodic_xfer(dwc_otg_hcd_t * hcd,
40632 + dwc_hc_t * hc,
40633 + dwc_otg_hc_regs_t * hc_regs,
40634 + dwc_otg_qtd_t * qtd,
40635 + dwc_otg_halt_status_e halt_status)
40636 +{
40637 + hcint_data_t hcint;
40638 +
40639 + qtd->error_count = 0;
40640 +
40641 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
40642 + if (hcint.b.nyet) {
40643 + /*
40644 + * Got a NYET on the last transaction of the transfer. This
40645 + * means that the endpoint should be in the PING state at the
40646 + * beginning of the next transfer.
40647 + */
40648 + hc->qh->ping_state = 1;
40649 + clear_hc_int(hc_regs, nyet);
40650 + }
40651 +
40652 + /*
40653 + * Always halt and release the host channel to make it available for
40654 + * more transfers. There may still be more phases for a control
40655 + * transfer or more data packets for a bulk transfer at this point,
40656 + * but the host channel is still halted. A channel will be reassigned
40657 + * to the transfer when the non-periodic schedule is processed after
40658 + * the channel is released. This allows transactions to be queued
40659 + * properly via dwc_otg_hcd_queue_transactions, which also enables the
40660 + * Tx FIFO Empty interrupt if necessary.
40661 + */
40662 + if (hc->ep_is_in) {
40663 + /*
40664 + * IN transfers in Slave mode require an explicit disable to
40665 + * halt the channel. (In DMA mode, this call simply releases
40666 + * the channel.)
40667 + */
40668 + halt_channel(hcd, hc, qtd, halt_status);
40669 + } else {
40670 + /*
40671 + * The channel is automatically disabled by the core for OUT
40672 + * transfers in Slave mode.
40673 + */
40674 + release_channel(hcd, hc, qtd, halt_status);
40675 + }
40676 +}
40677 +
40678 +/**
40679 + * Performs common cleanup for periodic transfers after a Transfer Complete
40680 + * interrupt. This function should be called after any endpoint type specific
40681 + * handling is finished to release the host channel.
40682 + */
40683 +static void complete_periodic_xfer(dwc_otg_hcd_t * hcd,
40684 + dwc_hc_t * hc,
40685 + dwc_otg_hc_regs_t * hc_regs,
40686 + dwc_otg_qtd_t * qtd,
40687 + dwc_otg_halt_status_e halt_status)
40688 +{
40689 + hctsiz_data_t hctsiz;
40690 + qtd->error_count = 0;
40691 +
40692 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40693 + if (!hc->ep_is_in || hctsiz.b.pktcnt == 0) {
40694 + /* Core halts channel in these cases. */
40695 + release_channel(hcd, hc, qtd, halt_status);
40696 + } else {
40697 + /* Flush any outstanding requests from the Tx queue. */
40698 + halt_channel(hcd, hc, qtd, halt_status);
40699 + }
40700 +}
40701 +
40702 +static int32_t handle_xfercomp_isoc_split_in(dwc_otg_hcd_t * hcd,
40703 + dwc_hc_t * hc,
40704 + dwc_otg_hc_regs_t * hc_regs,
40705 + dwc_otg_qtd_t * qtd)
40706 +{
40707 + uint32_t len;
40708 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
40709 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
40710 +
40711 + len = get_actual_xfer_length(hc, hc_regs, qtd,
40712 + DWC_OTG_HC_XFER_COMPLETE, NULL);
40713 +
40714 + if (!len) {
40715 + qtd->complete_split = 0;
40716 + qtd->isoc_split_offset = 0;
40717 + return 0;
40718 + }
40719 + frame_desc->actual_length += len;
40720 +
40721 + if (hc->align_buff && len)
40722 + dwc_memcpy(qtd->urb->buf + frame_desc->offset +
40723 + qtd->isoc_split_offset, hc->qh->dw_align_buf, len);
40724 + qtd->isoc_split_offset += len;
40725 +
40726 + if (frame_desc->length == frame_desc->actual_length) {
40727 + frame_desc->status = 0;
40728 + qtd->isoc_frame_index++;
40729 + qtd->complete_split = 0;
40730 + qtd->isoc_split_offset = 0;
40731 + }
40732 +
40733 + if (qtd->isoc_frame_index == qtd->urb->packet_count) {
40734 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
40735 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
40736 + } else {
40737 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
40738 + }
40739 +
40740 + return 1; /* Indicates that channel released */
40741 +}
40742 +
40743 +/**
40744 + * Handles a host channel Transfer Complete interrupt. This handler may be
40745 + * called in either DMA mode or Slave mode.
40746 + */
40747 +static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t * hcd,
40748 + dwc_hc_t * hc,
40749 + dwc_otg_hc_regs_t * hc_regs,
40750 + dwc_otg_qtd_t * qtd)
40751 +{
40752 + int urb_xfer_done;
40753 + dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE;
40754 + dwc_otg_hcd_urb_t *urb = qtd->urb;
40755 + int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
40756 +
40757 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
40758 + "Transfer Complete--\n", hc->hc_num);
40759 +
40760 + if (hcd->core_if->dma_desc_enable) {
40761 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, halt_status);
40762 + if (pipe_type == UE_ISOCHRONOUS) {
40763 + /* Do not disable the interrupt, just clear it */
40764 + clear_hc_int(hc_regs, xfercomp);
40765 + return 1;
40766 + }
40767 + goto handle_xfercomp_done;
40768 + }
40769 +
40770 + /*
40771 + * Handle xfer complete on CSPLIT.
40772 + */
40773 +
40774 + if (hc->qh->do_split) {
40775 + if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hc->ep_is_in
40776 + && hcd->core_if->dma_enable) {
40777 + if (qtd->complete_split
40778 + && handle_xfercomp_isoc_split_in(hcd, hc, hc_regs,
40779 + qtd))
40780 + goto handle_xfercomp_done;
40781 + } else {
40782 + qtd->complete_split = 0;
40783 + }
40784 + }
40785 +
40786 + /* Update the QTD and URB states. */
40787 + switch (pipe_type) {
40788 + case UE_CONTROL:
40789 + switch (qtd->control_phase) {
40790 + case DWC_OTG_CONTROL_SETUP:
40791 + if (urb->length > 0) {
40792 + qtd->control_phase = DWC_OTG_CONTROL_DATA;
40793 + } else {
40794 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
40795 + }
40796 + DWC_DEBUGPL(DBG_HCDV,
40797 + " Control setup transaction done\n");
40798 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40799 + break;
40800 + case DWC_OTG_CONTROL_DATA:{
40801 + urb_xfer_done =
40802 + update_urb_state_xfer_comp(hc, hc_regs, urb,
40803 + qtd);
40804 + if (urb_xfer_done) {
40805 + qtd->control_phase =
40806 + DWC_OTG_CONTROL_STATUS;
40807 + DWC_DEBUGPL(DBG_HCDV,
40808 + " Control data transfer done\n");
40809 + } else {
40810 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
40811 + }
40812 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40813 + break;
40814 + }
40815 + case DWC_OTG_CONTROL_STATUS:
40816 + DWC_DEBUGPL(DBG_HCDV, " Control transfer complete\n");
40817 + if (urb->status == -DWC_E_IN_PROGRESS) {
40818 + urb->status = 0;
40819 + }
40820 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
40821 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
40822 + break;
40823 + }
40824 +
40825 + complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40826 + break;
40827 + case UE_BULK:
40828 + DWC_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n");
40829 + urb_xfer_done =
40830 + update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
40831 + if (urb_xfer_done) {
40832 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
40833 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
40834 + } else {
40835 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40836 + }
40837 +
40838 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
40839 + complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40840 + break;
40841 + case UE_INTERRUPT:
40842 + DWC_DEBUGPL(DBG_HCDV, " Interrupt transfer complete\n");
40843 + urb_xfer_done =
40844 + update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
40845 +
40846 + /*
40847 + * Interrupt URB is done on the first transfer complete
40848 + * interrupt.
40849 + */
40850 + if (urb_xfer_done) {
40851 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
40852 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
40853 + } else {
40854 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40855 + }
40856 +
40857 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
40858 + complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40859 + break;
40860 + case UE_ISOCHRONOUS:
40861 + DWC_DEBUGPL(DBG_HCDV, " Isochronous transfer complete\n");
40862 + if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) {
40863 + halt_status =
40864 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
40865 + DWC_OTG_HC_XFER_COMPLETE);
40866 + }
40867 + complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40868 + break;
40869 + }
40870 +
40871 +handle_xfercomp_done:
40872 + disable_hc_int(hc_regs, xfercompl);
40873 +
40874 + return 1;
40875 +}
40876 +
40877 +/**
40878 + * Handles a host channel STALL interrupt. This handler may be called in
40879 + * either DMA mode or Slave mode.
40880 + */
40881 +static int32_t handle_hc_stall_intr(dwc_otg_hcd_t * hcd,
40882 + dwc_hc_t * hc,
40883 + dwc_otg_hc_regs_t * hc_regs,
40884 + dwc_otg_qtd_t * qtd)
40885 +{
40886 + dwc_otg_hcd_urb_t *urb = qtd->urb;
40887 + int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
40888 +
40889 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
40890 + "STALL Received--\n", hc->hc_num);
40891 +
40892 + if (hcd->core_if->dma_desc_enable) {
40893 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_STALL);
40894 + goto handle_stall_done;
40895 + }
40896 +
40897 + if (pipe_type == UE_CONTROL) {
40898 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
40899 + }
40900 +
40901 + if (pipe_type == UE_BULK || pipe_type == UE_INTERRUPT) {
40902 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
40903 + /*
40904 + * USB protocol requires resetting the data toggle for bulk
40905 + * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
40906 + * setup command is issued to the endpoint. Anticipate the
40907 + * CLEAR_FEATURE command since a STALL has occurred and reset
40908 + * the data toggle now.
40909 + */
40910 + hc->qh->data_toggle = 0;
40911 + }
40912 +
40913 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_STALL);
40914 +
40915 +handle_stall_done:
40916 + disable_hc_int(hc_regs, stall);
40917 +
40918 + return 1;
40919 +}
40920 +
40921 +/*
40922 + * Updates the state of the URB when a transfer has been stopped due to an
40923 + * abnormal condition before the transfer completes. Modifies the
40924 + * actual_length field of the URB to reflect the number of bytes that have
40925 + * actually been transferred via the host channel.
40926 + */
40927 +static void update_urb_state_xfer_intr(dwc_hc_t * hc,
40928 + dwc_otg_hc_regs_t * hc_regs,
40929 + dwc_otg_hcd_urb_t * urb,
40930 + dwc_otg_qtd_t * qtd,
40931 + dwc_otg_halt_status_e halt_status)
40932 +{
40933 + uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd,
40934 + halt_status, NULL);
40935 + /* non DWORD-aligned buffer case handling. */
40936 + if (hc->align_buff && bytes_transferred && hc->ep_is_in) {
40937 + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
40938 + bytes_transferred);
40939 + }
40940 +
40941 + urb->actual_length += bytes_transferred;
40942 +
40943 +#ifdef DEBUG
40944 + {
40945 + hctsiz_data_t hctsiz;
40946 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40947 + DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
40948 + __func__, (hc->ep_is_in ? "IN" : "OUT"),
40949 + hc->hc_num);
40950 + DWC_DEBUGPL(DBG_HCDV, " hc->start_pkt_count %d\n",
40951 + hc->start_pkt_count);
40952 + DWC_DEBUGPL(DBG_HCDV, " hctsiz.pktcnt %d\n", hctsiz.b.pktcnt);
40953 + DWC_DEBUGPL(DBG_HCDV, " hc->max_packet %d\n", hc->max_packet);
40954 + DWC_DEBUGPL(DBG_HCDV, " bytes_transferred %d\n",
40955 + bytes_transferred);
40956 + DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n",
40957 + urb->actual_length);
40958 + DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n",
40959 + urb->length);
40960 + }
40961 +#endif
40962 +}
40963 +
40964 +/**
40965 + * Handles a host channel NAK interrupt. This handler may be called in either
40966 + * DMA mode or Slave mode.
40967 + */
40968 +static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd,
40969 + dwc_hc_t * hc,
40970 + dwc_otg_hc_regs_t * hc_regs,
40971 + dwc_otg_qtd_t * qtd)
40972 +{
40973 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
40974 + "NAK Received--\n", hc->hc_num);
40975 +
40976 + /*
40977 + * When we get bulk NAKs then remember this so we holdoff on this qh until
40978 + * the beginning of the next frame
40979 + */
40980 + switch(dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
40981 + case UE_BULK:
40982 + //case UE_INTERRUPT:
40983 + //case UE_CONTROL:
40984 + if (nak_holdoff_enable)
40985 + hc->qh->nak_frame = dwc_otg_hcd_get_frame_number(hcd);
40986 + }
40987 +
40988 + /*
40989 + * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
40990 + * interrupt. Re-start the SSPLIT transfer.
40991 + */
40992 + if (hc->do_split) {
40993 + if (hc->complete_split) {
40994 + qtd->error_count = 0;
40995 + }
40996 + qtd->complete_split = 0;
40997 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
40998 + goto handle_nak_done;
40999 + }
41000 +
41001 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
41002 + case UE_CONTROL:
41003 + case UE_BULK:
41004 + if (hcd->core_if->dma_enable && hc->ep_is_in) {
41005 + /*
41006 + * NAK interrupts are enabled on bulk/control IN
41007 + * transfers in DMA mode for the sole purpose of
41008 + * resetting the error count after a transaction error
41009 + * occurs. The core will continue transferring data.
41010 + */
41011 + qtd->error_count = 0;
41012 + goto handle_nak_done;
41013 + }
41014 +
41015 + /*
41016 + * NAK interrupts normally occur during OUT transfers in DMA
41017 + * or Slave mode. For IN transfers, more requests will be
41018 + * queued as request queue space is available.
41019 + */
41020 + qtd->error_count = 0;
41021 +
41022 + if (!hc->qh->ping_state) {
41023 + update_urb_state_xfer_intr(hc, hc_regs,
41024 + qtd->urb, qtd,
41025 + DWC_OTG_HC_XFER_NAK);
41026 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41027 +
41028 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH)
41029 + hc->qh->ping_state = 1;
41030 + }
41031 +
41032 + /*
41033 + * Halt the channel so the transfer can be re-started from
41034 + * the appropriate point or the PING protocol will
41035 + * start/continue.
41036 + */
41037 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
41038 + break;
41039 + case UE_INTERRUPT:
41040 + qtd->error_count = 0;
41041 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
41042 + break;
41043 + case UE_ISOCHRONOUS:
41044 + /* Should never get called for isochronous transfers. */
41045 + DWC_ASSERT(1, "NACK interrupt for ISOC transfer\n");
41046 + break;
41047 + }
41048 +
41049 +handle_nak_done:
41050 + disable_hc_int(hc_regs, nak);
41051 +
41052 + return 1;
41053 +}
41054 +
41055 +/**
41056 + * Handles a host channel ACK interrupt. This interrupt is enabled when
41057 + * performing the PING protocol in Slave mode, when errors occur during
41058 + * either Slave mode or DMA mode, and during Start Split transactions.
41059 + */
41060 +static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd,
41061 + dwc_hc_t * hc,
41062 + dwc_otg_hc_regs_t * hc_regs,
41063 + dwc_otg_qtd_t * qtd)
41064 +{
41065 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41066 + "ACK Received--\n", hc->hc_num);
41067 +
41068 + if (hc->do_split) {
41069 + /*
41070 + * Handle ACK on SSPLIT.
41071 + * ACK should not occur in CSPLIT.
41072 + */
41073 + if (!hc->ep_is_in && hc->data_pid_start != DWC_OTG_HC_PID_SETUP) {
41074 + qtd->ssplit_out_xfer_count = hc->xfer_len;
41075 + }
41076 + if (!(hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in)) {
41077 + /* Don't need complete for isochronous out transfers. */
41078 + qtd->complete_split = 1;
41079 + }
41080 +
41081 + /* ISOC OUT */
41082 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
41083 + switch (hc->xact_pos) {
41084 + case DWC_HCSPLIT_XACTPOS_ALL:
41085 + break;
41086 + case DWC_HCSPLIT_XACTPOS_END:
41087 + qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
41088 + qtd->isoc_split_offset = 0;
41089 + break;
41090 + case DWC_HCSPLIT_XACTPOS_BEGIN:
41091 + case DWC_HCSPLIT_XACTPOS_MID:
41092 + /*
41093 + * For BEGIN or MID, calculate the length for
41094 + * the next microframe to determine the correct
41095 + * SSPLIT token, either MID or END.
41096 + */
41097 + {
41098 + struct dwc_otg_hcd_iso_packet_desc
41099 + *frame_desc;
41100 +
41101 + frame_desc =
41102 + &qtd->urb->
41103 + iso_descs[qtd->isoc_frame_index];
41104 + qtd->isoc_split_offset += 188;
41105 +
41106 + if ((frame_desc->length -
41107 + qtd->isoc_split_offset) <= 188) {
41108 + qtd->isoc_split_pos =
41109 + DWC_HCSPLIT_XACTPOS_END;
41110 + } else {
41111 + qtd->isoc_split_pos =
41112 + DWC_HCSPLIT_XACTPOS_MID;
41113 + }
41114 +
41115 + }
41116 + break;
41117 + }
41118 + } else {
41119 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
41120 + }
41121 + } else {
41122 + qtd->error_count = 0;
41123 +
41124 + if (hc->qh->ping_state) {
41125 + hc->qh->ping_state = 0;
41126 + /*
41127 + * Halt the channel so the transfer can be re-started
41128 + * from the appropriate point. This only happens in
41129 + * Slave mode. In DMA mode, the ping_state is cleared
41130 + * when the transfer is started because the core
41131 + * automatically executes the PING, then the transfer.
41132 + */
41133 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
41134 + }
41135 + }
41136 +
41137 + /*
41138 + * If the ACK occurred when _not_ in the PING state, let the channel
41139 + * continue transferring data after clearing the error count.
41140 + */
41141 +
41142 + disable_hc_int(hc_regs, ack);
41143 +
41144 + return 1;
41145 +}
41146 +
41147 +/**
41148 + * Handles a host channel NYET interrupt. This interrupt should only occur on
41149 + * Bulk and Control OUT endpoints and for complete split transactions. If a
41150 + * NYET occurs at the same time as a Transfer Complete interrupt, it is
41151 + * handled in the xfercomp interrupt handler, not here. This handler may be
41152 + * called in either DMA mode or Slave mode.
41153 + */
41154 +static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd,
41155 + dwc_hc_t * hc,
41156 + dwc_otg_hc_regs_t * hc_regs,
41157 + dwc_otg_qtd_t * qtd)
41158 +{
41159 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41160 + "NYET Received--\n", hc->hc_num);
41161 +
41162 + /*
41163 + * NYET on CSPLIT
41164 + * re-do the CSPLIT immediately on non-periodic
41165 + */
41166 + if (hc->do_split && hc->complete_split) {
41167 + if (hc->ep_is_in && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
41168 + && hcd->core_if->dma_enable) {
41169 + qtd->complete_split = 0;
41170 + qtd->isoc_split_offset = 0;
41171 + if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
41172 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
41173 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
41174 + }
41175 + else
41176 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
41177 + goto handle_nyet_done;
41178 + }
41179 +
41180 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
41181 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
41182 + int frnum = dwc_otg_hcd_get_frame_number(hcd);
41183 +
41184 + if (dwc_full_frame_num(frnum) !=
41185 + dwc_full_frame_num(hc->qh->sched_frame)) {
41186 + /*
41187 + * No longer in the same full speed frame.
41188 + * Treat this as a transaction error.
41189 + */
41190 +#if 0
41191 + /** @todo Fix system performance so this can
41192 + * be treated as an error. Right now complete
41193 + * splits cannot be scheduled precisely enough
41194 + * due to other system activity, so this error
41195 + * occurs regularly in Slave mode.
41196 + */
41197 + qtd->error_count++;
41198 +#endif
41199 + qtd->complete_split = 0;
41200 + halt_channel(hcd, hc, qtd,
41201 + DWC_OTG_HC_XFER_XACT_ERR);
41202 + /** @todo add support for isoc release */
41203 + goto handle_nyet_done;
41204 + }
41205 + }
41206 +
41207 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
41208 + goto handle_nyet_done;
41209 + }
41210 +
41211 + hc->qh->ping_state = 1;
41212 + qtd->error_count = 0;
41213 +
41214 + update_urb_state_xfer_intr(hc, hc_regs, qtd->urb, qtd,
41215 + DWC_OTG_HC_XFER_NYET);
41216 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41217 +
41218 + /*
41219 + * Halt the channel and re-start the transfer so the PING
41220 + * protocol will start.
41221 + */
41222 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
41223 +
41224 +handle_nyet_done:
41225 + disable_hc_int(hc_regs, nyet);
41226 + return 1;
41227 +}
41228 +
41229 +/**
41230 + * Handles a host channel babble interrupt. This handler may be called in
41231 + * either DMA mode or Slave mode.
41232 + */
41233 +static int32_t handle_hc_babble_intr(dwc_otg_hcd_t * hcd,
41234 + dwc_hc_t * hc,
41235 + dwc_otg_hc_regs_t * hc_regs,
41236 + dwc_otg_qtd_t * qtd)
41237 +{
41238 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41239 + "Babble Error--\n", hc->hc_num);
41240 +
41241 + if (hcd->core_if->dma_desc_enable) {
41242 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41243 + DWC_OTG_HC_XFER_BABBLE_ERR);
41244 + goto handle_babble_done;
41245 + }
41246 +
41247 + if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
41248 + hcd->fops->complete(hcd, qtd->urb->priv,
41249 + qtd->urb, -DWC_E_OVERFLOW);
41250 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_BABBLE_ERR);
41251 + } else {
41252 + dwc_otg_halt_status_e halt_status;
41253 + halt_status = update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41254 + DWC_OTG_HC_XFER_BABBLE_ERR);
41255 + halt_channel(hcd, hc, qtd, halt_status);
41256 + }
41257 +
41258 +handle_babble_done:
41259 + disable_hc_int(hc_regs, bblerr);
41260 + return 1;
41261 +}
41262 +
41263 +/**
41264 + * Handles a host channel AHB error interrupt. This handler is only called in
41265 + * DMA mode.
41266 + */
41267 +static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t * hcd,
41268 + dwc_hc_t * hc,
41269 + dwc_otg_hc_regs_t * hc_regs,
41270 + dwc_otg_qtd_t * qtd)
41271 +{
41272 + hcchar_data_t hcchar;
41273 + hcsplt_data_t hcsplt;
41274 + hctsiz_data_t hctsiz;
41275 + uint32_t hcdma;
41276 + char *pipetype, *speed;
41277 +
41278 + dwc_otg_hcd_urb_t *urb = qtd->urb;
41279 +
41280 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41281 + "AHB Error--\n", hc->hc_num);
41282 +
41283 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
41284 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
41285 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
41286 + hcdma = DWC_READ_REG32(&hc_regs->hcdma);
41287 +
41288 + DWC_ERROR("AHB ERROR, Channel %d\n", hc->hc_num);
41289 + DWC_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);
41290 + DWC_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);
41291 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n");
41292 + DWC_ERROR(" Device address: %d\n",
41293 + dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
41294 + DWC_ERROR(" Endpoint: %d, %s\n",
41295 + dwc_otg_hcd_get_ep_num(&urb->pipe_info),
41296 + (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT"));
41297 +
41298 + switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
41299 + case UE_CONTROL:
41300 + pipetype = "CONTROL";
41301 + break;
41302 + case UE_BULK:
41303 + pipetype = "BULK";
41304 + break;
41305 + case UE_INTERRUPT:
41306 + pipetype = "INTERRUPT";
41307 + break;
41308 + case UE_ISOCHRONOUS:
41309 + pipetype = "ISOCHRONOUS";
41310 + break;
41311 + default:
41312 + pipetype = "UNKNOWN";
41313 + break;
41314 + }
41315 +
41316 + DWC_ERROR(" Endpoint type: %s\n", pipetype);
41317 +
41318 + switch (hc->speed) {
41319 + case DWC_OTG_EP_SPEED_HIGH:
41320 + speed = "HIGH";
41321 + break;
41322 + case DWC_OTG_EP_SPEED_FULL:
41323 + speed = "FULL";
41324 + break;
41325 + case DWC_OTG_EP_SPEED_LOW:
41326 + speed = "LOW";
41327 + break;
41328 + default:
41329 + speed = "UNKNOWN";
41330 + break;
41331 + };
41332 +
41333 + DWC_ERROR(" Speed: %s\n", speed);
41334 +
41335 + DWC_ERROR(" Max packet size: %d\n",
41336 + dwc_otg_hcd_get_mps(&urb->pipe_info));
41337 + DWC_ERROR(" Data buffer length: %d\n", urb->length);
41338 + DWC_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n",
41339 + urb->buf, (void *)urb->dma);
41340 + DWC_ERROR(" Setup buffer: %p, Setup DMA: %p\n",
41341 + urb->setup_packet, (void *)urb->setup_dma);
41342 + DWC_ERROR(" Interval: %d\n", urb->interval);
41343 +
41344 + /* Core haltes the channel for Descriptor DMA mode */
41345 + if (hcd->core_if->dma_desc_enable) {
41346 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41347 + DWC_OTG_HC_XFER_AHB_ERR);
41348 + goto handle_ahberr_done;
41349 + }
41350 +
41351 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_IO);
41352 +
41353 + /*
41354 + * Force a channel halt. Don't call halt_channel because that won't
41355 + * write to the HCCHARn register in DMA mode to force the halt.
41356 + */
41357 + dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_AHB_ERR);
41358 +handle_ahberr_done:
41359 + disable_hc_int(hc_regs, ahberr);
41360 + return 1;
41361 +}
41362 +
41363 +/**
41364 + * Handles a host channel transaction error interrupt. This handler may be
41365 + * called in either DMA mode or Slave mode.
41366 + */
41367 +static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t * hcd,
41368 + dwc_hc_t * hc,
41369 + dwc_otg_hc_regs_t * hc_regs,
41370 + dwc_otg_qtd_t * qtd)
41371 +{
41372 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41373 + "Transaction Error--\n", hc->hc_num);
41374 +
41375 + if (hcd->core_if->dma_desc_enable) {
41376 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41377 + DWC_OTG_HC_XFER_XACT_ERR);
41378 + goto handle_xacterr_done;
41379 + }
41380 +
41381 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
41382 + case UE_CONTROL:
41383 + case UE_BULK:
41384 + qtd->error_count++;
41385 + if (!hc->qh->ping_state) {
41386 +
41387 + update_urb_state_xfer_intr(hc, hc_regs,
41388 + qtd->urb, qtd,
41389 + DWC_OTG_HC_XFER_XACT_ERR);
41390 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41391 + if (!hc->ep_is_in && hc->speed == DWC_OTG_EP_SPEED_HIGH) {
41392 + hc->qh->ping_state = 1;
41393 + }
41394 + }
41395 +
41396 + /*
41397 + * Halt the channel so the transfer can be re-started from
41398 + * the appropriate point or the PING protocol will start.
41399 + */
41400 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
41401 + break;
41402 + case UE_INTERRUPT:
41403 + qtd->error_count++;
41404 + if (hc->do_split && hc->complete_split) {
41405 + qtd->complete_split = 0;
41406 + }
41407 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
41408 + break;
41409 + case UE_ISOCHRONOUS:
41410 + {
41411 + dwc_otg_halt_status_e halt_status;
41412 + halt_status =
41413 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41414 + DWC_OTG_HC_XFER_XACT_ERR);
41415 +
41416 + halt_channel(hcd, hc, qtd, halt_status);
41417 + }
41418 + break;
41419 + }
41420 +handle_xacterr_done:
41421 + disable_hc_int(hc_regs, xacterr);
41422 +
41423 + return 1;
41424 +}
41425 +
41426 +/**
41427 + * Handles a host channel frame overrun interrupt. This handler may be called
41428 + * in either DMA mode or Slave mode.
41429 + */
41430 +static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t * hcd,
41431 + dwc_hc_t * hc,
41432 + dwc_otg_hc_regs_t * hc_regs,
41433 + dwc_otg_qtd_t * qtd)
41434 +{
41435 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41436 + "Frame Overrun--\n", hc->hc_num);
41437 +
41438 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
41439 + case UE_CONTROL:
41440 + case UE_BULK:
41441 + break;
41442 + case UE_INTERRUPT:
41443 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN);
41444 + break;
41445 + case UE_ISOCHRONOUS:
41446 + {
41447 + dwc_otg_halt_status_e halt_status;
41448 + halt_status =
41449 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41450 + DWC_OTG_HC_XFER_FRAME_OVERRUN);
41451 +
41452 + halt_channel(hcd, hc, qtd, halt_status);
41453 + }
41454 + break;
41455 + }
41456 +
41457 + disable_hc_int(hc_regs, frmovrun);
41458 +
41459 + return 1;
41460 +}
41461 +
41462 +/**
41463 + * Handles a host channel data toggle error interrupt. This handler may be
41464 + * called in either DMA mode or Slave mode.
41465 + */
41466 +static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd,
41467 + dwc_hc_t * hc,
41468 + dwc_otg_hc_regs_t * hc_regs,
41469 + dwc_otg_qtd_t * qtd)
41470 +{
41471 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41472 + "Data Toggle Error on %s transfer--\n",
41473 + hc->hc_num, (hc->ep_is_in ? "IN" : "OUT"));
41474 +
41475 + /* Data toggles on split transactions cause the hc to halt.
41476 + * restart transfer */
41477 + if(hc->qh->do_split)
41478 + {
41479 + qtd->error_count++;
41480 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41481 + update_urb_state_xfer_intr(hc, hc_regs,
41482 + qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR);
41483 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
41484 + } else if (hc->ep_is_in) {
41485 + qtd->error_count = 0;
41486 + }
41487 +
41488 + disable_hc_int(hc_regs, datatglerr);
41489 +
41490 + return 1;
41491 +}
41492 +
41493 +#ifdef DEBUG
41494 +/**
41495 + * This function is for debug only. It checks that a valid halt status is set
41496 + * and that HCCHARn.chdis is clear. If there's a problem, corrective action is
41497 + * taken and a warning is issued.
41498 + * @return 1 if halt status is ok, 0 otherwise.
41499 + */
41500 +static inline int halt_status_ok(dwc_otg_hcd_t * hcd,
41501 + dwc_hc_t * hc,
41502 + dwc_otg_hc_regs_t * hc_regs,
41503 + dwc_otg_qtd_t * qtd)
41504 +{
41505 + hcchar_data_t hcchar;
41506 + hctsiz_data_t hctsiz;
41507 + hcint_data_t hcint;
41508 + hcintmsk_data_t hcintmsk;
41509 + hcsplt_data_t hcsplt;
41510 +
41511 + if (hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) {
41512 + /*
41513 + * This code is here only as a check. This condition should
41514 + * never happen. Ignore the halt if it does occur.
41515 + */
41516 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
41517 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
41518 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
41519 + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
41520 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
41521 + DWC_WARN
41522 + ("%s: hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, "
41523 + "channel %d, hcchar 0x%08x, hctsiz 0x%08x, "
41524 + "hcint 0x%08x, hcintmsk 0x%08x, "
41525 + "hcsplt 0x%08x, qtd->complete_split %d\n", __func__,
41526 + hc->hc_num, hcchar.d32, hctsiz.d32, hcint.d32,
41527 + hcintmsk.d32, hcsplt.d32, qtd->complete_split);
41528 +
41529 + DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n",
41530 + __func__, hc->hc_num);
41531 + DWC_WARN("\n");
41532 + clear_hc_int(hc_regs, chhltd);
41533 + return 0;
41534 + }
41535 +
41536 + /*
41537 + * This code is here only as a check. hcchar.chdis should
41538 + * never be set when the halt interrupt occurs. Halt the
41539 + * channel again if it does occur.
41540 + */
41541 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
41542 + if (hcchar.b.chdis) {
41543 + DWC_WARN("%s: hcchar.chdis set unexpectedly, "
41544 + "hcchar 0x%08x, trying to halt again\n",
41545 + __func__, hcchar.d32);
41546 + clear_hc_int(hc_regs, chhltd);
41547 + hc->halt_pending = 0;
41548 + halt_channel(hcd, hc, qtd, hc->halt_status);
41549 + return 0;
41550 + }
41551 +
41552 + return 1;
41553 +}
41554 +#endif
41555 +
41556 +/**
41557 + * Handles a host Channel Halted interrupt in DMA mode. This handler
41558 + * determines the reason the channel halted and proceeds accordingly.
41559 + */
41560 +static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd,
41561 + dwc_hc_t * hc,
41562 + dwc_otg_hc_regs_t * hc_regs,
41563 + dwc_otg_qtd_t * qtd)
41564 +{
41565 + hcint_data_t hcint;
41566 + hcintmsk_data_t hcintmsk;
41567 + int out_nak_enh = 0;
41568 +
41569 + /* For core with OUT NAK enhancement, the flow for high-
41570 + * speed CONTROL/BULK OUT is handled a little differently.
41571 + */
41572 + if (hcd->core_if->snpsid >= OTG_CORE_REV_2_71a) {
41573 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH && !hc->ep_is_in &&
41574 + (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
41575 + hc->ep_type == DWC_OTG_EP_TYPE_BULK)) {
41576 + out_nak_enh = 1;
41577 + }
41578 + }
41579 +
41580 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
41581 + (hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR
41582 + && !hcd->core_if->dma_desc_enable)) {
41583 + /*
41584 + * Just release the channel. A dequeue can happen on a
41585 + * transfer timeout. In the case of an AHB Error, the channel
41586 + * was forced to halt because there's no way to gracefully
41587 + * recover.
41588 + */
41589 + if (hcd->core_if->dma_desc_enable)
41590 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41591 + hc->halt_status);
41592 + else
41593 + release_channel(hcd, hc, qtd, hc->halt_status);
41594 + return;
41595 + }
41596 +
41597 + /* Read the HCINTn register to determine the cause for the halt. */
41598 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
41599 + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
41600 +
41601 + if (hcint.b.xfercomp) {
41602 + /** @todo This is here because of a possible hardware bug. Spec
41603 + * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT
41604 + * interrupt w/ACK bit set should occur, but I only see the
41605 + * XFERCOMP bit, even with it masked out. This is a workaround
41606 + * for that behavior. Should fix this when hardware is fixed.
41607 + */
41608 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
41609 + handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
41610 + }
41611 + handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd);
41612 + } else if (hcint.b.stall) {
41613 + handle_hc_stall_intr(hcd, hc, hc_regs, qtd);
41614 + } else if (hcint.b.xacterr && !hcd->core_if->dma_desc_enable) {
41615 + if (out_nak_enh) {
41616 + if (hcint.b.nyet || hcint.b.nak || hcint.b.ack) {
41617 + DWC_DEBUGPL(DBG_HCD, "XactErr with NYET/NAK/ACK\n");
41618 + qtd->error_count = 0;
41619 + } else {
41620 + DWC_DEBUGPL(DBG_HCD, "XactErr without NYET/NAK/ACK\n");
41621 + }
41622 + }
41623 +
41624 + /*
41625 + * Must handle xacterr before nak or ack. Could get a xacterr
41626 + * at the same time as either of these on a BULK/CONTROL OUT
41627 + * that started with a PING. The xacterr takes precedence.
41628 + */
41629 + handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
41630 + } else if (hcint.b.xcs_xact && hcd->core_if->dma_desc_enable) {
41631 + handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
41632 + } else if (hcint.b.ahberr && hcd->core_if->dma_desc_enable) {
41633 + handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd);
41634 + } else if (hcint.b.bblerr) {
41635 + handle_hc_babble_intr(hcd, hc, hc_regs, qtd);
41636 + } else if (hcint.b.frmovrun) {
41637 + handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd);
41638 + } else if (hcint.b.datatglerr) {
41639 + handle_hc_datatglerr_intr(hcd, hc, hc_regs, qtd);
41640 + } else if (!out_nak_enh) {
41641 + if (hcint.b.nyet) {
41642 + /*
41643 + * Must handle nyet before nak or ack. Could get a nyet at the
41644 + * same time as either of those on a BULK/CONTROL OUT that
41645 + * started with a PING. The nyet takes precedence.
41646 + */
41647 + handle_hc_nyet_intr(hcd, hc, hc_regs, qtd);
41648 + } else if (hcint.b.nak && !hcintmsk.b.nak) {
41649 + /*
41650 + * If nak is not masked, it's because a non-split IN transfer
41651 + * is in an error state. In that case, the nak is handled by
41652 + * the nak interrupt handler, not here. Handle nak here for
41653 + * BULK/CONTROL OUT transfers, which halt on a NAK to allow
41654 + * rewinding the buffer pointer.
41655 + */
41656 + handle_hc_nak_intr(hcd, hc, hc_regs, qtd);
41657 + } else if (hcint.b.ack && !hcintmsk.b.ack) {
41658 + /*
41659 + * If ack is not masked, it's because a non-split IN transfer
41660 + * is in an error state. In that case, the ack is handled by
41661 + * the ack interrupt handler, not here. Handle ack here for
41662 + * split transfers. Start splits halt on ACK.
41663 + */
41664 + handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
41665 + } else {
41666 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
41667 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
41668 + /*
41669 + * A periodic transfer halted with no other channel
41670 + * interrupts set. Assume it was halted by the core
41671 + * because it could not be completed in its scheduled
41672 + * (micro)frame.
41673 + */
41674 +#ifdef DEBUG
41675 + DWC_PRINTF
41676 + ("%s: Halt channel %d (assume incomplete periodic transfer)\n",
41677 + __func__, hc->hc_num);
41678 +#endif
41679 + halt_channel(hcd, hc, qtd,
41680 + DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE);
41681 + } else {
41682 + DWC_ERROR
41683 + ("%s: Channel %d, DMA Mode -- ChHltd set, but reason "
41684 + "for halting is unknown, hcint 0x%08x, intsts 0x%08x\n",
41685 + __func__, hc->hc_num, hcint.d32,
41686 + DWC_READ_REG32(&hcd->
41687 + core_if->core_global_regs->
41688 + gintsts));
41689 + }
41690 +
41691 + }
41692 + } else {
41693 + DWC_PRINTF("NYET/NAK/ACK/other in non-error case, 0x%08x\n",
41694 + hcint.d32);
41695 + }
41696 +}
41697 +
41698 +/**
41699 + * Handles a host channel Channel Halted interrupt.
41700 + *
41701 + * In slave mode, this handler is called only when the driver specifically
41702 + * requests a halt. This occurs during handling other host channel interrupts
41703 + * (e.g. nak, xacterr, stall, nyet, etc.).
41704 + *
41705 + * In DMA mode, this is the interrupt that occurs when the core has finished
41706 + * processing a transfer on a channel. Other host channel interrupts (except
41707 + * ahberr) are disabled in DMA mode.
41708 + */
41709 +static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd,
41710 + dwc_hc_t * hc,
41711 + dwc_otg_hc_regs_t * hc_regs,
41712 + dwc_otg_qtd_t * qtd)
41713 +{
41714 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41715 + "Channel Halted--\n", hc->hc_num);
41716 +
41717 + if (hcd->core_if->dma_enable) {
41718 + handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd);
41719 + } else {
41720 +#ifdef DEBUG
41721 + if (!halt_status_ok(hcd, hc, hc_regs, qtd)) {
41722 + return 1;
41723 + }
41724 +#endif
41725 + release_channel(hcd, hc, qtd, hc->halt_status);
41726 + }
41727 +
41728 + return 1;
41729 +}
41730 +
41731 +/** Handles interrupt for a specific Host Channel */
41732 +int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
41733 +{
41734 + int retval = 0;
41735 + hcint_data_t hcint;
41736 + hcintmsk_data_t hcintmsk;
41737 + dwc_hc_t *hc;
41738 + dwc_otg_hc_regs_t *hc_regs;
41739 + dwc_otg_qtd_t *qtd;
41740 +
41741 + DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", num);
41742 +
41743 + hc = dwc_otg_hcd->hc_ptr_array[num];
41744 + hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num];
41745 + qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
41746 +
41747 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
41748 + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
41749 + DWC_DEBUGPL(DBG_HCDV,
41750 + " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
41751 + hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));
41752 + hcint.d32 = hcint.d32 & hcintmsk.d32;
41753 +
41754 + if (!dwc_otg_hcd->core_if->dma_enable) {
41755 + if (hcint.b.chhltd && hcint.d32 != 0x2) {
41756 + hcint.b.chhltd = 0;
41757 + }
41758 + }
41759 +
41760 + if (hcint.b.xfercomp) {
41761 + retval |=
41762 + handle_hc_xfercomp_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41763 + /*
41764 + * If NYET occurred at same time as Xfer Complete, the NYET is
41765 + * handled by the Xfer Complete interrupt handler. Don't want
41766 + * to call the NYET interrupt handler in this case.
41767 + */
41768 + hcint.b.nyet = 0;
41769 + }
41770 + if (hcint.b.chhltd) {
41771 + retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41772 + }
41773 + if (hcint.b.ahberr) {
41774 + retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41775 + }
41776 + if (hcint.b.stall) {
41777 + retval |= handle_hc_stall_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41778 + }
41779 + if (hcint.b.nak) {
41780 + retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41781 + }
41782 + if (hcint.b.ack) {
41783 + if(!hcint.b.chhltd)
41784 + retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41785 + }
41786 + if (hcint.b.nyet) {
41787 + retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41788 + }
41789 + if (hcint.b.xacterr) {
41790 + retval |= handle_hc_xacterr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41791 + }
41792 + if (hcint.b.bblerr) {
41793 + retval |= handle_hc_babble_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41794 + }
41795 + if (hcint.b.frmovrun) {
41796 + retval |=
41797 + handle_hc_frmovrun_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41798 + }
41799 + if (hcint.b.datatglerr) {
41800 + retval |=
41801 + handle_hc_datatglerr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41802 + }
41803 +
41804 + return retval;
41805 +}
41806 +#endif /* DWC_DEVICE_ONLY */
41807 --- /dev/null
41808 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
41809 @@ -0,0 +1,955 @@
41810 +
41811 +/* ==========================================================================
41812 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $
41813 + * $Revision: #20 $
41814 + * $Date: 2011/10/26 $
41815 + * $Change: 1872981 $
41816 + *
41817 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
41818 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
41819 + * otherwise expressly agreed to in writing between Synopsys and you.
41820 + *
41821 + * The Software IS NOT an item of Licensed Software or Licensed Product under
41822 + * any End User Software License Agreement or Agreement for Licensed Product
41823 + * with Synopsys or any supplement thereto. You are permitted to use and
41824 + * redistribute this Software in source and binary forms, with or without
41825 + * modification, provided that redistributions of source code must retain this
41826 + * notice. You may not view, use, disclose, copy or distribute this file or
41827 + * any information contained herein except pursuant to this license grant from
41828 + * Synopsys. If you do not agree with this notice, including the disclaimer
41829 + * below, then you are not authorized to use the Software.
41830 + *
41831 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
41832 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41833 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41834 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
41835 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41836 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
41837 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
41838 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41839 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41840 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
41841 + * DAMAGE.
41842 + * ========================================================================== */
41843 +#ifndef DWC_DEVICE_ONLY
41844 +
41845 +/**
41846 + * @file
41847 + *
41848 + * This file contains the implementation of the HCD. In Linux, the HCD
41849 + * implements the hc_driver API.
41850 + */
41851 +#include <linux/kernel.h>
41852 +#include <linux/module.h>
41853 +#include <linux/moduleparam.h>
41854 +#include <linux/init.h>
41855 +#include <linux/device.h>
41856 +#include <linux/errno.h>
41857 +#include <linux/list.h>
41858 +#include <linux/interrupt.h>
41859 +#include <linux/string.h>
41860 +#include <linux/dma-mapping.h>
41861 +#include <linux/version.h>
41862 +#include <asm/io.h>
41863 +#include <asm/fiq.h>
41864 +#include <linux/usb.h>
41865 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
41866 +#include <../drivers/usb/core/hcd.h>
41867 +#else
41868 +#include <linux/usb/hcd.h>
41869 +#endif
41870 +
41871 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
41872 +#define USB_URB_EP_LINKING 1
41873 +#else
41874 +#define USB_URB_EP_LINKING 0
41875 +#endif
41876 +
41877 +#include "dwc_otg_hcd_if.h"
41878 +#include "dwc_otg_dbg.h"
41879 +#include "dwc_otg_driver.h"
41880 +#include "dwc_otg_hcd.h"
41881 +#include "dwc_otg_mphi_fix.h"
41882 +
41883 +/**
41884 + * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is
41885 + * qualified with its direction (possible 32 endpoints per device).
41886 + */
41887 +#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
41888 + ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
41889 +
41890 +static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
41891 +
41892 +extern bool fiq_fix_enable;
41893 +
41894 +/** @name Linux HC Driver API Functions */
41895 +/** @{ */
41896 +/* manage i/o requests, device state */
41897 +static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
41898 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
41899 + struct usb_host_endpoint *ep,
41900 +#endif
41901 + struct urb *urb, gfp_t mem_flags);
41902 +
41903 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
41904 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
41905 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
41906 +#endif
41907 +#else /* kernels at or post 2.6.30 */
41908 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd,
41909 + struct urb *urb, int status);
41910 +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) */
41911 +
41912 +static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
41913 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
41914 +static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
41915 +#endif
41916 +static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd);
41917 +extern int hcd_start(struct usb_hcd *hcd);
41918 +extern void hcd_stop(struct usb_hcd *hcd);
41919 +static int get_frame_number(struct usb_hcd *hcd);
41920 +extern int hub_status_data(struct usb_hcd *hcd, char *buf);
41921 +extern int hub_control(struct usb_hcd *hcd,
41922 + u16 typeReq,
41923 + u16 wValue, u16 wIndex, char *buf, u16 wLength);
41924 +
41925 +struct wrapper_priv_data {
41926 + dwc_otg_hcd_t *dwc_otg_hcd;
41927 +};
41928 +
41929 +/** @} */
41930 +
41931 +static struct hc_driver dwc_otg_hc_driver = {
41932 +
41933 + .description = dwc_otg_hcd_name,
41934 + .product_desc = "DWC OTG Controller",
41935 + .hcd_priv_size = sizeof(struct wrapper_priv_data),
41936 +
41937 + .irq = dwc_otg_hcd_irq,
41938 +
41939 + .flags = HCD_MEMORY | HCD_USB2,
41940 +
41941 + //.reset =
41942 + .start = hcd_start,
41943 + //.suspend =
41944 + //.resume =
41945 + .stop = hcd_stop,
41946 +
41947 + .urb_enqueue = dwc_otg_urb_enqueue,
41948 + .urb_dequeue = dwc_otg_urb_dequeue,
41949 + .endpoint_disable = endpoint_disable,
41950 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
41951 + .endpoint_reset = endpoint_reset,
41952 +#endif
41953 + .get_frame_number = get_frame_number,
41954 +
41955 + .hub_status_data = hub_status_data,
41956 + .hub_control = hub_control,
41957 + //.bus_suspend =
41958 + //.bus_resume =
41959 +};
41960 +
41961 +/** Gets the dwc_otg_hcd from a struct usb_hcd */
41962 +static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
41963 +{
41964 + struct wrapper_priv_data *p;
41965 + p = (struct wrapper_priv_data *)(hcd->hcd_priv);
41966 + return p->dwc_otg_hcd;
41967 +}
41968 +
41969 +/** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */
41970 +static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t * dwc_otg_hcd)
41971 +{
41972 + return dwc_otg_hcd_get_priv_data(dwc_otg_hcd);
41973 +}
41974 +
41975 +/** Gets the usb_host_endpoint associated with an URB. */
41976 +inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb)
41977 +{
41978 + struct usb_device *dev = urb->dev;
41979 + int ep_num = usb_pipeendpoint(urb->pipe);
41980 +
41981 + if (usb_pipein(urb->pipe))
41982 + return dev->ep_in[ep_num];
41983 + else
41984 + return dev->ep_out[ep_num];
41985 +}
41986 +
41987 +static int _disconnect(dwc_otg_hcd_t * hcd)
41988 +{
41989 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
41990 +
41991 + usb_hcd->self.is_b_host = 0;
41992 + return 0;
41993 +}
41994 +
41995 +static int _start(dwc_otg_hcd_t * hcd)
41996 +{
41997 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
41998 +
41999 + usb_hcd->self.is_b_host = dwc_otg_hcd_is_b_host(hcd);
42000 + hcd_start(usb_hcd);
42001 +
42002 + return 0;
42003 +}
42004 +
42005 +static int _hub_info(dwc_otg_hcd_t * hcd, void *urb_handle, uint32_t * hub_addr,
42006 + uint32_t * port_addr)
42007 +{
42008 + struct urb *urb = (struct urb *)urb_handle;
42009 + struct usb_bus *bus;
42010 +#if 1 //GRAYG - temporary
42011 + if (NULL == urb_handle)
42012 + DWC_ERROR("**** %s - NULL URB handle\n", __func__);//GRAYG
42013 + if (NULL == urb->dev)
42014 + DWC_ERROR("**** %s - URB has no device\n", __func__);//GRAYG
42015 + if (NULL == port_addr)
42016 + DWC_ERROR("**** %s - NULL port_address\n", __func__);//GRAYG
42017 +#endif
42018 + if (urb->dev->tt) {
42019 + if (NULL == urb->dev->tt->hub) {
42020 + DWC_ERROR("**** %s - (URB's transactor has no TT - giving no hub)\n",
42021 + __func__); //GRAYG
42022 + //*hub_addr = (u8)usb_pipedevice(urb->pipe); //GRAYG
42023 + *hub_addr = 0; //GRAYG
42024 + // we probably shouldn't have a transaction translator if
42025 + // there's no associated hub?
42026 + } else {
42027 + bus = hcd_to_bus(dwc_otg_hcd_to_hcd(hcd));
42028 + if (urb->dev->tt->hub == bus->root_hub)
42029 + *hub_addr = 0;
42030 + else
42031 + *hub_addr = urb->dev->tt->hub->devnum;
42032 + }
42033 + *port_addr = urb->dev->tt->multi ? urb->dev->ttport : 1;
42034 + } else {
42035 + *hub_addr = 0;
42036 + *port_addr = urb->dev->ttport;
42037 + }
42038 + return 0;
42039 +}
42040 +
42041 +static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle)
42042 +{
42043 + struct urb *urb = (struct urb *)urb_handle;
42044 + return urb->dev->speed;
42045 +}
42046 +
42047 +static int _get_b_hnp_enable(dwc_otg_hcd_t * hcd)
42048 +{
42049 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
42050 + return usb_hcd->self.b_hnp_enable;
42051 +}
42052 +
42053 +static void allocate_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
42054 + struct urb *urb)
42055 +{
42056 + hcd_to_bus(hcd)->bandwidth_allocated += bw / urb->interval;
42057 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42058 + hcd_to_bus(hcd)->bandwidth_isoc_reqs++;
42059 + } else {
42060 + hcd_to_bus(hcd)->bandwidth_int_reqs++;
42061 + }
42062 +}
42063 +
42064 +static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
42065 + struct urb *urb)
42066 +{
42067 + hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval;
42068 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42069 + hcd_to_bus(hcd)->bandwidth_isoc_reqs--;
42070 + } else {
42071 + hcd_to_bus(hcd)->bandwidth_int_reqs--;
42072 + }
42073 +}
42074 +
42075 +/**
42076 + * Sets the final status of an URB and returns it to the device driver. Any
42077 + * required cleanup of the URB is performed. The HCD lock should be held on
42078 + * entry.
42079 + */
42080 +static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
42081 + dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
42082 +{
42083 + struct urb *urb = (struct urb *)urb_handle;
42084 + urb_tq_entry_t *new_entry;
42085 + int rc = 0;
42086 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42087 + DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
42088 + __func__, urb, usb_pipedevice(urb->pipe),
42089 + usb_pipeendpoint(urb->pipe),
42090 + usb_pipein(urb->pipe) ? "IN" : "OUT", status);
42091 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42092 + int i;
42093 + for (i = 0; i < urb->number_of_packets; i++) {
42094 + DWC_PRINTF(" ISO Desc %d status: %d\n",
42095 + i, urb->iso_frame_desc[i].status);
42096 + }
42097 + }
42098 + }
42099 + new_entry = DWC_ALLOC_ATOMIC(sizeof(urb_tq_entry_t));
42100 + urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
42101 + /* Convert status value. */
42102 + switch (status) {
42103 + case -DWC_E_PROTOCOL:
42104 + status = -EPROTO;
42105 + break;
42106 + case -DWC_E_IN_PROGRESS:
42107 + status = -EINPROGRESS;
42108 + break;
42109 + case -DWC_E_PIPE:
42110 + status = -EPIPE;
42111 + break;
42112 + case -DWC_E_IO:
42113 + status = -EIO;
42114 + break;
42115 + case -DWC_E_TIMEOUT:
42116 + status = -ETIMEDOUT;
42117 + break;
42118 + case -DWC_E_OVERFLOW:
42119 + status = -EOVERFLOW;
42120 + break;
42121 + default:
42122 + if (status) {
42123 + DWC_PRINTF("Uknown urb status %d\n", status);
42124 +
42125 + }
42126 + }
42127 +
42128 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42129 + int i;
42130 +
42131 + urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
42132 + for (i = 0; i < urb->number_of_packets; ++i) {
42133 + urb->iso_frame_desc[i].actual_length =
42134 + dwc_otg_hcd_urb_get_iso_desc_actual_length
42135 + (dwc_otg_urb, i);
42136 + urb->iso_frame_desc[i].status =
42137 + dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i);
42138 + }
42139 + }
42140 +
42141 + urb->status = status;
42142 + urb->hcpriv = NULL;
42143 + if (!status) {
42144 + if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
42145 + (urb->actual_length < urb->transfer_buffer_length)) {
42146 + urb->status = -EREMOTEIO;
42147 + }
42148 + }
42149 +
42150 + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
42151 + (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
42152 + struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
42153 + if (ep) {
42154 + free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
42155 + dwc_otg_hcd_get_ep_bandwidth(hcd,
42156 + ep->hcpriv),
42157 + urb);
42158 + }
42159 + }
42160 +
42161 + DWC_FREE(dwc_otg_urb);
42162 + if (!new_entry) {
42163 + DWC_ERROR("dwc_otg_hcd: complete: cannot allocate URB TQ entry\n");
42164 + urb->status = -EPROTO;
42165 + /* don't schedule the tasklet -
42166 + * directly return the packet here with error. */
42167 +#if USB_URB_EP_LINKING
42168 + usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
42169 +#endif
42170 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42171 + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
42172 +#else
42173 + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status);
42174 +#endif
42175 + } else {
42176 + new_entry->urb = urb;
42177 +#if USB_URB_EP_LINKING
42178 + rc = usb_hcd_check_unlink_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status);
42179 + if(0 == rc) {
42180 + usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
42181 + }
42182 +#endif
42183 + if(0 == rc) {
42184 + DWC_TAILQ_INSERT_TAIL(&hcd->completed_urb_list, new_entry,
42185 + urb_tq_entries);
42186 + DWC_TASK_HI_SCHEDULE(hcd->completion_tasklet);
42187 + }
42188 + }
42189 + return 0;
42190 +}
42191 +
42192 +static struct dwc_otg_hcd_function_ops hcd_fops = {
42193 + .start = _start,
42194 + .disconnect = _disconnect,
42195 + .hub_info = _hub_info,
42196 + .speed = _speed,
42197 + .complete = _complete,
42198 + .get_b_hnp_enable = _get_b_hnp_enable,
42199 +};
42200 +
42201 +static struct fiq_handler fh = {
42202 + .name = "usb_fiq",
42203 +};
42204 +static uint8_t fiqStack[1024];
42205 +
42206 +extern mphi_regs_t c_mphi_regs;
42207 +/**
42208 + * Initializes the HCD. This function allocates memory for and initializes the
42209 + * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the
42210 + * USB bus with the core and calls the hc_driver->start() function. It returns
42211 + * a negative error on failure.
42212 + */
42213 +int hcd_init(dwc_bus_dev_t *_dev)
42214 +{
42215 + struct usb_hcd *hcd = NULL;
42216 + dwc_otg_hcd_t *dwc_otg_hcd = NULL;
42217 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
42218 + int retval = 0;
42219 + u64 dmamask;
42220 + struct pt_regs regs;
42221 +
42222 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT otg_dev=%p\n", otg_dev);
42223 +
42224 + /* Set device flags indicating whether the HCD supports DMA. */
42225 + if (dwc_otg_is_dma_enable(otg_dev->core_if))
42226 + dmamask = DMA_BIT_MASK(32);
42227 + else
42228 + dmamask = 0;
42229 +
42230 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
42231 + dma_set_mask(&_dev->dev, dmamask);
42232 + dma_set_coherent_mask(&_dev->dev, dmamask);
42233 +#elif defined(PCI_INTERFACE)
42234 + pci_set_dma_mask(_dev, dmamask);
42235 + pci_set_consistent_dma_mask(_dev, dmamask);
42236 +#endif
42237 +
42238 + if (fiq_fix_enable)
42239 + {
42240 + // Set up fiq
42241 + claim_fiq(&fh);
42242 + set_fiq_handler(__FIQ_Branch, 4);
42243 + memset(&regs,0,sizeof(regs));
42244 + regs.ARM_r8 = (long)dwc_otg_hcd_handle_fiq;
42245 + regs.ARM_r9 = (long)0;
42246 + regs.ARM_sp = (long)fiqStack + sizeof(fiqStack) - 4;
42247 + set_fiq_regs(&regs);
42248 + }
42249 +
42250 + /*
42251 + * Allocate memory for the base HCD plus the DWC OTG HCD.
42252 + * Initialize the base HCD.
42253 + */
42254 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
42255 + hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, _dev->dev.bus_id);
42256 +#else
42257 + hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, dev_name(&_dev->dev));
42258 + hcd->has_tt = 1;
42259 +// hcd->uses_new_polling = 1;
42260 +// hcd->poll_rh = 0;
42261 +#endif
42262 + if (!hcd) {
42263 + retval = -ENOMEM;
42264 + goto error1;
42265 + }
42266 +
42267 + hcd->regs = otg_dev->os_dep.base;
42268 +
42269 + if (fiq_fix_enable)
42270 + {
42271 + //Set the mphi periph to the required registers
42272 + c_mphi_regs.base = otg_dev->os_dep.mphi_base;
42273 + c_mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c;
42274 + c_mphi_regs.outdda = otg_dev->os_dep.mphi_base + 0x28;
42275 + c_mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c;
42276 + c_mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50;
42277 +
42278 + //Enable mphi peripheral
42279 + writel((1<<31),c_mphi_regs.ctrl);
42280 +#ifdef DEBUG
42281 + if (readl(c_mphi_regs.ctrl) & 0x80000000)
42282 + DWC_DEBUGPL(DBG_USER, "MPHI periph has been enabled\n");
42283 + else
42284 + DWC_DEBUGPL(DBG_USER, "MPHI periph has NOT been enabled\n");
42285 +#endif
42286 + // Enable FIQ interrupt from USB peripheral
42287 + enable_fiq(INTERRUPT_VC_USB);
42288 + }
42289 + /* Initialize the DWC OTG HCD. */
42290 + dwc_otg_hcd = dwc_otg_hcd_alloc_hcd();
42291 + if (!dwc_otg_hcd) {
42292 + goto error2;
42293 + }
42294 + ((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd =
42295 + dwc_otg_hcd;
42296 + otg_dev->hcd = dwc_otg_hcd;
42297 +
42298 + if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) {
42299 + goto error2;
42300 + }
42301 +
42302 + otg_dev->hcd->otg_dev = otg_dev;
42303 + hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd);
42304 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel)
42305 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) //version field absent later
42306 + hcd->self.otg_version = dwc_otg_get_otg_version(otg_dev->core_if);
42307 +#endif
42308 + /* Don't support SG list at this point */
42309 + hcd->self.sg_tablesize = 0;
42310 +#endif
42311 + /*
42312 + * Finish generic HCD initialization and start the HCD. This function
42313 + * allocates the DMA buffer pool, registers the USB bus, requests the
42314 + * IRQ line, and calls hcd_start method.
42315 + */
42316 +#ifdef PLATFORM_INTERFACE
42317 + retval = usb_add_hcd(hcd, platform_get_irq(_dev, 0), IRQF_SHARED | IRQF_DISABLED);
42318 +#else
42319 + retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED);
42320 +#endif
42321 + if (retval < 0) {
42322 + goto error2;
42323 + }
42324 +
42325 + dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd);
42326 + return 0;
42327 +
42328 +error2:
42329 + usb_put_hcd(hcd);
42330 +error1:
42331 + return retval;
42332 +}
42333 +
42334 +/**
42335 + * Removes the HCD.
42336 + * Frees memory and resources associated with the HCD and deregisters the bus.
42337 + */
42338 +void hcd_remove(dwc_bus_dev_t *_dev)
42339 +{
42340 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
42341 + dwc_otg_hcd_t *dwc_otg_hcd;
42342 + struct usb_hcd *hcd;
42343 +
42344 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE otg_dev=%p\n", otg_dev);
42345 +
42346 + if (!otg_dev) {
42347 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
42348 + return;
42349 + }
42350 +
42351 + dwc_otg_hcd = otg_dev->hcd;
42352 +
42353 + if (!dwc_otg_hcd) {
42354 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
42355 + return;
42356 + }
42357 +
42358 + hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
42359 +
42360 + if (!hcd) {
42361 + DWC_DEBUGPL(DBG_ANY,
42362 + "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n",
42363 + __func__);
42364 + return;
42365 + }
42366 + usb_remove_hcd(hcd);
42367 + dwc_otg_hcd_set_priv_data(dwc_otg_hcd, NULL);
42368 + dwc_otg_hcd_remove(dwc_otg_hcd);
42369 + usb_put_hcd(hcd);
42370 +}
42371 +
42372 +/* =========================================================================
42373 + * Linux HC Driver Functions
42374 + * ========================================================================= */
42375 +
42376 +/** Initializes the DWC_otg controller and its root hub and prepares it for host
42377 + * mode operation. Activates the root port. Returns 0 on success and a negative
42378 + * error code on failure. */
42379 +int hcd_start(struct usb_hcd *hcd)
42380 +{
42381 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42382 + struct usb_bus *bus;
42383 +
42384 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
42385 + bus = hcd_to_bus(hcd);
42386 +
42387 + hcd->state = HC_STATE_RUNNING;
42388 + if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) {
42389 + return 0;
42390 + }
42391 +
42392 + /* Initialize and connect root hub if one is not already attached */
42393 + if (bus->root_hub) {
42394 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
42395 + /* Inform the HUB driver to resume. */
42396 + usb_hcd_resume_root_hub(hcd);
42397 + }
42398 +
42399 + return 0;
42400 +}
42401 +
42402 +/**
42403 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
42404 + * stopped.
42405 + */
42406 +void hcd_stop(struct usb_hcd *hcd)
42407 +{
42408 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42409 +
42410 + dwc_otg_hcd_stop(dwc_otg_hcd);
42411 +}
42412 +
42413 +/** Returns the current frame number. */
42414 +static int get_frame_number(struct usb_hcd *hcd)
42415 +{
42416 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42417 +
42418 + return dwc_otg_hcd_get_frame_number(dwc_otg_hcd);
42419 +}
42420 +
42421 +#ifdef DEBUG
42422 +static void dump_urb_info(struct urb *urb, char *fn_name)
42423 +{
42424 + DWC_PRINTF("%s, urb %p\n", fn_name, urb);
42425 + DWC_PRINTF(" Device address: %d\n", usb_pipedevice(urb->pipe));
42426 + DWC_PRINTF(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
42427 + (usb_pipein(urb->pipe) ? "IN" : "OUT"));
42428 + DWC_PRINTF(" Endpoint type: %s\n", ( {
42429 + char *pipetype;
42430 + switch (usb_pipetype(urb->pipe)) {
42431 +case PIPE_CONTROL:
42432 +pipetype = "CONTROL"; break; case PIPE_BULK:
42433 +pipetype = "BULK"; break; case PIPE_INTERRUPT:
42434 +pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS:
42435 +pipetype = "ISOCHRONOUS"; break; default:
42436 + pipetype = "UNKNOWN"; break;};
42437 + pipetype;}
42438 + )) ;
42439 + DWC_PRINTF(" Speed: %s\n", ( {
42440 + char *speed; switch (urb->dev->speed) {
42441 +case USB_SPEED_HIGH:
42442 +speed = "HIGH"; break; case USB_SPEED_FULL:
42443 +speed = "FULL"; break; case USB_SPEED_LOW:
42444 +speed = "LOW"; break; default:
42445 + speed = "UNKNOWN"; break;};
42446 + speed;}
42447 + )) ;
42448 + DWC_PRINTF(" Max packet size: %d\n",
42449 + usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
42450 + DWC_PRINTF(" Data buffer length: %d\n", urb->transfer_buffer_length);
42451 + DWC_PRINTF(" Transfer buffer: %p, Transfer DMA: %p\n",
42452 + urb->transfer_buffer, (void *)urb->transfer_dma);
42453 + DWC_PRINTF(" Setup buffer: %p, Setup DMA: %p\n",
42454 + urb->setup_packet, (void *)urb->setup_dma);
42455 + DWC_PRINTF(" Interval: %d\n", urb->interval);
42456 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42457 + int i;
42458 + for (i = 0; i < urb->number_of_packets; i++) {
42459 + DWC_PRINTF(" ISO Desc %d:\n", i);
42460 + DWC_PRINTF(" offset: %d, length %d\n",
42461 + urb->iso_frame_desc[i].offset,
42462 + urb->iso_frame_desc[i].length);
42463 + }
42464 + }
42465 +}
42466 +#endif
42467 +
42468 +/** Starts processing a USB transfer request specified by a USB Request Block
42469 + * (URB). mem_flags indicates the type of memory allocation to use while
42470 + * processing this URB. */
42471 +static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
42472 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42473 + struct usb_host_endpoint *ep,
42474 +#endif
42475 + struct urb *urb, gfp_t mem_flags)
42476 +{
42477 + int retval = 0;
42478 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
42479 + struct usb_host_endpoint *ep = urb->ep;
42480 +#endif
42481 +#if USB_URB_EP_LINKING
42482 + dwc_irqflags_t irqflags;
42483 +#endif
42484 + void **ref_ep_hcpriv = &ep->hcpriv;
42485 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42486 + dwc_otg_hcd_urb_t *dwc_otg_urb;
42487 + int i;
42488 + int alloc_bandwidth = 0;
42489 + uint8_t ep_type = 0;
42490 + uint32_t flags = 0;
42491 + void *buf;
42492 +
42493 +#ifdef DEBUG
42494 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42495 + dump_urb_info(urb, "dwc_otg_urb_enqueue");
42496 + }
42497 +#endif
42498 +
42499 + if (!urb->transfer_buffer && urb->transfer_buffer_length)
42500 + return -EINVAL;
42501 +
42502 + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
42503 + || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
42504 + if (!dwc_otg_hcd_is_bandwidth_allocated
42505 + (dwc_otg_hcd, ref_ep_hcpriv)) {
42506 + alloc_bandwidth = 1;
42507 + }
42508 + }
42509 +
42510 + switch (usb_pipetype(urb->pipe)) {
42511 + case PIPE_CONTROL:
42512 + ep_type = USB_ENDPOINT_XFER_CONTROL;
42513 + break;
42514 + case PIPE_ISOCHRONOUS:
42515 + ep_type = USB_ENDPOINT_XFER_ISOC;
42516 + break;
42517 + case PIPE_BULK:
42518 + ep_type = USB_ENDPOINT_XFER_BULK;
42519 + break;
42520 + case PIPE_INTERRUPT:
42521 + ep_type = USB_ENDPOINT_XFER_INT;
42522 + break;
42523 + default:
42524 + DWC_WARN("Wrong EP type - %d\n", usb_pipetype(urb->pipe));
42525 + }
42526 +
42527 + /* # of packets is often 0 - do we really need to call this then? */
42528 + dwc_otg_urb = dwc_otg_hcd_urb_alloc(dwc_otg_hcd,
42529 + urb->number_of_packets,
42530 + mem_flags == GFP_ATOMIC ? 1 : 0);
42531 +
42532 + if(dwc_otg_urb == NULL)
42533 + return -ENOMEM;
42534 +
42535 + urb->hcpriv = dwc_otg_urb;
42536 + if (!dwc_otg_urb && urb->number_of_packets)
42537 + return -ENOMEM;
42538 +
42539 + dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
42540 + usb_pipeendpoint(urb->pipe), ep_type,
42541 + usb_pipein(urb->pipe),
42542 + usb_maxpacket(urb->dev, urb->pipe,
42543 + !(usb_pipein(urb->pipe))));
42544 +
42545 + buf = urb->transfer_buffer;
42546 + if (hcd->self.uses_dma) {
42547 + /*
42548 + * Calculate virtual address from physical address,
42549 + * because some class driver may not fill transfer_buffer.
42550 + * In Buffer DMA mode virual address is used,
42551 + * when handling non DWORD aligned buffers.
42552 + */
42553 + //buf = phys_to_virt(urb->transfer_dma);
42554 + // DMA addresses are bus addresses not physical addresses!
42555 + buf = dma_to_virt(&urb->dev->dev, urb->transfer_dma);
42556 + }
42557 +
42558 + if (!(urb->transfer_flags & URB_NO_INTERRUPT))
42559 + flags |= URB_GIVEBACK_ASAP;
42560 + if (urb->transfer_flags & URB_ZERO_PACKET)
42561 + flags |= URB_SEND_ZERO_PACKET;
42562 +
42563 + dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf,
42564 + urb->transfer_dma,
42565 + urb->transfer_buffer_length,
42566 + urb->setup_packet,
42567 + urb->setup_dma, flags, urb->interval);
42568 +
42569 + for (i = 0; i < urb->number_of_packets; ++i) {
42570 + dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_urb, i,
42571 + urb->
42572 + iso_frame_desc[i].offset,
42573 + urb->
42574 + iso_frame_desc[i].length);
42575 + }
42576 +
42577 +#if USB_URB_EP_LINKING
42578 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
42579 + retval = usb_hcd_link_urb_to_ep(hcd, urb);
42580 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
42581 + if (0 == retval)
42582 +#endif
42583 + {
42584 + retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb,
42585 + /*(dwc_otg_qh_t **)*/
42586 + ref_ep_hcpriv,
42587 + mem_flags == GFP_ATOMIC ? 1 : 0);
42588 + if (0 == retval) {
42589 + if (alloc_bandwidth) {
42590 + allocate_bus_bandwidth(hcd,
42591 + dwc_otg_hcd_get_ep_bandwidth(
42592 + dwc_otg_hcd, *ref_ep_hcpriv),
42593 + urb);
42594 + }
42595 + } else {
42596 +#if USB_URB_EP_LINKING
42597 + dwc_irqflags_t irqflags;
42598 + DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval);
42599 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
42600 + usb_hcd_unlink_urb_from_ep(hcd, urb);
42601 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
42602 +#endif
42603 + if (retval == -DWC_E_NO_DEVICE) {
42604 + retval = -ENODEV;
42605 + }
42606 + }
42607 + }
42608 + return retval;
42609 +}
42610 +
42611 +/** Aborts/cancels a USB transfer request. Always returns 0 to indicate
42612 + * success. */
42613 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42614 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
42615 +#else
42616 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
42617 +#endif
42618 +{
42619 + dwc_irqflags_t flags;
42620 + dwc_otg_hcd_t *dwc_otg_hcd;
42621 + int rc;
42622 +
42623 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
42624 +
42625 + dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42626 +
42627 +#ifdef DEBUG
42628 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42629 + dump_urb_info(urb, "dwc_otg_urb_dequeue");
42630 + }
42631 +#endif
42632 +
42633 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
42634 + rc = usb_hcd_check_unlink_urb(hcd, urb, status);
42635 + if (0 == rc) {
42636 + if(urb->hcpriv != NULL) {
42637 + dwc_otg_hcd_urb_dequeue(dwc_otg_hcd,
42638 + (dwc_otg_hcd_urb_t *)urb->hcpriv);
42639 +
42640 + DWC_FREE(urb->hcpriv);
42641 + urb->hcpriv = NULL;
42642 + }
42643 + }
42644 +
42645 + if (0 == rc) {
42646 + /* Higher layer software sets URB status. */
42647 +#if USB_URB_EP_LINKING
42648 + usb_hcd_unlink_urb_from_ep(hcd, urb);
42649 +#endif
42650 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
42651 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42652 + usb_hcd_giveback_urb(hcd, urb);
42653 +#else
42654 + usb_hcd_giveback_urb(hcd, urb, status);
42655 +#endif
42656 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42657 + DWC_PRINTF("Called usb_hcd_giveback_urb() \n");
42658 + DWC_PRINTF(" 1urb->status = %d\n", urb->status);
42659 + }
42660 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue OK\n");
42661 + } else {
42662 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
42663 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue failed - rc %d\n",
42664 + rc);
42665 + }
42666 +
42667 + return rc;
42668 +}
42669 +
42670 +/* Frees resources in the DWC_otg controller related to a given endpoint. Also
42671 + * clears state in the HCD related to the endpoint. Any URBs for the endpoint
42672 + * must already be dequeued. */
42673 +static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
42674 +{
42675 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42676 +
42677 + DWC_DEBUGPL(DBG_HCD,
42678 + "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
42679 + "endpoint=%d\n", ep->desc.bEndpointAddress,
42680 + dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress));
42681 + dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250);
42682 + ep->hcpriv = NULL;
42683 +}
42684 +
42685 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
42686 +/* Resets endpoint specific parameter values, in current version used to reset
42687 + * the data toggle(as a WA). This function can be called from usb_clear_halt routine */
42688 +static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
42689 +{
42690 + dwc_irqflags_t flags;
42691 + struct usb_device *udev = NULL;
42692 + int epnum = usb_endpoint_num(&ep->desc);
42693 + int is_out = usb_endpoint_dir_out(&ep->desc);
42694 + int is_control = usb_endpoint_xfer_control(&ep->desc);
42695 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42696 + struct device *dev = DWC_OTG_OS_GETDEV(dwc_otg_hcd->otg_dev->os_dep);
42697 +
42698 + if (dev)
42699 + udev = to_usb_device(dev);
42700 + else
42701 + return;
42702 +
42703 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP RESET: Endpoint Num=0x%02d\n", epnum);
42704 +
42705 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
42706 + usb_settoggle(udev, epnum, is_out, 0);
42707 + if (is_control)
42708 + usb_settoggle(udev, epnum, !is_out, 0);
42709 +
42710 + if (ep->hcpriv) {
42711 + dwc_otg_hcd_endpoint_reset(dwc_otg_hcd, ep->hcpriv);
42712 + }
42713 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
42714 +}
42715 +#endif
42716 +
42717 +/** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
42718 + * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
42719 + * interrupt.
42720 + *
42721 + * This function is called by the USB core when an interrupt occurs */
42722 +static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd)
42723 +{
42724 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42725 + int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd);
42726 + if (retval != 0) {
42727 + S3C2410X_CLEAR_EINTPEND();
42728 + }
42729 + return IRQ_RETVAL(retval);
42730 +}
42731 +
42732 +/** Creates Status Change bitmap for the root hub and root port. The bitmap is
42733 + * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
42734 + * is the status change indicator for the single root port. Returns 1 if either
42735 + * change indicator is 1, otherwise returns 0. */
42736 +int hub_status_data(struct usb_hcd *hcd, char *buf)
42737 +{
42738 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42739 +
42740 + buf[0] = 0;
42741 + buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1;
42742 +
42743 + return (buf[0] != 0);
42744 +}
42745 +
42746 +/** Handles hub class-specific requests. */
42747 +int hub_control(struct usb_hcd *hcd,
42748 + u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
42749 +{
42750 + int retval;
42751 +
42752 + retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd),
42753 + typeReq, wValue, wIndex, buf, wLength);
42754 +
42755 + switch (retval) {
42756 + case -DWC_E_INVALID:
42757 + retval = -EINVAL;
42758 + break;
42759 + }
42760 +
42761 + return retval;
42762 +}
42763 +
42764 +#endif /* DWC_DEVICE_ONLY */
42765 --- /dev/null
42766 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
42767 @@ -0,0 +1,958 @@
42768 +/* ==========================================================================
42769 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_queue.c $
42770 + * $Revision: #44 $
42771 + * $Date: 2011/10/26 $
42772 + * $Change: 1873028 $
42773 + *
42774 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
42775 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
42776 + * otherwise expressly agreed to in writing between Synopsys and you.
42777 + *
42778 + * The Software IS NOT an item of Licensed Software or Licensed Product under
42779 + * any End User Software License Agreement or Agreement for Licensed Product
42780 + * with Synopsys or any supplement thereto. You are permitted to use and
42781 + * redistribute this Software in source and binary forms, with or without
42782 + * modification, provided that redistributions of source code must retain this
42783 + * notice. You may not view, use, disclose, copy or distribute this file or
42784 + * any information contained herein except pursuant to this license grant from
42785 + * Synopsys. If you do not agree with this notice, including the disclaimer
42786 + * below, then you are not authorized to use the Software.
42787 + *
42788 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
42789 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42790 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42791 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
42792 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
42793 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
42794 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
42795 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42796 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42797 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
42798 + * DAMAGE.
42799 + * ========================================================================== */
42800 +#ifndef DWC_DEVICE_ONLY
42801 +
42802 +/**
42803 + * @file
42804 + *
42805 + * This file contains the functions to manage Queue Heads and Queue
42806 + * Transfer Descriptors.
42807 + */
42808 +
42809 +#include "dwc_otg_hcd.h"
42810 +#include "dwc_otg_regs.h"
42811 +
42812 +extern bool microframe_schedule;
42813 +
42814 +/**
42815 + * Free each QTD in the QH's QTD-list then free the QH. QH should already be
42816 + * removed from a list. QTD list should already be empty if called from URB
42817 + * Dequeue.
42818 + *
42819 + * @param hcd HCD instance.
42820 + * @param qh The QH to free.
42821 + */
42822 +void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
42823 +{
42824 + dwc_otg_qtd_t *qtd, *qtd_tmp;
42825 +
42826 + /* Free each QTD in the QTD list */
42827 + DWC_SPINLOCK(hcd->lock);
42828 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
42829 + DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
42830 + dwc_otg_hcd_qtd_free(qtd);
42831 + }
42832 +
42833 + if (hcd->core_if->dma_desc_enable) {
42834 + dwc_otg_hcd_qh_free_ddma(hcd, qh);
42835 + } else if (qh->dw_align_buf) {
42836 + uint32_t buf_size;
42837 + if (qh->ep_type == UE_ISOCHRONOUS) {
42838 + buf_size = 4096;
42839 + } else {
42840 + buf_size = hcd->core_if->core_params->max_transfer_size;
42841 + }
42842 + DWC_DMA_FREE(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma);
42843 + }
42844 +
42845 + DWC_FREE(qh);
42846 + DWC_SPINUNLOCK(hcd->lock);
42847 + return;
42848 +}
42849 +
42850 +#define BitStuffTime(bytecount) ((8 * 7* bytecount) / 6)
42851 +#define HS_HOST_DELAY 5 /* nanoseconds */
42852 +#define FS_LS_HOST_DELAY 1000 /* nanoseconds */
42853 +#define HUB_LS_SETUP 333 /* nanoseconds */
42854 +#define NS_TO_US(ns) ((ns + 500) / 1000)
42855 + /* convert & round nanoseconds to microseconds */
42856 +
42857 +static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, int bytecount)
42858 +{
42859 + unsigned long retval;
42860 +
42861 + switch (speed) {
42862 + case USB_SPEED_HIGH:
42863 + if (is_isoc) {
42864 + retval =
42865 + ((38 * 8 * 2083) +
42866 + (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
42867 + HS_HOST_DELAY;
42868 + } else {
42869 + retval =
42870 + ((55 * 8 * 2083) +
42871 + (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
42872 + HS_HOST_DELAY;
42873 + }
42874 + break;
42875 + case USB_SPEED_FULL:
42876 + if (is_isoc) {
42877 + retval =
42878 + (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
42879 + if (is_in) {
42880 + retval = 7268 + FS_LS_HOST_DELAY + retval;
42881 + } else {
42882 + retval = 6265 + FS_LS_HOST_DELAY + retval;
42883 + }
42884 + } else {
42885 + retval =
42886 + (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
42887 + retval = 9107 + FS_LS_HOST_DELAY + retval;
42888 + }
42889 + break;
42890 + case USB_SPEED_LOW:
42891 + if (is_in) {
42892 + retval =
42893 + (67667 * (31 + 10 * BitStuffTime(bytecount))) /
42894 + 1000;
42895 + retval =
42896 + 64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
42897 + retval;
42898 + } else {
42899 + retval =
42900 + (66700 * (31 + 10 * BitStuffTime(bytecount))) /
42901 + 1000;
42902 + retval =
42903 + 64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
42904 + retval;
42905 + }
42906 + break;
42907 + default:
42908 + DWC_WARN("Unknown device speed\n");
42909 + retval = -1;
42910 + }
42911 +
42912 + return NS_TO_US(retval);
42913 +}
42914 +
42915 +/**
42916 + * Initializes a QH structure.
42917 + *
42918 + * @param hcd The HCD state structure for the DWC OTG controller.
42919 + * @param qh The QH to init.
42920 + * @param urb Holds the information about the device/endpoint that we need
42921 + * to initialize the QH.
42922 + */
42923 +#define SCHEDULE_SLOP 10
42924 +void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
42925 +{
42926 + char *speed, *type;
42927 + int dev_speed;
42928 + uint32_t hub_addr, hub_port;
42929 +
42930 + dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
42931 +
42932 + /* Initialize QH */
42933 + qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
42934 + qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
42935 +
42936 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
42937 + qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info);
42938 + DWC_CIRCLEQ_INIT(&qh->qtd_list);
42939 + DWC_LIST_INIT(&qh->qh_list_entry);
42940 + qh->channel = NULL;
42941 +
42942 + /* FS/LS Enpoint on HS Hub
42943 + * NOT virtual root hub */
42944 + dev_speed = hcd->fops->speed(hcd, urb->priv);
42945 +
42946 + hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
42947 + qh->do_split = 0;
42948 + if (microframe_schedule)
42949 + qh->speed = dev_speed;
42950 +
42951 + qh->nak_frame = 0xffff;
42952 +
42953 + if (((dev_speed == USB_SPEED_LOW) ||
42954 + (dev_speed == USB_SPEED_FULL)) &&
42955 + (hub_addr != 0 && hub_addr != 1)) {
42956 + DWC_DEBUGPL(DBG_HCD,
42957 + "QH init: EP %d: TT found at hub addr %d, for port %d\n",
42958 + dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
42959 + hub_port);
42960 + qh->do_split = 1;
42961 + }
42962 +
42963 + if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
42964 + /* Compute scheduling parameters once and save them. */
42965 + hprt0_data_t hprt;
42966 +
42967 + /** @todo Account for split transfers in the bus time. */
42968 + int bytecount =
42969 + dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
42970 +
42971 + qh->usecs =
42972 + calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed),
42973 + qh->ep_is_in, (qh->ep_type == UE_ISOCHRONOUS),
42974 + bytecount);
42975 + /* Start in a slightly future (micro)frame. */
42976 + qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
42977 + SCHEDULE_SLOP);
42978 + qh->interval = urb->interval;
42979 +
42980 +#if 0
42981 + /* Increase interrupt polling rate for debugging. */
42982 + if (qh->ep_type == UE_INTERRUPT) {
42983 + qh->interval = 8;
42984 + }
42985 +#endif
42986 + hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
42987 + if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
42988 + ((dev_speed == USB_SPEED_LOW) ||
42989 + (dev_speed == USB_SPEED_FULL))) {
42990 + qh->interval *= 8;
42991 + qh->sched_frame |= 0x7;
42992 + qh->start_split_frame = qh->sched_frame;
42993 + }
42994 +
42995 + }
42996 +
42997 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
42998 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - qh = %p\n", qh);
42999 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Device Address = %d\n",
43000 + dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
43001 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Endpoint %d, %s\n",
43002 + dwc_otg_hcd_get_ep_num(&urb->pipe_info),
43003 + dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
43004 + switch (dev_speed) {
43005 + case USB_SPEED_LOW:
43006 + qh->dev_speed = DWC_OTG_EP_SPEED_LOW;
43007 + speed = "low";
43008 + break;
43009 + case USB_SPEED_FULL:
43010 + qh->dev_speed = DWC_OTG_EP_SPEED_FULL;
43011 + speed = "full";
43012 + break;
43013 + case USB_SPEED_HIGH:
43014 + qh->dev_speed = DWC_OTG_EP_SPEED_HIGH;
43015 + speed = "high";
43016 + break;
43017 + default:
43018 + speed = "?";
43019 + break;
43020 + }
43021 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Speed = %s\n", speed);
43022 +
43023 + switch (qh->ep_type) {
43024 + case UE_ISOCHRONOUS:
43025 + type = "isochronous";
43026 + break;
43027 + case UE_INTERRUPT:
43028 + type = "interrupt";
43029 + break;
43030 + case UE_CONTROL:
43031 + type = "control";
43032 + break;
43033 + case UE_BULK:
43034 + type = "bulk";
43035 + break;
43036 + default:
43037 + type = "?";
43038 + break;
43039 + }
43040 +
43041 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Type = %s\n", type);
43042 +
43043 +#ifdef DEBUG
43044 + if (qh->ep_type == UE_INTERRUPT) {
43045 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
43046 + qh->usecs);
43047 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
43048 + qh->interval);
43049 + }
43050 +#endif
43051 +
43052 +}
43053 +
43054 +/**
43055 + * This function allocates and initializes a QH.
43056 + *
43057 + * @param hcd The HCD state structure for the DWC OTG controller.
43058 + * @param urb Holds the information about the device/endpoint that we need
43059 + * to initialize the QH.
43060 + * @param atomic_alloc Flag to do atomic allocation if needed
43061 + *
43062 + * @return Returns pointer to the newly allocated QH, or NULL on error. */
43063 +dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
43064 + dwc_otg_hcd_urb_t * urb, int atomic_alloc)
43065 +{
43066 + dwc_otg_qh_t *qh;
43067 +
43068 + /* Allocate memory */
43069 + /** @todo add memflags argument */
43070 + qh = dwc_otg_hcd_qh_alloc(atomic_alloc);
43071 + if (qh == NULL) {
43072 + DWC_ERROR("qh allocation failed");
43073 + return NULL;
43074 + }
43075 +
43076 + qh_init(hcd, qh, urb);
43077 +
43078 + if (hcd->core_if->dma_desc_enable
43079 + && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) {
43080 + dwc_otg_hcd_qh_free(hcd, qh);
43081 + return NULL;
43082 + }
43083 +
43084 + return qh;
43085 +}
43086 +
43087 +/* microframe_schedule=0 start */
43088 +
43089 +/**
43090 + * Checks that a channel is available for a periodic transfer.
43091 + *
43092 + * @return 0 if successful, negative error code otherise.
43093 + */
43094 +static int periodic_channel_available(dwc_otg_hcd_t * hcd)
43095 +{
43096 + /*
43097 + * Currently assuming that there is a dedicated host channnel for each
43098 + * periodic transaction plus at least one host channel for
43099 + * non-periodic transactions.
43100 + */
43101 + int status;
43102 + int num_channels;
43103 +
43104 + num_channels = hcd->core_if->core_params->host_channels;
43105 + if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels)
43106 + && (hcd->periodic_channels < num_channels - 1)) {
43107 + status = 0;
43108 + } else {
43109 + DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
43110 + __func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels); //NOTICE
43111 + status = -DWC_E_NO_SPACE;
43112 + }
43113 +
43114 + return status;
43115 +}
43116 +
43117 +/**
43118 + * Checks that there is sufficient bandwidth for the specified QH in the
43119 + * periodic schedule. For simplicity, this calculation assumes that all the
43120 + * transfers in the periodic schedule may occur in the same (micro)frame.
43121 + *
43122 + * @param hcd The HCD state structure for the DWC OTG controller.
43123 + * @param qh QH containing periodic bandwidth required.
43124 + *
43125 + * @return 0 if successful, negative error code otherwise.
43126 + */
43127 +static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43128 +{
43129 + int status;
43130 + int16_t max_claimed_usecs;
43131 +
43132 + status = 0;
43133 +
43134 + if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) {
43135 + /*
43136 + * High speed mode.
43137 + * Max periodic usecs is 80% x 125 usec = 100 usec.
43138 + */
43139 +
43140 + max_claimed_usecs = 100 - qh->usecs;
43141 + } else {
43142 + /*
43143 + * Full speed mode.
43144 + * Max periodic usecs is 90% x 1000 usec = 900 usec.
43145 + */
43146 + max_claimed_usecs = 900 - qh->usecs;
43147 + }
43148 +
43149 + if (hcd->periodic_usecs > max_claimed_usecs) {
43150 + DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs); //NOTICE
43151 + status = -DWC_E_NO_SPACE;
43152 + }
43153 +
43154 + return status;
43155 +}
43156 +
43157 +/* microframe_schedule=0 end */
43158 +
43159 +/**
43160 + * Microframe scheduler
43161 + * track the total use in hcd->frame_usecs
43162 + * keep each qh use in qh->frame_usecs
43163 + * when surrendering the qh then donate the time back
43164 + */
43165 +const unsigned short max_uframe_usecs[]={ 100, 100, 100, 100, 100, 100, 30, 0 };
43166 +
43167 +/*
43168 + * called from dwc_otg_hcd.c:dwc_otg_hcd_init
43169 + */
43170 +int init_hcd_usecs(dwc_otg_hcd_t *_hcd)
43171 +{
43172 + int i;
43173 + for (i=0; i<8; i++) {
43174 + _hcd->frame_usecs[i] = max_uframe_usecs[i];
43175 + }
43176 + return 0;
43177 +}
43178 +
43179 +static int find_single_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
43180 +{
43181 + int i;
43182 + unsigned short utime;
43183 + int t_left;
43184 + int ret;
43185 + int done;
43186 +
43187 + ret = -1;
43188 + utime = _qh->usecs;
43189 + t_left = utime;
43190 + i = 0;
43191 + done = 0;
43192 + while (done == 0) {
43193 + /* At the start _hcd->frame_usecs[i] = max_uframe_usecs[i]; */
43194 + if (utime <= _hcd->frame_usecs[i]) {
43195 + _hcd->frame_usecs[i] -= utime;
43196 + _qh->frame_usecs[i] += utime;
43197 + t_left -= utime;
43198 + ret = i;
43199 + done = 1;
43200 + return ret;
43201 + } else {
43202 + i++;
43203 + if (i == 8) {
43204 + done = 1;
43205 + ret = -1;
43206 + }
43207 + }
43208 + }
43209 + return ret;
43210 + }
43211 +
43212 +/*
43213 + * use this for FS apps that can span multiple uframes
43214 + */
43215 +static int find_multi_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
43216 +{
43217 + int i;
43218 + int j;
43219 + unsigned short utime;
43220 + int t_left;
43221 + int ret;
43222 + int done;
43223 + unsigned short xtime;
43224 +
43225 + ret = -1;
43226 + utime = _qh->usecs;
43227 + t_left = utime;
43228 + i = 0;
43229 + done = 0;
43230 +loop:
43231 + while (done == 0) {
43232 + if(_hcd->frame_usecs[i] <= 0) {
43233 + i++;
43234 + if (i == 8) {
43235 + done = 1;
43236 + ret = -1;
43237 + }
43238 + goto loop;
43239 + }
43240 +
43241 + /*
43242 + * we need n consecutive slots
43243 + * so use j as a start slot j plus j+1 must be enough time (for now)
43244 + */
43245 + xtime= _hcd->frame_usecs[i];
43246 + for (j = i+1 ; j < 8 ; j++ ) {
43247 + /*
43248 + * if we add this frame remaining time to xtime we may
43249 + * be OK, if not we need to test j for a complete frame
43250 + */
43251 + if ((xtime+_hcd->frame_usecs[j]) < utime) {
43252 + if (_hcd->frame_usecs[j] < max_uframe_usecs[j]) {
43253 + j = 8;
43254 + ret = -1;
43255 + continue;
43256 + }
43257 + }
43258 + if (xtime >= utime) {
43259 + ret = i;
43260 + j = 8; /* stop loop with a good value ret */
43261 + continue;
43262 + }
43263 + /* add the frame time to x time */
43264 + xtime += _hcd->frame_usecs[j];
43265 + /* we must have a fully available next frame or break */
43266 + if ((xtime < utime)
43267 + && (_hcd->frame_usecs[j] == max_uframe_usecs[j])) {
43268 + ret = -1;
43269 + j = 8; /* stop loop with a bad value ret */
43270 + continue;
43271 + }
43272 + }
43273 + if (ret >= 0) {
43274 + t_left = utime;
43275 + for (j = i; (t_left>0) && (j < 8); j++ ) {
43276 + t_left -= _hcd->frame_usecs[j];
43277 + if ( t_left <= 0 ) {
43278 + _qh->frame_usecs[j] += _hcd->frame_usecs[j] + t_left;
43279 + _hcd->frame_usecs[j]= -t_left;
43280 + ret = i;
43281 + done = 1;
43282 + } else {
43283 + _qh->frame_usecs[j] += _hcd->frame_usecs[j];
43284 + _hcd->frame_usecs[j] = 0;
43285 + }
43286 + }
43287 + } else {
43288 + i++;
43289 + if (i == 8) {
43290 + done = 1;
43291 + ret = -1;
43292 + }
43293 + }
43294 + }
43295 + return ret;
43296 +}
43297 +
43298 +static int find_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
43299 +{
43300 + int ret;
43301 + ret = -1;
43302 +
43303 + if (_qh->speed == USB_SPEED_HIGH) {
43304 + /* if this is a hs transaction we need a full frame */
43305 + ret = find_single_uframe(_hcd, _qh);
43306 + } else {
43307 + /* if this is a fs transaction we may need a sequence of frames */
43308 + ret = find_multi_uframe(_hcd, _qh);
43309 + }
43310 + return ret;
43311 +}
43312 +
43313 +/**
43314 + * Checks that the max transfer size allowed in a host channel is large enough
43315 + * to handle the maximum data transfer in a single (micro)frame for a periodic
43316 + * transfer.
43317 + *
43318 + * @param hcd The HCD state structure for the DWC OTG controller.
43319 + * @param qh QH for a periodic endpoint.
43320 + *
43321 + * @return 0 if successful, negative error code otherwise.
43322 + */
43323 +static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43324 +{
43325 + int status;
43326 + uint32_t max_xfer_size;
43327 + uint32_t max_channel_xfer_size;
43328 +
43329 + status = 0;
43330 +
43331 + max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
43332 + max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
43333 +
43334 + if (max_xfer_size > max_channel_xfer_size) {
43335 + DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n",
43336 + __func__, max_xfer_size, max_channel_xfer_size); //NOTICE
43337 + status = -DWC_E_NO_SPACE;
43338 + }
43339 +
43340 + return status;
43341 +}
43342 +
43343 +
43344 +extern int g_next_sched_frame, g_np_count, g_np_sent;
43345 +
43346 +/**
43347 + * Schedules an interrupt or isochronous transfer in the periodic schedule.
43348 + *
43349 + * @param hcd The HCD state structure for the DWC OTG controller.
43350 + * @param qh QH for the periodic transfer. The QH should already contain the
43351 + * scheduling information.
43352 + *
43353 + * @return 0 if successful, negative error code otherwise.
43354 + */
43355 +static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43356 +{
43357 + int status = 0;
43358 +
43359 + if (microframe_schedule) {
43360 + int frame;
43361 + status = find_uframe(hcd, qh);
43362 + frame = -1;
43363 + if (status == 0) {
43364 + frame = 7;
43365 + } else {
43366 + if (status > 0 )
43367 + frame = status-1;
43368 + }
43369 +
43370 + /* Set the new frame up */
43371 + if (frame > -1) {
43372 + qh->sched_frame &= ~0x7;
43373 + qh->sched_frame |= (frame & 7);
43374 + }
43375 +
43376 + if (status != -1)
43377 + status = 0;
43378 + } else {
43379 + status = periodic_channel_available(hcd);
43380 + if (status) {
43381 + DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__); //NOTICE
43382 + return status;
43383 + }
43384 +
43385 + status = check_periodic_bandwidth(hcd, qh);
43386 + }
43387 + if (status) {
43388 + DWC_INFO("%s: Insufficient periodic bandwidth for "
43389 + "periodic transfer.\n", __func__);
43390 + return status;
43391 + }
43392 + status = check_max_xfer_size(hcd, qh);
43393 + if (status) {
43394 + DWC_INFO("%s: Channel max transfer size too small "
43395 + "for periodic transfer.\n", __func__);
43396 + return status;
43397 + }
43398 +
43399 + if (hcd->core_if->dma_desc_enable) {
43400 + /* Don't rely on SOF and start in ready schedule */
43401 + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
43402 + }
43403 + else {
43404 + if(DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, g_next_sched_frame))
43405 + {
43406 + g_next_sched_frame = qh->sched_frame;
43407 +
43408 + }
43409 + /* Always start in the inactive schedule. */
43410 + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
43411 + }
43412 +
43413 + if (!microframe_schedule) {
43414 + /* Reserve the periodic channel. */
43415 + hcd->periodic_channels++;
43416 + }
43417 +
43418 + /* Update claimed usecs per (micro)frame. */
43419 + hcd->periodic_usecs += qh->usecs;
43420 +
43421 + return status;
43422 +}
43423 +
43424 +
43425 +/**
43426 + * This function adds a QH to either the non periodic or periodic schedule if
43427 + * it is not already in the schedule. If the QH is already in the schedule, no
43428 + * action is taken.
43429 + *
43430 + * @return 0 if successful, negative error code otherwise.
43431 + */
43432 +int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43433 +{
43434 + int status = 0;
43435 + gintmsk_data_t intr_mask = {.d32 = 0 };
43436 +
43437 + if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
43438 + /* QH already in a schedule. */
43439 + return status;
43440 + }
43441 +
43442 + /* Add the new QH to the appropriate schedule */
43443 + if (dwc_qh_is_non_per(qh)) {
43444 + /* Always start in the inactive schedule. */
43445 + DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
43446 + &qh->qh_list_entry);
43447 + g_np_count++;
43448 + } else {
43449 + status = schedule_periodic(hcd, qh);
43450 + if ( !hcd->periodic_qh_count ) {
43451 + intr_mask.b.sofintr = 1;
43452 + DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
43453 + intr_mask.d32, intr_mask.d32);
43454 + }
43455 + hcd->periodic_qh_count++;
43456 + }
43457 +
43458 + return status;
43459 +}
43460 +
43461 +/**
43462 + * Removes an interrupt or isochronous transfer from the periodic schedule.
43463 + *
43464 + * @param hcd The HCD state structure for the DWC OTG controller.
43465 + * @param qh QH for the periodic transfer.
43466 + */
43467 +static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43468 +{
43469 + int i;
43470 + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
43471 +
43472 + /* Update claimed usecs per (micro)frame. */
43473 + hcd->periodic_usecs -= qh->usecs;
43474 +
43475 + if (!microframe_schedule) {
43476 + /* Release the periodic channel reservation. */
43477 + hcd->periodic_channels--;
43478 + } else {
43479 + for (i = 0; i < 8; i++) {
43480 + hcd->frame_usecs[i] += qh->frame_usecs[i];
43481 + qh->frame_usecs[i] = 0;
43482 + }
43483 + }
43484 +}
43485 +
43486 +/**
43487 + * Removes a QH from either the non-periodic or periodic schedule. Memory is
43488 + * not freed.
43489 + *
43490 + * @param hcd The HCD state structure.
43491 + * @param qh QH to remove from schedule. */
43492 +void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43493 +{
43494 + gintmsk_data_t intr_mask = {.d32 = 0 };
43495 +
43496 + if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
43497 + /* QH is not in a schedule. */
43498 + return;
43499 + }
43500 +
43501 + if (dwc_qh_is_non_per(qh)) {
43502 + if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
43503 + hcd->non_periodic_qh_ptr =
43504 + hcd->non_periodic_qh_ptr->next;
43505 + }
43506 + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
43507 + } else {
43508 + deschedule_periodic(hcd, qh);
43509 + hcd->periodic_qh_count--;
43510 + if( !hcd->periodic_qh_count ) {
43511 + intr_mask.b.sofintr = 1;
43512 + DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
43513 + intr_mask.d32, 0);
43514 + }
43515 + }
43516 +}
43517 +
43518 +/**
43519 + * Deactivates a QH. For non-periodic QHs, removes the QH from the active
43520 + * non-periodic schedule. The QH is added to the inactive non-periodic
43521 + * schedule if any QTDs are still attached to the QH.
43522 + *
43523 + * For periodic QHs, the QH is removed from the periodic queued schedule. If
43524 + * there are any QTDs still attached to the QH, the QH is added to either the
43525 + * periodic inactive schedule or the periodic ready schedule and its next
43526 + * scheduled frame is calculated. The QH is placed in the ready schedule if
43527 + * the scheduled frame has been reached already. Otherwise it's placed in the
43528 + * inactive schedule. If there are no QTDs attached to the QH, the QH is
43529 + * completely removed from the periodic schedule.
43530 + */
43531 +void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
43532 + int sched_next_periodic_split)
43533 +{
43534 + if (dwc_qh_is_non_per(qh)) {
43535 +
43536 + dwc_otg_qh_t *qh_tmp;
43537 + dwc_list_link_t *qh_list;
43538 + DWC_LIST_FOREACH(qh_list, &hcd->non_periodic_sched_inactive)
43539 + {
43540 + qh_tmp = DWC_LIST_ENTRY(qh_list, struct dwc_otg_qh, qh_list_entry);
43541 + if(qh_tmp == qh)
43542 + {
43543 + /*
43544 + * FIQ is being disabled because this one nevers gets a np_count increment
43545 + * This is still not absolutely correct, but it should fix itself with
43546 + * just an unnecessary extra interrupt
43547 + */
43548 + g_np_sent = g_np_count;
43549 + }
43550 + }
43551 +
43552 +
43553 + dwc_otg_hcd_qh_remove(hcd, qh);
43554 + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
43555 + /* Add back to inactive non-periodic schedule. */
43556 + dwc_otg_hcd_qh_add(hcd, qh);
43557 + }
43558 + } else {
43559 + uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);
43560 +
43561 + if (qh->do_split) {
43562 + /* Schedule the next continuing periodic split transfer */
43563 + if (sched_next_periodic_split) {
43564 +
43565 + qh->sched_frame = frame_number;
43566 +
43567 + if (dwc_frame_num_le(frame_number,
43568 + dwc_frame_num_inc
43569 + (qh->start_split_frame,
43570 + 1))) {
43571 + /*
43572 + * Allow one frame to elapse after start
43573 + * split microframe before scheduling
43574 + * complete split, but DONT if we are
43575 + * doing the next start split in the
43576 + * same frame for an ISOC out.
43577 + */
43578 + if ((qh->ep_type != UE_ISOCHRONOUS) ||
43579 + (qh->ep_is_in != 0)) {
43580 + qh->sched_frame =
43581 + dwc_frame_num_inc(qh->sched_frame, 1);
43582 + }
43583 + }
43584 + } else {
43585 + qh->sched_frame =
43586 + dwc_frame_num_inc(qh->start_split_frame,
43587 + qh->interval);
43588 + if (dwc_frame_num_le
43589 + (qh->sched_frame, frame_number)) {
43590 + qh->sched_frame = frame_number;
43591 + }
43592 + qh->sched_frame |= 0x7;
43593 + qh->start_split_frame = qh->sched_frame;
43594 + }
43595 + } else {
43596 + qh->sched_frame =
43597 + dwc_frame_num_inc(qh->sched_frame, qh->interval);
43598 + if (dwc_frame_num_le(qh->sched_frame, frame_number)) {
43599 + qh->sched_frame = frame_number;
43600 + }
43601 + }
43602 +
43603 + if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
43604 + dwc_otg_hcd_qh_remove(hcd, qh);
43605 + } else {
43606 + /*
43607 + * Remove from periodic_sched_queued and move to
43608 + * appropriate queue.
43609 + */
43610 + if ((microframe_schedule && dwc_frame_num_le(qh->sched_frame, frame_number)) ||
43611 + (!microframe_schedule && qh->sched_frame == frame_number)) {
43612 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
43613 + &qh->qh_list_entry);
43614 + } else {
43615 + if(!dwc_frame_num_le(g_next_sched_frame, qh->sched_frame))
43616 + {
43617 + g_next_sched_frame = qh->sched_frame;
43618 + }
43619 +
43620 + DWC_LIST_MOVE_HEAD
43621 + (&hcd->periodic_sched_inactive,
43622 + &qh->qh_list_entry);
43623 + }
43624 + }
43625 + }
43626 +}
43627 +
43628 +/**
43629 + * This function allocates and initializes a QTD.
43630 + *
43631 + * @param urb The URB to create a QTD from. Each URB-QTD pair will end up
43632 + * pointing to each other so each pair should have a unique correlation.
43633 + * @param atomic_alloc Flag to do atomic alloc if needed
43634 + *
43635 + * @return Returns pointer to the newly allocated QTD, or NULL on error. */
43636 +dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb, int atomic_alloc)
43637 +{
43638 + dwc_otg_qtd_t *qtd;
43639 +
43640 + qtd = dwc_otg_hcd_qtd_alloc(atomic_alloc);
43641 + if (qtd == NULL) {
43642 + return NULL;
43643 + }
43644 +
43645 + dwc_otg_hcd_qtd_init(qtd, urb);
43646 + return qtd;
43647 +}
43648 +
43649 +/**
43650 + * Initializes a QTD structure.
43651 + *
43652 + * @param qtd The QTD to initialize.
43653 + * @param urb The URB to use for initialization. */
43654 +void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
43655 +{
43656 + dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t));
43657 + qtd->urb = urb;
43658 + if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) {
43659 + /*
43660 + * The only time the QTD data toggle is used is on the data
43661 + * phase of control transfers. This phase always starts with
43662 + * DATA1.
43663 + */
43664 + qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
43665 + qtd->control_phase = DWC_OTG_CONTROL_SETUP;
43666 + }
43667 +
43668 + /* start split */
43669 + qtd->complete_split = 0;
43670 + qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
43671 + qtd->isoc_split_offset = 0;
43672 + qtd->in_process = 0;
43673 +
43674 + /* Store the qtd ptr in the urb to reference what QTD. */
43675 + urb->qtd = qtd;
43676 + return;
43677 +}
43678 +
43679 +/**
43680 + * This function adds a QTD to the QTD-list of a QH. It will find the correct
43681 + * QH to place the QTD into. If it does not find a QH, then it will create a
43682 + * new QH. If the QH to which the QTD is added is not currently scheduled, it
43683 + * is placed into the proper schedule based on its EP type.
43684 + *
43685 + * @param[in] qtd The QTD to add
43686 + * @param[in] hcd The DWC HCD structure
43687 + * @param[out] qh out parameter to return queue head
43688 + * @param atomic_alloc Flag to do atomic alloc if needed
43689 + *
43690 + * @return 0 if successful, negative error code otherwise.
43691 + */
43692 +int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
43693 + dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
43694 +{
43695 + int retval = 0;
43696 + dwc_irqflags_t flags;
43697 +
43698 + dwc_otg_hcd_urb_t *urb = qtd->urb;
43699 +
43700 + /*
43701 + * Get the QH which holds the QTD-list to insert to. Create QH if it
43702 + * doesn't exist.
43703 + */
43704 + if (*qh == NULL) {
43705 + *qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
43706 + if (*qh == NULL) {
43707 + retval = -DWC_E_NO_MEMORY;
43708 + goto done;
43709 + }
43710 + }
43711 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
43712 + retval = dwc_otg_hcd_qh_add(hcd, *qh);
43713 + if (retval == 0) {
43714 + DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
43715 + qtd_list_entry);
43716 + qtd->qh = *qh;
43717 + }
43718 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
43719 +
43720 +done:
43721 +
43722 + return retval;
43723 +}
43724 +
43725 +#endif /* DWC_DEVICE_ONLY */
43726 --- /dev/null
43727 +++ b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c
43728 @@ -0,0 +1,113 @@
43729 +#include "dwc_otg_regs.h"
43730 +#include "dwc_otg_dbg.h"
43731 +
43732 +void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name)
43733 +{
43734 + DWC_DEBUGPL(DBG_USER, "*** Debugging from within the %s function: ***\n"
43735 + "curmode: %1i Modemismatch: %1i otgintr: %1i sofintr: %1i\n"
43736 + "rxstsqlvl: %1i nptxfempty : %1i ginnakeff: %1i goutnakeff: %1i\n"
43737 + "ulpickint: %1i i2cintr: %1i erlysuspend:%1i usbsuspend: %1i\n"
43738 + "usbreset: %1i enumdone: %1i isooutdrop: %1i eopframe: %1i\n"
43739 + "restoredone: %1i epmismatch: %1i inepint: %1i outepintr: %1i\n"
43740 + "incomplisoin:%1i incomplisoout:%1i fetsusp: %1i resetdet: %1i\n"
43741 + "portintr: %1i hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i\n"
43742 + "conidstschng:%1i disconnect: %1i sessreqintr:%1i wkupintr: %1i\n",
43743 + function_name,
43744 + gintsts.b.curmode,
43745 + gintsts.b.modemismatch,
43746 + gintsts.b.otgintr,
43747 + gintsts.b.sofintr,
43748 + gintsts.b.rxstsqlvl,
43749 + gintsts.b.nptxfempty,
43750 + gintsts.b.ginnakeff,
43751 + gintsts.b.goutnakeff,
43752 + gintsts.b.ulpickint,
43753 + gintsts.b.i2cintr,
43754 + gintsts.b.erlysuspend,
43755 + gintsts.b.usbsuspend,
43756 + gintsts.b.usbreset,
43757 + gintsts.b.enumdone,
43758 + gintsts.b.isooutdrop,
43759 + gintsts.b.eopframe,
43760 + gintsts.b.restoredone,
43761 + gintsts.b.epmismatch,
43762 + gintsts.b.inepint,
43763 + gintsts.b.outepintr,
43764 + gintsts.b.incomplisoin,
43765 + gintsts.b.incomplisoout,
43766 + gintsts.b.fetsusp,
43767 + gintsts.b.resetdet,
43768 + gintsts.b.portintr,
43769 + gintsts.b.hcintr,
43770 + gintsts.b.ptxfempty,
43771 + gintsts.b.lpmtranrcvd,
43772 + gintsts.b.conidstschng,
43773 + gintsts.b.disconnect,
43774 + gintsts.b.sessreqintr,
43775 + gintsts.b.wkupintr);
43776 + return;
43777 +}
43778 +
43779 +void dwc_debug_core_int_mask(gintmsk_data_t gintmsk, const char* function_name)
43780 +{
43781 + DWC_DEBUGPL(DBG_USER, "Interrupt Mask status (called from %s) :\n"
43782 + "modemismatch: %1i otgintr: %1i sofintr: %1i rxstsqlvl: %1i\n"
43783 + "nptxfempty: %1i ginnakeff: %1i goutnakeff: %1i ulpickint: %1i\n"
43784 + "i2cintr: %1i erlysuspend:%1i usbsuspend: %1i usbreset: %1i\n"
43785 + "enumdone: %1i isooutdrop: %1i eopframe: %1i restoredone: %1i\n"
43786 + "epmismatch: %1i inepintr: %1i outepintr: %1i incomplisoin:%1i\n"
43787 + "incomplisoout:%1i fetsusp: %1i resetdet: %1i portintr: %1i\n"
43788 + "hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i conidstschng:%1i\n"
43789 + "disconnect: %1i sessreqintr:%1i wkupintr: %1i\n",
43790 + function_name,
43791 + gintmsk.b.modemismatch,
43792 + gintmsk.b.otgintr,
43793 + gintmsk.b.sofintr,
43794 + gintmsk.b.rxstsqlvl,
43795 + gintmsk.b.nptxfempty,
43796 + gintmsk.b.ginnakeff,
43797 + gintmsk.b.goutnakeff,
43798 + gintmsk.b.ulpickint,
43799 + gintmsk.b.i2cintr,
43800 + gintmsk.b.erlysuspend,
43801 + gintmsk.b.usbsuspend,
43802 + gintmsk.b.usbreset,
43803 + gintmsk.b.enumdone,
43804 + gintmsk.b.isooutdrop,
43805 + gintmsk.b.eopframe,
43806 + gintmsk.b.restoredone,
43807 + gintmsk.b.epmismatch,
43808 + gintmsk.b.inepintr,
43809 + gintmsk.b.outepintr,
43810 + gintmsk.b.incomplisoin,
43811 + gintmsk.b.incomplisoout,
43812 + gintmsk.b.fetsusp,
43813 + gintmsk.b.resetdet,
43814 + gintmsk.b.portintr,
43815 + gintmsk.b.hcintr,
43816 + gintmsk.b.ptxfempty,
43817 + gintmsk.b.lpmtranrcvd,
43818 + gintmsk.b.conidstschng,
43819 + gintmsk.b.disconnect,
43820 + gintmsk.b.sessreqintr,
43821 + gintmsk.b.wkupintr);
43822 + return;
43823 +}
43824 +
43825 +void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name)
43826 +{
43827 + DWC_DEBUGPL(DBG_USER, "otg int register (from %s function):\n"
43828 + "sesenddet:%1i sesreqsucstschung:%2i hstnegsucstschng:%1i\n"
43829 + "hstnegdet:%1i adevtoutchng: %2i debdone: %1i\n"
43830 + "mvic: %1i\n",
43831 + function_name,
43832 + gotgint.b.sesenddet,
43833 + gotgint.b.sesreqsucstschng,
43834 + gotgint.b.hstnegsucstschng,
43835 + gotgint.b.hstnegdet,
43836 + gotgint.b.adevtoutchng,
43837 + gotgint.b.debdone,
43838 + gotgint.b.mvic);
43839 +
43840 + return;
43841 +}
43842 --- /dev/null
43843 +++ b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h
43844 @@ -0,0 +1,36 @@
43845 +#ifndef __DWC_OTG_MPHI_FIX_H__
43846 +#define __DWC_OTG_MPHI_FIX_H__
43847 +
43848 +#define FIQ_WRITE_IO_ADDRESS(_addr_,_data_) *(volatile uint32_t *) IO_ADDRESS(_addr_) = _data_
43849 +#define FIQ_READ_IO_ADDRESS(_addr_) *(volatile uint32_t *) IO_ADDRESS(_addr_)
43850 +#define FIQ_MODIFY_IO_ADDRESS(_addr_,_clear_,_set_) FIQ_WRITE_IO_ADDRESS(_addr_ , (FIQ_READ_IO_ADDRESS(_addr_)&~_clear_)|_set_)
43851 +#define FIQ_WRITE(_addr_,_data_) *(volatile uint32_t *) _addr_ = _data_
43852 +
43853 +typedef struct {
43854 + volatile void* base;
43855 + volatile void* ctrl;
43856 + volatile void* outdda;
43857 + volatile void* outddb;
43858 + volatile void* intstat;
43859 +} mphi_regs_t;
43860 +
43861 +void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name);
43862 +void dwc_debug_core_int_mask(gintsts_data_t gintmsk, const char* function_name);
43863 +void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name);
43864 +
43865 +
43866 +
43867 +#ifdef DEBUG
43868 +#define DWC_DBG_PRINT_CORE_INT(_arg_) dwc_debug_print_core_int_reg(_arg_,__func__)
43869 +#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_) dwc_debug_core_int_mask(_arg_,__func__)
43870 +#define DWC_DBG_PRINT_OTG_INT(_arg_) dwc_debug_otg_int(_arg_,__func__)
43871 +
43872 +#else
43873 +#define DWC_DBG_PRINT_CORE_INT(_arg_)
43874 +#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_)
43875 +#define DWC_DBG_PRINT_OTG_INT(_arg_)
43876 +
43877 +
43878 +#endif
43879 +
43880 +#endif
43881 --- /dev/null
43882 +++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
43883 @@ -0,0 +1,188 @@
43884 +#ifndef _DWC_OS_DEP_H_
43885 +#define _DWC_OS_DEP_H_
43886 +
43887 +/**
43888 + * @file
43889 + *
43890 + * This file contains OS dependent structures.
43891 + *
43892 + */
43893 +
43894 +#include <linux/kernel.h>
43895 +#include <linux/module.h>
43896 +#include <linux/moduleparam.h>
43897 +#include <linux/init.h>
43898 +#include <linux/device.h>
43899 +#include <linux/errno.h>
43900 +#include <linux/types.h>
43901 +#include <linux/slab.h>
43902 +#include <linux/list.h>
43903 +#include <linux/interrupt.h>
43904 +#include <linux/ctype.h>
43905 +#include <linux/string.h>
43906 +#include <linux/dma-mapping.h>
43907 +#include <linux/jiffies.h>
43908 +#include <linux/delay.h>
43909 +#include <linux/timer.h>
43910 +#include <linux/workqueue.h>
43911 +#include <linux/stat.h>
43912 +#include <linux/pci.h>
43913 +
43914 +#include <linux/version.h>
43915 +
43916 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
43917 +# include <linux/irq.h>
43918 +#endif
43919 +
43920 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
43921 +# include <linux/usb/ch9.h>
43922 +#else
43923 +# include <linux/usb_ch9.h>
43924 +#endif
43925 +
43926 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
43927 +# include <linux/usb/gadget.h>
43928 +#else
43929 +# include <linux/usb_gadget.h>
43930 +#endif
43931 +
43932 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
43933 +# include <asm/irq.h>
43934 +#endif
43935 +
43936 +#ifdef PCI_INTERFACE
43937 +# include <asm/io.h>
43938 +#endif
43939 +
43940 +#ifdef LM_INTERFACE
43941 +# include <asm/unaligned.h>
43942 +# include <asm/sizes.h>
43943 +# include <asm/param.h>
43944 +# include <asm/io.h>
43945 +# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
43946 +# include <asm/arch/hardware.h>
43947 +# include <asm/arch/lm.h>
43948 +# include <asm/arch/irqs.h>
43949 +# include <asm/arch/regs-irq.h>
43950 +# else
43951 +/* in 2.6.31, at least, we seem to have lost the generic LM infrastructure -
43952 + here we assume that the machine architecture provides definitions
43953 + in its own header
43954 +*/
43955 +# include <mach/lm.h>
43956 +# include <mach/hardware.h>
43957 +# endif
43958 +#endif
43959 +
43960 +#ifdef PLATFORM_INTERFACE
43961 +#include <linux/platform_device.h>
43962 +#include <asm/mach/map.h>
43963 +#endif
43964 +
43965 +/** The OS page size */
43966 +#define DWC_OS_PAGE_SIZE PAGE_SIZE
43967 +
43968 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
43969 +typedef int gfp_t;
43970 +#endif
43971 +
43972 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
43973 +# define IRQF_SHARED SA_SHIRQ
43974 +#endif
43975 +
43976 +typedef struct os_dependent {
43977 + /** Base address returned from ioremap() */
43978 + void *base;
43979 +
43980 + /** Register offset for Diagnostic API */
43981 + uint32_t reg_offset;
43982 +
43983 + /** Base address for MPHI peripheral */
43984 + void *mphi_base;
43985 +
43986 +#ifdef LM_INTERFACE
43987 + struct lm_device *lmdev;
43988 +#elif defined(PCI_INTERFACE)
43989 + struct pci_dev *pcidev;
43990 +
43991 + /** Start address of a PCI region */
43992 + resource_size_t rsrc_start;
43993 +
43994 + /** Length address of a PCI region */
43995 + resource_size_t rsrc_len;
43996 +#elif defined(PLATFORM_INTERFACE)
43997 + struct platform_device *platformdev;
43998 +#endif
43999 +
44000 +} os_dependent_t;
44001 +
44002 +#ifdef __cplusplus
44003 +}
44004 +#endif
44005 +
44006 +
44007 +
44008 +/* Type for the our device on the chosen bus */
44009 +#if defined(LM_INTERFACE)
44010 +typedef struct lm_device dwc_bus_dev_t;
44011 +#elif defined(PCI_INTERFACE)
44012 +typedef struct pci_dev dwc_bus_dev_t;
44013 +#elif defined(PLATFORM_INTERFACE)
44014 +typedef struct platform_device dwc_bus_dev_t;
44015 +#endif
44016 +
44017 +/* Helper macro to retrieve drvdata from the device on the chosen bus */
44018 +#if defined(LM_INTERFACE)
44019 +#define DWC_OTG_BUSDRVDATA(_dev) lm_get_drvdata(_dev)
44020 +#elif defined(PCI_INTERFACE)
44021 +#define DWC_OTG_BUSDRVDATA(_dev) pci_get_drvdata(_dev)
44022 +#elif defined(PLATFORM_INTERFACE)
44023 +#define DWC_OTG_BUSDRVDATA(_dev) platform_get_drvdata(_dev)
44024 +#endif
44025 +
44026 +/**
44027 + * Helper macro returning the otg_device structure of a given struct device
44028 + *
44029 + * c.f. static dwc_otg_device_t *dwc_otg_drvdev(struct device *_dev)
44030 + */
44031 +#ifdef LM_INTERFACE
44032 +#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
44033 + struct lm_device *lm_dev = \
44034 + container_of(_dev, struct lm_device, dev); \
44035 + _var = lm_get_drvdata(lm_dev); \
44036 + } while (0)
44037 +
44038 +#elif defined(PCI_INTERFACE)
44039 +#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
44040 + _var = dev_get_drvdata(_dev); \
44041 + } while (0)
44042 +
44043 +#elif defined(PLATFORM_INTERFACE)
44044 +#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
44045 + struct platform_device *platform_dev = \
44046 + container_of(_dev, struct platform_device, dev); \
44047 + _var = platform_get_drvdata(platform_dev); \
44048 + } while (0)
44049 +#endif
44050 +
44051 +
44052 +/**
44053 + * Helper macro returning the struct dev of the given struct os_dependent
44054 + *
44055 + * c.f. static struct device *dwc_otg_getdev(struct os_dependent *osdep)
44056 + */
44057 +#ifdef LM_INTERFACE
44058 +#define DWC_OTG_OS_GETDEV(_osdep) \
44059 + ((_osdep).lmdev == NULL? NULL: &(_osdep).lmdev->dev)
44060 +#elif defined(PCI_INTERFACE)
44061 +#define DWC_OTG_OS_GETDEV(_osdep) \
44062 + ((_osdep).pci_dev == NULL? NULL: &(_osdep).pci_dev->dev)
44063 +#elif defined(PLATFORM_INTERFACE)
44064 +#define DWC_OTG_OS_GETDEV(_osdep) \
44065 + ((_osdep).platformdev == NULL? NULL: &(_osdep).platformdev->dev)
44066 +#endif
44067 +
44068 +
44069 +
44070 +
44071 +#endif /* _DWC_OS_DEP_H_ */
44072 --- /dev/null
44073 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd.c
44074 @@ -0,0 +1,2708 @@
44075 +/* ==========================================================================
44076 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.c $
44077 + * $Revision: #101 $
44078 + * $Date: 2012/08/10 $
44079 + * $Change: 2047372 $
44080 + *
44081 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
44082 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
44083 + * otherwise expressly agreed to in writing between Synopsys and you.
44084 + *
44085 + * The Software IS NOT an item of Licensed Software or Licensed Product under
44086 + * any End User Software License Agreement or Agreement for Licensed Product
44087 + * with Synopsys or any supplement thereto. You are permitted to use and
44088 + * redistribute this Software in source and binary forms, with or without
44089 + * modification, provided that redistributions of source code must retain this
44090 + * notice. You may not view, use, disclose, copy or distribute this file or
44091 + * any information contained herein except pursuant to this license grant from
44092 + * Synopsys. If you do not agree with this notice, including the disclaimer
44093 + * below, then you are not authorized to use the Software.
44094 + *
44095 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
44096 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44097 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44098 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
44099 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
44100 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
44101 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
44102 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44103 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44104 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
44105 + * DAMAGE.
44106 + * ========================================================================== */
44107 +#ifndef DWC_HOST_ONLY
44108 +
44109 +/** @file
44110 + * This file implements PCD Core. All code in this file is portable and doesn't
44111 + * use any OS specific functions.
44112 + * PCD Core provides Interface, defined in <code><dwc_otg_pcd_if.h></code>
44113 + * header file, which can be used to implement OS specific PCD interface.
44114 + *
44115 + * An important function of the PCD is managing interrupts generated
44116 + * by the DWC_otg controller. The implementation of the DWC_otg device
44117 + * mode interrupt service routines is in dwc_otg_pcd_intr.c.
44118 + *
44119 + * @todo Add Device Mode test modes (Test J mode, Test K mode, etc).
44120 + * @todo Does it work when the request size is greater than DEPTSIZ
44121 + * transfer size
44122 + *
44123 + */
44124 +
44125 +#include "dwc_otg_pcd.h"
44126 +
44127 +#ifdef DWC_UTE_CFI
44128 +#include "dwc_otg_cfi.h"
44129 +
44130 +extern int init_cfi(cfiobject_t * cfiobj);
44131 +#endif
44132 +
44133 +/**
44134 + * Choose endpoint from ep arrays using usb_ep structure.
44135 + */
44136 +static dwc_otg_pcd_ep_t *get_ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
44137 +{
44138 + int i;
44139 + if (pcd->ep0.priv == handle) {
44140 + return &pcd->ep0;
44141 + }
44142 + for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
44143 + if (pcd->in_ep[i].priv == handle)
44144 + return &pcd->in_ep[i];
44145 + if (pcd->out_ep[i].priv == handle)
44146 + return &pcd->out_ep[i];
44147 + }
44148 +
44149 + return NULL;
44150 +}
44151 +
44152 +/**
44153 + * This function completes a request. It call's the request call back.
44154 + */
44155 +void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req,
44156 + int32_t status)
44157 +{
44158 + unsigned stopped = ep->stopped;
44159 +
44160 + DWC_DEBUGPL(DBG_PCDV, "%s(ep %p req %p)\n", __func__, ep, req);
44161 + DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
44162 +
44163 + /* don't modify queue heads during completion callback */
44164 + ep->stopped = 1;
44165 + /* spin_unlock/spin_lock now done in fops->complete() */
44166 + ep->pcd->fops->complete(ep->pcd, ep->priv, req->priv, status,
44167 + req->actual);
44168 +
44169 + if (ep->pcd->request_pending > 0) {
44170 + --ep->pcd->request_pending;
44171 + }
44172 +
44173 + ep->stopped = stopped;
44174 + DWC_FREE(req);
44175 +}
44176 +
44177 +/**
44178 + * This function terminates all the requsts in the EP request queue.
44179 + */
44180 +void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep)
44181 +{
44182 + dwc_otg_pcd_request_t *req;
44183 +
44184 + ep->stopped = 1;
44185 +
44186 + /* called with irqs blocked?? */
44187 + while (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
44188 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
44189 + dwc_otg_request_done(ep, req, -DWC_E_SHUTDOWN);
44190 + }
44191 +}
44192 +
44193 +void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
44194 + const struct dwc_otg_pcd_function_ops *fops)
44195 +{
44196 + pcd->fops = fops;
44197 +}
44198 +
44199 +/**
44200 + * PCD Callback function for initializing the PCD when switching to
44201 + * device mode.
44202 + *
44203 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
44204 + */
44205 +static int32_t dwc_otg_pcd_start_cb(void *p)
44206 +{
44207 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
44208 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
44209 +
44210 + /*
44211 + * Initialized the Core for Device mode.
44212 + */
44213 + if (dwc_otg_is_device_mode(core_if)) {
44214 + dwc_otg_core_dev_init(core_if);
44215 + /* Set core_if's lock pointer to the pcd->lock */
44216 + core_if->lock = pcd->lock;
44217 + }
44218 + return 1;
44219 +}
44220 +
44221 +/** CFI-specific buffer allocation function for EP */
44222 +#ifdef DWC_UTE_CFI
44223 +uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
44224 + size_t buflen, int flags)
44225 +{
44226 + dwc_otg_pcd_ep_t *ep;
44227 + ep = get_ep_from_handle(pcd, pep);
44228 + if (!ep) {
44229 + DWC_WARN("bad ep\n");
44230 + return -DWC_E_INVALID;
44231 + }
44232 +
44233 + return pcd->cfi->ops.ep_alloc_buf(pcd->cfi, pcd, ep, addr, buflen,
44234 + flags);
44235 +}
44236 +#else
44237 +uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
44238 + size_t buflen, int flags);
44239 +#endif
44240 +
44241 +/**
44242 + * PCD Callback function for notifying the PCD when resuming from
44243 + * suspend.
44244 + *
44245 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
44246 + */
44247 +static int32_t dwc_otg_pcd_resume_cb(void *p)
44248 +{
44249 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
44250 +
44251 + if (pcd->fops->resume) {
44252 + pcd->fops->resume(pcd);
44253 + }
44254 +
44255 + /* Stop the SRP timeout timer. */
44256 + if ((GET_CORE_IF(pcd)->core_params->phy_type != DWC_PHY_TYPE_PARAM_FS)
44257 + || (!GET_CORE_IF(pcd)->core_params->i2c_enable)) {
44258 + if (GET_CORE_IF(pcd)->srp_timer_started) {
44259 + GET_CORE_IF(pcd)->srp_timer_started = 0;
44260 + DWC_TIMER_CANCEL(GET_CORE_IF(pcd)->srp_timer);
44261 + }
44262 + }
44263 + return 1;
44264 +}
44265 +
44266 +/**
44267 + * PCD Callback function for notifying the PCD device is suspended.
44268 + *
44269 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
44270 + */
44271 +static int32_t dwc_otg_pcd_suspend_cb(void *p)
44272 +{
44273 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
44274 +
44275 + if (pcd->fops->suspend) {
44276 + DWC_SPINUNLOCK(pcd->lock);
44277 + pcd->fops->suspend(pcd);
44278 + DWC_SPINLOCK(pcd->lock);
44279 + }
44280 +
44281 + return 1;
44282 +}
44283 +
44284 +/**
44285 + * PCD Callback function for stopping the PCD when switching to Host
44286 + * mode.
44287 + *
44288 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
44289 + */
44290 +static int32_t dwc_otg_pcd_stop_cb(void *p)
44291 +{
44292 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
44293 + extern void dwc_otg_pcd_stop(dwc_otg_pcd_t * _pcd);
44294 +
44295 + dwc_otg_pcd_stop(pcd);
44296 + return 1;
44297 +}
44298 +
44299 +/**
44300 + * PCD Callback structure for handling mode switching.
44301 + */
44302 +static dwc_otg_cil_callbacks_t pcd_callbacks = {
44303 + .start = dwc_otg_pcd_start_cb,
44304 + .stop = dwc_otg_pcd_stop_cb,
44305 + .suspend = dwc_otg_pcd_suspend_cb,
44306 + .resume_wakeup = dwc_otg_pcd_resume_cb,
44307 + .p = 0, /* Set at registration */
44308 +};
44309 +
44310 +/**
44311 + * This function allocates a DMA Descriptor chain for the Endpoint
44312 + * buffer to be used for a transfer to/from the specified endpoint.
44313 + */
44314 +dwc_otg_dev_dma_desc_t *dwc_otg_ep_alloc_desc_chain(dwc_dma_t * dma_desc_addr,
44315 + uint32_t count)
44316 +{
44317 + return DWC_DMA_ALLOC_ATOMIC(count * sizeof(dwc_otg_dev_dma_desc_t),
44318 + dma_desc_addr);
44319 +}
44320 +
44321 +/**
44322 + * This function frees a DMA Descriptor chain that was allocated by ep_alloc_desc.
44323 + */
44324 +void dwc_otg_ep_free_desc_chain(dwc_otg_dev_dma_desc_t * desc_addr,
44325 + uint32_t dma_desc_addr, uint32_t count)
44326 +{
44327 + DWC_DMA_FREE(count * sizeof(dwc_otg_dev_dma_desc_t), desc_addr,
44328 + dma_desc_addr);
44329 +}
44330 +
44331 +#ifdef DWC_EN_ISOC
44332 +
44333 +/**
44334 + * This function initializes a descriptor chain for Isochronous transfer
44335 + *
44336 + * @param core_if Programming view of DWC_otg controller.
44337 + * @param dwc_ep The EP to start the transfer on.
44338 + *
44339 + */
44340 +void dwc_otg_iso_ep_start_ddma_transfer(dwc_otg_core_if_t * core_if,
44341 + dwc_ep_t * dwc_ep)
44342 +{
44343 +
44344 + dsts_data_t dsts = {.d32 = 0 };
44345 + depctl_data_t depctl = {.d32 = 0 };
44346 + volatile uint32_t *addr;
44347 + int i, j;
44348 + uint32_t len;
44349 +
44350 + if (dwc_ep->is_in)
44351 + dwc_ep->desc_cnt = dwc_ep->buf_proc_intrvl / dwc_ep->bInterval;
44352 + else
44353 + dwc_ep->desc_cnt =
44354 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
44355 + dwc_ep->bInterval;
44356 +
44357 + /** Allocate descriptors for double buffering */
44358 + dwc_ep->iso_desc_addr =
44359 + dwc_otg_ep_alloc_desc_chain(&dwc_ep->iso_dma_desc_addr,
44360 + dwc_ep->desc_cnt * 2);
44361 + if (dwc_ep->desc_addr) {
44362 + DWC_WARN("%s, can't allocate DMA descriptor chain\n", __func__);
44363 + return;
44364 + }
44365 +
44366 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
44367 +
44368 + /** ISO OUT EP */
44369 + if (dwc_ep->is_in == 0) {
44370 + dev_dma_desc_sts_t sts = {.d32 = 0 };
44371 + dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
44372 + dma_addr_t dma_ad;
44373 + uint32_t data_per_desc;
44374 + dwc_otg_dev_out_ep_regs_t *out_regs =
44375 + core_if->dev_if->out_ep_regs[dwc_ep->num];
44376 + int offset;
44377 +
44378 + addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
44379 + dma_ad = (dma_addr_t) DWC_READ_REG32(&(out_regs->doepdma));
44380 +
44381 + /** Buffer 0 descriptors setup */
44382 + dma_ad = dwc_ep->dma_addr0;
44383 +
44384 + sts.b_iso_out.bs = BS_HOST_READY;
44385 + sts.b_iso_out.rxsts = 0;
44386 + sts.b_iso_out.l = 0;
44387 + sts.b_iso_out.sp = 0;
44388 + sts.b_iso_out.ioc = 0;
44389 + sts.b_iso_out.pid = 0;
44390 + sts.b_iso_out.framenum = 0;
44391 +
44392 + offset = 0;
44393 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
44394 + i += dwc_ep->pkt_per_frm) {
44395 +
44396 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
44397 + uint32_t len = (j + 1) * dwc_ep->maxpacket;
44398 + if (len > dwc_ep->data_per_frame)
44399 + data_per_desc =
44400 + dwc_ep->data_per_frame -
44401 + j * dwc_ep->maxpacket;
44402 + else
44403 + data_per_desc = dwc_ep->maxpacket;
44404 + len = data_per_desc % 4;
44405 + if (len)
44406 + data_per_desc += 4 - len;
44407 +
44408 + sts.b_iso_out.rxbytes = data_per_desc;
44409 + dma_desc->buf = dma_ad;
44410 + dma_desc->status.d32 = sts.d32;
44411 +
44412 + offset += data_per_desc;
44413 + dma_desc++;
44414 + dma_ad += data_per_desc;
44415 + }
44416 + }
44417 +
44418 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
44419 + uint32_t len = (j + 1) * dwc_ep->maxpacket;
44420 + if (len > dwc_ep->data_per_frame)
44421 + data_per_desc =
44422 + dwc_ep->data_per_frame -
44423 + j * dwc_ep->maxpacket;
44424 + else
44425 + data_per_desc = dwc_ep->maxpacket;
44426 + len = data_per_desc % 4;
44427 + if (len)
44428 + data_per_desc += 4 - len;
44429 + sts.b_iso_out.rxbytes = data_per_desc;
44430 + dma_desc->buf = dma_ad;
44431 + dma_desc->status.d32 = sts.d32;
44432 +
44433 + offset += data_per_desc;
44434 + dma_desc++;
44435 + dma_ad += data_per_desc;
44436 + }
44437 +
44438 + sts.b_iso_out.ioc = 1;
44439 + len = (j + 1) * dwc_ep->maxpacket;
44440 + if (len > dwc_ep->data_per_frame)
44441 + data_per_desc =
44442 + dwc_ep->data_per_frame - j * dwc_ep->maxpacket;
44443 + else
44444 + data_per_desc = dwc_ep->maxpacket;
44445 + len = data_per_desc % 4;
44446 + if (len)
44447 + data_per_desc += 4 - len;
44448 + sts.b_iso_out.rxbytes = data_per_desc;
44449 +
44450 + dma_desc->buf = dma_ad;
44451 + dma_desc->status.d32 = sts.d32;
44452 + dma_desc++;
44453 +
44454 + /** Buffer 1 descriptors setup */
44455 + sts.b_iso_out.ioc = 0;
44456 + dma_ad = dwc_ep->dma_addr1;
44457 +
44458 + offset = 0;
44459 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
44460 + i += dwc_ep->pkt_per_frm) {
44461 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
44462 + uint32_t len = (j + 1) * dwc_ep->maxpacket;
44463 + if (len > dwc_ep->data_per_frame)
44464 + data_per_desc =
44465 + dwc_ep->data_per_frame -
44466 + j * dwc_ep->maxpacket;
44467 + else
44468 + data_per_desc = dwc_ep->maxpacket;
44469 + len = data_per_desc % 4;
44470 + if (len)
44471 + data_per_desc += 4 - len;
44472 +
44473 + data_per_desc =
44474 + sts.b_iso_out.rxbytes = data_per_desc;
44475 + dma_desc->buf = dma_ad;
44476 + dma_desc->status.d32 = sts.d32;
44477 +
44478 + offset += data_per_desc;
44479 + dma_desc++;
44480 + dma_ad += data_per_desc;
44481 + }
44482 + }
44483 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
44484 + data_per_desc =
44485 + ((j + 1) * dwc_ep->maxpacket >
44486 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
44487 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
44488 + data_per_desc +=
44489 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
44490 + sts.b_iso_out.rxbytes = data_per_desc;
44491 + dma_desc->buf = dma_ad;
44492 + dma_desc->status.d32 = sts.d32;
44493 +
44494 + offset += data_per_desc;
44495 + dma_desc++;
44496 + dma_ad += data_per_desc;
44497 + }
44498 +
44499 + sts.b_iso_out.ioc = 1;
44500 + sts.b_iso_out.l = 1;
44501 + data_per_desc =
44502 + ((j + 1) * dwc_ep->maxpacket >
44503 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
44504 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
44505 + data_per_desc +=
44506 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
44507 + sts.b_iso_out.rxbytes = data_per_desc;
44508 +
44509 + dma_desc->buf = dma_ad;
44510 + dma_desc->status.d32 = sts.d32;
44511 +
44512 + dwc_ep->next_frame = 0;
44513 +
44514 + /** Write dma_ad into DOEPDMA register */
44515 + DWC_WRITE_REG32(&(out_regs->doepdma),
44516 + (uint32_t) dwc_ep->iso_dma_desc_addr);
44517 +
44518 + }
44519 + /** ISO IN EP */
44520 + else {
44521 + dev_dma_desc_sts_t sts = {.d32 = 0 };
44522 + dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
44523 + dma_addr_t dma_ad;
44524 + dwc_otg_dev_in_ep_regs_t *in_regs =
44525 + core_if->dev_if->in_ep_regs[dwc_ep->num];
44526 + unsigned int frmnumber;
44527 + fifosize_data_t txfifosize, rxfifosize;
44528 +
44529 + txfifosize.d32 =
44530 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[dwc_ep->num]->
44531 + dtxfsts);
44532 + rxfifosize.d32 =
44533 + DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
44534 +
44535 + addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
44536 +
44537 + dma_ad = dwc_ep->dma_addr0;
44538 +
44539 + dsts.d32 =
44540 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
44541 +
44542 + sts.b_iso_in.bs = BS_HOST_READY;
44543 + sts.b_iso_in.txsts = 0;
44544 + sts.b_iso_in.sp =
44545 + (dwc_ep->data_per_frame % dwc_ep->maxpacket) ? 1 : 0;
44546 + sts.b_iso_in.ioc = 0;
44547 + sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
44548 +
44549 + frmnumber = dwc_ep->next_frame;
44550 +
44551 + sts.b_iso_in.framenum = frmnumber;
44552 + sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
44553 + sts.b_iso_in.l = 0;
44554 +
44555 + /** Buffer 0 descriptors setup */
44556 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
44557 + dma_desc->buf = dma_ad;
44558 + dma_desc->status.d32 = sts.d32;
44559 + dma_desc++;
44560 +
44561 + dma_ad += dwc_ep->data_per_frame;
44562 + sts.b_iso_in.framenum += dwc_ep->bInterval;
44563 + }
44564 +
44565 + sts.b_iso_in.ioc = 1;
44566 + dma_desc->buf = dma_ad;
44567 + dma_desc->status.d32 = sts.d32;
44568 + ++dma_desc;
44569 +
44570 + /** Buffer 1 descriptors setup */
44571 + sts.b_iso_in.ioc = 0;
44572 + dma_ad = dwc_ep->dma_addr1;
44573 +
44574 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
44575 + i += dwc_ep->pkt_per_frm) {
44576 + dma_desc->buf = dma_ad;
44577 + dma_desc->status.d32 = sts.d32;
44578 + dma_desc++;
44579 +
44580 + dma_ad += dwc_ep->data_per_frame;
44581 + sts.b_iso_in.framenum += dwc_ep->bInterval;
44582 +
44583 + sts.b_iso_in.ioc = 0;
44584 + }
44585 + sts.b_iso_in.ioc = 1;
44586 + sts.b_iso_in.l = 1;
44587 +
44588 + dma_desc->buf = dma_ad;
44589 + dma_desc->status.d32 = sts.d32;
44590 +
44591 + dwc_ep->next_frame = sts.b_iso_in.framenum + dwc_ep->bInterval;
44592 +
44593 + /** Write dma_ad into diepdma register */
44594 + DWC_WRITE_REG32(&(in_regs->diepdma),
44595 + (uint32_t) dwc_ep->iso_dma_desc_addr);
44596 + }
44597 + /** Enable endpoint, clear nak */
44598 + depctl.d32 = 0;
44599 + depctl.b.epena = 1;
44600 + depctl.b.usbactep = 1;
44601 + depctl.b.cnak = 1;
44602 +
44603 + DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
44604 + depctl.d32 = DWC_READ_REG32(addr);
44605 +}
44606 +
44607 +/**
44608 + * This function initializes a descriptor chain for Isochronous transfer
44609 + *
44610 + * @param core_if Programming view of DWC_otg controller.
44611 + * @param ep The EP to start the transfer on.
44612 + *
44613 + */
44614 +void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
44615 + dwc_ep_t * ep)
44616 +{
44617 + depctl_data_t depctl = {.d32 = 0 };
44618 + volatile uint32_t *addr;
44619 +
44620 + if (ep->is_in) {
44621 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
44622 + } else {
44623 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
44624 + }
44625 +
44626 + if (core_if->dma_enable == 0 || core_if->dma_desc_enable != 0) {
44627 + return;
44628 + } else {
44629 + deptsiz_data_t deptsiz = {.d32 = 0 };
44630 +
44631 + ep->xfer_len =
44632 + ep->data_per_frame * ep->buf_proc_intrvl / ep->bInterval;
44633 + ep->pkt_cnt =
44634 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
44635 + ep->xfer_count = 0;
44636 + ep->xfer_buff =
44637 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
44638 + ep->dma_addr =
44639 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
44640 +
44641 + if (ep->is_in) {
44642 + /* Program the transfer size and packet count
44643 + * as follows: xfersize = N * maxpacket +
44644 + * short_packet pktcnt = N + (short_packet
44645 + * exist ? 1 : 0)
44646 + */
44647 + deptsiz.b.mc = ep->pkt_per_frm;
44648 + deptsiz.b.xfersize = ep->xfer_len;
44649 + deptsiz.b.pktcnt =
44650 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
44651 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
44652 + dieptsiz, deptsiz.d32);
44653 +
44654 + /* Write the DMA register */
44655 + DWC_WRITE_REG32(&
44656 + (core_if->dev_if->in_ep_regs[ep->num]->
44657 + diepdma), (uint32_t) ep->dma_addr);
44658 +
44659 + } else {
44660 + deptsiz.b.pktcnt =
44661 + (ep->xfer_len + (ep->maxpacket - 1)) /
44662 + ep->maxpacket;
44663 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
44664 +
44665 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->
44666 + doeptsiz, deptsiz.d32);
44667 +
44668 + /* Write the DMA register */
44669 + DWC_WRITE_REG32(&
44670 + (core_if->dev_if->out_ep_regs[ep->num]->
44671 + doepdma), (uint32_t) ep->dma_addr);
44672 +
44673 + }
44674 + /** Enable endpoint, clear nak */
44675 + depctl.d32 = 0;
44676 + depctl.b.epena = 1;
44677 + depctl.b.cnak = 1;
44678 +
44679 + DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
44680 + }
44681 +}
44682 +
44683 +/**
44684 + * This function does the setup for a data transfer for an EP and
44685 + * starts the transfer. For an IN transfer, the packets will be
44686 + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
44687 + * the packets are unloaded from the Rx FIFO in the ISR.
44688 + *
44689 + * @param core_if Programming view of DWC_otg controller.
44690 + * @param ep The EP to start the transfer on.
44691 + */
44692 +
44693 +static void dwc_otg_iso_ep_start_transfer(dwc_otg_core_if_t * core_if,
44694 + dwc_ep_t * ep)
44695 +{
44696 + if (core_if->dma_enable) {
44697 + if (core_if->dma_desc_enable) {
44698 + if (ep->is_in) {
44699 + ep->desc_cnt = ep->pkt_cnt / ep->pkt_per_frm;
44700 + } else {
44701 + ep->desc_cnt = ep->pkt_cnt;
44702 + }
44703 + dwc_otg_iso_ep_start_ddma_transfer(core_if, ep);
44704 + } else {
44705 + if (core_if->pti_enh_enable) {
44706 + dwc_otg_iso_ep_start_buf_transfer(core_if, ep);
44707 + } else {
44708 + ep->cur_pkt_addr =
44709 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->
44710 + xfer_buff0;
44711 + ep->cur_pkt_dma_addr =
44712 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->
44713 + dma_addr0;
44714 + dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
44715 + }
44716 + }
44717 + } else {
44718 + ep->cur_pkt_addr =
44719 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
44720 + ep->cur_pkt_dma_addr =
44721 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
44722 + dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
44723 + }
44724 +}
44725 +
44726 +/**
44727 + * This function stops transfer for an EP and
44728 + * resets the ep's variables.
44729 + *
44730 + * @param core_if Programming view of DWC_otg controller.
44731 + * @param ep The EP to start the transfer on.
44732 + */
44733 +
44734 +void dwc_otg_iso_ep_stop_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
44735 +{
44736 + depctl_data_t depctl = {.d32 = 0 };
44737 + volatile uint32_t *addr;
44738 +
44739 + if (ep->is_in == 1) {
44740 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
44741 + } else {
44742 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
44743 + }
44744 +
44745 + /* disable the ep */
44746 + depctl.d32 = DWC_READ_REG32(addr);
44747 +
44748 + depctl.b.epdis = 1;
44749 + depctl.b.snak = 1;
44750 +
44751 + DWC_WRITE_REG32(addr, depctl.d32);
44752 +
44753 + if (core_if->dma_desc_enable &&
44754 + ep->iso_desc_addr && ep->iso_dma_desc_addr) {
44755 + dwc_otg_ep_free_desc_chain(ep->iso_desc_addr,
44756 + ep->iso_dma_desc_addr,
44757 + ep->desc_cnt * 2);
44758 + }
44759 +
44760 + /* reset varibales */
44761 + ep->dma_addr0 = 0;
44762 + ep->dma_addr1 = 0;
44763 + ep->xfer_buff0 = 0;
44764 + ep->xfer_buff1 = 0;
44765 + ep->data_per_frame = 0;
44766 + ep->data_pattern_frame = 0;
44767 + ep->sync_frame = 0;
44768 + ep->buf_proc_intrvl = 0;
44769 + ep->bInterval = 0;
44770 + ep->proc_buf_num = 0;
44771 + ep->pkt_per_frm = 0;
44772 + ep->pkt_per_frm = 0;
44773 + ep->desc_cnt = 0;
44774 + ep->iso_desc_addr = 0;
44775 + ep->iso_dma_desc_addr = 0;
44776 +}
44777 +
44778 +int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
44779 + uint8_t * buf0, uint8_t * buf1, dwc_dma_t dma0,
44780 + dwc_dma_t dma1, int sync_frame, int dp_frame,
44781 + int data_per_frame, int start_frame,
44782 + int buf_proc_intrvl, void *req_handle,
44783 + int atomic_alloc)
44784 +{
44785 + dwc_otg_pcd_ep_t *ep;
44786 + dwc_irqflags_t flags = 0;
44787 + dwc_ep_t *dwc_ep;
44788 + int32_t frm_data;
44789 + dsts_data_t dsts;
44790 + dwc_otg_core_if_t *core_if;
44791 +
44792 + ep = get_ep_from_handle(pcd, ep_handle);
44793 +
44794 + if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
44795 + DWC_WARN("bad ep\n");
44796 + return -DWC_E_INVALID;
44797 + }
44798 +
44799 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
44800 + core_if = GET_CORE_IF(pcd);
44801 + dwc_ep = &ep->dwc_ep;
44802 +
44803 + if (ep->iso_req_handle) {
44804 + DWC_WARN("ISO request in progress\n");
44805 + }
44806 +
44807 + dwc_ep->dma_addr0 = dma0;
44808 + dwc_ep->dma_addr1 = dma1;
44809 +
44810 + dwc_ep->xfer_buff0 = buf0;
44811 + dwc_ep->xfer_buff1 = buf1;
44812 +
44813 + dwc_ep->data_per_frame = data_per_frame;
44814 +
44815 + /** @todo - pattern data support is to be implemented in the future */
44816 + dwc_ep->data_pattern_frame = dp_frame;
44817 + dwc_ep->sync_frame = sync_frame;
44818 +
44819 + dwc_ep->buf_proc_intrvl = buf_proc_intrvl;
44820 +
44821 + dwc_ep->bInterval = 1 << (ep->desc->bInterval - 1);
44822 +
44823 + dwc_ep->proc_buf_num = 0;
44824 +
44825 + dwc_ep->pkt_per_frm = 0;
44826 + frm_data = ep->dwc_ep.data_per_frame;
44827 + while (frm_data > 0) {
44828 + dwc_ep->pkt_per_frm++;
44829 + frm_data -= ep->dwc_ep.maxpacket;
44830 + }
44831 +
44832 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
44833 +
44834 + if (start_frame == -1) {
44835 + dwc_ep->next_frame = dsts.b.soffn + 1;
44836 + if (dwc_ep->bInterval != 1) {
44837 + dwc_ep->next_frame =
44838 + dwc_ep->next_frame + (dwc_ep->bInterval - 1 -
44839 + dwc_ep->next_frame %
44840 + dwc_ep->bInterval);
44841 + }
44842 + } else {
44843 + dwc_ep->next_frame = start_frame;
44844 + }
44845 +
44846 + if (!core_if->pti_enh_enable) {
44847 + dwc_ep->pkt_cnt =
44848 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
44849 + dwc_ep->bInterval;
44850 + } else {
44851 + dwc_ep->pkt_cnt =
44852 + (dwc_ep->data_per_frame *
44853 + (dwc_ep->buf_proc_intrvl / dwc_ep->bInterval)
44854 + - 1 + dwc_ep->maxpacket) / dwc_ep->maxpacket;
44855 + }
44856 +
44857 + if (core_if->dma_desc_enable) {
44858 + dwc_ep->desc_cnt =
44859 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
44860 + dwc_ep->bInterval;
44861 + }
44862 +
44863 + if (atomic_alloc) {
44864 + dwc_ep->pkt_info =
44865 + DWC_ALLOC_ATOMIC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
44866 + } else {
44867 + dwc_ep->pkt_info =
44868 + DWC_ALLOC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
44869 + }
44870 + if (!dwc_ep->pkt_info) {
44871 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44872 + return -DWC_E_NO_MEMORY;
44873 + }
44874 + if (core_if->pti_enh_enable) {
44875 + dwc_memset(dwc_ep->pkt_info, 0,
44876 + sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
44877 + }
44878 +
44879 + dwc_ep->cur_pkt = 0;
44880 + ep->iso_req_handle = req_handle;
44881 +
44882 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44883 + dwc_otg_iso_ep_start_transfer(core_if, dwc_ep);
44884 + return 0;
44885 +}
44886 +
44887 +int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
44888 + void *req_handle)
44889 +{
44890 + dwc_irqflags_t flags = 0;
44891 + dwc_otg_pcd_ep_t *ep;
44892 + dwc_ep_t *dwc_ep;
44893 +
44894 + ep = get_ep_from_handle(pcd, ep_handle);
44895 + if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
44896 + DWC_WARN("bad ep\n");
44897 + return -DWC_E_INVALID;
44898 + }
44899 + dwc_ep = &ep->dwc_ep;
44900 +
44901 + dwc_otg_iso_ep_stop_transfer(GET_CORE_IF(pcd), dwc_ep);
44902 +
44903 + DWC_FREE(dwc_ep->pkt_info);
44904 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
44905 + if (ep->iso_req_handle != req_handle) {
44906 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44907 + return -DWC_E_INVALID;
44908 + }
44909 +
44910 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44911 +
44912 + ep->iso_req_handle = 0;
44913 + return 0;
44914 +}
44915 +
44916 +/**
44917 + * This function is used for perodical data exchnage between PCD and gadget drivers.
44918 + * for Isochronous EPs
44919 + *
44920 + * - Every time a sync period completes this function is called to
44921 + * perform data exchange between PCD and gadget
44922 + */
44923 +void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
44924 + void *req_handle)
44925 +{
44926 + int i;
44927 + dwc_ep_t *dwc_ep;
44928 +
44929 + dwc_ep = &ep->dwc_ep;
44930 +
44931 + DWC_SPINUNLOCK(ep->pcd->lock);
44932 + pcd->fops->isoc_complete(pcd, ep->priv, ep->iso_req_handle,
44933 + dwc_ep->proc_buf_num ^ 0x1);
44934 + DWC_SPINLOCK(ep->pcd->lock);
44935 +
44936 + for (i = 0; i < dwc_ep->pkt_cnt; ++i) {
44937 + dwc_ep->pkt_info[i].status = 0;
44938 + dwc_ep->pkt_info[i].offset = 0;
44939 + dwc_ep->pkt_info[i].length = 0;
44940 + }
44941 +}
44942 +
44943 +int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd, void *ep_handle,
44944 + void *iso_req_handle)
44945 +{
44946 + dwc_otg_pcd_ep_t *ep;
44947 + dwc_ep_t *dwc_ep;
44948 +
44949 + ep = get_ep_from_handle(pcd, ep_handle);
44950 + if (!ep->desc || ep->dwc_ep.num == 0) {
44951 + DWC_WARN("bad ep\n");
44952 + return -DWC_E_INVALID;
44953 + }
44954 + dwc_ep = &ep->dwc_ep;
44955 +
44956 + return dwc_ep->pkt_cnt;
44957 +}
44958 +
44959 +void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd, void *ep_handle,
44960 + void *iso_req_handle, int packet,
44961 + int *status, int *actual, int *offset)
44962 +{
44963 + dwc_otg_pcd_ep_t *ep;
44964 + dwc_ep_t *dwc_ep;
44965 +
44966 + ep = get_ep_from_handle(pcd, ep_handle);
44967 + if (!ep)
44968 + DWC_WARN("bad ep\n");
44969 +
44970 + dwc_ep = &ep->dwc_ep;
44971 +
44972 + *status = dwc_ep->pkt_info[packet].status;
44973 + *actual = dwc_ep->pkt_info[packet].length;
44974 + *offset = dwc_ep->pkt_info[packet].offset;
44975 +}
44976 +
44977 +#endif /* DWC_EN_ISOC */
44978 +
44979 +static void dwc_otg_pcd_init_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * pcd_ep,
44980 + uint32_t is_in, uint32_t ep_num)
44981 +{
44982 + /* Init EP structure */
44983 + pcd_ep->desc = 0;
44984 + pcd_ep->pcd = pcd;
44985 + pcd_ep->stopped = 1;
44986 + pcd_ep->queue_sof = 0;
44987 +
44988 + /* Init DWC ep structure */
44989 + pcd_ep->dwc_ep.is_in = is_in;
44990 + pcd_ep->dwc_ep.num = ep_num;
44991 + pcd_ep->dwc_ep.active = 0;
44992 + pcd_ep->dwc_ep.tx_fifo_num = 0;
44993 + /* Control until ep is actvated */
44994 + pcd_ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
44995 + pcd_ep->dwc_ep.maxpacket = MAX_PACKET_SIZE;
44996 + pcd_ep->dwc_ep.dma_addr = 0;
44997 + pcd_ep->dwc_ep.start_xfer_buff = 0;
44998 + pcd_ep->dwc_ep.xfer_buff = 0;
44999 + pcd_ep->dwc_ep.xfer_len = 0;
45000 + pcd_ep->dwc_ep.xfer_count = 0;
45001 + pcd_ep->dwc_ep.sent_zlp = 0;
45002 + pcd_ep->dwc_ep.total_len = 0;
45003 + pcd_ep->dwc_ep.desc_addr = 0;
45004 + pcd_ep->dwc_ep.dma_desc_addr = 0;
45005 + DWC_CIRCLEQ_INIT(&pcd_ep->queue);
45006 +}
45007 +
45008 +/**
45009 + * Initialize ep's
45010 + */
45011 +static void dwc_otg_pcd_reinit(dwc_otg_pcd_t * pcd)
45012 +{
45013 + int i;
45014 + uint32_t hwcfg1;
45015 + dwc_otg_pcd_ep_t *ep;
45016 + int in_ep_cntr, out_ep_cntr;
45017 + uint32_t num_in_eps = (GET_CORE_IF(pcd))->dev_if->num_in_eps;
45018 + uint32_t num_out_eps = (GET_CORE_IF(pcd))->dev_if->num_out_eps;
45019 +
45020 + /**
45021 + * Initialize the EP0 structure.
45022 + */
45023 + ep = &pcd->ep0;
45024 + dwc_otg_pcd_init_ep(pcd, ep, 0, 0);
45025 +
45026 + in_ep_cntr = 0;
45027 + hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 3;
45028 + for (i = 1; in_ep_cntr < num_in_eps; i++) {
45029 + if ((hwcfg1 & 0x1) == 0) {
45030 + dwc_otg_pcd_ep_t *ep = &pcd->in_ep[in_ep_cntr];
45031 + in_ep_cntr++;
45032 + /**
45033 + * @todo NGS: Add direction to EP, based on contents
45034 + * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
45035 + * sprintf(";r
45036 + */
45037 + dwc_otg_pcd_init_ep(pcd, ep, 1 /* IN */ , i);
45038 +
45039 + DWC_CIRCLEQ_INIT(&ep->queue);
45040 + }
45041 + hwcfg1 >>= 2;
45042 + }
45043 +
45044 + out_ep_cntr = 0;
45045 + hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 2;
45046 + for (i = 1; out_ep_cntr < num_out_eps; i++) {
45047 + if ((hwcfg1 & 0x1) == 0) {
45048 + dwc_otg_pcd_ep_t *ep = &pcd->out_ep[out_ep_cntr];
45049 + out_ep_cntr++;
45050 + /**
45051 + * @todo NGS: Add direction to EP, based on contents
45052 + * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
45053 + * sprintf(";r
45054 + */
45055 + dwc_otg_pcd_init_ep(pcd, ep, 0 /* OUT */ , i);
45056 + DWC_CIRCLEQ_INIT(&ep->queue);
45057 + }
45058 + hwcfg1 >>= 2;
45059 + }
45060 +
45061 + pcd->ep0state = EP0_DISCONNECT;
45062 + pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE;
45063 + pcd->ep0.dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
45064 +}
45065 +
45066 +/**
45067 + * This function is called when the SRP timer expires. The SRP should
45068 + * complete within 6 seconds.
45069 + */
45070 +static void srp_timeout(void *ptr)
45071 +{
45072 + gotgctl_data_t gotgctl;
45073 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
45074 + volatile uint32_t *addr = &core_if->core_global_regs->gotgctl;
45075 +
45076 + gotgctl.d32 = DWC_READ_REG32(addr);
45077 +
45078 + core_if->srp_timer_started = 0;
45079 +
45080 + if (core_if->adp_enable) {
45081 + if (gotgctl.b.bsesvld == 0) {
45082 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
45083 + DWC_PRINTF("SRP Timeout BSESSVLD = 0\n");
45084 + /* Power off the core */
45085 + if (core_if->power_down == 2) {
45086 + gpwrdn.b.pwrdnswtch = 1;
45087 + DWC_MODIFY_REG32(&core_if->
45088 + core_global_regs->gpwrdn,
45089 + gpwrdn.d32, 0);
45090 + }
45091 +
45092 + gpwrdn.d32 = 0;
45093 + gpwrdn.b.pmuintsel = 1;
45094 + gpwrdn.b.pmuactv = 1;
45095 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
45096 + gpwrdn.d32);
45097 + dwc_otg_adp_probe_start(core_if);
45098 + } else {
45099 + DWC_PRINTF("SRP Timeout BSESSVLD = 1\n");
45100 + core_if->op_state = B_PERIPHERAL;
45101 + dwc_otg_core_init(core_if);
45102 + dwc_otg_enable_global_interrupts(core_if);
45103 + cil_pcd_start(core_if);
45104 + }
45105 + }
45106 +
45107 + if ((core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) &&
45108 + (core_if->core_params->i2c_enable)) {
45109 + DWC_PRINTF("SRP Timeout\n");
45110 +
45111 + if ((core_if->srp_success) && (gotgctl.b.bsesvld)) {
45112 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
45113 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
45114 + }
45115 +
45116 + /* Clear Session Request */
45117 + gotgctl.d32 = 0;
45118 + gotgctl.b.sesreq = 1;
45119 + DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl,
45120 + gotgctl.d32, 0);
45121 +
45122 + core_if->srp_success = 0;
45123 + } else {
45124 + __DWC_ERROR("Device not connected/responding\n");
45125 + gotgctl.b.sesreq = 0;
45126 + DWC_WRITE_REG32(addr, gotgctl.d32);
45127 + }
45128 + } else if (gotgctl.b.sesreq) {
45129 + DWC_PRINTF("SRP Timeout\n");
45130 +
45131 + __DWC_ERROR("Device not connected/responding\n");
45132 + gotgctl.b.sesreq = 0;
45133 + DWC_WRITE_REG32(addr, gotgctl.d32);
45134 + } else {
45135 + DWC_PRINTF(" SRP GOTGCTL=%0x\n", gotgctl.d32);
45136 + }
45137 +}
45138 +
45139 +/**
45140 + * Tasklet
45141 + *
45142 + */
45143 +extern void start_next_request(dwc_otg_pcd_ep_t * ep);
45144 +
45145 +static void start_xfer_tasklet_func(void *data)
45146 +{
45147 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
45148 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
45149 +
45150 + int i;
45151 + depctl_data_t diepctl;
45152 +
45153 + DWC_DEBUGPL(DBG_PCDV, "Start xfer tasklet\n");
45154 +
45155 + diepctl.d32 = DWC_READ_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl);
45156 +
45157 + if (pcd->ep0.queue_sof) {
45158 + pcd->ep0.queue_sof = 0;
45159 + start_next_request(&pcd->ep0);
45160 + // break;
45161 + }
45162 +
45163 + for (i = 0; i < core_if->dev_if->num_in_eps; i++) {
45164 + depctl_data_t diepctl;
45165 + diepctl.d32 =
45166 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
45167 +
45168 + if (pcd->in_ep[i].queue_sof) {
45169 + pcd->in_ep[i].queue_sof = 0;
45170 + start_next_request(&pcd->in_ep[i]);
45171 + // break;
45172 + }
45173 + }
45174 +
45175 + return;
45176 +}
45177 +
45178 +/**
45179 + * This function initialized the PCD portion of the driver.
45180 + *
45181 + */
45182 +dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if)
45183 +{
45184 + dwc_otg_pcd_t *pcd = NULL;
45185 + dwc_otg_dev_if_t *dev_if;
45186 + int i;
45187 +
45188 + /*
45189 + * Allocate PCD structure
45190 + */
45191 + pcd = DWC_ALLOC(sizeof(dwc_otg_pcd_t));
45192 +
45193 + if (pcd == NULL) {
45194 + return NULL;
45195 + }
45196 +
45197 + pcd->lock = DWC_SPINLOCK_ALLOC();
45198 + DWC_DEBUGPL(DBG_HCDV, "Init of PCD %p given core_if %p\n",
45199 + pcd, core_if);//GRAYG
45200 + if (!pcd->lock) {
45201 + DWC_ERROR("Could not allocate lock for pcd");
45202 + DWC_FREE(pcd);
45203 + return NULL;
45204 + }
45205 + /* Set core_if's lock pointer to hcd->lock */
45206 + core_if->lock = pcd->lock;
45207 + pcd->core_if = core_if;
45208 +
45209 + dev_if = core_if->dev_if;
45210 + dev_if->isoc_ep = NULL;
45211 +
45212 + if (core_if->hwcfg4.b.ded_fifo_en) {
45213 + DWC_PRINTF("Dedicated Tx FIFOs mode\n");
45214 + } else {
45215 + DWC_PRINTF("Shared Tx FIFO mode\n");
45216 + }
45217 +
45218 + /*
45219 + * Initialized the Core for Device mode here if there is nod ADP support.
45220 + * Otherwise it will be done later in dwc_otg_adp_start routine.
45221 + */
45222 + if (dwc_otg_is_device_mode(core_if) /*&& !core_if->adp_enable*/) {
45223 + dwc_otg_core_dev_init(core_if);
45224 + }
45225 +
45226 + /*
45227 + * Register the PCD Callbacks.
45228 + */
45229 + dwc_otg_cil_register_pcd_callbacks(core_if, &pcd_callbacks, pcd);
45230 +
45231 + /*
45232 + * Initialize the DMA buffer for SETUP packets
45233 + */
45234 + if (GET_CORE_IF(pcd)->dma_enable) {
45235 + pcd->setup_pkt =
45236 + DWC_DMA_ALLOC(sizeof(*pcd->setup_pkt) * 5,
45237 + &pcd->setup_pkt_dma_handle);
45238 + if (pcd->setup_pkt == NULL) {
45239 + DWC_FREE(pcd);
45240 + return NULL;
45241 + }
45242 +
45243 + pcd->status_buf =
45244 + DWC_DMA_ALLOC(sizeof(uint16_t),
45245 + &pcd->status_buf_dma_handle);
45246 + if (pcd->status_buf == NULL) {
45247 + DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
45248 + pcd->setup_pkt, pcd->setup_pkt_dma_handle);
45249 + DWC_FREE(pcd);
45250 + return NULL;
45251 + }
45252 +
45253 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45254 + dev_if->setup_desc_addr[0] =
45255 + dwc_otg_ep_alloc_desc_chain
45256 + (&dev_if->dma_setup_desc_addr[0], 1);
45257 + dev_if->setup_desc_addr[1] =
45258 + dwc_otg_ep_alloc_desc_chain
45259 + (&dev_if->dma_setup_desc_addr[1], 1);
45260 + dev_if->in_desc_addr =
45261 + dwc_otg_ep_alloc_desc_chain
45262 + (&dev_if->dma_in_desc_addr, 1);
45263 + dev_if->out_desc_addr =
45264 + dwc_otg_ep_alloc_desc_chain
45265 + (&dev_if->dma_out_desc_addr, 1);
45266 + pcd->data_terminated = 0;
45267 +
45268 + if (dev_if->setup_desc_addr[0] == 0
45269 + || dev_if->setup_desc_addr[1] == 0
45270 + || dev_if->in_desc_addr == 0
45271 + || dev_if->out_desc_addr == 0) {
45272 +
45273 + if (dev_if->out_desc_addr)
45274 + dwc_otg_ep_free_desc_chain
45275 + (dev_if->out_desc_addr,
45276 + dev_if->dma_out_desc_addr, 1);
45277 + if (dev_if->in_desc_addr)
45278 + dwc_otg_ep_free_desc_chain
45279 + (dev_if->in_desc_addr,
45280 + dev_if->dma_in_desc_addr, 1);
45281 + if (dev_if->setup_desc_addr[1])
45282 + dwc_otg_ep_free_desc_chain
45283 + (dev_if->setup_desc_addr[1],
45284 + dev_if->dma_setup_desc_addr[1], 1);
45285 + if (dev_if->setup_desc_addr[0])
45286 + dwc_otg_ep_free_desc_chain
45287 + (dev_if->setup_desc_addr[0],
45288 + dev_if->dma_setup_desc_addr[0], 1);
45289 +
45290 + DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
45291 + pcd->setup_pkt,
45292 + pcd->setup_pkt_dma_handle);
45293 + DWC_DMA_FREE(sizeof(*pcd->status_buf),
45294 + pcd->status_buf,
45295 + pcd->status_buf_dma_handle);
45296 +
45297 + DWC_FREE(pcd);
45298 +
45299 + return NULL;
45300 + }
45301 + }
45302 + } else {
45303 + pcd->setup_pkt = DWC_ALLOC(sizeof(*pcd->setup_pkt) * 5);
45304 + if (pcd->setup_pkt == NULL) {
45305 + DWC_FREE(pcd);
45306 + return NULL;
45307 + }
45308 +
45309 + pcd->status_buf = DWC_ALLOC(sizeof(uint16_t));
45310 + if (pcd->status_buf == NULL) {
45311 + DWC_FREE(pcd->setup_pkt);
45312 + DWC_FREE(pcd);
45313 + return NULL;
45314 + }
45315 + }
45316 +
45317 + dwc_otg_pcd_reinit(pcd);
45318 +
45319 + /* Allocate the cfi object for the PCD */
45320 +#ifdef DWC_UTE_CFI
45321 + pcd->cfi = DWC_ALLOC(sizeof(cfiobject_t));
45322 + if (NULL == pcd->cfi)
45323 + goto fail;
45324 + if (init_cfi(pcd->cfi)) {
45325 + CFI_INFO("%s: Failed to init the CFI object\n", __func__);
45326 + goto fail;
45327 + }
45328 +#endif
45329 +
45330 + /* Initialize tasklets */
45331 + pcd->start_xfer_tasklet = DWC_TASK_ALLOC("xfer_tasklet",
45332 + start_xfer_tasklet_func, pcd);
45333 + pcd->test_mode_tasklet = DWC_TASK_ALLOC("test_mode_tasklet",
45334 + do_test_mode, pcd);
45335 +
45336 + /* Initialize SRP timer */
45337 + core_if->srp_timer = DWC_TIMER_ALLOC("SRP TIMER", srp_timeout, core_if);
45338 +
45339 + if (core_if->core_params->dev_out_nak) {
45340 + /**
45341 + * Initialize xfer timeout timer. Implemented for
45342 + * 2.93a feature "Device DDMA OUT NAK Enhancement"
45343 + */
45344 + for(i = 0; i < MAX_EPS_CHANNELS; i++) {
45345 + pcd->core_if->ep_xfer_timer[i] =
45346 + DWC_TIMER_ALLOC("ep timer", ep_xfer_timeout,
45347 + &pcd->core_if->ep_xfer_info[i]);
45348 + }
45349 + }
45350 +
45351 + return pcd;
45352 +#ifdef DWC_UTE_CFI
45353 +fail:
45354 +#endif
45355 + if (pcd->setup_pkt)
45356 + DWC_FREE(pcd->setup_pkt);
45357 + if (pcd->status_buf)
45358 + DWC_FREE(pcd->status_buf);
45359 +#ifdef DWC_UTE_CFI
45360 + if (pcd->cfi)
45361 + DWC_FREE(pcd->cfi);
45362 +#endif
45363 + if (pcd)
45364 + DWC_FREE(pcd);
45365 + return NULL;
45366 +
45367 +}
45368 +
45369 +/**
45370 + * Remove PCD specific data
45371 + */
45372 +void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd)
45373 +{
45374 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
45375 + int i;
45376 + if (pcd->core_if->core_params->dev_out_nak) {
45377 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
45378 + DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[i]);
45379 + pcd->core_if->ep_xfer_info[i].state = 0;
45380 + }
45381 + }
45382 +
45383 + if (GET_CORE_IF(pcd)->dma_enable) {
45384 + DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5, pcd->setup_pkt,
45385 + pcd->setup_pkt_dma_handle);
45386 + DWC_DMA_FREE(sizeof(uint16_t), pcd->status_buf,
45387 + pcd->status_buf_dma_handle);
45388 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45389 + dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[0],
45390 + dev_if->dma_setup_desc_addr
45391 + [0], 1);
45392 + dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[1],
45393 + dev_if->dma_setup_desc_addr
45394 + [1], 1);
45395 + dwc_otg_ep_free_desc_chain(dev_if->in_desc_addr,
45396 + dev_if->dma_in_desc_addr, 1);
45397 + dwc_otg_ep_free_desc_chain(dev_if->out_desc_addr,
45398 + dev_if->dma_out_desc_addr,
45399 + 1);
45400 + }
45401 + } else {
45402 + DWC_FREE(pcd->setup_pkt);
45403 + DWC_FREE(pcd->status_buf);
45404 + }
45405 + DWC_SPINLOCK_FREE(pcd->lock);
45406 + /* Set core_if's lock pointer to NULL */
45407 + pcd->core_if->lock = NULL;
45408 +
45409 + DWC_TASK_FREE(pcd->start_xfer_tasklet);
45410 + DWC_TASK_FREE(pcd->test_mode_tasklet);
45411 + if (pcd->core_if->core_params->dev_out_nak) {
45412 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
45413 + if (pcd->core_if->ep_xfer_timer[i]) {
45414 + DWC_TIMER_FREE(pcd->core_if->ep_xfer_timer[i]);
45415 + }
45416 + }
45417 + }
45418 +
45419 +/* Release the CFI object's dynamic memory */
45420 +#ifdef DWC_UTE_CFI
45421 + if (pcd->cfi->ops.release) {
45422 + pcd->cfi->ops.release(pcd->cfi);
45423 + }
45424 +#endif
45425 +
45426 + DWC_FREE(pcd);
45427 +}
45428 +
45429 +/**
45430 + * Returns whether registered pcd is dual speed or not
45431 + */
45432 +uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd)
45433 +{
45434 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
45435 +
45436 + if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) ||
45437 + ((core_if->hwcfg2.b.hs_phy_type == 2) &&
45438 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
45439 + (core_if->core_params->ulpi_fs_ls))) {
45440 + return 0;
45441 + }
45442 +
45443 + return 1;
45444 +}
45445 +
45446 +/**
45447 + * Returns whether registered pcd is OTG capable or not
45448 + */
45449 +uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd)
45450 +{
45451 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
45452 + gusbcfg_data_t usbcfg = {.d32 = 0 };
45453 +
45454 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
45455 + if (!usbcfg.b.srpcap || !usbcfg.b.hnpcap) {
45456 + return 0;
45457 + }
45458 +
45459 + return 1;
45460 +}
45461 +
45462 +/**
45463 + * This function assigns periodic Tx FIFO to an periodic EP
45464 + * in shared Tx FIFO mode
45465 + */
45466 +static uint32_t assign_tx_fifo(dwc_otg_core_if_t * core_if)
45467 +{
45468 + uint32_t TxMsk = 1;
45469 + int i;
45470 +
45471 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; ++i) {
45472 + if ((TxMsk & core_if->tx_msk) == 0) {
45473 + core_if->tx_msk |= TxMsk;
45474 + return i + 1;
45475 + }
45476 + TxMsk <<= 1;
45477 + }
45478 + return 0;
45479 +}
45480 +
45481 +/**
45482 + * This function assigns periodic Tx FIFO to an periodic EP
45483 + * in shared Tx FIFO mode
45484 + */
45485 +static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t * core_if)
45486 +{
45487 + uint32_t PerTxMsk = 1;
45488 + int i;
45489 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; ++i) {
45490 + if ((PerTxMsk & core_if->p_tx_msk) == 0) {
45491 + core_if->p_tx_msk |= PerTxMsk;
45492 + return i + 1;
45493 + }
45494 + PerTxMsk <<= 1;
45495 + }
45496 + return 0;
45497 +}
45498 +
45499 +/**
45500 + * This function releases periodic Tx FIFO
45501 + * in shared Tx FIFO mode
45502 + */
45503 +static void release_perio_tx_fifo(dwc_otg_core_if_t * core_if,
45504 + uint32_t fifo_num)
45505 +{
45506 + core_if->p_tx_msk =
45507 + (core_if->p_tx_msk & (1 << (fifo_num - 1))) ^ core_if->p_tx_msk;
45508 +}
45509 +
45510 +/**
45511 + * This function releases periodic Tx FIFO
45512 + * in shared Tx FIFO mode
45513 + */
45514 +static void release_tx_fifo(dwc_otg_core_if_t * core_if, uint32_t fifo_num)
45515 +{
45516 + core_if->tx_msk =
45517 + (core_if->tx_msk & (1 << (fifo_num - 1))) ^ core_if->tx_msk;
45518 +}
45519 +
45520 +/**
45521 + * This function is being called from gadget
45522 + * to enable PCD endpoint.
45523 + */
45524 +int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
45525 + const uint8_t * ep_desc, void *usb_ep)
45526 +{
45527 + int num, dir;
45528 + dwc_otg_pcd_ep_t *ep = NULL;
45529 + const usb_endpoint_descriptor_t *desc;
45530 + dwc_irqflags_t flags;
45531 + fifosize_data_t dptxfsiz = {.d32 = 0 };
45532 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
45533 + gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
45534 + int retval = 0;
45535 + int i, epcount;
45536 +
45537 + desc = (const usb_endpoint_descriptor_t *)ep_desc;
45538 +
45539 + if (!desc) {
45540 + pcd->ep0.priv = usb_ep;
45541 + ep = &pcd->ep0;
45542 + retval = -DWC_E_INVALID;
45543 + goto out;
45544 + }
45545 +
45546 + num = UE_GET_ADDR(desc->bEndpointAddress);
45547 + dir = UE_GET_DIR(desc->bEndpointAddress);
45548 +
45549 + if (!desc->wMaxPacketSize) {
45550 + DWC_WARN("bad maxpacketsize\n");
45551 + retval = -DWC_E_INVALID;
45552 + goto out;
45553 + }
45554 +
45555 + if (dir == UE_DIR_IN) {
45556 + epcount = pcd->core_if->dev_if->num_in_eps;
45557 + for (i = 0; i < epcount; i++) {
45558 + if (num == pcd->in_ep[i].dwc_ep.num) {
45559 + ep = &pcd->in_ep[i];
45560 + break;
45561 + }
45562 + }
45563 + } else {
45564 + epcount = pcd->core_if->dev_if->num_out_eps;
45565 + for (i = 0; i < epcount; i++) {
45566 + if (num == pcd->out_ep[i].dwc_ep.num) {
45567 + ep = &pcd->out_ep[i];
45568 + break;
45569 + }
45570 + }
45571 + }
45572 +
45573 + if (!ep) {
45574 + DWC_WARN("bad address\n");
45575 + retval = -DWC_E_INVALID;
45576 + goto out;
45577 + }
45578 +
45579 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45580 +
45581 + ep->desc = desc;
45582 + ep->priv = usb_ep;
45583 +
45584 + /*
45585 + * Activate the EP
45586 + */
45587 + ep->stopped = 0;
45588 +
45589 + ep->dwc_ep.is_in = (dir == UE_DIR_IN);
45590 + ep->dwc_ep.maxpacket = UGETW(desc->wMaxPacketSize);
45591 +
45592 + ep->dwc_ep.type = desc->bmAttributes & UE_XFERTYPE;
45593 +
45594 + if (ep->dwc_ep.is_in) {
45595 + if (!GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45596 + ep->dwc_ep.tx_fifo_num = 0;
45597 +
45598 + if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
45599 + /*
45600 + * if ISOC EP then assign a Periodic Tx FIFO.
45601 + */
45602 + ep->dwc_ep.tx_fifo_num =
45603 + assign_perio_tx_fifo(GET_CORE_IF(pcd));
45604 + }
45605 + } else {
45606 + /*
45607 + * if Dedicated FIFOs mode is on then assign a Tx FIFO.
45608 + */
45609 + ep->dwc_ep.tx_fifo_num =
45610 + assign_tx_fifo(GET_CORE_IF(pcd));
45611 + }
45612 +
45613 + /* Calculating EP info controller base address */
45614 + if (ep->dwc_ep.tx_fifo_num
45615 + && GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45616 + gdfifocfg.d32 =
45617 + DWC_READ_REG32(&GET_CORE_IF(pcd)->
45618 + core_global_regs->gdfifocfg);
45619 + gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
45620 + dptxfsiz.d32 =
45621 + (DWC_READ_REG32
45622 + (&GET_CORE_IF(pcd)->core_global_regs->
45623 + dtxfsiz[ep->dwc_ep.tx_fifo_num - 1]) >> 16);
45624 + gdfifocfg.b.epinfobase =
45625 + gdfifocfgbase.d32 + dptxfsiz.d32;
45626 + if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) {
45627 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
45628 + core_global_regs->gdfifocfg,
45629 + gdfifocfg.d32);
45630 + }
45631 + }
45632 + }
45633 + /* Set initial data PID. */
45634 + if (ep->dwc_ep.type == UE_BULK) {
45635 + ep->dwc_ep.data_pid_start = 0;
45636 + }
45637 +
45638 + /* Alloc DMA Descriptors */
45639 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45640 +#ifndef DWC_UTE_PER_IO
45641 + if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
45642 +#endif
45643 + ep->dwc_ep.desc_addr =
45644 + dwc_otg_ep_alloc_desc_chain(&ep->
45645 + dwc_ep.dma_desc_addr,
45646 + MAX_DMA_DESC_CNT);
45647 + if (!ep->dwc_ep.desc_addr) {
45648 + DWC_WARN("%s, can't allocate DMA descriptor\n",
45649 + __func__);
45650 + retval = -DWC_E_SHUTDOWN;
45651 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45652 + goto out;
45653 + }
45654 +#ifndef DWC_UTE_PER_IO
45655 + }
45656 +#endif
45657 + }
45658 +
45659 + DWC_DEBUGPL(DBG_PCD, "Activate %s: type=%d, mps=%d desc=%p\n",
45660 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
45661 + ep->dwc_ep.type, ep->dwc_ep.maxpacket, ep->desc);
45662 +#ifdef DWC_UTE_PER_IO
45663 + ep->dwc_ep.xiso_bInterval = 1 << (ep->desc->bInterval - 1);
45664 +#endif
45665 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
45666 + ep->dwc_ep.bInterval = 1 << (ep->desc->bInterval - 1);
45667 + ep->dwc_ep.frame_num = 0xFFFFFFFF;
45668 + }
45669 +
45670 + dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
45671 +
45672 +#ifdef DWC_UTE_CFI
45673 + if (pcd->cfi->ops.ep_enable) {
45674 + pcd->cfi->ops.ep_enable(pcd->cfi, pcd, ep);
45675 + }
45676 +#endif
45677 +
45678 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45679 +
45680 +out:
45681 + return retval;
45682 +}
45683 +
45684 +/**
45685 + * This function is being called from gadget
45686 + * to disable PCD endpoint.
45687 + */
45688 +int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle)
45689 +{
45690 + dwc_otg_pcd_ep_t *ep;
45691 + dwc_irqflags_t flags;
45692 + dwc_otg_dev_dma_desc_t *desc_addr;
45693 + dwc_dma_t dma_desc_addr;
45694 + gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
45695 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
45696 + fifosize_data_t dptxfsiz = {.d32 = 0 };
45697 +
45698 + ep = get_ep_from_handle(pcd, ep_handle);
45699 +
45700 + if (!ep || !ep->desc) {
45701 + DWC_DEBUGPL(DBG_PCD, "bad ep address\n");
45702 + return -DWC_E_INVALID;
45703 + }
45704 +
45705 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45706 +
45707 + dwc_otg_request_nuke(ep);
45708 +
45709 + dwc_otg_ep_deactivate(GET_CORE_IF(pcd), &ep->dwc_ep);
45710 + if (pcd->core_if->core_params->dev_out_nak) {
45711 + DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[ep->dwc_ep.num]);
45712 + pcd->core_if->ep_xfer_info[ep->dwc_ep.num].state = 0;
45713 + }
45714 + ep->desc = NULL;
45715 + ep->stopped = 1;
45716 +
45717 + gdfifocfg.d32 =
45718 + DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg);
45719 + gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
45720 +
45721 + if (ep->dwc_ep.is_in) {
45722 + if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45723 + /* Flush the Tx FIFO */
45724 + dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd),
45725 + ep->dwc_ep.tx_fifo_num);
45726 + }
45727 + release_perio_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
45728 + release_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
45729 + if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45730 + /* Decreasing EPinfo Base Addr */
45731 + dptxfsiz.d32 =
45732 + (DWC_READ_REG32
45733 + (&GET_CORE_IF(pcd)->
45734 + core_global_regs->dtxfsiz[ep->dwc_ep.tx_fifo_num-1]) >> 16);
45735 + gdfifocfg.b.epinfobase = gdfifocfgbase.d32 - dptxfsiz.d32;
45736 + if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) {
45737 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg,
45738 + gdfifocfg.d32);
45739 + }
45740 + }
45741 + }
45742 +
45743 + /* Free DMA Descriptors */
45744 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45745 + if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
45746 + desc_addr = ep->dwc_ep.desc_addr;
45747 + dma_desc_addr = ep->dwc_ep.dma_desc_addr;
45748 +
45749 + /* Cannot call dma_free_coherent() with IRQs disabled */
45750 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45751 + dwc_otg_ep_free_desc_chain(desc_addr, dma_desc_addr,
45752 + MAX_DMA_DESC_CNT);
45753 +
45754 + goto out_unlocked;
45755 + }
45756 + }
45757 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45758 +
45759 +out_unlocked:
45760 + DWC_DEBUGPL(DBG_PCD, "%d %s disabled\n", ep->dwc_ep.num,
45761 + ep->dwc_ep.is_in ? "IN" : "OUT");
45762 + return 0;
45763 +
45764 +}
45765 +
45766 +/******************************************************************************/
45767 +#ifdef DWC_UTE_PER_IO
45768 +
45769 +/**
45770 + * Free the request and its extended parts
45771 + *
45772 + */
45773 +void dwc_pcd_xiso_ereq_free(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req)
45774 +{
45775 + DWC_FREE(req->ext_req.per_io_frame_descs);
45776 + DWC_FREE(req);
45777 +}
45778 +
45779 +/**
45780 + * Start the next request in the endpoint's queue.
45781 + *
45782 + */
45783 +int dwc_otg_pcd_xiso_start_next_request(dwc_otg_pcd_t * pcd,
45784 + dwc_otg_pcd_ep_t * ep)
45785 +{
45786 + int i;
45787 + dwc_otg_pcd_request_t *req = NULL;
45788 + dwc_ep_t *dwcep = NULL;
45789 + struct dwc_iso_xreq_port *ereq = NULL;
45790 + struct dwc_iso_pkt_desc_port *ddesc_iso;
45791 + uint16_t nat;
45792 + depctl_data_t diepctl;
45793 +
45794 + dwcep = &ep->dwc_ep;
45795 +
45796 + if (dwcep->xiso_active_xfers > 0) {
45797 +#if 0 //Disable this to decrease s/w overhead that is crucial for Isoc transfers
45798 + DWC_WARN("There are currently active transfers for EP%d \
45799 + (active=%d; queued=%d)", dwcep->num, dwcep->xiso_active_xfers,
45800 + dwcep->xiso_queued_xfers);
45801 +#endif
45802 + return 0;
45803 + }
45804 +
45805 + nat = UGETW(ep->desc->wMaxPacketSize);
45806 + nat = (nat >> 11) & 0x03;
45807 +
45808 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
45809 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
45810 + ereq = &req->ext_req;
45811 + ep->stopped = 0;
45812 +
45813 + /* Get the frame number */
45814 + dwcep->xiso_frame_num =
45815 + dwc_otg_get_frame_number(GET_CORE_IF(pcd));
45816 + DWC_DEBUG("FRM_NUM=%d", dwcep->xiso_frame_num);
45817 +
45818 + ddesc_iso = ereq->per_io_frame_descs;
45819 +
45820 + if (dwcep->is_in) {
45821 + /* Setup DMA Descriptor chain for IN Isoc request */
45822 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45823 + //if ((i % (nat + 1)) == 0)
45824 + if ( i > 0 )
45825 + dwcep->xiso_frame_num =
45826 + (dwcep->xiso_bInterval +
45827 + dwcep->xiso_frame_num) & 0x3FFF;
45828 + dwcep->desc_addr[i].buf =
45829 + req->dma + ddesc_iso[i].offset;
45830 + dwcep->desc_addr[i].status.b_iso_in.txbytes =
45831 + ddesc_iso[i].length;
45832 + dwcep->desc_addr[i].status.b_iso_in.framenum =
45833 + dwcep->xiso_frame_num;
45834 + dwcep->desc_addr[i].status.b_iso_in.bs =
45835 + BS_HOST_READY;
45836 + dwcep->desc_addr[i].status.b_iso_in.txsts = 0;
45837 + dwcep->desc_addr[i].status.b_iso_in.sp =
45838 + (ddesc_iso[i].length %
45839 + dwcep->maxpacket) ? 1 : 0;
45840 + dwcep->desc_addr[i].status.b_iso_in.ioc = 0;
45841 + dwcep->desc_addr[i].status.b_iso_in.pid = nat + 1;
45842 + dwcep->desc_addr[i].status.b_iso_in.l = 0;
45843 +
45844 + /* Process the last descriptor */
45845 + if (i == ereq->pio_pkt_count - 1) {
45846 + dwcep->desc_addr[i].status.b_iso_in.ioc = 1;
45847 + dwcep->desc_addr[i].status.b_iso_in.l = 1;
45848 + }
45849 + }
45850 +
45851 + /* Setup and start the transfer for this endpoint */
45852 + dwcep->xiso_active_xfers++;
45853 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->dev_if->
45854 + in_ep_regs[dwcep->num]->diepdma,
45855 + dwcep->dma_desc_addr);
45856 + diepctl.d32 = 0;
45857 + diepctl.b.epena = 1;
45858 + diepctl.b.cnak = 1;
45859 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if->
45860 + in_ep_regs[dwcep->num]->diepctl, 0,
45861 + diepctl.d32);
45862 + } else {
45863 + /* Setup DMA Descriptor chain for OUT Isoc request */
45864 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45865 + //if ((i % (nat + 1)) == 0)
45866 + dwcep->xiso_frame_num = (dwcep->xiso_bInterval +
45867 + dwcep->xiso_frame_num) & 0x3FFF;
45868 + dwcep->desc_addr[i].buf =
45869 + req->dma + ddesc_iso[i].offset;
45870 + dwcep->desc_addr[i].status.b_iso_out.rxbytes =
45871 + ddesc_iso[i].length;
45872 + dwcep->desc_addr[i].status.b_iso_out.framenum =
45873 + dwcep->xiso_frame_num;
45874 + dwcep->desc_addr[i].status.b_iso_out.bs =
45875 + BS_HOST_READY;
45876 + dwcep->desc_addr[i].status.b_iso_out.rxsts = 0;
45877 + dwcep->desc_addr[i].status.b_iso_out.sp =
45878 + (ddesc_iso[i].length %
45879 + dwcep->maxpacket) ? 1 : 0;
45880 + dwcep->desc_addr[i].status.b_iso_out.ioc = 0;
45881 + dwcep->desc_addr[i].status.b_iso_out.pid = nat + 1;
45882 + dwcep->desc_addr[i].status.b_iso_out.l = 0;
45883 +
45884 + /* Process the last descriptor */
45885 + if (i == ereq->pio_pkt_count - 1) {
45886 + dwcep->desc_addr[i].status.b_iso_out.ioc = 1;
45887 + dwcep->desc_addr[i].status.b_iso_out.l = 1;
45888 + }
45889 + }
45890 +
45891 + /* Setup and start the transfer for this endpoint */
45892 + dwcep->xiso_active_xfers++;
45893 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
45894 + dev_if->out_ep_regs[dwcep->num]->
45895 + doepdma, dwcep->dma_desc_addr);
45896 + diepctl.d32 = 0;
45897 + diepctl.b.epena = 1;
45898 + diepctl.b.cnak = 1;
45899 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
45900 + dev_if->out_ep_regs[dwcep->num]->
45901 + doepctl, 0, diepctl.d32);
45902 + }
45903 +
45904 + } else {
45905 + ep->stopped = 1;
45906 + }
45907 +
45908 + return 0;
45909 +}
45910 +
45911 +/**
45912 + * - Remove the request from the queue
45913 + */
45914 +void complete_xiso_ep(dwc_otg_pcd_ep_t * ep)
45915 +{
45916 + dwc_otg_pcd_request_t *req = NULL;
45917 + struct dwc_iso_xreq_port *ereq = NULL;
45918 + struct dwc_iso_pkt_desc_port *ddesc_iso = NULL;
45919 + dwc_ep_t *dwcep = NULL;
45920 + int i;
45921 +
45922 + //DWC_DEBUG();
45923 + dwcep = &ep->dwc_ep;
45924 +
45925 + /* Get the first pending request from the queue */
45926 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
45927 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
45928 + if (!req) {
45929 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
45930 + return;
45931 + }
45932 + dwcep->xiso_active_xfers--;
45933 + dwcep->xiso_queued_xfers--;
45934 + /* Remove this request from the queue */
45935 + DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
45936 + } else {
45937 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
45938 + return;
45939 + }
45940 +
45941 + ep->stopped = 1;
45942 + ereq = &req->ext_req;
45943 + ddesc_iso = ereq->per_io_frame_descs;
45944 +
45945 + if (dwcep->xiso_active_xfers < 0) {
45946 + DWC_WARN("EP#%d (xiso_active_xfers=%d)", dwcep->num,
45947 + dwcep->xiso_active_xfers);
45948 + }
45949 +
45950 + /* Fill the Isoc descs of portable extended req from dma descriptors */
45951 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45952 + if (dwcep->is_in) { /* IN endpoints */
45953 + ddesc_iso[i].actual_length = ddesc_iso[i].length -
45954 + dwcep->desc_addr[i].status.b_iso_in.txbytes;
45955 + ddesc_iso[i].status =
45956 + dwcep->desc_addr[i].status.b_iso_in.txsts;
45957 + } else { /* OUT endpoints */
45958 + ddesc_iso[i].actual_length = ddesc_iso[i].length -
45959 + dwcep->desc_addr[i].status.b_iso_out.rxbytes;
45960 + ddesc_iso[i].status =
45961 + dwcep->desc_addr[i].status.b_iso_out.rxsts;
45962 + }
45963 + }
45964 +
45965 + DWC_SPINUNLOCK(ep->pcd->lock);
45966 +
45967 + /* Call the completion function in the non-portable logic */
45968 + ep->pcd->fops->xisoc_complete(ep->pcd, ep->priv, req->priv, 0,
45969 + &req->ext_req);
45970 +
45971 + DWC_SPINLOCK(ep->pcd->lock);
45972 +
45973 + /* Free the request - specific freeing needed for extended request object */
45974 + dwc_pcd_xiso_ereq_free(ep, req);
45975 +
45976 + /* Start the next request */
45977 + dwc_otg_pcd_xiso_start_next_request(ep->pcd, ep);
45978 +
45979 + return;
45980 +}
45981 +
45982 +/**
45983 + * Create and initialize the Isoc pkt descriptors of the extended request.
45984 + *
45985 + */
45986 +static int dwc_otg_pcd_xiso_create_pkt_descs(dwc_otg_pcd_request_t * req,
45987 + void *ereq_nonport,
45988 + int atomic_alloc)
45989 +{
45990 + struct dwc_iso_xreq_port *ereq = NULL;
45991 + struct dwc_iso_xreq_port *req_mapped = NULL;
45992 + struct dwc_iso_pkt_desc_port *ipds = NULL; /* To be created in this function */
45993 + uint32_t pkt_count;
45994 + int i;
45995 +
45996 + ereq = &req->ext_req;
45997 + req_mapped = (struct dwc_iso_xreq_port *)ereq_nonport;
45998 + pkt_count = req_mapped->pio_pkt_count;
45999 +
46000 + /* Create the isoc descs */
46001 + if (atomic_alloc) {
46002 + ipds = DWC_ALLOC_ATOMIC(sizeof(*ipds) * pkt_count);
46003 + } else {
46004 + ipds = DWC_ALLOC(sizeof(*ipds) * pkt_count);
46005 + }
46006 +
46007 + if (!ipds) {
46008 + DWC_ERROR("Failed to allocate isoc descriptors");
46009 + return -DWC_E_NO_MEMORY;
46010 + }
46011 +
46012 + /* Initialize the extended request fields */
46013 + ereq->per_io_frame_descs = ipds;
46014 + ereq->error_count = 0;
46015 + ereq->pio_alloc_pkt_count = pkt_count;
46016 + ereq->pio_pkt_count = pkt_count;
46017 + ereq->tr_sub_flags = req_mapped->tr_sub_flags;
46018 +
46019 + /* Init the Isoc descriptors */
46020 + for (i = 0; i < pkt_count; i++) {
46021 + ipds[i].length = req_mapped->per_io_frame_descs[i].length;
46022 + ipds[i].offset = req_mapped->per_io_frame_descs[i].offset;
46023 + ipds[i].status = req_mapped->per_io_frame_descs[i].status; /* 0 */
46024 + ipds[i].actual_length =
46025 + req_mapped->per_io_frame_descs[i].actual_length;
46026 + }
46027 +
46028 + return 0;
46029 +}
46030 +
46031 +static void prn_ext_request(struct dwc_iso_xreq_port *ereq)
46032 +{
46033 + struct dwc_iso_pkt_desc_port *xfd = NULL;
46034 + int i;
46035 +
46036 + DWC_DEBUG("per_io_frame_descs=%p", ereq->per_io_frame_descs);
46037 + DWC_DEBUG("tr_sub_flags=%d", ereq->tr_sub_flags);
46038 + DWC_DEBUG("error_count=%d", ereq->error_count);
46039 + DWC_DEBUG("pio_alloc_pkt_count=%d", ereq->pio_alloc_pkt_count);
46040 + DWC_DEBUG("pio_pkt_count=%d", ereq->pio_pkt_count);
46041 + DWC_DEBUG("res=%d", ereq->res);
46042 +
46043 + for (i = 0; i < ereq->pio_pkt_count; i++) {
46044 + xfd = &ereq->per_io_frame_descs[0];
46045 + DWC_DEBUG("FD #%d", i);
46046 +
46047 + DWC_DEBUG("xfd->actual_length=%d", xfd->actual_length);
46048 + DWC_DEBUG("xfd->length=%d", xfd->length);
46049 + DWC_DEBUG("xfd->offset=%d", xfd->offset);
46050 + DWC_DEBUG("xfd->status=%d", xfd->status);
46051 + }
46052 +}
46053 +
46054 +/**
46055 + *
46056 + */
46057 +int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
46058 + uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
46059 + int zero, void *req_handle, int atomic_alloc,
46060 + void *ereq_nonport)
46061 +{
46062 + dwc_otg_pcd_request_t *req = NULL;
46063 + dwc_otg_pcd_ep_t *ep;
46064 + dwc_irqflags_t flags;
46065 + int res;
46066 +
46067 + ep = get_ep_from_handle(pcd, ep_handle);
46068 + if (!ep) {
46069 + DWC_WARN("bad ep\n");
46070 + return -DWC_E_INVALID;
46071 + }
46072 +
46073 + /* We support this extension only for DDMA mode */
46074 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
46075 + if (!GET_CORE_IF(pcd)->dma_desc_enable)
46076 + return -DWC_E_INVALID;
46077 +
46078 + /* Create a dwc_otg_pcd_request_t object */
46079 + if (atomic_alloc) {
46080 + req = DWC_ALLOC_ATOMIC(sizeof(*req));
46081 + } else {
46082 + req = DWC_ALLOC(sizeof(*req));
46083 + }
46084 +
46085 + if (!req) {
46086 + return -DWC_E_NO_MEMORY;
46087 + }
46088 +
46089 + /* Create the Isoc descs for this request which shall be the exact match
46090 + * of the structure sent to us from the non-portable logic */
46091 + res =
46092 + dwc_otg_pcd_xiso_create_pkt_descs(req, ereq_nonport, atomic_alloc);
46093 + if (res) {
46094 + DWC_WARN("Failed to init the Isoc descriptors");
46095 + DWC_FREE(req);
46096 + return res;
46097 + }
46098 +
46099 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46100 +
46101 + DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
46102 + req->buf = buf;
46103 + req->dma = dma_buf;
46104 + req->length = buflen;
46105 + req->sent_zlp = zero;
46106 + req->priv = req_handle;
46107 +
46108 + //DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46109 + ep->dwc_ep.dma_addr = dma_buf;
46110 + ep->dwc_ep.start_xfer_buff = buf;
46111 + ep->dwc_ep.xfer_buff = buf;
46112 + ep->dwc_ep.xfer_len = 0;
46113 + ep->dwc_ep.xfer_count = 0;
46114 + ep->dwc_ep.sent_zlp = 0;
46115 + ep->dwc_ep.total_len = buflen;
46116 +
46117 + /* Add this request to the tail */
46118 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
46119 + ep->dwc_ep.xiso_queued_xfers++;
46120 +
46121 +//DWC_DEBUG("CP_0");
46122 +//DWC_DEBUG("req->ext_req.tr_sub_flags=%d", req->ext_req.tr_sub_flags);
46123 +//prn_ext_request((struct dwc_iso_xreq_port *) ereq_nonport);
46124 +//prn_ext_request(&req->ext_req);
46125 +
46126 + //DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46127 +
46128 + /* If the req->status == ASAP then check if there is any active transfer
46129 + * for this endpoint. If no active transfers, then get the first entry
46130 + * from the queue and start that transfer
46131 + */
46132 + if (req->ext_req.tr_sub_flags == DWC_EREQ_TF_ASAP) {
46133 + res = dwc_otg_pcd_xiso_start_next_request(pcd, ep);
46134 + if (res) {
46135 + DWC_WARN("Failed to start the next Isoc transfer");
46136 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46137 + DWC_FREE(req);
46138 + return res;
46139 + }
46140 + }
46141 +
46142 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46143 + return 0;
46144 +}
46145 +
46146 +#endif
46147 +/* END ifdef DWC_UTE_PER_IO ***************************************************/
46148 +int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
46149 + uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
46150 + int zero, void *req_handle, int atomic_alloc)
46151 +{
46152 + dwc_irqflags_t flags;
46153 + dwc_otg_pcd_request_t *req;
46154 + dwc_otg_pcd_ep_t *ep;
46155 + uint32_t max_transfer;
46156 +
46157 + ep = get_ep_from_handle(pcd, ep_handle);
46158 + if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
46159 + DWC_WARN("bad ep\n");
46160 + return -DWC_E_INVALID;
46161 + }
46162 +
46163 + if (atomic_alloc) {
46164 + req = DWC_ALLOC_ATOMIC(sizeof(*req));
46165 + } else {
46166 + req = DWC_ALLOC(sizeof(*req));
46167 + }
46168 +
46169 + if (!req) {
46170 + return -DWC_E_NO_MEMORY;
46171 + }
46172 + DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
46173 + if (!GET_CORE_IF(pcd)->core_params->opt) {
46174 + if (ep->dwc_ep.num != 0) {
46175 + DWC_ERROR("queue req %p, len %d buf %p\n",
46176 + req_handle, buflen, buf);
46177 + }
46178 + }
46179 +
46180 + req->buf = buf;
46181 + req->dma = dma_buf;
46182 + req->length = buflen;
46183 + req->sent_zlp = zero;
46184 + req->priv = req_handle;
46185 + req->dw_align_buf = NULL;
46186 + if ((dma_buf & 0x3) && GET_CORE_IF(pcd)->dma_enable
46187 + && !GET_CORE_IF(pcd)->dma_desc_enable)
46188 + req->dw_align_buf = DWC_DMA_ALLOC(buflen,
46189 + &req->dw_align_buf_dma);
46190 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46191 +
46192 + /*
46193 + * After adding request to the queue for IN ISOC wait for In Token Received
46194 + * when TX FIFO is empty interrupt and for OUT ISOC wait for OUT Token
46195 + * Received when EP is disabled interrupt to obtain starting microframe
46196 + * (odd/even) start transfer
46197 + */
46198 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
46199 + if (req != 0) {
46200 + depctl_data_t depctl = {.d32 =
46201 + DWC_READ_REG32(&pcd->core_if->dev_if->
46202 + in_ep_regs[ep->dwc_ep.num]->
46203 + diepctl) };
46204 + ++pcd->request_pending;
46205 +
46206 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
46207 + if (ep->dwc_ep.is_in) {
46208 + depctl.b.cnak = 1;
46209 + DWC_WRITE_REG32(&pcd->core_if->dev_if->
46210 + in_ep_regs[ep->dwc_ep.num]->
46211 + diepctl, depctl.d32);
46212 + }
46213 +
46214 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46215 + }
46216 + return 0;
46217 + }
46218 +
46219 + /*
46220 + * For EP0 IN without premature status, zlp is required?
46221 + */
46222 + if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) {
46223 + DWC_DEBUGPL(DBG_PCDV, "%d-OUT ZLP\n", ep->dwc_ep.num);
46224 + //_req->zero = 1;
46225 + }
46226 +
46227 + /* Start the transfer */
46228 + if (DWC_CIRCLEQ_EMPTY(&ep->queue) && !ep->stopped) {
46229 + /* EP0 Transfer? */
46230 + if (ep->dwc_ep.num == 0) {
46231 + switch (pcd->ep0state) {
46232 + case EP0_IN_DATA_PHASE:
46233 + DWC_DEBUGPL(DBG_PCD,
46234 + "%s ep0: EP0_IN_DATA_PHASE\n",
46235 + __func__);
46236 + break;
46237 +
46238 + case EP0_OUT_DATA_PHASE:
46239 + DWC_DEBUGPL(DBG_PCD,
46240 + "%s ep0: EP0_OUT_DATA_PHASE\n",
46241 + __func__);
46242 + if (pcd->request_config) {
46243 + /* Complete STATUS PHASE */
46244 + ep->dwc_ep.is_in = 1;
46245 + pcd->ep0state = EP0_IN_STATUS_PHASE;
46246 + }
46247 + break;
46248 +
46249 + case EP0_IN_STATUS_PHASE:
46250 + DWC_DEBUGPL(DBG_PCD,
46251 + "%s ep0: EP0_IN_STATUS_PHASE\n",
46252 + __func__);
46253 + break;
46254 +
46255 + default:
46256 + DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n",
46257 + pcd->ep0state);
46258 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46259 + return -DWC_E_SHUTDOWN;
46260 + }
46261 +
46262 + ep->dwc_ep.dma_addr = dma_buf;
46263 + ep->dwc_ep.start_xfer_buff = buf;
46264 + ep->dwc_ep.xfer_buff = buf;
46265 + ep->dwc_ep.xfer_len = buflen;
46266 + ep->dwc_ep.xfer_count = 0;
46267 + ep->dwc_ep.sent_zlp = 0;
46268 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
46269 +
46270 + if (zero) {
46271 + if ((ep->dwc_ep.xfer_len %
46272 + ep->dwc_ep.maxpacket == 0)
46273 + && (ep->dwc_ep.xfer_len != 0)) {
46274 + ep->dwc_ep.sent_zlp = 1;
46275 + }
46276 +
46277 + }
46278 +
46279 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
46280 + &ep->dwc_ep);
46281 + } // non-ep0 endpoints
46282 + else {
46283 +#ifdef DWC_UTE_CFI
46284 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
46285 + /* store the request length */
46286 + ep->dwc_ep.cfi_req_len = buflen;
46287 + pcd->cfi->ops.build_descriptors(pcd->cfi, pcd,
46288 + ep, req);
46289 + } else {
46290 +#endif
46291 + max_transfer =
46292 + GET_CORE_IF(ep->pcd)->core_params->
46293 + max_transfer_size;
46294 +
46295 + /* Setup and start the Transfer */
46296 + if (req->dw_align_buf){
46297 + if (ep->dwc_ep.is_in)
46298 + dwc_memcpy(req->dw_align_buf,
46299 + buf, buflen);
46300 + ep->dwc_ep.dma_addr =
46301 + req->dw_align_buf_dma;
46302 + ep->dwc_ep.start_xfer_buff =
46303 + req->dw_align_buf;
46304 + ep->dwc_ep.xfer_buff =
46305 + req->dw_align_buf;
46306 + } else {
46307 + ep->dwc_ep.dma_addr = dma_buf;
46308 + ep->dwc_ep.start_xfer_buff = buf;
46309 + ep->dwc_ep.xfer_buff = buf;
46310 + }
46311 + ep->dwc_ep.xfer_len = 0;
46312 + ep->dwc_ep.xfer_count = 0;
46313 + ep->dwc_ep.sent_zlp = 0;
46314 + ep->dwc_ep.total_len = buflen;
46315 +
46316 + ep->dwc_ep.maxxfer = max_transfer;
46317 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
46318 + uint32_t out_max_xfer =
46319 + DDMA_MAX_TRANSFER_SIZE -
46320 + (DDMA_MAX_TRANSFER_SIZE % 4);
46321 + if (ep->dwc_ep.is_in) {
46322 + if (ep->dwc_ep.maxxfer >
46323 + DDMA_MAX_TRANSFER_SIZE) {
46324 + ep->dwc_ep.maxxfer =
46325 + DDMA_MAX_TRANSFER_SIZE;
46326 + }
46327 + } else {
46328 + if (ep->dwc_ep.maxxfer >
46329 + out_max_xfer) {
46330 + ep->dwc_ep.maxxfer =
46331 + out_max_xfer;
46332 + }
46333 + }
46334 + }
46335 + if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
46336 + ep->dwc_ep.maxxfer -=
46337 + (ep->dwc_ep.maxxfer %
46338 + ep->dwc_ep.maxpacket);
46339 + }
46340 +
46341 + if (zero) {
46342 + if ((ep->dwc_ep.total_len %
46343 + ep->dwc_ep.maxpacket == 0)
46344 + && (ep->dwc_ep.total_len != 0)) {
46345 + ep->dwc_ep.sent_zlp = 1;
46346 + }
46347 + }
46348 +#ifdef DWC_UTE_CFI
46349 + }
46350 +#endif
46351 + dwc_otg_ep_start_transfer(GET_CORE_IF(pcd),
46352 + &ep->dwc_ep);
46353 + }
46354 + }
46355 +
46356 + if (req != 0) {
46357 + ++pcd->request_pending;
46358 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
46359 + if (ep->dwc_ep.is_in && ep->stopped
46360 + && !(GET_CORE_IF(pcd)->dma_enable)) {
46361 + /** @todo NGS Create a function for this. */
46362 + diepmsk_data_t diepmsk = {.d32 = 0 };
46363 + diepmsk.b.intktxfemp = 1;
46364 + if (GET_CORE_IF(pcd)->multiproc_int_enable) {
46365 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
46366 + dev_if->dev_global_regs->diepeachintmsk
46367 + [ep->dwc_ep.num], 0,
46368 + diepmsk.d32);
46369 + } else {
46370 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
46371 + dev_if->dev_global_regs->
46372 + diepmsk, 0, diepmsk.d32);
46373 + }
46374 +
46375 + }
46376 + }
46377 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46378 +
46379 + return 0;
46380 +}
46381 +
46382 +int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
46383 + void *req_handle)
46384 +{
46385 + dwc_irqflags_t flags;
46386 + dwc_otg_pcd_request_t *req;
46387 + dwc_otg_pcd_ep_t *ep;
46388 +
46389 + ep = get_ep_from_handle(pcd, ep_handle);
46390 + if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
46391 + DWC_WARN("bad argument\n");
46392 + return -DWC_E_INVALID;
46393 + }
46394 +
46395 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46396 +
46397 + /* make sure it's actually queued on this endpoint */
46398 + DWC_CIRCLEQ_FOREACH(req, &ep->queue, queue_entry) {
46399 + if (req->priv == (void *)req_handle) {
46400 + break;
46401 + }
46402 + }
46403 +
46404 + if (req->priv != (void *)req_handle) {
46405 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46406 + return -DWC_E_INVALID;
46407 + }
46408 +
46409 + if (!DWC_CIRCLEQ_EMPTY_ENTRY(req, queue_entry)) {
46410 + dwc_otg_request_done(ep, req, -DWC_E_RESTART);
46411 + } else {
46412 + req = NULL;
46413 + }
46414 +
46415 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46416 +
46417 + return req ? 0 : -DWC_E_SHUTDOWN;
46418 +
46419 +}
46420 +
46421 +/**
46422 + * dwc_otg_pcd_ep_wedge - sets the halt feature and ignores clear requests
46423 + *
46424 + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
46425 + * requests. If the gadget driver clears the halt status, it will
46426 + * automatically unwedge the endpoint.
46427 + *
46428 + * Returns zero on success, else negative DWC error code.
46429 + */
46430 +int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle)
46431 +{
46432 + dwc_otg_pcd_ep_t *ep;
46433 + dwc_irqflags_t flags;
46434 + int retval = 0;
46435 +
46436 + ep = get_ep_from_handle(pcd, ep_handle);
46437 +
46438 + if ((!ep->desc && ep != &pcd->ep0) ||
46439 + (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
46440 + DWC_WARN("%s, bad ep\n", __func__);
46441 + return -DWC_E_INVALID;
46442 + }
46443 +
46444 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46445 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
46446 + DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
46447 + ep->dwc_ep.is_in ? "IN" : "OUT");
46448 + retval = -DWC_E_AGAIN;
46449 + } else {
46450 + /* This code needs to be reviewed */
46451 + if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
46452 + dtxfsts_data_t txstatus;
46453 + fifosize_data_t txfifosize;
46454 +
46455 + txfifosize.d32 =
46456 + DWC_READ_REG32(&GET_CORE_IF(pcd)->
46457 + core_global_regs->dtxfsiz[ep->dwc_ep.
46458 + tx_fifo_num]);
46459 + txstatus.d32 =
46460 + DWC_READ_REG32(&GET_CORE_IF(pcd)->
46461 + dev_if->in_ep_regs[ep->dwc_ep.num]->
46462 + dtxfsts);
46463 +
46464 + if (txstatus.b.txfspcavail < txfifosize.b.depth) {
46465 + DWC_WARN("%s() Data In Tx Fifo\n", __func__);
46466 + retval = -DWC_E_AGAIN;
46467 + } else {
46468 + if (ep->dwc_ep.num == 0) {
46469 + pcd->ep0state = EP0_STALL;
46470 + }
46471 +
46472 + ep->stopped = 1;
46473 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
46474 + &ep->dwc_ep);
46475 + }
46476 + } else {
46477 + if (ep->dwc_ep.num == 0) {
46478 + pcd->ep0state = EP0_STALL;
46479 + }
46480 +
46481 + ep->stopped = 1;
46482 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
46483 + }
46484 + }
46485 +
46486 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46487 +
46488 + return retval;
46489 +}
46490 +
46491 +int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value)
46492 +{
46493 + dwc_otg_pcd_ep_t *ep;
46494 + dwc_irqflags_t flags;
46495 + int retval = 0;
46496 +
46497 + ep = get_ep_from_handle(pcd, ep_handle);
46498 +
46499 + if (!ep || (!ep->desc && ep != &pcd->ep0) ||
46500 + (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
46501 + DWC_WARN("%s, bad ep\n", __func__);
46502 + return -DWC_E_INVALID;
46503 + }
46504 +
46505 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46506 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
46507 + DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
46508 + ep->dwc_ep.is_in ? "IN" : "OUT");
46509 + retval = -DWC_E_AGAIN;
46510 + } else if (value == 0) {
46511 + dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
46512 + } else if (value == 1) {
46513 + if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
46514 + dtxfsts_data_t txstatus;
46515 + fifosize_data_t txfifosize;
46516 +
46517 + txfifosize.d32 =
46518 + DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->
46519 + dtxfsiz[ep->dwc_ep.tx_fifo_num]);
46520 + txstatus.d32 =
46521 + DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
46522 + in_ep_regs[ep->dwc_ep.num]->dtxfsts);
46523 +
46524 + if (txstatus.b.txfspcavail < txfifosize.b.depth) {
46525 + DWC_WARN("%s() Data In Tx Fifo\n", __func__);
46526 + retval = -DWC_E_AGAIN;
46527 + } else {
46528 + if (ep->dwc_ep.num == 0) {
46529 + pcd->ep0state = EP0_STALL;
46530 + }
46531 +
46532 + ep->stopped = 1;
46533 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
46534 + &ep->dwc_ep);
46535 + }
46536 + } else {
46537 + if (ep->dwc_ep.num == 0) {
46538 + pcd->ep0state = EP0_STALL;
46539 + }
46540 +
46541 + ep->stopped = 1;
46542 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
46543 + }
46544 + } else if (value == 2) {
46545 + ep->dwc_ep.stall_clear_flag = 0;
46546 + } else if (value == 3) {
46547 + ep->dwc_ep.stall_clear_flag = 1;
46548 + }
46549 +
46550 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46551 +
46552 + return retval;
46553 +}
46554 +
46555 +/**
46556 + * This function initiates remote wakeup of the host from suspend state.
46557 + */
46558 +void dwc_otg_pcd_rem_wkup_from_suspend(dwc_otg_pcd_t * pcd, int set)
46559 +{
46560 + dctl_data_t dctl = { 0 };
46561 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46562 + dsts_data_t dsts;
46563 +
46564 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
46565 + if (!dsts.b.suspsts) {
46566 + DWC_WARN("Remote wakeup while is not in suspend state\n");
46567 + }
46568 + /* Check if DEVICE_REMOTE_WAKEUP feature enabled */
46569 + if (pcd->remote_wakeup_enable) {
46570 + if (set) {
46571 +
46572 + if (core_if->adp_enable) {
46573 + gpwrdn_data_t gpwrdn;
46574 +
46575 + dwc_otg_adp_probe_stop(core_if);
46576 +
46577 + /* Mask SRP detected interrupt from Power Down Logic */
46578 + gpwrdn.d32 = 0;
46579 + gpwrdn.b.srp_det_msk = 1;
46580 + DWC_MODIFY_REG32(&core_if->
46581 + core_global_regs->gpwrdn,
46582 + gpwrdn.d32, 0);
46583 +
46584 + /* Disable Power Down Logic */
46585 + gpwrdn.d32 = 0;
46586 + gpwrdn.b.pmuactv = 1;
46587 + DWC_MODIFY_REG32(&core_if->
46588 + core_global_regs->gpwrdn,
46589 + gpwrdn.d32, 0);
46590 +
46591 + /*
46592 + * Initialize the Core for Device mode.
46593 + */
46594 + core_if->op_state = B_PERIPHERAL;
46595 + dwc_otg_core_init(core_if);
46596 + dwc_otg_enable_global_interrupts(core_if);
46597 + cil_pcd_start(core_if);
46598 +
46599 + dwc_otg_initiate_srp(core_if);
46600 + }
46601 +
46602 + dctl.b.rmtwkupsig = 1;
46603 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
46604 + dctl, 0, dctl.d32);
46605 + DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
46606 +
46607 + dwc_mdelay(2);
46608 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
46609 + dctl, dctl.d32, 0);
46610 + DWC_DEBUGPL(DBG_PCD, "Clear Remote Wakeup\n");
46611 + }
46612 + } else {
46613 + DWC_DEBUGPL(DBG_PCD, "Remote Wakeup is disabled\n");
46614 + }
46615 +}
46616 +
46617 +#ifdef CONFIG_USB_DWC_OTG_LPM
46618 +/**
46619 + * This function initiates remote wakeup of the host from L1 sleep state.
46620 + */
46621 +void dwc_otg_pcd_rem_wkup_from_sleep(dwc_otg_pcd_t * pcd, int set)
46622 +{
46623 + glpmcfg_data_t lpmcfg;
46624 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46625 +
46626 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
46627 +
46628 + /* Check if we are in L1 state */
46629 + if (!lpmcfg.b.prt_sleep_sts) {
46630 + DWC_DEBUGPL(DBG_PCD, "Device is not in sleep state\n");
46631 + return;
46632 + }
46633 +
46634 + /* Check if host allows remote wakeup */
46635 + if (!lpmcfg.b.rem_wkup_en) {
46636 + DWC_DEBUGPL(DBG_PCD, "Host does not allow remote wakeup\n");
46637 + return;
46638 + }
46639 +
46640 + /* Check if Resume OK */
46641 + if (!lpmcfg.b.sleep_state_resumeok) {
46642 + DWC_DEBUGPL(DBG_PCD, "Sleep state resume is not OK\n");
46643 + return;
46644 + }
46645 +
46646 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
46647 + lpmcfg.b.en_utmi_sleep = 0;
46648 + lpmcfg.b.hird_thres &= (~(1 << 4));
46649 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
46650 +
46651 + if (set) {
46652 + dctl_data_t dctl = {.d32 = 0 };
46653 + dctl.b.rmtwkupsig = 1;
46654 + /* Set RmtWkUpSig bit to start remote wakup signaling.
46655 + * Hardware will automatically clear this bit.
46656 + */
46657 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl,
46658 + 0, dctl.d32);
46659 + DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
46660 + }
46661 +
46662 +}
46663 +#endif
46664 +
46665 +/**
46666 + * Performs remote wakeup.
46667 + */
46668 +void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set)
46669 +{
46670 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46671 + dwc_irqflags_t flags;
46672 + if (dwc_otg_is_device_mode(core_if)) {
46673 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46674 +#ifdef CONFIG_USB_DWC_OTG_LPM
46675 + if (core_if->lx_state == DWC_OTG_L1) {
46676 + dwc_otg_pcd_rem_wkup_from_sleep(pcd, set);
46677 + } else {
46678 +#endif
46679 + dwc_otg_pcd_rem_wkup_from_suspend(pcd, set);
46680 +#ifdef CONFIG_USB_DWC_OTG_LPM
46681 + }
46682 +#endif
46683 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46684 + }
46685 + return;
46686 +}
46687 +
46688 +void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs)
46689 +{
46690 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46691 + dctl_data_t dctl = { 0 };
46692 +
46693 + if (dwc_otg_is_device_mode(core_if)) {
46694 + dctl.b.sftdiscon = 1;
46695 + DWC_PRINTF("Soft disconnect for %d useconds\n",no_of_usecs);
46696 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
46697 + dwc_udelay(no_of_usecs);
46698 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32,0);
46699 +
46700 + } else{
46701 + DWC_PRINTF("NOT SUPPORTED IN HOST MODE\n");
46702 + }
46703 + return;
46704 +
46705 +}
46706 +
46707 +int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd)
46708 +{
46709 + dsts_data_t dsts;
46710 + gotgctl_data_t gotgctl;
46711 +
46712 + /*
46713 + * This function starts the Protocol if no session is in progress. If
46714 + * a session is already in progress, but the device is suspended,
46715 + * remote wakeup signaling is started.
46716 + */
46717 +
46718 + /* Check if valid session */
46719 + gotgctl.d32 =
46720 + DWC_READ_REG32(&(GET_CORE_IF(pcd)->core_global_regs->gotgctl));
46721 + if (gotgctl.b.bsesvld) {
46722 + /* Check if suspend state */
46723 + dsts.d32 =
46724 + DWC_READ_REG32(&
46725 + (GET_CORE_IF(pcd)->dev_if->
46726 + dev_global_regs->dsts));
46727 + if (dsts.b.suspsts) {
46728 + dwc_otg_pcd_remote_wakeup(pcd, 1);
46729 + }
46730 + } else {
46731 + dwc_otg_pcd_initiate_srp(pcd);
46732 + }
46733 +
46734 + return 0;
46735 +
46736 +}
46737 +
46738 +/**
46739 + * Start the SRP timer to detect when the SRP does not complete within
46740 + * 6 seconds.
46741 + *
46742 + * @param pcd the pcd structure.
46743 + */
46744 +void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd)
46745 +{
46746 + dwc_irqflags_t flags;
46747 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46748 + dwc_otg_initiate_srp(GET_CORE_IF(pcd));
46749 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46750 +}
46751 +
46752 +int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd)
46753 +{
46754 + return dwc_otg_get_frame_number(GET_CORE_IF(pcd));
46755 +}
46756 +
46757 +int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd)
46758 +{
46759 + return GET_CORE_IF(pcd)->core_params->lpm_enable;
46760 +}
46761 +
46762 +uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd)
46763 +{
46764 + return pcd->b_hnp_enable;
46765 +}
46766 +
46767 +uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd)
46768 +{
46769 + return pcd->a_hnp_support;
46770 +}
46771 +
46772 +uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd)
46773 +{
46774 + return pcd->a_alt_hnp_support;
46775 +}
46776 +
46777 +int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd)
46778 +{
46779 + return pcd->remote_wakeup_enable;
46780 +}
46781 +
46782 +#endif /* DWC_HOST_ONLY */
46783 --- /dev/null
46784 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd.h
46785 @@ -0,0 +1,266 @@
46786 +/* ==========================================================================
46787 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.h $
46788 + * $Revision: #48 $
46789 + * $Date: 2012/08/10 $
46790 + * $Change: 2047372 $
46791 + *
46792 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
46793 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
46794 + * otherwise expressly agreed to in writing between Synopsys and you.
46795 + *
46796 + * The Software IS NOT an item of Licensed Software or Licensed Product under
46797 + * any End User Software License Agreement or Agreement for Licensed Product
46798 + * with Synopsys or any supplement thereto. You are permitted to use and
46799 + * redistribute this Software in source and binary forms, with or without
46800 + * modification, provided that redistributions of source code must retain this
46801 + * notice. You may not view, use, disclose, copy or distribute this file or
46802 + * any information contained herein except pursuant to this license grant from
46803 + * Synopsys. If you do not agree with this notice, including the disclaimer
46804 + * below, then you are not authorized to use the Software.
46805 + *
46806 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
46807 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46808 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46809 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
46810 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46811 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
46812 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
46813 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46814 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46815 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
46816 + * DAMAGE.
46817 + * ========================================================================== */
46818 +#ifndef DWC_HOST_ONLY
46819 +#if !defined(__DWC_PCD_H__)
46820 +#define __DWC_PCD_H__
46821 +
46822 +#include "dwc_otg_os_dep.h"
46823 +#include "usb.h"
46824 +#include "dwc_otg_cil.h"
46825 +#include "dwc_otg_pcd_if.h"
46826 +struct cfiobject;
46827 +
46828 +/**
46829 + * @file
46830 + *
46831 + * This file contains the structures, constants, and interfaces for
46832 + * the Perpherial Contoller Driver (PCD).
46833 + *
46834 + * The Peripheral Controller Driver (PCD) for Linux will implement the
46835 + * Gadget API, so that the existing Gadget drivers can be used. For
46836 + * the Mass Storage Function driver the File-backed USB Storage Gadget
46837 + * (FBS) driver will be used. The FBS driver supports the
46838 + * Control-Bulk (CB), Control-Bulk-Interrupt (CBI), and Bulk-Only
46839 + * transports.
46840 + *
46841 + */
46842 +
46843 +/** Invalid DMA Address */
46844 +#define DWC_DMA_ADDR_INVALID (~(dwc_dma_t)0)
46845 +
46846 +/** Max Transfer size for any EP */
46847 +#define DDMA_MAX_TRANSFER_SIZE 65535
46848 +
46849 +/**
46850 + * Get the pointer to the core_if from the pcd pointer.
46851 + */
46852 +#define GET_CORE_IF( _pcd ) (_pcd->core_if)
46853 +
46854 +/**
46855 + * States of EP0.
46856 + */
46857 +typedef enum ep0_state {
46858 + EP0_DISCONNECT, /* no host */
46859 + EP0_IDLE,
46860 + EP0_IN_DATA_PHASE,
46861 + EP0_OUT_DATA_PHASE,
46862 + EP0_IN_STATUS_PHASE,
46863 + EP0_OUT_STATUS_PHASE,
46864 + EP0_STALL,
46865 +} ep0state_e;
46866 +
46867 +/** Fordward declaration.*/
46868 +struct dwc_otg_pcd;
46869 +
46870 +/** DWC_otg iso request structure.
46871 + *
46872 + */
46873 +typedef struct usb_iso_request dwc_otg_pcd_iso_request_t;
46874 +
46875 +#ifdef DWC_UTE_PER_IO
46876 +
46877 +/**
46878 + * This shall be the exact analogy of the same type structure defined in the
46879 + * usb_gadget.h. Each descriptor contains
46880 + */
46881 +struct dwc_iso_pkt_desc_port {
46882 + uint32_t offset;
46883 + uint32_t length; /* expected length */
46884 + uint32_t actual_length;
46885 + uint32_t status;
46886 +};
46887 +
46888 +struct dwc_iso_xreq_port {
46889 + /** transfer/submission flag */
46890 + uint32_t tr_sub_flags;
46891 + /** Start the request ASAP */
46892 +#define DWC_EREQ_TF_ASAP 0x00000002
46893 + /** Just enqueue the request w/o initiating a transfer */
46894 +#define DWC_EREQ_TF_ENQUEUE 0x00000004
46895 +
46896 + /**
46897 + * count of ISO packets attached to this request - shall
46898 + * not exceed the pio_alloc_pkt_count
46899 + */
46900 + uint32_t pio_pkt_count;
46901 + /** count of ISO packets allocated for this request */
46902 + uint32_t pio_alloc_pkt_count;
46903 + /** number of ISO packet errors */
46904 + uint32_t error_count;
46905 + /** reserved for future extension */
46906 + uint32_t res;
46907 + /** Will be allocated and freed in the UTE gadget and based on the CFC value */
46908 + struct dwc_iso_pkt_desc_port *per_io_frame_descs;
46909 +};
46910 +#endif
46911 +/** DWC_otg request structure.
46912 + * This structure is a list of requests.
46913 + */
46914 +typedef struct dwc_otg_pcd_request {
46915 + void *priv;
46916 + void *buf;
46917 + dwc_dma_t dma;
46918 + uint32_t length;
46919 + uint32_t actual;
46920 + unsigned sent_zlp:1;
46921 + /**
46922 + * Used instead of original buffer if
46923 + * it(physical address) is not dword-aligned.
46924 + **/
46925 + uint8_t *dw_align_buf;
46926 + dwc_dma_t dw_align_buf_dma;
46927 +
46928 + DWC_CIRCLEQ_ENTRY(dwc_otg_pcd_request) queue_entry;
46929 +#ifdef DWC_UTE_PER_IO
46930 + struct dwc_iso_xreq_port ext_req;
46931 + //void *priv_ereq_nport; /* */
46932 +#endif
46933 +} dwc_otg_pcd_request_t;
46934 +
46935 +DWC_CIRCLEQ_HEAD(req_list, dwc_otg_pcd_request);
46936 +
46937 +/** PCD EP structure.
46938 + * This structure describes an EP, there is an array of EPs in the PCD
46939 + * structure.
46940 + */
46941 +typedef struct dwc_otg_pcd_ep {
46942 + /** USB EP Descriptor */
46943 + const usb_endpoint_descriptor_t *desc;
46944 +
46945 + /** queue of dwc_otg_pcd_requests. */
46946 + struct req_list queue;
46947 + unsigned stopped:1;
46948 + unsigned disabling:1;
46949 + unsigned dma:1;
46950 + unsigned queue_sof:1;
46951 +
46952 +#ifdef DWC_EN_ISOC
46953 + /** ISOC req handle passed */
46954 + void *iso_req_handle;
46955 +#endif //_EN_ISOC_
46956 +
46957 + /** DWC_otg ep data. */
46958 + dwc_ep_t dwc_ep;
46959 +
46960 + /** Pointer to PCD */
46961 + struct dwc_otg_pcd *pcd;
46962 +
46963 + void *priv;
46964 +} dwc_otg_pcd_ep_t;
46965 +
46966 +/** DWC_otg PCD Structure.
46967 + * This structure encapsulates the data for the dwc_otg PCD.
46968 + */
46969 +struct dwc_otg_pcd {
46970 + const struct dwc_otg_pcd_function_ops *fops;
46971 + /** The DWC otg device pointer */
46972 + struct dwc_otg_device *otg_dev;
46973 + /** Core Interface */
46974 + dwc_otg_core_if_t *core_if;
46975 + /** State of EP0 */
46976 + ep0state_e ep0state;
46977 + /** EP0 Request is pending */
46978 + unsigned ep0_pending:1;
46979 + /** Indicates when SET CONFIGURATION Request is in process */
46980 + unsigned request_config:1;
46981 + /** The state of the Remote Wakeup Enable. */
46982 + unsigned remote_wakeup_enable:1;
46983 + /** The state of the B-Device HNP Enable. */
46984 + unsigned b_hnp_enable:1;
46985 + /** The state of A-Device HNP Support. */
46986 + unsigned a_hnp_support:1;
46987 + /** The state of the A-Device Alt HNP support. */
46988 + unsigned a_alt_hnp_support:1;
46989 + /** Count of pending Requests */
46990 + unsigned request_pending;
46991 +
46992 + /** SETUP packet for EP0
46993 + * This structure is allocated as a DMA buffer on PCD initialization
46994 + * with enough space for up to 3 setup packets.
46995 + */
46996 + union {
46997 + usb_device_request_t req;
46998 + uint32_t d32[2];
46999 + } *setup_pkt;
47000 +
47001 + dwc_dma_t setup_pkt_dma_handle;
47002 +
47003 + /* Additional buffer and flag for CTRL_WR premature case */
47004 + uint8_t *backup_buf;
47005 + unsigned data_terminated;
47006 +
47007 + /** 2-byte dma buffer used to return status from GET_STATUS */
47008 + uint16_t *status_buf;
47009 + dwc_dma_t status_buf_dma_handle;
47010 +
47011 + /** EP0 */
47012 + dwc_otg_pcd_ep_t ep0;
47013 +
47014 + /** Array of IN EPs. */
47015 + dwc_otg_pcd_ep_t in_ep[MAX_EPS_CHANNELS - 1];
47016 + /** Array of OUT EPs. */
47017 + dwc_otg_pcd_ep_t out_ep[MAX_EPS_CHANNELS - 1];
47018 + /** number of valid EPs in the above array. */
47019 +// unsigned num_eps : 4;
47020 + dwc_spinlock_t *lock;
47021 +
47022 + /** Tasklet to defer starting of TEST mode transmissions until
47023 + * Status Phase has been completed.
47024 + */
47025 + dwc_tasklet_t *test_mode_tasklet;
47026 +
47027 + /** Tasklet to delay starting of xfer in DMA mode */
47028 + dwc_tasklet_t *start_xfer_tasklet;
47029 +
47030 + /** The test mode to enter when the tasklet is executed. */
47031 + unsigned test_mode;
47032 + /** The cfi_api structure that implements most of the CFI API
47033 + * and OTG specific core configuration functionality
47034 + */
47035 +#ifdef DWC_UTE_CFI
47036 + struct cfiobject *cfi;
47037 +#endif
47038 +
47039 +};
47040 +
47041 +//FIXME this functions should be static, and this prototypes should be removed
47042 +extern void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep);
47043 +extern void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep,
47044 + dwc_otg_pcd_request_t * req, int32_t status);
47045 +
47046 +void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
47047 + void *req_handle);
47048 +
47049 +extern void do_test_mode(void *data);
47050 +#endif
47051 +#endif /* DWC_HOST_ONLY */
47052 --- /dev/null
47053 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
47054 @@ -0,0 +1,360 @@
47055 +/* ==========================================================================
47056 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_if.h $
47057 + * $Revision: #11 $
47058 + * $Date: 2011/10/26 $
47059 + * $Change: 1873028 $
47060 + *
47061 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
47062 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
47063 + * otherwise expressly agreed to in writing between Synopsys and you.
47064 + *
47065 + * The Software IS NOT an item of Licensed Software or Licensed Product under
47066 + * any End User Software License Agreement or Agreement for Licensed Product
47067 + * with Synopsys or any supplement thereto. You are permitted to use and
47068 + * redistribute this Software in source and binary forms, with or without
47069 + * modification, provided that redistributions of source code must retain this
47070 + * notice. You may not view, use, disclose, copy or distribute this file or
47071 + * any information contained herein except pursuant to this license grant from
47072 + * Synopsys. If you do not agree with this notice, including the disclaimer
47073 + * below, then you are not authorized to use the Software.
47074 + *
47075 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
47076 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47077 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47078 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
47079 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
47080 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
47081 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
47082 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47083 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47084 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
47085 + * DAMAGE.
47086 + * ========================================================================== */
47087 +#ifndef DWC_HOST_ONLY
47088 +
47089 +#if !defined(__DWC_PCD_IF_H__)
47090 +#define __DWC_PCD_IF_H__
47091 +
47092 +//#include "dwc_os.h"
47093 +#include "dwc_otg_core_if.h"
47094 +
47095 +/** @file
47096 + * This file defines DWC_OTG PCD Core API.
47097 + */
47098 +
47099 +struct dwc_otg_pcd;
47100 +typedef struct dwc_otg_pcd dwc_otg_pcd_t;
47101 +
47102 +/** Maxpacket size for EP0 */
47103 +#define MAX_EP0_SIZE 64
47104 +/** Maxpacket size for any EP */
47105 +#define MAX_PACKET_SIZE 1024
47106 +
47107 +/** @name Function Driver Callbacks */
47108 +/** @{ */
47109 +
47110 +/** This function will be called whenever a previously queued request has
47111 + * completed. The status value will be set to -DWC_E_SHUTDOWN to indicated a
47112 + * failed or aborted transfer, or -DWC_E_RESTART to indicate the device was reset,
47113 + * or -DWC_E_TIMEOUT to indicate it timed out, or -DWC_E_INVALID to indicate invalid
47114 + * parameters. */
47115 +typedef int (*dwc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
47116 + void *req_handle, int32_t status,
47117 + uint32_t actual);
47118 +/**
47119 + * This function will be called whenever a previousle queued ISOC request has
47120 + * completed. Count of ISOC packets could be read using dwc_otg_pcd_get_iso_packet_count
47121 + * function.
47122 + * The status of each ISOC packet could be read using dwc_otg_pcd_get_iso_packet_*
47123 + * functions.
47124 + */
47125 +typedef int (*dwc_isoc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
47126 + void *req_handle, int proc_buf_num);
47127 +/** This function should handle any SETUP request that cannot be handled by the
47128 + * PCD Core. This includes most GET_DESCRIPTORs, SET_CONFIGS, Any
47129 + * class-specific requests, etc. The function must non-blocking.
47130 + *
47131 + * Returns 0 on success.
47132 + * Returns -DWC_E_NOT_SUPPORTED if the request is not supported.
47133 + * Returns -DWC_E_INVALID if the setup request had invalid parameters or bytes.
47134 + * Returns -DWC_E_SHUTDOWN on any other error. */
47135 +typedef int (*dwc_setup_cb_t) (dwc_otg_pcd_t * pcd, uint8_t * bytes);
47136 +/** This is called whenever the device has been disconnected. The function
47137 + * driver should take appropriate action to clean up all pending requests in the
47138 + * PCD Core, remove all endpoints (except ep0), and initialize back to reset
47139 + * state. */
47140 +typedef int (*dwc_disconnect_cb_t) (dwc_otg_pcd_t * pcd);
47141 +/** This function is called when device has been connected. */
47142 +typedef int (*dwc_connect_cb_t) (dwc_otg_pcd_t * pcd, int speed);
47143 +/** This function is called when device has been suspended */
47144 +typedef int (*dwc_suspend_cb_t) (dwc_otg_pcd_t * pcd);
47145 +/** This function is called when device has received LPM tokens, i.e.
47146 + * device has been sent to sleep state. */
47147 +typedef int (*dwc_sleep_cb_t) (dwc_otg_pcd_t * pcd);
47148 +/** This function is called when device has been resumed
47149 + * from suspend(L2) or L1 sleep state. */
47150 +typedef int (*dwc_resume_cb_t) (dwc_otg_pcd_t * pcd);
47151 +/** This function is called whenever hnp params has been changed.
47152 + * User can call get_b_hnp_enable, get_a_hnp_support, get_a_alt_hnp_support functions
47153 + * to get hnp parameters. */
47154 +typedef int (*dwc_hnp_params_changed_cb_t) (dwc_otg_pcd_t * pcd);
47155 +/** This function is called whenever USB RESET is detected. */
47156 +typedef int (*dwc_reset_cb_t) (dwc_otg_pcd_t * pcd);
47157 +
47158 +typedef int (*cfi_setup_cb_t) (dwc_otg_pcd_t * pcd, void *ctrl_req_bytes);
47159 +
47160 +/**
47161 + *
47162 + * @param ep_handle Void pointer to the usb_ep structure
47163 + * @param ereq_port Pointer to the extended request structure created in the
47164 + * portable part.
47165 + */
47166 +typedef int (*xiso_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
47167 + void *req_handle, int32_t status,
47168 + void *ereq_port);
47169 +/** Function Driver Ops Data Structure */
47170 +struct dwc_otg_pcd_function_ops {
47171 + dwc_connect_cb_t connect;
47172 + dwc_disconnect_cb_t disconnect;
47173 + dwc_setup_cb_t setup;
47174 + dwc_completion_cb_t complete;
47175 + dwc_isoc_completion_cb_t isoc_complete;
47176 + dwc_suspend_cb_t suspend;
47177 + dwc_sleep_cb_t sleep;
47178 + dwc_resume_cb_t resume;
47179 + dwc_reset_cb_t reset;
47180 + dwc_hnp_params_changed_cb_t hnp_changed;
47181 + cfi_setup_cb_t cfi_setup;
47182 +#ifdef DWC_UTE_PER_IO
47183 + xiso_completion_cb_t xisoc_complete;
47184 +#endif
47185 +};
47186 +/** @} */
47187 +
47188 +/** @name Function Driver Functions */
47189 +/** @{ */
47190 +
47191 +/** Call this function to get pointer on dwc_otg_pcd_t,
47192 + * this pointer will be used for all PCD API functions.
47193 + *
47194 + * @param core_if The DWC_OTG Core
47195 + */
47196 +extern dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if);
47197 +
47198 +/** Frees PCD allocated by dwc_otg_pcd_init
47199 + *
47200 + * @param pcd The PCD
47201 + */
47202 +extern void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd);
47203 +
47204 +/** Call this to bind the function driver to the PCD Core.
47205 + *
47206 + * @param pcd Pointer on dwc_otg_pcd_t returned by dwc_otg_pcd_init function.
47207 + * @param fops The Function Driver Ops data structure containing pointers to all callbacks.
47208 + */
47209 +extern void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
47210 + const struct dwc_otg_pcd_function_ops *fops);
47211 +
47212 +/** Enables an endpoint for use. This function enables an endpoint in
47213 + * the PCD. The endpoint is described by the ep_desc which has the
47214 + * same format as a USB ep descriptor. The ep_handle parameter is used to refer
47215 + * to the endpoint from other API functions and in callbacks. Normally this
47216 + * should be called after a SET_CONFIGURATION/SET_INTERFACE to configure the
47217 + * core for that interface.
47218 + *
47219 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47220 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
47221 + * Returns 0 on success.
47222 + *
47223 + * @param pcd The PCD
47224 + * @param ep_desc Endpoint descriptor
47225 + * @param usb_ep Handle on endpoint, that will be used to identify endpoint.
47226 + */
47227 +extern int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
47228 + const uint8_t * ep_desc, void *usb_ep);
47229 +
47230 +/** Disable the endpoint referenced by ep_handle.
47231 + *
47232 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47233 + * Returns -DWC_E_SHUTDOWN if any other error occurred.
47234 + * Returns 0 on success. */
47235 +extern int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle);
47236 +
47237 +/** Queue a data transfer request on the endpoint referenced by ep_handle.
47238 + * After the transfer is completes, the complete callback will be called with
47239 + * the request status.
47240 + *
47241 + * @param pcd The PCD
47242 + * @param ep_handle The handle of the endpoint
47243 + * @param buf The buffer for the data
47244 + * @param dma_buf The DMA buffer for the data
47245 + * @param buflen The length of the data transfer
47246 + * @param zero Specifies whether to send zero length last packet.
47247 + * @param req_handle Set this handle to any value to use to reference this
47248 + * request in the ep_dequeue function or from the complete callback
47249 + * @param atomic_alloc If driver need to perform atomic allocations
47250 + * for internal data structures.
47251 + *
47252 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47253 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
47254 + * Returns 0 on success. */
47255 +extern int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
47256 + uint8_t * buf, dwc_dma_t dma_buf,
47257 + uint32_t buflen, int zero, void *req_handle,
47258 + int atomic_alloc);
47259 +#ifdef DWC_UTE_PER_IO
47260 +/**
47261 + *
47262 + * @param ereq_nonport Pointer to the extended request part of the
47263 + * usb_request structure defined in usb_gadget.h file.
47264 + */
47265 +extern int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
47266 + uint8_t * buf, dwc_dma_t dma_buf,
47267 + uint32_t buflen, int zero,
47268 + void *req_handle, int atomic_alloc,
47269 + void *ereq_nonport);
47270 +
47271 +#endif
47272 +
47273 +/** De-queue the specified data transfer that has not yet completed.
47274 + *
47275 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47276 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
47277 + * Returns 0 on success. */
47278 +extern int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
47279 + void *req_handle);
47280 +
47281 +/** Halt (STALL) an endpoint or clear it.
47282 + *
47283 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47284 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
47285 + * Returns -DWC_E_AGAIN if the STALL cannot be sent and must be tried again later
47286 + * Returns 0 on success. */
47287 +extern int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value);
47288 +
47289 +/** This function */
47290 +extern int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle);
47291 +
47292 +/** This function should be called on every hardware interrupt */
47293 +extern int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd);
47294 +
47295 +/** This function returns current frame number */
47296 +extern int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd);
47297 +
47298 +/**
47299 + * Start isochronous transfers on the endpoint referenced by ep_handle.
47300 + * For isochronous transfers duble buffering is used.
47301 + * After processing each of buffers comlete callback will be called with
47302 + * status for each transaction.
47303 + *
47304 + * @param pcd The PCD
47305 + * @param ep_handle The handle of the endpoint
47306 + * @param buf0 The virtual address of first data buffer
47307 + * @param buf1 The virtual address of second data buffer
47308 + * @param dma0 The DMA address of first data buffer
47309 + * @param dma1 The DMA address of second data buffer
47310 + * @param sync_frame Data pattern frame number
47311 + * @param dp_frame Data size for pattern frame
47312 + * @param data_per_frame Data size for regular frame
47313 + * @param start_frame Frame number to start transfers, if -1 then start transfers ASAP.
47314 + * @param buf_proc_intrvl Interval of ISOC Buffer processing
47315 + * @param req_handle Handle of ISOC request
47316 + * @param atomic_alloc Specefies whether to perform atomic allocation for
47317 + * internal data structures.
47318 + *
47319 + * Returns -DWC_E_NO_MEMORY if there is no enough memory.
47320 + * Returns -DWC_E_INVALID if incorrect arguments are passed to the function.
47321 + * Returns -DW_E_SHUTDOWN for any other error.
47322 + * Returns 0 on success
47323 + */
47324 +extern int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
47325 + uint8_t * buf0, uint8_t * buf1,
47326 + dwc_dma_t dma0, dwc_dma_t dma1,
47327 + int sync_frame, int dp_frame,
47328 + int data_per_frame, int start_frame,
47329 + int buf_proc_intrvl, void *req_handle,
47330 + int atomic_alloc);
47331 +
47332 +/** Stop ISOC transfers on endpoint referenced by ep_handle.
47333 + *
47334 + * @param pcd The PCD
47335 + * @param ep_handle The handle of the endpoint
47336 + * @param req_handle Handle of ISOC request
47337 + *
47338 + * Returns -DWC_E_INVALID if incorrect arguments are passed to the function
47339 + * Returns 0 on success
47340 + */
47341 +int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
47342 + void *req_handle);
47343 +
47344 +/** Get ISOC packet status.
47345 + *
47346 + * @param pcd The PCD
47347 + * @param ep_handle The handle of the endpoint
47348 + * @param iso_req_handle Isochronoush request handle
47349 + * @param packet Number of packet
47350 + * @param status Out parameter for returning status
47351 + * @param actual Out parameter for returning actual length
47352 + * @param offset Out parameter for returning offset
47353 + *
47354 + */
47355 +extern void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd,
47356 + void *ep_handle,
47357 + void *iso_req_handle, int packet,
47358 + int *status, int *actual,
47359 + int *offset);
47360 +
47361 +/** Get ISOC packet count.
47362 + *
47363 + * @param pcd The PCD
47364 + * @param ep_handle The handle of the endpoint
47365 + * @param iso_req_handle
47366 + */
47367 +extern int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd,
47368 + void *ep_handle,
47369 + void *iso_req_handle);
47370 +
47371 +/** This function starts the SRP Protocol if no session is in progress. If
47372 + * a session is already in progress, but the device is suspended,
47373 + * remote wakeup signaling is started.
47374 + */
47375 +extern int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd);
47376 +
47377 +/** This function returns 1 if LPM support is enabled, and 0 otherwise. */
47378 +extern int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd);
47379 +
47380 +/** This function returns 1 if remote wakeup is allowed and 0, otherwise. */
47381 +extern int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd);
47382 +
47383 +/** Initiate SRP */
47384 +extern void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd);
47385 +
47386 +/** Starts remote wakeup signaling. */
47387 +extern void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set);
47388 +
47389 +/** Starts micorsecond soft disconnect. */
47390 +extern void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs);
47391 +/** This function returns whether device is dualspeed.*/
47392 +extern uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd);
47393 +
47394 +/** This function returns whether device is otg. */
47395 +extern uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd);
47396 +
47397 +/** These functions allow to get hnp parameters */
47398 +extern uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd);
47399 +extern uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd);
47400 +extern uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd);
47401 +
47402 +/** CFI specific Interface functions */
47403 +/** Allocate a cfi buffer */
47404 +extern uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep,
47405 + dwc_dma_t * addr, size_t buflen,
47406 + int flags);
47407 +
47408 +/******************************************************************************/
47409 +
47410 +/** @} */
47411 +
47412 +#endif /* __DWC_PCD_IF_H__ */
47413 +
47414 +#endif /* DWC_HOST_ONLY */
47415 --- /dev/null
47416 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
47417 @@ -0,0 +1,5147 @@
47418 +/* ==========================================================================
47419 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_intr.c $
47420 + * $Revision: #116 $
47421 + * $Date: 2012/08/10 $
47422 + * $Change: 2047372 $
47423 + *
47424 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
47425 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
47426 + * otherwise expressly agreed to in writing between Synopsys and you.
47427 + *
47428 + * The Software IS NOT an item of Licensed Software or Licensed Product under
47429 + * any End User Software License Agreement or Agreement for Licensed Product
47430 + * with Synopsys or any supplement thereto. You are permitted to use and
47431 + * redistribute this Software in source and binary forms, with or without
47432 + * modification, provided that redistributions of source code must retain this
47433 + * notice. You may not view, use, disclose, copy or distribute this file or
47434 + * any information contained herein except pursuant to this license grant from
47435 + * Synopsys. If you do not agree with this notice, including the disclaimer
47436 + * below, then you are not authorized to use the Software.
47437 + *
47438 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
47439 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47440 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47441 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
47442 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
47443 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
47444 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
47445 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47446 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47447 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
47448 + * DAMAGE.
47449 + * ========================================================================== */
47450 +#ifndef DWC_HOST_ONLY
47451 +
47452 +#include "dwc_otg_pcd.h"
47453 +
47454 +#ifdef DWC_UTE_CFI
47455 +#include "dwc_otg_cfi.h"
47456 +#endif
47457 +
47458 +#ifdef DWC_UTE_PER_IO
47459 +extern void complete_xiso_ep(dwc_otg_pcd_ep_t * ep);
47460 +#endif
47461 +//#define PRINT_CFI_DMA_DESCS
47462 +
47463 +#define DEBUG_EP0
47464 +
47465 +/**
47466 + * This function updates OTG.
47467 + */
47468 +static void dwc_otg_pcd_update_otg(dwc_otg_pcd_t * pcd, const unsigned reset)
47469 +{
47470 +
47471 + if (reset) {
47472 + pcd->b_hnp_enable = 0;
47473 + pcd->a_hnp_support = 0;
47474 + pcd->a_alt_hnp_support = 0;
47475 + }
47476 +
47477 + if (pcd->fops->hnp_changed) {
47478 + pcd->fops->hnp_changed(pcd);
47479 + }
47480 +}
47481 +
47482 +/** @file
47483 + * This file contains the implementation of the PCD Interrupt handlers.
47484 + *
47485 + * The PCD handles the device interrupts. Many conditions can cause a
47486 + * device interrupt. When an interrupt occurs, the device interrupt
47487 + * service routine determines the cause of the interrupt and
47488 + * dispatches handling to the appropriate function. These interrupt
47489 + * handling functions are described below.
47490 + * All interrupt registers are processed from LSB to MSB.
47491 + */
47492 +
47493 +/**
47494 + * This function prints the ep0 state for debug purposes.
47495 + */
47496 +static inline void print_ep0_state(dwc_otg_pcd_t * pcd)
47497 +{
47498 +#ifdef DEBUG
47499 + char str[40];
47500 +
47501 + switch (pcd->ep0state) {
47502 + case EP0_DISCONNECT:
47503 + dwc_strcpy(str, "EP0_DISCONNECT");
47504 + break;
47505 + case EP0_IDLE:
47506 + dwc_strcpy(str, "EP0_IDLE");
47507 + break;
47508 + case EP0_IN_DATA_PHASE:
47509 + dwc_strcpy(str, "EP0_IN_DATA_PHASE");
47510 + break;
47511 + case EP0_OUT_DATA_PHASE:
47512 + dwc_strcpy(str, "EP0_OUT_DATA_PHASE");
47513 + break;
47514 + case EP0_IN_STATUS_PHASE:
47515 + dwc_strcpy(str, "EP0_IN_STATUS_PHASE");
47516 + break;
47517 + case EP0_OUT_STATUS_PHASE:
47518 + dwc_strcpy(str, "EP0_OUT_STATUS_PHASE");
47519 + break;
47520 + case EP0_STALL:
47521 + dwc_strcpy(str, "EP0_STALL");
47522 + break;
47523 + default:
47524 + dwc_strcpy(str, "EP0_INVALID");
47525 + }
47526 +
47527 + DWC_DEBUGPL(DBG_ANY, "%s(%d)\n", str, pcd->ep0state);
47528 +#endif
47529 +}
47530 +
47531 +/**
47532 + * This function calculate the size of the payload in the memory
47533 + * for out endpoints and prints size for debug purposes(used in
47534 + * 2.93a DevOutNak feature).
47535 + */
47536 +static inline void print_memory_payload(dwc_otg_pcd_t * pcd, dwc_ep_t * ep)
47537 +{
47538 +#ifdef DEBUG
47539 + deptsiz_data_t deptsiz_init = {.d32 = 0 };
47540 + deptsiz_data_t deptsiz_updt = {.d32 = 0 };
47541 + int pack_num;
47542 + unsigned payload;
47543 +
47544 + deptsiz_init.d32 = pcd->core_if->start_doeptsiz_val[ep->num];
47545 + deptsiz_updt.d32 =
47546 + DWC_READ_REG32(&pcd->core_if->dev_if->
47547 + out_ep_regs[ep->num]->doeptsiz);
47548 + /* Payload will be */
47549 + payload = deptsiz_init.b.xfersize - deptsiz_updt.b.xfersize;
47550 + /* Packet count is decremented every time a packet
47551 + * is written to the RxFIFO not in to the external memory
47552 + * So, if payload == 0, then it means no packet was sent to ext memory*/
47553 + pack_num = (!payload) ? 0 : (deptsiz_init.b.pktcnt - deptsiz_updt.b.pktcnt);
47554 + DWC_DEBUGPL(DBG_PCDV,
47555 + "Payload for EP%d-%s\n",
47556 + ep->num, (ep->is_in ? "IN" : "OUT"));
47557 + DWC_DEBUGPL(DBG_PCDV,
47558 + "Number of transfered bytes = 0x%08x\n", payload);
47559 + DWC_DEBUGPL(DBG_PCDV,
47560 + "Number of transfered packets = %d\n", pack_num);
47561 +#endif
47562 +}
47563 +
47564 +
47565 +#ifdef DWC_UTE_CFI
47566 +static inline void print_desc(struct dwc_otg_dma_desc *ddesc,
47567 + const uint8_t * epname, int descnum)
47568 +{
47569 + CFI_INFO
47570 + ("%s DMA_DESC(%d) buf=0x%08x bytes=0x%04x; sp=0x%x; l=0x%x; sts=0x%02x; bs=0x%02x\n",
47571 + epname, descnum, ddesc->buf, ddesc->status.b.bytes,
47572 + ddesc->status.b.sp, ddesc->status.b.l, ddesc->status.b.sts,
47573 + ddesc->status.b.bs);
47574 +}
47575 +#endif
47576 +
47577 +/**
47578 + * This function returns pointer to in ep struct with number ep_num
47579 + */
47580 +static inline dwc_otg_pcd_ep_t *get_in_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
47581 +{
47582 + int i;
47583 + int num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
47584 + if (ep_num == 0) {
47585 + return &pcd->ep0;
47586 + } else {
47587 + for (i = 0; i < num_in_eps; ++i) {
47588 + if (pcd->in_ep[i].dwc_ep.num == ep_num)
47589 + return &pcd->in_ep[i];
47590 + }
47591 + return 0;
47592 + }
47593 +}
47594 +
47595 +/**
47596 + * This function returns pointer to out ep struct with number ep_num
47597 + */
47598 +static inline dwc_otg_pcd_ep_t *get_out_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
47599 +{
47600 + int i;
47601 + int num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
47602 + if (ep_num == 0) {
47603 + return &pcd->ep0;
47604 + } else {
47605 + for (i = 0; i < num_out_eps; ++i) {
47606 + if (pcd->out_ep[i].dwc_ep.num == ep_num)
47607 + return &pcd->out_ep[i];
47608 + }
47609 + return 0;
47610 + }
47611 +}
47612 +
47613 +/**
47614 + * This functions gets a pointer to an EP from the wIndex address
47615 + * value of the control request.
47616 + */
47617 +dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex)
47618 +{
47619 + dwc_otg_pcd_ep_t *ep;
47620 + uint32_t ep_num = UE_GET_ADDR(wIndex);
47621 +
47622 + if (ep_num == 0) {
47623 + ep = &pcd->ep0;
47624 + } else if (UE_GET_DIR(wIndex) == UE_DIR_IN) { /* in ep */
47625 + ep = &pcd->in_ep[ep_num - 1];
47626 + } else {
47627 + ep = &pcd->out_ep[ep_num - 1];
47628 + }
47629 +
47630 + return ep;
47631 +}
47632 +
47633 +/**
47634 + * This function checks the EP request queue, if the queue is not
47635 + * empty the next request is started.
47636 + */
47637 +void start_next_request(dwc_otg_pcd_ep_t * ep)
47638 +{
47639 + dwc_otg_pcd_request_t *req = 0;
47640 + uint32_t max_transfer =
47641 + GET_CORE_IF(ep->pcd)->core_params->max_transfer_size;
47642 +
47643 +#ifdef DWC_UTE_CFI
47644 + struct dwc_otg_pcd *pcd;
47645 + pcd = ep->pcd;
47646 +#endif
47647 +
47648 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
47649 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
47650 +
47651 +#ifdef DWC_UTE_CFI
47652 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
47653 + ep->dwc_ep.cfi_req_len = req->length;
47654 + pcd->cfi->ops.build_descriptors(pcd->cfi, pcd, ep, req);
47655 + } else {
47656 +#endif
47657 + /* Setup and start the Transfer */
47658 + if (req->dw_align_buf) {
47659 + ep->dwc_ep.dma_addr = req->dw_align_buf_dma;
47660 + ep->dwc_ep.start_xfer_buff = req->dw_align_buf;
47661 + ep->dwc_ep.xfer_buff = req->dw_align_buf;
47662 + } else {
47663 + ep->dwc_ep.dma_addr = req->dma;
47664 + ep->dwc_ep.start_xfer_buff = req->buf;
47665 + ep->dwc_ep.xfer_buff = req->buf;
47666 + }
47667 + ep->dwc_ep.sent_zlp = 0;
47668 + ep->dwc_ep.total_len = req->length;
47669 + ep->dwc_ep.xfer_len = 0;
47670 + ep->dwc_ep.xfer_count = 0;
47671 +
47672 + ep->dwc_ep.maxxfer = max_transfer;
47673 + if (GET_CORE_IF(ep->pcd)->dma_desc_enable) {
47674 + uint32_t out_max_xfer = DDMA_MAX_TRANSFER_SIZE
47675 + - (DDMA_MAX_TRANSFER_SIZE % 4);
47676 + if (ep->dwc_ep.is_in) {
47677 + if (ep->dwc_ep.maxxfer >
47678 + DDMA_MAX_TRANSFER_SIZE) {
47679 + ep->dwc_ep.maxxfer =
47680 + DDMA_MAX_TRANSFER_SIZE;
47681 + }
47682 + } else {
47683 + if (ep->dwc_ep.maxxfer > out_max_xfer) {
47684 + ep->dwc_ep.maxxfer =
47685 + out_max_xfer;
47686 + }
47687 + }
47688 + }
47689 + if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
47690 + ep->dwc_ep.maxxfer -=
47691 + (ep->dwc_ep.maxxfer % ep->dwc_ep.maxpacket);
47692 + }
47693 + if (req->sent_zlp) {
47694 + if ((ep->dwc_ep.total_len %
47695 + ep->dwc_ep.maxpacket == 0)
47696 + && (ep->dwc_ep.total_len != 0)) {
47697 + ep->dwc_ep.sent_zlp = 1;
47698 + }
47699 +
47700 + }
47701 +#ifdef DWC_UTE_CFI
47702 + }
47703 +#endif
47704 + dwc_otg_ep_start_transfer(GET_CORE_IF(ep->pcd), &ep->dwc_ep);
47705 + } else if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
47706 + DWC_PRINTF("There are no more ISOC requests \n");
47707 + ep->dwc_ep.frame_num = 0xFFFFFFFF;
47708 + }
47709 +}
47710 +
47711 +/**
47712 + * This function handles the SOF Interrupts. At this time the SOF
47713 + * Interrupt is disabled.
47714 + */
47715 +int32_t dwc_otg_pcd_handle_sof_intr(dwc_otg_pcd_t * pcd)
47716 +{
47717 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47718 +
47719 + gintsts_data_t gintsts;
47720 +
47721 + DWC_DEBUGPL(DBG_PCD, "SOF\n");
47722 +
47723 + /* Clear interrupt */
47724 + gintsts.d32 = 0;
47725 + gintsts.b.sofintr = 1;
47726 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
47727 +
47728 + return 1;
47729 +}
47730 +
47731 +/**
47732 + * This function handles the Rx Status Queue Level Interrupt, which
47733 + * indicates that there is a least one packet in the Rx FIFO. The
47734 + * packets are moved from the FIFO to memory, where they will be
47735 + * processed when the Endpoint Interrupt Register indicates Transfer
47736 + * Complete or SETUP Phase Done.
47737 + *
47738 + * Repeat the following until the Rx Status Queue is empty:
47739 + * -# Read the Receive Status Pop Register (GRXSTSP) to get Packet
47740 + * info
47741 + * -# If Receive FIFO is empty then skip to step Clear the interrupt
47742 + * and exit
47743 + * -# If SETUP Packet call dwc_otg_read_setup_packet to copy the
47744 + * SETUP data to the buffer
47745 + * -# If OUT Data Packet call dwc_otg_read_packet to copy the data
47746 + * to the destination buffer
47747 + */
47748 +int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(dwc_otg_pcd_t * pcd)
47749 +{
47750 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47751 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
47752 + gintmsk_data_t gintmask = {.d32 = 0 };
47753 + device_grxsts_data_t status;
47754 + dwc_otg_pcd_ep_t *ep;
47755 + gintsts_data_t gintsts;
47756 +#ifdef DEBUG
47757 + static char *dpid_str[] = { "D0", "D2", "D1", "MDATA" };
47758 +#endif
47759 +
47760 + //DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd);
47761 + /* Disable the Rx Status Queue Level interrupt */
47762 + gintmask.b.rxstsqlvl = 1;
47763 + DWC_MODIFY_REG32(&global_regs->gintmsk, gintmask.d32, 0);
47764 +
47765 + /* Get the Status from the top of the FIFO */
47766 + status.d32 = DWC_READ_REG32(&global_regs->grxstsp);
47767 +
47768 + DWC_DEBUGPL(DBG_PCD, "EP:%d BCnt:%d DPID:%s "
47769 + "pktsts:%x Frame:%d(0x%0x)\n",
47770 + status.b.epnum, status.b.bcnt,
47771 + dpid_str[status.b.dpid],
47772 + status.b.pktsts, status.b.fn, status.b.fn);
47773 + /* Get pointer to EP structure */
47774 + ep = get_out_ep(pcd, status.b.epnum);
47775 +
47776 + switch (status.b.pktsts) {
47777 + case DWC_DSTS_GOUT_NAK:
47778 + DWC_DEBUGPL(DBG_PCDV, "Global OUT NAK\n");
47779 + break;
47780 + case DWC_STS_DATA_UPDT:
47781 + DWC_DEBUGPL(DBG_PCDV, "OUT Data Packet\n");
47782 + if (status.b.bcnt && ep->dwc_ep.xfer_buff) {
47783 + /** @todo NGS Check for buffer overflow? */
47784 + dwc_otg_read_packet(core_if,
47785 + ep->dwc_ep.xfer_buff,
47786 + status.b.bcnt);
47787 + ep->dwc_ep.xfer_count += status.b.bcnt;
47788 + ep->dwc_ep.xfer_buff += status.b.bcnt;
47789 + }
47790 + break;
47791 + case DWC_STS_XFER_COMP:
47792 + DWC_DEBUGPL(DBG_PCDV, "OUT Complete\n");
47793 + break;
47794 + case DWC_DSTS_SETUP_COMP:
47795 +#ifdef DEBUG_EP0
47796 + DWC_DEBUGPL(DBG_PCDV, "Setup Complete\n");
47797 +#endif
47798 + break;
47799 + case DWC_DSTS_SETUP_UPDT:
47800 + dwc_otg_read_setup_packet(core_if, pcd->setup_pkt->d32);
47801 +#ifdef DEBUG_EP0
47802 + DWC_DEBUGPL(DBG_PCD,
47803 + "SETUP PKT: %02x.%02x v%04x i%04x l%04x\n",
47804 + pcd->setup_pkt->req.bmRequestType,
47805 + pcd->setup_pkt->req.bRequest,
47806 + UGETW(pcd->setup_pkt->req.wValue),
47807 + UGETW(pcd->setup_pkt->req.wIndex),
47808 + UGETW(pcd->setup_pkt->req.wLength));
47809 +#endif
47810 + ep->dwc_ep.xfer_count += status.b.bcnt;
47811 + break;
47812 + default:
47813 + DWC_DEBUGPL(DBG_PCDV, "Invalid Packet Status (0x%0x)\n",
47814 + status.b.pktsts);
47815 + break;
47816 + }
47817 +
47818 + /* Enable the Rx Status Queue Level interrupt */
47819 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmask.d32);
47820 + /* Clear interrupt */
47821 + gintsts.d32 = 0;
47822 + gintsts.b.rxstsqlvl = 1;
47823 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
47824 +
47825 + //DWC_DEBUGPL(DBG_PCDV, "EXIT: %s\n", __func__);
47826 + return 1;
47827 +}
47828 +
47829 +/**
47830 + * This function examines the Device IN Token Learning Queue to
47831 + * determine the EP number of the last IN token received. This
47832 + * implementation is for the Mass Storage device where there are only
47833 + * 2 IN EPs (Control-IN and BULK-IN).
47834 + *
47835 + * The EP numbers for the first six IN Tokens are in DTKNQR1 and there
47836 + * are 8 EP Numbers in each of the other possible DTKNQ Registers.
47837 + *
47838 + * @param core_if Programming view of DWC_otg controller.
47839 + *
47840 + */
47841 +static inline int get_ep_of_last_in_token(dwc_otg_core_if_t * core_if)
47842 +{
47843 + dwc_otg_device_global_regs_t *dev_global_regs =
47844 + core_if->dev_if->dev_global_regs;
47845 + const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
47846 + /* Number of Token Queue Registers */
47847 + const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
47848 + dtknq1_data_t dtknqr1;
47849 + uint32_t in_tkn_epnums[4];
47850 + int ndx = 0;
47851 + int i = 0;
47852 + volatile uint32_t *addr = &dev_global_regs->dtknqr1;
47853 + int epnum = 0;
47854 +
47855 + //DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
47856 +
47857 + /* Read the DTKNQ Registers */
47858 + for (i = 0; i < DTKNQ_REG_CNT; i++) {
47859 + in_tkn_epnums[i] = DWC_READ_REG32(addr);
47860 + DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
47861 + in_tkn_epnums[i]);
47862 + if (addr == &dev_global_regs->dvbusdis) {
47863 + addr = &dev_global_regs->dtknqr3_dthrctl;
47864 + } else {
47865 + ++addr;
47866 + }
47867 +
47868 + }
47869 +
47870 + /* Copy the DTKNQR1 data to the bit field. */
47871 + dtknqr1.d32 = in_tkn_epnums[0];
47872 + /* Get the EP numbers */
47873 + in_tkn_epnums[0] = dtknqr1.b.epnums0_5;
47874 + ndx = dtknqr1.b.intknwptr - 1;
47875 +
47876 + //DWC_DEBUGPL(DBG_PCDV,"ndx=%d\n",ndx);
47877 + if (ndx == -1) {
47878 + /** @todo Find a simpler way to calculate the max
47879 + * queue position.*/
47880 + int cnt = TOKEN_Q_DEPTH;
47881 + if (TOKEN_Q_DEPTH <= 6) {
47882 + cnt = TOKEN_Q_DEPTH - 1;
47883 + } else if (TOKEN_Q_DEPTH <= 14) {
47884 + cnt = TOKEN_Q_DEPTH - 7;
47885 + } else if (TOKEN_Q_DEPTH <= 22) {
47886 + cnt = TOKEN_Q_DEPTH - 15;
47887 + } else {
47888 + cnt = TOKEN_Q_DEPTH - 23;
47889 + }
47890 + epnum = (in_tkn_epnums[DTKNQ_REG_CNT - 1] >> (cnt * 4)) & 0xF;
47891 + } else {
47892 + if (ndx <= 5) {
47893 + epnum = (in_tkn_epnums[0] >> (ndx * 4)) & 0xF;
47894 + } else if (ndx <= 13) {
47895 + ndx -= 6;
47896 + epnum = (in_tkn_epnums[1] >> (ndx * 4)) & 0xF;
47897 + } else if (ndx <= 21) {
47898 + ndx -= 14;
47899 + epnum = (in_tkn_epnums[2] >> (ndx * 4)) & 0xF;
47900 + } else if (ndx <= 29) {
47901 + ndx -= 22;
47902 + epnum = (in_tkn_epnums[3] >> (ndx * 4)) & 0xF;
47903 + }
47904 + }
47905 + //DWC_DEBUGPL(DBG_PCD,"epnum=%d\n",epnum);
47906 + return epnum;
47907 +}
47908 +
47909 +/**
47910 + * This interrupt occurs when the non-periodic Tx FIFO is half-empty.
47911 + * The active request is checked for the next packet to be loaded into
47912 + * the non-periodic Tx FIFO.
47913 + */
47914 +int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(dwc_otg_pcd_t * pcd)
47915 +{
47916 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47917 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
47918 + dwc_otg_dev_in_ep_regs_t *ep_regs;
47919 + gnptxsts_data_t txstatus = {.d32 = 0 };
47920 + gintsts_data_t gintsts;
47921 +
47922 + int epnum = 0;
47923 + dwc_otg_pcd_ep_t *ep = 0;
47924 + uint32_t len = 0;
47925 + int dwords;
47926 +
47927 + /* Get the epnum from the IN Token Learning Queue. */
47928 + epnum = get_ep_of_last_in_token(core_if);
47929 + ep = get_in_ep(pcd, epnum);
47930 +
47931 + DWC_DEBUGPL(DBG_PCD, "NP TxFifo Empty: %d \n", epnum);
47932 +
47933 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
47934 +
47935 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47936 + if (len > ep->dwc_ep.maxpacket) {
47937 + len = ep->dwc_ep.maxpacket;
47938 + }
47939 + dwords = (len + 3) / 4;
47940 +
47941 + /* While there is space in the queue and space in the FIFO and
47942 + * More data to tranfer, Write packets to the Tx FIFO */
47943 + txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
47944 + DWC_DEBUGPL(DBG_PCDV, "b4 GNPTXSTS=0x%08x\n", txstatus.d32);
47945 +
47946 + while (txstatus.b.nptxqspcavail > 0 &&
47947 + txstatus.b.nptxfspcavail > dwords &&
47948 + ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len) {
47949 + /* Write the FIFO */
47950 + dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
47951 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47952 +
47953 + if (len > ep->dwc_ep.maxpacket) {
47954 + len = ep->dwc_ep.maxpacket;
47955 + }
47956 +
47957 + dwords = (len + 3) / 4;
47958 + txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
47959 + DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n", txstatus.d32);
47960 + }
47961 +
47962 + DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n",
47963 + DWC_READ_REG32(&global_regs->gnptxsts));
47964 +
47965 + /* Clear interrupt */
47966 + gintsts.d32 = 0;
47967 + gintsts.b.nptxfempty = 1;
47968 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
47969 +
47970 + return 1;
47971 +}
47972 +
47973 +/**
47974 + * This function is called when dedicated Tx FIFO Empty interrupt occurs.
47975 + * The active request is checked for the next packet to be loaded into
47976 + * apropriate Tx FIFO.
47977 + */
47978 +static int32_t write_empty_tx_fifo(dwc_otg_pcd_t * pcd, uint32_t epnum)
47979 +{
47980 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47981 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
47982 + dwc_otg_dev_in_ep_regs_t *ep_regs;
47983 + dtxfsts_data_t txstatus = {.d32 = 0 };
47984 + dwc_otg_pcd_ep_t *ep = 0;
47985 + uint32_t len = 0;
47986 + int dwords;
47987 +
47988 + ep = get_in_ep(pcd, epnum);
47989 +
47990 + DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
47991 +
47992 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
47993 +
47994 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47995 +
47996 + if (len > ep->dwc_ep.maxpacket) {
47997 + len = ep->dwc_ep.maxpacket;
47998 + }
47999 +
48000 + dwords = (len + 3) / 4;
48001 +
48002 + /* While there is space in the queue and space in the FIFO and
48003 + * More data to tranfer, Write packets to the Tx FIFO */
48004 + txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
48005 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
48006 +
48007 + while (txstatus.b.txfspcavail > dwords &&
48008 + ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len &&
48009 + ep->dwc_ep.xfer_len != 0) {
48010 + /* Write the FIFO */
48011 + dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
48012 +
48013 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
48014 + if (len > ep->dwc_ep.maxpacket) {
48015 + len = ep->dwc_ep.maxpacket;
48016 + }
48017 +
48018 + dwords = (len + 3) / 4;
48019 + txstatus.d32 =
48020 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
48021 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
48022 + txstatus.d32);
48023 + }
48024 +
48025 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
48026 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
48027 +
48028 + return 1;
48029 +}
48030 +
48031 +/**
48032 + * This function is called when the Device is disconnected. It stops
48033 + * any active requests and informs the Gadget driver of the
48034 + * disconnect.
48035 + */
48036 +void dwc_otg_pcd_stop(dwc_otg_pcd_t * pcd)
48037 +{
48038 + int i, num_in_eps, num_out_eps;
48039 + dwc_otg_pcd_ep_t *ep;
48040 +
48041 + gintmsk_data_t intr_mask = {.d32 = 0 };
48042 +
48043 + DWC_SPINLOCK(pcd->lock);
48044 +
48045 + num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
48046 + num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
48047 +
48048 + DWC_DEBUGPL(DBG_PCDV, "%s() \n", __func__);
48049 + /* don't disconnect drivers more than once */
48050 + if (pcd->ep0state == EP0_DISCONNECT) {
48051 + DWC_DEBUGPL(DBG_ANY, "%s() Already Disconnected\n", __func__);
48052 + DWC_SPINUNLOCK(pcd->lock);
48053 + return;
48054 + }
48055 + pcd->ep0state = EP0_DISCONNECT;
48056 +
48057 + /* Reset the OTG state. */
48058 + dwc_otg_pcd_update_otg(pcd, 1);
48059 +
48060 + /* Disable the NP Tx Fifo Empty Interrupt. */
48061 + intr_mask.b.nptxfempty = 1;
48062 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
48063 + intr_mask.d32, 0);
48064 +
48065 + /* Flush the FIFOs */
48066 + /**@todo NGS Flush Periodic FIFOs */
48067 + dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), 0x10);
48068 + dwc_otg_flush_rx_fifo(GET_CORE_IF(pcd));
48069 +
48070 + /* prevent new request submissions, kill any outstanding requests */
48071 + ep = &pcd->ep0;
48072 + dwc_otg_request_nuke(ep);
48073 + /* prevent new request submissions, kill any outstanding requests */
48074 + for (i = 0; i < num_in_eps; i++) {
48075 + dwc_otg_pcd_ep_t *ep = &pcd->in_ep[i];
48076 + dwc_otg_request_nuke(ep);
48077 + }
48078 + /* prevent new request submissions, kill any outstanding requests */
48079 + for (i = 0; i < num_out_eps; i++) {
48080 + dwc_otg_pcd_ep_t *ep = &pcd->out_ep[i];
48081 + dwc_otg_request_nuke(ep);
48082 + }
48083 +
48084 + /* report disconnect; the driver is already quiesced */
48085 + if (pcd->fops->disconnect) {
48086 + DWC_SPINUNLOCK(pcd->lock);
48087 + pcd->fops->disconnect(pcd);
48088 + DWC_SPINLOCK(pcd->lock);
48089 + }
48090 + DWC_SPINUNLOCK(pcd->lock);
48091 +}
48092 +
48093 +/**
48094 + * This interrupt indicates that ...
48095 + */
48096 +int32_t dwc_otg_pcd_handle_i2c_intr(dwc_otg_pcd_t * pcd)
48097 +{
48098 + gintmsk_data_t intr_mask = {.d32 = 0 };
48099 + gintsts_data_t gintsts;
48100 +
48101 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "i2cintr");
48102 + intr_mask.b.i2cintr = 1;
48103 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
48104 + intr_mask.d32, 0);
48105 +
48106 + /* Clear interrupt */
48107 + gintsts.d32 = 0;
48108 + gintsts.b.i2cintr = 1;
48109 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48110 + gintsts.d32);
48111 + return 1;
48112 +}
48113 +
48114 +/**
48115 + * This interrupt indicates that ...
48116 + */
48117 +int32_t dwc_otg_pcd_handle_early_suspend_intr(dwc_otg_pcd_t * pcd)
48118 +{
48119 + gintsts_data_t gintsts;
48120 +#if defined(VERBOSE)
48121 + DWC_PRINTF("Early Suspend Detected\n");
48122 +#endif
48123 +
48124 + /* Clear interrupt */
48125 + gintsts.d32 = 0;
48126 + gintsts.b.erlysuspend = 1;
48127 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48128 + gintsts.d32);
48129 + return 1;
48130 +}
48131 +
48132 +/**
48133 + * This function configures EPO to receive SETUP packets.
48134 + *
48135 + * @todo NGS: Update the comments from the HW FS.
48136 + *
48137 + * -# Program the following fields in the endpoint specific registers
48138 + * for Control OUT EP 0, in order to receive a setup packet
48139 + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
48140 + * setup packets)
48141 + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
48142 + * to back setup packets)
48143 + * - In DMA mode, DOEPDMA0 Register with a memory address to
48144 + * store any setup packets received
48145 + *
48146 + * @param core_if Programming view of DWC_otg controller.
48147 + * @param pcd Programming view of the PCD.
48148 + */
48149 +static inline void ep0_out_start(dwc_otg_core_if_t * core_if,
48150 + dwc_otg_pcd_t * pcd)
48151 +{
48152 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
48153 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
48154 + dwc_otg_dev_dma_desc_t *dma_desc;
48155 + depctl_data_t doepctl = {.d32 = 0 };
48156 +
48157 +#ifdef VERBOSE
48158 + DWC_DEBUGPL(DBG_PCDV, "%s() doepctl0=%0x\n", __func__,
48159 + DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
48160 +#endif
48161 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
48162 + doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
48163 + if (doepctl.b.epena) {
48164 + return;
48165 + }
48166 + }
48167 +
48168 + doeptsize0.b.supcnt = 3;
48169 + doeptsize0.b.pktcnt = 1;
48170 + doeptsize0.b.xfersize = 8 * 3;
48171 +
48172 + if (core_if->dma_enable) {
48173 + if (!core_if->dma_desc_enable) {
48174 + /** put here as for Hermes mode deptisz register should not be written */
48175 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
48176 + doeptsize0.d32);
48177 +
48178 + /** @todo dma needs to handle multiple setup packets (up to 3) */
48179 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
48180 + pcd->setup_pkt_dma_handle);
48181 + } else {
48182 + dev_if->setup_desc_index =
48183 + (dev_if->setup_desc_index + 1) & 1;
48184 + dma_desc =
48185 + dev_if->setup_desc_addr[dev_if->setup_desc_index];
48186 +
48187 + /** DMA Descriptor Setup */
48188 + dma_desc->status.b.bs = BS_HOST_BUSY;
48189 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
48190 + dma_desc->status.b.sr = 0;
48191 + dma_desc->status.b.mtrf = 0;
48192 + }
48193 + dma_desc->status.b.l = 1;
48194 + dma_desc->status.b.ioc = 1;
48195 + dma_desc->status.b.bytes = pcd->ep0.dwc_ep.maxpacket;
48196 + dma_desc->buf = pcd->setup_pkt_dma_handle;
48197 + dma_desc->status.b.sts = 0;
48198 + dma_desc->status.b.bs = BS_HOST_READY;
48199 +
48200 + /** DOEPDMA0 Register write */
48201 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
48202 + dev_if->dma_setup_desc_addr
48203 + [dev_if->setup_desc_index]);
48204 + }
48205 +
48206 + } else {
48207 + /** put here as for Hermes mode deptisz register should not be written */
48208 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
48209 + doeptsize0.d32);
48210 + }
48211 +
48212 + /** DOEPCTL0 Register write cnak will be set after setup interrupt */
48213 + doepctl.d32 = 0;
48214 + doepctl.b.epena = 1;
48215 + if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
48216 + doepctl.b.cnak = 1;
48217 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
48218 + } else {
48219 + DWC_MODIFY_REG32(&dev_if->out_ep_regs[0]->doepctl, 0, doepctl.d32);
48220 + }
48221 +
48222 +#ifdef VERBOSE
48223 + DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
48224 + DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
48225 + DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
48226 + DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
48227 +#endif
48228 +}
48229 +
48230 +/**
48231 + * This interrupt occurs when a USB Reset is detected. When the USB
48232 + * Reset Interrupt occurs the device state is set to DEFAULT and the
48233 + * EP0 state is set to IDLE.
48234 + * -# Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1)
48235 + * -# Unmask the following interrupt bits
48236 + * - DAINTMSK.INEP0 = 1 (Control 0 IN endpoint)
48237 + * - DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint)
48238 + * - DOEPMSK.SETUP = 1
48239 + * - DOEPMSK.XferCompl = 1
48240 + * - DIEPMSK.XferCompl = 1
48241 + * - DIEPMSK.TimeOut = 1
48242 + * -# Program the following fields in the endpoint specific registers
48243 + * for Control OUT EP 0, in order to receive a setup packet
48244 + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
48245 + * setup packets)
48246 + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
48247 + * to back setup packets)
48248 + * - In DMA mode, DOEPDMA0 Register with a memory address to
48249 + * store any setup packets received
48250 + * At this point, all the required initialization, except for enabling
48251 + * the control 0 OUT endpoint is done, for receiving SETUP packets.
48252 + */
48253 +int32_t dwc_otg_pcd_handle_usb_reset_intr(dwc_otg_pcd_t * pcd)
48254 +{
48255 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48256 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
48257 + depctl_data_t doepctl = {.d32 = 0 };
48258 + depctl_data_t diepctl = {.d32 = 0 };
48259 + daint_data_t daintmsk = {.d32 = 0 };
48260 + doepmsk_data_t doepmsk = {.d32 = 0 };
48261 + diepmsk_data_t diepmsk = {.d32 = 0 };
48262 + dcfg_data_t dcfg = {.d32 = 0 };
48263 + grstctl_t resetctl = {.d32 = 0 };
48264 + dctl_data_t dctl = {.d32 = 0 };
48265 + int i = 0;
48266 + gintsts_data_t gintsts;
48267 + pcgcctl_data_t power = {.d32 = 0 };
48268 +
48269 + power.d32 = DWC_READ_REG32(core_if->pcgcctl);
48270 + if (power.b.stoppclk) {
48271 + power.d32 = 0;
48272 + power.b.stoppclk = 1;
48273 + DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
48274 +
48275 + power.b.pwrclmp = 1;
48276 + DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
48277 +
48278 + power.b.rstpdwnmodule = 1;
48279 + DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
48280 + }
48281 +
48282 + core_if->lx_state = DWC_OTG_L0;
48283 +
48284 + DWC_PRINTF("USB RESET\n");
48285 +#ifdef DWC_EN_ISOC
48286 + for (i = 1; i < 16; ++i) {
48287 + dwc_otg_pcd_ep_t *ep;
48288 + dwc_ep_t *dwc_ep;
48289 + ep = get_in_ep(pcd, i);
48290 + if (ep != 0) {
48291 + dwc_ep = &ep->dwc_ep;
48292 + dwc_ep->next_frame = 0xffffffff;
48293 + }
48294 + }
48295 +#endif /* DWC_EN_ISOC */
48296 +
48297 + /* reset the HNP settings */
48298 + dwc_otg_pcd_update_otg(pcd, 1);
48299 +
48300 + /* Clear the Remote Wakeup Signalling */
48301 + dctl.b.rmtwkupsig = 1;
48302 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
48303 +
48304 + /* Set NAK for all OUT EPs */
48305 + doepctl.b.snak = 1;
48306 + for (i = 0; i <= dev_if->num_out_eps; i++) {
48307 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
48308 + }
48309 +
48310 + /* Flush the NP Tx FIFO */
48311 + dwc_otg_flush_tx_fifo(core_if, 0x10);
48312 + /* Flush the Learning Queue */
48313 + resetctl.b.intknqflsh = 1;
48314 + DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
48315 +
48316 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
48317 + core_if->start_predict = 0;
48318 + for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) {
48319 + core_if->nextep_seq[i] = 0xff; // 0xff - EP not active
48320 + }
48321 + core_if->nextep_seq[0] = 0;
48322 + core_if->first_in_nextep_seq = 0;
48323 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
48324 + diepctl.b.nextep = 0;
48325 + DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
48326 +
48327 + /* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
48328 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
48329 + dcfg.b.epmscnt = 2;
48330 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
48331 +
48332 + DWC_DEBUGPL(DBG_PCDV,
48333 + "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
48334 + __func__, core_if->first_in_nextep_seq);
48335 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
48336 + DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
48337 + }
48338 + }
48339 +
48340 + if (core_if->multiproc_int_enable) {
48341 + daintmsk.b.inep0 = 1;
48342 + daintmsk.b.outep0 = 1;
48343 + DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk,
48344 + daintmsk.d32);
48345 +
48346 + doepmsk.b.setup = 1;
48347 + doepmsk.b.xfercompl = 1;
48348 + doepmsk.b.ahberr = 1;
48349 + doepmsk.b.epdisabled = 1;
48350 +
48351 + if ((core_if->dma_desc_enable) ||
48352 + (core_if->dma_enable
48353 + && core_if->snpsid >= OTG_CORE_REV_3_00a)) {
48354 + doepmsk.b.stsphsercvd = 1;
48355 + }
48356 + if (core_if->dma_desc_enable)
48357 + doepmsk.b.bna = 1;
48358 +/*
48359 + doepmsk.b.babble = 1;
48360 + doepmsk.b.nyet = 1;
48361 +
48362 + if (core_if->dma_enable) {
48363 + doepmsk.b.nak = 1;
48364 + }
48365 +*/
48366 + DWC_WRITE_REG32(&dev_if->dev_global_regs->doepeachintmsk[0],
48367 + doepmsk.d32);
48368 +
48369 + diepmsk.b.xfercompl = 1;
48370 + diepmsk.b.timeout = 1;
48371 + diepmsk.b.epdisabled = 1;
48372 + diepmsk.b.ahberr = 1;
48373 + diepmsk.b.intknepmis = 1;
48374 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
48375 + diepmsk.b.intknepmis = 0;
48376 +
48377 +/* if (core_if->dma_desc_enable) {
48378 + diepmsk.b.bna = 1;
48379 + }
48380 +*/
48381 +/*
48382 + if (core_if->dma_enable) {
48383 + diepmsk.b.nak = 1;
48384 + }
48385 +*/
48386 + DWC_WRITE_REG32(&dev_if->dev_global_regs->diepeachintmsk[0],
48387 + diepmsk.d32);
48388 + } else {
48389 + daintmsk.b.inep0 = 1;
48390 + daintmsk.b.outep0 = 1;
48391 + DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk,
48392 + daintmsk.d32);
48393 +
48394 + doepmsk.b.setup = 1;
48395 + doepmsk.b.xfercompl = 1;
48396 + doepmsk.b.ahberr = 1;
48397 + doepmsk.b.epdisabled = 1;
48398 +
48399 + if ((core_if->dma_desc_enable) ||
48400 + (core_if->dma_enable
48401 + && core_if->snpsid >= OTG_CORE_REV_3_00a)) {
48402 + doepmsk.b.stsphsercvd = 1;
48403 + }
48404 + if (core_if->dma_desc_enable)
48405 + doepmsk.b.bna = 1;
48406 + DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, doepmsk.d32);
48407 +
48408 + diepmsk.b.xfercompl = 1;
48409 + diepmsk.b.timeout = 1;
48410 + diepmsk.b.epdisabled = 1;
48411 + diepmsk.b.ahberr = 1;
48412 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
48413 + diepmsk.b.intknepmis = 0;
48414 +/*
48415 + if (core_if->dma_desc_enable) {
48416 + diepmsk.b.bna = 1;
48417 + }
48418 +*/
48419 +
48420 + DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, diepmsk.d32);
48421 + }
48422 +
48423 + /* Reset Device Address */
48424 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
48425 + dcfg.b.devaddr = 0;
48426 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
48427 +
48428 + /* setup EP0 to receive SETUP packets */
48429 + if (core_if->snpsid <= OTG_CORE_REV_2_94a)
48430 + ep0_out_start(core_if, pcd);
48431 +
48432 + /* Clear interrupt */
48433 + gintsts.d32 = 0;
48434 + gintsts.b.usbreset = 1;
48435 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
48436 +
48437 + return 1;
48438 +}
48439 +
48440 +/**
48441 + * Get the device speed from the device status register and convert it
48442 + * to USB speed constant.
48443 + *
48444 + * @param core_if Programming view of DWC_otg controller.
48445 + */
48446 +static int get_device_speed(dwc_otg_core_if_t * core_if)
48447 +{
48448 + dsts_data_t dsts;
48449 + int speed = 0;
48450 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
48451 +
48452 + switch (dsts.b.enumspd) {
48453 + case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
48454 + speed = USB_SPEED_HIGH;
48455 + break;
48456 + case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
48457 + case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
48458 + speed = USB_SPEED_FULL;
48459 + break;
48460 +
48461 + case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
48462 + speed = USB_SPEED_LOW;
48463 + break;
48464 + }
48465 +
48466 + return speed;
48467 +}
48468 +
48469 +/**
48470 + * Read the device status register and set the device speed in the
48471 + * data structure.
48472 + * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate.
48473 + */
48474 +int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t * pcd)
48475 +{
48476 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48477 + gintsts_data_t gintsts;
48478 + gusbcfg_data_t gusbcfg;
48479 + dwc_otg_core_global_regs_t *global_regs =
48480 + GET_CORE_IF(pcd)->core_global_regs;
48481 + uint8_t utmi16b, utmi8b;
48482 + int speed;
48483 + DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n");
48484 +
48485 + if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_2_60a) {
48486 + utmi16b = 6; //vahrama old value was 6;
48487 + utmi8b = 9;
48488 + } else {
48489 + utmi16b = 4;
48490 + utmi8b = 8;
48491 + }
48492 + dwc_otg_ep0_activate(GET_CORE_IF(pcd), &ep0->dwc_ep);
48493 + if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a) {
48494 + ep0_out_start(GET_CORE_IF(pcd), pcd);
48495 + }
48496 +
48497 +#ifdef DEBUG_EP0
48498 + print_ep0_state(pcd);
48499 +#endif
48500 +
48501 + if (pcd->ep0state == EP0_DISCONNECT) {
48502 + pcd->ep0state = EP0_IDLE;
48503 + } else if (pcd->ep0state == EP0_STALL) {
48504 + pcd->ep0state = EP0_IDLE;
48505 + }
48506 +
48507 + pcd->ep0state = EP0_IDLE;
48508 +
48509 + ep0->stopped = 0;
48510 +
48511 + speed = get_device_speed(GET_CORE_IF(pcd));
48512 + pcd->fops->connect(pcd, speed);
48513 +
48514 + /* Set USB turnaround time based on device speed and PHY interface. */
48515 + gusbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
48516 + if (speed == USB_SPEED_HIGH) {
48517 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
48518 + DWC_HWCFG2_HS_PHY_TYPE_ULPI) {
48519 + /* ULPI interface */
48520 + gusbcfg.b.usbtrdtim = 9;
48521 + }
48522 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
48523 + DWC_HWCFG2_HS_PHY_TYPE_UTMI) {
48524 + /* UTMI+ interface */
48525 + if (GET_CORE_IF(pcd)->hwcfg4.b.utmi_phy_data_width == 0) {
48526 + gusbcfg.b.usbtrdtim = utmi8b;
48527 + } else if (GET_CORE_IF(pcd)->hwcfg4.
48528 + b.utmi_phy_data_width == 1) {
48529 + gusbcfg.b.usbtrdtim = utmi16b;
48530 + } else if (GET_CORE_IF(pcd)->
48531 + core_params->phy_utmi_width == 8) {
48532 + gusbcfg.b.usbtrdtim = utmi8b;
48533 + } else {
48534 + gusbcfg.b.usbtrdtim = utmi16b;
48535 + }
48536 + }
48537 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
48538 + DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) {
48539 + /* UTMI+ OR ULPI interface */
48540 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
48541 + /* ULPI interface */
48542 + gusbcfg.b.usbtrdtim = 9;
48543 + } else {
48544 + /* UTMI+ interface */
48545 + if (GET_CORE_IF(pcd)->
48546 + core_params->phy_utmi_width == 16) {
48547 + gusbcfg.b.usbtrdtim = utmi16b;
48548 + } else {
48549 + gusbcfg.b.usbtrdtim = utmi8b;
48550 + }
48551 + }
48552 + }
48553 + } else {
48554 + /* Full or low speed */
48555 + gusbcfg.b.usbtrdtim = 9;
48556 + }
48557 + DWC_WRITE_REG32(&global_regs->gusbcfg, gusbcfg.d32);
48558 +
48559 + /* Clear interrupt */
48560 + gintsts.d32 = 0;
48561 + gintsts.b.enumdone = 1;
48562 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48563 + gintsts.d32);
48564 + return 1;
48565 +}
48566 +
48567 +/**
48568 + * This interrupt indicates that the ISO OUT Packet was dropped due to
48569 + * Rx FIFO full or Rx Status Queue Full. If this interrupt occurs
48570 + * read all the data from the Rx FIFO.
48571 + */
48572 +int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr(dwc_otg_pcd_t * pcd)
48573 +{
48574 + gintmsk_data_t intr_mask = {.d32 = 0 };
48575 + gintsts_data_t gintsts;
48576 +
48577 + DWC_WARN("INTERRUPT Handler not implemented for %s\n",
48578 + "ISOC Out Dropped");
48579 +
48580 + intr_mask.b.isooutdrop = 1;
48581 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
48582 + intr_mask.d32, 0);
48583 +
48584 + /* Clear interrupt */
48585 + gintsts.d32 = 0;
48586 + gintsts.b.isooutdrop = 1;
48587 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48588 + gintsts.d32);
48589 +
48590 + return 1;
48591 +}
48592 +
48593 +/**
48594 + * This interrupt indicates the end of the portion of the micro-frame
48595 + * for periodic transactions. If there is a periodic transaction for
48596 + * the next frame, load the packets into the EP periodic Tx FIFO.
48597 + */
48598 +int32_t dwc_otg_pcd_handle_end_periodic_frame_intr(dwc_otg_pcd_t * pcd)
48599 +{
48600 + gintmsk_data_t intr_mask = {.d32 = 0 };
48601 + gintsts_data_t gintsts;
48602 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "EOP");
48603 +
48604 + intr_mask.b.eopframe = 1;
48605 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
48606 + intr_mask.d32, 0);
48607 +
48608 + /* Clear interrupt */
48609 + gintsts.d32 = 0;
48610 + gintsts.b.eopframe = 1;
48611 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48612 + gintsts.d32);
48613 +
48614 + return 1;
48615 +}
48616 +
48617 +/**
48618 + * This interrupt indicates that EP of the packet on the top of the
48619 + * non-periodic Tx FIFO does not match EP of the IN Token received.
48620 + *
48621 + * The "Device IN Token Queue" Registers are read to determine the
48622 + * order the IN Tokens have been received. The non-periodic Tx FIFO
48623 + * is flushed, so it can be reloaded in the order seen in the IN Token
48624 + * Queue.
48625 + */
48626 +int32_t dwc_otg_pcd_handle_ep_mismatch_intr(dwc_otg_pcd_t * pcd)
48627 +{
48628 + gintsts_data_t gintsts;
48629 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48630 + dctl_data_t dctl;
48631 + gintmsk_data_t intr_mask = {.d32 = 0 };
48632 +
48633 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable) {
48634 + core_if->start_predict = 1;
48635 +
48636 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
48637 +
48638 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
48639 + if (!gintsts.b.ginnakeff) {
48640 + /* Disable EP Mismatch interrupt */
48641 + intr_mask.d32 = 0;
48642 + intr_mask.b.epmismatch = 1;
48643 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
48644 + /* Enable the Global IN NAK Effective Interrupt */
48645 + intr_mask.d32 = 0;
48646 + intr_mask.b.ginnakeff = 1;
48647 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
48648 + /* Set the global non-periodic IN NAK handshake */
48649 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
48650 + dctl.b.sgnpinnak = 1;
48651 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
48652 + } else {
48653 + DWC_PRINTF("gintsts.b.ginnakeff = 1! dctl.b.sgnpinnak not set\n");
48654 + }
48655 + /* Disabling of all EP's will be done in dwc_otg_pcd_handle_in_nak_effective()
48656 + * handler after Global IN NAK Effective interrupt will be asserted */
48657 + }
48658 + /* Clear interrupt */
48659 + gintsts.d32 = 0;
48660 + gintsts.b.epmismatch = 1;
48661 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
48662 +
48663 + return 1;
48664 +}
48665 +
48666 +/**
48667 + * This interrupt is valid only in DMA mode. This interrupt indicates that the
48668 + * core has stopped fetching data for IN endpoints due to the unavailability of
48669 + * TxFIFO space or Request Queue space. This interrupt is used by the
48670 + * application for an endpoint mismatch algorithm.
48671 + *
48672 + * @param pcd The PCD
48673 + */
48674 +int32_t dwc_otg_pcd_handle_ep_fetsusp_intr(dwc_otg_pcd_t * pcd)
48675 +{
48676 + gintsts_data_t gintsts;
48677 + gintmsk_data_t gintmsk_data;
48678 + dctl_data_t dctl;
48679 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48680 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
48681 +
48682 + /* Clear the global non-periodic IN NAK handshake */
48683 + dctl.d32 = 0;
48684 + dctl.b.cgnpinnak = 1;
48685 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
48686 +
48687 + /* Mask GINTSTS.FETSUSP interrupt */
48688 + gintmsk_data.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
48689 + gintmsk_data.b.fetsusp = 0;
48690 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk_data.d32);
48691 +
48692 + /* Clear interrupt */
48693 + gintsts.d32 = 0;
48694 + gintsts.b.fetsusp = 1;
48695 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
48696 +
48697 + return 1;
48698 +}
48699 +/**
48700 + * This funcion stalls EP0.
48701 + */
48702 +static inline void ep0_do_stall(dwc_otg_pcd_t * pcd, const int err_val)
48703 +{
48704 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48705 + usb_device_request_t *ctrl = &pcd->setup_pkt->req;
48706 + DWC_WARN("req %02x.%02x protocol STALL; err %d\n",
48707 + ctrl->bmRequestType, ctrl->bRequest, err_val);
48708 +
48709 + ep0->dwc_ep.is_in = 1;
48710 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep0->dwc_ep);
48711 + pcd->ep0.stopped = 1;
48712 + pcd->ep0state = EP0_IDLE;
48713 + ep0_out_start(GET_CORE_IF(pcd), pcd);
48714 +}
48715 +
48716 +/**
48717 + * This functions delegates the setup command to the gadget driver.
48718 + */
48719 +static inline void do_gadget_setup(dwc_otg_pcd_t * pcd,
48720 + usb_device_request_t * ctrl)
48721 +{
48722 + int ret = 0;
48723 + DWC_SPINUNLOCK(pcd->lock);
48724 + ret = pcd->fops->setup(pcd, (uint8_t *) ctrl);
48725 + DWC_SPINLOCK(pcd->lock);
48726 + if (ret < 0) {
48727 + ep0_do_stall(pcd, ret);
48728 + }
48729 +
48730 + /** @todo This is a g_file_storage gadget driver specific
48731 + * workaround: a DELAYED_STATUS result from the fsg_setup
48732 + * routine will result in the gadget queueing a EP0 IN status
48733 + * phase for a two-stage control transfer. Exactly the same as
48734 + * a SET_CONFIGURATION/SET_INTERFACE except that this is a class
48735 + * specific request. Need a generic way to know when the gadget
48736 + * driver will queue the status phase. Can we assume when we
48737 + * call the gadget driver setup() function that it will always
48738 + * queue and require the following flag? Need to look into
48739 + * this.
48740 + */
48741 +
48742 + if (ret == 256 + 999) {
48743 + pcd->request_config = 1;
48744 + }
48745 +}
48746 +
48747 +#ifdef DWC_UTE_CFI
48748 +/**
48749 + * This functions delegates the CFI setup commands to the gadget driver.
48750 + * This function will return a negative value to indicate a failure.
48751 + */
48752 +static inline int cfi_gadget_setup(dwc_otg_pcd_t * pcd,
48753 + struct cfi_usb_ctrlrequest *ctrl_req)
48754 +{
48755 + int ret = 0;
48756 +
48757 + if (pcd->fops && pcd->fops->cfi_setup) {
48758 + DWC_SPINUNLOCK(pcd->lock);
48759 + ret = pcd->fops->cfi_setup(pcd, ctrl_req);
48760 + DWC_SPINLOCK(pcd->lock);
48761 + if (ret < 0) {
48762 + ep0_do_stall(pcd, ret);
48763 + return ret;
48764 + }
48765 + }
48766 +
48767 + return ret;
48768 +}
48769 +#endif
48770 +
48771 +/**
48772 + * This function starts the Zero-Length Packet for the IN status phase
48773 + * of a 2 stage control transfer.
48774 + */
48775 +static inline void do_setup_in_status_phase(dwc_otg_pcd_t * pcd)
48776 +{
48777 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48778 + if (pcd->ep0state == EP0_STALL) {
48779 + return;
48780 + }
48781 +
48782 + pcd->ep0state = EP0_IN_STATUS_PHASE;
48783 +
48784 + /* Prepare for more SETUP Packets */
48785 + DWC_DEBUGPL(DBG_PCD, "EP0 IN ZLP\n");
48786 + if ((GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a)
48787 + && (pcd->core_if->dma_desc_enable)
48788 + && (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len)) {
48789 + DWC_DEBUGPL(DBG_PCDV,
48790 + "Data terminated wait next packet in out_desc_addr\n");
48791 + pcd->backup_buf = phys_to_virt(ep0->dwc_ep.dma_addr);
48792 + pcd->data_terminated = 1;
48793 + }
48794 + ep0->dwc_ep.xfer_len = 0;
48795 + ep0->dwc_ep.xfer_count = 0;
48796 + ep0->dwc_ep.is_in = 1;
48797 + ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
48798 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
48799 +
48800 + /* Prepare for more SETUP Packets */
48801 + //ep0_out_start(GET_CORE_IF(pcd), pcd);
48802 +}
48803 +
48804 +/**
48805 + * This function starts the Zero-Length Packet for the OUT status phase
48806 + * of a 2 stage control transfer.
48807 + */
48808 +static inline void do_setup_out_status_phase(dwc_otg_pcd_t * pcd)
48809 +{
48810 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48811 + if (pcd->ep0state == EP0_STALL) {
48812 + DWC_DEBUGPL(DBG_PCD, "EP0 STALLED\n");
48813 + return;
48814 + }
48815 + pcd->ep0state = EP0_OUT_STATUS_PHASE;
48816 +
48817 + DWC_DEBUGPL(DBG_PCD, "EP0 OUT ZLP\n");
48818 + ep0->dwc_ep.xfer_len = 0;
48819 + ep0->dwc_ep.xfer_count = 0;
48820 + ep0->dwc_ep.is_in = 0;
48821 + ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
48822 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
48823 +
48824 + /* Prepare for more SETUP Packets */
48825 + if (GET_CORE_IF(pcd)->dma_enable == 0) {
48826 + ep0_out_start(GET_CORE_IF(pcd), pcd);
48827 + }
48828 +}
48829 +
48830 +/**
48831 + * Clear the EP halt (STALL) and if pending requests start the
48832 + * transfer.
48833 + */
48834 +static inline void pcd_clear_halt(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
48835 +{
48836 + if (ep->dwc_ep.stall_clear_flag == 0)
48837 + dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
48838 +
48839 + /* Reactive the EP */
48840 + dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
48841 + if (ep->stopped) {
48842 + ep->stopped = 0;
48843 + /* If there is a request in the EP queue start it */
48844 +
48845 + /** @todo FIXME: this causes an EP mismatch in DMA mode.
48846 + * epmismatch not yet implemented. */
48847 +
48848 + /*
48849 + * Above fixme is solved by implmenting a tasklet to call the
48850 + * start_next_request(), outside of interrupt context at some
48851 + * time after the current time, after a clear-halt setup packet.
48852 + * Still need to implement ep mismatch in the future if a gadget
48853 + * ever uses more than one endpoint at once
48854 + */
48855 + ep->queue_sof = 1;
48856 + DWC_TASK_SCHEDULE(pcd->start_xfer_tasklet);
48857 + }
48858 + /* Start Control Status Phase */
48859 + do_setup_in_status_phase(pcd);
48860 +}
48861 +
48862 +/**
48863 + * This function is called when the SET_FEATURE TEST_MODE Setup packet
48864 + * is sent from the host. The Device Control register is written with
48865 + * the Test Mode bits set to the specified Test Mode. This is done as
48866 + * a tasklet so that the "Status" phase of the control transfer
48867 + * completes before transmitting the TEST packets.
48868 + *
48869 + * @todo This has not been tested since the tasklet struct was put
48870 + * into the PCD struct!
48871 + *
48872 + */
48873 +void do_test_mode(void *data)
48874 +{
48875 + dctl_data_t dctl;
48876 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
48877 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48878 + int test_mode = pcd->test_mode;
48879 +
48880 +// DWC_WARN("%s() has not been tested since being rewritten!\n", __func__);
48881 +
48882 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
48883 + switch (test_mode) {
48884 + case 1: // TEST_J
48885 + dctl.b.tstctl = 1;
48886 + break;
48887 +
48888 + case 2: // TEST_K
48889 + dctl.b.tstctl = 2;
48890 + break;
48891 +
48892 + case 3: // TEST_SE0_NAK
48893 + dctl.b.tstctl = 3;
48894 + break;
48895 +
48896 + case 4: // TEST_PACKET
48897 + dctl.b.tstctl = 4;
48898 + break;
48899 +
48900 + case 5: // TEST_FORCE_ENABLE
48901 + dctl.b.tstctl = 5;
48902 + break;
48903 + }
48904 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
48905 +}
48906 +
48907 +/**
48908 + * This function process the GET_STATUS Setup Commands.
48909 + */
48910 +static inline void do_get_status(dwc_otg_pcd_t * pcd)
48911 +{
48912 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48913 + dwc_otg_pcd_ep_t *ep;
48914 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48915 + uint16_t *status = pcd->status_buf;
48916 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48917 +
48918 +#ifdef DEBUG_EP0
48919 + DWC_DEBUGPL(DBG_PCD,
48920 + "GET_STATUS %02x.%02x v%04x i%04x l%04x\n",
48921 + ctrl.bmRequestType, ctrl.bRequest,
48922 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
48923 + UGETW(ctrl.wLength));
48924 +#endif
48925 +
48926 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
48927 + case UT_DEVICE:
48928 + if(UGETW(ctrl.wIndex) == 0xF000) { /* OTG Status selector */
48929 + DWC_PRINTF("wIndex - %d\n", UGETW(ctrl.wIndex));
48930 + DWC_PRINTF("OTG VERSION - %d\n", core_if->otg_ver);
48931 + DWC_PRINTF("OTG CAP - %d, %d\n",
48932 + core_if->core_params->otg_cap,
48933 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
48934 + if (core_if->otg_ver == 1
48935 + && core_if->core_params->otg_cap ==
48936 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48937 + uint8_t *otgsts = (uint8_t*)pcd->status_buf;
48938 + *otgsts = (core_if->otg_sts & 0x1);
48939 + pcd->ep0_pending = 1;
48940 + ep0->dwc_ep.start_xfer_buff =
48941 + (uint8_t *) otgsts;
48942 + ep0->dwc_ep.xfer_buff = (uint8_t *) otgsts;
48943 + ep0->dwc_ep.dma_addr =
48944 + pcd->status_buf_dma_handle;
48945 + ep0->dwc_ep.xfer_len = 1;
48946 + ep0->dwc_ep.xfer_count = 0;
48947 + ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
48948 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
48949 + &ep0->dwc_ep);
48950 + return;
48951 + } else {
48952 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48953 + return;
48954 + }
48955 + break;
48956 + } else {
48957 + *status = 0x1; /* Self powered */
48958 + *status |= pcd->remote_wakeup_enable << 1;
48959 + break;
48960 + }
48961 + case UT_INTERFACE:
48962 + *status = 0;
48963 + break;
48964 +
48965 + case UT_ENDPOINT:
48966 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
48967 + if (ep == 0 || UGETW(ctrl.wLength) > 2) {
48968 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48969 + return;
48970 + }
48971 + /** @todo check for EP stall */
48972 + *status = ep->stopped;
48973 + break;
48974 + }
48975 + pcd->ep0_pending = 1;
48976 + ep0->dwc_ep.start_xfer_buff = (uint8_t *) status;
48977 + ep0->dwc_ep.xfer_buff = (uint8_t *) status;
48978 + ep0->dwc_ep.dma_addr = pcd->status_buf_dma_handle;
48979 + ep0->dwc_ep.xfer_len = 2;
48980 + ep0->dwc_ep.xfer_count = 0;
48981 + ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
48982 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
48983 +}
48984 +
48985 +/**
48986 + * This function process the SET_FEATURE Setup Commands.
48987 + */
48988 +static inline void do_set_feature(dwc_otg_pcd_t * pcd)
48989 +{
48990 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48991 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
48992 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48993 + dwc_otg_pcd_ep_t *ep = 0;
48994 + int32_t otg_cap_param = core_if->core_params->otg_cap;
48995 + gotgctl_data_t gotgctl = {.d32 = 0 };
48996 +
48997 + DWC_DEBUGPL(DBG_PCD, "SET_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
48998 + ctrl.bmRequestType, ctrl.bRequest,
48999 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
49000 + UGETW(ctrl.wLength));
49001 + DWC_DEBUGPL(DBG_PCD, "otg_cap=%d\n", otg_cap_param);
49002 +
49003 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
49004 + case UT_DEVICE:
49005 + switch (UGETW(ctrl.wValue)) {
49006 + case UF_DEVICE_REMOTE_WAKEUP:
49007 + pcd->remote_wakeup_enable = 1;
49008 + break;
49009 +
49010 + case UF_TEST_MODE:
49011 + /* Setup the Test Mode tasklet to do the Test
49012 + * Packet generation after the SETUP Status
49013 + * phase has completed. */
49014 +
49015 + /** @todo This has not been tested since the
49016 + * tasklet struct was put into the PCD
49017 + * struct! */
49018 + pcd->test_mode = UGETW(ctrl.wIndex) >> 8;
49019 + DWC_TASK_SCHEDULE(pcd->test_mode_tasklet);
49020 + break;
49021 +
49022 + case UF_DEVICE_B_HNP_ENABLE:
49023 + DWC_DEBUGPL(DBG_PCDV,
49024 + "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
49025 +
49026 + /* dev may initiate HNP */
49027 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
49028 + pcd->b_hnp_enable = 1;
49029 + dwc_otg_pcd_update_otg(pcd, 0);
49030 + DWC_DEBUGPL(DBG_PCD, "Request B HNP\n");
49031 + /**@todo Is the gotgctl.devhnpen cleared
49032 + * by a USB Reset? */
49033 + gotgctl.b.devhnpen = 1;
49034 + gotgctl.b.hnpreq = 1;
49035 + DWC_WRITE_REG32(&global_regs->gotgctl,
49036 + gotgctl.d32);
49037 + } else {
49038 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
49039 + return;
49040 + }
49041 + break;
49042 +
49043 + case UF_DEVICE_A_HNP_SUPPORT:
49044 + /* RH port supports HNP */
49045 + DWC_DEBUGPL(DBG_PCDV,
49046 + "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n");
49047 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
49048 + pcd->a_hnp_support = 1;
49049 + dwc_otg_pcd_update_otg(pcd, 0);
49050 + } else {
49051 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
49052 + return;
49053 + }
49054 + break;
49055 +
49056 + case UF_DEVICE_A_ALT_HNP_SUPPORT:
49057 + /* other RH port does */
49058 + DWC_DEBUGPL(DBG_PCDV,
49059 + "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
49060 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
49061 + pcd->a_alt_hnp_support = 1;
49062 + dwc_otg_pcd_update_otg(pcd, 0);
49063 + } else {
49064 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
49065 + return;
49066 + }
49067 + break;
49068 +
49069 + default:
49070 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
49071 + return;
49072 +
49073 + }
49074 + do_setup_in_status_phase(pcd);
49075 + break;
49076 +
49077 + case UT_INTERFACE:
49078 + do_gadget_setup(pcd, &ctrl);
49079 + break;
49080 +
49081 + case UT_ENDPOINT:
49082 + if (UGETW(ctrl.wValue) == UF_ENDPOINT_HALT) {
49083 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
49084 + if (ep == 0) {
49085 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
49086 + return;
49087 + }
49088 + ep->stopped = 1;
49089 + dwc_otg_ep_set_stall(core_if, &ep->dwc_ep);
49090 + }
49091 + do_setup_in_status_phase(pcd);
49092 + break;
49093 + }
49094 +}
49095 +
49096 +/**
49097 + * This function process the CLEAR_FEATURE Setup Commands.
49098 + */
49099 +static inline void do_clear_feature(dwc_otg_pcd_t * pcd)
49100 +{
49101 + usb_device_request_t ctrl = pcd->setup_pkt->req;
49102 + dwc_otg_pcd_ep_t *ep = 0;
49103 +
49104 + DWC_DEBUGPL(DBG_PCD,
49105 + "CLEAR_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
49106 + ctrl.bmRequestType, ctrl.bRequest,
49107 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
49108 + UGETW(ctrl.wLength));
49109 +
49110 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
49111 + case UT_DEVICE:
49112 + switch (UGETW(ctrl.wValue)) {
49113 + case UF_DEVICE_REMOTE_WAKEUP:
49114 + pcd->remote_wakeup_enable = 0;
49115 + break;
49116 +
49117 + case UF_TEST_MODE:
49118 + /** @todo Add CLEAR_FEATURE for TEST modes. */
49119 + break;
49120 +
49121 + default:
49122 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
49123 + return;
49124 + }
49125 + do_setup_in_status_phase(pcd);
49126 + break;
49127 +
49128 + case UT_ENDPOINT:
49129 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
49130 + if (ep == 0) {
49131 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
49132 + return;
49133 + }
49134 +
49135 + pcd_clear_halt(pcd, ep);
49136 +
49137 + break;
49138 + }
49139 +}
49140 +
49141 +/**
49142 + * This function process the SET_ADDRESS Setup Commands.
49143 + */
49144 +static inline void do_set_address(dwc_otg_pcd_t * pcd)
49145 +{
49146 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
49147 + usb_device_request_t ctrl = pcd->setup_pkt->req;
49148 +
49149 + if (ctrl.bmRequestType == UT_DEVICE) {
49150 + dcfg_data_t dcfg = {.d32 = 0 };
49151 +
49152 +#ifdef DEBUG_EP0
49153 +// DWC_DEBUGPL(DBG_PCDV, "SET_ADDRESS:%d\n", ctrl.wValue);
49154 +#endif
49155 + dcfg.b.devaddr = UGETW(ctrl.wValue);
49156 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dcfg, 0, dcfg.d32);
49157 + do_setup_in_status_phase(pcd);
49158 + }
49159 +}
49160 +
49161 +/**
49162 + * This function processes SETUP commands. In Linux, the USB Command
49163 + * processing is done in two places - the first being the PCD and the
49164 + * second in the Gadget Driver (for example, the File-Backed Storage
49165 + * Gadget Driver).
49166 + *
49167 + * <table>
49168 + * <tr><td>Command </td><td>Driver </td><td>Description</td></tr>
49169 + *
49170 + * <tr><td>GET_STATUS </td><td>PCD </td><td>Command is processed as
49171 + * defined in chapter 9 of the USB 2.0 Specification chapter 9
49172 + * </td></tr>
49173 + *
49174 + * <tr><td>CLEAR_FEATURE </td><td>PCD </td><td>The Device and Endpoint
49175 + * requests are the ENDPOINT_HALT feature is procesed, all others the
49176 + * interface requests are ignored.</td></tr>
49177 + *
49178 + * <tr><td>SET_FEATURE </td><td>PCD </td><td>The Device and Endpoint
49179 + * requests are processed by the PCD. Interface requests are passed
49180 + * to the Gadget Driver.</td></tr>
49181 + *
49182 + * <tr><td>SET_ADDRESS </td><td>PCD </td><td>Program the DCFG reg,
49183 + * with device address received </td></tr>
49184 + *
49185 + * <tr><td>GET_DESCRIPTOR </td><td>Gadget Driver </td><td>Return the
49186 + * requested descriptor</td></tr>
49187 + *
49188 + * <tr><td>SET_DESCRIPTOR </td><td>Gadget Driver </td><td>Optional -
49189 + * not implemented by any of the existing Gadget Drivers.</td></tr>
49190 + *
49191 + * <tr><td>SET_CONFIGURATION </td><td>Gadget Driver </td><td>Disable
49192 + * all EPs and enable EPs for new configuration.</td></tr>
49193 + *
49194 + * <tr><td>GET_CONFIGURATION </td><td>Gadget Driver </td><td>Return
49195 + * the current configuration</td></tr>
49196 + *
49197 + * <tr><td>SET_INTERFACE </td><td>Gadget Driver </td><td>Disable all
49198 + * EPs and enable EPs for new configuration.</td></tr>
49199 + *
49200 + * <tr><td>GET_INTERFACE </td><td>Gadget Driver </td><td>Return the
49201 + * current interface.</td></tr>
49202 + *
49203 + * <tr><td>SYNC_FRAME </td><td>PCD </td><td>Display debug
49204 + * message.</td></tr>
49205 + * </table>
49206 + *
49207 + * When the SETUP Phase Done interrupt occurs, the PCD SETUP commands are
49208 + * processed by pcd_setup. Calling the Function Driver's setup function from
49209 + * pcd_setup processes the gadget SETUP commands.
49210 + */
49211 +static inline void pcd_setup(dwc_otg_pcd_t * pcd)
49212 +{
49213 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
49214 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
49215 + usb_device_request_t ctrl = pcd->setup_pkt->req;
49216 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
49217 +
49218 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
49219 +
49220 +#ifdef DWC_UTE_CFI
49221 + int retval = 0;
49222 + struct cfi_usb_ctrlrequest cfi_req;
49223 +#endif
49224 +
49225 + doeptsize0.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doeptsiz);
49226 +
49227 + /** In BDMA more then 1 setup packet is not supported till 3.00a */
49228 + if (core_if->dma_enable && core_if->dma_desc_enable == 0
49229 + && (doeptsize0.b.supcnt < 2)
49230 + && (core_if->snpsid < OTG_CORE_REV_2_94a)) {
49231 + DWC_ERROR
49232 + ("\n\n----------- CANNOT handle > 1 setup packet in DMA mode\n\n");
49233 + }
49234 + if ((core_if->snpsid >= OTG_CORE_REV_3_00a)
49235 + && (core_if->dma_enable == 1) && (core_if->dma_desc_enable == 0)) {
49236 + ctrl =
49237 + (pcd->setup_pkt +
49238 + (3 - doeptsize0.b.supcnt - 1 +
49239 + ep0->dwc_ep.stp_rollover))->req;
49240 + }
49241 +#ifdef DEBUG_EP0
49242 + DWC_DEBUGPL(DBG_PCD, "SETUP %02x.%02x v%04x i%04x l%04x\n",
49243 + ctrl.bmRequestType, ctrl.bRequest,
49244 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
49245 + UGETW(ctrl.wLength));
49246 +#endif
49247 +
49248 + /* Clean up the request queue */
49249 + dwc_otg_request_nuke(ep0);
49250 + ep0->stopped = 0;
49251 +
49252 + if (ctrl.bmRequestType & UE_DIR_IN) {
49253 + ep0->dwc_ep.is_in = 1;
49254 + pcd->ep0state = EP0_IN_DATA_PHASE;
49255 + } else {
49256 + ep0->dwc_ep.is_in = 0;
49257 + pcd->ep0state = EP0_OUT_DATA_PHASE;
49258 + }
49259 +
49260 + if (UGETW(ctrl.wLength) == 0) {
49261 + ep0->dwc_ep.is_in = 1;
49262 + pcd->ep0state = EP0_IN_STATUS_PHASE;
49263 + }
49264 +
49265 + if (UT_GET_TYPE(ctrl.bmRequestType) != UT_STANDARD) {
49266 +
49267 +#ifdef DWC_UTE_CFI
49268 + DWC_MEMCPY(&cfi_req, &ctrl, sizeof(usb_device_request_t));
49269 +
49270 + //printk(KERN_ALERT "CFI: req_type=0x%02x; req=0x%02x\n",
49271 + ctrl.bRequestType, ctrl.bRequest);
49272 + if (UT_GET_TYPE(cfi_req.bRequestType) == UT_VENDOR) {
49273 + if (cfi_req.bRequest > 0xB0 && cfi_req.bRequest < 0xBF) {
49274 + retval = cfi_setup(pcd, &cfi_req);
49275 + if (retval < 0) {
49276 + ep0_do_stall(pcd, retval);
49277 + pcd->ep0_pending = 0;
49278 + return;
49279 + }
49280 +
49281 + /* if need gadget setup then call it and check the retval */
49282 + if (pcd->cfi->need_gadget_att) {
49283 + retval =
49284 + cfi_gadget_setup(pcd,
49285 + &pcd->
49286 + cfi->ctrl_req);
49287 + if (retval < 0) {
49288 + pcd->ep0_pending = 0;
49289 + return;
49290 + }
49291 + }
49292 +
49293 + if (pcd->cfi->need_status_in_complete) {
49294 + do_setup_in_status_phase(pcd);
49295 + }
49296 + return;
49297 + }
49298 + }
49299 +#endif
49300 +
49301 + /* handle non-standard (class/vendor) requests in the gadget driver */
49302 + do_gadget_setup(pcd, &ctrl);
49303 + return;
49304 + }
49305 +
49306 + /** @todo NGS: Handle bad setup packet? */
49307 +
49308 +///////////////////////////////////////////
49309 +//// --- Standard Request handling --- ////
49310 +
49311 + switch (ctrl.bRequest) {
49312 + case UR_GET_STATUS:
49313 + do_get_status(pcd);
49314 + break;
49315 +
49316 + case UR_CLEAR_FEATURE:
49317 + do_clear_feature(pcd);
49318 + break;
49319 +
49320 + case UR_SET_FEATURE:
49321 + do_set_feature(pcd);
49322 + break;
49323 +
49324 + case UR_SET_ADDRESS:
49325 + do_set_address(pcd);
49326 + break;
49327 +
49328 + case UR_SET_INTERFACE:
49329 + case UR_SET_CONFIG:
49330 +// _pcd->request_config = 1; /* Configuration changed */
49331 + do_gadget_setup(pcd, &ctrl);
49332 + break;
49333 +
49334 + case UR_SYNCH_FRAME:
49335 + do_gadget_setup(pcd, &ctrl);
49336 + break;
49337 +
49338 + default:
49339 + /* Call the Gadget Driver's setup functions */
49340 + do_gadget_setup(pcd, &ctrl);
49341 + break;
49342 + }
49343 +}
49344 +
49345 +/**
49346 + * This function completes the ep0 control transfer.
49347 + */
49348 +static int32_t ep0_complete_request(dwc_otg_pcd_ep_t * ep)
49349 +{
49350 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
49351 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
49352 + dwc_otg_dev_in_ep_regs_t *in_ep_regs =
49353 + dev_if->in_ep_regs[ep->dwc_ep.num];
49354 +#ifdef DEBUG_EP0
49355 + dwc_otg_dev_out_ep_regs_t *out_ep_regs =
49356 + dev_if->out_ep_regs[ep->dwc_ep.num];
49357 +#endif
49358 + deptsiz0_data_t deptsiz;
49359 + dev_dma_desc_sts_t desc_sts;
49360 + dwc_otg_pcd_request_t *req;
49361 + int is_last = 0;
49362 + dwc_otg_pcd_t *pcd = ep->pcd;
49363 +
49364 +#ifdef DWC_UTE_CFI
49365 + struct cfi_usb_ctrlrequest *ctrlreq;
49366 + int retval = -DWC_E_NOT_SUPPORTED;
49367 +#endif
49368 +
49369 + desc_sts.b.bytes = 0;
49370 +
49371 + if (pcd->ep0_pending && DWC_CIRCLEQ_EMPTY(&ep->queue)) {
49372 + if (ep->dwc_ep.is_in) {
49373 +#ifdef DEBUG_EP0
49374 + DWC_DEBUGPL(DBG_PCDV, "Do setup OUT status phase\n");
49375 +#endif
49376 + do_setup_out_status_phase(pcd);
49377 + } else {
49378 +#ifdef DEBUG_EP0
49379 + DWC_DEBUGPL(DBG_PCDV, "Do setup IN status phase\n");
49380 +#endif
49381 +
49382 +#ifdef DWC_UTE_CFI
49383 + ctrlreq = &pcd->cfi->ctrl_req;
49384 +
49385 + if (UT_GET_TYPE(ctrlreq->bRequestType) == UT_VENDOR) {
49386 + if (ctrlreq->bRequest > 0xB0
49387 + && ctrlreq->bRequest < 0xBF) {
49388 +
49389 + /* Return if the PCD failed to handle the request */
49390 + if ((retval =
49391 + pcd->cfi->ops.
49392 + ctrl_write_complete(pcd->cfi,
49393 + pcd)) < 0) {
49394 + CFI_INFO
49395 + ("ERROR setting a new value in the PCD(%d)\n",
49396 + retval);
49397 + ep0_do_stall(pcd, retval);
49398 + pcd->ep0_pending = 0;
49399 + return 0;
49400 + }
49401 +
49402 + /* If the gadget needs to be notified on the request */
49403 + if (pcd->cfi->need_gadget_att == 1) {
49404 + //retval = do_gadget_setup(pcd, &pcd->cfi->ctrl_req);
49405 + retval =
49406 + cfi_gadget_setup(pcd,
49407 + &pcd->cfi->
49408 + ctrl_req);
49409 +
49410 + /* Return from the function if the gadget failed to process
49411 + * the request properly - this should never happen !!!
49412 + */
49413 + if (retval < 0) {
49414 + CFI_INFO
49415 + ("ERROR setting a new value in the gadget(%d)\n",
49416 + retval);
49417 + pcd->ep0_pending = 0;
49418 + return 0;
49419 + }
49420 + }
49421 +
49422 + CFI_INFO("%s: RETVAL=%d\n", __func__,
49423 + retval);
49424 + /* If we hit here then the PCD and the gadget has properly
49425 + * handled the request - so send the ZLP IN to the host.
49426 + */
49427 + /* @todo: MAS - decide whether we need to start the setup
49428 + * stage based on the need_setup value of the cfi object
49429 + */
49430 + do_setup_in_status_phase(pcd);
49431 + pcd->ep0_pending = 0;
49432 + return 1;
49433 + }
49434 + }
49435 +#endif
49436 +
49437 + do_setup_in_status_phase(pcd);
49438 + }
49439 + pcd->ep0_pending = 0;
49440 + return 1;
49441 + }
49442 +
49443 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
49444 + return 0;
49445 + }
49446 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
49447 +
49448 + if (pcd->ep0state == EP0_OUT_STATUS_PHASE
49449 + || pcd->ep0state == EP0_IN_STATUS_PHASE) {
49450 + is_last = 1;
49451 + } else if (ep->dwc_ep.is_in) {
49452 + deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
49453 + if (core_if->dma_desc_enable != 0)
49454 + desc_sts = dev_if->in_desc_addr->status;
49455 +#ifdef DEBUG_EP0
49456 + DWC_DEBUGPL(DBG_PCDV, "%d len=%d xfersize=%d pktcnt=%d\n",
49457 + ep->dwc_ep.num, ep->dwc_ep.xfer_len,
49458 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49459 +#endif
49460 +
49461 + if (((core_if->dma_desc_enable == 0)
49462 + && (deptsiz.b.xfersize == 0))
49463 + || ((core_if->dma_desc_enable != 0)
49464 + && (desc_sts.b.bytes == 0))) {
49465 + req->actual = ep->dwc_ep.xfer_count;
49466 + /* Is a Zero Len Packet needed? */
49467 + if (req->sent_zlp) {
49468 +#ifdef DEBUG_EP0
49469 + DWC_DEBUGPL(DBG_PCD, "Setup Rx ZLP\n");
49470 +#endif
49471 + req->sent_zlp = 0;
49472 + }
49473 + do_setup_out_status_phase(pcd);
49474 + }
49475 + } else {
49476 + /* ep0-OUT */
49477 +#ifdef DEBUG_EP0
49478 + deptsiz.d32 = DWC_READ_REG32(&out_ep_regs->doeptsiz);
49479 + DWC_DEBUGPL(DBG_PCDV, "%d len=%d xsize=%d pktcnt=%d\n",
49480 + ep->dwc_ep.num, ep->dwc_ep.xfer_len,
49481 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49482 +#endif
49483 + req->actual = ep->dwc_ep.xfer_count;
49484 +
49485 + /* Is a Zero Len Packet needed? */
49486 + if (req->sent_zlp) {
49487 +#ifdef DEBUG_EP0
49488 + DWC_DEBUGPL(DBG_PCDV, "Setup Tx ZLP\n");
49489 +#endif
49490 + req->sent_zlp = 0;
49491 + }
49492 + /* For older cores do setup in status phase in Slave/BDMA modes,
49493 + * starting from 3.00 do that only in slave, and for DMA modes
49494 + * just re-enable ep 0 OUT here*/
49495 + if (core_if->dma_enable == 0
49496 + || (core_if->dma_desc_enable == 0
49497 + && core_if->snpsid <= OTG_CORE_REV_2_94a)) {
49498 + do_setup_in_status_phase(pcd);
49499 + } else if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
49500 + DWC_DEBUGPL(DBG_PCDV,
49501 + "Enable out ep before in status phase\n");
49502 + ep0_out_start(core_if, pcd);
49503 + }
49504 + }
49505 +
49506 + /* Complete the request */
49507 + if (is_last) {
49508 + dwc_otg_request_done(ep, req, 0);
49509 + ep->dwc_ep.start_xfer_buff = 0;
49510 + ep->dwc_ep.xfer_buff = 0;
49511 + ep->dwc_ep.xfer_len = 0;
49512 + return 1;
49513 + }
49514 + return 0;
49515 +}
49516 +
49517 +#ifdef DWC_UTE_CFI
49518 +/**
49519 + * This function calculates traverses all the CFI DMA descriptors and
49520 + * and accumulates the bytes that are left to be transfered.
49521 + *
49522 + * @return The total bytes left to transfered, or a negative value as failure
49523 + */
49524 +static inline int cfi_calc_desc_residue(dwc_otg_pcd_ep_t * ep)
49525 +{
49526 + int32_t ret = 0;
49527 + int i;
49528 + struct dwc_otg_dma_desc *ddesc = NULL;
49529 + struct cfi_ep *cfiep;
49530 +
49531 + /* See if the pcd_ep has its respective cfi_ep mapped */
49532 + cfiep = get_cfi_ep_by_pcd_ep(ep->pcd->cfi, ep);
49533 + if (!cfiep) {
49534 + CFI_INFO("%s: Failed to find ep\n", __func__);
49535 + return -1;
49536 + }
49537 +
49538 + ddesc = ep->dwc_ep.descs;
49539 +
49540 + for (i = 0; (i < cfiep->desc_count) && (i < MAX_DMA_DESCS_PER_EP); i++) {
49541 +
49542 +#if defined(PRINT_CFI_DMA_DESCS)
49543 + print_desc(ddesc, ep->ep.name, i);
49544 +#endif
49545 + ret += ddesc->status.b.bytes;
49546 + ddesc++;
49547 + }
49548 +
49549 + if (ret)
49550 + CFI_INFO("!!!!!!!!!! WARNING (%s) - residue=%d\n", __func__,
49551 + ret);
49552 +
49553 + return ret;
49554 +}
49555 +#endif
49556 +
49557 +/**
49558 + * This function completes the request for the EP. If there are
49559 + * additional requests for the EP in the queue they will be started.
49560 + */
49561 +static void complete_ep(dwc_otg_pcd_ep_t * ep)
49562 +{
49563 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
49564 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
49565 + dwc_otg_dev_in_ep_regs_t *in_ep_regs =
49566 + dev_if->in_ep_regs[ep->dwc_ep.num];
49567 + deptsiz_data_t deptsiz;
49568 + dev_dma_desc_sts_t desc_sts;
49569 + dwc_otg_pcd_request_t *req = 0;
49570 + dwc_otg_dev_dma_desc_t *dma_desc;
49571 + uint32_t byte_count = 0;
49572 + int is_last = 0;
49573 + int i;
49574 +
49575 + DWC_DEBUGPL(DBG_PCDV, "%s() %d-%s\n", __func__, ep->dwc_ep.num,
49576 + (ep->dwc_ep.is_in ? "IN" : "OUT"));
49577 +
49578 + /* Get any pending requests */
49579 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
49580 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
49581 + if (!req) {
49582 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
49583 + return;
49584 + }
49585 + } else {
49586 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
49587 + return;
49588 + }
49589 +
49590 + DWC_DEBUGPL(DBG_PCD, "Requests %d\n", ep->pcd->request_pending);
49591 +
49592 + if (ep->dwc_ep.is_in) {
49593 + deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
49594 +
49595 + if (core_if->dma_enable) {
49596 + if (core_if->dma_desc_enable == 0) {
49597 + if (deptsiz.b.xfersize == 0
49598 + && deptsiz.b.pktcnt == 0) {
49599 + byte_count =
49600 + ep->dwc_ep.xfer_len -
49601 + ep->dwc_ep.xfer_count;
49602 +
49603 + ep->dwc_ep.xfer_buff += byte_count;
49604 + ep->dwc_ep.dma_addr += byte_count;
49605 + ep->dwc_ep.xfer_count += byte_count;
49606 +
49607 + DWC_DEBUGPL(DBG_PCDV,
49608 + "%d-%s len=%d xfersize=%d pktcnt=%d\n",
49609 + ep->dwc_ep.num,
49610 + (ep->dwc_ep.
49611 + is_in ? "IN" : "OUT"),
49612 + ep->dwc_ep.xfer_len,
49613 + deptsiz.b.xfersize,
49614 + deptsiz.b.pktcnt);
49615 +
49616 + if (ep->dwc_ep.xfer_len <
49617 + ep->dwc_ep.total_len) {
49618 + dwc_otg_ep_start_transfer
49619 + (core_if, &ep->dwc_ep);
49620 + } else if (ep->dwc_ep.sent_zlp) {
49621 + /*
49622 + * This fragment of code should initiate 0
49623 + * length transfer in case if it is queued
49624 + * a transfer with size divisible to EPs max
49625 + * packet size and with usb_request zero field
49626 + * is set, which means that after data is transfered,
49627 + * it is also should be transfered
49628 + * a 0 length packet at the end. For Slave and
49629 + * Buffer DMA modes in this case SW has
49630 + * to initiate 2 transfers one with transfer size,
49631 + * and the second with 0 size. For Descriptor
49632 + * DMA mode SW is able to initiate a transfer,
49633 + * which will handle all the packets including
49634 + * the last 0 length.
49635 + */
49636 + ep->dwc_ep.sent_zlp = 0;
49637 + dwc_otg_ep_start_zl_transfer
49638 + (core_if, &ep->dwc_ep);
49639 + } else {
49640 + is_last = 1;
49641 + }
49642 + } else {
49643 + if (ep->dwc_ep.type ==
49644 + DWC_OTG_EP_TYPE_ISOC) {
49645 + req->actual = 0;
49646 + dwc_otg_request_done(ep, req, 0);
49647 +
49648 + ep->dwc_ep.start_xfer_buff = 0;
49649 + ep->dwc_ep.xfer_buff = 0;
49650 + ep->dwc_ep.xfer_len = 0;
49651 +
49652 + /* If there is a request in the queue start it. */
49653 + start_next_request(ep);
49654 + } else
49655 + DWC_WARN
49656 + ("Incomplete transfer (%d - %s [siz=%d pkt=%d])\n",
49657 + ep->dwc_ep.num,
49658 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
49659 + deptsiz.b.xfersize,
49660 + deptsiz.b.pktcnt);
49661 + }
49662 + } else {
49663 + dma_desc = ep->dwc_ep.desc_addr;
49664 + byte_count = 0;
49665 + ep->dwc_ep.sent_zlp = 0;
49666 +
49667 +#ifdef DWC_UTE_CFI
49668 + CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
49669 + ep->dwc_ep.buff_mode);
49670 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
49671 + int residue;
49672 +
49673 + residue = cfi_calc_desc_residue(ep);
49674 + if (residue < 0)
49675 + return;
49676 +
49677 + byte_count = residue;
49678 + } else {
49679 +#endif
49680 + for (i = 0; i < ep->dwc_ep.desc_cnt;
49681 + ++i) {
49682 + desc_sts = dma_desc->status;
49683 + byte_count += desc_sts.b.bytes;
49684 + dma_desc++;
49685 + }
49686 +#ifdef DWC_UTE_CFI
49687 + }
49688 +#endif
49689 + if (byte_count == 0) {
49690 + ep->dwc_ep.xfer_count =
49691 + ep->dwc_ep.total_len;
49692 + is_last = 1;
49693 + } else {
49694 + DWC_WARN("Incomplete transfer\n");
49695 + }
49696 + }
49697 + } else {
49698 + if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0) {
49699 + DWC_DEBUGPL(DBG_PCDV,
49700 + "%d-%s len=%d xfersize=%d pktcnt=%d\n",
49701 + ep->dwc_ep.num,
49702 + ep->dwc_ep.is_in ? "IN" : "OUT",
49703 + ep->dwc_ep.xfer_len,
49704 + deptsiz.b.xfersize,
49705 + deptsiz.b.pktcnt);
49706 +
49707 + /* Check if the whole transfer was completed,
49708 + * if no, setup transfer for next portion of data
49709 + */
49710 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
49711 + dwc_otg_ep_start_transfer(core_if,
49712 + &ep->dwc_ep);
49713 + } else if (ep->dwc_ep.sent_zlp) {
49714 + /*
49715 + * This fragment of code should initiate 0
49716 + * length trasfer in case if it is queued
49717 + * a trasfer with size divisible to EPs max
49718 + * packet size and with usb_request zero field
49719 + * is set, which means that after data is transfered,
49720 + * it is also should be transfered
49721 + * a 0 length packet at the end. For Slave and
49722 + * Buffer DMA modes in this case SW has
49723 + * to initiate 2 transfers one with transfer size,
49724 + * and the second with 0 size. For Desriptor
49725 + * DMA mode SW is able to initiate a transfer,
49726 + * which will handle all the packets including
49727 + * the last 0 legth.
49728 + */
49729 + ep->dwc_ep.sent_zlp = 0;
49730 + dwc_otg_ep_start_zl_transfer(core_if,
49731 + &ep->dwc_ep);
49732 + } else {
49733 + is_last = 1;
49734 + }
49735 + } else {
49736 + DWC_WARN
49737 + ("Incomplete transfer (%d-%s [siz=%d pkt=%d])\n",
49738 + ep->dwc_ep.num,
49739 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
49740 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49741 + }
49742 + }
49743 + } else {
49744 + dwc_otg_dev_out_ep_regs_t *out_ep_regs =
49745 + dev_if->out_ep_regs[ep->dwc_ep.num];
49746 + desc_sts.d32 = 0;
49747 + if (core_if->dma_enable) {
49748 + if (core_if->dma_desc_enable) {
49749 + dma_desc = ep->dwc_ep.desc_addr;
49750 + byte_count = 0;
49751 + ep->dwc_ep.sent_zlp = 0;
49752 +
49753 +#ifdef DWC_UTE_CFI
49754 + CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
49755 + ep->dwc_ep.buff_mode);
49756 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
49757 + int residue;
49758 + residue = cfi_calc_desc_residue(ep);
49759 + if (residue < 0)
49760 + return;
49761 + byte_count = residue;
49762 + } else {
49763 +#endif
49764 +
49765 + for (i = 0; i < ep->dwc_ep.desc_cnt;
49766 + ++i) {
49767 + desc_sts = dma_desc->status;
49768 + byte_count += desc_sts.b.bytes;
49769 + dma_desc++;
49770 + }
49771 +
49772 +#ifdef DWC_UTE_CFI
49773 + }
49774 +#endif
49775 + /* Checking for interrupt Out transfers with not
49776 + * dword aligned mps sizes
49777 + */
49778 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_INTR &&
49779 + (ep->dwc_ep.maxpacket%4)) {
49780 + ep->dwc_ep.xfer_count =
49781 + ep->dwc_ep.total_len - byte_count;
49782 + if ((ep->dwc_ep.xfer_len %
49783 + ep->dwc_ep.maxpacket)
49784 + && (ep->dwc_ep.xfer_len /
49785 + ep->dwc_ep.maxpacket <
49786 + MAX_DMA_DESC_CNT))
49787 + ep->dwc_ep.xfer_len -=
49788 + (ep->dwc_ep.desc_cnt -
49789 + 1) * ep->dwc_ep.maxpacket +
49790 + ep->dwc_ep.xfer_len %
49791 + ep->dwc_ep.maxpacket;
49792 + else
49793 + ep->dwc_ep.xfer_len -=
49794 + ep->dwc_ep.desc_cnt *
49795 + ep->dwc_ep.maxpacket;
49796 + if (ep->dwc_ep.xfer_len > 0) {
49797 + dwc_otg_ep_start_transfer
49798 + (core_if, &ep->dwc_ep);
49799 + } else {
49800 + is_last = 1;
49801 + }
49802 + } else {
49803 + ep->dwc_ep.xfer_count =
49804 + ep->dwc_ep.total_len - byte_count +
49805 + ((4 -
49806 + (ep->dwc_ep.
49807 + total_len & 0x3)) & 0x3);
49808 + is_last = 1;
49809 + }
49810 + } else {
49811 + deptsiz.d32 = 0;
49812 + deptsiz.d32 =
49813 + DWC_READ_REG32(&out_ep_regs->doeptsiz);
49814 +
49815 + byte_count = (ep->dwc_ep.xfer_len -
49816 + ep->dwc_ep.xfer_count -
49817 + deptsiz.b.xfersize);
49818 + ep->dwc_ep.xfer_buff += byte_count;
49819 + ep->dwc_ep.dma_addr += byte_count;
49820 + ep->dwc_ep.xfer_count += byte_count;
49821 +
49822 + /* Check if the whole transfer was completed,
49823 + * if no, setup transfer for next portion of data
49824 + */
49825 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
49826 + dwc_otg_ep_start_transfer(core_if,
49827 + &ep->dwc_ep);
49828 + } else if (ep->dwc_ep.sent_zlp) {
49829 + /*
49830 + * This fragment of code should initiate 0
49831 + * length trasfer in case if it is queued
49832 + * a trasfer with size divisible to EPs max
49833 + * packet size and with usb_request zero field
49834 + * is set, which means that after data is transfered,
49835 + * it is also should be transfered
49836 + * a 0 length packet at the end. For Slave and
49837 + * Buffer DMA modes in this case SW has
49838 + * to initiate 2 transfers one with transfer size,
49839 + * and the second with 0 size. For Desriptor
49840 + * DMA mode SW is able to initiate a transfer,
49841 + * which will handle all the packets including
49842 + * the last 0 legth.
49843 + */
49844 + ep->dwc_ep.sent_zlp = 0;
49845 + dwc_otg_ep_start_zl_transfer(core_if,
49846 + &ep->dwc_ep);
49847 + } else {
49848 + is_last = 1;
49849 + }
49850 + }
49851 + } else {
49852 + /* Check if the whole transfer was completed,
49853 + * if no, setup transfer for next portion of data
49854 + */
49855 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
49856 + dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
49857 + } else if (ep->dwc_ep.sent_zlp) {
49858 + /*
49859 + * This fragment of code should initiate 0
49860 + * length transfer in case if it is queued
49861 + * a transfer with size divisible to EPs max
49862 + * packet size and with usb_request zero field
49863 + * is set, which means that after data is transfered,
49864 + * it is also should be transfered
49865 + * a 0 length packet at the end. For Slave and
49866 + * Buffer DMA modes in this case SW has
49867 + * to initiate 2 transfers one with transfer size,
49868 + * and the second with 0 size. For Descriptor
49869 + * DMA mode SW is able to initiate a transfer,
49870 + * which will handle all the packets including
49871 + * the last 0 length.
49872 + */
49873 + ep->dwc_ep.sent_zlp = 0;
49874 + dwc_otg_ep_start_zl_transfer(core_if,
49875 + &ep->dwc_ep);
49876 + } else {
49877 + is_last = 1;
49878 + }
49879 + }
49880 +
49881 + DWC_DEBUGPL(DBG_PCDV,
49882 + "addr %p, %d-%s len=%d cnt=%d xsize=%d pktcnt=%d\n",
49883 + &out_ep_regs->doeptsiz, ep->dwc_ep.num,
49884 + ep->dwc_ep.is_in ? "IN" : "OUT",
49885 + ep->dwc_ep.xfer_len, ep->dwc_ep.xfer_count,
49886 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49887 + }
49888 +
49889 + /* Complete the request */
49890 + if (is_last) {
49891 +#ifdef DWC_UTE_CFI
49892 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
49893 + req->actual = ep->dwc_ep.cfi_req_len - byte_count;
49894 + } else {
49895 +#endif
49896 + req->actual = ep->dwc_ep.xfer_count;
49897 +#ifdef DWC_UTE_CFI
49898 + }
49899 +#endif
49900 + if (req->dw_align_buf) {
49901 + if (!ep->dwc_ep.is_in) {
49902 + dwc_memcpy(req->buf, req->dw_align_buf, req->length);
49903 + }
49904 + DWC_DMA_FREE(req->length, req->dw_align_buf,
49905 + req->dw_align_buf_dma);
49906 + }
49907 +
49908 + dwc_otg_request_done(ep, req, 0);
49909 +
49910 + ep->dwc_ep.start_xfer_buff = 0;
49911 + ep->dwc_ep.xfer_buff = 0;
49912 + ep->dwc_ep.xfer_len = 0;
49913 +
49914 + /* If there is a request in the queue start it. */
49915 + start_next_request(ep);
49916 + }
49917 +}
49918 +
49919 +#ifdef DWC_EN_ISOC
49920 +
49921 +/**
49922 + * This function BNA interrupt for Isochronous EPs
49923 + *
49924 + */
49925 +static void dwc_otg_pcd_handle_iso_bna(dwc_otg_pcd_ep_t * ep)
49926 +{
49927 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
49928 + volatile uint32_t *addr;
49929 + depctl_data_t depctl = {.d32 = 0 };
49930 + dwc_otg_pcd_t *pcd = ep->pcd;
49931 + dwc_otg_dev_dma_desc_t *dma_desc;
49932 + int i;
49933 +
49934 + dma_desc =
49935 + dwc_ep->iso_desc_addr + dwc_ep->desc_cnt * (dwc_ep->proc_buf_num);
49936 +
49937 + if (dwc_ep->is_in) {
49938 + dev_dma_desc_sts_t sts = {.d32 = 0 };
49939 + for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
49940 + sts.d32 = dma_desc->status.d32;
49941 + sts.b_iso_in.bs = BS_HOST_READY;
49942 + dma_desc->status.d32 = sts.d32;
49943 + }
49944 + } else {
49945 + dev_dma_desc_sts_t sts = {.d32 = 0 };
49946 + for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
49947 + sts.d32 = dma_desc->status.d32;
49948 + sts.b_iso_out.bs = BS_HOST_READY;
49949 + dma_desc->status.d32 = sts.d32;
49950 + }
49951 + }
49952 +
49953 + if (dwc_ep->is_in == 0) {
49954 + addr =
49955 + &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->
49956 + num]->doepctl;
49957 + } else {
49958 + addr =
49959 + &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
49960 + }
49961 + depctl.b.epena = 1;
49962 + DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
49963 +}
49964 +
49965 +/**
49966 + * This function sets latest iso packet information(non-PTI mode)
49967 + *
49968 + * @param core_if Programming view of DWC_otg controller.
49969 + * @param ep The EP to start the transfer on.
49970 + *
49971 + */
49972 +void set_current_pkt_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
49973 +{
49974 + deptsiz_data_t deptsiz = {.d32 = 0 };
49975 + dma_addr_t dma_addr;
49976 + uint32_t offset;
49977 +
49978 + if (ep->proc_buf_num)
49979 + dma_addr = ep->dma_addr1;
49980 + else
49981 + dma_addr = ep->dma_addr0;
49982 +
49983 + if (ep->is_in) {
49984 + deptsiz.d32 =
49985 + DWC_READ_REG32(&core_if->dev_if->
49986 + in_ep_regs[ep->num]->dieptsiz);
49987 + offset = ep->data_per_frame;
49988 + } else {
49989 + deptsiz.d32 =
49990 + DWC_READ_REG32(&core_if->dev_if->
49991 + out_ep_regs[ep->num]->doeptsiz);
49992 + offset =
49993 + ep->data_per_frame +
49994 + (0x4 & (0x4 - (ep->data_per_frame & 0x3)));
49995 + }
49996 +
49997 + if (!deptsiz.b.xfersize) {
49998 + ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
49999 + ep->pkt_info[ep->cur_pkt].offset =
50000 + ep->cur_pkt_dma_addr - dma_addr;
50001 + ep->pkt_info[ep->cur_pkt].status = 0;
50002 + } else {
50003 + ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
50004 + ep->pkt_info[ep->cur_pkt].offset =
50005 + ep->cur_pkt_dma_addr - dma_addr;
50006 + ep->pkt_info[ep->cur_pkt].status = -DWC_E_NO_DATA;
50007 + }
50008 + ep->cur_pkt_addr += offset;
50009 + ep->cur_pkt_dma_addr += offset;
50010 + ep->cur_pkt++;
50011 +}
50012 +
50013 +/**
50014 + * This function sets latest iso packet information(DDMA mode)
50015 + *
50016 + * @param core_if Programming view of DWC_otg controller.
50017 + * @param dwc_ep The EP to start the transfer on.
50018 + *
50019 + */
50020 +static void set_ddma_iso_pkts_info(dwc_otg_core_if_t * core_if,
50021 + dwc_ep_t * dwc_ep)
50022 +{
50023 + dwc_otg_dev_dma_desc_t *dma_desc;
50024 + dev_dma_desc_sts_t sts = {.d32 = 0 };
50025 + iso_pkt_info_t *iso_packet;
50026 + uint32_t data_per_desc;
50027 + uint32_t offset;
50028 + int i, j;
50029 +
50030 + iso_packet = dwc_ep->pkt_info;
50031 +
50032 + /** Reinit closed DMA Descriptors*/
50033 + /** ISO OUT EP */
50034 + if (dwc_ep->is_in == 0) {
50035 + dma_desc =
50036 + dwc_ep->iso_desc_addr +
50037 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
50038 + offset = 0;
50039 +
50040 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
50041 + i += dwc_ep->pkt_per_frm) {
50042 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
50043 + data_per_desc =
50044 + ((j + 1) * dwc_ep->maxpacket >
50045 + dwc_ep->
50046 + data_per_frame) ? dwc_ep->data_per_frame -
50047 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
50048 + data_per_desc +=
50049 + (data_per_desc % 4) ? (4 -
50050 + data_per_desc %
50051 + 4) : 0;
50052 +
50053 + sts.d32 = dma_desc->status.d32;
50054 +
50055 + /* Write status in iso_packet_decsriptor */
50056 + iso_packet->status =
50057 + sts.b_iso_out.rxsts +
50058 + (sts.b_iso_out.bs ^ BS_DMA_DONE);
50059 + if (iso_packet->status) {
50060 + iso_packet->status = -DWC_E_NO_DATA;
50061 + }
50062 +
50063 + /* Received data length */
50064 + if (!sts.b_iso_out.rxbytes) {
50065 + iso_packet->length =
50066 + data_per_desc -
50067 + sts.b_iso_out.rxbytes;
50068 + } else {
50069 + iso_packet->length =
50070 + data_per_desc -
50071 + sts.b_iso_out.rxbytes + (4 -
50072 + dwc_ep->data_per_frame
50073 + % 4);
50074 + }
50075 +
50076 + iso_packet->offset = offset;
50077 +
50078 + offset += data_per_desc;
50079 + dma_desc++;
50080 + iso_packet++;
50081 + }
50082 + }
50083 +
50084 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
50085 + data_per_desc =
50086 + ((j + 1) * dwc_ep->maxpacket >
50087 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
50088 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
50089 + data_per_desc +=
50090 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
50091 +
50092 + sts.d32 = dma_desc->status.d32;
50093 +
50094 + /* Write status in iso_packet_decsriptor */
50095 + iso_packet->status =
50096 + sts.b_iso_out.rxsts +
50097 + (sts.b_iso_out.bs ^ BS_DMA_DONE);
50098 + if (iso_packet->status) {
50099 + iso_packet->status = -DWC_E_NO_DATA;
50100 + }
50101 +
50102 + /* Received data length */
50103 + iso_packet->length =
50104 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
50105 +
50106 + iso_packet->offset = offset;
50107 +
50108 + offset += data_per_desc;
50109 + iso_packet++;
50110 + dma_desc++;
50111 + }
50112 +
50113 + sts.d32 = dma_desc->status.d32;
50114 +
50115 + /* Write status in iso_packet_decsriptor */
50116 + iso_packet->status =
50117 + sts.b_iso_out.rxsts + (sts.b_iso_out.bs ^ BS_DMA_DONE);
50118 + if (iso_packet->status) {
50119 + iso_packet->status = -DWC_E_NO_DATA;
50120 + }
50121 + /* Received data length */
50122 + if (!sts.b_iso_out.rxbytes) {
50123 + iso_packet->length =
50124 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
50125 + } else {
50126 + iso_packet->length =
50127 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes +
50128 + (4 - dwc_ep->data_per_frame % 4);
50129 + }
50130 +
50131 + iso_packet->offset = offset;
50132 + } else {
50133 +/** ISO IN EP */
50134 +
50135 + dma_desc =
50136 + dwc_ep->iso_desc_addr +
50137 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
50138 +
50139 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
50140 + sts.d32 = dma_desc->status.d32;
50141 +
50142 + /* Write status in iso packet descriptor */
50143 + iso_packet->status =
50144 + sts.b_iso_in.txsts +
50145 + (sts.b_iso_in.bs ^ BS_DMA_DONE);
50146 + if (iso_packet->status != 0) {
50147 + iso_packet->status = -DWC_E_NO_DATA;
50148 +
50149 + }
50150 + /* Bytes has been transfered */
50151 + iso_packet->length =
50152 + dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
50153 +
50154 + dma_desc++;
50155 + iso_packet++;
50156 + }
50157 +
50158 + sts.d32 = dma_desc->status.d32;
50159 + while (sts.b_iso_in.bs == BS_DMA_BUSY) {
50160 + sts.d32 = dma_desc->status.d32;
50161 + }
50162 +
50163 + /* Write status in iso packet descriptor ??? do be done with ERROR codes */
50164 + iso_packet->status =
50165 + sts.b_iso_in.txsts + (sts.b_iso_in.bs ^ BS_DMA_DONE);
50166 + if (iso_packet->status != 0) {
50167 + iso_packet->status = -DWC_E_NO_DATA;
50168 + }
50169 +
50170 + /* Bytes has been transfered */
50171 + iso_packet->length =
50172 + dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
50173 + }
50174 +}
50175 +
50176 +/**
50177 + * This function reinitialize DMA Descriptors for Isochronous transfer
50178 + *
50179 + * @param core_if Programming view of DWC_otg controller.
50180 + * @param dwc_ep The EP to start the transfer on.
50181 + *
50182 + */
50183 +static void reinit_ddma_iso_xfer(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
50184 +{
50185 + int i, j;
50186 + dwc_otg_dev_dma_desc_t *dma_desc;
50187 + dma_addr_t dma_ad;
50188 + volatile uint32_t *addr;
50189 + dev_dma_desc_sts_t sts = {.d32 = 0 };
50190 + uint32_t data_per_desc;
50191 +
50192 + if (dwc_ep->is_in == 0) {
50193 + addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
50194 + } else {
50195 + addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
50196 + }
50197 +
50198 + if (dwc_ep->proc_buf_num == 0) {
50199 + /** Buffer 0 descriptors setup */
50200 + dma_ad = dwc_ep->dma_addr0;
50201 + } else {
50202 + /** Buffer 1 descriptors setup */
50203 + dma_ad = dwc_ep->dma_addr1;
50204 + }
50205 +
50206 + /** Reinit closed DMA Descriptors*/
50207 + /** ISO OUT EP */
50208 + if (dwc_ep->is_in == 0) {
50209 + dma_desc =
50210 + dwc_ep->iso_desc_addr +
50211 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
50212 +
50213 + sts.b_iso_out.bs = BS_HOST_READY;
50214 + sts.b_iso_out.rxsts = 0;
50215 + sts.b_iso_out.l = 0;
50216 + sts.b_iso_out.sp = 0;
50217 + sts.b_iso_out.ioc = 0;
50218 + sts.b_iso_out.pid = 0;
50219 + sts.b_iso_out.framenum = 0;
50220 +
50221 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
50222 + i += dwc_ep->pkt_per_frm) {
50223 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
50224 + data_per_desc =
50225 + ((j + 1) * dwc_ep->maxpacket >
50226 + dwc_ep->
50227 + data_per_frame) ? dwc_ep->data_per_frame -
50228 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
50229 + data_per_desc +=
50230 + (data_per_desc % 4) ? (4 -
50231 + data_per_desc %
50232 + 4) : 0;
50233 + sts.b_iso_out.rxbytes = data_per_desc;
50234 + dma_desc->buf = dma_ad;
50235 + dma_desc->status.d32 = sts.d32;
50236 +
50237 + dma_ad += data_per_desc;
50238 + dma_desc++;
50239 + }
50240 + }
50241 +
50242 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
50243 +
50244 + data_per_desc =
50245 + ((j + 1) * dwc_ep->maxpacket >
50246 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
50247 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
50248 + data_per_desc +=
50249 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
50250 + sts.b_iso_out.rxbytes = data_per_desc;
50251 +
50252 + dma_desc->buf = dma_ad;
50253 + dma_desc->status.d32 = sts.d32;
50254 +
50255 + dma_desc++;
50256 + dma_ad += data_per_desc;
50257 + }
50258 +
50259 + sts.b_iso_out.ioc = 1;
50260 + sts.b_iso_out.l = dwc_ep->proc_buf_num;
50261 +
50262 + data_per_desc =
50263 + ((j + 1) * dwc_ep->maxpacket >
50264 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
50265 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
50266 + data_per_desc +=
50267 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
50268 + sts.b_iso_out.rxbytes = data_per_desc;
50269 +
50270 + dma_desc->buf = dma_ad;
50271 + dma_desc->status.d32 = sts.d32;
50272 + } else {
50273 +/** ISO IN EP */
50274 +
50275 + dma_desc =
50276 + dwc_ep->iso_desc_addr +
50277 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
50278 +
50279 + sts.b_iso_in.bs = BS_HOST_READY;
50280 + sts.b_iso_in.txsts = 0;
50281 + sts.b_iso_in.sp = 0;
50282 + sts.b_iso_in.ioc = 0;
50283 + sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
50284 + sts.b_iso_in.framenum = dwc_ep->next_frame;
50285 + sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
50286 + sts.b_iso_in.l = 0;
50287 +
50288 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
50289 + dma_desc->buf = dma_ad;
50290 + dma_desc->status.d32 = sts.d32;
50291 +
50292 + sts.b_iso_in.framenum += dwc_ep->bInterval;
50293 + dma_ad += dwc_ep->data_per_frame;
50294 + dma_desc++;
50295 + }
50296 +
50297 + sts.b_iso_in.ioc = 1;
50298 + sts.b_iso_in.l = dwc_ep->proc_buf_num;
50299 +
50300 + dma_desc->buf = dma_ad;
50301 + dma_desc->status.d32 = sts.d32;
50302 +
50303 + dwc_ep->next_frame =
50304 + sts.b_iso_in.framenum + dwc_ep->bInterval * 1;
50305 + }
50306 + dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
50307 +}
50308 +
50309 +/**
50310 + * This function is to handle Iso EP transfer complete interrupt
50311 + * in case Iso out packet was dropped
50312 + *
50313 + * @param core_if Programming view of DWC_otg controller.
50314 + * @param dwc_ep The EP for wihich transfer complete was asserted
50315 + *
50316 + */
50317 +static uint32_t handle_iso_out_pkt_dropped(dwc_otg_core_if_t * core_if,
50318 + dwc_ep_t * dwc_ep)
50319 +{
50320 + uint32_t dma_addr;
50321 + uint32_t drp_pkt;
50322 + uint32_t drp_pkt_cnt;
50323 + deptsiz_data_t deptsiz = {.d32 = 0 };
50324 + depctl_data_t depctl = {.d32 = 0 };
50325 + int i;
50326 +
50327 + deptsiz.d32 =
50328 + DWC_READ_REG32(&core_if->dev_if->
50329 + out_ep_regs[dwc_ep->num]->doeptsiz);
50330 +
50331 + drp_pkt = dwc_ep->pkt_cnt - deptsiz.b.pktcnt;
50332 + drp_pkt_cnt = dwc_ep->pkt_per_frm - (drp_pkt % dwc_ep->pkt_per_frm);
50333 +
50334 + /* Setting dropped packets status */
50335 + for (i = 0; i < drp_pkt_cnt; ++i) {
50336 + dwc_ep->pkt_info[drp_pkt].status = -DWC_E_NO_DATA;
50337 + drp_pkt++;
50338 + deptsiz.b.pktcnt--;
50339 + }
50340 +
50341 + if (deptsiz.b.pktcnt > 0) {
50342 + deptsiz.b.xfersize =
50343 + dwc_ep->xfer_len - (dwc_ep->pkt_cnt -
50344 + deptsiz.b.pktcnt) * dwc_ep->maxpacket;
50345 + } else {
50346 + deptsiz.b.xfersize = 0;
50347 + deptsiz.b.pktcnt = 0;
50348 + }
50349 +
50350 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz,
50351 + deptsiz.d32);
50352 +
50353 + if (deptsiz.b.pktcnt > 0) {
50354 + if (dwc_ep->proc_buf_num) {
50355 + dma_addr =
50356 + dwc_ep->dma_addr1 + dwc_ep->xfer_len -
50357 + deptsiz.b.xfersize;
50358 + } else {
50359 + dma_addr =
50360 + dwc_ep->dma_addr0 + dwc_ep->xfer_len -
50361 + deptsiz.b.xfersize;;
50362 + }
50363 +
50364 + DWC_WRITE_REG32(&core_if->dev_if->
50365 + out_ep_regs[dwc_ep->num]->doepdma, dma_addr);
50366 +
50367 + /** Re-enable endpoint, clear nak */
50368 + depctl.d32 = 0;
50369 + depctl.b.epena = 1;
50370 + depctl.b.cnak = 1;
50371 +
50372 + DWC_MODIFY_REG32(&core_if->dev_if->
50373 + out_ep_regs[dwc_ep->num]->doepctl, depctl.d32,
50374 + depctl.d32);
50375 + return 0;
50376 + } else {
50377 + return 1;
50378 + }
50379 +}
50380 +
50381 +/**
50382 + * This function sets iso packets information(PTI mode)
50383 + *
50384 + * @param core_if Programming view of DWC_otg controller.
50385 + * @param ep The EP to start the transfer on.
50386 + *
50387 + */
50388 +static uint32_t set_iso_pkts_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
50389 +{
50390 + int i, j;
50391 + dma_addr_t dma_ad;
50392 + iso_pkt_info_t *packet_info = ep->pkt_info;
50393 + uint32_t offset;
50394 + uint32_t frame_data;
50395 + deptsiz_data_t deptsiz;
50396 +
50397 + if (ep->proc_buf_num == 0) {
50398 + /** Buffer 0 descriptors setup */
50399 + dma_ad = ep->dma_addr0;
50400 + } else {
50401 + /** Buffer 1 descriptors setup */
50402 + dma_ad = ep->dma_addr1;
50403 + }
50404 +
50405 + if (ep->is_in) {
50406 + deptsiz.d32 =
50407 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
50408 + dieptsiz);
50409 + } else {
50410 + deptsiz.d32 =
50411 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[ep->num]->
50412 + doeptsiz);
50413 + }
50414 +
50415 + if (!deptsiz.b.xfersize) {
50416 + offset = 0;
50417 + for (i = 0; i < ep->pkt_cnt; i += ep->pkt_per_frm) {
50418 + frame_data = ep->data_per_frame;
50419 + for (j = 0; j < ep->pkt_per_frm; ++j) {
50420 +
50421 + /* Packet status - is not set as initially
50422 + * it is set to 0 and if packet was sent
50423 + successfully, status field will remain 0*/
50424 +
50425 + /* Bytes has been transfered */
50426 + packet_info->length =
50427 + (ep->maxpacket <
50428 + frame_data) ? ep->maxpacket : frame_data;
50429 +
50430 + /* Received packet offset */
50431 + packet_info->offset = offset;
50432 + offset += packet_info->length;
50433 + frame_data -= packet_info->length;
50434 +
50435 + packet_info++;
50436 + }
50437 + }
50438 + return 1;
50439 + } else {
50440 + /* This is a workaround for in case of Transfer Complete with
50441 + * PktDrpSts interrupts merging - in this case Transfer complete
50442 + * interrupt for Isoc Out Endpoint is asserted without PktDrpSts
50443 + * set and with DOEPTSIZ register non zero. Investigations showed,
50444 + * that this happens when Out packet is dropped, but because of
50445 + * interrupts merging during first interrupt handling PktDrpSts
50446 + * bit is cleared and for next merged interrupts it is not reset.
50447 + * In this case SW hadles the interrupt as if PktDrpSts bit is set.
50448 + */
50449 + if (ep->is_in) {
50450 + return 1;
50451 + } else {
50452 + return handle_iso_out_pkt_dropped(core_if, ep);
50453 + }
50454 + }
50455 +}
50456 +
50457 +/**
50458 + * This function is to handle Iso EP transfer complete interrupt
50459 + *
50460 + * @param pcd The PCD
50461 + * @param ep The EP for which transfer complete was asserted
50462 + *
50463 + */
50464 +static void complete_iso_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
50465 +{
50466 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
50467 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
50468 + uint8_t is_last = 0;
50469 +
50470 + if (ep->dwc_ep.next_frame == 0xffffffff) {
50471 + DWC_WARN("Next frame is not set!\n");
50472 + return;
50473 + }
50474 +
50475 + if (core_if->dma_enable) {
50476 + if (core_if->dma_desc_enable) {
50477 + set_ddma_iso_pkts_info(core_if, dwc_ep);
50478 + reinit_ddma_iso_xfer(core_if, dwc_ep);
50479 + is_last = 1;
50480 + } else {
50481 + if (core_if->pti_enh_enable) {
50482 + if (set_iso_pkts_info(core_if, dwc_ep)) {
50483 + dwc_ep->proc_buf_num =
50484 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
50485 + dwc_otg_iso_ep_start_buf_transfer
50486 + (core_if, dwc_ep);
50487 + is_last = 1;
50488 + }
50489 + } else {
50490 + set_current_pkt_info(core_if, dwc_ep);
50491 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
50492 + is_last = 1;
50493 + dwc_ep->cur_pkt = 0;
50494 + dwc_ep->proc_buf_num =
50495 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
50496 + if (dwc_ep->proc_buf_num) {
50497 + dwc_ep->cur_pkt_addr =
50498 + dwc_ep->xfer_buff1;
50499 + dwc_ep->cur_pkt_dma_addr =
50500 + dwc_ep->dma_addr1;
50501 + } else {
50502 + dwc_ep->cur_pkt_addr =
50503 + dwc_ep->xfer_buff0;
50504 + dwc_ep->cur_pkt_dma_addr =
50505 + dwc_ep->dma_addr0;
50506 + }
50507 +
50508 + }
50509 + dwc_otg_iso_ep_start_frm_transfer(core_if,
50510 + dwc_ep);
50511 + }
50512 + }
50513 + } else {
50514 + set_current_pkt_info(core_if, dwc_ep);
50515 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
50516 + is_last = 1;
50517 + dwc_ep->cur_pkt = 0;
50518 + dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
50519 + if (dwc_ep->proc_buf_num) {
50520 + dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff1;
50521 + dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr1;
50522 + } else {
50523 + dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff0;
50524 + dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr0;
50525 + }
50526 +
50527 + }
50528 + dwc_otg_iso_ep_start_frm_transfer(core_if, dwc_ep);
50529 + }
50530 + if (is_last)
50531 + dwc_otg_iso_buffer_done(pcd, ep, ep->iso_req_handle);
50532 +}
50533 +#endif /* DWC_EN_ISOC */
50534 +
50535 +/**
50536 + * This function handle BNA interrupt for Non Isochronous EPs
50537 + *
50538 + */
50539 +static void dwc_otg_pcd_handle_noniso_bna(dwc_otg_pcd_ep_t * ep)
50540 +{
50541 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
50542 + volatile uint32_t *addr;
50543 + depctl_data_t depctl = {.d32 = 0 };
50544 + dwc_otg_pcd_t *pcd = ep->pcd;
50545 + dwc_otg_dev_dma_desc_t *dma_desc;
50546 + dev_dma_desc_sts_t sts = {.d32 = 0 };
50547 + dwc_otg_core_if_t *core_if = ep->pcd->core_if;
50548 + int i, start;
50549 +
50550 + if (!dwc_ep->desc_cnt)
50551 + DWC_WARN("Ep%d %s Descriptor count = %d \n", dwc_ep->num,
50552 + (dwc_ep->is_in ? "IN" : "OUT"), dwc_ep->desc_cnt);
50553 +
50554 + if (core_if->core_params->cont_on_bna && !dwc_ep->is_in
50555 + && dwc_ep->type != DWC_OTG_EP_TYPE_CONTROL) {
50556 + uint32_t doepdma;
50557 + dwc_otg_dev_out_ep_regs_t *out_regs =
50558 + core_if->dev_if->out_ep_regs[dwc_ep->num];
50559 + doepdma = DWC_READ_REG32(&(out_regs->doepdma));
50560 + start = (doepdma - dwc_ep->dma_desc_addr)/sizeof(dwc_otg_dev_dma_desc_t);
50561 + dma_desc = &(dwc_ep->desc_addr[start]);
50562 + } else {
50563 + start = 0;
50564 + dma_desc = dwc_ep->desc_addr;
50565 + }
50566 +
50567 +
50568 + for (i = start; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
50569 + sts.d32 = dma_desc->status.d32;
50570 + sts.b.bs = BS_HOST_READY;
50571 + dma_desc->status.d32 = sts.d32;
50572 + }
50573 +
50574 + if (dwc_ep->is_in == 0) {
50575 + addr =
50576 + &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->num]->
50577 + doepctl;
50578 + } else {
50579 + addr =
50580 + &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
50581 + }
50582 + depctl.b.epena = 1;
50583 + depctl.b.cnak = 1;
50584 + DWC_MODIFY_REG32(addr, 0, depctl.d32);
50585 +}
50586 +
50587 +/**
50588 + * This function handles EP0 Control transfers.
50589 + *
50590 + * The state of the control transfers are tracked in
50591 + * <code>ep0state</code>.
50592 + */
50593 +static void handle_ep0(dwc_otg_pcd_t * pcd)
50594 +{
50595 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
50596 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
50597 + dev_dma_desc_sts_t desc_sts;
50598 + deptsiz0_data_t deptsiz;
50599 + uint32_t byte_count;
50600 +
50601 +#ifdef DEBUG_EP0
50602 + DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
50603 + print_ep0_state(pcd);
50604 +#endif
50605 +
50606 +// DWC_PRINTF("HANDLE EP0\n");
50607 +
50608 + switch (pcd->ep0state) {
50609 + case EP0_DISCONNECT:
50610 + break;
50611 +
50612 + case EP0_IDLE:
50613 + pcd->request_config = 0;
50614 +
50615 + pcd_setup(pcd);
50616 + break;
50617 +
50618 + case EP0_IN_DATA_PHASE:
50619 +#ifdef DEBUG_EP0
50620 + DWC_DEBUGPL(DBG_PCD, "DATA_IN EP%d-%s: type=%d, mps=%d\n",
50621 + ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
50622 + ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
50623 +#endif
50624 +
50625 + if (core_if->dma_enable != 0) {
50626 + /*
50627 + * For EP0 we can only program 1 packet at a time so we
50628 + * need to do the make calculations after each complete.
50629 + * Call write_packet to make the calculations, as in
50630 + * slave mode, and use those values to determine if we
50631 + * can complete.
50632 + */
50633 + if (core_if->dma_desc_enable == 0) {
50634 + deptsiz.d32 =
50635 + DWC_READ_REG32(&core_if->
50636 + dev_if->in_ep_regs[0]->
50637 + dieptsiz);
50638 + byte_count =
50639 + ep0->dwc_ep.xfer_len - deptsiz.b.xfersize;
50640 + } else {
50641 + desc_sts =
50642 + core_if->dev_if->in_desc_addr->status;
50643 + byte_count =
50644 + ep0->dwc_ep.xfer_len - desc_sts.b.bytes;
50645 + }
50646 + ep0->dwc_ep.xfer_count += byte_count;
50647 + ep0->dwc_ep.xfer_buff += byte_count;
50648 + ep0->dwc_ep.dma_addr += byte_count;
50649 + }
50650 + if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
50651 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50652 + &ep0->dwc_ep);
50653 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
50654 + } else if (ep0->dwc_ep.sent_zlp) {
50655 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50656 + &ep0->dwc_ep);
50657 + ep0->dwc_ep.sent_zlp = 0;
50658 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n");
50659 + } else {
50660 + ep0_complete_request(ep0);
50661 + DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
50662 + }
50663 + break;
50664 + case EP0_OUT_DATA_PHASE:
50665 +#ifdef DEBUG_EP0
50666 + DWC_DEBUGPL(DBG_PCD, "DATA_OUT EP%d-%s: type=%d, mps=%d\n",
50667 + ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
50668 + ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
50669 +#endif
50670 + if (core_if->dma_enable != 0) {
50671 + if (core_if->dma_desc_enable == 0) {
50672 + deptsiz.d32 =
50673 + DWC_READ_REG32(&core_if->
50674 + dev_if->out_ep_regs[0]->
50675 + doeptsiz);
50676 + byte_count =
50677 + ep0->dwc_ep.maxpacket - deptsiz.b.xfersize;
50678 + } else {
50679 + desc_sts =
50680 + core_if->dev_if->out_desc_addr->status;
50681 + byte_count =
50682 + ep0->dwc_ep.maxpacket - desc_sts.b.bytes;
50683 + }
50684 + ep0->dwc_ep.xfer_count += byte_count;
50685 + ep0->dwc_ep.xfer_buff += byte_count;
50686 + ep0->dwc_ep.dma_addr += byte_count;
50687 + }
50688 + if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
50689 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50690 + &ep0->dwc_ep);
50691 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
50692 + } else if (ep0->dwc_ep.sent_zlp) {
50693 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50694 + &ep0->dwc_ep);
50695 + ep0->dwc_ep.sent_zlp = 0;
50696 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n");
50697 + } else {
50698 + ep0_complete_request(ep0);
50699 + DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
50700 + }
50701 + break;
50702 +
50703 + case EP0_IN_STATUS_PHASE:
50704 + case EP0_OUT_STATUS_PHASE:
50705 + DWC_DEBUGPL(DBG_PCD, "CASE: EP0_STATUS\n");
50706 + ep0_complete_request(ep0);
50707 + pcd->ep0state = EP0_IDLE;
50708 + ep0->stopped = 1;
50709 + ep0->dwc_ep.is_in = 0; /* OUT for next SETUP */
50710 +
50711 + /* Prepare for more SETUP Packets */
50712 + if (core_if->dma_enable) {
50713 + ep0_out_start(core_if, pcd);
50714 + }
50715 + break;
50716 +
50717 + case EP0_STALL:
50718 + DWC_ERROR("EP0 STALLed, should not get here pcd_setup()\n");
50719 + break;
50720 + }
50721 +#ifdef DEBUG_EP0
50722 + print_ep0_state(pcd);
50723 +#endif
50724 +}
50725 +
50726 +/**
50727 + * Restart transfer
50728 + */
50729 +static void restart_transfer(dwc_otg_pcd_t * pcd, const uint32_t epnum)
50730 +{
50731 + dwc_otg_core_if_t *core_if;
50732 + dwc_otg_dev_if_t *dev_if;
50733 + deptsiz_data_t dieptsiz = {.d32 = 0 };
50734 + dwc_otg_pcd_ep_t *ep;
50735 +
50736 + ep = get_in_ep(pcd, epnum);
50737 +
50738 +#ifdef DWC_EN_ISOC
50739 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
50740 + return;
50741 + }
50742 +#endif /* DWC_EN_ISOC */
50743 +
50744 + core_if = GET_CORE_IF(pcd);
50745 + dev_if = core_if->dev_if;
50746 +
50747 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
50748 +
50749 + DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x xfer_len=%0x"
50750 + " stopped=%d\n", ep->dwc_ep.xfer_buff,
50751 + ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len, ep->stopped);
50752 + /*
50753 + * If xfersize is 0 and pktcnt in not 0, resend the last packet.
50754 + */
50755 + if (dieptsiz.b.pktcnt && dieptsiz.b.xfersize == 0 &&
50756 + ep->dwc_ep.start_xfer_buff != 0) {
50757 + if (ep->dwc_ep.total_len <= ep->dwc_ep.maxpacket) {
50758 + ep->dwc_ep.xfer_count = 0;
50759 + ep->dwc_ep.xfer_buff = ep->dwc_ep.start_xfer_buff;
50760 + ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
50761 + } else {
50762 + ep->dwc_ep.xfer_count -= ep->dwc_ep.maxpacket;
50763 + /* convert packet size to dwords. */
50764 + ep->dwc_ep.xfer_buff -= ep->dwc_ep.maxpacket;
50765 + ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
50766 + }
50767 + ep->stopped = 0;
50768 + DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x "
50769 + "xfer_len=%0x stopped=%d\n",
50770 + ep->dwc_ep.xfer_buff,
50771 + ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len,
50772 + ep->stopped);
50773 + if (epnum == 0) {
50774 + dwc_otg_ep0_start_transfer(core_if, &ep->dwc_ep);
50775 + } else {
50776 + dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
50777 + }
50778 + }
50779 +}
50780 +
50781 +/*
50782 + * This function create new nextep sequnce based on Learn Queue.
50783 + *
50784 + * @param core_if Programming view of DWC_otg controller
50785 + */
50786 +void predict_nextep_seq( dwc_otg_core_if_t * core_if)
50787 +{
50788 + dwc_otg_device_global_regs_t *dev_global_regs =
50789 + core_if->dev_if->dev_global_regs;
50790 + const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
50791 + /* Number of Token Queue Registers */
50792 + const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
50793 + dtknq1_data_t dtknqr1;
50794 + uint32_t in_tkn_epnums[4];
50795 + uint8_t seqnum[MAX_EPS_CHANNELS];
50796 + uint8_t intkn_seq[TOKEN_Q_DEPTH];
50797 + grstctl_t resetctl = {.d32 = 0 };
50798 + uint8_t temp;
50799 + int ndx = 0;
50800 + int start = 0;
50801 + int end = 0;
50802 + int sort_done = 0;
50803 + int i = 0;
50804 + volatile uint32_t *addr = &dev_global_regs->dtknqr1;
50805 +
50806 +
50807 + DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
50808 +
50809 + /* Read the DTKNQ Registers */
50810 + for (i = 0; i < DTKNQ_REG_CNT; i++) {
50811 + in_tkn_epnums[i] = DWC_READ_REG32(addr);
50812 + DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
50813 + in_tkn_epnums[i]);
50814 + if (addr == &dev_global_regs->dvbusdis) {
50815 + addr = &dev_global_regs->dtknqr3_dthrctl;
50816 + } else {
50817 + ++addr;
50818 + }
50819 +
50820 + }
50821 +
50822 + /* Copy the DTKNQR1 data to the bit field. */
50823 + dtknqr1.d32 = in_tkn_epnums[0];
50824 + if (dtknqr1.b.wrap_bit) {
50825 + ndx = dtknqr1.b.intknwptr;
50826 + end = ndx -1;
50827 + if (end < 0)
50828 + end = TOKEN_Q_DEPTH -1;
50829 + } else {
50830 + ndx = 0;
50831 + end = dtknqr1.b.intknwptr -1;
50832 + if (end < 0)
50833 + end = 0;
50834 + }
50835 + start = ndx;
50836 +
50837 + /* Fill seqnum[] by initial values: EP number + 31 */
50838 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
50839 + seqnum[i] = i +31;
50840 + }
50841 +
50842 + /* Fill intkn_seq[] from in_tkn_epnums[0] */
50843 + for (i=0; i < 6; i++)
50844 + intkn_seq[i] = (in_tkn_epnums[0] >> ((7-i) * 4)) & 0xf;
50845 +
50846 + if (TOKEN_Q_DEPTH > 6) {
50847 + /* Fill intkn_seq[] from in_tkn_epnums[1] */
50848 + for (i=6; i < 14; i++)
50849 + intkn_seq[i] =
50850 + (in_tkn_epnums[1] >> ((7 - (i - 6)) * 4)) & 0xf;
50851 + }
50852 +
50853 + if (TOKEN_Q_DEPTH > 14) {
50854 + /* Fill intkn_seq[] from in_tkn_epnums[1] */
50855 + for (i=14; i < 22; i++)
50856 + intkn_seq[i] =
50857 + (in_tkn_epnums[2] >> ((7 - (i - 14)) * 4)) & 0xf;
50858 + }
50859 +
50860 + if (TOKEN_Q_DEPTH > 22) {
50861 + /* Fill intkn_seq[] from in_tkn_epnums[1] */
50862 + for (i=22; i < 30; i++)
50863 + intkn_seq[i] =
50864 + (in_tkn_epnums[3] >> ((7 - (i - 22)) * 4)) & 0xf;
50865 + }
50866 +
50867 + DWC_DEBUGPL(DBG_PCDV, "%s start=%d end=%d intkn_seq[]:\n", __func__,
50868 + start, end);
50869 + for (i=0; i<TOKEN_Q_DEPTH; i++)
50870 + DWC_DEBUGPL(DBG_PCDV,"%d\n", intkn_seq[i]);
50871 +
50872 + /* Update seqnum based on intkn_seq[] */
50873 + i = 0;
50874 + do {
50875 + seqnum[intkn_seq[ndx]] = i;
50876 + ndx++;
50877 + i++;
50878 + if (ndx == TOKEN_Q_DEPTH)
50879 + ndx = 0;
50880 + } while ( i < TOKEN_Q_DEPTH );
50881 +
50882 + /* Mark non active EP's in seqnum[] by 0xff */
50883 + for (i=0; i<=core_if->dev_if->num_in_eps; i++) {
50884 + if (core_if->nextep_seq[i] == 0xff )
50885 + seqnum[i] = 0xff;
50886 + }
50887 +
50888 + /* Sort seqnum[] */
50889 + sort_done = 0;
50890 + while (!sort_done) {
50891 + sort_done = 1;
50892 + for (i=0; i<core_if->dev_if->num_in_eps; i++) {
50893 + if (seqnum[i] > seqnum[i+1]) {
50894 + temp = seqnum[i];
50895 + seqnum[i] = seqnum[i+1];
50896 + seqnum[i+1] = temp;
50897 + sort_done = 0;
50898 + }
50899 + }
50900 + }
50901 +
50902 + ndx = start + seqnum[0];
50903 + if (ndx >= TOKEN_Q_DEPTH)
50904 + ndx = ndx % TOKEN_Q_DEPTH;
50905 + core_if->first_in_nextep_seq = intkn_seq[ndx];
50906 +
50907 + /* Update seqnum[] by EP numbers */
50908 + for (i=0; i<=core_if->dev_if->num_in_eps; i++) {
50909 + ndx = start + i;
50910 + if (seqnum[i] < 31) {
50911 + ndx = start + seqnum[i];
50912 + if (ndx >= TOKEN_Q_DEPTH)
50913 + ndx = ndx % TOKEN_Q_DEPTH;
50914 + seqnum[i] = intkn_seq[ndx];
50915 + } else {
50916 + if (seqnum[i] < 0xff) {
50917 + seqnum[i] = seqnum[i] - 31;
50918 + } else {
50919 + break;
50920 + }
50921 + }
50922 + }
50923 +
50924 + /* Update nextep_seq[] based on seqnum[] */
50925 + for (i=0; i<core_if->dev_if->num_in_eps; i++) {
50926 + if (seqnum[i] != 0xff) {
50927 + if (seqnum[i+1] != 0xff) {
50928 + core_if->nextep_seq[seqnum[i]] = seqnum[i+1];
50929 + } else {
50930 + core_if->nextep_seq[seqnum[i]] = core_if->first_in_nextep_seq;
50931 + break;
50932 + }
50933 + } else {
50934 + break;
50935 + }
50936 + }
50937 +
50938 + DWC_DEBUGPL(DBG_PCDV, "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
50939 + __func__, core_if->first_in_nextep_seq);
50940 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
50941 + DWC_DEBUGPL(DBG_PCDV,"%2d\n", core_if->nextep_seq[i]);
50942 + }
50943 +
50944 + /* Flush the Learning Queue */
50945 + resetctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->grstctl);
50946 + resetctl.b.intknqflsh = 1;
50947 + DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
50948 +
50949 +
50950 +}
50951 +
50952 +/**
50953 + * handle the IN EP disable interrupt.
50954 + */
50955 +static inline void handle_in_ep_disable_intr(dwc_otg_pcd_t * pcd,
50956 + const uint32_t epnum)
50957 +{
50958 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
50959 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
50960 + deptsiz_data_t dieptsiz = {.d32 = 0 };
50961 + dctl_data_t dctl = {.d32 = 0 };
50962 + dwc_otg_pcd_ep_t *ep;
50963 + dwc_ep_t *dwc_ep;
50964 + gintmsk_data_t gintmsk_data;
50965 + depctl_data_t depctl;
50966 + uint32_t diepdma;
50967 + uint32_t remain_to_transfer = 0;
50968 + uint8_t i;
50969 + uint32_t xfer_size;
50970 +
50971 + ep = get_in_ep(pcd, epnum);
50972 + dwc_ep = &ep->dwc_ep;
50973 +
50974 + if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
50975 + dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
50976 + complete_ep(ep);
50977 + return;
50978 + }
50979 +
50980 + DWC_DEBUGPL(DBG_PCD, "diepctl%d=%0x\n", epnum,
50981 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl));
50982 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
50983 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
50984 +
50985 + DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
50986 + dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
50987 +
50988 + if ((core_if->start_predict == 0) || (depctl.b.eptype & 1)) {
50989 + if (ep->stopped) {
50990 + if (core_if->en_multiple_tx_fifo)
50991 + /* Flush the Tx FIFO */
50992 + dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
50993 + /* Clear the Global IN NP NAK */
50994 + dctl.d32 = 0;
50995 + dctl.b.cgnpinnak = 1;
50996 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
50997 + /* Restart the transaction */
50998 + if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
50999 + restart_transfer(pcd, epnum);
51000 + }
51001 + } else {
51002 + /* Restart the transaction */
51003 + if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
51004 + restart_transfer(pcd, epnum);
51005 + }
51006 + DWC_DEBUGPL(DBG_ANY, "STOPPED!!!\n");
51007 + }
51008 + return;
51009 + }
51010 +
51011 + if (core_if->start_predict > 2) { // NP IN EP
51012 + core_if->start_predict--;
51013 + return;
51014 + }
51015 +
51016 + core_if->start_predict--;
51017 +
51018 + if (core_if->start_predict == 1) { // All NP IN Ep's disabled now
51019 +
51020 + predict_nextep_seq(core_if);
51021 +
51022 + /* Update all active IN EP's NextEP field based of nextep_seq[] */
51023 + for ( i = 0; i <= core_if->dev_if->num_in_eps; i++) {
51024 + depctl.d32 =
51025 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
51026 + if (core_if->nextep_seq[i] != 0xff) { // Active NP IN EP
51027 + depctl.b.nextep = core_if->nextep_seq[i];
51028 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
51029 + }
51030 + }
51031 + /* Flush Shared NP TxFIFO */
51032 + dwc_otg_flush_tx_fifo(core_if, 0);
51033 + /* Rewind buffers */
51034 + if (!core_if->dma_desc_enable) {
51035 + i = core_if->first_in_nextep_seq;
51036 + do {
51037 + ep = get_in_ep(pcd, i);
51038 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
51039 + xfer_size = ep->dwc_ep.total_len - ep->dwc_ep.xfer_count;
51040 + if (xfer_size > ep->dwc_ep.maxxfer)
51041 + xfer_size = ep->dwc_ep.maxxfer;
51042 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
51043 + if (dieptsiz.b.pktcnt != 0) {
51044 + if (xfer_size == 0) {
51045 + remain_to_transfer = 0;
51046 + } else {
51047 + if ((xfer_size % ep->dwc_ep.maxpacket) == 0) {
51048 + remain_to_transfer =
51049 + dieptsiz.b.pktcnt * ep->dwc_ep.maxpacket;
51050 + } else {
51051 + remain_to_transfer = ((dieptsiz.b.pktcnt -1) * ep->dwc_ep.maxpacket)
51052 + + (xfer_size % ep->dwc_ep.maxpacket);
51053 + }
51054 + }
51055 + diepdma = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepdma);
51056 + dieptsiz.b.xfersize = remain_to_transfer;
51057 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, dieptsiz.d32);
51058 + diepdma = ep->dwc_ep.dma_addr + (xfer_size - remain_to_transfer);
51059 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, diepdma);
51060 + }
51061 + i = core_if->nextep_seq[i];
51062 + } while (i != core_if->first_in_nextep_seq);
51063 + } else { // dma_desc_enable
51064 + DWC_PRINTF("%s Learning Queue not supported in DDMA\n", __func__);
51065 + }
51066 +
51067 + /* Restart transfers in predicted sequences */
51068 + i = core_if->first_in_nextep_seq;
51069 + do {
51070 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
51071 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
51072 + if (dieptsiz.b.pktcnt != 0) {
51073 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
51074 + depctl.b.epena = 1;
51075 + depctl.b.cnak = 1;
51076 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
51077 + }
51078 + i = core_if->nextep_seq[i];
51079 + } while (i != core_if->first_in_nextep_seq);
51080 +
51081 + /* Clear the global non-periodic IN NAK handshake */
51082 + dctl.d32 = 0;
51083 + dctl.b.cgnpinnak = 1;
51084 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
51085 +
51086 + /* Unmask EP Mismatch interrupt */
51087 + gintmsk_data.d32 = 0;
51088 + gintmsk_data.b.epmismatch = 1;
51089 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk_data.d32);
51090 +
51091 + core_if->start_predict = 0;
51092 +
51093 + }
51094 +}
51095 +
51096 +/**
51097 + * Handler for the IN EP timeout handshake interrupt.
51098 + */
51099 +static inline void handle_in_ep_timeout_intr(dwc_otg_pcd_t * pcd,
51100 + const uint32_t epnum)
51101 +{
51102 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
51103 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
51104 +
51105 +#ifdef DEBUG
51106 + deptsiz_data_t dieptsiz = {.d32 = 0 };
51107 + uint32_t num = 0;
51108 +#endif
51109 + dctl_data_t dctl = {.d32 = 0 };
51110 + dwc_otg_pcd_ep_t *ep;
51111 +
51112 + gintmsk_data_t intr_mask = {.d32 = 0 };
51113 +
51114 + ep = get_in_ep(pcd, epnum);
51115 +
51116 + /* Disable the NP Tx Fifo Empty Interrrupt */
51117 + if (!core_if->dma_enable) {
51118 + intr_mask.b.nptxfempty = 1;
51119 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
51120 + intr_mask.d32, 0);
51121 + }
51122 + /** @todo NGS Check EP type.
51123 + * Implement for Periodic EPs */
51124 + /*
51125 + * Non-periodic EP
51126 + */
51127 + /* Enable the Global IN NAK Effective Interrupt */
51128 + intr_mask.b.ginnakeff = 1;
51129 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
51130 +
51131 + /* Set Global IN NAK */
51132 + dctl.b.sgnpinnak = 1;
51133 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
51134 +
51135 + ep->stopped = 1;
51136 +
51137 +#ifdef DEBUG
51138 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[num]->dieptsiz);
51139 + DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
51140 + dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
51141 +#endif
51142 +
51143 +#ifdef DISABLE_PERIODIC_EP
51144 + /*
51145 + * Set the NAK bit for this EP to
51146 + * start the disable process.
51147 + */
51148 + diepctl.d32 = 0;
51149 + diepctl.b.snak = 1;
51150 + DWC_MODIFY_REG32(&dev_if->in_ep_regs[num]->diepctl, diepctl.d32,
51151 + diepctl.d32);
51152 + ep->disabling = 1;
51153 + ep->stopped = 1;
51154 +#endif
51155 +}
51156 +
51157 +/**
51158 + * Handler for the IN EP NAK interrupt.
51159 + */
51160 +static inline int32_t handle_in_ep_nak_intr(dwc_otg_pcd_t * pcd,
51161 + const uint32_t epnum)
51162 +{
51163 + /** @todo implement ISR */
51164 + dwc_otg_core_if_t *core_if;
51165 + diepmsk_data_t intr_mask = {.d32 = 0 };
51166 +
51167 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "IN EP NAK");
51168 + core_if = GET_CORE_IF(pcd);
51169 + intr_mask.b.nak = 1;
51170 +
51171 + if (core_if->multiproc_int_enable) {
51172 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
51173 + diepeachintmsk[epnum], intr_mask.d32, 0);
51174 + } else {
51175 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->diepmsk,
51176 + intr_mask.d32, 0);
51177 + }
51178 +
51179 + return 1;
51180 +}
51181 +
51182 +/**
51183 + * Handler for the OUT EP Babble interrupt.
51184 + */
51185 +static inline int32_t handle_out_ep_babble_intr(dwc_otg_pcd_t * pcd,
51186 + const uint32_t epnum)
51187 +{
51188 + /** @todo implement ISR */
51189 + dwc_otg_core_if_t *core_if;
51190 + doepmsk_data_t intr_mask = {.d32 = 0 };
51191 +
51192 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
51193 + "OUT EP Babble");
51194 + core_if = GET_CORE_IF(pcd);
51195 + intr_mask.b.babble = 1;
51196 +
51197 + if (core_if->multiproc_int_enable) {
51198 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
51199 + doepeachintmsk[epnum], intr_mask.d32, 0);
51200 + } else {
51201 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
51202 + intr_mask.d32, 0);
51203 + }
51204 +
51205 + return 1;
51206 +}
51207 +
51208 +/**
51209 + * Handler for the OUT EP NAK interrupt.
51210 + */
51211 +static inline int32_t handle_out_ep_nak_intr(dwc_otg_pcd_t * pcd,
51212 + const uint32_t epnum)
51213 +{
51214 + /** @todo implement ISR */
51215 + dwc_otg_core_if_t *core_if;
51216 + doepmsk_data_t intr_mask = {.d32 = 0 };
51217 +
51218 + DWC_DEBUGPL(DBG_ANY, "INTERRUPT Handler not implemented for %s\n", "OUT EP NAK");
51219 + core_if = GET_CORE_IF(pcd);
51220 + intr_mask.b.nak = 1;
51221 +
51222 + if (core_if->multiproc_int_enable) {
51223 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
51224 + doepeachintmsk[epnum], intr_mask.d32, 0);
51225 + } else {
51226 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
51227 + intr_mask.d32, 0);
51228 + }
51229 +
51230 + return 1;
51231 +}
51232 +
51233 +/**
51234 + * Handler for the OUT EP NYET interrupt.
51235 + */
51236 +static inline int32_t handle_out_ep_nyet_intr(dwc_otg_pcd_t * pcd,
51237 + const uint32_t epnum)
51238 +{
51239 + /** @todo implement ISR */
51240 + dwc_otg_core_if_t *core_if;
51241 + doepmsk_data_t intr_mask = {.d32 = 0 };
51242 +
51243 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NYET");
51244 + core_if = GET_CORE_IF(pcd);
51245 + intr_mask.b.nyet = 1;
51246 +
51247 + if (core_if->multiproc_int_enable) {
51248 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
51249 + doepeachintmsk[epnum], intr_mask.d32, 0);
51250 + } else {
51251 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
51252 + intr_mask.d32, 0);
51253 + }
51254 +
51255 + return 1;
51256 +}
51257 +
51258 +/**
51259 + * This interrupt indicates that an IN EP has a pending Interrupt.
51260 + * The sequence for handling the IN EP interrupt is shown below:
51261 + * -# Read the Device All Endpoint Interrupt register
51262 + * -# Repeat the following for each IN EP interrupt bit set (from
51263 + * LSB to MSB).
51264 + * -# Read the Device Endpoint Interrupt (DIEPINTn) register
51265 + * -# If "Transfer Complete" call the request complete function
51266 + * -# If "Endpoint Disabled" complete the EP disable procedure.
51267 + * -# If "AHB Error Interrupt" log error
51268 + * -# If "Time-out Handshake" log error
51269 + * -# If "IN Token Received when TxFIFO Empty" write packet to Tx
51270 + * FIFO.
51271 + * -# If "IN Token EP Mismatch" (disable, this is handled by EP
51272 + * Mismatch Interrupt)
51273 + */
51274 +static int32_t dwc_otg_pcd_handle_in_ep_intr(dwc_otg_pcd_t * pcd)
51275 +{
51276 +#define CLEAR_IN_EP_INTR(__core_if,__epnum,__intr) \
51277 +do { \
51278 + diepint_data_t diepint = {.d32=0}; \
51279 + diepint.b.__intr = 1; \
51280 + DWC_WRITE_REG32(&__core_if->dev_if->in_ep_regs[__epnum]->diepint, \
51281 + diepint.d32); \
51282 +} while (0)
51283 +
51284 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
51285 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
51286 + diepint_data_t diepint = {.d32 = 0 };
51287 + depctl_data_t depctl = {.d32 = 0 };
51288 + uint32_t ep_intr;
51289 + uint32_t epnum = 0;
51290 + dwc_otg_pcd_ep_t *ep;
51291 + dwc_ep_t *dwc_ep;
51292 + gintmsk_data_t intr_mask = {.d32 = 0 };
51293 +
51294 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, pcd);
51295 +
51296 + /* Read in the device interrupt bits */
51297 + ep_intr = dwc_otg_read_dev_all_in_ep_intr(core_if);
51298 +
51299 + /* Service the Device IN interrupts for each endpoint */
51300 + while (ep_intr) {
51301 + if (ep_intr & 0x1) {
51302 + uint32_t empty_msk;
51303 + /* Get EP pointer */
51304 + ep = get_in_ep(pcd, epnum);
51305 + dwc_ep = &ep->dwc_ep;
51306 +
51307 + depctl.d32 =
51308 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
51309 + empty_msk =
51310 + DWC_READ_REG32(&dev_if->
51311 + dev_global_regs->dtknqr4_fifoemptymsk);
51312 +
51313 + DWC_DEBUGPL(DBG_PCDV,
51314 + "IN EP INTERRUPT - %d\nepmty_msk - %8x diepctl - %8x\n",
51315 + epnum, empty_msk, depctl.d32);
51316 +
51317 + DWC_DEBUGPL(DBG_PCD,
51318 + "EP%d-%s: type=%d, mps=%d\n",
51319 + dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
51320 + dwc_ep->type, dwc_ep->maxpacket);
51321 +
51322 + diepint.d32 =
51323 + dwc_otg_read_dev_in_ep_intr(core_if, dwc_ep);
51324 +
51325 + DWC_DEBUGPL(DBG_PCDV,
51326 + "EP %d Interrupt Register - 0x%x\n", epnum,
51327 + diepint.d32);
51328 + /* Transfer complete */
51329 + if (diepint.b.xfercompl) {
51330 + /* Disable the NP Tx FIFO Empty
51331 + * Interrupt */
51332 + if (core_if->en_multiple_tx_fifo == 0) {
51333 + intr_mask.b.nptxfempty = 1;
51334 + DWC_MODIFY_REG32
51335 + (&core_if->core_global_regs->gintmsk,
51336 + intr_mask.d32, 0);
51337 + } else {
51338 + /* Disable the Tx FIFO Empty Interrupt for this EP */
51339 + uint32_t fifoemptymsk =
51340 + 0x1 << dwc_ep->num;
51341 + DWC_MODIFY_REG32(&core_if->
51342 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
51343 + fifoemptymsk, 0);
51344 + }
51345 + /* Clear the bit in DIEPINTn for this interrupt */
51346 + CLEAR_IN_EP_INTR(core_if, epnum, xfercompl);
51347 +
51348 + /* Complete the transfer */
51349 + if (epnum == 0) {
51350 + handle_ep0(pcd);
51351 + }
51352 +#ifdef DWC_EN_ISOC
51353 + else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51354 + if (!ep->stopped)
51355 + complete_iso_ep(pcd, ep);
51356 + }
51357 +#endif /* DWC_EN_ISOC */
51358 +#ifdef DWC_UTE_PER_IO
51359 + else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51360 + if (!ep->stopped)
51361 + complete_xiso_ep(ep);
51362 + }
51363 +#endif /* DWC_UTE_PER_IO */
51364 + else {
51365 + if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC &&
51366 + dwc_ep->bInterval > 1) {
51367 + dwc_ep->frame_num += dwc_ep->bInterval;
51368 + if (dwc_ep->frame_num > 0x3FFF)
51369 + {
51370 + dwc_ep->frm_overrun = 1;
51371 + dwc_ep->frame_num &= 0x3FFF;
51372 + } else
51373 + dwc_ep->frm_overrun = 0;
51374 + }
51375 + complete_ep(ep);
51376 + if(diepint.b.nak)
51377 + CLEAR_IN_EP_INTR(core_if, epnum, nak);
51378 + }
51379 + }
51380 + /* Endpoint disable */
51381 + if (diepint.b.epdisabled) {
51382 + DWC_DEBUGPL(DBG_ANY, "EP%d IN disabled\n",
51383 + epnum);
51384 + handle_in_ep_disable_intr(pcd, epnum);
51385 +
51386 + /* Clear the bit in DIEPINTn for this interrupt */
51387 + CLEAR_IN_EP_INTR(core_if, epnum, epdisabled);
51388 + }
51389 + /* AHB Error */
51390 + if (diepint.b.ahberr) {
51391 + DWC_ERROR("EP%d IN AHB Error\n", epnum);
51392 + /* Clear the bit in DIEPINTn for this interrupt */
51393 + CLEAR_IN_EP_INTR(core_if, epnum, ahberr);
51394 + }
51395 + /* TimeOUT Handshake (non-ISOC IN EPs) */
51396 + if (diepint.b.timeout) {
51397 + DWC_ERROR("EP%d IN Time-out\n", epnum);
51398 + handle_in_ep_timeout_intr(pcd, epnum);
51399 +
51400 + CLEAR_IN_EP_INTR(core_if, epnum, timeout);
51401 + }
51402 + /** IN Token received with TxF Empty */
51403 + if (diepint.b.intktxfemp) {
51404 + DWC_DEBUGPL(DBG_ANY,
51405 + "EP%d IN TKN TxFifo Empty\n",
51406 + epnum);
51407 + if (!ep->stopped && epnum != 0) {
51408 +
51409 + diepmsk_data_t diepmsk = {.d32 = 0 };
51410 + diepmsk.b.intktxfemp = 1;
51411 +
51412 + if (core_if->multiproc_int_enable) {
51413 + DWC_MODIFY_REG32
51414 + (&dev_if->dev_global_regs->diepeachintmsk
51415 + [epnum], diepmsk.d32, 0);
51416 + } else {
51417 + DWC_MODIFY_REG32
51418 + (&dev_if->dev_global_regs->diepmsk,
51419 + diepmsk.d32, 0);
51420 + }
51421 + } else if (core_if->dma_desc_enable
51422 + && epnum == 0
51423 + && pcd->ep0state ==
51424 + EP0_OUT_STATUS_PHASE) {
51425 + // EP0 IN set STALL
51426 + depctl.d32 =
51427 + DWC_READ_REG32(&dev_if->in_ep_regs
51428 + [epnum]->diepctl);
51429 +
51430 + /* set the disable and stall bits */
51431 + if (depctl.b.epena) {
51432 + depctl.b.epdis = 1;
51433 + }
51434 + depctl.b.stall = 1;
51435 + DWC_WRITE_REG32(&dev_if->in_ep_regs
51436 + [epnum]->diepctl,
51437 + depctl.d32);
51438 + }
51439 + CLEAR_IN_EP_INTR(core_if, epnum, intktxfemp);
51440 + }
51441 + /** IN Token Received with EP mismatch */
51442 + if (diepint.b.intknepmis) {
51443 + DWC_DEBUGPL(DBG_ANY,
51444 + "EP%d IN TKN EP Mismatch\n", epnum);
51445 + CLEAR_IN_EP_INTR(core_if, epnum, intknepmis);
51446 + }
51447 + /** IN Endpoint NAK Effective */
51448 + if (diepint.b.inepnakeff) {
51449 + DWC_DEBUGPL(DBG_ANY,
51450 + "EP%d IN EP NAK Effective\n",
51451 + epnum);
51452 + /* Periodic EP */
51453 + if (ep->disabling) {
51454 + depctl.d32 = 0;
51455 + depctl.b.snak = 1;
51456 + depctl.b.epdis = 1;
51457 + DWC_MODIFY_REG32(&dev_if->in_ep_regs
51458 + [epnum]->diepctl,
51459 + depctl.d32,
51460 + depctl.d32);
51461 + }
51462 + CLEAR_IN_EP_INTR(core_if, epnum, inepnakeff);
51463 +
51464 + }
51465 +
51466 + /** IN EP Tx FIFO Empty Intr */
51467 + if (diepint.b.emptyintr) {
51468 + DWC_DEBUGPL(DBG_ANY,
51469 + "EP%d Tx FIFO Empty Intr \n",
51470 + epnum);
51471 + write_empty_tx_fifo(pcd, epnum);
51472 +
51473 + CLEAR_IN_EP_INTR(core_if, epnum, emptyintr);
51474 +
51475 + }
51476 +
51477 + /** IN EP BNA Intr */
51478 + if (diepint.b.bna) {
51479 + CLEAR_IN_EP_INTR(core_if, epnum, bna);
51480 + if (core_if->dma_desc_enable) {
51481 +#ifdef DWC_EN_ISOC
51482 + if (dwc_ep->type ==
51483 + DWC_OTG_EP_TYPE_ISOC) {
51484 + /*
51485 + * This checking is performed to prevent first "false" BNA
51486 + * handling occuring right after reconnect
51487 + */
51488 + if (dwc_ep->next_frame !=
51489 + 0xffffffff)
51490 + dwc_otg_pcd_handle_iso_bna(ep);
51491 + } else
51492 +#endif /* DWC_EN_ISOC */
51493 + {
51494 + dwc_otg_pcd_handle_noniso_bna(ep);
51495 + }
51496 + }
51497 + }
51498 + /* NAK Interrutp */
51499 + if (diepint.b.nak) {
51500 + DWC_DEBUGPL(DBG_ANY, "EP%d IN NAK Interrupt\n",
51501 + epnum);
51502 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
51503 + depctl_data_t depctl;
51504 + if (ep->dwc_ep.frame_num == 0xFFFFFFFF) {
51505 + ep->dwc_ep.frame_num = core_if->frame_num;
51506 + if (ep->dwc_ep.bInterval > 1) {
51507 + depctl.d32 = 0;
51508 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
51509 + if (ep->dwc_ep.frame_num & 0x1) {
51510 + depctl.b.setd1pid = 1;
51511 + depctl.b.setd0pid = 0;
51512 + } else {
51513 + depctl.b.setd0pid = 1;
51514 + depctl.b.setd1pid = 0;
51515 + }
51516 + DWC_WRITE_REG32(&dev_if->in_ep_regs[epnum]->diepctl, depctl.d32);
51517 + }
51518 + start_next_request(ep);
51519 + }
51520 + ep->dwc_ep.frame_num += ep->dwc_ep.bInterval;
51521 + if (dwc_ep->frame_num > 0x3FFF) {
51522 + dwc_ep->frm_overrun = 1;
51523 + dwc_ep->frame_num &= 0x3FFF;
51524 + } else
51525 + dwc_ep->frm_overrun = 0;
51526 + }
51527 +
51528 + CLEAR_IN_EP_INTR(core_if, epnum, nak);
51529 + }
51530 + }
51531 + epnum++;
51532 + ep_intr >>= 1;
51533 + }
51534 +
51535 + return 1;
51536 +#undef CLEAR_IN_EP_INTR
51537 +}
51538 +
51539 +/**
51540 + * This interrupt indicates that an OUT EP has a pending Interrupt.
51541 + * The sequence for handling the OUT EP interrupt is shown below:
51542 + * -# Read the Device All Endpoint Interrupt register
51543 + * -# Repeat the following for each OUT EP interrupt bit set (from
51544 + * LSB to MSB).
51545 + * -# Read the Device Endpoint Interrupt (DOEPINTn) register
51546 + * -# If "Transfer Complete" call the request complete function
51547 + * -# If "Endpoint Disabled" complete the EP disable procedure.
51548 + * -# If "AHB Error Interrupt" log error
51549 + * -# If "Setup Phase Done" process Setup Packet (See Standard USB
51550 + * Command Processing)
51551 + */
51552 +static int32_t dwc_otg_pcd_handle_out_ep_intr(dwc_otg_pcd_t * pcd)
51553 +{
51554 +#define CLEAR_OUT_EP_INTR(__core_if,__epnum,__intr) \
51555 +do { \
51556 + doepint_data_t doepint = {.d32=0}; \
51557 + doepint.b.__intr = 1; \
51558 + DWC_WRITE_REG32(&__core_if->dev_if->out_ep_regs[__epnum]->doepint, \
51559 + doepint.d32); \
51560 +} while (0)
51561 +
51562 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
51563 + uint32_t ep_intr;
51564 + doepint_data_t doepint = {.d32 = 0 };
51565 + uint32_t epnum = 0;
51566 + dwc_otg_pcd_ep_t *ep;
51567 + dwc_ep_t *dwc_ep;
51568 + dctl_data_t dctl = {.d32 = 0 };
51569 + gintmsk_data_t gintmsk = {.d32 = 0 };
51570 +
51571 +
51572 + DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
51573 +
51574 + /* Read in the device interrupt bits */
51575 + ep_intr = dwc_otg_read_dev_all_out_ep_intr(core_if);
51576 +
51577 + while (ep_intr) {
51578 + if (ep_intr & 0x1) {
51579 + /* Get EP pointer */
51580 + ep = get_out_ep(pcd, epnum);
51581 + dwc_ep = &ep->dwc_ep;
51582 +
51583 +#ifdef VERBOSE
51584 + DWC_DEBUGPL(DBG_PCDV,
51585 + "EP%d-%s: type=%d, mps=%d\n",
51586 + dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
51587 + dwc_ep->type, dwc_ep->maxpacket);
51588 +#endif
51589 + doepint.d32 =
51590 + dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep);
51591 + /* Moved this interrupt upper due to core deffect of asserting
51592 + * OUT EP 0 xfercompl along with stsphsrcvd in BDMA */
51593 + if (doepint.b.stsphsercvd) {
51594 + deptsiz0_data_t deptsiz;
51595 + CLEAR_OUT_EP_INTR(core_if, epnum, stsphsercvd);
51596 + deptsiz.d32 =
51597 + DWC_READ_REG32(&core_if->dev_if->
51598 + out_ep_regs[0]->doeptsiz);
51599 + if (core_if->snpsid >= OTG_CORE_REV_3_00a
51600 + && core_if->dma_enable
51601 + && core_if->dma_desc_enable == 0
51602 + && doepint.b.xfercompl
51603 + && deptsiz.b.xfersize == 24) {
51604 + CLEAR_OUT_EP_INTR(core_if, epnum,
51605 + xfercompl);
51606 + doepint.b.xfercompl = 0;
51607 + ep0_out_start(core_if, pcd);
51608 + }
51609 + if ((core_if->dma_desc_enable) ||
51610 + (core_if->dma_enable
51611 + && core_if->snpsid >=
51612 + OTG_CORE_REV_3_00a)) {
51613 + do_setup_in_status_phase(pcd);
51614 + }
51615 + }
51616 + /* Transfer complete */
51617 + if (doepint.b.xfercompl) {
51618 +
51619 + if (epnum == 0) {
51620 + /* Clear the bit in DOEPINTn for this interrupt */
51621 + CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
51622 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
51623 + DWC_DEBUGPL(DBG_PCDV, "DOEPINT=%x doepint=%x\n",
51624 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepint),
51625 + doepint.d32);
51626 + DWC_DEBUGPL(DBG_PCDV, "DOEPCTL=%x \n",
51627 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepctl));
51628 +
51629 + if (core_if->snpsid >= OTG_CORE_REV_3_00a
51630 + && core_if->dma_enable == 0) {
51631 + doepint_data_t doepint;
51632 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51633 + out_ep_regs[0]->doepint);
51634 + if (pcd->ep0state == EP0_IDLE && doepint.b.sr) {
51635 + CLEAR_OUT_EP_INTR(core_if, epnum, sr);
51636 + goto exit_xfercompl;
51637 + }
51638 + }
51639 + /* In case of DDMA look at SR bit to go to the Data Stage */
51640 + if (core_if->dma_desc_enable) {
51641 + dev_dma_desc_sts_t status = {.d32 = 0};
51642 + if (pcd->ep0state == EP0_IDLE) {
51643 + status.d32 = core_if->dev_if->setup_desc_addr[core_if->
51644 + dev_if->setup_desc_index]->status.d32;
51645 + if(pcd->data_terminated) {
51646 + pcd->data_terminated = 0;
51647 + status.d32 = core_if->dev_if->out_desc_addr->status.d32;
51648 + dwc_memcpy(&pcd->setup_pkt->req, pcd->backup_buf, 8);
51649 + }
51650 + if (status.b.sr) {
51651 + if (doepint.b.setup) {
51652 + DWC_DEBUGPL(DBG_PCDV, "DMA DESC EP0_IDLE SR=1 setup=1\n");
51653 + /* Already started data stage, clear setup */
51654 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51655 + doepint.b.setup = 0;
51656 + handle_ep0(pcd);
51657 + /* Prepare for more setup packets */
51658 + if (pcd->ep0state == EP0_IN_STATUS_PHASE ||
51659 + pcd->ep0state == EP0_IN_DATA_PHASE) {
51660 + ep0_out_start(core_if, pcd);
51661 + }
51662 +
51663 + goto exit_xfercompl;
51664 + } else {
51665 + /* Prepare for more setup packets */
51666 + DWC_DEBUGPL(DBG_PCDV,
51667 + "EP0_IDLE SR=1 setup=0 new setup comes\n");
51668 + ep0_out_start(core_if, pcd);
51669 + }
51670 + }
51671 + } else {
51672 + dwc_otg_pcd_request_t *req;
51673 + dev_dma_desc_sts_t status = {.d32 = 0};
51674 + diepint_data_t diepint0;
51675 + diepint0.d32 = DWC_READ_REG32(&core_if->dev_if->
51676 + in_ep_regs[0]->diepint);
51677 +
51678 + if (pcd->ep0state == EP0_STALL || pcd->ep0state == EP0_DISCONNECT) {
51679 + DWC_ERROR("EP0 is stalled/disconnected\n");
51680 + }
51681 +
51682 + /* Clear IN xfercompl if set */
51683 + if (diepint0.b.xfercompl && (pcd->ep0state == EP0_IN_STATUS_PHASE
51684 + || pcd->ep0state == EP0_IN_DATA_PHASE)) {
51685 + DWC_WRITE_REG32(&core_if->dev_if->
51686 + in_ep_regs[0]->diepint, diepint0.d32);
51687 + }
51688 +
51689 + status.d32 = core_if->dev_if->setup_desc_addr[core_if->
51690 + dev_if->setup_desc_index]->status.d32;
51691 +
51692 + if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len
51693 + && (pcd->ep0state == EP0_OUT_DATA_PHASE))
51694 + status.d32 = core_if->dev_if->out_desc_addr->status.d32;
51695 + if (pcd->ep0state == EP0_OUT_STATUS_PHASE)
51696 + status.d32 = status.d32 = core_if->dev_if->
51697 + out_desc_addr->status.d32;
51698 +
51699 + if (status.b.sr) {
51700 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
51701 + DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n");
51702 + } else {
51703 + DWC_DEBUGPL(DBG_PCDV, "complete req!!\n");
51704 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
51705 + if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len &&
51706 + pcd->ep0state == EP0_OUT_DATA_PHASE) {
51707 + /* Read arrived setup packet from req->buf */
51708 + dwc_memcpy(&pcd->setup_pkt->req,
51709 + req->buf + ep->dwc_ep.xfer_count, 8);
51710 + }
51711 + req->actual = ep->dwc_ep.xfer_count;
51712 + dwc_otg_request_done(ep, req, -ECONNRESET);
51713 + ep->dwc_ep.start_xfer_buff = 0;
51714 + ep->dwc_ep.xfer_buff = 0;
51715 + ep->dwc_ep.xfer_len = 0;
51716 + }
51717 + pcd->ep0state = EP0_IDLE;
51718 + if (doepint.b.setup) {
51719 + DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n");
51720 + /* Data stage started, clear setup */
51721 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51722 + doepint.b.setup = 0;
51723 + handle_ep0(pcd);
51724 + /* Prepare for setup packets if ep0in was enabled*/
51725 + if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
51726 + ep0_out_start(core_if, pcd);
51727 + }
51728 +
51729 + goto exit_xfercompl;
51730 + } else {
51731 + /* Prepare for more setup packets */
51732 + DWC_DEBUGPL(DBG_PCDV,
51733 + "EP0_IDLE SR=1 setup=0 new setup comes 2\n");
51734 + ep0_out_start(core_if, pcd);
51735 + }
51736 + }
51737 + }
51738 + }
51739 + if (core_if->snpsid >= OTG_CORE_REV_2_94a && core_if->dma_enable
51740 + && core_if->dma_desc_enable == 0) {
51741 + doepint_data_t doepint_temp = {.d32 = 0};
51742 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
51743 + doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if->
51744 + out_ep_regs[ep->dwc_ep.num]->doepint);
51745 + doeptsize0.d32 = DWC_READ_REG32(&core_if->dev_if->
51746 + out_ep_regs[ep->dwc_ep.num]->doeptsiz);
51747 + if (pcd->ep0state == EP0_IDLE) {
51748 + if (doepint_temp.b.sr) {
51749 + CLEAR_OUT_EP_INTR(core_if, epnum, sr);
51750 + }
51751 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51752 + out_ep_regs[0]->doepint);
51753 + if (doeptsize0.b.supcnt == 3) {
51754 + DWC_DEBUGPL(DBG_ANY, "Rolling over!!!!!!!\n");
51755 + ep->dwc_ep.stp_rollover = 1;
51756 + }
51757 + if (doepint.b.setup) {
51758 +retry:
51759 + /* Already started data stage, clear setup */
51760 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51761 + doepint.b.setup = 0;
51762 + handle_ep0(pcd);
51763 + ep->dwc_ep.stp_rollover = 0;
51764 + /* Prepare for more setup packets */
51765 + if (pcd->ep0state == EP0_IN_STATUS_PHASE ||
51766 + pcd->ep0state == EP0_IN_DATA_PHASE) {
51767 + ep0_out_start(core_if, pcd);
51768 + }
51769 + goto exit_xfercompl;
51770 + } else {
51771 + /* Prepare for more setup packets */
51772 + DWC_DEBUGPL(DBG_ANY,
51773 + "EP0_IDLE SR=1 setup=0 new setup comes\n");
51774 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51775 + out_ep_regs[0]->doepint);
51776 + if(doepint.b.setup)
51777 + goto retry;
51778 + ep0_out_start(core_if, pcd);
51779 + }
51780 + } else {
51781 + dwc_otg_pcd_request_t *req;
51782 + diepint_data_t diepint0 = {.d32 = 0};
51783 + doepint_data_t doepint_temp = {.d32 = 0};
51784 + depctl_data_t diepctl0;
51785 + diepint0.d32 = DWC_READ_REG32(&core_if->dev_if->
51786 + in_ep_regs[0]->diepint);
51787 + diepctl0.d32 = DWC_READ_REG32(&core_if->dev_if->
51788 + in_ep_regs[0]->diepctl);
51789 +
51790 + if (pcd->ep0state == EP0_IN_DATA_PHASE
51791 + || pcd->ep0state == EP0_IN_STATUS_PHASE) {
51792 + if (diepint0.b.xfercompl) {
51793 + DWC_WRITE_REG32(&core_if->dev_if->
51794 + in_ep_regs[0]->diepint, diepint0.d32);
51795 + }
51796 + if (diepctl0.b.epena) {
51797 + diepint_data_t diepint = {.d32 = 0};
51798 + diepctl0.b.snak = 1;
51799 + DWC_WRITE_REG32(&core_if->dev_if->
51800 + in_ep_regs[0]->diepctl, diepctl0.d32);
51801 + do {
51802 + dwc_udelay(10);
51803 + diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51804 + in_ep_regs[0]->diepint);
51805 + } while (!diepint.b.inepnakeff);
51806 + diepint.b.inepnakeff = 1;
51807 + DWC_WRITE_REG32(&core_if->dev_if->
51808 + in_ep_regs[0]->diepint, diepint.d32);
51809 + diepctl0.d32 = 0;
51810 + diepctl0.b.epdis = 1;
51811 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl,
51812 + diepctl0.d32);
51813 + do {
51814 + dwc_udelay(10);
51815 + diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51816 + in_ep_regs[0]->diepint);
51817 + } while (!diepint.b.epdisabled);
51818 + diepint.b.epdisabled = 1;
51819 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepint,
51820 + diepint.d32);
51821 + }
51822 + }
51823 + doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if->
51824 + out_ep_regs[ep->dwc_ep.num]->doepint);
51825 + if (doepint_temp.b.sr) {
51826 + CLEAR_OUT_EP_INTR(core_if, epnum, sr);
51827 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
51828 + DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n");
51829 + } else {
51830 + DWC_DEBUGPL(DBG_PCDV, "complete req!!\n");
51831 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
51832 + if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len &&
51833 + pcd->ep0state == EP0_OUT_DATA_PHASE) {
51834 + /* Read arrived setup packet from req->buf */
51835 + dwc_memcpy(&pcd->setup_pkt->req,
51836 + req->buf + ep->dwc_ep.xfer_count, 8);
51837 + }
51838 + req->actual = ep->dwc_ep.xfer_count;
51839 + dwc_otg_request_done(ep, req, -ECONNRESET);
51840 + ep->dwc_ep.start_xfer_buff = 0;
51841 + ep->dwc_ep.xfer_buff = 0;
51842 + ep->dwc_ep.xfer_len = 0;
51843 + }
51844 + pcd->ep0state = EP0_IDLE;
51845 + if (doepint.b.setup) {
51846 + DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n");
51847 + /* Data stage started, clear setup */
51848 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51849 + doepint.b.setup = 0;
51850 + handle_ep0(pcd);
51851 + /* Prepare for setup packets if ep0in was enabled*/
51852 + if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
51853 + ep0_out_start(core_if, pcd);
51854 + }
51855 + goto exit_xfercompl;
51856 + } else {
51857 + /* Prepare for more setup packets */
51858 + DWC_DEBUGPL(DBG_PCDV,
51859 + "EP0_IDLE SR=1 setup=0 new setup comes 2\n");
51860 + ep0_out_start(core_if, pcd);
51861 + }
51862 + }
51863 + }
51864 + }
51865 + if (core_if->dma_enable == 0 || pcd->ep0state != EP0_IDLE)
51866 + handle_ep0(pcd);
51867 +exit_xfercompl:
51868 + DWC_DEBUGPL(DBG_PCDV, "DOEPINT=%x doepint=%x\n",
51869 + dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep), doepint.d32);
51870 + } else {
51871 + if (core_if->dma_desc_enable == 0
51872 + || pcd->ep0state != EP0_IDLE)
51873 + handle_ep0(pcd);
51874 + }
51875 +#ifdef DWC_EN_ISOC
51876 + } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51877 + if (doepint.b.pktdrpsts == 0) {
51878 + /* Clear the bit in DOEPINTn for this interrupt */
51879 + CLEAR_OUT_EP_INTR(core_if,
51880 + epnum,
51881 + xfercompl);
51882 + complete_iso_ep(pcd, ep);
51883 + } else {
51884 +
51885 + doepint_data_t doepint = {.d32 = 0 };
51886 + doepint.b.xfercompl = 1;
51887 + doepint.b.pktdrpsts = 1;
51888 + DWC_WRITE_REG32
51889 + (&core_if->dev_if->out_ep_regs
51890 + [epnum]->doepint,
51891 + doepint.d32);
51892 + if (handle_iso_out_pkt_dropped
51893 + (core_if, dwc_ep)) {
51894 + complete_iso_ep(pcd,
51895 + ep);
51896 + }
51897 + }
51898 +#endif /* DWC_EN_ISOC */
51899 +#ifdef DWC_UTE_PER_IO
51900 + } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51901 + CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
51902 + if (!ep->stopped)
51903 + complete_xiso_ep(ep);
51904 +#endif /* DWC_UTE_PER_IO */
51905 + } else {
51906 + /* Clear the bit in DOEPINTn for this interrupt */
51907 + CLEAR_OUT_EP_INTR(core_if, epnum,
51908 + xfercompl);
51909 +
51910 + if (core_if->core_params->dev_out_nak) {
51911 + DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[epnum]);
51912 + pcd->core_if->ep_xfer_info[epnum].state = 0;
51913 +#ifdef DEBUG
51914 + print_memory_payload(pcd, dwc_ep);
51915 +#endif
51916 + }
51917 + complete_ep(ep);
51918 + }
51919 +
51920 + }
51921 +
51922 + /* Endpoint disable */
51923 + if (doepint.b.epdisabled) {
51924 +
51925 + /* Clear the bit in DOEPINTn for this interrupt */
51926 + CLEAR_OUT_EP_INTR(core_if, epnum, epdisabled);
51927 + if (core_if->core_params->dev_out_nak) {
51928 +#ifdef DEBUG
51929 + print_memory_payload(pcd, dwc_ep);
51930 +#endif
51931 + /* In case of timeout condition */
51932 + if (core_if->ep_xfer_info[epnum].state == 2) {
51933 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
51934 + dev_global_regs->dctl);
51935 + dctl.b.cgoutnak = 1;
51936 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
51937 + dctl.d32);
51938 + /* Unmask goutnakeff interrupt which was masked
51939 + * during handle nak out interrupt */
51940 + gintmsk.b.goutnakeff = 1;
51941 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
51942 + 0, gintmsk.d32);
51943 +
51944 + complete_ep(ep);
51945 + }
51946 + }
51947 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
51948 + {
51949 + dctl_data_t dctl;
51950 + gintmsk_data_t intr_mask = {.d32 = 0};
51951 + dwc_otg_pcd_request_t *req = 0;
51952 +
51953 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
51954 + dev_global_regs->dctl);
51955 + dctl.b.cgoutnak = 1;
51956 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
51957 + dctl.d32);
51958 +
51959 + intr_mask.d32 = 0;
51960 + intr_mask.b.incomplisoout = 1;
51961 +
51962 + /* Get any pending requests */
51963 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
51964 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
51965 + if (!req) {
51966 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
51967 + } else {
51968 + dwc_otg_request_done(ep, req, 0);
51969 + start_next_request(ep);
51970 + }
51971 + } else {
51972 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
51973 + }
51974 + }
51975 + }
51976 + /* AHB Error */
51977 + if (doepint.b.ahberr) {
51978 + DWC_ERROR("EP%d OUT AHB Error\n", epnum);
51979 + DWC_ERROR("EP%d DEPDMA=0x%08x \n",
51980 + epnum, core_if->dev_if->out_ep_regs[epnum]->doepdma);
51981 + CLEAR_OUT_EP_INTR(core_if, epnum, ahberr);
51982 + }
51983 + /* Setup Phase Done (contorl EPs) */
51984 + if (doepint.b.setup) {
51985 +#ifdef DEBUG_EP0
51986 + DWC_DEBUGPL(DBG_PCD, "EP%d SETUP Done\n", epnum);
51987 +#endif
51988 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51989 +
51990 + handle_ep0(pcd);
51991 + }
51992 +
51993 + /** OUT EP BNA Intr */
51994 + if (doepint.b.bna) {
51995 + CLEAR_OUT_EP_INTR(core_if, epnum, bna);
51996 + if (core_if->dma_desc_enable) {
51997 +#ifdef DWC_EN_ISOC
51998 + if (dwc_ep->type ==
51999 + DWC_OTG_EP_TYPE_ISOC) {
52000 + /*
52001 + * This checking is performed to prevent first "false" BNA
52002 + * handling occuring right after reconnect
52003 + */
52004 + if (dwc_ep->next_frame !=
52005 + 0xffffffff)
52006 + dwc_otg_pcd_handle_iso_bna(ep);
52007 + } else
52008 +#endif /* DWC_EN_ISOC */
52009 + {
52010 + dwc_otg_pcd_handle_noniso_bna(ep);
52011 + }
52012 + }
52013 + }
52014 + /* Babble Interrupt */
52015 + if (doepint.b.babble) {
52016 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT Babble\n",
52017 + epnum);
52018 + handle_out_ep_babble_intr(pcd, epnum);
52019 +
52020 + CLEAR_OUT_EP_INTR(core_if, epnum, babble);
52021 + }
52022 + if (doepint.b.outtknepdis) {
52023 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT Token received when EP is \
52024 + disabled\n",epnum);
52025 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
52026 + doepmsk_data_t doepmsk = {.d32 = 0};
52027 + ep->dwc_ep.frame_num = core_if->frame_num;
52028 + if (ep->dwc_ep.bInterval > 1) {
52029 + depctl_data_t depctl;
52030 + depctl.d32 = DWC_READ_REG32(&core_if->dev_if->
52031 + out_ep_regs[epnum]->doepctl);
52032 + if (ep->dwc_ep.frame_num & 0x1) {
52033 + depctl.b.setd1pid = 1;
52034 + depctl.b.setd0pid = 0;
52035 + } else {
52036 + depctl.b.setd0pid = 1;
52037 + depctl.b.setd1pid = 0;
52038 + }
52039 + DWC_WRITE_REG32(&core_if->dev_if->
52040 + out_ep_regs[epnum]->doepctl, depctl.d32);
52041 + }
52042 + start_next_request(ep);
52043 + doepmsk.b.outtknepdis = 1;
52044 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
52045 + doepmsk.d32, 0);
52046 + }
52047 + CLEAR_OUT_EP_INTR(core_if, epnum, outtknepdis);
52048 + }
52049 +
52050 + /* NAK Interrutp */
52051 + if (doepint.b.nak) {
52052 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT NAK\n", epnum);
52053 + handle_out_ep_nak_intr(pcd, epnum);
52054 +
52055 + CLEAR_OUT_EP_INTR(core_if, epnum, nak);
52056 + }
52057 + /* NYET Interrutp */
52058 + if (doepint.b.nyet) {
52059 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT NYET\n", epnum);
52060 + handle_out_ep_nyet_intr(pcd, epnum);
52061 +
52062 + CLEAR_OUT_EP_INTR(core_if, epnum, nyet);
52063 + }
52064 + }
52065 +
52066 + epnum++;
52067 + ep_intr >>= 1;
52068 + }
52069 +
52070 + return 1;
52071 +
52072 +#undef CLEAR_OUT_EP_INTR
52073 +}
52074 +static int drop_transfer(uint32_t trgt_fr, uint32_t curr_fr, uint8_t frm_overrun)
52075 +{
52076 + int retval = 0;
52077 + if(!frm_overrun && curr_fr >= trgt_fr)
52078 + retval = 1;
52079 + else if (frm_overrun
52080 + && (curr_fr >= trgt_fr && ((curr_fr - trgt_fr) < 0x3FFF / 2)))
52081 + retval = 1;
52082 + return retval;
52083 +}
52084 +/**
52085 + * Incomplete ISO IN Transfer Interrupt.
52086 + * This interrupt indicates one of the following conditions occurred
52087 + * while transmitting an ISOC transaction.
52088 + * - Corrupted IN Token for ISOC EP.
52089 + * - Packet not complete in FIFO.
52090 + * The follow actions will be taken:
52091 + * -# Determine the EP
52092 + * -# Set incomplete flag in dwc_ep structure
52093 + * -# Disable EP; when "Endpoint Disabled" interrupt is received
52094 + * Flush FIFO
52095 + */
52096 +int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr(dwc_otg_pcd_t * pcd)
52097 +{
52098 + gintsts_data_t gintsts;
52099 +
52100 +#ifdef DWC_EN_ISOC
52101 + dwc_otg_dev_if_t *dev_if;
52102 + deptsiz_data_t deptsiz = {.d32 = 0 };
52103 + depctl_data_t depctl = {.d32 = 0 };
52104 + dsts_data_t dsts = {.d32 = 0 };
52105 + dwc_ep_t *dwc_ep;
52106 + int i;
52107 +
52108 + dev_if = GET_CORE_IF(pcd)->dev_if;
52109 +
52110 + for (i = 1; i <= dev_if->num_in_eps; ++i) {
52111 + dwc_ep = &pcd->in_ep[i].dwc_ep;
52112 + if (dwc_ep->active && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
52113 + deptsiz.d32 =
52114 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
52115 + depctl.d32 =
52116 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
52117 +
52118 + if (depctl.b.epdis && deptsiz.d32) {
52119 + set_current_pkt_info(GET_CORE_IF(pcd), dwc_ep);
52120 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
52121 + dwc_ep->cur_pkt = 0;
52122 + dwc_ep->proc_buf_num =
52123 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
52124 +
52125 + if (dwc_ep->proc_buf_num) {
52126 + dwc_ep->cur_pkt_addr =
52127 + dwc_ep->xfer_buff1;
52128 + dwc_ep->cur_pkt_dma_addr =
52129 + dwc_ep->dma_addr1;
52130 + } else {
52131 + dwc_ep->cur_pkt_addr =
52132 + dwc_ep->xfer_buff0;
52133 + dwc_ep->cur_pkt_dma_addr =
52134 + dwc_ep->dma_addr0;
52135 + }
52136 +
52137 + }
52138 +
52139 + dsts.d32 =
52140 + DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
52141 + dev_global_regs->dsts);
52142 + dwc_ep->next_frame = dsts.b.soffn;
52143 +
52144 + dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
52145 + (pcd),
52146 + dwc_ep);
52147 + }
52148 + }
52149 + }
52150 +
52151 +#else
52152 + depctl_data_t depctl = {.d32 = 0 };
52153 + dwc_ep_t *dwc_ep;
52154 + dwc_otg_dev_if_t *dev_if;
52155 + int i;
52156 + dev_if = GET_CORE_IF(pcd)->dev_if;
52157 +
52158 + DWC_DEBUGPL(DBG_PCD,"Incomplete ISO IN \n");
52159 +
52160 + for (i = 1; i <= dev_if->num_in_eps; ++i) {
52161 + dwc_ep = &pcd->in_ep[i-1].dwc_ep;
52162 + depctl.d32 =
52163 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
52164 + if (depctl.b.epena && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
52165 + if (drop_transfer(dwc_ep->frame_num, GET_CORE_IF(pcd)->frame_num,
52166 + dwc_ep->frm_overrun))
52167 + {
52168 + depctl.d32 =
52169 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
52170 + depctl.b.snak = 1;
52171 + depctl.b.epdis = 1;
52172 + DWC_MODIFY_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32, depctl.d32);
52173 + }
52174 + }
52175 + }
52176 +
52177 + /*intr_mask.b.incomplisoin = 1;
52178 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
52179 + intr_mask.d32, 0); */
52180 +#endif //DWC_EN_ISOC
52181 +
52182 + /* Clear interrupt */
52183 + gintsts.d32 = 0;
52184 + gintsts.b.incomplisoin = 1;
52185 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52186 + gintsts.d32);
52187 +
52188 + return 1;
52189 +}
52190 +
52191 +/**
52192 + * Incomplete ISO OUT Transfer Interrupt.
52193 + *
52194 + * This interrupt indicates that the core has dropped an ISO OUT
52195 + * packet. The following conditions can be the cause:
52196 + * - FIFO Full, the entire packet would not fit in the FIFO.
52197 + * - CRC Error
52198 + * - Corrupted Token
52199 + * The follow actions will be taken:
52200 + * -# Determine the EP
52201 + * -# Set incomplete flag in dwc_ep structure
52202 + * -# Read any data from the FIFO
52203 + * -# Disable EP. When "Endpoint Disabled" interrupt is received
52204 + * re-enable EP.
52205 + */
52206 +int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr(dwc_otg_pcd_t * pcd)
52207 +{
52208 +
52209 + gintsts_data_t gintsts;
52210 +
52211 +#ifdef DWC_EN_ISOC
52212 + dwc_otg_dev_if_t *dev_if;
52213 + deptsiz_data_t deptsiz = {.d32 = 0 };
52214 + depctl_data_t depctl = {.d32 = 0 };
52215 + dsts_data_t dsts = {.d32 = 0 };
52216 + dwc_ep_t *dwc_ep;
52217 + int i;
52218 +
52219 + dev_if = GET_CORE_IF(pcd)->dev_if;
52220 +
52221 + for (i = 1; i <= dev_if->num_out_eps; ++i) {
52222 + dwc_ep = &pcd->in_ep[i].dwc_ep;
52223 + if (pcd->out_ep[i].dwc_ep.active &&
52224 + pcd->out_ep[i].dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
52225 + deptsiz.d32 =
52226 + DWC_READ_REG32(&dev_if->out_ep_regs[i]->doeptsiz);
52227 + depctl.d32 =
52228 + DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
52229 +
52230 + if (depctl.b.epdis && deptsiz.d32) {
52231 + set_current_pkt_info(GET_CORE_IF(pcd),
52232 + &pcd->out_ep[i].dwc_ep);
52233 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
52234 + dwc_ep->cur_pkt = 0;
52235 + dwc_ep->proc_buf_num =
52236 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
52237 +
52238 + if (dwc_ep->proc_buf_num) {
52239 + dwc_ep->cur_pkt_addr =
52240 + dwc_ep->xfer_buff1;
52241 + dwc_ep->cur_pkt_dma_addr =
52242 + dwc_ep->dma_addr1;
52243 + } else {
52244 + dwc_ep->cur_pkt_addr =
52245 + dwc_ep->xfer_buff0;
52246 + dwc_ep->cur_pkt_dma_addr =
52247 + dwc_ep->dma_addr0;
52248 + }
52249 +
52250 + }
52251 +
52252 + dsts.d32 =
52253 + DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
52254 + dev_global_regs->dsts);
52255 + dwc_ep->next_frame = dsts.b.soffn;
52256 +
52257 + dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
52258 + (pcd),
52259 + dwc_ep);
52260 + }
52261 + }
52262 + }
52263 +#else
52264 + /** @todo implement ISR */
52265 + gintmsk_data_t intr_mask = {.d32 = 0 };
52266 + dwc_otg_core_if_t *core_if;
52267 + deptsiz_data_t deptsiz = {.d32 = 0 };
52268 + depctl_data_t depctl = {.d32 = 0 };
52269 + dctl_data_t dctl = {.d32 = 0 };
52270 + dwc_ep_t *dwc_ep = NULL;
52271 + int i;
52272 + core_if = GET_CORE_IF(pcd);
52273 +
52274 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
52275 + dwc_ep = &pcd->out_ep[i].dwc_ep;
52276 + depctl.d32 =
52277 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
52278 + if (depctl.b.epena && depctl.b.dpid == (core_if->frame_num & 0x1)) {
52279 + core_if->dev_if->isoc_ep = dwc_ep;
52280 + deptsiz.d32 =
52281 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz);
52282 + break;
52283 + }
52284 + }
52285 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
52286 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
52287 + intr_mask.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
52288 +
52289 + if (!intr_mask.b.goutnakeff) {
52290 + /* Unmask it */
52291 + intr_mask.b.goutnakeff = 1;
52292 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32);
52293 + }
52294 + if (!gintsts.b.goutnakeff) {
52295 + dctl.b.sgoutnak = 1;
52296 + }
52297 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
52298 +
52299 + depctl.d32 = DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
52300 + if (depctl.b.epena) {
52301 + depctl.b.epdis = 1;
52302 + depctl.b.snak = 1;
52303 + }
52304 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl, depctl.d32);
52305 +
52306 + intr_mask.d32 = 0;
52307 + intr_mask.b.incomplisoout = 1;
52308 +
52309 +#endif /* DWC_EN_ISOC */
52310 +
52311 + /* Clear interrupt */
52312 + gintsts.d32 = 0;
52313 + gintsts.b.incomplisoout = 1;
52314 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52315 + gintsts.d32);
52316 +
52317 + return 1;
52318 +}
52319 +
52320 +/**
52321 + * This function handles the Global IN NAK Effective interrupt.
52322 + *
52323 + */
52324 +int32_t dwc_otg_pcd_handle_in_nak_effective(dwc_otg_pcd_t * pcd)
52325 +{
52326 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
52327 + depctl_data_t diepctl = {.d32 = 0 };
52328 + gintmsk_data_t intr_mask = {.d32 = 0 };
52329 + gintsts_data_t gintsts;
52330 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
52331 + int i;
52332 +
52333 + DWC_DEBUGPL(DBG_PCD, "Global IN NAK Effective\n");
52334 +
52335 + /* Disable all active IN EPs */
52336 + for (i = 0; i <= dev_if->num_in_eps; i++) {
52337 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
52338 + if (!(diepctl.b.eptype & 1) && diepctl.b.epena) {
52339 + if (core_if->start_predict > 0)
52340 + core_if->start_predict++;
52341 + diepctl.b.epdis = 1;
52342 + diepctl.b.snak = 1;
52343 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, diepctl.d32);
52344 + }
52345 + }
52346 +
52347 +
52348 + /* Disable the Global IN NAK Effective Interrupt */
52349 + intr_mask.b.ginnakeff = 1;
52350 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
52351 + intr_mask.d32, 0);
52352 +
52353 + /* Clear interrupt */
52354 + gintsts.d32 = 0;
52355 + gintsts.b.ginnakeff = 1;
52356 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52357 + gintsts.d32);
52358 +
52359 + return 1;
52360 +}
52361 +
52362 +/**
52363 + * OUT NAK Effective.
52364 + *
52365 + */
52366 +int32_t dwc_otg_pcd_handle_out_nak_effective(dwc_otg_pcd_t * pcd)
52367 +{
52368 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
52369 + gintmsk_data_t intr_mask = {.d32 = 0 };
52370 + gintsts_data_t gintsts;
52371 + depctl_data_t doepctl;
52372 + int i;
52373 +
52374 + /* Disable the Global OUT NAK Effective Interrupt */
52375 + intr_mask.b.goutnakeff = 1;
52376 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
52377 + intr_mask.d32, 0);
52378 +
52379 + /* If DEV OUT NAK enabled*/
52380 + if (pcd->core_if->core_params->dev_out_nak) {
52381 + /* Run over all out endpoints to determine the ep number on
52382 + * which the timeout has happened
52383 + */
52384 + for (i = 0; i <= dev_if->num_out_eps; i++) {
52385 + if ( pcd->core_if->ep_xfer_info[i].state == 2 )
52386 + break;
52387 + }
52388 + if (i > dev_if->num_out_eps) {
52389 + dctl_data_t dctl;
52390 + dctl.d32 =
52391 + DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
52392 + dctl.b.cgoutnak = 1;
52393 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl,
52394 + dctl.d32);
52395 + goto out;
52396 + }
52397 +
52398 + /* Disable the endpoint */
52399 + doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
52400 + if (doepctl.b.epena) {
52401 + doepctl.b.epdis = 1;
52402 + doepctl.b.snak = 1;
52403 + }
52404 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
52405 + return 1;
52406 + }
52407 + /* We come here from Incomplete ISO OUT handler */
52408 + if (dev_if->isoc_ep) {
52409 + dwc_ep_t *dwc_ep = (dwc_ep_t *)dev_if->isoc_ep;
52410 + uint32_t epnum = dwc_ep->num;
52411 + doepint_data_t doepint;
52412 + doepint.d32 =
52413 + DWC_READ_REG32(&dev_if->out_ep_regs[dwc_ep->num]->doepint);
52414 + dev_if->isoc_ep = NULL;
52415 + doepctl.d32 =
52416 + DWC_READ_REG32(&dev_if->out_ep_regs[epnum]->doepctl);
52417 + DWC_PRINTF("Before disable DOEPCTL = %08x\n", doepctl.d32);
52418 + if (doepctl.b.epena) {
52419 + doepctl.b.epdis = 1;
52420 + doepctl.b.snak = 1;
52421 + }
52422 + DWC_WRITE_REG32(&dev_if->out_ep_regs[epnum]->doepctl,
52423 + doepctl.d32);
52424 + return 1;
52425 + } else
52426 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
52427 + "Global OUT NAK Effective\n");
52428 +
52429 +out:
52430 + /* Clear interrupt */
52431 + gintsts.d32 = 0;
52432 + gintsts.b.goutnakeff = 1;
52433 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52434 + gintsts.d32);
52435 +
52436 + return 1;
52437 +}
52438 +
52439 +/**
52440 + * PCD interrupt handler.
52441 + *
52442 + * The PCD handles the device interrupts. Many conditions can cause a
52443 + * device interrupt. When an interrupt occurs, the device interrupt
52444 + * service routine determines the cause of the interrupt and
52445 + * dispatches handling to the appropriate function. These interrupt
52446 + * handling functions are described below.
52447 + *
52448 + * All interrupt registers are processed from LSB to MSB.
52449 + *
52450 + */
52451 +int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd)
52452 +{
52453 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
52454 +#ifdef VERBOSE
52455 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
52456 +#endif
52457 + gintsts_data_t gintr_status;
52458 + int32_t retval = 0;
52459 +
52460 + /* Exit from ISR if core is hibernated */
52461 + if (core_if->hibernation_suspend == 1) {
52462 + return retval;
52463 + }
52464 +#ifdef VERBOSE
52465 + DWC_DEBUGPL(DBG_ANY, "%s() gintsts=%08x gintmsk=%08x\n",
52466 + __func__,
52467 + DWC_READ_REG32(&global_regs->gintsts),
52468 + DWC_READ_REG32(&global_regs->gintmsk));
52469 +#endif
52470 +
52471 + if (dwc_otg_is_device_mode(core_if)) {
52472 + DWC_SPINLOCK(pcd->lock);
52473 +#ifdef VERBOSE
52474 + DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%08x gintmsk=%08x\n",
52475 + __func__,
52476 + DWC_READ_REG32(&global_regs->gintsts),
52477 + DWC_READ_REG32(&global_regs->gintmsk));
52478 +#endif
52479 +
52480 + gintr_status.d32 = dwc_otg_read_core_intr(core_if);
52481 +
52482 + DWC_DEBUGPL(DBG_PCDV, "%s: gintsts&gintmsk=%08x\n",
52483 + __func__, gintr_status.d32);
52484 +
52485 + if (gintr_status.b.sofintr) {
52486 + retval |= dwc_otg_pcd_handle_sof_intr(pcd);
52487 + }
52488 + if (gintr_status.b.rxstsqlvl) {
52489 + retval |=
52490 + dwc_otg_pcd_handle_rx_status_q_level_intr(pcd);
52491 + }
52492 + if (gintr_status.b.nptxfempty) {
52493 + retval |= dwc_otg_pcd_handle_np_tx_fifo_empty_intr(pcd);
52494 + }
52495 + if (gintr_status.b.goutnakeff) {
52496 + retval |= dwc_otg_pcd_handle_out_nak_effective(pcd);
52497 + }
52498 + if (gintr_status.b.i2cintr) {
52499 + retval |= dwc_otg_pcd_handle_i2c_intr(pcd);
52500 + }
52501 + if (gintr_status.b.erlysuspend) {
52502 + retval |= dwc_otg_pcd_handle_early_suspend_intr(pcd);
52503 + }
52504 + if (gintr_status.b.usbreset) {
52505 + retval |= dwc_otg_pcd_handle_usb_reset_intr(pcd);
52506 + }
52507 + if (gintr_status.b.enumdone) {
52508 + retval |= dwc_otg_pcd_handle_enum_done_intr(pcd);
52509 + }
52510 + if (gintr_status.b.isooutdrop) {
52511 + retval |=
52512 + dwc_otg_pcd_handle_isoc_out_packet_dropped_intr
52513 + (pcd);
52514 + }
52515 + if (gintr_status.b.eopframe) {
52516 + retval |=
52517 + dwc_otg_pcd_handle_end_periodic_frame_intr(pcd);
52518 + }
52519 + if (gintr_status.b.inepint) {
52520 + if (!core_if->multiproc_int_enable) {
52521 + retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
52522 + }
52523 + }
52524 + if (gintr_status.b.outepintr) {
52525 + if (!core_if->multiproc_int_enable) {
52526 + retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
52527 + }
52528 + }
52529 + if (gintr_status.b.epmismatch) {
52530 + retval |= dwc_otg_pcd_handle_ep_mismatch_intr(pcd);
52531 + }
52532 + if (gintr_status.b.fetsusp) {
52533 + retval |= dwc_otg_pcd_handle_ep_fetsusp_intr(pcd);
52534 + }
52535 + if (gintr_status.b.ginnakeff) {
52536 + retval |= dwc_otg_pcd_handle_in_nak_effective(pcd);
52537 + }
52538 + if (gintr_status.b.incomplisoin) {
52539 + retval |=
52540 + dwc_otg_pcd_handle_incomplete_isoc_in_intr(pcd);
52541 + }
52542 + if (gintr_status.b.incomplisoout) {
52543 + retval |=
52544 + dwc_otg_pcd_handle_incomplete_isoc_out_intr(pcd);
52545 + }
52546 +
52547 + /* In MPI mode Device Endpoints interrupts are asserted
52548 + * without setting outepintr and inepint bits set, so these
52549 + * Interrupt handlers are called without checking these bit-fields
52550 + */
52551 + if (core_if->multiproc_int_enable) {
52552 + retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
52553 + retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
52554 + }
52555 +#ifdef VERBOSE
52556 + DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%0x\n", __func__,
52557 + DWC_READ_REG32(&global_regs->gintsts));
52558 +#endif
52559 + DWC_SPINUNLOCK(pcd->lock);
52560 + }
52561 + return retval;
52562 +}
52563 +
52564 +#endif /* DWC_HOST_ONLY */
52565 --- /dev/null
52566 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
52567 @@ -0,0 +1,1358 @@
52568 + /* ==========================================================================
52569 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_linux.c $
52570 + * $Revision: #21 $
52571 + * $Date: 2012/08/10 $
52572 + * $Change: 2047372 $
52573 + *
52574 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
52575 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
52576 + * otherwise expressly agreed to in writing between Synopsys and you.
52577 + *
52578 + * The Software IS NOT an item of Licensed Software or Licensed Product under
52579 + * any End User Software License Agreement or Agreement for Licensed Product
52580 + * with Synopsys or any supplement thereto. You are permitted to use and
52581 + * redistribute this Software in source and binary forms, with or without
52582 + * modification, provided that redistributions of source code must retain this
52583 + * notice. You may not view, use, disclose, copy or distribute this file or
52584 + * any information contained herein except pursuant to this license grant from
52585 + * Synopsys. If you do not agree with this notice, including the disclaimer
52586 + * below, then you are not authorized to use the Software.
52587 + *
52588 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
52589 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52590 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52591 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
52592 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
52593 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
52594 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
52595 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52596 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52597 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
52598 + * DAMAGE.
52599 + * ========================================================================== */
52600 +#ifndef DWC_HOST_ONLY
52601 +
52602 +/** @file
52603 + * This file implements the Peripheral Controller Driver.
52604 + *
52605 + * The Peripheral Controller Driver (PCD) is responsible for
52606 + * translating requests from the Function Driver into the appropriate
52607 + * actions on the DWC_otg controller. It isolates the Function Driver
52608 + * from the specifics of the controller by providing an API to the
52609 + * Function Driver.
52610 + *
52611 + * The Peripheral Controller Driver for Linux will implement the
52612 + * Gadget API, so that the existing Gadget drivers can be used.
52613 + * (Gadget Driver is the Linux terminology for a Function Driver.)
52614 + *
52615 + * The Linux Gadget API is defined in the header file
52616 + * <code><linux/usb_gadget.h></code>. The USB EP operations API is
52617 + * defined in the structure <code>usb_ep_ops</code> and the USB
52618 + * Controller API is defined in the structure
52619 + * <code>usb_gadget_ops</code>.
52620 + *
52621 + */
52622 +
52623 +#include "dwc_otg_os_dep.h"
52624 +#include "dwc_otg_pcd_if.h"
52625 +#include "dwc_otg_pcd.h"
52626 +#include "dwc_otg_driver.h"
52627 +#include "dwc_otg_dbg.h"
52628 +
52629 +static struct gadget_wrapper {
52630 + dwc_otg_pcd_t *pcd;
52631 +
52632 + struct usb_gadget gadget;
52633 + struct usb_gadget_driver *driver;
52634 +
52635 + struct usb_ep ep0;
52636 + struct usb_ep in_ep[16];
52637 + struct usb_ep out_ep[16];
52638 +
52639 +} *gadget_wrapper;
52640 +
52641 +/* Display the contents of the buffer */
52642 +extern void dump_msg(const u8 * buf, unsigned int length);
52643 +/**
52644 + * Get the dwc_otg_pcd_ep_t* from usb_ep* pointer - NULL in case
52645 + * if the endpoint is not found
52646 + */
52647 +static struct dwc_otg_pcd_ep *ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
52648 +{
52649 + int i;
52650 + if (pcd->ep0.priv == handle) {
52651 + return &pcd->ep0;
52652 + }
52653 +
52654 + for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
52655 + if (pcd->in_ep[i].priv == handle)
52656 + return &pcd->in_ep[i];
52657 + if (pcd->out_ep[i].priv == handle)
52658 + return &pcd->out_ep[i];
52659 + }
52660 +
52661 + return NULL;
52662 +}
52663 +
52664 +/* USB Endpoint Operations */
52665 +/*
52666 + * The following sections briefly describe the behavior of the Gadget
52667 + * API endpoint operations implemented in the DWC_otg driver
52668 + * software. Detailed descriptions of the generic behavior of each of
52669 + * these functions can be found in the Linux header file
52670 + * include/linux/usb_gadget.h.
52671 + *
52672 + * The Gadget API provides wrapper functions for each of the function
52673 + * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper
52674 + * function, which then calls the underlying PCD function. The
52675 + * following sections are named according to the wrapper
52676 + * functions. Within each section, the corresponding DWC_otg PCD
52677 + * function name is specified.
52678 + *
52679 + */
52680 +
52681 +/**
52682 + * This function is called by the Gadget Driver for each EP to be
52683 + * configured for the current configuration (SET_CONFIGURATION).
52684 + *
52685 + * This function initializes the dwc_otg_ep_t data structure, and then
52686 + * calls dwc_otg_ep_activate.
52687 + */
52688 +static int ep_enable(struct usb_ep *usb_ep,
52689 + const struct usb_endpoint_descriptor *ep_desc)
52690 +{
52691 + int retval;
52692 +
52693 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, ep_desc);
52694 +
52695 + if (!usb_ep || !ep_desc || ep_desc->bDescriptorType != USB_DT_ENDPOINT) {
52696 + DWC_WARN("%s, bad ep or descriptor\n", __func__);
52697 + return -EINVAL;
52698 + }
52699 + if (usb_ep == &gadget_wrapper->ep0) {
52700 + DWC_WARN("%s, bad ep(0)\n", __func__);
52701 + return -EINVAL;
52702 + }
52703 +
52704 + /* Check FIFO size? */
52705 + if (!ep_desc->wMaxPacketSize) {
52706 + DWC_WARN("%s, bad %s maxpacket\n", __func__, usb_ep->name);
52707 + return -ERANGE;
52708 + }
52709 +
52710 + if (!gadget_wrapper->driver ||
52711 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52712 + DWC_WARN("%s, bogus device state\n", __func__);
52713 + return -ESHUTDOWN;
52714 + }
52715 +
52716 + /* Delete after check - MAS */
52717 +#if 0
52718 + nat = (uint32_t) ep_desc->wMaxPacketSize;
52719 + printk(KERN_ALERT "%s: nat (before) =%d\n", __func__, nat);
52720 + nat = (nat >> 11) & 0x03;
52721 + printk(KERN_ALERT "%s: nat (after) =%d\n", __func__, nat);
52722 +#endif
52723 + retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd,
52724 + (const uint8_t *)ep_desc,
52725 + (void *)usb_ep);
52726 + if (retval) {
52727 + DWC_WARN("dwc_otg_pcd_ep_enable failed\n");
52728 + return -EINVAL;
52729 + }
52730 +
52731 + usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize);
52732 +
52733 + return 0;
52734 +}
52735 +
52736 +/**
52737 + * This function is called when an EP is disabled due to disconnect or
52738 + * change in configuration. Any pending requests will terminate with a
52739 + * status of -ESHUTDOWN.
52740 + *
52741 + * This function modifies the dwc_otg_ep_t data structure for this EP,
52742 + * and then calls dwc_otg_ep_deactivate.
52743 + */
52744 +static int ep_disable(struct usb_ep *usb_ep)
52745 +{
52746 + int retval;
52747 +
52748 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, usb_ep);
52749 + if (!usb_ep) {
52750 + DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__,
52751 + usb_ep ? usb_ep->name : NULL);
52752 + return -EINVAL;
52753 + }
52754 +
52755 + retval = dwc_otg_pcd_ep_disable(gadget_wrapper->pcd, usb_ep);
52756 + if (retval) {
52757 + retval = -EINVAL;
52758 + }
52759 +
52760 + return retval;
52761 +}
52762 +
52763 +/**
52764 + * This function allocates a request object to use with the specified
52765 + * endpoint.
52766 + *
52767 + * @param ep The endpoint to be used with with the request
52768 + * @param gfp_flags the GFP_* flags to use.
52769 + */
52770 +static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep,
52771 + gfp_t gfp_flags)
52772 +{
52773 + struct usb_request *usb_req;
52774 +
52775 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags);
52776 + if (0 == ep) {
52777 + DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
52778 + return 0;
52779 + }
52780 + usb_req = kmalloc(sizeof(*usb_req), gfp_flags);
52781 + if (0 == usb_req) {
52782 + DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n");
52783 + return 0;
52784 + }
52785 + memset(usb_req, 0, sizeof(*usb_req));
52786 + usb_req->dma = DWC_DMA_ADDR_INVALID;
52787 +
52788 + return usb_req;
52789 +}
52790 +
52791 +/**
52792 + * This function frees a request object.
52793 + *
52794 + * @param ep The endpoint associated with the request
52795 + * @param req The request being freed
52796 + */
52797 +static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req)
52798 +{
52799 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req);
52800 +
52801 + if (0 == ep || 0 == req) {
52802 + DWC_WARN("%s() %s\n", __func__,
52803 + "Invalid ep or req argument!\n");
52804 + return;
52805 + }
52806 +
52807 + kfree(req);
52808 +}
52809 +
52810 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
52811 +/**
52812 + * This function allocates an I/O buffer to be used for a transfer
52813 + * to/from the specified endpoint.
52814 + *
52815 + * @param usb_ep The endpoint to be used with with the request
52816 + * @param bytes The desired number of bytes for the buffer
52817 + * @param dma Pointer to the buffer's DMA address; must be valid
52818 + * @param gfp_flags the GFP_* flags to use.
52819 + * @return address of a new buffer or null is buffer could not be allocated.
52820 + */
52821 +static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *usb_ep, unsigned bytes,
52822 + dma_addr_t * dma, gfp_t gfp_flags)
52823 +{
52824 + void *buf;
52825 + dwc_otg_pcd_t *pcd = 0;
52826 +
52827 + pcd = gadget_wrapper->pcd;
52828 +
52829 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d,%p,%0x)\n", __func__, usb_ep, bytes,
52830 + dma, gfp_flags);
52831 +
52832 + /* Check dword alignment */
52833 + if ((bytes & 0x3UL) != 0) {
52834 + DWC_WARN("%s() Buffer size is not a multiple of"
52835 + "DWORD size (%d)", __func__, bytes);
52836 + }
52837 +
52838 + buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags);
52839 +
52840 + /* Check dword alignment */
52841 + if (((int)buf & 0x3UL) != 0) {
52842 + DWC_WARN("%s() Buffer is not DWORD aligned (%p)",
52843 + __func__, buf);
52844 + }
52845 +
52846 + return buf;
52847 +}
52848 +
52849 +/**
52850 + * This function frees an I/O buffer that was allocated by alloc_buffer.
52851 + *
52852 + * @param usb_ep the endpoint associated with the buffer
52853 + * @param buf address of the buffer
52854 + * @param dma The buffer's DMA address
52855 + * @param bytes The number of bytes of the buffer
52856 + */
52857 +static void dwc_otg_pcd_free_buffer(struct usb_ep *usb_ep, void *buf,
52858 + dma_addr_t dma, unsigned bytes)
52859 +{
52860 + dwc_otg_pcd_t *pcd = 0;
52861 +
52862 + pcd = gadget_wrapper->pcd;
52863 +
52864 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%0x,%d)\n", __func__, buf, dma, bytes);
52865 +
52866 + dma_free_coherent(NULL, bytes, buf, dma);
52867 +}
52868 +#endif
52869 +
52870 +/**
52871 + * This function is used to submit an I/O Request to an EP.
52872 + *
52873 + * - When the request completes the request's completion callback
52874 + * is called to return the request to the driver.
52875 + * - An EP, except control EPs, may have multiple requests
52876 + * pending.
52877 + * - Once submitted the request cannot be examined or modified.
52878 + * - Each request is turned into one or more packets.
52879 + * - A BULK EP can queue any amount of data; the transfer is
52880 + * packetized.
52881 + * - Zero length Packets are specified with the request 'zero'
52882 + * flag.
52883 + */
52884 +static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
52885 + gfp_t gfp_flags)
52886 +{
52887 + dwc_otg_pcd_t *pcd;
52888 + struct dwc_otg_pcd_ep *ep = NULL;
52889 + int retval = 0, is_isoc_ep = 0;
52890 + dma_addr_t dma_addr = DWC_DMA_ADDR_INVALID;
52891 +
52892 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n",
52893 + __func__, usb_ep, usb_req, gfp_flags);
52894 +
52895 + if (!usb_req || !usb_req->complete || !usb_req->buf) {
52896 + DWC_WARN("bad params\n");
52897 + return -EINVAL;
52898 + }
52899 +
52900 + if (!usb_ep) {
52901 + DWC_WARN("bad ep\n");
52902 + return -EINVAL;
52903 + }
52904 +
52905 + pcd = gadget_wrapper->pcd;
52906 + if (!gadget_wrapper->driver ||
52907 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52908 + DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
52909 + gadget_wrapper->gadget.speed);
52910 + DWC_WARN("bogus device state\n");
52911 + return -ESHUTDOWN;
52912 + }
52913 +
52914 + DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
52915 + usb_ep->name, usb_req, usb_req->length, usb_req->buf);
52916 +
52917 + usb_req->status = -EINPROGRESS;
52918 + usb_req->actual = 0;
52919 +
52920 + ep = ep_from_handle(pcd, usb_ep);
52921 + if (ep == NULL)
52922 + is_isoc_ep = 0;
52923 + else
52924 + is_isoc_ep = (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) ? 1 : 0;
52925 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
52926 + dma_addr = usb_req->dma;
52927 +#else
52928 + if (GET_CORE_IF(pcd)->dma_enable) {
52929 + dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev;
52930 + struct device *dev = NULL;
52931 +
52932 + if (otg_dev != NULL)
52933 + dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep);
52934 +
52935 + if (usb_req->length != 0 &&
52936 + usb_req->dma == DWC_DMA_ADDR_INVALID) {
52937 + dma_addr = dma_map_single(dev, usb_req->buf,
52938 + usb_req->length,
52939 + ep->dwc_ep.is_in ?
52940 + DMA_TO_DEVICE:
52941 + DMA_FROM_DEVICE);
52942 + }
52943 + }
52944 +#endif
52945 +
52946 +#ifdef DWC_UTE_PER_IO
52947 + if (is_isoc_ep == 1) {
52948 + retval = dwc_otg_pcd_xiso_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
52949 + usb_req->length, usb_req->zero, usb_req,
52950 + gfp_flags == GFP_ATOMIC ? 1 : 0, &usb_req->ext_req);
52951 + if (retval)
52952 + return -EINVAL;
52953 +
52954 + return 0;
52955 + }
52956 +#endif
52957 + retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
52958 + usb_req->length, usb_req->zero, usb_req,
52959 + gfp_flags == GFP_ATOMIC ? 1 : 0);
52960 + if (retval) {
52961 + return -EINVAL;
52962 + }
52963 +
52964 + return 0;
52965 +}
52966 +
52967 +/**
52968 + * This function cancels an I/O request from an EP.
52969 + */
52970 +static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
52971 +{
52972 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req);
52973 +
52974 + if (!usb_ep || !usb_req) {
52975 + DWC_WARN("bad argument\n");
52976 + return -EINVAL;
52977 + }
52978 + if (!gadget_wrapper->driver ||
52979 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52980 + DWC_WARN("bogus device state\n");
52981 + return -ESHUTDOWN;
52982 + }
52983 + if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) {
52984 + return -EINVAL;
52985 + }
52986 +
52987 + return 0;
52988 +}
52989 +
52990 +/**
52991 + * usb_ep_set_halt stalls an endpoint.
52992 + *
52993 + * usb_ep_clear_halt clears an endpoint halt and resets its data
52994 + * toggle.
52995 + *
52996 + * Both of these functions are implemented with the same underlying
52997 + * function. The behavior depends on the value argument.
52998 + *
52999 + * @param[in] usb_ep the Endpoint to halt or clear halt.
53000 + * @param[in] value
53001 + * - 0 means clear_halt.
53002 + * - 1 means set_halt,
53003 + * - 2 means clear stall lock flag.
53004 + * - 3 means set stall lock flag.
53005 + */
53006 +static int ep_halt(struct usb_ep *usb_ep, int value)
53007 +{
53008 + int retval = 0;
53009 +
53010 + DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value);
53011 +
53012 + if (!usb_ep) {
53013 + DWC_WARN("bad ep\n");
53014 + return -EINVAL;
53015 + }
53016 +
53017 + retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value);
53018 + if (retval == -DWC_E_AGAIN) {
53019 + return -EAGAIN;
53020 + } else if (retval) {
53021 + retval = -EINVAL;
53022 + }
53023 +
53024 + return retval;
53025 +}
53026 +
53027 +//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
53028 +#if 0
53029 +/**
53030 + * ep_wedge: sets the halt feature and ignores clear requests
53031 + *
53032 + * @usb_ep: the endpoint being wedged
53033 + *
53034 + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
53035 + * requests. If the gadget driver clears the halt status, it will
53036 + * automatically unwedge the endpoint.
53037 + *
53038 + * Returns zero on success, else negative errno. *
53039 + * Check usb_ep_set_wedge() at "usb_gadget.h" for details
53040 + */
53041 +static int ep_wedge(struct usb_ep *usb_ep)
53042 +{
53043 + int retval = 0;
53044 +
53045 + DWC_DEBUGPL(DBG_PCD, "WEDGE %s\n", usb_ep->name);
53046 +
53047 + if (!usb_ep) {
53048 + DWC_WARN("bad ep\n");
53049 + return -EINVAL;
53050 + }
53051 +
53052 + retval = dwc_otg_pcd_ep_wedge(gadget_wrapper->pcd, usb_ep);
53053 + if (retval == -DWC_E_AGAIN) {
53054 + retval = -EAGAIN;
53055 + } else if (retval) {
53056 + retval = -EINVAL;
53057 + }
53058 +
53059 + return retval;
53060 +}
53061 +#endif
53062 +
53063 +#ifdef DWC_EN_ISOC
53064 +/**
53065 + * This function is used to submit an ISOC Transfer Request to an EP.
53066 + *
53067 + * - Every time a sync period completes the request's completion callback
53068 + * is called to provide data to the gadget driver.
53069 + * - Once submitted the request cannot be modified.
53070 + * - Each request is turned into periodic data packets untill ISO
53071 + * Transfer is stopped..
53072 + */
53073 +static int iso_ep_start(struct usb_ep *usb_ep, struct usb_iso_request *req,
53074 + gfp_t gfp_flags)
53075 +{
53076 + int retval = 0;
53077 +
53078 + if (!req || !req->process_buffer || !req->buf0 || !req->buf1) {
53079 + DWC_WARN("bad params\n");
53080 + return -EINVAL;
53081 + }
53082 +
53083 + if (!usb_ep) {
53084 + DWC_PRINTF("bad params\n");
53085 + return -EINVAL;
53086 + }
53087 +
53088 + req->status = -EINPROGRESS;
53089 +
53090 + retval =
53091 + dwc_otg_pcd_iso_ep_start(gadget_wrapper->pcd, usb_ep, req->buf0,
53092 + req->buf1, req->dma0, req->dma1,
53093 + req->sync_frame, req->data_pattern_frame,
53094 + req->data_per_frame,
53095 + req->
53096 + flags & USB_REQ_ISO_ASAP ? -1 :
53097 + req->start_frame, req->buf_proc_intrvl,
53098 + req, gfp_flags == GFP_ATOMIC ? 1 : 0);
53099 +
53100 + if (retval) {
53101 + return -EINVAL;
53102 + }
53103 +
53104 + return retval;
53105 +}
53106 +
53107 +/**
53108 + * This function stops ISO EP Periodic Data Transfer.
53109 + */
53110 +static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req)
53111 +{
53112 + int retval = 0;
53113 + if (!usb_ep) {
53114 + DWC_WARN("bad ep\n");
53115 + }
53116 +
53117 + if (!gadget_wrapper->driver ||
53118 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
53119 + DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
53120 + gadget_wrapper->gadget.speed);
53121 + DWC_WARN("bogus device state\n");
53122 + }
53123 +
53124 + dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req);
53125 + if (retval) {
53126 + retval = -EINVAL;
53127 + }
53128 +
53129 + return retval;
53130 +}
53131 +
53132 +static struct usb_iso_request *alloc_iso_request(struct usb_ep *ep,
53133 + int packets, gfp_t gfp_flags)
53134 +{
53135 + struct usb_iso_request *pReq = NULL;
53136 + uint32_t req_size;
53137 +
53138 + req_size = sizeof(struct usb_iso_request);
53139 + req_size +=
53140 + (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor)));
53141 +
53142 + pReq = kmalloc(req_size, gfp_flags);
53143 + if (!pReq) {
53144 + DWC_WARN("Can't allocate Iso Request\n");
53145 + return 0;
53146 + }
53147 + pReq->iso_packet_desc0 = (void *)(pReq + 1);
53148 +
53149 + pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets;
53150 +
53151 + return pReq;
53152 +}
53153 +
53154 +static void free_iso_request(struct usb_ep *ep, struct usb_iso_request *req)
53155 +{
53156 + kfree(req);
53157 +}
53158 +
53159 +static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = {
53160 + .ep_ops = {
53161 + .enable = ep_enable,
53162 + .disable = ep_disable,
53163 +
53164 + .alloc_request = dwc_otg_pcd_alloc_request,
53165 + .free_request = dwc_otg_pcd_free_request,
53166 +
53167 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
53168 + .alloc_buffer = dwc_otg_pcd_alloc_buffer,
53169 + .free_buffer = dwc_otg_pcd_free_buffer,
53170 +#endif
53171 +
53172 + .queue = ep_queue,
53173 + .dequeue = ep_dequeue,
53174 +
53175 + .set_halt = ep_halt,
53176 + .fifo_status = 0,
53177 + .fifo_flush = 0,
53178 + },
53179 + .iso_ep_start = iso_ep_start,
53180 + .iso_ep_stop = iso_ep_stop,
53181 + .alloc_iso_request = alloc_iso_request,
53182 + .free_iso_request = free_iso_request,
53183 +};
53184 +
53185 +#else
53186 +
53187 + int (*enable) (struct usb_ep *ep,
53188 + const struct usb_endpoint_descriptor *desc);
53189 + int (*disable) (struct usb_ep *ep);
53190 +
53191 + struct usb_request *(*alloc_request) (struct usb_ep *ep,
53192 + gfp_t gfp_flags);
53193 + void (*free_request) (struct usb_ep *ep, struct usb_request *req);
53194 +
53195 + int (*queue) (struct usb_ep *ep, struct usb_request *req,
53196 + gfp_t gfp_flags);
53197 + int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
53198 +
53199 + int (*set_halt) (struct usb_ep *ep, int value);
53200 + int (*set_wedge) (struct usb_ep *ep);
53201 +
53202 + int (*fifo_status) (struct usb_ep *ep);
53203 + void (*fifo_flush) (struct usb_ep *ep);
53204 +static struct usb_ep_ops dwc_otg_pcd_ep_ops = {
53205 + .enable = ep_enable,
53206 + .disable = ep_disable,
53207 +
53208 + .alloc_request = dwc_otg_pcd_alloc_request,
53209 + .free_request = dwc_otg_pcd_free_request,
53210 +
53211 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
53212 + .alloc_buffer = dwc_otg_pcd_alloc_buffer,
53213 + .free_buffer = dwc_otg_pcd_free_buffer,
53214 +#else
53215 + /* .set_wedge = ep_wedge, */
53216 + .set_wedge = NULL, /* uses set_halt instead */
53217 +#endif
53218 +
53219 + .queue = ep_queue,
53220 + .dequeue = ep_dequeue,
53221 +
53222 + .set_halt = ep_halt,
53223 + .fifo_status = 0,
53224 + .fifo_flush = 0,
53225 +
53226 +};
53227 +
53228 +#endif /* _EN_ISOC_ */
53229 +/* Gadget Operations */
53230 +/**
53231 + * The following gadget operations will be implemented in the DWC_otg
53232 + * PCD. Functions in the API that are not described below are not
53233 + * implemented.
53234 + *
53235 + * The Gadget API provides wrapper functions for each of the function
53236 + * pointers defined in usb_gadget_ops. The Gadget Driver calls the
53237 + * wrapper function, which then calls the underlying PCD function. The
53238 + * following sections are named according to the wrapper functions
53239 + * (except for ioctl, which doesn't have a wrapper function). Within
53240 + * each section, the corresponding DWC_otg PCD function name is
53241 + * specified.
53242 + *
53243 + */
53244 +
53245 +/**
53246 + *Gets the USB Frame number of the last SOF.
53247 + */
53248 +static int get_frame_number(struct usb_gadget *gadget)
53249 +{
53250 + struct gadget_wrapper *d;
53251 +
53252 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
53253 +
53254 + if (gadget == 0) {
53255 + return -ENODEV;
53256 + }
53257 +
53258 + d = container_of(gadget, struct gadget_wrapper, gadget);
53259 + return dwc_otg_pcd_get_frame_number(d->pcd);
53260 +}
53261 +
53262 +#ifdef CONFIG_USB_DWC_OTG_LPM
53263 +static int test_lpm_enabled(struct usb_gadget *gadget)
53264 +{
53265 + struct gadget_wrapper *d;
53266 +
53267 + d = container_of(gadget, struct gadget_wrapper, gadget);
53268 +
53269 + return dwc_otg_pcd_is_lpm_enabled(d->pcd);
53270 +}
53271 +#endif
53272 +
53273 +/**
53274 + * Initiates Session Request Protocol (SRP) to wakeup the host if no
53275 + * session is in progress. If a session is already in progress, but
53276 + * the device is suspended, remote wakeup signaling is started.
53277 + *
53278 + */
53279 +static int wakeup(struct usb_gadget *gadget)
53280 +{
53281 + struct gadget_wrapper *d;
53282 +
53283 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
53284 +
53285 + if (gadget == 0) {
53286 + return -ENODEV;
53287 + } else {
53288 + d = container_of(gadget, struct gadget_wrapper, gadget);
53289 + }
53290 + dwc_otg_pcd_wakeup(d->pcd);
53291 + return 0;
53292 +}
53293 +
53294 +static const struct usb_gadget_ops dwc_otg_pcd_ops = {
53295 + .get_frame = get_frame_number,
53296 + .wakeup = wakeup,
53297 +#ifdef CONFIG_USB_DWC_OTG_LPM
53298 + .lpm_support = test_lpm_enabled,
53299 +#endif
53300 + // current versions must always be self-powered
53301 +};
53302 +
53303 +static int _setup(dwc_otg_pcd_t * pcd, uint8_t * bytes)
53304 +{
53305 + int retval = -DWC_E_NOT_SUPPORTED;
53306 + if (gadget_wrapper->driver && gadget_wrapper->driver->setup) {
53307 + retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget,
53308 + (struct usb_ctrlrequest
53309 + *)bytes);
53310 + }
53311 +
53312 + if (retval == -ENOTSUPP) {
53313 + retval = -DWC_E_NOT_SUPPORTED;
53314 + } else if (retval < 0) {
53315 + retval = -DWC_E_INVALID;
53316 + }
53317 +
53318 + return retval;
53319 +}
53320 +
53321 +#ifdef DWC_EN_ISOC
53322 +static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
53323 + void *req_handle, int proc_buf_num)
53324 +{
53325 + int i, packet_count;
53326 + struct usb_gadget_iso_packet_descriptor *iso_packet = 0;
53327 + struct usb_iso_request *iso_req = req_handle;
53328 +
53329 + if (proc_buf_num) {
53330 + iso_packet = iso_req->iso_packet_desc1;
53331 + } else {
53332 + iso_packet = iso_req->iso_packet_desc0;
53333 + }
53334 + packet_count =
53335 + dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle);
53336 + for (i = 0; i < packet_count; ++i) {
53337 + int status;
53338 + int actual;
53339 + int offset;
53340 + dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle,
53341 + i, &status, &actual, &offset);
53342 + switch (status) {
53343 + case -DWC_E_NO_DATA:
53344 + status = -ENODATA;
53345 + break;
53346 + default:
53347 + if (status) {
53348 + DWC_PRINTF("unknown status in isoc packet\n");
53349 + }
53350 +
53351 + }
53352 + iso_packet[i].status = status;
53353 + iso_packet[i].offset = offset;
53354 + iso_packet[i].actual_length = actual;
53355 + }
53356 +
53357 + iso_req->status = 0;
53358 + iso_req->process_buffer(ep_handle, iso_req);
53359 +
53360 + return 0;
53361 +}
53362 +#endif /* DWC_EN_ISOC */
53363 +
53364 +#ifdef DWC_UTE_PER_IO
53365 +/**
53366 + * Copy the contents of the extended request to the Linux usb_request's
53367 + * extended part and call the gadget's completion.
53368 + *
53369 + * @param pcd Pointer to the pcd structure
53370 + * @param ep_handle Void pointer to the usb_ep structure
53371 + * @param req_handle Void pointer to the usb_request structure
53372 + * @param status Request status returned from the portable logic
53373 + * @param ereq_port Void pointer to the extended request structure
53374 + * created in the the portable part that contains the
53375 + * results of the processed iso packets.
53376 + */
53377 +static int _xisoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
53378 + void *req_handle, int32_t status, void *ereq_port)
53379 +{
53380 + struct dwc_ute_iso_req_ext *ereqorg = NULL;
53381 + struct dwc_iso_xreq_port *ereqport = NULL;
53382 + struct dwc_ute_iso_packet_descriptor *desc_org = NULL;
53383 + int i;
53384 + struct usb_request *req;
53385 + //struct dwc_ute_iso_packet_descriptor *
53386 + //int status = 0;
53387 +
53388 + req = (struct usb_request *)req_handle;
53389 + ereqorg = &req->ext_req;
53390 + ereqport = (struct dwc_iso_xreq_port *)ereq_port;
53391 + desc_org = ereqorg->per_io_frame_descs;
53392 +
53393 + if (req && req->complete) {
53394 + /* Copy the request data from the portable logic to our request */
53395 + for (i = 0; i < ereqport->pio_pkt_count; i++) {
53396 + desc_org[i].actual_length =
53397 + ereqport->per_io_frame_descs[i].actual_length;
53398 + desc_org[i].status =
53399 + ereqport->per_io_frame_descs[i].status;
53400 + }
53401 +
53402 + switch (status) {
53403 + case -DWC_E_SHUTDOWN:
53404 + req->status = -ESHUTDOWN;
53405 + break;
53406 + case -DWC_E_RESTART:
53407 + req->status = -ECONNRESET;
53408 + break;
53409 + case -DWC_E_INVALID:
53410 + req->status = -EINVAL;
53411 + break;
53412 + case -DWC_E_TIMEOUT:
53413 + req->status = -ETIMEDOUT;
53414 + break;
53415 + default:
53416 + req->status = status;
53417 + }
53418 +
53419 + /* And call the gadget's completion */
53420 + req->complete(ep_handle, req);
53421 + }
53422 +
53423 + return 0;
53424 +}
53425 +#endif /* DWC_UTE_PER_IO */
53426 +
53427 +static int _complete(dwc_otg_pcd_t * pcd, void *ep_handle,
53428 + void *req_handle, int32_t status, uint32_t actual)
53429 +{
53430 + struct usb_request *req = (struct usb_request *)req_handle;
53431 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
53432 + struct dwc_otg_pcd_ep *ep = NULL;
53433 +#endif
53434 +
53435 + if (req && req->complete) {
53436 + switch (status) {
53437 + case -DWC_E_SHUTDOWN:
53438 + req->status = -ESHUTDOWN;
53439 + break;
53440 + case -DWC_E_RESTART:
53441 + req->status = -ECONNRESET;
53442 + break;
53443 + case -DWC_E_INVALID:
53444 + req->status = -EINVAL;
53445 + break;
53446 + case -DWC_E_TIMEOUT:
53447 + req->status = -ETIMEDOUT;
53448 + break;
53449 + default:
53450 + req->status = status;
53451 +
53452 + }
53453 +
53454 + req->actual = actual;
53455 + DWC_SPINUNLOCK(pcd->lock);
53456 + req->complete(ep_handle, req);
53457 + DWC_SPINLOCK(pcd->lock);
53458 + }
53459 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
53460 + ep = ep_from_handle(pcd, ep_handle);
53461 + if (GET_CORE_IF(pcd)->dma_enable) {
53462 + if (req->length != 0) {
53463 + dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev;
53464 + struct device *dev = NULL;
53465 +
53466 + if (otg_dev != NULL)
53467 + dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep);
53468 +
53469 + dma_unmap_single(dev, req->dma, req->length,
53470 + ep->dwc_ep.is_in ?
53471 + DMA_TO_DEVICE: DMA_FROM_DEVICE);
53472 + }
53473 + }
53474 +#endif
53475 +
53476 + return 0;
53477 +}
53478 +
53479 +static int _connect(dwc_otg_pcd_t * pcd, int speed)
53480 +{
53481 + gadget_wrapper->gadget.speed = speed;
53482 + return 0;
53483 +}
53484 +
53485 +static int _disconnect(dwc_otg_pcd_t * pcd)
53486 +{
53487 + if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) {
53488 + gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget);
53489 + }
53490 + return 0;
53491 +}
53492 +
53493 +static int _resume(dwc_otg_pcd_t * pcd)
53494 +{
53495 + if (gadget_wrapper->driver && gadget_wrapper->driver->resume) {
53496 + gadget_wrapper->driver->resume(&gadget_wrapper->gadget);
53497 + }
53498 +
53499 + return 0;
53500 +}
53501 +
53502 +static int _suspend(dwc_otg_pcd_t * pcd)
53503 +{
53504 + if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) {
53505 + gadget_wrapper->driver->suspend(&gadget_wrapper->gadget);
53506 + }
53507 + return 0;
53508 +}
53509 +
53510 +/**
53511 + * This function updates the otg values in the gadget structure.
53512 + */
53513 +static int _hnp_changed(dwc_otg_pcd_t * pcd)
53514 +{
53515 +
53516 + if (!gadget_wrapper->gadget.is_otg)
53517 + return 0;
53518 +
53519 + gadget_wrapper->gadget.b_hnp_enable = get_b_hnp_enable(pcd);
53520 + gadget_wrapper->gadget.a_hnp_support = get_a_hnp_support(pcd);
53521 + gadget_wrapper->gadget.a_alt_hnp_support = get_a_alt_hnp_support(pcd);
53522 + return 0;
53523 +}
53524 +
53525 +static int _reset(dwc_otg_pcd_t * pcd)
53526 +{
53527 + return 0;
53528 +}
53529 +
53530 +#ifdef DWC_UTE_CFI
53531 +static int _cfi_setup(dwc_otg_pcd_t * pcd, void *cfi_req)
53532 +{
53533 + int retval = -DWC_E_INVALID;
53534 + if (gadget_wrapper->driver->cfi_feature_setup) {
53535 + retval =
53536 + gadget_wrapper->driver->
53537 + cfi_feature_setup(&gadget_wrapper->gadget,
53538 + (struct cfi_usb_ctrlrequest *)cfi_req);
53539 + }
53540 +
53541 + return retval;
53542 +}
53543 +#endif
53544 +
53545 +static const struct dwc_otg_pcd_function_ops fops = {
53546 + .complete = _complete,
53547 +#ifdef DWC_EN_ISOC
53548 + .isoc_complete = _isoc_complete,
53549 +#endif
53550 + .setup = _setup,
53551 + .disconnect = _disconnect,
53552 + .connect = _connect,
53553 + .resume = _resume,
53554 + .suspend = _suspend,
53555 + .hnp_changed = _hnp_changed,
53556 + .reset = _reset,
53557 +#ifdef DWC_UTE_CFI
53558 + .cfi_setup = _cfi_setup,
53559 +#endif
53560 +#ifdef DWC_UTE_PER_IO
53561 + .xisoc_complete = _xisoc_complete,
53562 +#endif
53563 +};
53564 +
53565 +/**
53566 + * This function is the top level PCD interrupt handler.
53567 + */
53568 +static irqreturn_t dwc_otg_pcd_irq(int irq, void *dev)
53569 +{
53570 + dwc_otg_pcd_t *pcd = dev;
53571 + int32_t retval = IRQ_NONE;
53572 +
53573 + retval = dwc_otg_pcd_handle_intr(pcd);
53574 + if (retval != 0) {
53575 + S3C2410X_CLEAR_EINTPEND();
53576 + }
53577 + return IRQ_RETVAL(retval);
53578 +}
53579 +
53580 +/**
53581 + * This function initialized the usb_ep structures to there default
53582 + * state.
53583 + *
53584 + * @param d Pointer on gadget_wrapper.
53585 + */
53586 +void gadget_add_eps(struct gadget_wrapper *d)
53587 +{
53588 + static const char *names[] = {
53589 +
53590 + "ep0",
53591 + "ep1in",
53592 + "ep2in",
53593 + "ep3in",
53594 + "ep4in",
53595 + "ep5in",
53596 + "ep6in",
53597 + "ep7in",
53598 + "ep8in",
53599 + "ep9in",
53600 + "ep10in",
53601 + "ep11in",
53602 + "ep12in",
53603 + "ep13in",
53604 + "ep14in",
53605 + "ep15in",
53606 + "ep1out",
53607 + "ep2out",
53608 + "ep3out",
53609 + "ep4out",
53610 + "ep5out",
53611 + "ep6out",
53612 + "ep7out",
53613 + "ep8out",
53614 + "ep9out",
53615 + "ep10out",
53616 + "ep11out",
53617 + "ep12out",
53618 + "ep13out",
53619 + "ep14out",
53620 + "ep15out"
53621 + };
53622 +
53623 + int i;
53624 + struct usb_ep *ep;
53625 + int8_t dev_endpoints;
53626 +
53627 + DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__);
53628 +
53629 + INIT_LIST_HEAD(&d->gadget.ep_list);
53630 + d->gadget.ep0 = &d->ep0;
53631 + d->gadget.speed = USB_SPEED_UNKNOWN;
53632 +
53633 + INIT_LIST_HEAD(&d->gadget.ep0->ep_list);
53634 +
53635 + /**
53636 + * Initialize the EP0 structure.
53637 + */
53638 + ep = &d->ep0;
53639 +
53640 + /* Init the usb_ep structure. */
53641 + ep->name = names[0];
53642 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
53643 +
53644 + /**
53645 + * @todo NGS: What should the max packet size be set to
53646 + * here? Before EP type is set?
53647 + */
53648 + ep->maxpacket = MAX_PACKET_SIZE;
53649 + dwc_otg_pcd_ep_enable(d->pcd, NULL, ep);
53650 +
53651 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
53652 +
53653 + /**
53654 + * Initialize the EP structures.
53655 + */
53656 + dev_endpoints = d->pcd->core_if->dev_if->num_in_eps;
53657 +
53658 + for (i = 0; i < dev_endpoints; i++) {
53659 + ep = &d->in_ep[i];
53660 +
53661 + /* Init the usb_ep structure. */
53662 + ep->name = names[d->pcd->in_ep[i].dwc_ep.num];
53663 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
53664 +
53665 + /**
53666 + * @todo NGS: What should the max packet size be set to
53667 + * here? Before EP type is set?
53668 + */
53669 + ep->maxpacket = MAX_PACKET_SIZE;
53670 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
53671 + }
53672 +
53673 + dev_endpoints = d->pcd->core_if->dev_if->num_out_eps;
53674 +
53675 + for (i = 0; i < dev_endpoints; i++) {
53676 + ep = &d->out_ep[i];
53677 +
53678 + /* Init the usb_ep structure. */
53679 + ep->name = names[15 + d->pcd->out_ep[i].dwc_ep.num];
53680 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
53681 +
53682 + /**
53683 + * @todo NGS: What should the max packet size be set to
53684 + * here? Before EP type is set?
53685 + */
53686 + ep->maxpacket = MAX_PACKET_SIZE;
53687 +
53688 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
53689 + }
53690 +
53691 + /* remove ep0 from the list. There is a ep0 pointer. */
53692 + list_del_init(&d->ep0.ep_list);
53693 +
53694 + d->ep0.maxpacket = MAX_EP0_SIZE;
53695 +}
53696 +
53697 +/**
53698 + * This function releases the Gadget device.
53699 + * required by device_unregister().
53700 + *
53701 + * @todo Should this do something? Should it free the PCD?
53702 + */
53703 +static void dwc_otg_pcd_gadget_release(struct device *dev)
53704 +{
53705 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
53706 +}
53707 +
53708 +static struct gadget_wrapper *alloc_wrapper(dwc_bus_dev_t *_dev)
53709 +{
53710 + static char pcd_name[] = "dwc_otg_pcd";
53711 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
53712 + struct gadget_wrapper *d;
53713 + int retval;
53714 +
53715 + d = DWC_ALLOC(sizeof(*d));
53716 + if (d == NULL) {
53717 + return NULL;
53718 + }
53719 +
53720 + memset(d, 0, sizeof(*d));
53721 +
53722 + d->gadget.name = pcd_name;
53723 + d->pcd = otg_dev->pcd;
53724 +
53725 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
53726 + strcpy(d->gadget.dev.bus_id, "gadget");
53727 +#else
53728 + dev_set_name(&d->gadget.dev, "%s", "gadget");
53729 +#endif
53730 +
53731 + d->gadget.dev.parent = &_dev->dev;
53732 + d->gadget.dev.release = dwc_otg_pcd_gadget_release;
53733 + d->gadget.ops = &dwc_otg_pcd_ops;
53734 + d->gadget.max_speed = dwc_otg_pcd_is_dualspeed(otg_dev->pcd) ? USB_SPEED_HIGH:USB_SPEED_FULL;
53735 + d->gadget.is_otg = dwc_otg_pcd_is_otg(otg_dev->pcd);
53736 +
53737 + d->driver = 0;
53738 + /* Register the gadget device */
53739 + retval = device_register(&d->gadget.dev);
53740 + if (retval != 0) {
53741 + DWC_ERROR("device_register failed\n");
53742 + DWC_FREE(d);
53743 + return NULL;
53744 + }
53745 +
53746 + return d;
53747 +}
53748 +
53749 +static void free_wrapper(struct gadget_wrapper *d)
53750 +{
53751 + if (d->driver) {
53752 + /* should have been done already by driver model core */
53753 + DWC_WARN("driver '%s' is still registered\n",
53754 + d->driver->driver.name);
53755 + usb_gadget_unregister_driver(d->driver);
53756 + }
53757 +
53758 + device_unregister(&d->gadget.dev);
53759 + DWC_FREE(d);
53760 +}
53761 +
53762 +/**
53763 + * This function initialized the PCD portion of the driver.
53764 + *
53765 + */
53766 +int pcd_init(dwc_bus_dev_t *_dev)
53767 +{
53768 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
53769 + int retval = 0;
53770 +
53771 + DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev=%p\n", __func__, _dev, otg_dev);
53772 +
53773 + otg_dev->pcd = dwc_otg_pcd_init(otg_dev->core_if);
53774 +
53775 + if (!otg_dev->pcd) {
53776 + DWC_ERROR("dwc_otg_pcd_init failed\n");
53777 + return -ENOMEM;
53778 + }
53779 +
53780 + otg_dev->pcd->otg_dev = otg_dev;
53781 + gadget_wrapper = alloc_wrapper(_dev);
53782 +
53783 + /*
53784 + * Initialize EP structures
53785 + */
53786 + gadget_add_eps(gadget_wrapper);
53787 + /*
53788 + * Setup interupt handler
53789 + */
53790 +#ifdef PLATFORM_INTERFACE
53791 + DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
53792 + platform_get_irq(_dev, 0));
53793 + retval = request_irq(platform_get_irq(_dev, 0), dwc_otg_pcd_irq,
53794 + IRQF_SHARED, gadget_wrapper->gadget.name,
53795 + otg_dev->pcd);
53796 + if (retval != 0) {
53797 + DWC_ERROR("request of irq%d failed\n",
53798 + platform_get_irq(_dev, 0));
53799 + free_wrapper(gadget_wrapper);
53800 + return -EBUSY;
53801 + }
53802 +#else
53803 + DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
53804 + _dev->irq);
53805 + retval = request_irq(_dev->irq, dwc_otg_pcd_irq,
53806 + IRQF_SHARED | IRQF_DISABLED,
53807 + gadget_wrapper->gadget.name, otg_dev->pcd);
53808 + if (retval != 0) {
53809 + DWC_ERROR("request of irq%d failed\n", _dev->irq);
53810 + free_wrapper(gadget_wrapper);
53811 + return -EBUSY;
53812 + }
53813 +#endif
53814 +
53815 + dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
53816 +
53817 + return retval;
53818 +}
53819 +
53820 +/**
53821 + * Cleanup the PCD.
53822 + */
53823 +void pcd_remove(dwc_bus_dev_t *_dev)
53824 +{
53825 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
53826 + dwc_otg_pcd_t *pcd = otg_dev->pcd;
53827 +
53828 + DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev);
53829 +
53830 + /*
53831 + * Free the IRQ
53832 + */
53833 +#ifdef PLATFORM_INTERFACE
53834 + free_irq(platform_get_irq(_dev, 0), pcd);
53835 +#else
53836 + free_irq(_dev->irq, pcd);
53837 +#endif
53838 + dwc_otg_pcd_remove(otg_dev->pcd);
53839 + free_wrapper(gadget_wrapper);
53840 + otg_dev->pcd = 0;
53841 +}
53842 +
53843 +/**
53844 + * This function registers a gadget driver with the PCD.
53845 + *
53846 + * When a driver is successfully registered, it will receive control
53847 + * requests including set_configuration(), which enables non-control
53848 + * requests. then usb traffic follows until a disconnect is reported.
53849 + * then a host may connect again, or the driver might get unbound.
53850 + *
53851 + * @param driver The driver being registered
53852 + * @param bind The bind function of gadget driver
53853 + */
53854 +
53855 +int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
53856 +{
53857 + int retval;
53858 +
53859 + DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n",
53860 + driver->driver.name);
53861 +
53862 + if (!driver || driver->max_speed == USB_SPEED_UNKNOWN ||
53863 + !driver->bind ||
53864 + !driver->unbind || !driver->disconnect || !driver->setup) {
53865 + DWC_DEBUGPL(DBG_PCDV, "EINVAL\n");
53866 + return -EINVAL;
53867 + }
53868 + if (gadget_wrapper == 0) {
53869 + DWC_DEBUGPL(DBG_PCDV, "ENODEV\n");
53870 + return -ENODEV;
53871 + }
53872 + if (gadget_wrapper->driver != 0) {
53873 + DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", gadget_wrapper->driver);
53874 + return -EBUSY;
53875 + }
53876 +
53877 + /* hook up the driver */
53878 + gadget_wrapper->driver = driver;
53879 + gadget_wrapper->gadget.dev.driver = &driver->driver;
53880 +
53881 + DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", driver->driver.name);
53882 + retval = driver->bind(&gadget_wrapper->gadget, gadget_wrapper->driver);
53883 + if (retval) {
53884 + DWC_ERROR("bind to driver %s --> error %d\n",
53885 + driver->driver.name, retval);
53886 + gadget_wrapper->driver = 0;
53887 + gadget_wrapper->gadget.dev.driver = 0;
53888 + return retval;
53889 + }
53890 + DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n",
53891 + driver->driver.name);
53892 + return 0;
53893 +}
53894 +EXPORT_SYMBOL(usb_gadget_probe_driver);
53895 +
53896 +/**
53897 + * This function unregisters a gadget driver
53898 + *
53899 + * @param driver The driver being unregistered
53900 + */
53901 +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
53902 +{
53903 + //DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver);
53904 +
53905 + if (gadget_wrapper == 0) {
53906 + DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__,
53907 + -ENODEV);
53908 + return -ENODEV;
53909 + }
53910 + if (driver == 0 || driver != gadget_wrapper->driver) {
53911 + DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__,
53912 + -EINVAL);
53913 + return -EINVAL;
53914 + }
53915 +
53916 + driver->unbind(&gadget_wrapper->gadget);
53917 + gadget_wrapper->driver = 0;
53918 +
53919 + DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", driver->driver.name);
53920 + return 0;
53921 +}
53922 +
53923 +EXPORT_SYMBOL(usb_gadget_unregister_driver);
53924 +
53925 +#endif /* DWC_HOST_ONLY */
53926 --- /dev/null
53927 +++ b/drivers/usb/host/dwc_otg/dwc_otg_regs.h
53928 @@ -0,0 +1,2550 @@
53929 +/* ==========================================================================
53930 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_regs.h $
53931 + * $Revision: #98 $
53932 + * $Date: 2012/08/10 $
53933 + * $Change: 2047372 $
53934 + *
53935 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
53936 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
53937 + * otherwise expressly agreed to in writing between Synopsys and you.
53938 + *
53939 + * The Software IS NOT an item of Licensed Software or Licensed Product under
53940 + * any End User Software License Agreement or Agreement for Licensed Product
53941 + * with Synopsys or any supplement thereto. You are permitted to use and
53942 + * redistribute this Software in source and binary forms, with or without
53943 + * modification, provided that redistributions of source code must retain this
53944 + * notice. You may not view, use, disclose, copy or distribute this file or
53945 + * any information contained herein except pursuant to this license grant from
53946 + * Synopsys. If you do not agree with this notice, including the disclaimer
53947 + * below, then you are not authorized to use the Software.
53948 + *
53949 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
53950 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53951 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53952 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
53953 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
53954 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
53955 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
53956 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53957 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53958 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
53959 + * DAMAGE.
53960 + * ========================================================================== */
53961 +
53962 +#ifndef __DWC_OTG_REGS_H__
53963 +#define __DWC_OTG_REGS_H__
53964 +
53965 +#include "dwc_otg_core_if.h"
53966 +
53967 +/**
53968 + * @file
53969 + *
53970 + * This file contains the data structures for accessing the DWC_otg core registers.
53971 + *
53972 + * The application interfaces with the HS OTG core by reading from and
53973 + * writing to the Control and Status Register (CSR) space through the
53974 + * AHB Slave interface. These registers are 32 bits wide, and the
53975 + * addresses are 32-bit-block aligned.
53976 + * CSRs are classified as follows:
53977 + * - Core Global Registers
53978 + * - Device Mode Registers
53979 + * - Device Global Registers
53980 + * - Device Endpoint Specific Registers
53981 + * - Host Mode Registers
53982 + * - Host Global Registers
53983 + * - Host Port CSRs
53984 + * - Host Channel Specific Registers
53985 + *
53986 + * Only the Core Global registers can be accessed in both Device and
53987 + * Host modes. When the HS OTG core is operating in one mode, either
53988 + * Device or Host, the application must not access registers from the
53989 + * other mode. When the core switches from one mode to another, the
53990 + * registers in the new mode of operation must be reprogrammed as they
53991 + * would be after a power-on reset.
53992 + */
53993 +
53994 +/****************************************************************************/
53995 +/** DWC_otg Core registers .
53996 + * The dwc_otg_core_global_regs structure defines the size
53997 + * and relative field offsets for the Core Global registers.
53998 + */
53999 +typedef struct dwc_otg_core_global_regs {
54000 + /** OTG Control and Status Register. <i>Offset: 000h</i> */
54001 + volatile uint32_t gotgctl;
54002 + /** OTG Interrupt Register. <i>Offset: 004h</i> */
54003 + volatile uint32_t gotgint;
54004 + /**Core AHB Configuration Register. <i>Offset: 008h</i> */
54005 + volatile uint32_t gahbcfg;
54006 +
54007 +#define DWC_GLBINTRMASK 0x0001
54008 +#define DWC_DMAENABLE 0x0020
54009 +#define DWC_NPTXEMPTYLVL_EMPTY 0x0080
54010 +#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000
54011 +#define DWC_PTXEMPTYLVL_EMPTY 0x0100
54012 +#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000
54013 +
54014 + /**Core USB Configuration Register. <i>Offset: 00Ch</i> */
54015 + volatile uint32_t gusbcfg;
54016 + /**Core Reset Register. <i>Offset: 010h</i> */
54017 + volatile uint32_t grstctl;
54018 + /**Core Interrupt Register. <i>Offset: 014h</i> */
54019 + volatile uint32_t gintsts;
54020 + /**Core Interrupt Mask Register. <i>Offset: 018h</i> */
54021 + volatile uint32_t gintmsk;
54022 + /**Receive Status Queue Read Register (Read Only). <i>Offset: 01Ch</i> */
54023 + volatile uint32_t grxstsr;
54024 + /**Receive Status Queue Read & POP Register (Read Only). <i>Offset: 020h</i>*/
54025 + volatile uint32_t grxstsp;
54026 + /**Receive FIFO Size Register. <i>Offset: 024h</i> */
54027 + volatile uint32_t grxfsiz;
54028 + /**Non Periodic Transmit FIFO Size Register. <i>Offset: 028h</i> */
54029 + volatile uint32_t gnptxfsiz;
54030 + /**Non Periodic Transmit FIFO/Queue Status Register (Read
54031 + * Only). <i>Offset: 02Ch</i> */
54032 + volatile uint32_t gnptxsts;
54033 + /**I2C Access Register. <i>Offset: 030h</i> */
54034 + volatile uint32_t gi2cctl;
54035 + /**PHY Vendor Control Register. <i>Offset: 034h</i> */
54036 + volatile uint32_t gpvndctl;
54037 + /**General Purpose Input/Output Register. <i>Offset: 038h</i> */
54038 + volatile uint32_t ggpio;
54039 + /**User ID Register. <i>Offset: 03Ch</i> */
54040 + volatile uint32_t guid;
54041 + /**Synopsys ID Register (Read Only). <i>Offset: 040h</i> */
54042 + volatile uint32_t gsnpsid;
54043 + /**User HW Config1 Register (Read Only). <i>Offset: 044h</i> */
54044 + volatile uint32_t ghwcfg1;
54045 + /**User HW Config2 Register (Read Only). <i>Offset: 048h</i> */
54046 + volatile uint32_t ghwcfg2;
54047 +#define DWC_SLAVE_ONLY_ARCH 0
54048 +#define DWC_EXT_DMA_ARCH 1
54049 +#define DWC_INT_DMA_ARCH 2
54050 +
54051 +#define DWC_MODE_HNP_SRP_CAPABLE 0
54052 +#define DWC_MODE_SRP_ONLY_CAPABLE 1
54053 +#define DWC_MODE_NO_HNP_SRP_CAPABLE 2
54054 +#define DWC_MODE_SRP_CAPABLE_DEVICE 3
54055 +#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4
54056 +#define DWC_MODE_SRP_CAPABLE_HOST 5
54057 +#define DWC_MODE_NO_SRP_CAPABLE_HOST 6
54058 +
54059 + /**User HW Config3 Register (Read Only). <i>Offset: 04Ch</i> */
54060 + volatile uint32_t ghwcfg3;
54061 + /**User HW Config4 Register (Read Only). <i>Offset: 050h</i>*/
54062 + volatile uint32_t ghwcfg4;
54063 + /** Core LPM Configuration register <i>Offset: 054h</i>*/
54064 + volatile uint32_t glpmcfg;
54065 + /** Global PowerDn Register <i>Offset: 058h</i> */
54066 + volatile uint32_t gpwrdn;
54067 + /** Global DFIFO SW Config Register <i>Offset: 05Ch</i> */
54068 + volatile uint32_t gdfifocfg;
54069 + /** ADP Control Register <i>Offset: 060h</i> */
54070 + volatile uint32_t adpctl;
54071 + /** Reserved <i>Offset: 064h-0FFh</i> */
54072 + volatile uint32_t reserved39[39];
54073 + /** Host Periodic Transmit FIFO Size Register. <i>Offset: 100h</i> */
54074 + volatile uint32_t hptxfsiz;
54075 + /** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled,
54076 + otherwise Device Transmit FIFO#n Register.
54077 + * <i>Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15).</i> */
54078 + volatile uint32_t dtxfsiz[15];
54079 +} dwc_otg_core_global_regs_t;
54080 +
54081 +/**
54082 + * This union represents the bit fields of the Core OTG Control
54083 + * and Status Register (GOTGCTL). Set the bits using the bit
54084 + * fields then write the <i>d32</i> value to the register.
54085 + */
54086 +typedef union gotgctl_data {
54087 + /** raw register data */
54088 + uint32_t d32;
54089 + /** register bits */
54090 + struct {
54091 + unsigned sesreqscs:1;
54092 + unsigned sesreq:1;
54093 + unsigned vbvalidoven:1;
54094 + unsigned vbvalidovval:1;
54095 + unsigned avalidoven:1;
54096 + unsigned avalidovval:1;
54097 + unsigned bvalidoven:1;
54098 + unsigned bvalidovval:1;
54099 + unsigned hstnegscs:1;
54100 + unsigned hnpreq:1;
54101 + unsigned hstsethnpen:1;
54102 + unsigned devhnpen:1;
54103 + unsigned reserved12_15:4;
54104 + unsigned conidsts:1;
54105 + unsigned dbnctime:1;
54106 + unsigned asesvld:1;
54107 + unsigned bsesvld:1;
54108 + unsigned otgver:1;
54109 + unsigned reserved1:1;
54110 + unsigned multvalidbc:5;
54111 + unsigned chirpen:1;
54112 + unsigned reserved28_31:4;
54113 + } b;
54114 +} gotgctl_data_t;
54115 +
54116 +/**
54117 + * This union represents the bit fields of the Core OTG Interrupt Register
54118 + * (GOTGINT). Set/clear the bits using the bit fields then write the <i>d32</i>
54119 + * value to the register.
54120 + */
54121 +typedef union gotgint_data {
54122 + /** raw register data */
54123 + uint32_t d32;
54124 + /** register bits */
54125 + struct {
54126 + /** Current Mode */
54127 + unsigned reserved0_1:2;
54128 +
54129 + /** Session End Detected */
54130 + unsigned sesenddet:1;
54131 +
54132 + unsigned reserved3_7:5;
54133 +
54134 + /** Session Request Success Status Change */
54135 + unsigned sesreqsucstschng:1;
54136 + /** Host Negotiation Success Status Change */
54137 + unsigned hstnegsucstschng:1;
54138 +
54139 + unsigned reserved10_16:7;
54140 +
54141 + /** Host Negotiation Detected */
54142 + unsigned hstnegdet:1;
54143 + /** A-Device Timeout Change */
54144 + unsigned adevtoutchng:1;
54145 + /** Debounce Done */
54146 + unsigned debdone:1;
54147 + /** Multi-Valued input changed */
54148 + unsigned mvic:1;
54149 +
54150 + unsigned reserved31_21:11;
54151 +
54152 + } b;
54153 +} gotgint_data_t;
54154 +
54155 +/**
54156 + * This union represents the bit fields of the Core AHB Configuration
54157 + * Register (GAHBCFG). Set/clear the bits using the bit fields then
54158 + * write the <i>d32</i> value to the register.
54159 + */
54160 +typedef union gahbcfg_data {
54161 + /** raw register data */
54162 + uint32_t d32;
54163 + /** register bits */
54164 + struct {
54165 + unsigned glblintrmsk:1;
54166 +#define DWC_GAHBCFG_GLBINT_ENABLE 1
54167 +
54168 + unsigned hburstlen:4;
54169 +#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE 0
54170 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR 1
54171 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR4 3
54172 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR8 5
54173 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR16 7
54174 +
54175 + unsigned dmaenable:1;
54176 +#define DWC_GAHBCFG_DMAENABLE 1
54177 + unsigned reserved:1;
54178 + unsigned nptxfemplvl_txfemplvl:1;
54179 + unsigned ptxfemplvl:1;
54180 +#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY 1
54181 +#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0
54182 + unsigned reserved9_20:12;
54183 + unsigned remmemsupp:1;
54184 + unsigned notialldmawrit:1;
54185 + unsigned ahbsingle:1;
54186 + unsigned reserved24_31:8;
54187 + } b;
54188 +} gahbcfg_data_t;
54189 +
54190 +/**
54191 + * This union represents the bit fields of the Core USB Configuration
54192 + * Register (GUSBCFG). Set the bits using the bit fields then write
54193 + * the <i>d32</i> value to the register.
54194 + */
54195 +typedef union gusbcfg_data {
54196 + /** raw register data */
54197 + uint32_t d32;
54198 + /** register bits */
54199 + struct {
54200 + unsigned toutcal:3;
54201 + unsigned phyif:1;
54202 + unsigned ulpi_utmi_sel:1;
54203 + unsigned fsintf:1;
54204 + unsigned physel:1;
54205 + unsigned ddrsel:1;
54206 + unsigned srpcap:1;
54207 + unsigned hnpcap:1;
54208 + unsigned usbtrdtim:4;
54209 + unsigned reserved1:1;
54210 + unsigned phylpwrclksel:1;
54211 + unsigned otgutmifssel:1;
54212 + unsigned ulpi_fsls:1;
54213 + unsigned ulpi_auto_res:1;
54214 + unsigned ulpi_clk_sus_m:1;
54215 + unsigned ulpi_ext_vbus_drv:1;
54216 + unsigned ulpi_int_vbus_indicator:1;
54217 + unsigned term_sel_dl_pulse:1;
54218 + unsigned indicator_complement:1;
54219 + unsigned indicator_pass_through:1;
54220 + unsigned ulpi_int_prot_dis:1;
54221 + unsigned ic_usb_cap:1;
54222 + unsigned ic_traffic_pull_remove:1;
54223 + unsigned tx_end_delay:1;
54224 + unsigned force_host_mode:1;
54225 + unsigned force_dev_mode:1;
54226 + unsigned reserved31:1;
54227 + } b;
54228 +} gusbcfg_data_t;
54229 +
54230 +/**
54231 + * This union represents the bit fields of the Core Reset Register
54232 + * (GRSTCTL). Set/clear the bits using the bit fields then write the
54233 + * <i>d32</i> value to the register.
54234 + */
54235 +typedef union grstctl_data {
54236 + /** raw register data */
54237 + uint32_t d32;
54238 + /** register bits */
54239 + struct {
54240 + /** Core Soft Reset (CSftRst) (Device and Host)
54241 + *
54242 + * The application can flush the control logic in the
54243 + * entire core using this bit. This bit resets the
54244 + * pipelines in the AHB Clock domain as well as the
54245 + * PHY Clock domain.
54246 + *
54247 + * The state machines are reset to an IDLE state, the
54248 + * control bits in the CSRs are cleared, all the
54249 + * transmit FIFOs and the receive FIFO are flushed.
54250 + *
54251 + * The status mask bits that control the generation of
54252 + * the interrupt, are cleared, to clear the
54253 + * interrupt. The interrupt status bits are not
54254 + * cleared, so the application can get the status of
54255 + * any events that occurred in the core after it has
54256 + * set this bit.
54257 + *
54258 + * Any transactions on the AHB are terminated as soon
54259 + * as possible following the protocol. Any
54260 + * transactions on the USB are terminated immediately.
54261 + *
54262 + * The configuration settings in the CSRs are
54263 + * unchanged, so the software doesn't have to
54264 + * reprogram these registers (Device
54265 + * Configuration/Host Configuration/Core System
54266 + * Configuration/Core PHY Configuration).
54267 + *
54268 + * The application can write to this bit, any time it
54269 + * wants to reset the core. This is a self clearing
54270 + * bit and the core clears this bit after all the
54271 + * necessary logic is reset in the core, which may
54272 + * take several clocks, depending on the current state
54273 + * of the core.
54274 + */
54275 + unsigned csftrst:1;
54276 + /** Hclk Soft Reset
54277 + *
54278 + * The application uses this bit to reset the control logic in
54279 + * the AHB clock domain. Only AHB clock domain pipelines are
54280 + * reset.
54281 + */
54282 + unsigned hsftrst:1;
54283 + /** Host Frame Counter Reset (Host Only)<br>
54284 + *
54285 + * The application can reset the (micro)frame number
54286 + * counter inside the core, using this bit. When the
54287 + * (micro)frame counter is reset, the subsequent SOF
54288 + * sent out by the core, will have a (micro)frame
54289 + * number of 0.
54290 + */
54291 + unsigned hstfrm:1;
54292 + /** In Token Sequence Learning Queue Flush
54293 + * (INTknQFlsh) (Device Only)
54294 + */
54295 + unsigned intknqflsh:1;
54296 + /** RxFIFO Flush (RxFFlsh) (Device and Host)
54297 + *
54298 + * The application can flush the entire Receive FIFO
54299 + * using this bit. The application must first
54300 + * ensure that the core is not in the middle of a
54301 + * transaction. The application should write into
54302 + * this bit, only after making sure that neither the
54303 + * DMA engine is reading from the RxFIFO nor the MAC
54304 + * is writing the data in to the FIFO. The
54305 + * application should wait until the bit is cleared
54306 + * before performing any other operations. This bit
54307 + * will takes 8 clocks (slowest of PHY or AHB clock)
54308 + * to clear.
54309 + */
54310 + unsigned rxfflsh:1;
54311 + /** TxFIFO Flush (TxFFlsh) (Device and Host).
54312 + *
54313 + * This bit is used to selectively flush a single or
54314 + * all transmit FIFOs. The application must first
54315 + * ensure that the core is not in the middle of a
54316 + * transaction. The application should write into
54317 + * this bit, only after making sure that neither the
54318 + * DMA engine is writing into the TxFIFO nor the MAC
54319 + * is reading the data out of the FIFO. The
54320 + * application should wait until the core clears this
54321 + * bit, before performing any operations. This bit
54322 + * will takes 8 clocks (slowest of PHY or AHB clock)
54323 + * to clear.
54324 + */
54325 + unsigned txfflsh:1;
54326 +
54327 + /** TxFIFO Number (TxFNum) (Device and Host).
54328 + *
54329 + * This is the FIFO number which needs to be flushed,
54330 + * using the TxFIFO Flush bit. This field should not
54331 + * be changed until the TxFIFO Flush bit is cleared by
54332 + * the core.
54333 + * - 0x0 : Non Periodic TxFIFO Flush
54334 + * - 0x1 : Periodic TxFIFO #1 Flush in device mode
54335 + * or Periodic TxFIFO in host mode
54336 + * - 0x2 : Periodic TxFIFO #2 Flush in device mode.
54337 + * - ...
54338 + * - 0xF : Periodic TxFIFO #15 Flush in device mode
54339 + * - 0x10: Flush all the Transmit NonPeriodic and
54340 + * Transmit Periodic FIFOs in the core
54341 + */
54342 + unsigned txfnum:5;
54343 + /** Reserved */
54344 + unsigned reserved11_29:19;
54345 + /** DMA Request Signal. Indicated DMA request is in
54346 + * probress. Used for debug purpose. */
54347 + unsigned dmareq:1;
54348 + /** AHB Master Idle. Indicates the AHB Master State
54349 + * Machine is in IDLE condition. */
54350 + unsigned ahbidle:1;
54351 + } b;
54352 +} grstctl_t;
54353 +
54354 +/**
54355 + * This union represents the bit fields of the Core Interrupt Mask
54356 + * Register (GINTMSK). Set/clear the bits using the bit fields then
54357 + * write the <i>d32</i> value to the register.
54358 + */
54359 +typedef union gintmsk_data {
54360 + /** raw register data */
54361 + uint32_t d32;
54362 + /** register bits */
54363 + struct {
54364 + unsigned reserved0:1;
54365 + unsigned modemismatch:1;
54366 + unsigned otgintr:1;
54367 + unsigned sofintr:1;
54368 + unsigned rxstsqlvl:1;
54369 + unsigned nptxfempty:1;
54370 + unsigned ginnakeff:1;
54371 + unsigned goutnakeff:1;
54372 + unsigned ulpickint:1;
54373 + unsigned i2cintr:1;
54374 + unsigned erlysuspend:1;
54375 + unsigned usbsuspend:1;
54376 + unsigned usbreset:1;
54377 + unsigned enumdone:1;
54378 + unsigned isooutdrop:1;
54379 + unsigned eopframe:1;
54380 + unsigned restoredone:1;
54381 + unsigned epmismatch:1;
54382 + unsigned inepintr:1;
54383 + unsigned outepintr:1;
54384 + unsigned incomplisoin:1;
54385 + unsigned incomplisoout:1;
54386 + unsigned fetsusp:1;
54387 + unsigned resetdet:1;
54388 + unsigned portintr:1;
54389 + unsigned hcintr:1;
54390 + unsigned ptxfempty:1;
54391 + unsigned lpmtranrcvd:1;
54392 + unsigned conidstschng:1;
54393 + unsigned disconnect:1;
54394 + unsigned sessreqintr:1;
54395 + unsigned wkupintr:1;
54396 + } b;
54397 +} gintmsk_data_t;
54398 +/**
54399 + * This union represents the bit fields of the Core Interrupt Register
54400 + * (GINTSTS). Set/clear the bits using the bit fields then write the
54401 + * <i>d32</i> value to the register.
54402 + */
54403 +typedef union gintsts_data {
54404 + /** raw register data */
54405 + uint32_t d32;
54406 +#define DWC_SOF_INTR_MASK 0x0008
54407 + /** register bits */
54408 + struct {
54409 +#define DWC_HOST_MODE 1
54410 + unsigned curmode:1;
54411 + unsigned modemismatch:1;
54412 + unsigned otgintr:1;
54413 + unsigned sofintr:1;
54414 + unsigned rxstsqlvl:1;
54415 + unsigned nptxfempty:1;
54416 + unsigned ginnakeff:1;
54417 + unsigned goutnakeff:1;
54418 + unsigned ulpickint:1;
54419 + unsigned i2cintr:1;
54420 + unsigned erlysuspend:1;
54421 + unsigned usbsuspend:1;
54422 + unsigned usbreset:1;
54423 + unsigned enumdone:1;
54424 + unsigned isooutdrop:1;
54425 + unsigned eopframe:1;
54426 + unsigned restoredone:1;
54427 + unsigned epmismatch:1;
54428 + unsigned inepint:1;
54429 + unsigned outepintr:1;
54430 + unsigned incomplisoin:1;
54431 + unsigned incomplisoout:1;
54432 + unsigned fetsusp:1;
54433 + unsigned resetdet:1;
54434 + unsigned portintr:1;
54435 + unsigned hcintr:1;
54436 + unsigned ptxfempty:1;
54437 + unsigned lpmtranrcvd:1;
54438 + unsigned conidstschng:1;
54439 + unsigned disconnect:1;
54440 + unsigned sessreqintr:1;
54441 + unsigned wkupintr:1;
54442 + } b;
54443 +} gintsts_data_t;
54444 +
54445 +/**
54446 + * This union represents the bit fields in the Device Receive Status Read and
54447 + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
54448 + * element then read out the bits using the <i>b</i>it elements.
54449 + */
54450 +typedef union device_grxsts_data {
54451 + /** raw register data */
54452 + uint32_t d32;
54453 + /** register bits */
54454 + struct {
54455 + unsigned epnum:4;
54456 + unsigned bcnt:11;
54457 + unsigned dpid:2;
54458 +
54459 +#define DWC_STS_DATA_UPDT 0x2 // OUT Data Packet
54460 +#define DWC_STS_XFER_COMP 0x3 // OUT Data Transfer Complete
54461 +
54462 +#define DWC_DSTS_GOUT_NAK 0x1 // Global OUT NAK
54463 +#define DWC_DSTS_SETUP_COMP 0x4 // Setup Phase Complete
54464 +#define DWC_DSTS_SETUP_UPDT 0x6 // SETUP Packet
54465 + unsigned pktsts:4;
54466 + unsigned fn:4;
54467 + unsigned reserved25_31:7;
54468 + } b;
54469 +} device_grxsts_data_t;
54470 +
54471 +/**
54472 + * This union represents the bit fields in the Host Receive Status Read and
54473 + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
54474 + * element then read out the bits using the <i>b</i>it elements.
54475 + */
54476 +typedef union host_grxsts_data {
54477 + /** raw register data */
54478 + uint32_t d32;
54479 + /** register bits */
54480 + struct {
54481 + unsigned chnum:4;
54482 + unsigned bcnt:11;
54483 + unsigned dpid:2;
54484 +
54485 + unsigned pktsts:4;
54486 +#define DWC_GRXSTS_PKTSTS_IN 0x2
54487 +#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP 0x3
54488 +#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5
54489 +#define DWC_GRXSTS_PKTSTS_CH_HALTED 0x7
54490 +
54491 + unsigned reserved21_31:11;
54492 + } b;
54493 +} host_grxsts_data_t;
54494 +
54495 +/**
54496 + * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ,
54497 + * GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). Read the register into the <i>d32</i> element
54498 + * then read out the bits using the <i>b</i>it elements.
54499 + */
54500 +typedef union fifosize_data {
54501 + /** raw register data */
54502 + uint32_t d32;
54503 + /** register bits */
54504 + struct {
54505 + unsigned startaddr:16;
54506 + unsigned depth:16;
54507 + } b;
54508 +} fifosize_data_t;
54509 +
54510 +/**
54511 + * This union represents the bit fields in the Non-Periodic Transmit
54512 + * FIFO/Queue Status Register (GNPTXSTS). Read the register into the
54513 + * <i>d32</i> element then read out the bits using the <i>b</i>it
54514 + * elements.
54515 + */
54516 +typedef union gnptxsts_data {
54517 + /** raw register data */
54518 + uint32_t d32;
54519 + /** register bits */
54520 + struct {
54521 + unsigned nptxfspcavail:16;
54522 + unsigned nptxqspcavail:8;
54523 + /** Top of the Non-Periodic Transmit Request Queue
54524 + * - bit 24 - Terminate (Last entry for the selected
54525 + * channel/EP)
54526 + * - bits 26:25 - Token Type
54527 + * - 2'b00 - IN/OUT
54528 + * - 2'b01 - Zero Length OUT
54529 + * - 2'b10 - PING/Complete Split
54530 + * - 2'b11 - Channel Halt
54531 + * - bits 30:27 - Channel/EP Number
54532 + */
54533 + unsigned nptxqtop_terminate:1;
54534 + unsigned nptxqtop_token:2;
54535 + unsigned nptxqtop_chnep:4;
54536 + unsigned reserved:1;
54537 + } b;
54538 +} gnptxsts_data_t;
54539 +
54540 +/**
54541 + * This union represents the bit fields in the Transmit
54542 + * FIFO Status Register (DTXFSTS). Read the register into the
54543 + * <i>d32</i> element then read out the bits using the <i>b</i>it
54544 + * elements.
54545 + */
54546 +typedef union dtxfsts_data {
54547 + /** raw register data */
54548 + uint32_t d32;
54549 + /** register bits */
54550 + struct {
54551 + unsigned txfspcavail:16;
54552 + unsigned reserved:16;
54553 + } b;
54554 +} dtxfsts_data_t;
54555 +
54556 +/**
54557 + * This union represents the bit fields in the I2C Control Register
54558 + * (I2CCTL). Read the register into the <i>d32</i> element then read out the
54559 + * bits using the <i>b</i>it elements.
54560 + */
54561 +typedef union gi2cctl_data {
54562 + /** raw register data */
54563 + uint32_t d32;
54564 + /** register bits */
54565 + struct {
54566 + unsigned rwdata:8;
54567 + unsigned regaddr:8;
54568 + unsigned addr:7;
54569 + unsigned i2cen:1;
54570 + unsigned ack:1;
54571 + unsigned i2csuspctl:1;
54572 + unsigned i2cdevaddr:2;
54573 + unsigned i2cdatse0:1;
54574 + unsigned reserved:1;
54575 + unsigned rw:1;
54576 + unsigned bsydne:1;
54577 + } b;
54578 +} gi2cctl_data_t;
54579 +
54580 +/**
54581 + * This union represents the bit fields in the PHY Vendor Control Register
54582 + * (GPVNDCTL). Read the register into the <i>d32</i> element then read out the
54583 + * bits using the <i>b</i>it elements.
54584 + */
54585 +typedef union gpvndctl_data {
54586 + /** raw register data */
54587 + uint32_t d32;
54588 + /** register bits */
54589 + struct {
54590 + unsigned regdata:8;
54591 + unsigned vctrl:8;
54592 + unsigned regaddr16_21:6;
54593 + unsigned regwr:1;
54594 + unsigned reserved23_24:2;
54595 + unsigned newregreq:1;
54596 + unsigned vstsbsy:1;
54597 + unsigned vstsdone:1;
54598 + unsigned reserved28_30:3;
54599 + unsigned disulpidrvr:1;
54600 + } b;
54601 +} gpvndctl_data_t;
54602 +
54603 +/**
54604 + * This union represents the bit fields in the General Purpose
54605 + * Input/Output Register (GGPIO).
54606 + * Read the register into the <i>d32</i> element then read out the
54607 + * bits using the <i>b</i>it elements.
54608 + */
54609 +typedef union ggpio_data {
54610 + /** raw register data */
54611 + uint32_t d32;
54612 + /** register bits */
54613 + struct {
54614 + unsigned gpi:16;
54615 + unsigned gpo:16;
54616 + } b;
54617 +} ggpio_data_t;
54618 +
54619 +/**
54620 + * This union represents the bit fields in the User ID Register
54621 + * (GUID). Read the register into the <i>d32</i> element then read out the
54622 + * bits using the <i>b</i>it elements.
54623 + */
54624 +typedef union guid_data {
54625 + /** raw register data */
54626 + uint32_t d32;
54627 + /** register bits */
54628 + struct {
54629 + unsigned rwdata:32;
54630 + } b;
54631 +} guid_data_t;
54632 +
54633 +/**
54634 + * This union represents the bit fields in the Synopsys ID Register
54635 + * (GSNPSID). Read the register into the <i>d32</i> element then read out the
54636 + * bits using the <i>b</i>it elements.
54637 + */
54638 +typedef union gsnpsid_data {
54639 + /** raw register data */
54640 + uint32_t d32;
54641 + /** register bits */
54642 + struct {
54643 + unsigned rwdata:32;
54644 + } b;
54645 +} gsnpsid_data_t;
54646 +
54647 +/**
54648 + * This union represents the bit fields in the User HW Config1
54649 + * Register. Read the register into the <i>d32</i> element then read
54650 + * out the bits using the <i>b</i>it elements.
54651 + */
54652 +typedef union hwcfg1_data {
54653 + /** raw register data */
54654 + uint32_t d32;
54655 + /** register bits */
54656 + struct {
54657 + unsigned ep_dir0:2;
54658 + unsigned ep_dir1:2;
54659 + unsigned ep_dir2:2;
54660 + unsigned ep_dir3:2;
54661 + unsigned ep_dir4:2;
54662 + unsigned ep_dir5:2;
54663 + unsigned ep_dir6:2;
54664 + unsigned ep_dir7:2;
54665 + unsigned ep_dir8:2;
54666 + unsigned ep_dir9:2;
54667 + unsigned ep_dir10:2;
54668 + unsigned ep_dir11:2;
54669 + unsigned ep_dir12:2;
54670 + unsigned ep_dir13:2;
54671 + unsigned ep_dir14:2;
54672 + unsigned ep_dir15:2;
54673 + } b;
54674 +} hwcfg1_data_t;
54675 +
54676 +/**
54677 + * This union represents the bit fields in the User HW Config2
54678 + * Register. Read the register into the <i>d32</i> element then read
54679 + * out the bits using the <i>b</i>it elements.
54680 + */
54681 +typedef union hwcfg2_data {
54682 + /** raw register data */
54683 + uint32_t d32;
54684 + /** register bits */
54685 + struct {
54686 + /* GHWCFG2 */
54687 + unsigned op_mode:3;
54688 +#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0
54689 +#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1
54690 +#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2
54691 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3
54692 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4
54693 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5
54694 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6
54695 +
54696 + unsigned architecture:2;
54697 + unsigned point2point:1;
54698 + unsigned hs_phy_type:2;
54699 +#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
54700 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1
54701 +#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2
54702 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
54703 +
54704 + unsigned fs_phy_type:2;
54705 + unsigned num_dev_ep:4;
54706 + unsigned num_host_chan:4;
54707 + unsigned perio_ep_supported:1;
54708 + unsigned dynamic_fifo:1;
54709 + unsigned multi_proc_int:1;
54710 + unsigned reserved21:1;
54711 + unsigned nonperio_tx_q_depth:2;
54712 + unsigned host_perio_tx_q_depth:2;
54713 + unsigned dev_token_q_depth:5;
54714 + unsigned otg_enable_ic_usb:1;
54715 + } b;
54716 +} hwcfg2_data_t;
54717 +
54718 +/**
54719 + * This union represents the bit fields in the User HW Config3
54720 + * Register. Read the register into the <i>d32</i> element then read
54721 + * out the bits using the <i>b</i>it elements.
54722 + */
54723 +typedef union hwcfg3_data {
54724 + /** raw register data */
54725 + uint32_t d32;
54726 + /** register bits */
54727 + struct {
54728 + /* GHWCFG3 */
54729 + unsigned xfer_size_cntr_width:4;
54730 + unsigned packet_size_cntr_width:3;
54731 + unsigned otg_func:1;
54732 + unsigned i2c:1;
54733 + unsigned vendor_ctrl_if:1;
54734 + unsigned optional_features:1;
54735 + unsigned synch_reset_type:1;
54736 + unsigned adp_supp:1;
54737 + unsigned otg_enable_hsic:1;
54738 + unsigned bc_support:1;
54739 + unsigned otg_lpm_en:1;
54740 + unsigned dfifo_depth:16;
54741 + } b;
54742 +} hwcfg3_data_t;
54743 +
54744 +/**
54745 + * This union represents the bit fields in the User HW Config4
54746 + * Register. Read the register into the <i>d32</i> element then read
54747 + * out the bits using the <i>b</i>it elements.
54748 + */
54749 +typedef union hwcfg4_data {
54750 + /** raw register data */
54751 + uint32_t d32;
54752 + /** register bits */
54753 + struct {
54754 + unsigned num_dev_perio_in_ep:4;
54755 + unsigned power_optimiz:1;
54756 + unsigned min_ahb_freq:1;
54757 + unsigned hiber:1;
54758 + unsigned xhiber:1;
54759 + unsigned reserved:6;
54760 + unsigned utmi_phy_data_width:2;
54761 + unsigned num_dev_mode_ctrl_ep:4;
54762 + unsigned iddig_filt_en:1;
54763 + unsigned vbus_valid_filt_en:1;
54764 + unsigned a_valid_filt_en:1;
54765 + unsigned b_valid_filt_en:1;
54766 + unsigned session_end_filt_en:1;
54767 + unsigned ded_fifo_en:1;
54768 + unsigned num_in_eps:4;
54769 + unsigned desc_dma:1;
54770 + unsigned desc_dma_dyn:1;
54771 + } b;
54772 +} hwcfg4_data_t;
54773 +
54774 +/**
54775 + * This union represents the bit fields of the Core LPM Configuration
54776 + * Register (GLPMCFG). Set the bits using bit fields then write
54777 + * the <i>d32</i> value to the register.
54778 + */
54779 +typedef union glpmctl_data {
54780 + /** raw register data */
54781 + uint32_t d32;
54782 + /** register bits */
54783 + struct {
54784 + /** LPM-Capable (LPMCap) (Device and Host)
54785 + * The application uses this bit to control
54786 + * the DWC_otg core LPM capabilities.
54787 + */
54788 + unsigned lpm_cap_en:1;
54789 + /** LPM response programmed by application (AppL1Res) (Device)
54790 + * Handshake response to LPM token pre-programmed
54791 + * by device application software.
54792 + */
54793 + unsigned appl_resp:1;
54794 + /** Host Initiated Resume Duration (HIRD) (Device and Host)
54795 + * In Host mode this field indicates the value of HIRD
54796 + * to be sent in an LPM transaction.
54797 + * In Device mode this field is updated with the
54798 + * Received LPM Token HIRD bmAttribute
54799 + * when an ACK/NYET/STALL response is sent
54800 + * to an LPM transaction.
54801 + */
54802 + unsigned hird:4;
54803 + /** RemoteWakeEnable (bRemoteWake) (Device and Host)
54804 + * In Host mode this bit indicates the value of remote
54805 + * wake up to be sent in wIndex field of LPM transaction.
54806 + * In Device mode this field is updated with the
54807 + * Received LPM Token bRemoteWake bmAttribute
54808 + * when an ACK/NYET/STALL response is sent
54809 + * to an LPM transaction.
54810 + */
54811 + unsigned rem_wkup_en:1;
54812 + /** Enable utmi_sleep_n (EnblSlpM) (Device and Host)
54813 + * The application uses this bit to control
54814 + * the utmi_sleep_n assertion to the PHY when in L1 state.
54815 + */
54816 + unsigned en_utmi_sleep:1;
54817 + /** HIRD Threshold (HIRD_Thres) (Device and Host)
54818 + */
54819 + unsigned hird_thres:5;
54820 + /** LPM Response (CoreL1Res) (Device and Host)
54821 + * In Host mode this bit contains handsake response to
54822 + * LPM transaction.
54823 + * In Device mode the response of the core to
54824 + * LPM transaction received is reflected in these two bits.
54825 + - 0x0 : ERROR (No handshake response)
54826 + - 0x1 : STALL
54827 + - 0x2 : NYET
54828 + - 0x3 : ACK
54829 + */
54830 + unsigned lpm_resp:2;
54831 + /** Port Sleep Status (SlpSts) (Device and Host)
54832 + * This bit is set as long as a Sleep condition
54833 + * is present on the USB bus.
54834 + */
54835 + unsigned prt_sleep_sts:1;
54836 + /** Sleep State Resume OK (L1ResumeOK) (Device and Host)
54837 + * Indicates that the application or host
54838 + * can start resume from Sleep state.
54839 + */
54840 + unsigned sleep_state_resumeok:1;
54841 + /** LPM channel Index (LPM_Chnl_Indx) (Host)
54842 + * The channel number on which the LPM transaction
54843 + * has to be applied while sending
54844 + * an LPM transaction to the local device.
54845 + */
54846 + unsigned lpm_chan_index:4;
54847 + /** LPM Retry Count (LPM_Retry_Cnt) (Host)
54848 + * Number host retries that would be performed
54849 + * if the device response was not valid response.
54850 + */
54851 + unsigned retry_count:3;
54852 + /** Send LPM Transaction (SndLPM) (Host)
54853 + * When set by application software,
54854 + * an LPM transaction containing two tokens
54855 + * is sent.
54856 + */
54857 + unsigned send_lpm:1;
54858 + /** LPM Retry status (LPM_RetryCnt_Sts) (Host)
54859 + * Number of LPM Host Retries still remaining
54860 + * to be transmitted for the current LPM sequence
54861 + */
54862 + unsigned retry_count_sts:3;
54863 + unsigned reserved28_29:2;
54864 + /** In host mode once this bit is set, the host
54865 + * configures to drive the HSIC Idle state on the bus.
54866 + * It then waits for the device to initiate the Connect sequence.
54867 + * In device mode once this bit is set, the device waits for
54868 + * the HSIC Idle line state on the bus. Upon receving the Idle
54869 + * line state, it initiates the HSIC Connect sequence.
54870 + */
54871 + unsigned hsic_connect:1;
54872 + /** This bit overrides and functionally inverts
54873 + * the if_select_hsic input port signal.
54874 + */
54875 + unsigned inv_sel_hsic:1;
54876 + } b;
54877 +} glpmcfg_data_t;
54878 +
54879 +/**
54880 + * This union represents the bit fields of the Core ADP Timer, Control and
54881 + * Status Register (ADPTIMCTLSTS). Set the bits using bit fields then write
54882 + * the <i>d32</i> value to the register.
54883 + */
54884 +typedef union adpctl_data {
54885 + /** raw register data */
54886 + uint32_t d32;
54887 + /** register bits */
54888 + struct {
54889 + /** Probe Discharge (PRB_DSCHG)
54890 + * These bits set the times for TADP_DSCHG.
54891 + * These bits are defined as follows:
54892 + * 2'b00 - 4 msec
54893 + * 2'b01 - 8 msec
54894 + * 2'b10 - 16 msec
54895 + * 2'b11 - 32 msec
54896 + */
54897 + unsigned prb_dschg:2;
54898 + /** Probe Delta (PRB_DELTA)
54899 + * These bits set the resolution for RTIM value.
54900 + * The bits are defined in units of 32 kHz clock cycles as follows:
54901 + * 2'b00 - 1 cycles
54902 + * 2'b01 - 2 cycles
54903 + * 2'b10 - 3 cycles
54904 + * 2'b11 - 4 cycles
54905 + * For example if this value is chosen to 2'b01, it means that RTIM
54906 + * increments for every 3(three) 32Khz clock cycles.
54907 + */
54908 + unsigned prb_delta:2;
54909 + /** Probe Period (PRB_PER)
54910 + * These bits sets the TADP_PRD as shown in Figure 4 as follows:
54911 + * 2'b00 - 0.625 to 0.925 sec (typical 0.775 sec)
54912 + * 2'b01 - 1.25 to 1.85 sec (typical 1.55 sec)
54913 + * 2'b10 - 1.9 to 2.6 sec (typical 2.275 sec)
54914 + * 2'b11 - Reserved
54915 + */
54916 + unsigned prb_per:2;
54917 + /** These bits capture the latest time it took for VBUS to ramp from
54918 + * VADP_SINK to VADP_PRB.
54919 + * 0x000 - 1 cycles
54920 + * 0x001 - 2 cycles
54921 + * 0x002 - 3 cycles
54922 + * etc
54923 + * 0x7FF - 2048 cycles
54924 + * A time of 1024 cycles at 32 kHz corresponds to a time of 32 msec.
54925 + */
54926 + unsigned rtim:11;
54927 + /** Enable Probe (EnaPrb)
54928 + * When programmed to 1'b1, the core performs a probe operation.
54929 + * This bit is valid only if OTG_Ver = 1'b1.
54930 + */
54931 + unsigned enaprb:1;
54932 + /** Enable Sense (EnaSns)
54933 + * When programmed to 1'b1, the core performs a Sense operation.
54934 + * This bit is valid only if OTG_Ver = 1'b1.
54935 + */
54936 + unsigned enasns:1;
54937 + /** ADP Reset (ADPRes)
54938 + * When set, ADP controller is reset.
54939 + * This bit is valid only if OTG_Ver = 1'b1.
54940 + */
54941 + unsigned adpres:1;
54942 + /** ADP Enable (ADPEn)
54943 + * When set, the core performs either ADP probing or sensing
54944 + * based on EnaPrb or EnaSns.
54945 + * This bit is valid only if OTG_Ver = 1'b1.
54946 + */
54947 + unsigned adpen:1;
54948 + /** ADP Probe Interrupt (ADP_PRB_INT)
54949 + * When this bit is set, it means that the VBUS
54950 + * voltage is greater than VADP_PRB or VADP_PRB is reached.
54951 + * This bit is valid only if OTG_Ver = 1'b1.
54952 + */
54953 + unsigned adp_prb_int:1;
54954 + /**
54955 + * ADP Sense Interrupt (ADP_SNS_INT)
54956 + * When this bit is set, it means that the VBUS voltage is greater than
54957 + * VADP_SNS value or VADP_SNS is reached.
54958 + * This bit is valid only if OTG_Ver = 1'b1.
54959 + */
54960 + unsigned adp_sns_int:1;
54961 + /** ADP Tomeout Interrupt (ADP_TMOUT_INT)
54962 + * This bit is relevant only for an ADP probe.
54963 + * When this bit is set, it means that the ramp time has
54964 + * completed ie ADPCTL.RTIM has reached its terminal value
54965 + * of 0x7FF. This is a debug feature that allows software
54966 + * to read the ramp time after each cycle.
54967 + * This bit is valid only if OTG_Ver = 1'b1.
54968 + */
54969 + unsigned adp_tmout_int:1;
54970 + /** ADP Probe Interrupt Mask (ADP_PRB_INT_MSK)
54971 + * When this bit is set, it unmasks the interrupt due to ADP_PRB_INT.
54972 + * This bit is valid only if OTG_Ver = 1'b1.
54973 + */
54974 + unsigned adp_prb_int_msk:1;
54975 + /** ADP Sense Interrupt Mask (ADP_SNS_INT_MSK)
54976 + * When this bit is set, it unmasks the interrupt due to ADP_SNS_INT.
54977 + * This bit is valid only if OTG_Ver = 1'b1.
54978 + */
54979 + unsigned adp_sns_int_msk:1;
54980 + /** ADP Timoeout Interrupt Mask (ADP_TMOUT_MSK)
54981 + * When this bit is set, it unmasks the interrupt due to ADP_TMOUT_INT.
54982 + * This bit is valid only if OTG_Ver = 1'b1.
54983 + */
54984 + unsigned adp_tmout_int_msk:1;
54985 + /** Access Request
54986 + * 2'b00 - Read/Write Valid (updated by the core)
54987 + * 2'b01 - Read
54988 + * 2'b00 - Write
54989 + * 2'b00 - Reserved
54990 + */
54991 + unsigned ar:2;
54992 + /** Reserved */
54993 + unsigned reserved29_31:3;
54994 + } b;
54995 +} adpctl_data_t;
54996 +
54997 +////////////////////////////////////////////
54998 +// Device Registers
54999 +/**
55000 + * Device Global Registers. <i>Offsets 800h-BFFh</i>
55001 + *
55002 + * The following structures define the size and relative field offsets
55003 + * for the Device Mode Registers.
55004 + *
55005 + * <i>These registers are visible only in Device mode and must not be
55006 + * accessed in Host mode, as the results are unknown.</i>
55007 + */
55008 +typedef struct dwc_otg_dev_global_regs {
55009 + /** Device Configuration Register. <i>Offset 800h</i> */
55010 + volatile uint32_t dcfg;
55011 + /** Device Control Register. <i>Offset: 804h</i> */
55012 + volatile uint32_t dctl;
55013 + /** Device Status Register (Read Only). <i>Offset: 808h</i> */
55014 + volatile uint32_t dsts;
55015 + /** Reserved. <i>Offset: 80Ch</i> */
55016 + uint32_t unused;
55017 + /** Device IN Endpoint Common Interrupt Mask
55018 + * Register. <i>Offset: 810h</i> */
55019 + volatile uint32_t diepmsk;
55020 + /** Device OUT Endpoint Common Interrupt Mask
55021 + * Register. <i>Offset: 814h</i> */
55022 + volatile uint32_t doepmsk;
55023 + /** Device All Endpoints Interrupt Register. <i>Offset: 818h</i> */
55024 + volatile uint32_t daint;
55025 + /** Device All Endpoints Interrupt Mask Register. <i>Offset:
55026 + * 81Ch</i> */
55027 + volatile uint32_t daintmsk;
55028 + /** Device IN Token Queue Read Register-1 (Read Only).
55029 + * <i>Offset: 820h</i> */
55030 + volatile uint32_t dtknqr1;
55031 + /** Device IN Token Queue Read Register-2 (Read Only).
55032 + * <i>Offset: 824h</i> */
55033 + volatile uint32_t dtknqr2;
55034 + /** Device VBUS discharge Register. <i>Offset: 828h</i> */
55035 + volatile uint32_t dvbusdis;
55036 + /** Device VBUS Pulse Register. <i>Offset: 82Ch</i> */
55037 + volatile uint32_t dvbuspulse;
55038 + /** Device IN Token Queue Read Register-3 (Read Only). /
55039 + * Device Thresholding control register (Read/Write)
55040 + * <i>Offset: 830h</i> */
55041 + volatile uint32_t dtknqr3_dthrctl;
55042 + /** Device IN Token Queue Read Register-4 (Read Only). /
55043 + * Device IN EPs empty Inr. Mask Register (Read/Write)
55044 + * <i>Offset: 834h</i> */
55045 + volatile uint32_t dtknqr4_fifoemptymsk;
55046 + /** Device Each Endpoint Interrupt Register (Read Only). /
55047 + * <i>Offset: 838h</i> */
55048 + volatile uint32_t deachint;
55049 + /** Device Each Endpoint Interrupt mask Register (Read/Write). /
55050 + * <i>Offset: 83Ch</i> */
55051 + volatile uint32_t deachintmsk;
55052 + /** Device Each In Endpoint Interrupt mask Register (Read/Write). /
55053 + * <i>Offset: 840h</i> */
55054 + volatile uint32_t diepeachintmsk[MAX_EPS_CHANNELS];
55055 + /** Device Each Out Endpoint Interrupt mask Register (Read/Write). /
55056 + * <i>Offset: 880h</i> */
55057 + volatile uint32_t doepeachintmsk[MAX_EPS_CHANNELS];
55058 +} dwc_otg_device_global_regs_t;
55059 +
55060 +/**
55061 + * This union represents the bit fields in the Device Configuration
55062 + * Register. Read the register into the <i>d32</i> member then
55063 + * set/clear the bits using the <i>b</i>it elements. Write the
55064 + * <i>d32</i> member to the dcfg register.
55065 + */
55066 +typedef union dcfg_data {
55067 + /** raw register data */
55068 + uint32_t d32;
55069 + /** register bits */
55070 + struct {
55071 + /** Device Speed */
55072 + unsigned devspd:2;
55073 + /** Non Zero Length Status OUT Handshake */
55074 + unsigned nzstsouthshk:1;
55075 +#define DWC_DCFG_SEND_STALL 1
55076 +
55077 + unsigned ena32khzs:1;
55078 + /** Device Addresses */
55079 + unsigned devaddr:7;
55080 + /** Periodic Frame Interval */
55081 + unsigned perfrint:2;
55082 +#define DWC_DCFG_FRAME_INTERVAL_80 0
55083 +#define DWC_DCFG_FRAME_INTERVAL_85 1
55084 +#define DWC_DCFG_FRAME_INTERVAL_90 2
55085 +#define DWC_DCFG_FRAME_INTERVAL_95 3
55086 +
55087 + /** Enable Device OUT NAK for bulk in DDMA mode */
55088 + unsigned endevoutnak:1;
55089 +
55090 + unsigned reserved14_17:4;
55091 + /** In Endpoint Mis-match count */
55092 + unsigned epmscnt:5;
55093 + /** Enable Descriptor DMA in Device mode */
55094 + unsigned descdma:1;
55095 + unsigned perschintvl:2;
55096 + unsigned resvalid:6;
55097 + } b;
55098 +} dcfg_data_t;
55099 +
55100 +/**
55101 + * This union represents the bit fields in the Device Control
55102 + * Register. Read the register into the <i>d32</i> member then
55103 + * set/clear the bits using the <i>b</i>it elements.
55104 + */
55105 +typedef union dctl_data {
55106 + /** raw register data */
55107 + uint32_t d32;
55108 + /** register bits */
55109 + struct {
55110 + /** Remote Wakeup */
55111 + unsigned rmtwkupsig:1;
55112 + /** Soft Disconnect */
55113 + unsigned sftdiscon:1;
55114 + /** Global Non-Periodic IN NAK Status */
55115 + unsigned gnpinnaksts:1;
55116 + /** Global OUT NAK Status */
55117 + unsigned goutnaksts:1;
55118 + /** Test Control */
55119 + unsigned tstctl:3;
55120 + /** Set Global Non-Periodic IN NAK */
55121 + unsigned sgnpinnak:1;
55122 + /** Clear Global Non-Periodic IN NAK */
55123 + unsigned cgnpinnak:1;
55124 + /** Set Global OUT NAK */
55125 + unsigned sgoutnak:1;
55126 + /** Clear Global OUT NAK */
55127 + unsigned cgoutnak:1;
55128 + /** Power-On Programming Done */
55129 + unsigned pwronprgdone:1;
55130 + /** Reserved */
55131 + unsigned reserved:1;
55132 + /** Global Multi Count */
55133 + unsigned gmc:2;
55134 + /** Ignore Frame Number for ISOC EPs */
55135 + unsigned ifrmnum:1;
55136 + /** NAK on Babble */
55137 + unsigned nakonbble:1;
55138 + /** Enable Continue on BNA */
55139 + unsigned encontonbna:1;
55140 +
55141 + unsigned reserved18_31:14;
55142 + } b;
55143 +} dctl_data_t;
55144 +
55145 +/**
55146 + * This union represents the bit fields in the Device Status
55147 + * Register. Read the register into the <i>d32</i> member then
55148 + * set/clear the bits using the <i>b</i>it elements.
55149 + */
55150 +typedef union dsts_data {
55151 + /** raw register data */
55152 + uint32_t d32;
55153 + /** register bits */
55154 + struct {
55155 + /** Suspend Status */
55156 + unsigned suspsts:1;
55157 + /** Enumerated Speed */
55158 + unsigned enumspd:2;
55159 +#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0
55160 +#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1
55161 +#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2
55162 +#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3
55163 + /** Erratic Error */
55164 + unsigned errticerr:1;
55165 + unsigned reserved4_7:4;
55166 + /** Frame or Microframe Number of the received SOF */
55167 + unsigned soffn:14;
55168 + unsigned reserved22_31:10;
55169 + } b;
55170 +} dsts_data_t;
55171 +
55172 +/**
55173 + * This union represents the bit fields in the Device IN EP Interrupt
55174 + * Register and the Device IN EP Common Mask Register.
55175 + *
55176 + * - Read the register into the <i>d32</i> member then set/clear the
55177 + * bits using the <i>b</i>it elements.
55178 + */
55179 +typedef union diepint_data {
55180 + /** raw register data */
55181 + uint32_t d32;
55182 + /** register bits */
55183 + struct {
55184 + /** Transfer complete mask */
55185 + unsigned xfercompl:1;
55186 + /** Endpoint disable mask */
55187 + unsigned epdisabled:1;
55188 + /** AHB Error mask */
55189 + unsigned ahberr:1;
55190 + /** TimeOUT Handshake mask (non-ISOC EPs) */
55191 + unsigned timeout:1;
55192 + /** IN Token received with TxF Empty mask */
55193 + unsigned intktxfemp:1;
55194 + /** IN Token Received with EP mismatch mask */
55195 + unsigned intknepmis:1;
55196 + /** IN Endpoint NAK Effective mask */
55197 + unsigned inepnakeff:1;
55198 + /** Reserved */
55199 + unsigned emptyintr:1;
55200 +
55201 + unsigned txfifoundrn:1;
55202 +
55203 + /** BNA Interrupt mask */
55204 + unsigned bna:1;
55205 +
55206 + unsigned reserved10_12:3;
55207 + /** BNA Interrupt mask */
55208 + unsigned nak:1;
55209 +
55210 + unsigned reserved14_31:18;
55211 + } b;
55212 +} diepint_data_t;
55213 +
55214 +/**
55215 + * This union represents the bit fields in the Device IN EP
55216 + * Common/Dedicated Interrupt Mask Register.
55217 + */
55218 +typedef union diepint_data diepmsk_data_t;
55219 +
55220 +/**
55221 + * This union represents the bit fields in the Device OUT EP Interrupt
55222 + * Registerand Device OUT EP Common Interrupt Mask Register.
55223 + *
55224 + * - Read the register into the <i>d32</i> member then set/clear the
55225 + * bits using the <i>b</i>it elements.
55226 + */
55227 +typedef union doepint_data {
55228 + /** raw register data */
55229 + uint32_t d32;
55230 + /** register bits */
55231 + struct {
55232 + /** Transfer complete */
55233 + unsigned xfercompl:1;
55234 + /** Endpoint disable */
55235 + unsigned epdisabled:1;
55236 + /** AHB Error */
55237 + unsigned ahberr:1;
55238 + /** Setup Phase Done (contorl EPs) */
55239 + unsigned setup:1;
55240 + /** OUT Token Received when Endpoint Disabled */
55241 + unsigned outtknepdis:1;
55242 +
55243 + unsigned stsphsercvd:1;
55244 + /** Back-to-Back SETUP Packets Received */
55245 + unsigned back2backsetup:1;
55246 +
55247 + unsigned reserved7:1;
55248 + /** OUT packet Error */
55249 + unsigned outpkterr:1;
55250 + /** BNA Interrupt */
55251 + unsigned bna:1;
55252 +
55253 + unsigned reserved10:1;
55254 + /** Packet Drop Status */
55255 + unsigned pktdrpsts:1;
55256 + /** Babble Interrupt */
55257 + unsigned babble:1;
55258 + /** NAK Interrupt */
55259 + unsigned nak:1;
55260 + /** NYET Interrupt */
55261 + unsigned nyet:1;
55262 + /** Bit indicating setup packet received */
55263 + unsigned sr:1;
55264 +
55265 + unsigned reserved16_31:16;
55266 + } b;
55267 +} doepint_data_t;
55268 +
55269 +/**
55270 + * This union represents the bit fields in the Device OUT EP
55271 + * Common/Dedicated Interrupt Mask Register.
55272 + */
55273 +typedef union doepint_data doepmsk_data_t;
55274 +
55275 +/**
55276 + * This union represents the bit fields in the Device All EP Interrupt
55277 + * and Mask Registers.
55278 + * - Read the register into the <i>d32</i> member then set/clear the
55279 + * bits using the <i>b</i>it elements.
55280 + */
55281 +typedef union daint_data {
55282 + /** raw register data */
55283 + uint32_t d32;
55284 + /** register bits */
55285 + struct {
55286 + /** IN Endpoint bits */
55287 + unsigned in:16;
55288 + /** OUT Endpoint bits */
55289 + unsigned out:16;
55290 + } ep;
55291 + struct {
55292 + /** IN Endpoint bits */
55293 + unsigned inep0:1;
55294 + unsigned inep1:1;
55295 + unsigned inep2:1;
55296 + unsigned inep3:1;
55297 + unsigned inep4:1;
55298 + unsigned inep5:1;
55299 + unsigned inep6:1;
55300 + unsigned inep7:1;
55301 + unsigned inep8:1;
55302 + unsigned inep9:1;
55303 + unsigned inep10:1;
55304 + unsigned inep11:1;
55305 + unsigned inep12:1;
55306 + unsigned inep13:1;
55307 + unsigned inep14:1;
55308 + unsigned inep15:1;
55309 + /** OUT Endpoint bits */
55310 + unsigned outep0:1;
55311 + unsigned outep1:1;
55312 + unsigned outep2:1;
55313 + unsigned outep3:1;
55314 + unsigned outep4:1;
55315 + unsigned outep5:1;
55316 + unsigned outep6:1;
55317 + unsigned outep7:1;
55318 + unsigned outep8:1;
55319 + unsigned outep9:1;
55320 + unsigned outep10:1;
55321 + unsigned outep11:1;
55322 + unsigned outep12:1;
55323 + unsigned outep13:1;
55324 + unsigned outep14:1;
55325 + unsigned outep15:1;
55326 + } b;
55327 +} daint_data_t;
55328 +
55329 +/**
55330 + * This union represents the bit fields in the Device IN Token Queue
55331 + * Read Registers.
55332 + * - Read the register into the <i>d32</i> member.
55333 + * - READ-ONLY Register
55334 + */
55335 +typedef union dtknq1_data {
55336 + /** raw register data */
55337 + uint32_t d32;
55338 + /** register bits */
55339 + struct {
55340 + /** In Token Queue Write Pointer */
55341 + unsigned intknwptr:5;
55342 + /** Reserved */
55343 + unsigned reserved05_06:2;
55344 + /** write pointer has wrapped. */
55345 + unsigned wrap_bit:1;
55346 + /** EP Numbers of IN Tokens 0 ... 4 */
55347 + unsigned epnums0_5:24;
55348 + } b;
55349 +} dtknq1_data_t;
55350 +
55351 +/**
55352 + * This union represents Threshold control Register
55353 + * - Read and write the register into the <i>d32</i> member.
55354 + * - READ-WRITABLE Register
55355 + */
55356 +typedef union dthrctl_data {
55357 + /** raw register data */
55358 + uint32_t d32;
55359 + /** register bits */
55360 + struct {
55361 + /** non ISO Tx Thr. Enable */
55362 + unsigned non_iso_thr_en:1;
55363 + /** ISO Tx Thr. Enable */
55364 + unsigned iso_thr_en:1;
55365 + /** Tx Thr. Length */
55366 + unsigned tx_thr_len:9;
55367 + /** AHB Threshold ratio */
55368 + unsigned ahb_thr_ratio:2;
55369 + /** Reserved */
55370 + unsigned reserved13_15:3;
55371 + /** Rx Thr. Enable */
55372 + unsigned rx_thr_en:1;
55373 + /** Rx Thr. Length */
55374 + unsigned rx_thr_len:9;
55375 + unsigned reserved26:1;
55376 + /** Arbiter Parking Enable*/
55377 + unsigned arbprken:1;
55378 + /** Reserved */
55379 + unsigned reserved28_31:4;
55380 + } b;
55381 +} dthrctl_data_t;
55382 +
55383 +/**
55384 + * Device Logical IN Endpoint-Specific Registers. <i>Offsets
55385 + * 900h-AFCh</i>
55386 + *
55387 + * There will be one set of endpoint registers per logical endpoint
55388 + * implemented.
55389 + *
55390 + * <i>These registers are visible only in Device mode and must not be
55391 + * accessed in Host mode, as the results are unknown.</i>
55392 + */
55393 +typedef struct dwc_otg_dev_in_ep_regs {
55394 + /** Device IN Endpoint Control Register. <i>Offset:900h +
55395 + * (ep_num * 20h) + 00h</i> */
55396 + volatile uint32_t diepctl;
55397 + /** Reserved. <i>Offset:900h + (ep_num * 20h) + 04h</i> */
55398 + uint32_t reserved04;
55399 + /** Device IN Endpoint Interrupt Register. <i>Offset:900h +
55400 + * (ep_num * 20h) + 08h</i> */
55401 + volatile uint32_t diepint;
55402 + /** Reserved. <i>Offset:900h + (ep_num * 20h) + 0Ch</i> */
55403 + uint32_t reserved0C;
55404 + /** Device IN Endpoint Transfer Size
55405 + * Register. <i>Offset:900h + (ep_num * 20h) + 10h</i> */
55406 + volatile uint32_t dieptsiz;
55407 + /** Device IN Endpoint DMA Address Register. <i>Offset:900h +
55408 + * (ep_num * 20h) + 14h</i> */
55409 + volatile uint32_t diepdma;
55410 + /** Device IN Endpoint Transmit FIFO Status Register. <i>Offset:900h +
55411 + * (ep_num * 20h) + 18h</i> */
55412 + volatile uint32_t dtxfsts;
55413 + /** Device IN Endpoint DMA Buffer Register. <i>Offset:900h +
55414 + * (ep_num * 20h) + 1Ch</i> */
55415 + volatile uint32_t diepdmab;
55416 +} dwc_otg_dev_in_ep_regs_t;
55417 +
55418 +/**
55419 + * Device Logical OUT Endpoint-Specific Registers. <i>Offsets:
55420 + * B00h-CFCh</i>
55421 + *
55422 + * There will be one set of endpoint registers per logical endpoint
55423 + * implemented.
55424 + *
55425 + * <i>These registers are visible only in Device mode and must not be
55426 + * accessed in Host mode, as the results are unknown.</i>
55427 + */
55428 +typedef struct dwc_otg_dev_out_ep_regs {
55429 + /** Device OUT Endpoint Control Register. <i>Offset:B00h +
55430 + * (ep_num * 20h) + 00h</i> */
55431 + volatile uint32_t doepctl;
55432 + /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 04h</i> */
55433 + uint32_t reserved04;
55434 + /** Device OUT Endpoint Interrupt Register. <i>Offset:B00h +
55435 + * (ep_num * 20h) + 08h</i> */
55436 + volatile uint32_t doepint;
55437 + /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 0Ch</i> */
55438 + uint32_t reserved0C;
55439 + /** Device OUT Endpoint Transfer Size Register. <i>Offset:
55440 + * B00h + (ep_num * 20h) + 10h</i> */
55441 + volatile uint32_t doeptsiz;
55442 + /** Device OUT Endpoint DMA Address Register. <i>Offset:B00h
55443 + * + (ep_num * 20h) + 14h</i> */
55444 + volatile uint32_t doepdma;
55445 + /** Reserved. <i>Offset:B00h + * (ep_num * 20h) + 18h</i> */
55446 + uint32_t unused;
55447 + /** Device OUT Endpoint DMA Buffer Register. <i>Offset:B00h
55448 + * + (ep_num * 20h) + 1Ch</i> */
55449 + uint32_t doepdmab;
55450 +} dwc_otg_dev_out_ep_regs_t;
55451 +
55452 +/**
55453 + * This union represents the bit fields in the Device EP Control
55454 + * Register. Read the register into the <i>d32</i> member then
55455 + * set/clear the bits using the <i>b</i>it elements.
55456 + */
55457 +typedef union depctl_data {
55458 + /** raw register data */
55459 + uint32_t d32;
55460 + /** register bits */
55461 + struct {
55462 + /** Maximum Packet Size
55463 + * IN/OUT EPn
55464 + * IN/OUT EP0 - 2 bits
55465 + * 2'b00: 64 Bytes
55466 + * 2'b01: 32
55467 + * 2'b10: 16
55468 + * 2'b11: 8 */
55469 + unsigned mps:11;
55470 +#define DWC_DEP0CTL_MPS_64 0
55471 +#define DWC_DEP0CTL_MPS_32 1
55472 +#define DWC_DEP0CTL_MPS_16 2
55473 +#define DWC_DEP0CTL_MPS_8 3
55474 +
55475 + /** Next Endpoint
55476 + * IN EPn/IN EP0
55477 + * OUT EPn/OUT EP0 - reserved */
55478 + unsigned nextep:4;
55479 +
55480 + /** USB Active Endpoint */
55481 + unsigned usbactep:1;
55482 +
55483 + /** Endpoint DPID (INTR/Bulk IN and OUT endpoints)
55484 + * This field contains the PID of the packet going to
55485 + * be received or transmitted on this endpoint. The
55486 + * application should program the PID of the first
55487 + * packet going to be received or transmitted on this
55488 + * endpoint , after the endpoint is
55489 + * activated. Application use the SetD1PID and
55490 + * SetD0PID fields of this register to program either
55491 + * D0 or D1 PID.
55492 + *
55493 + * The encoding for this field is
55494 + * - 0: D0
55495 + * - 1: D1
55496 + */
55497 + unsigned dpid:1;
55498 +
55499 + /** NAK Status */
55500 + unsigned naksts:1;
55501 +
55502 + /** Endpoint Type
55503 + * 2'b00: Control
55504 + * 2'b01: Isochronous
55505 + * 2'b10: Bulk
55506 + * 2'b11: Interrupt */
55507 + unsigned eptype:2;
55508 +
55509 + /** Snoop Mode
55510 + * OUT EPn/OUT EP0
55511 + * IN EPn/IN EP0 - reserved */
55512 + unsigned snp:1;
55513 +
55514 + /** Stall Handshake */
55515 + unsigned stall:1;
55516 +
55517 + /** Tx Fifo Number
55518 + * IN EPn/IN EP0
55519 + * OUT EPn/OUT EP0 - reserved */
55520 + unsigned txfnum:4;
55521 +
55522 + /** Clear NAK */
55523 + unsigned cnak:1;
55524 + /** Set NAK */
55525 + unsigned snak:1;
55526 + /** Set DATA0 PID (INTR/Bulk IN and OUT endpoints)
55527 + * Writing to this field sets the Endpoint DPID (DPID)
55528 + * field in this register to DATA0. Set Even
55529 + * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints)
55530 + * Writing to this field sets the Even/Odd
55531 + * (micro)frame (EO_FrNum) field to even (micro)
55532 + * frame.
55533 + */
55534 + unsigned setd0pid:1;
55535 + /** Set DATA1 PID (INTR/Bulk IN and OUT endpoints)
55536 + * Writing to this field sets the Endpoint DPID (DPID)
55537 + * field in this register to DATA1 Set Odd
55538 + * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints)
55539 + * Writing to this field sets the Even/Odd
55540 + * (micro)frame (EO_FrNum) field to odd (micro) frame.
55541 + */
55542 + unsigned setd1pid:1;
55543 +
55544 + /** Endpoint Disable */
55545 + unsigned epdis:1;
55546 + /** Endpoint Enable */
55547 + unsigned epena:1;
55548 + } b;
55549 +} depctl_data_t;
55550 +
55551 +/**
55552 + * This union represents the bit fields in the Device EP Transfer
55553 + * Size Register. Read the register into the <i>d32</i> member then
55554 + * set/clear the bits using the <i>b</i>it elements.
55555 + */
55556 +typedef union deptsiz_data {
55557 + /** raw register data */
55558 + uint32_t d32;
55559 + /** register bits */
55560 + struct {
55561 + /** Transfer size */
55562 + unsigned xfersize:19;
55563 +/** Max packet count for EP (pow(2,10)-1) */
55564 +#define MAX_PKT_CNT 1023
55565 + /** Packet Count */
55566 + unsigned pktcnt:10;
55567 + /** Multi Count - Periodic IN endpoints */
55568 + unsigned mc:2;
55569 + unsigned reserved:1;
55570 + } b;
55571 +} deptsiz_data_t;
55572 +
55573 +/**
55574 + * This union represents the bit fields in the Device EP 0 Transfer
55575 + * Size Register. Read the register into the <i>d32</i> member then
55576 + * set/clear the bits using the <i>b</i>it elements.
55577 + */
55578 +typedef union deptsiz0_data {
55579 + /** raw register data */
55580 + uint32_t d32;
55581 + /** register bits */
55582 + struct {
55583 + /** Transfer size */
55584 + unsigned xfersize:7;
55585 + /** Reserved */
55586 + unsigned reserved7_18:12;
55587 + /** Packet Count */
55588 + unsigned pktcnt:2;
55589 + /** Reserved */
55590 + unsigned reserved21_28:8;
55591 + /**Setup Packet Count (DOEPTSIZ0 Only) */
55592 + unsigned supcnt:2;
55593 + unsigned reserved31;
55594 + } b;
55595 +} deptsiz0_data_t;
55596 +
55597 +/////////////////////////////////////////////////
55598 +// DMA Descriptor Specific Structures
55599 +//
55600 +
55601 +/** Buffer status definitions */
55602 +
55603 +#define BS_HOST_READY 0x0
55604 +#define BS_DMA_BUSY 0x1
55605 +#define BS_DMA_DONE 0x2
55606 +#define BS_HOST_BUSY 0x3
55607 +
55608 +/** Receive/Transmit status definitions */
55609 +
55610 +#define RTS_SUCCESS 0x0
55611 +#define RTS_BUFFLUSH 0x1
55612 +#define RTS_RESERVED 0x2
55613 +#define RTS_BUFERR 0x3
55614 +
55615 +/**
55616 + * This union represents the bit fields in the DMA Descriptor
55617 + * status quadlet. Read the quadlet into the <i>d32</i> member then
55618 + * set/clear the bits using the <i>b</i>it, <i>b_iso_out</i> and
55619 + * <i>b_iso_in</i> elements.
55620 + */
55621 +typedef union dev_dma_desc_sts {
55622 + /** raw register data */
55623 + uint32_t d32;
55624 + /** quadlet bits */
55625 + struct {
55626 + /** Received number of bytes */
55627 + unsigned bytes:16;
55628 + /** NAK bit - only for OUT EPs */
55629 + unsigned nak:1;
55630 + unsigned reserved17_22:6;
55631 + /** Multiple Transfer - only for OUT EPs */
55632 + unsigned mtrf:1;
55633 + /** Setup Packet received - only for OUT EPs */
55634 + unsigned sr:1;
55635 + /** Interrupt On Complete */
55636 + unsigned ioc:1;
55637 + /** Short Packet */
55638 + unsigned sp:1;
55639 + /** Last */
55640 + unsigned l:1;
55641 + /** Receive Status */
55642 + unsigned sts:2;
55643 + /** Buffer Status */
55644 + unsigned bs:2;
55645 + } b;
55646 +
55647 +//#ifdef DWC_EN_ISOC
55648 + /** iso out quadlet bits */
55649 + struct {
55650 + /** Received number of bytes */
55651 + unsigned rxbytes:11;
55652 +
55653 + unsigned reserved11:1;
55654 + /** Frame Number */
55655 + unsigned framenum:11;
55656 + /** Received ISO Data PID */
55657 + unsigned pid:2;
55658 + /** Interrupt On Complete */
55659 + unsigned ioc:1;
55660 + /** Short Packet */
55661 + unsigned sp:1;
55662 + /** Last */
55663 + unsigned l:1;
55664 + /** Receive Status */
55665 + unsigned rxsts:2;
55666 + /** Buffer Status */
55667 + unsigned bs:2;
55668 + } b_iso_out;
55669 +
55670 + /** iso in quadlet bits */
55671 + struct {
55672 + /** Transmited number of bytes */
55673 + unsigned txbytes:12;
55674 + /** Frame Number */
55675 + unsigned framenum:11;
55676 + /** Transmited ISO Data PID */
55677 + unsigned pid:2;
55678 + /** Interrupt On Complete */
55679 + unsigned ioc:1;
55680 + /** Short Packet */
55681 + unsigned sp:1;
55682 + /** Last */
55683 + unsigned l:1;
55684 + /** Transmit Status */
55685 + unsigned txsts:2;
55686 + /** Buffer Status */
55687 + unsigned bs:2;
55688 + } b_iso_in;
55689 +//#endif /* DWC_EN_ISOC */
55690 +} dev_dma_desc_sts_t;
55691 +
55692 +/**
55693 + * DMA Descriptor structure
55694 + *
55695 + * DMA Descriptor structure contains two quadlets:
55696 + * Status quadlet and Data buffer pointer.
55697 + */
55698 +typedef struct dwc_otg_dev_dma_desc {
55699 + /** DMA Descriptor status quadlet */
55700 + dev_dma_desc_sts_t status;
55701 + /** DMA Descriptor data buffer pointer */
55702 + uint32_t buf;
55703 +} dwc_otg_dev_dma_desc_t;
55704 +
55705 +/**
55706 + * The dwc_otg_dev_if structure contains information needed to manage
55707 + * the DWC_otg controller acting in device mode. It represents the
55708 + * programming view of the device-specific aspects of the controller.
55709 + */
55710 +typedef struct dwc_otg_dev_if {
55711 + /** Pointer to device Global registers.
55712 + * Device Global Registers starting at offset 800h
55713 + */
55714 + dwc_otg_device_global_regs_t *dev_global_regs;
55715 +#define DWC_DEV_GLOBAL_REG_OFFSET 0x800
55716 +
55717 + /**
55718 + * Device Logical IN Endpoint-Specific Registers 900h-AFCh
55719 + */
55720 + dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS];
55721 +#define DWC_DEV_IN_EP_REG_OFFSET 0x900
55722 +#define DWC_EP_REG_OFFSET 0x20
55723 +
55724 + /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */
55725 + dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS];
55726 +#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00
55727 +
55728 + /* Device configuration information */
55729 + uint8_t speed; /**< Device Speed 0: Unknown, 1: LS, 2:FS, 3: HS */
55730 + uint8_t num_in_eps; /**< Number # of Tx EP range: 0-15 exept ep0 */
55731 + uint8_t num_out_eps; /**< Number # of Rx EP range: 0-15 exept ep 0*/
55732 +
55733 + /** Size of periodic FIFOs (Bytes) */
55734 + uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS];
55735 +
55736 + /** Size of Tx FIFOs (Bytes) */
55737 + uint16_t tx_fifo_size[MAX_TX_FIFOS];
55738 +
55739 + /** Thresholding enable flags and length varaiables **/
55740 + uint16_t rx_thr_en;
55741 + uint16_t iso_tx_thr_en;
55742 + uint16_t non_iso_tx_thr_en;
55743 +
55744 + uint16_t rx_thr_length;
55745 + uint16_t tx_thr_length;
55746 +
55747 + /**
55748 + * Pointers to the DMA Descriptors for EP0 Control
55749 + * transfers (virtual and physical)
55750 + */
55751 +
55752 + /** 2 descriptors for SETUP packets */
55753 + dwc_dma_t dma_setup_desc_addr[2];
55754 + dwc_otg_dev_dma_desc_t *setup_desc_addr[2];
55755 +
55756 + /** Pointer to Descriptor with latest SETUP packet */
55757 + dwc_otg_dev_dma_desc_t *psetup;
55758 +
55759 + /** Index of current SETUP handler descriptor */
55760 + uint32_t setup_desc_index;
55761 +
55762 + /** Descriptor for Data In or Status In phases */
55763 + dwc_dma_t dma_in_desc_addr;
55764 + dwc_otg_dev_dma_desc_t *in_desc_addr;
55765 +
55766 + /** Descriptor for Data Out or Status Out phases */
55767 + dwc_dma_t dma_out_desc_addr;
55768 + dwc_otg_dev_dma_desc_t *out_desc_addr;
55769 +
55770 + /** Setup Packet Detected - if set clear NAK when queueing */
55771 + uint32_t spd;
55772 + /** Isoc ep pointer on which incomplete happens */
55773 + void *isoc_ep;
55774 +
55775 +} dwc_otg_dev_if_t;
55776 +
55777 +/////////////////////////////////////////////////
55778 +// Host Mode Register Structures
55779 +//
55780 +/**
55781 + * The Host Global Registers structure defines the size and relative
55782 + * field offsets for the Host Mode Global Registers. Host Global
55783 + * Registers offsets 400h-7FFh.
55784 +*/
55785 +typedef struct dwc_otg_host_global_regs {
55786 + /** Host Configuration Register. <i>Offset: 400h</i> */
55787 + volatile uint32_t hcfg;
55788 + /** Host Frame Interval Register. <i>Offset: 404h</i> */
55789 + volatile uint32_t hfir;
55790 + /** Host Frame Number / Frame Remaining Register. <i>Offset: 408h</i> */
55791 + volatile uint32_t hfnum;
55792 + /** Reserved. <i>Offset: 40Ch</i> */
55793 + uint32_t reserved40C;
55794 + /** Host Periodic Transmit FIFO/ Queue Status Register. <i>Offset: 410h</i> */
55795 + volatile uint32_t hptxsts;
55796 + /** Host All Channels Interrupt Register. <i>Offset: 414h</i> */
55797 + volatile uint32_t haint;
55798 + /** Host All Channels Interrupt Mask Register. <i>Offset: 418h</i> */
55799 + volatile uint32_t haintmsk;
55800 + /** Host Frame List Base Address Register . <i>Offset: 41Ch</i> */
55801 + volatile uint32_t hflbaddr;
55802 +} dwc_otg_host_global_regs_t;
55803 +
55804 +/**
55805 + * This union represents the bit fields in the Host Configuration Register.
55806 + * Read the register into the <i>d32</i> member then set/clear the bits using
55807 + * the <i>b</i>it elements. Write the <i>d32</i> member to the hcfg register.
55808 + */
55809 +typedef union hcfg_data {
55810 + /** raw register data */
55811 + uint32_t d32;
55812 +
55813 + /** register bits */
55814 + struct {
55815 + /** FS/LS Phy Clock Select */
55816 + unsigned fslspclksel:2;
55817 +#define DWC_HCFG_30_60_MHZ 0
55818 +#define DWC_HCFG_48_MHZ 1
55819 +#define DWC_HCFG_6_MHZ 2
55820 +
55821 + /** FS/LS Only Support */
55822 + unsigned fslssupp:1;
55823 + unsigned reserved3_6:4;
55824 + /** Enable 32-KHz Suspend Mode */
55825 + unsigned ena32khzs:1;
55826 + /** Resume Validation Periiod */
55827 + unsigned resvalid:8;
55828 + unsigned reserved16_22:7;
55829 + /** Enable Scatter/gather DMA in Host mode */
55830 + unsigned descdma:1;
55831 + /** Frame List Entries */
55832 + unsigned frlisten:2;
55833 + /** Enable Periodic Scheduling */
55834 + unsigned perschedena:1;
55835 + unsigned reserved27_30:4;
55836 + unsigned modechtimen:1;
55837 + } b;
55838 +} hcfg_data_t;
55839 +
55840 +/**
55841 + * This union represents the bit fields in the Host Frame Remaing/Number
55842 + * Register.
55843 + */
55844 +typedef union hfir_data {
55845 + /** raw register data */
55846 + uint32_t d32;
55847 +
55848 + /** register bits */
55849 + struct {
55850 + unsigned frint:16;
55851 + unsigned hfirrldctrl:1;
55852 + unsigned reserved:15;
55853 + } b;
55854 +} hfir_data_t;
55855 +
55856 +/**
55857 + * This union represents the bit fields in the Host Frame Remaing/Number
55858 + * Register.
55859 + */
55860 +typedef union hfnum_data {
55861 + /** raw register data */
55862 + uint32_t d32;
55863 +
55864 + /** register bits */
55865 + struct {
55866 + unsigned frnum:16;
55867 +#define DWC_HFNUM_MAX_FRNUM 0x3FFF
55868 + unsigned frrem:16;
55869 + } b;
55870 +} hfnum_data_t;
55871 +
55872 +typedef union hptxsts_data {
55873 + /** raw register data */
55874 + uint32_t d32;
55875 +
55876 + /** register bits */
55877 + struct {
55878 + unsigned ptxfspcavail:16;
55879 + unsigned ptxqspcavail:8;
55880 + /** Top of the Periodic Transmit Request Queue
55881 + * - bit 24 - Terminate (last entry for the selected channel)
55882 + * - bits 26:25 - Token Type
55883 + * - 2'b00 - Zero length
55884 + * - 2'b01 - Ping
55885 + * - 2'b10 - Disable
55886 + * - bits 30:27 - Channel Number
55887 + * - bit 31 - Odd/even microframe
55888 + */
55889 + unsigned ptxqtop_terminate:1;
55890 + unsigned ptxqtop_token:2;
55891 + unsigned ptxqtop_chnum:4;
55892 + unsigned ptxqtop_odd:1;
55893 + } b;
55894 +} hptxsts_data_t;
55895 +
55896 +/**
55897 + * This union represents the bit fields in the Host Port Control and Status
55898 + * Register. Read the register into the <i>d32</i> member then set/clear the
55899 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
55900 + * hprt0 register.
55901 + */
55902 +typedef union hprt0_data {
55903 + /** raw register data */
55904 + uint32_t d32;
55905 + /** register bits */
55906 + struct {
55907 + unsigned prtconnsts:1;
55908 + unsigned prtconndet:1;
55909 + unsigned prtena:1;
55910 + unsigned prtenchng:1;
55911 + unsigned prtovrcurract:1;
55912 + unsigned prtovrcurrchng:1;
55913 + unsigned prtres:1;
55914 + unsigned prtsusp:1;
55915 + unsigned prtrst:1;
55916 + unsigned reserved9:1;
55917 + unsigned prtlnsts:2;
55918 + unsigned prtpwr:1;
55919 + unsigned prttstctl:4;
55920 + unsigned prtspd:2;
55921 +#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0
55922 +#define DWC_HPRT0_PRTSPD_FULL_SPEED 1
55923 +#define DWC_HPRT0_PRTSPD_LOW_SPEED 2
55924 + unsigned reserved19_31:13;
55925 + } b;
55926 +} hprt0_data_t;
55927 +
55928 +/**
55929 + * This union represents the bit fields in the Host All Interrupt
55930 + * Register.
55931 + */
55932 +typedef union haint_data {
55933 + /** raw register data */
55934 + uint32_t d32;
55935 + /** register bits */
55936 + struct {
55937 + unsigned ch0:1;
55938 + unsigned ch1:1;
55939 + unsigned ch2:1;
55940 + unsigned ch3:1;
55941 + unsigned ch4:1;
55942 + unsigned ch5:1;
55943 + unsigned ch6:1;
55944 + unsigned ch7:1;
55945 + unsigned ch8:1;
55946 + unsigned ch9:1;
55947 + unsigned ch10:1;
55948 + unsigned ch11:1;
55949 + unsigned ch12:1;
55950 + unsigned ch13:1;
55951 + unsigned ch14:1;
55952 + unsigned ch15:1;
55953 + unsigned reserved:16;
55954 + } b;
55955 +
55956 + struct {
55957 + unsigned chint:16;
55958 + unsigned reserved:16;
55959 + } b2;
55960 +} haint_data_t;
55961 +
55962 +/**
55963 + * This union represents the bit fields in the Host All Interrupt
55964 + * Register.
55965 + */
55966 +typedef union haintmsk_data {
55967 + /** raw register data */
55968 + uint32_t d32;
55969 + /** register bits */
55970 + struct {
55971 + unsigned ch0:1;
55972 + unsigned ch1:1;
55973 + unsigned ch2:1;
55974 + unsigned ch3:1;
55975 + unsigned ch4:1;
55976 + unsigned ch5:1;
55977 + unsigned ch6:1;
55978 + unsigned ch7:1;
55979 + unsigned ch8:1;
55980 + unsigned ch9:1;
55981 + unsigned ch10:1;
55982 + unsigned ch11:1;
55983 + unsigned ch12:1;
55984 + unsigned ch13:1;
55985 + unsigned ch14:1;
55986 + unsigned ch15:1;
55987 + unsigned reserved:16;
55988 + } b;
55989 +
55990 + struct {
55991 + unsigned chint:16;
55992 + unsigned reserved:16;
55993 + } b2;
55994 +} haintmsk_data_t;
55995 +
55996 +/**
55997 + * Host Channel Specific Registers. <i>500h-5FCh</i>
55998 + */
55999 +typedef struct dwc_otg_hc_regs {
56000 + /** Host Channel 0 Characteristic Register. <i>Offset: 500h + (chan_num * 20h) + 00h</i> */
56001 + volatile uint32_t hcchar;
56002 + /** Host Channel 0 Split Control Register. <i>Offset: 500h + (chan_num * 20h) + 04h</i> */
56003 + volatile uint32_t hcsplt;
56004 + /** Host Channel 0 Interrupt Register. <i>Offset: 500h + (chan_num * 20h) + 08h</i> */
56005 + volatile uint32_t hcint;
56006 + /** Host Channel 0 Interrupt Mask Register. <i>Offset: 500h + (chan_num * 20h) + 0Ch</i> */
56007 + volatile uint32_t hcintmsk;
56008 + /** Host Channel 0 Transfer Size Register. <i>Offset: 500h + (chan_num * 20h) + 10h</i> */
56009 + volatile uint32_t hctsiz;
56010 + /** Host Channel 0 DMA Address Register. <i>Offset: 500h + (chan_num * 20h) + 14h</i> */
56011 + volatile uint32_t hcdma;
56012 + volatile uint32_t reserved;
56013 + /** Host Channel 0 DMA Buffer Address Register. <i>Offset: 500h + (chan_num * 20h) + 1Ch</i> */
56014 + volatile uint32_t hcdmab;
56015 +} dwc_otg_hc_regs_t;
56016 +
56017 +/**
56018 + * This union represents the bit fields in the Host Channel Characteristics
56019 + * Register. Read the register into the <i>d32</i> member then set/clear the
56020 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
56021 + * hcchar register.
56022 + */
56023 +typedef union hcchar_data {
56024 + /** raw register data */
56025 + uint32_t d32;
56026 +
56027 + /** register bits */
56028 + struct {
56029 + /** Maximum packet size in bytes */
56030 + unsigned mps:11;
56031 +
56032 + /** Endpoint number */
56033 + unsigned epnum:4;
56034 +
56035 + /** 0: OUT, 1: IN */
56036 + unsigned epdir:1;
56037 +
56038 + unsigned reserved:1;
56039 +
56040 + /** 0: Full/high speed device, 1: Low speed device */
56041 + unsigned lspddev:1;
56042 +
56043 + /** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */
56044 + unsigned eptype:2;
56045 +
56046 + /** Packets per frame for periodic transfers. 0 is reserved. */
56047 + unsigned multicnt:2;
56048 +
56049 + /** Device address */
56050 + unsigned devaddr:7;
56051 +
56052 + /**
56053 + * Frame to transmit periodic transaction.
56054 + * 0: even, 1: odd
56055 + */
56056 + unsigned oddfrm:1;
56057 +
56058 + /** Channel disable */
56059 + unsigned chdis:1;
56060 +
56061 + /** Channel enable */
56062 + unsigned chen:1;
56063 + } b;
56064 +} hcchar_data_t;
56065 +
56066 +typedef union hcsplt_data {
56067 + /** raw register data */
56068 + uint32_t d32;
56069 +
56070 + /** register bits */
56071 + struct {
56072 + /** Port Address */
56073 + unsigned prtaddr:7;
56074 +
56075 + /** Hub Address */
56076 + unsigned hubaddr:7;
56077 +
56078 + /** Transaction Position */
56079 + unsigned xactpos:2;
56080 +#define DWC_HCSPLIT_XACTPOS_MID 0
56081 +#define DWC_HCSPLIT_XACTPOS_END 1
56082 +#define DWC_HCSPLIT_XACTPOS_BEGIN 2
56083 +#define DWC_HCSPLIT_XACTPOS_ALL 3
56084 +
56085 + /** Do Complete Split */
56086 + unsigned compsplt:1;
56087 +
56088 + /** Reserved */
56089 + unsigned reserved:14;
56090 +
56091 + /** Split Enble */
56092 + unsigned spltena:1;
56093 + } b;
56094 +} hcsplt_data_t;
56095 +
56096 +/**
56097 + * This union represents the bit fields in the Host All Interrupt
56098 + * Register.
56099 + */
56100 +typedef union hcint_data {
56101 + /** raw register data */
56102 + uint32_t d32;
56103 + /** register bits */
56104 + struct {
56105 + /** Transfer Complete */
56106 + unsigned xfercomp:1;
56107 + /** Channel Halted */
56108 + unsigned chhltd:1;
56109 + /** AHB Error */
56110 + unsigned ahberr:1;
56111 + /** STALL Response Received */
56112 + unsigned stall:1;
56113 + /** NAK Response Received */
56114 + unsigned nak:1;
56115 + /** ACK Response Received */
56116 + unsigned ack:1;
56117 + /** NYET Response Received */
56118 + unsigned nyet:1;
56119 + /** Transaction Err */
56120 + unsigned xacterr:1;
56121 + /** Babble Error */
56122 + unsigned bblerr:1;
56123 + /** Frame Overrun */
56124 + unsigned frmovrun:1;
56125 + /** Data Toggle Error */
56126 + unsigned datatglerr:1;
56127 + /** Buffer Not Available (only for DDMA mode) */
56128 + unsigned bna:1;
56129 + /** Exessive transaction error (only for DDMA mode) */
56130 + unsigned xcs_xact:1;
56131 + /** Frame List Rollover interrupt */
56132 + unsigned frm_list_roll:1;
56133 + /** Reserved */
56134 + unsigned reserved14_31:18;
56135 + } b;
56136 +} hcint_data_t;
56137 +
56138 +/**
56139 + * This union represents the bit fields in the Host Channel Interrupt Mask
56140 + * Register. Read the register into the <i>d32</i> member then set/clear the
56141 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
56142 + * hcintmsk register.
56143 + */
56144 +typedef union hcintmsk_data {
56145 + /** raw register data */
56146 + uint32_t d32;
56147 +
56148 + /** register bits */
56149 + struct {
56150 + unsigned xfercompl:1;
56151 + unsigned chhltd:1;
56152 + unsigned ahberr:1;
56153 + unsigned stall:1;
56154 + unsigned nak:1;
56155 + unsigned ack:1;
56156 + unsigned nyet:1;
56157 + unsigned xacterr:1;
56158 + unsigned bblerr:1;
56159 + unsigned frmovrun:1;
56160 + unsigned datatglerr:1;
56161 + unsigned bna:1;
56162 + unsigned xcs_xact:1;
56163 + unsigned frm_list_roll:1;
56164 + unsigned reserved14_31:18;
56165 + } b;
56166 +} hcintmsk_data_t;
56167 +
56168 +/**
56169 + * This union represents the bit fields in the Host Channel Transfer Size
56170 + * Register. Read the register into the <i>d32</i> member then set/clear the
56171 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
56172 + * hcchar register.
56173 + */
56174 +
56175 +typedef union hctsiz_data {
56176 + /** raw register data */
56177 + uint32_t d32;
56178 +
56179 + /** register bits */
56180 + struct {
56181 + /** Total transfer size in bytes */
56182 + unsigned xfersize:19;
56183 +
56184 + /** Data packets to transfer */
56185 + unsigned pktcnt:10;
56186 +
56187 + /**
56188 + * Packet ID for next data packet
56189 + * 0: DATA0
56190 + * 1: DATA2
56191 + * 2: DATA1
56192 + * 3: MDATA (non-Control), SETUP (Control)
56193 + */
56194 + unsigned pid:2;
56195 +#define DWC_HCTSIZ_DATA0 0
56196 +#define DWC_HCTSIZ_DATA1 2
56197 +#define DWC_HCTSIZ_DATA2 1
56198 +#define DWC_HCTSIZ_MDATA 3
56199 +#define DWC_HCTSIZ_SETUP 3
56200 +
56201 + /** Do PING protocol when 1 */
56202 + unsigned dopng:1;
56203 + } b;
56204 +
56205 + /** register bits */
56206 + struct {
56207 + /** Scheduling information */
56208 + unsigned schinfo:8;
56209 +
56210 + /** Number of transfer descriptors.
56211 + * Max value:
56212 + * 64 in general,
56213 + * 256 only for HS isochronous endpoint.
56214 + */
56215 + unsigned ntd:8;
56216 +
56217 + /** Data packets to transfer */
56218 + unsigned reserved16_28:13;
56219 +
56220 + /**
56221 + * Packet ID for next data packet
56222 + * 0: DATA0
56223 + * 1: DATA2
56224 + * 2: DATA1
56225 + * 3: MDATA (non-Control)
56226 + */
56227 + unsigned pid:2;
56228 +
56229 + /** Do PING protocol when 1 */
56230 + unsigned dopng:1;
56231 + } b_ddma;
56232 +} hctsiz_data_t;
56233 +
56234 +/**
56235 + * This union represents the bit fields in the Host DMA Address
56236 + * Register used in Descriptor DMA mode.
56237 + */
56238 +typedef union hcdma_data {
56239 + /** raw register data */
56240 + uint32_t d32;
56241 + /** register bits */
56242 + struct {
56243 + unsigned reserved0_2:3;
56244 + /** Current Transfer Descriptor. Not used for ISOC */
56245 + unsigned ctd:8;
56246 + /** Start Address of Descriptor List */
56247 + unsigned dma_addr:21;
56248 + } b;
56249 +} hcdma_data_t;
56250 +
56251 +/**
56252 + * This union represents the bit fields in the DMA Descriptor
56253 + * status quadlet for host mode. Read the quadlet into the <i>d32</i> member then
56254 + * set/clear the bits using the <i>b</i>it elements.
56255 + */
56256 +typedef union host_dma_desc_sts {
56257 + /** raw register data */
56258 + uint32_t d32;
56259 + /** quadlet bits */
56260 +
56261 + /* for non-isochronous */
56262 + struct {
56263 + /** Number of bytes */
56264 + unsigned n_bytes:17;
56265 + /** QTD offset to jump when Short Packet received - only for IN EPs */
56266 + unsigned qtd_offset:6;
56267 + /**
56268 + * Set to request the core to jump to alternate QTD if
56269 + * Short Packet received - only for IN EPs
56270 + */
56271 + unsigned a_qtd:1;
56272 + /**
56273 + * Setup Packet bit. When set indicates that buffer contains
56274 + * setup packet.
56275 + */
56276 + unsigned sup:1;
56277 + /** Interrupt On Complete */
56278 + unsigned ioc:1;
56279 + /** End of List */
56280 + unsigned eol:1;
56281 + unsigned reserved27:1;
56282 + /** Rx/Tx Status */
56283 + unsigned sts:2;
56284 +#define DMA_DESC_STS_PKTERR 1
56285 + unsigned reserved30:1;
56286 + /** Active Bit */
56287 + unsigned a:1;
56288 + } b;
56289 + /* for isochronous */
56290 + struct {
56291 + /** Number of bytes */
56292 + unsigned n_bytes:12;
56293 + unsigned reserved12_24:13;
56294 + /** Interrupt On Complete */
56295 + unsigned ioc:1;
56296 + unsigned reserved26_27:2;
56297 + /** Rx/Tx Status */
56298 + unsigned sts:2;
56299 + unsigned reserved30:1;
56300 + /** Active Bit */
56301 + unsigned a:1;
56302 + } b_isoc;
56303 +} host_dma_desc_sts_t;
56304 +
56305 +#define MAX_DMA_DESC_SIZE 131071
56306 +#define MAX_DMA_DESC_NUM_GENERIC 64
56307 +#define MAX_DMA_DESC_NUM_HS_ISOC 256
56308 +#define MAX_FRLIST_EN_NUM 64
56309 +/**
56310 + * Host-mode DMA Descriptor structure
56311 + *
56312 + * DMA Descriptor structure contains two quadlets:
56313 + * Status quadlet and Data buffer pointer.
56314 + */
56315 +typedef struct dwc_otg_host_dma_desc {
56316 + /** DMA Descriptor status quadlet */
56317 + host_dma_desc_sts_t status;
56318 + /** DMA Descriptor data buffer pointer */
56319 + uint32_t buf;
56320 +} dwc_otg_host_dma_desc_t;
56321 +
56322 +/** OTG Host Interface Structure.
56323 + *
56324 + * The OTG Host Interface Structure structure contains information
56325 + * needed to manage the DWC_otg controller acting in host mode. It
56326 + * represents the programming view of the host-specific aspects of the
56327 + * controller.
56328 + */
56329 +typedef struct dwc_otg_host_if {
56330 + /** Host Global Registers starting at offset 400h.*/
56331 + dwc_otg_host_global_regs_t *host_global_regs;
56332 +#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400
56333 +
56334 + /** Host Port 0 Control and Status Register */
56335 + volatile uint32_t *hprt0;
56336 +#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440
56337 +
56338 + /** Host Channel Specific Registers at offsets 500h-5FCh. */
56339 + dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS];
56340 +#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500
56341 +#define DWC_OTG_CHAN_REGS_OFFSET 0x20
56342 +
56343 + /* Host configuration information */
56344 + /** Number of Host Channels (range: 1-16) */
56345 + uint8_t num_host_channels;
56346 + /** Periodic EPs supported (0: no, 1: yes) */
56347 + uint8_t perio_eps_supported;
56348 + /** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */
56349 + uint16_t perio_tx_fifo_size;
56350 +
56351 +} dwc_otg_host_if_t;
56352 +
56353 +/**
56354 + * This union represents the bit fields in the Power and Clock Gating Control
56355 + * Register. Read the register into the <i>d32</i> member then set/clear the
56356 + * bits using the <i>b</i>it elements.
56357 + */
56358 +typedef union pcgcctl_data {
56359 + /** raw register data */
56360 + uint32_t d32;
56361 +
56362 + /** register bits */
56363 + struct {
56364 + /** Stop Pclk */
56365 + unsigned stoppclk:1;
56366 + /** Gate Hclk */
56367 + unsigned gatehclk:1;
56368 + /** Power Clamp */
56369 + unsigned pwrclmp:1;
56370 + /** Reset Power Down Modules */
56371 + unsigned rstpdwnmodule:1;
56372 + /** Reserved */
56373 + unsigned reserved:1;
56374 + /** Enable Sleep Clock Gating (Enbl_L1Gating) */
56375 + unsigned enbl_sleep_gating:1;
56376 + /** PHY In Sleep (PhySleep) */
56377 + unsigned phy_in_sleep:1;
56378 + /** Deep Sleep*/
56379 + unsigned deep_sleep:1;
56380 + unsigned resetaftsusp:1;
56381 + unsigned restoremode:1;
56382 + unsigned enbl_extnd_hiber:1;
56383 + unsigned extnd_hiber_pwrclmp:1;
56384 + unsigned extnd_hiber_switch:1;
56385 + unsigned ess_reg_restored:1;
56386 + unsigned prt_clk_sel:2;
56387 + unsigned port_power:1;
56388 + unsigned max_xcvrselect:2;
56389 + unsigned max_termsel:1;
56390 + unsigned mac_dev_addr:7;
56391 + unsigned p2hd_dev_enum_spd:2;
56392 + unsigned p2hd_prt_spd:2;
56393 + unsigned if_dev_mode:1;
56394 + } b;
56395 +} pcgcctl_data_t;
56396 +
56397 +/**
56398 + * This union represents the bit fields in the Global Data FIFO Software
56399 + * Configuration Register. Read the register into the <i>d32</i> member then
56400 + * set/clear the bits using the <i>b</i>it elements.
56401 + */
56402 +typedef union gdfifocfg_data {
56403 + /* raw register data */
56404 + uint32_t d32;
56405 + /** register bits */
56406 + struct {
56407 + /** OTG Data FIFO depth */
56408 + unsigned gdfifocfg:16;
56409 + /** Start address of EP info controller */
56410 + unsigned epinfobase:16;
56411 + } b;
56412 +} gdfifocfg_data_t;
56413 +
56414 +/**
56415 + * This union represents the bit fields in the Global Power Down Register
56416 + * Register. Read the register into the <i>d32</i> member then set/clear the
56417 + * bits using the <i>b</i>it elements.
56418 + */
56419 +typedef union gpwrdn_data {
56420 + /* raw register data */
56421 + uint32_t d32;
56422 +
56423 + /** register bits */
56424 + struct {
56425 + /** PMU Interrupt Select */
56426 + unsigned pmuintsel:1;
56427 + /** PMU Active */
56428 + unsigned pmuactv:1;
56429 + /** Restore */
56430 + unsigned restore:1;
56431 + /** Power Down Clamp */
56432 + unsigned pwrdnclmp:1;
56433 + /** Power Down Reset */
56434 + unsigned pwrdnrstn:1;
56435 + /** Power Down Switch */
56436 + unsigned pwrdnswtch:1;
56437 + /** Disable VBUS */
56438 + unsigned dis_vbus:1;
56439 + /** Line State Change */
56440 + unsigned lnstschng:1;
56441 + /** Line state change mask */
56442 + unsigned lnstchng_msk:1;
56443 + /** Reset Detected */
56444 + unsigned rst_det:1;
56445 + /** Reset Detect mask */
56446 + unsigned rst_det_msk:1;
56447 + /** Disconnect Detected */
56448 + unsigned disconn_det:1;
56449 + /** Disconnect Detect mask */
56450 + unsigned disconn_det_msk:1;
56451 + /** Connect Detected*/
56452 + unsigned connect_det:1;
56453 + /** Connect Detected Mask*/
56454 + unsigned connect_det_msk:1;
56455 + /** SRP Detected */
56456 + unsigned srp_det:1;
56457 + /** SRP Detect mask */
56458 + unsigned srp_det_msk:1;
56459 + /** Status Change Interrupt */
56460 + unsigned sts_chngint:1;
56461 + /** Status Change Interrupt Mask */
56462 + unsigned sts_chngint_msk:1;
56463 + /** Line State */
56464 + unsigned linestate:2;
56465 + /** Indicates current mode(status of IDDIG signal) */
56466 + unsigned idsts:1;
56467 + /** B Session Valid signal status*/
56468 + unsigned bsessvld:1;
56469 + /** ADP Event Detected */
56470 + unsigned adp_int:1;
56471 + /** Multi Valued ID pin */
56472 + unsigned mult_val_id_bc:5;
56473 + /** Reserved 24_31 */
56474 + unsigned reserved29_31:3;
56475 + } b;
56476 +} gpwrdn_data_t;
56477 +
56478 +#endif
56479 --- /dev/null
56480 +++ b/drivers/usb/host/dwc_otg/Makefile
56481 @@ -0,0 +1,81 @@
56482 +#
56483 +# Makefile for DWC_otg Highspeed USB controller driver
56484 +#
56485 +
56486 +ifneq ($(KERNELRELEASE),)
56487 +
56488 +# Use the BUS_INTERFACE variable to compile the software for either
56489 +# PCI(PCI_INTERFACE) or LM(LM_INTERFACE) bus.
56490 +ifeq ($(BUS_INTERFACE),)
56491 +# BUS_INTERFACE = -DPCI_INTERFACE
56492 +# BUS_INTERFACE = -DLM_INTERFACE
56493 + BUS_INTERFACE = -DPLATFORM_INTERFACE
56494 +endif
56495 +
56496 +#EXTRA_CFLAGS += -DDEBUG
56497 +#EXTRA_CFLAGS += -DDWC_OTG_DEBUGLEV=1 # reduce common debug msgs
56498 +
56499 +# Use one of the following flags to compile the software in host-only or
56500 +# device-only mode.
56501 +#EXTRA_CFLAGS += -DDWC_HOST_ONLY
56502 +#EXTRA_CFLAGS += -DDWC_DEVICE_ONLY
56503 +
56504 +EXTRA_CFLAGS += -Dlinux -DDWC_HS_ELECT_TST
56505 +#EXTRA_CFLAGS += -DDWC_EN_ISOC
56506 +EXTRA_CFLAGS += -I$(obj)/../dwc_common_port
56507 +#EXTRA_CFLAGS += -I$(PORTLIB)
56508 +EXTRA_CFLAGS += -DDWC_LINUX
56509 +EXTRA_CFLAGS += $(CFI)
56510 +EXTRA_CFLAGS += $(BUS_INTERFACE)
56511 +#EXTRA_CFLAGS += -DDWC_DEV_SRPCAP
56512 +
56513 +obj-$(CONFIG_USB_DWCOTG) += dwc_otg.o
56514 +
56515 +dwc_otg-objs := dwc_otg_driver.o dwc_otg_attr.o
56516 +dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o
56517 +dwc_otg-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o
56518 +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
56519 +dwc_otg-objs += dwc_otg_adp.o
56520 +dwc_otg-objs += dwc_otg_mphi_fix.o
56521 +ifneq ($(CFI),)
56522 +dwc_otg-objs += dwc_otg_cfi.o
56523 +endif
56524 +
56525 +kernrelwd := $(subst ., ,$(KERNELRELEASE))
56526 +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
56527 +
56528 +ifneq ($(kernrel3),2.6.20)
56529 +EXTRA_CFLAGS += $(CPPFLAGS)
56530 +endif
56531 +
56532 +else
56533 +
56534 +PWD := $(shell pwd)
56535 +PORTLIB := $(PWD)/../dwc_common_port
56536 +
56537 +# Command paths
56538 +CTAGS := $(CTAGS)
56539 +DOXYGEN := $(DOXYGEN)
56540 +
56541 +default: portlib
56542 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
56543 +
56544 +install: default
56545 + $(MAKE) -C$(KDIR) M=$(PORTLIB) modules_install
56546 + $(MAKE) -C$(KDIR) M=$(PWD) modules_install
56547 +
56548 +portlib:
56549 + $(MAKE) -C$(KDIR) M=$(PORTLIB) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
56550 + cp $(PORTLIB)/Module.symvers $(PWD)/
56551 +
56552 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
56553 + $(DOXYGEN) doc/doxygen.cfg
56554 +
56555 +tags: $(wildcard *.[hc])
56556 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
56557 +
56558 +
56559 +clean:
56560 + rm -rf *.o *.ko .*cmd *.mod.c .tmp_versions Module.symvers
56561 +
56562 +endif
56563 --- /dev/null
56564 +++ b/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
56565 @@ -0,0 +1,337 @@
56566 +package dwc_otg_test;
56567 +
56568 +use strict;
56569 +use Exporter ();
56570 +
56571 +use vars qw(@ISA @EXPORT
56572 +$sysfsdir $paramdir $errors $params
56573 +);
56574 +
56575 +@ISA = qw(Exporter);
56576 +
56577 +#
56578 +# Globals
56579 +#
56580 +$sysfsdir = "/sys/devices/lm0";
56581 +$paramdir = "/sys/module/dwc_otg";
56582 +$errors = 0;
56583 +
56584 +$params = [
56585 + {
56586 + NAME => "otg_cap",
56587 + DEFAULT => 0,
56588 + ENUM => [],
56589 + LOW => 0,
56590 + HIGH => 2
56591 + },
56592 + {
56593 + NAME => "dma_enable",
56594 + DEFAULT => 0,
56595 + ENUM => [],
56596 + LOW => 0,
56597 + HIGH => 1
56598 + },
56599 + {
56600 + NAME => "dma_burst_size",
56601 + DEFAULT => 32,
56602 + ENUM => [1, 4, 8, 16, 32, 64, 128, 256],
56603 + LOW => 1,
56604 + HIGH => 256
56605 + },
56606 + {
56607 + NAME => "host_speed",
56608 + DEFAULT => 0,
56609 + ENUM => [],
56610 + LOW => 0,
56611 + HIGH => 1
56612 + },
56613 + {
56614 + NAME => "host_support_fs_ls_low_power",
56615 + DEFAULT => 0,
56616 + ENUM => [],
56617 + LOW => 0,
56618 + HIGH => 1
56619 + },
56620 + {
56621 + NAME => "host_ls_low_power_phy_clk",
56622 + DEFAULT => 0,
56623 + ENUM => [],
56624 + LOW => 0,
56625 + HIGH => 1
56626 + },
56627 + {
56628 + NAME => "dev_speed",
56629 + DEFAULT => 0,
56630 + ENUM => [],
56631 + LOW => 0,
56632 + HIGH => 1
56633 + },
56634 + {
56635 + NAME => "enable_dynamic_fifo",
56636 + DEFAULT => 1,
56637 + ENUM => [],
56638 + LOW => 0,
56639 + HIGH => 1
56640 + },
56641 + {
56642 + NAME => "data_fifo_size",
56643 + DEFAULT => 8192,
56644 + ENUM => [],
56645 + LOW => 32,
56646 + HIGH => 32768
56647 + },
56648 + {
56649 + NAME => "dev_rx_fifo_size",
56650 + DEFAULT => 1064,
56651 + ENUM => [],
56652 + LOW => 16,
56653 + HIGH => 32768
56654 + },
56655 + {
56656 + NAME => "dev_nperio_tx_fifo_size",
56657 + DEFAULT => 1024,
56658 + ENUM => [],
56659 + LOW => 16,
56660 + HIGH => 32768
56661 + },
56662 + {
56663 + NAME => "dev_perio_tx_fifo_size_1",
56664 + DEFAULT => 256,
56665 + ENUM => [],
56666 + LOW => 4,
56667 + HIGH => 768
56668 + },
56669 + {
56670 + NAME => "dev_perio_tx_fifo_size_2",
56671 + DEFAULT => 256,
56672 + ENUM => [],
56673 + LOW => 4,
56674 + HIGH => 768
56675 + },
56676 + {
56677 + NAME => "dev_perio_tx_fifo_size_3",
56678 + DEFAULT => 256,
56679 + ENUM => [],
56680 + LOW => 4,
56681 + HIGH => 768
56682 + },
56683 + {
56684 + NAME => "dev_perio_tx_fifo_size_4",
56685 + DEFAULT => 256,
56686 + ENUM => [],
56687 + LOW => 4,
56688 + HIGH => 768
56689 + },
56690 + {
56691 + NAME => "dev_perio_tx_fifo_size_5",
56692 + DEFAULT => 256,
56693 + ENUM => [],
56694 + LOW => 4,
56695 + HIGH => 768
56696 + },
56697 + {
56698 + NAME => "dev_perio_tx_fifo_size_6",
56699 + DEFAULT => 256,
56700 + ENUM => [],
56701 + LOW => 4,
56702 + HIGH => 768
56703 + },
56704 + {
56705 + NAME => "dev_perio_tx_fifo_size_7",
56706 + DEFAULT => 256,
56707 + ENUM => [],
56708 + LOW => 4,
56709 + HIGH => 768
56710 + },
56711 + {
56712 + NAME => "dev_perio_tx_fifo_size_8",
56713 + DEFAULT => 256,
56714 + ENUM => [],
56715 + LOW => 4,
56716 + HIGH => 768
56717 + },
56718 + {
56719 + NAME => "dev_perio_tx_fifo_size_9",
56720 + DEFAULT => 256,
56721 + ENUM => [],
56722 + LOW => 4,
56723 + HIGH => 768
56724 + },
56725 + {
56726 + NAME => "dev_perio_tx_fifo_size_10",
56727 + DEFAULT => 256,
56728 + ENUM => [],
56729 + LOW => 4,
56730 + HIGH => 768
56731 + },
56732 + {
56733 + NAME => "dev_perio_tx_fifo_size_11",
56734 + DEFAULT => 256,
56735 + ENUM => [],
56736 + LOW => 4,
56737 + HIGH => 768
56738 + },
56739 + {
56740 + NAME => "dev_perio_tx_fifo_size_12",
56741 + DEFAULT => 256,
56742 + ENUM => [],
56743 + LOW => 4,
56744 + HIGH => 768
56745 + },
56746 + {
56747 + NAME => "dev_perio_tx_fifo_size_13",
56748 + DEFAULT => 256,
56749 + ENUM => [],
56750 + LOW => 4,
56751 + HIGH => 768
56752 + },
56753 + {
56754 + NAME => "dev_perio_tx_fifo_size_14",
56755 + DEFAULT => 256,
56756 + ENUM => [],
56757 + LOW => 4,
56758 + HIGH => 768
56759 + },
56760 + {
56761 + NAME => "dev_perio_tx_fifo_size_15",
56762 + DEFAULT => 256,
56763 + ENUM => [],
56764 + LOW => 4,
56765 + HIGH => 768
56766 + },
56767 + {
56768 + NAME => "host_rx_fifo_size",
56769 + DEFAULT => 1024,
56770 + ENUM => [],
56771 + LOW => 16,
56772 + HIGH => 32768
56773 + },
56774 + {
56775 + NAME => "host_nperio_tx_fifo_size",
56776 + DEFAULT => 1024,
56777 + ENUM => [],
56778 + LOW => 16,
56779 + HIGH => 32768
56780 + },
56781 + {
56782 + NAME => "host_perio_tx_fifo_size",
56783 + DEFAULT => 1024,
56784 + ENUM => [],
56785 + LOW => 16,
56786 + HIGH => 32768
56787 + },
56788 + {
56789 + NAME => "max_transfer_size",
56790 + DEFAULT => 65535,
56791 + ENUM => [],
56792 + LOW => 2047,
56793 + HIGH => 65535
56794 + },
56795 + {
56796 + NAME => "max_packet_count",
56797 + DEFAULT => 511,
56798 + ENUM => [],
56799 + LOW => 15,
56800 + HIGH => 511
56801 + },
56802 + {
56803 + NAME => "host_channels",
56804 + DEFAULT => 12,
56805 + ENUM => [],
56806 + LOW => 1,
56807 + HIGH => 16
56808 + },
56809 + {
56810 + NAME => "dev_endpoints",
56811 + DEFAULT => 6,
56812 + ENUM => [],
56813 + LOW => 1,
56814 + HIGH => 15
56815 + },
56816 + {
56817 + NAME => "phy_type",
56818 + DEFAULT => 1,
56819 + ENUM => [],
56820 + LOW => 0,
56821 + HIGH => 2
56822 + },
56823 + {
56824 + NAME => "phy_utmi_width",
56825 + DEFAULT => 16,
56826 + ENUM => [8, 16],
56827 + LOW => 8,
56828 + HIGH => 16
56829 + },
56830 + {
56831 + NAME => "phy_ulpi_ddr",
56832 + DEFAULT => 0,
56833 + ENUM => [],
56834 + LOW => 0,
56835 + HIGH => 1
56836 + },
56837 + ];
56838 +
56839 +
56840 +#
56841 +#
56842 +sub check_arch {
56843 + $_ = `uname -m`;
56844 + chomp;
56845 + unless (m/armv4tl/) {
56846 + warn "# \n# Can't execute on $_. Run on integrator platform.\n# \n";
56847 + return 0;
56848 + }
56849 + return 1;
56850 +}
56851 +
56852 +#
56853 +#
56854 +sub load_module {
56855 + my $params = shift;
56856 + print "\nRemoving Module\n";
56857 + system "rmmod dwc_otg";
56858 + print "Loading Module\n";
56859 + if ($params ne "") {
56860 + print "Module Parameters: $params\n";
56861 + }
56862 + if (system("modprobe dwc_otg $params")) {
56863 + warn "Unable to load module\n";
56864 + return 0;
56865 + }
56866 + return 1;
56867 +}
56868 +
56869 +#
56870 +#
56871 +sub test_status {
56872 + my $arg = shift;
56873 +
56874 + print "\n";
56875 +
56876 + if (defined $arg) {
56877 + warn "WARNING: $arg\n";
56878 + }
56879 +
56880 + if ($errors > 0) {
56881 + warn "TEST FAILED with $errors errors\n";
56882 + return 0;
56883 + } else {
56884 + print "TEST PASSED\n";
56885 + return 0 if (defined $arg);
56886 + }
56887 + return 1;
56888 +}
56889 +
56890 +#
56891 +#
56892 +@EXPORT = qw(
56893 +$sysfsdir
56894 +$paramdir
56895 +$params
56896 +$errors
56897 +check_arch
56898 +load_module
56899 +test_status
56900 +);
56901 +
56902 +1;
56903 --- /dev/null
56904 +++ b/drivers/usb/host/dwc_otg/test/Makefile
56905 @@ -0,0 +1,16 @@
56906 +
56907 +PERL=/usr/bin/perl
56908 +PL_TESTS=test_sysfs.pl test_mod_param.pl
56909 +
56910 +.PHONY : test
56911 +test : perl_tests
56912 +
56913 +perl_tests :
56914 + @echo
56915 + @echo Running perl tests
56916 + @for test in $(PL_TESTS); do \
56917 + if $(PERL) ./$$test ; then \
56918 + echo "=======> $$test, PASSED" ; \
56919 + else echo "=======> $$test, FAILED" ; \
56920 + fi \
56921 + done
56922 --- /dev/null
56923 +++ b/drivers/usb/host/dwc_otg/test/test_mod_param.pl
56924 @@ -0,0 +1,133 @@
56925 +#!/usr/bin/perl -w
56926 +#
56927 +# Run this program on the integrator.
56928 +#
56929 +# - Tests module parameter default values.
56930 +# - Tests setting of valid module parameter values via modprobe.
56931 +# - Tests invalid module parameter values.
56932 +# -----------------------------------------------------------------------------
56933 +use strict;
56934 +use dwc_otg_test;
56935 +
56936 +check_arch() or die;
56937 +
56938 +#
56939 +#
56940 +sub test {
56941 + my ($param,$expected) = @_;
56942 + my $value = get($param);
56943 +
56944 + if ($value == $expected) {
56945 + print "$param = $value, okay\n";
56946 + }
56947 +
56948 + else {
56949 + warn "ERROR: value of $param != $expected, $value\n";
56950 + $errors ++;
56951 + }
56952 +}
56953 +
56954 +#
56955 +#
56956 +sub get {
56957 + my $param = shift;
56958 + my $tmp = `cat $paramdir/$param`;
56959 + chomp $tmp;
56960 + return $tmp;
56961 +}
56962 +
56963 +#
56964 +#
56965 +sub test_main {
56966 +
56967 + print "\nTesting Module Parameters\n";
56968 +
56969 + load_module("") or die;
56970 +
56971 + # Test initial values
56972 + print "\nTesting Default Values\n";
56973 + foreach (@{$params}) {
56974 + test ($_->{NAME}, $_->{DEFAULT});
56975 + }
56976 +
56977 + # Test low value
56978 + print "\nTesting Low Value\n";
56979 + my $cmd_params = "";
56980 + foreach (@{$params}) {
56981 + $cmd_params = $cmd_params . "$_->{NAME}=$_->{LOW} ";
56982 + }
56983 + load_module($cmd_params) or die;
56984 +
56985 + foreach (@{$params}) {
56986 + test ($_->{NAME}, $_->{LOW});
56987 + }
56988 +
56989 + # Test high value
56990 + print "\nTesting High Value\n";
56991 + $cmd_params = "";
56992 + foreach (@{$params}) {
56993 + $cmd_params = $cmd_params . "$_->{NAME}=$_->{HIGH} ";
56994 + }
56995 + load_module($cmd_params) or die;
56996 +
56997 + foreach (@{$params}) {
56998 + test ($_->{NAME}, $_->{HIGH});
56999 + }
57000 +
57001 + # Test Enum
57002 + print "\nTesting Enumerated\n";
57003 + foreach (@{$params}) {
57004 + if (defined $_->{ENUM}) {
57005 + my $value;
57006 + foreach $value (@{$_->{ENUM}}) {
57007 + $cmd_params = "$_->{NAME}=$value";
57008 + load_module($cmd_params) or die;
57009 + test ($_->{NAME}, $value);
57010 + }
57011 + }
57012 + }
57013 +
57014 + # Test Invalid Values
57015 + print "\nTesting Invalid Values\n";
57016 + $cmd_params = "";
57017 + foreach (@{$params}) {
57018 + $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{LOW}-1;
57019 + }
57020 + load_module($cmd_params) or die;
57021 +
57022 + foreach (@{$params}) {
57023 + test ($_->{NAME}, $_->{DEFAULT});
57024 + }
57025 +
57026 + $cmd_params = "";
57027 + foreach (@{$params}) {
57028 + $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{HIGH}+1;
57029 + }
57030 + load_module($cmd_params) or die;
57031 +
57032 + foreach (@{$params}) {
57033 + test ($_->{NAME}, $_->{DEFAULT});
57034 + }
57035 +
57036 + print "\nTesting Enumerated\n";
57037 + foreach (@{$params}) {
57038 + if (defined $_->{ENUM}) {
57039 + my $value;
57040 + foreach $value (@{$_->{ENUM}}) {
57041 + $value = $value + 1;
57042 + $cmd_params = "$_->{NAME}=$value";
57043 + load_module($cmd_params) or die;
57044 + test ($_->{NAME}, $_->{DEFAULT});
57045 + $value = $value - 2;
57046 + $cmd_params = "$_->{NAME}=$value";
57047 + load_module($cmd_params) or die;
57048 + test ($_->{NAME}, $_->{DEFAULT});
57049 + }
57050 + }
57051 + }
57052 +
57053 + test_status() or die;
57054 +}
57055 +
57056 +test_main();
57057 +0;
57058 --- /dev/null
57059 +++ b/drivers/usb/host/dwc_otg/test/test_sysfs.pl
57060 @@ -0,0 +1,193 @@
57061 +#!/usr/bin/perl -w
57062 +#
57063 +# Run this program on the integrator
57064 +# - Tests select sysfs attributes.
57065 +# - Todo ... test more attributes, hnp/srp, buspower/bussuspend, etc.
57066 +# -----------------------------------------------------------------------------
57067 +use strict;
57068 +use dwc_otg_test;
57069 +
57070 +check_arch() or die;
57071 +
57072 +#
57073 +#
57074 +sub test {
57075 + my ($attr,$expected) = @_;
57076 + my $string = get($attr);
57077 +
57078 + if ($string eq $expected) {
57079 + printf("$attr = $string, okay\n");
57080 + }
57081 + else {
57082 + warn "ERROR: value of $attr != $expected, $string\n";
57083 + $errors ++;
57084 + }
57085 +}
57086 +
57087 +#
57088 +#
57089 +sub set {
57090 + my ($reg, $value) = @_;
57091 + system "echo $value > $sysfsdir/$reg";
57092 +}
57093 +
57094 +#
57095 +#
57096 +sub get {
57097 + my $attr = shift;
57098 + my $string = `cat $sysfsdir/$attr`;
57099 + chomp $string;
57100 + if ($string =~ m/\s\=\s/) {
57101 + my $tmp;
57102 + ($tmp, $string) = split /\s=\s/, $string;
57103 + }
57104 + return $string;
57105 +}
57106 +
57107 +#
57108 +#
57109 +sub test_main {
57110 + print("\nTesting Sysfs Attributes\n");
57111 +
57112 + load_module("") or die;
57113 +
57114 + # Test initial values of regoffset/regvalue/guid/gsnpsid
57115 + print("\nTesting Default Values\n");
57116 +
57117 + test("regoffset", "0xffffffff");
57118 + test("regvalue", "invalid offset");
57119 + test("guid", "0x12345678"); # this will fail if it has been changed
57120 + test("gsnpsid", "0x4f54200a");
57121 +
57122 + # Test operation of regoffset/regvalue
57123 + print("\nTesting regoffset\n");
57124 + set('regoffset', '5a5a5a5a');
57125 + test("regoffset", "0xffffffff");
57126 +
57127 + set('regoffset', '0');
57128 + test("regoffset", "0x00000000");
57129 +
57130 + set('regoffset', '40000');
57131 + test("regoffset", "0x00000000");
57132 +
57133 + set('regoffset', '3ffff');
57134 + test("regoffset", "0x0003ffff");
57135 +
57136 + set('regoffset', '1');
57137 + test("regoffset", "0x00000001");
57138 +
57139 + print("\nTesting regvalue\n");
57140 + set('regoffset', '3c');
57141 + test("regvalue", "0x12345678");
57142 + set('regvalue', '5a5a5a5a');
57143 + test("regvalue", "0x5a5a5a5a");
57144 + set('regvalue','a5a5a5a5');
57145 + test("regvalue", "0xa5a5a5a5");
57146 + set('guid','12345678');
57147 +
57148 + # Test HNP Capable
57149 + print("\nTesting HNP Capable bit\n");
57150 + set('hnpcapable', '1');
57151 + test("hnpcapable", "0x1");
57152 + set('hnpcapable','0');
57153 + test("hnpcapable", "0x0");
57154 +
57155 + set('regoffset','0c');
57156 +
57157 + my $old = get('gusbcfg');
57158 + print("setting hnpcapable\n");
57159 + set('hnpcapable', '1');
57160 + test("hnpcapable", "0x1");
57161 + test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<9)));
57162 + test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<9)));
57163 +
57164 + $old = get('gusbcfg');
57165 + print("clearing hnpcapable\n");
57166 + set('hnpcapable', '0');
57167 + test("hnpcapable", "0x0");
57168 + test ('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<9)));
57169 + test ('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<9)));
57170 +
57171 + # Test SRP Capable
57172 + print("\nTesting SRP Capable bit\n");
57173 + set('srpcapable', '1');
57174 + test("srpcapable", "0x1");
57175 + set('srpcapable','0');
57176 + test("srpcapable", "0x0");
57177 +
57178 + set('regoffset','0c');
57179 +
57180 + $old = get('gusbcfg');
57181 + print("setting srpcapable\n");
57182 + set('srpcapable', '1');
57183 + test("srpcapable", "0x1");
57184 + test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<8)));
57185 + test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<8)));
57186 +
57187 + $old = get('gusbcfg');
57188 + print("clearing srpcapable\n");
57189 + set('srpcapable', '0');
57190 + test("srpcapable", "0x0");
57191 + test('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<8)));
57192 + test('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<8)));
57193 +
57194 + # Test GGPIO
57195 + print("\nTesting GGPIO\n");
57196 + set('ggpio','5a5a5a5a');
57197 + test('ggpio','0x5a5a0000');
57198 + set('ggpio','a5a5a5a5');
57199 + test('ggpio','0xa5a50000');
57200 + set('ggpio','11110000');
57201 + test('ggpio','0x11110000');
57202 + set('ggpio','00001111');
57203 + test('ggpio','0x00000000');
57204 +
57205 + # Test DEVSPEED
57206 + print("\nTesting DEVSPEED\n");
57207 + set('regoffset','800');
57208 + $old = get('regvalue');
57209 + set('devspeed','0');
57210 + test('devspeed','0x0');
57211 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
57212 + set('devspeed','1');
57213 + test('devspeed','0x1');
57214 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
57215 + set('devspeed','2');
57216 + test('devspeed','0x2');
57217 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 2));
57218 + set('devspeed','3');
57219 + test('devspeed','0x3');
57220 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 3));
57221 + set('devspeed','4');
57222 + test('devspeed','0x0');
57223 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
57224 + set('devspeed','5');
57225 + test('devspeed','0x1');
57226 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
57227 +
57228 +
57229 + # mode Returns the current mode:0 for device mode1 for host mode Read
57230 + # hnp Initiate the Host Negotiation Protocol. Read returns the status. Read/Write
57231 + # srp Initiate the Session Request Protocol. Read returns the status. Read/Write
57232 + # buspower Get or Set the Power State of the bus (0 - Off or 1 - On) Read/Write
57233 + # bussuspend Suspend the USB bus. Read/Write
57234 + # busconnected Get the connection status of the bus Read
57235 +
57236 + # gotgctl Get or set the Core Control Status Register. Read/Write
57237 + ## gusbcfg Get or set the Core USB Configuration Register Read/Write
57238 + # grxfsiz Get or set the Receive FIFO Size Register Read/Write
57239 + # gnptxfsiz Get or set the non-periodic Transmit Size Register Read/Write
57240 + # gpvndctl Get or set the PHY Vendor Control Register Read/Write
57241 + ## ggpio Get the value in the lower 16-bits of the General Purpose IO Register or Set the upper 16 bits. Read/Write
57242 + ## guid Get or set the value of the User ID Register Read/Write
57243 + ## gsnpsid Get the value of the Synopsys ID Regester Read
57244 + ## devspeed Get or set the device speed setting in the DCFG register Read/Write
57245 + # enumspeed Gets the device enumeration Speed. Read
57246 + # hptxfsiz Get the value of the Host Periodic Transmit FIFO Read
57247 + # hprt0 Get or Set the value in the Host Port Control and Status Register Read/Write
57248 +
57249 + test_status("TEST NYI") or die;
57250 +}
57251 +
57252 +test_main();
57253 +0;
57254 --- a/drivers/usb/host/Kconfig
57255 +++ b/drivers/usb/host/Kconfig
57256 @@ -663,6 +663,19 @@ config USB_HWA_HCD
57257 To compile this driver a module, choose M here: the module
57258 will be called "hwa-hc".
57259
57260 +config USB_DWCOTG
57261 + tristate "Synopsis DWC host support"
57262 + depends on USB
57263 + help
57264 + The Synopsis DWC controller is a dual-role
57265 + host/peripheral/OTG ("On The Go") USB controllers.
57266 +
57267 + Enable this option to support this IP in host controller mode.
57268 + If unsure, say N.
57269 +
57270 + To compile this driver as a module, choose M here: the
57271 + modules built will be called dwc_otg and dwc_common_port.
57272 +
57273 config USB_IMX21_HCD
57274 tristate "i.MX21 HCD support"
57275 depends on ARM && ARCH_MXC
57276 --- a/drivers/usb/host/Makefile
57277 +++ b/drivers/usb/host/Makefile
57278 @@ -47,6 +47,8 @@ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
57279 obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
57280 obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
57281 obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
57282 +
57283 +obj-$(CONFIG_USB_DWCOTG) += dwc_otg/ dwc_common_port/
57284 obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
57285 obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
57286 obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
57287 --- a/drivers/usb/Makefile
57288 +++ b/drivers/usb/Makefile
57289 @@ -23,6 +23,7 @@ obj-$(CONFIG_USB_U132_HCD) += host/
57290 obj-$(CONFIG_USB_R8A66597_HCD) += host/
57291 obj-$(CONFIG_USB_HWA_HCD) += host/
57292 obj-$(CONFIG_USB_ISP1760_HCD) += host/
57293 +obj-$(CONFIG_USB_DWCOTG) += host/
57294 obj-$(CONFIG_USB_IMX21_HCD) += host/
57295 obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
57296