On Tue, 2019-12-10 at 10:15 +0100, Greg Kroah-Hartman wrote: > This driver was merged back in 2013 and shows no progress toward every > being merged into the "correct" part of the kernel. The code doesn't > even build for anyone unless you have the specific hardware platform > selected, so odds are it doesn't even work anymore. > > Remove it for now and is someone comes along that has the hardware and > is willing to fix it up, it can be reverted. > > Cc: Aaro Koskinen <aaro.koskinen@xxxxxx> > Cc: David Daney <ddaney.cavm@xxxxxxxxx> > Cc: Nishka Dasgupta <nishkadg.linux@xxxxxxxxx> > Cc: Himadri Pandya <himadri18.07@xxxxxxxxx> > Cc: "Frank A. Cancio Bello" <frank@xxxxxxxxxxxxxxxxxxxxxx> > Cc: Sumit Pundir <pundirsumit11@xxxxxxxxx> > Cc: Laura Lazzati <laura.lazzati.15@xxxxxxxxx> > Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> > --- Similarly we'd really like to keep this too. > drivers/staging/Kconfig | 2 - > drivers/staging/Makefile | 1 - > drivers/staging/octeon-usb/Kconfig | 11 - > drivers/staging/octeon-usb/Makefile | 2 - > drivers/staging/octeon-usb/TODO | 8 - > drivers/staging/octeon-usb/octeon-hcd.c | 3737 ----------------------- > drivers/staging/octeon-usb/octeon-hcd.h | 1847 ----------- > 7 files changed, 5608 deletions(-) > delete mode 100644 drivers/staging/octeon-usb/Kconfig > delete mode 100644 drivers/staging/octeon-usb/Makefile > delete mode 100644 drivers/staging/octeon-usb/TODO > delete mode 100644 drivers/staging/octeon-usb/octeon-hcd.c > delete mode 100644 drivers/staging/octeon-usb/octeon-hcd.h > > diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig > index 15d3549e7cc7..198bf59bc1e6 100644 > --- a/drivers/staging/Kconfig > +++ b/drivers/staging/Kconfig > @@ -42,8 +42,6 @@ source "drivers/staging/rtl8188eu/Kconfig" > > source "drivers/staging/rts5208/Kconfig" > > -source "drivers/staging/octeon-usb/Kconfig" > - > source "drivers/staging/vt6655/Kconfig" > > source "drivers/staging/vt6656/Kconfig" > diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile > index c521204220b5..bf230a830338 100644 > --- a/drivers/staging/Makefile > +++ b/drivers/staging/Makefile > @@ -12,7 +12,6 @@ obj-$(CONFIG_R8712U) += rtl8712/ > obj-$(CONFIG_R8188EU) += rtl8188eu/ > obj-$(CONFIG_RTS5208) += rts5208/ > obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/ > -obj-$(CONFIG_OCTEON_USB) += octeon-usb/ > obj-$(CONFIG_VT6655) += vt6655/ > obj-$(CONFIG_VT6656) += vt6656/ > obj-$(CONFIG_VME_BUS) += vme/ > diff --git a/drivers/staging/octeon-usb/Kconfig b/drivers/staging/octeon-usb/Kconfig > deleted file mode 100644 > index 6a5d842ee0f2..000000000000 > --- a/drivers/staging/octeon-usb/Kconfig > +++ /dev/null > @@ -1,11 +0,0 @@ > -# SPDX-License-Identifier: GPL-2.0 > -config OCTEON_USB > - tristate "Cavium Networks Octeon USB support" > - depends on CAVIUM_OCTEON_SOC && USB > - help > - This driver supports USB host controller on some Cavium > - Networks' products in the Octeon family. > - > - To compile this driver as a module, choose M here. The module > - will be called octeon-hcd. > - > diff --git a/drivers/staging/octeon-usb/Makefile b/drivers/staging/octeon-usb/Makefile > deleted file mode 100644 > index 9873a0130ad5..000000000000 > --- a/drivers/staging/octeon-usb/Makefile > +++ /dev/null > @@ -1,2 +0,0 @@ > -# SPDX-License-Identifier: GPL-2.0 > -obj-${CONFIG_OCTEON_USB} := octeon-hcd.o > diff --git a/drivers/staging/octeon-usb/TODO b/drivers/staging/octeon-usb/TODO > deleted file mode 100644 > index 2b29acca5caa..000000000000 > --- a/drivers/staging/octeon-usb/TODO > +++ /dev/null > @@ -1,8 +0,0 @@ > -This driver is functional and has been tested on EdgeRouter Lite, > -D-Link DSR-1000N and EBH5600 evaluation board with USB mass storage. > - > -TODO: > - - kernel coding style > - - checkpatch warnings > - > -Contact: Aaro Koskinen <aaro.koskinen@xxxxxx> > diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c > deleted file mode 100644 > index 582c9187559d..000000000000 > --- a/drivers/staging/octeon-usb/octeon-hcd.c > +++ /dev/null > @@ -1,3737 +0,0 @@ > -// SPDX-License-Identifier: GPL-2.0 > -/* > - * This file is subject to the terms and conditions of the GNU General Public > - * License. See the file "COPYING" in the main directory of this archive > - * for more details. > - * > - * Copyright (C) 2008 Cavium Networks > - * > - * Some parts of the code were originally released under BSD license: > - * > - * Copyright (c) 2003-2010 Cavium Networks (support@xxxxxxxxxx). All rights > - * reserved. > - * > - * Redistribution and use in source and binary forms, with or without > - * modification, are permitted provided that the following conditions are > - * met: > - * > - * * Redistributions of source code must retain the above copyright > - * notice, this list of conditions and the following disclaimer. > - * > - * * Redistributions in binary form must reproduce the above > - * copyright notice, this list of conditions and the following > - * disclaimer in the documentation and/or other materials provided > - * with the distribution. > - * > - * * Neither the name of Cavium Networks nor the names of > - * its contributors may be used to endorse or promote products > - * derived from this software without specific prior written > - * permission. > - * > - * This Software, including technical data, may be subject to U.S. export > - * control laws, including the U.S. Export Administration Act and its associated > - * regulations, and may be subject to export or import regulations in other > - * countries. > - * > - * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" > - * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR > - * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO > - * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION > - * OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM > - * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, > - * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF > - * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR > - * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR > - * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. > - */ > - > -#include <linux/usb.h> > -#include <linux/slab.h> > -#include <linux/module.h> > -#include <linux/usb/hcd.h> > -#include <linux/prefetch.h> > -#include <linux/dma-mapping.h> > -#include <linux/platform_device.h> > - > -#include <asm/octeon/octeon.h> > - > -#include "octeon-hcd.h" > - > -/** > - * enum cvmx_usb_speed - the possible USB device speeds > - * > - * @CVMX_USB_SPEED_HIGH: Device is operation at 480Mbps > - * @CVMX_USB_SPEED_FULL: Device is operation at 12Mbps > - * @CVMX_USB_SPEED_LOW: Device is operation at 1.5Mbps > - */ > -enum cvmx_usb_speed { > - CVMX_USB_SPEED_HIGH = 0, > - CVMX_USB_SPEED_FULL = 1, > - CVMX_USB_SPEED_LOW = 2, > -}; > - > -/** > - * enum cvmx_usb_transfer - the possible USB transfer types > - * > - * @CVMX_USB_TRANSFER_CONTROL: USB transfer type control for hub and status > - * transfers > - * @CVMX_USB_TRANSFER_ISOCHRONOUS: USB transfer type isochronous for low > - * priority periodic transfers > - * @CVMX_USB_TRANSFER_BULK: USB transfer type bulk for large low priority > - * transfers > - * @CVMX_USB_TRANSFER_INTERRUPT: USB transfer type interrupt for high priority > - * periodic transfers > - */ > -enum cvmx_usb_transfer { > - CVMX_USB_TRANSFER_CONTROL = 0, > - CVMX_USB_TRANSFER_ISOCHRONOUS = 1, > - CVMX_USB_TRANSFER_BULK = 2, > - CVMX_USB_TRANSFER_INTERRUPT = 3, > -}; > - > -/** > - * enum cvmx_usb_direction - the transfer directions > - * > - * @CVMX_USB_DIRECTION_OUT: Data is transferring from Octeon to the device/host > - * @CVMX_USB_DIRECTION_IN: Data is transferring from the device/host to Octeon > - */ > -enum cvmx_usb_direction { > - CVMX_USB_DIRECTION_OUT, > - CVMX_USB_DIRECTION_IN, > -}; > - > -/** > - * enum cvmx_usb_status - possible callback function status codes > - * > - * @CVMX_USB_STATUS_OK: The transaction / operation finished without > - * any errors > - * @CVMX_USB_STATUS_SHORT: FIXME: This is currently not implemented > - * @CVMX_USB_STATUS_CANCEL: The transaction was canceled while in flight > - * by a user call to cvmx_usb_cancel > - * @CVMX_USB_STATUS_ERROR: The transaction aborted with an unexpected > - * error status > - * @CVMX_USB_STATUS_STALL: The transaction received a USB STALL response > - * from the device > - * @CVMX_USB_STATUS_XACTERR: The transaction failed with an error from the > - * device even after a number of retries > - * @CVMX_USB_STATUS_DATATGLERR: The transaction failed with a data toggle > - * error even after a number of retries > - * @CVMX_USB_STATUS_BABBLEERR: The transaction failed with a babble error > - * @CVMX_USB_STATUS_FRAMEERR: The transaction failed with a frame error > - * even after a number of retries > - */ > -enum cvmx_usb_status { > - CVMX_USB_STATUS_OK, > - CVMX_USB_STATUS_SHORT, > - CVMX_USB_STATUS_CANCEL, > - CVMX_USB_STATUS_ERROR, > - CVMX_USB_STATUS_STALL, > - CVMX_USB_STATUS_XACTERR, > - CVMX_USB_STATUS_DATATGLERR, > - CVMX_USB_STATUS_BABBLEERR, > - CVMX_USB_STATUS_FRAMEERR, > -}; > - > -/** > - * struct cvmx_usb_port_status - the USB port status information > - * > - * @port_enabled: 1 = Usb port is enabled, 0 = disabled > - * @port_over_current: 1 = Over current detected, 0 = Over current not > - * detected. Octeon doesn't support over current detection. > - * @port_powered: 1 = Port power is being supplied to the device, 0 = > - * power is off. Octeon doesn't support turning port power > - * off. > - * @port_speed: Current port speed. > - * @connected: 1 = A device is connected to the port, 0 = No device is > - * connected. > - * @connect_change: 1 = Device connected state changed since the last set > - * status call. > - */ > -struct cvmx_usb_port_status { > - u32 reserved : 25; > - u32 port_enabled : 1; > - u32 port_over_current : 1; > - u32 port_powered : 1; > - enum cvmx_usb_speed port_speed : 2; > - u32 connected : 1; > - u32 connect_change : 1; > -}; > - > -/** > - * struct cvmx_usb_iso_packet - descriptor for Isochronous packets > - * > - * @offset: This is the offset in bytes into the main buffer where this data > - * is stored. > - * @length: This is the length in bytes of the data. > - * @status: This is the status of this individual packet transfer. > - */ > -struct cvmx_usb_iso_packet { > - int offset; > - int length; > - enum cvmx_usb_status status; > -}; > - > -/** > - * enum cvmx_usb_initialize_flags - flags used by the initialization function > - * > - * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI: The USB port uses a 12MHz crystal > - * as clock source at USB_XO and > - * USB_XI. > - * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND: The USB port uses 12/24/48MHz 2.5V > - * board clock source at USB_XO. > - * USB_XI should be tied to GND. > - * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK: Mask for clock speed field > - * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ: Speed of reference clock or > - * crystal > - * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ: Speed of reference clock > - * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ: Speed of reference clock > - * @CVMX_USB_INITIALIZE_FLAGS_NO_DMA: Disable DMA and used polled IO for > - * data transfer use for the USB > - */ > -enum cvmx_usb_initialize_flags { > - CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI = 1 << 0, > - CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND = 1 << 1, > - CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK = 3 << 3, > - CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ = 1 << 3, > - CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ = 2 << 3, > - CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ = 3 << 3, > - /* Bits 3-4 used to encode the clock frequency */ > - CVMX_USB_INITIALIZE_FLAGS_NO_DMA = 1 << 5, > -}; > - > -/** > - * enum cvmx_usb_pipe_flags - internal flags for a pipe. > - * > - * @CVMX_USB_PIPE_FLAGS_SCHEDULED: Used internally to determine if a pipe is > - * actively using hardware. > - * @CVMX_USB_PIPE_FLAGS_NEED_PING: Used internally to determine if a high speed > - * pipe is in the ping state. > - */ > -enum cvmx_usb_pipe_flags { > - CVMX_USB_PIPE_FLAGS_SCHEDULED = 1 << 17, > - CVMX_USB_PIPE_FLAGS_NEED_PING = 1 << 18, > -}; > - > -/* Maximum number of times to retry failed transactions */ > -#define MAX_RETRIES 3 > - > -/* Maximum number of hardware channels supported by the USB block */ > -#define MAX_CHANNELS 8 > - > -/* > - * The low level hardware can transfer a maximum of this number of bytes in each > - * transfer. The field is 19 bits wide > - */ > -#define MAX_TRANSFER_BYTES ((1 << 19) - 1) > - > -/* > - * The low level hardware can transfer a maximum of this number of packets in > - * each transfer. The field is 10 bits wide > - */ > -#define MAX_TRANSFER_PACKETS ((1 << 10) - 1) > - > -/** > - * Logical transactions may take numerous low level > - * transactions, especially when splits are concerned. This > - * enum represents all of the possible stages a transaction can > - * be in. Note that split completes are always even. This is so > - * the NAK handler can backup to the previous low level > - * transaction with a simple clearing of bit 0. > - */ > -enum cvmx_usb_stage { > - CVMX_USB_STAGE_NON_CONTROL, > - CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE, > - CVMX_USB_STAGE_SETUP, > - CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE, > - CVMX_USB_STAGE_DATA, > - CVMX_USB_STAGE_DATA_SPLIT_COMPLETE, > - CVMX_USB_STAGE_STATUS, > - CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE, > -}; > - > -/** > - * struct cvmx_usb_transaction - describes each pending USB transaction > - * regardless of type. These are linked together > - * to form a list of pending requests for a pipe. > - * > - * @node: List node for transactions in the pipe. > - * @type: Type of transaction, duplicated of the pipe. > - * @flags: State flags for this transaction. > - * @buffer: User's physical buffer address to read/write. > - * @buffer_length: Size of the user's buffer in bytes. > - * @control_header: For control transactions, physical address of the 8 > - * byte standard header. > - * @iso_start_frame: For ISO transactions, the starting frame number. > - * @iso_number_packets: For ISO transactions, the number of packets in the > - * request. > - * @iso_packets: For ISO transactions, the sub packets in the request. > - * @actual_bytes: Actual bytes transfer for this transaction. > - * @stage: For control transactions, the current stage. > - * @urb: URB. > - */ > -struct cvmx_usb_transaction { > - struct list_head node; > - enum cvmx_usb_transfer type; > - u64 buffer; > - int buffer_length; > - u64 control_header; > - int iso_start_frame; > - int iso_number_packets; > - struct cvmx_usb_iso_packet *iso_packets; > - int xfersize; > - int pktcnt; > - int retries; > - int actual_bytes; > - enum cvmx_usb_stage stage; > - struct urb *urb; > -}; > - > -/** > - * struct cvmx_usb_pipe - a pipe represents a virtual connection between Octeon > - * and some USB device. It contains a list of pending > - * request to the device. > - * > - * @node: List node for pipe list > - * @next: Pipe after this one in the list > - * @transactions: List of pending transactions > - * @interval: For periodic pipes, the interval between packets in > - * frames > - * @next_tx_frame: The next frame this pipe is allowed to transmit on > - * @flags: State flags for this pipe > - * @device_speed: Speed of device connected to this pipe > - * @transfer_type: Type of transaction supported by this pipe > - * @transfer_dir: IN or OUT. Ignored for Control > - * @multi_count: Max packet in a row for the device > - * @max_packet: The device's maximum packet size in bytes > - * @device_addr: USB device address at other end of pipe > - * @endpoint_num: USB endpoint number at other end of pipe > - * @hub_device_addr: Hub address this device is connected to > - * @hub_port: Hub port this device is connected to > - * @pid_toggle: This toggles between 0/1 on every packet send to track > - * the data pid needed > - * @channel: Hardware DMA channel for this pipe > - * @split_sc_frame: The low order bits of the frame number the split > - * complete should be sent on > - */ > -struct cvmx_usb_pipe { > - struct list_head node; > - struct list_head transactions; > - u64 interval; > - u64 next_tx_frame; > - enum cvmx_usb_pipe_flags flags; > - enum cvmx_usb_speed device_speed; > - enum cvmx_usb_transfer transfer_type; > - enum cvmx_usb_direction transfer_dir; > - int multi_count; > - u16 max_packet; > - u8 device_addr; > - u8 endpoint_num; > - u8 hub_device_addr; > - u8 hub_port; > - u8 pid_toggle; > - u8 channel; > - s8 split_sc_frame; > -}; > - > -struct cvmx_usb_tx_fifo { > - struct { > - int channel; > - int size; > - u64 address; > - } entry[MAX_CHANNELS + 1]; > - int head; > - int tail; > -}; > - > -/** > - * struct octeon_hcd - the state of the USB block > - * > - * lock: Serialization lock. > - * init_flags: Flags passed to initialize. > - * index: Which USB block this is for. > - * idle_hardware_channels: Bit set for every idle hardware channel. > - * usbcx_hprt: Stored port status so we don't need to read a CSR to > - * determine splits. > - * pipe_for_channel: Map channels to pipes. > - * pipe: Storage for pipes. > - * indent: Used by debug output to indent functions. > - * port_status: Last port status used for change notification. > - * idle_pipes: List of open pipes that have no transactions. > - * active_pipes: Active pipes indexed by transfer type. > - * frame_number: Increments every SOF interrupt for time keeping. > - * active_split: Points to the current active split, or NULL. > - */ > -struct octeon_hcd { > - spinlock_t lock; /* serialization lock */ > - int init_flags; > - int index; > - int idle_hardware_channels; > - union cvmx_usbcx_hprt usbcx_hprt; > - struct cvmx_usb_pipe *pipe_for_channel[MAX_CHANNELS]; > - int indent; > - struct cvmx_usb_port_status port_status; > - struct list_head idle_pipes; > - struct list_head active_pipes[4]; > - u64 frame_number; > - struct cvmx_usb_transaction *active_split; > - struct cvmx_usb_tx_fifo periodic; > - struct cvmx_usb_tx_fifo nonperiodic; > -}; > - > -/* > - * This macro logically sets a single field in a CSR. It does the sequence > - * read, modify, and write > - */ > -#define USB_SET_FIELD32(address, _union, field, value) \ > - do { \ > - union _union c; \ > - \ > - c.u32 = cvmx_usb_read_csr32(usb, address); \ > - c.s.field = value; \ > - cvmx_usb_write_csr32(usb, address, c.u32); \ > - } while (0) > - > -/* Returns the IO address to push/pop stuff data from the FIFOs */ > -#define USB_FIFO_ADDRESS(channel, usb_index) \ > - (CVMX_USBCX_GOTGCTL(usb_index) + ((channel) + 1) * 0x1000) > - > -/** > - * struct octeon_temp_buffer - a bounce buffer for USB transfers > - * @orig_buffer: the original buffer passed by the USB stack > - * @data: the newly allocated temporary buffer (excluding meta-data) > - * > - * Both the DMA engine and FIFO mode will always transfer full 32-bit words. If > - * the buffer is too short, we need to allocate a temporary one, and this struct > - * represents it. > - */ > -struct octeon_temp_buffer { > - void *orig_buffer; > - u8 data[0]; > -}; > - > -static inline struct usb_hcd *octeon_to_hcd(struct octeon_hcd *p) > -{ > - return container_of((void *)p, struct usb_hcd, hcd_priv); > -} > - > -/** > - * octeon_alloc_temp_buffer - allocate a temporary buffer for USB transfer > - * (if needed) > - * @urb: URB. > - * @mem_flags: Memory allocation flags. > - * > - * This function allocates a temporary bounce buffer whenever it's needed > - * due to HW limitations. > - */ > -static int octeon_alloc_temp_buffer(struct urb *urb, gfp_t mem_flags) > -{ > - struct octeon_temp_buffer *temp; > - > - if (urb->num_sgs || urb->sg || > - (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) || > - !(urb->transfer_buffer_length % sizeof(u32))) > - return 0; > - > - temp = kmalloc(ALIGN(urb->transfer_buffer_length, sizeof(u32)) + > - sizeof(*temp), mem_flags); > - if (!temp) > - return -ENOMEM; > - > - temp->orig_buffer = urb->transfer_buffer; > - if (usb_urb_dir_out(urb)) > - memcpy(temp->data, urb->transfer_buffer, > - urb->transfer_buffer_length); > - urb->transfer_buffer = temp->data; > - urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER; > - > - return 0; > -} > - > -/** > - * octeon_free_temp_buffer - free a temporary buffer used by USB transfers. > - * @urb: URB. > - * > - * Frees a buffer allocated by octeon_alloc_temp_buffer(). > - */ > -static void octeon_free_temp_buffer(struct urb *urb) > -{ > - struct octeon_temp_buffer *temp; > - size_t length; > - > - if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) > - return; > - > - temp = container_of(urb->transfer_buffer, struct octeon_temp_buffer, > - data); > - if (usb_urb_dir_in(urb)) { > - if (usb_pipeisoc(urb->pipe)) > - length = urb->transfer_buffer_length; > - else > - length = urb->actual_length; > - > - memcpy(temp->orig_buffer, urb->transfer_buffer, length); > - } > - urb->transfer_buffer = temp->orig_buffer; > - urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; > - kfree(temp); > -} > - > -/** > - * octeon_map_urb_for_dma - Octeon-specific map_urb_for_dma(). > - * @hcd: USB HCD structure. > - * @urb: URB. > - * @mem_flags: Memory allocation flags. > - */ > -static int octeon_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, > - gfp_t mem_flags) > -{ > - int ret; > - > - ret = octeon_alloc_temp_buffer(urb, mem_flags); > - if (ret) > - return ret; > - > - ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); > - if (ret) > - octeon_free_temp_buffer(urb); > - > - return ret; > -} > - > -/** > - * octeon_unmap_urb_for_dma - Octeon-specific unmap_urb_for_dma() > - * @hcd: USB HCD structure. > - * @urb: URB. > - */ > -static void octeon_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) > -{ > - usb_hcd_unmap_urb_for_dma(hcd, urb); > - octeon_free_temp_buffer(urb); > -} > - > -/** > - * Read a USB 32bit CSR. It performs the necessary address swizzle > - * for 32bit CSRs and logs the value in a readable format if > - * debugging is on. > - * > - * @usb: USB block this access is for > - * @address: 64bit address to read > - * > - * Returns: Result of the read > - */ > -static inline u32 cvmx_usb_read_csr32(struct octeon_hcd *usb, u64 address) > -{ > - return cvmx_read64_uint32(address ^ 4); > -} > - > -/** > - * Write a USB 32bit CSR. It performs the necessary address > - * swizzle for 32bit CSRs and logs the value in a readable format > - * if debugging is on. > - * > - * @usb: USB block this access is for > - * @address: 64bit address to write > - * @value: Value to write > - */ > -static inline void cvmx_usb_write_csr32(struct octeon_hcd *usb, > - u64 address, u32 value) > -{ > - cvmx_write64_uint32(address ^ 4, value); > - cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index)); > -} > - > -/** > - * Return non zero if this pipe connects to a non HIGH speed > - * device through a high speed hub. > - * > - * @usb: USB block this access is for > - * @pipe: Pipe to check > - * > - * Returns: Non zero if we need to do split transactions > - */ > -static inline int cvmx_usb_pipe_needs_split(struct octeon_hcd *usb, > - struct cvmx_usb_pipe *pipe) > -{ > - return pipe->device_speed != CVMX_USB_SPEED_HIGH && > - usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH; > -} > - > -/** > - * Trivial utility function to return the correct PID for a pipe > - * > - * @pipe: pipe to check > - * > - * Returns: PID for pipe > - */ > -static inline int cvmx_usb_get_data_pid(struct cvmx_usb_pipe *pipe) > -{ > - if (pipe->pid_toggle) > - return 2; /* Data1 */ > - return 0; /* Data0 */ > -} > - > -/* Loops through register until txfflsh or rxfflsh become zero.*/ > -static int cvmx_wait_tx_rx(struct octeon_hcd *usb, int fflsh_type) > -{ > - int result; > - u64 address = CVMX_USBCX_GRSTCTL(usb->index); > - u64 done = cvmx_get_cycle() + 100 * > - (u64)octeon_get_clock_rate / 1000000; > - union cvmx_usbcx_grstctl c; > - > - while (1) { > - c.u32 = cvmx_usb_read_csr32(usb, address); > - if (fflsh_type == 0 && c.s.txfflsh == 0) { > - result = 0; > - break; > - } else if (fflsh_type == 1 && c.s.rxfflsh == 0) { > - result = 0; > - break; > - } else if (cvmx_get_cycle() > done) { > - result = -1; > - break; > - } > - > - __delay(100); > - } > - return result; > -} > - > -static void cvmx_fifo_setup(struct octeon_hcd *usb) > -{ > - union cvmx_usbcx_ghwcfg3 usbcx_ghwcfg3; > - union cvmx_usbcx_gnptxfsiz npsiz; > - union cvmx_usbcx_hptxfsiz psiz; > - > - usbcx_ghwcfg3.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_GHWCFG3(usb->index)); > - > - /* > - * Program the USBC_GRXFSIZ register to select the size of the receive > - * FIFO (25%). > - */ > - USB_SET_FIELD32(CVMX_USBCX_GRXFSIZ(usb->index), cvmx_usbcx_grxfsiz, > - rxfdep, usbcx_ghwcfg3.s.dfifodepth / 4); > - > - /* > - * Program the USBC_GNPTXFSIZ register to select the size and the start > - * address of the non-periodic transmit FIFO for nonperiodic > - * transactions (50%). > - */ > - npsiz.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index)); > - npsiz.s.nptxfdep = usbcx_ghwcfg3.s.dfifodepth / 2; > - npsiz.s.nptxfstaddr = usbcx_ghwcfg3.s.dfifodepth / 4; > - cvmx_usb_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index), npsiz.u32); > - > - /* > - * Program the USBC_HPTXFSIZ register to select the size and start > - * address of the periodic transmit FIFO for periodic transactions > - * (25%). > - */ > - psiz.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index)); > - psiz.s.ptxfsize = usbcx_ghwcfg3.s.dfifodepth / 4; > - psiz.s.ptxfstaddr = 3 * usbcx_ghwcfg3.s.dfifodepth / 4; > - cvmx_usb_write_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index), psiz.u32); > - > - /* Flush all FIFOs */ > - USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), > - cvmx_usbcx_grstctl, txfnum, 0x10); > - USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), > - cvmx_usbcx_grstctl, txfflsh, 1); > - cvmx_wait_tx_rx(usb, 0); > - USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), > - cvmx_usbcx_grstctl, rxfflsh, 1); > - cvmx_wait_tx_rx(usb, 1); > -} > - > -/** > - * Shutdown a USB port after a call to cvmx_usb_initialize(). > - * The port should be disabled with all pipes closed when this > - * function is called. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * > - * Returns: 0 or a negative error code. > - */ > -static int cvmx_usb_shutdown(struct octeon_hcd *usb) > -{ > - union cvmx_usbnx_clk_ctl usbn_clk_ctl; > - > - /* Make sure all pipes are closed */ > - if (!list_empty(&usb->idle_pipes) || > - !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_ISOCHRONOUS]) || > - !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_INTERRUPT]) || > - !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_CONTROL]) || > - !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_BULK])) > - return -EBUSY; > - > - /* Disable the clocks and put them in power on reset */ > - usbn_clk_ctl.u64 = cvmx_read64_uint64(CVMX_USBNX_CLK_CTL(usb->index)); > - usbn_clk_ctl.s.enable = 1; > - usbn_clk_ctl.s.por = 1; > - usbn_clk_ctl.s.hclk_rst = 1; > - usbn_clk_ctl.s.prst = 0; > - usbn_clk_ctl.s.hrst = 0; > - cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64); > - return 0; > -} > - > -/** > - * Initialize a USB port for use. This must be called before any > - * other access to the Octeon USB port is made. The port starts > - * off in the disabled state. > - * > - * @dev: Pointer to struct device for logging purposes. > - * @usb: Pointer to struct octeon_hcd. > - * > - * Returns: 0 or a negative error code. > - */ > -static int cvmx_usb_initialize(struct device *dev, > - struct octeon_hcd *usb) > -{ > - int channel; > - int divisor; > - int retries = 0; > - union cvmx_usbcx_hcfg usbcx_hcfg; > - union cvmx_usbnx_clk_ctl usbn_clk_ctl; > - union cvmx_usbcx_gintsts usbc_gintsts; > - union cvmx_usbcx_gahbcfg usbcx_gahbcfg; > - union cvmx_usbcx_gintmsk usbcx_gintmsk; > - union cvmx_usbcx_gusbcfg usbcx_gusbcfg; > - union cvmx_usbnx_usbp_ctl_status usbn_usbp_ctl_status; > - > -retry: > - /* > - * Power On Reset and PHY Initialization > - * > - * 1. Wait for DCOK to assert (nothing to do) > - * > - * 2a. Write USBN0/1_CLK_CTL[POR] = 1 and > - * USBN0/1_CLK_CTL[HRST,PRST,HCLK_RST] = 0 > - */ > - usbn_clk_ctl.u64 = cvmx_read64_uint64(CVMX_USBNX_CLK_CTL(usb->index)); > - usbn_clk_ctl.s.por = 1; > - usbn_clk_ctl.s.hrst = 0; > - usbn_clk_ctl.s.prst = 0; > - usbn_clk_ctl.s.hclk_rst = 0; > - usbn_clk_ctl.s.enable = 0; > - /* > - * 2b. Select the USB reference clock/crystal parameters by writing > - * appropriate values to USBN0/1_CLK_CTL[P_C_SEL, P_RTYPE, P_COM_ON] > - */ > - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) { > - /* > - * The USB port uses 12/24/48MHz 2.5V board clock > - * source at USB_XO. USB_XI should be tied to GND. > - * Most Octeon evaluation boards require this setting > - */ > - if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || > - OCTEON_IS_MODEL(OCTEON_CN56XX) || > - OCTEON_IS_MODEL(OCTEON_CN50XX)) > - /* From CN56XX,CN50XX,CN31XX,CN30XX manuals */ > - usbn_clk_ctl.s.p_rtype = 2; /* p_rclk=1 & p_xenbn=0 */ > - else > - /* From CN52XX manual */ > - usbn_clk_ctl.s.p_rtype = 1; > - > - switch (usb->init_flags & > - CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK) { > - case CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ: > - usbn_clk_ctl.s.p_c_sel = 0; > - break; > - case CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ: > - usbn_clk_ctl.s.p_c_sel = 1; > - break; > - case CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ: > - usbn_clk_ctl.s.p_c_sel = 2; > - break; > - } > - } else { > - /* > - * The USB port uses a 12MHz crystal as clock source > - * at USB_XO and USB_XI > - */ > - if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) > - /* From CN31XX,CN30XX manual */ > - usbn_clk_ctl.s.p_rtype = 3; /* p_rclk=1 & p_xenbn=1 */ > - else > - /* From CN56XX,CN52XX,CN50XX manuals. */ > - usbn_clk_ctl.s.p_rtype = 0; > - > - usbn_clk_ctl.s.p_c_sel = 0; > - } > - /* > - * 2c. Select the HCLK via writing USBN0/1_CLK_CTL[DIVIDE, DIVIDE2] and > - * setting USBN0/1_CLK_CTL[ENABLE] = 1. Divide the core clock down > - * such that USB is as close as possible to 125Mhz > - */ > - divisor = DIV_ROUND_UP(octeon_get_clock_rate(), 125000000); > - /* Lower than 4 doesn't seem to work properly */ > - if (divisor < 4) > - divisor = 4; > - usbn_clk_ctl.s.divide = divisor; > - usbn_clk_ctl.s.divide2 = 0; > - cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64); > - > - /* 2d. Write USBN0/1_CLK_CTL[HCLK_RST] = 1 */ > - usbn_clk_ctl.s.hclk_rst = 1; > - cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64); > - /* 2e. Wait 64 core-clock cycles for HCLK to stabilize */ > - __delay(64); > - /* > - * 3. Program the power-on reset field in the USBN clock-control > - * register: > - * USBN_CLK_CTL[POR] = 0 > - */ > - usbn_clk_ctl.s.por = 0; > - cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64); > - /* 4. Wait 1 ms for PHY clock to start */ > - mdelay(1); > - /* > - * 5. Program the Reset input from automatic test equipment field in the > - * USBP control and status register: > - * USBN_USBP_CTL_STATUS[ATE_RESET] = 1 > - */ > - usbn_usbp_ctl_status.u64 = > - cvmx_read64_uint64(CVMX_USBNX_USBP_CTL_STATUS(usb->index)); > - usbn_usbp_ctl_status.s.ate_reset = 1; > - cvmx_write64_uint64(CVMX_USBNX_USBP_CTL_STATUS(usb->index), > - usbn_usbp_ctl_status.u64); > - /* 6. Wait 10 cycles */ > - __delay(10); > - /* > - * 7. Clear ATE_RESET field in the USBN clock-control register: > - * USBN_USBP_CTL_STATUS[ATE_RESET] = 0 > - */ > - usbn_usbp_ctl_status.s.ate_reset = 0; > - cvmx_write64_uint64(CVMX_USBNX_USBP_CTL_STATUS(usb->index), > - usbn_usbp_ctl_status.u64); > - /* > - * 8. Program the PHY reset field in the USBN clock-control register: > - * USBN_CLK_CTL[PRST] = 1 > - */ > - usbn_clk_ctl.s.prst = 1; > - cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64); > - /* > - * 9. Program the USBP control and status register to select host or > - * device mode. USBN_USBP_CTL_STATUS[HST_MODE] = 0 for host, = 1 for > - * device > - */ > - usbn_usbp_ctl_status.s.hst_mode = 0; > - cvmx_write64_uint64(CVMX_USBNX_USBP_CTL_STATUS(usb->index), > - usbn_usbp_ctl_status.u64); > - /* 10. Wait 1 us */ > - udelay(1); > - /* > - * 11. Program the hreset_n field in the USBN clock-control register: > - * USBN_CLK_CTL[HRST] = 1 > - */ > - usbn_clk_ctl.s.hrst = 1; > - cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64); > - /* 12. Proceed to USB core initialization */ > - usbn_clk_ctl.s.enable = 1; > - cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64); > - udelay(1); > - > - /* > - * USB Core Initialization > - * > - * 1. Read USBC_GHWCFG1, USBC_GHWCFG2, USBC_GHWCFG3, USBC_GHWCFG4 to > - * determine USB core configuration parameters. > - * > - * Nothing needed > - * > - * 2. Program the following fields in the global AHB configuration > - * register (USBC_GAHBCFG) > - * DMA mode, USBC_GAHBCFG[DMAEn]: 1 = DMA mode, 0 = slave mode > - * Burst length, USBC_GAHBCFG[HBSTLEN] = 0 > - * Nonperiodic TxFIFO empty level (slave mode only), > - * USBC_GAHBCFG[NPTXFEMPLVL] > - * Periodic TxFIFO empty level (slave mode only), > - * USBC_GAHBCFG[PTXFEMPLVL] > - * Global interrupt mask, USBC_GAHBCFG[GLBLINTRMSK] = 1 > - */ > - usbcx_gahbcfg.u32 = 0; > - usbcx_gahbcfg.s.dmaen = !(usb->init_flags & > - CVMX_USB_INITIALIZE_FLAGS_NO_DMA); > - usbcx_gahbcfg.s.hbstlen = 0; > - usbcx_gahbcfg.s.nptxfemplvl = 1; > - usbcx_gahbcfg.s.ptxfemplvl = 1; > - usbcx_gahbcfg.s.glblintrmsk = 1; > - cvmx_usb_write_csr32(usb, CVMX_USBCX_GAHBCFG(usb->index), > - usbcx_gahbcfg.u32); > - > - /* > - * 3. Program the following fields in USBC_GUSBCFG register. > - * HS/FS timeout calibration, USBC_GUSBCFG[TOUTCAL] = 0 > - * ULPI DDR select, USBC_GUSBCFG[DDRSEL] = 0 > - * USB turnaround time, USBC_GUSBCFG[USBTRDTIM] = 0x5 > - * PHY low-power clock select, USBC_GUSBCFG[PHYLPWRCLKSEL] = 0 > - */ > - usbcx_gusbcfg.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_GUSBCFG(usb->index)); > - usbcx_gusbcfg.s.toutcal = 0; > - usbcx_gusbcfg.s.ddrsel = 0; > - usbcx_gusbcfg.s.usbtrdtim = 0x5; > - usbcx_gusbcfg.s.phylpwrclksel = 0; > - cvmx_usb_write_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index), > - usbcx_gusbcfg.u32); > - > - /* > - * 4. The software must unmask the following bits in the USBC_GINTMSK > - * register. > - * OTG interrupt mask, USBC_GINTMSK[OTGINTMSK] = 1 > - * Mode mismatch interrupt mask, USBC_GINTMSK[MODEMISMSK] = 1 > - */ > - usbcx_gintmsk.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_GINTMSK(usb->index)); > - usbcx_gintmsk.s.otgintmsk = 1; > - usbcx_gintmsk.s.modemismsk = 1; > - usbcx_gintmsk.s.hchintmsk = 1; > - usbcx_gintmsk.s.sofmsk = 0; > - /* We need RX FIFO interrupts if we don't have DMA */ > - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) > - usbcx_gintmsk.s.rxflvlmsk = 1; > - cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTMSK(usb->index), > - usbcx_gintmsk.u32); > - > - /* > - * Disable all channel interrupts. We'll enable them per channel later. > - */ > - for (channel = 0; channel < 8; channel++) > - cvmx_usb_write_csr32(usb, > - CVMX_USBCX_HCINTMSKX(channel, usb->index), > - 0); > - > - /* > - * Host Port Initialization > - * > - * 1. Program the host-port interrupt-mask field to unmask, > - * USBC_GINTMSK[PRTINT] = 1 > - */ > - USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), > - cvmx_usbcx_gintmsk, prtintmsk, 1); > - USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), > - cvmx_usbcx_gintmsk, disconnintmsk, 1); > - > - /* > - * 2. Program the USBC_HCFG register to select full-speed host > - * or high-speed host. > - */ > - usbcx_hcfg.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HCFG(usb->index)); > - usbcx_hcfg.s.fslssupp = 0; > - usbcx_hcfg.s.fslspclksel = 0; > - cvmx_usb_write_csr32(usb, CVMX_USBCX_HCFG(usb->index), usbcx_hcfg.u32); > - > - cvmx_fifo_setup(usb); > - > - /* > - * If the controller is getting port events right after the reset, it > - * means the initialization failed. Try resetting the controller again > - * in such case. This is seen to happen after cold boot on DSR-1000N. > - */ > - usbc_gintsts.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_GINTSTS(usb->index)); > - cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index), > - usbc_gintsts.u32); > - dev_dbg(dev, "gintsts after reset: 0x%x\n", (int)usbc_gintsts.u32); > - if (!usbc_gintsts.s.disconnint && !usbc_gintsts.s.prtint) > - return 0; > - if (retries++ >= 5) > - return -EAGAIN; > - dev_info(dev, "controller reset failed (gintsts=0x%x) - retrying\n", > - (int)usbc_gintsts.u32); > - msleep(50); > - cvmx_usb_shutdown(usb); > - msleep(50); > - goto retry; > -} > - > -/** > - * Reset a USB port. After this call succeeds, the USB port is > - * online and servicing requests. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - */ > -static void cvmx_usb_reset_port(struct octeon_hcd *usb) > -{ > - usb->usbcx_hprt.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HPRT(usb->index)); > - > - /* Program the port reset bit to start the reset process */ > - USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt, > - prtrst, 1); > - > - /* > - * Wait at least 50ms (high speed), or 10ms (full speed) for the reset > - * process to complete. > - */ > - mdelay(50); > - > - /* Program the port reset bit to 0, USBC_HPRT[PRTRST] = 0 */ > - USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt, > - prtrst, 0); > - > - /* > - * Read the port speed field to get the enumerated speed, > - * USBC_HPRT[PRTSPD]. > - */ > - usb->usbcx_hprt.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HPRT(usb->index)); > -} > - > -/** > - * Disable a USB port. After this call the USB port will not > - * generate data transfers and will not generate events. > - * Transactions in process will fail and call their > - * associated callbacks. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * > - * Returns: 0 or a negative error code. > - */ > -static int cvmx_usb_disable(struct octeon_hcd *usb) > -{ > - /* Disable the port */ > - USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt, > - prtena, 1); > - return 0; > -} > - > -/** > - * Get the current state of the USB port. Use this call to > - * determine if the usb port has anything connected, is enabled, > - * or has some sort of error condition. The return value of this > - * call has "changed" bits to signal of the value of some fields > - * have changed between calls. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * > - * Returns: Port status information > - */ > -static struct cvmx_usb_port_status cvmx_usb_get_status(struct octeon_hcd *usb) > -{ > - union cvmx_usbcx_hprt usbc_hprt; > - struct cvmx_usb_port_status result; > - > - memset(&result, 0, sizeof(result)); > - > - usbc_hprt.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index)); > - result.port_enabled = usbc_hprt.s.prtena; > - result.port_over_current = usbc_hprt.s.prtovrcurract; > - result.port_powered = usbc_hprt.s.prtpwr; > - result.port_speed = usbc_hprt.s.prtspd; > - result.connected = usbc_hprt.s.prtconnsts; > - result.connect_change = > - result.connected != usb->port_status.connected; > - > - return result; > -} > - > -/** > - * Open a virtual pipe between the host and a USB device. A pipe > - * must be opened before data can be transferred between a device > - * and Octeon. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * @device_addr: > - * USB device address to open the pipe to > - * (0-127). > - * @endpoint_num: > - * USB endpoint number to open the pipe to > - * (0-15). > - * @device_speed: > - * The speed of the device the pipe is going > - * to. This must match the device's speed, > - * which may be different than the port speed. > - * @max_packet: The maximum packet length the device can > - * transmit/receive (low speed=0-8, full > - * speed=0-1023, high speed=0-1024). This value > - * comes from the standard endpoint descriptor > - * field wMaxPacketSize bits <10:0>. > - * @transfer_type: > - * The type of transfer this pipe is for. > - * @transfer_dir: > - * The direction the pipe is in. This is not > - * used for control pipes. > - * @interval: For ISOCHRONOUS and INTERRUPT transfers, > - * this is how often the transfer is scheduled > - * for. All other transfers should specify > - * zero. The units are in frames (8000/sec at > - * high speed, 1000/sec for full speed). > - * @multi_count: > - * For high speed devices, this is the maximum > - * allowed number of packet per microframe. > - * Specify zero for non high speed devices. This > - * value comes from the standard endpoint descriptor > - * field wMaxPacketSize bits <12:11>. > - * @hub_device_addr: > - * Hub device address this device is connected > - * to. Devices connected directly to Octeon > - * use zero. This is only used when the device > - * is full/low speed behind a high speed hub. > - * The address will be of the high speed hub, > - * not and full speed hubs after it. > - * @hub_port: Which port on the hub the device is > - * connected. Use zero for devices connected > - * directly to Octeon. Like hub_device_addr, > - * this is only used for full/low speed > - * devices behind a high speed hub. > - * > - * Returns: A non-NULL value is a pipe. NULL means an error. > - */ > -static struct cvmx_usb_pipe *cvmx_usb_open_pipe(struct octeon_hcd *usb, > - int device_addr, > - int endpoint_num, > - enum cvmx_usb_speed > - device_speed, > - int max_packet, > - enum cvmx_usb_transfer > - transfer_type, > - enum cvmx_usb_direction > - transfer_dir, > - int interval, int multi_count, > - int hub_device_addr, > - int hub_port) > -{ > - struct cvmx_usb_pipe *pipe; > - > - pipe = kzalloc(sizeof(*pipe), GFP_ATOMIC); > - if (!pipe) > - return NULL; > - if ((device_speed == CVMX_USB_SPEED_HIGH) && > - (transfer_dir == CVMX_USB_DIRECTION_OUT) && > - (transfer_type == CVMX_USB_TRANSFER_BULK)) > - pipe->flags |= CVMX_USB_PIPE_FLAGS_NEED_PING; > - pipe->device_addr = device_addr; > - pipe->endpoint_num = endpoint_num; > - pipe->device_speed = device_speed; > - pipe->max_packet = max_packet; > - pipe->transfer_type = transfer_type; > - pipe->transfer_dir = transfer_dir; > - INIT_LIST_HEAD(&pipe->transactions); > - > - /* > - * All pipes use interval to rate limit NAK processing. Force an > - * interval if one wasn't supplied > - */ > - if (!interval) > - interval = 1; > - if (cvmx_usb_pipe_needs_split(usb, pipe)) { > - pipe->interval = interval * 8; > - /* Force start splits to be schedule on uFrame 0 */ > - pipe->next_tx_frame = ((usb->frame_number + 7) & ~7) + > - pipe->interval; > - } else { > - pipe->interval = interval; > - pipe->next_tx_frame = usb->frame_number + pipe->interval; > - } > - pipe->multi_count = multi_count; > - pipe->hub_device_addr = hub_device_addr; > - pipe->hub_port = hub_port; > - pipe->pid_toggle = 0; > - pipe->split_sc_frame = -1; > - list_add_tail(&pipe->node, &usb->idle_pipes); > - > - /* > - * We don't need to tell the hardware about this pipe yet since > - * it doesn't have any submitted requests > - */ > - > - return pipe; > -} > - > -/** > - * Poll the RX FIFOs and remove data as needed. This function is only used > - * in non DMA mode. It is very important that this function be called quickly > - * enough to prevent FIFO overflow. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - */ > -static void cvmx_usb_poll_rx_fifo(struct octeon_hcd *usb) > -{ > - union cvmx_usbcx_grxstsph rx_status; > - int channel; > - int bytes; > - u64 address; > - u32 *ptr; > - > - rx_status.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_GRXSTSPH(usb->index)); > - /* Only read data if IN data is there */ > - if (rx_status.s.pktsts != 2) > - return; > - /* Check if no data is available */ > - if (!rx_status.s.bcnt) > - return; > - > - channel = rx_status.s.chnum; > - bytes = rx_status.s.bcnt; > - if (!bytes) > - return; > - > - /* Get where the DMA engine would have written this data */ > - address = cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index) + > - channel * 8); > - > - ptr = cvmx_phys_to_ptr(address); > - cvmx_write64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel * 8, > - address + bytes); > - > - /* Loop writing the FIFO data for this packet into memory */ > - while (bytes > 0) { > - *ptr++ = cvmx_usb_read_csr32(usb, > - USB_FIFO_ADDRESS(channel, usb->index)); > - bytes -= 4; > - } > - CVMX_SYNCW; > -} > - > -/** > - * Fill the TX hardware fifo with data out of the software > - * fifos > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * @fifo: Software fifo to use > - * @available: Amount of space in the hardware fifo > - * > - * Returns: Non zero if the hardware fifo was too small and needs > - * to be serviced again. > - */ > -static int cvmx_usb_fill_tx_hw(struct octeon_hcd *usb, > - struct cvmx_usb_tx_fifo *fifo, int available) > -{ > - /* > - * We're done either when there isn't anymore space or the software FIFO > - * is empty > - */ > - while (available && (fifo->head != fifo->tail)) { > - int i = fifo->tail; > - const u32 *ptr = cvmx_phys_to_ptr(fifo->entry[i].address); > - u64 csr_address = USB_FIFO_ADDRESS(fifo->entry[i].channel, > - usb->index) ^ 4; > - int words = available; > - > - /* Limit the amount of data to what the SW fifo has */ > - if (fifo->entry[i].size <= available) { > - words = fifo->entry[i].size; > - fifo->tail++; > - if (fifo->tail > MAX_CHANNELS) > - fifo->tail = 0; > - } > - > - /* Update the next locations and counts */ > - available -= words; > - fifo->entry[i].address += words * 4; > - fifo->entry[i].size -= words; > - > - /* > - * Write the HW fifo data. The read every three writes is due > - * to an errata on CN3XXX chips > - */ > - while (words > 3) { > - cvmx_write64_uint32(csr_address, *ptr++); > - cvmx_write64_uint32(csr_address, *ptr++); > - cvmx_write64_uint32(csr_address, *ptr++); > - cvmx_read64_uint64( > - CVMX_USBNX_DMA0_INB_CHN0(usb->index)); > - words -= 3; > - } > - cvmx_write64_uint32(csr_address, *ptr++); > - if (--words) { > - cvmx_write64_uint32(csr_address, *ptr++); > - if (--words) > - cvmx_write64_uint32(csr_address, *ptr++); > - } > - cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index)); > - } > - return fifo->head != fifo->tail; > -} > - > -/** > - * Check the hardware FIFOs and fill them as needed > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - */ > -static void cvmx_usb_poll_tx_fifo(struct octeon_hcd *usb) > -{ > - if (usb->periodic.head != usb->periodic.tail) { > - union cvmx_usbcx_hptxsts tx_status; > - > - tx_status.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HPTXSTS(usb->index)); > - if (cvmx_usb_fill_tx_hw(usb, &usb->periodic, > - tx_status.s.ptxfspcavail)) > - USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), > - cvmx_usbcx_gintmsk, ptxfempmsk, 1); > - else > - USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), > - cvmx_usbcx_gintmsk, ptxfempmsk, 0); > - } > - > - if (usb->nonperiodic.head != usb->nonperiodic.tail) { > - union cvmx_usbcx_gnptxsts tx_status; > - > - tx_status.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_GNPTXSTS(usb->index)); > - if (cvmx_usb_fill_tx_hw(usb, &usb->nonperiodic, > - tx_status.s.nptxfspcavail)) > - USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), > - cvmx_usbcx_gintmsk, nptxfempmsk, 1); > - else > - USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), > - cvmx_usbcx_gintmsk, nptxfempmsk, 0); > - } > -} > - > -/** > - * Fill the TX FIFO with an outgoing packet > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * @channel: Channel number to get packet from > - */ > -static void cvmx_usb_fill_tx_fifo(struct octeon_hcd *usb, int channel) > -{ > - union cvmx_usbcx_hccharx hcchar; > - union cvmx_usbcx_hcspltx usbc_hcsplt; > - union cvmx_usbcx_hctsizx usbc_hctsiz; > - struct cvmx_usb_tx_fifo *fifo; > - > - /* We only need to fill data on outbound channels */ > - hcchar.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HCCHARX(channel, usb->index)); > - if (hcchar.s.epdir != CVMX_USB_DIRECTION_OUT) > - return; > - > - /* OUT Splits only have data on the start and not the complete */ > - usbc_hcsplt.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HCSPLTX(channel, usb->index)); > - if (usbc_hcsplt.s.spltena && usbc_hcsplt.s.compsplt) > - return; > - > - /* > - * Find out how many bytes we need to fill and convert it into 32bit > - * words. > - */ > - usbc_hctsiz.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HCTSIZX(channel, usb->index)); > - if (!usbc_hctsiz.s.xfersize) > - return; > - > - if ((hcchar.s.eptype == CVMX_USB_TRANSFER_INTERRUPT) || > - (hcchar.s.eptype == CVMX_USB_TRANSFER_ISOCHRONOUS)) > - fifo = &usb->periodic; > - else > - fifo = &usb->nonperiodic; > - > - fifo->entry[fifo->head].channel = channel; > - fifo->entry[fifo->head].address = > - cvmx_read64_uint64(CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + > - channel * 8); > - fifo->entry[fifo->head].size = (usbc_hctsiz.s.xfersize + 3) >> 2; > - fifo->head++; > - if (fifo->head > MAX_CHANNELS) > - fifo->head = 0; > - > - cvmx_usb_poll_tx_fifo(usb); > -} > - > -/** > - * Perform channel specific setup for Control transactions. All > - * the generic stuff will already have been done in cvmx_usb_start_channel(). > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * @channel: Channel to setup > - * @pipe: Pipe for control transaction > - */ > -static void cvmx_usb_start_channel_control(struct octeon_hcd *usb, > - int channel, > - struct cvmx_usb_pipe *pipe) > -{ > - struct usb_hcd *hcd = octeon_to_hcd(usb); > - struct device *dev = hcd->self.controller; > - struct cvmx_usb_transaction *transaction = > - list_first_entry(&pipe->transactions, typeof(*transaction), > - node); > - struct usb_ctrlrequest *header = > - cvmx_phys_to_ptr(transaction->control_header); > - int bytes_to_transfer = transaction->buffer_length - > - transaction->actual_bytes; > - int packets_to_transfer; > - union cvmx_usbcx_hctsizx usbc_hctsiz; > - > - usbc_hctsiz.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HCTSIZX(channel, usb->index)); > - > - switch (transaction->stage) { > - case CVMX_USB_STAGE_NON_CONTROL: > - case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE: > - dev_err(dev, "%s: ERROR - Non control stage\n", __func__); > - break; > - case CVMX_USB_STAGE_SETUP: > - usbc_hctsiz.s.pid = 3; /* Setup */ > - bytes_to_transfer = sizeof(*header); > - /* All Control operations start with a setup going OUT */ > - USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), > - cvmx_usbcx_hccharx, epdir, > - CVMX_USB_DIRECTION_OUT); > - /* > - * Setup send the control header instead of the buffer data. The > - * buffer data will be used in the next stage > - */ > - cvmx_write64_uint64(CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + > - channel * 8, > - transaction->control_header); > - break; > - case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE: > - usbc_hctsiz.s.pid = 3; /* Setup */ > - bytes_to_transfer = 0; > - /* All Control operations start with a setup going OUT */ > - USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), > - cvmx_usbcx_hccharx, epdir, > - CVMX_USB_DIRECTION_OUT); > - > - USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), > - cvmx_usbcx_hcspltx, compsplt, 1); > - break; > - case CVMX_USB_STAGE_DATA: > - usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe); > - if (cvmx_usb_pipe_needs_split(usb, pipe)) { > - if (header->bRequestType & USB_DIR_IN) > - bytes_to_transfer = 0; > - else if (bytes_to_transfer > pipe->max_packet) > - bytes_to_transfer = pipe->max_packet; > - } > - USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), > - cvmx_usbcx_hccharx, epdir, > - ((header->bRequestType & USB_DIR_IN) ? > - CVMX_USB_DIRECTION_IN : > - CVMX_USB_DIRECTION_OUT)); > - break; > - case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE: > - usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe); > - if (!(header->bRequestType & USB_DIR_IN)) > - bytes_to_transfer = 0; > - USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), > - cvmx_usbcx_hccharx, epdir, > - ((header->bRequestType & USB_DIR_IN) ? > - CVMX_USB_DIRECTION_IN : > - CVMX_USB_DIRECTION_OUT)); > - USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), > - cvmx_usbcx_hcspltx, compsplt, 1); > - break; > - case CVMX_USB_STAGE_STATUS: > - usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe); > - bytes_to_transfer = 0; > - USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), > - cvmx_usbcx_hccharx, epdir, > - ((header->bRequestType & USB_DIR_IN) ? > - CVMX_USB_DIRECTION_OUT : > - CVMX_USB_DIRECTION_IN)); > - break; > - case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE: > - usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe); > - bytes_to_transfer = 0; > - USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), > - cvmx_usbcx_hccharx, epdir, > - ((header->bRequestType & USB_DIR_IN) ? > - CVMX_USB_DIRECTION_OUT : > - CVMX_USB_DIRECTION_IN)); > - USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), > - cvmx_usbcx_hcspltx, compsplt, 1); > - break; > - } > - > - /* > - * Make sure the transfer never exceeds the byte limit of the hardware. > - * Further bytes will be sent as continued transactions > - */ > - if (bytes_to_transfer > MAX_TRANSFER_BYTES) { > - /* Round MAX_TRANSFER_BYTES to a multiple of out packet size */ > - bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet; > - bytes_to_transfer *= pipe->max_packet; > - } > - > - /* > - * Calculate the number of packets to transfer. If the length is zero > - * we still need to transfer one packet > - */ > - packets_to_transfer = DIV_ROUND_UP(bytes_to_transfer, > - pipe->max_packet); > - if (packets_to_transfer == 0) { > - packets_to_transfer = 1; > - } else if ((packets_to_transfer > 1) && > - (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) { > - /* > - * Limit to one packet when not using DMA. Channels must be > - * restarted between every packet for IN transactions, so there > - * is no reason to do multiple packets in a row > - */ > - packets_to_transfer = 1; > - bytes_to_transfer = packets_to_transfer * pipe->max_packet; > - } else if (packets_to_transfer > MAX_TRANSFER_PACKETS) { > - /* > - * Limit the number of packet and data transferred to what the > - * hardware can handle > - */ > - packets_to_transfer = MAX_TRANSFER_PACKETS; > - bytes_to_transfer = packets_to_transfer * pipe->max_packet; > - } > - > - usbc_hctsiz.s.xfersize = bytes_to_transfer; > - usbc_hctsiz.s.pktcnt = packets_to_transfer; > - > - cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index), > - usbc_hctsiz.u32); > -} > - > -/** > - * Start a channel to perform the pipe's head transaction > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * @channel: Channel to setup > - * @pipe: Pipe to start > - */ > -static void cvmx_usb_start_channel(struct octeon_hcd *usb, int channel, > - struct cvmx_usb_pipe *pipe) > -{ > - struct cvmx_usb_transaction *transaction = > - list_first_entry(&pipe->transactions, typeof(*transaction), > - node); > - > - /* Make sure all writes to the DMA region get flushed */ > - CVMX_SYNCW; > - > - /* Attach the channel to the pipe */ > - usb->pipe_for_channel[channel] = pipe; > - pipe->channel = channel; > - pipe->flags |= CVMX_USB_PIPE_FLAGS_SCHEDULED; > - > - /* Mark this channel as in use */ > - usb->idle_hardware_channels &= ~(1 << channel); > - > - /* Enable the channel interrupt bits */ > - { > - union cvmx_usbcx_hcintx usbc_hcint; > - union cvmx_usbcx_hcintmskx usbc_hcintmsk; > - union cvmx_usbcx_haintmsk usbc_haintmsk; > - > - /* Clear all channel status bits */ > - usbc_hcint.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HCINTX(channel, usb->index)); > - > - cvmx_usb_write_csr32(usb, > - CVMX_USBCX_HCINTX(channel, usb->index), > - usbc_hcint.u32); > - > - usbc_hcintmsk.u32 = 0; > - usbc_hcintmsk.s.chhltdmsk = 1; > - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) { > - /* > - * Channels need these extra interrupts when we aren't > - * in DMA mode. > - */ > - usbc_hcintmsk.s.datatglerrmsk = 1; > - usbc_hcintmsk.s.frmovrunmsk = 1; > - usbc_hcintmsk.s.bblerrmsk = 1; > - usbc_hcintmsk.s.xacterrmsk = 1; > - if (cvmx_usb_pipe_needs_split(usb, pipe)) { > - /* > - * Splits don't generate xfercompl, so we need > - * ACK and NYET. > - */ > - usbc_hcintmsk.s.nyetmsk = 1; > - usbc_hcintmsk.s.ackmsk = 1; > - } > - usbc_hcintmsk.s.nakmsk = 1; > - usbc_hcintmsk.s.stallmsk = 1; > - usbc_hcintmsk.s.xfercomplmsk = 1; > - } > - cvmx_usb_write_csr32(usb, > - CVMX_USBCX_HCINTMSKX(channel, usb->index), > - usbc_hcintmsk.u32); > - > - /* Enable the channel interrupt to propagate */ > - usbc_haintmsk.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HAINTMSK(usb->index)); > - usbc_haintmsk.s.haintmsk |= 1 << channel; > - cvmx_usb_write_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index), > - usbc_haintmsk.u32); > - } > - > - /* Setup the location the DMA engine uses. */ > - { > - u64 reg; > - u64 dma_address = transaction->buffer + > - transaction->actual_bytes; > - > - if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS) > - dma_address = transaction->buffer + > - transaction->iso_packets[0].offset + > - transaction->actual_bytes; > - > - if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) > - reg = CVMX_USBNX_DMA0_OUTB_CHN0(usb->index); > - else > - reg = CVMX_USBNX_DMA0_INB_CHN0(usb->index); > - cvmx_write64_uint64(reg + channel * 8, dma_address); > - } > - > - /* Setup both the size of the transfer and the SPLIT characteristics */ > - { > - union cvmx_usbcx_hcspltx usbc_hcsplt = {.u32 = 0}; > - union cvmx_usbcx_hctsizx usbc_hctsiz = {.u32 = 0}; > - int packets_to_transfer; > - int bytes_to_transfer = transaction->buffer_length - > - transaction->actual_bytes; > - > - /* > - * ISOCHRONOUS transactions store each individual transfer size > - * in the packet structure, not the global buffer_length > - */ > - if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS) > - bytes_to_transfer = > - transaction->iso_packets[0].length - > - transaction->actual_bytes; > - > - /* > - * We need to do split transactions when we are talking to non > - * high speed devices that are behind a high speed hub > - */ > - if (cvmx_usb_pipe_needs_split(usb, pipe)) { > - /* > - * On the start split phase (stage is even) record the > - * frame number we will need to send the split complete. > - * We only store the lower two bits since the time ahead > - * can only be two frames > - */ > - if ((transaction->stage & 1) == 0) { > - if (transaction->type == CVMX_USB_TRANSFER_BULK) > - pipe->split_sc_frame = > - (usb->frame_number + 1) & 0x7f; > - else > - pipe->split_sc_frame = > - (usb->frame_number + 2) & 0x7f; > - } else { > - pipe->split_sc_frame = -1; > - } > - > - usbc_hcsplt.s.spltena = 1; > - usbc_hcsplt.s.hubaddr = pipe->hub_device_addr; > - usbc_hcsplt.s.prtaddr = pipe->hub_port; > - usbc_hcsplt.s.compsplt = (transaction->stage == > - CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE); > - > - /* > - * SPLIT transactions can only ever transmit one data > - * packet so limit the transfer size to the max packet > - * size > - */ > - if (bytes_to_transfer > pipe->max_packet) > - bytes_to_transfer = pipe->max_packet; > - > - /* > - * ISOCHRONOUS OUT splits are unique in that they limit > - * data transfers to 188 byte chunks representing the > - * begin/middle/end of the data or all > - */ > - if (!usbc_hcsplt.s.compsplt && > - (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) && > - (pipe->transfer_type == > - CVMX_USB_TRANSFER_ISOCHRONOUS)) { > - /* > - * Clear the split complete frame number as > - * there isn't going to be a split complete > - */ > - pipe->split_sc_frame = -1; > - /* > - * See if we've started this transfer and sent > - * data > - */ > - if (transaction->actual_bytes == 0) { > - /* > - * Nothing sent yet, this is either a > - * begin or the entire payload > - */ > - if (bytes_to_transfer <= 188) > - /* Entire payload in one go */ > - usbc_hcsplt.s.xactpos = 3; > - else > - /* First part of payload */ > - usbc_hcsplt.s.xactpos = 2; > - } else { > - /* > - * Continuing the previous data, we must > - * either be in the middle or at the end > - */ > - if (bytes_to_transfer <= 188) > - /* End of payload */ > - usbc_hcsplt.s.xactpos = 1; > - else > - /* Middle of payload */ > - usbc_hcsplt.s.xactpos = 0; > - } > - /* > - * Again, the transfer size is limited to 188 > - * bytes > - */ > - if (bytes_to_transfer > 188) > - bytes_to_transfer = 188; > - } > - } > - > - /* > - * Make sure the transfer never exceeds the byte limit of the > - * hardware. Further bytes will be sent as continued > - * transactions > - */ > - if (bytes_to_transfer > MAX_TRANSFER_BYTES) { > - /* > - * Round MAX_TRANSFER_BYTES to a multiple of out packet > - * size > - */ > - bytes_to_transfer = MAX_TRANSFER_BYTES / > - pipe->max_packet; > - bytes_to_transfer *= pipe->max_packet; > - } > - > - /* > - * Calculate the number of packets to transfer. If the length is > - * zero we still need to transfer one packet > - */ > - packets_to_transfer = > - DIV_ROUND_UP(bytes_to_transfer, pipe->max_packet); > - if (packets_to_transfer == 0) { > - packets_to_transfer = 1; > - } else if ((packets_to_transfer > 1) && > - (usb->init_flags & > - CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) { > - /* > - * Limit to one packet when not using DMA. Channels must > - * be restarted between every packet for IN > - * transactions, so there is no reason to do multiple > - * packets in a row > - */ > - packets_to_transfer = 1; > - bytes_to_transfer = packets_to_transfer * > - pipe->max_packet; > - } else if (packets_to_transfer > MAX_TRANSFER_PACKETS) { > - /* > - * Limit the number of packet and data transferred to > - * what the hardware can handle > - */ > - packets_to_transfer = MAX_TRANSFER_PACKETS; > - bytes_to_transfer = packets_to_transfer * > - pipe->max_packet; > - } > - > - usbc_hctsiz.s.xfersize = bytes_to_transfer; > - usbc_hctsiz.s.pktcnt = packets_to_transfer; > - > - /* Update the DATA0/DATA1 toggle */ > - usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe); > - /* > - * High speed pipes may need a hardware ping before they start > - */ > - if (pipe->flags & CVMX_USB_PIPE_FLAGS_NEED_PING) > - usbc_hctsiz.s.dopng = 1; > - > - cvmx_usb_write_csr32(usb, > - CVMX_USBCX_HCSPLTX(channel, usb->index), > - usbc_hcsplt.u32); > - cvmx_usb_write_csr32(usb, > - CVMX_USBCX_HCTSIZX(channel, usb->index), > - usbc_hctsiz.u32); > - } > - > - /* Setup the Host Channel Characteristics Register */ > - { > - union cvmx_usbcx_hccharx usbc_hcchar = {.u32 = 0}; > - > - /* > - * Set the startframe odd/even properly. This is only used for > - * periodic > - */ > - usbc_hcchar.s.oddfrm = usb->frame_number & 1; > - > - /* > - * Set the number of back to back packets allowed by this > - * endpoint. Split transactions interpret "ec" as the number of > - * immediate retries of failure. These retries happen too > - * quickly, so we disable these entirely for splits > - */ > - if (cvmx_usb_pipe_needs_split(usb, pipe)) > - usbc_hcchar.s.ec = 1; > - else if (pipe->multi_count < 1) > - usbc_hcchar.s.ec = 1; > - else if (pipe->multi_count > 3) > - usbc_hcchar.s.ec = 3; > - else > - usbc_hcchar.s.ec = pipe->multi_count; > - > - /* Set the rest of the endpoint specific settings */ > - usbc_hcchar.s.devaddr = pipe->device_addr; > - usbc_hcchar.s.eptype = transaction->type; > - usbc_hcchar.s.lspddev = > - (pipe->device_speed == CVMX_USB_SPEED_LOW); > - usbc_hcchar.s.epdir = pipe->transfer_dir; > - usbc_hcchar.s.epnum = pipe->endpoint_num; > - usbc_hcchar.s.mps = pipe->max_packet; > - cvmx_usb_write_csr32(usb, > - CVMX_USBCX_HCCHARX(channel, usb->index), > - usbc_hcchar.u32); > - } > - > - /* Do transaction type specific fixups as needed */ > - switch (transaction->type) { > - case CVMX_USB_TRANSFER_CONTROL: > - cvmx_usb_start_channel_control(usb, channel, pipe); > - break; > - case CVMX_USB_TRANSFER_BULK: > - case CVMX_USB_TRANSFER_INTERRUPT: > - break; > - case CVMX_USB_TRANSFER_ISOCHRONOUS: > - if (!cvmx_usb_pipe_needs_split(usb, pipe)) { > - /* > - * ISO transactions require different PIDs depending on > - * direction and how many packets are needed > - */ > - if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) { > - if (pipe->multi_count < 2) /* Need DATA0 */ > - USB_SET_FIELD32( > - CVMX_USBCX_HCTSIZX(channel, > - usb->index), > - cvmx_usbcx_hctsizx, pid, 0); > - else /* Need MDATA */ > - USB_SET_FIELD32( > - CVMX_USBCX_HCTSIZX(channel, > - usb->index), > - cvmx_usbcx_hctsizx, pid, 3); > - } > - } > - break; > - } > - { > - union cvmx_usbcx_hctsizx usbc_hctsiz = { .u32 = > - cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HCTSIZX(channel, > - usb->index)) > - }; > - transaction->xfersize = usbc_hctsiz.s.xfersize; > - transaction->pktcnt = usbc_hctsiz.s.pktcnt; > - } > - /* Remember when we start a split transaction */ > - if (cvmx_usb_pipe_needs_split(usb, pipe)) > - usb->active_split = transaction; > - USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), > - cvmx_usbcx_hccharx, chena, 1); > - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) > - cvmx_usb_fill_tx_fifo(usb, channel); > -} > - > -/** > - * Find a pipe that is ready to be scheduled to hardware. > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * @xfer_type: Transfer type > - * > - * Returns: Pipe or NULL if none are ready > - */ > -static struct cvmx_usb_pipe *cvmx_usb_find_ready_pipe(struct octeon_hcd *usb, > - enum cvmx_usb_transfer xfer_type) > -{ > - struct list_head *list = usb->active_pipes + xfer_type; > - u64 current_frame = usb->frame_number; > - struct cvmx_usb_pipe *pipe; > - > - list_for_each_entry(pipe, list, node) { > - struct cvmx_usb_transaction *t = > - list_first_entry(&pipe->transactions, typeof(*t), > - node); > - if (!(pipe->flags & CVMX_USB_PIPE_FLAGS_SCHEDULED) && t && > - (pipe->next_tx_frame <= current_frame) && > - ((pipe->split_sc_frame == -1) || > - ((((int)current_frame - pipe->split_sc_frame) & 0x7f) < > - 0x40)) && > - (!usb->active_split || (usb->active_split == t))) { > - prefetch(t); > - return pipe; > - } > - } > - return NULL; > -} > - > -static struct cvmx_usb_pipe *cvmx_usb_next_pipe(struct octeon_hcd *usb, > - int is_sof) > -{ > - struct cvmx_usb_pipe *pipe; > - > - /* Find a pipe needing service. */ > - if (is_sof) { > - /* > - * Only process periodic pipes on SOF interrupts. This way we > - * are sure that the periodic data is sent in the beginning of > - * the frame. > - */ > - pipe = cvmx_usb_find_ready_pipe(usb, > - CVMX_USB_TRANSFER_ISOCHRONOUS); > - if (pipe) > - return pipe; > - pipe = cvmx_usb_find_ready_pipe(usb, > - CVMX_USB_TRANSFER_INTERRUPT); > - if (pipe) > - return pipe; > - } > - pipe = cvmx_usb_find_ready_pipe(usb, CVMX_USB_TRANSFER_CONTROL); > - if (pipe) > - return pipe; > - return cvmx_usb_find_ready_pipe(usb, CVMX_USB_TRANSFER_BULK); > -} > - > -/** > - * Called whenever a pipe might need to be scheduled to the > - * hardware. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * @is_sof: True if this schedule was called on a SOF interrupt. > - */ > -static void cvmx_usb_schedule(struct octeon_hcd *usb, int is_sof) > -{ > - int channel; > - struct cvmx_usb_pipe *pipe; > - int need_sof; > - enum cvmx_usb_transfer ttype; > - > - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) { > - /* > - * Without DMA we need to be careful to not schedule something > - * at the end of a frame and cause an overrun. > - */ > - union cvmx_usbcx_hfnum hfnum = { > - .u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HFNUM(usb->index)) > - }; > - > - union cvmx_usbcx_hfir hfir = { > - .u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HFIR(usb->index)) > - }; > - > - if (hfnum.s.frrem < hfir.s.frint / 4) > - goto done; > - } > - > - while (usb->idle_hardware_channels) { > - /* Find an idle channel */ > - channel = __fls(usb->idle_hardware_channels); > - if (unlikely(channel > 7)) > - break; > - > - pipe = cvmx_usb_next_pipe(usb, is_sof); > - if (!pipe) > - break; > - > - cvmx_usb_start_channel(usb, channel, pipe); > - } > - > -done: > - /* > - * Only enable SOF interrupts when we have transactions pending in the > - * future that might need to be scheduled > - */ > - need_sof = 0; > - for (ttype = CVMX_USB_TRANSFER_CONTROL; > - ttype <= CVMX_USB_TRANSFER_INTERRUPT; ttype++) { > - list_for_each_entry(pipe, &usb->active_pipes[ttype], node) { > - if (pipe->next_tx_frame > usb->frame_number) { > - need_sof = 1; > - break; > - } > - } > - } > - USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), > - cvmx_usbcx_gintmsk, sofmsk, need_sof); > -} > - > -static void octeon_usb_urb_complete_callback(struct octeon_hcd *usb, > - enum cvmx_usb_status status, > - struct cvmx_usb_pipe *pipe, > - struct cvmx_usb_transaction > - *transaction, > - int bytes_transferred, > - struct urb *urb) > -{ > - struct usb_hcd *hcd = octeon_to_hcd(usb); > - struct device *dev = hcd->self.controller; > - > - if (likely(status == CVMX_USB_STATUS_OK)) > - urb->actual_length = bytes_transferred; > - else > - urb->actual_length = 0; > - > - urb->hcpriv = NULL; > - > - /* For Isochronous transactions we need to update the URB packet status > - * list from data in our private copy > - */ > - if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { > - int i; > - /* > - * The pointer to the private list is stored in the setup_packet > - * field. > - */ > - struct cvmx_usb_iso_packet *iso_packet = > - (struct cvmx_usb_iso_packet *)urb->setup_packet; > - /* Recalculate the transfer size by adding up each packet */ > - urb->actual_length = 0; > - for (i = 0; i < urb->number_of_packets; i++) { > - if (iso_packet[i].status == CVMX_USB_STATUS_OK) { > - urb->iso_frame_desc[i].status = 0; > - urb->iso_frame_desc[i].actual_length = > - iso_packet[i].length; > - urb->actual_length += > - urb->iso_frame_desc[i].actual_length; > - } else { > - dev_dbg(dev, "ISOCHRONOUS packet=%d of %d status=%d pipe=%p transaction=%p size=%d\n", > - i, urb->number_of_packets, > - iso_packet[i].status, pipe, > - transaction, iso_packet[i].length); > - urb->iso_frame_desc[i].status = -EREMOTEIO; > - } > - } > - /* Free the private list now that we don't need it anymore */ > - kfree(iso_packet); > - urb->setup_packet = NULL; > - } > - > - switch (status) { > - case CVMX_USB_STATUS_OK: > - urb->status = 0; > - break; > - case CVMX_USB_STATUS_CANCEL: > - if (urb->status == 0) > - urb->status = -ENOENT; > - break; > - case CVMX_USB_STATUS_STALL: > - dev_dbg(dev, "status=stall pipe=%p transaction=%p size=%d\n", > - pipe, transaction, bytes_transferred); > - urb->status = -EPIPE; > - break; > - case CVMX_USB_STATUS_BABBLEERR: > - dev_dbg(dev, "status=babble pipe=%p transaction=%p size=%d\n", > - pipe, transaction, bytes_transferred); > - urb->status = -EPIPE; > - break; > - case CVMX_USB_STATUS_SHORT: > - dev_dbg(dev, "status=short pipe=%p transaction=%p size=%d\n", > - pipe, transaction, bytes_transferred); > - urb->status = -EREMOTEIO; > - break; > - case CVMX_USB_STATUS_ERROR: > - case CVMX_USB_STATUS_XACTERR: > - case CVMX_USB_STATUS_DATATGLERR: > - case CVMX_USB_STATUS_FRAMEERR: > - dev_dbg(dev, "status=%d pipe=%p transaction=%p size=%d\n", > - status, pipe, transaction, bytes_transferred); > - urb->status = -EPROTO; > - break; > - } > - usb_hcd_unlink_urb_from_ep(octeon_to_hcd(usb), urb); > - spin_unlock(&usb->lock); > - usb_hcd_giveback_urb(octeon_to_hcd(usb), urb, urb->status); > - spin_lock(&usb->lock); > -} > - > -/** > - * Signal the completion of a transaction and free it. The > - * transaction will be removed from the pipe transaction list. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * @pipe: Pipe the transaction is on > - * @transaction: > - * Transaction that completed > - * @complete_code: > - * Completion code > - */ > -static void cvmx_usb_complete(struct octeon_hcd *usb, > - struct cvmx_usb_pipe *pipe, > - struct cvmx_usb_transaction *transaction, > - enum cvmx_usb_status complete_code) > -{ > - /* If this was a split then clear our split in progress marker */ > - if (usb->active_split == transaction) > - usb->active_split = NULL; > - > - /* > - * Isochronous transactions need extra processing as they might not be > - * done after a single data transfer > - */ > - if (unlikely(transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)) { > - /* Update the number of bytes transferred in this ISO packet */ > - transaction->iso_packets[0].length = transaction->actual_bytes; > - transaction->iso_packets[0].status = complete_code; > - > - /* > - * If there are more ISOs pending and we succeeded, schedule the > - * next one > - */ > - if ((transaction->iso_number_packets > 1) && > - (complete_code == CVMX_USB_STATUS_OK)) { > - /* No bytes transferred for this packet as of yet */ > - transaction->actual_bytes = 0; > - /* One less ISO waiting to transfer */ > - transaction->iso_number_packets--; > - /* Increment to the next location in our packet array */ > - transaction->iso_packets++; > - transaction->stage = CVMX_USB_STAGE_NON_CONTROL; > - return; > - } > - } > - > - /* Remove the transaction from the pipe list */ > - list_del(&transaction->node); > - if (list_empty(&pipe->transactions)) > - list_move_tail(&pipe->node, &usb->idle_pipes); > - octeon_usb_urb_complete_callback(usb, complete_code, pipe, > - transaction, > - transaction->actual_bytes, > - transaction->urb); > - kfree(transaction); > -} > - > -/** > - * Submit a usb transaction to a pipe. Called for all types > - * of transactions. > - * > - * @usb: > - * @pipe: Which pipe to submit to. > - * @type: Transaction type > - * @buffer: User buffer for the transaction > - * @buffer_length: > - * User buffer's length in bytes > - * @control_header: > - * For control transactions, the 8 byte standard header > - * @iso_start_frame: > - * For ISO transactions, the start frame > - * @iso_number_packets: > - * For ISO, the number of packet in the transaction. > - * @iso_packets: > - * A description of each ISO packet > - * @urb: URB for the callback > - * > - * Returns: Transaction or NULL on failure. > - */ > -static struct cvmx_usb_transaction *cvmx_usb_submit_transaction( > - struct octeon_hcd *usb, > - struct cvmx_usb_pipe *pipe, > - enum cvmx_usb_transfer type, > - u64 buffer, > - int buffer_length, > - u64 control_header, > - int iso_start_frame, > - int iso_number_packets, > - struct cvmx_usb_iso_packet *iso_packets, > - struct urb *urb) > -{ > - struct cvmx_usb_transaction *transaction; > - > - if (unlikely(pipe->transfer_type != type)) > - return NULL; > - > - transaction = kzalloc(sizeof(*transaction), GFP_ATOMIC); > - if (unlikely(!transaction)) > - return NULL; > - > - transaction->type = type; > - transaction->buffer = buffer; > - transaction->buffer_length = buffer_length; > - transaction->control_header = control_header; > - /* FIXME: This is not used, implement it. */ > - transaction->iso_start_frame = iso_start_frame; > - transaction->iso_number_packets = iso_number_packets; > - transaction->iso_packets = iso_packets; > - transaction->urb = urb; > - if (transaction->type == CVMX_USB_TRANSFER_CONTROL) > - transaction->stage = CVMX_USB_STAGE_SETUP; > - else > - transaction->stage = CVMX_USB_STAGE_NON_CONTROL; > - > - if (!list_empty(&pipe->transactions)) { > - list_add_tail(&transaction->node, &pipe->transactions); > - } else { > - list_add_tail(&transaction->node, &pipe->transactions); > - list_move_tail(&pipe->node, > - &usb->active_pipes[pipe->transfer_type]); > - > - /* > - * We may need to schedule the pipe if this was the head of the > - * pipe. > - */ > - cvmx_usb_schedule(usb, 0); > - } > - > - return transaction; > -} > - > -/** > - * Call to submit a USB Bulk transfer to a pipe. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * @pipe: Handle to the pipe for the transfer. > - * @urb: URB. > - * > - * Returns: A submitted transaction or NULL on failure. > - */ > -static struct cvmx_usb_transaction *cvmx_usb_submit_bulk( > - struct octeon_hcd *usb, > - struct cvmx_usb_pipe *pipe, > - struct urb *urb) > -{ > - return cvmx_usb_submit_transaction(usb, pipe, CVMX_USB_TRANSFER_BULK, > - urb->transfer_dma, > - urb->transfer_buffer_length, > - 0, /* control_header */ > - 0, /* iso_start_frame */ > - 0, /* iso_number_packets */ > - NULL, /* iso_packets */ > - urb); > -} > - > -/** > - * Call to submit a USB Interrupt transfer to a pipe. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * @pipe: Handle to the pipe for the transfer. > - * @urb: URB returned when the callback is called. > - * > - * Returns: A submitted transaction or NULL on failure. > - */ > -static struct cvmx_usb_transaction *cvmx_usb_submit_interrupt( > - struct octeon_hcd *usb, > - struct cvmx_usb_pipe *pipe, > - struct urb *urb) > -{ > - return cvmx_usb_submit_transaction(usb, pipe, > - CVMX_USB_TRANSFER_INTERRUPT, > - urb->transfer_dma, > - urb->transfer_buffer_length, > - 0, /* control_header */ > - 0, /* iso_start_frame */ > - 0, /* iso_number_packets */ > - NULL, /* iso_packets */ > - urb); > -} > - > -/** > - * Call to submit a USB Control transfer to a pipe. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * @pipe: Handle to the pipe for the transfer. > - * @urb: URB. > - * > - * Returns: A submitted transaction or NULL on failure. > - */ > -static struct cvmx_usb_transaction *cvmx_usb_submit_control( > - struct octeon_hcd *usb, > - struct cvmx_usb_pipe *pipe, > - struct urb *urb) > -{ > - int buffer_length = urb->transfer_buffer_length; > - u64 control_header = urb->setup_dma; > - struct usb_ctrlrequest *header = cvmx_phys_to_ptr(control_header); > - > - if ((header->bRequestType & USB_DIR_IN) == 0) > - buffer_length = le16_to_cpu(header->wLength); > - > - return cvmx_usb_submit_transaction(usb, pipe, > - CVMX_USB_TRANSFER_CONTROL, > - urb->transfer_dma, buffer_length, > - control_header, > - 0, /* iso_start_frame */ > - 0, /* iso_number_packets */ > - NULL, /* iso_packets */ > - urb); > -} > - > -/** > - * Call to submit a USB Isochronous transfer to a pipe. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * @pipe: Handle to the pipe for the transfer. > - * @urb: URB returned when the callback is called. > - * > - * Returns: A submitted transaction or NULL on failure. > - */ > -static struct cvmx_usb_transaction *cvmx_usb_submit_isochronous( > - struct octeon_hcd *usb, > - struct cvmx_usb_pipe *pipe, > - struct urb *urb) > -{ > - struct cvmx_usb_iso_packet *packets; > - > - packets = (struct cvmx_usb_iso_packet *)urb->setup_packet; > - return cvmx_usb_submit_transaction(usb, pipe, > - CVMX_USB_TRANSFER_ISOCHRONOUS, > - urb->transfer_dma, > - urb->transfer_buffer_length, > - 0, /* control_header */ > - urb->start_frame, > - urb->number_of_packets, > - packets, urb); > -} > - > -/** > - * Cancel one outstanding request in a pipe. Canceling a request > - * can fail if the transaction has already completed before cancel > - * is called. Even after a successful cancel call, it may take > - * a frame or two for the cvmx_usb_poll() function to call the > - * associated callback. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * @pipe: Pipe to cancel requests in. > - * @transaction: Transaction to cancel, returned by the submit function. > - * > - * Returns: 0 or a negative error code. > - */ > -static int cvmx_usb_cancel(struct octeon_hcd *usb, > - struct cvmx_usb_pipe *pipe, > - struct cvmx_usb_transaction *transaction) > -{ > - /* > - * If the transaction is the HEAD of the queue and scheduled. We need to > - * treat it special > - */ > - if (list_first_entry(&pipe->transactions, typeof(*transaction), node) == > - transaction && (pipe->flags & CVMX_USB_PIPE_FLAGS_SCHEDULED)) { > - union cvmx_usbcx_hccharx usbc_hcchar; > - > - usb->pipe_for_channel[pipe->channel] = NULL; > - pipe->flags &= ~CVMX_USB_PIPE_FLAGS_SCHEDULED; > - > - CVMX_SYNCW; > - > - usbc_hcchar.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HCCHARX(pipe->channel, usb->index)); > - /* > - * If the channel isn't enabled then the transaction already > - * completed. > - */ > - if (usbc_hcchar.s.chena) { > - usbc_hcchar.s.chdis = 1; > - cvmx_usb_write_csr32(usb, > - CVMX_USBCX_HCCHARX(pipe->channel, > - usb->index), > - usbc_hcchar.u32); > - } > - } > - cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_CANCEL); > - return 0; > -} > - > -/** > - * Cancel all outstanding requests in a pipe. Logically all this > - * does is call cvmx_usb_cancel() in a loop. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * @pipe: Pipe to cancel requests in. > - * > - * Returns: 0 or a negative error code. > - */ > -static int cvmx_usb_cancel_all(struct octeon_hcd *usb, > - struct cvmx_usb_pipe *pipe) > -{ > - struct cvmx_usb_transaction *transaction, *next; > - > - /* Simply loop through and attempt to cancel each transaction */ > - list_for_each_entry_safe(transaction, next, &pipe->transactions, node) { > - int result = cvmx_usb_cancel(usb, pipe, transaction); > - > - if (unlikely(result != 0)) > - return result; > - } > - return 0; > -} > - > -/** > - * Close a pipe created with cvmx_usb_open_pipe(). > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * @pipe: Pipe to close. > - * > - * Returns: 0 or a negative error code. EBUSY is returned if the pipe has > - * outstanding transfers. > - */ > -static int cvmx_usb_close_pipe(struct octeon_hcd *usb, > - struct cvmx_usb_pipe *pipe) > -{ > - /* Fail if the pipe has pending transactions */ > - if (!list_empty(&pipe->transactions)) > - return -EBUSY; > - > - list_del(&pipe->node); > - kfree(pipe); > - > - return 0; > -} > - > -/** > - * Get the current USB protocol level frame number. The frame > - * number is always in the range of 0-0x7ff. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * > - * Returns: USB frame number > - */ > -static int cvmx_usb_get_frame_number(struct octeon_hcd *usb) > -{ > - union cvmx_usbcx_hfnum usbc_hfnum; > - > - usbc_hfnum.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index)); > - > - return usbc_hfnum.s.frnum; > -} > - > -static void cvmx_usb_transfer_control(struct octeon_hcd *usb, > - struct cvmx_usb_pipe *pipe, > - struct cvmx_usb_transaction *transaction, > - union cvmx_usbcx_hccharx usbc_hcchar, > - int buffer_space_left, > - int bytes_in_last_packet) > -{ > - switch (transaction->stage) { > - case CVMX_USB_STAGE_NON_CONTROL: > - case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE: > - /* This should be impossible */ > - cvmx_usb_complete(usb, pipe, transaction, > - CVMX_USB_STATUS_ERROR); > - break; > - case CVMX_USB_STAGE_SETUP: > - pipe->pid_toggle = 1; > - if (cvmx_usb_pipe_needs_split(usb, pipe)) { > - transaction->stage = > - CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE; > - } else { > - struct usb_ctrlrequest *header = > - cvmx_phys_to_ptr(transaction->control_header); > - if (header->wLength) > - transaction->stage = CVMX_USB_STAGE_DATA; > - else > - transaction->stage = CVMX_USB_STAGE_STATUS; > - } > - break; > - case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE: > - { > - struct usb_ctrlrequest *header = > - cvmx_phys_to_ptr(transaction->control_header); > - if (header->wLength) > - transaction->stage = CVMX_USB_STAGE_DATA; > - else > - transaction->stage = CVMX_USB_STAGE_STATUS; > - } > - break; > - case CVMX_USB_STAGE_DATA: > - if (cvmx_usb_pipe_needs_split(usb, pipe)) { > - transaction->stage = CVMX_USB_STAGE_DATA_SPLIT_COMPLETE; > - /* > - * For setup OUT data that are splits, > - * the hardware doesn't appear to count > - * transferred data. Here we manually > - * update the data transferred > - */ > - if (!usbc_hcchar.s.epdir) { > - if (buffer_space_left < pipe->max_packet) > - transaction->actual_bytes += > - buffer_space_left; > - else > - transaction->actual_bytes += > - pipe->max_packet; > - } > - } else if ((buffer_space_left == 0) || > - (bytes_in_last_packet < pipe->max_packet)) { > - pipe->pid_toggle = 1; > - transaction->stage = CVMX_USB_STAGE_STATUS; > - } > - break; > - case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE: > - if ((buffer_space_left == 0) || > - (bytes_in_last_packet < pipe->max_packet)) { > - pipe->pid_toggle = 1; > - transaction->stage = CVMX_USB_STAGE_STATUS; > - } else { > - transaction->stage = CVMX_USB_STAGE_DATA; > - } > - break; > - case CVMX_USB_STAGE_STATUS: > - if (cvmx_usb_pipe_needs_split(usb, pipe)) > - transaction->stage = > - CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE; > - else > - cvmx_usb_complete(usb, pipe, transaction, > - CVMX_USB_STATUS_OK); > - break; > - case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE: > - cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_OK); > - break; > - } > -} > - > -static void cvmx_usb_transfer_bulk(struct octeon_hcd *usb, > - struct cvmx_usb_pipe *pipe, > - struct cvmx_usb_transaction *transaction, > - union cvmx_usbcx_hcintx usbc_hcint, > - int buffer_space_left, > - int bytes_in_last_packet) > -{ > - /* > - * The only time a bulk transfer isn't complete when it finishes with > - * an ACK is during a split transaction. For splits we need to continue > - * the transfer if more data is needed. > - */ > - if (cvmx_usb_pipe_needs_split(usb, pipe)) { > - if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL) > - transaction->stage = > - CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE; > - else if (buffer_space_left && > - (bytes_in_last_packet == pipe->max_packet)) > - transaction->stage = CVMX_USB_STAGE_NON_CONTROL; > - else > - cvmx_usb_complete(usb, pipe, transaction, > - CVMX_USB_STATUS_OK); > - } else { > - if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) && > - (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) && > - (usbc_hcint.s.nak)) > - pipe->flags |= CVMX_USB_PIPE_FLAGS_NEED_PING; > - if (!buffer_space_left || > - (bytes_in_last_packet < pipe->max_packet)) > - cvmx_usb_complete(usb, pipe, transaction, > - CVMX_USB_STATUS_OK); > - } > -} > - > -static void cvmx_usb_transfer_intr(struct octeon_hcd *usb, > - struct cvmx_usb_pipe *pipe, > - struct cvmx_usb_transaction *transaction, > - int buffer_space_left, > - int bytes_in_last_packet) > -{ > - if (cvmx_usb_pipe_needs_split(usb, pipe)) { > - if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL) { > - transaction->stage = > - CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE; > - } else if (buffer_space_left && > - (bytes_in_last_packet == pipe->max_packet)) { > - transaction->stage = CVMX_USB_STAGE_NON_CONTROL; > - } else { > - pipe->next_tx_frame += pipe->interval; > - cvmx_usb_complete(usb, pipe, transaction, > - CVMX_USB_STATUS_OK); > - } > - } else if (!buffer_space_left || > - (bytes_in_last_packet < pipe->max_packet)) { > - pipe->next_tx_frame += pipe->interval; > - cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_OK); > - } > -} > - > -static void cvmx_usb_transfer_isoc(struct octeon_hcd *usb, > - struct cvmx_usb_pipe *pipe, > - struct cvmx_usb_transaction *transaction, > - int buffer_space_left, > - int bytes_in_last_packet, > - int bytes_this_transfer) > -{ > - if (cvmx_usb_pipe_needs_split(usb, pipe)) { > - /* > - * ISOCHRONOUS OUT splits don't require a complete split stage. > - * Instead they use a sequence of begin OUT splits to transfer > - * the data 188 bytes at a time. Once the transfer is complete, > - * the pipe sleeps until the next schedule interval. > - */ > - if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) { > - /* > - * If no space left or this wasn't a max size packet > - * then this transfer is complete. Otherwise start it > - * again to send the next 188 bytes > - */ > - if (!buffer_space_left || (bytes_this_transfer < 188)) { > - pipe->next_tx_frame += pipe->interval; > - cvmx_usb_complete(usb, pipe, transaction, > - CVMX_USB_STATUS_OK); > - } > - return; > - } > - if (transaction->stage == > - CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE) { > - /* > - * We are in the incoming data phase. Keep getting data > - * until we run out of space or get a small packet > - */ > - if ((buffer_space_left == 0) || > - (bytes_in_last_packet < pipe->max_packet)) { > - pipe->next_tx_frame += pipe->interval; > - cvmx_usb_complete(usb, pipe, transaction, > - CVMX_USB_STATUS_OK); > - } > - } else { > - transaction->stage = > - CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE; > - } > - } else { > - pipe->next_tx_frame += pipe->interval; > - cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_OK); > - } > -} > - > -/** > - * Poll a channel for status > - * > - * @usb: USB device > - * @channel: Channel to poll > - * > - * Returns: Zero on success > - */ > -static int cvmx_usb_poll_channel(struct octeon_hcd *usb, int channel) > -{ > - struct usb_hcd *hcd = octeon_to_hcd(usb); > - struct device *dev = hcd->self.controller; > - union cvmx_usbcx_hcintx usbc_hcint; > - union cvmx_usbcx_hctsizx usbc_hctsiz; > - union cvmx_usbcx_hccharx usbc_hcchar; > - struct cvmx_usb_pipe *pipe; > - struct cvmx_usb_transaction *transaction; > - int bytes_this_transfer; > - int bytes_in_last_packet; > - int packets_processed; > - int buffer_space_left; > - > - /* Read the interrupt status bits for the channel */ > - usbc_hcint.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HCINTX(channel, usb->index)); > - > - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) { > - usbc_hcchar.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HCCHARX(channel, usb->index)); > - > - if (usbc_hcchar.s.chena && usbc_hcchar.s.chdis) { > - /* > - * There seems to be a bug in CN31XX which can cause > - * interrupt IN transfers to get stuck until we do a > - * write of HCCHARX without changing things > - */ > - cvmx_usb_write_csr32(usb, > - CVMX_USBCX_HCCHARX(channel, > - usb->index), > - usbc_hcchar.u32); > - return 0; > - } > - > - /* > - * In non DMA mode the channels don't halt themselves. We need > - * to manually disable channels that are left running > - */ > - if (!usbc_hcint.s.chhltd) { > - if (usbc_hcchar.s.chena) { > - union cvmx_usbcx_hcintmskx hcintmsk; > - /* Disable all interrupts except CHHLTD */ > - hcintmsk.u32 = 0; > - hcintmsk.s.chhltdmsk = 1; > - cvmx_usb_write_csr32(usb, > - CVMX_USBCX_HCINTMSKX(channel, usb->index), > - hcintmsk.u32); > - usbc_hcchar.s.chdis = 1; > - cvmx_usb_write_csr32(usb, > - CVMX_USBCX_HCCHARX(channel, usb->index), > - usbc_hcchar.u32); > - return 0; > - } else if (usbc_hcint.s.xfercompl) { > - /* > - * Successful IN/OUT with transfer complete. > - * Channel halt isn't needed. > - */ > - } else { > - dev_err(dev, "USB%d: Channel %d interrupt without halt\n", > - usb->index, channel); > - return 0; > - } > - } > - } else { > - /* > - * There is are no interrupts that we need to process when the > - * channel is still running > - */ > - if (!usbc_hcint.s.chhltd) > - return 0; > - } > - > - /* Disable the channel interrupts now that it is done */ > - cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0); > - usb->idle_hardware_channels |= (1 << channel); > - > - /* Make sure this channel is tied to a valid pipe */ > - pipe = usb->pipe_for_channel[channel]; > - prefetch(pipe); > - if (!pipe) > - return 0; > - transaction = list_first_entry(&pipe->transactions, > - typeof(*transaction), > - node); > - prefetch(transaction); > - > - /* > - * Disconnect this pipe from the HW channel. Later the schedule > - * function will figure out which pipe needs to go > - */ > - usb->pipe_for_channel[channel] = NULL; > - pipe->flags &= ~CVMX_USB_PIPE_FLAGS_SCHEDULED; > - > - /* > - * Read the channel config info so we can figure out how much data > - * transferred > - */ > - usbc_hcchar.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HCCHARX(channel, usb->index)); > - usbc_hctsiz.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HCTSIZX(channel, usb->index)); > - > - /* > - * Calculating the number of bytes successfully transferred is dependent > - * on the transfer direction > - */ > - packets_processed = transaction->pktcnt - usbc_hctsiz.s.pktcnt; > - if (usbc_hcchar.s.epdir) { > - /* > - * IN transactions are easy. For every byte received the > - * hardware decrements xfersize. All we need to do is subtract > - * the current value of xfersize from its starting value and we > - * know how many bytes were written to the buffer > - */ > - bytes_this_transfer = transaction->xfersize - > - usbc_hctsiz.s.xfersize; > - } else { > - /* > - * OUT transaction don't decrement xfersize. Instead pktcnt is > - * decremented on every successful packet send. The hardware > - * does this when it receives an ACK, or NYET. If it doesn't > - * receive one of these responses pktcnt doesn't change > - */ > - bytes_this_transfer = packets_processed * usbc_hcchar.s.mps; > - /* > - * The last packet may not be a full transfer if we didn't have > - * enough data > - */ > - if (bytes_this_transfer > transaction->xfersize) > - bytes_this_transfer = transaction->xfersize; > - } > - /* Figure out how many bytes were in the last packet of the transfer */ > - if (packets_processed) > - bytes_in_last_packet = bytes_this_transfer - > - (packets_processed - 1) * usbc_hcchar.s.mps; > - else > - bytes_in_last_packet = bytes_this_transfer; > - > - /* > - * As a special case, setup transactions output the setup header, not > - * the user's data. For this reason we don't count setup data as bytes > - * transferred > - */ > - if ((transaction->stage == CVMX_USB_STAGE_SETUP) || > - (transaction->stage == CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE)) > - bytes_this_transfer = 0; > - > - /* > - * Add the bytes transferred to the running total. It is important that > - * bytes_this_transfer doesn't count any data that needs to be > - * retransmitted > - */ > - transaction->actual_bytes += bytes_this_transfer; > - if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS) > - buffer_space_left = transaction->iso_packets[0].length - > - transaction->actual_bytes; > - else > - buffer_space_left = transaction->buffer_length - > - transaction->actual_bytes; > - > - /* > - * We need to remember the PID toggle state for the next transaction. > - * The hardware already updated it for the next transaction > - */ > - pipe->pid_toggle = !(usbc_hctsiz.s.pid == 0); > - > - /* > - * For high speed bulk out, assume the next transaction will need to do > - * a ping before proceeding. If this isn't true the ACK processing below > - * will clear this flag > - */ > - if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) && > - (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) && > - (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT)) > - pipe->flags |= CVMX_USB_PIPE_FLAGS_NEED_PING; > - > - if (WARN_ON_ONCE(bytes_this_transfer < 0)) { > - /* > - * In some rare cases the DMA engine seems to get stuck and > - * keeps substracting same byte count over and over again. In > - * such case we just need to fail every transaction. > - */ > - cvmx_usb_complete(usb, pipe, transaction, > - CVMX_USB_STATUS_ERROR); > - return 0; > - } > - > - if (usbc_hcint.s.stall) { > - /* > - * STALL as a response means this transaction cannot be > - * completed because the device can't process transactions. Tell > - * the user. Any data that was transferred will be counted on > - * the actual bytes transferred > - */ > - pipe->pid_toggle = 0; > - cvmx_usb_complete(usb, pipe, transaction, > - CVMX_USB_STATUS_STALL); > - } else if (usbc_hcint.s.xacterr) { > - /* > - * XactErr as a response means the device signaled > - * something wrong with the transfer. For example, PID > - * toggle errors cause these. > - */ > - cvmx_usb_complete(usb, pipe, transaction, > - CVMX_USB_STATUS_XACTERR); > - } else if (usbc_hcint.s.bblerr) { > - /* Babble Error (BblErr) */ > - cvmx_usb_complete(usb, pipe, transaction, > - CVMX_USB_STATUS_BABBLEERR); > - } else if (usbc_hcint.s.datatglerr) { > - /* Data toggle error */ > - cvmx_usb_complete(usb, pipe, transaction, > - CVMX_USB_STATUS_DATATGLERR); > - } else if (usbc_hcint.s.nyet) { > - /* > - * NYET as a response is only allowed in three cases: as a > - * response to a ping, as a response to a split transaction, and > - * as a response to a bulk out. The ping case is handled by > - * hardware, so we only have splits and bulk out > - */ > - if (!cvmx_usb_pipe_needs_split(usb, pipe)) { > - transaction->retries = 0; > - /* > - * If there is more data to go then we need to try > - * again. Otherwise this transaction is complete > - */ > - if ((buffer_space_left == 0) || > - (bytes_in_last_packet < pipe->max_packet)) > - cvmx_usb_complete(usb, pipe, > - transaction, > - CVMX_USB_STATUS_OK); > - } else { > - /* > - * Split transactions retry the split complete 4 times > - * then rewind to the start split and do the entire > - * transactions again > - */ > - transaction->retries++; > - if ((transaction->retries & 0x3) == 0) { > - /* > - * Rewind to the beginning of the transaction by > - * anding off the split complete bit > - */ > - transaction->stage &= ~1; > - pipe->split_sc_frame = -1; > - } > - } > - } else if (usbc_hcint.s.ack) { > - transaction->retries = 0; > - /* > - * The ACK bit can only be checked after the other error bits. > - * This is because a multi packet transfer may succeed in a > - * number of packets and then get a different response on the > - * last packet. In this case both ACK and the last response bit > - * will be set. If none of the other response bits is set, then > - * the last packet must have been an ACK > - * > - * Since we got an ACK, we know we don't need to do a ping on > - * this pipe > - */ > - pipe->flags &= ~CVMX_USB_PIPE_FLAGS_NEED_PING; > - > - switch (transaction->type) { > - case CVMX_USB_TRANSFER_CONTROL: > - cvmx_usb_transfer_control(usb, pipe, transaction, > - usbc_hcchar, > - buffer_space_left, > - bytes_in_last_packet); > - break; > - case CVMX_USB_TRANSFER_BULK: > - cvmx_usb_transfer_bulk(usb, pipe, transaction, > - usbc_hcint, buffer_space_left, > - bytes_in_last_packet); > - break; > - case CVMX_USB_TRANSFER_INTERRUPT: > - cvmx_usb_transfer_intr(usb, pipe, transaction, > - buffer_space_left, > - bytes_in_last_packet); > - break; > - case CVMX_USB_TRANSFER_ISOCHRONOUS: > - cvmx_usb_transfer_isoc(usb, pipe, transaction, > - buffer_space_left, > - bytes_in_last_packet, > - bytes_this_transfer); > - break; > - } > - } else if (usbc_hcint.s.nak) { > - /* > - * If this was a split then clear our split in progress marker. > - */ > - if (usb->active_split == transaction) > - usb->active_split = NULL; > - /* > - * NAK as a response means the device couldn't accept the > - * transaction, but it should be retried in the future. Rewind > - * to the beginning of the transaction by anding off the split > - * complete bit. Retry in the next interval > - */ > - transaction->retries = 0; > - transaction->stage &= ~1; > - pipe->next_tx_frame += pipe->interval; > - if (pipe->next_tx_frame < usb->frame_number) > - pipe->next_tx_frame = usb->frame_number + > - pipe->interval - > - (usb->frame_number - pipe->next_tx_frame) % > - pipe->interval; > - } else { > - struct cvmx_usb_port_status port; > - > - port = cvmx_usb_get_status(usb); > - if (port.port_enabled) { > - /* We'll retry the exact same transaction again */ > - transaction->retries++; > - } else { > - /* > - * We get channel halted interrupts with no result bits > - * sets when the cable is unplugged > - */ > - cvmx_usb_complete(usb, pipe, transaction, > - CVMX_USB_STATUS_ERROR); > - } > - } > - return 0; > -} > - > -static void octeon_usb_port_callback(struct octeon_hcd *usb) > -{ > - spin_unlock(&usb->lock); > - usb_hcd_poll_rh_status(octeon_to_hcd(usb)); > - spin_lock(&usb->lock); > -} > - > -/** > - * Poll the USB block for status and call all needed callback > - * handlers. This function is meant to be called in the interrupt > - * handler for the USB controller. It can also be called > - * periodically in a loop for non-interrupt based operation. > - * > - * @usb: USB device state populated by cvmx_usb_initialize(). > - * > - * Returns: 0 or a negative error code. > - */ > -static int cvmx_usb_poll(struct octeon_hcd *usb) > -{ > - union cvmx_usbcx_hfnum usbc_hfnum; > - union cvmx_usbcx_gintsts usbc_gintsts; > - > - prefetch_range(usb, sizeof(*usb)); > - > - /* Update the frame counter */ > - usbc_hfnum.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index)); > - if ((usb->frame_number & 0x3fff) > usbc_hfnum.s.frnum) > - usb->frame_number += 0x4000; > - usb->frame_number &= ~0x3fffull; > - usb->frame_number |= usbc_hfnum.s.frnum; > - > - /* Read the pending interrupts */ > - usbc_gintsts.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_GINTSTS(usb->index)); > - > - /* Clear the interrupts now that we know about them */ > - cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index), > - usbc_gintsts.u32); > - > - if (usbc_gintsts.s.rxflvl) { > - /* > - * RxFIFO Non-Empty (RxFLvl) > - * Indicates that there is at least one packet pending to be > - * read from the RxFIFO. > - * > - * In DMA mode this is handled by hardware > - */ > - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) > - cvmx_usb_poll_rx_fifo(usb); > - } > - if (usbc_gintsts.s.ptxfemp || usbc_gintsts.s.nptxfemp) { > - /* Fill the Tx FIFOs when not in DMA mode */ > - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) > - cvmx_usb_poll_tx_fifo(usb); > - } > - if (usbc_gintsts.s.disconnint || usbc_gintsts.s.prtint) { > - union cvmx_usbcx_hprt usbc_hprt; > - /* > - * Disconnect Detected Interrupt (DisconnInt) > - * Asserted when a device disconnect is detected. > - * > - * Host Port Interrupt (PrtInt) > - * The core sets this bit to indicate a change in port status of > - * one of the O2P USB core ports in Host mode. The application > - * must read the Host Port Control and Status (HPRT) register to > - * determine the exact event that caused this interrupt. The > - * application must clear the appropriate status bit in the Host > - * Port Control and Status register to clear this bit. > - * > - * Call the user's port callback > - */ > - octeon_usb_port_callback(usb); > - /* Clear the port change bits */ > - usbc_hprt.u32 = > - cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index)); > - usbc_hprt.s.prtena = 0; > - cvmx_usb_write_csr32(usb, CVMX_USBCX_HPRT(usb->index), > - usbc_hprt.u32); > - } > - if (usbc_gintsts.s.hchint) { > - /* > - * Host Channels Interrupt (HChInt) > - * The core sets this bit to indicate that an interrupt is > - * pending on one of the channels of the core (in Host mode). > - * The application must read the Host All Channels Interrupt > - * (HAINT) register to determine the exact number of the channel > - * on which the interrupt occurred, and then read the > - * corresponding Host Channel-n Interrupt (HCINTn) register to > - * determine the exact cause of the interrupt. The application > - * must clear the appropriate status bit in the HCINTn register > - * to clear this bit. > - */ > - union cvmx_usbcx_haint usbc_haint; > - > - usbc_haint.u32 = cvmx_usb_read_csr32(usb, > - CVMX_USBCX_HAINT(usb->index)); > - while (usbc_haint.u32) { > - int channel; > - > - channel = __fls(usbc_haint.u32); > - cvmx_usb_poll_channel(usb, channel); > - usbc_haint.u32 ^= 1 << channel; > - } > - } > - > - cvmx_usb_schedule(usb, usbc_gintsts.s.sof); > - > - return 0; > -} > - > -/* convert between an HCD pointer and the corresponding struct octeon_hcd */ > -static inline struct octeon_hcd *hcd_to_octeon(struct usb_hcd *hcd) > -{ > - return (struct octeon_hcd *)(hcd->hcd_priv); > -} > - > -static irqreturn_t octeon_usb_irq(struct usb_hcd *hcd) > -{ > - struct octeon_hcd *usb = hcd_to_octeon(hcd); > - unsigned long flags; > - > - spin_lock_irqsave(&usb->lock, flags); > - cvmx_usb_poll(usb); > - spin_unlock_irqrestore(&usb->lock, flags); > - return IRQ_HANDLED; > -} > - > -static int octeon_usb_start(struct usb_hcd *hcd) > -{ > - hcd->state = HC_STATE_RUNNING; > - return 0; > -} > - > -static void octeon_usb_stop(struct usb_hcd *hcd) > -{ > - hcd->state = HC_STATE_HALT; > -} > - > -static int octeon_usb_get_frame_number(struct usb_hcd *hcd) > -{ > - struct octeon_hcd *usb = hcd_to_octeon(hcd); > - > - return cvmx_usb_get_frame_number(usb); > -} > - > -static int octeon_usb_urb_enqueue(struct usb_hcd *hcd, > - struct urb *urb, > - gfp_t mem_flags) > -{ > - struct octeon_hcd *usb = hcd_to_octeon(hcd); > - struct device *dev = hcd->self.controller; > - struct cvmx_usb_transaction *transaction = NULL; > - struct cvmx_usb_pipe *pipe; > - unsigned long flags; > - struct cvmx_usb_iso_packet *iso_packet; > - struct usb_host_endpoint *ep = urb->ep; > - int rc; > - > - urb->status = 0; > - spin_lock_irqsave(&usb->lock, flags); > - > - rc = usb_hcd_link_urb_to_ep(hcd, urb); > - if (rc) { > - spin_unlock_irqrestore(&usb->lock, flags); > - return rc; > - } > - > - if (!ep->hcpriv) { > - enum cvmx_usb_transfer transfer_type; > - enum cvmx_usb_speed speed; > - int split_device = 0; > - int split_port = 0; > - > - switch (usb_pipetype(urb->pipe)) { > - case PIPE_ISOCHRONOUS: > - transfer_type = CVMX_USB_TRANSFER_ISOCHRONOUS; > - break; > - case PIPE_INTERRUPT: > - transfer_type = CVMX_USB_TRANSFER_INTERRUPT; > - break; > - case PIPE_CONTROL: > - transfer_type = CVMX_USB_TRANSFER_CONTROL; > - break; > - default: > - transfer_type = CVMX_USB_TRANSFER_BULK; > - break; > - } > - switch (urb->dev->speed) { > - case USB_SPEED_LOW: > - speed = CVMX_USB_SPEED_LOW; > - break; > - case USB_SPEED_FULL: > - speed = CVMX_USB_SPEED_FULL; > - break; > - default: > - speed = CVMX_USB_SPEED_HIGH; > - break; > - } > - /* > - * For slow devices on high speed ports we need to find the hub > - * that does the speed translation so we know where to send the > - * split transactions. > - */ > - if (speed != CVMX_USB_SPEED_HIGH) { > - /* > - * Start at this device and work our way up the usb > - * tree. > - */ > - struct usb_device *dev = urb->dev; > - > - while (dev->parent) { > - /* > - * If our parent is high speed then he'll > - * receive the splits. > - */ > - if (dev->parent->speed == USB_SPEED_HIGH) { > - split_device = dev->parent->devnum; > - split_port = dev->portnum; > - break; > - } > - /* > - * Move up the tree one level. If we make it all > - * the way up the tree, then the port must not > - * be in high speed mode and we don't need a > - * split. > - */ > - dev = dev->parent; > - } > - } > - pipe = cvmx_usb_open_pipe(usb, usb_pipedevice(urb->pipe), > - usb_pipeendpoint(urb->pipe), speed, > - le16_to_cpu(ep->desc.wMaxPacketSize) > - & 0x7ff, > - transfer_type, > - usb_pipein(urb->pipe) ? > - CVMX_USB_DIRECTION_IN : > - CVMX_USB_DIRECTION_OUT, > - urb->interval, > - (le16_to_cpu(ep->desc.wMaxPacketSize) > - >> 11) & 0x3, > - split_device, split_port); > - if (!pipe) { > - usb_hcd_unlink_urb_from_ep(hcd, urb); > - spin_unlock_irqrestore(&usb->lock, flags); > - dev_dbg(dev, "Failed to create pipe\n"); > - return -ENOMEM; > - } > - ep->hcpriv = pipe; > - } else { > - pipe = ep->hcpriv; > - } > - > - switch (usb_pipetype(urb->pipe)) { > - case PIPE_ISOCHRONOUS: > - dev_dbg(dev, "Submit isochronous to %d.%d\n", > - usb_pipedevice(urb->pipe), > - usb_pipeendpoint(urb->pipe)); > - /* > - * Allocate a structure to use for our private list of > - * isochronous packets. > - */ > - iso_packet = kmalloc_array(urb->number_of_packets, > - sizeof(struct cvmx_usb_iso_packet), > - GFP_ATOMIC); > - if (iso_packet) { > - int i; > - /* Fill the list with the data from the URB */ > - for (i = 0; i < urb->number_of_packets; i++) { > - iso_packet[i].offset = > - urb->iso_frame_desc[i].offset; > - iso_packet[i].length = > - urb->iso_frame_desc[i].length; > - iso_packet[i].status = CVMX_USB_STATUS_ERROR; > - } > - /* > - * Store a pointer to the list in the URB setup_packet > - * field. We know this currently isn't being used and > - * this saves us a bunch of logic. > - */ > - urb->setup_packet = (char *)iso_packet; > - transaction = cvmx_usb_submit_isochronous(usb, > - pipe, urb); > - /* > - * If submit failed we need to free our private packet > - * list. > - */ > - if (!transaction) { > - urb->setup_packet = NULL; > - kfree(iso_packet); > - } > - } > - break; > - case PIPE_INTERRUPT: > - dev_dbg(dev, "Submit interrupt to %d.%d\n", > - usb_pipedevice(urb->pipe), > - usb_pipeendpoint(urb->pipe)); > - transaction = cvmx_usb_submit_interrupt(usb, pipe, urb); > - break; > - case PIPE_CONTROL: > - dev_dbg(dev, "Submit control to %d.%d\n", > - usb_pipedevice(urb->pipe), > - usb_pipeendpoint(urb->pipe)); > - transaction = cvmx_usb_submit_control(usb, pipe, urb); > - break; > - case PIPE_BULK: > - dev_dbg(dev, "Submit bulk to %d.%d\n", > - usb_pipedevice(urb->pipe), > - usb_pipeendpoint(urb->pipe)); > - transaction = cvmx_usb_submit_bulk(usb, pipe, urb); > - break; > - } > - if (!transaction) { > - usb_hcd_unlink_urb_from_ep(hcd, urb); > - spin_unlock_irqrestore(&usb->lock, flags); > - dev_dbg(dev, "Failed to submit\n"); > - return -ENOMEM; > - } > - urb->hcpriv = transaction; > - spin_unlock_irqrestore(&usb->lock, flags); > - return 0; > -} > - > -static int octeon_usb_urb_dequeue(struct usb_hcd *hcd, > - struct urb *urb, > - int status) > -{ > - struct octeon_hcd *usb = hcd_to_octeon(hcd); > - unsigned long flags; > - int rc; > - > - if (!urb->dev) > - return -EINVAL; > - > - spin_lock_irqsave(&usb->lock, flags); > - > - rc = usb_hcd_check_unlink_urb(hcd, urb, status); > - if (rc) > - goto out; > - > - urb->status = status; > - cvmx_usb_cancel(usb, urb->ep->hcpriv, urb->hcpriv); > - > -out: > - spin_unlock_irqrestore(&usb->lock, flags); > - > - return rc; > -} > - > -static void octeon_usb_endpoint_disable(struct usb_hcd *hcd, > - struct usb_host_endpoint *ep) > -{ > - struct device *dev = hcd->self.controller; > - > - if (ep->hcpriv) { > - struct octeon_hcd *usb = hcd_to_octeon(hcd); > - struct cvmx_usb_pipe *pipe = ep->hcpriv; > - unsigned long flags; > - > - spin_lock_irqsave(&usb->lock, flags); > - cvmx_usb_cancel_all(usb, pipe); > - if (cvmx_usb_close_pipe(usb, pipe)) > - dev_dbg(dev, "Closing pipe %p failed\n", pipe); > - spin_unlock_irqrestore(&usb->lock, flags); > - ep->hcpriv = NULL; > - } > -} > - > -static int octeon_usb_hub_status_data(struct usb_hcd *hcd, char *buf) > -{ > - struct octeon_hcd *usb = hcd_to_octeon(hcd); > - struct cvmx_usb_port_status port_status; > - unsigned long flags; > - > - spin_lock_irqsave(&usb->lock, flags); > - port_status = cvmx_usb_get_status(usb); > - spin_unlock_irqrestore(&usb->lock, flags); > - buf[0] = port_status.connect_change << 1; > - > - return buf[0] != 0; > -} > - > -static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, > - u16 wIndex, char *buf, u16 wLength) > -{ > - struct octeon_hcd *usb = hcd_to_octeon(hcd); > - struct device *dev = hcd->self.controller; > - struct cvmx_usb_port_status usb_port_status; > - int port_status; > - struct usb_hub_descriptor *desc; > - unsigned long flags; > - > - switch (typeReq) { > - case ClearHubFeature: > - dev_dbg(dev, "ClearHubFeature\n"); > - switch (wValue) { > - case C_HUB_LOCAL_POWER: > - case C_HUB_OVER_CURRENT: > - /* Nothing required here */ > - break; > - default: > - return -EINVAL; > - } > - break; > - case ClearPortFeature: > - dev_dbg(dev, "ClearPortFeature\n"); > - if (wIndex != 1) { > - dev_dbg(dev, " INVALID\n"); > - return -EINVAL; > - } > - > - switch (wValue) { > - case USB_PORT_FEAT_ENABLE: > - dev_dbg(dev, " ENABLE\n"); > - spin_lock_irqsave(&usb->lock, flags); > - cvmx_usb_disable(usb); > - spin_unlock_irqrestore(&usb->lock, flags); > - break; > - case USB_PORT_FEAT_SUSPEND: > - dev_dbg(dev, " SUSPEND\n"); > - /* Not supported on Octeon */ > - break; > - case USB_PORT_FEAT_POWER: > - dev_dbg(dev, " POWER\n"); > - /* Not supported on Octeon */ > - break; > - case USB_PORT_FEAT_INDICATOR: > - dev_dbg(dev, " INDICATOR\n"); > - /* Port inidicator not supported */ > - break; > - case USB_PORT_FEAT_C_CONNECTION: > - dev_dbg(dev, " C_CONNECTION\n"); > - /* Clears drivers internal connect status change flag */ > - spin_lock_irqsave(&usb->lock, flags); > - usb->port_status = cvmx_usb_get_status(usb); > - spin_unlock_irqrestore(&usb->lock, flags); > - break; > - case USB_PORT_FEAT_C_RESET: > - dev_dbg(dev, " C_RESET\n"); > - /* > - * Clears the driver's internal Port Reset Change flag. > - */ > - spin_lock_irqsave(&usb->lock, flags); > - usb->port_status = cvmx_usb_get_status(usb); > - spin_unlock_irqrestore(&usb->lock, flags); > - break; > - case USB_PORT_FEAT_C_ENABLE: > - dev_dbg(dev, " C_ENABLE\n"); > - /* > - * Clears the driver's internal Port Enable/Disable > - * Change flag. > - */ > - spin_lock_irqsave(&usb->lock, flags); > - usb->port_status = cvmx_usb_get_status(usb); > - spin_unlock_irqrestore(&usb->lock, flags); > - break; > - case USB_PORT_FEAT_C_SUSPEND: > - dev_dbg(dev, " C_SUSPEND\n"); > - /* > - * Clears the driver's internal Port Suspend Change > - * flag, which is set when resume signaling on the host > - * port is complete. > - */ > - break; > - case USB_PORT_FEAT_C_OVER_CURRENT: > - dev_dbg(dev, " C_OVER_CURRENT\n"); > - /* Clears the driver's overcurrent Change flag */ > - spin_lock_irqsave(&usb->lock, flags); > - usb->port_status = cvmx_usb_get_status(usb); > - spin_unlock_irqrestore(&usb->lock, flags); > - break; > - default: > - dev_dbg(dev, " UNKNOWN\n"); > - return -EINVAL; > - } > - break; > - case GetHubDescriptor: > - dev_dbg(dev, "GetHubDescriptor\n"); > - desc = (struct usb_hub_descriptor *)buf; > - desc->bDescLength = 9; > - desc->bDescriptorType = 0x29; > - desc->bNbrPorts = 1; > - desc->wHubCharacteristics = cpu_to_le16(0x08); > - desc->bPwrOn2PwrGood = 1; > - desc->bHubContrCurrent = 0; > - desc->u.hs.DeviceRemovable[0] = 0; > - desc->u.hs.DeviceRemovable[1] = 0xff; > - break; > - case GetHubStatus: > - dev_dbg(dev, "GetHubStatus\n"); > - *(__le32 *)buf = 0; > - break; > - case GetPortStatus: > - dev_dbg(dev, "GetPortStatus\n"); > - if (wIndex != 1) { > - dev_dbg(dev, " INVALID\n"); > - return -EINVAL; > - } > - > - spin_lock_irqsave(&usb->lock, flags); > - usb_port_status = cvmx_usb_get_status(usb); > - spin_unlock_irqrestore(&usb->lock, flags); > - port_status = 0; > - > - if (usb_port_status.connect_change) { > - port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); > - dev_dbg(dev, " C_CONNECTION\n"); > - } > - > - if (usb_port_status.port_enabled) { > - port_status |= (1 << USB_PORT_FEAT_C_ENABLE); > - dev_dbg(dev, " C_ENABLE\n"); > - } > - > - if (usb_port_status.connected) { > - port_status |= (1 << USB_PORT_FEAT_CONNECTION); > - dev_dbg(dev, " CONNECTION\n"); > - } > - > - if (usb_port_status.port_enabled) { > - port_status |= (1 << USB_PORT_FEAT_ENABLE); > - dev_dbg(dev, " ENABLE\n"); > - } > - > - if (usb_port_status.port_over_current) { > - port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT); > - dev_dbg(dev, " OVER_CURRENT\n"); > - } > - > - if (usb_port_status.port_powered) { > - port_status |= (1 << USB_PORT_FEAT_POWER); > - dev_dbg(dev, " POWER\n"); > - } > - > - if (usb_port_status.port_speed == CVMX_USB_SPEED_HIGH) { > - port_status |= USB_PORT_STAT_HIGH_SPEED; > - dev_dbg(dev, " HIGHSPEED\n"); > - } else if (usb_port_status.port_speed == CVMX_USB_SPEED_LOW) { > - port_status |= (1 << USB_PORT_FEAT_LOWSPEED); > - dev_dbg(dev, " LOWSPEED\n"); > - } > - > - *((__le32 *)buf) = cpu_to_le32(port_status); > - break; > - case SetHubFeature: > - dev_dbg(dev, "SetHubFeature\n"); > - /* No HUB features supported */ > - break; > - case SetPortFeature: > - dev_dbg(dev, "SetPortFeature\n"); > - if (wIndex != 1) { > - dev_dbg(dev, " INVALID\n"); > - return -EINVAL; > - } > - > - switch (wValue) { > - case USB_PORT_FEAT_SUSPEND: > - dev_dbg(dev, " SUSPEND\n"); > - return -EINVAL; > - case USB_PORT_FEAT_POWER: > - dev_dbg(dev, " POWER\n"); > - /* > - * Program the port power bit to drive VBUS on the USB. > - */ > - spin_lock_irqsave(&usb->lock, flags); > - USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), > - cvmx_usbcx_hprt, prtpwr, 1); > - spin_unlock_irqrestore(&usb->lock, flags); > - return 0; > - case USB_PORT_FEAT_RESET: > - dev_dbg(dev, " RESET\n"); > - spin_lock_irqsave(&usb->lock, flags); > - cvmx_usb_reset_port(usb); > - spin_unlock_irqrestore(&usb->lock, flags); > - return 0; > - case USB_PORT_FEAT_INDICATOR: > - dev_dbg(dev, " INDICATOR\n"); > - /* Not supported */ > - break; > - default: > - dev_dbg(dev, " UNKNOWN\n"); > - return -EINVAL; > - } > - break; > - default: > - dev_dbg(dev, "Unknown root hub request\n"); > - return -EINVAL; > - } > - return 0; > -} > - > -static const struct hc_driver octeon_hc_driver = { > - .description = "Octeon USB", > - .product_desc = "Octeon Host Controller", > - .hcd_priv_size = sizeof(struct octeon_hcd), > - .irq = octeon_usb_irq, > - .flags = HCD_MEMORY | HCD_DMA | HCD_USB2, > - .start = octeon_usb_start, > - .stop = octeon_usb_stop, > - .urb_enqueue = octeon_usb_urb_enqueue, > - .urb_dequeue = octeon_usb_urb_dequeue, > - .endpoint_disable = octeon_usb_endpoint_disable, > - .get_frame_number = octeon_usb_get_frame_number, > - .hub_status_data = octeon_usb_hub_status_data, > - .hub_control = octeon_usb_hub_control, > - .map_urb_for_dma = octeon_map_urb_for_dma, > - .unmap_urb_for_dma = octeon_unmap_urb_for_dma, > -}; > - > -static int octeon_usb_probe(struct platform_device *pdev) > -{ > - int status; > - int initialize_flags; > - int usb_num; > - struct resource *res_mem; > - struct device_node *usbn_node; > - int irq = platform_get_irq(pdev, 0); > - struct device *dev = &pdev->dev; > - struct octeon_hcd *usb; > - struct usb_hcd *hcd; > - u32 clock_rate = 48000000; > - bool is_crystal_clock = false; > - const char *clock_type; > - int i; > - > - if (!dev->of_node) { > - dev_err(dev, "Error: empty of_node\n"); > - return -ENXIO; > - } > - usbn_node = dev->of_node->parent; > - > - i = of_property_read_u32(usbn_node, > - "clock-frequency", &clock_rate); > - if (i) > - i = of_property_read_u32(usbn_node, > - "refclk-frequency", &clock_rate); > - if (i) { > - dev_err(dev, "No USBN \"clock-frequency\"\n"); > - return -ENXIO; > - } > - switch (clock_rate) { > - case 12000000: > - initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ; > - break; > - case 24000000: > - initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ; > - break; > - case 48000000: > - initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ; > - break; > - default: > - dev_err(dev, "Illegal USBN \"clock-frequency\" %u\n", > - clock_rate); > - return -ENXIO; > - } > - > - i = of_property_read_string(usbn_node, > - "cavium,refclk-type", &clock_type); > - if (i) > - i = of_property_read_string(usbn_node, > - "refclk-type", &clock_type); > - > - if (!i && strcmp("crystal", clock_type) == 0) > - is_crystal_clock = true; > - > - if (is_crystal_clock) > - initialize_flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI; > - else > - initialize_flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND; > - > - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); > - if (!res_mem) { > - dev_err(dev, "found no memory resource\n"); > - return -ENXIO; > - } > - usb_num = (res_mem->start >> 44) & 1; > - > - if (irq < 0) { > - /* Defective device tree, but we know how to fix it. */ > - irq_hw_number_t hwirq = usb_num ? (1 << 6) + 17 : 56; > - > - irq = irq_create_mapping(NULL, hwirq); > - } > - > - /* > - * Set the DMA mask to 64bits so we get buffers already translated for > - * DMA. > - */ > - i = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); > - if (i) > - return i; > - > - /* > - * Only cn52XX and cn56XX have DWC_OTG USB hardware and the > - * IOB priority registers. Under heavy network load USB > - * hardware can be starved by the IOB causing a crash. Give > - * it a priority boost if it has been waiting more than 400 > - * cycles to avoid this situation. > - * > - * Testing indicates that a cnt_val of 8192 is not sufficient, > - * but no failures are seen with 4096. We choose a value of > - * 400 to give a safety factor of 10. > - */ > - if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) { > - union cvmx_iob_n2c_l2c_pri_cnt pri_cnt; > - > - pri_cnt.u64 = 0; > - pri_cnt.s.cnt_enb = 1; > - pri_cnt.s.cnt_val = 400; > - cvmx_write_csr(CVMX_IOB_N2C_L2C_PRI_CNT, pri_cnt.u64); > - } > - > - hcd = usb_create_hcd(&octeon_hc_driver, dev, dev_name(dev)); > - if (!hcd) { > - dev_dbg(dev, "Failed to allocate memory for HCD\n"); > - return -1; > - } > - hcd->uses_new_polling = 1; > - usb = (struct octeon_hcd *)hcd->hcd_priv; > - > - spin_lock_init(&usb->lock); > - > - usb->init_flags = initialize_flags; > - > - /* Initialize the USB state structure */ > - usb->index = usb_num; > - INIT_LIST_HEAD(&usb->idle_pipes); > - for (i = 0; i < ARRAY_SIZE(usb->active_pipes); i++) > - INIT_LIST_HEAD(&usb->active_pipes[i]); > - > - /* Due to an errata, CN31XX doesn't support DMA */ > - if (OCTEON_IS_MODEL(OCTEON_CN31XX)) { > - usb->init_flags |= CVMX_USB_INITIALIZE_FLAGS_NO_DMA; > - /* Only use one channel with non DMA */ > - usb->idle_hardware_channels = 0x1; > - } else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) { > - /* CN5XXX have an errata with channel 3 */ > - usb->idle_hardware_channels = 0xf7; > - } else { > - usb->idle_hardware_channels = 0xff; > - } > - > - status = cvmx_usb_initialize(dev, usb); > - if (status) { > - dev_dbg(dev, "USB initialization failed with %d\n", status); > - usb_put_hcd(hcd); > - return -1; > - } > - > - status = usb_add_hcd(hcd, irq, 0); > - if (status) { > - dev_dbg(dev, "USB add HCD failed with %d\n", status); > - usb_put_hcd(hcd); > - return -1; > - } > - device_wakeup_enable(hcd->self.controller); > - > - dev_info(dev, "Registered HCD for port %d on irq %d\n", usb_num, irq); > - > - return 0; > -} > - > -static int octeon_usb_remove(struct platform_device *pdev) > -{ > - int status; > - struct device *dev = &pdev->dev; > - struct usb_hcd *hcd = dev_get_drvdata(dev); > - struct octeon_hcd *usb = hcd_to_octeon(hcd); > - unsigned long flags; > - > - usb_remove_hcd(hcd); > - spin_lock_irqsave(&usb->lock, flags); > - status = cvmx_usb_shutdown(usb); > - spin_unlock_irqrestore(&usb->lock, flags); > - if (status) > - dev_dbg(dev, "USB shutdown failed with %d\n", status); > - > - usb_put_hcd(hcd); > - > - return 0; > -} > - > -static const struct of_device_id octeon_usb_match[] = { > - { > - .compatible = "cavium,octeon-5750-usbc", > - }, > - {}, > -}; > -MODULE_DEVICE_TABLE(of, octeon_usb_match); > - > -static struct platform_driver octeon_usb_driver = { > - .driver = { > - .name = "octeon-hcd", > - .of_match_table = octeon_usb_match, > - }, > - .probe = octeon_usb_probe, > - .remove = octeon_usb_remove, > -}; > - > -static int __init octeon_usb_driver_init(void) > -{ > - if (usb_disabled()) > - return 0; > - > - return platform_driver_register(&octeon_usb_driver); > -} > -module_init(octeon_usb_driver_init); > - > -static void __exit octeon_usb_driver_exit(void) > -{ > - if (usb_disabled()) > - return; > - > - platform_driver_unregister(&octeon_usb_driver); > -} > -module_exit(octeon_usb_driver_exit); > - > -MODULE_LICENSE("GPL"); > -MODULE_AUTHOR("Cavium, Inc. <support@xxxxxxxxxx>"); > -MODULE_DESCRIPTION("Cavium Inc. OCTEON USB Host driver."); > diff --git a/drivers/staging/octeon-usb/octeon-hcd.h b/drivers/staging/octeon-usb/octeon-hcd.h > deleted file mode 100644 > index 9ed619c93a4e..000000000000 > --- a/drivers/staging/octeon-usb/octeon-hcd.h > +++ /dev/null > @@ -1,1847 +0,0 @@ > -/* SPDX-License-Identifier: GPL-2.0 */ > -/* > - * Octeon HCD hardware register definitions. > - * > - * This file is subject to the terms and conditions of the GNU General Public > - * License. See the file "COPYING" in the main directory of this archive > - * for more details. > - * > - * Some parts of the code were originally released under BSD license: > - * > - * Copyright (c) 2003-2010 Cavium Networks (support@xxxxxxxxxx). All rights > - * reserved. > - * > - * Redistribution and use in source and binary forms, with or without > - * modification, are permitted provided that the following conditions are > - * met: > - * > - * * Redistributions of source code must retain the above copyright > - * notice, this list of conditions and the following disclaimer. > - * > - * * Redistributions in binary form must reproduce the above > - * copyright notice, this list of conditions and the following > - * disclaimer in the documentation and/or other materials provided > - * with the distribution. > - * > - * * Neither the name of Cavium Networks nor the names of > - * its contributors may be used to endorse or promote products > - * derived from this software without specific prior written > - * permission. > - * > - * This Software, including technical data, may be subject to U.S. export > - * control laws, including the U.S. Export Administration Act and its associated > - * regulations, and may be subject to export or import regulations in other > - * countries. > - * > - * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" > - * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR > - * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO > - * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION > - * OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM > - * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, > - * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF > - * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR > - * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR > - * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. > - */ > - > -#ifndef __OCTEON_HCD_H__ > -#define __OCTEON_HCD_H__ > - > -#include <asm/bitfield.h> > - > -#define CVMX_USBCXBASE 0x00016F0010000000ull > -#define CVMX_USBCXREG1(reg, bid) \ > - (CVMX_ADD_IO_SEG(CVMX_USBCXBASE | reg) + \ > - ((bid) & 1) * 0x100000000000ull) > -#define CVMX_USBCXREG2(reg, bid, off) \ > - (CVMX_ADD_IO_SEG(CVMX_USBCXBASE | reg) + \ > - (((off) & 7) + ((bid) & 1) * 0x8000000000ull) * 32) > - > -#define CVMX_USBCX_GAHBCFG(bid) CVMX_USBCXREG1(0x008, bid) > -#define CVMX_USBCX_GHWCFG3(bid) CVMX_USBCXREG1(0x04c, bid) > -#define CVMX_USBCX_GINTMSK(bid) CVMX_USBCXREG1(0x018, bid) > -#define CVMX_USBCX_GINTSTS(bid) CVMX_USBCXREG1(0x014, bid) > -#define CVMX_USBCX_GNPTXFSIZ(bid) CVMX_USBCXREG1(0x028, bid) > -#define CVMX_USBCX_GNPTXSTS(bid) CVMX_USBCXREG1(0x02c, bid) > -#define CVMX_USBCX_GOTGCTL(bid) CVMX_USBCXREG1(0x000, bid) > -#define CVMX_USBCX_GRSTCTL(bid) CVMX_USBCXREG1(0x010, bid) > -#define CVMX_USBCX_GRXFSIZ(bid) CVMX_USBCXREG1(0x024, bid) > -#define CVMX_USBCX_GRXSTSPH(bid) CVMX_USBCXREG1(0x020, bid) > -#define CVMX_USBCX_GUSBCFG(bid) CVMX_USBCXREG1(0x00c, bid) > -#define CVMX_USBCX_HAINT(bid) CVMX_USBCXREG1(0x414, bid) > -#define CVMX_USBCX_HAINTMSK(bid) CVMX_USBCXREG1(0x418, bid) > -#define CVMX_USBCX_HCCHARX(off, bid) CVMX_USBCXREG2(0x500, bid, off) > -#define CVMX_USBCX_HCFG(bid) CVMX_USBCXREG1(0x400, bid) > -#define CVMX_USBCX_HCINTMSKX(off, bid) CVMX_USBCXREG2(0x50c, bid, off) > -#define CVMX_USBCX_HCINTX(off, bid) CVMX_USBCXREG2(0x508, bid, off) > -#define CVMX_USBCX_HCSPLTX(off, bid) CVMX_USBCXREG2(0x504, bid, off) > -#define CVMX_USBCX_HCTSIZX(off, bid) CVMX_USBCXREG2(0x510, bid, off) > -#define CVMX_USBCX_HFIR(bid) CVMX_USBCXREG1(0x404, bid) > -#define CVMX_USBCX_HFNUM(bid) CVMX_USBCXREG1(0x408, bid) > -#define CVMX_USBCX_HPRT(bid) CVMX_USBCXREG1(0x440, bid) > -#define CVMX_USBCX_HPTXFSIZ(bid) CVMX_USBCXREG1(0x100, bid) > -#define CVMX_USBCX_HPTXSTS(bid) CVMX_USBCXREG1(0x410, bid) > - > -#define CVMX_USBNXBID1(bid) (((bid) & 1) * 0x10000000ull) > -#define CVMX_USBNXBID2(bid) (((bid) & 1) * 0x100000000000ull) > - > -#define CVMX_USBNXREG1(reg, bid) \ > - (CVMX_ADD_IO_SEG(0x0001180068000000ull | reg) + CVMX_USBNXBID1(bid)) > -#define CVMX_USBNXREG2(reg, bid) \ > - (CVMX_ADD_IO_SEG(0x00016F0000000000ull | reg) + CVMX_USBNXBID2(bid)) > - > -#define CVMX_USBNX_CLK_CTL(bid) CVMX_USBNXREG1(0x10, bid) > -#define CVMX_USBNX_DMA0_INB_CHN0(bid) CVMX_USBNXREG2(0x818, bid) > -#define CVMX_USBNX_DMA0_OUTB_CHN0(bid) CVMX_USBNXREG2(0x858, bid) > -#define CVMX_USBNX_USBP_CTL_STATUS(bid) CVMX_USBNXREG1(0x18, bid) > - > -/** > - * cvmx_usbc#_gahbcfg > - * > - * Core AHB Configuration Register (GAHBCFG) > - * > - * This register can be used to configure the core after power-on or a change in > - * mode of operation. This register mainly contains AHB system-related > - * configuration parameters. The AHB is the processor interface to the O2P USB > - * core. In general, software need not know about this interface except to > - * program the values as specified. > - * > - * The application must program this register as part of the O2P USB core > - * initialization. Do not change this register after the initial programming. > - */ > -union cvmx_usbcx_gahbcfg { > - u32 u32; > - /** > - * struct cvmx_usbcx_gahbcfg_s > - * @ptxfemplvl: Periodic TxFIFO Empty Level (PTxFEmpLvl) > - * Software should set this bit to 0x1. > - * Indicates when the Periodic TxFIFO Empty Interrupt bit in the > - * Core Interrupt register (GINTSTS.PTxFEmp) is triggered. This > - * bit is used only in Slave mode. > - * * 1'b0: GINTSTS.PTxFEmp interrupt indicates that the Periodic > - * TxFIFO is half empty > - * * 1'b1: GINTSTS.PTxFEmp interrupt indicates that the Periodic > - * TxFIFO is completely empty > - * @nptxfemplvl: Non-Periodic TxFIFO Empty Level (NPTxFEmpLvl) > - * Software should set this bit to 0x1. > - * Indicates when the Non-Periodic TxFIFO Empty Interrupt bit in > - * the Core Interrupt register (GINTSTS.NPTxFEmp) is triggered. > - * This bit is used only in Slave mode. > - * * 1'b0: GINTSTS.NPTxFEmp interrupt indicates that the Non- > - * Periodic TxFIFO is half empty > - * * 1'b1: GINTSTS.NPTxFEmp interrupt indicates that the Non- > - * Periodic TxFIFO is completely empty > - * @dmaen: DMA Enable (DMAEn) > - * * 1'b0: Core operates in Slave mode > - * * 1'b1: Core operates in a DMA mode > - * @hbstlen: Burst Length/Type (HBstLen) > - * This field has not effect and should be left as 0x0. > - * @glblintrmsk: Global Interrupt Mask (GlblIntrMsk) > - * Software should set this field to 0x1. > - * The application uses this bit to mask or unmask the interrupt > - * line assertion to itself. Irrespective of this bit's setting, > - * the interrupt status registers are updated by the core. > - * * 1'b0: Mask the interrupt assertion to the application. > - * * 1'b1: Unmask the interrupt assertion to the application. > - */ > - struct cvmx_usbcx_gahbcfg_s { > - __BITFIELD_FIELD(u32 reserved_9_31 : 23, > - __BITFIELD_FIELD(u32 ptxfemplvl : 1, > - __BITFIELD_FIELD(u32 nptxfemplvl : 1, > - __BITFIELD_FIELD(u32 reserved_6_6 : 1, > - __BITFIELD_FIELD(u32 dmaen : 1, > - __BITFIELD_FIELD(u32 hbstlen : 4, > - __BITFIELD_FIELD(u32 glblintrmsk : 1, > - ;))))))) > - } s; > -}; > - > -/** > - * cvmx_usbc#_ghwcfg3 > - * > - * User HW Config3 Register (GHWCFG3) > - * > - * This register contains the configuration options of the O2P USB core. > - */ > -union cvmx_usbcx_ghwcfg3 { > - u32 u32; > - /** > - * struct cvmx_usbcx_ghwcfg3_s > - * @dfifodepth: DFIFO Depth (DfifoDepth) > - * This value is in terms of 32-bit words. > - * * Minimum value is 32 > - * * Maximum value is 32768 > - * @ahbphysync: AHB and PHY Synchronous (AhbPhySync) > - * Indicates whether AHB and PHY clocks are synchronous to > - * each other. > - * * 1'b0: No > - * * 1'b1: Yes > - * This bit is tied to 1. > - * @rsttype: Reset Style for Clocked always Blocks in RTL (RstType) > - * * 1'b0: Asynchronous reset is used in the core > - * * 1'b1: Synchronous reset is used in the core > - * @optfeature: Optional Features Removed (OptFeature) > - * Indicates whether the User ID register, GPIO interface ports, > - * and SOF toggle and counter ports were removed for gate count > - * optimization. > - * @vendor_control_interface_support: Vendor Control Interface Support > - * * 1'b0: Vendor Control Interface is not available on the core. > - * * 1'b1: Vendor Control Interface is available. > - * @i2c_selection: I2C Selection > - * * 1'b0: I2C Interface is not available on the core. > - * * 1'b1: I2C Interface is available on the core. > - * @otgen: OTG Function Enabled (OtgEn) > - * The application uses this bit to indicate the O2P USB core's > - * OTG capabilities. > - * * 1'b0: Not OTG capable > - * * 1'b1: OTG Capable > - * @pktsizewidth: Width of Packet Size Counters (PktSizeWidth) > - * * 3'b000: 4 bits > - * * 3'b001: 5 bits > - * * 3'b010: 6 bits > - * * 3'b011: 7 bits > - * * 3'b100: 8 bits > - * * 3'b101: 9 bits > - * * 3'b110: 10 bits > - * * Others: Reserved > - * @xfersizewidth: Width of Transfer Size Counters (XferSizeWidth) > - * * 4'b0000: 11 bits > - * * 4'b0001: 12 bits > - * - ... > - * * 4'b1000: 19 bits > - * * Others: Reserved > - */ > - struct cvmx_usbcx_ghwcfg3_s { > - __BITFIELD_FIELD(u32 dfifodepth : 16, > - __BITFIELD_FIELD(u32 reserved_13_15 : 3, > - __BITFIELD_FIELD(u32 ahbphysync : 1, > - __BITFIELD_FIELD(u32 rsttype : 1, > - __BITFIELD_FIELD(u32 optfeature : 1, > - __BITFIELD_FIELD(u32 vendor_control_interface_support : 1, > - __BITFIELD_FIELD(u32 i2c_selection : 1, > - __BITFIELD_FIELD(u32 otgen : 1, > - __BITFIELD_FIELD(u32 pktsizewidth : 3, > - __BITFIELD_FIELD(u32 xfersizewidth : 4, > - ;)))))))))) > - } s; > -}; > - > -/** > - * cvmx_usbc#_gintmsk > - * > - * Core Interrupt Mask Register (GINTMSK) > - * > - * This register works with the Core Interrupt register to interrupt the > - * application. When an interrupt bit is masked, the interrupt associated with > - * that bit will not be generated. However, the Core Interrupt (GINTSTS) > - * register bit corresponding to that interrupt will still be set. > - * Mask interrupt: 1'b0, Unmask interrupt: 1'b1 > - */ > -union cvmx_usbcx_gintmsk { > - u32 u32; > - /** > - * struct cvmx_usbcx_gintmsk_s > - * @wkupintmsk: Resume/Remote Wakeup Detected Interrupt Mask > - * (WkUpIntMsk) > - * @sessreqintmsk: Session Request/New Session Detected Interrupt Mask > - * (SessReqIntMsk) > - * @disconnintmsk: Disconnect Detected Interrupt Mask (DisconnIntMsk) > - * @conidstschngmsk: Connector ID Status Change Mask (ConIDStsChngMsk) > - * @ptxfempmsk: Periodic TxFIFO Empty Mask (PTxFEmpMsk) > - * @hchintmsk: Host Channels Interrupt Mask (HChIntMsk) > - * @prtintmsk: Host Port Interrupt Mask (PrtIntMsk) > - * @fetsuspmsk: Data Fetch Suspended Mask (FetSuspMsk) > - * @incomplpmsk: Incomplete Periodic Transfer Mask (incomplPMsk) > - * Incomplete Isochronous OUT Transfer Mask > - * (incompISOOUTMsk) > - * @incompisoinmsk: Incomplete Isochronous IN Transfer Mask > - * (incompISOINMsk) > - * @oepintmsk: OUT Endpoints Interrupt Mask (OEPIntMsk) > - * @inepintmsk: IN Endpoints Interrupt Mask (INEPIntMsk) > - * @epmismsk: Endpoint Mismatch Interrupt Mask (EPMisMsk) > - * @eopfmsk: End of Periodic Frame Interrupt Mask (EOPFMsk) > - * @isooutdropmsk: Isochronous OUT Packet Dropped Interrupt Mask > - * (ISOOutDropMsk) > - * @enumdonemsk: Enumeration Done Mask (EnumDoneMsk) > - * @usbrstmsk: USB Reset Mask (USBRstMsk) > - * @usbsuspmsk: USB Suspend Mask (USBSuspMsk) > - * @erlysuspmsk: Early Suspend Mask (ErlySuspMsk) > - * @i2cint: I2C Interrupt Mask (I2CINT) > - * @ulpickintmsk: ULPI Carkit Interrupt Mask (ULPICKINTMsk) > - * I2C Carkit Interrupt Mask (I2CCKINTMsk) > - * @goutnakeffmsk: Global OUT NAK Effective Mask (GOUTNakEffMsk) > - * @ginnakeffmsk: Global Non-Periodic IN NAK Effective Mask > - * (GINNakEffMsk) > - * @nptxfempmsk: Non-Periodic TxFIFO Empty Mask (NPTxFEmpMsk) > - * @rxflvlmsk: Receive FIFO Non-Empty Mask (RxFLvlMsk) > - * @sofmsk: Start of (micro)Frame Mask (SofMsk) > - * @otgintmsk: OTG Interrupt Mask (OTGIntMsk) > - * @modemismsk: Mode Mismatch Interrupt Mask (ModeMisMsk) > - */ > - struct cvmx_usbcx_gintmsk_s { > - __BITFIELD_FIELD(u32 wkupintmsk : 1, > - __BITFIELD_FIELD(u32 sessreqintmsk : 1, > - __BITFIELD_FIELD(u32 disconnintmsk : 1, > - __BITFIELD_FIELD(u32 conidstschngmsk : 1, > - __BITFIELD_FIELD(u32 reserved_27_27 : 1, > - __BITFIELD_FIELD(u32 ptxfempmsk : 1, > - __BITFIELD_FIELD(u32 hchintmsk : 1, > - __BITFIELD_FIELD(u32 prtintmsk : 1, > - __BITFIELD_FIELD(u32 reserved_23_23 : 1, > - __BITFIELD_FIELD(u32 fetsuspmsk : 1, > - __BITFIELD_FIELD(u32 incomplpmsk : 1, > - __BITFIELD_FIELD(u32 incompisoinmsk : 1, > - __BITFIELD_FIELD(u32 oepintmsk : 1, > - __BITFIELD_FIELD(u32 inepintmsk : 1, > - __BITFIELD_FIELD(u32 epmismsk : 1, > - __BITFIELD_FIELD(u32 reserved_16_16 : 1, > - __BITFIELD_FIELD(u32 eopfmsk : 1, > - __BITFIELD_FIELD(u32 isooutdropmsk : 1, > - __BITFIELD_FIELD(u32 enumdonemsk : 1, > - __BITFIELD_FIELD(u32 usbrstmsk : 1, > - __BITFIELD_FIELD(u32 usbsuspmsk : 1, > - __BITFIELD_FIELD(u32 erlysuspmsk : 1, > - __BITFIELD_FIELD(u32 i2cint : 1, > - __BITFIELD_FIELD(u32 ulpickintmsk : 1, > - __BITFIELD_FIELD(u32 goutnakeffmsk : 1, > - __BITFIELD_FIELD(u32 ginnakeffmsk : 1, > - __BITFIELD_FIELD(u32 nptxfempmsk : 1, > - __BITFIELD_FIELD(u32 rxflvlmsk : 1, > - __BITFIELD_FIELD(u32 sofmsk : 1, > - __BITFIELD_FIELD(u32 otgintmsk : 1, > - __BITFIELD_FIELD(u32 modemismsk : 1, > - __BITFIELD_FIELD(u32 reserved_0_0 : 1, > - ;)))))))))))))))))))))))))))))))) > - } s; > -}; > - > -/** > - * cvmx_usbc#_gintsts > - * > - * Core Interrupt Register (GINTSTS) > - * > - * This register interrupts the application for system-level events in the > - * current mode of operation (Device mode or Host mode). It is shown in > - * Interrupt. Some of the bits in this register are valid only in Host mode, > - * while others are valid in Device mode only. This register also indicates the > - * current mode of operation. In order to clear the interrupt status bits of > - * type R_SS_WC, the application must write 1'b1 into the bit. The FIFO status > - * interrupts are read only; once software reads from or writes to the FIFO > - * while servicing these interrupts, FIFO interrupt conditions are cleared > - * automatically. > - */ > -union cvmx_usbcx_gintsts { > - u32 u32; > - /** > - * struct cvmx_usbcx_gintsts_s > - * @wkupint: Resume/Remote Wakeup Detected Interrupt (WkUpInt) > - * In Device mode, this interrupt is asserted when a resume is > - * detected on the USB. In Host mode, this interrupt is asserted > - * when a remote wakeup is detected on the USB. > - * For more information on how to use this interrupt, see "Partial > - * Power-Down and Clock Gating Programming Model" on > - * page 353. > - * @sessreqint: Session Request/New Session Detected Interrupt > - * (SessReqInt) > - * In Host mode, this interrupt is asserted when a session request > - * is detected from the device. In Device mode, this interrupt is > - * asserted when the utmiotg_bvalid signal goes high. > - * For more information on how to use this interrupt, see "Partial > - * Power-Down and Clock Gating Programming Model" on > - * page 353. > - * @disconnint: Disconnect Detected Interrupt (DisconnInt) > - * Asserted when a device disconnect is detected. > - * @conidstschng: Connector ID Status Change (ConIDStsChng) > - * The core sets this bit when there is a change in connector ID > - * status. > - * @ptxfemp: Periodic TxFIFO Empty (PTxFEmp) > - * Asserted when the Periodic Transmit FIFO is either half or > - * completely empty and there is space for at least one entry to be > - * written in the Periodic Request Queue. The half or completely > - * empty status is determined by the Periodic TxFIFO Empty Level > - * bit in the Core AHB Configuration register > - * (GAHBCFG.PTxFEmpLvl). > - * @hchint: Host Channels Interrupt (HChInt) > - * The core sets this bit to indicate that an interrupt is pending > - * on one of the channels of the core (in Host mode). The > - * application must read the Host All Channels Interrupt (HAINT) > - * register to determine the exact number of the channel on which > - * the interrupt occurred, and then read the corresponding Host > - * Channel-n Interrupt (HCINTn) register to determine the exact > - * cause of the interrupt. The application must clear the > - * appropriate status bit in the HCINTn register to clear this bit. > - * @prtint: Host Port Interrupt (PrtInt) > - * The core sets this bit to indicate a change in port status of > - * one of the O2P USB core ports in Host mode. The application must > - * read the Host Port Control and Status (HPRT) register to > - * determine the exact event that caused this interrupt. The > - * application must clear the appropriate status bit in the Host > - * Port Control and Status register to clear this bit. > - * @fetsusp: Data Fetch Suspended (FetSusp) > - * This interrupt is valid only in DMA mode. This interrupt > - * indicates that the core has stopped fetching data for IN > - * endpoints due to the unavailability of TxFIFO space or Request > - * Queue space. This interrupt is used by the application for an > - * endpoint mismatch algorithm. > - * @incomplp: Incomplete Periodic Transfer (incomplP) > - * In Host mode, the core sets this interrupt bit when there are > - * incomplete periodic transactions still pending which are > - * scheduled for the current microframe. > - * Incomplete Isochronous OUT Transfer (incompISOOUT) > - * The Device mode, the core sets this interrupt to indicate that > - * there is at least one isochronous OUT endpoint on which the > - * transfer is not completed in the current microframe. This > - * interrupt is asserted along with the End of Periodic Frame > - * Interrupt (EOPF) bit in this register. > - * @incompisoin: Incomplete Isochronous IN Transfer (incompISOIN) > - * The core sets this interrupt to indicate that there is at least > - * one isochronous IN endpoint on which the transfer is not > - * completed in the current microframe. This interrupt is asserted > - * along with the End of Periodic Frame Interrupt (EOPF) bit in > - * this register. > - * @oepint: OUT Endpoints Interrupt (OEPInt) > - * The core sets this bit to indicate that an interrupt is pending > - * on one of the OUT endpoints of the core (in Device mode). The > - * application must read the Device All Endpoints Interrupt > - * (DAINT) register to determine the exact number of the OUT > - * endpoint on which the interrupt occurred, and then read the > - * corresponding Device OUT Endpoint-n Interrupt (DOEPINTn) > - * register to determine the exact cause of the interrupt. The > - * application must clear the appropriate status bit in the > - * corresponding DOEPINTn register to clear this bit. > - * @iepint: IN Endpoints Interrupt (IEPInt) > - * The core sets this bit to indicate that an interrupt is pending > - * on one of the IN endpoints of the core (in Device mode). The > - * application must read the Device All Endpoints Interrupt > - * (DAINT) register to determine the exact number of the IN > - * endpoint on which the interrupt occurred, and then read the > - * corresponding Device IN Endpoint-n Interrupt (DIEPINTn) > - * register to determine the exact cause of the interrupt. The > - * application must clear the appropriate status bit in the > - * corresponding DIEPINTn register to clear this bit. > - * @epmis: Endpoint Mismatch Interrupt (EPMis) > - * Indicates that an IN token has been received for a non-periodic > - * endpoint, but the data for another endpoint is present in the > - * top of the Non-Periodic Transmit FIFO and the IN endpoint > - * mismatch count programmed by the application has expired. > - * @eopf: End of Periodic Frame Interrupt (EOPF) > - * Indicates that the period specified in the Periodic Frame > - * Interval field of the Device Configuration register > - * (DCFG.PerFrInt) has been reached in the current microframe. > - * @isooutdrop: Isochronous OUT Packet Dropped Interrupt (ISOOutDrop) > - * The core sets this bit when it fails to write an isochronous OUT > - * packet into the RxFIFO because the RxFIFO doesn't have > - * enough space to accommodate a maximum packet size packet > - * for the isochronous OUT endpoint. > - * @enumdone: Enumeration Done (EnumDone) > - * The core sets this bit to indicate that speed enumeration is > - * complete. The application must read the Device Status (DSTS) > - * register to obtain the enumerated speed. > - * @usbrst: USB Reset (USBRst) > - * The core sets this bit to indicate that a reset is detected on > - * the USB. > - * @usbsusp: USB Suspend (USBSusp) > - * The core sets this bit to indicate that a suspend was detected > - * on the USB. The core enters the Suspended state when there > - * is no activity on the phy_line_state_i signal for an extended > - * period of time. > - * @erlysusp: Early Suspend (ErlySusp) > - * The core sets this bit to indicate that an Idle state has been > - * detected on the USB for 3 ms. > - * @i2cint: I2C Interrupt (I2CINT) > - * This bit is always 0x0. > - * @ulpickint: ULPI Carkit Interrupt (ULPICKINT) > - * This bit is always 0x0. > - * @goutnakeff: Global OUT NAK Effective (GOUTNakEff) > - * Indicates that the Set Global OUT NAK bit in the Device Control > - * register (DCTL.SGOUTNak), set by the application, has taken > - * effect in the core. This bit can be cleared by writing the Clear > - * Global OUT NAK bit in the Device Control register > - * (DCTL.CGOUTNak). > - * @ginnakeff: Global IN Non-Periodic NAK Effective (GINNakEff) > - * Indicates that the Set Global Non-Periodic IN NAK bit in the > - * Device Control register (DCTL.SGNPInNak), set by the > - * application, has taken effect in the core. That is, the core has > - * sampled the Global IN NAK bit set by the application. This bit > - * can be cleared by clearing the Clear Global Non-Periodic IN > - * NAK bit in the Device Control register (DCTL.CGNPInNak). > - * This interrupt does not necessarily mean that a NAK handshake > - * is sent out on the USB. The STALL bit takes precedence over > - * the NAK bit. > - * @nptxfemp: Non-Periodic TxFIFO Empty (NPTxFEmp) > - * This interrupt is asserted when the Non-Periodic TxFIFO is > - * either half or completely empty, and there is space for at least > - * one entry to be written to the Non-Periodic Transmit Request > - * Queue. The half or completely empty status is determined by > - * the Non-Periodic TxFIFO Empty Level bit in the Core AHB > - * Configuration register (GAHBCFG.NPTxFEmpLvl). > - * @rxflvl: RxFIFO Non-Empty (RxFLvl) > - * Indicates that there is at least one packet pending to be read > - * from the RxFIFO. > - * @sof: Start of (micro)Frame (Sof) > - * In Host mode, the core sets this bit to indicate that an SOF > - * (FS), micro-SOF (HS), or Keep-Alive (LS) is transmitted on the > - * USB. The application must write a 1 to this bit to clear the > - * interrupt. > - * In Device mode, in the core sets this bit to indicate that an > - * SOF token has been received on the USB. The application can read > - * the Device Status register to get the current (micro)frame > - * number. This interrupt is seen only when the core is operating > - * at either HS or FS. > - * @otgint: OTG Interrupt (OTGInt) > - * The core sets this bit to indicate an OTG protocol event. The > - * application must read the OTG Interrupt Status (GOTGINT) > - * register to determine the exact event that caused this > - * interrupt. The application must clear the appropriate status bit > - * in the GOTGINT register to clear this bit. > - * @modemis: Mode Mismatch Interrupt (ModeMis) > - * The core sets this bit when the application is trying to access: > - * * A Host mode register, when the core is operating in Device > - * mode > - * * A Device mode register, when the core is operating in Host > - * mode > - * The register access is completed on the AHB with an OKAY > - * response, but is ignored by the core internally and doesn't > - * affect the operation of the core. > - * @curmod: Current Mode of Operation (CurMod) > - * Indicates the current mode of operation. > - * * 1'b0: Device mode > - * * 1'b1: Host mode > - */ > - struct cvmx_usbcx_gintsts_s { > - __BITFIELD_FIELD(u32 wkupint : 1, > - __BITFIELD_FIELD(u32 sessreqint : 1, > - __BITFIELD_FIELD(u32 disconnint : 1, > - __BITFIELD_FIELD(u32 conidstschng : 1, > - __BITFIELD_FIELD(u32 reserved_27_27 : 1, > - __BITFIELD_FIELD(u32 ptxfemp : 1, > - __BITFIELD_FIELD(u32 hchint : 1, > - __BITFIELD_FIELD(u32 prtint : 1, > - __BITFIELD_FIELD(u32 reserved_23_23 : 1, > - __BITFIELD_FIELD(u32 fetsusp : 1, > - __BITFIELD_FIELD(u32 incomplp : 1, > - __BITFIELD_FIELD(u32 incompisoin : 1, > - __BITFIELD_FIELD(u32 oepint : 1, > - __BITFIELD_FIELD(u32 iepint : 1, > - __BITFIELD_FIELD(u32 epmis : 1, > - __BITFIELD_FIELD(u32 reserved_16_16 : 1, > - __BITFIELD_FIELD(u32 eopf : 1, > - __BITFIELD_FIELD(u32 isooutdrop : 1, > - __BITFIELD_FIELD(u32 enumdone : 1, > - __BITFIELD_FIELD(u32 usbrst : 1, > - __BITFIELD_FIELD(u32 usbsusp : 1, > - __BITFIELD_FIELD(u32 erlysusp : 1, > - __BITFIELD_FIELD(u32 i2cint : 1, > - __BITFIELD_FIELD(u32 ulpickint : 1, > - __BITFIELD_FIELD(u32 goutnakeff : 1, > - __BITFIELD_FIELD(u32 ginnakeff : 1, > - __BITFIELD_FIELD(u32 nptxfemp : 1, > - __BITFIELD_FIELD(u32 rxflvl : 1, > - __BITFIELD_FIELD(u32 sof : 1, > - __BITFIELD_FIELD(u32 otgint : 1, > - __BITFIELD_FIELD(u32 modemis : 1, > - __BITFIELD_FIELD(u32 curmod : 1, > - ;)))))))))))))))))))))))))))))))) > - } s; > -}; > - > -/** > - * cvmx_usbc#_gnptxfsiz > - * > - * Non-Periodic Transmit FIFO Size Register (GNPTXFSIZ) > - * > - * The application can program the RAM size and the memory start address for the > - * Non-Periodic TxFIFO. > - */ > -union cvmx_usbcx_gnptxfsiz { > - u32 u32; > - /** > - * struct cvmx_usbcx_gnptxfsiz_s > - * @nptxfdep: Non-Periodic TxFIFO Depth (NPTxFDep) > - * This value is in terms of 32-bit words. > - * Minimum value is 16 > - * Maximum value is 32768 > - * @nptxfstaddr: Non-Periodic Transmit RAM Start Address (NPTxFStAddr) > - * This field contains the memory start address for Non-Periodic > - * Transmit FIFO RAM. > - */ > - struct cvmx_usbcx_gnptxfsiz_s { > - __BITFIELD_FIELD(u32 nptxfdep : 16, > - __BITFIELD_FIELD(u32 nptxfstaddr : 16, > - ;)) > - } s; > -}; > - > -/** > - * cvmx_usbc#_gnptxsts > - * > - * Non-Periodic Transmit FIFO/Queue Status Register (GNPTXSTS) > - * > - * This read-only register contains the free space information for the > - * Non-Periodic TxFIFO and the Non-Periodic Transmit Request Queue. > - */ > -union cvmx_usbcx_gnptxsts { > - u32 u32; > - /** > - * struct cvmx_usbcx_gnptxsts_s > - * @nptxqtop: Top of the Non-Periodic Transmit Request Queue (NPTxQTop) > - * Entry in the Non-Periodic Tx Request Queue that is currently > - * being processed by the MAC. > - * * Bits [30:27]: Channel/endpoint number > - * * Bits [26:25]: > - * - 2'b00: IN/OUT token > - * - 2'b01: Zero-length transmit packet (device IN/host OUT) > - * - 2'b10: PING/CSPLIT token > - * - 2'b11: Channel halt command > - * * Bit [24]: Terminate (last entry for selected channel/endpoint) > - * @nptxqspcavail: Non-Periodic Transmit Request Queue Space Available > - * (NPTxQSpcAvail) > - * Indicates the amount of free space available in the Non- > - * Periodic Transmit Request Queue. This queue holds both IN > - * and OUT requests in Host mode. Device mode has only IN > - * requests. > - * * 8'h0: Non-Periodic Transmit Request Queue is full > - * * 8'h1: 1 location available > - * * 8'h2: 2 locations available > - * * n: n locations available (0..8) > - * * Others: Reserved > - * @nptxfspcavail: Non-Periodic TxFIFO Space Avail (NPTxFSpcAvail) > - * Indicates the amount of free space available in the Non- > - * Periodic TxFIFO. > - * Values are in terms of 32-bit words. > - * * 16'h0: Non-Periodic TxFIFO is full > - * * 16'h1: 1 word available > - * * 16'h2: 2 words available > - * * 16'hn: n words available (where 0..32768) > - * * 16'h8000: 32768 words available > - * * Others: Reserved > - */ > - struct cvmx_usbcx_gnptxsts_s { > - __BITFIELD_FIELD(u32 reserved_31_31 : 1, > - __BITFIELD_FIELD(u32 nptxqtop : 7, > - __BITFIELD_FIELD(u32 nptxqspcavail : 8, > - __BITFIELD_FIELD(u32 nptxfspcavail : 16, > - ;)))) > - } s; > -}; > - > -/** > - * cvmx_usbc#_grstctl > - * > - * Core Reset Register (GRSTCTL) > - * > - * The application uses this register to reset various hardware features inside > - * the core. > - */ > -union cvmx_usbcx_grstctl { > - u32 u32; > - /** > - * struct cvmx_usbcx_grstctl_s > - * @ahbidle: AHB Master Idle (AHBIdle) > - * Indicates that the AHB Master State Machine is in the IDLE > - * condition. > - * @dmareq: DMA Request Signal (DMAReq) > - * Indicates that the DMA request is in progress. Used for debug. > - * @txfnum: TxFIFO Number (TxFNum) > - * This is the FIFO number that must be flushed using the TxFIFO > - * Flush bit. This field must not be changed until the core clears > - * the TxFIFO Flush bit. > - * * 5'h0: Non-Periodic TxFIFO flush > - * * 5'h1: Periodic TxFIFO 1 flush in Device mode or Periodic > - * TxFIFO flush in Host mode > - * * 5'h2: Periodic TxFIFO 2 flush in Device mode > - * - ... > - * * 5'hF: Periodic TxFIFO 15 flush in Device mode > - * * 5'h10: Flush all the Periodic and Non-Periodic TxFIFOs in the > - * core > - * @txfflsh: TxFIFO Flush (TxFFlsh) > - * This bit selectively flushes a single or all transmit FIFOs, but > - * cannot do so if the core is in the midst of a transaction. > - * The application must only write this bit after checking that the > - * core is neither writing to the TxFIFO nor reading from the > - * TxFIFO. > - * The application must wait until the core clears this bit before > - * performing any operations. This bit takes 8 clocks (of phy_clk > - * or hclk, whichever is slower) to clear. > - * @rxfflsh: RxFIFO Flush (RxFFlsh) > - * The application can flush the entire RxFIFO using this bit, but > - * must first ensure that the core is not in the middle of a > - * transaction. > - * The application must only write to this bit after checking that > - * the core is neither reading from the RxFIFO nor writing to the > - * RxFIFO. > - * The application must wait until the bit is cleared before > - * performing any other operations. This bit will take 8 clocks > - * (slowest of PHY or AHB clock) to clear. > - * @intknqflsh: IN Token Sequence Learning Queue Flush (INTknQFlsh) > - * The application writes this bit to flush the IN Token Sequence > - * Learning Queue. > - * @frmcntrrst: Host Frame Counter Reset (FrmCntrRst) > - * The application writes this bit to reset the (micro)frame number > - * counter inside the core. When the (micro)frame counter is reset, > - * the subsequent SOF sent out by the core will have a > - * (micro)frame number of 0. > - * @hsftrst: HClk Soft Reset (HSftRst) > - * The application uses this bit to flush the control logic in the > - * AHB Clock domain. Only AHB Clock Domain pipelines are reset. > - * * FIFOs are not flushed with this bit. > - * * All state machines in the AHB clock domain are reset to the > - * Idle state after terminating the transactions on the AHB, > - * following the protocol. > - * * CSR control bits used by the AHB clock domain state > - * machines are cleared. > - * * To clear this interrupt, status mask bits that control the > - * interrupt status and are generated by the AHB clock domain > - * state machine are cleared. > - * * Because interrupt status bits are not cleared, the application > - * can get the status of any core events that occurred after it set > - * this bit. > - * This is a self-clearing bit that the core clears after all > - * necessary logic is reset in the core. This may take several > - * clocks, depending on the core's current state. > - * @csftrst: Core Soft Reset (CSftRst) > - * Resets the hclk and phy_clock domains as follows: > - * * Clears the interrupts and all the CSR registers except the > - * following register bits: > - * - PCGCCTL.RstPdwnModule > - * - PCGCCTL.GateHclk > - * - PCGCCTL.PwrClmp > - * - PCGCCTL.StopPPhyLPwrClkSelclk > - * - GUSBCFG.PhyLPwrClkSel > - * - GUSBCFG.DDRSel > - * - GUSBCFG.PHYSel > - * - GUSBCFG.FSIntf > - * - GUSBCFG.ULPI_UTMI_Sel > - * - GUSBCFG.PHYIf > - * - HCFG.FSLSPclkSel > - * - DCFG.DevSpd > - * * All module state machines (except the AHB Slave Unit) are > - * reset to the IDLE state, and all the transmit FIFOs and the > - * receive FIFO are flushed. > - * * Any transactions on the AHB Master are terminated as soon > - * as possible, after gracefully completing the last data phase of > - * an AHB transfer. Any transactions on the USB are terminated > - * immediately. > - * The application can write to this bit any time it wants to reset > - * the core. This is a self-clearing bit and the core clears this > - * bit after all the necessary logic is reset in the core, which > - * may take several clocks, depending on the current state of the > - * core. Once this bit is cleared software should wait at least 3 > - * PHY clocks before doing any access to the PHY domain > - * (synchronization delay). Software should also should check that > - * bit 31 of this register is 1 (AHB Master is IDLE) before > - * starting any operation. > - * Typically software reset is used during software development > - * and also when you dynamically change the PHY selection bits > - * in the USB configuration registers listed above. When you > - * change the PHY, the corresponding clock for the PHY is > - * selected and used in the PHY domain. Once a new clock is > - * selected, the PHY domain has to be reset for proper operation. > - */ > - struct cvmx_usbcx_grstctl_s { > - __BITFIELD_FIELD(u32 ahbidle : 1, > - __BITFIELD_FIELD(u32 dmareq : 1, > - __BITFIELD_FIELD(u32 reserved_11_29 : 19, > - __BITFIELD_FIELD(u32 txfnum : 5, > - __BITFIELD_FIELD(u32 txfflsh : 1, > - __BITFIELD_FIELD(u32 rxfflsh : 1, > - __BITFIELD_FIELD(u32 intknqflsh : 1, > - __BITFIELD_FIELD(u32 frmcntrrst : 1, > - __BITFIELD_FIELD(u32 hsftrst : 1, > - __BITFIELD_FIELD(u32 csftrst : 1, > - ;)))))))))) > - } s; > -}; > - > -/** > - * cvmx_usbc#_grxfsiz > - * > - * Receive FIFO Size Register (GRXFSIZ) > - * > - * The application can program the RAM size that must be allocated to the > - * RxFIFO. > - */ > -union cvmx_usbcx_grxfsiz { > - u32 u32; > - /** > - * struct cvmx_usbcx_grxfsiz_s > - * @rxfdep: RxFIFO Depth (RxFDep) > - * This value is in terms of 32-bit words. > - * * Minimum value is 16 > - * * Maximum value is 32768 > - */ > - struct cvmx_usbcx_grxfsiz_s { > - __BITFIELD_FIELD(u32 reserved_16_31 : 16, > - __BITFIELD_FIELD(u32 rxfdep : 16, > - ;)) > - } s; > -}; > - > -/** > - * cvmx_usbc#_grxstsph > - * > - * Receive Status Read and Pop Register, Host Mode (GRXSTSPH) > - * > - * A read to the Receive Status Read and Pop register returns and additionally > - * pops the top data entry out of the RxFIFO. > - * This Description is only valid when the core is in Host Mode. For Device Mode > - * use USBC_GRXSTSPD instead. > - * NOTE: GRXSTSPH and GRXSTSPD are physically the same register and share the > - * same offset in the O2P USB core. The offset difference shown in this > - * document is for software clarity and is actually ignored by the > - * hardware. > - */ > -union cvmx_usbcx_grxstsph { > - u32 u32; > - /** > - * struct cvmx_usbcx_grxstsph_s > - * @pktsts: Packet Status (PktSts) > - * Indicates the status of the received packet > - * * 4'b0010: IN data packet received > - * * 4'b0011: IN transfer completed (triggers an interrupt) > - * * 4'b0101: Data toggle error (triggers an interrupt) > - * * 4'b0111: Channel halted (triggers an interrupt) > - * * Others: Reserved > - * @dpid: Data PID (DPID) > - * * 2'b00: DATA0 > - * * 2'b10: DATA1 > - * * 2'b01: DATA2 > - * * 2'b11: MDATA > - * @bcnt: Byte Count (BCnt) > - * Indicates the byte count of the received IN data packet > - * @chnum: Channel Number (ChNum) > - * Indicates the channel number to which the current received > - * packet belongs. > - */ > - struct cvmx_usbcx_grxstsph_s { > - __BITFIELD_FIELD(u32 reserved_21_31 : 11, > - __BITFIELD_FIELD(u32 pktsts : 4, > - __BITFIELD_FIELD(u32 dpid : 2, > - __BITFIELD_FIELD(u32 bcnt : 11, > - __BITFIELD_FIELD(u32 chnum : 4, > - ;))))) > - } s; > -}; > - > -/** > - * cvmx_usbc#_gusbcfg > - * > - * Core USB Configuration Register (GUSBCFG) > - * > - * This register can be used to configure the core after power-on or a changing > - * to Host mode or Device mode. It contains USB and USB-PHY related > - * configuration parameters. The application must program this register before > - * starting any transactions on either the AHB or the USB. Do not make changes > - * to this register after the initial programming. > - */ > -union cvmx_usbcx_gusbcfg { > - u32 u32; > - /** > - * struct cvmx_usbcx_gusbcfg_s > - * @otgi2csel: UTMIFS or I2C Interface Select (OtgI2CSel) > - * This bit is always 0x0. > - * @phylpwrclksel: PHY Low-Power Clock Select (PhyLPwrClkSel) > - * Software should set this bit to 0x0. > - * Selects either 480-MHz or 48-MHz (low-power) PHY mode. In > - * FS and LS modes, the PHY can usually operate on a 48-MHz > - * clock to save power. > - * * 1'b0: 480-MHz Internal PLL clock > - * * 1'b1: 48-MHz External Clock > - * In 480 MHz mode, the UTMI interface operates at either 60 or > - * 30-MHz, depending upon whether 8- or 16-bit data width is > - * selected. In 48-MHz mode, the UTMI interface operates at 48 > - * MHz in FS mode and at either 48 or 6 MHz in LS mode > - * (depending on the PHY vendor). > - * This bit drives the utmi_fsls_low_power core output signal, and > - * is valid only for UTMI+ PHYs. > - * @usbtrdtim: USB Turnaround Time (USBTrdTim) > - * Sets the turnaround time in PHY clocks. > - * Specifies the response time for a MAC request to the Packet > - * FIFO Controller (PFC) to fetch data from the DFIFO (SPRAM). > - * This must be programmed to 0x5. > - * @hnpcap: HNP-Capable (HNPCap) > - * This bit is always 0x0. > - * @srpcap: SRP-Capable (SRPCap) > - * This bit is always 0x0. > - * @ddrsel: ULPI DDR Select (DDRSel) > - * Software should set this bit to 0x0. > - * @physel: USB 2.0 High-Speed PHY or USB 1.1 Full-Speed Serial > - * Software should set this bit to 0x0. > - * @fsintf: Full-Speed Serial Interface Select (FSIntf) > - * Software should set this bit to 0x0. > - * @ulpi_utmi_sel: ULPI or UTMI+ Select (ULPI_UTMI_Sel) > - * This bit is always 0x0. > - * @phyif: PHY Interface (PHYIf) > - * This bit is always 0x1. > - * @toutcal: HS/FS Timeout Calibration (TOutCal) > - * The number of PHY clocks that the application programs in this > - * field is added to the high-speed/full-speed interpacket timeout > - * duration in the core to account for any additional delays > - * introduced by the PHY. This may be required, since the delay > - * introduced by the PHY in generating the linestate condition may > - * vary from one PHY to another. > - * The USB standard timeout value for high-speed operation is > - * 736 to 816 (inclusive) bit times. The USB standard timeout > - * value for full-speed operation is 16 to 18 (inclusive) bit > - * times. The application must program this field based on the > - * speed of enumeration. The number of bit times added per PHY > - * clock are: > - * High-speed operation: > - * * One 30-MHz PHY clock = 16 bit times > - * * One 60-MHz PHY clock = 8 bit times > - * Full-speed operation: > - * * One 30-MHz PHY clock = 0.4 bit times > - * * One 60-MHz PHY clock = 0.2 bit times > - * * One 48-MHz PHY clock = 0.25 bit times > - */ > - struct cvmx_usbcx_gusbcfg_s { > - __BITFIELD_FIELD(u32 reserved_17_31 : 15, > - __BITFIELD_FIELD(u32 otgi2csel : 1, > - __BITFIELD_FIELD(u32 phylpwrclksel : 1, > - __BITFIELD_FIELD(u32 reserved_14_14 : 1, > - __BITFIELD_FIELD(u32 usbtrdtim : 4, > - __BITFIELD_FIELD(u32 hnpcap : 1, > - __BITFIELD_FIELD(u32 srpcap : 1, > - __BITFIELD_FIELD(u32 ddrsel : 1, > - __BITFIELD_FIELD(u32 physel : 1, > - __BITFIELD_FIELD(u32 fsintf : 1, > - __BITFIELD_FIELD(u32 ulpi_utmi_sel : 1, > - __BITFIELD_FIELD(u32 phyif : 1, > - __BITFIELD_FIELD(u32 toutcal : 3, > - ;))))))))))))) > - } s; > -}; > - > -/** > - * cvmx_usbc#_haint > - * > - * Host All Channels Interrupt Register (HAINT) > - * > - * When a significant event occurs on a channel, the Host All Channels Interrupt > - * register interrupts the application using the Host Channels Interrupt bit of > - * the Core Interrupt register (GINTSTS.HChInt). This is shown in Interrupt. > - * There is one interrupt bit per channel, up to a maximum of 16 bits. Bits in > - * this register are set and cleared when the application sets and clears bits > - * in the corresponding Host Channel-n Interrupt register. > - */ > -union cvmx_usbcx_haint { > - u32 u32; > - /** > - * struct cvmx_usbcx_haint_s > - * @haint: Channel Interrupts (HAINT) > - * One bit per channel: Bit 0 for Channel 0, bit 15 for Channel 15 > - */ > - struct cvmx_usbcx_haint_s { > - __BITFIELD_FIELD(u32 reserved_16_31 : 16, > - __BITFIELD_FIELD(u32 haint : 16, > - ;)) > - } s; > -}; > - > -/** > - * cvmx_usbc#_haintmsk > - * > - * Host All Channels Interrupt Mask Register (HAINTMSK) > - * > - * The Host All Channel Interrupt Mask register works with the Host All Channel > - * Interrupt register to interrupt the application when an event occurs on a > - * channel. There is one interrupt mask bit per channel, up to a maximum of 16 > - * bits. > - * Mask interrupt: 1'b0 Unmask interrupt: 1'b1 > - */ > -union cvmx_usbcx_haintmsk { > - u32 u32; > - /** > - * struct cvmx_usbcx_haintmsk_s > - * @haintmsk: Channel Interrupt Mask (HAINTMsk) > - * One bit per channel: Bit 0 for channel 0, bit 15 for channel 15 > - */ > - struct cvmx_usbcx_haintmsk_s { > - __BITFIELD_FIELD(u32 reserved_16_31 : 16, > - __BITFIELD_FIELD(u32 haintmsk : 16, > - ;)) > - } s; > -}; > - > -/** > - * cvmx_usbc#_hcchar# > - * > - * Host Channel-n Characteristics Register (HCCHAR) > - * > - */ > -union cvmx_usbcx_hccharx { > - u32 u32; > - /** > - * struct cvmx_usbcx_hccharx_s > - * @chena: Channel Enable (ChEna) > - * This field is set by the application and cleared by the OTG > - * host. > - * * 1'b0: Channel disabled > - * * 1'b1: Channel enabled > - * @chdis: Channel Disable (ChDis) > - * The application sets this bit to stop transmitting/receiving > - * data on a channel, even before the transfer for that channel is > - * complete. The application must wait for the Channel Disabled > - * interrupt before treating the channel as disabled. > - * @oddfrm: Odd Frame (OddFrm) > - * This field is set (reset) by the application to indicate that > - * the OTG host must perform a transfer in an odd (micro)frame. > - * This field is applicable for only periodic (isochronous and > - * interrupt) transactions. > - * * 1'b0: Even (micro)frame > - * * 1'b1: Odd (micro)frame > - * @devaddr: Device Address (DevAddr) > - * This field selects the specific device serving as the data > - * source or sink. > - * @ec: Multi Count (MC) / Error Count (EC) > - * When the Split Enable bit of the Host Channel-n Split Control > - * register (HCSPLTn.SpltEna) is reset (1'b0), this field indicates > - * to the host the number of transactions that should be executed > - * per microframe for this endpoint. > - * * 2'b00: Reserved. This field yields undefined results. > - * * 2'b01: 1 transaction > - * * 2'b10: 2 transactions to be issued for this endpoint per > - * microframe > - * * 2'b11: 3 transactions to be issued for this endpoint per > - * microframe > - * When HCSPLTn.SpltEna is set (1'b1), this field indicates the > - * number of immediate retries to be performed for a periodic split > - * transactions on transaction errors. This field must be set to at > - * least 2'b01. > - * @eptype: Endpoint Type (EPType) > - * Indicates the transfer type selected. > - * * 2'b00: Control > - * * 2'b01: Isochronous > - * * 2'b10: Bulk > - * * 2'b11: Interrupt > - * @lspddev: Low-Speed Device (LSpdDev) > - * This field is set by the application to indicate that this > - * channel is communicating to a low-speed device. > - * @epdir: Endpoint Direction (EPDir) > - * Indicates whether the transaction is IN or OUT. > - * * 1'b0: OUT > - * * 1'b1: IN > - * @epnum: Endpoint Number (EPNum) > - * Indicates the endpoint number on the device serving as the > - * data source or sink. > - * @mps: Maximum Packet Size (MPS) > - * Indicates the maximum packet size of the associated endpoint. > - */ > - struct cvmx_usbcx_hccharx_s { > - __BITFIELD_FIELD(u32 chena : 1, > - __BITFIELD_FIELD(u32 chdis : 1, > - __BITFIELD_FIELD(u32 oddfrm : 1, > - __BITFIELD_FIELD(u32 devaddr : 7, > - __BITFIELD_FIELD(u32 ec : 2, > - __BITFIELD_FIELD(u32 eptype : 2, > - __BITFIELD_FIELD(u32 lspddev : 1, > - __BITFIELD_FIELD(u32 reserved_16_16 : 1, > - __BITFIELD_FIELD(u32 epdir : 1, > - __BITFIELD_FIELD(u32 epnum : 4, > - __BITFIELD_FIELD(u32 mps : 11, > - ;))))))))))) > - } s; > -}; > - > -/** > - * cvmx_usbc#_hcfg > - * > - * Host Configuration Register (HCFG) > - * > - * This register configures the core after power-on. Do not make changes to this > - * register after initializing the host. > - */ > -union cvmx_usbcx_hcfg { > - u32 u32; > - /** > - * struct cvmx_usbcx_hcfg_s > - * @fslssupp: FS- and LS-Only Support (FSLSSupp) > - * The application uses this bit to control the core's enumeration > - * speed. Using this bit, the application can make the core > - * enumerate as a FS host, even if the connected device supports > - * HS traffic. Do not make changes to this field after initial > - * programming. > - * * 1'b0: HS/FS/LS, based on the maximum speed supported by > - * the connected device > - * * 1'b1: FS/LS-only, even if the connected device can support HS > - * @fslspclksel: FS/LS PHY Clock Select (FSLSPclkSel) > - * When the core is in FS Host mode > - * * 2'b00: PHY clock is running at 30/60 MHz > - * * 2'b01: PHY clock is running at 48 MHz > - * * Others: Reserved > - * When the core is in LS Host mode > - * * 2'b00: PHY clock is running at 30/60 MHz. When the > - * UTMI+/ULPI PHY Low Power mode is not selected, use > - * 30/60 MHz. > - * * 2'b01: PHY clock is running at 48 MHz. When the UTMI+ > - * PHY Low Power mode is selected, use 48MHz if the PHY > - * supplies a 48 MHz clock during LS mode. > - * * 2'b10: PHY clock is running at 6 MHz. In USB 1.1 FS mode, > - * use 6 MHz when the UTMI+ PHY Low Power mode is > - * selected and the PHY supplies a 6 MHz clock during LS > - * mode. If you select a 6 MHz clock during LS mode, you must > - * do a soft reset. > - * * 2'b11: Reserved > - */ > - struct cvmx_usbcx_hcfg_s { > - __BITFIELD_FIELD(u32 reserved_3_31 : 29, > - __BITFIELD_FIELD(u32 fslssupp : 1, > - __BITFIELD_FIELD(u32 fslspclksel : 2, > - ;))) > - } s; > -}; > - > -/** > - * cvmx_usbc#_hcint# > - * > - * Host Channel-n Interrupt Register (HCINT) > - * > - * This register indicates the status of a channel with respect to USB- and > - * AHB-related events. The application must read this register when the Host > - * Channels Interrupt bit of the Core Interrupt register (GINTSTS.HChInt) is > - * set. Before the application can read this register, it must first read > - * the Host All Channels Interrupt (HAINT) register to get the exact channel > - * number for the Host Channel-n Interrupt register. The application must clear > - * the appropriate bit in this register to clear the corresponding bits in the > - * HAINT and GINTSTS registers. > - */ > -union cvmx_usbcx_hcintx { > - u32 u32; > - /** > - * struct cvmx_usbcx_hcintx_s > - * @datatglerr: Data Toggle Error (DataTglErr) > - * @frmovrun: Frame Overrun (FrmOvrun) > - * @bblerr: Babble Error (BblErr) > - * @xacterr: Transaction Error (XactErr) > - * @nyet: NYET Response Received Interrupt (NYET) > - * @ack: ACK Response Received Interrupt (ACK) > - * @nak: NAK Response Received Interrupt (NAK) > - * @stall: STALL Response Received Interrupt (STALL) > - * @ahberr: This bit is always 0x0. > - * @chhltd: Channel Halted (ChHltd) > - * Indicates the transfer completed abnormally either because of > - * any USB transaction error or in response to disable request by > - * the application. > - * @xfercompl: Transfer Completed (XferCompl) > - * Transfer completed normally without any errors. > - */ > - struct cvmx_usbcx_hcintx_s { > - __BITFIELD_FIELD(u32 reserved_11_31 : 21, > - __BITFIELD_FIELD(u32 datatglerr : 1, > - __BITFIELD_FIELD(u32 frmovrun : 1, > - __BITFIELD_FIELD(u32 bblerr : 1, > - __BITFIELD_FIELD(u32 xacterr : 1, > - __BITFIELD_FIELD(u32 nyet : 1, > - __BITFIELD_FIELD(u32 ack : 1, > - __BITFIELD_FIELD(u32 nak : 1, > - __BITFIELD_FIELD(u32 stall : 1, > - __BITFIELD_FIELD(u32 ahberr : 1, > - __BITFIELD_FIELD(u32 chhltd : 1, > - __BITFIELD_FIELD(u32 xfercompl : 1, > - ;)))))))))))) > - } s; > -}; > - > -/** > - * cvmx_usbc#_hcintmsk# > - * > - * Host Channel-n Interrupt Mask Register (HCINTMSKn) > - * > - * This register reflects the mask for each channel status described in the > - * previous section. > - * Mask interrupt: 1'b0 Unmask interrupt: 1'b1 > - */ > -union cvmx_usbcx_hcintmskx { > - u32 u32; > - /** > - * struct cvmx_usbcx_hcintmskx_s > - * @datatglerrmsk: Data Toggle Error Mask (DataTglErrMsk) > - * @frmovrunmsk: Frame Overrun Mask (FrmOvrunMsk) > - * @bblerrmsk: Babble Error Mask (BblErrMsk) > - * @xacterrmsk: Transaction Error Mask (XactErrMsk) > - * @nyetmsk: NYET Response Received Interrupt Mask (NyetMsk) > - * @ackmsk: ACK Response Received Interrupt Mask (AckMsk) > - * @nakmsk: NAK Response Received Interrupt Mask (NakMsk) > - * @stallmsk: STALL Response Received Interrupt Mask (StallMsk) > - * @ahberrmsk: AHB Error Mask (AHBErrMsk) > - * @chhltdmsk: Channel Halted Mask (ChHltdMsk) > - * @xfercomplmsk: Transfer Completed Mask (XferComplMsk) > - */ > - struct cvmx_usbcx_hcintmskx_s { > - __BITFIELD_FIELD(u32 reserved_11_31 : 21, > - __BITFIELD_FIELD(u32 datatglerrmsk : 1, > - __BITFIELD_FIELD(u32 frmovrunmsk : 1, > - __BITFIELD_FIELD(u32 bblerrmsk : 1, > - __BITFIELD_FIELD(u32 xacterrmsk : 1, > - __BITFIELD_FIELD(u32 nyetmsk : 1, > - __BITFIELD_FIELD(u32 ackmsk : 1, > - __BITFIELD_FIELD(u32 nakmsk : 1, > - __BITFIELD_FIELD(u32 stallmsk : 1, > - __BITFIELD_FIELD(u32 ahberrmsk : 1, > - __BITFIELD_FIELD(u32 chhltdmsk : 1, > - __BITFIELD_FIELD(u32 xfercomplmsk : 1, > - ;)))))))))))) > - } s; > -}; > - > -/** > - * cvmx_usbc#_hcsplt# > - * > - * Host Channel-n Split Control Register (HCSPLT) > - * > - */ > -union cvmx_usbcx_hcspltx { > - u32 u32; > - /** > - * struct cvmx_usbcx_hcspltx_s > - * @spltena: Split Enable (SpltEna) > - * The application sets this field to indicate that this channel is > - * enabled to perform split transactions. > - * @compsplt: Do Complete Split (CompSplt) > - * The application sets this field to request the OTG host to > - * perform a complete split transaction. > - * @xactpos: Transaction Position (XactPos) > - * This field is used to determine whether to send all, first, > - * middle, or last payloads with each OUT transaction. > - * * 2'b11: All. This is the entire data payload is of this > - * transaction (which is less than or equal to 188 bytes). > - * * 2'b10: Begin. This is the first data payload of this > - * transaction (which is larger than 188 bytes). > - * * 2'b00: Mid. This is the middle payload of this transaction > - * (which is larger than 188 bytes). > - * * 2'b01: End. This is the last payload of this transaction > - * (which is larger than 188 bytes). > - * @hubaddr: Hub Address (HubAddr) > - * This field holds the device address of the transaction > - * translator's hub. > - * @prtaddr: Port Address (PrtAddr) > - * This field is the port number of the recipient transaction > - * translator. > - */ > - struct cvmx_usbcx_hcspltx_s { > - __BITFIELD_FIELD(u32 spltena : 1, > - __BITFIELD_FIELD(u32 reserved_17_30 : 14, > - __BITFIELD_FIELD(u32 compsplt : 1, > - __BITFIELD_FIELD(u32 xactpos : 2, > - __BITFIELD_FIELD(u32 hubaddr : 7, > - __BITFIELD_FIELD(u32 prtaddr : 7, > - ;)))))) > - } s; > -}; > - > -/** > - * cvmx_usbc#_hctsiz# > - * > - * Host Channel-n Transfer Size Register (HCTSIZ) > - * > - */ > -union cvmx_usbcx_hctsizx { > - u32 u32; > - /** > - * struct cvmx_usbcx_hctsizx_s > - * @dopng: Do Ping (DoPng) > - * Setting this field to 1 directs the host to do PING protocol. > - * @pid: PID (Pid) > - * The application programs this field with the type of PID to use > - * for the initial transaction. The host will maintain this field > - * for the rest of the transfer. > - * * 2'b00: DATA0 > - * * 2'b01: DATA2 > - * * 2'b10: DATA1 > - * * 2'b11: MDATA (non-control)/SETUP (control) > - * @pktcnt: Packet Count (PktCnt) > - * This field is programmed by the application with the expected > - * number of packets to be transmitted (OUT) or received (IN). > - * The host decrements this count on every successful > - * transmission or reception of an OUT/IN packet. Once this count > - * reaches zero, the application is interrupted to indicate normal > - * completion. > - * @xfersize: Transfer Size (XferSize) > - * For an OUT, this field is the number of data bytes the host will > - * send during the transfer. > - * For an IN, this field is the buffer size that the application > - * has reserved for the transfer. The application is expected to > - * program this field as an integer multiple of the maximum packet > - * size for IN transactions (periodic and non-periodic). > - */ > - struct cvmx_usbcx_hctsizx_s { > - __BITFIELD_FIELD(u32 dopng : 1, > - __BITFIELD_FIELD(u32 pid : 2, > - __BITFIELD_FIELD(u32 pktcnt : 10, > - __BITFIELD_FIELD(u32 xfersize : 19, > - ;)))) > - } s; > -}; > - > -/** > - * cvmx_usbc#_hfir > - * > - * Host Frame Interval Register (HFIR) > - * > - * This register stores the frame interval information for the current speed to > - * which the O2P USB core has enumerated. > - */ > -union cvmx_usbcx_hfir { > - u32 u32; > - /** > - * struct cvmx_usbcx_hfir_s > - * @frint: Frame Interval (FrInt) > - * The value that the application programs to this field specifies > - * the interval between two consecutive SOFs (FS) or micro- > - * SOFs (HS) or Keep-Alive tokens (HS). This field contains the > - * number of PHY clocks that constitute the required frame > - * interval. The default value set in this field for a FS operation > - * when the PHY clock frequency is 60 MHz. The application can > - * write a value to this register only after the Port Enable bit of > - * the Host Port Control and Status register (HPRT.PrtEnaPort) > - * has been set. If no value is programmed, the core calculates > - * the value based on the PHY clock specified in the FS/LS PHY > - * Clock Select field of the Host Configuration register > - * (HCFG.FSLSPclkSel). Do not change the value of this field > - * after the initial configuration. > - * * 125 us (PHY clock frequency for HS) > - * * 1 ms (PHY clock frequency for FS/LS) > - */ > - struct cvmx_usbcx_hfir_s { > - __BITFIELD_FIELD(u32 reserved_16_31 : 16, > - __BITFIELD_FIELD(u32 frint : 16, > - ;)) > - } s; > -}; > - > -/** > - * cvmx_usbc#_hfnum > - * > - * Host Frame Number/Frame Time Remaining Register (HFNUM) > - * > - * This register indicates the current frame number. > - * It also indicates the time remaining (in terms of the number of PHY clocks) > - * in the current (micro)frame. > - */ > -union cvmx_usbcx_hfnum { > - u32 u32; > - /** > - * struct cvmx_usbcx_hfnum_s > - * @frrem: Frame Time Remaining (FrRem) > - * Indicates the amount of time remaining in the current > - * microframe (HS) or frame (FS/LS), in terms of PHY clocks. > - * This field decrements on each PHY clock. When it reaches > - * zero, this field is reloaded with the value in the Frame > - * Interval register and a new SOF is transmitted on the USB. > - * @frnum: Frame Number (FrNum) > - * This field increments when a new SOF is transmitted on the > - * USB, and is reset to 0 when it reaches 16'h3FFF. > - */ > - struct cvmx_usbcx_hfnum_s { > - __BITFIELD_FIELD(u32 frrem : 16, > - __BITFIELD_FIELD(u32 frnum : 16, > - ;)) > - } s; > -}; > - > -/** > - * cvmx_usbc#_hprt > - * > - * Host Port Control and Status Register (HPRT) > - * > - * This register is available in both Host and Device modes. > - * Currently, the OTG Host supports only one port. > - * A single register holds USB port-related information such as USB reset, > - * enable, suspend, resume, connect status, and test mode for each port. The > - * R_SS_WC bits in this register can trigger an interrupt to the application > - * through the Host Port Interrupt bit of the Core Interrupt register > - * (GINTSTS.PrtInt). On a Port Interrupt, the application must read this > - * register and clear the bit that caused the interrupt. For the R_SS_WC bits, > - * the application must write a 1 to the bit to clear the interrupt. > - */ > -union cvmx_usbcx_hprt { > - u32 u32; > - /** > - * struct cvmx_usbcx_hprt_s > - * @prtspd: Port Speed (PrtSpd) > - * Indicates the speed of the device attached to this port. > - * * 2'b00: High speed > - * * 2'b01: Full speed > - * * 2'b10: Low speed > - * * 2'b11: Reserved > - * @prttstctl: Port Test Control (PrtTstCtl) > - * The application writes a nonzero value to this field to put > - * the port into a Test mode, and the corresponding pattern is > - * signaled on the port. > - * * 4'b0000: Test mode disabled > - * * 4'b0001: Test_J mode > - * * 4'b0010: Test_K mode > - * * 4'b0011: Test_SE0_NAK mode > - * * 4'b0100: Test_Packet mode > - * * 4'b0101: Test_Force_Enable > - * * Others: Reserved > - * PrtSpd must be zero (i.e. the interface must be in high-speed > - * mode) to use the PrtTstCtl test modes. > - * @prtpwr: Port Power (PrtPwr) > - * The application uses this field to control power to this port, > - * and the core clears this bit on an overcurrent condition. > - * * 1'b0: Power off > - * * 1'b1: Power on > - * @prtlnsts: Port Line Status (PrtLnSts) > - * Indicates the current logic level USB data lines > - * * Bit [10]: Logic level of D- > - * * Bit [11]: Logic level of D+ > - * @prtrst: Port Reset (PrtRst) > - * When the application sets this bit, a reset sequence is > - * started on this port. The application must time the reset > - * period and clear this bit after the reset sequence is > - * complete. > - * * 1'b0: Port not in reset > - * * 1'b1: Port in reset > - * The application must leave this bit set for at least a > - * minimum duration mentioned below to start a reset on the > - * port. The application can leave it set for another 10 ms in > - * addition to the required minimum duration, before clearing > - * the bit, even though there is no maximum limit set by the > - * USB standard. > - * * High speed: 50 ms > - * * Full speed/Low speed: 10 ms > - * @prtsusp: Port Suspend (PrtSusp) > - * The application sets this bit to put this port in Suspend > - * mode. The core only stops sending SOFs when this is set. > - * To stop the PHY clock, the application must set the Port > - * Clock Stop bit, which will assert the suspend input pin of > - * the PHY. > - * The read value of this bit reflects the current suspend > - * status of the port. This bit is cleared by the core after a > - * remote wakeup signal is detected or the application sets > - * the Port Reset bit or Port Resume bit in this register or the > - * Resume/Remote Wakeup Detected Interrupt bit or > - * Disconnect Detected Interrupt bit in the Core Interrupt > - * register (GINTSTS.WkUpInt or GINTSTS.DisconnInt, > - * respectively). > - * * 1'b0: Port not in Suspend mode > - * * 1'b1: Port in Suspend mode > - * @prtres: Port Resume (PrtRes) > - * The application sets this bit to drive resume signaling on > - * the port. The core continues to drive the resume signal > - * until the application clears this bit. > - * If the core detects a USB remote wakeup sequence, as > - * indicated by the Port Resume/Remote Wakeup Detected > - * Interrupt bit of the Core Interrupt register > - * (GINTSTS.WkUpInt), the core starts driving resume > - * signaling without application intervention and clears this bit > - * when it detects a disconnect condition. The read value of > - * this bit indicates whether the core is currently driving > - * resume signaling. > - * * 1'b0: No resume driven > - * * 1'b1: Resume driven > - * @prtovrcurrchng: Port Overcurrent Change (PrtOvrCurrChng) > - * The core sets this bit when the status of the Port > - * Overcurrent Active bit (bit 4) in this register changes. > - * @prtovrcurract: Port Overcurrent Active (PrtOvrCurrAct) > - * Indicates the overcurrent condition of the port. > - * * 1'b0: No overcurrent condition > - * * 1'b1: Overcurrent condition > - * @prtenchng: Port Enable/Disable Change (PrtEnChng) > - * The core sets this bit when the status of the Port Enable bit > - * [2] of this register changes. > - * @prtena: Port Enable (PrtEna) > - * A port is enabled only by the core after a reset sequence, > - * and is disabled by an overcurrent condition, a disconnect > - * condition, or by the application clearing this bit. The > - * application cannot set this bit by a register write. It can only > - * clear it to disable the port. This bit does not trigger any > - * interrupt to the application. > - * * 1'b0: Port disabled > - * * 1'b1: Port enabled > - * @prtconndet: Port Connect Detected (PrtConnDet) > - * The core sets this bit when a device connection is detected > - * to trigger an interrupt to the application using the Host Port > - * Interrupt bit of the Core Interrupt register (GINTSTS.PrtInt). > - * The application must write a 1 to this bit to clear the > - * interrupt. > - * @prtconnsts: Port Connect Status (PrtConnSts) > - * * 0: No device is attached to the port. > - * * 1: A device is attached to the port. > - */ > - struct cvmx_usbcx_hprt_s { > - __BITFIELD_FIELD(u32 reserved_19_31 : 13, > - __BITFIELD_FIELD(u32 prtspd : 2, > - __BITFIELD_FIELD(u32 prttstctl : 4, > - __BITFIELD_FIELD(u32 prtpwr : 1, > - __BITFIELD_FIELD(u32 prtlnsts : 2, > - __BITFIELD_FIELD(u32 reserved_9_9 : 1, > - __BITFIELD_FIELD(u32 prtrst : 1, > - __BITFIELD_FIELD(u32 prtsusp : 1, > - __BITFIELD_FIELD(u32 prtres : 1, > - __BITFIELD_FIELD(u32 prtovrcurrchng : 1, > - __BITFIELD_FIELD(u32 prtovrcurract : 1, > - __BITFIELD_FIELD(u32 prtenchng : 1, > - __BITFIELD_FIELD(u32 prtena : 1, > - __BITFIELD_FIELD(u32 prtconndet : 1, > - __BITFIELD_FIELD(u32 prtconnsts : 1, > - ;))))))))))))))) > - } s; > -}; > - > -/** > - * cvmx_usbc#_hptxfsiz > - * > - * Host Periodic Transmit FIFO Size Register (HPTXFSIZ) > - * > - * This register holds the size and the memory start address of the Periodic > - * TxFIFO, as shown in Figures 310 and 311. > - */ > -union cvmx_usbcx_hptxfsiz { > - u32 u32; > - /** > - * struct cvmx_usbcx_hptxfsiz_s > - * @ptxfsize: Host Periodic TxFIFO Depth (PTxFSize) > - * This value is in terms of 32-bit words. > - * * Minimum value is 16 > - * * Maximum value is 32768 > - * @ptxfstaddr: Host Periodic TxFIFO Start Address (PTxFStAddr) > - */ > - struct cvmx_usbcx_hptxfsiz_s { > - __BITFIELD_FIELD(u32 ptxfsize : 16, > - __BITFIELD_FIELD(u32 ptxfstaddr : 16, > - ;)) > - } s; > -}; > - > -/** > - * cvmx_usbc#_hptxsts > - * > - * Host Periodic Transmit FIFO/Queue Status Register (HPTXSTS) > - * > - * This read-only register contains the free space information for the Periodic > - * TxFIFO and the Periodic Transmit Request Queue > - */ > -union cvmx_usbcx_hptxsts { > - u32 u32; > - /** > - * struct cvmx_usbcx_hptxsts_s > - * @ptxqtop: Top of the Periodic Transmit Request Queue (PTxQTop) > - * This indicates the entry in the Periodic Tx Request Queue that > - * is currently being processes by the MAC. > - * This register is used for debugging. > - * * Bit [31]: Odd/Even (micro)frame > - * - 1'b0: send in even (micro)frame > - * - 1'b1: send in odd (micro)frame > - * * Bits [30:27]: Channel/endpoint number > - * * Bits [26:25]: Type > - * - 2'b00: IN/OUT > - * - 2'b01: Zero-length packet > - * - 2'b10: CSPLIT > - * - 2'b11: Disable channel command > - * * Bit [24]: Terminate (last entry for the selected > - * channel/endpoint) > - * @ptxqspcavail: Periodic Transmit Request Queue Space Available > - * (PTxQSpcAvail) > - * Indicates the number of free locations available to be written > - * in the Periodic Transmit Request Queue. This queue holds both > - * IN and OUT requests. > - * * 8'h0: Periodic Transmit Request Queue is full > - * * 8'h1: 1 location available > - * * 8'h2: 2 locations available > - * * n: n locations available (0..8) > - * * Others: Reserved > - * @ptxfspcavail: Periodic Transmit Data FIFO Space Available > - * (PTxFSpcAvail) > - * Indicates the number of free locations available to be written > - * to in the Periodic TxFIFO. > - * Values are in terms of 32-bit words > - * * 16'h0: Periodic TxFIFO is full > - * * 16'h1: 1 word available > - * * 16'h2: 2 words available > - * * 16'hn: n words available (where 0..32768) > - * * 16'h8000: 32768 words available > - * * Others: Reserved > - */ > - struct cvmx_usbcx_hptxsts_s { > - __BITFIELD_FIELD(u32 ptxqtop : 8, > - __BITFIELD_FIELD(u32 ptxqspcavail : 8, > - __BITFIELD_FIELD(u32 ptxfspcavail : 16, > - ;))) > - } s; > -}; > - > -/** > - * cvmx_usbn#_clk_ctl > - * > - * USBN_CLK_CTL = USBN's Clock Control > - * > - * This register is used to control the frequency of the hclk and the > - * hreset and phy_rst signals. > - */ > -union cvmx_usbnx_clk_ctl { > - u64 u64; > - /** > - * struct cvmx_usbnx_clk_ctl_s > - * @divide2: The 'hclk' used by the USB subsystem is derived > - * from the eclk. > - * Also see the field DIVIDE. DIVIDE2<1> must currently > - * be zero because it is not implemented, so the maximum > - * ratio of eclk/hclk is currently 16. > - * The actual divide number for hclk is: > - * (DIVIDE2 + 1) * (DIVIDE + 1) > - * @hclk_rst: When this field is '0' the HCLK-DIVIDER used to > - * generate the hclk in the USB Subsystem is held > - * in reset. This bit must be set to '0' before > - * changing the value os DIVIDE in this register. > - * The reset to the HCLK_DIVIDERis also asserted > - * when core reset is asserted. > - * @p_x_on: Force USB-PHY on during suspend. > - * '1' USB-PHY XO block is powered-down during > - * suspend. > - * '0' USB-PHY XO block is powered-up during > - * suspend. > - * The value of this field must be set while POR is > - * active. > - * @p_rtype: PHY reference clock type > - * On CN50XX/CN52XX/CN56XX the values are: > - * '0' The USB-PHY uses a 12MHz crystal as a clock source > - * at the USB_XO and USB_XI pins. > - * '1' Reserved. > - * '2' The USB_PHY uses 12/24/48MHz 2.5V board clock at the > - * USB_XO pin. USB_XI should be tied to ground in this > - * case. > - * '3' Reserved. > - * On CN3xxx bits 14 and 15 are p_xenbn and p_rclk and values are: > - * '0' Reserved. > - * '1' Reserved. > - * '2' The PHY PLL uses the XO block output as a reference. > - * The XO block uses an external clock supplied on the > - * XO pin. USB_XI should be tied to ground for this > - * usage. > - * '3' The XO block uses the clock from a crystal. > - * @p_com_on: '0' Force USB-PHY XO Bias, Bandgap and PLL to > - * remain powered in Suspend Mode. > - * '1' The USB-PHY XO Bias, Bandgap and PLL are > - * powered down in suspend mode. > - * The value of this field must be set while POR is > - * active. > - * @p_c_sel: Phy clock speed select. > - * Selects the reference clock / crystal frequency. > - * '11': Reserved > - * '10': 48 MHz (reserved when a crystal is used) > - * '01': 24 MHz (reserved when a crystal is used) > - * '00': 12 MHz > - * The value of this field must be set while POR is > - * active. > - * NOTE: if a crystal is used as a reference clock, > - * this field must be set to 12 MHz. > - * @cdiv_byp: Used to enable the bypass input to the USB_CLK_DIV. > - * @sd_mode: Scaledown mode for the USBC. Control timing events > - * in the USBC, for normal operation this must be '0'. > - * @s_bist: Starts bist on the hclk memories, during the '0' > - * to '1' transition. > - * @por: Power On Reset for the PHY. > - * Resets all the PHYS registers and state machines. > - * @enable: When '1' allows the generation of the hclk. When > - * '0' the hclk will not be generated. SEE DIVIDE > - * field of this register. > - * @prst: When this field is '0' the reset associated with > - * the phy_clk functionality in the USB Subsystem is > - * help in reset. This bit should not be set to '1' > - * until the time it takes 6 clocks (hclk or phy_clk, > - * whichever is slower) has passed. Under normal > - * operation once this bit is set to '1' it should not > - * be set to '0'. > - * @hrst: When this field is '0' the reset associated with > - * the hclk functioanlity in the USB Subsystem is > - * held in reset.This bit should not be set to '1' > - * until 12ms after phy_clk is stable. Under normal > - * operation, once this bit is set to '1' it should > - * not be set to '0'. > - * @divide: The frequency of 'hclk' used by the USB subsystem > - * is the eclk frequency divided by the value of > - * (DIVIDE2 + 1) * (DIVIDE + 1), also see the field > - * DIVIDE2 of this register. > - * The hclk frequency should be less than 125Mhz. > - * After writing a value to this field the SW should > - * read the field for the value written. > - * The ENABLE field of this register should not be set > - * until AFTER this field is set and then read. > - */ > - struct cvmx_usbnx_clk_ctl_s { > - __BITFIELD_FIELD(u64 reserved_20_63 : 44, > - __BITFIELD_FIELD(u64 divide2 : 2, > - __BITFIELD_FIELD(u64 hclk_rst : 1, > - __BITFIELD_FIELD(u64 p_x_on : 1, > - __BITFIELD_FIELD(u64 p_rtype : 2, > - __BITFIELD_FIELD(u64 p_com_on : 1, > - __BITFIELD_FIELD(u64 p_c_sel : 2, > - __BITFIELD_FIELD(u64 cdiv_byp : 1, > - __BITFIELD_FIELD(u64 sd_mode : 2, > - __BITFIELD_FIELD(u64 s_bist : 1, > - __BITFIELD_FIELD(u64 por : 1, > - __BITFIELD_FIELD(u64 enable : 1, > - __BITFIELD_FIELD(u64 prst : 1, > - __BITFIELD_FIELD(u64 hrst : 1, > - __BITFIELD_FIELD(u64 divide : 3, > - ;))))))))))))))) > - } s; > -}; > - > -/** > - * cvmx_usbn#_usbp_ctl_status > - * > - * USBN_USBP_CTL_STATUS = USBP Control And Status Register > - * > - * Contains general control and status information for the USBN block. > - */ > -union cvmx_usbnx_usbp_ctl_status { > - u64 u64; > - /** > - * struct cvmx_usbnx_usbp_ctl_status_s > - * @txrisetune: HS Transmitter Rise/Fall Time Adjustment > - * @txvreftune: HS DC Voltage Level Adjustment > - * @txfslstune: FS/LS Source Impedance Adjustment > - * @txhsxvtune: Transmitter High-Speed Crossover Adjustment > - * @sqrxtune: Squelch Threshold Adjustment > - * @compdistune: Disconnect Threshold Adjustment > - * @otgtune: VBUS Valid Threshold Adjustment > - * @otgdisable: OTG Block Disable > - * @portreset: Per_Port Reset > - * @drvvbus: Drive VBUS > - * @lsbist: Low-Speed BIST Enable. > - * @fsbist: Full-Speed BIST Enable. > - * @hsbist: High-Speed BIST Enable. > - * @bist_done: PHY Bist Done. > - * Asserted at the end of the PHY BIST sequence. > - * @bist_err: PHY Bist Error. > - * Indicates an internal error was detected during > - * the BIST sequence. > - * @tdata_out: PHY Test Data Out. > - * Presents either internally generated signals or > - * test register contents, based upon the value of > - * test_data_out_sel. > - * @siddq: Drives the USBP (USB-PHY) SIDDQ input. > - * Normally should be set to zero. > - * When customers have no intent to use USB PHY > - * interface, they should: > - * - still provide 3.3V to USB_VDD33, and > - * - tie USB_REXT to 3.3V supply, and > - * - set USBN*_USBP_CTL_STATUS[SIDDQ]=1 > - * @txpreemphasistune: HS Transmitter Pre-Emphasis Enable > - * @dma_bmode: When set to 1 the L2C DMA address will be updated > - * with byte-counts between packets. When set to 0 > - * the L2C DMA address is incremented to the next > - * 4-byte aligned address after adding byte-count. > - * @usbc_end: Bigendian input to the USB Core. This should be > - * set to '0' for operation. > - * @usbp_bist: PHY, This is cleared '0' to run BIST on the USBP. > - * @tclk: PHY Test Clock, used to load TDATA_IN to the USBP. > - * @dp_pulld: PHY DP_PULLDOWN input to the USB-PHY. > - * This signal enables the pull-down resistance on > - * the D+ line. '1' pull down-resistance is connected > - * to D+/ '0' pull down resistance is not connected > - * to D+. When an A/B device is acting as a host > - * (downstream-facing port), dp_pulldown and > - * dm_pulldown are enabled. This must not toggle > - * during normal operation. > - * @dm_pulld: PHY DM_PULLDOWN input to the USB-PHY. > - * This signal enables the pull-down resistance on > - * the D- line. '1' pull down-resistance is connected > - * to D-. '0' pull down resistance is not connected > - * to D-. When an A/B device is acting as a host > - * (downstream-facing port), dp_pulldown and > - * dm_pulldown are enabled. This must not toggle > - * during normal operation. > - * @hst_mode: When '0' the USB is acting as HOST, when '1' > - * USB is acting as device. This field needs to be > - * set while the USB is in reset. > - * @tuning: Transmitter Tuning for High-Speed Operation. > - * Tunes the current supply and rise/fall output > - * times for high-speed operation. > - * [20:19] == 11: Current supply increased > - * approximately 9% > - * [20:19] == 10: Current supply increased > - * approximately 4.5% > - * [20:19] == 01: Design default. > - * [20:19] == 00: Current supply decreased > - * approximately 4.5% > - * [22:21] == 11: Rise and fall times are increased. > - * [22:21] == 10: Design default. > - * [22:21] == 01: Rise and fall times are decreased. > - * [22:21] == 00: Rise and fall times are decreased > - * further as compared to the 01 setting. > - * @tx_bs_enh: Transmit Bit Stuffing on [15:8]. > - * Enables or disables bit stuffing on data[15:8] > - * when bit-stuffing is enabled. > - * @tx_bs_en: Transmit Bit Stuffing on [7:0]. > - * Enables or disables bit stuffing on data[7:0] > - * when bit-stuffing is enabled. > - * @loop_enb: PHY Loopback Test Enable. > - * '1': During data transmission the receive is > - * enabled. > - * '0': During data transmission the receive is > - * disabled. > - * Must be '0' for normal operation. > - * @vtest_enb: Analog Test Pin Enable. > - * '1' The PHY's analog_test pin is enabled for the > - * input and output of applicable analog test signals. > - * '0' THe analog_test pin is disabled. > - * @bist_enb: Built-In Self Test Enable. > - * Used to activate BIST in the PHY. > - * @tdata_sel: Test Data Out Select. > - * '1' test_data_out[3:0] (PHY) register contents > - * are output. '0' internally generated signals are > - * output. > - * @taddr_in: Mode Address for Test Interface. > - * Specifies the register address for writing to or > - * reading from the PHY test interface register. > - * @tdata_in: Internal Testing Register Input Data and Select > - * This is a test bus. Data is present on [3:0], > - * and its corresponding select (enable) is present > - * on bits [7:4]. > - * @ate_reset: Reset input from automatic test equipment. > - * This is a test signal. When the USB Core is > - * powered up (not in Susned Mode), an automatic > - * tester can use this to disable phy_clock and > - * free_clk, then re-enable them with an aligned > - * phase. > - * '1': The phy_clk and free_clk outputs are > - * disabled. "0": The phy_clock and free_clk outputs > - * are available within a specific period after the > - * de-assertion. > - */ > - struct cvmx_usbnx_usbp_ctl_status_s { > - __BITFIELD_FIELD(u64 txrisetune : 1, > - __BITFIELD_FIELD(u64 txvreftune : 4, > - __BITFIELD_FIELD(u64 txfslstune : 4, > - __BITFIELD_FIELD(u64 txhsxvtune : 2, > - __BITFIELD_FIELD(u64 sqrxtune : 3, > - __BITFIELD_FIELD(u64 compdistune : 3, > - __BITFIELD_FIELD(u64 otgtune : 3, > - __BITFIELD_FIELD(u64 otgdisable : 1, > - __BITFIELD_FIELD(u64 portreset : 1, > - __BITFIELD_FIELD(u64 drvvbus : 1, > - __BITFIELD_FIELD(u64 lsbist : 1, > - __BITFIELD_FIELD(u64 fsbist : 1, > - __BITFIELD_FIELD(u64 hsbist : 1, > - __BITFIELD_FIELD(u64 bist_done : 1, > - __BITFIELD_FIELD(u64 bist_err : 1, > - __BITFIELD_FIELD(u64 tdata_out : 4, > - __BITFIELD_FIELD(u64 siddq : 1, > - __BITFIELD_FIELD(u64 txpreemphasistune : 1, > - __BITFIELD_FIELD(u64 dma_bmode : 1, > - __BITFIELD_FIELD(u64 usbc_end : 1, > - __BITFIELD_FIELD(u64 usbp_bist : 1, > - __BITFIELD_FIELD(u64 tclk : 1, > - __BITFIELD_FIELD(u64 dp_pulld : 1, > - __BITFIELD_FIELD(u64 dm_pulld : 1, > - __BITFIELD_FIELD(u64 hst_mode : 1, > - __BITFIELD_FIELD(u64 tuning : 4, > - __BITFIELD_FIELD(u64 tx_bs_enh : 1, > - __BITFIELD_FIELD(u64 tx_bs_en : 1, > - __BITFIELD_FIELD(u64 loop_enb : 1, > - __BITFIELD_FIELD(u64 vtest_enb : 1, > - __BITFIELD_FIELD(u64 bist_enb : 1, > - __BITFIELD_FIELD(u64 tdata_sel : 1, > - __BITFIELD_FIELD(u64 taddr_in : 4, > - __BITFIELD_FIELD(u64 tdata_in : 8, > - __BITFIELD_FIELD(u64 ate_reset : 1, > - ;))))))))))))))))))))))))))))))))))) > - } s; > -}; > - > -#endif /* __OCTEON_HCD_H__ */ _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel