]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PciCfg2.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / PcatSingleSegmentPciCfg2Pei / PciCfg2.c
CommitLineData
fb0b259e 1/** @file\r
d1102dba
LG
2 This driver installs Single Segment Pci Configuration 2 PPI\r
3 to provide read, write and modify access to Pci configuration space in PEI phase.\r
109e9a61 4 To follow PI specification, these services also support access to the unaligned Pci address.\r
12232778 5\r
d1102dba 6 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
12232778 8\r
9**/\r
10\r
11#include <PiPei.h>\r
12232778 12#include <Ppi/PciCfg2.h>\r
12232778 13#include <Library/BaseLib.h>\r
14#include <Library/DebugLib.h>\r
15#include <Library/PciLib.h>\r
16#include <Library/PeimEntryPoint.h>\r
77dfa7c7 17#include <Library/PeiServicesLib.h>\r
2d85ada2 18#include <IndustryStandard/Pci.h>\r
12232778 19\r
aa79b0b3 20/**\r
21 Convert EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS to PCI_LIB_ADDRESS.\r
22\r
109e9a61 23 @param Address PCI address with EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS format.\r
aa79b0b3 24\r
109e9a61 25 @return PCI address with PCI_LIB_ADDRESS format.\r
aa79b0b3 26\r
27**/\r
28UINTN\r
29PciCfgAddressConvert (\r
30 EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *Address\r
31 )\r
32{\r
33 if (Address->ExtendedRegister == 0) {\r
34 return PCI_LIB_ADDRESS (Address->Bus, Address->Device, Address->Function, Address->Register);\r
35 }\r
36\r
37 return PCI_LIB_ADDRESS (Address->Bus, Address->Device, Address->Function, Address->ExtendedRegister);\r
38}\r
39\r
12232778 40/**\r
41 Reads from a given location in the PCI configuration space.\r
42\r
43 @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.\r
12232778 44 @param This Pointer to local data for the interface.\r
12232778 45 @param Width The width of the access. Enumerated in bytes.\r
46 See EFI_PEI_PCI_CFG_PPI_WIDTH above.\r
12232778 47 @param Address The physical address of the access. The format of\r
48 the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.\r
109e9a61 49 @param Buffer A pointer to the buffer of data.\r
12232778 50\r
51 @retval EFI_SUCCESS The function completed successfully.\r
109e9a61 52 @retval EFI_INVALID_PARAMETER The invalid access width.\r
d1102dba 53\r
12232778 54**/\r
55EFI_STATUS\r
fb0b259e 56EFIAPI\r
12232778 57PciCfg2Read (\r
58 IN CONST EFI_PEI_SERVICES **PeiServices,\r
59 IN CONST EFI_PEI_PCI_CFG2_PPI *This,\r
60 IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,\r
61 IN UINT64 Address,\r
62 IN OUT VOID *Buffer\r
cebc8d48 63 )\r
12232778 64{\r
65 UINTN PciLibAddress;\r
66\r
d8b61daa 67 PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address);\r
12232778 68\r
69 if (Width == EfiPeiPciCfgWidthUint8) {\r
70 *((UINT8 *) Buffer) = PciRead8 (PciLibAddress);\r
71 } else if (Width == EfiPeiPciCfgWidthUint16) {\r
8501ba4c
LG
72 if ((PciLibAddress & 0x01) == 0) {\r
73 //\r
74 // Aligned Pci address access\r
75 //\r
76 WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress));\r
77 } else {\r
78 //\r
79 // Unaligned Pci address access, break up the request into byte by byte.\r
80 //\r
81 *((UINT8 *) Buffer) = PciRead8 (PciLibAddress);\r
82 *((UINT8 *) Buffer + 1) = PciRead8 (PciLibAddress + 1);\r
83 }\r
12232778 84 } else if (Width == EfiPeiPciCfgWidthUint32) {\r
8501ba4c
LG
85 if ((PciLibAddress & 0x03) == 0) {\r
86 //\r
87 // Aligned Pci address access\r
88 //\r
89 WriteUnaligned32 (((UINT32 *) Buffer), PciRead32 (PciLibAddress));\r
90 } else if ((PciLibAddress & 0x01) == 0) {\r
91 //\r
92 // Unaligned Pci address access, break up the request into word by word.\r
93 //\r
94 WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress));\r
95 WriteUnaligned16 (((UINT16 *) Buffer + 1), PciRead16 (PciLibAddress + 2));\r
96 } else {\r
97 //\r
98 // Unaligned Pci address access, break up the request into byte by byte.\r
99 //\r
100 *((UINT8 *) Buffer) = PciRead8 (PciLibAddress);\r
101 *((UINT8 *) Buffer + 1) = PciRead8 (PciLibAddress + 1);\r
102 *((UINT8 *) Buffer + 2) = PciRead8 (PciLibAddress + 2);\r
103 *((UINT8 *) Buffer + 3) = PciRead8 (PciLibAddress + 3);\r
104 }\r
12232778 105 } else {\r
106 return EFI_INVALID_PARAMETER;\r
107 }\r
108\r
109 return EFI_SUCCESS;\r
110}\r
111\r
112/**\r
113 Write to a given location in the PCI configuration space.\r
114\r
115 @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.\r
12232778 116 @param This Pointer to local data for the interface.\r
12232778 117 @param Width The width of the access. Enumerated in bytes.\r
118 See EFI_PEI_PCI_CFG_PPI_WIDTH above.\r
12232778 119 @param Address The physical address of the access. The format of\r
120 the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.\r
109e9a61 121 @param Buffer A pointer to the buffer of data.\r
12232778 122\r
123 @retval EFI_SUCCESS The function completed successfully.\r
109e9a61 124 @retval EFI_INVALID_PARAMETER The invalid access width.\r
12232778 125\r
126**/\r
127EFI_STATUS\r
fb0b259e 128EFIAPI\r
12232778 129PciCfg2Write (\r
130 IN CONST EFI_PEI_SERVICES **PeiServices,\r
131 IN CONST EFI_PEI_PCI_CFG2_PPI *This,\r
132 IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,\r
133 IN UINT64 Address,\r
134 IN OUT VOID *Buffer\r
cebc8d48 135 )\r
12232778 136{\r
137 UINTN PciLibAddress;\r
138\r
d8b61daa 139 PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address);\r
12232778 140\r
141 if (Width == EfiPeiPciCfgWidthUint8) {\r
142 PciWrite8 (PciLibAddress, *((UINT8 *) Buffer));\r
143 } else if (Width == EfiPeiPciCfgWidthUint16) {\r
8501ba4c
LG
144 if ((PciLibAddress & 0x01) == 0) {\r
145 //\r
146 // Aligned Pci address access\r
147 //\r
148 PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer));\r
149 } else {\r
150 //\r
151 // Unaligned Pci address access, break up the request into byte by byte.\r
152 //\r
153 PciWrite8 (PciLibAddress, *((UINT8 *) Buffer));\r
d1102dba 154 PciWrite8 (PciLibAddress + 1, *((UINT8 *) Buffer + 1));\r
8501ba4c 155 }\r
12232778 156 } else if (Width == EfiPeiPciCfgWidthUint32) {\r
8501ba4c
LG
157 if ((PciLibAddress & 0x03) == 0) {\r
158 //\r
159 // Aligned Pci address access\r
160 //\r
161 PciWrite32 (PciLibAddress, ReadUnaligned32 ((UINT32 *) Buffer));\r
162 } else if ((PciLibAddress & 0x01) == 0) {\r
163 //\r
164 // Unaligned Pci address access, break up the request into word by word.\r
165 //\r
166 PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer));\r
167 PciWrite16 (PciLibAddress + 2, ReadUnaligned16 ((UINT16 *) Buffer + 1));\r
168 } else {\r
169 //\r
170 // Unaligned Pci address access, break up the request into byte by byte.\r
171 //\r
172 PciWrite8 (PciLibAddress, *((UINT8 *) Buffer));\r
d1102dba
LG
173 PciWrite8 (PciLibAddress + 1, *((UINT8 *) Buffer + 1));\r
174 PciWrite8 (PciLibAddress + 2, *((UINT8 *) Buffer + 2));\r
175 PciWrite8 (PciLibAddress + 3, *((UINT8 *) Buffer + 3));\r
8501ba4c 176 }\r
12232778 177 } else {\r
178 return EFI_INVALID_PARAMETER;\r
179 }\r
180\r
181 return EFI_SUCCESS;\r
182}\r
183\r
184\r
185/**\r
109e9a61
LG
186 This function performs a read-modify-write operation on the contents from a given\r
187 location in the PCI configuration space.\r
12232778 188\r
189 @param PeiServices An indirect pointer to the PEI Services Table\r
190 published by the PEI Foundation.\r
12232778 191 @param This Pointer to local data for the interface.\r
12232778 192 @param Width The width of the access. Enumerated in bytes. Type\r
193 EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read().\r
12232778 194 @param Address The physical address of the access.\r
12232778 195 @param SetBits Points to value to bitwise-OR with the read configuration value.\r
12232778 196 The size of the value is determined by Width.\r
12232778 197 @param ClearBits Points to the value to negate and bitwise-AND with the read configuration value.\r
198 The size of the value is determined by Width.\r
199\r
12232778 200 @retval EFI_SUCCESS The function completed successfully.\r
109e9a61 201 @retval EFI_INVALID_PARAMETER The invalid access width.\r
12232778 202\r
203**/\r
204EFI_STATUS\r
fb0b259e 205EFIAPI\r
12232778 206PciCfg2Modify (\r
207 IN CONST EFI_PEI_SERVICES **PeiServices,\r
208 IN CONST EFI_PEI_PCI_CFG2_PPI *This,\r
209 IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,\r
210 IN UINT64 Address,\r
01edaf2a 211 IN VOID *SetBits,\r
212 IN VOID *ClearBits\r
cebc8d48 213 )\r
12232778 214{\r
702887db 215 UINTN PciLibAddress;\r
216 UINT16 ClearValue16;\r
217 UINT16 SetValue16;\r
218 UINT32 ClearValue32;\r
219 UINT32 SetValue32;\r
12232778 220\r
d8b61daa 221 PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address);\r
12232778 222\r
223 if (Width == EfiPeiPciCfgWidthUint8) {\r
702887db 224 PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits));\r
12232778 225 } else if (Width == EfiPeiPciCfgWidthUint16) {\r
8501ba4c
LG
226 if ((PciLibAddress & 0x01) == 0) {\r
227 //\r
228 // Aligned Pci address access\r
229 //\r
230 ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits));\r
231 SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits);\r
232 PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16);\r
233 } else {\r
234 //\r
235 // Unaligned Pci address access, break up the request into byte by byte.\r
236 //\r
237 PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits));\r
238 PciAndThenOr8 (PciLibAddress + 1, (UINT8) (~(*((UINT8 *) ClearBits + 1))), *((UINT8 *) SetBits + 1));\r
239 }\r
12232778 240 } else if (Width == EfiPeiPciCfgWidthUint32) {\r
8501ba4c
LG
241 if ((PciLibAddress & 0x03) == 0) {\r
242 //\r
243 // Aligned Pci address access\r
244 //\r
245 ClearValue32 = (UINT32) (~ReadUnaligned32 ((UINT32 *) ClearBits));\r
246 SetValue32 = ReadUnaligned32 ((UINT32 *) SetBits);\r
247 PciAndThenOr32 (PciLibAddress, ClearValue32, SetValue32);\r
248 } else if ((PciLibAddress & 0x01) == 0) {\r
249 //\r
250 // Unaligned Pci address access, break up the request into word by word.\r
251 //\r
252 ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits));\r
253 SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits);\r
254 PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16);\r
255\r
256 ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits + 1));\r
257 SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits + 1);\r
258 PciAndThenOr16 (PciLibAddress + 2, ClearValue16, SetValue16);\r
259 } else {\r
260 //\r
261 // Unaligned Pci address access, break up the request into byte by byte.\r
262 //\r
263 PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits));\r
264 PciAndThenOr8 (PciLibAddress + 1, (UINT8) (~(*((UINT8 *) ClearBits + 1))), *((UINT8 *) SetBits + 1));\r
265 PciAndThenOr8 (PciLibAddress + 2, (UINT8) (~(*((UINT8 *) ClearBits + 2))), *((UINT8 *) SetBits + 2));\r
266 PciAndThenOr8 (PciLibAddress + 3, (UINT8) (~(*((UINT8 *) ClearBits + 3))), *((UINT8 *) SetBits + 3));\r
267 }\r
12232778 268 } else {\r
269 return EFI_INVALID_PARAMETER;\r
270 }\r
109e9a61 271\r
12232778 272 return EFI_SUCCESS;\r
273}\r
274\r
109e9a61
LG
275EFI_PEI_PCI_CFG2_PPI gPciCfg2Ppi = {\r
276 PciCfg2Read,\r
277 PciCfg2Write,\r
278 PciCfg2Modify,\r
279 0\r
280};\r
281\r
282EFI_PEI_PPI_DESCRIPTOR gPciCfg2PpiList = {\r
283 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
284 &gEfiPciCfg2PpiGuid,\r
285 &gPciCfg2Ppi\r
286};\r
287\r
cebc8d48 288/**\r
d1102dba 289 Module's entry function.\r
cebc8d48 290 This routine will install EFI_PEI_PCI_CFG2_PPI.\r
d1102dba 291\r
cebc8d48
LG
292 @param FileHandle Handle of the file being invoked.\r
293 @param PeiServices Describes the list of possible PEI Services.\r
12232778 294\r
cebc8d48
LG
295 @return Whether success to install service.\r
296**/\r
12232778 297EFI_STATUS\r
298EFIAPI\r
299PeimInitializePciCfg (\r
8bd22b8a
LG
300 IN EFI_PEI_FILE_HANDLE FileHandle,\r
301 IN CONST EFI_PEI_SERVICES **PeiServices\r
12232778 302 )\r
303{\r
304 EFI_STATUS Status;\r
305\r
8bd22b8a 306 (**(EFI_PEI_SERVICES **)PeiServices).PciCfg = &gPciCfg2Ppi;\r
77dfa7c7 307 Status = PeiServicesInstallPpi (&gPciCfg2PpiList);\r
308 ASSERT_EFI_ERROR (Status);\r
12232778 309\r
310 return Status;\r
311}\r