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 - 2008, Intel Corporation
7 All rights reserved. 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 <IndustryStandard/Pci.h>
26 Convert EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS to PCI_LIB_ADDRESS.
28 @param Address PCI address with EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS format.
30 @return PCI address with PCI_LIB_ADDRESS format.
34 PciCfgAddressConvert (
35 EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS
*Address
38 if (Address
->ExtendedRegister
== 0) {
39 return PCI_LIB_ADDRESS (Address
->Bus
, Address
->Device
, Address
->Function
, Address
->Register
);
42 return PCI_LIB_ADDRESS (Address
->Bus
, Address
->Device
, Address
->Function
, Address
->ExtendedRegister
);
46 Reads from a given location in the PCI configuration space.
48 @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
49 @param This Pointer to local data for the interface.
50 @param Width The width of the access. Enumerated in bytes.
51 See EFI_PEI_PCI_CFG_PPI_WIDTH above.
52 @param Address The physical address of the access. The format of
53 the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
54 @param Buffer A pointer to the buffer of data.
56 @retval EFI_SUCCESS The function completed successfully.
57 @retval EFI_INVALID_PARAMETER The invalid access width.
63 IN CONST EFI_PEI_SERVICES
**PeiServices
,
64 IN CONST EFI_PEI_PCI_CFG2_PPI
*This
,
65 IN EFI_PEI_PCI_CFG_PPI_WIDTH Width
,
72 PciLibAddress
= PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS
*) &Address
);
74 if (Width
== EfiPeiPciCfgWidthUint8
) {
75 *((UINT8
*) Buffer
) = PciRead8 (PciLibAddress
);
76 } else if (Width
== EfiPeiPciCfgWidthUint16
) {
77 if ((PciLibAddress
& 0x01) == 0) {
79 // Aligned Pci address access
81 WriteUnaligned16 (((UINT16
*) Buffer
), PciRead16 (PciLibAddress
));
84 // Unaligned Pci address access, break up the request into byte by byte.
86 *((UINT8
*) Buffer
) = PciRead8 (PciLibAddress
);
87 *((UINT8
*) Buffer
+ 1) = PciRead8 (PciLibAddress
+ 1);
89 } else if (Width
== EfiPeiPciCfgWidthUint32
) {
90 if ((PciLibAddress
& 0x03) == 0) {
92 // Aligned Pci address access
94 WriteUnaligned32 (((UINT32
*) Buffer
), PciRead32 (PciLibAddress
));
95 } else if ((PciLibAddress
& 0x01) == 0) {
97 // Unaligned Pci address access, break up the request into word by word.
99 WriteUnaligned16 (((UINT16
*) Buffer
), PciRead16 (PciLibAddress
));
100 WriteUnaligned16 (((UINT16
*) Buffer
+ 1), PciRead16 (PciLibAddress
+ 2));
103 // Unaligned Pci address access, break up the request into byte by byte.
105 *((UINT8
*) Buffer
) = PciRead8 (PciLibAddress
);
106 *((UINT8
*) Buffer
+ 1) = PciRead8 (PciLibAddress
+ 1);
107 *((UINT8
*) Buffer
+ 2) = PciRead8 (PciLibAddress
+ 2);
108 *((UINT8
*) Buffer
+ 3) = PciRead8 (PciLibAddress
+ 3);
111 return EFI_INVALID_PARAMETER
;
118 Write to a given location in the PCI configuration space.
120 @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
121 @param This Pointer to local data for the interface.
122 @param Width The width of the access. Enumerated in bytes.
123 See EFI_PEI_PCI_CFG_PPI_WIDTH above.
124 @param Address The physical address of the access. The format of
125 the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
126 @param Buffer A pointer to the buffer of data.
128 @retval EFI_SUCCESS The function completed successfully.
129 @retval EFI_INVALID_PARAMETER The invalid access width.
135 IN CONST EFI_PEI_SERVICES
**PeiServices
,
136 IN CONST EFI_PEI_PCI_CFG2_PPI
*This
,
137 IN EFI_PEI_PCI_CFG_PPI_WIDTH Width
,
144 PciLibAddress
= PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS
*) &Address
);
146 if (Width
== EfiPeiPciCfgWidthUint8
) {
147 PciWrite8 (PciLibAddress
, *((UINT8
*) Buffer
));
148 } else if (Width
== EfiPeiPciCfgWidthUint16
) {
149 if ((PciLibAddress
& 0x01) == 0) {
151 // Aligned Pci address access
153 PciWrite16 (PciLibAddress
, ReadUnaligned16 ((UINT16
*) Buffer
));
156 // Unaligned Pci address access, break up the request into byte by byte.
158 PciWrite8 (PciLibAddress
, *((UINT8
*) Buffer
));
159 PciWrite8 (PciLibAddress
+ 1, *((UINT8
*) Buffer
+ 1));
161 } else if (Width
== EfiPeiPciCfgWidthUint32
) {
162 if ((PciLibAddress
& 0x03) == 0) {
164 // Aligned Pci address access
166 PciWrite32 (PciLibAddress
, ReadUnaligned32 ((UINT32
*) Buffer
));
167 } else if ((PciLibAddress
& 0x01) == 0) {
169 // Unaligned Pci address access, break up the request into word by word.
171 PciWrite16 (PciLibAddress
, ReadUnaligned16 ((UINT16
*) Buffer
));
172 PciWrite16 (PciLibAddress
+ 2, ReadUnaligned16 ((UINT16
*) Buffer
+ 1));
175 // Unaligned Pci address access, break up the request into byte by byte.
177 PciWrite8 (PciLibAddress
, *((UINT8
*) Buffer
));
178 PciWrite8 (PciLibAddress
+ 1, *((UINT8
*) Buffer
+ 1));
179 PciWrite8 (PciLibAddress
+ 2, *((UINT8
*) Buffer
+ 2));
180 PciWrite8 (PciLibAddress
+ 3, *((UINT8
*) Buffer
+ 3));
183 return EFI_INVALID_PARAMETER
;
191 This function performs a read-modify-write operation on the contents from a given
192 location in the PCI configuration space.
194 @param PeiServices An indirect pointer to the PEI Services Table
195 published by the PEI Foundation.
196 @param This Pointer to local data for the interface.
197 @param Width The width of the access. Enumerated in bytes. Type
198 EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read().
199 @param Address The physical address of the access.
200 @param SetBits Points to value to bitwise-OR with the read configuration value.
201 The size of the value is determined by Width.
202 @param ClearBits Points to the value to negate and bitwise-AND with the read configuration value.
203 The size of the value is determined by Width.
205 @retval EFI_SUCCESS The function completed successfully.
206 @retval EFI_INVALID_PARAMETER The invalid access width.
212 IN CONST EFI_PEI_SERVICES
**PeiServices
,
213 IN CONST EFI_PEI_PCI_CFG2_PPI
*This
,
214 IN EFI_PEI_PCI_CFG_PPI_WIDTH Width
,
226 PciLibAddress
= PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS
*) &Address
);
228 if (Width
== EfiPeiPciCfgWidthUint8
) {
229 PciAndThenOr8 (PciLibAddress
, (UINT8
) (~(*(UINT8
*) ClearBits
)), *((UINT8
*) SetBits
));
230 } else if (Width
== EfiPeiPciCfgWidthUint16
) {
231 if ((PciLibAddress
& 0x01) == 0) {
233 // Aligned Pci address access
235 ClearValue16
= (UINT16
) (~ReadUnaligned16 ((UINT16
*) ClearBits
));
236 SetValue16
= ReadUnaligned16 ((UINT16
*) SetBits
);
237 PciAndThenOr16 (PciLibAddress
, ClearValue16
, SetValue16
);
240 // Unaligned Pci address access, break up the request into byte by byte.
242 PciAndThenOr8 (PciLibAddress
, (UINT8
) (~(*(UINT8
*) ClearBits
)), *((UINT8
*) SetBits
));
243 PciAndThenOr8 (PciLibAddress
+ 1, (UINT8
) (~(*((UINT8
*) ClearBits
+ 1))), *((UINT8
*) SetBits
+ 1));
245 } else if (Width
== EfiPeiPciCfgWidthUint32
) {
246 if ((PciLibAddress
& 0x03) == 0) {
248 // Aligned Pci address access
250 ClearValue32
= (UINT32
) (~ReadUnaligned32 ((UINT32
*) ClearBits
));
251 SetValue32
= ReadUnaligned32 ((UINT32
*) SetBits
);
252 PciAndThenOr32 (PciLibAddress
, ClearValue32
, SetValue32
);
253 } else if ((PciLibAddress
& 0x01) == 0) {
255 // Unaligned Pci address access, break up the request into word by word.
257 ClearValue16
= (UINT16
) (~ReadUnaligned16 ((UINT16
*) ClearBits
));
258 SetValue16
= ReadUnaligned16 ((UINT16
*) SetBits
);
259 PciAndThenOr16 (PciLibAddress
, ClearValue16
, SetValue16
);
261 ClearValue16
= (UINT16
) (~ReadUnaligned16 ((UINT16
*) ClearBits
+ 1));
262 SetValue16
= ReadUnaligned16 ((UINT16
*) SetBits
+ 1);
263 PciAndThenOr16 (PciLibAddress
+ 2, ClearValue16
, SetValue16
);
266 // Unaligned Pci address access, break up the request into byte by byte.
268 PciAndThenOr8 (PciLibAddress
, (UINT8
) (~(*(UINT8
*) ClearBits
)), *((UINT8
*) SetBits
));
269 PciAndThenOr8 (PciLibAddress
+ 1, (UINT8
) (~(*((UINT8
*) ClearBits
+ 1))), *((UINT8
*) SetBits
+ 1));
270 PciAndThenOr8 (PciLibAddress
+ 2, (UINT8
) (~(*((UINT8
*) ClearBits
+ 2))), *((UINT8
*) SetBits
+ 2));
271 PciAndThenOr8 (PciLibAddress
+ 3, (UINT8
) (~(*((UINT8
*) ClearBits
+ 3))), *((UINT8
*) SetBits
+ 3));
274 return EFI_INVALID_PARAMETER
;
280 EFI_PEI_PCI_CFG2_PPI gPciCfg2Ppi
= {
287 EFI_PEI_PPI_DESCRIPTOR gPciCfg2PpiList
= {
288 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
294 Module's entry function.
295 This routine will install EFI_PEI_PCI_CFG2_PPI.
297 @param FileHandle Handle of the file being invoked.
298 @param PeiServices Describes the list of possible PEI Services.
300 @return Whether success to install service.
304 PeimInitializePciCfg (
305 IN EFI_PEI_FILE_HANDLE FileHandle
,
306 IN CONST EFI_PEI_SERVICES
**PeiServices
311 ASSERT ((**PeiServices
).Hdr
.Revision
>= PI_SPECIFICATION_VERSION
);
313 (**(EFI_PEI_SERVICES
**)PeiServices
).PciCfg
= &gPciCfg2Ppi
;
314 Status
= (**PeiServices
).InstallPpi (PeiServices
, &gPciCfg2PpiList
);