diff options
author | Maurus Cuelenaere <mcuelenaere@gmail.com> | 2008-08-06 20:39:02 +0000 |
---|---|---|
committer | Maurus Cuelenaere <mcuelenaere@gmail.com> | 2008-08-06 20:39:02 +0000 |
commit | 88ae9024e4a1fec45e867f6a1f6cbea0ae0455bb (patch) | |
tree | 67fd77d2267eeda80987db55692886546a457e59 /firmware/target/mips/ingenic_jz47xx | |
parent | 496e1f7e85f929c487eb89f85ff0fc7edfcf3a27 (diff) |
* Add basic (non-working) support for NAND flash
* Add panicf() handling
* Add not-yet-enabled dma acceleration
* Other (minor) fixes
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18203 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/mips/ingenic_jz47xx')
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c | 277 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/boot.lds | 2 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/crt0.S | 17 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/dma_acc-jz4740.c | 119 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/system-jz4740.c | 32 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/system-target.h | 2 |
6 files changed, 407 insertions, 42 deletions
diff --git a/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c b/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c index 00165b2d2d..c6eb55f0b9 100644 --- a/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c @@ -22,6 +22,9 @@ #include "config.h" #include "jz4740.h" #include "ata.h" +#include "nand_id.h" +#include "system.h" +#include "panic.h" #define NAND_CMD_READ1_00 0x00 #define NAND_CMD_READ1_01 0x01 @@ -35,21 +38,219 @@ #define NAND_CMD_BLOCK_ERASE_CONFIRM 0xD0 #define NAND_CMD_READ_STATUS 0x70 -#define NANDFLASH_CLE 0x00008000 //PA[15] -#define NANDFLASH_ALE 0x00010000 //PA[16] +#define NANDFLASH_CLE 0x00008000 //PA[15] +#define NANDFLASH_ALE 0x00010000 //PA[16] -#define NANDFLASH_BASE 0xB8000000 -#define REG_NAND_DATA (*((volatile unsigned char *) NANDFLASH_BASE)) -#define REG_NAND_CMD (*((volatile unsigned char *) (NANDFLASH_BASE + NANDFLASH_CLE))) -#define REG_NAND_ADDR (*((volatile unsigned char *) (NANDFLASH_BASE + NANDFLASH_ALE))) +#define NANDFLASH_BASE 0xB8000000 +#define REG_NAND_DATA (*((volatile unsigned char *)NANDFLASH_BASE)) +#define REG_NAND_CMD (*((volatile unsigned char *)(NANDFLASH_BASE + NANDFLASH_CLE))) +#define REG_NAND_ADDR (*((volatile unsigned char *)(NANDFLASH_BASE + NANDFLASH_ALE))) -#define JZ_NAND_SET_CLE (NANDFLASH_BASE |= NANDFLASH_CLE) -#define JZ_NAND_CLR_CLE (NANDFLASH_BASE &= ~NANDFLASH_CLE) -#define JZ_NAND_SET_ALE (NANDFLASH_BASE |= NANDFLASH_ALE) -#define JZ_NAND_CLR_ALE (NANDFLASH_BASE &= ~NANDFLASH_ALE) +#define JZ_NAND_SELECT (REG_EMC_NFCSR |= EMC_NFCSR_NFCE1 ) +#define JZ_NAND_DESELECT (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1)) -#define JZ_NAND_SELECT (REG_EMC_NFCSR |= EMC_NFCSR_NFCE1 ) -#define JZ_NAND_DESELECT (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1)) +#define __nand_enable() (REG_EMC_NFCSR |= (EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1)) +#define __nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1)) +#define __nand_ecc_disable() (REG_EMC_NFECR &= ~EMC_NFECR_ECCE) +#define __nand_ecc_encode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_ENCF)) +#define __nand_ecc_decode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_DECF)) +#define __nand_ecc_rs_encoding() \ + (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST | EMC_NFECR_RS | EMC_NFECR_RS_ENCODING) +#define __nand_ecc_rs_decoding() \ + (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST | EMC_NFECR_RS | EMC_NFECR_RS_DECODING) + +#define my__gpio_as_nand() \ +do { \ + REG_GPIO_PXFUNS(1) = 0x1E018000; \ + REG_GPIO_PXSELC(1) = 0x1E018000; \ + REG_GPIO_PXFUNS(2) = 0x30000000; \ + REG_GPIO_PXSELC(2) = 0x30000000; \ + REG_GPIO_PXFUNC(2) = 0x40000000; \ + REG_GPIO_PXSELC(2) = 0x40000000; \ + REG_GPIO_PXDIRC(2) = 0x40000000; \ + REG_GPIO_PXFUNS(1) = 0x00400000; \ + REG_GPIO_PXSELC(1) = 0x00400000; \ +} while (0) + +static struct nand_info* chip_info = NULL; +#define NAND_BLOCK_SIZE (chip_info->pages_per_block * chip_info->page_size) +#define NAND_OOB_SIZE (chip_info->page_size / 32) + +struct nand_page_info_t +{ + unsigned char block_status; + unsigned int reserved; + unsigned short block_addr_field; + unsigned int lifetime; + unsigned char ecc_field[50];//[NAND_OOB_SIZE - 11]; +} __attribute__ ((packed)); + +static void nand_wait_ready(void) +{ + int wait = 100; + while(REG_GPIO_PXPIN(2) & (1 << 30) && wait--); + while (!(REG_GPIO_PXPIN(2) & 0x40000000)); +} + +static inline void nand_read_memcpy(void *target, void *source, unsigned int len) +{ + int ch = 2; + + if(((unsigned int)source < 0xa0000000) && len) + dma_cache_wback_inv((unsigned long)source, len); + + if(((unsigned int)target < 0xa0000000) && len) + dma_cache_wback_inv((unsigned long)target, len); + + REG_DMAC_DSAR(ch) = PHYSADDR((unsigned long)source); + REG_DMAC_DTAR(ch) = PHYSADDR((unsigned long)target); + REG_DMAC_DTCR(ch) = len / 4; + REG_DMAC_DRSR(ch) = DMAC_DRSR_RS_AUTO; + REG_DMAC_DCMD(ch) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT; + REG_DMAC_DCCSR(ch) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES; + while ( REG_DMAC_DTCR(ch) ); +} + +static void rs_correct(unsigned char *buf, int idx, int mask) +{ + int i, j; + unsigned short d, d1, dm; + + i = (idx * 9) >> 3; + j = (idx * 9) & 0x7; + + i = (j == 0) ? (i - 1) : i; + j = (j == 0) ? 7 : (j - 1); + if(i >= 512) + return; + + d = (buf[i] << 8) | buf[i - 1]; + + d1 = (d >> j) & 0x1ff; + d1 ^= mask; + + dm = ~(0x1ff << j); + d = (d & dm) | (d1 << j); + + buf[i - 1] = d & 0xff; + buf[i] = (d >> 8) & 0xff; + + +} + +static inline int nand_rs_correct(unsigned char *data) +{ + unsigned int stat = REG_EMC_NFINTS; + if (stat & EMC_NFINTS_ERR) { + if (stat & EMC_NFINTS_UNCOR) + { + panicf("Uncorrectable ECC error occurred!\n stat = 0x%x", stat); + return -1; + } + else + { + unsigned int errcnt = (stat & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT; + switch (errcnt) + { + case 4: + rs_correct(data, (REG_EMC_NFERR3 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR3 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); + break; + + case 3: + rs_correct(data, (REG_EMC_NFERR2 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR2 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); + break; + + case 2: + rs_correct(data, (REG_EMC_NFERR1 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR1 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); + break; + + case 1: + rs_correct(data, (REG_EMC_NFERR0 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR0 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); + break; + } + } + + } + return 0; +} + +static inline void nand_send_readaddr(unsigned int pageaddr, unsigned int offset) +{ + int i; + + /* Read command */ + REG_NAND_CMD = 0x00; + + /* Write column address */ + for (i = 0; i < chip_info->col_cycles; i++) + { + REG_NAND_ADDR = offset & 0xFF; + offset = offset >> 8; + } + + /* Write row address */ + for (i = 0; i < chip_info->row_cycles; i++) + { + REG_NAND_ADDR = pageaddr & 0xFF; + pageaddr = pageaddr >> 8; + } +} + +static inline void nand_send_readcacheaddr(unsigned short offset) +{ + REG_NAND_CMD = 0x05; + REG_NAND_ADDR = (unsigned char)((offset & 0x000000FF) >> 0); + REG_NAND_ADDR = (unsigned char)((offset & 0x0000FF00) >> 8); + REG_NAND_CMD = 0xe0; +} + +static inline int nand_read_oob(int page, unsigned char *data) +{ + unsigned short i; + + nand_send_readaddr(page, chip_info->page_size); + + REG_NAND_CMD = 0x30; + + nand_wait_ready(); + + for ( i = 0; i < NAND_OOB_SIZE; i++) + *data++ = REG_NAND_ADDR; + + return 0; +} + +static int nand_read_page_info(int page, struct nand_page_info_t *info) +{ + int ret; + + JZ_NAND_SELECT; + ret = nand_read_oob(page, (unsigned char*)info); + JZ_NAND_DESELECT; + + return ret; +} + +static struct nand_page_info_t page_info; + +int jz_nand_read_page (int page, unsigned char *data) +{ + int ret, i; + + JZ_NAND_SELECT; + ret = nand_read_oob(page, &page_info); + + nand_send_readcacheaddr(0); + + /* TODO: use information from page_info */ + + for ( i = 0; i < chip_info->page_size; i++) + *data++ = REG_NAND_ADDR; + + JZ_NAND_DESELECT; + + return ret; +} int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf) { @@ -67,26 +268,40 @@ int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const v return 0; } -static int jz_device_ready(void) -{ - int ready, wait = 10; - while (wait--); - ready = __gpio_get_pin(32*2+30); - return ready; -} - int ata_init(void) -{ - /* - * EMC setup - */ +{ + /* Read/Write timings */ +#define SET_STANDARD_TIMING(x) x = (((x) & ~0xFF) | 0x4621200) + SET_STANDARD_TIMING(REG_EMC_SMCR1); + SET_STANDARD_TIMING(REG_EMC_SMCR2); + SET_STANDARD_TIMING(REG_EMC_SMCR3); + SET_STANDARD_TIMING(REG_EMC_SMCR4); + + /* Set NFE bit */ + REG_EMC_NFCSR = EMC_NFCSR_NFE1; + + __nand_ecc_disable(); + + unsigned char cData[5]; + JZ_NAND_SELECT; + REG_NAND_CMD = NAND_CMD_READ_ID1; + REG_NAND_ADDR = NAND_CMD_READ1_00; + cData[0] = REG_NAND_DATA; + cData[1] = REG_NAND_DATA; + cData[2] = REG_NAND_DATA; + cData[3] = REG_NAND_DATA; + cData[4] = REG_NAND_DATA; + JZ_NAND_DESELECT; + + chip_info = nand_identify(cData); + if(chip_info == NULL) + { + panicf("Unknown NAND flash chip: 0x%x 0x%x 0x%x 0x%x 0x%x", cData[0], + cData[1], cData[2], cData[3], cData[4]); + return -1; + } + + /* Set timings */ - /* Set NFE bit */ - REG_EMC_NFCSR |= EMC_NFCSR_NFE1; - - /* Read/Write timings */ - REG_EMC_SMCR1 = (EMC_SMCR_BL_4 | EMC_SMCR_BW_8BIT | 4 << EMC_SMCR_TAS_BIT - | 4 << EMC_SMCR_TAH_BIT | 4 << EMC_SMCR_TBP_BIT | 4 << EMC_SMCR_TAW_BIT - | 4 << EMC_SMCR_STRV_BIT); return 0; } diff --git a/firmware/target/mips/ingenic_jz47xx/boot.lds b/firmware/target/mips/ingenic_jz47xx/boot.lds index e0569be93f..cba23e972a 100644 --- a/firmware/target/mips/ingenic_jz47xx/boot.lds +++ b/firmware/target/mips/ingenic_jz47xx/boot.lds @@ -58,7 +58,6 @@ SECTIONS *(.irodata); *(.idata); *(.data*); - *(.scommon*); *(.sdata*); . = ALIGN(0x4); _dataend = . ; @@ -92,6 +91,7 @@ SECTIONS *(.bss*); *(.ibss); *(COMMON) + *(.scommon*); _end = .; } > DRAM diff --git a/firmware/target/mips/ingenic_jz47xx/crt0.S b/firmware/target/mips/ingenic_jz47xx/crt0.S index d56bd57f16..2dff67c79f 100644 --- a/firmware/target/mips/ingenic_jz47xx/crt0.S +++ b/firmware/target/mips/ingenic_jz47xx/crt0.S @@ -98,14 +98,15 @@ _init_cache_loop: mtc0 t0, C0_CONFIG nop - //---------------------------------------------------- - // clear BSS section - //---------------------------------------------------- - la t0, _edata - la t1, _end -1: sw zero, 0(t0) - bne t0, t1, 1b - addiu t0, 4 + //---------------------------------------------------- + // clear BSS section + //---------------------------------------------------- + la t0, _edata + la t1, _end +_init_bss_loop: + sw zero, 0(t0) + bne t0, t1, _init_bss_loop + addiu t0, 4 //---------------------------------------------------- // setup stack, jump to C code diff --git a/firmware/target/mips/ingenic_jz47xx/dma_acc-jz4740.c b/firmware/target/mips/ingenic_jz47xx/dma_acc-jz4740.c new file mode 100644 index 0000000000..c4d79a7567 --- /dev/null +++ b/firmware/target/mips/ingenic_jz47xx/dma_acc-jz4740.c @@ -0,0 +1,119 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Maurus Cuelenaere + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "system.h" + +void memset(void *target, unsigned char c, size_t len) +{ + int ch = DMA_CHANNEL; + unsigned int d; + unsigned char *dp; + + if(len < 32) + _memset(target,c,len); + else + { + if(((unsigned int)target < 0xa0000000) && len) + dma_cache_wback_inv((unsigned long)target, len); + + dp = (unsigned char *)((unsigned int)(&d) | 0xa0000000); + *(dp + 0) = c; + *(dp + 1) = c; + *(dp + 2) = c; + *(dp + 3) = c; + REG_DMAC_DSAR(ch) = PHYSADDR((unsigned long)dp); + REG_DMAC_DTAR(ch) = PHYSADDR((unsigned long)target); + REG_DMAC_DTCR(ch) = len / 32; + REG_DMAC_DRSR(ch) = DMAC_DRSR_RS_AUTO; + REG_DMAC_DCMD(ch) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE; + REG_DMAC_DCCSR(ch) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES; + + while (REG_DMAC_DTCR(ch)); + if(len % 32) + { + dp = (unsigned char *)((unsigned int)target + (len & (32 - 1))); + for(d = 0;d < (len % 32); d++) + *dp++ = c; + + } + } +} + +void memset16(void *target, unsigned short c, size_t len) +{ + int ch = DMA_CHANNEL; + unsigned short d; + unsigned short *dp; + + if(len < 32) + _memset16(target,c,len); + else + { + if(((unsigned int)target < 0xa0000000) && len) + dma_cache_wback_inv((unsigned long)target, len); + + d = c; + REG_DMAC_DSAR(ch) = PHYSADDR((unsigned long)&d); + REG_DMAC_DTAR(ch) = PHYSADDR((unsigned long)target); + REG_DMAC_DTCR(ch) = len / 32; + REG_DMAC_DRSR(ch) = DMAC_DRSR_RS_AUTO; + REG_DMAC_DCMD(ch) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | DMAC_DCMD_DS_32BYTE; + REG_DMAC_DCCSR(ch) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES; + + while (REG_DMAC_DTCR(ch)); + if(len % 32) + { + dp = (unsigned short *)((unsigned int)target + (len & (32 - 1))); + for(d = 0; d < (len % 32); d++) + *dp++ = c; + } + } +} + +void memcpy(void *target, const void *source, size_t len) +{ + int ch = DMA_CHANNEL; + unsigned char *dp; + + if(len < 4) + _memcpy(target, source, len); + + if(((unsigned int)source < 0xa0000000) && len) + dma_cache_wback_inv((unsigned long)source, len); + + if(((unsigned int)target < 0xa0000000) && len) + dma_cache_wback_inv((unsigned long)target, len); + + REG_DMAC_DSAR(ch) = PHYSADDR((unsigned long)source); + REG_DMAC_DTAR(ch) = PHYSADDR((unsigned long)target); + REG_DMAC_DTCR(ch) = len / 4; + REG_DMAC_DRSR(ch) = DMAC_DRSR_RS_AUTO; + REG_DMAC_DCMD(ch) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT; + + REG_DMAC_DCCSR(ch) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES; + while (REG_DMAC_DTCR(ch)); + if(len % 4) + { + dp = (unsigned char*)((unsigned int)target + (len & (4 - 1))); + for(i = 0; i < (len % 4); i++) + *dp++ = *source; + } +} diff --git a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c index 30681974da..a4bf76608b 100644 --- a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c @@ -209,6 +209,28 @@ void __dcache_writeback_all(void) SYNC_WB(); } +void dma_cache_wback_inv(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= CACHE_SIZE) + __dcache_writeback_all(); + else + { + unsigned long dc_lsize = CACHE_LINE_SIZE; + + a = addr & ~(dc_lsize - 1); + end = (addr + size - 1) & ~(dc_lsize - 1); + while (1) + { + __flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + if (a == end) + break; + a += dc_lsize; + } + } +} + extern void (*tick_funcs[MAX_NUM_TICK_TASKS])(void); #define USE_RTC_CLOCK 0 @@ -251,15 +273,21 @@ extern unsigned int _vectorsend; /* see boot.lds/app.lds */ void system_main(void) { cli(); - write_c0_status(0x10000400); + write_c0_status(1 << 28 | 1 << 10); /* Enable CP | Mask interrupt 2 */ - memcpy((void *)A_K0BASE, (void *)&_loadaddress, 0x20); + memcpy((void *)A_K0BASE, (void *)&_vectorsstart, 0x20); memcpy((void *)(A_K0BASE + 0x180), (void *)&_vectorsstart, 0x20); memcpy((void *)(A_K0BASE + 0x200), (void *)&_vectorsstart, 0x20); __dcache_writeback_all(); __icache_invalidate_all(); + (*((unsigned int*)(0x80000200))) = 0x42; + (*((unsigned int*)(0x80000204))) = 0x45; + (*((unsigned int*)(0x80000208))) = 0x10020; + + set_c0_status(1 << 22); /* Enable Boot Exception Vectors */ + sti(); detect_clock(); diff --git a/firmware/target/mips/ingenic_jz47xx/system-target.h b/firmware/target/mips/ingenic_jz47xx/system-target.h index c11ad4be1f..f60bcff7c8 100644 --- a/firmware/target/mips/ingenic_jz47xx/system-target.h +++ b/firmware/target/mips/ingenic_jz47xx/system-target.h @@ -101,11 +101,13 @@ static inline void restore_interrupt(int status) #define swap32(x) (((x) & 0xff) << 24 | ((x) & 0xff00) << 8 | ((x) & 0xff0000) >> 8 | ((x) >> 24) & 0xff) #define UNCACHED_ADDRESS(addr) ((unsigned int)(addr) | 0xA0000000) +#define PHYSADDR(x) ((x) & 0x1fffffff) void __dcache_writeback_all(void); void __dcache_invalidate_all(void); void __icache_invalidate_all(void); void __flush_dcache_line(unsigned long addr); +void dma_cache_wback_inv(unsigned long addr, unsigned long size); void sti(void); void cli(void); |