From 81a529fd4b7705b4bf7ae043ffc140be265a4abf Mon Sep 17 00:00:00 2001 From: Vikram Pandita Date: Fri, 25 May 2007 14:59:39 -0700 Subject: [PATCH] musb_hdrc: MUSB HOST support on 2430SDP Fix Mentor controller DMA for OMAP2430/3430 Signed-off-by: Vikram Pandita Signed-off-by: Nishant Kamat Acked-by: Kevin Hilman Signed-off-by: Tony Lindgren --- drivers/usb/musb/musb_gadget.c | 24 ++- drivers/usb/musb/musb_host.c | 39 +--- drivers/usb/musb/musbdefs.h | 3 +- drivers/usb/musb/musbhsdma.c | 375 ++++++++++++++++++--------------- drivers/usb/musb/omap2430.c | 124 ++++++++--- drivers/usb/musb/omap2430.h | 42 +++- 6 files changed, 362 insertions(+), 245 deletions(-) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 0626aa51481..b466495debf 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -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); diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 82ece3b20c8..35582a070fa 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -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 ... */ diff --git a/drivers/usb/musb/musbdefs.h b/drivers/usb/musb/musbdefs.h index a64e2edcc45..b534d796035 100644 --- a/drivers/usb/musb/musbdefs.h +++ b/drivers/usb/musb/musbdefs.h @@ -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 ... */ diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index ea39d0ce293..22baf00b3d8 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -1,6 +1,6 @@ /****************************************************************** * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments + * Copyright (C) 2005-2007 by Texas Instruments * * This file is part of the Inventra Controller Driver for Linux. * @@ -32,88 +32,108 @@ ******************************************************************/ /* - * Interface to Mentor's DMA engine + * Implementation for the DMA controller within the MUSBMHDRC. */ +#include +#include #include - #include "musbdefs.h" +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) +#include "omap2430.h" +#endif -/****************************** CONSTANTS ********************************/ - -#define MGC_O_HSDMA_BASE 0x200 -#define MGC_O_HSDMA_INTR 0x200 - -#define MGC_O_HSDMA_CONTROL 4 -#define MGC_O_HSDMA_ADDRESS 8 -#define MGC_O_HSDMA_COUNT 0xc +#define MGC_O_HSDMA_BASE 0x200 +#define MGC_O_HSDMA_INTR (MGC_O_HSDMA_BASE + 0) +#define MGC_O_HSDMA_CONTROL 0x4 +#define MGC_O_HSDMA_ADDRESS 0x8 +#define MGC_O_HSDMA_COUNT 0xc #define MGC_HSDMA_CHANNEL_OFFSET(_bChannel, _bOffset) \ (MGC_O_HSDMA_BASE + (_bChannel << 4) + _bOffset) /* control register (16-bit): */ -#define MGC_S_HSDMA_ENABLE 0 -#define MGC_S_HSDMA_TRANSMIT 1 -#define MGC_S_HSDMA_MODE1 2 -#define MGC_S_HSDMA_IRQENABLE 3 -#define MGC_S_HSDMA_ENDPOINT 4 -#define MGC_S_HSDMA_BUSERROR 8 -#define MGC_S_HSDMA_BURSTMODE 9 -#define MGC_M_HSDMA_BURSTMODE (3 << MGC_S_HSDMA_BURSTMODE) -#define MGC_HSDMA_BURSTMODE_UNSPEC 0 -#define MGC_HSDMA_BURSTMODE_INCR4 1 -#define MGC_HSDMA_BURSTMODE_INCR8 2 -#define MGC_HSDMA_BURSTMODE_INCR16 3 - -#define MGC_HSDMA_CHANNELS 8 - -/******************************* Types ********************************/ - -struct hsdma_channel { - struct dma_channel Channel; - struct hsdma *pController; - u32 dwStartAddress; - u32 dwCount; - u8 bIndex; - u8 bEnd; - u8 bTransmit; +#define MGC_S_HSDMA_ENABLE 0 +#define MGC_S_HSDMA_TRANSMIT 1 +#define MGC_S_HSDMA_MODE1 2 +#define MGC_S_HSDMA_IRQENABLE 3 +#define MGC_S_HSDMA_ENDPOINT 4 +#define MGC_S_HSDMA_BUSERROR 8 +#define MGC_S_HSDMA_BURSTMODE 9 +#define MGC_M_HSDMA_BURSTMODE (3 << MGC_S_HSDMA_BURSTMODE) +#define MGC_HSDMA_BURSTMODE_UNSPEC 0 +#define MGC_HSDMA_BURSTMODE_INCR4 1 +#define MGC_HSDMA_BURSTMODE_INCR8 2 +#define MGC_HSDMA_BURSTMODE_INCR16 3 + +#define MGC_HSDMA_CHANNELS 8 + +struct musb_dma_controller; + +struct musb_dma_channel { + struct dma_channel Channel; + struct musb_dma_controller *pController; + u32 dwStartAddress; + u32 dwCount; + u16 wMaxPacketSize; + u8 bIndex; + u8 bEnd; + u8 bTransmit; }; -struct hsdma { - struct dma_controller Controller; - struct hsdma_channel aChannel[MGC_HSDMA_CHANNELS]; - void *pDmaPrivate; - void __iomem *pCoreBase; - u8 bChannelCount; - u8 bmUsedChannels; +struct musb_dma_controller { + struct dma_controller Controller; + struct musb_dma_channel aChannel[MGC_HSDMA_CHANNELS]; + void *pDmaPrivate; + void __iomem *pCoreBase; + u8 bChannelCount; + u8 bmUsedChannels; + u8 irq; }; -/****************************** FUNCTIONS ********************************/ - -static int hsdma_start(struct dma_controller *c) +static int dma_controller_start(struct dma_controller *c) { /* nothing to do */ return 0; } -static int hsdma_stop(struct dma_controller *c) +static void dma_channel_release(struct dma_channel *pChannel); + +static int dma_controller_stop(struct dma_controller *c) { - /* nothing to do */ + struct musb_dma_controller *pController = + container_of(c, struct musb_dma_controller, Controller); + struct musb *pThis = (struct musb *) pController->pDmaPrivate; + struct dma_channel *pChannel; + u8 bBit; + + if (pController->bmUsedChannels != 0) { + dev_err(pThis->controller, + "Stopping DMA controller while channel active\n"); + + for (bBit = 0; bBit < MGC_HSDMA_CHANNELS; bBit++) { + if (pController->bmUsedChannels & (1 << bBit)) { + pChannel = &(pController->aChannel[bBit].Channel); + dma_channel_release(pChannel); + + if (!pController->bmUsedChannels) + break; + } + } + } return 0; } -static struct dma_channel * -hsdma_channel_alloc(struct dma_controller *c, - struct musb_hw_ep *hw_ep, - u8 bTransmit) +static struct dma_channel* dma_channel_allocate(struct dma_controller *c, + struct musb_hw_ep *hw_ep, u8 bTransmit) { u8 bBit; struct dma_channel *pChannel = NULL; - struct hsdma_channel *pImplChannel = NULL; - struct hsdma *pController; + struct musb_dma_channel *pImplChannel = NULL; + struct musb_dma_controller *pController = + container_of(c, struct musb_dma_controller, Controller); - pController = container_of(c, struct hsdma, Controller); for (bBit = 0; bBit < MGC_HSDMA_CHANNELS; bBit++) { if (!(pController->bmUsedChannels & (1 << bBit))) { pController->bmUsedChannels |= (1 << bBit); @@ -135,48 +155,33 @@ hsdma_channel_alloc(struct dma_controller *c, return pChannel; } -static void hsdma_channel_release(struct dma_channel *pChannel) +static void dma_channel_release(struct dma_channel *pChannel) { - struct hsdma_channel *pImplChannel = pChannel->pPrivateData; - - pImplChannel->pController->bmUsedChannels &= - ~(1 << pImplChannel->bIndex); - pChannel->bStatus = MGC_DMA_STATUS_FREE; -} - -static void clear_state(struct dma_channel *pChannel) -{ - struct hsdma_channel *pImplChannel = pChannel->pPrivateData; - struct hsdma *pController = pImplChannel->pController; - u8 *pBase = pController->pCoreBase; - u8 bChannel = pImplChannel->bIndex; - - musb_writew(pBase, - MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_CONTROL), - 0); - musb_writel(pBase, - MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_ADDRESS), - 0); - musb_writel(pBase, - MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_COUNT), - 0); + struct musb_dma_channel *pImplChannel = + (struct musb_dma_channel *) pChannel->pPrivateData; - pChannel->dwActualLength = 0L; + pChannel->dwActualLength = 0; pImplChannel->dwStartAddress = 0; pImplChannel->dwCount = 0; + + pImplChannel->pController->bmUsedChannels &= + ~(1 << pImplChannel->bIndex); + + pChannel->bStatus = MGC_DMA_STATUS_UNKNOWN; } -static u8 configure_channel(struct dma_channel *pChannel, - u16 wPacketSize, u8 bMode, - dma_addr_t dma_addr, u32 dwLength) +static void configure_channel(struct dma_channel *pChannel, + u16 wPacketSize, u8 bMode, + dma_addr_t dma_addr, u32 dwLength) { - struct hsdma_channel *pImplChannel = pChannel->pPrivateData; - struct hsdma *pController = pImplChannel->pController; + struct musb_dma_channel *pImplChannel = + (struct musb_dma_channel *) pChannel->pPrivateData; + struct musb_dma_controller *pController = pImplChannel->pController; u8 *pBase = pController->pCoreBase; u8 bChannel = pImplChannel->bIndex; u16 wCsr = 0; - DBG(2, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n", + DBG(4, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n", pChannel, wPacketSize, dma_addr, dwLength, bMode); if (bMode) { @@ -213,45 +218,32 @@ static u8 configure_channel(struct dma_channel *pChannel, musb_writew(pBase, MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_CONTROL), wCsr); - - return TRUE; } -static int hsdma_channel_program(struct dma_channel * pChannel, - u16 wPacketSize, u8 bMode, - dma_addr_t dma_addr, u32 dwLength) +static int dma_channel_program(struct dma_channel * pChannel, + u16 wPacketSize, u8 bMode, + dma_addr_t dma_addr, u32 dwLength) { - struct hsdma_channel *pImplChannel = pChannel->pPrivateData; + struct musb_dma_channel *pImplChannel = + (struct musb_dma_channel *) pChannel->pPrivateData; - DBG(2, "pkt_sz %d, dma_addr 0x%x length %d, mode %d\n", - wPacketSize, dma_addr, dwLength, bMode); + DBG(2, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n", + pImplChannel->bEnd, + pImplChannel->bTransmit ? "Tx" : "Rx", + wPacketSize, dma_addr, dwLength, bMode); - BUG_ON(pChannel->bStatus != MGC_DMA_STATUS_FREE); + BUG_ON(pChannel->bStatus == MGC_DMA_STATUS_UNKNOWN || + pChannel->bStatus == MGC_DMA_STATUS_BUSY); - pChannel->dwActualLength = 0L; + pChannel->dwActualLength = 0; pImplChannel->dwStartAddress = dma_addr; pImplChannel->dwCount = dwLength; - + pImplChannel->wMaxPacketSize = wPacketSize; pChannel->bStatus = MGC_DMA_STATUS_BUSY; if ((bMode == 1) && (dwLength >= wPacketSize)) { - -#if 0 - /* mode 1 sends an extra IN token at the end of - * full packet transfer in host Rx - */ - if (dwLength % wPacketSize == 0) - dwLength -= wPacketSize; - - /* mode 1 doesn't give an interrupt on short packet */ - configure_channel(pChannel, wPacketSize, 1, dma_addr, - dwLength & ~(wPacketSize - 1)); - /* the rest (<= pkt_size) will be transferred in mode 0 */ -#endif - configure_channel(pChannel, wPacketSize, 1, dma_addr, dwLength); - } else configure_channel(pChannel, wPacketSize, 0, dma_addr, dwLength); @@ -259,32 +251,70 @@ static int hsdma_channel_program(struct dma_channel * pChannel, return TRUE; } -// REVISIT... -static int hsdma_channel_abort(struct dma_channel *pChannel) +static int dma_channel_abort(struct dma_channel *pChannel) { - clear_state(pChannel); - pChannel->bStatus = MGC_DMA_STATUS_FREE; + struct musb_dma_channel *pImplChannel = + (struct musb_dma_channel *) pChannel->pPrivateData; + u8 bChannel = pImplChannel->bIndex; + u8 *pBase = pImplChannel->pController->pCoreBase; + u16 csr; + + if (pChannel->bStatus == MGC_DMA_STATUS_BUSY) { + if (pImplChannel->bTransmit) { + + csr = musb_readw(pBase, + MGC_END_OFFSET(pImplChannel->bEnd,MGC_O_HDRC_TXCSR)); + csr &= ~(MGC_M_TXCSR_AUTOSET | + MGC_M_TXCSR_DMAENAB | + MGC_M_TXCSR_DMAMODE); + musb_writew(pBase, + MGC_END_OFFSET(pImplChannel->bEnd,MGC_O_HDRC_TXCSR), + csr); + } + else { + csr = musb_readw(pBase, + MGC_END_OFFSET(pImplChannel->bEnd,MGC_O_HDRC_RXCSR)); + csr &= ~(MGC_M_RXCSR_AUTOCLEAR | + MGC_M_RXCSR_DMAENAB | + MGC_M_RXCSR_DMAMODE); + musb_writew(pBase, + MGC_END_OFFSET(pImplChannel->bEnd,MGC_O_HDRC_RXCSR), + csr); + } + + musb_writew(pBase, + MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_CONTROL), 0); + musb_writel(pBase, + MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_ADDRESS), 0); + musb_writel(pBase, + MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_COUNT), 0); + + pChannel->bStatus = MGC_DMA_STATUS_FREE; + } return 0; } -static irqreturn_t hsdma_irq(int irq, void *pPrivateData) +static irqreturn_t dma_controller_irq(int irq, void *pPrivateData) { + struct musb_dma_controller *pController = + (struct musb_dma_controller *)pPrivateData; + struct musb_dma_channel *pImplChannel; + u8 *pBase = pController->pCoreBase; + struct dma_channel *pChannel; u8 bChannel; u16 wCsr; u32 dwAddress; - struct hsdma_channel *pImplChannel; - struct hsdma *pController = pPrivateData; - u8 *pBase = pController->pCoreBase; - struct dma_channel *pChannel; - u8 bIntr = musb_readb(pBase, MGC_O_HSDMA_INTR); + u8 bIntr; + irqreturn_t retval = IRQ_NONE; + bIntr = musb_readb(pBase, MGC_O_HSDMA_INTR); if (!bIntr) - return IRQ_NONE; + goto done; for (bChannel = 0; bChannel < MGC_HSDMA_CHANNELS; bChannel++) { if (bIntr & (1 << bChannel)) { - - pImplChannel = &pController->aChannel[bChannel]; + pImplChannel = (struct musb_dma_channel *) + &(pController->aChannel[bChannel]); pChannel = &pImplChannel->Channel; wCsr = musb_readw(pBase, @@ -296,8 +326,8 @@ static irqreturn_t hsdma_irq(int irq, void *pPrivateData) MGC_DMA_STATUS_BUS_ABORT; } else { dwAddress = musb_readl(pBase, - MGC_HSDMA_CHANNEL_OFFSET - (bChannel, + MGC_HSDMA_CHANNEL_OFFSET( + bChannel, MGC_O_HSDMA_ADDRESS)); pChannel->dwActualLength = dwAddress - pImplChannel->dwStartAddress; @@ -309,55 +339,57 @@ static irqreturn_t hsdma_irq(int irq, void *pPrivateData) (pChannel->dwActualLength < pImplChannel->dwCount) ? "=> reconfig 0": "=> complete"); -#if 0 - if (pChannel->dwActualLength < - pImplChannel->dwCount) { - /* mode 1 sends an extra IN request if - the last packet is a complete packet */ - u16 newcsr = MGC_ReadCsr16(pBase, - MGC_O_HDRC_RXCSR, - pImplChannel->bEnd); - newcsr &= ~(MGC_M_RXCSR_H_AUTOREQ | - MGC_M_RXCSR_H_REQPKT); - MGC_WriteCsr16(pBase, MGC_O_HDRC_RXCSR, - pImplChannel->bEnd, - MGC_M_RXCSR_H_WZC_BITS | - newcsr); - - configure_channel(pChannel, - pImplChannel->wMaxPacketSize, - 0, dwAddress, - pImplChannel->dwCount - - pChannel->dwActualLength); - } - else -#endif - { - pChannel->bStatus = MGC_DMA_STATUS_FREE; - /* completed */ + + u8 devctl = musb_readb(pBase, + MGC_O_HDRC_DEVCTL); + + pChannel->bStatus = MGC_DMA_STATUS_FREE; + + /* completed */ + if ((devctl & MGC_M_DEVCTL_HM) + && (pImplChannel->bTransmit) + && ((pChannel->bDesiredMode == 0) + || (pChannel->dwActualLength & + (pImplChannel->wMaxPacketSize - 1))) + ) { + /* Send out the packet */ + MGC_SelectEnd(pBase, + pImplChannel->bEnd); + musb_writew(pBase, + MGC_END_OFFSET(pImplChannel->bEnd,MGC_O_HDRC_TXCSR), + MGC_M_TXCSR_TXPKTRDY); + } else musb_dma_completion( pController->pDmaPrivate, pImplChannel->bEnd, pImplChannel->bTransmit); - } } } } - return IRQ_HANDLED; + retval = IRQ_HANDLED; +done: + return retval; } -void dma_controller_destroy(struct dma_controller *pController) +void dma_controller_destroy(struct dma_controller *c) { - struct hsdma *pHsController = pController->pPrivateData; + struct musb_dma_controller *pController = + (struct musb_dma_controller *) c->pPrivateData; - pHsController->Controller.pPrivateData = NULL; - kfree(pHsController); + if (!pController) + return; + + if (pController->irq) + free_irq(pController->irq, c); + + kfree(pController); + c->pPrivateData = NULL; } struct dma_controller *__init dma_controller_create(struct musb *pThis, void __iomem *pCoreBase) { - struct hsdma *pController; + struct musb_dma_controller *pController; struct device *dev = pThis->controller; struct platform_device *pdev = to_platform_device(dev); int irq = platform_get_irq(pdev, 1); @@ -367,7 +399,8 @@ dma_controller_create(struct musb *pThis, void __iomem *pCoreBase) return NULL; } - if (!(pController = kzalloc(sizeof *pController, GFP_KERNEL))) + if (!(pController = kzalloc(sizeof(struct musb_dma_controller), + GFP_KERNEL))) return NULL; pController->bChannelCount = MGC_HSDMA_CHANNELS; @@ -375,19 +408,21 @@ dma_controller_create(struct musb *pThis, void __iomem *pCoreBase) pController->pCoreBase = pCoreBase; pController->Controller.pPrivateData = pController; - pController->Controller.start = hsdma_start; - pController->Controller.stop = hsdma_stop; - pController->Controller.channel_alloc = hsdma_channel_alloc; - pController->Controller.channel_release = hsdma_channel_release; - pController->Controller.channel_program = hsdma_channel_program; - pController->Controller.channel_abort = hsdma_channel_abort; - - if (request_irq(irq, hsdma_irq, IRQF_DISABLED, + pController->Controller.start = dma_controller_start; + pController->Controller.stop = dma_controller_stop; + pController->Controller.channel_alloc = dma_channel_allocate; + pController->Controller.channel_release = dma_channel_release; + pController->Controller.channel_program = dma_channel_program; + pController->Controller.channel_abort = dma_channel_abort; + + if (request_irq(irq, dma_controller_irq, IRQF_DISABLED, pThis->controller->bus_id, &pController->Controller)) { dev_err(dev, "request_irq %d failed!\n", irq); - kfree(pController); + dma_controller_destroy(&pController->Controller); return NULL; } + pController->irq = irq; + return &pController->Controller; } diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 18aba33c919..e475bc9e5f0 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -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; } diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h index c6ac6d3a549..3ce7be174f5 100644 --- a/drivers/usb/musb/omap2430.h +++ b/drivers/usb/musb/omap2430.h @@ -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 #include - /* * 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 */ -- 2.41.0