void oper_flash_read_id(void* data) /* */ /* INPUTS : o data Point to a variable to read the ID */ /* OUTPUTS : o data The ID is stored in data */ /* RETURNS : o --- */ /* DESCRIPTION: */ /* Only reads the manufacturer and part number codes for the first */ /* device(s) in series. It is assumed that any devices in series */ /* will be of the same type. */ /* $rtn_hdr_end */ /*****************************************************************************/ { #ifndef HAVE_SERIAL_FLASH typedef void c_fun(void*); c_fun *_flash_query; #ifndef IROSBOOT unsigned long cur_interrupt_state; HAL_FLASH_CACHES_STATE(d_cache, i_cache); #endif _flash_query = (c_fun*) __anonymizer(&flash_query); #ifndef IROSBOOT HAL_DISABLE_INTERRUPTS(cur_interrupt_state); HAL_FLASH_CACHES_OFF(d_cache, i_cache); #endif (*_flash_query)(data); #ifndef IROSBOOT HAL_FLASH_CACHES_ON(d_cache, i_cache); HAL_RESTORE_INTERRUPTS(cur_interrupt_state); #endif #else flash_query(data); #endif /* HAVE_SERIAL_FLASH */ return; }
int oper_flash_erase_block(void* block) /* */ /* INPUTS : o block Block address */ /* OUTPUTS : ---- */ /* RETURNS : o --- */ /* DESCRIPTION: */ /* This function is used to erase a block */ /* $rtn_hdr_end */ /*****************************************************************************/ { int stat = 0; #ifndef IROSBOOT unsigned long cur_interrupt_state; HAL_FLASH_CACHES_STATE(d_cache, i_cache); HAL_DISABLE_INTERRUPTS(cur_interrupt_state); HAL_FLASH_CACHES_OFF(d_cache, i_cache); #endif #ifdef HAVE_SERIAL_FLASH flash_erase_block((cs_uint32)block,0); #else typedef int c_fun(unsigned short *, unsigned int); c_fun *_flash_erase_block; _flash_erase_block = (c_fun*) __anonymizer(&flash_erase_block); stat = (*_flash_erase_block)(block, flash_dev_info->block_size); #endif /* HAVE_SERIAL_FLASH */ #ifndef IROSBOOT HAL_FLASH_CACHES_ON(d_cache, i_cache); HAL_RESTORE_INTERRUPTS(cur_interrupt_state); #endif return stat; }
int oper_flash_write(void* addr, int data) /* */ /* INPUTS : o addr Address to which data to be written */ /* o data Data that need to be written */ /* OUTPUTS : ---- */ /* RETURNS : o Status of the write operation */ /* DESCRIPTION: */ /* This function writes the data to the flash */ /* THIS FUNCTION CONSIDERES THE BLOCK IN UNLOCKED */ /* WRITE ONLY 2 BYTE */ /* $rtn_hdr_end */ /*****************************************************************************/ { int stat = 0; #ifndef IROSBOOT unsigned long cur_interrupt_state; HAL_FLASH_CACHES_STATE(d_cache, i_cache); HAL_DISABLE_INTERRUPTS(cur_interrupt_state); HAL_FLASH_CACHES_OFF(d_cache, i_cache); #endif #ifdef HAVE_SERIAL_FLASH flash_program_buf_word(addr,(cs_uint32)data); #else typedef int c_fun(void *, int); c_fun *_flash_program_buf_word; _flash_program_buf_word = (c_fun*) __anonymizer(&flash_program_buf_word); stat = (*_flash_program_buf_word)(addr, data); #endif /* HAVE_SERIAL_FLASH */ #ifndef IROSBOOT HAL_FLASH_CACHES_ON(d_cache, i_cache); HAL_RESTORE_INTERRUPTS(cur_interrupt_state); #endif return stat; }
int oper_flash_unlock_block(void* block) /* */ /* INPUTS : o block Block start address */ /* OUTPUTS : ---- */ /* RETURNS : o Status of unlock operation */ /* DESCRIPTION: */ /* This function will unlock the blocks. */ /* $rtn_hdr_end */ /*****************************************************************************/ { int stat = 0; #ifndef HAVE_SERIAL_FLASH typedef int c_fun(unsigned short *, int, int); c_fun *_flash_unlock_block; #ifndef IROSBOOT unsigned long cur_interrupt_state; HAL_FLASH_CACHES_STATE(d_cache, i_cache); #endif _flash_unlock_block = (c_fun*) __anonymizer(&flash_unlock_block); #ifndef IROSBOOT HAL_DISABLE_INTERRUPTS(cur_interrupt_state); HAL_FLASH_CACHES_OFF(d_cache, i_cache); #endif stat = (*_flash_unlock_block)(block, flash_dev_info->block_size, 0x1); #ifndef IROSBOOT HAL_FLASH_CACHES_ON(d_cache, i_cache); HAL_RESTORE_INTERRUPTS(cur_interrupt_state); #endif #endif /* HAVE_SERIAL_FLASH */ return stat; }
int oper_flash_bulk_write(void* _addr, void* _data, int len) /* */ /* INPUTS : o addr Address to which data to be written */ /* o data Address of Data that need to be written */ /* o len Length of data hat need to be written */ /* OUTPUTS : ---- */ /* RETURNS : o Status of the write operation */ /* DESCRIPTION: */ /* This function writes the bulk data to the flash */ /* THIS FUNCTION UNLOCKS THE BLOCK FIRST BEFORE IT WRITES */ /* $rtn_hdr_end */ /*****************************************************************************/ { int stat = 0; #ifndef IROSBOOT unsigned long cur_interrupt_state; HAL_FLASH_CACHES_STATE(d_cache, i_cache); HAL_DISABLE_INTERRUPTS(cur_interrupt_state); HAL_FLASH_CACHES_OFF(d_cache, i_cache); #endif #ifdef HAVE_SERIAL_FLASH flash_program_buf((cs_uint32)_addr,(cs_uint32)_data,len,0,0); #else int size; typedef int c_fun(void *, void *, int, unsigned long, int); c_fun *_flash_program_buf; unsigned char *addr = (unsigned char *)_addr; unsigned char *data = (unsigned char *)_data; unsigned long tmp; _flash_program_buf = (c_fun*) __anonymizer(&flash_program_buf); while (len > 0) { size = len; if (size > flash_dev_info->block_size) size = flash_dev_info->block_size; tmp = (unsigned long) addr & (~flash_dev_info->block_mask); if (tmp) { tmp = flash_dev_info->block_size - tmp; if (size > tmp) size = tmp; } stat = (*_flash_program_buf)(addr, data, size, flash_dev_info->block_mask, 0x0); if (stat != FLASH_ERR_OK) { break; } len -= size; addr += size/sizeof(*addr); data += size/sizeof(*data); } #endif /* HAVE_SERIAL_FLASH */ #ifndef IROSBOOT HAL_FLASH_CACHES_ON(d_cache, i_cache); HAL_RESTORE_INTERRUPTS(cur_interrupt_state); #endif return (stat); }
__externC int cyg_flash_unlock(const cyg_flashaddr_t flash_base, size_t len, cyg_flashaddr_t *err_address) { cyg_flashaddr_t block, end_addr; struct cyg_flash_dev * dev; size_t unlock_count; int stat = CYG_FLASH_ERR_OK; HAL_FLASH_CACHES_STATE(d_cache, i_cache); dev = find_dev(flash_base, &stat); if (!dev) return stat; if (!dev->funs->flash_block_unlock) return CYG_FLASH_ERR_INVALID; CHECK_SOFT_WRITE_PROTECT(flash_base, len); LOCK(dev); if (len > (dev->end + 1 - flash_base)) { end_addr = dev->end; } else { end_addr = flash_base + len - 1; } block = flash_block_begin(flash_base, dev); unlock_count = (end_addr + 1) - block; CHATTER(dev, "... Unlocking from %p-%p: ", (void*)block, (void*)end_addr); HAL_FLASH_CACHES_OFF(d_cache, i_cache); FLASH_Enable(flash_base, end_addr); while (unlock_count > 0) { size_t block_size = flash_block_size(dev, block); if (unlock_count < block_size) { unlock_count = block_size; } stat = dev->funs->flash_block_unlock(dev,block); if (CYG_FLASH_ERR_OK != stat && err_address) { *err_address = block; break; } block += block_size; unlock_count -= block_size; CHATTER(dev, "."); } FLASH_Disable(flash_base, end_addr); HAL_FLASH_CACHES_ON(d_cache, i_cache); CHATTER(dev, "\n"); UNLOCK(dev); if (stat != CYG_FLASH_ERR_OK) { return stat; } // Recurse if necessary for the next device if (len > (dev->end + 1 - flash_base)) { return cyg_flash_lock(dev->end+1, len - (dev->end + 1 - flash_base), err_address); } return CYG_FLASH_ERR_OK; }
__externC int cyg_flash_read(const cyg_flashaddr_t flash_base, void *ram_base, size_t len, cyg_flashaddr_t *err_address) { struct cyg_flash_dev * dev; cyg_flashaddr_t addr, end_addr; unsigned char * ram = (unsigned char *)ram_base; size_t read_count; int stat = CYG_FLASH_ERR_OK; dev = find_dev(flash_base, &stat); if (!dev) return stat; LOCK(dev); addr = flash_base; if (len > (dev->end + 1 - flash_base)) { end_addr = dev->end; } else { end_addr = flash_base + len - 1; } read_count = (end_addr + 1) - flash_base; // CHATTER(dev, "... Read from %p-%p to %p: ", addr, end_addr, ram_base); // If the flash is directly accessible, just read it in one go. This // still happens with the mutex locked to protect against concurrent // programs/erases. if (! dev->funs->flash_read) { memcpy(ram, (void*)addr, read_count); } else { #ifndef CYGHWR_IO_FLASH_INDIRECT_READS CYG_FAIL("read function supplied but indirect reads not enabled"); stat = CYG_FLASH_ERR_PROTOCOL; if (err_address) { *err_address = addr; } #else // We have to indirect through the device driver. // The first read may be in the middle of a block. Do the necessary // adjustment here rather than inside the loop. size_t offset; cyg_flashaddr_t block = flash_block_begin(flash_base, dev); HAL_FLASH_CACHES_STATE(d_cache, i_cache); if (addr == block) { offset = 0; } else { offset = addr - block; } HAL_FLASH_CACHES_OFF(d_cache, i_cache); FLASH_Enable(flash_base, end_addr); while (read_count > 0) { size_t block_size = flash_block_size(dev, addr); size_t this_read; if (read_count > (block_size - offset)) { this_read = block_size - offset; } else { this_read = read_count; } // Only the first block may need the offset offset = 0; FLASH_WATCHDOG_RESET; stat = dev->funs->flash_read(dev, addr, ram, this_read); if (CYG_FLASH_ERR_OK != stat && err_address) { *err_address = addr; break; } // CHATTER(dev, "."); read_count -= this_read; addr += this_read; ram += this_read; } FLASH_Disable(flash_base, end_addr); HAL_FLASH_CACHES_ON(d_cache, i_cache); #endif } // CHATTER(dev, "\n"); UNLOCK(dev); if (stat != CYG_FLASH_ERR_OK) { return (stat); } if (len > (dev->end + 1 - flash_base)) { FLASH_WATCHDOG_RESET; return cyg_flash_read(dev->end+1, ram, len - (dev->end + 1 - flash_base), err_address); } return CYG_FLASH_ERR_OK; }
__externC int cyg_flash_program(cyg_flashaddr_t flash_base, const void *ram_base, size_t len, cyg_flashaddr_t *err_address) { struct cyg_flash_dev * dev; cyg_flashaddr_t addr, end_addr, block; const unsigned char * ram = ram_base; size_t write_count, offset; int stat = CYG_FLASH_ERR_OK; HAL_FLASH_CACHES_STATE(d_cache, i_cache); dev = find_dev(flash_base, &stat); if (!dev) return stat; CHECK_SOFT_WRITE_PROTECT(flash_base, len); LOCK(dev); addr = flash_base; if (len > (dev->end + 1 - flash_base)) { end_addr = dev->end; } else { end_addr = flash_base + len - 1; } write_count = (end_addr + 1) - flash_base; // The first write may be in the middle of a block. Do the necessary // adjustment here rather than inside the loop. block = flash_block_begin(flash_base, dev); if (addr == block) { offset = 0; } else { offset = addr - block; } CHATTER(dev, "... Program from %p-%p to %p: ", ram_base, ((CYG_ADDRESS)ram_base)+write_count, addr); HAL_FLASH_CACHES_OFF(d_cache, i_cache); FLASH_Enable(flash_base, end_addr); while (write_count > 0) { size_t block_size = flash_block_size(dev, addr); size_t this_write; if (write_count > (block_size - offset)) { this_write = block_size - offset; } else { this_write = write_count; } // Only the first block may need the offset. offset = 0; FLASH_WATCHDOG_RESET; stat = dev->funs->flash_program(dev, addr, ram, this_write); #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM if (CYG_FLASH_ERR_OK == stat) // Claims to be OK if (!dev->funs->flash_read && memcmp((void *)addr, ram, this_write) != 0) { stat = CYG_FLASH_ERR_DRV_VERIFY; CHATTER(dev, "V"); } #endif if (CYG_FLASH_ERR_OK != stat) { if (err_address) *err_address = addr; break; } CHATTER(dev, "."); write_count -= this_write; addr += this_write; ram += this_write; } FLASH_Disable(flash_base, end_addr); HAL_FLASH_CACHES_ON(d_cache, i_cache); CHATTER(dev, "\n"); UNLOCK(dev); if (stat != CYG_FLASH_ERR_OK) { return (stat); } if (len > (dev->end + 1 - flash_base)) { FLASH_WATCHDOG_RESET; return cyg_flash_program(dev->end+1, ram, len - (dev->end + 1 - flash_base), err_address); } return CYG_FLASH_ERR_OK; }
__externC int cyg_flash_erase(cyg_flashaddr_t flash_base, size_t len, cyg_flashaddr_t *err_address) { cyg_flashaddr_t block, end_addr; struct cyg_flash_dev * dev; size_t erase_count; int stat = CYG_FLASH_ERR_OK; HAL_FLASH_CACHES_STATE(d_cache, i_cache); dev = find_dev(flash_base, &stat); if (!dev) return stat; CHECK_SOFT_WRITE_PROTECT(flash_base, len); LOCK(dev); // Check whether or not we are going past the end of this device, on // to the next one. If so the next device will be handled by a // recursive call later on. if (len > (dev->end + 1 - flash_base)) { end_addr = dev->end; } else { end_addr = flash_base + len - 1; } // erase can only happen on a block boundary, so adjust for this block = flash_block_begin(flash_base, dev); erase_count = (end_addr + 1) - block; CHATTER(dev, "... Erase from %p-%p: ", (void*)block, (void*)end_addr); HAL_FLASH_CACHES_OFF(d_cache, i_cache); FLASH_Enable(flash_base, end_addr); while (erase_count > 0) { int i; unsigned char *dp; bool erased = false; size_t block_size = flash_block_size(dev, block); // Pad to the block boundary, if necessary if (erase_count < block_size) { erase_count = block_size; } // If there is a read function it probably means the flash // cannot be read directly. if (!dev->funs->flash_read) { erased = true; dp = (unsigned char *)block; for (i = 0; i < block_size; i++) { if (*dp++ != (unsigned char)0xFF) { erased = false; break; } } } if (!erased) { FLASH_WATCHDOG_RESET; stat = dev->funs->flash_erase_block(dev,block); } if (CYG_FLASH_ERR_OK != stat) { if (err_address) *err_address = block; break; } block += block_size; erase_count -= block_size; CHATTER(dev, "."); } FLASH_Disable(flash_base, end_addr); HAL_FLASH_CACHES_ON(d_cache, i_cache); CHATTER(dev, "\n"); UNLOCK(dev); if (stat != CYG_FLASH_ERR_OK) { return stat; } // If there are multiple flash devices in series the erase operation // may touch successive devices. This can be handled by recursion. // The stack overheads should be minimal because the number of // devices will be small. if (len > (dev->end + 1 - flash_base)) { return cyg_flash_erase(dev->end+1, len - (dev->end + 1 - flash_base), err_address); } return CYG_FLASH_ERR_OK; }