From e5bb028400659e93fe532cf2da37c4133de9bede Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 5 Sep 2006 14:07:15 +0300 Subject: [PATCH] MUSB: Update register access based on new HDRC core spec Catch up to info from latest HDRC core spec ... some new registers and fields, and constraints notably - not clearing TX fifo unless it's empty (that might explain some host side glitching). - not all POWER fields are writable Signed-off-by: David Brownell --- drivers/usb/musb/g_ep0.c | 3 +- drivers/usb/musb/musb_gadget.c | 65 +++++++++++++++++++++------------- drivers/usb/musb/musb_host.c | 23 +++++++++--- drivers/usb/musb/musbhdrc.h | 22 ++++++++---- drivers/usb/musb/plat_uds.c | 5 ++- drivers/usb/musb/virthub.c | 1 - 6 files changed, 80 insertions(+), 39 deletions(-) diff --git a/drivers/usb/musb/g_ep0.c b/drivers/usb/musb/g_ep0.c index 35153c5f47a..fc6a7c0bf10 100644 --- a/drivers/usb/musb/g_ep0.c +++ b/drivers/usb/musb/g_ep0.c @@ -387,9 +387,10 @@ stall: if (is_in) { csr = musb_readw(regs, MGC_O_HDRC_TXCSR); + if (csr & MGC_M_TXCSR_FIFONOTEMPTY) + csr |= MGC_M_TXCSR_FLUSHFIFO; csr |= MGC_M_TXCSR_P_SENDSTALL | MGC_M_TXCSR_CLRDATATOG - | MGC_M_TXCSR_FLUSHFIFO | MGC_M_TXCSR_P_WZC_BITS; musb_writew(regs, MGC_O_HDRC_TXCSR, csr); diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index bd889aeeed9..24a07ccb5ad 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -297,11 +297,12 @@ static void txstate(struct musb *pThis, struct musb_request *req) pRequest->dma, request_size); if (use_dma) { if (pEnd->dma->bDesiredMode == 0) { + /* ASSERT: DMAENAB is clear */ wCsrVal &= ~(MGC_M_TXCSR_AUTOSET | MGC_M_TXCSR_DMAMODE); wCsrVal |= (MGC_M_TXCSR_DMAENAB | MGC_M_TXCSR_MODE); - // against programming guide + // against programming guide } else wCsrVal |= (MGC_M_TXCSR_AUTOSET @@ -347,6 +348,7 @@ static void txstate(struct musb *pThis, struct musb_request *req) if (!use_dma) { c->channel_release(pEnd->dma); pEnd->dma = NULL; + /* ASSERT: DMAENAB clear */ wCsrVal &= ~(MGC_M_TXCSR_DMAMODE | MGC_M_TXCSR_MODE); /* invariant: prequest->buf is non-null */ } @@ -837,8 +839,10 @@ done: static int musb_gadget_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) { - unsigned long flags; - struct musb_ep *pEnd; + unsigned long flags; + struct musb_ep *pEnd; + struct musb_hw_ep *hw_ep; + void __iomem *regs; struct musb *pThis; void __iomem *pBase; u8 bEnd; @@ -850,6 +854,8 @@ static int musb_gadget_enable(struct usb_ep *ep, return -EINVAL; pEnd = to_musb_ep(ep); + hw_ep = pEnd->hw_ep; + regs = hw_ep->regs; pThis = pEnd->pThis; pBase = pThis->pRegs; bEnd = pEnd->bEndNumber; @@ -879,11 +885,11 @@ static int musb_gadget_enable(struct usb_ep *ep, if (desc->bEndpointAddress & USB_DIR_IN) { u16 wIntrTxE = musb_readw(pBase, MGC_O_HDRC_INTRTXE); - if (pEnd->hw_ep->bIsSharedFifo) + if (hw_ep->bIsSharedFifo) pEnd->is_in = 1; if (!pEnd->is_in) goto fail; - if (tmp > pEnd->hw_ep->wMaxPacketSizeTx) + if (tmp > hw_ep->wMaxPacketSizeTx) goto fail; wIntrTxE |= (1 << bEnd); @@ -892,25 +898,28 @@ static int musb_gadget_enable(struct usb_ep *ep, /* REVISIT if can_bulk_split(), use by updating "tmp"; * likewise high bandwidth periodic tx */ - MGC_WriteCsr16(pBase, MGC_O_HDRC_TXMAXP, bEnd, tmp); + musb_writew(regs, MGC_O_HDRC_TXMAXP, tmp); - csr = MGC_M_TXCSR_MODE | MGC_M_TXCSR_CLRDATATOG - | MGC_M_TXCSR_FLUSHFIFO; + csr = MGC_M_TXCSR_MODE | MGC_M_TXCSR_CLRDATATOG; + if (musb_readw(regs, MGC_O_HDRC_TXCSR) + & MGC_M_TXCSR_FIFONOTEMPTY) + csr |= MGC_M_TXCSR_FLUSHFIFO; if (pEnd->type == USB_ENDPOINT_XFER_ISOC) csr |= MGC_M_TXCSR_P_ISO; /* set twice in case of double buffering */ - MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd, csr); - MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd, csr); + musb_writew(regs, MGC_O_HDRC_TXCSR, csr); + /* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */ + musb_writew(regs, MGC_O_HDRC_TXCSR, csr); } else { u16 wIntrRxE = musb_readw(pBase, MGC_O_HDRC_INTRRXE); - if (pEnd->hw_ep->bIsSharedFifo) + if (hw_ep->bIsSharedFifo) pEnd->is_in = 0; if (pEnd->is_in) goto fail; - if (tmp > pEnd->hw_ep->wMaxPacketSizeRx) + if (tmp > hw_ep->wMaxPacketSizeRx) goto fail; wIntrRxE |= (1 << bEnd); @@ -922,7 +931,7 @@ static int musb_gadget_enable(struct usb_ep *ep, MGC_WriteCsr16(pBase, MGC_O_HDRC_RXMAXP, bEnd, tmp); /* force shared fifo to OUT-only mode */ - if (pEnd->hw_ep->bIsSharedFifo) { + if (hw_ep->bIsSharedFifo) { csr = musb_readw(pBase, MGC_O_HDRC_TXCSR); csr &= ~(MGC_M_TXCSR_MODE | MGC_M_TXCSR_TXPKTRDY); MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd, csr); @@ -945,7 +954,7 @@ static int musb_gadget_enable(struct usb_ep *ep, if (is_dma_capable() && pThis->pDmaController) { struct dma_controller *c = pThis->pDmaController; - pEnd->dma = c->channel_alloc(c, pEnd->hw_ep, + pEnd->dma = c->channel_alloc(c, hw_ep, (desc->bEndpointAddress & USB_DIR_IN)); } else pEnd->dma = NULL; @@ -1292,9 +1301,10 @@ int musb_gadget_set_halt(struct usb_ep *ep, int value) DBG(2, "%s: %s stall\n", ep->name, value ? "set" : "clear"); if (pEnd->is_in) { wCsr = MGC_ReadCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd); + if (wCsr & MGC_M_TXCSR_FIFONOTEMPTY) + wCsr |= MGC_M_TXCSR_FLUSHFIFO; wCsr |= MGC_M_TXCSR_P_WZC_BITS - | MGC_M_TXCSR_CLRDATATOG - | MGC_M_TXCSR_FLUSHFIFO; + | MGC_M_TXCSR_CLRDATATOG; if (value) wCsr |= MGC_M_TXCSR_P_SENDSTALL; else @@ -1371,9 +1381,12 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep) if (musb_ep->is_in) { wCsr = MGC_ReadCsr16(mbase, MGC_O_HDRC_TXCSR, nEnd); - wCsr |= MGC_M_TXCSR_FLUSHFIFO | MGC_M_TXCSR_P_WZC_BITS; - MGC_WriteCsr16(mbase, MGC_O_HDRC_TXCSR, nEnd, wCsr); - MGC_WriteCsr16(mbase, MGC_O_HDRC_TXCSR, nEnd, wCsr); + if (wCsr & MGC_M_TXCSR_FIFONOTEMPTY) { + wCsr |= MGC_M_TXCSR_FLUSHFIFO | MGC_M_TXCSR_P_WZC_BITS; + MGC_WriteCsr16(mbase, MGC_O_HDRC_TXCSR, nEnd, wCsr); + /* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */ + MGC_WriteCsr16(mbase, MGC_O_HDRC_TXCSR, nEnd, wCsr); + } } else { wCsr = MGC_ReadCsr16(mbase, MGC_O_HDRC_RXCSR, nEnd); wCsr |= MGC_M_RXCSR_FLUSHFIFO | MGC_M_RXCSR_P_WZC_BITS; @@ -1413,17 +1426,21 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget) { struct musb *musb = gadget_to_musb(gadget); unsigned long flags; - int status = 0; + int status = -EINVAL; u8 power; spin_lock_irqsave(&musb->Lock, flags); + /* fail if we're not suspended */ + power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER); + if (!(power & MGC_M_POWER_SUSPENDM)) + goto done; + switch (musb->xceiv.state) { case OTG_STATE_B_PERIPHERAL: - /* FIXME if not suspended, fail */ if (musb->bMayWakeup) break; - goto fail; + goto done; case OTG_STATE_B_IDLE: /* REVISIT we might be able to do SRP even without OTG, * though Linux doesn't yet expose that capability @@ -1434,12 +1451,10 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget) } /* FALLTHROUGH */ default: -fail: - status = -EINVAL; goto done; } - power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER); + status = 0; power |= MGC_M_POWER_RESUME; musb_writeb(musb->pRegs, MGC_O_HDRC_POWER, power); diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index d10dad91523..6cf568058d1 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -717,7 +717,11 @@ static void musb_ep_program(struct musb *pThis, u8 bEnd, if (bEnd) { u16 csr = wCsr; + /* 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 @@ -727,8 +731,7 @@ static void musb_ep_program(struct musb *pThis, u8 bEnd, | MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY ); - csr |= MGC_M_TXCSR_FLUSHFIFO - | MGC_M_TXCSR_MODE; + csr |= MGC_M_TXCSR_MODE; if (qh->type == USB_ENDPOINT_XFER_ISOC) csr |= MGC_M_TXCSR_ISO; @@ -742,6 +745,7 @@ static void musb_ep_program(struct musb *pThis, u8 bEnd, /* twice in case of double packet buffering */ MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd, csr); + /* REVISIT may need to clear FLUSHFIFO ... */ MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd, csr); wCsr = MGC_ReadCsr16(pBase, MGC_O_HDRC_TXCSR, @@ -765,6 +769,7 @@ static void musb_ep_program(struct musb *pThis, u8 bEnd, musb_writeb(pBase, MGC_BUSCTL_OFFSET(bEnd, MGC_O_HDRC_TXHUBPORT), qh->h_port_reg); +/* FIXME if !bEnd, do the same for RX ... */ } else musb_writeb(pBase, MGC_O_HDRC_FADDR, qh->addr_reg); @@ -884,6 +889,8 @@ static void musb_ep_program(struct musb *pThis, u8 bEnd, } #endif if (wLoadCount) { + /* ASSERT: TXCSR_DMAENAB was already cleared */ + /* PIO to load FIFO */ qh->segsize = wLoadCount; musb_write_fifo(pEnd, wLoadCount, pBuffer); @@ -1223,13 +1230,15 @@ void musb_host_tx(struct musb *pThis, u8 bEnd) /* check for errors */ if (wTxCsrVal & MGC_M_TXCSR_H_RXSTALL) { + /* dma was disabled, fifo flushed */ DBG(3, "TX end %d stall\n", bEnd); /* stall; record URB status */ status = -EPIPE; } else if (wTxCsrVal & MGC_M_TXCSR_H_ERROR) { - DBG(3, "TX data error on ep=%d\n", bEnd); + /* (NON-ISO) dma was disabled, fifo flushed */ + DBG(3, "TX 3strikes on ep=%d\n", bEnd); status = -ETIMEDOUT; @@ -1260,6 +1269,8 @@ void musb_host_tx(struct musb *pThis, u8 bEnd) * 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 @@ -1267,10 +1278,10 @@ void musb_host_tx(struct musb *pThis, u8 bEnd) | MGC_M_TXCSR_H_RXSTALL | MGC_M_TXCSR_H_NAKTIMEOUT ); - wTxCsrVal |= MGC_M_TXCSR_FLUSHFIFO; MGC_SelectEnd(pBase, bEnd); MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd, wTxCsrVal); + /* REVISIT may need to clear FLUSHFIFO ... */ MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd, wTxCsrVal); MGC_WriteCsr8(pBase, MGC_O_HDRC_TXINTERVAL, bEnd, 0); @@ -1977,6 +1988,8 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in) } 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 @@ -1984,8 +1997,8 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in) | MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_FIFONOTEMPTY ); - csr |= MGC_M_TXCSR_FLUSHFIFO; MGC_WriteCsr16(regs, MGC_O_HDRC_TXCSR, 0, csr); + /* REVISIT may need to clear FLUSHFIFO ... */ MGC_WriteCsr16(regs, MGC_O_HDRC_TXCSR, 0, csr); /* flush cpu writebuffer */ csr = MGC_ReadCsr16(regs, MGC_O_HDRC_TXCSR, hw_end); diff --git a/drivers/usb/musb/musbhdrc.h b/drivers/usb/musb/musbhdrc.h index 188a7f07541..59fbbd7d486 100644 --- a/drivers/usb/musb/musbhdrc.h +++ b/drivers/usb/musb/musbhdrc.h @@ -71,8 +71,6 @@ /* Additional Control Registers */ #define MGC_O_HDRC_DEVCTL 0x60 /* 8 bit */ -// vctrl/vstatus: optional vendor utmi+phy register at 0x68 -#define MGC_O_HDRC_HWVERS 0x6C /* 8 bit */ /* These are always controlled through the INDEX register */ #define MGC_O_HDRC_TXFIFOSZ 0x62 /* 8-bit (see masks) */ @@ -80,6 +78,17 @@ #define MGC_O_HDRC_TXFIFOADD 0x64 /* 16-bit offset shifted right 3 */ #define MGC_O_HDRC_RXFIFOADD 0x66 /* 16-bit offset shifted right 3 */ +// vctrl/vstatus: optional vendor utmi+phy register at 0x68 +#define MGC_O_HDRC_HWVERS 0x6C /* 8 bit */ + +#define MGC_O_HDRC_EPINFO 0x78 /* 8 bit */ +#define MGC_O_HDRC_RAMINFO 0x79 /* 8 bit */ +#define MGC_O_HDRC_LINKINFO 0x7a /* 8 bit */ +#define MGC_O_HDRC_VPLEN 0x7b /* 8 bit */ +#define MGC_O_HDRC_HS_EOF1 0x7c /* 8 bit */ +#define MGC_O_HDRC_FS_EOF1 0x7d /* 8 bit */ +#define MGC_O_HDRC_LS_EOF1 0x7e /* 8 bit */ + /* offsets to endpoint registers */ #define MGC_O_HDRC_TXMAXP 0x00 #define MGC_O_HDRC_TXCSR 0x02 @@ -112,7 +121,7 @@ #include "tusb6010.h" /* needed "only" for TUSB_EP0_CONF */ #endif -/* "bus control" registers */ +/* "bus control"/target registers, for host side multipoint (external hubs) */ #define MGC_O_HDRC_TXFUNCADDR 0x00 #define MGC_O_HDRC_TXHUBADDR 0x02 #define MGC_O_HDRC_TXHUBPORT 0x03 @@ -149,7 +158,6 @@ #define MGC_M_INTR_DISCONNECT 0x20 #define MGC_M_INTR_SESSREQ 0x40 #define MGC_M_INTR_VBUSERROR 0x80 /* FOR SESSION END */ -#define MGC_M_INTR_EP0 0x01 /* FOR EP0 INTERRUPT */ /* DEVCTL */ #define MGC_M_DEVCTL_BDEVICE 0x80 @@ -191,6 +199,7 @@ #define MGC_M_CSR0_P_SENTSTALL 0x0004 /* CSR0 in Host mode */ +#define MGC_M_CSR0_H_DIS_PING 0x0800 #define MGC_M_CSR0_H_WR_DATATOGGLE 0x0400 /* set to allow setting: */ #define MGC_M_CSR0_H_DATATOGGLE 0x0200 /* data toggle control */ #define MGC_M_CSR0_H_NAKTIMEOUT 0x0080 @@ -214,9 +223,9 @@ #define MGC_TYPE_SPEED_HIGH 1 #define MGC_TYPE_SPEED_FULL 2 #define MGC_TYPE_SPEED_LOW 3 -#define MGC_M_TYPE_PROTO 0x30 +#define MGC_M_TYPE_PROTO 0x30 /* implicitly zero for ep0 */ #define MGC_S_TYPE_PROTO 4 -#define MGC_M_TYPE_REMOTE_END 0xf +#define MGC_M_TYPE_REMOTE_END 0xf /* implicitly zero for ep0 */ /* CONFIGDATA */ @@ -271,6 +280,7 @@ #define MGC_M_RXCSR_AUTOCLEAR 0x8000 #define MGC_M_RXCSR_DMAENAB 0x2000 #define MGC_M_RXCSR_DISNYET 0x1000 +#define MGC_M_RXCSR_PID_ERR 0x1000 #define MGC_M_RXCSR_DMAMODE 0x0800 #define MGC_M_RXCSR_INCOMPRX 0x0100 #define MGC_M_RXCSR_CLRDATATOG 0x0080 diff --git a/drivers/usb/musb/plat_uds.c b/drivers/usb/musb/plat_uds.c index 9ba7b230ca5..77fd3a31b17 100644 --- a/drivers/usb/musb/plat_uds.c +++ b/drivers/usb/musb/plat_uds.c @@ -387,7 +387,10 @@ static irqreturn_t musb_stage0_irq(struct musb * pThis, u8 bIntrUSB, if (devctl & MGC_M_DEVCTL_HM) { #ifdef CONFIG_USB_MUSB_HDRC_HCD - /* REVISIT: this is where SRP kicks in, yes? */ + /* REVISIT: this is where SRP kicks in, yes? + * host responsibility should be to CLEAR the + * resume signaling after 50 msec ... + */ MUSB_HST_MODE(pThis); /* unnecessary */ power &= ~MGC_M_POWER_SUSPENDM; musb_writeb(pBase, MGC_O_HDRC_POWER, diff --git a/drivers/usb/musb/virthub.c b/drivers/usb/musb/virthub.c index 0aa87bb3473..b3300705dc7 100644 --- a/drivers/usb/musb/virthub.c +++ b/drivers/usb/musb/virthub.c @@ -60,7 +60,6 @@ static void musb_port_suspend(struct musb *musb, u8 bSuspend) musb->port1_status |= USB_PORT_STAT_SUSPEND; } else if (power & MGC_M_POWER_SUSPENDM) { DBG(3, "Root port resumed\n"); - power &= ~(MGC_M_POWER_SUSPENDM | MGC_M_POWER_RESUME); musb_writeb(pBase, MGC_O_HDRC_POWER, power | MGC_M_POWER_RESUME); -- 2.41.1