]>
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 | |
25 | UINT32 Type;\r | |
26 | UINT64 ChildBase;\r | |
27 | UINT64 CpuBase;\r | |
28 | UINT64 Size;\r | |
29 | } DTB_PCI_HOST_RANGE_RECORD;\r | |
30 | #pragma pack ()\r | |
31 | \r | |
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 | |
39 | \r | |
40 | STATIC\r | |
41 | RETURN_STATUS\r | |
42 | GetPciIoTranslation (\r | |
43 | IN FDT_CLIENT_PROTOCOL *FdtClient,\r | |
44 | IN INT32 Node,\r | |
45 | OUT UINT64 *IoTranslation\r | |
46 | )\r | |
47 | {\r | |
48 | UINT32 RecordIdx;\r | |
49 | CONST VOID *Prop;\r | |
50 | UINT32 Len;\r | |
51 | EFI_STATUS Status;\r | |
52 | UINT64 IoBase;\r | |
53 | \r | |
54 | //\r | |
55 | // Iterate over "ranges".\r | |
56 | //\r | |
57 | Status = FdtClient->GetNodeProperty (FdtClient, Node, "ranges", &Prop, &Len);\r | |
58 | if (EFI_ERROR (Status) || Len == 0 ||\r | |
59 | Len % sizeof (DTB_PCI_HOST_RANGE_RECORD) != 0) {\r | |
47719926 | 60 | DEBUG ((DEBUG_ERROR, "%a: 'ranges' not found or invalid\n", __FUNCTION__));\r |
c8f1a75a AB |
61 | return RETURN_PROTOCOL_ERROR;\r |
62 | }\r | |
63 | \r | |
64 | for (RecordIdx = 0; RecordIdx < Len / sizeof (DTB_PCI_HOST_RANGE_RECORD);\r | |
65 | ++RecordIdx) {\r | |
66 | CONST DTB_PCI_HOST_RANGE_RECORD *Record;\r | |
67 | UINT32 Type;\r | |
68 | \r | |
69 | Record = (CONST DTB_PCI_HOST_RANGE_RECORD *)Prop + RecordIdx;\r | |
70 | Type = SwapBytes32 (Record->Type) & DTB_PCI_HOST_RANGE_TYPEMASK;\r | |
71 | if (Type == DTB_PCI_HOST_RANGE_IO) {\r | |
72 | IoBase = SwapBytes64 (Record->ChildBase);\r | |
73 | *IoTranslation = SwapBytes64 (Record->CpuBase) - IoBase;\r | |
74 | \r | |
75 | return RETURN_SUCCESS;\r | |
76 | }\r | |
77 | }\r | |
78 | return RETURN_NOT_FOUND;\r | |
79 | }\r | |
80 | \r | |
33ac4566 AB |
81 | RETURN_STATUS\r |
82 | EFIAPI\r | |
83 | FdtPciPcdProducerLibConstructor (\r | |
84 | VOID\r | |
85 | )\r | |
86 | {\r | |
87 | UINT64 PciExpressBaseAddress;\r | |
88 | FDT_CLIENT_PROTOCOL *FdtClient;\r | |
89 | CONST UINT64 *Reg;\r | |
c8f1a75a | 90 | UINT32 RegSize;\r |
33ac4566 | 91 | EFI_STATUS Status;\r |
c8f1a75a AB |
92 | INT32 Node;\r |
93 | RETURN_STATUS RetStatus;\r | |
94 | UINT64 IoTranslation;\r | |
5d1546b4 | 95 | RETURN_STATUS PcdStatus;\r |
33ac4566 AB |
96 | \r |
97 | PciExpressBaseAddress = PcdGet64 (PcdPciExpressBaseAddress);\r | |
98 | if (PciExpressBaseAddress != MAX_UINT64) {\r | |
c8f1a75a AB |
99 | //\r |
100 | // Assume that the fact that PciExpressBaseAddress has been changed from\r | |
101 | // its default value of MAX_UINT64 implies that this code has been\r | |
102 | // executed already, in the context of another module. That means we can\r | |
103 | // assume that PcdPciIoTranslation has been discovered from the DT node\r | |
104 | // as well.\r | |
105 | //\r | |
33ac4566 AB |
106 | return EFI_SUCCESS;\r |
107 | }\r | |
108 | \r | |
109 | Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL,\r | |
110 | (VOID **)&FdtClient);\r | |
111 | ASSERT_EFI_ERROR (Status);\r | |
112 | \r | |
c8f1a75a AB |
113 | PciExpressBaseAddress = 0;\r |
114 | Status = FdtClient->FindCompatibleNode (FdtClient, "pci-host-ecam-generic",\r | |
115 | &Node);\r | |
116 | \r | |
117 | if (!EFI_ERROR (Status)) {\r | |
118 | Status = FdtClient->GetNodeProperty (FdtClient, Node, "reg",\r | |
119 | (CONST VOID **)&Reg, &RegSize);\r | |
120 | \r | |
121 | if (!EFI_ERROR (Status) && RegSize == 2 * sizeof (UINT64)) {\r | |
122 | PciExpressBaseAddress = SwapBytes64 (*Reg);\r | |
33ac4566 | 123 | \r |
5d1546b4 LE |
124 | PcdStatus = PcdSetBoolS (PcdPciDisableBusEnumeration, FALSE);\r |
125 | ASSERT_RETURN_ERROR (PcdStatus);\r | |
33ac4566 | 126 | \r |
70c368e2 | 127 | IoTranslation = 0;\r |
c8f1a75a AB |
128 | RetStatus = GetPciIoTranslation (FdtClient, Node, &IoTranslation);\r |
129 | if (!RETURN_ERROR (RetStatus)) {\r | |
5d1546b4 LE |
130 | PcdStatus = PcdSet64S (PcdPciIoTranslation, IoTranslation);\r |
131 | ASSERT_RETURN_ERROR (PcdStatus);\r | |
c8f1a75a AB |
132 | } else {\r |
133 | //\r | |
134 | // Support for I/O BARs is not mandatory, and so it does not make sense\r | |
135 | // to abort in the general case. So leave it up to the actual driver to\r | |
136 | // complain about this if it wants to, and just issue a warning here.\r | |
137 | //\r | |
47719926 | 138 | DEBUG ((DEBUG_WARN,\r |
c8f1a75a AB |
139 | "%a: 'pci-host-ecam-generic' device encountered with no I/O range\n",\r |
140 | __FUNCTION__));\r | |
141 | }\r | |
142 | }\r | |
33ac4566 AB |
143 | }\r |
144 | \r | |
5d1546b4 LE |
145 | PcdStatus = PcdSet64S (PcdPciExpressBaseAddress, PciExpressBaseAddress);\r |
146 | ASSERT_RETURN_ERROR (PcdStatus);\r | |
33ac4566 AB |
147 | \r |
148 | return RETURN_SUCCESS;\r | |
149 | }\r |