X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fcpu%2Farm%2Fdrv%2Fflash_lpc2.c;h=e1a3391bf7bbc39a1deec9a8728228f5af300854;hb=aa23c5d7c7b2b79e8ff74eb00bb12531b35731b4;hp=f3c60f1fd28a763f59e1620615e6cd00176786a4;hpb=2c2b94faec39918adfcb6eb94f65ed5c312826cd;p=bertos.git diff --git a/bertos/cpu/arm/drv/flash_lpc2.c b/bertos/cpu/arm/drv/flash_lpc2.c index f3c60f1f..e1a3391b 100644 --- a/bertos/cpu/arm/drv/flash_lpc2.c +++ b/bertos/cpu/arm/drv/flash_lpc2.c @@ -34,6 +34,8 @@ * \author Daniele Basile * * \brief NPX lpc23xx embedded flash read/write driver. + * + * notest:arm */ #include "flash_lpc2.h" @@ -48,17 +50,19 @@ #include #include #include +#include -#include - +#include #include #include #include -#include +#include +#include +/* Embedded flash programming defines. */ #define IAP_ADDRESS 0x7ffffff1 typedef enum IapCommands @@ -73,9 +77,51 @@ typedef enum IapCommands REINVOKE_ISP = 57, } IapCommands; +#if CPU_ARM_LPC2378 + #define FLASH_MEM_SIZE (504 * 1024L) + #define FLASH_PAGE_SIZE_BYTES 4096 + #define FLASH_REAL_PAGE_CNT 28 +#else + #error Unknown CPU +#endif #define CMD_SUCCESS 0 +struct FlashHardware +{ + uint8_t status; + int flags; +}; + +#define FLASH_PAGE_CNT FLASH_MEM_SIZE / FLASH_PAGE_SIZE_BYTES + +BITARRAY_ALLOC(page_dirty, FLASH_PAGE_CNT); +static BitArray lpc2_bitx; + +uint8_t erase_group[] = { + + 4096 / FLASH_PAGE_SIZE_BYTES, 4096 / FLASH_PAGE_SIZE_BYTES, + 4096 / FLASH_PAGE_SIZE_BYTES, 4096 / FLASH_PAGE_SIZE_BYTES, + + 4096 / FLASH_PAGE_SIZE_BYTES, 4096 / FLASH_PAGE_SIZE_BYTES, + 4096 / FLASH_PAGE_SIZE_BYTES, 4096 / FLASH_PAGE_SIZE_BYTES, + + 32768 / FLASH_PAGE_SIZE_BYTES, 32768 / FLASH_PAGE_SIZE_BYTES, + 32768 / FLASH_PAGE_SIZE_BYTES, 32768 / FLASH_PAGE_SIZE_BYTES, + + 32768 / FLASH_PAGE_SIZE_BYTES, 32768 / FLASH_PAGE_SIZE_BYTES, + 32768 / FLASH_PAGE_SIZE_BYTES, 32768 / FLASH_PAGE_SIZE_BYTES, + + 32768 / FLASH_PAGE_SIZE_BYTES, 32768 / FLASH_PAGE_SIZE_BYTES, + 32768 / FLASH_PAGE_SIZE_BYTES, 32768 / FLASH_PAGE_SIZE_BYTES, + + 32768 / FLASH_PAGE_SIZE_BYTES, 32768 / FLASH_PAGE_SIZE_BYTES, + 4096 / FLASH_PAGE_SIZE_BYTES, 4096 / FLASH_PAGE_SIZE_BYTES, + + 4096 / FLASH_PAGE_SIZE_BYTES, 4096 / FLASH_PAGE_SIZE_BYTES, + 4096 / FLASH_PAGE_SIZE_BYTES, 4096 / FLASH_PAGE_SIZE_BYTES, +}; + typedef struct IapCmd { uint32_t cmd; @@ -90,13 +136,9 @@ typedef struct IapRes typedef void (*iap_callback_t)(IapCmd *, IapRes *); -iap_callback_t iap=(iap_callback_t)IAP_ADDRESS; - -#define FLASH_MEM_SIZE (504 * 1024L) - -static size_t flash_start_addr; +iap_callback_t iap = (iap_callback_t)IAP_ADDRESS; -static size_t sector_size(page_t page) +static size_t sector_size(uint32_t page) { if (page < 8) return 4096; @@ -109,7 +151,7 @@ static size_t sector_size(page_t page) return 0; } -static size_t sector_addr(page_t page) +static size_t sector_addr(uint32_t page) { if (page < 8) return page * 4096; @@ -123,7 +165,7 @@ static size_t sector_addr(page_t page) } -static page_t addr_to_sector(size_t addr) +static uint32_t addr_to_sector(size_t addr) { if (addr < 4096 * 8) return addr / 4096; @@ -136,232 +178,188 @@ static page_t addr_to_sector(size_t addr) return 0; } -static page_addr_t addr_to_pageaddr(size_t addr) +static size_t lpc2_flash_readDirect(struct KBlock *blk, block_idx_t idx, void *buf, size_t offset, size_t size) { - if (addr < 4096 * 8) - return addr % 4096; - else if (addr < 4096 * 8 + 32768L * 14) - return (addr - 4096 * 8) % 32768; - else if (addr < 4096 * 8 + 32768L * 14 + 4096 * 6) - return (addr - 4096 * 8 - 32768L * 14) % 4096; - - ASSERT(0); - return 0; + memcpy(buf, (void *)(idx * blk->blk_size + offset), size); + return size; } +static size_t lpc2_flash_writeDirect(struct KBlock *blk, block_idx_t idx, const void *_buf, size_t offset, size_t size) +{ + ASSERT(offset == 0); + ASSERT(FLASH_PAGE_SIZE_BYTES == size); -static uint32_t page_buf[1024];//MAX_FLASH_PAGE_SIZE / sizeof(uint32_t)]; -static bool page_dirty; -static page_t curr_page; + Flash *fls = FLASH_CAST(blk); + if (!(fls->hw->flags & FLASH_WRITE_ONCE)) + ASSERT(sector_size(idx) <= FLASH_PAGE_SIZE_BYTES); -/** - * Send write command. - * - * After WR command cpu write bufferd page into flash memory. - * - */ -static void flash_lpc2_writePage(page_t page, uint32_t *buf) -{ + const uint8_t *buf = (const uint8_t *)_buf; cpu_flags_t flags; //Compute page address of current page. - page_addr_t addr = sector_addr(page); - - LOG_INFO("Writing page %ld...\n", page); + uint32_t addr = idx * blk->blk_size; + uint32_t sector = addr_to_sector(addr); + // Compute the first page index in the sector to manage the status + int idx_sector = sector_addr(sector) / blk->blk_size; + LOG_INFO("Writing page[%ld]sector[%ld]idx[%d]\n", idx, sector, idx_sector); IRQ_SAVE_DISABLE(flags); IapCmd cmd; IapRes res; cmd.cmd = PREPARE_SECTOR_FOR_WRITE; - cmd.param[0] = cmd.param[1] = page; + cmd.param[0] = cmd.param[1] = sector; iap(&cmd, &res); - if (res.status != CMD_SUCCESS) - LOG_ERR("%ld\n", res.status); - cmd.cmd = ERASE_SECTOR; - cmd.param[0] = cmd.param[1] = page; - cmd.param[2] = CPU_FREQ / 1000; - iap(&cmd, &res); if (res.status != CMD_SUCCESS) - LOG_ERR("%ld\n", res.status); + goto flash_error; - size_t size = sector_size(page); + if ((fls->hw->flags & FLASH_WRITE_ONCE) && + bitarray_isRangeFull(&lpc2_bitx, idx_sector, erase_group[sector])) + { + kputs("blocchi pieni\n"); + ASSERT(0); + goto flash_error; + } + + bool erase = false; + if ((fls->hw->flags & FLASH_WRITE_ONCE) && + bitarray_isRangeEmpty(&lpc2_bitx, idx_sector, erase_group[sector])) + erase = true; - while (size) + if (!(fls->hw->flags & FLASH_WRITE_ONCE)) + erase = true; + + if (erase) { - LOG_INFO("Writing page %ld, addr %ld, size %d\n", page, addr, size); - cmd.cmd = PREPARE_SECTOR_FOR_WRITE; - cmd.param[0] = cmd.param[1] = page; + cmd.cmd = ERASE_SECTOR; + cmd.param[0] = cmd.param[1] = sector; + cmd.param[2] = CPU_FREQ / 1000; iap(&cmd, &res); - if (res.status != CMD_SUCCESS) - LOG_ERR("%ld\n", res.status); - cmd.cmd = COPY_RAM_TO_FLASH; - cmd.param[0] = addr; - cmd.param[1] = (uint32_t)buf; - cmd.param[2] = 4096; - cmd.param[3] = CPU_FREQ / 1000; - iap(&cmd, &res); if (res.status != CMD_SUCCESS) - LOG_ERR("%ld\n", res.status); + goto flash_error; + } - size -= 4096; - addr += 4096; - buf += 4096 / sizeof(uint32_t); + LOG_INFO("Writing page [%ld], addr [%ld] in sector[%ld]\n", idx, addr, sector); + cmd.cmd = PREPARE_SECTOR_FOR_WRITE; + cmd.param[0] = cmd.param[1] = sector; + iap(&cmd, &res); + + if (res.status != CMD_SUCCESS) + goto flash_error; + + if (fls->hw->flags & FLASH_WRITE_ONCE) + { + if (bitarray_test(&lpc2_bitx, idx)) + { + ASSERT(0); + goto flash_error; + } + else + bitarray_set(&lpc2_bitx, idx); } + cmd.cmd = COPY_RAM_TO_FLASH; + cmd.param[0] = addr; + cmd.param[1] = (uint32_t)buf; + cmd.param[2] = FLASH_PAGE_SIZE_BYTES; + cmd.param[3] = CPU_FREQ / 1000; + iap(&cmd, &res); + + if (res.status != CMD_SUCCESS) + goto flash_error; + IRQ_RESTORE(flags); LOG_INFO("Done\n"); + + return blk->blk_size; + +flash_error: + IRQ_RESTORE(flags); + LOG_ERR("%ld\n", res.status); + fls->hw->status |= FLASH_WR_ERR; + return 0; } -/** - * Write modified page on internal latch, and then send write command to - * flush page to internal flash. - */ -static int flash_lpc2_flush(UNUSED_ARG(KFile *, _fd)) +static int lpc2_flash_close(UNUSED_ARG(struct KBlock, *blk)) { - if (page_dirty) - { - flash_lpc2_writePage(curr_page, page_buf); - page_dirty = false; - } + memset(page_dirty, 0, sizeof(page_dirty)); return 0; } -/** - * Check current page and if \a page is different, load it in - * temporary buffer. - */ -static void flash_lpc2_loadPage(KFile *fd, page_t page) +static int lpc2_flash_error(struct KBlock *blk) { - if (page != curr_page) - { - flash_lpc2_flush(fd); - - size_t addr = sector_addr(page); - size_t size = sector_size(page); - LOG_INFO("page %ld, addr %d, size %d\n", page, addr, size); - // Load page - memcpy(page_buf, (char *)addr, size); - curr_page = page; - LOG_INFO("Loaded page %lu\n", curr_page); - } + Flash *fls = FLASH_CAST(blk); + return fls->hw->status; } -/** - * Write program memory. - * Write \a size bytes from buffer \a _buf to file \a fd - * \note Write operations are buffered. - */ -static size_t flash_lpc2_write(struct KFile *fd, const void *_buf, size_t size) +static void lpc2_flash_clearerror(struct KBlock *blk) { - const uint8_t *buf =(const uint8_t *)_buf; - - page_t page; - page_addr_t page_addr; - size_t total_write = 0; - - size = MIN((kfile_off_t)size, fd->size - fd->seek_pos); - - LOG_INFO("Writing at pos[%lu]\n", fd->seek_pos); - while (size) - { - page = addr_to_sector(fd->seek_pos + flash_start_addr); - page_addr = addr_to_pageaddr(fd->seek_pos + flash_start_addr); - LOG_INFO("addr %ld, page %ld, page_addr %ld\n", fd->seek_pos + flash_start_addr, page, page_addr); + Flash *fls = FLASH_CAST(blk); + fls->hw->status = 0; +} - flash_lpc2_loadPage(fd, page); +static const KBlockVTable flash_lpc2_buffered_vt = +{ + .readDirect = lpc2_flash_readDirect, + .writeDirect = lpc2_flash_writeDirect, - size_t wr_len = MIN(size, (size_t)(sector_size(page) - page_addr)); + .readBuf = kblock_swReadBuf, + .writeBuf = kblock_swWriteBuf, + .load = kblock_swLoad, + .store = kblock_swStore, - memcpy(((uint8_t *)page_buf) + page_addr, buf, wr_len); - page_dirty = true; + .close = lpc2_flash_close, - buf += wr_len; - fd->seek_pos += wr_len; - size -= wr_len; - total_write += wr_len; - } - LOG_INFO("written %u bytes\n", total_write); - return total_write; -} + .error = lpc2_flash_error, + .clearerr = lpc2_flash_clearerror, +}; -/** - * Open flash file \a fd - * \a name and \a mode are unused, cause flash memory is - * threated like one file. - */ -static void flash_lpc2_open(struct FlashLpc2 *fd) +static const KBlockVTable flash_lpc2_unbuffered_vt = { - curr_page = addr_to_sector(FLASH_BOOT_SIZE); - if (addr_to_pageaddr(FLASH_BOOT_SIZE)) - curr_page++; + .readDirect = lpc2_flash_readDirect, + .writeDirect = lpc2_flash_writeDirect, - flash_start_addr = sector_addr(curr_page); - LOG_INFO("Boot size %d, curr_page %ld, flash_start_addr %d\n", FLASH_BOOT_SIZE, curr_page, flash_start_addr); + .close = lpc2_flash_close, - fd->fd.size = FLASH_MEM_SIZE - sector_addr(curr_page); - fd->fd.seek_pos = 0; + .error = lpc2_flash_error, + .clearerr = lpc2_flash_clearerror, +}; - memcpy(page_buf, (char *)sector_addr(curr_page), sector_size(curr_page)); +static struct FlashHardware flash_lpc2_hw; +static uint8_t flash_buf[FLASH_PAGE_SIZE_BYTES]; - page_dirty = false; - LOG_INFO("Flash file opened, pos %ld, size %ld\n", fd->fd.seek_pos, fd->fd.size); -} - -/** - * 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_lpc2_read(struct KFile *fd, void *_buf, size_t size) +static void common_init(Flash *fls, int flags) { - uint8_t *buf =(uint8_t *)_buf; - - size = MIN((kfile_off_t)size, fd->size - fd->seek_pos); - - LOG_INFO("Reading at pos[%lu]\n", fd->seek_pos); + memset(fls, 0, sizeof(*fls)); + DB(fls->blk.priv.type = KBT_FLASH); - // Flush current buffered page (if modified). - flash_lpc2_flush(fd); + fls->hw = &flash_lpc2_hw; + fls->hw->flags = flags; - kfile_off_t *addr = (kfile_off_t *)(fd->seek_pos + flash_start_addr); - LOG_INFO("actual addr %ld\n", (uint32_t)addr); - memcpy(buf, addr, size); + fls->blk.blk_size = FLASH_PAGE_SIZE_BYTES; + fls->blk.blk_cnt = FLASH_MEM_SIZE / FLASH_PAGE_SIZE_BYTES; - for (unsigned i = 0; i< size; i++) - { - if (i % 16 == 0) - kputchar('\n'); + bitarray_init(&lpc2_bitx, FLASH_PAGE_CNT, page_dirty, sizeof(page_dirty)); +} - kprintf("%02x ", buf[i]); - } - kputchar('\n'); +void flash_hw_init(Flash *fls, int flags) +{ + common_init(fls, flags); + fls->blk.priv.vt = &flash_lpc2_buffered_vt; + fls->blk.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE; + fls->blk.priv.buf = flash_buf; - fd->seek_pos += size; - LOG_INFO("Read %u bytes\n", size); - return size; + /* Load the first block in the cache */ + void *flash_start = 0x0; + memcpy(fls->blk.priv.buf, flash_start, fls->blk.blk_size); } - -/** - * Init module to perform write and read operation on internal - * flash memory. - */ -void flash_hw_init(struct FlashLpc2 *fd) +void flash_hw_initUnbuffered(Flash *fls, int flags) { - memset(fd, 0, sizeof(*fd)); - // Init base class. - kfile_init(&fd->fd); - DB(fd->fd._type = KFT_FLASH); - - // Set up flash programming functions. - fd->fd.write = flash_lpc2_write; - fd->fd.read = flash_lpc2_read; - fd->fd.flush = flash_lpc2_flush; - - flash_lpc2_open(fd); - TRACE; + common_init(fls, flags); + fls->blk.priv.vt = &flash_lpc2_unbuffered_vt; }