From a003d4c2a077f7c60ab84a6894bcb9c423ec09a7 Mon Sep 17 00:00:00 2001 From: aleph Date: Wed, 4 May 2011 10:03:54 +0000 Subject: [PATCH] mt29f nand driver: add kblock interface. kblock blocks are mapped on nand 128k erase blocks. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4872 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/cpu/cortex-m3/drv/mt29f_sam3.c | 137 +++++++++++++++++++++++--- bertos/cpu/cortex-m3/drv/mt29f_sam3.h | 1 + bertos/drv/mt29f.h | 34 +++++-- 3 files changed, 148 insertions(+), 24 deletions(-) diff --git a/bertos/cpu/cortex-m3/drv/mt29f_sam3.c b/bertos/cpu/cortex-m3/drv/mt29f_sam3.c index 130b251e..1bea6671 100644 --- a/bertos/cpu/cortex-m3/drv/mt29f_sam3.c +++ b/bertos/cpu/cortex-m3/drv/mt29f_sam3.c @@ -332,7 +332,7 @@ static bool mt29f_readPage(Mt29f *chip, uint32_t page, uint16_t offset) * Read page data and ECC, checking for errors. * TODO: fix errors with ECC when possible. */ -bool mt29f_read(Mt29f *chip, uint32_t page, void *buf, uint16_t size) +static bool mt29f_read(Mt29f *chip, uint32_t page, void *buf, uint16_t size) { ASSERT(size <= MT29F_DATA_SIZE); @@ -341,7 +341,7 @@ bool mt29f_read(Mt29f *chip, uint32_t page, void *buf, uint16_t size) memcpy(buf, (void *)NFC_SRAM_BASE_ADDR, size); - return checkEcc(); + return checkEcc(chip); } @@ -442,7 +442,7 @@ static bool mt29f_writePageSpare(Mt29f *chip, uint32_t page) } -bool mt29f_write(Mt29f *chip, uint32_t page, const void *buf, uint16_t size) +static bool mt29f_write(Mt29f *chip, uint32_t page, const void *buf, uint16_t size) { return mt29f_writePageData(chip, page, buf, size) && @@ -450,18 +450,6 @@ bool mt29f_write(Mt29f *chip, uint32_t page, const void *buf, uint16_t size) } -int mt29f_error(Mt29f *chip) -{ - return chip->status; -} - - -void mt29f_clearError(Mt29f *chip) -{ - chip->status = 0; -} - - /* * Check if the given block is marked bad: ONFI standard mandates * that bad block are marked with "00" bytes on the spare area of the @@ -728,10 +716,14 @@ static void initSmc(void) } -bool mt29f_init(Mt29f *chip, struct Heap *heap, uint8_t chip_select) +static bool commonInit(Mt29f *chip, struct Heap *heap, unsigned chip_select) { memset(chip, 0, sizeof(Mt29f)); + DB(chip->kblock.priv.type = KBT_NAND); + chip->kblock.blk_size = MT29F_BLOCK_SIZE; + chip->kblock.blk_cnt = MT29F_NUM_USER_BLOCKS; + chip->chip_select = chip_select; chip->block_map = heap_allocmem(heap, MT29F_NUM_USER_BLOCKS * sizeof(*chip->block_map)); if (!chip->block_map) @@ -748,3 +740,116 @@ bool mt29f_init(Mt29f *chip, struct Heap *heap, uint8_t chip_select) return true; } + +/**************** Kblock interface ****************/ + + +static size_t mt29f_writeDirect(struct KBlock *kblk, block_idx_t idx, const void *buf, size_t offset, size_t size) +{ + ASSERT(offset <= MT29F_BLOCK_SIZE); + ASSERT(offset % MT29F_DATA_SIZE == 0); + ASSERT(size <= MT29F_BLOCK_SIZE); + ASSERT(size % MT29F_DATA_SIZE == 0); + + while (offset < size) + { + uint32_t page = (idx * MT29F_PAGES_PER_BLOCK) + (offset / MT29F_DATA_SIZE); + + if (!mt29f_write(MT29F_CAST(kblk), page, buf, MT29F_DATA_SIZE)) + break; + + offset += MT29F_DATA_SIZE; + buf = (const char *)buf + MT29F_DATA_SIZE; + } + + return offset; +} + + +static size_t mt29f_readDirect(struct KBlock *kblk, block_idx_t idx, void *buf, size_t offset, size_t size) +{ + ASSERT(offset <= MT29F_BLOCK_SIZE); + ASSERT(offset % MT29F_DATA_SIZE == 0); + ASSERT(size <= MT29F_BLOCK_SIZE); + ASSERT(size % MT29F_DATA_SIZE == 0); + + while (offset < size) + { + uint32_t page = (idx * MT29F_PAGES_PER_BLOCK) + (offset / MT29F_DATA_SIZE); + + if (!mt29f_read(MT29F_CAST(kblk), page, buf, MT29F_DATA_SIZE)) + break; + + offset += MT29F_DATA_SIZE; + buf = (char *)buf + MT29F_DATA_SIZE; + } + + return offset; +} + + +static int mt29f_error(struct KBlock *kblk) +{ + Mt29f *chip = MT29F_CAST(kblk); + return chip->status; +} + + +static void mt29f_clearError(struct KBlock *kblk) +{ + Mt29f *chip = MT29F_CAST(kblk); + chip->status = 0; +} + + +static const KBlockVTable mt29f_buffered_vt = +{ + .readDirect = mt29f_readDirect, + .writeDirect = mt29f_writeDirect, + + .readBuf = kblock_swReadBuf, + .writeBuf = kblock_swWriteBuf, + .load = kblock_swLoad, + .store = kblock_swStore, + + .error = mt29f_error, + .clearerr = mt29f_clearError, +}; + +static const KBlockVTable mt29f_unbuffered_vt = +{ + .readDirect = mt29f_readDirect, + .writeDirect = mt29f_writeDirect, + + .error = mt29f_error, + .clearerr = mt29f_clearError, +}; + + +bool mt29f_init(Mt29f *chip, struct Heap *heap, unsigned chip_select) +{ + if (!commonInit(chip, heap, chip_select)) + return false; + + chip->kblock.priv.vt = &mt29f_buffered_vt; + chip->kblock.priv.flags |= KB_BUFFERED; + + chip->kblock.priv.buf = heap_allocmem(heap, MT29F_BLOCK_SIZE); + if (!chip->kblock.priv.buf) + { + LOG_ERR("mt29f: error allocating block buffer\n"); + return false; + } + + // Load the first block in the cache + return mt29f_readDirect(&chip->kblock, 0, chip->kblock.priv.buf, 0, MT29F_DATA_SIZE); +} + + +bool mt29f_initUnbuffered(Mt29f *chip, struct Heap *heap, unsigned chip_select) +{ + chip->kblock.priv.vt = &mt29f_unbuffered_vt; + return commonInit(chip, heap, chip_select); +} + + diff --git a/bertos/cpu/cortex-m3/drv/mt29f_sam3.h b/bertos/cpu/cortex-m3/drv/mt29f_sam3.h index 3a8a9abe..969496a9 100644 --- a/bertos/cpu/cortex-m3/drv/mt29f_sam3.h +++ b/bertos/cpu/cortex-m3/drv/mt29f_sam3.h @@ -46,6 +46,7 @@ #define MT29F_SPARE_SIZE 0x40 // 64 B #define MT29F_PAGE_SIZE (MT29F_DATA_SIZE + MT29F_SPARE_SIZE) #define MT29F_PAGES_PER_BLOCK 64 +#define MT29F_BLOCK_SIZE (MT29F_DATA_SIZE * MT29F_PAGES_PER_BLOCK) #define MT29F_NUM_BLOCKS 2048 #define MT29F_ECC_NWORDS (MT29F_DATA_SIZE / 256) #define MT29F_REMAP_TAG_OFFSET 0x38 diff --git a/bertos/drv/mt29f.h b/bertos/drv/mt29f.h index cf80ea77..e6c8ad7d 100644 --- a/bertos/drv/mt29f.h +++ b/bertos/drv/mt29f.h @@ -37,7 +37,7 @@ * \author Stefano Fedrigo * * $WIZ$ module_name = "mt29f" -* $WIZ$ module_depends = "kfile", "kfile_block", "kblock", "heap" +* $WIZ$ module_depends = "timer", "kblock", "heap" * $WIZ$ module_configuration = "bertos/cfg/cfg_mt29f.h" */ @@ -46,6 +46,7 @@ #include "cfg/cfg_mt29f.h" #include +#include /** @@ -54,8 +55,9 @@ */ #define MT29F_ERR_ERASE BV(1) ///< Error erasing a block #define MT29F_ERR_WRITE BV(2) ///< Error writing a page -#define MT29F_ERR_RD_TMOUT BV(2) ///< Read timeout -#define MT29F_ERR_WR_TMOUT BV(2) ///< Write timeout +#define MT29F_ERR_RD_TMOUT BV(3) ///< Read timeout +#define MT29F_ERR_WR_TMOUT BV(4) ///< Write timeout +#define MT29F_ERR_ECC BV(5) ///< Unrecoverable ECC error /** \} */ @@ -64,6 +66,8 @@ */ typedef struct Mt29f { + KBlock kblock; + uint8_t chip_select; uint8_t status; @@ -71,15 +75,29 @@ typedef struct Mt29f uint16_t remap_start; // First unused remap block } Mt29f; +/* + * Kblock id. + */ +#define KBT_NAND MAKE_ID('N', 'A', 'N', 'D') + +/** +* Convert + ASSERT from generic KBlock to NAND context. +*/ +INLINE Mt29f *MT29F_CAST(KBlock *kb) +{ + ASSERT(kb->priv.type == KBT_NAND); + return (Mt29f *)kb; +} + struct Heap; -bool mt29f_init(Mt29f *chip, struct Heap *heap, uint8_t chip_select); +// Kblock interface +bool mt29f_init(Mt29f *chip, struct Heap *heap, unsigned chip_select); +bool mt29f_initUnbuffered(Mt29f *chip, struct Heap *heap, unsigned chip_select); + +// Private functions: use at your own risk, could change in any moment bool mt29f_getDevId(Mt29f *chip, uint8_t dev_id[5]); int mt29f_blockErase(Mt29f *chip, uint16_t block); -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); #endif /* DRV_MT29F_H */ -- 2.25.1