From 9bcb96f4908c480727de5cafa804d476c6819790 Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere Date: Mon, 23 Feb 2009 16:10:46 +0000 Subject: Ingenic Jz4740: * Fix USB issues + add DMA support (doesn't work fully) * Make exception handler a bit more descriptive git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20091 a1c6a512-1295-4272-9138-f99709370657 --- firmware/export/jz4740.h | 20 +- .../target/mips/ingenic_jz47xx/system-jz4740.c | 4 +- firmware/target/mips/ingenic_jz47xx/usb-jz4740.c | 261 +++++++++++++-------- 3 files changed, 178 insertions(+), 107 deletions(-) diff --git a/firmware/export/jz4740.h b/firmware/export/jz4740.h index 5642dc8464..f029ad606e 100644 --- a/firmware/export/jz4740.h +++ b/firmware/export/jz4740.h @@ -2471,11 +2471,11 @@ #define USB_CSR0_SVDSETUPEND 0x80 /* Endpoint CSR register bits */ -#define USB_INCSRH_AUTOSET 0x8000 -#define USB_INCSRH_ISO 0x4000 -#define USB_INCSRH_MODE 0x2000 -#define USB_INCSRH_DMAREQENAB 0x1000 -#define USB_INCSRH_DMAREQMODE 0x0400 +#define USB_INCSRH_AUTOSET 0x80 +#define USB_INCSRH_ISO 0x40 +#define USB_INCSRH_MODE 0x20 +#define USB_INCSRH_DMAREQENAB 0x10 +#define USB_INCSRH_DMAREQMODE 0x04 #define USB_INCSR_CDT 0x40 #define USB_INCSR_SENTSTALL 0x20 #define USB_INCSR_SENDSTALL 0x10 @@ -2483,11 +2483,11 @@ #define USB_INCSR_UNDERRUN 0x04 #define USB_INCSR_FFNOTEMPT 0x02 #define USB_INCSR_INPKTRDY 0x01 -#define USB_OUTCSRH_AUTOCLR 0x8000 -#define USB_OUTCSRH_ISO 0x4000 -#define USB_OUTCSRH_DMAREQENAB 0x2000 -#define USB_OUTCSRH_DNYT 0x1000 -#define USB_OUTCSRH_DMAREQMODE 0x0800 +#define USB_OUTCSRH_AUTOCLR 0x80 +#define USB_OUTCSRH_ISO 0x40 +#define USB_OUTCSRH_DMAREQENAB 0x20 +#define USB_OUTCSRH_DNYT 0x10 +#define USB_OUTCSRH_DMAREQMODE 0x08 #define USB_OUTCSR_CDT 0x80 #define USB_OUTCSR_SENTSTALL 0x40 #define USB_OUTCSR_SENDSTALL 0x20 diff --git a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c index c029dd46bb..f78f3592e5 100644 --- a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c @@ -238,7 +238,7 @@ static char* parse_exception(unsigned int cause) void exception_handler(void* stack_ptr, unsigned int cause, unsigned int epc) { - panicf("Exception occurred: %s [0x%08x] at 0x%08x (stack at 0x%08x)", parse_exception(cause), cause, epc, (unsigned int)stack_ptr); + panicf("Exception occurred: %s [0x%08x] at 0x%08x (stack at 0x%08x)", parse_exception(cause), read_c0_badvaddr(), epc, (unsigned int)stack_ptr); } void tlb_refill_handler(void) @@ -308,7 +308,7 @@ static void pll_init(void) 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 9 }; - int div[5] = {1, 3, 3, 3, 3}; /* divisors of I:S:P:L:M */ + int div[5] = {0, 3, 3, 3, 3}; /* divisors of I:S:P:L:M */ int nf, pllout2; cfcr = CPM_CPCCR_CLKOEN | diff --git a/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c b/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c index 7bd0ba4ae5..2dd73c01a4 100644 --- a/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c @@ -127,21 +127,30 @@ static void writeFIFO(struct usb_endpoint *ep, unsigned int size) { logf("writeFIFO(EP%d, %d)", EP_NUMBER2(ep), size); - register unsigned int *d = (unsigned int *)EP_PTR(ep); - register unsigned char *c; + register unsigned int *d32 = (unsigned int *)EP_PTR(ep); + register unsigned char *d8 = (unsigned char *)EP_PTR(ep); register unsigned int s; if(size > 0) { - s = size >> 2; - while (s--) - REG32(ep->fifo_addr) = *d++; - - if( (s = size & 3) ) + if(UNLIKELY((unsigned int)d8 & 3)) + { + s = size; + while(s--) + REG8(ep->fifo_addr) = *d8++; + } + else { - c = (unsigned char *)d; + s = size >> 2; while (s--) - REG8(ep->fifo_addr) = *c++; + REG32(ep->fifo_addr) = *d32++; + + if( (s = size & 3) ) + { + d8 = (unsigned char *)d32; + while (s--) + REG8(ep->fifo_addr) = *d8++; + } } } } @@ -158,9 +167,9 @@ static void flushFIFO(struct usb_endpoint *ep) case ep_bulk: case ep_interrupt: if(EP_IS_IN(ep)) - REG_USB_REG_INCSR |= USB_INCSR_FF; + REG_USB_REG_INCSR |= (USB_INCSR_FF | USB_INCSR_CDT); else - REG_USB_REG_OUTCSR |= USB_OUTCSR_FF; + REG_USB_REG_OUTCSR |= (USB_OUTCSR_FF | USB_OUTCSR_CDT); break; } } @@ -249,7 +258,7 @@ static void EP0_handler(void) } static void EPIN_handler(unsigned int endpoint) -{ +{ struct usb_endpoint* ep = &endpoints[endpoint*2+1]; unsigned int length, csr; @@ -266,14 +275,12 @@ static void EPIN_handler(unsigned int endpoint) return; } -#if 0 - if(ep->use_dma == true) + if(ep->use_dma) return; -#endif if(csr & USB_INCSR_FFNOTEMPT) { - logf("FIFO is not empty!: 0x%x", csr); + logf("FIFO is not empty! 0x%x", csr); return; } @@ -306,56 +313,113 @@ static void EPOUT_handler(unsigned int endpoint) struct usb_endpoint* ep = &endpoints[endpoint*2]; unsigned int size, csr; - select_endpoint(endpoint); - csr = REG_USB_REG_OUTCSR; - logf("EPOUT_handler(%d): 0x%x", endpoint, csr); - if(!ep->busy) return; - - if(csr & USB_OUTCSR_SENTSTALL) - { - logf("stall sent, flushing fifo.."); - flushFIFO(ep); - REG_USB_REG_OUTCSR = csr & ~USB_OUTCSR_SENTSTALL; - return; - } - if(csr & USB_OUTCSR_OUTPKTRDY) /* There is a packet in the fifo */ + select_endpoint(endpoint); + while((csr = REG_USB_REG_OUTCSR) & (USB_OUTCSR_SENTSTALL|USB_OUTCSR_OUTPKTRDY)) { - size = REG_USB_REG_OUTCOUNT; + logf("EPOUT_handler(%d): 0x%x", endpoint, csr); + if(csr & USB_OUTCSR_SENTSTALL) + { + logf("stall sent, flushing fifo.."); + flushFIFO(ep); + REG_USB_REG_OUTCSR = csr & ~USB_OUTCSR_SENTSTALL; + return; + } - readFIFO(ep, size); - ep->received += size; + if(ep->use_dma) + return; + + if(csr & USB_OUTCSR_OUTPKTRDY) /* There is a packet in the fifo */ + { + size = REG_USB_REG_OUTCOUNT; + + readFIFO(ep, size); + ep->received += size; + + /*if(csr & USB_OUTCSR_FFFULL) + csr &= ~USB_OUTCSR_FFFULL;*/ + + REG_USB_REG_OUTCSR = csr & ~USB_OUTCSR_OUTPKTRDY; + + logf("received: %d max length: %d", ep->received, ep->length); + + if(size < ep->fifo_size || ep->received >= ep->length) + { + usb_core_transfer_complete(endpoint, USB_DIR_OUT, 0, ep->received); + if(ep->wait) + wakeup_signal(&ep_wkup[endpoint*2]); + logf("receive transfer_complete"); + ep->received = 0; + ep->length = 0; + ep->buf = NULL; + ep->busy = false; + return; + } + } + } +} - REG_USB_REG_OUTCSR = csr & ~USB_OUTCSR_OUTPKTRDY; +static void EPDMA_handler(int number) +{ + int endpoint=-1; + unsigned int size=0; + if(number == USB_INTR_DMA_BULKIN) + endpoint = (REG_USB_REG_CNTL1 >> 4) & 0xF; + else if(number == USB_INTR_DMA_BULKOUT) + endpoint = (REG_USB_REG_CNTL2 >> 4) & 0xF; + + struct usb_endpoint* ep = &endpoints[endpoint]; + logf("DMA_BULK%d %d", number, endpoint); + + if(number == USB_INTR_DMA_BULKIN) + size = (unsigned int)ep->buf - REG_USB_REG_ADDR1; + else if(number == USB_INTR_DMA_BULKOUT) + size = (unsigned int)ep->buf - REG_USB_REG_ADDR2; + + if(number == USB_INTR_DMA_BULKOUT) + { + /* Disable DMA */ + REG_USB_REG_CNTL2 = 0; - logf("received: %d max length: %d", ep->received, ep->length); + __dcache_invalidate_all(); - if(size < ep->fifo_size || ep->received >= ep->length) + select_endpoint(endpoint); + /* Read out last packet manually */ + unsigned int lpack_size = REG_USB_REG_OUTCOUNT; + if(lpack_size > 0) { - usb_core_transfer_complete(endpoint, USB_DIR_OUT, 0, ep->received); - if(ep->wait) - wakeup_signal(&ep_wkup[endpoint*2]); - logf("receive transfer_complete"); - ep->received = 0; - ep->length = 0; - ep->buf = NULL; - ep->busy = false; + ep->buf += ep->length - lpack_size; + readFIFO(ep, lpack_size); + REG_USB_REG_OUTCSR &= ~USB_OUTCSR_OUTPKTRDY; } } + else if(number == USB_INTR_DMA_BULKIN && size % ep->fifo_size) + /* If the last packet is less than MAXP, set INPKTRDY manually */ + REG_USB_REG_INCSR |= USB_INCSR_INPKTRDY; + + usb_core_transfer_complete(endpoint, EP_IS_IN(ep) ? USB_DIR_IN : USB_DIR_OUT, + 0, ep->length); + + ep->busy = false; + ep->sent = 0; + ep->length = 0; + ep->buf = NULL; + if(ep->wait) + wakeup_signal(&ep_wkup[EP_NUMBER(ep)]); } static void setup_endpoint(struct usb_endpoint *ep) { - int csr; - ep->sent = 0; - ep->length = 0; + int csr, csrh; select_endpoint(EP_NUMBER2(ep)); ep->busy = false; ep->wait = false; + ep->sent = 0; + ep->length = 0; if(ep->type == ep_bulk) { @@ -367,27 +431,31 @@ static void setup_endpoint(struct usb_endpoint *ep) if(EP_IS_IN(ep)) { - REG_USB_REG_INMAXP = ep->fifo_size; - csr = (USB_INCSR_FF | USB_INCSR_CDT | USB_INCSRH_MODE); + csr = (USB_INCSR_FF | USB_INCSR_CDT); + csrh = USB_INCSRH_MODE; if(ep->use_dma) - csr |= (USB_INCSRH_DMAREQENAB | USB_INCSRH_AUTOSET); + csrh |= (USB_INCSRH_DMAREQENAB | USB_INCSRH_AUTOSET | USB_INCSRH_DMAREQMODE); - REG_USB_REG_INTRINE |= USB_INTR_EP(EP_NUMBER2(ep)); + REG_USB_REG_INMAXP = ep->fifo_size; REG_USB_REG_INCSR = csr; + REG_USB_REG_INCSRH = csrh; + REG_USB_REG_INTRINE |= USB_INTR_EP(EP_NUMBER2(ep)); } else - { - REG_USB_REG_OUTMAXP = ep->fifo_size; + { csr = (USB_OUTCSR_FF | USB_OUTCSR_CDT); + csrh = 0; if(ep->type == ep_interrupt) - csr |= USB_OUTCSRH_DNYT; + csrh |= USB_OUTCSRH_DNYT; if(ep->use_dma) - csr |= (USB_OUTCSRH_DMAREQENAB | USB_OUTCSRH_AUTOCLR | USB_OUTCSRH_DMAREQMODE); + csrh |= (USB_OUTCSRH_DMAREQENAB | USB_OUTCSRH_AUTOCLR | USB_OUTCSRH_DMAREQMODE); - REG_USB_REG_INTROUTE |= USB_INTR_EP(EP_NUMBER2(ep)); + REG_USB_REG_OUTMAXP = ep->fifo_size; REG_USB_REG_OUTCSR = csr; + REG_USB_REG_OUTCSRH = csrh; + REG_USB_REG_INTROUTE |= USB_INTR_EP(EP_NUMBER2(ep)); } } @@ -395,13 +463,13 @@ static void udc_reset(void) { /* From the datasheet: - When a reset condition is detected on the USB, the controller performs the following actions: - * Sets FAddr to 0. - * Sets Index to 0. - * Flushes all endpoint FIFOs. - * Clears all control/status registers. - * Enables all endpoint interrupts. - * Generates a Reset interrupt. + When a reset condition is detected on the USB, the controller performs the following actions: + * Sets FAddr to 0. + * Sets Index to 0. + * Flushes all endpoint FIFOs. + * Clears all control/status registers. + * Enables all endpoint interrupts. + * Generates a Reset interrupt. */ logf("udc_reset()"); @@ -430,7 +498,8 @@ static void udc_reset(void) select_endpoint(0); REG_USB_REG_CSR0 = (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_SVDSETUPEND); - for(i=2; i> 4) & 0xF)); - unsigned int size = (unsigned int)endpoints[3].buf - REG_USB_REG_ADDR2; - if(size < endpoints[3].length) - { - select_endpoint(1); - writeFIFO(endpoints[3], endpoints[3].length - size); - REG_USB_REG_INCSR |= USB_INCSR_INPKTRDY; - } - - usb_core_transfer_complete(1, USB_DIR_IN, 0, endpoints[3].length); - } + EPDMA_handler(USB_INTR_DMA_BULKIN); if(intrDMA & USB_INTR_DMA_BULKOUT) - { - logf("DMA_BULKOUT %d", ((REG_USB_REG_CNTL2 >> 4) & 0xF)); - - select_endpoint(1); - REG_USB_REG_OUTCSR &= ~(USB_OUTCSRH_DMAREQENAB | USB_OUTCSR_OUTPKTRDY); - - usb_core_transfer_complete(1, USB_DIR_OUT, 0, 0); - } -#endif + EPDMA_handler(USB_INTR_DMA_BULKOUT); } bool usb_drv_stalled(int endpoint, bool in) @@ -610,6 +661,10 @@ void usb_drv_init(void) /* Enable the USB PHY */ REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE; + /* Dis- and reconnect from USB */ + REG_USB_REG_POWER &= ~USB_POWER_SOFTCONN; + REG_USB_REG_POWER |= USB_POWER_SOFTCONN; + udc_reset(); } @@ -660,8 +715,8 @@ int usb_drv_send_nonblocking(int endpoint, void* ptr, int length) endpoints[1].length = length; ep0state = USB_EP0_TX; EP0_send(); - restore_irq(flags); + return 0; } else @@ -671,15 +726,19 @@ int usb_drv_send_nonblocking(int endpoint, void* ptr, int length) endpoints[endpoint*2+1].sent = 0; endpoints[endpoint*2+1].length = length; endpoints[endpoint*2+1].busy = true; -#if 0 - select_endpoint(endpoint); + if(endpoints[endpoint*2+1].use_dma) + { + //dma_cache_wback_inv((unsigned long)ptr, length); + __dcache_writeback_all(); + REG_USB_REG_ADDR1 = (unsigned long)ptr & 0x7fffffff; + REG_USB_REG_COUNT1 = length; + REG_USB_REG_CNTL1 = (USB_CNTL_INTR_EN | USB_CNTL_MODE_1 | + USB_CNTL_DIR_IN | USB_CNTL_ENA | + USB_CNTL_EP(endpoint) | USB_CNTL_BURST_16); + } + else + EPIN_handler(endpoint); - REG_USB_REG_ADDR2 = ((unsigned long)ptr) & 0x7fffffff; - REG_USB_REG_COUNT2 = length; - REG_USB_REG_CNTL2 = (USB_CNTL_INTR_EN | USB_CNTL_MODE_1 | USB_CNTL_DIR_IN | USB_CNTL_ENA); -#else - EPIN_handler(endpoint); -#endif restore_irq(flags); return 0; } @@ -717,8 +776,20 @@ int usb_drv_recv(int endpoint, void* ptr, int length) endpoints[endpoint*2].received = 0; endpoints[endpoint*2].length = length; endpoints[endpoint*2].busy = true; - restore_irq(flags); + if(endpoints[endpoint*2].use_dma) + { + //dma_cache_wback_inv((unsigned long)ptr, length); + __dcache_writeback_all(); + REG_USB_REG_ADDR2 = (unsigned long)ptr & 0x7fffffff; + REG_USB_REG_COUNT2 = length; + REG_USB_REG_CNTL2 = (USB_CNTL_INTR_EN | USB_CNTL_MODE_1 | + USB_CNTL_ENA | USB_CNTL_EP(endpoint) | + USB_CNTL_BURST_16); + } + else + EPOUT_handler(endpoint); + restore_irq(flags); return 0; } } -- cgit v1.2.3