/** @file
|
SynQuacer DXE platform driver.
|
|
Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
|
|
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;
|
}
|