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