These tests ensure that the new UEFI SPI I/O protocol support works as
expected. They intended to execute on the sandbox target.

Signed-off-by: Paul Barker <paul.bar...@sancloud.com>
---
 MAINTAINERS                                  |   1 +
 arch/sandbox/dts/test.dts                    |  13 +
 lib/efi_selftest/Makefile                    |   1 +
 lib/efi_selftest/efi_selftest_spi_protocol.c | 284 +++++++++++++++++++
 4 files changed, 299 insertions(+)
 create mode 100644 lib/efi_selftest/efi_selftest_spi_protocol.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 6a82cdbbb474..54742e759e4c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -931,6 +931,7 @@ M:  Paul Barker <paul.bar...@sancloud.com>
 S:     Maintained
 F:     include/efi_spi_protocol.h
 F:     lib/efi_loader/efi_spi_protocol.c
+F:     lib/efi_selftest/efi_selftest_spi_protocol.c
 
 ENVIRONMENT
 M:     Joe Hershberger <joe.hershber...@ni.com>
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index dffe10adbf47..003af61113a8 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -1253,6 +1253,13 @@
                        compatible = "spansion,m25p16", "jedec,spi-nor";
                        spi-max-frequency = <40000000>;
                        sandbox,filename = "spi.bin";
+
+                       u-boot,uefi-spi-vendor = "spansion";
+                       u-boot,uefi-spi-part-number = "mt25p16";
+
+                       /* GUID in UEFI format: 
b881eb5d-ad92-4a48-8fdd-fa75a8e4c6b8 */
+                       u-boot,uefi-spi-io-guid = [5d eb 81 b8 92 ad 48 4a
+                                                  8f dd fa 75 a8 e4 c6 b8];
                };
                spi.bin@1 {
                        reg = <1>;
@@ -1261,6 +1268,12 @@
                        sandbox,filename = "spi.bin";
                        spi-cpol;
                        spi-cpha;
+
+                       u-boot,uefi-spi-vendor = "spansion";
+                       u-boot,uefi-spi-part-number = "mt25p16";
+                       /* GUID in UEFI format: 
b6b39ecd-2b1f-a643-b8d7-3192d7cf7270 */
+                       u-boot,uefi-spi-io-guid = [cd 9e b3 b6 1f 2b 43 a6
+                                                  b8 d7 31 92 d7 cf 72 70];
                };
        };
 
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
index e4d75420bff6..e2c4fcd40795 100644
--- a/lib/efi_selftest/Makefile
+++ b/lib/efi_selftest/Makefile
@@ -63,6 +63,7 @@ obj-$(CONFIG_EFI_LOADER_HII) += efi_selftest_hii.o
 obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_selftest_rng.o
 obj-$(CONFIG_EFI_GET_TIME) += efi_selftest_rtc.o
 obj-$(CONFIG_EFI_TCG2_PROTOCOL) += efi_selftest_tcg2.o
+obj-$(CONFIG_EFI_SPI_PROTOCOL) += efi_selftest_spi_protocol.o
 
 ifeq ($(CONFIG_GENERATE_ACPI_TABLE),)
 obj-y += efi_selftest_fdt.o
diff --git a/lib/efi_selftest/efi_selftest_spi_protocol.c 
b/lib/efi_selftest/efi_selftest_spi_protocol.c
new file mode 100644
index 000000000000..946d04dbb557
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_spi_protocol.c
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Micron Technology, Inc.
+ */
+
+#include <efi_selftest.h>
+#include <efi_spi_protocol.h>
+
+static struct efi_boot_services *boottime;
+static efi_guid_t efi_spi_configuration_guid = EFI_SPI_CONFIGURATION_GUID;
+
+static int setup(const efi_handle_t img_handle,
+                const struct efi_system_table *systable)
+{
+       boottime = systable->boottime;
+       return EFI_ST_SUCCESS;
+}
+
+static int test_peripheral(struct efi_spi_peripheral *p, struct efi_spi_bus 
*bus)
+{
+       struct efi_spi_io_protocol *io_protocol;
+       u8 req[5], resp[5];
+       efi_status_t ret;
+
+       if (!p->friendly_name) {
+               efi_st_error("SPI peripheral lacks a friendly name\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!p->spi_peripheral_driver_guid) {
+               efi_st_error("SPI peripheral lacks driver GUID\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!p->spi_part) {
+               efi_st_error("SPI peripheral lacks SPI part definition\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!p->max_clock_hz) {
+               efi_st_error("SPI peripheral has a max clock rate of zero\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!p->spi_bus) {
+               efi_st_error("SPI peripheral lack pointer to SPI bus\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (p->spi_bus != bus) {
+               efi_st_error("SPI peripheral spi_bus pointer points to the 
wrong bus\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!p->chip_select) {
+               efi_st_error("SPI peripheral lacks chip_select function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!p->spi_part->vendor) {
+               efi_st_error("SPI part lacks vendor string\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!p->spi_part->part_number) {
+               efi_st_error("SPI part lacks part number string\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (p->spi_part->min_clock_hz > p->spi_part->max_clock_hz) {
+               efi_st_error("SPI part min clock rate is greater than max clock 
rate\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (p->spi_part->max_clock_hz != p->max_clock_hz) {
+               efi_st_error("SPI part max clock rate does not match peripheral 
max clock rate\n");
+               return EFI_ST_FAILURE;
+       }
+
+       ret = boottime->locate_protocol(p->spi_peripheral_driver_guid,
+                                       NULL, (void **)&io_protocol);
+       if (ret != EFI_SUCCESS) {
+               efi_st_error("SPI IO protocol not available\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (io_protocol->spi_peripheral != p) {
+               efi_st_error("SPI IO protocol spi_peripheral pointer points to 
the wrong peripheral\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (io_protocol->original_spi_peripheral != p) {
+               efi_st_error("SPI IO protocol original_spi_peripheral pointer 
points to the wrong peripheral\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!io_protocol->maximum_transfer_bytes) {
+               efi_st_error("SPI IO protocol has zero maximum transfer 
size\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!io_protocol->legacy_spi_protocol) {
+               efi_st_error("SPI IO protocol lacks legacy SPI protocol\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!io_protocol->transaction) {
+               efi_st_error("SPI IO protocol lacks transaction function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!io_protocol->update_spi_peripheral) {
+               efi_st_error("SPI IO protocol lacks update_spi_peripheral 
function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!io_protocol->legacy_spi_protocol->erase_block_opcode) {
+               efi_st_error("SPI legacy controller protocol lacks 
erase_block_opcode function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (io_protocol->legacy_spi_protocol->erase_block_opcode(
+                       io_protocol->legacy_spi_protocol,
+                       0) != EFI_UNSUPPORTED) {
+               efi_st_error("Incorrect return value from SPI legacy controller 
protocol erase_block_opcode function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!io_protocol->legacy_spi_protocol->write_status_prefix) {
+               efi_st_error("SPI legacy controller protocol lacks 
write_status_prefix function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (io_protocol->legacy_spi_protocol->write_status_prefix(
+                       io_protocol->legacy_spi_protocol,
+                       0) != EFI_UNSUPPORTED) {
+               efi_st_error("Incorrect return value from SPI legacy controller 
protocol write_status_prefix function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!io_protocol->legacy_spi_protocol->bios_base_address) {
+               efi_st_error("SPI legacy controller protocol lacks 
bios_base_address function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (io_protocol->legacy_spi_protocol->bios_base_address(
+                       io_protocol->legacy_spi_protocol,
+                       0) != EFI_UNSUPPORTED) {
+               efi_st_error("Incorrect return value from SPI legacy controller 
protocol bios_base_address function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!io_protocol->legacy_spi_protocol->clear_spi_protect) {
+               efi_st_error("SPI legacy controller protocol lacks 
clear_spi_protect function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (io_protocol->legacy_spi_protocol->clear_spi_protect(
+                       io_protocol->legacy_spi_protocol) != EFI_UNSUPPORTED) {
+               efi_st_error("Incorrect return value from SPI legacy controller 
protocol clear_spi_protect function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!io_protocol->legacy_spi_protocol->is_range_protected) {
+               efi_st_error("SPI legacy controller protocol lacks 
is_range_protected function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (io_protocol->legacy_spi_protocol->is_range_protected(
+                       io_protocol->legacy_spi_protocol,
+                       0, 0)) {
+               efi_st_error("Incorrect return value from SPI legacy controller 
protocol is_range_protected function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!io_protocol->legacy_spi_protocol->protect_next_range) {
+               efi_st_error("SPI legacy controller protocol lacks 
protect_next_range function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (io_protocol->legacy_spi_protocol->protect_next_range(
+                       io_protocol->legacy_spi_protocol,
+                       0, 0) != EFI_UNSUPPORTED) {
+               efi_st_error("Incorrect return value from SPI legacy controller 
protocol protect_next_range function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!io_protocol->legacy_spi_protocol->lock_controller) {
+               efi_st_error("SPI legacy controller protocol lacks 
lock_controller function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (io_protocol->legacy_spi_protocol->lock_controller(
+                       io_protocol->legacy_spi_protocol) != EFI_UNSUPPORTED) {
+               efi_st_error("Incorrect return value from SPI legacy controller 
protocol lock_controller function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       req[0] = 0x9f;
+       ret = io_protocol->transaction(io_protocol,
+                                      SPI_TRANSACTION_FULL_DUPLEX,
+                                      false, 0, 1, 8,
+                                      sizeof(req), req,
+                                      sizeof(resp), resp);
+       if (ret != EFI_SUCCESS) {
+               efi_st_error("SPI transaction failed\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if ((resp[0] != 0xff) || (resp[1] != 0x20) || (resp[2] != 0x20) || 
(resp[3] != 0x15)) {
+               efi_st_error("Incorrect response from sandbox SPI flash 
emulator\n");
+               return EFI_ST_FAILURE;
+       }
+
+       return EFI_ST_SUCCESS;
+}
+
+static int test_bus(struct efi_spi_bus *bus)
+{
+       struct efi_spi_peripheral *p;
+       int status;
+
+       if (!bus->friendly_name) {
+               efi_st_error("SPI bus lacks a friendly name\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!bus->peripheral_list) {
+               efi_st_error("SPI bus has zero peripherals\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!bus->clock) {
+               efi_st_error("SPI bus lacks clock function\n");
+               return EFI_ST_FAILURE;
+       }
+
+       for (p = bus->peripheral_list; p; p = p->next_spi_peripheral) {
+               status = test_peripheral(p, bus);
+               if (status) {
+                       efi_st_error("Failed testing SPI peripheral\n");
+                       return status;
+               }
+       }
+
+       return EFI_ST_SUCCESS;
+}
+
+static int execute(void)
+{
+       struct efi_spi_configuration_protocol *spi;
+       efi_status_t ret;
+       int status;
+       u32 i;
+
+       ret = boottime->locate_protocol(&efi_spi_configuration_guid,
+                                       NULL, (void **)&spi);
+       if (ret != EFI_SUCCESS) {
+               efi_st_error("SPI configuration protocol not available\n");
+               return EFI_ST_FAILURE;
+       }
+
+       if (!spi->bus_count) {
+               efi_st_error("SPI configuration protocol has zero busses\n");
+               return EFI_ST_FAILURE;
+       }
+
+       for (i = 0; i < spi->bus_count; i++) {
+               status = test_bus(spi->bus_list[i]);
+               if (status) {
+                       efi_st_error("Failed testing SPI bus %d\n", i);
+                       return status;
+               }
+       }
+
+       return EFI_ST_SUCCESS;
+}
+
+EFI_UNIT_TEST(spi_protocol) = {
+    .name = "SPI protocol",
+    .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+    .setup = setup,
+    .execute = execute,
+};
-- 
2.25.1

Reply via email to