162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
462306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
562306a36Sopenharmony_ci * for more details.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2008 Cavium Networks
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Some parts of the code were originally released under BSD license:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights
1262306a36Sopenharmony_ci * reserved.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
1562306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are
1662306a36Sopenharmony_ci * met:
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci *   * Redistributions of source code must retain the above copyright
1962306a36Sopenharmony_ci *     notice, this list of conditions and the following disclaimer.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci *   * Redistributions in binary form must reproduce the above
2262306a36Sopenharmony_ci *     copyright notice, this list of conditions and the following
2362306a36Sopenharmony_ci *     disclaimer in the documentation and/or other materials provided
2462306a36Sopenharmony_ci *     with the distribution.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci *   * Neither the name of Cavium Networks nor the names of
2762306a36Sopenharmony_ci *     its contributors may be used to endorse or promote products
2862306a36Sopenharmony_ci *     derived from this software without specific prior written
2962306a36Sopenharmony_ci *     permission.
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * This Software, including technical data, may be subject to U.S. export
3262306a36Sopenharmony_ci * control laws, including the U.S. Export Administration Act and its associated
3362306a36Sopenharmony_ci * regulations, and may be subject to export or import regulations in other
3462306a36Sopenharmony_ci * countries.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
3762306a36Sopenharmony_ci * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR
3862306a36Sopenharmony_ci * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
3962306a36Sopenharmony_ci * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION
4062306a36Sopenharmony_ci * OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
4162306a36Sopenharmony_ci * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
4262306a36Sopenharmony_ci * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
4362306a36Sopenharmony_ci * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
4462306a36Sopenharmony_ci * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR
4562306a36Sopenharmony_ci * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#include <linux/usb.h>
4962306a36Sopenharmony_ci#include <linux/slab.h>
5062306a36Sopenharmony_ci#include <linux/module.h>
5162306a36Sopenharmony_ci#include <linux/usb/hcd.h>
5262306a36Sopenharmony_ci#include <linux/prefetch.h>
5362306a36Sopenharmony_ci#include <linux/irqdomain.h>
5462306a36Sopenharmony_ci#include <linux/dma-mapping.h>
5562306a36Sopenharmony_ci#include <linux/platform_device.h>
5662306a36Sopenharmony_ci#include <linux/of.h>
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#include <asm/octeon/octeon.h>
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#include "octeon-hcd.h"
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/**
6362306a36Sopenharmony_ci * enum cvmx_usb_speed - the possible USB device speeds
6462306a36Sopenharmony_ci *
6562306a36Sopenharmony_ci * @CVMX_USB_SPEED_HIGH: Device is operation at 480Mbps
6662306a36Sopenharmony_ci * @CVMX_USB_SPEED_FULL: Device is operation at 12Mbps
6762306a36Sopenharmony_ci * @CVMX_USB_SPEED_LOW:  Device is operation at 1.5Mbps
6862306a36Sopenharmony_ci */
6962306a36Sopenharmony_cienum cvmx_usb_speed {
7062306a36Sopenharmony_ci	CVMX_USB_SPEED_HIGH = 0,
7162306a36Sopenharmony_ci	CVMX_USB_SPEED_FULL = 1,
7262306a36Sopenharmony_ci	CVMX_USB_SPEED_LOW = 2,
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/**
7662306a36Sopenharmony_ci * enum cvmx_usb_transfer - the possible USB transfer types
7762306a36Sopenharmony_ci *
7862306a36Sopenharmony_ci * @CVMX_USB_TRANSFER_CONTROL:	   USB transfer type control for hub and status
7962306a36Sopenharmony_ci *				   transfers
8062306a36Sopenharmony_ci * @CVMX_USB_TRANSFER_ISOCHRONOUS: USB transfer type isochronous for low
8162306a36Sopenharmony_ci *				   priority periodic transfers
8262306a36Sopenharmony_ci * @CVMX_USB_TRANSFER_BULK:	   USB transfer type bulk for large low priority
8362306a36Sopenharmony_ci *				   transfers
8462306a36Sopenharmony_ci * @CVMX_USB_TRANSFER_INTERRUPT:   USB transfer type interrupt for high priority
8562306a36Sopenharmony_ci *				   periodic transfers
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_cienum cvmx_usb_transfer {
8862306a36Sopenharmony_ci	CVMX_USB_TRANSFER_CONTROL = 0,
8962306a36Sopenharmony_ci	CVMX_USB_TRANSFER_ISOCHRONOUS = 1,
9062306a36Sopenharmony_ci	CVMX_USB_TRANSFER_BULK = 2,
9162306a36Sopenharmony_ci	CVMX_USB_TRANSFER_INTERRUPT = 3,
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/**
9562306a36Sopenharmony_ci * enum cvmx_usb_direction - the transfer directions
9662306a36Sopenharmony_ci *
9762306a36Sopenharmony_ci * @CVMX_USB_DIRECTION_OUT: Data is transferring from Octeon to the device/host
9862306a36Sopenharmony_ci * @CVMX_USB_DIRECTION_IN:  Data is transferring from the device/host to Octeon
9962306a36Sopenharmony_ci */
10062306a36Sopenharmony_cienum cvmx_usb_direction {
10162306a36Sopenharmony_ci	CVMX_USB_DIRECTION_OUT,
10262306a36Sopenharmony_ci	CVMX_USB_DIRECTION_IN,
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/**
10662306a36Sopenharmony_ci * enum cvmx_usb_status - possible callback function status codes
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci * @CVMX_USB_STATUS_OK:		  The transaction / operation finished without
10962306a36Sopenharmony_ci *				  any errors
11062306a36Sopenharmony_ci * @CVMX_USB_STATUS_SHORT:	  FIXME: This is currently not implemented
11162306a36Sopenharmony_ci * @CVMX_USB_STATUS_CANCEL:	  The transaction was canceled while in flight
11262306a36Sopenharmony_ci *				  by a user call to cvmx_usb_cancel
11362306a36Sopenharmony_ci * @CVMX_USB_STATUS_ERROR:	  The transaction aborted with an unexpected
11462306a36Sopenharmony_ci *				  error status
11562306a36Sopenharmony_ci * @CVMX_USB_STATUS_STALL:	  The transaction received a USB STALL response
11662306a36Sopenharmony_ci *				  from the device
11762306a36Sopenharmony_ci * @CVMX_USB_STATUS_XACTERR:	  The transaction failed with an error from the
11862306a36Sopenharmony_ci *				  device even after a number of retries
11962306a36Sopenharmony_ci * @CVMX_USB_STATUS_DATATGLERR:	  The transaction failed with a data toggle
12062306a36Sopenharmony_ci *				  error even after a number of retries
12162306a36Sopenharmony_ci * @CVMX_USB_STATUS_BABBLEERR:	  The transaction failed with a babble error
12262306a36Sopenharmony_ci * @CVMX_USB_STATUS_FRAMEERR:	  The transaction failed with a frame error
12362306a36Sopenharmony_ci *				  even after a number of retries
12462306a36Sopenharmony_ci */
12562306a36Sopenharmony_cienum cvmx_usb_status {
12662306a36Sopenharmony_ci	CVMX_USB_STATUS_OK,
12762306a36Sopenharmony_ci	CVMX_USB_STATUS_SHORT,
12862306a36Sopenharmony_ci	CVMX_USB_STATUS_CANCEL,
12962306a36Sopenharmony_ci	CVMX_USB_STATUS_ERROR,
13062306a36Sopenharmony_ci	CVMX_USB_STATUS_STALL,
13162306a36Sopenharmony_ci	CVMX_USB_STATUS_XACTERR,
13262306a36Sopenharmony_ci	CVMX_USB_STATUS_DATATGLERR,
13362306a36Sopenharmony_ci	CVMX_USB_STATUS_BABBLEERR,
13462306a36Sopenharmony_ci	CVMX_USB_STATUS_FRAMEERR,
13562306a36Sopenharmony_ci};
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/**
13862306a36Sopenharmony_ci * struct cvmx_usb_port_status - the USB port status information
13962306a36Sopenharmony_ci *
14062306a36Sopenharmony_ci * @port_enabled:	1 = Usb port is enabled, 0 = disabled
14162306a36Sopenharmony_ci * @port_over_current:	1 = Over current detected, 0 = Over current not
14262306a36Sopenharmony_ci *			detected. Octeon doesn't support over current detection.
14362306a36Sopenharmony_ci * @port_powered:	1 = Port power is being supplied to the device, 0 =
14462306a36Sopenharmony_ci *			power is off. Octeon doesn't support turning port power
14562306a36Sopenharmony_ci *			off.
14662306a36Sopenharmony_ci * @port_speed:		Current port speed.
14762306a36Sopenharmony_ci * @connected:		1 = A device is connected to the port, 0 = No device is
14862306a36Sopenharmony_ci *			connected.
14962306a36Sopenharmony_ci * @connect_change:	1 = Device connected state changed since the last set
15062306a36Sopenharmony_ci *			status call.
15162306a36Sopenharmony_ci */
15262306a36Sopenharmony_cistruct cvmx_usb_port_status {
15362306a36Sopenharmony_ci	u32 reserved			: 25;
15462306a36Sopenharmony_ci	u32 port_enabled		: 1;
15562306a36Sopenharmony_ci	u32 port_over_current		: 1;
15662306a36Sopenharmony_ci	u32 port_powered		: 1;
15762306a36Sopenharmony_ci	enum cvmx_usb_speed port_speed	: 2;
15862306a36Sopenharmony_ci	u32 connected			: 1;
15962306a36Sopenharmony_ci	u32 connect_change		: 1;
16062306a36Sopenharmony_ci};
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci/**
16362306a36Sopenharmony_ci * struct cvmx_usb_iso_packet - descriptor for Isochronous packets
16462306a36Sopenharmony_ci *
16562306a36Sopenharmony_ci * @offset:	This is the offset in bytes into the main buffer where this data
16662306a36Sopenharmony_ci *		is stored.
16762306a36Sopenharmony_ci * @length:	This is the length in bytes of the data.
16862306a36Sopenharmony_ci * @status:	This is the status of this individual packet transfer.
16962306a36Sopenharmony_ci */
17062306a36Sopenharmony_cistruct cvmx_usb_iso_packet {
17162306a36Sopenharmony_ci	int offset;
17262306a36Sopenharmony_ci	int length;
17362306a36Sopenharmony_ci	enum cvmx_usb_status status;
17462306a36Sopenharmony_ci};
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/**
17762306a36Sopenharmony_ci * enum cvmx_usb_initialize_flags - flags used by the initialization function
17862306a36Sopenharmony_ci *
17962306a36Sopenharmony_ci * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI:    The USB port uses a 12MHz crystal
18062306a36Sopenharmony_ci *					      as clock source at USB_XO and
18162306a36Sopenharmony_ci *					      USB_XI.
18262306a36Sopenharmony_ci * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND:   The USB port uses 12/24/48MHz 2.5V
18362306a36Sopenharmony_ci *					      board clock source at USB_XO.
18462306a36Sopenharmony_ci *					      USB_XI should be tied to GND.
18562306a36Sopenharmony_ci * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK: Mask for clock speed field
18662306a36Sopenharmony_ci * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ:    Speed of reference clock or
18762306a36Sopenharmony_ci *					      crystal
18862306a36Sopenharmony_ci * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ:    Speed of reference clock
18962306a36Sopenharmony_ci * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ:    Speed of reference clock
19062306a36Sopenharmony_ci * @CVMX_USB_INITIALIZE_FLAGS_NO_DMA:	      Disable DMA and used polled IO for
19162306a36Sopenharmony_ci *					      data transfer use for the USB
19262306a36Sopenharmony_ci */
19362306a36Sopenharmony_cienum cvmx_usb_initialize_flags {
19462306a36Sopenharmony_ci	CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI		= 1 << 0,
19562306a36Sopenharmony_ci	CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND		= 1 << 1,
19662306a36Sopenharmony_ci	CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK	= 3 << 3,
19762306a36Sopenharmony_ci	CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ		= 1 << 3,
19862306a36Sopenharmony_ci	CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ		= 2 << 3,
19962306a36Sopenharmony_ci	CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ		= 3 << 3,
20062306a36Sopenharmony_ci	/* Bits 3-4 used to encode the clock frequency */
20162306a36Sopenharmony_ci	CVMX_USB_INITIALIZE_FLAGS_NO_DMA		= 1 << 5,
20262306a36Sopenharmony_ci};
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci/**
20562306a36Sopenharmony_ci * enum cvmx_usb_pipe_flags - internal flags for a pipe.
20662306a36Sopenharmony_ci *
20762306a36Sopenharmony_ci * @CVMX_USB_PIPE_FLAGS_SCHEDULED: Used internally to determine if a pipe is
20862306a36Sopenharmony_ci *				   actively using hardware.
20962306a36Sopenharmony_ci * @CVMX_USB_PIPE_FLAGS_NEED_PING: Used internally to determine if a high speed
21062306a36Sopenharmony_ci *				   pipe is in the ping state.
21162306a36Sopenharmony_ci */
21262306a36Sopenharmony_cienum cvmx_usb_pipe_flags {
21362306a36Sopenharmony_ci	CVMX_USB_PIPE_FLAGS_SCHEDULED	= 1 << 17,
21462306a36Sopenharmony_ci	CVMX_USB_PIPE_FLAGS_NEED_PING	= 1 << 18,
21562306a36Sopenharmony_ci};
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/* Maximum number of times to retry failed transactions */
21862306a36Sopenharmony_ci#define MAX_RETRIES		3
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci/* Maximum number of hardware channels supported by the USB block */
22162306a36Sopenharmony_ci#define MAX_CHANNELS		8
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci/*
22462306a36Sopenharmony_ci * The low level hardware can transfer a maximum of this number of bytes in each
22562306a36Sopenharmony_ci * transfer. The field is 19 bits wide
22662306a36Sopenharmony_ci */
22762306a36Sopenharmony_ci#define MAX_TRANSFER_BYTES	((1 << 19) - 1)
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci/*
23062306a36Sopenharmony_ci * The low level hardware can transfer a maximum of this number of packets in
23162306a36Sopenharmony_ci * each transfer. The field is 10 bits wide
23262306a36Sopenharmony_ci */
23362306a36Sopenharmony_ci#define MAX_TRANSFER_PACKETS	((1 << 10) - 1)
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci/**
23662306a36Sopenharmony_ci * Logical transactions may take numerous low level
23762306a36Sopenharmony_ci * transactions, especially when splits are concerned. This
23862306a36Sopenharmony_ci * enum represents all of the possible stages a transaction can
23962306a36Sopenharmony_ci * be in. Note that split completes are always even. This is so
24062306a36Sopenharmony_ci * the NAK handler can backup to the previous low level
24162306a36Sopenharmony_ci * transaction with a simple clearing of bit 0.
24262306a36Sopenharmony_ci */
24362306a36Sopenharmony_cienum cvmx_usb_stage {
24462306a36Sopenharmony_ci	CVMX_USB_STAGE_NON_CONTROL,
24562306a36Sopenharmony_ci	CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE,
24662306a36Sopenharmony_ci	CVMX_USB_STAGE_SETUP,
24762306a36Sopenharmony_ci	CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE,
24862306a36Sopenharmony_ci	CVMX_USB_STAGE_DATA,
24962306a36Sopenharmony_ci	CVMX_USB_STAGE_DATA_SPLIT_COMPLETE,
25062306a36Sopenharmony_ci	CVMX_USB_STAGE_STATUS,
25162306a36Sopenharmony_ci	CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE,
25262306a36Sopenharmony_ci};
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci/**
25562306a36Sopenharmony_ci * struct cvmx_usb_transaction - describes each pending USB transaction
25662306a36Sopenharmony_ci *				 regardless of type. These are linked together
25762306a36Sopenharmony_ci *				 to form a list of pending requests for a pipe.
25862306a36Sopenharmony_ci *
25962306a36Sopenharmony_ci * @node:		List node for transactions in the pipe.
26062306a36Sopenharmony_ci * @type:		Type of transaction, duplicated of the pipe.
26162306a36Sopenharmony_ci * @flags:		State flags for this transaction.
26262306a36Sopenharmony_ci * @buffer:		User's physical buffer address to read/write.
26362306a36Sopenharmony_ci * @buffer_length:	Size of the user's buffer in bytes.
26462306a36Sopenharmony_ci * @control_header:	For control transactions, physical address of the 8
26562306a36Sopenharmony_ci *			byte standard header.
26662306a36Sopenharmony_ci * @iso_start_frame:	For ISO transactions, the starting frame number.
26762306a36Sopenharmony_ci * @iso_number_packets:	For ISO transactions, the number of packets in the
26862306a36Sopenharmony_ci *			request.
26962306a36Sopenharmony_ci * @iso_packets:	For ISO transactions, the sub packets in the request.
27062306a36Sopenharmony_ci * @actual_bytes:	Actual bytes transfer for this transaction.
27162306a36Sopenharmony_ci * @stage:		For control transactions, the current stage.
27262306a36Sopenharmony_ci * @urb:		URB.
27362306a36Sopenharmony_ci */
27462306a36Sopenharmony_cistruct cvmx_usb_transaction {
27562306a36Sopenharmony_ci	struct list_head node;
27662306a36Sopenharmony_ci	enum cvmx_usb_transfer type;
27762306a36Sopenharmony_ci	u64 buffer;
27862306a36Sopenharmony_ci	int buffer_length;
27962306a36Sopenharmony_ci	u64 control_header;
28062306a36Sopenharmony_ci	int iso_start_frame;
28162306a36Sopenharmony_ci	int iso_number_packets;
28262306a36Sopenharmony_ci	struct cvmx_usb_iso_packet *iso_packets;
28362306a36Sopenharmony_ci	int xfersize;
28462306a36Sopenharmony_ci	int pktcnt;
28562306a36Sopenharmony_ci	int retries;
28662306a36Sopenharmony_ci	int actual_bytes;
28762306a36Sopenharmony_ci	enum cvmx_usb_stage stage;
28862306a36Sopenharmony_ci	struct urb *urb;
28962306a36Sopenharmony_ci};
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/**
29262306a36Sopenharmony_ci * struct cvmx_usb_pipe - a pipe represents a virtual connection between Octeon
29362306a36Sopenharmony_ci *			  and some USB device. It contains a list of pending
29462306a36Sopenharmony_ci *			  request to the device.
29562306a36Sopenharmony_ci *
29662306a36Sopenharmony_ci * @node:		List node for pipe list
29762306a36Sopenharmony_ci * @next:		Pipe after this one in the list
29862306a36Sopenharmony_ci * @transactions:	List of pending transactions
29962306a36Sopenharmony_ci * @interval:		For periodic pipes, the interval between packets in
30062306a36Sopenharmony_ci *			frames
30162306a36Sopenharmony_ci * @next_tx_frame:	The next frame this pipe is allowed to transmit on
30262306a36Sopenharmony_ci * @flags:		State flags for this pipe
30362306a36Sopenharmony_ci * @device_speed:	Speed of device connected to this pipe
30462306a36Sopenharmony_ci * @transfer_type:	Type of transaction supported by this pipe
30562306a36Sopenharmony_ci * @transfer_dir:	IN or OUT. Ignored for Control
30662306a36Sopenharmony_ci * @multi_count:	Max packet in a row for the device
30762306a36Sopenharmony_ci * @max_packet:		The device's maximum packet size in bytes
30862306a36Sopenharmony_ci * @device_addr:	USB device address at other end of pipe
30962306a36Sopenharmony_ci * @endpoint_num:	USB endpoint number at other end of pipe
31062306a36Sopenharmony_ci * @hub_device_addr:	Hub address this device is connected to
31162306a36Sopenharmony_ci * @hub_port:		Hub port this device is connected to
31262306a36Sopenharmony_ci * @pid_toggle:		This toggles between 0/1 on every packet send to track
31362306a36Sopenharmony_ci *			the data pid needed
31462306a36Sopenharmony_ci * @channel:		Hardware DMA channel for this pipe
31562306a36Sopenharmony_ci * @split_sc_frame:	The low order bits of the frame number the split
31662306a36Sopenharmony_ci *			complete should be sent on
31762306a36Sopenharmony_ci */
31862306a36Sopenharmony_cistruct cvmx_usb_pipe {
31962306a36Sopenharmony_ci	struct list_head node;
32062306a36Sopenharmony_ci	struct list_head transactions;
32162306a36Sopenharmony_ci	u64 interval;
32262306a36Sopenharmony_ci	u64 next_tx_frame;
32362306a36Sopenharmony_ci	enum cvmx_usb_pipe_flags flags;
32462306a36Sopenharmony_ci	enum cvmx_usb_speed device_speed;
32562306a36Sopenharmony_ci	enum cvmx_usb_transfer transfer_type;
32662306a36Sopenharmony_ci	enum cvmx_usb_direction transfer_dir;
32762306a36Sopenharmony_ci	int multi_count;
32862306a36Sopenharmony_ci	u16 max_packet;
32962306a36Sopenharmony_ci	u8 device_addr;
33062306a36Sopenharmony_ci	u8 endpoint_num;
33162306a36Sopenharmony_ci	u8 hub_device_addr;
33262306a36Sopenharmony_ci	u8 hub_port;
33362306a36Sopenharmony_ci	u8 pid_toggle;
33462306a36Sopenharmony_ci	u8 channel;
33562306a36Sopenharmony_ci	s8 split_sc_frame;
33662306a36Sopenharmony_ci};
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistruct cvmx_usb_tx_fifo {
33962306a36Sopenharmony_ci	struct {
34062306a36Sopenharmony_ci		int channel;
34162306a36Sopenharmony_ci		int size;
34262306a36Sopenharmony_ci		u64 address;
34362306a36Sopenharmony_ci	} entry[MAX_CHANNELS + 1];
34462306a36Sopenharmony_ci	int head;
34562306a36Sopenharmony_ci	int tail;
34662306a36Sopenharmony_ci};
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci/**
34962306a36Sopenharmony_ci * struct octeon_hcd - the state of the USB block
35062306a36Sopenharmony_ci *
35162306a36Sopenharmony_ci * lock:		   Serialization lock.
35262306a36Sopenharmony_ci * init_flags:		   Flags passed to initialize.
35362306a36Sopenharmony_ci * index:		   Which USB block this is for.
35462306a36Sopenharmony_ci * idle_hardware_channels: Bit set for every idle hardware channel.
35562306a36Sopenharmony_ci * usbcx_hprt:		   Stored port status so we don't need to read a CSR to
35662306a36Sopenharmony_ci *			   determine splits.
35762306a36Sopenharmony_ci * pipe_for_channel:	   Map channels to pipes.
35862306a36Sopenharmony_ci * pipe:		   Storage for pipes.
35962306a36Sopenharmony_ci * indent:		   Used by debug output to indent functions.
36062306a36Sopenharmony_ci * port_status:		   Last port status used for change notification.
36162306a36Sopenharmony_ci * idle_pipes:		   List of open pipes that have no transactions.
36262306a36Sopenharmony_ci * active_pipes:	   Active pipes indexed by transfer type.
36362306a36Sopenharmony_ci * frame_number:	   Increments every SOF interrupt for time keeping.
36462306a36Sopenharmony_ci * active_split:	   Points to the current active split, or NULL.
36562306a36Sopenharmony_ci */
36662306a36Sopenharmony_cistruct octeon_hcd {
36762306a36Sopenharmony_ci	spinlock_t lock; /* serialization lock */
36862306a36Sopenharmony_ci	int init_flags;
36962306a36Sopenharmony_ci	int index;
37062306a36Sopenharmony_ci	int idle_hardware_channels;
37162306a36Sopenharmony_ci	union cvmx_usbcx_hprt usbcx_hprt;
37262306a36Sopenharmony_ci	struct cvmx_usb_pipe *pipe_for_channel[MAX_CHANNELS];
37362306a36Sopenharmony_ci	int indent;
37462306a36Sopenharmony_ci	struct cvmx_usb_port_status port_status;
37562306a36Sopenharmony_ci	struct list_head idle_pipes;
37662306a36Sopenharmony_ci	struct list_head active_pipes[4];
37762306a36Sopenharmony_ci	u64 frame_number;
37862306a36Sopenharmony_ci	struct cvmx_usb_transaction *active_split;
37962306a36Sopenharmony_ci	struct cvmx_usb_tx_fifo periodic;
38062306a36Sopenharmony_ci	struct cvmx_usb_tx_fifo nonperiodic;
38162306a36Sopenharmony_ci};
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci/*
38462306a36Sopenharmony_ci * This macro logically sets a single field in a CSR. It does the sequence
38562306a36Sopenharmony_ci * read, modify, and write
38662306a36Sopenharmony_ci */
38762306a36Sopenharmony_ci#define USB_SET_FIELD32(address, _union, field, value)		\
38862306a36Sopenharmony_ci	do {							\
38962306a36Sopenharmony_ci		union _union c;					\
39062306a36Sopenharmony_ci								\
39162306a36Sopenharmony_ci		c.u32 = cvmx_usb_read_csr32(usb, address);	\
39262306a36Sopenharmony_ci		c.s.field = value;				\
39362306a36Sopenharmony_ci		cvmx_usb_write_csr32(usb, address, c.u32);	\
39462306a36Sopenharmony_ci	} while (0)
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci/* Returns the IO address to push/pop stuff data from the FIFOs */
39762306a36Sopenharmony_ci#define USB_FIFO_ADDRESS(channel, usb_index) \
39862306a36Sopenharmony_ci	(CVMX_USBCX_GOTGCTL(usb_index) + ((channel) + 1) * 0x1000)
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci/**
40162306a36Sopenharmony_ci * struct octeon_temp_buffer - a bounce buffer for USB transfers
40262306a36Sopenharmony_ci * @orig_buffer: the original buffer passed by the USB stack
40362306a36Sopenharmony_ci * @data:	 the newly allocated temporary buffer (excluding meta-data)
40462306a36Sopenharmony_ci *
40562306a36Sopenharmony_ci * Both the DMA engine and FIFO mode will always transfer full 32-bit words. If
40662306a36Sopenharmony_ci * the buffer is too short, we need to allocate a temporary one, and this struct
40762306a36Sopenharmony_ci * represents it.
40862306a36Sopenharmony_ci */
40962306a36Sopenharmony_cistruct octeon_temp_buffer {
41062306a36Sopenharmony_ci	void *orig_buffer;
41162306a36Sopenharmony_ci	u8 data[];
41262306a36Sopenharmony_ci};
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic inline struct usb_hcd *octeon_to_hcd(struct octeon_hcd *p)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	return container_of((void *)p, struct usb_hcd, hcd_priv);
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci/**
42062306a36Sopenharmony_ci * octeon_alloc_temp_buffer - allocate a temporary buffer for USB transfer
42162306a36Sopenharmony_ci *                            (if needed)
42262306a36Sopenharmony_ci * @urb:	URB.
42362306a36Sopenharmony_ci * @mem_flags:	Memory allocation flags.
42462306a36Sopenharmony_ci *
42562306a36Sopenharmony_ci * This function allocates a temporary bounce buffer whenever it's needed
42662306a36Sopenharmony_ci * due to HW limitations.
42762306a36Sopenharmony_ci */
42862306a36Sopenharmony_cistatic int octeon_alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	struct octeon_temp_buffer *temp;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	if (urb->num_sgs || urb->sg ||
43362306a36Sopenharmony_ci	    (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) ||
43462306a36Sopenharmony_ci	    !(urb->transfer_buffer_length % sizeof(u32)))
43562306a36Sopenharmony_ci		return 0;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	temp = kmalloc(ALIGN(urb->transfer_buffer_length, sizeof(u32)) +
43862306a36Sopenharmony_ci		       sizeof(*temp), mem_flags);
43962306a36Sopenharmony_ci	if (!temp)
44062306a36Sopenharmony_ci		return -ENOMEM;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	temp->orig_buffer = urb->transfer_buffer;
44362306a36Sopenharmony_ci	if (usb_urb_dir_out(urb))
44462306a36Sopenharmony_ci		memcpy(temp->data, urb->transfer_buffer,
44562306a36Sopenharmony_ci		       urb->transfer_buffer_length);
44662306a36Sopenharmony_ci	urb->transfer_buffer = temp->data;
44762306a36Sopenharmony_ci	urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	return 0;
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci/**
45362306a36Sopenharmony_ci * octeon_free_temp_buffer - free a temporary buffer used by USB transfers.
45462306a36Sopenharmony_ci * @urb: URB.
45562306a36Sopenharmony_ci *
45662306a36Sopenharmony_ci * Frees a buffer allocated by octeon_alloc_temp_buffer().
45762306a36Sopenharmony_ci */
45862306a36Sopenharmony_cistatic void octeon_free_temp_buffer(struct urb *urb)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	struct octeon_temp_buffer *temp;
46162306a36Sopenharmony_ci	size_t length;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
46462306a36Sopenharmony_ci		return;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	temp = container_of(urb->transfer_buffer, struct octeon_temp_buffer,
46762306a36Sopenharmony_ci			    data);
46862306a36Sopenharmony_ci	if (usb_urb_dir_in(urb)) {
46962306a36Sopenharmony_ci		if (usb_pipeisoc(urb->pipe))
47062306a36Sopenharmony_ci			length = urb->transfer_buffer_length;
47162306a36Sopenharmony_ci		else
47262306a36Sopenharmony_ci			length = urb->actual_length;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci		memcpy(temp->orig_buffer, urb->transfer_buffer, length);
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci	urb->transfer_buffer = temp->orig_buffer;
47762306a36Sopenharmony_ci	urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
47862306a36Sopenharmony_ci	kfree(temp);
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci/**
48262306a36Sopenharmony_ci * octeon_map_urb_for_dma - Octeon-specific map_urb_for_dma().
48362306a36Sopenharmony_ci * @hcd:	USB HCD structure.
48462306a36Sopenharmony_ci * @urb:	URB.
48562306a36Sopenharmony_ci * @mem_flags:	Memory allocation flags.
48662306a36Sopenharmony_ci */
48762306a36Sopenharmony_cistatic int octeon_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
48862306a36Sopenharmony_ci				  gfp_t mem_flags)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	int ret;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	ret = octeon_alloc_temp_buffer(urb, mem_flags);
49362306a36Sopenharmony_ci	if (ret)
49462306a36Sopenharmony_ci		return ret;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
49762306a36Sopenharmony_ci	if (ret)
49862306a36Sopenharmony_ci		octeon_free_temp_buffer(urb);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	return ret;
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci/**
50462306a36Sopenharmony_ci * octeon_unmap_urb_for_dma - Octeon-specific unmap_urb_for_dma()
50562306a36Sopenharmony_ci * @hcd:	USB HCD structure.
50662306a36Sopenharmony_ci * @urb:	URB.
50762306a36Sopenharmony_ci */
50862306a36Sopenharmony_cistatic void octeon_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	usb_hcd_unmap_urb_for_dma(hcd, urb);
51162306a36Sopenharmony_ci	octeon_free_temp_buffer(urb);
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci/**
51562306a36Sopenharmony_ci * Read a USB 32bit CSR. It performs the necessary address swizzle
51662306a36Sopenharmony_ci * for 32bit CSRs and logs the value in a readable format if
51762306a36Sopenharmony_ci * debugging is on.
51862306a36Sopenharmony_ci *
51962306a36Sopenharmony_ci * @usb:     USB block this access is for
52062306a36Sopenharmony_ci * @address: 64bit address to read
52162306a36Sopenharmony_ci *
52262306a36Sopenharmony_ci * Returns: Result of the read
52362306a36Sopenharmony_ci */
52462306a36Sopenharmony_cistatic inline u32 cvmx_usb_read_csr32(struct octeon_hcd *usb, u64 address)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	return cvmx_read64_uint32(address ^ 4);
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci/**
53062306a36Sopenharmony_ci * Write a USB 32bit CSR. It performs the necessary address
53162306a36Sopenharmony_ci * swizzle for 32bit CSRs and logs the value in a readable format
53262306a36Sopenharmony_ci * if debugging is on.
53362306a36Sopenharmony_ci *
53462306a36Sopenharmony_ci * @usb:     USB block this access is for
53562306a36Sopenharmony_ci * @address: 64bit address to write
53662306a36Sopenharmony_ci * @value:   Value to write
53762306a36Sopenharmony_ci */
53862306a36Sopenharmony_cistatic inline void cvmx_usb_write_csr32(struct octeon_hcd *usb,
53962306a36Sopenharmony_ci					u64 address, u32 value)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	cvmx_write64_uint32(address ^ 4, value);
54262306a36Sopenharmony_ci	cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci/**
54662306a36Sopenharmony_ci * Return non zero if this pipe connects to a non HIGH speed
54762306a36Sopenharmony_ci * device through a high speed hub.
54862306a36Sopenharmony_ci *
54962306a36Sopenharmony_ci * @usb:    USB block this access is for
55062306a36Sopenharmony_ci * @pipe:   Pipe to check
55162306a36Sopenharmony_ci *
55262306a36Sopenharmony_ci * Returns: Non zero if we need to do split transactions
55362306a36Sopenharmony_ci */
55462306a36Sopenharmony_cistatic inline int cvmx_usb_pipe_needs_split(struct octeon_hcd *usb,
55562306a36Sopenharmony_ci					    struct cvmx_usb_pipe *pipe)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	return pipe->device_speed != CVMX_USB_SPEED_HIGH &&
55862306a36Sopenharmony_ci	       usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci/**
56262306a36Sopenharmony_ci * Trivial utility function to return the correct PID for a pipe
56362306a36Sopenharmony_ci *
56462306a36Sopenharmony_ci * @pipe:   pipe to check
56562306a36Sopenharmony_ci *
56662306a36Sopenharmony_ci * Returns: PID for pipe
56762306a36Sopenharmony_ci */
56862306a36Sopenharmony_cistatic inline int cvmx_usb_get_data_pid(struct cvmx_usb_pipe *pipe)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	if (pipe->pid_toggle)
57162306a36Sopenharmony_ci		return 2; /* Data1 */
57262306a36Sopenharmony_ci	return 0; /* Data0 */
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci/* Loops through register until txfflsh or rxfflsh become zero.*/
57662306a36Sopenharmony_cistatic int cvmx_wait_tx_rx(struct octeon_hcd *usb, int fflsh_type)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	int result;
57962306a36Sopenharmony_ci	u64 address = CVMX_USBCX_GRSTCTL(usb->index);
58062306a36Sopenharmony_ci	u64 done = cvmx_get_cycle() + 100 *
58162306a36Sopenharmony_ci		   (u64)octeon_get_clock_rate / 1000000;
58262306a36Sopenharmony_ci	union cvmx_usbcx_grstctl c;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	while (1) {
58562306a36Sopenharmony_ci		c.u32 = cvmx_usb_read_csr32(usb, address);
58662306a36Sopenharmony_ci		if (fflsh_type == 0 && c.s.txfflsh == 0) {
58762306a36Sopenharmony_ci			result = 0;
58862306a36Sopenharmony_ci			break;
58962306a36Sopenharmony_ci		} else if (fflsh_type == 1 && c.s.rxfflsh == 0) {
59062306a36Sopenharmony_ci			result = 0;
59162306a36Sopenharmony_ci			break;
59262306a36Sopenharmony_ci		} else if (cvmx_get_cycle() > done) {
59362306a36Sopenharmony_ci			result = -1;
59462306a36Sopenharmony_ci			break;
59562306a36Sopenharmony_ci		}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci		__delay(100);
59862306a36Sopenharmony_ci	}
59962306a36Sopenharmony_ci	return result;
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_cistatic void cvmx_fifo_setup(struct octeon_hcd *usb)
60362306a36Sopenharmony_ci{
60462306a36Sopenharmony_ci	union cvmx_usbcx_ghwcfg3 usbcx_ghwcfg3;
60562306a36Sopenharmony_ci	union cvmx_usbcx_gnptxfsiz npsiz;
60662306a36Sopenharmony_ci	union cvmx_usbcx_hptxfsiz psiz;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	usbcx_ghwcfg3.u32 = cvmx_usb_read_csr32(usb,
60962306a36Sopenharmony_ci						CVMX_USBCX_GHWCFG3(usb->index));
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	/*
61262306a36Sopenharmony_ci	 * Program the USBC_GRXFSIZ register to select the size of the receive
61362306a36Sopenharmony_ci	 * FIFO (25%).
61462306a36Sopenharmony_ci	 */
61562306a36Sopenharmony_ci	USB_SET_FIELD32(CVMX_USBCX_GRXFSIZ(usb->index), cvmx_usbcx_grxfsiz,
61662306a36Sopenharmony_ci			rxfdep, usbcx_ghwcfg3.s.dfifodepth / 4);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/*
61962306a36Sopenharmony_ci	 * Program the USBC_GNPTXFSIZ register to select the size and the start
62062306a36Sopenharmony_ci	 * address of the non-periodic transmit FIFO for nonperiodic
62162306a36Sopenharmony_ci	 * transactions (50%).
62262306a36Sopenharmony_ci	 */
62362306a36Sopenharmony_ci	npsiz.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index));
62462306a36Sopenharmony_ci	npsiz.s.nptxfdep = usbcx_ghwcfg3.s.dfifodepth / 2;
62562306a36Sopenharmony_ci	npsiz.s.nptxfstaddr = usbcx_ghwcfg3.s.dfifodepth / 4;
62662306a36Sopenharmony_ci	cvmx_usb_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index), npsiz.u32);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	/*
62962306a36Sopenharmony_ci	 * Program the USBC_HPTXFSIZ register to select the size and start
63062306a36Sopenharmony_ci	 * address of the periodic transmit FIFO for periodic transactions
63162306a36Sopenharmony_ci	 * (25%).
63262306a36Sopenharmony_ci	 */
63362306a36Sopenharmony_ci	psiz.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index));
63462306a36Sopenharmony_ci	psiz.s.ptxfsize = usbcx_ghwcfg3.s.dfifodepth / 4;
63562306a36Sopenharmony_ci	psiz.s.ptxfstaddr = 3 * usbcx_ghwcfg3.s.dfifodepth / 4;
63662306a36Sopenharmony_ci	cvmx_usb_write_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index), psiz.u32);
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	/* Flush all FIFOs */
63962306a36Sopenharmony_ci	USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
64062306a36Sopenharmony_ci			cvmx_usbcx_grstctl, txfnum, 0x10);
64162306a36Sopenharmony_ci	USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
64262306a36Sopenharmony_ci			cvmx_usbcx_grstctl, txfflsh, 1);
64362306a36Sopenharmony_ci	cvmx_wait_tx_rx(usb, 0);
64462306a36Sopenharmony_ci	USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
64562306a36Sopenharmony_ci			cvmx_usbcx_grstctl, rxfflsh, 1);
64662306a36Sopenharmony_ci	cvmx_wait_tx_rx(usb, 1);
64762306a36Sopenharmony_ci}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci/**
65062306a36Sopenharmony_ci * Shutdown a USB port after a call to cvmx_usb_initialize().
65162306a36Sopenharmony_ci * The port should be disabled with all pipes closed when this
65262306a36Sopenharmony_ci * function is called.
65362306a36Sopenharmony_ci *
65462306a36Sopenharmony_ci * @usb: USB device state populated by cvmx_usb_initialize().
65562306a36Sopenharmony_ci *
65662306a36Sopenharmony_ci * Returns: 0 or a negative error code.
65762306a36Sopenharmony_ci */
65862306a36Sopenharmony_cistatic int cvmx_usb_shutdown(struct octeon_hcd *usb)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	union cvmx_usbnx_clk_ctl usbn_clk_ctl;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	/* Make sure all pipes are closed */
66362306a36Sopenharmony_ci	if (!list_empty(&usb->idle_pipes) ||
66462306a36Sopenharmony_ci	    !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_ISOCHRONOUS]) ||
66562306a36Sopenharmony_ci	    !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_INTERRUPT]) ||
66662306a36Sopenharmony_ci	    !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_CONTROL]) ||
66762306a36Sopenharmony_ci	    !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_BULK]))
66862306a36Sopenharmony_ci		return -EBUSY;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	/* Disable the clocks and put them in power on reset */
67162306a36Sopenharmony_ci	usbn_clk_ctl.u64 = cvmx_read64_uint64(CVMX_USBNX_CLK_CTL(usb->index));
67262306a36Sopenharmony_ci	usbn_clk_ctl.s.enable = 1;
67362306a36Sopenharmony_ci	usbn_clk_ctl.s.por = 1;
67462306a36Sopenharmony_ci	usbn_clk_ctl.s.hclk_rst = 1;
67562306a36Sopenharmony_ci	usbn_clk_ctl.s.prst = 0;
67662306a36Sopenharmony_ci	usbn_clk_ctl.s.hrst = 0;
67762306a36Sopenharmony_ci	cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
67862306a36Sopenharmony_ci	return 0;
67962306a36Sopenharmony_ci}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci/**
68262306a36Sopenharmony_ci * Initialize a USB port for use. This must be called before any
68362306a36Sopenharmony_ci * other access to the Octeon USB port is made. The port starts
68462306a36Sopenharmony_ci * off in the disabled state.
68562306a36Sopenharmony_ci *
68662306a36Sopenharmony_ci * @dev:	 Pointer to struct device for logging purposes.
68762306a36Sopenharmony_ci * @usb:	 Pointer to struct octeon_hcd.
68862306a36Sopenharmony_ci *
68962306a36Sopenharmony_ci * Returns: 0 or a negative error code.
69062306a36Sopenharmony_ci */
69162306a36Sopenharmony_cistatic int cvmx_usb_initialize(struct device *dev,
69262306a36Sopenharmony_ci			       struct octeon_hcd *usb)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	int channel;
69562306a36Sopenharmony_ci	int divisor;
69662306a36Sopenharmony_ci	int retries = 0;
69762306a36Sopenharmony_ci	union cvmx_usbcx_hcfg usbcx_hcfg;
69862306a36Sopenharmony_ci	union cvmx_usbnx_clk_ctl usbn_clk_ctl;
69962306a36Sopenharmony_ci	union cvmx_usbcx_gintsts usbc_gintsts;
70062306a36Sopenharmony_ci	union cvmx_usbcx_gahbcfg usbcx_gahbcfg;
70162306a36Sopenharmony_ci	union cvmx_usbcx_gintmsk usbcx_gintmsk;
70262306a36Sopenharmony_ci	union cvmx_usbcx_gusbcfg usbcx_gusbcfg;
70362306a36Sopenharmony_ci	union cvmx_usbnx_usbp_ctl_status usbn_usbp_ctl_status;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ciretry:
70662306a36Sopenharmony_ci	/*
70762306a36Sopenharmony_ci	 * Power On Reset and PHY Initialization
70862306a36Sopenharmony_ci	 *
70962306a36Sopenharmony_ci	 * 1. Wait for DCOK to assert (nothing to do)
71062306a36Sopenharmony_ci	 *
71162306a36Sopenharmony_ci	 * 2a. Write USBN0/1_CLK_CTL[POR] = 1 and
71262306a36Sopenharmony_ci	 *     USBN0/1_CLK_CTL[HRST,PRST,HCLK_RST] = 0
71362306a36Sopenharmony_ci	 */
71462306a36Sopenharmony_ci	usbn_clk_ctl.u64 = cvmx_read64_uint64(CVMX_USBNX_CLK_CTL(usb->index));
71562306a36Sopenharmony_ci	usbn_clk_ctl.s.por = 1;
71662306a36Sopenharmony_ci	usbn_clk_ctl.s.hrst = 0;
71762306a36Sopenharmony_ci	usbn_clk_ctl.s.prst = 0;
71862306a36Sopenharmony_ci	usbn_clk_ctl.s.hclk_rst = 0;
71962306a36Sopenharmony_ci	usbn_clk_ctl.s.enable = 0;
72062306a36Sopenharmony_ci	/*
72162306a36Sopenharmony_ci	 * 2b. Select the USB reference clock/crystal parameters by writing
72262306a36Sopenharmony_ci	 *     appropriate values to USBN0/1_CLK_CTL[P_C_SEL, P_RTYPE, P_COM_ON]
72362306a36Sopenharmony_ci	 */
72462306a36Sopenharmony_ci	if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) {
72562306a36Sopenharmony_ci		/*
72662306a36Sopenharmony_ci		 * The USB port uses 12/24/48MHz 2.5V board clock
72762306a36Sopenharmony_ci		 * source at USB_XO. USB_XI should be tied to GND.
72862306a36Sopenharmony_ci		 * Most Octeon evaluation boards require this setting
72962306a36Sopenharmony_ci		 */
73062306a36Sopenharmony_ci		if (OCTEON_IS_MODEL(OCTEON_CN3XXX) ||
73162306a36Sopenharmony_ci		    OCTEON_IS_MODEL(OCTEON_CN56XX) ||
73262306a36Sopenharmony_ci		    OCTEON_IS_MODEL(OCTEON_CN50XX))
73362306a36Sopenharmony_ci			/* From CN56XX,CN50XX,CN31XX,CN30XX manuals */
73462306a36Sopenharmony_ci			usbn_clk_ctl.s.p_rtype = 2; /* p_rclk=1 & p_xenbn=0 */
73562306a36Sopenharmony_ci		else
73662306a36Sopenharmony_ci			/* From CN52XX manual */
73762306a36Sopenharmony_ci			usbn_clk_ctl.s.p_rtype = 1;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci		switch (usb->init_flags &
74062306a36Sopenharmony_ci			CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK) {
74162306a36Sopenharmony_ci		case CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ:
74262306a36Sopenharmony_ci			usbn_clk_ctl.s.p_c_sel = 0;
74362306a36Sopenharmony_ci			break;
74462306a36Sopenharmony_ci		case CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ:
74562306a36Sopenharmony_ci			usbn_clk_ctl.s.p_c_sel = 1;
74662306a36Sopenharmony_ci			break;
74762306a36Sopenharmony_ci		case CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ:
74862306a36Sopenharmony_ci			usbn_clk_ctl.s.p_c_sel = 2;
74962306a36Sopenharmony_ci			break;
75062306a36Sopenharmony_ci		}
75162306a36Sopenharmony_ci	} else {
75262306a36Sopenharmony_ci		/*
75362306a36Sopenharmony_ci		 * The USB port uses a 12MHz crystal as clock source
75462306a36Sopenharmony_ci		 * at USB_XO and USB_XI
75562306a36Sopenharmony_ci		 */
75662306a36Sopenharmony_ci		if (OCTEON_IS_MODEL(OCTEON_CN3XXX))
75762306a36Sopenharmony_ci			/* From CN31XX,CN30XX manual */
75862306a36Sopenharmony_ci			usbn_clk_ctl.s.p_rtype = 3; /* p_rclk=1 & p_xenbn=1 */
75962306a36Sopenharmony_ci		else
76062306a36Sopenharmony_ci			/* From CN56XX,CN52XX,CN50XX manuals. */
76162306a36Sopenharmony_ci			usbn_clk_ctl.s.p_rtype = 0;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci		usbn_clk_ctl.s.p_c_sel = 0;
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci	/*
76662306a36Sopenharmony_ci	 * 2c. Select the HCLK via writing USBN0/1_CLK_CTL[DIVIDE, DIVIDE2] and
76762306a36Sopenharmony_ci	 *     setting USBN0/1_CLK_CTL[ENABLE] = 1. Divide the core clock down
76862306a36Sopenharmony_ci	 *     such that USB is as close as possible to 125Mhz
76962306a36Sopenharmony_ci	 */
77062306a36Sopenharmony_ci	divisor = DIV_ROUND_UP(octeon_get_clock_rate(), 125000000);
77162306a36Sopenharmony_ci	/* Lower than 4 doesn't seem to work properly */
77262306a36Sopenharmony_ci	if (divisor < 4)
77362306a36Sopenharmony_ci		divisor = 4;
77462306a36Sopenharmony_ci	usbn_clk_ctl.s.divide = divisor;
77562306a36Sopenharmony_ci	usbn_clk_ctl.s.divide2 = 0;
77662306a36Sopenharmony_ci	cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	/* 2d. Write USBN0/1_CLK_CTL[HCLK_RST] = 1 */
77962306a36Sopenharmony_ci	usbn_clk_ctl.s.hclk_rst = 1;
78062306a36Sopenharmony_ci	cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
78162306a36Sopenharmony_ci	/* 2e.  Wait 64 core-clock cycles for HCLK to stabilize */
78262306a36Sopenharmony_ci	__delay(64);
78362306a36Sopenharmony_ci	/*
78462306a36Sopenharmony_ci	 * 3. Program the power-on reset field in the USBN clock-control
78562306a36Sopenharmony_ci	 *    register:
78662306a36Sopenharmony_ci	 *    USBN_CLK_CTL[POR] = 0
78762306a36Sopenharmony_ci	 */
78862306a36Sopenharmony_ci	usbn_clk_ctl.s.por = 0;
78962306a36Sopenharmony_ci	cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
79062306a36Sopenharmony_ci	/* 4. Wait 1 ms for PHY clock to start */
79162306a36Sopenharmony_ci	mdelay(1);
79262306a36Sopenharmony_ci	/*
79362306a36Sopenharmony_ci	 * 5. Program the Reset input from automatic test equipment field in the
79462306a36Sopenharmony_ci	 *    USBP control and status register:
79562306a36Sopenharmony_ci	 *    USBN_USBP_CTL_STATUS[ATE_RESET] = 1
79662306a36Sopenharmony_ci	 */
79762306a36Sopenharmony_ci	usbn_usbp_ctl_status.u64 =
79862306a36Sopenharmony_ci		cvmx_read64_uint64(CVMX_USBNX_USBP_CTL_STATUS(usb->index));
79962306a36Sopenharmony_ci	usbn_usbp_ctl_status.s.ate_reset = 1;
80062306a36Sopenharmony_ci	cvmx_write64_uint64(CVMX_USBNX_USBP_CTL_STATUS(usb->index),
80162306a36Sopenharmony_ci			    usbn_usbp_ctl_status.u64);
80262306a36Sopenharmony_ci	/* 6. Wait 10 cycles */
80362306a36Sopenharmony_ci	__delay(10);
80462306a36Sopenharmony_ci	/*
80562306a36Sopenharmony_ci	 * 7. Clear ATE_RESET field in the USBN clock-control register:
80662306a36Sopenharmony_ci	 *    USBN_USBP_CTL_STATUS[ATE_RESET] = 0
80762306a36Sopenharmony_ci	 */
80862306a36Sopenharmony_ci	usbn_usbp_ctl_status.s.ate_reset = 0;
80962306a36Sopenharmony_ci	cvmx_write64_uint64(CVMX_USBNX_USBP_CTL_STATUS(usb->index),
81062306a36Sopenharmony_ci			    usbn_usbp_ctl_status.u64);
81162306a36Sopenharmony_ci	/*
81262306a36Sopenharmony_ci	 * 8. Program the PHY reset field in the USBN clock-control register:
81362306a36Sopenharmony_ci	 *    USBN_CLK_CTL[PRST] = 1
81462306a36Sopenharmony_ci	 */
81562306a36Sopenharmony_ci	usbn_clk_ctl.s.prst = 1;
81662306a36Sopenharmony_ci	cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
81762306a36Sopenharmony_ci	/*
81862306a36Sopenharmony_ci	 * 9. Program the USBP control and status register to select host or
81962306a36Sopenharmony_ci	 *    device mode. USBN_USBP_CTL_STATUS[HST_MODE] = 0 for host, = 1 for
82062306a36Sopenharmony_ci	 *    device
82162306a36Sopenharmony_ci	 */
82262306a36Sopenharmony_ci	usbn_usbp_ctl_status.s.hst_mode = 0;
82362306a36Sopenharmony_ci	cvmx_write64_uint64(CVMX_USBNX_USBP_CTL_STATUS(usb->index),
82462306a36Sopenharmony_ci			    usbn_usbp_ctl_status.u64);
82562306a36Sopenharmony_ci	/* 10. Wait 1 us */
82662306a36Sopenharmony_ci	udelay(1);
82762306a36Sopenharmony_ci	/*
82862306a36Sopenharmony_ci	 * 11. Program the hreset_n field in the USBN clock-control register:
82962306a36Sopenharmony_ci	 *     USBN_CLK_CTL[HRST] = 1
83062306a36Sopenharmony_ci	 */
83162306a36Sopenharmony_ci	usbn_clk_ctl.s.hrst = 1;
83262306a36Sopenharmony_ci	cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
83362306a36Sopenharmony_ci	/* 12. Proceed to USB core initialization */
83462306a36Sopenharmony_ci	usbn_clk_ctl.s.enable = 1;
83562306a36Sopenharmony_ci	cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
83662306a36Sopenharmony_ci	udelay(1);
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	/*
83962306a36Sopenharmony_ci	 * USB Core Initialization
84062306a36Sopenharmony_ci	 *
84162306a36Sopenharmony_ci	 * 1. Read USBC_GHWCFG1, USBC_GHWCFG2, USBC_GHWCFG3, USBC_GHWCFG4 to
84262306a36Sopenharmony_ci	 *    determine USB core configuration parameters.
84362306a36Sopenharmony_ci	 *
84462306a36Sopenharmony_ci	 *    Nothing needed
84562306a36Sopenharmony_ci	 *
84662306a36Sopenharmony_ci	 * 2. Program the following fields in the global AHB configuration
84762306a36Sopenharmony_ci	 *    register (USBC_GAHBCFG)
84862306a36Sopenharmony_ci	 *    DMA mode, USBC_GAHBCFG[DMAEn]: 1 = DMA mode, 0 = slave mode
84962306a36Sopenharmony_ci	 *    Burst length, USBC_GAHBCFG[HBSTLEN] = 0
85062306a36Sopenharmony_ci	 *    Nonperiodic TxFIFO empty level (slave mode only),
85162306a36Sopenharmony_ci	 *    USBC_GAHBCFG[NPTXFEMPLVL]
85262306a36Sopenharmony_ci	 *    Periodic TxFIFO empty level (slave mode only),
85362306a36Sopenharmony_ci	 *    USBC_GAHBCFG[PTXFEMPLVL]
85462306a36Sopenharmony_ci	 *    Global interrupt mask, USBC_GAHBCFG[GLBLINTRMSK] = 1
85562306a36Sopenharmony_ci	 */
85662306a36Sopenharmony_ci	usbcx_gahbcfg.u32 = 0;
85762306a36Sopenharmony_ci	usbcx_gahbcfg.s.dmaen = !(usb->init_flags &
85862306a36Sopenharmony_ci				  CVMX_USB_INITIALIZE_FLAGS_NO_DMA);
85962306a36Sopenharmony_ci	usbcx_gahbcfg.s.hbstlen = 0;
86062306a36Sopenharmony_ci	usbcx_gahbcfg.s.nptxfemplvl = 1;
86162306a36Sopenharmony_ci	usbcx_gahbcfg.s.ptxfemplvl = 1;
86262306a36Sopenharmony_ci	usbcx_gahbcfg.s.glblintrmsk = 1;
86362306a36Sopenharmony_ci	cvmx_usb_write_csr32(usb, CVMX_USBCX_GAHBCFG(usb->index),
86462306a36Sopenharmony_ci			     usbcx_gahbcfg.u32);
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	/*
86762306a36Sopenharmony_ci	 * 3. Program the following fields in USBC_GUSBCFG register.
86862306a36Sopenharmony_ci	 *    HS/FS timeout calibration, USBC_GUSBCFG[TOUTCAL] = 0
86962306a36Sopenharmony_ci	 *    ULPI DDR select, USBC_GUSBCFG[DDRSEL] = 0
87062306a36Sopenharmony_ci	 *    USB turnaround time, USBC_GUSBCFG[USBTRDTIM] = 0x5
87162306a36Sopenharmony_ci	 *    PHY low-power clock select, USBC_GUSBCFG[PHYLPWRCLKSEL] = 0
87262306a36Sopenharmony_ci	 */
87362306a36Sopenharmony_ci	usbcx_gusbcfg.u32 = cvmx_usb_read_csr32(usb,
87462306a36Sopenharmony_ci						CVMX_USBCX_GUSBCFG(usb->index));
87562306a36Sopenharmony_ci	usbcx_gusbcfg.s.toutcal = 0;
87662306a36Sopenharmony_ci	usbcx_gusbcfg.s.ddrsel = 0;
87762306a36Sopenharmony_ci	usbcx_gusbcfg.s.usbtrdtim = 0x5;
87862306a36Sopenharmony_ci	usbcx_gusbcfg.s.phylpwrclksel = 0;
87962306a36Sopenharmony_ci	cvmx_usb_write_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index),
88062306a36Sopenharmony_ci			     usbcx_gusbcfg.u32);
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	/*
88362306a36Sopenharmony_ci	 * 4. The software must unmask the following bits in the USBC_GINTMSK
88462306a36Sopenharmony_ci	 *    register.
88562306a36Sopenharmony_ci	 *    OTG interrupt mask, USBC_GINTMSK[OTGINTMSK] = 1
88662306a36Sopenharmony_ci	 *    Mode mismatch interrupt mask, USBC_GINTMSK[MODEMISMSK] = 1
88762306a36Sopenharmony_ci	 */
88862306a36Sopenharmony_ci	usbcx_gintmsk.u32 = cvmx_usb_read_csr32(usb,
88962306a36Sopenharmony_ci						CVMX_USBCX_GINTMSK(usb->index));
89062306a36Sopenharmony_ci	usbcx_gintmsk.s.otgintmsk = 1;
89162306a36Sopenharmony_ci	usbcx_gintmsk.s.modemismsk = 1;
89262306a36Sopenharmony_ci	usbcx_gintmsk.s.hchintmsk = 1;
89362306a36Sopenharmony_ci	usbcx_gintmsk.s.sofmsk = 0;
89462306a36Sopenharmony_ci	/* We need RX FIFO interrupts if we don't have DMA */
89562306a36Sopenharmony_ci	if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
89662306a36Sopenharmony_ci		usbcx_gintmsk.s.rxflvlmsk = 1;
89762306a36Sopenharmony_ci	cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTMSK(usb->index),
89862306a36Sopenharmony_ci			     usbcx_gintmsk.u32);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	/*
90162306a36Sopenharmony_ci	 * Disable all channel interrupts. We'll enable them per channel later.
90262306a36Sopenharmony_ci	 */
90362306a36Sopenharmony_ci	for (channel = 0; channel < 8; channel++)
90462306a36Sopenharmony_ci		cvmx_usb_write_csr32(usb,
90562306a36Sopenharmony_ci				     CVMX_USBCX_HCINTMSKX(channel, usb->index),
90662306a36Sopenharmony_ci				     0);
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	/*
90962306a36Sopenharmony_ci	 * Host Port Initialization
91062306a36Sopenharmony_ci	 *
91162306a36Sopenharmony_ci	 * 1. Program the host-port interrupt-mask field to unmask,
91262306a36Sopenharmony_ci	 *    USBC_GINTMSK[PRTINT] = 1
91362306a36Sopenharmony_ci	 */
91462306a36Sopenharmony_ci	USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
91562306a36Sopenharmony_ci			cvmx_usbcx_gintmsk, prtintmsk, 1);
91662306a36Sopenharmony_ci	USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
91762306a36Sopenharmony_ci			cvmx_usbcx_gintmsk, disconnintmsk, 1);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	/*
92062306a36Sopenharmony_ci	 * 2. Program the USBC_HCFG register to select full-speed host
92162306a36Sopenharmony_ci	 *    or high-speed host.
92262306a36Sopenharmony_ci	 */
92362306a36Sopenharmony_ci	usbcx_hcfg.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HCFG(usb->index));
92462306a36Sopenharmony_ci	usbcx_hcfg.s.fslssupp = 0;
92562306a36Sopenharmony_ci	usbcx_hcfg.s.fslspclksel = 0;
92662306a36Sopenharmony_ci	cvmx_usb_write_csr32(usb, CVMX_USBCX_HCFG(usb->index), usbcx_hcfg.u32);
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	cvmx_fifo_setup(usb);
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	/*
93162306a36Sopenharmony_ci	 * If the controller is getting port events right after the reset, it
93262306a36Sopenharmony_ci	 * means the initialization failed. Try resetting the controller again
93362306a36Sopenharmony_ci	 * in such case. This is seen to happen after cold boot on DSR-1000N.
93462306a36Sopenharmony_ci	 */
93562306a36Sopenharmony_ci	usbc_gintsts.u32 = cvmx_usb_read_csr32(usb,
93662306a36Sopenharmony_ci					       CVMX_USBCX_GINTSTS(usb->index));
93762306a36Sopenharmony_ci	cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index),
93862306a36Sopenharmony_ci			     usbc_gintsts.u32);
93962306a36Sopenharmony_ci	dev_dbg(dev, "gintsts after reset: 0x%x\n", (int)usbc_gintsts.u32);
94062306a36Sopenharmony_ci	if (!usbc_gintsts.s.disconnint && !usbc_gintsts.s.prtint)
94162306a36Sopenharmony_ci		return 0;
94262306a36Sopenharmony_ci	if (retries++ >= 5)
94362306a36Sopenharmony_ci		return -EAGAIN;
94462306a36Sopenharmony_ci	dev_info(dev, "controller reset failed (gintsts=0x%x) - retrying\n",
94562306a36Sopenharmony_ci		 (int)usbc_gintsts.u32);
94662306a36Sopenharmony_ci	msleep(50);
94762306a36Sopenharmony_ci	cvmx_usb_shutdown(usb);
94862306a36Sopenharmony_ci	msleep(50);
94962306a36Sopenharmony_ci	goto retry;
95062306a36Sopenharmony_ci}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci/**
95362306a36Sopenharmony_ci * Reset a USB port. After this call succeeds, the USB port is
95462306a36Sopenharmony_ci * online and servicing requests.
95562306a36Sopenharmony_ci *
95662306a36Sopenharmony_ci * @usb: USB device state populated by cvmx_usb_initialize().
95762306a36Sopenharmony_ci */
95862306a36Sopenharmony_cistatic void cvmx_usb_reset_port(struct octeon_hcd *usb)
95962306a36Sopenharmony_ci{
96062306a36Sopenharmony_ci	usb->usbcx_hprt.u32 = cvmx_usb_read_csr32(usb,
96162306a36Sopenharmony_ci						  CVMX_USBCX_HPRT(usb->index));
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	/* Program the port reset bit to start the reset process */
96462306a36Sopenharmony_ci	USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt,
96562306a36Sopenharmony_ci			prtrst, 1);
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	/*
96862306a36Sopenharmony_ci	 * Wait at least 50ms (high speed), or 10ms (full speed) for the reset
96962306a36Sopenharmony_ci	 * process to complete.
97062306a36Sopenharmony_ci	 */
97162306a36Sopenharmony_ci	mdelay(50);
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	/* Program the port reset bit to 0, USBC_HPRT[PRTRST] = 0 */
97462306a36Sopenharmony_ci	USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt,
97562306a36Sopenharmony_ci			prtrst, 0);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	/*
97862306a36Sopenharmony_ci	 * Read the port speed field to get the enumerated speed,
97962306a36Sopenharmony_ci	 * USBC_HPRT[PRTSPD].
98062306a36Sopenharmony_ci	 */
98162306a36Sopenharmony_ci	usb->usbcx_hprt.u32 = cvmx_usb_read_csr32(usb,
98262306a36Sopenharmony_ci						  CVMX_USBCX_HPRT(usb->index));
98362306a36Sopenharmony_ci}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci/**
98662306a36Sopenharmony_ci * Disable a USB port. After this call the USB port will not
98762306a36Sopenharmony_ci * generate data transfers and will not generate events.
98862306a36Sopenharmony_ci * Transactions in process will fail and call their
98962306a36Sopenharmony_ci * associated callbacks.
99062306a36Sopenharmony_ci *
99162306a36Sopenharmony_ci * @usb: USB device state populated by cvmx_usb_initialize().
99262306a36Sopenharmony_ci *
99362306a36Sopenharmony_ci * Returns: 0 or a negative error code.
99462306a36Sopenharmony_ci */
99562306a36Sopenharmony_cistatic int cvmx_usb_disable(struct octeon_hcd *usb)
99662306a36Sopenharmony_ci{
99762306a36Sopenharmony_ci	/* Disable the port */
99862306a36Sopenharmony_ci	USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt,
99962306a36Sopenharmony_ci			prtena, 1);
100062306a36Sopenharmony_ci	return 0;
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci/**
100462306a36Sopenharmony_ci * Get the current state of the USB port. Use this call to
100562306a36Sopenharmony_ci * determine if the usb port has anything connected, is enabled,
100662306a36Sopenharmony_ci * or has some sort of error condition. The return value of this
100762306a36Sopenharmony_ci * call has "changed" bits to signal of the value of some fields
100862306a36Sopenharmony_ci * have changed between calls.
100962306a36Sopenharmony_ci *
101062306a36Sopenharmony_ci * @usb: USB device state populated by cvmx_usb_initialize().
101162306a36Sopenharmony_ci *
101262306a36Sopenharmony_ci * Returns: Port status information
101362306a36Sopenharmony_ci */
101462306a36Sopenharmony_cistatic struct cvmx_usb_port_status cvmx_usb_get_status(struct octeon_hcd *usb)
101562306a36Sopenharmony_ci{
101662306a36Sopenharmony_ci	union cvmx_usbcx_hprt usbc_hprt;
101762306a36Sopenharmony_ci	struct cvmx_usb_port_status result;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	memset(&result, 0, sizeof(result));
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	usbc_hprt.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
102262306a36Sopenharmony_ci	result.port_enabled = usbc_hprt.s.prtena;
102362306a36Sopenharmony_ci	result.port_over_current = usbc_hprt.s.prtovrcurract;
102462306a36Sopenharmony_ci	result.port_powered = usbc_hprt.s.prtpwr;
102562306a36Sopenharmony_ci	result.port_speed = usbc_hprt.s.prtspd;
102662306a36Sopenharmony_ci	result.connected = usbc_hprt.s.prtconnsts;
102762306a36Sopenharmony_ci	result.connect_change =
102862306a36Sopenharmony_ci		result.connected != usb->port_status.connected;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	return result;
103162306a36Sopenharmony_ci}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci/**
103462306a36Sopenharmony_ci * Open a virtual pipe between the host and a USB device. A pipe
103562306a36Sopenharmony_ci * must be opened before data can be transferred between a device
103662306a36Sopenharmony_ci * and Octeon.
103762306a36Sopenharmony_ci *
103862306a36Sopenharmony_ci * @usb:	     USB device state populated by cvmx_usb_initialize().
103962306a36Sopenharmony_ci * @device_addr:
104062306a36Sopenharmony_ci *		     USB device address to open the pipe to
104162306a36Sopenharmony_ci *		     (0-127).
104262306a36Sopenharmony_ci * @endpoint_num:
104362306a36Sopenharmony_ci *		     USB endpoint number to open the pipe to
104462306a36Sopenharmony_ci *		     (0-15).
104562306a36Sopenharmony_ci * @device_speed:
104662306a36Sopenharmony_ci *		     The speed of the device the pipe is going
104762306a36Sopenharmony_ci *		     to. This must match the device's speed,
104862306a36Sopenharmony_ci *		     which may be different than the port speed.
104962306a36Sopenharmony_ci * @max_packet:	     The maximum packet length the device can
105062306a36Sopenharmony_ci *		     transmit/receive (low speed=0-8, full
105162306a36Sopenharmony_ci *		     speed=0-1023, high speed=0-1024). This value
105262306a36Sopenharmony_ci *		     comes from the standard endpoint descriptor
105362306a36Sopenharmony_ci *		     field wMaxPacketSize bits <10:0>.
105462306a36Sopenharmony_ci * @transfer_type:
105562306a36Sopenharmony_ci *		     The type of transfer this pipe is for.
105662306a36Sopenharmony_ci * @transfer_dir:
105762306a36Sopenharmony_ci *		     The direction the pipe is in. This is not
105862306a36Sopenharmony_ci *		     used for control pipes.
105962306a36Sopenharmony_ci * @interval:	     For ISOCHRONOUS and INTERRUPT transfers,
106062306a36Sopenharmony_ci *		     this is how often the transfer is scheduled
106162306a36Sopenharmony_ci *		     for. All other transfers should specify
106262306a36Sopenharmony_ci *		     zero. The units are in frames (8000/sec at
106362306a36Sopenharmony_ci *		     high speed, 1000/sec for full speed).
106462306a36Sopenharmony_ci * @multi_count:
106562306a36Sopenharmony_ci *		     For high speed devices, this is the maximum
106662306a36Sopenharmony_ci *		     allowed number of packet per microframe.
106762306a36Sopenharmony_ci *		     Specify zero for non high speed devices. This
106862306a36Sopenharmony_ci *		     value comes from the standard endpoint descriptor
106962306a36Sopenharmony_ci *		     field wMaxPacketSize bits <12:11>.
107062306a36Sopenharmony_ci * @hub_device_addr:
107162306a36Sopenharmony_ci *		     Hub device address this device is connected
107262306a36Sopenharmony_ci *		     to. Devices connected directly to Octeon
107362306a36Sopenharmony_ci *		     use zero. This is only used when the device
107462306a36Sopenharmony_ci *		     is full/low speed behind a high speed hub.
107562306a36Sopenharmony_ci *		     The address will be of the high speed hub,
107662306a36Sopenharmony_ci *		     not and full speed hubs after it.
107762306a36Sopenharmony_ci * @hub_port:	     Which port on the hub the device is
107862306a36Sopenharmony_ci *		     connected. Use zero for devices connected
107962306a36Sopenharmony_ci *		     directly to Octeon. Like hub_device_addr,
108062306a36Sopenharmony_ci *		     this is only used for full/low speed
108162306a36Sopenharmony_ci *		     devices behind a high speed hub.
108262306a36Sopenharmony_ci *
108362306a36Sopenharmony_ci * Returns: A non-NULL value is a pipe. NULL means an error.
108462306a36Sopenharmony_ci */
108562306a36Sopenharmony_cistatic struct cvmx_usb_pipe *cvmx_usb_open_pipe(struct octeon_hcd *usb,
108662306a36Sopenharmony_ci						int device_addr,
108762306a36Sopenharmony_ci						int endpoint_num,
108862306a36Sopenharmony_ci						enum cvmx_usb_speed
108962306a36Sopenharmony_ci							device_speed,
109062306a36Sopenharmony_ci						int max_packet,
109162306a36Sopenharmony_ci						enum cvmx_usb_transfer
109262306a36Sopenharmony_ci							transfer_type,
109362306a36Sopenharmony_ci						enum cvmx_usb_direction
109462306a36Sopenharmony_ci							transfer_dir,
109562306a36Sopenharmony_ci						int interval, int multi_count,
109662306a36Sopenharmony_ci						int hub_device_addr,
109762306a36Sopenharmony_ci						int hub_port)
109862306a36Sopenharmony_ci{
109962306a36Sopenharmony_ci	struct cvmx_usb_pipe *pipe;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	pipe = kzalloc(sizeof(*pipe), GFP_ATOMIC);
110262306a36Sopenharmony_ci	if (!pipe)
110362306a36Sopenharmony_ci		return NULL;
110462306a36Sopenharmony_ci	if ((device_speed == CVMX_USB_SPEED_HIGH) &&
110562306a36Sopenharmony_ci	    (transfer_dir == CVMX_USB_DIRECTION_OUT) &&
110662306a36Sopenharmony_ci	    (transfer_type == CVMX_USB_TRANSFER_BULK))
110762306a36Sopenharmony_ci		pipe->flags |= CVMX_USB_PIPE_FLAGS_NEED_PING;
110862306a36Sopenharmony_ci	pipe->device_addr = device_addr;
110962306a36Sopenharmony_ci	pipe->endpoint_num = endpoint_num;
111062306a36Sopenharmony_ci	pipe->device_speed = device_speed;
111162306a36Sopenharmony_ci	pipe->max_packet = max_packet;
111262306a36Sopenharmony_ci	pipe->transfer_type = transfer_type;
111362306a36Sopenharmony_ci	pipe->transfer_dir = transfer_dir;
111462306a36Sopenharmony_ci	INIT_LIST_HEAD(&pipe->transactions);
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	/*
111762306a36Sopenharmony_ci	 * All pipes use interval to rate limit NAK processing. Force an
111862306a36Sopenharmony_ci	 * interval if one wasn't supplied
111962306a36Sopenharmony_ci	 */
112062306a36Sopenharmony_ci	if (!interval)
112162306a36Sopenharmony_ci		interval = 1;
112262306a36Sopenharmony_ci	if (cvmx_usb_pipe_needs_split(usb, pipe)) {
112362306a36Sopenharmony_ci		pipe->interval = interval * 8;
112462306a36Sopenharmony_ci		/* Force start splits to be schedule on uFrame 0 */
112562306a36Sopenharmony_ci		pipe->next_tx_frame = ((usb->frame_number + 7) & ~7) +
112662306a36Sopenharmony_ci					pipe->interval;
112762306a36Sopenharmony_ci	} else {
112862306a36Sopenharmony_ci		pipe->interval = interval;
112962306a36Sopenharmony_ci		pipe->next_tx_frame = usb->frame_number + pipe->interval;
113062306a36Sopenharmony_ci	}
113162306a36Sopenharmony_ci	pipe->multi_count = multi_count;
113262306a36Sopenharmony_ci	pipe->hub_device_addr = hub_device_addr;
113362306a36Sopenharmony_ci	pipe->hub_port = hub_port;
113462306a36Sopenharmony_ci	pipe->pid_toggle = 0;
113562306a36Sopenharmony_ci	pipe->split_sc_frame = -1;
113662306a36Sopenharmony_ci	list_add_tail(&pipe->node, &usb->idle_pipes);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	/*
113962306a36Sopenharmony_ci	 * We don't need to tell the hardware about this pipe yet since
114062306a36Sopenharmony_ci	 * it doesn't have any submitted requests
114162306a36Sopenharmony_ci	 */
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	return pipe;
114462306a36Sopenharmony_ci}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci/**
114762306a36Sopenharmony_ci * Poll the RX FIFOs and remove data as needed. This function is only used
114862306a36Sopenharmony_ci * in non DMA mode. It is very important that this function be called quickly
114962306a36Sopenharmony_ci * enough to prevent FIFO overflow.
115062306a36Sopenharmony_ci *
115162306a36Sopenharmony_ci * @usb:	USB device state populated by cvmx_usb_initialize().
115262306a36Sopenharmony_ci */
115362306a36Sopenharmony_cistatic void cvmx_usb_poll_rx_fifo(struct octeon_hcd *usb)
115462306a36Sopenharmony_ci{
115562306a36Sopenharmony_ci	union cvmx_usbcx_grxstsph rx_status;
115662306a36Sopenharmony_ci	int channel;
115762306a36Sopenharmony_ci	int bytes;
115862306a36Sopenharmony_ci	u64 address;
115962306a36Sopenharmony_ci	u32 *ptr;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	rx_status.u32 = cvmx_usb_read_csr32(usb,
116262306a36Sopenharmony_ci					    CVMX_USBCX_GRXSTSPH(usb->index));
116362306a36Sopenharmony_ci	/* Only read data if IN data is there */
116462306a36Sopenharmony_ci	if (rx_status.s.pktsts != 2)
116562306a36Sopenharmony_ci		return;
116662306a36Sopenharmony_ci	/* Check if no data is available */
116762306a36Sopenharmony_ci	if (!rx_status.s.bcnt)
116862306a36Sopenharmony_ci		return;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	channel = rx_status.s.chnum;
117162306a36Sopenharmony_ci	bytes = rx_status.s.bcnt;
117262306a36Sopenharmony_ci	if (!bytes)
117362306a36Sopenharmony_ci		return;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	/* Get where the DMA engine would have written this data */
117662306a36Sopenharmony_ci	address = cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index) +
117762306a36Sopenharmony_ci				     channel * 8);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	ptr = cvmx_phys_to_ptr(address);
118062306a36Sopenharmony_ci	cvmx_write64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel * 8,
118162306a36Sopenharmony_ci			    address + bytes);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	/* Loop writing the FIFO data for this packet into memory */
118462306a36Sopenharmony_ci	while (bytes > 0) {
118562306a36Sopenharmony_ci		*ptr++ = cvmx_usb_read_csr32(usb,
118662306a36Sopenharmony_ci					USB_FIFO_ADDRESS(channel, usb->index));
118762306a36Sopenharmony_ci		bytes -= 4;
118862306a36Sopenharmony_ci	}
118962306a36Sopenharmony_ci	CVMX_SYNCW;
119062306a36Sopenharmony_ci}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci/**
119362306a36Sopenharmony_ci * Fill the TX hardware fifo with data out of the software
119462306a36Sopenharmony_ci * fifos
119562306a36Sopenharmony_ci *
119662306a36Sopenharmony_ci * @usb:	    USB device state populated by cvmx_usb_initialize().
119762306a36Sopenharmony_ci * @fifo:	    Software fifo to use
119862306a36Sopenharmony_ci * @available:	    Amount of space in the hardware fifo
119962306a36Sopenharmony_ci *
120062306a36Sopenharmony_ci * Returns: Non zero if the hardware fifo was too small and needs
120162306a36Sopenharmony_ci *	    to be serviced again.
120262306a36Sopenharmony_ci */
120362306a36Sopenharmony_cistatic int cvmx_usb_fill_tx_hw(struct octeon_hcd *usb,
120462306a36Sopenharmony_ci			       struct cvmx_usb_tx_fifo *fifo, int available)
120562306a36Sopenharmony_ci{
120662306a36Sopenharmony_ci	/*
120762306a36Sopenharmony_ci	 * We're done either when there isn't anymore space or the software FIFO
120862306a36Sopenharmony_ci	 * is empty
120962306a36Sopenharmony_ci	 */
121062306a36Sopenharmony_ci	while (available && (fifo->head != fifo->tail)) {
121162306a36Sopenharmony_ci		int i = fifo->tail;
121262306a36Sopenharmony_ci		const u32 *ptr = cvmx_phys_to_ptr(fifo->entry[i].address);
121362306a36Sopenharmony_ci		u64 csr_address = USB_FIFO_ADDRESS(fifo->entry[i].channel,
121462306a36Sopenharmony_ci						   usb->index) ^ 4;
121562306a36Sopenharmony_ci		int words = available;
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci		/* Limit the amount of data to what the SW fifo has */
121862306a36Sopenharmony_ci		if (fifo->entry[i].size <= available) {
121962306a36Sopenharmony_ci			words = fifo->entry[i].size;
122062306a36Sopenharmony_ci			fifo->tail++;
122162306a36Sopenharmony_ci			if (fifo->tail > MAX_CHANNELS)
122262306a36Sopenharmony_ci				fifo->tail = 0;
122362306a36Sopenharmony_ci		}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci		/* Update the next locations and counts */
122662306a36Sopenharmony_ci		available -= words;
122762306a36Sopenharmony_ci		fifo->entry[i].address += words * 4;
122862306a36Sopenharmony_ci		fifo->entry[i].size -= words;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci		/*
123162306a36Sopenharmony_ci		 * Write the HW fifo data. The read every three writes is due
123262306a36Sopenharmony_ci		 * to an errata on CN3XXX chips
123362306a36Sopenharmony_ci		 */
123462306a36Sopenharmony_ci		while (words > 3) {
123562306a36Sopenharmony_ci			cvmx_write64_uint32(csr_address, *ptr++);
123662306a36Sopenharmony_ci			cvmx_write64_uint32(csr_address, *ptr++);
123762306a36Sopenharmony_ci			cvmx_write64_uint32(csr_address, *ptr++);
123862306a36Sopenharmony_ci			cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
123962306a36Sopenharmony_ci			words -= 3;
124062306a36Sopenharmony_ci		}
124162306a36Sopenharmony_ci		cvmx_write64_uint32(csr_address, *ptr++);
124262306a36Sopenharmony_ci		if (--words) {
124362306a36Sopenharmony_ci			cvmx_write64_uint32(csr_address, *ptr++);
124462306a36Sopenharmony_ci			if (--words)
124562306a36Sopenharmony_ci				cvmx_write64_uint32(csr_address, *ptr++);
124662306a36Sopenharmony_ci		}
124762306a36Sopenharmony_ci		cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
124862306a36Sopenharmony_ci	}
124962306a36Sopenharmony_ci	return fifo->head != fifo->tail;
125062306a36Sopenharmony_ci}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci/**
125362306a36Sopenharmony_ci * Check the hardware FIFOs and fill them as needed
125462306a36Sopenharmony_ci *
125562306a36Sopenharmony_ci * @usb:	USB device state populated by cvmx_usb_initialize().
125662306a36Sopenharmony_ci */
125762306a36Sopenharmony_cistatic void cvmx_usb_poll_tx_fifo(struct octeon_hcd *usb)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	if (usb->periodic.head != usb->periodic.tail) {
126062306a36Sopenharmony_ci		union cvmx_usbcx_hptxsts tx_status;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci		tx_status.u32 = cvmx_usb_read_csr32(usb,
126362306a36Sopenharmony_ci						    CVMX_USBCX_HPTXSTS(usb->index));
126462306a36Sopenharmony_ci		if (cvmx_usb_fill_tx_hw(usb, &usb->periodic,
126562306a36Sopenharmony_ci					tx_status.s.ptxfspcavail))
126662306a36Sopenharmony_ci			USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
126762306a36Sopenharmony_ci					cvmx_usbcx_gintmsk, ptxfempmsk, 1);
126862306a36Sopenharmony_ci		else
126962306a36Sopenharmony_ci			USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
127062306a36Sopenharmony_ci					cvmx_usbcx_gintmsk, ptxfempmsk, 0);
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	if (usb->nonperiodic.head != usb->nonperiodic.tail) {
127462306a36Sopenharmony_ci		union cvmx_usbcx_gnptxsts tx_status;
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci		tx_status.u32 = cvmx_usb_read_csr32(usb,
127762306a36Sopenharmony_ci						    CVMX_USBCX_GNPTXSTS(usb->index));
127862306a36Sopenharmony_ci		if (cvmx_usb_fill_tx_hw(usb, &usb->nonperiodic,
127962306a36Sopenharmony_ci					tx_status.s.nptxfspcavail))
128062306a36Sopenharmony_ci			USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
128162306a36Sopenharmony_ci					cvmx_usbcx_gintmsk, nptxfempmsk, 1);
128262306a36Sopenharmony_ci		else
128362306a36Sopenharmony_ci			USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
128462306a36Sopenharmony_ci					cvmx_usbcx_gintmsk, nptxfempmsk, 0);
128562306a36Sopenharmony_ci	}
128662306a36Sopenharmony_ci}
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci/**
128962306a36Sopenharmony_ci * Fill the TX FIFO with an outgoing packet
129062306a36Sopenharmony_ci *
129162306a36Sopenharmony_ci * @usb:	  USB device state populated by cvmx_usb_initialize().
129262306a36Sopenharmony_ci * @channel:	  Channel number to get packet from
129362306a36Sopenharmony_ci */
129462306a36Sopenharmony_cistatic void cvmx_usb_fill_tx_fifo(struct octeon_hcd *usb, int channel)
129562306a36Sopenharmony_ci{
129662306a36Sopenharmony_ci	union cvmx_usbcx_hccharx hcchar;
129762306a36Sopenharmony_ci	union cvmx_usbcx_hcspltx usbc_hcsplt;
129862306a36Sopenharmony_ci	union cvmx_usbcx_hctsizx usbc_hctsiz;
129962306a36Sopenharmony_ci	struct cvmx_usb_tx_fifo *fifo;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	/* We only need to fill data on outbound channels */
130262306a36Sopenharmony_ci	hcchar.u32 = cvmx_usb_read_csr32(usb,
130362306a36Sopenharmony_ci					 CVMX_USBCX_HCCHARX(channel, usb->index));
130462306a36Sopenharmony_ci	if (hcchar.s.epdir != CVMX_USB_DIRECTION_OUT)
130562306a36Sopenharmony_ci		return;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	/* OUT Splits only have data on the start and not the complete */
130862306a36Sopenharmony_ci	usbc_hcsplt.u32 = cvmx_usb_read_csr32(usb,
130962306a36Sopenharmony_ci					      CVMX_USBCX_HCSPLTX(channel, usb->index));
131062306a36Sopenharmony_ci	if (usbc_hcsplt.s.spltena && usbc_hcsplt.s.compsplt)
131162306a36Sopenharmony_ci		return;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	/*
131462306a36Sopenharmony_ci	 * Find out how many bytes we need to fill and convert it into 32bit
131562306a36Sopenharmony_ci	 * words.
131662306a36Sopenharmony_ci	 */
131762306a36Sopenharmony_ci	usbc_hctsiz.u32 = cvmx_usb_read_csr32(usb,
131862306a36Sopenharmony_ci					      CVMX_USBCX_HCTSIZX(channel, usb->index));
131962306a36Sopenharmony_ci	if (!usbc_hctsiz.s.xfersize)
132062306a36Sopenharmony_ci		return;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	if ((hcchar.s.eptype == CVMX_USB_TRANSFER_INTERRUPT) ||
132362306a36Sopenharmony_ci	    (hcchar.s.eptype == CVMX_USB_TRANSFER_ISOCHRONOUS))
132462306a36Sopenharmony_ci		fifo = &usb->periodic;
132562306a36Sopenharmony_ci	else
132662306a36Sopenharmony_ci		fifo = &usb->nonperiodic;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	fifo->entry[fifo->head].channel = channel;
132962306a36Sopenharmony_ci	fifo->entry[fifo->head].address =
133062306a36Sopenharmony_ci		cvmx_read64_uint64(CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) +
133162306a36Sopenharmony_ci				   channel * 8);
133262306a36Sopenharmony_ci	fifo->entry[fifo->head].size = (usbc_hctsiz.s.xfersize + 3) >> 2;
133362306a36Sopenharmony_ci	fifo->head++;
133462306a36Sopenharmony_ci	if (fifo->head > MAX_CHANNELS)
133562306a36Sopenharmony_ci		fifo->head = 0;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	cvmx_usb_poll_tx_fifo(usb);
133862306a36Sopenharmony_ci}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci/**
134162306a36Sopenharmony_ci * Perform channel specific setup for Control transactions. All
134262306a36Sopenharmony_ci * the generic stuff will already have been done in cvmx_usb_start_channel().
134362306a36Sopenharmony_ci *
134462306a36Sopenharmony_ci * @usb:	  USB device state populated by cvmx_usb_initialize().
134562306a36Sopenharmony_ci * @channel:	  Channel to setup
134662306a36Sopenharmony_ci * @pipe:	  Pipe for control transaction
134762306a36Sopenharmony_ci */
134862306a36Sopenharmony_cistatic void cvmx_usb_start_channel_control(struct octeon_hcd *usb,
134962306a36Sopenharmony_ci					   int channel,
135062306a36Sopenharmony_ci					   struct cvmx_usb_pipe *pipe)
135162306a36Sopenharmony_ci{
135262306a36Sopenharmony_ci	struct usb_hcd *hcd = octeon_to_hcd(usb);
135362306a36Sopenharmony_ci	struct device *dev = hcd->self.controller;
135462306a36Sopenharmony_ci	struct cvmx_usb_transaction *transaction =
135562306a36Sopenharmony_ci		list_first_entry(&pipe->transactions, typeof(*transaction),
135662306a36Sopenharmony_ci				 node);
135762306a36Sopenharmony_ci	struct usb_ctrlrequest *header =
135862306a36Sopenharmony_ci		cvmx_phys_to_ptr(transaction->control_header);
135962306a36Sopenharmony_ci	int bytes_to_transfer = transaction->buffer_length -
136062306a36Sopenharmony_ci		transaction->actual_bytes;
136162306a36Sopenharmony_ci	int packets_to_transfer;
136262306a36Sopenharmony_ci	union cvmx_usbcx_hctsizx usbc_hctsiz;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	usbc_hctsiz.u32 = cvmx_usb_read_csr32(usb,
136562306a36Sopenharmony_ci					      CVMX_USBCX_HCTSIZX(channel, usb->index));
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	switch (transaction->stage) {
136862306a36Sopenharmony_ci	case CVMX_USB_STAGE_NON_CONTROL:
136962306a36Sopenharmony_ci	case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
137062306a36Sopenharmony_ci		dev_err(dev, "%s: ERROR - Non control stage\n", __func__);
137162306a36Sopenharmony_ci		break;
137262306a36Sopenharmony_ci	case CVMX_USB_STAGE_SETUP:
137362306a36Sopenharmony_ci		usbc_hctsiz.s.pid = 3; /* Setup */
137462306a36Sopenharmony_ci		bytes_to_transfer = sizeof(*header);
137562306a36Sopenharmony_ci		/* All Control operations start with a setup going OUT */
137662306a36Sopenharmony_ci		USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
137762306a36Sopenharmony_ci				cvmx_usbcx_hccharx, epdir,
137862306a36Sopenharmony_ci				CVMX_USB_DIRECTION_OUT);
137962306a36Sopenharmony_ci		/*
138062306a36Sopenharmony_ci		 * Setup send the control header instead of the buffer data. The
138162306a36Sopenharmony_ci		 * buffer data will be used in the next stage
138262306a36Sopenharmony_ci		 */
138362306a36Sopenharmony_ci		cvmx_write64_uint64(CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) +
138462306a36Sopenharmony_ci					channel * 8,
138562306a36Sopenharmony_ci				    transaction->control_header);
138662306a36Sopenharmony_ci		break;
138762306a36Sopenharmony_ci	case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
138862306a36Sopenharmony_ci		usbc_hctsiz.s.pid = 3; /* Setup */
138962306a36Sopenharmony_ci		bytes_to_transfer = 0;
139062306a36Sopenharmony_ci		/* All Control operations start with a setup going OUT */
139162306a36Sopenharmony_ci		USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
139262306a36Sopenharmony_ci				cvmx_usbcx_hccharx, epdir,
139362306a36Sopenharmony_ci				CVMX_USB_DIRECTION_OUT);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci		USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index),
139662306a36Sopenharmony_ci				cvmx_usbcx_hcspltx, compsplt, 1);
139762306a36Sopenharmony_ci		break;
139862306a36Sopenharmony_ci	case CVMX_USB_STAGE_DATA:
139962306a36Sopenharmony_ci		usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe);
140062306a36Sopenharmony_ci		if (cvmx_usb_pipe_needs_split(usb, pipe)) {
140162306a36Sopenharmony_ci			if (header->bRequestType & USB_DIR_IN)
140262306a36Sopenharmony_ci				bytes_to_transfer = 0;
140362306a36Sopenharmony_ci			else if (bytes_to_transfer > pipe->max_packet)
140462306a36Sopenharmony_ci				bytes_to_transfer = pipe->max_packet;
140562306a36Sopenharmony_ci		}
140662306a36Sopenharmony_ci		USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
140762306a36Sopenharmony_ci				cvmx_usbcx_hccharx, epdir,
140862306a36Sopenharmony_ci				((header->bRequestType & USB_DIR_IN) ?
140962306a36Sopenharmony_ci					CVMX_USB_DIRECTION_IN :
141062306a36Sopenharmony_ci					CVMX_USB_DIRECTION_OUT));
141162306a36Sopenharmony_ci		break;
141262306a36Sopenharmony_ci	case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE:
141362306a36Sopenharmony_ci		usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe);
141462306a36Sopenharmony_ci		if (!(header->bRequestType & USB_DIR_IN))
141562306a36Sopenharmony_ci			bytes_to_transfer = 0;
141662306a36Sopenharmony_ci		USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
141762306a36Sopenharmony_ci				cvmx_usbcx_hccharx, epdir,
141862306a36Sopenharmony_ci				((header->bRequestType & USB_DIR_IN) ?
141962306a36Sopenharmony_ci					CVMX_USB_DIRECTION_IN :
142062306a36Sopenharmony_ci					CVMX_USB_DIRECTION_OUT));
142162306a36Sopenharmony_ci		USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index),
142262306a36Sopenharmony_ci				cvmx_usbcx_hcspltx, compsplt, 1);
142362306a36Sopenharmony_ci		break;
142462306a36Sopenharmony_ci	case CVMX_USB_STAGE_STATUS:
142562306a36Sopenharmony_ci		usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe);
142662306a36Sopenharmony_ci		bytes_to_transfer = 0;
142762306a36Sopenharmony_ci		USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
142862306a36Sopenharmony_ci				cvmx_usbcx_hccharx, epdir,
142962306a36Sopenharmony_ci				((header->bRequestType & USB_DIR_IN) ?
143062306a36Sopenharmony_ci					CVMX_USB_DIRECTION_OUT :
143162306a36Sopenharmony_ci					CVMX_USB_DIRECTION_IN));
143262306a36Sopenharmony_ci		break;
143362306a36Sopenharmony_ci	case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
143462306a36Sopenharmony_ci		usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe);
143562306a36Sopenharmony_ci		bytes_to_transfer = 0;
143662306a36Sopenharmony_ci		USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
143762306a36Sopenharmony_ci				cvmx_usbcx_hccharx, epdir,
143862306a36Sopenharmony_ci				((header->bRequestType & USB_DIR_IN) ?
143962306a36Sopenharmony_ci					CVMX_USB_DIRECTION_OUT :
144062306a36Sopenharmony_ci					CVMX_USB_DIRECTION_IN));
144162306a36Sopenharmony_ci		USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index),
144262306a36Sopenharmony_ci				cvmx_usbcx_hcspltx, compsplt, 1);
144362306a36Sopenharmony_ci		break;
144462306a36Sopenharmony_ci	}
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	/*
144762306a36Sopenharmony_ci	 * Make sure the transfer never exceeds the byte limit of the hardware.
144862306a36Sopenharmony_ci	 * Further bytes will be sent as continued transactions
144962306a36Sopenharmony_ci	 */
145062306a36Sopenharmony_ci	if (bytes_to_transfer > MAX_TRANSFER_BYTES) {
145162306a36Sopenharmony_ci		/* Round MAX_TRANSFER_BYTES to a multiple of out packet size */
145262306a36Sopenharmony_ci		bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet;
145362306a36Sopenharmony_ci		bytes_to_transfer *= pipe->max_packet;
145462306a36Sopenharmony_ci	}
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	/*
145762306a36Sopenharmony_ci	 * Calculate the number of packets to transfer. If the length is zero
145862306a36Sopenharmony_ci	 * we still need to transfer one packet
145962306a36Sopenharmony_ci	 */
146062306a36Sopenharmony_ci	packets_to_transfer = DIV_ROUND_UP(bytes_to_transfer,
146162306a36Sopenharmony_ci					   pipe->max_packet);
146262306a36Sopenharmony_ci	if (packets_to_transfer == 0) {
146362306a36Sopenharmony_ci		packets_to_transfer = 1;
146462306a36Sopenharmony_ci	} else if ((packets_to_transfer > 1) &&
146562306a36Sopenharmony_ci			(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
146662306a36Sopenharmony_ci		/*
146762306a36Sopenharmony_ci		 * Limit to one packet when not using DMA. Channels must be
146862306a36Sopenharmony_ci		 * restarted between every packet for IN transactions, so there
146962306a36Sopenharmony_ci		 * is no reason to do multiple packets in a row
147062306a36Sopenharmony_ci		 */
147162306a36Sopenharmony_ci		packets_to_transfer = 1;
147262306a36Sopenharmony_ci		bytes_to_transfer = packets_to_transfer * pipe->max_packet;
147362306a36Sopenharmony_ci	} else if (packets_to_transfer > MAX_TRANSFER_PACKETS) {
147462306a36Sopenharmony_ci		/*
147562306a36Sopenharmony_ci		 * Limit the number of packet and data transferred to what the
147662306a36Sopenharmony_ci		 * hardware can handle
147762306a36Sopenharmony_ci		 */
147862306a36Sopenharmony_ci		packets_to_transfer = MAX_TRANSFER_PACKETS;
147962306a36Sopenharmony_ci		bytes_to_transfer = packets_to_transfer * pipe->max_packet;
148062306a36Sopenharmony_ci	}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	usbc_hctsiz.s.xfersize = bytes_to_transfer;
148362306a36Sopenharmony_ci	usbc_hctsiz.s.pktcnt = packets_to_transfer;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index),
148662306a36Sopenharmony_ci			     usbc_hctsiz.u32);
148762306a36Sopenharmony_ci}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci/**
149062306a36Sopenharmony_ci * Start a channel to perform the pipe's head transaction
149162306a36Sopenharmony_ci *
149262306a36Sopenharmony_ci * @usb:	  USB device state populated by cvmx_usb_initialize().
149362306a36Sopenharmony_ci * @channel:	  Channel to setup
149462306a36Sopenharmony_ci * @pipe:	  Pipe to start
149562306a36Sopenharmony_ci */
149662306a36Sopenharmony_cistatic void cvmx_usb_start_channel(struct octeon_hcd *usb, int channel,
149762306a36Sopenharmony_ci				   struct cvmx_usb_pipe *pipe)
149862306a36Sopenharmony_ci{
149962306a36Sopenharmony_ci	struct cvmx_usb_transaction *transaction =
150062306a36Sopenharmony_ci		list_first_entry(&pipe->transactions, typeof(*transaction),
150162306a36Sopenharmony_ci				 node);
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	/* Make sure all writes to the DMA region get flushed */
150462306a36Sopenharmony_ci	CVMX_SYNCW;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	/* Attach the channel to the pipe */
150762306a36Sopenharmony_ci	usb->pipe_for_channel[channel] = pipe;
150862306a36Sopenharmony_ci	pipe->channel = channel;
150962306a36Sopenharmony_ci	pipe->flags |= CVMX_USB_PIPE_FLAGS_SCHEDULED;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	/* Mark this channel as in use */
151262306a36Sopenharmony_ci	usb->idle_hardware_channels &= ~(1 << channel);
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	/* Enable the channel interrupt bits */
151562306a36Sopenharmony_ci	{
151662306a36Sopenharmony_ci		union cvmx_usbcx_hcintx usbc_hcint;
151762306a36Sopenharmony_ci		union cvmx_usbcx_hcintmskx usbc_hcintmsk;
151862306a36Sopenharmony_ci		union cvmx_usbcx_haintmsk usbc_haintmsk;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci		/* Clear all channel status bits */
152162306a36Sopenharmony_ci		usbc_hcint.u32 = cvmx_usb_read_csr32(usb,
152262306a36Sopenharmony_ci						     CVMX_USBCX_HCINTX(channel, usb->index));
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci		cvmx_usb_write_csr32(usb,
152562306a36Sopenharmony_ci				     CVMX_USBCX_HCINTX(channel, usb->index),
152662306a36Sopenharmony_ci				     usbc_hcint.u32);
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci		usbc_hcintmsk.u32 = 0;
152962306a36Sopenharmony_ci		usbc_hcintmsk.s.chhltdmsk = 1;
153062306a36Sopenharmony_ci		if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
153162306a36Sopenharmony_ci			/*
153262306a36Sopenharmony_ci			 * Channels need these extra interrupts when we aren't
153362306a36Sopenharmony_ci			 * in DMA mode.
153462306a36Sopenharmony_ci			 */
153562306a36Sopenharmony_ci			usbc_hcintmsk.s.datatglerrmsk = 1;
153662306a36Sopenharmony_ci			usbc_hcintmsk.s.frmovrunmsk = 1;
153762306a36Sopenharmony_ci			usbc_hcintmsk.s.bblerrmsk = 1;
153862306a36Sopenharmony_ci			usbc_hcintmsk.s.xacterrmsk = 1;
153962306a36Sopenharmony_ci			if (cvmx_usb_pipe_needs_split(usb, pipe)) {
154062306a36Sopenharmony_ci				/*
154162306a36Sopenharmony_ci				 * Splits don't generate xfercompl, so we need
154262306a36Sopenharmony_ci				 * ACK and NYET.
154362306a36Sopenharmony_ci				 */
154462306a36Sopenharmony_ci				usbc_hcintmsk.s.nyetmsk = 1;
154562306a36Sopenharmony_ci				usbc_hcintmsk.s.ackmsk = 1;
154662306a36Sopenharmony_ci			}
154762306a36Sopenharmony_ci			usbc_hcintmsk.s.nakmsk = 1;
154862306a36Sopenharmony_ci			usbc_hcintmsk.s.stallmsk = 1;
154962306a36Sopenharmony_ci			usbc_hcintmsk.s.xfercomplmsk = 1;
155062306a36Sopenharmony_ci		}
155162306a36Sopenharmony_ci		cvmx_usb_write_csr32(usb,
155262306a36Sopenharmony_ci				     CVMX_USBCX_HCINTMSKX(channel, usb->index),
155362306a36Sopenharmony_ci				     usbc_hcintmsk.u32);
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci		/* Enable the channel interrupt to propagate */
155662306a36Sopenharmony_ci		usbc_haintmsk.u32 = cvmx_usb_read_csr32(usb,
155762306a36Sopenharmony_ci							CVMX_USBCX_HAINTMSK(usb->index));
155862306a36Sopenharmony_ci		usbc_haintmsk.s.haintmsk |= 1 << channel;
155962306a36Sopenharmony_ci		cvmx_usb_write_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index),
156062306a36Sopenharmony_ci				     usbc_haintmsk.u32);
156162306a36Sopenharmony_ci	}
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	/* Setup the location the DMA engine uses. */
156462306a36Sopenharmony_ci	{
156562306a36Sopenharmony_ci		u64 reg;
156662306a36Sopenharmony_ci		u64 dma_address = transaction->buffer +
156762306a36Sopenharmony_ci				  transaction->actual_bytes;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci		if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
157062306a36Sopenharmony_ci			dma_address = transaction->buffer +
157162306a36Sopenharmony_ci					transaction->iso_packets[0].offset +
157262306a36Sopenharmony_ci					transaction->actual_bytes;
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci		if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT)
157562306a36Sopenharmony_ci			reg = CVMX_USBNX_DMA0_OUTB_CHN0(usb->index);
157662306a36Sopenharmony_ci		else
157762306a36Sopenharmony_ci			reg = CVMX_USBNX_DMA0_INB_CHN0(usb->index);
157862306a36Sopenharmony_ci		cvmx_write64_uint64(reg + channel * 8, dma_address);
157962306a36Sopenharmony_ci	}
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	/* Setup both the size of the transfer and the SPLIT characteristics */
158262306a36Sopenharmony_ci	{
158362306a36Sopenharmony_ci		union cvmx_usbcx_hcspltx usbc_hcsplt = {.u32 = 0};
158462306a36Sopenharmony_ci		union cvmx_usbcx_hctsizx usbc_hctsiz = {.u32 = 0};
158562306a36Sopenharmony_ci		int packets_to_transfer;
158662306a36Sopenharmony_ci		int bytes_to_transfer = transaction->buffer_length -
158762306a36Sopenharmony_ci			transaction->actual_bytes;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci		/*
159062306a36Sopenharmony_ci		 * ISOCHRONOUS transactions store each individual transfer size
159162306a36Sopenharmony_ci		 * in the packet structure, not the global buffer_length
159262306a36Sopenharmony_ci		 */
159362306a36Sopenharmony_ci		if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
159462306a36Sopenharmony_ci			bytes_to_transfer =
159562306a36Sopenharmony_ci				transaction->iso_packets[0].length -
159662306a36Sopenharmony_ci				transaction->actual_bytes;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci		/*
159962306a36Sopenharmony_ci		 * We need to do split transactions when we are talking to non
160062306a36Sopenharmony_ci		 * high speed devices that are behind a high speed hub
160162306a36Sopenharmony_ci		 */
160262306a36Sopenharmony_ci		if (cvmx_usb_pipe_needs_split(usb, pipe)) {
160362306a36Sopenharmony_ci			/*
160462306a36Sopenharmony_ci			 * On the start split phase (stage is even) record the
160562306a36Sopenharmony_ci			 * frame number we will need to send the split complete.
160662306a36Sopenharmony_ci			 * We only store the lower two bits since the time ahead
160762306a36Sopenharmony_ci			 * can only be two frames
160862306a36Sopenharmony_ci			 */
160962306a36Sopenharmony_ci			if ((transaction->stage & 1) == 0) {
161062306a36Sopenharmony_ci				if (transaction->type == CVMX_USB_TRANSFER_BULK)
161162306a36Sopenharmony_ci					pipe->split_sc_frame =
161262306a36Sopenharmony_ci						(usb->frame_number + 1) & 0x7f;
161362306a36Sopenharmony_ci				else
161462306a36Sopenharmony_ci					pipe->split_sc_frame =
161562306a36Sopenharmony_ci						(usb->frame_number + 2) & 0x7f;
161662306a36Sopenharmony_ci			} else {
161762306a36Sopenharmony_ci				pipe->split_sc_frame = -1;
161862306a36Sopenharmony_ci			}
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci			usbc_hcsplt.s.spltena = 1;
162162306a36Sopenharmony_ci			usbc_hcsplt.s.hubaddr = pipe->hub_device_addr;
162262306a36Sopenharmony_ci			usbc_hcsplt.s.prtaddr = pipe->hub_port;
162362306a36Sopenharmony_ci			usbc_hcsplt.s.compsplt = (transaction->stage ==
162462306a36Sopenharmony_ci				CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE);
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci			/*
162762306a36Sopenharmony_ci			 * SPLIT transactions can only ever transmit one data
162862306a36Sopenharmony_ci			 * packet so limit the transfer size to the max packet
162962306a36Sopenharmony_ci			 * size
163062306a36Sopenharmony_ci			 */
163162306a36Sopenharmony_ci			if (bytes_to_transfer > pipe->max_packet)
163262306a36Sopenharmony_ci				bytes_to_transfer = pipe->max_packet;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci			/*
163562306a36Sopenharmony_ci			 * ISOCHRONOUS OUT splits are unique in that they limit
163662306a36Sopenharmony_ci			 * data transfers to 188 byte chunks representing the
163762306a36Sopenharmony_ci			 * begin/middle/end of the data or all
163862306a36Sopenharmony_ci			 */
163962306a36Sopenharmony_ci			if (!usbc_hcsplt.s.compsplt &&
164062306a36Sopenharmony_ci			    (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
164162306a36Sopenharmony_ci			    (pipe->transfer_type ==
164262306a36Sopenharmony_ci			     CVMX_USB_TRANSFER_ISOCHRONOUS)) {
164362306a36Sopenharmony_ci				/*
164462306a36Sopenharmony_ci				 * Clear the split complete frame number as
164562306a36Sopenharmony_ci				 * there isn't going to be a split complete
164662306a36Sopenharmony_ci				 */
164762306a36Sopenharmony_ci				pipe->split_sc_frame = -1;
164862306a36Sopenharmony_ci				/*
164962306a36Sopenharmony_ci				 * See if we've started this transfer and sent
165062306a36Sopenharmony_ci				 * data
165162306a36Sopenharmony_ci				 */
165262306a36Sopenharmony_ci				if (transaction->actual_bytes == 0) {
165362306a36Sopenharmony_ci					/*
165462306a36Sopenharmony_ci					 * Nothing sent yet, this is either a
165562306a36Sopenharmony_ci					 * begin or the entire payload
165662306a36Sopenharmony_ci					 */
165762306a36Sopenharmony_ci					if (bytes_to_transfer <= 188)
165862306a36Sopenharmony_ci						/* Entire payload in one go */
165962306a36Sopenharmony_ci						usbc_hcsplt.s.xactpos = 3;
166062306a36Sopenharmony_ci					else
166162306a36Sopenharmony_ci						/* First part of payload */
166262306a36Sopenharmony_ci						usbc_hcsplt.s.xactpos = 2;
166362306a36Sopenharmony_ci				} else {
166462306a36Sopenharmony_ci					/*
166562306a36Sopenharmony_ci					 * Continuing the previous data, we must
166662306a36Sopenharmony_ci					 * either be in the middle or at the end
166762306a36Sopenharmony_ci					 */
166862306a36Sopenharmony_ci					if (bytes_to_transfer <= 188)
166962306a36Sopenharmony_ci						/* End of payload */
167062306a36Sopenharmony_ci						usbc_hcsplt.s.xactpos = 1;
167162306a36Sopenharmony_ci					else
167262306a36Sopenharmony_ci						/* Middle of payload */
167362306a36Sopenharmony_ci						usbc_hcsplt.s.xactpos = 0;
167462306a36Sopenharmony_ci				}
167562306a36Sopenharmony_ci				/*
167662306a36Sopenharmony_ci				 * Again, the transfer size is limited to 188
167762306a36Sopenharmony_ci				 * bytes
167862306a36Sopenharmony_ci				 */
167962306a36Sopenharmony_ci				if (bytes_to_transfer > 188)
168062306a36Sopenharmony_ci					bytes_to_transfer = 188;
168162306a36Sopenharmony_ci			}
168262306a36Sopenharmony_ci		}
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci		/*
168562306a36Sopenharmony_ci		 * Make sure the transfer never exceeds the byte limit of the
168662306a36Sopenharmony_ci		 * hardware. Further bytes will be sent as continued
168762306a36Sopenharmony_ci		 * transactions
168862306a36Sopenharmony_ci		 */
168962306a36Sopenharmony_ci		if (bytes_to_transfer > MAX_TRANSFER_BYTES) {
169062306a36Sopenharmony_ci			/*
169162306a36Sopenharmony_ci			 * Round MAX_TRANSFER_BYTES to a multiple of out packet
169262306a36Sopenharmony_ci			 * size
169362306a36Sopenharmony_ci			 */
169462306a36Sopenharmony_ci			bytes_to_transfer = MAX_TRANSFER_BYTES /
169562306a36Sopenharmony_ci				pipe->max_packet;
169662306a36Sopenharmony_ci			bytes_to_transfer *= pipe->max_packet;
169762306a36Sopenharmony_ci		}
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci		/*
170062306a36Sopenharmony_ci		 * Calculate the number of packets to transfer. If the length is
170162306a36Sopenharmony_ci		 * zero we still need to transfer one packet
170262306a36Sopenharmony_ci		 */
170362306a36Sopenharmony_ci		packets_to_transfer =
170462306a36Sopenharmony_ci			DIV_ROUND_UP(bytes_to_transfer, pipe->max_packet);
170562306a36Sopenharmony_ci		if (packets_to_transfer == 0) {
170662306a36Sopenharmony_ci			packets_to_transfer = 1;
170762306a36Sopenharmony_ci		} else if ((packets_to_transfer > 1) &&
170862306a36Sopenharmony_ci			   (usb->init_flags &
170962306a36Sopenharmony_ci			    CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
171062306a36Sopenharmony_ci			/*
171162306a36Sopenharmony_ci			 * Limit to one packet when not using DMA. Channels must
171262306a36Sopenharmony_ci			 * be restarted between every packet for IN
171362306a36Sopenharmony_ci			 * transactions, so there is no reason to do multiple
171462306a36Sopenharmony_ci			 * packets in a row
171562306a36Sopenharmony_ci			 */
171662306a36Sopenharmony_ci			packets_to_transfer = 1;
171762306a36Sopenharmony_ci			bytes_to_transfer = packets_to_transfer *
171862306a36Sopenharmony_ci				pipe->max_packet;
171962306a36Sopenharmony_ci		} else if (packets_to_transfer > MAX_TRANSFER_PACKETS) {
172062306a36Sopenharmony_ci			/*
172162306a36Sopenharmony_ci			 * Limit the number of packet and data transferred to
172262306a36Sopenharmony_ci			 * what the hardware can handle
172362306a36Sopenharmony_ci			 */
172462306a36Sopenharmony_ci			packets_to_transfer = MAX_TRANSFER_PACKETS;
172562306a36Sopenharmony_ci			bytes_to_transfer = packets_to_transfer *
172662306a36Sopenharmony_ci				pipe->max_packet;
172762306a36Sopenharmony_ci		}
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci		usbc_hctsiz.s.xfersize = bytes_to_transfer;
173062306a36Sopenharmony_ci		usbc_hctsiz.s.pktcnt = packets_to_transfer;
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci		/* Update the DATA0/DATA1 toggle */
173362306a36Sopenharmony_ci		usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe);
173462306a36Sopenharmony_ci		/*
173562306a36Sopenharmony_ci		 * High speed pipes may need a hardware ping before they start
173662306a36Sopenharmony_ci		 */
173762306a36Sopenharmony_ci		if (pipe->flags & CVMX_USB_PIPE_FLAGS_NEED_PING)
173862306a36Sopenharmony_ci			usbc_hctsiz.s.dopng = 1;
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci		cvmx_usb_write_csr32(usb,
174162306a36Sopenharmony_ci				     CVMX_USBCX_HCSPLTX(channel, usb->index),
174262306a36Sopenharmony_ci				     usbc_hcsplt.u32);
174362306a36Sopenharmony_ci		cvmx_usb_write_csr32(usb,
174462306a36Sopenharmony_ci				     CVMX_USBCX_HCTSIZX(channel, usb->index),
174562306a36Sopenharmony_ci				     usbc_hctsiz.u32);
174662306a36Sopenharmony_ci	}
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	/* Setup the Host Channel Characteristics Register */
174962306a36Sopenharmony_ci	{
175062306a36Sopenharmony_ci		union cvmx_usbcx_hccharx usbc_hcchar = {.u32 = 0};
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci		/*
175362306a36Sopenharmony_ci		 * Set the startframe odd/even properly. This is only used for
175462306a36Sopenharmony_ci		 * periodic
175562306a36Sopenharmony_ci		 */
175662306a36Sopenharmony_ci		usbc_hcchar.s.oddfrm = usb->frame_number & 1;
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci		/*
175962306a36Sopenharmony_ci		 * Set the number of back to back packets allowed by this
176062306a36Sopenharmony_ci		 * endpoint. Split transactions interpret "ec" as the number of
176162306a36Sopenharmony_ci		 * immediate retries of failure. These retries happen too
176262306a36Sopenharmony_ci		 * quickly, so we disable these entirely for splits
176362306a36Sopenharmony_ci		 */
176462306a36Sopenharmony_ci		if (cvmx_usb_pipe_needs_split(usb, pipe))
176562306a36Sopenharmony_ci			usbc_hcchar.s.ec = 1;
176662306a36Sopenharmony_ci		else if (pipe->multi_count < 1)
176762306a36Sopenharmony_ci			usbc_hcchar.s.ec = 1;
176862306a36Sopenharmony_ci		else if (pipe->multi_count > 3)
176962306a36Sopenharmony_ci			usbc_hcchar.s.ec = 3;
177062306a36Sopenharmony_ci		else
177162306a36Sopenharmony_ci			usbc_hcchar.s.ec = pipe->multi_count;
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci		/* Set the rest of the endpoint specific settings */
177462306a36Sopenharmony_ci		usbc_hcchar.s.devaddr = pipe->device_addr;
177562306a36Sopenharmony_ci		usbc_hcchar.s.eptype = transaction->type;
177662306a36Sopenharmony_ci		usbc_hcchar.s.lspddev =
177762306a36Sopenharmony_ci			(pipe->device_speed == CVMX_USB_SPEED_LOW);
177862306a36Sopenharmony_ci		usbc_hcchar.s.epdir = pipe->transfer_dir;
177962306a36Sopenharmony_ci		usbc_hcchar.s.epnum = pipe->endpoint_num;
178062306a36Sopenharmony_ci		usbc_hcchar.s.mps = pipe->max_packet;
178162306a36Sopenharmony_ci		cvmx_usb_write_csr32(usb,
178262306a36Sopenharmony_ci				     CVMX_USBCX_HCCHARX(channel, usb->index),
178362306a36Sopenharmony_ci				     usbc_hcchar.u32);
178462306a36Sopenharmony_ci	}
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	/* Do transaction type specific fixups as needed */
178762306a36Sopenharmony_ci	switch (transaction->type) {
178862306a36Sopenharmony_ci	case CVMX_USB_TRANSFER_CONTROL:
178962306a36Sopenharmony_ci		cvmx_usb_start_channel_control(usb, channel, pipe);
179062306a36Sopenharmony_ci		break;
179162306a36Sopenharmony_ci	case CVMX_USB_TRANSFER_BULK:
179262306a36Sopenharmony_ci	case CVMX_USB_TRANSFER_INTERRUPT:
179362306a36Sopenharmony_ci		break;
179462306a36Sopenharmony_ci	case CVMX_USB_TRANSFER_ISOCHRONOUS:
179562306a36Sopenharmony_ci		if (!cvmx_usb_pipe_needs_split(usb, pipe)) {
179662306a36Sopenharmony_ci			/*
179762306a36Sopenharmony_ci			 * ISO transactions require different PIDs depending on
179862306a36Sopenharmony_ci			 * direction and how many packets are needed
179962306a36Sopenharmony_ci			 */
180062306a36Sopenharmony_ci			if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
180162306a36Sopenharmony_ci				if (pipe->multi_count < 2) /* Need DATA0 */
180262306a36Sopenharmony_ci					USB_SET_FIELD32(
180362306a36Sopenharmony_ci						CVMX_USBCX_HCTSIZX(channel,
180462306a36Sopenharmony_ci								   usb->index),
180562306a36Sopenharmony_ci						cvmx_usbcx_hctsizx, pid, 0);
180662306a36Sopenharmony_ci				else /* Need MDATA */
180762306a36Sopenharmony_ci					USB_SET_FIELD32(
180862306a36Sopenharmony_ci						CVMX_USBCX_HCTSIZX(channel,
180962306a36Sopenharmony_ci								   usb->index),
181062306a36Sopenharmony_ci						cvmx_usbcx_hctsizx, pid, 3);
181162306a36Sopenharmony_ci			}
181262306a36Sopenharmony_ci		}
181362306a36Sopenharmony_ci		break;
181462306a36Sopenharmony_ci	}
181562306a36Sopenharmony_ci	{
181662306a36Sopenharmony_ci		union cvmx_usbcx_hctsizx usbc_hctsiz = { .u32 =
181762306a36Sopenharmony_ci			cvmx_usb_read_csr32(usb,
181862306a36Sopenharmony_ci					    CVMX_USBCX_HCTSIZX(channel,
181962306a36Sopenharmony_ci							       usb->index))
182062306a36Sopenharmony_ci		};
182162306a36Sopenharmony_ci		transaction->xfersize = usbc_hctsiz.s.xfersize;
182262306a36Sopenharmony_ci		transaction->pktcnt = usbc_hctsiz.s.pktcnt;
182362306a36Sopenharmony_ci	}
182462306a36Sopenharmony_ci	/* Remember when we start a split transaction */
182562306a36Sopenharmony_ci	if (cvmx_usb_pipe_needs_split(usb, pipe))
182662306a36Sopenharmony_ci		usb->active_split = transaction;
182762306a36Sopenharmony_ci	USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
182862306a36Sopenharmony_ci			cvmx_usbcx_hccharx, chena, 1);
182962306a36Sopenharmony_ci	if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
183062306a36Sopenharmony_ci		cvmx_usb_fill_tx_fifo(usb, channel);
183162306a36Sopenharmony_ci}
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci/**
183462306a36Sopenharmony_ci * Find a pipe that is ready to be scheduled to hardware.
183562306a36Sopenharmony_ci * @usb:	 USB device state populated by cvmx_usb_initialize().
183662306a36Sopenharmony_ci * @xfer_type:	 Transfer type
183762306a36Sopenharmony_ci *
183862306a36Sopenharmony_ci * Returns: Pipe or NULL if none are ready
183962306a36Sopenharmony_ci */
184062306a36Sopenharmony_cistatic struct cvmx_usb_pipe *cvmx_usb_find_ready_pipe(struct octeon_hcd *usb,
184162306a36Sopenharmony_ci						      enum cvmx_usb_transfer xfer_type)
184262306a36Sopenharmony_ci{
184362306a36Sopenharmony_ci	struct list_head *list = usb->active_pipes + xfer_type;
184462306a36Sopenharmony_ci	u64 current_frame = usb->frame_number;
184562306a36Sopenharmony_ci	struct cvmx_usb_pipe *pipe;
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	list_for_each_entry(pipe, list, node) {
184862306a36Sopenharmony_ci		struct cvmx_usb_transaction *t =
184962306a36Sopenharmony_ci			list_first_entry(&pipe->transactions, typeof(*t),
185062306a36Sopenharmony_ci					 node);
185162306a36Sopenharmony_ci		if (!(pipe->flags & CVMX_USB_PIPE_FLAGS_SCHEDULED) && t &&
185262306a36Sopenharmony_ci		    (pipe->next_tx_frame <= current_frame) &&
185362306a36Sopenharmony_ci		    ((pipe->split_sc_frame == -1) ||
185462306a36Sopenharmony_ci		     ((((int)current_frame - pipe->split_sc_frame) & 0x7f) <
185562306a36Sopenharmony_ci		      0x40)) &&
185662306a36Sopenharmony_ci		    (!usb->active_split || (usb->active_split == t))) {
185762306a36Sopenharmony_ci			prefetch(t);
185862306a36Sopenharmony_ci			return pipe;
185962306a36Sopenharmony_ci		}
186062306a36Sopenharmony_ci	}
186162306a36Sopenharmony_ci	return NULL;
186262306a36Sopenharmony_ci}
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_cistatic struct cvmx_usb_pipe *cvmx_usb_next_pipe(struct octeon_hcd *usb,
186562306a36Sopenharmony_ci						int is_sof)
186662306a36Sopenharmony_ci{
186762306a36Sopenharmony_ci	struct cvmx_usb_pipe *pipe;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	/* Find a pipe needing service. */
187062306a36Sopenharmony_ci	if (is_sof) {
187162306a36Sopenharmony_ci		/*
187262306a36Sopenharmony_ci		 * Only process periodic pipes on SOF interrupts. This way we
187362306a36Sopenharmony_ci		 * are sure that the periodic data is sent in the beginning of
187462306a36Sopenharmony_ci		 * the frame.
187562306a36Sopenharmony_ci		 */
187662306a36Sopenharmony_ci		pipe = cvmx_usb_find_ready_pipe(usb,
187762306a36Sopenharmony_ci						CVMX_USB_TRANSFER_ISOCHRONOUS);
187862306a36Sopenharmony_ci		if (pipe)
187962306a36Sopenharmony_ci			return pipe;
188062306a36Sopenharmony_ci		pipe = cvmx_usb_find_ready_pipe(usb,
188162306a36Sopenharmony_ci						CVMX_USB_TRANSFER_INTERRUPT);
188262306a36Sopenharmony_ci		if (pipe)
188362306a36Sopenharmony_ci			return pipe;
188462306a36Sopenharmony_ci	}
188562306a36Sopenharmony_ci	pipe = cvmx_usb_find_ready_pipe(usb, CVMX_USB_TRANSFER_CONTROL);
188662306a36Sopenharmony_ci	if (pipe)
188762306a36Sopenharmony_ci		return pipe;
188862306a36Sopenharmony_ci	return cvmx_usb_find_ready_pipe(usb, CVMX_USB_TRANSFER_BULK);
188962306a36Sopenharmony_ci}
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci/**
189262306a36Sopenharmony_ci * Called whenever a pipe might need to be scheduled to the
189362306a36Sopenharmony_ci * hardware.
189462306a36Sopenharmony_ci *
189562306a36Sopenharmony_ci * @usb:	 USB device state populated by cvmx_usb_initialize().
189662306a36Sopenharmony_ci * @is_sof:	 True if this schedule was called on a SOF interrupt.
189762306a36Sopenharmony_ci */
189862306a36Sopenharmony_cistatic void cvmx_usb_schedule(struct octeon_hcd *usb, int is_sof)
189962306a36Sopenharmony_ci{
190062306a36Sopenharmony_ci	int channel;
190162306a36Sopenharmony_ci	struct cvmx_usb_pipe *pipe;
190262306a36Sopenharmony_ci	int need_sof;
190362306a36Sopenharmony_ci	enum cvmx_usb_transfer ttype;
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
190662306a36Sopenharmony_ci		/*
190762306a36Sopenharmony_ci		 * Without DMA we need to be careful to not schedule something
190862306a36Sopenharmony_ci		 * at the end of a frame and cause an overrun.
190962306a36Sopenharmony_ci		 */
191062306a36Sopenharmony_ci		union cvmx_usbcx_hfnum hfnum = {
191162306a36Sopenharmony_ci			.u32 = cvmx_usb_read_csr32(usb,
191262306a36Sopenharmony_ci						CVMX_USBCX_HFNUM(usb->index))
191362306a36Sopenharmony_ci		};
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci		union cvmx_usbcx_hfir hfir = {
191662306a36Sopenharmony_ci			.u32 = cvmx_usb_read_csr32(usb,
191762306a36Sopenharmony_ci						CVMX_USBCX_HFIR(usb->index))
191862306a36Sopenharmony_ci		};
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci		if (hfnum.s.frrem < hfir.s.frint / 4)
192162306a36Sopenharmony_ci			goto done;
192262306a36Sopenharmony_ci	}
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	while (usb->idle_hardware_channels) {
192562306a36Sopenharmony_ci		/* Find an idle channel */
192662306a36Sopenharmony_ci		channel = __fls(usb->idle_hardware_channels);
192762306a36Sopenharmony_ci		if (unlikely(channel > 7))
192862306a36Sopenharmony_ci			break;
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci		pipe = cvmx_usb_next_pipe(usb, is_sof);
193162306a36Sopenharmony_ci		if (!pipe)
193262306a36Sopenharmony_ci			break;
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci		cvmx_usb_start_channel(usb, channel, pipe);
193562306a36Sopenharmony_ci	}
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_cidone:
193862306a36Sopenharmony_ci	/*
193962306a36Sopenharmony_ci	 * Only enable SOF interrupts when we have transactions pending in the
194062306a36Sopenharmony_ci	 * future that might need to be scheduled
194162306a36Sopenharmony_ci	 */
194262306a36Sopenharmony_ci	need_sof = 0;
194362306a36Sopenharmony_ci	for (ttype = CVMX_USB_TRANSFER_CONTROL;
194462306a36Sopenharmony_ci	     ttype <= CVMX_USB_TRANSFER_INTERRUPT; ttype++) {
194562306a36Sopenharmony_ci		list_for_each_entry(pipe, &usb->active_pipes[ttype], node) {
194662306a36Sopenharmony_ci			if (pipe->next_tx_frame > usb->frame_number) {
194762306a36Sopenharmony_ci				need_sof = 1;
194862306a36Sopenharmony_ci				break;
194962306a36Sopenharmony_ci			}
195062306a36Sopenharmony_ci		}
195162306a36Sopenharmony_ci	}
195262306a36Sopenharmony_ci	USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
195362306a36Sopenharmony_ci			cvmx_usbcx_gintmsk, sofmsk, need_sof);
195462306a36Sopenharmony_ci}
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_cistatic void octeon_usb_urb_complete_callback(struct octeon_hcd *usb,
195762306a36Sopenharmony_ci					     enum cvmx_usb_status status,
195862306a36Sopenharmony_ci					     struct cvmx_usb_pipe *pipe,
195962306a36Sopenharmony_ci					     struct cvmx_usb_transaction
196062306a36Sopenharmony_ci						*transaction,
196162306a36Sopenharmony_ci					     int bytes_transferred,
196262306a36Sopenharmony_ci					     struct urb *urb)
196362306a36Sopenharmony_ci{
196462306a36Sopenharmony_ci	struct usb_hcd *hcd = octeon_to_hcd(usb);
196562306a36Sopenharmony_ci	struct device *dev = hcd->self.controller;
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	if (likely(status == CVMX_USB_STATUS_OK))
196862306a36Sopenharmony_ci		urb->actual_length = bytes_transferred;
196962306a36Sopenharmony_ci	else
197062306a36Sopenharmony_ci		urb->actual_length = 0;
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	urb->hcpriv = NULL;
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	/* For Isochronous transactions we need to update the URB packet status
197562306a36Sopenharmony_ci	 * list from data in our private copy
197662306a36Sopenharmony_ci	 */
197762306a36Sopenharmony_ci	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
197862306a36Sopenharmony_ci		int i;
197962306a36Sopenharmony_ci		/*
198062306a36Sopenharmony_ci		 * The pointer to the private list is stored in the setup_packet
198162306a36Sopenharmony_ci		 * field.
198262306a36Sopenharmony_ci		 */
198362306a36Sopenharmony_ci		struct cvmx_usb_iso_packet *iso_packet =
198462306a36Sopenharmony_ci			(struct cvmx_usb_iso_packet *)urb->setup_packet;
198562306a36Sopenharmony_ci		/* Recalculate the transfer size by adding up each packet */
198662306a36Sopenharmony_ci		urb->actual_length = 0;
198762306a36Sopenharmony_ci		for (i = 0; i < urb->number_of_packets; i++) {
198862306a36Sopenharmony_ci			if (iso_packet[i].status == CVMX_USB_STATUS_OK) {
198962306a36Sopenharmony_ci				urb->iso_frame_desc[i].status = 0;
199062306a36Sopenharmony_ci				urb->iso_frame_desc[i].actual_length =
199162306a36Sopenharmony_ci					iso_packet[i].length;
199262306a36Sopenharmony_ci				urb->actual_length +=
199362306a36Sopenharmony_ci					urb->iso_frame_desc[i].actual_length;
199462306a36Sopenharmony_ci			} else {
199562306a36Sopenharmony_ci				dev_dbg(dev, "ISOCHRONOUS packet=%d of %d status=%d pipe=%p transaction=%p size=%d\n",
199662306a36Sopenharmony_ci					i, urb->number_of_packets,
199762306a36Sopenharmony_ci					iso_packet[i].status, pipe,
199862306a36Sopenharmony_ci					transaction, iso_packet[i].length);
199962306a36Sopenharmony_ci				urb->iso_frame_desc[i].status = -EREMOTEIO;
200062306a36Sopenharmony_ci			}
200162306a36Sopenharmony_ci		}
200262306a36Sopenharmony_ci		/* Free the private list now that we don't need it anymore */
200362306a36Sopenharmony_ci		kfree(iso_packet);
200462306a36Sopenharmony_ci		urb->setup_packet = NULL;
200562306a36Sopenharmony_ci	}
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci	switch (status) {
200862306a36Sopenharmony_ci	case CVMX_USB_STATUS_OK:
200962306a36Sopenharmony_ci		urb->status = 0;
201062306a36Sopenharmony_ci		break;
201162306a36Sopenharmony_ci	case CVMX_USB_STATUS_CANCEL:
201262306a36Sopenharmony_ci		if (urb->status == 0)
201362306a36Sopenharmony_ci			urb->status = -ENOENT;
201462306a36Sopenharmony_ci		break;
201562306a36Sopenharmony_ci	case CVMX_USB_STATUS_STALL:
201662306a36Sopenharmony_ci		dev_dbg(dev, "status=stall pipe=%p transaction=%p size=%d\n",
201762306a36Sopenharmony_ci			pipe, transaction, bytes_transferred);
201862306a36Sopenharmony_ci		urb->status = -EPIPE;
201962306a36Sopenharmony_ci		break;
202062306a36Sopenharmony_ci	case CVMX_USB_STATUS_BABBLEERR:
202162306a36Sopenharmony_ci		dev_dbg(dev, "status=babble pipe=%p transaction=%p size=%d\n",
202262306a36Sopenharmony_ci			pipe, transaction, bytes_transferred);
202362306a36Sopenharmony_ci		urb->status = -EPIPE;
202462306a36Sopenharmony_ci		break;
202562306a36Sopenharmony_ci	case CVMX_USB_STATUS_SHORT:
202662306a36Sopenharmony_ci		dev_dbg(dev, "status=short pipe=%p transaction=%p size=%d\n",
202762306a36Sopenharmony_ci			pipe, transaction, bytes_transferred);
202862306a36Sopenharmony_ci		urb->status = -EREMOTEIO;
202962306a36Sopenharmony_ci		break;
203062306a36Sopenharmony_ci	case CVMX_USB_STATUS_ERROR:
203162306a36Sopenharmony_ci	case CVMX_USB_STATUS_XACTERR:
203262306a36Sopenharmony_ci	case CVMX_USB_STATUS_DATATGLERR:
203362306a36Sopenharmony_ci	case CVMX_USB_STATUS_FRAMEERR:
203462306a36Sopenharmony_ci		dev_dbg(dev, "status=%d pipe=%p transaction=%p size=%d\n",
203562306a36Sopenharmony_ci			status, pipe, transaction, bytes_transferred);
203662306a36Sopenharmony_ci		urb->status = -EPROTO;
203762306a36Sopenharmony_ci		break;
203862306a36Sopenharmony_ci	}
203962306a36Sopenharmony_ci	usb_hcd_unlink_urb_from_ep(octeon_to_hcd(usb), urb);
204062306a36Sopenharmony_ci	spin_unlock(&usb->lock);
204162306a36Sopenharmony_ci	usb_hcd_giveback_urb(octeon_to_hcd(usb), urb, urb->status);
204262306a36Sopenharmony_ci	spin_lock(&usb->lock);
204362306a36Sopenharmony_ci}
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci/**
204662306a36Sopenharmony_ci * Signal the completion of a transaction and free it. The
204762306a36Sopenharmony_ci * transaction will be removed from the pipe transaction list.
204862306a36Sopenharmony_ci *
204962306a36Sopenharmony_ci * @usb:	 USB device state populated by cvmx_usb_initialize().
205062306a36Sopenharmony_ci * @pipe:	 Pipe the transaction is on
205162306a36Sopenharmony_ci * @transaction:
205262306a36Sopenharmony_ci *		 Transaction that completed
205362306a36Sopenharmony_ci * @complete_code:
205462306a36Sopenharmony_ci *		 Completion code
205562306a36Sopenharmony_ci */
205662306a36Sopenharmony_cistatic void cvmx_usb_complete(struct octeon_hcd *usb,
205762306a36Sopenharmony_ci			      struct cvmx_usb_pipe *pipe,
205862306a36Sopenharmony_ci			      struct cvmx_usb_transaction *transaction,
205962306a36Sopenharmony_ci			      enum cvmx_usb_status complete_code)
206062306a36Sopenharmony_ci{
206162306a36Sopenharmony_ci	/* If this was a split then clear our split in progress marker */
206262306a36Sopenharmony_ci	if (usb->active_split == transaction)
206362306a36Sopenharmony_ci		usb->active_split = NULL;
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	/*
206662306a36Sopenharmony_ci	 * Isochronous transactions need extra processing as they might not be
206762306a36Sopenharmony_ci	 * done after a single data transfer
206862306a36Sopenharmony_ci	 */
206962306a36Sopenharmony_ci	if (unlikely(transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)) {
207062306a36Sopenharmony_ci		/* Update the number of bytes transferred in this ISO packet */
207162306a36Sopenharmony_ci		transaction->iso_packets[0].length = transaction->actual_bytes;
207262306a36Sopenharmony_ci		transaction->iso_packets[0].status = complete_code;
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci		/*
207562306a36Sopenharmony_ci		 * If there are more ISOs pending and we succeeded, schedule the
207662306a36Sopenharmony_ci		 * next one
207762306a36Sopenharmony_ci		 */
207862306a36Sopenharmony_ci		if ((transaction->iso_number_packets > 1) &&
207962306a36Sopenharmony_ci		    (complete_code == CVMX_USB_STATUS_OK)) {
208062306a36Sopenharmony_ci			/* No bytes transferred for this packet as of yet */
208162306a36Sopenharmony_ci			transaction->actual_bytes = 0;
208262306a36Sopenharmony_ci			/* One less ISO waiting to transfer */
208362306a36Sopenharmony_ci			transaction->iso_number_packets--;
208462306a36Sopenharmony_ci			/* Increment to the next location in our packet array */
208562306a36Sopenharmony_ci			transaction->iso_packets++;
208662306a36Sopenharmony_ci			transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
208762306a36Sopenharmony_ci			return;
208862306a36Sopenharmony_ci		}
208962306a36Sopenharmony_ci	}
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	/* Remove the transaction from the pipe list */
209262306a36Sopenharmony_ci	list_del(&transaction->node);
209362306a36Sopenharmony_ci	if (list_empty(&pipe->transactions))
209462306a36Sopenharmony_ci		list_move_tail(&pipe->node, &usb->idle_pipes);
209562306a36Sopenharmony_ci	octeon_usb_urb_complete_callback(usb, complete_code, pipe,
209662306a36Sopenharmony_ci					 transaction,
209762306a36Sopenharmony_ci					 transaction->actual_bytes,
209862306a36Sopenharmony_ci					 transaction->urb);
209962306a36Sopenharmony_ci	kfree(transaction);
210062306a36Sopenharmony_ci}
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci/**
210362306a36Sopenharmony_ci * Submit a usb transaction to a pipe. Called for all types
210462306a36Sopenharmony_ci * of transactions.
210562306a36Sopenharmony_ci *
210662306a36Sopenharmony_ci * @usb:
210762306a36Sopenharmony_ci * @pipe:	    Which pipe to submit to.
210862306a36Sopenharmony_ci * @type:	    Transaction type
210962306a36Sopenharmony_ci * @buffer:	    User buffer for the transaction
211062306a36Sopenharmony_ci * @buffer_length:
211162306a36Sopenharmony_ci *		    User buffer's length in bytes
211262306a36Sopenharmony_ci * @control_header:
211362306a36Sopenharmony_ci *		    For control transactions, the 8 byte standard header
211462306a36Sopenharmony_ci * @iso_start_frame:
211562306a36Sopenharmony_ci *		    For ISO transactions, the start frame
211662306a36Sopenharmony_ci * @iso_number_packets:
211762306a36Sopenharmony_ci *		    For ISO, the number of packet in the transaction.
211862306a36Sopenharmony_ci * @iso_packets:
211962306a36Sopenharmony_ci *		    A description of each ISO packet
212062306a36Sopenharmony_ci * @urb:	    URB for the callback
212162306a36Sopenharmony_ci *
212262306a36Sopenharmony_ci * Returns: Transaction or NULL on failure.
212362306a36Sopenharmony_ci */
212462306a36Sopenharmony_cistatic struct cvmx_usb_transaction *cvmx_usb_submit_transaction(
212562306a36Sopenharmony_ci				struct octeon_hcd *usb,
212662306a36Sopenharmony_ci				struct cvmx_usb_pipe *pipe,
212762306a36Sopenharmony_ci				enum cvmx_usb_transfer type,
212862306a36Sopenharmony_ci				u64 buffer,
212962306a36Sopenharmony_ci				int buffer_length,
213062306a36Sopenharmony_ci				u64 control_header,
213162306a36Sopenharmony_ci				int iso_start_frame,
213262306a36Sopenharmony_ci				int iso_number_packets,
213362306a36Sopenharmony_ci				struct cvmx_usb_iso_packet *iso_packets,
213462306a36Sopenharmony_ci				struct urb *urb)
213562306a36Sopenharmony_ci{
213662306a36Sopenharmony_ci	struct cvmx_usb_transaction *transaction;
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	if (unlikely(pipe->transfer_type != type))
213962306a36Sopenharmony_ci		return NULL;
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	transaction = kzalloc(sizeof(*transaction), GFP_ATOMIC);
214262306a36Sopenharmony_ci	if (unlikely(!transaction))
214362306a36Sopenharmony_ci		return NULL;
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	transaction->type = type;
214662306a36Sopenharmony_ci	transaction->buffer = buffer;
214762306a36Sopenharmony_ci	transaction->buffer_length = buffer_length;
214862306a36Sopenharmony_ci	transaction->control_header = control_header;
214962306a36Sopenharmony_ci	/* FIXME: This is not used, implement it. */
215062306a36Sopenharmony_ci	transaction->iso_start_frame = iso_start_frame;
215162306a36Sopenharmony_ci	transaction->iso_number_packets = iso_number_packets;
215262306a36Sopenharmony_ci	transaction->iso_packets = iso_packets;
215362306a36Sopenharmony_ci	transaction->urb = urb;
215462306a36Sopenharmony_ci	if (transaction->type == CVMX_USB_TRANSFER_CONTROL)
215562306a36Sopenharmony_ci		transaction->stage = CVMX_USB_STAGE_SETUP;
215662306a36Sopenharmony_ci	else
215762306a36Sopenharmony_ci		transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	if (!list_empty(&pipe->transactions)) {
216062306a36Sopenharmony_ci		list_add_tail(&transaction->node, &pipe->transactions);
216162306a36Sopenharmony_ci	} else {
216262306a36Sopenharmony_ci		list_add_tail(&transaction->node, &pipe->transactions);
216362306a36Sopenharmony_ci		list_move_tail(&pipe->node,
216462306a36Sopenharmony_ci			       &usb->active_pipes[pipe->transfer_type]);
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci		/*
216762306a36Sopenharmony_ci		 * We may need to schedule the pipe if this was the head of the
216862306a36Sopenharmony_ci		 * pipe.
216962306a36Sopenharmony_ci		 */
217062306a36Sopenharmony_ci		cvmx_usb_schedule(usb, 0);
217162306a36Sopenharmony_ci	}
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	return transaction;
217462306a36Sopenharmony_ci}
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci/**
217762306a36Sopenharmony_ci * Call to submit a USB Bulk transfer to a pipe.
217862306a36Sopenharmony_ci *
217962306a36Sopenharmony_ci * @usb:	    USB device state populated by cvmx_usb_initialize().
218062306a36Sopenharmony_ci * @pipe:	    Handle to the pipe for the transfer.
218162306a36Sopenharmony_ci * @urb:	    URB.
218262306a36Sopenharmony_ci *
218362306a36Sopenharmony_ci * Returns: A submitted transaction or NULL on failure.
218462306a36Sopenharmony_ci */
218562306a36Sopenharmony_cistatic struct cvmx_usb_transaction *cvmx_usb_submit_bulk(
218662306a36Sopenharmony_ci						struct octeon_hcd *usb,
218762306a36Sopenharmony_ci						struct cvmx_usb_pipe *pipe,
218862306a36Sopenharmony_ci						struct urb *urb)
218962306a36Sopenharmony_ci{
219062306a36Sopenharmony_ci	return cvmx_usb_submit_transaction(usb, pipe, CVMX_USB_TRANSFER_BULK,
219162306a36Sopenharmony_ci					   urb->transfer_dma,
219262306a36Sopenharmony_ci					   urb->transfer_buffer_length,
219362306a36Sopenharmony_ci					   0, /* control_header */
219462306a36Sopenharmony_ci					   0, /* iso_start_frame */
219562306a36Sopenharmony_ci					   0, /* iso_number_packets */
219662306a36Sopenharmony_ci					   NULL, /* iso_packets */
219762306a36Sopenharmony_ci					   urb);
219862306a36Sopenharmony_ci}
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci/**
220162306a36Sopenharmony_ci * Call to submit a USB Interrupt transfer to a pipe.
220262306a36Sopenharmony_ci *
220362306a36Sopenharmony_ci * @usb:	    USB device state populated by cvmx_usb_initialize().
220462306a36Sopenharmony_ci * @pipe:	    Handle to the pipe for the transfer.
220562306a36Sopenharmony_ci * @urb:	    URB returned when the callback is called.
220662306a36Sopenharmony_ci *
220762306a36Sopenharmony_ci * Returns: A submitted transaction or NULL on failure.
220862306a36Sopenharmony_ci */
220962306a36Sopenharmony_cistatic struct cvmx_usb_transaction *cvmx_usb_submit_interrupt(
221062306a36Sopenharmony_ci						struct octeon_hcd *usb,
221162306a36Sopenharmony_ci						struct cvmx_usb_pipe *pipe,
221262306a36Sopenharmony_ci						struct urb *urb)
221362306a36Sopenharmony_ci{
221462306a36Sopenharmony_ci	return cvmx_usb_submit_transaction(usb, pipe,
221562306a36Sopenharmony_ci					   CVMX_USB_TRANSFER_INTERRUPT,
221662306a36Sopenharmony_ci					   urb->transfer_dma,
221762306a36Sopenharmony_ci					   urb->transfer_buffer_length,
221862306a36Sopenharmony_ci					   0, /* control_header */
221962306a36Sopenharmony_ci					   0, /* iso_start_frame */
222062306a36Sopenharmony_ci					   0, /* iso_number_packets */
222162306a36Sopenharmony_ci					   NULL, /* iso_packets */
222262306a36Sopenharmony_ci					   urb);
222362306a36Sopenharmony_ci}
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci/**
222662306a36Sopenharmony_ci * Call to submit a USB Control transfer to a pipe.
222762306a36Sopenharmony_ci *
222862306a36Sopenharmony_ci * @usb:	    USB device state populated by cvmx_usb_initialize().
222962306a36Sopenharmony_ci * @pipe:	    Handle to the pipe for the transfer.
223062306a36Sopenharmony_ci * @urb:	    URB.
223162306a36Sopenharmony_ci *
223262306a36Sopenharmony_ci * Returns: A submitted transaction or NULL on failure.
223362306a36Sopenharmony_ci */
223462306a36Sopenharmony_cistatic struct cvmx_usb_transaction *cvmx_usb_submit_control(
223562306a36Sopenharmony_ci						struct octeon_hcd *usb,
223662306a36Sopenharmony_ci						struct cvmx_usb_pipe *pipe,
223762306a36Sopenharmony_ci						struct urb *urb)
223862306a36Sopenharmony_ci{
223962306a36Sopenharmony_ci	int buffer_length = urb->transfer_buffer_length;
224062306a36Sopenharmony_ci	u64 control_header = urb->setup_dma;
224162306a36Sopenharmony_ci	struct usb_ctrlrequest *header = cvmx_phys_to_ptr(control_header);
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	if ((header->bRequestType & USB_DIR_IN) == 0)
224462306a36Sopenharmony_ci		buffer_length = le16_to_cpu(header->wLength);
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	return cvmx_usb_submit_transaction(usb, pipe,
224762306a36Sopenharmony_ci					   CVMX_USB_TRANSFER_CONTROL,
224862306a36Sopenharmony_ci					   urb->transfer_dma, buffer_length,
224962306a36Sopenharmony_ci					   control_header,
225062306a36Sopenharmony_ci					   0, /* iso_start_frame */
225162306a36Sopenharmony_ci					   0, /* iso_number_packets */
225262306a36Sopenharmony_ci					   NULL, /* iso_packets */
225362306a36Sopenharmony_ci					   urb);
225462306a36Sopenharmony_ci}
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci/**
225762306a36Sopenharmony_ci * Call to submit a USB Isochronous transfer to a pipe.
225862306a36Sopenharmony_ci *
225962306a36Sopenharmony_ci * @usb:	    USB device state populated by cvmx_usb_initialize().
226062306a36Sopenharmony_ci * @pipe:	    Handle to the pipe for the transfer.
226162306a36Sopenharmony_ci * @urb:	    URB returned when the callback is called.
226262306a36Sopenharmony_ci *
226362306a36Sopenharmony_ci * Returns: A submitted transaction or NULL on failure.
226462306a36Sopenharmony_ci */
226562306a36Sopenharmony_cistatic struct cvmx_usb_transaction *cvmx_usb_submit_isochronous(
226662306a36Sopenharmony_ci						struct octeon_hcd *usb,
226762306a36Sopenharmony_ci						struct cvmx_usb_pipe *pipe,
226862306a36Sopenharmony_ci						struct urb *urb)
226962306a36Sopenharmony_ci{
227062306a36Sopenharmony_ci	struct cvmx_usb_iso_packet *packets;
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci	packets = (struct cvmx_usb_iso_packet *)urb->setup_packet;
227362306a36Sopenharmony_ci	return cvmx_usb_submit_transaction(usb, pipe,
227462306a36Sopenharmony_ci					   CVMX_USB_TRANSFER_ISOCHRONOUS,
227562306a36Sopenharmony_ci					   urb->transfer_dma,
227662306a36Sopenharmony_ci					   urb->transfer_buffer_length,
227762306a36Sopenharmony_ci					   0, /* control_header */
227862306a36Sopenharmony_ci					   urb->start_frame,
227962306a36Sopenharmony_ci					   urb->number_of_packets,
228062306a36Sopenharmony_ci					   packets, urb);
228162306a36Sopenharmony_ci}
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci/**
228462306a36Sopenharmony_ci * Cancel one outstanding request in a pipe. Canceling a request
228562306a36Sopenharmony_ci * can fail if the transaction has already completed before cancel
228662306a36Sopenharmony_ci * is called. Even after a successful cancel call, it may take
228762306a36Sopenharmony_ci * a frame or two for the cvmx_usb_poll() function to call the
228862306a36Sopenharmony_ci * associated callback.
228962306a36Sopenharmony_ci *
229062306a36Sopenharmony_ci * @usb:	 USB device state populated by cvmx_usb_initialize().
229162306a36Sopenharmony_ci * @pipe:	 Pipe to cancel requests in.
229262306a36Sopenharmony_ci * @transaction: Transaction to cancel, returned by the submit function.
229362306a36Sopenharmony_ci *
229462306a36Sopenharmony_ci * Returns: 0 or a negative error code.
229562306a36Sopenharmony_ci */
229662306a36Sopenharmony_cistatic int cvmx_usb_cancel(struct octeon_hcd *usb,
229762306a36Sopenharmony_ci			   struct cvmx_usb_pipe *pipe,
229862306a36Sopenharmony_ci			   struct cvmx_usb_transaction *transaction)
229962306a36Sopenharmony_ci{
230062306a36Sopenharmony_ci	/*
230162306a36Sopenharmony_ci	 * If the transaction is the HEAD of the queue and scheduled. We need to
230262306a36Sopenharmony_ci	 * treat it special
230362306a36Sopenharmony_ci	 */
230462306a36Sopenharmony_ci	if (list_first_entry(&pipe->transactions, typeof(*transaction), node) ==
230562306a36Sopenharmony_ci	    transaction && (pipe->flags & CVMX_USB_PIPE_FLAGS_SCHEDULED)) {
230662306a36Sopenharmony_ci		union cvmx_usbcx_hccharx usbc_hcchar;
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci		usb->pipe_for_channel[pipe->channel] = NULL;
230962306a36Sopenharmony_ci		pipe->flags &= ~CVMX_USB_PIPE_FLAGS_SCHEDULED;
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci		CVMX_SYNCW;
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci		usbc_hcchar.u32 = cvmx_usb_read_csr32(usb,
231462306a36Sopenharmony_ci						      CVMX_USBCX_HCCHARX(pipe->channel,
231562306a36Sopenharmony_ci									 usb->index));
231662306a36Sopenharmony_ci		/*
231762306a36Sopenharmony_ci		 * If the channel isn't enabled then the transaction already
231862306a36Sopenharmony_ci		 * completed.
231962306a36Sopenharmony_ci		 */
232062306a36Sopenharmony_ci		if (usbc_hcchar.s.chena) {
232162306a36Sopenharmony_ci			usbc_hcchar.s.chdis = 1;
232262306a36Sopenharmony_ci			cvmx_usb_write_csr32(usb,
232362306a36Sopenharmony_ci					     CVMX_USBCX_HCCHARX(pipe->channel,
232462306a36Sopenharmony_ci								usb->index),
232562306a36Sopenharmony_ci					     usbc_hcchar.u32);
232662306a36Sopenharmony_ci		}
232762306a36Sopenharmony_ci	}
232862306a36Sopenharmony_ci	cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_CANCEL);
232962306a36Sopenharmony_ci	return 0;
233062306a36Sopenharmony_ci}
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci/**
233362306a36Sopenharmony_ci * Cancel all outstanding requests in a pipe. Logically all this
233462306a36Sopenharmony_ci * does is call cvmx_usb_cancel() in a loop.
233562306a36Sopenharmony_ci *
233662306a36Sopenharmony_ci * @usb:	 USB device state populated by cvmx_usb_initialize().
233762306a36Sopenharmony_ci * @pipe:	 Pipe to cancel requests in.
233862306a36Sopenharmony_ci *
233962306a36Sopenharmony_ci * Returns: 0 or a negative error code.
234062306a36Sopenharmony_ci */
234162306a36Sopenharmony_cistatic int cvmx_usb_cancel_all(struct octeon_hcd *usb,
234262306a36Sopenharmony_ci			       struct cvmx_usb_pipe *pipe)
234362306a36Sopenharmony_ci{
234462306a36Sopenharmony_ci	struct cvmx_usb_transaction *transaction, *next;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	/* Simply loop through and attempt to cancel each transaction */
234762306a36Sopenharmony_ci	list_for_each_entry_safe(transaction, next, &pipe->transactions, node) {
234862306a36Sopenharmony_ci		int result = cvmx_usb_cancel(usb, pipe, transaction);
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci		if (unlikely(result != 0))
235162306a36Sopenharmony_ci			return result;
235262306a36Sopenharmony_ci	}
235362306a36Sopenharmony_ci	return 0;
235462306a36Sopenharmony_ci}
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci/**
235762306a36Sopenharmony_ci * Close a pipe created with cvmx_usb_open_pipe().
235862306a36Sopenharmony_ci *
235962306a36Sopenharmony_ci * @usb:	 USB device state populated by cvmx_usb_initialize().
236062306a36Sopenharmony_ci * @pipe:	 Pipe to close.
236162306a36Sopenharmony_ci *
236262306a36Sopenharmony_ci * Returns: 0 or a negative error code. EBUSY is returned if the pipe has
236362306a36Sopenharmony_ci *	    outstanding transfers.
236462306a36Sopenharmony_ci */
236562306a36Sopenharmony_cistatic int cvmx_usb_close_pipe(struct octeon_hcd *usb,
236662306a36Sopenharmony_ci			       struct cvmx_usb_pipe *pipe)
236762306a36Sopenharmony_ci{
236862306a36Sopenharmony_ci	/* Fail if the pipe has pending transactions */
236962306a36Sopenharmony_ci	if (!list_empty(&pipe->transactions))
237062306a36Sopenharmony_ci		return -EBUSY;
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	list_del(&pipe->node);
237362306a36Sopenharmony_ci	kfree(pipe);
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci	return 0;
237662306a36Sopenharmony_ci}
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci/**
237962306a36Sopenharmony_ci * Get the current USB protocol level frame number. The frame
238062306a36Sopenharmony_ci * number is always in the range of 0-0x7ff.
238162306a36Sopenharmony_ci *
238262306a36Sopenharmony_ci * @usb: USB device state populated by cvmx_usb_initialize().
238362306a36Sopenharmony_ci *
238462306a36Sopenharmony_ci * Returns: USB frame number
238562306a36Sopenharmony_ci */
238662306a36Sopenharmony_cistatic int cvmx_usb_get_frame_number(struct octeon_hcd *usb)
238762306a36Sopenharmony_ci{
238862306a36Sopenharmony_ci	union cvmx_usbcx_hfnum usbc_hfnum;
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci	usbc_hfnum.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index));
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	return usbc_hfnum.s.frnum;
239362306a36Sopenharmony_ci}
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_cistatic void cvmx_usb_transfer_control(struct octeon_hcd *usb,
239662306a36Sopenharmony_ci				      struct cvmx_usb_pipe *pipe,
239762306a36Sopenharmony_ci				      struct cvmx_usb_transaction *transaction,
239862306a36Sopenharmony_ci				      union cvmx_usbcx_hccharx usbc_hcchar,
239962306a36Sopenharmony_ci				      int buffer_space_left,
240062306a36Sopenharmony_ci				      int bytes_in_last_packet)
240162306a36Sopenharmony_ci{
240262306a36Sopenharmony_ci	switch (transaction->stage) {
240362306a36Sopenharmony_ci	case CVMX_USB_STAGE_NON_CONTROL:
240462306a36Sopenharmony_ci	case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
240562306a36Sopenharmony_ci		/* This should be impossible */
240662306a36Sopenharmony_ci		cvmx_usb_complete(usb, pipe, transaction,
240762306a36Sopenharmony_ci				  CVMX_USB_STATUS_ERROR);
240862306a36Sopenharmony_ci		break;
240962306a36Sopenharmony_ci	case CVMX_USB_STAGE_SETUP:
241062306a36Sopenharmony_ci		pipe->pid_toggle = 1;
241162306a36Sopenharmony_ci		if (cvmx_usb_pipe_needs_split(usb, pipe)) {
241262306a36Sopenharmony_ci			transaction->stage =
241362306a36Sopenharmony_ci				CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE;
241462306a36Sopenharmony_ci		} else {
241562306a36Sopenharmony_ci			struct usb_ctrlrequest *header =
241662306a36Sopenharmony_ci				cvmx_phys_to_ptr(transaction->control_header);
241762306a36Sopenharmony_ci			if (header->wLength)
241862306a36Sopenharmony_ci				transaction->stage = CVMX_USB_STAGE_DATA;
241962306a36Sopenharmony_ci			else
242062306a36Sopenharmony_ci				transaction->stage = CVMX_USB_STAGE_STATUS;
242162306a36Sopenharmony_ci		}
242262306a36Sopenharmony_ci		break;
242362306a36Sopenharmony_ci	case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
242462306a36Sopenharmony_ci		{
242562306a36Sopenharmony_ci			struct usb_ctrlrequest *header =
242662306a36Sopenharmony_ci				cvmx_phys_to_ptr(transaction->control_header);
242762306a36Sopenharmony_ci			if (header->wLength)
242862306a36Sopenharmony_ci				transaction->stage = CVMX_USB_STAGE_DATA;
242962306a36Sopenharmony_ci			else
243062306a36Sopenharmony_ci				transaction->stage = CVMX_USB_STAGE_STATUS;
243162306a36Sopenharmony_ci		}
243262306a36Sopenharmony_ci		break;
243362306a36Sopenharmony_ci	case CVMX_USB_STAGE_DATA:
243462306a36Sopenharmony_ci		if (cvmx_usb_pipe_needs_split(usb, pipe)) {
243562306a36Sopenharmony_ci			transaction->stage = CVMX_USB_STAGE_DATA_SPLIT_COMPLETE;
243662306a36Sopenharmony_ci			/*
243762306a36Sopenharmony_ci			 * For setup OUT data that are splits,
243862306a36Sopenharmony_ci			 * the hardware doesn't appear to count
243962306a36Sopenharmony_ci			 * transferred data. Here we manually
244062306a36Sopenharmony_ci			 * update the data transferred
244162306a36Sopenharmony_ci			 */
244262306a36Sopenharmony_ci			if (!usbc_hcchar.s.epdir) {
244362306a36Sopenharmony_ci				if (buffer_space_left < pipe->max_packet)
244462306a36Sopenharmony_ci					transaction->actual_bytes +=
244562306a36Sopenharmony_ci						buffer_space_left;
244662306a36Sopenharmony_ci				else
244762306a36Sopenharmony_ci					transaction->actual_bytes +=
244862306a36Sopenharmony_ci						pipe->max_packet;
244962306a36Sopenharmony_ci			}
245062306a36Sopenharmony_ci		} else if ((buffer_space_left == 0) ||
245162306a36Sopenharmony_ci			   (bytes_in_last_packet < pipe->max_packet)) {
245262306a36Sopenharmony_ci			pipe->pid_toggle = 1;
245362306a36Sopenharmony_ci			transaction->stage = CVMX_USB_STAGE_STATUS;
245462306a36Sopenharmony_ci		}
245562306a36Sopenharmony_ci		break;
245662306a36Sopenharmony_ci	case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE:
245762306a36Sopenharmony_ci		if ((buffer_space_left == 0) ||
245862306a36Sopenharmony_ci		    (bytes_in_last_packet < pipe->max_packet)) {
245962306a36Sopenharmony_ci			pipe->pid_toggle = 1;
246062306a36Sopenharmony_ci			transaction->stage = CVMX_USB_STAGE_STATUS;
246162306a36Sopenharmony_ci		} else {
246262306a36Sopenharmony_ci			transaction->stage = CVMX_USB_STAGE_DATA;
246362306a36Sopenharmony_ci		}
246462306a36Sopenharmony_ci		break;
246562306a36Sopenharmony_ci	case CVMX_USB_STAGE_STATUS:
246662306a36Sopenharmony_ci		if (cvmx_usb_pipe_needs_split(usb, pipe))
246762306a36Sopenharmony_ci			transaction->stage =
246862306a36Sopenharmony_ci				CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE;
246962306a36Sopenharmony_ci		else
247062306a36Sopenharmony_ci			cvmx_usb_complete(usb, pipe, transaction,
247162306a36Sopenharmony_ci					  CVMX_USB_STATUS_OK);
247262306a36Sopenharmony_ci		break;
247362306a36Sopenharmony_ci	case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
247462306a36Sopenharmony_ci		cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_OK);
247562306a36Sopenharmony_ci		break;
247662306a36Sopenharmony_ci	}
247762306a36Sopenharmony_ci}
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_cistatic void cvmx_usb_transfer_bulk(struct octeon_hcd *usb,
248062306a36Sopenharmony_ci				   struct cvmx_usb_pipe *pipe,
248162306a36Sopenharmony_ci				   struct cvmx_usb_transaction *transaction,
248262306a36Sopenharmony_ci				   union cvmx_usbcx_hcintx usbc_hcint,
248362306a36Sopenharmony_ci				   int buffer_space_left,
248462306a36Sopenharmony_ci				   int bytes_in_last_packet)
248562306a36Sopenharmony_ci{
248662306a36Sopenharmony_ci	/*
248762306a36Sopenharmony_ci	 * The only time a bulk transfer isn't complete when it finishes with
248862306a36Sopenharmony_ci	 * an ACK is during a split transaction. For splits we need to continue
248962306a36Sopenharmony_ci	 * the transfer if more data is needed.
249062306a36Sopenharmony_ci	 */
249162306a36Sopenharmony_ci	if (cvmx_usb_pipe_needs_split(usb, pipe)) {
249262306a36Sopenharmony_ci		if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL)
249362306a36Sopenharmony_ci			transaction->stage =
249462306a36Sopenharmony_ci				CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
249562306a36Sopenharmony_ci		else if (buffer_space_left &&
249662306a36Sopenharmony_ci			 (bytes_in_last_packet == pipe->max_packet))
249762306a36Sopenharmony_ci			transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
249862306a36Sopenharmony_ci		else
249962306a36Sopenharmony_ci			cvmx_usb_complete(usb, pipe, transaction,
250062306a36Sopenharmony_ci					  CVMX_USB_STATUS_OK);
250162306a36Sopenharmony_ci	} else {
250262306a36Sopenharmony_ci		if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
250362306a36Sopenharmony_ci		    (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
250462306a36Sopenharmony_ci		    (usbc_hcint.s.nak))
250562306a36Sopenharmony_ci			pipe->flags |= CVMX_USB_PIPE_FLAGS_NEED_PING;
250662306a36Sopenharmony_ci		if (!buffer_space_left ||
250762306a36Sopenharmony_ci		    (bytes_in_last_packet < pipe->max_packet))
250862306a36Sopenharmony_ci			cvmx_usb_complete(usb, pipe, transaction,
250962306a36Sopenharmony_ci					  CVMX_USB_STATUS_OK);
251062306a36Sopenharmony_ci	}
251162306a36Sopenharmony_ci}
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_cistatic void cvmx_usb_transfer_intr(struct octeon_hcd *usb,
251462306a36Sopenharmony_ci				   struct cvmx_usb_pipe *pipe,
251562306a36Sopenharmony_ci				   struct cvmx_usb_transaction *transaction,
251662306a36Sopenharmony_ci				   int buffer_space_left,
251762306a36Sopenharmony_ci				   int bytes_in_last_packet)
251862306a36Sopenharmony_ci{
251962306a36Sopenharmony_ci	if (cvmx_usb_pipe_needs_split(usb, pipe)) {
252062306a36Sopenharmony_ci		if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL) {
252162306a36Sopenharmony_ci			transaction->stage =
252262306a36Sopenharmony_ci				CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
252362306a36Sopenharmony_ci		} else if (buffer_space_left &&
252462306a36Sopenharmony_ci			   (bytes_in_last_packet == pipe->max_packet)) {
252562306a36Sopenharmony_ci			transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
252662306a36Sopenharmony_ci		} else {
252762306a36Sopenharmony_ci			pipe->next_tx_frame += pipe->interval;
252862306a36Sopenharmony_ci			cvmx_usb_complete(usb, pipe, transaction,
252962306a36Sopenharmony_ci					  CVMX_USB_STATUS_OK);
253062306a36Sopenharmony_ci		}
253162306a36Sopenharmony_ci	} else if (!buffer_space_left ||
253262306a36Sopenharmony_ci		   (bytes_in_last_packet < pipe->max_packet)) {
253362306a36Sopenharmony_ci		pipe->next_tx_frame += pipe->interval;
253462306a36Sopenharmony_ci		cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_OK);
253562306a36Sopenharmony_ci	}
253662306a36Sopenharmony_ci}
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_cistatic void cvmx_usb_transfer_isoc(struct octeon_hcd *usb,
253962306a36Sopenharmony_ci				   struct cvmx_usb_pipe *pipe,
254062306a36Sopenharmony_ci				   struct cvmx_usb_transaction *transaction,
254162306a36Sopenharmony_ci				   int buffer_space_left,
254262306a36Sopenharmony_ci				   int bytes_in_last_packet,
254362306a36Sopenharmony_ci				   int bytes_this_transfer)
254462306a36Sopenharmony_ci{
254562306a36Sopenharmony_ci	if (cvmx_usb_pipe_needs_split(usb, pipe)) {
254662306a36Sopenharmony_ci		/*
254762306a36Sopenharmony_ci		 * ISOCHRONOUS OUT splits don't require a complete split stage.
254862306a36Sopenharmony_ci		 * Instead they use a sequence of begin OUT splits to transfer
254962306a36Sopenharmony_ci		 * the data 188 bytes at a time. Once the transfer is complete,
255062306a36Sopenharmony_ci		 * the pipe sleeps until the next schedule interval.
255162306a36Sopenharmony_ci		 */
255262306a36Sopenharmony_ci		if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
255362306a36Sopenharmony_ci			/*
255462306a36Sopenharmony_ci			 * If no space left or this wasn't a max size packet
255562306a36Sopenharmony_ci			 * then this transfer is complete. Otherwise start it
255662306a36Sopenharmony_ci			 * again to send the next 188 bytes
255762306a36Sopenharmony_ci			 */
255862306a36Sopenharmony_ci			if (!buffer_space_left || (bytes_this_transfer < 188)) {
255962306a36Sopenharmony_ci				pipe->next_tx_frame += pipe->interval;
256062306a36Sopenharmony_ci				cvmx_usb_complete(usb, pipe, transaction,
256162306a36Sopenharmony_ci						  CVMX_USB_STATUS_OK);
256262306a36Sopenharmony_ci			}
256362306a36Sopenharmony_ci			return;
256462306a36Sopenharmony_ci		}
256562306a36Sopenharmony_ci		if (transaction->stage ==
256662306a36Sopenharmony_ci		    CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE) {
256762306a36Sopenharmony_ci			/*
256862306a36Sopenharmony_ci			 * We are in the incoming data phase. Keep getting data
256962306a36Sopenharmony_ci			 * until we run out of space or get a small packet
257062306a36Sopenharmony_ci			 */
257162306a36Sopenharmony_ci			if ((buffer_space_left == 0) ||
257262306a36Sopenharmony_ci			    (bytes_in_last_packet < pipe->max_packet)) {
257362306a36Sopenharmony_ci				pipe->next_tx_frame += pipe->interval;
257462306a36Sopenharmony_ci				cvmx_usb_complete(usb, pipe, transaction,
257562306a36Sopenharmony_ci						  CVMX_USB_STATUS_OK);
257662306a36Sopenharmony_ci			}
257762306a36Sopenharmony_ci		} else {
257862306a36Sopenharmony_ci			transaction->stage =
257962306a36Sopenharmony_ci				CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
258062306a36Sopenharmony_ci		}
258162306a36Sopenharmony_ci	} else {
258262306a36Sopenharmony_ci		pipe->next_tx_frame += pipe->interval;
258362306a36Sopenharmony_ci		cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_OK);
258462306a36Sopenharmony_ci	}
258562306a36Sopenharmony_ci}
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci/**
258862306a36Sopenharmony_ci * Poll a channel for status
258962306a36Sopenharmony_ci *
259062306a36Sopenharmony_ci * @usb:     USB device
259162306a36Sopenharmony_ci * @channel: Channel to poll
259262306a36Sopenharmony_ci *
259362306a36Sopenharmony_ci * Returns: Zero on success
259462306a36Sopenharmony_ci */
259562306a36Sopenharmony_cistatic int cvmx_usb_poll_channel(struct octeon_hcd *usb, int channel)
259662306a36Sopenharmony_ci{
259762306a36Sopenharmony_ci	struct usb_hcd *hcd = octeon_to_hcd(usb);
259862306a36Sopenharmony_ci	struct device *dev = hcd->self.controller;
259962306a36Sopenharmony_ci	union cvmx_usbcx_hcintx usbc_hcint;
260062306a36Sopenharmony_ci	union cvmx_usbcx_hctsizx usbc_hctsiz;
260162306a36Sopenharmony_ci	union cvmx_usbcx_hccharx usbc_hcchar;
260262306a36Sopenharmony_ci	struct cvmx_usb_pipe *pipe;
260362306a36Sopenharmony_ci	struct cvmx_usb_transaction *transaction;
260462306a36Sopenharmony_ci	int bytes_this_transfer;
260562306a36Sopenharmony_ci	int bytes_in_last_packet;
260662306a36Sopenharmony_ci	int packets_processed;
260762306a36Sopenharmony_ci	int buffer_space_left;
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	/* Read the interrupt status bits for the channel */
261062306a36Sopenharmony_ci	usbc_hcint.u32 = cvmx_usb_read_csr32(usb,
261162306a36Sopenharmony_ci					     CVMX_USBCX_HCINTX(channel, usb->index));
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_ci	if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
261462306a36Sopenharmony_ci		usbc_hcchar.u32 = cvmx_usb_read_csr32(usb,
261562306a36Sopenharmony_ci						      CVMX_USBCX_HCCHARX(channel,
261662306a36Sopenharmony_ci									 usb->index));
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_ci		if (usbc_hcchar.s.chena && usbc_hcchar.s.chdis) {
261962306a36Sopenharmony_ci			/*
262062306a36Sopenharmony_ci			 * There seems to be a bug in CN31XX which can cause
262162306a36Sopenharmony_ci			 * interrupt IN transfers to get stuck until we do a
262262306a36Sopenharmony_ci			 * write of HCCHARX without changing things
262362306a36Sopenharmony_ci			 */
262462306a36Sopenharmony_ci			cvmx_usb_write_csr32(usb,
262562306a36Sopenharmony_ci					     CVMX_USBCX_HCCHARX(channel,
262662306a36Sopenharmony_ci								usb->index),
262762306a36Sopenharmony_ci					     usbc_hcchar.u32);
262862306a36Sopenharmony_ci			return 0;
262962306a36Sopenharmony_ci		}
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci		/*
263262306a36Sopenharmony_ci		 * In non DMA mode the channels don't halt themselves. We need
263362306a36Sopenharmony_ci		 * to manually disable channels that are left running
263462306a36Sopenharmony_ci		 */
263562306a36Sopenharmony_ci		if (!usbc_hcint.s.chhltd) {
263662306a36Sopenharmony_ci			if (usbc_hcchar.s.chena) {
263762306a36Sopenharmony_ci				union cvmx_usbcx_hcintmskx hcintmsk;
263862306a36Sopenharmony_ci				/* Disable all interrupts except CHHLTD */
263962306a36Sopenharmony_ci				hcintmsk.u32 = 0;
264062306a36Sopenharmony_ci				hcintmsk.s.chhltdmsk = 1;
264162306a36Sopenharmony_ci				cvmx_usb_write_csr32(usb,
264262306a36Sopenharmony_ci						     CVMX_USBCX_HCINTMSKX(channel, usb->index),
264362306a36Sopenharmony_ci						     hcintmsk.u32);
264462306a36Sopenharmony_ci				usbc_hcchar.s.chdis = 1;
264562306a36Sopenharmony_ci				cvmx_usb_write_csr32(usb,
264662306a36Sopenharmony_ci						     CVMX_USBCX_HCCHARX(channel, usb->index),
264762306a36Sopenharmony_ci						     usbc_hcchar.u32);
264862306a36Sopenharmony_ci				return 0;
264962306a36Sopenharmony_ci			} else if (usbc_hcint.s.xfercompl) {
265062306a36Sopenharmony_ci				/*
265162306a36Sopenharmony_ci				 * Successful IN/OUT with transfer complete.
265262306a36Sopenharmony_ci				 * Channel halt isn't needed.
265362306a36Sopenharmony_ci				 */
265462306a36Sopenharmony_ci			} else {
265562306a36Sopenharmony_ci				dev_err(dev, "USB%d: Channel %d interrupt without halt\n",
265662306a36Sopenharmony_ci					usb->index, channel);
265762306a36Sopenharmony_ci				return 0;
265862306a36Sopenharmony_ci			}
265962306a36Sopenharmony_ci		}
266062306a36Sopenharmony_ci	} else {
266162306a36Sopenharmony_ci		/*
266262306a36Sopenharmony_ci		 * There is are no interrupts that we need to process when the
266362306a36Sopenharmony_ci		 * channel is still running
266462306a36Sopenharmony_ci		 */
266562306a36Sopenharmony_ci		if (!usbc_hcint.s.chhltd)
266662306a36Sopenharmony_ci			return 0;
266762306a36Sopenharmony_ci	}
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_ci	/* Disable the channel interrupts now that it is done */
267062306a36Sopenharmony_ci	cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0);
267162306a36Sopenharmony_ci	usb->idle_hardware_channels |= (1 << channel);
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ci	/* Make sure this channel is tied to a valid pipe */
267462306a36Sopenharmony_ci	pipe = usb->pipe_for_channel[channel];
267562306a36Sopenharmony_ci	prefetch(pipe);
267662306a36Sopenharmony_ci	if (!pipe)
267762306a36Sopenharmony_ci		return 0;
267862306a36Sopenharmony_ci	transaction = list_first_entry(&pipe->transactions,
267962306a36Sopenharmony_ci				       typeof(*transaction),
268062306a36Sopenharmony_ci				       node);
268162306a36Sopenharmony_ci	prefetch(transaction);
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci	/*
268462306a36Sopenharmony_ci	 * Disconnect this pipe from the HW channel. Later the schedule
268562306a36Sopenharmony_ci	 * function will figure out which pipe needs to go
268662306a36Sopenharmony_ci	 */
268762306a36Sopenharmony_ci	usb->pipe_for_channel[channel] = NULL;
268862306a36Sopenharmony_ci	pipe->flags &= ~CVMX_USB_PIPE_FLAGS_SCHEDULED;
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci	/*
269162306a36Sopenharmony_ci	 * Read the channel config info so we can figure out how much data
269262306a36Sopenharmony_ci	 * transferred
269362306a36Sopenharmony_ci	 */
269462306a36Sopenharmony_ci	usbc_hcchar.u32 = cvmx_usb_read_csr32(usb,
269562306a36Sopenharmony_ci					      CVMX_USBCX_HCCHARX(channel, usb->index));
269662306a36Sopenharmony_ci	usbc_hctsiz.u32 = cvmx_usb_read_csr32(usb,
269762306a36Sopenharmony_ci					      CVMX_USBCX_HCTSIZX(channel, usb->index));
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_ci	/*
270062306a36Sopenharmony_ci	 * Calculating the number of bytes successfully transferred is dependent
270162306a36Sopenharmony_ci	 * on the transfer direction
270262306a36Sopenharmony_ci	 */
270362306a36Sopenharmony_ci	packets_processed = transaction->pktcnt - usbc_hctsiz.s.pktcnt;
270462306a36Sopenharmony_ci	if (usbc_hcchar.s.epdir) {
270562306a36Sopenharmony_ci		/*
270662306a36Sopenharmony_ci		 * IN transactions are easy. For every byte received the
270762306a36Sopenharmony_ci		 * hardware decrements xfersize. All we need to do is subtract
270862306a36Sopenharmony_ci		 * the current value of xfersize from its starting value and we
270962306a36Sopenharmony_ci		 * know how many bytes were written to the buffer
271062306a36Sopenharmony_ci		 */
271162306a36Sopenharmony_ci		bytes_this_transfer = transaction->xfersize -
271262306a36Sopenharmony_ci			usbc_hctsiz.s.xfersize;
271362306a36Sopenharmony_ci	} else {
271462306a36Sopenharmony_ci		/*
271562306a36Sopenharmony_ci		 * OUT transaction don't decrement xfersize. Instead pktcnt is
271662306a36Sopenharmony_ci		 * decremented on every successful packet send. The hardware
271762306a36Sopenharmony_ci		 * does this when it receives an ACK, or NYET. If it doesn't
271862306a36Sopenharmony_ci		 * receive one of these responses pktcnt doesn't change
271962306a36Sopenharmony_ci		 */
272062306a36Sopenharmony_ci		bytes_this_transfer = packets_processed * usbc_hcchar.s.mps;
272162306a36Sopenharmony_ci		/*
272262306a36Sopenharmony_ci		 * The last packet may not be a full transfer if we didn't have
272362306a36Sopenharmony_ci		 * enough data
272462306a36Sopenharmony_ci		 */
272562306a36Sopenharmony_ci		if (bytes_this_transfer > transaction->xfersize)
272662306a36Sopenharmony_ci			bytes_this_transfer = transaction->xfersize;
272762306a36Sopenharmony_ci	}
272862306a36Sopenharmony_ci	/* Figure out how many bytes were in the last packet of the transfer */
272962306a36Sopenharmony_ci	if (packets_processed)
273062306a36Sopenharmony_ci		bytes_in_last_packet = bytes_this_transfer -
273162306a36Sopenharmony_ci			(packets_processed - 1) * usbc_hcchar.s.mps;
273262306a36Sopenharmony_ci	else
273362306a36Sopenharmony_ci		bytes_in_last_packet = bytes_this_transfer;
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	/*
273662306a36Sopenharmony_ci	 * As a special case, setup transactions output the setup header, not
273762306a36Sopenharmony_ci	 * the user's data. For this reason we don't count setup data as bytes
273862306a36Sopenharmony_ci	 * transferred
273962306a36Sopenharmony_ci	 */
274062306a36Sopenharmony_ci	if ((transaction->stage == CVMX_USB_STAGE_SETUP) ||
274162306a36Sopenharmony_ci	    (transaction->stage == CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE))
274262306a36Sopenharmony_ci		bytes_this_transfer = 0;
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci	/*
274562306a36Sopenharmony_ci	 * Add the bytes transferred to the running total. It is important that
274662306a36Sopenharmony_ci	 * bytes_this_transfer doesn't count any data that needs to be
274762306a36Sopenharmony_ci	 * retransmitted
274862306a36Sopenharmony_ci	 */
274962306a36Sopenharmony_ci	transaction->actual_bytes += bytes_this_transfer;
275062306a36Sopenharmony_ci	if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
275162306a36Sopenharmony_ci		buffer_space_left = transaction->iso_packets[0].length -
275262306a36Sopenharmony_ci			transaction->actual_bytes;
275362306a36Sopenharmony_ci	else
275462306a36Sopenharmony_ci		buffer_space_left = transaction->buffer_length -
275562306a36Sopenharmony_ci			transaction->actual_bytes;
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci	/*
275862306a36Sopenharmony_ci	 * We need to remember the PID toggle state for the next transaction.
275962306a36Sopenharmony_ci	 * The hardware already updated it for the next transaction
276062306a36Sopenharmony_ci	 */
276162306a36Sopenharmony_ci	pipe->pid_toggle = !(usbc_hctsiz.s.pid == 0);
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci	/*
276462306a36Sopenharmony_ci	 * For high speed bulk out, assume the next transaction will need to do
276562306a36Sopenharmony_ci	 * a ping before proceeding. If this isn't true the ACK processing below
276662306a36Sopenharmony_ci	 * will clear this flag
276762306a36Sopenharmony_ci	 */
276862306a36Sopenharmony_ci	if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
276962306a36Sopenharmony_ci	    (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) &&
277062306a36Sopenharmony_ci	    (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT))
277162306a36Sopenharmony_ci		pipe->flags |= CVMX_USB_PIPE_FLAGS_NEED_PING;
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci	if (WARN_ON_ONCE(bytes_this_transfer < 0)) {
277462306a36Sopenharmony_ci		/*
277562306a36Sopenharmony_ci		 * In some rare cases the DMA engine seems to get stuck and
277662306a36Sopenharmony_ci		 * keeps substracting same byte count over and over again. In
277762306a36Sopenharmony_ci		 * such case we just need to fail every transaction.
277862306a36Sopenharmony_ci		 */
277962306a36Sopenharmony_ci		cvmx_usb_complete(usb, pipe, transaction,
278062306a36Sopenharmony_ci				  CVMX_USB_STATUS_ERROR);
278162306a36Sopenharmony_ci		return 0;
278262306a36Sopenharmony_ci	}
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci	if (usbc_hcint.s.stall) {
278562306a36Sopenharmony_ci		/*
278662306a36Sopenharmony_ci		 * STALL as a response means this transaction cannot be
278762306a36Sopenharmony_ci		 * completed because the device can't process transactions. Tell
278862306a36Sopenharmony_ci		 * the user. Any data that was transferred will be counted on
278962306a36Sopenharmony_ci		 * the actual bytes transferred
279062306a36Sopenharmony_ci		 */
279162306a36Sopenharmony_ci		pipe->pid_toggle = 0;
279262306a36Sopenharmony_ci		cvmx_usb_complete(usb, pipe, transaction,
279362306a36Sopenharmony_ci				  CVMX_USB_STATUS_STALL);
279462306a36Sopenharmony_ci	} else if (usbc_hcint.s.xacterr) {
279562306a36Sopenharmony_ci		/*
279662306a36Sopenharmony_ci		 * XactErr as a response means the device signaled
279762306a36Sopenharmony_ci		 * something wrong with the transfer. For example, PID
279862306a36Sopenharmony_ci		 * toggle errors cause these.
279962306a36Sopenharmony_ci		 */
280062306a36Sopenharmony_ci		cvmx_usb_complete(usb, pipe, transaction,
280162306a36Sopenharmony_ci				  CVMX_USB_STATUS_XACTERR);
280262306a36Sopenharmony_ci	} else if (usbc_hcint.s.bblerr) {
280362306a36Sopenharmony_ci		/* Babble Error (BblErr) */
280462306a36Sopenharmony_ci		cvmx_usb_complete(usb, pipe, transaction,
280562306a36Sopenharmony_ci				  CVMX_USB_STATUS_BABBLEERR);
280662306a36Sopenharmony_ci	} else if (usbc_hcint.s.datatglerr) {
280762306a36Sopenharmony_ci		/* Data toggle error */
280862306a36Sopenharmony_ci		cvmx_usb_complete(usb, pipe, transaction,
280962306a36Sopenharmony_ci				  CVMX_USB_STATUS_DATATGLERR);
281062306a36Sopenharmony_ci	} else if (usbc_hcint.s.nyet) {
281162306a36Sopenharmony_ci		/*
281262306a36Sopenharmony_ci		 * NYET as a response is only allowed in three cases: as a
281362306a36Sopenharmony_ci		 * response to a ping, as a response to a split transaction, and
281462306a36Sopenharmony_ci		 * as a response to a bulk out. The ping case is handled by
281562306a36Sopenharmony_ci		 * hardware, so we only have splits and bulk out
281662306a36Sopenharmony_ci		 */
281762306a36Sopenharmony_ci		if (!cvmx_usb_pipe_needs_split(usb, pipe)) {
281862306a36Sopenharmony_ci			transaction->retries = 0;
281962306a36Sopenharmony_ci			/*
282062306a36Sopenharmony_ci			 * If there is more data to go then we need to try
282162306a36Sopenharmony_ci			 * again. Otherwise this transaction is complete
282262306a36Sopenharmony_ci			 */
282362306a36Sopenharmony_ci			if ((buffer_space_left == 0) ||
282462306a36Sopenharmony_ci			    (bytes_in_last_packet < pipe->max_packet))
282562306a36Sopenharmony_ci				cvmx_usb_complete(usb, pipe,
282662306a36Sopenharmony_ci						  transaction,
282762306a36Sopenharmony_ci						  CVMX_USB_STATUS_OK);
282862306a36Sopenharmony_ci		} else {
282962306a36Sopenharmony_ci			/*
283062306a36Sopenharmony_ci			 * Split transactions retry the split complete 4 times
283162306a36Sopenharmony_ci			 * then rewind to the start split and do the entire
283262306a36Sopenharmony_ci			 * transactions again
283362306a36Sopenharmony_ci			 */
283462306a36Sopenharmony_ci			transaction->retries++;
283562306a36Sopenharmony_ci			if ((transaction->retries & 0x3) == 0) {
283662306a36Sopenharmony_ci				/*
283762306a36Sopenharmony_ci				 * Rewind to the beginning of the transaction by
283862306a36Sopenharmony_ci				 * anding off the split complete bit
283962306a36Sopenharmony_ci				 */
284062306a36Sopenharmony_ci				transaction->stage &= ~1;
284162306a36Sopenharmony_ci				pipe->split_sc_frame = -1;
284262306a36Sopenharmony_ci			}
284362306a36Sopenharmony_ci		}
284462306a36Sopenharmony_ci	} else if (usbc_hcint.s.ack) {
284562306a36Sopenharmony_ci		transaction->retries = 0;
284662306a36Sopenharmony_ci		/*
284762306a36Sopenharmony_ci		 * The ACK bit can only be checked after the other error bits.
284862306a36Sopenharmony_ci		 * This is because a multi packet transfer may succeed in a
284962306a36Sopenharmony_ci		 * number of packets and then get a different response on the
285062306a36Sopenharmony_ci		 * last packet. In this case both ACK and the last response bit
285162306a36Sopenharmony_ci		 * will be set. If none of the other response bits is set, then
285262306a36Sopenharmony_ci		 * the last packet must have been an ACK
285362306a36Sopenharmony_ci		 *
285462306a36Sopenharmony_ci		 * Since we got an ACK, we know we don't need to do a ping on
285562306a36Sopenharmony_ci		 * this pipe
285662306a36Sopenharmony_ci		 */
285762306a36Sopenharmony_ci		pipe->flags &= ~CVMX_USB_PIPE_FLAGS_NEED_PING;
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ci		switch (transaction->type) {
286062306a36Sopenharmony_ci		case CVMX_USB_TRANSFER_CONTROL:
286162306a36Sopenharmony_ci			cvmx_usb_transfer_control(usb, pipe, transaction,
286262306a36Sopenharmony_ci						  usbc_hcchar,
286362306a36Sopenharmony_ci						  buffer_space_left,
286462306a36Sopenharmony_ci						  bytes_in_last_packet);
286562306a36Sopenharmony_ci			break;
286662306a36Sopenharmony_ci		case CVMX_USB_TRANSFER_BULK:
286762306a36Sopenharmony_ci			cvmx_usb_transfer_bulk(usb, pipe, transaction,
286862306a36Sopenharmony_ci					       usbc_hcint, buffer_space_left,
286962306a36Sopenharmony_ci					       bytes_in_last_packet);
287062306a36Sopenharmony_ci			break;
287162306a36Sopenharmony_ci		case CVMX_USB_TRANSFER_INTERRUPT:
287262306a36Sopenharmony_ci			cvmx_usb_transfer_intr(usb, pipe, transaction,
287362306a36Sopenharmony_ci					       buffer_space_left,
287462306a36Sopenharmony_ci					       bytes_in_last_packet);
287562306a36Sopenharmony_ci			break;
287662306a36Sopenharmony_ci		case CVMX_USB_TRANSFER_ISOCHRONOUS:
287762306a36Sopenharmony_ci			cvmx_usb_transfer_isoc(usb, pipe, transaction,
287862306a36Sopenharmony_ci					       buffer_space_left,
287962306a36Sopenharmony_ci					       bytes_in_last_packet,
288062306a36Sopenharmony_ci					       bytes_this_transfer);
288162306a36Sopenharmony_ci			break;
288262306a36Sopenharmony_ci		}
288362306a36Sopenharmony_ci	} else if (usbc_hcint.s.nak) {
288462306a36Sopenharmony_ci		/*
288562306a36Sopenharmony_ci		 * If this was a split then clear our split in progress marker.
288662306a36Sopenharmony_ci		 */
288762306a36Sopenharmony_ci		if (usb->active_split == transaction)
288862306a36Sopenharmony_ci			usb->active_split = NULL;
288962306a36Sopenharmony_ci		/*
289062306a36Sopenharmony_ci		 * NAK as a response means the device couldn't accept the
289162306a36Sopenharmony_ci		 * transaction, but it should be retried in the future. Rewind
289262306a36Sopenharmony_ci		 * to the beginning of the transaction by anding off the split
289362306a36Sopenharmony_ci		 * complete bit. Retry in the next interval
289462306a36Sopenharmony_ci		 */
289562306a36Sopenharmony_ci		transaction->retries = 0;
289662306a36Sopenharmony_ci		transaction->stage &= ~1;
289762306a36Sopenharmony_ci		pipe->next_tx_frame += pipe->interval;
289862306a36Sopenharmony_ci		if (pipe->next_tx_frame < usb->frame_number)
289962306a36Sopenharmony_ci			pipe->next_tx_frame = usb->frame_number +
290062306a36Sopenharmony_ci				pipe->interval -
290162306a36Sopenharmony_ci				(usb->frame_number - pipe->next_tx_frame) %
290262306a36Sopenharmony_ci				pipe->interval;
290362306a36Sopenharmony_ci	} else {
290462306a36Sopenharmony_ci		struct cvmx_usb_port_status port;
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci		port = cvmx_usb_get_status(usb);
290762306a36Sopenharmony_ci		if (port.port_enabled) {
290862306a36Sopenharmony_ci			/* We'll retry the exact same transaction again */
290962306a36Sopenharmony_ci			transaction->retries++;
291062306a36Sopenharmony_ci		} else {
291162306a36Sopenharmony_ci			/*
291262306a36Sopenharmony_ci			 * We get channel halted interrupts with no result bits
291362306a36Sopenharmony_ci			 * sets when the cable is unplugged
291462306a36Sopenharmony_ci			 */
291562306a36Sopenharmony_ci			cvmx_usb_complete(usb, pipe, transaction,
291662306a36Sopenharmony_ci					  CVMX_USB_STATUS_ERROR);
291762306a36Sopenharmony_ci		}
291862306a36Sopenharmony_ci	}
291962306a36Sopenharmony_ci	return 0;
292062306a36Sopenharmony_ci}
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_cistatic void octeon_usb_port_callback(struct octeon_hcd *usb)
292362306a36Sopenharmony_ci{
292462306a36Sopenharmony_ci	spin_unlock(&usb->lock);
292562306a36Sopenharmony_ci	usb_hcd_poll_rh_status(octeon_to_hcd(usb));
292662306a36Sopenharmony_ci	spin_lock(&usb->lock);
292762306a36Sopenharmony_ci}
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci/**
293062306a36Sopenharmony_ci * Poll the USB block for status and call all needed callback
293162306a36Sopenharmony_ci * handlers. This function is meant to be called in the interrupt
293262306a36Sopenharmony_ci * handler for the USB controller. It can also be called
293362306a36Sopenharmony_ci * periodically in a loop for non-interrupt based operation.
293462306a36Sopenharmony_ci *
293562306a36Sopenharmony_ci * @usb: USB device state populated by cvmx_usb_initialize().
293662306a36Sopenharmony_ci *
293762306a36Sopenharmony_ci * Returns: 0 or a negative error code.
293862306a36Sopenharmony_ci */
293962306a36Sopenharmony_cistatic int cvmx_usb_poll(struct octeon_hcd *usb)
294062306a36Sopenharmony_ci{
294162306a36Sopenharmony_ci	union cvmx_usbcx_hfnum usbc_hfnum;
294262306a36Sopenharmony_ci	union cvmx_usbcx_gintsts usbc_gintsts;
294362306a36Sopenharmony_ci
294462306a36Sopenharmony_ci	prefetch_range(usb, sizeof(*usb));
294562306a36Sopenharmony_ci
294662306a36Sopenharmony_ci	/* Update the frame counter */
294762306a36Sopenharmony_ci	usbc_hfnum.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index));
294862306a36Sopenharmony_ci	if ((usb->frame_number & 0x3fff) > usbc_hfnum.s.frnum)
294962306a36Sopenharmony_ci		usb->frame_number += 0x4000;
295062306a36Sopenharmony_ci	usb->frame_number &= ~0x3fffull;
295162306a36Sopenharmony_ci	usb->frame_number |= usbc_hfnum.s.frnum;
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci	/* Read the pending interrupts */
295462306a36Sopenharmony_ci	usbc_gintsts.u32 = cvmx_usb_read_csr32(usb,
295562306a36Sopenharmony_ci					       CVMX_USBCX_GINTSTS(usb->index));
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci	/* Clear the interrupts now that we know about them */
295862306a36Sopenharmony_ci	cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index),
295962306a36Sopenharmony_ci			     usbc_gintsts.u32);
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci	if (usbc_gintsts.s.rxflvl) {
296262306a36Sopenharmony_ci		/*
296362306a36Sopenharmony_ci		 * RxFIFO Non-Empty (RxFLvl)
296462306a36Sopenharmony_ci		 * Indicates that there is at least one packet pending to be
296562306a36Sopenharmony_ci		 * read from the RxFIFO.
296662306a36Sopenharmony_ci		 *
296762306a36Sopenharmony_ci		 * In DMA mode this is handled by hardware
296862306a36Sopenharmony_ci		 */
296962306a36Sopenharmony_ci		if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
297062306a36Sopenharmony_ci			cvmx_usb_poll_rx_fifo(usb);
297162306a36Sopenharmony_ci	}
297262306a36Sopenharmony_ci	if (usbc_gintsts.s.ptxfemp || usbc_gintsts.s.nptxfemp) {
297362306a36Sopenharmony_ci		/* Fill the Tx FIFOs when not in DMA mode */
297462306a36Sopenharmony_ci		if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
297562306a36Sopenharmony_ci			cvmx_usb_poll_tx_fifo(usb);
297662306a36Sopenharmony_ci	}
297762306a36Sopenharmony_ci	if (usbc_gintsts.s.disconnint || usbc_gintsts.s.prtint) {
297862306a36Sopenharmony_ci		union cvmx_usbcx_hprt usbc_hprt;
297962306a36Sopenharmony_ci		/*
298062306a36Sopenharmony_ci		 * Disconnect Detected Interrupt (DisconnInt)
298162306a36Sopenharmony_ci		 * Asserted when a device disconnect is detected.
298262306a36Sopenharmony_ci		 *
298362306a36Sopenharmony_ci		 * Host Port Interrupt (PrtInt)
298462306a36Sopenharmony_ci		 * The core sets this bit to indicate a change in port status of
298562306a36Sopenharmony_ci		 * one of the O2P USB core ports in Host mode. The application
298662306a36Sopenharmony_ci		 * must read the Host Port Control and Status (HPRT) register to
298762306a36Sopenharmony_ci		 * determine the exact event that caused this interrupt. The
298862306a36Sopenharmony_ci		 * application must clear the appropriate status bit in the Host
298962306a36Sopenharmony_ci		 * Port Control and Status register to clear this bit.
299062306a36Sopenharmony_ci		 *
299162306a36Sopenharmony_ci		 * Call the user's port callback
299262306a36Sopenharmony_ci		 */
299362306a36Sopenharmony_ci		octeon_usb_port_callback(usb);
299462306a36Sopenharmony_ci		/* Clear the port change bits */
299562306a36Sopenharmony_ci		usbc_hprt.u32 =
299662306a36Sopenharmony_ci			cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
299762306a36Sopenharmony_ci		usbc_hprt.s.prtena = 0;
299862306a36Sopenharmony_ci		cvmx_usb_write_csr32(usb, CVMX_USBCX_HPRT(usb->index),
299962306a36Sopenharmony_ci				     usbc_hprt.u32);
300062306a36Sopenharmony_ci	}
300162306a36Sopenharmony_ci	if (usbc_gintsts.s.hchint) {
300262306a36Sopenharmony_ci		/*
300362306a36Sopenharmony_ci		 * Host Channels Interrupt (HChInt)
300462306a36Sopenharmony_ci		 * The core sets this bit to indicate that an interrupt is
300562306a36Sopenharmony_ci		 * pending on one of the channels of the core (in Host mode).
300662306a36Sopenharmony_ci		 * The application must read the Host All Channels Interrupt
300762306a36Sopenharmony_ci		 * (HAINT) register to determine the exact number of the channel
300862306a36Sopenharmony_ci		 * on which the interrupt occurred, and then read the
300962306a36Sopenharmony_ci		 * corresponding Host Channel-n Interrupt (HCINTn) register to
301062306a36Sopenharmony_ci		 * determine the exact cause of the interrupt. The application
301162306a36Sopenharmony_ci		 * must clear the appropriate status bit in the HCINTn register
301262306a36Sopenharmony_ci		 * to clear this bit.
301362306a36Sopenharmony_ci		 */
301462306a36Sopenharmony_ci		union cvmx_usbcx_haint usbc_haint;
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci		usbc_haint.u32 = cvmx_usb_read_csr32(usb,
301762306a36Sopenharmony_ci						     CVMX_USBCX_HAINT(usb->index));
301862306a36Sopenharmony_ci		while (usbc_haint.u32) {
301962306a36Sopenharmony_ci			int channel;
302062306a36Sopenharmony_ci
302162306a36Sopenharmony_ci			channel = __fls(usbc_haint.u32);
302262306a36Sopenharmony_ci			cvmx_usb_poll_channel(usb, channel);
302362306a36Sopenharmony_ci			usbc_haint.u32 ^= 1 << channel;
302462306a36Sopenharmony_ci		}
302562306a36Sopenharmony_ci	}
302662306a36Sopenharmony_ci
302762306a36Sopenharmony_ci	cvmx_usb_schedule(usb, usbc_gintsts.s.sof);
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_ci	return 0;
303062306a36Sopenharmony_ci}
303162306a36Sopenharmony_ci
303262306a36Sopenharmony_ci/* convert between an HCD pointer and the corresponding struct octeon_hcd */
303362306a36Sopenharmony_cistatic inline struct octeon_hcd *hcd_to_octeon(struct usb_hcd *hcd)
303462306a36Sopenharmony_ci{
303562306a36Sopenharmony_ci	return (struct octeon_hcd *)(hcd->hcd_priv);
303662306a36Sopenharmony_ci}
303762306a36Sopenharmony_ci
303862306a36Sopenharmony_cistatic irqreturn_t octeon_usb_irq(struct usb_hcd *hcd)
303962306a36Sopenharmony_ci{
304062306a36Sopenharmony_ci	struct octeon_hcd *usb = hcd_to_octeon(hcd);
304162306a36Sopenharmony_ci	unsigned long flags;
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_ci	spin_lock_irqsave(&usb->lock, flags);
304462306a36Sopenharmony_ci	cvmx_usb_poll(usb);
304562306a36Sopenharmony_ci	spin_unlock_irqrestore(&usb->lock, flags);
304662306a36Sopenharmony_ci	return IRQ_HANDLED;
304762306a36Sopenharmony_ci}
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_cistatic int octeon_usb_start(struct usb_hcd *hcd)
305062306a36Sopenharmony_ci{
305162306a36Sopenharmony_ci	hcd->state = HC_STATE_RUNNING;
305262306a36Sopenharmony_ci	return 0;
305362306a36Sopenharmony_ci}
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_cistatic void octeon_usb_stop(struct usb_hcd *hcd)
305662306a36Sopenharmony_ci{
305762306a36Sopenharmony_ci	hcd->state = HC_STATE_HALT;
305862306a36Sopenharmony_ci}
305962306a36Sopenharmony_ci
306062306a36Sopenharmony_cistatic int octeon_usb_get_frame_number(struct usb_hcd *hcd)
306162306a36Sopenharmony_ci{
306262306a36Sopenharmony_ci	struct octeon_hcd *usb = hcd_to_octeon(hcd);
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_ci	return cvmx_usb_get_frame_number(usb);
306562306a36Sopenharmony_ci}
306662306a36Sopenharmony_ci
306762306a36Sopenharmony_cistatic int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
306862306a36Sopenharmony_ci				  struct urb *urb,
306962306a36Sopenharmony_ci				  gfp_t mem_flags)
307062306a36Sopenharmony_ci{
307162306a36Sopenharmony_ci	struct octeon_hcd *usb = hcd_to_octeon(hcd);
307262306a36Sopenharmony_ci	struct device *dev = hcd->self.controller;
307362306a36Sopenharmony_ci	struct cvmx_usb_transaction *transaction = NULL;
307462306a36Sopenharmony_ci	struct cvmx_usb_pipe *pipe;
307562306a36Sopenharmony_ci	unsigned long flags;
307662306a36Sopenharmony_ci	struct cvmx_usb_iso_packet *iso_packet;
307762306a36Sopenharmony_ci	struct usb_host_endpoint *ep = urb->ep;
307862306a36Sopenharmony_ci	int rc;
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_ci	urb->status = 0;
308162306a36Sopenharmony_ci	spin_lock_irqsave(&usb->lock, flags);
308262306a36Sopenharmony_ci
308362306a36Sopenharmony_ci	rc = usb_hcd_link_urb_to_ep(hcd, urb);
308462306a36Sopenharmony_ci	if (rc) {
308562306a36Sopenharmony_ci		spin_unlock_irqrestore(&usb->lock, flags);
308662306a36Sopenharmony_ci		return rc;
308762306a36Sopenharmony_ci	}
308862306a36Sopenharmony_ci
308962306a36Sopenharmony_ci	if (!ep->hcpriv) {
309062306a36Sopenharmony_ci		enum cvmx_usb_transfer transfer_type;
309162306a36Sopenharmony_ci		enum cvmx_usb_speed speed;
309262306a36Sopenharmony_ci		int split_device = 0;
309362306a36Sopenharmony_ci		int split_port = 0;
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_ci		switch (usb_pipetype(urb->pipe)) {
309662306a36Sopenharmony_ci		case PIPE_ISOCHRONOUS:
309762306a36Sopenharmony_ci			transfer_type = CVMX_USB_TRANSFER_ISOCHRONOUS;
309862306a36Sopenharmony_ci			break;
309962306a36Sopenharmony_ci		case PIPE_INTERRUPT:
310062306a36Sopenharmony_ci			transfer_type = CVMX_USB_TRANSFER_INTERRUPT;
310162306a36Sopenharmony_ci			break;
310262306a36Sopenharmony_ci		case PIPE_CONTROL:
310362306a36Sopenharmony_ci			transfer_type = CVMX_USB_TRANSFER_CONTROL;
310462306a36Sopenharmony_ci			break;
310562306a36Sopenharmony_ci		default:
310662306a36Sopenharmony_ci			transfer_type = CVMX_USB_TRANSFER_BULK;
310762306a36Sopenharmony_ci			break;
310862306a36Sopenharmony_ci		}
310962306a36Sopenharmony_ci		switch (urb->dev->speed) {
311062306a36Sopenharmony_ci		case USB_SPEED_LOW:
311162306a36Sopenharmony_ci			speed = CVMX_USB_SPEED_LOW;
311262306a36Sopenharmony_ci			break;
311362306a36Sopenharmony_ci		case USB_SPEED_FULL:
311462306a36Sopenharmony_ci			speed = CVMX_USB_SPEED_FULL;
311562306a36Sopenharmony_ci			break;
311662306a36Sopenharmony_ci		default:
311762306a36Sopenharmony_ci			speed = CVMX_USB_SPEED_HIGH;
311862306a36Sopenharmony_ci			break;
311962306a36Sopenharmony_ci		}
312062306a36Sopenharmony_ci		/*
312162306a36Sopenharmony_ci		 * For slow devices on high speed ports we need to find the hub
312262306a36Sopenharmony_ci		 * that does the speed translation so we know where to send the
312362306a36Sopenharmony_ci		 * split transactions.
312462306a36Sopenharmony_ci		 */
312562306a36Sopenharmony_ci		if (speed != CVMX_USB_SPEED_HIGH) {
312662306a36Sopenharmony_ci			/*
312762306a36Sopenharmony_ci			 * Start at this device and work our way up the usb
312862306a36Sopenharmony_ci			 * tree.
312962306a36Sopenharmony_ci			 */
313062306a36Sopenharmony_ci			struct usb_device *dev = urb->dev;
313162306a36Sopenharmony_ci
313262306a36Sopenharmony_ci			while (dev->parent) {
313362306a36Sopenharmony_ci				/*
313462306a36Sopenharmony_ci				 * If our parent is high speed then he'll
313562306a36Sopenharmony_ci				 * receive the splits.
313662306a36Sopenharmony_ci				 */
313762306a36Sopenharmony_ci				if (dev->parent->speed == USB_SPEED_HIGH) {
313862306a36Sopenharmony_ci					split_device = dev->parent->devnum;
313962306a36Sopenharmony_ci					split_port = dev->portnum;
314062306a36Sopenharmony_ci					break;
314162306a36Sopenharmony_ci				}
314262306a36Sopenharmony_ci				/*
314362306a36Sopenharmony_ci				 * Move up the tree one level. If we make it all
314462306a36Sopenharmony_ci				 * the way up the tree, then the port must not
314562306a36Sopenharmony_ci				 * be in high speed mode and we don't need a
314662306a36Sopenharmony_ci				 * split.
314762306a36Sopenharmony_ci				 */
314862306a36Sopenharmony_ci				dev = dev->parent;
314962306a36Sopenharmony_ci			}
315062306a36Sopenharmony_ci		}
315162306a36Sopenharmony_ci		pipe = cvmx_usb_open_pipe(usb, usb_pipedevice(urb->pipe),
315262306a36Sopenharmony_ci					  usb_pipeendpoint(urb->pipe), speed,
315362306a36Sopenharmony_ci					  le16_to_cpu(ep->desc.wMaxPacketSize)
315462306a36Sopenharmony_ci					  & 0x7ff,
315562306a36Sopenharmony_ci					  transfer_type,
315662306a36Sopenharmony_ci					  usb_pipein(urb->pipe) ?
315762306a36Sopenharmony_ci						CVMX_USB_DIRECTION_IN :
315862306a36Sopenharmony_ci						CVMX_USB_DIRECTION_OUT,
315962306a36Sopenharmony_ci					  urb->interval,
316062306a36Sopenharmony_ci					  (le16_to_cpu(ep->desc.wMaxPacketSize)
316162306a36Sopenharmony_ci					   >> 11) & 0x3,
316262306a36Sopenharmony_ci					  split_device, split_port);
316362306a36Sopenharmony_ci		if (!pipe) {
316462306a36Sopenharmony_ci			usb_hcd_unlink_urb_from_ep(hcd, urb);
316562306a36Sopenharmony_ci			spin_unlock_irqrestore(&usb->lock, flags);
316662306a36Sopenharmony_ci			dev_dbg(dev, "Failed to create pipe\n");
316762306a36Sopenharmony_ci			return -ENOMEM;
316862306a36Sopenharmony_ci		}
316962306a36Sopenharmony_ci		ep->hcpriv = pipe;
317062306a36Sopenharmony_ci	} else {
317162306a36Sopenharmony_ci		pipe = ep->hcpriv;
317262306a36Sopenharmony_ci	}
317362306a36Sopenharmony_ci
317462306a36Sopenharmony_ci	switch (usb_pipetype(urb->pipe)) {
317562306a36Sopenharmony_ci	case PIPE_ISOCHRONOUS:
317662306a36Sopenharmony_ci		dev_dbg(dev, "Submit isochronous to %d.%d\n",
317762306a36Sopenharmony_ci			usb_pipedevice(urb->pipe),
317862306a36Sopenharmony_ci			usb_pipeendpoint(urb->pipe));
317962306a36Sopenharmony_ci		/*
318062306a36Sopenharmony_ci		 * Allocate a structure to use for our private list of
318162306a36Sopenharmony_ci		 * isochronous packets.
318262306a36Sopenharmony_ci		 */
318362306a36Sopenharmony_ci		iso_packet = kmalloc_array(urb->number_of_packets,
318462306a36Sopenharmony_ci					   sizeof(struct cvmx_usb_iso_packet),
318562306a36Sopenharmony_ci					   GFP_ATOMIC);
318662306a36Sopenharmony_ci		if (iso_packet) {
318762306a36Sopenharmony_ci			int i;
318862306a36Sopenharmony_ci			/* Fill the list with the data from the URB */
318962306a36Sopenharmony_ci			for (i = 0; i < urb->number_of_packets; i++) {
319062306a36Sopenharmony_ci				iso_packet[i].offset =
319162306a36Sopenharmony_ci					urb->iso_frame_desc[i].offset;
319262306a36Sopenharmony_ci				iso_packet[i].length =
319362306a36Sopenharmony_ci					urb->iso_frame_desc[i].length;
319462306a36Sopenharmony_ci				iso_packet[i].status = CVMX_USB_STATUS_ERROR;
319562306a36Sopenharmony_ci			}
319662306a36Sopenharmony_ci			/*
319762306a36Sopenharmony_ci			 * Store a pointer to the list in the URB setup_packet
319862306a36Sopenharmony_ci			 * field. We know this currently isn't being used and
319962306a36Sopenharmony_ci			 * this saves us a bunch of logic.
320062306a36Sopenharmony_ci			 */
320162306a36Sopenharmony_ci			urb->setup_packet = (char *)iso_packet;
320262306a36Sopenharmony_ci			transaction = cvmx_usb_submit_isochronous(usb,
320362306a36Sopenharmony_ci								  pipe, urb);
320462306a36Sopenharmony_ci			/*
320562306a36Sopenharmony_ci			 * If submit failed we need to free our private packet
320662306a36Sopenharmony_ci			 * list.
320762306a36Sopenharmony_ci			 */
320862306a36Sopenharmony_ci			if (!transaction) {
320962306a36Sopenharmony_ci				urb->setup_packet = NULL;
321062306a36Sopenharmony_ci				kfree(iso_packet);
321162306a36Sopenharmony_ci			}
321262306a36Sopenharmony_ci		}
321362306a36Sopenharmony_ci		break;
321462306a36Sopenharmony_ci	case PIPE_INTERRUPT:
321562306a36Sopenharmony_ci		dev_dbg(dev, "Submit interrupt to %d.%d\n",
321662306a36Sopenharmony_ci			usb_pipedevice(urb->pipe),
321762306a36Sopenharmony_ci			usb_pipeendpoint(urb->pipe));
321862306a36Sopenharmony_ci		transaction = cvmx_usb_submit_interrupt(usb, pipe, urb);
321962306a36Sopenharmony_ci		break;
322062306a36Sopenharmony_ci	case PIPE_CONTROL:
322162306a36Sopenharmony_ci		dev_dbg(dev, "Submit control to %d.%d\n",
322262306a36Sopenharmony_ci			usb_pipedevice(urb->pipe),
322362306a36Sopenharmony_ci			usb_pipeendpoint(urb->pipe));
322462306a36Sopenharmony_ci		transaction = cvmx_usb_submit_control(usb, pipe, urb);
322562306a36Sopenharmony_ci		break;
322662306a36Sopenharmony_ci	case PIPE_BULK:
322762306a36Sopenharmony_ci		dev_dbg(dev, "Submit bulk to %d.%d\n",
322862306a36Sopenharmony_ci			usb_pipedevice(urb->pipe),
322962306a36Sopenharmony_ci			usb_pipeendpoint(urb->pipe));
323062306a36Sopenharmony_ci		transaction = cvmx_usb_submit_bulk(usb, pipe, urb);
323162306a36Sopenharmony_ci		break;
323262306a36Sopenharmony_ci	}
323362306a36Sopenharmony_ci	if (!transaction) {
323462306a36Sopenharmony_ci		usb_hcd_unlink_urb_from_ep(hcd, urb);
323562306a36Sopenharmony_ci		spin_unlock_irqrestore(&usb->lock, flags);
323662306a36Sopenharmony_ci		dev_dbg(dev, "Failed to submit\n");
323762306a36Sopenharmony_ci		return -ENOMEM;
323862306a36Sopenharmony_ci	}
323962306a36Sopenharmony_ci	urb->hcpriv = transaction;
324062306a36Sopenharmony_ci	spin_unlock_irqrestore(&usb->lock, flags);
324162306a36Sopenharmony_ci	return 0;
324262306a36Sopenharmony_ci}
324362306a36Sopenharmony_ci
324462306a36Sopenharmony_cistatic int octeon_usb_urb_dequeue(struct usb_hcd *hcd,
324562306a36Sopenharmony_ci				  struct urb *urb,
324662306a36Sopenharmony_ci				  int status)
324762306a36Sopenharmony_ci{
324862306a36Sopenharmony_ci	struct octeon_hcd *usb = hcd_to_octeon(hcd);
324962306a36Sopenharmony_ci	unsigned long flags;
325062306a36Sopenharmony_ci	int rc;
325162306a36Sopenharmony_ci
325262306a36Sopenharmony_ci	if (!urb->dev)
325362306a36Sopenharmony_ci		return -EINVAL;
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_ci	spin_lock_irqsave(&usb->lock, flags);
325662306a36Sopenharmony_ci
325762306a36Sopenharmony_ci	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
325862306a36Sopenharmony_ci	if (rc)
325962306a36Sopenharmony_ci		goto out;
326062306a36Sopenharmony_ci
326162306a36Sopenharmony_ci	urb->status = status;
326262306a36Sopenharmony_ci	cvmx_usb_cancel(usb, urb->ep->hcpriv, urb->hcpriv);
326362306a36Sopenharmony_ci
326462306a36Sopenharmony_ciout:
326562306a36Sopenharmony_ci	spin_unlock_irqrestore(&usb->lock, flags);
326662306a36Sopenharmony_ci
326762306a36Sopenharmony_ci	return rc;
326862306a36Sopenharmony_ci}
326962306a36Sopenharmony_ci
327062306a36Sopenharmony_cistatic void octeon_usb_endpoint_disable(struct usb_hcd *hcd,
327162306a36Sopenharmony_ci					struct usb_host_endpoint *ep)
327262306a36Sopenharmony_ci{
327362306a36Sopenharmony_ci	struct device *dev = hcd->self.controller;
327462306a36Sopenharmony_ci
327562306a36Sopenharmony_ci	if (ep->hcpriv) {
327662306a36Sopenharmony_ci		struct octeon_hcd *usb = hcd_to_octeon(hcd);
327762306a36Sopenharmony_ci		struct cvmx_usb_pipe *pipe = ep->hcpriv;
327862306a36Sopenharmony_ci		unsigned long flags;
327962306a36Sopenharmony_ci
328062306a36Sopenharmony_ci		spin_lock_irqsave(&usb->lock, flags);
328162306a36Sopenharmony_ci		cvmx_usb_cancel_all(usb, pipe);
328262306a36Sopenharmony_ci		if (cvmx_usb_close_pipe(usb, pipe))
328362306a36Sopenharmony_ci			dev_dbg(dev, "Closing pipe %p failed\n", pipe);
328462306a36Sopenharmony_ci		spin_unlock_irqrestore(&usb->lock, flags);
328562306a36Sopenharmony_ci		ep->hcpriv = NULL;
328662306a36Sopenharmony_ci	}
328762306a36Sopenharmony_ci}
328862306a36Sopenharmony_ci
328962306a36Sopenharmony_cistatic int octeon_usb_hub_status_data(struct usb_hcd *hcd, char *buf)
329062306a36Sopenharmony_ci{
329162306a36Sopenharmony_ci	struct octeon_hcd *usb = hcd_to_octeon(hcd);
329262306a36Sopenharmony_ci	struct cvmx_usb_port_status port_status;
329362306a36Sopenharmony_ci	unsigned long flags;
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	spin_lock_irqsave(&usb->lock, flags);
329662306a36Sopenharmony_ci	port_status = cvmx_usb_get_status(usb);
329762306a36Sopenharmony_ci	spin_unlock_irqrestore(&usb->lock, flags);
329862306a36Sopenharmony_ci	buf[0] = port_status.connect_change << 1;
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ci	return buf[0] != 0;
330162306a36Sopenharmony_ci}
330262306a36Sopenharmony_ci
330362306a36Sopenharmony_cistatic int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
330462306a36Sopenharmony_ci				  u16 wIndex, char *buf, u16 wLength)
330562306a36Sopenharmony_ci{
330662306a36Sopenharmony_ci	struct octeon_hcd *usb = hcd_to_octeon(hcd);
330762306a36Sopenharmony_ci	struct device *dev = hcd->self.controller;
330862306a36Sopenharmony_ci	struct cvmx_usb_port_status usb_port_status;
330962306a36Sopenharmony_ci	int port_status;
331062306a36Sopenharmony_ci	struct usb_hub_descriptor *desc;
331162306a36Sopenharmony_ci	unsigned long flags;
331262306a36Sopenharmony_ci
331362306a36Sopenharmony_ci	switch (typeReq) {
331462306a36Sopenharmony_ci	case ClearHubFeature:
331562306a36Sopenharmony_ci		dev_dbg(dev, "ClearHubFeature\n");
331662306a36Sopenharmony_ci		switch (wValue) {
331762306a36Sopenharmony_ci		case C_HUB_LOCAL_POWER:
331862306a36Sopenharmony_ci		case C_HUB_OVER_CURRENT:
331962306a36Sopenharmony_ci			/* Nothing required here */
332062306a36Sopenharmony_ci			break;
332162306a36Sopenharmony_ci		default:
332262306a36Sopenharmony_ci			return -EINVAL;
332362306a36Sopenharmony_ci		}
332462306a36Sopenharmony_ci		break;
332562306a36Sopenharmony_ci	case ClearPortFeature:
332662306a36Sopenharmony_ci		dev_dbg(dev, "ClearPortFeature\n");
332762306a36Sopenharmony_ci		if (wIndex != 1) {
332862306a36Sopenharmony_ci			dev_dbg(dev, " INVALID\n");
332962306a36Sopenharmony_ci			return -EINVAL;
333062306a36Sopenharmony_ci		}
333162306a36Sopenharmony_ci
333262306a36Sopenharmony_ci		switch (wValue) {
333362306a36Sopenharmony_ci		case USB_PORT_FEAT_ENABLE:
333462306a36Sopenharmony_ci			dev_dbg(dev, " ENABLE\n");
333562306a36Sopenharmony_ci			spin_lock_irqsave(&usb->lock, flags);
333662306a36Sopenharmony_ci			cvmx_usb_disable(usb);
333762306a36Sopenharmony_ci			spin_unlock_irqrestore(&usb->lock, flags);
333862306a36Sopenharmony_ci			break;
333962306a36Sopenharmony_ci		case USB_PORT_FEAT_SUSPEND:
334062306a36Sopenharmony_ci			dev_dbg(dev, " SUSPEND\n");
334162306a36Sopenharmony_ci			/* Not supported on Octeon */
334262306a36Sopenharmony_ci			break;
334362306a36Sopenharmony_ci		case USB_PORT_FEAT_POWER:
334462306a36Sopenharmony_ci			dev_dbg(dev, " POWER\n");
334562306a36Sopenharmony_ci			/* Not supported on Octeon */
334662306a36Sopenharmony_ci			break;
334762306a36Sopenharmony_ci		case USB_PORT_FEAT_INDICATOR:
334862306a36Sopenharmony_ci			dev_dbg(dev, " INDICATOR\n");
334962306a36Sopenharmony_ci			/* Port inidicator not supported */
335062306a36Sopenharmony_ci			break;
335162306a36Sopenharmony_ci		case USB_PORT_FEAT_C_CONNECTION:
335262306a36Sopenharmony_ci			dev_dbg(dev, " C_CONNECTION\n");
335362306a36Sopenharmony_ci			/* Clears drivers internal connect status change flag */
335462306a36Sopenharmony_ci			spin_lock_irqsave(&usb->lock, flags);
335562306a36Sopenharmony_ci			usb->port_status = cvmx_usb_get_status(usb);
335662306a36Sopenharmony_ci			spin_unlock_irqrestore(&usb->lock, flags);
335762306a36Sopenharmony_ci			break;
335862306a36Sopenharmony_ci		case USB_PORT_FEAT_C_RESET:
335962306a36Sopenharmony_ci			dev_dbg(dev, " C_RESET\n");
336062306a36Sopenharmony_ci			/*
336162306a36Sopenharmony_ci			 * Clears the driver's internal Port Reset Change flag.
336262306a36Sopenharmony_ci			 */
336362306a36Sopenharmony_ci			spin_lock_irqsave(&usb->lock, flags);
336462306a36Sopenharmony_ci			usb->port_status = cvmx_usb_get_status(usb);
336562306a36Sopenharmony_ci			spin_unlock_irqrestore(&usb->lock, flags);
336662306a36Sopenharmony_ci			break;
336762306a36Sopenharmony_ci		case USB_PORT_FEAT_C_ENABLE:
336862306a36Sopenharmony_ci			dev_dbg(dev, " C_ENABLE\n");
336962306a36Sopenharmony_ci			/*
337062306a36Sopenharmony_ci			 * Clears the driver's internal Port Enable/Disable
337162306a36Sopenharmony_ci			 * Change flag.
337262306a36Sopenharmony_ci			 */
337362306a36Sopenharmony_ci			spin_lock_irqsave(&usb->lock, flags);
337462306a36Sopenharmony_ci			usb->port_status = cvmx_usb_get_status(usb);
337562306a36Sopenharmony_ci			spin_unlock_irqrestore(&usb->lock, flags);
337662306a36Sopenharmony_ci			break;
337762306a36Sopenharmony_ci		case USB_PORT_FEAT_C_SUSPEND:
337862306a36Sopenharmony_ci			dev_dbg(dev, " C_SUSPEND\n");
337962306a36Sopenharmony_ci			/*
338062306a36Sopenharmony_ci			 * Clears the driver's internal Port Suspend Change
338162306a36Sopenharmony_ci			 * flag, which is set when resume signaling on the host
338262306a36Sopenharmony_ci			 * port is complete.
338362306a36Sopenharmony_ci			 */
338462306a36Sopenharmony_ci			break;
338562306a36Sopenharmony_ci		case USB_PORT_FEAT_C_OVER_CURRENT:
338662306a36Sopenharmony_ci			dev_dbg(dev, " C_OVER_CURRENT\n");
338762306a36Sopenharmony_ci			/* Clears the driver's overcurrent Change flag */
338862306a36Sopenharmony_ci			spin_lock_irqsave(&usb->lock, flags);
338962306a36Sopenharmony_ci			usb->port_status = cvmx_usb_get_status(usb);
339062306a36Sopenharmony_ci			spin_unlock_irqrestore(&usb->lock, flags);
339162306a36Sopenharmony_ci			break;
339262306a36Sopenharmony_ci		default:
339362306a36Sopenharmony_ci			dev_dbg(dev, " UNKNOWN\n");
339462306a36Sopenharmony_ci			return -EINVAL;
339562306a36Sopenharmony_ci		}
339662306a36Sopenharmony_ci		break;
339762306a36Sopenharmony_ci	case GetHubDescriptor:
339862306a36Sopenharmony_ci		dev_dbg(dev, "GetHubDescriptor\n");
339962306a36Sopenharmony_ci		desc = (struct usb_hub_descriptor *)buf;
340062306a36Sopenharmony_ci		desc->bDescLength = 9;
340162306a36Sopenharmony_ci		desc->bDescriptorType = 0x29;
340262306a36Sopenharmony_ci		desc->bNbrPorts = 1;
340362306a36Sopenharmony_ci		desc->wHubCharacteristics = cpu_to_le16(0x08);
340462306a36Sopenharmony_ci		desc->bPwrOn2PwrGood = 1;
340562306a36Sopenharmony_ci		desc->bHubContrCurrent = 0;
340662306a36Sopenharmony_ci		desc->u.hs.DeviceRemovable[0] = 0;
340762306a36Sopenharmony_ci		desc->u.hs.DeviceRemovable[1] = 0xff;
340862306a36Sopenharmony_ci		break;
340962306a36Sopenharmony_ci	case GetHubStatus:
341062306a36Sopenharmony_ci		dev_dbg(dev, "GetHubStatus\n");
341162306a36Sopenharmony_ci		*(__le32 *)buf = 0;
341262306a36Sopenharmony_ci		break;
341362306a36Sopenharmony_ci	case GetPortStatus:
341462306a36Sopenharmony_ci		dev_dbg(dev, "GetPortStatus\n");
341562306a36Sopenharmony_ci		if (wIndex != 1) {
341662306a36Sopenharmony_ci			dev_dbg(dev, " INVALID\n");
341762306a36Sopenharmony_ci			return -EINVAL;
341862306a36Sopenharmony_ci		}
341962306a36Sopenharmony_ci
342062306a36Sopenharmony_ci		spin_lock_irqsave(&usb->lock, flags);
342162306a36Sopenharmony_ci		usb_port_status = cvmx_usb_get_status(usb);
342262306a36Sopenharmony_ci		spin_unlock_irqrestore(&usb->lock, flags);
342362306a36Sopenharmony_ci		port_status = 0;
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_ci		if (usb_port_status.connect_change) {
342662306a36Sopenharmony_ci			port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
342762306a36Sopenharmony_ci			dev_dbg(dev, " C_CONNECTION\n");
342862306a36Sopenharmony_ci		}
342962306a36Sopenharmony_ci
343062306a36Sopenharmony_ci		if (usb_port_status.port_enabled) {
343162306a36Sopenharmony_ci			port_status |= (1 << USB_PORT_FEAT_C_ENABLE);
343262306a36Sopenharmony_ci			dev_dbg(dev, " C_ENABLE\n");
343362306a36Sopenharmony_ci		}
343462306a36Sopenharmony_ci
343562306a36Sopenharmony_ci		if (usb_port_status.connected) {
343662306a36Sopenharmony_ci			port_status |= (1 << USB_PORT_FEAT_CONNECTION);
343762306a36Sopenharmony_ci			dev_dbg(dev, " CONNECTION\n");
343862306a36Sopenharmony_ci		}
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci		if (usb_port_status.port_enabled) {
344162306a36Sopenharmony_ci			port_status |= (1 << USB_PORT_FEAT_ENABLE);
344262306a36Sopenharmony_ci			dev_dbg(dev, " ENABLE\n");
344362306a36Sopenharmony_ci		}
344462306a36Sopenharmony_ci
344562306a36Sopenharmony_ci		if (usb_port_status.port_over_current) {
344662306a36Sopenharmony_ci			port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT);
344762306a36Sopenharmony_ci			dev_dbg(dev, " OVER_CURRENT\n");
344862306a36Sopenharmony_ci		}
344962306a36Sopenharmony_ci
345062306a36Sopenharmony_ci		if (usb_port_status.port_powered) {
345162306a36Sopenharmony_ci			port_status |= (1 << USB_PORT_FEAT_POWER);
345262306a36Sopenharmony_ci			dev_dbg(dev, " POWER\n");
345362306a36Sopenharmony_ci		}
345462306a36Sopenharmony_ci
345562306a36Sopenharmony_ci		if (usb_port_status.port_speed == CVMX_USB_SPEED_HIGH) {
345662306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_HIGH_SPEED;
345762306a36Sopenharmony_ci			dev_dbg(dev, " HIGHSPEED\n");
345862306a36Sopenharmony_ci		} else if (usb_port_status.port_speed == CVMX_USB_SPEED_LOW) {
345962306a36Sopenharmony_ci			port_status |= (1 << USB_PORT_FEAT_LOWSPEED);
346062306a36Sopenharmony_ci			dev_dbg(dev, " LOWSPEED\n");
346162306a36Sopenharmony_ci		}
346262306a36Sopenharmony_ci
346362306a36Sopenharmony_ci		*((__le32 *)buf) = cpu_to_le32(port_status);
346462306a36Sopenharmony_ci		break;
346562306a36Sopenharmony_ci	case SetHubFeature:
346662306a36Sopenharmony_ci		dev_dbg(dev, "SetHubFeature\n");
346762306a36Sopenharmony_ci		/* No HUB features supported */
346862306a36Sopenharmony_ci		break;
346962306a36Sopenharmony_ci	case SetPortFeature:
347062306a36Sopenharmony_ci		dev_dbg(dev, "SetPortFeature\n");
347162306a36Sopenharmony_ci		if (wIndex != 1) {
347262306a36Sopenharmony_ci			dev_dbg(dev, " INVALID\n");
347362306a36Sopenharmony_ci			return -EINVAL;
347462306a36Sopenharmony_ci		}
347562306a36Sopenharmony_ci
347662306a36Sopenharmony_ci		switch (wValue) {
347762306a36Sopenharmony_ci		case USB_PORT_FEAT_SUSPEND:
347862306a36Sopenharmony_ci			dev_dbg(dev, " SUSPEND\n");
347962306a36Sopenharmony_ci			return -EINVAL;
348062306a36Sopenharmony_ci		case USB_PORT_FEAT_POWER:
348162306a36Sopenharmony_ci			dev_dbg(dev, " POWER\n");
348262306a36Sopenharmony_ci			/*
348362306a36Sopenharmony_ci			 * Program the port power bit to drive VBUS on the USB.
348462306a36Sopenharmony_ci			 */
348562306a36Sopenharmony_ci			spin_lock_irqsave(&usb->lock, flags);
348662306a36Sopenharmony_ci			USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index),
348762306a36Sopenharmony_ci					cvmx_usbcx_hprt, prtpwr, 1);
348862306a36Sopenharmony_ci			spin_unlock_irqrestore(&usb->lock, flags);
348962306a36Sopenharmony_ci			return 0;
349062306a36Sopenharmony_ci		case USB_PORT_FEAT_RESET:
349162306a36Sopenharmony_ci			dev_dbg(dev, " RESET\n");
349262306a36Sopenharmony_ci			spin_lock_irqsave(&usb->lock, flags);
349362306a36Sopenharmony_ci			cvmx_usb_reset_port(usb);
349462306a36Sopenharmony_ci			spin_unlock_irqrestore(&usb->lock, flags);
349562306a36Sopenharmony_ci			return 0;
349662306a36Sopenharmony_ci		case USB_PORT_FEAT_INDICATOR:
349762306a36Sopenharmony_ci			dev_dbg(dev, " INDICATOR\n");
349862306a36Sopenharmony_ci			/* Not supported */
349962306a36Sopenharmony_ci			break;
350062306a36Sopenharmony_ci		default:
350162306a36Sopenharmony_ci			dev_dbg(dev, " UNKNOWN\n");
350262306a36Sopenharmony_ci			return -EINVAL;
350362306a36Sopenharmony_ci		}
350462306a36Sopenharmony_ci		break;
350562306a36Sopenharmony_ci	default:
350662306a36Sopenharmony_ci		dev_dbg(dev, "Unknown root hub request\n");
350762306a36Sopenharmony_ci		return -EINVAL;
350862306a36Sopenharmony_ci	}
350962306a36Sopenharmony_ci	return 0;
351062306a36Sopenharmony_ci}
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_cistatic const struct hc_driver octeon_hc_driver = {
351362306a36Sopenharmony_ci	.description		= "Octeon USB",
351462306a36Sopenharmony_ci	.product_desc		= "Octeon Host Controller",
351562306a36Sopenharmony_ci	.hcd_priv_size		= sizeof(struct octeon_hcd),
351662306a36Sopenharmony_ci	.irq			= octeon_usb_irq,
351762306a36Sopenharmony_ci	.flags			= HCD_MEMORY | HCD_DMA | HCD_USB2,
351862306a36Sopenharmony_ci	.start			= octeon_usb_start,
351962306a36Sopenharmony_ci	.stop			= octeon_usb_stop,
352062306a36Sopenharmony_ci	.urb_enqueue		= octeon_usb_urb_enqueue,
352162306a36Sopenharmony_ci	.urb_dequeue		= octeon_usb_urb_dequeue,
352262306a36Sopenharmony_ci	.endpoint_disable	= octeon_usb_endpoint_disable,
352362306a36Sopenharmony_ci	.get_frame_number	= octeon_usb_get_frame_number,
352462306a36Sopenharmony_ci	.hub_status_data	= octeon_usb_hub_status_data,
352562306a36Sopenharmony_ci	.hub_control		= octeon_usb_hub_control,
352662306a36Sopenharmony_ci	.map_urb_for_dma	= octeon_map_urb_for_dma,
352762306a36Sopenharmony_ci	.unmap_urb_for_dma	= octeon_unmap_urb_for_dma,
352862306a36Sopenharmony_ci};
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_cistatic int octeon_usb_probe(struct platform_device *pdev)
353162306a36Sopenharmony_ci{
353262306a36Sopenharmony_ci	int status;
353362306a36Sopenharmony_ci	int initialize_flags;
353462306a36Sopenharmony_ci	int usb_num;
353562306a36Sopenharmony_ci	struct resource *res_mem;
353662306a36Sopenharmony_ci	struct device_node *usbn_node;
353762306a36Sopenharmony_ci	int irq = platform_get_irq(pdev, 0);
353862306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
353962306a36Sopenharmony_ci	struct octeon_hcd *usb;
354062306a36Sopenharmony_ci	struct usb_hcd *hcd;
354162306a36Sopenharmony_ci	u32 clock_rate = 48000000;
354262306a36Sopenharmony_ci	bool is_crystal_clock = false;
354362306a36Sopenharmony_ci	const char *clock_type;
354462306a36Sopenharmony_ci	int i;
354562306a36Sopenharmony_ci
354662306a36Sopenharmony_ci	if (!dev->of_node) {
354762306a36Sopenharmony_ci		dev_err(dev, "Error: empty of_node\n");
354862306a36Sopenharmony_ci		return -ENXIO;
354962306a36Sopenharmony_ci	}
355062306a36Sopenharmony_ci	usbn_node = dev->of_node->parent;
355162306a36Sopenharmony_ci
355262306a36Sopenharmony_ci	i = of_property_read_u32(usbn_node,
355362306a36Sopenharmony_ci				 "clock-frequency", &clock_rate);
355462306a36Sopenharmony_ci	if (i)
355562306a36Sopenharmony_ci		i = of_property_read_u32(usbn_node,
355662306a36Sopenharmony_ci					 "refclk-frequency", &clock_rate);
355762306a36Sopenharmony_ci	if (i) {
355862306a36Sopenharmony_ci		dev_err(dev, "No USBN \"clock-frequency\"\n");
355962306a36Sopenharmony_ci		return -ENXIO;
356062306a36Sopenharmony_ci	}
356162306a36Sopenharmony_ci	switch (clock_rate) {
356262306a36Sopenharmony_ci	case 12000000:
356362306a36Sopenharmony_ci		initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ;
356462306a36Sopenharmony_ci		break;
356562306a36Sopenharmony_ci	case 24000000:
356662306a36Sopenharmony_ci		initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ;
356762306a36Sopenharmony_ci		break;
356862306a36Sopenharmony_ci	case 48000000:
356962306a36Sopenharmony_ci		initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ;
357062306a36Sopenharmony_ci		break;
357162306a36Sopenharmony_ci	default:
357262306a36Sopenharmony_ci		dev_err(dev, "Illegal USBN \"clock-frequency\" %u\n",
357362306a36Sopenharmony_ci			clock_rate);
357462306a36Sopenharmony_ci		return -ENXIO;
357562306a36Sopenharmony_ci	}
357662306a36Sopenharmony_ci
357762306a36Sopenharmony_ci	i = of_property_read_string(usbn_node,
357862306a36Sopenharmony_ci				    "cavium,refclk-type", &clock_type);
357962306a36Sopenharmony_ci	if (i)
358062306a36Sopenharmony_ci		i = of_property_read_string(usbn_node,
358162306a36Sopenharmony_ci					    "refclk-type", &clock_type);
358262306a36Sopenharmony_ci
358362306a36Sopenharmony_ci	if (!i && strcmp("crystal", clock_type) == 0)
358462306a36Sopenharmony_ci		is_crystal_clock = true;
358562306a36Sopenharmony_ci
358662306a36Sopenharmony_ci	if (is_crystal_clock)
358762306a36Sopenharmony_ci		initialize_flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI;
358862306a36Sopenharmony_ci	else
358962306a36Sopenharmony_ci		initialize_flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND;
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
359262306a36Sopenharmony_ci	if (!res_mem) {
359362306a36Sopenharmony_ci		dev_err(dev, "found no memory resource\n");
359462306a36Sopenharmony_ci		return -ENXIO;
359562306a36Sopenharmony_ci	}
359662306a36Sopenharmony_ci	usb_num = (res_mem->start >> 44) & 1;
359762306a36Sopenharmony_ci
359862306a36Sopenharmony_ci	if (irq < 0) {
359962306a36Sopenharmony_ci		/* Defective device tree, but we know how to fix it. */
360062306a36Sopenharmony_ci		irq_hw_number_t hwirq = usb_num ? (1 << 6) + 17 : 56;
360162306a36Sopenharmony_ci
360262306a36Sopenharmony_ci		irq = irq_create_mapping(NULL, hwirq);
360362306a36Sopenharmony_ci	}
360462306a36Sopenharmony_ci
360562306a36Sopenharmony_ci	/*
360662306a36Sopenharmony_ci	 * Set the DMA mask to 64bits so we get buffers already translated for
360762306a36Sopenharmony_ci	 * DMA.
360862306a36Sopenharmony_ci	 */
360962306a36Sopenharmony_ci	i = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
361062306a36Sopenharmony_ci	if (i)
361162306a36Sopenharmony_ci		return i;
361262306a36Sopenharmony_ci
361362306a36Sopenharmony_ci	/*
361462306a36Sopenharmony_ci	 * Only cn52XX and cn56XX have DWC_OTG USB hardware and the
361562306a36Sopenharmony_ci	 * IOB priority registers.  Under heavy network load USB
361662306a36Sopenharmony_ci	 * hardware can be starved by the IOB causing a crash.  Give
361762306a36Sopenharmony_ci	 * it a priority boost if it has been waiting more than 400
361862306a36Sopenharmony_ci	 * cycles to avoid this situation.
361962306a36Sopenharmony_ci	 *
362062306a36Sopenharmony_ci	 * Testing indicates that a cnt_val of 8192 is not sufficient,
362162306a36Sopenharmony_ci	 * but no failures are seen with 4096.  We choose a value of
362262306a36Sopenharmony_ci	 * 400 to give a safety factor of 10.
362362306a36Sopenharmony_ci	 */
362462306a36Sopenharmony_ci	if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) {
362562306a36Sopenharmony_ci		union cvmx_iob_n2c_l2c_pri_cnt pri_cnt;
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ci		pri_cnt.u64 = 0;
362862306a36Sopenharmony_ci		pri_cnt.s.cnt_enb = 1;
362962306a36Sopenharmony_ci		pri_cnt.s.cnt_val = 400;
363062306a36Sopenharmony_ci		cvmx_write_csr(CVMX_IOB_N2C_L2C_PRI_CNT, pri_cnt.u64);
363162306a36Sopenharmony_ci	}
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_ci	hcd = usb_create_hcd(&octeon_hc_driver, dev, dev_name(dev));
363462306a36Sopenharmony_ci	if (!hcd) {
363562306a36Sopenharmony_ci		dev_dbg(dev, "Failed to allocate memory for HCD\n");
363662306a36Sopenharmony_ci		return -1;
363762306a36Sopenharmony_ci	}
363862306a36Sopenharmony_ci	hcd->uses_new_polling = 1;
363962306a36Sopenharmony_ci	usb = (struct octeon_hcd *)hcd->hcd_priv;
364062306a36Sopenharmony_ci
364162306a36Sopenharmony_ci	spin_lock_init(&usb->lock);
364262306a36Sopenharmony_ci
364362306a36Sopenharmony_ci	usb->init_flags = initialize_flags;
364462306a36Sopenharmony_ci
364562306a36Sopenharmony_ci	/* Initialize the USB state structure */
364662306a36Sopenharmony_ci	usb->index = usb_num;
364762306a36Sopenharmony_ci	INIT_LIST_HEAD(&usb->idle_pipes);
364862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(usb->active_pipes); i++)
364962306a36Sopenharmony_ci		INIT_LIST_HEAD(&usb->active_pipes[i]);
365062306a36Sopenharmony_ci
365162306a36Sopenharmony_ci	/* Due to an errata, CN31XX doesn't support DMA */
365262306a36Sopenharmony_ci	if (OCTEON_IS_MODEL(OCTEON_CN31XX)) {
365362306a36Sopenharmony_ci		usb->init_flags |= CVMX_USB_INITIALIZE_FLAGS_NO_DMA;
365462306a36Sopenharmony_ci		/* Only use one channel with non DMA */
365562306a36Sopenharmony_ci		usb->idle_hardware_channels = 0x1;
365662306a36Sopenharmony_ci	} else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
365762306a36Sopenharmony_ci		/* CN5XXX have an errata with channel 3 */
365862306a36Sopenharmony_ci		usb->idle_hardware_channels = 0xf7;
365962306a36Sopenharmony_ci	} else {
366062306a36Sopenharmony_ci		usb->idle_hardware_channels = 0xff;
366162306a36Sopenharmony_ci	}
366262306a36Sopenharmony_ci
366362306a36Sopenharmony_ci	status = cvmx_usb_initialize(dev, usb);
366462306a36Sopenharmony_ci	if (status) {
366562306a36Sopenharmony_ci		dev_dbg(dev, "USB initialization failed with %d\n", status);
366662306a36Sopenharmony_ci		usb_put_hcd(hcd);
366762306a36Sopenharmony_ci		return -1;
366862306a36Sopenharmony_ci	}
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_ci	status = usb_add_hcd(hcd, irq, 0);
367162306a36Sopenharmony_ci	if (status) {
367262306a36Sopenharmony_ci		dev_dbg(dev, "USB add HCD failed with %d\n", status);
367362306a36Sopenharmony_ci		usb_put_hcd(hcd);
367462306a36Sopenharmony_ci		return -1;
367562306a36Sopenharmony_ci	}
367662306a36Sopenharmony_ci	device_wakeup_enable(hcd->self.controller);
367762306a36Sopenharmony_ci
367862306a36Sopenharmony_ci	dev_info(dev, "Registered HCD for port %d on irq %d\n", usb_num, irq);
367962306a36Sopenharmony_ci
368062306a36Sopenharmony_ci	return 0;
368162306a36Sopenharmony_ci}
368262306a36Sopenharmony_ci
368362306a36Sopenharmony_cistatic void octeon_usb_remove(struct platform_device *pdev)
368462306a36Sopenharmony_ci{
368562306a36Sopenharmony_ci	int status;
368662306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
368762306a36Sopenharmony_ci	struct usb_hcd *hcd = dev_get_drvdata(dev);
368862306a36Sopenharmony_ci	struct octeon_hcd *usb = hcd_to_octeon(hcd);
368962306a36Sopenharmony_ci	unsigned long flags;
369062306a36Sopenharmony_ci
369162306a36Sopenharmony_ci	usb_remove_hcd(hcd);
369262306a36Sopenharmony_ci	spin_lock_irqsave(&usb->lock, flags);
369362306a36Sopenharmony_ci	status = cvmx_usb_shutdown(usb);
369462306a36Sopenharmony_ci	spin_unlock_irqrestore(&usb->lock, flags);
369562306a36Sopenharmony_ci	if (status)
369662306a36Sopenharmony_ci		dev_dbg(dev, "USB shutdown failed with %d\n", status);
369762306a36Sopenharmony_ci
369862306a36Sopenharmony_ci	usb_put_hcd(hcd);
369962306a36Sopenharmony_ci}
370062306a36Sopenharmony_ci
370162306a36Sopenharmony_cistatic const struct of_device_id octeon_usb_match[] = {
370262306a36Sopenharmony_ci	{
370362306a36Sopenharmony_ci		.compatible = "cavium,octeon-5750-usbc",
370462306a36Sopenharmony_ci	},
370562306a36Sopenharmony_ci	{},
370662306a36Sopenharmony_ci};
370762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, octeon_usb_match);
370862306a36Sopenharmony_ci
370962306a36Sopenharmony_cistatic struct platform_driver octeon_usb_driver = {
371062306a36Sopenharmony_ci	.driver = {
371162306a36Sopenharmony_ci		.name		= "octeon-hcd",
371262306a36Sopenharmony_ci		.of_match_table = octeon_usb_match,
371362306a36Sopenharmony_ci	},
371462306a36Sopenharmony_ci	.probe      = octeon_usb_probe,
371562306a36Sopenharmony_ci	.remove_new = octeon_usb_remove,
371662306a36Sopenharmony_ci};
371762306a36Sopenharmony_ci
371862306a36Sopenharmony_cistatic int __init octeon_usb_driver_init(void)
371962306a36Sopenharmony_ci{
372062306a36Sopenharmony_ci	if (usb_disabled())
372162306a36Sopenharmony_ci		return 0;
372262306a36Sopenharmony_ci
372362306a36Sopenharmony_ci	return platform_driver_register(&octeon_usb_driver);
372462306a36Sopenharmony_ci}
372562306a36Sopenharmony_cimodule_init(octeon_usb_driver_init);
372662306a36Sopenharmony_ci
372762306a36Sopenharmony_cistatic void __exit octeon_usb_driver_exit(void)
372862306a36Sopenharmony_ci{
372962306a36Sopenharmony_ci	if (usb_disabled())
373062306a36Sopenharmony_ci		return;
373162306a36Sopenharmony_ci
373262306a36Sopenharmony_ci	platform_driver_unregister(&octeon_usb_driver);
373362306a36Sopenharmony_ci}
373462306a36Sopenharmony_cimodule_exit(octeon_usb_driver_exit);
373562306a36Sopenharmony_ci
373662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
373762306a36Sopenharmony_ciMODULE_AUTHOR("Cavium, Inc. <support@cavium.com>");
373862306a36Sopenharmony_ciMODULE_DESCRIPTION("Cavium Inc. OCTEON USB Host driver.");
3739