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