2 FDT client library for consumers of PCI related dynamic PCDs
4 Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <Library/BaseLib.h>
13 #include <Library/DebugLib.h>
14 #include <Library/PcdLib.h>
15 #include <Library/UefiBootServicesTableLib.h>
17 #include <Protocol/FdtClient.h>
20 // We expect the "ranges" property of "pci-host-ecam-generic" to consist of
29 } DTB_PCI_HOST_RANGE_RECORD
;
32 #define DTB_PCI_HOST_RANGE_RELOCATABLE BIT31
33 #define DTB_PCI_HOST_RANGE_PREFETCHABLE BIT30
34 #define DTB_PCI_HOST_RANGE_ALIASED BIT29
35 #define DTB_PCI_HOST_RANGE_MMIO32 BIT25
36 #define DTB_PCI_HOST_RANGE_MMIO64 (BIT25 | BIT24)
37 #define DTB_PCI_HOST_RANGE_IO BIT24
38 #define DTB_PCI_HOST_RANGE_TYPEMASK (BIT31 | BIT30 | BIT29 | BIT25 | BIT24)
43 IN FDT_CLIENT_PROTOCOL
*FdtClient
,
45 OUT UINT64
*IoTranslation
55 // Iterate over "ranges".
57 Status
= FdtClient
->GetNodeProperty (FdtClient
, Node
, "ranges", &Prop
, &Len
);
58 if (EFI_ERROR (Status
) || (Len
== 0) ||
59 (Len
% sizeof (DTB_PCI_HOST_RANGE_RECORD
) != 0))
61 DEBUG ((DEBUG_ERROR
, "%a: 'ranges' not found or invalid\n", __FUNCTION__
));
62 return RETURN_PROTOCOL_ERROR
;
65 for (RecordIdx
= 0; RecordIdx
< Len
/ sizeof (DTB_PCI_HOST_RANGE_RECORD
);
68 CONST DTB_PCI_HOST_RANGE_RECORD
*Record
;
71 Record
= (CONST DTB_PCI_HOST_RANGE_RECORD
*)Prop
+ RecordIdx
;
72 Type
= SwapBytes32 (Record
->Type
) & DTB_PCI_HOST_RANGE_TYPEMASK
;
73 if (Type
== DTB_PCI_HOST_RANGE_IO
) {
74 IoBase
= SwapBytes64 (Record
->ChildBase
);
75 *IoTranslation
= SwapBytes64 (Record
->CpuBase
) - IoBase
;
77 return RETURN_SUCCESS
;
81 return RETURN_NOT_FOUND
;
86 FdtPciPcdProducerLibConstructor (
90 UINT64 PciExpressBaseAddress
;
91 FDT_CLIENT_PROTOCOL
*FdtClient
;
96 RETURN_STATUS RetStatus
;
98 RETURN_STATUS PcdStatus
;
100 PciExpressBaseAddress
= PcdGet64 (PcdPciExpressBaseAddress
);
101 if (PciExpressBaseAddress
!= MAX_UINT64
) {
103 // Assume that the fact that PciExpressBaseAddress has been changed from
104 // its default value of MAX_UINT64 implies that this code has been
105 // executed already, in the context of another module. That means we can
106 // assume that PcdPciIoTranslation has been discovered from the DT node
112 Status
= gBS
->LocateProtocol (
113 &gFdtClientProtocolGuid
,
117 ASSERT_EFI_ERROR (Status
);
119 PciExpressBaseAddress
= 0;
120 Status
= FdtClient
->FindCompatibleNode (
122 "pci-host-ecam-generic",
126 if (!EFI_ERROR (Status
)) {
127 Status
= FdtClient
->GetNodeProperty (
135 if (!EFI_ERROR (Status
) && (RegSize
== 2 * sizeof (UINT64
))) {
136 PciExpressBaseAddress
= SwapBytes64 (*Reg
);
138 PcdStatus
= PcdSetBoolS (PcdPciDisableBusEnumeration
, FALSE
);
139 ASSERT_RETURN_ERROR (PcdStatus
);
142 RetStatus
= GetPciIoTranslation (FdtClient
, Node
, &IoTranslation
);
143 if (!RETURN_ERROR (RetStatus
)) {
144 PcdStatus
= PcdSet64S (PcdPciIoTranslation
, IoTranslation
);
145 ASSERT_RETURN_ERROR (PcdStatus
);
148 // Support for I/O BARs is not mandatory, and so it does not make sense
149 // to abort in the general case. So leave it up to the actual driver to
150 // complain about this if it wants to, and just issue a warning here.
154 "%a: 'pci-host-ecam-generic' device encountered with no I/O range\n",
161 PcdStatus
= PcdSet64S (PcdPciExpressBaseAddress
, PciExpressBaseAddress
);
162 ASSERT_RETURN_ERROR (PcdStatus
);
164 return RETURN_SUCCESS
;