flash_lm3s.c

Go to the documentation of this file.
00001 
00038 #include "flash_lm3s.h"
00039 #include "cfg/log.h"
00040 
00041 #include <cfg/macros.h>
00042 
00043 #include <kern/kfile.h>
00044 
00045 #include <drv/timer.h>
00046 #include <drv/flash.h>
00047 #include <cpu/power.h> /* cpu_relax() */
00048 
00049 #include <string.h> /* memcpy() */
00050 
00051 
00052 static int flash_lm3s_erase_page(page_t addr)
00053 {
00054     FLASH_FCMISC_R = FLASH_FCMISC_AMISC;
00055 
00056     FLASH_FMA_R = (volatile uint32_t)addr;
00057     FLASH_FMC_R = FLASH_FMC_WRKEY | FLASH_FMC_ERASE;
00058 
00059     while (FLASH_FMC_R & FLASH_FMC_ERASE)
00060         cpu_relax();
00061     if (FLASH_FCRIS_R & FLASH_FCRIS_ARIS)
00062         return -1;
00063     return 0;
00064 }
00065 
00066 static int flash_lm3s_write_word(page_t addr, const uint8_t *data, size_t len)
00067 {
00068     FLASH_FCMISC_R = FLASH_FCMISC_AMISC;
00069 
00070     uint32_t _data;
00071     memcpy(&_data, data, len);
00072     FLASH_FMA_R = (volatile uint32_t)addr;
00073     FLASH_FMD_R = (volatile uint32_t)_data;
00074     FLASH_FMC_R = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
00075 
00076     while (FLASH_FMC_R & FLASH_FMC_WRITE)
00077         cpu_relax();
00078     if (FLASH_FCRIS_R & FLASH_FCRIS_ARIS)
00079         return -1;
00080     return 0;
00081 }
00082 
00083 static void _flash_lm3s_flush(Flash *fd)
00084 {
00085     if (!fd->page_dirty)
00086         return;
00087 
00088     LOG_INFO("Erase page %p\n", fd->curr_page);
00089     flash_lm3s_erase_page(fd->curr_page);
00090 
00091     LOG_INFO("Flush page %p\n", fd->curr_page);
00092     for (int i = 0; i < FLASH_PAGE_SIZE_BYTES; i+=4)
00093         flash_lm3s_write_word(fd->curr_page + i, &fd->page_buf[i], sizeof(uint32_t));
00094     fd->page_dirty = false;
00095 }
00096 
00097 static void flash_lm3s_load_page(Flash *fd, page_t page)
00098 {
00099     ASSERT(!((size_t)page % FLASH_PAGE_SIZE_BYTES));
00100 
00101     if (page == fd->curr_page)
00102         return;
00103 
00104     /* Flush old page */
00105     _flash_lm3s_flush(fd);
00106 
00107     /* Load a new page */
00108     memcpy(fd->page_buf, FLASH_BASE + (uint8_t *)page, FLASH_PAGE_SIZE_BYTES);
00109     fd->curr_page = page;
00110     LOG_INFO("Loaded page %p\n", fd->curr_page);
00111 }
00112 
00118 static size_t flash_lm3s_write(struct KFile *_fd, const void *_buf, size_t size)
00119 {
00120     Flash *fd = FLASH_CAST(_fd);
00121     const uint8_t *buf =(const uint8_t *)_buf;
00122     size_t total_write = 0;
00123     size_t len;
00124 
00125     size = MIN((kfile_off_t)size,
00126         (kfile_off_t)(fd->fd.size - (fd->fd.seek_pos - FLASH_BASE)));
00127 
00128     LOG_INFO("Writing at pos[%lx]\n", fd->fd.seek_pos);
00129     while (size)
00130     {
00131         page_t page = (fd->fd.seek_pos & ~(FLASH_PAGE_SIZE_BYTES - 1));
00132         size_t offset = fd->fd.seek_pos % FLASH_PAGE_SIZE_BYTES;
00133 
00134         flash_lm3s_load_page(fd, page);
00135 
00136         len = MIN(size, FLASH_PAGE_SIZE_BYTES - offset);
00137 
00138         memcpy((uint8_t *)fd->page_buf + offset, buf, len);
00139         fd->page_dirty = true;
00140 
00141         buf += len;
00142         fd->fd.seek_pos += len;
00143         size -= len;
00144         total_write += len;
00145     }
00146     LOG_INFO("written %u bytes\n", total_write);
00147     return total_write;
00148 }
00149 
00153 static int flash_lm3s_close(struct KFile *_fd)
00154 {
00155     Flash *fd = FLASH_CAST(_fd);
00156     _flash_lm3s_flush(fd);
00157     LOG_INFO("Flash file closed\n");
00158     return 0;
00159 }
00160 
00164 static void flash_lm3s_open(Flash *fd)
00165 {
00166     fd->fd.size = FLASH_BASE + FLASH_MEM_SIZE;
00167     fd->fd.seek_pos = FLASH_BASE;
00168     /*
00169      * Set an invalid page to force the load of the next actually used page
00170      * in cache.
00171      */
00172     fd->curr_page = FLASH_BASE + FLASH_MEM_SIZE;
00173 
00174     fd->page_dirty = false;
00175     LOG_INFO("Flash file opened\n");
00176 }
00177 
00181 static kfile_off_t flash_lm3s_seek(struct KFile *_fd, kfile_off_t offset, KSeekMode whence)
00182 {
00183     Flash *fd = FLASH_CAST(_fd);
00184     kfile_off_t seek_pos;
00185 
00186     switch (whence)
00187     {
00188     case KSM_SEEK_SET:
00189         seek_pos = FLASH_BASE;
00190         break;
00191     case KSM_SEEK_END:
00192         seek_pos = FLASH_BASE + fd->fd.size;
00193         break;
00194     case KSM_SEEK_CUR:
00195         seek_pos = fd->fd.seek_pos;
00196         break;
00197     default:
00198         ASSERT(0);
00199         return EOF;
00200         break;
00201     }
00202     if (seek_pos + offset > fd->fd.size)
00203         LOG_ERR("seek outside EOF\n");
00204     fd->fd.seek_pos = seek_pos + offset;
00205 
00206     return fd->fd.seek_pos - FLASH_BASE;
00207 }
00208 
00212 static struct KFile *flash_lm3s_reopen(struct KFile *_fd)
00213 {
00214     Flash *fd = FLASH_CAST(_fd);
00215     flash_lm3s_close(_fd);
00216     flash_lm3s_open(fd);
00217 
00218     return _fd;
00219 }
00220 
00225 static size_t flash_lm3s_read(struct KFile *_fd, void *_buf, size_t size)
00226 {
00227     Flash *fd = FLASH_CAST(_fd);
00228     uint8_t *buf =(uint8_t *)_buf, *addr;
00229 
00230     size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
00231 
00232     LOG_INFO("Reading at pos[%lx]\n", fd->fd.seek_pos);
00233     /* Check if we can get current cached page */
00234     if ((size_t)fd->fd.seek_pos / FLASH_PAGE_SIZE_BYTES ==
00235                 (size_t)fd->curr_page)
00236         addr = (uint8_t *)fd->curr_page +
00237             fd->fd.seek_pos % FLASH_PAGE_SIZE_BYTES;
00238     else
00239         addr = (uint8_t *)fd->fd.seek_pos;
00240     memcpy(buf, (uint8_t *)addr, size);
00241     fd->fd.seek_pos += size;
00242 
00243     LOG_INFO("Read %u bytes\n", size);
00244     return size;
00245 }
00246 
00247 static int flash_lm3s_flush(struct KFile *_fd)
00248 {
00249     Flash *fd = FLASH_CAST(_fd);
00250 
00251     _flash_lm3s_flush(fd);
00252     return 0;
00253 }
00254 
00259 void flash_hw_init(Flash *fd)
00260 {
00261     memset(fd, 0, sizeof(*fd));
00262     DB(fd->fd._type = KFT_FLASH);
00263 
00264     fd->fd.reopen = flash_lm3s_reopen;
00265     fd->fd.close = flash_lm3s_close;
00266     fd->fd.write = flash_lm3s_write;
00267     fd->fd.read = flash_lm3s_read;
00268     fd->fd.seek = flash_lm3s_seek;
00269     fd->fd.flush = flash_lm3s_flush;
00270 
00271     FLASH_USECRL_R = CPU_FREQ / 1000000 - 1;
00272 
00273     flash_lm3s_open(fd);
00274 }