1210284Sjmallett/***********************license start***************
2232812Sjmallett * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3215990Sjmallett * reserved.
4210284Sjmallett *
5210284Sjmallett *
6215990Sjmallett * Redistribution and use in source and binary forms, with or without
7215990Sjmallett * modification, are permitted provided that the following conditions are
8215990Sjmallett * met:
9210284Sjmallett *
10215990Sjmallett *   * Redistributions of source code must retain the above copyright
11215990Sjmallett *     notice, this list of conditions and the following disclaimer.
12210284Sjmallett *
13215990Sjmallett *   * Redistributions in binary form must reproduce the above
14215990Sjmallett *     copyright notice, this list of conditions and the following
15215990Sjmallett *     disclaimer in the documentation and/or other materials provided
16215990Sjmallett *     with the distribution.
17215990Sjmallett
18232812Sjmallett *   * Neither the name of Cavium Inc. nor the names of
19215990Sjmallett *     its contributors may be used to endorse or promote products
20215990Sjmallett *     derived from this software without specific prior written
21215990Sjmallett *     permission.
22215990Sjmallett
23215990Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24215990Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25215990Sjmallett * regulations, and may be subject to export or import  regulations in other
26215990Sjmallett * countries.
27215990Sjmallett
28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38210284Sjmallett ***********************license end**************************************/
39210284Sjmallett
40215990Sjmallett
41210284Sjmallett/**
42210284Sjmallett * @file
43210284Sjmallett *
44210284Sjmallett * "cvmx-usb.h" defines a set of low level USB functions to help
45210284Sjmallett * developers create Octeon USB drivers for various operating
46210284Sjmallett * systems. These functions provide a generic API to the Octeon
47210284Sjmallett * USB blocks, hiding the internal hardware specific
48210284Sjmallett * operations.
49210284Sjmallett *
50210284Sjmallett * At a high level the device driver needs to:
51210284Sjmallett *
52210284Sjmallett * -# Call cvmx_usb_get_num_ports() to get the number of
53210284Sjmallett *  supported ports.
54210284Sjmallett * -# Call cvmx_usb_initialize() for each Octeon USB port.
55210284Sjmallett * -# Enable the port using cvmx_usb_enable().
56210284Sjmallett * -# Either periodically, or in an interrupt handler, call
57210284Sjmallett *  cvmx_usb_poll() to service USB events.
58210284Sjmallett * -# Manage pipes using cvmx_usb_open_pipe() and
59210284Sjmallett *  cvmx_usb_close_pipe().
60210284Sjmallett * -# Manage transfers using cvmx_usb_submit_*() and
61210284Sjmallett *  cvmx_usb_cancel*().
62210284Sjmallett * -# Shutdown USB on unload using cvmx_usb_shutdown().
63210284Sjmallett *
64210284Sjmallett * To monitor USB status changes, the device driver must use
65210284Sjmallett * cvmx_usb_register_callback() to register for events that it
66210284Sjmallett * is interested in. Below are a few hints on successfully
67210284Sjmallett * implementing a driver on top of this API.
68210284Sjmallett *
69210284Sjmallett * <h2>Initialization</h2>
70210284Sjmallett *
71210284Sjmallett * When a driver is first loaded, it is normally not necessary
72210284Sjmallett * to bring up the USB port completely. Most operating systems
73210284Sjmallett * expect to initialize and enable the port in two independent
74210284Sjmallett * steps. Normally an operating system will probe hardware,
75210284Sjmallett * initialize anything found, and then enable the hardware.
76210284Sjmallett *
77210284Sjmallett * In the probe phase you should:
78210284Sjmallett * -# Use cvmx_usb_get_num_ports() to determine the number of
79210284Sjmallett *  USB port to be supported.
80210284Sjmallett * -# Allocate space for a cvmx_usb_state_t structure for each
81210284Sjmallett *  port.
82210284Sjmallett * -# Tell the operating system about each port
83210284Sjmallett *
84210284Sjmallett * In the initialization phase you should:
85210284Sjmallett * -# Use cvmx_usb_initialize() on each port.
86210284Sjmallett * -# Do not call cvmx_usb_enable(). This leaves the USB port in
87210284Sjmallett *  the disabled state until the operating system is ready.
88210284Sjmallett *
89210284Sjmallett * Finally, in the enable phase you should:
90210284Sjmallett * -# Call cvmx_usb_enable() on the appropriate port.
91210284Sjmallett * -# Note that some operating system use a RESET instead of an
92210284Sjmallett *  enable call. To implement RESET, you should call
93210284Sjmallett *  cvmx_usb_disable() followed by cvmx_usb_enable().
94210284Sjmallett *
95210284Sjmallett * <h2>Locking</h2>
96210284Sjmallett *
97210284Sjmallett * All of the functions in the cvmx-usb API assume exclusive
98210284Sjmallett * access to the USB hardware and internal data structures. This
99210284Sjmallett * means that the driver must provide locking as necessary.
100210284Sjmallett *
101210284Sjmallett * In the single CPU state it is normally enough to disable
102210284Sjmallett * interrupts before every call to cvmx_usb*() and enable them
103210284Sjmallett * again after the call is complete. Keep in mind that it is
104210284Sjmallett * very common for the callback handlers to make additional
105210284Sjmallett * calls into cvmx-usb, so the disable/enable must be protected
106210284Sjmallett * against recursion. As an example, the Linux kernel
107210284Sjmallett * local_irq_save() and local_irq_restore() are perfect for this
108210284Sjmallett * in the non SMP case.
109210284Sjmallett *
110210284Sjmallett * In the SMP case, locking is more complicated. For SMP you not
111210284Sjmallett * only need to disable interrupts on the local core, but also
112210284Sjmallett * take a lock to make sure that another core cannot call
113210284Sjmallett * cvmx-usb.
114210284Sjmallett *
115210284Sjmallett * <h2>Port callback</h2>
116210284Sjmallett *
117210284Sjmallett * The port callback prototype needs to look as follows:
118210284Sjmallett *
119210284Sjmallett * void port_callback(cvmx_usb_state_t *usb,
120210284Sjmallett *                    cvmx_usb_callback_t reason,
121210284Sjmallett *                    cvmx_usb_complete_t status,
122210284Sjmallett *                    int pipe_handle,
123210284Sjmallett *                    int submit_handle,
124210284Sjmallett *                    int bytes_transferred,
125210284Sjmallett *                    void *user_data);
126210284Sjmallett * - @b usb is the cvmx_usb_state_t for the port.
127210284Sjmallett * - @b reason will always be
128210284Sjmallett *   CVMX_USB_CALLBACK_PORT_CHANGED.
129210284Sjmallett * - @b status will always be CVMX_USB_COMPLETE_SUCCESS.
130210284Sjmallett * - @b pipe_handle will always be -1.
131210284Sjmallett * - @b submit_handle will always be -1.
132210284Sjmallett * - @b bytes_transferred will always be 0.
133210284Sjmallett * - @b user_data is the void pointer originally passed along
134210284Sjmallett *   with the callback. Use this for any state information you
135210284Sjmallett *   need.
136210284Sjmallett *
137210284Sjmallett * The port callback will be called whenever the user plugs /
138210284Sjmallett * unplugs a device from the port. It will not be called when a
139210284Sjmallett * device is plugged / unplugged from a hub connected to the
140210284Sjmallett * root port. Normally all the callback needs to do is tell the
141210284Sjmallett * operating system to poll the root hub for status. Under
142210284Sjmallett * Linux, this is performed by calling usb_hcd_poll_rh_status().
143210284Sjmallett * In the Linux driver we use @b user_data. to pass around the
144210284Sjmallett * Linux "hcd" structure. Once the port callback completes,
145210284Sjmallett * Linux automatically calls octeon_usb_hub_status_data() which
146210284Sjmallett * uses cvmx_usb_get_status() to determine the root port status.
147210284Sjmallett *
148210284Sjmallett * <h2>Complete callback</h2>
149210284Sjmallett *
150210284Sjmallett * The completion callback prototype needs to look as follows:
151210284Sjmallett *
152210284Sjmallett * void complete_callback(cvmx_usb_state_t *usb,
153210284Sjmallett *                        cvmx_usb_callback_t reason,
154210284Sjmallett *                        cvmx_usb_complete_t status,
155210284Sjmallett *                        int pipe_handle,
156210284Sjmallett *                        int submit_handle,
157210284Sjmallett *                        int bytes_transferred,
158210284Sjmallett *                        void *user_data);
159210284Sjmallett * - @b usb is the cvmx_usb_state_t for the port.
160210284Sjmallett * - @b reason will always be
161210284Sjmallett *   CVMX_USB_CALLBACK_TRANSFER_COMPLETE.
162210284Sjmallett * - @b status will be one of the cvmx_usb_complete_t
163210284Sjmallett *   enumerations.
164210284Sjmallett * - @b pipe_handle is the handle to the pipe the transaction
165210284Sjmallett *   was originally submitted on.
166210284Sjmallett * - @b submit_handle is the handle returned by the original
167210284Sjmallett *   cvmx_usb_submit_* call.
168210284Sjmallett * - @b bytes_transferred is the number of bytes successfully
169210284Sjmallett *   transferred in the transaction. This will be zero on most
170210284Sjmallett *   error conditions.
171210284Sjmallett * - @b user_data is the void pointer originally passed along
172210284Sjmallett *   with the callback. Use this for any state information you
173210284Sjmallett *   need. For example, the Linux "urb" is stored in here in the
174210284Sjmallett *   Linux driver.
175210284Sjmallett *
176210284Sjmallett * In general your callback handler should use @b status and @b
177210284Sjmallett * bytes_transferred to tell the operating system the how the
178210284Sjmallett * transaction completed. Normally the pipe is not changed in
179210284Sjmallett * this callback.
180210284Sjmallett *
181210284Sjmallett * <h2>Canceling transactions</h2>
182210284Sjmallett *
183210284Sjmallett * When a transaction is cancelled using cvmx_usb_cancel*(), the
184210284Sjmallett * actual length of time until the complete callback is called
185210284Sjmallett * can vary greatly. It may be called before cvmx_usb_cancel*()
186210284Sjmallett * returns, or it may be called a number of usb frames in the
187210284Sjmallett * future once the hardware frees the transaction. In either of
188210284Sjmallett * these cases, the complete handler will receive
189210284Sjmallett * CVMX_USB_COMPLETE_CANCEL.
190210284Sjmallett *
191210284Sjmallett * <h2>Handling pipes</h2>
192210284Sjmallett *
193210284Sjmallett * USB "pipes" is a software construct created by this API to
194210284Sjmallett * enable the ordering of usb transactions to a device endpoint.
195210284Sjmallett * Octeon's underlying hardware doesn't have any concept
196210284Sjmallett * equivalent to "pipes". The hardware instead has eight
197210284Sjmallett * channels that can be used simultaneously to have up to eight
198210284Sjmallett * transaction in process at the same time. In order to maintain
199210284Sjmallett * ordering in a pipe, the transactions for a pipe will only be
200210284Sjmallett * active in one hardware channel at a time. From an API user's
201210284Sjmallett * perspective, this doesn't matter but it can be helpful to
202210284Sjmallett * keep this in mind when you are probing hardware while
203210284Sjmallett * debugging.
204210284Sjmallett *
205210284Sjmallett * Also keep in mind that usb transactions contain state
206210284Sjmallett * information about the previous transaction to the same
207210284Sjmallett * endpoint. Each transaction has a PID toggle that changes 0/1
208210284Sjmallett * between each sub packet. This is maintained in the pipe data
209210284Sjmallett * structures. For this reason, you generally cannot create and
210210284Sjmallett * destroy a pipe for every transaction. A sequence of
211210284Sjmallett * transaction to the same endpoint must use the same pipe.
212210284Sjmallett *
213210284Sjmallett * <h2>Root Hub</h2>
214210284Sjmallett *
215210284Sjmallett * Some operating systems view the usb root port as a normal usb
216210284Sjmallett * hub. These systems attempt to control the root hub with
217210284Sjmallett * messages similar to the usb 2.0 spec for hub control and
218210284Sjmallett * status. For these systems it may be necessary to write
219210284Sjmallett * function to decode standard usb control messages into
220210284Sjmallett * equivalent cvmx-usb API calls. As an example, the following
221210284Sjmallett * code is used under Linux for some of the basic hub control
222210284Sjmallett * messages.
223210284Sjmallett *
224210284Sjmallett * @code
225210284Sjmallett * static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
226210284Sjmallett * {
227210284Sjmallett *     cvmx_usb_state_t *usb = (cvmx_usb_state_t *)hcd->hcd_priv;
228210284Sjmallett *     cvmx_usb_port_status_t usb_port_status;
229210284Sjmallett *     int port_status;
230210284Sjmallett *     struct usb_hub_descriptor *desc;
231210284Sjmallett *     unsigned long flags;
232210284Sjmallett *
233210284Sjmallett *     switch (typeReq)
234210284Sjmallett *     {
235210284Sjmallett *         case ClearHubFeature:
236210284Sjmallett *             DEBUG_ROOT_HUB("OcteonUSB: ClearHubFeature\n");
237210284Sjmallett *             switch (wValue)
238210284Sjmallett *             {
239210284Sjmallett *                 case C_HUB_LOCAL_POWER:
240210284Sjmallett *                 case C_HUB_OVER_CURRENT:
241210284Sjmallett *                     // Nothing required here
242210284Sjmallett *                     break;
243210284Sjmallett *                 default:
244210284Sjmallett *                     return -EINVAL;
245210284Sjmallett *             }
246210284Sjmallett *             break;
247210284Sjmallett *         case ClearPortFeature:
248210284Sjmallett *             DEBUG_ROOT_HUB("OcteonUSB: ClearPortFeature");
249210284Sjmallett *             if (wIndex != 1)
250210284Sjmallett *             {
251210284Sjmallett *                 DEBUG_ROOT_HUB(" INVALID\n");
252210284Sjmallett *                 return -EINVAL;
253210284Sjmallett *             }
254210284Sjmallett *
255210284Sjmallett *             switch (wValue)
256210284Sjmallett *             {
257210284Sjmallett *                 case USB_PORT_FEAT_ENABLE:
258210284Sjmallett *                     DEBUG_ROOT_HUB(" ENABLE");
259210284Sjmallett *                     local_irq_save(flags);
260210284Sjmallett *                     cvmx_usb_disable(usb);
261210284Sjmallett *                     local_irq_restore(flags);
262210284Sjmallett *                     break;
263210284Sjmallett *                 case USB_PORT_FEAT_SUSPEND:
264210284Sjmallett *                     DEBUG_ROOT_HUB(" SUSPEND");
265210284Sjmallett *                     // Not supported on Octeon
266210284Sjmallett *                     break;
267210284Sjmallett *                 case USB_PORT_FEAT_POWER:
268210284Sjmallett *                     DEBUG_ROOT_HUB(" POWER");
269210284Sjmallett *                     // Not supported on Octeon
270210284Sjmallett *                     break;
271210284Sjmallett *                 case USB_PORT_FEAT_INDICATOR:
272210284Sjmallett *                     DEBUG_ROOT_HUB(" INDICATOR");
273210284Sjmallett *                     // Port inidicator not supported
274210284Sjmallett *                     break;
275210284Sjmallett *                 case USB_PORT_FEAT_C_CONNECTION:
276210284Sjmallett *                     DEBUG_ROOT_HUB(" C_CONNECTION");
277210284Sjmallett *                     // Clears drivers internal connect status change flag
278210284Sjmallett *                     cvmx_usb_set_status(usb, cvmx_usb_get_status(usb));
279210284Sjmallett *                     break;
280210284Sjmallett *                 case USB_PORT_FEAT_C_RESET:
281210284Sjmallett *                     DEBUG_ROOT_HUB(" C_RESET");
282210284Sjmallett *                     // Clears the driver's internal Port Reset Change flag
283210284Sjmallett *                     cvmx_usb_set_status(usb, cvmx_usb_get_status(usb));
284210284Sjmallett *                     break;
285210284Sjmallett *                 case USB_PORT_FEAT_C_ENABLE:
286210284Sjmallett *                     DEBUG_ROOT_HUB(" C_ENABLE");
287210284Sjmallett *                     // Clears the driver's internal Port Enable/Disable Change flag
288210284Sjmallett *                     cvmx_usb_set_status(usb, cvmx_usb_get_status(usb));
289210284Sjmallett *                     break;
290210284Sjmallett *                 case USB_PORT_FEAT_C_SUSPEND:
291210284Sjmallett *                     DEBUG_ROOT_HUB(" C_SUSPEND");
292210284Sjmallett *                     // Clears the driver's internal Port Suspend Change flag,
293210284Sjmallett *                         which is set when resume signaling on the host port is
294210284Sjmallett *                         complete
295210284Sjmallett *                     break;
296210284Sjmallett *                 case USB_PORT_FEAT_C_OVER_CURRENT:
297210284Sjmallett *                     DEBUG_ROOT_HUB(" C_OVER_CURRENT");
298210284Sjmallett *                     // Clears the driver's overcurrent Change flag
299210284Sjmallett *                     cvmx_usb_set_status(usb, cvmx_usb_get_status(usb));
300210284Sjmallett *                     break;
301210284Sjmallett *                 default:
302210284Sjmallett *                     DEBUG_ROOT_HUB(" UNKNOWN\n");
303210284Sjmallett *                     return -EINVAL;
304210284Sjmallett *             }
305210284Sjmallett *             DEBUG_ROOT_HUB("\n");
306210284Sjmallett *             break;
307210284Sjmallett *         case GetHubDescriptor:
308210284Sjmallett *             DEBUG_ROOT_HUB("OcteonUSB: GetHubDescriptor\n");
309210284Sjmallett *             desc = (struct usb_hub_descriptor *)buf;
310210284Sjmallett *             desc->bDescLength = 9;
311210284Sjmallett *             desc->bDescriptorType = 0x29;
312210284Sjmallett *             desc->bNbrPorts = 1;
313210284Sjmallett *             desc->wHubCharacteristics = 0x08;
314210284Sjmallett *             desc->bPwrOn2PwrGood = 1;
315210284Sjmallett *             desc->bHubContrCurrent = 0;
316210284Sjmallett *             desc->bitmap[0] = 0;
317210284Sjmallett *             desc->bitmap[1] = 0xff;
318210284Sjmallett *             break;
319210284Sjmallett *         case GetHubStatus:
320210284Sjmallett *             DEBUG_ROOT_HUB("OcteonUSB: GetHubStatus\n");
321210284Sjmallett *             *(__le32 *)buf = 0;
322210284Sjmallett *             break;
323210284Sjmallett *         case GetPortStatus:
324210284Sjmallett *             DEBUG_ROOT_HUB("OcteonUSB: GetPortStatus");
325210284Sjmallett *             if (wIndex != 1)
326210284Sjmallett *             {
327210284Sjmallett *                 DEBUG_ROOT_HUB(" INVALID\n");
328210284Sjmallett *                 return -EINVAL;
329210284Sjmallett *             }
330210284Sjmallett *
331210284Sjmallett *             usb_port_status = cvmx_usb_get_status(usb);
332210284Sjmallett *             port_status = 0;
333210284Sjmallett *
334210284Sjmallett *             if (usb_port_status.connect_change)
335210284Sjmallett *             {
336210284Sjmallett *                 port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
337210284Sjmallett *                 DEBUG_ROOT_HUB(" C_CONNECTION");
338210284Sjmallett *             }
339210284Sjmallett *
340210284Sjmallett *             if (usb_port_status.port_enabled)
341210284Sjmallett *             {
342210284Sjmallett *                 port_status |= (1 << USB_PORT_FEAT_C_ENABLE);
343210284Sjmallett *                 DEBUG_ROOT_HUB(" C_ENABLE");
344210284Sjmallett *             }
345210284Sjmallett *
346210284Sjmallett *             if (usb_port_status.connected)
347210284Sjmallett *             {
348210284Sjmallett *                 port_status |= (1 << USB_PORT_FEAT_CONNECTION);
349210284Sjmallett *                 DEBUG_ROOT_HUB(" CONNECTION");
350210284Sjmallett *             }
351210284Sjmallett *
352210284Sjmallett *             if (usb_port_status.port_enabled)
353210284Sjmallett *             {
354210284Sjmallett *                 port_status |= (1 << USB_PORT_FEAT_ENABLE);
355210284Sjmallett *                 DEBUG_ROOT_HUB(" ENABLE");
356210284Sjmallett *             }
357210284Sjmallett *
358210284Sjmallett *             if (usb_port_status.port_over_current)
359210284Sjmallett *             {
360210284Sjmallett *                 port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT);
361210284Sjmallett *                 DEBUG_ROOT_HUB(" OVER_CURRENT");
362210284Sjmallett *             }
363210284Sjmallett *
364210284Sjmallett *             if (usb_port_status.port_powered)
365210284Sjmallett *             {
366210284Sjmallett *                 port_status |= (1 << USB_PORT_FEAT_POWER);
367210284Sjmallett *                 DEBUG_ROOT_HUB(" POWER");
368210284Sjmallett *             }
369210284Sjmallett *
370210284Sjmallett *             if (usb_port_status.port_speed == CVMX_USB_SPEED_HIGH)
371210284Sjmallett *             {
372210284Sjmallett *                 port_status |= (1 << USB_PORT_FEAT_HIGHSPEED);
373210284Sjmallett *                 DEBUG_ROOT_HUB(" HIGHSPEED");
374210284Sjmallett *             }
375210284Sjmallett *             else if (usb_port_status.port_speed == CVMX_USB_SPEED_LOW)
376210284Sjmallett *             {
377210284Sjmallett *                 port_status |= (1 << USB_PORT_FEAT_LOWSPEED);
378210284Sjmallett *                 DEBUG_ROOT_HUB(" LOWSPEED");
379210284Sjmallett *             }
380210284Sjmallett *
381210284Sjmallett *             *((__le32 *)buf) = cpu_to_le32(port_status);
382210284Sjmallett *             DEBUG_ROOT_HUB("\n");
383210284Sjmallett *             break;
384210284Sjmallett *         case SetHubFeature:
385210284Sjmallett *             DEBUG_ROOT_HUB("OcteonUSB: SetHubFeature\n");
386210284Sjmallett *             // No HUB features supported
387210284Sjmallett *             break;
388210284Sjmallett *         case SetPortFeature:
389210284Sjmallett *             DEBUG_ROOT_HUB("OcteonUSB: SetPortFeature");
390210284Sjmallett *             if (wIndex != 1)
391210284Sjmallett *             {
392210284Sjmallett *                 DEBUG_ROOT_HUB(" INVALID\n");
393210284Sjmallett *                 return -EINVAL;
394210284Sjmallett *             }
395210284Sjmallett *
396210284Sjmallett *             switch (wValue)
397210284Sjmallett *             {
398210284Sjmallett *                 case USB_PORT_FEAT_SUSPEND:
399210284Sjmallett *                     DEBUG_ROOT_HUB(" SUSPEND\n");
400210284Sjmallett *                     return -EINVAL;
401210284Sjmallett *                 case USB_PORT_FEAT_POWER:
402210284Sjmallett *                     DEBUG_ROOT_HUB(" POWER\n");
403210284Sjmallett *                     return -EINVAL;
404210284Sjmallett *                 case USB_PORT_FEAT_RESET:
405210284Sjmallett *                     DEBUG_ROOT_HUB(" RESET\n");
406210284Sjmallett *                     local_irq_save(flags);
407210284Sjmallett *                     cvmx_usb_disable(usb);
408210284Sjmallett *                     if (cvmx_usb_enable(usb))
409210284Sjmallett *                         DEBUG_ERROR("Failed to enable the port\n");
410210284Sjmallett *                     local_irq_restore(flags);
411210284Sjmallett *                     return 0;
412210284Sjmallett *                 case USB_PORT_FEAT_INDICATOR:
413210284Sjmallett *                     DEBUG_ROOT_HUB(" INDICATOR\n");
414210284Sjmallett *                     // Not supported
415210284Sjmallett *                     break;
416210284Sjmallett *                 default:
417210284Sjmallett *                     DEBUG_ROOT_HUB(" UNKNOWN\n");
418210284Sjmallett *                     return -EINVAL;
419210284Sjmallett *             }
420210284Sjmallett *             break;
421210284Sjmallett *         default:
422210284Sjmallett *             DEBUG_ROOT_HUB("OcteonUSB: Unknown root hub request\n");
423210284Sjmallett *             return -EINVAL;
424210284Sjmallett *     }
425210284Sjmallett *     return 0;
426210284Sjmallett * }
427210284Sjmallett * @endcode
428210284Sjmallett *
429210284Sjmallett * <h2>Interrupts</h2>
430210284Sjmallett *
431210284Sjmallett * If you plan on using usb interrupts, cvmx_usb_poll() must be
432210284Sjmallett * called on every usb interrupt. It will read the usb state,
433210284Sjmallett * call any needed callbacks, and schedule transactions as
434210284Sjmallett * needed. Your device driver needs only to hookup an interrupt
435210284Sjmallett * handler and call cvmx_usb_poll(). Octeon's usb port 0 causes
436210284Sjmallett * CIU bit CIU_INT*_SUM0[USB] to be set (bit 56). For port 1,
437210284Sjmallett * CIU bit CIU_INT_SUM1[USB1] is set (bit 17). How these bits
438210284Sjmallett * are turned into interrupt numbers is operating system
439210284Sjmallett * specific. For Linux, there are the convenient defines
440210284Sjmallett * OCTEON_IRQ_USB0 and OCTEON_IRQ_USB1 for the IRQ numbers.
441210284Sjmallett *
442210284Sjmallett * If you aren't using interrupts, simple call cvmx_usb_poll()
443210284Sjmallett * in your main processing loop.
444210284Sjmallett *
445210284Sjmallett * <hr>$Revision: 32636 $<hr>
446210284Sjmallett */
447210284Sjmallett
448210284Sjmallett#ifndef __CVMX_USB_H__
449210284Sjmallett#define __CVMX_USB_H__
450210284Sjmallett
451210284Sjmallett#ifdef	__cplusplus
452210284Sjmallettextern "C" {
453210284Sjmallett#endif
454210284Sjmallett
455210284Sjmallett/**
456210284Sjmallett * Enumerations representing the status of function calls.
457210284Sjmallett */
458210284Sjmalletttypedef enum
459210284Sjmallett{
460210284Sjmallett    CVMX_USB_SUCCESS = 0,           /**< There were no errors */
461210284Sjmallett    CVMX_USB_INVALID_PARAM = -1,    /**< A parameter to the function was invalid */
462210284Sjmallett    CVMX_USB_NO_MEMORY = -2,        /**< Insufficient resources were available for the request */
463210284Sjmallett    CVMX_USB_BUSY = -3,             /**< The resource is busy and cannot service the request */
464210284Sjmallett    CVMX_USB_TIMEOUT = -4,          /**< Waiting for an action timed out */
465210284Sjmallett    CVMX_USB_INCORRECT_MODE = -5,   /**< The function call doesn't work in the current USB
466210284Sjmallett                                         mode. This happens when host only functions are
467210284Sjmallett                                         called in device mode or vice versa */
468210284Sjmallett} cvmx_usb_status_t;
469210284Sjmallett
470210284Sjmallett/**
471210284Sjmallett * Enumerations representing the possible USB device speeds
472210284Sjmallett */
473210284Sjmalletttypedef enum
474210284Sjmallett{
475210284Sjmallett    CVMX_USB_SPEED_HIGH = 0,        /**< Device is operation at 480Mbps */
476210284Sjmallett    CVMX_USB_SPEED_FULL = 1,        /**< Device is operation at 12Mbps */
477210284Sjmallett    CVMX_USB_SPEED_LOW = 2,         /**< Device is operation at 1.5Mbps */
478210284Sjmallett} cvmx_usb_speed_t;
479210284Sjmallett
480210284Sjmallett/**
481210284Sjmallett * Enumeration representing the possible USB transfer types.
482210284Sjmallett */
483210284Sjmalletttypedef enum
484210284Sjmallett{
485210284Sjmallett    CVMX_USB_TRANSFER_CONTROL = 0,      /**< USB transfer type control for hub and status transfers */
486210284Sjmallett    CVMX_USB_TRANSFER_ISOCHRONOUS = 1,  /**< USB transfer type isochronous for low priority periodic transfers */
487210284Sjmallett    CVMX_USB_TRANSFER_BULK = 2,         /**< USB transfer type bulk for large low priority transfers */
488210284Sjmallett    CVMX_USB_TRANSFER_INTERRUPT = 3,    /**< USB transfer type interrupt for high priority periodic transfers */
489210284Sjmallett} cvmx_usb_transfer_t;
490210284Sjmallett
491210284Sjmallett/**
492210284Sjmallett * Enumeration of the transfer directions
493210284Sjmallett */
494210284Sjmalletttypedef enum
495210284Sjmallett{
496210284Sjmallett    CVMX_USB_DIRECTION_OUT,         /**< Data is transferring from Octeon to the device/host */
497210284Sjmallett    CVMX_USB_DIRECTION_IN,          /**< Data is transferring from the device/host to Octeon */
498210284Sjmallett} cvmx_usb_direction_t;
499210284Sjmallett
500210284Sjmallett/**
501210284Sjmallett * Enumeration of all possible status codes passed to callback
502210284Sjmallett * functions.
503210284Sjmallett */
504210284Sjmalletttypedef enum
505210284Sjmallett{
506210284Sjmallett    CVMX_USB_COMPLETE_SUCCESS,      /**< The transaction / operation finished without any errors */
507210284Sjmallett    CVMX_USB_COMPLETE_SHORT,        /**< FIXME: This is currently not implemented */
508210284Sjmallett    CVMX_USB_COMPLETE_CANCEL,       /**< The transaction was canceled while in flight by a user call to cvmx_usb_cancel* */
509210284Sjmallett    CVMX_USB_COMPLETE_ERROR,        /**< The transaction aborted with an unexpected error status */
510210284Sjmallett    CVMX_USB_COMPLETE_STALL,        /**< The transaction received a USB STALL response from the device */
511210284Sjmallett    CVMX_USB_COMPLETE_XACTERR,      /**< The transaction failed with an error from the device even after a number of retries */
512210284Sjmallett    CVMX_USB_COMPLETE_DATATGLERR,   /**< The transaction failed with a data toggle error even after a number of retries */
513210284Sjmallett    CVMX_USB_COMPLETE_BABBLEERR,    /**< The transaction failed with a babble error */
514210284Sjmallett    CVMX_USB_COMPLETE_FRAMEERR,     /**< The transaction failed with a frame error even after a number of retries */
515210284Sjmallett} cvmx_usb_complete_t;
516210284Sjmallett
517210284Sjmallett/**
518210284Sjmallett * Structure returned containing the USB port status information.
519210284Sjmallett */
520210284Sjmalletttypedef struct
521210284Sjmallett{
522210284Sjmallett    uint32_t reserved           : 25;
523210284Sjmallett    uint32_t port_enabled       : 1; /**< 1 = Usb port is enabled, 0 = disabled */
524210284Sjmallett    uint32_t port_over_current  : 1; /**< 1 = Over current detected, 0 = Over current not detected. Octeon doesn't support over current detection */
525210284Sjmallett    uint32_t port_powered       : 1; /**< 1 = Port power is being supplied to the device, 0 = power is off. Octeon doesn't support turning port power off */
526210284Sjmallett    cvmx_usb_speed_t port_speed : 2; /**< Current port speed */
527210284Sjmallett    uint32_t connected          : 1; /**< 1 = A device is connected to the port, 0 = No device is connected */
528210284Sjmallett    uint32_t connect_change     : 1; /**< 1 = Device connected state changed since the last set status call */
529210284Sjmallett} cvmx_usb_port_status_t;
530210284Sjmallett
531210284Sjmallett/**
532210284Sjmallett * This is the structure of a Control packet header
533210284Sjmallett */
534210284Sjmalletttypedef union
535210284Sjmallett{
536210284Sjmallett    uint64_t u64;
537210284Sjmallett    struct
538210284Sjmallett    {
539210284Sjmallett        uint64_t request_type   : 8;  /**< Bit 7 tells the direction: 1=IN, 0=OUT */
540210284Sjmallett        uint64_t request        : 8;  /**< The standard usb request to make */
541210284Sjmallett        uint64_t value          : 16; /**< Value parameter for the request in little endian format */
542210284Sjmallett        uint64_t index          : 16; /**< Index for the request in little endian format */
543210284Sjmallett        uint64_t length         : 16; /**< Length of the data associated with this request in little endian format */
544210284Sjmallett    } s;
545210284Sjmallett} cvmx_usb_control_header_t;
546210284Sjmallett
547210284Sjmallett/**
548210284Sjmallett * Descriptor for Isochronous packets
549210284Sjmallett */
550210284Sjmalletttypedef struct
551210284Sjmallett{
552210284Sjmallett    int offset;                     /**< This is the offset in bytes into the main buffer where this data is stored */
553210284Sjmallett    int length;                     /**< This is the length in bytes of the data */
554210284Sjmallett    cvmx_usb_complete_t status;     /**< This is the status of this individual packet transfer */
555210284Sjmallett} cvmx_usb_iso_packet_t;
556210284Sjmallett
557210284Sjmallett/**
558210284Sjmallett * Possible callback reasons for the USB API.
559210284Sjmallett */
560210284Sjmalletttypedef enum
561210284Sjmallett{
562210284Sjmallett    CVMX_USB_CALLBACK_TRANSFER_COMPLETE,
563210284Sjmallett                                    /**< A callback of this type is called when a submitted transfer
564210284Sjmallett                                        completes. The completion callback will be called even if the
565210284Sjmallett                                        transfer fails or is canceled. The status parameter will
566210284Sjmallett                                        contain details of why he callback was called. */
567210284Sjmallett    CVMX_USB_CALLBACK_PORT_CHANGED, /**< The status of the port changed. For example, someone may have
568210284Sjmallett                                        plugged a device in. The status parameter contains
569210284Sjmallett                                        CVMX_USB_COMPLETE_SUCCESS. Use cvmx_usb_get_status() to get
570210284Sjmallett                                        the new port status. */
571210284Sjmallett    __CVMX_USB_CALLBACK_END         /**< Do not use. Used internally for array bounds */
572210284Sjmallett} cvmx_usb_callback_t;
573210284Sjmallett
574210284Sjmallett/**
575210284Sjmallett * USB state internal data. The contents of this structure
576210284Sjmallett * may change in future SDKs. No data in it should be referenced
577210284Sjmallett * by user's of this API.
578210284Sjmallett */
579210284Sjmalletttypedef struct
580210284Sjmallett{
581210284Sjmallett    char data[65536];
582210284Sjmallett} cvmx_usb_state_t;
583210284Sjmallett
584210284Sjmallett/**
585210284Sjmallett * USB callback functions are always of the following type.
586210284Sjmallett * The parameters are as follows:
587210284Sjmallett *      - state = USB device state populated by
588210284Sjmallett *        cvmx_usb_initialize().
589210284Sjmallett *      - reason = The cvmx_usb_callback_t used to register
590210284Sjmallett *        the callback.
591210284Sjmallett *      - status = The cvmx_usb_complete_t representing the
592210284Sjmallett *        status code of a transaction.
593210284Sjmallett *      - pipe_handle = The Pipe that caused this callback, or
594210284Sjmallett *        -1 if this callback wasn't associated with a pipe.
595210284Sjmallett *      - submit_handle = Transfer submit handle causing this
596210284Sjmallett *        callback, or -1 if this callback wasn't associated
597210284Sjmallett *        with a transfer.
598210284Sjmallett *      - Actual number of bytes transfer.
599210284Sjmallett *      - user_data = The user pointer supplied to the
600210284Sjmallett *        function cvmx_usb_submit() or
601210284Sjmallett *        cvmx_usb_register_callback() */
602210284Sjmalletttypedef void (*cvmx_usb_callback_func_t)(cvmx_usb_state_t *state,
603210284Sjmallett                                         cvmx_usb_callback_t reason,
604210284Sjmallett                                         cvmx_usb_complete_t status,
605210284Sjmallett                                         int pipe_handle, int submit_handle,
606210284Sjmallett                                         int bytes_transferred, void *user_data);
607210284Sjmallett
608210284Sjmallett/**
609210284Sjmallett * Flags to pass the initialization function.
610210284Sjmallett */
611210284Sjmalletttypedef enum
612210284Sjmallett{
613210284Sjmallett    CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI = 1<<0,       /**< The USB port uses a 12MHz crystal as clock source
614210284Sjmallett                                                            at USB_XO and USB_XI. */
615210284Sjmallett    CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND = 1<<1,      /**< The USB port uses 12/24/48MHz 2.5V board clock
616210284Sjmallett                                                            source at USB_XO. USB_XI should be tied to GND.*/
617210284Sjmallett    CVMX_USB_INITIALIZE_FLAGS_CLOCK_AUTO = 0,           /**< Automatically determine clock type based on function
618210284Sjmallett                                                             in cvmx-helper-board.c. */
619210284Sjmallett    CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK  = 3<<3,       /**< Mask for clock speed field */
620210284Sjmallett    CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ = 1<<3,       /**< Speed of reference clock or crystal */
621210284Sjmallett    CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ = 2<<3,       /**< Speed of reference clock */
622210284Sjmallett    CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ = 3<<3,       /**< Speed of reference clock */
623210284Sjmallett    /* Bits 3-4 used to encode the clock frequency */
624215990Sjmallett    CVMX_USB_INITIALIZE_FLAGS_NO_DMA = 1<<5,            /**< Disable DMA and used polled IO for data transfer use for the USB  */
625210284Sjmallett    CVMX_USB_INITIALIZE_FLAGS_DEBUG_TRANSFERS = 1<<16,  /**< Enable extra console output for debugging USB transfers */
626210284Sjmallett    CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLBACKS = 1<<17,  /**< Enable extra console output for debugging USB callbacks */
627210284Sjmallett    CVMX_USB_INITIALIZE_FLAGS_DEBUG_INFO = 1<<18,       /**< Enable extra console output for USB informational data */
628210284Sjmallett    CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLS = 1<<19,      /**< Enable extra console output for every function call */
629210284Sjmallett    CVMX_USB_INITIALIZE_FLAGS_DEBUG_CSRS = 1<<20,       /**< Enable extra console output for every CSR access */
630210284Sjmallett    CVMX_USB_INITIALIZE_FLAGS_DEBUG_ALL = ((CVMX_USB_INITIALIZE_FLAGS_DEBUG_CSRS<<1)-1) - (CVMX_USB_INITIALIZE_FLAGS_DEBUG_TRANSFERS-1),
631210284Sjmallett} cvmx_usb_initialize_flags_t;
632210284Sjmallett
633210284Sjmallett/**
634210284Sjmallett * Flags for passing when a pipe is created. Currently no flags
635210284Sjmallett * need to be passed.
636210284Sjmallett */
637210284Sjmalletttypedef enum
638210284Sjmallett{
639210284Sjmallett    CVMX_USB_PIPE_FLAGS_DEBUG_TRANSFERS = 1<<15,/**< Used to display CVMX_USB_INITIALIZE_FLAGS_DEBUG_TRANSFERS for a specific pipe only */
640210284Sjmallett    __CVMX_USB_PIPE_FLAGS_OPEN = 1<<16,         /**< Used internally to determine if a pipe is open. Do not use */
641210284Sjmallett    __CVMX_USB_PIPE_FLAGS_SCHEDULED = 1<<17,    /**< Used internally to determine if a pipe is actively using hardware. Do not use */
642210284Sjmallett    __CVMX_USB_PIPE_FLAGS_NEED_PING = 1<<18,    /**< Used internally to determine if a high speed pipe is in the ping state. Do not use */
643210284Sjmallett} cvmx_usb_pipe_flags_t;
644210284Sjmallett
645210284Sjmallett/**
646210284Sjmallett * Return the number of USB ports supported by this Octeon
647210284Sjmallett * chip. If the chip doesn't support USB, or is not supported
648210284Sjmallett * by this API, a zero will be returned. Most Octeon chips
649210284Sjmallett * support one usb port, but some support two ports.
650210284Sjmallett * cvmx_usb_initialize() must be called on independent
651210284Sjmallett * cvmx_usb_state_t structures.
652210284Sjmallett *
653210284Sjmallett * @return Number of port, zero if usb isn't supported
654210284Sjmallett */
655210284Sjmallettextern int cvmx_usb_get_num_ports(void);
656210284Sjmallett
657210284Sjmallett/**
658210284Sjmallett * Initialize a USB port for use. This must be called before any
659210284Sjmallett * other access to the Octeon USB port is made. The port starts
660210284Sjmallett * off in the disabled state.
661210284Sjmallett *
662210284Sjmallett * @param state  Pointer to an empty cvmx_usb_state_t structure
663210284Sjmallett *               that will be populated by the initialize call.
664210284Sjmallett *               This structure is then passed to all other USB
665210284Sjmallett *               functions.
666210284Sjmallett * @param usb_port_number
667210284Sjmallett *               Which Octeon USB port to initialize.
668210284Sjmallett * @param flags  Flags to control hardware initialization. See
669210284Sjmallett *               cvmx_usb_initialize_flags_t for the flag
670210284Sjmallett *               definitions. Some flags are mandatory.
671210284Sjmallett *
672210284Sjmallett * @return CVMX_USB_SUCCESS or a negative error code defined in
673210284Sjmallett *         cvmx_usb_status_t.
674210284Sjmallett */
675210284Sjmallettextern cvmx_usb_status_t cvmx_usb_initialize(cvmx_usb_state_t *state,
676210284Sjmallett                                             int usb_port_number,
677210284Sjmallett                                             cvmx_usb_initialize_flags_t flags);
678210284Sjmallett
679210284Sjmallett/**
680210284Sjmallett * Shutdown a USB port after a call to cvmx_usb_initialize().
681210284Sjmallett * The port should be disabled with all pipes closed when this
682210284Sjmallett * function is called.
683210284Sjmallett *
684210284Sjmallett * @param state  USB device state populated by
685210284Sjmallett *               cvmx_usb_initialize().
686210284Sjmallett *
687210284Sjmallett * @return CVMX_USB_SUCCESS or a negative error code defined in
688210284Sjmallett *         cvmx_usb_status_t.
689210284Sjmallett */
690210284Sjmallettextern cvmx_usb_status_t cvmx_usb_shutdown(cvmx_usb_state_t *state);
691210284Sjmallett
692210284Sjmallett/**
693210284Sjmallett * Enable a USB port. After this call succeeds, the USB port is
694210284Sjmallett * online and servicing requests.
695210284Sjmallett *
696210284Sjmallett * @param state  USB device state populated by
697210284Sjmallett *               cvmx_usb_initialize().
698210284Sjmallett *
699210284Sjmallett * @return CVMX_USB_SUCCESS or a negative error code defined in
700210284Sjmallett *         cvmx_usb_status_t.
701210284Sjmallett */
702210284Sjmallettextern cvmx_usb_status_t cvmx_usb_enable(cvmx_usb_state_t *state);
703210284Sjmallett
704210284Sjmallett/**
705210284Sjmallett * Disable a USB port. After this call the USB port will not
706210284Sjmallett * generate data transfers and will not generate events.
707210284Sjmallett * Transactions in process will fail and call their
708210284Sjmallett * associated callbacks.
709210284Sjmallett *
710210284Sjmallett * @param state  USB device state populated by
711210284Sjmallett *               cvmx_usb_initialize().
712210284Sjmallett *
713210284Sjmallett * @return CVMX_USB_SUCCESS or a negative error code defined in
714210284Sjmallett *         cvmx_usb_status_t.
715210284Sjmallett */
716210284Sjmallettextern cvmx_usb_status_t cvmx_usb_disable(cvmx_usb_state_t *state);
717210284Sjmallett
718210284Sjmallett/**
719210284Sjmallett * Get the current state of the USB port. Use this call to
720210284Sjmallett * determine if the usb port has anything connected, is enabled,
721210284Sjmallett * or has some sort of error condition. The return value of this
722210284Sjmallett * call has "changed" bits to signal of the value of some fields
723210284Sjmallett * have changed between calls. These "changed" fields are based
724210284Sjmallett * on the last call to cvmx_usb_set_status(). In order to clear
725210284Sjmallett * them, you must update the status through cvmx_usb_set_status().
726210284Sjmallett *
727210284Sjmallett * @param state  USB device state populated by
728210284Sjmallett *               cvmx_usb_initialize().
729210284Sjmallett *
730210284Sjmallett * @return Port status information
731210284Sjmallett */
732210284Sjmallettextern cvmx_usb_port_status_t cvmx_usb_get_status(cvmx_usb_state_t *state);
733210284Sjmallett
734210284Sjmallett/**
735210284Sjmallett * Set the current state of the USB port. The status is used as
736210284Sjmallett * a reference for the "changed" bits returned by
737210284Sjmallett * cvmx_usb_get_status(). Other than serving as a reference, the
738210284Sjmallett * status passed to this function is not used. No fields can be
739210284Sjmallett * changed through this call.
740210284Sjmallett *
741210284Sjmallett * @param state  USB device state populated by
742210284Sjmallett *               cvmx_usb_initialize().
743210284Sjmallett * @param port_status
744210284Sjmallett *               Port status to set, most like returned by cvmx_usb_get_status()
745210284Sjmallett */
746210284Sjmallettextern void cvmx_usb_set_status(cvmx_usb_state_t *state, cvmx_usb_port_status_t port_status);
747210284Sjmallett
748210284Sjmallett/**
749210284Sjmallett * Open a virtual pipe between the host and a USB device. A pipe
750210284Sjmallett * must be opened before data can be transferred between a device
751210284Sjmallett * and Octeon.
752210284Sjmallett *
753210284Sjmallett * @param state      USB device state populated by
754210284Sjmallett *                   cvmx_usb_initialize().
755210284Sjmallett * @param flags      Optional pipe flags defined in
756210284Sjmallett *                   cvmx_usb_pipe_flags_t.
757210284Sjmallett * @param device_addr
758210284Sjmallett *                   USB device address to open the pipe to
759210284Sjmallett *                   (0-127).
760210284Sjmallett * @param endpoint_num
761210284Sjmallett *                   USB endpoint number to open the pipe to
762210284Sjmallett *                   (0-15).
763210284Sjmallett * @param device_speed
764210284Sjmallett *                   The speed of the device the pipe is going
765210284Sjmallett *                   to. This must match the device's speed,
766210284Sjmallett *                   which may be different than the port speed.
767210284Sjmallett * @param max_packet The maximum packet length the device can
768210284Sjmallett *                   transmit/receive (low speed=0-8, full
769210284Sjmallett *                   speed=0-1023, high speed=0-1024). This value
770215990Sjmallett *                   comes from the standard endpoint descriptor
771210284Sjmallett *                   field wMaxPacketSize bits <10:0>.
772210284Sjmallett * @param transfer_type
773210284Sjmallett *                   The type of transfer this pipe is for.
774210284Sjmallett * @param transfer_dir
775210284Sjmallett *                   The direction the pipe is in. This is not
776210284Sjmallett *                   used for control pipes.
777210284Sjmallett * @param interval   For ISOCHRONOUS and INTERRUPT transfers,
778210284Sjmallett *                   this is how often the transfer is scheduled
779210284Sjmallett *                   for. All other transfers should specify
780210284Sjmallett *                   zero. The units are in frames (8000/sec at
781210284Sjmallett *                   high speed, 1000/sec for full speed).
782210284Sjmallett * @param multi_count
783210284Sjmallett *                   For high speed devices, this is the maximum
784210284Sjmallett *                   allowed number of packet per microframe.
785210284Sjmallett *                   Specify zero for non high speed devices. This
786215990Sjmallett *                   value comes from the standard endpoint descriptor
787210284Sjmallett *                   field wMaxPacketSize bits <12:11>.
788210284Sjmallett * @param hub_device_addr
789210284Sjmallett *                   Hub device address this device is connected
790210284Sjmallett *                   to. Devices connected directly to Octeon
791210284Sjmallett *                   use zero. This is only used when the device
792210284Sjmallett *                   is full/low speed behind a high speed hub.
793210284Sjmallett *                   The address will be of the high speed hub,
794210284Sjmallett *                   not and full speed hubs after it.
795210284Sjmallett * @param hub_port   Which port on the hub the device is
796210284Sjmallett *                   connected. Use zero for devices connected
797210284Sjmallett *                   directly to Octeon. Like hub_device_addr,
798210284Sjmallett *                   this is only used for full/low speed
799210284Sjmallett *                   devices behind a high speed hub.
800210284Sjmallett *
801210284Sjmallett * @return A non negative value is a pipe handle. Negative
802210284Sjmallett *         values are failure codes from cvmx_usb_status_t.
803210284Sjmallett */
804210284Sjmallettextern int cvmx_usb_open_pipe(cvmx_usb_state_t *state,
805210284Sjmallett                              cvmx_usb_pipe_flags_t flags,
806210284Sjmallett                              int device_addr, int endpoint_num,
807210284Sjmallett                              cvmx_usb_speed_t device_speed, int max_packet,
808210284Sjmallett                              cvmx_usb_transfer_t transfer_type,
809210284Sjmallett                              cvmx_usb_direction_t transfer_dir, int interval,
810210284Sjmallett                              int multi_count, int hub_device_addr,
811210284Sjmallett                              int hub_port);
812210284Sjmallett
813210284Sjmallett/**
814210284Sjmallett * Call to submit a USB Bulk transfer to a pipe.
815210284Sjmallett *
816210284Sjmallett * @param state     USB device state populated by
817210284Sjmallett *                  cvmx_usb_initialize().
818210284Sjmallett * @param pipe_handle
819210284Sjmallett *                  Handle to the pipe for the transfer.
820210284Sjmallett * @param buffer    Physical address of the data buffer in
821210284Sjmallett *                  memory. Note that this is NOT A POINTER, but
822210284Sjmallett *                  the full 64bit physical address of the
823210284Sjmallett *                  buffer. This may be zero if buffer_length is
824210284Sjmallett *                  zero.
825210284Sjmallett * @param buffer_length
826210284Sjmallett *                  Length of buffer in bytes.
827210284Sjmallett * @param callback  Function to call when this transaction
828210284Sjmallett *                  completes. If the return value of this
829210284Sjmallett *                  function isn't an error, then this function
830210284Sjmallett *                  is guaranteed to be called when the
831210284Sjmallett *                  transaction completes. If this parameter is
832210284Sjmallett *                  NULL, then the generic callback registered
833210284Sjmallett *                  through cvmx_usb_register_callback is
834210284Sjmallett *                  called. If both are NULL, then there is no
835210284Sjmallett *                  way to know when a transaction completes.
836210284Sjmallett * @param user_data User supplied data returned when the
837210284Sjmallett *                  callback is called. This is only used if
838210284Sjmallett *                  callback in not NULL.
839210284Sjmallett *
840210284Sjmallett * @return A submitted transaction handle or negative on
841210284Sjmallett *         failure. Negative values are failure codes from
842210284Sjmallett *         cvmx_usb_status_t.
843210284Sjmallett */
844210284Sjmallettextern int cvmx_usb_submit_bulk(cvmx_usb_state_t *state, int pipe_handle,
845210284Sjmallett                                uint64_t buffer, int buffer_length,
846210284Sjmallett                                cvmx_usb_callback_func_t callback,
847210284Sjmallett                                void *user_data);
848210284Sjmallett
849210284Sjmallett/**
850210284Sjmallett * Call to submit a USB Interrupt transfer to a pipe.
851210284Sjmallett *
852210284Sjmallett * @param state     USB device state populated by
853210284Sjmallett *                  cvmx_usb_initialize().
854210284Sjmallett * @param pipe_handle
855210284Sjmallett *                  Handle to the pipe for the transfer.
856210284Sjmallett * @param buffer    Physical address of the data buffer in
857210284Sjmallett *                  memory. Note that this is NOT A POINTER, but
858210284Sjmallett *                  the full 64bit physical address of the
859210284Sjmallett *                  buffer. This may be zero if buffer_length is
860210284Sjmallett *                  zero.
861210284Sjmallett * @param buffer_length
862210284Sjmallett *                  Length of buffer in bytes.
863210284Sjmallett * @param callback  Function to call when this transaction
864210284Sjmallett *                  completes. If the return value of this
865210284Sjmallett *                  function isn't an error, then this function
866210284Sjmallett *                  is guaranteed to be called when the
867210284Sjmallett *                  transaction completes. If this parameter is
868210284Sjmallett *                  NULL, then the generic callback registered
869210284Sjmallett *                  through cvmx_usb_register_callback is
870210284Sjmallett *                  called. If both are NULL, then there is no
871210284Sjmallett *                  way to know when a transaction completes.
872210284Sjmallett * @param user_data User supplied data returned when the
873210284Sjmallett *                  callback is called. This is only used if
874210284Sjmallett *                  callback in not NULL.
875210284Sjmallett *
876210284Sjmallett * @return A submitted transaction handle or negative on
877210284Sjmallett *         failure. Negative values are failure codes from
878210284Sjmallett *         cvmx_usb_status_t.
879210284Sjmallett */
880210284Sjmallettextern int cvmx_usb_submit_interrupt(cvmx_usb_state_t *state, int pipe_handle,
881210284Sjmallett                                     uint64_t buffer, int buffer_length,
882210284Sjmallett                                     cvmx_usb_callback_func_t callback,
883210284Sjmallett                                     void *user_data);
884210284Sjmallett
885210284Sjmallett/**
886210284Sjmallett * Call to submit a USB Control transfer to a pipe.
887210284Sjmallett *
888210284Sjmallett * @param state     USB device state populated by
889210284Sjmallett *                  cvmx_usb_initialize().
890210284Sjmallett * @param pipe_handle
891210284Sjmallett *                  Handle to the pipe for the transfer.
892210284Sjmallett * @param control_header
893210284Sjmallett *                  USB 8 byte control header physical address.
894210284Sjmallett *                  Note that this is NOT A POINTER, but the
895210284Sjmallett *                  full 64bit physical address of the buffer.
896210284Sjmallett * @param buffer    Physical address of the data buffer in
897210284Sjmallett *                  memory. Note that this is NOT A POINTER, but
898210284Sjmallett *                  the full 64bit physical address of the
899210284Sjmallett *                  buffer. This may be zero if buffer_length is
900210284Sjmallett *                  zero.
901210284Sjmallett * @param buffer_length
902210284Sjmallett *                  Length of buffer in bytes.
903210284Sjmallett * @param callback  Function to call when this transaction
904210284Sjmallett *                  completes. If the return value of this
905210284Sjmallett *                  function isn't an error, then this function
906210284Sjmallett *                  is guaranteed to be called when the
907210284Sjmallett *                  transaction completes. If this parameter is
908210284Sjmallett *                  NULL, then the generic callback registered
909210284Sjmallett *                  through cvmx_usb_register_callback is
910210284Sjmallett *                  called. If both are NULL, then there is no
911210284Sjmallett *                  way to know when a transaction completes.
912210284Sjmallett * @param user_data User supplied data returned when the
913210284Sjmallett *                  callback is called. This is only used if
914210284Sjmallett *                  callback in not NULL.
915210284Sjmallett *
916210284Sjmallett * @return A submitted transaction handle or negative on
917210284Sjmallett *         failure. Negative values are failure codes from
918210284Sjmallett *         cvmx_usb_status_t.
919210284Sjmallett */
920210284Sjmallettextern int cvmx_usb_submit_control(cvmx_usb_state_t *state, int pipe_handle,
921210284Sjmallett                                   uint64_t control_header,
922210284Sjmallett                                   uint64_t buffer, int buffer_length,
923210284Sjmallett                                   cvmx_usb_callback_func_t callback,
924210284Sjmallett                                   void *user_data);
925210284Sjmallett
926210284Sjmallett/**
927210284Sjmallett * Flags to pass the cvmx_usb_submit_isochronous() function.
928210284Sjmallett */
929210284Sjmalletttypedef enum
930210284Sjmallett{
931210284Sjmallett    CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT = 1<<0,  /**< Do not return an error if a transfer is less than the maximum packet size of the device */
932210284Sjmallett    CVMX_USB_ISOCHRONOUS_FLAGS_ASAP = 1<<1,         /**< Schedule the transaction as soon as possible */
933210284Sjmallett} cvmx_usb_isochronous_flags_t;
934210284Sjmallett
935210284Sjmallett/**
936210284Sjmallett * Call to submit a USB Isochronous transfer to a pipe.
937210284Sjmallett *
938210284Sjmallett * @param state     USB device state populated by
939210284Sjmallett *                  cvmx_usb_initialize().
940210284Sjmallett * @param pipe_handle
941210284Sjmallett *                  Handle to the pipe for the transfer.
942210284Sjmallett * @param start_frame
943210284Sjmallett *                  Number of frames into the future to schedule
944210284Sjmallett *                  this transaction.
945210284Sjmallett * @param flags     Flags to control the transfer. See
946210284Sjmallett *                  cvmx_usb_isochronous_flags_t for the flag
947210284Sjmallett *                  definitions.
948210284Sjmallett * @param number_packets
949210284Sjmallett *                  Number of sequential packets to transfer.
950210284Sjmallett *                  "packets" is a pointer to an array of this
951210284Sjmallett *                  many packet structures.
952210284Sjmallett * @param packets   Description of each transfer packet as
953210284Sjmallett *                  defined by cvmx_usb_iso_packet_t. The array
954210284Sjmallett *                  pointed to here must stay valid until the
955210284Sjmallett *                  complete callback is called.
956210284Sjmallett * @param buffer    Physical address of the data buffer in
957210284Sjmallett *                  memory. Note that this is NOT A POINTER, but
958210284Sjmallett *                  the full 64bit physical address of the
959210284Sjmallett *                  buffer. This may be zero if buffer_length is
960210284Sjmallett *                  zero.
961210284Sjmallett * @param buffer_length
962210284Sjmallett *                  Length of buffer in bytes.
963210284Sjmallett * @param callback  Function to call when this transaction
964210284Sjmallett *                  completes. If the return value of this
965210284Sjmallett *                  function isn't an error, then this function
966210284Sjmallett *                  is guaranteed to be called when the
967210284Sjmallett *                  transaction completes. If this parameter is
968210284Sjmallett *                  NULL, then the generic callback registered
969210284Sjmallett *                  through cvmx_usb_register_callback is
970210284Sjmallett *                  called. If both are NULL, then there is no
971210284Sjmallett *                  way to know when a transaction completes.
972210284Sjmallett * @param user_data User supplied data returned when the
973210284Sjmallett *                  callback is called. This is only used if
974210284Sjmallett *                  callback in not NULL.
975210284Sjmallett *
976210284Sjmallett * @return A submitted transaction handle or negative on
977210284Sjmallett *         failure. Negative values are failure codes from
978210284Sjmallett *         cvmx_usb_status_t.
979210284Sjmallett */
980210284Sjmallettextern int cvmx_usb_submit_isochronous(cvmx_usb_state_t *state, int pipe_handle,
981210284Sjmallett                                       int start_frame, int flags,
982210284Sjmallett                                       int number_packets,
983210284Sjmallett                                       cvmx_usb_iso_packet_t packets[],
984210284Sjmallett                                       uint64_t buffer, int buffer_length,
985210284Sjmallett                                       cvmx_usb_callback_func_t callback,
986210284Sjmallett                                       void *user_data);
987210284Sjmallett
988210284Sjmallett/**
989210284Sjmallett * Cancel one outstanding request in a pipe. Canceling a request
990210284Sjmallett * can fail if the transaction has already completed before cancel
991210284Sjmallett * is called. Even after a successful cancel call, it may take
992210284Sjmallett * a frame or two for the cvmx_usb_poll() function to call the
993210284Sjmallett * associated callback.
994210284Sjmallett *
995210284Sjmallett * @param state  USB device state populated by
996210284Sjmallett *               cvmx_usb_initialize().
997210284Sjmallett * @param pipe_handle
998210284Sjmallett *               Pipe handle to cancel requests in.
999210284Sjmallett * @param submit_handle
1000210284Sjmallett *               Handle to transaction to cancel, returned by the submit function.
1001210284Sjmallett *
1002210284Sjmallett * @return CVMX_USB_SUCCESS or a negative error code defined in
1003210284Sjmallett *         cvmx_usb_status_t.
1004210284Sjmallett */
1005210284Sjmallettextern cvmx_usb_status_t cvmx_usb_cancel(cvmx_usb_state_t *state,
1006210284Sjmallett                                         int pipe_handle, int submit_handle);
1007210284Sjmallett
1008210284Sjmallett
1009210284Sjmallett/**
1010210284Sjmallett * Cancel all outstanding requests in a pipe. Logically all this
1011210284Sjmallett * does is call cvmx_usb_cancel() in a loop.
1012210284Sjmallett *
1013210284Sjmallett * @param state  USB device state populated by
1014210284Sjmallett *               cvmx_usb_initialize().
1015210284Sjmallett * @param pipe_handle
1016210284Sjmallett *               Pipe handle to cancel requests in.
1017210284Sjmallett *
1018210284Sjmallett * @return CVMX_USB_SUCCESS or a negative error code defined in
1019210284Sjmallett *         cvmx_usb_status_t.
1020210284Sjmallett */
1021210284Sjmallettextern cvmx_usb_status_t cvmx_usb_cancel_all(cvmx_usb_state_t *state,
1022210284Sjmallett                                             int pipe_handle);
1023210284Sjmallett
1024210284Sjmallett/**
1025210284Sjmallett * Close a pipe created with cvmx_usb_open_pipe().
1026210284Sjmallett *
1027210284Sjmallett * @param state  USB device state populated by
1028210284Sjmallett *               cvmx_usb_initialize().
1029210284Sjmallett * @param pipe_handle
1030210284Sjmallett *               Pipe handle to close.
1031210284Sjmallett *
1032210284Sjmallett * @return CVMX_USB_SUCCESS or a negative error code defined in
1033210284Sjmallett *         cvmx_usb_status_t. CVMX_USB_BUSY is returned if the
1034210284Sjmallett *         pipe has outstanding transfers.
1035210284Sjmallett */
1036210284Sjmallettextern cvmx_usb_status_t cvmx_usb_close_pipe(cvmx_usb_state_t *state,
1037210284Sjmallett                                             int pipe_handle);
1038210284Sjmallett
1039210284Sjmallett/**
1040210284Sjmallett * Register a function to be called when various USB events occur.
1041210284Sjmallett *
1042210284Sjmallett * @param state     USB device state populated by
1043210284Sjmallett *                  cvmx_usb_initialize().
1044210284Sjmallett * @param reason    Which event to register for.
1045210284Sjmallett * @param callback  Function to call when the event occurs.
1046210284Sjmallett * @param user_data User data parameter to the function.
1047210284Sjmallett *
1048210284Sjmallett * @return CVMX_USB_SUCCESS or a negative error code defined in
1049210284Sjmallett *         cvmx_usb_status_t.
1050210284Sjmallett */
1051210284Sjmallettextern cvmx_usb_status_t cvmx_usb_register_callback(cvmx_usb_state_t *state,
1052210284Sjmallett                                                    cvmx_usb_callback_t reason,
1053210284Sjmallett                                                    cvmx_usb_callback_func_t callback,
1054210284Sjmallett                                                    void *user_data);
1055210284Sjmallett
1056210284Sjmallett/**
1057210284Sjmallett * Get the current USB protocol level frame number. The frame
1058210284Sjmallett * number is always in the range of 0-0x7ff.
1059210284Sjmallett *
1060210284Sjmallett * @param state  USB device state populated by
1061210284Sjmallett *               cvmx_usb_initialize().
1062210284Sjmallett *
1063210284Sjmallett * @return USB frame number
1064210284Sjmallett */
1065210284Sjmallettextern int cvmx_usb_get_frame_number(cvmx_usb_state_t *state);
1066210284Sjmallett
1067210284Sjmallett/**
1068210284Sjmallett * Poll the USB block for status and call all needed callback
1069210284Sjmallett * handlers. This function is meant to be called in the interrupt
1070210284Sjmallett * handler for the USB controller. It can also be called
1071210284Sjmallett * periodically in a loop for non-interrupt based operation.
1072210284Sjmallett *
1073210284Sjmallett * @param state  USB device state populated by
1074210284Sjmallett *               cvmx_usb_initialize().
1075210284Sjmallett *
1076210284Sjmallett * @return CVMX_USB_SUCCESS or a negative error code defined in
1077210284Sjmallett *         cvmx_usb_status_t.
1078210284Sjmallett */
1079210284Sjmallettextern cvmx_usb_status_t cvmx_usb_poll(cvmx_usb_state_t *state);
1080210284Sjmallett
1081210311Sjmallett/*
1082210311Sjmallett * The FreeBSD host driver uses these functions to manipulate the toggle to deal
1083210311Sjmallett * more easily with endpoint management.
1084210311Sjmallett */
1085210311Sjmallettextern void cvmx_usb_set_toggle(cvmx_usb_state_t *state, int endpoint_num, int toggle);
1086210311Sjmallettextern int cvmx_usb_get_toggle(cvmx_usb_state_t *state, int endpoint_num);
1087210311Sjmallett
1088210284Sjmallett#ifdef	__cplusplus
1089210284Sjmallett}
1090210284Sjmallett#endif
1091210284Sjmallett
1092210284Sjmallett#endif  /* __CVMX_USB_H__ */
1093