From 8e11797618a45a38a951e5482fc7d888edca21f5 Mon Sep 17 00:00:00 2001 From: Ryan QIAN Date: Tue, 7 Jan 2025 15:09:18 +0800 Subject: [PATCH] contrib/loaders/flash/hpmicro: add hpmicro device xpi support - add xpi flash support for hpmicro devices Change-Id: I3531fdf20a34561c6f3fe6ac0b9af988d483aae7 Signed-off-by: Ryan QIAN Reviewed-on: https://review.openocd.org/c/openocd/+/8695 Tested-by: jenkins Reviewed-by: Tomas Vanek --- contrib/loaders/flash/hpmicro/Makefile | 51 +++ contrib/loaders/flash/hpmicro/README | 7 + contrib/loaders/flash/hpmicro/func_table.S | 21 + contrib/loaders/flash/hpmicro/hpm_common.h | 203 +++++++++ contrib/loaders/flash/hpmicro/hpm_romapi.h | 52 +++ .../flash/hpmicro/hpm_romapi_xpi_def.h | 254 +++++++++++ .../flash/hpmicro/hpm_romapi_xpi_nor_def.h | 426 ++++++++++++++++++ .../flash/hpmicro/hpm_romapi_xpi_soc_def.h | 69 +++ contrib/loaders/flash/hpmicro/hpm_xpi_flash.h | 17 + .../loaders/flash/hpmicro/hpm_xpi_flash.inc | 72 +++ contrib/loaders/flash/hpmicro/linker.ld | 48 ++ .../flash/hpmicro/openocd_flash_algo.c | 154 +++++++ 12 files changed, 1374 insertions(+) create mode 100644 contrib/loaders/flash/hpmicro/Makefile create mode 100644 contrib/loaders/flash/hpmicro/README create mode 100644 contrib/loaders/flash/hpmicro/func_table.S create mode 100644 contrib/loaders/flash/hpmicro/hpm_common.h create mode 100644 contrib/loaders/flash/hpmicro/hpm_romapi.h create mode 100644 contrib/loaders/flash/hpmicro/hpm_romapi_xpi_def.h create mode 100644 contrib/loaders/flash/hpmicro/hpm_romapi_xpi_nor_def.h create mode 100644 contrib/loaders/flash/hpmicro/hpm_romapi_xpi_soc_def.h create mode 100644 contrib/loaders/flash/hpmicro/hpm_xpi_flash.h create mode 100644 contrib/loaders/flash/hpmicro/hpm_xpi_flash.inc create mode 100644 contrib/loaders/flash/hpmicro/linker.ld create mode 100644 contrib/loaders/flash/hpmicro/openocd_flash_algo.c diff --git a/contrib/loaders/flash/hpmicro/Makefile b/contrib/loaders/flash/hpmicro/Makefile new file mode 100644 index 000000000..304363171 --- /dev/null +++ b/contrib/loaders/flash/hpmicro/Makefile @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2023 HPMicro +# +BIN2C = ../../../../src/helper/bin2char.sh + + +PROJECT=hpm_xpi_flash +CROSS_COMPILE ?= riscv32-unknown-elf- +CC=$(CROSS_COMPILE)gcc +AS=$(CROSS_COMPILE)gcc +OBJCOPY=$(CROSS_COMPILE)objcopy +OBJDUMP=$(CROSS_COMPILE)objdump +LD=$(CROSS_COMPILE)ld +LDSCRIPT=linker.ld + +OPT=-O3 + +ASFLAGS= +CFLAGS=$(OPT) -fomit-frame-pointer -Wall +LDFLAGS=-nostartfiles -T$(LDSCRIPT) -Wl,-Map=$(PROJECT).map -static -Wl,--gc-sections +OBJS=$(ASRC:.S=.o) $(SRC:.c=.o) + +SRC=openocd_flash_algo.c +ASRC=func_table.S + +all: $(OBJS) $(PROJECT).elf $(PROJECT).bin $(PROJECT).lst $(PROJECT).inc + +%o: %c + @$(CC) -c $(CFLAGS) -I . $< -o $@ + +%o: %S + @$(AS) -c $(ASFLAGS) -I . $< -o $@ + +%elf: $(OBJS) + @$(CC) $(OBJS) $(LDFLAGS) -o $@ + +%lst: %elf + @$(OBJDUMP) -h -S $< > $@ + +%bin: %elf + @$(OBJCOPY) -Obinary $< $@ + +%inc: %bin + $(BIN2C) < $< > $@ + +clean: + @-rm -f *.o *.elf *.lst *.bin *.inc + +.PHONY: all clean + +.INTERMEDIATE: $(patsubst %.S,%.o,$(SRCS)) $(patsubst %.S,%.elf,$(SRCS)) $(patsubst %.S,%.bin,$(SRCS)) diff --git a/contrib/loaders/flash/hpmicro/README b/contrib/loaders/flash/hpmicro/README new file mode 100644 index 000000000..a6c047a11 --- /dev/null +++ b/contrib/loaders/flash/hpmicro/README @@ -0,0 +1,7 @@ +The loader relies on the romapi provided by HPMicro devices. + +- hpm_common.h and all the hpm_romapi_*.c/h are reused from hpm_sdk +(v1.9.0 https://github.com/hpmicro/hpm_sdk/releases). + +Due to different coding rules, these source code needs to be updated +accordingly to pass the coding rule check for openocd. diff --git a/contrib/loaders/flash/hpmicro/func_table.S b/contrib/loaders/flash/hpmicro/func_table.S new file mode 100644 index 000000000..d5f34265e --- /dev/null +++ b/contrib/loaders/flash/hpmicro/func_table.S @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2021 HPMicro + */ + .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/hpmicro/hpm_common.h b/contrib/loaders/flash/hpmicro/hpm_common.h new file mode 100644 index 000000000..8190fbfed --- /dev/null +++ b/contrib/loaders/flash/hpmicro/hpm_common.h @@ -0,0 +1,203 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Copyright (c) 2021-2023 HPMicro + */ + +#ifndef _HPM_COMMON_H +#define _HPM_COMMON_H + +#include +#include +#include +#include +#include + +/** + * + * @brief COMMON driver APIs + * @defgroup common_interface COMMON driver APIs + * @{ + * + */ + +#define __R volatile const /* Define "read-only" permission */ +#define __RW volatile /* Define "read-write" permission */ +#define __W volatile /* Define "write-only" permission */ + +#ifndef __I +#define __I __R +#endif + +#ifndef __IO +#define __IO __RW +#endif + +#ifndef __O +#define __O __W +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif + +#define HPM_BITSMASK(val, offset) ((uint32_t)(val) << (offset)) +#define IS_HPM_BITMASK_SET(val, mask) (((uint32_t)(val) & (uint32_t)(mask)) != 0U) +#define IS_HPM_BIT_SET(val, offset) (((uint32_t)(val) & (1UL << (offset))) != 0U) +#define IS_HPM_BITMASK_CLR(val, mask) (((uint32_t)(val) & (uint32_t)(mask)) == 0U) +#define IS_HPM_BIT_CLR(val, offset) (((uint32_t)(val) & (1UL << (offset))) == 0U) + +#define HPM_BREAK_IF(cond) do {if (cond) break; } while (0) +#define HPM_CONTINUE_IF(cond) do {if (cond) continue; } while (0) + +#define HPM_CHECK_RET(x) \ + do { \ + stat = (x); \ + if (status_success != stat) { \ + return stat; \ + } \ + } while (false) + +#define SIZE_1KB (1024UL) +#define SIZE_1MB (1048576UL) + +typedef uint32_t hpm_stat_t; + +/* @brief Enum definition for the Status group + * Rule: + * [Group] 0-999 for the SoC driver and the corresponding components + * 1000 or above for the application status group + * [Code] Valid value: 0-999 + * + */ +#define MAKE_STATUS(group, code) ((uint32_t)(group) * 1000U + (uint32_t)(code)) +/* @brief System status group definitions */ +enum { + status_group_common = 0, + status_group_uart = 1, + status_group_i2c = 2, + status_group_spi = 3, + status_group_usb = 4, + status_group_i2s = 5, + status_group_xpi = 6, + status_group_l1c, + status_group_dma, + status_group_femc, + status_group_sdp, + status_group_xpi_nor, + status_group_otp, + status_group_lcdc, + status_group_mbx, + status_group_rng, + status_group_pdma, + status_group_wdg, + status_group_pmic_sec, + status_group_can, + status_group_sdxc, + status_group_pcfg, + status_group_clk, + status_group_pllctl, + status_group_pllctlv2, + status_group_ffa, + status_group_mcan, + + status_group_middleware_start = 500, + status_group_sdmmc = status_group_middleware_start, + status_group_audio_codec, + status_group_dma_manager, +}; + +/* @brief Common status code definitions */ +enum { + status_success = MAKE_STATUS(status_group_common, 0), + status_fail = MAKE_STATUS(status_group_common, 1), + status_invalid_argument = MAKE_STATUS(status_group_common, 2), + status_timeout = MAKE_STATUS(status_group_common, 3), +}; + +#if defined(__GNUC__) + +/* alway_inline */ +#define ATTR_ALWAYS_INLINE __attribute__((always_inline)) + +/* weak */ +#define ATTR_WEAK __attribute__((weak)) + +/* alignment */ +#define ATTR_ALIGN(alignment) __attribute__((aligned(alignment))) + +/* place var_declare at section_name, e.x. PLACE_AT(".target_section", var); */ +#define ATTR_PLACE_AT(section_name) __attribute__((section(section_name))) + +#define ATTR_PLACE_AT_WITH_ALIGNMENT(section_name, alignment) \ +ATTR_PLACE_AT(section_name) ATTR_ALIGN(alignment) + +#define ATTR_PLACE_AT_NONCACHEABLE ATTR_PLACE_AT(".noncacheable.bss") +#define ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(alignment) \ + ATTR_PLACE_AT_NONCACHEABLE ATTR_ALIGN(alignment) + +#define ATTR_PLACE_AT_NONCACHEABLE_BSS ATTR_PLACE_AT(".noncacheable.bss") +#define ATTR_PLACE_AT_NONCACHEABLE_BSS_WITH_ALIGNMENT(alignment) \ + ATTR_PLACE_AT_NONCACHEABLE_BSS ATTR_ALIGN(alignment) + +/* initialize variable x with y using PLACE_AT_NONCACHEABLE_INIT(x) = {y}; */ +#define ATTR_PLACE_AT_NONCACHEABLE_INIT ATTR_PLACE_AT(".noncacheable.init") +#define ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(alignment) \ + ATTR_PLACE_AT_NONCACHEABLE_INIT ATTR_ALIGN(alignment) + +#define ATTR_RAMFUNC ATTR_PLACE_AT(".fast") +#define ATTR_RAMFUNC_WITH_ALIGNMENT(alignment) \ + ATTR_RAMFUNC ATTR_ALIGN(alignment) + +#define ATTR_SHARE_MEM ATTR_PLACE_AT(".sh_mem") + +#define NOP() __asm volatile("nop") +#define WFI() __asm volatile("wfi") + +#define HPM_ATTR_MACHINE_INTERRUPT __attribute__ ((section(".isr_vector"), interrupt("machine"), aligned(4))) + +#elif defined(__ICCRISCV__) + +/* alway_inline */ +#define ATTR_ALWAYS_INLINE __attribute__((always_inline)) + +/* weak */ +#define ATTR_WEAK __weak + +/* alignment */ +#define ATTR_ALIGN(alignment) __attribute__((aligned(alignment))) + +/* place var_declare at section_name, e.x. PLACE_AT(".target_section", var); */ +#define ATTR_PLACE_AT(section_name) __attribute__((section(section_name))) + +#define ATTR_PLACE_AT_WITH_ALIGNMENT(section_name, alignment) \ +ATTR_PLACE_AT(section_name) ATTR_ALIGN(alignment) + +#define ATTR_PLACE_AT_NONCACHEABLE ATTR_PLACE_AT(".noncacheable.bss") +#define ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(alignment) \ + ATTR_PLACE_AT_NONCACHEABLE ATTR_ALIGN(alignment) + +#define ATTR_PLACE_AT_NONCACHEABLE_BSS ATTR_PLACE_AT(".noncacheable.bss") +#define ATTR_PLACE_AT_NONCACHEABLE_BSS_WITH_ALIGNMENT(alignment) \ + ATTR_PLACE_AT_NONCACHEABLE_BSS ATTR_ALIGN(alignment) + +/* initialize variable x with y using PLACE_AT_NONCACHEABLE_INIT(x) = {y}; */ +#define ATTR_PLACE_AT_NONCACHEABLE_INIT ATTR_PLACE_AT(".noncacheable.init") +#define ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(alignment) \ + ATTR_PLACE_AT_NONCACHEABLE_INIT ATTR_ALIGN(alignment) + +#define ATTR_RAMFUNC ATTR_PLACE_AT(".fast") +#define ATTR_RAMFUNC_WITH_ALIGNMENT(alignment) \ + ATTR_RAMFUNC ATTR_ALIGN(alignment) + +#define ATTR_SHARE_MEM ATTR_PLACE_AT(".sh_mem") + +#define NOP() __asm volatile("nop") +#define WFI() __asm volatile("wfi") + +#define HPM_ATTR_MACHINE_INTERRUPT __machine __interrupt + +#else +#error Unknown toolchain +#endif +#endif /* _HPM_COMMON_H */ diff --git a/contrib/loaders/flash/hpmicro/hpm_romapi.h b/contrib/loaders/flash/hpmicro/hpm_romapi.h new file mode 100644 index 000000000..d19f55199 --- /dev/null +++ b/contrib/loaders/flash/hpmicro/hpm_romapi.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Copyright (c) 2021-2023 HPMicro + */ + +#ifndef HPM_ROMAPI_H +#define HPM_ROMAPI_H + +/** + * @brief ROM APIs + * @defgroup romapi_interface ROM APIs + * @{ + */ + +#include "hpm_common.h" +#include "hpm_romapi_xpi_def.h" +#include "hpm_romapi_xpi_soc_def.h" +#include "hpm_romapi_xpi_nor_def.h" + +/*********************************************************************************************************************** + * + * + * Definitions + * + * + **********************************************************************************************************************/ + +/** + * @brief Bootloader API table + */ +struct bootloader_api_table_t { + /**< Bootloader API table: version */ + const uint32_t version; + /**< Bootloader API table: copyright string address */ + const char *copyright; + /**< Bootloader API table: run_bootloader API */ + const uint32_t reserved0; + /**< Bootloader API table: otp driver interface address */ + const uint32_t reserved1; + /**< Bootloader API table: xpi driver interface address */ + const struct xpi_driver_interface_t *xpi_driver_if; + /**< Bootloader API table: xpi nor driver interface address */ + const struct xpi_nor_driver_interface_t *xpi_nor_driver_if; + /**< Bootloader API table: xpi ram driver interface address */ + const uint32_t reserved2; +}; + +/**< Bootloader API table Root */ +#define ROM_API_TABLE_ROOT ((const struct bootloader_api_table_t *)0x2001FF00U) + +#endif /* HPM_ROMAPI_H */ diff --git a/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_def.h b/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_def.h new file mode 100644 index 000000000..b4d73bd10 --- /dev/null +++ b/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_def.h @@ -0,0 +1,254 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Copyright (c) 2021 HPMicro + */ +#ifndef HPM_ROMAPI_XPI_DEF_H +#define HPM_ROMAPI_XPI_DEF_H + +/** + * @brief XPI ROM APIs + * @defgroup xpi_interface XPI driver APIs + * @{ + */ + +#include "hpm_common.h" + +/** + * @brief XPI Read Sample Clock source options + */ +enum xpi_rxclksrc_type_t { + xpi_rxclksrc_internal_loopback = 0, /**< Internal loopback */ + xpi_rxclksrc_dqs_loopback = 1, /**< Loopback from DQS pad */ + xpi_rxclksrc_external_dqs = 3, /**< Read is driven by External DQS pad */ +}; + +/** + * @brief XPI pad definitions + */ +#define XPI_1PAD (0U) /**< Single pad */ +#define XPI_2PADS (1U) /**< Dual pads */ +#define XPI_4PADS (2U) /**< Quad pads */ +#define XPI_8PADS (3U) /**< Octal pads */ + +/** + * @brief XPI IO pin group options + */ +enum xpi_io_group_t { + xpi_io_1st_group, /**< First/Primary group */ + xpi_io_2nd_group, /**< Second/Secondary group */ +}; + +/** + * @brief XPI Transfer Channel type definitions + */ +enum xpi_xfer_channel_t { + xpi_xfer_channel_a1, /**< The address is based on the device connected to Channel A1 */ + xpi_xfer_channel_a2, /**< The address is based on the device connected to Channel A2 */ + xpi_xfer_channel_b1, /**< The address is based on the device connected to Channel B1 */ + xpi_xfer_channel_b2, /**< The address is based on the device connected to Channel B2 */ + xpi_xfer_channel_auto, /**< The channel is auto determined */ +}; + +/** + * @brief XPI Channel definitions + */ +enum xpi_channel_t { + xpi_channel_a1, /**< Port: Channel A1 */ + xpi_channel_a2, /**< Port: Channel A2 */ + xpi_channel_b1, /**< Port: Channel B1 */ + xpi_channel_b2, /**< Port: Channel B2 */ +}; + +/** + * @brief XPI APB Transfer type + */ +enum xpi_apb_xfer_type_t { + xpi_apb_xfer_type_cmd, /**< APB Command Type: Command only */ + xpi_apb_xfer_type_config, /**< APB Command Type: Configuration */ + xpi_apb_xfer_type_read, /**< APB Command Type: Read */ + xpi_apb_xfer_type_write, /**< APB Command Type: Write */ +}; + +/** + * @brief XPI Xfer Mode + */ +enum xpi_xfer_mode_t { + xpi_xfer_mode_polling, /**< Transfer mode: Polling */ + xpi_xfer_mode_dma, /**< Transfer mode: DMA */ + xpi_xfer_mode_interrupt, /**< Transfer mode: Interrupt */ +}; + +/** + * @brief XPI Xfer context + */ +struct xpi_xfer_ctx_t { + uint32_t addr; /**< device address for XPI transfer */ + uint8_t channel; /**< channel for XPI transfer */ + uint8_t cmd_type; /**< command type for XPI transfer */ + uint8_t seq_idx; /**< Sequence index for XPI transfer */ + uint8_t seq_num; /**< Sequence number for XPI transfer */ + uint32_t *buf; /**< Buffer for XPI transfer */ + uint32_t xfer_size; /**< Transfer size in bytes */ +}; + +/** + * @brief XPI instruction sequence + */ +struct xpi_instr_seq_t { + uint32_t entry[4]; +}; + +/** + * @brief XPI Phase definitions + */ +#define XPI_PHASE_STOP (0x00U) /**< Phase: Stop */ +#define XPI_PHASE_CMD_SDR (0x01U) /**< Phase: Send CMD in SDR mode */ +#define XPI_PHASE_RADDR_SDR (0x02U) /**< Phase: Send Row Address in SDR Mode */ +#define XPI_PHASE_CADDR_SDR (0x03U) /**< Phase: Send Column Address in SDR Mode */ +#define XPI_PHASE_MODE4_SDR (0x06U) /**< Phase: Send Mode 4 in SDR Mode */ +#define XPI_PHASE_MODE8_SDR (0x07U) /**< Phase: Send Mode 8 in SDR Mode */ +#define XPI_PHASE_WRITE_SDR (0x08U) /**< Phase: Write data in SDR Mode */ +#define XPI_PHASE_READ_SDR (0x09U) /**< Phase: Read data in SDR Mode */ +#define XPI_PHASE_DUMMY_SDR (0X0CU) /**< Phase: Send Dummy in SDR Mode */ +#define XPI_PHASE_DUMMY_RWDS_SDR (0x0DU) /**< Phase: Send Dummy RWDS in SDR Mode */ + +#define XPI_PHASE_CMD_DDR (0x21U) /**< Phase: Send CMD in DDR Mode */ +#define XPI_PHASE_RADDR_DDR (0x22U) /**< Phase: Send Raw Address in DDR Mode */ +#define XPI_PHASE_CADDR_DDR (0x23U) /**< Phase: Send Column address in DDR Mode */ +#define XPI_PHASE_MODE4_DDR (0x26U) /**< Phase: Send Mode 4 in DDR Mode */ +#define XPI_PHASE_MODE8_DDR (0x27U) /**< Phase: Send Mode 8 in DDR Mode */ +#define XPI_PHASE_WRITE_DDR (0x28U) /**< Phase: Write data in DDR Mode */ +#define XPI_PHASE_READ_DDR (0x29U) /**< Phase: Read data in SDR Mode */ +#define XPI_PHASE_DUMMY_DDR (0x2CU) /**< Phase: Send DUMMY in DDR Mode */ +#define XPI_PHASE_DUMMY_RWDS_DDR (0x2DU) /**< Phase: Send DUMMY RWDS in DDR Mode */ + +/** + * @brief XPI API command error codes + */ +enum { + status_xpi_apb_jump_on_cs = MAKE_STATUS(status_group_xpi, 1), + status_xpi_apb_unknown_inst = MAKE_STATUS(status_group_xpi, 2), + status_xpi_apb_dummy_sdr_in_ddr_seq = MAKE_STATUS(status_group_xpi, 3), + status_xpi_apb_dummy_ddr_in_sdr_seq = MAKE_STATUS(status_group_xpi, 4), + status_xpi_apb_exceed_addr_range = MAKE_STATUS(status_group_xpi, 5), + status_xpi_apb_seq_timeout = MAKE_STATUS(status_group_xpi, 6), + status_xpi_apb_cross_boundary = MAKE_STATUS(status_group_xpi, 7), +}; + +/** + * @brief Delay line definitions + */ +enum { + xpi_dll_half_cycle = 0xFU, + xpi_dll_quarter_cycle = 0x7U, + xpi_dll_sdr_default_cycle = xpi_dll_half_cycle, + xpi_dll_ddr_default_cycle = xpi_dll_quarter_cycle, +}; + +/** + * @brief XPI configuration structure + */ +struct xpi_config_t { + uint8_t rxclk_src; /**< Read sample clock source */ + uint8_t reserved0[7]; /**< Reserved */ + uint8_t tx_watermark_in_dwords; /**< Tx watermark in double words */ + uint8_t rx_watermark_in_dwords; /**< Rx watermark in double words */ + uint8_t enable_differential_clk; /**< Enable differential clock */ + uint8_t reserved1[5]; /**< Reserved */ + uint32_t access_flags; /**< Access flags */ +}; + +/** + * @brief XPI Device Configuration structure + */ +struct xpi_device_config_t { + uint32_t size_in_kbytes; /**< Device size in kbytes */ + uint32_t serial_root_clk_freq; /**< XPI serial root clock frequency */ + + uint8_t enable_write_mask; /**< Enable write mask, typically for PSRAM/HyperRAM */ + uint8_t data_valid_time; /**< Data valid time, Unit 0.1ns */ + uint8_t reserved0[2]; + + uint8_t cs_hold_time; /**< CS hold time, cycles in terms of FLASH clock */ + uint8_t cs_setup_time; /**< CS setup time, cycles in terms of FLASH clock */ + uint16_t cs_interval; /**< CS interval, cycles in terms of FLASH clock */ + + uint8_t reserved1; + uint8_t column_addr_size; /**< Column address bits */ + uint8_t enable_word_address; /**< Enable word address, for HyperFLASH/HyperRAM */ + uint8_t dly_target; /**< Delay target */ + + uint8_t ahb_write_seq_idx; /**< AHB write sequence index */ + uint8_t ahb_write_seq_num; /**< AHB write sequence number */ + uint8_t ahb_read_seq_idx; /**< AHB read sequence index */ + uint8_t ahb_read_seq_num; /**< AHB read sequence number */ + + uint8_t ahb_write_wait_interval; /**< AHB write wait interval, in terms of FLASH clock */ + uint8_t reserved2[3]; +}; + +/** + * @brief SUB Instruction + * @param [in] phase Name + * @param [in] pad Pad for Phase + * @param [in] op Operand for Phase + */ +#define SUB_INSTR(phase, pad, op) ((uint32_t)(((uint16_t)(phase) << 10) | ((uint16_t)(pad) << 8) | ((uint16_t)(op)))) +/** + * @brief Generate a single word INSTRUCTION sequence word + * @note Here intentionally use the MACRO because when the arguments are constant value, the compiler + * can generate the const entry word during pre-processing + */ +#define XPI_INSTR_SEQ(phase0, pad0, op0, phase1, pad1, op1) \ + (SUB_INSTR(phase0, pad0, op0) | (SUB_INSTR(phase1, pad1, op1) << 16)) + +struct xpi_ahb_buffer_cfg_t { + struct { + uint8_t priority; /* Offset: 0x00 */ + uint8_t master_idx; /* Offset: 0x01 */ + uint8_t buf_size_in_dword; /* Offset: 0x02 */ + bool enable_prefetch; /* Offset: 0x03 */ + } entry[8]; +}; + +/** + * @brief XPI driver interface + */ +struct xpi_driver_interface_t { + /**< XPI driver interface: version */ + uint32_t version; + /**< XPI driver interface: get default configuration */ + hpm_stat_t (*get_default_config)(struct xpi_config_t *xpi_config); + /**< XPI driver interface: get default device configuration */ + hpm_stat_t (*get_default_device_config)(struct xpi_device_config_t *dev_config); + /**< XPI driver interface: initialize the XPI using xpi_config */ + hpm_stat_t (*init)(uint32_t *base, struct xpi_config_t *xpi_config); + /**< XPI driver interface: configure the AHB buffer */ + hpm_stat_t (*config_ahb_buffer)(uint32_t *base, struct xpi_ahb_buffer_cfg_t *ahb_buf_cfg); + /**< XPI driver interface: configure the device */ + hpm_stat_t (*config_device)(uint32_t *base, struct xpi_device_config_t *dev_cfg, enum xpi_channel_t channel); + /**< XPI driver interface: update instruction talbe */ + hpm_stat_t (*update_instr_table)(uint32_t *base, const uint32_t *inst_base, uint32_t seq_idx, uint32_t num); + /**< XPI driver interface: transfer command/data using block interface */ + hpm_stat_t (*transfer_blocking)(uint32_t *base, struct xpi_xfer_ctx_t *xfer); + /**< Software reset the XPI controller */ + void (*software_reset)(uint32_t *base); + /**< XPI driver interface: Check whether IP is idle */ + bool (*is_idle)(uint32_t *base); + /**< XPI driver interface: update delay line setting */ + void (*update_dllcr)(uint32_t *base, + uint32_t serial_root_clk_freq, + uint32_t data_valid_time, + enum xpi_channel_t channel, + uint32_t dly_target); + /**< XPI driver interface: Get absolute address for APB transfer */ + hpm_stat_t + (*get_abs_apb_xfer_addr)(uint32_t *base, enum xpi_xfer_channel_t channel, uint32_t in_addr, uint32_t *out_addr); +}; + +/** + * @} + */ + +#endif /* HPM_ROMAPI_XPI_DEF_H */ diff --git a/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_nor_def.h b/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_nor_def.h new file mode 100644 index 000000000..edde8402f --- /dev/null +++ b/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_nor_def.h @@ -0,0 +1,426 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Copyright (c) 2021 HPMicro + */ +#ifndef HPM_ROMAPI_XPI_NOR_DEF_H +#define HPM_ROMAPI_XPI_NOR_DEF_H + +/** + * @brief XPI NOR ROM APIs + * @defgroup xpi_nor_interface XPI NOR driver APIs + * @ingroup romapi_interfaces + * @{ + */ + +#include "hpm_common.h" +#include "hpm_romapi_xpi_def.h" + +#define XPI_NOR_CFG_TAG 0x524f4E58U /**< ASCII: "XNOR" */ + +/** + * @brief XPI NOR properties + */ +enum { + xpi_nor_property_total_size, /**< Total size in bytes */ + xpi_nor_property_page_size, /**< Page size in bytes */ + xpi_nor_property_sector_size, /**xpi_nor_driver_if->version >= 0x56010300) + +struct hpm_flash_info_t { + uint32_t total_sz_in_bytes; + uint32_t sector_sz_in_bytes; +}; + +__attribute__ ((section(".flash_algo.data"))) struct 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; +__attribute__ ((section(".flash_algo.data"))) uint32_t *xpi_base; + +__attribute__ ((section(".flash_algo.text"))) void refresh_device_size(uint32_t *base, + struct xpi_nor_config_option_t *option) +{ + volatile uint32_t *dev_size = (volatile uint32_t *)((uint32_t)base + 0x60); + bool enable_channelb = false; + if (option->header.words > 1) + enable_channelb = option->option1.connection_sel == xpi_nor_connection_sel_chnb_cs0; + if (enable_channelb) { + dev_size[0] = 0; + dev_size[1] = 0; + } +} + +__attribute__ ((section(".flash_algo.text"))) uint32_t flash_init(uint32_t flash_base, uint32_t header, + uint32_t opt0, uint32_t opt1, uint32_t xpi_base_addr) +{ + uint32_t i = 0; + struct xpi_nor_config_option_t cfg_option; + hpm_stat_t stat = status_success; + + xpi_base = (uint32_t *)xpi_base_addr; + if (xpi_inited) + return stat; + + __asm volatile("csrc %0, %1" : : "i"(CSR_MCACHE_CTL), "r"(HPM_MCACHE_CTL_DC_EN_MASK)); + 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; + + 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; + + if (ROMAPI_SUPPORTS_HYBRIDXPI()) + ROM_API_TABLE_ROOT->xpi_nor_driver_if->enable_hybrid_xpi(xpi_base); + + refresh_device_size(xpi_base, &cfg_option); + + 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) +{ + hpm_stat_t stat = status_success; + uint32_t left, start, block_size, align; + + left = size; + start = address; + if (ROMAPI_SUPPORTS_HYBRIDXPI()) + start += flash_base; + 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) +{ + hpm_stat_t stat; + + if (ROMAPI_SUPPORTS_HYBRIDXPI()) + address += flash_base; + 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) +{ + hpm_stat_t stat; + + if (ROMAPI_SUPPORTS_HYBRIDXPI()) + address += flash_base; + stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->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, + struct 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) +{ + return ROM_API_TABLE_ROOT->xpi_nor_driver_if->erase_chip(xpi_base, channel, &nor_config); +} + +__attribute__ ((section(".flash_algo.text"))) void flash_deinit(void) +{ +}