| // Copyright lowRISC contributors. | |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. | |
| // SPDX-License-Identifier: Apache-2.0 | |
| #include "sw/device/lib/testing/spi_device_testutils.h" | |
| #include "sw/device/lib/dif/dif_spi_device.h" | |
| #include "sw/device/lib/testing/test_framework/check.h" | |
| void spi_device_testutils_configure_passthrough( | |
| dif_spi_device_handle_t *spi_device, uint32_t filters, | |
| bool upload_write_commands) { | |
| dif_spi_device_config_t spi_device_config = { | |
| .clock_polarity = kDifSpiDeviceEdgePositive, | |
| .data_phase = kDifSpiDeviceEdgeNegative, | |
| .tx_order = kDifSpiDeviceBitOrderMsbToLsb, | |
| .rx_order = kDifSpiDeviceBitOrderMsbToLsb, | |
| .device_mode = kDifSpiDeviceModePassthrough, | |
| }; | |
| CHECK_DIF_OK(dif_spi_device_configure(spi_device, spi_device_config)); | |
| // Zero-init the payload memory to avoid X-triggered assertions in sim. | |
| uint8_t zeroes[256]; | |
| memset(zeroes, 0, sizeof(zeroes)); | |
| CHECK_DIF_OK(dif_spi_device_write_flash_buffer( | |
| spi_device, kDifSpiDeviceFlashBufferTypePayload, 0, sizeof(zeroes), | |
| zeroes)); | |
| dif_spi_device_passthrough_intercept_config_t intercept_config = { | |
| .status = upload_write_commands, | |
| .jedec_id = false, | |
| .sfdp = false, | |
| .mailbox = false, | |
| }; | |
| CHECK_DIF_OK(dif_spi_device_set_passthrough_intercept_config( | |
| spi_device, intercept_config)); | |
| // Set up passthrough filter to allow all commands, initially. | |
| CHECK_DIF_OK(dif_spi_device_set_all_passthrough_command_filters( | |
| spi_device, kDifToggleDisabled)); | |
| dif_spi_device_flash_command_t read_commands[] = { | |
| { | |
| // Slot 0: ReadStatus1 | |
| .opcode = kSpiDeviceFlashOpReadStatus1, | |
| .address_type = kDifSpiDeviceFlashAddrDisabled, | |
| .dummy_cycles = 0, | |
| .payload_io_type = kDifSpiDevicePayloadIoSingle, | |
| .payload_dir_to_host = true, | |
| }, | |
| { | |
| // Slot 1: ReadStatus2 | |
| .opcode = kSpiDeviceFlashOpReadStatus2, | |
| .address_type = kDifSpiDeviceFlashAddrDisabled, | |
| .dummy_cycles = 0, | |
| .payload_io_type = kDifSpiDevicePayloadIoSingle, | |
| .payload_dir_to_host = true, | |
| }, | |
| { | |
| // Slot 2: ReadStatus3 | |
| .opcode = kSpiDeviceFlashOpReadStatus3, | |
| .address_type = kDifSpiDeviceFlashAddrDisabled, | |
| .dummy_cycles = 0, | |
| .payload_io_type = kDifSpiDevicePayloadIoSingle, | |
| .payload_dir_to_host = true, | |
| }, | |
| { | |
| // Slot 3: ReadJedecID | |
| .opcode = kSpiDeviceFlashOpReadJedec, | |
| .address_type = kDifSpiDeviceFlashAddrDisabled, | |
| .dummy_cycles = 0, | |
| .payload_io_type = kDifSpiDevicePayloadIoSingle, | |
| .payload_dir_to_host = true, | |
| }, | |
| { | |
| // Slot 4: ReadSfdp | |
| .opcode = kSpiDeviceFlashOpReadSfdp, | |
| .address_type = kDifSpiDeviceFlashAddr3Byte, | |
| .dummy_cycles = 8, | |
| .payload_io_type = kDifSpiDevicePayloadIoSingle, | |
| .payload_dir_to_host = true, | |
| }, | |
| { | |
| // Slot 5: ReadNormal | |
| .opcode = kSpiDeviceFlashOpReadNormal, | |
| .address_type = kDifSpiDeviceFlashAddrCfg, | |
| .passthrough_swap_address = true, | |
| .dummy_cycles = 0, | |
| .payload_io_type = kDifSpiDevicePayloadIoSingle, | |
| .payload_dir_to_host = true, | |
| }, | |
| { | |
| // Slot 6: ReadFast | |
| .opcode = kSpiDeviceFlashOpReadFast, | |
| .address_type = kDifSpiDeviceFlashAddrCfg, | |
| .passthrough_swap_address = true, | |
| .dummy_cycles = 8, | |
| .payload_io_type = kDifSpiDevicePayloadIoSingle, | |
| .payload_dir_to_host = true, | |
| }, | |
| { | |
| // Slot 7: ReadDual | |
| .opcode = kSpiDeviceFlashOpReadDual, | |
| .address_type = kDifSpiDeviceFlashAddrCfg, | |
| .passthrough_swap_address = true, | |
| .dummy_cycles = 8, | |
| .payload_io_type = kDifSpiDevicePayloadIoDual, | |
| .payload_dir_to_host = true, | |
| }, | |
| { | |
| // Slot 8: ReadQuad | |
| .opcode = kSpiDeviceFlashOpReadQuad, | |
| .address_type = kDifSpiDeviceFlashAddrCfg, | |
| .passthrough_swap_address = true, | |
| .dummy_cycles = 8, | |
| .payload_io_type = kDifSpiDevicePayloadIoQuad, | |
| .payload_dir_to_host = true, | |
| }, | |
| }; | |
| for (int i = 0; i < ARRAYSIZE(read_commands); ++i) { | |
| uint8_t slot = i + kSpiDeviceReadCommandSlotBase; | |
| if (bitfield_bit32_read(filters, slot)) { | |
| CHECK_DIF_OK(dif_spi_device_set_passthrough_command_filter( | |
| spi_device, read_commands[i].opcode, kDifToggleEnabled)); | |
| } | |
| CHECK_DIF_OK(dif_spi_device_set_flash_command_slot( | |
| spi_device, slot, kDifToggleEnabled, read_commands[i])); | |
| } | |
| dif_spi_device_flash_command_t write_commands[] = { | |
| { | |
| // Slot 11: WriteStatus1 | |
| .opcode = kSpiDeviceFlashOpWriteStatus1, | |
| .address_type = kDifSpiDeviceFlashAddrDisabled, | |
| .payload_io_type = kDifSpiDevicePayloadIoSingle, | |
| .payload_dir_to_host = false, | |
| .upload = upload_write_commands, | |
| .set_busy_status = upload_write_commands, | |
| }, | |
| { | |
| // Slot 12: WriteStatus2 | |
| .opcode = kSpiDeviceFlashOpWriteStatus2, | |
| .address_type = kDifSpiDeviceFlashAddrDisabled, | |
| .payload_io_type = kDifSpiDevicePayloadIoSingle, | |
| .payload_dir_to_host = false, | |
| .upload = upload_write_commands, | |
| .set_busy_status = upload_write_commands, | |
| }, | |
| { | |
| // Slot 13: WriteStatus3 | |
| .opcode = kSpiDeviceFlashOpWriteStatus3, | |
| .address_type = kDifSpiDeviceFlashAddrDisabled, | |
| .payload_io_type = kDifSpiDevicePayloadIoSingle, | |
| .payload_dir_to_host = false, | |
| .upload = upload_write_commands, | |
| .set_busy_status = upload_write_commands, | |
| }, | |
| { | |
| // Slot 14: ChipErase | |
| .opcode = kSpiDeviceFlashOpChipErase, | |
| .address_type = kDifSpiDeviceFlashAddrDisabled, | |
| .payload_io_type = kDifSpiDevicePayloadIoNone, | |
| .upload = upload_write_commands, | |
| .set_busy_status = upload_write_commands, | |
| }, | |
| { | |
| // Slot 15: SectorErase | |
| .opcode = kSpiDeviceFlashOpSectorErase, | |
| .address_type = kDifSpiDeviceFlashAddrCfg, | |
| .payload_io_type = kDifSpiDevicePayloadIoNone, | |
| .upload = upload_write_commands, | |
| .set_busy_status = upload_write_commands, | |
| }, | |
| { | |
| // Slot 16: PageProgram | |
| .opcode = kSpiDeviceFlashOpPageProgram, | |
| .address_type = kDifSpiDeviceFlashAddrCfg, | |
| .payload_io_type = kDifSpiDevicePayloadIoSingle, | |
| .payload_dir_to_host = false, | |
| .upload = upload_write_commands, | |
| .set_busy_status = upload_write_commands, | |
| }, | |
| }; | |
| for (int i = 0; i < ARRAYSIZE(write_commands); ++i) { | |
| uint8_t slot = i + kSpiDeviceWriteCommandSlotBase; | |
| if (bitfield_bit32_read(filters, slot) || upload_write_commands) { | |
| CHECK_DIF_OK(dif_spi_device_set_passthrough_command_filter( | |
| spi_device, write_commands[i].opcode, kDifToggleEnabled)); | |
| } | |
| CHECK_DIF_OK(dif_spi_device_set_flash_command_slot( | |
| spi_device, slot, kDifToggleEnabled, write_commands[i])); | |
| } | |
| // This configuration for these commands does not guard against misbehaved | |
| // hosts. The timing of any of these commands relative to an uploaded command | |
| // cannot be determined. | |
| CHECK_DIF_OK(dif_spi_device_configure_flash_wren_command( | |
| spi_device, kDifToggleEnabled, kSpiDeviceFlashOpWriteEnable)); | |
| CHECK_DIF_OK(dif_spi_device_configure_flash_wrdi_command( | |
| spi_device, kDifToggleEnabled, kSpiDeviceFlashOpWriteDisable)); | |
| CHECK_DIF_OK(dif_spi_device_configure_flash_en4b_command( | |
| spi_device, kDifToggleEnabled, kSpiDeviceFlashOpEnter4bAddr)); | |
| CHECK_DIF_OK(dif_spi_device_configure_flash_ex4b_command( | |
| spi_device, kDifToggleEnabled, kSpiDeviceFlashOpExit4bAddr)); | |
| if (upload_write_commands) { | |
| CHECK_DIF_OK(dif_spi_device_set_passthrough_command_filter( | |
| spi_device, kSpiDeviceFlashOpReadStatus1, kDifToggleEnabled)); | |
| CHECK_DIF_OK(dif_spi_device_set_passthrough_command_filter( | |
| spi_device, kSpiDeviceFlashOpReadStatus2, kDifToggleEnabled)); | |
| CHECK_DIF_OK(dif_spi_device_set_passthrough_command_filter( | |
| spi_device, kSpiDeviceFlashOpReadStatus3, kDifToggleEnabled)); | |
| CHECK_DIF_OK(dif_spi_device_set_passthrough_command_filter( | |
| spi_device, kSpiDeviceFlashOpWriteEnable, kDifToggleEnabled)); | |
| CHECK_DIF_OK(dif_spi_device_set_passthrough_command_filter( | |
| spi_device, kSpiDeviceFlashOpWriteDisable, kDifToggleEnabled)); | |
| } | |
| } |