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