162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0+ */
262306a36Sopenharmony_ci#ifndef __ASPEED_VHUB_H
362306a36Sopenharmony_ci#define __ASPEED_VHUB_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/usb.h>
662306a36Sopenharmony_ci#include <linux/usb/ch11.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*****************************
962306a36Sopenharmony_ci *                           *
1062306a36Sopenharmony_ci * VHUB register definitions *
1162306a36Sopenharmony_ci *                           *
1262306a36Sopenharmony_ci *****************************/
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define	AST_VHUB_CTRL		0x00	/* Root Function Control & Status Register */
1562306a36Sopenharmony_ci#define	AST_VHUB_CONF		0x04	/* Root Configuration Setting Register */
1662306a36Sopenharmony_ci#define	AST_VHUB_IER		0x08	/* Interrupt Ctrl Register */
1762306a36Sopenharmony_ci#define	AST_VHUB_ISR		0x0C	/* Interrupt Status Register */
1862306a36Sopenharmony_ci#define	AST_VHUB_EP_ACK_IER	0x10	/* Programmable Endpoint Pool ACK Interrupt Enable Register */
1962306a36Sopenharmony_ci#define	AST_VHUB_EP_NACK_IER	0x14	/* Programmable Endpoint Pool NACK Interrupt Enable Register  */
2062306a36Sopenharmony_ci#define AST_VHUB_EP_ACK_ISR	0x18	/* Programmable Endpoint Pool ACK Interrupt Status Register  */
2162306a36Sopenharmony_ci#define AST_VHUB_EP_NACK_ISR	0x1C	/* Programmable Endpoint Pool NACK Interrupt Status Register  */
2262306a36Sopenharmony_ci#define AST_VHUB_SW_RESET	0x20	/* Device Controller Soft Reset Enable Register */
2362306a36Sopenharmony_ci#define AST_VHUB_USBSTS		0x24	/* USB Status Register */
2462306a36Sopenharmony_ci#define AST_VHUB_EP_TOGGLE	0x28	/* Programmable Endpoint Pool Data Toggle Value Set */
2562306a36Sopenharmony_ci#define AST_VHUB_ISO_FAIL_ACC	0x2C	/* Isochronous Transaction Fail Accumulator */
2662306a36Sopenharmony_ci#define AST_VHUB_EP0_CTRL	0x30	/* Endpoint 0 Contrl/Status Register */
2762306a36Sopenharmony_ci#define AST_VHUB_EP0_DATA	0x34	/* Base Address of Endpoint 0 In/OUT Data Buffer Register */
2862306a36Sopenharmony_ci#define AST_VHUB_EP1_CTRL	0x38	/* Endpoint 1 Contrl/Status Register */
2962306a36Sopenharmony_ci#define AST_VHUB_EP1_STS_CHG	0x3C	/* Endpoint 1 Status Change Bitmap Data */
3062306a36Sopenharmony_ci#define AST_VHUB_SETUP0		0x80	/* Root Device Setup Data Buffer0 */
3162306a36Sopenharmony_ci#define AST_VHUB_SETUP1		0x84	/* Root Device Setup Data Buffer1 */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* Main control reg */
3462306a36Sopenharmony_ci#define VHUB_CTRL_PHY_CLK			(1 << 31)
3562306a36Sopenharmony_ci#define VHUB_CTRL_PHY_LOOP_TEST			(1 << 25)
3662306a36Sopenharmony_ci#define VHUB_CTRL_DN_PWN			(1 << 24)
3762306a36Sopenharmony_ci#define VHUB_CTRL_DP_PWN			(1 << 23)
3862306a36Sopenharmony_ci#define VHUB_CTRL_LONG_DESC			(1 << 18)
3962306a36Sopenharmony_ci#define VHUB_CTRL_ISO_RSP_CTRL			(1 << 17)
4062306a36Sopenharmony_ci#define VHUB_CTRL_SPLIT_IN			(1 << 16)
4162306a36Sopenharmony_ci#define VHUB_CTRL_LOOP_T_RESULT			(1 << 15)
4262306a36Sopenharmony_ci#define VHUB_CTRL_LOOP_T_STS			(1 << 14)
4362306a36Sopenharmony_ci#define VHUB_CTRL_PHY_BIST_RESULT		(1 << 13)
4462306a36Sopenharmony_ci#define VHUB_CTRL_PHY_BIST_CTRL			(1 << 12)
4562306a36Sopenharmony_ci#define VHUB_CTRL_PHY_RESET_DIS			(1 << 11)
4662306a36Sopenharmony_ci#define VHUB_CTRL_SET_TEST_MODE(x)		((x) << 8)
4762306a36Sopenharmony_ci#define VHUB_CTRL_MANUAL_REMOTE_WAKEUP		(1 << 4)
4862306a36Sopenharmony_ci#define VHUB_CTRL_AUTO_REMOTE_WAKEUP		(1 << 3)
4962306a36Sopenharmony_ci#define VHUB_CTRL_CLK_STOP_SUSPEND		(1 << 2)
5062306a36Sopenharmony_ci#define VHUB_CTRL_FULL_SPEED_ONLY		(1 << 1)
5162306a36Sopenharmony_ci#define VHUB_CTRL_UPSTREAM_CONNECT		(1 << 0)
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* IER & ISR */
5462306a36Sopenharmony_ci#define VHUB_IRQ_DEV1_BIT			9
5562306a36Sopenharmony_ci#define VHUB_IRQ_USB_CMD_DEADLOCK		(1 << 18)
5662306a36Sopenharmony_ci#define VHUB_IRQ_EP_POOL_NAK			(1 << 17)
5762306a36Sopenharmony_ci#define VHUB_IRQ_EP_POOL_ACK_STALL		(1 << 16)
5862306a36Sopenharmony_ci#define VHUB_IRQ_DEVICE1			(1 << (VHUB_IRQ_DEV1_BIT))
5962306a36Sopenharmony_ci#define VHUB_IRQ_BUS_RESUME			(1 << 8)
6062306a36Sopenharmony_ci#define VHUB_IRQ_BUS_SUSPEND 			(1 << 7)
6162306a36Sopenharmony_ci#define VHUB_IRQ_BUS_RESET 			(1 << 6)
6262306a36Sopenharmony_ci#define VHUB_IRQ_HUB_EP1_IN_DATA_ACK		(1 << 5)
6362306a36Sopenharmony_ci#define VHUB_IRQ_HUB_EP0_IN_DATA_NAK		(1 << 4)
6462306a36Sopenharmony_ci#define VHUB_IRQ_HUB_EP0_IN_ACK_STALL		(1 << 3)
6562306a36Sopenharmony_ci#define VHUB_IRQ_HUB_EP0_OUT_NAK		(1 << 2)
6662306a36Sopenharmony_ci#define VHUB_IRQ_HUB_EP0_OUT_ACK_STALL		(1 << 1)
6762306a36Sopenharmony_ci#define VHUB_IRQ_HUB_EP0_SETUP			(1 << 0)
6862306a36Sopenharmony_ci#define VHUB_IRQ_ACK_ALL			0x1ff
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* Downstream device IRQ mask. */
7162306a36Sopenharmony_ci#define VHUB_DEV_IRQ(n)				(VHUB_IRQ_DEVICE1 << (n))
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* SW reset reg */
7462306a36Sopenharmony_ci#define VHUB_SW_RESET_EP_POOL			(1 << 9)
7562306a36Sopenharmony_ci#define VHUB_SW_RESET_DMA_CONTROLLER		(1 << 8)
7662306a36Sopenharmony_ci#define VHUB_SW_RESET_DEVICE5			(1 << 5)
7762306a36Sopenharmony_ci#define VHUB_SW_RESET_DEVICE4			(1 << 4)
7862306a36Sopenharmony_ci#define VHUB_SW_RESET_DEVICE3			(1 << 3)
7962306a36Sopenharmony_ci#define VHUB_SW_RESET_DEVICE2			(1 << 2)
8062306a36Sopenharmony_ci#define VHUB_SW_RESET_DEVICE1			(1 << 1)
8162306a36Sopenharmony_ci#define VHUB_SW_RESET_ROOT_HUB			(1 << 0)
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/* EP ACK/NACK IRQ masks */
8462306a36Sopenharmony_ci#define VHUB_EP_IRQ(n)				(1 << (n))
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/* USB status reg */
8762306a36Sopenharmony_ci#define VHUB_USBSTS_HISPEED			(1 << 27)
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/* EP toggle */
9062306a36Sopenharmony_ci#define VHUB_EP_TOGGLE_VALUE			(1 << 8)
9162306a36Sopenharmony_ci#define VHUB_EP_TOGGLE_SET_EPNUM(x)		((x) & 0x1f)
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/* HUB EP0 control */
9462306a36Sopenharmony_ci#define VHUB_EP0_CTRL_STALL			(1 << 0)
9562306a36Sopenharmony_ci#define VHUB_EP0_TX_BUFF_RDY			(1 << 1)
9662306a36Sopenharmony_ci#define VHUB_EP0_RX_BUFF_RDY			(1 << 2)
9762306a36Sopenharmony_ci#define VHUB_EP0_RX_LEN(x)			(((x) >> 16) & 0x7f)
9862306a36Sopenharmony_ci#define VHUB_EP0_SET_TX_LEN(x)			(((x) & 0x7f) << 8)
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/* HUB EP1 control */
10162306a36Sopenharmony_ci#define VHUB_EP1_CTRL_RESET_TOGGLE		(1 << 2)
10262306a36Sopenharmony_ci#define VHUB_EP1_CTRL_STALL			(1 << 1)
10362306a36Sopenharmony_ci#define VHUB_EP1_CTRL_ENABLE			(1 << 0)
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/***********************************
10662306a36Sopenharmony_ci *                                 *
10762306a36Sopenharmony_ci * per-device register definitions *
10862306a36Sopenharmony_ci *                                 *
10962306a36Sopenharmony_ci ***********************************/
11062306a36Sopenharmony_ci#define AST_VHUB_DEV_EN_CTRL		0x00
11162306a36Sopenharmony_ci#define AST_VHUB_DEV_ISR		0x04
11262306a36Sopenharmony_ci#define AST_VHUB_DEV_EP0_CTRL		0x08
11362306a36Sopenharmony_ci#define AST_VHUB_DEV_EP0_DATA		0x0c
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/* Device enable control */
11662306a36Sopenharmony_ci#define VHUB_DEV_EN_SET_ADDR(x)			((x) << 8)
11762306a36Sopenharmony_ci#define VHUB_DEV_EN_ADDR_MASK			((0xff) << 8)
11862306a36Sopenharmony_ci#define VHUB_DEV_EN_EP0_NAK_IRQEN		(1 << 6)
11962306a36Sopenharmony_ci#define VHUB_DEV_EN_EP0_IN_ACK_IRQEN		(1 << 5)
12062306a36Sopenharmony_ci#define VHUB_DEV_EN_EP0_OUT_NAK_IRQEN		(1 << 4)
12162306a36Sopenharmony_ci#define VHUB_DEV_EN_EP0_OUT_ACK_IRQEN		(1 << 3)
12262306a36Sopenharmony_ci#define VHUB_DEV_EN_EP0_SETUP_IRQEN		(1 << 2)
12362306a36Sopenharmony_ci#define VHUB_DEV_EN_SPEED_SEL_HIGH		(1 << 1)
12462306a36Sopenharmony_ci#define VHUB_DEV_EN_ENABLE_PORT			(1 << 0)
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/* Interrupt status */
12762306a36Sopenharmony_ci#define VHUV_DEV_IRQ_EP0_IN_DATA_NACK		(1 << 4)
12862306a36Sopenharmony_ci#define VHUV_DEV_IRQ_EP0_IN_ACK_STALL		(1 << 3)
12962306a36Sopenharmony_ci#define VHUV_DEV_IRQ_EP0_OUT_DATA_NACK		(1 << 2)
13062306a36Sopenharmony_ci#define VHUV_DEV_IRQ_EP0_OUT_ACK_STALL		(1 << 1)
13162306a36Sopenharmony_ci#define VHUV_DEV_IRQ_EP0_SETUP			(1 << 0)
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/* Control bits.
13462306a36Sopenharmony_ci *
13562306a36Sopenharmony_ci * Note: The driver relies on the bulk of those bits
13662306a36Sopenharmony_ci *       matching corresponding vHub EP0 control bits
13762306a36Sopenharmony_ci */
13862306a36Sopenharmony_ci#define VHUB_DEV_EP0_CTRL_STALL			VHUB_EP0_CTRL_STALL
13962306a36Sopenharmony_ci#define VHUB_DEV_EP0_TX_BUFF_RDY		VHUB_EP0_TX_BUFF_RDY
14062306a36Sopenharmony_ci#define VHUB_DEV_EP0_RX_BUFF_RDY		VHUB_EP0_RX_BUFF_RDY
14162306a36Sopenharmony_ci#define VHUB_DEV_EP0_RX_LEN(x)			VHUB_EP0_RX_LEN(x)
14262306a36Sopenharmony_ci#define VHUB_DEV_EP0_SET_TX_LEN(x)		VHUB_EP0_SET_TX_LEN(x)
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/*************************************
14562306a36Sopenharmony_ci *                                   *
14662306a36Sopenharmony_ci * per-endpoint register definitions *
14762306a36Sopenharmony_ci *                                   *
14862306a36Sopenharmony_ci *************************************/
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci#define AST_VHUB_EP_CONFIG		0x00
15162306a36Sopenharmony_ci#define AST_VHUB_EP_DMA_CTLSTAT		0x04
15262306a36Sopenharmony_ci#define AST_VHUB_EP_DESC_BASE		0x08
15362306a36Sopenharmony_ci#define AST_VHUB_EP_DESC_STATUS		0x0C
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/* EP config reg */
15662306a36Sopenharmony_ci#define VHUB_EP_CFG_SET_MAX_PKT(x)	(((x) & 0x3ff) << 16)
15762306a36Sopenharmony_ci#define VHUB_EP_CFG_AUTO_DATA_DISABLE	(1 << 13)
15862306a36Sopenharmony_ci#define VHUB_EP_CFG_STALL_CTRL		(1 << 12)
15962306a36Sopenharmony_ci#define VHUB_EP_CFG_SET_EP_NUM(x)	(((x) & 0xf) << 8)
16062306a36Sopenharmony_ci#define VHUB_EP_CFG_SET_TYPE(x)		((x) << 5)
16162306a36Sopenharmony_ci#define   EP_TYPE_OFF			0
16262306a36Sopenharmony_ci#define   EP_TYPE_BULK			1
16362306a36Sopenharmony_ci#define   EP_TYPE_INT			2
16462306a36Sopenharmony_ci#define   EP_TYPE_ISO			3
16562306a36Sopenharmony_ci#define VHUB_EP_CFG_DIR_OUT		(1 << 4)
16662306a36Sopenharmony_ci#define VHUB_EP_CFG_SET_DEV(x)		((x) << 1)
16762306a36Sopenharmony_ci#define VHUB_EP_CFG_ENABLE		(1 << 0)
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci/* EP DMA control */
17062306a36Sopenharmony_ci#define VHUB_EP_DMA_PROC_STATUS(x)	(((x) >> 4) & 0xf)
17162306a36Sopenharmony_ci#define   EP_DMA_PROC_RX_IDLE		0
17262306a36Sopenharmony_ci#define   EP_DMA_PROC_TX_IDLE		8
17362306a36Sopenharmony_ci#define VHUB_EP_DMA_IN_LONG_MODE	(1 << 3)
17462306a36Sopenharmony_ci#define VHUB_EP_DMA_OUT_CONTIG_MODE	(1 << 3)
17562306a36Sopenharmony_ci#define VHUB_EP_DMA_CTRL_RESET		(1 << 2)
17662306a36Sopenharmony_ci#define VHUB_EP_DMA_SINGLE_STAGE	(1 << 1)
17762306a36Sopenharmony_ci#define VHUB_EP_DMA_DESC_MODE		(1 << 0)
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci/* EP DMA status */
18062306a36Sopenharmony_ci#define VHUB_EP_DMA_SET_TX_SIZE(x)	((x) << 16)
18162306a36Sopenharmony_ci#define VHUB_EP_DMA_TX_SIZE(x)		(((x) >> 16) & 0x7ff)
18262306a36Sopenharmony_ci#define VHUB_EP_DMA_RPTR(x)		(((x) >> 8) & 0xff)
18362306a36Sopenharmony_ci#define VHUB_EP_DMA_SET_RPTR(x)		(((x) & 0xff) << 8)
18462306a36Sopenharmony_ci#define VHUB_EP_DMA_SET_CPU_WPTR(x)	(x)
18562306a36Sopenharmony_ci#define VHUB_EP_DMA_SINGLE_KICK		(1 << 0) /* WPTR = 1 for single mode */
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci/*******************************
18862306a36Sopenharmony_ci *                             *
18962306a36Sopenharmony_ci * DMA descriptors definitions *
19062306a36Sopenharmony_ci *                             *
19162306a36Sopenharmony_ci *******************************/
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci/* Desc W1 IN */
19462306a36Sopenharmony_ci#define VHUB_DSC1_IN_INTERRUPT		(1 << 31)
19562306a36Sopenharmony_ci#define VHUB_DSC1_IN_SPID_DATA0		(0 << 14)
19662306a36Sopenharmony_ci#define VHUB_DSC1_IN_SPID_DATA2		(1 << 14)
19762306a36Sopenharmony_ci#define VHUB_DSC1_IN_SPID_DATA1		(2 << 14)
19862306a36Sopenharmony_ci#define VHUB_DSC1_IN_SPID_MDATA		(3 << 14)
19962306a36Sopenharmony_ci#define VHUB_DSC1_IN_SET_LEN(x)		((x) & 0xfff)
20062306a36Sopenharmony_ci#define VHUB_DSC1_IN_LEN(x)		((x) & 0xfff)
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci/****************************************
20362306a36Sopenharmony_ci *                                      *
20462306a36Sopenharmony_ci * Data structures and misc definitions *
20562306a36Sopenharmony_ci *                                      *
20662306a36Sopenharmony_ci ****************************************/
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci/*
20962306a36Sopenharmony_ci * AST_VHUB_NUM_GEN_EPs and AST_VHUB_NUM_PORTS are kept to avoid breaking
21062306a36Sopenharmony_ci * existing AST2400/AST2500 platforms. AST2600 and future vhub revisions
21162306a36Sopenharmony_ci * should define number of downstream ports and endpoints in device tree.
21262306a36Sopenharmony_ci */
21362306a36Sopenharmony_ci#define AST_VHUB_NUM_GEN_EPs	15	/* Generic non-0 EPs */
21462306a36Sopenharmony_ci#define AST_VHUB_NUM_PORTS	5	/* vHub ports */
21562306a36Sopenharmony_ci#define AST_VHUB_EP0_MAX_PACKET	64	/* EP0's max packet size */
21662306a36Sopenharmony_ci#define AST_VHUB_EPn_MAX_PACKET	1024	/* Generic EPs max packet size */
21762306a36Sopenharmony_ci#define AST_VHUB_DESCS_COUNT	256	/* Use 256 descriptor mode (valid
21862306a36Sopenharmony_ci					 * values are 256 and 32)
21962306a36Sopenharmony_ci					 */
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistruct ast_vhub;
22262306a36Sopenharmony_cistruct ast_vhub_dev;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci/*
22562306a36Sopenharmony_ci * DMA descriptor (generic EPs only, currently only used
22662306a36Sopenharmony_ci * for IN endpoints
22762306a36Sopenharmony_ci */
22862306a36Sopenharmony_cistruct ast_vhub_desc {
22962306a36Sopenharmony_ci	__le32	w0;
23062306a36Sopenharmony_ci	__le32	w1;
23162306a36Sopenharmony_ci};
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci/* A transfer request, either core-originated or internal */
23462306a36Sopenharmony_cistruct ast_vhub_req {
23562306a36Sopenharmony_ci	struct usb_request	req;
23662306a36Sopenharmony_ci	struct list_head	queue;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	/* Actual count written to descriptors (desc mode only) */
23962306a36Sopenharmony_ci	unsigned int		act_count;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	/*
24262306a36Sopenharmony_ci	 * Desc number of the final packet or -1. For non-desc
24362306a36Sopenharmony_ci	 * mode (or ep0), any >= 0 value means "last packet"
24462306a36Sopenharmony_ci	 */
24562306a36Sopenharmony_ci	int			last_desc;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	/* Request active (pending DMAs) */
24862306a36Sopenharmony_ci	bool			active  : 1;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	/* Internal request (don't call back core) */
25162306a36Sopenharmony_ci	bool			internal : 1;
25262306a36Sopenharmony_ci};
25362306a36Sopenharmony_ci#define to_ast_req(__ureq) container_of(__ureq, struct ast_vhub_req, req)
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/* Current state of an EP0 */
25662306a36Sopenharmony_cienum ep0_state {
25762306a36Sopenharmony_ci	ep0_state_token,
25862306a36Sopenharmony_ci	ep0_state_data,
25962306a36Sopenharmony_ci	ep0_state_status,
26062306a36Sopenharmony_ci	ep0_state_stall,
26162306a36Sopenharmony_ci};
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci/*
26462306a36Sopenharmony_ci * An endpoint, either generic, ep0, actual gadget EP
26562306a36Sopenharmony_ci * or internal use vhub EP0. vhub EP1 doesn't have an
26662306a36Sopenharmony_ci * associated structure as it's mostly HW managed.
26762306a36Sopenharmony_ci */
26862306a36Sopenharmony_cistruct ast_vhub_ep {
26962306a36Sopenharmony_ci	struct usb_ep		ep;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* Request queue */
27262306a36Sopenharmony_ci	struct list_head	queue;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	/* EP index in the device, 0 means this is an EP0 */
27562306a36Sopenharmony_ci	unsigned int		d_idx;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	/* Dev pointer or NULL for vHub EP0 */
27862306a36Sopenharmony_ci	struct ast_vhub_dev	*dev;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/* vHub itself */
28162306a36Sopenharmony_ci	struct ast_vhub		*vhub;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	/*
28462306a36Sopenharmony_ci	 * DMA buffer for EP0, fallback DMA buffer for misaligned
28562306a36Sopenharmony_ci	 * OUT transfers for generic EPs
28662306a36Sopenharmony_ci	 */
28762306a36Sopenharmony_ci	void			*buf;
28862306a36Sopenharmony_ci	dma_addr_t		buf_dma;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	/* The rest depends on the EP type */
29162306a36Sopenharmony_ci	union {
29262306a36Sopenharmony_ci		/* EP0 (either device or vhub) */
29362306a36Sopenharmony_ci		struct {
29462306a36Sopenharmony_ci			/*
29562306a36Sopenharmony_ci			 * EP0 registers are "similar" for
29662306a36Sopenharmony_ci			 * vHub and devices but located in
29762306a36Sopenharmony_ci			 * different places.
29862306a36Sopenharmony_ci			 */
29962306a36Sopenharmony_ci			void __iomem		*ctlstat;
30062306a36Sopenharmony_ci			void __iomem		*setup;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci			/* Current state & direction */
30362306a36Sopenharmony_ci			enum ep0_state		state;
30462306a36Sopenharmony_ci			bool			dir_in;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci			/* Internal use request */
30762306a36Sopenharmony_ci			struct ast_vhub_req	req;
30862306a36Sopenharmony_ci		} ep0;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci		/* Generic endpoint (aka EPn) */
31162306a36Sopenharmony_ci		struct {
31262306a36Sopenharmony_ci			/* Registers */
31362306a36Sopenharmony_ci			void __iomem   		*regs;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci			/* Index in global pool (zero-based) */
31662306a36Sopenharmony_ci			unsigned int		g_idx;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci			/* DMA Descriptors */
31962306a36Sopenharmony_ci			struct ast_vhub_desc	*descs;
32062306a36Sopenharmony_ci			dma_addr_t		descs_dma;
32162306a36Sopenharmony_ci			unsigned int		d_next;
32262306a36Sopenharmony_ci			unsigned int		d_last;
32362306a36Sopenharmony_ci			unsigned int		dma_conf;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci			/* Max chunk size for IN EPs */
32662306a36Sopenharmony_ci			unsigned int		chunk_max;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci			/* State flags */
32962306a36Sopenharmony_ci			bool			is_in :  1;
33062306a36Sopenharmony_ci			bool			is_iso : 1;
33162306a36Sopenharmony_ci			bool			stalled : 1;
33262306a36Sopenharmony_ci			bool			wedged : 1;
33362306a36Sopenharmony_ci			bool			enabled : 1;
33462306a36Sopenharmony_ci			bool			desc_mode : 1;
33562306a36Sopenharmony_ci		} epn;
33662306a36Sopenharmony_ci	};
33762306a36Sopenharmony_ci};
33862306a36Sopenharmony_ci#define to_ast_ep(__uep) container_of(__uep, struct ast_vhub_ep, ep)
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci/* A device attached to a vHub port */
34162306a36Sopenharmony_cistruct ast_vhub_dev {
34262306a36Sopenharmony_ci	struct ast_vhub			*vhub;
34362306a36Sopenharmony_ci	void __iomem			*regs;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* Device index (zero-based) and name string */
34662306a36Sopenharmony_ci	unsigned int			index;
34762306a36Sopenharmony_ci	const char			*name;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	/* sysfs enclosure for the gadget gunk */
35062306a36Sopenharmony_ci	struct device			*port_dev;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	/* Link to gadget core */
35362306a36Sopenharmony_ci	struct usb_gadget		gadget;
35462306a36Sopenharmony_ci	struct usb_gadget_driver	*driver;
35562306a36Sopenharmony_ci	bool				registered : 1;
35662306a36Sopenharmony_ci	bool				wakeup_en : 1;
35762306a36Sopenharmony_ci	bool				enabled : 1;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	/* Endpoint structures */
36062306a36Sopenharmony_ci	struct ast_vhub_ep		ep0;
36162306a36Sopenharmony_ci	struct ast_vhub_ep		**epns;
36262306a36Sopenharmony_ci	u32				max_epns;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci};
36562306a36Sopenharmony_ci#define to_ast_dev(__g) container_of(__g, struct ast_vhub_dev, gadget)
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci/* Per vhub port stateinfo structure */
36862306a36Sopenharmony_cistruct ast_vhub_port {
36962306a36Sopenharmony_ci	/* Port status & status change registers */
37062306a36Sopenharmony_ci	u16			status;
37162306a36Sopenharmony_ci	u16			change;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/* Associated device slot */
37462306a36Sopenharmony_ci	struct ast_vhub_dev	dev;
37562306a36Sopenharmony_ci};
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistruct ast_vhub_full_cdesc {
37862306a36Sopenharmony_ci	struct usb_config_descriptor	cfg;
37962306a36Sopenharmony_ci	struct usb_interface_descriptor intf;
38062306a36Sopenharmony_ci	struct usb_endpoint_descriptor	ep;
38162306a36Sopenharmony_ci} __packed;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci/* Global vhub structure */
38462306a36Sopenharmony_cistruct ast_vhub {
38562306a36Sopenharmony_ci	struct platform_device		*pdev;
38662306a36Sopenharmony_ci	void __iomem			*regs;
38762306a36Sopenharmony_ci	int				irq;
38862306a36Sopenharmony_ci	spinlock_t			lock;
38962306a36Sopenharmony_ci	struct work_struct		wake_work;
39062306a36Sopenharmony_ci	struct clk			*clk;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	/* EP0 DMA buffers allocated in one chunk */
39362306a36Sopenharmony_ci	void				*ep0_bufs;
39462306a36Sopenharmony_ci	dma_addr_t			ep0_bufs_dma;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* EP0 of the vhub itself */
39762306a36Sopenharmony_ci	struct ast_vhub_ep		ep0;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* State of vhub ep1 */
40062306a36Sopenharmony_ci	bool				ep1_stalled : 1;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	/* Per-port info */
40362306a36Sopenharmony_ci	struct ast_vhub_port		*ports;
40462306a36Sopenharmony_ci	u32				max_ports;
40562306a36Sopenharmony_ci	u32				port_irq_mask;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	/* Generic EP data structures */
40862306a36Sopenharmony_ci	struct ast_vhub_ep		*epns;
40962306a36Sopenharmony_ci	u32				max_epns;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	/* Upstream bus is suspended ? */
41262306a36Sopenharmony_ci	bool				suspended : 1;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/* Hub itself can signal remote wakeup */
41562306a36Sopenharmony_ci	bool				wakeup_en : 1;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	/* Force full speed only */
41862306a36Sopenharmony_ci	bool				force_usb1 : 1;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* Upstream bus speed captured at bus reset */
42162306a36Sopenharmony_ci	unsigned int			speed;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	/* Standard USB Descriptors of the vhub. */
42462306a36Sopenharmony_ci	struct usb_device_descriptor	vhub_dev_desc;
42562306a36Sopenharmony_ci	struct ast_vhub_full_cdesc	vhub_conf_desc;
42662306a36Sopenharmony_ci	struct usb_hub_descriptor	vhub_hub_desc;
42762306a36Sopenharmony_ci	struct list_head		vhub_str_desc;
42862306a36Sopenharmony_ci	struct usb_qualifier_descriptor	vhub_qual_desc;
42962306a36Sopenharmony_ci};
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci/* Standard request handlers result codes */
43262306a36Sopenharmony_cienum std_req_rc {
43362306a36Sopenharmony_ci	std_req_stall = -1,	/* Stall requested */
43462306a36Sopenharmony_ci	std_req_complete = 0,	/* Request completed with no data */
43562306a36Sopenharmony_ci	std_req_data = 1,	/* Request completed with data */
43662306a36Sopenharmony_ci	std_req_driver = 2,	/* Pass to driver pls */
43762306a36Sopenharmony_ci};
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci#ifdef CONFIG_USB_GADGET_VERBOSE
44062306a36Sopenharmony_ci#define UDCVDBG(u, fmt...)	dev_dbg(&(u)->pdev->dev, fmt)
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci#define EPVDBG(ep, fmt, ...)	do {			\
44362306a36Sopenharmony_ci	dev_dbg(&(ep)->vhub->pdev->dev,			\
44462306a36Sopenharmony_ci		"%s:EP%d " fmt,				\
44562306a36Sopenharmony_ci		(ep)->dev ? (ep)->dev->name : "hub",	\
44662306a36Sopenharmony_ci		(ep)->d_idx, ##__VA_ARGS__);		\
44762306a36Sopenharmony_ci	} while(0)
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci#define DVDBG(d, fmt, ...)	do {			\
45062306a36Sopenharmony_ci	dev_dbg(&(d)->vhub->pdev->dev,			\
45162306a36Sopenharmony_ci		"%s " fmt, (d)->name,			\
45262306a36Sopenharmony_ci		##__VA_ARGS__);				\
45362306a36Sopenharmony_ci	} while(0)
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci#else
45662306a36Sopenharmony_ci#define UDCVDBG(u, fmt...)	do { } while(0)
45762306a36Sopenharmony_ci#define EPVDBG(ep, fmt, ...)	do { } while(0)
45862306a36Sopenharmony_ci#define DVDBG(d, fmt, ...)	do { } while(0)
45962306a36Sopenharmony_ci#endif
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci#ifdef CONFIG_USB_GADGET_DEBUG
46262306a36Sopenharmony_ci#define UDCDBG(u, fmt...)	dev_dbg(&(u)->pdev->dev, fmt)
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci#define EPDBG(ep, fmt, ...)	do {			\
46562306a36Sopenharmony_ci	dev_dbg(&(ep)->vhub->pdev->dev,			\
46662306a36Sopenharmony_ci		"%s:EP%d " fmt,				\
46762306a36Sopenharmony_ci		(ep)->dev ? (ep)->dev->name : "hub",	\
46862306a36Sopenharmony_ci		(ep)->d_idx, ##__VA_ARGS__);		\
46962306a36Sopenharmony_ci	} while(0)
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci#define DDBG(d, fmt, ...)	do {			\
47262306a36Sopenharmony_ci	dev_dbg(&(d)->vhub->pdev->dev,			\
47362306a36Sopenharmony_ci		"%s " fmt, (d)->name,			\
47462306a36Sopenharmony_ci		##__VA_ARGS__);				\
47562306a36Sopenharmony_ci	} while(0)
47662306a36Sopenharmony_ci#else
47762306a36Sopenharmony_ci#define UDCDBG(u, fmt...)	do { } while(0)
47862306a36Sopenharmony_ci#define EPDBG(ep, fmt, ...)	do { } while(0)
47962306a36Sopenharmony_ci#define DDBG(d, fmt, ...)	do { } while(0)
48062306a36Sopenharmony_ci#endif
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic inline void vhub_dma_workaround(void *addr)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	/*
48562306a36Sopenharmony_ci	 * This works around a confirmed HW issue with the Aspeed chip.
48662306a36Sopenharmony_ci	 *
48762306a36Sopenharmony_ci	 * The core uses a different bus to memory than the AHB going to
48862306a36Sopenharmony_ci	 * the USB device controller. Due to the latter having a higher
48962306a36Sopenharmony_ci	 * priority than the core for arbitration on that bus, it's
49062306a36Sopenharmony_ci	 * possible for an MMIO to the device, followed by a DMA by the
49162306a36Sopenharmony_ci	 * device from memory to all be performed and services before
49262306a36Sopenharmony_ci	 * a previous store to memory gets completed.
49362306a36Sopenharmony_ci	 *
49462306a36Sopenharmony_ci	 * This the following scenario can happen:
49562306a36Sopenharmony_ci	 *
49662306a36Sopenharmony_ci	 *    - Driver writes to a DMA descriptor (Mbus)
49762306a36Sopenharmony_ci	 *    - Driver writes to the MMIO register to start the DMA (AHB)
49862306a36Sopenharmony_ci	 *    - The gadget sees the second write and sends a read of the
49962306a36Sopenharmony_ci	 *      descriptor to the memory controller (Mbus)
50062306a36Sopenharmony_ci	 *    - The gadget hits memory before the descriptor write
50162306a36Sopenharmony_ci	 *      causing it to read an obsolete value.
50262306a36Sopenharmony_ci	 *
50362306a36Sopenharmony_ci	 * Thankfully the problem is limited to the USB gadget device, other
50462306a36Sopenharmony_ci	 * masters in the SoC all have a lower priority than the core, thus
50562306a36Sopenharmony_ci	 * ensuring that the store by the core arrives first.
50662306a36Sopenharmony_ci	 *
50762306a36Sopenharmony_ci	 * The workaround consists of using a dummy read of the memory before
50862306a36Sopenharmony_ci	 * doing the MMIO writes. This will ensure that the previous writes
50962306a36Sopenharmony_ci	 * have been "pushed out".
51062306a36Sopenharmony_ci	 */
51162306a36Sopenharmony_ci	mb();
51262306a36Sopenharmony_ci	(void)__raw_readl((void __iomem *)addr);
51362306a36Sopenharmony_ci}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci/* core.c */
51662306a36Sopenharmony_civoid ast_vhub_done(struct ast_vhub_ep *ep, struct ast_vhub_req *req,
51762306a36Sopenharmony_ci		   int status);
51862306a36Sopenharmony_civoid ast_vhub_nuke(struct ast_vhub_ep *ep, int status);
51962306a36Sopenharmony_cistruct usb_request *ast_vhub_alloc_request(struct usb_ep *u_ep,
52062306a36Sopenharmony_ci					   gfp_t gfp_flags);
52162306a36Sopenharmony_civoid ast_vhub_free_request(struct usb_ep *u_ep, struct usb_request *u_req);
52262306a36Sopenharmony_civoid ast_vhub_init_hw(struct ast_vhub *vhub);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci/* ep0.c */
52562306a36Sopenharmony_civoid ast_vhub_ep0_handle_ack(struct ast_vhub_ep *ep, bool in_ack);
52662306a36Sopenharmony_civoid ast_vhub_ep0_handle_setup(struct ast_vhub_ep *ep);
52762306a36Sopenharmony_civoid ast_vhub_reset_ep0(struct ast_vhub_dev *dev);
52862306a36Sopenharmony_civoid ast_vhub_init_ep0(struct ast_vhub *vhub, struct ast_vhub_ep *ep,
52962306a36Sopenharmony_ci		       struct ast_vhub_dev *dev);
53062306a36Sopenharmony_ciint ast_vhub_reply(struct ast_vhub_ep *ep, char *ptr, int len);
53162306a36Sopenharmony_ciint __ast_vhub_simple_reply(struct ast_vhub_ep *ep, int len, ...);
53262306a36Sopenharmony_ci#define ast_vhub_simple_reply(udc, ...)					       \
53362306a36Sopenharmony_ci	__ast_vhub_simple_reply((udc),					       \
53462306a36Sopenharmony_ci			       sizeof((u8[]) { __VA_ARGS__ })/sizeof(u8),      \
53562306a36Sopenharmony_ci			       __VA_ARGS__)
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci/* hub.c */
53862306a36Sopenharmony_ciint ast_vhub_init_hub(struct ast_vhub *vhub);
53962306a36Sopenharmony_cienum std_req_rc ast_vhub_std_hub_request(struct ast_vhub_ep *ep,
54062306a36Sopenharmony_ci					 struct usb_ctrlrequest *crq);
54162306a36Sopenharmony_cienum std_req_rc ast_vhub_class_hub_request(struct ast_vhub_ep *ep,
54262306a36Sopenharmony_ci					   struct usb_ctrlrequest *crq);
54362306a36Sopenharmony_civoid ast_vhub_device_connect(struct ast_vhub *vhub, unsigned int port,
54462306a36Sopenharmony_ci			     bool on);
54562306a36Sopenharmony_civoid ast_vhub_hub_suspend(struct ast_vhub *vhub);
54662306a36Sopenharmony_civoid ast_vhub_hub_resume(struct ast_vhub *vhub);
54762306a36Sopenharmony_civoid ast_vhub_hub_reset(struct ast_vhub *vhub);
54862306a36Sopenharmony_civoid ast_vhub_hub_wake_all(struct ast_vhub *vhub);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci/* dev.c */
55162306a36Sopenharmony_ciint ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx);
55262306a36Sopenharmony_civoid ast_vhub_del_dev(struct ast_vhub_dev *d);
55362306a36Sopenharmony_civoid ast_vhub_dev_irq(struct ast_vhub_dev *d);
55462306a36Sopenharmony_ciint ast_vhub_std_dev_request(struct ast_vhub_ep *ep,
55562306a36Sopenharmony_ci			     struct usb_ctrlrequest *crq);
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci/* epn.c */
55862306a36Sopenharmony_civoid ast_vhub_epn_ack_irq(struct ast_vhub_ep *ep);
55962306a36Sopenharmony_civoid ast_vhub_update_epn_stall(struct ast_vhub_ep *ep);
56062306a36Sopenharmony_cistruct ast_vhub_ep *ast_vhub_alloc_epn(struct ast_vhub_dev *d, u8 addr);
56162306a36Sopenharmony_civoid ast_vhub_dev_suspend(struct ast_vhub_dev *d);
56262306a36Sopenharmony_civoid ast_vhub_dev_resume(struct ast_vhub_dev *d);
56362306a36Sopenharmony_civoid ast_vhub_dev_reset(struct ast_vhub_dev *d);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci#endif /* __ASPEED_VHUB_H */
566