mt29f nand driver: add kblock interface.
authoraleph <aleph@38d2e660-2303-0410-9eaa-f027e97ec537>
Wed, 4 May 2011 10:03:54 +0000 (10:03 +0000)
committeraleph <aleph@38d2e660-2303-0410-9eaa-f027e97ec537>
Wed, 4 May 2011 10:03:54 +0000 (10:03 +0000)
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
bertos/cpu/cortex-m3/drv/mt29f_sam3.h
bertos/drv/mt29f.h

index 130b251eaacf170e9b12d61129f4d6fd8ad8b27a..1bea667176cc17778b98d974090f8838e806e1d7 100644 (file)
@@ -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);
+}
+
+
index 3a8a9abe68cd7dbedebe164af8cca92b54f0333d..969496a97805991ef6d15fec9fefdd13893ff353 100644 (file)
@@ -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
index cf80ea7729964c4c8b2163c658d9799092d42b45..e6c8ad7d9b8859d196caaaec2370112efd6f819f 100644 (file)
@@ -37,7 +37,7 @@
 * \author Stefano Fedrigo <aleph@develer.com>
 *
 * $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 <cfg/macros.h>
+#include <io/kblock.h>
 
 
 /**
@@ -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 */