| /* |
| * Copyright (c) 2019-2020, Arm Limited. All rights reserved. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| * |
| */ |
| |
| #include <stdbool.h> |
| #include "target.h" |
| #include "flash_map/flash_map.h" |
| #include "flash_map_backend/flash_map_backend.h" |
| #include "bootutil/bootutil_log.h" |
| #include "Driver_Flash.h" |
| |
| /* When undefined FLASH_DEV_NAME_0 or FLASH_DEVICE_ID_0 , default */ |
| #if !defined(FLASH_DEV_NAME_0) || !defined(FLASH_DEVICE_ID_0) |
| #define FLASH_DEV_NAME_0 FLASH_DEV_NAME |
| #define FLASH_DEVICE_ID_0 FLASH_DEVICE_ID |
| #endif |
| |
| /* When undefined FLASH_DEV_NAME_1 or FLASH_DEVICE_ID_1 , default */ |
| #if !defined(FLASH_DEV_NAME_1) || !defined(FLASH_DEVICE_ID_1) |
| #define FLASH_DEV_NAME_1 FLASH_DEV_NAME |
| #define FLASH_DEVICE_ID_1 FLASH_DEVICE_ID |
| #endif |
| |
| /* When undefined FLASH_DEV_NAME_2 or FLASH_DEVICE_ID_2 , default */ |
| #if !defined(FLASH_DEV_NAME_2) || !defined(FLASH_DEVICE_ID_2) |
| #define FLASH_DEV_NAME_2 FLASH_DEV_NAME |
| #define FLASH_DEVICE_ID_2 FLASH_DEVICE_ID |
| #endif |
| |
| /* When undefined FLASH_DEV_NAME_3 or FLASH_DEVICE_ID_3 , default */ |
| #if !defined(FLASH_DEV_NAME_3) || !defined(FLASH_DEVICE_ID_3) |
| #define FLASH_DEV_NAME_3 FLASH_DEV_NAME |
| #define FLASH_DEVICE_ID_3 FLASH_DEVICE_ID |
| #endif |
| |
| /* When undefined FLASH_DEV_NAME_SCRATCH or FLASH_DEVICE_ID_SCRATCH , default */ |
| #if !defined(FLASH_DEV_NAME_SCRATCH) || !defined(FLASH_DEVICE_ID_SCRATCH) |
| #define FLASH_DEV_NAME_SCRATCH FLASH_DEV_NAME |
| #define FLASH_DEVICE_ID_SCRATCH FLASH_DEVICE_ID |
| #endif |
| |
| #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof((arr)[0])) |
| |
| /* Flash device names must be specified by target */ |
| extern ARM_DRIVER_FLASH FLASH_DEV_NAME_0; |
| extern ARM_DRIVER_FLASH FLASH_DEV_NAME_1; |
| extern ARM_DRIVER_FLASH FLASH_DEV_NAME_2; |
| extern ARM_DRIVER_FLASH FLASH_DEV_NAME_3; |
| extern ARM_DRIVER_FLASH FLASH_DEV_NAME_SCRATCH; |
| |
| static const struct flash_area flash_map[] = { |
| { |
| .fa_id = FLASH_AREA_0_ID, |
| .fa_device_id = FLASH_DEVICE_ID_0, |
| .fa_driver = &FLASH_DEV_NAME_0, |
| .fa_off = FLASH_AREA_0_OFFSET, |
| .fa_size = FLASH_AREA_0_SIZE, |
| }, |
| { |
| .fa_id = FLASH_AREA_2_ID, |
| .fa_device_id = FLASH_DEVICE_ID_2, |
| .fa_driver = &FLASH_DEV_NAME_2, |
| .fa_off = FLASH_AREA_2_OFFSET, |
| .fa_size = FLASH_AREA_2_SIZE, |
| }, |
| #if (MCUBOOT_IMAGE_NUMBER == 2) |
| { |
| .fa_id = FLASH_AREA_1_ID, |
| .fa_device_id = FLASH_DEVICE_ID_1, |
| .fa_driver = &FLASH_DEV_NAME_1, |
| .fa_off = FLASH_AREA_1_OFFSET, |
| .fa_size = FLASH_AREA_1_SIZE, |
| }, |
| { |
| .fa_id = FLASH_AREA_3_ID, |
| .fa_device_id = FLASH_DEVICE_ID_3, |
| .fa_driver = &FLASH_DEV_NAME_3, |
| .fa_off = FLASH_AREA_3_OFFSET, |
| .fa_size = FLASH_AREA_3_SIZE, |
| }, |
| #endif |
| { |
| .fa_id = FLASH_AREA_SCRATCH_ID, |
| .fa_device_id = FLASH_DEVICE_ID_SCRATCH, |
| .fa_driver = &FLASH_DEV_NAME_SCRATCH, |
| .fa_off = FLASH_AREA_SCRATCH_OFFSET, |
| .fa_size = FLASH_AREA_SCRATCH_SIZE, |
| }, |
| }; |
| |
| static const int flash_map_entry_num = ARRAY_SIZE(flash_map); |
| |
| /* |
| * `open` a flash area. The `area` in this case is not the individual |
| * sectors, but describes the particular flash area in question. |
| */ |
| int flash_area_open(uint8_t id, const struct flash_area **area) |
| { |
| int i; |
| |
| BOOT_LOG_DBG("area %d", id); |
| |
| for (i = 0; i < flash_map_entry_num; i++) { |
| if (id == flash_map[i].fa_id) { |
| break; |
| } |
| } |
| if (i == flash_map_entry_num) { |
| return -1; |
| } |
| |
| *area = &flash_map[i]; |
| return 0; |
| } |
| |
| void flash_area_close(const struct flash_area *area) |
| { |
| /* Nothing to do. */ |
| } |
| |
| int flash_area_read(const struct flash_area *area, uint32_t off, void *dst, |
| uint32_t len) |
| { |
| BOOT_LOG_DBG("read area=%d, off=%#x, len=%#x", area->fa_id, off, len); |
| return DRV_FLASH_AREA(area)->ReadData(area->fa_off + off, dst, len); |
| } |
| |
| int flash_area_write(const struct flash_area *area, uint32_t off, |
| const void *src, uint32_t len) |
| { |
| BOOT_LOG_DBG("write area=%d, off=%#x, len=%#x", area->fa_id, off, len); |
| return DRV_FLASH_AREA(area)->ProgramData(area->fa_off + off, src, len); |
| } |
| |
| int flash_area_erase(const struct flash_area *area, uint32_t off, uint32_t len) |
| { |
| ARM_FLASH_INFO *flash_info; |
| uint32_t deleted_len = 0; |
| int32_t rc = 0; |
| |
| BOOT_LOG_DBG("erase area=%d, off=%#x, len=%#x", area->fa_id, off, len); |
| flash_info = DRV_FLASH_AREA(area)->GetInfo(); |
| |
| if (flash_info->sector_info == NULL) { |
| /* Uniform sector layout */ |
| while (deleted_len < len) { |
| rc = DRV_FLASH_AREA(area)->EraseSector(area->fa_off + off); |
| if (rc != 0) { |
| break; |
| } |
| deleted_len += flash_info->sector_size; |
| off += flash_info->sector_size; |
| } |
| } else { |
| /* Inhomogeneous sector layout, explicitly defined |
| * Currently not supported. |
| */ |
| } |
| |
| return rc; |
| } |
| |
| uint32_t flash_area_align(const struct flash_area *area) |
| { |
| ARM_FLASH_INFO *flash_info; |
| |
| flash_info = DRV_FLASH_AREA(area)->GetInfo(); |
| return flash_info->program_unit; |
| } |