EarlyFdt16550SerialPortHookLib.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /** @file
  2. Early Platform Hook Library instance for 16550 Uart.
  3. Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Base.h>
  7. #include <Uefi.h>
  8. #include <Pi/PiBootMode.h>
  9. #include <Pi/PiHob.h>
  10. #include <Library/BaseLib.h>
  11. #include <Library/DebugLib.h>
  12. #include <Library/HobLib.h>
  13. #include <Library/PcdLib.h>
  14. #include <Library/PlatformHookLib.h>
  15. #include <libfdt.h>
  16. /** Get the UART base address of the console serial-port from the DT.
  17. This function fetches the node referenced in the "stdout-path"
  18. property of the "chosen" node and returns the base address of
  19. the console UART.
  20. @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
  21. @param [out] SerialConsoleAddress If success, contains the base address
  22. of the console serial-port.
  23. @retval EFI_SUCCESS The function completed successfully.
  24. @retval EFI_NOT_FOUND Console serial-port info not found in DT.
  25. @retval EFI_INVALID_PARAMETER Invalid parameter.
  26. **/
  27. STATIC
  28. EFI_STATUS
  29. EFIAPI
  30. GetSerialConsolePortAddress (
  31. IN CONST VOID *Fdt,
  32. OUT UINT64 *SerialConsoleAddress
  33. )
  34. {
  35. CONST CHAR8 *Prop;
  36. INT32 PropSize;
  37. CONST CHAR8 *Path;
  38. INT32 PathLen;
  39. INT32 ChosenNode;
  40. INT32 SerialConsoleNode;
  41. INT32 Len;
  42. CONST CHAR8 *NodeStatus;
  43. CONST UINT64 *RegProperty;
  44. if ((Fdt == NULL) || (fdt_check_header (Fdt) != 0)) {
  45. return EFI_INVALID_PARAMETER;
  46. }
  47. // The "chosen" node resides at the the root of the DT. Fetch it.
  48. ChosenNode = fdt_path_offset (Fdt, "/chosen");
  49. if (ChosenNode < 0) {
  50. return EFI_NOT_FOUND;
  51. }
  52. Prop = fdt_getprop (Fdt, ChosenNode, "stdout-path", &PropSize);
  53. if (PropSize < 0) {
  54. return EFI_NOT_FOUND;
  55. }
  56. // Determine the actual path length, as a colon terminates the path.
  57. Path = ScanMem8 (Prop, ':', PropSize);
  58. if (Path == NULL) {
  59. PathLen = AsciiStrLen (Prop);
  60. } else {
  61. PathLen = Path - Prop;
  62. }
  63. // Aliases cannot start with a '/', so it must be the actual path.
  64. if (Prop[0] == '/') {
  65. SerialConsoleNode = fdt_path_offset_namelen (Fdt, Prop, PathLen);
  66. } else {
  67. // Lookup the alias, as this contains the actual path.
  68. Path = fdt_get_alias_namelen (Fdt, Prop, PathLen);
  69. if (Path == NULL) {
  70. return EFI_NOT_FOUND;
  71. }
  72. SerialConsoleNode = fdt_path_offset (Fdt, Path);
  73. }
  74. NodeStatus = fdt_getprop (Fdt, SerialConsoleNode, "status", &Len);
  75. if ((NodeStatus != NULL) && (AsciiStrCmp (NodeStatus, "okay") != 0)) {
  76. return EFI_NOT_FOUND;
  77. }
  78. RegProperty = fdt_getprop (Fdt, SerialConsoleNode, "reg", &Len);
  79. if (Len != 16) {
  80. return EFI_INVALID_PARAMETER;
  81. }
  82. *SerialConsoleAddress = fdt64_to_cpu (ReadUnaligned64 (RegProperty));
  83. return EFI_SUCCESS;
  84. }
  85. /** Platform hook to retrieve the 16550 UART base address from the platform
  86. Device tree and store it in PcdSerialRegisterBase.
  87. @retval RETURN_SUCCESS Success.
  88. @retval RETURN_INVALID_PARAMETER A parameter was invalid.
  89. @retval RETURN_NOT_FOUND Serial port information not found.
  90. **/
  91. RETURN_STATUS
  92. EFIAPI
  93. PlatformHookSerialPortInitialize (
  94. VOID
  95. )
  96. {
  97. RETURN_STATUS Status;
  98. VOID *DeviceTreeBase;
  99. UINT64 SerialConsoleAddress;
  100. if (PcdGet64 (PcdSerialRegisterBase) != 0) {
  101. return RETURN_SUCCESS;
  102. }
  103. DeviceTreeBase = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeInitialBaseAddress);
  104. if (DeviceTreeBase == NULL) {
  105. return RETURN_NOT_FOUND;
  106. }
  107. Status = GetSerialConsolePortAddress (DeviceTreeBase, &SerialConsoleAddress);
  108. if (RETURN_ERROR (Status)) {
  109. return Status;
  110. }
  111. return (EFI_STATUS)PcdSet64S (PcdSerialRegisterBase, SerialConsoleAddress);
  112. }