Move kfile interface to the io/ directory.
[bertos.git] / bertos / cpu / arm / drv / flash_at91.c
index 06ff71e4dbb77503ee9842dfbdc2087ced723272..83cc73b7aaf110505f286a03291336b56bb024a8 100644 (file)
@@ -54,7 +54,7 @@
 #include <cpu/attr.h>
 #include <cpu/power.h>
 
-#include <kern/kfile.h>
+#include <io/kfile.h>
 
 #include <io/arm.h>
 
 
 #include <string.h>
 
-/*
- * Check if flash memory is ready to accept other commands.
- */
-RAM_FUNC static bool flash_at91_isReady(void)
+#define FLASH_START_PAGE DIV_ROUNDUP(FLASH_BOOT_SIZE, FLASH_PAGE_SIZE_BYTES)
+#define FLASH_START_ADDR (FLASH_START_PAGE * FLASH_PAGE_SIZE_BYTES)
+
+/**
+ * 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 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_at91_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
  * read or write operation, otherwise return error code.
  */
-RAM_FUNC static int flash_at91_getStatus(struct KFile *_fd)
+static int flash_at91_getStatus(UNUSED_ARG(struct KFile *, _fd))
 {
-       (void)_fd;
-
-
        /*
         * This bit is set to one if we programming of at least one locked lock
         * region.
@@ -131,8 +133,9 @@ RAM_FUNC static int flash_at91_getStatus(struct KFile *_fd)
  * 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)
+static int flash_at91_flush(KFile *_fd)
 {
+       Flash *fd = FLASH_CAST(_fd);
        if (fd->page_dirty)
        {
                //Compute page address of current page.
@@ -141,27 +144,17 @@ RAM_FUNC static void flash_at91_flush(Flash *fd)
                //Copy modified page into internal latch.
                for (page_addr_t page_addr = 0; page_addr < FLASH_PAGE_SIZE_BYTES; page_addr += 4)
                {
+                       // This is needed in order to have a single 32bit write instruction in addr.
+                       // (8 and 16 writes cause unpredictable results).
                        uint32_t data;
                        memcpy(&data, &fd->page_buf[page_addr], sizeof(data));
-                       *addr = data;
-                       addr++;
+                       *addr++ = data;
                }
 
                // Send write command to transfer page from latch to internal flash memory.
                flash_at91_sendWRcmd(fd->curr_page);
+               fd->page_dirty = 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;
 }
 
@@ -174,9 +167,9 @@ static void flash_at91_loadPage(Flash *fd, page_t page)
 {
        if (page != fd->curr_page)
        {
-               flash_at91_flush(fd);
+               flash_at91_flush(&fd->fd);
                // Load page
-               memcpy(fd->page_buf, (const char *)((page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
+               memcpy(fd->page_buf, (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);
        }
@@ -197,13 +190,13 @@ static size_t flash_at91_write(struct KFile *_fd, const void *_buf, size_t size)
        page_addr_t page_addr;
        size_t total_write = 0;
 
-       size = MIN((kfile_off_t)size, (kfile_off_t)(fd->fd.size - (fd->fd.seek_pos - FLASH_BASE)));
+       size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
 
        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;
+               page = (fd->fd.seek_pos + FLASH_START_ADDR) / FLASH_PAGE_SIZE_BYTES;
+               page_addr = (fd->fd.seek_pos + FLASH_START_ADDR) % FLASH_PAGE_SIZE_BYTES;
 
                flash_at91_loadPage(fd, page);
 
@@ -221,18 +214,6 @@ static size_t flash_at91_write(struct KFile *_fd, const void *_buf, size_t size)
        return total_write;
 }
 
-/**
- * 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;
-}
-
 /**
  * Open flash file \a fd
  * \a name and \a mode are unused, cause flash memory is
@@ -240,65 +221,14 @@ static int flash_at91_close(struct KFile *_fd)
  */
 static void flash_at91_open(struct Flash *fd)
 {
-       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->curr_page = FLASH_START_PAGE;
+       fd->fd.size = FLASH_MEM_SIZE - fd->curr_page * FLASH_PAGE_SIZE_BYTES;
+       fd->fd.seek_pos = 0;
+       
+       memcpy(fd->page_buf, (char *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
 
        fd->page_dirty = false;
-       LOG_INFO("Flash file opened\n");
-}
-
-
-/**
- * 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)
-{
-       Flash *fd = FLASH_CAST(_fd);
-       kfile_off_t seek_pos;
-
-       switch (whence)
-       {
-
-       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;
-       }
-
-       #if LOG_LEVEL >= LOG_LVL_INFO
-       /* Bound check */
-       if (seek_pos + offset > fd->fd.size)
-               LOG_INFO("seek outside EOF\n");
-       #endif
-
-       fd->fd.seek_pos = seek_pos + offset;
-
-       return fd->fd.seek_pos - (FLASH_BASE + FLASH_BOOT_SIZE);
-}
-
-/**
- * Reopen file \a fd
- */
-static struct KFile *flash_at91_reopen(struct KFile *_fd)
-{
-       Flash *fd = FLASH_CAST(_fd);
-       flash_at91_close(_fd);
-       flash_at91_open(fd);
-
-       return _fd;
+       LOG_INFO("Flash file opened, pos %ld, size %ld\n", fd->fd.seek_pos, fd->fd.size);
 }
 
 /**
@@ -315,10 +245,10 @@ static size_t flash_at91_read(struct KFile *_fd, void *_buf, size_t size)
        LOG_INFO("Reading at pos[%lu]\n", fd->fd.seek_pos);
 
        // Flush current buffered page (if modified).
-       flash_at91_flush(fd);
+       flash_at91_flush(&fd->fd);
 
-       uint32_t *addr = (uint32_t *)fd->fd.seek_pos;
-       memcpy(buf, (uint8_t *)addr, size);
+       kfile_off_t *addr = (kfile_off_t *)(fd->fd.seek_pos + FLASH_START_ADDR);
+       memcpy(buf, addr, size);
 
        fd->fd.seek_pos += size;
 
@@ -334,45 +264,15 @@ static size_t flash_at91_read(struct KFile *_fd, void *_buf, size_t size)
 void flash_hw_init(struct Flash *fd)
 {
        memset(fd, 0, sizeof(*fd));
+       // Init base class.
+       kfile_init(&fd->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;
+       fd->fd.flush = flash_at91_flush;
 
        flash_at91_open(fd);
-
-       uint32_t fmcn;
-       uint32_t fws = 0;
-
-
-       /*
-        * Compute values to insert into mode register.
-        */
-
-       /* main clocks in 1.5uS */
-       fmcn = (CPU_FREQ/1000000ul) + (CPU_FREQ/2000000ul) + 1;
-
-       /* hard overclocking */
-       if (fmcn > 0xFF)
-               fmcn = 0xFF;
-
-       /* Only allow fmcn=0 if clock period is > 30 us = 33kHz. */
-       if (CPU_FREQ <= 33333ul)
-               fmcn = 0;
-
-       /* Only allow fws=0 if clock frequency is < 30 MHz. */
-       if (CPU_FREQ > 30000000ul)
-       {
-               fws = 1;
-       }
-
-       // Set wait states and number of MCK cycles in 1.5 usecs
-       MC_FMR = fmcn << 16 | fws << 8;
-
 }