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>
00048
00049 #include <string.h>
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
00105 _flash_lm3s_flush(fd);
00106
00107
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
00170
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
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 }