diff options
author | Riku Voipio <riku.voipio@nokia.com> | 2009-12-03 15:56:08 +0200 |
---|---|---|
committer | Aurelien Jarno <aurelien@aurel32.net> | 2009-12-18 23:23:56 +0100 |
commit | 384dce1eded17cb0413b473d0d0bee993f254045 (patch) | |
tree | 232bfae4da5d7d8f5424573ac17e7341f43b3ac4 /hw | |
parent | 109ac32fb510c30ec64557179fd491435a0f1598 (diff) | |
download | hqemu-384dce1eded17cb0413b473d0d0bee993f254045.zip hqemu-384dce1eded17cb0413b473d0d0bee993f254045.tar.gz |
usb-musb: convert fifo to 8bit and add more registers
Convert musb fifo to 8bit to allow 8/16/32bit access
MUSB allows reading and writing to the fifo in 32/16/8 bit
width. The Linux kernel does this sometimes, most usually at
the end of writing the packet to allow packet to end at a
odd bytecount.
Convert the fifo to 8bit allows removing lots of shifts
which shows that the fifo is more natural as 8bit.
While at it, add multiple missing register definitions and
and cleanup debug prints.
Signed-off-by: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/usb-musb.c | 164 |
1 files changed, 107 insertions, 57 deletions
diff --git a/hw/usb-musb.c b/hw/usb-musb.c index 09ec5a1..7f15842 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -24,6 +24,7 @@ #include "qemu-timer.h" #include "usb.h" #include "irq.h" +#include "hw.h" /* Common USB registers */ #define MUSB_HDRC_FADDR 0x00 /* 8-bit */ @@ -248,6 +249,16 @@ #define MGC_M_ULPI_REGCTL_COMPLETE 0x02 #define MGC_M_ULPI_REGCTL_REG 0x01 +/* #define MUSB_DEBUG */ + +#ifdef MUSB_DEBUG +#define TRACE(fmt,...) fprintf(stderr, "%s@%d: " fmt "\n", __FUNCTION__, \ + __LINE__, ##__VA_ARGS__) +#else +#define TRACE(...) +#endif + + static void musb_attach(USBPort *port, USBDevice *dev); typedef struct { @@ -263,7 +274,7 @@ typedef struct { uint8_t fifosize; int timeout[2]; /* Always in microframes */ - uint32_t *buf[2]; + uint8_t *buf[2]; int fifolen[2]; int fifostart[2]; int fifoaddr[2]; @@ -299,7 +310,7 @@ struct MUSBState { int setup_len; int session; - uint32_t buf[0x2000]; + uint8_t buf[0x8000]; /* Duplicating the world since 2008!... probably we should have 32 * logical, single endpoints instead. */ @@ -774,7 +785,7 @@ static void musb_tx_rdy(MUSBState *s, int epnum) MUSBEndPoint *ep = s->ep + epnum; int pid; int total, valid = 0; - + TRACE("start %d, len %d", ep->fifostart[0], ep->fifolen[0] ); ep->fifostart[0] += ep->fifolen[0]; ep->fifolen[0] = 0; @@ -789,18 +800,18 @@ static void musb_tx_rdy(MUSBState *s, int epnum) } /* If the packet is not fully ready yet, wait for a next segment. */ - if (epnum && (ep->fifostart[0] << 2) < total) + if (epnum && (ep->fifostart[0]) < total) return; if (!valid) - total = ep->fifostart[0] << 2; + total = ep->fifostart[0]; pid = USB_TOKEN_OUT; if (!epnum && (ep->csr[0] & MGC_M_CSR0_H_SETUPPKT)) { pid = USB_TOKEN_SETUP; - if (total != 8) - printf("%s: illegal SETUPPKT length of %i bytes\n", - __FUNCTION__, total); + if (total != 8) { + TRACE("illegal SETUPPKT length of %i bytes", total); + } /* Controller should retry SETUP packets three times on errors * but it doesn't make sense for us to do that. */ } @@ -817,12 +828,13 @@ static void musb_rx_req(MUSBState *s, int epnum) /* If we already have a packet, which didn't fit into the * 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */ if (ep->packey[1].pid == USB_TOKEN_IN && ep->status[1] >= 0 && - (ep->fifostart[1] << 2) + ep->rxcount < + (ep->fifostart[1]) + ep->rxcount < ep->packey[1].len) { - ep->fifostart[1] += ep->rxcount >> 2; + TRACE("0x%08x, %d", ep->fifostart[1], ep->rxcount ); + ep->fifostart[1] += ep->rxcount; ep->fifolen[1] = 0; - ep->rxcount = MIN(ep->packey[0].len - (ep->fifostart[1] << 2), + ep->rxcount = MIN(ep->packey[0].len - (ep->fifostart[1]), ep->maxp[1]); ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT; @@ -872,6 +884,36 @@ static void musb_rx_req(MUSBState *s, int epnum) total, musb_rx_packet_complete, 1); } +static uint8_t musb_read_fifo(MUSBEndPoint *ep) +{ + uint8_t value; + if (ep->fifolen[1] >= 64) { + /* We have a FIFO underrun */ + TRACE("EP%d FIFO is now empty, stop reading", ep->epnum); + return 0x00000000; + } + /* In DMA mode clear RXPKTRDY and set REQPKT automatically + * (if AUTOREQ is set) */ + + ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL; + value=ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++]; + TRACE("EP%d 0x%02x, %d", ep->epnum, value, ep->fifolen[1] ); + return value; +} + +static void musb_write_fifo(MUSBEndPoint *ep, uint8_t value) +{ + TRACE("EP%d = %02x", ep->epnum, value); + if (ep->fifolen[0] >= 64) { + /* We have a FIFO overrun */ + TRACE("EP%d FIFO exceeded 64 bytes, stop feeding data", ep->epnum); + return; + } + + ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value; + ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY; +} + static void musb_ep_frame_cancel(MUSBEndPoint *ep, int dir) { if (ep->intv_timer[dir]) @@ -895,7 +937,7 @@ static uint8_t musb_busctl_readb(void *opaque, int ep, int addr) return s->ep[ep].hport[1]; default: - printf("%s: unknown register at %02x\n", __FUNCTION__, addr); + TRACE("unknown register 0x%02x", addr); return 0x00; }; } @@ -905,6 +947,12 @@ static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value) MUSBState *s = (MUSBState *) opaque; switch (addr) { + case MUSB_HDRC_TXFUNCADDR: + s->ep[ep].faddr[0] = value; + break; + case MUSB_HDRC_RXFUNCADDR: + s->ep[ep].faddr[1] = value; + break; case MUSB_HDRC_TXHUBADDR: s->ep[ep].haddr[0] = value; break; @@ -919,7 +967,8 @@ static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value) break; default: - printf("%s: unknown register at %02x\n", __FUNCTION__, addr); + TRACE("unknown register 0x%02x", addr); + break; }; } @@ -975,9 +1024,11 @@ static uint8_t musb_ep_readb(void *opaque, int ep, int addr) return 0x00; case MUSB_HDRC_FIFOSIZE: return ep ? s->ep[ep].fifosize : s->ep[ep].config; + case MUSB_HDRC_RXCOUNT: + return s->ep[ep].rxcount; default: - printf("%s: unknown register at %02x\n", __FUNCTION__, addr); + TRACE("unknown register 0x%02x", addr); return 0x00; }; } @@ -1004,13 +1055,12 @@ static void musb_ep_writeb(void *opaque, int ep, int addr, uint8_t value) case (MUSB_HDRC_FIFOSIZE & ~1): break; case MUSB_HDRC_FIFOSIZE: - printf("%s: somebody messes with fifosize (now %i bytes)\n", - __FUNCTION__, value); + TRACE("somebody messes with fifosize (now %i bytes)", value); s->ep[ep].fifosize = value; break; - default: - printf("%s: unknown register at %02x\n", __FUNCTION__, addr); + TRACE("unknown register 0x%02x", addr); + break; }; } @@ -1194,8 +1244,12 @@ static uint32_t musb_readb(void *opaque, target_phys_addr_t addr) ep = (addr >> 4) & 0xf; return musb_ep_readb(s, ep, addr & 0xf); + case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): + ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; + return musb_read_fifo(s->ep + ep); + default: - printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr); + TRACE("unknown register 0x%02x", (int) addr); return 0x00; }; } @@ -1276,8 +1330,14 @@ static void musb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) musb_ep_writeb(s, ep, addr & 0xf, value); break; + case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): + ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; + musb_write_fifo(s->ep + ep, value & 0xff); + break; + default: - printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr); + TRACE("unknown register 0x%02x", (int) addr); + break; }; } @@ -1326,6 +1386,10 @@ static uint32_t musb_readh(void *opaque, target_phys_addr_t addr) ep = (addr >> 4) & 0xf; return musb_ep_readh(s, ep, addr & 0xf); + case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): + ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; + return (musb_read_fifo(s->ep + ep) | musb_read_fifo(s->ep + ep) << 8); + default: return musb_readb(s, addr) | (musb_readb(s, addr | 1) << 8); }; @@ -1353,12 +1417,12 @@ static void musb_writeh(void *opaque, target_phys_addr_t addr, uint32_t value) case MUSB_HDRC_TXFIFOADDR: s->ep[s->idx].fifoaddr[0] = value; s->ep[s->idx].buf[0] = - s->buf + ((value << 1) & (sizeof(s->buf) / 4 - 1)); + s->buf + ((value << 3) & 0x7ff ); break; case MUSB_HDRC_RXFIFOADDR: s->ep[s->idx].fifoaddr[1] = value; s->ep[s->idx].buf[1] = - s->buf + ((value << 1) & (sizeof(s->buf) / 4 - 1)); + s->buf + ((value << 3) & 0x7ff); break; case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): @@ -1375,6 +1439,12 @@ static void musb_writeh(void *opaque, target_phys_addr_t addr, uint32_t value) musb_ep_writeh(s, ep, addr & 0xf, value); break; + case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): + ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; + musb_write_fifo(s->ep + ep, value & 0xff); + musb_write_fifo(s->ep + ep, (value >> 8) & 0xff); + break; + default: musb_writeb(s, addr, value & 0xff); musb_writeb(s, addr | 1, value >> 8); @@ -1384,28 +1454,17 @@ static void musb_writeh(void *opaque, target_phys_addr_t addr, uint32_t value) static uint32_t musb_readw(void *opaque, target_phys_addr_t addr) { MUSBState *s = (MUSBState *) opaque; - MUSBEndPoint *ep; - int epnum; + int ep; switch (addr) { case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): - epnum = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; - ep = s->ep + epnum; - - if (ep->fifolen[1] >= 16) { - /* We have a FIFO underrun */ - printf("%s: EP%i FIFO is now empty, stop reading\n", - __FUNCTION__, epnum); - return 0x00000000; - } - /* In DMA mode clear RXPKTRDY and set REQPKT automatically - * (if AUTOREQ is set) */ - - ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL; - return ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++]; - + ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; + return ( musb_read_fifo(s->ep + ep) | + musb_read_fifo(s->ep + ep) << 8 | + musb_read_fifo(s->ep + ep) << 16 | + musb_read_fifo(s->ep + ep) << 24 ); default: - printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr); + TRACE("unknown register 0x%02x", (int) addr); return 0x00000000; }; } @@ -1413,28 +1472,19 @@ static uint32_t musb_readw(void *opaque, target_phys_addr_t addr) static void musb_writew(void *opaque, target_phys_addr_t addr, uint32_t value) { MUSBState *s = (MUSBState *) opaque; - MUSBEndPoint *ep; - int epnum; + int ep; switch (addr) { case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): - epnum = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; - ep = s->ep + epnum; - - if (ep->fifolen[0] >= 16) { - /* We have a FIFO overrun */ - printf("%s: EP%i FIFO exceeded 64 bytes, stop feeding data\n", - __FUNCTION__, epnum); + ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; + musb_write_fifo(s->ep + ep, value & 0xff); + musb_write_fifo(s->ep + ep, (value >> 8 ) & 0xff); + musb_write_fifo(s->ep + ep, (value >> 16) & 0xff); + musb_write_fifo(s->ep + ep, (value >> 24) & 0xff); break; - } - - ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value; - if (epnum) - ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY; - break; - default: - printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr); + TRACE("unknown register 0x%02x", (int) addr); + break; }; } |