X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fcpu%2Farm%2Fdrv%2Fflash_at91.c;h=514d54e4326811042b4ea7dcafcf0e1f5e815857;hb=48608a70827e29e594e42605275362af7905bc7a;hp=06ff71e4dbb77503ee9842dfbdc2087ced723272;hpb=2302be36b228a46292a3f4eae649f5e29bd9999c;p=bertos.git diff --git a/bertos/cpu/arm/drv/flash_at91.c b/bertos/cpu/arm/drv/flash_at91.c index 06ff71e4..514d54e4 100644 --- a/bertos/cpu/arm/drv/flash_at91.c +++ b/bertos/cpu/arm/drv/flash_at91.c @@ -39,23 +39,20 @@ #include "flash_at91.h" -#include "cfg/cfg_flash_at91.h" +#include "cfg/cfg_emb_flash.h" #include -#include "hw/hw_boot.h" - // Define log settings for cfg/log.h -#define LOG_LEVEL CONFIG_FLASH_AT91_LOG_LEVEL -#define LOG_FORMAT CONFIG_FLASH_AT91_LOG_FORMAT +#define LOG_LEVEL CONFIG_FLASH_EMB_LOG_LEVEL +#define LOG_FORMAT CONFIG_FLASH_EMB_LOG_FORMAT #include - #include #include #include -#include - +#include +#include #include #include @@ -63,316 +60,182 @@ #include -/* - * Check if flash memory is ready to accept other commands. +struct FlashHardware +{ + uint8_t status; +}; + + +/** + * 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 static bool flash_at91_isReady(void) +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_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 + * Return true 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 bool flash_getStatus(struct KBlock *blk) { - (void)_fd; - - - /* - * This bit is set to one if we programming of at least one locked lock - * region. - */ - if(MC_FSR & BV(MC_LOCKE)) - return -1; - + Flash *fls = FLASH_CAST(blk); /* * This bit is set to one if an invalid command and/or a bad keywords was/were * written in the Flash Command Register. */ if(MC_FSR & BV(MC_PROGE)) - return -2; - - return 0; -} - + { + fls->hw->status |= FLASH_WR_ERR; + LOG_ERR("flash not erased..\n"); + return false; + } -/** - * 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) -{ - if (fd->page_dirty) + /* + * This bit is set to one if we programming of at least one locked lock + * region. + */ + if(MC_FSR & BV(MC_LOCKE)) { - //Compute page address of current page. - page_addr_t *addr = (page_addr_t *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE); - - //Copy modified page into internal latch. - for (page_addr_t page_addr = 0; page_addr < FLASH_PAGE_SIZE_BYTES; page_addr += 4) - { - uint32_t data; - memcpy(&data, &fd->page_buf[page_addr], sizeof(data)); - *addr = data; - addr++; - } - - // Send write command to transfer page from latch to internal flash memory. - flash_at91_sendWRcmd(fd->curr_page); + fls->hw->status |= FLASH_WR_PROTECT; + LOG_ERR("wr protect..\n"); + return 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; + return true; } - -/** - * Check current page and if \a page is different, load it in - * temporary buffer. - */ -static void flash_at91_loadPage(Flash *fd, page_t page) +static size_t at91_flash_readDirect(struct KBlock *blk, block_idx_t idx, void *buf, size_t offset, size_t size) { - if (page != fd->curr_page) - { - flash_at91_flush(fd); - // Load page - memcpy(fd->page_buf, (const 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); - } + memcpy(buf, (void *)(idx * blk->blk_size + FLASH_BASE + offset), size); + return size; } - -/** - * Write program memory. - * Write \a size bytes from buffer \a _buf to file \a fd - * \note Write operations are buffered. - */ -static size_t flash_at91_write(struct KFile *_fd, const void *_buf, size_t size) +static size_t at91_flash_writeDirect(struct KBlock *blk, block_idx_t idx, const void *_buf, size_t offset, size_t size) { - Flash *fd = FLASH_CAST(_fd); - const uint8_t *buf =(const uint8_t *)_buf; + ASSERT(offset == 0); + ASSERT(size == blk->blk_size); - page_t page; - page_addr_t page_addr; - size_t total_write = 0; + uint32_t *addr = (uint32_t *)(idx * blk->blk_size + FLASH_BASE); + const uint8_t *buf = (const uint8_t *)_buf; - size = MIN((kfile_off_t)size, (kfile_off_t)(fd->fd.size - (fd->fd.seek_pos - FLASH_BASE))); - - 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; - - flash_at91_loadPage(fd, page); + uint32_t data = (*(buf + 3) << 24) | + (*(buf + 2) << 16) | + (*(buf + 1) << 8) | + *buf; + *addr = data; + + size -= 4; + buf += 4; + addr++; + } - size_t wr_len = MIN(size, (size_t)(FLASH_PAGE_SIZE_BYTES - page_addr)); + flash_sendWRcmd(idx); - memcpy(fd->page_buf + page_addr, buf, wr_len); - fd->page_dirty = true; + if (!flash_getStatus(blk)) + return 0; - buf += wr_len; - fd->fd.seek_pos += wr_len; - size -= wr_len; - total_write += wr_len; - } - LOG_INFO("written %u bytes\n", total_write); - return total_write; + return blk->blk_size; } -/** - * 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; +static int at91_flash_error(struct KBlock *blk) +{ + Flash *fls = FLASH_CAST(blk); + return fls->hw->status; } -/** - * Open flash file \a fd - * \a name and \a mode are unused, cause flash memory is - * threated like one file. - */ -static void flash_at91_open(struct Flash *fd) +static void at91_flash_clearerror(struct KBlock *blk) { - 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->page_dirty = false; - LOG_INFO("Flash file opened\n"); + Flash *fls = FLASH_CAST(blk); + fls->hw->status = 0; } - -/** - * 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) +static const KBlockVTable flash_at91_buffered_vt = { - Flash *fd = FLASH_CAST(_fd); - kfile_off_t seek_pos; + .readDirect = at91_flash_readDirect, + .writeDirect = at91_flash_writeDirect, - switch (whence) - { + .readBuf = kblock_swReadBuf, + .writeBuf = kblock_swWriteBuf, + .load = kblock_swLoad, + .store = kblock_swStore, - 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; - } + .error = at91_flash_error, + .clearerr = at91_flash_clearerror, +}; - #if LOG_LEVEL >= LOG_LVL_INFO - /* Bound check */ - if (seek_pos + offset > fd->fd.size) - LOG_INFO("seek outside EOF\n"); - #endif +static const KBlockVTable flash_at91_unbuffered_vt = +{ + .readDirect = at91_flash_readDirect, + .writeDirect = at91_flash_writeDirect, - fd->fd.seek_pos = seek_pos + offset; + .error = at91_flash_error, + .clearerr = at91_flash_clearerror, +}; - return fd->fd.seek_pos - (FLASH_BASE + FLASH_BOOT_SIZE); -} +static struct FlashHardware flash_at91_hw; +static uint8_t flash_buf[FLASH_PAGE_SIZE_BYTES]; -/** - * Reopen file \a fd - */ -static struct KFile *flash_at91_reopen(struct KFile *_fd) +static void common_init(Flash *fls) { - Flash *fd = FLASH_CAST(_fd); - flash_at91_close(_fd); - flash_at91_open(fd); + memset(fls, 0, sizeof(*fls)); + DB(fls->blk.priv.type = KBT_FLASH); + + fls->hw = &flash_at91_hw; - return _fd; + fls->blk.blk_size = FLASH_PAGE_SIZE_BYTES; + fls->blk.blk_cnt = FLASH_MEM_SIZE / FLASH_PAGE_SIZE_BYTES; } -/** - * Read from file \a fd \a size bytes and put it in buffer \a buf - * \return the number of bytes read. - */ -static size_t flash_at91_read(struct KFile *_fd, void *_buf, size_t size) +void flash_hw_init(Flash *fls, UNUSED_ARG(int, flags)) { - Flash *fd = FLASH_CAST(_fd); - uint8_t *buf =(uint8_t *)_buf; - - size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos); - - LOG_INFO("Reading at pos[%lu]\n", fd->fd.seek_pos); - - // Flush current buffered page (if modified). - flash_at91_flush(fd); - - uint32_t *addr = (uint32_t *)fd->fd.seek_pos; - memcpy(buf, (uint8_t *)addr, size); - - fd->fd.seek_pos += size; + common_init(fls); + fls->blk.priv.vt = &flash_at91_buffered_vt; + fls->blk.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE; + fls->blk.priv.buf = flash_buf; - LOG_INFO("Read %u bytes\n", size); - return size; + /* Load the first block in the cache */ + memcpy(fls->blk.priv.buf, (void *)(FLASH_BASE), fls->blk.blk_size); } - -/** - * Init module to perform write and read operation on internal - * flash memory. - */ -void flash_hw_init(struct Flash *fd) +void flash_hw_initUnbuffered(Flash *fls, UNUSED_ARG(int, flags)) { - memset(fd, 0, sizeof(*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; - - 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; - + common_init(fls); + fls->blk.priv.vt = &flash_at91_unbuffered_vt; } +