X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fcpu%2Farm%2Fdrv%2Fflash_lpc2.c;h=e1a3391bf7bbc39a1deec9a8728228f5af300854;hb=HEAD;hp=7e0013ca6d67532ec7bdbdb50746785c0a520163;hpb=d9e5b68973a06a7f721af148b6cccdef0ddce3f2;p=bertos.git diff --git a/bertos/cpu/arm/drv/flash_lpc2.c b/bertos/cpu/arm/drv/flash_lpc2.c index 7e0013ca..e1a3391b 100644 --- a/bertos/cpu/arm/drv/flash_lpc2.c +++ b/bertos/cpu/arm/drv/flash_lpc2.c @@ -35,7 +35,7 @@ * * \brief NPX lpc23xx embedded flash read/write driver. * - * notest: arm + * notest:arm */ #include "flash_lpc2.h" @@ -58,13 +58,68 @@ #include #include +#include + #include +/* Embedded flash programming defines. */ +#define IAP_ADDRESS 0x7ffffff1 + +typedef enum IapCommands +{ + PREPARE_SECTOR_FOR_WRITE = 50, + COPY_RAM_TO_FLASH = 51, + ERASE_SECTOR = 52, + BLANK_CHECK_SECTOR = 53, + READ_PART_ID = 54, + READ_BOOT_VER = 55, + COMPARE = 56, + 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 @@ -123,107 +178,117 @@ static uint32_t addr_to_sector(size_t addr) return 0; } -static uint32_t addr_to_pageaddr(size_t addr) -{ - 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; -} - static size_t lpc2_flash_readDirect(struct KBlock *blk, block_idx_t idx, void *buf, size_t offset, size_t size) { - ASSERT(offset == 0); - ASSERT(size == blk->blk_size); - - ASSERT(sector_size(idx) <= FLASH_PAGE_SIZE_BYTES); - - memcpy(buf, (void *)(idx * blk->blk_size), size); + 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(size == blk->blk_size); - ASSERT(sector_size(idx) <= FLASH_PAGE_SIZE_BYTES); + ASSERT(FLASH_PAGE_SIZE_BYTES == size); Flash *fls = FLASH_CAST(blk); + if (!(fls->hw->flags & FLASH_WRITE_ONCE)) + ASSERT(sector_size(idx) <= FLASH_PAGE_SIZE_BYTES); + const uint8_t *buf = (const uint8_t *)_buf; cpu_flags_t flags; //Compute page address of current page. - uint32_t addr = sector_addr(idx); - - LOG_INFO("Writing page %ld...\n", idx); + 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] = idx; + cmd.param[0] = cmd.param[1] = sector; iap(&cmd, &res); - if (res.status != CMD_SUCCESS) - { - LOG_ERR("%ld\n", res.status); - fls->hw->status |= FLASH_WR_ERR; - return 0; - } - cmd.cmd = ERASE_SECTOR; - cmd.param[0] = cmd.param[1] = idx; - cmd.param[2] = CPU_FREQ / 1000; - iap(&cmd, &res); if (res.status != CMD_SUCCESS) + goto flash_error; + + if ((fls->hw->flags & FLASH_WRITE_ONCE) && + bitarray_isRangeFull(&lpc2_bitx, idx_sector, erase_group[sector])) { - LOG_ERR("%ld\n", res.status); - fls->hw->status |= FLASH_WR_ERR; - return 0; + kputs("blocchi pieni\n"); + ASSERT(0); + goto flash_error; } - while (size) + bool erase = false; + if ((fls->hw->flags & FLASH_WRITE_ONCE) && + bitarray_isRangeEmpty(&lpc2_bitx, idx_sector, erase_group[sector])) + erase = true; + + if (!(fls->hw->flags & FLASH_WRITE_ONCE)) + erase = true; + + if (erase) { - LOG_INFO("Writing page %ld, addr %ld, size %d\n", idx, addr, size); - cmd.cmd = PREPARE_SECTOR_FOR_WRITE; - cmd.param[0] = cmd.param[1] = idx; + 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); - fls->hw->status |= FLASH_WR_ERR; - return 0; - } - 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) + goto flash_error; + } + + 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)) { - LOG_ERR("%ld\n", res.status); - fls->hw->status |= FLASH_WR_ERR; - return 0; + ASSERT(0); + goto flash_error; } - - size -= 4096; - addr += 4096; - buf += 4096 / sizeof(uint32_t); + 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; } +static int lpc2_flash_close(UNUSED_ARG(struct KBlock, *blk)) +{ + memset(page_dirty, 0, sizeof(page_dirty)); + return 0; +} + + static int lpc2_flash_error(struct KBlock *blk) { Flash *fls = FLASH_CAST(blk); @@ -246,7 +311,7 @@ static const KBlockVTable flash_lpc2_buffered_vt = .load = kblock_swLoad, .store = kblock_swStore, - .close = kblock_swClose, + .close = lpc2_flash_close, .error = lpc2_flash_error, .clearerr = lpc2_flash_clearerror, @@ -257,7 +322,7 @@ static const KBlockVTable flash_lpc2_unbuffered_vt = .readDirect = lpc2_flash_readDirect, .writeDirect = lpc2_flash_writeDirect, - .close = kblock_swClose, + .close = lpc2_flash_close, .error = lpc2_flash_error, .clearerr = lpc2_flash_clearerror, @@ -266,33 +331,35 @@ static const KBlockVTable flash_lpc2_unbuffered_vt = static struct FlashHardware flash_lpc2_hw; static uint8_t flash_buf[FLASH_PAGE_SIZE_BYTES]; -static void common_init(Flash *fls) +static void common_init(Flash *fls, int flags) { memset(fls, 0, sizeof(*fls)); DB(fls->blk.priv.type = KBT_FLASH); fls->hw = &flash_lpc2_hw; + fls->hw->flags = flags; fls->blk.blk_size = FLASH_PAGE_SIZE_BYTES; - fls->blk.blk_cnt = 28; + fls->blk.blk_cnt = FLASH_MEM_SIZE / FLASH_PAGE_SIZE_BYTES; + + bitarray_init(&lpc2_bitx, FLASH_PAGE_CNT, page_dirty, sizeof(page_dirty)); } -void flash_hw_init(Flash *fls) +void flash_hw_init(Flash *fls, int flags) { - common_init(fls); + 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; + /* Load the first block in the cache */ void *flash_start = 0x0; memcpy(fls->blk.priv.buf, flash_start, fls->blk.blk_size); - - kprintf("page[%d]\n", sector_addr(22)); } -void flash_hw_initUnbuffered(Flash *fls) +void flash_hw_initUnbuffered(Flash *fls, int flags) { - common_init(fls); + common_init(fls, flags); fls->blk.priv.vt = &flash_lpc2_unbuffered_vt; }