text: /*
   * Copyright (c) 2013-2019 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 "RTE_Device.h"
  
  #ifndef ARG_UNUSED
  #define ARG_UNUSED(arg)  ((void)arg)
  #endif
  
  #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 */
  
  /* Driver version */
  #define ARM_FLASH_DRV_VERSION      ARM_DRIVER_VERSION_MAJOR_MINOR(1, 1)
  #define ARM_FLASH_DRV_ERASE_VALUE  0xFF
  
  /*
   * ARM FLASH device structure
   *
   * 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;
  }
  
  static int32_t is_flash_ready_to_write(const uint8_t *start_addr, uint32_t cnt)
  {
      int32_t rc = 0;
      uint32_t i;
  
      for (i = 0; i < cnt; i++) {
          if(start_addr[i] != ARM_FLASH_DRV_ERASE_VALUE) {
              rc = -1;
              break;
          }
      }
  
      return rc;
  }
  
  #if (RTE_FLASH0)
  static ARM_FLASH_INFO ARM_FLASH0_DEV_DATA = {
      .sector_info  = NULL,                  /* Uniform sector layout */
      .sector_count = FLASH0_SIZE / FLASH0_SECTOR_SIZE,
      .sector_size  = FLASH0_SECTOR_SIZE,
      .page_size    = FLASH0_PAGE_SIZE,
      .program_unit = FLASH0_PROGRAM_UNIT,
      .erased_value = ARM_FLASH_DRV_ERASE_VALUE};
  
  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;
      }
  
      /* Check if the flash area to write the data was erased previously */
      rc = is_flash_ready_to_write((const uint8_t*)start_addr, cnt);
      if (rc != 0) {
          return ARM_DRIVER_ERROR;
      }
  
      /* 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 */
  