static void program_flash(cyg_addrword_t arg) { diag_printf("PROGRAM FLASH here!\n"); HAL_UCACHE_SYNC(); // ROM space is marked cacheable which causes problems! HAL_UCACHE_DISABLE(); // So, just disable caches. identify_FLASH(); diag_printf("About to program FLASH using data at %x..%x\n", flash_buffer, flash_buffer_end); diag_printf("*** Press RESET now to abort!\n"); cyg_thread_delay(5*100); diag_printf("\n"); diag_printf("... Erase sector\n"); if (erase_sector(ROM_address)) { diag_printf("... Programming FLASH\n"); while (flash_buffer < flash_buffer_end) { if (!write_flash(flash_buffer++, ROM_address++)) break; } } // Exit Program Mode switch (manuf_code) { case ATMEL_MANUF: FLASH[ATMEL_SEQ_ADD1] = ATMEL_START_CMD1; FLASH[ATMEL_SEQ_ADD2] = ATMEL_START_CMD2; FLASH[ATMEL_SEQ_ADD1] = ATMEL_STOP_CMD; break; case INTEL_MANUF: FLASH[0] = INTEL_STOP_CMD; break; } diag_printf("All done!\n"); cyg_test_exit(); }
void find_erase_sector(unsigned cclk, unsigned dst) { unsigned k; __disable_irq(); for(k = USER_START_SECTOR;k <= MAX_USER_SECTOR; k++) { if(dst < sector_end_map[k]) { if(dst == sector_start_map[k]) { erase_sector(k, k, cclk); } break; } } __enable_irq(); if(result_table[0] != CMD_SUCCESS) { serial_writestr("Error: erasing data\n"); } }
/*---------------------------------------------------------------------------*/ int xmem_erase(long size, unsigned long addr) { unsigned long end = addr + size; if(size % XMEM_ERASE_UNIT_SIZE != 0) { PRINTF("xmem_erase: bad size\n"); return -1; } if(addr % XMEM_ERASE_UNIT_SIZE != 0) { PRINTF("xmem_erase: bad offset\n"); return -1; } watchdog_stop(); for (; addr < end; addr += XMEM_ERASE_UNIT_SIZE) { erase_sector(addr); } watchdog_start(); return size; }
/* erase both sectors */ bool AP_FlashStorage::erase_all(void) { write_error = false; current_sector = 0; write_offset = sizeof(struct sector_header); if (!erase_sector(0) || !erase_sector(1)) { return false; } // mark current sector as in-use struct sector_header header; header.signature = signature; header.state = SECTOR_STATE_IN_USE; return flash_write(current_sector, 0, (const uint8_t *)&header, sizeof(header)); }
void erase_user_flash(void) { prepare_sector(USER_START_SECTOR,MAX_USER_SECTOR,SystemCoreClock/1000); erase_sector(USER_START_SECTOR,MAX_USER_SECTOR,SystemCoreClock/1000); if(result_table[0] != CMD_SUCCESS) { serial_writestr("Error: erasing data\n"); } }
void erase_user_flash(void) { prepare_sector(USER_START_SECTOR,MAX_USER_SECTOR,SystemCoreClock/1000); erase_sector(USER_START_SECTOR,MAX_USER_SECTOR,SystemCoreClock/1000); if(result_table[0] != CMD_SUCCESS) { while(1); /* No way to recover. Just let OS report a write failure */ } }
/* * Erase an address range on the flash chip. The address range may extend * one or more erase sectors. Return an error is there is a problem erasing. */ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) { struct m25p *flash = mtd_to_m25p(mtd); u32 addr,len; DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", flash->spi->dev.bus_id, __func__, "at", (u32)instr->addr, instr->len); /* sanity checks */ if (instr->addr + instr->len > flash->mtd.size) return -EINVAL; if ((instr->addr % mtd->erasesize) != 0 || (instr->len % mtd->erasesize) != 0) { return -EINVAL; } addr = instr->addr; len = instr->len; mutex_lock(&flash->lock); /* whole-chip erase? */ if (len == flash->mtd.size && erase_chip(flash)) { instr->state = MTD_ERASE_FAILED; mutex_unlock(&flash->lock); return -EIO; /* REVISIT in some cases we could speed up erasing large regions * by using OPCODE_SE instead of OPCODE_BE_4K. We may have set up * to use "small sector erase", but that's not always optimal. */ /* "sector"-at-a-time erase */ } else { while (len) { if (erase_sector(flash, addr)) { instr->state = MTD_ERASE_FAILED; mutex_unlock(&flash->lock); return -EIO; } addr += mtd->erasesize; len -= mtd->erasesize; } } mutex_unlock(&flash->lock); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
int Usb3Camera::erase_eeprom (std::function<void(int)> progress) { int r = -1; progress(0); for (unsigned int i = 0; i < 5; ++i) { r = erase_sector(i * SECTOR_SIZE); if (r == 0) progress(20 * (i+1)); } return r; }
/* * Erase an address range on the flash chip. The address range may extend * one or more erase sectors. Return an error is there is a problem erasing. */ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) { struct m25p *flash = mtd_to_m25p(mtd); u32 addr,len; DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", flash->spi->dev.bus_id, __func__, "at", (u32)instr->addr, instr->len); /* sanity checks */ if (instr->addr + instr->len > flash->mtd.size) return -EINVAL; if ((instr->addr % mtd->erasesize) != 0 || (instr->len % mtd->erasesize) != 0) { return -EINVAL; } addr = instr->addr; len = instr->len; mutex_lock(&flash->lock); /* REVISIT in some cases we could speed up erasing large regions * by using OPCODE_SE instead of OPCODE_BE_4K */ /* now erase those sectors */ while (len) { if (erase_sector(flash, addr)) { instr->state = MTD_ERASE_FAILED; mutex_unlock(&flash->lock); return -EIO; } addr += mtd->erasesize; len -= mtd->erasesize; } mutex_unlock(&flash->lock); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
// switch full sector - should only be called when safe to have CPU // offline for considerable periods as an erase will be needed bool AP_FlashStorage::switch_full_sector(void) { debug("running switch_full_sector()\n"); // clear any write error write_error = false; reserved_space = 0; if (!write_all()) { return false; } if (!erase_sector(current_sector ^ 1)) { return false; } return switch_sectors(); }
int parameter_flashfs_erase(void) { int rv = -ENXIO; if (sector_map) { rv = 0; for (int s = 0; sector_map[s].address; s++) { int sz = erase_sector(§or_map[s], (flash_entry_header_t *)sector_map[s].address); if (sz != 0) { return sz; } rv += sector_map[s].size; } } return rv; }
void find_erase_prepare_sector(unsigned cclk, unsigned dst) { unsigned i; __disable_irq(); for(i = USER_START_SECTOR; i <= MAX_USER_SECTOR; i++) { if(dst < sector_end_map[i]) { if(dst == sector_start_map[i]) { prepare_sector(i, i, cclk); erase_sector(i, i, cclk); } prepare_sector(i , i, cclk); break; } } __enable_irq(); }
// Check if a sector is blank and if not, erase it // wipe_sector isn't working for unknown reasons // Doesn't return an error, just seems to freeze the MBED // uint16_t sector => sector id to wipe unsigned wipe_sector(uint16_t sector) { #if DEBUG==1 tty_writeln("Wiping sector"); #endif blank_check_sector(sector, sector); if(output[0] == SECTOR_NOT_BLANK) { prepare_sector_write(sector, sector); if (output[0] !=0) { write_error(output[0]); return output[0]; } erase_sector(sector, sector); if (output[0] !=0) { write_error(output[0]); return output[0]; } } #if DEBUG==1 tty_writeln("Sector wipe"); #endif return 0; }
/* * Erase an address range on the flash chip. The address range may extend * one or more erase sectors. Return an error is there is a problem erasing. */ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) { struct m25p *flash = mtd_to_m25p(mtd); u32 addr,len; uint64_t tmpdiv; int rem, rem1; DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", flash->spi->dev.bus_id, __FUNCTION__, "at", (u32)instr->addr, instr->len); /* sanity checks */ if (instr->addr + instr->len > device_size(&(flash->mtd))) return -EINVAL; tmpdiv = (uint64_t) instr->addr; rem = do_div(tmpdiv, mtd->erasesize); tmpdiv = (uint64_t) instr->len; rem1 = do_div(tmpdiv, mtd->erasesize); if (rem != 0 || rem1 != 0) { return -EINVAL; } addr = instr->addr; len = instr->len; mutex_lock(&flash->lock); /* REVISIT in some cases we could speed up erasing large regions * by using OPCODE_SE instead of OPCODE_BE_4K */ /* now erase those sectors */ while (len) { #ifdef CONFIG_MIPS_BRCM97XXX /* BSPI remaps each 4MB segment */ if (erase_sector(flash, (addr + 0x400000) & 0xffffff)) { #else if (erase_sector(flash, addr)) { #endif instr->state = MTD_ERASE_FAILED; mutex_unlock(&flash->lock); return -EIO; } addr += mtd->erasesize; len -= mtd->erasesize; } mutex_unlock(&flash->lock); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; } /* * Read an address range from the flash chip. The address range * may be any size provided it is within the physical boundaries. */ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct m25p *flash = mtd_to_m25p(mtd); struct spi_transfer t[2]; struct spi_message m; size_t total_len = len; DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", flash->spi->dev.bus_id, __FUNCTION__, "from", (u32)from, len); /* sanity checks */ if (!len) return 0; if (from + len > device_size(&(flash->mtd))) return -EINVAL; if (retlen) *retlen = 0; total_len = len; while(total_len) { len = total_len; #if 0 //defined(BRCM_SPI_SS_WAR) /* * For testing purposes only - read 12 bytes at a time: * * 3548a0 MSPI has a 12-byte limit (PR42350). * MSPI emulated via BSPI has no such limit. * In production BSPI is always used because it is much faster. */ if(len > 12) len = 12; #endif #ifdef CONFIG_MIPS_BRCM97XXX /* don't cross a 4MB boundary due to remapping */ len = min(len, (0x400000 - ((u32)from & 0x3fffff))); #endif spi_message_init(&m); memset(t, 0, (sizeof t)); t[0].tx_buf = flash->command; t[0].len = sizeof(flash->command); spi_message_add_tail(&t[0], &m); t[1].rx_buf = buf; t[1].len = len; spi_message_add_tail(&t[1], &m); /* Byte count starts at zero. */ mutex_lock(&flash->lock); /* Wait till previous write/erase is done. */ if (wait_till_ready(flash)) { /* REVISIT status return?? */ mutex_unlock(&flash->lock); return 1; } /* FIXME switch to OPCODE_FAST_READ. It's required for higher * clocks; and at this writing, every chip this driver handles * supports that opcode. */ /* Set up the write data buffer. */ flash->command[0] = OPCODE_READ; #ifdef CONFIG_MIPS_BRCM97XXX /* BSPI remaps each 4MB segment */ flash->command[1] = ((from >> 16) + 0x40) & 0xff; #else flash->command[1] = from >> 16; #endif flash->command[2] = from >> 8; flash->command[3] = from; spi_sync(flash->spi, &m); *retlen += m.actual_length - sizeof(flash->command); mutex_unlock(&flash->lock); from += len; buf += len; total_len -= len; } return 0; } /* * Write an address range to the flash chip. Data must be written in * FLASH_PAGESIZE chunks. The address range may be any size provided * it is within the physical boundaries. */ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { struct m25p *flash = mtd_to_m25p(mtd); u32 page_offset, page_size; struct spi_transfer t[2]; struct spi_message m; DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", flash->spi->dev.bus_id, __FUNCTION__, "to", (u32)to, len); if (retlen) *retlen = 0; /* sanity checks */ if (!len) return(0); if (to + len > device_size(&(flash->mtd))) return -EINVAL; #ifdef BRCM_SPI_SS_WAR if(len > 12) return -EIO; #endif spi_message_init(&m); memset(t, 0, (sizeof t)); t[0].tx_buf = flash->command; t[0].len = sizeof(flash->command); spi_message_add_tail(&t[0], &m); t[1].tx_buf = buf; spi_message_add_tail(&t[1], &m); mutex_lock(&flash->lock); /* Wait until finished previous write command. */ if (wait_till_ready(flash)) return 1; write_enable(flash); /* Set up the opcode in the write buffer. */ flash->command[0] = OPCODE_PP; #ifdef CONFIG_MIPS_BRCM97XXX /* BSPI remaps each 4MB segment */ flash->command[1] = ((to >> 16) + 0x40) & 0xff; #else flash->command[1] = to >> 16; #endif flash->command[2] = to >> 8; flash->command[3] = to; /* what page do we start with? */ page_offset = to % FLASH_PAGESIZE; /* do all the bytes fit onto one page? */ if (page_offset + len <= FLASH_PAGESIZE) { t[1].len = len; spi_sync(flash->spi, &m); *retlen = m.actual_length - sizeof(flash->command); } else { u32 i; /* the size of data remaining on the first page */ page_size = FLASH_PAGESIZE - page_offset; t[1].len = page_size; spi_sync(flash->spi, &m); *retlen = m.actual_length - sizeof(flash->command); /* write everything in PAGESIZE chunks */ for (i = page_size; i < len; i += page_size) { page_size = len - i; if (page_size > FLASH_PAGESIZE) page_size = FLASH_PAGESIZE; /* write the next page to flash */ #ifdef CONFIG_MIPS_BRCM97XXX /* BSPI remaps each 4MB segment */ flash->command[1] = (((to + i) >> 16) + 0x40) & 0xff; #else flash->command[1] = (to + i) >> 16; #endif flash->command[2] = (to + i) >> 8; flash->command[3] = (to + i); t[1].tx_buf = buf + i; t[1].len = page_size; wait_till_ready(flash); write_enable(flash); spi_sync(flash->spi, &m); if (retlen) *retlen += m.actual_length - sizeof(flash->command); } } mutex_unlock(&flash->lock); return 0; } /****************************************************************************/ /* * SPI device driver setup and teardown */ struct flash_info { char *name; /* JEDEC id zero means "no ID" (most older chips); otherwise it has * a high byte of zero plus three data bytes: the manufacturer id, * then a two byte device id. */ u32 jedec_id; /* The size listed here is what works with OPCODE_SE, which isn't * necessarily called a "sector" by the vendor. */ unsigned sector_size; u16 n_sectors; u16 flags; #define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */ }; /* NOTE: double check command sets and memory organization when you add * more flash chips. This current list focusses on newer chips, which * have been converging on command sets which including JEDEC ID. */ static struct flash_info __devinitdata m25p_data [] = { /* Atmel -- some are (confusingly) marketed as "DataFlash" */ { "at25fs010", 0x1f6601, 32 * 1024, 4, SECT_4K, }, { "at25fs040", 0x1f6604, 64 * 1024, 8, SECT_4K, }, { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, }, { "at26f004", 0x1f0400, 64 * 1024, 8, SECT_4K, }, { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, }, { "at26df161a", 0x1f4601, 64 * 1024, 32, SECT_4K, }, { "at26df321", 0x1f4701, 64 * 1024, 64, SECT_4K, }, /* Spansion -- single (large) sector size only, at least * for the chips listed here (without boot sectors). */ { "s25sl004a", 0x010212, 64 * 1024, 8, }, { "s25sl008a", 0x010213, 64 * 1024, 16, }, { "s25sl016a", 0x010214, 64 * 1024, 32, }, { "s25sl032a", 0x010215, 64 * 1024, 64, }, { "s25sl064a", 0x010216, 64 * 1024, 128, }, #ifdef CONFIG_MIPS_BRCM97XXX { "s25fl128p", 0x012018, 64 * 1024, 256, }, #endif /* SST -- large erase sizes are "overlays", "sectors" are 4K */ { "sst25vf040b", 0xbf258d, 64 * 1024, 8, SECT_4K, }, { "sst25vf080b", 0xbf258e, 64 * 1024, 16, SECT_4K, }, { "sst25vf016b", 0xbf2541, 64 * 1024, 32, SECT_4K, }, { "sst25vf032b", 0xbf254a, 64 * 1024, 64, SECT_4K, }, /* ST Microelectronics -- newer production may have feature updates */ { "m25p05", 0x202010, 32 * 1024, 2, }, { "m25p10", 0x202011, 32 * 1024, 4, }, { "m25p20", 0x202012, 64 * 1024, 4, }, { "m25p40", 0x202013, 64 * 1024, 8, }, #ifndef CONFIG_MIPS_BRCM97XXX /* ID 0 is detected when there's nothing on the bus */ { "m25p80", 0, 64 * 1024, 16, }, #endif { "m25p16", 0x202015, 64 * 1024, 32, }, { "m25p32", 0x202016, 64 * 1024, 64, }, { "m25p64", 0x202017, 64 * 1024, 128, }, { "m25p128", 0x202018, 256 * 1024, 64, }, { "m45pe80", 0x204014, 64 * 1024, 16, }, { "m45pe16", 0x204015, 64 * 1024, 32, }, { "m25pe80", 0x208014, 64 * 1024, 16, }, { "m25pe16", 0x208015, 64 * 1024, 32, SECT_4K, }, /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ { "w25x10", 0xef3011, 64 * 1024, 2, SECT_4K, }, { "w25x20", 0xef3012, 64 * 1024, 4, SECT_4K, }, { "w25x40", 0xef3013, 64 * 1024, 8, SECT_4K, }, { "w25x80", 0xef3014, 64 * 1024, 16, SECT_4K, }, { "w25x16", 0xef3015, 64 * 1024, 32, SECT_4K, }, { "w25x32", 0xef3016, 64 * 1024, 64, SECT_4K, }, { "w25x64", 0xef3017, 64 * 1024, 128, SECT_4K, }, }; static struct flash_info *__devinit jedec_probe(struct spi_device *spi) { int tmp; u8 code = OPCODE_RDID; u8 id[3]; u32 jedec; struct flash_info *info; /* JEDEC also defines an optional "extended device information" * string for after vendor-specific data, after the three bytes * we use here. Supporting some chips might require using it. */ tmp = spi_write_then_read(spi, &code, 1, id, 3); if (tmp < 0) { DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", spi->dev.bus_id, tmp); return NULL; } jedec = id[0]; jedec = jedec << 8; jedec |= id[1]; jedec = jedec << 8; jedec |= id[2]; for (tmp = 0, info = m25p_data; tmp < ARRAY_SIZE(m25p_data); tmp++, info++) { if (info->jedec_id == jedec) return info; } dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec); return NULL; }
// initialise storage bool AP_FlashStorage::init(void) { debug("running init()\n"); // start with empty memory buffer memset(mem_buffer, 0, storage_size); // find state of sectors struct sector_header header[2]; // read headers and possibly initialise if bad signature for (uint8_t i=0; i<2; i++) { if (!flash_read(i, 0, (uint8_t *)&header[i], sizeof(header[i]))) { return false; } bool bad_header = (header[i].signature != signature); enum SectorState state = (enum SectorState)header[i].state; if (state != SECTOR_STATE_AVAILABLE && state != SECTOR_STATE_IN_USE && state != SECTOR_STATE_FULL) { bad_header = true; } // initialise if bad header if (bad_header) { return erase_all(); } } // work out the first sector to read from using sector states enum SectorState states[2] {(enum SectorState)header[0].state, (enum SectorState)header[1].state}; uint8_t first_sector; if (states[0] == states[1]) { if (states[0] != SECTOR_STATE_AVAILABLE) { return erase_all(); } first_sector = 0; } else if (states[0] == SECTOR_STATE_FULL) { first_sector = 0; } else if (states[1] == SECTOR_STATE_FULL) { first_sector = 1; } else if (states[0] == SECTOR_STATE_IN_USE) { first_sector = 0; } else if (states[1] == SECTOR_STATE_IN_USE) { first_sector = 1; } else { // doesn't matter which is first first_sector = 0; } // load data from any current sectors for (uint8_t i=0; i<2; i++) { uint8_t sector = (first_sector + i) & 1; if (states[sector] == SECTOR_STATE_IN_USE || states[sector] == SECTOR_STATE_FULL) { if (!load_sector(sector)) { return erase_all(); } } } // clear any write error write_error = false; reserved_space = 0; // if the first sector is full then write out all data so we can erase it if (states[first_sector] == SECTOR_STATE_FULL) { current_sector = first_sector ^ 1; if (!write_all()) { return erase_all(); } } // erase any sectors marked full for (uint8_t i=0; i<2; i++) { if (states[i] == SECTOR_STATE_FULL) { if (!erase_sector(i)) { return false; } } } reserved_space = 0; // ready to use return true; }
bool FLASHDRVR::write(const unsigned addr, const unsigned len, const unsigned *data, const bool verify) { // Work through this one sector at a time. // If this buffer is equal to the sector value(s), go on // If not, erase the sector // m_fpga->writeio(R_QSPI_CREG, 2); // m_fpga->readio(R_VERSION); // Read something innocuous // m_fpga->writeio(R_QSPI_SREG, 0); // m_fpga->readio(R_VERSION); // Read something innocuous for(unsigned s=SECTOROF(addr); s<SECTOROF(addr+len+SECTORSZ-1); s+=SECTORSZ) { // printf("IN LOOP, s=%08x\n", s); // Do we need to erase? bool need_erase = false; unsigned newv = 0; // (s<addr)?addr:s; { DEVBUS::BUSW *sbuf = new DEVBUS::BUSW[SECTORSZ]; const DEVBUS::BUSW *dp; unsigned base,ln; base = (addr>s)?addr:s; ln=((addr+len>s+SECTORSZ)?(s+SECTORSZ):(addr+len))-base; m_fpga->readi(base, ln, sbuf); dp = &data[base-addr]; for(unsigned i=0; i<ln; i++) { if ((sbuf[i]&dp[i]) != dp[i]) { printf("\nNEED-ERASE @0x%08x ... %08x != %08x (Goal)\n", i+base-addr, sbuf[i], dp[i]); need_erase = true; newv = i+base; break; } else if ((sbuf[i] != dp[i])&&(newv == 0)) { // if (newv == 0) // printf("MEM[%08x] = %08x (!= %08x (Goal))\n", // i+base, sbuf[i], dp[i]); newv = i+base; } } } if (newv == 0) continue; // This sector already matches // Just erase anyway if ((need_erase)&&(!erase_sector(s, verify))) { printf("SECTOR ERASE FAILED!\n"); return false; } else if (!need_erase) printf("NO ERASE NEEDED\n"); else { printf("ERASING SECTOR %08x\n", s); newv = (s<addr) ? addr : s; } for(unsigned p=newv; (p<s+SECTORSZ)&&(p<addr+len); p=PAGEOF(p+PGLEN)) if (!write_page(p, (p+PGLEN<addr+len) ?((PAGEOF(p)!=PAGEOF(p+PGLEN-1))?(PAGEOF(p+PGLEN-1)-p):PGLEN) :(addr+len-p), &data[p-addr]), verify) { printf("WRITE-PAGE FAILED!\n"); return false; } } m_fpga->writeio(R_QSPI_EREG, 0); // Re-enable write protection return true; }
int parameter_flashfs_write(flash_file_token_t token, uint8_t *buffer, size_t buf_size) { int rv = -ENXIO; if (sector_map) { rv = 0; /* Calculate the total space needed */ size_t total_size = buf_size + sizeof(flash_entry_header_t); size_t alignment = sizeof(h_magic_t) - 1; size_t size_adjust = ((total_size + alignment) & ~alignment) - total_size; total_size += size_adjust; /* Is this and existing entry */ flash_entry_header_t *pf = find_entry(token); if (!pf) { /* No Entry exists for this token so find a place for it */ pf = find_free(total_size); /* No Space */ if (pf == 0) { return -ENOSPC; } } else { /* Do we have space after the entry in the sector for the update */ sector_descriptor_t *current_sector = check_free_space_in_sector(pf, total_size); if (current_sector == 0) { /* Mark the last entry erased */ /* todo:consider a 2 stage erase or write before erase and do a fs check * at start up */ rv = erase_entry(pf); if (rv < 0) { return rv; } /* We had space and marked the last entry erased so use the Next Free */ pf = next_entry(pf); } else { /* * We did not have space in the current sector so select the next sector */ current_sector = get_next_sector_descriptor(current_sector); /* Will the data fit */ if (current_sector->size < total_size) { return -ENOSPC; } /* Mark the last entry erased */ /* todo:consider a 2 stage erase or write before erase and do a fs check * at start up */ rv = erase_entry(pf); if (rv < 0) { return rv; } pf = (flash_entry_header_t *) current_sector->address; } if (!blank_check(pf, total_size)) { rv = erase_sector(current_sector, pf); } } flash_entry_header_t *pn = (flash_entry_header_t *)(buffer - sizeof(flash_entry_header_t)); pn->magic = MagicSig; pn->file_token.t = token.t; pn->flag = ValidEntry + size_adjust; pn->size = total_size; for (size_t a = 0; a < size_adjust; a++) { buffer[buf_size + a] = (uint8_t)BlankSig; } pn->crc = crc32(entry_crc_start(pn), entry_crc_length(pn)); rv = up_progmem_write((size_t) pf, pn, pn->size); int system_bytes = (sizeof(flash_entry_header_t) + size_adjust); if (rv >= system_bytes) { rv -= system_bytes; } } return rv; }
void burn(libusb_device_handle *h, const char *filename) { printf("burning %s\n", filename); FILE *f = fopen(filename, "rb"); if (!f) { printf("couldn't open %s\n", filename); exit(1); } uint32_t write_addr = 0; // this image will start to be burned at zero uint8_t tx_msg[64] = {0}; tx_msg[0] = 1; // command: flash tx_msg[1] = 1; // subcmd: write tx_msg[2] = 32; // write length int num_transferred = 0; while (!feof(f)) { if ((write_addr & 0xffff) == 0) { // we're on a new sector boundary. erase it so we can program it. printf("erasing sector starting at 0x%08x\n", (unsigned)write_addr); if (!erase_sector(h, write_addr)) break; } if (write_addr % 0x1000 == 0) printf("writing to 0x%08x\r\n", write_addr); //if (write_addr >= 0x10000) // break; memcpy(&tx_msg[4], &write_addr, sizeof(write_addr)); memset(&tx_msg[8], 0, 32); size_t nread = fread(&tx_msg[8], 1, 32, f); if (nread != 32) printf("read %d bytes. last page?\n", (int)nread); if (nread == 0) break; int tx_rc = libusb_bulk_transfer(h, 2, tx_msg, sizeof(tx_msg), &num_transferred, 100); if (tx_rc != 0) { printf("tx_rc = %d\n", tx_rc); break; } uint8_t rx_msg[64] = {0}; int rx_rc = libusb_bulk_transfer(h, 0x81, rx_msg, sizeof(rx_msg), &num_transferred, 100); if (rx_rc != 0) { printf("rx err code: %d\n", rx_rc); printf("errno: %d = %s\n", errno, strerror(errno)); break; } uint32_t response_write_addr = 0; memcpy(&response_write_addr, &rx_msg[4], sizeof(uint32_t)); if (write_addr != response_write_addr) { printf("write addr mismatch: 0x%08x != 0x%08x\n", response_write_addr, write_addr); break; } write_addr += 32; } }
//*---------------------------------------------------------------------------- //* Function Name : flash_at49_erase_write_block //* Object : check if sector is erased if not erase erase and write //* Input Parameters : <buffer> data block addressFlash //* <size> sector size in byte //* Output Parameters : if data sector erase TRUE or FALSE //*---------------------------------------------------------------------------- int flash_at49_erase_write_block ( u_char *buffer,int size) //* Begin { unsigned short data ; unsigned int count; int sector_found ; int change_sector ; //* For each word read from the file for ( count =0 ; count < size ; count +=2 ) { //data = buffer[count]; data = (unsigned short) buffer[count]| (unsigned short)buffer[count+1] << 8 ; //* Clear sector found flag sector_found = FALSE ; //* Clear Sector change flag change_sector = FALSE ; //* While sector not found while ( sector_found == FALSE ) { //* If program address lower than current sector address + its size if (( addr_prg_sector + (flash->flash_org[block].sector_size/2) ) > addr_load ) { //* Flag sector found sector_found = TRUE ; } //* Else else { //* Flag sector change change_sector = TRUE ; //* Add current sector size to program address addr_prg_sector += (flash->flash_org[block].sector_size/2) ; //* Increment the sector number nb_sector++ ; //* If last sector in block tested if ( nb_sector >= flash->flash_org[block].sector_number ) { //* Re-initialize sector number in block nb_sector = 0 ; //* Increment block number block ++ ; //* If last block tested if ( block >= flash->flash_block_nb ) { //* Error Address not found in the Flash Address Field Return False return ( FALSE ) ; } //* Endif } //* Endif } //* EndIf } //* EndWhile //* Unflag Erasing erase = FALSE ; //* If new sector or first sector if (( change_sector == TRUE ) || ( first == TRUE )) { //* If not first sector if ( first == FALSE ) { //* Flag Erasing erase = TRUE ; } //* Else, if first sector else { //* Flag to erase the sector erase = TRUE ; } //* Endif } //* Endif //* If Erasing flagged if ( erase == TRUE ) { //* Erase, if Timeout if ( erase_sector ( addr_base, addr_prg_sector, flash->flash_org[block].sector_size) != TRUE ) { //* Return False return ( FALSE ) ; } //* Endif } //* Endif //* Write the value read in Flash, if error if ( flash_at49_write_flash ( addr_base,addr_load, data )!= TRUE ) { //* Return False return ( FALSE ) ; } //* Endif //* Increment load address addr_load ++ ; //* Remove first address to program flag first = FALSE ; } //* EndWhile //* Return True return ( TRUE ) ; }