26 #include "sw/device/lib/runtime/irq.h"
29 #include "sw/device/lib/testing/rv_plic_testutils.h"
30 #include "sw/device/lib/testing/spi_device_testutils.h"
31 #include "sw/device/lib/testing/spi_flash_testutils.h"
32 #include "sw/device/lib/testing/spi_host_testutils.h"
33 #include "sw/device/lib/testing/test_framework/check.h"
37 #include "spi_host_regs.h"
39 static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__,
40 "This test assumes the target platform is little endian.");
42 OTTF_DEFINE_TEST_CONFIG();
44 dif_spi_host_t spi_host;
51 static volatile status_t test_result;
53 static volatile dif_spi_host_irq_t irq_fired;
54 static dif_rv_plic_t plic;
81 "IRQ from incorrect peripheral: exp = %d(spi_host0), found = %d",
84 irq_fired = (dif_spi_host_irq_t)(plic_irq_id -
90 TRY(dif_spi_host_irq_get_type(&spi_host, irq_fired, &irq_type));
93 TRY(dif_spi_host_irq_acknowledge(&spi_host, irq_fired));
101 TRY(dif_spi_host_irq_set_enabled(&spi_host, irq_fired,
105 LOG_ERROR(
"Unexpected interrupt type: %d", irq_type);
114 void ottf_external_isr(uint32_t *exc_info) { test_result = external_isr(); }
116 static status_t active_event_irq(
void) {
118 memset(data, 0xA5,
sizeof(data));
120 irq_fired = UINT32_MAX;
124 TRY_CHECK(!
status.active);
136 ATOMIC_WAIT_FOR_INTERRUPT(irq_fired == kDifSpiHostIrqSpiEvent);
143 CHECK_DIF_OK(dif_spi_host_irq_set_enabled(&spi_host, kDifSpiHostIrqSpiEvent,
149 static status_t ready_event_irq(
void) {
150 enum { kDataSize = 260, kCommands = 5 };
151 static_assert(kDataSize % kCommands == 0,
"Must be multiple.");
153 uint8_t data[kDataSize];
154 memset(data, 0xA5, kDataSize);
157 irq_fired = UINT32_MAX;
161 TRY_CHECK(!
status.active);
165 for (
size_t i = 0; i < kCommands; ++i) {
173 ATOMIC_WAIT_FOR_INTERRUPT(irq_fired == kDifSpiHostIrqSpiEvent);
180 CHECK_DIF_OK(dif_spi_host_irq_set_enabled(&spi_host, kDifSpiHostIrqSpiEvent,
186 static status_t tx_empty_event_irq(
void) {
188 memset(data, 0xA5,
sizeof(data));
190 irq_fired = UINT32_MAX;
194 TRY_CHECK(
status.tx_empty);
204 ATOMIC_WAIT_FOR_INTERRUPT(irq_fired == kDifSpiHostIrqSpiEvent);
211 CHECK_DIF_OK(dif_spi_host_irq_set_enabled(&spi_host, kDifSpiHostIrqSpiEvent,
216 static status_t tx_wm_event_irq(
void) {
217 uint8_t data[kTxWatermark *
sizeof(uint32_t) + 1];
218 memset(data, 0xA5,
sizeof(data));
220 irq_fired = UINT32_MAX;
224 TRY_CHECK(
status.tx_water_mark);
229 TRY_CHECK(
status.tx_queue_depth >= kTxWatermark,
"%d",
status.tx_queue_depth);
230 TRY_CHECK(!
status.tx_water_mark);
238 ATOMIC_WAIT_FOR_INTERRUPT(irq_fired == kDifSpiHostIrqSpiEvent);
245 CHECK_DIF_OK(dif_spi_host_irq_set_enabled(&spi_host, kDifSpiHostIrqSpiEvent,
250 static status_t dummy_read_from_flash(uint32_t address, uint16_t len) {
257 uint8_t opcode = kSpiDeviceFlashOpReadNormal;
274 static status_t rx_full_event_irq(
void) {
275 enum { kRxFifoLen = SPI_HOST_PARAM_RX_DEPTH *
sizeof(uint32_t) };
276 static_assert(kRxFifoLen <= UINT16_MAX,
"kRxFifoLen must fit in uint16_t");
277 irq_fired = UINT32_MAX;
281 TRY_CHECK(!
status.rx_full);
283 TRY(dummy_read_from_flash(0x00, kRxFifoLen));
287 ATOMIC_WAIT_FOR_INTERRUPT(irq_fired == kDifSpiHostIrqSpiEvent);
294 CHECK_DIF_OK(dif_spi_host_irq_set_enabled(&spi_host, kDifSpiHostIrqSpiEvent,
296 return spi_host_testutils_flush(&spi_host);
299 static status_t rx_wm_event_irq(
void) {
300 enum { kRxWmLen = kRxWatermark *
sizeof(uint32_t) };
302 irq_fired = UINT32_MAX;
306 TRY_CHECK(!
status.rx_water_mark);
308 TRY(dummy_read_from_flash(0x00, kRxWmLen));
312 ATOMIC_WAIT_FOR_INTERRUPT(irq_fired == kDifSpiHostIrqSpiEvent);
319 CHECK_DIF_OK(dif_spi_host_irq_set_enabled(&spi_host, kDifSpiHostIrqSpiEvent,
325 static status_t cmd_busy_error_irq(
void) {
330 static_assert(kDataSize % kCommands == 0,
"Must be multiple.");
332 uint8_t data[kDataSize];
333 memset(data, 0xA5, kDataSize);
336 irq_fired = UINT32_MAX;
341 TRY_CHECK(!
status.active);
345 for (
size_t i = 0; i < kCommands; ++i) {
357 ATOMIC_WAIT_FOR_INTERRUPT(irq_fired == kDifSpiHostIrqError);
372 TRY(dif_spi_host_init(base_addr, &spi_host));
374 uint32_t spi_clock_freq_hz = 1000000;
379 spi_clock_freq_hz = 100000;
382 "kClockFreqHiSpeedPeripheralHz must fit in uint32_t");
386 .spi_clock = spi_clock_freq_hz,
388 .rx_watermark = kRxWatermark,
389 .tx_watermark = kTxWatermark,
394 TRY(dif_rv_plic_init(base_addr, &plic));
396 rv_plic_testutils_irq_range_enable(&plic, kHart,
400 dif_spi_host_irq_state_snapshot_t spi_host_irqs =
401 (dif_spi_host_irq_state_snapshot_t)UINT_MAX;
402 TRY(dif_spi_host_irq_restore_all(&spi_host, &spi_host_irqs));
404 irq_global_ctrl(
true);
405 irq_external_ctrl(
true);
410 CHECK_STATUS_OK(test_init());
411 test_result = OK_STATUS();
421 return status_ok(test_result);