Move flash related flags to the flash driver; refactor accordingly.
[bertos.git] / bertos / cpu / cortex-m3 / drv / flash_lm3s.c
index b7498caceb31e9d34f88d3ea8182f616b1e0bbec..ffec0db7c0c20e94b310668aa84ae5a6e72ccd11 100644 (file)
  */
 
 #include "flash_lm3s.h"
-#include "cfg/log.h"
+#include "cfg/cfg_emb_flash.h"
 
+// Define log settings for cfg/log.h
+#define LOG_LEVEL    CONFIG_FLASH_EMB_LOG_LEVEL
+#define LOG_FORMAT   CONFIG_FLASH_EMB_LOG_FORMAT
+#include <cfg/log.h>
 #include <cfg/macros.h>
 
-#include <io/kfile.h>
+#include <io/kblock.h>
 
 #include <drv/timer.h>
 #include <drv/flash.h>
+
 #include <cpu/power.h> /* cpu_relax() */
+#include <cpu/types.h>
 
 #include <string.h> /* memcpy() */
 
-
-static int flash_lm3s_erase_page(page_t addr)
+struct FlashHardware
 {
-       FLASH_FCMISC_R = FLASH_FCMISC_AMISC;
+       int status;
+};
 
-       FLASH_FMA_R = (volatile uint32_t)addr;
-       FLASH_FMC_R = FLASH_FMC_WRKEY | FLASH_FMC_ERASE;
+static bool flash_wait(struct KBlock *blk, uint32_t event)
+{
+       Flash *fls = FLASH_CAST(blk);
+       ticks_t start = timer_clock();
+       while (true)
+       {
+               if (!(FLASH_FMC_R & event))
+                       break;
+
+               if (FLASH_FCRIS_R & FLASH_FCRIS_ARIS)
+               {
+                       fls->hw->status |= FLASH_WR_PROTECT;
+                       LOG_ERR("wr protect..\n");
+                       return false;
+               }
+
+               if (timer_clock() - start > ms_to_ticks(CONFIG_FLASH_WR_TIMEOUT))
+               {
+                       fls->hw->status |= FLASH_WR_TIMEOUT;
+                       LOG_ERR("Timeout..\n");
+                       return false;
+               }
 
-       while (FLASH_FMC_R & FLASH_FMC_ERASE)
                cpu_relax();
-       if (FLASH_FCRIS_R & FLASH_FCRIS_ARIS)
-               return -1;
-       return 0;
+       }
+
+       return true;
 }
 
-static int flash_lm3s_write_word(page_t addr, const uint8_t *data, size_t len)
+static int lm3s_erasePage(struct KBlock *blk, uint32_t addr)
 {
        FLASH_FCMISC_R = FLASH_FCMISC_AMISC;
 
-       uint32_t _data;
-       memcpy(&_data, data, len);
        FLASH_FMA_R = (volatile uint32_t)addr;
-       FLASH_FMD_R = (volatile uint32_t)_data;
-       FLASH_FMC_R = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
+       FLASH_FMC_R = FLASH_FMC_WRKEY | FLASH_FMC_ERASE;
 
-       while (FLASH_FMC_R & FLASH_FMC_WRITE)
-               cpu_relax();
-       if (FLASH_FCRIS_R & FLASH_FCRIS_ARIS)
-               return -1;
-       return 0;
+       return flash_wait(blk, FLASH_FMC_ERASE);
 }
 
-static void _flash_lm3s_flush(Flash *fd)
+static int lm3s_writeWord(struct KBlock *blk, uint32_t addr, uint32_t data)
 {
-       if (!fd->page_dirty)
-               return;
+       FLASH_FCMISC_R = FLASH_FCMISC_AMISC;
 
-       LOG_INFO("Erase page %p\n", fd->curr_page);
-       flash_lm3s_erase_page(fd->curr_page);
+       FLASH_FMA_R = (volatile uint32_t)addr;
+       FLASH_FMD_R = (volatile uint32_t)data;
+       FLASH_FMC_R = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
 
-       LOG_INFO("Flush page %p\n", fd->curr_page);
-       for (int i = 0; i < FLASH_PAGE_SIZE_BYTES; i+=4)
-               flash_lm3s_write_word(fd->curr_page + i, &fd->page_buf[i], sizeof(uint32_t));
-       fd->page_dirty = false;
+       return flash_wait(blk, FLASH_FMC_WRITE);
 }
 
-static void flash_lm3s_load_page(Flash *fd, page_t page)
+static size_t lm3s_flash_readDirect(struct KBlock *blk, block_idx_t idx, void *buf, size_t offset, size_t size)
 {
-       ASSERT(!((size_t)page % FLASH_PAGE_SIZE_BYTES));
-
-       if (page == fd->curr_page)
-               return;
-
-       /* Flush old page */
-       _flash_lm3s_flush(fd);
-
-       /* Load a new page */
-       memcpy(fd->page_buf, FLASH_BASE + (uint8_t *)page, FLASH_PAGE_SIZE_BYTES);
-       fd->curr_page = page;
-       LOG_INFO("Loaded page %p\n", fd->curr_page);
+       memcpy(buf, (void *)(idx * blk->blk_size + offset), size);
+       return size;
 }
 
-/**
- * Write program memory.
- * Write \a size bytes from buffer \a _buf to file \a fd
- * \note Write operations are not buffered.
- */
-static size_t flash_lm3s_write(struct KFile *_fd, const void *_buf, size_t size)
+static size_t lm3s_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;
-       size_t total_write = 0;
-       size_t len;
+       (void)offset;
+       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)));
+       if (!lm3s_erasePage(blk, (idx * blk->blk_size)))
+               return 0;
+
+       uint32_t addr = idx * blk->blk_size;
+       const uint8_t *buf = (const uint8_t *)_buf;
 
-       LOG_INFO("Writing at pos[%lx]\n", fd->fd.seek_pos);
        while (size)
        {
-               page_t page = (fd->fd.seek_pos & ~(FLASH_PAGE_SIZE_BYTES - 1));
-               size_t offset = fd->fd.seek_pos % FLASH_PAGE_SIZE_BYTES;
-
-               flash_lm3s_load_page(fd, page);
-
-               len = MIN(size, FLASH_PAGE_SIZE_BYTES - offset);
+               uint32_t data = (*(buf + 3) << 24) |
+                                               (*(buf + 2) << 16) |
+                                               (*(buf + 1) << 8)  |
+                                               *buf;
 
-               memcpy((uint8_t *)fd->page_buf + offset, buf, len);
-               fd->page_dirty = true;
+               if (!lm3s_writeWord(blk, addr, data))
+                       return 0;
 
-               buf += len;
-               fd->fd.seek_pos += len;
-               size -= len;
-               total_write += len;
+               size -= 4;
+               buf += 4;
+               addr += 4;
        }
-       LOG_INFO("written %u bytes\n", total_write);
-       return total_write;
+
+       return blk->blk_size;
 }
 
-/**
- * Close file \a fd
- */
-static int flash_lm3s_close(struct KFile *_fd)
+static int lm3s_flash_error(struct KBlock *blk)
 {
-       Flash *fd = FLASH_CAST(_fd);
-       _flash_lm3s_flush(fd);
-       LOG_INFO("Flash file closed\n");
-       return 0;
+       Flash *fls = FLASH_CAST(blk);
+       return fls->hw->status;
 }
 
-/**
- * Open flash file \a fd
- */
-static void flash_lm3s_open(Flash *fd)
+static void lm3s_flash_clearerror(struct KBlock *blk)
 {
-       fd->fd.size = FLASH_BASE + FLASH_MEM_SIZE;
-       fd->fd.seek_pos = FLASH_BASE;
-       /*
-        * Set an invalid page to force the load of the next actually used page
-        * in cache.
-        */
-       fd->curr_page = FLASH_BASE + FLASH_MEM_SIZE;
-
-       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_lm3s_seek(struct KFile *_fd, kfile_off_t offset, KSeekMode whence)
+static const KBlockVTable flash_lm3s_buffered_vt =
 {
-       Flash *fd = FLASH_CAST(_fd);
-       kfile_off_t seek_pos;
+       .readDirect = lm3s_flash_readDirect,
+       .writeDirect = lm3s_flash_writeDirect,
 
-       switch (whence)
-       {
-       case KSM_SEEK_SET:
-               seek_pos = FLASH_BASE;
-               break;
-       case KSM_SEEK_END:
-               seek_pos = FLASH_BASE + fd->fd.size;
-               break;
-       case KSM_SEEK_CUR:
-               seek_pos = fd->fd.seek_pos;
-               break;
-       default:
-               ASSERT(0);
-               return EOF;
-               break;
-       }
-       if (seek_pos + offset > fd->fd.size)
-               LOG_ERR("seek outside EOF\n");
-       fd->fd.seek_pos = seek_pos + offset;
+       .readBuf = kblock_swReadBuf,
+       .writeBuf = kblock_swWriteBuf,
+       .load = kblock_swLoad,
+       .store = kblock_swStore,
 
-       return fd->fd.seek_pos - FLASH_BASE;
-}
+       .close = kblock_swClose,
 
-/**
- * Reopen file \a fd
- */
-static struct KFile *flash_lm3s_reopen(struct KFile *_fd)
+       .error = lm3s_flash_error,
+       .clearerr = lm3s_flash_clearerror,
+};
+
+static const KBlockVTable flash_lm3s_unbuffered_vt =
 {
-       Flash *fd = FLASH_CAST(_fd);
-       flash_lm3s_close(_fd);
-       flash_lm3s_open(fd);
+       .readDirect = lm3s_flash_readDirect,
+       .writeDirect = lm3s_flash_writeDirect,
 
-       return _fd;
-}
+       .close = kblock_swClose,
 
-/**
- * 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_lm3s_read(struct KFile *_fd, void *_buf, size_t size)
+       .error = lm3s_flash_error,
+       .clearerr = lm3s_flash_clearerror,
+};
+
+static struct FlashHardware flash_lm3s_hw;
+static uint8_t flash_buf[FLASH_PAGE_SIZE];
+
+static void common_init(Flash *fls)
 {
-       Flash *fd = FLASH_CAST(_fd);
-       uint8_t *buf =(uint8_t *)_buf, *addr;
-
-       size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
-
-       LOG_INFO("Reading at pos[%lx]\n", fd->fd.seek_pos);
-       /* Check if we can get current cached page */
-       if ((size_t)fd->fd.seek_pos / FLASH_PAGE_SIZE_BYTES ==
-                               (size_t)fd->curr_page)
-               addr = (uint8_t *)fd->curr_page +
-                       fd->fd.seek_pos % FLASH_PAGE_SIZE_BYTES;
-       else
-               addr = (uint8_t *)fd->fd.seek_pos;
-       memcpy(buf, (uint8_t *)addr, size);
-       fd->fd.seek_pos += size;
-
-       LOG_INFO("Read %u bytes\n", size);
-       return size;
+       memset(fls, 0, sizeof(*fls));
+       DB(fls->blk.priv.type = KBT_FLASH);
+
+       FLASH_USECRL_R = CPU_FREQ / 1000000 - 1;
+
+       fls->hw = &flash_lm3s_hw;
+
+       fls->blk.blk_size = FLASH_PAGE_SIZE;
+       fls->blk.blk_cnt =  FLASH_SIZE / FLASH_PAGE_SIZE;
 }
 
-static int flash_lm3s_flush(struct KFile *_fd)
-{
-       Flash *fd = FLASH_CAST(_fd);
 
-       _flash_lm3s_flush(fd);
-       return 0;
+void flash_hw_init(Flash *fls, UNUSED_ARG(int, flags))
+{
+       common_init(fls);
+       fls->blk.priv.vt = &flash_lm3s_buffered_vt;
+       fls->blk.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE;
+       fls->blk.priv.buf = flash_buf;
+
+       /* Load the first block in the cache */
+       void *flash_start = 0x0;
+       memcpy(fls->blk.priv.buf, flash_start, fls->blk.blk_size);
 }
 
-/**
- * Init module to perform write and read operation on internal
- * flash memory.
- */
-void flash_hw_init(Flash *fd)
+void flash_hw_initUnbuffered(Flash *fls, UNUSED_ARG(int, flags))
 {
-       memset(fd, 0, sizeof(*fd));
-       DB(fd->fd._type = KFT_FLASH);
+       common_init(fls);
+       fls->blk.priv.vt = &flash_lm3s_unbuffered_vt;
+}
 
-       fd->fd.reopen = flash_lm3s_reopen;
-       fd->fd.close = flash_lm3s_close;
-       fd->fd.write = flash_lm3s_write;
-       fd->fd.read = flash_lm3s_read;
-       fd->fd.seek = flash_lm3s_seek;
-       fd->fd.flush = flash_lm3s_flush;
 
-       FLASH_USECRL_R = CPU_FREQ / 1000000 - 1;
 
-       flash_lm3s_open(fd);
-}