static int lpc2000_erase(struct flash_bank *bank, int first, int last) { struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; uint32_t param_table[5]; uint32_t result_table[4]; int status_code; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } param_table[0] = first; param_table[1] = last; param_table[2] = lpc2000_info->cclk; /* Prepare sectors */ status_code = lpc2000_iap_call(bank, 50, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: return ERROR_FLASH_OPERATION_FAILED; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: return ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); return ERROR_FLASH_OPERATION_FAILED; } /* Erase sectors */ status_code = lpc2000_iap_call(bank, 52, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: return ERROR_FLASH_OPERATION_FAILED; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: return ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 erase sectors returned %i", status_code); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; }
static int get_lpc2000_part_id(struct flash_bank *bank, uint32_t *part_id) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } uint32_t param_table[5] = {0}; uint32_t result_table[4]; struct working_area *iap_working_area; int retval = lpc2000_iap_working_area_init(bank, &iap_working_area); if (retval != ERROR_OK) return retval; /* The status seems to be bogus with the part ID command on some IAP firmwares, so ignore it. */ lpc2000_iap_call(bank, iap_working_area, 54, param_table, result_table); struct target *target = bank->target; target_free_working_area(target, iap_working_area); /* If the result is zero, the command probably didn't work out. */ if (result_table[0] == 0) return LPC2000_INVALID_COMMAND; *part_id = result_table[0]; return LPC2000_CMD_SUCCESS; }
static int lpc2000_iap_blank_check(struct flash_bank *bank, int first, int last) { if ((first < 0) || (last >= bank->num_sectors)) return ERROR_FLASH_SECTOR_INVALID; uint32_t param_table[5] = {0}; uint32_t result_table[4]; struct working_area *iap_working_area; int retval = lpc2000_iap_working_area_init(bank, &iap_working_area); if (retval != ERROR_OK) return retval; struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; if (lpc2000_info->variant == lpc4300) param_table[2] = lpc2000_info->lpc4300_bank; for (int i = first; i <= last && retval == ERROR_OK; i++) { /* check single sector */ param_table[0] = param_table[1] = i; int status_code = lpc2000_iap_call(bank, iap_working_area, 53, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: bank->sectors[i].is_erased = 1; break; case LPC2000_SECTOR_NOT_BLANK: bank->sectors[i].is_erased = 0; break; case LPC2000_INVALID_SECTOR: bank->sectors[i].is_erased = 0; break; case LPC2000_BUSY: retval = ERROR_FLASH_BUSY; break; default: LOG_ERROR("BUG: unknown LPC2000 status code %i", status_code); exit(-1); } } struct target *target = bank->target; target_free_working_area(target, iap_working_area); return retval; }
static int lpc2000_iap_blank_check(struct flash_bank *bank, int first, int last) { uint32_t param_table[5]; uint32_t result_table[4]; int status_code; int i; if ((first < 0) || (last >= bank->num_sectors)) return ERROR_FLASH_SECTOR_INVALID; for (i = first; i <= last; i++) { /* check single sector */ param_table[0] = param_table[1] = i; status_code = lpc2000_iap_call(bank, 53, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: return ERROR_FLASH_OPERATION_FAILED; case LPC2000_CMD_SUCCESS: bank->sectors[i].is_erased = 1; break; case LPC2000_SECTOR_NOT_BLANK: bank->sectors[i].is_erased = 0; break; case LPC2000_INVALID_SECTOR: bank->sectors[i].is_erased = 0; break; case LPC2000_BUSY: return ERROR_FLASH_BUSY; break; default: LOG_ERROR("BUG: unknown LPC2000 status code %i", status_code); exit(-1); } } return ERROR_OK; }
static int get_lpc2000_part_id(struct flash_bank *bank, uint32_t *part_id) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } uint32_t param_table[5] = {0}; uint32_t result_table[4]; struct working_area *iap_working_area; int retval = lpc2000_iap_working_area_init(bank, &iap_working_area); if (retval != ERROR_OK) return retval; int status_code = lpc2000_iap_call(bank, iap_working_area, 54, param_table, result_table); if (status_code == LPC2000_CMD_SUCCESS) *part_id = result_table[0]; return status_code; }
static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; struct target *target = bank->target; uint32_t dst_min_alignment; uint32_t bytes_remaining = count; uint32_t bytes_written = 0; int first_sector = 0; int last_sector = 0; uint32_t param_table[5]; uint32_t result_table[4]; int status_code; int i; struct working_area *download_area; int retval = ERROR_OK; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; dst_min_alignment = lpc2000_info->cmd51_dst_boundary; if (offset % dst_min_alignment) { LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32, offset, dst_min_alignment); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } for (i = 0; i < bank->num_sectors; i++) { if (offset >= bank->sectors[i].offset) first_sector = i; if (offset + DIV_ROUND_UP(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset) last_sector = i; } LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector); /* check if exception vectors should be flashed */ if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum) { uint32_t checksum = 0; for (i = 0; i < 8; i++) { LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4, buf_get_u32(buffer + (i * 4), 0, 32)); if (i != lpc2000_info->checksum_vector) checksum += buf_get_u32(buffer + (i * 4), 0, 32); } checksum = 0 - checksum; LOG_DEBUG("checksum: 0x%8.8" PRIx32, checksum); uint32_t original_value = buf_get_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32); if (original_value != checksum) { LOG_WARNING("Verification will fail since checksum in image (0x%8.8" PRIx32 ") " "to be written to flash is different from calculated vector " "checksum (0x%8.8" PRIx32 ").", original_value, checksum); LOG_WARNING("To remove this warning modify build tools on developer PC " "to inject correct LPC vector checksum."); } buf_set_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32, checksum); } /* allocate a working area */ if (target_alloc_working_area(target, lpc2000_info->cmd51_max_buffer, &download_area) != ERROR_OK) { LOG_ERROR("no working area specified, can't write LPC2000 internal flash"); return ERROR_FLASH_OPERATION_FAILED; } while (bytes_remaining > 0) { uint32_t thisrun_bytes; if (bytes_remaining >= lpc2000_info->cmd51_max_buffer) thisrun_bytes = lpc2000_info->cmd51_max_buffer; else if (bytes_remaining >= 1024) thisrun_bytes = 1024; else if ((bytes_remaining >= 512) || (!lpc2000_info->cmd51_can_256b)) thisrun_bytes = 512; else thisrun_bytes = 256; /* Prepare sectors */ param_table[0] = first_sector; param_table[1] = last_sector; status_code = lpc2000_iap_call(bank, 50, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: retval = ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; } /* Exit if error occured */ if (retval != ERROR_OK) break; if (bytes_remaining >= thisrun_bytes) { retval = target_write_buffer(bank->target, download_area->address, thisrun_bytes, buffer + bytes_written); if (retval != ERROR_OK) { retval = ERROR_FLASH_OPERATION_FAILED; break; } } else { uint8_t *last_buffer = malloc(thisrun_bytes); memcpy(last_buffer, buffer + bytes_written, bytes_remaining); memset(last_buffer + bytes_remaining, 0xff, thisrun_bytes - bytes_remaining); target_write_buffer(bank->target, download_area->address, thisrun_bytes, last_buffer); free(last_buffer); } LOG_DEBUG("writing 0x%" PRIx32 " bytes to address 0x%" PRIx32, thisrun_bytes, bank->base + offset + bytes_written); /* Write data */ param_table[0] = bank->base + offset + bytes_written; param_table[1] = download_area->address; param_table[2] = thisrun_bytes; param_table[3] = lpc2000_info->cclk; status_code = lpc2000_iap_call(bank, 51, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: retval = ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; } /* Exit if error occured */ if (retval != ERROR_OK) break; if (bytes_remaining > thisrun_bytes) bytes_remaining -= thisrun_bytes; else bytes_remaining = 0; bytes_written += thisrun_bytes; } target_free_working_area(target, download_area); return retval; }
static int lpc2000_erase(struct flash_bank *bank, int first, int last) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; uint32_t param_table[5] = {0}; param_table[0] = first; param_table[1] = last; if (lpc2000_info->variant == lpc4300) param_table[2] = lpc2000_info->lpc4300_bank; else param_table[2] = lpc2000_info->cclk; uint32_t result_table[4]; struct working_area *iap_working_area; int retval = lpc2000_iap_working_area_init(bank, &iap_working_area); if (retval != ERROR_OK) return retval; if (lpc2000_info->variant == lpc4300) /* Init IAP Anyway */ lpc2000_iap_call(bank, iap_working_area, 49, param_table, result_table); /* Prepare sectors */ int status_code = lpc2000_iap_call(bank, iap_working_area, 50, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: retval = ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (retval == ERROR_OK) { /* Erase sectors */ param_table[2] = lpc2000_info->cclk; if (lpc2000_info->variant == lpc4300) param_table[3] = lpc2000_info->lpc4300_bank; status_code = lpc2000_iap_call(bank, iap_working_area, 52, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: retval = ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 erase sectors returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; } } struct target *target = bank->target; target_free_working_area(target, iap_working_area); return retval; }