提交 550a7375 编写于 作者: F Felipe Balbi 提交者: Greg Kroah-Hartman

USB: Add MUSB and TUSB support

This patch adds support for MUSB and TUSB controllers
integrated into omap2430 and davinci. It also adds support
for external tusb6010 controller.

Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Tony Lindgren <tony@atomide.com>
Signed-off-by: NFelipe Balbi <felipe.balbi@nokia.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 f331e40e
......@@ -2928,6 +2928,12 @@ M: jirislaby@gmail.com
L: linux-kernel@vger.kernel.org
S: Maintained
MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
P: Felipe Balbi
M: felipe.balbi@nokia.com
L: linux-usb@vger.kernel.org
S: Maintained
MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
P: Andrew Gallatin
M: gallatin@myri.com
......
......@@ -57,6 +57,7 @@ obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/
obj-$(CONFIG_PARIDE) += block/paride/
obj-$(CONFIG_TC) += tc/
obj-$(CONFIG_USB) += usb/
obj-$(CONFIG_USB_MUSB_HDRC) += usb/musb/
obj-$(CONFIG_PCI) += usb/
obj-$(CONFIG_USB_GADGET) += usb/gadget/
obj-$(CONFIG_SERIO) += input/serio/
......
......@@ -99,6 +99,8 @@ source "drivers/usb/mon/Kconfig"
source "drivers/usb/host/Kconfig"
source "drivers/usb/musb/Kconfig"
source "drivers/usb/class/Kconfig"
source "drivers/usb/storage/Kconfig"
......
......@@ -284,6 +284,16 @@ config USB_LH7A40X
default USB_GADGET
select USB_GADGET_SELECTED
# built in ../musb along with host support
config USB_GADGET_MUSB_HDRC
boolean "Inventra HDRC USB Peripheral (TI, ...)"
depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
select USB_GADGET_DUALSPEED
select USB_GADGET_SELECTED
help
This OTG-capable silicon IP is used in dual designs including
the TI DaVinci, OMAP 243x, OMAP 343x, and TUSB 6010.
config USB_GADGET_OMAP
boolean "OMAP USB Device Controller"
depends on ARCH_OMAP
......
#
# USB Dual Role (OTG-ready) Controller Drivers
# for silicon based on Mentor Graphics INVENTRA designs
#
comment "Enable Host or Gadget support to see Inventra options"
depends on !USB && USB_GADGET=n
# (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
config USB_MUSB_HDRC
depends on (USB || USB_GADGET) && HAVE_CLK
select TWL4030_USB if MACH_OMAP_3430SDP
tristate 'Inventra Highspeed Dual Role Controller (TI, ...)'
help
Say Y here if your system has a dual role high speed USB
controller based on the Mentor Graphics silicon IP. Then
configure options to match your silicon and the board
it's being used with, including the USB peripheral role,
or the USB host role, or both.
Texas Instruments parts using this IP include DaVinci 644x,
OMAP 243x, OMAP 343x, and TUSB 6010.
If you do not know what this is, please say N.
To compile this driver as a module, choose M here; the
module will be called "musb_hdrc".
config USB_MUSB_SOC
boolean
depends on USB_MUSB_HDRC
default y if ARCH_DAVINCI
default y if ARCH_OMAP2430
default y if ARCH_OMAP34XX
help
Use a static <asm/arch/hdrc_cnf.h> file to describe how the
controller is configured (endpoints, mechanisms, etc) on the
current iteration of a given system-on-chip.
comment "DaVinci 644x USB support"
depends on USB_MUSB_HDRC && ARCH_DAVINCI
comment "OMAP 243x high speed USB support"
depends on USB_MUSB_HDRC && ARCH_OMAP2430
comment "OMAP 343x high speed USB support"
depends on USB_MUSB_HDRC && ARCH_OMAP34XX
config USB_TUSB6010
boolean "TUSB 6010 support"
depends on USB_MUSB_HDRC && !USB_MUSB_SOC
default y
help
The TUSB 6010 chip, from Texas Instruments, connects a discrete
HDRC core using a 16-bit parallel bus (NOR flash style) or VLYNQ
(a high speed serial link). It can use system-specific external
DMA controllers.
choice
prompt "Driver Mode"
depends on USB_MUSB_HDRC
help
Dual-Role devices can support both host and peripheral roles,
as well as a the special "OTG Device" role which can switch
between both roles as needed.
# use USB_MUSB_HDRC_HCD not USB_MUSB_HOST to #ifdef host side support;
# OTG needs both roles, not just USB_MUSB_HOST.
config USB_MUSB_HOST
depends on USB
bool "USB Host"
help
Say Y here if your system supports the USB host role.
If it has a USB "A" (rectangular), "Mini-A" (uncommon),
or "Mini-AB" connector, it supports the host role.
(With a "Mini-AB" connector, you should enable USB OTG.)
# use USB_GADGET_MUSB_HDRC not USB_MUSB_PERIPHERAL to #ifdef peripheral
# side support ... OTG needs both roles
config USB_MUSB_PERIPHERAL
depends on USB_GADGET
bool "USB Peripheral (gadget stack)"
select USB_GADGET_MUSB_HDRC
help
Say Y here if your system supports the USB peripheral role.
If it has a USB "B" (squarish), "Mini-B", or "Mini-AB"
connector, it supports the peripheral role.
(With a "Mini-AB" connector, you should enable USB OTG.)
config USB_MUSB_OTG
depends on USB && USB_GADGET && PM && EXPERIMENTAL
bool "Both host and peripheral: USB OTG (On The Go) Device"
select USB_GADGET_MUSB_HDRC
select USB_OTG
help
The most notable feature of USB OTG is support for a
"Dual-Role" device, which can act as either a device
or a host. The initial role choice can be changed
later, when two dual-role devices talk to each other.
At this writing, the OTG support in this driver is incomplete,
omitting the mandatory HNP or SRP protocols. However, some
of the cable based role switching works. (That is, grounding
the ID pin switches the controller to host mode, while leaving
it floating leaves it in peripheral mode.)
Select this if your system has a Mini-AB connector, or
to simplify certain kinds of configuration.
To implement your OTG Targeted Peripherals List (TPL), enable
USB_OTG_WHITELIST and update "drivers/usb/core/otg_whitelist.h"
to match your requirements.
endchoice
# enable peripheral support (including with OTG)
config USB_GADGET_MUSB_HDRC
bool
depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
# default y
# select USB_GADGET_DUALSPEED
# select USB_GADGET_SELECTED
# enables host support (including with OTG)
config USB_MUSB_HDRC_HCD
bool
depends on USB_MUSB_HDRC && (USB_MUSB_HOST || USB_MUSB_OTG)
select USB_OTG if USB_GADGET_MUSB_HDRC
default y
config MUSB_PIO_ONLY
bool 'Disable DMA (always use PIO)'
depends on USB_MUSB_HDRC
default y if USB_TUSB6010
help
All data is copied between memory and FIFO by the CPU.
DMA controllers are ignored.
Do not select 'n' here unless DMA support for your SOC or board
is unavailable (or unstable). When DMA is enabled at compile time,
you can still disable it at run time using the "use_dma=n" module
parameter.
config USB_INVENTRA_DMA
bool
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
default ARCH_OMAP2430 || ARCH_OMAP34XX
help
Enable DMA transfers using Mentor's engine.
config USB_TI_CPPI_DMA
bool
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
default ARCH_DAVINCI
help
Enable DMA transfers when TI CPPI DMA is available.
config USB_TUSB_OMAP_DMA
bool
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
depends on USB_TUSB6010
depends on ARCH_OMAP
default y
help
Enable DMA transfers on TUSB 6010 when OMAP DMA is available.
config USB_MUSB_LOGLEVEL
depends on USB_MUSB_HDRC
int 'Logging Level (0 - none / 3 - annoying / ... )'
default 0
help
Set the logging level. 0 disables the debugging altogether,
although when USB_DEBUG is set the value is at least 1.
Starting at level 3, per-transfer (urb, usb_request, packet,
or dma transfer) tracing may kick in.
#
# for USB OTG silicon based on Mentor Graphics INVENTRA designs
#
musb_hdrc-objs := musb_core.o
obj-$(CONFIG_USB_MUSB_HDRC) += musb_hdrc.o
ifeq ($(CONFIG_ARCH_DAVINCI),y)
musb_hdrc-objs += davinci.o
endif
ifeq ($(CONFIG_USB_TUSB6010),y)
musb_hdrc-objs += tusb6010.o
endif
ifeq ($(CONFIG_ARCH_OMAP2430),y)
musb_hdrc-objs += omap2430.o
endif
ifeq ($(CONFIG_ARCH_OMAP3430),y)
musb_hdrc-objs += omap2430.o
endif
ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y)
musb_hdrc-objs += musb_gadget_ep0.o musb_gadget.o
endif
ifeq ($(CONFIG_USB_MUSB_HDRC_HCD),y)
musb_hdrc-objs += musb_virthub.o musb_host.o
endif
# the kconfig must guarantee that only one of the
# possible I/O schemes will be enabled at a time ...
# PIO only, or DMA (several potential schemes).
# though PIO is always there to back up DMA, and for ep0
ifneq ($(CONFIG_MUSB_PIO_ONLY),y)
ifeq ($(CONFIG_USB_INVENTRA_DMA),y)
musb_hdrc-objs += musbhsdma.o
else
ifeq ($(CONFIG_USB_TI_CPPI_DMA),y)
musb_hdrc-objs += cppi_dma.o
else
ifeq ($(CONFIG_USB_TUSB_OMAP_DMA),y)
musb_hdrc-objs += tusb6010_omap.o
endif
endif
endif
endif
################################################################################
# FIXME remove all these extra "-DMUSB_* things, stick to CONFIG_*
ifeq ($(CONFIG_USB_INVENTRA_MUSB_HAS_AHB_ID),y)
EXTRA_CFLAGS += -DMUSB_AHB_ID
endif
# Debugging
MUSB_DEBUG:=$(CONFIG_USB_MUSB_LOGLEVEL)
ifeq ("$(strip $(MUSB_DEBUG))","")
ifdef CONFIG_USB_DEBUG
MUSB_DEBUG:=1
else
MUSB_DEBUG:=0
endif
endif
ifneq ($(MUSB_DEBUG),0)
EXTRA_CFLAGS += -DDEBUG
ifeq ($(CONFIG_PROC_FS),y)
musb_hdrc-objs += musb_procfs.o
endif
endif
EXTRA_CFLAGS += -DMUSB_DEBUG=$(MUSB_DEBUG)
此差异已折叠。
/* Copyright (C) 2005-2006 by Texas Instruments */
#ifndef _CPPI_DMA_H_
#define _CPPI_DMA_H_
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/dmapool.h>
#include "musb_dma.h"
#include "musb_core.h"
/* FIXME fully isolate CPPI from DaVinci ... the "CPPI generic" registers
* would seem to be shared with the TUSB6020 (over VLYNQ).
*/
#include "davinci.h"
/* CPPI RX/TX state RAM */
struct cppi_tx_stateram {
u32 tx_head; /* "DMA packet" head descriptor */
u32 tx_buf;
u32 tx_current; /* current descriptor */
u32 tx_buf_current;
u32 tx_info; /* flags, remaining buflen */
u32 tx_rem_len;
u32 tx_dummy; /* unused */
u32 tx_complete;
};
struct cppi_rx_stateram {
u32 rx_skipbytes;
u32 rx_head;
u32 rx_sop; /* "DMA packet" head descriptor */
u32 rx_current; /* current descriptor */
u32 rx_buf_current;
u32 rx_len_len;
u32 rx_cnt_cnt;
u32 rx_complete;
};
/* hw_options bits in CPPI buffer descriptors */
#define CPPI_SOP_SET ((u32)(1 << 31))
#define CPPI_EOP_SET ((u32)(1 << 30))
#define CPPI_OWN_SET ((u32)(1 << 29)) /* owned by cppi */
#define CPPI_EOQ_MASK ((u32)(1 << 28))
#define CPPI_ZERO_SET ((u32)(1 << 23)) /* rx saw zlp; tx issues one */
#define CPPI_RXABT_MASK ((u32)(1 << 19)) /* need more rx buffers */
#define CPPI_RECV_PKTLEN_MASK 0xFFFF
#define CPPI_BUFFER_LEN_MASK 0xFFFF
#define CPPI_TEAR_READY ((u32)(1 << 31))
/* CPPI data structure definitions */
#define CPPI_DESCRIPTOR_ALIGN 16 /* bytes; 5-dec docs say 4-byte align */
struct cppi_descriptor {
/* hardware overlay */
u32 hw_next; /* next buffer descriptor Pointer */
u32 hw_bufp; /* i/o buffer pointer */
u32 hw_off_len; /* buffer_offset16, buffer_length16 */
u32 hw_options; /* flags: SOP, EOP etc*/
struct cppi_descriptor *next;
dma_addr_t dma; /* address of this descriptor */
u32 buflen; /* for RX: original buffer length */
} __attribute__ ((aligned(CPPI_DESCRIPTOR_ALIGN)));
struct cppi;
/* CPPI Channel Control structure */
struct cppi_channel {
struct dma_channel channel;
/* back pointer to the DMA controller structure */
struct cppi *controller;
/* which direction of which endpoint? */
struct musb_hw_ep *hw_ep;
bool transmit;
u8 index;
/* DMA modes: RNDIS or "transparent" */
u8 is_rndis;
/* book keeping for current transfer request */
dma_addr_t buf_dma;
u32 buf_len;
u32 maxpacket;
u32 offset; /* dma requested */
void __iomem *state_ram; /* CPPI state */
struct cppi_descriptor *freelist;
/* BD management fields */
struct cppi_descriptor *head;
struct cppi_descriptor *tail;
struct cppi_descriptor *last_processed;
/* use tx_complete in host role to track endpoints waiting for
* FIFONOTEMPTY to clear.
*/
struct list_head tx_complete;
};
/* CPPI DMA controller object */
struct cppi {
struct dma_controller controller;
struct musb *musb;
void __iomem *mregs; /* Mentor regs */
void __iomem *tibase; /* TI/CPPI regs */
struct cppi_channel tx[MUSB_C_NUM_EPT - 1];
struct cppi_channel rx[MUSB_C_NUM_EPR - 1];
struct dma_pool *pool;
struct list_head tx_complete;
};
/* irq handling hook */
extern void cppi_completion(struct musb *, u32 rx, u32 tx);
#endif /* end of ifndef _CPPI_DMA_H_ */
/*
* Copyright (C) 2005-2006 by Texas Instruments
*
* This file is part of the Inventra Controller Driver for Linux.
*
* The Inventra Controller Driver for Linux is free software; you
* can redistribute it and/or modify it under the terms of the GNU
* General Public License version 2 as published by the Free Software
* Foundation.
*
* The Inventra Controller Driver for Linux is distributed in
* the hope that 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 The Inventra Controller Driver for Linux ; if not,
* write to the Free Software Foundation, Inc., 59 Temple Place,
* Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/memory.h>
#include <asm/arch/gpio.h>
#include <asm/mach-types.h>
#include "musb_core.h"
#ifdef CONFIG_MACH_DAVINCI_EVM
#include <asm/arch/i2c-client.h>
#endif
#include "davinci.h"
#include "cppi_dma.h"
/* REVISIT (PM) we should be able to keep the PHY in low power mode most
* of the time (24 MHZ oscillator and PLL off, etc) by setting POWER.D0
* and, when in host mode, autosuspending idle root ports... PHYPLLON
* (overriding SUSPENDM?) then likely needs to stay off.
*/
static inline void phy_on(void)
{
/* start the on-chip PHY and its PLL */
__raw_writel(USBPHY_SESNDEN | USBPHY_VBDTCTEN | USBPHY_PHYPLLON,
(void __force __iomem *) IO_ADDRESS(USBPHY_CTL_PADDR));
while ((__raw_readl((void __force __iomem *)
IO_ADDRESS(USBPHY_CTL_PADDR))
& USBPHY_PHYCLKGD) == 0)
cpu_relax();
}
static inline void phy_off(void)
{
/* powerdown the on-chip PHY and its oscillator */
__raw_writel(USBPHY_OSCPDWN | USBPHY_PHYPDWN, (void __force __iomem *)
IO_ADDRESS(USBPHY_CTL_PADDR));
}
static int dma_off = 1;
void musb_platform_enable(struct musb *musb)
{
u32 tmp, old, val;
/* workaround: setup irqs through both register sets */
tmp = (musb->epmask & DAVINCI_USB_TX_ENDPTS_MASK)
<< DAVINCI_USB_TXINT_SHIFT;
musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
old = tmp;
tmp = (musb->epmask & (0xfffe & DAVINCI_USB_RX_ENDPTS_MASK))
<< DAVINCI_USB_RXINT_SHIFT;
musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
tmp |= old;
val = ~MUSB_INTR_SOF;
tmp |= ((val & 0x01ff) << DAVINCI_USB_USBINT_SHIFT);
musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
if (is_dma_capable() && !dma_off)
printk(KERN_WARNING "%s %s: dma not reactivated\n",
__FILE__, __func__);
else
dma_off = 0;
/* force a DRVVBUS irq so we can start polling for ID change */
if (is_otg_enabled(musb))
musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT);
}
/*
* Disable the HDRC and flush interrupts
*/
void musb_platform_disable(struct musb *musb)
{
/* because we don't set CTRLR.UINT, "important" to:
* - not read/write INTRUSB/INTRUSBE
* - (except during initial setup, as workaround)
* - use INTSETR/INTCLRR instead
*/
musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_CLR_REG,
DAVINCI_USB_USBINT_MASK
| DAVINCI_USB_TXINT_MASK
| DAVINCI_USB_RXINT_MASK);
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
musb_writel(musb->ctrl_base, DAVINCI_USB_EOI_REG, 0);
if (is_dma_capable() && !dma_off)
WARNING("dma still active\n");
}
/* REVISIT it's not clear whether DaVinci can support full OTG. */
static int vbus_state = -1;
#ifdef CONFIG_USB_MUSB_HDRC_HCD
#define portstate(stmt) stmt
#else
#define portstate(stmt)
#endif
/* VBUS SWITCHING IS BOARD-SPECIFIC */
#ifdef CONFIG_MACH_DAVINCI_EVM
#ifndef CONFIG_MACH_DAVINCI_EVM_OTG
/* I2C operations are always synchronous, and require a task context.
* With unloaded systems, using the shared workqueue seems to suffice
* to satisfy the 100msec A_WAIT_VRISE timeout...
*/
static void evm_deferred_drvvbus(struct work_struct *ignored)
{
davinci_i2c_expander_op(0x3a, USB_DRVVBUS, vbus_state);
vbus_state = !vbus_state;
}
static DECLARE_WORK(evm_vbus_work, evm_deferred_drvvbus);
#endif /* modified board */
#endif /* EVM */
static void davinci_source_power(struct musb *musb, int is_on, int immediate)
{
if (is_on)
is_on = 1;
if (vbus_state == is_on)
return;
vbus_state = !is_on; /* 0/1 vs "-1 == unknown/init" */
#ifdef CONFIG_MACH_DAVINCI_EVM
if (machine_is_davinci_evm()) {
#ifdef CONFIG_MACH_DAVINCI_EVM_OTG
/* modified EVM board switching VBUS with GPIO(6) not I2C
* NOTE: PINMUX0.RGB888 (bit23) must be clear
*/
if (is_on)
gpio_set(GPIO(6));
else
gpio_clear(GPIO(6));
immediate = 1;
#else
if (immediate)
davinci_i2c_expander_op(0x3a, USB_DRVVBUS, !is_on);
else
schedule_work(&evm_vbus_work);
#endif
}
#endif
if (immediate)
vbus_state = is_on;
}
static void davinci_set_vbus(struct musb *musb, int is_on)
{
WARN_ON(is_on && is_peripheral_active(musb));
davinci_source_power(musb, is_on, 0);
}
#define POLL_SECONDS 2
static struct timer_list otg_workaround;
static void otg_timer(unsigned long _musb)
{
struct musb *musb = (void *)_musb;
void __iomem *mregs = musb->mregs;
u8 devctl;
unsigned long flags;
/* We poll because DaVinci's won't expose several OTG-critical
* status change events (from the transceiver) otherwise.
*/
devctl = musb_readb(mregs, MUSB_DEVCTL);
DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv.state) {
case OTG_STATE_A_WAIT_VFALL:
/* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL
* seems to mis-handle session "start" otherwise (or in our
* case "recover"), in routine "VBUS was valid by the time
* VBUSERR got reported during enumeration" cases.
*/
if (devctl & MUSB_DEVCTL_VBUS) {
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
break;
}
musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);
break;
case OTG_STATE_B_IDLE:
if (!is_peripheral_enabled(musb))
break;
/* There's no ID-changed IRQ, so we have no good way to tell
* when to switch to the A-Default state machine (by setting
* the DEVCTL.SESSION flag).
*
* Workaround: whenever we're in B_IDLE, try setting the
* session flag every few seconds. If it works, ID was
* grounded and we're now in the A-Default state machine.
*
* NOTE setting the session flag is _supposed_ to trigger
* SRP, but clearly it doesn't.
*/
musb_writeb(mregs, MUSB_DEVCTL,
devctl | MUSB_DEVCTL_SESSION);
devctl = musb_readb(mregs, MUSB_DEVCTL);
if (devctl & MUSB_DEVCTL_BDEVICE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
else
musb->xceiv.state = OTG_STATE_A_IDLE;
break;
default:
break;
}
spin_unlock_irqrestore(&musb->lock, flags);
}
static irqreturn_t davinci_interrupt(int irq, void *__hci)
{
unsigned long flags;
irqreturn_t retval = IRQ_NONE;
struct musb *musb = __hci;
void __iomem *tibase = musb->ctrl_base;
u32 tmp;
spin_lock_irqsave(&musb->lock, flags);
/* NOTE: DaVinci shadows the Mentor IRQs. Don't manage them through
* the Mentor registers (except for setup), use the TI ones and EOI.
*
* Docs describe irq "vector" registers asociated with the CPPI and
* USB EOI registers. These hold a bitmask corresponding to the
* current IRQ, not an irq handler address. Would using those bits
* resolve some of the races observed in this dispatch code??
*/
/* CPPI interrupts share the same IRQ line, but have their own
* mask, state, "vector", and EOI registers.
*/
if (is_cppi_enabled()) {
u32 cppi_tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
u32 cppi_rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
if (cppi_tx || cppi_rx) {
DBG(4, "CPPI IRQ t%x r%x\n", cppi_tx, cppi_rx);
cppi_completion(musb, cppi_rx, cppi_tx);
retval = IRQ_HANDLED;
}
}
/* ack and handle non-CPPI interrupts */
tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG);
musb_writel(tibase, DAVINCI_USB_INT_SRC_CLR_REG, tmp);
DBG(4, "IRQ %08x\n", tmp);
musb->int_rx = (tmp & DAVINCI_USB_RXINT_MASK)
>> DAVINCI_USB_RXINT_SHIFT;
musb->int_tx = (tmp & DAVINCI_USB_TXINT_MASK)
>> DAVINCI_USB_TXINT_SHIFT;
musb->int_usb = (tmp & DAVINCI_USB_USBINT_MASK)
>> DAVINCI_USB_USBINT_SHIFT;
/* DRVVBUS irqs are the only proxy we have (a very poor one!) for
* DaVinci's missing ID change IRQ. We need an ID change IRQ to
* switch appropriately between halves of the OTG state machine.
* Managing DEVCTL.SESSION per Mentor docs requires we know its
* value, but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
* Also, DRVVBUS pulses for SRP (but not at 5V) ...
*/
if (tmp & (DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT)) {
int drvvbus = musb_readl(tibase, DAVINCI_USB_STAT_REG);
void __iomem *mregs = musb->mregs;
u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
int err = musb->int_usb & MUSB_INTR_VBUSERROR;
err = is_host_enabled(musb)
&& (musb->int_usb & MUSB_INTR_VBUSERROR);
if (err) {
/* The Mentor core doesn't debounce VBUS as needed
* to cope with device connect current spikes. This
* means it's not uncommon for bus-powered devices
* to get VBUS errors during enumeration.
*
* This is a workaround, but newer RTL from Mentor
* seems to allow a better one: "re"starting sessions
* without waiting (on EVM, a **long** time) for VBUS
* to stop registering in devctl.
*/
musb->int_usb &= ~MUSB_INTR_VBUSERROR;
musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
WARNING("VBUS error workaround (delay coming)\n");
} else if (is_host_enabled(musb) && drvvbus) {
musb->is_active = 1;
MUSB_HST_MODE(musb);
musb->xceiv.default_a = 1;
musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
portstate(musb->port1_status |= USB_PORT_STAT_POWER);
del_timer(&otg_workaround);
} else {
musb->is_active = 0;
MUSB_DEV_MODE(musb);
musb->xceiv.default_a = 0;
musb->xceiv.state = OTG_STATE_B_IDLE;
portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
}
/* NOTE: this must complete poweron within 100 msec */
davinci_source_power(musb, drvvbus, 0);
DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
otg_state_string(musb),
err ? " ERROR" : "",
devctl);
retval = IRQ_HANDLED;
}
if (musb->int_tx || musb->int_rx || musb->int_usb)
retval |= musb_interrupt(musb);
/* irq stays asserted until EOI is written */
musb_writel(tibase, DAVINCI_USB_EOI_REG, 0);
/* poll for ID change */
if (is_otg_enabled(musb)
&& musb->xceiv.state == OTG_STATE_B_IDLE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
spin_unlock_irqrestore(&musb->lock, flags);
/* REVISIT we sometimes get unhandled IRQs
* (e.g. ep0). not clear why...
*/
if (retval != IRQ_HANDLED)
DBG(5, "unhandled? %08x\n", tmp);
return IRQ_HANDLED;
}
int __init musb_platform_init(struct musb *musb)
{
void __iomem *tibase = musb->ctrl_base;
u32 revision;
musb->mregs += DAVINCI_BASE_OFFSET;
#if 0
/* REVISIT there's something odd about clocking, this
* didn't appear do the job ...
*/
musb->clock = clk_get(pDevice, "usb");
if (IS_ERR(musb->clock))
return PTR_ERR(musb->clock);
status = clk_enable(musb->clock);
if (status < 0)
return -ENODEV;
#endif
/* returns zero if e.g. not clocked */
revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
if (revision == 0)
return -ENODEV;
if (is_host_enabled(musb))
setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
musb->board_set_vbus = davinci_set_vbus;
davinci_source_power(musb, 0, 1);
/* reset the controller */
musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1);
/* start the on-chip PHY and its PLL */
phy_on();
msleep(5);
/* NOTE: irqs are in mixed mode, not bypass to pure-musb */
pr_debug("DaVinci OTG revision %08x phy %03x control %02x\n",
revision, __raw_readl((void __force __iomem *)
IO_ADDRESS(USBPHY_CTL_PADDR)),
musb_readb(tibase, DAVINCI_USB_CTRL_REG));
musb->isr = davinci_interrupt;
return 0;
}
int musb_platform_exit(struct musb *musb)
{
if (is_host_enabled(musb))
del_timer_sync(&otg_workaround);
davinci_source_power(musb, 0 /*off*/, 1);
/* delay, to avoid problems with module reload */
if (is_host_enabled(musb) && musb->xceiv.default_a) {
int maxdelay = 30;
u8 devctl, warn = 0;
/* if there's no peripheral connected, this can take a
* long time to fall, especially on EVM with huge C133.
*/
do {
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
if (!(devctl & MUSB_DEVCTL_VBUS))
break;
if ((devctl & MUSB_DEVCTL_VBUS) != warn) {
warn = devctl & MUSB_DEVCTL_VBUS;
DBG(1, "VBUS %d\n",
warn >> MUSB_DEVCTL_VBUS_SHIFT);
}
msleep(1000);
maxdelay--;
} while (maxdelay > 0);
/* in OTG mode, another host might be connected */
if (devctl & MUSB_DEVCTL_VBUS)
DBG(1, "VBUS off timeout (devctl %02x)\n", devctl);
}
phy_off();
return 0;
}
/*
* Copyright (C) 2005-2006 by Texas Instruments
*
* The Inventra Controller Driver for Linux is free software; you
* can redistribute it and/or modify it under the terms of the GNU
* General Public License version 2 as published by the Free Software
* Foundation.
*/
#ifndef __MUSB_HDRDF_H__
#define __MUSB_HDRDF_H__
/*
* DaVinci-specific definitions
*/
/* Integrated highspeed/otg PHY */
#define USBPHY_CTL_PADDR (DAVINCI_SYSTEM_MODULE_BASE + 0x34)
#define USBPHY_PHYCLKGD (1 << 8)
#define USBPHY_SESNDEN (1 << 7) /* v(sess_end) comparator */
#define USBPHY_VBDTCTEN (1 << 6) /* v(bus) comparator */
#define USBPHY_PHYPLLON (1 << 4) /* override pll suspend */
#define USBPHY_CLKO1SEL (1 << 3)
#define USBPHY_OSCPDWN (1 << 2)
#define USBPHY_PHYPDWN (1 << 0)
/* For now include usb OTG module registers here */
#define DAVINCI_USB_VERSION_REG 0x00
#define DAVINCI_USB_CTRL_REG 0x04
#define DAVINCI_USB_STAT_REG 0x08
#define DAVINCI_RNDIS_REG 0x10
#define DAVINCI_AUTOREQ_REG 0x14
#define DAVINCI_USB_INT_SOURCE_REG 0x20
#define DAVINCI_USB_INT_SET_REG 0x24
#define DAVINCI_USB_INT_SRC_CLR_REG 0x28
#define DAVINCI_USB_INT_MASK_REG 0x2c
#define DAVINCI_USB_INT_MASK_SET_REG 0x30
#define DAVINCI_USB_INT_MASK_CLR_REG 0x34
#define DAVINCI_USB_INT_SRC_MASKED_REG 0x38
#define DAVINCI_USB_EOI_REG 0x3c
#define DAVINCI_USB_EOI_INTVEC 0x40
/* BEGIN CPPI-generic (?) */
/* CPPI related registers */
#define DAVINCI_TXCPPI_CTRL_REG 0x80
#define DAVINCI_TXCPPI_TEAR_REG 0x84
#define DAVINCI_CPPI_EOI_REG 0x88
#define DAVINCI_CPPI_INTVEC_REG 0x8c
#define DAVINCI_TXCPPI_MASKED_REG 0x90
#define DAVINCI_TXCPPI_RAW_REG 0x94
#define DAVINCI_TXCPPI_INTENAB_REG 0x98
#define DAVINCI_TXCPPI_INTCLR_REG 0x9c
#define DAVINCI_RXCPPI_CTRL_REG 0xC0
#define DAVINCI_RXCPPI_MASKED_REG 0xD0
#define DAVINCI_RXCPPI_RAW_REG 0xD4
#define DAVINCI_RXCPPI_INTENAB_REG 0xD8
#define DAVINCI_RXCPPI_INTCLR_REG 0xDC
#define DAVINCI_RXCPPI_BUFCNT0_REG 0xE0
#define DAVINCI_RXCPPI_BUFCNT1_REG 0xE4
#define DAVINCI_RXCPPI_BUFCNT2_REG 0xE8
#define DAVINCI_RXCPPI_BUFCNT3_REG 0xEC
/* CPPI state RAM entries */
#define DAVINCI_CPPI_STATERAM_BASE_OFFSET 0x100
#define DAVINCI_TXCPPI_STATERAM_OFFSET(chnum) \
(DAVINCI_CPPI_STATERAM_BASE_OFFSET + ((chnum) * 0x40))
#define DAVINCI_RXCPPI_STATERAM_OFFSET(chnum) \
(DAVINCI_CPPI_STATERAM_BASE_OFFSET + 0x20 + ((chnum) * 0x40))
/* CPPI masks */
#define DAVINCI_DMA_CTRL_ENABLE 1
#define DAVINCI_DMA_CTRL_DISABLE 0
#define DAVINCI_DMA_ALL_CHANNELS_ENABLE 0xF
#define DAVINCI_DMA_ALL_CHANNELS_DISABLE 0xF
/* END CPPI-generic (?) */
#define DAVINCI_USB_TX_ENDPTS_MASK 0x1f /* ep0 + 4 tx */
#define DAVINCI_USB_RX_ENDPTS_MASK 0x1e /* 4 rx */
#define DAVINCI_USB_USBINT_SHIFT 16
#define DAVINCI_USB_TXINT_SHIFT 0
#define DAVINCI_USB_RXINT_SHIFT 8
#define DAVINCI_INTR_DRVVBUS 0x0100
#define DAVINCI_USB_USBINT_MASK 0x01ff0000 /* 8 Mentor, DRVVBUS */
#define DAVINCI_USB_TXINT_MASK \
(DAVINCI_USB_TX_ENDPTS_MASK << DAVINCI_USB_TXINT_SHIFT)
#define DAVINCI_USB_RXINT_MASK \
(DAVINCI_USB_RX_ENDPTS_MASK << DAVINCI_USB_RXINT_SHIFT)
#define DAVINCI_BASE_OFFSET 0x400
#endif /* __MUSB_HDRDF_H__ */
此差异已折叠。
此差异已折叠。
/*
* MUSB OTG driver debug defines
*
* Copyright 2005 Mentor Graphics Corporation
* Copyright (C) 2005-2006 by Texas Instruments
* Copyright (C) 2006-2007 Nokia Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that 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
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __MUSB_LINUX_DEBUG_H__
#define __MUSB_LINUX_DEBUG_H__
#define yprintk(facility, format, args...) \
do { printk(facility "%s %d: " format , \
__func__, __LINE__ , ## args); } while (0)
#define WARNING(fmt, args...) yprintk(KERN_WARNING, fmt, ## args)
#define INFO(fmt, args...) yprintk(KERN_INFO, fmt, ## args)
#define ERR(fmt, args...) yprintk(KERN_ERR, fmt, ## args)
#define xprintk(level, facility, format, args...) do { \
if (_dbg_level(level)) { \
printk(facility "%s %d: " format , \
__func__, __LINE__ , ## args); \
} } while (0)
#if MUSB_DEBUG > 0
extern unsigned debug;
#else
#define debug 0
#endif
static inline int _dbg_level(unsigned l)
{
return debug >= l;
}
#define DBG(level, fmt, args...) xprintk(level, KERN_DEBUG, fmt, ## args)
extern const char *otg_state_string(struct musb *);
#endif /* __MUSB_LINUX_DEBUG_H__ */
此差异已折叠。
此差异已折叠。
/*
* MUSB OTG driver peripheral defines
*
* Copyright 2005 Mentor Graphics Corporation
* Copyright (C) 2005-2006 by Texas Instruments
* Copyright (C) 2006-2007 Nokia Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that 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
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __MUSB_GADGET_H
#define __MUSB_GADGET_H
struct musb_request {
struct usb_request request;
struct musb_ep *ep;
struct musb *musb;
u8 tx; /* endpoint direction */
u8 epnum;
u8 mapped;
};
static inline struct musb_request *to_musb_request(struct usb_request *req)
{
return req ? container_of(req, struct musb_request, request) : NULL;
}
extern struct usb_request *
musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags);
extern void musb_free_request(struct usb_ep *ep, struct usb_request *req);
/*
* struct musb_ep - peripheral side view of endpoint rx or tx side
*/
struct musb_ep {
/* stuff towards the head is basically write-once. */
struct usb_ep end_point;
char name[12];
struct musb_hw_ep *hw_ep;
struct musb *musb;
u8 current_epnum;
/* ... when enabled/disabled ... */
u8 type;
u8 is_in;
u16 packet_sz;
const struct usb_endpoint_descriptor *desc;
struct dma_channel *dma;
/* later things are modified based on usage */
struct list_head req_list;
/* true if lock must be dropped but req_list may not be advanced */
u8 busy;
};
static inline struct musb_ep *to_musb_ep(struct usb_ep *ep)
{
return ep ? container_of(ep, struct musb_ep, end_point) : NULL;
}
static inline struct usb_request *next_request(struct musb_ep *ep)
{
struct list_head *queue = &ep->req_list;
if (list_empty(queue))
return NULL;
return container_of(queue->next, struct usb_request, list);
}
extern void musb_g_tx(struct musb *musb, u8 epnum);
extern void musb_g_rx(struct musb *musb, u8 epnum);
extern const struct usb_ep_ops musb_g_ep0_ops;
extern int musb_gadget_setup(struct musb *);
extern void musb_gadget_cleanup(struct musb *);
extern void musb_g_giveback(struct musb_ep *, struct usb_request *, int);
extern int musb_gadget_set_halt(struct usb_ep *ep, int value);
#endif /* __MUSB_GADGET_H */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册