[spi_device] Add most DIFs for flash / passthrough

DIFs for handling the general command info table, passthrough filters,
address and data swapping, basic FIFO and memory interaction, flash
status registers, address modes, and identification are all contained in
this commit.

Signed-off-by: Alexander Williams <awill@google.com>
diff --git a/sw/device/lib/dif/dif_spi_device.c b/sw/device/lib/dif/dif_spi_device.c
index 92b895c..6bf058a 100644
--- a/sw/device/lib/dif/dif_spi_device.c
+++ b/sw/device/lib/dif/dif_spi_device.c
@@ -12,6 +12,18 @@
 
 const uint16_t kDifSpiDeviceBufferLen = SPI_DEVICE_BUFFER_SIZE_BYTES;
 
+enum { kDifSpiDeviceEFlashLen = 2048 };
+enum { kDifSpiDeviceMailboxLen = 1024 };
+enum { kDifSpiDeviceSfdpLen = 256 };
+enum { kDifSpiDevicePayloadLen = 256 };
+
+enum {
+  kDifSpiDeviceEFlashOffset = 0,
+  kDifSpiDeviceMailboxOffset = 2048,
+  kDifSpiDeviceSfdpOffset = 3072,
+  kDifSpiDevicePayloadOffset = 3328,
+};
+
 /**
  * Computes the required value of the control register from a given
  * configuration.
@@ -56,6 +68,12 @@
     case kDifSpiDeviceModeGeneric:
       device_mode = SPI_DEVICE_CONTROL_MODE_VALUE_FWMODE;
       break;
+    case kDifSpiDeviceModeFlashEmulation:
+      device_mode = SPI_DEVICE_CONTROL_MODE_VALUE_FLASHMODE;
+      break;
+    case kDifSpiDeviceModePassthrough:
+      device_mode = SPI_DEVICE_CONTROL_MODE_VALUE_PASSTHROUGH;
+      break;
     default:
       return kDifBadArg;
   }
@@ -476,3 +494,539 @@
   }
   return kDifOk;
 }
+
+dif_result_t dif_spi_device_enable_mailbox(dif_spi_device_handle_t *spi,
+                                           uint32_t address) {
+  if (spi == NULL) {
+    return kDifBadArg;
+  }
+  mmio_region_write32(spi->dev.base_addr, SPI_DEVICE_MAILBOX_ADDR_REG_OFFSET,
+                      address);
+  uint32_t cfg_reg =
+      mmio_region_read32(spi->dev.base_addr, SPI_DEVICE_CFG_REG_OFFSET);
+  cfg_reg = bitfield_bit32_write(cfg_reg, SPI_DEVICE_CFG_MAILBOX_EN_BIT, 1);
+  mmio_region_write32(spi->dev.base_addr, SPI_DEVICE_CFG_REG_OFFSET, cfg_reg);
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_disable_mailbox(dif_spi_device_handle_t *spi) {
+  if (spi == NULL) {
+    return kDifBadArg;
+  }
+  uint32_t cfg_reg =
+      mmio_region_read32(spi->dev.base_addr, SPI_DEVICE_CFG_REG_OFFSET);
+  cfg_reg = bitfield_bit32_write(cfg_reg, SPI_DEVICE_CFG_MAILBOX_EN_BIT, 0);
+  mmio_region_write32(spi->dev.base_addr, SPI_DEVICE_CFG_REG_OFFSET, cfg_reg);
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_get_mailbox_configuration(
+    dif_spi_device_handle_t *spi, dif_toggle_t *is_enabled, uint32_t *address) {
+  if (spi == NULL || is_enabled == NULL || address == NULL) {
+    return kDifBadArg;
+  }
+  uint32_t cfg_reg =
+      mmio_region_read32(spi->dev.base_addr, SPI_DEVICE_CFG_REG_OFFSET);
+  bool mailbox_enabled =
+      bitfield_bit32_read(cfg_reg, SPI_DEVICE_CFG_MAILBOX_EN_BIT);
+  *is_enabled = dif_bool_to_toggle(mailbox_enabled);
+  *address = mmio_region_read32(spi->dev.base_addr,
+                                SPI_DEVICE_MAILBOX_ADDR_REG_OFFSET);
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_set_4b_address_mode(dif_spi_device_handle_t *spi,
+                                                dif_toggle_t addr_4b) {
+  if (spi == NULL || !dif_is_valid_toggle(addr_4b)) {
+    return kDifBadArg;
+  }
+  uint32_t cfg_reg =
+      mmio_region_read32(spi->dev.base_addr, SPI_DEVICE_CFG_REG_OFFSET);
+  if (addr_4b == kDifToggleEnabled) {
+    cfg_reg =
+        bitfield_bit32_write(cfg_reg, SPI_DEVICE_CFG_ADDR_4B_EN_BIT, true);
+  } else {
+    cfg_reg =
+        bitfield_bit32_write(cfg_reg, SPI_DEVICE_CFG_ADDR_4B_EN_BIT, false);
+  }
+  mmio_region_write32(spi->dev.base_addr, SPI_DEVICE_CFG_REG_OFFSET, cfg_reg);
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_get_4b_address_mode(dif_spi_device_handle_t *spi,
+                                                dif_toggle_t *addr_4b) {
+  if (spi == NULL || addr_4b == NULL) {
+    return kDifBadArg;
+  }
+  uint32_t cfg_reg =
+      mmio_region_read32(spi->dev.base_addr, SPI_DEVICE_CFG_REG_OFFSET);
+  if (bitfield_bit32_read(cfg_reg, SPI_DEVICE_CFG_ADDR_4B_EN_BIT)) {
+    *addr_4b = kDifToggleEnabled;
+  } else {
+    *addr_4b = kDifToggleDisabled;
+  }
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_get_flash_id(dif_spi_device_handle_t *spi,
+                                         dif_spi_device_flash_id_t *id) {
+  if (spi == NULL || id == NULL) {
+    return kDifBadArg;
+  }
+  uint32_t cc_reg =
+      mmio_region_read32(spi->dev.base_addr, SPI_DEVICE_JEDEC_CC_REG_OFFSET);
+  uint32_t id_reg =
+      mmio_region_read32(spi->dev.base_addr, SPI_DEVICE_JEDEC_ID_REG_OFFSET);
+  id->num_continuation_code =
+      bitfield_field32_read(cc_reg, SPI_DEVICE_JEDEC_CC_NUM_CC_FIELD);
+  id->continuation_code =
+      bitfield_field32_read(cc_reg, SPI_DEVICE_JEDEC_CC_CC_FIELD);
+  id->manufacturer_id =
+      bitfield_field32_read(id_reg, SPI_DEVICE_JEDEC_ID_MF_FIELD);
+  id->device_id = bitfield_field32_read(id_reg, SPI_DEVICE_JEDEC_ID_ID_FIELD);
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_set_flash_id(dif_spi_device_handle_t *spi,
+                                         dif_spi_device_flash_id_t id) {
+  if (spi == NULL) {
+    return kDifBadArg;
+  }
+  uint32_t cc_reg = bitfield_field32_write(0, SPI_DEVICE_JEDEC_CC_NUM_CC_FIELD,
+                                           id.num_continuation_code);
+  cc_reg = bitfield_field32_write(cc_reg, SPI_DEVICE_JEDEC_CC_CC_FIELD,
+                                  id.continuation_code);
+  uint32_t id_reg = bitfield_field32_write(0, SPI_DEVICE_JEDEC_ID_MF_FIELD,
+                                           id.manufacturer_id);
+  id_reg = bitfield_field32_write(id_reg, SPI_DEVICE_JEDEC_ID_ID_FIELD,
+                                  id.device_id);
+  mmio_region_write32(spi->dev.base_addr, SPI_DEVICE_JEDEC_CC_REG_OFFSET,
+                      cc_reg);
+  mmio_region_write32(spi->dev.base_addr, SPI_DEVICE_JEDEC_ID_REG_OFFSET,
+                      id_reg);
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_set_flash_command_slot(
+    dif_spi_device_handle_t *spi, uint8_t slot, dif_toggle_t enable,
+    dif_spi_device_flash_command_t command_info) {
+  if (spi == NULL || slot >= SPI_DEVICE_PARAM_NUM_CMD_INFO ||
+      !dif_is_valid_toggle(enable)) {
+    return kDifBadArg;
+  }
+  ptrdiff_t reg_offset =
+      SPI_DEVICE_CMD_INFO_0_REG_OFFSET + slot * sizeof(uint32_t);
+  uint32_t reg_val = 0;
+  if (enable == kDifToggleDisabled) {
+    reg_val =
+        bitfield_bit32_write(reg_val, SPI_DEVICE_CMD_INFO_0_VALID_0_BIT, false);
+  } else {
+    // Validate command info parameters.
+    uint32_t address_mode;
+    switch (command_info.address_type) {
+      case kDifSpiDeviceFlashAddrDisabled:
+        address_mode = SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDRDISABLED;
+        break;
+      case kDifSpiDeviceFlashAddrCfg:
+        address_mode = SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDRCFG;
+        break;
+      case kDifSpiDeviceFlashAddr3Byte:
+        address_mode = SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDR3B;
+        break;
+      case kDifSpiDeviceFlashAddr4Byte:
+        address_mode = SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDR4B;
+        break;
+      default:
+        return kDifBadArg;
+    }
+    if (command_info.dummy_cycles >
+        (1u + SPI_DEVICE_CMD_INFO_0_DUMMY_SIZE_0_MASK)) {
+      return kDifBadArg;
+    }
+
+    uint32_t payload_en;
+    switch (command_info.payload_io_type) {
+      case kDifSpiDevicePayloadIoNone:
+        payload_en = 0x0;
+        break;
+      case kDifSpiDevicePayloadIoSingle:
+        if (command_info.payload_dir_to_host) {
+          payload_en = 0x2;
+        } else {
+          payload_en = 0x1;
+        }
+        break;
+      case kDifSpiDevicePayloadIoDual:
+        payload_en = 0x3;
+        break;
+      case kDifSpiDevicePayloadIoQuad:
+        payload_en = 0xf;
+        break;
+      default:
+        return kDifBadArg;
+    }
+
+    // Check for invalid argument combinations.
+    if (command_info.payload_swap_enable &&
+        (command_info.payload_dir_to_host ||
+         command_info.payload_io_type != kDifSpiDevicePayloadIoSingle)) {
+      return kDifBadArg;
+    }
+    if (command_info.passthrough_swap_address &&
+        command_info.address_type == kDifSpiDeviceFlashAddrDisabled) {
+      return kDifBadArg;
+    }
+
+    // Write the command info values.
+    reg_val = bitfield_field32_write(
+        reg_val, SPI_DEVICE_CMD_INFO_0_OPCODE_0_FIELD, command_info.opcode);
+    reg_val = bitfield_field32_write(
+        reg_val, SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_FIELD, address_mode);
+    reg_val =
+        bitfield_bit32_write(reg_val, SPI_DEVICE_CMD_INFO_0_ADDR_SWAP_EN_0_BIT,
+                             command_info.passthrough_swap_address);
+    if (command_info.dummy_cycles > 0) {
+      reg_val = bitfield_field32_write(reg_val,
+                                       SPI_DEVICE_CMD_INFO_0_DUMMY_SIZE_0_FIELD,
+                                       command_info.dummy_cycles - 1);
+      reg_val = bitfield_bit32_write(
+          reg_val, SPI_DEVICE_CMD_INFO_0_DUMMY_EN_0_BIT, true);
+    }
+    reg_val = bitfield_field32_write(
+        reg_val, SPI_DEVICE_CMD_INFO_0_PAYLOAD_EN_0_FIELD, payload_en);
+    reg_val =
+        bitfield_bit32_write(reg_val, SPI_DEVICE_CMD_INFO_0_PAYLOAD_DIR_0_BIT,
+                             command_info.payload_dir_to_host);
+    reg_val = bitfield_bit32_write(reg_val,
+                                   SPI_DEVICE_CMD_INFO_0_PAYLOAD_SWAP_EN_0_BIT,
+                                   command_info.payload_swap_enable);
+    reg_val = bitfield_bit32_write(reg_val, SPI_DEVICE_CMD_INFO_0_UPLOAD_0_BIT,
+                                   command_info.upload);
+    reg_val = bitfield_bit32_write(reg_val, SPI_DEVICE_CMD_INFO_0_BUSY_0_BIT,
+                                   command_info.set_busy_status);
+    reg_val =
+        bitfield_bit32_write(reg_val, SPI_DEVICE_CMD_INFO_0_VALID_0_BIT, true);
+  }
+  mmio_region_write32(spi->dev.base_addr, reg_offset, reg_val);
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_get_flash_command_slot(
+    dif_spi_device_handle_t *spi, uint8_t slot, dif_toggle_t *enabled,
+    dif_spi_device_flash_command_t *command_info) {
+  if (spi == NULL || enabled == NULL || command_info == NULL ||
+      slot >= SPI_DEVICE_PARAM_NUM_CMD_INFO) {
+    return kDifBadArg;
+  }
+  ptrdiff_t reg_offset =
+      SPI_DEVICE_CMD_INFO_0_REG_OFFSET + slot * sizeof(uint32_t);
+  uint32_t reg_val = mmio_region_read32(spi->dev.base_addr, reg_offset);
+
+  dif_spi_device_flash_address_type_t address_type;
+  uint32_t reg_val_address_mode =
+      bitfield_field32_read(reg_val, SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_FIELD);
+  switch (reg_val_address_mode) {
+    case SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDRDISABLED:
+      address_type = kDifSpiDeviceFlashAddrDisabled;
+      break;
+    case SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDRCFG:
+      address_type = kDifSpiDeviceFlashAddrCfg;
+      break;
+    case SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDR3B:
+      address_type = kDifSpiDeviceFlashAddr3Byte;
+      break;
+    case SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDR4B:
+      address_type = kDifSpiDeviceFlashAddr4Byte;
+      break;
+    default:
+      address_type = kDifSpiDeviceFlashAddrCount;
+      break;
+  }
+
+  uint32_t dummy_cycles;
+  if (bitfield_bit32_read(reg_val, SPI_DEVICE_CMD_INFO_0_DUMMY_EN_0_BIT)) {
+    dummy_cycles = 1 + bitfield_field32_read(
+                           reg_val, SPI_DEVICE_CMD_INFO_0_DUMMY_SIZE_0_FIELD);
+  } else {
+    dummy_cycles = 0;
+  }
+
+  uint32_t payload_en =
+      bitfield_field32_read(reg_val, SPI_DEVICE_CMD_INFO_0_PAYLOAD_EN_0_FIELD);
+  bool payload_dir_to_host =
+      bitfield_bit32_read(reg_val, SPI_DEVICE_CMD_INFO_0_PAYLOAD_DIR_0_BIT);
+  dif_spi_device_payload_io_t payload_io_type;
+  switch (payload_en) {
+    case 0x0:
+      payload_io_type = kDifSpiDevicePayloadIoNone;
+      break;
+    case 0x1:
+      if (payload_dir_to_host) {
+        payload_io_type = kDifSpiDevicePayloadIoInvalid;
+      } else {
+        payload_io_type = kDifSpiDevicePayloadIoSingle;
+      }
+      break;
+    case 0x2:
+      if (!payload_dir_to_host) {
+        payload_io_type = kDifSpiDevicePayloadIoInvalid;
+      } else {
+        payload_io_type = kDifSpiDevicePayloadIoSingle;
+      }
+      break;
+    case 0x3:
+      payload_io_type = kDifSpiDevicePayloadIoDual;
+      break;
+    case 0xf:
+      payload_io_type = kDifSpiDevicePayloadIoQuad;
+      break;
+    default:
+      payload_io_type = kDifSpiDevicePayloadIoInvalid;
+      break;
+  }
+
+  dif_spi_device_flash_command_t cmd = {
+      .opcode =
+          bitfield_field32_read(reg_val, SPI_DEVICE_CMD_INFO_0_OPCODE_0_FIELD),
+      .address_type = address_type,
+      .dummy_cycles = dummy_cycles,
+      .payload_io_type = payload_io_type,
+      .passthrough_swap_address = bitfield_bit32_read(
+          reg_val, SPI_DEVICE_CMD_INFO_0_PAYLOAD_SWAP_EN_0_BIT),
+      .payload_dir_to_host = payload_dir_to_host,
+      .payload_swap_enable = bitfield_bit32_read(
+          reg_val, SPI_DEVICE_CMD_INFO_0_PAYLOAD_SWAP_EN_0_BIT),
+      .upload =
+          bitfield_bit32_read(reg_val, SPI_DEVICE_CMD_INFO_0_UPLOAD_0_BIT),
+      .set_busy_status =
+          bitfield_bit32_read(reg_val, SPI_DEVICE_CMD_INFO_0_BUSY_0_BIT),
+  };
+  *command_info = cmd;
+
+  if (bitfield_bit32_read(reg_val, SPI_DEVICE_CMD_INFO_0_VALID_0_BIT)) {
+    *enabled = kDifToggleEnabled;
+  } else {
+    *enabled = kDifToggleDisabled;
+  }
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_set_flash_address_swap(dif_spi_device_handle_t *spi,
+                                                   uint32_t mask,
+                                                   uint32_t replacement) {
+  if (spi == NULL) {
+    return kDifBadArg;
+  }
+  mmio_region_write32(spi->dev.base_addr, SPI_DEVICE_ADDR_SWAP_MASK_REG_OFFSET,
+                      mask);
+  mmio_region_write32(spi->dev.base_addr, SPI_DEVICE_ADDR_SWAP_DATA_REG_OFFSET,
+                      replacement);
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_set_flash_payload_swap(dif_spi_device_handle_t *spi,
+                                                   uint32_t mask,
+                                                   uint32_t replacement) {
+  if (spi == NULL) {
+    return kDifBadArg;
+  }
+  mmio_region_write32(spi->dev.base_addr,
+                      SPI_DEVICE_PAYLOAD_SWAP_MASK_REG_OFFSET, mask);
+  mmio_region_write32(spi->dev.base_addr,
+                      SPI_DEVICE_PAYLOAD_SWAP_DATA_REG_OFFSET, replacement);
+  return kDifOk;
+}
+
+// TODO: Does the IP handle overrun / underrun correctly?
+dif_result_t dif_spi_device_pop_flash_command_fifo(dif_spi_device_handle_t *spi,
+                                                   uint8_t *command) {
+  if (spi == NULL || command == NULL) {
+    return kDifBadArg;
+  }
+  uint32_t upload_status = mmio_region_read32(
+      spi->dev.base_addr, SPI_DEVICE_UPLOAD_STATUS_REG_OFFSET);
+  if (!bitfield_bit32_read(upload_status,
+                           SPI_DEVICE_UPLOAD_STATUS_CMDFIFO_NOTEMPTY_BIT)) {
+    return kDifUnavailable;
+  }
+  uint32_t cmd_item = mmio_region_read32(spi->dev.base_addr,
+                                         SPI_DEVICE_UPLOAD_CMDFIFO_REG_OFFSET);
+  *command =
+      bitfield_field32_read(cmd_item, SPI_DEVICE_UPLOAD_CMDFIFO_DATA_FIELD);
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_pop_flash_address_fifo(dif_spi_device_handle_t *spi,
+                                                   uint32_t *address) {
+  if (spi == NULL || address == NULL) {
+    return kDifBadArg;
+  }
+  uint32_t upload_status = mmio_region_read32(
+      spi->dev.base_addr, SPI_DEVICE_UPLOAD_STATUS_REG_OFFSET);
+  if (!bitfield_bit32_read(upload_status,
+                           SPI_DEVICE_UPLOAD_STATUS_ADDRFIFO_NOTEMPTY_BIT)) {
+    return kDifUnavailable;
+  }
+  *address = mmio_region_read32(spi->dev.base_addr,
+                                SPI_DEVICE_UPLOAD_ADDRFIFO_REG_OFFSET);
+  return kDifOk;
+}
+
+typedef struct dif_spi_device_flash_buffer_info {
+  size_t buffer_len;
+  ptrdiff_t buffer_offset;
+} dif_spi_device_flash_buffer_info_t;
+
+static dif_result_t dif_spi_device_get_flash_buffer_info(
+    dif_spi_device_flash_buffer_type_t buffer_type,
+    dif_spi_device_flash_buffer_info_t *info) {
+  switch (buffer_type) {
+    case kDifSpiDeviceFlashBufferTypeEFlash:
+      info->buffer_len = kDifSpiDeviceEFlashLen;
+      info->buffer_offset = kDifSpiDeviceEFlashOffset;
+      break;
+    case kDifSpiDeviceFlashBufferTypeMailbox:
+      info->buffer_len = kDifSpiDeviceMailboxLen;
+      info->buffer_offset = kDifSpiDeviceMailboxOffset;
+      break;
+    case kDifSpiDeviceFlashBufferTypeSfdp:
+      info->buffer_len = kDifSpiDeviceSfdpLen;
+      info->buffer_offset = kDifSpiDeviceSfdpOffset;
+      break;
+    case kDifSpiDeviceFlashBufferTypePayload:
+      info->buffer_len = kDifSpiDevicePayloadLen;
+      info->buffer_offset = kDifSpiDevicePayloadOffset;
+      break;
+    default:
+      return kDifBadArg;
+  }
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_read_flash_buffer(
+    dif_spi_device_handle_t *spi,
+    dif_spi_device_flash_buffer_type_t buffer_type, uint32_t offset,
+    size_t length, uint8_t *buf) {
+  if (spi == NULL || buf == NULL) {
+    return kDifBadArg;
+  }
+  dif_spi_device_flash_buffer_info_t info;
+  dif_result_t status =
+      dif_spi_device_get_flash_buffer_info(buffer_type, &info);
+  if (status != kDifOk) {
+    return status;
+  }
+  if (offset >= (info.buffer_offset + info.buffer_len) ||
+      length > (info.buffer_offset + info.buffer_len - offset)) {
+    return kDifBadArg;
+  }
+  ptrdiff_t offset_from_base =
+      SPI_DEVICE_BUFFER_REG_OFFSET + info.buffer_offset + offset;
+  mmio_region_memcpy_from_mmio32(spi->dev.base_addr, offset_from_base, buf,
+                                 length);
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_write_flash_buffer(
+    dif_spi_device_handle_t *spi,
+    dif_spi_device_flash_buffer_type_t buffer_type, uint32_t offset,
+    size_t length, const uint8_t *buf) {
+  if (spi == NULL || buf == NULL) {
+    return kDifBadArg;
+  }
+  dif_spi_device_flash_buffer_info_t info;
+  dif_result_t status =
+      dif_spi_device_get_flash_buffer_info(buffer_type, &info);
+  if (status != kDifOk) {
+    return status;
+  }
+  if (offset >= (info.buffer_offset + info.buffer_len) ||
+      length > (info.buffer_offset + info.buffer_len - offset)) {
+    return kDifBadArg;
+  }
+  ptrdiff_t offset_from_base =
+      SPI_DEVICE_BUFFER_REG_OFFSET + info.buffer_offset + offset;
+  mmio_region_memcpy_to_mmio32(spi->dev.base_addr, offset_from_base, buf,
+                               length);
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_get_passthrough_command_filter(
+    dif_spi_device_handle_t *spi, uint8_t command, dif_toggle_t *enabled) {
+  if (spi == NULL || enabled == NULL) {
+    return kDifBadArg;
+  }
+  ptrdiff_t reg_offset =
+      SPI_DEVICE_CMD_FILTER_0_REG_OFFSET + (command >> 5) * sizeof(uint32_t);
+  uint32_t command_index = command & 0x1fu;
+  uint32_t reg_value = mmio_region_read32(spi->dev.base_addr, reg_offset);
+  bool filtered = bitfield_bit32_read(reg_value, command_index);
+  if (filtered) {
+    *enabled = kDifToggleEnabled;
+  } else {
+    *enabled = kDifToggleDisabled;
+  }
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_set_passthrough_command_filter(
+    dif_spi_device_handle_t *spi, uint8_t command, dif_toggle_t enabled) {
+  if (spi == NULL || !dif_is_valid_toggle(enabled)) {
+    return kDifBadArg;
+  }
+  bool enable_filter = dif_toggle_to_bool(enabled);
+  ptrdiff_t reg_offset =
+      SPI_DEVICE_CMD_FILTER_0_REG_OFFSET + (command >> 5) * sizeof(uint32_t);
+  uint32_t command_index = command & 0x1fu;
+  uint32_t reg_value = mmio_region_read32(spi->dev.base_addr, reg_offset);
+  reg_value = bitfield_bit32_write(reg_value, command_index, enable_filter);
+  mmio_region_write32(spi->dev.base_addr, reg_offset, reg_value);
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_set_all_passthrough_command_filters(
+    dif_spi_device_handle_t *spi, dif_toggle_t enable) {
+  if (spi == NULL || !dif_is_valid_toggle(enable)) {
+    return kDifBadArg;
+  }
+  uint32_t reg_value = dif_toggle_to_bool(enable) ? UINT32_MAX : 0;
+  for (int i = 0; i < SPI_DEVICE_CMD_FILTER_MULTIREG_COUNT; i++) {
+    uint32_t reg_offset =
+        SPI_DEVICE_CMD_FILTER_0_REG_OFFSET + i * sizeof(uint32_t);
+    mmio_region_write32(spi->dev.base_addr, reg_offset, reg_value);
+  }
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_clear_flash_busy_bit(dif_spi_device_handle_t *spi) {
+  if (spi == NULL) {
+    return kDifBadArg;
+  }
+  uint32_t reg_val = mmio_region_read32(spi->dev.base_addr,
+                                        SPI_DEVICE_FLASH_STATUS_REG_OFFSET);
+  reg_val =
+      bitfield_bit32_write(reg_val, SPI_DEVICE_FLASH_STATUS_BUSY_BIT, false);
+  mmio_region_write32(spi->dev.base_addr, SPI_DEVICE_FLASH_STATUS_REG_OFFSET,
+                      reg_val);
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_set_flash_status_registers(
+    dif_spi_device_handle_t *spi, uint32_t value) {
+  if (spi == NULL) {
+    return kDifBadArg;
+  }
+  mmio_region_write32(spi->dev.base_addr, SPI_DEVICE_FLASH_STATUS_REG_OFFSET,
+                      value);
+  return kDifOk;
+}
+
+dif_result_t dif_spi_device_get_flash_status_registers(
+    dif_spi_device_handle_t *spi, uint32_t *value) {
+  if (spi == NULL || value == NULL) {
+    return kDifBadArg;
+  }
+  *value = mmio_region_read32(spi->dev.base_addr,
+                              SPI_DEVICE_FLASH_STATUS_REG_OFFSET);
+  return kDifOk;
+}
diff --git a/sw/device/lib/dif/dif_spi_device.h b/sw/device/lib/dif/dif_spi_device.h
index 9bad0b1..c68eb9e 100644
--- a/sw/device/lib/dif/dif_spi_device.h
+++ b/sw/device/lib/dif/dif_spi_device.h
@@ -25,7 +25,7 @@
 #endif  // __cplusplus
 
 /**
- * The mode that the spi device operates in
+ * The mode that the spi device operates in.
  */
 typedef enum dif_spi_device_mode {
   /**
@@ -264,6 +264,361 @@
 dif_result_t dif_spi_device_send(dif_spi_device_handle_t *spi, const void *buf,
                                  size_t buf_len, size_t *bytes_sent);
 
+typedef struct dif_spi_device_flash_id {
+  /** The device ID for the SPI flash. */
+  uint16_t device_id;
+  /** The JEDEC manufacturer ID. */
+  uint8_t manufacturer_id;
+  /** The continuation code used before the `manufacturer_id` byte. */
+  uint8_t continuation_code;
+  /** The number of continuation codes preceding the `manufacturer_id`. */
+  uint8_t num_continuation_code;
+} dif_spi_device_flash_id_t;
+
+/**
+ * Enable the mailbox region for spi_device flash / passthrough modes.
+ *
+ * Allocate 1 KiB for the mailbox, starting from the provided base `address`.
+ *
+ * @param spi A SPI device.
+ * @param address The base address of the 1 KiB mailbox. The lower 10 bits are
+ * ignored.
+ * @return kDifBadArg if spi is null, else kDifOk.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_enable_mailbox(dif_spi_device_handle_t *spi,
+                                           uint32_t address);
+
+/**
+ * Disable the mailbox region for spi_device flash / passthrough modes.
+ *
+ * @param spi A SPI device.
+ * @return kDifBadArg if spi is null, else kDifOk.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_disable_mailbox(dif_spi_device_handle_t *spi);
+
+/**
+ * Get the active configuration for the mailbox region.
+ *
+ * @param spi A SPI device.
+ * @param[out] is_enabled Whether the mailbox region is enabled.
+ * @param[out] address If the mailbox is enabled, the base address of the
+ * mailbox region.
+ * @return kDifBadArg if any argument is null, else kDifOk.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_get_mailbox_configuration(
+    dif_spi_device_handle_t *spi, dif_toggle_t *is_enabled, uint32_t *address);
+
+/**
+ * Set the address mode of the SPI device in flash/passthrough mode.
+ *
+ * @param spi A SPI device.
+ * @param addr_4b If kDifToggleEnabled, set the address mode to 4 Bytes.
+ * Otherwise, set the address mode to 3 Bytes.
+ * @return kDifBadArg if spi is NULL or addr_4b is not a valid toggle. kDifOk
+ * otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_set_4b_address_mode(dif_spi_device_handle_t *spi,
+                                                dif_toggle_t addr_4b);
+/**
+ * Get the address mode of the SPI device in flash/passthrough mode.
+ *
+ * @param spi A SPI device.
+ * @param[out] addr_4b Points to toggle that will be set to `kDifToggleEnabled`
+ * if the device is in 4-byte address mode, else `kDifToggleDisabled`.
+ * @return kDifBadArg if spi or addr_4b are NULL. kDifOk otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_get_4b_address_mode(dif_spi_device_handle_t *spi,
+                                                dif_toggle_t *addr_4b);
+
+/**
+ * Get the JEDEC ID presented when in flash / passthrough modes.
+ *
+ * @param spi A SPI device.
+ * @param[out] id Points to location that will be set to the current JEDEC ID.
+ * @return kDifBadArg if spi or id are NULL. kDifOk otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_get_flash_id(dif_spi_device_handle_t *spi,
+                                         dif_spi_device_flash_id_t *id);
+/**
+ * Set the JEDEC ID presented when in flash / passthrough modes.
+ *
+ * @param spi A SPI device.
+ * @param id The JEDEC ID to set.
+ * @return kDifBadArg if spi is NULL. kDifOk otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_set_flash_id(dif_spi_device_handle_t *spi,
+                                         dif_spi_device_flash_id_t id);
+
+typedef enum dif_spi_device_flash_address_type {
+  /** No address for this command */
+  kDifSpiDeviceFlashAddrDisabled = 0,
+  /** Address size for this command is determined by the current address mode */
+  kDifSpiDeviceFlashAddrCfg,
+  /** Address size for this command is fixed at 3 bytes */
+  kDifSpiDeviceFlashAddr3Byte,
+  /** Address size for this command is fixed at 4 bytes */
+  kDifSpiDeviceFlashAddr4Byte,
+  kDifSpiDeviceFlashAddrCount,
+} dif_spi_device_flash_address_type_t;
+
+typedef enum dif_spi_device_payload_io {
+  kDifSpiDevicePayloadIoNone = 0x0,
+  kDifSpiDevicePayloadIoSingle = 0x1,
+  kDifSpiDevicePayloadIoDual = 0x3,
+  kDifSpiDevicePayloadIoQuad = 0xf,
+  kDifSpiDevicePayloadIoInvalid = 0x10,
+} dif_spi_device_payload_io_t;
+
+typedef struct dif_spi_device_flash_command {
+  /** The opcode for this command. */
+  uint8_t opcode;
+  /* The presence and type of the address phase of this command. */
+  dif_spi_device_flash_address_type_t address_type;
+  /** The number of dummy cycles between the address phase and the payload phase
+   * of a command. Note that if `payload_io_width` is
+   * `kDifSpiDevicePayloadIoNone`, a nonzero value may cause undefined behavior,
+   * possibly including the device assuming dummy cycles are part of this
+   * payload-less command.
+   */
+  uint8_t dummy_cycles;
+  /** The I/O width for the payload phase of this command. */
+  dif_spi_device_payload_io_t payload_io_type;
+  /**
+   * Whether to translate the address using the address swap mask and value
+   * provided to `dif_spi_device_passthrough_set_swap_address()`. Incompatible
+   * with a command with `address_type` that is
+   * `kDifSpiDeviceFlashAddrDisabled`.
+   */
+  bool passthrough_swap_address;
+  /** Whether the SPI host is receiving this command's payload phase. */
+  bool payload_dir_to_host;
+  /** Whether to swap up to the first 32 bits of the payload. */
+  bool payload_swap_enable;
+  /** Whether to upload the command to the payload FIFO. */
+  bool upload;
+  /** Whether to set the busy bit in the status register. */
+  bool set_busy_status;
+} dif_spi_device_flash_command_t;
+
+typedef enum dif_spi_device_flash_buffer_type {
+  /** eFlash region */
+  kDifSpiDeviceFlashBufferTypeEFlash = 0,
+  /** Mailbox region */
+  kDifSpiDeviceFlashBufferTypeMailbox,
+  /** SFDP region */
+  kDifSpiDeviceFlashBufferTypeSfdp,
+  /** Payload for uploaded commands */
+  kDifSpiDeviceFlashBufferTypePayload,
+  /** Count of buffer types */
+  kDifSpiDeviceFlashBufferTypes,
+} dif_spi_device_flash_buffer_type_t;
+
+/**
+ * Set up the indicated command info slot for flash / passthrough modes.
+ *
+ * @param spi A handle to a spi device.
+ * @param slot A command info slot ID.
+ * @param enable Whether to enable or disable the command slot.
+ * @param command_info If `enable` is set, provides the configuration for the
+ *        command.
+ * @return `kDifBadArg` if `spi` is NULL or `slot` is larger than the number of
+ * command slots. `kDifOk` otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_set_flash_command_slot(
+    dif_spi_device_handle_t *spi, uint8_t slot, dif_toggle_t enable,
+    dif_spi_device_flash_command_t command_info);
+
+/**
+ * Get the current configuration of the indicated command info slot.
+ *
+ * @param spi A handle to a spi device.
+ * @param slot A command info slot ID.
+ * @param[out] enabled A pointer to where the current slot state can be stored.
+ * @param[out] command_info If `enabled`, points to where the current command
+ * configuration can be stored.
+ * @return `kDifBadArg` if any pointers are NULL or `slot` is larger than the
+ * number of command slots. `kDifOk` otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_get_flash_command_slot(
+    dif_spi_device_handle_t *spi, uint8_t slot, dif_toggle_t *enabled,
+    dif_spi_device_flash_command_t *command_info);
+
+/**
+ * Set which address bits are swapped and their values for commands that have
+ * the address swap enabled.
+ *
+ * @param spi A handle to a spi device.
+ * @param mask A bitmask indicating which address bits should be replaced.
+ * @param replacement The values to swap in for the masked address bits.
+ * @return `kDifBadArg` if spi is NULL, else `kDifOk`.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_set_flash_address_swap(dif_spi_device_handle_t *spi,
+                                                   uint32_t mask,
+                                                   uint32_t replacement);
+
+/**
+ * Set which bits are swapped and their values for commands that have
+ * the first-word payload swap function enabled.
+ *
+ * @param spi A handle to a spi device.
+ * @param mask A bitmask indicating which bits should be replaced.
+ * @param replacement The values to swap in for the masked bits.
+ * @return `kDifBadArg` if spi is NULL, else `kDifOk`.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_set_flash_payload_swap(dif_spi_device_handle_t *spi,
+                                                   uint32_t mask,
+                                                   uint32_t replacement);
+
+/**
+ * Pop the first command from the uploaded command FIFO.
+ *
+ * @param spi A handle to a spi device.
+ * @param[out] command A pointer to where the command can be stored.
+ * @return `kDifBadArg` if any pointers are NULL. `kDifUnavailable` if the FIFO
+ * was empty. `kDifOk` otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_pop_flash_command_fifo(dif_spi_device_handle_t *spi,
+                                                   uint8_t *command);
+
+/**
+ * Pop the first address from the uploaded address FIFO.
+ *
+ * @param spi A handle to a spi device.
+ * @param[out] address A pointer to where the address can be stored.
+ * @return `kDifBadArg` if any pointers are NULL. `kDifUnavailable` if the FIFO
+ * was empty. `kDifOk` otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_pop_flash_address_fifo(dif_spi_device_handle_t *spi,
+                                                   uint32_t *address);
+
+/**
+ * Read data from one of the memories associated with flash / passthrough modes.
+ *
+ * @param spi A handle to a spi device.
+ * @param buffer_type An identifier for which memory space to read from.
+ * @param offset The starting offset for read data in the memory.
+ * @param length The length, in bytes, of the data to be copied.
+ * @param[out] buf A pointer to the location where the data should be stored.
+ * @return `kDifBadArg` is any pointers are NULL or the `buffer_type` does not
+ * exist. `kDifOutOfRange` if the requested `offset` and `length` go beyond the
+ * indicated `buffer_type` region. `kDifOk` otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_read_flash_buffer(
+    dif_spi_device_handle_t *spi,
+    dif_spi_device_flash_buffer_type_t buffer_type, uint32_t offset,
+    size_t length, uint8_t *buf);
+
+/**
+ * Write data to one of the memories associated with flash / passthrough modes.
+ *
+ * @param spi A handle to a spi device.
+ * @param buffer_type An identifier for which memory space to write to.
+ * @param offset The starting offset for the write location of the data.
+ * @param length The length, in bytes, of the data to be copied.
+ * @param buf A pointer to the location where the data can be copied from.
+ * @return `kDifBadArg` is any pointers are NULL or the `buffer_type` does not
+ * exist. `kDifOutOfRange` if the requested `offset` and `length` go beyond the
+ * indicated `buffer_type` region. `kDifOk` otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_write_flash_buffer(
+    dif_spi_device_handle_t *spi,
+    dif_spi_device_flash_buffer_type_t buffer_type, uint32_t offset,
+    size_t length, const uint8_t *buf);
+
+/**
+ * Get whether the indicated command is filtered for passthrough.
+ *
+ * @param spi A handle to a spi device.
+ * @param command The command to be queried.
+ * @param[out] enabled A pointer to a location where the filter status can be
+ * stored. `kDifEnabled` means the command is filtered.
+ * @return `kDifBadArg` if any pointers are NULL. `kDifOk` otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_get_passthrough_command_filter(
+    dif_spi_device_handle_t *spi, uint8_t command, dif_toggle_t *enabled);
+
+/**
+ * Set whether the indicated command is filtered for passthrough.
+ *
+ * @param spi A handle to a spi device.
+ * @param command The command to have its filter status updated.
+ * @param enable Whether to enable the command filter for the `command`.
+ * @return `kDifBadArg` if `spi` is NULL or `enable` is invalid. `kDifOk`
+ * otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_set_passthrough_command_filter(
+    dif_spi_device_handle_t *spi, uint8_t command, dif_toggle_t enable);
+
+/**
+ * Set whether ALL commands are filtered for passthrough.
+ *
+ * Can be used for a faster initial state before using
+ * `dif_spi_device_set_passthrough_command_filter` to set the filter status for
+ * individual commands.
+ *
+ * @param spi A handle to a spi device.
+ * @param enable Whether to enable the command filter for all commands.
+ * @return `kDifBadArg` if `spi` is NULL or `enable` is invalid. `kDifOk`
+ * otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_set_all_passthrough_command_filters(
+    dif_spi_device_handle_t *spi, dif_toggle_t enable);
+
+/**
+ * Clear the busy bit for flash / passthrough modes.
+ *
+ * @param spi A handle to a spi device.
+ * @return `kDifBadArg` if `spi` is NULL. `kDifOk` otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_clear_flash_busy_bit(dif_spi_device_handle_t *spi);
+
+/**
+ * Write the status registers for flash / passthrough modes.
+ *
+ * Note that the three registers are concatenated to make one 24-bit value, with
+ * the LSB being the busy bit.
+ *
+ * @param spi A handle to a spi device.
+ * @param value The value to write to the registers.
+ * @return `kDifBadArg` if `spi` is NULL. `kDifOk` otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_set_flash_status_registers(
+    dif_spi_device_handle_t *spi, uint32_t value);
+
+/**
+ * Get the values of the status registers for flash / passthrough modes.
+ *
+ * Note that the three registers are concatenated to make one 24-bit value, with
+ * the LSB being the busy bit.
+ *
+ * @param spi A handle to a spi device.
+ * @param[out] value A pointer to where to write the values of the registesr.
+ * @return `kDifBadArg` if any pointer arguments are NULL. `kDifOk` otherwise.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_spi_device_get_flash_status_registers(
+    dif_spi_device_handle_t *spi, uint32_t *value);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif  // __cplusplus
diff --git a/sw/device/lib/dif/dif_spi_device_unittest.cc b/sw/device/lib/dif/dif_spi_device_unittest.cc
index 26557b6..1673dd7 100644
--- a/sw/device/lib/dif/dif_spi_device_unittest.cc
+++ b/sw/device/lib/dif/dif_spi_device_unittest.cc
@@ -745,9 +745,504 @@
         .rx_order = kDifSpiDeviceBitOrderMsbToLsb,
         .device_mode = kDifSpiDeviceModePassthrough,
     };
-    spi_.config = config;
+    EXPECT_DIF_OK(dif_spi_device_init_handle(dev().region(), &spi_));
+    EXPECT_WRITE32(SPI_DEVICE_CFG_REG_OFFSET,
+                   {
+                       {SPI_DEVICE_CFG_CPOL_BIT, 0},
+                       {SPI_DEVICE_CFG_CPHA_BIT, 0},
+                       {SPI_DEVICE_CFG_TX_ORDER_BIT, 0},
+                       {SPI_DEVICE_CFG_RX_ORDER_BIT, 0},
+                   });
+    EXPECT_READ32(SPI_DEVICE_CONTROL_REG_OFFSET,
+                  {
+                      {SPI_DEVICE_CONTROL_MODE_OFFSET, 0},
+                      {SPI_DEVICE_CONTROL_SRAM_CLK_EN_BIT, 1},
+                  });
+    EXPECT_WRITE32(SPI_DEVICE_CONTROL_REG_OFFSET,
+                   {
+                       {SPI_DEVICE_CONTROL_MODE_OFFSET, 0},
+                       {SPI_DEVICE_CONTROL_SRAM_CLK_EN_BIT, 0},
+                   });
+    EXPECT_WRITE32(SPI_DEVICE_CONTROL_REG_OFFSET,
+                   {
+                       {SPI_DEVICE_CONTROL_MODE_OFFSET,
+                        SPI_DEVICE_CONTROL_MODE_VALUE_PASSTHROUGH},
+                       {SPI_DEVICE_CONTROL_SRAM_CLK_EN_BIT, 0},
+                   });
+    EXPECT_WRITE32(SPI_DEVICE_CONTROL_REG_OFFSET,
+                   {
+                       {SPI_DEVICE_CONTROL_MODE_OFFSET,
+                        SPI_DEVICE_CONTROL_MODE_VALUE_PASSTHROUGH},
+                       {SPI_DEVICE_CONTROL_SRAM_CLK_EN_BIT, 1},
+                   });
+    EXPECT_DIF_OK(dif_spi_device_configure(&spi_, config));
   };
 };
 
+TEST_F(FlashTest, NullArgs) {
+  dif_toggle_t toggle_arg;
+  uint32_t uint32_arg;
+  uint8_t uint8_arg;
+  dif_spi_device_flash_id_t id_arg;
+  dif_spi_device_flash_command_t command_arg;
+  EXPECT_DIF_BADARG(dif_spi_device_init_handle(dev().region(), nullptr));
+  EXPECT_DIF_BADARG(dif_spi_device_enable_mailbox(nullptr, /*address=*/0x1000));
+  EXPECT_DIF_BADARG(dif_spi_device_disable_mailbox(nullptr));
+  EXPECT_DIF_BADARG(dif_spi_device_get_mailbox_configuration(
+      nullptr, &toggle_arg, &uint32_arg));
+  EXPECT_DIF_BADARG(
+      dif_spi_device_get_mailbox_configuration(&spi_, nullptr, &uint32_arg));
+  EXPECT_DIF_BADARG(
+      dif_spi_device_get_mailbox_configuration(&spi_, &toggle_arg, nullptr));
+  EXPECT_DIF_BADARG(
+      dif_spi_device_set_4b_address_mode(nullptr, kDifToggleEnabled));
+  EXPECT_DIF_BADARG(dif_spi_device_get_4b_address_mode(nullptr, &toggle_arg));
+  EXPECT_DIF_BADARG(dif_spi_device_get_4b_address_mode(&spi_, nullptr));
+  EXPECT_DIF_BADARG(dif_spi_device_get_flash_id(nullptr, &id_arg));
+  EXPECT_DIF_BADARG(dif_spi_device_get_flash_id(&spi_, nullptr));
+  EXPECT_DIF_BADARG(dif_spi_device_set_flash_id(nullptr, id_arg));
+  EXPECT_DIF_BADARG(dif_spi_device_get_flash_command_slot(
+      nullptr, /*slot=*/0, &toggle_arg, &command_arg));
+  EXPECT_DIF_BADARG(dif_spi_device_get_flash_command_slot(
+      &spi_, /*slot=*/0, nullptr, &command_arg));
+  EXPECT_DIF_BADARG(dif_spi_device_get_flash_command_slot(
+      &spi_, /*slot=*/0, &toggle_arg, nullptr));
+  EXPECT_DIF_BADARG(dif_spi_device_set_flash_command_slot(
+      nullptr, /*slot=*/0, kDifToggleEnabled, command_arg));
+  EXPECT_DIF_BADARG(dif_spi_device_set_flash_address_swap(nullptr, /*mask=*/0,
+                                                          /*replacement=*/0));
+  EXPECT_DIF_BADARG(dif_spi_device_set_flash_payload_swap(nullptr, /*mask=*/0,
+                                                          /*replacement=*/0));
+  EXPECT_DIF_BADARG(dif_spi_device_pop_flash_command_fifo(nullptr, &uint8_arg));
+  EXPECT_DIF_BADARG(dif_spi_device_pop_flash_command_fifo(&spi_, nullptr));
+  EXPECT_DIF_BADARG(
+      dif_spi_device_pop_flash_address_fifo(nullptr, &uint32_arg));
+  EXPECT_DIF_BADARG(dif_spi_device_pop_flash_address_fifo(&spi_, nullptr));
+  EXPECT_DIF_BADARG(dif_spi_device_read_flash_buffer(
+      nullptr, kDifSpiDeviceFlashBufferTypeSfdp, /*offset=*/0, /*length=*/1,
+      &uint8_arg));
+  EXPECT_DIF_BADARG(
+      dif_spi_device_read_flash_buffer(&spi_, kDifSpiDeviceFlashBufferTypeSfdp,
+                                       /*offset=*/0, /*length=*/1, nullptr));
+  EXPECT_DIF_BADARG(dif_spi_device_write_flash_buffer(
+      nullptr, kDifSpiDeviceFlashBufferTypeSfdp, /*offset=*/0, /*length=*/1,
+      &uint8_arg));
+  EXPECT_DIF_BADARG(
+      dif_spi_device_write_flash_buffer(&spi_, kDifSpiDeviceFlashBufferTypeSfdp,
+                                        /*offset=*/0, /*length=*/1, nullptr));
+  EXPECT_DIF_BADARG(dif_spi_device_get_passthrough_command_filter(
+      nullptr, /*command=*/0, &toggle_arg));
+  EXPECT_DIF_BADARG(dif_spi_device_get_passthrough_command_filter(
+      &spi_, /*command=*/0, nullptr));
+  EXPECT_DIF_BADARG(dif_spi_device_set_passthrough_command_filter(
+      nullptr, /*command=*/0, kDifToggleEnabled));
+  EXPECT_DIF_BADARG(dif_spi_device_set_all_passthrough_command_filters(
+      nullptr, kDifToggleEnabled));
+  EXPECT_DIF_BADARG(dif_spi_device_clear_flash_busy_bit(nullptr));
+  EXPECT_DIF_BADARG(
+      dif_spi_device_set_flash_status_registers(nullptr, /*value=*/0));
+  EXPECT_DIF_BADARG(
+      dif_spi_device_get_flash_status_registers(nullptr, &uint32_arg));
+  EXPECT_DIF_BADARG(dif_spi_device_get_flash_status_registers(&spi_, nullptr));
+}
+
+TEST_F(FlashTest, MailboxConfigTest) {
+  dif_toggle_t toggle;
+  uint32_t address = 0x3f0000;
+  EXPECT_WRITE32(SPI_DEVICE_MAILBOX_ADDR_REG_OFFSET, address);
+  EXPECT_READ32(SPI_DEVICE_CFG_REG_OFFSET, {
+                                               {SPI_DEVICE_CFG_CPOL_BIT, 1},
+                                               {SPI_DEVICE_CFG_CPHA_BIT, 1},
+                                           });
+  EXPECT_WRITE32(SPI_DEVICE_CFG_REG_OFFSET,
+                 {
+                     {SPI_DEVICE_CFG_CPOL_BIT, 1},
+                     {SPI_DEVICE_CFG_CPHA_BIT, 1},
+                     {SPI_DEVICE_CFG_MAILBOX_EN_BIT, 1},
+                 });
+  EXPECT_DIF_OK(dif_spi_device_enable_mailbox(&spi_, address));
+  EXPECT_READ32(SPI_DEVICE_CFG_REG_OFFSET,
+                {
+                    {SPI_DEVICE_CFG_MAILBOX_EN_BIT, 1},
+                    {SPI_DEVICE_CFG_TX_ORDER_BIT, 1},
+                    {SPI_DEVICE_CFG_RX_ORDER_BIT, 1},
+                });
+  EXPECT_WRITE32(SPI_DEVICE_CFG_REG_OFFSET,
+                 {
+                     {SPI_DEVICE_CFG_MAILBOX_EN_BIT, 0},
+                     {SPI_DEVICE_CFG_TX_ORDER_BIT, 1},
+                     {SPI_DEVICE_CFG_RX_ORDER_BIT, 1},
+                 });
+  EXPECT_DIF_OK(dif_spi_device_disable_mailbox(&spi_));
+  EXPECT_READ32(SPI_DEVICE_CFG_REG_OFFSET,
+                {
+                    {SPI_DEVICE_CFG_MAILBOX_EN_BIT, 1},
+                    {SPI_DEVICE_CFG_TX_ORDER_BIT, 1},
+                });
+  EXPECT_READ32(SPI_DEVICE_MAILBOX_ADDR_REG_OFFSET, 0x100000);
+  EXPECT_DIF_OK(
+      dif_spi_device_get_mailbox_configuration(&spi_, &toggle, &address));
+  EXPECT_EQ(toggle, kDifToggleEnabled);
+  EXPECT_EQ(address, 0x100000);
+  EXPECT_READ32(SPI_DEVICE_CFG_REG_OFFSET,
+                {
+                    {SPI_DEVICE_CFG_MAILBOX_EN_BIT, 0},
+                });
+  EXPECT_READ32(SPI_DEVICE_MAILBOX_ADDR_REG_OFFSET, 0x100000);
+  EXPECT_DIF_OK(
+      dif_spi_device_get_mailbox_configuration(&spi_, &toggle, &address));
+  EXPECT_EQ(toggle, kDifToggleDisabled);
+}
+
+TEST_F(FlashTest, Addr4bConfig) {
+  dif_toggle_t toggle;
+  EXPECT_READ32(SPI_DEVICE_CFG_REG_OFFSET,
+                {
+                    {SPI_DEVICE_CFG_MAILBOX_EN_BIT, 1},
+                });
+  EXPECT_DIF_OK(dif_spi_device_get_4b_address_mode(&spi_, &toggle));
+  EXPECT_EQ(toggle, kDifToggleDisabled);
+
+  EXPECT_READ32(SPI_DEVICE_CFG_REG_OFFSET,
+                {
+                    {SPI_DEVICE_CFG_MAILBOX_EN_BIT, 1},
+                    {SPI_DEVICE_CFG_ADDR_4B_EN_BIT, 1},
+                });
+  EXPECT_DIF_OK(dif_spi_device_get_4b_address_mode(&spi_, &toggle));
+  EXPECT_EQ(toggle, kDifToggleEnabled);
+
+  EXPECT_READ32(SPI_DEVICE_CFG_REG_OFFSET,
+                {
+                    {SPI_DEVICE_CFG_MAILBOX_EN_BIT, 1},
+                    {SPI_DEVICE_CFG_ADDR_4B_EN_BIT, 0},
+                });
+  EXPECT_WRITE32(SPI_DEVICE_CFG_REG_OFFSET,
+                 {
+                     {SPI_DEVICE_CFG_MAILBOX_EN_BIT, 1},
+                     {SPI_DEVICE_CFG_ADDR_4B_EN_BIT, 1},
+                 });
+  EXPECT_DIF_OK(dif_spi_device_set_4b_address_mode(&spi_, kDifToggleEnabled));
+  EXPECT_READ32(SPI_DEVICE_CFG_REG_OFFSET,
+                {
+                    {SPI_DEVICE_CFG_MAILBOX_EN_BIT, 1},
+                    {SPI_DEVICE_CFG_ADDR_4B_EN_BIT, 1},
+                });
+  EXPECT_WRITE32(SPI_DEVICE_CFG_REG_OFFSET,
+                 {
+                     {SPI_DEVICE_CFG_MAILBOX_EN_BIT, 1},
+                     {SPI_DEVICE_CFG_ADDR_4B_EN_BIT, 0},
+                 });
+  EXPECT_DIF_OK(dif_spi_device_set_4b_address_mode(&spi_, kDifToggleDisabled));
+}
+
+TEST_F(FlashTest, DeviceId) {
+  dif_spi_device_flash_id_t id;
+  EXPECT_READ32(SPI_DEVICE_JEDEC_CC_REG_OFFSET,
+                {
+                    {SPI_DEVICE_JEDEC_CC_NUM_CC_OFFSET, 10},
+                    {SPI_DEVICE_JEDEC_CC_CC_OFFSET, 0x5a},
+                });
+  EXPECT_READ32(SPI_DEVICE_JEDEC_ID_REG_OFFSET,
+                {
+                    {SPI_DEVICE_JEDEC_ID_MF_OFFSET, 0xca},
+                    {SPI_DEVICE_JEDEC_ID_ID_OFFSET, 0x1234},
+                });
+  EXPECT_DIF_OK(dif_spi_device_get_flash_id(&spi_, &id));
+  EXPECT_EQ(id.num_continuation_code, 10);
+  EXPECT_EQ(id.continuation_code, 0x5a);
+  EXPECT_EQ(id.manufacturer_id, 0xca);
+  EXPECT_EQ(id.device_id, 0x1234);
+
+  id = (dif_spi_device_flash_id_t){
+      .device_id = 0x2202,
+      .manufacturer_id = 0xd7,
+      .continuation_code = 0x7f,
+      .num_continuation_code = 7,
+  };
+  EXPECT_WRITE32(SPI_DEVICE_JEDEC_CC_REG_OFFSET,
+                 {
+                     {SPI_DEVICE_JEDEC_CC_NUM_CC_OFFSET, 7},
+                     {SPI_DEVICE_JEDEC_CC_CC_OFFSET, 0x7f},
+                 });
+  EXPECT_WRITE32(SPI_DEVICE_JEDEC_ID_REG_OFFSET,
+                 {
+                     {SPI_DEVICE_JEDEC_ID_MF_OFFSET, 0xd7},
+                     {SPI_DEVICE_JEDEC_ID_ID_OFFSET, 0x2202},
+                 });
+  EXPECT_DIF_OK(dif_spi_device_set_flash_id(&spi_, id));
+}
+
+TEST_F(FlashTest, CommandInfo) {
+  dif_spi_device_flash_command_t command_info;
+  dif_toggle_t toggle;
+  EXPECT_READ32(SPI_DEVICE_CMD_INFO_0_REG_OFFSET,
+                {
+                    {SPI_DEVICE_CMD_INFO_0_OPCODE_0_OFFSET, 0x6b},
+                    {SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_OFFSET,
+                     SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDRCFG},
+                    {SPI_DEVICE_CMD_INFO_0_DUMMY_EN_0_BIT, 1},
+                    {SPI_DEVICE_CMD_INFO_0_DUMMY_SIZE_0_OFFSET, 7},
+                    {SPI_DEVICE_CMD_INFO_0_PAYLOAD_EN_0_OFFSET, 0xf},
+                    {SPI_DEVICE_CMD_INFO_0_PAYLOAD_DIR_0_BIT, 1},
+                    {SPI_DEVICE_CMD_INFO_0_ADDR_SWAP_EN_0_BIT, 0},
+                    {SPI_DEVICE_CMD_INFO_0_PAYLOAD_SWAP_EN_0_BIT, 0},
+                    {SPI_DEVICE_CMD_INFO_0_UPLOAD_0_BIT, 0},
+                    {SPI_DEVICE_CMD_INFO_0_BUSY_0_BIT, 0},
+                    {SPI_DEVICE_CMD_INFO_0_VALID_0_BIT, 0},
+                });
+  EXPECT_DIF_OK(dif_spi_device_get_flash_command_slot(&spi_, /*slot=*/0,
+                                                      &toggle, &command_info));
+  EXPECT_EQ(toggle, kDifToggleDisabled);
+
+  EXPECT_READ32(SPI_DEVICE_CMD_INFO_1_REG_OFFSET,
+                {
+                    {SPI_DEVICE_CMD_INFO_1_OPCODE_1_OFFSET, 0x6b},
+                    {SPI_DEVICE_CMD_INFO_1_ADDR_MODE_1_OFFSET,
+                     SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDRCFG},
+                    {SPI_DEVICE_CMD_INFO_1_DUMMY_EN_1_BIT, 1},
+                    {SPI_DEVICE_CMD_INFO_1_DUMMY_SIZE_1_OFFSET, 7},
+                    {SPI_DEVICE_CMD_INFO_1_PAYLOAD_EN_1_OFFSET, 0xf},
+                    {SPI_DEVICE_CMD_INFO_1_PAYLOAD_DIR_1_BIT, 1},
+                    {SPI_DEVICE_CMD_INFO_1_ADDR_SWAP_EN_1_BIT, 0},
+                    {SPI_DEVICE_CMD_INFO_1_PAYLOAD_SWAP_EN_1_BIT, 0},
+                    {SPI_DEVICE_CMD_INFO_1_UPLOAD_1_BIT, 0},
+                    {SPI_DEVICE_CMD_INFO_1_BUSY_1_BIT, 0},
+                    {SPI_DEVICE_CMD_INFO_1_VALID_1_BIT, 1},
+                });
+  EXPECT_DIF_OK(dif_spi_device_get_flash_command_slot(&spi_, /*slot=*/1,
+                                                      &toggle, &command_info));
+  EXPECT_EQ(toggle, kDifToggleEnabled);
+  EXPECT_EQ(command_info.opcode, 0x6b);
+  EXPECT_EQ(command_info.address_type, kDifSpiDeviceFlashAddrCfg);
+  EXPECT_EQ(command_info.dummy_cycles, 8);
+  EXPECT_EQ(command_info.payload_io_type, kDifSpiDevicePayloadIoQuad);
+  EXPECT_FALSE(command_info.passthrough_swap_address);
+  EXPECT_TRUE(command_info.payload_dir_to_host);
+  EXPECT_FALSE(command_info.payload_swap_enable);
+  EXPECT_FALSE(command_info.upload);
+  EXPECT_FALSE(command_info.set_busy_status);
+
+  EXPECT_READ32(SPI_DEVICE_CMD_INFO_1_REG_OFFSET,
+                {
+                    {SPI_DEVICE_CMD_INFO_1_OPCODE_1_OFFSET, 0x12},
+                    {SPI_DEVICE_CMD_INFO_1_ADDR_MODE_1_OFFSET,
+                     SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDR4B},
+                    {SPI_DEVICE_CMD_INFO_1_DUMMY_EN_1_BIT, 0},
+                    {SPI_DEVICE_CMD_INFO_1_DUMMY_SIZE_1_OFFSET, 7},
+                    {SPI_DEVICE_CMD_INFO_1_PAYLOAD_EN_1_OFFSET, 0x1},
+                    {SPI_DEVICE_CMD_INFO_1_PAYLOAD_DIR_1_BIT, 0},
+                    {SPI_DEVICE_CMD_INFO_1_ADDR_SWAP_EN_1_BIT, 1},
+                    {SPI_DEVICE_CMD_INFO_1_PAYLOAD_SWAP_EN_1_BIT, 1},
+                    {SPI_DEVICE_CMD_INFO_1_UPLOAD_1_BIT, 1},
+                    {SPI_DEVICE_CMD_INFO_1_BUSY_1_BIT, 1},
+                    {SPI_DEVICE_CMD_INFO_1_VALID_1_BIT, 1},
+                });
+  EXPECT_DIF_OK(dif_spi_device_get_flash_command_slot(&spi_, /*slot=*/1,
+                                                      &toggle, &command_info));
+  EXPECT_EQ(toggle, kDifToggleEnabled);
+  EXPECT_EQ(command_info.opcode, 0x12);
+  EXPECT_EQ(command_info.address_type, kDifSpiDeviceFlashAddr4Byte);
+  EXPECT_EQ(command_info.dummy_cycles, 0);
+  EXPECT_EQ(command_info.payload_io_type, kDifSpiDevicePayloadIoSingle);
+  EXPECT_TRUE(command_info.passthrough_swap_address);
+  EXPECT_FALSE(command_info.payload_dir_to_host);
+  EXPECT_TRUE(command_info.payload_swap_enable);
+  EXPECT_TRUE(command_info.upload);
+  EXPECT_TRUE(command_info.set_busy_status);
+
+  command_info = (dif_spi_device_flash_command_t){
+      .opcode = 0x06,
+      .address_type = kDifSpiDeviceFlashAddrDisabled,
+      .dummy_cycles = 0,
+      .payload_io_type = kDifSpiDevicePayloadIoSingle,
+      .passthrough_swap_address = false,
+      .payload_dir_to_host = false,
+      .payload_swap_enable = true,
+      .upload = true,
+      .set_busy_status = true,
+  };
+  EXPECT_WRITE32(SPI_DEVICE_CMD_INFO_1_REG_OFFSET,
+                 {
+                     {SPI_DEVICE_CMD_INFO_1_OPCODE_1_OFFSET, 0x06},
+                     {SPI_DEVICE_CMD_INFO_1_ADDR_MODE_1_OFFSET,
+                      SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDRDISABLED},
+                     {SPI_DEVICE_CMD_INFO_1_DUMMY_EN_1_BIT, 0},
+                     {SPI_DEVICE_CMD_INFO_1_DUMMY_SIZE_1_OFFSET, 0},
+                     {SPI_DEVICE_CMD_INFO_1_PAYLOAD_EN_1_OFFSET, 0x1},
+                     {SPI_DEVICE_CMD_INFO_1_PAYLOAD_DIR_1_BIT, 0},
+                     {SPI_DEVICE_CMD_INFO_1_ADDR_SWAP_EN_1_BIT, 0},
+                     {SPI_DEVICE_CMD_INFO_1_PAYLOAD_SWAP_EN_1_BIT, 1},
+                     {SPI_DEVICE_CMD_INFO_1_UPLOAD_1_BIT, 1},
+                     {SPI_DEVICE_CMD_INFO_1_BUSY_1_BIT, 1},
+                     {SPI_DEVICE_CMD_INFO_1_VALID_1_BIT, 1},
+                 });
+  EXPECT_DIF_OK(dif_spi_device_set_flash_command_slot(
+      &spi_, /*slot=*/1, kDifToggleEnabled, command_info));
+  command_info = (dif_spi_device_flash_command_t){
+      .opcode = 0x5a,
+      .address_type = kDifSpiDeviceFlashAddr3Byte,
+      .dummy_cycles = 8,
+      .payload_io_type = kDifSpiDevicePayloadIoSingle,
+      .passthrough_swap_address = false,
+      .payload_dir_to_host = true,
+      .payload_swap_enable = false,
+      .upload = false,
+      .set_busy_status = false,
+  };
+  EXPECT_WRITE32(SPI_DEVICE_CMD_INFO_1_REG_OFFSET,
+                 {
+                     {SPI_DEVICE_CMD_INFO_1_OPCODE_1_OFFSET, 0x5a},
+                     {SPI_DEVICE_CMD_INFO_1_ADDR_MODE_1_OFFSET,
+                      SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDR3B},
+                     {SPI_DEVICE_CMD_INFO_1_DUMMY_EN_1_BIT, 1},
+                     {SPI_DEVICE_CMD_INFO_1_DUMMY_SIZE_1_OFFSET, 7},
+                     {SPI_DEVICE_CMD_INFO_1_PAYLOAD_EN_1_OFFSET, 0x2},
+                     {SPI_DEVICE_CMD_INFO_1_PAYLOAD_DIR_1_BIT, 1},
+                     {SPI_DEVICE_CMD_INFO_1_ADDR_SWAP_EN_1_BIT, 0},
+                     {SPI_DEVICE_CMD_INFO_1_PAYLOAD_SWAP_EN_1_BIT, 0},
+                     {SPI_DEVICE_CMD_INFO_1_UPLOAD_1_BIT, 0},
+                     {SPI_DEVICE_CMD_INFO_1_BUSY_1_BIT, 0},
+                     {SPI_DEVICE_CMD_INFO_1_VALID_1_BIT, 1},
+                 });
+  EXPECT_DIF_OK(dif_spi_device_set_flash_command_slot(
+      &spi_, /*slot=*/1, kDifToggleEnabled, command_info));
+}
+
+TEST_F(FlashTest, Swaps) {
+  EXPECT_WRITE32(SPI_DEVICE_ADDR_SWAP_MASK_REG_OFFSET, 0x10203456u);
+  EXPECT_WRITE32(SPI_DEVICE_ADDR_SWAP_DATA_REG_OFFSET, 0xffff0000u);
+  EXPECT_DIF_OK(
+      dif_spi_device_set_flash_address_swap(&spi_, 0x10203456u, 0xffff0000u));
+
+  EXPECT_WRITE32(SPI_DEVICE_PAYLOAD_SWAP_MASK_REG_OFFSET, 0x24587001u);
+  EXPECT_WRITE32(SPI_DEVICE_PAYLOAD_SWAP_DATA_REG_OFFSET, 0xa5a5f00fu);
+  EXPECT_DIF_OK(
+      dif_spi_device_set_flash_payload_swap(&spi_, 0x24587001u, 0xa5a5f00fu));
+}
+
+TEST_F(FlashTest, FifoPop) {
+  uint8_t command;
+  uint32_t address;
+  EXPECT_READ32(SPI_DEVICE_UPLOAD_STATUS_REG_OFFSET,
+                {
+                    {SPI_DEVICE_UPLOAD_STATUS_CMDFIFO_NOTEMPTY_BIT, 0},
+                    {SPI_DEVICE_UPLOAD_STATUS_ADDRFIFO_NOTEMPTY_BIT, 1},
+                });
+  EXPECT_EQ(dif_spi_device_pop_flash_command_fifo(&spi_, &command),
+            kDifUnavailable);
+
+  EXPECT_READ32(SPI_DEVICE_UPLOAD_STATUS_REG_OFFSET,
+                {
+                    {SPI_DEVICE_UPLOAD_STATUS_CMDFIFO_NOTEMPTY_BIT, 1},
+                    {SPI_DEVICE_UPLOAD_STATUS_ADDRFIFO_NOTEMPTY_BIT, 1},
+                });
+  EXPECT_READ32(SPI_DEVICE_UPLOAD_CMDFIFO_REG_OFFSET, 0x06);
+  EXPECT_DIF_OK(dif_spi_device_pop_flash_command_fifo(&spi_, &command));
+  EXPECT_EQ(command, 0x06);
+
+  EXPECT_READ32(SPI_DEVICE_UPLOAD_STATUS_REG_OFFSET,
+                {
+                    {SPI_DEVICE_UPLOAD_STATUS_CMDFIFO_NOTEMPTY_BIT, 1},
+                    {SPI_DEVICE_UPLOAD_STATUS_ADDRFIFO_NOTEMPTY_BIT, 0},
+                });
+  EXPECT_EQ(dif_spi_device_pop_flash_address_fifo(&spi_, &address),
+            kDifUnavailable);
+
+  EXPECT_READ32(SPI_DEVICE_UPLOAD_STATUS_REG_OFFSET,
+                {
+                    {SPI_DEVICE_UPLOAD_STATUS_CMDFIFO_NOTEMPTY_BIT, 1},
+                    {SPI_DEVICE_UPLOAD_STATUS_ADDRFIFO_NOTEMPTY_BIT, 1},
+                });
+  EXPECT_READ32(SPI_DEVICE_UPLOAD_ADDRFIFO_REG_OFFSET, 0x76543210);
+  EXPECT_DIF_OK(dif_spi_device_pop_flash_address_fifo(&spi_, &address));
+  EXPECT_EQ(address, 0x76543210);
+}
+
+TEST_F(FlashTest, MemoryOps) {
+  constexpr uint32_t kSfdpOffset = 3072;
+  constexpr uint32_t kMailboxOffset = 2048;
+
+  uint32_t buf[64];
+  for (uint32_t i = 0; i < (sizeof(buf) / sizeof(buf[0])); i++) {
+    buf[i] = i;
+    EXPECT_WRITE32(
+        SPI_DEVICE_BUFFER_REG_OFFSET + kSfdpOffset + i * sizeof(uint32_t), i);
+  }
+  EXPECT_DIF_OK(dif_spi_device_write_flash_buffer(
+      &spi_, kDifSpiDeviceFlashBufferTypeSfdp, /*offset=*/0,
+      /*length=*/sizeof(buf), reinterpret_cast<uint8_t *>(buf)));
+  for (uint32_t i = 4; i < (sizeof(buf) / sizeof(buf[0])); i++) {
+    EXPECT_READ32(
+        SPI_DEVICE_BUFFER_REG_OFFSET + kMailboxOffset + i * sizeof(uint32_t),
+        0x1000u - i);
+  }
+  EXPECT_DIF_OK(dif_spi_device_read_flash_buffer(
+      &spi_, kDifSpiDeviceFlashBufferTypeMailbox, /*offset=*/16,
+      /*length=*/sizeof(buf) - 16, reinterpret_cast<uint8_t *>(buf)));
+  for (uint32_t i = 4; i < (sizeof(buf) / sizeof(buf[0])); i++) {
+    EXPECT_EQ(buf[i - 4], 0x1000u - i);
+  }
+}
+
+TEST_F(FlashTest, CommandFilters) {
+  dif_toggle_t toggle;
+  EXPECT_READ32(SPI_DEVICE_CMD_FILTER_0_REG_OFFSET, 0xa5642301u);
+  EXPECT_DIF_OK(dif_spi_device_get_passthrough_command_filter(
+      &spi_, /*opcode=*/18, &toggle));
+  EXPECT_EQ(toggle, kDifToggleEnabled);
+
+  EXPECT_READ32(SPI_DEVICE_CMD_FILTER_3_REG_OFFSET, 0xa5642301u);
+  EXPECT_DIF_OK(dif_spi_device_get_passthrough_command_filter(
+      &spi_, /*opcode=*/(3 * 32 + 19), &toggle));
+  EXPECT_EQ(toggle, kDifToggleDisabled);
+
+  EXPECT_READ32(SPI_DEVICE_CMD_FILTER_0_REG_OFFSET, 0xa5a5a5a5u);
+  EXPECT_WRITE32(SPI_DEVICE_CMD_FILTER_0_REG_OFFSET, 0xa585a5a5u);
+  EXPECT_DIF_OK(dif_spi_device_set_passthrough_command_filter(
+      &spi_, /*opcode=*/21, kDifToggleDisabled));
+
+  EXPECT_READ32(SPI_DEVICE_CMD_FILTER_7_REG_OFFSET, 0x5555aaaau);
+  EXPECT_WRITE32(SPI_DEVICE_CMD_FILTER_7_REG_OFFSET, 0x5555aaabu);
+  EXPECT_DIF_OK(dif_spi_device_set_passthrough_command_filter(
+      &spi_, /*opcode=*/224, kDifToggleEnabled));
+
+  for (int i = 0; i < 8; i++) {
+    EXPECT_WRITE32(SPI_DEVICE_CMD_FILTER_0_REG_OFFSET + i * sizeof(uint32_t),
+                   0);
+  }
+  EXPECT_DIF_OK(dif_spi_device_set_all_passthrough_command_filters(
+      &spi_, kDifToggleDisabled));
+
+  for (int i = 0; i < 8; i++) {
+    EXPECT_WRITE32(SPI_DEVICE_CMD_FILTER_0_REG_OFFSET + i * sizeof(uint32_t),
+                   UINT32_MAX);
+  }
+  EXPECT_DIF_OK(dif_spi_device_set_all_passthrough_command_filters(
+      &spi_, kDifToggleEnabled));
+}
+
+TEST_F(FlashTest, StatusRegisters) {
+  uint32_t status;
+  EXPECT_READ32(SPI_DEVICE_FLASH_STATUS_REG_OFFSET,
+                {
+                    {SPI_DEVICE_FLASH_STATUS_BUSY_BIT, 1},
+                    {SPI_DEVICE_FLASH_STATUS_STATUS_OFFSET, 0x143200},
+                });
+  EXPECT_WRITE32(SPI_DEVICE_FLASH_STATUS_REG_OFFSET,
+                 {
+                     {SPI_DEVICE_FLASH_STATUS_BUSY_BIT, 0},
+                     {SPI_DEVICE_FLASH_STATUS_STATUS_OFFSET, 0x143200},
+                 });
+  EXPECT_DIF_OK(dif_spi_device_clear_flash_busy_bit(&spi_));
+
+  EXPECT_WRITE32(SPI_DEVICE_FLASH_STATUS_REG_OFFSET, 0x198234);
+  EXPECT_DIF_OK(
+      dif_spi_device_set_flash_status_registers(&spi_, /*status=*/0x198234));
+
+  EXPECT_READ32(SPI_DEVICE_FLASH_STATUS_REG_OFFSET, 0x765432);
+  EXPECT_DIF_OK(dif_spi_device_get_flash_status_registers(&spi_, &status));
+  EXPECT_EQ(status, 0x765432);
+}
+
 }  // namespace
 }  // namespace dif_spi_device_unittest