-/******************************************************************
+/*
+ * MUSB OTG driver host support
+ *
* Copyright 2005 Mentor Graphics Corporation
* Copyright (C) 2005-2006 by Texas Instruments
- * Copyright (C) 2006 by Nokia Corporation
+ * Copyright (C) 2006-2007 Nokia Corporation
*
- * This file is part of the Inventra Controller Driver for Linux.
+ * 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.
*
- * The Inventra Controller Driver for Linux is free software; you
- * can redistribute it and/or modify it under the terms of the GNU
- * General Public License version 2 as published by the Free Software
- * Foundation.
- *
- * The Inventra Controller Driver for Linux is distributed in
- * the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
- * License for more details.
+ * 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 The Inventra Controller Driver for Linux ; if not,
- * write to the Free Software Foundation, Inc., 59 Temple Place,
- * Suite 330, Boston, MA 02111-1307 USA
+ * 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.
*
- * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
- * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
- * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
- * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
- * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
- * NON-INFRINGEMENT. MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
- * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
- * GRAPHICS SUPPORT CUSTOMER.
- ******************************************************************/
+ */
#include <linux/module.h>
#include <linux/kernel.h>
/*************************** Forwards ***************************/
-static void musb_ep_program(struct musb *pThis, u8 bEnd,
- struct urb *pUrb, unsigned int nOut,
- u8 * pBuffer, u32 dwLength);
+static void musb_ep_program(struct musb *musb, u8 epnum,
+ struct urb *urb, unsigned int nOut,
+ u8 * buf, u32 len);
+
+/*
+ * Clear TX fifo. Needed to avoid BABBLE errors.
+ */
+static inline void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
+{
+ void __iomem *epio = ep->regs;
+ u16 csr;
+ int retries = 1000;
+
+ csr = musb_readw(epio, MUSB_TXCSR);
+ while (csr & MUSB_TXCSR_FIFONOTEMPTY) {
+ DBG(5, "Host TX FIFONOTEMPTY csr: %02x\n", 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);
+ return;
+ }
+ mdelay(1);
+ }
+}
/*
* Start transmit. Caller is responsible for locking shared resources.
- * pThis must be locked.
+ * musb must be locked.
*/
static inline void musb_h_tx_start(struct musb_hw_ep *ep)
{
u16 txcsr;
/* NOTE: no locks here; caller should lock and select EP */
- if (ep->bLocalEnd) {
- txcsr = musb_readw(ep->regs, MGC_O_HDRC_TXCSR);
- txcsr |= MGC_M_TXCSR_TXPKTRDY | MGC_M_TXCSR_H_WZC_BITS;
- musb_writew(ep->regs, MGC_O_HDRC_TXCSR, txcsr);
+ if (ep->epnum) {
+ txcsr = musb_readw(ep->regs, MUSB_TXCSR);
+ txcsr |= MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_H_WZC_BITS;
+ musb_writew(ep->regs, MUSB_TXCSR, txcsr);
} else {
- txcsr = MGC_M_CSR0_H_SETUPPKT | MGC_M_CSR0_TXPKTRDY;
- musb_writew(ep->regs, MGC_O_HDRC_CSR0, txcsr);
+ txcsr = MUSB_CSR0_H_SETUPPKT | MUSB_CSR0_TXPKTRDY;
+ musb_writew(ep->regs, MUSB_CSR0, txcsr);
}
}
u16 txcsr;
/* NOTE: no locks here; caller should lock and select EP */
- txcsr = musb_readw(ep->regs, MGC_O_HDRC_TXCSR);
- txcsr |= MGC_M_TXCSR_DMAENAB | MGC_M_TXCSR_H_WZC_BITS;
- musb_writew(ep->regs, MGC_O_HDRC_TXCSR, txcsr);
+ txcsr = musb_readw(ep->regs, MUSB_TXCSR);
+ txcsr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_H_WZC_BITS;
+ musb_writew(ep->regs, MUSB_TXCSR, txcsr);
}
/*
musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
{
u16 wFrame;
- u32 dwLength;
- void *pBuffer;
- void __iomem *pBase = musb->pRegs;
+ u32 len;
+ void *buf;
+ void __iomem *mbase = musb->mregs;
struct urb *urb = next_urb(qh);
- struct musb_hw_ep *pEnd = qh->hw_ep;
- unsigned nPipe = urb->pipe;
- u8 bAddress = usb_pipedevice(nPipe);
- int bEnd = pEnd->bLocalEnd;
+ struct musb_hw_ep *hw_ep = qh->hw_ep;
+ unsigned pipe = urb->pipe;
+ u8 address = usb_pipedevice(pipe);
+ int epnum = hw_ep->epnum;
/* initialize software qh state */
qh->offset = 0;
case USB_ENDPOINT_XFER_CONTROL:
/* control transfers always start with SETUP */
is_in = 0;
- pEnd->out_qh = qh;
- musb->bEnd0Stage = MGC_END0_START;
- pBuffer = urb->setup_packet;
- dwLength = 8;
+ hw_ep->out_qh = qh;
+ musb->ep0_stage = MGC_END0_START;
+ buf = urb->setup_packet;
+ len = 8;
break;
case USB_ENDPOINT_XFER_ISOC:
qh->iso_idx = 0;
qh->frame = 0;
- pBuffer = urb->transfer_buffer + urb->iso_frame_desc[0].offset;
- dwLength = urb->iso_frame_desc[0].length;
+ buf = urb->transfer_buffer + urb->iso_frame_desc[0].offset;
+ len = urb->iso_frame_desc[0].length;
break;
default: /* bulk, interrupt */
- pBuffer = urb->transfer_buffer;
- dwLength = urb->transfer_buffer_length;
+ buf = urb->transfer_buffer;
+ len = urb->transfer_buffer_length;
}
DBG(4, "qh %p urb %p dev%d ep%d%s%s, hw_ep %d, %p/%d\n",
- qh, urb, bAddress, qh->epnum,
+ qh, urb, address, qh->epnum,
is_in ? "in" : "out",
({char *s; switch (qh->type) {
case USB_ENDPOINT_XFER_CONTROL: s = ""; break;
case USB_ENDPOINT_XFER_ISOC: s = "-iso"; break;
default: s = "-intr"; break;
}; s;}),
- bEnd, pBuffer, dwLength);
+ epnum, buf, len);
/* Configure endpoint */
- if (is_in || pEnd->bIsSharedFifo)
- pEnd->in_qh = qh;
+ if (is_in || hw_ep->is_shared_fifo)
+ hw_ep->in_qh = qh;
else
- pEnd->out_qh = qh;
- musb_ep_program(musb, bEnd, urb, !is_in, pBuffer, dwLength);
+ hw_ep->out_qh = qh;
+ musb_ep_program(musb, epnum, urb, !is_in, buf, len);
/* transmit may have more work: start it when it is time */
if (is_in)
case USB_ENDPOINT_XFER_INT:
DBG(3, "check whether there's still time for periodic Tx\n");
qh->iso_idx = 0;
- wFrame = musb_readw(pBase, MGC_O_HDRC_FRAME);
+ wFrame = musb_readw(mbase, MUSB_FRAME);
/* FIXME this doesn't implement that scheduling policy ...
* or handle framecounter wrapping
*/
} else {
qh->frame = urb->start_frame;
/* enable SOF interrupt so we can count down */
-DBG(1,"SOF for %d\n", bEnd);
+DBG(1,"SOF for %d\n", epnum);
#if 1 // ifndef CONFIG_ARCH_DAVINCI
- musb_writeb(pBase, MGC_O_HDRC_INTRUSBE, 0xff);
+ musb_writeb(mbase, MUSB_INTRUSBE, 0xff);
#endif
}
break;
default:
start:
- DBG(4, "Start TX%d %s\n", bEnd,
- pEnd->tx_channel ? "dma" : "pio");
+ DBG(4, "Start TX%d %s\n", epnum,
+ hw_ep->tx_channel ? "dma" : "pio");
- if (!pEnd->tx_channel)
- musb_h_tx_start(pEnd);
- else if (is_cppi_enabled())
- cppi_host_txdma_start(pEnd);
+ if (!hw_ep->tx_channel)
+ musb_h_tx_start(hw_ep);
+ else if (is_cppi_enabled() || tusb_dma_omap())
+ cppi_host_txdma_start(hw_ep);
}
}
/* caller owns controller lock, irqs are blocked */
static void
__musb_giveback(struct musb *musb, struct urb *urb, int status)
-__releases(musb->Lock)
-__acquires(musb->Lock)
+__releases(musb->lock)
+__acquires(musb->lock)
{
if ((urb->transfer_flags & URB_SHORT_NOT_OK)
&& (urb->actual_length < urb->transfer_buffer_length)
urb->actual_length, urb->transfer_buffer_length
);
- spin_unlock(&musb->Lock);
+ spin_unlock(&musb->lock);
usb_hcd_giveback_urb(musb_to_hcd(musb), urb);
- spin_lock(&musb->Lock);
+ spin_lock(&musb->lock);
}
/* for bulk/interrupt endpoints only */
{
struct usb_device *udev = urb->dev;
u16 csr;
- void __iomem *hw = ep->musb->pRegs;
+ void __iomem *epio = ep->regs;
struct musb_qh *qh;
/* FIXME: the current Mentor DMA code seems to have
* problems getting toggle correct.
*/
- if (is_in || ep->bIsSharedFifo)
+ if (is_in || ep->is_shared_fifo)
qh = ep->in_qh;
else
qh = ep->out_qh;
if (!is_in) {
- csr = MGC_ReadCsr16(hw, MGC_O_HDRC_TXCSR,
- ep->bLocalEnd);
+ csr = musb_readw(epio, MUSB_TXCSR);
usb_settoggle(udev, qh->epnum, 1,
- (csr & MGC_M_TXCSR_H_DATATOGGLE)
+ (csr & MUSB_TXCSR_H_DATATOGGLE)
? 1 : 0);
} else {
- csr = MGC_ReadCsr16(hw, MGC_O_HDRC_RXCSR,
- ep->bLocalEnd);
+ csr = musb_readw(epio, MUSB_RXCSR);
usb_settoggle(udev, qh->epnum, 0,
- (csr & MGC_M_RXCSR_H_DATATOGGLE)
+ (csr & MUSB_RXCSR_H_DATATOGGLE)
? 1 : 0);
}
}
struct musb *musb = ep->musb;
int ready = qh->is_ready;
- if (ep->bIsSharedFifo)
+ if (ep->is_shared_fifo)
is_in = 1;
else
is_in = usb_pipein(urb->pipe);
ep->tx_reinit = 1;
/* clobber old pointers to this qh */
- if (is_in || ep->bIsSharedFifo)
+ if (is_in || ep->is_shared_fifo)
ep->in_qh = NULL;
else
ep->out_qh = NULL;
* de-allocated if it's tracked and allocated;
* and where we'd update the schedule tree...
*/
- musb->periodic[ep->bLocalEnd] = NULL;
+ musb->periodic[ep->epnum] = NULL;
kfree(qh);
qh = NULL;
break;
* Context: caller owns controller lock, irqs are blocked
*/
static void
-musb_advance_schedule(struct musb *pThis, struct urb *urb,
- struct musb_hw_ep *pEnd, int is_in)
+musb_advance_schedule(struct musb *musb, struct urb *urb,
+ struct musb_hw_ep *hw_ep, int is_in)
{
struct musb_qh *qh;
- if (is_in || pEnd->bIsSharedFifo)
- qh = pEnd->in_qh;
+ if (is_in || hw_ep->is_shared_fifo)
+ qh = hw_ep->in_qh;
else
- qh = pEnd->out_qh;
+ qh = hw_ep->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',
+ hw_ep->epnum, is_in ? 'R' : 'T',
next_urb(qh));
- musb_start_urb(pThis, is_in, qh);
+ musb_start_urb(musb, is_in, qh);
}
}
* ignore dma (various models),
* leave toggle alone (may not have been saved yet)
*/
- csr |= MGC_M_RXCSR_FLUSHFIFO | MGC_M_RXCSR_RXPKTRDY;
- csr &= ~( MGC_M_RXCSR_H_REQPKT
- | MGC_M_RXCSR_H_AUTOREQ
- | MGC_M_RXCSR_AUTOCLEAR
+ csr |= MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_RXPKTRDY;
+ csr &= ~( MUSB_RXCSR_H_REQPKT
+ | MUSB_RXCSR_H_AUTOREQ
+ | MUSB_RXCSR_AUTOCLEAR
);
/* write 2x to allow double buffering */
- musb_writew(hw_ep->regs, MGC_O_HDRC_RXCSR, csr);
- musb_writew(hw_ep->regs, MGC_O_HDRC_RXCSR, csr);
+ musb_writew(hw_ep->regs, MUSB_RXCSR, csr);
+ musb_writew(hw_ep->regs, MUSB_RXCSR, csr);
/* flush writebuffer */
- return musb_readw(hw_ep->regs, MGC_O_HDRC_RXCSR);
+ return musb_readw(hw_ep->regs, MUSB_RXCSR);
}
/*
* PIO RX for a packet (or part of it).
*/
-static u8 musb_host_packet_rx(struct musb *pThis, struct urb *pUrb,
- u8 bEnd, u8 bIsochError)
+static u8 musb_host_packet_rx(struct musb *musb, struct urb *urb,
+ u8 epnum, u8 iso_err)
{
- u16 wRxCount;
- u8 *pBuffer;
- u16 wCsr;
- u8 bDone = FALSE;
+ u16 rx_count;
+ u8 *buf;
+ u16 csr;
+ u8 done = FALSE;
u32 length;
int do_flush = 0;
- void __iomem *pBase = pThis->pRegs;
- struct musb_hw_ep *pEnd = pThis->aLocalEnd + bEnd;
- struct musb_qh *qh = pEnd->in_qh;
- int nPipe = pUrb->pipe;
- void *buffer = pUrb->transfer_buffer;
-
- // MGC_SelectEnd(pBase, bEnd);
- wRxCount = MGC_ReadCsr16(pBase, MGC_O_HDRC_RXCOUNT, bEnd);
+ struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
+ void __iomem *epio = hw_ep->regs;
+ struct musb_qh *qh = hw_ep->in_qh;
+ int pipe = urb->pipe;
+ void *buffer = urb->transfer_buffer;
+
+ // musb_ep_select(mbase, epnum);
+ rx_count = musb_readw(epio, MUSB_RXCOUNT);
+ DBG(3, "RX%d count %d, buffer %p len %d/%d\n", epnum, rx_count,
+ urb->transfer_buffer, qh->offset,
+ urb->transfer_buffer_length);
/* unload FIFO */
- if (usb_pipeisoc(nPipe)) {
+ if (usb_pipeisoc(pipe)) {
int status = 0;
struct usb_iso_packet_descriptor *d;
- if (bIsochError) {
+ if (iso_err) {
status = -EILSEQ;
- pUrb->error_count++;
+ urb->error_count++;
}
- d = pUrb->iso_frame_desc + qh->iso_idx;
- pBuffer = buffer + d->offset;
+ d = urb->iso_frame_desc + qh->iso_idx;
+ buf = buffer + d->offset;
length = d->length;
- if (wRxCount > length) {
+ if (rx_count > length) {
if (status == 0) {
status = -EOVERFLOW;
- pUrb->error_count++;
+ urb->error_count++;
}
- DBG(2, "** OVERFLOW %d into %d\n", wRxCount, length);
+ DBG(2, "** OVERFLOW %d into %d\n", rx_count, length);
do_flush = 1;
} else
- length = wRxCount;
- pUrb->actual_length += length;
+ length = rx_count;
+ urb->actual_length += length;
d->actual_length = length;
d->status = status;
/* see if we are done */
- bDone = (++qh->iso_idx >= pUrb->number_of_packets);
+ done = (++qh->iso_idx >= urb->number_of_packets);
} else {
/* non-isoch */
- pBuffer = buffer + qh->offset;
- length = pUrb->transfer_buffer_length - qh->offset;
- if (wRxCount > length) {
- if (pUrb->status == -EINPROGRESS)
- pUrb->status = -EOVERFLOW;
- DBG(2, "** OVERFLOW %d into %d\n", wRxCount, length);
+ buf = buffer + qh->offset;
+ length = urb->transfer_buffer_length - qh->offset;
+ if (rx_count > length) {
+ if (urb->status == -EINPROGRESS)
+ urb->status = -EOVERFLOW;
+ DBG(2, "** OVERFLOW %d into %d\n", rx_count, length);
do_flush = 1;
} else
- length = wRxCount;
- pUrb->actual_length += length;
+ length = rx_count;
+ urb->actual_length += length;
qh->offset += length;
/* see if we are done */
- bDone = (pUrb->actual_length == pUrb->transfer_buffer_length)
- || (wRxCount < qh->maxpacket)
- || (pUrb->status != -EINPROGRESS);
- if (bDone
- && (pUrb->status == -EINPROGRESS)
- && (pUrb->transfer_flags & URB_SHORT_NOT_OK)
- && (pUrb->actual_length
- < pUrb->transfer_buffer_length))
- pUrb->status = -EREMOTEIO;
+ done = (urb->actual_length == urb->transfer_buffer_length)
+ || (rx_count < qh->maxpacket)
+ || (urb->status != -EINPROGRESS);
+ if (done
+ && (urb->status == -EINPROGRESS)
+ && (urb->transfer_flags & URB_SHORT_NOT_OK)
+ && (urb->actual_length
+ < urb->transfer_buffer_length))
+ urb->status = -EREMOTEIO;
}
- musb_read_fifo(pEnd, length, pBuffer);
+ musb_read_fifo(hw_ep, length, buf);
- wCsr = MGC_ReadCsr16(pBase, MGC_O_HDRC_RXCSR, bEnd);
- wCsr |= MGC_M_RXCSR_H_WZC_BITS;
+ csr = musb_readw(epio, MUSB_RXCSR);
+ csr |= MUSB_RXCSR_H_WZC_BITS;
if (unlikely(do_flush))
- musb_h_flush_rxfifo(pEnd, wCsr);
+ musb_h_flush_rxfifo(hw_ep, csr);
else {
/* REVISIT this assumes AUTOCLEAR is never set */
- wCsr &= ~(MGC_M_RXCSR_RXPKTRDY | MGC_M_RXCSR_H_REQPKT);
- if (!bDone)
- wCsr |= MGC_M_RXCSR_H_REQPKT;
- MGC_WriteCsr16(pBase, MGC_O_HDRC_RXCSR, bEnd, wCsr);
+ csr &= ~(MUSB_RXCSR_RXPKTRDY | MUSB_RXCSR_H_REQPKT);
+ if (!done)
+ csr |= MUSB_RXCSR_H_REQPKT;
+ musb_writew(epio, MUSB_RXCSR, csr);
}
- return bDone;
+ return done;
}
/* we don't always need to reinit a given side of an endpoint...
*/
/* if programmed for Tx, put it in RX mode */
- if (ep->bIsSharedFifo) {
- csr = musb_readw(ep->regs, MGC_O_HDRC_TXCSR);
- if (csr & MGC_M_TXCSR_MODE) {
- if (csr & MGC_M_TXCSR_FIFONOTEMPTY) {
- /* this shouldn't happen; irq?? */
- ERR("shared fifo not empty?\n");
- musb_writew(ep->regs, MGC_O_HDRC_TXCSR,
- MGC_M_TXCSR_FLUSHFIFO);
- musb_writew(ep->regs, MGC_O_HDRC_TXCSR,
- MGC_M_TXCSR_FRCDATATOG);
- }
+ if (ep->is_shared_fifo) {
+ csr = musb_readw(ep->regs, MUSB_TXCSR);
+ if (csr & MUSB_TXCSR_MODE) {
+ musb_h_tx_flush_fifo(ep);
+ musb_writew(ep->regs, MUSB_TXCSR,
+ MUSB_TXCSR_FRCDATATOG);
}
/* clear mode (and everything else) to enable Rx */
- musb_writew(ep->regs, MGC_O_HDRC_TXCSR, 0);
+ musb_writew(ep->regs, MUSB_TXCSR, 0);
/* scrub all previous state, clearing toggle */
} else {
- csr = musb_readw(ep->regs, MGC_O_HDRC_RXCSR);
- if (csr & MGC_M_RXCSR_RXPKTRDY)
- WARN("rx%d, packet/%d ready?\n", ep->bLocalEnd,
- musb_readw(ep->regs, MGC_O_HDRC_RXCOUNT));
+ csr = musb_readw(ep->regs, MUSB_RXCSR);
+ if (csr & MUSB_RXCSR_RXPKTRDY)
+ WARN("rx%d, packet/%d ready?\n", ep->epnum,
+ musb_readw(ep->regs, MUSB_RXCOUNT));
- musb_h_flush_rxfifo(ep, MGC_M_RXCSR_CLRDATATOG);
+ musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG);
}
/* target addr and (for multipoint) hub addr/port */
- if (musb->bIsMultipoint) {
- musb_writeb(ep->target_regs, MGC_O_HDRC_RXFUNCADDR,
+ if (musb->is_multipoint) {
+ musb_writeb(ep->target_regs, MUSB_RXFUNCADDR,
qh->addr_reg);
- musb_writeb(ep->target_regs, MGC_O_HDRC_RXHUBADDR,
+ musb_writeb(ep->target_regs, MUSB_RXHUBADDR,
qh->h_addr_reg);
- musb_writeb(ep->target_regs, MGC_O_HDRC_RXHUBPORT,
+ musb_writeb(ep->target_regs, MUSB_RXHUBPORT,
qh->h_port_reg);
} else
- musb_writeb(musb->pRegs, MGC_O_HDRC_FADDR, qh->addr_reg);
+ musb_writeb(musb->mregs, MUSB_FADDR, qh->addr_reg);
/* protocol/endpoint, interval/NAKlimit, i/o size */
- musb_writeb(ep->regs, MGC_O_HDRC_RXTYPE, qh->type_reg);
- musb_writeb(ep->regs, MGC_O_HDRC_RXINTERVAL, qh->intv_reg);
+ musb_writeb(ep->regs, MUSB_RXTYPE, qh->type_reg);
+ musb_writeb(ep->regs, MUSB_RXINTERVAL, qh->intv_reg);
/* NOTE: bulk combining rewrites high bits of maxpacket */
- musb_writew(ep->regs, MGC_O_HDRC_RXMAXP, qh->maxpacket);
+ musb_writew(ep->regs, MUSB_RXMAXP, qh->maxpacket);
ep->rx_reinit = 0;
}
* Program an HDRC endpoint as per the given URB
* Context: irqs blocked, controller lock held
*/
-static void musb_ep_program(struct musb *pThis, u8 bEnd,
- struct urb *pUrb, unsigned int is_out,
- u8 * pBuffer, u32 dwLength)
+static void musb_ep_program(struct musb *musb, u8 epnum,
+ struct urb *urb, unsigned int is_out,
+ u8 * buf, u32 len)
{
- struct dma_controller *pDmaController;
- struct dma_channel *pDmaChannel;
- u8 bDmaOk;
- void __iomem *pBase = pThis->pRegs;
- struct musb_hw_ep *pEnd = pThis->aLocalEnd + bEnd;
+ struct dma_controller *dma_controller;
+ struct dma_channel *dma_channel;
+ u8 dma_ok;
+ void __iomem *mbase = musb->mregs;
+ struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
+ void __iomem *epio = hw_ep->regs;
struct musb_qh *qh;
- u16 wPacketSize;
+ u16 packet_sz;
- if (!is_out || pEnd->bIsSharedFifo)
- qh = pEnd->in_qh;
+ if (!is_out || hw_ep->is_shared_fifo)
+ qh = hw_ep->in_qh;
else
- qh = pEnd->out_qh;
+ qh = hw_ep->out_qh;
- wPacketSize = qh->maxpacket;
+ packet_sz = qh->maxpacket;
DBG(3, "%s hw%d urb %p spd%d dev%d ep%d%s "
"h_addr%02x h_port%02x bytes %d\n",
is_out ? "-->" : "<--",
- bEnd, pUrb, pUrb->dev->speed,
+ epnum, urb, urb->dev->speed,
qh->addr_reg, qh->epnum, is_out ? "out" : "in",
qh->h_addr_reg, qh->h_port_reg,
- dwLength);
+ len);
- MGC_SelectEnd(pBase, bEnd);
+ musb_ep_select(mbase, epnum);
/* candidate for DMA? */
- pDmaController = pThis->pDmaController;
- if (is_dma_capable() && bEnd && pDmaController) {
- pDmaChannel = is_out ? pEnd->tx_channel : pEnd->rx_channel;
- if (!pDmaChannel) {
- pDmaChannel = pDmaController->channel_alloc(
- pDmaController, pEnd, is_out);
+ dma_controller = musb->dma_controller;
+ if (is_dma_capable() && epnum && dma_controller) {
+ dma_channel = is_out ? hw_ep->tx_channel : hw_ep->rx_channel;
+ if (!dma_channel) {
+ dma_channel = dma_controller->channel_alloc(
+ dma_controller, hw_ep, is_out);
if (is_out)
- pEnd->tx_channel = pDmaChannel;
+ hw_ep->tx_channel = dma_channel;
else
- pEnd->rx_channel = pDmaChannel;
+ hw_ep->rx_channel = dma_channel;
}
} else
- pDmaChannel = NULL;
+ dma_channel = NULL;
/* make sure we clear DMAEnab, autoSet bits from previous run */
/* OUT/transmit/EP0 or IN/receive? */
if (is_out) {
- u16 wCsr;
- u16 wIntrTxE;
- u16 wLoadCount;
+ u16 csr;
+ u16 int_txe;
+ u16 load_count;
- wCsr = MGC_ReadCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd);
+ csr = musb_readw(epio, MUSB_TXCSR);
/* disable interrupt in case we flush */
- wIntrTxE = musb_readw(pBase, MGC_O_HDRC_INTRTXE);
- musb_writew(pBase, MGC_O_HDRC_INTRTXE, wIntrTxE & ~(1 << bEnd));
+ int_txe = musb_readw(mbase, MUSB_INTRTXE);
+ musb_writew(mbase, MUSB_INTRTXE, int_txe & ~(1 << epnum));
/* general endpoint setup */
- if (bEnd) {
- u16 csr = wCsr;
+ if (epnum) {
+ u16 csr = csr;
/* ASSERT: TXCSR_DMAENAB was already cleared */
/* flush all old state, set default */
- if (csr & MGC_M_TXCSR_FIFONOTEMPTY)
- csr |= MGC_M_TXCSR_FLUSHFIFO;
- csr &= ~(MGC_M_TXCSR_H_NAKTIMEOUT
- | MGC_M_TXCSR_DMAMODE
- | MGC_M_TXCSR_FRCDATATOG
- | MGC_M_TXCSR_H_RXSTALL
- | MGC_M_TXCSR_H_ERROR
- | MGC_M_TXCSR_FIFONOTEMPTY
- | MGC_M_TXCSR_TXPKTRDY
+ musb_h_tx_flush_fifo(hw_ep);
+ csr &= ~(MUSB_TXCSR_H_NAKTIMEOUT
+ | MUSB_TXCSR_DMAMODE
+ | MUSB_TXCSR_FRCDATATOG
+ | MUSB_TXCSR_H_RXSTALL
+ | MUSB_TXCSR_H_ERROR
+ | MUSB_TXCSR_TXPKTRDY
);
- csr |= MGC_M_TXCSR_MODE;
+ csr |= MUSB_TXCSR_MODE;
- if (usb_gettoggle(pUrb->dev,
+ if (usb_gettoggle(urb->dev,
qh->epnum, 1))
- csr |= MGC_M_TXCSR_H_WR_DATATOGGLE
- | MGC_M_TXCSR_H_DATATOGGLE;
+ csr |= MUSB_TXCSR_H_WR_DATATOGGLE
+ | MUSB_TXCSR_H_DATATOGGLE;
else
- csr |= MGC_M_TXCSR_CLRDATATOG;
+ csr |= MUSB_TXCSR_CLRDATATOG;
/* twice in case of double packet buffering */
- MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd,
- csr);
+ musb_writew(epio, MUSB_TXCSR, csr);
/* REVISIT may need to clear FLUSHFIFO ... */
- MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd,
- csr);
- wCsr = MGC_ReadCsr16(pBase, MGC_O_HDRC_TXCSR,
- bEnd);
+ musb_writew(epio, MUSB_TXCSR, csr);
+ csr = musb_readw(epio, MUSB_TXCSR);
} else {
/* endpoint 0: just flush */
- MGC_WriteCsr16(pBase, MGC_O_HDRC_CSR0, bEnd,
- wCsr | MGC_M_CSR0_FLUSHFIFO);
- MGC_WriteCsr16(pBase, MGC_O_HDRC_CSR0, bEnd,
- wCsr | MGC_M_CSR0_FLUSHFIFO);
+ musb_writew(epio, MUSB_CSR0,
+ csr | MUSB_CSR0_FLUSHFIFO);
+ musb_writew(epio, MUSB_CSR0,
+ csr | MUSB_CSR0_FLUSHFIFO);
}
/* target addr and (for multipoint) hub addr/port */
- if (pThis->bIsMultipoint) {
- musb_writeb(pBase,
- MGC_BUSCTL_OFFSET(bEnd, MGC_O_HDRC_TXFUNCADDR),
+ if (musb->is_multipoint) {
+ musb_writeb(mbase,
+ MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR),
qh->addr_reg);
- musb_writeb(pBase,
- MGC_BUSCTL_OFFSET(bEnd, MGC_O_HDRC_TXHUBADDR),
+ musb_writeb(mbase,
+ MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR),
qh->h_addr_reg);
- musb_writeb(pBase,
- MGC_BUSCTL_OFFSET(bEnd, MGC_O_HDRC_TXHUBPORT),
+ musb_writeb(mbase,
+ MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT),
qh->h_port_reg);
-/* FIXME if !bEnd, do the same for RX ... */
+/* FIXME if !epnum, do the same for RX ... */
} else
- musb_writeb(pBase, MGC_O_HDRC_FADDR, qh->addr_reg);
+ musb_writeb(mbase, MUSB_FADDR, qh->addr_reg);
/* protocol/endpoint/interval/NAKlimit */
- if (bEnd) {
- MGC_WriteCsr8(pBase, MGC_O_HDRC_TXTYPE, bEnd,
- qh->type_reg);
- if (can_bulk_split(pThis, qh->type))
- MGC_WriteCsr16(pBase, MGC_O_HDRC_TXMAXP, bEnd,
- wPacketSize
- | ((pEnd->wMaxPacketSizeTx /
- wPacketSize) - 1) << 11);
+ if (epnum) {
+ musb_writeb(epio, MUSB_TXTYPE, qh->type_reg);
+ if (can_bulk_split(musb, qh->type))
+ musb_writew(epio, MUSB_TXMAXP,
+ packet_sz
+ | ((hw_ep->max_packet_sz_tx /
+ packet_sz) - 1) << 11);
else
- MGC_WriteCsr16(pBase, MGC_O_HDRC_TXMAXP, bEnd,
- wPacketSize);
- MGC_WriteCsr8(pBase, MGC_O_HDRC_TXINTERVAL, bEnd,
- qh->intv_reg);
+ musb_writew(epio, MUSB_TXMAXP,
+ packet_sz);
+ musb_writeb(epio, MUSB_TXINTERVAL, qh->intv_reg);
} else {
- MGC_WriteCsr8(pBase, MGC_O_HDRC_NAKLIMIT0, 0,
- qh->intv_reg);
- if (pThis->bIsMultipoint)
- MGC_WriteCsr8(pBase, MGC_O_HDRC_TYPE0, 0,
+ musb_writeb(epio, MUSB_NAKLIMIT0, qh->intv_reg);
+ if (musb->is_multipoint)
+ musb_writeb(epio, MUSB_TYPE0,
qh->type_reg);
}
- if (can_bulk_split(pThis, qh->type))
- wLoadCount = min((u32) pEnd->wMaxPacketSizeTx,
- dwLength);
+ if (can_bulk_split(musb, qh->type))
+ load_count = min((u32) hw_ep->max_packet_sz_tx,
+ len);
else
- wLoadCount = min((u32) wPacketSize, dwLength);
+ load_count = min((u32) packet_sz, len);
#ifdef CONFIG_USB_INVENTRA_DMA
- if (pDmaChannel) {
+ if (dma_channel) {
/* clear previous state */
- wCsr = MGC_ReadCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd);
- wCsr &= ~(MGC_M_TXCSR_AUTOSET
- | MGC_M_TXCSR_DMAMODE
- | MGC_M_TXCSR_DMAENAB);
- wCsr |= MGC_M_TXCSR_MODE;
- MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd,
- wCsr | MGC_M_TXCSR_MODE);
-
- qh->segsize = min(dwLength, pDmaChannel->dwMaxLength);
-
- if (qh->segsize <= wPacketSize)
- pDmaChannel->bDesiredMode = 0;
+ csr = musb_readw(epio, MUSB_TXCSR);
+ csr &= ~(MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_DMAMODE
+ | MUSB_TXCSR_DMAENAB);
+ csr |= MUSB_TXCSR_MODE;
+ musb_writew(epio, MUSB_TXCSR,
+ csr | MUSB_TXCSR_MODE);
+
+ qh->segsize = min(len, dma_channel->max_len);
+
+ if (qh->segsize <= packet_sz)
+ dma_channel->desired_mode = 0;
else
- pDmaChannel->bDesiredMode = 1;
+ dma_channel->desired_mode = 1;
- if (pDmaChannel->bDesiredMode == 0) {
- wCsr &= ~(MGC_M_TXCSR_AUTOSET
- | MGC_M_TXCSR_DMAMODE);
- wCsr |= (MGC_M_TXCSR_DMAENAB);
+ if (dma_channel->desired_mode == 0) {
+ csr &= ~(MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_DMAMODE);
+ csr |= (MUSB_TXCSR_DMAENAB);
// against programming guide
} else
- wCsr |= (MGC_M_TXCSR_AUTOSET
- | MGC_M_TXCSR_DMAENAB
- | MGC_M_TXCSR_DMAMODE);
+ csr |= (MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_DMAENAB
+ | MUSB_TXCSR_DMAMODE);
- MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd, wCsr);
+ musb_writew(epio, MUSB_TXCSR, csr);
- bDmaOk = pDmaController->channel_program(
- pDmaChannel, wPacketSize,
- pDmaChannel->bDesiredMode,
- pUrb->transfer_dma,
+ dma_ok = dma_controller->channel_program(
+ dma_channel, packet_sz,
+ dma_channel->desired_mode,
+ urb->transfer_dma,
qh->segsize);
- if (bDmaOk) {
- wLoadCount = 0;
+ if (dma_ok) {
+ load_count = 0;
} else {
- pDmaController->channel_release(pDmaChannel);
- pDmaChannel = pEnd->pDmaChannel = NULL;
+ dma_controller->channel_release(dma_channel);
+ if (is_out)
+ hw_ep->tx_channel = NULL;
+ else
+ hw_ep->rx_channel = NULL;
+ dma_channel = NULL;
}
}
#endif
/* candidate for DMA */
- if (is_cppi_enabled() && pDmaChannel) {
+ if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) {
/* program endpoint CSRs first, then setup DMA.
* assume CPPI setup succeeds.
* defer enabling dma.
*/
- wCsr = MGC_ReadCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd);
- wCsr &= ~(MGC_M_TXCSR_AUTOSET
- | MGC_M_TXCSR_DMAMODE
- | MGC_M_TXCSR_DMAENAB);
- wCsr |= MGC_M_TXCSR_MODE;
- MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd,
- wCsr | MGC_M_TXCSR_MODE);
+ csr = musb_readw(epio, MUSB_TXCSR);
+ csr &= ~(MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_DMAMODE
+ | MUSB_TXCSR_DMAENAB);
+ csr |= MUSB_TXCSR_MODE;
+ musb_writew(epio, MUSB_TXCSR,
+ csr | MUSB_TXCSR_MODE);
- pDmaChannel->dwActualLength = 0L;
- qh->segsize = dwLength;
+ dma_channel->actual_len = 0L;
+ qh->segsize = len;
/* TX uses "rndis" mode automatically, but needs help
* to identify the zero-length-final-packet case.
*/
- bDmaOk = pDmaController->channel_program(
- pDmaChannel, wPacketSize,
- (pUrb->transfer_flags
+ dma_ok = dma_controller->channel_program(
+ dma_channel, packet_sz,
+ (urb->transfer_flags
& URB_ZERO_PACKET)
== URB_ZERO_PACKET,
- pUrb->transfer_dma,
+ urb->transfer_dma,
qh->segsize);
- if (bDmaOk) {
- wLoadCount = 0;
+ if (dma_ok) {
+ load_count = 0;
} else {
- pDmaController->channel_release(pDmaChannel);
- pDmaChannel = pEnd->tx_channel = NULL;
+ dma_controller->channel_release(dma_channel);
+ dma_channel = hw_ep->tx_channel = NULL;
/* REVISIT there's an error path here that
* needs handling: can't do dma, but
}
}
- if (wLoadCount) {
+ if (load_count) {
/* ASSERT: TXCSR_DMAENAB was already cleared */
/* PIO to load FIFO */
- qh->segsize = wLoadCount;
- musb_write_fifo(pEnd, wLoadCount, pBuffer);
- wCsr = MGC_ReadCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd);
- wCsr &= ~(MGC_M_TXCSR_DMAENAB
- | MGC_M_TXCSR_DMAMODE
- | MGC_M_TXCSR_AUTOSET);
+ qh->segsize = load_count;
+ musb_write_fifo(hw_ep, load_count, buf);
+ csr = musb_readw(epio, MUSB_TXCSR);
+ csr &= ~(MUSB_TXCSR_DMAENAB
+ | MUSB_TXCSR_DMAMODE
+ | MUSB_TXCSR_AUTOSET);
/* write CSR */
- wCsr |= MGC_M_TXCSR_MODE;
-
- if (bEnd)
- MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR,
- bEnd, wCsr);
+ csr |= MUSB_TXCSR_MODE;
+ if (epnum)
+ musb_writew(epio, MUSB_TXCSR, csr);
}
/* re-enable interrupt */
- musb_writew(pBase, MGC_O_HDRC_INTRTXE, wIntrTxE);
+ musb_writew(mbase, MUSB_INTRTXE, int_txe);
/* IN/receive */
} else {
u16 csr;
- if (pEnd->rx_reinit) {
- musb_rx_reinit(pThis, qh, pEnd);
+ if (hw_ep->rx_reinit) {
+ musb_rx_reinit(musb, qh, hw_ep);
/* init new state: toggle and NYET, maybe DMA later */
- if (usb_gettoggle(pUrb->dev, qh->epnum, 0))
- csr = MGC_M_RXCSR_H_WR_DATATOGGLE
- | MGC_M_RXCSR_H_DATATOGGLE;
+ if (usb_gettoggle(urb->dev, qh->epnum, 0))
+ csr = MUSB_RXCSR_H_WR_DATATOGGLE
+ | MUSB_RXCSR_H_DATATOGGLE;
else
csr = 0;
if (qh->type == USB_ENDPOINT_XFER_INT)
- csr |= MGC_M_RXCSR_DISNYET;
+ csr |= MUSB_RXCSR_DISNYET;
} else {
- csr = musb_readw(pEnd->regs, MGC_O_HDRC_RXCSR);
+ csr = musb_readw(hw_ep->regs, MUSB_RXCSR);
- if (csr & (MGC_M_RXCSR_RXPKTRDY
- | MGC_M_RXCSR_DMAENAB
- | MGC_M_RXCSR_H_REQPKT))
+ if (csr & (MUSB_RXCSR_RXPKTRDY
+ | MUSB_RXCSR_DMAENAB
+ | MUSB_RXCSR_H_REQPKT))
ERR("broken !rx_reinit, ep%d csr %04x\n",
- pEnd->bLocalEnd, csr);
+ hw_ep->epnum, csr);
/* scrub any stale state, leaving toggle alone */
- csr &= MGC_M_RXCSR_DISNYET;
+ csr &= MUSB_RXCSR_DISNYET;
}
/* kick things off */
- if (is_cppi_enabled()) {
+ if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) {
/* candidate for DMA */
- if (pDmaChannel) {
- pDmaChannel->dwActualLength = 0L;
- qh->segsize = dwLength;
+ if (dma_channel) {
+ dma_channel->actual_len = 0L;
+ qh->segsize = len;
/* AUTOREQ is in a DMA register */
- musb_writew(pEnd->regs, MGC_O_HDRC_RXCSR, csr);
- csr = musb_readw(pEnd->regs,
- MGC_O_HDRC_RXCSR);
+ musb_writew(hw_ep->regs, MUSB_RXCSR, csr);
+ csr = musb_readw(hw_ep->regs,
+ MUSB_RXCSR);
/* unless caller treats short rx transfers as
* errors, we dare not queue multiple transfers.
*/
- bDmaOk = pDmaController->channel_program(
- pDmaChannel, wPacketSize,
- !(pUrb->transfer_flags
+ dma_ok = dma_controller->channel_program(
+ dma_channel, packet_sz,
+ !(urb->transfer_flags
& URB_SHORT_NOT_OK),
- pUrb->transfer_dma,
+ urb->transfer_dma,
qh->segsize);
- if (!bDmaOk) {
- pDmaController->channel_release(
- pDmaChannel);
- pDmaChannel = pEnd->rx_channel = NULL;
+ if (!dma_ok) {
+ dma_controller->channel_release(
+ dma_channel);
+ dma_channel = hw_ep->rx_channel = NULL;
} else
- csr |= MGC_M_RXCSR_DMAENAB;
+ csr |= MUSB_RXCSR_DMAENAB;
}
}
- csr |= MGC_M_RXCSR_H_REQPKT;
- DBG(7, "RXCSR%d := %04x\n", bEnd, csr);
- musb_writew(pEnd->regs, MGC_O_HDRC_RXCSR, csr);
- csr = musb_readw(pEnd->regs, MGC_O_HDRC_RXCSR);
+ csr |= MUSB_RXCSR_H_REQPKT;
+ DBG(7, "RXCSR%d := %04x\n", epnum, csr);
+ musb_writew(hw_ep->regs, MUSB_RXCSR, csr);
+ csr = musb_readw(hw_ep->regs, MUSB_RXCSR);
}
}
/*
* Service the default endpoint (ep0) as host.
- * return TRUE if more packets are required for this transaction
+ * Return TRUE until it's time to start the status stage.
*/
-static u8 musb_h_ep0_continue(struct musb *pThis,
- u16 wCount, struct urb *pUrb)
+static int musb_h_ep0_continue(struct musb *musb,
+ u16 len, struct urb *urb)
{
- u8 bMore = FALSE;
- u8 *pFifoDest = NULL;
- u16 wFifoCount = 0;
- struct musb_hw_ep *pEnd = pThis->control_ep;
- struct musb_qh *qh = pEnd->in_qh;
- struct usb_ctrlrequest *pRequest;
-
- pRequest = (struct usb_ctrlrequest *) pUrb->setup_packet;
- if (MGC_END0_IN == pThis->bEnd0Stage) {
- /* we are receiving from peripheral */
- pFifoDest = pUrb->transfer_buffer + pUrb->actual_length;
- wFifoCount = min(wCount, ((u16) (pUrb->transfer_buffer_length
- - pUrb->actual_length)));
- if (wFifoCount < wCount)
- pUrb->status = -EOVERFLOW;
-
- musb_read_fifo(pEnd, wFifoCount, pFifoDest);
-
- pUrb->actual_length += wFifoCount;
- if (wCount < qh->maxpacket) {
+ int bMore = FALSE;
+ u8 *fifo_dest = NULL;
+ u16 fifo_count = 0;
+ struct musb_hw_ep *hw_ep = musb->control_ep;
+ struct musb_qh *qh = hw_ep->in_qh;
+ struct usb_ctrlrequest *request;
+
+ switch (musb->ep0_stage) {
+ case MGC_END0_IN:
+ fifo_dest = urb->transfer_buffer + urb->actual_length;
+ fifo_count = min(len, ((u16) (urb->transfer_buffer_length
+ - urb->actual_length)));
+ if (fifo_count < len)
+ urb->status = -EOVERFLOW;
+
+ musb_read_fifo(hw_ep, fifo_count, fifo_dest);
+
+ urb->actual_length += fifo_count;
+ if (len < qh->maxpacket) {
/* always terminate on short read; it's
* rarely reported as an error.
*/
- if ((pUrb->transfer_flags & URB_SHORT_NOT_OK)
- && (pUrb->actual_length <
- pUrb->transfer_buffer_length))
- pUrb->status = -EREMOTEIO;
- } else if (pUrb->actual_length <
- pUrb->transfer_buffer_length)
+ } else if (urb->actual_length <
+ urb->transfer_buffer_length)
bMore = TRUE;
- } else {
-/*
- DBG(3, "%s hw%d urb %p spd%d dev%d ep%d%s "
- "hub%d port%d%s bytes %d\n",
- is_out ? "-->" : "<--",
- bEnd, pUrb, pUrb->dev->speed,
- bAddress, qh->epnum, is_out ? "out" : "in",
- bHubAddr, bHubPort + 1,
- bIsMulti ? " multi" : "",
- dwLength);
-*/
- if ((MGC_END0_START == pThis->bEnd0Stage)
- && (pRequest->bRequestType & USB_DIR_IN)) {
- /* this means we just did setup; switch to IN */
+ break;
+ case MGC_END0_START:
+ request = (struct usb_ctrlrequest *) urb->setup_packet;
+
+ if (!request->wLength) {
+ DBG(4, "start no-DATA\n");
+ break;
+ } else if (request->bRequestType & USB_DIR_IN) {
DBG(4, "start IN-DATA\n");
- pThis->bEnd0Stage = MGC_END0_IN;
+ musb->ep0_stage = MGC_END0_IN;
bMore = TRUE;
-
- } else if (pRequest->wLength
- && (MGC_END0_START == pThis->bEnd0Stage)) {
- pThis->bEnd0Stage = MGC_END0_OUT;
- pFifoDest = (u8 *) (pUrb->transfer_buffer
- + pUrb->actual_length);
- wFifoCount = min(qh->maxpacket, ((u16)
- (pUrb->transfer_buffer_length
- - pUrb->actual_length)));
+ break;
+ } else {
+ DBG(4, "start OUT-DATA\n");
+ musb->ep0_stage = MGC_END0_OUT;
+ bMore = TRUE;
+ }
+ /* FALLTHROUGH */
+ case MGC_END0_OUT:
+ fifo_count = min(qh->maxpacket, ((u16)
+ (urb->transfer_buffer_length
+ - urb->actual_length)));
+
+ if (fifo_count) {
+ fifo_dest = (u8 *) (urb->transfer_buffer
+ + urb->actual_length);
DBG(3, "Sending %d bytes to %p\n",
- wFifoCount, pFifoDest);
- musb_write_fifo(pEnd, wFifoCount, pFifoDest);
-
- qh->segsize = wFifoCount;
- pUrb->actual_length += wFifoCount;
- if (pUrb->actual_length
- < pUrb->transfer_buffer_length) {
- bMore = TRUE;
- }
+ fifo_count, fifo_dest);
+ musb_write_fifo(hw_ep, fifo_count, fifo_dest);
+
+ urb->actual_length += fifo_count;
+ bMore = TRUE;
}
+ break;
+ default:
+ ERR("bogus ep0 stage %d\n", musb->ep0_stage);
+ break;
}
return bMore;
*
* called with controller irqlocked
*/
-irqreturn_t musb_h_ep0_irq(struct musb *pThis)
+irqreturn_t musb_h_ep0_irq(struct musb *musb)
{
- struct urb *pUrb;
- u16 wCsrVal, wCount;
+ struct urb *urb;
+ u16 csr, len;
int status = 0;
- void __iomem *pBase = pThis->pRegs;
- struct musb_hw_ep *pEnd = pThis->control_ep;
- struct musb_qh *qh = pEnd->in_qh;
+ void __iomem *mbase = musb->mregs;
+ struct musb_hw_ep *hw_ep = musb->control_ep;
+ void __iomem *epio = hw_ep->regs;
+ struct musb_qh *qh = hw_ep->in_qh;
u8 bComplete = FALSE;
irqreturn_t retval = IRQ_NONE;
/* ep0 only has one queue, "in" */
- pUrb = next_urb(qh);
+ urb = next_urb(qh);
- MGC_SelectEnd(pBase, 0);
- wCsrVal = MGC_ReadCsr16(pBase, MGC_O_HDRC_CSR0, 0);
- wCount = MGC_ReadCsr8(pBase, MGC_O_HDRC_COUNT0, 0);
+ musb_ep_select(mbase, 0);
+ csr = musb_readw(epio, MUSB_CSR0);
+ len = (csr & MUSB_CSR0_RXPKTRDY)
+ ? musb_readb(epio, MUSB_COUNT0)
+ : 0;
DBG(4, "<== csr0 %04x, qh %p, count %d, urb %p, stage %d\n",
- wCsrVal, qh, wCount, pUrb, pThis->bEnd0Stage);
+ csr, qh, len, urb, musb->ep0_stage);
/* if we just did status stage, we are done */
- if (MGC_END0_STATUS == pThis->bEnd0Stage) {
+ if (MGC_END0_STATUS == musb->ep0_stage) {
retval = IRQ_HANDLED;
bComplete = TRUE;
}
/* prepare status */
- if (wCsrVal & MGC_M_CSR0_H_RXSTALL) {
+ if (csr & MUSB_CSR0_H_RXSTALL) {
DBG(6, "STALLING ENDPOINT\n");
status = -EPIPE;
- } else if (wCsrVal & MGC_M_CSR0_H_ERROR) {
- DBG(2, "no response, csr0 %04x\n", wCsrVal);
+ } else if (csr & MUSB_CSR0_H_ERROR) {
+ DBG(2, "no response, csr0 %04x\n", csr);
status = -EPROTO;
- } else if (wCsrVal & MGC_M_CSR0_H_NAKTIMEOUT) {
+ } else if (csr & MUSB_CSR0_H_NAKTIMEOUT) {
DBG(2, "control NAK timeout\n");
/* NOTE: this code path would be a good place to PAUSE a
* if (qh->ring.next != &musb->control), then
* we have a candidate... NAKing is *NOT* an error
*/
- MGC_WriteCsr16(pBase, MGC_O_HDRC_CSR0, 0, 0);
+ musb_writew(epio, MUSB_CSR0, 0);
retval = IRQ_HANDLED;
}
if (status) {
DBG(6, "aborting\n");
retval = IRQ_HANDLED;
- if (pUrb)
- pUrb->status = status;
+ if (urb)
+ urb->status = status;
bComplete = TRUE;
/* use the proper sequence to abort the transfer */
- if (wCsrVal & MGC_M_CSR0_H_REQPKT) {
- wCsrVal &= ~MGC_M_CSR0_H_REQPKT;
- MGC_WriteCsr16(pBase, MGC_O_HDRC_CSR0, 0, wCsrVal);
- wCsrVal &= ~MGC_M_CSR0_H_NAKTIMEOUT;
- MGC_WriteCsr16(pBase, MGC_O_HDRC_CSR0, 0, wCsrVal);
+ if (csr & MUSB_CSR0_H_REQPKT) {
+ csr &= ~MUSB_CSR0_H_REQPKT;
+ musb_writew(epio, MUSB_CSR0, csr);
+ csr &= ~MUSB_CSR0_H_NAKTIMEOUT;
+ musb_writew(epio, MUSB_CSR0, csr);
} else {
- wCsrVal |= MGC_M_CSR0_FLUSHFIFO;
- MGC_WriteCsr16(pBase, MGC_O_HDRC_CSR0, 0, wCsrVal);
- MGC_WriteCsr16(pBase, MGC_O_HDRC_CSR0, 0, wCsrVal);
- wCsrVal &= ~MGC_M_CSR0_H_NAKTIMEOUT;
- MGC_WriteCsr16(pBase, MGC_O_HDRC_CSR0, 0, wCsrVal);
+ csr |= MUSB_CSR0_FLUSHFIFO;
+ musb_writew(epio, MUSB_CSR0, csr);
+ musb_writew(epio, MUSB_CSR0, csr);
+ csr &= ~MUSB_CSR0_H_NAKTIMEOUT;
+ musb_writew(epio, MUSB_CSR0, csr);
}
- MGC_WriteCsr8(pBase, MGC_O_HDRC_NAKLIMIT0, 0, 0);
+ musb_writeb(epio, MUSB_NAKLIMIT0, 0);
/* clear it */
- MGC_WriteCsr16(pBase, MGC_O_HDRC_CSR0, 0, 0);
+ musb_writew(epio, MUSB_CSR0, 0);
}
- if (unlikely(!pUrb)) {
+ if (unlikely(!urb)) {
/* stop endpoint since we have no place for its data, this
* SHOULD NEVER HAPPEN! */
ERR("no URB for end 0\n");
- MGC_WriteCsr16(pBase, MGC_O_HDRC_CSR0, 0, MGC_M_CSR0_FLUSHFIFO);
- MGC_WriteCsr16(pBase, MGC_O_HDRC_CSR0, 0, MGC_M_CSR0_FLUSHFIFO);
- MGC_WriteCsr16(pBase, MGC_O_HDRC_CSR0, 0, 0);
+ musb_writew(epio, MUSB_CSR0, MUSB_CSR0_FLUSHFIFO);
+ musb_writew(epio, MUSB_CSR0, MUSB_CSR0_FLUSHFIFO);
+ musb_writew(epio, MUSB_CSR0, 0);
goto done;
}
if (!bComplete) {
/* call common logic and prepare response */
- if (musb_h_ep0_continue(pThis, wCount, pUrb)) {
+ if (musb_h_ep0_continue(musb, len, urb)) {
/* more packets required */
- wCsrVal = (MGC_END0_IN == pThis->bEnd0Stage)
- ? MGC_M_CSR0_H_REQPKT : MGC_M_CSR0_TXPKTRDY;
+ csr = (MGC_END0_IN == musb->ep0_stage)
+ ? MUSB_CSR0_H_REQPKT : MUSB_CSR0_TXPKTRDY;
} else {
/* data transfer complete; perform status phase */
- wCsrVal = MGC_M_CSR0_H_STATUSPKT
- | (usb_pipeout(pUrb->pipe)
- ? MGC_M_CSR0_H_REQPKT
- : MGC_M_CSR0_TXPKTRDY);
+ if (usb_pipeout(urb->pipe)
+ || !urb->transfer_buffer_length)
+ csr = MUSB_CSR0_H_STATUSPKT
+ | MUSB_CSR0_H_REQPKT;
+ else
+ csr = MUSB_CSR0_H_STATUSPKT
+ | MUSB_CSR0_TXPKTRDY;
+
/* flag status stage */
- pThis->bEnd0Stage = MGC_END0_STATUS;
+ musb->ep0_stage = MGC_END0_STATUS;
- DBG(5, "ep0 STATUS, csr %04x\n", wCsrVal);
+ DBG(5, "ep0 STATUS, csr %04x\n", csr);
}
- MGC_WriteCsr16(pBase, MGC_O_HDRC_CSR0, 0, wCsrVal);
+ musb_writew(epio, MUSB_CSR0, csr);
retval = IRQ_HANDLED;
- }
+ } else
+ musb->ep0_stage = MGC_END0_IDLE;
/* call completion handler if done */
if (bComplete)
- musb_advance_schedule(pThis, pUrb, pEnd, 1);
+ musb_advance_schedule(musb, urb, hw_ep, 1);
done:
return retval;
}
#endif
/* Service a Tx-Available or dma completion irq for the endpoint */
-void musb_host_tx(struct musb *pThis, u8 bEnd)
+void musb_host_tx(struct musb *musb, u8 epnum)
{
- int nPipe;
- u8 bDone = FALSE;
- u16 wTxCsrVal;
+ int pipe;
+ u8 done = FALSE;
+ u16 tx_csr;
size_t wLength = 0;
- u8 *pBuffer = NULL;
- struct urb *pUrb;
- struct musb_hw_ep *pEnd = pThis->aLocalEnd + bEnd;
- struct musb_qh *qh = pEnd->out_qh;
+ u8 *buf = NULL;
+ struct urb *urb;
+ struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
+ void __iomem *epio = hw_ep->regs;
+ struct musb_qh *qh = hw_ep->out_qh;
u32 status = 0;
- void __iomem *pBase = pThis->pRegs;
+ void __iomem *mbase = musb->mregs;
struct dma_channel *dma;
- pUrb = next_urb(qh);
+ urb = next_urb(qh);
- MGC_SelectEnd(pBase, bEnd);
- wTxCsrVal = MGC_ReadCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd);
+ musb_ep_select(mbase, epnum);
+ tx_csr = musb_readw(epio, MUSB_TXCSR);
/* with CPPI, DMA sometimes triggers "extra" irqs */
- if (!pUrb) {
- DBG(4, "extra TX%d ready, csr %04x\n", bEnd, wTxCsrVal);
+ if (!urb) {
+ DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr);
goto finish;
}
- nPipe = pUrb->pipe;
- dma = is_dma_capable() ? pEnd->tx_channel : NULL;
- DBG(4, "OUT/TX%d end, csr %04x%s\n", bEnd, wTxCsrVal,
+ pipe = urb->pipe;
+ dma = is_dma_capable() ? hw_ep->tx_channel : NULL;
+ DBG(4, "OUT/TX%d end, csr %04x%s\n", epnum, tx_csr,
dma ? ", dma" : "");
/* check for errors */
- if (wTxCsrVal & MGC_M_TXCSR_H_RXSTALL) {
+ if (tx_csr & MUSB_TXCSR_H_RXSTALL) {
/* dma was disabled, fifo flushed */
- DBG(3, "TX end %d stall\n", bEnd);
+ DBG(3, "TX end %d stall\n", epnum);
/* stall; record URB status */
status = -EPIPE;
- } else if (wTxCsrVal & MGC_M_TXCSR_H_ERROR) {
+ } else if (tx_csr & MUSB_TXCSR_H_ERROR) {
/* (NON-ISO) dma was disabled, fifo flushed */
- DBG(3, "TX 3strikes on ep=%d\n", bEnd);
+ DBG(3, "TX 3strikes on ep=%d\n", epnum);
status = -ETIMEDOUT;
- } else if (wTxCsrVal & MGC_M_TXCSR_H_NAKTIMEOUT) {
- DBG(6, "TX end=%d device not responding\n", bEnd);
+ } else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) {
+ DBG(6, "TX end=%d device not responding\n", epnum);
/* NOTE: this code path would be a good place to PAUSE a
* transfer, if there's some other (nonperiodic) tx urb
* if (bulk && qh->ring.next != &musb->out_bulk), then
* we have a candidate... NAKing is *NOT* an error
*/
- MGC_SelectEnd(pBase, bEnd);
- MGC_WriteCsr16(pBase, MGC_O_HDRC_CSR0, 0,
- MGC_M_TXCSR_H_WZC_BITS
- | MGC_M_TXCSR_TXPKTRDY);
+ musb_ep_select(mbase, epnum);
+ musb_writew(epio, MUSB_CSR0,
+ MUSB_TXCSR_H_WZC_BITS
+ | MUSB_TXCSR_TXPKTRDY);
goto finish;
}
if (status) {
if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
- dma->bStatus = MGC_DMA_STATUS_CORE_ABORT;
- (void) pThis->pDmaController->channel_abort(dma);
+ dma->status = MGC_DMA_STATUS_CORE_ABORT;
+ (void) musb->dma_controller->channel_abort(dma);
}
/* do the proper sequence to abort the transfer in the
* usb core; the dma engine should already be stopped.
*/
-// SCRUB (TX)
- if (wTxCsrVal & MGC_M_TXCSR_FIFONOTEMPTY)
- wTxCsrVal |= MGC_M_TXCSR_FLUSHFIFO;
- wTxCsrVal &= ~(MGC_M_TXCSR_FIFONOTEMPTY
- | MGC_M_TXCSR_AUTOSET
- | MGC_M_TXCSR_DMAENAB
- | MGC_M_TXCSR_H_ERROR
- | MGC_M_TXCSR_H_RXSTALL
- | MGC_M_TXCSR_H_NAKTIMEOUT
+ musb_h_tx_flush_fifo(hw_ep);
+ tx_csr &= ~(MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_DMAENAB
+ | MUSB_TXCSR_H_ERROR
+ | MUSB_TXCSR_H_RXSTALL
+ | MUSB_TXCSR_H_NAKTIMEOUT
);
- MGC_SelectEnd(pBase, bEnd);
- MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd, wTxCsrVal);
+ musb_ep_select(mbase, epnum);
+ musb_writew(epio, MUSB_TXCSR, tx_csr);
/* REVISIT may need to clear FLUSHFIFO ... */
- MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd, wTxCsrVal);
- MGC_WriteCsr8(pBase, MGC_O_HDRC_TXINTERVAL, bEnd, 0);
+ musb_writew(epio, MUSB_TXCSR, tx_csr);
+ musb_writeb(epio, MUSB_TXINTERVAL, 0);
- bDone = TRUE;
+ done = TRUE;
}
/* second cppi case */
if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
- DBG(4, "extra TX%d ready, csr %04x\n", bEnd, wTxCsrVal);
+ DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr);
goto finish;
}
/* 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);
- MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd,
- MGC_M_TXCSR_TXPKTRDY);
- }
-#endif
+ if (!status || dma || usb_pipeisoc(pipe)) {
if (dma)
- wLength = dma->dwActualLength;
+ wLength = dma->actual_len;
else
wLength = qh->segsize;
qh->offset += wLength;
- if (usb_pipeisoc(nPipe)) {
+ if (usb_pipeisoc(pipe)) {
struct usb_iso_packet_descriptor *d;
- d = pUrb->iso_frame_desc + qh->iso_idx;
+ d = urb->iso_frame_desc + qh->iso_idx;
d->actual_length = qh->segsize;
- if (++qh->iso_idx >= pUrb->number_of_packets) {
- bDone = TRUE;
+ if (++qh->iso_idx >= urb->number_of_packets) {
+ done = TRUE;
} else if (!dma) {
d++;
- pBuffer = pUrb->transfer_buffer + d->offset;
+ buf = urb->transfer_buffer + d->offset;
wLength = d->length;
}
} else if (dma) {
- bDone = TRUE;
+ done = TRUE;
} else {
/* see if we need to send more data, or ZLP */
if (qh->segsize < qh->maxpacket)
- bDone = TRUE;
- else if (qh->offset == pUrb->transfer_buffer_length
- && !(pUrb-> transfer_flags
+ done = TRUE;
+ else if (qh->offset == urb->transfer_buffer_length
+ && !(urb-> transfer_flags
& URB_ZERO_PACKET))
- bDone = TRUE;
- if (!bDone) {
- pBuffer = pUrb->transfer_buffer
+ done = TRUE;
+ if (!done) {
+ buf = urb->transfer_buffer
+ qh->offset;
- wLength = pUrb->transfer_buffer_length
+ wLength = urb->transfer_buffer_length
- qh->offset;
}
}
/* urb->status != -EINPROGRESS means request has been faulted,
* so we must abort this transfer after cleanup
*/
- if (pUrb->status != -EINPROGRESS) {
- bDone = TRUE;
+ if (urb->status != -EINPROGRESS) {
+ done = TRUE;
if (status == 0)
- status = pUrb->status;
+ status = urb->status;
}
- if (bDone) {
+ if (done) {
/* set status */
- pUrb->status = status;
- pUrb->actual_length = qh->offset;
- musb_advance_schedule(pThis, pUrb, pEnd, USB_DIR_OUT);
+ urb->status = status;
+ urb->actual_length = qh->offset;
+ musb_advance_schedule(musb, urb, hw_ep, USB_DIR_OUT);
- } else if (!(wTxCsrVal & MGC_M_TXCSR_DMAENAB)) {
- // WARN_ON(!pBuffer);
+ } else if (!(tx_csr & MUSB_TXCSR_DMAENAB)) {
+ // WARN_ON(!buf);
- /* REVISIT: some docs say that when pEnd->tx_double_buffered,
+ /* REVISIT: some docs say that when hw_ep->tx_double_buffered,
* (and presumably, fifo is not half-full) we should write TWO
* packets before updating TXCSR ... other docs disagree ...
*/
/* PIO: start next packet in this URB */
wLength = min(qh->maxpacket, (u16) wLength);
- musb_write_fifo(pEnd, wLength, pBuffer);
+ musb_write_fifo(hw_ep, wLength, buf);
qh->segsize = wLength;
- MGC_SelectEnd(pBase, bEnd);
- MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd,
- MGC_M_TXCSR_H_WZC_BITS | MGC_M_TXCSR_TXPKTRDY);
+ musb_ep_select(mbase, epnum);
+ musb_writew(epio, MUSB_TXCSR,
+ MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
} else
DBG(1, "not complete, but dma enabled?\n");
* Service an RX interrupt for the given IN endpoint; docs cover bulk, iso,
* and high-bandwidth IN transfer cases.
*/
-void musb_host_rx(struct musb *pThis, u8 bEnd)
+void musb_host_rx(struct musb *musb, u8 epnum)
{
- struct urb *pUrb;
- struct musb_hw_ep *pEnd = pThis->aLocalEnd + bEnd;
- struct musb_qh *qh = pEnd->in_qh;
+ struct urb *urb;
+ struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
+ void __iomem *epio = hw_ep->regs;
+ struct musb_qh *qh = hw_ep->in_qh;
size_t xfer_len;
- void __iomem *pBase = pThis->pRegs;
- int nPipe;
- u16 wRxCsrVal, wVal;
- u8 bIsochError = FALSE;
- u8 bDone = FALSE;
+ void __iomem *mbase = musb->mregs;
+ int pipe;
+ u16 rx_csr, wVal;
+ u8 iso_err = FALSE;
+ u8 done = FALSE;
u32 status;
struct dma_channel *dma;
- MGC_SelectEnd(pBase, bEnd);
+ musb_ep_select(mbase, epnum);
- pUrb = next_urb(qh);
- dma = is_dma_capable() ? pEnd->rx_channel : NULL;
+ urb = next_urb(qh);
+ dma = is_dma_capable() ? hw_ep->rx_channel : NULL;
status = 0;
xfer_len = 0;
- wVal = wRxCsrVal = MGC_ReadCsr16(pBase, MGC_O_HDRC_RXCSR, bEnd);
+ wVal = rx_csr = musb_readw(epio, MUSB_RXCSR);
- if (unlikely(!pUrb)) {
+ if (unlikely(!urb)) {
/* REVISIT -- THIS SHOULD NEVER HAPPEN ... but, at least
* usbtest #11 (unlinks) triggers it regularly, sometimes
* with fifo full. (Only with DMA??)
*/
- DBG(3, "BOGUS RX%d ready, csr %04x, count %d\n", bEnd, wVal,
- MGC_ReadCsr16(pBase, MGC_O_HDRC_RXCOUNT, bEnd));
- musb_h_flush_rxfifo(pEnd, MGC_M_RXCSR_CLRDATATOG);
+ DBG(3, "BOGUS RX%d ready, csr %04x, count %d\n", epnum, wVal,
+ musb_readw(epio, MUSB_RXCOUNT));
+ musb_h_flush_rxfifo(hw_ep, MUSB_RXCSR_CLRDATATOG);
return;
}
- nPipe = pUrb->pipe;
+ pipe = urb->pipe;
DBG(5, "<== hw %d rxcsr %04x, urb actual %d (+dma %zd)\n",
- bEnd, wRxCsrVal, pUrb->actual_length,
- dma ? dma->dwActualLength : 0);
+ epnum, rx_csr, urb->actual_length,
+ dma ? dma->actual_len : 0);
/* check for errors, concurrent stall & unlink is not really
* handled yet! */
- if (wRxCsrVal & MGC_M_RXCSR_H_RXSTALL) {
- DBG(3, "RX end %d STALL\n", bEnd);
+ if (rx_csr & MUSB_RXCSR_H_RXSTALL) {
+ DBG(3, "RX end %d STALL\n", epnum);
/* stall; record URB status */
status = -EPIPE;
- } else if (wRxCsrVal & MGC_M_RXCSR_H_ERROR) {
- DBG(3, "end %d RX proto error\n", bEnd);
+ } else if (rx_csr & MUSB_RXCSR_H_ERROR) {
+ DBG(3, "end %d RX proto error\n", epnum);
status = -EPROTO;
- MGC_WriteCsr8(pBase, MGC_O_HDRC_RXINTERVAL, bEnd, 0);
+ musb_writeb(epio, MUSB_RXINTERVAL, 0);
- } else if (wRxCsrVal & MGC_M_RXCSR_DATAERROR) {
+ } else if (rx_csr & MUSB_RXCSR_DATAERROR) {
if (USB_ENDPOINT_XFER_ISOC != qh->type) {
/* NOTE this code path would be a good place to PAUSE a
* if (bulk && qh->ring.next != &musb->in_bulk), then
* we have a candidate... NAKing is *NOT* an error
*/
- DBG(6, "RX end %d NAK timeout\n", bEnd);
- MGC_SelectEnd(pBase, bEnd);
- MGC_WriteCsr16(pBase, MGC_O_HDRC_RXCSR, bEnd,
- MGC_M_RXCSR_H_WZC_BITS
- | MGC_M_RXCSR_H_REQPKT);
+ DBG(6, "RX end %d NAK timeout\n", epnum);
+ musb_ep_select(mbase, epnum);
+ musb_writew(epio, MUSB_RXCSR,
+ MUSB_RXCSR_H_WZC_BITS
+ | MUSB_RXCSR_H_REQPKT);
goto finish;
} else {
- DBG(4, "RX end %d ISO data error\n", bEnd);
+ DBG(4, "RX end %d ISO data error\n", epnum);
/* packet error reported later */
- bIsochError = TRUE;
+ iso_err = TRUE;
}
}
if (status) {
/* clean up dma and collect transfer count */
if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
- dma->bStatus = MGC_DMA_STATUS_CORE_ABORT;
- (void) pThis->pDmaController->channel_abort(dma);
- xfer_len = dma->dwActualLength;
+ dma->status = MGC_DMA_STATUS_CORE_ABORT;
+ (void) musb->dma_controller->channel_abort(dma);
+ xfer_len = dma->actual_len;
}
- musb_h_flush_rxfifo(pEnd, 0);
- MGC_WriteCsr8(pBase, MGC_O_HDRC_RXINTERVAL, bEnd, 0);
- bDone = TRUE;
+ musb_h_flush_rxfifo(hw_ep, 0);
+ musb_writeb(epio, MUSB_RXINTERVAL, 0);
+ done = TRUE;
goto finish;
}
if (unlikely(dma_channel_status(dma) == MGC_DMA_STATUS_BUSY)) {
/* SHOULD NEVER HAPPEN ... but at least DaVinci has done it */
- ERR("RX%d dma busy, csr %04x\n", bEnd, wRxCsrVal);
+ ERR("RX%d dma busy, csr %04x\n", epnum, rx_csr);
goto finish;
}
/* FIXME this is _way_ too much in-line logic for Mentor DMA */
#ifndef CONFIG_USB_INVENTRA_DMA
- if (wRxCsrVal & MGC_M_RXCSR_H_REQPKT) {
+ if (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,
* shouldn't this be the "half full" double buffer case?
*/
if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
- dma->bStatus = MGC_DMA_STATUS_CORE_ABORT;
- (void) pThis->pDmaController->channel_abort(dma);
- xfer_len = dma->dwActualLength;
- bDone = TRUE;
+ dma->status = MGC_DMA_STATUS_CORE_ABORT;
+ (void) musb->dma_controller->channel_abort(dma);
+ xfer_len = dma->actual_len;
+ done = TRUE;
}
- DBG(2, "RXCSR%d %04x, reqpkt, len %zd%s\n", bEnd, wRxCsrVal,
+ DBG(2, "RXCSR%d %04x, reqpkt, len %zd%s\n", epnum, rx_csr,
xfer_len, dma ? ", dma" : "");
- wRxCsrVal &= ~MGC_M_RXCSR_H_REQPKT;
+ rx_csr &= ~MUSB_RXCSR_H_REQPKT;
- MGC_SelectEnd(pBase, bEnd);
- MGC_WriteCsr16(pBase, MGC_O_HDRC_RXCSR, bEnd,
- MGC_M_RXCSR_H_WZC_BITS | wRxCsrVal);
+ musb_ep_select(mbase, epnum);
+ musb_writew(epio, MUSB_RXCSR,
+ MUSB_RXCSR_H_WZC_BITS | rx_csr);
}
#endif
- if (dma && (wRxCsrVal & MGC_M_RXCSR_DMAENAB)) {
- xfer_len = dma->dwActualLength;
+ if (dma && (rx_csr & MUSB_RXCSR_DMAENAB)) {
+ xfer_len = dma->actual_len;
- wVal &= ~(MGC_M_RXCSR_DMAENAB
- | MGC_M_RXCSR_H_AUTOREQ
- | MGC_M_RXCSR_AUTOCLEAR
- | MGC_M_RXCSR_RXPKTRDY);
- musb_writew(pEnd->regs, MGC_O_HDRC_RXCSR, wVal);
+ wVal &= ~(MUSB_RXCSR_DMAENAB
+ | MUSB_RXCSR_H_AUTOREQ
+ | MUSB_RXCSR_AUTOCLEAR
+ | MUSB_RXCSR_RXPKTRDY);
+ musb_writew(hw_ep->regs, MUSB_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)
- || (dma->dwActualLength & (qh->maxpacket - 1));
+ /* done if urb buffer is full or short packet is recd */
+ done = ((urb->actual_length + xfer_len) >=
+ urb->transfer_buffer_length)
+ || (dma->actual_len & (qh->maxpacket - 1));
/* send IN token for next packet, without AUTOREQ */
- if (!bDone) {
- wVal |= MGC_M_RXCSR_H_REQPKT;
- MGC_WriteCsr16(pBase, MGC_O_HDRC_RXCSR, bEnd,
- MGC_M_RXCSR_H_WZC_BITS | wVal);
+ if (!done) {
+ wVal |= MUSB_RXCSR_H_REQPKT;
+ musb_writew(epio, MUSB_RXCSR,
+ MUSB_RXCSR_H_WZC_BITS | wVal);
}
- DBG(4, "ep %d dma %s, rxcsr %04x, rxcount %d\n", bEnd,
- bDone ? "off" : "reset",
- MGC_ReadCsr16(pBase, MGC_O_HDRC_RXCSR, bEnd),
- MGC_ReadCsr16(pBase, MGC_O_HDRC_RXCOUNT, bEnd));
+ DBG(4, "ep %d dma %s, rxcsr %04x, rxcount %d\n", epnum,
+ done ? "off" : "reset",
+ musb_readw(epio, MUSB_RXCSR),
+ musb_readw(epio, MUSB_RXCOUNT));
#else
- bDone = TRUE;
+ done = TRUE;
#endif
- } else if (pUrb->status == -EINPROGRESS) {
+ } else if (urb->status == -EINPROGRESS) {
/* if no errors, be sure a packet is ready for unloading */
- if (unlikely(!(wRxCsrVal & MGC_M_RXCSR_RXPKTRDY))) {
+ if (unlikely(!(rx_csr & MUSB_RXCSR_RXPKTRDY))) {
status = -EPROTO;
ERR("Rx interrupt with no errors or packet!\n");
// SCRUB (RX)
/* do the proper sequence to abort the transfer */
- MGC_SelectEnd(pBase, bEnd);
- wVal &= ~MGC_M_RXCSR_H_REQPKT;
- MGC_WriteCsr16(pBase, MGC_O_HDRC_RXCSR, bEnd, wVal);
+ musb_ep_select(mbase, epnum);
+ wVal &= ~MUSB_RXCSR_H_REQPKT;
+ musb_writew(epio, MUSB_RXCSR, wVal);
goto finish;
}
#ifdef CONFIG_USB_INVENTRA_DMA
if (dma) {
struct dma_controller *c;
- u16 wRxCount;
+ u16 rx_count;
int status;
- wRxCount = MGC_ReadCsr16(pBase,
- MGC_O_HDRC_RXCOUNT, bEnd);
+ rx_count = musb_readw(epio, MUSB_RXCOUNT);
DBG(2, "RX%d count %d, buffer 0x%x len %d/%d\n",
- bEnd, wRxCount,
- pUrb->transfer_dma
- + pUrb->actual_length,
+ epnum, rx_count,
+ urb->transfer_dma
+ + urb->actual_length,
qh->offset,
- pUrb->transfer_buffer_length);
+ urb->transfer_buffer_length);
- c = pThis->pDmaController;
+ c = musb->dma_controller;
- dma->bDesiredMode = 0;
+ dma->desired_mode = 0;
#ifdef USE_MODE1
/* because of the issue below, mode 1 will
* only rarely behave with correct semantics.
*/
- if ((pUrb->transfer_flags &
+ if ((urb->transfer_flags &
URB_SHORT_NOT_OK)
- && (pUrb->transfer_buffer_length -
- pUrb->actual_length)
+ && (urb->transfer_buffer_length -
+ urb->actual_length)
> qh->maxpacket)
- dma->bDesiredMode = 1;
+ dma->desired_mode = 1;
#endif
/* Disadvantage of using mode 1:
* wait for an interrupt when the pkt is recd. Well, you won't get any!
*/
- wVal = MGC_ReadCsr16(pBase, MGC_O_HDRC_RXCSR, bEnd);
- wVal &= ~MGC_M_RXCSR_H_REQPKT;
+ wVal = musb_readw(epio, MUSB_RXCSR);
+ wVal &= ~MUSB_RXCSR_H_REQPKT;
- if (dma->bDesiredMode == 0)
- wVal &= ~MGC_M_RXCSR_H_AUTOREQ;
+ if (dma->desired_mode == 0)
+ wVal &= ~MUSB_RXCSR_H_AUTOREQ;
else
- wVal |= MGC_M_RXCSR_H_AUTOREQ;
- wVal |= MGC_M_RXCSR_AUTOCLEAR | MGC_M_RXCSR_DMAENAB;
+ wVal |= MUSB_RXCSR_H_AUTOREQ;
+ wVal |= MUSB_RXCSR_AUTOCLEAR | MUSB_RXCSR_DMAENAB;
- MGC_WriteCsr16(pBase, MGC_O_HDRC_RXCSR, bEnd,
- MGC_M_RXCSR_H_WZC_BITS | wVal);
+ musb_writew(epio, MUSB_RXCSR,
+ MUSB_RXCSR_H_WZC_BITS | wVal);
/* REVISIT if when actual_length != 0,
* transfer_buffer_length needs to be
*/
status = c->channel_program(
dma, qh->maxpacket,
- dma->bDesiredMode,
- pUrb->transfer_dma
- + pUrb->actual_length,
- (dma->bDesiredMode == 0)
- ? wRxCount
- : pUrb->transfer_buffer_length);
+ dma->desired_mode,
+ urb->transfer_dma
+ + urb->actual_length,
+ (dma->desired_mode == 0)
+ ? rx_count
+ : urb->transfer_buffer_length);
if (!status) {
c->channel_release(dma);
- dma = pEnd->rx_channel = NULL;
+ dma = hw_ep->rx_channel = NULL;
/* REVISIT reset CSR */
}
}
#endif /* Mentor DMA */
if (!dma) {
- bDone = musb_host_packet_rx(pThis, pUrb,
- bEnd, bIsochError);
- DBG(6, "read %spacket\n", bDone ? "last " : "");
+ done = musb_host_packet_rx(musb, urb,
+ epnum, iso_err);
+ DBG(6, "read %spacket\n", done ? "last " : "");
}
}
finish:
- pUrb->actual_length += xfer_len;
+ urb->actual_length += xfer_len;
qh->offset += xfer_len;
- if (bDone) {
- if (pUrb->status == -EINPROGRESS)
- pUrb->status = status;
- musb_advance_schedule(pThis, pUrb, pEnd, USB_DIR_IN);
+ if (done) {
+ if (urb->status == -EINPROGRESS)
+ urb->status = status;
+ musb_advance_schedule(musb, urb, hw_ep, USB_DIR_IN);
}
}
wBestDiff = 4096;
nBestEnd = -1;
- for (nEnd = 1; nEnd < musb->bEndCount; nEnd++) {
+ for (nEnd = 1; nEnd < musb->nr_endpoints; nEnd++) {
int diff;
if (musb->periodic[nEnd])
continue;
- hw_ep = &musb->aLocalEnd[nEnd];
+ hw_ep = &musb->endpoints[nEnd];
if (hw_ep == musb->bulk_ep)
continue;
if (is_in)
- diff = hw_ep->wMaxPacketSizeRx - qh->maxpacket;
+ diff = hw_ep->max_packet_sz_rx - qh->maxpacket;
else
- diff = hw_ep->wMaxPacketSizeTx - qh->maxpacket;
+ diff = hw_ep->max_packet_sz_tx - qh->maxpacket;
if (diff > 0 && wBestDiff > diff) {
wBestDiff = diff;
return -ENOSPC;
idle = 1;
- hw_ep = musb->aLocalEnd + nBestEnd;
+ hw_ep = musb->endpoints + nBestEnd;
musb->periodic[nBestEnd] = qh;
DBG(4, "qh %p periodic slot %d\n", qh, nBestEnd);
success:
* transfer scheduling logic to try some other qh, e.g. try
* for 2 msec first:
*
- * interval = (USB_SPEED_HIGH == pUrb->dev->speed) ? 16 : 2;
+ * interval = (USB_SPEED_HIGH == urb->dev->speed) ? 16 : 2;
*
* The downside of disabling this is that transfer scheduling
* gets VERY unfair for nonperiodic transfers; a misbehaving
qh->intv_reg = interval;
/* precompute addressing for external hub/tt ports */
- if (musb->bIsMultipoint) {
+ if (musb->is_multipoint) {
struct usb_device *parent = urb->dev->parent;
if (parent != hcd->self.root_hub) {
* until we get real dma queues (with an entry for each urb/buffer),
* we only have work to do in the former case.
*/
- spin_lock_irqsave(&musb->Lock, flags);
+ spin_lock_irqsave(&musb->lock, flags);
if (hep->hcpriv) {
/* some concurrent activity submitted another urb to hep...
* odd, rare, error prone, but legal.
* musb_start_urb(), but otherwise only konicawc cares ...
*/
}
- spin_unlock_irqrestore(&musb->Lock, flags);
+ spin_unlock_irqrestore(&musb->lock, flags);
done:
if (status != 0)
static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in)
{
struct musb_hw_ep *ep = qh->hw_ep;
- unsigned hw_end = ep->bLocalEnd;
- void __iomem *regs = ep->musb->pRegs;
+ void __iomem *epio = ep->regs;
+ unsigned hw_end = ep->epnum;
+ void __iomem *regs = ep->musb->mregs;
u16 csr;
int status = 0;
- MGC_SelectEnd(regs, hw_end);
+ musb_ep_select(regs, hw_end);
if (is_dma_capable()) {
struct dma_channel *dma;
dma = is_in ? ep->rx_channel : ep->tx_channel;
if (dma) {
- status = ep->musb->pDmaController->channel_abort(dma);
+ status = ep->musb->dma_controller->channel_abort(dma);
DBG(status ? 1 : 3,
"abort %cX%d DMA for urb %p --> %d\n",
- is_in ? 'R' : 'T', ep->bLocalEnd,
+ is_in ? 'R' : 'T', ep->epnum,
urb, status);
- urb->actual_length += dma->dwActualLength;
+ urb->actual_length += dma->actual_len;
}
}
* clearing that status is platform-specific...
*/
} else {
-// SCRUB (TX)
- csr = MGC_ReadCsr16(regs, MGC_O_HDRC_TXCSR, hw_end);
- if (csr & MGC_M_TXCSR_FIFONOTEMPTY)
- csr |= MGC_M_TXCSR_FLUSHFIFO;
- csr &= ~( MGC_M_TXCSR_AUTOSET
- | MGC_M_TXCSR_DMAENAB
- | MGC_M_TXCSR_H_RXSTALL
- | MGC_M_TXCSR_H_NAKTIMEOUT
- | MGC_M_TXCSR_H_ERROR
- | MGC_M_TXCSR_FIFONOTEMPTY
+ musb_h_tx_flush_fifo(ep);
+ csr = musb_readw(epio, MUSB_TXCSR);
+ csr &= ~( MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_DMAENAB
+ | MUSB_TXCSR_H_RXSTALL
+ | MUSB_TXCSR_H_NAKTIMEOUT
+ | MUSB_TXCSR_H_ERROR
+ | MUSB_TXCSR_TXPKTRDY
);
- MGC_WriteCsr16(regs, MGC_O_HDRC_TXCSR, 0, csr);
+ musb_writew(epio, MUSB_TXCSR, csr);
/* REVISIT may need to clear FLUSHFIFO ... */
- MGC_WriteCsr16(regs, MGC_O_HDRC_TXCSR, 0, csr);
+ musb_writew(epio, MUSB_TXCSR, csr);
/* flush cpu writebuffer */
- csr = MGC_ReadCsr16(regs, MGC_O_HDRC_TXCSR, hw_end);
+ csr = musb_readw(epio, MUSB_TXCSR);
}
if (status == 0)
musb_advance_schedule(ep->musb, urb, ep, is_in);
usb_pipeendpoint(urb->pipe),
usb_pipein(urb->pipe) ? "in" : "out");
- spin_lock_irqsave(&musb->Lock, flags);
+ spin_lock_irqsave(&musb->lock, flags);
/* make sure the urb is still queued and not completed */
spin_lock(&urb->lock);
}
}
spin_unlock(&urb->lock);
+
+ /* already completed */
+ if (!qh) {
+ status = 0;
+ goto done;
+ }
+
+ /* still queued but not found on the list */
if (status)
goto done;
} else
status = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
done:
- spin_unlock_irqrestore(&musb->Lock, flags);
+ spin_unlock_irqrestore(&musb->lock, flags);
return status;
}
if (!qh)
return;
- spin_lock_irqsave(&musb->Lock, flags);
+ spin_lock_irqsave(&musb->lock, flags);
switch (qh->type) {
case USB_ENDPOINT_XFER_CONTROL:
list_for_each_entry_safe_from(urb, tmp, &hep->urb_list, urb_list)
musb_giveback(qh, urb, -ESHUTDOWN);
- spin_unlock_irqrestore(&musb->Lock, flags);
+ spin_unlock_irqrestore(&musb->lock, flags);
}
static int musb_h_get_frame_number(struct usb_hcd *hcd)
{
struct musb *musb = hcd_to_musb(hcd);
- return musb_readw(musb->pRegs, MGC_O_HDRC_FRAME);
+ return musb_readw(musb->mregs, MUSB_FRAME);
}
static int musb_h_start(struct usb_hcd *hcd)
{
+ struct musb *musb = hcd_to_musb(hcd);
+
/* NOTE: musb_start() is called when the hub driver turns
* on port power, or when (OTG) peripheral starts.
*/
hcd->state = HC_STATE_RUNNING;
+ musb->port1_status = 0;
return 0;
}
{
struct musb *musb = hcd_to_musb(hcd);
- return musb->is_active ? -EBUSY : 0;
+ if (is_host_active(musb) && musb->is_active)
+ return -EBUSY;
+ else
+ return 0;
}
static int musb_bus_resume(struct usb_hcd *hcd)