2 FDT client library for consumers of PCI related dynamic PCDs
4 Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include <Library/BaseLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/PcdLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
23 #include <Protocol/FdtClient.h>
26 // We expect the "ranges" property of "pci-host-ecam-generic" to consist of
35 } DTB_PCI_HOST_RANGE_RECORD
;
38 #define DTB_PCI_HOST_RANGE_RELOCATABLE BIT31
39 #define DTB_PCI_HOST_RANGE_PREFETCHABLE BIT30
40 #define DTB_PCI_HOST_RANGE_ALIASED BIT29
41 #define DTB_PCI_HOST_RANGE_MMIO32 BIT25
42 #define DTB_PCI_HOST_RANGE_MMIO64 (BIT25 | BIT24)
43 #define DTB_PCI_HOST_RANGE_IO BIT24
44 #define DTB_PCI_HOST_RANGE_TYPEMASK (BIT31 | BIT30 | BIT29 | BIT25 | BIT24)
49 IN FDT_CLIENT_PROTOCOL
*FdtClient
,
51 OUT UINT64
*IoTranslation
61 // Iterate over "ranges".
63 Status
= FdtClient
->GetNodeProperty (FdtClient
, Node
, "ranges", &Prop
, &Len
);
64 if (EFI_ERROR (Status
) || Len
== 0 ||
65 Len
% sizeof (DTB_PCI_HOST_RANGE_RECORD
) != 0) {
66 DEBUG ((EFI_D_ERROR
, "%a: 'ranges' not found or invalid\n", __FUNCTION__
));
67 return RETURN_PROTOCOL_ERROR
;
70 for (RecordIdx
= 0; RecordIdx
< Len
/ sizeof (DTB_PCI_HOST_RANGE_RECORD
);
72 CONST DTB_PCI_HOST_RANGE_RECORD
*Record
;
75 Record
= (CONST DTB_PCI_HOST_RANGE_RECORD
*)Prop
+ RecordIdx
;
76 Type
= SwapBytes32 (Record
->Type
) & DTB_PCI_HOST_RANGE_TYPEMASK
;
77 if (Type
== DTB_PCI_HOST_RANGE_IO
) {
78 IoBase
= SwapBytes64 (Record
->ChildBase
);
79 *IoTranslation
= SwapBytes64 (Record
->CpuBase
) - IoBase
;
81 return RETURN_SUCCESS
;
84 return RETURN_NOT_FOUND
;
89 FdtPciPcdProducerLibConstructor (
93 UINT64 PciExpressBaseAddress
;
94 FDT_CLIENT_PROTOCOL
*FdtClient
;
99 RETURN_STATUS RetStatus
;
100 UINT64 IoTranslation
;
102 PciExpressBaseAddress
= PcdGet64 (PcdPciExpressBaseAddress
);
103 if (PciExpressBaseAddress
!= MAX_UINT64
) {
105 // Assume that the fact that PciExpressBaseAddress has been changed from
106 // its default value of MAX_UINT64 implies that this code has been
107 // executed already, in the context of another module. That means we can
108 // assume that PcdPciIoTranslation has been discovered from the DT node
114 Status
= gBS
->LocateProtocol (&gFdtClientProtocolGuid
, NULL
,
115 (VOID
**)&FdtClient
);
116 ASSERT_EFI_ERROR (Status
);
118 PciExpressBaseAddress
= 0;
119 Status
= FdtClient
->FindCompatibleNode (FdtClient
, "pci-host-ecam-generic",
122 if (!EFI_ERROR (Status
)) {
123 Status
= FdtClient
->GetNodeProperty (FdtClient
, Node
, "reg",
124 (CONST VOID
**)&Reg
, &RegSize
);
126 if (!EFI_ERROR (Status
) && RegSize
== 2 * sizeof (UINT64
)) {
127 PciExpressBaseAddress
= SwapBytes64 (*Reg
);
129 PcdSetBool (PcdPciDisableBusEnumeration
, FALSE
);
131 RetStatus
= GetPciIoTranslation (FdtClient
, Node
, &IoTranslation
);
132 if (!RETURN_ERROR (RetStatus
)) {
133 PcdSet64 (PcdPciIoTranslation
, IoTranslation
);
136 // Support for I/O BARs is not mandatory, and so it does not make sense
137 // to abort in the general case. So leave it up to the actual driver to
138 // complain about this if it wants to, and just issue a warning here.
141 "%a: 'pci-host-ecam-generic' device encountered with no I/O range\n",
147 PcdSet64 (PcdPciExpressBaseAddress
, PciExpressBaseAddress
);
149 return RETURN_SUCCESS
;