This patchset builds on top of Leif's DtbLoader, adding support to pick a laptop specific dtb based on SMBIOS tables, and patching for /chosen/panel-id based on UEFIDisplayInfo. I'll send a new version of the kernel side patchset that uses /chosen/panel-id to pick the appropriate panel driver in the near future (ie. I'll probably get to it tomorrow)
Rob Clark (5): DtbLoader: refactor out helper to try loading dtb DtbLoader: Try to pick dtb based on SMBIOS tables DtbLoader: move CRC calculation DtbLoader: resize fdt DtbLoader: add panel-id detection/fixup for qcom devices
.../Application/ConfigTableLoader/Common.h | 2 + .../Application/ConfigTableLoader/DtbLoader.c | 437 +++++++++++++++--- .../ConfigTableLoader/DtbLoader.inf | 2 + .../Application/ConfigTableLoader/Qcom.c | 94 ++++ .../Application/ConfigTableLoader/Qcom.h | 30 ++ 5 files changed, 506 insertions(+), 59 deletions(-) create mode 100644 EmbeddedPkg/Application/ConfigTableLoader/Qcom.c create mode 100644 EmbeddedPkg/Application/ConfigTableLoader/Qcom.h
If we are going to pick a dtb based on SMBIOS info, we'll want to try a few possibilities, so refactor out the string construction logic.
This drops using relative path of DtbLoader.efi in constructing the path, in favor of finding them relative to the root. I'm not there is a good argument to give distros the possibility to put things in different locations.
Signed-off-by: Rob Clark robdclark@gmail.com --- .../Application/ConfigTableLoader/Common.h | 2 + .../Application/ConfigTableLoader/DtbLoader.c | 143 +++++++++++++----- 2 files changed, 105 insertions(+), 40 deletions(-)
diff --git a/EmbeddedPkg/Application/ConfigTableLoader/Common.h b/EmbeddedPkg/Application/ConfigTableLoader/Common.h index 9474c00b03..757180dc5b 100644 --- a/EmbeddedPkg/Application/ConfigTableLoader/Common.h +++ b/EmbeddedPkg/Application/ConfigTableLoader/Common.h @@ -14,6 +14,8 @@ #include <Protocol/LoadedImage.h> #include <Protocol/SimpleFileSystem.h>
+#define Dbg(...) do { Print(__VA_ARGS__); gBS->Stall(100000); } while (0) + /** Acquires a LOADED_IMAGE_PROTOCOL structure that points to the instance for the currently executing image. diff --git a/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c b/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c index 4fba272e43..d1a8e2e81c 100644 --- a/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c +++ b/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c @@ -11,6 +11,7 @@
#include <libfdt.h> #include <Uefi.h> +#include <Library/DebugLib.h> #include <Library/MemoryAllocationLib.h> #include <Library/UefiLib.h> #include <Library/UefiApplicationEntryPoint.h> @@ -22,8 +23,6 @@
#include "Common.h"
-#define DTB_BLOB_NAME L"MY.DTB" - STATIC struct { UINT32 Crc32; UINT32 FileSize; @@ -100,6 +99,101 @@ ReadBlob ( return Status; }
+/** + Construct a path string from an array of path components, and try to load + a dtb blob from that path. + + The file path is constructed as (for example): + + PathComponents[0] + "" + ... + "" + PathComponents[n] + "" + + FileComponents[0] + "-" + ... + "-" + FileComponents[m] + ".dtb" + +**/ +STATIC +EFI_STATUS +TryLoadBlob ( + IN EFI_FILE_PROTOCOL *Root, + IN CHAR16 **PathComponents, + IN UINT32 PathComponentsLen, + IN CHAR16 **FileComponents, + IN UINT32 FileComponentsLen, + IN OUT VOID **Blob + ) +{ + CHAR16 *BlobName; + UINTN BlobPathLength; + EFI_STATUS Status; + + ASSERT (PathComponentsLen > 0); + ASSERT (FileComponentsLen > 0); + + BlobPathLength = 1; // terminating null + + for (UINT32 i = 0; i < PathComponentsLen; i++) { + BlobPathLength += StrLen (PathComponents[i]); + BlobPathLength += 1; // +1 for '' + } + + for (UINT32 i = 0; i < FileComponentsLen; i++) { + BlobPathLength += StrLen (FileComponents[i]); + BlobPathLength += 1; // +1 for '' or '.' + } + + BlobPathLength += 3; // for "dtb" + + BlobName = AllocatePool (BlobPathLength * sizeof (CHAR16)); + if (BlobName == NULL) { + Print (L"Memory allocation failed!\n"); + return EFI_OUT_OF_RESOURCES; + } + + BlobName[0] = L'\0'; + + for (UINT32 i = 0; i < PathComponentsLen; i++) { + Status = StrCatS (BlobName, BlobPathLength, PathComponents[i]); + if (EFI_ERROR (Status)) { + Print (L"%a:%d: Status = %x\n", __func__, __LINE__, Status); + goto Cleanup; + } + Status = StrCatS (BlobName, BlobPathLength, L"\"); + if (EFI_ERROR (Status)) { + Print (L"%a:%d: Status = %x\n", __func__, __LINE__, Status); + goto Cleanup; + } + } + + for (UINT32 i = 0; i < FileComponentsLen; i++) { + if (i > 0) { + Status = StrCatS (BlobName, BlobPathLength, L"-"); + if (EFI_ERROR (Status)) { + Print (L"%a:%d: Status = %x\n", __func__, __LINE__, Status); + goto Cleanup; + } + } + Status = StrCatS (BlobName, BlobPathLength, FileComponents[i]); + if (EFI_ERROR (Status)) { + Print (L"%a:%d: Status = %x\n", __func__, __LINE__, Status); + goto Cleanup; + } + } + + Dbg (L"BlobName=%s\n", BlobName); + + Status = StrCatS (BlobName, BlobPathLength, L".dtb"); + if (EFI_ERROR (Status)) { + Print (L"%a:%d: Status = %x\n", __func__, __LINE__, Status); + goto Cleanup; + } + + Dbg (L"Try to load: %s\n", BlobName); + + Status = ReadBlob (Root, BlobName, Blob); + + Cleanup: + FreePool (BlobName); + return Status; +} + STATIC EFI_STATUS RegisterDtBlob ( @@ -176,12 +270,7 @@ UefiMain ( { EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem; - EFI_DEVICE_PATH_PROTOCOL *ImagePath; EFI_FILE_PROTOCOL *Root; - CHAR16 *FileName; - CHAR16 *TempString; - CHAR16 *BlobName; - UINTN BlobPathLength; EFI_STATUS Status; VOID *Blob;
@@ -195,43 +284,19 @@ UefiMain ( return Status; }
- ImagePath = LoadedImage->FilePath; - FileName = (CHAR16 *)((UINTN)ImagePath + 4); - - // Even paths to files in root directory start with '' - TempString = StrRChr (FileName, L'\'); - if (TempString == NULL) { - Print (L"Invalid path for image: '%s'\n", FileName); - return EFI_UNSUPPORTED; - } - - BlobPathLength = StrLen (DTB_BLOB_NAME); - BlobPathLength += TempString - FileName + 1; // + 1 for '' - BlobPathLength += 1; // + 1 for '\0' - - BlobName = AllocatePool (BlobPathLength * sizeof (CHAR16)); - if (BlobName == NULL) { - Print (L"Memory allocation failed!\n"); - return EFI_OUT_OF_RESOURCES; - } - - Status = StrnCpyS (BlobName, BlobPathLength, FileName, - TempString - FileName + 1); - if (EFI_ERROR (Status)) { - Print (L"Status = %x\n", Status); - } - Status = StrCatS (BlobName, BlobPathLength, DTB_BLOB_NAME); - if (EFI_ERROR (Status)) { - Print (L"Status = %x\n", Status); - } - Status = FileSystem->OpenVolume (FileSystem, &Root); if (EFI_ERROR (Status)) { Print (L"OpenVolume call failed!\n"); goto Cleanup; }
- Status = ReadBlob (Root, BlobName, &Blob); + /* fallback to trying \MY.DTB: */ + Status = TryLoadBlob ( + Root, + &(CHAR16 *){ L"" }, 1, + &(CHAR16 *){ L"MY" }, 1, + &Blob + ); if (!EFI_ERROR (Status)) { EFI_EVENT ExitBootServicesEvent;
@@ -256,7 +321,5 @@ UefiMain ( }
Cleanup: - FreePool (BlobName); - return Status; }
To better support multiple different aarch64 laptops with a single image, add logic to pick the dtb to load based on SMBIOS tables.
This involves jumping thru some hoops, as the SMBIOS tables may not yet be installed when DtbLoader is installed, so we need to hook notifiers to defer SMBIOS parsing and dtb loading.
Signed-off-by: Rob Clark robdclark@gmail.com --- .../Application/ConfigTableLoader/DtbLoader.c | 251 ++++++++++++++++-- 1 file changed, 232 insertions(+), 19 deletions(-)
diff --git a/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c b/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c index d1a8e2e81c..2acd9cb698 100644 --- a/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c +++ b/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c @@ -18,6 +18,9 @@ #include <Library/UefiBootServicesTableLib.h> #include <Library/UefiRuntimeServicesTableLib.h>
+#include <Guid/SmBios.h> +#include <IndustryStandard/SmBios.h> + #include <Guid/Fdt.h> #include <Guid/FileInfo.h>
@@ -30,6 +33,137 @@ STATIC struct { VOID *Data; } mBlobInfo;
+/* + * These map to what linux prints at boot, when you see a string like: + * + * DMI: LENOVO 81JL/LNVNB161216, BIOS ... + * + * We don't really care about the BIOS version information, but the + * first part gives a reasonable way to pick a dtb. + */ +STATIC struct { + CHAR16 *SysVendor; /* System Information/Manufacturer */ + CHAR16 *ProductName; /* System Information/Product Name */ + CHAR16 *BoardName; /* Base Board Information/Product Name */ +} mSmbiosInfo; + +STATIC EFI_EVENT mSmbiosTableEvent; +STATIC EFI_EVENT mSmbios3TableEvent; + +// HACK, why do I need this? +EFI_GUID gEfiSmbios3TableGuid = { 0xF2FD1544, 0x9794, 0x4A2C, { 0x99, 0x2E, 0xE5, 0xBB, 0xCF, 0x20, 0xE3, 0x94 }}; +EFI_GUID gEfiSmbiosTableGuid = { 0xEB9D2D31, 0x2D88, 0x11D3, { 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; + +STATIC +VOID * +GetSmbiosTable (VOID) +{ + SMBIOS_TABLE_ENTRY_POINT *SmbiosTable = NULL; + SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios64BitTable = NULL; + EFI_STATUS Status; + + Status = EfiGetSystemConfigurationTable (&gEfiSmbios3TableGuid, (VOID**)&Smbios64BitTable); + if (Smbios64BitTable) { + Print (L"Got 64b SMBIOS Table\n"); + return (VOID *) (UINTN) (Smbios64BitTable->TableAddress); + } else { + Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID**)&SmbiosTable); + if (SmbiosTable) { + Print (L"Got SMBIOS Table\n"); + return (VOID *) (UINTN) (SmbiosTable->TableAddress); + } else { + Print (L"%a:%d: Status = %x\n", __func__, __LINE__, Status); + return NULL; + } + } +} + + +STATIC +CHAR16* +LibGetSmbiosString ( + IN SMBIOS_STRUCTURE_POINTER *Smbios, + IN UINT16 StringNumber + ) +{ + UINT16 Index; + CHAR8 *String; + + ASSERT (Smbios != NULL); + + // + // Skip over formatted section + // + String = (CHAR8 *) (Smbios->Raw + Smbios->Hdr->Length); + + // + // Look through unformatted section + // + for (Index = 1; Index <= StringNumber; Index++) { + if (StringNumber == Index) { + UINTN StrSize = AsciiStrnLenS (String, ~0) + 1; + CHAR16 *String16 = AllocatePool (StrSize * sizeof (CHAR16)); + AsciiStrToUnicodeStrS (String, String16, StrSize); + return String16; + } + // + // Skip string + // + for (; *String != 0; String++); + String++; + + if (*String == 0) { + // + // If double NULL then we are done. + // Return pointer to next structure in Smbios. + // if you pass in a -1 you will always get here + // + Smbios->Raw = (UINT8 *)++String; + return NULL; + } + } + + return NULL; +} + +STATIC +EFI_STATUS +ReadSmbiosInfo (VOID) +{ + SMBIOS_TABLE_TYPE1 *Type1Record; + SMBIOS_TABLE_TYPE2 *Type2Record; + SMBIOS_STRUCTURE_POINTER Smbios; + + Smbios.Raw = GetSmbiosTable(); + + if (!Smbios.Raw) + return EFI_NOT_FOUND; + + while (Smbios.Hdr->Type != 127) { + Dbg (L"Record: %d\n", Smbios.Hdr->Type); + + if (Smbios.Hdr->Type == SMBIOS_TYPE_SYSTEM_INFORMATION) { + Type1Record = (SMBIOS_TABLE_TYPE1 *) Smbios.Raw; + mSmbiosInfo.SysVendor = LibGetSmbiosString(&Smbios, Type1Record->Manufacturer); + mSmbiosInfo.ProductName = LibGetSmbiosString(&Smbios, Type1Record->ProductName); + } + + if (Smbios.Hdr->Type == SMBIOS_TYPE_BASEBOARD_INFORMATION) { + Type2Record = (SMBIOS_TABLE_TYPE2 *) Smbios.Raw; + mSmbiosInfo.BoardName = LibGetSmbiosString(&Smbios, Type2Record->ProductName); + } + + // + // Walk to next structure + // + LibGetSmbiosString (&Smbios, (UINT16) (-1)); + } + + Dbg (L"SysVendor=%s, ProductName=%s, BoardName=%s\n", mSmbiosInfo.SysVendor, mSmbiosInfo.ProductName, mSmbiosInfo.BoardName); + + return EFI_SUCCESS; +} + STATIC EFI_STATUS ReadBlob ( @@ -250,23 +384,9 @@ ExitBootServicesHook ( gBS->InstallConfigurationTable (&gEfiAcpi20TableGuid, NULL); }
-/** - The user Entry Point for Application. The user code starts with this function - as the real entry point for the application. - - @param[in] ImageHandle The firmware allocated handle for the EFI image. - @param[in] SystemTable A pointer to the EFI System Table. - - @retval EFI_SUCCESS The entry point is executed successfully. - @retval other Some error occurs when executing this entry point. - -**/ +STATIC EFI_STATUS -EFIAPI -UefiMain ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable - ) +LoadAndRegisterDtb (VOID) { EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem; @@ -274,6 +394,8 @@ UefiMain ( EFI_STATUS Status; VOID *Blob;
+ Dbg (L"LoadAndRegisterDtb\n"); + Status = GetLoadedImageProtocol (&LoadedImage); if (EFI_ERROR (Status)) { return Status; @@ -284,19 +406,46 @@ UefiMain ( return Status; }
+ Status = ReadSmbiosInfo(); + if (EFI_ERROR (Status)) { + Print (L"Failed to read SMBIOS info: Status = %x\n", Status); + goto Cleanup; + } + Status = FileSystem->OpenVolume (FileSystem, &Root); if (EFI_ERROR (Status)) { Print (L"OpenVolume call failed!\n"); goto Cleanup; }
- /* fallback to trying \MY.DTB: */ + /* First try \dtb\SysVendor\ProductName-BoardName.dtb */ Status = TryLoadBlob ( Root, - &(CHAR16 *){ L"" }, 1, - &(CHAR16 *){ L"MY" }, 1, + (CHAR16 *[]){ L"\dtb", mSmbiosInfo.SysVendor }, 2, + (CHAR16 *[]){ mSmbiosInfo.ProductName, mSmbiosInfo.BoardName }, 2, &Blob ); + if (EFI_ERROR (Status)) { + /* Then fallback to \dtb\SysVendor\ProductName.dtb */ + Status = TryLoadBlob ( + Root, + (CHAR16 *[]){ L"\dtb", mSmbiosInfo.SysVendor }, 2, + (CHAR16 *[]){ mSmbiosInfo.ProductName }, 1, + &Blob + ); + } + + if (EFI_ERROR (Status)) { + /* finally fallback to trying \MY.DTB: */ + // TODO should we try this first, as a convenient way to override default dtb for devel?? + Status = TryLoadBlob ( + Root, + (CHAR16 *[]){ L"" }, 1, + (CHAR16 *[]){ L"MY" }, 1, + &Blob + ); + } + if (!EFI_ERROR (Status)) { EFI_EVENT ExitBootServicesEvent;
@@ -323,3 +472,67 @@ UefiMain ( Cleanup: return Status; } + +STATIC +VOID +OnSmbiosTablesRegistered ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + Dbg (L"OnSmbiosTablesRegistered\n"); + + if (GetSmbiosTable()) { + Status = LoadAndRegisterDtb(); + Print (L"%a:%d: Status = %x\n", __func__, __LINE__, Status); + if (Status == EFI_SUCCESS) { + gBS->CloseEvent(mSmbiosTableEvent); + gBS->CloseEvent(mSmbios3TableEvent); + } + } +} + +/** + The user Entry Point for Application. The user code starts with this function + as the real entry point for the application. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + if (GetSmbiosTable()) { + /* already got SMBIOS tables configured, so just go: */ + return LoadAndRegisterDtb(); + } + + /* + * SMBIOS config tables not ready yet, so hook in notifier to do our work + * later once they are registered: + */ + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, + OnSmbiosTablesRegistered, NULL, &gEfiSmbios3TableGuid, + &mSmbios3TableEvent); + ASSERT_EFI_ERROR (Status); + + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, + OnSmbiosTablesRegistered, NULL, &gEfiSmbiosTableGuid, + &mSmbiosTableEvent); + ASSERT_EFI_ERROR (Status); + + return Status; +} +
Move this to just before registering the config table. This way we can more easily add dt fixup code (ie. inserting stuff into chosen node), which would need to happen before we calculate CRC. Also add a comment better explaining the purpose of the CRC check.
Signed-off-by: Rob Clark robdclark@gmail.com --- .../Application/ConfigTableLoader/DtbLoader.c | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c b/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c index 2acd9cb698..c32c4a8dd3 100644 --- a/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c +++ b/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c @@ -140,8 +140,6 @@ ReadSmbiosInfo (VOID) return EFI_NOT_FOUND;
while (Smbios.Hdr->Type != 127) { - Dbg (L"Record: %d\n", Smbios.Hdr->Type); - if (Smbios.Hdr->Type == SMBIOS_TYPE_SYSTEM_INFORMATION) { Type1Record = (SMBIOS_TABLE_TYPE1 *) Smbios.Raw; mSmbiosInfo.SysVendor = LibGetSmbiosString(&Smbios, Type1Record->Manufacturer); @@ -216,17 +214,9 @@ ReadBlob ( }
// Save DT info to detect changes. - gBS->CalculateCrc32 (*Blob, FileInfo->FileSize, &mBlobInfo.Crc32); mBlobInfo.FileSize = FileInfo->FileSize; - mBlobInfo.TotalSize = fdt_totalsize (*Blob); mBlobInfo.Data = *Blob;
- Print (L"DT CRC32: %08x\n", mBlobInfo.Crc32); - Print (L"DT TotalSize: %d bytes\n", mBlobInfo.TotalSize); - if (mBlobInfo.FileSize < mBlobInfo.TotalSize) { - Print (L"Warning: File size (%d bytes) < TotalSize\n", mBlobInfo.FileSize); - } - Cleanup: FreePool (FileInfo); Root->Close (File); @@ -311,8 +301,6 @@ TryLoadBlob ( } }
- Dbg (L"BlobName=%s\n", BlobName); - Status = StrCatS (BlobName, BlobPathLength, L".dtb"); if (EFI_ERROR (Status)) { Print (L"%a:%d: Status = %x\n", __func__, __LINE__, Status); @@ -336,6 +324,21 @@ RegisterDtBlob ( { EFI_STATUS Status;
+ /* Calculate CRC to detect changes. The linux kernel's efi libstub + * will insert the kernel commandline into the chosen node before + * calling ExitBootServices, and we can use this to differentiate + * between ACPI boot (ie. windows) and DT boot. + */ + gBS->CalculateCrc32 (mBlobInfo.Data, mBlobInfo.FileSize, &mBlobInfo.Crc32); + mBlobInfo.TotalSize = fdt_totalsize (mBlobInfo.Data); + + Print (L"DT CRC32: %08x\n", mBlobInfo.Crc32); + Print (L"DT TotalSize: %d bytes\n", mBlobInfo.TotalSize); + Print (L"DT FileSize: %d bytes\n", mBlobInfo.FileSize); + if (mBlobInfo.FileSize < mBlobInfo.TotalSize) { + Print (L"Warning: File size (%d bytes) < TotalSize\n", mBlobInfo.FileSize); + } + Status = gBS->InstallConfigurationTable (&gFdtTableGuid, Blob); if (!EFI_ERROR (Status)) { Print (L"DTB installed successfully!\n");
We could only conditionally do this, if we know we are going to need to add nodes. But it's easier to just do this unconditionally.
Signed-off-by: Rob Clark robdclark@gmail.com --- .../Application/ConfigTableLoader/DtbLoader.c | 38 +++++++++++++++++++ .../ConfigTableLoader/DtbLoader.inf | 1 + 2 files changed, 39 insertions(+)
diff --git a/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c b/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c index c32c4a8dd3..2d32cc5b64 100644 --- a/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c +++ b/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c @@ -162,6 +162,43 @@ ReadSmbiosInfo (VOID) return EFI_SUCCESS; }
+#define FDT_ADDITIONAL_SIZE 0x400 + +/* Increase the size of the FDT blob so that we can patch in new nodes */ +STATIC +EFI_STATUS +ResizeBlob ( + IN OUT VOID **Blob + ) +{ + VOID *NewBlob; + UINTN NewSize; + INTN Err; + + NewSize = fdt_totalsize (*Blob) + FDT_ADDITIONAL_SIZE; + NewBlob = AllocatePool (NewSize); + if (!NewBlob) { + Print (L"%a:%d: allocation failed\n", __func__, __LINE__); + return EFI_OUT_OF_RESOURCES; + } + + Err = fdt_open_into (*Blob, NewBlob, NewSize); + if (Err) { + Print (L"Could not expand fdt: %a\n", fdt_strerror (Err)); + FreePool (NewBlob); + return EFI_OUT_OF_RESOURCES; + } + + /* Successfully Resized: */ + mBlobInfo.FileSize += FDT_ADDITIONAL_SIZE; + mBlobInfo.Data = NewBlob; + + FreePool (*Blob); + *Blob = NewBlob; + + return EFI_SUCCESS; +} + STATIC EFI_STATUS ReadBlob ( @@ -452,6 +489,7 @@ LoadAndRegisterDtb (VOID) if (!EFI_ERROR (Status)) { EFI_EVENT ExitBootServicesEvent;
+ ResizeBlob (&Blob); RegisterDtBlob (Blob);
Status = gBS->CreateEvent ( diff --git a/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.inf b/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.inf index 751fe175ea..1f73594d60 100644 --- a/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.inf +++ b/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.inf @@ -32,6 +32,7 @@
[LibraryClasses] BaseLib + FdtLib UefiDriverEntryPoint UefiBootServicesTableLib UefiRuntimeServicesTableLib
Put this in it's own file. Maybe at some point there will be other aarch64 laptops from other SoC vendors which need their own specific dt patching.
Signed-off-by: Rob Clark robdclark@gmail.com --- .../Application/ConfigTableLoader/DtbLoader.c | 2 + .../ConfigTableLoader/DtbLoader.inf | 1 + .../Application/ConfigTableLoader/Qcom.c | 94 +++++++++++++++++++ .../Application/ConfigTableLoader/Qcom.h | 30 ++++++ 4 files changed, 127 insertions(+) create mode 100644 EmbeddedPkg/Application/ConfigTableLoader/Qcom.c create mode 100644 EmbeddedPkg/Application/ConfigTableLoader/Qcom.h
diff --git a/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c b/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c index 2d32cc5b64..adda525847 100644 --- a/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c +++ b/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.c @@ -25,6 +25,7 @@ #include <Guid/FileInfo.h>
#include "Common.h" +#include "Qcom.h"
STATIC struct { UINT32 Crc32; @@ -490,6 +491,7 @@ LoadAndRegisterDtb (VOID) EFI_EVENT ExitBootServicesEvent;
ResizeBlob (&Blob); + QcomDetectPanel (Blob); RegisterDtBlob (Blob);
Status = gBS->CreateEvent ( diff --git a/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.inf b/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.inf index 1f73594d60..bb91739950 100644 --- a/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.inf +++ b/EmbeddedPkg/Application/ConfigTableLoader/DtbLoader.inf @@ -29,6 +29,7 @@ [Sources.common] Common.c DtbLoader.c + Qcom.c
[LibraryClasses] BaseLib diff --git a/EmbeddedPkg/Application/ConfigTableLoader/Qcom.c b/EmbeddedPkg/Application/ConfigTableLoader/Qcom.c new file mode 100644 index 0000000000..ad33b738ed --- /dev/null +++ b/EmbeddedPkg/Application/ConfigTableLoader/Qcom.c @@ -0,0 +1,94 @@ +/** @file + + Copyright (c) 2019, Linaro. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <libfdt.h> +#include <Uefi.h> +#include <Library/BaseLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiBootServicesTableLib.h> + +#include "Common.h" + +/* + * We (at least currently) don't care about most of the fields, just + * panel_id: + */ +typedef struct { + UINT32 VersionInfo; + UINT32 pad0[9]; + UINT32 PanelId; + UINT32 pad1[17]; +} MdpDispInfo; + +#define MDP_DISP_INFO_VERSION_MAGIC 0xaa + + +/** + Detect (if present) the qcom specific UEFIDisplayInfo variable, and + patch /chosen/panel-id accordingly. + + @param[in] Blob The fdt blob to patch if panel id is detected + + @retval EFI_SUCCESS The panel was detected and dt patched successfully. + @retval other Error. + +**/ +EFI_STATUS +EFIAPI +QcomDetectPanel ( + IN VOID *Blob + ) +{ + EFI_STATUS Status; + MdpDispInfo *DispInfo; + INT32 ChosenNode; + UINT32 FdtPanelId; + INT32 Err; + + Status = GetVariable3 ( + L"UEFIDisplayInfo", + &gEfiGraphicsOutputProtocolGuid, + (VOID **) &DispInfo, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + Print (L"%a:%d: Status = %x\n", __func__, __LINE__, Status); + return Status; + } + + Dbg (L"Got VersionInfo: 0x%08x\n", DispInfo->VersionInfo); + + if ((DispInfo->VersionInfo >> 16) != MDP_DISP_INFO_VERSION_MAGIC) { + Print (L"Bad VersionInfo magic: 0x%08x\n", DispInfo->VersionInfo); + goto Cleanup; + } + + Dbg (L"Got PanelId: 0x%x\n", DispInfo->PanelId); + + /* We found our panel-id, now patch up the fdt: */ + ChosenNode = fdt_subnode_offset (Blob, 0, "chosen"); + if (ChosenNode < 0) { + Print (L"ChosenNode not found: %s\n", fdt_strerror (ChosenNode)); + return EFI_NOT_FOUND; + } + + FdtPanelId = cpu_to_fdt32 (DispInfo->PanelId); + Err = fdt_setprop (Blob, ChosenNode, "panel-id", &FdtPanelId, sizeof(FdtPanelId)); + if (Err) { + Print (L"Could not add panel-id: %a\n", fdt_strerror (Err)); + return EFI_OUT_OF_RESOURCES; + } + + Dbg (L"fdt patched successfully\n"); + + Cleanup: + FreePool (DispInfo); + return Status; +} diff --git a/EmbeddedPkg/Application/ConfigTableLoader/Qcom.h b/EmbeddedPkg/Application/ConfigTableLoader/Qcom.h new file mode 100644 index 0000000000..8a92033cbe --- /dev/null +++ b/EmbeddedPkg/Application/ConfigTableLoader/Qcom.h @@ -0,0 +1,30 @@ +/** @file + + Copyright (c) 2019, Linaro. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef QCOM_H_ +#define QCOM_H_ + +#include <Uefi.h> + +/** + Detect (if present) the qcom specific UEFIDisplayInfo variable, and + patch /chosen/panel-id accordingly. + + @param[in] Blob The fdt blob to patch if panel id is detected + + @retval EFI_SUCCESS The panel was detected and dt patched successfully. + @retval other Error. + +**/ +EFI_STATUS +EFIAPI +QcomDetectPanel ( + IN VOID *Blob + ); + +#endif /* QCOM_H_ */
aarch64-laptops@lists.linaro.org