flash/stm32f1x: add support for RISC-V GigaDevice GD32VF103 04/6704/12
authorTomas Vanek <vanekt@fbl.cz>
Tue, 16 Nov 2021 11:23:48 +0000 (12:23 +0100)
committerTomas Vanek <vanekt@fbl.cz>
Sun, 24 Apr 2022 08:26:08 +0000 (08:26 +0000)
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>
contrib/loaders/flash/gd32vf103/Makefile [new file with mode: 0644]
contrib/loaders/flash/gd32vf103/gd32vf103.c [new file with mode: 0644]
contrib/loaders/flash/gd32vf103/gd32vf103.inc [new file with mode: 0644]
doc/openocd.texi
src/flash/nor/stm32f1x.c

diff --git a/contrib/loaders/flash/gd32vf103/Makefile b/contrib/loaders/flash/gd32vf103/Makefile
new file mode 100644 (file)
index 0000000..2c34e08
--- /dev/null
@@ -0,0 +1,28 @@
+BIN2C = ../../../../src/helper/bin2char.sh
+
+CROSS_COMPILE ?= riscv-none-embed-
+
+CC=$(CROSS_COMPILE)gcc
+OBJCOPY=$(CROSS_COMPILE)objcopy
+OBJDUMP=$(CROSS_COMPILE)objdump
+
+CFLAGS = -march=rv32i -mabi=ilp32 -static -nostartfiles -nostdlib -Os -g -fPIC
+
+all: gd32vf103.inc
+
+.PHONY: clean
+
+%.elf: %.c
+       $(CC) $(CFLAGS) $< -o $@
+
+%.lst: %.elf
+       $(OBJDUMP) -S $< > $@
+
+%.bin: %.elf
+       $(OBJCOPY) -Obinary $< $@
+
+%.inc: %.bin
+       $(BIN2C) < $< > $@
+
+clean:
+       -rm -f *.elf *.lst *.bin *.inc
diff --git a/contrib/loaders/flash/gd32vf103/gd32vf103.c b/contrib/loaders/flash/gd32vf103/gd32vf103.c
new file mode 100644 (file)
index 0000000..69225a0
--- /dev/null
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <stdint.h>
+
+#define FLASH_BSY      (1 << 0)
+#define FLASH_PGERR    (1 << 2)
+#define FLASH_WRPRTERR (1 << 4)
+
+void flash_write(volatile uint32_t *flash_sr,
+               uint32_t hwords_count,
+               uint16_t *buffer,
+               uint16_t *target_addr) __attribute__((naked));
+
+void flash_write(volatile uint32_t *flash_sr,
+               uint32_t hwords_count,
+               uint16_t *buffer,
+               uint16_t *target_addr)
+{
+       do {
+               *target_addr = *buffer++;
+
+               register uint32_t sr;
+               do {
+                       sr = *flash_sr;
+               } while (sr & FLASH_BSY);
+
+               if (sr & (FLASH_PGERR | FLASH_WRPRTERR))
+                       break;
+
+               target_addr++;
+       } while (--hwords_count);
+       asm("ebreak");
+}
diff --git a/contrib/loaders/flash/gd32vf103/gd32vf103.inc b/contrib/loaders/flash/gd32vf103/gd32vf103.inc
new file mode 100644 (file)
index 0000000..05eabff
--- /dev/null
@@ -0,0 +1,4 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0x83,0x57,0x06,0x00,0x13,0x06,0x26,0x00,0x23,0x90,0xf6,0x00,0x83,0x27,0x05,0x00,
+0x13,0xf7,0x17,0x00,0xe3,0x1c,0x07,0xfe,0x93,0xf7,0x47,0x01,0x63,0x98,0x07,0x00,
+0x93,0x85,0xf5,0xff,0x93,0x86,0x26,0x00,0xe3,0x9c,0x05,0xfc,0x73,0x00,0x10,0x00,
index 121873522caa15c6136091b0149a15c3ed6434ff..d55002733196a394c14da9154c978328535b1e12 100644 (file)
@@ -7293,6 +7293,7 @@ applied to all of them.
 All members of the STM32F0, STM32F1 and STM32F3 microcontroller families
 from STMicroelectronics and all members of the GD32F1x0, GD32F3x0 and GD32E23x microcontroller
 families from GigaDevice include internal flash and use ARM Cortex-M0/M3/M4/M23 cores.
+The driver also works with GD32VF103 powered by RISC-V core.
 The driver automatically recognizes a number of these chips using
 the chip identification register, and autoconfigures itself.
 
index 8e66af368fa642138903d95fbb3459981e455f54..dea8df759a7dd67fcb0a3674e3bf99e50e37a9da 100644 (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;
-
-       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;

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)