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