#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;
}
+