Add chip_sw_flash_ctrl_ops and chip_sw_spi_device_pass_through_collision
to edacloud

Change-Id: Ib30284da25ecb5e84008cc54ddd4beafef57a0d4
diff --git a/hw/top_matcha/dv/chip_sim_cfg.hjson b/hw/top_matcha/dv/chip_sim_cfg.hjson
index 0a049d6..479eae3 100644
--- a/hw/top_matcha/dv/chip_sim_cfg.hjson
+++ b/hw/top_matcha/dv/chip_sim_cfg.hjson
@@ -837,7 +837,7 @@
     {
       name: chip_sw_spi_device_pass_through_collision
       uvm_test_seq: chip_sw_spi_passthrough_collision_vseq
-      sw_images: ["//sw/device/tests/sim_dv:spi_passthrough_test:1"]
+      sw_images: ["//sw/device/tests/sim_dv:spi_passthrough_test:1:matcha"]
       en_run_modes: ["sw_test_mode_test_rom"]
     }
     {
@@ -849,7 +849,7 @@
     {
       name: chip_sw_flash_ctrl_ops
       uvm_test_seq: chip_sw_base_vseq
-      sw_images: ["//sw/device/tests:flash_ctrl_ops_test:1"]
+      sw_images: ["//sw/device/tests:flash_ctrl_ops_test:1:matcha"]
       en_run_modes: ["sw_test_mode_test_rom"]
       run_opts: ["+sw_test_timeout_ns=14_000_000"]
     }
@@ -2145,6 +2145,7 @@
         "chip_sw_flash_ctrl_access",
         "chip_sw_flash_ctrl_access_jitter_en",
         "chip_sw_flash_ctrl_access_jitter_en_reduced_freq",
+        "chip_sw_flash_ctrl_ops",
         "chip_sw_gpio",
         "chip_sw_hmac_enc",
         "chip_sw_hmac_smoketest",
@@ -2208,6 +2209,7 @@
         "chip_sw_smc_tlul_mailbox_test",
         "chip_sw_smc_virtual_memory_test",
         "chip_sw_spi_device_pass_through",
+        "chip_sw_spi_device_pass_through_collision",
         "chip_sw_spi_device_tx_rx",
         "chip_sw_spi_host_tx_rx",
         "chip_sw_sram_ctrl_execution_main",
@@ -2266,6 +2268,7 @@
         "chip_sw_flash_ctrl_access",
         "chip_sw_flash_ctrl_access_jitter_en",
         "chip_sw_flash_ctrl_access_jitter_en_reduced_freq",
+        "chip_sw_flash_ctrl_ops",
         "chip_sw_gpio",
         "chip_sw_hmac_enc",
         "chip_sw_hmac_smoketest",
@@ -2338,6 +2341,7 @@
         "chip_sw_smc_tlul_mailbox_test",
         "chip_sw_smc_virtual_memory_test",
         "chip_sw_spi_device_pass_through",
+        "chip_sw_spi_device_pass_through_collision",
         "chip_sw_spi_device_tx_rx",
         "chip_sw_spi_host_tx_rx",
         "chip_sw_sram_ctrl_execution_main",
diff --git a/sw/device/tests/BUILD b/sw/device/tests/BUILD
index c012506..0ca35ef 100644
--- a/sw/device/tests/BUILD
+++ b/sw/device/tests/BUILD
@@ -1246,6 +1246,19 @@
     ],
 )
 
+matcha_dv_test(
+    name = "flash_ctrl_ops_test",
+    srcs = ["flash_ctrl_ops_test.c"],
+    deps = [
+        ":test_dv_lib",
+        "//sw/device/lib/dif:rv_plic_sec",
+        "//sw/device/lib/testing:isr_testutils",
+        "@lowrisc_opentitan//sw/device/lib/dif:flash_ctrl",
+        "@lowrisc_opentitan//sw/device/lib/testing:flash_ctrl_testutils",
+        "@lowrisc_opentitan//sw/device/lib/testing:rv_plic_testutils",
+    ],
+)
+
 # Smoke tests
 matcha_dv_test(
     name = "aes_smoketest",
diff --git a/sw/device/tests/flash_ctrl_ops_test.c b/sw/device/tests/flash_ctrl_ops_test.c
new file mode 100644
index 0000000..ea8ef8c
--- /dev/null
+++ b/sw/device/tests/flash_ctrl_ops_test.c
@@ -0,0 +1,348 @@
+// Copyright 2023 Google LLC.
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "hw/top_matcha/sw/autogen/top_matcha.h"
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/dif/dif_flash_ctrl.h"
+#include "sw/device/lib/dif/dif_rv_plic.h"
+#include "sw/device/lib/runtime/irq.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/autogen/isr_testutils.h"
+#include "sw/device/lib/testing/flash_ctrl_testutils.h"
+#include "sw/device/lib/testing/rv_plic_testutils.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/test_framework/ottf_main.h"
+
+#define FLASH_CTRL_NUM_IRQS 5
+
+OTTF_DEFINE_TEST_CONFIG();
+
+static dif_rv_plic_t plic0;
+static dif_flash_ctrl_state_t flash_state;
+static dif_flash_ctrl_t flash_ctrl;
+
+static plic_isr_ctx_t plic_ctx = {
+    .rv_plic = &plic0,
+    .hart_id = kTopMatchaPlicTargetIbex0,
+};
+
+static flash_ctrl_isr_ctx_t flash_ctx = {
+    .flash_ctrl = &flash_ctrl,
+    .plic_flash_ctrl_start_irq_id = kTopMatchaPlicIrqIdFlashCtrlProgEmpty,
+    .is_only_irq = false,
+};
+
+enum {
+  kFlashInfoPageIdCreatorSecret = 1,
+  kFlashInfoPageIdOwnerSecret = 2,
+  kFlashInfoPageIdIsoPart = 3,
+  kFlashInfoBank = 0,
+  kRegionBaseBank0Page0Index = 0,
+  kRegionBaseBank1Page0Index = 256,
+  kRegionBaseBank1Page255Index = 511,
+  kFlashBank0DataRegion = 0,
+  kFlashBank1DataRegion = 1,
+  kPartitionId = 0,
+  kRegionSize = 1,
+  kInfoSize = 16,
+  kDataSize = 32,
+  kPageSize = 2048,
+};
+
+const uint32_t kRandomData1[kInfoSize] = {
+    0xb295d21b, 0xecdfbdcd, 0x67e7ab2d, 0x6f660b08, 0x273bf65c, 0xe80f1695,
+    0x586b80db, 0xc3dba27e, 0xdc124c5d, 0xb01ccd52, 0x815713e1, 0x31a141b2,
+    0x2124be3b, 0x299a6f2a, 0x1f2a4741, 0x1a073cc0,
+};
+
+const uint32_t kRandomData2[kInfoSize] = {
+    0x69e705a0, 0x65c2ec6b, 0x04b0b634, 0x59313526, 0x1858aee1, 0xd49f3ba9,
+    0x230bcd38, 0xc1eb6b3e, 0x68c15e3b, 0x024d02a9, 0x0b062ae4, 0x334dd155,
+    0x53fdbf8a, 0x3792f1e2, 0xee317161, 0x33b19bf3,
+};
+
+const uint32_t kRandomData3[kInfoSize] = {
+    0x2b78dbf5, 0x3e6e5a00, 0xbf82c6d5, 0x68d8e33f, 0x9c524bbc, 0xac5beeef,
+    0x1287ca5a, 0x12b61419, 0x872e709f, 0xf91b7c0c, 0x18312a1f, 0x325cef9a,
+    0x19fefa95, 0x4ceb421b, 0xa57d74c4, 0xaf1d723d,
+};
+
+const uint32_t kRandomData4[kDataSize] = {
+    0x0f5b84a3, 0xfa0330c3, 0xe125d174, 0x959d9779, 0xe10da3ba, 0x739e804d,
+    0xf8f8c317, 0xf236e75f, 0xa2118c37, 0x2d12fa9d, 0xa6fd72cd, 0x4b21d3dc,
+    0x6d36ca93, 0xbac514a6, 0x5f5695f8, 0xe7fdbe07, 0xde77eac9, 0x5ee7432f,
+    0xc7d26081, 0xae1d7262, 0x47d46715, 0x9da2de97, 0xa41e639d, 0x34470ce0,
+    0x8ac69175, 0x1dbcd910, 0x8193d43e, 0xe1538689, 0x166599e1, 0x0d5cc465,
+    0x86298854, 0x93121b13,
+};
+
+const uint32_t kRandomData5[kDataSize] = {
+    0xe5214227, 0x8473a570, 0xc6fc9728, 0x6110fbbe, 0xa2b4cdc8, 0x0156836a,
+    0xa0c90954, 0x23e66c9b, 0x607c9e7c, 0x40f993b6, 0x253dfc7d, 0xe0c70727,
+    0xa7b974ea, 0x0e8561c8, 0xfe8858a9, 0x36bf06bc, 0x2a734e91, 0xf0aca1e6,
+    0x6e22f4c5, 0x469cb0a2, 0x0f6bbc43, 0xc719f5cd, 0x0a129d7d, 0x9a6c171e,
+    0x1b39ff3a, 0x9644ab82, 0x5209d14c, 0x46a7e380, 0x575b1e0b, 0x4af5e8c3,
+    0xfcbbfa64, 0xe3afddf2,
+};
+
+static volatile bool expected_irqs[FLASH_CTRL_NUM_IRQS];
+static volatile bool fired_irqs[FLASH_CTRL_NUM_IRQS];
+
+/**
+ * Provides external IRQ handling for this test.
+ *
+ * This function overrides the default OTTF external ISR.
+ */
+void ottf_external_isr(void) {
+  top_matcha_plic_peripheral_t peripheral_serviced;
+  dif_flash_ctrl_irq_t irq_serviced;
+  isr_testutils_flash_ctrl_isr(plic_ctx, flash_ctx, &peripheral_serviced,
+                               &irq_serviced);
+  CHECK(peripheral_serviced == kTopMatchaPlicPeripheralFlashCtrl,
+        "Interurpt from unexpected peripheral: %d", peripheral_serviced);
+  fired_irqs[irq_serviced] = true;
+}
+
+/**
+ * Clear the volatile IRQ variables.
+ */
+static void clear_irq_variables(void) {
+  for (int i = 0; i < FLASH_CTRL_NUM_IRQS; ++i) {
+    expected_irqs[i] = false;
+    fired_irqs[i] = false;
+  }
+}
+
+/**
+ * Initializes FLASH_CTRL and enables the relevant interrupts.
+ */
+static void flash_ctrl_init_with_irqs(mmio_region_t base_addr,
+                                      dif_flash_ctrl_state_t *flash_state,
+                                      dif_flash_ctrl_t *flash_ctrl) {
+  CHECK_DIF_OK(dif_flash_ctrl_init(base_addr, flash_ctrl));
+  CHECK_DIF_OK(dif_flash_ctrl_init_state(flash_state, base_addr));
+
+  for (int i = 0; i < FLASH_CTRL_NUM_IRQS; ++i) {
+    CHECK_DIF_OK(dif_flash_ctrl_irq_set_enabled(
+        flash_ctrl, kDifFlashCtrlIrqProgEmpty + i, kDifToggleEnabled));
+  }
+  clear_irq_variables();
+}
+
+/**
+ * Compares the expected and fired IRQs and clears both.
+ */
+static void compare_and_clear_irq_variables(void) {
+  for (int i = 0; i < FLASH_CTRL_NUM_IRQS; ++i) {
+    CHECK(expected_irqs[i] == fired_irqs[i], "expected IRQ mismatch = %d", i);
+  }
+  clear_irq_variables();
+}
+
+/**
+ * Check data read from host interface against known data.
+ */
+static void read_and_check_host_if(uint32_t addr, const uint32_t *check_data) {
+  mmio_region_t flash_addr =
+      mmio_region_from_addr(TOP_MATCHA_EFLASH_BASE_ADDR + addr);
+  uint32_t host_data[kDataSize];
+  for (int i = 0; i < kDataSize; ++i) {
+    host_data[i] = mmio_region_read32(flash_addr, i * sizeof(uint32_t));
+  }
+  CHECK_ARRAYS_EQ(host_data, check_data, kDataSize);
+}
+
+/**
+ * Tests the interrupts for erase, write and
+ * read of the specified information partition.
+ * Confirms that the written data is read back correctly.
+ */
+static void do_info_partition_test(uint32_t partition_number,
+                                   const uint32_t *test_data) {
+  uint32_t address = flash_ctrl_testutils_info_region_setup(
+      &flash_state, partition_number, kFlashInfoBank, kPartitionId);
+
+  CHECK_DIF_OK(dif_flash_ctrl_set_prog_fifo_watermark(&flash_state, 0));
+  CHECK_DIF_OK(dif_flash_ctrl_set_read_fifo_watermark(&flash_state, 8));
+
+  clear_irq_variables();
+
+  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
+  CHECK(flash_ctrl_testutils_erase_page(&flash_state, address, kPartitionId,
+                                        kDifFlashCtrlPartitionTypeInfo));
+  compare_and_clear_irq_variables();
+
+  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
+  expected_irqs[kDifFlashCtrlIrqProgEmpty] = true;
+  expected_irqs[kDifFlashCtrlIrqProgLvl] = true;
+  CHECK(flash_ctrl_testutils_write(&flash_state, address, kPartitionId,
+                                   test_data, kDifFlashCtrlPartitionTypeInfo,
+                                   kInfoSize));
+
+  compare_and_clear_irq_variables();
+
+  uint32_t readback_data[kInfoSize];
+  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
+  expected_irqs[kDifFlashCtrlIrqRdLvl] = true;
+  expected_irqs[kDifFlashCtrlIrqRdFull] = true;
+  CHECK(flash_ctrl_testutils_read(&flash_state, address, kPartitionId,
+                                  readback_data, kDifFlashCtrlPartitionTypeInfo,
+                                  kInfoSize, 1));
+
+  compare_and_clear_irq_variables();
+
+  CHECK_ARRAYS_EQ(readback_data, test_data, kInfoSize);
+}
+
+/**
+ * Tests the interrupts for read of bank0 data partition.
+ * Only read is tested as this partition contains the program
+ * code so should not be erased or written.
+ * The data read via the flash_ctrl interface is checked against the
+ * data read via the host interface.
+ */
+static void do_bank0_data_partition_test(void) {
+  uint32_t address = flash_ctrl_testutils_data_region_setup(
+      &flash_state, kRegionBaseBank0Page0Index, kFlashBank0DataRegion,
+      kRegionSize);
+
+  CHECK_DIF_OK(dif_flash_ctrl_set_read_fifo_watermark(&flash_state, 8));
+
+  clear_irq_variables();
+  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
+  expected_irqs[kDifFlashCtrlIrqRdLvl] = true;
+  expected_irqs[kDifFlashCtrlIrqRdFull] = true;
+
+  uint32_t readback_data[kDataSize];
+  CHECK(flash_ctrl_testutils_read(&flash_state, address, kPartitionId,
+                                  readback_data, kDifFlashCtrlPartitionTypeData,
+                                  kDataSize, 1));
+
+  compare_and_clear_irq_variables();
+  read_and_check_host_if(0, readback_data);
+}
+
+/**
+ * Tests the interrupts for erase, write and read of
+ * the lowest and highest page of bank 1 data partition.
+ * Confirms that the written data is read back correctly.
+ * The whole bank is then erased and the interrupt is checked
+ * followed by confirmation that the previously written data
+ * has been wiped.
+ */
+static void do_bank1_data_partition_test(void) {
+  uint32_t address;
+
+  CHECK_DIF_OK(dif_flash_ctrl_set_prog_fifo_watermark(&flash_state, 0));
+  CHECK_DIF_OK(dif_flash_ctrl_set_read_fifo_watermark(&flash_state, 8));
+
+  // Loop for low and high page erase, write and read.
+  for (int i = 0; i < 2; ++i) {
+    uint32_t page_index =
+        (i == 0) ? kRegionBaseBank1Page0Index : kRegionBaseBank1Page255Index;
+    const uint32_t *test_data = (i == 0) ? kRandomData4 : kRandomData5;
+
+    address = flash_ctrl_testutils_data_region_setup(
+        &flash_state, page_index, kFlashBank1DataRegion, kRegionSize);
+
+    clear_irq_variables();
+
+    expected_irqs[kDifFlashCtrlIrqOpDone] = true;
+    CHECK(flash_ctrl_testutils_erase_page(&flash_state, address, kPartitionId,
+                                          kDifFlashCtrlPartitionTypeData));
+
+    compare_and_clear_irq_variables();
+
+    expected_irqs[kDifFlashCtrlIrqOpDone] = true;
+    expected_irqs[kDifFlashCtrlIrqProgEmpty] = true;
+    expected_irqs[kDifFlashCtrlIrqProgLvl] = true;
+    CHECK(flash_ctrl_testutils_write(&flash_state, address, kPartitionId,
+                                     test_data, kDifFlashCtrlPartitionTypeData,
+                                     kDataSize));
+
+    compare_and_clear_irq_variables();
+
+    uint32_t readback_data[kDataSize];
+    expected_irqs[kDifFlashCtrlIrqOpDone] = true;
+    expected_irqs[kDifFlashCtrlIrqRdLvl] = true;
+    expected_irqs[kDifFlashCtrlIrqRdFull] = true;
+    CHECK(flash_ctrl_testutils_read(
+        &flash_state, address, kPartitionId, readback_data,
+        kDifFlashCtrlPartitionTypeData, kDataSize, 1));
+
+    compare_and_clear_irq_variables();
+
+    read_and_check_host_if(kPageSize * page_index, test_data);
+    CHECK_ARRAYS_EQ(readback_data, test_data, kDataSize);
+  }
+
+  // Erasing the whole of bank 1.
+  CHECK_DIF_OK(dif_flash_ctrl_set_bank_erase_enablement(&flash_state, 1,
+                                                        kDifToggleEnabled));
+  expected_irqs[kDifFlashCtrlIrqOpDone] = true;
+
+  address = flash_ctrl_testutils_data_region_setup(
+      &flash_state, kRegionBaseBank1Page0Index, kFlashBank1DataRegion,
+      kRegionSize);
+  dif_flash_ctrl_transaction_t transaction = {
+      .byte_address = address,
+      .op = kDifFlashCtrlOpBankErase,
+      .partition_type = kDifFlashCtrlPartitionTypeData,
+      .partition_id = 0x0,
+      .word_count = 0x0};
+  CHECK_DIF_OK(dif_flash_ctrl_start(&flash_state, transaction));
+  CHECK(flash_ctrl_testutils_wait_transaction_end(&flash_state));
+
+  compare_and_clear_irq_variables();
+
+  // Loop for low and high page read back after bank erase.
+  for (int i = 0; i < 2; ++i) {
+    uint32_t page_index =
+        (i == 0) ? kRegionBaseBank1Page0Index : kRegionBaseBank1Page255Index;
+
+    address = flash_ctrl_testutils_data_region_setup(
+        &flash_state, page_index, kFlashBank1DataRegion, kRegionSize);
+
+    uint32_t readback_data[kDataSize];
+    expected_irqs[kDifFlashCtrlIrqOpDone] = true;
+    expected_irqs[kDifFlashCtrlIrqRdLvl] = true;
+    expected_irqs[kDifFlashCtrlIrqRdFull] = true;
+    CHECK(flash_ctrl_testutils_read(
+        &flash_state, address, kPartitionId, readback_data,
+        kDifFlashCtrlPartitionTypeData, kDataSize, 1));
+
+    compare_and_clear_irq_variables();
+
+    uint32_t expected_data[kDataSize];
+    memset(expected_data, 0xff, sizeof(expected_data));
+
+    read_and_check_host_if(kPageSize * page_index, expected_data);
+    CHECK_ARRAYS_EQ(readback_data, expected_data, kDataSize);
+  }
+}
+
+bool test_main(void) {
+  CHECK_DIF_OK(dif_rv_plic_init(
+      mmio_region_from_addr(TOP_MATCHA_RV_PLIC_BASE_ADDR), &plic0));
+
+  flash_ctrl_init_with_irqs(
+      mmio_region_from_addr(TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR), &flash_state,
+      &flash_ctrl);
+  rv_plic_testutils_irq_range_enable(&plic0, plic_ctx.hart_id,
+                                     kTopMatchaPlicIrqIdFlashCtrlProgEmpty,
+                                     kTopMatchaPlicIrqIdFlashCtrlOpDone);
+
+  // Enable the external IRQ at Ibex.
+  irq_global_ctrl(true);
+  irq_external_ctrl(true);
+
+  do_info_partition_test(kFlashInfoPageIdCreatorSecret, kRandomData1);
+  do_info_partition_test(kFlashInfoPageIdOwnerSecret, kRandomData2);
+  do_info_partition_test(kFlashInfoPageIdIsoPart, kRandomData3);
+  do_bank0_data_partition_test();
+  do_bank1_data_partition_test();
+
+  return true;
+}