Platform: Add MUSCA_B1_SECURE_ENCLAVE platform
Change-Id: Iffbfe782222332fa0b94fc26c2eb9832d487f63e
Signed-off-by: Gabor Abonyi <gabor.abonyi@arm.com>
Signed-off-by: Mark Horvath <mark.horvath@arm.com>
diff --git a/docs/getting_started/tfm_user_guide.rst b/docs/getting_started/tfm_user_guide.rst
index d834785..58746ef 100644
--- a/docs/getting_started/tfm_user_guide.rst
+++ b/docs/getting_started/tfm_user_guide.rst
@@ -427,6 +427,12 @@
srec_cat bin/tfm_s.bin -Binary -offset 0xA000000 bin/tfm_ns.bin -Binary -offset 0xA080000 -o tfm.hex -Intel
+Example application or regression tests on Musca-B1 using the Secure Enclave
+============================================================================
+
+Follow the above procedures, but to create a unified hex please check the
+:doc:`Musca-B1 Secure Enclave readme </platform/ext/target/musca_b1_secure_enclave/readme>`.
+
********************************************************
Execute TF-M example and regression tests on MPS3 boards
********************************************************
diff --git a/docs/introduction/readme.rst b/docs/introduction/readme.rst
index 914ea6d..e867ba3 100644
--- a/docs/introduction/readme.rst
+++ b/docs/introduction/readme.rst
@@ -160,6 +160,10 @@
- `PSoc64.
<https://www.cypress.com/documentation/product-brochures/cypress-psoc-64-secure-microcontrollers>`_
+ - Secure Enclave system:
+
+ - :doc:`Musca-B1 Secure Enclave. </platform/ext/target/musca_b1_secure_enclave/readme>`
+
The document :doc:`Platform Deprecation and Removal </docs/contributing/platform_deprecation>`
lists the deprecated platforms planned to be removed from upstream.
diff --git a/lib/ext/cryptocell-312-runtime/shared/hw/include/musca_b1_secure_enclave/dx_reg_base_host.h b/lib/ext/cryptocell-312-runtime/shared/hw/include/musca_b1_secure_enclave/dx_reg_base_host.h
new file mode 100644
index 0000000..2cf0368
--- /dev/null
+++ b/lib/ext/cryptocell-312-runtime/shared/hw/include/musca_b1_secure_enclave/dx_reg_base_host.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2001-2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __DX_REG_BASE_HOST_H__
+#define __DX_REG_BASE_HOST_H__
+
+/* Identify platform: ARM MUSCA_B1_SECURE_ENCLAVE */
+#define DX_PLAT_MUSCA_B1_SECURE_ENCLAVE 1
+
+#define DX_BASE_CC 0x50088000
+
+#define DX_BASE_HOST_RGF 0x0UL
+#define DX_BASE_CRY_KERNEL 0x0UL
+
+#define DX_BASE_RNG 0x0000UL
+#endif /*__DX_REG_BASE_HOST_H__*/
diff --git a/platform/ext/target/musca_b1_secure_enclave/CMSIS_Driver/Config/RTE_Device.h b/platform/ext/target/musca_b1_secure_enclave/CMSIS_Driver/Config/RTE_Device.h
new file mode 100644
index 0000000..6303551
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/CMSIS_Driver/Config/RTE_Device.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018-2020 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.
+ */
+
+//-------- <<< Use Configuration Wizard in Context Menu >>> --------------------
+
+#ifndef __RTE_DEVICE_H__
+#define __RTE_DEVICE_H__
+
+// <e> QSPI FLASH (Flash Memory) [Driver_QSPI_FLASH0]
+// <i> Configuration settings for Driver_QSPI_FLASH0 in component ::Drivers:FLASH
+#define RTE_QSPI_FLASH0 1
+// </e> QSPI FLASH (Flash Memory) [Driver_QSPI_FLASH0]
+
+// <e> EFLASH (Flash Memory) [Driver_EFLASH0]
+// <i> Configuration settings for Driver_EFLASH0 in component ::Drivers:FLASH
+#define RTE_EFLASH0 1
+// </e> EFLASH (Flash Memory) [Driver_EFLASH0]
+
+// <e> EFLASH (Flash Memory) [Driver_EFLASH1]
+// <i> Configuration settings for Driver_EFLASH1 in component ::Drivers:FLASH
+#define RTE_EFLASH1 1
+// </e> EFLASH (Flash Memory) [Driver_EFLASH1]
+
+#endif /* __RTE_DEVICE_H__ */
diff --git a/platform/ext/target/musca_b1_secure_enclave/CMSIS_Driver/Config/cmsis_driver_config.h b/platform/ext/target/musca_b1_secure_enclave/CMSIS_Driver/Config/cmsis_driver_config.h
new file mode 100644
index 0000000..b633da3
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/CMSIS_Driver/Config/cmsis_driver_config.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018-2020 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.
+ */
+
+#ifndef __CMSIS_DRIVER_CONFIG_H__
+#define __CMSIS_DRIVER_CONFIG_H__
+
+#include "device_cfg.h"
+#include "device_definition.h"
+#include "platform_description.h"
+#include "RTE_Device.h"
+#include "target_cfg.h"
+
+#define FLASH0_DEV MT25QL_DEV_S
+#define EFLASH0_DEV GFC100_EFLASH0_DEV_S
+#define EFLASH1_DEV GFC100_EFLASH1_DEV_S
+
+#endif /* __CMSIS_DRIVER_CONFIG_H__ */
diff --git a/platform/ext/target/musca_b1_secure_enclave/CMSIS_Driver/Driver_GFC100_EFlash.c b/platform/ext/target/musca_b1_secure_enclave/CMSIS_Driver/Driver_GFC100_EFlash.c
new file mode 100644
index 0000000..c929e7e
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/CMSIS_Driver/Driver_GFC100_EFlash.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2018-2020 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 "gfc100_eflash_drv.h"
+#include "RTE_Device.h"
+#include "device_cfg.h"
+#include "device_definition.h"
+#include "system_core_init.h"
+#include "cmsis_driver_config.h"
+
+/**
+ * \file Driver_GFC100_EFlash.c
+ *
+ * \brief CMSIS Flash driver for GFC100 flash controller
+ */
+
+#ifndef ARG_UNUSED
+#define ARG_UNUSED(arg) (void)arg
+#endif
+
+#ifndef ARG_NOT_USED
+#define ARG_NOT_USED 0U
+#endif
+
+/* Driver version */
+#define ARM_FLASH_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1, 0)
+
+const ARM_DRIVER_VERSION GFC100_EFlash_Driver_Version = {
+ ARM_FLASH_API_VERSION, /* Defined in the CMSIS Flash Driver header file */
+ ARM_FLASH_DRV_VERSION
+};
+
+/**
+ * Event ready values for ARM_FLASH_CAPABILITIES::event_ready
+ * \ref ARM_FLASH_CAPABILITIES
+ */
+enum {
+ EVENT_READY_NOT_AVAILABLE = 0u,
+ EVENT_READY_AVAILABLE
+};
+
+/**
+ * Data width values for ARM_FLASH_CAPABILITIES::data_width
+ * \ref ARM_FLASH_CAPABILITIES
+ */
+ enum {
+ DATA_WIDTH_8BIT = 0u,
+ DATA_WIDTH_16BIT,
+ DATA_WIDTH_32BIT
+};
+
+/**
+ * Erase chip values for ARM_FLASH_CAPABILITIES::erase_chip
+ * \ref ARM_FLASH_CAPABILITIES
+ */
+enum {
+ CHIP_ERASE_NOT_SUPPORTED = 0u,
+ CHIP_ERASE_SUPPORTED
+};
+
+/** Driver Capabilities */
+static const ARM_FLASH_CAPABILITIES DriverCapabilities = {
+ .event_ready = EVENT_READY_NOT_AVAILABLE,
+ .data_width = DATA_WIDTH_32BIT,
+ .erase_chip = CHIP_ERASE_SUPPORTED
+};
+
+/**
+ * \brief Flash busy values flash status \ref ARM_FLASH_STATUS
+ */
+enum {
+ DRIVER_STATUS_IDLE = 0u,
+ DRIVER_STATUS_BUSY
+};
+
+/**
+ * \brief Flash error values flash status \ref ARM_FLASH_STATUS
+ */
+enum {
+ DRIVER_STATUS_NO_ERROR = 0u,
+ DRIVER_STATUS_ERROR
+};
+
+/**
+ * \brief Arm Flash device structure.
+ */
+typedef struct _FLASHx_Resources {
+ struct gfc100_eflash_dev_t* dev; /*!< FLASH memory device structure */
+ ARM_FLASH_INFO *data; /*!< FLASH memory device data */
+ ARM_FLASH_STATUS status;
+} ARM_FLASHx_Resources;
+
+static ARM_DRIVER_VERSION ARM_Flash_GetVersion(void)
+{
+ return GFC100_EFlash_Driver_Version;
+}
+
+static ARM_FLASH_CAPABILITIES ARM_Flash_GetCapabilities(void)
+{
+ return DriverCapabilities;
+}
+
+static int32_t ARM_Flashx_Initialize(ARM_FLASHx_Resources *ARM_FLASHx_DEV,
+ ARM_Flash_SignalEvent_t cb_event)
+{
+ ARG_UNUSED(cb_event);
+
+ uint32_t page_size = gfc100_get_eflash_page_size(ARM_FLASHx_DEV->dev);
+ uint32_t flash_size = gfc100_get_eflash_size(ARM_FLASHx_DEV->dev);
+
+ /* Validate hardcoded parameters of the flash */
+ if ((ARM_FLASHx_DEV->data->page_size != page_size) ||
+ (ARM_FLASHx_DEV->data->sector_size != page_size) ||
+ (ARM_FLASHx_DEV->data->sector_count != (flash_size / page_size))) {
+ return ARM_DRIVER_ERROR_PARAMETER;
+ }
+
+ gfc100_eflash_init(ARM_FLASHx_DEV->dev, SystemCoreClock);
+
+ return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flashx_Uninitialize(ARM_FLASHx_Resources *ARM_FLASHx_DEV)
+{
+ ARG_UNUSED(ARM_FLASHx_DEV);
+
+ /* Nothing to do */
+ return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flashx_PowerControl(ARM_FLASHx_Resources *ARM_FLASHx_DEV,
+ ARM_POWER_STATE state)
+{
+ ARG_UNUSED(ARM_FLASHx_DEV);
+
+ switch(state) {
+ case ARM_POWER_FULL:
+ /* Nothing to do */
+ 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_Flashx_ReadData(ARM_FLASHx_Resources *ARM_FLASHx_DEV,
+ uint32_t addr, void *data, uint32_t cnt)
+{
+ enum gfc100_error_t err = GFC100_ERROR_NONE;
+ uint32_t flash_size = gfc100_get_eflash_size(ARM_FLASHx_DEV->dev);
+
+ ARM_FLASHx_DEV->status.error = DRIVER_STATUS_NO_ERROR;
+
+ /* Check if range is valid */
+ if ((addr + cnt) > flash_size) {
+ ARM_FLASHx_DEV->status.error = DRIVER_STATUS_ERROR;
+ return ARM_DRIVER_ERROR_PARAMETER;
+ }
+
+ ARM_FLASHx_DEV->status.busy = DRIVER_STATUS_BUSY;
+
+ err = gfc100_eflash_read(ARM_FLASHx_DEV->dev, addr, data, &cnt);
+
+ ARM_FLASHx_DEV->status.busy = DRIVER_STATUS_IDLE;
+
+ if(err != GFC100_ERROR_NONE) {
+ ARM_FLASHx_DEV->status.error = DRIVER_STATUS_ERROR;
+ return ARM_DRIVER_ERROR;
+ }
+
+ return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flashx_ProgramData(ARM_FLASHx_Resources *ARM_FLASHx_DEV,
+ uint32_t addr, const void *data,
+ uint32_t cnt)
+{
+ enum gfc100_error_t err = GFC100_ERROR_NONE;
+
+ ARM_FLASHx_DEV->status.error = DRIVER_STATUS_NO_ERROR;
+ ARM_FLASHx_DEV->status.busy = DRIVER_STATUS_BUSY;
+
+ /* Note: There is a significantly faster way to write to the flash using
+ * gfc100_eflash_row_write. It has the disadvantage that all IRQs have
+ * to be disabled, because the implementation is sensitive to timing.
+ * For applications where timing can be guaranteed this can be replaced
+ * with gfc100_eflash_row_write. For generic use, simple write is used here.
+ */
+ err = gfc100_eflash_write(ARM_FLASHx_DEV->dev, addr, data, &cnt);
+
+ ARM_FLASHx_DEV->status.busy = DRIVER_STATUS_IDLE;
+
+ if(err != GFC100_ERROR_NONE) {
+ ARM_FLASHx_DEV->status.error = DRIVER_STATUS_ERROR;
+ if ((err == GFC100_ERROR_OUT_OF_RANGE) ||
+ (err == GFC100_ERROR_UNALIGNED_PARAM)) {
+ /* The native driver checks aligment and range */
+ return ARM_DRIVER_ERROR_PARAMETER;
+ }
+ return ARM_DRIVER_ERROR;
+ }
+
+ return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flashx_EraseSector(ARM_FLASHx_Resources *ARM_FLASHx_DEV,
+ uint32_t addr)
+{
+ enum gfc100_error_t err = GFC100_ERROR_NONE;
+
+ ARM_FLASHx_DEV->status.error = DRIVER_STATUS_NO_ERROR;
+ ARM_FLASHx_DEV->status.busy = DRIVER_STATUS_BUSY;
+
+ /* The erase function checks whether the address is within the valid flash
+ * address range, and the HW will align the address to page boundary if
+ * it is not aligned.
+ */
+ err = gfc100_eflash_erase(ARM_FLASHx_DEV->dev, addr, GFC100_ERASE_PAGE);
+
+ ARM_FLASHx_DEV->status.busy = DRIVER_STATUS_IDLE;
+
+ if (err != GFC100_ERROR_NONE) {
+ ARM_FLASHx_DEV->status.error = DRIVER_STATUS_ERROR;
+ if (err == GFC100_ERROR_OUT_OF_RANGE) {
+ return ARM_DRIVER_ERROR_PARAMETER;
+ }
+ return ARM_DRIVER_ERROR;
+ }
+
+ return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flashx_EraseChip(ARM_FLASHx_Resources *ARM_FLASHx_DEV)
+{
+ enum gfc100_error_t err = GFC100_ERROR_NONE;
+
+ ARM_FLASHx_DEV->status.error = DRIVER_STATUS_NO_ERROR;
+ ARM_FLASHx_DEV->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 = gfc100_eflash_erase(ARM_FLASHx_DEV->dev, ARG_NOT_USED,
+ GFC100_MASS_ERASE_MAIN_AREA);
+
+ ARM_FLASHx_DEV->status.busy = DRIVER_STATUS_IDLE;
+
+ if(err != GFC100_ERROR_NONE) {
+ ARM_FLASHx_DEV->status.error = DRIVER_STATUS_ERROR;
+ return ARM_DRIVER_ERROR;
+ }
+
+ return ARM_DRIVER_OK;
+}
+
+static ARM_FLASH_STATUS
+ARM_Flashx_GetStatus(ARM_FLASHx_Resources *ARM_FLASHx_DEV)
+{
+ return ARM_FLASHx_DEV->status;
+}
+
+static ARM_FLASH_INFO * ARM_Flashx_GetInfo(ARM_FLASHx_Resources *ARM_FLASHx_DEV)
+{
+ return ARM_FLASHx_DEV->data;
+}
+
+#if (RTE_EFLASH0)
+static ARM_FLASH_INFO ARM_FLASH0_DEV_DATA = {
+ .sector_info = NULL, /* Uniform sector layout */
+ .sector_count = (0x200000u / 0x4000u), /* 2MB (flash size) / 16kB */
+ .sector_size = 0x4000u, /* 16kB - as there are no sectors the page size
+ * size is used here
+ */
+ .page_size = 0x4000u, /* 16kB */
+ .program_unit = 4u, /* Minimum write size in bytes */
+ .erased_value = 0xFF
+};
+
+static ARM_FLASHx_Resources ARM_FLASH0_DEV = {
+ .dev = &EFLASH0_DEV,
+ .data = &(ARM_FLASH0_DEV_DATA),
+ .status = {
+ .busy = DRIVER_STATUS_IDLE,
+ .error = DRIVER_STATUS_NO_ERROR,
+ .reserved = 0,
+ },
+};
+
+static ARM_DRIVER_VERSION ARM_Flash0_GetVersion(void)
+{
+ return ARM_Flash_GetVersion();
+}
+
+static ARM_FLASH_CAPABILITIES ARM_Flash0_GetCapabilities(void)
+{
+ return ARM_Flash_GetCapabilities();
+}
+
+static int32_t ARM_Flash0_Initialize(ARM_Flash_SignalEvent_t cb_event)
+{
+ return ARM_Flashx_Initialize(&ARM_FLASH0_DEV, cb_event);
+}
+
+static int32_t ARM_Flash0_Uninitialize(void)
+{
+ return ARM_Flashx_Uninitialize(&ARM_FLASH0_DEV);
+}
+
+static int32_t ARM_Flash0_PowerControl(ARM_POWER_STATE state)
+{
+ return ARM_Flashx_PowerControl(&ARM_FLASH0_DEV, state);
+}
+
+static int32_t ARM_Flash0_ReadData(uint32_t addr, void *data, uint32_t cnt)
+{
+ return ARM_Flashx_ReadData(&ARM_FLASH0_DEV, addr, data, cnt);
+}
+
+static int32_t ARM_Flash0_ProgramData(uint32_t addr, const void *data,
+ uint32_t cnt)
+{
+ return ARM_Flashx_ProgramData(&ARM_FLASH0_DEV, addr, data, cnt);
+}
+
+static int32_t ARM_Flash0_EraseSector(uint32_t addr)
+{
+ return ARM_Flashx_EraseSector(&ARM_FLASH0_DEV, addr);
+}
+
+static int32_t ARM_Flash0_EraseChip(void)
+{
+ return ARM_Flashx_EraseChip(&ARM_FLASH0_DEV);
+}
+
+static ARM_FLASH_STATUS ARM_Flash0_GetStatus(void)
+{
+ return ARM_Flashx_GetStatus(&ARM_FLASH0_DEV);
+}
+
+static ARM_FLASH_INFO * ARM_Flash0_GetInfo(void)
+{
+ return ARM_Flashx_GetInfo(&ARM_FLASH0_DEV);
+}
+
+ARM_DRIVER_FLASH Driver_EFLASH0 = {
+ ARM_Flash0_GetVersion,
+ ARM_Flash0_GetCapabilities,
+ ARM_Flash0_Initialize,
+ ARM_Flash0_Uninitialize,
+ ARM_Flash0_PowerControl,
+ ARM_Flash0_ReadData,
+ ARM_Flash0_ProgramData,
+ ARM_Flash0_EraseSector,
+ ARM_Flash0_EraseChip,
+ ARM_Flash0_GetStatus,
+ ARM_Flash0_GetInfo
+};
+#endif /* RTE_EFLASH0 */
+
+#if (RTE_EFLASH1)
+static ARM_FLASH_INFO ARM_FLASH1_DEV_DATA = {
+ .sector_info = NULL, /* Uniform sector layout */
+ .sector_count = (0x200000u / 0x4000u), /* 2MB (flash size) / 16kB */
+ .sector_size = 0x4000u, /* 16kB - as there are no sectors the page size
+ * size is used here
+ */
+ .page_size = 0x4000u, /* 16kB */
+ .program_unit = 4u, /* Minimum write size in bytes */
+ .erased_value = 0xFF
+};
+
+static ARM_FLASHx_Resources ARM_FLASH1_DEV = {
+ .dev = &EFLASH1_DEV,
+ .data = &ARM_FLASH1_DEV_DATA,
+ .status = {
+ .busy = DRIVER_STATUS_IDLE,
+ .error = DRIVER_STATUS_NO_ERROR,
+ .reserved = 0,
+ },
+};
+
+static ARM_DRIVER_VERSION ARM_Flash1_GetVersion(void)
+{
+ return ARM_Flash_GetVersion();
+}
+
+static ARM_FLASH_CAPABILITIES ARM_Flash1_GetCapabilities(void)
+{
+ return ARM_Flash_GetCapabilities();
+}
+
+static int32_t ARM_Flash1_Initialize(ARM_Flash_SignalEvent_t cb_event)
+{
+ return ARM_Flashx_Initialize(&ARM_FLASH1_DEV, cb_event);
+}
+
+static int32_t ARM_Flash1_Uninitialize(void)
+{
+ return ARM_Flashx_Uninitialize(&ARM_FLASH1_DEV);
+}
+
+static int32_t ARM_Flash1_PowerControl(ARM_POWER_STATE state)
+{
+ return ARM_Flashx_PowerControl(&ARM_FLASH1_DEV, state);
+}
+
+static int32_t ARM_Flash1_ReadData(uint32_t addr, void *data, uint32_t cnt)
+{
+ return ARM_Flashx_ReadData(&ARM_FLASH1_DEV, addr, data, cnt);
+}
+
+static int32_t ARM_Flash1_ProgramData(uint32_t addr, const void *data,
+ uint32_t cnt)
+{
+ return ARM_Flashx_ProgramData(&ARM_FLASH1_DEV, addr, data, cnt);
+}
+
+static int32_t ARM_Flash1_EraseSector(uint32_t addr)
+{
+ return ARM_Flashx_EraseSector(&ARM_FLASH1_DEV, addr);
+}
+
+static int32_t ARM_Flash1_EraseChip(void)
+{
+ return ARM_Flashx_EraseChip(&ARM_FLASH1_DEV);
+}
+
+static ARM_FLASH_STATUS ARM_Flash1_GetStatus(void)
+{
+ return (ARM_Flashx_GetStatus(&ARM_FLASH1_DEV));
+}
+
+static ARM_FLASH_INFO * ARM_Flash1_GetInfo(void)
+{
+ return ARM_Flashx_GetInfo(&ARM_FLASH1_DEV);
+}
+
+ARM_DRIVER_FLASH Driver_EFLASH1 = {
+ ARM_Flash1_GetVersion,
+ ARM_Flash1_GetCapabilities,
+ ARM_Flash1_Initialize,
+ ARM_Flash1_Uninitialize,
+ ARM_Flash1_PowerControl,
+ ARM_Flash1_ReadData,
+ ARM_Flash1_ProgramData,
+ ARM_Flash1_EraseSector,
+ ARM_Flash1_EraseChip,
+ ARM_Flash1_GetStatus,
+ ARM_Flash1_GetInfo
+};
+#endif /* RTE_EFLASH1 */
diff --git a/platform/ext/target/musca_b1_secure_enclave/CMSIS_Driver/Driver_QSPI_Flash.c b/platform/ext/target/musca_b1_secure_enclave/CMSIS_Driver/Driver_QSPI_Flash.c
new file mode 100644
index 0000000..195cb80
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/CMSIS_Driver/Driver_QSPI_Flash.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2013-2020 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 "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
+};
+
+/**
+ * \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 = QSPI_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 = QSPI_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 = &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)
+{
+ enum mt25ql_error_t err = MT25QL_ERR_NONE;
+ bool is_valid = true;
+
+ 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;
+
+ err = mt25ql_command_read(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_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, 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_b1_secure_enclave/CMakeLists.txt b/platform/ext/target/musca_b1_secure_enclave/CMakeLists.txt
new file mode 100644
index 0000000..f8253d3
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/CMakeLists.txt
@@ -0,0 +1,126 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+cmake_policy(SET CMP0076 NEW)
+set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR})
+
+#========================= Platform region defs ===============================#
+
+target_include_directories(platform_region_defs
+ INTERFACE
+ partition
+)
+
+#========================= Platform common defs ===============================#
+
+# Specify the location of platform specific build dependencies.
+target_sources(tfm_s
+ PRIVATE
+ $<$<C_COMPILER_ID:ARMClang>:${CMAKE_CURRENT_SOURCE_DIR}/Device/Source/armclang/startup_musca_b1_secure_enclave_s.s>
+ $<$<C_COMPILER_ID:GNU>:${CMAKE_CURRENT_SOURCE_DIR}/Device/Source/gcc/startup_musca_b1_secure_enclave_s.S>
+ # This file contains an IRQ handler. Linking it from a different library to
+ # overwrite the default weak function would require intrusive cmake hacks.
+ mailbox/mailbox_ipc_intr.c
+)
+target_add_scatter_file(tfm_s
+ $<$<C_COMPILER_ID:ARMClang>:${CMAKE_BINARY_DIR}/generated/platform/ext/common/armclang/tfm_common_s.sct>
+ $<$<C_COMPILER_ID:GNU>:${CMAKE_BINARY_DIR}/generated/platform/ext/common/gcc/tfm_common_s.ld>
+)
+
+if(BL2)
+ target_sources(bl2
+ PRIVATE
+ $<$<C_COMPILER_ID:ARMClang>:${CMAKE_CURRENT_SOURCE_DIR}/Device/Source/armclang/startup_musca_b1_secure_enclave_bl2.s>
+ $<$<C_COMPILER_ID:GNU>:${CMAKE_CURRENT_SOURCE_DIR}/Device/Source/gcc/startup_musca_b1_secure_enclave_bl2.S>
+ )
+ target_add_scatter_file(bl2
+ $<$<C_COMPILER_ID:ARMClang>:${CMAKE_CURRENT_SOURCE_DIR}/Device/Source/armclang/musca_b1_secure_enclave_bl2.sct>
+ $<$<C_COMPILER_ID:GNU>:${CMAKE_CURRENT_SOURCE_DIR}/Device/Source/gcc/musca_b1_secure_enclave_bl2.ld>
+ )
+endif()
+
+#========================= Platform Secure ====================================#
+
+target_include_directories(platform_s
+ PUBLIC
+ .
+ CMSIS_Driver
+ CMSIS_Driver/Config
+ Device/Config
+ Device/Include
+ Native_Driver
+ partition
+ services/include
+ Libraries
+ mailbox
+)
+
+target_sources(platform_s
+ PRIVATE
+ CMSIS_Driver/Driver_GFC100_EFlash.c
+ Native_Driver/musca_b1_eflash_drv.c
+ Native_Driver/gfc100_eflash_drv.c
+ CMSIS_Driver/Driver_QSPI_Flash.c
+ Native_Driver/qspi_ip6514e_drv.c
+ Libraries/mt25ql_flash_lib.c
+ Native_Driver/mhu_v2_x.c
+ Device/Source/device_definition.c
+ Device/Source/system_core_init.c
+ mailbox/platform_multicore.c
+ mailbox/platform_spe_mailbox.c
+ spm_hal.c
+ target_cfg.c
+ tfm_hal_isolation.c
+ uart_stdout.c
+ $<$<BOOL:TFM_PARTITION_PLATFORM>:${CMAKE_CURRENT_SOURCE_DIR}/services/src/tfm_platform_system.c>
+)
+
+target_link_libraries(platform_s
+ PUBLIC
+ tfm_spm
+)
+#========================= Platform Non-Secure ================================#
+
+# FIXME: platform_ns must have at least 1 source, even if it is not used
+target_sources(platform_ns
+ PRIVATE
+ Device/Source/system_core_init.c
+)
+
+target_include_directories(platform_ns
+ PUBLIC
+ Device/Include
+)
+
+#========================= Platform BL2 =======================================#
+
+if(BL2)
+ target_sources(platform_bl2
+ PRIVATE
+ boot_hal.c
+ Device/Source/system_core_init.c
+ Device/Source/device_definition.c
+ CMSIS_Driver/Driver_GFC100_EFlash.c
+ Native_Driver/gfc100_eflash_drv.c
+ Native_Driver/musca_b1_eflash_drv.c
+ uart_stdout.c
+ )
+
+ target_include_directories(platform_bl2
+ PUBLIC
+ partition
+ Device/Include
+ PRIVATE
+ .
+ CMSIS_Driver/Config
+ Device/Config
+ Native_Driver
+ Libraries
+ ${MCUBOOT_PATH}/boot/bootutil/include # for fault_injection_hardening.h only
+ ${CMAKE_CURRENT_BINARY_DIR}/../../../../bl2/ext/mcuboot # for mcuboot_con
+ )
+endif()
diff --git a/platform/ext/target/musca_b1_secure_enclave/Device/Config/device_cfg.h b/platform/ext/target/musca_b1_secure_enclave/Device/Config/device_cfg.h
new file mode 100644
index 0000000..b093b19
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Device/Config/device_cfg.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017-2020 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.
+ */
+
+#ifndef __MUSCA_B1_SECURE_ENCLAVE_DEVICE_CFG_H__
+#define __MUSCA_B1_SECURE_ENCLAVE_DEVICE_CFG_H__
+
+/**
+ * \file device_cfg.h
+ * \brief Configuration file native driver re-targeting
+ *
+ * \details This file can be used to add native driver specific macro
+ * definitions to select which peripherals are available in the build.
+ *
+ * This is a default device configuration file with all peripherals enabled.
+ */
+
+/* GFC-100 EFlash controller */
+#define GFC100_EFLASH0_S
+#define GFC100_EFLASH1_S
+
+/* Cadence QSPI Flash Controller */
+#define QSPI_IP6514E_S
+
+/* MT25QL Flash memory library */
+#define MT25QL_S
+
+/* MHU */
+#define MHU0_SENDER
+#define MHU0_RECEIVER
+
+#endif /* __MUSCA_B1_SECURE_ENCLAVE_DEVICE_CFG_H__ */
diff --git a/platform/ext/target/musca_b1_secure_enclave/Device/Include/cmsis.h b/platform/ext/target/musca_b1_secure_enclave/Device/Include/cmsis.h
new file mode 100644
index 0000000..97e5643
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Device/Include/cmsis.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2009-2020 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.
+ */
+
+#ifndef __CMSIS_H__
+#define __CMSIS_H__
+
+/* Configuration of the ARM Cortex-M0+ Processor and Core Peripherals */
+#define __CM0PLUS_REV 0x0001U /* CM0PLUS Core Revision */
+#define __NVIC_PRIO_BITS 2 /* Number of Bits used for Priority Levels */
+#define __Vendor_SysTickConfig 0 /* Set to 1 if different SysTick Config is used */
+#define __VTOR_PRESENT 1 /* Set to 1 if CPU supports Vector Table Offset Register */
+#define __MPU_PRESENT 1 /* MPU present */
+
+#include "cmsis_compiler.h"
+#include "platform_base_address.h"
+#include "system_core_init.h"
+#include "platform_irq.h"
+#include "core_cm0plus.h"
+
+#endif /*__CMSIS_H__ */
diff --git a/platform/ext/target/musca_b1_secure_enclave/Device/Include/device_definition.h b/platform/ext/target/musca_b1_secure_enclave/Device/Include/device_definition.h
new file mode 100644
index 0000000..2f1c02e
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Device/Include/device_definition.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017-2020 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.
+ */
+
+/**
+ * \file device_definition.h
+ * \brief The structure definitions in this file are exported based on the
+ * peripheral definitions from device_cfg.h.
+ * This file is meant to be used as a helper for baremetal
+ * applications and/or as an example of how to configure the generic
+ * driver structures.
+ */
+
+#ifndef __MUSCA_B1_SECURE_ENCLAVE_DEVICE_DEFINITION_H__
+#define __MUSCA_B1_SECURE_ENCLAVE_DEVICE_DEFINITION_H__
+
+#include "device_cfg.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef GFC100_EFLASH0_S
+#include "gfc100_eflash_drv.h"
+extern struct gfc100_eflash_dev_t GFC100_EFLASH0_DEV_S;
+#endif
+#ifdef GFC100_EFLASH1_S
+#include "gfc100_eflash_drv.h"
+extern struct gfc100_eflash_dev_t GFC100_EFLASH1_DEV_S;
+#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
+
+/* MT25QL Flash memory library structures */
+#if (defined(MT25QL_S) && defined(QSPI_IP6514E_S))
+#include "mt25ql_flash_lib.h"
+extern struct mt25ql_dev_t MT25QL_DEV_S;
+#endif
+
+/* MHU driver structures */
+#ifdef MHU0_SENDER
+#include "mhu_v2_x.h"
+extern struct mhu_v2_x_dev_t MHU0_SENDER_DEV;
+#endif
+
+#ifdef MHU0_RECEIVER
+#include "mhu_v2_x.h"
+extern struct mhu_v2_x_dev_t MHU0_RECEIVER_DEV;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MUSCA_B1_SECURE_ENCLAVE_DEVICE_DEFINITION_H__ */
diff --git a/platform/ext/target/musca_b1_secure_enclave/Device/Include/platform_base_address.h b/platform/ext/target/musca_b1_secure_enclave/Device/Include/platform_base_address.h
new file mode 100644
index 0000000..a0ee419
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Device/Include/platform_base_address.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020 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.
+ */
+
+#ifndef __MUSCA_B1_SECURE_ENCLAVE_BASE_ADDRESS_H__
+#define __MUSCA_B1_SECURE_ENCLAVE_BASE_ADDRESS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Peripheries from Secure Enclave subsystem */
+#define MHU0_SENDER_FRAME_BASE (0x50003000UL)
+#define MHU0_RECEIVER_FRAME_BASE (0x50004000UL)
+
+/* Peripheries remapped from SSE-200 subsystem with SYS remap
+ * SYS remap offset should be set to 0x5200_0000
+ * SYS remap mask should be set to 0x00FF_FFFF */
+#define REMAPPED_MUSCA_B1_EFLASH0_REG_MAP_S_BASE (0xA0400000UL)
+#define REMAPPED_MUSCA_B1_EFLASH1_REG_MAP_S_BASE (0xA0500000UL)
+#define REMAPPED_MUSCA_B1_QSPI_REG_S_BASE (0xA0800000UL)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MUSCA_B1_SECURE_ENCLAVE_BASE_ADDRESS_H__ */
diff --git a/platform/ext/target/musca_b1_secure_enclave/Device/Include/platform_description.h b/platform/ext/target/musca_b1_secure_enclave/Device/Include/platform_description.h
new file mode 100644
index 0000000..6ea03ba
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Device/Include/platform_description.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018-2020 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.
+ */
+
+#ifndef __MUSCA_B1_SECURE_ENCLAVE_PLATFORM_DESCRIPTION_H__
+#define __MUSCA_B1_SECURE_ENCLAVE_PLATFORM_DESCRIPTION_H__
+
+#include "platform_base_address.h"
+#include "cmsis.h"
+
+#endif /* __MUSCA_B1_SECURE_ENCLAVE_PLATFORM_DESCRIPTION_H__ */
diff --git a/platform/ext/target/musca_b1_secure_enclave/Device/Include/platform_irq.h b/platform/ext/target/musca_b1_secure_enclave/Device/Include/platform_irq.h
new file mode 100644
index 0000000..a5df3f7
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Device/Include/platform_irq.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019-2020 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.
+ */
+
+#ifndef __PLATFORM_IRQ_H__
+#define __PLATFORM_IRQ_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ========================================================================== */
+/* ============= Interrupt Number Definition ================ */
+/* ========================================================================== */
+
+typedef enum IRQn
+{
+ Reset_IRQn = -15, /* !< -15 Reset Vector, invoked on Power up and warm reset */
+ NonMaskableInt_IRQn = -14, /* !< -14 Non maskable Interrupt, cannot be stopped or preempted */
+ HardFault_IRQn = -13, /* !< -13 Hard Fault, all classes of Fault */
+ SVCall_IRQn = -5, /* !< -5 System Service Call via SVC instruction */
+ PendSV_IRQn = -2, /* !< -2 Pendable request for system service */
+ SysTick_IRQn = -1, /* !< -1 System Tick Timer */
+
+ ExternalIRQ_IRQn = 0,
+ CC312_IRQn = 1,
+ CC312_APB_C_IRQn = 2,
+ Watchdog_IRQn = 3,
+ /* reserved = 4, */
+ Timer0_IRQn = 5,
+ Timer1_IRQn = 6,
+ /* reserved = 7, */
+ /* reserved = 8, */
+ GPIO_IRQn = 9,
+ GPIO_0_IRQn = 10,
+ GPIO_1_IRQn = 11,
+ GPIO_2_IRQn = 12,
+ GPIO_3_IRQn = 13,
+ GPIO_4_IRQn = 14,
+ GPIO_5_IRQn = 15,
+ GPIO_6_IRQn = 16,
+ GPIO_7_IRQn = 17,
+ /* reserved = 18, */
+ /* reserved = 19, */
+ /* reserved = 20, */
+ MHU0_NR2R_IRQn = 21,
+ MHU0_R2NR_IRQn = 22,
+ MHU0_COMB_IRQn = 23,
+ MHU0_MSG_0_IRQn = 24,
+ MHU0_MSG_1_IRQn = 25,
+ MHU1_NR2R_IRQn = 26,
+ MHU1_R2NR_IRQn = 27,
+ MHU1_COMB_IRQn = 28,
+ MHU1_MSG_0_IRQn = 29,
+ MHU1_MSG_1_IRQn = 30,
+ /* reserved = 31, */
+} IRQn_Type;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PLATFORM_IRQ_H__ */
diff --git a/platform/ext/target/musca_b1_secure_enclave/Device/Include/system_core_init.h b/platform/ext/target/musca_b1_secure_enclave/Device/Include/system_core_init.h
new file mode 100644
index 0000000..8f4d33c
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Device/Include/system_core_init.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009-2020 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.
+ *
+ * This file is derivative of CMSIS V5.01 \Device\ARM\ARMCM0plus\Include\system_ARMCM0plus.h
+ * Git SHA: 8a1d9d6ee18b143ae5befefa14d89fb5b3f99c75
+ *
+ */
+
+#ifndef __MUSCA_B1_SECURE_ENCLAVE_SYSTEM_CORE_INIT_H__
+#define __MUSCA_B1_SECURE_ENCLAVE_SYSTEM_CORE_INIT_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
+extern uint32_t PeripheralClock; /*!< Peripheral Clock Frequency */
+
+/**
+ \brief Setup the microcontroller system.
+
+ Initialize the System and update the SystemCoreClock variable.
+ It should be called from Reset Handler within the first few steps.
+ The minimal feature set should be initialised for successful exit
+ from Reset Handler to main entry point.
+ */
+extern void SystemInit (void);
+
+
+/**
+ \brief Update SystemCoreClock variable.
+
+ Updates the SystemCoreClock with current core Clock retrieved from cpu registers.
+ */
+extern void SystemCoreClockUpdate (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MUSCA_B1_SECURE_ENCLAVE_SYSTEM_CORE_INIT_H__ */
diff --git a/platform/ext/target/musca_b1_secure_enclave/Device/Source/armclang/musca_b1_secure_enclave_bl2.sct b/platform/ext/target/musca_b1_secure_enclave/Device/Source/armclang/musca_b1_secure_enclave_bl2.sct
new file mode 100644
index 0000000..430dd79
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Device/Source/armclang/musca_b1_secure_enclave_bl2.sct
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018-2020 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 "region_defs.h"
+
+LR_CODE BL2_CODE_START {
+ ER_CODE BL2_CODE_START BL2_CODE_SIZE {
+ *.o (RESET +First)
+ * (+RO)
+ }
+
+ /* eFlash driver code that gets copied from Flash to SRAM */
+ ER_CODE_SRAM EFLASH_DRIVER_REGION_BASE EFLASH_DRIVER_REGION_SIZE {
+ Driver_GFC100_EFlash.o (+RO)
+ gfc100_eflash_drv.o (+RO)
+ musca_b1_eflash_drv.o (+RO)
+ }
+
+ /* Base address of bootloader data area */
+ BL2_DATA_START S_DATA_START {
+ }
+
+ TFM_SHARED_DATA BOOT_TFM_SHARED_DATA_BASE ALIGN 32 EMPTY BOOT_TFM_SHARED_DATA_SIZE {
+ }
+
+ ER_DATA +0 {
+ * (+ZI +RW)
+ }
+
+ /* MSP */
+ ARM_LIB_STACK +0 ALIGN 32 EMPTY BL2_MSP_STACK_SIZE {
+ }
+
+ ARM_LIB_HEAP +0 ALIGN 8 EMPTY BL2_HEAP_SIZE {
+ }
+
+ /* This empty, zero long execution region is here to mark the limit address
+ * of the last execution region that is allocated in SRAM.
+ */
+ SRAM_WATERMARK +0 EMPTY 0x0 {
+ }
+
+ /* Make sure that the sections allocated in the SRAM does not exceed the
+ * size of the SRAM available.
+ */
+ ScatterAssert(ImageLimit(SRAM_WATERMARK) <= BL2_DATA_START + BL2_DATA_SIZE)
+}
diff --git a/platform/ext/target/musca_b1_secure_enclave/Device/Source/armclang/startup_musca_b1_secure_enclave_bl2.s b/platform/ext/target/musca_b1_secure_enclave/Device/Source/armclang/startup_musca_b1_secure_enclave_bl2.s
new file mode 100644
index 0000000..dd92be5
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Device/Source/armclang/startup_musca_b1_secure_enclave_bl2.s
@@ -0,0 +1,154 @@
+;/*
+; * Copyright (c) 2009-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.
+; */
+;
+; This file is derivative of CMSIS V5.01 startup_ARMv8MML.s
+; Git SHA: 8a1d9d6ee18b143ae5befefa14d89fb5b3f99c75
+
+;/*
+;//-------- <<< Use Configuration Wizard in Context Menu >>> ------------------
+;*/
+
+
+; <h> Stack Configuration
+; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
+; </h>
+
+ IMPORT |Image$$ARM_LIB_STACK$$ZI$$Limit|
+
+; Vector Table Mapped to Address 0 at Reset
+
+ AREA RESET, DATA, READONLY
+ EXPORT __Vectors
+ EXPORT __Vectors_End
+ EXPORT __Vectors_Size
+
+__Vectors ;Core Interrupts
+ DCD |Image$$ARM_LIB_STACK$$ZI$$Limit| ; Top of Stack
+ DCD Reset_Handler ; Reset Handler
+ DCD NMI_Handler ; -14 NMI Handler
+ DCD HardFault_Handler ; -13 Hard Fault Handler
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD SVC_Handler ; -5 SVCall Handler
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD PendSV_Handler ; -2 PendSV Handler
+ DCD SysTick_Handler ; -1 SysTick Handler
+
+ ;musca_b1_secure_enclave Interrupts
+ DCD ExternalIRQ_Handler ; 0:
+ DCD CC312_Handler ; 1:
+ DCD CC312_APB_C_Handler ; 2:
+ DCD Watchdog_Handler ; 3:
+ DCD 0 ; 4: Reserved
+ DCD Timer0_Handler ; 5:
+ DCD Timer1_Handler ; 6:
+ DCD 0 ; 7: Reserved
+ DCD 0 ; 8: Reserved
+ DCD GPIO_Handler ; 9:
+ DCD GPIO_0_Handler ; 10:
+ DCD GPIO_1_Handler ; 11:
+ DCD GPIO_2_Handler ; 12:
+ DCD GPIO_3_Handler ; 13:
+ DCD GPIO_4_Handler ; 14:
+ DCD GPIO_5_Handler ; 15:
+ DCD GPIO_6_Handler ; 16:
+ DCD GPIO_7_Handler ; 17:
+ DCD 0 ; 18:
+ DCD 0 ; 19:
+ DCD 0 ; 20:
+ DCD MHU0_NR2R_Handler ; 21:
+ DCD MHU0_R2NR_Handler ; 22:
+ DCD MHU0_COMB_Handler ; 23:
+ DCD MHU0_MSG_0_Handler ; 24:
+ DCD MHU0_MSG_1_Handler ; 25:
+ DCD MHU1_NR2R_Handler ; 26:
+ DCD MHU1_R2NR_Handler ; 27:
+ DCD MHU1_COMB_Handler ; 28:
+ DCD MHU1_MSG_0_Handler ; 29:
+ DCD MHU1_MSG_1_Handler ; 30:
+ DCD 0 ; 31:
+
+__Vectors_End
+
+__Vectors_Size EQU __Vectors_End - __Vectors
+
+; Reset Handler
+ AREA |.text|, CODE, READONLY
+Reset_Handler PROC
+ EXPORT Reset_Handler [WEAK]
+ IMPORT SystemInit
+ IMPORT __main
+ LDR R0, =SystemInit
+ BLX R0
+ LDR R0, =__main
+ BX R0
+ ENDP
+End_Of_Main
+ B .
+
+
+; Dummy Exception Handlers (infinite loops which can be modified)
+ MACRO
+ Default_Handler $handler_name
+$handler_name PROC
+ EXPORT $handler_name [WEAK]
+ B .
+ ENDP
+ MEND
+
+ Default_Handler NMI_Handler
+ Default_Handler HardFault_Handler
+ Default_Handler SVC_Handler
+ Default_Handler PendSV_Handler
+ Default_Handler SysTick_Handler
+
+ Default_Handler ExternalIRQ_Handler
+ Default_Handler CC312_Handler
+ Default_Handler CC312_APB_C_Handler
+ Default_Handler Watchdog_Handler
+
+ Default_Handler Timer0_Handler
+ Default_Handler Timer1_Handler
+
+ Default_Handler GPIO_Handler
+ Default_Handler GPIO_0_Handler
+ Default_Handler GPIO_1_Handler
+ Default_Handler GPIO_2_Handler
+ Default_Handler GPIO_3_Handler
+ Default_Handler GPIO_4_Handler
+ Default_Handler GPIO_5_Handler
+ Default_Handler GPIO_6_Handler
+ Default_Handler GPIO_7_Handler
+
+ Default_Handler MHU0_NR2R_Handler
+ Default_Handler MHU0_R2NR_Handler
+ Default_Handler MHU0_COMB_Handler
+ Default_Handler MHU0_MSG_0_Handler
+ Default_Handler MHU0_MSG_1_Handler
+ Default_Handler MHU1_NR2R_Handler
+ Default_Handler MHU1_R2NR_Handler
+ Default_Handler MHU1_COMB_Handler
+ Default_Handler MHU1_MSG_0_Handler
+ Default_Handler MHU1_MSG_1_Handler
+ ALIGN
+
+ END
diff --git a/platform/ext/target/musca_b1_secure_enclave/Device/Source/armclang/startup_musca_b1_secure_enclave_s.s b/platform/ext/target/musca_b1_secure_enclave/Device/Source/armclang/startup_musca_b1_secure_enclave_s.s
new file mode 100644
index 0000000..95c505d
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Device/Source/armclang/startup_musca_b1_secure_enclave_s.s
@@ -0,0 +1,162 @@
+;/*
+; * Copyright (c) 2009-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.
+; */
+;
+; This file is derivative of CMSIS V5.01 startup_ARMv8MML.s
+; Git SHA: 8a1d9d6ee18b143ae5befefa14d89fb5b3f99c75
+
+;/*
+;//-------- <<< Use Configuration Wizard in Context Menu >>> ------------------
+;*/
+
+
+; <h> Stack Configuration
+; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
+; </h>
+
+ IMPORT |Image$$ARM_LIB_STACK_MSP$$ZI$$Limit|
+
+; Vector Table Mapped to Address 0 at Reset
+
+ PRESERVE8
+ AREA RESET, DATA, READONLY
+ EXPORT __Vectors
+ EXPORT __Vectors_End
+ EXPORT __Vectors_Size
+
+__Vectors ;Core Interrupts
+ DCD |Image$$ARM_LIB_STACK_MSP$$ZI$$Limit| ; Top of Stack
+ DCD Reset_Handler ; Reset Handler
+ DCD NMI_Handler ; -14 NMI Handler
+ DCD HardFault_Handler ; -13 Hard Fault Handler
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD SVC_Handler ; -5 SVCall Handler
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD PendSV_Handler ; -2 PendSV Handler
+ DCD SysTick_Handler ; -1 SysTick Handler
+
+ ;musca_b1_secure_enclave Interrupts
+ DCD ExternalIRQ_Handler ; 0:
+ DCD CC312_Handler ; 1:
+ DCD CC312_APB_C_Handler ; 2:
+ DCD Watchdog_Handler ; 3:
+ DCD 0 ; 4: Reserved
+ DCD TFM_TIMER0_IRQ_Handler ; 5:
+ DCD Timer1_Handler ; 6:
+ DCD 0 ; 7: Reserved
+ DCD 0 ; 8: Reserved
+ DCD GPIO_Handler ; 9:
+ DCD GPIO_0_Handler ; 10:
+ DCD GPIO_1_Handler ; 11:
+ DCD GPIO_2_Handler ; 12:
+ DCD GPIO_3_Handler ; 13:
+ DCD GPIO_4_Handler ; 14:
+ DCD GPIO_5_Handler ; 15:
+ DCD GPIO_6_Handler ; 16:
+ DCD GPIO_7_Handler ; 17:
+ DCD 0 ; 18:
+ DCD 0 ; 19:
+ DCD 0 ; 20:
+ DCD MHU0_NR2R_Handler ; 21:
+ DCD MHU0_R2NR_Handler ; 22:
+ DCD MHU0_COMB_Handler ; 23:
+ DCD MHU0_MSG_0_Handler ; 24:
+ DCD MHU0_MSG_1_Handler ; 25:
+ DCD MHU1_NR2R_Handler ; 26:
+ DCD MHU1_R2NR_Handler ; 27:
+ DCD MHU1_COMB_Handler ; 28:
+ DCD MHU1_MSG_0_Handler ; 29:
+ DCD MHU1_MSG_1_Handler ; 30:
+ DCD 0 ; 31:
+
+__Vectors_End
+
+__Vectors_Size EQU __Vectors_End - __Vectors
+
+; Reset Handler
+ AREA |.text|, CODE, READONLY
+Reset_Handler PROC
+ EXPORT Reset_Handler [WEAK]
+ IMPORT SystemInit
+ IMPORT __main
+ CPSID i ; Disable IRQs
+ LDR R0, =SystemInit
+ BLX R0
+
+ MRS R0, control ; Get control value
+ MOVS R1, #2
+ ORRS R0, R0, R1 ; Select switch to PSP
+ MSR control, R0
+
+ LDR R0, =__main
+ BX R0
+ ENDP
+End_Of_Main
+ B .
+
+
+; Dummy Exception Handlers (infinite loops which can be modified)
+ MACRO
+ Default_Handler $handler_name
+$handler_name PROC
+ EXPORT $handler_name [WEAK]
+ B .
+ ENDP
+ MEND
+
+ Default_Handler NMI_Handler
+ Default_Handler HardFault_Handler
+ Default_Handler SVC_Handler
+ Default_Handler PendSV_Handler
+ Default_Handler SysTick_Handler
+
+ Default_Handler ExternalIRQ_Handler
+ Default_Handler CC312_Handler
+ Default_Handler CC312_APB_C_Handler
+ Default_Handler Watchdog_Handler
+
+ Default_Handler TFM_TIMER0_IRQ_Handler
+ Default_Handler Timer1_Handler
+
+ Default_Handler GPIO_Handler
+ Default_Handler GPIO_0_Handler
+ Default_Handler GPIO_1_Handler
+ Default_Handler GPIO_2_Handler
+ Default_Handler GPIO_3_Handler
+ Default_Handler GPIO_4_Handler
+ Default_Handler GPIO_5_Handler
+ Default_Handler GPIO_6_Handler
+ Default_Handler GPIO_7_Handler
+
+ Default_Handler MHU0_NR2R_Handler
+ Default_Handler MHU0_R2NR_Handler
+ Default_Handler MHU0_COMB_Handler
+ Default_Handler MHU0_MSG_0_Handler
+ Default_Handler MHU0_MSG_1_Handler
+ Default_Handler MHU1_NR2R_Handler
+ Default_Handler MHU1_R2NR_Handler
+ Default_Handler MHU1_COMB_Handler
+ Default_Handler MHU1_MSG_0_Handler
+ Default_Handler MHU1_MSG_1_Handler
+ ALIGN
+
+ END
diff --git a/platform/ext/target/musca_b1_secure_enclave/Device/Source/device_definition.c b/platform/ext/target/musca_b1_secure_enclave/Device/Source/device_definition.c
new file mode 100644
index 0000000..192400c
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Device/Source/device_definition.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2017-2020 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.
+ */
+
+/**
+ * \file device_definition.c
+ * \brief This file defines exports the structures based on the peripheral
+ * definitions from device_cfg.h.
+ * This retarget file is meant to be used as a helper for baremetal
+ * applications and/or as an example of how to configure the generic
+ * driver structures.
+ */
+
+#include "device_cfg.h"
+#include "device_definition.h"
+#include "platform_base_address.h"
+#include "tfm_plat_defs.h"
+
+/** GFC-100 eflash driver structures */
+#ifdef GFC100_EFLASH0_S
+static const struct gfc100_eflash_dev_cfg_t GFC100_EFLASH0_CFG_S = {
+ .base = REMAPPED_MUSCA_B1_EFLASH0_REG_MAP_S_BASE};
+static struct gfc100_eflash_dev_data_t GFC100_EFLASH0_DATA_S = {
+ .is_initialized = false,
+ .flash_size = 0};
+struct gfc100_eflash_dev_t GFC100_EFLASH0_DEV_S = {&(GFC100_EFLASH0_CFG_S),
+ &(GFC100_EFLASH0_DATA_S)};
+#endif
+
+#ifdef GFC100_EFLASH1_S
+static const struct gfc100_eflash_dev_cfg_t GFC100_EFLASH1_CFG_S = {
+ .base = REMAPPED_MUSCA_B1_EFLASH1_REG_MAP_S_BASE};
+static struct gfc100_eflash_dev_data_t GFC100_EFLASH1_DATA_S = {
+ .is_initialized = false,
+ .flash_size = 0};
+struct gfc100_eflash_dev_t GFC100_EFLASH1_DEV_S = {&(GFC100_EFLASH1_CFG_S),
+ &(GFC100_EFLASH1_DATA_S)};
+#endif
+
+/* QSPI IP6514E driver structures */
+#ifdef QSPI_IP6514E_S
+static const struct qspi_ip6514e_dev_cfg_t QSPI_DEV_CFG_S = {
+ .base = REMAPPED_MUSCA_B1_QSPI_REG_S_BASE,
+ .addr_mask = (1U << 23) - 1, /* 8MiB minus 1 byte */
+};
+struct qspi_ip6514e_dev_t QSPI_DEV_S = {
+ &QSPI_DEV_CFG_S
+};
+#endif
+
+/* MT25QL Flash memory library structures */
+#if (defined(MT25QL_S) && defined(QSPI_IP6514E_S))
+struct mt25ql_dev_t MT25QL_DEV_S = {
+ .controller = &QSPI_DEV_S,
+ /* Direct access not possible from Secure Enclave, so dummy address set */
+ .direct_access_start_addr = 0xFFFFFFFF,
+ .baud_rate_div = 4U,
+ .size = 0x00800000U, /* 8 MiB */
+ .config_state = { 0 },
+};
+#endif
+
+/* MHU */
+#ifdef MHU0_SENDER
+struct mhu_v2_x_dev_t MHU0_SENDER_DEV = {
+ .base = MHU0_SENDER_FRAME_BASE,
+ .frame = MHU_V2_X_SENDER_FRAME
+};
+#endif
+
+#ifdef MHU0_RECEIVER
+struct mhu_v2_x_dev_t MHU0_RECEIVER_DEV = {
+ .base = MHU0_RECEIVER_FRAME_BASE,
+ .frame = MHU_V2_X_RECEIVER_FRAME
+};
+#endif
diff --git a/platform/ext/target/musca_b1_secure_enclave/Device/Source/gcc/musca_b1_secure_enclave_bl2.ld b/platform/ext/target/musca_b1_secure_enclave/Device/Source/gcc/musca_b1_secure_enclave_bl2.ld
new file mode 100644
index 0000000..d614fb1
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Device/Source/gcc/musca_b1_secure_enclave_bl2.ld
@@ -0,0 +1,214 @@
+;/*
+; * Copyright (c) 2009-2020 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.
+; *
+; *
+; * This file is derivative of CMSIS V5.00 gcc_arm.ld
+; */
+
+/* Linker script to configure memory regions. */
+/* This file will be run trough the pre-processor. */
+
+#include "region_defs.h"
+
+MEMORY
+{
+ FLASH (rx) : ORIGIN = BL2_CODE_START, LENGTH = BL2_CODE_SIZE
+ EFLASH_DRIVER_REGION (rwx) : ORIGIN = EFLASH_DRIVER_REGION_BASE, LENGTH = EFLASH_DRIVER_REGION_SIZE
+ RAM (rwx) : ORIGIN = BL2_DATA_START, LENGTH = BL2_DATA_SIZE
+}
+
+__heap_size__ = BL2_HEAP_SIZE;
+__msp_stack_size__ = BL2_MSP_STACK_SIZE;
+
+/* Library configurations */
+GROUP(libgcc.a libc.a libm.a libnosys.a)
+
+ENTRY(Reset_Handler)
+
+SECTIONS
+{
+ /* Startup section is loaded to Flash and runs from Flash */
+ .startup :
+ {
+ KEEP(*(.vectors))
+ __Vectors_End = .;
+ __Vectors_Size = __Vectors_End - __Vectors;
+ __end__ = .;
+
+ *startup_musca_b1_secure_enclave_bl2.*
+ } > FLASH
+
+ /* eFlash driver code that gets copied from Flash to SRAM */
+ .ER_EFLASH_DRIVER : ALIGN(4)
+ {
+ *Driver_GFC100_EFlash.o(.text*)
+ *Driver_GFC100_EFlash.o(.rodata*)
+ *gfc100_eflash_drv.o(.text*)
+ *gfc100_eflash_drv.o(.rodata*)
+ *musca_b1_eflash_drv.o(.text*)
+ *musca_b1_eflash_drv.o(.rodata*)
+ . = ALIGN(4); /* This alignment is needed to make the section size 4 bytes aligned */
+ } > EFLASH_DRIVER_REGION AT > FLASH
+ Image$$ER_EFLASH_DRIVER$$Base = ADDR(.ER_EFLASH_DRIVER);
+ Image$$ER_EFLASH_DRIVER$$Limit = ADDR(.ER_EFLASH_DRIVER) + SIZEOF(.ER_EFLASH_DRIVER);
+
+ .text :
+ {
+ *(.text*)
+
+ KEEP(*(.init))
+ KEEP(*(.fini))
+
+ /* .ctors */
+ *crtbegin.o(.ctors)
+ *crtbegin?.o(.ctors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+ *(SORT(.ctors.*))
+ *(.ctors)
+
+ /* .dtors */
+ *crtbegin.o(.dtors)
+ *crtbegin?.o(.dtors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+ *(SORT(.dtors.*))
+ *(.dtors)
+
+ *(.rodata*)
+
+ KEEP(*(.eh_frame*))
+ } > FLASH
+
+ .ARM.extab :
+ {
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ } > FLASH
+
+ __exidx_start = .;
+ .ARM.exidx :
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } > FLASH
+ __exidx_end = .;
+
+ /* To copy multiple ROM to RAM sections,
+ * define etext2/data2_start/data2_end and
+ * define __STARTUP_COPY_MULTIPLE in startup_cmsdk_musca_bl2.S */
+ .copy.table :
+ {
+ . = ALIGN(4);
+ __copy_table_start__ = .;
+ LONG (__etext)
+ LONG (__data_start__)
+ LONG (__data_end__ - __data_start__)
+ LONG (LOADADDR(.ER_EFLASH_DRIVER))
+ LONG (ADDR(.ER_EFLASH_DRIVER))
+ LONG (SIZEOF(.ER_EFLASH_DRIVER))
+ LONG (DEFINED(__etext2) ? __etext2 : 0)
+ LONG (DEFINED(__data2_start__) ? __data2_start__ : 0)
+ LONG (DEFINED(__data2_start__) ? __data2_end__ - __data2_start__ : 0)
+ __copy_table_end__ = .;
+ } > FLASH
+
+ /* To clear multiple BSS sections,
+ * uncomment .zero.table section and,
+ * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_cmsdk_musca_bl2.S */
+ .zero.table :
+ {
+ . = ALIGN(4);
+ __zero_table_start__ = .;
+ LONG (__bss_start__)
+ LONG (__bss_end__ - __bss_start__)
+ LONG (DEFINED(__bss2_start__) ? __bss2_start__ : 0)
+ LONG (DEFINED(__bss2_start__) ? __bss2_end__ - __bss2_start__ : 0)
+ __zero_table_end__ = .;
+ } > FLASH
+
+ __etext = .;
+
+ .tfm_bl2_shared_data BOOT_TFM_SHARED_DATA_BASE : ALIGN(32)
+ {
+ . += BOOT_TFM_SHARED_DATA_SIZE;
+ } > RAM
+ Image$$SHARED_DATA$$RW$$Base = ADDR(.tfm_bl2_shared_data);
+ Image$$SHARED_DATA$$RW$$Limit = ADDR(.tfm_bl2_shared_data) + SIZEOF(.tfm_bl2_shared_data);
+
+ .data : AT (__etext)
+ {
+ __data_start__ = .;
+ *(vtable)
+ *(.data*)
+
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP(*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+
+ . = ALIGN(4);
+ /* init data */
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP(*(SORT(.init_array.*)))
+ KEEP(*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+
+
+ . = ALIGN(4);
+ /* finit data */
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP(*(SORT(.fini_array.*)))
+ KEEP(*(.fini_array))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+
+ KEEP(*(.jcr*))
+ . = ALIGN(4);
+ /* All data end */
+ __data_end__ = .;
+
+ } > RAM
+ Image$$ER_DATA$$Base = ADDR(.data);
+
+ .bss :
+ {
+ . = ALIGN(4);
+ __bss_start__ = .;
+ *(.bss*)
+ *(COMMON)
+ . = ALIGN(4);
+ __bss_end__ = .;
+ } > RAM
+
+ bss_size = __bss_end__ - __bss_start__;
+
+ .msp_stack : ALIGN(32)
+ {
+ . += __msp_stack_size__;
+ } > RAM
+ Image$$ARM_LIB_STACK$$ZI$$Base = ADDR(.msp_stack);
+ Image$$ARM_LIB_STACK$$ZI$$Limit = ADDR(.msp_stack) + SIZEOF(.msp_stack);
+
+ .heap : ALIGN(8)
+ {
+ . = ALIGN(8);
+ __end__ = .;
+ PROVIDE(end = .);
+ __HeapBase = .;
+ . += __heap_size__;
+ __HeapLimit = .;
+ __heap_limit = .; /* Add for _sbrk */
+ } > RAM
+ Image$$ARM_LIB_HEAP$$ZI$$Limit = ADDR(.heap) + SIZEOF(.heap);
+
+ PROVIDE(__stack = Image$$ARM_LIB_STACK$$ZI$$Limit);
+}
diff --git a/platform/ext/target/musca_b1_secure_enclave/Device/Source/gcc/startup_musca_b1_secure_enclave_bl2.S b/platform/ext/target/musca_b1_secure_enclave/Device/Source/gcc/startup_musca_b1_secure_enclave_bl2.S
new file mode 100644
index 0000000..a124c46
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Device/Source/gcc/startup_musca_b1_secure_enclave_bl2.S
@@ -0,0 +1,278 @@
+;/*
+; * Copyright (c) 2009-2020 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.
+; *
+; *
+; * This file is derivative of CMSIS V5.00 startup_ARMCM33.S
+; */
+
+#include "tfm_plat_config.h"
+
+ .syntax unified
+ .arch armv6-m
+
+ .section .vectors
+ .align 2
+ .globl __Vectors
+__Vectors:
+ .long Image$$ARM_LIB_STACK$$ZI$$Limit /* Top of Stack */
+ .long Reset_Handler /* Reset Handler */
+ .long NMI_Handler /* -14 NMI Handler */
+ .long HardFault_Handler /* -13 Hard Fault Handler */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long SVC_Handler /* -5 SVCall Handler */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long PendSV_Handler /* -2 PendSV Handler */
+ .long SysTick_Handler /* -1 SysTick Handler */
+
+ /* Core interrupts */
+ .long ExternalIRQ_Handler /* 0: */
+ .long CC312_Handler /* 1: */
+ .long CC312_APB_C_Handler /* 2: */
+ .long Watchdog_Handler /* 3: */
+ .long 0 /* 4: Reserved */
+ .long Timer0_Handler /* 5: */
+ .long Timer1_Handler /* 6: */
+ .long 0 /* 7: Reserved */
+ .long 0 /* 8: Reserved */
+ .long GPIO_Handler /* 9: */
+ .long GPIO_0_Handler /* 10: */
+ .long GPIO_1_Handler /* 11: */
+ .long GPIO_2_Handler /* 12: */
+ .long GPIO_3_Handler /* 13: */
+ .long GPIO_4_Handler /* 14: */
+ .long GPIO_5_Handler /* 15: */
+ .long GPIO_6_Handler /* 16: */
+ .long GPIO_7_Handler /* 17: */
+ .long 0 /* 18: */
+ .long 0 /* 19: */
+ .long 0 /* 20: */
+ .long MHU0_NR2R_Handler /* 21: */
+ .long MHU0_R2NR_Handler /* 22: */
+ .long MHU0_COMB_Handler /* 23: */
+ .long MHU0_MSG_0_Handler /* 24: */
+ .long MHU0_MSG_1_Handler /* 25: */
+ .long MHU1_NR2R_Handler /* 26: */
+ .long MHU1_R2NR_Handler /* 27: */
+ .long MHU1_COMB_Handler /* 28: */
+ .long MHU1_MSG_0_Handler /* 29: */
+ .long MHU1_MSG_1_Handler /* 30: */
+ .long 0 /* 31: */
+
+ .size __Vectors, . - __Vectors
+
+ .text
+ .thumb
+ .thumb_func
+ .align 2
+ .globl Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+/* Firstly it copies data from read only memory to RAM. There are two schemes
+ * to copy. One can copy more than one sections. Another can only copy
+ * one section. The former scheme needs more instructions and read-only
+ * data to implement than the latter.
+ * Macro __STARTUP_COPY_MULTIPLE is used to choose between two schemes. */
+
+#ifdef __STARTUP_COPY_MULTIPLE
+/* Multiple sections scheme.
+ *
+ * Between symbol address __copy_table_start__ and __copy_table_end__,
+ * there are array of triplets, each of which specify:
+ * offset 0: LMA of start of a section to copy from
+ * offset 4: VMA of start of a section to copy to
+ * offset 8: size of the section to copy. Must be multiply of 4
+ *
+ * All addresses must be aligned to 4 bytes boundary.
+ */
+ ldr r4, =__copy_table_start__
+ ldr r5, =__copy_table_end__
+
+.L_loop0:
+ cmp r4, r5
+ bge .L_loop0_done
+ ldr r1, [r4]
+ ldr r2, [r4, #4]
+ ldr r3, [r4, #8]
+
+.L_loop0_0:
+ subs r3, #4
+ blt .L_loop0_0_done
+ ldr r0, [r1, r3]
+ str r0, [r2, r3]
+ b .L_loop0_0
+
+.L_loop0_0_done:
+ adds r4, #12
+ b .L_loop0
+
+.L_loop0_done:
+#else
+/* Single section scheme.
+ *
+ * The ranges of copy from/to are specified by following symbols
+ * __etext: LMA of start of the section to copy from. Usually end of text
+ * __data_start__: VMA of start of the section to copy to
+ * __data_end__: VMA of end of the section to copy to
+ *
+ * All addresses must be aligned to 4 bytes boundary.
+ */
+ ldr r1, =__etext
+ ldr r2, =__data_start__
+ ldr r3, =__data_end__
+
+ subs r3, r2
+ ble .L_loop1_done
+
+.L_loop1:
+ subs r3, #4
+ ldr r0, [r1,r3]
+ str r0, [r2,r3]
+ bgt .L_loop1
+
+.L_loop1_done:
+#endif /*__STARTUP_COPY_MULTIPLE */
+
+/* This part of work usually is done in C library startup code. Otherwise,
+ * define this macro to enable it in this startup.
+ *
+ * There are two schemes too. One can clear multiple BSS sections. Another
+ * can only clear one section. The former is more size expensive than the
+ * latter.
+ *
+ * Define macro __STARTUP_CLEAR_BSS_MULTIPLE to choose the former.
+ * Otherwise efine macro __STARTUP_CLEAR_BSS to choose the later.
+ */
+#ifdef __STARTUP_CLEAR_BSS_MULTIPLE
+/* Multiple sections scheme.
+ *
+ * Between symbol address __copy_table_start__ and __copy_table_end__,
+ * there are array of tuples specifying:
+ * offset 0: Start of a BSS section
+ * offset 4: Size of this BSS section. Must be multiply of 4
+ */
+ ldr r3, =__zero_table_start__
+ ldr r4, =__zero_table_end__
+
+.L_loop2:
+ cmp r3, r4
+ bge .L_loop2_done
+ ldr r1, [r3]
+ ldr r2, [r3, #4]
+ movs r0, 0
+
+.L_loop2_0:
+ subs r2, #4
+ blt .L_loop2_0_done
+ str r0, [r1, r2]
+ b .L_loop2_0
+.L_loop2_0_done:
+
+ adds r3, #8
+ b .L_loop2
+.L_loop2_done:
+#elif defined (__STARTUP_CLEAR_BSS)
+/* Single BSS section scheme.
+ *
+ * The BSS section is specified by following symbols
+ * __bss_start__: start of the BSS section.
+ * __bss_end__: end of the BSS section.
+ *
+ * Both addresses must be aligned to 4 bytes boundary.
+ */
+ ldr r1, =__bss_start__
+ ldr r2, =__bss_end__
+
+ movs r0, 0
+
+ subs r2, r1
+ ble .L_loop3_done
+
+.L_loop3:
+ subs r2, #4
+ str r0, [r1, r2]
+ bgt .L_loop3
+.L_loop3_done:
+#endif /* __STARTUP_CLEAR_BSS_MULTIPLE || __STARTUP_CLEAR_BSS */
+
+ bl SystemInit
+
+#ifndef __START
+#define __START _start
+#endif
+ bl __START
+
+ .pool
+ .size Reset_Handler, . - Reset_Handler
+
+
+ .align 1
+ .thumb_func
+ .type Default_Handler, %function
+Default_Handler:
+ b Default_Handler
+ .size Default_Handler, . - Default_Handler
+
+/* Macro to define default exception/interrupt handlers.
+ * Default handler are weak symbols with an endless loop.
+ * They can be overwritten by real handlers.
+ */
+ .macro def_irq_handler Handler_Name
+ .weak \Handler_Name
+ .set \Handler_Name, Default_Handler
+ .endm
+
+ def_irq_handler NMI_Handler
+ def_irq_handler HardFault_Handler
+ def_irq_handler SVC_Handler
+ def_irq_handler PendSV_Handler
+ def_irq_handler SysTick_Handler
+
+ def_irq_handler ExternalIRQ_Handler
+ def_irq_handler CC312_Handler
+ def_irq_handler CC312_APB_C_Handler
+ def_irq_handler Watchdog_Handler
+
+ def_irq_handler Timer0_Handler
+ def_irq_handler Timer1_Handler
+
+ def_irq_handler GPIO_Handler
+ def_irq_handler GPIO_0_Handler
+ def_irq_handler GPIO_1_Handler
+ def_irq_handler GPIO_2_Handler
+ def_irq_handler GPIO_3_Handler
+ def_irq_handler GPIO_4_Handler
+ def_irq_handler GPIO_5_Handler
+ def_irq_handler GPIO_6_Handler
+ def_irq_handler GPIO_7_Handler
+
+ def_irq_handler MHU0_NR2R_Handler
+ def_irq_handler MHU0_R2NR_Handler
+ def_irq_handler MHU0_COMB_Handler
+ def_irq_handler MHU0_MSG_0_Handler
+ def_irq_handler MHU0_MSG_1_Handler
+ def_irq_handler MHU1_NR2R_Handler
+ def_irq_handler MHU1_R2NR_Handler
+ def_irq_handler MHU1_COMB_Handler
+ def_irq_handler MHU1_MSG_0_Handler
+ def_irq_handler MHU1_MSG_1_Handler
+
+ .end
diff --git a/platform/ext/target/musca_b1_secure_enclave/Device/Source/gcc/startup_musca_b1_secure_enclave_s.S b/platform/ext/target/musca_b1_secure_enclave/Device/Source/gcc/startup_musca_b1_secure_enclave_s.S
new file mode 100644
index 0000000..bd4c1d9
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Device/Source/gcc/startup_musca_b1_secure_enclave_s.S
@@ -0,0 +1,286 @@
+;/*
+; * Copyright (c) 2009-2020 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.
+; *
+; *
+; * This file is derivative of CMSIS V5.00 startup_ARMCM33.S
+; */
+
+#include "tfm_plat_config.h"
+
+ .syntax unified
+ .arch armv6-m
+
+ .section .vectors
+ .align 2
+ .globl __Vectors
+__Vectors:
+ .long Image$$ARM_LIB_STACK_MSP$$ZI$$Limit /* Top of Stack */
+ .long Reset_Handler /* Reset Handler */
+ .long NMI_Handler /* -14 NMI Handler */
+ .long HardFault_Handler /* -13 Hard Fault Handler */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long SVC_Handler /* -5 SVCall Handler */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long PendSV_Handler /* -2 PendSV Handler */
+ .long SysTick_Handler /* -1 SysTick Handler */
+
+ /* Core interrupts */
+ .long ExternalIRQ_Handler /* 0: */
+ .long CC312_Handler /* 1: */
+ .long CC312_APB_C_Handler /* 2: */
+ .long Watchdog_Handler /* 3: */
+ .long 0 /* 4: Reserved */
+ .long TFM_TIMER0_IRQ_Handler /* 5: */
+ .long Timer1_Handler /* 6: */
+ .long 0 /* 7: Reserved */
+ .long 0 /* 8: Reserved */
+ .long GPIO_Handler /* 9: */
+ .long GPIO_0_Handler /* 10: */
+ .long GPIO_1_Handler /* 11: */
+ .long GPIO_2_Handler /* 12: */
+ .long GPIO_3_Handler /* 13: */
+ .long GPIO_4_Handler /* 14: */
+ .long GPIO_5_Handler /* 15: */
+ .long GPIO_6_Handler /* 16: */
+ .long GPIO_7_Handler /* 17: */
+ .long 0 /* 18: */
+ .long 0 /* 19: */
+ .long 0 /* 20: */
+ .long MHU0_NR2R_Handler /* 21: */
+ .long MHU0_R2NR_Handler /* 22: */
+ .long MHU0_COMB_Handler /* 23: */
+ .long MHU0_MSG_0_Handler /* 24: */
+ .long MHU0_MSG_1_Handler /* 25: */
+ .long MHU1_NR2R_Handler /* 26: */
+ .long MHU1_R2NR_Handler /* 27: */
+ .long MHU1_COMB_Handler /* 28: */
+ .long MHU1_MSG_0_Handler /* 29: */
+ .long MHU1_MSG_1_Handler /* 30: */
+ .long 0 /* 31: */
+
+ .size __Vectors, . - __Vectors
+
+ .text
+ .thumb
+ .thumb_func
+ .align 2
+ .globl Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+ cpsid i
+/* Firstly it copies data from read only memory to RAM. There are two schemes
+ * to copy. One can copy more than one sections. Another can only copy
+ * one section. The former scheme needs more instructions and read-only
+ * data to implement than the latter.
+ * Macro __STARTUP_COPY_MULTIPLE is used to choose between two schemes. */
+
+#ifdef __STARTUP_COPY_MULTIPLE
+/* Multiple sections scheme.
+ *
+ * Between symbol address __copy_table_start__ and __copy_table_end__,
+ * there are array of triplets, each of which specify:
+ * offset 0: LMA of start of a section to copy from
+ * offset 4: VMA of start of a section to copy to
+ * offset 8: size of the section to copy. Must be multiply of 4
+ *
+ * All addresses must be aligned to 4 bytes boundary.
+ */
+ ldr r4, =__copy_table_start__
+ ldr r5, =__copy_table_end__
+
+.L_loop0:
+ cmp r4, r5
+ bge .L_loop0_done
+ ldr r1, [r4]
+ ldr r2, [r4, #4]
+ ldr r3, [r4, #8]
+
+.L_loop0_0:
+ subs r3, #4
+ blt .L_loop0_0_done
+ ldr r0, [r1, r3]
+ str r0, [r2, r3]
+ b .L_loop0_0
+
+.L_loop0_0_done:
+ adds r4, #12
+ b .L_loop0
+
+.L_loop0_done:
+#else
+/* Single section scheme.
+ *
+ * The ranges of copy from/to are specified by following symbols
+ * __etext: LMA of start of the section to copy from. Usually end of text
+ * __data_start__: VMA of start of the section to copy to
+ * __data_end__: VMA of end of the section to copy to
+ *
+ * All addresses must be aligned to 4 bytes boundary.
+ */
+ ldr r1, =__etext
+ ldr r2, =__data_start__
+ ldr r3, =__data_end__
+
+ subs r3, r2
+ ble .L_loop1_done
+
+.L_loop1:
+ subs r3, #4
+ ldr r0, [r1,r3]
+ str r0, [r2,r3]
+ bgt .L_loop1
+
+.L_loop1_done:
+#endif /*__STARTUP_COPY_MULTIPLE */
+
+/* This part of work usually is done in C library startup code. Otherwise,
+ * define this macro to enable it in this startup.
+ *
+ * There are two schemes too. One can clear multiple BSS sections. Another
+ * can only clear one section. The former is more size expensive than the
+ * latter.
+ *
+ * Define macro __STARTUP_CLEAR_BSS_MULTIPLE to choose the former.
+ * Otherwise efine macro __STARTUP_CLEAR_BSS to choose the later.
+ */
+#ifdef __STARTUP_CLEAR_BSS_MULTIPLE
+/* Multiple sections scheme.
+ *
+ * Between symbol address __copy_table_start__ and __copy_table_end__,
+ * there are array of tuples specifying:
+ * offset 0: Start of a BSS section
+ * offset 4: Size of this BSS section. Must be multiply of 4
+ */
+ ldr r3, =__zero_table_start__
+ ldr r4, =__zero_table_end__
+
+.L_loop2:
+ cmp r3, r4
+ bge .L_loop2_done
+ ldr r1, [r3]
+ ldr r2, [r3, #4]
+ movs r0, 0
+
+.L_loop2_0:
+ subs r2, #4
+ blt .L_loop2_0_done
+ str r0, [r1, r2]
+ b .L_loop2_0
+.L_loop2_0_done:
+
+ adds r3, #8
+ b .L_loop2
+.L_loop2_done:
+#elif defined (__STARTUP_CLEAR_BSS)
+/* Single BSS section scheme.
+ *
+ * The BSS section is specified by following symbols
+ * __bss_start__: start of the BSS section.
+ * __bss_end__: end of the BSS section.
+ *
+ * Both addresses must be aligned to 4 bytes boundary.
+ */
+ ldr r1, =__bss_start__
+ ldr r2, =__bss_end__
+
+ movs r0, 0
+
+ subs r2, r1
+ ble .L_loop3_done
+
+.L_loop3:
+ subs r2, #4
+ str r0, [r1, r2]
+ bgt .L_loop3
+.L_loop3_done:
+#endif /* __STARTUP_CLEAR_BSS_MULTIPLE || __STARTUP_CLEAR_BSS */
+
+ bl SystemInit
+
+ mrs r0, control /* Get control value */
+ movs r1, #2
+ orrs r0, r0, r1 /* Select switch to PSP */
+ msr control, r0
+ ldr r0, =Image$$ARM_LIB_STACK$$ZI$$Limit
+ msr psp, r0
+
+#ifndef __START
+#define __START _start
+#endif
+ bl __START
+
+ .pool
+ .size Reset_Handler, . - Reset_Handler
+
+
+ .align 1
+ .thumb_func
+ .type Default_Handler, %function
+Default_Handler:
+ b Default_Handler
+ .size Default_Handler, . - Default_Handler
+
+/* Macro to define default exception/interrupt handlers.
+ * Default handler are weak symbols with an endless loop.
+ * They can be overwritten by real handlers.
+ */
+ .macro def_irq_handler Handler_Name
+ .weak \Handler_Name
+ .set \Handler_Name, Default_Handler
+ .endm
+
+ def_irq_handler NMI_Handler
+ def_irq_handler HardFault_Handler
+ def_irq_handler SVC_Handler
+ def_irq_handler PendSV_Handler
+ def_irq_handler SysTick_Handler
+
+ def_irq_handler ExternalIRQ_Handler
+ def_irq_handler CC312_Handler
+ def_irq_handler CC312_APB_C_Handler
+ def_irq_handler Watchdog_Handler
+
+ def_irq_handler TFM_TIMER0_IRQ_Handler
+ def_irq_handler Timer1_Handler
+
+ def_irq_handler GPIO_Handler
+ def_irq_handler GPIO_0_Handler
+ def_irq_handler GPIO_1_Handler
+ def_irq_handler GPIO_2_Handler
+ def_irq_handler GPIO_3_Handler
+ def_irq_handler GPIO_4_Handler
+ def_irq_handler GPIO_5_Handler
+ def_irq_handler GPIO_6_Handler
+ def_irq_handler GPIO_7_Handler
+
+ def_irq_handler MHU0_NR2R_Handler
+ def_irq_handler MHU0_R2NR_Handler
+ def_irq_handler MHU0_COMB_Handler
+ def_irq_handler MHU0_MSG_0_Handler
+ def_irq_handler MHU0_MSG_1_Handler
+ def_irq_handler MHU1_NR2R_Handler
+ def_irq_handler MHU1_R2NR_Handler
+ def_irq_handler MHU1_COMB_Handler
+ def_irq_handler MHU1_MSG_0_Handler
+ def_irq_handler MHU1_MSG_1_Handler
+
+ .end
diff --git a/platform/ext/target/musca_b1_secure_enclave/Device/Source/system_core_init.c b/platform/ext/target/musca_b1_secure_enclave/Device/Source/system_core_init.c
new file mode 100644
index 0000000..2c45fd7
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Device/Source/system_core_init.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2009-2020 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.
+ */
+
+/*
+ * This file is derivative of CMSIS V5.01:
+ * \Device\ARM\ARMCM0plus\Source\system_ARMCM0plus.c
+ */
+
+#include "system_core_init.h"
+#include "cmsis.h"
+
+/*----------------------------------------------------------------------------
+ Define clocks
+ *----------------------------------------------------------------------------*/
+#define SYSTEM_CLOCK (40960000UL)
+#define PERIPHERAL_CLOCK (40960000UL)
+
+/*----------------------------------------------------------------------------
+ Externals
+ *----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ System Core Clock Variable
+ *----------------------------------------------------------------------------*/
+uint32_t SystemCoreClock = SYSTEM_CLOCK;
+uint32_t PeripheralClock = PERIPHERAL_CLOCK;
+
+/*----------------------------------------------------------------------------
+ System Core Clock update function
+ *----------------------------------------------------------------------------*/
+void SystemCoreClockUpdate (void)
+{
+ SystemCoreClock = SYSTEM_CLOCK;
+ PeripheralClock = PERIPHERAL_CLOCK;
+}
+
+/*----------------------------------------------------------------------------
+ System initialization function
+ *----------------------------------------------------------------------------*/
+void SystemInit (void)
+{
+#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U)
+ extern uint32_t __Vectors;
+ SCB->VTOR = (uint32_t) &__Vectors;
+#endif
+ SystemCoreClockUpdate();
+}
diff --git a/platform/ext/target/musca_b1_secure_enclave/Libraries/mt25ql_flash_lib.c b/platform/ext/target/musca_b1_secure_enclave/Libraries/mt25ql_flash_lib.c
new file mode 100644
index 0000000..578cc5b
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Libraries/mt25ql_flash_lib.c
@@ -0,0 +1,901 @@
+/*
+ * 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 <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){ 0 };
+ 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_b1_secure_enclave/Libraries/mt25ql_flash_lib.h b/platform/ext/target/musca_b1_secure_enclave/Libraries/mt25ql_flash_lib.h
new file mode 100644
index 0000000..c2dac2c
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/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_b1_secure_enclave/Native_Driver/gfc100_eflash_drv.c b/platform/ext/target/musca_b1_secure_enclave/Native_Driver/gfc100_eflash_drv.c
new file mode 100644
index 0000000..b8bf522
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Native_Driver/gfc100_eflash_drv.c
@@ -0,0 +1,558 @@
+/*
+ * 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.
+ */
+
+/**
+ * \file gfc100_eflash_drv.c
+ *
+ * \brief Generic driver for GFC100 flash controller
+ */
+
+#include "gfc100_eflash_drv.h"
+#include "gfc100_process_spec_api.h"
+
+#define BITMASK(width) ((1U<<(width))-1)
+
+/** The MSB Addr[21] selects between memory ranges*/
+#define GFC100_EXTENDED_AREA_OFFSET (1U << 21)
+
+/* Process specific register map offset */
+#define GFC100_PROCESS_SPEC_REG_MAP_OFF 0x1000U
+
+#define WORD_ALIGN_16B_MASK 0xFU /* Masks the first 4 bits */
+#define WORD_ALIGN_4B_MASK 0x3U /* Masks the first 2 bits */
+#define IS_ADDR_4B_ALIGNED(addr) (((uint32_t)addr & WORD_ALIGN_4B_MASK) == 0U)
+
+/** Currently only 128 bit word width is supported by the driver */
+#define GFC100_SUPPORTED_WORD_BIT_WIDTH 128U
+
+/** Read is done with maximum word width */
+#define BITS_IN_BYTE 8U
+#define GFC100_READ_BYTE_SIZE \
+ (GFC100_SUPPORTED_WORD_BIT_WIDTH / BITS_IN_BYTE)
+
+/** Write is done in 4 byte chunks */
+#define GFC100_WRITE_BYTE_SIZE 4U
+
+/** GFC100 generic controller register map */
+struct gfc100_reg_map_t {
+ volatile uint32_t irq_enable_set; /* 0x000 RW Interrupt enable */
+ volatile uint32_t irq_enable_clr; /* 0x004 RW Interrupt disable */
+ volatile uint32_t irq_status_set; /* 0x008 RW Interrupt status set */
+ volatile uint32_t irq_status_clr; /* 0x00C RW Interrupt status clear */
+ volatile uint32_t irq_masked_status; /* 0x010 RO Interrupt masked status */
+ volatile uint32_t ctrl; /* 0x014 RW Control */
+ volatile uint32_t status; /* 0x018 RO Status */
+ volatile uint32_t addr; /* 0x01C RW Address */
+ volatile uint32_t data0; /* 0x020 RW Data 0 */
+ volatile uint32_t data1; /* 0x024 RO Data 1 */
+ volatile uint32_t data2; /* 0x028 RO Data 2 */
+ volatile uint32_t data3; /* 0x02C RO Data 3 */
+ volatile uint32_t reserved[1000]; /* 0x030 Reserved */
+ volatile uint32_t pidr4; /* 0xFD0 RO Peripheral id register 4 */
+ volatile uint32_t reserved2[3]; /* 0xFD4 Reserved */
+ volatile uint32_t pidr0; /* 0xFE0 RO Peripheral id register 0 */
+ volatile uint32_t pidr1; /* 0xFE4 RO Peripheral id register 1 */
+ volatile uint32_t pidr2; /* 0xFE8 RO Peripheral id register 2 */
+ volatile uint32_t pidr3; /* 0xFEC RO Peripheral id register 3 */
+ volatile uint32_t cidr0; /* 0xFF0 RO Component id register 0 */
+ volatile uint32_t cidr1; /* 0xFF4 RO Component id register 1 */
+ volatile uint32_t cidr2; /* 0xFF8 RO Component id register 2 */
+ volatile uint32_t cidr3; /* 0xFFC RO Component id register 3 */
+};
+
+/* Bit definition for the interrupt registers */
+#define GFC100_CMD_ACCEPT_IRQ_POS 0U
+#define GFC100_CMD_ACCEPT_IRQ_MASK (1U<<GFC100_CMD_ACCEPT_IRQ_POS)
+#define GFC100_CMD_SUCCESS_IRQ_POS 1U
+#define GFC100_CMD_SUCCESS_IRQ_MASK (1U<<GFC100_CMD_SUCCESS_IRQ_POS)
+#define GFC100_CMD_FAIL_IRQ_POS 2U
+#define GFC100_CMD_FAIL_IRQ_MASK (1U<<GFC100_CMD_FAIL_IRQ_POS)
+#define GFC100_CMD_REJECT_IRQ_POS 3U
+#define GFC100_CMD_REJECT_IRQ_MASK (1U<<GFC100_CMD_REJECT_IRQ_POS)
+#define GFC100_CMD_OVERFLOW_IRQ_POS 4U
+#define GFC100_CMD_OVERFLOW_IRQ_MASK (1U<<GFC100_CMD_OVERFLOW_IRQ_POS)
+
+#define GFC100_IRQ_MAX_NUMBER 5U
+#define GFC100_ALL_IRQ_MASK BITMASK(GFC100_IRQ_MAX_NUMBER)
+
+/* Bit definitons for the control register */
+#define GFC100_CTRL_CMD_POS 0U
+#define GFC100_CTRL_CMD_WIDTH 3U
+#define GFC100_CTRL_CMD_MASK \
+ (BITMASK(GFC100_CTRL_CMD_WIDTH)<<GFC100_CTRL_CMD_POS)
+ #define CMD_READ 0x1U
+ #define CMD_WRITE 0x2U
+ #define CMD_ROW_WRITE 0x3U
+ #define CMD_ERASE 0x4U
+ #define CMD_MASS_ERASE 0x7U
+#define GFC100_CTRL_CMD_ABORT_POS 4U
+#define GFC100_CTRL_CMD_ABORT_WIDTH 1U
+#define GFC100_CTRL_CMD_ABORT_MASK \
+ (BITMASK(GFC100_CTRL_CMD_ABORT_WIDTH)<<GFC100_CTRL_CMD_ABORT_POS)
+
+/* Bit definition for the status registers */
+#define GFC100_CMD_STAT_PENDING_POS 0U
+#define GFC100_CMD_STAT_PENDING_MASK (1U<<GFC100_CMD_STAT_PENDING_POS)
+#define GFC100_CMD_STAT_ACCEPT_POS 1U
+#define GFC100_CMD_STAT_ACCEPT_MASK (1U<<GFC100_CMD_STAT_ACCEPT_POS)
+#define GFC100_CMD_STAT_SUCCESS_POS 2U
+#define GFC100_CMD_STAT_SUCCESS_MASK (1U<<GFC100_CMD_STAT_SUCCESS_POS)
+#define GFC100_CMD_STAT_FAIL_POS 3U
+#define GFC100_CMD_STAT_FAIL_MASK (1U<<GFC100_CMD_STAT_FAIL_POS)
+#define GFC100_CMD_STAT_FINISH_POS 4U
+#define GFC100_CMD_STAT_FINISH_MASK (1U<<GFC100_CMD_STAT_FINISH_POS)
+#define GFC100_CMD_STAT_ARB_LOCKED_POS 5U
+#define GFC100_CMD_STAT_ARB_LOCKED_MASK (1U<<GFC100_CMD_STAT_ARB_LOCKED_POS)
+
+#define GFC100_CMD_SUCCEEDED_OR_FAILED \
+ (GFC100_CMD_STAT_SUCCESS_MASK | GFC100_CMD_STAT_FAIL_MASK)
+#define GFC100_CMD_HAS_FINISHED \
+ (GFC100_CMD_SUCCEEDED_OR_FAILED | GFC100_CMD_STAT_FINISH_MASK)
+
+/**
+ * \brief Enables or disables IRQs
+ *
+ * \param[in] dev GFC100 device struct \ref gfc100_eflash_dev_t
+ * \param[in] irq_mask IRQs to enable/disable
+ * \param[in] enable True if the given IRQs need to be enabled, false
+ * if they need to be disabled
+ */
+static void gfc100_eflash_irq_enable(struct gfc100_eflash_dev_t *dev,
+ uint32_t irq_mask, bool enable)
+{
+ struct gfc100_reg_map_t *reg_map =
+ (struct gfc100_reg_map_t *)dev->cfg->base;
+
+ if (enable) {
+ reg_map->irq_enable_set = (irq_mask & GFC100_ALL_IRQ_MASK);
+ } else {
+ reg_map->irq_enable_clr = (irq_mask & GFC100_ALL_IRQ_MASK);
+ }
+}
+
+void gfc100_eflash_init(struct gfc100_eflash_dev_t *dev, uint32_t sys_clk)
+{
+ /* The driver polls the status register of the controller rather
+ * than using interrupts, so interrupts need to be disabled.
+ */
+ gfc100_eflash_irq_enable(dev, GFC100_ALL_IRQ_MASK, false);
+
+ /* Call process specific API to the set timing parameters */
+ gfc100_proc_spec_set_eflash_timing(
+ dev->cfg->base + GFC100_PROCESS_SPEC_REG_MAP_OFF, sys_clk);
+
+ /* Store flash size */
+ dev->data->flash_size = gfc100_get_eflash_size(dev);
+
+ dev->data->is_initialized = true;
+}
+
+/**
+ * \brief Clears IRQ status
+ *
+ * \param[in] reg_map GFC100 register map struct \ref gfc100_reg_map_t
+ */
+static inline void clear_irq_status(struct gfc100_reg_map_t *reg_map)
+{
+ reg_map->irq_status_clr = GFC100_ALL_IRQ_MASK;
+}
+
+/**
+ * \brief Waits for command ready flags after issuing a command
+ *
+ * \param[in] reg_map GFC100 register map struct \ref gfc100_reg_map_t
+ *
+ * \return Returns status register of the device
+ */
+static uint32_t check_cmd_result(struct gfc100_reg_map_t *reg_map)
+{
+ uint32_t status = 0;
+
+ while (!(status = (reg_map->status & GFC100_CMD_HAS_FINISHED))) {};
+
+ if (status & GFC100_CMD_STAT_FINISH_MASK) {
+ /* FINISH bit means the FAIL and SUCCESS status cannot be updated
+ * as the interrupt status register still holds the status
+ * of the previous command.
+ * Clearing the interrupts is needed to the get the result
+ * of the current command.
+ */
+ clear_irq_status(reg_map);
+
+ /* Wait for the SUCCESS or FAIL bit to get set */
+ while (!(status =
+ (reg_map->status & GFC100_CMD_SUCCEEDED_OR_FAILED))) {};
+ }
+
+ return status;
+}
+
+/**
+ * \brief Triggers read command and blocks until command has finished
+ *
+ * \param[in] reg_map GFC100 register map struct \ref gfc100_reg_map_t
+ *
+ * \return Returns status regster of the device
+ */
+static uint32_t trigger_read_cmd(struct gfc100_reg_map_t *reg_map,
+ uint32_t addr)
+{
+ /* Wait until the previous command is pending */
+ while ((reg_map->status & GFC100_CMD_STAT_PENDING_MASK)) {};
+
+ /* Set the address to read from */
+ reg_map->addr = addr;
+
+ /* Initiate read command */
+ reg_map->ctrl = (CMD_READ << GFC100_CTRL_CMD_POS);
+
+ return (check_cmd_result(reg_map));
+}
+
+/**
+ * \brief Copies data from GFC100 data registers
+ *
+ * \param[in] reg_map GFC100 register map struct \ref gfc100_reg_map_t
+ * \param[out] to_ptr Pointer to copy the data to
+ * \param[in] size Number of bytes that needs to be copied
+ * \param[in] offset Offset to the first byte that needs to be copied
+ *
+ * \return Returns the number of bytes that were copied
+ *
+ * \note The function checks the offset and the maximum size the data
+ * registers can hold and adjusts the size with them, so copies only
+ * the number of available bytes
+ */
+static uint32_t copy_from_data_regs(struct gfc100_reg_map_t *reg_map,
+ void *to_ptr, uint32_t size,
+ uint32_t offset)
+{
+ offset &= (GFC100_READ_BYTE_SIZE - 1);
+ uint8_t *dst = (uint8_t *)to_ptr;
+ volatile uint8_t *src = ((uint8_t *)®_map->data0) + offset;
+ uint32_t i;
+
+ /* Read is always done in 16 bytes chunks from a 16 byte aligned address.
+ * If address is not aligned then HW will align it, so the SW needs to make
+ * sure the right bytes are read from the right location.
+ */
+
+ /* Maximum 16 bytes can be copied from the 16 byte aligned address.
+ * If the read size with the offset overlaps the 16 byte boundary,
+ * only the bytes up to the boundary can be copied. */
+ if (size + offset > GFC100_READ_BYTE_SIZE) {
+ size = GFC100_READ_BYTE_SIZE - offset;
+ }
+
+ /* If the address or the size is not aligned then memcpy can
+ * generate unaligned accesses which is not desired
+ * on the APB, so instead of using memcpy this for cycle is used.
+ */
+ for (i=0; i<size; i++) {
+ *dst = *src;
+ src++;
+ dst++;
+ }
+
+ return size;
+}
+
+enum gfc100_error_t gfc100_eflash_read(struct gfc100_eflash_dev_t *dev,
+ uint32_t addr, void *data, uint32_t *len)
+{
+ struct gfc100_reg_map_t *reg_map =
+ (struct gfc100_reg_map_t *)dev->cfg->base;
+ uint32_t remaining_len = *len;
+ uint32_t status = 0U;
+ uint32_t curr_read_len = 0U;
+ uint32_t addr_align_off = 0U;
+
+ if (dev->data->is_initialized == false) {
+ return GFC100_ERROR_NOT_INITED;
+ }
+
+ if ((addr + *len) > dev->data->flash_size) {
+ return GFC100_ERROR_OUT_OF_RANGE;
+ }
+
+ if (reg_map->status & GFC100_CMD_STAT_PENDING_MASK) {
+ /* Previous command is still pending */
+ return GFC100_ERROR_CMD_PENDING;
+ }
+
+ if (gfc100_proc_spec_get_eflash_word_width(dev->cfg->base + GFC100_PROCESS_SPEC_REG_MAP_OFF)
+ != GFC100_SUPPORTED_WORD_BIT_WIDTH) {
+ /* Curently only 128 bit word width is supported by the driver */
+ return GFC100_ERROR_INVALID_WORD_WIDTH;
+ }
+
+ while (remaining_len && !(status & GFC100_CMD_STAT_FAIL_MASK)) {
+ status = trigger_read_cmd(reg_map, addr);
+
+ addr_align_off = addr & WORD_ALIGN_16B_MASK;
+
+ curr_read_len = copy_from_data_regs(reg_map, data, remaining_len,
+ addr_align_off);
+ remaining_len -= curr_read_len;
+ addr += curr_read_len;
+ data = (void *)((uintptr_t)data + curr_read_len);
+
+ /* Clear IRQ status before issuing the next command */
+ clear_irq_status(reg_map);
+ }
+
+ if (status & GFC100_CMD_STAT_FAIL_MASK) {
+ /* If there was error, then this last read was not successful */
+ remaining_len += curr_read_len;
+ }
+
+ /* Adjust length to sign how many bytes were actually read */
+ *len -= remaining_len;
+
+ return ((status & GFC100_CMD_STAT_FAIL_MASK) ?
+ GFC100_ERROR_CMD_FAIL : GFC100_ERROR_NONE);
+}
+
+/**
+ * \brief Triggers write command and blocks until command has finished
+ *
+ * \param[in] reg_map GFC100 register map struct \ref gfc100_reg_map_t
+ * \param[in] addr Flash address to write to
+ * \param[in] data Data to write to the flash
+ *
+ * \return Returns status regster of the device
+ */
+static uint32_t trigger_write_cmd(struct gfc100_reg_map_t *reg_map,
+ uint32_t addr, uint32_t data)
+{
+ uint32_t status;
+
+ /* Set address and data to write */
+ reg_map->addr = addr;
+ reg_map->data0 = data;
+
+ /* Initiate write command */
+ reg_map->ctrl = (CMD_WRITE << GFC100_CTRL_CMD_POS);
+
+ status = check_cmd_result(reg_map);
+
+ return status;
+}
+
+enum gfc100_error_t gfc100_eflash_write(struct gfc100_eflash_dev_t *dev,
+ uint32_t addr, const void *data,
+ uint32_t *len)
+{
+ struct gfc100_reg_map_t *reg_map =
+ (struct gfc100_reg_map_t *)dev->cfg->base;
+ uint32_t status = 0U;
+ uint32_t remaining_len = *len;
+
+ if (dev->data->is_initialized == false) {
+ return GFC100_ERROR_NOT_INITED;
+ }
+
+ if ((addr + *len) > dev->data->flash_size) {
+ return GFC100_ERROR_OUT_OF_RANGE;
+ }
+
+ if (reg_map->status & GFC100_CMD_STAT_PENDING_MASK) {
+ /* Previous command is still pending */
+ return GFC100_ERROR_CMD_PENDING;
+ }
+
+ if (!IS_ADDR_4B_ALIGNED(addr) || !IS_ADDR_4B_ALIGNED(*len)) {
+ /* Both address and length needs to be 4 byte aligned */
+ return GFC100_ERROR_UNALIGNED_PARAM;
+ }
+
+ while (remaining_len && !(status & GFC100_CMD_STAT_FAIL_MASK)) {
+ status = trigger_write_cmd(reg_map, addr, *(uint32_t *)data);
+ addr += GFC100_WRITE_BYTE_SIZE;
+ data = (void *)((uint32_t)data + GFC100_WRITE_BYTE_SIZE);
+ remaining_len -= GFC100_WRITE_BYTE_SIZE;
+ /* Clear IRQ status before issuing the next command */
+ clear_irq_status(reg_map);
+ }
+
+ if (status & GFC100_CMD_STAT_FAIL_MASK) {
+ /* If there was error, then this last write was not successful */
+ remaining_len += GFC100_WRITE_BYTE_SIZE;
+ }
+
+ /* Adjust length to sign how many bytes were actually read */
+ *len -= remaining_len;
+
+ return ((status & GFC100_CMD_STAT_FAIL_MASK) ?
+ GFC100_ERROR_CMD_FAIL : GFC100_ERROR_NONE);
+}
+
+
+enum gfc100_error_t gfc100_eflash_row_write(struct gfc100_eflash_dev_t *dev,
+ uint32_t addr, const void *data,
+ uint32_t *len)
+{
+ struct gfc100_reg_map_t *reg_map =
+ (struct gfc100_reg_map_t *)dev->cfg->base;
+ uint32_t status = 0U;
+ uint32_t remaining_len = *len;
+ uint32_t flag = GFC100_CMD_STAT_ACCEPT_MASK;
+
+ if (dev->data->is_initialized == false) {
+ return GFC100_ERROR_NOT_INITED;
+ }
+
+ if ((addr + *len) > dev->data->flash_size) {
+ return GFC100_ERROR_OUT_OF_RANGE;
+ }
+
+ if (reg_map->status & GFC100_CMD_STAT_PENDING_MASK) {
+ /* Previous command is still pending */
+ return GFC100_ERROR_CMD_PENDING;
+ }
+
+ if (!IS_ADDR_4B_ALIGNED(addr) || !IS_ADDR_4B_ALIGNED(*len)) {
+ /* Both address and length needs to be 4 byte aligned */
+ return GFC100_ERROR_UNALIGNED_PARAM;
+ }
+
+ while (remaining_len) {
+ /* Set address and data to write */
+ reg_map->addr = addr;
+ reg_map->data0 = *(uint32_t *)data;
+
+ /* Initiate write command */
+ reg_map->ctrl = (CMD_ROW_WRITE << GFC100_CTRL_CMD_POS);
+
+ /* When the first command is sent we only need accept flag to be set.
+ * After the first command we need two flags, accept flag from the
+ * current, and success flag from the previous command.
+ * Note: If interrupts are enabled or execution speed is limited for
+ * other reason, there is a chance that the requested row write command
+ * is not only accepted but executed already before the ACCEPT flag
+ * is checked. If this happens, the code execution will stall.
+ */
+ while (!(((status = reg_map->status) & flag) == flag)) {
+ if (status & GFC100_CMD_STAT_FAIL_MASK) {
+ /* Adjust length to sign how many bytes were actually read */
+ *len -= remaining_len;
+ clear_irq_status(reg_map);
+ return GFC100_ERROR_CMD_FAIL;
+ }
+ }
+ flag = (GFC100_CMD_STAT_ACCEPT_MASK | GFC100_CMD_STAT_SUCCESS_MASK);
+
+ /* Adjust data pointers and the length */
+ addr += GFC100_WRITE_BYTE_SIZE;
+ data = (void *)((uintptr_t)data + GFC100_WRITE_BYTE_SIZE);
+ remaining_len -= GFC100_WRITE_BYTE_SIZE;
+
+ /* Clear IRQ status before issuing the next command */
+ clear_irq_status(reg_map);
+ }
+
+ /* Wait for the success flag of the last command to arrive */
+ while (!(reg_map->status & GFC100_CMD_STAT_SUCCESS_MASK)) {};
+
+ /* Adjust length to sign how many bytes were actually read */
+ *len -= remaining_len;
+
+ clear_irq_status(reg_map);
+
+ return GFC100_ERROR_NONE;
+}
+
+enum gfc100_error_t gfc100_eflash_erase(struct gfc100_eflash_dev_t *dev,
+ uint32_t addr,
+ enum gfc100_erase_type_t erase)
+{
+ struct gfc100_reg_map_t *reg_map =
+ (struct gfc100_reg_map_t *)dev->cfg->base;
+ uint32_t status = 0U;
+
+ if (dev->data->is_initialized == false) {
+ return GFC100_ERROR_NOT_INITED;
+ }
+
+ if (reg_map->status & GFC100_CMD_STAT_PENDING_MASK) {
+ /* Previous command is still pending */
+ return GFC100_ERROR_CMD_PENDING;
+ }
+
+ switch (erase) {
+ case GFC100_ERASE_PAGE:
+ if (addr > dev->data->flash_size) {
+ return GFC100_ERROR_OUT_OF_RANGE;
+ }
+ reg_map->addr = addr;
+ reg_map->ctrl = (CMD_ERASE << GFC100_CTRL_CMD_POS);
+ status = check_cmd_result(reg_map);
+ /* Clear IRQ status before issuing the next command */
+ clear_irq_status(reg_map);
+ break;
+ case GFC100_MASS_ERASE_MAIN_AREA:
+ reg_map->addr = 0U;
+ reg_map->ctrl = (CMD_MASS_ERASE << GFC100_CTRL_CMD_POS);
+ status = check_cmd_result(reg_map);
+ /* Clear IRQ status before issuing the next command */
+ clear_irq_status(reg_map);
+ break;
+ case GFC100_MASS_ERASE_ALL:
+ reg_map->addr = GFC100_EXTENDED_AREA_OFFSET;
+ reg_map->ctrl = (CMD_MASS_ERASE << GFC100_CTRL_CMD_POS);
+ status = check_cmd_result(reg_map);
+ /* Clear IRQ status before issuing the next command */
+ clear_irq_status(reg_map);
+ break;
+ default:
+ return GFC100_ERROR_INVALID_PARAM;
+ }
+
+ return ((status == GFC100_CMD_STAT_FAIL_MASK) ?
+ GFC100_ERROR_CMD_FAIL : GFC100_ERROR_NONE);
+}
+
+bool gfc100_is_controller_locked(struct gfc100_eflash_dev_t *dev)
+{
+ struct gfc100_reg_map_t *reg_map =
+ (struct gfc100_reg_map_t *)dev->cfg->base;
+
+ return (bool)(reg_map->status & GFC100_CMD_STAT_ARB_LOCKED_MASK);
+}
+
+uint32_t gfc100_get_eflash_size(struct gfc100_eflash_dev_t *dev)
+{
+ return (gfc100_proc_spec_get_eflash_size(
+ dev->cfg->base + GFC100_PROCESS_SPEC_REG_MAP_OFF));
+}
+
+uint32_t gfc100_get_eflash_page_size(struct gfc100_eflash_dev_t *dev)
+{
+ return (gfc100_proc_spec_get_eflash_page_size(
+ dev->cfg->base + GFC100_PROCESS_SPEC_REG_MAP_OFF));
+}
+
+uint32_t gfc100_get_num_of_info_pages(struct gfc100_eflash_dev_t *dev)
+{
+ return (gfc100_proc_spec_get_num_of_info_pages(
+ dev->cfg->base + GFC100_PROCESS_SPEC_REG_MAP_OFF));
+}
+
+uint32_t gfc100_get_proc_spec_error(struct gfc100_eflash_dev_t *dev)
+{
+ return (gfc100_proc_spec_get_error_cause(
+ dev->cfg->base + GFC100_PROCESS_SPEC_REG_MAP_OFF));
+}
diff --git a/platform/ext/target/musca_b1_secure_enclave/Native_Driver/gfc100_eflash_drv.h b/platform/ext/target/musca_b1_secure_enclave/Native_Driver/gfc100_eflash_drv.h
new file mode 100644
index 0000000..b4d6cfb
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Native_Driver/gfc100_eflash_drv.h
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ */
+
+/**
+ * \file gfc100_eflash_drv.h
+ *
+ * \brief Generic driver for GFC100 flash controller
+ */
+
+#ifndef __GFC100_FLASH_DRV_H__
+#define __GFC100_FLASH_DRV_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+
+enum gfc100_error_t {
+ GFC100_ERROR_NONE = 0U, /*!< No error */
+ GFC100_ERROR_NOT_INITED, /*!< Device not inited error */
+ GFC100_ERROR_CMD_PENDING, /*!< Previous cmd is still pending error */
+ GFC100_ERROR_INVALID_WORD_WIDTH, /*!< Invalid word width error */
+ GFC100_ERROR_INVALID_PARAM, /*!< Invalid parameter error */
+ GFC100_ERROR_OUT_OF_RANGE, /*!< Flash address out of range error */
+ GFC100_ERROR_CMD_FAIL, /*!< Command failed error */
+ GFC100_ERROR_UNALIGNED_PARAM /*!< Unaligned parameter error */
+};
+
+/** GFC100 Flash controller device configuration structure */
+struct gfc100_eflash_dev_cfg_t {
+ const uint32_t base; /*!< GFC100 base address */
+};
+
+/** GFC100 Flash controller device data structure */
+struct gfc100_eflash_dev_data_t {
+ bool is_initialized; /*!< Indicates if the device is initialized */
+ uint32_t flash_size; /*!< Size of the flash area */
+};
+
+/** GFC100 Flash controller device structure */
+struct gfc100_eflash_dev_t {
+ const struct gfc100_eflash_dev_cfg_t* const cfg;
+ /*!< GFC100 configuration */
+ struct gfc100_eflash_dev_data_t* const data; /*!< GFC100 data */
+};
+
+enum gfc100_erase_type_t {
+ GFC100_ERASE_PAGE = 0U, /*!< Erase 1 page */
+ GFC100_MASS_ERASE_MAIN_AREA, /*!< Erase main area */
+ GFC100_MASS_ERASE_ALL /*!< Erase main + extended area */
+};
+
+/**
+ * \brief Initializes GFC100 flash controller
+ *
+ * \param[in] dev GFC100 device struct \ref gfc100_eflash_dev_t
+ * \param[in] sys_clk System clock in Hz
+ *
+ * \note This API needs to be called prior to any other APIs.
+ * \note For better performance, this function doesn't check if dev is NULL
+ */
+void gfc100_eflash_init(struct gfc100_eflash_dev_t *dev, uint32_t sys_clk);
+
+/**
+ * \brief Reads data from the flash in a blocking call
+ *
+ * \param[in] dev GFC100 device struct \ref gfc100_eflash_dev_t
+ * \param[in] addr Address to read data from the flash
+ * \param[out] data Pointer to store data read from the flash
+ * \param[in,out] len Number of bytes to read, number of bytes read
+ *
+ * \return Returns error code as specified in \ref gfc100_error_t
+ *
+ * \note This API reads the flash memory by sending read commands with the
+ * controller, but reading through the AHB directly mapped address gives
+ * better performance (if flash is mapped for direct read).
+ * \note Addr is expected to be within the [0x0 - Flash size] range
+ * \note For better performance, this function doesn't check if dev is NULL
+ * \note Addr, data and len can have any aligment
+ */
+enum gfc100_error_t gfc100_eflash_read(struct gfc100_eflash_dev_t *dev,
+ uint32_t addr, void *data, uint32_t *len);
+
+/**
+ * \brief Writes data to the flash in a blocking call
+ *
+ * \param[in] dev GFC100 device struct \ref gfc100_eflash_dev_t
+ * \param[in] addr Address to write data to the flash
+ * \param[in] data Pointer to the data to be written
+ * \param[in] len Number of bytes to write
+ *
+ * \return Returns error code as specified in \ref gfc100_error_t
+ *
+ * \note Flash area needs to be pre-erased before writing to it
+ * \note Addr is expected to be within the [0x0 - Flash size] range
+ * \note For better performance, this function doesn't check if dev is NULL
+ * \note Addr and len must be 4 bytes aligned
+ */
+enum gfc100_error_t gfc100_eflash_write(struct gfc100_eflash_dev_t *dev,
+ uint32_t addr, const void *data,
+ uint32_t *len);
+
+/**
+ * \brief Writes data to the flash in a blocking call
+ *
+ * \param[in] dev GFC100 device struct \ref gfc100_eflash_dev_t
+ * \param[in] addr Address to write data to the flash
+ * \param[in] data Pointer to the data to be written
+ * \param[in] len Number of bytes to write
+ *
+ * \return Returns error code as specified in \ref gfc100_error_t
+ *
+ * \note This API uses the Row Write command by sending the commands
+ * continuously so the controller won't close the transfer and start a new
+ * for the next 4 bytes.This gives much better performance
+ * than simple Write command, so this API is preferred to use if many
+ * bytes needs to be written to the flash.
+ * \note Addr is expected to be within the [0x0 - Flash size] range
+ * \note For better performance, this function doesn't check if dev is NULL
+ * \note Addr and len must be 4 bytes aligned
+ */
+enum gfc100_error_t gfc100_eflash_row_write(struct gfc100_eflash_dev_t *dev,
+ uint32_t addr, const void *data,
+ uint32_t *len);
+
+/**
+ * \brief Erases the flash
+ *
+ * \param[in] dev GFC100 device struct \ref gfc100_eflash_dev_t
+ * \param[in] addr Address of the page to erase
+ * \param[in] erase Erase type \ref gfc100_erase_type_t
+ *
+ * \return Returns error code as specified in \ref gfc100_error_t
+ *
+ * \note For better performance, this function doesn't check if dev is NULL
+ * \note Addr is expected to be within the [0x0 - Flash size] range
+ * \note Addr is only used for page erase, and is automatically aligned
+ * to page size.
+ */
+enum gfc100_error_t gfc100_eflash_erase(struct gfc100_eflash_dev_t *dev,
+ uint32_t addr,
+ enum gfc100_erase_type_t erase);
+
+/**
+ * \brief Checks if controller is locked
+ *
+ * \param[in] dev GFC100 device struct \ref gfc100_eflash_dev_t
+ *
+ * \return Returns true is controller is locked, false otherwise
+ *
+ * \note For better performance, this function doesn't check if dev is NULL
+ * \note This can be used by the software to detect why the APB request
+ * is being held up.
+ */
+bool gfc100_is_controller_locked(struct gfc100_eflash_dev_t *dev);
+
+/**
+ * \brief Gets flash memory size in bytes
+ *
+ * \param[in] dev GFC100 device struct \ref gfc100_eflash_dev_t
+ *
+ * \return Returns the size of the flash memory in bytes
+ *
+ * \note For better performance, this function doesn't check if dev is NULL
+ */
+uint32_t gfc100_get_eflash_size(struct gfc100_eflash_dev_t *dev);
+
+/**
+ * \brief Gets flash page size in bytes
+ *
+ * \param[in] dev GFC100 device struct \ref gfc100_eflash_dev_t
+ *
+ * \return Returns the page size of the flash memory in bytes
+ *
+ * \note For better performance, this function doesn't check if dev is NULL
+ */
+uint32_t gfc100_get_eflash_page_size(struct gfc100_eflash_dev_t *dev);
+
+/**
+ * \brief Gets number of info pages
+ *
+ * \param[in] dev GFC100 device struct \ref gfc100_eflash_dev_t
+ *
+ * \return Returns the number of info pages from the extended area
+ *
+ * \note For better performance, this function doesn't check if dev is NULL.
+ */
+uint32_t gfc100_get_num_of_info_pages(struct gfc100_eflash_dev_t *dev);
+
+/**
+ * \brief Gets process specific error bits
+ *
+ * \param[in] dev GFC100 device struct \ref gfc100_eflash_dev_t
+ *
+ * \return Returns the error bits specified by the process specific part
+ * of the controller.
+ *
+ * \note For better performance, this function doesn't check if dev is NULL.
+ * \note Can be used for debug purposes.
+ */
+uint32_t gfc100_get_proc_spec_error(struct gfc100_eflash_dev_t *dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GFC100_FLASH_DRV_H__ */
+
diff --git a/platform/ext/target/musca_b1_secure_enclave/Native_Driver/gfc100_process_spec_api.h b/platform/ext/target/musca_b1_secure_enclave/Native_Driver/gfc100_process_spec_api.h
new file mode 100644
index 0000000..723ea25
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Native_Driver/gfc100_process_spec_api.h
@@ -0,0 +1,93 @@
+/*
+ * 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 gfc100_process_specific_api.h
+*
+* \brief Header file for the process specific part of the
+* GFC100 flash controller
+*/
+
+#ifndef __GFC100_PROCESS_SPEC_API_H__
+#define __GFC100_PROCESS_SPEC_API_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+/**
+ * \brief Sets timing parameters on the process specific part
+ *
+ * \param[in] reg_map_base Process specific register map base
+ * \param[in] sys_clk System clock in Hz
+ */
+void gfc100_proc_spec_set_eflash_timing(uint32_t reg_map_base,
+ uint32_t sys_clk);
+
+/**
+ * \brief Gets flash memory size
+ *
+ * \param[in] reg_map_base Process specific register map base
+ *
+ * \return Returns the size of the flash memory
+ */
+uint32_t gfc100_proc_spec_get_eflash_size(uint32_t reg_map_base);
+
+/**
+ * \brief Gets flash page size
+ *
+ * \param[in] reg_map_base Process specific register map base
+ *
+ * \return Returns the page size of the flash memory
+ */
+uint32_t gfc100_proc_spec_get_eflash_page_size(uint32_t reg_map_base);
+
+/**
+ * \brief Gets word width of the process specific part
+ *
+ * \param[in] reg_map_base Process specific register map base
+ *
+ * \return Returns word width of the process specific part
+ */
+uint32_t gfc100_proc_spec_get_eflash_word_width(uint32_t reg_map_base);
+
+/**
+ * \brief Gets number of info pages
+ *
+ * \param[in] reg_map_base Process specific register map base
+ *
+ * \return Returns the number of info pages from the extended area
+ */
+uint32_t gfc100_proc_spec_get_num_of_info_pages(uint32_t reg_map_base);
+
+/**
+ * \brief Gets process specific error bits
+ *
+ * \param[in] reg_map_base Process specific register map base
+ *
+ * \return Returns the error bits specified by the process specific part
+ * of the controller.
+ */
+uint32_t gfc100_proc_spec_get_error_cause(uint32_t reg_map_base);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GFC100_PROCESS_SPEC_API_H__ */
+
diff --git a/platform/ext/target/musca_b1_secure_enclave/Native_Driver/mhu_v2_x.c b/platform/ext/target/musca_b1_secure_enclave/Native_Driver/mhu_v2_x.c
new file mode 100644
index 0000000..b228c3f
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Native_Driver/mhu_v2_x.c
@@ -0,0 +1,603 @@
+/*
+ * Copyright (c) 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 <stdint.h>
+#include <stdbool.h>
+#include "mhu_v2_x.h"
+
+#define _MHU_V2_X_MAX_CHANNELS 124
+#define _MHU_V2_1_MAX_CHCOMB_INT 4
+#define ENABLE 0x1
+#define DISABLE 0x0
+#define CLEAR_INTR 0x1
+#define CH_PER_CH_COMB 0x20
+#define SEND_FRAME(p_mhu) ((struct _mhu_v2_x_send_frame_t *)p_mhu)
+#define RECV_FRAME(p_mhu) ((struct _mhu_v2_x_recv_frame_t *)p_mhu)
+
+#define MHU_MAJOR_REV_V2 0x1u
+#define MHU_MINOR_REV_2_0 0x0u
+#define MHU_MINOR_REV_2_1 0x1u
+
+struct _mhu_v2_x_send_ch_window_t {
+ /* Offset: 0x00 (R/ ) Channel Status */
+ volatile uint32_t ch_st;
+ /* Offset: 0x04 (R/ ) Reserved */
+ volatile uint32_t reserved_0;
+ /* Offset: 0x08 (R/ ) Reserved */
+ volatile uint32_t reserved_1;
+ /* Offset: 0x0C ( /W) Channel Set */
+ volatile uint32_t ch_set;
+ /* Offset: 0x10 (R/ ) Channel Interrupt Status (Reserved in 2.0) */
+ volatile uint32_t ch_int_st;
+ /* Offset: 0x14 ( /W) Channel Interrupt Clear (Reserved in 2.0) */
+ volatile uint32_t ch_int_clr;
+ /* Offset: 0x18 (R/W) Channel Interrupt Enable (Reserved in 2.0) */
+ volatile uint32_t ch_int_en;
+ /* Offset: 0x1C (R/ ) Reserved */
+ volatile uint32_t reserved_2;
+};
+
+struct _mhu_v2_x_send_frame_t {
+ /* Offset: 0x000 ( / ) Sender Channel Window 0 -123 */
+ struct _mhu_v2_x_send_ch_window_t send_ch_window[_MHU_V2_X_MAX_CHANNELS];
+ /* Offset: 0xF80 (R/ ) Message Handling Unit Configuration */
+ volatile uint32_t mhu_cfg;
+ /* Offset: 0xF84 (R/W) Response Configuration */
+ volatile uint32_t resp_cfg;
+ /* Offset: 0xF88 (R/W) Access Request */
+ volatile uint32_t access_request;
+ /* Offset: 0xF8C (R/ ) Access Ready */
+ volatile uint32_t access_ready;
+ /* Offset: 0xF90 (R/ ) Interrupt Status */
+ volatile uint32_t int_st;
+ /* Offset: 0xF94 ( /W) Interrupt Clear */
+ volatile uint32_t int_clr;
+ /* Offset: 0xF98 (R/W) Interrupt Enable */
+ volatile uint32_t int_en;
+ /* Offset: 0xF9C (R/ ) Reserved */
+ volatile uint32_t reserved_0;
+ /* Offset: 0xFA0 (R/W) Channel Combined Interrupt Stat (Reserved in 2.0) */
+ volatile uint32_t ch_comb_int_st[_MHU_V2_1_MAX_CHCOMB_INT];
+ /* Offset: â€0xFC4‬ (R/ ) Reserved */
+ volatile uint32_t reserved_1[6];
+ /* Offset: 0xFC8 (R/ ) Implementer Identification Register */
+ volatile uint32_t iidr;
+ /* Offset: 0xFCC (R/ ) Architecture Identification Register */
+ volatile uint32_t aidr;
+ /* Offset: 0xFD0 (R/ ) */
+ volatile uint32_t pid_1[4];
+ /* Offset: 0xFE0 (R/ ) */
+ volatile uint32_t pid_0[4];
+ /* Offset: 0xFF0 (R/ ) */
+ volatile uint32_t cid[4];
+};
+
+struct _mhu_v2_x_rec_ch_window_t {
+ /* Offset: 0x00 (R/ ) Channel Status */
+ volatile uint32_t ch_st;
+ /* Offset: 0x04 (R/ ) Channel Status Masked */
+ volatile uint32_t ch_st_msk;
+ /* Offset: 0x08 ( /W) Channel Clear */
+ volatile uint32_t ch_clr;
+ /* Offset: 0x0C (R/ ) Reserved */
+ volatile uint32_t reserved_0;
+ /* Offset: 0x10 (R/ ) Channel Mask Status */
+ volatile uint32_t ch_msk_st;
+ /* Offset: 0x14 ( /W) Channel Mask Set */
+ volatile uint32_t ch_msk_set;
+ /* Offset: 0x18 ( /W) Channel Mask Clear */
+ volatile uint32_t ch_msk_clr;
+ /* Offset: 0x1C (R/ ) Reserved */
+ volatile uint32_t reserved_1;
+};
+
+struct _mhu_v2_x_recv_frame_t {
+ /* Offset: 0x000 ( / ) Receiver Channel Window 0 -123 */
+ struct _mhu_v2_x_rec_ch_window_t rec_ch_window[_MHU_V2_X_MAX_CHANNELS];
+ /* Offset: 0xF80 (R/ ) Message Handling Unit Configuration */
+ volatile uint32_t mhu_cfg;
+ /* Offset: 0xF84 (R/ ) Reserved */
+ volatile uint32_t reserved_0[3];
+ /* Offset: 0xF90 (R/ ) Interrupt Status (Reserved in 2.0) */
+ volatile uint32_t int_st;
+ /* Offset: 0xF94 (R/ ) Interrupt Clear (Reserved in 2.0) */
+ volatile uint32_t int_clr;
+ /* Offset: 0xF98 (R/W) Interrupt Enable (Reserved in 2.0) */
+ volatile uint32_t int_en;
+ /* Offset: 0xF9C (R/ ) Reserved */
+ volatile uint32_t reserved_1;
+ /* Offset: 0xFA0 (R/ ) Channel Combined Interrupt Stat (Reserved in 2.0) */
+ volatile uint32_t ch_comb_int_st[_MHU_V2_1_MAX_CHCOMB_INT];
+ /* Offset: 0xFB0 (R/ ) Reserved */
+ volatile uint32_t reserved_2[6];
+ /* Offset: 0xFC8 (R/ ) Implementer Identification Register */
+ volatile uint32_t iidr;
+ /* Offset: 0xFCC (R/ ) Architecture Identification Register */
+ volatile uint32_t aidr;
+ /* Offset: 0xFD0 (R/ ) */
+ volatile uint32_t pid_1[4];
+ /* Offset: 0xFE0 (R/ ) */
+ volatile uint32_t pid_0[4];
+ /* Offset: 0xFF0 (R/ ) */
+ volatile uint32_t cid[4];
+};
+
+union _mhu_v2_x_frame_t {
+ struct _mhu_v2_x_send_frame_t send_frame;
+ struct _mhu_v2_x_recv_frame_t recv_frame;
+};
+
+enum mhu_v2_x_error_t mhu_v2_x_driver_init(struct mhu_v2_x_dev_t *dev,
+ enum mhu_v2_x_supported_revisions rev)
+{
+ uint32_t AIDR = 0;
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if (dev->is_initialized) {
+ return MHU_V_2_X_ERR_ALREADY_INIT;
+ }
+
+ if (rev == MHU_REV_READ_FROM_HW) {
+ /* Read revision from HW */
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ AIDR = p_mhu->recv_frame.aidr;
+ } else {
+ AIDR = p_mhu->send_frame.aidr;
+ }
+
+ /* Get bits 7:4 to read major revision */
+ if ( ((AIDR >> 4) & 0b1111) != MHU_MAJOR_REV_V2) {
+ /* Unsupported MHU version */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ } /* No need to save major version, driver only supports MHUv2 */
+
+ /* Get bits 3:0 to read minor revision */
+ dev->subversion = AIDR & 0b1111;
+
+ if (dev->subversion != MHU_MINOR_REV_2_0 &&
+ dev->subversion != MHU_MINOR_REV_2_1) {
+ /* Unsupported subversion */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+ } else {
+ /* Revisions were provided by caller */
+ if (rev == MHU_REV_2_0) {
+ dev->subversion = MHU_MINOR_REV_2_0;
+ } else if (rev == MHU_REV_2_1) {
+ dev->subversion = MHU_MINOR_REV_2_1;
+ } else {
+ /* Unsupported subversion */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }/* No need to save major version, driver only supports MHUv2 */
+ }
+
+ dev->is_initialized = true;
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+uint32_t mhu_v2_x_get_num_channel_implemented(const struct mhu_v2_x_dev_t *dev)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ return (SEND_FRAME(p_mhu))->mhu_cfg;
+ } else {
+ return (RECV_FRAME(p_mhu))->mhu_cfg;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_send(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel, uint32_t val)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_set = val;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_clear(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_clr = UINT32_MAX;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_receive(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t *value)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ *value = (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_st;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_set(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_msk_set = mask;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_msk_clr = mask;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_enable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->subversion == MHU_MINOR_REV_2_1) {
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_int_en = ENABLE;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_disable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->subversion == MHU_MINOR_REV_2_1) {
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_int_en = DISABLE;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->subversion == MHU_MINOR_REV_2_1) {
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_int_clr = CLEAR_INTR;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_initiate_transfer(
+ const struct mhu_v2_x_dev_t *dev)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ (SEND_FRAME(p_mhu))->access_request = ENABLE;
+
+ while ( !((SEND_FRAME(p_mhu))->access_ready) ) {
+ /* Wait in a loop for access ready signal to be high */
+ ;
+ }
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_close_transfer(const struct mhu_v2_x_dev_t *dev)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ (SEND_FRAME(p_mhu))->access_request = DISABLE;
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_get_access_request(
+ const struct mhu_v2_x_dev_t *dev, uint32_t *val)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ *val = (SEND_FRAME(p_mhu))->access_request;
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_set_access_request(
+ const struct mhu_v2_x_dev_t *dev)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ (SEND_FRAME(p_mhu))->access_request = ENABLE;
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_reset_access_request(
+ const struct mhu_v2_x_dev_t *dev)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ (SEND_FRAME(p_mhu))->access_request = DISABLE;
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_get_access_ready(
+ const struct mhu_v2_x_dev_t *dev, uint32_t *val)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ *val = (SEND_FRAME(p_mhu))->access_ready;
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+uint32_t mhu_v2_x_get_interrupt_status(const struct mhu_v2_x_dev_t *dev)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ return (SEND_FRAME(p_mhu))->int_st;
+ } else {
+ return (RECV_FRAME(p_mhu))->int_st;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_enable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t mask)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->subversion == MHU_MINOR_REV_2_0) {
+ if (mask & MHU_2_1_INTR_CHCOMB_MASK) {
+ /* Combined channel IRQ is not present in v2.0 */
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ /* Only sender frame has these registers */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->int_en |= mask;
+ } else {
+ (RECV_FRAME(p_mhu))->int_en |= mask;
+ }
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_disable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t mask)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->subversion == MHU_MINOR_REV_2_0) {
+ if (mask & MHU_2_1_INTR_CHCOMB_MASK) {
+ /* Combined channel IRQ is not present in v2.0 */
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ /* Only sender frame has these registers */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->int_en &= ~mask;
+ } else {
+ (RECV_FRAME(p_mhu))->int_en &= ~mask;
+ }
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t mask)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->subversion == MHU_MINOR_REV_2_0) {
+ if (mask & MHU_2_1_INTR_CHCOMB_MASK) {
+ /* Combined channel IRQ is not present in v2.0 */
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ /* Only sender frame has these registers */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->int_clr = mask;
+ } else {
+ (RECV_FRAME(p_mhu))->int_clr = mask;
+ }
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_1_get_ch_interrupt_num(
+ const struct mhu_v2_x_dev_t *dev, uint32_t *channel)
+{
+ uint32_t i, j, status;
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->subversion != MHU_MINOR_REV_2_1) {
+ /* Feature is only supported in MHU v2.1 */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+
+ for(i = 0; i < _MHU_V2_1_MAX_CHCOMB_INT; i++) {
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ status = (SEND_FRAME(p_mhu))->ch_comb_int_st[i];
+ } else {
+ status = (RECV_FRAME(p_mhu))->ch_comb_int_st[i];
+ }
+
+ for(j = 0; j < CH_PER_CH_COMB; j++) {
+ if (status & ENABLE) {
+ *channel = (j + (i * CH_PER_CH_COMB));
+ return MHU_V_2_X_ERR_NONE;
+ }
+ status >>= 1;
+ }
+ }
+
+ return MHU_V_2_X_ERR_GENERAL;
+}
diff --git a/platform/ext/target/musca_b1_secure_enclave/Native_Driver/mhu_v2_x.h b/platform/ext/target/musca_b1_secure_enclave/Native_Driver/mhu_v2_x.h
new file mode 100644
index 0000000..08e0dd3
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Native_Driver/mhu_v2_x.h
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/**
+ * \file mhu_v2_x.h
+ * \brief Driver for Arm MHU v2.0 and v2.1
+ */
+
+#ifndef __MHU_V2_X_H__
+#define __MHU_V2_X_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MHU_2_X_INTR_NR2R_OFF (0x0u)
+#define MHU_2_X_INTR_R2NR_OFF (0x1u)
+#define MHU_2_1_INTR_CHCOMB_OFF (0x2u)
+
+#define MHU_2_X_INTR_NR2R_MASK (0x1u << MHU_2_X_INTR_NR2R_OFF)
+#define MHU_2_X_INTR_R2NR_MASK (0x1u << MHU_2_X_INTR_R2NR_OFF)
+#define MHU_2_1_INTR_CHCOMB_MASK (0x1u << MHU_2_1_INTR_CHCOMB_OFF)
+
+enum mhu_v2_x_frame_t {
+ MHU_V2_X_SENDER_FRAME = 0x0u,
+ MHU_V2_X_RECEIVER_FRAME = 0x1u,
+};
+
+enum mhu_v2_x_supported_revisions {
+ MHU_REV_READ_FROM_HW = 0,
+ MHU_REV_2_0,
+ MHU_REV_2_1,
+};
+
+struct mhu_v2_x_dev_t {
+ const uint32_t base;
+ enum mhu_v2_x_frame_t frame;
+ uint32_t subversion; /*!< Hardware subversion: v2.X */
+ bool is_initialized; /*!< Indicates if the MHU driver
+ * is initialized and enabled
+ */
+};
+
+/**
+ * \brief MHU v2 error enumeration types.
+ */
+enum mhu_v2_x_error_t {
+ MHU_V_2_X_ERR_NONE = 0,
+ MHU_V_2_X_ERR_NOT_INIT = -1,
+ MHU_V_2_X_ERR_ALREADY_INIT = -2,
+ MHU_V_2_X_ERR_UNSUPPORTED_VERSION = -3,
+ MHU_V_2_X_ERR_INVALID_ARG = -4,
+ MHU_V_2_X_ERR_GENERAL = -5
+};
+
+/**
+ * \brief Initializes the driver
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] rev MHU revision (if can't be identified from HW)
+ *
+ * Reads the MHU hardware version
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note MHU revision only has to be specified when versions can't be read
+ * from HW (ARCH_MAJOR_REV reg reads as 0x0).
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_driver_init(struct mhu_v2_x_dev_t *dev,
+ enum mhu_v2_x_supported_revisions rev);
+
+/**
+ * \brief Returns the number of channels implemented.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * Returns the number of channels implemented.
+ *
+ * \return Returns the number of channels implemented.
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+uint32_t mhu_v2_x_get_num_channel_implemented(
+ const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Sends the value over a channel.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Channel to send the value over.
+ * \param[in] val Value to send.
+ *
+ * Sends the value over a channel.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_send(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel, uint32_t val);
+
+/**
+ * \brief Clears the channel after the value is send over it.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Channel to clear.
+ *
+ * Clears the channel after the value is send over it.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_clear(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel);
+
+/**
+ * \brief Receives the value over a channel.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Channel to receive the value from.
+ * \param[out] value Pointer to variable that will store the value.
+ *
+ * Receives the value over a channel.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_receive(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t *value);
+
+/**
+ * \brief Sets bits in the Channel Mask.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Which channel's mask to set.
+ * \param[in] mask Mask to be set over a receiver frame.
+ *
+ * Sets bits in the Channel Mask.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_set(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask);
+
+/**
+ * \brief Clears bits in the Channel Mask.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Which channel's mask to clear.
+ * \param[in] mask Mask to be clear over a receiver frame.
+ *
+ * Clears bits in the Channel Mask.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask);
+
+/**
+ * \brief Enables the Channel interrupt.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Which channel's interrupt to enable.
+ *
+ * Enables the Channel clear interrupt.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_enable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel);
+
+/**
+ * \brief Disables the Channel interrupt.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Which channel's interrupt to disable.
+ *
+ * Disables the Channel interrupt.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_disable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel);
+
+/**
+ * \brief Cleares the Channel interrupt.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Which channel's interrupt to clear.
+ *
+ * Cleares the Channel interrupt.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel);
+
+/**
+ * \brief Initiates a MHU transfer with the handshake signals.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * Initiates a MHU transfer with the handshake signals in a blocking mode.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_initiate_transfer(
+ const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Closes a MHU transfer with the handshake signals.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * Closes a MHU transfer with the handshake signals in a blocking mode.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_close_transfer(
+ const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Returns the value of access request signal.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[out] val Pointer to variable that will store the value.
+ *
+ * For more information please read the MHU v2 user guide
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_get_access_request(
+ const struct mhu_v2_x_dev_t *dev, uint32_t *val);
+
+/**
+ * \brief Sets the value of access request signal to high.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * For more information please read the MHU v2 user guide
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_set_access_request(
+ const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Sets the value of access request signal to low.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * For more information please read the MHU v2 user guide
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_reset_access_request(
+ const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Returns the value of access ready signal.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[out] val Pointer to variable that will store the value.
+ *
+ * For more information please read the MHU v2 user guide
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_get_access_ready(
+ const struct mhu_v2_x_dev_t *dev, uint32_t *val);
+
+/**
+ * \brief Returns the MHU interrupt status.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * \return Interrupt status register value. Masking is needed for individual
+ * interrupts.
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+uint32_t mhu_v2_x_get_interrupt_status(const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Enables MHU interrupts.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] mask Bit mask for enabling/disabling interrupts
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_enable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t mask);
+
+/**
+ * \brief Disables MHU interrupts.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] mask Bit mask for enabling/disabling interrupts
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_disable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t mask);
+
+/**
+ * \brief Clears MHU interrupts.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] mask Bit mask for clearing interrupts
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t mask);
+
+/**
+ * \brief Returns the first channel number whose interrupt bit is high.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[out] channel Pointer to variable that will have the channel value.
+ *
+ * \return Returns the first channel number whose interrupt bit is high.
+ * \return Returns mhu_v2_x_error_t error code.
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_1_get_ch_interrupt_num(
+ const struct mhu_v2_x_dev_t *dev, uint32_t *channel);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MHU_V2_X_H__ */
diff --git a/platform/ext/target/musca_b1_secure_enclave/Native_Driver/musca_b1_eflash_drv.c b/platform/ext/target/musca_b1_secure_enclave/Native_Driver/musca_b1_eflash_drv.c
new file mode 100644
index 0000000..ccfde9c
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/Native_Driver/musca_b1_eflash_drv.c
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+/**
+ * \file musca_b1_eflash_drv.c
+ *
+ * \brief Process specifinc implementation of GFC100 flash controller for
+ * Musca B1 board.
+ */
+
+#include "gfc100_process_spec_api.h"
+
+void gfc100_proc_spec_set_eflash_timing(uint32_t reg_map_base,
+ uint32_t sys_clk)
+{
+ (void)sys_clk;
+
+ *(uint32_t *)reg_map_base = 0x11082801;
+ *(uint32_t *)(reg_map_base + 4U) = 0x64050208;
+ *(uint32_t *)(reg_map_base + 8U) = 0xa0a0a08;
+}
+
+uint32_t gfc100_proc_spec_get_eflash_word_width(uint32_t reg_map_base)
+{
+ (void)reg_map_base;
+
+ return 128U;
+}
+
+uint32_t gfc100_proc_spec_get_eflash_size(uint32_t reg_map_base)
+{
+ (void)reg_map_base;
+
+ return 0x200000U;
+}
+
+uint32_t gfc100_proc_spec_get_eflash_page_size(uint32_t reg_map_base)
+{
+ (void)reg_map_base;
+
+ return 0x4000;
+}
+
+uint32_t gfc100_proc_spec_get_num_of_info_pages(uint32_t reg_map_base)
+{
+ (void)reg_map_base;
+
+ return 3U;
+}
+
+uint32_t gfc100_proc_spec_get_error_cause(uint32_t reg_map_base)
+{
+ return *(uint32_t *)(reg_map_base + 0x18);
+}
+
diff --git a/platform/ext/target/musca_b1_secure_enclave/Native_Driver/qspi_ip6514e_drv.c b/platform/ext/target/musca_b1_secure_enclave/Native_Driver/qspi_ip6514e_drv.c
new file mode 100644
index 0000000..bb13a42
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/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_b1_secure_enclave/Native_Driver/qspi_ip6514e_drv.h b/platform/ext/target/musca_b1_secure_enclave/Native_Driver/qspi_ip6514e_drv.h
new file mode 100644
index 0000000..6992925
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/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_b1_secure_enclave/boot_hal.c b/platform/ext/target/musca_b1_secure_enclave/boot_hal.c
new file mode 100644
index 0000000..5673bd0
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/boot_hal.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdio.h>
+#include "cmsis.h"
+#include "region.h"
+#include "target_cfg.h"
+#include "boot_hal.h"
+#include "Driver_Flash.h"
+#include "flash_layout.h"
+#include "bootutil/fault_injection_hardening.h"
+
+#if defined(CRYPTO_HW_ACCELERATOR) || \
+ defined(CRYPTO_HW_ACCELERATOR_OTP_PROVISIONING)
+#include "crypto_hw.h"
+#endif
+
+/* Flash device name must be specified by target */
+extern ARM_DRIVER_FLASH FLASH_DEV_NAME;
+
+REGION_DECLARE(Image$$, ER_DATA, $$Base)[];
+REGION_DECLARE(Image$$, ARM_LIB_HEAP, $$ZI$$Limit)[];
+
+__attribute__((naked)) void boot_clear_bl2_ram_area(void)
+{
+ __ASM volatile(
+#ifndef __ICCARM__
+ ".syntax unified \n"
+#endif
+ "movs r0, #0 \n"
+ "subs %1, %1, %0 \n"
+ "Loop: \n"
+ "subs %1, #4 \n"
+ "blt Clear_done \n"
+ "str r0, [%0, %1] \n"
+ "b Loop \n"
+ "Clear_done: \n"
+ "bx lr \n"
+ :
+ : "r" (REGION_NAME(Image$$, ER_DATA, $$Base)),
+ "r" (REGION_NAME(Image$$, ARM_LIB_HEAP, $$ZI$$Limit))
+ : "r0", "memory"
+ );
+}
+
+int32_t boot_platform_init(void)
+{
+ int32_t result;
+
+ result = FLASH_DEV_NAME.Initialize(NULL);
+ if (result != ARM_DRIVER_OK) {
+ return 1;
+ }
+
+#ifdef CRYPTO_HW_ACCELERATOR
+ result = crypto_hw_accelerator_init();
+ if (result) {
+ return 1;
+ }
+#endif /* CRYPTO_HW_ACCELERATOR */
+
+/* This is a workaround to program the TF-M related cryptographic keys
+ * to CC312 OTP memory. This functionality is independent from secure boot,
+ * this is usually done on the factory floor during chip manufacturing.
+ */
+#ifdef CRYPTO_HW_ACCELERATOR_OTP_PROVISIONING
+ printf("OTP provisioning started.");
+ result = crypto_hw_accelerator_otp_provisioning();
+ if (result) {
+ printf("OTP provisioning FAILED: 0x%X", result);
+ return 1;
+ } else {
+ printf("OTP provisioning succeeded. TF-M won't be loaded.");
+
+ /* We don't need to boot - the only aim is provisioning. */
+ while (1);
+ }
+#endif /* CRYPTO_HW_ACCELERATOR_OTP_PROVISIONING */
+
+ return 0;
+}
+
+void boot_platform_quit(struct boot_arm_vector_table *vt)
+{
+ /* Clang at O0, stores variables on the stack with SP relative addressing.
+ * When manually set the SP then the place of reset vector is lost.
+ * Static variables are stored in 'data' or 'bss' section, change of SP has
+ * no effect on them.
+ */
+ static struct boot_arm_vector_table *vt_cpy;
+ int32_t result;
+
+#ifdef CRYPTO_HW_ACCELERATOR
+ result = crypto_hw_accelerator_finish();
+ if (result) {
+ while (1);
+ }
+
+ (void)fih_delay_init();
+#endif /* CRYPTO_HW_ACCELERATOR */
+
+ result = FLASH_DEV_NAME.Uninitialize();
+ if (result != ARM_DRIVER_OK) {
+ while (1);
+ }
+
+ vt_cpy = vt;
+
+ __set_MSP(vt->msp);
+ __DSB();
+ __ISB();
+
+ boot_jump_to_next_image(vt_cpy->reset);
+}
diff --git a/platform/ext/target/musca_b1_secure_enclave/config.cmake b/platform/ext/target/musca_b1_secure_enclave/config.cmake
new file mode 100644
index 0000000..0b923c2
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/config.cmake
@@ -0,0 +1,25 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+# Configuration values forced due to the Secure Enclave topology
+set(TFM_MULTI_CORE_TOPOLOGY ON CACHE BOOL "Whether to build for a dual-cpu architecture" FORCE)
+set(TFM_PSA_API ON CACHE BOOL "Use PSA api (IPC mode) instead of secure library mode" FORCE)
+set(NS FALSE CACHE BOOL "Whether to build NS app" FORCE)
+set(TEST_NS OFF CACHE BOOL "Whether to build NS regression tests" FORCE)
+
+# Serial output is not available for Secure Enclave
+set(PLATFORM_DEFAULT_UART_STDOUT FALSE CACHE BOOL "Use default uart stdout implementation." FORCE)
+set(MCUBOOT_LOG_LEVEL "NONE" CACHE STRING "Level of logging to use for MCUboot [OFF, ERROR, WARNING, INFO, DEBUG]" FORCE)
+
+# Test services are inaccessible via Proxy service
+set(TEST_S OFF CACHE BOOL "Whether to build S regression tests" FORCE)
+
+# Currently only level 1 isolation is supported
+set(TFM_ISOLATION_LEVEL 1 CACHE STRING "Isolation level" FORCE)
+
+# Crypto hardware accelerator is turned on by default
+set(CRYPTO_HW_ACCELERATOR ON CACHE BOOL "Whether to enable the crypto hardware accelerator on supported platforms")
diff --git a/platform/ext/target/musca_b1_secure_enclave/mailbox/mailbox_ipc_intr.c b/platform/ext/target/musca_b1_secure_enclave/mailbox/mailbox_ipc_intr.c
new file mode 100644
index 0000000..283d3bb
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/mailbox/mailbox_ipc_intr.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+
+#include "cmsis.h"
+#include "platform_multicore.h"
+
+__STATIC_INLINE void tfm_trigger_pendsv(void)
+{
+ SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
+}
+
+void MHU0_MSG_0_Handler(void)
+{
+ uint32_t magic;
+
+ platform_mailbox_fetch_msg_data(&magic);
+
+ /* Sanity check based on predefined arbitrary value */
+ if (magic == PSA_CLIENT_CALL_REQ_MAGIC) {
+ tfm_trigger_pendsv();
+ }
+}
diff --git a/platform/ext/target/musca_b1_secure_enclave/mailbox/platform_multicore.c b/platform/ext/target/musca_b1_secure_enclave/mailbox/platform_multicore.c
new file mode 100644
index 0000000..e568449
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/mailbox/platform_multicore.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "platform_multicore.h"
+#include "cmsis.h"
+#include "mhu_v2_x.h"
+#include "device_definition.h"
+
+void platform_init_mailbox_hw(void)
+{
+ mhu_v2_x_driver_init(&MHU0_SENDER_DEV, MHU_REV_2_0);
+ mhu_v2_x_driver_init(&MHU0_RECEIVER_DEV, MHU_REV_2_0);
+}
+
+void platform_mailbox_send_msg_data(uint32_t data)
+{
+ mhu_v2_x_initiate_transfer(&MHU0_SENDER_DEV);
+ mhu_v2_x_channel_send(&MHU0_SENDER_DEV, 0, data);
+ mhu_v2_x_close_transfer(&MHU0_SENDER_DEV);
+}
+
+void platform_mailbox_fetch_msg_data(uint32_t *data_ptr)
+{
+ mhu_v2_x_channel_receive(&MHU0_RECEIVER_DEV, 0, data_ptr);
+ mhu_v2_x_channel_clear(&MHU0_RECEIVER_DEV, 0);
+
+ NVIC_ClearPendingIRQ(PSA_CLIENT_CALL_NVIC_IRQn);
+}
+
+void platform_mailbox_fetch_msg_ptr(void **msg_ptr)
+{
+ mhu_v2_x_channel_receive(&MHU0_RECEIVER_DEV, 0, (uint32_t*)(msg_ptr));
+ mhu_v2_x_channel_clear(&MHU0_RECEIVER_DEV, 0);
+
+ NVIC_ClearPendingIRQ(PSA_CLIENT_CALL_NVIC_IRQn);
+}
+
+void platform_mailbox_wait_for_notify(void)
+{
+ while(NVIC_GetPendingIRQ(PSA_CLIENT_CALL_NVIC_IRQn) == 0);
+}
diff --git a/platform/ext/target/musca_b1_secure_enclave/mailbox/platform_multicore.h b/platform/ext/target/musca_b1_secure_enclave/mailbox/platform_multicore.h
new file mode 100644
index 0000000..c8e5871
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/mailbox/platform_multicore.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2019, Cypress Semiconductor Corporation. All rights reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PLATFORM_MULTICORE_H_
+#define _PLATFORM_MULTICORE_H_
+
+#include <stdint.h>
+
+/* Arbitrary predefined values to sync between Host and Secure Enclave */
+#define IPC_SYNC_MAGIC (0x7DADE011)
+
+#define NS_MAILBOX_INIT_ENABLE (0xAE)
+#define S_MAILBOX_READY (0xC3)
+
+#define PLATFORM_MAILBOX_SUCCESS (0x0)
+
+#define PSA_CLIENT_CALL_REQ_MAGIC (0xA5CF50C6)
+#define PSA_CLIENT_CALL_REPLY_MAGIC (0xC605FC5A)
+
+#define PSA_CLIENT_CALL_NVIC_IRQn (MHU0_MSG_0_IRQn)
+
+/**
+ * \brief Initialize mailbox HW
+ */
+void platform_init_mailbox_hw(void);
+
+/**
+ * \brief Fetch a pointer from mailbox
+ *
+ * \param[out] msg_ptr The address to write the pointer value to.
+ *
+ * \retval 0 The operation succeeds.
+ * \retval else The operation fails.
+ */
+void platform_mailbox_fetch_msg_ptr(void **msg_ptr);
+
+/**
+ * \brief Fetch a data value from mailbox
+ *
+ * \param[out] data_ptr The address to write the pointer value to.
+ *
+ * \retval 0 The operation succeeds.
+ * \retval else The operation fails.
+ */
+void platform_mailbox_fetch_msg_data(uint32_t *data_ptr);
+
+/**
+ * \brief Send a data value via mailbox
+ *
+ * \param[in] data The data value to be sent
+ *
+ * \retval 0 The operation succeeds.
+ * \retval else The operation fails.
+ */
+void platform_mailbox_send_msg_data(uint32_t data);
+
+/**
+ * \brief Wait for a mailbox notify event.
+ */
+void platform_mailbox_wait_for_notify(void);
+
+#endif /* _PLATFORM_MULTICORE_H_ */
diff --git a/platform/ext/target/musca_b1_secure_enclave/mailbox/platform_spe_mailbox.c b/platform/ext/target/musca_b1_secure_enclave/mailbox/platform_spe_mailbox.c
new file mode 100644
index 0000000..1ccdfce
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/mailbox/platform_spe_mailbox.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2019, Cypress Semiconductor Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "platform_multicore.h"
+#include "tfm_spe_mailbox.h"
+#include "cmsis.h"
+
+static void mailbox_ipc_config(void)
+{
+ /* 2 NVIC bits present on this platform, setting the almost lowest priority. */
+ NVIC_SetPriority(PSA_CLIENT_CALL_NVIC_IRQn, 2);
+
+ NVIC_EnableIRQ(PSA_CLIENT_CALL_NVIC_IRQn);
+}
+
+int32_t tfm_mailbox_hal_notify_peer(void)
+{
+ platform_mailbox_send_msg_data(PSA_CLIENT_CALL_REPLY_MAGIC);
+
+ return MAILBOX_SUCCESS;
+}
+
+int32_t tfm_mailbox_hal_init(struct secure_mailbox_queue_t *s_queue)
+{
+ struct ns_mailbox_queue_t *ns_queue = NULL;
+
+ /* Inform NSPE that NSPE mailbox initialization can start */
+ platform_mailbox_send_msg_data(NS_MAILBOX_INIT_ENABLE);
+
+ platform_mailbox_wait_for_notify();
+
+ /* Receive the address of NSPE mailbox queue */
+ platform_mailbox_fetch_msg_ptr((void **)&ns_queue);
+
+ /*
+ * FIXME
+ * Necessary sanity check of the address of NPSE mailbox queue should
+ * be implemented there.
+ */
+ s_queue->ns_queue = ns_queue;
+
+ mailbox_ipc_config();
+
+ /* Inform NSPE that SPE mailbox service is ready */
+ platform_mailbox_send_msg_data(S_MAILBOX_READY);
+
+ return MAILBOX_SUCCESS;
+}
+
+void tfm_mailbox_hal_enter_critical(void)
+{
+ /* Protection against concurrent access should be added
+ * if more messages are sent parallel. */
+}
+
+void tfm_mailbox_hal_exit_critical(void)
+{
+ /* Protection against concurrent access should be added
+ * if more messages are sent parallel. */
+}
diff --git a/platform/ext/target/musca_b1_secure_enclave/partition/flash_layout.h b/platform/ext/target/musca_b1_secure_enclave/partition/flash_layout.h
new file mode 100644
index 0000000..80815f2
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/partition/flash_layout.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2018-2020 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.
+ */
+
+#ifndef __FLASH_LAYOUT_H__
+#define __FLASH_LAYOUT_H__
+
+/* Flash (and Code SRAM) layout on Musca-B1 if Secure Enclave (SE) is used
+ * BL2 is mandatory in this case, and MCUBOOT_IMAGE_NUMBER must be 2
+ *
+ * SE images are placed in eFlash 0 and eFlash 1 and remapped to SE's memory
+ * space by ROM and CODE remap.
+ * ROM remap offset should be set to 0x1A02_0000
+ * ROM remap mask should be set to 0x0001_FFFF
+ * CODE remap offset should be set to 0x1A20_0000
+ * CODE remap mask should be set to 0x003F_FFFF
+ *
+ * Some memory areas are not accessible for SE over the remap address ranges.
+ * ITS, PS, and NV counters are accessible for SE over the flash controllers.
+ * The image base addresses for both subsystems can be found in the following
+ * table, N/A for unaccessible addresses:
+ *
+* SSE-200 address SE address
+ * eFlash 0:
+ * SSE-200 BL0 (128 KiB) 0x1A000000 N/A
+ * SE MCUBoot (128 KiB) 0x1A020000 0x00000000
+ * Internal Trusted Storage Area (32 KiB) 0x1A040000 N/A
+ * NV counters area (16 KiB) 0x1A048000 N/A
+ * Unused (196 KiB) 0x1A04C000 N/A
+ *
+ * eFlash 1:
+ * SE TF-M image primary slot (384 KiB) 0x1A200000 0x38000000
+ * SSE-200 combined image primary slot (512 KiB) 0x1A260000 0x38060000
+ * SE TF-M image secondary slot (384 KiB) 0x1A2E0000 0x380E0000
+ * SSE-200 combined image secondary slot (512 KiB) 0x1A360000 0x38160000
+ * Scratch area (64 KiB) 0x1A3C0000 0x381C0000
+ * Unused (196 KiB) 0x1A3D0000 0x381D0000
+ *
+ * Code SRAM:
+ * SSE-200 BL0 ramload area (16 KiB) 0x1A400000 0x38200000
+ * SE MCUBoot eFlash driver ramload area (16 KiB) 0x1A404000 0x38204000
+ * IPC Shared memory area (476 KiB) 0x1A408000 0x38208000
+ *
+ * The SE MCUBoot eFlash driver is copied into Code SRAM. If the driver would
+ * run from eFlash0 it would not be possible to write the NV counters also
+ * placed in eFlash0. It is not advisable to write to and fetch instructions
+ * from flash at the same time. For the same reason SSE-200 BL0 is running
+ * from Code SRAM.
+ */
+
+/* This header file is included from linker scatter file as well, where only a
+ * limited C constructs are allowed. Therefore it is not possible to include
+ * here the platform_base_address.h to access flash related defines. To resolve this
+ * some of the values are redefined here with different names, these are marked
+ * with comment.
+ */
+
+/* The size of partitions */
+#define FLASH_S_PARTITION_SIZE (0x60000) /* 384 KiB */
+#define FLASH_SSE_200_PARTITION_SIZE (0x80000) /* 512 KiB */
+#define FLASH_MAX_PARTITION_SIZE ((FLASH_S_PARTITION_SIZE > \
+ FLASH_SSE_200_PARTITION_SIZE) ? \
+ FLASH_S_PARTITION_SIZE : \
+ FLASH_SSE_200_PARTITION_SIZE)
+
+/* Sector size of the embedded flash hardware */
+#define FLASH_AREA_IMAGE_SECTOR_SIZE (0x4000) /* 16 KB */
+#define FLASH_TOTAL_SIZE (0x200000) /* 2 MB */
+
+/* Sector size of the QSPI flash hardware */
+#define QSPI_FLASH_AREA_IMAGE_SECTOR_SIZE (0x1000) /* 4 KB */
+#define QSPI_FLASH_TOTAL_SIZE (0x800000) /* 8 MB */
+
+
+/* Flash layout info for BL2 bootloader, images are placed in eFlash1 */
+#define FLASH_BASE_ADDRESS (0x38000000)
+
+#if !defined(MCUBOOT_IMAGE_NUMBER) || (MCUBOOT_IMAGE_NUMBER == 2)
+/* SE TF-M image primary slot */
+#define FLASH_AREA_0_ID (1)
+#define FLASH_AREA_0_OFFSET (0)
+#define FLASH_AREA_0_SIZE (FLASH_S_PARTITION_SIZE)
+
+/* SSE-200 image primary slot */
+#define FLASH_AREA_1_ID (FLASH_AREA_0_ID + 1)
+#define FLASH_AREA_1_OFFSET (FLASH_AREA_0_OFFSET + FLASH_AREA_0_SIZE)
+#define FLASH_AREA_1_SIZE (FLASH_SSE_200_PARTITION_SIZE)
+
+/* SE TF-M image secondary slot */
+#define FLASH_AREA_2_ID (FLASH_AREA_1_ID + 1)
+#define FLASH_AREA_2_OFFSET (FLASH_AREA_1_OFFSET + FLASH_AREA_1_SIZE)
+#define FLASH_AREA_2_SIZE (FLASH_S_PARTITION_SIZE)
+
+/* SSE-200 image secondary slot */
+#define FLASH_AREA_3_ID (FLASH_AREA_2_ID + 1)
+#define FLASH_AREA_3_OFFSET (FLASH_AREA_2_OFFSET + FLASH_AREA_2_SIZE)
+#define FLASH_AREA_3_SIZE (FLASH_SSE_200_PARTITION_SIZE)
+
+/* Scratch area */
+#define FLASH_AREA_SCRATCH_ID (FLASH_AREA_3_ID + 1)
+#define FLASH_AREA_SCRATCH_OFFSET (FLASH_AREA_3_OFFSET + FLASH_AREA_3_SIZE)
+#define FLASH_AREA_SCRATCH_SIZE (4 * FLASH_AREA_IMAGE_SECTOR_SIZE)
+
+/* The maximum number of status entries supported by the bootloader. */
+#define MCUBOOT_STATUS_MAX_ENTRIES (FLASH_MAX_PARTITION_SIZE / \
+ FLASH_AREA_SCRATCH_SIZE)
+
+/* Maximum number of image sectors supported by the bootloader. */
+#define NEEDED_MCUBOOT_IMG_SECTORS (FLASH_MAX_PARTITION_SIZE / \
+ FLASH_AREA_IMAGE_SECTOR_SIZE)
+#define MCUBOOT_MAX_IMG_SECTORS (NEEDED_MCUBOOT_IMG_SECTORS > 32 ? \
+ NEEDED_MCUBOOT_IMG_SECTORS : \
+ 32)
+
+#else /* MCUBOOT_IMAGE_NUMBER == 2 */
+#error "Only MCUBOOT_IMAGE_NUMBER 2 is supported!"
+#endif /* MCUBOOT_IMAGE_NUMBER */
+
+/* Flash device name used by BL2
+ * Name is defined in flash driver file: Driver_Flash.c
+ */
+#define FLASH_DEV_NAME Driver_EFLASH1
+
+
+/* Assets in eFlash0 */
+/* SSE-200 BL0 component */
+#define SSE200_BL0_OFFSET (0x0)
+#define SSE200_BL0_SIZE (0x20000) /* 128 KB */
+
+/* SE BL2 image */
+#define FLASH_AREA_BL2_OFFSET (SSE200_BL0_OFFSET + \
+ SSE200_BL0_SIZE)
+/* Maximum memory window size with ROM remap */
+#define FLASH_AREA_BL2_SIZE (0x20000) /* 128 KB */
+
+/* Internal Trusted Storage (ITS) Service definitions */
+#define FLASH_ITS_AREA_OFFSET (FLASH_AREA_BL2_OFFSET + \
+ FLASH_AREA_BL2_SIZE)
+#define FLASH_ITS_AREA_SIZE (2 * FLASH_AREA_IMAGE_SECTOR_SIZE)
+
+/* NV Counters definitions */
+#define FLASH_NV_COUNTERS_AREA_OFFSET (FLASH_ITS_AREA_OFFSET + \
+ FLASH_ITS_AREA_SIZE)
+#define FLASH_NV_COUNTERS_AREA_SIZE (FLASH_AREA_IMAGE_SECTOR_SIZE)
+
+
+/* Internal Trusted Storage (ITS) Service definitions
+ * Note: Further documentation of these definitions can be found in the
+ * TF-M ITS Integration Guide.
+ */
+#define ITS_FLASH_DEV_NAME Driver_EFLASH0
+
+/* In this target the CMSIS driver requires only the offset from the base
+ * address instead of the full memory address.
+ */
+#define ITS_FLASH_AREA_ADDR FLASH_ITS_AREA_OFFSET
+/* Dedicated flash area for ITS */
+#define ITS_FLASH_AREA_SIZE FLASH_ITS_AREA_SIZE
+#define ITS_RAM_FS_SIZE ITS_FLASH_AREA_SIZE
+#define ITS_SECTOR_SIZE FLASH_AREA_IMAGE_SECTOR_SIZE
+/* Number of ITS_SECTOR_SIZE per block */
+#define ITS_SECTORS_PER_BLOCK (0x1)
+/* Specifies the smallest flash programmable unit in bytes */
+#define ITS_FLASH_PROGRAM_UNIT (0x4)
+
+/* NV Counters definitions */
+#define NV_COUNTERS_FLASH_DEV_NAME Driver_EFLASH0
+#define TFM_NV_COUNTERS_AREA_ADDR FLASH_NV_COUNTERS_AREA_OFFSET
+#define TFM_NV_COUNTERS_AREA_SIZE (0x18) /* 24 Bytes */
+#define TFM_NV_COUNTERS_SECTOR_ADDR FLASH_NV_COUNTERS_AREA_OFFSET
+#define TFM_NV_COUNTERS_SECTOR_SIZE FLASH_NV_COUNTERS_AREA_SIZE
+
+
+/* Protected Storage (PS) Service definitions. PS is placed in QSPI flash */
+#define FLASH_PS_AREA_OFFSET (0x0)
+#define FLASH_PS_AREA_SIZE (5 * QSPI_FLASH_AREA_IMAGE_SECTOR_SIZE)
+
+/* Protected Storage (PS) Service definitions
+ * Note: Further documentation of these definitions can be found in the
+ * TF-M PS Integration Guide.
+ */
+#define PS_FLASH_DEV_NAME Driver_QSPI_FLASH0
+
+/* In this target the CMSIS driver requires only the offset from the base
+ * address instead of the full memory address.
+ */
+#define PS_FLASH_AREA_ADDR FLASH_PS_AREA_OFFSET
+/* Dedicated flash area for PS */
+#define PS_FLASH_AREA_SIZE FLASH_PS_AREA_SIZE
+#define PS_RAM_FS_SIZE PS_FLASH_AREA_SIZE
+#define PS_SECTOR_SIZE QSPI_FLASH_AREA_IMAGE_SECTOR_SIZE
+/* Number of PS_SECTOR_SIZE per block */
+#define PS_SECTORS_PER_BLOCK (0x1)
+/* Specifies the smallest flash programmable unit in bytes */
+#define PS_FLASH_PROGRAM_UNIT (0x1)
+/* The maximum asset size to be stored in the PS area */
+
+#endif /* __FLASH_LAYOUT_H__ */
diff --git a/platform/ext/target/musca_b1_secure_enclave/partition/region_defs.h b/platform/ext/target/musca_b1_secure_enclave/partition/region_defs.h
new file mode 100644
index 0000000..a85cba3
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/partition/region_defs.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2017-2020 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.
+ */
+
+#ifndef __REGION_DEFS_H__
+#define __REGION_DEFS_H__
+
+#include "flash_layout.h"
+
+#define BL2_HEAP_SIZE (0x0001000)
+#define BL2_MSP_STACK_SIZE (0x0001800)
+
+#define S_HEAP_SIZE (0x0000200)
+#define S_MSP_STACK_SIZE_INIT (0x0000400)
+#define S_MSP_STACK_SIZE (0x0000800)
+#define S_PSP_STACK_SIZE (0x0000800)
+
+/* This size of buffer is big enough to store an attestation
+ * token produced by initial attestation service
+ */
+#define PSA_INITIAL_ATTEST_TOKEN_MAX_SIZE (0x250)
+
+#ifndef LINK_TO_SECONDARY_PARTITION
+#define S_IMAGE_PRIMARY_PARTITION_OFFSET (FLASH_AREA_0_OFFSET)
+#define S_IMAGE_SECONDARY_PARTITION_OFFSET (FLASH_AREA_2_OFFSET)
+#else
+#define S_IMAGE_PRIMARY_PARTITION_OFFSET (FLASH_AREA_2_OFFSET)
+#define S_IMAGE_SECONDARY_PARTITION_OFFSET (FLASH_AREA_0_OFFSET)
+#endif /* !LINK_TO_SECONDARY_PARTITION */
+
+#define BL2_HEADER_SIZE (0x400) /* 1 KB */
+#define BL2_TRAILER_SIZE (0x800) /* 2 KB */
+
+#define IMAGE_S_CODE_SIZE \
+ (FLASH_S_PARTITION_SIZE - BL2_HEADER_SIZE - BL2_TRAILER_SIZE)
+
+/* Code SRAM area */
+#define CODE_SRAM_BASE (0x38200000)
+#define CODE_SRAM_SIZE (0x00080000) /* 512 KiB */
+
+/* Reserved area for SSE-200 BL0 */
+#define SSE200_BL0_RAM_BASE CODE_SRAM_BASE
+#define SSE200_BL0_RAM_SIZE (0x00004000) /* 16 KiB */
+
+/* eFlash drivers are copied to Code SRAM in BL2 */
+#define EFLASH_DRIVER_REGION_BASE (SSE200_BL0_RAM_BASE + SSE200_BL0_RAM_SIZE)
+#define EFLASH_DRIVER_REGION_SIZE (0x00004000) /* 16 KiB */
+
+/* Memory area used as shared memory between SSE-200 and SE */
+#define IPC_SHARED_MEMORY_BASE (EFLASH_DRIVER_REGION_BASE + \
+ EFLASH_DRIVER_REGION_SIZE)
+#define IPC_SHARED_MEMORY_SIZE (CODE_SRAM_SIZE - \
+ SSE200_BL0_SIZE - \
+ EFLASH_DRIVER_REGION_SIZE) /* 476 KiB */
+
+/* Secure Enclave internal SRAM */
+#define SRAM_BASE (0x30000000)
+#define SRAM_SIZE (0x00010000) /* 64 KiB */
+
+/* Secure regions */
+#define S_CODE_START (FLASH_BASE_ADDRESS + \
+ S_IMAGE_PRIMARY_PARTITION_OFFSET + \
+ BL2_HEADER_SIZE)
+#define S_CODE_SIZE (IMAGE_S_CODE_SIZE)
+#define S_CODE_LIMIT (S_CODE_START + S_CODE_SIZE - 1)
+
+#define S_DATA_START (SRAM_BASE)
+#define S_DATA_SIZE (SRAM_SIZE)
+#define S_UNPRIV_DATA_SIZE (0x3000)
+#define S_DATA_LIMIT (S_DATA_START + S_DATA_SIZE - 1)
+#define S_DATA_PRIV_START (S_DATA_START + S_UNPRIV_DATA_SIZE)
+
+/* Shared data area between bootloader and runtime firmware.
+ * Shared data area is allocated at the beginning of the privileged data area,
+ * it is overlapping with TF-M Secure code's MSP stack
+ */
+#define BOOT_TFM_SHARED_DATA_BASE (S_DATA_PRIV_START)
+#define BOOT_TFM_SHARED_DATA_SIZE (0x400)
+#define BOOT_TFM_SHARED_DATA_LIMIT (BOOT_TFM_SHARED_DATA_BASE + \
+ BOOT_TFM_SHARED_DATA_SIZE - 1)
+
+/* Whole SSE-200 image treated as Non-secure */
+#ifndef LINK_TO_SECONDARY_PARTITION
+#define NS_IMAGE_PRIMARY_PARTITION_OFFSET (FLASH_AREA_1_OFFSET)
+#else
+#define NS_IMAGE_PRIMARY_PARTITION_OFFSET (FLASH_AREA_3_OFFSET)
+#endif /* !LINK_TO_SECONDARY_PARTITION */
+
+#define NS_PARTITION_START (FLASH_BASE_ADDRESS + \
+ NS_IMAGE_PRIMARY_PARTITION_OFFSET)
+#define NS_PARTITION_SIZE (FLASH_SSE_200_PARTITION_SIZE)
+
+/* The shared memory is treated as NS memory */
+#define NS_DATA_START IPC_SHARED_MEMORY_BASE
+#define NS_DATA_SIZE IPC_SHARED_MEMORY_SIZE
+#define NS_DATA_LIMIT (NS_DATA_START + NS_DATA_SIZE - 1)
+
+#define NS_CODE_START (NS_PARTITION_START)
+#define NS_CODE_SIZE (NS_PARTITION_SIZE)
+#define NS_CODE_LIMIT (NS_CODE_START + NS_CODE_SIZE - 1)
+
+/* Secondary partition for new images in case of firmware upgrade.
+ * This area is reserved for both secondary images. */
+#define SECONDARY_PARTITION_START (S_IMAGE_SECONDARY_PARTITION_OFFSET)
+#define SECONDARY_PARTITION_SIZE (FLASH_S_PARTITION_SIZE + \
+ FLASH_SSE_200_PARTITION_SIZE)
+
+/* Bootloader regions */
+/* ROM remap is mapped to 0x0 in SE */
+#define BL2_CODE_START (0x0)
+#define BL2_CODE_SIZE (FLASH_AREA_BL2_SIZE)
+#define BL2_CODE_LIMIT (BL2_CODE_START + BL2_CODE_SIZE - 1)
+
+#define BL2_DATA_START (S_DATA_START)
+#define BL2_DATA_SIZE (S_DATA_SIZE)
+#define BL2_DATA_LIMIT (BL2_DATA_START + BL2_DATA_SIZE - 1)
+
+
+#endif /* __REGION_DEFS_H__ */
+
diff --git a/platform/ext/target/musca_b1_secure_enclave/preload.cmake b/platform/ext/target/musca_b1_secure_enclave/preload.cmake
new file mode 100644
index 0000000..f334999
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/preload.cmake
@@ -0,0 +1,18 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+# preload.cmake is used to set things that related to the platform that are both
+# immutable and global, which is to say they should apply to any kind of project
+# that uses this plaform. In practise this is normally compiler definitions and
+# variables related to hardware.
+
+# Set architecture and CPU
+set(TFM_SYSTEM_PROCESSOR cortex-m0plus)
+set(TFM_SYSTEM_ARCHITECTURE armv6-m)
+
+# The Musca-B1 Secure Enclave has a CryptoCell-312 as an accelerator.
+set(CRYPTO_HW_ACCELERATOR_TYPE cc312)
diff --git a/platform/ext/target/musca_b1_secure_enclave/preload_ns.cmake b/platform/ext/target/musca_b1_secure_enclave/preload_ns.cmake
new file mode 100644
index 0000000..3b9601f
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/preload_ns.cmake
@@ -0,0 +1,9 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+# Placeholder because of interface include rule when TFM_MULTI_CORE_TOPOLOGY is
+# set.
diff --git a/platform/ext/target/musca_b1_secure_enclave/readme.rst b/platform/ext/target/musca_b1_secure_enclave/readme.rst
new file mode 100644
index 0000000..fa58bf8
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/readme.rst
@@ -0,0 +1,96 @@
+#################################
+Musca-B1 Secure Enclave Specifics
+#################################
+
+************
+Introduction
+************
+
+The Musca-B1 System-on-Chip contains two subsystems:
+
+- SSE-200 subsystem to host the main application.
+- CryptoIsland-300 subsystem can be used as a Secure Enclave (mentioned as *SE*
+ in the document).
+
+If TF-M is built with default configuration to the MUSCA-B1 platform only the
+SSE-200 subsystem used. But if the ``FORWARD_PROT_MSG`` cmake flag is turned
+on, the TF-M instance running on SSE-200 will communicate with the SE.
+
+For more information you can check the
+:doc:`Secure Enclave design document <docs/design_documents/secure_enclave_solution.rst>`.
+
+***********
+System boot
+***********
+
+The desired boot flow would be to start up SE first at power on as SE is the
+Root of Trust in the system, and SSE-200 should be started up by SE. But the
+current Musca-B1 DAPLink FW releases the SSE-200 subsystem from reset first,
+and it would require complex changes to modify this boot order. So an
+additional SSE-200 BL0 component was added to the system to imitate that SE is
+the subsystem started up first.
+
+.. uml::
+
+ @startuml
+
+ title Implemented boot flow
+
+ start
+ :Power On button pressed.;
+ :DAPLink Starts up SSE-200.;
+ :SSE-200 BL0 starts up the SE (through SCC), then enters wait state.;
+ :SE starts to run its MCUBoot image and authenticates all images (SE TF-M
+ image and the combined SSE-200 image). If all images are valid, control jumps
+ to SE’s TF-M image.;
+ :SE's TF-M image starts up, when initialization finishes, SSE-200 is
+ virtually released from reset by sending the start address of the combined
+ SSE-200 image over MHU;
+ :SSE-200 TF-M image starts up and synchronizes with SE over MHU;
+ :SSE-200 and SE are ready to communicate;
+ stop
+
+ @enduml
+
+.. Note::
+
+ Without the SSE-200 BL0 component, the boot flow can be treated as a valid
+ reference solution.
+
+*****
+Build
+*****
+
+To produce all the images, TF-M build needs to be executed twice:
+
+- One build needed to create the SSE-200 images (BL0 and the combined SSE-200
+ image containing TF-M and the non-secure application), target platform needs
+ to be set to ``MUSCA_B1`` and the ``FORWARD_PROT_MSG`` cmake flag also needs
+ to be set.
+- One build needed to create the SE images (MCUBoot and TF-M), target platform
+ needs to be set to ``MUSCA_B1_SECURE_ENCLAVE``.
+
+The order of the two builds is indifferent. The BL2 setting is mandatory for
+both builds, but MCUBoot image is only built for the SE platform.
+
+To create a unified hex file:
+
+- Windows::
+
+ srec_cat.exe TBD
+
+- Linux::
+
+ srec_cat TBD
+
+*****************
+Known limitations
+*****************
+- Musca-B1 Secure Enclave cannot reset the whole SoC, only itself. So if SE
+ does a system reset it will stuck in a state waiting for a handshake signal
+ from SSE-200. (It will never come, as SSE-200 is not reseted in such a
+ situation.)
+
+--------------
+
+*Copyright (c) 2020, Arm Limited. All rights reserved.*
diff --git a/platform/ext/target/musca_b1_secure_enclave/services/src/tfm_platform_system.c b/platform/ext/target/musca_b1_secure_enclave/services/src/tfm_platform_system.c
new file mode 100644
index 0000000..283af84
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/services/src/tfm_platform_system.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "tfm_platform_system.h"
+#include "cmsis.h"
+
+void tfm_platform_hal_system_reset(void)
+{
+ /* Reset the system */
+ NVIC_SystemReset();
+}
+
+enum tfm_platform_err_t tfm_platform_hal_ioctl(tfm_platform_ioctl_req_t request,
+ psa_invec *in_vec,
+ psa_outvec *out_vec)
+{
+ (void)in_vec;
+ (void)out_vec;
+ return TFM_PLATFORM_ERR_NOT_SUPPORTED;
+}
+
diff --git a/platform/ext/target/musca_b1_secure_enclave/spm_hal.c b/platform/ext/target/musca_b1_secure_enclave/spm_hal.c
new file mode 100644
index 0000000..fceb6d1
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/spm_hal.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2020, Cypress Semiconductor Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+
+#include "tfm_spm_hal.h"
+#include "device_definition.h"
+#include "region_defs.h"
+#include "target_cfg.h"
+#include "tfm_multi_core.h"
+#include "platform_multicore.h"
+
+#include "cmsis.h"
+
+/* Declared in target_cfg.c */
+extern const struct memory_region_limits memory_regions;
+
+enum tfm_plat_err_t tfm_spm_hal_init_isolation_hw(void)
+{
+ /* Nothing to do, there is no isolation HW in this platform to be
+ * configured by Secure Enclave */
+ return TFM_PLAT_ERR_SUCCESS;
+}
+
+enum tfm_plat_err_t tfm_spm_hal_configure_default_isolation(
+ uint32_t partition_idx,
+ const struct tfm_spm_partition_platform_data_t *platform_data)
+{
+ /* Nothing to do, there is no isolation HW in this platform to be
+ * configured by Secure Enclave */
+ (void) partition_idx;
+ (void) platform_data;
+ return TFM_PLAT_ERR_SUCCESS;
+}
+
+void tfm_spm_hal_boot_ns_cpu(uintptr_t start_addr)
+{
+ uint32_t translated_address = 0;
+
+ platform_init_mailbox_hw();
+
+ translated_address = (uint32_t) start_addr
+ + 0x1A200000 /* eFlash 1 base from SSE-200's point of view */
+ - 0x38000000 /* eFlash 1 base from SE's point of view */;
+
+ platform_mailbox_send_msg_data(translated_address);
+}
+
+void tfm_spm_hal_wait_for_ns_cpu_ready(void)
+{
+ uint32_t data = 0;
+
+ while (data != IPC_SYNC_MAGIC) {
+ platform_mailbox_wait_for_notify();
+ platform_mailbox_fetch_msg_data(&data);
+ }
+}
+
+enum tfm_plat_err_t tfm_spm_hal_set_secure_irq_priority(IRQn_Type irq_line,
+ uint32_t priority)
+{
+ uint32_t quantized_priority = priority >> (8U - __NVIC_PRIO_BITS);
+ NVIC_SetPriority(irq_line, quantized_priority);
+
+ return TFM_PLAT_ERR_SUCCESS;
+}
+
+void tfm_spm_hal_get_mem_security_attr(const void *p, size_t s,
+ struct security_attr_info_t *p_attr)
+{
+ /* Check static memory layout to get memory attributes */
+ tfm_get_mem_region_security_attr(p, s, p_attr);
+}
+
+void tfm_spm_hal_get_secure_access_attr(const void *p, size_t s,
+ struct mem_attr_info_t *p_attr)
+{
+ /* Check static memory layout to get memory attributes */
+ tfm_get_secure_mem_region_attr(p, s, p_attr);
+
+}
+
+void tfm_spm_hal_get_ns_access_attr(const void *p, size_t s,
+ struct mem_attr_info_t *p_attr)
+{
+ /* Check static memory layout to get memory attributes */
+ tfm_get_ns_mem_region_attr(p, s, p_attr);
+}
+
+enum tfm_plat_err_t tfm_spm_hal_nvic_interrupt_enable(void)
+{
+ /* Nothing to do, mailbox interrupt enabled at mailbox initialization,
+ * no other interrupt source used in Secure Enclave */
+ return TFM_PLAT_ERR_SUCCESS;
+}
+
+void tfm_spm_hal_clear_pending_irq(IRQn_Type irq_line)
+{
+ NVIC_ClearPendingIRQ(irq_line);
+}
+
+void tfm_spm_hal_enable_irq(IRQn_Type irq_line)
+{
+ NVIC_EnableIRQ(irq_line);
+}
+
+void tfm_spm_hal_disable_irq(IRQn_Type irq_line)
+{
+ NVIC_DisableIRQ(irq_line);
+}
+
+enum irq_target_state_t tfm_spm_hal_set_irq_target_state(
+ IRQn_Type irq_line,
+ enum irq_target_state_t target_state)
+{
+ /* Nothing to do, target state of interrupts cannot be set on Armv6-m */
+ (void)irq_line;
+ (void)target_state;
+
+ return TFM_IRQ_TARGET_STATE_SECURE;
+}
+
+enum tfm_plat_err_t tfm_spm_hal_nvic_interrupt_target_state_cfg(void)
+{
+ /* Nothing to do, target state of interrupts cannot be set on Armv6-m */
+ return TFM_PLAT_ERR_SUCCESS;
+}
+
+enum tfm_plat_err_t tfm_spm_hal_enable_fault_handlers(void)
+{
+ /* Nothing to do, fault handlers are not implemented on Armv6-m */
+ return TFM_PLAT_ERR_SUCCESS;
+}
+
+enum tfm_plat_err_t tfm_spm_hal_system_reset_cfg(void)
+{
+ /* Nothing to do, system reset do no require any initialization */
+ return TFM_PLAT_ERR_SUCCESS;
+}
+
+enum tfm_plat_err_t tfm_spm_hal_init_debug(void)
+{
+ /* Nothing to do, no initialization options for the debug subsystem on
+ * Armv6-m */
+ return TFM_PLAT_ERR_SUCCESS;
+}
+
+uint32_t tfm_spm_hal_get_ns_VTOR(void)
+{
+ return memory_regions.non_secure_code_start;
+}
+
+uint32_t tfm_spm_hal_get_ns_entry_point(void)
+{
+ return *((uint32_t *)(memory_regions.non_secure_code_start+ 4));
+}
diff --git a/platform/ext/target/musca_b1_secure_enclave/target_cfg.c b/platform/ext/target/musca_b1_secure_enclave/target_cfg.c
new file mode 100644
index 0000000..c1986ae
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/target_cfg.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018-2020, 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 "target_cfg.h"
+#include "region.h"
+#include "region_defs.h"
+
+REGION_DECLARE(Load$$LR$$, LR_NS_PARTITION, $$Base);
+
+const struct memory_region_limits memory_regions = {
+ .non_secure_code_start =
+ (uint32_t)®ION_NAME(Load$$LR$$, LR_NS_PARTITION, $$Base) +
+ BL2_HEADER_SIZE,
+
+ .non_secure_partition_base =
+ (uint32_t)®ION_NAME(Load$$LR$$, LR_NS_PARTITION, $$Base),
+
+ .non_secure_partition_limit =
+ (uint32_t)®ION_NAME(Load$$LR$$, LR_NS_PARTITION, $$Base) +
+ NS_PARTITION_SIZE - 1,
+};
diff --git a/platform/ext/target/musca_b1_secure_enclave/target_cfg.h b/platform/ext/target/musca_b1_secure_enclave/target_cfg.h
new file mode 100644
index 0000000..eccde58
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/target_cfg.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018-2020, 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.
+ */
+
+#ifndef __TARGET_CFG_H__
+#define __TARGET_CFG_H__
+
+/**
+ * \brief Store the addresses of memory regions
+ */
+
+#include <stdint.h>
+
+struct memory_region_limits {
+ uint32_t non_secure_code_start;
+ uint32_t non_secure_partition_base;
+ uint32_t non_secure_partition_limit;
+};
+#endif /* __TARGET_CFG_H__ */
diff --git a/platform/ext/target/musca_b1_secure_enclave/tfm_hal_isolation.c b/platform/ext/target/musca_b1_secure_enclave/tfm_hal_isolation.c
new file mode 100644
index 0000000..e120795
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/tfm_hal_isolation.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "tfm_api.h"
+#include "tfm_hal_defs.h"
+#include "tfm_multi_core.h"
+
+enum tfm_hal_status_t tfm_hal_set_up_static_boundaries(void)
+{
+ /* Nothing to do, there is no isolation HW in this platform to be
+ * configured by Secure Enclave */
+ return TFM_HAL_SUCCESS;
+}
+
+enum tfm_hal_status_t tfm_hal_memory_has_access(uintptr_t base,
+ size_t size,
+ uint32_t attr)
+{
+ enum tfm_status_e status;
+
+ status = tfm_has_access_to_region((const void *)base, size, attr);
+ if (status != TFM_SUCCESS) {
+ return TFM_HAL_ERROR_MEM_FAULT;
+ }
+
+ return TFM_HAL_SUCCESS;
+}
diff --git a/platform/ext/target/musca_b1_secure_enclave/tfm_peripherals_def.h b/platform/ext/target/musca_b1_secure_enclave/tfm_peripherals_def.h
new file mode 100644
index 0000000..6775553
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/tfm_peripherals_def.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020, Cypress Semiconductor Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_PERIPHERALS_DEF_H__
+#define __TFM_PERIPHERALS_DEF_H__
+
+#include "cmsis.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Empty header needed for compilation */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_PERIPHERALS_DEF_H__ */
diff --git a/platform/ext/target/musca_b1_secure_enclave/uart_stdout.c b/platform/ext/target/musca_b1_secure_enclave/uart_stdout.c
new file mode 100644
index 0000000..48ef7b9
--- /dev/null
+++ b/platform/ext/target/musca_b1_secure_enclave/uart_stdout.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
+ *
+ * Licensed under the Apace 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.apace.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 "uart_stdout.h"
+#include <stdio.h>
+
+int stdio_output_string(const unsigned char *str, uint32_t len)
+{
+ /* Nothing to do as there is no serial output */
+ (void)str;
+ return len;
+}
+
+/* Redirects printf to STDIO_DRIVER in case of ARMCLANG*/
+#if defined(__ARMCC_VERSION)
+/* Struct FILE is implemented in stdio.h. Used to redirect printf to
+ * STDIO_DRIVER
+ */
+FILE __stdout;
+/* __ARMCC_VERSION is only defined starting from Arm compiler version 6 */
+int fputc(int ch, FILE *f)
+{
+ (void)f;
+
+ /* Send byte to USART */
+ (void)stdio_output_string((const unsigned char *)&ch, 1);
+
+ /* Return character written */
+ return ch;
+}
+#elif defined(__GNUC__)
+/* Redirects printf to STDIO_DRIVER in case of GNUARM */
+int _write(int fd, char *str, int len)
+{
+ (void)fd;
+
+ /* Send string and return the number of characters written */
+ return stdio_output_string((const unsigned char *)str, (uint32_t)len);
+}
+#elif defined(__ICCARM__)
+int putchar(int ch)
+{
+ /* Send byte to USART */
+ (void)stdio_output_string((const unsigned char *)&ch, 1);
+
+ /* Return character written */
+ return ch;
+}
+#endif
+
+void stdio_init(void)
+{
+ /* Nothing to do as there is no serial output */
+}
+
+void stdio_uninit(void)
+{
+ /* Nothing to do as there is no serial output */
+}