/** @file SynQuacer DXE platform driver. Copyright (c) 2017, Linaro, Ltd. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "PlatformDxe.h" UINT64 mHiiSettingsVal; SYNQUACER_PLATFORM_VARSTORE_DATA *mHiiSettings; #pragma pack (1) typedef struct { MAC_ADDR_DEVICE_PATH MacAddrDevicePath; EFI_DEVICE_PATH_PROTOCOL End; } NETSEC_DEVICE_PATH; typedef struct { NETSEC_DEVICE_PATH DevicePath; NON_DISCOVERABLE_DEVICE NonDiscoverableDevice; } NETSEC_DEVICE; #pragma pack () typedef struct { VENDOR_DEVICE_PATH VendorDevicePath; EFI_DEVICE_PATH_PROTOCOL End; } HII_VENDOR_DEVICE_PATH; STATIC HII_VENDOR_DEVICE_PATH mPlatformDxeHiiVendorDevicePath = { { { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { (UINT8) (sizeof (VENDOR_DEVICE_PATH)), (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) } }, SYNQUACER_PLATFORM_FORMSET_GUID }, { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { (UINT8) (END_DEVICE_PATH_LENGTH), (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) } } }; STATIC EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR mNetsecDesc[] = { { ACPI_ADDRESS_SPACE_DESCRIPTOR, // Desc sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3, // Len ACPI_ADDRESS_SPACE_TYPE_MEM, // ResType 0, // GenFlag 0, // SpecificFlag 32, // AddrSpaceGranularity SYNQUACER_NETSEC1_BASE, // AddrRangeMin SYNQUACER_NETSEC1_BASE + SYNQUACER_NETSEC1_BASE_SZ - 1, // AddrRangeMax 0, // AddrTranslationOffset SYNQUACER_NETSEC1_BASE_SZ, // AddrLen }, { ACPI_ADDRESS_SPACE_DESCRIPTOR, // Desc sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3, // Len ACPI_ADDRESS_SPACE_TYPE_MEM, // ResType 0, // GenFlag 0, // SpecificFlag 32, // AddrSpaceGranularity FixedPcdGet32 (PcdNetsecEepromBase), // AddrRangeMin FixedPcdGet32 (PcdNetsecEepromBase) + SYNQUACER_EEPROM_BASE_SZ - 1, // AddrRangeMax 0, // AddrTranslationOffset SYNQUACER_EEPROM_BASE_SZ, // AddrLen }, { ACPI_ADDRESS_SPACE_DESCRIPTOR, // Desc sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3, // Len ACPI_ADDRESS_SPACE_TYPE_MEM, // ResType 0, // GenFlag 0, // SpecificFlag 32, // AddrSpaceGranularity FixedPcdGet32 (PcdNetsecPhyAddress), // AddrRangeMin FixedPcdGet32 (PcdNetsecPhyAddress), // AddrRangeMax 0, // AddrTranslationOffset 1, // AddrLen }, { ACPI_END_TAG_DESCRIPTOR // Desc } }; STATIC EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR mI2c0Desc[] = { { ACPI_ADDRESS_SPACE_DESCRIPTOR, // Desc sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3, // Len ACPI_ADDRESS_SPACE_TYPE_MEM, // ResType 0, // GenFlag 0, // SpecificFlag 32, // AddrSpaceGranularity SYNQUACER_I2C0_BASE, // AddrRangeMin SYNQUACER_I2C0_BASE + SYNQUACER_I2C0_SIZE - 1, // AddrRangeMax 0, // AddrTranslationOffset SYNQUACER_I2C0_SIZE, // AddrLen }, { ACPI_END_TAG_DESCRIPTOR // Desc } }; STATIC EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR mI2c1Desc[] = { { ACPI_ADDRESS_SPACE_DESCRIPTOR, // Desc sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3, // Len ACPI_ADDRESS_SPACE_TYPE_MEM, // ResType 0, // GenFlag 0, // SpecificFlag 32, // AddrSpaceGranularity SYNQUACER_I2C1_BASE, // AddrRangeMin SYNQUACER_I2C1_BASE + SYNQUACER_I2C1_SIZE - 1, // AddrRangeMax 0, // AddrTranslationOffset SYNQUACER_I2C1_SIZE, // AddrLen }, { ACPI_END_TAG_DESCRIPTOR // Desc } }; STATIC NETSEC_DEVICE mNetsecDevice = { { { { MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, { sizeof (MAC_ADDR_DEVICE_PATH), 0 }, }, {}, NET_IFTYPE_ETHERNET, }, { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } } }, { &gNetsecNonDiscoverableDeviceGuid, NonDiscoverableDeviceDmaTypeCoherent, NULL, mNetsecDesc } }; STATIC EFI_ACPI_DESCRIPTION_HEADER *mEmmcSsdt; STATIC UINTN mEmmcSsdtSize; STATIC EFI_ACPI_DESCRIPTION_HEADER *mTos0Ssdt; STATIC UINTN mTos0SsdtSize; STATIC VOID *mAcpiTableEventRegistration; STATIC EFI_STATUS RegisterDevice ( IN EFI_GUID *TypeGuid, IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc, OUT EFI_HANDLE *Handle ) { NON_DISCOVERABLE_DEVICE *Device; EFI_STATUS Status; Device = (NON_DISCOVERABLE_DEVICE *)AllocateZeroPool (sizeof (*Device)); if (Device == NULL) { return EFI_OUT_OF_RESOURCES; } Device->Type = TypeGuid; Device->DmaType = NonDiscoverableDeviceDmaTypeCoherent; Device->Resources = Desc; Status = gBS->InstallMultipleProtocolInterfaces (Handle, &gEdkiiNonDiscoverableDeviceProtocolGuid, Device, NULL); if (EFI_ERROR (Status)) { goto FreeDevice; } return EFI_SUCCESS; FreeDevice: FreePool (Device); return Status; } #define SMMU_SCR0 0x0 #define SMMU_SCR0_SHCFG_INNER (0x2 << 22) #define SMMU_SCR0_MTCFG (0x1 << 20) #define SMMU_SCR0_MEMATTR_INNER_OUTER_WB (0xf << 16) STATIC VOID SmmuEnableCoherentDma ( VOID ) { // // The SCB SMMU (MMU-500) is shared between the NETSEC and eMMC devices, and // is configured in passthrough mode by default. Let's set the global memory // type override as well, so that all memory accesses by these devices are // inner shareable inner/outer writeback cacheable. // MmioOr32 (SYNQUACER_SCB_SMMU_BASE + SMMU_SCR0, SMMU_SCR0_SHCFG_INNER | SMMU_SCR0_MTCFG | SMMU_SCR0_MEMATTR_INNER_OUTER_WB); } #define MMIO_TIMER_CNTFRQ_OFFSET 0x10 STATIC VOID SetMmioTimerFrequency ( VOID ) { // // Initialize the CNTFRQ field of the first non-secure MMIO timer frame. // This field should be a read-only alias of the global frequency register // but in reality, it is a separate field that needs to be set explicitly. // MmioWrite32 (SYNQUACER_MMIO_TIMER_CNT_BASE0 + MMIO_TIMER_CNTFRQ_OFFSET, ArmGenericTimerGetTimerFreq ()); } STATIC EFI_STATUS InstallHiiPages ( VOID ) { EFI_STATUS Status; EFI_HII_HANDLE HiiHandle; EFI_HANDLE DriverHandle; DriverHandle = NULL; Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle, &gEfiDevicePathProtocolGuid, &mPlatformDxeHiiVendorDevicePath, NULL); if (EFI_ERROR (Status)) { return Status; } HiiHandle = HiiAddPackages (&gSynQuacerPlatformFormSetGuid, DriverHandle, PlatformDxeStrings, PlatformDxeHiiBin, NULL); if (HiiHandle == NULL) { gBS->UninstallMultipleProtocolInterfaces (DriverHandle, &gEfiDevicePathProtocolGuid, &mPlatformDxeHiiVendorDevicePath, NULL); return EFI_OUT_OF_RESOURCES; } return EFI_SUCCESS; } STATIC EFI_STATUS EnableSettingsForm ( VOID ) { EFI_STATUS Status; UINTN VarSize; SYNQUACER_PLATFORM_VARSTORE_DATA Settings; VarSize = sizeof (Settings); Status = gRT->GetVariable (SYNQUACER_PLATFORM_VARIABLE_NAME, &gSynQuacerPlatformFormSetGuid, NULL, &VarSize, &Settings); if (Status == EFI_NOT_FOUND) { // // Variable does not exist yet - create it // SetMem (&Settings, sizeof (Settings), 0); Status = gRT->SetVariable (SYNQUACER_PLATFORM_VARIABLE_NAME, &gSynQuacerPlatformFormSetGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, sizeof (Settings), &Settings); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_WARN, "%a: EfiSetVariable failed - %r\n", __FUNCTION__, Status)); return Status; } } else if (EFI_ERROR (Status)) { DEBUG ((DEBUG_WARN, "%a: EfiGetVariable failed - %r\n", __FUNCTION__, Status)); return Status; } return InstallHiiPages (); } STATIC VOID EFIAPI InstallAcpiTables ( IN EFI_EVENT Event, IN VOID* Context ) { UINTN TableKey; EFI_STATUS Status; EFI_ACPI_TABLE_PROTOCOL *AcpiTable; Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable); if (EFI_ERROR (Status)) { return; } if (mEmmcSsdtSize > 0) { Status = AcpiTable->InstallAcpiTable (AcpiTable, mEmmcSsdt, mEmmcSsdtSize, &TableKey); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_WARN, "%a: failed to install SSDT table for eMMC - %r\n", __FUNCTION__, Status)); } } if (mTos0SsdtSize > 0) { Status = AcpiTable->InstallAcpiTable (AcpiTable, mTos0Ssdt, mTos0SsdtSize, &TableKey); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_WARN, "%a: failed to install SSDT table for OP-TEE - %r\n", __FUNCTION__, Status)); } } } STATIC VOID NetsecReadMacAddress ( OUT EFI_MAC_ADDRESS *MacAddress ) { MacAddress->Addr[0] = MmioRead8 (FixedPcdGet32 (PcdNetsecEepromBase) + 3); MacAddress->Addr[1] = MmioRead8 (FixedPcdGet32 (PcdNetsecEepromBase) + 2); MacAddress->Addr[2] = MmioRead8 (FixedPcdGet32 (PcdNetsecEepromBase) + 1); MacAddress->Addr[3] = MmioRead8 (FixedPcdGet32 (PcdNetsecEepromBase) + 0); MacAddress->Addr[4] = MmioRead8 (FixedPcdGet32 (PcdNetsecEepromBase) + 7); MacAddress->Addr[5] = MmioRead8 (FixedPcdGet32 (PcdNetsecEepromBase) + 6); } STATIC VOID EFIAPI RegisterDevices ( EFI_EVENT Event, VOID *Context ) { EFI_HANDLE Handle; EFI_STATUS Status; NetsecReadMacAddress (&mNetsecDevice.DevicePath.MacAddrDevicePath.MacAddress); Handle = NULL; Status = gBS->InstallMultipleProtocolInterfaces (&Handle, &gEfiDevicePathProtocolGuid, &mNetsecDevice.DevicePath, &gEdkiiNonDiscoverableDeviceProtocolGuid, &mNetsecDevice.NonDiscoverableDevice, NULL); ASSERT_EFI_ERROR (Status); if (mHiiSettings->EnableEmmc == EMMC_ENABLED) { Status = RegisterEmmc (); ASSERT_EFI_ERROR (Status); } } EFI_STATUS EFIAPI PlatformDxeEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; VOID *Dtb; UINTN DtbSize; EFI_HANDLE Handle; EFI_ACPI_DESCRIPTION_HEADER *Ssdt; UINTN SsdtSize; UINTN Index; EFI_EVENT EndOfDxeEvent; mHiiSettingsVal = PcdGet64 (PcdPlatformSettings); mHiiSettings = (SYNQUACER_PLATFORM_VARSTORE_DATA *)&mHiiSettingsVal; if (mHiiSettings->AcpiPref == ACPIPREF_DT) { Dtb = NULL; Status = DtPlatformLoadDtb (&Dtb, &DtbSize); if (!EFI_ERROR (Status)) { Status = gBS->InstallConfigurationTable (&gFdtTableGuid, Dtb); } if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: failed to install FDT configuration table - %r\n", __FUNCTION__, Status)); } } else { // // ACPI was selected: install the gEdkiiPlatformHasAcpiGuid GUID as a // NULL protocol to unlock dispatch of ACPI related drivers. // Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle, &gEdkiiPlatformHasAcpiGuid, NULL, NULL); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: failed to install gEdkiiPlatformHasAcpiGuid as a protocol\n", __FUNCTION__)); } } Handle = NULL; Status = RegisterDevice (&gSynQuacerNonDiscoverableRuntimeI2cMasterGuid, mI2c0Desc, &Handle); ASSERT_EFI_ERROR (Status); // // Install the PCF8563 I2C Master protocol on this handle so the RTC driver // can identify it as the I2C master it can invoke directly, rather than // through the I2C driver stack (which cannot be used at runtime) // Status = gBS->InstallProtocolInterface (&Handle, &gPcf8563RealTimeClockLibI2cMasterProtocolGuid, EFI_NATIVE_INTERFACE, NULL); ASSERT_EFI_ERROR (Status); Handle = NULL; Status = RegisterDevice (&gSynQuacerNonDiscoverableI2cMasterGuid, mI2c1Desc, &Handle); ASSERT_EFI_ERROR (Status); // // Install the g96BoardsI2c0MasterGuid GUID onto the same handle, // identifying I2C #1 on our SoC as I2C #0 on the 96boards low speed connector // Status = gBS->InstallProtocolInterface (&Handle, &g96BoardsI2c0MasterGuid, EFI_NATIVE_INTERFACE, NULL); ASSERT_EFI_ERROR (Status); SmmuEnableCoherentDma (); SetMmioTimerFrequency (); Status = RegisterPcieNotifier (); ASSERT_EFI_ERROR (Status); Status = EnableSettingsForm (); ASSERT_EFI_ERROR (Status); if (mHiiSettings->AcpiPref == ACPIPREF_ACPI) { // // Load the SSDT tables from a raw section in this FFS file. // for (Index = 0;; Index++) { Status = GetSectionFromFv (&gEfiCallerIdGuid, EFI_SECTION_RAW, Index, (VOID **)&Ssdt, &SsdtSize); if (EFI_ERROR (Status)) { break; } switch (Ssdt->OemTableId) { case EMMC_TABLE_ID: if (mHiiSettings->EnableEmmc != EMMC_ENABLED) { break; } mEmmcSsdt = Ssdt; mEmmcSsdtSize = SsdtSize; break; case TOS0_TABLE_ID: if (!IsOpteePresent ()) { break; } mTos0Ssdt = Ssdt; mTos0SsdtSize = SsdtSize; break; } } if (mEmmcSsdtSize > 0 || mTos0SsdtSize > 0) { // // Register for the ACPI table protocol if we found any SSDTs to install // EfiCreateProtocolNotifyEvent (&gEfiAcpiTableProtocolGuid, TPL_CALLBACK, InstallAcpiTables, NULL, &mAcpiTableEventRegistration); } } Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, RegisterDevices, NULL, &gEfiEndOfDxeEventGroupGuid, &EndOfDxeEvent); ASSERT_EFI_ERROR (Status); return EFI_SUCCESS; }