Software APIs
flash_ctrl_idle_low_power_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 
12 #include "sw/device/lib/runtime/irq.h"
14 #include "sw/device/lib/testing/flash_ctrl_testutils.h"
15 #include "sw/device/lib/testing/pwrmgr_testutils.h"
16 #include "sw/device/lib/testing/rand_testutils.h"
17 #include "sw/device/lib/testing/rstmgr_testutils.h"
18 #include "sw/device/lib/testing/test_framework/check.h"
20 
22 #include "sw/device/lib/testing/autogen/isr_testutils.h"
23 
24 OTTF_DEFINE_TEST_CONFIG();
25 
26 static dif_rv_plic_t plic;
27 static dif_aon_timer_t aon;
28 static dif_rv_core_ibex_t rv_core_ibex;
29 
30 static plic_isr_ctx_t plic_ctx = {
31  .rv_plic = &plic,
32  .hart_id = kTopEarlgreyPlicTargetIbex0,
33 };
34 
35 static aon_timer_isr_ctx_t aon_timer_ctx = {
36  .aon_timer = &aon,
37  .plic_aon_timer_start_irq_id =
39  .is_only_irq = false,
40 };
41 
42 static top_earlgrey_plic_peripheral_t peripheral_serviced;
43 static dif_aon_timer_irq_t irq_serviced;
44 
45 enum {
46  kFlashDataRegion = 0,
47  kRegionBasePageIndex = 256, // First page in bank 1 (avoids program code.)
48  kPartitionId = 0,
49  kRegionSize = 1,
50  kNumWords = 128,
51  kAONBarkTh = 64,
52  kAONBiteTh = 256,
53 };
54 
55 /**
56  * External interrupt handler.
57  */
58 void ottf_external_isr(uint32_t *exc_info) {
59  isr_testutils_aon_timer_isr(plic_ctx, aon_timer_ctx, &peripheral_serviced,
60  &irq_serviced);
61 }
62 
63 /**
64  * OTTF external NMI internal IRQ handler.
65  * The ROM configures the watchdog to generates a NMI at bark, so we clean the
66  * NMI and wait the external irq handler next.
67  */
68 void ottf_external_nmi_handler(void) {
69  bool is_pending;
70  // The watchdog bark external interrupt is also connected to the NMI input
71  // of rv_core_ibex. We therefore expect the interrupt to be pending on the
72  // peripheral side (the check is done later in the test function).
73  CHECK_DIF_OK(dif_aon_timer_irq_is_pending(&aon, kDifAonTimerIrqWdogTimerBark,
74  &is_pending));
75  // In order to handle the NMI we need to acknowledge the interrupt status
76  // bit it at the peripheral side.
77  CHECK_DIF_OK(
78  dif_aon_timer_irq_acknowledge(&aon, kDifAonTimerIrqWdogTimerBark));
79 
80  CHECK_DIF_OK(dif_rv_core_ibex_clear_nmi_state(&rv_core_ibex,
81  kDifRvCoreIbexNmiSourceAll));
82 }
83 
84 static void enable_irqs(void) {
85  // Enable the AON bark interrupt.
86  CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(
89  CHECK_DIF_OK(dif_rv_plic_irq_set_priority(
93  &plic, kTopEarlgreyPlicTargetIbex0, 0x0));
94  // Enable the external IRQ at Ibex.
95  irq_global_ctrl(true);
96  irq_external_ctrl(true);
97 }
98 
99 bool test_main(void) {
101  dif_pwrmgr_t pwrmgr;
102  dif_rstmgr_t rstmgr;
103 
104  CHECK_DIF_OK(dif_rv_plic_init(
106  CHECK_DIF_OK(dif_flash_ctrl_init_state(
108  CHECK_DIF_OK(dif_pwrmgr_init(
110  CHECK_DIF_OK(dif_rstmgr_init(
112  CHECK_DIF_OK(dif_aon_timer_init(
114  CHECK_DIF_OK(dif_rv_core_ibex_init(
116  &rv_core_ibex));
117  enable_irqs();
118 
119  CHECK_DIF_OK(dif_aon_timer_watchdog_stop(&aon));
121  kDifPwrmgrResetRequestSourceTwo,
123 
124  dif_rstmgr_reset_info_bitfield_t rstmgr_reset_info;
125  rstmgr_reset_info = rstmgr_testutils_reason_get();
126 
127  uint32_t address = 0;
128  CHECK_STATUS_OK(flash_ctrl_testutils_data_region_setup(
129  &flash, kRegionBasePageIndex, kFlashDataRegion, kRegionSize, &address));
130 
131  if (rstmgr_reset_info == kDifRstmgrResetInfoPor) {
132  // Create data. Random data will be different than
133  // the 0xFFFFFFFF that is created with an erase.
134  uint32_t data[kNumWords];
135  for (int i = 0; i < kNumWords; ++i) {
136  data[i] = rand_testutils_gen32();
137  }
138 
139  // Erasing the page and writing data to it followed
140  // by a read back and compare to sanity check basic operation.
141  CHECK_STATUS_OK(flash_ctrl_testutils_erase_and_write_page(
142  &flash, address, kPartitionId, data, kDifFlashCtrlPartitionTypeData,
143  kNumWords));
144  uint32_t readback_data[kNumWords];
145  CHECK_STATUS_OK(flash_ctrl_testutils_read(
146  &flash, address, kPartitionId, readback_data,
147  kDifFlashCtrlPartitionTypeData, kNumWords, 0));
148  CHECK_ARRAYS_EQ(data, readback_data, kNumWords);
149 
150  // Setting up low power hint and starting watchdog timer followed by
151  // a flash operation (page erase) and WFI. This will create a bite
152  // interrupt at some time following the start of the flash operation.
153  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
154  &pwrmgr, kDifPwrmgrWakeupRequestSourceTwo, 0));
155 
156  CHECK_DIF_OK(dif_aon_timer_watchdog_stop(&aon));
157 
158  uint32_t bark_th = kAONBarkTh;
159  uint32_t bite_th = kAONBiteTh;
160 
161  // Update bark and bite threshold in case of silicon test
162  if (kDeviceType == kDeviceSilicon) {
163  bark_th = 4000;
164  bite_th = 4 * bark_th;
165  }
166  CHECK_DIF_OK(dif_aon_timer_watchdog_start(
167  &aon /* aon */, bark_th /* bark_threshold */,
168  bite_th /* bite_threshold */, false /* pause_in_sleep */,
169  false /* lock */));
170 
171  dif_flash_ctrl_transaction_t transaction = {
172  .byte_address = address,
174  .partition_type = kDifFlashCtrlPartitionTypeData,
175  .partition_id = kPartitionId,
176  .word_count = 0x0};
177 
178  CHECK_DIF_OK(dif_flash_ctrl_start(&flash, transaction));
179  // Do not put any print here.
180  // That will cause interrupt miss and spurious test failure
182 
183  // Return from interrupt. Stop the watchdog. Check the reset info
184  // is still POR and the interrupt came from the correct source.
185  // Check the erase operation completed successfully.
186  CHECK_DIF_OK(dif_aon_timer_watchdog_stop(&aon));
187 
188  rstmgr_reset_info = rstmgr_testutils_reason_get();
189  CHECK(rstmgr_reset_info == kDifRstmgrResetInfoPor);
190  CHECK(peripheral_serviced == kTopEarlgreyPlicPeripheralAonTimerAon);
191  CHECK(irq_serviced == kDifAonTimerIrqWdogTimerBark);
192 
193  CHECK_STATUS_OK(flash_ctrl_testutils_wait_transaction_end(&flash));
194 
195  CHECK_STATUS_OK(flash_ctrl_testutils_read(
196  &flash, address, kPartitionId, readback_data,
197  kDifFlashCtrlPartitionTypeData, kNumWords, 0));
198  uint32_t expected_data[kNumWords];
199  memset(expected_data, 0xff, sizeof(expected_data));
200  CHECK_ARRAYS_EQ(readback_data, expected_data, kNumWords);
201 
202  rstmgr_testutils_reason_clear();
203  } else {
204  LOG_ERROR("Unexepected reset type detected. Reset info = %08x",
205  rstmgr_reset_info);
206  return false;
207  }
208 
209  return true;
210 }