jz4760: Heavily rework USB driver to add working DMA support

* DMA Bulk IN (ie our TX) results in sequential transfers 33-68% faster.
 * DMA Bulk OUT (ie RX) is mostly stripped out due to complete brokenness.
 * Interrupt and control endpoints remain PIO-driven.

Other improvements:

1) Use consistent endpoint references (no magic numbers)
2) Greatly enhanced logging
3) DMA support can be compiled out completely
4) Setting lockswitch will disable all DMA operations at runtime
5) Much more robust error checking and recovery

Change-Id: I57b82e655e55ced0dfe289e379b0b61d8fe443b4
This commit is contained in:
Solomon Peachy 2020-09-14 20:36:24 -04:00
parent a66b908801
commit ec413f7692
4 changed files with 261 additions and 138 deletions

View file

@ -6992,8 +6992,12 @@ do { \
#define USB_OUTCSRH (USB_BASE + 0x17) /* EP1-15 OUT CSR MSB 8-bit */
#define USB_OUTCOUNT (USB_BASE + 0x18) /* EP1-15 OUT FIFO count 16-bit */
#define USB_CONFIGDATA (USB_BASE + 0x1f) /* Fixed config */
#define USB_FIFO_EP(n) (USB_BASE + (n)*4 + 0x20)
#define USB_HWVERS (USB_BASE + 0x6c)
#define USB_EPINFO (USB_BASE + 0x78) /* Endpoint information */
#define USB_RAMINFO (USB_BASE + 0x79) /* RAM information */
@ -7034,6 +7038,7 @@ do { \
#define USB_INCSRH_DMAREQENAB 0x10
#define USB_INCSRH_FRCDATATOG 0x08
#define USB_INCSRH_DMAREQMODE 0x04
#define USB_INCSR_INCOMPTX 0x80
#define USB_INCSR_CDT 0x40
#define USB_INCSR_SENTSTALL 0x20
#define USB_INCSR_SENDSTALL 0x10
@ -7077,6 +7082,10 @@ do { \
#define USB_CNTL_BURST_8 (2 << 9)
#define USB_CNTL_BURST_16 (3 << 9)
/* USB HW revision */
#define USB_HWVERS_MAJOR(x) ((x >> 10) & 0x1f)
#define USB_HWVERS_MINOR(x) (x & 0x3ff)
/* DMA interrupt bits */
#define USB_INTR_DMA_BULKIN 1
#define USB_INTR_DMA_BULKOUT 2
@ -7104,6 +7113,7 @@ do { \
#define REG_USB_OUTCSRH REG8(USB_OUTCSRH)
#define REG_USB_OUTCOUNT REG16(USB_OUTCOUNT)
#define REG_USB_CONFIGDATA REG8(USB_CONFIGDATA)
#define REG_USB_FIFO_EP(n) REG32(USB_FIFO_EP(n))
#define REG_USB_INTR REG8(USB_INTR)
@ -7111,6 +7121,8 @@ do { \
#define REG_USB_ADDR(n) REG32(USB_ADDR(n))
#define REG_USB_COUNT(n) REG32(USB_COUNT(n))
#define REG_USB_HWVERS REG16(USB_HWVERS)
#define REG_USB_EPINFO REG8(USB_EPINFO)
#define REG_USB_RAMINFO REG8(USB_RAMINFO)

View file

@ -83,6 +83,7 @@ static inline void restore_interrupt(int status)
#define UNCACHED_ADDRESS(addr) ((unsigned int)(addr) | 0xA0000000)
#define UNCACHED_ADDR(x) UNCACHED_ADDRESS((x))
#define PHYSADDR(x) ((x) & 0x1fffffff)
#define VIRTADDR(x) ((x) | 0xA0000000)
void system_enable_irq(unsigned int irq);
void udelay(unsigned int usec);

View file

@ -7,7 +7,8 @@
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2016 by Roman Stolyarov
* Copyright (C) 2016 Roman Stolyarov
* Copyright (C) 2020 Solomon Peachy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -20,7 +21,7 @@
****************************************************************************/
#include "config.h"
/*#define LOGF_ENABLE*/
//#define LOGF_ENABLE
#include "logf.h"
#include "system.h"
#include "usb_ch9.h"
@ -29,6 +30,8 @@
#include "cpu.h"
#include "thread.h"
#define USE_USB_DMA
#define PIN_USB_DET (32*4+19)
#define IRQ_USB_DET GPIO_IRQ(PIN_USB_DET)
#define GPIO_USB_DET GPIO147
@ -43,6 +46,13 @@
#define TOTAL_EP() (sizeof(endpoints)/sizeof(struct usb_endpoint))
#define EP_IS_IN(ep) (EP_NUMBER((ep))%2)
#define TXCSR_WZC_BITS (USB_INCSR_SENTSTALL | USB_INCSR_UNDERRUN | USB_INCSR_FFNOTEMPT | USB_INCSR_INCOMPTX)
/* NOTE: IN/OUT is from the HOST perspective. We're a peripheral, so:
IN = DEV->HOST, (ie we send)
OUT = HOST->DEV, (ie we recv)
*/
enum ep_type
{
ep_control,
@ -53,6 +63,16 @@ enum ep_type
struct usb_endpoint
{
const enum ep_type type;
const long fifo_addr;
unsigned short fifo_size;
bool allocated;
int use_dma; /* -1 = no, 0 = mode_0, 1 = mode_1 */
struct semaphore complete;
uint8_t config;
volatile void *buf;
volatile size_t length;
union
@ -60,24 +80,14 @@ struct usb_endpoint
volatile size_t sent;
volatile size_t received;
};
volatile bool busy;
const enum ep_type type;
const bool use_dma;
const long fifo_addr;
unsigned short fifo_size;
volatile bool wait;
struct semaphore complete;
volatile int rc;
bool allocated;
volatile bool busy;
volatile bool wait;
};
#define EP_INIT(_type, _fifo_addr, _fifo_size, _buf, _use_dma) \
#define EP_INIT(_type, _fifo_addr, _fifo_size, _buf) \
{ .type = (_type), .fifo_addr = (_fifo_addr), .fifo_size = (_fifo_size), \
.buf = (_buf), .use_dma = (_use_dma), \
.buf = (_buf), .use_dma = -1, \
.length = 0, .busy = false, .wait = false, .allocated = false }
static union
@ -91,12 +101,12 @@ static volatile bool ep0_data_requested = false;
static struct usb_endpoint endpoints[] =
{
EP_INIT(ep_control, USB_FIFO_EP(0), 64, NULL, false),
EP_INIT(ep_control, USB_FIFO_EP(0), 64, &ep0_rx.buf, false),
EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL, false),
EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL, false),
EP_INIT(ep_interrupt, USB_FIFO_EP(2), 512, NULL, false),
EP_INIT(ep_interrupt, USB_FIFO_EP(2), 512, NULL, false),
EP_INIT(ep_control, USB_FIFO_EP(0), 64, NULL),
EP_INIT(ep_control, USB_FIFO_EP(0), 64, &ep0_rx.buf),
EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL),
EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL),
EP_INIT(ep_interrupt, USB_FIFO_EP(2), 512, NULL),
EP_INIT(ep_interrupt, USB_FIFO_EP(2), 512, NULL),
};
static inline void select_endpoint(int ep)
@ -329,7 +339,8 @@ static void EP0_handler(void)
EP0_send();
}
static void EPIN_handler(unsigned int endpoint)
/* Does new work */
static void EPIN_send(unsigned int endpoint)
{
struct usb_endpoint* ep = &endpoints[endpoint*2];
unsigned int length, csr;
@ -338,45 +349,153 @@ static void EPIN_handler(unsigned int endpoint)
csr = REG_USB_INCSR;
logf("%s(%d): 0x%x", __func__, endpoint, csr);
if(!ep->busy)
{
if (!ep->busy) {
logf("Entered EPIN handler without work!");
return;
}
if(csr & USB_INCSR_SENTSTALL)
{
if (csr & USB_INCSR_INPKTRDY) {
logf("PKTRDY %d", endpoint);
return;
}
if (csr & USB_INCSR_SENTSTALL) {
logf("SENDSTALL %d", endpoint);
REG_USB_INCSR = csr & ~USB_INCSR_SENTSTALL;
return;
}
if(ep->use_dma)
return;
if(csr & USB_INCSR_FFNOTEMPT)
{
if (csr & USB_INCSR_FFNOTEMPT) {
logf("FIFO is not empty! 0x%x", csr);
return;
}
#ifdef USE_USB_DMA
if(ep->use_dma >= 0) {
logf("DMA busy(%x %x %x)", REG_USB_ADDR(USB_INTR_DMA_BULKIN), REG_USB_COUNT(USB_INTR_DMA_BULKIN),REG_USB_CNTL(USB_INTR_DMA_BULKIN));
return;
}
#endif
logf("EP%d: %d -> %d", endpoint, ep->sent, ep->length);
#ifdef USE_USB_DMA
/* Can we use DMA? */
if (ep->type == ep_bulk && ep->length && (!(((unsigned long)ep->buf + ep->sent) % 4)) && !button_hold()) {
if (ep->length >= ep->fifo_size)
ep->use_dma = 1;
else
ep->use_dma = 0;
} else {
ep->use_dma = -1;
}
if (ep->use_dma >= 0) {
commit_discard_dcache_range((void*)ep->buf + ep->sent, ep->length - ep->sent);
/* Set up DMA */
uint16_t dmacr = USB_CNTL_BURST_16 | USB_CNTL_EP(EP_NUMBER2(ep)) | USB_CNTL_ENA | USB_CNTL_INTR_EN | USB_CNTL_DIR_IN ;
if (ep->use_dma > 0)
dmacr |= USB_CNTL_MODE_1;
REG_USB_ADDR(USB_INTR_DMA_BULKIN) = PHYSADDR((unsigned long)ep->buf + ep->sent);
REG_USB_COUNT(USB_INTR_DMA_BULKIN) = ep->length - ep->sent;
REG_USB_CNTL(USB_INTR_DMA_BULKIN) = dmacr;
uint16_t csr = REG_USB_INCSR;
if (ep->use_dma == 0) {
csr &= ~((USB_INCSRH_AUTOSET | USB_INCSRH_DMAREQENAB) << 8);
REG_USB_INCSR = csr | TXCSR_WZC_BITS;
csr &= ~((USB_INCSRH_DMAREQMODE) << 8);
csr |= ((USB_INCSRH_DMAREQENAB | USB_INCSRH_MODE) << 8);
} else {
csr |= ((USB_INCSRH_DMAREQENAB | USB_INCSRH_MODE | USB_INCSRH_DMAREQMODE) << 8);
csr |= ((USB_INCSRH_AUTOSET) << 8);
}
csr &= ~USB_INCSR_UNDERRUN;
logf("DMA setup(%d: %x %x %x %x - %d)", EP_NUMBER2(ep), (unsigned int)PHYSADDR((unsigned long)ep->buf), ep->length, dmacr, csr, ep->use_dma);
REG_USB_INCSR = csr;
return;
}
#endif
/* Non-DMA code */
if(ep->sent == 0)
length = MIN(ep->length, ep->fifo_size);
else
length = MIN(EP_BUF_LEFT(ep), ep->fifo_size);
writeFIFO(ep, length);
REG_USB_INCSR = csr | USB_INCSR_INPKTRDY;
ep->sent += length;
csr &= ~USB_INCSR_UNDERRUN;
csr |= USB_INCSR_INPKTRDY;
logf("Non-DMA TX %x", csr);
REG_USB_INCSR = csr;
}
if(ep->sent >= ep->length)
{
static void EPIN_complete(unsigned int endpoint)
{
struct usb_endpoint* ep = &endpoints[endpoint*2];
uint16_t csr;
select_endpoint(endpoint);
csr = REG_USB_INCSR;
logf("%s(%d): 0x%x", __func__, endpoint, csr);
if (csr & USB_INCSR_SENTSTALL) {
logf("SENDSTALL %d\n", endpoint);
REG_USB_INCSR = csr & ~USB_INCSR_SENTSTALL; // XXX TXCSR_P_WZC_BITS
return;
}
if (csr & USB_INCSR_UNDERRUN) {
csr |= TXCSR_WZC_BITS;
csr &= ~(USB_INCSR_UNDERRUN | USB_INCSR_INPKTRDY);
REG_USB_INCSR = csr;
logf("underrun! %x", csr);
}
if (!ep->busy) {
logf("Entered EPIN_complete without work!");
return;
}
if (ep->use_dma >= 0) {
logf("DMA status (%x %x %x)", REG_USB_ADDR(USB_INTR_DMA_BULKIN), REG_USB_COUNT(USB_INTR_DMA_BULKIN),REG_USB_CNTL(USB_INTR_DMA_BULKIN));
return;
}
/* If we get here, the operation is completed, and we need to clean up */
/* Make sure DMA engine is idle */
if (csr & (USB_INCSRH_DMAREQENAB << 8)) {
csr |= TXCSR_WZC_BITS;
csr &= ~(USB_INCSR_UNDERRUN | USB_INCSR_INPKTRDY |
((USB_INCSRH_DMAREQENAB | USB_INCSRH_AUTOSET) << 8));
REG_USB_INCSR = csr;
csr = REG_USB_INCSR;
logf("DMA cleanup %x", csr);
}
// XXX send a zero-length packet if necessary.
// if tx complete, and ep->length > 0 and ep->length % fifo == 0,
// REG_USB_INCSR = MODE | PKTRDY;
// Not needed for mass storage as it counts packets but
// if we ever enable other protocls...
logf("EP%d: %d -> %d", endpoint, ep->sent, ep->length);
if(ep->sent >= ep->length) {
if (!ep->wait)
usb_core_transfer_complete(endpoint, USB_DIR_IN, 0, ep->sent);
ep->rc = 0;
ep_transfer_completed(ep);
logf("sent complete");
logf("send complete");
} else {
EPIN_send(endpoint);
}
}
@ -403,9 +522,6 @@ static void EPOUT_handler(unsigned int endpoint)
return;
}
if(ep->use_dma)
return;
if(csr & USB_OUTCSR_OUTPKTRDY) /* There is a packet in the fifo */
{
size = REG_USB_OUTCOUNT;
@ -430,59 +546,55 @@ static void EPOUT_handler(unsigned int endpoint)
}
}
#ifdef USE_USB_DMA
static void EPDMA_handler(int number)
{
int endpoint = -1;
unsigned int size = 0;
int size = 0;
struct usb_endpoint* ep = NULL;
if(number == USB_INTR_DMA_BULKIN)
{
endpoint = (REG_USB_CNTL(0) >> 4) & 0xF;
ep = &endpoints[endpoint*2];
size = (unsigned int)ep->buf - REG_USB_ADDR(0);
}
else if(number == USB_INTR_DMA_BULKOUT)
{
endpoint = (REG_USB_CNTL(1) >> 4) & 0xF;
ep = &endpoints[endpoint*2+1];
size = (unsigned int)ep->buf - REG_USB_ADDR(1);
}
endpoint = (REG_USB_CNTL(number) >> 4) & 0xF;
ep = &endpoints[endpoint*2];
if (!(REG_USB_CNTL(number) & USB_CNTL_DIR_IN))
ep++; /* RX endpoint is +1 in the array */
size = VIRTADDR(REG_USB_ADDR(number)) - ((unsigned int)ep->buf + ep->sent);
logf("DMA_BULK%d %d", number, endpoint);
if (number == USB_INTR_DMA_BULKIN) {
if ((ep->use_dma == 0) || (size % ep->fifo_size)) {
/* DMA is completed, but the final (short) packet needs to
be manually initiated! */
uint16_t incsr;
select_endpoint(endpoint);
incsr = REG_USB_INCSR;
if(number == USB_INTR_DMA_BULKOUT)
{
/* Disable DMA */
REG_USB_CNTL(1) = 0;
commit_discard_dcache(); // XXX range?
select_endpoint(endpoint);
/* Read out last packet manually */
unsigned int lpack_size = REG_USB_OUTCOUNT;
if(lpack_size > 0)
{
ep->buf += ep->length - lpack_size;
readFIFO(ep, lpack_size);
REG_USB_OUTCSR &= ~USB_OUTCSR_OUTPKTRDY;
if (ep->use_dma == 1) {
/* Switch to Mode 0 DMA */
incsr &= ~((USB_INCSRH_AUTOSET | USB_INCSRH_DMAREQENAB) << 8);
REG_USB_INCSR = incsr;
incsr &= ~((USB_INCSRH_DMAREQMODE) << 8);
incsr |= ((USB_INCSRH_DMAREQENAB) << 8);
}
incsr |= USB_INCSR_INPKTRDY;
logf("DMA dangling %x", incsr);
REG_USB_INCSR = incsr;
}
}
else if(number == USB_INTR_DMA_BULKIN && size % ep->fifo_size)
{
/* If the last packet is less than MAXP, set INPKTRDY manually */
REG_USB_INCSR |= USB_INCSR_INPKTRDY;
}
logf("DMA TX%d %d @%d/%d", number, size, ep->sent, ep->length);
ep->sent += size;
ep->use_dma = -1; /* DMA is complete, mark channel as idle */
if (ep)
{
int dir = EP_IS_IN(ep) ? USB_DIR_IN : USB_DIR_OUT;
if ((dir == USB_DIR_OUT) || !ep->wait)
usb_core_transfer_complete(endpoint, dir, 0, ep->length);
ep->rc = 0;
ep_transfer_completed(ep);
EPIN_complete(endpoint);
} else if (number == USB_INTR_DMA_BULKOUT) {
/* RX DMA completed */
logf("DMA RX%d %d @%d/%d", number, size, ep->received, ep->length);
ep->received += size;
ep->use_dma = -1;
EPOUT_handler(endpoint);
} else if (ep) {
ep->use_dma = -1;
}
}
#endif
static void setup_endpoint(struct usb_endpoint *ep)
{
@ -510,14 +622,13 @@ static void setup_endpoint(struct usb_endpoint *ep)
if(ep->type != ep_control)
ep->fifo_size = usb_drv_port_speed() ? 512 : 64;
ep->config = REG_USB_CONFIGDATA;
if(EP_IS_IN(ep))
{
csr = (USB_INCSR_FF | USB_INCSR_CDT);
csrh = USB_INCSRH_MODE;
if(ep->use_dma)
csrh |= (USB_INCSRH_DMAREQENAB | USB_INCSRH_AUTOSET | USB_INCSRH_DMAREQMODE);
if(ep->type == ep_interrupt)
csrh |= USB_INCSRH_FRCDATATOG;
@ -525,6 +636,8 @@ static void setup_endpoint(struct usb_endpoint *ep)
REG_USB_INCSR = csr;
REG_USB_INCSRH = csrh;
logf("IN %d (%x %x %x)", endpoint, ep->fifo_size, csr, csrh);
if (ep->allocated)
REG_USB_INTRINE |= USB_INTR_EP(EP_NUMBER2(ep));
}
@ -536,13 +649,12 @@ static void setup_endpoint(struct usb_endpoint *ep)
if(ep->type == ep_interrupt)
csrh |= USB_OUTCSRH_DNYT;
if(ep->use_dma)
csrh |= (USB_OUTCSRH_DMAREQENAB | USB_OUTCSRH_AUTOCLR | USB_OUTCSRH_DMAREQMODE);
REG_USB_OUTMAXP = ep->fifo_size;
REG_USB_OUTCSR = csr;
REG_USB_OUTCSRH = csrh;
logf("OUT %d (%x %x %x)", endpoint, ep->fifo_size, csr, csrh);
if (ep->allocated)
REG_USB_INTROUTE |= USB_INTR_EP(EP_NUMBER2(ep));
}
@ -574,8 +686,8 @@ static void udc_reset(void)
REG_USB_INTRUSBE = 0;
/* Disable DMA */
REG_USB_CNTL(0) = 0;
REG_USB_CNTL(1) = 0;
REG_USB_CNTL(USB_INTR_DMA_BULKIN) = 0;
REG_USB_CNTL(USB_INTR_DMA_BULKOUT) = 0;
/* High speed, softconnect */
REG_USB_POWER = (USB_POWER_SOFTCONN | USB_POWER_HSENAB);
@ -584,6 +696,9 @@ static void udc_reset(void)
select_endpoint(0);
REG_USB_CSR0 = (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_SVDSETUPEND | USB_CSR0_FLUSHFIFO);
endpoints[0].config = REG_USB_CONFIGDATA;
endpoints[1].config = REG_USB_CONFIGDATA;
if (endpoints[0].busy)
{
if (endpoints[0].wait)
@ -627,17 +742,19 @@ void OTG(void)
unsigned char intrUSB = REG_USB_INTRUSB;
unsigned short intrIn = REG_USB_INTRIN;
unsigned short intrOut = REG_USB_INTROUT;
#ifdef USE_USB_DMA
unsigned char intrDMA = REG_USB_INTR;
#endif
logf("%x %x %x %x", intrUSB, intrIn, intrOut, intrDMA);
logf("IRQ %x %x %x %x", intrUSB, intrIn, intrOut, intrDMA);
/* EPIN & EPOUT are all handled in DMA */
if(intrIn & USB_INTR_EP(0))
EP0_handler();
if(intrIn & USB_INTR_EP(1))
EPIN_handler(1);
EPIN_complete(1);
if(intrIn & USB_INTR_EP(2))
EPIN_handler(2);
EPIN_complete(2);
if(intrOut & USB_INTR_EP(1))
EPOUT_handler(1);
if(intrOut & USB_INTR_EP(2))
@ -648,10 +765,12 @@ void OTG(void)
logf("USB suspend");
if(intrUSB & USB_INTR_RESUME)
logf("USB resume");
if(intrDMA & USB_INTR_DMA_BULKIN)
#ifdef USE_USB_DMA
if(intrDMA & (1<<USB_INTR_DMA_BULKIN))
EPDMA_handler(USB_INTR_DMA_BULKIN);
if(intrDMA & USB_INTR_DMA_BULKOUT)
if(intrDMA & (1<<USB_INTR_DMA_BULKOUT))
EPDMA_handler(USB_INTR_DMA_BULKOUT);
#endif
}
bool usb_drv_stalled(int endpoint, bool in)
@ -790,6 +909,10 @@ void usb_drv_exit(void)
{
logf("%s()", __func__);
select_endpoint(1);
logf("DMA X (%x %x %x %x)", REG_USB_ADDR(USB_INTR_DMA_BULKIN), REG_USB_COUNT(USB_INTR_DMA_BULKIN),REG_USB_CNTL(USB_INTR_DMA_BULKIN), REG_USB_INCSR);
REG_USB_FADDR = 0;
REG_USB_INDEX = 0;
@ -798,9 +921,11 @@ void usb_drv_exit(void)
REG_USB_INTROUTE = 0;
REG_USB_INTRUSBE = 0;
#ifdef USE_USB_DMA
/* Disable DMA */
REG_USB_CNTL(0) = 0;
REG_USB_CNTL(1) = 0;
REG_USB_CNTL(USB_INTR_DMA_BULKIN) = 0;
REG_USB_CNTL(USB_INTR_DMA_BULKOUT) = 0;
#endif
/* Disconnect from USB */
REG_USB_POWER &= ~USB_POWER_SOFTCONN;
@ -817,10 +942,8 @@ static void usb_drv_send_internal(struct usb_endpoint* ep, void* ptr, int length
{
int flags = disable_irq_save();
if(ep->type == ep_control)
{
if ((ptr == NULL && length == 0) || !ep0_data_requested)
{
if (ep->type == ep_control) {
if ((ptr == NULL && length == 0) || !ep0_data_requested) {
restore_irq(flags);
return;
}
@ -831,36 +954,22 @@ static void usb_drv_send_internal(struct usb_endpoint* ep, void* ptr, int length
ep->sent = 0;
ep->length = length;
ep->busy = true;
if(blocking)
{
if(blocking) {
ep->rc = -1;
ep->wait = true;
} else {
ep->rc = 0;
}
else ep->rc = 0;
if(ep->type == ep_control)
{
if (ep->type == ep_control) {
EP0_send();
}
else
{
if(ep->use_dma)
{
commit_discard_dcache_range(ptr, length);
REG_USB_ADDR(0) = PHYSADDR((unsigned long)ptr);
REG_USB_COUNT(0) = length;
REG_USB_CNTL(0) = (USB_CNTL_INTR_EN | USB_CNTL_MODE_1 |
USB_CNTL_DIR_IN | USB_CNTL_ENA |
USB_CNTL_EP(EP_NUMBER2(ep)) | USB_CNTL_BURST_16);
}
else
EPIN_handler(EP_NUMBER2(ep));
} else {
EPIN_send(EP_NUMBER2(ep));
}
restore_irq(flags);
if(blocking)
{
if(blocking) {
semaphore_wait(&ep->complete, HZ);
ep->wait = false;
}
@ -918,23 +1027,12 @@ int usb_drv_recv(int endpoint, void* ptr, int length)
ep->received = 0;
ep->length = length;
ep->busy = true;
if(ep->use_dma)
{
discard_dcache_range(ptr, length);
REG_USB_ADDR(1) = PHYSADDR((unsigned long)ptr);
REG_USB_COUNT(1) = length;
REG_USB_CNTL(1) = (USB_CNTL_INTR_EN | USB_CNTL_MODE_1 |
USB_CNTL_ENA | USB_CNTL_EP(endpoint) |
USB_CNTL_BURST_16);
}
else
{
if (endpoint == EP_CONTROL)
{
ep0_data_supplied = false;
EP0_handler();
}
else EPOUT_handler(endpoint);
if (endpoint == EP_CONTROL) {
ep0_data_supplied = false;
EP0_handler();
} else {
EPOUT_handler(endpoint);
}
restore_irq(flags);
@ -976,6 +1074,12 @@ void usb_drv_cancel_all_transfers(void)
unsigned int i, flags = disable_irq_save();
#ifdef USE_USB_DMA
/* Disable DMA */
REG_USB_CNTL(USB_INTR_DMA_BULKIN) = 0;
REG_USB_CNTL(USB_INTR_DMA_BULKOUT) = 0;
#endif
for(i=0; i<TOTAL_EP(); i++)
{
if (endpoints[i].busy)
@ -996,6 +1100,7 @@ void usb_drv_cancel_all_transfers(void)
select_endpoint(i/2);
flushFIFO(&endpoints[i]);
}
restore_irq(flags);
}

View file

@ -6966,6 +6966,8 @@ do { \
#define USB_FIFO_EP(n) (USB_BASE + (n)*4 + 0x20)
#define USB_HWVERS (USB_BASE + 0x6c)
#define USB_EPINFO (USB_BASE + 0x78) /* Endpoint information */
#define USB_RAMINFO (USB_BASE + 0x79) /* RAM information */
@ -7006,6 +7008,7 @@ do { \
#define USB_INCSRH_DMAREQENAB 0x10
#define USB_INCSRH_FRCDATATOG 0x08
#define USB_INCSRH_DMAREQMODE 0x04
#define USB_INCSR_INCOMPTX 0x80
#define USB_INCSR_CDT 0x40
#define USB_INCSR_SENTSTALL 0x20
#define USB_INCSR_SENDSTALL 0x10
@ -7083,6 +7086,8 @@ do { \
#define REG_USB_ADDR(n) REG32(USB_ADDR(n))
#define REG_USB_COUNT(n) REG32(USB_COUNT(n))
#define REG_USB_HWVERS REG16(USB_HWVERS)
#define REG_USB_EPINFO REG8(USB_EPINFO)
#define REG_USB_RAMINFO REG8(USB_RAMINFO)