From 1f4efc03049eab97f4dfde5d1020b20edf93c979 Mon Sep 17 00:00:00 2001 From: aleph Date: Thu, 21 Apr 2011 16:30:58 +0000 Subject: [PATCH] sam3 nand driver: initial ECC implementation. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4865 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/cpu/cortex-m3/drv/mt29f_sam3.c | 122 +++++++++++++++++++++----- bertos/cpu/cortex-m3/drv/mt29f_sam3.h | 5 +- bertos/drv/mt29f.h | 4 +- 3 files changed, 105 insertions(+), 26 deletions(-) diff --git a/bertos/cpu/cortex-m3/drv/mt29f_sam3.c b/bertos/cpu/cortex-m3/drv/mt29f_sam3.c index a0a7bfd3..237d7224 100644 --- a/bertos/cpu/cortex-m3/drv/mt29f_sam3.c +++ b/bertos/cpu/cortex-m3/drv/mt29f_sam3.c @@ -101,7 +101,7 @@ * Fourth BA15 BA14 BA13 BA12 BA11 BA10 BA9 BA8 * Fifth LOW LOW LOW LOW LOW LOW LOW BA16 */ -static void getAddrCycles(uint32_t page, size_t offset, uint32_t *cycle0, uint32_t *cycle1234) +static void getAddrCycles(uint32_t page, uint16_t offset, uint32_t *cycle0, uint32_t *cycle1234) { ASSERT(offset < MT29F_PAGE_SIZE); @@ -257,16 +257,22 @@ bool mt29f_getDevId(Mt29f *chip, uint8_t dev_id[5]) } -size_t mt29f_pageRead(Mt29f *chip, uint32_t page, void *buf, size_t offset, size_t size) +static bool checkEcc(void) +{ + // TODO: implement it actually... + LOG_INFO("ECC_SR1: 0x%lx\n", SMC_ECC_SR1); + return true; +} + + +static bool mt29f_readPage(Mt29f *chip, uint32_t page, uint16_t offset) { uint32_t cycle0; uint32_t cycle1234; - ASSERT(offset == 0); - - LOG_INFO("mt29f_pageRead\n"); + LOG_INFO("mt29f_readPage: page 0x%lx off 0x%x\n", page, offset); - getAddrCycles(page, 0, &cycle0, &cycle1234); + getAddrCycles(page, offset, &cycle0, &cycle1234); sendCommand( NFC_CMD_NFCCMD | NFC_CMD_NFCEN | MT29F_CSID | NFC_CMD_ACYCLE_FIVE | NFC_CMD_VCMD2 | @@ -278,27 +284,51 @@ size_t mt29f_pageRead(Mt29f *chip, uint32_t page, void *buf, size_t offset, size { LOG_ERR("mt29f: read timeout\n"); chip->status |= MT29F_ERR_RD_TMOUT; - return 0; + return false; } + return true; +} + + +/* + * Read page data and ECC, checking for errors and fixing them if + * possible. + */ +bool mt29f_read(Mt29f *chip, uint32_t page, void *buf, uint16_t size) +{ + ASSERT(size <= MT29F_DATA_SIZE); + + if (!mt29f_readPage(chip, page, 0)) + return false; + memcpy(buf, (void *)NFC_SRAM_BASE_ADDR, size); - return size; + checkEcc(); + + return true; } -size_t mt29f_pageWrite(Mt29f *chip, uint32_t page, const void *buf, size_t offset, size_t size) +/* + * Write data in NFC SRAM buffer to a NAND page, starting at a given offset. + * Usually offset will be 0 to write data or MT29F_DATA_SIZE to write the spare + * area. + * + * According to datasheet to get ECC computed by hardware is sufficient + * to write the main area. But it seems that in that way the last ECC_PR + * register is not generated. The workaround is to write data and dummy (ff) + * spare data in one write, at this point the last ECC_PR is correct and + * ECC data can be written in the spare area with a second program operation. + */ +static bool mt29f_writePage(Mt29f *chip, uint32_t page, uint16_t offset) { uint32_t cycle0; uint32_t cycle1234; - ASSERT(offset == 0); - - LOG_INFO("mt29f_pageWrite\n"); + LOG_INFO("mt29f_writePage: page 0x%lx off 0x%x\n", page, offset); - memcpy((void *)NFC_SRAM_BASE_ADDR, buf, size); - - getAddrCycles(page, 0, &cycle0, &cycle1234); + getAddrCycles(page, offset, &cycle0, &cycle1234); sendCommand( NFC_CMD_NFCCMD | NFC_CMD_NFCWR | NFC_CMD_NFCEN | MT29F_CSID | NFC_CMD_ACYCLE_FIVE | @@ -309,7 +339,7 @@ size_t mt29f_pageWrite(Mt29f *chip, uint32_t page, const void *buf, size_t offse { LOG_ERR("mt29f: write timeout\n"); chip->status |= MT29F_ERR_WR_TMOUT; - return 0; + return false; } sendCommand( @@ -323,10 +353,54 @@ size_t mt29f_pageWrite(Mt29f *chip, uint32_t page, const void *buf, size_t offse { LOG_ERR("mt29f: error writing page\n"); chip->status |= MT29F_ERR_WRITE; - return 0; + return false; } - return size; + return true; +} + + +/* + * Write data in a page. + */ +static bool mt29f_writePageData(Mt29f *chip, uint32_t page, const void *buf, uint16_t size) +{ + ASSERT(size <= MT29F_DATA_SIZE); + + memset((void *)NFC_SRAM_BASE_ADDR, 0xff, MT29F_PAGE_SIZE); + memcpy((void *)NFC_SRAM_BASE_ADDR, buf, size); + + return mt29f_writePage(chip, page, 0); +} + + +/* + * Write the ECC for a page. + * + * ECC data are extracted from ECC_PRx registers and written + * in the page's spare area. + * For 2048 bytes pages and 1 ECC word each 256 bytes, + * 24 bytes of ECC data are stored. + */ +static bool mt29f_writePageEcc(Mt29f *chip, uint32_t page) +{ + int i; + uint32_t *buf = (uint32_t *)NFC_SRAM_BASE_ADDR; + + memset((void *)NFC_SRAM_BASE_ADDR, 0xff, MT29F_SPARE_SIZE); + + for (i = 0; i < MT29F_ECC_NWORDS; i++) + buf[i] = *((reg32_t *)(SMC_BASE + SMC_ECC_PR0_OFF) + i); + + return mt29f_writePage(chip, page, MT29F_DATA_SIZE); +} + + +bool mt29f_write(Mt29f *chip, uint32_t page, const void *buf, uint16_t size) +{ + return + mt29f_writePageData(chip, page, buf, size) && + mt29f_writePageEcc(chip, page); } @@ -342,7 +416,7 @@ void mt29f_clearError(Mt29f *chip) } -static void initPio(Mt29f *chip) +static void initPio(void) { /* * TODO: put following stuff in hw_ file dependent (and configurable cs?) @@ -368,7 +442,7 @@ static void initPio(Mt29f *chip) } -static void initSmc(Mt29f *chip) +static void initSmc(void) { SMC_SETUP0 = SMC_SETUP_NWE_SETUP(0) | SMC_SETUP_NCS_WR_SETUP(0) @@ -397,7 +471,9 @@ static void initSmc(Mt29f *chip) SMC_CFG = SMC_CFG_PAGESIZE_PS2048_64 | SMC_CFG_EDGECTRL | SMC_CFG_DTOMUL_X1048576 - | SMC_CFG_DTOCYC(0xF); + | SMC_CFG_DTOCYC(0xF) + | SMC_CFG_WSPARE + | SMC_CFG_RSPARE; // Disable SMC interrupts, reset and enable NFC controller SMC_IDR = ~0; @@ -412,8 +488,8 @@ static void initSmc(Mt29f *chip) void mt29f_init(Mt29f *chip) { - initPio(chip); - initSmc(chip); + initPio(); + initSmc(); mt29f_clearError(chip); diff --git a/bertos/cpu/cortex-m3/drv/mt29f_sam3.h b/bertos/cpu/cortex-m3/drv/mt29f_sam3.h index 2d2d7353..284d937b 100644 --- a/bertos/cpu/cortex-m3/drv/mt29f_sam3.h +++ b/bertos/cpu/cortex-m3/drv/mt29f_sam3.h @@ -42,9 +42,12 @@ // MT29F2G08AAD, FIXME: configurable -#define MT29F_PAGE_SIZE 0x800 // 2048 B +#define MT29F_DATA_SIZE 0x800 // 2048 B +#define MT29F_SPARE_SIZE 0x40 // 64 B +#define MT29F_PAGE_SIZE (MT29F_DATA_SIZE + MT29F_SPARE_SIZE) #define MT29F_BLOCK_SIZE 0x20000 // 128 kB #define MT29F_SIZE 0x10000000 // 256 MB +#define MT29F_ECC_NWORDS (MT29F_DATA_SIZE / 256) #define MT29F_CSID NFC_CMD_CSID_0 // Chip select /* diff --git a/bertos/drv/mt29f.h b/bertos/drv/mt29f.h index 9f5fd1b6..2dcc34eb 100644 --- a/bertos/drv/mt29f.h +++ b/bertos/drv/mt29f.h @@ -92,8 +92,8 @@ typedef struct Mt29f void mt29f_init(Mt29f *chip); bool mt29f_getDevId(Mt29f *chip, uint8_t dev_id[5]); int mt29f_blockErase(Mt29f *chip, uint32_t blk); -size_t mt29f_pageRead(Mt29f *chip, uint32_t page, void *buf, size_t offset, size_t size); -size_t mt29f_pageWrite(Mt29f *chip, uint32_t page, const void *buf, size_t offset, size_t size); +bool mt29f_read(Mt29f *chip, uint32_t page, void *buf, uint16_t size); +bool mt29f_write(Mt29f *chip, uint32_t page, const void *buf, uint16_t size); int mt29f_error(Mt29f *chip); void mt29f_clearError(Mt29f *chip); -- 2.25.1