10 #include "dt/dt_pinmux.h"
11 #include "dt/dt_rv_plic.h"
12 #include "dt/dt_spi_device.h"
13 #include "dt/dt_spi_host.h"
22 #include "sw/device/lib/runtime/irq.h"
24 #include "sw/device/lib/testing/pinmux_testutils.h"
25 #include "sw/device/lib/testing/spi_device_testutils.h"
26 #include "sw/device/lib/testing/spi_flash_testutils.h"
27 #include "sw/device/lib/testing/spi_host_testutils.h"
28 #include "sw/device/lib/testing/test_framework/check.h"
31 OTTF_DEFINE_TEST_CONFIG();
35 const volatile uint32_t kFilteredCommands;
38 const volatile uint8_t kUploadWriteCommands;
40 static const uint32_t kPlicTarget = 0;
41 static dif_pinmux_t pinmux;
42 static dt_pinmux_t kPinmuxDt = (dt_pinmux_t)0;
43 static_assert(kDtPinmuxCount >= 1,
"This test requires Pinmux");
44 static dif_rv_plic_t rv_plic;
45 static dt_rv_plic_t kRvPlicDt = (dt_rv_plic_t)0;
46 static_assert(kDtRvPlicCount >= 1,
"This test requires a RV PLIC");
48 static dt_spi_device_t kSpiDeviceDt = (dt_spi_device_t)0;
49 static_assert(kDtSpiDeviceCount >= 1,
50 "This test requires one SPI Device instance");
51 static dif_spi_host_t spi_hosts[kDtSpiHostCount];
52 static dt_spi_host_t kSpiHost0Dt = (dt_spi_host_t)0;
53 static_assert(kDtSpiHostCount >= 1,
54 "This test requiest at least one SPI Host instance");
58 #if defined(OPENTITAN_IS_EARLGREY)
61 .flags = kDifPinmuxPadAttrPullResistorEnable |
62 kDifPinmuxPadAttrPullResistorUp,
66 .flags = kDifPinmuxPadAttrPullResistorEnable |
67 kDifPinmuxPadAttrPullResistorUp,
69 #elif defined(OPENTITAN_IS_DARJEELING)
72 #error "spi_passthrough_test does not support this top"
75 .pad = kDtPadSpiHost0Sd0,
76 .flags = kDifPinmuxPadAttrPullResistorEnable |
77 kDifPinmuxPadAttrPullResistorUp,
80 .pad = kDtPadSpiHost0Sd1,
81 .flags = kDifPinmuxPadAttrPullResistorEnable |
82 kDifPinmuxPadAttrPullResistorUp,
85 .pad = kDtPadSpiHost0Sd2,
86 .flags = kDifPinmuxPadAttrPullResistorEnable |
87 kDifPinmuxPadAttrPullResistorUp,
90 .pad = kDtPadSpiHost0Sd3,
91 .flags = kDifPinmuxPadAttrPullResistorEnable |
92 kDifPinmuxPadAttrPullResistorUp,
96 #if defined(OPENTITAN_IS_EARLGREY)
103 dt_spi_host_t peripheral_dt;
104 dt_spi_host_periph_io_t peripheral_sig;
110 .peripheral_dt = kDtSpiHost1,
111 .peripheral_sig = kDtSpiHostPeriphIoCsb,
115 .peripheral_dt = kDtSpiHost1,
116 .peripheral_sig = kDtSpiHostPeriphIoSck,
120 .peripheral_dt = kDtSpiHost1,
121 .peripheral_sig = kDtSpiHostPeriphIoSd0,
125 .peripheral_dt = kDtSpiHost1,
126 .peripheral_sig = kDtSpiHostPeriphIoSd1,
144 .peripheral_dt = kDtSpiHost1,
145 .peripheral_sig = kDtSpiHostPeriphIoSd0,
149 .peripheral_dt = kDtSpiHost1,
150 .peripheral_sig = kDtSpiHostPeriphIoSd1,
164 #elif defined(OPENTITAN_IS_DARJEELING)
167 #error "spi_passthrough_test does not support this top"
175 void init_spi_host(dif_spi_host_t *spi_host,
176 uint32_t peripheral_clock_freq_hz) {
178 .
spi_clock = peripheral_clock_freq_hz / 2,
179 .peripheral_clock_freq_hz = peripheral_clock_freq_hz,
202 void handle_write_status(uint32_t
status, uint8_t offset, uint8_t opcode) {
205 uint32_t start_offset;
207 &spi_device, &occupancy, &start_offset));
208 CHECK(occupancy == 1);
210 &spi_device, start_offset, occupancy, &payload));
212 status &= (0xffu << offset);
213 status |= ((uint32_t)(payload) << offset);
216 CHECK_STATUS_OK(spi_flash_testutils_issue_write_enable(&spi_hosts[0]));
233 CHECK_STATUS_OK(spi_flash_testutils_wait_until_not_busy(&spi_hosts[0]));
242 void handle_chip_erase(
void) {
243 CHECK_STATUS_OK(spi_flash_testutils_erase_chip(&spi_hosts[0]));
252 void handle_sector_erase(
void) {
256 CHECK(occupancy == 1);
267 spi_flash_testutils_erase_sector(&spi_hosts[0], address, addr_is_4b));
276 void handle_page_program(
void) {
277 uint8_t address_occupancy;
279 &spi_device, &address_occupancy));
280 CHECK(address_occupancy == 1);
285 uint8_t payload[256];
286 uint16_t payload_occupancy;
287 uint32_t start_offset;
289 &spi_device, &payload_occupancy, &start_offset));
290 CHECK(start_offset == 0);
291 CHECK(payload_occupancy <=
sizeof(payload));
293 &spi_device, start_offset, payload_occupancy, payload));
300 CHECK_STATUS_OK(spi_flash_testutils_program_page(
301 &spi_hosts[0], payload, payload_occupancy, address, addr_is_4b));
307 void spi_device_process_upload_fifo(
void) {
309 CHECK_DIF_OK(dif_spi_device_irq_get_type(
310 &spi_device.
dev, kDifSpiDeviceIrqUploadCmdfifoNotEmpty, &irq_type));
312 CHECK_DIF_OK(dif_spi_device_irq_acknowledge(
313 &spi_device.
dev, kDifSpiDeviceIrqUploadCmdfifoNotEmpty));
320 CHECK(
status & kSpiFlashStatusBitWip);
321 CHECK(
status & kSpiFlashStatusBitWel);
328 if (command == kSpiDeviceFlashOpWriteStatus1) {
329 handle_write_status(
status, 0, command);
330 }
else if (command == kSpiDeviceFlashOpWriteStatus2) {
331 handle_write_status(
status, 8, command);
332 }
else if (command == kSpiDeviceFlashOpWriteStatus3) {
333 handle_write_status(
status, 16, command);
334 }
else if (command == kSpiDeviceFlashOpChipErase) {
336 }
else if (command == kSpiDeviceFlashOpSectorErase) {
337 handle_sector_erase();
338 }
else if (command == kSpiDeviceFlashOpPageProgram) {
339 handle_page_program();
341 CHECK(
false,
"Received unexpected command 0x%x", command);
344 CHECK_DIF_OK(dif_spi_device_irq_set_enabled(
345 &spi_device.
dev, kDifSpiDeviceIrqUploadCmdfifoNotEmpty,
355 void spi_device_isr(
void) {
356 bool cmdfifo_not_empty;
357 CHECK_DIF_OK(dif_spi_device_irq_is_pending(
358 &spi_device.
dev, kDifSpiDeviceIrqUploadCmdfifoNotEmpty,
359 &cmdfifo_not_empty));
360 CHECK(cmdfifo_not_empty);
361 CHECK_DIF_OK(dif_spi_device_irq_set_enabled(
362 &spi_device.
dev, kDifSpiDeviceIrqUploadCmdfifoNotEmpty,
371 void ottf_external_isr(uint32_t *exc_info) {
375 dt_instance_id_t peripheral_id = dt_plic_id_to_instance_id(plic_irq_id);
376 if (peripheral_id == dt_spi_device_instance_id(kSpiDeviceDt)) {
377 dt_spi_device_irq_t irq =
378 dt_spi_device_irq_from_plic_id(kSpiDeviceDt, plic_irq_id);
379 CHECK(irq == kDtSpiDeviceIrqUploadCmdfifoNotEmpty);
389 CHECK_DIF_OK(dif_pinmux_init_from_dt(kPinmuxDt, &pinmux));
390 pinmux_testutils_init(&pinmux);
391 pinmux_testutils_configure_pads(&pinmux, pinmux_pad_config,
393 #if defined(OPENTITAN_IS_EARLGREY)
394 for (
int i = 0; i <
ARRAYSIZE(pinmux_in_config); ++i) {
396 dt_periph_io_t peripheral =
397 dt_spi_host_periph_io(setting.peripheral_dt, setting.peripheral_sig);
400 for (
int i = 0; i <
ARRAYSIZE(pinmux_out_config); ++i) {
402 dt_periph_io_t peripheral =
403 dt_spi_host_periph_io(setting.peripheral_dt, setting.peripheral_sig);
407 #elif defined(OPENTITAN_IS_DARJEELING)
410 #error "spi_passthrough_test does not support this top"
415 CHECK_STATUS_OK(spi_host_testutils_configure_host0_pad_attrs(&pinmux));
418 CHECK_STATUS_OK(spi_device_testutils_configure_pad_attrs(&pinmux));
421 CHECK_DIF_OK(dif_rv_plic_init_from_dt(kRvPlicDt, &rv_plic));
424 for (
size_t i = 0; i < kDtSpiHostCount; i++) {
425 dt_spi_host_t spi_host_dt = (dt_spi_host_t)i;
426 uint32_t clock_freq =
427 dt_clock_frequency(dt_spi_host_clock(spi_host_dt, kDtSpiHostClockClk));
428 CHECK_DIF_OK(dif_spi_host_init_from_dt(spi_host_dt, &spi_hosts[i]));
429 init_spi_host(&spi_hosts[i], clock_freq);
433 CHECK_DIF_OK(dif_spi_device_init_from_dt(kSpiDeviceDt, &spi_device.
dev));
434 bool upload_write_commands = (kUploadWriteCommands != 0);
435 CHECK_STATUS_OK(spi_device_testutils_configure_passthrough(
436 &spi_device, kFilteredCommands, upload_write_commands));
440 for (
int i = 0; i < kDtSpiDeviceIrqCount; ++i) {
441 dt_spi_device_irq_t spi_irq = (dt_spi_device_irq_t)i;
442 CHECK_DIF_OK(dif_spi_device_irq_set_enabled(&spi_device.
dev, spi_irq,
445 dt_spi_device_irq_to_plic_id(kSpiDeviceDt, spi_irq);
450 for (
int i = 0; i < kDtSpiHostIrqCount; ++i) {
451 dt_spi_host_irq_t spi_irq = (dt_spi_host_irq_t)i;
452 CHECK_DIF_OK(dif_spi_host_irq_set_enabled(&spi_hosts[0], spi_irq,
459 irq_external_ctrl(
true);
467 bool cmdfifo_not_empty_irq_pending;
468 irq_global_ctrl(
false);
469 CHECK_DIF_OK(dif_spi_device_irq_is_pending(
470 &spi_device.
dev, kDifSpiDeviceIrqUploadCmdfifoNotEmpty,
471 &cmdfifo_not_empty_irq_pending));
472 if (!cmdfifo_not_empty_irq_pending) {
475 irq_global_ctrl(
true);
476 spi_device_process_upload_fifo();