/** @file
96boards Secure96 mezzanine board DXE driver.
Copyright (c) 2018, Linaro, Ltd. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "Secure96.h"
#define SECURE96_SSDT_OEM_TABLE_ID SIGNATURE_64('S','E','C','U','R','E','9','6')
STATIC CONST UINT32 mI2cAtmelSha204aSlaveAddress[] = {
ATSHA204A_SLAVE_ADDRESS,
//
// The Atmel AtSha204a has an annoying 'wake' mode where it will only wake
// up if SDA is held low for a certain amount of time. Attempting to access
// a device at address 0x0 at 100 kHz should be sufficient to create this
// wake condition, so add address 0x0 to the slave addresses.
//
0
};
STATIC CONST EFI_I2C_DEVICE mI2c0Devices[] = {
{
&gAtSha204aI2cDeviceGuid, // DeviceGuid
0, // DeviceIndex
0, // HardwareRevision
0, // I2C bus configuration
ARRAY_SIZE (mI2cAtmelSha204aSlaveAddress), // SlaveAddressCount
mI2cAtmelSha204aSlaveAddress // SlaveAddressArray
}
};
STATIC CONST CHAR8 mLedNodes[][46] = {
"/fragment@2/__overlay__/gpio-leds/secure96-u1",
"/fragment@2/__overlay__/gpio-leds/secure96-u2",
"/fragment@2/__overlay__/gpio-leds/secure96-u3",
"/fragment@2/__overlay__/gpio-leds/secure96-u4",
};
STATIC
VOID
SetOverlayFragmentTarget (
VOID *Overlay,
CONST CHAR8 *NodeName,
CONST CHAR8 *Target
)
{
INT32 Node;
INT32 Err;
Node = fdt_path_offset (Overlay, NodeName);
ASSERT (Node > 0);
Err = fdt_setprop (Overlay, Node, "target-path", Target,
AsciiStrLen (Target) + 1);
if (Err) {
DEBUG ((DEBUG_ERROR, "%a: fdt_setprop() failed - %a\n",
__FUNCTION__, fdt_strerror (Err)));
}
}
STATIC
VOID
FixupOverlay (
VOID *Dtb,
VOID *Overlay
)
{
INT32 Node;
UINT32 GpioPhandle;
UINTN Idx;
UINT32 *GpioProp;
INT32 Err;
//
// Set the correct GPIO phandle in the LED nodes
//
Node = fdt_path_offset (Dtb, FixedPcdGetPtr (PcdGpioParent));
ASSERT (Node > 0);
GpioPhandle = fdt_get_phandle (Dtb, Node);
if (!GpioPhandle) {
//
// Node has no phandle yet -> create one
//
GpioPhandle = 1 + fdt_get_max_phandle (Dtb);
ASSERT (GpioPhandle >= 1);
Err = fdt_setprop_u32 (Dtb, Node, "phandle", GpioPhandle);
if (Err) {
DEBUG ((DEBUG_ERROR,
"%a: fdt_setprop_u32(.., .., \"phandle\", 0x%x) failed - %a\n",
__FUNCTION__, GpioPhandle, fdt_strerror (Err)));
}
}
for (Idx = 0; Idx < ARRAY_SIZE (mLedNodes); Idx++) {
Node = fdt_path_offset (Overlay, mLedNodes[Idx]);
ASSERT (Node > 0);
GpioProp = fdt_getprop_w (Overlay, Node, "gpios", NULL);
ASSERT (GpioProp != NULL);
*GpioProp = cpu_to_fdt32 (GpioPhandle);
}
SetOverlayFragmentTarget (Overlay, "/fragment@0",
FixedPcdGetPtr (PcdI2c0Parent));
SetOverlayFragmentTarget (Overlay, "/fragment@1",
FixedPcdGetPtr (PcdSpiParent));
}
/**
Apply the mezzanine's DT overlay
@param[in] This Pointer to the MEZZANINE_PROTOCOL instance.
@param[in,out] Dtb Pointer to the device tree blob
@return EFI_SUCCESS Operation succeeded.
@return other An error has occurred.
**/
STATIC
EFI_STATUS
ApplyDeviceTreeOverlay (
IN MEZZANINE_PROTOCOL *This,
IN OUT VOID *Dtb
)
{
VOID *Overlay;
UINTN OverlaySize;
EFI_STATUS Status;
INT32 Err;
UINTN Index;
//
// Load the raw overlay DTB image from the raw section of this FFS file.
//
for (Index = 0;; Index++) {
Status = GetSectionFromFv (&gEfiCallerIdGuid,
EFI_SECTION_RAW, Index, &Overlay, &OverlaySize);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
if (!fdt_check_header (Overlay)) {
break;
}
}
//
// Fix up unresolved references in the overlay.
//
FixupOverlay (Dtb, Overlay);
//
// Merge the overlay with the DTB
//
Err = fdt_overlay_apply (Dtb, Overlay);
if (Err) {
DEBUG ((DEBUG_ERROR, "%a: fdt_overlay_apply() failed - %a\n",
__FUNCTION__, fdt_strerror (Err)));
return EFI_NOT_FOUND;
}
return EFI_SUCCESS;
}
/**
Install the mezzanine's SSDT table
@param[in] This Pointer to the MEZZANINE_PROTOCOL instance.
@param[in] Dtb Pointer to the device tree blob
@return EFI_SUCCESS Operation succeeded.
@return other An error has occurred.
**/
STATIC
EFI_STATUS
EFIAPI
InstallSsdtTable (
IN MEZZANINE_PROTOCOL *This,
IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol
)
{
EFI_ACPI_DESCRIPTION_HEADER *Ssdt;
UINTN SsdtSize;
EFI_STATUS Status;
UINTN Index;
UINTN TableKey;
//
// Load SSDT table from the raw section of this FFS file.
//
for (Index = 0;; Index++) {
Status = GetSectionFromFv (&gEfiCallerIdGuid, EFI_SECTION_RAW, Index,
(VOID **)&Ssdt, &SsdtSize);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
if (SsdtSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER) &&
Ssdt->OemTableId == SECURE96_SSDT_OEM_TABLE_ID) {
break;
}
}
return AcpiProtocol->InstallAcpiTable (AcpiProtocol, Ssdt, SsdtSize,
&TableKey);
}
STATIC MEZZANINE_PROTOCOL mMezzanine = {
ApplyDeviceTreeOverlay,
InstallSsdtTable,
ARRAY_SIZE (mI2c0Devices),
0,
mI2c0Devices,
NULL,
NULL,
};
EFI_STATUS
EFIAPI
Secure96DxeEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
LS_CONNECTOR_PROTOCOL *LsConnector;
Status = gBS->LocateProtocol (&g96BoardsLsConnectorProtocolGuid, NULL,
(VOID **)&LsConnector);
ASSERT_EFI_ERROR (Status);
if (LsConnector->MezzanineType != MezzanineSecure96) {
return EFI_NOT_FOUND;
}
return gBS->InstallProtocolInterface (&ImageHandle,
&g96BoardsMezzanineProtocolGuid,
EFI_NATIVE_INTERFACE,
&mMezzanine);
}