Commit 228c2be6 authored by Tony Lindgren's avatar Tony Lindgren

Merge branch 'musb'

parents 9d211b76 414ed166
......@@ -2979,6 +2979,7 @@ MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
P: Felipe Balbi
M: felipe.balbi@nokia.com
L: linux-usb@vger.kernel.org
T: git gitorious.org:/musb/mainline.git
S: Maintained
MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
......
......@@ -297,13 +297,13 @@ config USB_S3C2410_DEBUG
# musb builds in ../musb along with host support
config USB_GADGET_MUSB_HDRC
boolean "Inventra HDRC USB Peripheral (TI, ...)"
boolean "Inventra HDRC USB Peripheral (TI, ADI, ...)"
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.
the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin
config USB_GADGET_M66592
boolean "Renesas M66592 USB Peripheral Controller"
......
......@@ -11,7 +11,7 @@ config USB_MUSB_HDRC
depends on (USB || USB_GADGET) && HAVE_CLK
depends on !SUPERH
select TWL4030_USB if MACH_OMAP_3430SDP
tristate 'Inventra Highspeed Dual Role Controller (TI, ...)'
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
help
Say Y here if your system has a dual role high speed USB
controller based on the Mentor Graphics silicon IP. Then
......@@ -22,6 +22,9 @@ config USB_MUSB_HDRC
Texas Instruments parts using this IP include DaVinci 644x,
OMAP 243x, OMAP 343x, and TUSB 6010.
Analog Devices parts using this IP include Blackfin BF54x,
BF525 and BF527.
If you do not know what this is, please say N.
To compile this driver as a module, choose M here; the
......@@ -33,6 +36,8 @@ config USB_MUSB_SOC
default y if ARCH_DAVINCI
default y if ARCH_OMAP2430
default y if ARCH_OMAP34XX
default y if (BF54x && !BF544)
default y if (BF52x && !BF522 && !BF523)
comment "DaVinci 644x USB support"
depends on USB_MUSB_HDRC && ARCH_DAVINCI
......@@ -43,6 +48,9 @@ comment "OMAP 243x high speed USB support"
comment "OMAP 343x high speed USB support"
depends on USB_MUSB_HDRC && ARCH_OMAP34XX
comment "Blackfin high speed USB Support"
depends on USB_MUSB_HDRC && (BF54x && !BF544) || (BF52x && !BF522 && !BF523)
config USB_TUSB6010
boolean "TUSB 6010 support"
depends on USB_MUSB_HDRC && !USB_MUSB_SOC
......@@ -142,7 +150,7 @@ config MUSB_PIO_ONLY
config USB_INVENTRA_DMA
bool
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
default ARCH_OMAP2430 || ARCH_OMAP34XX
default ARCH_OMAP2430 || ARCH_OMAP34XX || BLACKFIN
help
Enable DMA transfers using Mentor's engine.
......
......@@ -22,6 +22,14 @@ ifeq ($(CONFIG_ARCH_OMAP3430),y)
musb_hdrc-objs += omap2430.o
endif
ifeq ($(CONFIG_BF54x),y)
musb_hdrc-objs += blackfin.o
endif
ifeq ($(CONFIG_BF52x),y)
musb_hdrc-objs += blackfin.o
endif
ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y)
musb_hdrc-objs += musb_gadget_ep0.o musb_gadget.o
endif
......
/*
* MUSB OTG controller driver for Blackfin Processors
*
* Copyright 2006-2008 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*/
#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/clk.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <asm/cacheflush.h>
#include "musb_core.h"
#include "blackfin.h"
/*
* Load an endpoint's FIFO
*/
void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
{
void __iomem *fifo = hw_ep->fifo;
void __iomem *epio = hw_ep->regs;
prefetch((u8 *)src);
musb_writew(epio, MUSB_TXCOUNT, len);
DBG(4, "TX ep%d fifo %p count %d buf %p, epio %p\n",
hw_ep->epnum, fifo, len, src, epio);
dump_fifo_data(src, len);
if (unlikely((unsigned long)src & 0x01))
outsw_8((unsigned long)fifo, src,
len & 0x01 ? (len >> 1) + 1 : len >> 1);
else
outsw((unsigned long)fifo, src,
len & 0x01 ? (len >> 1) + 1 : len >> 1);
}
/*
* Unload an endpoint's FIFO
*/
void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
{
void __iomem *fifo = hw_ep->fifo;
u8 epnum = hw_ep->epnum;
u16 dma_reg = 0;
DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
'R', hw_ep->epnum, fifo, len, dst);
#ifdef CONFIG_BF52x
invalidate_dcache_range((unsigned int)dst,
(unsigned int)(dst + len));
/* Setup DMA address register */
dma_reg = (u16) ((u32) dst & 0xFFFF);
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
SSYNC();
dma_reg = (u16) (((u32) dst >> 16) & 0xFFFF);
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
SSYNC();
/* Setup DMA count register */
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len);
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0);
SSYNC();
/* Enable the DMA */
dma_reg = (epnum << 4) | DMA_ENA | INT_ENA;
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);
SSYNC();
/* Wait for compelete */
while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))
cpu_relax();
/* acknowledge dma interrupt */
bfin_write_USB_DMA_INTERRUPT(1 << epnum);
SSYNC();
/* Reset DMA */
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0);
SSYNC();
#else
if (unlikely((unsigned long)dst & 0x01))
insw_8((unsigned long)fifo, dst,
len & 0x01 ? (len >> 1) + 1 : len >> 1);
else
insw((unsigned long)fifo, dst,
len & 0x01 ? (len >> 1) + 1 : len >> 1);
#endif
dump_fifo_data(dst, len);
}
static irqreturn_t blackfin_interrupt(int irq, void *__hci)
{
unsigned long flags;
irqreturn_t retval = IRQ_NONE;
struct musb *musb = __hci;
spin_lock_irqsave(&musb->lock, flags);
musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
if (musb->int_usb || musb->int_tx || musb->int_rx) {
musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
retval = musb_interrupt(musb);
}
spin_unlock_irqrestore(&musb->lock, flags);
/* REVISIT we sometimes get spurious IRQs on g_ep0
* not clear why... fall in BF54x too.
*/
if (retval != IRQ_HANDLED)
DBG(5, "spurious?\n");
return IRQ_HANDLED;
}
static void musb_conn_timer_handler(unsigned long _musb)
{
struct musb *musb = (void *)_musb;
unsigned long flags;
u16 val;
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv.state) {
case OTG_STATE_A_IDLE:
case OTG_STATE_A_WAIT_BCON:
/* Start a new session */
val = musb_readw(musb->mregs, MUSB_DEVCTL);
val |= MUSB_DEVCTL_SESSION;
musb_writew(musb->mregs, MUSB_DEVCTL, val);
val = musb_readw(musb->mregs, MUSB_DEVCTL);
if (!(val & MUSB_DEVCTL_BDEVICE)) {
gpio_set_value(musb->config->gpio_vrsel, 1);
musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
} else {
gpio_set_value(musb->config->gpio_vrsel, 0);
/* Ignore VBUSERROR and SUSPEND IRQ */
val = musb_readb(musb->mregs, MUSB_INTRUSBE);
val &= ~MUSB_INTR_VBUSERROR;
musb_writeb(musb->mregs, MUSB_INTRUSBE, val);
val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
musb_writeb(musb->mregs, MUSB_INTRUSB, val);
val = MUSB_POWER_HSENAB;
musb_writeb(musb->mregs, MUSB_POWER, val);
}
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
break;
default:
DBG(1, "%s state not handled\n", otg_state_string(musb));
break;
}
spin_unlock_irqrestore(&musb->lock, flags);
DBG(4, "state is %s\n", otg_state_string(musb));
}
void musb_platform_enable(struct musb *musb)
{
if (is_host_enabled(musb)) {
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
musb->a_wait_bcon = TIMER_DELAY;
}
}
void musb_platform_disable(struct musb *musb)
{
}
static void bfin_vbus_power(struct musb *musb, int is_on, int sleeping)
{
}
static void bfin_set_vbus(struct musb *musb, int is_on)
{
if (is_on)
gpio_set_value(musb->config->gpio_vrsel, 1);
else
gpio_set_value(musb->config->gpio_vrsel, 0);
DBG(1, "VBUS %s, devctl %02x "
/* otg %3x conf %08x prcm %08x */ "\n",
otg_state_string(musb),
musb_readb(musb->mregs, MUSB_DEVCTL));
}
static int bfin_set_power(struct otg_transceiver *x, unsigned mA)
{
return 0;
}
void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
{
if (is_host_enabled(musb))
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
}
int musb_platform_get_vbus_status(struct musb *musb)
{
return 0;
}
void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
{
}
int __init musb_platform_init(struct musb *musb)
{
/*
* Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
* and OTG HOST modes, while rev 1.1 and greater require PE7 to
* be low for DEVICE mode and high for HOST mode. We set it high
* here because we are in host mode
*/
if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d \n",
musb->config->gpio_vrsel);
return -ENODEV;
}
gpio_direction_output(musb->config->gpio_vrsel, 0);
if (ANOMALY_05000346) {
bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
SSYNC();
}
if (ANOMALY_05000347) {
bfin_write_USB_APHY_CNTRL(0x0);
SSYNC();
}
/* TODO
* Set SIC-IVG register
*/
/* Configure PLL oscillator register */
bfin_write_USB_PLLOSC_CTRL(0x30a8);
SSYNC();
bfin_write_USB_SRP_CLKDIV((get_sclk()/1000) / 32 - 1);
SSYNC();
bfin_write_USB_EP_NI0_RXMAXP(64);
SSYNC();
bfin_write_USB_EP_NI0_TXMAXP(64);
SSYNC();
/* Route INTRUSB/INTR_RX/INTR_TX to USB_INT0*/
bfin_write_USB_GLOBINTR(0x7);
SSYNC();
bfin_write_USB_GLOBAL_CTL(GLOBAL_ENA | EP1_TX_ENA | EP2_TX_ENA |
EP3_TX_ENA | EP4_TX_ENA | EP5_TX_ENA |
EP6_TX_ENA | EP7_TX_ENA | EP1_RX_ENA |
EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA |
EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA);
SSYNC();
if (is_host_enabled(musb)) {
musb->board_set_vbus = bfin_set_vbus;
setup_timer(&musb_conn_timer,
musb_conn_timer_handler, (unsigned long) musb);
}
if (is_peripheral_enabled(musb))
musb->xceiv.set_power = bfin_set_power;
musb->isr = blackfin_interrupt;
return 0;
}
int musb_platform_suspend(struct musb *musb)
{
return 0;
}
int musb_platform_resume(struct musb *musb)
{
return 0;
}
int musb_platform_exit(struct musb *musb)
{
bfin_vbus_power(musb, 0 /*off*/, 1);
gpio_free(musb->config->gpio_vrsel);
musb_platform_suspend(musb);
return 0;
}
/*
* Copyright (C) 2007 by Analog Devices, Inc.
*
* 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_BLACKFIN_H__
#define __MUSB_BLACKFIN_H__
/*
* Blackfin specific definitions
*/
#undef DUMP_FIFO_DATA
#ifdef DUMP_FIFO_DATA
static void dump_fifo_data(u8 *buf, u16 len)
{
u8 *tmp = buf;
int i;
for (i = 0; i < len; i++) {
if (!(i % 16) && i)
pr_debug("\n");
pr_debug("%02x ", *tmp++);
}
pr_debug("\n");
}
#else
#define dump_fifo_data(buf, len) do {} while (0)
#endif
#ifdef CONFIG_BF52x
#define USB_DMA_BASE USB_DMA_INTERRUPT
#define USB_DMAx_CTRL 0x04
#define USB_DMAx_ADDR_LOW 0x08
#define USB_DMAx_ADDR_HIGH 0x0C
#define USB_DMAx_COUNT_LOW 0x10
#define USB_DMAx_COUNT_HIGH 0x14
#define USB_DMA_REG(ep, reg) (USB_DMA_BASE + 0x20 * ep + reg)
#endif
/* Almost 1 second */
#define TIMER_DELAY (1 * HZ)
static struct timer_list musb_conn_timer;
#endif /* __MUSB_BLACKFIN_H__ */
......@@ -32,9 +32,9 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <asm/arch/hardware.h>
#include <asm/arch/memory.h>
#include <asm/arch/gpio.h>
#include <mach/arch/hardware.h>
#include <mach/arch/memory.h>
#include <mach/arch/gpio.h>
#include <asm/mach-types.h>
#include "musb_core.h"
......@@ -265,7 +265,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
/* CPPI interrupts share the same IRQ line, but have their own
* mask, state, "vector", and EOI registers.
*/
if (is_cppi_enabled()) {
if (cppi_ti_dma()) {
u32 cppi_tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
u32 cppi_rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
......@@ -364,6 +364,18 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
return IRQ_HANDLED;
}
int musb_platform_set_mode(struct musb *musb, u8 mode)
{
/* EVM can't do this (right?) */
return -EIO;
}
int musb_platform_set_mode(struct musb *musb, u8 mode)
{
/* EVM can't do this (right?) */
return -EIO;
}
int __init musb_platform_init(struct musb *musb)
{
void __iomem *tibase = musb->ctrl_base;
......
......@@ -148,7 +148,8 @@ static inline struct musb *dev_to_musb(struct device *dev)
/*-------------------------------------------------------------------------*/
#ifndef CONFIG_USB_TUSB6010
#if !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN)
/*
* Load an endpoint's FIFO
*/
......@@ -1124,25 +1125,25 @@ fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep,
#endif
switch (cfg->style) {
case FIFO_TX:
musb_writeb(mbase, MUSB_TXFIFOSZ, c_size);
musb_writew(mbase, MUSB_TXFIFOADD, c_off);
musb_write_txfifosz(mbase, c_size);
musb_write_txfifoadd(mbase, c_off);
hw_ep->tx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB);
hw_ep->max_packet_sz_tx = maxpacket;
break;
case FIFO_RX:
musb_writeb(mbase, MUSB_RXFIFOSZ, c_size);
musb_writew(mbase, MUSB_RXFIFOADD, c_off);
musb_write_rxfifosz(mbase, c_size);
musb_write_rxfifoadd(mbase, c_off);
hw_ep->rx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB);
hw_ep->max_packet_sz_rx = maxpacket;
break;
case FIFO_RXTX:
musb_writeb(mbase, MUSB_TXFIFOSZ, c_size);
musb_writew(mbase, MUSB_TXFIFOADD, c_off);
musb_write_txfifosz(mbase, c_size);
musb_write_txfifoadd(mbase, c_off);
hw_ep->rx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB);
hw_ep->max_packet_sz_rx = maxpacket;
musb_writeb(mbase, MUSB_RXFIFOSZ, c_size);
musb_writew(mbase, MUSB_RXFIFOADD, c_off);
musb_write_rxfifosz(mbase, c_size);
musb_write_rxfifoadd(mbase, c_off);
hw_ep->tx_double_buffered = hw_ep->rx_double_buffered;
hw_ep->max_packet_sz_tx = maxpacket;
......@@ -1212,7 +1213,7 @@ static int __init ep_config_from_table(struct musb *musb)
if (epn >= musb->config->num_eps) {
pr_debug("%s: invalid ep %d\n",
musb_driver_name, epn);
continue;
return -EINVAL;
}
offset = fifo_setup(musb, hw_ep + epn, cfg++, offset);
if (offset < 0) {
......@@ -1246,9 +1247,10 @@ static int __init ep_config_from_table(struct musb *musb)
*/
static int __init ep_config_from_hw(struct musb *musb)
{
u8 epnum = 0, reg;
u8 epnum = 0;
struct musb_hw_ep *hw_ep;
void *mbase = musb->mregs;
int ret = 0;
DBG(2, "<== static silicon ep config\n");
......@@ -1258,26 +1260,9 @@ static int __init ep_config_from_hw(struct musb *musb)
musb_ep_select(mbase, epnum);
hw_ep = musb->endpoints + epnum;
/* read from core using indexed model */
reg = musb_readb(hw_ep->regs, 0x10 + MUSB_FIFOSIZE);
if (!reg) {
/* 0's returned when no more endpoints */
ret = musb_read_fifosize(musb, hw_ep, epnum);
if (ret < 0)
break;
}
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;
continue;
} else {
hw_ep->max_packet_sz_rx = 1 << ((reg & 0xf0) >> 4);
hw_ep->is_shared_fifo = false;
}
/* FIXME set up hw_ep->{rx,tx}_double_buffered */
......@@ -1326,7 +1311,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
/* log core options (read using indexed model) */
musb_ep_select(mbase, 0);
reg = musb_readb(mbase, 0x10 + MUSB_CONFIGDATA);
reg = musb_read_configdata(mbase);
strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8");
if (reg & MUSB_CONFIGDATA_DYNFIFO)
......@@ -1391,7 +1376,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
}
/* log release info */
hwvers = musb_readw(mbase, MUSB_HWVERS);
hwvers = musb_read_hwvers(mbase);
rev_major = (hwvers >> 10) & 0x1f;
rev_minor = hwvers & 0x3ff;
snprintf(aRevision, 32, "%d.%d%s", rev_major,
......@@ -1400,8 +1385,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
musb_driver_name, type, aRevision, aDate);
/* configure ep0 */
musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE;
musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE;
musb_configure_ep0(musb);
/* discover endpoint configuration */
musb->nr_endpoints = 1;
......@@ -1445,7 +1429,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
hw_ep->regs = MUSB_EP_OFFSET(i, 0) + mbase;
#ifdef CONFIG_USB_MUSB_HDRC_HCD
hw_ep->target_regs = MUSB_BUSCTL_OFFSET(i, 0) + mbase;
hw_ep->target_regs = musb_read_target_reg_base(i, mbase);
hw_ep->rx_reinit = 1;
hw_ep->tx_reinit = 1;
#endif
......@@ -1612,7 +1596,7 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)
if (!epnum) {
#ifndef CONFIG_USB_TUSB_OMAP_DMA
if (!is_cppi_enabled()) {
if (!cppi_ti_dma()) {
/* endpoint 0 */
if (devctl & MUSB_DEVCTL_HM)
musb_h_ep0_irq(musb);
......@@ -1671,17 +1655,20 @@ musb_mode_store(struct device *dev, struct device_attribute *attr,
{
struct musb *musb = dev_to_musb(dev);
unsigned long flags;
int status;
spin_lock_irqsave(&musb->lock, flags);
if (!strncmp(buf, "host", 4))
musb_platform_set_mode(musb, MUSB_HOST);
if (!strncmp(buf, "peripheral", 10))
musb_platform_set_mode(musb, MUSB_PERIPHERAL);
if (!strncmp(buf, "otg", 3))
musb_platform_set_mode(musb, MUSB_OTG);
if (sysfs_streq(buf, "host"))
status = musb_platform_set_mode(musb, MUSB_HOST);
else if (sysfs_streq(buf, "peripheral"))
status = musb_platform_set_mode(musb, MUSB_PERIPHERAL);
else if (sysfs_streq(buf, "otg"))
status = musb_platform_set_mode(musb, MUSB_OTG);
else
status = -EINVAL;
spin_unlock_irqrestore(&musb->lock, flags);
return n;
return (status == 0) ? n : status;
}
static DEVICE_ATTR(mode, 0644, musb_mode_show, musb_mode_store);
......@@ -1810,7 +1797,6 @@ allocate_instance(struct device *dev,
for (epnum = 0, ep = musb->endpoints;
epnum < musb->config->num_eps;
epnum++, ep++) {
ep->musb = musb;
ep->epnum = epnum;
}
......@@ -1838,7 +1824,7 @@ static void musb_free(struct musb *musb)
musb_gadget_cleanup(musb);
#endif
if (musb->nIrq >= 0) {
if (musb->nIrq >= 0 && musb->irq_wake) {
disable_irq_wake(musb->nIrq);
free_irq(musb->nIrq, musb);
}
......@@ -1991,8 +1977,12 @@ bad_config:
}
musb->nIrq = nIrq;
/* FIXME this handles wakeup irqs wrong */
if (enable_irq_wake(nIrq) == 0)
if (enable_irq_wake(nIrq) == 0) {
musb->irq_wake = 1;
device_init_wakeup(dev, 1);
} else {
musb->irq_wake = 0;
}
pr_info("%s: USB %s mode controller at %p using %s, IRQ %d\n",
musb_driver_name,
......
......@@ -191,7 +191,7 @@ enum musb_g_ep0_state {
*/
#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_ARCH_OMAP2430) \
|| defined(CONFIG_ARCH_OMAP3430)
|| defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_BLACKFIN)
/* REVISIT indexed access seemed to
* misbehave (on DaVinci) for at least peripheral IN ...
*/
......@@ -359,6 +359,7 @@ struct musb {
struct otg_transceiver xceiv;
int nIrq;
unsigned irq_wake:1;
struct musb_hw_ep endpoints[MUSB_C_NUM_EPS];
#define control_ep endpoints
......@@ -447,6 +448,70 @@ static inline struct musb *gadget_to_musb(struct usb_gadget *g)
}
#endif
#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)
{
u8 reg = 0;
/* read from core using indexed model */
reg = musb_readb(hw_ep->regs, 0x10 + 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;
}
#endif /* CONFIG_BLACKFIN */
/***************************** Glue it together *****************************/
......@@ -467,16 +532,16 @@ extern void musb_platform_disable(struct musb *musb);
extern void musb_hnp_stop(struct musb *musb);
extern void musb_platform_set_mode(struct musb *musb, u8 musb_mode);
extern int musb_platform_set_mode(struct musb *musb, u8 musb_mode);
#if defined(CONFIG_USB_TUSB6010) || \
#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN) || \
defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout);
#else
#define musb_platform_try_idle(x, y) do {} while (0)
#endif
#ifdef CONFIG_USB_TUSB6010
#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN)
extern int musb_platform_get_vbus_status(struct musb *musb);
#else
#define musb_platform_get_vbus_status(x) 0
......
......@@ -69,15 +69,21 @@ struct musb_hw_ep;
#endif
#ifdef CONFIG_USB_TI_CPPI_DMA
#define is_cppi_enabled() 1
#define cppi_ti_dma() true
#else
#define is_cppi_enabled() 0
#define cppi_ti_dma() false
#endif
#ifdef CONFIG_USB_TUSB_OMAP_DMA
#define tusb_dma_omap() 1
#define tusb_dma_omap() true
#else
#define tusb_dma_omap() 0
#define tusb_dma_omap() false
#endif
#ifdef CONFIG_USB_INVENTRA_DMA
#define musb_inventra_dma() true
#else
#define musb_inventra_dma() false
#endif
/*
......
......@@ -297,8 +297,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
/* MUSB_TXCSR_P_ISO is still set correctly */
#ifdef CONFIG_USB_INVENTRA_DMA
{
if (musb_inventra_dma()) {
size_t request_size;
/* setup DMA, then program endpoint CSR */
......@@ -332,7 +331,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
}
}
#elif defined(CONFIG_USB_TI_CPPI_DMA)
if (cppi_ti_dma()) {
/* program endpoint CSR first, then setup DMA */
csr &= ~(MUSB_TXCSR_AUTOSET
| MUSB_TXCSR_DMAMODE
......@@ -368,13 +367,15 @@ static void txstate(struct musb *musb, struct musb_request *req)
csr &= ~(MUSB_TXCSR_DMAMODE | MUSB_TXCSR_MODE);
/* invariant: prequest->buf is non-null */
}
#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
}
if (tusb_dma_omap()) {
use_dma = use_dma && c->channel_program(
musb_ep->dma, musb_ep->packet_sz,
request->zero,
request->dma,
request->length);
#endif
}
}
#endif
......@@ -574,27 +575,28 @@ static void rxstate(struct musb *musb, struct musb_request *req)
const u8 epnum = req->epnum;
struct usb_request *request = &req->request;
struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out;
struct dma_controller *c = musb->dma_controller;
struct dma_channel *channel = musb_ep->dma;
void __iomem *epio = musb->endpoints[epnum].regs;
u16 fifo_count = 0;
u16 len = musb_ep->packet_sz;
int use_dma = 0;
csr = musb_readw(epio, MUSB_RXCSR);
if (is_cppi_enabled() && musb_ep->dma) {
struct dma_controller *c = musb->dma_controller;
struct dma_channel *channel = musb_ep->dma;
if (cppi_ti_dma() && musb_ep->dma) {
/* NOTE: CPPI won't actually stop advancing the DMA
* queue after short packet transfers, so this is almost
* always going to run as IRQ-per-packet DMA so that
* faults will be handled correctly.
*/
if (c->channel_program(channel,
use_dma = c->channel_program(channel,
musb_ep->packet_sz,
!request->short_not_ok,
request->dma + request->actual,
request->length - request->actual)) {
request->length - request->actual);
if (use_dma) {
/* make sure that if an rxpkt arrived after the irq,
* the cppi engine will be ready to take it as soon
* as DMA is enabled
......@@ -603,21 +605,12 @@ static void rxstate(struct musb *musb, struct musb_request *req)
| MUSB_RXCSR_DMAMODE);
csr |= MUSB_RXCSR_DMAENAB | MUSB_RXCSR_P_WZC_BITS;
musb_writew(epio, MUSB_RXCSR, csr);
return;
}
}
if (csr & MUSB_RXCSR_RXPKTRDY) {
len = musb_readw(epio, MUSB_RXCOUNT);
if (request->actual < request->length) {
#ifdef CONFIG_USB_INVENTRA_DMA
if (is_dma_capable() && musb_ep->dma) {
struct dma_controller *c;
struct dma_channel *channel;
int use_dma = 0;
c = musb->dma_controller;
channel = musb_ep->dma;
/* We use DMA Req mode 0 in rx_csr, and DMA controller operates in
* mode 0 only. So we do not get endpoint interrupts due to DMA
......@@ -639,6 +632,13 @@ static void rxstate(struct musb *musb, struct musb_request *req)
* REVISIT an updated g_file_storage can set req->short_not_ok, which
* then becomes usable as a runtime "use mode 1" hint...
*/
if (musb_inventra_dma() && musb_ep->dma) {
struct dma_controller *c;
struct dma_channel *channel;
int use_dma = 0;
c = musb->dma_controller;
channel = musb_ep->dma;
csr |= MUSB_RXCSR_DMAENAB;
#ifdef USE_MODE1
......@@ -674,37 +674,30 @@ static void rxstate(struct musb *musb, struct musb_request *req)
request->dma
+ request->actual,
transfer_size);
}
if (use_dma)
return;
}
#endif /* Mentor's DMA */
fifo_count = request->length - request->actual;
DBG(3, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n",
musb_ep->end_point.name,
len, fifo_count,
musb_ep->packet_sz);
fifo_count = min(len, fifo_count);
}
#ifdef CONFIG_USB_TUSB_OMAP_DMA
if (tusb_dma_omap() && musb_ep->dma) {
struct dma_controller *c = musb->dma_controller;
struct dma_channel *channel = musb_ep->dma;
u32 dma_addr = request->dma + request->actual;
int ret;
ret = c->channel_program(channel,
use_dma = c->channel_program(channel,
musb_ep->packet_sz,
channel->desired_mode,
dma_addr,
fifo_count);
if (ret)
if (use_dma)
return;
}
#endif
fifo_count = request->length - request->actual;
DBG(3, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n",
musb_ep->end_point.name,
len, fifo_count,
musb_ep->packet_sz);
fifo_count = min(len, fifo_count);
musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *)
(request->buf + request->actual));
......@@ -800,11 +793,11 @@ void musb_g_rx(struct musb *musb, u8 epnum)
musb_readw(epio, MUSB_RXCSR),
musb_ep->dma->actual_len, request);
#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
/* Autoclear doesn't clear RxPktRdy for short packets */
if ((dma->desired_mode == 0)
if ((tusb_dma_omap() || musb_inventra_dma())
&& ((dma->desired_mode == 0)
|| (dma->actual_len
& (musb_ep->packet_sz - 1))) {
& (musb_ep->packet_sz - 1)))) {
/* ack the read! */
csr &= ~MUSB_RXCSR_RXPKTRDY;
musb_writew(epio, MUSB_RXCSR, csr);
......@@ -815,7 +808,7 @@ void musb_g_rx(struct musb *musb, u8 epnum)
&& (musb_ep->dma->actual_len
== musb_ep->packet_sz))
goto done;
#endif
musb_g_giveback(musb_ep, request, 0);
request = next_request(musb_ep);
......
......@@ -112,18 +112,21 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
{
void __iomem *epio = ep->regs;
u16 csr;
u16 lastcsr = 0;
int retries = 1000;
csr = musb_readw(epio, MUSB_TXCSR);
while (csr & MUSB_TXCSR_FIFONOTEMPTY) {
DBG(5, "Host TX FIFONOTEMPTY csr: %02x\n", csr);
if (csr != lastcsr)
DBG(3, "Host TX FIFONOTEMPTY csr: %02x\n", csr);
lastcsr = csr;
csr |= MUSB_TXCSR_FLUSHFIFO;
musb_writew(epio, MUSB_TXCSR, csr);
csr = musb_readw(epio, MUSB_TXCSR);
if (retries-- < 1) {
ERR("Could not flush host TX fifo: csr: %04x\n", csr);
if (WARN(retries-- < 1,
"Could not flush host TX%d fifo: csr: %04x\n",
ep->epnum, csr))
return;
}
mdelay(1);
}
}
......@@ -257,7 +260,7 @@ start:
if (!hw_ep->tx_channel)
musb_h_tx_start(hw_ep);
else if (is_cppi_enabled() || tusb_dma_omap())
else if (cppi_ti_dma() || tusb_dma_omap())
cppi_host_txdma_start(hw_ep);
}
}
......@@ -268,7 +271,7 @@ __musb_giveback(struct musb *musb, struct urb *urb, int status)
__releases(musb->lock)
__acquires(musb->lock)
{
DBG(({ int level; switch (urb->status) {
DBG(({ int level; switch (status) {
case 0:
level = 4;
break;
......@@ -283,8 +286,8 @@ __acquires(musb->lock)
level = 2;
break;
}; level; }),
"complete %p (%d), dev%d ep%d%s, %d/%d\n",
urb, urb->status,
"complete %p %pF (%d), dev%d ep%d%s, %d/%d\n",
urb, urb->complete, status,
usb_pipedevice(urb->pipe),
usb_pipeendpoint(urb->pipe),
usb_pipein(urb->pipe) ? "in" : "out",
......@@ -593,12 +596,10 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
/* target addr and (for multipoint) hub addr/port */
if (musb->is_multipoint) {
musb_writeb(ep->target_regs, MUSB_RXFUNCADDR,
qh->addr_reg);
musb_writeb(ep->target_regs, MUSB_RXHUBADDR,
qh->h_addr_reg);
musb_writeb(ep->target_regs, MUSB_RXHUBPORT,
qh->h_port_reg);
musb_write_rxfunaddr(ep->target_regs, qh->addr_reg);
musb_write_rxhubaddr(ep->target_regs, qh->h_addr_reg);
musb_write_rxhubport(ep->target_regs, qh->h_port_reg);
} else
musb_writeb(musb->mregs, MUSB_FADDR, qh->addr_reg);
......@@ -712,15 +713,9 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
/* target addr and (for multipoint) hub addr/port */
if (musb->is_multipoint) {
musb_writeb(mbase,
MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR),
qh->addr_reg);
musb_writeb(mbase,
MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR),
qh->h_addr_reg);
musb_writeb(mbase,
MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT),
qh->h_port_reg);
musb_write_txfunaddr(mbase, epnum, qh->addr_reg);
musb_write_txhubaddr(mbase, epnum, qh->h_addr_reg);
musb_write_txhubport(mbase, epnum, qh->h_port_reg);
/* FIXME if !epnum, do the same for RX ... */
} else
musb_writeb(mbase, MUSB_FADDR, qh->addr_reg);
......@@ -750,8 +745,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
else
load_count = min((u32) packet_sz, len);
#ifdef CONFIG_USB_INVENTRA_DMA
if (dma_channel) {
if (musb_inventra_dma() && dma_channel) {
/* clear previous state */
csr = musb_readw(epio, MUSB_TXCSR);
......@@ -798,10 +792,9 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
dma_channel = NULL;
}
}
#endif
/* candidate for DMA */
if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) {
if ((cppi_ti_dma() || tusb_dma_omap()) && dma_channel) {
/* program endpoint CSRs first, then setup DMA.
* assume CPPI setup succeeds.
......@@ -893,7 +886,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
/* kick things off */
if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) {
if ((cppi_ti_dma() || tusb_dma_omap()) && dma_channel) {
/* candidate for DMA */
if (dma_channel) {
dma_channel->actual_len = 0L;
......@@ -988,8 +981,10 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)
if (fifo_count) {
fifo_dest = (u8 *) (urb->transfer_buffer
+ urb->actual_length);
DBG(3, "Sending %d bytes to %p\n",
fifo_count, fifo_dest);
DBG(3, "Sending %d byte%s to ep0 fifo %p\n",
fifo_count,
(fifo_count == 1) ? "" : "s",
fifo_dest);
musb_write_fifo(hw_ep, fifo_count, fifo_dest);
urb->actual_length += fifo_count;
......@@ -1476,8 +1471,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
/* FIXME this is _way_ too much in-line logic for Mentor DMA */
#ifndef CONFIG_USB_INVENTRA_DMA
if (rx_csr & MUSB_RXCSR_H_REQPKT) {
if (!musb_inventra_dma() && (rx_csr & MUSB_RXCSR_H_REQPKT)) {
/* REVISIT this happened for a while on some short reads...
* the cleanup still needs investigation... looks bad...
* and also duplicates dma cleanup code above ... plus,
......@@ -1498,7 +1492,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
musb_writew(epio, MUSB_RXCSR,
MUSB_RXCSR_H_WZC_BITS | rx_csr);
}
#endif
if (dma && (rx_csr & MUSB_RXCSR_DMAENAB)) {
xfer_len = dma->actual_len;
......@@ -1564,8 +1558,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
}
/* we are expecting IN packets */
#ifdef CONFIG_USB_INVENTRA_DMA
if (dma) {
if (musb_inventra_dma() && dma) {
struct dma_controller *c;
u16 rx_count;
int ret, length;
......@@ -1674,7 +1667,6 @@ void musb_host_rx(struct musb *musb, u8 epnum)
/* REVISIT reset CSR */
}
}
#endif /* Mentor DMA */
if (!dma) {
done = musb_host_packet_rx(musb, urb,
......
......@@ -39,7 +39,7 @@
#if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \
&& !defined(CONFIG_AVR32) && !defined(CONFIG_PPC32) \
&& !defined(CONFIG_PPC64)
&& !defined(CONFIG_PPC64) && !defined(CONFIG_BLACKFIN)
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)
......@@ -56,6 +56,8 @@ static inline void writesb(const void __iomem *addr, const void *buf, int len)
#endif
#ifndef CONFIG_BLACKFIN
/* NOTE: these offsets are all in bytes */
static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
......@@ -114,4 +116,26 @@ static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
#endif /* CONFIG_USB_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
This diff is collapsed.
......@@ -34,58 +34,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include "musb_core.h"
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
#include "omap2430.h"
#endif
#define MUSB_HSDMA_BASE 0x200
#define MUSB_HSDMA_INTR (MUSB_HSDMA_BASE + 0)
#define MUSB_HSDMA_CONTROL 0x4
#define MUSB_HSDMA_ADDRESS 0x8
#define MUSB_HSDMA_COUNT 0xc
#define MUSB_HSDMA_CHANNEL_OFFSET(_bchannel, _offset) \
(MUSB_HSDMA_BASE + (_bchannel << 4) + _offset)
/* control register (16-bit): */
#define MUSB_HSDMA_ENABLE_SHIFT 0
#define MUSB_HSDMA_TRANSMIT_SHIFT 1
#define MUSB_HSDMA_MODE1_SHIFT 2
#define MUSB_HSDMA_IRQENABLE_SHIFT 3
#define MUSB_HSDMA_ENDPOINT_SHIFT 4
#define MUSB_HSDMA_BUSERROR_SHIFT 8
#define MUSB_HSDMA_BURSTMODE_SHIFT 9
#define MUSB_HSDMA_BURSTMODE (3 << MUSB_HSDMA_BURSTMODE_SHIFT)
#define MUSB_HSDMA_BURSTMODE_UNSPEC 0
#define MUSB_HSDMA_BURSTMODE_INCR4 1
#define MUSB_HSDMA_BURSTMODE_INCR8 2
#define MUSB_HSDMA_BURSTMODE_INCR16 3
#define MUSB_HSDMA_CHANNELS 8
struct musb_dma_controller;
struct musb_dma_channel {
struct dma_channel channel;
struct musb_dma_controller *controller;
u32 start_addr;
u32 len;
u16 max_packet_sz;
u8 idx;
u8 epnum;
u8 transmit;
};
struct musb_dma_controller {
struct dma_controller controller;
struct musb_dma_channel channel[MUSB_HSDMA_CHANNELS];
void *private_data;
void __iomem *base;
u8 channel_count;
u8 used_channels;
u8 irq;
};
#include "musbhsdma.h"
static int dma_controller_start(struct dma_controller *c)
{
......@@ -179,36 +128,24 @@ static void configure_channel(struct dma_channel *channel,
DBG(4, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n",
channel, packet_sz, dma_addr, len, mode);
if (mode) {
csr |= 1 << MUSB_HSDMA_MODE1_SHIFT;
BUG_ON(len < packet_sz);
if (packet_sz >= 64) {
csr |= MUSB_HSDMA_BURSTMODE_INCR16
<< MUSB_HSDMA_BURSTMODE_SHIFT;
} else if (packet_sz >= 32) {
csr |= MUSB_HSDMA_BURSTMODE_INCR8
<< MUSB_HSDMA_BURSTMODE_SHIFT;
} else if (packet_sz >= 16) {
csr |= MUSB_HSDMA_BURSTMODE_INCR4
<< MUSB_HSDMA_BURSTMODE_SHIFT;
}
}
if (packet_sz >= 64)
csr |= MUSB_HSDMA_BURSTMODE_INCR16;
else if (packet_sz >= 32)
csr |= MUSB_HSDMA_BURSTMODE_INCR8;
else if (packet_sz >= 16)
csr |= MUSB_HSDMA_BURSTMODE_INCR4;
csr |= (musb_channel->epnum << MUSB_HSDMA_ENDPOINT_SHIFT)
| (1 << MUSB_HSDMA_ENABLE_SHIFT)
| (1 << MUSB_HSDMA_IRQENABLE_SHIFT)
| MUSB_HSDMA_MODE1
| MUSB_HSDMA_ENABLE
| MUSB_HSDMA_IRQENABLE
| (musb_channel->transmit
? (1 << MUSB_HSDMA_TRANSMIT_SHIFT)
? MUSB_HSDMA_TRANSMIT
: 0);
/* address/count */
musb_writel(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS),
dma_addr);
musb_writel(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT),
len);
musb_write_hsdma_addr(mbase, bchannel, dma_addr);
musb_write_hsdma_count(mbase, bchannel, len);
/* control (this should start things) */
musb_writew(mbase,
......@@ -236,10 +173,7 @@ static int dma_channel_program(struct dma_channel *channel,
musb_channel->max_packet_sz = packet_sz;
channel->status = MUSB_DMA_STATUS_BUSY;
if ((mode == 1) && (len >= packet_sz))
configure_channel(channel, packet_sz, 1, dma_addr, len);
else
configure_channel(channel, packet_sz, 0, dma_addr, len);
configure_channel(channel, packet_sz, mode, dma_addr, len);
return true;
}
......@@ -279,13 +213,8 @@ static int dma_channel_abort(struct dma_channel *channel)
musb_writew(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_CONTROL),
0);
musb_writel(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS),
0);
musb_writel(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT),
0);
musb_write_hsdma_addr(mbase, bchannel, 0);
musb_write_hsdma_count(mbase, bchannel, 0);
channel->status = MUSB_DMA_STATUS_FREE;
}
......@@ -327,16 +256,14 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
MUSB_HSDMA_CHANNEL_OFFSET(bchannel,
MUSB_HSDMA_CONTROL));
if (csr & (1 << MUSB_HSDMA_BUSERROR_SHIFT)) {
if (csr & MUSB_HSDMA_BUSERROR) {
musb_channel->channel.status =
MUSB_DMA_STATUS_BUS_ABORT;
} else {
u8 devctl;
addr = musb_readl(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(
bchannel,
MUSB_HSDMA_ADDRESS));
addr = musb_read_hsdma_addr(mbase,
bchannel);
channel->actual_len = addr
- musb_channel->start_addr;
......@@ -375,6 +302,12 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
}
}
}
#ifdef CONFIG_BLACKFIN
/* Clear DMA interrup flags */
musb_writeb(mbase, MUSB_HSDMA_INTR, int_hsdma);
#endif
retval = IRQ_HANDLED;
done:
spin_unlock_irqrestore(&musb->lock, flags);
......
/*
* MUSB OTG driver - support for Mentor's DMA controller
*
* Copyright 2005 Mentor Graphics Corporation
* Copyright (C) 2005-2007 by Texas Instruments
*
* 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.
*
*/
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
#include "omap2430.h"
#endif
#ifndef CONFIG_BLACKFIN
#define MUSB_HSDMA_BASE 0x200
#define MUSB_HSDMA_INTR (MUSB_HSDMA_BASE + 0)
#define MUSB_HSDMA_CONTROL 0x4
#define MUSB_HSDMA_ADDRESS 0x8
#define MUSB_HSDMA_COUNT 0xc
#define MUSB_HSDMA_CHANNEL_OFFSET(_bchannel, _offset) \
(MUSB_HSDMA_BASE + (_bchannel << 4) + _offset)
#define musb_read_hsdma_addr(mbase, bchannel) \
musb_readl(mbase, \
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS))
#define musb_write_hsdma_addr(mbase, bchannel, addr) \
musb_writel(mbase, \
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS), \
addr)
#define musb_write_hsdma_count(mbase, bchannel, len) \
musb_writel(mbase, \
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT), \
len)
#else
#define MUSB_HSDMA_BASE 0x400
#define MUSB_HSDMA_INTR (MUSB_HSDMA_BASE + 0)
#define MUSB_HSDMA_CONTROL 0x04
#define MUSB_HSDMA_ADDR_LOW 0x08
#define MUSB_HSDMA_ADDR_HIGH 0x0C
#define MUSB_HSDMA_COUNT_LOW 0x10
#define MUSB_HSDMA_COUNT_HIGH 0x14
#define MUSB_HSDMA_CHANNEL_OFFSET(_bchannel, _offset) \
(MUSB_HSDMA_BASE + (_bchannel * 0x20) + _offset)
static inline u32 musb_read_hsdma_addr(void __iomem *mbase, u8 bchannel)
{
u32 addr = musb_readw(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_HIGH));
addr = addr << 16;
addr |= musb_readw(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_LOW));
return addr;
}
static inline void musb_write_hsdma_addr(void __iomem *mbase,
u8 bchannel, dma_addr_t dma_addr)
{
musb_writew(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_LOW),
((u16)((u32) dma_addr & 0xFFFF)));
musb_writew(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_HIGH),
((u16)(((u32) dma_addr >> 16) & 0xFFFF)));
}
static inline void musb_write_hsdma_count(void __iomem *mbase,
u8 bchannel, u32 len)
{
musb_writew(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW),
((u16)((u32) len & 0xFFFF)));
musb_writew(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH),
((u16)(((u32) len >> 16) & 0xFFFF)));
}
#endif /* CONFIG_BLACKFIN */
/* control register (16-bit): */
#define MUSB_HSDMA_ENABLE (1 << 0)
#define MUSB_HSDMA_TRANSMIT (1 << 1)
#define MUSB_HSDMA_MODE1 (1 << 2)
#define MUSB_HSDMA_IRQENABLE (1 << 3)
#define MUSB_HSDMA_ENDPOINT_SHIFT 4
#define MUSB_HSDMA_BUSERROR (1 << 8)
#define MUSB_HSDMA_BURSTMODE_SHIFT 9
#define MUSB_HSDMA_BURSTMODE_UNSPEC (0 << MUSB_HSDMA_BURSTMODE_SHIFT)
#define MUSB_HSDMA_BURSTMODE_INCR4 (1 << MUSB_HSDMA_BURSTMODE_SHIFT)
#define MUSB_HSDMA_BURSTMODE_INCR8 (2 << MUSB_HSDMA_BURSTMODE_SHIFT)
#define MUSB_HSDMA_BURSTMODE_INCR16 (3 << MUSB_HSDMA_BURSTMODE_SHIFT)
#define MUSB_HSDMA_CHANNELS 8
struct musb_dma_controller;
struct musb_dma_channel {
struct dma_channel channel;
struct musb_dma_controller *controller;
u32 start_addr;
u32 len;
u16 max_packet_sz;
u8 idx;
u8 epnum;
u8 transmit;
};
struct musb_dma_controller {
struct dma_controller controller;
struct musb_dma_channel channel[MUSB_HSDMA_CHANNELS];
void *private_data;
void __iomem *base;
u8 channel_count;
u8 used_channels;
u8 irq;
};
......@@ -58,10 +58,10 @@ static void musb_do_idle(unsigned long _musb)
#endif
u8 devctl;
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
spin_lock_irqsave(&musb->lock, flags);
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
switch (musb->xceiv.state) {
case OTG_STATE_A_WAIT_BCON:
devctl &= ~MUSB_DEVCTL_SESSION;
......@@ -196,7 +196,7 @@ static int omap_set_power(struct otg_transceiver *x, unsigned mA)
static int musb_platform_resume(struct musb *musb);
void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
{
u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
......@@ -204,15 +204,24 @@ void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
switch (musb_mode) {
#ifdef CONFIG_USB_MUSB_HDRC_HCD
case MUSB_HOST:
otg_set_host(&musb->xceiv, musb->xceiv.host);
break;
#endif
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
case MUSB_PERIPHERAL:
otg_set_peripheral(&musb->xceiv, musb->xceiv.gadget);
break;
#endif
#ifdef CONFIG_USB_MUSB_OTG
case MUSB_OTG:
break;
#endif
default:
return -EINVAL;
}
return 0;
}
int __init musb_platform_init(struct musb *musb)
......
......@@ -598,7 +598,7 @@ static void tusb_source_power(struct musb *musb, int is_on)
* and peripheral modes in non-OTG configurations by reconfiguring hardware
* and then setting musb->board_mode. For now, only support OTG mode.
*/
void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
{
void __iomem *tbase = musb->ctrl_base;
u32 otg_stat, phy_otg_ctrl, phy_otg_ena, dev_conf;
......@@ -641,7 +641,8 @@ void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
#endif
default:
DBG(2, "Trying to set unknown mode %i\n", musb_mode);
DBG(2, "Trying to set mode %i\n", musb_mode);
return -EINVAL;
}
musb_writel(tbase, TUSB_PHY_OTG_CTRL,
......@@ -655,6 +656,8 @@ void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
!(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS))
INFO("Cannot be peripheral with mini-A cable "
"otg_stat: %08x\n", otg_stat);
return 0;
}
static inline unsigned long
......
......@@ -47,6 +47,11 @@ struct musb_hdrc_config {
u8 ram_bits; /* ram address size */
struct musb_hdrc_eps_bits *eps_bits;
#ifdef CONFIG_BLACKFIN
/* A GPIO controlling VRSEL in Blackfin */
unsigned int gpio_vrsel;
#endif
};
struct musb_hdrc_platform_data {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment