]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PciCfg2.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 - 2018, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include <PiPei.h>
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>
19
20 /**
21 Convert EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS to PCI_LIB_ADDRESS.
22
23 @param Address PCI address with EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS format.
24
25 @return PCI address with PCI_LIB_ADDRESS format.
26
27 **/
28 UINTN
29 PciCfgAddressConvert (
30 EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *Address
31 )
32 {
33 if (Address->ExtendedRegister == 0) {
34 return PCI_LIB_ADDRESS (Address->Bus, Address->Device, Address->Function, Address->Register);
35 }
36
37 return PCI_LIB_ADDRESS (Address->Bus, Address->Device, Address->Function, Address->ExtendedRegister);
38 }
39
40 /**
41 Reads from a given location in the PCI configuration space.
42
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.
50
51 @retval EFI_SUCCESS The function completed successfully.
52 @retval EFI_INVALID_PARAMETER The invalid access width.
53
54 **/
55 EFI_STATUS
56 EFIAPI
57 PciCfg2Read (
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,
61 IN UINT64 Address,
62 IN OUT VOID *Buffer
63 )
64 {
65 UINTN PciLibAddress;
66
67 PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *)&Address);
68
69 if (Width == EfiPeiPciCfgWidthUint8) {
70 *((UINT8 *)Buffer) = PciRead8 (PciLibAddress);
71 } else if (Width == EfiPeiPciCfgWidthUint16) {
72 if ((PciLibAddress & 0x01) == 0) {
73 //
74 // Aligned Pci address access
75 //
76 WriteUnaligned16 (((UINT16 *)Buffer), PciRead16 (PciLibAddress));
77 } else {
78 //
79 // Unaligned Pci address access, break up the request into byte by byte.
80 //
81 *((UINT8 *)Buffer) = PciRead8 (PciLibAddress);
82 *((UINT8 *)Buffer + 1) = PciRead8 (PciLibAddress + 1);
83 }
84 } else if (Width == EfiPeiPciCfgWidthUint32) {
85 if ((PciLibAddress & 0x03) == 0) {
86 //
87 // Aligned Pci address access
88 //
89 WriteUnaligned32 (((UINT32 *)Buffer), PciRead32 (PciLibAddress));
90 } else if ((PciLibAddress & 0x01) == 0) {
91 //
92 // Unaligned Pci address access, break up the request into word by word.
93 //
94 WriteUnaligned16 (((UINT16 *)Buffer), PciRead16 (PciLibAddress));
95 WriteUnaligned16 (((UINT16 *)Buffer + 1), PciRead16 (PciLibAddress + 2));
96 } else {
97 //
98 // Unaligned Pci address access, break up the request into byte by byte.
99 //
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);
104 }
105 } else {
106 return EFI_INVALID_PARAMETER;
107 }
108
109 return EFI_SUCCESS;
110 }
111
112 /**
113 Write to a given location in the PCI configuration space.
114
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.
122
123 @retval EFI_SUCCESS The function completed successfully.
124 @retval EFI_INVALID_PARAMETER The invalid access width.
125
126 **/
127 EFI_STATUS
128 EFIAPI
129 PciCfg2Write (
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,
133 IN UINT64 Address,
134 IN OUT VOID *Buffer
135 )
136 {
137 UINTN PciLibAddress;
138
139 PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *)&Address);
140
141 if (Width == EfiPeiPciCfgWidthUint8) {
142 PciWrite8 (PciLibAddress, *((UINT8 *)Buffer));
143 } else if (Width == EfiPeiPciCfgWidthUint16) {
144 if ((PciLibAddress & 0x01) == 0) {
145 //
146 // Aligned Pci address access
147 //
148 PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *)Buffer));
149 } else {
150 //
151 // Unaligned Pci address access, break up the request into byte by byte.
152 //
153 PciWrite8 (PciLibAddress, *((UINT8 *)Buffer));
154 PciWrite8 (PciLibAddress + 1, *((UINT8 *)Buffer + 1));
155 }
156 } else if (Width == EfiPeiPciCfgWidthUint32) {
157 if ((PciLibAddress & 0x03) == 0) {
158 //
159 // Aligned Pci address access
160 //
161 PciWrite32 (PciLibAddress, ReadUnaligned32 ((UINT32 *)Buffer));
162 } else if ((PciLibAddress & 0x01) == 0) {
163 //
164 // Unaligned Pci address access, break up the request into word by word.
165 //
166 PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *)Buffer));
167 PciWrite16 (PciLibAddress + 2, ReadUnaligned16 ((UINT16 *)Buffer + 1));
168 } else {
169 //
170 // Unaligned Pci address access, break up the request into byte by byte.
171 //
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));
176 }
177 } else {
178 return EFI_INVALID_PARAMETER;
179 }
180
181 return EFI_SUCCESS;
182 }
183
184 /**
185 This function performs a read-modify-write operation on the contents from a given
186 location in the PCI configuration space.
187
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.
198
199 @retval EFI_SUCCESS The function completed successfully.
200 @retval EFI_INVALID_PARAMETER The invalid access width.
201
202 **/
203 EFI_STATUS
204 EFIAPI
205 PciCfg2Modify (
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,
209 IN UINT64 Address,
210 IN VOID *SetBits,
211 IN VOID *ClearBits
212 )
213 {
214 UINTN PciLibAddress;
215 UINT16 ClearValue16;
216 UINT16 SetValue16;
217 UINT32 ClearValue32;
218 UINT32 SetValue32;
219
220 PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *)&Address);
221
222 if (Width == EfiPeiPciCfgWidthUint8) {
223 PciAndThenOr8 (PciLibAddress, (UINT8)(~(*(UINT8 *)ClearBits)), *((UINT8 *)SetBits));
224 } else if (Width == EfiPeiPciCfgWidthUint16) {
225 if ((PciLibAddress & 0x01) == 0) {
226 //
227 // Aligned Pci address access
228 //
229 ClearValue16 = (UINT16)(~ReadUnaligned16 ((UINT16 *)ClearBits));
230 SetValue16 = ReadUnaligned16 ((UINT16 *)SetBits);
231 PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16);
232 } else {
233 //
234 // Unaligned Pci address access, break up the request into byte by byte.
235 //
236 PciAndThenOr8 (PciLibAddress, (UINT8)(~(*(UINT8 *)ClearBits)), *((UINT8 *)SetBits));
237 PciAndThenOr8 (PciLibAddress + 1, (UINT8)(~(*((UINT8 *)ClearBits + 1))), *((UINT8 *)SetBits + 1));
238 }
239 } else if (Width == EfiPeiPciCfgWidthUint32) {
240 if ((PciLibAddress & 0x03) == 0) {
241 //
242 // Aligned Pci address access
243 //
244 ClearValue32 = (UINT32)(~ReadUnaligned32 ((UINT32 *)ClearBits));
245 SetValue32 = ReadUnaligned32 ((UINT32 *)SetBits);
246 PciAndThenOr32 (PciLibAddress, ClearValue32, SetValue32);
247 } else if ((PciLibAddress & 0x01) == 0) {
248 //
249 // Unaligned Pci address access, break up the request into word by word.
250 //
251 ClearValue16 = (UINT16)(~ReadUnaligned16 ((UINT16 *)ClearBits));
252 SetValue16 = ReadUnaligned16 ((UINT16 *)SetBits);
253 PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16);
254
255 ClearValue16 = (UINT16)(~ReadUnaligned16 ((UINT16 *)ClearBits + 1));
256 SetValue16 = ReadUnaligned16 ((UINT16 *)SetBits + 1);
257 PciAndThenOr16 (PciLibAddress + 2, ClearValue16, SetValue16);
258 } else {
259 //
260 // Unaligned Pci address access, break up the request into byte by byte.
261 //
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));
266 }
267 } else {
268 return EFI_INVALID_PARAMETER;
269 }
270
271 return EFI_SUCCESS;
272 }
273
274 EFI_PEI_PCI_CFG2_PPI gPciCfg2Ppi = {
275 PciCfg2Read,
276 PciCfg2Write,
277 PciCfg2Modify,
278 0
279 };
280
281 EFI_PEI_PPI_DESCRIPTOR gPciCfg2PpiList = {
282 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
283 &gEfiPciCfg2PpiGuid,
284 &gPciCfg2Ppi
285 };
286
287 /**
288 Module's entry function.
289 This routine will install EFI_PEI_PCI_CFG2_PPI.
290
291 @param FileHandle Handle of the file being invoked.
292 @param PeiServices Describes the list of possible PEI Services.
293
294 @return Whether success to install service.
295 **/
296 EFI_STATUS
297 EFIAPI
298 PeimInitializePciCfg (
299 IN EFI_PEI_FILE_HANDLE FileHandle,
300 IN CONST EFI_PEI_SERVICES **PeiServices
301 )
302 {
303 EFI_STATUS Status;
304
305 (**(EFI_PEI_SERVICES **)PeiServices).PciCfg = &gPciCfg2Ppi;
306 Status = PeiServicesInstallPpi (&gPciCfg2PpiList);
307 ASSERT_EFI_ERROR (Status);
308
309 return Status;
310 }