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
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
00063 #include <string.h>
00064
00065
00066
00067
00068 RAM_FUNC static bool flash_at91_isReady(void)
00069 {
00070 return (MC_FSR & BV(MC_FRDY));
00071 }
00072
00078 RAM_FUNC static void flash_at91_sendWRcmd(uint32_t page)
00079 {
00080 cpu_flags_t flags;
00081
00082
00083 while(!flash_at91_isReady())
00084 {
00085 cpu_relax();
00086 }
00087
00088 IRQ_SAVE_DISABLE(flags);
00089
00090
00091 MC_FCR = MC_KEY | MC_FCMD_WP | (MC_PAGEN_MASK & (page << 8));
00092
00093
00094 while(!flash_at91_isReady())
00095 {
00096 cpu_relax();
00097 }
00098
00099 IRQ_RESTORE(flags);
00100 }
00101
00106 RAM_FUNC static int flash_at91_getStatus(struct KFile *_fd)
00107 {
00108 (void)_fd;
00109
00110
00111
00112
00113
00114
00115 if(MC_FSR & BV(MC_LOCKE))
00116 return -1;
00117
00118
00119
00120
00121
00122 if(MC_FSR & BV(MC_PROGE))
00123 return -2;
00124
00125 return 0;
00126 }
00127
00128
00133 RAM_FUNC static void flash_at91_flush(FlashAt91 *fd)
00134 {
00135 if (fd->page_dirty)
00136 {
00137
00138 arm_page_addr_t *addr = (arm_page_addr_t *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE);
00139
00140
00141 for (arm_page_addr_t page_addr = 0; page_addr < FLASH_PAGE_SIZE_BYTES; page_addr += 4)
00142 {
00143 uint32_t data;
00144 memcpy(&data, &fd->page_buf[page_addr], sizeof(data));
00145 *addr = data;
00146 addr++;
00147 }
00148
00149
00150 flash_at91_sendWRcmd(fd->curr_page);
00151 }
00152 }
00153
00160 static int flash_at91_kfileFlush(struct KFile *_fd)
00161 {
00162 FlashAt91 *fd = FLASHAT91_CAST(_fd);
00163 flash_at91_flush(fd);
00164 return 0;
00165 }
00166
00167
00172 static void flash_at91_loadPage(FlashAt91 *fd, arm_page_t page)
00173 {
00174 if (page != fd->curr_page)
00175 {
00176 flash_at91_flush(fd);
00177
00178 memcpy(fd->page_buf, (const char *)((page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
00179 fd->curr_page = page;
00180 LOG_INFO("Loaded page %lu\n", fd->curr_page);
00181 }
00182 }
00183
00184
00190 static size_t flash_at91_write(struct KFile *_fd, const void *_buf, size_t size)
00191 {
00192 FlashAt91 *fd = FLASHAT91_CAST(_fd);
00193 const uint8_t *buf =(const uint8_t *)_buf;
00194
00195 arm_page_t page;
00196 arm_page_addr_t page_addr;
00197 size_t total_write = 0;
00198
00199 size = MIN((kfile_off_t)size, (kfile_off_t)(fd->fd.size - (fd->fd.seek_pos - FLASH_BASE)));
00200
00201 LOG_INFO("Writing at pos[%lu]\n", fd->fd.seek_pos);
00202 while (size)
00203 {
00204 page = (fd->fd.seek_pos - FLASH_BASE) / FLASH_PAGE_SIZE_BYTES;
00205 page_addr = (fd->fd.seek_pos - FLASH_BASE) % FLASH_PAGE_SIZE_BYTES;
00206
00207 flash_at91_loadPage(fd, page);
00208
00209 size_t wr_len = MIN(size, (size_t)(FLASH_PAGE_SIZE_BYTES - page_addr));
00210
00211 memcpy(fd->page_buf + page_addr, buf, wr_len);
00212 fd->page_dirty = true;
00213
00214 buf += wr_len;
00215 fd->fd.seek_pos += wr_len;
00216 size -= wr_len;
00217 total_write += wr_len;
00218 }
00219 LOG_INFO("written %u bytes\n", total_write);
00220 return total_write;
00221 }
00222
00226 static int flash_at91_close(struct KFile *_fd)
00227 {
00228 FlashAt91 *fd = FLASHAT91_CAST(_fd);
00229 flash_at91_flush(fd);
00230 LOG_INFO("Flash file closed\n");
00231
00232 return 0;
00233 }
00234
00240 static void flash_at91_open(struct FlashAt91 *fd)
00241 {
00242 fd->fd.size = FLASH_BASE + FLASH_MEM_SIZE;
00243 fd->fd.seek_pos = FLASH_BASE + FLASH_BOOT_SIZE;
00244 fd->curr_page = (fd->fd.seek_pos - FLASH_BASE) / FLASH_PAGE_SIZE_BYTES;
00245
00246 memcpy(fd->page_buf, (const char *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
00247
00248 fd->page_dirty = false;
00249 LOG_INFO("Flash file opened\n");
00250 }
00251
00252
00257 static kfile_off_t flash_at91_seek(struct KFile *_fd, kfile_off_t offset, KSeekMode whence)
00258 {
00259 FlashAt91 *fd = FLASHAT91_CAST(_fd);
00260 kfile_off_t seek_pos;
00261
00262 switch (whence)
00263 {
00264
00265 case KSM_SEEK_SET:
00266 seek_pos = FLASH_BASE + FLASH_BOOT_SIZE;
00267 break;
00268 case KSM_SEEK_END:
00269 seek_pos = fd->fd.size;
00270 break;
00271 case KSM_SEEK_CUR:
00272 seek_pos = fd->fd.seek_pos;
00273 break;
00274 default:
00275 ASSERT(0);
00276 return EOF;
00277 break;
00278 }
00279
00280 #if LOG_LEVEL >= LOG_LVL_INFO
00281
00282 if (seek_pos + offset > fd->fd.size)
00283 LOG_INFO("seek outside EOF\n");
00284 #endif
00285
00286 fd->fd.seek_pos = seek_pos + offset;
00287
00288 return fd->fd.seek_pos - (FLASH_BASE + FLASH_BOOT_SIZE);
00289 }
00290
00294 static struct KFile *flash_at91_reopen(struct KFile *_fd)
00295 {
00296 FlashAt91 *fd = FLASHAT91_CAST(_fd);
00297 flash_at91_close(_fd);
00298 flash_at91_open(fd);
00299
00300 return _fd;
00301 }
00302
00307 static size_t flash_at91_read(struct KFile *_fd, void *_buf, size_t size)
00308 {
00309 FlashAt91 *fd = FLASHAT91_CAST(_fd);
00310 uint8_t *buf =(uint8_t *)_buf;
00311
00312 size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
00313
00314 LOG_INFO("Reading at pos[%lu]\n", fd->fd.seek_pos);
00315
00316
00317 flash_at91_flush(fd);
00318
00319 uint32_t *addr = (uint32_t *)fd->fd.seek_pos;
00320 memcpy(buf, (uint8_t *)addr, size);
00321
00322 fd->fd.seek_pos += size;
00323
00324 LOG_INFO("Read %u bytes\n", size);
00325 return size;
00326 }
00327
00328
00333 void flash_at91_init(FlashAt91 *fd)
00334 {
00335 memset(fd, 0, sizeof(*fd));
00336 DB(fd->fd._type = KFT_FLASHAT91);
00337
00338
00339 fd->fd.reopen = flash_at91_reopen;
00340 fd->fd.close = flash_at91_close;
00341 fd->fd.write = flash_at91_write;
00342 fd->fd.read = flash_at91_read;
00343 fd->fd.seek = flash_at91_seek;
00344 fd->fd.error = flash_at91_getStatus;
00345 fd->fd.flush = flash_at91_kfileFlush;
00346
00347 flash_at91_open(fd);
00348
00349 uint32_t fmcn;
00350 uint32_t fws = 0;
00351
00352
00353
00354
00355
00356
00357
00358 fmcn = (CPU_FREQ/1000000ul) + (CPU_FREQ/2000000ul) + 1;
00359
00360
00361 if (fmcn > 0xFF)
00362 fmcn = 0xFF;
00363
00364
00365 if (CPU_FREQ <= 33333ul)
00366 fmcn = 0;
00367
00368
00369 if (CPU_FREQ > 30000000ul)
00370 {
00371 fws = 1;
00372 }
00373
00374
00375 MC_FMR = fmcn << 16 | fws << 8;
00376
00377 }