]>
git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Foundation/Library/RuntimeDxe/EfiRuntimeLib/X64/PlatformIoLib.c
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
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
55 Data
= (((UINT32
) Segment
) << 24);
56 Data
|= (((UINT32
) Bus
) << 16);
57 Data
|= (((UINT32
) DevFunc
) << 8);
58 Data
|= (UINT32
) Register
;
74 Perform an one byte PCI config cycle read
77 Segment - PCI Segment ACPI _SEG
79 DevFunc - PCI Device(7:3) and Func(2:0)
80 Register - PCI config space register
83 Data read from PCI config space
92 PciAddress
= GetPciAddress (Segment
, Bus
, DevFunc
, Register
);
94 // Set bit 31 for PCI config access
96 PciAddress1
= PciAddress
;
97 PciAddress
= ((PciAddress
& 0xFFFFFFFC) | (0x80000000));
99 Status
= EfiIoWrite (EfiCpuIoWidthUint32
, PCI_CONFIG_INDEX_PORT
, 1, &PciAddress
);
101 if (EFI_ERROR (Status
)) {
105 EfiIoRead (EfiCpuIoWidthUint8
, (PCI_CONFIG_DATA_PORT
+ (PciAddress1
& 0x3)), 1, &Data
);
120 Perform an two byte PCI config cycle read
123 Segment - PCI Segment ACPI _SEG
125 DevFunc - PCI Device(7:3) and Func(2:0)
126 Register - PCI config space register
129 Data read from PCI config space
138 PciAddress
= GetPciAddress (Segment
, Bus
, DevFunc
, Register
);
140 // Set bit 31 for PCI config access
142 PciAddress1
= PciAddress
;
143 PciAddress
= ((PciAddress
& 0xFFFFFFFC) | (0x80000000));
145 Status
= EfiIoWrite (EfiCpuIoWidthUint32
, PCI_CONFIG_INDEX_PORT
, 1, &PciAddress
);
147 if (EFI_ERROR (Status
)) {
151 EfiIoRead (EfiCpuIoWidthUint16
, (PCI_CONFIG_DATA_PORT
+ (PciAddress1
& 0x3)), 1, &Data
);
166 Perform an four byte PCI config cycle read
169 Segment - PCI Segment ACPI _SEG
171 DevFunc - PCI Device(7:3) and Func(2:0)
172 Register - PCI config space register
175 Data read from PCI config space
184 PciAddress
= GetPciAddress (Segment
, Bus
, DevFunc
, Register
);
186 // Set bit 31 for PCI config access
188 PciAddress1
= PciAddress
;
189 PciAddress
= ((PciAddress
& 0xFFFFFFFC) | (0x80000000));
191 Status
= EfiIoWrite (EfiCpuIoWidthUint32
, PCI_CONFIG_INDEX_PORT
, 1, &PciAddress
);
193 if (EFI_ERROR (Status
)) {
197 EfiIoRead (EfiCpuIoWidthUint32
, (PCI_CONFIG_DATA_PORT
+ (PciAddress1
& 0x3)), 1, &Data
);
213 Perform an one byte PCI config cycle write
216 Segment - PCI Segment ACPI _SEG
218 DevFunc - PCI Device(7:3) and Func(2:0)
219 Register - PCI config space register
231 PciAddress
= GetPciAddress (Segment
, Bus
, DevFunc
, Register
);
233 // Set bit 31 for PCI config access
235 PciAddress1
= PciAddress
;
236 PciAddress
= ((PciAddress
& 0xFFFFFFFC) | (0x80000000));
238 Status
= EfiIoWrite (EfiCpuIoWidthUint32
, PCI_CONFIG_INDEX_PORT
, 1, &PciAddress
);
240 if (EFI_ERROR (Status
)) {
244 EfiIoWrite (EfiCpuIoWidthUint8
, (PCI_CONFIG_DATA_PORT
+ (PciAddress1
& 0x3)), 1, &Data
);
258 Perform an two byte PCI config cycle write
261 Segment - PCI Segment ACPI _SEG
263 DevFunc - PCI Device(7:3) and Func(2:0)
264 Register - PCI config space register
276 PciAddress
= GetPciAddress (Segment
, Bus
, DevFunc
, Register
);
278 // Set bit 31 for PCI config access
280 PciAddress1
= PciAddress
;
281 PciAddress
= ((PciAddress
& 0xFFFFFFFC) | (0x80000000));
283 Status
= EfiIoWrite (EfiCpuIoWidthUint32
, PCI_CONFIG_INDEX_PORT
, 1, &PciAddress
);
285 if (EFI_ERROR (Status
)) {
289 EfiIoWrite (EfiCpuIoWidthUint16
, (PCI_CONFIG_DATA_PORT
+ (PciAddress1
& 0x3)), 1, &Data
);
303 Perform an four byte PCI config cycle write
306 Segment - PCI Segment ACPI _SEG
308 DevFunc - PCI Device(7:3) and Func(2:0)
309 Register - PCI config space register
321 PciAddress
= GetPciAddress (Segment
, Bus
, DevFunc
, Register
);
323 // Set bit 31 for PCI config access
325 PciAddress1
= PciAddress
;
326 PciAddress
= ((PciAddress
& 0xFFFFFFFC) | (0x80000000));
328 Status
= EfiIoWrite (EfiCpuIoWidthUint32
, PCI_CONFIG_INDEX_PORT
, 1, &PciAddress
);
330 if (EFI_ERROR (Status
)) {
334 EfiIoWrite (EfiCpuIoWidthUint32
, (PCI_CONFIG_DATA_PORT
+ (PciAddress1
& 0x3)), 1, &Data
);
341 IN UINTN Microseconds
346 Delay for at least the request number of microseconds
349 Microseconds - Number of microseconds to delay.
358 UINTN CycleIterations
;
364 if (EfiAtRuntime ()) {
366 // The time-source is 30 us granular, so calibrate the timing loop
367 // based on this baseline
368 // Error is possible 30us.
370 CycleIterations
= (Microseconds
- 1) / 30 + 1;
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.
378 // _____________/----------\__________/--------
380 // |<--15us-->|<--15us-->|
382 // --------------------------------------------------> Time (us)
384 while (CycleIterations
--) {
385 EfiIoRead (EfiCpuIoWidthUint8
, 0x61, 1, &Data
);
386 Data
&= REFRESH_CYCLE_TOGGLE_BIT
;
390 // Capture first transition (strictly less than one period)
392 while (InitialState
== Data
) {
393 EfiIoRead (EfiCpuIoWidthUint8
, 0x61, 1, &Data
);
394 Data
&= REFRESH_CYCLE_TOGGLE_BIT
;
399 // Capture next transition (guarantee at least one full pulse)
401 while (InitialState
== Data
) {
402 EfiIoRead (EfiCpuIoWidthUint8
, 0x61, 1, &Data
);
403 Data
&= REFRESH_CYCLE_TOGGLE_BIT
;
407 gBS
->Stall (Microseconds
);