aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerda Zsejke, More <gerdazsejke.more@arm.com>2021-03-01 16:06:39 +0100
committerAnton Komlev <Anton.Komlev@arm.com>2021-03-10 13:51:24 +0100
commit36023aabb7848cdef5f7c5bb727e0051ba873ebf (patch)
tree933ef9f3702c200ffb3b8844f5980bbb5aaa480a
parented3980e7405599b39cbf19aef2d7dbbc8506f28a (diff)
downloadtrusted-firmware-m-36023aabb7848cdef5f7c5bb727e0051ba873ebf.tar.gz
Platform: Enabled QSPI flash on Musca_S1 to store PS content
- Added QSPI flash driver implementation - Changed flash_layout to set PS service for QSPI flash - QSPI flash controller is set secure Signed-off-by: Gerda Zsejke, More <gerdazsejke.more@arm.com> Change-Id: Ica537baa2cc11c9470376aa9b7e53dc6e4ae7c14
-rw-r--r--lib/ext/cryptocell-312-runtime/shared/hw/include/musca_s1/dx_reg_base_host.h4
-rw-r--r--platform/ext/target/musca_s1/CMSIS_Driver/Config/RTE_Device.h7
-rw-r--r--platform/ext/target/musca_s1/CMSIS_Driver/Config/cmsis_driver_config.h4
-rw-r--r--platform/ext/target/musca_s1/CMSIS_Driver/Driver_QSPI_Flash.c352
-rw-r--r--platform/ext/target/musca_s1/CMakeLists.txt6
-rw-r--r--platform/ext/target/musca_s1/Device/Config/device_cfg.h8
-rw-r--r--platform/ext/target/musca_s1/Device/Include/device_definition.h26
-rw-r--r--platform/ext/target/musca_s1/Device/Source/device_definition.c46
-rw-r--r--platform/ext/target/musca_s1/Libraries/mt25ql_flash_lib.c901
-rw-r--r--platform/ext/target/musca_s1/Libraries/mt25ql_flash_lib.h271
-rw-r--r--platform/ext/target/musca_s1/Native_Driver/qspi_ip6514e_drv.c755
-rw-r--r--platform/ext/target/musca_s1/Native_Driver/qspi_ip6514e_drv.h416
-rw-r--r--platform/ext/target/musca_s1/partition/flash_layout.h40
-rw-r--r--platform/ext/target/musca_s1/target_cfg.c6
14 files changed, 2806 insertions, 36 deletions
diff --git a/lib/ext/cryptocell-312-runtime/shared/hw/include/musca_s1/dx_reg_base_host.h b/lib/ext/cryptocell-312-runtime/shared/hw/include/musca_s1/dx_reg_base_host.h
index 41a121176a..baec7048ac 100644
--- a/lib/ext/cryptocell-312-runtime/shared/hw/include/musca_s1/dx_reg_base_host.h
+++ b/lib/ext/cryptocell-312-runtime/shared/hw/include/musca_s1/dx_reg_base_host.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2001-2021, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -18,7 +18,7 @@
* Same as FLASH_TFM_CRYPTO_KEY_AREA as found in
* platform/ext/target/musca_s1/partition/flash_layout.h
*/
-#define DX_MRAM_CC 0x1A1EE000
+#define DX_MRAM_CC 0x1A1E9000
#define DX_BASE_ENV_REGS 0x500A0000 //TODO need confirm
diff --git a/platform/ext/target/musca_s1/CMSIS_Driver/Config/RTE_Device.h b/platform/ext/target/musca_s1/CMSIS_Driver/Config/RTE_Device.h
index 39dbb754b5..8fb06312d9 100644
--- a/platform/ext/target/musca_s1/CMSIS_Driver/Config/RTE_Device.h
+++ b/platform/ext/target/musca_s1/CMSIS_Driver/Config/RTE_Device.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2019 Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021 Arm Limited. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -92,4 +92,9 @@
#define RTE_FLASH0 1
// </e> FLASH (Flash Memory) [Driver_FLASH0]
+// <e> FLASH (Flash Memory) [Driver_QSPI_FLASH0]
+// <i> Configuration settings for Driver_QSPI_FLASH0 in component ::Drivers:FLASH
+#define RTE_QSPI_FLASH0 1
+// </e> FLASH (Flash Memory) [Driver_QSPI_FLASH0]
+
#endif /* __RTE_DEVICE_H__ */
diff --git a/platform/ext/target/musca_s1/CMSIS_Driver/Config/cmsis_driver_config.h b/platform/ext/target/musca_s1/CMSIS_Driver/Config/cmsis_driver_config.h
index a55e0130c9..2a8c723b12 100644
--- a/platform/ext/target/musca_s1/CMSIS_Driver/Config/cmsis_driver_config.h
+++ b/platform/ext/target/musca_s1/CMSIS_Driver/Config/cmsis_driver_config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020 Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021 Arm Limited. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,4 +43,6 @@
#define MUSCA_S1_SCC_DEV MUSCA_S1_SCC_DEV_S
#define SSE_200_CACHE_DEV SSE_200_CACHE_DEV_S
+#define QSPI_FLASH0_DEV MT25QL_DEV_S
+
#endif /* __CMSIS_DRIVER_CONFIG_H__ */
diff --git a/platform/ext/target/musca_s1/CMSIS_Driver/Driver_QSPI_Flash.c b/platform/ext/target/musca_s1/CMSIS_Driver/Driver_QSPI_Flash.c
new file mode 100644
index 0000000000..440ba94914
--- /dev/null
+++ b/platform/ext/target/musca_s1/CMSIS_Driver/Driver_QSPI_Flash.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Driver_Flash.h"
+
+#include <stdbool.h>
+#include <string.h>
+#include "cmsis_driver_config.h"
+#include "RTE_Device.h"
+#include "flash_layout.h"
+
+
+#ifndef ARG_UNUSED
+#define ARG_UNUSED(arg) ((void)arg)
+#endif
+
+/* Driver version */
+#define ARM_FLASH_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1, 0)
+
+static const ARM_DRIVER_VERSION DriverVersion = {
+ ARM_FLASH_API_VERSION, /* Defined in the CMSIS Flash Driver header file */
+ ARM_FLASH_DRV_VERSION
+};
+
+/**
+ * \brief Flash driver capability macro definitions \ref ARM_FLASH_CAPABILITIES
+ */
+/* Flash Ready event generation capability values */
+#define EVENT_READY_NOT_AVAILABLE (0u)
+#define EVENT_READY_AVAILABLE (1u)
+/* Data access size values */
+#define DATA_WIDTH_8BIT (0u)
+#define DATA_WIDTH_16BIT (1u)
+#define DATA_WIDTH_32BIT (2u)
+/* Chip erase capability values */
+#define CHIP_ERASE_NOT_SUPPORTED (0u)
+#define CHIP_ERASE_SUPPORTED (1u)
+
+/* Driver Capabilities */
+static const ARM_FLASH_CAPABILITIES DriverCapabilities = {
+ EVENT_READY_NOT_AVAILABLE,
+ DATA_WIDTH_32BIT,
+ CHIP_ERASE_SUPPORTED
+};
+
+/* Valid entries for data item width */
+static const uint32_t data_width_byte[] = {
+ sizeof(uint8_t),
+ sizeof(uint16_t),
+ sizeof(uint32_t),
+};
+
+/**
+ * \brief Flash status macro definitions \ref ARM_FLASH_STATUS
+ */
+/* Busy status values of the Flash driver */
+#define DRIVER_STATUS_IDLE (0u)
+#define DRIVER_STATUS_BUSY (1u)
+/* Error status values of the Flash driver */
+#define DRIVER_STATUS_NO_ERROR (0u)
+#define DRIVER_STATUS_ERROR (1u)
+
+/**
+ * \brief Arm Flash device structure.
+ */
+struct arm_flash_dev_t {
+ struct mt25ql_dev_t* dev; /*!< FLASH memory device structure */
+ ARM_FLASH_INFO *data; /*!< FLASH memory device data */
+};
+
+/**
+ * \brief Check if the Flash memory boundaries are not violated.
+ * \param[in] flash_dev Flash device structure \ref arm_flash_dev_t
+ * \param[in] offset Highest Flash memory address which would be accessed.
+ * \return Returns true if Flash memory boundaries are not violated, false
+ * otherwise.
+ */
+static bool is_range_valid(struct arm_flash_dev_t *flash_dev,
+ uint32_t offset)
+{
+ uint32_t flash_limit = 0;
+
+ /* Calculating the highest address of the Flash memory address range */
+ flash_limit = FLASH_TOTAL_SIZE - 1;
+
+ return (offset > flash_limit) ? (false) : (true) ;
+}
+
+/**
+ * \brief Check if the parameter is aligned to program_unit.
+ * \param[in] flash_dev Flash device structure \ref arm_flash_dev_t
+ * \param[in] param Any number that can be checked against the
+ * program_unit, e.g. Flash memory address or
+ * data length in bytes.
+ * \return Returns true if param is aligned to program_unit, false
+ * otherwise.
+ */
+static bool is_write_aligned(struct arm_flash_dev_t *flash_dev,
+ uint32_t param)
+{
+ return ((param % flash_dev->data->program_unit) != 0) ? (false) : (true);
+}
+
+#if (RTE_QSPI_FLASH0)
+static ARM_FLASH_INFO ARM_FLASH0_DEV_DATA = {
+ .sector_info = NULL, /* Uniform sector layout */
+ .sector_count = FLASH_TOTAL_SIZE / SUBSECTOR_4KB,
+ .sector_size = SUBSECTOR_4KB,
+ .page_size = FLASH_PAGE_SIZE,
+ .program_unit = 1u, /* Minimum write size in bytes */
+ .erased_value = 0xFF
+};
+
+static struct arm_flash_dev_t ARM_FLASH0_DEV = {
+ .dev = &QSPI_FLASH0_DEV,
+ .data = &(ARM_FLASH0_DEV_DATA)
+};
+
+/* Flash Status */
+static ARM_FLASH_STATUS ARM_FLASH0_STATUS = {0, 0, 0};
+
+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)
+{
+ enum mt25ql_error_t err = MT25QL_ERR_NONE;
+
+ ARG_UNUSED(cb_event);
+
+ qspi_ip6514e_enable(ARM_FLASH0_DEV.dev->controller);
+
+ /* Configure QSPI Flash controller to operate in single SPI mode and
+ * to use fast Flash commands */
+ err = mt25ql_config_mode(ARM_FLASH0_DEV.dev, MT25QL_FUNC_STATE_FAST);
+ if(err != MT25QL_ERR_NONE) {
+ return ARM_DRIVER_ERROR;
+ }
+
+ return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flash_Uninitialize(void)
+{
+ enum mt25ql_error_t err = MT25QL_ERR_NONE;
+
+ /* Restores the QSPI Flash controller and MT25QL to reset state */
+ err = mt25ql_restore_reset_state(ARM_FLASH0_DEV.dev);
+ if(err != MT25QL_ERR_NONE) {
+ return ARM_DRIVER_ERROR;
+ }
+
+ return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flash_PowerControl(ARM_POWER_STATE state)
+{
+ switch(state) {
+ case ARM_POWER_FULL:
+ /* Nothing to be done */
+ return ARM_DRIVER_OK;
+ case ARM_POWER_OFF:
+ case ARM_POWER_LOW:
+ return ARM_DRIVER_ERROR_UNSUPPORTED;
+ default:
+ return ARM_DRIVER_ERROR_PARAMETER;
+ }
+}
+
+static int32_t ARM_Flash_ReadData(uint32_t addr, void *data, uint32_t cnt)
+{
+ /* Function includes a workaround for Musca-A QSPI flash when read data
+ * could be corrupted if read size is not 4 byte aligned.
+ */
+ enum mt25ql_error_t err = MT25QL_ERR_NONE;
+ bool is_valid = true;
+ uint32_t extra_bytes = 0;
+ uint32_t extra_word = 0;
+
+ ARM_FLASH0_STATUS.error = DRIVER_STATUS_NO_ERROR;
+
+ /* Check Flash memory boundaries */
+ is_valid = is_range_valid(&ARM_FLASH0_DEV, addr + cnt);
+ if(is_valid != true) {
+ ARM_FLASH0_STATUS.error = DRIVER_STATUS_ERROR;
+ return ARM_DRIVER_ERROR_PARAMETER;
+ }
+
+ ARM_FLASH0_STATUS.busy = DRIVER_STATUS_BUSY;
+
+ if (cnt % data_width_byte[DriverCapabilities.data_width] != 0) {
+ extra_bytes = cnt % data_width_byte[DriverCapabilities.data_width];
+ cnt -= extra_bytes;
+ }
+
+ err = mt25ql_command_read(ARM_FLASH0_DEV.dev, addr, data, cnt);
+
+ if (extra_bytes != 0) {
+ err = mt25ql_command_read(ARM_FLASH0_DEV.dev, addr + cnt, &extra_word,
+ data_width_byte[DriverCapabilities.data_width]);
+ memcpy((char *) data + cnt, &extra_word, extra_bytes);
+ }
+
+ ARM_FLASH0_STATUS.busy = DRIVER_STATUS_IDLE;
+
+ if(err != MT25QL_ERR_NONE) {
+ ARM_FLASH0_STATUS.error = DRIVER_STATUS_ERROR;
+ return ARM_DRIVER_ERROR;
+ }
+
+ return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flash_ProgramData(uint32_t addr,
+ const void *data, uint32_t cnt)
+{
+ enum mt25ql_error_t err = MT25QL_ERR_NONE;
+
+ ARM_FLASH0_STATUS.error = DRIVER_STATUS_NO_ERROR;
+
+ /* Check Flash memory boundaries and alignment with minimum write size
+ * (program_unit), data size also needs to be a multiple of program_unit.
+ */
+ if(!(is_range_valid(&ARM_FLASH0_DEV, addr + cnt) &&
+ is_write_aligned(&ARM_FLASH0_DEV, addr) &&
+ is_write_aligned(&ARM_FLASH0_DEV, cnt) )) {
+
+ ARM_FLASH0_STATUS.error = DRIVER_STATUS_ERROR;
+ return ARM_DRIVER_ERROR_PARAMETER;
+ }
+
+ ARM_FLASH0_STATUS.busy = DRIVER_STATUS_BUSY;
+
+ err = mt25ql_command_write(ARM_FLASH0_DEV.dev, addr, data, cnt);
+
+ ARM_FLASH0_STATUS.busy = DRIVER_STATUS_IDLE;
+
+ if(err != MT25QL_ERR_NONE) {
+ ARM_FLASH0_STATUS.error = DRIVER_STATUS_ERROR;
+ return ARM_DRIVER_ERROR;
+ }
+
+ return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flash_EraseSector(uint32_t addr)
+{
+ enum mt25ql_error_t err = MT25QL_ERR_NONE;
+
+ ARM_FLASH0_STATUS.error = DRIVER_STATUS_NO_ERROR;
+ ARM_FLASH0_STATUS.busy = DRIVER_STATUS_BUSY;
+
+ /* The erase function checks whether the address is aligned with
+ * the sector or subsector and checks the Flash memory boundaries.
+ */
+ err = mt25ql_erase(ARM_FLASH0_DEV.dev, addr,
+ (enum mt25ql_erase_t) ARM_FLASH0_DEV.data->sector_size);
+
+ ARM_FLASH0_STATUS.busy = DRIVER_STATUS_IDLE;
+
+ if(err != MT25QL_ERR_NONE) {
+ ARM_FLASH0_STATUS.error = DRIVER_STATUS_ERROR;
+
+ if((err == MT25QL_ERR_ADDR_NOT_ALIGNED) ||
+ (err == MT25QL_ERR_ADDR_TOO_BIG) ||
+ (err == MT25QL_ERR_WRONG_ARGUMENT) ) {
+ return ARM_DRIVER_ERROR_PARAMETER;
+ }
+ return ARM_DRIVER_ERROR;
+ }
+
+ return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flash_EraseChip(void)
+{
+ enum mt25ql_error_t err = MT25QL_ERR_NONE;
+
+ if(DriverCapabilities.erase_chip == 1) {
+
+ ARM_FLASH0_STATUS.error = DRIVER_STATUS_NO_ERROR;
+ ARM_FLASH0_STATUS.busy = DRIVER_STATUS_BUSY;
+
+ /* The erase function checks whether the address is aligned with
+ * the sector or subsector and checks the Flash memory boundaries.
+ */
+ err = mt25ql_erase(ARM_FLASH0_DEV.dev, 0, MT25QL_ERASE_ALL_FLASH);
+
+ ARM_FLASH0_STATUS.busy = DRIVER_STATUS_IDLE;
+
+ if(err != MT25QL_ERR_NONE) {
+ ARM_FLASH0_STATUS.error = DRIVER_STATUS_ERROR;
+
+ if((err == MT25QL_ERR_ADDR_NOT_ALIGNED) ||
+ (err == MT25QL_ERR_ADDR_TOO_BIG) ||
+ (err == MT25QL_ERR_WRONG_ARGUMENT) ) {
+ return ARM_DRIVER_ERROR_PARAMETER;
+ }
+ return ARM_DRIVER_ERROR;
+ }
+
+ return ARM_DRIVER_OK;
+
+ } else {
+ return ARM_DRIVER_ERROR_UNSUPPORTED;
+ }
+}
+
+static ARM_FLASH_STATUS ARM_Flash_GetStatus(void)
+{
+ return ARM_FLASH0_STATUS;
+}
+
+static ARM_FLASH_INFO * ARM_Flash_GetInfo(void)
+{
+ return ARM_FLASH0_DEV.data;
+}
+
+ARM_DRIVER_FLASH Driver_QSPI_FLASH0 = {
+ ARM_Flash_GetVersion,
+ ARM_Flash_GetCapabilities,
+ ARM_Flash_Initialize,
+ ARM_Flash_Uninitialize,
+ ARM_Flash_PowerControl,
+ ARM_Flash_ReadData,
+ ARM_Flash_ProgramData,
+ ARM_Flash_EraseSector,
+ ARM_Flash_EraseChip,
+ ARM_Flash_GetStatus,
+ ARM_Flash_GetInfo
+};
+#endif /* RTE_QSPI_FLASH0 */
diff --git a/platform/ext/target/musca_s1/CMakeLists.txt b/platform/ext/target/musca_s1/CMakeLists.txt
index 33bcb85049..4d07d5342b 100644
--- a/platform/ext/target/musca_s1/CMakeLists.txt
+++ b/platform/ext/target/musca_s1/CMakeLists.txt
@@ -68,11 +68,13 @@ target_include_directories(platform_s
Native_Driver
partition
services/include
+ Libraries
)
target_sources(platform_s
PRIVATE
$<$<STREQUAL:${CRYPTO_HW_ACCELERATOR_OTP_STATE},ENABLED>:${CMAKE_CURRENT_SOURCE_DIR}/crypto_keys.c>
+ CMSIS_Driver/Driver_QSPI_Flash.c
CMSIS_Driver/Driver_Flash_MRAM.c
CMSIS_Driver/Driver_MPC.c
CMSIS_Driver/Driver_PPC.c
@@ -85,11 +87,13 @@ target_sources(platform_s
Native_Driver/gpio_cmsdk_drv.c
Native_Driver/uart_pl011_drv.c
Native_Driver/musca_s1_scc_drv.c
+ Native_Driver/qspi_ip6514e_drv.c
Native_Driver/cache_drv.c
spm_hal.c
tfm_hal_isolation.c
target_cfg.c
Native_Driver/timer_cmsdk_drv.c
+ Libraries/mt25ql_flash_lib.c
${CMAKE_SOURCE_DIR}/platform/ext/common/tfm_hal_isolation_mpu_v8m.c
$<$<BOOL:${TFM_PARTITION_PLATFORM}>:${CMAKE_CURRENT_SOURCE_DIR}/plat_test.c>
$<$<BOOL:${TFM_PARTITION_PLATFORM}>:${CMAKE_CURRENT_SOURCE_DIR}/services/src/tfm_platform_system.c>
@@ -121,6 +125,7 @@ target_include_directories(platform_ns
Device/Include
Native_Driver
services/include
+ Libraries
)
#========================= Platform BL2 =======================================#
@@ -143,6 +148,7 @@ if(BL2)
PUBLIC
partition
Device/Include
+ Libraries
PRIVATE
.
CMSIS_Driver/Config
diff --git a/platform/ext/target/musca_s1/Device/Config/device_cfg.h b/platform/ext/target/musca_s1/Device/Config/device_cfg.h
index 4a5e645518..7f9dae1605 100644
--- a/platform/ext/target/musca_s1/Device/Config/device_cfg.h
+++ b/platform/ext/target/musca_s1/Device/Config/device_cfg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2021 Arm Limited. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -68,4 +68,10 @@
/* Default UART baud rate */
#define DEFAULT_UART_BAUDRATE 115200
+/* Cadence QSPI Flash Controller */
+#define QSPI_IP6514E_S
+
+/* MT25QL Flash memory library */
+#define MT25QL_S
+
#endif /* __DEVICE_CFG_H__ */
diff --git a/platform/ext/target/musca_s1/Device/Include/device_definition.h b/platform/ext/target/musca_s1/Device/Include/device_definition.h
index 2e589f509d..b0a7828d98 100644
--- a/platform/ext/target/musca_s1/Device/Include/device_definition.h
+++ b/platform/ext/target/musca_s1/Device/Include/device_definition.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2021 Arm Limited. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -188,6 +188,17 @@ extern struct spi_ip6524_dev_t SPI0_DEV_S;
extern struct spi_ip6524_dev_t SPI0_DEV_NS;
#endif
+/* QSPI Flash Controller driver structures */
+#ifdef QSPI_IP6514E_S
+#include "qspi_ip6514e_drv.h"
+extern struct qspi_ip6514e_dev_t QSPI_DEV_S;
+#endif
+
+#ifdef QSPI_IP6514E_NS
+#include "qspi_ip6514e_drv.h"
+extern struct qspi_ip6514e_dev_t QSPI_DEV_NS;
+#endif
+
/* ARM PPC driver structures */
#ifdef AHB_PPC0_S
#include "ppc_sse200_drv.h"
@@ -235,6 +246,19 @@ extern struct musca_s1_scc_dev_t MUSCA_S1_SCC_DEV_NS;
extern struct arm_cache_dev_t SSE_200_CACHE_DEV_S;
#endif
+/* ======= External peripheral configuration structure declarations ======= */
+
+/* MT25QL Flash memory library structures */
+#if (defined(MT25QL_NS) && defined(QSPI_IP6514E_NS))
+#include "mt25ql_flash_lib.h"
+extern struct mt25ql_dev_t MT25QL_DEV_NS;
+#endif
+
+#if (defined(MT25QL_S) && defined(QSPI_IP6514E_S))
+#include "mt25ql_flash_lib.h"
+extern struct mt25ql_dev_t MT25QL_DEV_S;
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/platform/ext/target/musca_s1/Device/Source/device_definition.c b/platform/ext/target/musca_s1/Device/Source/device_definition.c
index 3176b76c0c..58b1689d96 100644
--- a/platform/ext/target/musca_s1/Device/Source/device_definition.c
+++ b/platform/ext/target/musca_s1/Device/Source/device_definition.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2021 Arm Limited. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -494,3 +494,47 @@ static const struct arm_cache_dev_cfg_t SSE_200_CACHE_CFG_S = {
.base = MUSCA_S1_CPU_ELEMENT_S_BASE};
struct arm_cache_dev_t SSE_200_CACHE_DEV_S = {&(SSE_200_CACHE_CFG_S)};
#endif
+
+/* QSPI IP6514E driver structures */
+#ifdef QSPI_IP6514E_NS
+static const struct qspi_ip6514e_dev_cfg_t QSPI_DEV_CFG_NS = {
+ .base = MUSCA_S1_QSPI_REG_NS_BASE,
+ .addr_mask = (1U << 25) - 1,
+};
+struct qspi_ip6514e_dev_t QSPI_DEV_NS = {
+ &QSPI_DEV_CFG_NS
+};
+#endif
+
+#ifdef QSPI_IP6514E_S
+static const struct qspi_ip6514e_dev_cfg_t QSPI_DEV_CFG_S = {
+ .base = MUSCA_S1_QSPI_REG_S_BASE,
+ .addr_mask = (1U << 25) - 1,
+};
+struct qspi_ip6514e_dev_t QSPI_DEV_S = {
+ &QSPI_DEV_CFG_S
+};
+#endif
+
+/* ======= External peripheral configuration structure definitions ======= */
+
+/* MT25QL Flash memory library structures */
+#if (defined(MT25QL_NS) && defined(QSPI_IP6514E_NS))
+struct mt25ql_dev_t MT25QL_DEV_NS = {
+ .controller = &QSPI_DEV_NS,
+ .direct_access_start_addr = MUSCA_S1_QSPI_FLASH_NS_BASE,
+ .baud_rate_div = 4U,
+ .size = 0x02000000U, /* 32 MiB */
+ .config_state = { MT25QL_FUNC_STATE_NOT_INITED },
+};
+#endif
+
+#if (defined(MT25QL_S) && defined(QSPI_IP6514E_S))
+struct mt25ql_dev_t MT25QL_DEV_S = {
+ .controller = &QSPI_DEV_S,
+ .direct_access_start_addr = MUSCA_S1_QSPI_FLASH_S_BASE,
+ .baud_rate_div = 4U,
+ .size = 0x02000000U, /* 32 MiB */
+ .config_state = { MT25QL_FUNC_STATE_NOT_INITED },
+};
+#endif
diff --git a/platform/ext/target/musca_s1/Libraries/mt25ql_flash_lib.c b/platform/ext/target/musca_s1/Libraries/mt25ql_flash_lib.c
new file mode 100644
index 0000000000..f748ecf92f
--- /dev/null
+++ b/platform/ext/target/musca_s1/Libraries/mt25ql_flash_lib.c
@@ -0,0 +1,901 @@
+/*
+ * Copyright (c) 2018-2020 Arm Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+/* Use memcpy function */
+#include <string.h>
+
+#include "mt25ql_flash_lib.h"
+#include "qspi_ip6514e_drv.h"
+
+/** Setter bit manipulation macro */
+#define SET_BIT(WORD, BIT_INDEX) ((WORD) |= (1U << (BIT_INDEX)))
+/** Clearing bit manipulation macro */
+#define CLR_BIT(WORD, BIT_INDEX) ((WORD) &= ~(1U << (BIT_INDEX)))
+/** Getter bit manipulation macro */
+#define GET_BIT(WORD, BIT_INDEX) (bool)(((WORD) & (1U << (BIT_INDEX))))
+
+#define BITS_PER_WORD 32U
+#define BYTES_PER_WORD 4U
+
+#define ARG_NOT_USED 0
+#define ARG_PTR_NOT_USED NULL
+
+/** MT25QL used command */
+#define WRITE_ENABLE_CMD 0x06U
+#define READ_ENHANCED_VOLATILE_CFG_REG_CMD 0x65U
+#define WRITE_ENHANCED_VOLATILE_CFG_REG_CMD 0x61U
+#define READ_VOLATILE_CFG_REG_CMD 0x85U
+#define WRITE_VOLATILE_CFG_REG_CMD 0x81U
+#define READ_FLAG_STATUS_REG_CMD 0x70U
+#define SUBSECTOR_ERASE_32KB_CMD 0x52U
+#define SUBSECTOR_ERASE_4KB_CMD 0x20U
+#define SECTOR_ERASE_CMD 0xD8U
+#define BULK_ERASE_CMD 0xC7U
+/*
+ * The baud rate divisor in \ref mt25ql_dev_t needs to be configured adequately
+ * to handle those commands.
+ */
+#define QUAD_OUTPUT_FAST_READ_CMD 0x6BU
+#define FAST_READ_CMD 0x0BU
+#define READ_CMD 0x03U
+#define QUAD_INPUT_FAST_PROGRAM_CMD 0x32U
+#define PAGE_PROGRAM_CMD 0x02U
+
+/** MT25QL Enhanced Volatile Configuration Register access */
+#define ENHANCED_VOLATILE_CFG_REG_LEN 1U
+#define ENHANCED_VOLATILE_CFG_REG_QSPI_POS 7U
+#define ENHANCED_VOLATILE_CFG_REG_DSPI_POS 6U
+
+/** MT25QL Volatile Configuration Register access */
+#define VOLATILE_CFG_REG_LEN 1U
+#define VOLATILE_CFG_REG_DUMMY_CYCLES_POS 4U
+#define VOLATILE_CFG_REG_DUMMY_CYCLES_BITS 4U
+
+/** MT25QL Flag Status Register access */
+#define FLAG_STATUS_REG_LEN 1U
+#define FLAG_STATUS_REG_READY_POS 7U
+
+/*
+ * 10 is the minimal number of dummy clock cycles needed to reach the maximal
+ * frequency of the Quad Output Fast Read Command.
+ */
+#define QUAD_OUTPUT_FAST_READ_DUMMY_CYCLES 10U
+#define FAST_READ_DUMMY_CYCLES 8U
+#define RESET_STATE_DUMMY_CYCLES 8U
+#define DEFAULT_READ_DUMMY_CYCLES 0U
+#define QUAD_INPUT_FAST_PROGRAM_DUMMY_CYCLES 0U
+#define PAGE_PROGRAM_DUMMY_CYCLES 0U
+
+/* Only up to 8 bytes can be read or written using the Flash commands. */
+#define CMD_DATA_MAX_SIZE 8U
+
+/**
+ * \brief Change specific bits in a 32 bits word.
+ *
+ * \param[in,out] word Pointer of the word to change
+ * \param[in] bits bits_length bits to put at bits_pos in the word
+ * pointed
+ * \param[in] bits_length Number of bits to change
+ * \param[in] bits_pos Position of the bits to change
+ *
+ * \note This function will do nothing if the parameters given are incorrect:
+ * * word is NULL
+ * * bits_length + bits_pos > 32
+ * * bits_length is 0
+ */
+static void change_bits_in_word(volatile uint32_t *word,
+ uint32_t bits,
+ uint32_t bits_length,
+ uint32_t bits_pos)
+{
+ uint32_t mask;
+
+ if ((word == NULL) ||
+ ((bits_length + bits_pos) > BITS_PER_WORD) ||
+ (bits_length == 0U)) {
+ /* Silently fail */
+ return;
+ }
+
+ /* Change all the bits */
+ if (bits_length == BITS_PER_WORD) {
+ *word = bits;
+ return;
+ }
+
+ mask = ((1U << bits_length) - 1);
+ /*
+ * We change the bits in three steps:
+ * - clear bits_length bits with zeroes at bits_pos in the word
+ * - mask bits in case it contains more than bits_length bits
+ * - set the new bits in the cleared word
+ * Because the data pointed by word is only read once, the data will still
+ * be coherent after an interruption that changes it.
+ */
+ *word = ((*word & ~(mask << bits_pos)) | ((bits & mask) << bits_pos));
+}
+
+/**
+ * \brief Send the Write Enable command, needed before any write.
+ *
+ * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t
+ */
+static void send_write_enable(struct mt25ql_dev_t* dev)
+{
+ qspi_ip6514e_send_simple_cmd(dev->controller, WRITE_ENABLE_CMD);
+}
+
+/**
+ * \brief Set SPI mode on the flash device and on the controller.
+ *
+ * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t
+ * \param[in] spi_mode SPI mode to be set on flash device and controller
+ * \ref qspi_ip6514e_spi_mode_t
+ *
+ * \return Return error code as specified in \ref mt25ql_error_t
+ */
+static enum mt25ql_error_t set_spi_mode(struct mt25ql_dev_t* dev,
+ enum qspi_ip6514e_spi_mode_t spi_mode)
+{
+ uint8_t enhanced_volatile_cfg_reg = 0;
+ enum qspi_ip6514e_error_t controller_error;
+
+ /* Read the Enhanced Volatile Configuration Register, modify it according
+ * to the requested SPI mode then write back the modified value to the
+ * register. This will activate the SPI mode on the flash side.
+ */
+ controller_error = qspi_ip6514e_send_read_cmd(
+ dev->controller,
+ READ_ENHANCED_VOLATILE_CFG_REG_CMD,
+ &enhanced_volatile_cfg_reg,
+ ENHANCED_VOLATILE_CFG_REG_LEN,
+ ARG_NOT_USED,
+ ARG_NOT_USED,
+ 0); /* No dummy cycles needed for
+ this command. */
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+
+ switch(spi_mode) {
+ case QSPI_IP6514E_SPI_MODE:
+ /* Disable the Dual- and Quad-SPI modes.
+ * Clearing the bit enables the mode, setting it disables it.
+ */
+ SET_BIT(enhanced_volatile_cfg_reg, ENHANCED_VOLATILE_CFG_REG_DSPI_POS);
+ SET_BIT(enhanced_volatile_cfg_reg, ENHANCED_VOLATILE_CFG_REG_QSPI_POS);
+ break;
+ case QSPI_IP6514E_DSPI_MODE:
+ /* Disable the Quad-SPI mode and activate DSPI mode.
+ * Clearing the bit enables the mode, setting it disables it.
+ */
+ CLR_BIT(enhanced_volatile_cfg_reg, ENHANCED_VOLATILE_CFG_REG_DSPI_POS);
+ SET_BIT(enhanced_volatile_cfg_reg, ENHANCED_VOLATILE_CFG_REG_QSPI_POS);
+ break;
+ case QSPI_IP6514E_QSPI_MODE:
+ /* Disable the Dual-SPI mode and activate QSPI mode.
+ * Clearing the bit enables the mode, setting it disables it.
+ */
+ SET_BIT(enhanced_volatile_cfg_reg, ENHANCED_VOLATILE_CFG_REG_DSPI_POS);
+ CLR_BIT(enhanced_volatile_cfg_reg, ENHANCED_VOLATILE_CFG_REG_QSPI_POS);
+ break;
+ default:
+ return MT25QL_ERR_WRONG_ARGUMENT;
+ }
+
+ send_write_enable(dev);
+
+ controller_error = qspi_ip6514e_send_write_cmd(
+ dev->controller,
+ WRITE_ENHANCED_VOLATILE_CFG_REG_CMD,
+ &enhanced_volatile_cfg_reg,
+ ENHANCED_VOLATILE_CFG_REG_LEN,
+ ARG_NOT_USED,
+ ARG_NOT_USED,
+ 0); /* No dummy cycles needed for
+ this command. */
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+
+ /* Activate the requested SPI mode on the controller side as well. */
+ controller_error = qspi_ip6514e_set_spi_mode(dev->controller,
+ spi_mode,
+ spi_mode,
+ spi_mode);
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+
+ return MT25QL_ERR_NONE;
+}
+
+/**
+ * \brief Change the number of dummy clock cycles subsequent to all FAST READ
+ * commands.
+ *
+ * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t
+ * \param[in] dummy_cycles Dummy clock cycles to set
+ *
+ * \return Return error code as specified in \ref mt25ql_error_t
+ */
+static enum mt25ql_error_t change_dummy_cycles(struct mt25ql_dev_t* dev,
+ uint32_t dummy_cycles)
+{
+ uint32_t volatile_cfg_reg = 0;
+ enum qspi_ip6514e_error_t controller_error;
+
+ /*
+ * Changes the number of dummy cycles in the Volatile Configuration
+ * Register.
+ */
+ controller_error = qspi_ip6514e_send_read_cmd(dev->controller,
+ READ_VOLATILE_CFG_REG_CMD,
+ &volatile_cfg_reg,
+ VOLATILE_CFG_REG_LEN,
+ ARG_NOT_USED,
+ ARG_NOT_USED,
+ 0); /* No dummy cycles needed
+ for this command. */
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+
+ change_bits_in_word(&volatile_cfg_reg,
+ dummy_cycles,
+ VOLATILE_CFG_REG_DUMMY_CYCLES_BITS,
+ VOLATILE_CFG_REG_DUMMY_CYCLES_POS);
+
+ send_write_enable(dev);
+
+ controller_error = qspi_ip6514e_send_write_cmd(dev->controller,
+ WRITE_VOLATILE_CFG_REG_CMD,
+ &volatile_cfg_reg,
+ VOLATILE_CFG_REG_LEN,
+ ARG_NOT_USED,
+ ARG_NOT_USED,
+ 0); /* No dummy cycles needed
+ for this command. */
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+
+ return MT25QL_ERR_NONE;
+}
+
+/**
+ * \brief Wait until the current program/erase is finished.
+ *
+ * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t
+ *
+ * \return Return error code as specified in \ref mt25ql_error_t
+ */
+static enum mt25ql_error_t wait_program_or_erase_complete(
+ struct mt25ql_dev_t* dev)
+{
+ enum qspi_ip6514e_error_t controller_error;
+ uint8_t flag_status_reg = 0;
+
+ /* Wait until the ready bit of the Flag Status Register is set */
+ while (!GET_BIT(flag_status_reg, FLAG_STATUS_REG_READY_POS)) {
+ controller_error = qspi_ip6514e_send_read_cmd(dev->controller,
+ READ_FLAG_STATUS_REG_CMD,
+ &flag_status_reg,
+ FLAG_STATUS_REG_LEN,
+ ARG_NOT_USED,
+ ARG_NOT_USED,
+ 0); /* No dummy cycles
+ needed for this
+ command. */
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+ }
+
+ return MT25QL_ERR_NONE;
+}
+
+/**
+ * \brief Execute a program command that crosses the page size boundary.
+ *
+ * \param[in] dev Pointer to MT25QL device structure
+ * \ref mt25ql_dev_t
+ * \param[in] opcode Opcode for the command.
+ * \param[in] write_data Pointer to a memory zone where the write_len
+ * number of bytes are located to write for this
+ * command.
+ * \param[in] write_len Number of bytes to write for the command.
+ * Between 1 and 8 bytes (both included) can be
+ * written.
+ * \param[in] addr Address used for the command
+ * \param[in] addr_bytes_number Number of address bytes for this command.
+ * If an address is not needed for the command,
+ * use 0 for argument, otherwise between 1 and
+ * 4 bytes (both included) can be used.
+ * \param[in] dummy_cycles Number of dummy cycles required for the
+ * command, between 0 and 31 (both included).
+ *
+ * \return Return error code as specified in \ref mt25ql_error_t
+ *
+ * \note This function will execute two commands: one to program the bytes up to
+ * the page boundary and another one to program the rest. It will wait
+ * that bytes are programmed from first command before triggering the
+ * second one.
+ * \note This function does not send a write enable command before the first
+ * command and does not check that bytes were programmed after the second
+ * command.
+ */
+static enum mt25ql_error_t send_boundary_cross_write_cmd(
+ struct mt25ql_dev_t* dev,
+ uint8_t opcode,
+ const void *write_data,
+ uint32_t write_len,
+ uint32_t addr,
+ uint32_t addr_bytes_number,
+ uint32_t dummy_cycles)
+{
+ enum qspi_ip6514e_error_t controller_error;
+ enum mt25ql_error_t library_error;
+ /*
+ * Remaining bytes between the current address and the end of the current
+ * page.
+ */
+ uint32_t page_remainder = FLASH_PAGE_SIZE - (addr % FLASH_PAGE_SIZE);
+
+ /* First write up to the end of the current page. */
+ controller_error = qspi_ip6514e_send_write_cmd(dev->controller, opcode,
+ write_data, page_remainder,
+ addr, addr_bytes_number,
+ dummy_cycles);
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+
+ write_data = (void *)((uint32_t)write_data + page_remainder);
+ addr += page_remainder;
+
+ /* Wait for the page to be written before sending new commands. */
+ library_error = wait_program_or_erase_complete(dev);
+ if (library_error != MT25QL_ERR_NONE) {
+ return library_error;
+ }
+
+ /* Then write the remaining data of the write_len bytes. */
+ send_write_enable(dev);
+ controller_error = qspi_ip6514e_send_write_cmd(dev->controller, opcode,
+ write_data,
+ write_len - page_remainder,
+ addr, addr_bytes_number,
+ dummy_cycles);
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+
+ return MT25QL_ERR_NONE;
+}
+
+enum mt25ql_error_t mt25ql_config_mode(struct mt25ql_dev_t* dev,
+ enum mt25ql_functional_state_t f_state)
+{
+ enum qspi_ip6514e_error_t controller_error;
+ enum mt25ql_error_t library_error;
+
+ switch(f_state) {
+ case MT25QL_FUNC_STATE_DEFAULT:
+ dev->config_state.spi_mode = QSPI_IP6514E_SPI_MODE;
+ dev->config_state.opcode_read = READ_CMD;
+ dev->config_state.dummy_cycles_read = DEFAULT_READ_DUMMY_CYCLES;
+ dev->config_state.opcode_write = PAGE_PROGRAM_CMD;
+ dev->config_state.dummy_cycles_write = PAGE_PROGRAM_DUMMY_CYCLES;
+ break;
+ case MT25QL_FUNC_STATE_FAST:
+ dev->config_state.spi_mode = QSPI_IP6514E_SPI_MODE;
+ dev->config_state.opcode_read = FAST_READ_CMD;
+ dev->config_state.dummy_cycles_read = FAST_READ_DUMMY_CYCLES;
+ dev->config_state.opcode_write = PAGE_PROGRAM_CMD;
+ dev->config_state.dummy_cycles_write = PAGE_PROGRAM_DUMMY_CYCLES;
+ break;
+ case MT25QL_FUNC_STATE_QUAD_FAST:
+ dev->config_state.spi_mode = QSPI_IP6514E_QSPI_MODE;
+ dev->config_state.opcode_read = QUAD_OUTPUT_FAST_READ_CMD;
+ dev->config_state.dummy_cycles_read =
+ QUAD_OUTPUT_FAST_READ_DUMMY_CYCLES;
+ dev->config_state.opcode_write = QUAD_INPUT_FAST_PROGRAM_CMD;
+ dev->config_state.dummy_cycles_write =
+ QUAD_INPUT_FAST_PROGRAM_DUMMY_CYCLES;
+ break;
+ default:
+ return MT25QL_ERR_WRONG_ARGUMENT;
+ }
+
+ dev->config_state.func_state = f_state;
+
+ /* This function will first set the Flash memory SPI mode and then set
+ * the controller's SPI mode. It will fail if the two sides do not have
+ * the same mode when this function is called.
+ */
+ library_error = set_spi_mode(dev, dev->config_state.spi_mode);
+ if (library_error != MT25QL_ERR_NONE) {
+ return library_error;
+ }
+
+ /* Set the number of dummy cycles for read commands. */
+ library_error = change_dummy_cycles(
+ dev, dev->config_state.dummy_cycles_read);
+ if (library_error != MT25QL_ERR_NONE) {
+ return library_error;
+ }
+
+ /* The rest of the configuration needs the controller to be disabled */
+ while(!qspi_ip6514e_is_idle(dev->controller));
+ qspi_ip6514e_disable(dev->controller);
+
+ /* Set the baud rate divisor as configured in the device structure. */
+ controller_error = qspi_ip6514e_set_baud_rate_div(dev->controller,
+ dev->baud_rate_div);
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+
+ /* Set opcode and dummy cycles needed for read commands. */
+ controller_error = qspi_ip6514e_cfg_reads(
+ dev->controller, dev->config_state.opcode_read,
+ dev->config_state.dummy_cycles_read);
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+
+ /* Set opcode and dummy cycles needed for write commands. */
+ controller_error = qspi_ip6514e_cfg_writes(
+ dev->controller, dev->config_state.opcode_write,
+ dev->config_state.dummy_cycles_write);
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+
+ /* Set Flash memory constants: bytes per page and address bytes. */
+ controller_error = qspi_ip6514e_cfg_page_size(dev->controller,
+ FLASH_PAGE_SIZE);
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+
+ controller_error = qspi_ip6514e_cfg_addr_bytes(dev->controller,
+ ADDR_BYTES);
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+
+ qspi_ip6514e_enable(dev->controller);
+
+ return MT25QL_ERR_NONE;
+}
+
+enum mt25ql_error_t mt25ql_restore_reset_state(struct mt25ql_dev_t* dev)
+{
+ enum mt25ql_error_t library_error;
+
+ /*
+ * This function will first change the Flash memory mode to single SPI and
+ * then change the controller to single SPI. It will fail if the two sides
+ * do not have the same mode when this function is called.
+ */
+ library_error = set_spi_mode(dev, QSPI_IP6514E_SPI_MODE);
+ if (library_error != MT25QL_ERR_NONE) {
+ return library_error;
+ }
+
+ /* Set the default number of dummy cycles for direct read commands. */
+ library_error = change_dummy_cycles(dev, RESET_STATE_DUMMY_CYCLES);
+ if (library_error != MT25QL_ERR_NONE) {
+ return library_error;
+ }
+
+ /* The rest of the configuration needs the controller to be disabled */
+ while(!qspi_ip6514e_is_idle(dev->controller));
+ qspi_ip6514e_disable(dev->controller);
+
+ /* Restore the default value of the QSPI controller registers. */
+ qspi_ip6514e_reset_regs(dev->controller);
+
+ qspi_ip6514e_enable(dev->controller);
+
+ dev->config_state = (struct mt25ql_config_state_t){ MT25QL_FUNC_STATE_NOT_INITED };
+ dev->config_state.func_state = MT25QL_FUNC_STATE_NOT_INITED;
+
+ return MT25QL_ERR_NONE;
+}
+
+enum mt25ql_error_t mt25ql_direct_read(struct mt25ql_dev_t* dev,
+ uint32_t addr,
+ void *data,
+ uint32_t len)
+{
+ /*
+ * The direct access window size is the size of the memory that can be
+ * accessed with a direct access.
+ */
+ uint32_t direct_access_window_size = dev->controller->cfg->addr_mask + 1;
+ /*
+ * The window number is the number of times it will be needed to remap the
+ * address with the remap register. We move this Direct Access window first
+ * window_number times starting at the beginning address to read full
+ * windows of direct_access_window_size bytes. Then we read the remainder
+ * bytes.
+ */
+ uint32_t window_number = len / direct_access_window_size;
+
+ if (data == NULL || len == 0) {
+ return MT25QL_ERR_WRONG_ARGUMENT;
+ }
+
+ if ((addr + len) >= dev->size) {
+ return MT25QL_ERR_ADDR_TOO_BIG;
+ }
+
+ /*
+ * There is no limitation reading through a Flash page boundary hence we
+ * do not add the same logic here than in the write function.
+ */
+
+ /* Transfer the bytes for the window_number windows first. */
+ for (uint32_t window = 0; window < window_number; window++) {
+ qspi_ip6514e_remap_addr(dev->controller, addr);
+
+ /*
+ * The AHB address to access the Flash memory does not change but it
+ * will be translated differently thanks to the remap function.
+ */
+ memcpy(data,
+ (void *)dev->direct_access_start_addr,
+ direct_access_window_size);
+
+ len -= direct_access_window_size;
+ data = (void *)((uint32_t)data + direct_access_window_size);
+ addr += direct_access_window_size;
+ }
+
+ if (len) {
+ /* Transfer the reminder bytes */
+ qspi_ip6514e_remap_addr(dev->controller, addr);
+
+ memcpy(data, (void *)dev->direct_access_start_addr, len);
+ }
+
+ /* Disable remapping for direct accesses outside of this function. */
+ qspi_ip6514e_disable_remap(dev->controller);
+
+ return MT25QL_ERR_NONE;
+}
+
+enum mt25ql_error_t mt25ql_direct_write(struct mt25ql_dev_t* dev,
+ uint32_t addr,
+ const void *data,
+ uint32_t len)
+{
+ enum mt25ql_error_t library_error;
+ /*
+ * The direct access window size is the size of the memory that can be
+ * accessed with a direct access.
+ */
+ uint32_t direct_access_window_size = dev->controller->cfg->addr_mask + 1;
+ uint32_t window_number;
+ /* Offset between address and the previous 32 bits aligned word */
+ uint32_t word_offset;
+
+ if (data == NULL || len == 0) {
+ return MT25QL_ERR_WRONG_ARGUMENT;
+ }
+
+ if ((addr + len) >= dev->size) {
+ return MT25QL_ERR_ADDR_TOO_BIG;
+ }
+
+ /*
+ * If the remapping address is not aligned on a 32 bits boundary, a direct
+ * access of one word could cross a Flash page boundary. If that happens,
+ * the bytes of that word that are over the page boundary will instead be
+ * written at the beginning of the same page.
+ * To counter this problem, we align the remapping address and add the word
+ * offset to the address of the direct access for the first window only.
+ */
+ word_offset = addr % BYTES_PER_WORD;
+ /* Make address aligned on a 32 bits alignment. */
+ addr -= word_offset;
+ /*
+ * Only direct_access_window_size address locations are available by direct
+ * access. We calculate the number of windows that we will need to transfer
+ * len bytes. We have to add in the window the offset that we add in the
+ * beginning.
+ */
+ window_number = (len + word_offset) / direct_access_window_size;
+
+ /*
+ * This function assumes that the flash has already been erased.
+ * Transfer the bytes for the window_number windows first.
+ */
+ for (uint32_t window = 0; window < window_number; window++) {
+ /* The controller needs to be disabled while remapping is done. */
+ qspi_ip6514e_remap_addr(dev->controller, addr);
+
+ /*
+ * The AHB address to access the Flash memory does not change but it
+ * will be translated differently thanks to the remap function.
+ */
+ memcpy((void *)(dev->direct_access_start_addr + word_offset),
+ data,
+ direct_access_window_size - word_offset);
+
+ len -= (direct_access_window_size - word_offset);
+ data = (void *)((uint32_t)data +
+ (direct_access_window_size - word_offset));
+ addr += direct_access_window_size;
+
+ /*
+ * The address is now aligned, there is no need to add an offset for the
+ * remaining windows.
+ */
+ word_offset = 0;
+
+ /*
+ * Wait until the last program operation is complete before changing
+ * the remap address.
+ */
+ library_error = wait_program_or_erase_complete(dev);
+ if (library_error != MT25QL_ERR_NONE) {
+ return library_error;
+ }
+ }
+
+ if (len) {
+ /* Transfer the reminder bytes */
+ qspi_ip6514e_remap_addr(dev->controller, addr);
+
+ memcpy((void *)(dev->direct_access_start_addr + word_offset),
+ data,
+ len);
+
+ /* Wait until the last program operation is complete */
+ library_error = wait_program_or_erase_complete(dev);
+ if (library_error != MT25QL_ERR_NONE) {
+ return library_error;
+ }
+ }
+
+ /*
+ * Disable the default remap address for direct accesses outside of this
+ * function.
+ */
+ qspi_ip6514e_disable_remap(dev->controller);
+
+ return MT25QL_ERR_NONE;
+}
+
+enum mt25ql_error_t mt25ql_command_read(struct mt25ql_dev_t* dev,
+ uint32_t addr,
+ void *data,
+ uint32_t len)
+{
+ /* With one single command only 8 bytes can be read. */
+ uint32_t cmd_number = len / CMD_DATA_MAX_SIZE;
+ enum qspi_ip6514e_error_t controller_error;
+
+ if (dev->config_state.func_state == MT25QL_FUNC_STATE_NOT_INITED) {
+ return MT25QL_ERR_NOT_INITED;
+ }
+
+ for (uint32_t cmd_index = 0; cmd_index < cmd_number; cmd_index++) {
+ controller_error = qspi_ip6514e_send_read_cmd(
+ dev->controller,
+ dev->config_state.opcode_read,
+ data, CMD_DATA_MAX_SIZE, addr,
+ ADDR_BYTES,
+ dev->config_state.dummy_cycles_read);
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+
+ data = (void *)((uint32_t)data + CMD_DATA_MAX_SIZE);
+ addr += CMD_DATA_MAX_SIZE;
+ len -= CMD_DATA_MAX_SIZE;
+ }
+
+ if (len) {
+ /* Read the remainder. */
+ controller_error = qspi_ip6514e_send_read_cmd(
+ dev->controller,
+ dev->config_state.opcode_read,
+ data, len, addr, ADDR_BYTES,
+ dev->config_state.dummy_cycles_read);
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+ }
+
+ return MT25QL_ERR_NONE;
+
+}
+
+enum mt25ql_error_t mt25ql_command_write(struct mt25ql_dev_t* dev,
+ uint32_t addr,
+ const void *data,
+ uint32_t len)
+{
+ /* With one single command only 8 bytes can be written. */
+ uint32_t cmd_number = len / CMD_DATA_MAX_SIZE;
+ enum qspi_ip6514e_error_t controller_error;
+ enum mt25ql_error_t library_error;
+
+ if (dev->config_state.func_state == MT25QL_FUNC_STATE_NOT_INITED) {
+ return MT25QL_ERR_NOT_INITED;
+ }
+
+ for (uint32_t cmd_index = 0; cmd_index < cmd_number; cmd_index++) {
+ send_write_enable(dev);
+
+ /*
+ * Check if this command is not writing over a page boundary: first and
+ * last bytes are in the same page.
+ */
+ if ((addr / FLASH_PAGE_SIZE) !=
+ ((addr + CMD_DATA_MAX_SIZE - 1) / FLASH_PAGE_SIZE)) {
+ /* The CMD_DATA_MAX_SIZE bytes written are crossing the boundary. */
+ library_error = send_boundary_cross_write_cmd(
+ dev, dev->config_state.opcode_write,
+ data, CMD_DATA_MAX_SIZE, addr,
+ ADDR_BYTES,
+ dev->config_state.dummy_cycles_write);
+ if (library_error != MT25QL_ERR_NONE) {
+ return library_error;
+ }
+ } else {
+ /* Normal case: not crossing the boundary. */
+ controller_error = qspi_ip6514e_send_write_cmd(
+ dev->controller,
+ dev->config_state.opcode_write,
+ data, CMD_DATA_MAX_SIZE, addr,
+ ADDR_BYTES,
+ dev->config_state.dummy_cycles_write);
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+ }
+
+ /* Wait until the write operation is complete. */
+ library_error = wait_program_or_erase_complete(dev);
+ if (library_error != MT25QL_ERR_NONE) {
+ return library_error;
+ }
+
+ data = (void *)((uint32_t)data + CMD_DATA_MAX_SIZE);
+ addr += CMD_DATA_MAX_SIZE;
+ len -= CMD_DATA_MAX_SIZE;
+ }
+
+ if (len) {
+ /* Write the remainder. */
+ send_write_enable(dev);
+ /*
+ * Check if this command is not writing over a page boundary: first and
+ * last bytes are in the same page.
+ */
+ if ((addr / FLASH_PAGE_SIZE) != ((addr + len - 1) / FLASH_PAGE_SIZE)) {
+ /* The CMD_DATA_MAX_SIZE bytes written are crossing the boundary. */
+ library_error = send_boundary_cross_write_cmd(
+ dev, dev->config_state.opcode_write,
+ data, len, addr, ADDR_BYTES,
+ dev->config_state.dummy_cycles_write);
+ if (library_error != MT25QL_ERR_NONE) {
+ return library_error;
+ }
+ } else {
+ /* Normal case: not crossing the boundary. */
+ controller_error = qspi_ip6514e_send_write_cmd(
+ dev->controller,
+ dev->config_state.opcode_write,
+ data, len, addr, ADDR_BYTES,
+ dev->config_state.dummy_cycles_write);
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+ }
+
+ /* Wait until the write operation is complete. */
+ library_error = wait_program_or_erase_complete(dev);
+ if (library_error != MT25QL_ERR_NONE) {
+ return library_error;
+ }
+ }
+
+ return MT25QL_ERR_NONE;
+
+}
+
+enum mt25ql_error_t mt25ql_erase(struct mt25ql_dev_t* dev,
+ uint32_t addr,
+ enum mt25ql_erase_t erase_type)
+{
+ enum qspi_ip6514e_error_t controller_error;
+ enum mt25ql_error_t library_error;
+ uint8_t erase_cmd;
+ uint32_t addr_bytes;
+
+ if (dev->config_state.func_state == MT25QL_FUNC_STATE_NOT_INITED) {
+ return MT25QL_ERR_NOT_INITED;
+ }
+
+ send_write_enable(dev);
+
+ switch (erase_type) {
+ case MT25QL_ERASE_ALL_FLASH:
+ if (addr != 0) {
+ return MT25QL_ERR_ADDR_NOT_ALIGNED;
+ }
+ erase_cmd = BULK_ERASE_CMD;
+ addr_bytes = ARG_NOT_USED;
+ break;
+ case MT25QL_ERASE_SECTOR_64K:
+ erase_cmd = SECTOR_ERASE_CMD;
+ addr_bytes = ADDR_BYTES;
+ if ((addr % SECTOR_64KB) != 0) {
+ return MT25QL_ERR_ADDR_NOT_ALIGNED;
+ }
+ break;
+ case MT25QL_ERASE_SUBSECTOR_32K:
+ erase_cmd = SUBSECTOR_ERASE_32KB_CMD;
+ addr_bytes = ADDR_BYTES;
+ if ((addr % SUBSECTOR_32KB) != 0) {
+ return MT25QL_ERR_ADDR_NOT_ALIGNED;
+ }
+ break;
+ case MT25QL_ERASE_SUBSECTOR_4K:
+ erase_cmd = SUBSECTOR_ERASE_4KB_CMD;
+ addr_bytes = ADDR_BYTES;
+ if ((addr % SUBSECTOR_4KB) != 0) {
+ return MT25QL_ERR_ADDR_NOT_ALIGNED;
+ }
+ break;
+ default:
+ return MT25QL_ERR_WRONG_ARGUMENT;
+ }
+
+ if (addr >= dev->size) {
+ return MT25QL_ERR_ADDR_TOO_BIG;
+ }
+
+ controller_error = qspi_ip6514e_send_cmd(dev->controller,
+ erase_cmd,
+ ARG_PTR_NOT_USED,
+ ARG_NOT_USED,
+ ARG_PTR_NOT_USED,
+ ARG_NOT_USED,
+ addr,
+ addr_bytes,
+ 0); /* No dummy cycles needed for
+ any erase command. */
+ if (controller_error != QSPI_IP6514E_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+
+ /* Wait until the erase operation is complete */
+ library_error = wait_program_or_erase_complete(dev);
+ if (library_error != MT25QL_ERR_NONE) {
+ return (enum mt25ql_error_t)controller_error;
+ }
+
+ return MT25QL_ERR_NONE;
+}
diff --git a/platform/ext/target/musca_s1/Libraries/mt25ql_flash_lib.h b/platform/ext/target/musca_s1/Libraries/mt25ql_flash_lib.h
new file mode 100644
index 0000000000..c2dac2ca21
--- /dev/null
+++ b/platform/ext/target/musca_s1/Libraries/mt25ql_flash_lib.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2018-2019 Arm Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This library provides functions to control the MT25QL256ABA-1EW7-OSIT flash
+ * memory from Micron and should work for similar devices from the same vendor.
+ */
+
+#ifndef __MT25QL_H__
+#define __MT25QL_H__
+
+#include "qspi_ip6514e_drv.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief MT25QL Flash Memory documentation defined values.
+ */
+#define FLASH_PAGE_SIZE (256U) /* 256B */
+#define SUBSECTOR_4KB (0x00001000U) /* 4KB */
+#define SUBSECTOR_32KB (0x00008000U) /* 32KB */
+#define SECTOR_64KB (0x00010000U) /* 64KB */
+#define ADDR_BYTES (3U)
+
+enum mt25ql_error_t {
+ MT25QL_ERR_NONE = QSPI_IP6514E_ERR_NONE,
+ MT25QL_ERR_WRONG_ARGUMENT = QSPI_IP6514E_ERR_WRONG_ARGUMENT,
+ MT25QL_ERR_CTRL_NOT_DISABLED = QSPI_IP6514E_ERR_CONTROLLER_NOT_DISABLED,
+ MT25QL_ERR_READ_IN_PROGRESS = QSPI_IP6514E_ERR_READ_IN_PROGRESS,
+ MT25QL_ERR_WRITE_IN_PROGRESS = QSPI_IP6514E_ERR_WRITE_IN_PROGRESS,
+ MT25QL_ERR_ADDR_NOT_ALIGNED,
+ MT25QL_ERR_NOT_INITED,
+ MT25QL_ERR_ADDR_TOO_BIG,
+};
+
+enum mt25ql_erase_t {
+ MT25QL_ERASE_ALL_FLASH = 0U, /*!< Erase all flash */
+ MT25QL_ERASE_SUBSECTOR_4K = SUBSECTOR_4KB, /*!< Erase a 4 KB subsector */
+ MT25QL_ERASE_SUBSECTOR_32K = SUBSECTOR_32KB, /*!< Erase a 32 KB subsector */
+ MT25QL_ERASE_SECTOR_64K = SECTOR_64KB, /*!< Erase a sector (64 KB) */
+};
+
+enum mt25ql_functional_state_t {
+ MT25QL_FUNC_STATE_NOT_INITED = 0U,
+ /*!< QSPI Flash controller is not initialized, only direct read
+ * is guaranteed to be working
+ */
+ MT25QL_FUNC_STATE_DEFAULT = 1U,
+ /*!< The QSPI Flash controller and memory is in default state,
+ * using basic read/write commands
+ */
+ MT25QL_FUNC_STATE_FAST = 2U,
+ /*!< The QSPI Flash controller and memory is configured to operate in
+ * single SPI mode and fast Flash commands could be used for read and
+ * program operations.
+ */
+ MT25QL_FUNC_STATE_QUAD_FAST = 3U,
+ /*!< The QSPI Flash controller and memory is configured to operate in
+ * Quad SPI mode and fast Flash commands could be used for read and
+ * program operations.
+ */
+};
+
+struct mt25ql_config_state_t {
+ enum mt25ql_functional_state_t func_state;
+ /*!< Functional state id */
+ enum qspi_ip6514e_spi_mode_t spi_mode;
+ /*!< SPI mode for the current functional state */
+ uint8_t opcode_read;
+ /*!< Read opcode for the current functional state */
+ uint8_t opcode_write;
+ /*!< Write opcode for the current functional state */
+ uint32_t dummy_cycles_read;
+ /*!< Dummy cycles for the read command for the current functional state */
+ uint32_t dummy_cycles_write;
+ /*!< Dummy cycles for the write command for the current functional state */
+};
+
+struct mt25ql_dev_t {
+ struct qspi_ip6514e_dev_t *controller;
+ /*!< QSPI Flash controller. */
+ uint32_t direct_access_start_addr;
+ /*!< AHB address to directly access the contents of the Flash memory
+ * through the QSPI Controller.
+ */
+ uint32_t baud_rate_div;
+ /*!< Clock divisor that will be used to configure the QSPI Flash
+ * Controller to access the Flash memory. The clock which frequency is
+ * divived is the one linked to the QSPI Flash controller. It can only
+ * be an even number between 2 and 32 (both included). It needs to be
+ * high enough to support the Quad Output Fast Read command with 8
+ * dummy cycles and the Quad Input Fast Program with 0 dummy cycles.
+ */
+ uint32_t size; /*!< Total size of the MT25QL Flash memory */
+ struct mt25ql_config_state_t config_state;
+ /*!< Configured functional state (with parameter settings) of the
+ * QSPI Flash controller and memory.
+ */
+
+};
+
+/**
+ * \brief Change configuration of the QSPI Flash controller and MT25QL memory
+ *
+ * Changes the configuration of the QSPI Flash controller and MT25QL
+ * Flash memory to operate in the specified SPI mode and to use the
+ * appropriate Flash commands for read and program operations.
+ * It also sets:
+ * + The number of dummy cycles for each operation
+ * + The bytes per page constant to 256 (MT25QL Flash specific)
+ * + The number of address bytes to 3
+ *
+ * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t
+ * \param[in] f_state Functional state to be set on flash controller
+ * and device \ref mt25ql_functional_state_t
+ *
+ * \return Return error code as specified in \ref mt25ql_error_t
+ *
+ * \note This function assumes that the Flash memory device and the QSPI Flash
+ * controller operates with the same SPI protocol. This function will fail
+ * if the Flash device is in a different configuration.
+ */
+enum mt25ql_error_t mt25ql_config_mode(struct mt25ql_dev_t* dev,
+ enum mt25ql_functional_state_t f_state);
+
+/**
+ * \brief Restore the QSPI Flash controller and MT25QL to reset state.
+ *
+ * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t
+ *
+ * \return Return error code as specified in \ref mt25ql_error_t
+ *
+ * \note This function assumes that the Flash memory device and the QSPI Flash
+ * controller operates with the same SPI protocol. This function will fail
+ * if the Flash device is in a different configuration.
+ */
+enum mt25ql_error_t mt25ql_restore_reset_state(struct mt25ql_dev_t* dev);
+
+/**
+ * \brief Read bytes from the flash memory (direct access)
+ *
+ * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t
+ * \param[in] addr Flash memory address for the read operation
+ * \param[out] data Pointer where len bytes read from the flash memory will be
+ * written to
+ * \param[in] len Number of bytes to read
+ *
+ * \return Return error code as specified in \ref mt25ql_error_t
+ *
+ * \note This function will use direct access to read from the Flash memory. It
+ * can be used to access above the direct accessible memory zone if
+ * not all the AHB address wires are connected.
+ * \note The address given should be the address of the data inside the flash
+ * memory. To read the first byte inside the memory, use 0x00000000.
+ */
+enum mt25ql_error_t mt25ql_direct_read(struct mt25ql_dev_t* dev,
+ uint32_t addr,
+ void *data,
+ uint32_t len);
+
+/**
+ * \brief Write bytes in the flash memory, at a location where data has already
+ * been erased (direct access)
+ *
+ * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t
+ * \param[in] addr Flash memory address for the write operation
+ * \param[in] data Pointer to the len bytes that will be written to the flash
+ * memory
+ * \param[in] len Number of bytes to write
+ *
+ * \return Return error code as specified in \ref mt25ql_error_t
+ *
+ * \note This function will use direct access to write to the Flash memory. It
+ * can be used to access outside of the direct accessible memory zone if
+ * not all the AHB address wires are connected.
+ * \note The address given should be the address of the data inside the flash
+ * memory. To write the first byte inside the memory, use 0x00000000.
+ * \note Writing bytes in the flash memory clear them from 1 to 0, for that
+ * matter the location where data is written needs to be erased
+ * beforehand.
+ */
+enum mt25ql_error_t mt25ql_direct_write(struct mt25ql_dev_t* dev,
+ uint32_t addr,
+ const void *data,
+ uint32_t len);
+
+/**
+ * \brief Read bytes from the flash memory (using Flash commands)
+ *
+ * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t
+ * \param[in] addr Flash memory address for the read operation
+ * \param[out] data Pointer where len bytes read from the flash memory will be
+ * written to
+ * \param[in] len Number of bytes to read
+ *
+ * \return Return error code as specified in \ref mt25ql_error_t
+ *
+ * \note This function will use the Software Triggered Instruction Generator to
+ * read from the Flash memory using Flash commands.
+ * \note The address given should be the address of the data inside the flash
+ * memory. To read the first byte inside the memory, use 0x00000000.
+ */
+enum mt25ql_error_t mt25ql_command_read(struct mt25ql_dev_t* dev,
+ uint32_t addr,
+ void *data,
+ uint32_t len);
+
+/**
+ * \brief Write bytes in the flash memory, at a location where data has already
+ * been erased (using Flash commands)
+ *
+ * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t
+ * \param[in] addr Flash memory address for the write operation
+ * \param[in] data Pointer to the len bytes that will be written to the flash
+ * memory
+ * \param[in] len Number of bytes to write
+ *
+ * \return Return error code as specified in \ref mt25ql_error_t
+ *
+ * \note This function will use the Software Triggered Instruction Generator to
+ * write to the Flash memory using Flash commands.
+ * \note The address given should be the address of the data inside the flash
+ * memory. To write the first byte inside the memory, use 0x00000000.
+ * \note Writing bytes in the flash memory clear them from 1 to 0, for that
+ * matter the location where data is written needs to be erased
+ * beforehand.
+ */
+enum mt25ql_error_t mt25ql_command_write(struct mt25ql_dev_t* dev,
+ uint32_t addr,
+ const void *data,
+ uint32_t len);
+
+/**
+ * \brief Erase all flash memory, a sector (64 KiB) or a subsector
+ * (32 KiB or 4 KiB)
+ *
+ * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t
+ * \param[in] addr Address where to erase in the flash memory
+ * \param[in] erase_type Type of what to erase at the specified address:
+ * * whole flash memory
+ * * a subsector (4 KiB or 32 KiB)
+ * * a sector (64 KiB)
+ * \return Return error code as specified in \ref mt25ql_error_t
+ *
+ * \note The address need to be aligned with the size of what is erased or 0 if
+ * all flash memory is to be erased.
+ */
+enum mt25ql_error_t mt25ql_erase(struct mt25ql_dev_t* dev,
+ uint32_t addr,
+ enum mt25ql_erase_t erase_type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MT25QL_H__ */
diff --git a/platform/ext/target/musca_s1/Native_Driver/qspi_ip6514e_drv.c b/platform/ext/target/musca_s1/Native_Driver/qspi_ip6514e_drv.c
new file mode 100644
index 0000000000..bb13a4219b
--- /dev/null
+++ b/platform/ext/target/musca_s1/Native_Driver/qspi_ip6514e_drv.c
@@ -0,0 +1,755 @@
+/*
+ * Copyright (c) 2018-2019 Arm Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+/* Use memcpy */
+#include <string.h>
+
+#include "qspi_ip6514e_drv.h"
+
+/** Setter bit manipulation macro */
+#define SET_BIT(WORD, BIT_INDEX) ((WORD) |= (1U << (BIT_INDEX)))
+/** Clearing bit manipulation macro */
+#define CLR_BIT(WORD, BIT_INDEX) ((WORD) &= ~(1U << (BIT_INDEX)))
+/** Getter bit manipulation macro */
+#define GET_BIT(WORD, BIT_INDEX) (bool)(((WORD) & (1U << (BIT_INDEX))))
+
+#define WORD_ALIGN_4B_MASK 0x3U /* Mask the first 2 bits */
+#define IS_ADDR_ALIGNED(ADDR) (((uint32_t)(ADDR) & (WORD_ALIGN_4B_MASK)) == 0U)
+
+#define BITS_PER_BYTE 8U
+#define BITS_PER_WORD 32U
+
+#define CFG_READS true
+#define CFG_WRITES false
+
+#define ARG_NOT_USED 0
+#define ARG_PTR_NOT_USED NULL
+
+#define DATA_REG_NUMBER 2U
+#define DATA_REG_LOWER 0U
+#define DATA_REG_UPPER 1U
+
+#define ERROR_VALUE 0xFFFFFFFFU
+
+/**
+ * \brief QSPI IP6514E register map structure
+ */
+struct _qspi_ip6514e_reg_map_t {
+ volatile uint32_t qspi_cfg; /*!< 0x00 (R/W) */
+ volatile uint32_t device_read_inst; /*!< 0x04 (R/W) */
+ volatile uint32_t device_write_inst; /*!< 0x08 (R/W) */
+ volatile uint32_t hidden1[2];
+ volatile uint32_t device_size; /*!< 0x14 (R/W) */
+ volatile uint32_t hidden2[3];
+ volatile uint32_t remap_addr; /*!< 0x24 (R/W) */
+ volatile uint32_t hidden3[26];
+ volatile uint32_t flash_cmd_ctrl; /*!< 0x90 (R/W) */
+ volatile uint32_t flash_cmd_addr; /*!< 0x94 (R/W) */
+ volatile uint32_t hidden4[2];
+ volatile uint32_t flash_cmd_read_data_lower; /*!< 0xA0 (R/ ) */
+ volatile uint32_t flash_cmd_read_data_upper; /*!< 0xA4 (R/ ) */
+ volatile uint32_t flash_cmd_write_data_lower; /*!< 0xA8 (R/W) */
+ volatile uint32_t flash_cmd_write_data_upper; /*!< 0xAC (R/W) */
+ volatile uint32_t hidden5[2];
+};
+
+/** QSPI Configuration register description (offset 0x00) */
+#define QSPI_CFG_ENABLE_POS 0U
+#define QSPI_CFG_ENABLE_ADDR_REMAP_POS 16U
+#define QSPI_CFG_BAUD_DIV_POS 19U
+ #define QSPI_CFG_BAUD_DIV_MIN 2U
+ #define QSPI_CFG_BAUD_DIV_MAX 32U
+ #define QSPI_CFG_BAUD_DIV_BITS 4U
+#define QSPI_CFG_IDLE_POS 31U
+
+/**
+ * Device Read/Write Instruction registers description (offset 0x04 and 0x08).
+ * These values are the same for the Device Read Instruction register at offset
+ * 0x04 and the Device Write Instruction register at offset 0x08.
+ */
+#define DEVICE_READ_WRITE_INST_OPCODE_POS 0U
+#define DEVICE_READ_INST_INST_TYPE_POS 8U /* Only applies to the Read
+ * register. */
+#define DEVICE_READ_WRITE_INST_ADDR_TYPE_POS 12U
+#define DEVICE_READ_WRITE_INST_DATA_TYPE_POS 16U
+ #define DEVICE_READ_WRITE_INST_MODE_QSPI 2U
+ #define DEVICE_READ_WRITE_INST_MODE_DSPI 1U
+ #define DEVICE_READ_WRITE_INST_MODE_SPI 0U
+ #define DEVICE_READ_WRITE_INST_MODE_BITS 2U
+#define DEVICE_READ_WRITE_INST_DUMMY_CYCLES_POS 24U
+ #define DEVICE_READ_WRITE_INST_DUMMY_CYCLES_BITS 5U
+ #define DEVICE_READ_WRITE_INST_DUMMY_CYCLES_MAX 31U
+
+/** Device Size Configuration register description (offset 0x14) */
+#define DEVICE_SIZE_ADDR_BYTES_POS 0U
+ #define DEVICE_SIZE_ADDR_BYTES_MIN 1U
+ #define DEVICE_SIZE_ADDR_BYTES_MAX 16U
+ #define DEVICE_SIZE_ADDR_BYTES_BITS 4U
+#define DEVICE_SIZE_PAGE_BYTES_POS 4U
+ #define DEVICE_SIZE_PAGE_BYTES_MAX 4095U
+ #define DEVICE_SIZE_PAGE_BYTES_BITS 12U
+
+/** Flash Command Control register description (offset 0x90) */
+#define FLASH_CMD_CTRL_EXECUTE_POS 0U
+#define FLASH_CMD_CTRL_BUSY_POS 1U
+#define FLASH_CMD_CTRL_DUMMY_CYCLES_POS 7U
+ #define FLASH_CMD_CTRL_DUMMY_CYCLES_MAX 31U
+ #define FLASH_CMD_CTRL_DUMMY_CYCLES_BITS 5U
+#define FLASH_CMD_CTRL_WRITE_BYTES_POS 12U
+ #define FLASH_CMD_CTRL_WRITE_BYTES_MAX 8U
+ #define FLASH_CMD_CTRL_WRITE_BYTES_BITS 3U
+#define FLASH_CMD_CTRL_WRITE_ENABLE_POS 15U
+#define FLASH_CMD_CTRL_ADDR_BYTES_POS 16U
+ #define FLASH_CMD_CTRL_ADDR_BYTES_MAX 4U
+ #define FLASH_CMD_CTRL_ADDR_BYTES_BITS 2U
+#define FLASH_CMD_CTRL_ADDR_ENABLE_POS 19U
+#define FLASH_CMD_CTRL_READ_BYTES_POS 20U
+ #define FLASH_CMD_CTRL_READ_BYTES_MAX 8U
+ #define FLASH_CMD_CTRL_READ_BYTES_BITS 3U
+#define FLASH_CMD_CTRL_READ_ENABLE_POS 23U
+#define FLASH_CMD_CTRL_OPCODE_POS 24U
+
+/** Default register values of the QSPI Flash controller */
+#define QSPI_CFG_REG_RESET_VALUE (0x80080080U)
+#define DEVICE_READ_INSTR_REG_RESET_VALUE (0x080220EBU)
+#define DEVICE_WRITE_INSTR_REG_RESET_VALUE (0x00000002U)
+#define DEVICE_SIZE_CFG_REG_RESET_VALUE (0x00101002U)
+#define REMAP_ADDR_REG_RESET_VALUE (0x00000000U)
+#define FLASH_CMD_CONTROL_REG_RESET_VALUE (0x00000000U)
+#define FLASH_CMD_ADDRESS_REG_RESET_VALUE (0x00000000U)
+#define FLASH_CMD_WRITE_DATA_REG_RESET_VALUE (0x00000000U)
+
+/**
+ * \brief Change specific bits in a 32 bits word.
+ *
+ * \param[in,out] word Pointer of the word to change
+ * \param[in] bits bits_length bits to put at bits_pos in the word
+ * pointed
+ * \param[in] bits_length Number of bits to change
+ * \param[in] bits_pos Position of the bits to change
+ *
+ * \note This function will do nothing if the parameters given are incorret:
+ * * word is NULL
+ * * bits_length + bits_pos > 32
+ * * bits_length is 0
+ */
+static void change_bits_in_word(volatile uint32_t *word,
+ uint32_t bits,
+ uint32_t bits_length,
+ uint32_t bits_pos)
+{
+ uint32_t mask;
+
+ if ((word == NULL) ||
+ ((bits_length + bits_pos) > BITS_PER_WORD) ||
+ (bits_length == 0U)) {
+ /* Silently fail */
+ return;
+ }
+
+ /* Change all the bits */
+ if (bits_length == BITS_PER_WORD) {
+ *word = bits;
+ return;
+ }
+
+ mask = ((1U << bits_length) - 1);
+ /*
+ * We change the bits in three steps:
+ * - clear bits_length bits with zeroes at bits_pos in the word
+ * - mask bits in case it contains more than bits_length bits
+ * - set the new bits in the cleared word
+ * Because the data pointed by word is only read once, the data will still
+ * be coherent after an interruption that changes it.
+ */
+ *word = ((*word & ~(mask << bits_pos)) | ((bits & mask) << bits_pos));
+}
+
+/**
+ * \brief Configure reads or writes commands for direct operations.
+ *
+ * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t
+ * \param[in] opcode Read/write opcode that will be used for every
+ * direct read/write
+ * \param[in] dummy_cycles Number of dummy cycles to wait before triggering
+ * the command, this value must be between 0 and 31
+ * (both included)
+ * \param[in] is_reads_cfg true to configure direct reads, false to configure
+ * direct writes
+ *
+ * \return Returns error code as specified in \ref qspi_ip6514e_error_t
+ *
+ * \note The QSPI controller should be idle before calling this function.
+ */
+static enum qspi_ip6514e_error_t qspi_ip6514e_cfg_reads_writes(
+ struct qspi_ip6514e_dev_t* dev,
+ uint8_t opcode,
+ uint32_t dummy_cycles,
+ bool is_reads_cfg)
+{
+ struct _qspi_ip6514e_reg_map_t *reg_map =
+ (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base;
+ /*
+ * Select the good register address if we want to configure reads or writes.
+ */
+ volatile uint32_t *device_read_write_inst_reg = is_reads_cfg ?
+ &(reg_map->device_read_inst) :
+ &(reg_map->device_write_inst);
+ uint32_t device_read_write_inst_reg_copy = *device_read_write_inst_reg;
+
+ /*
+ * Wait for the Serial Interface and QSPI pipeline to be IDLE when
+ * all low level synchronization has been done.
+ */
+ while(!qspi_ip6514e_is_idle(dev));
+
+ if (dummy_cycles > DEVICE_READ_WRITE_INST_DUMMY_CYCLES_MAX) {
+ return QSPI_IP6514E_ERR_WRONG_ARGUMENT;
+ }
+
+ change_bits_in_word(&device_read_write_inst_reg_copy,
+ (uint32_t)opcode,
+ BITS_PER_BYTE,
+ DEVICE_READ_WRITE_INST_OPCODE_POS);
+ change_bits_in_word(&device_read_write_inst_reg_copy,
+ dummy_cycles,
+ DEVICE_READ_WRITE_INST_DUMMY_CYCLES_BITS,
+ DEVICE_READ_WRITE_INST_DUMMY_CYCLES_POS);
+
+ *device_read_write_inst_reg = device_read_write_inst_reg_copy;
+
+ return QSPI_IP6514E_ERR_NONE;
+}
+
+/**
+ * \brief Given the public SPI mode enumeration, returns the private value it
+ * maps to in the register field.
+ *
+ * \param[in] spi_mode Read/write opcode that will be used for every direct
+ * read/write
+ *
+ * \return Return the correct DEVICE_READ_WRITE_INST_MODE value.
+ */
+static uint32_t spi_mode_field_value(enum qspi_ip6514e_spi_mode_t spi_mode)
+{
+ switch (spi_mode) {
+ case QSPI_IP6514E_SPI_MODE:
+ return DEVICE_READ_WRITE_INST_MODE_SPI;
+ case QSPI_IP6514E_DSPI_MODE:
+ return DEVICE_READ_WRITE_INST_MODE_DSPI;
+ case QSPI_IP6514E_QSPI_MODE:
+ return DEVICE_READ_WRITE_INST_MODE_QSPI;
+ default:
+ return ERROR_VALUE;
+ }
+}
+
+bool qspi_ip6514e_is_idle(struct qspi_ip6514e_dev_t* dev)
+{
+ struct _qspi_ip6514e_reg_map_t *reg_map =
+ (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base;
+
+ return GET_BIT(reg_map->qspi_cfg, QSPI_CFG_IDLE_POS);
+}
+
+bool qspi_ip6514e_is_enabled(struct qspi_ip6514e_dev_t* dev)
+{
+ struct _qspi_ip6514e_reg_map_t *reg_map =
+ (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base;
+
+ return GET_BIT(reg_map->qspi_cfg, QSPI_CFG_ENABLE_POS);
+}
+
+void qspi_ip6514e_disable(struct qspi_ip6514e_dev_t* dev)
+{
+ struct _qspi_ip6514e_reg_map_t *reg_map =
+ (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base;
+
+ CLR_BIT(reg_map->qspi_cfg, QSPI_CFG_ENABLE_POS);
+}
+
+void qspi_ip6514e_enable(struct qspi_ip6514e_dev_t* dev)
+{
+ struct _qspi_ip6514e_reg_map_t *reg_map =
+ (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base;
+
+ SET_BIT(reg_map->qspi_cfg, QSPI_CFG_ENABLE_POS);
+}
+
+enum qspi_ip6514e_error_t qspi_ip6514e_set_baud_rate_div(
+ struct qspi_ip6514e_dev_t* dev,
+ uint32_t div)
+{
+ struct _qspi_ip6514e_reg_map_t *reg_map =
+ (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base;
+
+ /*
+ * Wait for the Serial Interface and QSPI pipeline to be IDLE when
+ * all low level synchronization has been done.
+ */
+ while(!qspi_ip6514e_is_idle(dev));
+
+ /* div should be an even number. */
+ if (((div & 1U) == 1) ||
+ (div < QSPI_CFG_BAUD_DIV_MIN) ||
+ (div > QSPI_CFG_BAUD_DIV_MAX)) {
+ return QSPI_IP6514E_ERR_WRONG_ARGUMENT;
+ }
+
+ /*
+ * The div value (between 2 and 32) needs to be stored in the register on a
+ * 4 bits field.
+ */
+ change_bits_in_word(&(reg_map->qspi_cfg),
+ (div / 2) - 1,
+ QSPI_CFG_BAUD_DIV_BITS,
+ QSPI_CFG_BAUD_DIV_POS);
+
+ return QSPI_IP6514E_ERR_NONE;
+}
+
+enum qspi_ip6514e_error_t qspi_ip6514e_set_spi_mode(
+ struct qspi_ip6514e_dev_t* dev,
+ enum qspi_ip6514e_spi_mode_t inst_type,
+ enum qspi_ip6514e_spi_mode_t addr_type,
+ enum qspi_ip6514e_spi_mode_t data_type)
+{
+ struct _qspi_ip6514e_reg_map_t *reg_map =
+ (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base;
+ uint32_t inst_spi_mode, addr_spi_mode, data_spi_mode;
+ /*
+ * A local copy of the Device Read Instruction and Device Write Instruction
+ * registers is used to limit APB accesses.
+ */
+ uint32_t device_read_inst_cpy = reg_map->device_read_inst;
+ uint32_t device_write_inst_cpy = reg_map->device_write_inst;
+
+ /*
+ * Wait for the Serial Interface and QSPI pipeline to be IDLE when
+ * all low level synchronization has been done.
+ */
+ while(!qspi_ip6514e_is_idle(dev));
+
+ /*
+ * First check that the instruction mode is not SPI. If that is the case,
+ * the address and data mode register fields become DO NOT CARE.
+ */
+ inst_spi_mode = spi_mode_field_value(inst_type);
+ if (inst_spi_mode == ERROR_VALUE) {
+ return QSPI_IP6514E_ERR_WRONG_ARGUMENT;
+ }
+ if (inst_type != QSPI_IP6514E_SPI_MODE) {
+ change_bits_in_word(&(reg_map->device_read_inst),
+ inst_spi_mode,
+ DEVICE_READ_WRITE_INST_MODE_BITS,
+ DEVICE_READ_INST_INST_TYPE_POS);
+ return QSPI_IP6514E_ERR_NONE;
+ }
+
+ /* Now check and set address and data modes. */
+ addr_spi_mode = spi_mode_field_value(addr_type);
+ data_spi_mode = spi_mode_field_value(data_type);
+ if ((addr_spi_mode == ERROR_VALUE) || (data_spi_mode == ERROR_VALUE)) {
+ return QSPI_IP6514E_ERR_WRONG_ARGUMENT;
+ }
+
+ /* Change the Device Read Instruction register. */
+ change_bits_in_word(&device_read_inst_cpy,
+ inst_spi_mode,
+ DEVICE_READ_WRITE_INST_MODE_BITS,
+ DEVICE_READ_INST_INST_TYPE_POS);
+ change_bits_in_word(&device_read_inst_cpy,
+ addr_spi_mode,
+ DEVICE_READ_WRITE_INST_MODE_BITS,
+ DEVICE_READ_WRITE_INST_ADDR_TYPE_POS);
+ change_bits_in_word(&device_read_inst_cpy,
+ data_spi_mode,
+ DEVICE_READ_WRITE_INST_MODE_BITS,
+ DEVICE_READ_WRITE_INST_DATA_TYPE_POS);
+
+ /* Change the Device Write Instruction register. */
+ change_bits_in_word(&device_write_inst_cpy,
+ addr_spi_mode,
+ DEVICE_READ_WRITE_INST_MODE_BITS,
+ DEVICE_READ_WRITE_INST_ADDR_TYPE_POS);
+ change_bits_in_word(&device_write_inst_cpy,
+ data_spi_mode,
+ DEVICE_READ_WRITE_INST_MODE_BITS,
+ DEVICE_READ_WRITE_INST_DATA_TYPE_POS);
+
+ /* Save the changes. */
+ reg_map->device_read_inst = device_read_inst_cpy;
+ reg_map->device_write_inst = device_write_inst_cpy;
+
+ return QSPI_IP6514E_ERR_NONE;
+}
+
+enum qspi_ip6514e_error_t qspi_ip6514e_cfg_reads(struct qspi_ip6514e_dev_t* dev,
+ uint8_t opcode,
+ uint32_t dummy_cycles)
+{
+ return qspi_ip6514e_cfg_reads_writes(dev, opcode, dummy_cycles, CFG_READS);
+}
+
+enum qspi_ip6514e_error_t qspi_ip6514e_cfg_writes(
+ struct qspi_ip6514e_dev_t* dev,
+ uint8_t opcode,
+ uint32_t dummy_cycles)
+{
+ return qspi_ip6514e_cfg_reads_writes(dev, opcode, dummy_cycles, CFG_WRITES);
+}
+
+enum qspi_ip6514e_error_t qspi_ip6514e_cfg_page_size(
+ struct qspi_ip6514e_dev_t* dev,
+ uint32_t page_size)
+{
+ struct _qspi_ip6514e_reg_map_t *reg_map =
+ (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base;
+
+ /*
+ * Wait for the Serial Interface and QSPI pipeline to be IDLE when
+ * all low level synchronization has been done.
+ */
+ while(!qspi_ip6514e_is_idle(dev));
+
+ if (page_size > DEVICE_SIZE_PAGE_BYTES_MAX) {
+ return QSPI_IP6514E_ERR_WRONG_ARGUMENT;
+ }
+
+ change_bits_in_word(&(reg_map->device_size),
+ page_size,
+ DEVICE_SIZE_PAGE_BYTES_BITS,
+ DEVICE_SIZE_PAGE_BYTES_POS);
+
+ return QSPI_IP6514E_ERR_NONE;
+}
+
+enum qspi_ip6514e_error_t qspi_ip6514e_cfg_addr_bytes(
+ struct qspi_ip6514e_dev_t* dev,
+ uint32_t bytes_number)
+{
+ struct _qspi_ip6514e_reg_map_t *reg_map =
+ (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base;
+
+ /*
+ * Wait for the Serial Interface and QSPI pipeline to be IDLE when
+ * all low level synchronization has been done.
+ */
+ while(!qspi_ip6514e_is_idle(dev));
+
+ if (bytes_number < DEVICE_SIZE_ADDR_BYTES_MIN ||
+ bytes_number > DEVICE_SIZE_ADDR_BYTES_MAX) {
+ return QSPI_IP6514E_ERR_WRONG_ARGUMENT;
+ }
+
+ change_bits_in_word(&(reg_map->device_size),
+ bytes_number - 1,
+ DEVICE_SIZE_ADDR_BYTES_BITS,
+ DEVICE_SIZE_ADDR_BYTES_POS);
+
+
+ return QSPI_IP6514E_ERR_NONE;
+}
+
+void qspi_ip6514e_remap_addr(struct qspi_ip6514e_dev_t* dev, uint32_t offset)
+{
+ struct _qspi_ip6514e_reg_map_t *reg_map =
+ (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base;
+ /* Save the enable state to restore it after. */
+ bool is_enabled = qspi_ip6514e_is_enabled(dev);
+
+ if (is_enabled) {
+ qspi_ip6514e_disable(dev);
+ }
+
+ reg_map->remap_addr = offset;
+ SET_BIT(reg_map->qspi_cfg, QSPI_CFG_ENABLE_ADDR_REMAP_POS);
+
+ if (is_enabled) {
+ qspi_ip6514e_enable(dev);
+ }
+}
+
+void qspi_ip6514e_disable_remap(struct qspi_ip6514e_dev_t* dev)
+{
+ struct _qspi_ip6514e_reg_map_t *reg_map =
+ (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base;
+ /* Save the enable state to restore it after. */
+ bool is_enabled = qspi_ip6514e_is_enabled(dev);
+
+ if (is_enabled) {
+ qspi_ip6514e_disable(dev);
+ }
+
+ CLR_BIT(reg_map->qspi_cfg, QSPI_CFG_ENABLE_ADDR_REMAP_POS);
+
+ if (is_enabled) {
+ qspi_ip6514e_enable(dev);
+ }
+}
+
+void qspi_ip6514e_reset_regs(struct qspi_ip6514e_dev_t* dev)
+{
+ struct _qspi_ip6514e_reg_map_t *reg_map =
+ (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base;
+
+ /* Restore the default value of the QSPI Configuration register. */
+ reg_map->qspi_cfg = QSPI_CFG_REG_RESET_VALUE;
+
+ /* Restore the default value of the Device R/W Instruction registers. */
+ reg_map->device_read_inst = DEVICE_READ_INSTR_REG_RESET_VALUE;
+ reg_map->device_write_inst = DEVICE_WRITE_INSTR_REG_RESET_VALUE;
+
+ /* Restore the default value of the Device Size Configuration register. */
+ reg_map->device_size = DEVICE_SIZE_CFG_REG_RESET_VALUE;
+
+ /* Restore the default value of the Remap Address register. */
+ reg_map->remap_addr = REMAP_ADDR_REG_RESET_VALUE;
+
+ /* Restore the default value of the Flash Command Control register. */
+ reg_map->flash_cmd_ctrl = FLASH_CMD_CONTROL_REG_RESET_VALUE;
+ /* Restore the default value of the Flash Command Address register. */
+ reg_map->flash_cmd_addr = FLASH_CMD_ADDRESS_REG_RESET_VALUE;
+
+ /* Restore the default value of the Flash Command Write Data registers. */
+ reg_map->flash_cmd_write_data_lower = FLASH_CMD_WRITE_DATA_REG_RESET_VALUE;
+ reg_map->flash_cmd_write_data_upper = FLASH_CMD_WRITE_DATA_REG_RESET_VALUE;
+
+ /*
+ * This function does not affect the Flash Command Read Data registers
+ * which are completely Read-Only.
+ */
+}
+
+enum qspi_ip6514e_error_t qspi_ip6514e_send_cmd(struct qspi_ip6514e_dev_t* dev,
+ uint8_t opcode,
+ void *read_data,
+ uint32_t read_len,
+ const void *write_data,
+ uint32_t write_len,
+ uint32_t addr,
+ uint32_t addr_bytes_number,
+ uint32_t dummy_cycles)
+{
+ struct _qspi_ip6514e_reg_map_t *reg_map =
+ (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base;
+ /* To limit APB accesses, we set this reg up locally before */
+ uint32_t flash_cmd_ctrl = 0U;
+ bool read_requested = ((read_data != NULL) && (read_len != 0));
+ bool write_requested = ((write_data != NULL) && (write_len != 0));
+ bool addr_requested = (addr_bytes_number != 0);
+ /*
+ * To prevent unaligned and byte or halfbyte accesses to the APB registers,
+ * a word aligned buffer is used to temporary transfer the data before doing
+ * word accesses on these registers from that buffer.
+ */
+ uint32_t data_regs[DATA_REG_NUMBER] = {0};
+
+ if (read_len > FLASH_CMD_CTRL_READ_BYTES_MAX) {
+ return QSPI_IP6514E_ERR_WRONG_ARGUMENT;
+ }
+
+ if (write_len > FLASH_CMD_CTRL_WRITE_BYTES_MAX) {
+ return QSPI_IP6514E_ERR_WRONG_ARGUMENT;
+ }
+
+ if (addr_bytes_number > FLASH_CMD_CTRL_ADDR_BYTES_MAX) {
+ return QSPI_IP6514E_ERR_WRONG_ARGUMENT;
+ }
+
+ if (dummy_cycles > FLASH_CMD_CTRL_DUMMY_CYCLES_MAX) {
+ return QSPI_IP6514E_ERR_WRONG_ARGUMENT;
+ }
+
+ if (read_requested && write_requested) {
+ return QSPI_IP6514E_ERR_WRONG_ARGUMENT;
+ }
+
+ change_bits_in_word(&flash_cmd_ctrl,
+ (uint32_t)opcode,
+ BITS_PER_BYTE,
+ FLASH_CMD_CTRL_OPCODE_POS);
+
+ /* Enable read if requested */
+ if (read_requested) {
+ SET_BIT(flash_cmd_ctrl, FLASH_CMD_CTRL_READ_ENABLE_POS);
+ change_bits_in_word(&flash_cmd_ctrl,
+ read_len - 1,
+ FLASH_CMD_CTRL_READ_BYTES_BITS,
+ FLASH_CMD_CTRL_READ_BYTES_POS);
+ }
+
+ /* Enable write if requested */
+ if (write_requested) {
+ SET_BIT(flash_cmd_ctrl, FLASH_CMD_CTRL_WRITE_ENABLE_POS);
+ change_bits_in_word(&flash_cmd_ctrl,
+ write_len - 1,
+ FLASH_CMD_CTRL_WRITE_BYTES_BITS,
+ FLASH_CMD_CTRL_WRITE_BYTES_POS);
+
+ if (IS_ADDR_ALIGNED(write_data) && IS_ADDR_ALIGNED(write_len)) {
+ /*
+ * Optimised case when write_data is word aligned and write_len is
+ * 4 or 8.
+ */
+ reg_map->flash_cmd_write_data_lower = *(uint32_t *)write_data;
+ if (write_len == FLASH_CMD_CTRL_WRITE_BYTES_MAX) {
+ reg_map->flash_cmd_write_data_upper =
+ *((uint32_t *)write_data + 1);
+ }
+ } else {
+ /*
+ * data_regs is used as a buffer to only do unaligned access on the
+ * AHB bus and word aligned accesses to the APB registers.
+ */
+ memcpy((void *)data_regs, write_data, write_len);
+ /*
+ * Only write_len bytes will be written even if both data registers
+ * are written.
+ */
+ reg_map->flash_cmd_write_data_lower = data_regs[DATA_REG_LOWER];
+ reg_map->flash_cmd_write_data_upper = data_regs[DATA_REG_UPPER];
+ }
+ }
+
+ /* Enable the address if requested */
+ if (addr_requested) {
+ SET_BIT(flash_cmd_ctrl, FLASH_CMD_CTRL_ADDR_ENABLE_POS);
+ reg_map->flash_cmd_addr = addr;
+ change_bits_in_word(&flash_cmd_ctrl,
+ addr_bytes_number - 1,
+ FLASH_CMD_CTRL_ADDR_BYTES_BITS,
+ FLASH_CMD_CTRL_ADDR_BYTES_POS);
+ }
+
+ /* Put dummy cycles number */
+ change_bits_in_word(&flash_cmd_ctrl,
+ dummy_cycles,
+ FLASH_CMD_CTRL_DUMMY_CYCLES_BITS,
+ FLASH_CMD_CTRL_DUMMY_CYCLES_POS);
+
+ /* Copy the Flash Command Control register and execute the command */
+ reg_map->flash_cmd_ctrl = flash_cmd_ctrl;
+ SET_BIT(reg_map->flash_cmd_ctrl, FLASH_CMD_CTRL_EXECUTE_POS);
+
+ /* Wait for termination */
+ while (GET_BIT(reg_map->flash_cmd_ctrl, FLASH_CMD_CTRL_BUSY_POS));
+
+ /*
+ * Recolt the read data if it was requested. read_len validity has already
+ * been verified at this point.
+ */
+ if (read_requested) {
+ if (IS_ADDR_ALIGNED(read_data) && IS_ADDR_ALIGNED(read_len)) {
+ /*
+ * Optimised case when read_data is word aligned and read_len is
+ * 4 or 8.
+ */
+ *(uint32_t *)read_data = reg_map->flash_cmd_read_data_lower;
+ if (read_len == FLASH_CMD_CTRL_READ_BYTES_MAX) {
+ *((uint32_t *)read_data + 1) =
+ reg_map->flash_cmd_read_data_upper;
+ }
+ } else {
+ /*
+ * Only read_len bytes have been written even if both data registers
+ * are written.
+ */
+ data_regs[DATA_REG_LOWER] = reg_map->flash_cmd_read_data_lower;
+ data_regs[DATA_REG_UPPER] = reg_map->flash_cmd_read_data_upper;
+ /*
+ * data_regs is used as a buffer to only do unaligned access on the
+ * AHB bus and word aligned accesses to the APB registers.
+ */
+ memcpy(read_data, (void *)data_regs, read_len);
+ }
+ }
+
+ return QSPI_IP6514E_ERR_NONE;
+}
+
+void qspi_ip6514e_send_simple_cmd(struct qspi_ip6514e_dev_t* dev,
+ uint8_t opcode)
+{
+ /*
+ * No read/write data, no address, no dummy cycles.
+ * Given the arguments, this function can not fail.
+ */
+ (void)qspi_ip6514e_send_cmd(dev,
+ opcode,
+ ARG_PTR_NOT_USED,
+ ARG_NOT_USED,
+ ARG_PTR_NOT_USED,
+ ARG_NOT_USED,
+ ARG_NOT_USED,
+ ARG_NOT_USED,
+ 0);
+}
+
+enum qspi_ip6514e_error_t qspi_ip6514e_send_read_cmd(
+ struct qspi_ip6514e_dev_t* dev,
+ uint8_t opcode,
+ void *read_data,
+ uint32_t read_len,
+ uint32_t addr,
+ uint32_t addr_bytes_number,
+ uint32_t dummy_cycles)
+{
+ /* Read arguments are expected */
+ if (read_data == ARG_PTR_NOT_USED || read_len == ARG_NOT_USED) {
+ return QSPI_IP6514E_ERR_WRONG_ARGUMENT;
+ }
+
+ /* No write data */
+ return qspi_ip6514e_send_cmd(dev,
+ opcode,
+ read_data,
+ read_len,
+ ARG_PTR_NOT_USED,
+ ARG_NOT_USED,
+ addr,
+ addr_bytes_number,
+ dummy_cycles);
+}
+
+enum qspi_ip6514e_error_t qspi_ip6514e_send_write_cmd(
+ struct qspi_ip6514e_dev_t* dev,
+ uint8_t opcode,
+ const void *write_data,
+ uint32_t write_len,
+ uint32_t addr,
+ uint32_t addr_bytes_number,
+ uint32_t dummy_cycles)
+{
+ /* Write arguments are expected */
+ if (write_data == ARG_PTR_NOT_USED || write_len == ARG_NOT_USED) {
+ return QSPI_IP6514E_ERR_WRONG_ARGUMENT;
+ }
+
+ /* No read data, no dummy cycles */
+ return qspi_ip6514e_send_cmd(dev,
+ opcode,
+ ARG_PTR_NOT_USED,
+ ARG_NOT_USED,
+ write_data,
+ write_len,
+ addr,
+ addr_bytes_number,
+ dummy_cycles);
+}
diff --git a/platform/ext/target/musca_s1/Native_Driver/qspi_ip6514e_drv.h b/platform/ext/target/musca_s1/Native_Driver/qspi_ip6514e_drv.h
new file mode 100644
index 0000000000..69929255dd
--- /dev/null
+++ b/platform/ext/target/musca_s1/Native_Driver/qspi_ip6514e_drv.h
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2018 Arm Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file qspi_ip6514e_drv.h
+ * \brief Driver for Cadence QSPI Flash Controller IP.
+ * There are two ways to communicate with the flash memory device:
+ * - issue AHB requests for direct read and writes in the Flash memory
+ * mapped address zone. The commands used for those can be configured
+ * by the driver
+ * - send a command to the device to access his internal registers and
+ * do other operations like erasing a sector
+ * At reset, the QSPI controller will work in a default mode which will
+ * allow to do basic commands. It should be configured with the
+ * flash memory device specifications for optimal use for commands and
+ * direct reads/writes. Here is an example of configuration:
+ * - send command to activate QSPI mode on the flash memory device
+ * - send command to change dummy cycles on the flash memory device
+ * - check if any operation is ungoing
+ * - disable the QSPI controller
+ * - change the baud rate divisor
+ * - activate the QSPI mode on the controller
+ * - change the dummy cycles number and opcode for reads/writes
+ * - change the number of bytes per page
+ * - change the number of address bytes
+ * - activate the QSPI controller
+ *
+ * Warning: none of the functions declared here check if the dev
+ * argument points to NULL.
+ */
+
+#ifndef __QSPI_IP6514E_DRV_H__
+#define __QSPI_IP6514E_DRV_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Cadence QSPI IP6514E error enumeration types
+ */
+enum qspi_ip6514e_error_t {
+ QSPI_IP6514E_ERR_NONE,
+ QSPI_IP6514E_ERR_WRONG_ARGUMENT,
+ QSPI_IP6514E_ERR_CONTROLLER_NOT_DISABLED,
+ QSPI_IP6514E_ERR_READ_IN_PROGRESS,
+ QSPI_IP6514E_ERR_WRITE_IN_PROGRESS,
+ /* Any new error should be added to the enumeration type error of
+ * the corresponding Flash device library as well.
+ */
+};
+
+/**
+ * \brief Cadence QSPI IP6514E SPI modes
+ */
+enum qspi_ip6514e_spi_mode_t {
+ QSPI_IP6514E_SPI_MODE,
+ /*!< Use 1 line for Instruction, Address and Data */
+ QSPI_IP6514E_DSPI_MODE,
+ /*!< Use 2 lines for Instruction, Address and Data */
+ QSPI_IP6514E_QSPI_MODE,
+ /*!< Use 4 lines for Instruction, Address and Data */
+};
+
+/**
+ * \brief Cadence QSPI IP6514E device configuration structure
+ */
+struct qspi_ip6514e_dev_cfg_t {
+ const uint32_t base; /*!< QSPI IP6514E base address */
+ /*
+ * If not all the AHB wires are connected to the QSPI Flash Controller the
+ * driver can still access all of the Flash memory. The bits of this value
+ * should be put to 1 for every wire that is connected. Set it to
+ * 0xFFFFFFFFU if all AHB address wires are connected to the
+ * QSPI Flash Controller.
+ */
+ uint32_t addr_mask;
+};
+
+/**
+ * \brief Cadence QSPI IP6514E device structure
+ */
+struct qspi_ip6514e_dev_t {
+ const struct qspi_ip6514e_dev_cfg_t* const cfg;
+ /*!< QSPI IP6514E configuration */
+};
+
+/**
+ * \brief Check if the controller is idle.
+ *
+ * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t
+ *
+ * \return true if the controller is idle, false otherwise.
+ */
+bool qspi_ip6514e_is_idle(struct qspi_ip6514e_dev_t* dev);
+
+/**
+ * \brief Check if the controller is enabled.
+ *
+ * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t
+ *
+ * \return true if the controller is enabled, false otherwise.
+ */
+bool qspi_ip6514e_is_enabled(struct qspi_ip6514e_dev_t* dev);
+
+/**
+ * \brief Disable the QSPI controller.
+ *
+ * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t
+ */
+void qspi_ip6514e_disable(struct qspi_ip6514e_dev_t* dev);
+
+/**
+ * \brief Enable the QSPI controller.
+ *
+ * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t
+ */
+void qspi_ip6514e_enable(struct qspi_ip6514e_dev_t* dev);
+
+/**
+ * \brief Change the baud rate divisor.
+ *
+ * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t
+ * \param[in] div Baud rate divisor value. It can only be an even number
+ * between 2 and 32 (both included).
+ *
+ * \return Returns error code as specified in \ref qspi_ip6514e_error_t
+ *
+ * \note The QSPI frequency is calculated dividing the QSPI controller clock by
+ * this divisor. Please check Flash memory device specifications to know
+ * the maximal frequency that can be used.
+ * \note The QSPI controller should be disabled before calling this function.
+ */
+enum qspi_ip6514e_error_t qspi_ip6514e_set_baud_rate_div(
+ struct qspi_ip6514e_dev_t* dev,
+ uint32_t div);
+
+/**
+ * \brief Set SPI mode for instruction, address and data.
+ *
+ * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t
+ * \param[in] inst_type SPI mode to use for the instruction part of the command
+ * \param[in] addr_type SPI mode to use for the address part of the command
+ * \param[in] data_type SPI mode to use for the data part of the command
+ *
+ * \return Returns error code as specified in \ref qspi_ip6514e_error_t
+ *
+ * \note The QSPI controller should be idle before calling this function.
+ * \note Changing this setting will affect commands and direct operations.
+ */
+enum qspi_ip6514e_error_t qspi_ip6514e_set_spi_mode(
+ struct qspi_ip6514e_dev_t* dev,
+ enum qspi_ip6514e_spi_mode_t inst_type,
+ enum qspi_ip6514e_spi_mode_t addr_type,
+ enum qspi_ip6514e_spi_mode_t data_type);
+
+/**
+ * \brief Configure read commands for direct reads.
+ *
+ * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t
+ * \param[in] opcode Read opcode that will be used for every direct read
+ * \param[in] dummy_cycles Number of dummy cycles to wait before triggering the
+ * command, this value must be between 0 and 31
+ * (both included)
+ *
+ * \return Returns error code as specified in \ref qspi_ip6514e_error_t
+ *
+ * \note The QSPI controller should be idle before calling this function.
+ */
+enum qspi_ip6514e_error_t qspi_ip6514e_cfg_reads(struct qspi_ip6514e_dev_t* dev,
+ uint8_t opcode,
+ uint32_t dummy_cycles);
+
+/**
+ * \brief Configure write commands for direct writes.
+ *
+ * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t
+ * \param[in] opcode Write opcode that will be used for every direct write
+ * \param[in] dummy_cycles Number of dummy cycles to wait before triggering the
+ * command, this value must be between 0 and 31
+ * (both included)
+ *
+ * \return Returns error code as specified in \ref qspi_ip6514e_error_t
+ *
+ * \note The QSPI controller should be idle before calling this function.
+ */
+enum qspi_ip6514e_error_t qspi_ip6514e_cfg_writes(
+ struct qspi_ip6514e_dev_t* dev,
+ uint8_t opcode,
+ uint32_t dummy_cycles);
+
+/**
+ * \brief Change the number of bytes per device page.
+ *
+ * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t
+ * \param[in] page_size Number of bytes per device page, must be between 0
+ * and 4095 (both included)
+ *
+ * \return Returns error code as specified in \ref qspi_ip6514e_error_t
+ *
+ * \note The QSPI controller should be idle before calling this function.
+ * \note This function will affect direct reads/writes.
+ */
+enum qspi_ip6514e_error_t qspi_ip6514e_cfg_page_size(
+ struct qspi_ip6514e_dev_t* dev,
+ uint32_t page_size);
+
+/**
+ * \brief Change the number of device address bytes.
+ *
+ * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t
+ * \param[in] bytes_number Number of device address bytes, must be between 1
+ * and 16 (both included)
+ *
+ * \return Returns error code as specified in \ref qspi_ip6514e_error_t
+ *
+ * \note The QSPI controller should be idle before calling this function.
+ * \note This function will affect direct reads/writes.
+ */
+enum qspi_ip6514e_error_t qspi_ip6514e_cfg_addr_bytes(
+ struct qspi_ip6514e_dev_t* dev,
+ uint32_t bytes_number);
+
+/**
+ * \brief Remap the incoming AHB address with an offset for direct accesses.
+ *
+ * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t
+ * \param[in] offset Offset that will be added to the incoming AHB address to
+ * access the Flash memory
+ *
+ * \note This function will only affect direct reads/writes.
+ * \note This function does not check if the resulting address is out of memory
+ * bounds.
+ */
+void qspi_ip6514e_remap_addr(struct qspi_ip6514e_dev_t* dev, uint32_t offset);
+
+/**
+ * \brief Disable AHB address remapping for direct accesses.
+ *
+ * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t
+ *
+ * \note This function will disable the controller if it is not already
+ * disabled and enable it again (if it was).
+ * \note This function will only affect direct reads/writes.
+ */
+void qspi_ip6514e_disable_remap(struct qspi_ip6514e_dev_t* dev);
+
+/**
+ * \brief Restore the default value of the QSPI controller registers.
+ *
+ * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t
+ *
+ * \note The QSPI controller should be disabled before calling this function.
+ */
+void qspi_ip6514e_reset_regs(struct qspi_ip6514e_dev_t* dev);
+
+/**
+ * \brief Send a command to the flash memory device using the Software Triggered
+ * Instruction Generator (STIG).
+ *
+ * \param[in] dev QSPI IP6514E device struct
+ * \ref qspi_ip6514e_dev_t
+ * \param[in] opcode Opcode for the command.
+ * \param[out] read_data Pointer to a memory zone where the read_len
+ * bytes read will be written to. If no data is to
+ * be read for the command,
+ * this argument should be NULL.
+ * \param[in] read_len Number of bytes to read for the command. If
+ * no bytes are to be read, use 0 for argument
+ * otherwise between 1 and 8 bytes (both
+ * included) can be read.
+ * \param[in] write_data Pointer to a memory zone where are
+ * located the write_len bytes to write for
+ * this command. If no bytes are to be written,
+ * use NULL as argument.
+ * \param[in] write_len Number of bytes to write for the command. If
+ * no bytes are to be written, use 0 for
+ * argument otherwise between 1 and 8 bytes
+ * (both included) can be written.
+ * \param[in] addr Address used for the command
+ * \param[in] addr_bytes_number Number of address bytes for this command.
+ * If an address is not needed for the command,
+ * use 0 for argument, otherwise between 1 and
+ * 4 bytes (both included) can be used.
+ * \param[in] dummy_cycles Number of dummy cycles required for the
+ * command, between 0 and 31 (both included).
+ *
+ * \return Returns error code as specified in \ref qspi_ip6514e_error_t
+ *
+ * \note Check the flash memory device specifications for the possible opcodes
+ * that can be used and the other informations needed for this function.
+ * \note The SPI mode used for this command is the one set with the
+ * \ref qspi_ip6514e_activate_qspi_mode function or the default one.
+ */
+enum qspi_ip6514e_error_t qspi_ip6514e_send_cmd(struct qspi_ip6514e_dev_t* dev,
+ uint8_t opcode,
+ void *read_data,
+ uint32_t read_len,
+ const void *write_data,
+ uint32_t write_len,
+ uint32_t addr,
+ uint32_t addr_bytes_number,
+ uint32_t dummy_cycles);
+
+/**
+ * \brief Send a simple command to the flash memory device using the Software
+ * Triggered Instruction Generator (STIG) with no data arguments.
+ * This command can be used for example to send the WRITE ENABLE command.
+ *
+ * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t
+ * \param[in] opcode Opcode for the command.
+ *
+ * \note Check the flash memory device specifications for the possible opcodes
+ * that can be used and the other informations needed for this function.
+ * \note The SPI mode used for this command is the one set with the
+ * \ref qspi_ip6514e_activate_qspi_mode function or the default one.
+ */
+void qspi_ip6514e_send_simple_cmd(struct qspi_ip6514e_dev_t* dev,
+ uint8_t opcode);
+
+/**
+ * \brief Send a read command to the flash memory device using the Software
+ * Triggered Instruction Generator (STIG). This command can be used to
+ * read Flash memory data or registers.
+ *
+ * \param[in] dev QSPI IP6514E device struct
+ * \ref qspi_ip6514e_dev_t
+ * \param[in] opcode Opcode for the command.
+ * \param[out] read_data Pointer to a memory zone where the
+ * read_len bytes read will be written to.
+ * \param[in] read_len Number of bytes to read for the command.
+ * Between 1 and 8 bytes (both included) can be
+ * read.
+ * \param[in] addr Address used for the command
+ * \param[in] addr_bytes_number Number of address bytes for this command.
+ * If an address is not needed for the command,
+ * use 0 for argument, otherwise between 1 and
+ * 4 bytes (both included) can be used.
+ * \param[in] dummy_cycles Number of dummy cycles required for the
+ * command, between 0 and 31 (both included).
+ *
+ * \return Returns error code as specified in \ref qspi_ip6514e_error_t
+ *
+ * \note Check the flash memory device specifications for the possible opcodes
+ * that can be used and the other informations needed for this function.
+ * \note The SPI mode used for this command is the one set with the
+ * \ref qspi_ip6514e_activate_qspi_mode function or the default one.
+ */
+enum qspi_ip6514e_error_t qspi_ip6514e_send_read_cmd(
+ struct qspi_ip6514e_dev_t* dev,
+ uint8_t opcode,
+ void *read_data,
+ uint32_t read_len,
+ uint32_t addr,
+ uint32_t addr_bytes_number,
+ uint32_t dummy_cycles);
+
+/**
+ * \brief Send a write command to the flash memory device using the Software
+ * Triggered Instruction Generator (STIG). This command can be used to
+ * write Flash memory or registers.
+ *
+ * \param[in] dev QSPI IP6514E device struct
+ * \ref qspi_ip6514e_dev_t
+ * \param[in] opcode Opcode for the command.
+ * \param[in] write_data Pointer to a memory zone where are
+ * located the write_len bytes to write for
+ * this command.
+ * \param[in] write_len Number of bytes to write for the command.
+ * Between 1 and 8 bytes (both included) can be
+ * written.
+ * \param[in] addr Address used for the command
+ * \param[in] addr_bytes_number Number of address bytes for this command.
+ * If an address is not needed for the command,
+ * use 0 for argument, otherwise between 1 and
+ * 4 bytes (both included) can be used.
+ * \param[in] dummy_cycles Number of dummy cycles required for the
+ * command, between 0 and 31 (both included).
+ *
+ * \return Returns error code as specified in \ref qspi_ip6514e_error_t
+ *
+ * \note Check the flash memory device specifications for the possible opcodes
+ * that can be used and the other informations needed for this function.
+ * \note The SPI mode used for this command is the one set with the
+ * \ref qspi_ip6514e_activate_qspi_mode function or the default one.
+ */
+enum qspi_ip6514e_error_t qspi_ip6514e_send_write_cmd(
+ struct qspi_ip6514e_dev_t* dev,
+ uint8_t opcode,
+ const void *write_data,
+ uint32_t write_len,
+ uint32_t addr,
+ uint32_t addr_bytes_number,
+ uint32_t dummy_cycles);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __QSPI_IP6514E_DRV_H__ */
diff --git a/platform/ext/target/musca_s1/partition/flash_layout.h b/platform/ext/target/musca_s1/partition/flash_layout.h
index 2c3d4d2686..bec8cc84e2 100644
--- a/platform/ext/target/musca_s1/partition/flash_layout.h
+++ b/platform/ext/target/musca_s1/partition/flash_layout.h
@@ -25,13 +25,14 @@
* 0x0A10_0000 Secure image secondary (384 KB)
* 0x0A16_0000 Non-secure image secondary (512 KB)
* 0x0A1E_0000 Scratch Area (16 KB)
- * 0x0A1E_4000 Protected Storage Area (20 KB)
- * 0x0A1E_9000 Internal Trusted Storage Area (16 KB)
- * 0x0A1E_D000 NV counters area (4 KB)
- * 0x0A1E_E000 TF-M key area (256 bytes) This area is referred to in
+ * 0x0A1E_4000 Internal Trusted Storage Area (16 KB)
+ * 0x0A1E_8000 NV counters area (4 KB)
+ * 0x0A1E_9000 TF-M key area (256 bytes) This area is referred to in
* /lib/ext/cryptocell-312-runtime/shared/hw/include/musca_s1/ \
* dx_reg_base_host.h Do not change one without changing the other.
- * 0x0A1E_E100 Unused
+ * 0x0A1E_9100 Unused
+ * 0x0020_0000 Protected storage area (20 KB) This area is placed in the QSPI
+ * flash
*
* Flash layout on Musca-S1 with BL2(single image boot):
* 0x0A00_0000 BL2 - MCUBoot(128 KB)
@@ -42,13 +43,14 @@
* 0x0A10_0000 Secure image secondary (384 KB)
* 0x0A16_0000 Non-secure image secondary (512 KB)
* 0x0A1E_0000 Scratch Area (16 KB)
- * 0x0A1E_4000 Protected Storage Area (20 KB)
- * 0x0A1E_9000 Internal Trusted Storage Area (16 KB)
- * 0x0A1E_D000 NV counters area (4 KB)
- * 0x0A1E_E000 TF-M key area (256 bytes) This area is referred to in
+ * 0x0A1E_4000 Internal Trusted Storage Area (16 KB)
+ * 0x0A1E_8000 NV counters area (4 KB)
+ * 0x0A1E_9000 TF-M key area (256 bytes) This area is referred to in
* /lib/ext/cryptocell-312-runtime/shared/hw/include/musca_s1/ \
* dx_reg_base_host.h Do not change one without changing the other.
- * 0x0A1E_E100 Unused
+ * 0x0A1E_9100 Unused
+ * 0x0020_0000 Protected storage area (20 KB) This area is placed in the QSPI
+ * flash
*
* Flash layout on Musca-S1 without BL2:
* 0x0A00_0000 Secure image
@@ -140,17 +142,9 @@
#error "Only MCUBOOT_IMAGE_NUMBER 1 and 2 are supported!"
#endif /* MCUBOOT_IMAGE_NUMBER */
-/* Note: FLASH_PS_AREA_OFFSET, FLASH_ITS_AREA_OFFSET and
- * FLASH_NV_COUNTERS_AREA_OFFSET point to offsets in flash, but reads and writes
- * to these addresses are redirected to Code SRAM by Driver_Flash.c.
- */
-#define FLASH_PS_AREA_OFFSET (FLASH_AREA_SCRATCH_OFFSET + \
- FLASH_AREA_SCRATCH_SIZE)
-#define FLASH_PS_AREA_SIZE (0x5000) /* 20 KB */
-
/* Internal Trusted Storage (ITS) Service definitions */
-#define FLASH_ITS_AREA_OFFSET (FLASH_PS_AREA_OFFSET + \
- FLASH_PS_AREA_SIZE)
+#define FLASH_ITS_AREA_OFFSET (FLASH_AREA_SCRATCH_OFFSET + \
+ FLASH_AREA_SCRATCH_SIZE)
#define FLASH_ITS_AREA_SIZE (0x4000) /* 16 KB */
/* NV Counters definitions */
@@ -180,15 +174,15 @@
* Note: Further documentation of these definitions can be found in the
* TF-M PS Integration Guide.
*/
-#define TFM_HAL_PS_FLASH_DRIVER Driver_FLASH0
+#define TFM_HAL_PS_FLASH_DRIVER Driver_QSPI_FLASH0
/* In this target the CMSIS driver requires only the offset from the base
* address instead of the full memory address.
*/
/* Base address of dedicated flash area for PS */
-#define TFM_HAL_PS_FLASH_AREA_ADDR FLASH_PS_AREA_OFFSET
+#define TFM_HAL_PS_FLASH_AREA_ADDR 0x0
/* Size of dedicated flash area for PS */
-#define TFM_HAL_PS_FLASH_AREA_SIZE FLASH_PS_AREA_SIZE
+#define TFM_HAL_PS_FLASH_AREA_SIZE (0x5000) /* 20 KB */
#define PS_RAM_FS_SIZE TFM_HAL_PS_FLASH_AREA_SIZE
/* Number of physical erase sectors per logical FS block */
#define TFM_HAL_PS_SECTORS_PER_BLOCK (1)
diff --git a/platform/ext/target/musca_s1/target_cfg.c b/platform/ext/target/musca_s1/target_cfg.c
index 75a1e77b38..a512953933 100644
--- a/platform/ext/target/musca_s1/target_cfg.c
+++ b/platform/ext/target/musca_s1/target_cfg.c
@@ -635,12 +635,6 @@ int32_t ppc_init_cfg(void)
if (ret != ARM_DRIVER_OK) {
return ret;
}
- ret = Driver_APB_PPCEXP1.ConfigPeriph(MUSCA_S1_QSPI_APB_PPC_POS,
- ARM_PPC_NONSECURE_ONLY,
- ARM_PPC_PRIV_AND_NONPRIV);
- if (ret != ARM_DRIVER_OK) {
- return ret;
- }
ret = Driver_APB_PPCEXP1.ConfigPeriph(MUSCA_S1_GPTIMER0_APB_PPC_POS,
ARM_PPC_NONSECURE_ONLY,
ARM_PPC_PRIV_AND_NONPRIV);