]>
git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Foundation/Library/RuntimeDxe/EfiRuntimeLib/Ia32/PlatformIoLib.c
3 Copyright (c) 2004 - 2006, Intel Corporation
4 All rights reserved. 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
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.
21 #include "EfiRuntimeLib.h"
22 #include EFI_PROTOCOL_DEFINITION (CpuIo)
24 #define PCI_CONFIG_INDEX_PORT 0xcf8
25 #define PCI_CONFIG_DATA_PORT 0xcfc
26 #define REFRESH_CYCLE_TOGGLE_BIT 0x10
38 Constructs PCI Address 32 bits
41 Segment - PCI Segment ACPI _SEG
43 DevFunc - PCI Device(7:3) and Func(2:0)
44 Register - PCI config space register
47 PciAddress to be written to Config Port
53 Data
= (((UINT32
) Segment
) << 24);
54 Data
|= (((UINT32
) Bus
) << 16);
55 Data
|= (((UINT32
) DevFunc
) << 8);
56 Data
|= (UINT32
) Register
;
72 Perform an one byte PCI config cycle read
75 Segment - PCI Segment ACPI _SEG
77 DevFunc - PCI Device(7:3) and Func(2:0)
78 Register - PCI config space register
81 Data read from PCI config space
90 PciAddress
= GetPciAddress (Segment
, Bus
, DevFunc
, Register
);
92 // Set bit 31 for PCI config access
94 PciAddress1
= PciAddress
;
95 PciAddress
= ((PciAddress
& 0xFFFFFFFC) | (0x80000000));
97 Status
= EfiIoWrite (EfiCpuIoWidthUint32
, PCI_CONFIG_INDEX_PORT
, 1, &PciAddress
);
99 if (EFI_ERROR (Status
)) {
103 EfiIoRead (EfiCpuIoWidthUint8
, (PCI_CONFIG_DATA_PORT
+ (PciAddress1
& 0x3)), 1, &Data
);
118 Perform an two byte PCI config cycle read
121 Segment - PCI Segment ACPI _SEG
123 DevFunc - PCI Device(7:3) and Func(2:0)
124 Register - PCI config space register
127 Data read from PCI config space
136 PciAddress
= GetPciAddress (Segment
, Bus
, DevFunc
, Register
);
138 // Set bit 31 for PCI config access
140 PciAddress1
= PciAddress
;
141 PciAddress
= ((PciAddress
& 0xFFFFFFFC) | (0x80000000));
143 Status
= EfiIoWrite (EfiCpuIoWidthUint32
, PCI_CONFIG_INDEX_PORT
, 1, &PciAddress
);
145 if (EFI_ERROR (Status
)) {
149 EfiIoRead (EfiCpuIoWidthUint16
, (PCI_CONFIG_DATA_PORT
+ (PciAddress1
& 0x3)), 1, &Data
);
164 Perform an four byte PCI config cycle read
167 Segment - PCI Segment ACPI _SEG
169 DevFunc - PCI Device(7:3) and Func(2:0)
170 Register - PCI config space register
173 Data read from PCI config space
182 PciAddress
= GetPciAddress (Segment
, Bus
, DevFunc
, Register
);
184 // Set bit 31 for PCI config access
186 PciAddress1
= PciAddress
;
187 PciAddress
= ((PciAddress
& 0xFFFFFFFC) | (0x80000000));
189 Status
= EfiIoWrite (EfiCpuIoWidthUint32
, PCI_CONFIG_INDEX_PORT
, 1, &PciAddress
);
191 if (EFI_ERROR (Status
)) {
195 EfiIoRead (EfiCpuIoWidthUint32
, (PCI_CONFIG_DATA_PORT
+ (PciAddress1
& 0x3)), 1, &Data
);
211 Perform an one byte PCI config cycle write
214 Segment - PCI Segment ACPI _SEG
216 DevFunc - PCI Device(7:3) and Func(2:0)
217 Register - PCI config space register
229 PciAddress
= GetPciAddress (Segment
, Bus
, DevFunc
, Register
);
231 // Set bit 31 for PCI config access
233 PciAddress1
= PciAddress
;
234 PciAddress
= ((PciAddress
& 0xFFFFFFFC) | (0x80000000));
236 Status
= EfiIoWrite (EfiCpuIoWidthUint32
, PCI_CONFIG_INDEX_PORT
, 1, &PciAddress
);
238 if (EFI_ERROR (Status
)) {
242 EfiIoWrite (EfiCpuIoWidthUint8
, (PCI_CONFIG_DATA_PORT
+ (PciAddress1
& 0x3)), 1, &Data
);
256 Perform an two byte PCI config cycle write
259 Segment - PCI Segment ACPI _SEG
261 DevFunc - PCI Device(7:3) and Func(2:0)
262 Register - PCI config space register
274 PciAddress
= GetPciAddress (Segment
, Bus
, DevFunc
, Register
);
276 // Set bit 31 for PCI config access
278 PciAddress1
= PciAddress
;
279 PciAddress
= ((PciAddress
& 0xFFFFFFFC) | (0x80000000));
281 Status
= EfiIoWrite (EfiCpuIoWidthUint32
, PCI_CONFIG_INDEX_PORT
, 1, &PciAddress
);
283 if (EFI_ERROR (Status
)) {
287 EfiIoWrite (EfiCpuIoWidthUint16
, (PCI_CONFIG_DATA_PORT
+ (PciAddress1
& 0x3)), 1, &Data
);
301 Perform an four byte PCI config cycle write
304 Segment - PCI Segment ACPI _SEG
306 DevFunc - PCI Device(7:3) and Func(2:0)
307 Register - PCI config space register
319 PciAddress
= GetPciAddress (Segment
, Bus
, DevFunc
, Register
);
321 // Set bit 31 for PCI config access
323 PciAddress1
= PciAddress
;
324 PciAddress
= ((PciAddress
& 0xFFFFFFFC) | (0x80000000));
326 Status
= EfiIoWrite (EfiCpuIoWidthUint32
, PCI_CONFIG_INDEX_PORT
, 1, &PciAddress
);
328 if (EFI_ERROR (Status
)) {
332 EfiIoWrite (EfiCpuIoWidthUint32
, (PCI_CONFIG_DATA_PORT
+ (PciAddress1
& 0x3)), 1, &Data
);
339 IN UINTN Microseconds
344 Delay for at least the request number of microseconds
347 Microseconds - Number of microseconds to delay.
356 UINTN CycleIterations
;
362 if (EfiAtRuntime ()) {
364 // The time-source is 30 us granular, so calibrate the timing loop
365 // based on this baseline
366 // Error is possible 30us.
368 CycleIterations
= (Microseconds
- 1) / 30 + 1;
371 // Use the DMA Refresh timer in port 0x61. Cheap but effective.
372 // The only issue is that the granularity is 30us, and we want to
373 // guarantee "at least" one full transition to avoid races.
376 // _____________/----------\__________/--------
378 // |<--15us-->|<--15us-->|
380 // --------------------------------------------------> Time (us)
382 while (CycleIterations
--) {
383 EfiIoRead (EfiCpuIoWidthUint8
, 0x61, 1, &Data
);
384 Data
&= REFRESH_CYCLE_TOGGLE_BIT
;
388 // Capture first transition (strictly less than one period)
390 while (InitialState
== Data
) {
391 EfiIoRead (EfiCpuIoWidthUint8
, 0x61, 1, &Data
);
392 Data
&= REFRESH_CYCLE_TOGGLE_BIT
;
397 // Capture next transition (guarantee at least one full pulse)
399 while (InitialState
== Data
) {
400 EfiIoRead (EfiCpuIoWidthUint8
, 0x61, 1, &Data
);
401 Data
&= REFRESH_CYCLE_TOGGLE_BIT
;
405 gBS
->Stall (Microseconds
);