blob: ded7c2b7e41c98bbcda0f87d0309031c8c9e8ae6 [file] [log] [blame]
// 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));
}
}