]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Foundation/Library/RuntimeDxe/EfiRuntimeLib/X64/PlatformIoLib.c
Update the copyright notice format
[mirror_edk2.git] / EdkCompatibilityPkg / Foundation / Library / RuntimeDxe / EfiRuntimeLib / X64 / PlatformIoLib.c
1 /*++
2
3 Copyright (c) 2005 - 2006, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 PlatformIoLib.c
15
16 Abstract:
17
18 --*/
19
20 #include "Tiano.h"
21 #include "EfiRuntimeLib.h"
22 #include EFI_PROTOCOL_DEFINITION (CpuIo)
23
24 #define PCI_CONFIG_INDEX_PORT 0xcf8
25 #define PCI_CONFIG_DATA_PORT 0xcfc
26 #define REFRESH_CYCLE_TOGGLE_BIT 0x10
27
28 UINT32
29 GetPciAddress (
30 UINT8 Segment,
31 UINT8 Bus,
32 UINT8 DevFunc,
33 UINT8 Register
34 )
35 /*++
36
37 Routine Description:
38 Constructs PCI Address 32 bits
39
40 Arguments:
41 Segment - PCI Segment ACPI _SEG
42 Bus - PCI Bus
43 DevFunc - PCI Device(7:3) and Func(2:0)
44 Register - PCI config space register
45
46 Returns:
47 PciAddress to be written to Config Port
48
49 --*/
50 {
51 UINT32 Data;
52
53 Data = 0;
54
55 Data = (((UINT32) Segment) << 24);
56 Data |= (((UINT32) Bus) << 16);
57 Data |= (((UINT32) DevFunc) << 8);
58 Data |= (UINT32) Register;
59
60 return Data;
61
62 }
63
64 UINT8
65 PciRead8 (
66 UINT8 Segment,
67 UINT8 Bus,
68 UINT8 DevFunc,
69 UINT8 Register
70 )
71 /*++
72
73 Routine Description:
74 Perform an one byte PCI config cycle read
75
76 Arguments:
77 Segment - PCI Segment ACPI _SEG
78 Bus - PCI Bus
79 DevFunc - PCI Device(7:3) and Func(2:0)
80 Register - PCI config space register
81
82 Returns:
83 Data read from PCI config space
84
85 --*/
86 {
87 EFI_STATUS Status;
88 UINT32 PciAddress;
89 UINT32 PciAddress1;
90 UINT8 Data;
91
92 PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
93 //
94 // Set bit 31 for PCI config access
95 //
96 PciAddress1 = PciAddress;
97 PciAddress = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
98
99 Status = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
100
101 if (EFI_ERROR (Status)) {
102 return 0;
103 }
104
105 EfiIoRead (EfiCpuIoWidthUint8, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
106
107 return Data;
108 }
109
110 UINT16
111 PciRead16 (
112 UINT8 Segment,
113 UINT8 Bus,
114 UINT8 DevFunc,
115 UINT8 Register
116 )
117 /*++
118
119 Routine Description:
120 Perform an two byte PCI config cycle read
121
122 Arguments:
123 Segment - PCI Segment ACPI _SEG
124 Bus - PCI Bus
125 DevFunc - PCI Device(7:3) and Func(2:0)
126 Register - PCI config space register
127
128 Returns:
129 Data read from PCI config space
130
131 --*/
132 {
133 EFI_STATUS Status;
134 UINT32 PciAddress;
135 UINT32 PciAddress1;
136 UINT16 Data;
137
138 PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
139 //
140 // Set bit 31 for PCI config access
141 //
142 PciAddress1 = PciAddress;
143 PciAddress = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
144
145 Status = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
146
147 if (EFI_ERROR (Status)) {
148 return 0;
149 }
150
151 EfiIoRead (EfiCpuIoWidthUint16, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
152
153 return Data;
154 }
155
156 UINT32
157 PciRead32 (
158 UINT8 Segment,
159 UINT8 Bus,
160 UINT8 DevFunc,
161 UINT8 Register
162 )
163 /*++
164
165 Routine Description:
166 Perform an four byte PCI config cycle read
167
168 Arguments:
169 Segment - PCI Segment ACPI _SEG
170 Bus - PCI Bus
171 DevFunc - PCI Device(7:3) and Func(2:0)
172 Register - PCI config space register
173
174 Returns:
175 Data read from PCI config space
176
177 --*/
178 {
179 EFI_STATUS Status;
180 UINT32 PciAddress;
181 UINT32 PciAddress1;
182 UINT32 Data;
183
184 PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
185 //
186 // Set bit 31 for PCI config access
187 //
188 PciAddress1 = PciAddress;
189 PciAddress = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
190
191 Status = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
192
193 if (EFI_ERROR (Status)) {
194 return 0;
195 }
196
197 EfiIoRead (EfiCpuIoWidthUint32, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
198
199 return Data;
200 }
201
202 VOID
203 PciWrite8 (
204 UINT8 Segment,
205 UINT8 Bus,
206 UINT8 DevFunc,
207 UINT8 Register,
208 UINT8 Data
209 )
210 /*++
211
212 Routine Description:
213 Perform an one byte PCI config cycle write
214
215 Arguments:
216 Segment - PCI Segment ACPI _SEG
217 Bus - PCI Bus
218 DevFunc - PCI Device(7:3) and Func(2:0)
219 Register - PCI config space register
220 Data - Data to write
221
222 Returns:
223 NONE
224
225 --*/
226 {
227 EFI_STATUS Status;
228 UINT32 PciAddress;
229 UINT32 PciAddress1;
230
231 PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
232 //
233 // Set bit 31 for PCI config access
234 //
235 PciAddress1 = PciAddress;
236 PciAddress = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
237
238 Status = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
239
240 if (EFI_ERROR (Status)) {
241 return ;
242 }
243
244 EfiIoWrite (EfiCpuIoWidthUint8, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
245 }
246
247 VOID
248 PciWrite16 (
249 UINT8 Segment,
250 UINT8 Bus,
251 UINT8 DevFunc,
252 UINT8 Register,
253 UINT16 Data
254 )
255 /*++
256
257 Routine Description:
258 Perform an two byte PCI config cycle write
259
260 Arguments:
261 Segment - PCI Segment ACPI _SEG
262 Bus - PCI Bus
263 DevFunc - PCI Device(7:3) and Func(2:0)
264 Register - PCI config space register
265 Data - Data to write
266
267 Returns:
268 NONE
269
270 --*/
271 {
272 EFI_STATUS Status;
273 UINT32 PciAddress;
274 UINT32 PciAddress1;
275
276 PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
277 //
278 // Set bit 31 for PCI config access
279 //
280 PciAddress1 = PciAddress;
281 PciAddress = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
282
283 Status = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
284
285 if (EFI_ERROR (Status)) {
286 return ;
287 }
288
289 EfiIoWrite (EfiCpuIoWidthUint16, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
290 }
291
292 VOID
293 PciWrite32 (
294 UINT8 Segment,
295 UINT8 Bus,
296 UINT8 DevFunc,
297 UINT8 Register,
298 UINT32 Data
299 )
300 /*++
301
302 Routine Description:
303 Perform an four byte PCI config cycle write
304
305 Arguments:
306 Segment - PCI Segment ACPI _SEG
307 Bus - PCI Bus
308 DevFunc - PCI Device(7:3) and Func(2:0)
309 Register - PCI config space register
310 Data - Data to write
311
312 Returns:
313 NONE
314
315 --*/
316 {
317 EFI_STATUS Status;
318 UINT32 PciAddress;
319 UINT32 PciAddress1;
320
321 PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
322 //
323 // Set bit 31 for PCI config access
324 //
325 PciAddress1 = PciAddress;
326 PciAddress = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
327
328 Status = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
329
330 if (EFI_ERROR (Status)) {
331 return ;
332 }
333
334 EfiIoWrite (EfiCpuIoWidthUint32, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
335 }
336 //
337 // Delay Primative
338 //
339 VOID
340 EfiStall (
341 IN UINTN Microseconds
342 )
343 /*++
344
345 Routine Description:
346 Delay for at least the request number of microseconds
347
348 Arguments:
349 Microseconds - Number of microseconds to delay.
350
351 Returns:
352 NONE
353
354 --*/
355 {
356 UINT8 Data;
357 UINT8 InitialState;
358 UINTN CycleIterations;
359
360 CycleIterations = 0;
361 Data = 0;
362 InitialState = 0;
363
364 if (EfiAtRuntime ()) {
365 //
366 // The time-source is 30 us granular, so calibrate the timing loop
367 // based on this baseline
368 // Error is possible 30us.
369 //
370 CycleIterations = (Microseconds - 1) / 30 + 1;
371
372 //
373 // Use the DMA Refresh timer in port 0x61. Cheap but effective.
374 // The only issue is that the granularity is 30us, and we want to
375 // guarantee "at least" one full transition to avoid races.
376 //
377 //
378 // _____________/----------\__________/--------
379 //
380 // |<--15us-->|<--15us-->|
381 //
382 // --------------------------------------------------> Time (us)
383 //
384 while (CycleIterations--) {
385 EfiIoRead (EfiCpuIoWidthUint8, 0x61, 1, &Data);
386 Data &= REFRESH_CYCLE_TOGGLE_BIT;
387 InitialState = Data;
388
389 //
390 // Capture first transition (strictly less than one period)
391 //
392 while (InitialState == Data) {
393 EfiIoRead (EfiCpuIoWidthUint8, 0x61, 1, &Data);
394 Data &= REFRESH_CYCLE_TOGGLE_BIT;
395 }
396
397 InitialState = Data;
398 //
399 // Capture next transition (guarantee at least one full pulse)
400 //
401 while (InitialState == Data) {
402 EfiIoRead (EfiCpuIoWidthUint8, 0x61, 1, &Data);
403 Data &= REFRESH_CYCLE_TOGGLE_BIT;
404 }
405 }
406 } else {
407 gBS->Stall (Microseconds);
408 }
409 }