/** Checks whether a memory region is zeroed. */ int armv7m_blank_check_memory(struct target *target, uint32_t address, uint32_t count, uint32_t* blank) { struct working_area *erase_check_algorithm; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_info; int retval; uint32_t i; static const uint16_t erase_check_code[] = { /* loop: */ 0xF810, 0x3B01, /* ldrb r3, [r0], #1 */ 0xEA02, 0x0203, /* and r2, r2, r3 */ 0x3901, /* subs r1, r1, #1 */ 0xD1F9, /* bne loop */ 0xBE00, /* bkpt #0 */ }; /* make sure we have a working area */ if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK) { return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* convert flash writing code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(erase_check_code); i++) target_write_u16(target, erase_check_algorithm->address + i*sizeof(uint16_t), erase_check_code[i]); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARMV7M_MODE_ANY; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 0xff); retval = target_run_algorithm(target, 0, NULL, 3, reg_params, erase_check_algorithm->address, erase_check_algorithm->address + (sizeof(erase_check_code) - 2), 10000, &armv7m_info); if (retval == ERROR_OK) *blank = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, erase_check_algorithm); return retval; }
/** Checks whether a memory region is zeroed. */ int mips32_blank_check_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *blank) { struct working_area *erase_check_algorithm; struct reg_param reg_params[3]; struct mips32_algorithm mips32_info; static const uint32_t erase_check_code[] = { /* nbyte: */ 0x80880000, /* lb $t0, ($a0) */ 0x00C83024, /* and $a2, $a2, $t0 */ 0x24A5FFFF, /* addiu $a1, $a1, -1 */ 0x14A0FFFC, /* bne $a1, $zero, nbyte */ 0x24840001, /* addiu $a0, $a0, 1 */ 0x7000003F /* sdbbp */ }; /* make sure we have a working area */ if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* convert erase check code into a buffer in target endianness */ uint8_t erase_check_code_8[sizeof(erase_check_code)]; target_buffer_set_u32_array(target, erase_check_code_8, ARRAY_SIZE(erase_check_code), erase_check_code); target_write_buffer(target, erase_check_algorithm->address, sizeof(erase_check_code), erase_check_code_8); mips32_info.common_magic = MIPS32_COMMON_MAGIC; mips32_info.isa_mode = MIPS32_ISA_MIPS32; init_reg_param(®_params[0], "r4", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r5", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "r6", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 0xff); int retval = target_run_algorithm(target, 0, NULL, 3, reg_params, erase_check_algorithm->address, erase_check_algorithm->address + (sizeof(erase_check_code) - 4), 10000, &mips32_info); if (retval == ERROR_OK) *blank = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, erase_check_algorithm); return retval; }
/** Checks whether a memory region is zeroed. */ int xmc4xxx_blank_check_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *blank) { struct working_area *erase_check_algorithm; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_info; int retval; static const uint8_t erase_check_code[] = { #include "../../../contrib/loaders/erase_check/armv7m_0_erase_check.inc" }; /* make sure we have a working area */ if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; retval = target_write_buffer(target, erase_check_algorithm->address, sizeof(erase_check_code), (uint8_t *)erase_check_code); if (retval != ERROR_OK) return retval; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 0x00); retval = target_run_algorithm(target, 0, NULL, 3, reg_params, erase_check_algorithm->address, erase_check_algorithm->address + (sizeof(erase_check_code) - 2), 10000, &armv7m_info); if (retval == ERROR_OK) *blank = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, erase_check_algorithm); return retval; }
/** Generates a CRC32 checksum of a memory region. */ int armv7m_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct armv7m_algorithm armv7m_info; struct reg_param reg_params[2]; int retval; static const uint8_t cortex_m_crc_code[] = { #include "../../contrib/loaders/checksum/armv7m_crc.inc" }; retval = target_alloc_working_area(target, sizeof(cortex_m_crc_code), &crc_algorithm); if (retval != ERROR_OK) return retval; retval = target_write_buffer(target, crc_algorithm->address, sizeof(cortex_m_crc_code), (uint8_t *)cortex_m_crc_code); if (retval != ERROR_OK) goto cleanup; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, count); int timeout = 20000 * (1 + (count / (1024 * 1024))); retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, crc_algorithm->address + (sizeof(cortex_m_crc_code) - 6), timeout, &armv7m_info); if (retval == ERROR_OK) *checksum = buf_get_u32(reg_params[0].value, 0, 32); else LOG_ERROR("error executing cortex_m crc algorithm"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); cleanup: target_free_working_area(target, crc_algorithm); return retval; }
static int runCode(struct ecosflash_flash_bank *info, uint32_t codeStart, uint32_t codeStop, uint32_t r0, uint32_t r1, uint32_t r2, uint32_t *result, /* timeout in ms */ int timeout) { struct target *target = info->target; struct reg_param reg_params[3]; struct arm_algorithm armv4_5_info; armv4_5_info.common_magic = ARM_COMMON_MAGIC; armv4_5_info.core_mode = ARM_MODE_SVC; armv4_5_info.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, r0); buf_set_u32(reg_params[1].value, 0, 32, r1); buf_set_u32(reg_params[2].value, 0, 32, r2); int retval; if ((retval = target_run_algorithm(target, 0, NULL, 3, reg_params, codeStart, codeStop, timeout, &armv4_5_info)) != ERROR_OK) { LOG_ERROR("error executing eCos flash algorithm"); return retval; } *result = buf_get_u32(reg_params[0].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); return ERROR_OK; }
int mips32_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t* checksum) { struct working_area *crc_algorithm; struct reg_param reg_params[2]; struct mips32_algorithm mips32_info; int retval; uint32_t i; /* see contib/loaders/checksum/mips32.s for src */ static const uint32_t mips_crc_code[] = { 0x248C0000, /* addiu $t4, $a0, 0 */ 0x24AA0000, /* addiu $t2, $a1, 0 */ 0x2404FFFF, /* addiu $a0, $zero, 0xffffffff */ 0x10000010, /* beq $zero, $zero, ncomp */ 0x240B0000, /* addiu $t3, $zero, 0 */ /* nbyte: */ 0x81850000, /* lb $a1, ($t4) */ 0x218C0001, /* addi $t4, $t4, 1 */ 0x00052E00, /* sll $a1, $a1, 24 */ 0x3C0204C1, /* lui $v0, 0x04c1 */ 0x00852026, /* xor $a0, $a0, $a1 */ 0x34471DB7, /* ori $a3, $v0, 0x1db7 */ 0x00003021, /* addu $a2, $zero, $zero */ /* loop: */ 0x00044040, /* sll $t0, $a0, 1 */ 0x24C60001, /* addiu $a2, $a2, 1 */ 0x28840000, /* slti $a0, $a0, 0 */ 0x01074826, /* xor $t1, $t0, $a3 */ 0x0124400B, /* movn $t0, $t1, $a0 */ 0x28C30008, /* slti $v1, $a2, 8 */ 0x1460FFF9, /* bne $v1, $zero, loop */ 0x01002021, /* addu $a0, $t0, $zero */ /* ncomp: */ 0x154BFFF0, /* bne $t2, $t3, nbyte */ 0x256B0001, /* addiu $t3, $t3, 1 */ 0x7000003F, /* sdbbp */ }; /* make sure we have a working area */ if (target_alloc_working_area(target, sizeof(mips_crc_code), &crc_algorithm) != ERROR_OK) { return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* convert flash writing code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(mips_crc_code); i++) target_write_u32(target, crc_algorithm->address + i*sizeof(uint32_t), mips_crc_code[i]); mips32_info.common_magic = MIPS32_COMMON_MAGIC; mips32_info.isa_mode = MIPS32_ISA_MIPS32; init_reg_param(®_params[0], "a0", 32, PARAM_IN_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "a1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); int timeout = 20000 * (1 + (count / (1024 * 1024))); if ((retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, crc_algorithm->address + (sizeof(mips_crc_code)-4), timeout, &mips32_info)) != ERROR_OK) { destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); target_free_working_area(target, crc_algorithm); return 0; } *checksum = buf_get_u32(reg_params[0].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); target_free_working_area(target, crc_algorithm); return ERROR_OK; }
/** * Runs ARM code in the target to calculate a CRC32 checksum. * */ int arm_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct arm_algorithm arm_algo; struct arm *arm = target_to_arm(target); struct reg_param reg_params[2]; int retval; uint32_t i; uint32_t exit_var = 0; static const uint8_t arm_crc_code_le[] = { #include "../../contrib/loaders/checksum/armv4_5_crc.inc" }; assert(sizeof(arm_crc_code_le) % 4 == 0); retval = target_alloc_working_area(target, sizeof(arm_crc_code_le), &crc_algorithm); if (retval != ERROR_OK) return retval; /* convert code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(arm_crc_code_le) / 4; i++) { retval = target_write_u32(target, crc_algorithm->address + i * sizeof(uint32_t), le_to_h_u32(&arm_crc_code_le[i * 4])); if (retval != ERROR_OK) goto cleanup; } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, count); /* 20 second timeout/megabyte */ int timeout = 20000 * (1 + (count / (1024 * 1024))); /* armv4 must exit using a hardware breakpoint */ if (arm->is_armv4) exit_var = crc_algorithm->address + sizeof(arm_crc_code_le) - 8; retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, exit_var, timeout, &arm_algo); if (retval == ERROR_OK) *checksum = buf_get_u32(reg_params[0].value, 0, 32); else LOG_ERROR("error executing ARM crc algorithm"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); cleanup: target_free_working_area(target, crc_algorithm); return retval; }
static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* see contib/loaders/flash/stm32x.s for src */ static const uint8_t stm32x_flash_write_code[] = { /* #define STM32_FLASH_CR_OFFSET 0x10 */ /* #define STM32_FLASH_SR_OFFSET 0x0C */ /* write: */ 0x08, 0x4c, /* ldr r4, STM32_FLASH_BASE */ 0x1c, 0x44, /* add r4, r3 */ /* write_half_word: */ 0x01, 0x23, /* movs r3, #0x01 */ 0x23, 0x61, /* str r3, [r4, #STM32_FLASH_CR_OFFSET] */ 0x30, 0xf8, 0x02, 0x3b, /* ldrh r3, [r0], #0x02 */ 0x21, 0xf8, 0x02, 0x3b, /* strh r3, [r1], #0x02 */ /* busy: */ 0xe3, 0x68, /* ldr r3, [r4, #STM32_FLASH_SR_OFFSET] */ 0x13, 0xf0, 0x01, 0x0f, /* tst r3, #0x01 */ 0xfb, 0xd0, /* beq busy */ 0x13, 0xf0, 0x14, 0x0f, /* tst r3, #0x14 */ 0x01, 0xd1, /* bne exit */ 0x01, 0x3a, /* subs r2, r2, #0x01 */ 0xf0, 0xd1, /* bne write_half_word */ /* exit: */ 0x00, 0xbe, /* bkpt #0x00 */ 0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), &stm32x_info->write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; if ((retval = target_write_buffer(target, stm32x_info->write_algorithm->address, sizeof(stm32x_flash_write_code), (uint8_t*)stm32x_flash_write_code)) != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* if we already allocated the writing code, but failed to get a * buffer, free the algorithm */ if (stm32x_info->write_algorithm) target_free_working_area(target, stm32x_info->write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } }; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARMV7M_MODE_ANY; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT); while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count; if ((retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer)) != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); buf_set_u32(reg_params[3].value, 0, 32, stm32x_info->register_offset); if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, stm32x_info->write_algorithm->address, 0, 10000, &armv7m_info)) != ERROR_OK) { LOG_ERROR("error executing stm32x flash write algorithm"); break; } if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_PGERR) { LOG_ERROR("flash memory not erased before writing"); /* Clear but report errors */ target_write_u32(target, STM32_FLASH_SR, FLASH_PGERR); retval = ERROR_FAIL; break; } if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_WRPRTERR) { LOG_ERROR("flash memory write protected"); /* Clear but report errors */ target_write_u32(target, STM32_FLASH_SR, FLASH_WRPRTERR); retval = ERROR_FAIL; break; } buffer += thisrun_count * 2; address += thisrun_count * 2; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, stm32x_info->write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; }
/* Start a low level flash write for the specified region */ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes) { struct target *target = chip->target; uint32_t buffer_size = 8192; struct working_area *write_algorithm; struct working_area *source; uint32_t address = NRF5_FLASH_BASE + offset; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; LOG_DEBUG("Writing buffer to flash offset=0x%"PRIx32" bytes=0x%"PRIx32, offset, bytes); assert(bytes % 4 == 0); /* allocate working area with flash programming code */ if (target_alloc_working_area(target, sizeof(nrf5_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, falling back to slow memory writes"); for (; bytes > 0; bytes -= 4) { retval = target_write_memory(chip->target, offset, 4, 1, buffer); if (retval != ERROR_OK) return retval; retval = nrf5_wait_for_nvmc(chip); if (retval != ERROR_OK) return retval; offset += 4; buffer += 4; } return ERROR_OK; } LOG_WARNING("using fast async flash loader. This is currently supported"); LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add"); LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg/nrf52.cfg to disable it"); retval = target_write_buffer(target, write_algorithm->address, sizeof(nrf5_flash_write_code), nrf5_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */ if (buffer_size <= 256) { /* free working area, write algorithm already allocated */ target_free_working_area(target, write_algorithm); LOG_WARNING("No large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* byte count */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer start */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT); /* target address */ buf_set_u32(reg_params[0].value, 0, 32, bytes); buf_set_u32(reg_params[1].value, 0, 32, source->address); buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[3].value, 0, 32, address); retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4, 0, NULL, 4, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; }
static int str7x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct str7x_flash_bank *str7x_info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size = 32768; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[6]; struct arm_algorithm arm_algo; int retval = ERROR_OK; /* see contib/loaders/flash/str7x.s for src */ static const uint32_t str7x_flash_write_code[] = { /* write: */ 0xe3a04201, /* mov r4, #0x10000000 */ 0xe5824000, /* str r4, [r2, #0x0] */ 0xe5821010, /* str r1, [r2, #0x10] */ 0xe4904004, /* ldr r4, [r0], #4 */ 0xe5824008, /* str r4, [r2, #0x8] */ 0xe4904004, /* ldr r4, [r0], #4 */ 0xe582400c, /* str r4, [r2, #0xc] */ 0xe3a04209, /* mov r4, #0x90000000 */ 0xe5824000, /* str r4, [r2, #0x0] */ /* busy: */ 0xe5924000, /* ldr r4, [r2, #0x0] */ 0xe1140005, /* tst r4, r5 */ 0x1afffffc, /* bne busy */ 0xe5924014, /* ldr r4, [r2, #0x14] */ 0xe31400ff, /* tst r4, #0xff */ 0x03140c01, /* tsteq r4, #0x100 */ 0x1a000002, /* bne exit */ 0xe2811008, /* add r1, r1, #0x8 */ 0xe2533001, /* subs r3, r3, #1 */ 0x1affffec, /* bne write */ /* exit: */ 0xeafffffe, /* b exit */ }; /* flash write code */ if (target_alloc_working_area_try(target, sizeof(str7x_flash_write_code), &write_algorithm) != ERROR_OK) { return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } uint8_t code[sizeof(str7x_flash_write_code)]; target_buffer_set_u32_array(target, code, ARRAY_SIZE(str7x_flash_write_code), str7x_flash_write_code); target_write_buffer(target, write_algorithm->address, sizeof(code), code); /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_IN); init_reg_param(®_params[5], "r5", 32, PARAM_OUT); while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 8)) ? (buffer_size / 8) : count; target_write_buffer(target, source->address, thisrun_count * 8, buffer); buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, str7x_get_flash_adr(bank, FLASH_CR0)); buf_set_u32(reg_params[3].value, 0, 32, thisrun_count); buf_set_u32(reg_params[5].value, 0, 32, str7x_info->busy_bits); retval = target_run_algorithm(target, 0, NULL, 6, reg_params, write_algorithm->address, write_algorithm->address + (sizeof(str7x_flash_write_code) - 4), 10000, &arm_algo); if (retval != ERROR_OK) break; if (buf_get_u32(reg_params[4].value, 0, 32) != 0x00) { retval = str7x_result(bank); break; } buffer += thisrun_count * 8; address += thisrun_count * 8; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); return retval; }
static int fm3_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct fm3_flash_bank *fm3_info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size = 2048; /* 8192 for MB9Bxx6! */ struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; uint32_t u32FlashType; uint32_t u32FlashSeqAddress1; uint32_t u32FlashSeqAddress2; u32FlashType = (uint32_t) fm3_info->flashtype; if (u32FlashType == fm3_flash_type1) { u32FlashSeqAddress1 = 0x00001550; u32FlashSeqAddress2 = 0x00000AA8; } else if (u32FlashType == fm3_flash_type2) { u32FlashSeqAddress1 = 0x00000AA8; u32FlashSeqAddress2 = 0x00000554; } else { LOG_ERROR("Flash/Device type unknown!"); return ERROR_FLASH_OPERATION_FAILED; } /* RAMCODE used for fm3 Flash programming: */ /* R0 keeps source start address (u32Source) */ /* R1 keeps target start address (u32Target) */ /* R2 keeps number of halfwords to write (u32Count) */ /* R3 keeps Flash Sequence address 1 (u32FlashSeq1) */ /* R4 keeps Flash Sequence address 2 (u32FlashSeq2) */ /* R5 returns result value (u32FlashResult) */ const uint8_t fm3_flash_write_code[] = { /* fm3_FLASH_IF->FASZ &= 0xFFFD; */ 0x5F, 0xF0, 0x80, 0x45, /* MOVS.W R5, #(fm3_FLASH_IF->FASZ) */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x4F, 0xF6, 0xFD, 0x76, /* MOVW R6, #0xFFFD */ 0x35, 0x40, /* ANDS R5, R5, R6 */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x35, 0x60, /* STR R5, [R6] */ /* fm3_FLASH_IF->FASZ |= 1; */ 0x5F, 0xF0, 0x80, 0x45, /* MOVS.W R5, #(fm3_FLASH_IF->FASZ) */ 0x2D, 0x68, /* LDR R5, [R3] */ 0x55, 0xF0, 0x01, 0x05, /* ORRS.W R5, R5, #1 */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x35, 0x60, /* STR R5, [R6] */ /* u32DummyRead = fm3_FLASH_IF->FASZ; */ 0x28, 0x4D, /* LDR.N R5, ??u32DummyRead */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x36, 0x68, /* LDR R6, [R6] */ 0x2E, 0x60, /* STR R6, [R5] */ /* u32FlashResult = FLASH_WRITE_NO_RESULT */ 0x26, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x00, 0x26, /* MOVS R6, #0 */ 0x2E, 0x60, /* STR R6, [R5] */ /* while ((u32Count > 0 ) */ /* && (u32FlashResult */ /* == FLASH_WRITE_NO_RESULT)) */ 0x01, 0x2A, /* L0: CMP R2, #1 */ 0x2C, 0xDB, /* BLT.N L1 */ 0x24, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x00, 0x2D, /* CMP R5, #0 */ 0x28, 0xD1, /* BNE.N L1 */ /* *u32FlashSeq1 = FLASH_WRITE_1; */ 0xAA, 0x25, /* MOVS R5, #0xAA */ 0x1D, 0x60, /* STR R5, [R3] */ /* *u32FlashSeq2 = FLASH_WRITE_2; */ 0x55, 0x25, /* MOVS R5, #0x55 */ 0x25, 0x60, /* STR R5, [R4] */ /* *u32FlashSeq1 = FLASH_WRITE_3; */ 0xA0, 0x25, /* MOVS R5, #0xA0 */ 0x1D, 0x60, /* STRH R5, [R3] */ /* *(volatile uint16_t*)u32Target */ /* = *(volatile uint16_t*)u32Source; */ 0x05, 0x88, /* LDRH R5, [R0] */ 0x0D, 0x80, /* STRH R5, [R1] */ /* while (u32FlashResult */ /* == FLASH_WRITE_NO_RESTULT) */ 0x1E, 0x4D, /* L2: LDR.N R5, ??u32FlashResult */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x00, 0x2D, /* CMP R5, #0 */ 0x11, 0xD1, /* BNE.N L3 */ /* if ((*(volatile uint16_t*)u32Target */ /* & FLASH_DQ5) == FLASH_DQ5) */ 0x0D, 0x88, /* LDRH R5, [R1] */ 0xAD, 0x06, /* LSLS R5, R5, #0x1A */ 0x02, 0xD5, /* BPL.N L4 */ /* u32FlashResult = FLASH_WRITE_TIMEOUT */ 0x1A, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x02, 0x26, /* MOVS R6, #2 */ 0x2E, 0x60, /* STR R6, [R5] */ /* if ((*(volatile uint16_t *)u32Target */ /* & FLASH_DQ7) */ /* == (*(volatile uint16_t*)u32Source */ /* & FLASH_DQ7)) */ 0x0D, 0x88, /* L4: LDRH R5, [R1] */ 0x15, 0xF0, 0x80, 0x05, /* ANDS.W R5, R5, #0x80 */ 0x06, 0x88, /* LDRH R6, [R0] */ 0x16, 0xF0, 0x80, 0x06, /* ANDS.W R6, R6, #0x80 */ 0xB5, 0x42, /* CMP R5, R6 */ 0xED, 0xD1, /* BNE.N L2 */ /* u32FlashResult = FLASH_WRITE_OKAY */ 0x15, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x01, 0x26, /* MOVS R6, #1 */ 0x2E, 0x60, /* STR R6, [R5] */ 0xE9, 0xE7, /* B.N L2 */ /* if (u32FlashResult */ /* != FLASH_WRITE_TIMEOUT) */ 0x13, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x02, 0x2D, /* CMP R5, #2 */ 0x02, 0xD0, /* BEQ.N L5 */ /* u32FlashResult = FLASH_WRITE_NO_RESULT */ 0x11, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x00, 0x26, /* MOVS R6, #0 */ 0x2E, 0x60, /* STR R6, [R5] */ /* u32Count--; */ 0x52, 0x1E, /* L5: SUBS R2, R2, #1 */ /* u32Source += 2; */ 0x80, 0x1C, /* ADDS R0, R0, #2 */ /* u32Target += 2; */ 0x89, 0x1C, /* ADDS R1, R1, #2 */ 0xD0, 0xE7, /* B.N L0 */ /* fm3_FLASH_IF->FASZ &= 0xFFFE; */ 0x5F, 0xF0, 0x80, 0x45, /* L1: MOVS.W R5, #(fm3_FLASH_IF->FASZ) */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x4F, 0xF6, 0xFE, 0x76, /* MOVW R6, #0xFFFE */ 0x35, 0x40, /* ANDS R5, R5, R6 */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x35, 0x60, /* STR R5, [R6] */ /* fm3_FLASH_IF->FASZ |= 2; */ 0x5F, 0xF0, 0x80, 0x45, /* MOVS.W R5, #(fm3_FLASH_IF->FASZ) */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x55, 0xF0, 0x02, 0x05, /* ORRS.W R5, R5, #2 */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x35, 0x60, /* STR R5, [R6] */ /* u32DummyRead = fm3_FLASH_IF->FASZ; */ 0x04, 0x4D, /* LDR.N R5, ??u32DummyRead */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x36, 0x68, /* LDR R6, [R6] */ 0x2E, 0x60, /* STR R6, [R5] */ /* copy u32FlashResult to R3 for return */ /* value */ 0xDF, 0xF8, 0x08, 0x50, /* LDR.W R5, ??u32FlashResult */ 0x2D, 0x68, /* LDR R5, [R5] */ /* Breakpoint here */ 0x00, 0xBE, /* BKPT #0 */ /* The following address pointers assume, that the code is running from */ /* address 0x1FFF8008. These address pointers will be patched, if a */ /* different start address in RAM is used (e.g. for Flash type 2)! */ 0x00, 0x80, 0xFF, 0x1F, /* u32DummyRead address in RAM (0x1FFF8000) */ 0x04, 0x80, 0xFF, 0x1F /* u32FlashResult address in RAM (0x1FFF8004) */ }; LOG_INFO("Fujitsu MB9B500: FLASH Write ..."); /* disable HW watchdog */ retval = target_write_u32(target, 0x40011C00, 0x1ACCE551); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, 0x40011C00, 0xE5331AAE); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, 0x40011008, 0x00000000); if (retval != ERROR_OK) return retval; count = count / 2; /* number bytes -> number halfwords */ /* check code alignment */ if (offset & 0x1) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* allocate working area with flash programming code */ if (target_alloc_working_area(target, sizeof(fm3_flash_write_code), &fm3_info->write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, fm3_info->write_algorithm->address, sizeof(fm3_flash_write_code), fm3_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* free working area, if write algorithm already allocated */ if (fm3_info->write_algorithm) { target_free_working_area(target, fm3_info->write_algorithm); } LOG_WARNING("No large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARMV7M_MODE_ANY; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* source start address */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* target start address */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* number of halfwords to program */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* Flash Sequence address 1 */ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* Flash Sequence address 1 */ init_reg_param(®_params[5], "r5", 32, PARAM_IN); /* result */ /* write code buffer and use Flash programming code within fm3 */ /* Set breakpoint to 0 with time-out of 1000 ms */ while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count; retval = target_write_buffer(target, fm3_info->write_algorithm->address, 8, fm3_flash_write_code); if (retval != ERROR_OK) break; /* Patching 'local variable address' for different RAM addresses */ if (fm3_info->write_algorithm->address != 0x1FFF8008) { /* Algorithm: u32DummyRead: */ retval = target_write_u32(target, (fm3_info->write_algorithm->address) + sizeof(fm3_flash_write_code) - 8, (fm3_info->write_algorithm->address) - 8); if (retval != ERROR_OK) break; /* Algorithm: u32FlashResult: */ retval = target_write_u32(target, (fm3_info->write_algorithm->address) + sizeof(fm3_flash_write_code) - 4, (fm3_info->write_algorithm->address) - 4); if (retval != ERROR_OK) break; } retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer); if (retval != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); buf_set_u32(reg_params[3].value, 0, 32, u32FlashSeqAddress1); buf_set_u32(reg_params[4].value, 0, 32, u32FlashSeqAddress2); retval = target_run_algorithm(target, 0, NULL, 6, reg_params, fm3_info->write_algorithm->address, 0, 1000, &armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("Error executing fm3 Flash programming algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (buf_get_u32(reg_params[5].value, 0, 32) != ERROR_OK) { LOG_ERROR("Fujitsu MB9[A/B]FXXX: Flash programming ERROR (Timeout) \ -> Reg R3: %x", buf_get_u32(reg_params[5].value, 0, 32)); retval = ERROR_FLASH_OPERATION_FAILED; break; } buffer += thisrun_count * 2; address += thisrun_count * 2; count -= thisrun_count; }
static int lpcspifi_erase(struct flash_bank *bank, int first, int last) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; struct working_area *erase_algorithm; int retval = ERROR_OK; int sector; LOG_DEBUG("erase from sector %d to sector %d", first, last); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first < 0) || (last < first) || (last >= bank->num_sectors)) { LOG_ERROR("Flash sector invalid"); return ERROR_FLASH_SECTOR_INVALID; } if (!(lpcspifi_info->probed)) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } for (sector = first; sector <= last; sector++) { if (bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %d protected", sector); return ERROR_FAIL; } } /* If we're erasing the entire chip and the flash supports * it, use a bulk erase instead of going sector-by-sector. */ if (first == 0 && last == (bank->num_sectors - 1) && lpcspifi_info->dev->chip_erase_cmd != lpcspifi_info->dev->erase_cmd) { LOG_DEBUG("Chip supports the bulk erase command."\ " Will use bulk erase instead of sector-by-sector erase."); retval = lpcspifi_bulk_erase(bank); if (retval == ERROR_OK) { retval = lpcspifi_set_hw_mode(bank); return retval; } else LOG_WARNING("Bulk flash erase failed. Falling back to sector-by-sector erase."); } retval = lpcspifi_set_hw_mode(bank); if (retval != ERROR_OK) return retval; /* see contrib/loaders/flash/lpcspifi_erase.S for src */ static const uint8_t lpcspifi_flash_erase_code[] = { 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0xea, 0x08, 0xca, 0xf8, 0x8c, 0x81, 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x90, 0x81, 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x94, 0x81, 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x98, 0x81, 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x9c, 0x81, 0x4f, 0xf0, 0x44, 0x08, 0xca, 0xf8, 0xa0, 0x81, 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0x4f, 0xf4, 0x00, 0x68, 0xca, 0xf8, 0x14, 0x80, 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0x4f, 0xf0, 0xff, 0x08, 0xca, 0xf8, 0xab, 0x80, 0x4f, 0xf0, 0x00, 0x0a, 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x00, 0x08, 0xc0, 0xf2, 0x00, 0x18, 0xca, 0xf8, 0x94, 0x80, 0x4f, 0xf4, 0x00, 0x5a, 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x01, 0x08, 0xca, 0xf8, 0x00, 0x87, 0x4f, 0xf4, 0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0x07, 0x08, 0xca, 0xf8, 0x00, 0x80, 0x4f, 0xf0, 0x02, 0x08, 0xca, 0xf8, 0x10, 0x80, 0xca, 0xf8, 0x04, 0x80, 0x00, 0xf0, 0x52, 0xf8, 0x4f, 0xf0, 0x06, 0x09, 0x00, 0xf0, 0x3b, 0xf8, 0x00, 0xf0, 0x48, 0xf8, 0x00, 0xf0, 0x4a, 0xf8, 0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x33, 0xf8, 0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x2f, 0xf8, 0x00, 0xf0, 0x3c, 0xf8, 0x19, 0xf0, 0x02, 0x0f, 0x00, 0xf0, 0x45, 0x80, 0x00, 0xf0, 0x3a, 0xf8, 0x4f, 0xea, 0x02, 0x09, 0x00, 0xf0, 0x23, 0xf8, 0x4f, 0xea, 0x10, 0x49, 0x00, 0xf0, 0x1f, 0xf8, 0x4f, 0xea, 0x10, 0x29, 0x00, 0xf0, 0x1b, 0xf8, 0x4f, 0xea, 0x00, 0x09, 0x00, 0xf0, 0x17, 0xf8, 0x00, 0xf0, 0x24, 0xf8, 0x00, 0xf0, 0x26, 0xf8, 0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x0f, 0xf8, 0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x0b, 0xf8, 0x00, 0xf0, 0x18, 0xf8, 0x19, 0xf0, 0x01, 0x0f, 0x7f, 0xf4, 0xf0, 0xaf, 0x01, 0x39, 0xf9, 0xb1, 0x18, 0x44, 0xff, 0xf7, 0xbf, 0xbf, 0x4f, 0xf4, 0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0xca, 0xf8, 0x08, 0x90, 0xda, 0xf8, 0x0c, 0x90, 0x19, 0xf0, 0x10, 0x0f, 0x7f, 0xf4, 0xfa, 0xaf, 0xda, 0xf8, 0x08, 0x90, 0x70, 0x47, 0x4f, 0xf0, 0xff, 0x08, 0x00, 0xf0, 0x02, 0xb8, 0x4f, 0xf0, 0x00, 0x08, 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0xca, 0xf8, 0xab, 0x80, 0x70, 0x47, 0x00, 0x20, 0x00, 0xbe, 0xff, 0xff }; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; /* Get memory for spifi initialization algorithm */ retval = target_alloc_working_area(target, sizeof(lpcspifi_flash_erase_code), &erase_algorithm); if (retval != ERROR_OK) { LOG_ERROR("Insufficient working area. You must configure a working"\ " area of at least %zdB in order to erase SPIFI flash.", sizeof(lpcspifi_flash_erase_code)); return retval; } /* Write algorithm to working area */ retval = target_write_buffer(target, erase_algorithm->address, sizeof(lpcspifi_flash_erase_code), lpcspifi_flash_erase_code); if (retval != ERROR_OK) { target_free_working_area(target, erase_algorithm); return retval; } init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* Start address */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* Sector count */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* Erase command */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* Sector size */ buf_set_u32(reg_params[0].value, 0, 32, bank->sectors[first].offset); buf_set_u32(reg_params[1].value, 0, 32, last - first + 1); buf_set_u32(reg_params[2].value, 0, 32, lpcspifi_info->dev->erase_cmd); buf_set_u32(reg_params[3].value, 0, 32, bank->sectors[first].size); /* Run the algorithm */ retval = target_run_algorithm(target, 0 , NULL, 4, reg_params, erase_algorithm->address, erase_algorithm->address + sizeof(lpcspifi_flash_erase_code) - 4, 3000*(last - first + 1), &armv7m_info); if (retval != ERROR_OK) LOG_ERROR("Error executing flash erase algorithm"); target_free_working_area(target, erase_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); retval = lpcspifi_set_hw_mode(bank); return retval; }
/* call LPC1700/LPC2000 IAP function * uses 180 bytes working area * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait) * 0x8 to 0x1f: command parameter table (1+5 words) * 0x20 to 0x33: command result table (1+4 words) * 0x34 to 0xb3: stack (only 128b needed) */ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_table[5], uint32_t result_table[4]) { int retval; struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; struct target *target = bank->target; struct mem_param mem_params[2]; struct reg_param reg_params[5]; struct arm_algorithm arm_algo; /* for LPC2000 */ struct armv7m_algorithm armv7m_info; /* for LPC1700 */ uint32_t status_code; uint32_t iap_entry_point = 0; /* to make compiler happier */ /* regrab previously allocated working_area, or allocate a new one */ if (!lpc2000_info->iap_working_area) { uint8_t jump_gate[8]; /* make sure we have a working area */ if (target_alloc_working_area(target, 180, &lpc2000_info->iap_working_area) != ERROR_OK) { LOG_ERROR("no working area specified, can't write LPC2000 internal flash"); return ERROR_FLASH_OPERATION_FAILED; } /* write IAP code to working area */ switch (lpc2000_info->variant) { case lpc1700: target_buffer_set_u32(target, jump_gate, ARMV4_5_T_BX(12)); target_buffer_set_u32(target, jump_gate + 4, ARMV5_T_BKPT(0)); break; case lpc2000_v1: case lpc2000_v2: target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12)); target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0)); break; default: LOG_ERROR("BUG: unknown lpc2000_info->variant encountered"); exit(-1); } retval = target_write_memory(target, lpc2000_info->iap_working_area->address, 4, 2, jump_gate); if (retval != ERROR_OK) { LOG_ERROR( "Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)", lpc2000_info->iap_working_area->address); return retval; } } switch (lpc2000_info->variant) { case lpc1700: armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARMV7M_MODE_ANY; iap_entry_point = 0x1fff1ff1; break; case lpc2000_v1: case lpc2000_v2: arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; iap_entry_point = 0x7ffffff1; break; default: LOG_ERROR("BUG: unknown lpc2000->variant encountered"); exit(-1); } /* command parameter table */ init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 6 * 4, PARAM_OUT); target_buffer_set_u32(target, mem_params[0].value, code); target_buffer_set_u32(target, mem_params[0].value + 0x04, param_table[0]); target_buffer_set_u32(target, mem_params[0].value + 0x08, param_table[1]); target_buffer_set_u32(target, mem_params[0].value + 0x0c, param_table[2]); target_buffer_set_u32(target, mem_params[0].value + 0x10, param_table[3]); target_buffer_set_u32(target, mem_params[0].value + 0x14, param_table[4]); init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x08); /* command result table */ init_mem_param(&mem_params[1], lpc2000_info->iap_working_area->address + 0x20, 5 * 4, PARAM_IN); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, lpc2000_info->iap_working_area->address + 0x20); /* IAP entry point */ init_reg_param(®_params[2], "r12", 32, PARAM_OUT); buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point); switch (lpc2000_info->variant) { case lpc1700: /* IAP stack */ init_reg_param(®_params[3], "sp", 32, PARAM_OUT); buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4); /* return address */ init_reg_param(®_params[4], "lr", 32, PARAM_OUT); buf_set_u32(reg_params[4].value, 0, 32, (lpc2000_info->iap_working_area->address + 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */ target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, 0, 10000, &armv7m_info); break; case lpc2000_v1: case lpc2000_v2: /* IAP stack */ init_reg_param(®_params[3], "sp_svc", 32, PARAM_OUT); buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4); /* return address */ init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT); buf_set_u32(reg_params[4].value, 0, 32, lpc2000_info->iap_working_area->address + 0x04); target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &arm_algo); break; default: LOG_ERROR("BUG: unknown lpc2000->variant encountered"); exit(-1); } status_code = target_buffer_get_u32(target, mem_params[1].value); result_table[0] = target_buffer_get_u32(target, mem_params[1].value + 0x04); result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 0x08); result_table[2] = target_buffer_get_u32(target, mem_params[1].value + 0x0c); result_table[3] = target_buffer_get_u32(target, mem_params[1].value + 0x10); LOG_DEBUG("IAP command = %i (0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ") completed with result = %8.8" PRIx32, code, param_table[0], param_table[1], param_table[2], param_table[3], param_table[4], status_code); destroy_mem_param(&mem_params[0]); destroy_mem_param(&mem_params[1]); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return status_code; }
static int stm32lx_write_half_pages(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* see contib/loaders/flash/stm32lx.S for src */ static const uint8_t stm32lx_flash_write_code[] = { /* write_word: */ 0x00, 0x23, /* movs r3, #0 */ 0x04, 0xe0, /* b test_done */ /* write_word: */ 0x51, 0xf8, 0x04, 0xcb, /* ldr ip, [r1], #4 */ 0x40, 0xf8, 0x04, 0xcb, /* str ip, [r0], #4 */ 0x01, 0x33, /* adds r3, #1 */ /* test_done: */ 0x93, 0x42, /* cmp r3, r2 */ 0xf8, 0xd3, /* bcc write_word */ 0x00, 0xbe, /* bkpt 0 */ }; /* Check if there is an even number of half pages (128bytes) */ if (count % 128) { LOG_ERROR("there should be an even number " "of half pages = 128 bytes (count = %" PRIi32 " bytes)", count); return ERROR_FAIL; } /* flash write code */ if (target_alloc_working_area(target, sizeof(stm32lx_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_DEBUG("no working area for block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; /* Write the flashing code */ retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32lx_flash_write_code), (uint8_t *)stm32lx_flash_write_code); if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); return retval; } /* Allocate half pages memory */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { if (buffer_size > 1024) buffer_size -= 1024; else buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* Enable half-page write */ retval = stm32lx_enable_write_half_page(bank); if (retval != ERROR_OK) { target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); return retval; } struct armv7m_common *armv7m = target_to_armv7m(target); if (armv7m == NULL) { /* something is very wrong if armv7m is NULL */ LOG_ERROR("unable to get armv7m target"); return retval; } /* save any DEMCR flags and configure target to catch any Hard Faults */ uint32_t demcr_save = armv7m->demcr; armv7m->demcr = VC_HARDERR; /* Loop while there are bytes to write */ while (count > 0) { uint32_t this_count; this_count = (count > buffer_size) ? buffer_size : count; /* Write the next half pages */ retval = target_write_buffer(target, source->address, this_count, buffer); if (retval != ERROR_OK) break; /* 4: Store useful information in the registers */ /* the destination address of the copy (R0) */ buf_set_u32(reg_params[0].value, 0, 32, address); /* The source address of the copy (R1) */ buf_set_u32(reg_params[1].value, 0, 32, source->address); /* The length of the copy (R2) */ buf_set_u32(reg_params[2].value, 0, 32, this_count / 4); /* 5: Execute the bunch of code */ retval = target_run_algorithm(target, 0, NULL, sizeof(reg_params) / sizeof(*reg_params), reg_params, write_algorithm->address, 0, 10000, &armv7m_info); if (retval != ERROR_OK) break; /* check for Hard Fault */ if (armv7m->exception_number == 3) break; /* 6: Wait while busy */ retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) break; buffer += this_count; address += this_count; count -= this_count; } /* restore previous flags */ armv7m->demcr = demcr_save; if (armv7m->exception_number == 3) { /* the stm32l15x devices seem to have an issue when blank. * if a ram loader is executed on a blank device it will * Hard Fault, this issue does not happen for a already programmed device. * A related issue is described in the stm32l151xx errata (Doc ID 17721 Rev 6 - 2.1.3). * The workaround of handling the Hard Fault exception does work, but makes the * loader more complicated, as a compromise we manually write the pages, programming time * is reduced by 50% using this slower method. */ LOG_WARNING("couldn't use loader, falling back to page memory writes"); while (count > 0) { uint32_t this_count; this_count = (count > 128) ? 128 : count; /* Write the next half pages */ retval = target_write_buffer(target, address, this_count, buffer); if (retval != ERROR_OK) break; /* Wait while busy */ retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) break; buffer += this_count; address += this_count; count -= this_count; } } if (retval == ERROR_OK) retval = stm32lx_lock_program_memory(bank); target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); return retval; }
static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; uint8_t stm32x_flash_write_code[] = { /* write: */ 0xDF, 0xF8, 0x24, 0x40, /* ldr r4, STM32_FLASH_CR */ 0x09, 0x4D, /* ldr r5, STM32_FLASH_SR */ 0x4F, 0xF0, 0x01, 0x03, /* mov r3, #1 */ 0x23, 0x60, /* str r3, [r4, #0] */ 0x30, 0xF8, 0x02, 0x3B, /* ldrh r3, [r0], #2 */ 0x21, 0xF8, 0x02, 0x3B, /* strh r3, [r1], #2 */ /* busy: */ 0x2B, 0x68, /* ldr r3, [r5, #0] */ 0x13, 0xF0, 0x01, 0x0F, /* tst r3, #0x01 */ 0xFB, 0xD0, /* beq busy */ 0x13, 0xF0, 0x14, 0x0F, /* tst r3, #0x14 */ 0x01, 0xD1, /* bne exit */ 0x01, 0x3A, /* subs r2, r2, #1 */ 0xED, 0xD1, /* bne write */ /* exit: */ 0xFE, 0xE7, /* b exit */ 0x10, 0x20, 0x02, 0x40, /* STM32_FLASH_CR: .word 0x40022010 */ 0x0C, 0x20, 0x02, 0x40 /* STM32_FLASH_SR: .word 0x4002200C */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), &stm32x_info->write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; if ((retval = target_write_buffer(target, stm32x_info->write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code)) != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */ if (stm32x_info->write_algorithm) target_free_working_area(target, stm32x_info->write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } }; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARMV7M_MODE_ANY; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN); while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count; if ((retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer)) != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, stm32x_info->write_algorithm->address, \ stm32x_info->write_algorithm->address + (sizeof(stm32x_flash_write_code) - 10), 10000, &armv7m_info)) != ERROR_OK) { LOG_ERROR("error executing stm32x flash write algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_PGERR) { LOG_ERROR("flash memory not erased before writing"); /* Clear but report errors */ target_write_u32(target, STM32_FLASH_SR, FLASH_PGERR); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_WRPRTERR) { LOG_ERROR("flash memory write protected"); /* Clear but report errors */ target_write_u32(target, STM32_FLASH_SR, FLASH_WRPRTERR); retval = ERROR_FLASH_OPERATION_FAILED; break; } buffer += thisrun_count * 2; address += thisrun_count * 2; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, stm32x_info->write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; }
/** Checks whether a memory region is erased. */ int armv7m_blank_check_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value) { struct working_area *erase_check_algorithm; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_info; const uint8_t *code; uint32_t code_size; int retval; static const uint8_t erase_check_code[] = { #include "../../contrib/loaders/erase_check/armv7m_erase_check.inc" }; static const uint8_t zero_erase_check_code[] = { #include "../../contrib/loaders/erase_check/armv7m_0_erase_check.inc" }; switch (erased_value) { case 0x00: code = zero_erase_check_code; code_size = sizeof(zero_erase_check_code); break; case 0xff: default: code = erase_check_code; code_size = sizeof(erase_check_code); } /* make sure we have a working area */ if (target_alloc_working_area(target, code_size, &erase_check_algorithm) != ERROR_OK) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; retval = target_write_buffer(target, erase_check_algorithm->address, code_size, code); if (retval != ERROR_OK) goto cleanup; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, erased_value); retval = target_run_algorithm(target, 0, NULL, 3, reg_params, erase_check_algorithm->address, erase_check_algorithm->address + (code_size - 2), 10000, &armv7m_info); if (retval == ERROR_OK) *blank = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); cleanup: target_free_working_area(target, erase_check_algorithm); return retval; }
/** * Runs ARM code in the target to check whether a memory block holds * all ones. NOR flash which has been erased, and thus may be written, * holds all ones. * */ int arm_blank_check_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *blank) { struct working_area *check_algorithm; struct reg_param reg_params[3]; struct arm_algorithm arm_algo; struct arm *arm = target_to_arm(target); int retval; uint32_t i; uint32_t exit_var = 0; static const uint8_t check_code_le[] = { #include "../../contrib/loaders/erase_check/armv4_5_erase_check.inc" }; assert(sizeof(check_code_le) % 4 == 0); /* make sure we have a working area */ retval = target_alloc_working_area(target, sizeof(check_code_le), &check_algorithm); if (retval != ERROR_OK) return retval; /* convert code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(check_code_le) / 4; i++) { retval = target_write_u32(target, check_algorithm->address + i * sizeof(uint32_t), le_to_h_u32(&check_code_le[i * 4])); if (retval != ERROR_OK) goto cleanup; } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 0xff); /* armv4 must exit using a hardware breakpoint */ if (arm->is_armv4) exit_var = check_algorithm->address + sizeof(check_code_le) - 4; retval = target_run_algorithm(target, 0, NULL, 3, reg_params, check_algorithm->address, exit_var, 10000, &arm_algo); if (retval == ERROR_OK) *blank = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); cleanup: target_free_working_area(target, check_algorithm); return retval; }
static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv; int retval = ERROR_OK; uint32_t page_size, fifo_size; struct working_area *fifo; struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; struct working_area *write_algorithm; int sector; LOG_DEBUG("offset=0x%08" PRIx32 " count=0x%08" PRIx32, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > mrvlqspi_info->dev->size_in_bytes) { LOG_WARNING("Writes past end of flash. Extra data discarded."); count = mrvlqspi_info->dev->size_in_bytes - offset; } /* Check sector protection */ for (sector = 0; sector < bank->num_sectors; sector++) { /* Start offset in or before this sector? */ /* End offset in or behind this sector? */ if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) && ((offset + count - 1) >= bank->sectors[sector].offset) && bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %d protected", sector); return ERROR_FAIL; } } page_size = mrvlqspi_info->dev->pagesize; /* See contrib/loaders/flash/mrvlqspi.S for src */ static const uint8_t mrvlqspi_flash_write_code[] = { 0x4f, 0xf0, 0x00, 0x0a, 0xa2, 0x44, 0x92, 0x45, 0x7f, 0xf6, 0xfc, 0xaf, 0x00, 0xf0, 0x6b, 0xf8, 0x5f, 0xf0, 0x01, 0x08, 0xc5, 0xf8, 0x1c, 0x80, 0x5f, 0xf0, 0x06, 0x08, 0xc5, 0xf8, 0x10, 0x80, 0x5f, 0xf0, 0x01, 0x09, 0x00, 0xf0, 0x6b, 0xf8, 0x00, 0xf0, 0x7d, 0xf8, 0x5f, 0xf0, 0x31, 0x08, 0xc5, 0xf8, 0x1c, 0x80, 0x90, 0x46, 0xc5, 0xf8, 0x14, 0x80, 0x5f, 0xf0, 0x02, 0x08, 0xc5, 0xf8, 0x10, 0x80, 0x5f, 0xf0, 0x01, 0x09, 0x00, 0xf0, 0x5a, 0xf8, 0xd0, 0xf8, 0x00, 0x80, 0xb8, 0xf1, 0x00, 0x0f, 0x00, 0xf0, 0x8b, 0x80, 0x47, 0x68, 0x47, 0x45, 0x3f, 0xf4, 0xf6, 0xaf, 0x17, 0xf8, 0x01, 0x9b, 0x00, 0xf0, 0x30, 0xf8, 0x8f, 0x42, 0x28, 0xbf, 0x00, 0xf1, 0x08, 0x07, 0x47, 0x60, 0x01, 0x3b, 0x00, 0x2b, 0x00, 0xf0, 0x05, 0x80, 0x02, 0xf1, 0x01, 0x02, 0x92, 0x45, 0x7f, 0xf4, 0xe4, 0xaf, 0x00, 0xf0, 0x50, 0xf8, 0xa2, 0x44, 0x00, 0xf0, 0x2d, 0xf8, 0x5f, 0xf0, 0x01, 0x08, 0xc5, 0xf8, 0x1c, 0x80, 0x5f, 0xf0, 0x00, 0x08, 0xc5, 0xf8, 0x20, 0x80, 0x5f, 0xf0, 0x05, 0x08, 0xc5, 0xf8, 0x10, 0x80, 0x5f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x29, 0xf8, 0x00, 0xf0, 0x13, 0xf8, 0x09, 0xf0, 0x01, 0x09, 0xb9, 0xf1, 0x00, 0x0f, 0xf8, 0xd1, 0x00, 0xf0, 0x34, 0xf8, 0x00, 0x2b, 0xa4, 0xd1, 0x00, 0xf0, 0x53, 0xb8, 0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea, 0x08, 0x68, 0xfa, 0xd4, 0xc5, 0xf8, 0x08, 0x90, 0x70, 0x47, 0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea, 0xc8, 0x68, 0xfa, 0xd4, 0xd5, 0xf8, 0x0c, 0x90, 0x70, 0x47, 0xd5, 0xf8, 0x04, 0x80, 0x48, 0xf4, 0x00, 0x78, 0xc5, 0xf8, 0x04, 0x80, 0xd5, 0xf8, 0x04, 0x80, 0x5f, 0xea, 0x88, 0x58, 0xfa, 0xd4, 0x70, 0x47, 0xd5, 0xf8, 0x00, 0x80, 0x48, 0xf0, 0x01, 0x08, 0xc5, 0xf8, 0x00, 0x80, 0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea, 0x88, 0x78, 0xfa, 0xd5, 0xd5, 0xf8, 0x04, 0x80, 0x69, 0xf3, 0x4d, 0x38, 0x48, 0xf4, 0x00, 0x48, 0xc5, 0xf8, 0x04, 0x80, 0x70, 0x47, 0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea, 0x88, 0x78, 0xfa, 0xd5, 0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea, 0x48, 0x68, 0xfa, 0xd5, 0xd5, 0xf8, 0x04, 0x80, 0x48, 0xf4, 0x80, 0x48, 0xc5, 0xf8, 0x04, 0x80, 0xd5, 0xf8, 0x04, 0x80, 0x5f, 0xea, 0x08, 0x48, 0xfa, 0xd4, 0xd5, 0xf8, 0x00, 0x80, 0x28, 0xf0, 0x01, 0x08, 0xc5, 0xf8, 0x00, 0x80, 0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea, 0x88, 0x78, 0xfa, 0xd5, 0x70, 0x47, 0x00, 0x20, 0x50, 0x60, 0x30, 0x46, 0x00, 0xbe }; if (target_alloc_working_area(target, sizeof(mrvlqspi_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_ERROR("Insufficient working area. You must configure"\ " a working area > %zdB in order to write to SPIFI flash.", sizeof(mrvlqspi_flash_write_code)); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(mrvlqspi_flash_write_code), mrvlqspi_flash_write_code); if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); return retval; } /* FIFO allocation */ fifo_size = target_get_working_area_avail(target); if (fifo_size == 0) { /* if we already allocated the writing code but failed to get fifo * space, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_ERROR("Insufficient working area. Please allocate at least"\ " %zdB of working area to enable flash writes.", sizeof(mrvlqspi_flash_write_code) + 1 ); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } else if (fifo_size < page_size) LOG_WARNING("Working area size is limited; flash writes may be"\ " slow. Increase working area size to at least %zdB"\ " to reduce write times.", (size_t)(sizeof(mrvlqspi_flash_write_code) + page_size) ); if (target_alloc_working_area(target, fifo_size, &fifo) != ERROR_OK) { target_free_working_area(target, write_algorithm); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (halfword-16bit) */ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* page size */ init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* qspi base address */ buf_set_u32(reg_params[0].value, 0, 32, fifo->address); buf_set_u32(reg_params[1].value, 0, 32, fifo->address + fifo->size); buf_set_u32(reg_params[2].value, 0, 32, offset); buf_set_u32(reg_params[3].value, 0, 32, count); buf_set_u32(reg_params[4].value, 0, 32, page_size); buf_set_u32(reg_params[5].value, 0, 32, (uint32_t) mrvlqspi_info->reg_base); retval = target_run_flash_async_algorithm(target, buffer, count, 1, 0, NULL, 6, reg_params, fifo->address, fifo->size, write_algorithm->address, 0, &armv7m_info ); if (retval != ERROR_OK) LOG_ERROR("Error executing flash write algorithm"); target_free_working_area(target, fifo); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); return retval; }
/* Un-initialize the ssp module and initialize the SPIFI module */ static int lpcspifi_set_hw_mode(struct flash_bank *bank) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t ssp_base = lpcspifi_info->ssp_base; struct armv7m_algorithm armv7m_info; struct working_area *spifi_init_algorithm; struct reg_param reg_params[1]; int retval = ERROR_OK; LOG_DEBUG("Uninitializing LPC43xx SSP"); /* Turn off the SSP module */ retval = ssp_write_reg(target, ssp_base, SSP_CR1, 0x00000000); if (retval != ERROR_OK) return retval; /* see contrib/loaders/flash/lpcspifi_init.S for src */ static const uint8_t spifi_init_code[] = { 0x4f, 0xea, 0x00, 0x08, 0xa1, 0xb0, 0x00, 0xaf, 0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03, 0x4f, 0xf0, 0xf3, 0x02, 0xc3, 0xf8, 0x8c, 0x21, 0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03, 0x4f, 0xf4, 0xc0, 0x42, 0xc4, 0xf2, 0x08, 0x02, 0x4f, 0xf4, 0xc0, 0x41, 0xc4, 0xf2, 0x08, 0x01, 0x4f, 0xf4, 0xc0, 0x40, 0xc4, 0xf2, 0x08, 0x00, 0x4f, 0xf0, 0xd3, 0x04, 0xc0, 0xf8, 0x9c, 0x41, 0x20, 0x46, 0xc1, 0xf8, 0x98, 0x01, 0x01, 0x46, 0xc2, 0xf8, 0x94, 0x11, 0xc3, 0xf8, 0x90, 0x11, 0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03, 0x4f, 0xf0, 0x13, 0x02, 0xc3, 0xf8, 0xa0, 0x21, 0x40, 0xf2, 0x18, 0x13, 0xc1, 0xf2, 0x40, 0x03, 0x1b, 0x68, 0x1c, 0x68, 0x40, 0xf2, 0xb4, 0x30, 0xc1, 0xf2, 0x00, 0x00, 0x4f, 0xf0, 0x03, 0x01, 0x4f, 0xf0, 0xc0, 0x02, 0x4f, 0xea, 0x08, 0x03, 0xa0, 0x47, 0x00, 0xf0, 0x00, 0xb8, 0x00, 0xbe }; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; LOG_DEBUG("Allocating working area for SPIFI init algorithm"); /* Get memory for spifi initialization algorithm */ retval = target_alloc_working_area(target, sizeof(spifi_init_code), &spifi_init_algorithm); if (retval != ERROR_OK) { LOG_ERROR("Insufficient working area to initialize SPIFI "\ "module. You must allocate at least %zdB of working "\ "area in order to use this driver.", sizeof(spifi_init_code) ); return retval; } LOG_DEBUG("Writing algorithm to working area at 0x%08" PRIx32, spifi_init_algorithm->address); /* Write algorithm to working area */ retval = target_write_buffer(target, spifi_init_algorithm->address, sizeof(spifi_init_code), spifi_init_code ); if (retval != ERROR_OK) { target_free_working_area(target, spifi_init_algorithm); return retval; } init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* spifi clk speed */ /* For now, the algorithm will set up the SPIFI module * @ the IRC clock speed. In the future, it could be made * a bit smarter to use other clock sources if the user has * already configured them in order to speed up memory- * mapped reads. */ buf_set_u32(reg_params[0].value, 0, 32, 12); /* Run the algorithm */ LOG_DEBUG("Running SPIFI init algorithm"); retval = target_run_algorithm(target, 0 , NULL, 1, reg_params, spifi_init_algorithm->address, spifi_init_algorithm->address + sizeof(spifi_init_code) - 2, 1000, &armv7m_info); if (retval != ERROR_OK) LOG_ERROR("Error executing SPIFI init algorithm"); target_free_working_area(target, spifi_init_algorithm); destroy_reg_param(®_params[0]); return retval; }
/** * ARM-specific bulk write from buffer to address of 8-bit wide NAND. * For now this supports ARMv4,ARMv5 and ARMv7-M cores. * * Enhancements to target_run_algorithm() could enable: * - ARMv6 and ARMv7 cores in ARM mode * * Different code fragments could handle: * - 16-bit wide data (needs different setup) * * @param nand Pointer to the arm_nand_data struct that defines the I/O * @param data Pointer to the data to be copied to flash * @param size Size of the data being copied * @return Success or failure of the operation */ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size) { struct target *target = nand->target; struct arm_algorithm armv4_5_algo; struct armv7m_algorithm armv7m_algo; void *arm_algo; struct arm *arm = target->arch_info; struct reg_param reg_params[3]; uint32_t target_buf; uint32_t exit_var = 0; int retval; /* Inputs: * r0 NAND data address (byte wide) * r1 buffer address * r2 buffer length */ static const uint32_t code_armv4_5[] = { 0xe4d13001, /* s: ldrb r3, [r1], #1 */ 0xe5c03000, /* strb r3, [r0] */ 0xe2522001, /* subs r2, r2, #1 */ 0x1afffffb, /* bne s */ /* exit: ARMv4 needs hardware breakpoint */ 0xe1200070, /* e: bkpt #0 */ }; /* Inputs: * r0 NAND data address (byte wide) * r1 buffer address * r2 buffer length * * see contrib/loaders/flash/armv7m_io.s for src */ static const uint32_t code_armv7m[] = { 0x3b01f811, 0x3a017003, 0xaffaf47f, 0xbf00be00, }; int target_code_size = 0; const uint32_t *target_code_src = NULL; /* set up algorithm */ if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */ armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC; armv7m_algo.core_mode = ARM_MODE_THREAD; arm_algo = &armv7m_algo; target_code_size = sizeof(code_armv7m); target_code_src = code_armv7m; } else { armv4_5_algo.common_magic = ARM_COMMON_MAGIC; armv4_5_algo.core_mode = ARM_MODE_SVC; armv4_5_algo.core_state = ARM_STATE_ARM; arm_algo = &armv4_5_algo; target_code_size = sizeof(code_armv4_5); target_code_src = code_armv4_5; } if (nand->op != ARM_NAND_WRITE || !nand->copy_area) { retval = arm_code_to_working_area(target, target_code_src, target_code_size, nand->chunk_size, &nand->copy_area); if (retval != ERROR_OK) return retval; } nand->op = ARM_NAND_WRITE; /* copy data to work area */ target_buf = nand->copy_area->address + target_code_size; retval = target_write_buffer(target, target_buf, size, data); if (retval != ERROR_OK) return retval; /* set up parameters */ init_reg_param(®_params[0], "r0", 32, PARAM_IN); init_reg_param(®_params[1], "r1", 32, PARAM_IN); init_reg_param(®_params[2], "r2", 32, PARAM_IN); buf_set_u32(reg_params[0].value, 0, 32, nand->data); buf_set_u32(reg_params[1].value, 0, 32, target_buf); buf_set_u32(reg_params[2].value, 0, 32, size); /* armv4 must exit using a hardware breakpoint */ if (arm->is_armv4) exit_var = nand->copy_area->address + target_code_size - 4; /* use alg to write data from work area to NAND chip */ retval = target_run_algorithm(target, 0, NULL, 3, reg_params, nand->copy_area->address, exit_var, 1000, arm_algo); if (retval != ERROR_OK) LOG_ERROR("error executing hosted NAND write"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); return retval; }
static int lpcspifi_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t page_size, fifo_size; struct working_area *fifo; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; struct working_area *write_algorithm; int sector; int retval = ERROR_OK; LOG_DEBUG("offset=0x%08" PRIx32 " count=0x%08" PRIx32, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > lpcspifi_info->dev->size_in_bytes) { LOG_WARNING("Writes past end of flash. Extra data discarded."); count = lpcspifi_info->dev->size_in_bytes - offset; } /* Check sector protection */ for (sector = 0; sector < bank->num_sectors; sector++) { /* Start offset in or before this sector? */ /* End offset in or behind this sector? */ if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) && ((offset + count - 1) >= bank->sectors[sector].offset) && bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %d protected", sector); return ERROR_FAIL; } } page_size = lpcspifi_info->dev->pagesize; retval = lpcspifi_set_hw_mode(bank); if (retval != ERROR_OK) return retval; /* see contrib/loaders/flash/lpcspifi_write.S for src */ static const uint8_t lpcspifi_flash_write_code[] = { 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0xea, 0x08, 0xca, 0xf8, 0x8c, 0x81, 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x90, 0x81, 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x94, 0x81, 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x98, 0x81, 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x9c, 0x81, 0x4f, 0xf0, 0x44, 0x08, 0xca, 0xf8, 0xa0, 0x81, 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0x4f, 0xf4, 0x00, 0x68, 0xca, 0xf8, 0x14, 0x80, 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0x4f, 0xf0, 0xff, 0x08, 0xca, 0xf8, 0xab, 0x80, 0x4f, 0xf0, 0x00, 0x0a, 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x00, 0x08, 0xc0, 0xf2, 0x00, 0x18, 0xca, 0xf8, 0x94, 0x80, 0x4f, 0xf4, 0x00, 0x5a, 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x01, 0x08, 0xca, 0xf8, 0x00, 0x87, 0x4f, 0xf4, 0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0x07, 0x08, 0xca, 0xf8, 0x00, 0x80, 0x4f, 0xf0, 0x02, 0x08, 0xca, 0xf8, 0x10, 0x80, 0xca, 0xf8, 0x04, 0x80, 0x4f, 0xf0, 0x00, 0x0b, 0xa3, 0x44, 0x93, 0x45, 0x7f, 0xf6, 0xfc, 0xaf, 0x00, 0xf0, 0x6a, 0xf8, 0x4f, 0xf0, 0x06, 0x09, 0x00, 0xf0, 0x53, 0xf8, 0x00, 0xf0, 0x60, 0xf8, 0x00, 0xf0, 0x62, 0xf8, 0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x4b, 0xf8, 0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x47, 0xf8, 0x00, 0xf0, 0x54, 0xf8, 0x19, 0xf0, 0x02, 0x0f, 0x00, 0xf0, 0x5d, 0x80, 0x00, 0xf0, 0x52, 0xf8, 0x4f, 0xf0, 0x02, 0x09, 0x00, 0xf0, 0x3b, 0xf8, 0x4f, 0xea, 0x12, 0x49, 0x00, 0xf0, 0x37, 0xf8, 0x4f, 0xea, 0x12, 0x29, 0x00, 0xf0, 0x33, 0xf8, 0x4f, 0xea, 0x02, 0x09, 0x00, 0xf0, 0x2f, 0xf8, 0xd0, 0xf8, 0x00, 0x80, 0xb8, 0xf1, 0x00, 0x0f, 0x00, 0xf0, 0x47, 0x80, 0x47, 0x68, 0x47, 0x45, 0x3f, 0xf4, 0xf6, 0xaf, 0x17, 0xf8, 0x01, 0x9b, 0x00, 0xf0, 0x21, 0xf8, 0x8f, 0x42, 0x28, 0xbf, 0x00, 0xf1, 0x08, 0x07, 0x47, 0x60, 0x01, 0x3b, 0xbb, 0xb3, 0x02, 0xf1, 0x01, 0x02, 0x93, 0x45, 0x7f, 0xf4, 0xe6, 0xaf, 0x00, 0xf0, 0x22, 0xf8, 0xa3, 0x44, 0x00, 0xf0, 0x23, 0xf8, 0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x0c, 0xf8, 0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x08, 0xf8, 0x00, 0xf0, 0x15, 0xf8, 0x19, 0xf0, 0x01, 0x0f, 0x7f, 0xf4, 0xf0, 0xaf, 0xff, 0xf7, 0xa7, 0xbf, 0x4f, 0xf4, 0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0xca, 0xf8, 0x08, 0x90, 0xda, 0xf8, 0x0c, 0x90, 0x19, 0xf0, 0x10, 0x0f, 0x7f, 0xf4, 0xfa, 0xaf, 0xda, 0xf8, 0x08, 0x90, 0x70, 0x47, 0x4f, 0xf0, 0xff, 0x08, 0x00, 0xf0, 0x02, 0xb8, 0x4f, 0xf0, 0x00, 0x08, 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0xca, 0xf8, 0xab, 0x80, 0x70, 0x47, 0x00, 0x20, 0x50, 0x60, 0x30, 0x46, 0x00, 0xbe, 0xff, 0xff }; if (target_alloc_working_area(target, sizeof(lpcspifi_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_ERROR("Insufficient working area. You must configure"\ " a working area > %zdB in order to write to SPIFI flash.", sizeof(lpcspifi_flash_write_code)); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; retval = target_write_buffer(target, write_algorithm->address, sizeof(lpcspifi_flash_write_code), lpcspifi_flash_write_code); if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); return retval; } /* FIFO allocation */ fifo_size = target_get_working_area_avail(target); if (fifo_size == 0) { /* if we already allocated the writing code but failed to get fifo * space, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_ERROR("Insufficient working area. Please allocate at least"\ " %zdB of working area to enable flash writes.", sizeof(lpcspifi_flash_write_code) + 1 ); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } else if (fifo_size < page_size) LOG_WARNING("Working area size is limited; flash writes may be"\ " slow. Increase working area size to at least %zdB"\ " to reduce write times.", (size_t)(sizeof(lpcspifi_flash_write_code) + page_size) ); else if (fifo_size > 0x2000) /* Beyond this point, we start to get diminishing returns */ fifo_size = 0x2000; if (target_alloc_working_area(target, fifo_size, &fifo) != ERROR_OK) { target_free_working_area(target, write_algorithm); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (halfword-16bit) */ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* page size */ buf_set_u32(reg_params[0].value, 0, 32, fifo->address); buf_set_u32(reg_params[1].value, 0, 32, fifo->address + fifo->size); buf_set_u32(reg_params[2].value, 0, 32, offset); buf_set_u32(reg_params[3].value, 0, 32, count); buf_set_u32(reg_params[4].value, 0, 32, page_size); retval = target_run_flash_async_algorithm(target, buffer, count, 1, 0, NULL, 5, reg_params, fifo->address, fifo->size, write_algorithm->address, 0, &armv7m_info ); if (retval != ERROR_OK) LOG_ERROR("Error executing flash write algorithm"); target_free_working_area(target, fifo); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); /* Switch to HW mode before return to prompt */ retval = lpcspifi_set_hw_mode(bank); return retval; }
/** * Runs ARM code in the target to calculate a CRC32 checksum. * */ int arm_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct arm_algorithm arm_algo; struct arm *arm = target_to_arm(target); struct reg_param reg_params[2]; int retval; uint32_t i; uint32_t exit_var = 0; /* see contrib/loaders/checksum/armv4_5_crc.s for src */ static const uint32_t arm_crc_code[] = { 0xE1A02000, /* mov r2, r0 */ 0xE3E00000, /* mov r0, #0xffffffff */ 0xE1A03001, /* mov r3, r1 */ 0xE3A04000, /* mov r4, #0 */ 0xEA00000B, /* b ncomp */ /* nbyte: */ 0xE7D21004, /* ldrb r1, [r2, r4] */ 0xE59F7030, /* ldr r7, CRC32XOR */ 0xE0200C01, /* eor r0, r0, r1, asl 24 */ 0xE3A05000, /* mov r5, #0 */ /* loop: */ 0xE3500000, /* cmp r0, #0 */ 0xE1A06080, /* mov r6, r0, asl #1 */ 0xE2855001, /* add r5, r5, #1 */ 0xE1A00006, /* mov r0, r6 */ 0xB0260007, /* eorlt r0, r6, r7 */ 0xE3550008, /* cmp r5, #8 */ 0x1AFFFFF8, /* bne loop */ 0xE2844001, /* add r4, r4, #1 */ /* ncomp: */ 0xE1540003, /* cmp r4, r3 */ 0x1AFFFFF1, /* bne nbyte */ /* end: */ 0xe1200070, /* bkpt #0 */ /* CRC32XOR: */ 0x04C11DB7 /* .word 0x04C11DB7 */ }; retval = target_alloc_working_area(target, sizeof(arm_crc_code), &crc_algorithm); if (retval != ERROR_OK) return retval; /* convert code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(arm_crc_code); i++) { retval = target_write_u32(target, crc_algorithm->address + i * sizeof(uint32_t), arm_crc_code[i]); if (retval != ERROR_OK) return retval; } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, count); /* 20 second timeout/megabyte */ int timeout = 20000 * (1 + (count / (1024 * 1024))); /* armv4 must exit using a hardware breakpoint */ if (arm->is_armv4) exit_var = crc_algorithm->address + sizeof(arm_crc_code) - 8; retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, exit_var, timeout, &arm_algo); if (retval != ERROR_OK) { LOG_ERROR("error executing ARM crc algorithm"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); target_free_working_area(target, crc_algorithm); return retval; } *checksum = buf_get_u32(reg_params[0].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); target_free_working_area(target, crc_algorithm); return ERROR_OK; }
/** Checks whether a memory region is zeroed. */ int xmc4xxx_blank_check_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *blank) { struct working_area *erase_check_algorithm; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_info; int retval; /* see contrib/loaders/erase_check/armv7m_0_erase_check.s for src */ static const uint8_t erase_check_code[] = { /* loop: */ 0x03, 0x78, /* ldrb r3, [r0] */ 0x01, 0x30, /* adds r0, #1 */ 0x1A, 0x43, /* orrs r2, r2, r3 */ 0x01, 0x39, /* subs r1, r1, #1 */ 0xFA, 0xD1, /* bne loop */ 0x00, 0xBE /* bkpt #0 */ }; /* make sure we have a working area */ if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; retval = target_write_buffer(target, erase_check_algorithm->address, sizeof(erase_check_code), (uint8_t *)erase_check_code); if (retval != ERROR_OK) return retval; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 0x00); retval = target_run_algorithm(target, 0, NULL, 3, reg_params, erase_check_algorithm->address, erase_check_algorithm->address + (sizeof(erase_check_code) - 2), 10000, &armv7m_info); if (retval == ERROR_OK) *blank = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, erase_check_algorithm); return retval; }
/** * Runs ARM code in the target to check whether a memory block holds * all ones. NOR flash which has been erased, and thus may be written, * holds all ones. * */ int arm_blank_check_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *blank) { struct working_area *check_algorithm; struct reg_param reg_params[3]; struct arm_algorithm arm_algo; struct arm *arm = target_to_arm(target); int retval; uint32_t i; uint32_t exit_var = 0; /* see contrib/loaders/erase_check/armv4_5_erase_check.s for src */ static const uint32_t check_code[] = { /* loop: */ 0xe4d03001, /* ldrb r3, [r0], #1 */ 0xe0022003, /* and r2, r2, r3 */ 0xe2511001, /* subs r1, r1, #1 */ 0x1afffffb, /* bne loop */ /* end: */ 0xe1200070, /* bkpt #0 */ }; /* make sure we have a working area */ retval = target_alloc_working_area(target, sizeof(check_code), &check_algorithm); if (retval != ERROR_OK) return retval; /* convert code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(check_code); i++) { retval = target_write_u32(target, check_algorithm->address + i * sizeof(uint32_t), check_code[i]); if (retval != ERROR_OK) return retval; } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 0xff); /* armv4 must exit using a hardware breakpoint */ if (arm->is_armv4) exit_var = check_algorithm->address + sizeof(check_code) - 4; retval = target_run_algorithm(target, 0, NULL, 3, reg_params, check_algorithm->address, exit_var, 10000, &arm_algo); if (retval != ERROR_OK) { destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, check_algorithm); return retval; } *blank = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, check_algorithm); return ERROR_OK; }
/** Generates a CRC32 checksum of a memory region. */ int armv7m_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t* checksum) { struct working_area *crc_algorithm; struct armv7m_algorithm armv7m_info; struct reg_param reg_params[2]; int retval; /* see contib/loaders/checksum/armv7m_crc.s for src */ static const uint16_t cortex_m3_crc_code[] = { 0x4602, /* mov r2, r0 */ 0xF04F, 0x30FF, /* mov r0, #0xffffffff */ 0x460B, /* mov r3, r1 */ 0xF04F, 0x0400, /* mov r4, #0 */ 0xE013, /* b ncomp */ /* nbyte: */ 0x5D11, /* ldrb r1, [r2, r4] */ 0xF8DF, 0x7028, /* ldr r7, CRC32XOR */ 0xEA80, 0x6001, /* eor r0, r0, r1, asl #24 */ 0xF04F, 0x0500, /* mov r5, #0 */ /* loop: */ 0x2800, /* cmp r0, #0 */ 0xEA4F, 0x0640, /* mov r6, r0, asl #1 */ 0xF105, 0x0501, /* add r5, r5, #1 */ 0x4630, /* mov r0, r6 */ 0xBFB8, /* it lt */ 0xEA86, 0x0007, /* eor r0, r6, r7 */ 0x2D08, /* cmp r5, #8 */ 0xD1F4, /* bne loop */ 0xF104, 0x0401, /* add r4, r4, #1 */ /* ncomp: */ 0x429C, /* cmp r4, r3 */ 0xD1E9, /* bne nbyte */ 0xBE00, /* bkpt #0 */ 0x1DB7, 0x04C1 /* CRC32XOR: .word 0x04C11DB7 */ }; uint32_t i; retval = target_alloc_working_area(target, sizeof(cortex_m3_crc_code), &crc_algorithm); if (retval != ERROR_OK) return retval; /* convert flash writing code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(cortex_m3_crc_code); i++) { retval = target_write_u16(target, crc_algorithm->address + i*sizeof(uint16_t), cortex_m3_crc_code[i]); if (retval != ERROR_OK) goto cleanup; } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARMV7M_MODE_ANY; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, count); int timeout = 20000 * (1 + (count / (1024 * 1024))); retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, crc_algorithm->address + (sizeof(cortex_m3_crc_code) - 6), timeout, &armv7m_info); if (retval == ERROR_OK) *checksum = buf_get_u32(reg_params[0].value, 0, 32); else LOG_ERROR("error executing cortex_m3 crc algorithm"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); cleanup: target_free_working_area(target, crc_algorithm); return retval; }
/** * ARM-specific bulk write from buffer to address of 8-bit wide NAND. * For now this only supports ARMv4 and ARMv5 cores. * * Enhancements to target_run_algorithm() could enable: * - ARMv6 and ARMv7 cores in ARM mode * * Different code fragments could handle: * - Thumb2 cores like Cortex-M (needs different byteswapping) * - 16-bit wide data (needs different setup too) * * @param nand Pointer to the arm_nand_data struct that defines the I/O * @param data Pointer to the data to be copied to flash * @param size Size of the data being copied * @return Success or failure of the operation */ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size) { struct target *target = nand->target; struct arm_algorithm algo; struct arm *arm = target->arch_info; struct reg_param reg_params[3]; uint32_t target_buf; uint32_t exit_var = 0; int retval; /* Inputs: * r0 NAND data address (byte wide) * r1 buffer address * r2 buffer length */ static const uint32_t code[] = { 0xe4d13001, /* s: ldrb r3, [r1], #1 */ 0xe5c03000, /* strb r3, [r0] */ 0xe2522001, /* subs r2, r2, #1 */ 0x1afffffb, /* bne s */ /* exit: ARMv4 needs hardware breakpoint */ 0xe1200070, /* e: bkpt #0 */ }; if (nand->op != ARM_NAND_WRITE || !nand->copy_area) { retval = arm_code_to_working_area(target, code, sizeof(code), nand->chunk_size, &nand->copy_area); if (retval != ERROR_OK) return retval; } nand->op = ARM_NAND_WRITE; /* copy data to work area */ target_buf = nand->copy_area->address + sizeof(code); retval = target_write_buffer(target, target_buf, size, data); if (retval != ERROR_OK) return retval; /* set up algorithm and parameters */ algo.common_magic = ARM_COMMON_MAGIC; algo.core_mode = ARM_MODE_SVC; algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_IN); init_reg_param(®_params[1], "r1", 32, PARAM_IN); init_reg_param(®_params[2], "r2", 32, PARAM_IN); buf_set_u32(reg_params[0].value, 0, 32, nand->data); buf_set_u32(reg_params[1].value, 0, 32, target_buf); buf_set_u32(reg_params[2].value, 0, 32, size); /* armv4 must exit using a hardware breakpoint */ if (arm->is_armv4) exit_var = nand->copy_area->address + sizeof(code) - 4; /* use alg to write data from work area to NAND chip */ retval = target_run_algorithm(target, 0, NULL, 3, reg_params, nand->copy_area->address, exit_var, 1000, &algo); if (retval != ERROR_OK) LOG_ERROR("error executing hosted NAND write"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); return retval; }
/* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall * back to another mechanism that does not require onboard RAM * * Caller should not check for other return values specifically */ static int aduc702x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 7000; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[6]; struct arm_algorithm arm_algo; int retval = ERROR_OK; if (((count%2) != 0) || ((offset%2) != 0)) { LOG_ERROR("write block must be multiple of two bytes in offset & length"); return ERROR_FAIL; } /* parameters: r0 - address of source data (absolute) r1 - number of halfwords to be copied r2 - start address in flash (offset from beginning of flash memory) r3 - exit code r4 - base address of flash controller (0xFFFFF800) registers: r5 - scratch r6 - set to 2, used to write flash command */ static const uint32_t aduc702x_flash_write_code[] = { /* <_start>: */ 0xe3a05008, /* mov r5, #8 ; 0x8 */ 0xe5845004, /* str r5, [r4, #4] */ 0xe3a06002, /* mov r6, #2 ; 0x2 */ /* <next>: */ 0xe1c421b0, /* strh r2, [r4, #16] */ 0xe0d050b2, /* ldrh r5, [r0], #2 */ 0xe1c450bc, /* strh r5, [r4, #12] */ 0xe5c46008, /* strb r6, [r4, #8] */ /* <wait_complete>: */ 0xe1d430b0, /* ldrh r3, [r4] */ 0xe3130004, /* tst r3, #4 ; 0x4 */ 0x1afffffc, /* bne 1001c <wait_complete> */ 0xe2822002, /* add r2, r2, #2 ; 0x2 */ 0xe2511001, /* subs r1, r1, #1 ; 0x1 */ 0x0a000001, /* beq 1003c <done> */ 0xe3130001, /* tst r3, #1 ; 0x1 */ 0x1afffff3, /* bne 1000c <next> */ /* <done>: */ 0xeafffffe /* b 1003c <done> */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(aduc702x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } uint8_t code[sizeof(aduc702x_flash_write_code)]; target_buffer_set_u32_array(target, code, ARRAY_SIZE(aduc702x_flash_write_code), aduc702x_flash_write_code); retval = target_write_buffer(target, write_algorithm->address, sizeof(code), code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a buffer, *free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN); init_reg_param(®_params[4], "r4", 32, PARAM_OUT); while (count > 0) { uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count; retval = target_write_buffer(target, source->address, thisrun_count, buffer); if (retval != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, thisrun_count/2); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[4].value, 0, 32, 0xFFFFF800); retval = target_run_algorithm(target, 0, NULL, 5, reg_params, write_algorithm->address, write_algorithm->address + sizeof(aduc702x_flash_write_code) - 4, 10000, &arm_algo); if (retval != ERROR_OK) { LOG_ERROR("error executing aduc702x flash write algorithm"); break; } if ((buf_get_u32(reg_params[3].value, 0, 32) & 1) != 1) { /* FIX!!!! what does this mean??? replace w/sensible error message */ LOG_ERROR("aduc702x detected error writing flash"); retval = ERROR_FAIL; break; } buffer += thisrun_count; address += thisrun_count; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; }
/** Generates a CRC32 checksum of a memory region. */ int armv7m_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct armv7m_algorithm armv7m_info; struct reg_param reg_params[2]; int retval; /* see contrib/loaders/checksum/armv7m_crc.s for src */ static const uint8_t cortex_m3_crc_code[] = { /* main: */ 0x02, 0x46, /* mov r2, r0 */ 0x00, 0x20, /* movs r0, #0 */ 0xC0, 0x43, /* mvns r0, r0 */ 0x0A, 0x4E, /* ldr r6, CRC32XOR */ 0x0B, 0x46, /* mov r3, r1 */ 0x00, 0x24, /* movs r4, #0 */ 0x0D, 0xE0, /* b ncomp */ /* nbyte: */ 0x11, 0x5D, /* ldrb r1, [r2, r4] */ 0x09, 0x06, /* lsls r1, r1, #24 */ 0x48, 0x40, /* eors r0, r0, r1 */ 0x00, 0x25, /* movs r5, #0 */ /* loop: */ 0x00, 0x28, /* cmp r0, #0 */ 0x02, 0xDA, /* bge notset */ 0x40, 0x00, /* lsls r0, r0, #1 */ 0x70, 0x40, /* eors r0, r0, r6 */ 0x00, 0xE0, /* b cont */ /* notset: */ 0x40, 0x00, /* lsls r0, r0, #1 */ /* cont: */ 0x01, 0x35, /* adds r5, r5, #1 */ 0x08, 0x2D, /* cmp r5, #8 */ 0xF6, 0xD1, /* bne loop */ 0x01, 0x34, /* adds r4, r4, #1 */ /* ncomp: */ 0x9C, 0x42, /* cmp r4, r3 */ 0xEF, 0xD1, /* bne nbyte */ 0x00, 0xBE, /* bkpt #0 */ 0xB7, 0x1D, 0xC1, 0x04 /* CRC32XOR: .word 0x04c11db7 */ }; retval = target_alloc_working_area(target, sizeof(cortex_m3_crc_code), &crc_algorithm); if (retval != ERROR_OK) return retval; retval = target_write_buffer(target, crc_algorithm->address, sizeof(cortex_m3_crc_code), (uint8_t *)cortex_m3_crc_code); if (retval != ERROR_OK) goto cleanup; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, count); int timeout = 20000 * (1 + (count / (1024 * 1024))); retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, crc_algorithm->address + (sizeof(cortex_m3_crc_code) - 6), timeout, &armv7m_info); if (retval == ERROR_OK) *checksum = buf_get_u32(reg_params[0].value, 0, 32); else LOG_ERROR("error executing cortex_m crc algorithm"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); cleanup: target_free_working_area(target, crc_algorithm); return retval; }
static int str9x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 32768; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[4]; struct arm_algorithm arm_algo; int retval = ERROR_OK; /* see contib/loaders/flash/str9x.s for src */ static const uint32_t str9x_flash_write_code[] = { /* write: */ 0xe3c14003, /* bic r4, r1, #3 */ 0xe3a03040, /* mov r3, #0x40 */ 0xe1c430b0, /* strh r3, [r4, #0] */ 0xe0d030b2, /* ldrh r3, [r0], #2 */ 0xe0c130b2, /* strh r3, [r1], #2 */ 0xe3a03070, /* mov r3, #0x70 */ 0xe1c430b0, /* strh r3, [r4, #0] */ /* busy: */ 0xe5d43000, /* ldrb r3, [r4, #0] */ 0xe3130080, /* tst r3, #0x80 */ 0x0afffffc, /* beq busy */ 0xe3a05050, /* mov r5, #0x50 */ 0xe1c450b0, /* strh r5, [r4, #0] */ 0xe3a050ff, /* mov r5, #0xFF */ 0xe1c450b0, /* strh r5, [r4, #0] */ 0xe3130012, /* tst r3, #0x12 */ 0x1a000001, /* bne exit */ 0xe2522001, /* subs r2, r2, #1 */ 0x1affffed, /* bne write */ /* exit: */ 0xe1200070, /* bkpt #0 */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(str9x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; uint8_t code[sizeof(str9x_flash_write_code)]; target_buffer_set_u32_array(target, code, ARRAY_SIZE(str9x_flash_write_code), str9x_flash_write_code); target_write_buffer(target, write_algorithm->address, sizeof(code), code); /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN); while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count; target_write_buffer(target, source->address, thisrun_count * 2, buffer); buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); retval = target_run_algorithm(target, 0, NULL, 4, reg_params, write_algorithm->address, 0, 10000, &arm_algo); if (retval != ERROR_OK) { LOG_ERROR("error executing str9x flash write algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80) { retval = ERROR_FLASH_OPERATION_FAILED; break; } buffer += thisrun_count * 2; address += thisrun_count * 2; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; }
static int msp432_init(struct flash_bank *bank) { struct target *target = bank->target; struct msp432_bank *msp432_bank = bank->driver_priv; struct msp432_algo_params algo_params; struct reg_param reg_params[1]; const uint8_t *loader_code; uint32_t loader_size; uint32_t algo_entry_addr; int retval; /* Make sure we've probed the flash to get the device and size */ retval = msp432_auto_probe(bank); if (ERROR_OK != retval) return retval; /* Choose appropriate flash helper algorithm */ switch (msp432_bank->device_type) { case MSP432P401X: case MSP432P401X_DEPR: case MSP432P401X_GUESS: default: loader_code = msp432p401x_algo; loader_size = sizeof(msp432p401x_algo); algo_entry_addr = P4_ALGO_ENTRY_ADDR; break; case MSP432P411X: case MSP432P411X_GUESS: loader_code = msp432p411x_algo; loader_size = sizeof(msp432p411x_algo); algo_entry_addr = P4_ALGO_ENTRY_ADDR; break; case MSP432E401Y: case MSP432E411Y: case MSP432E4X_GUESS: loader_code = msp432e4x_algo; loader_size = sizeof(msp432e4x_algo); algo_entry_addr = E4_ALGO_ENTRY_ADDR; break; } /* Issue warnings if this is a device we may not be able to flash */ if (MSP432P401X_GUESS == msp432_bank->device_type || MSP432P411X_GUESS == msp432_bank->device_type) { /* Explicit device type check failed. Report this. */ LOG_WARNING( "msp432: Unrecognized MSP432P4 Device ID and Hardware " "Rev (%04X, %02X)", msp432_bank->device_id, msp432_bank->hardware_rev); } else if (MSP432P401X_DEPR == msp432_bank->device_type) { LOG_WARNING( "msp432: MSP432P401x pre-production device (deprecated " "silicon)\n" SUPPORT_MESSAGE); } else if (MSP432E4X_GUESS == msp432_bank->device_type) { /* Explicit device type check failed. Report this. */ LOG_WARNING( "msp432: Unrecognized MSP432E4 DID0 and DID1 values " "(%08X, %08X)", msp432_bank->device_id, msp432_bank->hardware_rev); } /* Check for working area to use for flash helper algorithm */ if (NULL != msp432_bank->working_area) target_free_working_area(target, msp432_bank->working_area); retval = target_alloc_working_area(target, ALGO_WORKING_SIZE, &msp432_bank->working_area); if (ERROR_OK != retval) return retval; /* Confirm the defined working address is the area we need to use */ if (ALGO_BASE_ADDR != msp432_bank->working_area->address) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* Write flash helper algorithm into target memory */ retval = target_write_buffer(target, ALGO_BASE_ADDR, loader_size, loader_code); if (ERROR_OK != retval) return retval; /* Initialize the ARMv7 specific info to run the algorithm */ msp432_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; msp432_bank->armv7m_info.core_mode = ARM_MODE_THREAD; /* Initialize algorithm parameters to default values */ msp432_init_params(&algo_params); /* Write out parameters to target memory */ retval = target_write_buffer(target, ALGO_PARAMS_BASE_ADDR, sizeof(algo_params), (uint8_t *)&algo_params); if (ERROR_OK != retval) return retval; /* Initialize stack pointer for flash helper algorithm */ init_reg_param(®_params[0], "sp", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, ALGO_STACK_POINTER_ADDR); /* Begin executing the flash helper algorithm */ retval = target_start_algorithm(target, 0, 0, 1, reg_params, algo_entry_addr, 0, &msp432_bank->armv7m_info); destroy_reg_param(®_params[0]); if (ERROR_OK != retval) { LOG_ERROR("msp432: Failed to start flash helper algorithm"); return retval; } /* * At this point, the algorithm is running on the target and * ready to receive commands and data to flash the target */ /* Issue the init command to the flash helper algorithm */ retval = msp432_exec_cmd(target, &algo_params, FLASH_INIT); if (ERROR_OK != retval) return retval; retval = msp432_wait_return_code(target); return retval; }