musb-new: port of Linux musb driver

Existing U-Boot musb driver has no support for the new gadget framework
and also seems to have other limitations. As gadget framework is ported
from Linux it seems pretty natural to port musb gadget driver as well.

This driver supports both host and peripheral modes.

This is not a replacement for current musb driver (at least now) as
there are still some consumers of the old UDC interface.

No DMA operation support included, CONFIG_MUSB_PIO_ONLY should be
defined.

Virtual root hub device is not implemented.

Known problems: with no devices connected usb_lowlevel_start() fails.

Signed-off-by: Ilya Yanok <ilya.yanok@cogentembedded.com>
This commit is contained in:
Ilya Yanok 2012-11-06 13:48:21 +00:00 committed by Marek Vasut
parent c60795f41d
commit eb81955bf0
18 changed files with 10853 additions and 2 deletions

View File

@ -322,6 +322,7 @@ LIBS-y += drivers/usb/eth/libusb_eth.o
LIBS-y += drivers/usb/gadget/libusb_gadget.o
LIBS-y += drivers/usb/host/libusb_host.o
LIBS-y += drivers/usb/musb/libusb_musb.o
LIBS-y += drivers/usb/musb-new/libusb_musb-new.o
LIBS-y += drivers/usb/phy/libusb_phy.o
LIBS-y += drivers/usb/ulpi/libusb_ulpi.o
LIBS-y += drivers/video/libvideo.o

View File

@ -125,8 +125,8 @@
#endif
/* Mentor high speed "dual role" controller, in peripheral role */
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
#define gadget_is_musbhdrc(g) (!strcmp("musb_hdrc", (g)->name))
#ifdef CONFIG_MUSB_GADGET
#define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name))
#else
#define gadget_is_musbhdrc(g) 0
#endif

View File

@ -0,0 +1,36 @@
#
# for USB OTG silicon based on Mentor Graphics INVENTRA designs
#
include $(TOPDIR)/config.mk
LIB := $(obj)libusb_musb-new.o
COBJS-$(CONFIG_MUSB_GADGET) += musb_gadget.o musb_gadget_ep0.o musb_core.o
COBJS-$(CONFIG_MUSB_GADGET) += musb_uboot.o
COBJS-$(CONFIG_MUSB_HOST) += musb_host.o musb_core.o musb_uboot.o
CFLAGS_NO_WARN := $(call cc-option,-Wno-unused-variable) \
$(call cc-option,-Wno-unused-but-set-variable) \
$(call cc-option,-Wno-unused-label)
CFLAGS += $(CFLAGS_NO_WARN)
COBJS := $(sort $(COBJS-y))
SRCS := $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS))
all: $(LIB)
#$(LIB): $(OBJS)
$(LIB): $(obj).depend $(OBJS)
$(call cmd_link_o_target, $(OBJS))
#########################################################################
# defines $(obj).depend target
include $(SRCTREE)/rules.mk
sinclude $(obj).depend
#########################################################################

View File

@ -0,0 +1,106 @@
#ifndef __LINUX_COMPAT_H__
#define __LINUX_COMPAT_H__
#include <malloc.h>
#include <linux/list.h>
#include <linux/compat.h>
#define __init
#define __devinit
#define __devinitdata
#define __devinitconst
#define __iomem
#define __deprecated
typedef enum { false = 0, true = 1 } bool;
struct unused {};
typedef struct unused unused_t;
typedef int irqreturn_t;
typedef unused_t spinlock_t;
struct work_struct {};
struct timer_list {};
struct notifier_block {};
typedef unsigned long dmaaddr_t;
#define spin_lock_init(lock) do {} while (0)
#define spin_lock(lock) do {} while (0)
#define spin_unlock(lock) do {} while (0)
#define spin_lock_irqsave(lock, flags) do {} while (0)
#define spin_unlock_irqrestore(lock, flags) do {} while (0)
#define setup_timer(timer, func, data) do {} while (0)
#define schedule_work(work) do {} while (0)
#define INIT_WORK(work, fun) do {} while (0)
#define cpu_relax() do {} while (0)
#define pr_debug(fmt, args...) debug(fmt, ##args)
#define dev_dbg(dev, fmt, args...) \
debug(fmt, ##args)
#define dev_vdbg(dev, fmt, args...) \
debug(fmt, ##args)
#define dev_info(dev, fmt, args...) \
printf(fmt, ##args)
#define dev_err(dev, fmt, args...) \
printf(fmt, ##args)
#define printk printf
#define WARN(condition, fmt, args...) ({ \
int ret_warn = !!condition; \
if (ret_warn) \
printf(fmt, ##args); \
ret_warn; })
#define KERN_DEBUG
#define KERN_NOTICE
#define KERN_WARNING
#define KERN_ERR
#define kfree(ptr) free(ptr)
#define pm_runtime_get_sync(dev) do {} while (0)
#define pm_runtime_put(dev) do {} while (0)
#define pm_runtime_put_sync(dev) do {} while (0)
#define pm_runtime_use_autosuspend(dev) do {} while (0)
#define pm_runtime_set_autosuspend_delay(dev, delay) do {} while (0)
#define pm_runtime_enable(dev) do {} while (0)
#define MODULE_DESCRIPTION(desc)
#define MODULE_AUTHOR(author)
#define MODULE_LICENSE(license)
#define MODULE_ALIAS(alias)
#define module_param(name, type, perm)
#define MODULE_PARM_DESC(name, desc)
#define EXPORT_SYMBOL_GPL(name)
#define writesl(a, d, s) __raw_writesl((unsigned long)a, d, s)
#define readsl(a, d, s) __raw_readsl((unsigned long)a, d, s)
#define writesw(a, d, s) __raw_writesw((unsigned long)a, d, s)
#define readsw(a, d, s) __raw_readsw((unsigned long)a, d, s)
#define writesb(a, d, s) __raw_writesb((unsigned long)a, d, s)
#define readsb(a, d, s) __raw_readsb((unsigned long)a, d, s)
#define IRQ_NONE 0
#define IRQ_HANDLED 0
#define dev_set_drvdata(dev, data) do {} while (0)
#define disable_irq_wake(irq) do {} while (0)
#define enable_irq_wake(irq) -EINVAL
#define free_irq(irq, data) do {} while (0)
#define request_irq(nr, f, flags, nm, data) 0
#define device_init_wakeup(dev, a) do {} while (0)
#define platform_data device_data
#ifndef wmb
#define wmb() asm volatile ("" : : : "memory")
#endif
#endif /* __LINUX_COMPAT_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,623 @@
/*
* MUSB OTG driver 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_CORE_H__
#define __MUSB_CORE_H__
#ifndef __UBOOT__
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/device.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>
#else
#include <asm/errno.h>
#endif
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/musb.h>
struct musb;
struct musb_hw_ep;
struct musb_ep;
/* Helper defines for struct musb->hwvers */
#define MUSB_HWVERS_MAJOR(x) ((x >> 10) & 0x1f)
#define MUSB_HWVERS_MINOR(x) (x & 0x3ff)
#define MUSB_HWVERS_RC 0x8000
#define MUSB_HWVERS_1300 0x52C
#define MUSB_HWVERS_1400 0x590
#define MUSB_HWVERS_1800 0x720
#define MUSB_HWVERS_1900 0x784
#define MUSB_HWVERS_2000 0x800
#include "musb_debug.h"
#include "musb_dma.h"
#include "musb_io.h"
#include "musb_regs.h"
#include "musb_gadget.h"
#ifndef __UBOOT__
#include <linux/usb/hcd.h>
#endif
#include "musb_host.h"
#define is_peripheral_enabled(musb) ((musb)->board_mode != MUSB_HOST)
#define is_host_enabled(musb) ((musb)->board_mode != MUSB_PERIPHERAL)
#define is_otg_enabled(musb) ((musb)->board_mode == MUSB_OTG)
/* NOTE: otg and peripheral-only state machines start at B_IDLE.
* OTG or host-only go to A_IDLE when ID is sensed.
*/
#define is_peripheral_active(m) (!(m)->is_host)
#define is_host_active(m) ((m)->is_host)
#ifdef CONFIG_PROC_FS
#include <linux/fs.h>
#define MUSB_CONFIG_PROC_FS
#endif
/****************************** PERIPHERAL ROLE *****************************/
#ifndef __UBOOT__
#define is_peripheral_capable() (1)
#else
#ifdef CONFIG_MUSB_GADGET
#define is_peripheral_capable() (1)
#else
#define is_peripheral_capable() (0)
#endif
#endif
extern irqreturn_t musb_g_ep0_irq(struct musb *);
extern void musb_g_tx(struct musb *, u8);
extern void musb_g_rx(struct musb *, u8);
extern void musb_g_reset(struct musb *);
extern void musb_g_suspend(struct musb *);
extern void musb_g_resume(struct musb *);
extern void musb_g_wakeup(struct musb *);
extern void musb_g_disconnect(struct musb *);
/****************************** HOST ROLE ***********************************/
#ifndef __UBOOT__
#define is_host_capable() (1)
#else
#ifdef CONFIG_MUSB_HOST
#define is_host_capable() (1)
#else
#define is_host_capable() (0)
#endif
#endif
extern irqreturn_t musb_h_ep0_irq(struct musb *);
extern void musb_host_tx(struct musb *, u8);
extern void musb_host_rx(struct musb *, u8);
/****************************** CONSTANTS ********************************/
#ifndef MUSB_C_NUM_EPS
#define MUSB_C_NUM_EPS ((u8)16)
#endif
#ifndef MUSB_MAX_END0_PACKET
#define MUSB_MAX_END0_PACKET ((u16)MUSB_EP0_FIFOSIZE)
#endif
/* host side ep0 states */
enum musb_h_ep0_state {
MUSB_EP0_IDLE,
MUSB_EP0_START, /* expect ack of setup */
MUSB_EP0_IN, /* expect IN DATA */
MUSB_EP0_OUT, /* expect ack of OUT DATA */
MUSB_EP0_STATUS, /* expect ack of STATUS */
} __attribute__ ((packed));
/* peripheral side ep0 states */
enum musb_g_ep0_state {
MUSB_EP0_STAGE_IDLE, /* idle, waiting for SETUP */
MUSB_EP0_STAGE_SETUP, /* received SETUP */
MUSB_EP0_STAGE_TX, /* IN data */
MUSB_EP0_STAGE_RX, /* OUT data */
MUSB_EP0_STAGE_STATUSIN, /* (after OUT data) */
MUSB_EP0_STAGE_STATUSOUT, /* (after IN data) */
MUSB_EP0_STAGE_ACKWAIT, /* after zlp, before statusin */
} __attribute__ ((packed));
/*
* OTG protocol constants. See USB OTG 1.3 spec,
* sections 5.5 "Device Timings" and 6.6.5 "Timers".
*/
#define OTG_TIME_A_WAIT_VRISE 100 /* msec (max) */
#define OTG_TIME_A_WAIT_BCON 1100 /* min 1 second */
#define OTG_TIME_A_AIDL_BDIS 200 /* min 200 msec */
#define OTG_TIME_B_ASE0_BRST 100 /* min 3.125 ms */
/*************************** REGISTER ACCESS ********************************/
/* Endpoint registers (other than dynfifo setup) can be accessed either
* directly with the "flat" model, or after setting up an index register.
*/
#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_SOC_OMAP2430) \
|| defined(CONFIG_SOC_OMAP3430) || defined(CONFIG_BLACKFIN) \
|| defined(CONFIG_ARCH_OMAP4)
/* REVISIT indexed access seemed to
* misbehave (on DaVinci) for at least peripheral IN ...
*/
#define MUSB_FLAT_REG
#endif
/* TUSB mapping: "flat" plus ep0 special cases */
#if defined(CONFIG_USB_MUSB_TUSB6010) || \
defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
#define musb_ep_select(_mbase, _epnum) \
musb_writeb((_mbase), MUSB_INDEX, (_epnum))
#define MUSB_EP_OFFSET MUSB_TUSB_OFFSET
/* "flat" mapping: each endpoint has its own i/o address */
#elif defined(MUSB_FLAT_REG)
#define musb_ep_select(_mbase, _epnum) (((void)(_mbase)), ((void)(_epnum)))
#define MUSB_EP_OFFSET MUSB_FLAT_OFFSET
/* "indexed" mapping: INDEX register controls register bank select */
#else
#define musb_ep_select(_mbase, _epnum) \
musb_writeb((_mbase), MUSB_INDEX, (_epnum))
#define MUSB_EP_OFFSET MUSB_INDEXED_OFFSET
#endif
/****************************** FUNCTIONS ********************************/
#define MUSB_HST_MODE(_musb)\
{ (_musb)->is_host = true; }
#define MUSB_DEV_MODE(_musb) \
{ (_musb)->is_host = false; }
#define test_devctl_hst_mode(_x) \
(musb_readb((_x)->mregs, MUSB_DEVCTL)&MUSB_DEVCTL_HM)
#define MUSB_MODE(musb) ((musb)->is_host ? "Host" : "Peripheral")
/******************************** TYPES *************************************/
/**
* struct musb_platform_ops - Operations passed to musb_core by HW glue layer
* @init: turns on clocks, sets up platform-specific registers, etc
* @exit: undoes @init
* @set_mode: forcefully changes operating mode
* @try_ilde: tries to idle the IP
* @vbus_status: returns vbus status if possible
* @set_vbus: forces vbus status
* @adjust_channel_params: pre check for standard dma channel_program func
*/
struct musb_platform_ops {
int (*init)(struct musb *musb);
int (*exit)(struct musb *musb);
void (*enable)(struct musb *musb);
void (*disable)(struct musb *musb);
int (*set_mode)(struct musb *musb, u8 mode);
void (*try_idle)(struct musb *musb, unsigned long timeout);
int (*vbus_status)(struct musb *musb);
void (*set_vbus)(struct musb *musb, int on);
int (*adjust_channel_params)(struct dma_channel *channel,
u16 packet_sz, u8 *mode,
dma_addr_t *dma_addr, u32 *len);
};
/*
* struct musb_hw_ep - endpoint hardware (bidirectional)
*
* Ordered slightly for better cacheline locality.
*/
struct musb_hw_ep {
struct musb *musb;
void __iomem *fifo;
void __iomem *regs;
#if defined(CONFIG_USB_MUSB_TUSB6010) || \
defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
void __iomem *conf;
#endif
/* index in musb->endpoints[] */
u8 epnum;
/* hardware configuration, possibly dynamic */
bool is_shared_fifo;
bool tx_double_buffered;
bool rx_double_buffered;
u16 max_packet_sz_tx;
u16 max_packet_sz_rx;
struct dma_channel *tx_channel;
struct dma_channel *rx_channel;
#if defined(CONFIG_USB_MUSB_TUSB6010) || \
defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
/* TUSB has "asynchronous" and "synchronous" dma modes */
dma_addr_t fifo_async;
dma_addr_t fifo_sync;
void __iomem *fifo_sync_va;
#endif
void __iomem *target_regs;
/* currently scheduled peripheral endpoint */
struct musb_qh *in_qh;
struct musb_qh *out_qh;
u8 rx_reinit;
u8 tx_reinit;
/* peripheral side */
struct musb_ep ep_in; /* TX */
struct musb_ep ep_out; /* RX */
};
static inline struct musb_request *next_in_request(struct musb_hw_ep *hw_ep)
{
return next_request(&hw_ep->ep_in);
}
static inline struct musb_request *next_out_request(struct musb_hw_ep *hw_ep)
{
return next_request(&hw_ep->ep_out);
}
struct musb_csr_regs {
/* FIFO registers */
u16 txmaxp, txcsr, rxmaxp, rxcsr;
u16 rxfifoadd, txfifoadd;
u8 txtype, txinterval, rxtype, rxinterval;
u8 rxfifosz, txfifosz;
u8 txfunaddr, txhubaddr, txhubport;
u8 rxfunaddr, rxhubaddr, rxhubport;
};
struct musb_context_registers {
u8 power;
u16 intrtxe, intrrxe;
u8 intrusbe;
u16 frame;
u8 index, testmode;
u8 devctl, busctl, misc;
u32 otg_interfsel;
struct musb_csr_regs index_regs[MUSB_C_NUM_EPS];
};
/*
* struct musb - Driver instance data.
*/
struct musb {
/* device lock */
spinlock_t lock;
const struct musb_platform_ops *ops;
struct musb_context_registers context;
irqreturn_t (*isr)(int, void *);
struct work_struct irq_work;
u16 hwvers;
/* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
#define MUSB_PORT_STAT_RESUME (1 << 31)
u32 port1_status;
unsigned long rh_timer;
enum musb_h_ep0_state ep0_stage;
/* bulk traffic normally dedicates endpoint hardware, and each
* direction has its own ring of host side endpoints.
* we try to progress the transfer at the head of each endpoint's
* queue until it completes or NAKs too much; then we try the next
* endpoint.
*/
struct musb_hw_ep *bulk_ep;
struct list_head control; /* of musb_qh */
struct list_head in_bulk; /* of musb_qh */
struct list_head out_bulk; /* of musb_qh */
struct timer_list otg_timer;
struct notifier_block nb;
struct dma_controller *dma_controller;
struct device *controller;
void __iomem *ctrl_base;
void __iomem *mregs;
#if defined(CONFIG_USB_MUSB_TUSB6010) || \
defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
dma_addr_t async;
dma_addr_t sync;
void __iomem *sync_va;
#endif
/* passed down from chip/board specific irq handlers */
u8 int_usb;
u16 int_rx;
u16 int_tx;
struct usb_phy *xceiv;
int nIrq;
unsigned irq_wake:1;
struct musb_hw_ep endpoints[MUSB_C_NUM_EPS];
#define control_ep endpoints
#define VBUSERR_RETRY_COUNT 3
u16 vbuserr_retry;
u16 epmask;
u8 nr_endpoints;
u8 board_mode; /* enum musb_mode */
int (*board_set_power)(int state);
u8 min_power; /* vbus for periph, in mA/2 */
bool is_host;
int a_wait_bcon; /* VBUS timeout in msecs */
unsigned long idle_timeout; /* Next timeout in jiffies */
/* active means connected and not suspended */
unsigned is_active:1;
unsigned is_multipoint:1;
unsigned ignore_disconnect:1; /* during bus resets */
unsigned hb_iso_rx:1; /* high bandwidth iso rx? */
unsigned hb_iso_tx:1; /* high bandwidth iso tx? */
unsigned dyn_fifo:1; /* dynamic FIFO supported? */
unsigned bulk_split:1;
#define can_bulk_split(musb,type) \
(((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_split)
unsigned bulk_combine:1;
#define can_bulk_combine(musb,type) \
(((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine)
/* is_suspended means USB B_PERIPHERAL suspend */
unsigned is_suspended:1;
/* may_wakeup means remote wakeup is enabled */
unsigned may_wakeup:1;
/* is_self_powered is reported in device status and the
* config descriptor. is_bus_powered means B_PERIPHERAL
* draws some VBUS current; both can be true.
*/
unsigned is_self_powered:1;
unsigned is_bus_powered:1;
unsigned set_address:1;
unsigned test_mode:1;
unsigned softconnect:1;
u8 address;
u8 test_mode_nr;
u16 ackpend; /* ep0 */
enum musb_g_ep0_state ep0_state;
struct usb_gadget g; /* the gadget */
struct usb_gadget_driver *gadget_driver; /* its driver */
/*
* FIXME: Remove this flag.
*
* This is only added to allow Blackfin to work
* with current driver. For some unknown reason
* Blackfin doesn't work with double buffering
* and that's enabled by default.
*
* We added this flag to forcefully disable double
* buffering until we get it working.
*/
unsigned double_buffer_not_ok:1;
struct musb_hdrc_config *config;
#ifdef MUSB_CONFIG_PROC_FS
struct proc_dir_entry *proc_entry;
#endif
};
static inline struct musb *gadget_to_musb(struct usb_gadget *g)
{
return container_of(g, struct musb, g);
}
#ifdef CONFIG_BLACKFIN
static inline int musb_read_fifosize(struct musb *musb,
struct musb_hw_ep *hw_ep, u8 epnum)
{
musb->nr_endpoints++;
musb->epmask |= (1 << epnum);
if (epnum < 5) {
hw_ep->max_packet_sz_tx = 128;
hw_ep->max_packet_sz_rx = 128;
} else {
hw_ep->max_packet_sz_tx = 1024;
hw_ep->max_packet_sz_rx = 1024;
}
hw_ep->is_shared_fifo = false;
return 0;
}
static inline void musb_configure_ep0(struct musb *musb)
{
musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE;
musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE;
musb->endpoints[0].is_shared_fifo = true;
}
#else
static inline int musb_read_fifosize(struct musb *musb,
struct musb_hw_ep *hw_ep, u8 epnum)
{
void *mbase = musb->mregs;
u8 reg = 0;
/* read from core using indexed model */
reg = musb_readb(mbase, MUSB_EP_OFFSET(epnum, MUSB_FIFOSIZE));
/* 0's returned when no more endpoints */
if (!reg)
return -ENODEV;
musb->nr_endpoints++;
musb->epmask |= (1 << epnum);
hw_ep->max_packet_sz_tx = 1 << (reg & 0x0f);
/* shared TX/RX FIFO? */
if ((reg & 0xf0) == 0xf0) {
hw_ep->max_packet_sz_rx = hw_ep->max_packet_sz_tx;
hw_ep->is_shared_fifo = true;
return 0;
} else {
hw_ep->max_packet_sz_rx = 1 << ((reg & 0xf0) >> 4);
hw_ep->is_shared_fifo = false;
}
return 0;
}
static inline void musb_configure_ep0(struct musb *musb)
{
musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE;
musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE;
musb->endpoints[0].is_shared_fifo = true;
}
#endif /* CONFIG_BLACKFIN */
/***************************** Glue it together *****************************/
extern const char musb_driver_name[];
extern void musb_start(struct musb *musb);
extern void musb_stop(struct musb *musb);
extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src);
extern void musb_read_fifo(struct musb_hw_ep *ep, u16 len, u8 *dst);
extern void musb_load_testpacket(struct musb *);
extern irqreturn_t musb_interrupt(struct musb *);
extern void musb_hnp_stop(struct musb *musb);
static inline void musb_platform_set_vbus(struct musb *musb, int is_on)
{
if (musb->ops->set_vbus)
musb->ops->set_vbus(musb, is_on);
}
static inline void musb_platform_enable(struct musb *musb)
{
if (musb->ops->enable)
musb->ops->enable(musb);
}
static inline void musb_platform_disable(struct musb *musb)
{
if (musb->ops->disable)
musb->ops->disable(musb);
}
static inline int musb_platform_set_mode(struct musb *musb, u8 mode)
{
if (!musb->ops->set_mode)
return 0;
return musb->ops->set_mode(musb, mode);
}
static inline void musb_platform_try_idle(struct musb *musb,
unsigned long timeout)
{
if (musb->ops->try_idle)
musb->ops->try_idle(musb, timeout);
}
static inline int musb_platform_get_vbus_status(struct musb *musb)
{
if (!musb->ops->vbus_status)
return 0;
return musb->ops->vbus_status(musb);
}
static inline int musb_platform_init(struct musb *musb)
{
if (!musb->ops->init)
return -EINVAL;
return musb->ops->init(musb);
}
static inline int musb_platform_exit(struct musb *musb)
{
if (!musb->ops->exit)
return -EINVAL;
return musb->ops->exit(musb);
}
#ifdef __UBOOT__
struct musb *
musb_init_controller(struct musb_hdrc_platform_data *plat, struct device *dev,
void *ctrl);
#endif
#endif /* __MUSB_CORE_H__ */

View File

@ -0,0 +1,58 @@
/*
* 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)
#ifdef CONFIG_DEBUG_FS
int musb_init_debugfs(struct musb *musb);
void musb_exit_debugfs(struct musb *musb);
#else
static inline int musb_init_debugfs(struct musb *musb)
{
return 0;
}
static inline void musb_exit_debugfs(struct musb *musb)
{
}
#endif
#endif /* __MUSB_LINUX_DEBUG_H__ */

View File

@ -0,0 +1,186 @@
/*
* MUSB OTG driver DMA controller abstraction
*
* 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_DMA_H__
#define __MUSB_DMA_H__
struct musb_hw_ep;
/*
* DMA Controller Abstraction
*
* DMA Controllers are abstracted to allow use of a variety of different
* implementations of DMA, as allowed by the Inventra USB cores. On the
* host side, usbcore sets up the DMA mappings and flushes caches; on the
* peripheral side, the gadget controller driver does. Responsibilities
* of a DMA controller driver include:
*
* - Handling the details of moving multiple USB packets
* in cooperation with the Inventra USB core, including especially
* the correct RX side treatment of short packets and buffer-full
* states (both of which terminate transfers).
*
* - Knowing the correlation between dma channels and the
* Inventra core's local endpoint resources and data direction.
*
* - Maintaining a list of allocated/available channels.
*
* - Updating channel status on interrupts,
* whether shared with the Inventra core or separate.
*/
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#ifndef CONFIG_MUSB_PIO_ONLY
#define is_dma_capable() (1)
#else
#define is_dma_capable() (0)
#endif
#ifdef CONFIG_USB_TI_CPPI_DMA
#define is_cppi_enabled() 1
#else
#define is_cppi_enabled() 0
#endif
#ifdef CONFIG_USB_TUSB_OMAP_DMA
#define tusb_dma_omap() 1
#else
#define tusb_dma_omap() 0
#endif
/* Anomaly 05000456 - USB Receive Interrupt Is Not Generated in DMA Mode 1
* Only allow DMA mode 1 to be used when the USB will actually generate the
* interrupts we expect.
*/
#ifdef CONFIG_BLACKFIN
# undef USE_MODE1
# if !ANOMALY_05000456
# define USE_MODE1
# endif
#endif
/*
* DMA channel status ... updated by the dma controller driver whenever that
* status changes, and protected by the overall controller spinlock.
*/
enum dma_channel_status {
/* unallocated */
MUSB_DMA_STATUS_UNKNOWN,
/* allocated ... but not busy, no errors */
MUSB_DMA_STATUS_FREE,
/* busy ... transactions are active */
MUSB_DMA_STATUS_BUSY,
/* transaction(s) aborted due to ... dma or memory bus error */
MUSB_DMA_STATUS_BUS_ABORT,
/* transaction(s) aborted due to ... core error or USB fault */
MUSB_DMA_STATUS_CORE_ABORT
};
struct dma_controller;
/**
* struct dma_channel - A DMA channel.
* @private_data: channel-private data
* @max_len: the maximum number of bytes the channel can move in one
* transaction (typically representing many USB maximum-sized packets)
* @actual_len: how many bytes have been transferred
* @status: current channel status (updated e.g. on interrupt)
* @desired_mode: true if mode 1 is desired; false if mode 0 is desired
*
* channels are associated with an endpoint for the duration of at least
* one usb transfer.
*/
struct dma_channel {
void *private_data;
/* FIXME not void* private_data, but a dma_controller * */
size_t max_len;
size_t actual_len;
enum dma_channel_status status;
bool desired_mode;
};
/*
* dma_channel_status - return status of dma channel
* @c: the channel
*
* Returns the software's view of the channel status. If that status is BUSY
* then it's possible that the hardware has completed (or aborted) a transfer,
* so the driver needs to update that status.
*/
static inline enum dma_channel_status
dma_channel_status(struct dma_channel *c)
{
return (is_dma_capable() && c) ? c->status : MUSB_DMA_STATUS_UNKNOWN;
}
/**
* struct dma_controller - A DMA Controller.
* @start: call this to start a DMA controller;
* return 0 on success, else negative errno
* @stop: call this to stop a DMA controller
* return 0 on success, else negative errno
* @channel_alloc: call this to allocate a DMA channel
* @channel_release: call this to release a DMA channel
* @channel_abort: call this to abort a pending DMA transaction,
* returning it to FREE (but allocated) state
*
* Controllers manage dma channels.
*/
struct dma_controller {
int (*start)(struct dma_controller *);
int (*stop)(struct dma_controller *);
struct dma_channel *(*channel_alloc)(struct dma_controller *,
struct musb_hw_ep *, u8 is_tx);
void (*channel_release)(struct dma_channel *);
int (*channel_program)(struct dma_channel *channel,
u16 maxpacket, u8 mode,
dma_addr_t dma_addr,
u32 length);
int (*channel_abort)(struct dma_channel *);
int (*is_compatible)(struct dma_channel *channel,
u16 maxpacket,
void *buf, u32 length);
};
/* called after channel_program(), may indicate a fault */
extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit);
extern struct dma_controller *__init
dma_controller_create(struct musb *, void __iomem *);
extern void dma_controller_destroy(struct dma_controller *);
#endif /* __MUSB_DMA_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,130 @@
/*
* 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
#include <linux/list.h>
#ifdef __UBOOT__
#include <asm/byteorder.h>
#include <asm/errno.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#endif
enum buffer_map_state {
UN_MAPPED = 0,
PRE_MAPPED,
MUSB_MAPPED
};
struct musb_request {
struct usb_request request;
struct list_head list;
struct musb_ep *ep;
struct musb *musb;
u8 tx; /* endpoint direction */
u8 epnum;
enum buffer_map_state map_state;
};
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;
u8 wedged;
/* true if lock must be dropped but req_list may not be advanced */
u8 busy;
u8 hb_mult;
};
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 musb_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 musb_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 void musb_ep_restart(struct musb *, struct musb_request *);
#ifdef __UBOOT__
int musb_gadget_start(struct usb_gadget *g, struct usb_gadget_driver *driver);
#endif
#endif /* __MUSB_GADGET_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,114 @@
/*
* MUSB OTG driver host 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_HOST_H
#define _MUSB_HOST_H
#ifdef __UBOOT__
#include "usb-compat.h"
#endif
static inline struct usb_hcd *musb_to_hcd(struct musb *musb)
{
return container_of((void *) musb, struct usb_hcd, hcd_priv);
}
static inline struct musb *hcd_to_musb(struct usb_hcd *hcd)
{
return (struct musb *) (hcd->hcd_priv);
}
/* stored in "usb_host_endpoint.hcpriv" for scheduled endpoints */
struct musb_qh {
struct usb_host_endpoint *hep; /* usbcore info */
struct usb_device *dev;
struct musb_hw_ep *hw_ep; /* current binding */
struct list_head ring; /* of musb_qh */
/* struct musb_qh *next; */ /* for periodic tree */
u8 mux; /* qh multiplexed to hw_ep */
unsigned offset; /* in urb->transfer_buffer */
unsigned segsize; /* current xfer fragment */
u8 type_reg; /* {rx,tx} type register */
u8 intv_reg; /* {rx,tx} interval register */
u8 addr_reg; /* device address register */
u8 h_addr_reg; /* hub address register */
u8 h_port_reg; /* hub port register */
u8 is_ready; /* safe to modify hw_ep */
u8 type; /* XFERTYPE_* */
u8 epnum;
u8 hb_mult; /* high bandwidth pkts per uf */
u16 maxpacket;
u16 frame; /* for periodic schedule */
unsigned iso_idx; /* in urb->iso_frame_desc[] */
};
/* map from control or bulk queue head to the first qh on that ring */
static inline struct musb_qh *first_qh(struct list_head *q)
{
if (list_empty(q))
return NULL;
return list_entry(q->next, struct musb_qh, ring);
}
extern void musb_root_disconnect(struct musb *musb);
struct usb_hcd;
extern int musb_hub_status_data(struct usb_hcd *hcd, char *buf);
extern int musb_hub_control(struct usb_hcd *hcd,
u16 typeReq, u16 wValue, u16 wIndex,
char *buf, u16 wLength);
extern const struct hc_driver musb_hc_driver;
static inline struct urb *next_urb(struct musb_qh *qh)
{
struct list_head *queue;
if (!qh)
return NULL;
queue = &qh->hep->urb_list;
if (list_empty(queue))
return NULL;
return list_entry(queue->next, struct urb, urb_list);
}
#ifdef __UBOOT__
int musb_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
#endif
#endif /* _MUSB_HOST_H */

View File

@ -0,0 +1,146 @@
/*
* MUSB OTG driver register I/O
*
* 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_PLATFORM_ARCH_H__
#define __MUSB_LINUX_PLATFORM_ARCH_H__
#ifndef __UBOOT__
#include <linux/io.h>
#else
#include <asm/io.h>
#endif
#if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \
&& !defined(CONFIG_AVR32) && !defined(CONFIG_PPC32) \
&& !defined(CONFIG_PPC64) && !defined(CONFIG_BLACKFIN) \
&& !defined(CONFIG_MIPS) && !defined(CONFIG_M68K)
static inline void readsl(const void __iomem *addr, void *buf, int len)
{ insl((unsigned long)addr, buf, len); }
static inline void readsw(const void __iomem *addr, void *buf, int len)
{ insw((unsigned long)addr, buf, len); }
static inline void readsb(const void __iomem *addr, void *buf, int len)
{ insb((unsigned long)addr, buf, len); }
static inline void writesl(const void __iomem *addr, const void *buf, int len)
{ outsl((unsigned long)addr, buf, len); }
static inline void writesw(const void __iomem *addr, const void *buf, int len)
{ outsw((unsigned long)addr, buf, len); }
static inline void writesb(const void __iomem *addr, const void *buf, int len)
{ outsb((unsigned long)addr, buf, len); }
#endif
#ifndef CONFIG_BLACKFIN
/* NOTE: these offsets are all in bytes */
static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
{ return __raw_readw(addr + offset); }
static inline u32 musb_readl(const void __iomem *addr, unsigned offset)
{ return __raw_readl(addr + offset); }
static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data)
{ __raw_writew(data, addr + offset); }
static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
{ __raw_writel(data, addr + offset); }
#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE)
/*
* TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum.
*/
static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
{
u16 tmp;
u8 val;
tmp = __raw_readw(addr + (offset & ~1));
if (offset & 1)
val = (tmp >> 8);
else
val = tmp & 0xff;
return val;
}
static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
{
u16 tmp;
tmp = __raw_readw(addr + (offset & ~1));
if (offset & 1)
tmp = (data << 8) | (tmp & 0xff);
else
tmp = (tmp & 0xff00) | data;
__raw_writew(tmp, addr + (offset & ~1));
}
#else
static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
{ return __raw_readb(addr + offset); }
static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
{ __raw_writeb(data, addr + offset); }
#endif /* CONFIG_USB_MUSB_TUSB6010 */
#else
static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
{ return (u8) (bfin_read16(addr + offset)); }
static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
{ return bfin_read16(addr + offset); }
static inline u32 musb_readl(const void __iomem *addr, unsigned offset)
{ return (u32) (bfin_read16(addr + offset)); }
static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
{ bfin_write16(addr + offset, (u16) data); }
static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data)
{ bfin_write16(addr + offset, data); }
static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
{ bfin_write16(addr + offset, (u16) data); }
#endif /* CONFIG_BLACKFIN */
#endif

View File

@ -0,0 +1,645 @@
/*
* MUSB OTG driver register 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_REGS_H__
#define __MUSB_REGS_H__
#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */
/*
* MUSB Register bits
*/
/* POWER */
#define MUSB_POWER_ISOUPDATE 0x80
#define MUSB_POWER_SOFTCONN 0x40
#define MUSB_POWER_HSENAB 0x20
#define MUSB_POWER_HSMODE 0x10
#define MUSB_POWER_RESET 0x08
#define MUSB_POWER_RESUME 0x04
#define MUSB_POWER_SUSPENDM 0x02
#define MUSB_POWER_ENSUSPEND 0x01
/* INTRUSB */
#define MUSB_INTR_SUSPEND 0x01
#define MUSB_INTR_RESUME 0x02
#define MUSB_INTR_RESET 0x04
#define MUSB_INTR_BABBLE 0x04
#define MUSB_INTR_SOF 0x08
#define MUSB_INTR_CONNECT 0x10
#define MUSB_INTR_DISCONNECT 0x20
#define MUSB_INTR_SESSREQ 0x40
#define MUSB_INTR_VBUSERROR 0x80 /* For SESSION end */
/* DEVCTL */
#define MUSB_DEVCTL_BDEVICE 0x80
#define MUSB_DEVCTL_FSDEV 0x40
#define MUSB_DEVCTL_LSDEV 0x20
#define MUSB_DEVCTL_VBUS 0x18
#define MUSB_DEVCTL_VBUS_SHIFT 3
#define MUSB_DEVCTL_HM 0x04
#define MUSB_DEVCTL_HR 0x02
#define MUSB_DEVCTL_SESSION 0x01
/* MUSB ULPI VBUSCONTROL */
#define MUSB_ULPI_USE_EXTVBUS 0x01
#define MUSB_ULPI_USE_EXTVBUSIND 0x02
/* ULPI_REG_CONTROL */
#define MUSB_ULPI_REG_REQ (1 << 0)
#define MUSB_ULPI_REG_CMPLT (1 << 1)
#define MUSB_ULPI_RDN_WR (1 << 2)
/* TESTMODE */
#define MUSB_TEST_FORCE_HOST 0x80
#define MUSB_TEST_FIFO_ACCESS 0x40
#define MUSB_TEST_FORCE_FS 0x20
#define MUSB_TEST_FORCE_HS 0x10
#define MUSB_TEST_PACKET 0x08
#define MUSB_TEST_K 0x04
#define MUSB_TEST_J 0x02
#define MUSB_TEST_SE0_NAK 0x01
/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */
#define MUSB_FIFOSZ_DPB 0x10
/* Allocation size (8, 16, 32, ... 4096) */
#define MUSB_FIFOSZ_SIZE 0x0f
/* CSR0 */
#define MUSB_CSR0_FLUSHFIFO 0x0100
#define MUSB_CSR0_TXPKTRDY 0x0002
#define MUSB_CSR0_RXPKTRDY 0x0001
/* CSR0 in Peripheral mode */
#define MUSB_CSR0_P_SVDSETUPEND 0x0080
#define MUSB_CSR0_P_SVDRXPKTRDY 0x0040
#define MUSB_CSR0_P_SENDSTALL 0x0020
#define MUSB_CSR0_P_SETUPEND 0x0010
#define MUSB_CSR0_P_DATAEND 0x0008
#define MUSB_CSR0_P_SENTSTALL 0x0004
/* CSR0 in Host mode */
#define MUSB_CSR0_H_DIS_PING 0x0800
#define MUSB_CSR0_H_WR_DATATOGGLE 0x0400 /* Set to allow setting: */
#define MUSB_CSR0_H_DATATOGGLE 0x0200 /* Data toggle control */
#define MUSB_CSR0_H_NAKTIMEOUT 0x0080
#define MUSB_CSR0_H_STATUSPKT 0x0040
#define MUSB_CSR0_H_REQPKT 0x0020
#define MUSB_CSR0_H_ERROR 0x0010
#define MUSB_CSR0_H_SETUPPKT 0x0008
#define MUSB_CSR0_H_RXSTALL 0x0004
/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */
#define MUSB_CSR0_P_WZC_BITS \
(MUSB_CSR0_P_SENTSTALL)
#define MUSB_CSR0_H_WZC_BITS \
(MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \
| MUSB_CSR0_RXPKTRDY)
/* TxType/RxType */
#define MUSB_TYPE_SPEED 0xc0
#define MUSB_TYPE_SPEED_SHIFT 6
#define MUSB_TYPE_PROTO 0x30 /* Implicitly zero for ep0 */
#define MUSB_TYPE_PROTO_SHIFT 4
#define MUSB_TYPE_REMOTE_END 0xf /* Implicitly zero for ep0 */
/* CONFIGDATA */
#define MUSB_CONFIGDATA_MPRXE 0x80 /* Auto bulk pkt combining */
#define MUSB_CONFIGDATA_MPTXE 0x40 /* Auto bulk pkt splitting */
#define MUSB_CONFIGDATA_BIGENDIAN 0x20
#define MUSB_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */
#define MUSB_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */
#define MUSB_CONFIGDATA_DYNFIFO 0x04 /* Dynamic FIFO sizing */
#define MUSB_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */
#define MUSB_CONFIGDATA_UTMIDW 0x01 /* Data width 0/1 => 8/16bits */
/* TXCSR in Peripheral and Host mode */
#define MUSB_TXCSR_AUTOSET 0x8000
#define MUSB_TXCSR_DMAENAB 0x1000
#define MUSB_TXCSR_FRCDATATOG 0x0800
#define MUSB_TXCSR_DMAMODE 0x0400
#define MUSB_TXCSR_CLRDATATOG 0x0040
#define MUSB_TXCSR_FLUSHFIFO 0x0008
#define MUSB_TXCSR_FIFONOTEMPTY 0x0002
#define MUSB_TXCSR_TXPKTRDY 0x0001
/* TXCSR in Peripheral mode */
#define MUSB_TXCSR_P_ISO 0x4000
#define MUSB_TXCSR_P_INCOMPTX 0x0080
#define MUSB_TXCSR_P_SENTSTALL 0x0020
#define MUSB_TXCSR_P_SENDSTALL 0x0010
#define MUSB_TXCSR_P_UNDERRUN 0x0004
/* TXCSR in Host mode */
#define MUSB_TXCSR_H_WR_DATATOGGLE 0x0200
#define MUSB_TXCSR_H_DATATOGGLE 0x0100
#define MUSB_TXCSR_H_NAKTIMEOUT 0x0080
#define MUSB_TXCSR_H_RXSTALL 0x0020
#define MUSB_TXCSR_H_ERROR 0x0004
/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
#define MUSB_TXCSR_P_WZC_BITS \
(MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \
| MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY)
#define MUSB_TXCSR_H_WZC_BITS \
(MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \
| MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY)
/* RXCSR in Peripheral and Host mode */
#define MUSB_RXCSR_AUTOCLEAR 0x8000
#define MUSB_RXCSR_DMAENAB 0x2000
#define MUSB_RXCSR_DISNYET 0x1000
#define MUSB_RXCSR_PID_ERR 0x1000
#define MUSB_RXCSR_DMAMODE 0x0800
#define MUSB_RXCSR_INCOMPRX 0x0100
#define MUSB_RXCSR_CLRDATATOG 0x0080
#define MUSB_RXCSR_FLUSHFIFO 0x0010
#define MUSB_RXCSR_DATAERROR 0x0008
#define MUSB_RXCSR_FIFOFULL 0x0002
#define MUSB_RXCSR_RXPKTRDY 0x0001
/* RXCSR in Peripheral mode */
#define MUSB_RXCSR_P_ISO 0x4000
#define MUSB_RXCSR_P_SENTSTALL 0x0040
#define MUSB_RXCSR_P_SENDSTALL 0x0020
#define MUSB_RXCSR_P_OVERRUN 0x0004
/* RXCSR in Host mode */
#define MUSB_RXCSR_H_AUTOREQ 0x4000
#define MUSB_RXCSR_H_WR_DATATOGGLE 0x0400
#define MUSB_RXCSR_H_DATATOGGLE 0x0200
#define MUSB_RXCSR_H_RXSTALL 0x0040
#define MUSB_RXCSR_H_REQPKT 0x0020
#define MUSB_RXCSR_H_ERROR 0x0004
/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
#define MUSB_RXCSR_P_WZC_BITS \
(MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \
| MUSB_RXCSR_RXPKTRDY)
#define MUSB_RXCSR_H_WZC_BITS \
(MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \
| MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY)
/* HUBADDR */
#define MUSB_HUBADDR_MULTI_TT 0x80
#ifndef CONFIG_BLACKFIN
/*
* Common USB registers
*/
#define MUSB_FADDR 0x00 /* 8-bit */
#define MUSB_POWER 0x01 /* 8-bit */
#define MUSB_INTRTX 0x02 /* 16-bit */
#define MUSB_INTRRX 0x04
#define MUSB_INTRTXE 0x06
#define MUSB_INTRRXE 0x08
#define MUSB_INTRUSB 0x0A /* 8 bit */
#define MUSB_INTRUSBE 0x0B /* 8 bit */
#define MUSB_FRAME 0x0C
#define MUSB_INDEX 0x0E /* 8 bit */
#define MUSB_TESTMODE 0x0F /* 8 bit */
/* Get offset for a given FIFO from musb->mregs */
#if defined(CONFIG_USB_MUSB_TUSB6010) || \
defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20))
#else
#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4))
#endif
/*
* Additional Control Registers
*/
#define MUSB_DEVCTL 0x60 /* 8 bit */
/* These are always controlled through the INDEX register */
#define MUSB_TXFIFOSZ 0x62 /* 8-bit (see masks) */
#define MUSB_RXFIFOSZ 0x63 /* 8-bit (see masks) */
#define MUSB_TXFIFOADD 0x64 /* 16-bit offset shifted right 3 */
#define MUSB_RXFIFOADD 0x66 /* 16-bit offset shifted right 3 */
/* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */
#define MUSB_HWVERS 0x6C /* 8 bit */
#define MUSB_ULPI_BUSCONTROL 0x70 /* 8 bit */
#define MUSB_ULPI_INT_MASK 0x72 /* 8 bit */
#define MUSB_ULPI_INT_SRC 0x73 /* 8 bit */
#define MUSB_ULPI_REG_DATA 0x74 /* 8 bit */
#define MUSB_ULPI_REG_ADDR 0x75 /* 8 bit */
#define MUSB_ULPI_REG_CONTROL 0x76 /* 8 bit */
#define MUSB_ULPI_RAW_DATA 0x77 /* 8 bit */
#define MUSB_EPINFO 0x78 /* 8 bit */
#define MUSB_RAMINFO 0x79 /* 8 bit */
#define MUSB_LINKINFO 0x7a /* 8 bit */
#define MUSB_VPLEN 0x7b /* 8 bit */
#define MUSB_HS_EOF1 0x7c /* 8 bit */
#define MUSB_FS_EOF1 0x7d /* 8 bit */
#define MUSB_LS_EOF1 0x7e /* 8 bit */
/* Offsets to endpoint registers */
#define MUSB_TXMAXP 0x00
#define MUSB_TXCSR 0x02
#define MUSB_CSR0 MUSB_TXCSR /* Re-used for EP0 */
#define MUSB_RXMAXP 0x04
#define MUSB_RXCSR 0x06
#define MUSB_RXCOUNT 0x08
#define MUSB_COUNT0 MUSB_RXCOUNT /* Re-used for EP0 */
#define MUSB_TXTYPE 0x0A
#define MUSB_TYPE0 MUSB_TXTYPE /* Re-used for EP0 */
#define MUSB_TXINTERVAL 0x0B
#define MUSB_NAKLIMIT0 MUSB_TXINTERVAL /* Re-used for EP0 */
#define MUSB_RXTYPE 0x0C
#define MUSB_RXINTERVAL 0x0D
#define MUSB_FIFOSIZE 0x0F
#define MUSB_CONFIGDATA MUSB_FIFOSIZE /* Re-used for EP0 */
/* Offsets to endpoint registers in indexed model (using INDEX register) */
#define MUSB_INDEXED_OFFSET(_epnum, _offset) \
(0x10 + (_offset))
/* Offsets to endpoint registers in flat models */
#define MUSB_FLAT_OFFSET(_epnum, _offset) \
(0x100 + (0x10*(_epnum)) + (_offset))
#if defined(CONFIG_USB_MUSB_TUSB6010) || \
defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
/* TUSB6010 EP0 configuration register is special */
#define MUSB_TUSB_OFFSET(_epnum, _offset) \
(0x10 + _offset)
#include "tusb6010.h" /* Needed "only" for TUSB_EP0_CONF */
#endif
#define MUSB_TXCSR_MODE 0x2000
/* "bus control"/target registers, for host side multipoint (external hubs) */
#define MUSB_TXFUNCADDR 0x00
#define MUSB_TXHUBADDR 0x02
#define MUSB_TXHUBPORT 0x03
#define MUSB_RXFUNCADDR 0x04
#define MUSB_RXHUBADDR 0x06
#define MUSB_RXHUBPORT 0x07
#define MUSB_BUSCTL_OFFSET(_epnum, _offset) \
(0x80 + (8*(_epnum)) + (_offset))
static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size)
{
musb_writeb(mbase, MUSB_TXFIFOSZ, c_size);
}
static inline void musb_write_txfifoadd(void __iomem *mbase, u16 c_off)
{
musb_writew(mbase, MUSB_TXFIFOADD, c_off);
}
static inline void musb_write_rxfifosz(void __iomem *mbase, u8 c_size)
{
musb_writeb(mbase, MUSB_RXFIFOSZ, c_size);
}
static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
{
musb_writew(mbase, MUSB_RXFIFOADD, c_off);
}
static inline void musb_write_ulpi_buscontrol(void __iomem *mbase, u8 val)
{
musb_writeb(mbase, MUSB_ULPI_BUSCONTROL, val);
}
static inline u8 musb_read_txfifosz(void __iomem *mbase)
{
return musb_readb(mbase, MUSB_TXFIFOSZ);
}
static inline u16 musb_read_txfifoadd(void __iomem *mbase)
{
return musb_readw(mbase, MUSB_TXFIFOADD);
}
static inline u8 musb_read_rxfifosz(void __iomem *mbase)
{
return musb_readb(mbase, MUSB_RXFIFOSZ);
}
static inline u16 musb_read_rxfifoadd(void __iomem *mbase)
{
return musb_readw(mbase, MUSB_RXFIFOADD);
}
static inline u8 musb_read_ulpi_buscontrol(void __iomem *mbase)
{
return musb_readb(mbase, MUSB_ULPI_BUSCONTROL);
}
static inline u8 musb_read_configdata(void __iomem *mbase)
{
musb_writeb(mbase, MUSB_INDEX, 0);
return musb_readb(mbase, 0x10 + MUSB_CONFIGDATA);
}
static inline u16 musb_read_hwvers(void __iomem *mbase)
{
return musb_readw(mbase, MUSB_HWVERS);
}
static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase)
{
return (MUSB_BUSCTL_OFFSET(i, 0) + mbase);
}
static inline void musb_write_rxfunaddr(void __iomem *ep_target_regs,
u8 qh_addr_reg)
{
musb_writeb(ep_target_regs, MUSB_RXFUNCADDR, qh_addr_reg);
}
static inline void musb_write_rxhubaddr(void __iomem *ep_target_regs,
u8 qh_h_addr_reg)
{
musb_writeb(ep_target_regs, MUSB_RXHUBADDR, qh_h_addr_reg);
}
static inline void musb_write_rxhubport(void __iomem *ep_target_regs,
u8 qh_h_port_reg)
{
musb_writeb(ep_target_regs, MUSB_RXHUBPORT, qh_h_port_reg);
}
static inline void musb_write_txfunaddr(void __iomem *mbase, u8 epnum,
u8 qh_addr_reg)
{
musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR),
qh_addr_reg);
}
static inline void musb_write_txhubaddr(void __iomem *mbase, u8 epnum,
u8 qh_addr_reg)
{
musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR),
qh_addr_reg);
}
static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum,
u8 qh_h_port_reg)
{
musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT),
qh_h_port_reg);
}
static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum)
{
return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXFUNCADDR));
}
static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum)
{
return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBADDR));
}
static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum)
{
return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBPORT));
}
static inline u8 musb_read_txfunaddr(void __iomem *mbase, u8 epnum)
{
return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR));
}
static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum)
{
return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR));
}
static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum)
{
return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT));
}
#else /* CONFIG_BLACKFIN */
#define USB_BASE USB_FADDR
#define USB_OFFSET(reg) (reg - USB_BASE)
/*
* Common USB registers
*/
#define MUSB_FADDR USB_OFFSET(USB_FADDR) /* 8-bit */
#define MUSB_POWER USB_OFFSET(USB_POWER) /* 8-bit */
#define MUSB_INTRTX USB_OFFSET(USB_INTRTX) /* 16-bit */
#define MUSB_INTRRX USB_OFFSET(USB_INTRRX)
#define MUSB_INTRTXE USB_OFFSET(USB_INTRTXE)
#define MUSB_INTRRXE USB_OFFSET(USB_INTRRXE)
#define MUSB_INTRUSB USB_OFFSET(USB_INTRUSB) /* 8 bit */
#define MUSB_INTRUSBE USB_OFFSET(USB_INTRUSBE)/* 8 bit */
#define MUSB_FRAME USB_OFFSET(USB_FRAME)
#define MUSB_INDEX USB_OFFSET(USB_INDEX) /* 8 bit */
#define MUSB_TESTMODE USB_OFFSET(USB_TESTMODE)/* 8 bit */
/* Get offset for a given FIFO from musb->mregs */
#define MUSB_FIFO_OFFSET(epnum) \
(USB_OFFSET(USB_EP0_FIFO) + ((epnum) * 8))
/*
* Additional Control Registers
*/
#define MUSB_DEVCTL USB_OFFSET(USB_OTG_DEV_CTL) /* 8 bit */
#define MUSB_LINKINFO USB_OFFSET(USB_LINKINFO)/* 8 bit */
#define MUSB_VPLEN USB_OFFSET(USB_VPLEN) /* 8 bit */
#define MUSB_HS_EOF1 USB_OFFSET(USB_HS_EOF1) /* 8 bit */
#define MUSB_FS_EOF1 USB_OFFSET(USB_FS_EOF1) /* 8 bit */
#define MUSB_LS_EOF1 USB_OFFSET(USB_LS_EOF1) /* 8 bit */
/* Offsets to endpoint registers */
#define MUSB_TXMAXP 0x00
#define MUSB_TXCSR 0x04
#define MUSB_CSR0 MUSB_TXCSR /* Re-used for EP0 */
#define MUSB_RXMAXP 0x08
#define MUSB_RXCSR 0x0C
#define MUSB_RXCOUNT 0x10
#define MUSB_COUNT0 MUSB_RXCOUNT /* Re-used for EP0 */
#define MUSB_TXTYPE 0x14
#define MUSB_TYPE0 MUSB_TXTYPE /* Re-used for EP0 */
#define MUSB_TXINTERVAL 0x18
#define MUSB_NAKLIMIT0 MUSB_TXINTERVAL /* Re-used for EP0 */
#define MUSB_RXTYPE 0x1C
#define MUSB_RXINTERVAL 0x20
#define MUSB_TXCOUNT 0x28
/* Offsets to endpoint registers in indexed model (using INDEX register) */
#define MUSB_INDEXED_OFFSET(_epnum, _offset) \
(0x40 + (_offset))
/* Offsets to endpoint registers in flat models */
#define MUSB_FLAT_OFFSET(_epnum, _offset) \
(USB_OFFSET(USB_EP_NI0_TXMAXP) + (0x40 * (_epnum)) + (_offset))
/* Not implemented - HW has separate Tx/Rx FIFO */
#define MUSB_TXCSR_MODE 0x0000
static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size)
{
}
static inline void musb_write_txfifoadd(void __iomem *mbase, u16 c_off)
{
}
static inline void musb_write_rxfifosz(void __iomem *mbase, u8 c_size)
{
}
static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
{
}
static inline void musb_write_ulpi_buscontrol(void __iomem *mbase, u8 val)
{
}
static inline u8 musb_read_txfifosz(void __iomem *mbase)
{
return 0;
}
static inline u16 musb_read_txfifoadd(void __iomem *mbase)
{
return 0;
}
static inline u8 musb_read_rxfifosz(void __iomem *mbase)
{
return 0;
}
static inline u16 musb_read_rxfifoadd(void __iomem *mbase)
{
return 0;
}
static inline u8 musb_read_ulpi_buscontrol(void __iomem *mbase)
{
return 0;
}
static inline u8 musb_read_configdata(void __iomem *mbase)
{
return 0;
}
static inline u16 musb_read_hwvers(void __iomem *mbase)
{
/*
* This register is invisible on Blackfin, actually the MUSB
* RTL version of Blackfin is 1.9, so just harcode its value.
*/
return MUSB_HWVERS_1900;
}
static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase)
{
return NULL;
}
static inline void musb_write_rxfunaddr(void __iomem *ep_target_regs,
u8 qh_addr_req)
{
}
static inline void musb_write_rxhubaddr(void __iomem *ep_target_regs,
u8 qh_h_addr_reg)
{
}
static inline void musb_write_rxhubport(void __iomem *ep_target_regs,
u8 qh_h_port_reg)
{
}
static inline void musb_write_txfunaddr(void __iomem *mbase, u8 epnum,
u8 qh_addr_reg)
{
}
static inline void musb_write_txhubaddr(void __iomem *mbase, u8 epnum,
u8 qh_addr_reg)
{
}
static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum,
u8 qh_h_port_reg)
{
}
static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum)
{
return 0;
}
static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum)
{
return 0;
}
static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum)
{
return 0;
}
static inline u8 musb_read_txfunaddr(void __iomem *mbase, u8 epnum)
{
return 0;
}
static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum)
{
return 0;
}
static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum)
{
return 0;
}
#endif /* CONFIG_BLACKFIN */
#endif /* __MUSB_REGS_H__ */

View File

@ -0,0 +1,237 @@
#include <common.h>
#include <asm/errno.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#define __UBOOT__
#include <usb.h>
#include "linux-compat.h"
#include "usb-compat.h"
#include "musb_core.h"
#include "musb_host.h"
#include "musb_gadget.h"
#ifdef CONFIG_MUSB_HOST
static struct musb *host;
static struct usb_hcd hcd;
static enum usb_device_speed host_speed;
static void musb_host_complete_urb(struct urb *urb)
{
urb->dev->status &= ~USB_ST_NOT_PROC;
urb->dev->act_len = urb->actual_length;
}
static struct usb_host_endpoint hep;
static struct urb urb;
static struct urb *construct_urb(struct usb_device *dev, int endpoint_type,
unsigned long pipe, void *buffer, int len,
struct devrequest *setup, int interval)
{
int epnum = usb_pipeendpoint(pipe);
int is_in = usb_pipein(pipe);
memset(&urb, 0, sizeof(struct urb));
memset(&hep, 0, sizeof(struct usb_host_endpoint));
INIT_LIST_HEAD(&hep.urb_list);
INIT_LIST_HEAD(&urb.urb_list);
urb.ep = &hep;
urb.complete = musb_host_complete_urb;
urb.status = -EINPROGRESS;
urb.dev = dev;
urb.pipe = pipe;
urb.transfer_buffer = buffer;
urb.transfer_dma = (unsigned long)buffer;
urb.transfer_buffer_length = len;
urb.setup_packet = (unsigned char *)setup;
urb.ep->desc.wMaxPacketSize =
__cpu_to_le16(is_in ? dev->epmaxpacketin[epnum] :
dev->epmaxpacketout[epnum]);
urb.ep->desc.bmAttributes = endpoint_type;
urb.ep->desc.bEndpointAddress =
(is_in ? USB_DIR_IN : USB_DIR_OUT) | epnum;
urb.ep->desc.bInterval = interval;
return &urb;
}
#define MUSB_HOST_TIMEOUT 0x3ffffff
static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
{
struct musb *host = hcd->hcd_priv;
int ret;
int timeout;
ret = musb_urb_enqueue(hcd, urb, 0);
if (ret < 0) {
printf("Failed to enqueue URB to controller\n");
return ret;
}
timeout = MUSB_HOST_TIMEOUT;
do {
if (ctrlc())
return -EIO;
host->isr(0, host);
} while ((urb->dev->status & USB_ST_NOT_PROC) && --timeout);
return urb->status;
}
int submit_control_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int len, struct devrequest *setup)
{
struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_CONTROL, pipe,
buffer, len, setup, 0);
/* Fix speed for non hub-attached devices */
if (!dev->parent)
dev->speed = host_speed;
return submit_urb(&hcd, urb);
}
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int len)
{
struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_BULK, pipe,
buffer, len, NULL, 0);
return submit_urb(&hcd, urb);
}
int submit_int_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int len, int interval)
{
struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_INT, pipe,
buffer, len, NULL, interval);
return submit_urb(&hcd, urb);
}
int usb_lowlevel_init(int index, void **controller)
{
u8 power;
void *mbase;
int timeout = MUSB_HOST_TIMEOUT;
if (!host) {
printf("MUSB host is not registered\n");
return -ENODEV;
}
musb_start(host);
mbase = host->mregs;
do {
if (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_HM)
break;
} while (--timeout);
if (!timeout)
return -ENODEV;
power = musb_readb(mbase, MUSB_POWER);
musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power);
udelay(30000);
power = musb_readb(mbase, MUSB_POWER);
musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power);
host->isr(0, host);
host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
USB_SPEED_HIGH :
(musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
USB_SPEED_FULL : USB_SPEED_LOW;
host->is_active = 1;
hcd.hcd_priv = host;
return 0;
}
int usb_lowlevel_stop(int index)
{
if (!host) {
printf("MUSB host is not registered\n");
return -ENODEV;
}
musb_stop(host);
return 0;
}
#endif /* CONFIG_MUSB_HOST */
#ifdef CONFIG_MUSB_GADGET
static struct musb *gadget;
int usb_gadget_handle_interrupts(void)
{
if (!gadget || !gadget->isr)
return -EINVAL;
return gadget->isr(0, gadget);
}
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
{
int ret;
if (!driver || driver->speed < USB_SPEED_HIGH || !driver->bind ||
!driver->setup) {
printf("bad parameter.\n");
return -EINVAL;
}
if (!gadget) {
printf("Controller uninitialized\n");
return -ENXIO;
}
ret = musb_gadget_start(&gadget->g, driver);
if (ret < 0) {
printf("gadget_start failed with %d\n", ret);
return ret;
}
ret = driver->bind(&gadget->g);
if (ret < 0) {
printf("bind failed with %d\n", ret);
return ret;
}
return 0;
}
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
{
/* TODO: implement me */
return 0;
}
#endif /* CONFIG_MUSB_GADGET */
int musb_register(struct musb_hdrc_platform_data *plat, void *bdata,
void *ctl_regs)
{
struct musb **musbp;
switch (plat->mode) {
#ifdef CONFIG_MUSB_HOST
case MUSB_HOST:
musbp = &host;
break;
#endif
#ifdef CONFIG_MUSB_GADGET
case MUSB_PERIPHERAL:
musbp = &gadget;
break;
#endif
default:
return -EINVAL;
}
*musbp = musb_init_controller(plat, (struct device *)bdata, ctl_regs);
if (!musbp) {
printf("Failed to init the controller\n");
return -EIO;
}
return 0;
}

View File

@ -0,0 +1,88 @@
#ifndef __USB_COMPAT_H__
#define __USB_COMPAT_H__
#include "usb.h"
struct usb_hcd {
void *hcd_priv;
};
struct usb_host_endpoint {
struct usb_endpoint_descriptor desc;
struct list_head urb_list;
void *hcpriv;
};
/*
* urb->transfer_flags:
*
* Note: URB_DIR_IN/OUT is automatically set in usb_submit_urb().
*/
#define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */
#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUT with short packet */
struct urb;
typedef void (*usb_complete_t)(struct urb *);
struct urb {
void *hcpriv; /* private data for host controller */
struct list_head urb_list; /* list head for use by the urb's
* current owner */
struct usb_device *dev; /* (in) pointer to associated device */
struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */
unsigned int pipe; /* (in) pipe information */
int status; /* (return) non-ISO status */
unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/
void *transfer_buffer; /* (in) associated data buffer */
dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */
u32 transfer_buffer_length; /* (in) data buffer length */
u32 actual_length; /* (return) actual transfer length */
unsigned char *setup_packet; /* (in) setup packet (control only) */
int start_frame; /* (modify) start frame (ISO) */
usb_complete_t complete; /* (in) completion routine */
};
#define usb_hcd_link_urb_to_ep(hcd, urb) ({ \
int ret = 0; \
list_add_tail(&urb->urb_list, &urb->ep->urb_list); \
ret; })
#define usb_hcd_unlink_urb_from_ep(hcd, urb) list_del_init(&urb->urb_list)
static inline void usb_hcd_giveback_urb(struct usb_hcd *hcd,
struct urb *urb,
int status)
{
urb->status = status;
if (urb->complete)
urb->complete(urb);
}
static inline int usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd,
struct urb *urb)
{
/* TODO: add cache invalidation here */
return 0;
}
static inline u16 find_tt(struct usb_device *dev)
{
u8 chid;
u8 hub;
/* Find out the nearest parent which is high speed */
while (dev->parent->parent != NULL)
if (dev->parent->speed != USB_SPEED_HIGH)
dev = dev->parent;
else
break;
/* determine the port address at that hub */
hub = dev->parent->devnum;
for (chid = 0; chid < USB_MAXCHILDREN; chid++)
if (dev->parent->children[chid] == dev)
break;
return (hub << 8) | chid;
}
#endif /* __USB_COMPAT_H__ */

162
include/linux/usb/musb.h Normal file
View File

@ -0,0 +1,162 @@
/*
* This is used to for host and peripheral modes of the driver for
* Inventra (Multidrop) Highspeed Dual-Role Controllers: (M)HDRC.
*
* Board initialization should put one of these into dev->platform_data,
* probably on some platform_device named "musb-hdrc". It encapsulates
* key configuration differences between boards.
*/
#ifndef __LINUX_USB_MUSB_H
#define __LINUX_USB_MUSB_H
#ifndef __deprecated
#define __deprecated
#endif
/* The USB role is defined by the connector used on the board, so long as
* standards are being followed. (Developer boards sometimes won't.)
*/
enum musb_mode {
MUSB_UNDEFINED = 0,
MUSB_HOST, /* A or Mini-A connector */
MUSB_PERIPHERAL, /* B or Mini-B connector */
MUSB_OTG /* Mini-AB connector */
};
struct clk;
enum musb_fifo_style {
FIFO_RXTX,
FIFO_TX,
FIFO_RX
} __attribute__ ((packed));
enum musb_buf_mode {
BUF_SINGLE,
BUF_DOUBLE
} __attribute__ ((packed));
struct musb_fifo_cfg {
u8 hw_ep_num;
enum musb_fifo_style style;
enum musb_buf_mode mode;
u16 maxpacket;
};
#define MUSB_EP_FIFO(ep, st, m, pkt) \
{ \
.hw_ep_num = ep, \
.style = st, \
.mode = m, \
.maxpacket = pkt, \
}
#define MUSB_EP_FIFO_SINGLE(ep, st, pkt) \
MUSB_EP_FIFO(ep, st, BUF_SINGLE, pkt)
#define MUSB_EP_FIFO_DOUBLE(ep, st, pkt) \
MUSB_EP_FIFO(ep, st, BUF_DOUBLE, pkt)
struct musb_hdrc_eps_bits {
const char name[16];
u8 bits;
};
struct musb_hdrc_config {
struct musb_fifo_cfg *fifo_cfg; /* board fifo configuration */
unsigned fifo_cfg_size; /* size of the fifo configuration */
/* MUSB configuration-specific details */
unsigned multipoint:1; /* multipoint device */
unsigned dyn_fifo:1 __deprecated; /* supports dynamic fifo sizing */
unsigned soft_con:1 __deprecated; /* soft connect required */
unsigned utm_16:1 __deprecated; /* utm data witdh is 16 bits */
unsigned big_endian:1; /* true if CPU uses big-endian */
unsigned mult_bulk_tx:1; /* Tx ep required for multbulk pkts */
unsigned mult_bulk_rx:1; /* Rx ep required for multbulk pkts */
unsigned high_iso_tx:1; /* Tx ep required for HB iso */
unsigned high_iso_rx:1; /* Rx ep required for HD iso */
unsigned dma:1 __deprecated; /* supports DMA */
unsigned vendor_req:1 __deprecated; /* vendor registers required */
u8 num_eps; /* number of endpoints _with_ ep0 */
u8 dma_channels __deprecated; /* number of dma channels */
u8 dyn_fifo_size; /* dynamic size in bytes */
u8 vendor_ctrl __deprecated; /* vendor control reg width */
u8 vendor_stat __deprecated; /* vendor status reg witdh */
u8 dma_req_chan __deprecated; /* bitmask for required dma channels */
u8 ram_bits; /* ram address size */
struct musb_hdrc_eps_bits *eps_bits __deprecated;
#ifdef CONFIG_BLACKFIN
/* A GPIO controlling VRSEL in Blackfin */
unsigned int gpio_vrsel;
unsigned int gpio_vrsel_active;
/* musb CLKIN in Blackfin in MHZ */
unsigned char clkin;
#endif
};
struct musb_hdrc_platform_data {
/* MUSB_HOST, MUSB_PERIPHERAL, or MUSB_OTG */
u8 mode;
/* for clk_get() */
const char *clock;
/* (HOST or OTG) switch VBUS on/off */
int (*set_vbus)(struct device *dev, int is_on);
/* (HOST or OTG) mA/2 power supplied on (default = 8mA) */
u8 power;
/* (PERIPHERAL) mA/2 max power consumed (default = 100mA) */
u8 min_power;
/* (HOST or OTG) msec/2 after VBUS on till power good */
u8 potpgt;
/* (HOST or OTG) program PHY for external Vbus */
unsigned extvbus:1;
/* Power the device on or off */
int (*set_power)(int state);
/* MUSB configuration-specific details */
struct musb_hdrc_config *config;
/* Architecture specific board data */
void *board_data;
/* Platform specific struct musb_ops pointer */
const void *platform_ops;
};
/* TUSB 6010 support */
#define TUSB6010_OSCCLK_60 16667 /* psec/clk @ 60.0 MHz */
#define TUSB6010_REFCLK_24 41667 /* psec/clk @ 24.0 MHz XI */
#define TUSB6010_REFCLK_19 52083 /* psec/clk @ 19.2 MHz CLKIN */
#ifdef CONFIG_ARCH_OMAP2
extern int __init tusb6010_setup_interface(
struct musb_hdrc_platform_data *data,
unsigned ps_refclk, unsigned waitpin,
unsigned async_cs, unsigned sync_cs,
unsigned irq, unsigned dmachan);
extern int tusb6010_platform_retime(unsigned is_refclk);
#endif /* OMAP2 */
/*
* U-Boot specfic stuff
*/
int musb_register(struct musb_hdrc_platform_data *plat, void *bdata,
void *ctl_regs);
#endif /* __LINUX_USB_MUSB_H */