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);
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
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 */
}
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;
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;
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);
/* 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);
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);
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;
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
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;
{
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
}
/* 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);
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
| 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;
/* 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,
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);
}
#endif
if (wLoadCount) {
+ /* ASSERT: TXCSR_DMAENAB was already cleared */
+
/* PIO to load FIFO */
qh->segsize = wLoadCount;
musb_write_fifo(pEnd, wLoadCount, pBuffer);
/* 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;
* 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_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);
} 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_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);
/* 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) */
#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
#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
#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
#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
#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 */
#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
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,
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);