5#include "sw/device/lib/testing/nvm_testutils.h"
12#include "sw/device/lib/base/multibits.h"
13#include "sw/device/lib/testing/test_framework/check.h"
17#include "sw/device/lib/testing/rram_ctrl_testutils.h"
22#include "sw/device/lib/testing/flash_ctrl_testutils.h"
23#include "sw/device/silicon_creator/lib/drivers/flash_ctrl.h"
24#if defined(OPENTITAN_IS_EARLGREY)
26#elif defined(OPENTITAN_IS_ENGLISHBREAKFAST)
30 "nvm_testutils.c requires OPENTITAN_IS_EARLGREY or OPENTITAN_IS_ENGLISHBREAKFAST"
35enum { kNvmMaxWordCount = 16 };
40const nvm_page_perms_t kPageReadOnly = {.read = kMultiBitBool4True,
41 .write = kMultiBitBool4False};
43const nvm_page_perms_t kPageReadWrite = {.read = kMultiBitBool4True,
44 .write = kMultiBitBool4True};
46const nvm_page_perms_t kPageWriteOnly = {.read = kMultiBitBool4False,
47 .write = kMultiBitBool4True};
49const nvm_page_cfg_t kPageScrambleCfg = {.scrambling = kMultiBitBool4True,
50 .ecc = kMultiBitBool4True};
52const nvm_page_cfg_t kPagePlainCfg = {.scrambling = kMultiBitBool4False,
53 .ecc = kMultiBitBool4True};
55const nvm_page_cfg_t kPageRawCfg = {.scrambling = kMultiBitBool4False,
56 .ecc = kMultiBitBool4False};
59 TRY(dif_rram_ctrl_init_state(
64status_t nvm_testutils_wait_for_init(
void) {
66 TRY(dif_rram_state_init(&rram));
67 dif_rram_ctrl_phy_status_t phy_status;
69 TRY(dif_rram_ctrl_get_phy_status(&rram, &phy_status));
74status_t nvm_testutils_rom_init(uint32_t otp_nvm_default_cfg) {
76 TRY(dif_rram_state_init(&rram));
77 TRY(dif_rram_ctrl_start_controller_init(&rram));
80 TRY(dif_rram_ctrl_get_status(&rram, &
status));
81 }
while (!
status.controller_init_done);
88 TRY(dif_rram_ctrl_get_default_region_properties(&rram, &props));
89 props.
rd_en = kMultiBitBool4True;
90 if (otp_nvm_default_cfg != 0) {
93 props.
scramble_en = bitfield_field32_read(otp_nvm_default_cfg,
94 RRAM_CTRL_OTP_FIELD_SCRAMBLING);
96 bitfield_field32_read(otp_nvm_default_cfg, RRAM_CTRL_OTP_FIELD_ECC);
98 TRY(dif_rram_ctrl_set_default_region_properties(&rram, props));
104static status_t rram_info_page_set_props(
107 return rram_ctrl_testutils_info_region_setup_properties(rram, page_id, props,
114static status_t rram_write_words(
117 enum { kRramWriteWords = 4, kRramWriteBytes = kRramWriteWords * 4 };
118 size_t remaining_words = word_count;
119 const uint32_t *src = data;
120 while (remaining_words > 0) {
121 if (addr % kRramWriteBytes == 0 && remaining_words >= kRramWriteWords) {
122 size_t full_words = (remaining_words / kRramWriteWords) * kRramWriteWords;
123 TRY(rram_ctrl_testutils_write(rram, addr, src, partition_type,
124 (uint32_t)full_words));
125 addr += (uint32_t)(full_words *
sizeof(uint32_t));
127 remaining_words -= full_words;
130 TRY(rram_ctrl_testutils_write_word(rram, addr, src, partition_type));
131 addr +=
sizeof(uint32_t);
139 const rram_ctrl_info_page_t *p,
140 nvm_page_cfg_t cfg) {
142 .rd_en = kMultiBitBool4True,
143 .wr_en = kMultiBitBool4True,
144 .scramble_en = cfg.scrambling,
152 uint32_t base = kRramCtrlEmulPageBaseB;
153 uint32_t region = kRramCtrlEmulRegionB;
155 kRramCtrlEmulPageEndB - kRramCtrlOtpPageCount - kRramCtrlEmulPageBaseB;
156 if (p->
page_id >= kRramCtrlEmulPageBaseA &&
157 p->
page_id < kRramCtrlEmulPageEndA) {
158 base = kRramCtrlEmulPageBaseA;
159 region = kRramCtrlEmulRegionA;
160 count = kRramCtrlEmulPageEndA - kRramCtrlEmulPageBaseA;
162 return rram_ctrl_testutils_data_region_setup_properties(
163 rram, base, region, count, properties, NULL);
166status_t nvm_testutils_info_page_setup(nvm_info_page_t page,
167 nvm_page_perms_t perms,
168 nvm_page_cfg_t cfg) {
169 const rram_ctrl_info_page_t *p = nvm_ctrl_rram_page_info(page);
171 TRY(dif_rram_state_init(&rram));
174 return rram_relocated_region_enable(&rram, p, cfg);
180 .wr_en = perms.write,
181 .scramble_en = cfg.scrambling,
184 return rram_info_page_set_props(&rram, p->
page_id, props);
187status_t nvm_testutils_write_info_page(nvm_info_page_t page,
188 uint32_t byte_offset,
189 const uint32_t *data,
size_t word_count,
190 bool erase_before_write,
bool readback) {
191 const rram_ctrl_info_page_t *p = nvm_ctrl_rram_page_info(page);
196 if (erase_before_write) {
197 TRY(nvm_ctrl_info_erase(page));
201 TRY(dif_rram_state_init(&rram));
202 dif_rram_ctrl_device_info_t info = dif_rram_ctrl_get_device_info();
204 !p->
emulated ? kDifRramCtrlPartitionTypeInfo
205 : kDifRramCtrlPartitionTypeData;
207 TRY(rram_write_words(&rram, address, data, word_count, partition_type));
210 uint32_t rb_buf[kNvmMaxWordCount];
211 size_t remaining = word_count;
212 size_t chunk_offset = 0;
213 while (remaining > 0) {
215 remaining < kNvmMaxWordCount ? remaining : kNvmMaxWordCount;
216 TRY(rram_ctrl_testutils_read(&rram,
217 address + chunk_offset *
sizeof(uint32_t),
218 rb_buf, partition_type, (uint32_t)chunk,
220 TRY_CHECK_ARRAYS_EQ(rb_buf, data + chunk_offset, chunk,
221 "NVM write readback mismatch at page %d offset %d",
222 page, byte_offset + chunk_offset *
sizeof(uint32_t));
223 chunk_offset += chunk;
230status_t nvm_testutils_read_info_page(nvm_info_page_t page,
231 uint32_t byte_offset, uint32_t *data,
233 const rram_ctrl_info_page_t *p = nvm_ctrl_rram_page_info(page);
235 TRY(dif_rram_state_init(&rram));
236 dif_rram_ctrl_device_info_t info = dif_rram_ctrl_get_device_info();
238 !p->
emulated ? kDifRramCtrlPartitionTypeInfo
239 : kDifRramCtrlPartitionTypeData;
241 return rram_ctrl_testutils_read(&rram, address, data, partition_type,
242 (uint32_t)word_count, 0);
245status_t nvm_testutils_info_page_lock(nvm_info_page_t page,
bool lock) {
249 const rram_ctrl_info_page_t *p = nvm_ctrl_rram_page_info(page);
256 TRY(dif_rram_state_init(&rram));
258 TRY(dif_rram_ctrl_lock_info_region_properties(&rram, region));
262status_t nvm_testutils_info_page_print(nvm_info_page_t page) {
263 const rram_ctrl_info_page_t *p = nvm_ctrl_rram_page_info(page);
265 TRY(dif_rram_state_init(&rram));
275 uint32_t data_region = p->
page_id >= kRramCtrlEmulPageBaseA &&
276 p->
page_id < kRramCtrlEmulPageEndA
277 ? kRramCtrlEmulRegionA
278 : kRramCtrlEmulRegionB;
280 TRY(dif_rram_ctrl_get_data_region_properties(&rram, data_region,
282 TRY(dif_rram_ctrl_data_region_is_locked(&rram, data_region, &locked));
285 TRY(dif_rram_ctrl_get_info_region_properties(&rram, region, &props));
286 TRY(dif_rram_ctrl_info_region_is_locked(&rram, region, &locked));
288 rram_ctrl_testutils_info_region_print(region, &props, locked);
295status_t nvm_testutils_data_region_setup(uint32_t region, uint32_t base,
296 uint32_t size, nvm_page_perms_t perms,
297 nvm_page_cfg_t cfg) {
299 TRY(dif_rram_state_init(&rram));
308 .wr_en = perms.write,
309 .scramble_en = cfg.scrambling,
313 TRY(dif_rram_ctrl_set_data_region_properties(&rram, region, config));
314 TRY(dif_rram_ctrl_set_data_region_enablement(&rram, region,
319status_t nvm_testutils_data_region_lock(uint32_t region,
bool lock) {
324 TRY(dif_rram_state_init(&rram));
325 TRY(dif_rram_ctrl_lock_data_region_properties(&rram, region));
329status_t nvm_testutils_data_write(uint32_t byte_address,
const uint32_t *data,
330 size_t word_count,
bool erase_before_write) {
332 (void)erase_before_write;
335 TRY(dif_rram_state_init(&rram));
336 return rram_write_words(&rram, byte_address, data, word_count,
337 kDifRramCtrlPartitionTypeData);
340status_t nvm_testutils_set_exec_enablement(
bool enable) {
342 TRY(dif_rram_state_init(&rram));
343 TRY(dif_rram_ctrl_set_exec_enablement(
348status_t nvm_testutils_show_faults(
void) {
350 TRY(dif_rram_state_init(&rram));
351 dif_rram_ctrl_faults_t faults;
352 TRY(dif_rram_ctrl_get_faults(&rram, &faults));
353#define LOG_IF_FIELD_SET(_struct, _field) \
354 if (_struct._field) { \
355 LOG_INFO("Rram_ctrl fault status has " #_field); \
357 LOG_IF_FIELD_SET(faults, lcmgr_operation_error);
358 LOG_IF_FIELD_SET(faults, lcmgr_memory_protection_error);
359 LOG_IF_FIELD_SET(faults, lcmgr_read_error);
360 LOG_IF_FIELD_SET(faults, lcmgr_write_error);
361 LOG_IF_FIELD_SET(faults, otp_operation_error);
362 LOG_IF_FIELD_SET(faults, otp_memory_protection_error);
363 LOG_IF_FIELD_SET(faults, otp_read_error);
364 LOG_IF_FIELD_SET(faults, otp_write_error);
365#undef LOG_IF_FIELD_SET
369status_t nvm_testutils_default_region_setup(nvm_page_perms_t perms,
370 nvm_page_cfg_t cfg) {
372 TRY(dif_rram_state_init(&rram));
377 .wr_en = perms.write,
378 .scramble_en = cfg.scrambling,
381 TRY(dif_rram_ctrl_set_default_region_properties(&rram, props));
385status_t nvm_testutils_default_region_get(nvm_page_perms_t *perms,
386 nvm_page_cfg_t *cfg) {
388 TRY(dif_rram_state_init(&rram));
390 TRY(dif_rram_ctrl_get_default_region_properties(&rram, &props));
392 perms->read = (uint32_t)props.
rd_en;
393 perms->write = (uint32_t)props.
wr_en;
395 perms->erase = kMultiBitBool4False;
399 cfg->ecc = (uint32_t)props.
ecc_en;
401 cfg->he = kMultiBitBool4False;
409const nvm_page_perms_t kPageReadOnly = {.read = kMultiBitBool4True,
410 .write = kMultiBitBool4False,
411 .erase = kMultiBitBool4False};
413const nvm_page_perms_t kPageReadWrite = {.read = kMultiBitBool4True,
414 .write = kMultiBitBool4True,
415 .erase = kMultiBitBool4True};
417const nvm_page_perms_t kPageWriteOnly = {.read = kMultiBitBool4False,
418 .write = kMultiBitBool4True,
419 .erase = kMultiBitBool4True};
421const nvm_page_cfg_t kPageScrambleCfg = {.scrambling = kMultiBitBool4True,
422 .ecc = kMultiBitBool4True,
423 .he = kMultiBitBool4False};
425const nvm_page_cfg_t kPagePlainCfg = {.scrambling = kMultiBitBool4False,
426 .ecc = kMultiBitBool4True,
427 .he = kMultiBitBool4False};
429const nvm_page_cfg_t kPageRawCfg = {.scrambling = kMultiBitBool4False,
430 .ecc = kMultiBitBool4False,
431 .he = kMultiBitBool4False};
437 uint32_t partition_id;
445 [kNvmInfoPageFactoryId] = {.page_id = 0, .bank = 0, .partition_id = 0},
446 [kNvmInfoPageCreatorSecret] = {.page_id = 1, .bank = 0, .partition_id = 0},
447 [kNvmInfoPageOwnerSecret] = {.page_id = 2, .bank = 0, .partition_id = 0},
448 [kNvmInfoPageWaferAuthSecret] = {.page_id = 3, .bank = 0, .partition_id = 0},
449 [kNvmInfoPageAttestationKeySeeds] = {.page_id = 4, .bank = 0, .partition_id = 0},
450 [kNvmInfoPageOwnerReserved0] = {.page_id = 5, .bank = 0, .partition_id = 0},
451 [kNvmInfoPageOwnerReserved1] = {.page_id = 6, .bank = 0, .partition_id = 0},
452 [kNvmInfoPageOwnerReserved2] = {.page_id = 7, .bank = 0, .partition_id = 0},
453 [kNvmInfoPageOwnerReserved3] = {.page_id = 8, .bank = 0, .partition_id = 0},
454 [kNvmInfoPageFactoryCerts] = {.page_id = 9, .bank = 0, .partition_id = 0},
456 [kNvmInfoPageBootData0] = {.page_id = 0, .bank = 1, .partition_id = 0},
457 [kNvmInfoPageBootData1] = {.page_id = 1, .bank = 1, .partition_id = 0},
458 [kNvmInfoPageOwnerSlot0] = {.page_id = 2, .bank = 1, .partition_id = 0},
459 [kNvmInfoPageOwnerSlot1] = {.page_id = 3, .bank = 1, .partition_id = 0},
460 [kNvmInfoPageCreatorReserved0] = {.page_id = 4, .bank = 1, .partition_id = 0},
461 [kNvmInfoPageOwnerReserved4] = {.page_id = 5, .bank = 1, .partition_id = 0},
462 [kNvmInfoPageOwnerReserved5] = {.page_id = 6, .bank = 1, .partition_id = 0},
463 [kNvmInfoPageOwnerReserved6] = {.page_id = 7, .bank = 1, .partition_id = 0},
464 [kNvmInfoPageOwnerReserved7] = {.page_id = 8, .bank = 1, .partition_id = 0},
465 [kNvmInfoPageDiceCerts] = {.page_id = 9, .bank = 1, .partition_id = 0},
470#if defined(OPENTITAN_IS_EARLGREY)
471 TRY(dif_flash_ctrl_init_state(
472 flash, mmio_region_from_addr(TOP_EARLGREY_FLASH_CTRL_CORE_BASE_ADDR)));
473#elif defined(OPENTITAN_IS_ENGLISHBREAKFAST)
474 TRY(dif_flash_ctrl_init_state(
481status_t nvm_testutils_wait_for_init(
void) {
483 TRY(dif_flash_state_init(&flash));
484 TRY(flash_ctrl_testutils_wait_for_init(&flash));
490 region.
bank = p->bank;
492 region.
page = p->page_id;
500 TRY(dif_flash_ctrl_set_info_region_properties(flash, region, props));
501 TRY(dif_flash_ctrl_set_info_region_enablement(flash, region,
506status_t nvm_testutils_rom_init(uint32_t otp_nvm_default_cfg) {
508 TRY(dif_flash_state_init(&flash));
509 TRY(dif_flash_ctrl_start_controller_init(&flash));
510 TRY(flash_ctrl_testutils_wait_for_init(&flash));
511 if (otp_nvm_default_cfg != 0) {
513 TRY(dif_flash_ctrl_get_default_region_properties(&flash, &props));
514 props.
scramble_en = bitfield_field32_read(otp_nvm_default_cfg,
515 FLASH_CTRL_OTP_FIELD_SCRAMBLING);
517 bitfield_field32_read(otp_nvm_default_cfg, FLASH_CTRL_OTP_FIELD_ECC);
519 bitfield_field32_read(otp_nvm_default_cfg, FLASH_CTRL_OTP_FIELD_HE);
520 TRY(dif_flash_ctrl_set_default_region_properties(&flash, props));
523#ifdef OPENTITAN_IS_EARLGREY
529status_t nvm_testutils_info_page_setup(nvm_info_page_t page,
530 nvm_page_perms_t perms,
531 nvm_page_cfg_t cfg) {
532 TRY_CHECK(page <
ARRAYSIZE(kPageMap),
"invalid page %d", page);
535 TRY(dif_flash_state_init(&flash));
538 .prog_en = perms.write,
539 .erase_en = perms.erase,
540 .scramble_en = cfg.scrambling,
542 .high_endurance_en = cfg.he,
544 TRY(info_page_set_props(&flash, &p, props));
548status_t nvm_testutils_write_info_page(nvm_info_page_t page,
549 uint32_t byte_offset,
550 const uint32_t *data,
size_t word_count,
551 bool erase_before_write,
bool readback) {
552 TRY_CHECK(page <
ARRAYSIZE(kPageMap),
"invalid page %d", page);
554 uint32_t address = p.page_id * NVM_BYTES_PER_PAGE + byte_offset;
557 TRY(dif_flash_state_init(&flash));
559 if (erase_before_write) {
560 TRY(flash_ctrl_testutils_erase_and_write_page(
561 &flash, address, p.partition_id, data, kDifFlashCtrlPartitionTypeInfo,
564 TRY(flash_ctrl_testutils_write(&flash, address, p.partition_id, data,
565 kDifFlashCtrlPartitionTypeInfo, word_count));
568 uint32_t rb_buf[kNvmMaxWordCount];
569 size_t remaining = word_count;
570 size_t chunk_offset = 0;
571 while (remaining > 0) {
573 remaining < kNvmMaxWordCount ? remaining : kNvmMaxWordCount;
574 TRY(flash_ctrl_testutils_read(
575 &flash, address + chunk_offset *
sizeof(uint32_t), p.partition_id,
576 rb_buf, kDifFlashCtrlPartitionTypeInfo, chunk, 0));
577 TRY_CHECK_ARRAYS_EQ(rb_buf, data + chunk_offset, chunk,
578 "NVM write readback mismatch at page %d offset %d",
579 page, byte_offset + chunk_offset *
sizeof(uint32_t));
580 chunk_offset += chunk;
587status_t nvm_testutils_read_info_page(nvm_info_page_t page,
588 uint32_t byte_offset, uint32_t *data,
590 TRY_CHECK(page <
ARRAYSIZE(kPageMap),
"invalid page %d", page);
592 uint32_t address = p.page_id * NVM_BYTES_PER_PAGE + byte_offset;
595 TRY(dif_flash_state_init(&flash));
597 TRY(flash_ctrl_testutils_read(&flash, address, p.partition_id, data,
598 kDifFlashCtrlPartitionTypeInfo, word_count, 0));
602status_t nvm_testutils_info_page_lock(nvm_info_page_t page,
bool lock) {
606 TRY_CHECK(page <
ARRAYSIZE(kPageMap),
"invalid page %d", page);
609 TRY(dif_flash_state_init(&flash));
610 TRY(dif_flash_ctrl_lock_info_region_properties(&flash, phys_to_region(&p)));
614status_t nvm_testutils_info_page_print(nvm_info_page_t page) {
615 TRY_CHECK(page <
ARRAYSIZE(kPageMap),
"invalid page %d", page);
618 TRY(dif_flash_state_init(&flash));
622 TRY(dif_flash_ctrl_get_info_region_properties(&flash, region, &props));
623 TRY(dif_flash_ctrl_info_region_is_locked(&flash, region, &locked));
624 flash_ctrl_testutils_info_region_print(region, &props, locked);
628status_t nvm_testutils_data_region_setup(uint32_t region, uint32_t base,
629 uint32_t size, nvm_page_perms_t perms,
630 nvm_page_cfg_t cfg) {
632 TRY(dif_flash_state_init(&flash));
639 .prog_en = perms.write,
640 .erase_en = perms.erase,
641 .scramble_en = cfg.scrambling,
643 .high_endurance_en = cfg.he,
646 TRY(dif_flash_ctrl_set_data_region_properties(&flash, region, config));
647 TRY(dif_flash_ctrl_set_data_region_enablement(&flash, region,
652status_t nvm_testutils_data_region_lock(uint32_t region,
bool lock) {
657 TRY(dif_flash_state_init(&flash));
658 TRY(dif_flash_ctrl_lock_data_region_properties(&flash, region));
662status_t nvm_testutils_data_write(uint32_t byte_address,
const uint32_t *data,
663 size_t word_count,
bool erase_before_write) {
665 TRY(dif_flash_state_init(&flash));
666 if (erase_before_write) {
667 TRY(flash_ctrl_testutils_erase_and_write_page(
668 &flash, byte_address, 0, data,
669 kDifFlashCtrlPartitionTypeData, (uint32_t)word_count));
671 TRY(flash_ctrl_testutils_write(&flash, byte_address, 0,
672 data, kDifFlashCtrlPartitionTypeData,
673 (uint32_t)word_count));
678status_t nvm_testutils_set_exec_enablement(
bool enable) {
680 TRY(dif_flash_state_init(&flash));
681 TRY(dif_flash_ctrl_set_exec_enablement(
686status_t nvm_testutils_show_faults(
void) {
689 TRY(dif_flash_ctrl_init_state_from_dt(&flash, kFlashCtrlDt));
690 TRY(flash_ctrl_testutils_show_faults(&flash));
694status_t nvm_testutils_default_region_setup(nvm_page_perms_t perms,
695 nvm_page_cfg_t cfg) {
697 TRY(dif_flash_state_init(&flash));
700 .prog_en = perms.write,
701 .erase_en = perms.erase,
702 .scramble_en = cfg.scrambling,
704 .high_endurance_en = cfg.he,
706 TRY(dif_flash_ctrl_set_default_region_properties(&flash, props));
710status_t nvm_testutils_default_region_get(nvm_page_perms_t *perms,
711 nvm_page_cfg_t *cfg) {
713 TRY(dif_flash_state_init(&flash));
715 TRY(dif_flash_ctrl_get_default_region_properties(&flash, &props));
717 perms->read = (uint32_t)props.
rd_en;
718 perms->write = (uint32_t)props.
prog_en;
719 perms->erase = (uint32_t)props.
erase_en;
723 cfg->ecc = (uint32_t)props.
ecc_en;