optimise musb driver

This commit is contained in:
sakumisu
2022-03-26 13:42:25 +08:00
parent 9ba35770bc
commit 22f7322ed9
2 changed files with 130 additions and 58 deletions

View File

@@ -441,16 +441,14 @@ int usbd_ep_write(const uint8_t ep, const uint8_t *data, uint32_t data_len, uint
uint8_t old_ep_idx; uint8_t old_ep_idx;
old_ep_idx = USBC_GetActiveEp(); old_ep_idx = USBC_GetActiveEp();
USBC_SelectActiveEp(ep_idx);
if (!data && data_len) { if (!data && data_len) {
ret = -1; ret = -1;
goto _RET; goto _RET;
} }
if (ep_idx == 0x00) { if (ep_idx == 0x00) {
USBC_SelectActiveEp(ep_idx);
while (HWREGB(USB_TXCSRLx_BASE) & USB_CSRL0_TXRDY) { while (HWREGB(USB_TXCSRLx_BASE) & USB_CSRL0_TXRDY) {
USBC_SelectActiveEp(ep_idx);
if (HWREGB(USB_TXCSRLx_BASE) & USB_CSRL0_ERROR) { if (HWREGB(USB_TXCSRLx_BASE) & USB_CSRL0_ERROR) {
ret = -2; ret = -2;
goto _RET; goto _RET;
@@ -461,9 +459,7 @@ int usbd_ep_write(const uint8_t ep, const uint8_t *data, uint32_t data_len, uint
} }
} }
} else { } else {
USBC_SelectActiveEp(ep_idx);
while (HWREGB(USB_TXCSRLx_BASE) & USB_TXCSRL1_TXRDY) { while (HWREGB(USB_TXCSRLx_BASE) & USB_TXCSRL1_TXRDY) {
USBC_SelectActiveEp(ep_idx);
if ((HWREGB(USB_TXCSRLx_BASE) & USB_TXCSRL1_ERROR) || (HWREGB(USB_TXCSRLx_BASE) & USB_TXCSRL1_UNDRN)) { if ((HWREGB(USB_TXCSRLx_BASE) & USB_TXCSRL1_ERROR) || (HWREGB(USB_TXCSRLx_BASE) & USB_TXCSRL1_UNDRN)) {
ret = -2; ret = -2;
goto _RET; goto _RET;
@@ -489,7 +485,6 @@ int usbd_ep_write(const uint8_t ep, const uint8_t *data, uint32_t data_len, uint
usb_musb_write_packet(ep_idx, (uint8_t *)data, data_len); usb_musb_write_packet(ep_idx, (uint8_t *)data, data_len);
if (ep_idx != 0) { if (ep_idx != 0) {
USBC_SelectActiveEp(ep_idx);
HWREGB(USB_TXCSRLx_BASE) = USB_TXCSRL1_TXRDY; HWREGB(USB_TXCSRLx_BASE) = USB_TXCSRL1_TXRDY;
} }
if (ret_bytes) { if (ret_bytes) {
@@ -509,13 +504,12 @@ int usbd_ep_read(const uint8_t ep, uint8_t *data, uint32_t max_data_len, uint32_
uint8_t old_ep_idx; uint8_t old_ep_idx;
old_ep_idx = USBC_GetActiveEp(); old_ep_idx = USBC_GetActiveEp();
USBC_SelectActiveEp(ep_idx);
if (!data && max_data_len) { if (!data && max_data_len) {
ret = -1; ret = -1;
goto _RET; goto _RET;
} }
USBC_SelectActiveEp(ep_idx);
if (!max_data_len) { if (!max_data_len) {
if (ep_idx != 0x00) { if (ep_idx != 0x00) {
HWREGB(USB_RXCSRLx_BASE) &= ~(USB_RXCSRL1_RXRDY); HWREGB(USB_RXCSRLx_BASE) &= ~(USB_RXCSRL1_RXRDY);

View File

@@ -107,7 +107,6 @@ struct usb_musb_chan {
uint8_t interval; /* Polling interval */ uint8_t interval; /* Polling interval */
uint8_t *buffer; uint8_t *buffer;
volatile uint32_t buflen; volatile uint32_t buflen;
volatile uint32_t once_outlen;
volatile uint16_t xfrd; /* Bytes transferred (at end of transfer) */ volatile uint16_t xfrd; /* Bytes transferred (at end of transfer) */
volatile int result; /* The result of the transfer */ volatile int result; /* The result of the transfer */
volatile bool waiter; /* True: Thread is waiting for a channel event */ volatile bool waiter; /* True: Thread is waiting for a channel event */
@@ -126,6 +125,7 @@ struct usb_musb_priv {
} g_usbhost; } g_usbhost;
volatile uint8_t usb_ep0_state = USB_EP0_STATE_SETUP; volatile uint8_t usb_ep0_state = USB_EP0_STATE_SETUP;
volatile uint8_t ep0_outlen = 0;
/* get current active ep */ /* get current active ep */
static uint8_t USBC_GetActiveEp(void) static uint8_t USBC_GetActiveEp(void)
@@ -257,7 +257,7 @@ static int usb_musb_chan_alloc(void)
/* Search the table of channels */ /* Search the table of channels */
for (chidx = 2; chidx < CONFIG_USBHOST_PIPE_NUM; chidx++) { for (chidx = 1; chidx < CONFIG_USBHOST_PIPE_NUM; chidx++) {
/* Is this channel available? */ /* Is this channel available? */
if (!g_usbhost.chan[chidx].inuse) { if (!g_usbhost.chan[chidx].inuse) {
/* Yes... make it "in use" and return the index */ /* Yes... make it "in use" and return the index */
@@ -399,7 +399,7 @@ static int usb_musb_chan_wait(struct usb_musb_chan *chan, uint32_t timeout)
} }
} }
/* The transfer is complete re-enable interrupts and return the result */ /* The transfer is complete and return the result */
ret = chan->result; ret = chan->result;
if (ret < 0) { if (ret < 0) {
@@ -491,6 +491,7 @@ int usb_hc_init(void)
USB->TXIE = USB_TXIE_EP0; USB->TXIE = USB_TXIE_EP0;
USB->RXIE = 0; USB->RXIE = 0;
USB->POWER |= USB_POWER_HSENAB;
USB->DEVCTL |= USB_DEVCTL_SESSION; USB->DEVCTL |= USB_DEVCTL_SESSION;
#ifdef USB_MUSB_SUNXI #ifdef USB_MUSB_SUNXI
@@ -539,8 +540,8 @@ int usbh_ep0_reconfigure(usbh_epinfo_t ep, uint8_t dev_addr, uint8_t ep_mps, uin
return ret; return ret;
} }
USBC_SelectActiveEp(ep0); USBC_SelectActiveEp(0);
HWREGB(USB_TXADDR_BASE(ep0)) = dev_addr; HWREGB(USB_TXADDR_BASE(0)) = dev_addr;
if (speed == USB_SPEED_HIGH) { if (speed == USB_SPEED_HIGH) {
USB->TYPE0 = USB_TYPE0_SPEED_HIGH; USB->TYPE0 = USB_TYPE0_SPEED_HIGH;
@@ -550,7 +551,6 @@ int usbh_ep0_reconfigure(usbh_epinfo_t ep, uint8_t dev_addr, uint8_t ep_mps, uin
USB->TYPE0 = USB_TYPE0_SPEED_LOW; USB->TYPE0 = USB_TYPE0_SPEED_LOW;
} }
chan = &g_usbhost.chan[ep0];
chan->mps = ep_mps; chan->mps = ep_mps;
usb_osal_mutex_give(chan->exclsem); usb_osal_mutex_give(chan->exclsem);
@@ -702,7 +702,7 @@ int usbh_control_transfer(usbh_epinfo_t ep, struct usb_setup_packet *setup, uint
usb_musb_chan_waitsetup(chan); usb_musb_chan_waitsetup(chan);
usb_musb_write_packet(0, (uint8_t *)setup, 8); usb_musb_write_packet(0, (uint8_t *)setup, 8);
chan->once_outlen = 8; ep0_outlen = 8;
if (setup->wLength && buffer) { if (setup->wLength && buffer) {
if (setup->bmRequestType & 0x80) { if (setup->bmRequestType & 0x80) {
usb_ep0_state = USB_EP0_STATE_IN_DATA; usb_ep0_state = USB_EP0_STATE_IN_DATA;
@@ -756,12 +756,9 @@ int usbh_ep_bulk_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, ui
buflen = chan->mps; buflen = chan->mps;
} }
usb_musb_write_packet(chidx, (uint8_t *)buffer, buflen); usb_musb_write_packet(chidx, chan->buffer, buflen);
USBC_SelectActiveEp(chidx); USBC_SelectActiveEp(chidx);
HWREGB(USB_TXCSRLx_BASE) = USB_TXCSRL1_TXRDY; HWREGB(USB_TXCSRLx_BASE) = USB_TXCSRL1_TXRDY;
chan->buffer += buflen;
chan->buflen -= buflen;
chan->xfrd += buflen;
} }
ret = usb_musb_chan_wait(chan, timeout); ret = usb_musb_chan_wait(chan, timeout);
if (ret < 0) { if (ret < 0) {
@@ -771,6 +768,7 @@ int usbh_ep_bulk_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, ui
usb_osal_mutex_give(chan->exclsem); usb_osal_mutex_give(chan->exclsem);
return ret; return ret;
errout_with_mutex: errout_with_mutex:
chan->waiter = false;
usb_osal_mutex_give(chan->exclsem); usb_osal_mutex_give(chan->exclsem);
return ret; return ret;
} }
@@ -801,12 +799,9 @@ int usbh_ep_intr_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, ui
buflen = chan->mps; buflen = chan->mps;
} }
usb_musb_write_packet(chidx, (uint8_t *)buffer, buflen); usb_musb_write_packet(chidx, chan->buffer, buflen);
USBC_SelectActiveEp(chidx); USBC_SelectActiveEp(chidx);
HWREGB(USB_TXCSRLx_BASE) = USB_TXCSRL1_TXRDY; HWREGB(USB_TXCSRLx_BASE) = USB_TXCSRL1_TXRDY;
chan->buffer += buflen;
chan->buflen -= buflen;
chan->xfrd += buflen;
} }
ret = usb_musb_chan_wait(chan, timeout); ret = usb_musb_chan_wait(chan, timeout);
if (ret < 0) { if (ret < 0) {
@@ -816,6 +811,7 @@ int usbh_ep_intr_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, ui
usb_osal_mutex_give(chan->exclsem); usb_osal_mutex_give(chan->exclsem);
return ret; return ret;
errout_with_mutex: errout_with_mutex:
chan->waiter = false;
usb_osal_mutex_give(chan->exclsem); usb_osal_mutex_give(chan->exclsem);
return ret; return ret;
} }
@@ -832,6 +828,25 @@ int usbh_ep_bulk_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t bufl
return ret; return ret;
} }
usb_musb_chan_asynchsetup(chan, callback, arg);
if (chan->in) {
chan->buffer = buffer;
chan->buflen = buflen;
USBC_SelectActiveEp(chidx);
HWREGB(USB_RXCSRLx_BASE) = USB_RXCSRL1_REQPKT;
} else {
chan->buffer = buffer;
chan->buflen = buflen;
if (buflen > chan->mps) {
buflen = chan->mps;
}
usb_musb_write_packet(chidx, chan->buffer, buflen);
USBC_SelectActiveEp(chidx);
HWREGB(USB_TXCSRLx_BASE) = USB_TXCSRL1_TXRDY;
}
usb_osal_mutex_give(chan->exclsem); usb_osal_mutex_give(chan->exclsem);
return ret; return ret;
} }
@@ -848,31 +863,88 @@ int usbh_ep_intr_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t bufl
return ret; return ret;
} }
usb_musb_chan_asynchsetup(chan, callback, arg);
if (chan->in) {
chan->buffer = buffer;
chan->buflen = buflen;
USBC_SelectActiveEp(chidx);
HWREGB(USB_RXCSRLx_BASE) = USB_RXCSRL1_REQPKT;
} else {
chan->buffer = buffer;
chan->buflen = buflen;
if (buflen > chan->mps) {
buflen = chan->mps;
}
usb_musb_write_packet(chidx, chan->buffer, buflen);
USBC_SelectActiveEp(chidx);
HWREGB(USB_TXCSRLx_BASE) = USB_TXCSRL1_TXRDY;
}
usb_osal_mutex_give(chan->exclsem); usb_osal_mutex_give(chan->exclsem);
return ret; return ret;
} }
int usb_ep_cancel(usbh_epinfo_t ep) int usb_ep_cancel(usbh_epinfo_t ep)
{ {
int ret;
uint32_t flags;
struct usb_musb_chan *chan;
uint8_t chidx = (uint8_t)ep;
#ifdef CONFIG_USBHOST_ASYNCH
usbh_asynch_callback_t callback;
void *arg;
#endif
chan = &g_usbhost.chan[chidx];
flags = usb_osal_enter_critical_section();
chan->result = -ESHUTDOWN;
#ifdef CONFIG_USBHOST_ASYNCH
/* Extract the callback information */
callback = chan->callback;
arg = chan->arg;
chan->callback = NULL;
chan->arg = NULL;
chan->xfrd = 0;
#endif
usb_osal_leave_critical_section(flags);
/* Is there a thread waiting for this transfer to complete? */
if (chan->waiter) {
/* Wake'em up! */
chan->waiter = false;
usb_osal_sem_give(chan->waitsem);
}
#ifdef CONFIG_USBHOST_ASYNCH
/* No.. is an asynchronous callback expected when the transfer completes? */
else if (callback) {
/* Then perform the callback */
callback(arg, -ESHUTDOWN);
}
#endif
return 0; return 0;
} }
void handle_ep0(void) void handle_ep0(void)
{ {
uint8_t ep0_status = USB->CSRL0; uint8_t ep0_status = USB->CSRL0;
struct usb_musb_chan *chan;
chan = &g_usbhost.chan[0];
if (ep0_status & USB_HOST_EP0_ERROR) { if (ep0_status & USB_HOST_EP0_ERROR) {
usb_musb_ep_status_clear(0, USB_HOST_EP0_ERROR); usb_musb_ep_status_clear(0, USB_HOST_EP0_ERROR);
usb_musb_fifo_flush(0); usb_musb_fifo_flush(0);
usb_ep0_state = USB_EP0_STATE_SETUP; usb_ep0_state = USB_EP0_STATE_SETUP;
g_usbhost.chan[0].result = -EIO; chan->result = -EIO;
goto chan_wait; goto chan_wait;
} }
if (ep0_status & USB_HOST_EP0_RX_STALL) { if (ep0_status & USB_HOST_EP0_RX_STALL) {
usb_musb_ep_status_clear(0, ep0_status & USB_HOST_IN_STATUS); usb_musb_ep_status_clear(0, ep0_status & USB_HOST_IN_STATUS);
usb_ep0_state = USB_EP0_STATE_SETUP; usb_ep0_state = USB_EP0_STATE_SETUP;
g_usbhost.chan[0].result = -EPERM; chan->result = -EPERM;
goto chan_wait; goto chan_wait;
} }
switch (usb_ep0_state) { switch (usb_ep0_state) {
@@ -881,61 +953,65 @@ void handle_ep0(void)
case USB_EP0_STATE_IN_DATA: case USB_EP0_STATE_IN_DATA:
USB->CSRL0 = USB_RXCSRL1_REQPKT; USB->CSRL0 = USB_RXCSRL1_REQPKT;
usb_ep0_state = USB_EP0_STATE_IN_DATA_C; usb_ep0_state = USB_EP0_STATE_IN_DATA_C;
g_usbhost.chan[0].xfrd += g_usbhost.chan[0].once_outlen; chan->xfrd += 8;
break; break;
case USB_EP0_STATE_IN_DATA_C: case USB_EP0_STATE_IN_DATA_C:
if (USB->CSRL0 & USB_CSRL0_RXRDY) { if (USB->CSRL0 & USB_CSRL0_RXRDY) {
uint32_t size = g_usbhost.chan[0].buflen; uint32_t size = chan->buflen;
if (size > g_usbhost.chan[0].mps) { if (size > chan->mps) {
size = g_usbhost.chan[0].mps; size = chan->mps;
} }
size = MIN(size, USB->COUNT0); size = MIN(size, USB->COUNT0);
usb_musb_read_packet(0, g_usbhost.chan[0].buffer, size); usb_musb_read_packet(0, chan->buffer, size);
USB->CSRL0 &= ~USB_CSRL0_RXRDY; USB->CSRL0 &= ~USB_CSRL0_RXRDY;
g_usbhost.chan[0].buffer += size; chan->buffer += size;
g_usbhost.chan[0].buflen -= size; chan->buflen -= size;
g_usbhost.chan[0].xfrd += size; chan->xfrd += size;
if ((size < g_usbhost.chan[0].mps) || (g_usbhost.chan[0].buflen == 0)) { if ((size < chan->mps) || (chan->buflen == 0)) {
usb_ep0_state = USB_EP0_STATE_IN_STATUS_C; usb_ep0_state = USB_EP0_STATE_OUT_STATUS;
USB->CSRL0 = USB_CSRL0_TXRDY | USB_CSRL0_STATUS; USB->CSRL0 = USB_CSRL0_TXRDY | USB_CSRL0_STATUS;
} else { } else {
USB->CSRL0 = USB_RXCSRL1_REQPKT; USB->CSRL0 = USB_RXCSRL1_REQPKT;
} }
} }
break; break;
case USB_EP0_STATE_OUT_STATUS:
usb_ep0_state = USB_EP0_STATE_SETUP;
chan->result = 0;
goto chan_wait;
case USB_EP0_STATE_IN_STATUS_C: case USB_EP0_STATE_IN_STATUS_C:
if (ep0_status & (USB_HOST_EP0_RXPKTRDY | USB_HOST_EP0_STATUS)) { if (ep0_status & (USB_HOST_EP0_RXPKTRDY | USB_HOST_EP0_STATUS)) {
usb_musb_ep_status_clear(0, (USB_HOST_EP0_RXPKTRDY | USB_HOST_EP0_STATUS)); usb_musb_ep_status_clear(0, (USB_HOST_EP0_RXPKTRDY | USB_HOST_EP0_STATUS));
} }
usb_ep0_state = USB_EP0_STATE_SETUP; usb_ep0_state = USB_EP0_STATE_SETUP;
g_usbhost.chan[0].result = 0; chan->result = 0;
goto chan_wait; goto chan_wait;
break; break;
case USB_EP0_STATE_IN_STATUS: case USB_EP0_STATE_IN_STATUS:
USB->CSRL0 = USB_CSRL0_REQPKT | USB_CSRL0_STATUS; USB->CSRL0 = USB_CSRL0_REQPKT | USB_CSRL0_STATUS;
usb_ep0_state = USB_EP0_STATE_IN_STATUS_C; usb_ep0_state = USB_EP0_STATE_IN_STATUS_C;
g_usbhost.chan[0].xfrd += g_usbhost.chan[0].once_outlen; chan->xfrd += 8;
break; break;
case USB_EP0_STATE_OUT_DATA: { case USB_EP0_STATE_OUT_DATA: {
g_usbhost.chan[0].xfrd += g_usbhost.chan[0].once_outlen; uint32_t size = chan->buflen;
if (size > chan->mps) {
uint32_t size = g_usbhost.chan[0].buflen; size = chan->mps;
if (size > g_usbhost.chan[0].mps) {
size = g_usbhost.chan[0].mps;
} }
usb_musb_write_packet(0, g_usbhost.chan[0].buffer, size); chan->xfrd += ep0_outlen;
g_usbhost.chan[0].buffer += size; usb_musb_write_packet(0, chan->buffer, size);
g_usbhost.chan[0].buflen -= size;
g_usbhost.chan[0].once_outlen = size; chan->buffer += size;
if (size == g_usbhost.chan[0].mps) { chan->buflen -= size;
ep0_outlen = size;
if (size == chan->mps) {
USB->CSRL0 = USB_CSRL0_TXRDY; USB->CSRL0 = USB_CSRL0_TXRDY;
} else { } else {
USB->CSRL0 = USB_CSRL0_TXRDY; USB->CSRL0 = USB_CSRL0_TXRDY;
@@ -947,7 +1023,7 @@ void handle_ep0(void)
} }
return; return;
chan_wait: chan_wait:
usb_musb_chan_wakeup(&g_usbhost.chan[0]); usb_musb_chan_wakeup(chan);
} }
void USBH_IRQHandler(void) void USBH_IRQHandler(void)
{ {
@@ -1025,18 +1101,20 @@ void USBH_IRQHandler(void)
} else { } else {
uint32_t size = chan->buflen; uint32_t size = chan->buflen;
if (size) { if (size > chan->mps) {
if (size > chan->mps) { size = chan->mps;
size = chan->mps; }
}
usb_musb_write_packet(chidx, chan->buffer, size); chan->buffer += size;
HWREGB(USB_TXCSRLx_BASE) = USB_TXCSRL1_TXRDY; chan->buflen -= size;
chan->buffer += size; chan->xfrd += size;
chan->buflen -= size;
chan->xfrd += size; if (chan->buflen == 0) {
} else {
chan->result = 0; chan->result = 0;
usb_musb_chan_wakeup(chan); usb_musb_chan_wakeup(chan);
} else {
usb_musb_write_packet(chidx, chan->buffer, size);
HWREGB(USB_TXCSRLx_BASE) = USB_TXCSRL1_TXRDY;
} }
} }
} }