FdtPciPcdProducerLib.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /** @file
  2. FDT client library for consumers of PCI related dynamic PCDs
  3. Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Uefi.h>
  7. #include <Library/BaseLib.h>
  8. #include <Library/DebugLib.h>
  9. #include <Library/PcdLib.h>
  10. #include <Library/UefiBootServicesTableLib.h>
  11. #include <Protocol/FdtClient.h>
  12. //
  13. // We expect the "ranges" property of "pci-host-ecam-generic" to consist of
  14. // records like this.
  15. //
  16. #pragma pack (1)
  17. typedef struct {
  18. UINT32 Type;
  19. UINT64 ChildBase;
  20. UINT64 CpuBase;
  21. UINT64 Size;
  22. } DTB_PCI_HOST_RANGE_RECORD;
  23. #pragma pack ()
  24. #define DTB_PCI_HOST_RANGE_RELOCATABLE BIT31
  25. #define DTB_PCI_HOST_RANGE_PREFETCHABLE BIT30
  26. #define DTB_PCI_HOST_RANGE_ALIASED BIT29
  27. #define DTB_PCI_HOST_RANGE_MMIO32 BIT25
  28. #define DTB_PCI_HOST_RANGE_MMIO64 (BIT25 | BIT24)
  29. #define DTB_PCI_HOST_RANGE_IO BIT24
  30. #define DTB_PCI_HOST_RANGE_TYPEMASK (BIT31 | BIT30 | BIT29 | BIT25 | BIT24)
  31. STATIC
  32. RETURN_STATUS
  33. GetPciIoTranslation (
  34. IN FDT_CLIENT_PROTOCOL *FdtClient,
  35. IN INT32 Node,
  36. OUT UINT64 *IoTranslation
  37. )
  38. {
  39. UINT32 RecordIdx;
  40. CONST VOID *Prop;
  41. UINT32 Len;
  42. EFI_STATUS Status;
  43. UINT64 IoBase;
  44. //
  45. // Iterate over "ranges".
  46. //
  47. Status = FdtClient->GetNodeProperty (FdtClient, Node, "ranges", &Prop, &Len);
  48. if (EFI_ERROR (Status) || (Len == 0) ||
  49. (Len % sizeof (DTB_PCI_HOST_RANGE_RECORD) != 0))
  50. {
  51. DEBUG ((DEBUG_ERROR, "%a: 'ranges' not found or invalid\n", __FUNCTION__));
  52. return RETURN_PROTOCOL_ERROR;
  53. }
  54. for (RecordIdx = 0; RecordIdx < Len / sizeof (DTB_PCI_HOST_RANGE_RECORD);
  55. ++RecordIdx)
  56. {
  57. CONST DTB_PCI_HOST_RANGE_RECORD *Record;
  58. UINT32 Type;
  59. Record = (CONST DTB_PCI_HOST_RANGE_RECORD *)Prop + RecordIdx;
  60. Type = SwapBytes32 (Record->Type) & DTB_PCI_HOST_RANGE_TYPEMASK;
  61. if (Type == DTB_PCI_HOST_RANGE_IO) {
  62. IoBase = SwapBytes64 (Record->ChildBase);
  63. *IoTranslation = SwapBytes64 (Record->CpuBase) - IoBase;
  64. return RETURN_SUCCESS;
  65. }
  66. }
  67. return RETURN_NOT_FOUND;
  68. }
  69. RETURN_STATUS
  70. EFIAPI
  71. FdtPciPcdProducerLibConstructor (
  72. VOID
  73. )
  74. {
  75. UINT64 PciExpressBaseAddress;
  76. FDT_CLIENT_PROTOCOL *FdtClient;
  77. CONST UINT64 *Reg;
  78. UINT32 RegSize;
  79. EFI_STATUS Status;
  80. INT32 Node;
  81. RETURN_STATUS RetStatus;
  82. UINT64 IoTranslation;
  83. RETURN_STATUS PcdStatus;
  84. PciExpressBaseAddress = PcdGet64 (PcdPciExpressBaseAddress);
  85. if (PciExpressBaseAddress != MAX_UINT64) {
  86. //
  87. // Assume that the fact that PciExpressBaseAddress has been changed from
  88. // its default value of MAX_UINT64 implies that this code has been
  89. // executed already, in the context of another module. That means we can
  90. // assume that PcdPciIoTranslation has been discovered from the DT node
  91. // as well.
  92. //
  93. return EFI_SUCCESS;
  94. }
  95. Status = gBS->LocateProtocol (
  96. &gFdtClientProtocolGuid,
  97. NULL,
  98. (VOID **)&FdtClient
  99. );
  100. ASSERT_EFI_ERROR (Status);
  101. PciExpressBaseAddress = 0;
  102. Status = FdtClient->FindCompatibleNode (
  103. FdtClient,
  104. "pci-host-ecam-generic",
  105. &Node
  106. );
  107. if (!EFI_ERROR (Status)) {
  108. Status = FdtClient->GetNodeProperty (
  109. FdtClient,
  110. Node,
  111. "reg",
  112. (CONST VOID **)&Reg,
  113. &RegSize
  114. );
  115. if (!EFI_ERROR (Status) && (RegSize == 2 * sizeof (UINT64))) {
  116. PciExpressBaseAddress = SwapBytes64 (*Reg);
  117. PcdStatus = PcdSetBoolS (PcdPciDisableBusEnumeration, FALSE);
  118. ASSERT_RETURN_ERROR (PcdStatus);
  119. IoTranslation = 0;
  120. RetStatus = GetPciIoTranslation (FdtClient, Node, &IoTranslation);
  121. if (!RETURN_ERROR (RetStatus)) {
  122. PcdStatus = PcdSet64S (PcdPciIoTranslation, IoTranslation);
  123. ASSERT_RETURN_ERROR (PcdStatus);
  124. } else {
  125. //
  126. // Support for I/O BARs is not mandatory, and so it does not make sense
  127. // to abort in the general case. So leave it up to the actual driver to
  128. // complain about this if it wants to, and just issue a warning here.
  129. //
  130. DEBUG ((
  131. DEBUG_WARN,
  132. "%a: 'pci-host-ecam-generic' device encountered with no I/O range\n",
  133. __FUNCTION__
  134. ));
  135. }
  136. }
  137. }
  138. PcdStatus = PcdSet64S (PcdPciExpressBaseAddress, PciExpressBaseAddress);
  139. ASSERT_RETURN_ERROR (PcdStatus);
  140. return RETURN_SUCCESS;
  141. }