aboutsummaryrefslogtreecommitdiff
path: root/platform/ext/target
diff options
context:
space:
mode:
authorSatish Kumar <satish.kumar01@arm.com>2021-05-04 17:46:26 +0100
committerAnton Komlev <Anton.Komlev@arm.com>2021-08-04 18:20:13 +0200
commit7f4eeb3e63ca37894043d555018c4c7fd5717dd2 (patch)
treed71ec172c68db1a0e5819a2f03b4cb59301713ec /platform/ext/target
parente87f1103967e68b8ce9df098e955588ef68ea00a (diff)
downloadtrusted-firmware-m-7f4eeb3e63ca37894043d555018c4c7fd5717dd2.tar.gz
Diphda: Implement and integrate drivers for PMOD SF3 external memory.
This commit implements drivers to access PMOD SF3 based external flash memory. The PMOD SF3 contains Micron's 32 MB Nor flash memory (N25Q256A). The FPGA uses Xilinx QSPI controller for the communication with the module. The commit provides native drivers for both, N25Q256A memory and QSPI controller. The CMSIS Driver for these native dirvers is also part of this commit. Change-Id: Iadde800a42f35d8cc128018c622950c1cfe4e99d Signed-off-by: Satish Kumar <satish.kumar01@arm.com>
Diffstat (limited to 'platform/ext/target')
-rwxr-xr-xplatform/ext/target/arm/diphda/CMSIS_Driver/Config/RTE_Device.h5
-rw-r--r--platform/ext/target/arm/diphda/CMSIS_Driver/Config/cmsis_driver_config.h3
-rw-r--r--platform/ext/target/arm/diphda/CMSIS_Driver/Driver_Flash.c302
-rw-r--r--platform/ext/target/arm/diphda/CMakeLists.txt4
-rw-r--r--platform/ext/target/arm/diphda/Device/Config/device_cfg.h6
-rw-r--r--platform/ext/target/arm/diphda/Device/Include/device_definition.h12
-rw-r--r--platform/ext/target/arm/diphda/Device/Include/platform_base_address.h2
-rw-r--r--platform/ext/target/arm/diphda/Device/Source/device_definition.c25
-rw-r--r--platform/ext/target/arm/diphda/Native_Driver/spi_flash_commands.h28
-rw-r--r--platform/ext/target/arm/diphda/Native_Driver/spi_n25q256a_flash_lib.c441
-rw-r--r--platform/ext/target/arm/diphda/Native_Driver/spi_n25q256a_flash_lib.h59
-rw-r--r--platform/ext/target/arm/diphda/Native_Driver/xilinx_pg153_axi_qspi_controller_drv.c183
-rw-r--r--platform/ext/target/arm/diphda/Native_Driver/xilinx_pg153_axi_qspi_controller_drv.h79
-rw-r--r--platform/ext/target/arm/diphda/bl1/CMakeLists.txt2
-rw-r--r--platform/ext/target/arm/diphda/bl1/bl1_boot_hal.c46
-rw-r--r--platform/ext/target/arm/diphda/partition/flash_layout.h26
-rw-r--r--platform/ext/target/arm/diphda/spm_hal.c9
17 files changed, 983 insertions, 249 deletions
diff --git a/platform/ext/target/arm/diphda/CMSIS_Driver/Config/RTE_Device.h b/platform/ext/target/arm/diphda/CMSIS_Driver/Config/RTE_Device.h
index 1366d2480b..571d342fba 100755
--- a/platform/ext/target/arm/diphda/CMSIS_Driver/Config/RTE_Device.h
+++ b/platform/ext/target/arm/diphda/CMSIS_Driver/Config/RTE_Device.h
@@ -29,9 +29,4 @@
#define RTE_FLASH0 1
// </e> FLASH (Flash Memory) [Driver_FLASH0]
-// <e> FLASH (Flash Memory) [Driver_FLASH1]
-// <i> Configuration settings for Driver_FLASH1 in component ::Drivers:FLASH
-#define RTE_FLASH1 1
-// </e> FLASH (Flash Memory) [Driver_FLASH1]
-
#endif /* __RTE_DEVICE_H */
diff --git a/platform/ext/target/arm/diphda/CMSIS_Driver/Config/cmsis_driver_config.h b/platform/ext/target/arm/diphda/CMSIS_Driver/Config/cmsis_driver_config.h
index b066b21ed4..f8b0708649 100644
--- a/platform/ext/target/arm/diphda/CMSIS_Driver/Config/cmsis_driver_config.h
+++ b/platform/ext/target/arm/diphda/CMSIS_Driver/Config/cmsis_driver_config.h
@@ -24,4 +24,7 @@
#define UART0_DEV UART0_PL011_DEV
+/* Externally attached PMOD SF3 Nor Flash Device to the MPS3 Board. */
+#define FLASH0_DEV SPI_N25Q256A_DEV
+
#endif /* __CMSIS_DRIVER_CONFIG_H__ */
diff --git a/platform/ext/target/arm/diphda/CMSIS_Driver/Driver_Flash.c b/platform/ext/target/arm/diphda/CMSIS_Driver/Driver_Flash.c
index 50c93f883a..8f7c4a9676 100644
--- a/platform/ext/target/arm/diphda/CMSIS_Driver/Driver_Flash.c
+++ b/platform/ext/target/arm/diphda/CMSIS_Driver/Driver_Flash.c
@@ -22,29 +22,21 @@
#include "RTE_Device.h"
#include "platform_base_address.h"
#include "flash_layout.h"
+#include "cmsis_driver_config.h"
#ifndef ARG_UNUSED
#define ARG_UNUSED(arg) ((void)arg)
#endif
-#define FLASH0_BASE FLASH_BASE_ADDRESS
-#define FLASH0_SIZE 0x02000000 /* 32 MB */
-#define FLASH0_SECTOR_SIZE 0x00001000 /* 4 kB */
-#define FLASH0_PAGE_SIZE 256
-#define FLASH0_PROGRAM_UNIT 1 /* Minimum write size */
-
-#define FLASH1_BASE (SRAM_BASE + SRAM_SIZE)
-#define FLASH1_SIZE 0x00009000 /* 36 KiB */
-#define FLASH1_SECTOR_SIZE 0x00000400 /* 1 kB */
-#define FLASH1_PAGE_SIZE 256
-#define FLASH1_PROGRAM_UNIT 1 /* Minimum write size */
-
/* Driver version */
#define ARM_FLASH_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1, 1)
#define ARM_FLASH_DRV_ERASE_VALUE 0xFF
+/*
+ * ARM FLASH device structure
+ */
struct arm_flash_dev_t {
- const uint32_t memory_base; /*!< FLASH memory base address */
+ struct spi_n25q256a_dev_t *dev; /*!< FLASH memory device structure */
ARM_FLASH_INFO *data; /*!< FLASH data */
};
@@ -58,64 +50,12 @@ static const ARM_DRIVER_VERSION DriverVersion = {
};
/* Driver Capabilities */
-static const ARM_FLASH_CAPABILITIES DriverCapabilities = {
+static const ARM_FLASH_CAPABILITIES N25Q256ADriverCapabilities = {
0, /* event_ready */
- 2, /* data_width = 0:8-bit, 1:16-bit, 2:32-bit */
+ 0, /* data_width = 0:8-bit, 1:16-bit, 2:32-bit */
1 /* erase_chip */
};
-static int32_t is_range_valid(struct arm_flash_dev_t *flash_dev,
- uint32_t offset)
-{
- uint32_t flash_limit = 0;
- int32_t rc = 0;
-
- flash_limit = (flash_dev->data->sector_count * flash_dev->data->sector_size)
- - 1;
-
- if (offset > flash_limit) {
- rc = -1;
- }
- return rc;
-}
-
-static int32_t is_write_aligned(struct arm_flash_dev_t *flash_dev,
- uint32_t param)
-{
- int32_t rc = 0;
-
- if ((param % flash_dev->data->program_unit) != 0) {
- rc = -1;
- }
- return rc;
-}
-
-static int32_t is_sector_aligned(struct arm_flash_dev_t *flash_dev,
- uint32_t offset)
-{
- int32_t rc = 0;
-
- if ((offset % flash_dev->data->sector_size) != 0) {
- rc = -1;
- }
- return rc;
-}
-
-static int32_t is_flash_ready_to_write(const uint8_t *start_addr, uint32_t cnt)
-{
- int32_t rc = 0;
- uint32_t i;
-
- for (i = 0; i < cnt; i++) {
- if(start_addr[i] != ARM_FLASH_DRV_ERASE_VALUE) {
- rc = -1;
- break;
- }
- }
-
- return rc;
-}
-
/*
* Common interface functions
*/
@@ -125,18 +65,6 @@ static ARM_DRIVER_VERSION ARM_Flash_GetVersion(void)
return DriverVersion;
}
-static ARM_FLASH_CAPABILITIES ARM_Flash_GetCapabilities(void)
-{
- return DriverCapabilities;
-}
-
-static int32_t ARM_Flash_Initialize(ARM_Flash_SignalEvent_t cb_event)
-{
- ARG_UNUSED(cb_event);
- /* Nothing to be done */
- return ARM_DRIVER_OK;
-}
-
static int32_t ARM_Flash_Uninitialize(void)
{
/* Nothing to be done */
@@ -165,202 +93,120 @@ static int32_t ARM_Flash_PowerControl(ARM_POWER_STATE state)
#if (RTE_FLASH0)
static ARM_FLASH_INFO ARM_FLASH0_DEV_DATA = {
- .sector_info = NULL, /* Uniform sector layout */
- .sector_count = FLASH0_SIZE / FLASH0_SECTOR_SIZE,
- .sector_size = FLASH0_SECTOR_SIZE,
- .page_size = FLASH0_PAGE_SIZE,
- .program_unit = FLASH0_PROGRAM_UNIT,
- .erased_value = ARM_FLASH_DRV_ERASE_VALUE};
+ .sector_info = NULL, /* Uniform sector layout */
+ .sector_count = PMOD_SF3_FLASH_TOTAL_SIZE / PMOD_SF3_FLASH_SECTOR_SIZE,
+ .sector_size = PMOD_SF3_FLASH_SECTOR_SIZE,
+ .page_size = PMOD_SF3_FLASH_PAGE_SIZE,
+ .program_unit = PMOD_SF3_FLASH_PROGRAM_UNIT,
+ .erased_value = ARM_FLASH_DRV_ERASE_VALUE
+};
static struct arm_flash_dev_t ARM_FLASH0_DEV = {
- .memory_base = FLASH0_BASE,
- .data = &(ARM_FLASH0_DEV_DATA)};
-
-struct arm_flash_dev_t *FLASH0_DEV = &ARM_FLASH0_DEV;
+ .dev = &FLASH0_DEV,
+ .data = &(ARM_FLASH0_DEV_DATA)
+};
/*
* Functions
*/
-static int32_t FLASH0_ARM_Flash_ReadData(uint32_t addr, void *data, uint32_t cnt)
+static ARM_FLASH_CAPABILITIES N25Q256A_Driver_GetCapabilities(void)
{
- uint32_t start_addr = FLASH0_DEV->memory_base + addr;
- int32_t rc = 0;
-
- /* Check flash memory boundaries */
- rc = is_range_valid(FLASH0_DEV, addr + cnt);
- if (rc != 0) {
- return ARM_DRIVER_ERROR_PARAMETER;
- }
-
- memcpy(data, (void *)start_addr, cnt);
- return ARM_DRIVER_OK;
+ return N25Q256ADriverCapabilities;
}
-static int32_t FLASH0_ARM_Flash_ProgramData(uint32_t addr, const void *data,
- uint32_t cnt)
-{
- ARG_UNUSED(addr);
- ARG_UNUSED(data);
- ARG_UNUSED(cnt);
- /* This flash device cannot be programmed over this interface. */
- return ARM_DRIVER_ERROR_UNSUPPORTED;
-}
-
-static int32_t FLASH0_ARM_Flash_EraseSector(uint32_t addr)
+static int32_t N25Q256A_Flash_Initialize(ARM_Flash_SignalEvent_t cb_event)
{
- ARG_UNUSED(addr);
-
- /* This flash device cannot be erased over this interface, but this
- * function must return with success. Only the bootloader used this driver,
- * and it might try do delete a bad firmware image from memory. It is not a
- * problem if the image not deleted, but returning with error would crash
- * the bootloader. */
- return ARM_DRIVER_OK;
-}
+ ARG_UNUSED(cb_event);
+ enum n25q256a_error_t ret;
+ struct spi_n25q256a_dev_t* dev = ARM_FLASH0_DEV.dev;
+ ARM_FLASH_INFO* data = ARM_FLASH0_DEV.data;
+
+ dev->total_sector_cnt = data->sector_count;
+ dev->page_size = data->page_size;
+ dev->sector_size = data->sector_size;
+ dev->program_unit = data->program_unit;
+
+ ret = spi_n25q256a_initialize(ARM_FLASH0_DEV.dev);
+ if (ret != N25Q256A_ERR_NONE) {
+ SPI_FLASH_LOG_MSG("%s: Initialization failed.\n\r", __func__);
+ return ARM_DRIVER_ERROR;
+ }
-static int32_t FLASH0_ARM_Flash_EraseChip(void)
-{
- /* This flash device cannot be erased over this interface, but this
- * function must return with success. Only the bootloader used this driver,
- * and it might try do delete a bad firmware image from memory. It is not a
- * problem if the image not deleted, but returning with error would crash
- * the bootloader. */
return ARM_DRIVER_OK;
}
-static ARM_FLASH_INFO * FLASH0_ARM_Flash_GetInfo(void)
+static int32_t N25Q256A_Flash_ReadData(uint32_t addr, void *data, uint32_t cnt)
{
- return FLASH0_DEV->data;
-}
-
-ARM_DRIVER_FLASH Driver_FLASH0 = {
- ARM_Flash_GetVersion,
- ARM_Flash_GetCapabilities,
- ARM_Flash_Initialize,
- ARM_Flash_Uninitialize,
- ARM_Flash_PowerControl,
- FLASH0_ARM_Flash_ReadData,
- FLASH0_ARM_Flash_ProgramData,
- FLASH0_ARM_Flash_EraseSector,
- FLASH0_ARM_Flash_EraseChip,
- ARM_Flash_GetStatus,
- FLASH0_ARM_Flash_GetInfo
-};
-#endif /* RTE_FLASH0 */
+ enum n25q256a_error_t ret;
-#if (RTE_FLASH1)
-static ARM_FLASH_INFO ARM_FLASH1_DEV_DATA = {
- .sector_info = NULL, /* Uniform sector layout */
- .sector_count = FLASH1_SIZE / FLASH1_SECTOR_SIZE,
- .sector_size = FLASH1_SECTOR_SIZE,
- .page_size = FLASH1_PAGE_SIZE,
- .program_unit = FLASH1_PROGRAM_UNIT,
- .erased_value = ARM_FLASH_DRV_ERASE_VALUE};
-
-static struct arm_flash_dev_t ARM_FLASH1_DEV = {
- .memory_base = FLASH1_BASE,
- .data = &(ARM_FLASH1_DEV_DATA)};
-
-struct arm_flash_dev_t *FLASH1_DEV = &ARM_FLASH1_DEV;
-
-/*
- * Functions
- */
-
-static int32_t FLASH1_ARM_Flash_ReadData(uint32_t addr, void *data, uint32_t cnt)
-{
- uint32_t start_addr = FLASH1_DEV->memory_base + addr;
- int32_t rc = 0;
-
- /* Check flash memory boundaries */
- rc = is_range_valid(FLASH1_DEV, addr + cnt);
- if (rc != 0) {
- return ARM_DRIVER_ERROR_PARAMETER;
+ ret = spi_n25q256a_read(ARM_FLASH0_DEV.dev, addr, data, cnt);
+ if (ret != N25Q256A_ERR_NONE) {
+ SPI_FLASH_LOG_MSG("%s: read failed: addr=0x%x, cnt=%u\n\r", __func__, addr, cnt);
+ return ARM_DRIVER_ERROR;
}
- memcpy(data, (void *)start_addr, cnt);
return ARM_DRIVER_OK;
}
-static int32_t FLASH1_ARM_Flash_ProgramData(uint32_t addr, const void *data,
- uint32_t cnt)
+static int32_t N25Q256A_Flash_ProgramData(uint32_t addr, const void *data,
+ uint32_t cnt)
{
- uint32_t start_addr = FLASH1_DEV->memory_base + addr;
- int32_t rc = 0;
-
- /* Check flash memory boundaries and alignment with minimal write size */
- rc = is_range_valid(FLASH1_DEV, addr + cnt);
- rc |= is_write_aligned(FLASH1_DEV, addr);
- rc |= is_write_aligned(FLASH1_DEV, cnt);
- if (rc != 0) {
- return ARM_DRIVER_ERROR_PARAMETER;
- }
+ enum n25q256a_error_t ret;
- /* Check if the flash area to write the data was erased previously */
- rc = is_flash_ready_to_write((const uint8_t*)start_addr, cnt);
- if (rc != 0) {
+ ret = spi_n25q256a_program(ARM_FLASH0_DEV.dev, addr, data, cnt);
+ if (ret != N25Q256A_ERR_NONE) {
+ SPI_FLASH_LOG_MSG("%s: program failed: addr=0x%x, cnt=%u\n\r", __func__, addr, cnt);
return ARM_DRIVER_ERROR;
}
- memcpy((void *)start_addr, data, cnt);
return ARM_DRIVER_OK;
}
-static int32_t FLASH1_ARM_Flash_EraseSector(uint32_t addr)
+static int32_t N25Q256A_Flash_EraseSector(uint32_t addr)
{
- uint32_t start_addr = FLASH1_DEV->memory_base + addr;
- uint32_t rc = 0;
+ enum n25q256a_error_t ret;
- rc = is_range_valid(FLASH1_DEV, addr);
- rc |= is_sector_aligned(FLASH1_DEV, addr);
- if (rc != 0) {
- return ARM_DRIVER_ERROR_PARAMETER;
+ ret = spi_n25q256a_erase(ARM_FLASH0_DEV.dev, addr);
+ if (ret != N25Q256A_ERR_NONE) {
+ SPI_FLASH_LOG_MSG("%s: erase failed: addr=0x%x\n\r", __func__, addr);
+ return ARM_DRIVER_ERROR;
}
- memset((void *)start_addr,
- FLASH1_DEV->data->erased_value,
- FLASH1_DEV->data->sector_size);
return ARM_DRIVER_OK;
}
-static int32_t FLASH1_ARM_Flash_EraseChip(void)
+static int32_t N25Q256A_Flash_EraseChip(void)
{
- uint32_t i;
- uint32_t addr = FLASH1_DEV->memory_base;
- int32_t rc = ARM_DRIVER_ERROR_UNSUPPORTED;
-
- /* Check driver capability erase_chip bit */
- if (DriverCapabilities.erase_chip == 1) {
- for (i = 0; i < FLASH1_DEV->data->sector_count; i++) {
- memset((void *)addr,
- FLASH1_DEV->data->erased_value,
- FLASH1_DEV->data->sector_size);
-
- addr += FLASH1_DEV->data->sector_size;
- rc = ARM_DRIVER_OK;
- }
+ enum n25q256a_error_t ret;
+
+ ret = spi_n25q256a_erase_chip(ARM_FLASH0_DEV.dev);
+ if (ret != N25Q256A_ERR_NONE) {
+ SPI_FLASH_LOG_MSG("%s: erase chip failed\n\r", __func__);
+ return ARM_DRIVER_ERROR;
}
- return rc;
+
+ return ARM_DRIVER_OK;
}
-static ARM_FLASH_INFO * FLASH1_ARM_Flash_GetInfo(void)
+static ARM_FLASH_INFO * N25Q256A_Flash_GetInfo(void)
{
- return FLASH1_DEV->data;
+ return ARM_FLASH0_DEV.data;
}
-ARM_DRIVER_FLASH Driver_FLASH1 = {
+ARM_DRIVER_FLASH Driver_FLASH0 = {
ARM_Flash_GetVersion,
- ARM_Flash_GetCapabilities,
- ARM_Flash_Initialize,
+ N25Q256A_Driver_GetCapabilities,
+ N25Q256A_Flash_Initialize,
ARM_Flash_Uninitialize,
ARM_Flash_PowerControl,
- FLASH1_ARM_Flash_ReadData,
- FLASH1_ARM_Flash_ProgramData,
- FLASH1_ARM_Flash_EraseSector,
- FLASH1_ARM_Flash_EraseChip,
+ N25Q256A_Flash_ReadData,
+ N25Q256A_Flash_ProgramData,
+ N25Q256A_Flash_EraseSector,
+ N25Q256A_Flash_EraseChip,
ARM_Flash_GetStatus,
- FLASH1_ARM_Flash_GetInfo
+ N25Q256A_Flash_GetInfo
};
-#endif /* RTE_FLASH1 */
+
+#endif /* RTE_FLASH0 */
diff --git a/platform/ext/target/arm/diphda/CMakeLists.txt b/platform/ext/target/arm/diphda/CMakeLists.txt
index 15c913c648..6a461a127c 100644
--- a/platform/ext/target/arm/diphda/CMakeLists.txt
+++ b/platform/ext/target/arm/diphda/CMakeLists.txt
@@ -58,6 +58,8 @@ target_sources(platform_s
Device/Source/system_core_init.c
Native_Driver/uart_pl011_drv.c
Native_Driver/mhu_v2_x.c
+ Native_Driver/xilinx_pg153_axi_qspi_controller_drv.c
+ Native_Driver/spi_n25q256a_flash_lib.c
spm_hal.c
tfm_hal_isolation.c
$<$<BOOL:TFM_PARTITION_PLATFORM>:${CMAKE_CURRENT_SOURCE_DIR}/services/src/tfm_platform_system.c>
@@ -77,6 +79,8 @@ target_sources(platform_bl2
Device/Source/device_definition.c
Device/Source/system_core_init.c
Native_Driver/uart_pl011_drv.c
+ Native_Driver/xilinx_pg153_axi_qspi_controller_drv.c
+ Native_Driver/spi_n25q256a_flash_lib.c
bl2_boot_hal.c
bl2_security_cnt.c
tfm_rotpk.c
diff --git a/platform/ext/target/arm/diphda/Device/Config/device_cfg.h b/platform/ext/target/arm/diphda/Device/Config/device_cfg.h
index f5803e711b..479ef32fa0 100644
--- a/platform/ext/target/arm/diphda/Device/Config/device_cfg.h
+++ b/platform/ext/target/arm/diphda/Device/Config/device_cfg.h
@@ -29,4 +29,10 @@
/*ARM MHU1 Host to SE*/
#define MHU1_HOST_TO_SE
+/* External PMOD SF3 Flash Device */
+#define SPI_N25Q256A_S
+
+/* AXI QSPI Controller */
+#define AXI_QSPI_S
+
#endif /* __DEVICE_CFG_H__ */
diff --git a/platform/ext/target/arm/diphda/Device/Include/device_definition.h b/platform/ext/target/arm/diphda/Device/Include/device_definition.h
index 68fbd19f98..98ce30dfae 100644
--- a/platform/ext/target/arm/diphda/Device/Include/device_definition.h
+++ b/platform/ext/target/arm/diphda/Device/Include/device_definition.h
@@ -46,4 +46,16 @@ extern struct mhu_v2_x_dev_t MHU1_SE_TO_HOST_DEV;
extern struct mhu_v2_x_dev_t MHU1_HOST_TO_SE_DEV;
#endif
+/* QSPI Flash Controller driver structures */
+#if (defined(SPI_N25Q256A_S) && defined(AXI_QSPI_S))
+#include "xilinx_pg153_axi_qspi_controller_drv.h"
+extern struct axi_qspi_dev_t AXI_QSPI_DEV_S;
+#endif
+
+/* PMOD SF3 Nor Flash N25Q256A driver structures */
+#if (defined(SPI_N25Q256A_S) && defined(AXI_QSPI_S))
+#include "spi_n25q256a_flash_lib.h"
+extern struct spi_n25q256a_dev_t SPI_N25Q256A_DEV;
+#endif
+
#endif /* __DEVICE_DEFINITION_H__ */
diff --git a/platform/ext/target/arm/diphda/Device/Include/platform_base_address.h b/platform/ext/target/arm/diphda/Device/Include/platform_base_address.h
index c5e24a5c62..e5e2bfa293 100644
--- a/platform/ext/target/arm/diphda/Device/Include/platform_base_address.h
+++ b/platform/ext/target/arm/diphda/Device/Include/platform_base_address.h
@@ -68,7 +68,9 @@
#define DIPHDA_HOST_BIR_BASE (0x60000000U) /* Boot Instruction Register */
#define DIPHDA_HOST_SHARED_RAM_BASE (0x62000000U) /* Shared RAM */
#define DIPHDA_HOST_XNVM_BASE (0x68000000U) /* XNVM */
+#define DIPHDA_AXI_QSPI_CTRL_REG_BASE (0x80050000U) /* AXI QSPI Controller */
#define DIPHDA_HOST_BASE_SYSTEM_CONTROL_BASE (0x7A010000U) /* Host SCB */
#define DIPHDA_HOST_FIREWALL_BASE (0x7A800000U) /* Host Firewall */
+#define DIPHDA_HOST_FPGA_SCC_REGISTERS (0x80000000U) /* FPGA SCC Registers */
#endif /* __PLATFORM_BASE_ADDRESS_H__ */
diff --git a/platform/ext/target/arm/diphda/Device/Source/device_definition.c b/platform/ext/target/arm/diphda/Device/Source/device_definition.c
index 1b61ea19c5..ba694472b2 100644
--- a/platform/ext/target/arm/diphda/Device/Source/device_definition.c
+++ b/platform/ext/target/arm/diphda/Device/Source/device_definition.c
@@ -41,3 +41,28 @@ struct mhu_v2_x_dev_t MHU1_SE_TO_HOST_DEV = {(DIPHDA_SEH_1_SENDER_BASE),
struct mhu_v2_x_dev_t MHU1_HOST_TO_SE_DEV = {(DIPHDA_HSE_1_RECEIVER_BASE),
(MHU_V2_X_RECEIVER_FRAME)};
#endif
+
+/* QSPI driver structures */
+#if (defined(SPI_N25Q256A_S) && defined(AXI_QSPI_S))
+static const struct axi_qspi_dev_cfg_t AXI_QSPI_DEV_CFG_S = {
+ .base = DIPHDA_AXI_QSPI_CTRL_REG_BASE,
+ .scc_base = DIPHDA_HOST_FPGA_SCC_REGISTERS
+};
+struct axi_qspi_dev_t AXI_QSPI_DEV_S = {
+ .cfg = &AXI_QSPI_DEV_CFG_S,
+ .is_initialized = false
+};
+#endif
+
+/* ======= External peripheral configuration structure definitions ======= */
+
+#if (defined(SPI_N25Q256A_S) && defined(AXI_QSPI_S))
+struct spi_n25q256a_dev_t SPI_N25Q256A_DEV = {
+ .controller = &AXI_QSPI_DEV_S,
+ .total_sector_cnt = 0,
+ .page_size = 0,
+ .sector_size = 0,
+ .program_unit = 0,
+ .is_initialized = false
+};
+#endif
diff --git a/platform/ext/target/arm/diphda/Native_Driver/spi_flash_commands.h b/platform/ext/target/arm/diphda/Native_Driver/spi_flash_commands.h
new file mode 100644
index 0000000000..33b66201fd
--- /dev/null
+++ b/platform/ext/target/arm/diphda/Native_Driver/spi_flash_commands.h
@@ -0,0 +1,28 @@
+/*
+ *
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SPI_FLASH_COMMANDS_H
+#define SPI_FLASH_COMMANDS_H
+
+
+#define CMD_WRITE_ENABLE 0x06
+#define CMD_RANDOM_READ 0x03
+#define CMD_FAST_READ 0x0B
+#define CMD_PAGE_PROGRAM 0x02
+#define CMD_SECTOR_ERASE 0xD8
+#define CMD_SUB_SECTOR_ERASE 0x20
+#define CMD_BULK_ERASE 0xC7
+#define CMD_READ_STATUSREG 0x05
+#define CMD_READ_ID 0x9E
+#define CMD_WRITE_STATUSREG 0x01
+#define CMD_READ_FLAG_STATUS 0x70
+#define CMD_CLEAR_FLAG_STATUS 0x50
+#define CMD_READ_VOLATILE_CONFIG 0x85
+
+
+#endif /* SPI_FLASH_COMMANDS_H */
diff --git a/platform/ext/target/arm/diphda/Native_Driver/spi_n25q256a_flash_lib.c b/platform/ext/target/arm/diphda/Native_Driver/spi_n25q256a_flash_lib.c
new file mode 100644
index 0000000000..ebc4d9bda8
--- /dev/null
+++ b/platform/ext/target/arm/diphda/Native_Driver/spi_n25q256a_flash_lib.c
@@ -0,0 +1,441 @@
+/*
+ *
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "spi_n25q256a_flash_lib.h"
+#include "spi_flash_commands.h"
+
+#define DUMMY_VAL 0xFF
+#define MAX_PROGRAM_SIZE 128 /* should be less than page size */
+#define MAX_READ_SIZE 128 /* should be less than page size */
+
+#define SR_IS_READY_MASK 0x01
+#define FSR_IS_ERASE_ERR_MASK 0x20
+#define FSR_IS_PROGRAM_ERR_MASK 0x10
+
+#define MANUFACTURER_ID 0x20
+#define MEMORY_TYPE 0xBA
+#define MEMORY_CAPACITY 0x19
+#define DATA_WIDTH 0x10
+
+#define CONFIG_REG_VALUE 0xFB
+
+uint8_t send_buf[256];
+uint8_t rcv_buf[256];
+
+static enum n25q256a_error_t spi_flash_read_reg(struct spi_n25q256a_dev_t* dev,
+ uint32_t *reg, uint32_t cmd)
+{
+ enum axi_qspi_error_t ret;
+
+ if (!reg) {
+ return N25Q256A_ERR_WRONG_ARGUMENT;
+ }
+
+ /* Read Flash Status Register */
+ send_buf[0] = cmd;
+ send_buf[1] = DUMMY_VAL;
+ ret = spi_transfer_and_receive(dev->controller, send_buf, rcv_buf, 2);
+ if (ret != AXI_QSPI_ERR_NONE) {
+ return ret;
+ }
+
+ *reg = rcv_buf[1] & 0xFF;
+
+ return N25Q256A_ERR_NONE;
+}
+
+static enum n25q256a_error_t spi_flash_wait_for_ready(
+ struct spi_n25q256a_dev_t* dev)
+{
+ uint32_t status_reg;
+ enum n25q256a_error_t ret;
+ uint32_t counter = 0;
+
+ while (1) {
+ /* Get the status register */
+ ret = spi_flash_read_reg(dev, &status_reg, CMD_READ_STATUSREG);
+ if (ret != N25Q256A_ERR_NONE) {
+ return ret;
+ }
+
+ if ((status_reg & SR_IS_READY_MASK) == 0) {
+ break;
+ }
+
+ if ((counter % 1000) == 0) {
+ SPI_FLASH_LOG_MSG("%s: WAITING status reg 0x%x\n\r",
+ __func__, status_reg);
+ counter++;
+ }
+ }
+
+ return N25Q256A_ERR_NONE;
+}
+
+static enum n25q256a_error_t spi_flash_write_enable(
+ struct spi_n25q256a_dev_t* dev)
+{
+ enum n25q256a_error_t ret;
+ enum axi_qspi_error_t qspi_ret;
+
+ ret = spi_flash_wait_for_ready(dev);
+ if (ret != N25Q256A_ERR_NONE) {
+ return ret;
+ }
+
+ send_buf[0] = CMD_WRITE_ENABLE;
+ qspi_ret = spi_transfer_and_receive(dev->controller, send_buf, NULL, 1);
+ if (qspi_ret != AXI_QSPI_ERR_NONE) {
+ return qspi_ret;
+ }
+
+ return N25Q256A_ERR_NONE;
+}
+
+static enum n25q256a_error_t spi_flash_identify_and_clear_error(
+ struct spi_n25q256a_dev_t* dev,
+ uint32_t mask)
+{
+ enum n25q256a_error_t ret;
+ enum axi_qspi_error_t qspi_ret;
+ uint32_t flag_reg;
+
+ ret = spi_flash_read_reg(dev, &flag_reg, CMD_READ_FLAG_STATUS);
+ if (ret != N25Q256A_ERR_NONE) {
+ return ret;
+ }
+
+ if ((flag_reg & mask) != 0) {
+ SPI_FLASH_LOG_MSG("%s:error identified at mask %x\n\r", __func__, mask);
+ send_buf[0] = CMD_CLEAR_FLAG_STATUS;
+ send_buf[1] = 0xFF;
+ qspi_ret = spi_transfer_and_receive(dev->controller, send_buf, NULL, 2);
+ if (qspi_ret != AXI_QSPI_ERR_NONE) {
+ return qspi_ret;
+ }
+ return N25Q256A_ERR_FLASH_CMD_FAILED;
+ }
+
+ return N25Q256A_ERR_NONE;
+}
+
+enum n25q256a_error_t spi_n25q256a_erase_chip(struct spi_n25q256a_dev_t* dev)
+{
+ enum n25q256a_error_t ret;
+ enum axi_qspi_error_t qspi_ret;
+
+ if (!dev->is_initialized) {
+ SPI_FLASH_LOG_MSG("%s: not initialized\n\r", __func__);
+ return N25Q256A_ERR_NOT_INITIALIZED;
+ }
+ SPI_FLASH_LOG_MSG("%s\n\r", __func__);
+
+ ret = spi_flash_write_enable(dev);
+ if (ret != N25Q256A_ERR_NONE) {
+ return ret;
+ }
+
+ send_buf[0] = CMD_BULK_ERASE;
+
+ /* start erase */
+ qspi_ret = spi_transfer_and_receive(dev->controller, send_buf, NULL, 1);
+ if (qspi_ret != AXI_QSPI_ERR_NONE) {
+ return qspi_ret;
+ }
+
+ /* wait for erase completion */
+ ret = spi_flash_wait_for_ready(dev);
+ if (ret != N25Q256A_ERR_NONE) {
+ return ret;
+ }
+
+ /* check for error */
+ ret = spi_flash_identify_and_clear_error(dev, FSR_IS_ERASE_ERR_MASK);
+ if (ret != N25Q256A_ERR_NONE) {
+ return ret;
+ }
+
+ return N25Q256A_ERR_NONE;
+}
+
+enum n25q256a_error_t spi_n25q256a_erase(struct spi_n25q256a_dev_t* dev,
+ uint32_t addr)
+{
+ enum n25q256a_error_t ret;
+ enum axi_qspi_error_t qspi_ret;
+
+ if (!dev->is_initialized) {
+ SPI_FLASH_LOG_MSG("%s: not initialized\n\r", __func__);
+ return N25Q256A_ERR_NOT_INITIALIZED;
+ }
+ SPI_FLASH_LOG_MSG("%s: addr=0x%x\n\r", __func__, addr);
+
+ ret = spi_flash_write_enable(dev);
+ if (ret != N25Q256A_ERR_NONE) {
+ return ret;
+ }
+
+ send_buf[0] = CMD_SUB_SECTOR_ERASE;
+ send_buf[1] = ((addr >> 24) & 0xFF);
+ send_buf[2] = ((addr >> 16) & 0xFF);
+ send_buf[3] = ((addr >> 8) & 0xFF);
+ send_buf[4] = ((addr >> 0) & 0xFF);
+
+ /* start erase */
+ qspi_ret = spi_transfer_and_receive(dev->controller, send_buf, NULL, 5);
+ if (qspi_ret != AXI_QSPI_ERR_NONE) {
+ return qspi_ret;
+ }
+
+ /* wait for erase completion */
+ ret = spi_flash_wait_for_ready(dev);
+ if (ret != N25Q256A_ERR_NONE) {
+ return ret;
+ }
+
+ /* check for error */
+ ret = spi_flash_identify_and_clear_error(dev, FSR_IS_ERASE_ERR_MASK);
+ if (ret != N25Q256A_ERR_NONE) {
+ return ret;
+ }
+
+ return N25Q256A_ERR_NONE;
+}
+
+static enum n25q256a_error_t spi_n25q256a_program_data(
+ struct spi_n25q256a_dev_t* dev, uint32_t addr,
+ const uint8_t *data, uint32_t cnt)
+{
+ enum n25q256a_error_t ret;
+ enum axi_qspi_error_t qspi_ret;
+ uint32_t remaining_bytes = cnt;
+ uint32_t current_data_index = 0;
+ uint32_t current_addr = addr;
+ uint32_t write_size;
+
+ while (remaining_bytes) {
+
+ /* write enable */
+ ret = spi_flash_write_enable(dev);
+ if (ret != N25Q256A_ERR_NONE) {
+ return ret;
+ }
+
+ /* prepare send buffer */
+ send_buf[0] = CMD_PAGE_PROGRAM;
+ send_buf[1] = ((current_addr >> 24) & 0xFF);
+ send_buf[2] = ((current_addr >> 16) & 0xFF);
+ send_buf[3] = ((current_addr >> 8) & 0xFF);
+ send_buf[4] = ((current_addr >> 0) & 0xFF);
+
+ if (remaining_bytes < MAX_PROGRAM_SIZE) {
+ write_size = remaining_bytes;
+ } else {
+ write_size = MAX_PROGRAM_SIZE;
+ }
+ for (int i = 0; i < write_size; i++) {
+ send_buf[i+5] = data[current_data_index++];
+ }
+
+ /* start program */
+ qspi_ret = spi_transfer_and_receive(dev->controller, send_buf, NULL,
+ write_size + 5);
+ if (qspi_ret != AXI_QSPI_ERR_NONE) {
+ return qspi_ret;
+ }
+ /* wait for write completion */
+ ret = spi_flash_wait_for_ready(dev);
+ if (ret != N25Q256A_ERR_NONE) {
+ return ret;
+ }
+ /* check for error */
+ ret = spi_flash_identify_and_clear_error(dev,
+ FSR_IS_PROGRAM_ERR_MASK);
+ if (ret != N25Q256A_ERR_NONE) {
+ return ret;
+ }
+
+ remaining_bytes -= write_size;
+ current_addr += write_size;
+ }
+
+ return N25Q256A_ERR_NONE;
+}
+
+enum n25q256a_error_t spi_n25q256a_program(
+ struct spi_n25q256a_dev_t* dev, uint32_t addr,
+ const uint8_t *data, uint32_t cnt)
+{
+ enum n25q256a_error_t ret;
+ uint32_t remaining_space;
+ uint32_t current_addr = addr;
+ uint8_t *current_data_ptr = (uint8_t*)data;
+ uint32_t current_cnt = cnt;
+
+ if (!dev->is_initialized) {
+ SPI_FLASH_LOG_MSG("%s: not initialized\n\r", __func__);
+ return N25Q256A_ERR_NOT_INITIALIZED;
+ }
+ SPI_FLASH_LOG_MSG("%s: addr=0x%x, cnt=%u\n\r", __func__, addr, cnt);
+
+ /* Is write alligned? */
+ if ((addr % dev->program_unit) != 0) {
+ return N25Q256A_ERR_WRONG_ARGUMENT;
+ }
+
+ /* Check the limits */
+ if ((addr + cnt) > (dev->total_sector_cnt * dev->sector_size)) {
+ return N25Q256A_ERR_WRONG_ARGUMENT;
+ }
+
+ if ((addr % MAX_PROGRAM_SIZE) != 0) {
+ /* unaligned addr */
+ remaining_space = MAX_PROGRAM_SIZE - (addr % MAX_PROGRAM_SIZE);
+ if (cnt > remaining_space) {
+ /* crossing the page boundary */
+ /* first write the unaligned data to make addr aligned*/
+ ret = spi_n25q256a_program_data(dev, current_addr, current_data_ptr,
+ remaining_space);
+ if (ret != N25Q256A_ERR_NONE) {
+ return ret;
+ }
+ current_addr += remaining_space;
+ current_data_ptr += remaining_space;
+ current_cnt -= remaining_space;
+ }
+ }
+
+ ret = spi_n25q256a_program_data(dev, current_addr, current_data_ptr,
+ current_cnt);
+
+ return ret;
+}
+
+enum n25q256a_error_t spi_n25q256a_read(struct spi_n25q256a_dev_t* dev,
+ uint32_t addr,
+ uint8_t *data, uint32_t cnt)
+{
+ enum axi_qspi_error_t qspi_ret;
+ uint32_t remaining_bytes = cnt;
+ uint32_t current_data_index = 0;
+ uint32_t current_addr = addr;
+ uint32_t read_size;
+
+ if (!dev->is_initialized) {
+ SPI_FLASH_LOG_MSG("%s: not initialized\n\r", __func__);
+ return N25Q256A_ERR_NOT_INITIALIZED;
+ }
+ SPI_FLASH_LOG_MSG("%s: addr=0x%x, cnt=%u\n\r", __func__, addr, cnt);
+
+ /* Check the limits */
+ if ((addr + cnt) > (dev->total_sector_cnt * dev->sector_size)) {
+ return N25Q256A_ERR_WRONG_ARGUMENT;
+ }
+
+ while (remaining_bytes) {
+
+ /* prepare send buffer */
+ send_buf[0] = CMD_RANDOM_READ;
+ send_buf[1] = ((current_addr >> 24) & 0xFF);
+ send_buf[2] = ((current_addr >> 16) & 0xFF);
+ send_buf[3] = ((current_addr >> 8) & 0xFF);
+ send_buf[4] = ((current_addr >> 0) & 0xFF);
+
+ if (remaining_bytes < MAX_READ_SIZE) {
+ read_size = remaining_bytes;
+ } else {
+ read_size = MAX_READ_SIZE;
+ }
+
+ /* start reading */
+ qspi_ret = spi_transfer_and_receive(dev->controller, send_buf, rcv_buf,
+ read_size + 5);
+ if (qspi_ret != AXI_QSPI_ERR_NONE) {
+ return qspi_ret;
+ }
+ /* copy data to user location */
+ for (int i = 0; i < read_size; i++) {
+ data[current_data_index] = rcv_buf[i+5];
+ current_data_index++;
+ }
+
+ remaining_bytes -= read_size;
+ current_addr += read_size;
+ }
+
+ return N25Q256A_ERR_NONE;
+}
+
+static enum n25q256a_error_t spi_n25q256a_verify_id(
+ struct spi_n25q256a_dev_t* dev)
+{
+ enum axi_qspi_error_t qspi_ret;
+
+ /* Read ID */
+ send_buf[0] = CMD_READ_ID;
+ for (int i = 1; i <= 6; i++) {
+ send_buf[i] = DUMMY_VAL;
+ }
+
+ qspi_ret = spi_transfer_and_receive(dev->controller, send_buf, rcv_buf, 7);
+ if (qspi_ret != AXI_QSPI_ERR_NONE) {
+ return qspi_ret;
+ }
+
+ if ((rcv_buf[1] != MANUFACTURER_ID) || (rcv_buf[2] != MEMORY_TYPE) ||
+ (rcv_buf[3] != MEMORY_CAPACITY) || (rcv_buf[4] != DATA_WIDTH)) {
+ SPI_FLASH_LOG_MSG("ID miss-match %X-%X-%X-%X\n\r",
+ rcv_buf[1], rcv_buf[2], rcv_buf[3], rcv_buf[4]);
+ return N25Q256A_ERR_WRONG_MEMORY;
+ }
+ SPI_FLASH_LOG_MSG("ID register: %X-%X-%X-%X\n\r", rcv_buf[1], rcv_buf[2],
+ rcv_buf[3], rcv_buf[4]);
+
+ return N25Q256A_ERR_NONE;
+}
+
+enum n25q256a_error_t spi_n25q256a_initialize(struct spi_n25q256a_dev_t* dev)
+{
+ enum axi_qspi_error_t qspi_ret;
+ enum n25q256a_error_t flash_ret;
+ uint32_t reg;
+
+ if (dev->is_initialized) {
+ SPI_FLASH_LOG_MSG("%s: already initialized\n\r", __func__);
+ return N25Q256A_ERR_NONE;
+ }
+
+ /* Initialize the QSPI controller */
+ qspi_ret = axi_qspi_initialize(dev->controller);
+ if (qspi_ret != AXI_QSPI_ERR_NONE) {
+ return qspi_ret;
+ }
+
+ /* Verify device id */
+ flash_ret = spi_n25q256a_verify_id(dev);
+ if (flash_ret != N25Q256A_ERR_NONE) {
+ return flash_ret;
+ }
+
+ /* Read Config Register */
+ flash_ret = spi_flash_read_reg(dev, &reg, CMD_READ_VOLATILE_CONFIG);
+ if (flash_ret != N25Q256A_ERR_NONE) {
+ return flash_ret;
+ }
+ if (reg != CONFIG_REG_VALUE) {
+ SPI_FLASH_LOG_MSG("config register is not as expected: %X\n\r", reg);
+ return N25Q256A_ERR_WRONG_MEMORY;
+ }
+ SPI_FLASH_LOG_MSG("Config register value : 0x%X\n\r", reg);
+
+ dev->is_initialized = true;
+
+ SPI_FLASH_LOG_MSG("%s: SPI Flash Lib is initialized.\n\r", __func__);
+
+ return N25Q256A_ERR_NONE;
+}
diff --git a/platform/ext/target/arm/diphda/Native_Driver/spi_n25q256a_flash_lib.h b/platform/ext/target/arm/diphda/Native_Driver/spi_n25q256a_flash_lib.h
new file mode 100644
index 0000000000..1d23d96b4f
--- /dev/null
+++ b/platform/ext/target/arm/diphda/Native_Driver/spi_n25q256a_flash_lib.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SPI_N25Q256A_FLASH_LIB_H
+#define SPI_N25Q256A_FLASH_LIB_H
+
+#include "xilinx_pg153_axi_qspi_controller_drv.h"
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief SPI Flash error enumeration types
+ */
+enum n25q256a_error_t {
+ N25Q256A_ERR_NONE = AXI_QSPI_ERR_NONE,
+ N25Q256A_ERR_WRONG_ARGUMENT = AXI_QSPI_ERR_WRONG_ARGUMENT,
+ N25Q256A_ERR_NOT_INITIALIZED = AXI_QSPI_ERR_NOT_INITIALIZED,
+ N25Q256A_ERR_WRONG_MEMORY,
+ N25Q256A_ERR_FLASH_CMD_FAILED,
+ N25Q256A_ERR_READ_IN_PROGRESS,
+ N25Q256A_ERR_WRITE_IN_PROGRESS
+};
+
+struct spi_n25q256a_dev_t {
+ struct axi_qspi_dev_t *controller; /* QSPI Flash Controller */
+ uint32_t total_sector_cnt;
+ uint32_t page_size;
+ uint32_t sector_size;
+ uint32_t program_unit;
+ bool is_initialized;
+};
+
+enum n25q256a_error_t spi_n25q256a_initialize(struct spi_n25q256a_dev_t* dev);
+
+enum n25q256a_error_t spi_n25q256a_erase(struct spi_n25q256a_dev_t* dev,
+ uint32_t addr);
+
+enum n25q256a_error_t spi_n25q256a_erase_chip(struct spi_n25q256a_dev_t* dev);
+
+enum n25q256a_error_t spi_n25q256a_program(struct spi_n25q256a_dev_t* dev,
+ uint32_t addr,
+ const uint8_t *data, uint32_t cnt);
+
+enum n25q256a_error_t spi_n25q256a_read(struct spi_n25q256a_dev_t* dev,
+ uint32_t addr,
+ uint8_t *data, uint32_t cnt);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPI_N25Q256A_FLASH_LIB_H */
diff --git a/platform/ext/target/arm/diphda/Native_Driver/xilinx_pg153_axi_qspi_controller_drv.c b/platform/ext/target/arm/diphda/Native_Driver/xilinx_pg153_axi_qspi_controller_drv.c
new file mode 100644
index 0000000000..f052d7d291
--- /dev/null
+++ b/platform/ext/target/arm/diphda/Native_Driver/xilinx_pg153_axi_qspi_controller_drv.c
@@ -0,0 +1,183 @@
+/*
+ *
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "xilinx_pg153_axi_qspi_controller_drv.h"
+
+static void WRITE_REGISTER(uint32_t base, uint32_t offset, uint32_t val)
+{
+ *((volatile unsigned int*)(base + offset)) = val;
+}
+
+/* QSPI controller registers */
+typedef struct qspi_controller_registers {
+ uint8_t space_1[28];
+ uint32_t dgier; /* 0x1C: Global interrupt enable */
+ uint32_t ipisr; /* 0x20: Interrupt status */
+ uint8_t space_2[4];
+ uint32_t ipier; /* 0x28: Interrupt enable */
+ uint8_t space_3[20];
+ uint32_t srr; /* 0x40: Software reset register */
+ uint8_t space_4[28];
+ uint32_t spi_cr; /* 0x60: SPI control */
+ uint32_t spi_sr; /* 0x64: SPI status */
+ uint32_t spi_dtr; /* 0x68: SPI TX FIFO data */
+ uint32_t spi_drr; /* 0x6C: SPI RX FIFO data */
+ uint32_t spi_ssr; /* 0x70: SPI slave select */
+ uint32_t spi_txf; /* 0x74: SPI TX FIFO occupancy */
+ uint32_t spi_rxf; /* 0x78: SPI RX FIFO occupancy */
+} qspi_controller_registers_t;
+
+#define MODE_REG_OFFSET 0x08 /* Change controller mode */
+
+/* SCC register control */
+#define XIPMODE 0x00 /* XIP controller mode */
+#define QSPIMODE 0x01 /* QSPI controller mode */
+
+/* SPI Software Reset Register value. */
+#define SRR_RESET_VALUE 0x0000000A
+
+/* SPI Control Register (CR) Masks */
+#define CR_ENABLE_MASK 0x00000002 /* System enable */
+#define CR_CTRL_MODE_MASK 0x00000004 /* Enable controlling mode */
+#define CR_TXFIFO_RESET_MASK 0x00000020 /* Reset transmit FIFO */
+#define CR_RXFIFO_RESET_MASK 0x00000040 /* Reset receive FIFO */
+#define CR_TRANS_INHIBIT_MASK 0x00000100 /* Transaction inhibit */
+
+#define ENABLE_IER 0x00000004 /* Enable IER */
+#define DISABLE_GLOBAL_ITR 0x00000000 /* Disable Global Interrupt */
+
+#define INTR_TX_EMPTY_MASK 0x00000004 /* DTR/TxFIFO is empty */
+#define SR_RX_EMPTY_MASK 0x00000001 /* Receive Reg/FIFO is empty */
+
+#define SLAVE_SELECT_MASK 0x00000000
+#define SLAVE_DESELECT_MASK 0xFFFFFFFF
+#define PAGE_SIZE 256
+
+enum axi_qspi_error_t spi_transfer_and_receive(struct axi_qspi_dev_t* dev,
+ uint8_t *send_buffer, uint8_t *rcv_buffer, int bytes)
+{
+ uint32_t control_reg;
+ uint8_t rcv_data;
+ int j = 0;
+ volatile qspi_controller_registers_t *ctrl_regs =
+ (qspi_controller_registers_t*)dev->cfg->base;
+
+ if (!dev->is_initialized) {
+ SPI_FLASH_LOG_MSG("%s: not initialized\n\r", __func__);
+ return AXI_QSPI_ERR_NOT_INITIALIZED;
+ }
+
+ /* FIFO depth is assumed to be PAGE_SIZE */
+ /* Max PAGE bytes */
+ if ((bytes == 0) || (bytes > PAGE_SIZE)) {
+ return AXI_QSPI_ERR_WRONG_ARGUMENT;
+ }
+
+ control_reg = ctrl_regs->spi_cr;
+ /* Reset fifo and set controlling mode */
+ control_reg |= CR_TXFIFO_RESET_MASK | CR_RXFIFO_RESET_MASK |
+ CR_ENABLE_MASK | CR_CTRL_MODE_MASK;
+ /* Transaction disable */
+ control_reg |= CR_TRANS_INHIBIT_MASK;
+ ctrl_regs->spi_cr = control_reg;
+
+ /* Write to Data Transmit Register */
+ /* Even in case of read, there is a need to write dummy data to
+ DTR for read to take place. */
+ for (int i = 0; i < bytes; i++) {
+ ctrl_regs->spi_dtr = send_buffer[i];
+ }
+
+ /* Slave selected */
+ ctrl_regs->spi_ssr = SLAVE_SELECT_MASK;
+
+ /* Start the transaction by no longer inhibiting the controller */
+ control_reg = ctrl_regs->spi_cr;
+ control_reg &= ~CR_TRANS_INHIBIT_MASK;
+ ctrl_regs->spi_cr = control_reg;
+
+ /* Polling starts */
+ /* Wait for TX FIFO empty */
+ while (!(ctrl_regs->ipisr & INTR_TX_EMPTY_MASK));
+
+ /* Clear TX Empty interrupt */
+ ctrl_regs->ipisr = INTR_TX_EMPTY_MASK;
+
+ /* Slave de-select */
+ ctrl_regs->spi_ssr = SLAVE_DESELECT_MASK;
+
+ /* Loop to read the received data */
+ while ((ctrl_regs->spi_sr & SR_RX_EMPTY_MASK) == 0)
+ {
+ rcv_data = ctrl_regs->spi_drr & 0xFF;
+ if (rcv_buffer) {
+ rcv_buffer[j++] = rcv_data;
+ }
+ }
+
+ return AXI_QSPI_ERR_NONE;
+}
+
+
+/**
+ * Enable the QSPI controller.
+ */
+enum axi_qspi_error_t axi_qspi_initialize(struct axi_qspi_dev_t* dev)
+{
+ volatile qspi_controller_registers_t *ctrl_regs =
+ (qspi_controller_registers_t*)dev->cfg->base;
+
+ if (dev->is_initialized) {
+ SPI_FLASH_LOG_MSG("%s: already initialized\n\r", __func__);
+ return AXI_QSPI_ERR_NONE;
+ }
+
+ /* Switch to QSPI Controller */
+ WRITE_REGISTER(dev->cfg->scc_base, MODE_REG_OFFSET, QSPIMODE);
+
+ /* Reset controller */
+ ctrl_regs->srr = SRR_RESET_VALUE;
+
+ /* Enable IER */
+ ctrl_regs->ipier = ENABLE_IER;
+ /* Disable Global Interrupts */
+ ctrl_regs->dgier = DISABLE_GLOBAL_ITR;
+
+ SPI_FLASH_LOG_MSG("%s %s %s QSPI Controller is initialized.\n\r",
+ __func__, __DATE__, __TIME__);
+
+ dev->is_initialized = true;
+ return AXI_QSPI_ERR_NONE;
+}
+
+enum axi_qspi_error_t select_xip_mode(struct axi_qspi_dev_t* dev)
+{
+ if (!dev->is_initialized) {
+ return AXI_QSPI_ERR_NOT_INITIALIZED;
+ }
+
+ /* Switch to XIP Controller */
+ WRITE_REGISTER(dev->cfg->scc_base, MODE_REG_OFFSET, XIPMODE);
+
+ return AXI_QSPI_ERR_NONE;
+}
+
+enum axi_qspi_error_t select_qspi_mode(struct axi_qspi_dev_t* dev)
+{
+ if (!dev->is_initialized) {
+ SPI_FLASH_LOG_MSG("%s: not initialized\n\r", __func__);
+ return AXI_QSPI_ERR_NOT_INITIALIZED;
+ }
+
+ /* Switch to XIP Controller */
+ WRITE_REGISTER(dev->cfg->scc_base, MODE_REG_OFFSET, QSPIMODE);
+ SPI_FLASH_LOG_MSG("Selecting QSPI flash controller.\n\r");
+
+ return AXI_QSPI_ERR_NONE;
+}
+
diff --git a/platform/ext/target/arm/diphda/Native_Driver/xilinx_pg153_axi_qspi_controller_drv.h b/platform/ext/target/arm/diphda/Native_Driver/xilinx_pg153_axi_qspi_controller_drv.h
new file mode 100644
index 0000000000..7385badb53
--- /dev/null
+++ b/platform/ext/target/arm/diphda/Native_Driver/xilinx_pg153_axi_qspi_controller_drv.h
@@ -0,0 +1,79 @@
+/*
+ *
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef AXI_QSPI_CONTROLLER_DRV_H
+#define AXI_QSPI_CONTROLLER_DRV_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Set 1 to enable debug messages */
+#define DEBUG_SPI_FLASH 0
+
+#include <stdio.h>
+#if (DEBUG_SPI_FLASH == 1)
+ #define SPI_FLASH_LOG_MSG(f_, ...) printf((f_), ##__VA_ARGS__)
+#else
+ #define SPI_FLASH_LOG_MSG(f_, ...)
+#endif
+
+/**
+ * \brief AXI QSPI error enumeration types
+ */
+enum axi_qspi_error_t {
+ AXI_QSPI_ERR_NONE,
+ AXI_QSPI_ERR_WRONG_ARGUMENT,
+ AXI_QSPI_ERR_NOT_INITIALIZED
+};
+
+/**
+ * \brief AXI QSPI device configuration structure
+ */
+struct axi_qspi_dev_cfg_t {
+ const uint32_t base; /*!< AXI QSPI base address */
+ const uint32_t scc_base; /*!< SCC base address */
+};
+
+/**
+ * \brief AXI QSPI controller device structure
+ */
+struct axi_qspi_dev_t {
+ const struct axi_qspi_dev_cfg_t* const cfg;
+ bool is_initialized;
+};
+
+/**
+ * Reset the QSPI controller.
+ */
+enum axi_qspi_error_t axi_qspi_initialize(struct axi_qspi_dev_t* dev);
+
+/**
+ * Main function to send data and rcv data through QSPI controller.
+ */
+enum axi_qspi_error_t spi_transfer_and_receive(struct axi_qspi_dev_t* dev,
+ uint8_t *send_buffer, uint8_t *rcv_buffer, int bytes);
+
+/**
+ * Selects the XiP controller by programming the MUX bit.
+ */
+enum axi_qspi_error_t select_xip_mode(struct axi_qspi_dev_t* dev);
+
+/**
+ * Selects the QSPI controller by programming the MUX bit.
+ */
+enum axi_qspi_error_t select_qspi_mode(struct axi_qspi_dev_t* dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AXI_QSPI_CONTROLLER_DRV_H */
diff --git a/platform/ext/target/arm/diphda/bl1/CMakeLists.txt b/platform/ext/target/arm/diphda/bl1/CMakeLists.txt
index dd693ce1fb..1dd1103bf5 100644
--- a/platform/ext/target/arm/diphda/bl1/CMakeLists.txt
+++ b/platform/ext/target/arm/diphda/bl1/CMakeLists.txt
@@ -231,6 +231,8 @@ target_sources(bl1_main
../Native_Driver/firewall.c
../Native_Driver/uart_pl011_drv.c
../tfm_rotpk.c
+ ../Native_Driver/xilinx_pg153_axi_qspi_controller_drv.c
+ ../Native_Driver/spi_n25q256a_flash_lib.c
bl1_boot_hal.c
bl1_flash_map.c
bl1_security_cnt.c
diff --git a/platform/ext/target/arm/diphda/bl1/bl1_boot_hal.c b/platform/ext/target/arm/diphda/bl1/bl1_boot_hal.c
index a0e3b4d36e..4367bbe2bd 100644
--- a/platform/ext/target/arm/diphda/bl1/bl1_boot_hal.c
+++ b/platform/ext/target/arm/diphda/bl1/bl1_boot_hal.c
@@ -28,8 +28,10 @@ REGION_DECLARE(Image$$, ARM_LIB_HEAP, $$ZI$$Limit)[];
#define HOST_BIR_BASE 0x00000000
#define HOST_SHARED_RAM_BASE 0x02000000
#define HOST_XNVM_BASE 0x08000000
+#define AXI_QSPI_CTRL_REG_BASE 0x40050000
#define HOST_BASE_SYSTEM_CONTROL_BASE 0x1A010000
#define HOST_FIREWALL_BASE 0x1A800000
+#define HOST_FPGA_SCC_REGISTERS 0x40000000
#define FW_CONTROLLER 0
#define COMP_FC1 1
#define SE_MID 0
@@ -147,6 +149,50 @@ static void setup_se_firewall(void)
fc_enable_mpe(RGN_MPE0);
fc_enable_regions();
+ /* QSPI Flash Write: 64KB */
+ fc_select_region(6);
+ fc_disable_regions();
+ fc_disable_mpe(RGN_MPE0);
+ fc_prog_rgn(RGN_SIZE_64KB, DIPHDA_AXI_QSPI_CTRL_REG_BASE);
+ fc_prog_rgn_upper_addr(AXI_QSPI_CTRL_REG_BASE);
+ fc_enable_addr_trans();
+ fc_init_mpl(RGN_MPE0);
+
+ mpl_rights = (RGN_MPL_SECURE_READ_MASK |
+ RGN_MPL_SECURE_WRITE_MASK |
+ RGN_MPL_SECURE_EXECUTE_MASK |
+ RGN_MPL_NONSECURE_READ_MASK |
+ RGN_MPL_NONSECURE_WRITE_MASK |
+ RGN_MPL_NONSECURE_EXECUTE_MASK);
+
+ fc_enable_mpl(RGN_MPE0, mpl_rights);
+ fc_prog_mid(RGN_MPE0, SE_MID);
+ fc_enable_mpe(RGN_MPE0);
+ fc_enable_regions();
+
+ /* FPGA – SCC Registers: 64KB */
+ fc_select_region(7);
+ fc_disable_regions();
+ fc_disable_mpe(RGN_MPE0);
+ fc_prog_rgn(RGN_SIZE_4KB, DIPHDA_HOST_FPGA_SCC_REGISTERS);
+ fc_prog_rgn_upper_addr(HOST_FPGA_SCC_REGISTERS);
+ fc_enable_addr_trans();
+ fc_init_mpl(RGN_MPE0);
+
+ mpl_rights = (RGN_MPL_SECURE_READ_MASK |
+ RGN_MPL_SECURE_WRITE_MASK |
+ RGN_MPL_SECURE_EXECUTE_MASK |
+ RGN_MPL_NONSECURE_READ_MASK |
+ RGN_MPL_NONSECURE_WRITE_MASK |
+ RGN_MPL_NONSECURE_EXECUTE_MASK);
+
+ /* Enable All accesses from boot-processor */
+ fc_enable_mpl(RGN_MPE0, mpl_rights);
+ fc_prog_mid(RGN_MPE0, SE_MID);
+ fc_enable_mpe(RGN_MPE0);
+ fc_enable_regions();
+
+
fc_pe_enable();
}
diff --git a/platform/ext/target/arm/diphda/partition/flash_layout.h b/platform/ext/target/arm/diphda/partition/flash_layout.h
index 15d9dc3ab8..8700a99b9c 100644
--- a/platform/ext/target/arm/diphda/partition/flash_layout.h
+++ b/platform/ext/target/arm/diphda/partition/flash_layout.h
@@ -62,11 +62,15 @@
#define BL1_DATA_SIZE (0x10000) /* 64 KiB*/
#define BL1_DATA_LIMIT (BL1_DATA_START + BL1_DATA_SIZE - 1)
-#define FLASH_AREA_IMAGE_SECTOR_SIZE (0x1000) /* 4 KiB */
-
+/* PMOD SF3 NOR FLASH */
+#define PMOD_SF3_FLASH_TOTAL_SIZE (0x02000000) /* 32 MB Nor Flash (PMOD SF3) */
+#define PMOD_SF3_FLASH_SECTOR_SIZE (0x00001000) /* 4 KB Sub sector size*/
+#define PMOD_SF3_FLASH_PAGE_SIZE (256U) /* 256 B */
+#define PMOD_SF3_FLASH_PROGRAM_UNIT (1U) /* 1 B */
#define FLASH_DEV_NAME Driver_FLASH0
-#define FLASH_TOTAL_SIZE (0x02000000) /* 32 MB */
+#define FLASH_TOTAL_SIZE (PMOD_SF3_FLASH_TOTAL_SIZE) /* 32 MB */
+#define FLASH_AREA_IMAGE_SECTOR_SIZE (PMOD_SF3_FLASH_SECTOR_SIZE) /* 4 KiB */
#ifdef BL1
@@ -155,24 +159,24 @@
#endif /* BL1 */
-#define FLASH1_SECTOR_SIZE 0x400 /* 1 kB */
+#define FLASH_SECTOR_SIZE (PMOD_SF3_FLASH_SECTOR_SIZE) /* 1 kB */
#define FLASH_ITS_AREA_OFFSET (0)
-#define FLASH_ITS_AREA_SIZE (4 * FLASH1_SECTOR_SIZE) /* 4 KiB */
+#define FLASH_ITS_AREA_SIZE (4 * FLASH_SECTOR_SIZE) /* 4 KiB */
#define FLASH_PS_AREA_OFFSET (FLASH_ITS_AREA_OFFSET + \
FLASH_ITS_AREA_SIZE)
-#define FLASH_PS_AREA_SIZE (16 * FLASH1_SECTOR_SIZE) /* 16 KB */
+#define FLASH_PS_AREA_SIZE (16 * FLASH_SECTOR_SIZE) /* 16 KB */
#define FLASH_NV_COUNTERS_AREA_OFFSET (FLASH_PS_AREA_OFFSET + \
FLASH_PS_AREA_SIZE)
-#define FLASH_NV_COUNTERS_AREA_SIZE (FLASH1_SECTOR_SIZE) /* 1 KiB */
+#define FLASH_NV_COUNTERS_AREA_SIZE (FLASH_SECTOR_SIZE) /* 1 KiB */
/* Internal Trusted Storage (ITS) Service definitions
* Note: Further documentation of these definitions can be found in the
* TF-M ITS Integration Guide.
*/
-#define TFM_HAL_ITS_FLASH_DRIVER Driver_FLASH1
+#define TFM_HAL_ITS_FLASH_DRIVER Driver_FLASH0
/* In this target the CMSIS driver requires only the offset from the base
* address instead of the full memory address.
@@ -190,7 +194,7 @@
* Note: Further documentation of these definitions can be found in the
* TF-M PS Integration Guide.
*/
-#define TFM_HAL_PS_FLASH_DRIVER Driver_FLASH1
+#define TFM_HAL_PS_FLASH_DRIVER Driver_FLASH0
/* In this target the CMSIS driver requires only the offset from the base
* address instead of the full memory address.
@@ -204,12 +208,12 @@
/* Smallest flash programmable unit in bytes */
#define TFM_HAL_PS_PROGRAM_UNIT (1)
-#define NV_COUNTERS_FLASH_DEV_NAME Driver_FLASH1
+#define NV_COUNTERS_FLASH_DEV_NAME Driver_FLASH0
/* NV Counters definitions */
#define TFM_NV_COUNTERS_AREA_ADDR FLASH_NV_COUNTERS_AREA_OFFSET
#define TFM_NV_COUNTERS_AREA_SIZE (0x20) /* 24 Bytes*/
#define TFM_NV_COUNTERS_SECTOR_ADDR FLASH_NV_COUNTERS_AREA_OFFSET
-#define TFM_NV_COUNTERS_SECTOR_SIZE FLASH1_SECTOR_SIZE
+#define TFM_NV_COUNTERS_SECTOR_SIZE FLASH_SECTOR_SIZE
#endif /* __FLASH_LAYOUT_H__ */
diff --git a/platform/ext/target/arm/diphda/spm_hal.c b/platform/ext/target/arm/diphda/spm_hal.c
index 66f0e1a95a..290a22bc50 100644
--- a/platform/ext/target/arm/diphda/spm_hal.c
+++ b/platform/ext/target/arm/diphda/spm_hal.c
@@ -20,11 +20,7 @@
#include "platform_base_address.h"
-enum tfm_plat_err_t tfm_spm_hal_init_isolation_hw(void)
-{
- /* Setup of isolation HW not implemented yet. */
- return TFM_PLAT_ERR_SUCCESS;
-}
+#include "xilinx_pg153_axi_qspi_controller_drv.h"
enum tfm_plat_err_t tfm_spm_hal_configure_default_isolation(
bool priviledged,
@@ -41,6 +37,9 @@ enum tfm_plat_err_t tfm_spm_hal_configure_default_isolation(
void tfm_spm_hal_boot_ns_cpu(uintptr_t start_addr)
{
+ /* Switch the flash controller to XiP mode for the host */
+ select_xip_mode(&AXI_QSPI_DEV_S);
+
volatile uint32_t *bir_base = (uint32_t *)DIPHDA_HOST_BIR_BASE;
/* Program Boot Instruction Register to jump to BL32 base address