5#include "sw/device/lib/testing/flash_ctrl_testutils.h"
11#include "dt/dt_flash_ctrl.h"
17#include "sw/device/lib/testing/test_framework/check.h"
19#include "flash_ctrl_regs.h"
21#define MODULE_ID MAKE_MODULE_ID('f', 'c', 't')
23status_t flash_ctrl_testutils_wait_for_init(
27 TRY(dif_flash_ctrl_get_status(flash_state, &
status));
28 }
while (
status.controller_init_wip);
32status_t flash_ctrl_testutils_wait_transaction_end(
34 dif_flash_ctrl_output_t output;
37 dif_result = dif_flash_ctrl_end(flash_state, &output);
44 uint32_t error_reg = 0;
45 error_reg = bitfield_bit32_write(error_reg, FLASH_CTRL_ERR_CODE_MP_ERR_BIT,
47 error_reg = bitfield_bit32_write(error_reg, FLASH_CTRL_ERR_CODE_RD_ERR_BIT,
50 bitfield_bit32_write(error_reg, FLASH_CTRL_ERR_CODE_PROG_WIN_ERR_BIT,
53 bitfield_bit32_write(error_reg, FLASH_CTRL_ERR_CODE_PROG_TYPE_ERR_BIT,
56 bitfield_bit32_write(error_reg, FLASH_CTRL_ERR_CODE_UPDATE_ERR_BIT,
59 TRY(dif_flash_ctrl_clear_error_codes(flash_state, output.
error_code.
codes));
63status_t flash_ctrl_testutils_data_region_setup_properties(
65 uint32_t data_region, uint32_t region_size,
68 .base = base_page_index,
69 .properties = region_properties,
72 TRY(dif_flash_ctrl_set_data_region_properties(flash_state, data_region,
73 data_region_properties));
74 TRY(dif_flash_ctrl_set_data_region_enablement(flash_state, data_region,
78 dif_flash_ctrl_device_info_t device_info = dif_flash_ctrl_get_device_info();
84status_t flash_ctrl_testutils_data_region_setup(
86 uint32_t data_region, uint32_t region_size, uint32_t *offset) {
88 .ecc_en = kMultiBitBool4True,
89 .high_endurance_en = kMultiBitBool4False,
90 .erase_en = kMultiBitBool4True,
91 .prog_en = kMultiBitBool4True,
92 .rd_en = kMultiBitBool4True,
93 .scramble_en = kMultiBitBool4False};
94 return flash_ctrl_testutils_data_region_setup_properties(
95 flash_state, base_page_index, data_region, region_size, region_properties,
99status_t flash_ctrl_testutils_data_region_scrambled_setup(
101 uint32_t data_region, uint32_t region_size, uint32_t *offset) {
103 .ecc_en = kMultiBitBool4True,
104 .high_endurance_en = kMultiBitBool4False,
105 .erase_en = kMultiBitBool4True,
106 .prog_en = kMultiBitBool4True,
107 .rd_en = kMultiBitBool4True,
108 .scramble_en = kMultiBitBool4True};
109 return flash_ctrl_testutils_data_region_setup_properties(
110 flash_state, base_page_index, data_region, region_size, region_properties,
114status_t flash_ctrl_testutils_info_region_setup_properties(
119 .bank = bank, .page = page_id, .partition_id = partition_id};
121 TRY(dif_flash_ctrl_set_info_region_properties(flash_state, info_region,
123 TRY(dif_flash_ctrl_set_info_region_enablement(flash_state, info_region,
126 if (offset != NULL) {
127 dif_flash_ctrl_device_info_t device_info = dif_flash_ctrl_get_device_info();
133status_t flash_ctrl_testutils_info_region_setup(
135 uint32_t partition_id, uint32_t *offset) {
137 .ecc_en = kMultiBitBool4True,
138 .high_endurance_en = kMultiBitBool4False,
139 .erase_en = kMultiBitBool4True,
140 .prog_en = kMultiBitBool4True,
141 .rd_en = kMultiBitBool4True,
142 .scramble_en = kMultiBitBool4False};
143 return flash_ctrl_testutils_info_region_setup_properties(
144 flash_state, page_id, bank, partition_id, region_properties, offset);
147status_t flash_ctrl_testutils_info_region_scrambled_setup(
149 uint32_t partition_id, uint32_t *offset) {
151 .ecc_en = kMultiBitBool4True,
152 .high_endurance_en = kMultiBitBool4False,
153 .erase_en = kMultiBitBool4True,
154 .prog_en = kMultiBitBool4True,
155 .rd_en = kMultiBitBool4True,
156 .scramble_en = kMultiBitBool4True};
157 return flash_ctrl_testutils_info_region_setup_properties(
158 flash_state, page_id, bank, partition_id, region_properties, offset);
161status_t flash_ctrl_testutils_erase_page(
164 dif_flash_ctrl_transaction_t transaction = {.byte_address = byte_address,
166 .partition_type = partition_type,
167 .partition_id = partition_id,
169 TRY(dif_flash_ctrl_start(flash_state, transaction));
170 return flash_ctrl_testutils_wait_transaction_end(flash_state);
173status_t flash_ctrl_testutils_write(
175 uint32_t partition_id,
const uint32_t *data,
182 if (byte_address & (
sizeof(uint32_t) - 1)) {
183 LOG_ERROR(
"Unaligned address 0x%x", byte_address);
184 return INVALID_ARGUMENT();
186 dif_flash_ctrl_transaction_t transaction = {.byte_address = byte_address,
188 .partition_type = partition_type,
189 .partition_id = partition_id,
191 static_assert(FLASH_CTRL_PARAM_BYTES_PER_WORD >=
sizeof(uint32_t),
192 "flash_ctrl_testutils_write() assumes the flash word width is"
193 "greater than or equal to the bus word width.");
194 uint32_t words_written = 0;
195 uint32_t word_address = byte_address /
sizeof(uint32_t);
196 const uint32_t prog_window_size =
197 (uint32_t)FLASH_CTRL_PARAM_REG_BUS_PGM_RES_BYTES /
sizeof(uint32_t);
198 const uint32_t prog_window_mask = ~(prog_window_size - 1);
200 status_t
status = OK_STATUS();
201 while (words_written < word_count) {
204 uint32_t window_limit =
205 ((word_address + prog_window_size) & prog_window_mask) - word_address;
206 uint32_t words_remaining = word_count - words_written;
207 uint32_t words_to_write =
208 (words_remaining < window_limit) ? words_remaining : window_limit;
209 transaction.
byte_address = word_address *
sizeof(uint32_t);
211 TRY(dif_flash_ctrl_start(flash_state, transaction));
212 TRY(dif_flash_ctrl_prog_fifo_push(flash_state, words_to_write,
213 data + words_written));
214 status = flash_ctrl_testutils_wait_transaction_end(flash_state);
215 word_address += words_to_write;
216 words_written += words_to_write;
222status_t flash_ctrl_testutils_erase_and_write_page(
224 uint32_t partition_id,
const uint32_t *data,
226 TRY(flash_ctrl_testutils_erase_page(flash_state, byte_address, partition_id,
228 TRY(flash_ctrl_testutils_write(flash_state, byte_address, partition_id, data,
229 partition_type, word_count));
233status_t flash_ctrl_testutils_read(
235 uint32_t partition_id, uint32_t *data_out,
237 uint32_t delay_micros) {
238 dif_flash_ctrl_transaction_t transaction = {.byte_address = byte_address,
240 .partition_type = partition_type,
241 .partition_id = partition_id,
242 .word_count = word_count};
245 TRY(dif_flash_ctrl_start(flash_state, transaction));
247 busy_spin_micros(delay_micros);
248 TRY(dif_flash_ctrl_read_fifo_pop(flash_state, word_count, data_out));
249 return flash_ctrl_testutils_wait_transaction_end(flash_state);
252status_t flash_ctrl_testutils_default_region_access(
254 bool erase_en,
bool scramble_en,
bool ecc_en,
bool high_endurance_en) {
256 .rd_en = rd_en ? kMultiBitBool4True : kMultiBitBool4False,
257 .prog_en = prog_en ? kMultiBitBool4True : kMultiBitBool4False,
258 .erase_en = erase_en ? kMultiBitBool4True : kMultiBitBool4False,
259 .scramble_en = scramble_en ? kMultiBitBool4True : kMultiBitBool4False,
260 .ecc_en = ecc_en ? kMultiBitBool4True : kMultiBitBool4False,
262 high_endurance_en ? kMultiBitBool4True : kMultiBitBool4False};
264 TRY(dif_flash_ctrl_set_default_region_properties(flash_state,
265 default_properties));
270 uint32_t bank,
bool data_only) {
272 TRY(dif_flash_ctrl_get_bank_erase_enablement(flash_state, bank,
273 &bank_erase_enabled));
276 TRY(dif_flash_ctrl_set_bank_erase_enablement(flash_state, bank,
280 dif_flash_ctrl_device_info_t flash_info = dif_flash_ctrl_get_device_info();
281 uint32_t byte_address =
284 data_only ? kDifFlashCtrlPartitionTypeData
285 : kDifFlashCtrlPartitionTypeInfo;
286 dif_flash_ctrl_transaction_t transaction = {.byte_address = byte_address,
288 .partition_type = partition_type,
291 TRY(dif_flash_ctrl_start(flash_state, transaction));
292 TRY(flash_ctrl_testutils_wait_transaction_end(flash_state));
294 TRY(dif_flash_ctrl_set_bank_erase_enablement(flash_state, bank,
295 bank_erase_enabled));
299status_t flash_ctrl_testutils_show_faults(
301 dif_flash_ctrl_faults_t faults = {.memory_properties_error =
false};
302 CHECK_DIF_OK(dif_flash_ctrl_get_faults(flash_ctrl, &faults));
303#define LOG_IF_FIELD_SET(_struct, _field) \
304 if (_struct._field != 0) { \
305 LOG_INFO("Flash_ctrl fault status has " #_field); \
308 LOG_IF_FIELD_SET(faults, memory_properties_error);
309 LOG_IF_FIELD_SET(faults, read_error);
310 LOG_IF_FIELD_SET(faults, prog_window_error);
311 LOG_IF_FIELD_SET(faults, prog_type_error);
312 LOG_IF_FIELD_SET(faults, host_gnt_error);
313 LOG_IF_FIELD_SET(faults, register_integrity_error);
314 LOG_IF_FIELD_SET(faults, phy_integrity_error);
315 LOG_IF_FIELD_SET(faults, lifecycle_manager_error);
316 LOG_IF_FIELD_SET(faults, shadow_storage_error);
317#undef LOG_IF_FIELD_SET