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>
This commit is contained in:
Tomas Vanek
2021-11-16 12:23:48 +01:00
parent a26ee5344c
commit f2b4897773
5 changed files with 227 additions and 44 deletions

View File

@@ -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;
struct stm32x_property_addr addr;
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;
}
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;