]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Foundation/Library/RuntimeDxe/EfiRuntimeLib/Ia32/PlatformIoLib.c
Update the copyright notice format
[mirror_edk2.git] / EdkCompatibilityPkg / Foundation / Library / RuntimeDxe / EfiRuntimeLib / Ia32 / PlatformIoLib.c
1 /*++
2
3 Copyright (c) 2004 - 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 = (((UINT32) Segment) << 24);
54 Data |= (((UINT32) Bus) << 16);
55 Data |= (((UINT32) DevFunc) << 8);
56 Data |= (UINT32) Register;
57
58 return Data;
59
60 }
61
62 UINT8
63 PciRead8 (
64 UINT8 Segment,
65 UINT8 Bus,
66 UINT8 DevFunc,
67 UINT8 Register
68 )
69 /*++
70
71 Routine Description:
72 Perform an one byte PCI config cycle read
73
74 Arguments:
75 Segment - PCI Segment ACPI _SEG
76 Bus - PCI Bus
77 DevFunc - PCI Device(7:3) and Func(2:0)
78 Register - PCI config space register
79
80 Returns:
81 Data read from PCI config space
82
83 --*/
84 {
85 EFI_STATUS Status;
86 UINT32 PciAddress;
87 UINT32 PciAddress1;
88 UINT8 Data;
89
90 PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
91 //
92 // Set bit 31 for PCI config access
93 //
94 PciAddress1 = PciAddress;
95 PciAddress = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
96
97 Status = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
98
99 if (EFI_ERROR (Status)) {
100 return 0;
101 }
102
103 EfiIoRead (EfiCpuIoWidthUint8, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
104
105 return Data;
106 }
107
108 UINT16
109 PciRead16 (
110 UINT8 Segment,
111 UINT8 Bus,
112 UINT8 DevFunc,
113 UINT8 Register
114 )
115 /*++
116
117 Routine Description:
118 Perform an two byte PCI config cycle read
119
120 Arguments:
121 Segment - PCI Segment ACPI _SEG
122 Bus - PCI Bus
123 DevFunc - PCI Device(7:3) and Func(2:0)
124 Register - PCI config space register
125
126 Returns:
127 Data read from PCI config space
128
129 --*/
130 {
131 EFI_STATUS Status;
132 UINT32 PciAddress;
133 UINT32 PciAddress1;
134 UINT16 Data;
135
136 PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
137 //
138 // Set bit 31 for PCI config access
139 //
140 PciAddress1 = PciAddress;
141 PciAddress = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
142
143 Status = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
144
145 if (EFI_ERROR (Status)) {
146 return 0;
147 }
148
149 EfiIoRead (EfiCpuIoWidthUint16, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
150
151 return Data;
152 }
153
154 UINT32
155 PciRead32 (
156 UINT8 Segment,
157 UINT8 Bus,
158 UINT8 DevFunc,
159 UINT8 Register
160 )
161 /*++
162
163 Routine Description:
164 Perform an four byte PCI config cycle read
165
166 Arguments:
167 Segment - PCI Segment ACPI _SEG
168 Bus - PCI Bus
169 DevFunc - PCI Device(7:3) and Func(2:0)
170 Register - PCI config space register
171
172 Returns:
173 Data read from PCI config space
174
175 --*/
176 {
177 EFI_STATUS Status;
178 UINT32 PciAddress;
179 UINT32 PciAddress1;
180 UINT32 Data;
181
182 PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
183 //
184 // Set bit 31 for PCI config access
185 //
186 PciAddress1 = PciAddress;
187 PciAddress = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
188
189 Status = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
190
191 if (EFI_ERROR (Status)) {
192 return 0;
193 }
194
195 EfiIoRead (EfiCpuIoWidthUint32, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
196
197 return Data;
198 }
199
200 VOID
201 PciWrite8 (
202 UINT8 Segment,
203 UINT8 Bus,
204 UINT8 DevFunc,
205 UINT8 Register,
206 UINT8 Data
207 )
208 /*++
209
210 Routine Description:
211 Perform an one byte PCI config cycle write
212
213 Arguments:
214 Segment - PCI Segment ACPI _SEG
215 Bus - PCI Bus
216 DevFunc - PCI Device(7:3) and Func(2:0)
217 Register - PCI config space register
218 Data - Data to write
219
220 Returns:
221 NONE
222
223 --*/
224 {
225 EFI_STATUS Status;
226 UINT32 PciAddress;
227 UINT32 PciAddress1;
228
229 PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
230 //
231 // Set bit 31 for PCI config access
232 //
233 PciAddress1 = PciAddress;
234 PciAddress = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
235
236 Status = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
237
238 if (EFI_ERROR (Status)) {
239 return ;
240 }
241
242 EfiIoWrite (EfiCpuIoWidthUint8, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
243 }
244
245 VOID
246 PciWrite16 (
247 UINT8 Segment,
248 UINT8 Bus,
249 UINT8 DevFunc,
250 UINT8 Register,
251 UINT16 Data
252 )
253 /*++
254
255 Routine Description:
256 Perform an two byte PCI config cycle write
257
258 Arguments:
259 Segment - PCI Segment ACPI _SEG
260 Bus - PCI Bus
261 DevFunc - PCI Device(7:3) and Func(2:0)
262 Register - PCI config space register
263 Data - Data to write
264
265 Returns:
266 NONE
267
268 --*/
269 {
270 EFI_STATUS Status;
271 UINT32 PciAddress;
272 UINT32 PciAddress1;
273
274 PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
275 //
276 // Set bit 31 for PCI config access
277 //
278 PciAddress1 = PciAddress;
279 PciAddress = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
280
281 Status = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
282
283 if (EFI_ERROR (Status)) {
284 return ;
285 }
286
287 EfiIoWrite (EfiCpuIoWidthUint16, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
288 }
289
290 VOID
291 PciWrite32 (
292 UINT8 Segment,
293 UINT8 Bus,
294 UINT8 DevFunc,
295 UINT8 Register,
296 UINT32 Data
297 )
298 /*++
299
300 Routine Description:
301 Perform an four byte PCI config cycle write
302
303 Arguments:
304 Segment - PCI Segment ACPI _SEG
305 Bus - PCI Bus
306 DevFunc - PCI Device(7:3) and Func(2:0)
307 Register - PCI config space register
308 Data - Data to write
309
310 Returns:
311 NONE
312
313 --*/
314 {
315 EFI_STATUS Status;
316 UINT32 PciAddress;
317 UINT32 PciAddress1;
318
319 PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
320 //
321 // Set bit 31 for PCI config access
322 //
323 PciAddress1 = PciAddress;
324 PciAddress = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
325
326 Status = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
327
328 if (EFI_ERROR (Status)) {
329 return ;
330 }
331
332 EfiIoWrite (EfiCpuIoWidthUint32, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
333 }
334 //
335 // Delay Primative
336 //
337 VOID
338 EfiStall (
339 IN UINTN Microseconds
340 )
341 /*++
342
343 Routine Description:
344 Delay for at least the request number of microseconds
345
346 Arguments:
347 Microseconds - Number of microseconds to delay.
348
349 Returns:
350 NONE
351
352 --*/
353 {
354 UINT8 Data;
355 UINT8 InitialState;
356 UINTN CycleIterations;
357
358 CycleIterations = 0;
359 Data = 0;
360 InitialState = 0;
361
362 if (EfiAtRuntime ()) {
363 //
364 // The time-source is 30 us granular, so calibrate the timing loop
365 // based on this baseline
366 // Error is possible 30us.
367 //
368 CycleIterations = (Microseconds - 1) / 30 + 1;
369
370 //
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.
374 //
375 //
376 // _____________/----------\__________/--------
377 //
378 // |<--15us-->|<--15us-->|
379 //
380 // --------------------------------------------------> Time (us)
381 //
382 while (CycleIterations--) {
383 EfiIoRead (EfiCpuIoWidthUint8, 0x61, 1, &Data);
384 Data &= REFRESH_CYCLE_TOGGLE_BIT;
385 InitialState = Data;
386
387 //
388 // Capture first transition (strictly less than one period)
389 //
390 while (InitialState == Data) {
391 EfiIoRead (EfiCpuIoWidthUint8, 0x61, 1, &Data);
392 Data &= REFRESH_CYCLE_TOGGLE_BIT;
393 }
394
395 InitialState = Data;
396 //
397 // Capture next transition (guarantee at least one full pulse)
398 //
399 while (InitialState == Data) {
400 EfiIoRead (EfiCpuIoWidthUint8, 0x61, 1, &Data);
401 Data &= REFRESH_CYCLE_TOGGLE_BIT;
402 }
403 }
404 } else {
405 gBS->Stall (Microseconds);
406 }
407 }