flash_at91.c

Go to the documentation of this file.
00001 
00040 #include "flash_at91.h"
00041 
00042 #include "cfg/cfg_flash_at91.h"
00043 #include <cfg/macros.h>
00044 
00045 #include "hw/hw_boot.h"
00046 
00047 // Define log settings for cfg/log.h
00048 #define LOG_LEVEL    CONFIG_FLASH_AT91_LOG_LEVEL
00049 #define LOG_FORMAT   CONFIG_FLASH_AT91_LOG_FORMAT
00050 #include <cfg/log.h>
00051 
00052 
00053 #include <cpu/irq.h>
00054 #include <cpu/attr.h>
00055 #include <cpu/power.h>
00056 
00057 #include <kern/kfile.h>
00058 
00059 #include <io/arm.h>
00060 
00061 #include <drv/timer.h>
00062 #include <drv/flash.h>
00063 
00064 #include <string.h>
00065 
00066 /*
00067  * Check if flash memory is ready to accept other commands.
00068  */
00069 RAM_FUNC static bool flash_at91_isReady(void)
00070 {
00071     return (MC_FSR & BV(MC_FRDY));
00072 }
00073 
00079 RAM_FUNC static void flash_at91_sendWRcmd(uint32_t page)
00080 {
00081     cpu_flags_t flags;
00082 
00083     // Wait for end of command
00084     while(!flash_at91_isReady())
00085     {
00086         cpu_relax();
00087     }
00088 
00089     IRQ_SAVE_DISABLE(flags);
00090 
00091     // Send the 'write page' command
00092     MC_FCR = MC_KEY | MC_FCMD_WP | (MC_PAGEN_MASK & (page << 8));
00093 
00094     // Wait for end of command
00095     while(!flash_at91_isReady())
00096     {
00097         cpu_relax();
00098     }
00099 
00100     IRQ_RESTORE(flags);
00101 }
00102 
00107 RAM_FUNC static int flash_at91_getStatus(struct KFile *_fd)
00108 {
00109     (void)_fd;
00110 
00111 
00112     /*
00113      * This bit is set to one if we programming of at least one locked lock
00114      * region.
00115      */
00116     if(MC_FSR & BV(MC_LOCKE))
00117         return -1;
00118 
00119     /*
00120      * This bit is set to one if an invalid command and/or a bad keywords was/were
00121      * written in the Flash Command Register.
00122      */
00123     if(MC_FSR & BV(MC_PROGE))
00124         return -2;
00125 
00126     return 0;
00127 }
00128 
00129 
00134 RAM_FUNC static void flash_at91_flush(Flash *fd)
00135 {
00136     if (fd->page_dirty)
00137     {
00138         //Compute page address of current page.
00139         page_addr_t *addr = (page_addr_t *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE);
00140 
00141         //Copy modified page into internal latch.
00142         for (page_addr_t page_addr = 0; page_addr < FLASH_PAGE_SIZE_BYTES; page_addr += 4)
00143         {
00144             uint32_t data;
00145             memcpy(&data, &fd->page_buf[page_addr], sizeof(data));
00146             *addr = data;
00147             addr++;
00148         }
00149 
00150         // Send write command to transfer page from latch to internal flash memory.
00151         flash_at91_sendWRcmd(fd->curr_page);
00152     }
00153 }
00154 
00161 static int flash_at91_kfileFlush(struct KFile *_fd)
00162 {
00163     Flash *fd = FLASH_CAST(_fd);
00164     flash_at91_flush(fd);
00165     return 0;
00166 }
00167 
00168 
00173 static void flash_at91_loadPage(Flash *fd, page_t page)
00174 {
00175     if (page != fd->curr_page)
00176     {
00177         flash_at91_flush(fd);
00178         // Load page
00179         memcpy(fd->page_buf, (const char *)((page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
00180         fd->curr_page = page;
00181         LOG_INFO("Loaded page %lu\n", fd->curr_page);
00182     }
00183 }
00184 
00185 
00191 static size_t flash_at91_write(struct KFile *_fd, const void *_buf, size_t size)
00192 {
00193     Flash *fd = FLASH_CAST(_fd);
00194     const uint8_t *buf =(const uint8_t *)_buf;
00195 
00196     page_t page;
00197     page_addr_t page_addr;
00198     size_t total_write = 0;
00199 
00200     size = MIN((kfile_off_t)size, (kfile_off_t)(fd->fd.size - (fd->fd.seek_pos - FLASH_BASE)));
00201 
00202     LOG_INFO("Writing at pos[%lu]\n", fd->fd.seek_pos);
00203     while (size)
00204     {
00205         page = (fd->fd.seek_pos - FLASH_BASE) / FLASH_PAGE_SIZE_BYTES;
00206         page_addr = (fd->fd.seek_pos - FLASH_BASE) % FLASH_PAGE_SIZE_BYTES;
00207 
00208         flash_at91_loadPage(fd, page);
00209 
00210         size_t wr_len = MIN(size, (size_t)(FLASH_PAGE_SIZE_BYTES - page_addr));
00211 
00212         memcpy(fd->page_buf + page_addr, buf, wr_len);
00213         fd->page_dirty = true;
00214 
00215         buf += wr_len;
00216         fd->fd.seek_pos += wr_len;
00217         size -= wr_len;
00218         total_write += wr_len;
00219     }
00220     LOG_INFO("written %u bytes\n", total_write);
00221     return total_write;
00222 }
00223 
00227 static int flash_at91_close(struct KFile *_fd)
00228 {
00229     Flash *fd = FLASH_CAST(_fd);
00230     flash_at91_flush(fd);
00231     LOG_INFO("Flash file closed\n");
00232 
00233     return 0;
00234 }
00235 
00241 static void flash_at91_open(struct Flash *fd)
00242 {
00243     fd->fd.size = FLASH_BASE + FLASH_MEM_SIZE;
00244     fd->fd.seek_pos = FLASH_BASE + FLASH_BOOT_SIZE;
00245     fd->curr_page = (fd->fd.seek_pos - FLASH_BASE) / FLASH_PAGE_SIZE_BYTES;
00246 
00247     memcpy(fd->page_buf, (const char *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
00248 
00249     fd->page_dirty = false;
00250     LOG_INFO("Flash file opened\n");
00251 }
00252 
00253 
00258 static kfile_off_t flash_at91_seek(struct KFile *_fd, kfile_off_t offset, KSeekMode whence)
00259 {
00260     Flash *fd = FLASH_CAST(_fd);
00261     kfile_off_t seek_pos;
00262 
00263     switch (whence)
00264     {
00265 
00266     case KSM_SEEK_SET:
00267         seek_pos = FLASH_BASE + FLASH_BOOT_SIZE;
00268         break;
00269     case KSM_SEEK_END:
00270         seek_pos = fd->fd.size;
00271         break;
00272     case KSM_SEEK_CUR:
00273         seek_pos = fd->fd.seek_pos;
00274         break;
00275     default:
00276         ASSERT(0);
00277         return EOF;
00278         break;
00279     }
00280 
00281     #if LOG_LEVEL >= LOG_LVL_INFO
00282     /* Bound check */
00283     if (seek_pos + offset > fd->fd.size)
00284         LOG_INFO("seek outside EOF\n");
00285     #endif
00286 
00287     fd->fd.seek_pos = seek_pos + offset;
00288 
00289     return fd->fd.seek_pos - (FLASH_BASE + FLASH_BOOT_SIZE);
00290 }
00291 
00295 static struct KFile *flash_at91_reopen(struct KFile *_fd)
00296 {
00297     Flash *fd = FLASH_CAST(_fd);
00298     flash_at91_close(_fd);
00299     flash_at91_open(fd);
00300 
00301     return _fd;
00302 }
00303 
00308 static size_t flash_at91_read(struct KFile *_fd, void *_buf, size_t size)
00309 {
00310     Flash *fd = FLASH_CAST(_fd);
00311     uint8_t *buf =(uint8_t *)_buf;
00312 
00313     size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
00314 
00315     LOG_INFO("Reading at pos[%lu]\n", fd->fd.seek_pos);
00316 
00317     // Flush current buffered page (if modified).
00318     flash_at91_flush(fd);
00319 
00320     uint32_t *addr = (uint32_t *)fd->fd.seek_pos;
00321     memcpy(buf, (uint8_t *)addr, size);
00322 
00323     fd->fd.seek_pos += size;
00324 
00325     LOG_INFO("Read %u bytes\n", size);
00326     return size;
00327 }
00328 
00329 
00334 void flash_hw_init(struct Flash *fd)
00335 {
00336     memset(fd, 0, sizeof(*fd));
00337     DB(fd->fd._type = KFT_FLASH);
00338 
00339     // Set up flash programming functions.
00340     fd->fd.reopen = flash_at91_reopen;
00341     fd->fd.close = flash_at91_close;
00342     fd->fd.write = flash_at91_write;
00343     fd->fd.read = flash_at91_read;
00344     fd->fd.seek = flash_at91_seek;
00345     fd->fd.error = flash_at91_getStatus;
00346     fd->fd.flush = flash_at91_kfileFlush;
00347 
00348     flash_at91_open(fd);
00349 
00350     uint32_t fmcn;
00351     uint32_t fws = 0;
00352 
00353 
00354     /*
00355      * Compute values to insert into mode register.
00356      */
00357 
00358     /* main clocks in 1.5uS */
00359     fmcn = (CPU_FREQ/1000000ul) + (CPU_FREQ/2000000ul) + 1;
00360 
00361     /* hard overclocking */
00362     if (fmcn > 0xFF)
00363         fmcn = 0xFF;
00364 
00365     /* Only allow fmcn=0 if clock period is > 30 us = 33kHz. */
00366     if (CPU_FREQ <= 33333ul)
00367         fmcn = 0;
00368 
00369     /* Only allow fws=0 if clock frequency is < 30 MHz. */
00370     if (CPU_FREQ > 30000000ul)
00371     {
00372         fws = 1;
00373     }
00374 
00375     // Set wait states and number of MCK cycles in 1.5 usecs
00376     MC_FMR = fmcn << 16 | fws << 8;
00377 
00378 }