This is an automated email from Gerrit. "Tomas Vanek <[email protected]>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/6704
-- gerrit commit 6eac39503d0b012bfa8cbcc18aff0f3bef0d9a5a Author: Tomas Vanek <[email protected]> Date: Tue Nov 16 12:23:48 2021 +0100 flash/stm32f1x: add support for RISC-V GigaDevice GD32VF103 [WIP] The device has compatible flash macro with STM32F1 family, reuse stm32f1x driver code. Detect non-ARM target - for simplicy test target type name 'riscv' TODO: add a magic number to riscv_info structure to make detection possible. In case of RISC-V CPU use block write algo - async algo cannot be used as RISC-V doesn't allow memory access when target is running. TODO: optimize xx_write_block() routines, branch ERROR_FLASH_OPERATION_FAILED is common to both Cortex-M and RISC-V and should be run also after host controlled write fallback. stm32x_write_options() does not work on RICS-V because directly calls stm32x_write_block() - it is inefficient for 8 words, no fallback is possible. TODO: refactor host controlled write code to a new procedure, call it from stm32x_write_options() TODO: This change does not contain contrib/loaders/flash/gd32vf103/* For testing use with #5839: flash/nor: Add GigaDevice GD32VF103 driver TODO: doc tcl/target/gd32vf103.cfg: redirect to stm32f1 driver, bigger work area size. Change-Id: Ie3886fbd8573652691f91a02335812a7300689f7 Signed-off-by: Tomas Vanek <[email protected]> diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 6744779e9..7011402ef 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> @@ -537,6 +539,159 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, return retval; } +static int gd32vf103_write_block(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct working_area *write_algorithm; + 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; + } + + uint32_t buffer_size = 16384; + struct working_area *source; + + /* memory buffer */ + while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { + buffer_size /= 2; + buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */ + 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; + } + } + + struct reg_param reg_params[5]; + + init_reg_param(®_params[0], "a0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */ + 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_OUT); /* buffer end */ + init_reg_param(®_params[4], "a4", 32, PARAM_IN_OUT); /* target address */ + + uint32_t wp_addr = source->address; + uint32_t rp_addr = source->address + 4; + uint32_t fifo_start_addr = source->address + 8; + uint32_t fifo_end_addr = source->address + source->size; + + uint32_t wp = fifo_start_addr; + uint32_t rp = fifo_start_addr; + + retval = target_write_u32(target, rp_addr, rp); + if (retval != ERROR_OK) + return retval; + + /* (2:block size) */ + uint32_t thisrun_bytes = fifo_end_addr-fifo_start_addr - 2; + uint32_t address = bank->base + offset; + + while (count > 0) { + const struct stm32x_flash_bank *gd32vf103_info = bank->driver_priv; + + retval = target_read_u32(target, rp_addr, &rp); + if (retval != ERROR_OK) { + LOG_ERROR("failed to get read pointer"); + break; + } + + if (wp != rp) { + LOG_ERROR("Failed to write flash ;; rp = 0x%x ;;; wp = 0x%x", rp, wp); + break; + } + wp = fifo_start_addr; + rp = fifo_start_addr; + retval = target_write_u32(target, rp_addr, rp); + if (retval != ERROR_OK) + break; + /* Limit to the amount of data we actually want to write */ + if (thisrun_bytes > count * 2) + thisrun_bytes = count * 2; + + /* Write data to fifo */ + retval = target_write_buffer(target, wp, thisrun_bytes, buffer); + if (retval != ERROR_OK) + break; + + /* Update counters and wrap write pointer */ + buffer += thisrun_bytes; + count -= thisrun_bytes / 2; + rp = fifo_start_addr; + wp = fifo_start_addr+thisrun_bytes; + + /* Store updated write pointer to target */ + retval = target_write_u32(target, wp_addr, wp); + if (retval != ERROR_OK) + break; + retval = target_write_u32(target, rp_addr, rp); + if (retval != ERROR_OK) + return retval; + + buf_set_u32(reg_params[0].value, 0, 32, gd32vf103_info->register_base); + buf_set_u32(reg_params[1].value, 0, 32, thisrun_bytes/2); + buf_set_u32(reg_params[2].value, 0, 32, source->address); + buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); + buf_set_u32(reg_params[4].value, 0, 32, address); + + retval = target_run_algorithm(target, 0, NULL, 5, reg_params, + write_algorithm->address, write_algorithm->address+4, + 10000, NULL); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", + write_algorithm->address, retval); + return retval; + } + + address += thisrun_bytes; + } + + if (retval == ERROR_FLASH_OPERATION_FAILED) { + LOG_ERROR("flash write failed at address 0x%"PRIx32, + buf_get_u32(reg_params[4].value, 0, 32)); + + if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_PGERR) { + LOG_ERROR("flash memory not erased before writing"); + /* Clear but report errors */ + target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), FLASH_PGERR); + } + + if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_WRPRTERR) { + LOG_ERROR("flash memory write protected"); + /* Clear but report errors */ + target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), FLASH_WRPRTERR); + } + } + + 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; +} + static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { @@ -583,8 +738,14 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) goto cleanup; - /* try using a block write */ - retval = stm32x_write_block(bank, buffer, bank->base + offset, words_remaining); + struct arm *arm = target_to_arm(target); + if (is_arm(arm)) { + /* try using a block write - on ARM architecture or... */ + retval = stm32x_write_block(bank, buffer, bank->base + offset, words_remaining); + } else { + /* ... RiscV architecture */ + retval = gd32vf103_write_block(bank, buffer, offset, words_remaining); + } if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), @@ -619,10 +780,32 @@ cleanup: return retval; } +/* Extension to enum cortex_m_partno */ +enum { + TARGET_TYPE_UNKNOWN, + TARGET_TYPE_RISCV, +}; + +static unsigned int stm32x_get_cm_partno(struct target *target) +{ + struct arm *arm = target_to_arm(target); + if (is_arm(arm)) { + struct cortex_m_common *cortex_m = target_to_cm(target); + if (cortex_m->common_magic == CORTEX_M_COMMON_MAGIC) + return cortex_m->core_info->partno; + + } else if (strcmp(target_type_name(target), "riscv") == 0) { + /* There is nothing like arm common_magic in riscv_info_t + * check text name of target + */ + return TARGET_TYPE_RISCV; + } + return TARGET_TYPE_UNKNOWN; +} + static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) { struct target *target = bank->target; - struct cortex_m_common *cortex_m = target_to_cm(target); uint32_t device_id_register = 0; if (!target_was_examined(target)) { @@ -630,11 +813,12 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) return ERROR_FAIL; } - switch (cortex_m->core_info->partno) { + switch (stm32x_get_cm_partno(target)) { case CORTEX_M0_PARTNO: /* STM32F0x devices */ device_id_register = 0x40015800; break; case CORTEX_M3_PARTNO: /* STM32F1x devices */ + case TARGET_TYPE_RISCV: /* GD32VF103 with RiscV CPU */ device_id_register = 0xE0042000; break; case CORTEX_M4_PARTNO: /* STM32F3x devices */ @@ -659,7 +843,6 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_in_kb) { struct target *target = bank->target; - struct cortex_m_common *cortex_m = target_to_cm(target); uint32_t flash_size_reg; if (!target_was_examined(target)) { @@ -667,11 +850,12 @@ static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_i return ERROR_FAIL; } - switch (cortex_m->core_info->partno) { + switch (stm32x_get_cm_partno(target)) { case CORTEX_M0_PARTNO: /* STM32F0x devices */ flash_size_reg = 0x1FFFF7CC; break; case CORTEX_M3_PARTNO: /* STM32F1x devices */ + case TARGET_TYPE_RISCV: /* GD32VF103 with RiscV CPU */ flash_size_reg = 0x1FFFF7E0; break; case CORTEX_M4_PARTNO: /* STM32F3x devices */ @@ -777,6 +961,7 @@ static int stm32x_probe(struct flash_bank *bank) max_flash_size_in_kb = 64; break; case 0x1704: /* gd32f3x0 */ + case 0x1906: /* gd32vf103 */ stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; break; @@ -995,6 +1180,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; diff --git a/tcl/target/gd32vf103.cfg b/tcl/target/gd32vf103.cfg index 0a43f0079..949f15929 100644 --- a/tcl/target/gd32vf103.cfg +++ b/tcl/target/gd32vf103.cfg @@ -12,10 +12,11 @@ if { [info exists CHIPNAME] } { set _CHIPNAME gd32vf103 } +# The smallest RAM size 6kB (GD32VF103C4/T4/R4) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { - set _WORKAREASIZE 0x800 + set _WORKAREASIZE 0x1800 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d @@ -26,4 +27,4 @@ target create $_TARGETNAME riscv -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME gd32vf103 0x08000000 0 0 0 $_TARGETNAME +flash bank $_FLASHNAME stm32f1x 0x08000000 0 0 0 $_TARGETNAME --
