Commit e5bb0284 authored by David Brownell's avatar David Brownell Committed by Tony Lindgren

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: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
parent 044fe6d5
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
......@@ -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
......
......@@ -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,
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment