]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PciCfg2.c
d2ca19c7b065156f2ad3c5c909d8ba37908188f3
[mirror_edk2.git] / MdeModulePkg / Universal / PcatSingleSegmentPciCfg2Pei / PciCfg2.c
1 /** @file
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.
5
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
11
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.
14
15 **/
16
17 #include <PiPei.h>
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>
24
25 /**
26 Convert EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS to PCI_LIB_ADDRESS.
27
28 @param Address PCI address with EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS format.
29
30 @return PCI address with PCI_LIB_ADDRESS format.
31
32 **/
33 UINTN
34 PciCfgAddressConvert (
35 EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *Address
36 )
37 {
38 if (Address->ExtendedRegister == 0) {
39 return PCI_LIB_ADDRESS (Address->Bus, Address->Device, Address->Function, Address->Register);
40 }
41
42 return PCI_LIB_ADDRESS (Address->Bus, Address->Device, Address->Function, Address->ExtendedRegister);
43 }
44
45 /**
46 Reads from a given location in the PCI configuration space.
47
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.
55
56 @retval EFI_SUCCESS The function completed successfully.
57 @retval EFI_INVALID_PARAMETER The invalid access width.
58
59 **/
60 EFI_STATUS
61 EFIAPI
62 PciCfg2Read (
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,
66 IN UINT64 Address,
67 IN OUT VOID *Buffer
68 )
69 {
70 UINTN PciLibAddress;
71
72 PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address);
73
74 if (Width == EfiPeiPciCfgWidthUint8) {
75 *((UINT8 *) Buffer) = PciRead8 (PciLibAddress);
76 } else if (Width == EfiPeiPciCfgWidthUint16) {
77 if ((PciLibAddress & 0x01) == 0) {
78 //
79 // Aligned Pci address access
80 //
81 WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress));
82 } else {
83 //
84 // Unaligned Pci address access, break up the request into byte by byte.
85 //
86 *((UINT8 *) Buffer) = PciRead8 (PciLibAddress);
87 *((UINT8 *) Buffer + 1) = PciRead8 (PciLibAddress + 1);
88 }
89 } else if (Width == EfiPeiPciCfgWidthUint32) {
90 if ((PciLibAddress & 0x03) == 0) {
91 //
92 // Aligned Pci address access
93 //
94 WriteUnaligned32 (((UINT32 *) Buffer), PciRead32 (PciLibAddress));
95 } else if ((PciLibAddress & 0x01) == 0) {
96 //
97 // Unaligned Pci address access, break up the request into word by word.
98 //
99 WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress));
100 WriteUnaligned16 (((UINT16 *) Buffer + 1), PciRead16 (PciLibAddress + 2));
101 } else {
102 //
103 // Unaligned Pci address access, break up the request into byte by byte.
104 //
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);
109 }
110 } else {
111 return EFI_INVALID_PARAMETER;
112 }
113
114 return EFI_SUCCESS;
115 }
116
117 /**
118 Write to a given location in the PCI configuration space.
119
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.
127
128 @retval EFI_SUCCESS The function completed successfully.
129 @retval EFI_INVALID_PARAMETER The invalid access width.
130
131 **/
132 EFI_STATUS
133 EFIAPI
134 PciCfg2Write (
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,
138 IN UINT64 Address,
139 IN OUT VOID *Buffer
140 )
141 {
142 UINTN PciLibAddress;
143
144 PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address);
145
146 if (Width == EfiPeiPciCfgWidthUint8) {
147 PciWrite8 (PciLibAddress, *((UINT8 *) Buffer));
148 } else if (Width == EfiPeiPciCfgWidthUint16) {
149 if ((PciLibAddress & 0x01) == 0) {
150 //
151 // Aligned Pci address access
152 //
153 PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer));
154 } else {
155 //
156 // Unaligned Pci address access, break up the request into byte by byte.
157 //
158 PciWrite8 (PciLibAddress, *((UINT8 *) Buffer));
159 PciWrite8 (PciLibAddress + 1, *((UINT8 *) Buffer + 1));
160 }
161 } else if (Width == EfiPeiPciCfgWidthUint32) {
162 if ((PciLibAddress & 0x03) == 0) {
163 //
164 // Aligned Pci address access
165 //
166 PciWrite32 (PciLibAddress, ReadUnaligned32 ((UINT32 *) Buffer));
167 } else if ((PciLibAddress & 0x01) == 0) {
168 //
169 // Unaligned Pci address access, break up the request into word by word.
170 //
171 PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer));
172 PciWrite16 (PciLibAddress + 2, ReadUnaligned16 ((UINT16 *) Buffer + 1));
173 } else {
174 //
175 // Unaligned Pci address access, break up the request into byte by byte.
176 //
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));
181 }
182 } else {
183 return EFI_INVALID_PARAMETER;
184 }
185
186 return EFI_SUCCESS;
187 }
188
189
190 /**
191 This function performs a read-modify-write operation on the contents from a given
192 location in the PCI configuration space.
193
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.
204
205 @retval EFI_SUCCESS The function completed successfully.
206 @retval EFI_INVALID_PARAMETER The invalid access width.
207
208 **/
209 EFI_STATUS
210 EFIAPI
211 PciCfg2Modify (
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,
215 IN UINT64 Address,
216 IN VOID *SetBits,
217 IN VOID *ClearBits
218 )
219 {
220 UINTN PciLibAddress;
221 UINT16 ClearValue16;
222 UINT16 SetValue16;
223 UINT32 ClearValue32;
224 UINT32 SetValue32;
225
226 PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address);
227
228 if (Width == EfiPeiPciCfgWidthUint8) {
229 PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits));
230 } else if (Width == EfiPeiPciCfgWidthUint16) {
231 if ((PciLibAddress & 0x01) == 0) {
232 //
233 // Aligned Pci address access
234 //
235 ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits));
236 SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits);
237 PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16);
238 } else {
239 //
240 // Unaligned Pci address access, break up the request into byte by byte.
241 //
242 PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits));
243 PciAndThenOr8 (PciLibAddress + 1, (UINT8) (~(*((UINT8 *) ClearBits + 1))), *((UINT8 *) SetBits + 1));
244 }
245 } else if (Width == EfiPeiPciCfgWidthUint32) {
246 if ((PciLibAddress & 0x03) == 0) {
247 //
248 // Aligned Pci address access
249 //
250 ClearValue32 = (UINT32) (~ReadUnaligned32 ((UINT32 *) ClearBits));
251 SetValue32 = ReadUnaligned32 ((UINT32 *) SetBits);
252 PciAndThenOr32 (PciLibAddress, ClearValue32, SetValue32);
253 } else if ((PciLibAddress & 0x01) == 0) {
254 //
255 // Unaligned Pci address access, break up the request into word by word.
256 //
257 ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits));
258 SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits);
259 PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16);
260
261 ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits + 1));
262 SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits + 1);
263 PciAndThenOr16 (PciLibAddress + 2, ClearValue16, SetValue16);
264 } else {
265 //
266 // Unaligned Pci address access, break up the request into byte by byte.
267 //
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));
272 }
273 } else {
274 return EFI_INVALID_PARAMETER;
275 }
276
277 return EFI_SUCCESS;
278 }
279
280 EFI_PEI_PCI_CFG2_PPI gPciCfg2Ppi = {
281 PciCfg2Read,
282 PciCfg2Write,
283 PciCfg2Modify,
284 0
285 };
286
287 EFI_PEI_PPI_DESCRIPTOR gPciCfg2PpiList = {
288 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
289 &gEfiPciCfg2PpiGuid,
290 &gPciCfg2Ppi
291 };
292
293 /**
294 Module's entry function.
295 This routine will install EFI_PEI_PCI_CFG2_PPI.
296
297 @param FileHandle Handle of the file being invoked.
298 @param PeiServices Describes the list of possible PEI Services.
299
300 @return Whether success to install service.
301 **/
302 EFI_STATUS
303 EFIAPI
304 PeimInitializePciCfg (
305 IN EFI_PEI_FILE_HANDLE FileHandle,
306 IN CONST EFI_PEI_SERVICES **PeiServices
307 )
308 {
309 EFI_STATUS Status;
310
311 ASSERT ((**PeiServices).Hdr.Revision >= PI_SPECIFICATION_VERSION);
312
313 (**(EFI_PEI_SERVICES **)PeiServices).PciCfg = &gPciCfg2Ppi;
314 Status = (**PeiServices).InstallPpi (PeiServices, &gPciCfg2PpiList);
315
316 return Status;
317 }