/** @file Early Platform Hook Library instance for 16550 Uart. Copyright (c) 2020 - 2023, Arm Ltd. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include /** 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; } /** Platform hook to retrieve the 16550 UART base address from the platform Device tree and store it in PcdSerialRegisterBase. @retval RETURN_SUCCESS Success. @retval RETURN_INVALID_PARAMETER A parameter was invalid. @retval RETURN_NOT_FOUND Serial port information not found. **/ RETURN_STATUS EFIAPI PlatformHookSerialPortInitialize ( VOID ) { RETURN_STATUS Status; VOID *DeviceTreeBase; UINT64 SerialConsoleAddress; if (PcdGet64 (PcdSerialRegisterBase) != 0) { return RETURN_SUCCESS; } DeviceTreeBase = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeInitialBaseAddress); if (DeviceTreeBase == NULL) { return RETURN_NOT_FOUND; } Status = GetSerialConsolePortAddress (DeviceTreeBase, &SerialConsoleAddress); if (RETURN_ERROR (Status)) { return Status; } return (EFI_STATUS)PcdSet64S (PcdSerialRegisterBase, SerialConsoleAddress); }