static int erase_sector(sector_descriptor_t *sm, flash_entry_header_t *pf) { int rv = 0; ssize_t page = up_progmem_getpage((size_t)pf); if (page > 0 && page == sm->page) { last_erased = sm->page; ssize_t size = up_progmem_erasepage(page); if (size < 0 || size != sm->size) { rv = size; } } return rv; }
ssize_t up_progmem_write(size_t addr, const void *buf, size_t count) { int page; int pagesize; size_t remain = count; page = up_progmem_getpage(addr + count); if (page < 0) { return -EINVAL; } pagesize = up_progmem_pagesize(page); while (remain) { int tmp = remain; irqstate_t irqs; if (tmp > pagesize) { tmp = pagesize; } /* Disable IRQs */ irqs = irqsave(); s5j_sflash_disable_wp(); /* Load and write data */ memcpy((void *)addr, buf, tmp); /* Flush cache */ arch_flush_dcache(addr, addr + tmp); s5j_sflash_enable_wp(); /* Restore IRQs */ irqrestore(irqs); buf += tmp; addr += tmp; remain -= tmp; } return count; }
static int install_remove(const char *scriptname) { FILE *fp; int progsize, addr, freedsize; uint16_t page; int status = 0; /* Parse script */ if ((fp = fopen(scriptname, "r"))) { progsize = install_getlasthexvalue(fp,'='); addr = install_getlasthexvalue(fp,' '); freedsize = progsize; } else { return -errno; } fclose(fp); /* Remove pages */ if (progsize <= 0 || addr <= 0) { return -EIO; } do { if ((page = up_progmem_getpage(addr)) < 0) { status = -page; break; } if (up_progmem_erasepage(page) < 0) { status = -page; break; } addr += up_progmem_pagesize(page); progsize -= up_progmem_pagesize(page); } while (progsize > 0); if (status < 0) { return status; } /* Remove script file */ if (unlink(scriptname) < 0) { return -errno; } return freedsize; }
ssize_t __ramfunc__ up_progmem_write(size_t addr, const void *buf, size_t size) { int ret = 0; int word_count; int num_words; int page_words; uint32_t *p_data; uint32_t *address = (uint32_t *)addr; uint32_t num_bytes = size; /* EFM32 requires word access */ if (addr & 3) { return -EINVAL; } /* EFM32 requires word access */ if (num_bytes & 3) { return -EINVAL; } efm32_flash_unlock(); /* enable writing to the flash */ bitband_set_peripheral(EFM32_MSC_WRITECTRL, _MSC_WRITECTRL_WREN_SHIFT, 1); /* Convert bytes to words */ num_words = num_bytes >> 2; /* The following loop splits the data into chunks corresponding to flash pages. * The address is loaded only once per page, because the hardware automatically * increments the address internally for each data load inside a page. */ for (word_count = 0, p_data = (uint32_t *)buf; word_count < num_words; ) { int page_bytes; ssize_t page_idx; irqstate_t flags; /* Compute the number of words to write to the current page. */ page_idx = up_progmem_getpage((size_t)address+(word_count << 2)); if (page_idx < 0) { ret = -EINVAL; break; } page_bytes = up_progmem_pagesize(page_idx); if (page_bytes < 0) { ret = -EINVAL; break; } page_words = (page_bytes - (((uint32_t) (address + word_count)) & \ (page_bytes-1))) / sizeof(uint32_t); if (page_words > num_words - word_count) { page_words = num_words - word_count; } flags = enter_critical_section(); /* First we load address. The address is auto-incremented within a page. * Therefore the address phase is only needed once for each page. */ ret = msc_load_verify_address(address + word_count); /* Now write the data in the current page. */ if (ret == 0) { ret = msc_load_write_data(p_data, page_words, true); } leave_critical_section(flags); if (ret != 0) { break; } word_count += page_words; p_data += page_words; } /* Disable writing to the MSC */ bitband_set_peripheral(EFM32_MSC_WRITECTRL, _MSC_WRITECTRL_WREN_SHIFT, 0); #if (defined(CONFIG_EFM32_EFM32GG) || defined(CONFIG_EFM32_EFM32WG)) && (2==WORDS_PER_DATA_PHASE) /* Turn off double word write cycle support. */ bitband_set_peripheral(EFM32_MSC_WRITECTRL, _MSC_WRITECTRL_WDOUBLE_SHIFT, 0); #endif if (ret < 0) { return ret; } return word_count; }