2 This driver installs Single Segment Pci Configuration 2 PPI
3 to provide read, write and modify access to Pci configuration space in PEI phase.
4 To follow PI specification, these services also support access to the unaligned Pci address.
6 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <Ppi/PciCfg2.h>
13 #include <Library/BaseLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/PciLib.h>
16 #include <Library/PeimEntryPoint.h>
17 #include <Library/PeiServicesLib.h>
18 #include <IndustryStandard/Pci.h>
21 Convert EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS to PCI_LIB_ADDRESS.
23 @param Address PCI address with EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS format.
25 @return PCI address with PCI_LIB_ADDRESS format.
29 PciCfgAddressConvert (
30 EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS
*Address
33 if (Address
->ExtendedRegister
== 0) {
34 return PCI_LIB_ADDRESS (Address
->Bus
, Address
->Device
, Address
->Function
, Address
->Register
);
37 return PCI_LIB_ADDRESS (Address
->Bus
, Address
->Device
, Address
->Function
, Address
->ExtendedRegister
);
41 Reads from a given location in the PCI configuration space.
43 @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
44 @param This Pointer to local data for the interface.
45 @param Width The width of the access. Enumerated in bytes.
46 See EFI_PEI_PCI_CFG_PPI_WIDTH above.
47 @param Address The physical address of the access. The format of
48 the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
49 @param Buffer A pointer to the buffer of data.
51 @retval EFI_SUCCESS The function completed successfully.
52 @retval EFI_INVALID_PARAMETER The invalid access width.
58 IN CONST EFI_PEI_SERVICES
**PeiServices
,
59 IN CONST EFI_PEI_PCI_CFG2_PPI
*This
,
60 IN EFI_PEI_PCI_CFG_PPI_WIDTH Width
,
67 PciLibAddress
= PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS
*)&Address
);
69 if (Width
== EfiPeiPciCfgWidthUint8
) {
70 *((UINT8
*)Buffer
) = PciRead8 (PciLibAddress
);
71 } else if (Width
== EfiPeiPciCfgWidthUint16
) {
72 if ((PciLibAddress
& 0x01) == 0) {
74 // Aligned Pci address access
76 WriteUnaligned16 (((UINT16
*)Buffer
), PciRead16 (PciLibAddress
));
79 // Unaligned Pci address access, break up the request into byte by byte.
81 *((UINT8
*)Buffer
) = PciRead8 (PciLibAddress
);
82 *((UINT8
*)Buffer
+ 1) = PciRead8 (PciLibAddress
+ 1);
84 } else if (Width
== EfiPeiPciCfgWidthUint32
) {
85 if ((PciLibAddress
& 0x03) == 0) {
87 // Aligned Pci address access
89 WriteUnaligned32 (((UINT32
*)Buffer
), PciRead32 (PciLibAddress
));
90 } else if ((PciLibAddress
& 0x01) == 0) {
92 // Unaligned Pci address access, break up the request into word by word.
94 WriteUnaligned16 (((UINT16
*)Buffer
), PciRead16 (PciLibAddress
));
95 WriteUnaligned16 (((UINT16
*)Buffer
+ 1), PciRead16 (PciLibAddress
+ 2));
98 // Unaligned Pci address access, break up the request into byte by byte.
100 *((UINT8
*)Buffer
) = PciRead8 (PciLibAddress
);
101 *((UINT8
*)Buffer
+ 1) = PciRead8 (PciLibAddress
+ 1);
102 *((UINT8
*)Buffer
+ 2) = PciRead8 (PciLibAddress
+ 2);
103 *((UINT8
*)Buffer
+ 3) = PciRead8 (PciLibAddress
+ 3);
106 return EFI_INVALID_PARAMETER
;
113 Write to a given location in the PCI configuration space.
115 @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
116 @param This Pointer to local data for the interface.
117 @param Width The width of the access. Enumerated in bytes.
118 See EFI_PEI_PCI_CFG_PPI_WIDTH above.
119 @param Address The physical address of the access. The format of
120 the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
121 @param Buffer A pointer to the buffer of data.
123 @retval EFI_SUCCESS The function completed successfully.
124 @retval EFI_INVALID_PARAMETER The invalid access width.
130 IN CONST EFI_PEI_SERVICES
**PeiServices
,
131 IN CONST EFI_PEI_PCI_CFG2_PPI
*This
,
132 IN EFI_PEI_PCI_CFG_PPI_WIDTH Width
,
139 PciLibAddress
= PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS
*)&Address
);
141 if (Width
== EfiPeiPciCfgWidthUint8
) {
142 PciWrite8 (PciLibAddress
, *((UINT8
*)Buffer
));
143 } else if (Width
== EfiPeiPciCfgWidthUint16
) {
144 if ((PciLibAddress
& 0x01) == 0) {
146 // Aligned Pci address access
148 PciWrite16 (PciLibAddress
, ReadUnaligned16 ((UINT16
*)Buffer
));
151 // Unaligned Pci address access, break up the request into byte by byte.
153 PciWrite8 (PciLibAddress
, *((UINT8
*)Buffer
));
154 PciWrite8 (PciLibAddress
+ 1, *((UINT8
*)Buffer
+ 1));
156 } else if (Width
== EfiPeiPciCfgWidthUint32
) {
157 if ((PciLibAddress
& 0x03) == 0) {
159 // Aligned Pci address access
161 PciWrite32 (PciLibAddress
, ReadUnaligned32 ((UINT32
*)Buffer
));
162 } else if ((PciLibAddress
& 0x01) == 0) {
164 // Unaligned Pci address access, break up the request into word by word.
166 PciWrite16 (PciLibAddress
, ReadUnaligned16 ((UINT16
*)Buffer
));
167 PciWrite16 (PciLibAddress
+ 2, ReadUnaligned16 ((UINT16
*)Buffer
+ 1));
170 // Unaligned Pci address access, break up the request into byte by byte.
172 PciWrite8 (PciLibAddress
, *((UINT8
*)Buffer
));
173 PciWrite8 (PciLibAddress
+ 1, *((UINT8
*)Buffer
+ 1));
174 PciWrite8 (PciLibAddress
+ 2, *((UINT8
*)Buffer
+ 2));
175 PciWrite8 (PciLibAddress
+ 3, *((UINT8
*)Buffer
+ 3));
178 return EFI_INVALID_PARAMETER
;
185 This function performs a read-modify-write operation on the contents from a given
186 location in the PCI configuration space.
188 @param PeiServices An indirect pointer to the PEI Services Table
189 published by the PEI Foundation.
190 @param This Pointer to local data for the interface.
191 @param Width The width of the access. Enumerated in bytes. Type
192 EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read().
193 @param Address The physical address of the access.
194 @param SetBits Points to value to bitwise-OR with the read configuration value.
195 The size of the value is determined by Width.
196 @param ClearBits Points to the value to negate and bitwise-AND with the read configuration value.
197 The size of the value is determined by Width.
199 @retval EFI_SUCCESS The function completed successfully.
200 @retval EFI_INVALID_PARAMETER The invalid access width.
206 IN CONST EFI_PEI_SERVICES
**PeiServices
,
207 IN CONST EFI_PEI_PCI_CFG2_PPI
*This
,
208 IN EFI_PEI_PCI_CFG_PPI_WIDTH Width
,
220 PciLibAddress
= PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS
*)&Address
);
222 if (Width
== EfiPeiPciCfgWidthUint8
) {
223 PciAndThenOr8 (PciLibAddress
, (UINT8
)(~(*(UINT8
*)ClearBits
)), *((UINT8
*)SetBits
));
224 } else if (Width
== EfiPeiPciCfgWidthUint16
) {
225 if ((PciLibAddress
& 0x01) == 0) {
227 // Aligned Pci address access
229 ClearValue16
= (UINT16
)(~ReadUnaligned16 ((UINT16
*)ClearBits
));
230 SetValue16
= ReadUnaligned16 ((UINT16
*)SetBits
);
231 PciAndThenOr16 (PciLibAddress
, ClearValue16
, SetValue16
);
234 // Unaligned Pci address access, break up the request into byte by byte.
236 PciAndThenOr8 (PciLibAddress
, (UINT8
)(~(*(UINT8
*)ClearBits
)), *((UINT8
*)SetBits
));
237 PciAndThenOr8 (PciLibAddress
+ 1, (UINT8
)(~(*((UINT8
*)ClearBits
+ 1))), *((UINT8
*)SetBits
+ 1));
239 } else if (Width
== EfiPeiPciCfgWidthUint32
) {
240 if ((PciLibAddress
& 0x03) == 0) {
242 // Aligned Pci address access
244 ClearValue32
= (UINT32
)(~ReadUnaligned32 ((UINT32
*)ClearBits
));
245 SetValue32
= ReadUnaligned32 ((UINT32
*)SetBits
);
246 PciAndThenOr32 (PciLibAddress
, ClearValue32
, SetValue32
);
247 } else if ((PciLibAddress
& 0x01) == 0) {
249 // Unaligned Pci address access, break up the request into word by word.
251 ClearValue16
= (UINT16
)(~ReadUnaligned16 ((UINT16
*)ClearBits
));
252 SetValue16
= ReadUnaligned16 ((UINT16
*)SetBits
);
253 PciAndThenOr16 (PciLibAddress
, ClearValue16
, SetValue16
);
255 ClearValue16
= (UINT16
)(~ReadUnaligned16 ((UINT16
*)ClearBits
+ 1));
256 SetValue16
= ReadUnaligned16 ((UINT16
*)SetBits
+ 1);
257 PciAndThenOr16 (PciLibAddress
+ 2, ClearValue16
, SetValue16
);
260 // Unaligned Pci address access, break up the request into byte by byte.
262 PciAndThenOr8 (PciLibAddress
, (UINT8
)(~(*(UINT8
*)ClearBits
)), *((UINT8
*)SetBits
));
263 PciAndThenOr8 (PciLibAddress
+ 1, (UINT8
)(~(*((UINT8
*)ClearBits
+ 1))), *((UINT8
*)SetBits
+ 1));
264 PciAndThenOr8 (PciLibAddress
+ 2, (UINT8
)(~(*((UINT8
*)ClearBits
+ 2))), *((UINT8
*)SetBits
+ 2));
265 PciAndThenOr8 (PciLibAddress
+ 3, (UINT8
)(~(*((UINT8
*)ClearBits
+ 3))), *((UINT8
*)SetBits
+ 3));
268 return EFI_INVALID_PARAMETER
;
274 EFI_PEI_PCI_CFG2_PPI gPciCfg2Ppi
= {
281 EFI_PEI_PPI_DESCRIPTOR gPciCfg2PpiList
= {
282 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
288 Module's entry function.
289 This routine will install EFI_PEI_PCI_CFG2_PPI.
291 @param FileHandle Handle of the file being invoked.
292 @param PeiServices Describes the list of possible PEI Services.
294 @return Whether success to install service.
298 PeimInitializePciCfg (
299 IN EFI_PEI_FILE_HANDLE FileHandle
,
300 IN CONST EFI_PEI_SERVICES
**PeiServices
305 (**(EFI_PEI_SERVICES
**)PeiServices
).PciCfg
= &gPciCfg2Ppi
;
306 Status
= PeiServicesInstallPpi (&gPciCfg2PpiList
);
307 ASSERT_EFI_ERROR (Status
);