usb: gadget: mv: Add USB 3.0 device driver for Marvell PXA2128 chip.
It supports Marvell USB 3.0 device controller for PXA2128 chip. Signed-off-by: Yu Xu <yuxu@marvell.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
Родитель
5ad1d31609
Коммит
3d4eb9dfa3
|
@ -321,6 +321,15 @@ config USB_MV_UDC
|
|||
USB2.0 OTG controller, which can be configured as high speed or
|
||||
full speed USB peripheral.
|
||||
|
||||
config USB_MV_U3D
|
||||
tristate "MARVELL PXA2128 USB 3.0 controller"
|
||||
depends on CPU_MMP3
|
||||
select USB_GADGET_DUALSPEED
|
||||
select USB_GADGET_SUPERSPEED
|
||||
help
|
||||
MARVELL PXA2128 Processor series include a super speed USB3.0 device
|
||||
controller, which support super speed USB peripheral.
|
||||
|
||||
#
|
||||
# Controllers available in both integrated and discrete versions
|
||||
#
|
||||
|
|
|
@ -29,6 +29,7 @@ obj-$(CONFIG_USB_EG20T) += pch_udc.o
|
|||
obj-$(CONFIG_USB_MV_UDC) += mv_udc.o
|
||||
mv_udc-y := mv_udc_core.o
|
||||
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
|
||||
obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o
|
||||
|
||||
#
|
||||
# USB gadget drivers
|
||||
|
|
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Marvell International Ltd. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __MV_U3D_H
|
||||
#define __MV_U3D_H
|
||||
|
||||
#define MV_U3D_EP_CONTEXT_ALIGNMENT 32
|
||||
#define MV_U3D_TRB_ALIGNMENT 16
|
||||
#define MV_U3D_DMA_BOUNDARY 4096
|
||||
#define MV_U3D_EP0_MAX_PKT_SIZE 512
|
||||
|
||||
/* ep0 transfer state */
|
||||
#define MV_U3D_WAIT_FOR_SETUP 0
|
||||
#define MV_U3D_DATA_STATE_XMIT 1
|
||||
#define MV_U3D_DATA_STATE_NEED_ZLP 2
|
||||
#define MV_U3D_WAIT_FOR_OUT_STATUS 3
|
||||
#define MV_U3D_DATA_STATE_RECV 4
|
||||
#define MV_U3D_STATUS_STAGE 5
|
||||
|
||||
#define MV_U3D_EP_MAX_LENGTH_TRANSFER 0x10000
|
||||
|
||||
/* USB3 Interrupt Status */
|
||||
#define MV_U3D_USBINT_SETUP 0x00000001
|
||||
#define MV_U3D_USBINT_RX_COMPLETE 0x00000002
|
||||
#define MV_U3D_USBINT_TX_COMPLETE 0x00000004
|
||||
#define MV_U3D_USBINT_UNDER_RUN 0x00000008
|
||||
#define MV_U3D_USBINT_RXDESC_ERR 0x00000010
|
||||
#define MV_U3D_USBINT_TXDESC_ERR 0x00000020
|
||||
#define MV_U3D_USBINT_RX_TRB_COMPLETE 0x00000040
|
||||
#define MV_U3D_USBINT_TX_TRB_COMPLETE 0x00000080
|
||||
#define MV_U3D_USBINT_VBUS_VALID 0x00010000
|
||||
#define MV_U3D_USBINT_STORAGE_CMD_FULL 0x00020000
|
||||
#define MV_U3D_USBINT_LINK_CHG 0x01000000
|
||||
|
||||
/* USB3 Interrupt Enable */
|
||||
#define MV_U3D_INTR_ENABLE_SETUP 0x00000001
|
||||
#define MV_U3D_INTR_ENABLE_RX_COMPLETE 0x00000002
|
||||
#define MV_U3D_INTR_ENABLE_TX_COMPLETE 0x00000004
|
||||
#define MV_U3D_INTR_ENABLE_UNDER_RUN 0x00000008
|
||||
#define MV_U3D_INTR_ENABLE_RXDESC_ERR 0x00000010
|
||||
#define MV_U3D_INTR_ENABLE_TXDESC_ERR 0x00000020
|
||||
#define MV_U3D_INTR_ENABLE_RX_TRB_COMPLETE 0x00000040
|
||||
#define MV_U3D_INTR_ENABLE_TX_TRB_COMPLETE 0x00000080
|
||||
#define MV_U3D_INTR_ENABLE_RX_BUFFER_ERR 0x00000100
|
||||
#define MV_U3D_INTR_ENABLE_VBUS_VALID 0x00010000
|
||||
#define MV_U3D_INTR_ENABLE_STORAGE_CMD_FULL 0x00020000
|
||||
#define MV_U3D_INTR_ENABLE_LINK_CHG 0x01000000
|
||||
#define MV_U3D_INTR_ENABLE_PRIME_STATUS 0x02000000
|
||||
|
||||
/* USB3 Link Change */
|
||||
#define MV_U3D_LINK_CHANGE_LINK_UP 0x00000001
|
||||
#define MV_U3D_LINK_CHANGE_SUSPEND 0x00000002
|
||||
#define MV_U3D_LINK_CHANGE_RESUME 0x00000004
|
||||
#define MV_U3D_LINK_CHANGE_WRESET 0x00000008
|
||||
#define MV_U3D_LINK_CHANGE_HRESET 0x00000010
|
||||
#define MV_U3D_LINK_CHANGE_VBUS_INVALID 0x00000020
|
||||
#define MV_U3D_LINK_CHANGE_INACT 0x00000040
|
||||
#define MV_U3D_LINK_CHANGE_DISABLE_AFTER_U0 0x00000080
|
||||
#define MV_U3D_LINK_CHANGE_U1 0x00000100
|
||||
#define MV_U3D_LINK_CHANGE_U2 0x00000200
|
||||
#define MV_U3D_LINK_CHANGE_U3 0x00000400
|
||||
|
||||
/* bridge setting */
|
||||
#define MV_U3D_BRIDGE_SETTING_VBUS_VALID (1 << 16)
|
||||
|
||||
/* Command Register Bit Masks */
|
||||
#define MV_U3D_CMD_RUN_STOP 0x00000001
|
||||
#define MV_U3D_CMD_CTRL_RESET 0x00000002
|
||||
|
||||
/* ep control register */
|
||||
#define MV_U3D_EPXCR_EP_TYPE_CONTROL 0
|
||||
#define MV_U3D_EPXCR_EP_TYPE_ISOC 1
|
||||
#define MV_U3D_EPXCR_EP_TYPE_BULK 2
|
||||
#define MV_U3D_EPXCR_EP_TYPE_INT 3
|
||||
#define MV_U3D_EPXCR_EP_ENABLE_SHIFT 4
|
||||
#define MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT 12
|
||||
#define MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT 16
|
||||
#define MV_U3D_USB_BULK_BURST_OUT 6
|
||||
#define MV_U3D_USB_BULK_BURST_IN 14
|
||||
|
||||
#define MV_U3D_EPXCR_EP_FLUSH (1 << 7)
|
||||
#define MV_U3D_EPXCR_EP_HALT (1 << 1)
|
||||
#define MV_U3D_EPXCR_EP_INIT (1)
|
||||
|
||||
/* TX/RX Status Register */
|
||||
#define MV_U3D_XFERSTATUS_COMPLETE_SHIFT 24
|
||||
#define MV_U3D_COMPLETE_INVALID 0
|
||||
#define MV_U3D_COMPLETE_SUCCESS 1
|
||||
#define MV_U3D_COMPLETE_BUFF_ERR 2
|
||||
#define MV_U3D_COMPLETE_SHORT_PACKET 3
|
||||
#define MV_U3D_COMPLETE_TRB_ERR 5
|
||||
#define MV_U3D_XFERSTATUS_TRB_LENGTH_MASK (0xFFFFFF)
|
||||
|
||||
#define MV_U3D_USB_LINK_BYPASS_VBUS 0x8
|
||||
|
||||
#define MV_U3D_LTSSM_PHY_INIT_DONE 0x80000000
|
||||
#define MV_U3D_LTSSM_NEVER_GO_COMPLIANCE 0x40000000
|
||||
|
||||
#define MV_U3D_USB3_OP_REGS_OFFSET 0x100
|
||||
#define MV_U3D_USB3_PHY_OFFSET 0xB800
|
||||
|
||||
#define DCS_ENABLE 0x1
|
||||
|
||||
/* timeout */
|
||||
#define MV_U3D_RESET_TIMEOUT 10000
|
||||
#define MV_U3D_FLUSH_TIMEOUT 100000
|
||||
#define MV_U3D_OWN_TIMEOUT 10000
|
||||
#define LOOPS_USEC_SHIFT 4
|
||||
#define LOOPS_USEC (1 << LOOPS_USEC_SHIFT)
|
||||
#define LOOPS(timeout) ((timeout) >> LOOPS_USEC_SHIFT)
|
||||
|
||||
/* ep direction */
|
||||
#define MV_U3D_EP_DIR_IN 1
|
||||
#define MV_U3D_EP_DIR_OUT 0
|
||||
#define mv_u3d_ep_dir(ep) (((ep)->ep_num == 0) ? \
|
||||
((ep)->u3d->ep0_dir) : ((ep)->direction))
|
||||
|
||||
/* usb capability registers */
|
||||
struct mv_u3d_cap_regs {
|
||||
u32 rsvd[5];
|
||||
u32 dboff; /* doorbell register offset */
|
||||
u32 rtsoff; /* runtime register offset */
|
||||
u32 vuoff; /* vendor unique register offset */
|
||||
};
|
||||
|
||||
/* operation registers */
|
||||
struct mv_u3d_op_regs {
|
||||
u32 usbcmd; /* Command register */
|
||||
u32 rsvd1[11];
|
||||
u32 dcbaapl; /* Device Context Base Address low register */
|
||||
u32 dcbaaph; /* Device Context Base Address high register */
|
||||
u32 rsvd2[243];
|
||||
u32 portsc; /* port status and control register*/
|
||||
u32 portlinkinfo; /* port link info register*/
|
||||
u32 rsvd3[9917];
|
||||
u32 doorbell; /* doorbell register */
|
||||
};
|
||||
|
||||
/* control enpoint enable registers */
|
||||
struct epxcr {
|
||||
u32 epxoutcr0; /* ep out control 0 register */
|
||||
u32 epxoutcr1; /* ep out control 1 register */
|
||||
u32 epxincr0; /* ep in control 0 register */
|
||||
u32 epxincr1; /* ep in control 1 register */
|
||||
};
|
||||
|
||||
/* transfer status registers */
|
||||
struct xferstatus {
|
||||
u32 curdeqlo; /* current TRB pointer low */
|
||||
u32 curdeqhi; /* current TRB pointer high */
|
||||
u32 statuslo; /* transfer status low */
|
||||
u32 statushi; /* transfer status high */
|
||||
};
|
||||
|
||||
/* vendor unique control registers */
|
||||
struct mv_u3d_vuc_regs {
|
||||
u32 ctrlepenable; /* control endpoint enable register */
|
||||
u32 setuplock; /* setup lock register */
|
||||
u32 endcomplete; /* endpoint transfer complete register */
|
||||
u32 intrcause; /* interrupt cause register */
|
||||
u32 intrenable; /* interrupt enable register */
|
||||
u32 trbcomplete; /* TRB complete register */
|
||||
u32 linkchange; /* link change register */
|
||||
u32 rsvd1[5];
|
||||
u32 trbunderrun; /* TRB underrun register */
|
||||
u32 rsvd2[43];
|
||||
u32 bridgesetting; /* bridge setting register */
|
||||
u32 rsvd3[7];
|
||||
struct xferstatus txst[16]; /* TX status register */
|
||||
struct xferstatus rxst[16]; /* RX status register */
|
||||
u32 ltssm; /* LTSSM control register */
|
||||
u32 pipe; /* PIPE control register */
|
||||
u32 linkcr0; /* link control 0 register */
|
||||
u32 linkcr1; /* link control 1 register */
|
||||
u32 rsvd6[60];
|
||||
u32 mib0; /* MIB0 counter register */
|
||||
u32 usblink; /* usb link control register */
|
||||
u32 ltssmstate; /* LTSSM state register */
|
||||
u32 linkerrorcause; /* link error cause register */
|
||||
u32 rsvd7[60];
|
||||
u32 devaddrtiebrkr; /* device address and tie breaker */
|
||||
u32 itpinfo0; /* ITP info 0 register */
|
||||
u32 itpinfo1; /* ITP info 1 register */
|
||||
u32 rsvd8[61];
|
||||
struct epxcr epcr[16]; /* ep control register */
|
||||
u32 rsvd9[64];
|
||||
u32 phyaddr; /* PHY address register */
|
||||
u32 phydata; /* PHY data register */
|
||||
};
|
||||
|
||||
/* Endpoint context structure */
|
||||
struct mv_u3d_ep_context {
|
||||
u32 rsvd0;
|
||||
u32 rsvd1;
|
||||
u32 trb_addr_lo; /* TRB address low 32 bit */
|
||||
u32 trb_addr_hi; /* TRB address high 32 bit */
|
||||
u32 rsvd2;
|
||||
u32 rsvd3;
|
||||
struct usb_ctrlrequest setup_buffer; /* setup data buffer */
|
||||
};
|
||||
|
||||
/* TRB control data structure */
|
||||
struct mv_u3d_trb_ctrl {
|
||||
u32 own:1; /* owner of TRB */
|
||||
u32 rsvd1:3;
|
||||
u32 chain:1; /* associate this TRB with the
|
||||
next TRB on the Ring */
|
||||
u32 ioc:1; /* interrupt on complete */
|
||||
u32 rsvd2:4;
|
||||
u32 type:6; /* TRB type */
|
||||
#define TYPE_NORMAL 1
|
||||
#define TYPE_DATA 3
|
||||
#define TYPE_LINK 6
|
||||
u32 dir:1; /* Working at data stage of control endpoint
|
||||
operation. 0 is OUT and 1 is IN. */
|
||||
u32 rsvd3:15;
|
||||
};
|
||||
|
||||
/* TRB data structure
|
||||
* For multiple TRB, all the TRBs' physical address should be continuous.
|
||||
*/
|
||||
struct mv_u3d_trb_hw {
|
||||
u32 buf_addr_lo; /* data buffer address low 32 bit */
|
||||
u32 buf_addr_hi; /* data buffer address high 32 bit */
|
||||
u32 trb_len; /* transfer length */
|
||||
struct mv_u3d_trb_ctrl ctrl; /* TRB control data */
|
||||
};
|
||||
|
||||
/* TRB structure */
|
||||
struct mv_u3d_trb {
|
||||
struct mv_u3d_trb_hw *trb_hw; /* point to the trb_hw structure */
|
||||
dma_addr_t trb_dma; /* dma address for this trb_hw */
|
||||
struct list_head trb_list; /* trb list */
|
||||
};
|
||||
|
||||
/* device data structure */
|
||||
struct mv_u3d {
|
||||
struct usb_gadget gadget;
|
||||
struct usb_gadget_driver *driver;
|
||||
spinlock_t lock; /* device lock */
|
||||
struct completion *done;
|
||||
struct device *dev;
|
||||
int irq;
|
||||
|
||||
/* usb controller registers */
|
||||
struct mv_u3d_cap_regs __iomem *cap_regs;
|
||||
struct mv_u3d_op_regs __iomem *op_regs;
|
||||
struct mv_u3d_vuc_regs __iomem *vuc_regs;
|
||||
void __iomem *phy_regs;
|
||||
|
||||
unsigned int max_eps;
|
||||
struct mv_u3d_ep_context *ep_context;
|
||||
size_t ep_context_size;
|
||||
dma_addr_t ep_context_dma;
|
||||
|
||||
struct dma_pool *trb_pool; /* for TRB data structure */
|
||||
struct mv_u3d_ep *eps;
|
||||
|
||||
struct mv_u3d_req *status_req; /* ep0 status request */
|
||||
struct usb_ctrlrequest local_setup_buff; /* store setup data*/
|
||||
|
||||
unsigned int resume_state; /* USB state to resume */
|
||||
unsigned int usb_state; /* USB current state */
|
||||
unsigned int ep0_state; /* Endpoint zero state */
|
||||
unsigned int ep0_dir;
|
||||
|
||||
unsigned int dev_addr; /* device address */
|
||||
|
||||
unsigned int errors;
|
||||
|
||||
unsigned softconnect:1;
|
||||
unsigned vbus_active:1; /* vbus is active or not */
|
||||
unsigned remote_wakeup:1; /* support remote wakeup */
|
||||
unsigned clock_gating:1; /* clock gating or not */
|
||||
unsigned active:1; /* udc is active or not */
|
||||
unsigned vbus_valid_detect:1; /* udc vbus detection */
|
||||
|
||||
struct mv_usb_addon_irq *vbus;
|
||||
unsigned int power;
|
||||
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
/* endpoint data structure */
|
||||
struct mv_u3d_ep {
|
||||
struct usb_ep ep;
|
||||
struct mv_u3d *u3d;
|
||||
struct list_head queue; /* ep request queued hardware */
|
||||
struct list_head req_list; /* list of ep request */
|
||||
struct mv_u3d_ep_context *ep_context; /* ep context */
|
||||
u32 direction;
|
||||
char name[14];
|
||||
u32 processing; /* there is ep request
|
||||
queued on haredware */
|
||||
spinlock_t req_lock; /* ep lock */
|
||||
unsigned wedge:1;
|
||||
unsigned enabled:1;
|
||||
unsigned ep_type:2;
|
||||
unsigned ep_num:8;
|
||||
};
|
||||
|
||||
/* request data structure */
|
||||
struct mv_u3d_req {
|
||||
struct usb_request req;
|
||||
struct mv_u3d_ep *ep;
|
||||
struct list_head queue; /* ep requst queued on hardware */
|
||||
struct list_head list; /* ep request list */
|
||||
struct list_head trb_list; /* trb list of a request */
|
||||
|
||||
struct mv_u3d_trb *trb_head; /* point to first trb of a request */
|
||||
unsigned trb_count; /* TRB number in the chain */
|
||||
unsigned chain; /* TRB chain or not */
|
||||
};
|
||||
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче