Read the VendorDtbOverlays EFI variable when the vendor_dtbo environment
variable is unavailable. Use the EFI-provided overlay identifiers during
FIT multi-DTB configuration matching.

Move QCOM FIT multi-DTB selection to EVT_POST_PREBOOT so EFI variables
can be initialized successfully before they are read.

Signed-off-by: Sumit Singh Dhami <[email protected]>
---
This patch extends the FIT multi-DTB support introduced by Aswin Murugan's
series: 
https://lore.kernel.org/u-boot/[email protected]/
---
 arch/arm/mach-snapdragon/board.c             |   6 -
 arch/arm/mach-snapdragon/qcom_fit_multidtb.c | 175 +++++++++++++++++--
 arch/arm/mach-snapdragon/qcom_fit_multidtb.h |  18 --
 3 files changed, 161 insertions(+), 38 deletions(-)

diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c
index 9bfb7183241..055ef6b8221 100644
--- a/arch/arm/mach-snapdragon/board.c
+++ b/arch/arm/mach-snapdragon/board.c
@@ -453,11 +453,5 @@ int board_late_init(void)
        /* Configure the dfu_string for capsule updates */
        qcom_configure_capsule_updates();
 
-       /* Try FIT multi-DTB selection if enabled */
-       if (IS_ENABLED(CONFIG_QCOM_FIT_MULTIDTB)) {
-               if (qcom_fit_multidtb_setup())
-                       log_debug("FIT multi-DTB selection not available or 
failed\n");
-       }
-
        return 0;
 }
diff --git a/arch/arm/mach-snapdragon/qcom_fit_multidtb.c 
b/arch/arm/mach-snapdragon/qcom_fit_multidtb.c
index 45423910d34..40f660b453b 100644
--- a/arch/arm/mach-snapdragon/qcom_fit_multidtb.c
+++ b/arch/arm/mach-snapdragon/qcom_fit_multidtb.c
@@ -27,6 +27,11 @@
 #include "qcom_fit_multidtb.h"
 #include "qcom_hwdetect.h"
 
+#if CONFIG_IS_ENABLED(EFI_VARIABLE_FILE_STORE)
+#include <efi_loader.h>
+#include <efi_variable.h>
+#endif
+
 /* GPT partition name containing the FIT image */
 #define QCOM_FIT_PARTNAME      "dtb_a"
 
@@ -60,6 +65,10 @@
 #define PROP_FDT               "fdt"
 #define PROP_DATA              "data"
 
+#if CONFIG_IS_ENABLED(EFI_VARIABLE_FILE_STORE)
+#define QCOM_VENDOR_DTBO_EFIVAR_MAX_LEN        256
+#endif
+
 /**
  * struct overlay_entry - Gathered overlay FDT image info
  * @name: Overlay image name in the FIT
@@ -72,6 +81,122 @@ struct overlay_entry {
        size_t size;
 };
 
+#if CONFIG_IS_ENABLED(EFI_VARIABLE_FILE_STORE)
+
+/* Qualcomm VendorDtbOverlays UEFI variable. */
+static const u16 qcom_vendor_dtbo_efivar_name[] = u"VendorDtbOverlays";
+
+static const efi_guid_t qcom_vendor_dtbo_efivar_guid =
+       EFI_GUID(0x882f8c2b, 0x9646, 0x435f,
+                0x8d, 0xe5, 0xf2, 0x08, 0xff, 0x80, 0xc1, 0xbd);
+
+/**
+ * qcom_efivar_payload_to_str() - Convert a efi variable payload to a C string
+ * @data: Payload bytes, ASCII or UTF-16LE restricted to ASCII characters
+ * @len: Payload length in bytes
+ * @out: Returns a malloc()'d NUL-terminated string
+ *
+ * The payload is detected as UTF-16LE when its length is even and every odd
+ * byte is zero. A single trailing NUL (character) is tolerated in both forms.
+ *
+ * Return: 0 on success, -ENOENT if empty, -EINVAL if it contains an
+ *        embedded NUL, -ENOMEM on allocation failure
+ */
+static int qcom_efivar_payload_to_str(const u8 *data, size_t len, char **out)
+{
+       bool utf16 = false;
+       size_t i, n;
+       char *str;
+
+       if (len >= 2 && !(len & 1)) {
+               utf16 = true;
+               for (i = 1; i < len; i += 2) {
+                       if (data[i]) {
+                               utf16 = false;
+                               break;
+                       }
+               }
+       }
+
+       /* Number of characters */
+       n = utf16 ? (len >> 1) : len;
+
+       /* Tolerate a single trailing NUL */
+       if (n && !data[utf16 ? 2 * (n - 1) : n - 1])
+               n--;
+
+       if (!n)
+               return -ENOENT;
+
+       str = malloc(n + 1);
+       if (!str)
+               return -ENOMEM;
+
+       if (utf16) {
+               for (i = 0; i < n; ++i)
+                       str[i] = data[i << 1];
+       } else {
+               for (i = 0; i < n; ++i)
+                       str[i] = data[i];
+       }
+
+       str[n] = '\0';
+
+       /* An embedded NUL would silently truncate the token list */
+       if (strlen(str) != n) {
+               free(str);
+               return -EINVAL;
+       }
+
+       *out = str;
+
+       return 0;
+}
+
+/**
+ * qcom_get_vendor_dtbo_from_efivar() - Reads VendorDtbOverlays efi variable
+ * @out: Returns a malloc()'d NUL-terminated token string
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int qcom_get_vendor_dtbo_from_efivar(char **out)
+{
+       u8 data[QCOM_VENDOR_DTBO_EFIVAR_MAX_LEN];
+       efi_uintn_t data_size = sizeof(data);
+       u32 attributes;
+       u64 timep;
+       int ret = -ENOENT;
+       efi_status_t status;
+
+       status = efi_init_obj_list();
+       if (status) {
+               log_err("Failed to initialize EFI variables: %lx\n", status);
+               return -EIO;
+       }
+       status = efi_get_variable_int(qcom_vendor_dtbo_efivar_name,
+                                     &qcom_vendor_dtbo_efivar_guid,
+                                     &attributes,
+                                     &data_size,
+                                     data,
+                                     &timep);
+       if (status) {
+               log_err("Failed to read EFI VendorDtbOverlays: %lx\n", status);
+               if (status == EFI_NOT_FOUND)
+                       return -ENOENT;
+               else if (status == EFI_BUFFER_TOO_SMALL)
+                       return -E2BIG;
+               else
+                       return -EINVAL;
+       }
+       ret = qcom_efivar_payload_to_str(data,
+                                        data_size,
+                                        out);
+       if (ret)
+               log_err("EFI variable VendorDtbOverlays contains invalid 
data\n");
+       return ret;
+}
+#endif
+
 /**
  * add_to_bucket() - Add a node name to the bucket list
  * @name: Node name to add
@@ -348,26 +473,40 @@ static int qcom_add_dtbo_tokens(const char *str, struct 
list_head *bucket_head)
 }
 
 /**
- * qcom_parse_vendor_dtbo() - Parse vendor_dtbo environment variable
+ * qcom_parse_vendor_dtbo() - Parse the vendor DTBO overlay identifiers
  * @bucket_head: Bucket list to add overlay tokens to
  *
- * Reads the "vendor_dtbo" environment variable and parses its comma-separated
- * overlay identifiers, adding them to the bucket list for FIT configuration
- * matching. This influences which FIT configuration is selected.
+ * Reads the comma-separated overlay identifiers from the "vendor_dtbo"
+ * environment variable falling back to the "VendorDtbOverlays" EFI variable.
+ * Adds the identifiers read to the bucket list for FIT configuration matching.
+ * This influences which FIT configuration is selected.
  *
- * Return: 0 on success, negative error code on failure or if unset
+ * Return: 0 on success, negative error code on failure
  */
 static int qcom_parse_vendor_dtbo(struct list_head *bucket_head)
 {
-       const char *vendor_dtbo;
+       const char *vendor_dtbo_env;
+       int ret = -ENOENT;
 
-       vendor_dtbo = env_get("vendor_dtbo");
-       if (!vendor_dtbo || !*vendor_dtbo)
-               return -ENOENT;
+       vendor_dtbo_env = env_get("vendor_dtbo");
+       if (vendor_dtbo_env && *vendor_dtbo_env) {
+               log_info("ENV vendor_dtbo data: %s\n", vendor_dtbo_env);
+               return qcom_add_dtbo_tokens(vendor_dtbo_env, bucket_head);
+       }
 
-       log_info("vendor_dtbo: %s\n", vendor_dtbo);
+#if (CONFIG_IS_ENABLED(EFI_VARIABLE_FILE_STORE))
+       {
+               char *vendor_dtbo_overlay_efi = NULL;
 
-       return qcom_add_dtbo_tokens(vendor_dtbo, bucket_head);
+               ret = 
qcom_get_vendor_dtbo_from_efivar(&vendor_dtbo_overlay_efi);
+               if (!ret) {
+                       log_info("EFI vendor_dtbo data: %s\n", 
vendor_dtbo_overlay_efi);
+                       ret = qcom_add_dtbo_tokens(vendor_dtbo_overlay_efi, 
bucket_head);
+                       free(vendor_dtbo_overlay_efi);
+               }
+       }
+#endif
+       return ret;
 }
 
 /**
@@ -917,9 +1056,9 @@ free_overlays:
  * 6. Load DTB and apply overlays
  * 7. Install FDT for EFI
  *
- * Return: 0 on success, negative error code on failure
+ * Return: 0 always, to prevent boot failure
  */
-int qcom_fit_multidtb_setup(void)
+static int qcom_fit_multidtb_setup(void)
 {
        void *fit = NULL;
        size_t fit_size = 0;
@@ -1029,5 +1168,13 @@ cleanup_fit:
        if (fit)
                free(fit);
 
-       return ret;
+       if (ret)
+               log_err("FIT multi-DTB selection not available or failed\n");
+
+       return 0;
 }
+
+/* Try FIT multi-DTB selection if enabled */
+#if CONFIG_IS_ENABLED(QCOM_FIT_MULTIDTB)
+EVENT_SPY_SIMPLE(EVT_POST_PREBOOT, qcom_fit_multidtb_setup);
+#endif
diff --git a/arch/arm/mach-snapdragon/qcom_fit_multidtb.h 
b/arch/arm/mach-snapdragon/qcom_fit_multidtb.h
index 00b6d935a4a..4929930e060 100644
--- a/arch/arm/mach-snapdragon/qcom_fit_multidtb.h
+++ b/arch/arm/mach-snapdragon/qcom_fit_multidtb.h
@@ -40,22 +40,4 @@ enum node_process_type {
        NODE_TYPE_SOFTSKU,
 };
 
-/* Function prototypes */
-
-/**
- * qcom_fit_multidtb_setup() - Main entry point for FIT multi-DTB selection
- *
- * This function:
- * 1. Loads qclinux_fit.img from EFI partition
- * 2. Extracts metadata DTB
- * 3. Detects hardware parameters from SMEM
- * 4. Builds bucket list from metadata
- * 5. Finds matching FIT configuration
- * 6. Loads DTB and applies overlays
- * 7. Sets FDT for EFI
- *
- * Return: 0 on success, negative error code on failure
- */
-int qcom_fit_multidtb_setup(void);
-
 #endif /* __QCOM_FIT_MULTIDTB_H__ */
---
base-commit: dfcfc4c9f78d1743f490a497082a4ec8e058aae8
prerequisite-patch-id: 288b5e1177317e5684aa37b877adaae1ecb87611
prerequisite-patch-id: 52c8de1a3d51dcb7487bc8252603fe89e731000f
prerequisite-patch-id: a9eaa119a8d0fc81394544f5cdbfb125726e9f57
prerequisite-patch-id: 48ad0bec210dfc2dfae8e1e69c831cc96073c1e3
prerequisite-patch-id: feacdbb3eb20691078dca1928afe7359f5eb181e
-- 
Best regards,
Sumit Singh Dhami

Reply via email to