|
@@ -0,0 +1,433 @@
|
|
|
+/** @file
|
|
|
+ Platform PEI driver
|
|
|
+
|
|
|
+ Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
|
|
|
+
|
|
|
+ SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
+
|
|
|
+ @par Glossary:
|
|
|
+ - Mem - Memory
|
|
|
+**/
|
|
|
+
|
|
|
+//
|
|
|
+// The package level header files this module uses
|
|
|
+//
|
|
|
+#include <PiPei.h>
|
|
|
+//
|
|
|
+// The Library classes this module consumes
|
|
|
+//
|
|
|
+#include <Library/DebugLib.h>
|
|
|
+#include <Library/HobLib.h>
|
|
|
+#include <Library/IoLib.h>
|
|
|
+#include <Library/MemoryAllocationLib.h>
|
|
|
+#include <Library/BaseMemoryLib.h>
|
|
|
+#include <Library/PcdLib.h>
|
|
|
+#include <Library/PeimEntryPoint.h>
|
|
|
+#include <Library/PeiServicesLib.h>
|
|
|
+#include <Library/ResourcePublicationLib.h>
|
|
|
+#include <Guid/MemoryTypeInformation.h>
|
|
|
+#include <Library/QemuFwCfgLib.h>
|
|
|
+#include <Library/MmuLib.h>
|
|
|
+#include <Guid/FdtHob.h>
|
|
|
+#include <libfdt.h>
|
|
|
+#include <Ppi/MasterBootMode.h>
|
|
|
+
|
|
|
+#include "Platform.h"
|
|
|
+
|
|
|
+/* TODO */
|
|
|
+EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = {
|
|
|
+ { EfiReservedMemoryType, 0x004 },
|
|
|
+ { EfiRuntimeServicesData, 0x024 },
|
|
|
+ { EfiRuntimeServicesCode, 0x030 },
|
|
|
+ { EfiBootServicesCode, 0x180 },
|
|
|
+ { EfiBootServicesData, 0xF00 },
|
|
|
+ { EfiMaxMemoryType, 0x000 }
|
|
|
+};
|
|
|
+
|
|
|
+//
|
|
|
+// Module globals
|
|
|
+//
|
|
|
+CONST EFI_PEI_PPI_DESCRIPTOR mPpiListBootMode = {
|
|
|
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
|
|
|
+ &gEfiPeiMasterBootModePpiGuid,
|
|
|
+ NULL
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ Create Reserved type memory range hand off block.
|
|
|
+
|
|
|
+ @param MemoryBase memory base address.
|
|
|
+ @param MemoryLimit memory length.
|
|
|
+
|
|
|
+ @return VOID
|
|
|
+**/
|
|
|
+VOID
|
|
|
+AddReservedMemoryBaseSizeHob (
|
|
|
+ EFI_PHYSICAL_ADDRESS MemoryBase,
|
|
|
+ UINT64 MemorySize
|
|
|
+ )
|
|
|
+{
|
|
|
+ BuildResourceDescriptorHob (
|
|
|
+ EFI_RESOURCE_MEMORY_RESERVED,
|
|
|
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
|
|
|
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
|
|
|
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
|
|
|
+ EFI_RESOURCE_ATTRIBUTE_TESTED,
|
|
|
+ MemoryBase,
|
|
|
+ MemorySize
|
|
|
+ );
|
|
|
+}
|
|
|
+/**
|
|
|
+ Create system type memory range hand off block.
|
|
|
+
|
|
|
+ @param MemoryBase memory base address.
|
|
|
+ @param MemoryLimit memory length.
|
|
|
+
|
|
|
+ @return VOID
|
|
|
+**/
|
|
|
+VOID
|
|
|
+AddMemoryBaseSizeHob (
|
|
|
+ EFI_PHYSICAL_ADDRESS MemoryBase,
|
|
|
+ UINT64 MemorySize
|
|
|
+ )
|
|
|
+{
|
|
|
+ BuildResourceDescriptorHob (
|
|
|
+ EFI_RESOURCE_SYSTEM_MEMORY,
|
|
|
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
|
|
|
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
|
|
|
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
|
|
|
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
|
|
|
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
|
|
|
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
|
|
|
+ EFI_RESOURCE_ATTRIBUTE_TESTED,
|
|
|
+ MemoryBase,
|
|
|
+ MemorySize
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ Create memory range hand off block.
|
|
|
+
|
|
|
+ @param MemoryBase memory base address.
|
|
|
+ @param MemoryLimit memory length.
|
|
|
+
|
|
|
+ @return VOID
|
|
|
+**/
|
|
|
+VOID
|
|
|
+AddMemoryRangeHob (
|
|
|
+ EFI_PHYSICAL_ADDRESS MemoryBase,
|
|
|
+ EFI_PHYSICAL_ADDRESS MemoryLimit
|
|
|
+ )
|
|
|
+{
|
|
|
+ AddMemoryBaseSizeHob (MemoryBase, (UINT64) (MemoryLimit - MemoryBase));
|
|
|
+}
|
|
|
+/**
|
|
|
+ Create memory type information hand off block.
|
|
|
+
|
|
|
+ @param VOID
|
|
|
+
|
|
|
+ @return VOID
|
|
|
+**/
|
|
|
+VOID
|
|
|
+MemMapInitialization (
|
|
|
+ VOID
|
|
|
+ )
|
|
|
+{
|
|
|
+ DEBUG ((DEBUG_INFO, "==%a==\n", __func__));
|
|
|
+ //
|
|
|
+ // Create Memory Type Information HOB
|
|
|
+ //
|
|
|
+ BuildGuidDataHob (
|
|
|
+ &gEfiMemoryTypeInformationGuid,
|
|
|
+ mDefaultMemoryTypeInformation,
|
|
|
+ sizeof (mDefaultMemoryTypeInformation)
|
|
|
+ );
|
|
|
+}
|
|
|
+/** Get the UART base address of the console serial-port from the DT.
|
|
|
+
|
|
|
+ This function fetches the node referenced in the "stdout-path"
|
|
|
+ property of the "chosen" node and returns the base address of
|
|
|
+ the console UART.
|
|
|
+
|
|
|
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
|
|
|
+ @param [out] SerialConsoleAddress If success, contains the base address
|
|
|
+ of the console serial-port.
|
|
|
+
|
|
|
+ @retval EFI_SUCCESS The function completed successfully.
|
|
|
+ @retval EFI_NOT_FOUND Console serial-port info not found in DT.
|
|
|
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
|
+**/
|
|
|
+STATIC
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+GetSerialConsolePortAddress (
|
|
|
+ IN CONST VOID *Fdt,
|
|
|
+ OUT UINT64 *SerialConsoleAddress
|
|
|
+ )
|
|
|
+{
|
|
|
+ CONST CHAR8 *Prop;
|
|
|
+ INT32 PropSize;
|
|
|
+ CONST CHAR8 *Path;
|
|
|
+ INT32 PathLen;
|
|
|
+ INT32 ChosenNode;
|
|
|
+ INT32 SerialConsoleNode;
|
|
|
+ INT32 Len;
|
|
|
+ CONST CHAR8 *NodeStatus;
|
|
|
+ CONST UINT64 *RegProperty;
|
|
|
+
|
|
|
+ if ((Fdt == NULL) || (fdt_check_header (Fdt) != 0)) {
|
|
|
+ return EFI_INVALID_PARAMETER;
|
|
|
+ }
|
|
|
+
|
|
|
+ // The "chosen" node resides at the root of the DT. Fetch it.
|
|
|
+ ChosenNode = fdt_path_offset (Fdt, "/chosen");
|
|
|
+ if (ChosenNode < 0) {
|
|
|
+ return EFI_NOT_FOUND;
|
|
|
+ }
|
|
|
+
|
|
|
+ Prop = fdt_getprop (Fdt, ChosenNode, "stdout-path", &PropSize);
|
|
|
+ if (PropSize < 0) {
|
|
|
+ return EFI_NOT_FOUND;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Determine the actual path length, as a colon terminates the path.
|
|
|
+ Path = ScanMem8 (Prop, ':', PropSize);
|
|
|
+ if (Path == NULL) {
|
|
|
+ PathLen = AsciiStrLen (Prop);
|
|
|
+ } else {
|
|
|
+ PathLen = Path - Prop;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Aliases cannot start with a '/', so it must be the actual path.
|
|
|
+ if (Prop[0] == '/') {
|
|
|
+ SerialConsoleNode = fdt_path_offset_namelen (Fdt, Prop, PathLen);
|
|
|
+ } else {
|
|
|
+ // Lookup the alias, as this contains the actual path.
|
|
|
+ Path = fdt_get_alias_namelen (Fdt, Prop, PathLen);
|
|
|
+ if (Path == NULL) {
|
|
|
+ return EFI_NOT_FOUND;
|
|
|
+ }
|
|
|
+
|
|
|
+ SerialConsoleNode = fdt_path_offset (Fdt, Path);
|
|
|
+ }
|
|
|
+
|
|
|
+ NodeStatus = fdt_getprop (Fdt, SerialConsoleNode, "status", &Len);
|
|
|
+ if ((NodeStatus != NULL) && (AsciiStrCmp (NodeStatus, "okay") != 0)) {
|
|
|
+ return EFI_NOT_FOUND;
|
|
|
+ }
|
|
|
+
|
|
|
+ RegProperty = fdt_getprop (Fdt, SerialConsoleNode, "reg", &Len);
|
|
|
+ if (Len != 16) {
|
|
|
+ return EFI_INVALID_PARAMETER;
|
|
|
+ }
|
|
|
+
|
|
|
+ *SerialConsoleAddress = fdt64_to_cpu (ReadUnaligned64 (RegProperty));
|
|
|
+
|
|
|
+ return EFI_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+/** Get the Rtc base address from the DT.
|
|
|
+
|
|
|
+ This function fetches the node referenced in the "loongson,ls7a-rtc"
|
|
|
+ property of the "reg" node and returns the base address of
|
|
|
+ the RTC.
|
|
|
+
|
|
|
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
|
|
|
+ @param [out] RtcBaseAddress If success, contains the base address
|
|
|
+ of the Rtc.
|
|
|
+
|
|
|
+ @retval EFI_SUCCESS The function completed successfully.
|
|
|
+ @retval EFI_NOT_FOUND RTC info not found in DT.
|
|
|
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
|
+**/
|
|
|
+STATIC
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+GetRtcAddress (
|
|
|
+ IN CONST VOID *Fdt,
|
|
|
+ OUT UINT64 *RtcBaseAddress
|
|
|
+ )
|
|
|
+{
|
|
|
+ INT32 Node;
|
|
|
+ INT32 Prev;
|
|
|
+ CONST CHAR8 *Type;
|
|
|
+ INT32 Len;
|
|
|
+ CONST UINT64 *RegProp;
|
|
|
+ EFI_STATUS Status;
|
|
|
+
|
|
|
+ if ((Fdt == NULL) || (fdt_check_header (Fdt) != 0)) {
|
|
|
+ return EFI_INVALID_PARAMETER;
|
|
|
+ }
|
|
|
+
|
|
|
+ Status = EFI_NOT_FOUND;
|
|
|
+ for (Prev = 0;; Prev = Node) {
|
|
|
+ Node = fdt_next_node (Fdt, Prev, NULL);
|
|
|
+ if (Node < 0) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+ // Check for memory node
|
|
|
+ //
|
|
|
+ Type = fdt_getprop (Fdt, Node, "compatible", &Len);
|
|
|
+ if ((Type)
|
|
|
+ && (AsciiStrnCmp (Type, "loongson,ls7a-rtc", Len) == 0))
|
|
|
+ {
|
|
|
+ //
|
|
|
+ // Get the 'reg' property of this node. For now, we will assume
|
|
|
+ // two 8 byte quantities for base and size, respectively.
|
|
|
+ //
|
|
|
+ RegProp = fdt_getprop (Fdt, Node, "reg", &Len);
|
|
|
+ if ((RegProp != 0)
|
|
|
+ && (Len == (2 * sizeof (UINT64))))
|
|
|
+ {
|
|
|
+ *RtcBaseAddress = SwapBytes64 (RegProp[0]);
|
|
|
+ Status = RETURN_SUCCESS;
|
|
|
+ DEBUG ((DEBUG_INFO, "%a Len %d RtcBase %llx\n",__func__, Len, *RtcBaseAddress));
|
|
|
+ break;
|
|
|
+ } else {
|
|
|
+ DEBUG ((DEBUG_ERROR, "%a: Failed to parse FDT rtc node\n",
|
|
|
+ __FUNCTION__));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return Status;
|
|
|
+}
|
|
|
+/**
|
|
|
+ Misc Initialization.
|
|
|
+
|
|
|
+ @param VOID
|
|
|
+
|
|
|
+ @return VOID
|
|
|
+**/
|
|
|
+VOID
|
|
|
+MiscInitialization (
|
|
|
+ VOID
|
|
|
+ )
|
|
|
+{
|
|
|
+ DEBUG ((DEBUG_INFO, "==%a==\n", __func__));
|
|
|
+ //
|
|
|
+ // Creat CPU HOBs.
|
|
|
+ //
|
|
|
+ BuildCpuHob (PcdGet8 (PcdPrePiCpuMemorySize), PcdGet8 (PcdPrePiCpuIoSize));
|
|
|
+}
|
|
|
+/**
|
|
|
+ add fdt hand off block.
|
|
|
+
|
|
|
+ @param VOID
|
|
|
+
|
|
|
+ @return VOID
|
|
|
+**/
|
|
|
+VOID
|
|
|
+AddFdtHob (VOID)
|
|
|
+{
|
|
|
+ VOID *Base;
|
|
|
+ VOID *NewBase;
|
|
|
+ UINTN FdtSize;
|
|
|
+ UINTN FdtPages;
|
|
|
+ UINT64 *FdtHobData;
|
|
|
+ UINT64 *UartHobData;
|
|
|
+ UINT64 SerialConsoleAddress;
|
|
|
+ UINT64 RtcBaseAddress;
|
|
|
+ RETURN_STATUS Status;
|
|
|
+
|
|
|
+ Base = (VOID*)(UINTN)PcdGet64 (PcdDeviceTreeBase);
|
|
|
+ ASSERT (Base != NULL);
|
|
|
+
|
|
|
+ Status = GetSerialConsolePortAddress (Base, &SerialConsoleAddress);
|
|
|
+ if (RETURN_ERROR (Status)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ UartHobData = BuildGuidHob (&gEarly16550UartBaseAddressGuid, sizeof *UartHobData);
|
|
|
+ ASSERT (UartHobData != NULL);
|
|
|
+ *UartHobData = SerialConsoleAddress;
|
|
|
+
|
|
|
+ Status = GetRtcAddress(Base, &RtcBaseAddress);
|
|
|
+ if (RETURN_ERROR (Status)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Status = PcdSet64S (PcdRtcBaseAddress, RtcBaseAddress);
|
|
|
+ if (RETURN_ERROR (Status)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ FdtSize = fdt_totalsize (Base) + PcdGet32 (PcdDeviceTreePadding);
|
|
|
+ FdtPages = EFI_SIZE_TO_PAGES (FdtSize);
|
|
|
+ NewBase = AllocatePages (FdtPages);
|
|
|
+ ASSERT (NewBase != NULL);
|
|
|
+ fdt_open_into (Base, NewBase, EFI_PAGES_TO_SIZE (FdtPages));
|
|
|
+
|
|
|
+ FdtHobData = BuildGuidHob (&gFdtHobGuid, sizeof *FdtHobData);
|
|
|
+ ASSERT (FdtHobData != NULL);
|
|
|
+ *FdtHobData = (UINTN)NewBase;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ Fetch the size of system memory from QEMU.
|
|
|
+
|
|
|
+ @param VOID
|
|
|
+
|
|
|
+ @return VOID
|
|
|
+**/
|
|
|
+VOID
|
|
|
+SystemMemorySizeInitialization (
|
|
|
+ VOID
|
|
|
+ )
|
|
|
+{
|
|
|
+ UINT64 RamSize;
|
|
|
+ RETURN_STATUS PcdStatus;
|
|
|
+
|
|
|
+ QemuFwCfgSelectItem (QemuFwCfgItemRamSize);
|
|
|
+ RamSize= QemuFwCfgRead64 ();
|
|
|
+ DEBUG ((DEBUG_INFO, "%a: QEMU reports %dM system memory\n", __FUNCTION__,
|
|
|
+ RamSize/1024/1024));
|
|
|
+
|
|
|
+ //
|
|
|
+ // If the fw_cfg key or fw_cfg entirely is unavailable, no change to PCD.
|
|
|
+ //
|
|
|
+ if (RamSize == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+ // Otherwise, set RamSize to PCD.
|
|
|
+ //
|
|
|
+ PcdStatus = PcdSet64S (PcdRamSize, RamSize);
|
|
|
+ ASSERT_RETURN_ERROR (PcdStatus);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ Perform Platform PEI initialization.
|
|
|
+
|
|
|
+ @param FileHandle Handle of the file being invoked.
|
|
|
+ @param PeiServices Describes the list of possible PEI Services.
|
|
|
+
|
|
|
+ @return EFI_SUCCESS The PEIM initialized successfully.
|
|
|
+**/
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+InitializePlatform (
|
|
|
+ IN EFI_PEI_FILE_HANDLE FileHandle,
|
|
|
+ IN CONST EFI_PEI_SERVICES **PeiServices
|
|
|
+ )
|
|
|
+{
|
|
|
+ EFI_STATUS Status;
|
|
|
+
|
|
|
+ DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
|
|
|
+
|
|
|
+ Status = PeiServicesInstallPpi (&mPpiListBootMode);
|
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
|
+
|
|
|
+ SystemMemorySizeInitialization ();
|
|
|
+ PublishPeiMemory ();
|
|
|
+ PeiFvInitialization ();
|
|
|
+ InitializeRamRegions ();
|
|
|
+ MemMapInitialization ();
|
|
|
+ MiscInitialization ();
|
|
|
+ AddFdtHob ();
|
|
|
+ ConfigureMmu ();
|
|
|
+
|
|
|
+ return EFI_SUCCESS;
|
|
|
+}
|