1 /*
2 * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
3 * Copyright (c) 2020, Cypress Semiconductor Corporation. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 */
8 #include <string.h>
9 #include "its_flash_nor.h"
10
11 #include "flash_fs/its_flash_fs.h"
12 #include "driver/Driver_Flash.h"
13
14 /* Valid entries for data item width */
15 static const uint32_t data_width_byte[] = {
16 sizeof(uint8_t),
17 sizeof(uint16_t),
18 sizeof(uint32_t),
19 };
20
21 /**
22 * \brief Gets physical address of the given block ID.
23 *
24 * \param[in] cfg Flash FS configuration
25 * \param[in] block_id Block ID
26 * \param[in] offset Offset position from the init of the block
27 *
28 * \returns Returns physical address for the given block ID.
29 */
get_phys_address(const struct its_flash_fs_config_t * cfg,uint32_t block_id,size_t offset)30 static uint32_t get_phys_address(const struct its_flash_fs_config_t *cfg,
31 uint32_t block_id, size_t offset)
32 {
33 return cfg->flash_area_addr + (block_id * cfg->block_size) + offset;
34 }
35
its_flash_nor_init(const struct its_flash_fs_config_t * cfg)36 static psa_status_t its_flash_nor_init(const struct its_flash_fs_config_t *cfg)
37 {
38 int32_t err;
39
40 err = ((ARM_DRIVER_FLASH *)cfg->flash_dev)->Initialize(NULL);
41 if (err != ARM_DRIVER_OK) {
42 return PSA_ERROR_STORAGE_FAILURE;
43 }
44
45 return PSA_SUCCESS;
46 }
47
flash_read_unaligned(const struct its_flash_fs_config_t * cfg,uint32_t addr,uint8_t * buff,size_t size)48 static psa_status_t flash_read_unaligned(
49 const struct its_flash_fs_config_t *cfg,
50 uint32_t addr, uint8_t *buff, size_t size)
51 {
52 uint32_t remaining_len, read_length = 0;
53 uint32_t aligned_addr;
54 uint32_t item_number;
55
56 /* The max size of flash data_width is 4 bytes. */
57 uint8_t temp_buffer[sizeof(uint32_t)];
58 ARM_FLASH_CAPABILITIES DriverCapabilities;
59 uint8_t data_width;
60 int ret;
61
62 DriverCapabilities =
63 ((ARM_DRIVER_FLASH *)cfg->flash_dev)->GetCapabilities();
64 data_width = data_width_byte[DriverCapabilities.data_width];
65
66 /*
67 * CMSIS ARM_FLASH_ReadData API requires the `addr` data type size
68 * aligned. Data type size is specified by the data_width in
69 * ARM_FLASH_CAPABILITIES.
70 */
71 aligned_addr = (addr / data_width) * data_width;
72 remaining_len = size;
73
74 /* Read the first data_width bytes data if `addr` is not aligned. */
75 if (aligned_addr != addr) {
76 ret = ((ARM_DRIVER_FLASH *)cfg->flash_dev)->ReadData(aligned_addr,
77 temp_buffer, 1);
78 if (ret < 0) {
79 return PSA_ERROR_STORAGE_FAILURE;
80 }
81
82 /* Record how many target data have been read. */
83 read_length = ((addr - aligned_addr + size >= data_width) ?
84 (data_width - (addr - aligned_addr)) : size);
85
86 /* Copy the read data. */
87 memcpy(buff, temp_buffer + addr - aligned_addr, read_length);
88 remaining_len -= read_length;
89 }
90
91 /*
92 * The `cnt` parameter in CMSIS ARM_FLASH_ReadData indicates number of
93 * data items to read.
94 */
95 if (remaining_len) {
96 item_number = remaining_len / data_width;
97 if (item_number) {
98 ret = ((ARM_DRIVER_FLASH *)cfg->flash_dev)->ReadData(
99 addr + read_length,
100 (uint8_t *)buff + read_length,
101 item_number);
102 if (ret < 0) {
103 return PSA_ERROR_STORAGE_FAILURE;
104 }
105 read_length += item_number * data_width;
106 remaining_len -= item_number * data_width;
107 }
108 }
109
110 /* Read the last data item if there is still remaing data. */
111 if (remaining_len) {
112 ret = ((ARM_DRIVER_FLASH *)cfg->flash_dev)->ReadData(
113 addr + read_length,
114 temp_buffer, 1);
115 if (ret < 0) {
116 return PSA_ERROR_STORAGE_FAILURE;
117 }
118 /* Copy the read data. */
119 memcpy(buff + read_length, temp_buffer, remaining_len);
120 }
121
122 return PSA_SUCCESS;
123 }
its_flash_nor_read(const struct its_flash_fs_config_t * cfg,uint32_t block_id,uint8_t * buff,size_t offset,size_t size)124 static psa_status_t its_flash_nor_read(const struct its_flash_fs_config_t *cfg,
125 uint32_t block_id, uint8_t *buff,
126 size_t offset, size_t size)
127 {
128 uint32_t addr;
129
130 if (size == 0) {
131 return PSA_SUCCESS;
132 }
133 addr = get_phys_address(cfg, block_id, offset);
134 return flash_read_unaligned(cfg, addr, buff, size);
135 }
136
its_flash_nor_write(const struct its_flash_fs_config_t * cfg,uint32_t block_id,const uint8_t * buff,size_t offset,size_t size)137 static psa_status_t its_flash_nor_write(const struct its_flash_fs_config_t *cfg,
138 uint32_t block_id, const uint8_t *buff,
139 size_t offset, size_t size)
140 {
141 int32_t err;
142 ARM_FLASH_CAPABILITIES DriverCapabilities;
143 uint32_t addr;
144 uint8_t data_width;
145
146 DriverCapabilities =
147 ((ARM_DRIVER_FLASH *)cfg->flash_dev)->GetCapabilities();
148 data_width = data_width_byte[DriverCapabilities.data_width];
149
150 addr = get_phys_address(cfg, block_id, offset);
151
152 err = ((ARM_DRIVER_FLASH *)cfg->flash_dev)->ProgramData(addr, buff,
153 size / data_width);
154 if (err < 0) {
155 return PSA_ERROR_STORAGE_FAILURE;
156 }
157
158 return PSA_SUCCESS;
159 }
160
its_flash_nor_flush(const struct its_flash_fs_config_t * cfg,uint32_t block_id)161 static psa_status_t its_flash_nor_flush(const struct its_flash_fs_config_t *cfg,
162 uint32_t block_id)
163 {
164 /* Nothing needs to be done for NOR flash, as writes are commited to flash
165 * immediately.
166 */
167 (void)cfg;
168 (void)block_id;
169 return PSA_SUCCESS;
170 }
171
its_flash_nor_erase(const struct its_flash_fs_config_t * cfg,uint32_t block_id)172 static psa_status_t its_flash_nor_erase(const struct its_flash_fs_config_t *cfg,
173 uint32_t block_id)
174 {
175 int32_t err;
176 uint32_t addr;
177 size_t offset;
178
179 for (offset = 0; offset < cfg->block_size; offset += cfg->sector_size) {
180 addr = get_phys_address(cfg, block_id, offset);
181
182 err = ((ARM_DRIVER_FLASH *)cfg->flash_dev)->EraseSector(addr);
183 if (err != ARM_DRIVER_OK) {
184 return PSA_ERROR_STORAGE_FAILURE;
185 }
186 }
187
188 return PSA_SUCCESS;
189 }
190
191 const struct its_flash_fs_ops_t its_flash_fs_ops_nor = {
192 .init = its_flash_nor_init,
193 .read = its_flash_nor_read,
194 .write = its_flash_nor_write,
195 .flush = its_flash_nor_flush,
196 .erase = its_flash_nor_erase,
197 };
198