Commit 81a529fd authored by Vikram Pandita's avatar Vikram Pandita Committed by Tony Lindgren

musb_hdrc: MUSB HOST support on 2430SDP

Fix Mentor controller DMA for OMAP2430/3430
Signed-off-by: default avatarVikram Pandita <vikram.pandita@ti.com>
Signed-off-by: default avatarNishant Kamat <nskamat@ti.com>
Acked-by: default avatarKevin Hilman <khilman@mvista.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent 8d937e97
......@@ -159,12 +159,24 @@ __acquires(ep->musb->Lock)
static void nuke(struct musb_ep *ep, const int status)
{
struct musb_request *req = NULL;
void __iomem *epio = ep->pThis->aLocalEnd[ep->bEndNumber].regs;
ep->busy = 1;
if (is_dma_capable() && ep->dma) {
struct dma_controller *c = ep->pThis->pDmaController;
int value;
if (ep->is_in) {
musb_writew(epio, MGC_O_HDRC_TXCSR,
0 | MGC_M_TXCSR_FLUSHFIFO);
musb_writew(epio, MGC_O_HDRC_TXCSR,
0 | MGC_M_TXCSR_FLUSHFIFO);
} else {
musb_writew(epio, MGC_O_HDRC_RXCSR,
0 | MGC_M_RXCSR_FLUSHFIFO);
musb_writew(epio, MGC_O_HDRC_RXCSR,
0 | MGC_M_RXCSR_FLUSHFIFO);
}
value = c->channel_abort(ep->dma);
DBG(value ? 1 : 6, "%s: abort DMA --> %d\n", ep->name, value);
......@@ -454,12 +466,12 @@ void musb_g_tx(struct musb *musb, u8 bEnd)
musb_writew(epio, MGC_O_HDRC_TXCSR, wCsrVal);
/* ensure writebuffer is empty */
wCsrVal = musb_readw(epio, MGC_O_HDRC_TXCSR);
pRequest->actual += pEnd->dma->dwActualLength;
DBG(4, "TXCSR%d %04x, dma off, "
"len %Zd, req %p\n",
bEnd, wCsrVal,
pEnd->dma->dwActualLength,
pRequest);
pRequest->actual += pEnd->dma->dwActualLength;
}
if (is_dma || pRequest->actual == pRequest->length) {
......@@ -475,8 +487,9 @@ void musb_g_tx(struct musb *musb, u8 bEnd)
== 0)
#ifdef CONFIG_USB_INVENTRA_DMA
|| (is_dma &&
(pRequest->actual
< pEnd->wPacketSize))
((!dma->bDesiredMode) ||
(pRequest->actual &
(pEnd->wPacketSize - 1))))
#endif
) {
/* on dma completion, fifo may not
......@@ -489,6 +502,7 @@ void musb_g_tx(struct musb *musb, u8 bEnd)
musb_writew(epio, MGC_O_HDRC_TXCSR,
MGC_M_TXCSR_MODE
| MGC_M_TXCSR_TXPKTRDY);
pRequest->zero = 0;
}
/* ... or if not, then complete it */
......@@ -1143,6 +1157,8 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
if (!ep || !req)
return -EINVAL;
if (!req->buf)
return -ENODATA;
pEnd = to_musb_ep(ep);
musb = pEnd->pThis;
......@@ -1275,6 +1291,8 @@ int musb_gadget_set_halt(struct usb_ep *ep, int value)
struct musb_request *pRequest = NULL;
int status = 0;
if (!ep)
return -EINVAL;
pBase = musb->pRegs;
spin_lock_irqsave(&musb->Lock, flags);
......
......@@ -435,21 +435,6 @@ musb_advance_schedule(struct musb *pThis, struct urb *urb,
qh = pEnd->out_qh;
qh = musb_giveback(qh, urb, 0);
#ifdef CONFIG_USB_INVENTRA_DMA
/* REVISIT udelay reportedly works around issues in unmodified
* Mentor RTL before v1.5, where it doesn't disable the pull-up
* resisters in high speed mode. That causes signal reflection
* and errors because inter packet IDLE time vanishes.
*
* Yes, this delay makes DMA-OUT a bit slower than PIO. But
* without it, some devices are unusable. But there seem to be
* other issues too, at least on DaVinci; the delay improves
* some full speed cases, and being DMA-coupled is strange...
*/
if (is_dma_capable() && !is_in && pEnd->tx_channel)
udelay(15); /* 10 usec ~= 1x 512byte packet */
#endif
if (qh && qh->is_ready && !list_empty(&qh->hep->urb_list)) {
DBG(4, "... next ep%d %cX urb %p\n",
pEnd->bLocalEnd, is_in ? 'R' : 'T',
......@@ -498,6 +483,9 @@ static u8 musb_host_packet_rx(struct musb *pThis, struct urb *pUrb,
// MGC_SelectEnd(pBase, bEnd);
wRxCount = musb_readw(epio, MGC_O_HDRC_RXCOUNT);
DBG(3, "RX%d count %d, buffer %p len %d/%d\n", bEnd, wRxCount,
pUrb->transfer_buffer, qh->offset,
pUrb->transfer_buffer_length);
/* unload FIFO */
if (usb_pipeisoc(nPipe)) {
......@@ -1271,20 +1259,6 @@ void musb_host_tx(struct musb *pThis, u8 bEnd)
/* REVISIT this looks wrong... */
if (!status || dma || usb_pipeisoc(nPipe)) {
#ifdef CONFIG_USB_INVENTRA_DMA
/* mode 0 or last short packet)
* REVISIT how about ZLP?
*/
if ((dma->bDesiredMode == 0)
|| (dma->dwActualLength
& (qh->maxpacket - 1))) {
/* Send out the packet first ... */
MGC_SelectEnd(pBase, bEnd);
musb_writew(epio, MGC_O_HDRC_TXCSR,
MGC_M_TXCSR_TXPKTRDY);
}
#endif
if (dma)
wLength = dma->dwActualLength;
else
......@@ -1542,11 +1516,9 @@ void musb_host_rx(struct musb *pThis, u8 bEnd)
musb_writew(pEnd->regs, MGC_O_HDRC_RXCSR, wVal);
#ifdef CONFIG_USB_INVENTRA_DMA
pUrb->actual_length += xfer_len;
qh->offset += xfer_len;
/* bDone if pUrb buffer is full or short packet is recd */
bDone = (pUrb->actual_length >= pUrb->transfer_buffer_length)
bDone = ((pUrb->actual_length + xfer_len) >=
pUrb->transfer_buffer_length)
|| (dma->dwActualLength & (qh->maxpacket - 1));
/* send IN token for next packet, without AUTOREQ */
......@@ -1969,6 +1941,7 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in)
| MGC_M_TXCSR_H_RXSTALL
| MGC_M_TXCSR_H_NAKTIMEOUT
| MGC_M_TXCSR_H_ERROR
| MGC_M_TXCSR_TXPKTRDY
);
musb_writew(epio, MGC_O_HDRC_TXCSR, csr);
/* REVISIT may need to clear FLUSHFIFO ... */
......
......@@ -206,7 +206,8 @@ enum musb_g_ep0_state {
* directly with the "flat" model, or after setting up an index register.
*/
#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_ARCH_OMAP2430)
#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_ARCH_OMAP2430) || \
defined(CONFIG_ARCH_OMAP3430)
/* REVISIT indexed access seemed to
* misbehave (on DaVinci) for at least peripheral IN ...
*/
......
This diff is collapsed.
......@@ -36,68 +36,134 @@
#include "musbdefs.h"
#include "omap2430.h"
#ifdef CONFIG_ARCH_OMAP3430
#define get_cpu_rev() 2
#endif
static int dma_off;
void musb_platform_enable(struct musb *musb)
{
if (is_dma_capable() && dma_off)
printk(KERN_WARNING "%s %s: dma not reactivated\n",
__FILE__, __FUNCTION__);
else
dma_off = 1;
}
void musb_platform_disable(struct musb *musb)
{
if (is_dma_capable()) {
printk(KERN_WARNING "%s %s: dma still active\n",
__FILE__, __FUNCTION__);
dma_off = 1;
}
}
static void omap_vbus_power(struct musb *musb, int is_on, int sleeping)
{
}
static void omap_set_vbus(struct musb *musb, int is_on)
{
WARN_ON(is_on && is_peripheral_active(musb));
return omap_vbus_power(musb, is_on, 0);
u8 devctl;
/* HDRC controls CPEN, but beware current surges during device
* connect. They can trigger transient overcurrent conditions
* that must be ignored.
*/
devctl = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL);
if (is_on) {
musb->is_active = 1;
musb->xceiv.default_a = 1;
musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
devctl |= MGC_M_DEVCTL_SESSION;
MUSB_HST_MODE(musb);
} else {
musb->is_active = 0;
/* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and
* jumping right to B_IDLE...
*/
musb->xceiv.default_a = 0;
musb->xceiv.state = OTG_STATE_B_IDLE;
devctl &= ~MGC_M_DEVCTL_SESSION;
MUSB_DEV_MODE(musb);
}
musb_writeb(musb->pRegs, MGC_O_HDRC_DEVCTL, devctl);
DBG(1, "VBUS %s, devctl %02x "
/* otg %3x conf %08x prcm %08x */ "\n",
otg_state_string(musb),
musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL));
}
static int omap_set_power(struct otg_transceiver *x, unsigned mA)
{
return 0;
}
int musb_platform_resume(struct musb *musb);
int __init musb_platform_init(struct musb *musb)
{
/* Erratum - reset value of STP has pull-down.
Change it to pull-up. */
#if defined(CONFIG_ARCH_OMAP2430)
omap_cfg_reg(AE5_2430_USB0HS_STP);
/* start clock */
/* get the clock */
musb->clock = clk_get((struct device *)musb->controller, "usbhs_ick");
clk_enable(musb->clock);
#else
musb->clock = clk_get((struct device *)musb->controller, "hsusb_ick");
#endif
if(IS_ERR(musb->clock))
return PTR_ERR(musb->clock);
omap_writel(omap_readl(OTG_INTERFSEL) | (1<<0), OTG_INTERFSEL);
omap_writel(omap_readl(OTG_SYSCONFIG) |
((1 << 12) | (1 << 3) | (1 << 2)),
OTG_SYSCONFIG);
musb_platform_resume(musb);
OTG_INTERFSEL_REG |= ULPI_12PIN;
pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
"sysstatus 0x%x, intrfsel 0x%x, simenable 0x%x\n",
omap_readl(OTG_REVISION), omap_readl(OTG_SYSCONFIG),
omap_readl(OTG_SYSSTATUS), omap_readl(OTG_INTERFSEL),
omap_readl(OTG_SIMENABLE));
OTG_REVISION_REG, OTG_SYSCONFIG_REG, OTG_SYSSTATUS_REG,
OTG_INTERFSEL_REG, OTG_SIMENABLE_REG);
musb->board_set_vbus = omap_set_vbus;
omap_vbus_power(musb, musb->board_mode == MUSB_HOST, 1);
if (is_host_enabled(musb))
musb->board_set_vbus = omap_set_vbus;
if (is_peripheral_enabled(musb))
musb->xceiv.set_power = omap_set_power;
return 0;
}
int musb_platform_suspend(struct musb *musb)
{
/* in any role */
OTG_FORCESTDBY_REG &= ~ENABLEFORCE; /* disable MSTANDBY */
OTG_SYSCONFIG_REG &= FORCESTDBY; /* enable force standby */
OTG_SYSCONFIG_REG &= ~AUTOIDLE; /* disable auto idle */
OTG_SYSCONFIG_REG |= SMARTIDLE; /* enable smart idle */
OTG_FORCESTDBY_REG |= ENABLEFORCE; /* enable MSTANDBY */
OTG_SYSCONFIG_REG |= AUTOIDLE; /* enable auto idle */
clk_disable(musb->clock);
return 0;
}
int musb_platform_resume(struct musb *musb)
{
clk_enable(musb->clock);
OTG_FORCESTDBY_REG &= ~ENABLEFORCE; /* disable MSTANDBY */
OTG_SYSCONFIG_REG |= SMARTSTDBY; /* enable smart standby */
OTG_SYSCONFIG_REG &= ~AUTOIDLE; /* disable auto idle */
OTG_SYSCONFIG_REG |= SMARTIDLE; /* enable smart idle */
OTG_SYSCONFIG_REG |= AUTOIDLE; /* enable auto idle */
return 0;
}
int musb_platform_exit(struct musb *musb)
{
omap_vbus_power(musb, 0 /*off*/, 1);
clk_disable(musb->clock);
musb_platform_suspend(musb);
clk_put(musb->clock);
musb->clock = 0;
return 0;
}
......@@ -10,21 +10,45 @@
#ifndef __MUSB_OMAP243X_H__
#define __MUSB_OMAP243X_H__
#ifdef CONFIG_ARCH_OMAP2430
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
#include <asm/arch/hardware.h>
#include <asm/arch/usb.h>
/*
* OMAP2430-specific definitions
*/
#define MENTOR_BASE_OFFSET 0
#define HS_OTG(offset) (OMAP243X_HS_BASE + (offset))
#define OTG_REVISION HS_OTG(0x400)
#define OTG_SYSCONFIG HS_OTG(0x404)
#define OTG_SYSSTATUS HS_OTG(0x408)
#define OTG_INTERFSEL HS_OTG(0x40c)
#define OTG_SIMENABLE HS_OTG(0x410)
#if defined(CONFIG_ARCH_OMAP2430)
#define OMAP_HSOTG_BASE (OMAP243X_HS_BASE)
#elif defined(CONFIG_ARCH_OMAP3430)
#define OMAP_HSOTG_BASE (HS_BASE)
#endif
#define OMAP_HSOTG(offset) __REG32(OMAP_HSOTG_BASE + 0x400 + (offset))
#define OTG_REVISION_REG OMAP_HSOTG(0x0)
#define OTG_SYSCONFIG_REG OMAP_HSOTG(0x4)
# define MIDLEMODE 12 /* bit position */
# define FORCESTDBY (0 << MIDLEMODE)
# define NOSTDBY (1 << MIDLEMODE)
# define SMARTSTDBY (2 << MIDLEMODE)
# define SIDLEMODE 3 /* bit position */
# define FORCEIDLE (0 << SIDLEMODE)
# define NOIDLE (1 << SIDLEMODE)
# define SMARTIDLE (2 << SIDLEMODE)
# define ENABLEWAKEUP (1 << 2)
# define SOFTRST (1 << 1)
# define AUTOIDLE (1 << 0)
#define OTG_SYSSTATUS_REG OMAP_HSOTG(0x8)
# define RESETDONE (1 << 0)
#define OTG_INTERFSEL_REG OMAP_HSOTG(0xc)
# define EXTCP (1 << 2)
# define PHYSEL 0 /* bit position */
# define UTMI_8BIT (0 << PHYSEL)
# define ULPI_12PIN (1 << PHYSEL)
# define ULPI_8PIN (2 << PHYSEL)
#define OTG_SIMENABLE_REG OMAP_HSOTG(0x10)
# define TM1 (1 << 0)
#define OTG_FORCESTDBY_REG OMAP_HSOTG(0x14)
# define ENABLEFORCE (1 << 0)
#endif /* CONFIG_ARCH_OMAP2430 */
......
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