aboutsummaryrefslogtreecommitdiff
path: root/src/flash
diff options
context:
space:
mode:
authorTomas Vanek <vanekt@fbl.cz>2021-11-16 12:23:48 +0100
committerTomas Vanek <vanekt@fbl.cz>2022-04-24 08:26:08 +0000
commitf2b4897773a1c9db185dfb61d474055559fd507a (patch)
tree6793b031e3173502fca50d4b3619ceaab3af51d8 /src/flash
parenta26ee5344cf70e068265ac2f03a2915fae070e14 (diff)
downloadriscv-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.c205
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(&reg_params[0], "a0", 32, PARAM_OUT); /* poiner to FLASH_SR */
+ init_reg_param(&reg_params[1], "a1", 32, PARAM_OUT); /* count (halfword-16bit) */
+ init_reg_param(&reg_params[2], "a2", 32, PARAM_OUT); /* buffer start */
+ init_reg_param(&reg_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(&reg_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;