diff options
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/crt0.S | 2 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/usb-jz4760.c | 251 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/boot-x1000.c | 17 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/boot-x1000.h | 4 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/crt0.S | 2 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/installer-x1000.c | 4 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/nand-x1000.c | 158 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/nand-x1000.h | 101 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/spl-nand-x1000.c | 4 |
9 files changed, 273 insertions, 270 deletions
diff --git a/firmware/target/mips/ingenic_jz47xx/crt0.S b/firmware/target/mips/ingenic_jz47xx/crt0.S index 258a5c02fc..1652bea8e5 100644 --- a/firmware/target/mips/ingenic_jz47xx/crt0.S +++ b/firmware/target/mips/ingenic_jz47xx/crt0.S @@ -185,7 +185,7 @@ _irq_stack_loop: jal system_main /* Init clocks etc first */ ssnop j main - ssnop + move ra, zero /* init backtrace root */ /* diff --git a/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c b/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c index 474d45edee..8ff6d4bc1e 100644 --- a/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c +++ b/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c @@ -54,16 +54,14 @@ OUT = HOST->DEV, (ie we recv) */ -enum ep_type -{ +enum ep_type { ep_control, ep_bulk, ep_interrupt, ep_isochronous }; -struct usb_endpoint -{ +struct usb_endpoint { const enum ep_type type; const long fifo_addr; unsigned short fifo_size; @@ -76,8 +74,7 @@ struct usb_endpoint volatile void *buf; volatile size_t length; - union - { + union { volatile size_t sent; volatile size_t received; }; @@ -94,8 +91,7 @@ struct usb_endpoint #define short_not_ok 1 /* only works for mass storage.. */ #define ep_doublebuf(__ep) 0 -static union -{ +static union { int buf[64 / sizeof(int)]; struct usb_ctrlrequest request; } ep0_rx; @@ -106,7 +102,7 @@ static volatile bool ep0_data_requested = false; static struct usb_endpoint endpoints[] = { 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_control, USB_FIFO_EP(0), 64, NULL), 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), @@ -127,19 +123,14 @@ static void readFIFO(struct usb_endpoint *ep, unsigned int size) register unsigned int s = size >> 2; register unsigned int x; - if(size > 0) - { - if( ((unsigned int)ptr & 3) == 0 ) - { - while(s--) + if(size > 0) { + if (((unsigned int)ptr & 3) == 0) { + while(s--) { *ptr32++ = REG32(ep->fifo_addr); - + } ptr = (unsigned char*)ptr32; - } - else - { - while(s--) - { + } else { + while(s--) { x = REG32(ep->fifo_addr); *ptr++ = x & 0xFF; x >>= 8; *ptr++ = x & 0xFF; x >>= 8; @@ -147,10 +138,10 @@ static void readFIFO(struct usb_endpoint *ep, unsigned int size) *ptr++ = x; } } - s = size & 3; - while(s--) + while(s--) { *ptr++ = REG8(ep->fifo_addr); + } } } @@ -163,18 +154,14 @@ static void writeFIFO(struct usb_endpoint *ep, size_t size) register size_t s = size >> 2; register unsigned int x; - if(size > 0) - { - if( ((unsigned int)d8 & 3) == 0 ) - { - while (s--) + if (size > 0) { + if (((unsigned int)d8 & 3) == 0) { + while (s--) { REG32(ep->fifo_addr) = *d32++; + } d8 = (unsigned char *)d32; - } - else - { - while (s--) - { + } else { + while (s--) { x = (unsigned int)(*d8++) & 0xff; x |= ((unsigned int)(*d8++) & 0xff) << 8; x |= ((unsigned int)(*d8++) & 0xff) << 16; @@ -182,11 +169,9 @@ static void writeFIFO(struct usb_endpoint *ep, size_t size) REG32(ep->fifo_addr) = x; } } - - if( (s = size & 3) ) - { - while (s--) - REG8(ep->fifo_addr) = *d8++; + s = size & 3; + while (s--) { + REG8(ep->fifo_addr) = *d8++; } } } @@ -195,18 +180,17 @@ static void flushFIFO(struct usb_endpoint *ep) { logf("%s(%d)", __func__, EP_NUMBER(ep)); - switch (ep->type) - { - case ep_control: + switch (ep->type) { + case ep_control: break; - - case ep_bulk: - case ep_interrupt: - case ep_isochronous: - if(EP_IS_IN(ep)) - REG_USB_INCSR |= (USB_INCSR_FF | USB_INCSR_CDT); - else - REG_USB_OUTCSR |= (USB_OUTCSR_FF | USB_OUTCSR_CDT); + case ep_bulk: + case ep_interrupt: + case ep_isochronous: + if (EP_IS_IN(ep)) { + REG_USB_INCSR |= (USB_INCSR_FF | USB_INCSR_CDT); + } else { + REG_USB_OUTCSR |= (USB_OUTCSR_FF | USB_OUTCSR_CDT); + } break; } } @@ -217,8 +201,9 @@ static inline void ep_transfer_completed(struct usb_endpoint* ep) ep->length = 0; ep->buf = NULL; ep->busy = false; - if(ep->wait) + if (ep->wait) { semaphore_release(&ep->complete); + } } static void EP0_send(void) @@ -232,27 +217,26 @@ static void EP0_send(void) logf("%s(): 0x%x %d %d", __func__, csr0, ep->sent, ep->length); - if(ep->sent == 0) - { + if (ep->sent == 0) { length = MIN(ep->length, ep->fifo_size); REG_USB_CSR0 = (csr0 | USB_CSR0_FLUSHFIFO); - } - else + } else { length = MIN(EP_BUF_LEFT(ep), ep->fifo_size); + } writeFIFO(ep, length); ep->sent += length; - if(ep->sent >= ep->length) - { + if (ep->sent >= ep->length) { REG_USB_CSR0 = (csr0 | USB_CSR0_INPKTRDY | USB_CSR0_DATAEND); /* Set data end! */ - if (!ep->wait) + if (!ep->wait) { usb_core_transfer_complete(EP_CONTROL, USB_DIR_IN, 0, ep->sent); + } ep->rc = 0; ep_transfer_completed(ep); - } - else + } else { REG_USB_CSR0 = (csr0 | USB_CSR0_INPKTRDY); + } } static void EP0_handler(void) @@ -270,8 +254,7 @@ static void EP0_handler(void) /* Check for SentStall: This bit is set when a STALL handshake is transmitted. The CPU should clear this bit. */ - if(csr0 & USB_CSR0_SENTSTALL) - { + if (csr0 & USB_CSR0_SENTSTALL) { REG_USB_CSR0 = csr0 & ~USB_CSR0_SENTSTALL; return; } @@ -281,68 +264,62 @@ static void EP0_handler(void) An interrupt will be generated and the FIFO flushed at this time. The bit is cleared by the CPU writing a 1 to the ServicedSetupEnd bit. */ - if(csr0 & USB_CSR0_SETUPEND) - { + if (csr0 & USB_CSR0_SETUPEND) { csr0 |= USB_CSR0_SVDSETUPEND; REG_USB_CSR0 = csr0; ep0_data_supplied = false; ep0_data_requested = false; - if (ep_send->busy) - { + if (ep_send->busy) { if (!ep_send->wait) usb_core_transfer_complete(EP_CONTROL, USB_DIR_IN, -1, 0); ep_transfer_completed(ep_send); } - if (ep_recv->busy) - { + if (ep_recv->busy) { usb_core_transfer_complete(EP_CONTROL, USB_DIR_OUT, -1, 0); ep_transfer_completed(ep_recv); } } /* Call relevant routines for endpoint 0 state */ - if(csr0 & USB_CSR0_OUTPKTRDY) /* There is a packet in the fifo */ - { - if (ep_send->busy) - { - if (!ep_send->wait) + if (csr0 & USB_CSR0_OUTPKTRDY) { /* There is a packet in the fifo */ + if (ep_send->busy) { + if (!ep_send->wait) { usb_core_transfer_complete(EP_CONTROL, USB_DIR_IN, -1, 0); + } ep_transfer_completed(ep_send); } - if (ep_recv->busy && ep_recv->buf && ep_recv->length) - { + if (ep_recv->busy && ep_recv->buf && ep_recv->length) { unsigned int size = REG_USB_COUNT0; readFIFO(ep_recv, size); ep_recv->received += size; - if (size < ep_recv->fifo_size || ep_recv->received >= ep_recv->length) - { + if (size < ep_recv->fifo_size || ep_recv->received >= ep_recv->length) { REG_USB_CSR0 = csr0 | USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND; /* Set data end! */ usb_core_transfer_complete(EP_CONTROL, USB_DIR_OUT, 0, ep_recv->received); ep_transfer_completed(ep_recv); + } else { + REG_USB_CSR0 = csr0 | USB_CSR0_SVDOUTPKTRDY; /* clear OUTPKTRDY bit */ } - else REG_USB_CSR0 = csr0 | USB_CSR0_SVDOUTPKTRDY; /* clear OUTPKTRDY bit */ - } - else if (!ep0_data_supplied) - { + } else if (!ep0_data_supplied) { ep_recv->buf = ep0_rx.buf; readFIFO(ep_recv, REG_USB_COUNT0); csr0 |= USB_CSR0_SVDOUTPKTRDY; - if (!ep0_rx.request.wLength) - { + if (!ep0_rx.request.wLength) { csr0 |= USB_CSR0_DATAEND; /* Set data end! */ ep0_data_requested = false; ep0_data_supplied = false; - } - else if (ep0_rx.request.bRequestType & USB_DIR_IN) + } else if (ep0_rx.request.bRequestType & USB_DIR_IN) { ep0_data_requested = true; - else ep0_data_supplied = true; + } else { + ep0_data_supplied = true; + } REG_USB_CSR0 = csr0; usb_core_legacy_control_request(&ep0_rx.request); ep_transfer_completed(ep_recv); } } - else if (ep_send->busy) + else if (ep_send->busy) { EP0_send(); + } } /* Does new work */ @@ -429,7 +406,7 @@ static void EPIN_send(unsigned int endpoint) #endif /* Non-DMA code */ - if(ep->sent == 0) + if (ep->sent == 0) length = MIN(ep->length, ep->fifo_size); else length = MIN(EP_BUF_LEFT(ep), ep->fifo_size); @@ -494,7 +471,7 @@ static void EPIN_complete(unsigned int endpoint) logf("EP%d: %d -> %d", endpoint, ep->sent, ep->length); - if(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; @@ -516,9 +493,9 @@ static void EPOUT_handler(unsigned int endpoint) } select_endpoint(endpoint); - while((csr = REG_USB_OUTCSR) & (USB_OUTCSR_SENTSTALL|USB_OUTCSR_OUTPKTRDY)) { + while ((csr = REG_USB_OUTCSR) & (USB_OUTCSR_SENTSTALL|USB_OUTCSR_OUTPKTRDY)) { logf("%s(%d): 0x%x", __func__, endpoint, csr); - if(csr & USB_OUTCSR_SENTSTALL) { + if (csr & USB_OUTCSR_SENTSTALL) { logf("stall sent, flushing fifo.."); flushFIFO(ep); REG_USB_OUTCSR = csr & ~USB_OUTCSR_SENTSTALL; @@ -593,7 +570,7 @@ static void EPOUT_handler(unsigned int endpoint) logf("received: %d max length: %d", ep->received, ep->length); - if(size < ep->fifo_size || ep->received >= ep->length) { + if (size < ep->fifo_size || ep->received >= ep->length) { usb_core_transfer_complete(endpoint, USB_DIR_OUT, 0, ep->received); ep_transfer_completed(ep); logf("receive transfer_complete"); @@ -613,8 +590,7 @@ static void EPOUT_ready(unsigned int endpoint) select_endpoint(endpoint); csr = REG_USB_OUTCSR; - if(!ep->busy) - { + if (!ep->busy) { logf("Entered EPOUT handler without work!"); return; } @@ -717,15 +693,15 @@ static void setup_endpoint(struct usb_endpoint *ep) select_endpoint(endpoint); - if (ep->busy) - { - if(EP_IS_IN(ep)) - { + if (ep->busy) { + if (EP_IS_IN(ep)) { if (ep->wait) semaphore_release(&ep->complete); - else usb_core_transfer_complete(endpoint, USB_DIR_IN, -1, 0); + else + usb_core_transfer_complete(endpoint, USB_DIR_IN, -1, 0); + } else { + usb_core_transfer_complete(endpoint, USB_DIR_OUT, -1, 0); } - else usb_core_transfer_complete(endpoint, USB_DIR_OUT, -1, 0); } ep->busy = false; @@ -733,17 +709,16 @@ static void setup_endpoint(struct usb_endpoint *ep) ep->sent = 0; ep->length = 0; - if(ep->type != ep_control) + if (ep->type != ep_control) ep->fifo_size = usb_drv_port_speed() ? 512 : 64; ep->config = REG_USB_CONFIGDATA; - if(EP_IS_IN(ep)) - { + if(EP_IS_IN(ep)) { csr = (USB_INCSR_FF | USB_INCSR_CDT); csrh = USB_INCSRH_MODE; - if(ep->type == ep_interrupt) + if (ep->type == ep_interrupt) csrh |= USB_INCSRH_FRCDATATOG; REG_USB_INMAXP = ep->fifo_size; @@ -754,9 +729,7 @@ static void setup_endpoint(struct usb_endpoint *ep) if (ep->allocated) REG_USB_INTRINE |= USB_INTR_EP(EP_NUMBER2(ep)); - } - else - { + } else { csr = (USB_OUTCSR_FF | USB_OUTCSR_CDT); csrh = 0; @@ -813,8 +786,7 @@ static void udc_reset(void) endpoints[0].config = REG_USB_CONFIGDATA; endpoints[1].config = REG_USB_CONFIGDATA; - if (endpoints[0].busy) - { + if (endpoints[0].busy) { if (endpoints[0].wait) semaphore_release(&endpoints[0].complete); else @@ -837,7 +809,7 @@ static void udc_reset(void) endpoints[1].allocated = true; /* Reset other endpoints */ - for(i=2; i<TOTAL_EP(); i++) + for (i=2; i<TOTAL_EP(); i++) setup_endpoint(&endpoints[i]); ep0_data_supplied = false; @@ -864,26 +836,26 @@ void OTG(void) logf("IRQ %x %x %x %x", intrUSB, intrIn, intrOut, intrDMA); /* EPIN & EPOUT are all handled in DMA */ - if(intrIn & USB_INTR_EP(0)) + if (intrIn & USB_INTR_EP(0)) EP0_handler(); - if(intrIn & USB_INTR_EP(1)) + if (intrIn & USB_INTR_EP(1)) EPIN_complete(1); - if(intrIn & USB_INTR_EP(2)) + if (intrIn & USB_INTR_EP(2)) EPIN_complete(2); - if(intrOut & USB_INTR_EP(1)) + if (intrOut & USB_INTR_EP(1)) EPOUT_ready(1); - if(intrOut & USB_INTR_EP(2)) + if (intrOut & USB_INTR_EP(2)) EPOUT_ready(2); - if(intrUSB & USB_INTR_RESET) + if (intrUSB & USB_INTR_RESET) udc_reset(); - if(intrUSB & USB_INTR_SUSPEND) + if (intrUSB & USB_INTR_SUSPEND) logf("USB suspend"); - if(intrUSB & USB_INTR_RESUME) + if (intrUSB & USB_INTR_RESUME) logf("USB resume"); #ifdef USE_USB_DMA - if(intrDMA & (1<<USB_INTR_DMA_BULKIN)) + if (intrDMA & (1<<USB_INTR_DMA_BULKIN)) EPDMA_handler(USB_INTR_DMA_BULKIN); - if(intrDMA & (1<<USB_INTR_DMA_BULKOUT)) + if (intrDMA & (1<<USB_INTR_DMA_BULKOUT)) EPDMA_handler(USB_INTR_DMA_BULKOUT); #endif } @@ -896,11 +868,10 @@ bool usb_drv_stalled(int endpoint, bool in) select_endpoint(endpoint); - if(endpoint == EP_CONTROL) + if (endpoint == EP_CONTROL) { return (REG_USB_CSR0 & USB_CSR0_SENDSTALL) != 0; - else - { - if(in) + } else { + if (in) return (REG_USB_INCSR & USB_INCSR_SENDSTALL) != 0; else return (REG_USB_OUTCSR & USB_OUTCSR_SENDSTALL) != 0; @@ -915,24 +886,18 @@ void usb_drv_stall(int endpoint, bool stall, bool in) select_endpoint(endpoint); - if(endpoint == EP_CONTROL) - { + if(endpoint == EP_CONTROL) { if(stall) REG_USB_CSR0 |= USB_CSR0_SENDSTALL; else REG_USB_CSR0 &= ~USB_CSR0_SENDSTALL; - } - else - { - if(in) - { + } else { + if(in) { if(stall) REG_USB_INCSR |= USB_INCSR_SENDSTALL; else REG_USB_INCSR = (REG_USB_INCSR & ~USB_INCSR_SENDSTALL) | USB_INCSR_CDT; - } - else - { + } else { if(stall) REG_USB_OUTCSR |= USB_OUTCSR_SENDSTALL; else @@ -965,7 +930,7 @@ void usb_init_device(void) system_enable_irq(IRQ_OTG); - for(unsigned i=0; i<TOTAL_EP(); i++) + for (unsigned i=0; i<TOTAL_EP(); i++) semaphore_init(&endpoints[i].complete, 1, 0); } @@ -979,7 +944,7 @@ static int usb_oneshot_callback(struct timeout *tmo) * and post appropriate event. */ usb_status_event(state); - if(state == USB_EXTRACTED) + if (state == USB_EXTRACTED) __gpio_as_irq_rise_edge(PIN_USB_DET); else __gpio_as_irq_fall_edge(PIN_USB_DET); @@ -996,7 +961,7 @@ void GPIO_USB_DET(void) void usb_enable(bool on) { - if(on) + if (on) usb_core_init(); else usb_core_exit(); @@ -1070,7 +1035,7 @@ 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 { @@ -1085,7 +1050,7 @@ static void usb_drv_send_internal(struct usb_endpoint* ep, void* ptr, int length restore_irq(flags); - if(blocking) { + if (blocking) { semaphore_wait(&ep->complete, HZ); ep->wait = false; } @@ -1097,8 +1062,7 @@ int usb_drv_send_nonblocking(int endpoint, void* ptr, int length) logf("%s(%d, 0x%x, %d)", __func__, endpoint, (int)ptr, length); - if (ep->allocated) - { + if (ep->allocated) { usb_drv_send_internal(ep, ptr, length, false); return 0; } @@ -1112,8 +1076,7 @@ int usb_drv_send(int endpoint, void* ptr, int length) logf("%s(%d, 0x%x, %d)", __func__, endpoint, (int)ptr, length); - if (ep->allocated) - { + if (ep->allocated) { usb_drv_send_internal(ep, ptr, length, true); return ep->rc; } @@ -1188,7 +1151,8 @@ void usb_drv_cancel_all_transfers(void) { logf("%s()", __func__); - unsigned int i, flags = disable_irq_save(); + unsigned int i; + unsigned int flags = disable_irq_save(); #ifdef USE_USB_DMA /* Disable DMA */ @@ -1204,7 +1168,8 @@ void usb_drv_cancel_all_transfers(void) usb_core_transfer_complete(i >> 1, USB_DIR_OUT, -1, 0); else if (endpoints[i].wait) semaphore_release(&endpoints[i].complete); - else usb_core_transfer_complete(i >> 1, USB_DIR_IN, -1, 0); + else + usb_core_transfer_complete(i >> 1, USB_DIR_IN, -1, 0); } if(i != 1) /* ep0 out needs special handling */ diff --git a/firmware/target/mips/ingenic_x1000/boot-x1000.c b/firmware/target/mips/ingenic_x1000/boot-x1000.c index aa97bfcd85..2f2714c67a 100644 --- a/firmware/target/mips/ingenic_x1000/boot-x1000.c +++ b/firmware/target/mips/ingenic_x1000/boot-x1000.c @@ -20,6 +20,7 @@ ****************************************************************************/ #include "system.h" +#include "usb.h" #include "boot-x1000.h" #include "nand-x1000.h" #include "gpio-x1000.h" @@ -113,6 +114,14 @@ void x1000_boot_linux(const void* source, size_t length, { size_t args_len = strlen(args); + /* Shut off USB to avoid "irq 21 nobody cared" error */ + usb_close(); + usb_enable(false); + + /* clear USB PHY voodoo bits, not all kernels use them */ + jz_writef(CPM_OPCR, GATE_USBPHY_CLK(0)); + jz_writef(CPM_USBCDR, PHY_GATE(0)); + disable_irq(); /* --- Beyond this point, do not call into DRAM --- */ @@ -121,7 +130,7 @@ void x1000_boot_linux(const void* source, size_t length, /* copy argument string to a safe location */ char* args_copy = safe_mem + 32; - iram_memmove(args_copy, args, args_len); + iram_memmove(args_copy, args, args_len+1); /* generate argv array */ char** argv = safe_mem; @@ -151,10 +160,6 @@ void x1000_dualboot_cleanup(void) jz_writef(LCD_CTRL, BEDN(0), EOFM(0), SOFM(0), IFUM(0), QDM(0)); jz_writef(CPM_CLKGR, LCD(1)); - /* clear USB PHY voodoo bits, not all kernels use them */ - jz_writef(CPM_OPCR, GATE_USBPHY_CLK(0)); - jz_writef(CPM_USBCDR, PHY_GATE(0)); - #if defined(FIIO_M3K) || defined(EROS_QN) /* * Need to bring up MPLL before booting Linux @@ -262,7 +267,7 @@ void x1000_dualboot_init_uart2(void) int x1000_dualboot_load_pdma_fw(void) { - nand_drv* n = nand_init(); + struct nand_drv* n = nand_init(); nand_lock(n); int ret = nand_open(n); diff --git a/firmware/target/mips/ingenic_x1000/boot-x1000.h b/firmware/target/mips/ingenic_x1000/boot-x1000.h index 1b7a0db1e9..eb476c513d 100644 --- a/firmware/target/mips/ingenic_x1000/boot-x1000.h +++ b/firmware/target/mips/ingenic_x1000/boot-x1000.h @@ -36,10 +36,10 @@ enum { }; void x1000_boot_rockbox(const void* source, size_t length) - __attribute__((section(".icode"))); + __attribute__((section(".icode.x1000_boot_rockbox"))); void x1000_boot_linux(const void* source, size_t length, void* load, void* entry, const char* args) - __attribute__((section(".icode"))); + __attribute__((section(".icode.x1000_boot_linux"))); /* dual boot support code */ void x1000_dualboot_cleanup(void); diff --git a/firmware/target/mips/ingenic_x1000/crt0.S b/firmware/target/mips/ingenic_x1000/crt0.S index d079b01e2a..9d89ac1227 100644 --- a/firmware/target/mips/ingenic_x1000/crt0.S +++ b/firmware/target/mips/ingenic_x1000/crt0.S @@ -110,7 +110,7 @@ _realstart: jal system_early_init nop j main - nop + move ra, zero /* init backtrace root */ /* copy(void* src, void* dst, void* dst_end) */ _copy: diff --git a/firmware/target/mips/ingenic_x1000/installer-x1000.c b/firmware/target/mips/ingenic_x1000/installer-x1000.c index 66aa42d4a1..48850f8a62 100644 --- a/firmware/target/mips/ingenic_x1000/installer-x1000.c +++ b/firmware/target/mips/ingenic_x1000/installer-x1000.c @@ -65,7 +65,7 @@ static const int num_updates = sizeof(updates) / sizeof(struct update_part); /* calculate the offset and length of the update image; this is constant * for a given target, based on the update parts and the NAND chip geometry. */ -static void get_image_loc(nand_drv* ndrv, size_t* offptr, size_t* lenptr) +static void get_image_loc(struct nand_drv* ndrv, size_t* offptr, size_t* lenptr) { size_t blk_size = ndrv->chip->page_size << ndrv->chip->log2_ppb; size_t img_off = 0; @@ -119,7 +119,7 @@ struct updater { size_t img_len; /* image length in flash = size of the buffer */ mtar_t* tar; - nand_drv* ndrv; + struct nand_drv* ndrv; }; static int updater_init(struct updater* u) diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.c b/firmware/target/mips/ingenic_x1000/nand-x1000.c index 5838b21b39..827a79ebce 100644 --- a/firmware/target/mips/ingenic_x1000/nand-x1000.c +++ b/firmware/target/mips/ingenic_x1000/nand-x1000.c @@ -22,49 +22,15 @@ #include "nand-x1000.h" #include "sfc-x1000.h" #include "system.h" +#include "logf.h" #include <string.h> -/* cmd mode a d phase format has data */ -#define NANDCMD_RESET SFC_CMD(0xff, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0) -#define NANDCMD_READID(x,y) SFC_CMD(0x9f, SFC_TMODE_1_1_1, x, y, SFC_PFMT_ADDR_FIRST, 1) -#define NANDCMD_WR_EN SFC_CMD(0x06, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0) -#define NANDCMD_GET_FEATURE SFC_CMD(0x0f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1) -#define NANDCMD_SET_FEATURE SFC_CMD(0x1f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1) -#define NANDCMD_PAGE_READ(x) SFC_CMD(0x13, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 0) -#define NANDCMD_READ_CACHE(x) SFC_CMD(0x0b, SFC_TMODE_1_1_1, x, 8, SFC_PFMT_ADDR_FIRST, 1) -#define NANDCMD_READ_CACHE_x4(x) SFC_CMD(0x6b, SFC_TMODE_1_1_4, x, 8, SFC_PFMT_ADDR_FIRST, 1) -#define NANDCMD_PROGRAM_LOAD(x) SFC_CMD(0x02, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 1) -#define NANDCMD_PROGRAM_LOAD_x4(x) SFC_CMD(0x32, SFC_TMODE_1_1_4, x, 0, SFC_PFMT_ADDR_FIRST, 1) -#define NANDCMD_PROGRAM_EXECUTE(x) SFC_CMD(0x10, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 0) -#define NANDCMD_BLOCK_ERASE(x) SFC_CMD(0xd8, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 0) - -/* Feature registers are found in linux/mtd/spinand.h, - * apparently these are pretty standardized */ -#define FREG_PROT 0xa0 -#define FREG_PROT_UNLOCK 0x00 - -#define FREG_CFG 0xb0 -#define FREG_CFG_OTP_ENABLE (1 << 6) -#define FREG_CFG_ECC_ENABLE (1 << 4) -#define FREG_CFG_QUAD_ENABLE (1 << 0) - -#define FREG_STATUS 0xc0 -#define FREG_STATUS_BUSY (1 << 0) -#define FREG_STATUS_EFAIL (1 << 2) -#define FREG_STATUS_PFAIL (1 << 3) -#define FREG_STATUS_ECC_MASK (3 << 4) -#define FREG_STATUS_ECC_NO_FLIPS (0 << 4) -#define FREG_STATUS_ECC_HAS_FLIPS (1 << 4) -#define FREG_STATUS_ECC_UNCOR_ERR (2 << 4) - -const nand_chip supported_nand_chips[] = { +const struct nand_chip supported_nand_chips[] = { #if defined(FIIO_M3K) || defined(SHANLING_Q1) || defined(EROS_QN) { /* ATO25D1GA */ .mf_id = 0x9b, .dev_id = 0x12, - .row_cycles = 3, - .col_cycles = 2, .log2_ppb = 6, /* 64 pages */ .page_size = 2048, .oob_size = 64, @@ -78,20 +44,24 @@ const nand_chip supported_nand_chips[] = { STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS), SMP_DELAY(1)), .flags = NAND_CHIPFLAG_QUAD | NAND_CHIPFLAG_HAS_QE_BIT, + .cmd_page_read = NANDCMD_PAGE_READ, + .cmd_program_execute = NANDCMD_PROGRAM_EXECUTE, + .cmd_block_erase = NANDCMD_BLOCK_ERASE, + .cmd_read_cache = NANDCMD_READ_CACHE_x4, + .cmd_program_load = NANDCMD_PROGRAM_LOAD_x4, }, #else { 0 }, #endif }; -const size_t nr_supported_nand_chips = - sizeof(supported_nand_chips) / sizeof(nand_chip); +const size_t nr_supported_nand_chips = ARRAYLEN(supported_nand_chips); -static nand_drv static_nand_drv; +static struct nand_drv static_nand_drv; static uint8_t static_scratch_buf[NAND_DRV_SCRATCHSIZE] CACHEALIGN_ATTR; static uint8_t static_page_buf[NAND_DRV_MAXPAGESIZE] CACHEALIGN_ATTR; -nand_drv* nand_init(void) +struct nand_drv* nand_init(void) { static bool inited = false; if(!inited) { @@ -104,19 +74,19 @@ nand_drv* nand_init(void) return &static_nand_drv; } -static uint8_t nand_get_reg(nand_drv* drv, uint8_t reg) +static uint8_t nand_get_reg(struct nand_drv* drv, uint8_t reg) { sfc_exec(NANDCMD_GET_FEATURE, reg, drv->scratch_buf, 1|SFC_READ); return drv->scratch_buf[0]; } -static void nand_set_reg(nand_drv* drv, uint8_t reg, uint8_t val) +static void nand_set_reg(struct nand_drv* drv, uint8_t reg, uint8_t val) { drv->scratch_buf[0] = val; sfc_exec(NANDCMD_SET_FEATURE, reg, drv->scratch_buf, 1|SFC_WRITE); } -static void nand_upd_reg(nand_drv* drv, uint8_t reg, uint8_t msk, uint8_t val) +static void nand_upd_reg(struct nand_drv* drv, uint8_t reg, uint8_t msk, uint8_t val) { uint8_t x = nand_get_reg(drv, reg); x &= ~msk; @@ -124,56 +94,43 @@ static void nand_upd_reg(nand_drv* drv, uint8_t reg, uint8_t msk, uint8_t val) nand_set_reg(drv, reg, x); } -static bool identify_chip(nand_drv* drv) +static bool identify_chip(struct nand_drv* drv) { /* Read ID command has some variations; Linux handles these 3: * - no address or dummy bytes * - 1 byte address, no dummy byte * - no address byte, 1 byte dummy * - * Right now there is only a need for the 2nd variation, as that is - * the method used by the ATO25D1GA. - * - * Some chips also output more than 2 ID bytes. + * Currently we use the 2nd method, aka. address read ID. */ - sfc_exec(NANDCMD_READID(1, 0), 0, drv->scratch_buf, 2|SFC_READ); + sfc_exec(NANDCMD_READID_ADDR, 0, drv->scratch_buf, 4|SFC_READ); drv->mf_id = drv->scratch_buf[0]; drv->dev_id = drv->scratch_buf[1]; + drv->dev_id2 = drv->scratch_buf[2]; for(size_t i = 0; i < nr_supported_nand_chips; ++i) { - const nand_chip* chip = &supported_nand_chips[i]; - if(chip->mf_id == drv->mf_id && chip->dev_id == drv->dev_id) { - drv->chip = chip; - return true; - } + const struct nand_chip* chip = &supported_nand_chips[i]; + if(chip->mf_id != drv->mf_id || chip->dev_id != drv->dev_id) + continue; + + if((chip->flags & NAND_CHIPFLAG_HAS_DEVID2) && + chip->dev_id2 != drv->dev_id2) + continue; + + drv->chip = chip; + return true; } return false; } -static void setup_chip_data(nand_drv* drv) +static void setup_chip_data(struct nand_drv* drv) { drv->ppb = 1 << drv->chip->log2_ppb; drv->fpage_size = drv->chip->page_size + drv->chip->oob_size; } -static void setup_chip_commands(nand_drv* drv) -{ - /* Select commands appropriate for the chip */ - drv->cmd_page_read = NANDCMD_PAGE_READ(drv->chip->row_cycles); - drv->cmd_program_execute = NANDCMD_PROGRAM_EXECUTE(drv->chip->row_cycles); - drv->cmd_block_erase = NANDCMD_BLOCK_ERASE(drv->chip->row_cycles); - - if(drv->chip->flags & NAND_CHIPFLAG_QUAD) { - drv->cmd_read_cache = NANDCMD_READ_CACHE_x4(drv->chip->col_cycles); - drv->cmd_program_load = NANDCMD_PROGRAM_LOAD_x4(drv->chip->col_cycles); - } else { - drv->cmd_read_cache = NANDCMD_READ_CACHE(drv->chip->col_cycles); - drv->cmd_program_load = NANDCMD_PROGRAM_LOAD(drv->chip->col_cycles); - } -} - -static void setup_chip_registers(nand_drv* drv) +static void setup_chip_registers(struct nand_drv* drv) { /* Set chip registers to enter normal operation */ if(drv->chip->flags & NAND_CHIPFLAG_HAS_QE_BIT) { @@ -182,14 +139,23 @@ static void setup_chip_registers(nand_drv* drv) en ? FREG_CFG_QUAD_ENABLE : 0); } + if(drv->chip->flags & NAND_CHIPFLAG_ON_DIE_ECC) { + /* Enable on-die ECC */ + nand_upd_reg(drv, FREG_CFG, FREG_CFG_ECC_ENABLE, FREG_CFG_ECC_ENABLE); + } + /* Clear OTP bit to access the main data array */ nand_upd_reg(drv, FREG_CFG, FREG_CFG_OTP_ENABLE, 0); /* Clear write protection bits */ nand_set_reg(drv, FREG_PROT, FREG_PROT_UNLOCK); + + /* Call any chip-specific hooks */ + if(drv->chip->setup_chip) + drv->chip->setup_chip(drv); } -int nand_open(nand_drv* drv) +int nand_open(struct nand_drv* drv) { if(drv->refcount > 0) { drv->refcount++; @@ -210,7 +176,6 @@ int nand_open(nand_drv* drv) return NAND_ERR_UNKNOWN_CHIP; setup_chip_data(drv); - setup_chip_commands(drv); /* Set new SFC parameters */ sfc_set_dev_conf(drv->chip->dev_conf); @@ -223,7 +188,7 @@ int nand_open(nand_drv* drv) return NAND_SUCCESS; } -void nand_close(nand_drv* drv) +void nand_close(struct nand_drv* drv) { --drv->refcount; if(drv->refcount > 0) @@ -237,7 +202,13 @@ void nand_close(nand_drv* drv) sfc_close(); } -static uint8_t nand_wait_busy(nand_drv* drv) +void nand_enable_otp(struct nand_drv* drv, bool enable) +{ + nand_upd_reg(drv, FREG_CFG, FREG_CFG_OTP_ENABLE, + enable ? FREG_CFG_OTP_ENABLE : 0); +} + +static uint8_t nand_wait_busy(struct nand_drv* drv) { uint8_t reg; do { @@ -246,10 +217,10 @@ static uint8_t nand_wait_busy(nand_drv* drv) return reg; } -int nand_block_erase(nand_drv* drv, nand_block_t block) +int nand_block_erase(struct nand_drv* drv, nand_block_t block) { sfc_exec(NANDCMD_WR_EN, 0, NULL, 0); - sfc_exec(drv->cmd_block_erase, block, NULL, 0); + sfc_exec(drv->chip->cmd_block_erase, block, NULL, 0); uint8_t status = nand_wait_busy(drv); if(status & FREG_STATUS_EFAIL) @@ -258,11 +229,12 @@ int nand_block_erase(nand_drv* drv, nand_block_t block) return NAND_SUCCESS; } -int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer) +int nand_page_program(struct nand_drv* drv, nand_page_t page, const void* buffer) { sfc_exec(NANDCMD_WR_EN, 0, NULL, 0); - sfc_exec(drv->cmd_program_load, 0, (void*)buffer, drv->fpage_size|SFC_WRITE); - sfc_exec(drv->cmd_program_execute, page, NULL, 0); + sfc_exec(drv->chip->cmd_program_load, + 0, (void*)buffer, drv->fpage_size|SFC_WRITE); + sfc_exec(drv->chip->cmd_program_execute, page, NULL, 0); uint8_t status = nand_wait_busy(drv); if(status & FREG_STATUS_PFAIL) @@ -271,15 +243,29 @@ int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer) return NAND_SUCCESS; } -int nand_page_read(nand_drv* drv, nand_page_t page, void* buffer) +int nand_page_read(struct nand_drv* drv, nand_page_t page, void* buffer) { - sfc_exec(drv->cmd_page_read, page, NULL, 0); + sfc_exec(drv->chip->cmd_page_read, page, NULL, 0); nand_wait_busy(drv); - sfc_exec(drv->cmd_read_cache, 0, buffer, drv->fpage_size|SFC_READ); + sfc_exec(drv->chip->cmd_read_cache, 0, buffer, drv->fpage_size|SFC_READ); + + if(drv->chip->flags & NAND_CHIPFLAG_ON_DIE_ECC) { + uint8_t status = nand_get_reg(drv, FREG_STATUS); + + if(status & FREG_STATUS_ECC_UNCOR_ERR) { + logf("ecc uncorrectable error on page %08lx", (unsigned long)page); + return NAND_ERR_ECC_FAIL; + } + + if(status & FREG_STATUS_ECC_HAS_FLIPS) { + logf("ecc corrected bitflips on page %08lx", (unsigned long)page); + } + } + return NAND_SUCCESS; } -int nand_read_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer) +int nand_read_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer) { if(byte_len == 0) return NAND_SUCCESS; @@ -307,7 +293,7 @@ int nand_read_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* return NAND_SUCCESS; } -int nand_write_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer) +int nand_write_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer) { if(byte_len == 0) return NAND_SUCCESS; diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.h b/firmware/target/mips/ingenic_x1000/nand-x1000.h index 668b3e3f82..227c71e3f4 100644 --- a/firmware/target/mips/ingenic_x1000/nand-x1000.h +++ b/firmware/target/mips/ingenic_x1000/nand-x1000.h @@ -32,6 +32,7 @@ #define NAND_ERR_PROGRAM_FAIL (-2) #define NAND_ERR_ERASE_FAIL (-3) #define NAND_ERR_UNALIGNED (-4) +#define NAND_ERR_ECC_FAIL (-5) /* keep max page size in sync with the NAND chip table in the .c file */ #define NAND_DRV_SCRATCHSIZE 32 @@ -41,6 +42,46 @@ #define NAND_CHIPFLAG_QUAD 0x0001 /* Chip requires QE bit set to enable quad I/O mode */ #define NAND_CHIPFLAG_HAS_QE_BIT 0x0002 +/* Chip has 2nd device ID byte */ +#define NAND_CHIPFLAG_HAS_DEVID2 0x0004 +/* True if the chip has on-die ECC */ +#define NAND_CHIPFLAG_ON_DIE_ECC 0x0008 + +/* cmd mode a d phase format has data */ +#define NANDCMD_RESET SFC_CMD(0xff, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0) +#define NANDCMD_READID_OPCODE SFC_CMD(0x9f, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_READID_ADDR SFC_CMD(0x9f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_READID_DUMMY SFC_CMD(0x9f, SFC_TMODE_1_1_1, 0, 8, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_WR_EN SFC_CMD(0x06, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0) +#define NANDCMD_GET_FEATURE SFC_CMD(0x0f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_SET_FEATURE SFC_CMD(0x1f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_PAGE_READ SFC_CMD(0x13, SFC_TMODE_1_1_1, 3, 0, SFC_PFMT_ADDR_FIRST, 0) +#define NANDCMD_READ_CACHE_SLOW SFC_CMD(0x03, SFC_TMODE_1_1_1, 2, 8, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_READ_CACHE SFC_CMD(0x0b, SFC_TMODE_1_1_1, 2, 8, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_READ_CACHE_x4 SFC_CMD(0x6b, SFC_TMODE_1_1_4, 2, 8, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_PROGRAM_EXECUTE SFC_CMD(0x10, SFC_TMODE_1_1_1, 3, 0, SFC_PFMT_ADDR_FIRST, 0) +#define NANDCMD_PROGRAM_LOAD SFC_CMD(0x02, SFC_TMODE_1_1_1, 2, 0, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_PROGRAM_LOAD_x4 SFC_CMD(0x32, SFC_TMODE_1_1_4, 2, 0, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_BLOCK_ERASE SFC_CMD(0xd8, SFC_TMODE_1_1_1, 3, 0, SFC_PFMT_ADDR_FIRST, 0) + +/* Feature registers are found in linux/mtd/spinand.h, + * apparently these are pretty standardized */ +#define FREG_PROT 0xa0 +#define FREG_PROT_UNLOCK 0x00 + +#define FREG_CFG 0xb0 +#define FREG_CFG_OTP_ENABLE (1 << 6) +#define FREG_CFG_ECC_ENABLE (1 << 4) +#define FREG_CFG_QUAD_ENABLE (1 << 0) + +#define FREG_STATUS 0xc0 +#define FREG_STATUS_BUSY (1 << 0) +#define FREG_STATUS_EFAIL (1 << 2) +#define FREG_STATUS_PFAIL (1 << 3) +#define FREG_STATUS_ECC_MASK (3 << 4) +#define FREG_STATUS_ECC_NO_FLIPS (0 << 4) +#define FREG_STATUS_ECC_HAS_FLIPS (1 << 4) +#define FREG_STATUS_ECC_UNCOR_ERR (2 << 4) /* Types to distinguish between block & page addresses in the API. * @@ -59,14 +100,13 @@ typedef uint32_t nand_block_t; typedef uint32_t nand_page_t; -typedef struct nand_chip { +struct nand_drv; + +struct nand_chip { /* Manufacturer and device ID bytes */ uint8_t mf_id; uint8_t dev_id; - - /* Row/column address width */ - uint8_t row_cycles; - uint8_t col_cycles; + uint8_t dev_id2; /* Base2 logarithm of the number of pages per block */ unsigned log2_ppb; @@ -89,9 +129,19 @@ typedef struct nand_chip { /* Chip specific flags */ uint32_t flags; -} nand_chip; -typedef struct nand_drv { + /* SFC commands for issuing I/O ops */ + uint32_t cmd_page_read; + uint32_t cmd_program_execute; + uint32_t cmd_block_erase; + uint32_t cmd_read_cache; + uint32_t cmd_program_load; + + /* Chip-specific setup routine */ + void(*setup_chip)(struct nand_drv* drv); +}; + +struct nand_drv { /* NAND access lock. Needs to be held during any operations. */ struct mutex mutex; @@ -113,7 +163,7 @@ typedef struct nand_drv { uint8_t* page_buf; /* Pointer to the chip data. */ - const nand_chip* chip; + const struct nand_chip* chip; /* Pages per block = 1 << chip->log2_ppb */ unsigned ppb; @@ -124,16 +174,10 @@ typedef struct nand_drv { /* Probed mf_id / dev_id for debugging, in case identification fails. */ uint8_t mf_id; uint8_t dev_id; + uint8_t dev_id2; +}; - /* SFC commands used for I/O, these are set based on chip data */ - uint32_t cmd_page_read; - uint32_t cmd_read_cache; - uint32_t cmd_program_load; - uint32_t cmd_program_execute; - uint32_t cmd_block_erase; -} nand_drv; - -extern const nand_chip supported_nand_chips[]; +extern const struct nand_chip supported_nand_chips[]; extern const size_t nr_supported_nand_chips; /* Return the static NAND driver instance. @@ -141,14 +185,14 @@ extern const size_t nr_supported_nand_chips; * ALL normal Rockbox code should use this instance. The SPL does not * use it, because it needs to manually place buffers in external RAM. */ -extern nand_drv* nand_init(void); +extern struct nand_drv* nand_init(void); -static inline void nand_lock(nand_drv* drv) +static inline void nand_lock(struct nand_drv* drv) { mutex_lock(&drv->mutex); } -static inline void nand_unlock(nand_drv* drv) +static inline void nand_unlock(struct nand_drv* drv) { mutex_unlock(&drv->mutex); } @@ -162,8 +206,11 @@ static inline void nand_unlock(nand_drv* drv) * * These functions require the lock to be held. */ -extern int nand_open(nand_drv* drv); -extern void nand_close(nand_drv* drv); +extern int nand_open(struct nand_drv* drv); +extern void nand_close(struct nand_drv* drv); + +/* Enable/disable OTP access. OTP data pages are usually vendor-specific. */ +void nand_enable_otp(struct nand_drv* drv, bool enable); /* Read / program / erase operations. Buffer needs to be cache-aligned for DMA. * Read and program operate on full page data, ie. including OOB data areas. @@ -171,15 +218,15 @@ extern void nand_close(nand_drv* drv); * NOTE: ECC is not implemented. If it ever needs to be, these functions will * probably use ECC transparently. All code should be written to expect this. */ -extern int nand_block_erase(nand_drv* drv, nand_block_t block); -extern int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer); -extern int nand_page_read(nand_drv* drv, nand_page_t page, void* buffer); +extern int nand_block_erase(struct nand_drv* drv, nand_block_t block); +extern int nand_page_program(struct nand_drv* drv, nand_page_t page, const void* buffer); +extern int nand_page_read(struct nand_drv* drv, nand_page_t page, void* buffer); /* Wrappers to read/write bytes. For simple access to the main data area only. * The write address / length must align to a block boundary. Reads do not have * any alignment requirement. OOB data is never read, and is written as 0xff. */ -extern int nand_read_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer); -extern int nand_write_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer); +extern int nand_read_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer); +extern int nand_write_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer); #endif /* __NAND_X1000_H__ */ diff --git a/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c b/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c index 82a05abf75..24eb42081e 100644 --- a/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c +++ b/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c @@ -23,7 +23,7 @@ #include "gpio-x1000.h" #include "nand-x1000.h" -static nand_drv* ndrv = NULL; +static struct nand_drv* ndrv = NULL; int spl_storage_open(void) { @@ -31,7 +31,7 @@ int spl_storage_open(void) gpioz_configure(GPIO_A, 0x3f << 26, GPIOF_DEVICE(1)); /* Allocate NAND driver manually in DRAM */ - ndrv = spl_alloc(sizeof(nand_drv)); + ndrv = spl_alloc(sizeof(struct nand_drv)); ndrv->page_buf = spl_alloc(NAND_DRV_MAXPAGESIZE); ndrv->scratch_buf = spl_alloc(NAND_DRV_SCRATCHSIZE); ndrv->refcount = 0; |