[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openocd-development
Subject:    [PATCH]: c9a7464bcb flash: nor: add hpm_xpi flash programming support
From:       gerrit () openocd ! org
Date:       2022-05-22 12:47:17
Message-ID: 20220522124718.23B97169 () openocd ! org
[Download RAW message or body]

This is an automated email from Gerrit.

"Ryan QIAN <jianghao.qian@outlook.com>" just uploaded a new patch set to Gerrit, \
which you can find at https://review.openocd.org/c/openocd/+/6985

-- gerrit

commit c9a7464bcbe02b3e8ddd763b395b32e039c280c2
Author: Ryan QIAN <jianghao.qian@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.qian@hpmicro.com>
    Change-Id: I9818ddb61d97ab6072b3fcc5bcb56604a0a99da1

diff --git a/contrib/loaders/flash/hpm_xpi/Makefile \
b/contrib/loaders/flash/hpm_xpi/Makefile new file mode 100644
index 0000000000..b35b7fe435
--- /dev/null
+++ b/contrib/loaders/flash/hpm_xpi/Makefile
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: BSD-3-Clause
+
+BIN2C = ../../../../src/helper/bin2char.sh
+
+SRCS += hpm_xpi_flash.bin
+OBJS=hpm_xpi_flash.inc
+
+all: $(OBJS)
+
+hpm_xpi_flash.inc: $(SRCS)
+	$(BIN2C) < $< > $@
+
+clean:
+	-rm -f *.bin *.inc
+
+.PHONY:	all clean
diff --git a/contrib/loaders/flash/hpm_xpi/README \
b/contrib/loaders/flash/hpm_xpi/README new file mode 100644
index 0000000000..81b31a607e
--- /dev/null
+++ b/contrib/loaders/flash/hpm_xpi/README
@@ -0,0 +1,6 @@
+HPMicro
+
+openocd_algo is an example in hpm_sdk, located at \
${HPM_SDK_BASE}/samples/openocd_flash_algo, +please refer to hpm_sdk readme to build \
it. +
+for more details, please refer to https://www.hpmicro.com/resources/software.html 
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..e734f2e1f1
--- /dev/null
+++ b/contrib/loaders/flash/hpm_xpi/hpm_xpi_flash.inc
@@ -0,0 +1,86 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0xef,0x00,0xa0,0x02,0x02,0x90,0xef,0x00,0x80,0x0f,0x02,0x90,0xef,0x00,0x20,0x20,
+0x02,0x90,0xef,0x00,0x00,0x24,0x02,0x90,0xef,0x00,0x00,0x28,0x02,0x90,0xef,0x00,
+0xa0,0x29,0x02,0x90,0xef,0x00,0xc0,0x2e,0x02,0x90,0x39,0x71,0x22,0xdc,0x26,0xda,
+0x4a,0xd8,0x06,0xde,0x4e,0xd6,0x52,0xd4,0x56,0xd2,0x5a,0xd0,0x37,0x07,0x00,0x80,
+0x2e,0x89,0xb2,0x84,0x36,0x84,0x63,0x09,0xe5,0x0a,0xaa,0x87,0x37,0x07,0x00,0x90,
+0x09,0x45,0x37,0x4b,0x04,0xf3,0x63,0x95,0xe7,0x08,0x17,0x0a,0x00,0x00,0x03,0x2a,
+0xea,0x4c,0x83,0x47,0x0a,0x00,0xd9,0xe7,0x97,0x0a,0x00,0x00,0x83,0xaa,0x8a,0x4b,
+0x02,0xc6,0x02,0xc8,0x02,0xca,0x02,0xcc,0x02,0xce,0xd6,0x87,0x13,0x87,0x0a,0x10,
+0x23,0xa0,0x07,0x00,0x91,0x07,0xe3,0x9d,0xe7,0xfe,0xb7,0x07,0x02,0x20,0x03,0xa7,
+0x47,0xf1,0x97,0x05,0x00,0x00,0x83,0xa5,0xa5,0x49,0x5a,0x85,0x18,0x47,0x93,0x89,
+0x07,0xf0,0x02,0x97,0x93,0x57,0x74,0x00,0x89,0x8b,0x17,0x07,0x00,0x00,0x03,0x27,
+0xa7,0x47,0x1c,0xc3,0x83,0xa7,0x49,0x01,0x70,0x00,0x4a,0xc6,0xfc,0x47,0x26,0xc8,
+0x22,0xca,0x97,0x05,0x00,0x00,0x83,0xa5,0xe5,0x45,0x5a,0x85,0x82,0x97,0x09,0xe9,
+0x83,0x47,0x0a,0x00,0x23,0x8a,0x0a,0x02,0x91,0xef,0x85,0x47,0x23,0x00,0xfa,0x00,
+0xf2,0x50,0x62,0x54,0xd2,0x54,0x42,0x59,0xb2,0x59,0x22,0x5a,0x92,0x5a,0x02,0x5b,
+0x21,0x61,0x82,0x80,0x01,0x45,0xed,0xb7,0x37,0x0b,0x04,0xf3,0xb9,0xbf,0x01,0x11,
+0x22,0xcc,0x4a,0xc8,0x06,0xce,0x26,0xca,0x4e,0xc6,0x52,0xc4,0x56,0xc2,0x5a,0xc0,
+0xb7,0x07,0x00,0x80,0x2e,0x89,0x32,0x84,0x63,0x0f,0xf5,0x0c,0xb7,0x07,0x00,0x90,
+0xb7,0x4a,0x04,0xf3,0x63,0x1e,0xf5,0x0a,0x17,0x06,0x00,0x00,0x03,0x26,0x86,0x3f,
+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,0x6b,0x3d,0x83,0x25,0x0b,0x00,0x9c,0x4f,0x52,0x87,0xca,0x86,
+0x56,0x85,0x82,0x97,0x3d,0xed,0xb3,0x89,0x99,0x40,0x4e,0x94,0x52,0x99,0x63,0xf2,
+0x84,0x06,0x17,0x0b,0x00,0x00,0x03,0x2b,0x2b,0x3b,0x37,0x0a,0x02,0x20,0x97,0x09,
+0x00,0x00,0x83,0xa9,0x29,0x3a,0x83,0x27,0x4a,0xf1,0x83,0x25,0x0b,0x00,0xca,0x86,
+0xdc,0x53,0x4e,0x86,0x56,0x85,0x82,0x97,0x05,0x8c,0x21,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,0xa6,0x35,0x05,0x61,
+0x82,0x87,0x01,0x45,0x19,0xc4,0x17,0x0b,0x00,0x00,0x03,0x2b,0xeb,0x34,0xd1,0xb7,
+0x09,0x45,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,0xa6,0x32,0x83,0x54,
+0x86,0x02,0xb7,0x0a,0x04,0xf3,0xaa,0x04,0xe3,0x65,0x94,0xfc,0x3d,0xb7,0x37,0x08,
+0x00,0x80,0x2e,0x87,0xb6,0x87,0x63,0x0b,0x05,0x03,0xb7,0x06,0x00,0x90,0x63,0x15,
+0xd5,0x02,0x37,0x45,0x04,0xf3,0xb7,0x06,0x02,0x20,0x83,0xa6,0x46,0xf1,0x97,0x05,
+0x00,0x00,0x83,0xa5,0x65,0x2f,0x8c,0x41,0x03,0xa8,0x86,0x02,0xb2,0x86,0x17,0x06,
+0x00,0x00,0x03,0x26,0x26,0x2e,0x02,0x88,0x09,0x45,0x82,0x80,0x37,0x05,0x04,0xf3,
+0xd9,0xbf,0xb7,0x08,0x00,0x80,0x2e,0x88,0x32,0x87,0xb6,0x87,0x63,0x0b,0x15,0x03,
+0xb7,0x06,0x00,0x90,0x63,0x15,0xd5,0x02,0x37,0x45,0x04,0xf3,0xb7,0x06,0x02,0x20,
+0x83,0xa6,0x46,0xf1,0x17,0x06,0x00,0x00,0x03,0x26,0x06,0x2b,0x0c,0x42,0x83,0xa8,
+0xc6,0x02,0x17,0x06,0x00,0x00,0x03,0x26,0xe6,0x29,0xc2,0x86,0x82,0x88,0x09,0x45,
+0x82,0x80,0x37,0x05,0x04,0xf3,0xd9,0xbf,0x91,0xcd,0x97,0x07,0x00,0x00,0x83,0xa7,
+0x67,0x28,0x98,0x53,0x83,0xd7,0x67,0x02,0x01,0x45,0x2a,0x07,0xaa,0x07,0x98,0xc1,
+0xdc,0xc1,0x82,0x80,0x09,0x45,0x82,0x80,0xb7,0x07,0x00,0x80,0x63,0x09,0xf5,0x02,
+0xb7,0x07,0x00,0x90,0x63,0x13,0xf5,0x02,0xb7,0x07,0x02,0x20,0x83,0xa7,0x47,0xf1,
+0x17,0x07,0x00,0x00,0x03,0x27,0x47,0x25,0x0c,0x43,0xdc,0x4f,0x37,0x45,0x04,0xf3,
+0x17,0x06,0x00,0x00,0x03,0x26,0x06,0x24,0x82,0x87,0x09,0x45,0x82,0x80,0xb7,0x07,
+0x02,0x20,0x83,0xa7,0x47,0xf1,0x17,0x07,0x00,0x00,0x03,0x27,0xe7,0x22,0x0c,0x43,
+0xdc,0x4f,0x37,0x05,0x04,0xf3,0x17,0x06,0x00,0x00,0x03,0x26,0xa6,0x21,0x82,0x87,
+0x82,0x80,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x1c,0x04,0x00,0x00,0x14,0x04,0x00,0x00,0x18,0x04,0x00,0x00,0x14,0x03,0x00,0x00,
+0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
+
diff --git a/contrib/loaders/flash/hpm_xpi/openocd_algo/CMakeLists.txt \
b/contrib/loaders/flash/hpm_xpi/openocd_algo/CMakeLists.txt new file mode 100644
index 0000000000..f91561d483
--- /dev/null
+++ b/contrib/loaders/flash/hpm_xpi/openocd_algo/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright 2021 hpmicro
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.13)
+
+set(CUSTOM_LINKER_FILE ${CMAKE_CURRENT_SOURCE_DIR}/src/linker.ld)
+set(CUSTOM_STARTUP_FILE ${CMAKE_CURRENT_SOURCE_DIR}/src/func_table.S)
+
+set(CMAKE_BUILD_TYPE RELEASE)
+
+find_package(hpm-sdk REQUIRED HINTS $ENV{HPM_SDK_BASE})
+
+project(openocd_flash_algo_example)
+
+sdk_app_src(src/openocd_flash_algo.c)
+sdk_compile_options(-fpic)
+
+add_custom_command(TARGET app POST_BUILD
+    COMMAND cp ${CMAKE_CURRENT_BINARY_DIR}/output/demo.bin \
                ${CMAKE_CURRENT_SOURCE_DIR}/../hpm_xpi_flash.bin)
diff --git a/contrib/loaders/flash/hpm_xpi/openocd_algo/src/func_table.S \
b/contrib/loaders/flash/hpm_xpi/openocd_algo/src/func_table.S new file mode 100644
index 0000000000..17f10854e7
--- /dev/null
+++ b/contrib/loaders/flash/hpm_xpi/openocd_algo/src/func_table.S
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021 hpmicro
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+  .section .func_table, "ax"
+  .global _init
+_init:
+  jal flash_init
+  ebreak
+  jal flash_erase
+  ebreak
+  jal flash_program
+  ebreak
+  jal flash_read
+  ebreak
+  jal flash_get_info
+  ebreak
+  jal flash_erase_chip
+  ebreak
+  jal flash_deinit
+  ebreak
diff --git a/contrib/loaders/flash/hpm_xpi/openocd_algo/src/linker.ld \
b/contrib/loaders/flash/hpm_xpi/openocd_algo/src/linker.ld new file mode 100644
index 0000000000..bfd28aed5c
--- /dev/null
+++ b/contrib/loaders/flash/hpm_xpi/openocd_algo/src/linker.ld
@@ -0,0 +1,36 @@
+ENTRY(_init)
+
+SECTIONS
+{
+    .text : {
+        *(.func_table)
+        KEEP(*(.flash_algo.text*))
+        KEEP(*(.rodata))
+        KEEP(*(.rodata*))
+        KEEP(*(.flash_algo.data*))
+        *(.text)
+        *(.text*)
+        __etext = .;
+    }
+    .discard : {
+        __noncacheable_start__ = .;
+        __noncacheable_bss_start__ = .;
+        __bss_start__ = .;
+        __bss_end__ = .;
+        __noncacheable_bss_end__ = .;
+        _end = .;
+        __noncacheable_init_start__ = .;
+        __data_start__ = .;
+        __data_end__ = .;
+        __noncacheable_init_end__ = .;
+        __noncacheable_end__ = .;
+        __heap_start__ = .;
+        __heap_end__ = .;
+        __ramfunc_start__ = .;
+        __ramfunc_end__ = .;
+        __noncacheable_bss_start__ = .;
+        __noncacheable_bss_end__ = .;
+        __noncacheable_init_start__ = .;
+        __noncacheable_init_end__ = .;
+    }
+}
diff --git a/contrib/loaders/flash/hpm_xpi/openocd_algo/src/openocd_flash_algo.c \
b/contrib/loaders/flash/hpm_xpi/openocd_algo/src/openocd_flash_algo.c new file mode \
100644 index 0000000000..500d598e94
--- /dev/null
+++ b/contrib/loaders/flash/hpm_xpi/openocd_algo/src/openocd_flash_algo.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2021 hpmicro
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "board.h"
+#include "hpm_common.h"
+#include "hpm_l1c_drv.h"
+#include "hpm_romapi.h"
+
+#define XPI0_MEM_START (0x80000000UL)
+#define XPI1_MEM_START (0x90000000UL)
+#define XPI_USE_PORT_B_MASK (0x100)
+#define XPI_USE_PORT_A_MASK (0)
+#define XPI_USE_PORT_SHIFT (0x8)
+
+typedef struct {
+    uint32_t total_sz_in_bytes;
+    uint32_t sector_sz_in_bytes;
+} hpm_flash_info_t;
+
+__attribute__ ((section(".flash_algo.data"))) xpi_nor_config_t nor_config;
+__attribute__ ((section(".flash_algo.data"))) bool xpi_inited = false;
+__attribute__ ((section(".flash_algo.data"))) uint32_t channel = xpi_channel_a1;
+
+const uint8_t flash_config_dummy[256] = {
+	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
+};
+
+__attribute__ ((section(".flash_algo.text"))) uint32_t flash_init(uint32_t \
flash_base, uint32_t header, uint32_t opt0, uint32_t opt1) +{
+    uint32_t i = 0;
+    XPI_Type *xpi_base;
+    xpi_nor_config_option_t cfg_option;
+    hpm_stat_t stat = status_success;
+
+    if (flash_base == XPI0_MEM_START) {
+        xpi_base = HPM_XPI0;
+    } else if (flash_base == XPI1_MEM_START) {
+        xpi_base = HPM_XPI1;
+    } else {
+        return status_invalid_argument;
+    }
+
+    if (xpi_inited) {
+        return stat;
+    }
+
+    for (i = 0; i < sizeof(cfg_option); i++) {
+        *((uint8_t *)&cfg_option + i) = 0;
+    }
+    for (i = 0; i < sizeof(nor_config); i++) {
+        *((uint8_t *)&nor_config + i) = 0;
+    }
+
+    /* dummy config needs to be done before actual configuration */
+    ROM_API_TABLE_ROOT->xpi_nor_driver_if->init(xpi_base, (xpi_nor_config_t \
*)flash_config_dummy); +
+    cfg_option.header.U = header;
+    cfg_option.option0.U = opt0;
+    cfg_option.option1.U = opt1;
+
+    if (opt1 & XPI_USE_PORT_B_MASK) {
+        channel = xpi_channel_b1;
+    } else {
+        channel = xpi_channel_a1;
+    }
+
+    stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->auto_config(xpi_base, &nor_config, \
&cfg_option); +    if (stat) {
+        return stat;
+    }
+    nor_config.device_info.clk_freq_for_non_read_cmd = 0;
+    if (!xpi_inited) {
+        xpi_inited = true;
+    }
+    return stat;
+}
+
+__attribute__ ((section(".flash_algo.text"))) uint32_t flash_erase(uint32_t \
flash_base, uint32_t address, uint32_t size) +{
+    XPI_Type *xpi_base;
+    hpm_stat_t stat = status_success;
+    uint32_t left, start, block_size, align;
+    if (flash_base == XPI0_MEM_START) {
+        xpi_base = HPM_XPI0;
+    } else if (flash_base == XPI1_MEM_START) {
+        xpi_base = HPM_XPI1;
+    } else {
+        return status_invalid_argument;
+    }
+
+    left = size;
+    start = address;
+    block_size = nor_config.device_info.block_size_kbytes * 1024;
+    if (left >= block_size) {
+        align = block_size - (start % block_size);
+        if (align != block_size) {
+            stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->erase(xpi_base, channel, \
&nor_config, start, align); +            if (stat != status_success) {
+                return stat;
+            }
+            left -= align;
+            start += align;
+        }
+        while (left > block_size) {
+            stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->erase_block(xpi_base, \
channel, &nor_config, start); +            if (stat != status_success) {
+                break;
+            }
+            left -= block_size;
+            start += block_size;
+        }
+    }
+    if ((stat == status_success) && left) {
+        stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->erase(xpi_base, channel, \
&nor_config, start, left); +    }
+    return stat;
+}
+
+__attribute__ ((section(".flash_algo.text"))) uint32_t flash_program(uint32_t \
flash_base, uint32_t address, uint32_t *buf, uint32_t size) +{
+    XPI_Type *xpi_base;
+    hpm_stat_t stat;
+
+    if (flash_base == XPI0_MEM_START) {
+        xpi_base = HPM_XPI0;
+    } else if (flash_base == XPI1_MEM_START) {
+        xpi_base = HPM_XPI1;
+    } else {
+        return status_invalid_argument;
+    }
+
+    stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->program(xpi_base, channel, \
&nor_config, buf, address, size); +    return stat;
+}
+
+__attribute__ ((section(".flash_algo.text"))) uint32_t flash_read(uint32_t \
flash_base, uint32_t *buf, uint32_t address, uint32_t size) +{
+    XPI_Type *xpi_base;
+    hpm_stat_t stat;
+    if (flash_base == XPI0_MEM_START) {
+        xpi_base = HPM_XPI0;
+    } else if (flash_base == XPI1_MEM_START) {
+        xpi_base = HPM_XPI1;
+    } else {
+        return status_invalid_argument;
+    }
+
+    stat = rom_xpi_nor_read(xpi_base, channel, &nor_config, buf, address, size);
+    return stat;
+}
+
+__attribute__ ((section(".flash_algo.text"))) uint32_t flash_get_info(uint32_t \
flash_base, hpm_flash_info_t *flash_info) +{
+    if (!flash_info) {
+        return status_invalid_argument;
+    }
+
+    flash_info->total_sz_in_bytes = nor_config.device_info.size_in_kbytes << 10;
+    flash_info->sector_sz_in_bytes = nor_config.device_info.sector_size_kbytes << \
10; +    return status_success;
+}
+
+__attribute__ ((section(".flash_algo.text"))) uint32_t flash_erase_chip(uint32_t \
flash_base) +{
+    XPI_Type *xpi_base;
+    if (flash_base == XPI0_MEM_START) {
+        xpi_base = HPM_XPI0;
+    } else if (flash_base == XPI1_MEM_START) {
+        xpi_base = HPM_XPI1;
+    } else {
+        return status_invalid_argument;
+    }
+
+    return rom_xpi_nor_erase_chip(xpi_base, channel, &nor_config);
+}
+
+__attribute__ ((section(".flash_algo.text"))) void flash_deinit(void)
+{
+    return;
+}
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(&reg_params[0], "a0", xlen, PARAM_IN_OUT);
+	init_reg_param(&reg_params[1], "a1", xlen, PARAM_OUT);
+	init_reg_param(&reg_params[2], "a2", xlen, PARAM_OUT);
+	init_reg_param(&reg_params[3], "a3", xlen, PARAM_OUT);
+	init_reg_param(&reg_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(&reg_params[0], "a0", xlen, PARAM_IN_OUT);
+	init_reg_param(&reg_params[1], "a1", xlen, PARAM_OUT);
+	init_reg_param(&reg_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(&reg_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(&reg_params[0], "a0", xlen, PARAM_IN_OUT);
+	init_reg_param(&reg_params[1], "a1", xlen, PARAM_OUT);
+	init_reg_param(&reg_params[2], "a2", xlen, PARAM_OUT);
+	init_reg_param(&reg_params[3], "a3", xlen, PARAM_OUT);
+	init_reg_param(&reg_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(&reg_params[0], "a0", xlen, PARAM_IN_OUT);
+	init_reg_param(&reg_params[1], "a1", xlen, PARAM_OUT);
+	init_reg_param(&reg_params[2], "a2", xlen, PARAM_OUT);
+	init_reg_param(&reg_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(&reg_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(&reg_params[0], "a0", xlen, PARAM_IN_OUT);
+	init_reg_param(&reg_params[1], "a1", xlen, PARAM_OUT);
+	init_reg_param(&reg_params[2], "a2", xlen, PARAM_OUT);
+	init_reg_param(&reg_params[3], "a3", xlen, PARAM_OUT);
+	init_reg_param(&reg_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(&reg_params[0], "a0", xlen, PARAM_IN_OUT);
+	init_reg_param(&reg_params[1], "a1", xlen, PARAM_OUT);
+	init_reg_param(&reg_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(&reg_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(&reg_params[0], "a0", xlen, PARAM_IN_OUT);
+	init_reg_param(&reg_params[1], "a1", xlen, PARAM_OUT);
+	init_reg_param(&reg_params[2], "a2", xlen, PARAM_OUT);
+	init_reg_param(&reg_params[3], "a3", xlen, PARAM_OUT);
+	init_reg_param(&reg_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(&reg_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(&reg_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,
+};

-- 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic