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
9 #include <string.h>
10
11 #include "its_flash_nand.h"
12 #include "flash_fs/its_flash_fs.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_nand_init(const struct its_flash_fs_config_t * cfg)36 static psa_status_t its_flash_nand_init(const struct its_flash_fs_config_t *cfg)
37 {
38 int32_t err;
39 struct its_flash_nand_dev_t *flash_dev =
40 (struct its_flash_nand_dev_t *)cfg->flash_dev;
41
42 if (flash_dev->buf_size < cfg->block_size) {
43 return PSA_ERROR_PROGRAMMER_ERROR;
44 }
45
46 err = flash_dev->driver->Initialize(NULL);
47 if (err != ARM_DRIVER_OK) {
48 return PSA_ERROR_STORAGE_FAILURE;
49 }
50
51 return PSA_SUCCESS;
52 }
53
its_flash_nand_read(const struct its_flash_fs_config_t * cfg,uint32_t block_id,uint8_t * buff,size_t offset,size_t size)54 static psa_status_t its_flash_nand_read(const struct its_flash_fs_config_t *cfg,
55 uint32_t block_id, uint8_t *buff,
56 size_t offset, size_t size)
57 {
58 struct its_flash_nand_dev_t *flash_dev =
59 (struct its_flash_nand_dev_t *)cfg->flash_dev;
60 uint32_t addr;
61 uint32_t remaining_len, read_length = 0;
62 uint32_t aligned_addr;
63 uint32_t item_number;
64
65 /* The max size of flash data_width is 4 bytes. */
66 uint8_t temp_buffer[sizeof(uint32_t)];
67 ARM_FLASH_CAPABILITIES DriverCapabilities;
68 uint8_t data_width;
69 int ret;
70
71 if (block_id == ITS_BLOCK_INVALID_ID) {
72 return PSA_ERROR_PROGRAMMER_ERROR;
73 }
74
75 if (block_id == flash_dev->buf_block_id_0) {
76 (void)memcpy(buff, flash_dev->write_buf_0 + offset, size);
77 } else if (block_id == flash_dev->buf_block_id_1) {
78 (void)memcpy(buff, flash_dev->write_buf_1 + offset, size);
79 } else {
80 addr = get_phys_address(cfg, block_id, offset);
81 remaining_len = size;
82 DriverCapabilities = flash_dev->driver->GetCapabilities();
83 data_width = data_width_byte[DriverCapabilities.data_width];
84
85 /*
86 * CMSIS ARM_FLASH_ReadData API requires the `addr` data type size
87 * aligned. Data type size is specified by the data_width in
88 * ARM_FLASH_CAPABILITIES.
89 */
90 aligned_addr = (addr / data_width) * data_width;
91
92 /* Read the first data_width bytes data if `addr` is not aligned. */
93 if (aligned_addr != addr) {
94 ret = flash_dev->driver->ReadData(aligned_addr, temp_buffer, 1);
95 if (ret < 0) {
96 return PSA_ERROR_STORAGE_FAILURE;
97 }
98
99 /* Record how many target data have been read. */
100 read_length = ((addr - aligned_addr + size >= data_width) ?
101 (data_width - (addr - aligned_addr)) : size);
102 /* Copy the read data. */
103 memcpy(buff, temp_buffer + addr - aligned_addr, read_length);
104 remaining_len -= read_length;
105 }
106
107 /*
108 * The `cnt` parameter in CMSIS ARM_FLASH_ReadData indicates number of
109 * data items to read.
110 */
111 if (remaining_len) {
112 item_number = remaining_len / data_width;
113 if (item_number) {
114 ret = flash_dev->driver->ReadData(addr + read_length,
115 (uint8_t *)buff + read_length,
116 item_number);
117 if (ret < 0) {
118 return PSA_ERROR_STORAGE_FAILURE;
119 }
120 read_length += item_number * data_width;
121 remaining_len -= item_number * data_width;
122 }
123 }
124
125 /* Read the last data item if there is still remaing data. */
126 if (remaining_len) {
127 ret = flash_dev->driver->ReadData(addr + read_length,
128 temp_buffer, 1);
129 if (ret < 0) {
130 return PSA_ERROR_STORAGE_FAILURE;
131 }
132 /* Copy the read data. */
133 memcpy(buff + read_length, temp_buffer, remaining_len);
134 }
135 }
136
137 return PSA_SUCCESS;
138 }
139
its_flash_nand_write(const struct its_flash_fs_config_t * cfg,uint32_t block_id,const uint8_t * buff,size_t offset,size_t size)140 static psa_status_t its_flash_nand_write(
141 const struct its_flash_fs_config_t *cfg,
142 uint32_t block_id, const uint8_t *buff,
143 size_t offset, size_t size)
144 {
145 struct its_flash_nand_dev_t *flash_dev =
146 (struct its_flash_nand_dev_t *)cfg->flash_dev;
147
148 if (block_id == ITS_BLOCK_INVALID_ID) {
149 return PSA_ERROR_PROGRAMMER_ERROR;
150 }
151
152 /* Write to the match block buffer if exists. Otherwise use the empty
153 * buffer if exists. If no more empty buffer, return error.
154 */
155 if (block_id == flash_dev->buf_block_id_0) {
156 (void)memcpy(flash_dev->write_buf_0 + offset, buff, size);
157 } else if (block_id == flash_dev->buf_block_id_1) {
158 (void)memcpy(flash_dev->write_buf_1 + offset, buff, size);
159 } else if (flash_dev->buf_block_id_0 == ITS_BLOCK_INVALID_ID) {
160 flash_dev->buf_block_id_0 = block_id;
161 (void)memcpy(flash_dev->write_buf_0 + offset, buff, size);
162 } else if (flash_dev->buf_block_id_1 == ITS_BLOCK_INVALID_ID) {
163 flash_dev->buf_block_id_1 = block_id;
164 (void)memcpy(flash_dev->write_buf_1 + offset, buff, size);
165 } else {
166 return PSA_ERROR_PROGRAMMER_ERROR;
167 }
168
169 return PSA_SUCCESS;
170 }
171
its_flash_nand_flush(const struct its_flash_fs_config_t * cfg,uint32_t block_id)172 static psa_status_t its_flash_nand_flush(
173 const struct its_flash_fs_config_t *cfg,
174 uint32_t block_id)
175 {
176 int32_t err;
177 struct its_flash_nand_dev_t *flash_dev =
178 (struct its_flash_nand_dev_t *)cfg->flash_dev;
179 uint32_t addr;
180 ARM_FLASH_CAPABILITIES DriverCapabilities;
181 uint8_t data_width;
182
183 DriverCapabilities = flash_dev->driver->GetCapabilities();
184 data_width = data_width_byte[DriverCapabilities.data_width];
185 if (block_id == flash_dev->buf_block_id_0) {
186 addr = get_phys_address(cfg, flash_dev->buf_block_id_0, 0);
187
188 /*
189 * Flush the buffered write data to flash. For NAND flash,
190 * cfg->block_size should always be a multiplier of data_width.
191 */
192 err = flash_dev->driver->ProgramData(addr, flash_dev->write_buf_0,
193 cfg->block_size / data_width);
194 if (err < 0) {
195 return PSA_ERROR_STORAGE_FAILURE;
196 }
197
198 /* Clear the write buffer */
199 (void)memset(flash_dev->write_buf_0, 0, flash_dev->buf_size);
200 flash_dev->buf_block_id_0 = ITS_BLOCK_INVALID_ID;
201 } else if (block_id == flash_dev->buf_block_id_1) {
202 addr = get_phys_address(cfg, flash_dev->buf_block_id_1, 0);
203
204 /* Flush the buffered write data to flash*/
205 err = flash_dev->driver->ProgramData(addr, flash_dev->write_buf_1,
206 cfg->block_size / data_width);
207 if (err < 0) {
208 return PSA_ERROR_STORAGE_FAILURE;
209 }
210
211 /* Clear the write buffer */
212 (void)memset(flash_dev->write_buf_1, 0, flash_dev->buf_size);
213 flash_dev->buf_block_id_1 = ITS_BLOCK_INVALID_ID;
214 } else {
215 return PSA_ERROR_GENERIC_ERROR;
216 }
217
218 return PSA_SUCCESS;
219 }
220
its_flash_nand_erase(const struct its_flash_fs_config_t * cfg,uint32_t block_id)221 static psa_status_t its_flash_nand_erase(const struct its_flash_fs_config_t *cfg,
222 uint32_t block_id)
223 {
224 int32_t err;
225 uint32_t addr;
226 size_t offset;
227 struct its_flash_nand_dev_t *flash_dev =
228 (struct its_flash_nand_dev_t *)cfg->flash_dev;
229
230 for (offset = 0; offset < cfg->block_size; offset += cfg->sector_size) {
231 addr = get_phys_address(cfg, block_id, offset);
232
233 err = flash_dev->driver->EraseSector(addr);
234 if (err != ARM_DRIVER_OK) {
235 return PSA_ERROR_STORAGE_FAILURE;
236 }
237 }
238
239 return PSA_SUCCESS;
240 }
241
242 const struct its_flash_fs_ops_t its_flash_fs_ops_nand = {
243 .init = its_flash_nand_init,
244 .read = its_flash_nand_read,
245 .write = its_flash_nand_write,
246 .flush = its_flash_nand_flush,
247 .erase = its_flash_nand_erase,
248 };
249