]> git.proxmox.com Git - mirror_edk2.git/blame - ArmVirtPkg/Library/FdtPciPcdProducerLib/FdtPciPcdProducerLib.c
ArmVirtPkg/FdtPciPcdProducerLib: add handling of PcdPciIoTranslation
[mirror_edk2.git] / ArmVirtPkg / Library / FdtPciPcdProducerLib / FdtPciPcdProducerLib.c
CommitLineData
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
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include <Uefi.h>\r
17\r
18#include <Library/BaseLib.h>\r
19#include <Library/DebugLib.h>\r
20#include <Library/PcdLib.h>\r
21#include <Library/UefiBootServicesTableLib.h>\r
22\r
23#include <Protocol/FdtClient.h>\r
24\r
c8f1a75a
AB
25//\r
26// We expect the "ranges" property of "pci-host-ecam-generic" to consist of\r
27// records like this.\r
28//\r
29#pragma pack (1)\r
30typedef struct {\r
31 UINT32 Type;\r
32 UINT64 ChildBase;\r
33 UINT64 CpuBase;\r
34 UINT64 Size;\r
35} DTB_PCI_HOST_RANGE_RECORD;\r
36#pragma pack ()\r
37\r
38#define DTB_PCI_HOST_RANGE_RELOCATABLE BIT31\r
39#define DTB_PCI_HOST_RANGE_PREFETCHABLE BIT30\r
40#define DTB_PCI_HOST_RANGE_ALIASED BIT29\r
41#define DTB_PCI_HOST_RANGE_MMIO32 BIT25\r
42#define DTB_PCI_HOST_RANGE_MMIO64 (BIT25 | BIT24)\r
43#define DTB_PCI_HOST_RANGE_IO BIT24\r
44#define DTB_PCI_HOST_RANGE_TYPEMASK (BIT31 | BIT30 | BIT29 | BIT25 | BIT24)\r
45\r
46STATIC\r
47RETURN_STATUS\r
48GetPciIoTranslation (\r
49 IN FDT_CLIENT_PROTOCOL *FdtClient,\r
50 IN INT32 Node,\r
51 OUT UINT64 *IoTranslation\r
52 )\r
53{\r
54 UINT32 RecordIdx;\r
55 CONST VOID *Prop;\r
56 UINT32 Len;\r
57 EFI_STATUS Status;\r
58 UINT64 IoBase;\r
59\r
60 //\r
61 // Iterate over "ranges".\r
62 //\r
63 Status = FdtClient->GetNodeProperty (FdtClient, Node, "ranges", &Prop, &Len);\r
64 if (EFI_ERROR (Status) || Len == 0 ||\r
65 Len % sizeof (DTB_PCI_HOST_RANGE_RECORD) != 0) {\r
66 DEBUG ((EFI_D_ERROR, "%a: 'ranges' not found or invalid\n", __FUNCTION__));\r
67 return RETURN_PROTOCOL_ERROR;\r
68 }\r
69\r
70 for (RecordIdx = 0; RecordIdx < Len / sizeof (DTB_PCI_HOST_RANGE_RECORD);\r
71 ++RecordIdx) {\r
72 CONST DTB_PCI_HOST_RANGE_RECORD *Record;\r
73 UINT32 Type;\r
74\r
75 Record = (CONST DTB_PCI_HOST_RANGE_RECORD *)Prop + RecordIdx;\r
76 Type = SwapBytes32 (Record->Type) & DTB_PCI_HOST_RANGE_TYPEMASK;\r
77 if (Type == DTB_PCI_HOST_RANGE_IO) {\r
78 IoBase = SwapBytes64 (Record->ChildBase);\r
79 *IoTranslation = SwapBytes64 (Record->CpuBase) - IoBase;\r
80\r
81 return RETURN_SUCCESS;\r
82 }\r
83 }\r
84 return RETURN_NOT_FOUND;\r
85}\r
86\r
33ac4566
AB
87RETURN_STATUS\r
88EFIAPI\r
89FdtPciPcdProducerLibConstructor (\r
90 VOID\r
91 )\r
92{\r
93 UINT64 PciExpressBaseAddress;\r
94 FDT_CLIENT_PROTOCOL *FdtClient;\r
95 CONST UINT64 *Reg;\r
c8f1a75a 96 UINT32 RegSize;\r
33ac4566 97 EFI_STATUS Status;\r
c8f1a75a
AB
98 INT32 Node;\r
99 RETURN_STATUS RetStatus;\r
100 UINT64 IoTranslation;\r
33ac4566
AB
101\r
102 PciExpressBaseAddress = PcdGet64 (PcdPciExpressBaseAddress);\r
103 if (PciExpressBaseAddress != MAX_UINT64) {\r
c8f1a75a
AB
104 //\r
105 // Assume that the fact that PciExpressBaseAddress has been changed from\r
106 // its default value of MAX_UINT64 implies that this code has been\r
107 // executed already, in the context of another module. That means we can\r
108 // assume that PcdPciIoTranslation has been discovered from the DT node\r
109 // as well.\r
110 //\r
33ac4566
AB
111 return EFI_SUCCESS;\r
112 }\r
113\r
114 Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL,\r
115 (VOID **)&FdtClient);\r
116 ASSERT_EFI_ERROR (Status);\r
117\r
c8f1a75a
AB
118 PciExpressBaseAddress = 0;\r
119 Status = FdtClient->FindCompatibleNode (FdtClient, "pci-host-ecam-generic",\r
120 &Node);\r
121\r
122 if (!EFI_ERROR (Status)) {\r
123 Status = FdtClient->GetNodeProperty (FdtClient, Node, "reg",\r
124 (CONST VOID **)&Reg, &RegSize);\r
125\r
126 if (!EFI_ERROR (Status) && RegSize == 2 * sizeof (UINT64)) {\r
127 PciExpressBaseAddress = SwapBytes64 (*Reg);\r
33ac4566 128\r
c8f1a75a 129 PcdSetBool (PcdPciDisableBusEnumeration, FALSE);\r
33ac4566 130\r
c8f1a75a
AB
131 RetStatus = GetPciIoTranslation (FdtClient, Node, &IoTranslation);\r
132 if (!RETURN_ERROR (RetStatus)) {\r
133 PcdSet64 (PcdPciIoTranslation, IoTranslation);\r
134 } else {\r
135 //\r
136 // Support for I/O BARs is not mandatory, and so it does not make sense\r
137 // to abort in the general case. So leave it up to the actual driver to\r
138 // complain about this if it wants to, and just issue a warning here.\r
139 //\r
140 DEBUG ((EFI_D_WARN,\r
141 "%a: 'pci-host-ecam-generic' device encountered with no I/O range\n",\r
142 __FUNCTION__));\r
143 }\r
144 }\r
33ac4566
AB
145 }\r
146\r
147 PcdSet64 (PcdPciExpressBaseAddress, PciExpressBaseAddress);\r
148\r
149 return RETURN_SUCCESS;\r
150}\r