/** @file * * Copyright (c) 2019 - 2020, ARM Limited. All rights reserved. * Copyright (c) 2018 - 2020, Andrei Warkentin * * SPDX-License-Identifier: BSD-2-Clause-Patent * **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ConfigDxeFormSetGuid.h" #include "ConfigDxe.h" #define FREQ_1_MHZ 1000000 extern UINT8 ConfigDxeHiiBin[]; extern UINT8 ConfigDxeStrings[]; STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL *mFwProtocol; STATIC UINT32 mModelFamily = 0; STATIC UINT32 mModelInstalledMB = 0; STATIC UINT32 mModelRevision = 0; STATIC EFI_MAC_ADDRESS mMacAddress; /* * The GUID inside Platform/RaspberryPi/RPi3/AcpiTables/AcpiTables.inf and * Platform/RaspberryPi/RPi4/AcpiTables/AcpiTables.inf _must_ match below. */ STATIC CONST EFI_GUID mAcpiTableFile = { 0x7E374E25, 0x8E01, 0x4FEE, { 0x87, 0xf2, 0x39, 0x0C, 0x23, 0xC6, 0x06, 0xCD } }; typedef struct { VENDOR_DEVICE_PATH VendorDevicePath; EFI_DEVICE_PATH_PROTOCOL End; } HII_VENDOR_DEVICE_PATH; #pragma pack (1) typedef struct { MAC_ADDR_DEVICE_PATH MacAddrDP; EFI_DEVICE_PATH_PROTOCOL End; } GENET_DEVICE_PATH; typedef struct { GENET_DEVICE_PATH DevicePath; BCM_GENET_PLATFORM_DEVICE_PROTOCOL PlatformDevice; } GENET_DEVICE; #pragma pack () STATIC HII_VENDOR_DEVICE_PATH mVendorDevicePath = { { { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { (UINT8)(sizeof (VENDOR_DEVICE_PATH)), (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8) } }, CONFIGDXE_FORM_SET_GUID }, { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { (UINT8)(END_DEVICE_PATH_LENGTH), (UINT8)((END_DEVICE_PATH_LENGTH) >> 8) } } }; STATIC GENET_DEVICE mGenetDevice = { { { { MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, { (UINT8)(sizeof (MAC_ADDR_DEVICE_PATH)), (UINT8)((sizeof (MAC_ADDR_DEVICE_PATH)) >> 8) } }, {{ 0 }}, NET_IFTYPE_ETHERNET }, { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } } }, { GENET_BASE_ADDRESS, {{ 0 }} } }; STATIC VOID EFIAPI RegisterDevices ( EFI_EVENT Event, VOID *Context ) { EFI_HANDLE Handle; EFI_STATUS Status; if (mModelFamily == 4) { DEBUG ((DEBUG_INFO, "GENET: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", mMacAddress.Addr[0], mMacAddress.Addr[1], mMacAddress.Addr[2], mMacAddress.Addr[3], mMacAddress.Addr[4], mMacAddress.Addr[5])); CopyMem (&mGenetDevice.DevicePath.MacAddrDP.MacAddress, mMacAddress.Addr, NET_ETHER_ADDR_LEN); CopyMem (&mGenetDevice.PlatformDevice.MacAddress, mMacAddress.Addr, NET_ETHER_ADDR_LEN); Handle = NULL; Status = gBS->InstallMultipleProtocolInterfaces (&Handle, &gEfiDevicePathProtocolGuid, &mGenetDevice.DevicePath, &gBcmGenetPlatformDeviceProtocolGuid, &mGenetDevice.PlatformDevice, NULL); ASSERT_EFI_ERROR (Status); } } STATIC EFI_STATUS InstallHiiPages ( VOID ) { EFI_STATUS Status; EFI_HII_HANDLE HiiHandle; EFI_HANDLE DriverHandle; DriverHandle = NULL; Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle, &gEfiDevicePathProtocolGuid, &mVendorDevicePath, NULL); if (EFI_ERROR (Status)) { return Status; } HiiHandle = HiiAddPackages (&gConfigDxeFormSetGuid, DriverHandle, ConfigDxeStrings, ConfigDxeHiiBin, NULL); if (HiiHandle == NULL) { gBS->UninstallMultipleProtocolInterfaces (DriverHandle, &gEfiDevicePathProtocolGuid, &mVendorDevicePath, NULL); return EFI_OUT_OF_RESOURCES; } return EFI_SUCCESS; } STATIC EFI_STATUS SetupVariables ( VOID ) { UINTN Size; UINT8 Var8; UINT32 Var32; CHAR16 AssetTagVar[ASSET_TAG_STR_STORAGE_SIZE] = L""; EFI_STATUS Status; /* * Create the vars with default value. * If we don't, forms won't be able to update. */ Size = sizeof (UINT32); Status = gRT->GetVariable (L"CpuClock", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status)) { Status = PcdSet32S (PcdCpuClock, PcdGet32 (PcdCpuClock)); ASSERT_EFI_ERROR (Status); } Size = sizeof (UINT32); Status = gRT->GetVariable (L"CustomCpuClock", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status)) { Status = PcdSet32S (PcdCustomCpuClock, PcdGet32 (PcdCustomCpuClock)); ASSERT_EFI_ERROR (Status); } if (mModelFamily >= 4 && mModelInstalledMB > 3 * 1024) { /* * This allows changing PcdRamLimitTo3GB in forms. */ Status = PcdSet32S (PcdRamMoreThan3GB, 1); ASSERT_EFI_ERROR (Status); Size = sizeof (UINT32); Status = gRT->GetVariable (L"RamLimitTo3GB", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status)) { Status = PcdSet32S (PcdRamLimitTo3GB, PcdGet32 (PcdRamLimitTo3GB)); ASSERT_EFI_ERROR (Status); } } else { Status = PcdSet32S (PcdRamMoreThan3GB, 0); ASSERT_EFI_ERROR (Status); Status = PcdSet32S (PcdRamLimitTo3GB, 0); ASSERT_EFI_ERROR (Status); } Size = sizeof (UINT32); Status = gRT->GetVariable (L"SystemTableMode", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status)) { Status = PcdSet32S (PcdSystemTableMode, PcdGet32 (PcdSystemTableMode)); ASSERT_EFI_ERROR (Status); } Size = sizeof (UINT32); Status = gRT->GetVariable (L"FanOnGpio", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status)) { Status = PcdSet32S (PcdFanOnGpio, PcdGet32 (PcdFanOnGpio)); ASSERT_EFI_ERROR (Status); } Size = sizeof (UINT32); Status = gRT->GetVariable (L"FanTemp", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status)) { Status = PcdSet32S (PcdFanTemp, PcdGet32 (PcdFanTemp)); ASSERT_EFI_ERROR (Status); } if (mModelFamily >= 4) { if (((mModelRevision >> 4) & 0xFF) == 0x14) { /* * Enable PCIe by default on CM4 */ Status = PcdSet32S (PcdXhciPci, 2); ASSERT_EFI_ERROR (Status); } else { Size = sizeof (UINT32); Status = gRT->GetVariable (L"XhciPci", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status) || (Var32 == 0)) { /* * Enable XHCI by default */ Status = PcdSet32S (PcdXhciPci, 0); ASSERT_EFI_ERROR (Status); } else { /* * Enable PCIe */ Status = PcdSet32S (PcdXhciPci, 1); ASSERT_EFI_ERROR (Status); } } } else { /* * Disable PCIe and XHCI */ Status = PcdSet32S (PcdXhciPci, 0); ASSERT_EFI_ERROR (Status); } Size = sizeof (AssetTagVar); Status = gRT->GetVariable (L"AssetTag", &gConfigDxeFormSetGuid, NULL, &Size, AssetTagVar); if (EFI_ERROR (Status)) { Status = gRT->SetVariable ( L"AssetTag", &gConfigDxeFormSetGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, sizeof (AssetTagVar), AssetTagVar ); } Size = sizeof (UINT32); Status = gRT->GetVariable (L"SdIsArasan", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status)) { Status = PcdSet32S (PcdSdIsArasan, PcdGet32 (PcdSdIsArasan)); ASSERT_EFI_ERROR (Status); } Size = sizeof (UINT32); Status = gRT->GetVariable (L"MmcDisableMulti", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status)) { Status = PcdSet32S (PcdMmcDisableMulti, PcdGet32 (PcdMmcDisableMulti)); ASSERT_EFI_ERROR (Status); } Size = sizeof (UINT32); Status = gRT->GetVariable (L"MmcForce1Bit", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status)) { Status = PcdSet32S (PcdMmcForce1Bit, PcdGet32 (PcdMmcForce1Bit)); ASSERT_EFI_ERROR (Status); } Size = sizeof (UINT32); Status = gRT->GetVariable (L"MmcForceDefaultSpeed", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status)) { Status = PcdSet32S (PcdMmcForceDefaultSpeed, PcdGet32 (PcdMmcForceDefaultSpeed)); ASSERT_EFI_ERROR (Status); } Size = sizeof (UINT32); Status = gRT->GetVariable (L"MmcSdDefaultSpeedMHz", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status)) { Status = PcdSet32S (PcdMmcSdDefaultSpeedMHz, PcdGet32 (PcdMmcSdDefaultSpeedMHz)); ASSERT_EFI_ERROR (Status); } Size = sizeof (UINT32); Status = gRT->GetVariable (L"MmcSdHighSpeedMHz", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status)) { Status = PcdSet32S (PcdMmcSdHighSpeedMHz, PcdGet32 (PcdMmcSdHighSpeedMHz)); ASSERT_EFI_ERROR (Status); } Size = sizeof (UINT32); Status = gRT->GetVariable (L"MmcEnableDma", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status)) { Status = PcdSet32S (PcdMmcEnableDma, PcdGet32 (PcdMmcEnableDma)); ASSERT_EFI_ERROR (Status); } Size = sizeof (UINT32); Status = gRT->GetVariable (L"DebugEnableJTAG", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status)) { Status = PcdSet32S (PcdDebugEnableJTAG, PcdGet32 (PcdDebugEnableJTAG)); ASSERT_EFI_ERROR (Status); } Size = sizeof (UINT8); Status = gRT->GetVariable (L"DisplayEnableScaledVModes", &gConfigDxeFormSetGuid, NULL, &Size, &Var8); if (EFI_ERROR (Status)) { Status = PcdSet8S (PcdDisplayEnableScaledVModes, PcdGet8 (PcdDisplayEnableScaledVModes)); ASSERT_EFI_ERROR (Status); } Size = sizeof (UINT32); Status = gRT->GetVariable (L"DisplayEnableSShot", &gConfigDxeFormSetGuid, NULL, &Size, &Var32); if (EFI_ERROR (Status)) { Status = PcdSet32S (PcdDisplayEnableSShot, PcdGet32 (PcdDisplayEnableSShot)); ASSERT_EFI_ERROR (Status); } if (mModelFamily == 4) { // // Get the MAC address from the firmware. // Status = mFwProtocol->GetMacAddress (mMacAddress.Addr); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_WARN, "%a: failed to retrieve MAC address\n", __FUNCTION__)); } } return EFI_SUCCESS; } STATIC VOID ApplyVariables ( VOID ) { UINTN Gpio34Group; UINTN Gpio48Group; EFI_STATUS Status; UINT32 CpuClock = PcdGet32 (PcdCpuClock); UINT32 CustomCpuClock = PcdGet32 (PcdCustomCpuClock); UINT32 Rate = 0; UINT32 FanOnGpio = PcdGet32 (PcdFanOnGpio); switch (CpuClock) { case CHIPSET_CPU_CLOCK_LOW: Rate = FixedPcdGet32 (PcdCpuLowSpeedMHz) * FREQ_1_MHZ; break; case CHIPSET_CPU_CLOCK_DEFAULT: /* * What the Raspberry Pi Foundation calls "max clock rate" is really the default value * from: https://www.raspberrypi.org/documentation/configuration/config-txt/overclocking.md */ Status = mFwProtocol->GetMaxClockRate (RPI_MBOX_CLOCK_RATE_ARM, &Rate); if (Status != EFI_SUCCESS) { DEBUG ((DEBUG_ERROR, "Couldn't read default CPU speed %r\n", Status)); } break; case CHIPSET_CPU_CLOCK_MAX: Rate = FixedPcdGet32 (PcdCpuMaxSpeedMHz) * FREQ_1_MHZ; break; case CHIPSET_CPU_CLOCK_CUSTOM: Rate = CustomCpuClock * FREQ_1_MHZ; break; } if (Rate != 0) { DEBUG ((DEBUG_INFO, "Setting CPU speed to %u MHz\n", Rate / FREQ_1_MHZ)); Status = mFwProtocol->SetClockRate (RPI_MBOX_CLOCK_RATE_ARM, Rate, 1); if (Status != EFI_SUCCESS) { DEBUG ((DEBUG_ERROR, "Couldn't set the CPU speed: %r\n", Status)); } else { Status = PcdSet32S (PcdCustomCpuClock, Rate / FREQ_1_MHZ); ASSERT_EFI_ERROR (Status); } } Status = mFwProtocol->GetClockRate (RPI_MBOX_CLOCK_RATE_ARM, &Rate); if (Status != EFI_SUCCESS) { DEBUG ((DEBUG_ERROR, "Couldn't get the CPU speed: %r\n", Status)); } else { DEBUG ((DEBUG_INFO, "Current CPU speed is %u MHz\n", Rate / FREQ_1_MHZ)); } if (mModelFamily >= 4 && PcdGet32 (PcdRamMoreThan3GB) != 0 && PcdGet32 (PcdRamLimitTo3GB) == 0) { UINT64 SystemMemorySize; UINT64 SystemMemorySizeBelow4GB; ASSERT (BCM2711_SOC_REGISTERS != 0); SystemMemorySize = (UINT64)mModelInstalledMB * SIZE_1MB; /* * Similar to how we compute the > 3 GB RAM segment's size in PlatformLib/ * RaspberryPiMem.c, with some overlap protection for the Bcm2xxx register * spaces. SystemMemorySizeBelow4GB tracks the maximum memory below 4GB * line, factoring in the limit imposed by the SoC register range. */ SystemMemorySizeBelow4GB = MIN (SystemMemorySize, 4UL * SIZE_1GB); SystemMemorySizeBelow4GB = MIN (SystemMemorySizeBelow4GB, BCM2836_SOC_REGISTERS); SystemMemorySizeBelow4GB = MIN (SystemMemorySizeBelow4GB, BCM2711_SOC_REGISTERS); ASSERT (SystemMemorySizeBelow4GB > 3UL * SIZE_1GB); Status = gDS->AddMemorySpace (EfiGcdMemoryTypeSystemMemory, 3UL * BASE_1GB, SystemMemorySizeBelow4GB - (3UL * SIZE_1GB), EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB); ASSERT_EFI_ERROR (Status); Status = gDS->SetMemorySpaceAttributes (3UL * BASE_1GB, SystemMemorySizeBelow4GB - (3UL * SIZE_1GB), EFI_MEMORY_WB); ASSERT_EFI_ERROR (Status); if (SystemMemorySize > 4UL * SIZE_1GB) { // // Register any memory above 4GB. // Status = gDS->AddMemorySpace (EfiGcdMemoryTypeSystemMemory, 4UL * BASE_1GB, SystemMemorySize - (4UL * SIZE_1GB), EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB); ASSERT_EFI_ERROR (Status); Status = gDS->SetMemorySpaceAttributes (4UL * BASE_1GB, SystemMemorySize - (4UL * SIZE_1GB), EFI_MEMORY_WB); ASSERT_EFI_ERROR (Status); } } if (mModelFamily == 3 || mModelFamily == 2) { /* * Pi 2B v1.2 / Pi 3: either Arasan or SdHost goes to SD card. * * Switching two groups around, so disable both first. * * No, I've not seen a problem, but having a group be * routed to two sets of pins seems like asking for trouble. */ GpioPinFuncSet (34, GPIO_FSEL_INPUT); GpioPinFuncSet (35, GPIO_FSEL_INPUT); GpioPinFuncSet (36, GPIO_FSEL_INPUT); GpioPinFuncSet (37, GPIO_FSEL_INPUT); GpioPinFuncSet (38, GPIO_FSEL_INPUT); GpioPinFuncSet (39, GPIO_FSEL_INPUT); GpioPinFuncSet (48, GPIO_FSEL_INPUT); GpioPinFuncSet (49, GPIO_FSEL_INPUT); GpioPinFuncSet (50, GPIO_FSEL_INPUT); GpioPinFuncSet (51, GPIO_FSEL_INPUT); GpioPinFuncSet (52, GPIO_FSEL_INPUT); GpioPinFuncSet (53, GPIO_FSEL_INPUT); if (PcdGet32 (PcdSdIsArasan)) { DEBUG ((DEBUG_INFO, "Routing SD to Arasan\n")); Gpio48Group = GPIO_FSEL_ALT3; /* * Route SDIO to SdHost. */ Gpio34Group = GPIO_FSEL_ALT0; } else { DEBUG ((DEBUG_INFO, "Routing SD to SdHost\n")); Gpio48Group = GPIO_FSEL_ALT0; /* * Route SDIO to Arasan. */ Gpio34Group = GPIO_FSEL_ALT3; } GpioPinFuncSet (34, Gpio34Group); GpioPinFuncSet (35, Gpio34Group); GpioPinFuncSet (36, Gpio34Group); GpioPinFuncSet (37, Gpio34Group); GpioPinFuncSet (38, Gpio34Group); GpioPinFuncSet (39, Gpio34Group); GpioPinFuncSet (48, Gpio48Group); GpioPinFuncSet (49, Gpio48Group); GpioPinFuncSet (50, Gpio48Group); GpioPinFuncSet (51, Gpio48Group); GpioPinFuncSet (52, Gpio48Group); GpioPinFuncSet (53, Gpio48Group); } else if (mModelFamily == 4) { /* * Pi 4: either Arasan or eMMC2 goes to SD card. */ if (PcdGet32 (PcdSdIsArasan)) { /* * WiFi disabled. */ GpioPinFuncSet (34, GPIO_FSEL_INPUT); GpioPinFuncSet (35, GPIO_FSEL_INPUT); GpioPinFuncSet (36, GPIO_FSEL_INPUT); GpioPinFuncSet (37, GPIO_FSEL_INPUT); GpioPinFuncSet (38, GPIO_FSEL_INPUT); GpioPinFuncSet (39, GPIO_FSEL_INPUT); /* * SD card pins go to Arasan. */ MmioOr32 (GPIO_BASE_ADDRESS + 0xD0, BIT1); } else { /* * SD card pins back to eMMC2. */ MmioAnd32 (GPIO_BASE_ADDRESS + 0xD0, ~BIT1); /* * WiFi back to Arasan. */ GpioPinFuncSet (34, GPIO_FSEL_ALT3); GpioPinFuncSet (35, GPIO_FSEL_ALT3); GpioPinFuncSet (36, GPIO_FSEL_ALT3); GpioPinFuncSet (37, GPIO_FSEL_ALT3); GpioPinFuncSet (38, GPIO_FSEL_ALT3); GpioPinFuncSet (39, GPIO_FSEL_ALT3); Status = mFwProtocol->SetPowerState (RPI_MBOX_POWER_STATE_SDHCI, TRUE, TRUE); //SD on with wait Status = mFwProtocol->SetGpioConfig (RPI_EXP_GPIO_SD_VOLT, RPI_EXP_GPIO_DIR_OUT, TRUE); //3.3v Status = mFwProtocol->SetClockState (RPI_MBOX_CLOCK_RATE_EMMC2, TRUE); Status = mFwProtocol->SetClockState (RPI_MBOX_CLOCK_RATE_EMMC, TRUE); } } else { DEBUG ((DEBUG_ERROR, "Model Family %d not supported...\n", mModelFamily)); } /* * JTAG pin JTAG sig GPIO Mode Header pin * 1 VREF N/A 1 * 3 nTRST GPIO22 ALT4 15 * 4 GND N/A 9 * 5 TDI GPIO26 ALT4 37 * 7 TMS GPIO27 ALT4 13 * 9 TCK GPIO25 ALT4 22 * 11 RTCK GPIO23 ALT4 16 * 13 TDO GPIO24 ALT4 18 */ if (PcdGet32 (PcdDebugEnableJTAG)) { GpioPinFuncSet (22, GPIO_FSEL_ALT4); GpioPinFuncSet (26, GPIO_FSEL_ALT4); GpioPinFuncSet (27, GPIO_FSEL_ALT4); GpioPinFuncSet (25, GPIO_FSEL_ALT4); GpioPinFuncSet (23, GPIO_FSEL_ALT4); GpioPinFuncSet (24, GPIO_FSEL_ALT4); } else { GpioPinFuncSet (22, GPIO_FSEL_INPUT); GpioPinFuncSet (26, GPIO_FSEL_INPUT); GpioPinFuncSet (27, GPIO_FSEL_INPUT); GpioPinFuncSet (25, GPIO_FSEL_INPUT); GpioPinFuncSet (23, GPIO_FSEL_INPUT); GpioPinFuncSet (24, GPIO_FSEL_INPUT); } if (FanOnGpio) { DEBUG ((DEBUG_INFO, "Fan enabled on GPIO %d\n", FanOnGpio)); GpioPinFuncSet (FanOnGpio, GPIO_FSEL_OUTPUT); } // // Fake the CTS signal as we don't support HW flow control yet. // Pin 31 must be held LOW so that we can talk to the BT chip // without flow control // GpioPinFuncSet (31, GPIO_FSEL_OUTPUT); GpioPinConfigure (31, CLEAR_GPIO); // // Bluetooth pin muxing // if ((PcdGet32 (PcdUartInUse) == PL011_UART_IN_USE)) { DEBUG ((DEBUG_INFO, "Enable Bluetooth over MiniUART\n")); GpioPinFuncSet (32, GPIO_FSEL_ALT5); GpioPinFuncSet (33, GPIO_FSEL_ALT5); } else { DEBUG ((DEBUG_INFO, "Enable Bluetooth over PL011 UART\n")); GpioPinFuncSet (32, GPIO_FSEL_ALT3); GpioPinFuncSet (33, GPIO_FSEL_ALT3); } } typedef struct { CHAR8 Name[4]; UINTN PcdToken; } AML_NAME_OP_REPLACE; typedef struct { UINT64 OemTableId; UINTN PcdToken; UINTN PcdTokenNot; CONST AML_NAME_OP_REPLACE *SdtNameOpReplace; } NAMESPACE_TABLES; #define SSDT_PATTERN_LEN 5 #define AML_NAMEOP_8 0x0A #define AML_NAMEOP_16 0x0B #define AML_NAMEOP_32 0x0C #define AML_NAMEOP_STR 0x0D // // Scan the given namespace table (DSDT/SSDT) for AML NameOps // listed in the NameOpReplace structure. If one is found then // update the value in the table from the specified Pcd // // This allows us to have conditionals in AML controlled // by options in the BDS or detected during firmware bootstrap. // We could extend this concept for strings/etc but due to len // variations its probably easier to encode the strings // in the ASL and pick the correct one based off a variable. // STATIC VOID UpdateSdtNameOps ( EFI_ACPI_DESCRIPTION_HEADER *AcpiTable, CONST AML_NAME_OP_REPLACE *NameOpReplace ) { UINTN Idx; UINTN Index; CHAR8 Pattern[SSDT_PATTERN_LEN]; UINTN PcdVal; UINT8 *SdtPtr; UINT32 SdtSize; SdtSize = AcpiTable->Length; if (SdtSize > 0) { SdtPtr = (UINT8 *)AcpiTable; for (Idx = 0; NameOpReplace && NameOpReplace[Idx].PcdToken; Idx++) { // // Do a single NameOp variable replacement these are of the // form 08 XXXX SIZE VAL, where SIZE is 0A=byte, 0B=word, 0C=dword // and XXXX is the name and VAL is the value // Pattern[0] = 0x08; Pattern[1] = NameOpReplace[Idx].Name[0]; Pattern[2] = NameOpReplace[Idx].Name[1]; Pattern[3] = NameOpReplace[Idx].Name[2]; Pattern[4] = NameOpReplace[Idx].Name[3]; for (Index = 0; Index < (SdtSize - SSDT_PATTERN_LEN); Index++) { if (CompareMem (SdtPtr + Index, Pattern, SSDT_PATTERN_LEN) == 0) { PcdVal = LibPcdGet32 (NameOpReplace[Idx].PcdToken); switch (SdtPtr[Index + SSDT_PATTERN_LEN]) { case AML_NAMEOP_32: SdtPtr[Index + SSDT_PATTERN_LEN + 4] = (PcdVal >> 24) & 0xFF; SdtPtr[Index + SSDT_PATTERN_LEN + 3] = (PcdVal >> 16) & 0xFF; // Fallthrough case AML_NAMEOP_16: SdtPtr[Index + SSDT_PATTERN_LEN + 2] = (PcdVal >> 8) & 0xFF; // Fallthrough case AML_NAMEOP_8: SdtPtr[Index + SSDT_PATTERN_LEN + 1] = PcdVal & 0xFF; break; case 0: case 1: SdtPtr[Index + SSDT_PATTERN_LEN + 1] = !!PcdVal; break; case AML_NAMEOP_STR: // // If the string val is added to the NameOpReplace, we can // dynamically update things like _HID too as long as the // string length matches. // break; } break; } } } } } STATIC BOOLEAN VerifyUpdateTable ( IN EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader, IN CONST NAMESPACE_TABLES *SdtTable ) { BOOLEAN Result; Result = TRUE; if (SdtTable->PcdToken && !LibPcdGet32 (SdtTable->PcdToken)) { Result = FALSE; } if (SdtTable->PcdTokenNot && LibPcdGet32 (SdtTable->PcdTokenNot)) { Result = FALSE; } if (Result && SdtTable->SdtNameOpReplace) { UpdateSdtNameOps (AcpiHeader, SdtTable->SdtNameOpReplace); } return Result; } STATIC CONST AML_NAME_OP_REPLACE SsdtNameOpReplace[] = { { "GIOP", PcdToken (PcdFanOnGpio) }, { "FTMP", PcdToken (PcdFanTemp) }, { } }; STATIC CONST AML_NAME_OP_REPLACE SsdtEmmcNameOpReplace[] = { { "SDMA", PcdToken (PcdMmcEnableDma) }, { } }; STATIC CONST AML_NAME_OP_REPLACE DsdtNameOpReplace[] = { { "URIU", PcdToken (PcdUartInUse) }, { } }; STATIC CONST NAMESPACE_TABLES SdtTables[] = { { SIGNATURE_64 ('R', 'P', 'I', 'T', 'H', 'F', 'A', 'N'), PcdToken(PcdFanOnGpio), 0, SsdtNameOpReplace }, { SIGNATURE_64 ('R', 'P', 'I', '4', 'E', 'M', 'M', 'C'), 0, PcdToken(PcdSdIsArasan), SsdtEmmcNameOpReplace }, #if (RPI_MODEL == 4) { SIGNATURE_64 ('R', 'P', 'I', '4', 'X', 'H', 'C', 'I'), 0, PcdToken(PcdXhciPci), NULL }, { SIGNATURE_64 ('R', 'P', 'I', '4', 'P', 'C', 'I', 'E'), PcdToken(PcdXhciPci), 0, NULL }, #endif { // DSDT SIGNATURE_64 ('R', 'P', 'I', 0, 0, 0, 0, 0), 0, 0, DsdtNameOpReplace }, { } }; // // Monitor the ACPI tables being installed and when // a DSDT/SSDT is detected validate that we want to // install it, and if so update any "NameOp" defined // variables contained in the table from PCD values // STATIC BOOLEAN HandleDynamicNamespace ( IN EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader ) { UINTN Tables; EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE *SpcrTable; DBG2_TABLE *Dbg2Table; switch (AcpiHeader->Signature) { case SIGNATURE_32 ('D', 'S', 'D', 'T'): case SIGNATURE_32 ('S', 'S', 'D', 'T'): for (Tables = 0; SdtTables[Tables].OemTableId; Tables++) { if (AcpiHeader->OemTableId == SdtTables[Tables].OemTableId) { return VerifyUpdateTable (AcpiHeader, &SdtTables[Tables]); } } DEBUG ((DEBUG_ERROR, "Found namespace table not in table list.\n")); return FALSE; case SIGNATURE_32 ('I', 'O', 'R', 'T'): // only enable the IORT on machines with >3G and no limit // to avoid problems with rhel/centos and other older OSs if (PcdGet32 (PcdRamLimitTo3GB) || !PcdGet32 (PcdRamMoreThan3GB)) { return FALSE; } return TRUE; case SIGNATURE_32 ('S', 'P', 'C', 'R'): SpcrTable = (EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE *)AcpiHeader; if ((PcdGet32 (PcdUartInUse) == PL011_UART_IN_USE) && (SpcrTable->InterfaceType == EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_ARM_PL011_UART)) { return TRUE; } else if ((PcdGet32 (PcdUartInUse) == MINI_UART_IN_USE) && (SpcrTable->InterfaceType == EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_BCM2835_UART)) { return TRUE; } return FALSE; case SIGNATURE_32 ('D', 'B', 'G', '2'): Dbg2Table = (DBG2_TABLE *)AcpiHeader; if ((PcdGet32 (PcdUartInUse) == PL011_UART_IN_USE) && (Dbg2Table->Dbg2DeviceInfo[0].Dbg2Device.PortSubtype == EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_PL011_UART)) { return TRUE; } else if ((PcdGet32 (PcdUartInUse) == MINI_UART_IN_USE) && (Dbg2Table->Dbg2DeviceInfo[0].Dbg2Device.PortSubtype == EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_BCM2835_UART)) { return TRUE; } return FALSE; } return TRUE; } EFI_STATUS EFIAPI ConfigInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_EVENT EndOfDxeEvent; if ((MmioRead32(GPIO_GPFSEL1) & GPFSEL1_UART_MASK) == PL011_UART_IN_USE_REG_VALUE) { PcdSet32S (PcdUartInUse, PL011_UART_IN_USE); } else if ((MmioRead32(GPIO_GPFSEL1) & GPFSEL1_UART_MASK) == MINI_UART_IN_USE_REG_VALUE) { PcdSet32S (PcdUartInUse, MINI_UART_IN_USE); } Status = gBS->LocateProtocol (&gRaspberryPiFirmwareProtocolGuid, NULL, (VOID**)&mFwProtocol); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } Status = mFwProtocol->GetModelFamily (&mModelFamily); if (Status != EFI_SUCCESS) { DEBUG ((DEBUG_ERROR, "Couldn't get the Raspberry Pi model family: %r\n", Status)); } else { DEBUG ((DEBUG_INFO, "Current Raspberry Pi model family is %d\n", mModelFamily)); } Status = mFwProtocol->GetModelInstalledMB (&mModelInstalledMB); if (Status != EFI_SUCCESS) { DEBUG ((DEBUG_ERROR, "Couldn't get the Raspberry Pi installed RAM size: %r\n", Status)); } else { DEBUG ((DEBUG_INFO, "Current Raspberry Pi installed RAM size is %d MB\n", mModelInstalledMB)); } Status = mFwProtocol->GetModelRevision (&mModelRevision); if (Status != EFI_SUCCESS) { DEBUG ((DEBUG_ERROR, "Couldn't get the Raspberry Pi revision: %r\n", Status)); } else { DEBUG ((DEBUG_INFO, "Current Raspberry Pi revision %x\n", mModelRevision)); } Status = SetupVariables (); if (Status != EFI_SUCCESS) { DEBUG ((DEBUG_ERROR, "Couldn't not setup NV vars: %r\n", Status)); } ApplyVariables (); Status = gBS->InstallProtocolInterface (&ImageHandle, &gRaspberryPiConfigAppliedProtocolGuid, EFI_NATIVE_INTERFACE, NULL); ASSERT_EFI_ERROR (Status); Status = InstallHiiPages (); if (Status != EFI_SUCCESS) { DEBUG ((DEBUG_ERROR, "Couldn't install ConfigDxe configuration pages: %r\n", Status)); } if (PcdGet32 (PcdSystemTableMode) == SYSTEM_TABLE_MODE_ACPI || PcdGet32 (PcdSystemTableMode) == SYSTEM_TABLE_MODE_BOTH) { Status = LocateAndInstallAcpiFromFvConditional (&mAcpiTableFile, &HandleDynamicNamespace); ASSERT_EFI_ERROR (Status); } Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, RegisterDevices, NULL, &gEfiEndOfDxeEventGroupGuid, &EndOfDxeEvent); ASSERT_EFI_ERROR (Status); if (mModelFamily == 4) { RegisterXhciQuirkHandler (mFwProtocol); } return EFI_SUCCESS; }