/** @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); }