Software APIs
flash_ctrl_ops_test.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
10 #include "sw/device/lib/runtime/irq.h"
12 #include "sw/device/lib/testing/flash_ctrl_testutils.h"
13 #include "sw/device/lib/testing/rv_plic_testutils.h"
14 #include "sw/device/lib/testing/test_framework/check.h"
16 
18 #include "otp_ctrl_regs.h"
19 #include "sw/device/lib/testing/autogen/isr_testutils.h"
20 
21 #define FLASH_CTRL_NUM_IRQS 5
22 
23 /**
24  * Bitfields for `CREATOR_SW_CFG_FLASH_DATA_DEFAULT_CFG` and
25  * `CREATOR_SW_CFG_FLASH_INFO_BOOT_DATA_CFG` OTP items.
26  *
27  * Defined here to be able to use in tests.
28  */
29 #define FLASH_CTRL_OTP_FIELD_SCRAMBLING \
30  (bitfield_field32_t) { .mask = UINT8_MAX, .index = CHAR_BIT * 0 }
31 #define FLASH_CTRL_OTP_FIELD_ECC \
32  (bitfield_field32_t) { .mask = UINT8_MAX, .index = CHAR_BIT * 1 }
33 #define FLASH_CTRL_OTP_FIELD_HE \
34  (bitfield_field32_t) { .mask = UINT8_MAX, .index = CHAR_BIT * 2 }
35 
36 OTTF_DEFINE_TEST_CONFIG();
37 
38 static dif_rv_plic_t plic0;
39 static dif_flash_ctrl_device_info_t flash_info;
40 static dif_flash_ctrl_state_t flash_state;
41 static dif_flash_ctrl_t flash_ctrl;
42 
43 static plic_isr_ctx_t plic_ctx = {
44  .rv_plic = &plic0,
45  .hart_id = kTopEarlgreyPlicTargetIbex0,
46 };
47 
48 static flash_ctrl_isr_ctx_t flash_ctx = {
49  .flash_ctrl = &flash_ctrl,
50  .plic_flash_ctrl_start_irq_id = kTopEarlgreyPlicIrqIdFlashCtrlProgEmpty,
51  .is_only_irq = false,
52 };
53 
54 static uint32_t flash_bank_0_data_region;
55 static uint32_t flash_bank_1_data_region;
56 static uint32_t flash_bank_1_data_region_scr;
57 static uint32_t flash_bank_1_page_index;
58 static uint32_t flash_bank_1_page_index_scr;
59 
60 enum {
61  kFlashInfoPageIdCreatorSecret = 1,
62  kFlashInfoPageIdOwnerSecret = 2,
63  kFlashInfoPageIdIsoPart = 3,
64  kFlashInfoBank = 0,
65  kRegionBaseBank0Page0Index = 0,
66  kPartitionId = 0,
67  kRegionSize = 1,
68  kInfoSize = 16,
69  kDataSize = 32,
70  kPageSize = 2048,
71 };
72 
73 const uint32_t kRandomData1[kInfoSize] = {
74  0xb295d21b, 0xecdfbdcd, 0x67e7ab2d, 0x6f660b08, 0x273bf65c, 0xe80f1695,
75  0x586b80db, 0xc3dba27e, 0xdc124c5d, 0xb01ccd52, 0x815713e1, 0x31a141b2,
76  0x2124be3b, 0x299a6f2a, 0x1f2a4741, 0x1a073cc0,
77 };
78 
79 const uint32_t kRandomData2[kInfoSize] = {
80  0x69e705a0, 0x65c2ec6b, 0x04b0b634, 0x59313526, 0x1858aee1, 0xd49f3ba9,
81  0x230bcd38, 0xc1eb6b3e, 0x68c15e3b, 0x024d02a9, 0x0b062ae4, 0x334dd155,
82  0x53fdbf8a, 0x3792f1e2, 0xee317161, 0x33b19bf3,
83 };
84 
85 const uint32_t kRandomData3[kInfoSize] = {
86  0x2b78dbf5, 0x3e6e5a00, 0xbf82c6d5, 0x68d8e33f, 0x9c524bbc, 0xac5beeef,
87  0x1287ca5a, 0x12b61419, 0x872e709f, 0xf91b7c0c, 0x18312a1f, 0x325cef9a,
88  0x19fefa95, 0x4ceb421b, 0xa57d74c4, 0xaf1d723d,
89 };
90 
91 const uint32_t kRandomData4[kDataSize] = {
92  0x0f5b84a3, 0xfa0330c3, 0xe125d174, 0x959d9779, 0xe10da3ba, 0x739e804d,
93  0xf8f8c317, 0xf236e75f, 0xa2118c37, 0x2d12fa9d, 0xa6fd72cd, 0x4b21d3dc,
94  0x6d36ca93, 0xbac514a6, 0x5f5695f8, 0xe7fdbe07, 0xde77eac9, 0x5ee7432f,
95  0xc7d26081, 0xae1d7262, 0x47d46715, 0x9da2de97, 0xa41e639d, 0x34470ce0,
96  0x8ac69175, 0x1dbcd910, 0x8193d43e, 0xe1538689, 0x166599e1, 0x0d5cc465,
97  0x86298854, 0x93121b13,
98 };
99 
100 const uint32_t kRandomData5[kDataSize] = {
101  0xe5214227, 0x8473a570, 0xc6fc9728, 0x6110fbbe, 0xa2b4cdc8, 0x0156836a,
102  0xa0c90954, 0x23e66c9b, 0x607c9e7c, 0x40f993b6, 0x253dfc7d, 0xe0c70727,
103  0xa7b974ea, 0x0e8561c8, 0xfe8858a9, 0x36bf06bc, 0x2a734e91, 0xf0aca1e6,
104  0x6e22f4c5, 0x469cb0a2, 0x0f6bbc43, 0xc719f5cd, 0x0a129d7d, 0x9a6c171e,
105  0x1b39ff3a, 0x9644ab82, 0x5209d14c, 0x46a7e380, 0x575b1e0b, 0x4af5e8c3,
106  0xfcbbfa64, 0xe3afddf2,
107 };
108 
109 static volatile bool expected_irqs[FLASH_CTRL_NUM_IRQS];
110 static volatile bool fired_irqs[FLASH_CTRL_NUM_IRQS];
111 
112 /**
113  * Provides external IRQ handling for this test.
114  *
115  * This function overrides the default OTTF external ISR.
116  */
117 void ottf_external_isr(uint32_t *exc_info) {
118  top_earlgrey_plic_peripheral_t peripheral_serviced;
119  dif_flash_ctrl_irq_t irq_serviced;
120  // Instruct the ISR to mute any status interrupt that is firing.
121  isr_testutils_flash_ctrl_isr(plic_ctx, flash_ctx, true, &peripheral_serviced,
122  &irq_serviced);
123  CHECK(peripheral_serviced == kTopEarlgreyPlicPeripheralFlashCtrl,
124  "Interurpt from unexpected peripheral: %d", peripheral_serviced);
125  fired_irqs[irq_serviced] = true;
126 }
127 
128 /**
129  * Clear the volatile IRQ variables.
130  */
131 static void clear_irq_variables(void) {
132  for (int i = 0; i < FLASH_CTRL_NUM_IRQS; ++i) {
133  expected_irqs[i] = false;
134  fired_irqs[i] = false;
135  }
136 }
137 
138 /**
139  * Initializes FLASH_CTRL and enables the relevant interrupts.
140  */
141 static void flash_ctrl_init_with_event_irqs(mmio_region_t base_addr,
142  dif_flash_ctrl_state_t *flash_state,
143  dif_flash_ctrl_t *flash_ctrl) {
144  CHECK_DIF_OK(dif_flash_ctrl_init(base_addr, flash_ctrl));
145  CHECK_DIF_OK(dif_flash_ctrl_init_state(flash_state, base_addr));
146 
147  for (dif_flash_ctrl_irq_t i = 0; i < FLASH_CTRL_NUM_IRQS; ++i) {
148  dif_irq_type_t type;
149  CHECK_DIF_OK(dif_flash_ctrl_irq_get_type(
150  flash_ctrl, kDifFlashCtrlIrqProgEmpty + i, &type));
151  if (type == kDifIrqTypeEvent) {
152  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
153  flash_ctrl, kDifFlashCtrlIrqProgEmpty + i, kDifToggleEnabled));
154  }
155  }
156  clear_irq_variables();
157 }
158 
159 /**
160  * Compares the expected and fired IRQs and clears both.
161  */
162 static void compare_and_clear_irq_variables(void) {
163  for (int i = 0; i < FLASH_CTRL_NUM_IRQS; ++i) {
164  CHECK(expected_irqs[i] == fired_irqs[i], "expected IRQ mismatch = %d", i);
165  }
166  clear_irq_variables();
167 }
168 
169 /**
170  * Check data read from host interface against known data.
171  */
172 static void read_and_check_host_if(uint32_t addr, const uint32_t *check_data) {
173  mmio_region_t flash_addr =
175  uint32_t host_data[kDataSize];
176  for (int i = 0; i < kDataSize; ++i) {
177  host_data[i] =
178  mmio_region_read32(flash_addr, i * (ptrdiff_t)sizeof(uint32_t));
179  }
180  CHECK_ARRAYS_EQ(host_data, check_data, kDataSize);
181 }
182 
183 /**
184  * Tests the interrupts for erase, write and
185  * read of the specified information partition.
186  * Confirms that the written data is read back correctly.
187  */
188 static void do_info_partition_test(uint32_t partition_number,
189  const uint32_t *test_data) {
190  uint32_t address = 0;
191  CHECK_STATUS_OK(flash_ctrl_testutils_info_region_setup(
192  &flash_state, partition_number, kFlashInfoBank, kPartitionId, &address));
193 
194  CHECK_DIF_OK(dif_flash_ctrl_set_prog_fifo_watermark(&flash_state, 0));
195  CHECK_DIF_OK(dif_flash_ctrl_set_read_fifo_watermark(&flash_state, 8));
196 
197  clear_irq_variables();
198 
199  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
200  CHECK_STATUS_OK(flash_ctrl_testutils_erase_page(
201  &flash_state, address, kPartitionId, kDifFlashCtrlPartitionTypeInfo));
202  compare_and_clear_irq_variables();
203 
204  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
205  expected_irqs[kDifFlashCtrlIrqProgEmpty] = true;
206  expected_irqs[kDifFlashCtrlIrqProgLvl] = true;
207  // Note: ProgEmpty and ProgLvl interrupts are enabled here and since the
208  // assert by default, they will be serviced and silenced right away. In order
209  // to test them more thoroughly, in this test, we would have to rework the
210  // write operation test utility.
211  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
212  &flash_ctrl, kDifFlashCtrlIrqProgEmpty, kDifToggleEnabled));
213  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
214  &flash_ctrl, kDifFlashCtrlIrqProgLvl, kDifToggleEnabled));
215  CHECK_STATUS_OK(
216  flash_ctrl_testutils_write(&flash_state, address, kPartitionId, test_data,
217  kDifFlashCtrlPartitionTypeInfo, kInfoSize));
218 
219  compare_and_clear_irq_variables();
220 
221  uint32_t readback_data[kInfoSize];
222  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
223  expected_irqs[kDifFlashCtrlIrqRdLvl] = true;
224  expected_irqs[kDifFlashCtrlIrqRdFull] = true;
225  // Note: RdLvl and RdFull interrupts are enabled here and as opposed to
226  // ProgEmpty and ProgLvl above, they will be tested correctly, since they only
227  // assert once the FIFO reaches the respective fill levels.
228  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
229  &flash_ctrl, kDifFlashCtrlIrqRdLvl, kDifToggleEnabled));
230  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
231  &flash_ctrl, kDifFlashCtrlIrqRdFull, kDifToggleEnabled));
232  CHECK_STATUS_OK(flash_ctrl_testutils_read(
233  &flash_state, address, kPartitionId, readback_data,
234  kDifFlashCtrlPartitionTypeInfo, kInfoSize, 1));
235 
236  compare_and_clear_irq_variables();
237 
238  CHECK_ARRAYS_EQ(readback_data, test_data, kInfoSize);
239 }
240 
241 /**
242  * Tests the interrupts for read of bank0 data partition.
243  * Only read is tested as this partition contains the program
244  * code so should not be erased or written.
245  * bootstrap uses programmed otp value to set default regions
246  * (https://github.com/lowRISC/opentitan/blob/2f58b40b9ce2f44b8e1f65cf87043eff97b0ad6c/
247  * sw/device/silicon_creator/lib/drivers/flash_ctrl.c#L270-L275)
248  *
249  * So set the region 0 as the same as bootstrap did.
250  * The data read via the flash_ctrl interface is checked against the
251  * data read via the host interface.
252  */
253 static void do_bank0_data_partition_test(void) {
254  uint32_t address = 0;
255  uint32_t otp_val = abs_mmio_read32(
256  TOP_EARLGREY_OTP_CTRL_CORE_BASE_ADDR + OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET +
257  OTP_CTRL_PARAM_CREATOR_SW_CFG_FLASH_DATA_DEFAULT_CFG_OFFSET);
258 
259  dif_flash_ctrl_region_properties_t region_properties = {
260  .ecc_en = bitfield_field32_read(otp_val, FLASH_CTRL_OTP_FIELD_ECC),
261  .high_endurance_en =
262  bitfield_field32_read(otp_val, FLASH_CTRL_OTP_FIELD_HE),
263  .scramble_en =
264  bitfield_field32_read(otp_val, FLASH_CTRL_OTP_FIELD_SCRAMBLING),
265  .erase_en = kMultiBitBool4True,
266  .prog_en = kMultiBitBool4True,
267  .rd_en = kMultiBitBool4True};
268 
269  CHECK_STATUS_OK(flash_ctrl_testutils_data_region_setup_properties(
270  &flash_state, kRegionBaseBank0Page0Index, flash_bank_0_data_region,
271  kRegionSize, region_properties, &address));
272  CHECK_DIF_OK(dif_flash_ctrl_set_read_fifo_watermark(&flash_state, 8));
273 
274  clear_irq_variables();
275  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
276  expected_irqs[kDifFlashCtrlIrqRdLvl] = true;
277  expected_irqs[kDifFlashCtrlIrqRdFull] = true;
278  // Note: RdLvl and RdFull interrupts are enabled here and as opposed to
279  // ProgEmpty and ProgLvl above, they will be tested correctly, since they only
280  // assert once the FIFO reaches the respective fill levels.
281  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
282  &flash_ctrl, kDifFlashCtrlIrqRdLvl, kDifToggleEnabled));
283  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
284  &flash_ctrl, kDifFlashCtrlIrqRdFull, kDifToggleEnabled));
285  uint32_t readback_data[kDataSize];
286  CHECK_STATUS_OK(flash_ctrl_testutils_read(
287  &flash_state, address, kPartitionId, readback_data,
288  kDifFlashCtrlPartitionTypeData, kDataSize, 1));
289 
290  compare_and_clear_irq_variables();
291  read_and_check_host_if(0, readback_data);
292 }
293 
294 /**
295  * Tests the interrupts for erase, write and read of
296  * the lowest and highest (usable) page of bank 1 data partition.
297  * Confirms that the written data is read back correctly.
298  * The whole bank is then erased and the interrupt is checked
299  * followed by confirmation that the previously written data
300  * has been wiped.
301  */
302 static void do_bank1_data_partition_test(void) {
303  uint32_t address = 0;
304  CHECK_DIF_OK(dif_flash_ctrl_set_prog_fifo_watermark(&flash_state, 0));
305  CHECK_DIF_OK(dif_flash_ctrl_set_read_fifo_watermark(&flash_state, 8));
306 
307  // Loop for low and high page erase, write and read.
308  for (int i = 0; i < 2; ++i) {
309  uint32_t page_index =
310  (i == 0) ? flash_bank_1_page_index : flash_bank_1_page_index_scr;
311  const uint32_t *test_data = (i == 0) ? kRandomData4 : kRandomData5;
312 
313  if (i == 0) {
314  // Set region1 for non-scrambled ecc enabled.
315  CHECK_STATUS_OK(flash_ctrl_testutils_data_region_setup(
316  &flash_state, page_index, flash_bank_1_data_region, kRegionSize,
317  &address));
318  } else {
319  // Set region2 for scrambled ecc enabled.
320  CHECK_STATUS_OK(flash_ctrl_testutils_data_region_scrambled_setup(
321  &flash_state, page_index, flash_bank_1_data_region_scr, kRegionSize,
322  &address));
323  }
324  clear_irq_variables();
325 
326  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
327  CHECK_STATUS_OK(flash_ctrl_testutils_erase_page(
328  &flash_state, address, kPartitionId, kDifFlashCtrlPartitionTypeData));
329 
330  compare_and_clear_irq_variables();
331 
332  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
333  expected_irqs[kDifFlashCtrlIrqProgEmpty] = true;
334  expected_irqs[kDifFlashCtrlIrqProgLvl] = true;
335  // Note: ProgEmpty and ProgLvl interrupts are enabled here and since the
336  // assert by default, they will be serviced and silenced right away. In
337  // order to test them more thoroughly, in this test, we would have to rework
338  // the write operation test utility.
339  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
340  &flash_ctrl, kDifFlashCtrlIrqProgEmpty, kDifToggleEnabled));
341  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
342  &flash_ctrl, kDifFlashCtrlIrqProgLvl, kDifToggleEnabled));
343  CHECK_STATUS_OK(flash_ctrl_testutils_write(
344  &flash_state, address, kPartitionId, test_data,
345  kDifFlashCtrlPartitionTypeData, kDataSize));
346 
347  compare_and_clear_irq_variables();
348 
349  uint32_t readback_data[kDataSize];
350  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
351  expected_irqs[kDifFlashCtrlIrqRdLvl] = true;
352  expected_irqs[kDifFlashCtrlIrqRdFull] = true;
353  // Note: RdLvl and RdFull interrupts are enabled here and as opposed to
354  // ProgEmpty and ProgLvl above, they will be tested correctly, since they
355  // only assert once the FIFO reaches the respective fill levels.
356  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
357  &flash_ctrl, kDifFlashCtrlIrqRdLvl, kDifToggleEnabled));
358  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
359  &flash_ctrl, kDifFlashCtrlIrqRdFull, kDifToggleEnabled));
360  CHECK_STATUS_OK(flash_ctrl_testutils_read(
361  &flash_state, address, kPartitionId, readback_data,
362  kDifFlashCtrlPartitionTypeData, kDataSize, 1));
363 
364  compare_and_clear_irq_variables();
365 
366  read_and_check_host_if(kPageSize * page_index, test_data);
367  CHECK_ARRAYS_EQ(readback_data, test_data, kDataSize);
368  }
369 
370  // Erasing the whole of bank 1.
371  CHECK_DIF_OK(dif_flash_ctrl_set_bank_erase_enablement(&flash_state, 1,
373  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
374 
375  CHECK_STATUS_OK(flash_ctrl_testutils_data_region_setup(
376  &flash_state, flash_bank_1_page_index, flash_bank_1_data_region,
377  kRegionSize, &address));
378  dif_flash_ctrl_transaction_t transaction = {
379  .byte_address = address,
381  .partition_type = kDifFlashCtrlPartitionTypeData,
382  .partition_id = 0x0,
383  .word_count = 0x0};
384  CHECK_DIF_OK(dif_flash_ctrl_start(&flash_state, transaction));
385  CHECK_STATUS_OK(flash_ctrl_testutils_wait_transaction_end(&flash_state));
386 
387  compare_and_clear_irq_variables();
388 
389  // Loop for low and high page read back after bank erase.
390  for (int i = 0; i < 2; ++i) {
391  uint32_t page_index =
392  (i == 0) ? flash_bank_1_page_index : flash_bank_1_page_index_scr;
393 
394  CHECK_STATUS_OK(flash_ctrl_testutils_data_region_setup(
395  &flash_state, page_index, flash_bank_1_data_region, kRegionSize,
396  &address));
397 
398  uint32_t readback_data[kDataSize];
399  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
400  expected_irqs[kDifFlashCtrlIrqRdLvl] = true;
401  expected_irqs[kDifFlashCtrlIrqRdFull] = true;
402  // Note: RdLvl and RdFull interrupts are enabled here and as opposed to
403  // ProgEmpty and ProgLvl above, they will be tested correctly, since they
404  // only assert once the FIFO reaches the respective fill levels.
405  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
406  &flash_ctrl, kDifFlashCtrlIrqRdLvl, kDifToggleEnabled));
407  CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
408  &flash_ctrl, kDifFlashCtrlIrqRdFull, kDifToggleEnabled));
409  CHECK_STATUS_OK(flash_ctrl_testutils_read(
410  &flash_state, address, kPartitionId, readback_data,
411  kDifFlashCtrlPartitionTypeData, kDataSize, 1));
412 
413  compare_and_clear_irq_variables();
414 
415  uint32_t expected_data[kDataSize];
416  memset(expected_data, 0xff, sizeof(expected_data));
417 
418  read_and_check_host_if(kPageSize * page_index, expected_data);
419  CHECK_ARRAYS_EQ(readback_data, expected_data, kDataSize);
420  }
421 }
422 
423 bool test_main(void) {
424  flash_info = dif_flash_ctrl_get_device_info();
425 
426  // Determine the region index and page index to use for tests.
427  // Test data page used for flash bank 1 should be the lowest and highest
428  // usable page.
429  if (kBootStage != kBootStageOwner) {
430  flash_bank_0_data_region = 0;
431  flash_bank_1_page_index = flash_info.data_pages;
432  } else {
433  // If we boot up in owner stage, the first 2 regions will be used by
434  // ROM_EXT.
435  flash_bank_0_data_region = 2;
436  // First 0x20 pages are configured by ROM_EXT. To avoid conflicts, skip over
437  // these pages.
438  flash_bank_1_page_index = flash_info.data_pages + 0x20;
439  }
440  flash_bank_1_data_region = flash_bank_0_data_region + 1;
441  flash_bank_1_data_region_scr = flash_bank_0_data_region + 2;
442  flash_bank_1_page_index_scr = flash_info.data_pages * 2 - 1;
443 
444  CHECK_DIF_OK(dif_rv_plic_init(
446 
447  flash_ctrl_init_with_event_irqs(
449  &flash_state, &flash_ctrl);
450  rv_plic_testutils_irq_range_enable(&plic0, plic_ctx.hart_id,
453 
454  // Enable the external IRQ at Ibex.
455  irq_global_ctrl(true);
456  irq_external_ctrl(true);
457 
458  if (kBootStage != kBootStageOwner) {
459  do_info_partition_test(kFlashInfoPageIdCreatorSecret, kRandomData1);
460  do_info_partition_test(kFlashInfoPageIdOwnerSecret, kRandomData2);
461  do_info_partition_test(kFlashInfoPageIdIsoPart, kRandomData3);
462  do_bank0_data_partition_test();
463  }
464  do_bank1_data_partition_test();
465 
466  return true;
467 }