diff options
author | Maurus Cuelenaere <mcuelenaere@gmail.com> | 2008-09-12 00:07:55 +0000 |
---|---|---|
committer | Maurus Cuelenaere <mcuelenaere@gmail.com> | 2008-09-12 00:07:55 +0000 |
commit | 69ec3bfdbe6821dd39afa735dbe6e89a5e707360 (patch) | |
tree | 0533b02155450fb9c9a3453df8e0986c48c63717 /firmware/target/mips/ingenic_jz47xx | |
parent | 8aa0491fb70ba698949142bfce613aae803d70e0 (diff) |
Get basic NAND driver working on Onda targets
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18499 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 | 587 |
1 files changed, 369 insertions, 218 deletions
diff --git a/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c b/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c index 20a7256f82..134d6d7be2 100644 --- a/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c @@ -18,7 +18,7 @@ * KIND, either express or implied. * ****************************************************************************/ - + #include "config.h" #include "jz4740.h" #include "ata.h" @@ -26,232 +26,381 @@ #include "system.h" #include "panic.h" -#define NAND_CMD_READ1_00 0x00 -#define NAND_CMD_READ1_01 0x01 -#define NAND_CMD_READ2 0x50 -#define NAND_CMD_READ_ID1 0x90 -#define NAND_CMD_READ_ID2 0x91 -#define NAND_CMD_RESET 0xFF -#define NAND_CMD_PAGE_PROGRAM_START 0x80 -#define NAND_CMD_PAGE_PROGRAM_STOP 0x10 -#define NAND_CMD_BLOCK_ERASE_START 0x60 -#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_BASE 0xB8000000 -#define REG_NAND_DATA8 (*((volatile unsigned char *)NANDFLASH_BASE)) -#define REG_NAND_DATA16 (*((volatile unsigned short *)NANDFLASH_BASE)) -#define REG_NAND_DATA REG_NAND_DATA8 -#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_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)) +/* + * Standard NAND flash commands + */ +#define NAND_CMD_READ0 0 +#define NAND_CMD_READ1 1 +#define NAND_CMD_RNDOUT 5 +#define NAND_CMD_PAGEPROG 0x10 +#define NAND_CMD_READOOB 0x50 +#define NAND_CMD_ERASE1 0x60 +#define NAND_CMD_STATUS 0x70 +#define NAND_CMD_STATUS_MULTI 0x71 +#define NAND_CMD_SEQIN 0x80 +#define NAND_CMD_RNDIN 0x85 +#define NAND_CMD_READID 0x90 +#define NAND_CMD_ERASE2 0xd0 +#define NAND_CMD_RESET 0xff + +/* Extended commands for large page devices */ +#define NAND_CMD_READSTART 0x30 +#define NAND_CMD_RNDOUTSTART 0xE0 +#define NAND_CMD_CACHEDPROG 0x15 + +/* Status bits */ +#define NAND_STATUS_FAIL 0x01 +#define NAND_STATUS_FAIL_N1 0x02 +#define NAND_STATUS_TRUE_READY 0x20 +#define NAND_STATUS_READY 0x40 +#define NAND_STATUS_WP 0x80 + +/* + * NAND parameter struct + */ +struct nand_param +{ + unsigned int bus_width; /* data bus width: 8-bit/16-bit */ + unsigned int row_cycle; /* row address cycles: 2/3 */ + unsigned int page_size; /* page size in bytes: 512/2048 */ + unsigned int oob_size; /* oob size in bytes: 16/64 */ + unsigned int page_per_block; /* pages per block: 32/64/128 */ +}; + +/* + * jz4740_nand.c + * + * NAND read routine for JZ4740 + * + * Copyright (c) 2005-2008 Ingenic Semiconductor Inc. + * + */ + +#define NAND_DATAPORT 0xb8000000 +#define NAND_ADDRPORT 0xb8010000 +#define NAND_COMMPORT 0xb8008000 + +#define ECC_BLOCK 512 +#define ECC_POS 6 +#define PAR_SIZE 9 + +#define __nand_cmd(n) (REG8(NAND_COMMPORT) = (n)) +#define __nand_addr(n) (REG8(NAND_ADDRPORT) = (n)) +#define __nand_data8() REG8(NAND_DATAPORT) +#define __nand_data16() REG16(NAND_DATAPORT) + +#define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1) +#define __nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1)) #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 __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 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) +static struct nand_param internal_param; -struct nand_page_info_t +static inline void nand_wait_ready(void) { - 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--); + unsigned int timeout = 1000; + while ((REG_GPIO_PXPIN(2) & 0x40000000) && timeout--); while (!(REG_GPIO_PXPIN(2) & 0x40000000)); } -static inline void nand_read_memcpy(void *target, void *source, unsigned int len) +static inline void nand_read_buf16(void *buf, int count) { - 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) ); + int i; + unsigned short *p = (unsigned short *)buf; + + for (i = 0; i < count; i += 2) + *p++ = __nand_data16(); } -static void rs_correct(unsigned char *buf, int idx, int mask) +static inline void nand_read_buf8(void *buf, int count) { - 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; + int i; + unsigned char *p = (unsigned char *)buf; - dm = ~(0x1ff << j); - d = (d & dm) | (d1 << j); - - buf[i - 1] = d & 0xff; - buf[i] = (d >> 8) & 0xff; - - + for (i = 0; i < count; i++) + *p++ = __nand_data8(); } -static inline int nand_rs_correct(unsigned char *data) +static inline void nand_read_buf(void *buf, int count, int bw) { - 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; + if (bw == 8) + nand_read_buf8(buf, count); + else + nand_read_buf16(buf, count); } -static inline void nand_send_readaddr(unsigned int pageaddr, unsigned int offset) +/* + * Correct 1~9-bit errors in 512-bytes data + */ +static void rs_correct(unsigned char *dat, int idx, int mask) { - 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; - } + int i, j; + unsigned short d, d1, dm; - /* Write row address */ - for (i = 0; i < chip_info->row_cycles; i++) - { - REG_NAND_ADDR = pageaddr & 0xFF; - pageaddr = pageaddr >> 8; - } + i = (idx * 9) >> 3; + j = (idx * 9) & 0x7; + + i = (j == 0) ? (i - 1) : i; + j = (j == 0) ? 7 : (j - 1); + + if (i > 512) return; + + if (i == 512) + d = dat[i - 1]; + else + d = (dat[i] << 8) | dat[i - 1]; + + d1 = (d >> j) & 0x1ff; + d1 ^= mask; + + dm = ~(0x1ff << j); + d = (d & dm) | (d1 << j); + + dat[i - 1] = d & 0xff; + if (i < 512) + dat[i] = (d >> 8) & 0xff; } -static inline void nand_send_readcacheaddr(unsigned short offset) +/* + * Read oob + */ +static int nand_read_oob(int page_addr, unsigned char *buf, int size) { - REG_NAND_CMD = 0x05; - REG_NAND_ADDR = (unsigned char)((offset & 0x000000FF) >> 0); - REG_NAND_ADDR = (unsigned char)((offset & 0x0000FF00) >> 8); - REG_NAND_CMD = 0xe0; + struct nand_param *nandp = &internal_param; + int page_size, row_cycle, bus_width; + int col_addr; + + page_size = nandp->page_size; + row_cycle = nandp->row_cycle; + bus_width = nandp->bus_width; + + if (page_size >= 2048) + col_addr = page_size; + else + col_addr = 0; + + if (page_size >= 2048) + /* Send READ0 command */ + __nand_cmd(NAND_CMD_READ0); + else + /* Send READOOB command */ + __nand_cmd(NAND_CMD_READOOB); + + /* Send column address */ + __nand_addr(col_addr & 0xff); + if (page_size >= 2048) + __nand_addr((col_addr >> 8) & 0xff); + + /* Send page address */ + __nand_addr(page_addr & 0xff); + __nand_addr((page_addr >> 8) & 0xff); + if (row_cycle == 3) + __nand_addr((page_addr >> 16) & 0xff); + + /* Send READSTART command for 2048 ps NAND */ + if (page_size >= 2048) + __nand_cmd(NAND_CMD_READSTART); + + /* Wait for device ready */ + nand_wait_ready(); + + /* Read oob data */ + nand_read_buf(buf, size, bus_width); + + return 0; } -static inline int nand_read_oob(int page, unsigned char *data) + +/* + * nand_read_page() + * + * Input: + * + * block - block number: 0, 1, 2, ... + * page - page number within a block: 0, 1, 2, ... + * dst - pointer to target buffer + */ +static int nand_read_page(int block, int page, unsigned char *dst) { - unsigned short i; - - nand_send_readaddr(page, chip_info->page_size); - - REG_NAND_CMD = 0x30; - + struct nand_param *nandp = &internal_param; + int page_size, oob_size, page_per_block; + int row_cycle, bus_width, ecc_count; + int page_addr, i, j; + unsigned char *data_buf; + unsigned char oob_buf[128]; + + page_size = nandp->page_size; + oob_size = nandp->oob_size; + page_per_block = nandp->page_per_block; + row_cycle = nandp->row_cycle; + bus_width = nandp->bus_width; + + page_addr = page + block * page_per_block; + + /* + * Read oob data + */ + nand_read_oob(page_addr, oob_buf, oob_size); + + /* + * Read page data + */ + + /* Send READ0 command */ + __nand_cmd(NAND_CMD_READ0); + + /* Send column address */ + __nand_addr(0); + if (page_size >= 2048) + __nand_addr(0); + + /* Send page address */ + __nand_addr(page_addr & 0xff); + __nand_addr((page_addr >> 8) & 0xff); + if (row_cycle == 3) + __nand_addr((page_addr >> 16) & 0xff); + + /* Send READSTART command for 2048 ps NAND */ + if (page_size >= 2048) + __nand_cmd(NAND_CMD_READSTART); + + /* Wait for device ready */ nand_wait_ready(); - - for ( i = 0; i < NAND_OOB_SIZE; i++) - *data++ = REG_NAND_ADDR; - + + /* Read page data */ + data_buf = dst; + + ecc_count = page_size / ECC_BLOCK; + + for (i = 0; i < ecc_count; i++) + { + volatile unsigned char *paraddr = (volatile unsigned char *)EMC_NFPAR0; + unsigned int stat; + + /* Enable RS decoding */ + REG_EMC_NFINTS = 0x0; + __nand_ecc_rs_decoding(); + + /* Read data */ + nand_read_buf((void *)data_buf, ECC_BLOCK, bus_width); + + /* Set PAR values */ + for (j = 0; j < PAR_SIZE; j++) + *paraddr++ = oob_buf[ECC_POS + i*PAR_SIZE + j]; + + /* Set PRDY */ + REG_EMC_NFECR |= EMC_NFECR_PRDY; + + /* Wait for completion */ + __nand_ecc_decode_sync(); + + /* Disable decoding */ + __nand_ecc_disable(); + + /* Check result of decoding */ + stat = REG_EMC_NFINTS; + if (stat & EMC_NFINTS_ERR) + { + /* Error occurred */ + if (stat & EMC_NFINTS_UNCOR) { + /* Uncorrectable error occurred */ + } + else + { + unsigned int errcnt, index, mask; + + errcnt = (stat & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT; + switch (errcnt) + { + case 4: + index = (REG_EMC_NFERR3 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT; + mask = (REG_EMC_NFERR3 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT; + rs_correct(data_buf, index, mask); + case 3: + index = (REG_EMC_NFERR2 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT; + mask = (REG_EMC_NFERR2 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT; + rs_correct(data_buf, index, mask); + case 2: + index = (REG_EMC_NFERR1 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT; + mask = (REG_EMC_NFERR1 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT; + rs_correct(data_buf, index, mask); + case 1: + index = (REG_EMC_NFERR0 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT; + mask = (REG_EMC_NFERR0 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT; + rs_correct(data_buf, index, mask); + break; + default: + break; + } + } + } + + data_buf += ECC_BLOCK; + } + return 0; } -static int nand_read_page_info(int page, struct nand_page_info_t *info) +/* + * Enable NAND controller + */ +static void nand_enable(void) { - int ret; - - JZ_NAND_SELECT; - ret = nand_read_oob(page, (unsigned char*)info); - JZ_NAND_DESELECT; - - return ret; + __nand_enable(); + + REG_EMC_SMCR1 = 0x04444400; } -static struct nand_page_info_t page_info; +/* + * Disable NAND controller + */ +static void nand_disable(void) +{ + __nand_disable(); +} -int jz_nand_read_page (int page, unsigned char *data) +int ata_init(void) { - int ret, i; - - JZ_NAND_SELECT; - ret = nand_read_oob(page, &page_info); + unsigned char cData[5]; - nand_send_readcacheaddr(0); + nand_enable(); - /* TODO: use information from page_info */ + __nand_cmd(NAND_CMD_READID); + __nand_addr(NAND_CMD_READ0); + cData[0] = __nand_data8(); + cData[1] = __nand_data8(); + cData[2] = __nand_data8(); + cData[3] = __nand_data8(); + cData[4] = __nand_data8(); - for ( i = 0; i < chip_info->page_size; i++) - *data++ = REG_NAND_ADDR; + 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; + } - JZ_NAND_DESELECT; + internal_param.bus_width = 8; + internal_param.row_cycle = chip_info->row_cycles; + internal_param.page_size = chip_info->page_size; + internal_param.oob_size = chip_info->page_size/32; + internal_param.page_per_block = chip_info->pages_per_block; - return ret; + return 0; +} + +void jz_nand_read(int block, int page, unsigned char *buf) +{ + nand_read_page(block, page, buf); } int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf) @@ -270,40 +419,42 @@ int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const v return 0; } -int ata_init(void) -{ - /* 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 */ - +void ata_spindown(int seconds) +{ + /* null */ + (void)seconds; +} + +bool ata_disk_is_active(void) +{ + /* null */ + return false; +} + +void ata_sleep(void) +{ + /* null */ +} + +void ata_spin(void) +{ + /* null */ +} + +int ata_hard_reset(void) +{ + /* null */ + return 0; +} + +int ata_soft_reset(void) +{ + /* null */ return 0; } + +void ata_enable(bool on) +{ + /* null - flash controller is enabled/disabled as needed. */ + (void)on; +} |