u-boot.lists.denx.de archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/2] Support UEFI SPI I/O protocol
@ 2022-07-08  9:45 Paul Barker
  2022-07-08  9:45 ` [RFC PATCH 1/2] efi_loader: Add SPI I/O protocol support Paul Barker
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Paul Barker @ 2022-07-08  9:45 UTC (permalink / raw)
  To: u-boot, Heinrich Schuchardt; +Cc: Paul Barker

I'm looking for some initial feedback on the following patches which add support
for the UEFI SPI I/O protocol defined in the UEFI Platform Initialization (PI)
Specification, Version 1.7 Errata A (April 2020). I'd like to know if the
overall approach is acceptable for inclusion in u-boot and if you have any
questions or can spot any implementation issues at this stage. I'm planning to
follow up with a v2 series addressing any feedback and adding test cases.

Paul Barker (2):
  efi_loader: Add SPI I/O protocol support
  arm: dts: am335x-sancloud-bbe-lite: UEFI SPI export

 MAINTAINERS                               |   6 +
 arch/arm/dts/am335x-sancloud-bbe-lite.dts |   8 +-
 include/efi_loader.h                      |   4 +
 include/efi_spi_protocol.h                | 158 ++++++
 lib/efi_loader/Kconfig                    |   8 +
 lib/efi_loader/Makefile                   |   1 +
 lib/efi_loader/efi_setup.c                |   6 +
 lib/efi_loader/efi_spi_protocol.c         | 565 ++++++++++++++++++++++
 8 files changed, 754 insertions(+), 2 deletions(-)
 create mode 100644 include/efi_spi_protocol.h
 create mode 100644 lib/efi_loader/efi_spi_protocol.c


-- 
2.25.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [RFC PATCH 1/2] efi_loader: Add SPI I/O protocol support
  2022-07-08  9:45 [RFC PATCH 0/2] Support UEFI SPI I/O protocol Paul Barker
@ 2022-07-08  9:45 ` Paul Barker
  2022-07-08 20:21   ` Tom Rini
  2022-07-11 13:12   ` Ilias Apalodimas
  2022-07-08  9:45 ` [RFC PATCH 2/2] arm: dts: am335x-sancloud-bbe-lite: UEFI SPI export Paul Barker
  2022-07-08 20:33 ` [RFC PATCH 0/2] Support UEFI SPI I/O protocol Heinrich Schuchardt
  2 siblings, 2 replies; 8+ messages in thread
From: Paul Barker @ 2022-07-08  9:45 UTC (permalink / raw)
  To: u-boot, Heinrich Schuchardt; +Cc: Paul Barker

This addition allows UEFI applications running under u-boot to access
peripherals on SPI busses. It is based on the UEFI Platform
Initialization (PI) Specification, Version 1.7 Errata A (April 2020).
Only the core functionality required to discover SPI peripherals and
communicate with them is currently implemented. Other functionality such
as the legacy SPI controller interface and the ability to update the SPI
peripheral object associated with a particular SPI I/O protocol object
is currently unimplemented.

Since there are no open source implementations of this protocol to use
as an example, educated guesses/hacks have been made in cases where the
UEFI PI specification is unclear and these are documented in comments.

This implementation has been tested on the SanCloud BBE Lite and allowed
a UEFI test application to successfully communicate with a Micron
Authenta flash device connected via the SPI bus.

Signed-off-by: Paul Barker <paul.barker@sancloud.com>
---
 MAINTAINERS                       |   6 +
 include/efi_loader.h              |   4 +
 include/efi_spi_protocol.h        | 158 +++++++++
 lib/efi_loader/Kconfig            |   8 +
 lib/efi_loader/Makefile           |   1 +
 lib/efi_loader/efi_setup.c        |   6 +
 lib/efi_loader/efi_spi_protocol.c | 565 ++++++++++++++++++++++++++++++
 7 files changed, 748 insertions(+)
 create mode 100644 include/efi_spi_protocol.h
 create mode 100644 lib/efi_loader/efi_spi_protocol.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 7f27ff4c20fc..4f5a735567a4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -831,6 +831,12 @@ F:	tools/efivar.py
 F:	tools/file2include.c
 F:	tools/mkeficapsule.c
 
+EFI SPI SUPPORT
+M:	Paul Barker <paul.barker@sancloud.com>
+S:	Maintained
+F:	include/efi_spi_protocol.h
+F:	lib/efi_loader/efi_spi_protocol.c
+
 EFI VARIABLES VIA OP-TEE
 M:	Ilias Apalodimas <ilias.apalodimas@linaro.org>
 S:	Maintained
diff --git a/include/efi_loader.h b/include/efi_loader.h
index c1e00ebac398..8fd867a78db2 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -537,6 +537,10 @@ efi_status_t efi_rng_register(void);
 efi_status_t efi_tcg2_register(void);
 /* Called by efi_init_obj_list() to install RISCV_EFI_BOOT_PROTOCOL */
 efi_status_t efi_riscv_register(void);
+/* Called by efi_init_obj_list() to install EFI_SPI_CONFIGURATION_PROTOCOL &
+ * EFI_SPI_IO_PROTOCOL
+ */
+efi_status_t efi_spi_protocol_register(void);
 /* Called by efi_init_obj_list() to do initial measurement */
 efi_status_t efi_tcg2_do_initial_measurement(void);
 /* measure the pe-coff image, extend PCR and add Event Log */
diff --git a/include/efi_spi_protocol.h b/include/efi_spi_protocol.h
new file mode 100644
index 000000000000..1a4456bd9349
--- /dev/null
+++ b/include/efi_spi_protocol.h
@@ -0,0 +1,158 @@
+/* SPDX-License-Identifier: BSD-2-Clause-Patent */
+/*
+ * Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ */
+
+#ifndef _EFI_SPI_PROTOCOL_H
+#define _EFI_SPI_PROTOCOL_H
+
+#include <efi.h>
+#include <efi_api.h>
+
+#define EFI_SPI_CONFIGURATION_GUID  \
+	EFI_GUID(0x85a6d3e6, 0xb65b, 0x4afc,     \
+		 0xb3, 0x8f, 0xc6, 0xd5, 0x4a, 0xf6, 0xdd, 0xc8)
+
+struct efi_spi_peripheral;
+
+struct efi_spi_part {
+	efi_string_t vendor;
+	efi_string_t part_number;
+	u32 min_clock_hz;
+	u32 max_clock_hz;
+	bool chip_select_polarity;
+};
+
+struct efi_spi_bus {
+	efi_string_t friendly_name;
+	struct efi_spi_peripheral *peripheral_list;
+	struct efi_device_path *controller_path;
+
+	efi_status_t
+	(EFIAPI * clock)(const struct efi_spi_peripheral *spi_peripheral,
+		u32 *clock_hz);
+
+	void *clock_parameter;
+};
+
+struct efi_spi_peripheral {
+	struct efi_spi_peripheral *next_spi_peripheral;
+	efi_string_t friendly_name;
+	efi_guid_t *spi_peripheral_driver_guid;
+	struct efi_spi_part *spi_part;
+	u32 max_clock_hz;
+	bool clock_polarity;
+	bool clock_phase;
+	u32 attributes;
+	void *configuration_data;
+	struct efi_spi_bus *spi_bus;
+
+	efi_status_t
+	(EFIAPI * chip_select)(const struct efi_spi_peripheral *spi_peripheral,
+		bool pin_value);
+
+	void *chip_select_parameter;
+};
+
+struct efi_spi_configuration_protocol {
+	u32 bus_count;
+	struct efi_spi_bus **bus_list;
+};
+
+#define EFI_LEGACY_SPI_CONTROLLER_GUID  \
+	EFI_GUID(0x39136fc7, 0x1a11, 0x49de,         \
+		 0xbf, 0x35, 0x0e, 0x78, 0xdd, 0xb5, 0x24, 0xfc)
+
+struct efi_legacy_spi_controller_protocol;
+
+struct efi_legacy_spi_controller_protocol {
+	u32 maximum_offset;
+	u32 maximum_range_bytes;
+	u32 range_register_count;
+
+	efi_status_t
+	(EFIAPI * erase_block_opcode)(const struct efi_legacy_spi_controller_protocol *this,
+		u8 erase_block_opcode);
+
+	efi_status_t
+	(EFIAPI * write_status_prefix)(const struct efi_legacy_spi_controller_protocol *this,
+		u8 write_status_prefix);
+
+	efi_status_t
+	(EFIAPI * bios_base_address)(const struct efi_legacy_spi_controller_protocol *this,
+		u32 bios_base_address);
+
+	efi_status_t
+	(EFIAPI * clear_spi_protect)(const struct efi_legacy_spi_controller_protocol *this);
+
+	bool
+	(EFIAPI * is_range_protected)(const struct efi_legacy_spi_controller_protocol *this,
+		u32 bios_address,
+		u32 blocks_to_protect);
+
+	efi_status_t
+	(EFIAPI * protect_next_range)(const struct efi_legacy_spi_controller_protocol *this,
+		u32 bios_address,
+		u32 blocks_to_protect);
+
+	efi_status_t
+	(EFIAPI * lock_controller)(const struct efi_legacy_spi_controller_protocol *this);
+};
+
+struct efi_spi_io_protocol;
+
+enum efi_spi_transaction_type {
+	SPI_TRANSACTION_FULL_DUPLEX,
+	SPI_TRANSACTION_WRITE_ONLY,
+	SPI_TRANSACTION_READ_ONLY,
+	SPI_TRANSACTION_WRITE_THEN_READ
+};
+
+struct efi_spi_bus_transaction {
+	struct efi_spi_peripheral *spi_peripheral;
+	enum efi_spi_transaction_type transaction_type;
+	bool debug_transaction;
+	u32 bus_width;
+	u32 frame_size;
+	u32 write_bytes;
+	u8 *write_buffer;
+	u32 read_bytes;
+	u8 *read_buffer;
+};
+
+struct efi_spi_io_protocol {
+	struct efi_spi_peripheral *spi_peripheral;
+	struct efi_spi_peripheral *original_spi_peripheral;
+	u32 frame_size_support_mask;
+	u32 maximum_transfer_bytes;
+	u32 attributes;
+	struct efi_legacy_spi_controller_protocol *legacy_spi_protocol;
+
+	efi_status_t
+	(EFIAPI * transaction)(const struct efi_spi_io_protocol *this,
+		enum efi_spi_transaction_type transaction_type,
+		bool debug_transaction,
+		u32 clock_hz,
+		u32 bus_width,
+		u32 frame_size,
+		u32 write_bytes,
+		u8 *write_buffer,
+		u32 read_bytes,
+		u8 *read_buffer);
+
+	efi_status_t
+	(EFIAPI * update_spi_peripheral)(struct efi_spi_io_protocol *this,
+		struct efi_spi_peripheral *spi_peripheral);
+};
+
+struct efi_spi_peripheral_priv {
+	struct efi_spi_peripheral peripheral;
+	struct efi_spi_part part;
+	struct efi_spi_io_protocol io_protocol;
+	efi_handle_t handle;
+	struct spi_slave *target;
+};
+
+efi_status_t efi_spi_protocol_register(void);
+
+#endif
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index e2a1a5a69a24..621768c07201 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -393,4 +393,12 @@ config EFI_RISCV_BOOT_PROTOCOL
 	  replace the transfer via the device-tree. The latter is not
 	  possible on systems using ACPI.
 
+config EFI_SPI_PROTOCOL
+	bool "EFI SPI protocol support"
+	default y
+	help
+	  Provide implementations of EFI_SPI_CONFIGURATION_PROTOCOL and
+	  EFI_SPI_IO_PROTOCOL to allow UEFI applications to access devices
+	  connected via SPI bus.
+
 endif
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index aaaa25cefe01..47f4e51d2a2b 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -75,6 +75,7 @@ obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o
 obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o
 obj-$(CONFIG_EFI_TCG2_PROTOCOL) += efi_tcg2.o
 obj-$(CONFIG_EFI_RISCV_BOOT_PROTOCOL) += efi_riscv.o
+obj-$(CONFIG_EFI_SPI_PROTOCOL) += efi_spi_protocol.o
 obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_load_initrd.o
 obj-$(CONFIG_EFI_SIGNATURE_SUPPORT) += efi_signature.o
 
diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
index 492ecf4cb15c..ef1ee9862b72 100644
--- a/lib/efi_loader/efi_setup.c
+++ b/lib/efi_loader/efi_setup.c
@@ -295,6 +295,12 @@ efi_status_t efi_init_obj_list(void)
 			goto out;
 	}
 
+	if (IS_ENABLED(CONFIG_EFI_SPI_PROTOCOL)) {
+		ret = efi_spi_protocol_register();
+		if (ret != EFI_SUCCESS)
+			goto out;
+	}
+
 	/* Secure boot */
 	ret = efi_init_secure_boot();
 	if (ret != EFI_SUCCESS)
diff --git a/lib/efi_loader/efi_spi_protocol.c b/lib/efi_loader/efi_spi_protocol.c
new file mode 100644
index 000000000000..495704c25baa
--- /dev/null
+++ b/lib/efi_loader/efi_spi_protocol.c
@@ -0,0 +1,565 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Micron Technology, Inc.
+ */
+
+#define LOG_CATEGORY LOGC_EFI
+
+#include <common.h>
+#include <dm/device.h>
+#include <dm/read.h>
+#include <efi.h>
+#include <efi_loader.h>
+#include <efi_spi_protocol.h>
+#include <malloc.h>
+#include <spi.h>
+
+static efi_string_t convert_efi_string(const char *str)
+{
+	efi_string_t str_16, tmp;
+	size_t sz_8, sz_16;
+
+	sz_8 = strlen(str);
+	sz_16 = utf8_utf16_strlen(str);
+	str_16 = calloc(sz_16 + 1, 2);
+	if (!str_16)
+		return NULL;
+
+	tmp = str_16;
+	utf8_utf16_strcpy(&tmp, str);
+
+	return str_16;
+}
+
+static efi_status_t
+efi_spi_bus_clock(const struct efi_spi_peripheral *spi_peripheral,
+		  u32 *clock_hz)
+{
+	EFI_ENTRY("%p, %p", spi_peripheral, clock_hz);
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t
+efi_spi_peripheral_chip_select(const struct efi_spi_peripheral *spi_peripheral,
+			       bool pin_value)
+{
+	EFI_ENTRY("%p, %d", spi_peripheral, pin_value);
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t
+legacy_erase_block_opcode(const struct efi_legacy_spi_controller_protocol *this,
+			  u8 erase_block_opcode)
+{
+	EFI_ENTRY("%p, %u", this, erase_block_opcode);
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t
+legacy_write_status_prefix(const struct efi_legacy_spi_controller_protocol *this,
+			   u8 write_status_prefix)
+{
+	EFI_ENTRY("%p, %u", this, write_status_prefix);
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t
+legacy_bios_base_address(const struct efi_legacy_spi_controller_protocol *this,
+			 u32 bios_base_address)
+{
+	EFI_ENTRY("%p, %u", this, bios_base_address);
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t
+legacy_clear_spi_protect(const struct efi_legacy_spi_controller_protocol *this)
+{
+	EFI_ENTRY("%p", this);
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static bool
+legacy_is_range_protected(const struct efi_legacy_spi_controller_protocol *this,
+			  u32 bios_address,
+			  u32 blocks_to_protect)
+{
+	EFI_ENTRY("%p, %u, %u", this, bios_address, blocks_to_protect);
+	return EFI_EXIT(false);
+}
+
+static efi_status_t
+legacy_protect_next_range(const struct efi_legacy_spi_controller_protocol *this,
+			  u32 bios_address,
+			  u32 blocks_to_protect)
+{
+	EFI_ENTRY("%p, %u, %u", this, bios_address, blocks_to_protect);
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t
+legacy_lock_controller(const struct efi_legacy_spi_controller_protocol *this)
+{
+	EFI_ENTRY("%p", this);
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t
+efi_spi_io_update_spi_peripheral(struct efi_spi_io_protocol *this,
+				 struct efi_spi_peripheral *spi_peripheral)
+{
+	EFI_ENTRY("%p, %p", this, spi_peripheral);
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t
+efi_spi_io_transaction(const struct efi_spi_io_protocol *this,
+		       enum efi_spi_transaction_type transaction_type,
+		       bool debug_transaction,
+		       u32 clock_hz,
+		       u32 bus_width,
+		       u32 frame_size,
+		       u32 write_bytes,
+		       u8 *write_buffer,
+		       u32 read_bytes,
+		       u8 *read_buffer)
+{
+	struct spi_slave *target;
+	efi_status_t status = EFI_SUCCESS;
+	int r;
+
+	/* We ignore the bus_width and frame_size arguments to this function as the
+	 * appropriate bus configuration for the connected device will be performed
+	 * during spi_claim_bus().
+	 */
+
+	/* TODO: Print transaction details if debug_transaction is true. */
+
+	EFI_ENTRY("%p, %u, %u, %u, %u, %u, %u, %p, %u, %p",
+		  this, transaction_type, debug_transaction,
+		  clock_hz, bus_width frame_size,
+		  write_bytes, write_buffer, read_bytes, read_buffer);
+
+	if (!this)
+		return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+	target = container_of(this, struct efi_spi_peripheral_priv, io_protocol)->target;
+
+	if (clock_hz > this->spi_peripheral->max_clock_hz)
+		return EFI_EXIT(EFI_UNSUPPORTED);
+
+	r = spi_claim_bus(target);
+	if (r != 0)
+		return EFI_EXIT(EFI_DEVICE_ERROR);
+	EFI_PRINT("SPI IO: Bus claimed\n");
+
+	if (clock_hz) {
+		EFI_PRINT("SPI IO: Setting clock rate to %u Hz\n", clock_hz);
+		spi_get_ops(target->dev->parent)->set_speed(target->dev->parent, clock_hz);
+	} else {
+		EFI_PRINT("SPI IO: Using default clock rate\n");
+	}
+
+	switch (transaction_type) {
+	case SPI_TRANSACTION_FULL_DUPLEX:
+		EFI_PRINT("SPI IO: Full-duplex\n");
+		if (write_bytes != read_bytes || !write_bytes || !write_buffer || !read_buffer) {
+			status = EFI_INVALID_PARAMETER;
+			break;
+		}
+		r = spi_xfer(target, 8 * write_bytes,
+			     write_buffer, read_buffer, SPI_XFER_ONCE);
+		EFI_PRINT("SPI IO: xfer returned %d\n", r);
+		status = (r == 0) ? EFI_SUCCESS : EFI_DEVICE_ERROR;
+		break;
+	case SPI_TRANSACTION_READ_ONLY:
+		EFI_PRINT("SPI IO: Read-only\n");
+		if (!read_bytes || !read_buffer) {
+			status = EFI_INVALID_PARAMETER;
+			break;
+		}
+		r = spi_xfer(target, 8 * read_bytes,
+			     NULL, read_buffer, SPI_XFER_ONCE);
+		EFI_PRINT("SPI IO: xfer returned %d\n", r);
+		status = (r == 0) ? EFI_SUCCESS : EFI_DEVICE_ERROR;
+		break;
+	case SPI_TRANSACTION_WRITE_ONLY:
+		EFI_PRINT("SPI IO: Write-only\n");
+		if (!write_bytes || !write_buffer) {
+			status = EFI_INVALID_PARAMETER;
+			break;
+		}
+		r = spi_xfer(target, 8 * write_bytes,
+			     write_buffer, NULL, SPI_XFER_ONCE);
+		EFI_PRINT("SPI IO: xfer returned %d\n", r);
+		status = (r == 0) ? EFI_SUCCESS : EFI_DEVICE_ERROR;
+		break;
+	case SPI_TRANSACTION_WRITE_THEN_READ:
+		EFI_PRINT("SPI IO: Write-then-read\n");
+		if (!write_bytes || !write_buffer || !read_bytes || !read_buffer) {
+			status = EFI_INVALID_PARAMETER;
+			break;
+		}
+		r = spi_xfer(target, 8 * write_bytes,
+			     write_buffer, NULL, SPI_XFER_BEGIN);
+		EFI_PRINT("SPI IO: xfer [1/2] returned %d\n", r);
+		if (r != 0) {
+			status = EFI_DEVICE_ERROR;
+			break;
+		}
+		r = spi_xfer(target, 8 * read_bytes,
+			     NULL, read_buffer, SPI_XFER_END);
+		EFI_PRINT("SPI IO: xfer [2/2] returned %d\n", r);
+		status = (r == 0) ? EFI_SUCCESS : EFI_DEVICE_ERROR;
+		break;
+	default:
+		status = EFI_INVALID_PARAMETER;
+		break;
+	}
+
+	spi_release_bus(target);
+	EFI_PRINT("SPI IO: Released bus\n");
+	return EFI_EXIT(status);
+}
+
+static struct efi_device_path null_device_path = {
+	.type     = DEVICE_PATH_TYPE_END,
+	.sub_type = DEVICE_PATH_SUB_TYPE_END,
+	.length   = 4
+};
+
+static struct efi_legacy_spi_controller_protocol
+dummy_legacy_spi_controller_protocol = {
+	.maximum_offset = 0,
+	.maximum_range_bytes = 0,
+	.range_register_count = 0,
+	.erase_block_opcode = legacy_erase_block_opcode,
+	.write_status_prefix = legacy_write_status_prefix,
+	.bios_base_address = legacy_bios_base_address,
+	.clear_spi_protect = legacy_clear_spi_protect,
+	.is_range_protected = legacy_is_range_protected,
+	.protect_next_range = legacy_protect_next_range,
+	.lock_controller = legacy_lock_controller
+};
+
+static efi_guid_t efi_spi_configuration_guid = EFI_SPI_CONFIGURATION_GUID;
+
+static void destroy_efi_spi_peripheral(struct efi_spi_peripheral *peripheral)
+{
+	struct efi_spi_peripheral_priv *priv =
+		container_of(peripheral,
+			     struct efi_spi_peripheral_priv,
+			     peripheral);
+	free(priv->peripheral.friendly_name);
+	free(priv->part.vendor);
+	free(priv->part.part_number);
+	efi_delete_handle(priv->handle);
+	free(priv);
+}
+
+static void destroy_efi_spi_bus(struct efi_spi_bus *bus)
+{
+	struct efi_spi_peripheral *peripheral = bus->peripheral_list;
+
+	while (peripheral) {
+		struct efi_spi_peripheral *next =
+			peripheral->next_spi_peripheral;
+		destroy_efi_spi_peripheral(peripheral);
+		peripheral = next;
+	}
+	free(bus->friendly_name);
+	free(bus);
+}
+
+static efi_status_t efi_spi_new_handle(const efi_guid_t *guid, void *proto)
+{
+	efi_status_t status;
+	efi_handle_t handle;
+
+	status = efi_create_handle(&handle);
+	if (status != EFI_SUCCESS) {
+		printf("Failed to create EFI handle\n");
+		goto fail_1;
+	}
+
+	status = efi_add_protocol(handle, guid, proto);
+	if (status != EFI_SUCCESS) {
+		printf("Failed to add protocol\n");
+		goto fail_2;
+	}
+
+	return EFI_SUCCESS;
+
+fail_2:
+	efi_delete_handle(handle);
+fail_1:
+	return status;
+}
+
+static void
+efi_spi_init_part(struct efi_spi_part *part,
+		  struct spi_slave *target,
+		  efi_string_t vendor_utf16,
+		  efi_string_t part_number_utf16
+)
+{
+	part->vendor = vendor_utf16;
+	part->part_number = part_number_utf16;
+	part->min_clock_hz = 0;
+	part->max_clock_hz = target->max_hz;
+	part->chip_select_polarity =
+		(target->mode & SPI_CS_HIGH) ? true : false;
+}
+
+static void
+efi_spi_init_peripheral(struct efi_spi_peripheral *peripheral,
+			struct efi_spi_part *part,
+			struct efi_spi_bus *bus,
+			struct spi_slave *target,
+			efi_guid_t *guid,
+			efi_string_t name_utf16
+)
+{
+	peripheral->friendly_name = name_utf16;
+	peripheral->spi_part = part;
+	peripheral->next_spi_peripheral = NULL;
+	peripheral->spi_peripheral_driver_guid = guid;
+	peripheral->max_clock_hz = target->max_hz;
+	peripheral->clock_polarity = (target->mode & SPI_CPOL) ? true : false;
+	peripheral->clock_phase = (target->mode & SPI_CPHA) ? true : false;
+	peripheral->attributes = 0;
+	peripheral->configuration_data = NULL;
+	peripheral->spi_bus = bus;
+	peripheral->chip_select = efi_spi_peripheral_chip_select;
+	peripheral->chip_select_parameter = NULL;
+}
+
+static void
+efi_spi_append_peripheral(struct efi_spi_peripheral *peripheral,
+			  struct efi_spi_bus *bus
+)
+{
+	if (bus->peripheral_list) {
+		struct efi_spi_peripheral *tmp = bus->peripheral_list;
+
+		while (tmp->next_spi_peripheral)
+			tmp = tmp->next_spi_peripheral;
+
+		tmp->next_spi_peripheral = peripheral;
+	} else {
+		bus->peripheral_list = peripheral;
+	}
+}
+
+static void
+efi_spi_init_io_protocol(struct efi_spi_io_protocol *io_protocol,
+			 struct efi_spi_peripheral *peripheral,
+			 struct spi_slave *target
+)
+{
+	io_protocol->spi_peripheral = peripheral;
+	io_protocol->original_spi_peripheral = peripheral;
+	io_protocol->legacy_spi_protocol = &dummy_legacy_spi_controller_protocol;
+	io_protocol->transaction = efi_spi_io_transaction;
+	io_protocol->update_spi_peripheral = efi_spi_io_update_spi_peripheral;
+
+	/* This is a bit of a hack. The EFI data structures do not allow us to
+	 * represent a frame size greater than 32 bits.
+	 */
+	if (target->wordlen <= 32)
+		io_protocol->frame_size_support_mask =
+			1 << (target->wordlen - 1);
+	else
+		io_protocol->frame_size_support_mask = 0;
+
+	/* Again, this is a bit of a hack. The EFI data structures only allow
+	 * for a single maximum transfer size whereas the u-boot spi_slave
+	 * structure records maximum read transfer size and maximum write
+	 * transfer size separately. So we need to take the minimum of these two
+	 * values.
+	 */
+	if (target->max_read_size > target->max_write_size)
+		io_protocol->maximum_transfer_bytes = target->max_write_size;
+	else
+		io_protocol->maximum_transfer_bytes = target->max_read_size;
+
+	/* Hack++. Leave attributes set to zero since the flags listed in the
+	 * UEFI PI spec have no defined numerical values and so cannot be used.
+	 */
+	io_protocol->attributes = 0;
+}
+
+static efi_status_t
+export_spi_peripheral(struct efi_spi_bus *bus, struct udevice *dev)
+{
+	efi_string_t name_utf16, vendor_utf16, part_number_utf16;
+	struct efi_spi_peripheral_priv *priv;
+	efi_status_t status;
+	struct udevice *dev_bus = dev->parent;
+	struct spi_slave *target = dev_get_parent_priv(dev);
+	const char *name = dev_read_name(dev);
+	const char *vendor = dev_read_string(dev, "uefi-spi-vendor");
+	const char *part_number = dev_read_string(dev, "uefi-spi-part-number");
+	efi_guid_t *guid =
+		(efi_guid_t *)dev_read_u8_array_ptr(dev, "uefi-spi-io-guid", 16);
+
+	if (!vendor || !part_number || !guid) {
+		printf("Skipping SPI peripheral %s\n", name);
+		status = EFI_UNSUPPORTED;
+		goto fail_1;
+	}
+
+	printf("Registering SPI dev %d:%d, name %s\n",
+	       dev_bus->seq_, spi_chip_select(dev), name);
+
+	priv = calloc(1, sizeof(*priv));
+	if (!priv) {
+		status = EFI_OUT_OF_RESOURCES;
+		goto fail_1;
+	}
+
+	vendor_utf16 = convert_efi_string(vendor);
+	if (!vendor_utf16) {
+		status = EFI_OUT_OF_RESOURCES;
+		goto fail_2;
+	}
+
+	part_number_utf16 = convert_efi_string(part_number);
+	if (!part_number_utf16) {
+		status = EFI_OUT_OF_RESOURCES;
+		goto fail_3;
+	}
+
+	name_utf16 = convert_efi_string(name);
+	if (!name_utf16) {
+		status = EFI_OUT_OF_RESOURCES;
+		goto fail_4;
+	}
+
+	priv->target = target;
+
+	efi_spi_init_part(&priv->part, target, vendor_utf16, part_number_utf16);
+
+	efi_spi_init_peripheral(&priv->peripheral, &priv->part,
+				bus, target, guid, name_utf16);
+
+	efi_spi_append_peripheral(&priv->peripheral, bus);
+
+	efi_spi_init_io_protocol(&priv->io_protocol, &priv->peripheral, target);
+
+	status = efi_spi_new_handle(guid, &priv->io_protocol);
+	if (status != EFI_SUCCESS)
+		goto fail_5;
+
+	printf("Added EFI_SPI_IO_PROTOCOL with guid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
+	       guid->b[0], guid->b[1], guid->b[2], guid->b[3],
+	       guid->b[4], guid->b[5], guid->b[6], guid->b[7],
+	       guid->b[8], guid->b[9], guid->b[10], guid->b[11],
+	       guid->b[12], guid->b[13], guid->b[14], guid->b[15]);
+	return EFI_SUCCESS;
+
+fail_5:
+	free(name_utf16);
+fail_4:
+	free(part_number_utf16);
+fail_3:
+	free(vendor_utf16);
+fail_2:
+	free(priv);
+fail_1:
+	return status;
+}
+
+static struct efi_spi_bus *export_spi_bus(int i)
+{
+	struct efi_spi_bus *bus;
+	struct udevice *dev, *child;
+	const char *name;
+	int r;
+
+	r = uclass_get_device(UCLASS_SPI, i, &dev);
+	if (r < 0) {
+		printf("Failed to get SPI bus %d\n", i);
+		goto fail_1;
+	}
+
+	name = dev_read_name(dev);
+	printf("Registering SPI bus %d, name %s\n", i, name);
+
+	bus = calloc(1, sizeof(*bus));
+	if (!bus)
+		goto fail_1;
+
+	bus->friendly_name = convert_efi_string(name);
+	if (!bus->friendly_name)
+		goto fail_2;
+
+	bus->peripheral_list = NULL;
+	bus->clock = efi_spi_bus_clock;
+	bus->clock_parameter = NULL;
+
+	/* For the purposes of the current implementation, we do not need to expose
+	 * the hardware device path to users of the SPI I/O protocol.
+	 */
+	bus->controller_path = &null_device_path;
+
+	device_foreach_child(child, dev) {
+		efi_status_t status = export_spi_peripheral(bus, child);
+
+		if (status == EFI_OUT_OF_RESOURCES)
+			goto fail_3;
+	}
+
+	return bus;
+
+fail_3:
+	destroy_efi_spi_bus(bus);
+fail_2:
+	free(bus);
+fail_1:
+	return NULL;
+}
+
+efi_status_t efi_spi_protocol_register(void)
+{
+	efi_status_t status;
+	struct efi_spi_configuration_protocol *proto;
+	uint i;
+
+	printf("Registering EFI_SPI_CONFIGURATION_PROTOCOL\n");
+
+	proto = calloc(1, sizeof(*proto));
+	if (!proto) {
+		status = EFI_OUT_OF_RESOURCES;
+		goto fail_1;
+	}
+
+	proto->bus_count = uclass_id_count(UCLASS_SPI);
+	proto->bus_list = calloc(proto->bus_count, sizeof(*proto->bus_list));
+	if (!proto->bus_list) {
+		status = EFI_OUT_OF_RESOURCES;
+		goto fail_2;
+	}
+
+	for (i = 0; i < proto->bus_count; i++) {
+		proto->bus_list[i] = export_spi_bus(i);
+		if (!proto->bus_list[i])
+			goto fail_3;
+	}
+
+	status = efi_spi_new_handle(&efi_spi_configuration_guid, proto);
+	if (status != EFI_SUCCESS)
+		goto fail_3;
+
+	return EFI_SUCCESS;
+
+fail_3:
+	for (i = 0; i < proto->bus_count; i++) {
+		if (proto->bus_list[i])
+			destroy_efi_spi_bus(proto->bus_list[i]);
+	}
+	free(proto->bus_list);
+fail_2:
+	free(proto);
+fail_1:
+	return status;
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [RFC PATCH 2/2] arm: dts: am335x-sancloud-bbe-lite: UEFI SPI export
  2022-07-08  9:45 [RFC PATCH 0/2] Support UEFI SPI I/O protocol Paul Barker
  2022-07-08  9:45 ` [RFC PATCH 1/2] efi_loader: Add SPI I/O protocol support Paul Barker
@ 2022-07-08  9:45 ` Paul Barker
  2022-07-08 20:33 ` [RFC PATCH 0/2] Support UEFI SPI I/O protocol Heinrich Schuchardt
  2 siblings, 0 replies; 8+ messages in thread
From: Paul Barker @ 2022-07-08  9:45 UTC (permalink / raw)
  To: u-boot, Heinrich Schuchardt; +Cc: Paul Barker

Add properties to the Authenta SPI flash device node to enable access by
a UEFI application using a fixed GUID. Also specify that this device is
JEDEC compatible so that it is correctly initialized when running
`sf probe`.

Signed-off-by: Paul Barker <paul.barker@sancloud.com>
---
 arch/arm/dts/am335x-sancloud-bbe-lite.dts | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm/dts/am335x-sancloud-bbe-lite.dts b/arch/arm/dts/am335x-sancloud-bbe-lite.dts
index d6ef19311a91..01866f3c3ff7 100644
--- a/arch/arm/dts/am335x-sancloud-bbe-lite.dts
+++ b/arch/arm/dts/am335x-sancloud-bbe-lite.dts
@@ -37,14 +37,18 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&bb_spi0_pins>;
 
-	channel@0 {
+	authenta-flash@0 {
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		compatible = "micron,spi-authenta";
+		compatible = "micron,spi-authenta", "jedec,spi-nor";
 
 		reg = <0>;
 		spi-max-frequency = <16000000>;
 		spi-cpha;
+
+		uefi-spi-vendor = "micron";
+		uefi-spi-part-number = "mt25ql128abb";
+		uefi-spi-io-guid = [30671277 caa4 8643 b341 881fe18e7f7d];
 	};
 };
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [RFC PATCH 1/2] efi_loader: Add SPI I/O protocol support
  2022-07-08  9:45 ` [RFC PATCH 1/2] efi_loader: Add SPI I/O protocol support Paul Barker
@ 2022-07-08 20:21   ` Tom Rini
  2022-07-11 13:12   ` Ilias Apalodimas
  1 sibling, 0 replies; 8+ messages in thread
From: Tom Rini @ 2022-07-08 20:21 UTC (permalink / raw)
  To: Paul Barker; +Cc: u-boot, Heinrich Schuchardt

[-- Attachment #1: Type: text/plain, Size: 1356 bytes --]

On Fri, Jul 08, 2022 at 10:45:55AM +0100, Paul Barker wrote:

> This addition allows UEFI applications running under u-boot to access
> peripherals on SPI busses. It is based on the UEFI Platform
> Initialization (PI) Specification, Version 1.7 Errata A (April 2020).
> Only the core functionality required to discover SPI peripherals and
> communicate with them is currently implemented. Other functionality such
> as the legacy SPI controller interface and the ability to update the SPI
> peripheral object associated with a particular SPI I/O protocol object
> is currently unimplemented.
> 
> Since there are no open source implementations of this protocol to use
> as an example, educated guesses/hacks have been made in cases where the
> UEFI PI specification is unclear and these are documented in comments.
> 
> This implementation has been tested on the SanCloud BBE Lite and allowed
> a UEFI test application to successfully communicate with a Micron
> Authenta flash device connected via the SPI bus.
> 
> Signed-off-by: Paul Barker <paul.barker@sancloud.com>

Thanks for doing this.  I'll defer to Heinrich for implementation
comments but please for the next round don't enable it by default,
enable it on your platform.  It's good to add this, but we don't want to
grow most platforms in code size for it.

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [RFC PATCH 0/2] Support UEFI SPI I/O protocol
  2022-07-08  9:45 [RFC PATCH 0/2] Support UEFI SPI I/O protocol Paul Barker
  2022-07-08  9:45 ` [RFC PATCH 1/2] efi_loader: Add SPI I/O protocol support Paul Barker
  2022-07-08  9:45 ` [RFC PATCH 2/2] arm: dts: am335x-sancloud-bbe-lite: UEFI SPI export Paul Barker
@ 2022-07-08 20:33 ` Heinrich Schuchardt
  2022-07-09 10:35   ` Paul Barker
  2 siblings, 1 reply; 8+ messages in thread
From: Heinrich Schuchardt @ 2022-07-08 20:33 UTC (permalink / raw)
  To: u-boot, Paul Barker

Am 8. Juli 2022 11:45:54 MESZ schrieb Paul Barker <paul.barker@sancloud.com>:
>I'm looking for some initial feedback on the following patches which add support
>for the UEFI SPI I/O protocol defined in the UEFI Platform Initialization (PI)
>Specification, Version 1.7 Errata A (April 2020). I'd like to know if the
>overall approach is acceptable for inclusion in u-boot and if you have any
>questions or can spot any implementation issues at this stage. I'm planning to
>follow up with a v2 series addressing any feedback and adding test cases.

Hello Paul,

up to now U-Boot does not implement any part of the PI specification. Please, explain why we should implement this protocol.

For all EFI protocols there should be a test that can be run in our Gitlab CI showing that it is working correctly.

Best regards

Heinrich

>
>Paul Barker (2):
>  efi_loader: Add SPI I/O protocol support
>  arm: dts: am335x-sancloud-bbe-lite: UEFI SPI export
>
> MAINTAINERS                               |   6 +
> arch/arm/dts/am335x-sancloud-bbe-lite.dts |   8 +-
> include/efi_loader.h                      |   4 +
> include/efi_spi_protocol.h                | 158 ++++++
> lib/efi_loader/Kconfig                    |   8 +
> lib/efi_loader/Makefile                   |   1 +
> lib/efi_loader/efi_setup.c                |   6 +
> lib/efi_loader/efi_spi_protocol.c         | 565 ++++++++++++++++++++++
> 8 files changed, 754 insertions(+), 2 deletions(-)
> create mode 100644 include/efi_spi_protocol.h
> create mode 100644 lib/efi_loader/efi_spi_protocol.c
>
>


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [RFC PATCH 0/2] Support UEFI SPI I/O protocol
  2022-07-08 20:33 ` [RFC PATCH 0/2] Support UEFI SPI I/O protocol Heinrich Schuchardt
@ 2022-07-09 10:35   ` Paul Barker
  0 siblings, 0 replies; 8+ messages in thread
From: Paul Barker @ 2022-07-09 10:35 UTC (permalink / raw)
  To: Heinrich Schuchardt, u-boot

Hi Heinrich,

On 08/07/2022 21:33, Heinrich Schuchardt wrote:
> Hello Paul,
> 
> up to now U-Boot does not implement any part of the PI specification. Please, explain why we should implement this protocol.

Implementing this protocol allows a UEFI application to interact with a 
device on the SPI bus. Similar protocols exist in the main UEFI 
specification for passing commands to an NVMe or SD/eMMC device. The 
code here is self-contained and easy to enable/disable at compile time.

Our goal in adding support for this protocol is to allow our UEFI 
application to interact with the Micron Authenta flash device on the 
SanCloud BBE Lite board and other future platforms. The application will 
link against mbedtls to provide cryptographic functions so isolating our 
application code in this way helps to keep the u-boot code size small.

> For all EFI protocols there should be a test that can be run in our Gitlab CI showing that it is working correctly.

I'm intending to add test cases based on the mock/sandbox SPI driver 
before this is submitted as a final/non-RFC patch series. I'd like to 
get some feedback on the overall approach at this stage as that will 
influence how the tests interact with the implementation.

Thanks,

-- 
Paul Barker
Principal Software Engineer
SanCloud Ltd

e: paul.barker@sancloud.com
w: https://sancloud.com/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [RFC PATCH 1/2] efi_loader: Add SPI I/O protocol support
  2022-07-08  9:45 ` [RFC PATCH 1/2] efi_loader: Add SPI I/O protocol support Paul Barker
  2022-07-08 20:21   ` Tom Rini
@ 2022-07-11 13:12   ` Ilias Apalodimas
  2022-07-11 13:25     ` Paul Barker
  1 sibling, 1 reply; 8+ messages in thread
From: Ilias Apalodimas @ 2022-07-11 13:12 UTC (permalink / raw)
  To: Paul Barker; +Cc: u-boot, Heinrich Schuchardt

Hi Paul

On Fri, 8 Jul 2022 at 12:46, Paul Barker <paul.barker@sancloud.com> wrote:
>
> This addition allows UEFI applications running under u-boot to access
> peripherals on SPI busses. It is based on the UEFI Platform
> Initialization (PI) Specification, Version 1.7 Errata A (April 2020).
> Only the core functionality required to discover SPI peripherals and
> communicate with them is currently implemented. Other functionality such
> as the legacy SPI controller interface and the ability to update the SPI
> peripheral object associated with a particular SPI I/O protocol object
> is currently unimplemented.
>
> Since there are no open source implementations of this protocol to use
> as an example, educated guesses/hacks have been made in cases where the
> UEFI PI specification is unclear and these are documented in comments.
>
> This implementation has been tested on the SanCloud BBE Lite and allowed
> a UEFI test application to successfully communicate with a Micron
> Authenta flash device connected via the SPI bus.
>
> Signed-off-by: Paul Barker <paul.barker@sancloud.com>
> ---
>  MAINTAINERS                       |   6 +
>  include/efi_loader.h              |   4 +
>  include/efi_spi_protocol.h        | 158 +++++++++
>  lib/efi_loader/Kconfig            |   8 +
>  lib/efi_loader/Makefile           |   1 +
>  lib/efi_loader/efi_setup.c        |   6 +
>  lib/efi_loader/efi_spi_protocol.c | 565 ++++++++++++++++++++++++++++++
>  7 files changed, 748 insertions(+)
>  create mode 100644 include/efi_spi_protocol.h
>  create mode 100644 lib/efi_loader/efi_spi_protocol.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 7f27ff4c20fc..4f5a735567a4 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -831,6 +831,12 @@ F: tools/efivar.py
>  F:     tools/file2include.c
>  F:     tools/mkeficapsule.c
>
> +EFI SPI SUPPORT
> +M:     Paul Barker <paul.barker@sancloud.com>
> +S:     Maintained
> +F:     include/efi_spi_protocol.h
> +F:     lib/efi_loader/efi_spi_protocol.c
> +
>  EFI VARIABLES VIA OP-TEE
>  M:     Ilias Apalodimas <ilias.apalodimas@linaro.org>
>  S:     Maintained
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index c1e00ebac398..8fd867a78db2 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -537,6 +537,10 @@ efi_status_t efi_rng_register(void);
>  efi_status_t efi_tcg2_register(void);
>  /* Called by efi_init_obj_list() to install RISCV_EFI_BOOT_PROTOCOL */
>  efi_status_t efi_riscv_register(void);
> +/* Called by efi_init_obj_list() to install EFI_SPI_CONFIGURATION_PROTOCOL &
> + * EFI_SPI_IO_PROTOCOL
> + */
> +efi_status_t efi_spi_protocol_register(void);
>  /* Called by efi_init_obj_list() to do initial measurement */
>  efi_status_t efi_tcg2_do_initial_measurement(void);
>  /* measure the pe-coff image, extend PCR and add Event Log */
> diff --git a/include/efi_spi_protocol.h b/include/efi_spi_protocol.h
> new file mode 100644
> index 000000000000..1a4456bd9349
> --- /dev/null
> +++ b/include/efi_spi_protocol.h
> @@ -0,0 +1,158 @@
> +/* SPDX-License-Identifier: BSD-2-Clause-Patent */
> +/*
> + * Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> + */
> +
> +#ifndef _EFI_SPI_PROTOCOL_H
> +#define _EFI_SPI_PROTOCOL_H
> +
> +#include <efi.h>
> +#include <efi_api.h>
> +
> +#define EFI_SPI_CONFIGURATION_GUID  \
> +       EFI_GUID(0x85a6d3e6, 0xb65b, 0x4afc,     \
> +                0xb3, 0x8f, 0xc6, 0xd5, 0x4a, 0xf6, 0xdd, 0xc8)
> +
> +struct efi_spi_peripheral;
> +
> +struct efi_spi_part {
> +       efi_string_t vendor;
> +       efi_string_t part_number;
> +       u32 min_clock_hz;
> +       u32 max_clock_hz;
> +       bool chip_select_polarity;
> +};
> +
> +struct efi_spi_bus {
> +       efi_string_t friendly_name;
> +       struct efi_spi_peripheral *peripheral_list;
> +       struct efi_device_path *controller_path;
> +
> +       efi_status_t
> +       (EFIAPI * clock)(const struct efi_spi_peripheral *spi_peripheral,
> +               u32 *clock_hz);
> +
> +       void *clock_parameter;
> +};
> +
> +struct efi_spi_peripheral {
> +       struct efi_spi_peripheral *next_spi_peripheral;
> +       efi_string_t friendly_name;
> +       efi_guid_t *spi_peripheral_driver_guid;
> +       struct efi_spi_part *spi_part;
> +       u32 max_clock_hz;
> +       bool clock_polarity;
> +       bool clock_phase;
> +       u32 attributes;
> +       void *configuration_data;
> +       struct efi_spi_bus *spi_bus;
> +
> +       efi_status_t
> +       (EFIAPI * chip_select)(const struct efi_spi_peripheral *spi_peripheral,
> +               bool pin_value);
> +
> +       void *chip_select_parameter;
> +};
> +
> +struct efi_spi_configuration_protocol {
> +       u32 bus_count;
> +       struct efi_spi_bus **bus_list;
> +};
> +
> +#define EFI_LEGACY_SPI_CONTROLLER_GUID  \
> +       EFI_GUID(0x39136fc7, 0x1a11, 0x49de,         \
> +                0xbf, 0x35, 0x0e, 0x78, 0xdd, 0xb5, 0x24, 0xfc)
> +
> +struct efi_legacy_spi_controller_protocol;
> +
> +struct efi_legacy_spi_controller_protocol {
> +       u32 maximum_offset;
> +       u32 maximum_range_bytes;
> +       u32 range_register_count;
> +
> +       efi_status_t
> +       (EFIAPI * erase_block_opcode)(const struct efi_legacy_spi_controller_protocol *this,
> +               u8 erase_block_opcode);
> +
> +       efi_status_t
> +       (EFIAPI * write_status_prefix)(const struct efi_legacy_spi_controller_protocol *this,
> +               u8 write_status_prefix);
> +
> +       efi_status_t
> +       (EFIAPI * bios_base_address)(const struct efi_legacy_spi_controller_protocol *this,
> +               u32 bios_base_address);
> +
> +       efi_status_t
> +       (EFIAPI * clear_spi_protect)(const struct efi_legacy_spi_controller_protocol *this);
> +
> +       bool
> +       (EFIAPI * is_range_protected)(const struct efi_legacy_spi_controller_protocol *this,
> +               u32 bios_address,
> +               u32 blocks_to_protect);
> +
> +       efi_status_t
> +       (EFIAPI * protect_next_range)(const struct efi_legacy_spi_controller_protocol *this,
> +               u32 bios_address,
> +               u32 blocks_to_protect);
> +
> +       efi_status_t
> +       (EFIAPI * lock_controller)(const struct efi_legacy_spi_controller_protocol *this);
> +};
> +
> +struct efi_spi_io_protocol;
> +
> +enum efi_spi_transaction_type {
> +       SPI_TRANSACTION_FULL_DUPLEX,
> +       SPI_TRANSACTION_WRITE_ONLY,
> +       SPI_TRANSACTION_READ_ONLY,
> +       SPI_TRANSACTION_WRITE_THEN_READ
> +};
> +
> +struct efi_spi_bus_transaction {
> +       struct efi_spi_peripheral *spi_peripheral;
> +       enum efi_spi_transaction_type transaction_type;
> +       bool debug_transaction;
> +       u32 bus_width;
> +       u32 frame_size;
> +       u32 write_bytes;
> +       u8 *write_buffer;
> +       u32 read_bytes;
> +       u8 *read_buffer;
> +};
> +
> +struct efi_spi_io_protocol {
> +       struct efi_spi_peripheral *spi_peripheral;
> +       struct efi_spi_peripheral *original_spi_peripheral;
> +       u32 frame_size_support_mask;
> +       u32 maximum_transfer_bytes;
> +       u32 attributes;
> +       struct efi_legacy_spi_controller_protocol *legacy_spi_protocol;
> +
> +       efi_status_t
> +       (EFIAPI * transaction)(const struct efi_spi_io_protocol *this,
> +               enum efi_spi_transaction_type transaction_type,
> +               bool debug_transaction,
> +               u32 clock_hz,
> +               u32 bus_width,
> +               u32 frame_size,
> +               u32 write_bytes,
> +               u8 *write_buffer,
> +               u32 read_bytes,
> +               u8 *read_buffer);
> +
> +       efi_status_t
> +       (EFIAPI * update_spi_peripheral)(struct efi_spi_io_protocol *this,
> +               struct efi_spi_peripheral *spi_peripheral);
> +};
> +
> +struct efi_spi_peripheral_priv {
> +       struct efi_spi_peripheral peripheral;
> +       struct efi_spi_part part;
> +       struct efi_spi_io_protocol io_protocol;
> +       efi_handle_t handle;
> +       struct spi_slave *target;
> +};
> +
> +efi_status_t efi_spi_protocol_register(void);
> +
> +#endif
> diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
> index e2a1a5a69a24..621768c07201 100644
> --- a/lib/efi_loader/Kconfig
> +++ b/lib/efi_loader/Kconfig
> @@ -393,4 +393,12 @@ config EFI_RISCV_BOOT_PROTOCOL
>           replace the transfer via the device-tree. The latter is not
>           possible on systems using ACPI.
>
> +config EFI_SPI_PROTOCOL
> +       bool "EFI SPI protocol support"
> +       default y
> +       help
> +         Provide implementations of EFI_SPI_CONFIGURATION_PROTOCOL and
> +         EFI_SPI_IO_PROTOCOL to allow UEFI applications to access devices
> +         connected via SPI bus.
> +
>  endif
> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
> index aaaa25cefe01..47f4e51d2a2b 100644
> --- a/lib/efi_loader/Makefile
> +++ b/lib/efi_loader/Makefile
> @@ -75,6 +75,7 @@ obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o
>  obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o
>  obj-$(CONFIG_EFI_TCG2_PROTOCOL) += efi_tcg2.o
>  obj-$(CONFIG_EFI_RISCV_BOOT_PROTOCOL) += efi_riscv.o
> +obj-$(CONFIG_EFI_SPI_PROTOCOL) += efi_spi_protocol.o
>  obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_load_initrd.o
>  obj-$(CONFIG_EFI_SIGNATURE_SUPPORT) += efi_signature.o
>
> diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
> index 492ecf4cb15c..ef1ee9862b72 100644
> --- a/lib/efi_loader/efi_setup.c
> +++ b/lib/efi_loader/efi_setup.c
> @@ -295,6 +295,12 @@ efi_status_t efi_init_obj_list(void)
>                         goto out;
>         }
>
> +       if (IS_ENABLED(CONFIG_EFI_SPI_PROTOCOL)) {
> +               ret = efi_spi_protocol_register();
> +               if (ret != EFI_SUCCESS)
> +                       goto out;
> +       }
> +
>         /* Secure boot */
>         ret = efi_init_secure_boot();
>         if (ret != EFI_SUCCESS)
> diff --git a/lib/efi_loader/efi_spi_protocol.c b/lib/efi_loader/efi_spi_protocol.c
> new file mode 100644
> index 000000000000..495704c25baa
> --- /dev/null
> +++ b/lib/efi_loader/efi_spi_protocol.c
> @@ -0,0 +1,565 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2022 Micron Technology, Inc.
> + */
> +
> +#define LOG_CATEGORY LOGC_EFI
> +
> +#include <common.h>
> +#include <dm/device.h>
> +#include <dm/read.h>
> +#include <efi.h>
> +#include <efi_loader.h>
> +#include <efi_spi_protocol.h>
> +#include <malloc.h>
> +#include <spi.h>
> +
> +static efi_string_t convert_efi_string(const char *str)
> +{
> +       efi_string_t str_16, tmp;
> +       size_t sz_8, sz_16;
> +
> +       sz_8 = strlen(str);
> +       sz_16 = utf8_utf16_strlen(str);
> +       str_16 = calloc(sz_16 + 1, 2);
> +       if (!str_16)
> +               return NULL;
> +
> +       tmp = str_16;
> +       utf8_utf16_strcpy(&tmp, str);
> +
> +       return str_16;
> +}
> +
> +static efi_status_t
> +efi_spi_bus_clock(const struct efi_spi_peripheral *spi_peripheral,
> +                 u32 *clock_hz)
> +{
> +       EFI_ENTRY("%p, %p", spi_peripheral, clock_hz);
> +       return EFI_EXIT(EFI_UNSUPPORTED);
> +}
> +

All the EFI_ENTRY/EXIT calls should be on functions marked as EFIAPI.
Most of the functions you use it on seem to be static function that
will never be called by an EFI application.

Regards
/Ilias

> +static efi_status_t
> +efi_spi_peripheral_chip_select(const struct efi_spi_peripheral *spi_peripheral,
> +                              bool pin_value)
> +{
> +       EFI_ENTRY("%p, %d", spi_peripheral, pin_value);
> +       return EFI_EXIT(EFI_UNSUPPORTED);
> +}
> +
> +static efi_status_t
> +legacy_erase_block_opcode(const struct efi_legacy_spi_controller_protocol *this,
> +                         u8 erase_block_opcode)
> +{
> +       EFI_ENTRY("%p, %u", this, erase_block_opcode);
> +       return EFI_EXIT(EFI_UNSUPPORTED);
> +}
> +
> +static efi_status_t
> +legacy_write_status_prefix(const struct efi_legacy_spi_controller_protocol *this,
> +                          u8 write_status_prefix)
> +{
> +       EFI_ENTRY("%p, %u", this, write_status_prefix);
> +       return EFI_EXIT(EFI_UNSUPPORTED);
> +}
> +
> +static efi_status_t
> +legacy_bios_base_address(const struct efi_legacy_spi_controller_protocol *this,
> +                        u32 bios_base_address)
> +{
> +       EFI_ENTRY("%p, %u", this, bios_base_address);
> +       return EFI_EXIT(EFI_UNSUPPORTED);
> +}
> +
> +static efi_status_t
> +legacy_clear_spi_protect(const struct efi_legacy_spi_controller_protocol *this)
> +{
> +       EFI_ENTRY("%p", this);
> +       return EFI_EXIT(EFI_UNSUPPORTED);
> +}
> +
> +static bool
> +legacy_is_range_protected(const struct efi_legacy_spi_controller_protocol *this,
> +                         u32 bios_address,
> +                         u32 blocks_to_protect)
> +{
> +       EFI_ENTRY("%p, %u, %u", this, bios_address, blocks_to_protect);
> +       return EFI_EXIT(false);
> +}
> +
> +static efi_status_t
> +legacy_protect_next_range(const struct efi_legacy_spi_controller_protocol *this,
> +                         u32 bios_address,
> +                         u32 blocks_to_protect)
> +{
> +       EFI_ENTRY("%p, %u, %u", this, bios_address, blocks_to_protect);
> +       return EFI_EXIT(EFI_UNSUPPORTED);
> +}
> +
> +static efi_status_t
> +legacy_lock_controller(const struct efi_legacy_spi_controller_protocol *this)
> +{
> +       EFI_ENTRY("%p", this);
> +       return EFI_EXIT(EFI_UNSUPPORTED);
> +}
> +
> +static efi_status_t
> +efi_spi_io_update_spi_peripheral(struct efi_spi_io_protocol *this,
> +                                struct efi_spi_peripheral *spi_peripheral)
> +{
> +       EFI_ENTRY("%p, %p", this, spi_peripheral);
> +       return EFI_EXIT(EFI_UNSUPPORTED);
> +}
> +
> +static efi_status_t
> +efi_spi_io_transaction(const struct efi_spi_io_protocol *this,
> +                      enum efi_spi_transaction_type transaction_type,
> +                      bool debug_transaction,
> +                      u32 clock_hz,
> +                      u32 bus_width,
> +                      u32 frame_size,
> +                      u32 write_bytes,
> +                      u8 *write_buffer,
> +                      u32 read_bytes,
> +                      u8 *read_buffer)
> +{
> +       struct spi_slave *target;
> +       efi_status_t status = EFI_SUCCESS;
> +       int r;
> +
> +       /* We ignore the bus_width and frame_size arguments to this function as the
> +        * appropriate bus configuration for the connected device will be performed
> +        * during spi_claim_bus().
> +        */
> +
> +       /* TODO: Print transaction details if debug_transaction is true. */
> +
> +       EFI_ENTRY("%p, %u, %u, %u, %u, %u, %u, %p, %u, %p",
> +                 this, transaction_type, debug_transaction,
> +                 clock_hz, bus_width frame_size,
> +                 write_bytes, write_buffer, read_bytes, read_buffer);
> +
> +       if (!this)
> +               return EFI_EXIT(EFI_INVALID_PARAMETER);
> +
> +       target = container_of(this, struct efi_spi_peripheral_priv, io_protocol)->target;
> +
> +       if (clock_hz > this->spi_peripheral->max_clock_hz)
> +               return EFI_EXIT(EFI_UNSUPPORTED);
> +
> +       r = spi_claim_bus(target);
> +       if (r != 0)
> +               return EFI_EXIT(EFI_DEVICE_ERROR);
> +       EFI_PRINT("SPI IO: Bus claimed\n");
> +
> +       if (clock_hz) {
> +               EFI_PRINT("SPI IO: Setting clock rate to %u Hz\n", clock_hz);
> +               spi_get_ops(target->dev->parent)->set_speed(target->dev->parent, clock_hz);
> +       } else {
> +               EFI_PRINT("SPI IO: Using default clock rate\n");
> +       }
> +
> +       switch (transaction_type) {
> +       case SPI_TRANSACTION_FULL_DUPLEX:
> +               EFI_PRINT("SPI IO: Full-duplex\n");
> +               if (write_bytes != read_bytes || !write_bytes || !write_buffer || !read_buffer) {
> +                       status = EFI_INVALID_PARAMETER;
> +                       break;
> +               }
> +               r = spi_xfer(target, 8 * write_bytes,
> +                            write_buffer, read_buffer, SPI_XFER_ONCE);
> +               EFI_PRINT("SPI IO: xfer returned %d\n", r);
> +               status = (r == 0) ? EFI_SUCCESS : EFI_DEVICE_ERROR;
> +               break;
> +       case SPI_TRANSACTION_READ_ONLY:
> +               EFI_PRINT("SPI IO: Read-only\n");
> +               if (!read_bytes || !read_buffer) {
> +                       status = EFI_INVALID_PARAMETER;
> +                       break;
> +               }
> +               r = spi_xfer(target, 8 * read_bytes,
> +                            NULL, read_buffer, SPI_XFER_ONCE);
> +               EFI_PRINT("SPI IO: xfer returned %d\n", r);
> +               status = (r == 0) ? EFI_SUCCESS : EFI_DEVICE_ERROR;
> +               break;
> +       case SPI_TRANSACTION_WRITE_ONLY:
> +               EFI_PRINT("SPI IO: Write-only\n");
> +               if (!write_bytes || !write_buffer) {
> +                       status = EFI_INVALID_PARAMETER;
> +                       break;
> +               }
> +               r = spi_xfer(target, 8 * write_bytes,
> +                            write_buffer, NULL, SPI_XFER_ONCE);
> +               EFI_PRINT("SPI IO: xfer returned %d\n", r);
> +               status = (r == 0) ? EFI_SUCCESS : EFI_DEVICE_ERROR;
> +               break;
> +       case SPI_TRANSACTION_WRITE_THEN_READ:
> +               EFI_PRINT("SPI IO: Write-then-read\n");
> +               if (!write_bytes || !write_buffer || !read_bytes || !read_buffer) {
> +                       status = EFI_INVALID_PARAMETER;
> +                       break;
> +               }
> +               r = spi_xfer(target, 8 * write_bytes,
> +                            write_buffer, NULL, SPI_XFER_BEGIN);
> +               EFI_PRINT("SPI IO: xfer [1/2] returned %d\n", r);
> +               if (r != 0) {
> +                       status = EFI_DEVICE_ERROR;
> +                       break;
> +               }
> +               r = spi_xfer(target, 8 * read_bytes,
> +                            NULL, read_buffer, SPI_XFER_END);
> +               EFI_PRINT("SPI IO: xfer [2/2] returned %d\n", r);
> +               status = (r == 0) ? EFI_SUCCESS : EFI_DEVICE_ERROR;
> +               break;
> +       default:
> +               status = EFI_INVALID_PARAMETER;
> +               break;
> +       }
> +
> +       spi_release_bus(target);
> +       EFI_PRINT("SPI IO: Released bus\n");
> +       return EFI_EXIT(status);
> +}
> +
> +static struct efi_device_path null_device_path = {
> +       .type     = DEVICE_PATH_TYPE_END,
> +       .sub_type = DEVICE_PATH_SUB_TYPE_END,
> +       .length   = 4
> +};
> +
> +static struct efi_legacy_spi_controller_protocol
> +dummy_legacy_spi_controller_protocol = {
> +       .maximum_offset = 0,
> +       .maximum_range_bytes = 0,
> +       .range_register_count = 0,
> +       .erase_block_opcode = legacy_erase_block_opcode,
> +       .write_status_prefix = legacy_write_status_prefix,
> +       .bios_base_address = legacy_bios_base_address,
> +       .clear_spi_protect = legacy_clear_spi_protect,
> +       .is_range_protected = legacy_is_range_protected,
> +       .protect_next_range = legacy_protect_next_range,
> +       .lock_controller = legacy_lock_controller
> +};
> +
> +static efi_guid_t efi_spi_configuration_guid = EFI_SPI_CONFIGURATION_GUID;
> +
> +static void destroy_efi_spi_peripheral(struct efi_spi_peripheral *peripheral)
> +{
> +       struct efi_spi_peripheral_priv *priv =
> +               container_of(peripheral,
> +                            struct efi_spi_peripheral_priv,
> +                            peripheral);
> +       free(priv->peripheral.friendly_name);
> +       free(priv->part.vendor);
> +       free(priv->part.part_number);
> +       efi_delete_handle(priv->handle);
> +       free(priv);
> +}
> +
> +static void destroy_efi_spi_bus(struct efi_spi_bus *bus)
> +{
> +       struct efi_spi_peripheral *peripheral = bus->peripheral_list;
> +
> +       while (peripheral) {
> +               struct efi_spi_peripheral *next =
> +                       peripheral->next_spi_peripheral;
> +               destroy_efi_spi_peripheral(peripheral);
> +               peripheral = next;
> +       }
> +       free(bus->friendly_name);
> +       free(bus);
> +}
> +
> +static efi_status_t efi_spi_new_handle(const efi_guid_t *guid, void *proto)
> +{
> +       efi_status_t status;
> +       efi_handle_t handle;
> +
> +       status = efi_create_handle(&handle);
> +       if (status != EFI_SUCCESS) {
> +               printf("Failed to create EFI handle\n");
> +               goto fail_1;
> +       }
> +
> +       status = efi_add_protocol(handle, guid, proto);
> +       if (status != EFI_SUCCESS) {
> +               printf("Failed to add protocol\n");
> +               goto fail_2;
> +       }
> +
> +       return EFI_SUCCESS;
> +
> +fail_2:
> +       efi_delete_handle(handle);
> +fail_1:
> +       return status;
> +}
> +
> +static void
> +efi_spi_init_part(struct efi_spi_part *part,
> +                 struct spi_slave *target,
> +                 efi_string_t vendor_utf16,
> +                 efi_string_t part_number_utf16
> +)
> +{
> +       part->vendor = vendor_utf16;
> +       part->part_number = part_number_utf16;
> +       part->min_clock_hz = 0;
> +       part->max_clock_hz = target->max_hz;
> +       part->chip_select_polarity =
> +               (target->mode & SPI_CS_HIGH) ? true : false;
> +}
> +
> +static void
> +efi_spi_init_peripheral(struct efi_spi_peripheral *peripheral,
> +                       struct efi_spi_part *part,
> +                       struct efi_spi_bus *bus,
> +                       struct spi_slave *target,
> +                       efi_guid_t *guid,
> +                       efi_string_t name_utf16
> +)
> +{
> +       peripheral->friendly_name = name_utf16;
> +       peripheral->spi_part = part;
> +       peripheral->next_spi_peripheral = NULL;
> +       peripheral->spi_peripheral_driver_guid = guid;
> +       peripheral->max_clock_hz = target->max_hz;
> +       peripheral->clock_polarity = (target->mode & SPI_CPOL) ? true : false;
> +       peripheral->clock_phase = (target->mode & SPI_CPHA) ? true : false;
> +       peripheral->attributes = 0;
> +       peripheral->configuration_data = NULL;
> +       peripheral->spi_bus = bus;
> +       peripheral->chip_select = efi_spi_peripheral_chip_select;
> +       peripheral->chip_select_parameter = NULL;
> +}
> +
> +static void
> +efi_spi_append_peripheral(struct efi_spi_peripheral *peripheral,
> +                         struct efi_spi_bus *bus
> +)
> +{
> +       if (bus->peripheral_list) {
> +               struct efi_spi_peripheral *tmp = bus->peripheral_list;
> +
> +               while (tmp->next_spi_peripheral)
> +                       tmp = tmp->next_spi_peripheral;
> +
> +               tmp->next_spi_peripheral = peripheral;
> +       } else {
> +               bus->peripheral_list = peripheral;
> +       }
> +}
> +
> +static void
> +efi_spi_init_io_protocol(struct efi_spi_io_protocol *io_protocol,
> +                        struct efi_spi_peripheral *peripheral,
> +                        struct spi_slave *target
> +)
> +{
> +       io_protocol->spi_peripheral = peripheral;
> +       io_protocol->original_spi_peripheral = peripheral;
> +       io_protocol->legacy_spi_protocol = &dummy_legacy_spi_controller_protocol;
> +       io_protocol->transaction = efi_spi_io_transaction;
> +       io_protocol->update_spi_peripheral = efi_spi_io_update_spi_peripheral;
> +
> +       /* This is a bit of a hack. The EFI data structures do not allow us to
> +        * represent a frame size greater than 32 bits.
> +        */
> +       if (target->wordlen <= 32)
> +               io_protocol->frame_size_support_mask =
> +                       1 << (target->wordlen - 1);
> +       else
> +               io_protocol->frame_size_support_mask = 0;
> +
> +       /* Again, this is a bit of a hack. The EFI data structures only allow
> +        * for a single maximum transfer size whereas the u-boot spi_slave
> +        * structure records maximum read transfer size and maximum write
> +        * transfer size separately. So we need to take the minimum of these two
> +        * values.
> +        */
> +       if (target->max_read_size > target->max_write_size)
> +               io_protocol->maximum_transfer_bytes = target->max_write_size;
> +       else
> +               io_protocol->maximum_transfer_bytes = target->max_read_size;
> +
> +       /* Hack++. Leave attributes set to zero since the flags listed in the
> +        * UEFI PI spec have no defined numerical values and so cannot be used.
> +        */
> +       io_protocol->attributes = 0;
> +}
> +
> +static efi_status_t
> +export_spi_peripheral(struct efi_spi_bus *bus, struct udevice *dev)
> +{
> +       efi_string_t name_utf16, vendor_utf16, part_number_utf16;
> +       struct efi_spi_peripheral_priv *priv;
> +       efi_status_t status;
> +       struct udevice *dev_bus = dev->parent;
> +       struct spi_slave *target = dev_get_parent_priv(dev);
> +       const char *name = dev_read_name(dev);
> +       const char *vendor = dev_read_string(dev, "uefi-spi-vendor");
> +       const char *part_number = dev_read_string(dev, "uefi-spi-part-number");
> +       efi_guid_t *guid =
> +               (efi_guid_t *)dev_read_u8_array_ptr(dev, "uefi-spi-io-guid", 16);
> +
> +       if (!vendor || !part_number || !guid) {
> +               printf("Skipping SPI peripheral %s\n", name);
> +               status = EFI_UNSUPPORTED;
> +               goto fail_1;
> +       }
> +
> +       printf("Registering SPI dev %d:%d, name %s\n",
> +              dev_bus->seq_, spi_chip_select(dev), name);
> +
> +       priv = calloc(1, sizeof(*priv));
> +       if (!priv) {
> +               status = EFI_OUT_OF_RESOURCES;
> +               goto fail_1;
> +       }
> +
> +       vendor_utf16 = convert_efi_string(vendor);
> +       if (!vendor_utf16) {
> +               status = EFI_OUT_OF_RESOURCES;
> +               goto fail_2;
> +       }
> +
> +       part_number_utf16 = convert_efi_string(part_number);
> +       if (!part_number_utf16) {
> +               status = EFI_OUT_OF_RESOURCES;
> +               goto fail_3;
> +       }
> +
> +       name_utf16 = convert_efi_string(name);
> +       if (!name_utf16) {
> +               status = EFI_OUT_OF_RESOURCES;
> +               goto fail_4;
> +       }
> +
> +       priv->target = target;
> +
> +       efi_spi_init_part(&priv->part, target, vendor_utf16, part_number_utf16);
> +
> +       efi_spi_init_peripheral(&priv->peripheral, &priv->part,
> +                               bus, target, guid, name_utf16);
> +
> +       efi_spi_append_peripheral(&priv->peripheral, bus);
> +
> +       efi_spi_init_io_protocol(&priv->io_protocol, &priv->peripheral, target);
> +
> +       status = efi_spi_new_handle(guid, &priv->io_protocol);
> +       if (status != EFI_SUCCESS)
> +               goto fail_5;
> +
> +       printf("Added EFI_SPI_IO_PROTOCOL with guid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
> +              guid->b[0], guid->b[1], guid->b[2], guid->b[3],
> +              guid->b[4], guid->b[5], guid->b[6], guid->b[7],
> +              guid->b[8], guid->b[9], guid->b[10], guid->b[11],
> +              guid->b[12], guid->b[13], guid->b[14], guid->b[15]);
> +       return EFI_SUCCESS;
> +
> +fail_5:
> +       free(name_utf16);
> +fail_4:
> +       free(part_number_utf16);
> +fail_3:
> +       free(vendor_utf16);
> +fail_2:
> +       free(priv);
> +fail_1:
> +       return status;
> +}
> +
> +static struct efi_spi_bus *export_spi_bus(int i)
> +{
> +       struct efi_spi_bus *bus;
> +       struct udevice *dev, *child;
> +       const char *name;
> +       int r;
> +
> +       r = uclass_get_device(UCLASS_SPI, i, &dev);
> +       if (r < 0) {
> +               printf("Failed to get SPI bus %d\n", i);
> +               goto fail_1;
> +       }
> +
> +       name = dev_read_name(dev);
> +       printf("Registering SPI bus %d, name %s\n", i, name);
> +
> +       bus = calloc(1, sizeof(*bus));
> +       if (!bus)
> +               goto fail_1;
> +
> +       bus->friendly_name = convert_efi_string(name);
> +       if (!bus->friendly_name)
> +               goto fail_2;
> +
> +       bus->peripheral_list = NULL;
> +       bus->clock = efi_spi_bus_clock;
> +       bus->clock_parameter = NULL;
> +
> +       /* For the purposes of the current implementation, we do not need to expose
> +        * the hardware device path to users of the SPI I/O protocol.
> +        */
> +       bus->controller_path = &null_device_path;
> +
> +       device_foreach_child(child, dev) {
> +               efi_status_t status = export_spi_peripheral(bus, child);
> +
> +               if (status == EFI_OUT_OF_RESOURCES)
> +                       goto fail_3;
> +       }
> +
> +       return bus;
> +
> +fail_3:
> +       destroy_efi_spi_bus(bus);
> +fail_2:
> +       free(bus);
> +fail_1:
> +       return NULL;
> +}
> +
> +efi_status_t efi_spi_protocol_register(void)
> +{
> +       efi_status_t status;
> +       struct efi_spi_configuration_protocol *proto;
> +       uint i;
> +
> +       printf("Registering EFI_SPI_CONFIGURATION_PROTOCOL\n");
> +
> +       proto = calloc(1, sizeof(*proto));
> +       if (!proto) {
> +               status = EFI_OUT_OF_RESOURCES;
> +               goto fail_1;
> +       }
> +
> +       proto->bus_count = uclass_id_count(UCLASS_SPI);
> +       proto->bus_list = calloc(proto->bus_count, sizeof(*proto->bus_list));
> +       if (!proto->bus_list) {
> +               status = EFI_OUT_OF_RESOURCES;
> +               goto fail_2;
> +       }
> +
> +       for (i = 0; i < proto->bus_count; i++) {
> +               proto->bus_list[i] = export_spi_bus(i);
> +               if (!proto->bus_list[i])
> +                       goto fail_3;
> +       }
> +
> +       status = efi_spi_new_handle(&efi_spi_configuration_guid, proto);
> +       if (status != EFI_SUCCESS)
> +               goto fail_3;
> +
> +       return EFI_SUCCESS;
> +
> +fail_3:
> +       for (i = 0; i < proto->bus_count; i++) {
> +               if (proto->bus_list[i])
> +                       destroy_efi_spi_bus(proto->bus_list[i]);
> +       }
> +       free(proto->bus_list);
> +fail_2:
> +       free(proto);
> +fail_1:
> +       return status;
> +}
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [RFC PATCH 1/2] efi_loader: Add SPI I/O protocol support
  2022-07-11 13:12   ` Ilias Apalodimas
@ 2022-07-11 13:25     ` Paul Barker
  0 siblings, 0 replies; 8+ messages in thread
From: Paul Barker @ 2022-07-11 13:25 UTC (permalink / raw)
  To: Ilias Apalodimas; +Cc: u-boot, Heinrich Schuchardt


[-- Attachment #1.1.1: Type: text/plain, Size: 823 bytes --]

On 11/07/2022 14:12, Ilias Apalodimas wrote:
> Hi Paul
> 
>> +static efi_status_t
>> +efi_spi_bus_clock(const struct efi_spi_peripheral *spi_peripheral,
>> +                 u32 *clock_hz)
>> +{
>> +       EFI_ENTRY("%p, %p", spi_peripheral, clock_hz);
>> +       return EFI_EXIT(EFI_UNSUPPORTED);
>> +}
>> +
> 
> All the EFI_ENTRY/EXIT calls should be on functions marked as EFIAPI.
> Most of the functions you use it on seem to be static function that
> will never be called by an EFI application.

These functions are actually exported as part of EFI protocols and so 
can be called by an EFI application. So I should mark them as EFIAPI 
when I send v2 of this series.

Thanks,

-- 
Paul Barker
Principal Software Engineer
SanCloud Ltd

e: paul.barker@sancloud.com
w: https://sancloud.com/

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 7645 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2022-07-11 13:25 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-08  9:45 [RFC PATCH 0/2] Support UEFI SPI I/O protocol Paul Barker
2022-07-08  9:45 ` [RFC PATCH 1/2] efi_loader: Add SPI I/O protocol support Paul Barker
2022-07-08 20:21   ` Tom Rini
2022-07-11 13:12   ` Ilias Apalodimas
2022-07-11 13:25     ` Paul Barker
2022-07-08  9:45 ` [RFC PATCH 2/2] arm: dts: am335x-sancloud-bbe-lite: UEFI SPI export Paul Barker
2022-07-08 20:33 ` [RFC PATCH 0/2] Support UEFI SPI I/O protocol Heinrich Schuchardt
2022-07-09 10:35   ` Paul Barker

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).