diff options
author | Tomas Vanek <vanekt@fbl.cz> | 2021-11-16 12:23:48 +0100 |
---|---|---|
committer | Tomas Vanek <vanekt@fbl.cz> | 2022-04-24 08:26:08 +0000 |
commit | f2b4897773a1c9db185dfb61d474055559fd507a (patch) | |
tree | 6793b031e3173502fca50d4b3619ceaab3af51d8 /src/flash | |
parent | a26ee5344cf70e068265ac2f03a2915fae070e14 (diff) | |
download | riscv-openocd-f2b4897773a1c9db185dfb61d474055559fd507a.zip riscv-openocd-f2b4897773a1c9db185dfb61d474055559fd507a.tar.gz riscv-openocd-f2b4897773a1c9db185dfb61d474055559fd507a.tar.bz2 |
flash/stm32f1x: add support for RISC-V GigaDevice GD32VF103
The device has compatible flash macro with STM32F1 family, reuse
stm32f1x driver code.
Detect non-ARM target - for simplicy test target type name 'riscv'
and the address has 32 bits.
In case of RISC-V CPU use simple chunked write algo - async algo
cannot be used as the core implemented in this device doesn't
allow memory access while running.
Change-Id: Ie3886fbd8573652691f91a02335812a7300689f7
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: https://review.openocd.org/c/openocd/+/6704
Tested-by: jenkins
Reviewed-by: Tim Newsome <tim@sifive.com>
Diffstat (limited to 'src/flash')
-rw-r--r-- | src/flash/nor/stm32f1x.c | 205 |
1 files changed, 161 insertions, 44 deletions
diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 8e66af3..dea8df7 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -26,6 +26,8 @@ #include "config.h" #endif +#include <string.h> + #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> @@ -129,7 +131,6 @@ struct stm32x_flash_bank { }; static int stm32x_mass_erase(struct flash_bank *bank); -static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id); static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t address, uint32_t hwords_count); @@ -550,6 +551,109 @@ static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buff return retval; } +static int stm32x_write_block_riscv(struct flash_bank *bank, const uint8_t *buffer, + uint32_t address, uint32_t hwords_count) +{ + struct target *target = bank->target; + uint32_t buffer_size; + struct working_area *write_algorithm; + struct working_area *source; + static const uint8_t gd32vf103_flash_write_code[] = { +#include "../../../contrib/loaders/flash/gd32vf103/gd32vf103.inc" + }; + + /* flash write code */ + if (target_alloc_working_area(target, sizeof(gd32vf103_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; + } + + int retval = target_write_buffer(target, write_algorithm->address, + sizeof(gd32vf103_flash_write_code), gd32vf103_flash_write_code); + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); + return retval; + } + + /* memory buffer */ + buffer_size = target_get_working_area_avail(target); + buffer_size = MIN(hwords_count * 2, MAX(buffer_size, 256)); + + retval = target_alloc_working_area(target, buffer_size, &source); + /* Allocated size is always word aligned */ + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); + LOG_WARNING("no large enough working area available, can't do block memory writes"); + /* target_alloc_working_area() may return ERROR_FAIL if area backup fails: + * convert any error to ERROR_TARGET_RESOURCE_NOT_AVAILABLE + */ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + struct reg_param reg_params[4]; + + init_reg_param(®_params[0], "a0", 32, PARAM_OUT); /* poiner to FLASH_SR */ + init_reg_param(®_params[1], "a1", 32, PARAM_OUT); /* count (halfword-16bit) */ + init_reg_param(®_params[2], "a2", 32, PARAM_OUT); /* buffer start */ + init_reg_param(®_params[3], "a3", 32, PARAM_IN_OUT); /* target address */ + + while (hwords_count > 0) { + uint32_t thisrun_hwords = source->size / 2; + + /* Limit to the amount of data we actually want to write */ + if (thisrun_hwords > hwords_count) + thisrun_hwords = hwords_count; + + /* Write data to buffer */ + retval = target_write_buffer(target, source->address, + thisrun_hwords * 2, buffer); + if (retval != ERROR_OK) + break; + + buf_set_u32(reg_params[0].value, 0, 32, stm32x_get_flash_reg(bank, STM32_FLASH_SR)); + buf_set_u32(reg_params[1].value, 0, 32, thisrun_hwords); + buf_set_u32(reg_params[2].value, 0, 32, source->address); + buf_set_u32(reg_params[3].value, 0, 32, address); + + retval = target_run_algorithm(target, + 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + write_algorithm->address, + write_algorithm->address + sizeof(gd32vf103_flash_write_code) - 4, + 10000, NULL); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", + write_algorithm->address, retval); + break; + } + + /* Actually we just need to check for programming errors + * stm32x_wait_status_busy also reports error and clears status bits + */ + retval = stm32x_wait_status_busy(bank, 5); + if (retval != ERROR_OK) { + LOG_ERROR("flash write failed at address 0x%"PRIx32, + buf_get_u32(reg_params[3].value, 0, 32)); + break; + } + + /* Update counters */ + buffer += thisrun_hwords * 2; + address += thisrun_hwords * 2; + hwords_count -= thisrun_hwords; + } + + for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) + destroy_reg_param(®_params[i]); + + target_free_working_area(target, source); + target_free_working_area(target, write_algorithm); + + return retval; +} + /** Writes a block to flash either using target algorithm * or use fallback, host controlled halfword-by-halfword access. * Flash controller must be unlocked before this call. @@ -564,8 +668,15 @@ static int stm32x_write_block(struct flash_bank *bank, */ assert(address % 2 == 0); - /* try using a block write - on ARM architecture or... */ - int retval = stm32x_write_block_async(bank, buffer, address, hwords_count); + int retval; + struct arm *arm = target_to_arm(target); + if (is_arm(arm)) { + /* try using a block write - on ARM architecture or... */ + retval = stm32x_write_block_async(bank, buffer, address, hwords_count); + } else { + /* ... RISC-V architecture */ + retval = stm32x_write_block_riscv(bank, buffer, address, hwords_count); + } if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), @@ -631,11 +742,13 @@ reset_pg_and_lock: return retval; } -static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) -{ - struct target *target = bank->target; - uint32_t device_id_register = 0; +struct stm32x_property_addr { + uint32_t device_id; + uint32_t flash_size; +}; +static int stm32x_get_property_addr(struct target *target, struct stm32x_property_addr *addr) +{ if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_TARGET_NOT_EXAMINED; @@ -643,63 +756,61 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) switch (cortex_m_get_partno_safe(target)) { case CORTEX_M0_PARTNO: /* STM32F0x devices */ - device_id_register = 0x40015800; - break; + addr->device_id = 0x40015800; + addr->flash_size = 0x1FFFF7CC; + return ERROR_OK; case CORTEX_M3_PARTNO: /* STM32F1x devices */ - device_id_register = 0xE0042000; - break; + addr->device_id = 0xE0042000; + addr->flash_size = 0x1FFFF7E0; + return ERROR_OK; case CORTEX_M4_PARTNO: /* STM32F3x devices */ - device_id_register = 0xE0042000; - break; + addr->device_id = 0xE0042000; + addr->flash_size = 0x1FFFF7CC; + return ERROR_OK; case CORTEX_M23_PARTNO: /* GD32E23x devices */ - device_id_register = 0x40015800; - break; + addr->device_id = 0x40015800; + addr->flash_size = 0x1FFFF7E0; + return ERROR_OK; + case CORTEX_M_PARTNO_INVALID: + /* Check for GD32VF103 with RISC-V CPU */ + if (strcmp(target_type_name(target), "riscv") == 0 + && target_address_bits(target) == 32) { + /* There is nothing like arm common_magic in riscv_info_t + * check text name of target and if target is 32-bit + */ + addr->device_id = 0xE0042000; + addr->flash_size = 0x1FFFF7E0; + return ERROR_OK; + } + /* fallthrough */ default: LOG_ERROR("Cannot identify target as a stm32x"); return ERROR_FAIL; } +} - /* read stm32 device id register */ - int retval = target_read_u32(target, device_id_register, device_id); +static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) +{ + struct target *target = bank->target; + struct stm32x_property_addr addr; + + int retval = stm32x_get_property_addr(target, &addr); if (retval != ERROR_OK) return retval; - return retval; + return target_read_u32(target, addr.device_id, device_id); } static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_in_kb) { struct target *target = bank->target; - uint32_t flash_size_reg; - - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_TARGET_NOT_EXAMINED; - } - - switch (cortex_m_get_partno_safe(target)) { - case CORTEX_M0_PARTNO: /* STM32F0x devices */ - flash_size_reg = 0x1FFFF7CC; - break; - case CORTEX_M3_PARTNO: /* STM32F1x devices */ - flash_size_reg = 0x1FFFF7E0; - break; - case CORTEX_M4_PARTNO: /* STM32F3x devices */ - flash_size_reg = 0x1FFFF7CC; - break; - case CORTEX_M23_PARTNO: /* GD32E23x devices */ - flash_size_reg = 0x1FFFF7E0; - break; - default: - LOG_ERROR("Cannot identify target as a stm32x"); - return ERROR_FAIL; - } + struct stm32x_property_addr addr; - int retval = target_read_u16(target, flash_size_reg, flash_size_in_kb); + int retval = stm32x_get_property_addr(target, &addr); if (retval != ERROR_OK) return retval; - return retval; + return target_read_u16(target, addr.flash_size, flash_size_in_kb); } static int stm32x_probe(struct flash_bank *bank) @@ -790,6 +901,8 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; break; + case 0x1906: /* gd32vf103 */ + break; case 0x1909: /* gd32e23x */ stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; @@ -1005,6 +1118,10 @@ static int get_stm32x_info(struct flash_bank *bank, struct command_invocation *c device_str = "GD32F3x0"; break; + case 0x1906: + device_str = "GD32VF103"; + break; + case 0x1909: /* gd32e23x */ device_str = "GD32E23x"; break; |