This is an automated email from Gerrit. "Ryan QIAN <jianghao.q...@outlook.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/6980
-- gerrit commit 7c54c29676230a37afbfbc633ea5e01db20b470b Author: Ryan QIAN <jianghao.q...@outlook.com> Date: Tue May 17 20:49:54 2022 +0800 flash: nor: add hpm_xpi flash programming support - Add qspi nor flash driver for HPM6700 series Signed-off-by: Ryan QIAN <jianghao.q...@outlook.com> Change-Id: I2a4e231cd48813dfeafc6b34896db5c589462464 diff --git a/contrib/loaders/flash/hpm_xpi/Makefile b/contrib/loaders/flash/hpm_xpi/Makefile new file mode 100644 index 0000000000..0b32941d4d --- /dev/null +++ b/contrib/loaders/flash/hpm_xpi/Makefile @@ -0,0 +1,26 @@ +BIN2C = ../../../../src/helper/bin2char.sh + + +#SRCS=hpm_xpi_flash.bin + +OBJS=hpm_xpi_flash.inc +#$(patsubst %.S,%.inc,$(SRCS)) $(patsubst %.S,%.asm,$(SRCS)) + +CROSS_COMPILE ?= riscv32-elf- +CC=$(CROSS_COMPILE)gcc +OBJCOPY=$(CROSS_COMPILE)objcopy +OBJDUMP=$(CROSS_COMPILE)objdump +LD=$(CROSS_COMPILE)ld + + +all: $(OBJS) + +hpm_xpi_flash.inc: hpm_xpi_flash.bin + $(BIN2C) < $< > $@ + +clean: + -rm -f *.o *.elf *.lst *.pdf *.inc + +.PHONY: all clean + +.INTERMEDIATE: $(patsubst %.S,%.o,$(SRCS)) $(patsubst %.S,%.elf,$(SRCS)) $(patsubst %.S,%.bin,$(SRCS)) diff --git a/contrib/loaders/flash/hpm_xpi/hpm_xpi_flash.bin b/contrib/loaders/flash/hpm_xpi/hpm_xpi_flash.bin new file mode 100755 index 0000000000..1e6930b3f0 Binary files /dev/null and b/contrib/loaders/flash/hpm_xpi/hpm_xpi_flash.bin differ diff --git a/contrib/loaders/flash/hpm_xpi/hpm_xpi_flash.h b/contrib/loaders/flash/hpm_xpi/hpm_xpi_flash.h new file mode 100644 index 0000000000..a86957038f --- /dev/null +++ b/contrib/loaders/flash/hpm_xpi/hpm_xpi_flash.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 hpmicro + * + * SPDX-License-Identifier: BSD-3-Clause * + */ + +#ifndef HPM_XPI_FLASH_H +#define HPM_XPI_FLASH_H + +#define FLASH_INIT (0) +#define FLASH_ERASE (0x6) +#define FLASH_PROGRAM (0xc) +#define FLASH_READ (0x12) +#define FLASH_GET_INFO (0x18) +#define FLASH_ERASE_CHIP (0x1e) + +uint8_t flash_algo[] = { +#include "hpm_xpi_flash.inc" +}; + +#endif diff --git a/contrib/loaders/flash/hpm_xpi/hpm_xpi_flash.inc b/contrib/loaders/flash/hpm_xpi/hpm_xpi_flash.inc new file mode 100644 index 0000000000..7c0186321b --- /dev/null +++ b/contrib/loaders/flash/hpm_xpi/hpm_xpi_flash.inc @@ -0,0 +1,87 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0xef,0x00,0xc0,0x02,0x02,0x90,0xef,0x00,0x20,0x10,0x02,0x90,0xef,0x00,0x00,0x21, +0x02,0x90,0xef,0x00,0x20,0x25,0x02,0x90,0xef,0x00,0x80,0x29,0x02,0x90,0xef,0x00, +0x20,0x2b,0x02,0x90,0xef,0x00,0x80,0x30,0x02,0x90,0x00,0x00,0x39,0x71,0x22,0xdc, +0x26,0xda,0x4a,0xd8,0x37,0x07,0x00,0x80,0x06,0xde,0x4e,0xd6,0x52,0xd4,0x56,0xd2, +0x2e,0x89,0xb2,0x84,0x36,0x84,0x63,0x0d,0xe5,0x0a,0xaa,0x87,0x37,0x07,0x00,0x90, +0x13,0x05,0x20,0x00,0xb7,0x4a,0x04,0xf3,0x63,0x98,0xe7,0x08,0x97,0x09,0x00,0x00, +0x83,0xa9,0x89,0x3e,0x83,0xc7,0x09,0x00,0xd1,0xeb,0x17,0x0a,0x00,0x00,0x03,0x2a, +0x2a,0x3d,0xd2,0x87,0x13,0x07,0x0a,0x10,0x02,0xc6,0x02,0xc8,0x02,0xca,0x02,0xcc, +0x23,0x2e,0x01,0x00,0x23,0xa0,0x07,0x00,0x91,0x07,0xe3,0x9d,0xe7,0xfe,0xb7,0x07, +0x02,0x20,0x83,0xa7,0x47,0xf1,0x97,0x05,0x00,0x00,0x83,0xa5,0x25,0x3b,0x9c,0x47, +0x56,0x85,0x82,0x97,0x4a,0xc6,0x26,0xc8,0x22,0xca,0x93,0x77,0x04,0x10,0x5b,0x73, +0x84,0x00,0x89,0x47,0x17,0x07,0x00,0x00,0x03,0x27,0xc7,0x38,0x1c,0xc3,0xb7,0x07, +0x02,0x20,0x83,0xa7,0x47,0xf1,0x70,0x00,0xfc,0x47,0x97,0x05,0x00,0x00,0x83,0xa5, +0x25,0x37,0x56,0x85,0x82,0x97,0x09,0xe9,0x83,0xc7,0x09,0x00,0x23,0x0a,0x0a,0x02, +0x91,0xef,0x85,0x47,0x23,0x80,0xf9,0x00,0xf2,0x50,0x62,0x54,0xd2,0x54,0x42,0x59, +0xb2,0x59,0x22,0x5a,0x92,0x5a,0x21,0x61,0x67,0x80,0x00,0x00,0x01,0x45,0xed,0xb7, +0xb7,0x0a,0x04,0xf3,0x6f,0xf0,0x9f,0xf5,0x01,0x11,0x22,0xcc,0x4a,0xc8,0xb7,0x07, +0x00,0x80,0x06,0xce,0x26,0xca,0x4e,0xc6,0x52,0xc4,0x56,0xc2,0x5a,0xc0,0x2e,0x89, +0x32,0x84,0x63,0x01,0xf5,0x0e,0xb7,0x07,0x00,0x90,0xb7,0x4a,0x04,0xf3,0x63,0x1f, +0xf5,0x0a,0x17,0x06,0x00,0x00,0x03,0x26,0xa6,0x30,0x83,0x54,0x86,0x02,0xaa,0x04, +0x63,0x6e,0x94,0x08,0xb3,0x79,0x99,0x02,0x33,0x8a,0x34,0x41,0x63,0x86,0x44,0x03, +0xb7,0x07,0x02,0x20,0x83,0xa7,0x47,0xf1,0x17,0x0b,0x00,0x00,0x03,0x2b,0x8b,0x2e, +0x9c,0x4f,0x83,0x25,0x0b,0x00,0x52,0x87,0xca,0x86,0x56,0x85,0x82,0x97,0x49,0xe1, +0xb3,0x89,0x99,0x40,0x4e,0x94,0x52,0x99,0x63,0xf2,0x84,0x06,0x17,0x0b,0x00,0x00, +0x03,0x2b,0x4b,0x2c,0x37,0x0a,0x02,0x20,0x97,0x09,0x00,0x00,0x83,0xa9,0x49,0x2b, +0x83,0x27,0x4a,0xf1,0x83,0x25,0x0b,0x00,0xdc,0x53,0xca,0x86,0x4e,0x86,0x56,0x85, +0x05,0x8c,0x82,0x97,0x31,0xe5,0x26,0x99,0xe3,0xe4,0x84,0xfe,0xb7,0x07,0x02,0x20, +0x83,0xa7,0x47,0xf1,0x22,0x87,0x62,0x44,0x83,0x25,0x0b,0x00,0xf2,0x40,0xd2,0x44, +0xb2,0x49,0x22,0x4a,0x02,0x4b,0x9c,0x4f,0xca,0x86,0x56,0x85,0x42,0x49,0x92,0x4a, +0x17,0x06,0x00,0x00,0x03,0x26,0xc6,0x26,0x05,0x61,0x82,0x87,0x01,0x45,0x09,0xc8, +0x17,0x0b,0x00,0x00,0x03,0x2b,0x0b,0x26,0x6f,0xf0,0x5f,0xfc,0x13,0x05,0x20,0x00, +0xf2,0x40,0x62,0x44,0xd2,0x44,0x42,0x49,0xb2,0x49,0x22,0x4a,0x92,0x4a,0x02,0x4b, +0x05,0x61,0x82,0x80,0x17,0x06,0x00,0x00,0x03,0x26,0x86,0x23,0x83,0x54,0x86,0x02, +0xb7,0x0a,0x04,0xf3,0xaa,0x04,0xe3,0x63,0x94,0xfc,0x2d,0xb7,0x37,0x08,0x00,0x80, +0x2e,0x87,0xb6,0x87,0x63,0x0c,0x05,0x03,0xb7,0x06,0x00,0x90,0x63,0x16,0xd5,0x02, +0x37,0x45,0x04,0xf3,0xb7,0x06,0x02,0x20,0x83,0xa6,0x46,0xf1,0x03,0xa8,0x86,0x02, +0x97,0x06,0x00,0x00,0x83,0xa6,0x06,0x20,0x8c,0x42,0xb2,0x86,0x17,0x06,0x00,0x00, +0x03,0x26,0x06,0x1f,0x67,0x00,0x08,0x00,0x09,0x45,0x82,0x80,0x37,0x05,0x04,0xf3, +0x6f,0xf0,0x5f,0xfd,0xb7,0x08,0x00,0x80,0x2e,0x88,0x32,0x87,0xb3,0x07,0xd0,0x00, +0x63,0x0c,0x15,0x03,0xb7,0x06,0x00,0x90,0x63,0x16,0xd5,0x02,0x37,0x45,0x04,0xf3, +0xb7,0x06,0x02,0x20,0x83,0xa6,0x46,0xf1,0x17,0x06,0x00,0x00,0x03,0x26,0x46,0x1b, +0x83,0xa8,0xc6,0x02,0x97,0x06,0x00,0x00,0x83,0xa6,0xc6,0x1a,0x8c,0x42,0xc2,0x86, +0x67,0x80,0x08,0x00,0x09,0x45,0x82,0x80,0x37,0x05,0x04,0xf3,0x6f,0xf0,0x5f,0xfd, +0x91,0xcd,0x97,0x07,0x00,0x00,0x83,0xa7,0xa7,0x18,0x98,0x53,0x83,0xd7,0x67,0x02, +0x2a,0x07,0xaa,0x07,0x01,0x45,0x98,0xc1,0xdc,0xc1,0x82,0x80,0x09,0x45,0x82,0x80, +0xb7,0x07,0x00,0x80,0x63,0x0a,0xf5,0x02,0xb7,0x07,0x00,0x90,0x63,0x14,0xf5,0x02, +0xb7,0x07,0x02,0x20,0x83,0xa7,0x47,0xf1,0x17,0x07,0x00,0x00,0x03,0x27,0x87,0x15, +0xdc,0x4f,0x0c,0x43,0x37,0x45,0x04,0xf3,0x17,0x06,0x00,0x00,0x03,0x26,0x46,0x14, +0x67,0x80,0x07,0x00,0x09,0x45,0x82,0x80,0xb7,0x07,0x02,0x20,0x83,0xa7,0x47,0xf1, +0x17,0x07,0x00,0x00,0x03,0x27,0x07,0x13,0xdc,0x4f,0x0c,0x43,0x37,0x05,0x04,0xf3, +0x17,0x06,0x00,0x00,0x03,0x26,0xc6,0x11,0x67,0x80,0x07,0x00,0x82,0x80,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x03,0x00,0x00, +0x30,0x03,0x00,0x00,0x34,0x03,0x00,0x00,0x54,0x04,0x00,0x00,0xff,0xff,0xff,0xff, +0x00,0x00,0x00,0x00,0x58,0x4e,0x4f,0x52,0x00,0x00,0x00,0x00,0x01,0x05,0x00,0x00, +0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x04,0x00,0x40,0x00,0x00,0x00, +0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x07,0x00,0x00,0x03,0x03,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xeb,0x04,0x18,0x0a,0x00,0x1e,0x04,0x32,0x04,0x26,0x00,0x00, +0x00,0x00,0x00,0x00,0x02,0x04,0x18,0x08,0x04,0x20,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x05,0x04,0x04,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x06,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x20,0x04,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xd8,0x04,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x60,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00, diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index a5ef422104..ad409200dc 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -75,7 +75,8 @@ NOR_DRIVERS = \ %D%/w600.c \ %D%/xcf.c \ %D%/xmc1xxx.c \ - %D%/xmc4xxx.c + %D%/xmc4xxx.c \ + %D%/hpm_xpi.c NORHEADERS = \ %D%/core.h \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 3e35c0954d..c0e440a751 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -89,6 +89,7 @@ extern const struct flash_driver w600_flash; extern const struct flash_driver xcf_flash; extern const struct flash_driver xmc1xxx_flash; extern const struct flash_driver xmc4xxx_flash; +extern const struct flash_driver hpm_xpi_flash; /** * The list of built-in flash drivers. @@ -164,6 +165,7 @@ static const struct flash_driver * const flash_drivers[] = { &xmc1xxx_flash, &xmc4xxx_flash, &w600_flash, + &hpm_xpi_flash, NULL, }; diff --git a/src/flash/nor/hpm_xpi.c b/src/flash/nor/hpm_xpi.c new file mode 100644 index 0000000000..0666a29be3 --- /dev/null +++ b/src/flash/nor/hpm_xpi.c @@ -0,0 +1,731 @@ +/* + * Copyright (c) 2021 hpmicro + * + * SPDX-License-Identifier: BSD-3-Clause * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "imp.h" +#include <helper/bits.h> +#include <helper/binarybuffer.h> +#include <helper/time_support.h> +#include <target/algorithm.h> +#include <target/image.h> +#include "target/riscv/program.h" + +#include "../../../contrib/loaders/flash/hpm_xpi/hpm_xpi_flash.h" +#define TIMEOUT_IN_MS (10000U) +#define ERASE_CHIP_TIMEOUT_IN_MS (100000U) +#define SECTOR_ERASE_TIMEOUT_IN_MS (100) +#define BLOCK_SIZE (4096U) +#define NOR_CFG_OPT_HEADER (0xFCF90000UL) + +typedef struct { + uint32_t total_sz_in_bytes; + uint32_t sector_sz_in_bytes; +} hpm_flash_info_t; + +typedef struct hpm_xpi_priv { + uint32_t io_base; + uint32_t header; + uint32_t opt0; + uint32_t opt1; + bool probed; +} hpm_xpi_priv_t; + +static int hpm_xpi_probe(struct flash_bank *bank) +{ + int retval = ERROR_OK; + struct reg_param reg_params[5]; + hpm_xpi_priv_t *xpi_priv; + int xlen; + hpm_flash_info_t flash_info = {0}; + struct working_area *data_wa = NULL; + struct target *target = bank->target; + struct flash_sector *sectors = NULL; + struct working_area *wa; + + LOG_DEBUG("%s", __func__); + xpi_priv = bank->driver_priv; + + if (xpi_priv->probed) { + xpi_priv->probed = false; + bank->size = 0; + bank->num_sectors = 0; + bank->sectors = NULL; + } + + for (target = all_targets; target; target = target->next) { + if (target->target_number == 0) { + riscv_set_current_hartid(target, 0); + target->coreid = 0; + break; + } + } + if (target == NULL) + target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + fflush(stdout); + return ERROR_TARGET_NOT_HALTED; + } + xlen = riscv_xlen(target); + + if (target_alloc_working_area(target, sizeof(flash_algo), + &wa) != ERROR_OK) { + LOG_WARNING("Couldn't allocate %zd-byte working area.", + sizeof(flash_algo)); + wa = NULL; + } else { + retval = target_write_buffer(target, wa->address, + sizeof(flash_algo), flash_algo); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write code to 0x%" TARGET_PRIxADDR ": %d", + wa->address, retval); + target_free_working_area(target, wa); + wa = NULL; + } + } + + if (wa == NULL) + goto err; + + init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); + init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); + init_reg_param(®_params[2], "a2", xlen, PARAM_OUT); + init_reg_param(®_params[3], "a3", xlen, PARAM_OUT); + init_reg_param(®_params[4], "ra", xlen, PARAM_OUT); + buf_set_u64(reg_params[0].value, 0, xlen, bank->base); + buf_set_u64(reg_params[1].value, 0, xlen, xpi_priv->header); + buf_set_u64(reg_params[2].value, 0, xlen, xpi_priv->opt0); + buf_set_u64(reg_params[3].value, 0, xlen, xpi_priv->opt1); + buf_set_u64(reg_params[4].value, 0, xlen, wa->address + FLASH_INIT + 4); + retval = target_run_algorithm(target, 0, NULL, 5, reg_params, + wa->address, wa->address + FLASH_INIT + 4, 500, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute run algorithm: %d", retval); + goto err; + } + + retval = buf_get_u32(reg_params[0].value, 0, xlen); + if (retval) { + LOG_ERROR("init flash failed on target: 0x%" PRIx32, retval); + goto err; + } + + if (target_alloc_working_area(target, sizeof(flash_info), + &data_wa) != ERROR_OK) { + LOG_WARNING("Couldn't allocate %zd-byte working area.", + sizeof(flash_info)); + goto err; + } + + init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); + init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); + init_reg_param(®_params[2], "ra", xlen, PARAM_OUT); + buf_set_u64(reg_params[0].value, 0, xlen, bank->base); + buf_set_u64(reg_params[1].value, 0, xlen, data_wa->address); + buf_set_u64(reg_params[2].value, 0, xlen, wa->address + FLASH_GET_INFO + 4); + + retval = target_run_algorithm(target, 0, NULL, 3, reg_params, + wa->address + FLASH_GET_INFO, wa->address + FLASH_GET_INFO + 4, 500, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to run algorithm at: %d", retval); + goto err; + } + + retval = buf_get_u32(reg_params[0].value, 0, xlen); + if (retval) { + LOG_ERROR("flash get info failed on target: 0x%" PRIx32, retval); + goto err; + } + + retval = target_read_memory(target, data_wa->address, xlen >> 3, + sizeof(flash_info) / (xlen >> 3), (uint8_t *)&flash_info); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read memory at 0x%" TARGET_PRIxADDR ": %d", data_wa->address, retval); + goto err; + } + + bank->size = flash_info.total_sz_in_bytes; + bank->num_sectors = flash_info.total_sz_in_bytes / flash_info.sector_sz_in_bytes; + bank->write_start_alignment = 2; + + /* create and fill sectors array */ + sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + if (sectors == NULL) { + LOG_ERROR("not enough memory"); + retval = ERROR_FAIL; + goto err; + } + + for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { + sectors[sector].offset = sector * (flash_info.sector_sz_in_bytes); + sectors[sector].size = flash_info.sector_sz_in_bytes; + sectors[sector].is_erased = -1; + sectors[sector].is_protected = 0; + } + + bank->sectors = sectors; + + xpi_priv->probed = true; + +err: + for (uint8_t k = 0; k < ARRAY_SIZE(reg_params); k++) + destroy_reg_param(®_params[k]); + if (data_wa) + target_free_working_area(target, data_wa); + if (wa) + target_free_working_area(target, wa); + return retval; +} + +static int hpm_xpi_auto_probe(struct flash_bank *bank) +{ + hpm_xpi_priv_t *xpi_priv = bank->driver_priv; + if (xpi_priv->probed) + return ERROR_OK; + return hpm_xpi_probe(bank); +} + +static int hpm_xpi_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct reg_param reg_params[5]; + int retval = ERROR_OK; + struct target *target; + struct working_area *data_wa = NULL; + struct working_area *wa = NULL; + uint32_t data_size = BLOCK_SIZE; + uint32_t left = count, i = 0; + int xlen; + hpm_xpi_priv_t *xpi_priv = bank->driver_priv; + + LOG_DEBUG("%s", __func__); + for (target = all_targets; target; target = target->next) { + if (target->target_number == 0) { + riscv_set_current_hartid(target, 0); + target->coreid = 0; + break; + } + } + + if (target == NULL) + target = bank->target; + + if (target_alloc_working_area(target, sizeof(flash_algo), + &wa) != ERROR_OK) { + LOG_WARNING("Couldn't allocate %zd-byte working area.", + sizeof(flash_algo)); + wa = NULL; + } else { + retval = target_write_buffer(target, wa->address, + sizeof(flash_algo), flash_algo); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write code to 0x%" TARGET_PRIxADDR ": %d", + wa->address, retval); + target_free_working_area(target, wa); + wa = NULL; + } + } + + if (wa == NULL) + goto err; + + xlen = riscv_xlen(target); + init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); + init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); + init_reg_param(®_params[2], "a2", xlen, PARAM_OUT); + init_reg_param(®_params[3], "a3", xlen, PARAM_OUT); + init_reg_param(®_params[4], "ra", xlen, PARAM_OUT); + buf_set_u64(reg_params[0].value, 0, xlen, bank->base); + buf_set_u64(reg_params[1].value, 0, xlen, xpi_priv->header); + buf_set_u64(reg_params[2].value, 0, xlen, xpi_priv->opt0); + buf_set_u64(reg_params[3].value, 0, xlen, xpi_priv->opt1); + buf_set_u64(reg_params[4].value, 0, xlen, wa->address + FLASH_INIT + 4); + retval = target_run_algorithm(target, 0, NULL, 5, reg_params, + wa->address, wa->address + FLASH_INIT + 4, 500, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute run algorithm: %d", retval); + goto err; + } + + retval = buf_get_u32(reg_params[0].value, 0, xlen); + if (retval) { + LOG_ERROR("init flash failed on target: 0x%" PRIx32, retval); + goto err; + } + + /* memory buffer */ + while (target_alloc_working_area_try(target, data_size, &data_wa) != ERROR_OK) { + data_size /= 2; + if (data_size <= 256) { + /* we already allocated the writing code, but failed to get a + * buffer, free the algorithm */ + target_free_working_area(target, wa); + + LOG_WARNING("no large enough working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } + + init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); + init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); + init_reg_param(®_params[2], "a2", xlen, PARAM_OUT); + init_reg_param(®_params[3], "a3", xlen, PARAM_OUT); + + while (left >= data_size) { + retval = target_write_buffer(target, data_wa->address, data_size, buffer + i * data_size); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write buffer to 0x%" TARGET_PRIxADDR ": %d", data_wa->address, retval); + goto err; + } + + buf_set_u32(reg_params[0].value, 0, xlen, bank->base); + buf_set_u32(reg_params[1].value, 0, xlen, offset + i * data_size); + buf_set_u32(reg_params[2].value, 0, xlen, data_wa->address); + buf_set_u32(reg_params[3].value, 0, xlen, data_size); + + retval = target_run_algorithm(target, 0, NULL, 4, reg_params, + wa->address + FLASH_PROGRAM, wa->address + FLASH_PROGRAM + 4, TIMEOUT_IN_MS, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", wa->address, retval); + goto err; + } + + retval = buf_get_u32(reg_params[0].value, 0, xlen); + if (retval) { + LOG_ERROR("flash write failed on target: 0x%" PRIx32, retval); + goto err; + } + i++; + left -= data_size; + } + + if (left) { + retval = target_write_buffer(target, data_wa->address, left, buffer + i * data_size); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write buffer to 0x%" TARGET_PRIxADDR ": %d", data_wa->address, retval); + goto err; + } + + buf_set_u32(reg_params[0].value, 0, xlen, bank->base); + buf_set_u32(reg_params[1].value, 0, xlen, offset + i * data_size); + buf_set_u32(reg_params[2].value, 0, xlen, data_wa->address); + buf_set_u32(reg_params[3].value, 0, xlen, left); + + retval = target_run_algorithm(target, 0, NULL, 4, reg_params, + wa->address + FLASH_PROGRAM, wa->address + FLASH_PROGRAM + 4, TIMEOUT_IN_MS, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", wa->address, retval); + goto err; + } + + retval = buf_get_u32(reg_params[0].value, 0, xlen); + if (retval) { + LOG_ERROR("flash write failed on target: 0x%" PRIx32, retval); + goto err; + } + } + +err: + if (data_wa) + target_free_working_area(target, data_wa); + if (wa) + target_free_working_area(target, wa); + + for (uint8_t k = 0; k < ARRAY_SIZE(reg_params); k++) + destroy_reg_param(®_params[k]); + return retval; +} + +static int hpm_xpi_erase(struct flash_bank *bank, unsigned int first, unsigned int last) +{ + int retval = ERROR_OK; + struct reg_param reg_params[5]; + struct target *target = bank->target; + struct working_area *wa = NULL; + int xlen; + hpm_xpi_priv_t *xpi_priv = bank->driver_priv; + + LOG_DEBUG("%s", __func__); + for (target = all_targets; target; target = target->next) { + if (target->target_number == 0) { + riscv_set_current_hartid(target, 0); + target->coreid = 0; + break; + } + } + + if (target == NULL) + target = bank->target; + + xlen = riscv_xlen(target); + if (target_alloc_working_area(target, sizeof(flash_algo), + &wa) != ERROR_OK) { + LOG_WARNING("Couldn't allocate %zd-byte working area.", + sizeof(flash_algo)); + wa = NULL; + } else { + retval = target_write_buffer(target, wa->address, + sizeof(flash_algo), flash_algo); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write code to 0x%" TARGET_PRIxADDR ": %d", + wa->address, retval); + target_free_working_area(target, wa); + wa = NULL; + } + } + + if (wa == NULL) + goto err; + + init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); + init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); + init_reg_param(®_params[2], "a2", xlen, PARAM_OUT); + init_reg_param(®_params[3], "a3", xlen, PARAM_OUT); + init_reg_param(®_params[4], "ra", xlen, PARAM_OUT); + buf_set_u64(reg_params[0].value, 0, xlen, bank->base); + buf_set_u64(reg_params[1].value, 0, xlen, xpi_priv->header); + buf_set_u64(reg_params[2].value, 0, xlen, xpi_priv->opt0); + buf_set_u64(reg_params[3].value, 0, xlen, xpi_priv->opt1); + buf_set_u64(reg_params[4].value, 0, xlen, wa->address + FLASH_INIT + 4); + retval = target_run_algorithm(target, 0, NULL, 5, reg_params, + wa->address, wa->address + FLASH_INIT + 4, 500, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute run algorithm: %d", retval); + goto err; + } + + retval = buf_get_u32(reg_params[0].value, 0, xlen); + if (retval) { + LOG_ERROR("init flash failed on target: 0x%" PRIx32, retval); + goto err; + } + + LOG_DEBUG("%s: from sector %u to sector %u", __func__, first, last); + + init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); + init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); + init_reg_param(®_params[2], "a2", xlen, PARAM_OUT); + + buf_set_u32(reg_params[0].value, 0, xlen, bank->base); + buf_set_u32(reg_params[1].value, 0, xlen, first * bank->sectors[0].size); + buf_set_u32(reg_params[2].value, 0, xlen, (last - first + 1) * bank->sectors[0].size); + + retval = target_run_algorithm(target, 0, NULL, 3, reg_params, + wa->address + FLASH_ERASE, wa->address + FLASH_ERASE + 4, + SECTOR_ERASE_TIMEOUT_IN_MS * (last - first + 1), NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", wa->address, retval); + goto err; + } + + retval = buf_get_u32(reg_params[0].value, 0, xlen); + if (retval) { + LOG_ERROR("flash erase failed on target: 0x%" PRIx32, retval); + goto err; + } + +err: + if (wa) + target_free_working_area(target, wa); + for (uint8_t k = 0; k < ARRAY_SIZE(reg_params); k++) + destroy_reg_param(®_params[k]); + return retval; +} + +static int hpm_xpi_erase_chip(struct flash_bank *bank) +{ + int retval = ERROR_OK; + struct reg_param reg_params[5]; + struct target *target = bank->target; + struct working_area *wa = NULL; + int xlen; + hpm_xpi_priv_t *xpi_priv = bank->driver_priv; + + LOG_DEBUG("%s", __func__); + for (target = all_targets; target; target = target->next) { + if (target->target_number == 0) { + riscv_set_current_hartid(target, 0); + target->coreid = 0; + break; + } + } + + if (target == NULL) + target = bank->target; + + xlen = riscv_xlen(target); + + if (target_alloc_working_area(target, sizeof(flash_algo), + &wa) != ERROR_OK) { + LOG_WARNING("Couldn't allocate %zd-byte working area.", + sizeof(flash_algo)); + wa = NULL; + } else { + retval = target_write_buffer(target, wa->address, + sizeof(flash_algo), flash_algo); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write code to 0x%" TARGET_PRIxADDR ": %d", + wa->address, retval); + target_free_working_area(target, wa); + wa = NULL; + } + } + + if (wa == NULL) + goto err; + + init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); + init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); + init_reg_param(®_params[2], "a2", xlen, PARAM_OUT); + init_reg_param(®_params[3], "a3", xlen, PARAM_OUT); + init_reg_param(®_params[4], "ra", xlen, PARAM_OUT); + buf_set_u64(reg_params[0].value, 0, xlen, bank->base); + buf_set_u64(reg_params[1].value, 0, xlen, xpi_priv->header); + buf_set_u64(reg_params[2].value, 0, xlen, xpi_priv->opt0); + buf_set_u64(reg_params[3].value, 0, xlen, xpi_priv->opt1); + buf_set_u64(reg_params[4].value, 0, xlen, wa->address + FLASH_INIT + 4); + retval = target_run_algorithm(target, 0, NULL, 5, reg_params, + wa->address, wa->address + FLASH_INIT + 4, 500, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute run algorithm: %d", retval); + goto err; + } + + retval = buf_get_u32(reg_params[0].value, 0, xlen); + if (retval) { + LOG_ERROR("init flash failed on target: 0x%" PRIx32, retval); + goto err; + } + init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); + buf_set_u64(reg_params[0].value, 0, xlen, bank->base); + + retval = target_run_algorithm(target, 0, NULL, 1, reg_params, + wa->address + FLASH_ERASE_CHIP, wa->address + FLASH_ERASE_CHIP + 4, ERASE_CHIP_TIMEOUT_IN_MS, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", wa->address, retval); + goto err; + } + + retval = buf_get_u32(reg_params[0].value, 0, xlen); + if (retval) { + LOG_ERROR("flash erase chip failed on target: 0x%" PRIx32, retval); + goto err; + } + +err: + if (wa) + target_free_working_area(target, wa); + for (uint8_t k = 0; k < ARRAY_SIZE(reg_params); k++) + destroy_reg_param(®_params[k]); + return retval; +} + + +static int hpm_xpi_get_info(struct flash_bank *bank, struct command_invocation *cmd) +{ + LOG_DEBUG("%s", __func__); + return ERROR_OK; +} + +static int hpm_xpi_protect(struct flash_bank *bank, int set, + unsigned int first, unsigned int last) +{ + LOG_DEBUG("%s", __func__); + return ERROR_OK; +} + +static int hpm_xpi_read(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + LOG_DEBUG("%s", __func__); + struct target *target = bank->target; + int xlen; + for (target = all_targets; target; target = target->next) { + if (target->target_number == 0) { + riscv_set_current_hartid(target, 0); + target->coreid = 0; + break; + } + } + if (target == NULL) + target = bank->target; + + xlen = riscv_xlen(target); + + return target_read_memory(bank->target, bank->base + offset, xlen >> 3, count / (xlen >> 3), buffer); +} + +static int hpm_xpi_blank_check(struct flash_bank *bank) +{ + LOG_DEBUG("%s", __func__); + return ERROR_OK; +} + +static int hpm_xpi_protect_check(struct flash_bank *bank) +{ + LOG_DEBUG("%s", __func__); + /* Nothing to do. Protection is only handled in SW. */ + return ERROR_OK; +} + +static int hpm_xpi_verify(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + int retval = ERROR_OK; + hpm_xpi_priv_t *xpi_priv; + struct target *target = bank->target; + uint8_t *buf_on_target = NULL; + int xlen; + + LOG_DEBUG("%s", __func__); + xpi_priv = bank->driver_priv; + if (!xpi_priv->probed) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + for (target = all_targets; target; target = target->next) { + if (target->target_number == 0) { + riscv_set_current_hartid(target, 0); + target->coreid = 0; + break; + } + } + + if (target == NULL) + target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + buf_on_target = malloc(count); + if (buf_on_target == NULL) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + xlen = riscv_xlen(target); + retval = target_read_memory(target, bank->base + offset, xlen >> 3, count / (xlen >> 3), buf_on_target); + if (ERROR_OK != retval) + return retval; + + if (!memcmp(buf_on_target, buffer, count)) + return ERROR_OK; + return ERROR_FAIL; +} + +COMMAND_HANDLER(hpm_xpi_handle_erase_chip_command) +{ + int retval; + struct flash_bank *bank; + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + LOG_DEBUG("%s", __func__); + + return hpm_xpi_erase_chip(bank); +} + + +static const struct command_registration hpm_xpi_exec_command_handlers[] = { + { + .name = "erase_chip", + .handler = hpm_xpi_handle_erase_chip_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "erase entire flash device.", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration hpm_xpi_command_handlers[] = { + { + .name = "hpm_xpi", + .mode = COMMAND_ANY, + .help = "hpm_xpi command group", + .usage = "", + .chain = hpm_xpi_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +FLASH_BANK_COMMAND_HANDLER(hpm_xpi_flash_bank_command) +{ + hpm_xpi_priv_t *xpi_priv; + uint32_t io_base; + uint32_t header; + uint32_t opt0; + uint32_t opt1; + + LOG_DEBUG("%s", __func__); + + if (CMD_ARGC < 7) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], io_base); + + switch (CMD_ARGC) { + case 7: + header = NOR_CFG_OPT_HEADER + 1; + opt1 = 0; + opt0 = 7; + break; + case 8: + header = NOR_CFG_OPT_HEADER + 1; + opt1 = 0; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], opt0); + break; + case 9: + header = NOR_CFG_OPT_HEADER + 2; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], opt0); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[8], opt1); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + xpi_priv = malloc(sizeof(struct hpm_xpi_priv)); + if (xpi_priv == NULL) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + bank->driver_priv = xpi_priv; + xpi_priv->io_base = io_base; + xpi_priv->header = header; + xpi_priv->opt0 = opt0; + xpi_priv->opt1 = opt1; + xpi_priv->probed = false; + + return ERROR_OK; +} + +static void hpm_xpi_free_driver_priv(struct flash_bank *bank) +{ + default_flash_free_driver_priv(bank); +} + +struct flash_driver hpm_xpi_flash = { + .name = "hpm_xpi", + .flash_bank_command = hpm_xpi_flash_bank_command, + .commands = hpm_xpi_command_handlers, + .erase = hpm_xpi_erase, + .protect = hpm_xpi_protect, + .write = hpm_xpi_write, + .read = hpm_xpi_read, + .verify = hpm_xpi_verify, + .probe = hpm_xpi_probe, + .auto_probe = hpm_xpi_auto_probe, + .erase_check = hpm_xpi_blank_check, + .protect_check = hpm_xpi_protect_check, + .info = hpm_xpi_get_info, + .free_driver_priv = hpm_xpi_free_driver_priv, +}; --