/** @file
|
96boards Secure96 mezzanine board DXE driver.
|
|
Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
**/
|
|
#include <PiDxe.h>
|
#include <libfdt.h>
|
#include <Library/BaseLib.h>
|
#include <Library/DebugLib.h>
|
#include <Library/DxeServicesLib.h>
|
#include <Library/UefiBootServicesTableLib.h>
|
#include <Library/UefiLib.h>
|
#include <Protocol/LsConnector.h>
|
#include <Protocol/Mezzanine.h>
|
|
#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);
|
}
|