Platform: implement CMSIS flash driver on MPS2

CMSIS compliant flash driver on MPS2:
 -- There is no flash memory on MPS2. Code runs from SRAM.
 -- Implement a CMSIS compliant flash driver which
    emulates flash interface and behaviour over code SRAM.
 -- Supported platforms: AN521 and AN519

Imported files from CMSIS_5:
 -- platform/ext/driver/Driver_Flash.h; tag:5.2.0

Change-Id: I7903bf78abcc736c32732750ccc12ae8592805e4
Signed-off-by: Tamas Ban <tamas.ban@arm.com>
diff --git a/platform/ext/driver/Driver_Flash.h b/platform/ext/driver/Driver_Flash.h
new file mode 100644
index 0000000..287add1
--- /dev/null
+++ b/platform/ext/driver/Driver_Flash.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2013-2017 ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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
+ *
+ * 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.
+ *
+ * $Date:        2. Feb 2017
+ * $Revision:    V2.1
+ *
+ * Project:      Flash Driver definitions
+ */
+
+/* History:
+ *  Version 2.1
+ *    ARM_FLASH_STATUS made volatile
+ *  Version 2.0
+ *    Renamed driver NOR -> Flash (more generic)
+ *    Non-blocking operation
+ *    Added Events, Status and Capabilities
+ *    Linked Flash information (GetInfo)
+ *  Version 1.11
+ *    Changed prefix ARM_DRV -> ARM_DRIVER
+ *  Version 1.10
+ *    Namespace prefix ARM_ added
+ *  Version 1.00
+ *    Initial release
+ */
+
+#ifndef DRIVER_FLASH_H_
+#define DRIVER_FLASH_H_
+
+#ifdef  __cplusplus
+extern "C"
+{
+#endif
+
+#include "Driver_Common.h"
+
+#define ARM_FLASH_API_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(2,1)  /* API version */
+
+
+#define _ARM_Driver_Flash_(n)      Driver_Flash##n
+#define  ARM_Driver_Flash_(n) _ARM_Driver_Flash_(n)
+
+
+#define ARM_FLASH_SECTOR_INFO(addr,size) { (addr), (addr)+(size)-1 }
+
+/**
+\brief Flash Sector information
+*/
+typedef struct _ARM_FLASH_SECTOR {
+  uint32_t start;                       ///< Sector Start address
+  uint32_t end;                         ///< Sector End address (start+size-1)
+} const ARM_FLASH_SECTOR;
+
+/**
+\brief Flash information
+*/
+typedef struct _ARM_FLASH_INFO {
+  ARM_FLASH_SECTOR *sector_info;        ///< Sector layout information (NULL=Uniform sectors)
+  uint32_t          sector_count;       ///< Number of sectors
+  uint32_t          sector_size;        ///< Uniform sector size in bytes (0=sector_info used) 
+  uint32_t          page_size;          ///< Optimal programming page size in bytes
+  uint32_t          program_unit;       ///< Smallest programmable unit in bytes
+  uint8_t           erased_value;       ///< Contents of erased memory (usually 0xFF)
+} const ARM_FLASH_INFO;
+
+
+/**
+\brief Flash Status
+*/
+typedef volatile struct _ARM_FLASH_STATUS {
+  uint32_t busy     : 1;                ///< Flash busy flag
+  uint32_t error    : 1;                ///< Read/Program/Erase error flag (cleared on start of next operation)
+  uint32_t reserved : 30;
+} ARM_FLASH_STATUS;
+
+
+/****** Flash Event *****/
+#define ARM_FLASH_EVENT_READY           (1UL << 0)  ///< Flash Ready
+#define ARM_FLASH_EVENT_ERROR           (1UL << 1)  ///< Read/Program/Erase Error
+
+
+// Function documentation
+/**
+  \fn          ARM_DRIVER_VERSION ARM_Flash_GetVersion (void)
+  \brief       Get driver version.
+  \return      \ref ARM_DRIVER_VERSION
+*/
+/**
+  \fn          ARM_FLASH_CAPABILITIES ARM_Flash_GetCapabilities (void)
+  \brief       Get driver capabilities.
+  \return      \ref ARM_FLASH_CAPABILITIES
+*/
+/**
+  \fn          int32_t ARM_Flash_Initialize (ARM_Flash_SignalEvent_t cb_event)
+  \brief       Initialize the Flash Interface.
+  \param[in]   cb_event  Pointer to \ref ARM_Flash_SignalEvent
+  \return      \ref execution_status
+*/
+/**
+  \fn          int32_t ARM_Flash_Uninitialize (void)
+  \brief       De-initialize the Flash Interface.
+  \return      \ref execution_status
+*/
+/**
+  \fn          int32_t ARM_Flash_PowerControl (ARM_POWER_STATE state)
+  \brief       Control the Flash interface power.
+  \param[in]   state  Power state
+  \return      \ref execution_status
+*/
+/**
+  \fn          int32_t ARM_Flash_ReadData (uint32_t addr, void *data, uint32_t cnt)
+  \brief       Read data from Flash.
+  \param[in]   addr  Data address.
+  \param[out]  data  Pointer to a buffer storing the data read from Flash.
+  \param[in]   cnt   Number of data items to read.
+  \return      number of data items read or \ref execution_status
+*/
+/**
+  \fn          int32_t ARM_Flash_ProgramData (uint32_t addr, const void *data, uint32_t cnt)
+  \brief       Program data to Flash.
+  \param[in]   addr  Data address.
+  \param[in]   data  Pointer to a buffer containing the data to be programmed to Flash.
+  \param[in]   cnt   Number of data items to program.
+  \return      number of data items programmed or \ref execution_status
+*/
+/**
+  \fn          int32_t ARM_Flash_EraseSector (uint32_t addr)
+  \brief       Erase Flash Sector.
+  \param[in]   addr  Sector address
+  \return      \ref execution_status
+*/
+/**
+  \fn          int32_t ARM_Flash_EraseChip (void)
+  \brief       Erase complete Flash.
+               Optional function for faster full chip erase.
+  \return      \ref execution_status
+*/
+/**
+  \fn          ARM_FLASH_STATUS ARM_Flash_GetStatus (void)
+  \brief       Get Flash status.
+  \return      Flash status \ref ARM_FLASH_STATUS
+*/
+/**
+  \fn          ARM_FLASH_INFO * ARM_Flash_GetInfo (void)
+  \brief       Get Flash information.
+  \return      Pointer to Flash information \ref ARM_FLASH_INFO
+*/
+
+/**
+  \fn          void ARM_Flash_SignalEvent (uint32_t event)
+  \brief       Signal Flash event.
+  \param[in]   event  Event notification mask
+  \return      none
+*/
+
+typedef void (*ARM_Flash_SignalEvent_t) (uint32_t event);    ///< Pointer to \ref ARM_Flash_SignalEvent : Signal Flash Event.
+
+
+/**
+\brief Flash Driver Capabilities.
+*/
+typedef struct _ARM_FLASH_CAPABILITIES {
+  uint32_t event_ready  : 1;            ///< Signal Flash Ready event
+  uint32_t data_width   : 2;            ///< Data width: 0=8-bit, 1=16-bit, 2=32-bit
+  uint32_t erase_chip   : 1;            ///< Supports EraseChip operation
+  uint32_t reserved     : 28;           ///< Reserved (must be zero)
+} ARM_FLASH_CAPABILITIES;
+
+
+/**
+\brief Access structure of the Flash Driver
+*/
+typedef struct _ARM_DRIVER_FLASH {
+  ARM_DRIVER_VERSION     (*GetVersion)     (void);                                          ///< Pointer to \ref ARM_Flash_GetVersion : Get driver version.
+  ARM_FLASH_CAPABILITIES (*GetCapabilities)(void);                                          ///< Pointer to \ref ARM_Flash_GetCapabilities : Get driver capabilities.
+  int32_t                (*Initialize)     (ARM_Flash_SignalEvent_t cb_event);              ///< Pointer to \ref ARM_Flash_Initialize : Initialize Flash Interface.
+  int32_t                (*Uninitialize)   (void);                                          ///< Pointer to \ref ARM_Flash_Uninitialize : De-initialize Flash Interface.
+  int32_t                (*PowerControl)   (ARM_POWER_STATE state);                         ///< Pointer to \ref ARM_Flash_PowerControl : Control Flash Interface Power.
+  int32_t                (*ReadData)       (uint32_t addr,       void *data, uint32_t cnt); ///< Pointer to \ref ARM_Flash_ReadData : Read data from Flash.
+  int32_t                (*ProgramData)    (uint32_t addr, const void *data, uint32_t cnt); ///< Pointer to \ref ARM_Flash_ProgramData : Program data to Flash.
+  int32_t                (*EraseSector)    (uint32_t addr);                                 ///< Pointer to \ref ARM_Flash_EraseSector : Erase Flash Sector.
+  int32_t                (*EraseChip)      (void);                                          ///< Pointer to \ref ARM_Flash_EraseChip : Erase complete Flash.
+  ARM_FLASH_STATUS       (*GetStatus)      (void);                                          ///< Pointer to \ref ARM_Flash_GetStatus : Get Flash status.
+  ARM_FLASH_INFO *       (*GetInfo)        (void);                                          ///< Pointer to \ref ARM_Flash_GetInfo : Get Flash information.
+} const ARM_DRIVER_FLASH;
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* DRIVER_FLASH_H_ */
diff --git a/platform/ext/target/mps2/an519/RTE_Device.h b/platform/ext/target/mps2/an519/RTE_Device.h
index 860a49f..3eef147 100644
--- a/platform/ext/target/mps2/an519/RTE_Device.h
+++ b/platform/ext/target/mps2/an519/RTE_Device.h
@@ -89,6 +89,11 @@
 #define   RTE_USART4                     0
 // </e> USART (Universal synchronous - asynchronous receiver transmitter) [Driver_USART4]
 
+// <e> FLASH (Flash Memory) [Driver_FLASH0]
+// <i> Configuration settings for Driver_FLASH0 in component ::Drivers:FLASH
+#define   RTE_FLASH0                     1
+// </e> FLASH (Flash Memory) [Driver_FLASH0]
+
 // <e> MPC (Memory Protection Controller) [Driver_ISRAM0_MPC]
 // <i> Configuration settings for Driver_ISRAM0_MPC in component ::Drivers:MPC
 #define   RTE_ISRAM0_MPC                 0
diff --git a/platform/ext/target/mps2/an519/cmsis_drivers/Driver_Flash.c b/platform/ext/target/mps2/an519/cmsis_drivers/Driver_Flash.c
new file mode 100644
index 0000000..fb6f448
--- /dev/null
+++ b/platform/ext/target/mps2/an519/cmsis_drivers/Driver_Flash.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2013-2018 ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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
+ *
+ * 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 <string.h>
+#include <stdint.h>
+#include "Driver_Flash.h"
+#include "platform_retarget.h"
+#include "RTE_Device.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)
+
+/*
+ * ARM FLASH device structure
+ *
+ * There is no real flash memory for code on MPS2 board. Instead a code SRAM is
+ * used for code storage: ZBT SSRAM1. This driver just emulates a flash
+ * interface and behaviour on top of the SRAM memory.
+ */
+struct arm_flash_dev_t {
+    const uint32_t memory_base;   /*!< FLASH memory base address */
+    ARM_FLASH_INFO *data;         /*!< FLASH data */
+};
+
+/* Flash Status */
+static ARM_FLASH_STATUS FlashStatus = {0, 0, 0};
+
+/* Driver Version */
+static const ARM_DRIVER_VERSION DriverVersion = {
+    ARM_FLASH_API_VERSION,
+    ARM_FLASH_DRV_VERSION
+};
+
+/* Driver Capabilities */
+static const ARM_FLASH_CAPABILITIES DriverCapabilities = {
+    0, /* event_ready */
+    2, /* data_width = 0:8-bit, 1:16-bit, 2:32-bit */
+    1  /* erase_chip */
+};
+
+static int32_t is_range_valid(struct arm_flash_dev_t *flash_dev,
+                              uint32_t offset)
+{
+    uint32_t flash_limit = 0;
+    int32_t rc = 0;
+
+    flash_limit = (flash_dev->data->sector_count * flash_dev->data->sector_size)
+                   - 1;
+
+    if (offset > flash_limit) {
+        rc = -1;
+    }
+    return rc;
+}
+
+static int32_t is_write_aligned(struct arm_flash_dev_t *flash_dev,
+                                uint32_t param)
+{
+    int32_t rc = 0;
+
+    if ((param % flash_dev->data->program_unit) != 0) {
+        rc = -1;
+    }
+    return rc;
+}
+
+static int32_t is_sector_aligned(struct arm_flash_dev_t *flash_dev,
+                                 uint32_t offset)
+{
+    int32_t rc = 0;
+
+    if ((offset % flash_dev->data->sector_size) != 0) {
+        rc = -1;
+    }
+    return rc;
+}
+
+#if (RTE_FLASH0)
+static ARM_FLASH_INFO ARM_FLASH0_DEV_DATA = {
+    .sector_info  = NULL,                  /* Uniform sector layout */
+    .sector_count = FLASH0_SIZE / FLASH0_SECTOR_SIZE,
+    .sector_size  = FLASH0_SECTOR_SIZE,
+    .page_size    = FLASH0_PAGE_SIZE,
+    .program_unit = FLASH0_PROGRAM_UNIT,
+    .erased_value = 0xFF};
+
+static struct arm_flash_dev_t ARM_FLASH0_DEV = {
+#if (__DOMAIN_NS == 1)
+    .memory_base = FLASH0_BASE_NS,
+#else
+    .memory_base = FLASH0_BASE_S,
+#endif /* __DOMAIN_NS == 1 */
+    .data        = &(ARM_FLASH0_DEV_DATA)};
+
+struct arm_flash_dev_t *FLASH0_DEV = &ARM_FLASH0_DEV;
+
+/*
+ * Functions
+ */
+
+static ARM_DRIVER_VERSION ARM_Flash_GetVersion(void)
+{
+    return DriverVersion;
+}
+
+static ARM_FLASH_CAPABILITIES ARM_Flash_GetCapabilities(void)
+{
+    return DriverCapabilities;
+}
+
+static int32_t ARM_Flash_Initialize(ARM_Flash_SignalEvent_t cb_event)
+{
+    ARG_UNUSED(cb_event);
+    /* Nothing to be done */
+    return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flash_Uninitialize(void)
+{
+    /* Nothing to be done */
+    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;
+        break;
+
+    case ARM_POWER_OFF:
+    case ARM_POWER_LOW:
+    default:
+        return ARM_DRIVER_ERROR_UNSUPPORTED;
+    }
+}
+
+static int32_t ARM_Flash_ReadData(uint32_t addr, void *data, uint32_t cnt)
+{
+    uint32_t start_addr = FLASH0_DEV->memory_base + addr;
+    int32_t rc = 0;
+
+    /* Check flash memory boundaries */
+    rc = is_range_valid(FLASH0_DEV, addr + cnt);
+    if (rc != 0) {
+        return ARM_DRIVER_ERROR_PARAMETER;
+    }
+
+    /* Flash interface just emulated over SRAM, use memcpy */
+    memcpy(data, (void *)start_addr, cnt);
+    return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flash_ProgramData(uint32_t addr, const void *data, uint32_t cnt)
+{
+    uint32_t start_addr = FLASH0_DEV->memory_base + addr;
+    int32_t rc = 0;
+
+    /* Check flash memory boundaries and alignment with minimal write size */
+    rc  = is_range_valid(FLASH0_DEV, addr + cnt);
+    rc |= is_write_aligned(FLASH0_DEV, addr);
+    rc |= is_write_aligned(FLASH0_DEV, cnt);
+    if (rc != 0) {
+        return ARM_DRIVER_ERROR_PARAMETER;
+    }
+
+    /* Flash interface just emulated over SRAM, use memcpy */
+    memcpy((void *)start_addr, data, cnt);
+    return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flash_EraseSector(uint32_t addr)
+{
+    uint32_t start_addr = FLASH0_DEV->memory_base + addr;
+    uint32_t rc = 0;
+
+    rc  = is_range_valid(FLASH0_DEV, addr);
+    rc |= is_sector_aligned(FLASH0_DEV, addr);
+    if (rc != 0) {
+        return ARM_DRIVER_ERROR_PARAMETER;
+    }
+
+    /* Flash interface just emulated over SRAM, use memset */
+    memset((void *)start_addr,
+           FLASH0_DEV->data->erased_value,
+           FLASH0_DEV->data->sector_size);
+    return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flash_EraseChip(void)
+{
+    uint32_t i;
+    uint32_t addr = FLASH0_DEV->memory_base;
+    int32_t rc = ARM_DRIVER_ERROR_UNSUPPORTED;
+
+    /* Check driver capability erase_chip bit */
+    if (DriverCapabilities.erase_chip == 1) {
+        for (i = 0; i < FLASH0_DEV->data->sector_count; i++) {
+            /* Flash interface just emulated over SRAM, use memset */
+            memset((void *)addr,
+                   FLASH0_DEV->data->erased_value,
+                   FLASH0_DEV->data->sector_size);
+
+            addr += FLASH0_DEV->data->sector_size;
+            rc = ARM_DRIVER_OK;
+        }
+    }
+    return rc;
+}
+
+static ARM_FLASH_STATUS ARM_Flash_GetStatus(void)
+{
+    return FlashStatus;
+}
+
+static ARM_FLASH_INFO * ARM_Flash_GetInfo(void)
+{
+    return FLASH0_DEV->data;
+}
+
+ARM_DRIVER_FLASH Driver_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_FLASH0 */
diff --git a/platform/ext/target/mps2/an519/retarget/platform_retarget.h b/platform/ext/target/mps2/an519/retarget/platform_retarget.h
index 60b3001..aeed376 100644
--- a/platform/ext/target/mps2/an519/retarget/platform_retarget.h
+++ b/platform/ext/target/mps2/an519/retarget/platform_retarget.h
@@ -110,4 +110,12 @@
 #define MPC_CODE_SRAM3_RANGE_BASE_S    0x38200000
 #define MPC_CODE_SRAM3_RANGE_LIMIT_S   0x383FFFFF
 
+/* Flash memory emulated over external SSRAM memory */
+#define FLASH0_BASE_S                  0x10000000
+#define FLASH0_BASE_NS                 0x00000000
+#define FLASH0_SIZE                    0x00400000  /* 4 MB */
+#define FLASH0_SECTOR_SIZE             0x00001000  /* 4 kB */
+#define FLASH0_PAGE_SIZE               0x00001000  /* 4 kB */
+#define FLASH0_PROGRAM_UNIT            0x1         /* Minimum write size */
+
 #endif  /* __ARM_LTD_AN519_RETARGET_H__ */
diff --git a/platform/ext/target/mps2/an521/RTE_Device.h b/platform/ext/target/mps2/an521/RTE_Device.h
index 860a49f..3eef147 100644
--- a/platform/ext/target/mps2/an521/RTE_Device.h
+++ b/platform/ext/target/mps2/an521/RTE_Device.h
@@ -89,6 +89,11 @@
 #define   RTE_USART4                     0
 // </e> USART (Universal synchronous - asynchronous receiver transmitter) [Driver_USART4]
 
+// <e> FLASH (Flash Memory) [Driver_FLASH0]
+// <i> Configuration settings for Driver_FLASH0 in component ::Drivers:FLASH
+#define   RTE_FLASH0                     1
+// </e> FLASH (Flash Memory) [Driver_FLASH0]
+
 // <e> MPC (Memory Protection Controller) [Driver_ISRAM0_MPC]
 // <i> Configuration settings for Driver_ISRAM0_MPC in component ::Drivers:MPC
 #define   RTE_ISRAM0_MPC                 0
diff --git a/platform/ext/target/mps2/an521/cmsis_drivers/Driver_Flash.c b/platform/ext/target/mps2/an521/cmsis_drivers/Driver_Flash.c
new file mode 100644
index 0000000..fb6f448
--- /dev/null
+++ b/platform/ext/target/mps2/an521/cmsis_drivers/Driver_Flash.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2013-2018 ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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
+ *
+ * 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 <string.h>
+#include <stdint.h>
+#include "Driver_Flash.h"
+#include "platform_retarget.h"
+#include "RTE_Device.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)
+
+/*
+ * ARM FLASH device structure
+ *
+ * There is no real flash memory for code on MPS2 board. Instead a code SRAM is
+ * used for code storage: ZBT SSRAM1. This driver just emulates a flash
+ * interface and behaviour on top of the SRAM memory.
+ */
+struct arm_flash_dev_t {
+    const uint32_t memory_base;   /*!< FLASH memory base address */
+    ARM_FLASH_INFO *data;         /*!< FLASH data */
+};
+
+/* Flash Status */
+static ARM_FLASH_STATUS FlashStatus = {0, 0, 0};
+
+/* Driver Version */
+static const ARM_DRIVER_VERSION DriverVersion = {
+    ARM_FLASH_API_VERSION,
+    ARM_FLASH_DRV_VERSION
+};
+
+/* Driver Capabilities */
+static const ARM_FLASH_CAPABILITIES DriverCapabilities = {
+    0, /* event_ready */
+    2, /* data_width = 0:8-bit, 1:16-bit, 2:32-bit */
+    1  /* erase_chip */
+};
+
+static int32_t is_range_valid(struct arm_flash_dev_t *flash_dev,
+                              uint32_t offset)
+{
+    uint32_t flash_limit = 0;
+    int32_t rc = 0;
+
+    flash_limit = (flash_dev->data->sector_count * flash_dev->data->sector_size)
+                   - 1;
+
+    if (offset > flash_limit) {
+        rc = -1;
+    }
+    return rc;
+}
+
+static int32_t is_write_aligned(struct arm_flash_dev_t *flash_dev,
+                                uint32_t param)
+{
+    int32_t rc = 0;
+
+    if ((param % flash_dev->data->program_unit) != 0) {
+        rc = -1;
+    }
+    return rc;
+}
+
+static int32_t is_sector_aligned(struct arm_flash_dev_t *flash_dev,
+                                 uint32_t offset)
+{
+    int32_t rc = 0;
+
+    if ((offset % flash_dev->data->sector_size) != 0) {
+        rc = -1;
+    }
+    return rc;
+}
+
+#if (RTE_FLASH0)
+static ARM_FLASH_INFO ARM_FLASH0_DEV_DATA = {
+    .sector_info  = NULL,                  /* Uniform sector layout */
+    .sector_count = FLASH0_SIZE / FLASH0_SECTOR_SIZE,
+    .sector_size  = FLASH0_SECTOR_SIZE,
+    .page_size    = FLASH0_PAGE_SIZE,
+    .program_unit = FLASH0_PROGRAM_UNIT,
+    .erased_value = 0xFF};
+
+static struct arm_flash_dev_t ARM_FLASH0_DEV = {
+#if (__DOMAIN_NS == 1)
+    .memory_base = FLASH0_BASE_NS,
+#else
+    .memory_base = FLASH0_BASE_S,
+#endif /* __DOMAIN_NS == 1 */
+    .data        = &(ARM_FLASH0_DEV_DATA)};
+
+struct arm_flash_dev_t *FLASH0_DEV = &ARM_FLASH0_DEV;
+
+/*
+ * Functions
+ */
+
+static ARM_DRIVER_VERSION ARM_Flash_GetVersion(void)
+{
+    return DriverVersion;
+}
+
+static ARM_FLASH_CAPABILITIES ARM_Flash_GetCapabilities(void)
+{
+    return DriverCapabilities;
+}
+
+static int32_t ARM_Flash_Initialize(ARM_Flash_SignalEvent_t cb_event)
+{
+    ARG_UNUSED(cb_event);
+    /* Nothing to be done */
+    return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flash_Uninitialize(void)
+{
+    /* Nothing to be done */
+    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;
+        break;
+
+    case ARM_POWER_OFF:
+    case ARM_POWER_LOW:
+    default:
+        return ARM_DRIVER_ERROR_UNSUPPORTED;
+    }
+}
+
+static int32_t ARM_Flash_ReadData(uint32_t addr, void *data, uint32_t cnt)
+{
+    uint32_t start_addr = FLASH0_DEV->memory_base + addr;
+    int32_t rc = 0;
+
+    /* Check flash memory boundaries */
+    rc = is_range_valid(FLASH0_DEV, addr + cnt);
+    if (rc != 0) {
+        return ARM_DRIVER_ERROR_PARAMETER;
+    }
+
+    /* Flash interface just emulated over SRAM, use memcpy */
+    memcpy(data, (void *)start_addr, cnt);
+    return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flash_ProgramData(uint32_t addr, const void *data, uint32_t cnt)
+{
+    uint32_t start_addr = FLASH0_DEV->memory_base + addr;
+    int32_t rc = 0;
+
+    /* Check flash memory boundaries and alignment with minimal write size */
+    rc  = is_range_valid(FLASH0_DEV, addr + cnt);
+    rc |= is_write_aligned(FLASH0_DEV, addr);
+    rc |= is_write_aligned(FLASH0_DEV, cnt);
+    if (rc != 0) {
+        return ARM_DRIVER_ERROR_PARAMETER;
+    }
+
+    /* Flash interface just emulated over SRAM, use memcpy */
+    memcpy((void *)start_addr, data, cnt);
+    return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flash_EraseSector(uint32_t addr)
+{
+    uint32_t start_addr = FLASH0_DEV->memory_base + addr;
+    uint32_t rc = 0;
+
+    rc  = is_range_valid(FLASH0_DEV, addr);
+    rc |= is_sector_aligned(FLASH0_DEV, addr);
+    if (rc != 0) {
+        return ARM_DRIVER_ERROR_PARAMETER;
+    }
+
+    /* Flash interface just emulated over SRAM, use memset */
+    memset((void *)start_addr,
+           FLASH0_DEV->data->erased_value,
+           FLASH0_DEV->data->sector_size);
+    return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_Flash_EraseChip(void)
+{
+    uint32_t i;
+    uint32_t addr = FLASH0_DEV->memory_base;
+    int32_t rc = ARM_DRIVER_ERROR_UNSUPPORTED;
+
+    /* Check driver capability erase_chip bit */
+    if (DriverCapabilities.erase_chip == 1) {
+        for (i = 0; i < FLASH0_DEV->data->sector_count; i++) {
+            /* Flash interface just emulated over SRAM, use memset */
+            memset((void *)addr,
+                   FLASH0_DEV->data->erased_value,
+                   FLASH0_DEV->data->sector_size);
+
+            addr += FLASH0_DEV->data->sector_size;
+            rc = ARM_DRIVER_OK;
+        }
+    }
+    return rc;
+}
+
+static ARM_FLASH_STATUS ARM_Flash_GetStatus(void)
+{
+    return FlashStatus;
+}
+
+static ARM_FLASH_INFO * ARM_Flash_GetInfo(void)
+{
+    return FLASH0_DEV->data;
+}
+
+ARM_DRIVER_FLASH Driver_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_FLASH0 */
diff --git a/platform/ext/target/mps2/an521/retarget/platform_retarget.h b/platform/ext/target/mps2/an521/retarget/platform_retarget.h
index f62d507..9c93895 100644
--- a/platform/ext/target/mps2/an521/retarget/platform_retarget.h
+++ b/platform/ext/target/mps2/an521/retarget/platform_retarget.h
@@ -132,4 +132,12 @@
 #define MPC_CODE_SRAM3_RANGE_BASE_S    0x38200000
 #define MPC_CODE_SRAM3_RANGE_LIMIT_S   0x383FFFFF
 
+/* Flash memory emulated over external SSRAM memory */
+#define FLASH0_BASE_S                  0x10000000
+#define FLASH0_BASE_NS                 0x00000000
+#define FLASH0_SIZE                    0x00400000  /* 4 MB */
+#define FLASH0_SECTOR_SIZE             0x00001000  /* 4 kB */
+#define FLASH0_PAGE_SIZE               0x00001000  /* 4 kB */
+#define FLASH0_PROGRAM_UNIT            0x1         /* Minimum write size */
+
 #endif  /* __ARM_LTD_AN521_RETARGET_H__ */