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 - 2010, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include <Ppi/PciCfg2.h>
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/PciLib.h>
22 #include <Library/PeimEntryPoint.h>
23 #include <Library/PeiServicesLib.h>
24 #include <IndustryStandard/Pci.h>
27 Convert EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS to PCI_LIB_ADDRESS.
29 @param Address PCI address with EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS format.
31 @return PCI address with PCI_LIB_ADDRESS format.
35 PciCfgAddressConvert (
36 EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS
*Address
39 if (Address
->ExtendedRegister
== 0) {
40 return PCI_LIB_ADDRESS (Address
->Bus
, Address
->Device
, Address
->Function
, Address
->Register
);
43 return PCI_LIB_ADDRESS (Address
->Bus
, Address
->Device
, Address
->Function
, Address
->ExtendedRegister
);
47 Reads from a given location in the PCI configuration space.
49 @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
50 @param This Pointer to local data for the interface.
51 @param Width The width of the access. Enumerated in bytes.
52 See EFI_PEI_PCI_CFG_PPI_WIDTH above.
53 @param Address The physical address of the access. The format of
54 the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
55 @param Buffer A pointer to the buffer of data.
57 @retval EFI_SUCCESS The function completed successfully.
58 @retval EFI_INVALID_PARAMETER The invalid access width.
64 IN CONST EFI_PEI_SERVICES
**PeiServices
,
65 IN CONST EFI_PEI_PCI_CFG2_PPI
*This
,
66 IN EFI_PEI_PCI_CFG_PPI_WIDTH Width
,
73 PciLibAddress
= PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS
*) &Address
);
75 if (Width
== EfiPeiPciCfgWidthUint8
) {
76 *((UINT8
*) Buffer
) = PciRead8 (PciLibAddress
);
77 } else if (Width
== EfiPeiPciCfgWidthUint16
) {
78 if ((PciLibAddress
& 0x01) == 0) {
80 // Aligned Pci address access
82 WriteUnaligned16 (((UINT16
*) Buffer
), PciRead16 (PciLibAddress
));
85 // Unaligned Pci address access, break up the request into byte by byte.
87 *((UINT8
*) Buffer
) = PciRead8 (PciLibAddress
);
88 *((UINT8
*) Buffer
+ 1) = PciRead8 (PciLibAddress
+ 1);
90 } else if (Width
== EfiPeiPciCfgWidthUint32
) {
91 if ((PciLibAddress
& 0x03) == 0) {
93 // Aligned Pci address access
95 WriteUnaligned32 (((UINT32
*) Buffer
), PciRead32 (PciLibAddress
));
96 } else if ((PciLibAddress
& 0x01) == 0) {
98 // Unaligned Pci address access, break up the request into word by word.
100 WriteUnaligned16 (((UINT16
*) Buffer
), PciRead16 (PciLibAddress
));
101 WriteUnaligned16 (((UINT16
*) Buffer
+ 1), PciRead16 (PciLibAddress
+ 2));
104 // Unaligned Pci address access, break up the request into byte by byte.
106 *((UINT8
*) Buffer
) = PciRead8 (PciLibAddress
);
107 *((UINT8
*) Buffer
+ 1) = PciRead8 (PciLibAddress
+ 1);
108 *((UINT8
*) Buffer
+ 2) = PciRead8 (PciLibAddress
+ 2);
109 *((UINT8
*) Buffer
+ 3) = PciRead8 (PciLibAddress
+ 3);
112 return EFI_INVALID_PARAMETER
;
119 Write to a given location in the PCI configuration space.
121 @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
122 @param This Pointer to local data for the interface.
123 @param Width The width of the access. Enumerated in bytes.
124 See EFI_PEI_PCI_CFG_PPI_WIDTH above.
125 @param Address The physical address of the access. The format of
126 the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
127 @param Buffer A pointer to the buffer of data.
129 @retval EFI_SUCCESS The function completed successfully.
130 @retval EFI_INVALID_PARAMETER The invalid access width.
136 IN CONST EFI_PEI_SERVICES
**PeiServices
,
137 IN CONST EFI_PEI_PCI_CFG2_PPI
*This
,
138 IN EFI_PEI_PCI_CFG_PPI_WIDTH Width
,
145 PciLibAddress
= PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS
*) &Address
);
147 if (Width
== EfiPeiPciCfgWidthUint8
) {
148 PciWrite8 (PciLibAddress
, *((UINT8
*) Buffer
));
149 } else if (Width
== EfiPeiPciCfgWidthUint16
) {
150 if ((PciLibAddress
& 0x01) == 0) {
152 // Aligned Pci address access
154 PciWrite16 (PciLibAddress
, ReadUnaligned16 ((UINT16
*) Buffer
));
157 // Unaligned Pci address access, break up the request into byte by byte.
159 PciWrite8 (PciLibAddress
, *((UINT8
*) Buffer
));
160 PciWrite8 (PciLibAddress
+ 1, *((UINT8
*) Buffer
+ 1));
162 } else if (Width
== EfiPeiPciCfgWidthUint32
) {
163 if ((PciLibAddress
& 0x03) == 0) {
165 // Aligned Pci address access
167 PciWrite32 (PciLibAddress
, ReadUnaligned32 ((UINT32
*) Buffer
));
168 } else if ((PciLibAddress
& 0x01) == 0) {
170 // Unaligned Pci address access, break up the request into word by word.
172 PciWrite16 (PciLibAddress
, ReadUnaligned16 ((UINT16
*) Buffer
));
173 PciWrite16 (PciLibAddress
+ 2, ReadUnaligned16 ((UINT16
*) Buffer
+ 1));
176 // Unaligned Pci address access, break up the request into byte by byte.
178 PciWrite8 (PciLibAddress
, *((UINT8
*) Buffer
));
179 PciWrite8 (PciLibAddress
+ 1, *((UINT8
*) Buffer
+ 1));
180 PciWrite8 (PciLibAddress
+ 2, *((UINT8
*) Buffer
+ 2));
181 PciWrite8 (PciLibAddress
+ 3, *((UINT8
*) Buffer
+ 3));
184 return EFI_INVALID_PARAMETER
;
192 This function performs a read-modify-write operation on the contents from a given
193 location in the PCI configuration space.
195 @param PeiServices An indirect pointer to the PEI Services Table
196 published by the PEI Foundation.
197 @param This Pointer to local data for the interface.
198 @param Width The width of the access. Enumerated in bytes. Type
199 EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read().
200 @param Address The physical address of the access.
201 @param SetBits Points to value to bitwise-OR with the read configuration value.
202 The size of the value is determined by Width.
203 @param ClearBits Points to the value to negate and bitwise-AND with the read configuration value.
204 The size of the value is determined by Width.
206 @retval EFI_SUCCESS The function completed successfully.
207 @retval EFI_INVALID_PARAMETER The invalid access width.
213 IN CONST EFI_PEI_SERVICES
**PeiServices
,
214 IN CONST EFI_PEI_PCI_CFG2_PPI
*This
,
215 IN EFI_PEI_PCI_CFG_PPI_WIDTH Width
,
227 PciLibAddress
= PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS
*) &Address
);
229 if (Width
== EfiPeiPciCfgWidthUint8
) {
230 PciAndThenOr8 (PciLibAddress
, (UINT8
) (~(*(UINT8
*) ClearBits
)), *((UINT8
*) SetBits
));
231 } else if (Width
== EfiPeiPciCfgWidthUint16
) {
232 if ((PciLibAddress
& 0x01) == 0) {
234 // Aligned Pci address access
236 ClearValue16
= (UINT16
) (~ReadUnaligned16 ((UINT16
*) ClearBits
));
237 SetValue16
= ReadUnaligned16 ((UINT16
*) SetBits
);
238 PciAndThenOr16 (PciLibAddress
, ClearValue16
, SetValue16
);
241 // Unaligned Pci address access, break up the request into byte by byte.
243 PciAndThenOr8 (PciLibAddress
, (UINT8
) (~(*(UINT8
*) ClearBits
)), *((UINT8
*) SetBits
));
244 PciAndThenOr8 (PciLibAddress
+ 1, (UINT8
) (~(*((UINT8
*) ClearBits
+ 1))), *((UINT8
*) SetBits
+ 1));
246 } else if (Width
== EfiPeiPciCfgWidthUint32
) {
247 if ((PciLibAddress
& 0x03) == 0) {
249 // Aligned Pci address access
251 ClearValue32
= (UINT32
) (~ReadUnaligned32 ((UINT32
*) ClearBits
));
252 SetValue32
= ReadUnaligned32 ((UINT32
*) SetBits
);
253 PciAndThenOr32 (PciLibAddress
, ClearValue32
, SetValue32
);
254 } else if ((PciLibAddress
& 0x01) == 0) {
256 // Unaligned Pci address access, break up the request into word by word.
258 ClearValue16
= (UINT16
) (~ReadUnaligned16 ((UINT16
*) ClearBits
));
259 SetValue16
= ReadUnaligned16 ((UINT16
*) SetBits
);
260 PciAndThenOr16 (PciLibAddress
, ClearValue16
, SetValue16
);
262 ClearValue16
= (UINT16
) (~ReadUnaligned16 ((UINT16
*) ClearBits
+ 1));
263 SetValue16
= ReadUnaligned16 ((UINT16
*) SetBits
+ 1);
264 PciAndThenOr16 (PciLibAddress
+ 2, ClearValue16
, SetValue16
);
267 // Unaligned Pci address access, break up the request into byte by byte.
269 PciAndThenOr8 (PciLibAddress
, (UINT8
) (~(*(UINT8
*) ClearBits
)), *((UINT8
*) SetBits
));
270 PciAndThenOr8 (PciLibAddress
+ 1, (UINT8
) (~(*((UINT8
*) ClearBits
+ 1))), *((UINT8
*) SetBits
+ 1));
271 PciAndThenOr8 (PciLibAddress
+ 2, (UINT8
) (~(*((UINT8
*) ClearBits
+ 2))), *((UINT8
*) SetBits
+ 2));
272 PciAndThenOr8 (PciLibAddress
+ 3, (UINT8
) (~(*((UINT8
*) ClearBits
+ 3))), *((UINT8
*) SetBits
+ 3));
275 return EFI_INVALID_PARAMETER
;
281 EFI_PEI_PCI_CFG2_PPI gPciCfg2Ppi
= {
288 EFI_PEI_PPI_DESCRIPTOR gPciCfg2PpiList
= {
289 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
295 Module's entry function.
296 This routine will install EFI_PEI_PCI_CFG2_PPI.
298 @param FileHandle Handle of the file being invoked.
299 @param PeiServices Describes the list of possible PEI Services.
301 @return Whether success to install service.
305 PeimInitializePciCfg (
306 IN EFI_PEI_FILE_HANDLE FileHandle
,
307 IN CONST EFI_PEI_SERVICES
**PeiServices
312 (**(EFI_PEI_SERVICES
**)PeiServices
).PciCfg
= &gPciCfg2Ppi
;
313 Status
= PeiServicesInstallPpi (&gPciCfg2PpiList
);
314 ASSERT_EFI_ERROR (Status
);