Move flash related flags to the flash driver; refactor accordingly.
[bertos.git] / bertos / cpu / arm / drv / flash_at91.c
index b20d11313526ba7ae4a84c2f29273b442063641b..514d54e4326811042b4ea7dcafcf0e1f5e815857 100644 (file)
 
 #include "flash_at91.h"
 
-#include "cfg/cfg_flash_at91.h"
+#include "cfg/cfg_emb_flash.h"
 #include <cfg/macros.h>
 
-#include "hw/hw_boot.h"
-
 // Define log settings for cfg/log.h
-#define LOG_LEVEL    CONFIG_FLASH_AT91_LOG_LEVEL
-#define LOG_FORMAT   CONFIG_FLASH_AT91_LOG_FORMAT
+#define LOG_LEVEL    CONFIG_FLASH_EMB_LOG_LEVEL
+#define LOG_FORMAT   CONFIG_FLASH_EMB_LOG_FORMAT
 #include <cfg/log.h>
 
-
 #include <cpu/irq.h>
 #include <cpu/attr.h>
 #include <cpu/power.h>
 
-#include <kern/kfile.h>
-
+#include <io/kfile.h>
+#include <io/kblock.h>
 #include <io/arm.h>
 
 #include <drv/timer.h>
 
 #include <string.h>
 
-/*
- * Check if flash memory is ready to accept other commands.
+struct FlashHardware
+{
+       uint8_t status;
+};
+
+
+/**
+ * Really send the flash write command.
+ *
+ * \note This function has to be placed in RAM because
+ *       executing code from flash while a writing process
+ *       is in progress is forbidden.
  */
-RAM_FUNC static bool flash_at91_isReady(void)
+RAM_FUNC NOINLINE static void write_page(uint32_t page)
 {
-       return (MC_FSR & BV(MC_FRDY));
+       // Send the 'write page' command
+       MC_FCR = MC_KEY | MC_FCMD_WP | (MC_PAGEN_MASK & (page << 8));
+
+       // Wait for the end of command
+       while(!(MC_FSR & BV(MC_FRDY)))
+       {
+               //NOP;
+       }
 }
 
+
 /**
  * Send write command.
  *
  * After WR command cpu write bufferd page into flash memory.
+ *
  */
-RAM_FUNC static void flash_at91_sendWRcmd(uint32_t page)
+INLINE void flash_sendWRcmd(uint32_t page)
 {
        cpu_flags_t flags;
 
-       // Wait for end of command
-       while(!flash_at91_isReady())
-       {
-               cpu_relax();
-       }
+       LOG_INFO("Writing page %ld...\n", page);
 
        IRQ_SAVE_DISABLE(flags);
-
-       // Send the 'write page' command
-       MC_FCR = MC_KEY | MC_FCMD_WP | (MC_PAGEN_MASK & (page << 8));
-
-       // Wait for end of command
-       while(!flash_at91_isReady())
-       {
-               cpu_relax();
-       }
+       write_page(page);
 
        IRQ_RESTORE(flags);
+       LOG_INFO("Done\n");
 }
 
 /**
- * Return 0 if no error are occurred after flash memory
+ * Return true if no error are occurred after flash memory
  * read or write operation, otherwise return error code.
  */
-RAM_FUNC static int flash_at91_getStatus(struct KFile *_fd)
+static bool flash_getStatus(struct KBlock *blk)
 {
-       (void)_fd;
-
-
-       /*
-        * This bit is set to one if we programming of at least one locked lock
-        * region.
-        */
-       if(MC_FSR & BV(MC_LOCKE))
-               return -1;
-
+       Flash *fls = FLASH_CAST(blk);
        /*
         * This bit is set to one if an invalid command and/or a bad keywords was/were
         * written in the Flash Command Register.
         */
        if(MC_FSR & BV(MC_PROGE))
-               return -2;
-
-       return 0;
-}
-
+       {
+               fls->hw->status |= FLASH_WR_ERR;
+               LOG_ERR("flash not erased..\n");
+               return false;
+       }
 
-/**
- * Write modified page on internal latch, and then send write command to
- * flush page to internal flash.
- */
-RAM_FUNC static void flash_at91_flush(Flash *fd)
-{
-       if (fd->page_dirty)
+       /*
+        * This bit is set to one if we programming of at least one locked lock
+        * region.
+        */
+       if(MC_FSR & BV(MC_LOCKE))
        {
-               //Compute page address of current page.
-               page_addr_t *addr = (page_addr_t *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE);
-
-               //Copy modified page into internal latch.
-               for (page_addr_t page_addr = 0; page_addr < FLASH_PAGE_SIZE_BYTES; page_addr += 4)
-               {
-                       uint32_t data;
-                       memcpy(&data, &fd->page_buf[page_addr], sizeof(data));
-                       *addr = data;
-                       addr++;
-               }
-
-               // Send write command to transfer page from latch to internal flash memory.
-               flash_at91_sendWRcmd(fd->curr_page);
+               fls->hw->status |= FLASH_WR_PROTECT;
+               LOG_ERR("wr protect..\n");
+               return false;
        }
-}
 
-/**
- * Flush At91 flash function.
- *
- * Write current buffered page in flash memory (if modified).
- * This function erase flash memory page before writing.
- */
-static int flash_at91_kfileFlush(struct KFile *_fd)
-{
-       Flash *fd = FLASH_CAST(_fd);
-       flash_at91_flush(fd);
-       return 0;
+       return true;
 }
 
-
-/**
- * Check current page and if \a page is different, load it in
- * temporary buffer.
- */
-static void flash_at91_loadPage(Flash *fd, page_t page)
+static size_t at91_flash_readDirect(struct KBlock *blk, block_idx_t idx, void *buf, size_t offset, size_t size)
 {
-       if (page != fd->curr_page)
-       {
-               flash_at91_flush(fd);
-               // Load page
-               memcpy(fd->page_buf, (const char *)((page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
-               fd->curr_page = page;
-               LOG_INFO("Loaded page %lu\n", fd->curr_page);
-       }
+       memcpy(buf, (void *)(idx * blk->blk_size +  FLASH_BASE + offset), size);
+       return size;
 }
 
-
-/**
- * Write program memory.
- * Write \a size bytes from buffer \a _buf to file \a fd
- * \note Write operations are buffered.
- */
-static size_t flash_at91_write(struct KFile *_fd, const void *_buf, size_t size)
+static size_t at91_flash_writeDirect(struct KBlock *blk, block_idx_t idx, const void *_buf, size_t offset, size_t size)
 {
-       Flash *fd = FLASH_CAST(_fd);
-       const uint8_t *buf =(const uint8_t *)_buf;
-
-       page_t page;
-       page_addr_t page_addr;
-       size_t total_write = 0;
+       ASSERT(offset == 0);
+       ASSERT(size == blk->blk_size);
 
-       size = MIN((kfile_off_t)size, (kfile_off_t)(fd->fd.size - (fd->fd.seek_pos - FLASH_BASE)));
+       uint32_t *addr = (uint32_t *)(idx * blk->blk_size +  FLASH_BASE);
+       const uint8_t *buf = (const uint8_t *)_buf;
 
-       LOG_INFO("Writing at pos[%lu]\n", fd->fd.seek_pos);
        while (size)
        {
-               page = (fd->fd.seek_pos - FLASH_BASE) / FLASH_PAGE_SIZE_BYTES;
-               page_addr = (fd->fd.seek_pos - FLASH_BASE) % FLASH_PAGE_SIZE_BYTES;
-
-               flash_at91_loadPage(fd, page);
+               uint32_t data = (*(buf + 3) << 24) |
+                                               (*(buf + 2) << 16) |
+                                               (*(buf + 1) << 8)  |
+                                               *buf;
+               *addr = data;
+
+               size -= 4;
+               buf += 4;
+               addr++;
+       }
 
-               size_t wr_len = MIN(size, (size_t)(FLASH_PAGE_SIZE_BYTES - page_addr));
+       flash_sendWRcmd(idx);
 
-               memcpy(fd->page_buf + page_addr, buf, wr_len);
-               fd->page_dirty = true;
+       if (!flash_getStatus(blk))
+               return 0;
 
-               buf += wr_len;
-               fd->fd.seek_pos += wr_len;
-               size -= wr_len;
-               total_write += wr_len;
-       }
-       LOG_INFO("written %u bytes\n", total_write);
-       return total_write;
+       return blk->blk_size;
 }
 
-/**
- * Close file \a fd
- */
-static int flash_at91_close(struct KFile *_fd)
-{
-       Flash *fd = FLASH_CAST(_fd);
-       flash_at91_flush(fd);
-       LOG_INFO("Flash file closed\n");
 
-       return 0;
+static int at91_flash_error(struct KBlock *blk)
+{
+       Flash *fls = FLASH_CAST(blk);
+       return fls->hw->status;
 }
 
-/**
- * Open flash file \a fd
- * \a name and \a mode are unused, cause flash memory is
- * threated like one file.
- */
-static void flash_at91_open(struct Flash *fd)
+static void at91_flash_clearerror(struct KBlock *blk)
 {
-       fd->fd.size = FLASH_BASE + FLASH_MEM_SIZE;
-       fd->fd.seek_pos = FLASH_BASE + FLASH_BOOT_SIZE;
-       fd->curr_page = (fd->fd.seek_pos - FLASH_BASE) / FLASH_PAGE_SIZE_BYTES;
-
-       memcpy(fd->page_buf, (const char *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
-
-       fd->page_dirty = false;
-       LOG_INFO("Flash file opened\n");
+       Flash *fls = FLASH_CAST(blk);
+       fls->hw->status = 0;
 }
 
-
-/**
- * Move \a fd file seek position of \a offset bytes from \a whence.
- *
- */
-static kfile_off_t flash_at91_seek(struct KFile *_fd, kfile_off_t offset, KSeekMode whence)
+static const KBlockVTable flash_at91_buffered_vt =
 {
-       Flash *fd = FLASH_CAST(_fd);
-       kfile_off_t seek_pos;
+       .readDirect = at91_flash_readDirect,
+       .writeDirect = at91_flash_writeDirect,
 
-       switch (whence)
-       {
+       .readBuf = kblock_swReadBuf,
+       .writeBuf = kblock_swWriteBuf,
+       .load = kblock_swLoad,
+       .store = kblock_swStore,
 
-       case KSM_SEEK_SET:
-               seek_pos = FLASH_BASE + FLASH_BOOT_SIZE;
-               break;
-       case KSM_SEEK_END:
-               seek_pos = fd->fd.size;
-               break;
-       case KSM_SEEK_CUR:
-               seek_pos = fd->fd.seek_pos;
-               break;
-       default:
-               ASSERT(0);
-               return EOF;
-               break;
-       }
+       .error = at91_flash_error,
+       .clearerr = at91_flash_clearerror,
+};
 
-       #if LOG_LEVEL >= LOG_LVL_INFO
-       /* Bound check */
-       if (seek_pos + offset > fd->fd.size)
-               LOG_INFO("seek outside EOF\n");
-       #endif
+static const KBlockVTable flash_at91_unbuffered_vt =
+{
+       .readDirect = at91_flash_readDirect,
+       .writeDirect = at91_flash_writeDirect,
 
-       fd->fd.seek_pos = seek_pos + offset;
+       .error = at91_flash_error,
+       .clearerr = at91_flash_clearerror,
+};
 
-       return fd->fd.seek_pos - (FLASH_BASE + FLASH_BOOT_SIZE);
-}
+static struct FlashHardware flash_at91_hw;
+static uint8_t flash_buf[FLASH_PAGE_SIZE_BYTES];
 
-/**
- * Reopen file \a fd
- */
-static struct KFile *flash_at91_reopen(struct KFile *_fd)
+static void common_init(Flash *fls)
 {
-       Flash *fd = FLASH_CAST(_fd);
-       flash_at91_close(_fd);
-       flash_at91_open(fd);
+       memset(fls, 0, sizeof(*fls));
+       DB(fls->blk.priv.type = KBT_FLASH);
+
+       fls->hw = &flash_at91_hw;
 
-       return _fd;
+       fls->blk.blk_size = FLASH_PAGE_SIZE_BYTES;
+       fls->blk.blk_cnt = FLASH_MEM_SIZE / FLASH_PAGE_SIZE_BYTES;
 }
 
-/**
- * Read from file \a fd \a size bytes and put it in buffer \a buf
- * \return the number of bytes read.
- */
-static size_t flash_at91_read(struct KFile *_fd, void *_buf, size_t size)
+void flash_hw_init(Flash *fls, UNUSED_ARG(int, flags))
 {
-       Flash *fd = FLASH_CAST(_fd);
-       uint8_t *buf =(uint8_t *)_buf;
-
-       size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
-
-       LOG_INFO("Reading at pos[%lu]\n", fd->fd.seek_pos);
-
-       // Flush current buffered page (if modified).
-       flash_at91_flush(fd);
-
-       uint32_t *addr = (uint32_t *)fd->fd.seek_pos;
-       memcpy(buf, (uint8_t *)addr, size);
-
-       fd->fd.seek_pos += size;
+       common_init(fls);
+       fls->blk.priv.vt = &flash_at91_buffered_vt;
+       fls->blk.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE;
+       fls->blk.priv.buf = flash_buf;
 
-       LOG_INFO("Read %u bytes\n", size);
-       return size;
+       /* Load the first block in the cache */
+       memcpy(fls->blk.priv.buf, (void *)(FLASH_BASE), fls->blk.blk_size);
 }
 
-
-/**
- * Init module to perform write and read operation on internal
- * flash memory.
- */
-void flash_hw_init(struct Flash *fd)
+void flash_hw_initUnbuffered(Flash *fls, UNUSED_ARG(int, flags))
 {
-       memset(fd, 0, sizeof(*fd));
-       DB(fd->fd._type = KFT_FLASH);
-
-       // Set up flash programming functions.
-       fd->fd.reopen = flash_at91_reopen;
-       fd->fd.close = flash_at91_close;
-       fd->fd.write = flash_at91_write;
-       fd->fd.read = flash_at91_read;
-       fd->fd.seek = flash_at91_seek;
-       fd->fd.error = flash_at91_getStatus;
-       fd->fd.flush = flash_at91_kfileFlush;
-
-       flash_at91_open(fd);
+       common_init(fls);
+       fls->blk.priv.vt = &flash_at91_unbuffered_vt;
 }
+