#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)
+{
+ Flash *fls = FLASH_CAST(blk);
+ ticks_t start = timer_clock();
+ while (true)
+ {
+ if (!(FLASH_FMC_R & FLASH_FMC_ERASE))
+ 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);
}
-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);
}
-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;
+ 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;
-}
+ .error = lm3s_flash_error,
+ .clearerr = lm3s_flash_clearerror,
+};
-/**
- * Reopen file \a fd
- */
-static struct KFile *flash_lm3s_reopen(struct KFile *_fd)
+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;
-}
+ .error = lm3s_flash_error,
+ .clearerr = lm3s_flash_clearerror,
+};
-/**
- * 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)
+/* Flash memory mapping */
+#if CPU_CM3_LM3S1968
+ #define EMB_FLASH_SIZE 0x40000 //< 256KiB
+ #define EMB_FLASH_PAGE_SIZE 0x400 //< 1KiB
+#else
+ #error Unknown CPU
+#endif
+
+static struct FlashHardware flash_lm3s_hw;
+static uint8_t flash_buf[EMB_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 = EMB_FLASH_PAGE_SIZE;
+ fls->blk.blk_cnt = EMB_FLASH_SIZE / EMB_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)
+{
+ 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;
}
-/**
- * Init module to perform write and read operation on internal
- * flash memory.
- */
-void flash_hw_init(Flash *fd)
+void flash_hw_initUnbuffered(Flash *fls)
{
- 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);
-}