5be19a9daa
Intel Langwell USB Device Controller is a High-Speed USB OTG device controller in Intel Moorestown platform. It can work in OTG device mode with Intel Langwell USB OTG transceiver driver as well as device-only mode. The number of programmable endpoints is different through controller revision. NOTE: This patch is the first version Intel Langwell USB OTG device controller driver. The bug fixing is on going for some hardware and software issues. Intel Langwell USB OTG transceiver driver and EHCI driver patches will be submitted later. Supported features: - USB OTG protocol support with Intel Langwell USB OTG transceiver driver (turn on CONFIG_USB_LANGWELL_OTG) - Support control, bulk, interrupt and isochronous endpoints (isochronous not tested) - PCI D0/D3 power management support - Link Power Management (LPM) support Tested gadget drivers: - g_file_storage - g_ether - g_zero The passed tests: - g_file_storage: USBCV Chapter 9 tests - g_file_storage: USBCV MSC tests - g_file_storage: from/to host files copying - g_ether: ping, ftp and scp files from/to host - Hotplug, with and without hubs Known issues: - g_ether: failed part of USBCV chap9 tests - LPM support not fully tested TODO: - g_ether: pass all USBCV chap9 tests - g_zero: pass usbtest tests - Stress tests on different gadget drivers - On-chip private SRAM caching support Signed-off-by: Xiaochen Shen <xiaochen.shen@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
229 lines
5.8 KiB
C
229 lines
5.8 KiB
C
/*
|
|
* Intel Langwell USB Device Controller driver
|
|
* Copyright (C) 2008-2009, Intel Corporation.
|
|
*
|
|
* 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.
|
|
*
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
*/
|
|
|
|
#include <linux/usb/langwell_udc.h>
|
|
|
|
#if defined(CONFIG_USB_LANGWELL_OTG)
|
|
#include <linux/usb/langwell_otg.h>
|
|
#endif
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/* driver data structures and utilities */
|
|
|
|
/*
|
|
* dTD: Device Endpoint Transfer Descriptor
|
|
* describe to the device controller the location and quantity of
|
|
* data to be send/received for given transfer
|
|
*/
|
|
struct langwell_dtd {
|
|
u32 dtd_next;
|
|
/* bits 31:5, next transfer element pointer */
|
|
#define DTD_NEXT(d) (((d)>>5)&0x7ffffff)
|
|
#define DTD_NEXT_MASK (0x7ffffff << 5)
|
|
/* terminate */
|
|
#define DTD_TERM BIT(0)
|
|
/* bits 7:0, execution back states */
|
|
u32 dtd_status:8;
|
|
#define DTD_STATUS(d) (((d)>>0)&0xff)
|
|
#define DTD_STS_ACTIVE BIT(7) /* active */
|
|
#define DTD_STS_HALTED BIT(6) /* halted */
|
|
#define DTD_STS_DBE BIT(5) /* data buffer error */
|
|
#define DTD_STS_TRE BIT(3) /* transaction error */
|
|
/* bits 9:8 */
|
|
u32 dtd_res0:2;
|
|
/* bits 11:10, multipier override */
|
|
u32 dtd_multo:2;
|
|
#define DTD_MULTO (BIT(11) | BIT(10))
|
|
/* bits 14:12 */
|
|
u32 dtd_res1:3;
|
|
/* bit 15, interrupt on complete */
|
|
u32 dtd_ioc:1;
|
|
#define DTD_IOC BIT(15)
|
|
/* bits 30:16, total bytes */
|
|
u32 dtd_total:15;
|
|
#define DTD_TOTAL(d) (((d)>>16)&0x7fff)
|
|
#define DTD_MAX_TRANSFER_LENGTH 0x4000
|
|
/* bit 31 */
|
|
u32 dtd_res2:1;
|
|
/* dTD buffer pointer page 0 to 4 */
|
|
u32 dtd_buf[5];
|
|
#define DTD_OFFSET_MASK 0xfff
|
|
/* bits 31:12, buffer pointer */
|
|
#define DTD_BUFFER(d) (((d)>>12)&0x3ff)
|
|
/* bits 11:0, current offset */
|
|
#define DTD_C_OFFSET(d) (((d)>>0)&0xfff)
|
|
/* bits 10:0, frame number */
|
|
#define DTD_FRAME(d) (((d)>>0)&0x7ff)
|
|
|
|
/* driver-private parts */
|
|
|
|
/* dtd dma address */
|
|
dma_addr_t dtd_dma;
|
|
/* next dtd virtual address */
|
|
struct langwell_dtd *next_dtd_virt;
|
|
};
|
|
|
|
|
|
/*
|
|
* dQH: Device Endpoint Queue Head
|
|
* describe where all transfers are managed
|
|
* 48-byte data structure, aligned on 64-byte boundary
|
|
*
|
|
* These are associated with dTD structure
|
|
*/
|
|
struct langwell_dqh {
|
|
/* endpoint capabilities and characteristics */
|
|
u32 dqh_res0:15; /* bits 14:0 */
|
|
u32 dqh_ios:1; /* bit 15, interrupt on setup */
|
|
#define DQH_IOS BIT(15)
|
|
u32 dqh_mpl:11; /* bits 26:16, maximum packet length */
|
|
#define DQH_MPL (0x7ff << 16)
|
|
u32 dqh_res1:2; /* bits 28:27 */
|
|
u32 dqh_zlt:1; /* bit 29, zero length termination */
|
|
#define DQH_ZLT BIT(29)
|
|
u32 dqh_mult:2; /* bits 31:30 */
|
|
#define DQH_MULT (BIT(30) | BIT(31))
|
|
|
|
/* current dTD pointer */
|
|
u32 dqh_current; /* locate the transfer in progress */
|
|
#define DQH_C_DTD(e) \
|
|
(((e)>>5)&0x7ffffff) /* bits 31:5, current dTD pointer */
|
|
|
|
/* transfer overlay, hardware parts of a struct langwell_dtd */
|
|
u32 dtd_next;
|
|
u32 dtd_status:8; /* bits 7:0, execution back states */
|
|
u32 dtd_res0:2; /* bits 9:8 */
|
|
u32 dtd_multo:2; /* bits 11:10, multipier override */
|
|
u32 dtd_res1:3; /* bits 14:12 */
|
|
u32 dtd_ioc:1; /* bit 15, interrupt on complete */
|
|
u32 dtd_total:15; /* bits 30:16, total bytes */
|
|
u32 dtd_res2:1; /* bit 31 */
|
|
u32 dtd_buf[5]; /* dTD buffer pointer page 0 to 4 */
|
|
|
|
u32 dqh_res2;
|
|
struct usb_ctrlrequest dqh_setup; /* setup packet buffer */
|
|
} __attribute__ ((aligned(64)));
|
|
|
|
|
|
/* endpoint data structure */
|
|
struct langwell_ep {
|
|
struct usb_ep ep;
|
|
dma_addr_t dma;
|
|
struct langwell_udc *dev;
|
|
unsigned long irqs;
|
|
struct list_head queue;
|
|
struct langwell_dqh *dqh;
|
|
const struct usb_endpoint_descriptor *desc;
|
|
char name[14];
|
|
unsigned stopped:1,
|
|
ep_type:2,
|
|
ep_num:8;
|
|
};
|
|
|
|
|
|
/* request data structure */
|
|
struct langwell_request {
|
|
struct usb_request req;
|
|
struct langwell_dtd *dtd, *head, *tail;
|
|
struct langwell_ep *ep;
|
|
dma_addr_t dtd_dma;
|
|
struct list_head queue;
|
|
unsigned dtd_count;
|
|
unsigned mapped:1;
|
|
};
|
|
|
|
|
|
/* ep0 transfer state */
|
|
enum ep0_state {
|
|
WAIT_FOR_SETUP,
|
|
DATA_STATE_XMIT,
|
|
DATA_STATE_NEED_ZLP,
|
|
WAIT_FOR_OUT_STATUS,
|
|
DATA_STATE_RECV,
|
|
};
|
|
|
|
|
|
/* device suspend state */
|
|
enum lpm_state {
|
|
LPM_L0, /* on */
|
|
LPM_L1, /* LPM L1 sleep */
|
|
LPM_L2, /* suspend */
|
|
LPM_L3, /* off */
|
|
};
|
|
|
|
|
|
/* device data structure */
|
|
struct langwell_udc {
|
|
/* each pci device provides one gadget, several endpoints */
|
|
struct usb_gadget gadget;
|
|
spinlock_t lock; /* device lock */
|
|
struct langwell_ep *ep;
|
|
struct usb_gadget_driver *driver;
|
|
struct otg_transceiver *transceiver;
|
|
u8 dev_addr;
|
|
u32 usb_state;
|
|
u32 resume_state;
|
|
u32 bus_reset;
|
|
enum lpm_state lpm_state;
|
|
enum ep0_state ep0_state;
|
|
u32 ep0_dir;
|
|
u16 dciversion;
|
|
unsigned ep_max;
|
|
unsigned devcap:1,
|
|
enabled:1,
|
|
region:1,
|
|
got_irq:1,
|
|
powered:1,
|
|
remote_wakeup:1,
|
|
rate:1,
|
|
is_reset:1,
|
|
softconnected:1,
|
|
vbus_active:1,
|
|
suspended:1,
|
|
stopped:1,
|
|
lpm:1; /* LPM capability */
|
|
|
|
/* pci state used to access those endpoints */
|
|
struct pci_dev *pdev;
|
|
|
|
/* Langwell otg transceiver */
|
|
struct langwell_otg *lotg;
|
|
|
|
/* control registers */
|
|
struct langwell_cap_regs __iomem *cap_regs;
|
|
struct langwell_op_regs __iomem *op_regs;
|
|
|
|
struct usb_ctrlrequest local_setup_buff;
|
|
struct langwell_dqh *ep_dqh;
|
|
size_t ep_dqh_size;
|
|
dma_addr_t ep_dqh_dma;
|
|
|
|
/* ep0 status request */
|
|
struct langwell_request *status_req;
|
|
|
|
/* dma pool */
|
|
struct dma_pool *dtd_pool;
|
|
|
|
/* make sure release() is done */
|
|
struct completion *done;
|
|
};
|
|
|