1/*++ 2 3Copyright (c) 2004 - 2006, Intel Corporation. All rights reserved.<BR> 4This program and the accompanying materials 5are licensed and made available under the terms and conditions of the BSD License 6which accompanies this distribution. The full text of the license may be found at 7http://opensource.org/licenses/bsd-license.php 8 9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12Module Name: 13 14 PlatformIoLib.c 15 16Abstract: 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 28UINT32 29GetPciAddress ( 30 UINT8 Segment, 31 UINT8 Bus, 32 UINT8 DevFunc, 33 UINT8 Register 34 ) 35/*++ 36 37Routine Description: 38 Constructs PCI Address 32 bits 39 40Arguments: 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 46Returns: 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 62UINT8 63PciRead8 ( 64 UINT8 Segment, 65 UINT8 Bus, 66 UINT8 DevFunc, 67 UINT8 Register 68 ) 69/*++ 70 71Routine Description: 72 Perform an one byte PCI config cycle read 73 74Arguments: 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 80Returns: 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 108UINT16 109PciRead16 ( 110 UINT8 Segment, 111 UINT8 Bus, 112 UINT8 DevFunc, 113 UINT8 Register 114 ) 115/*++ 116 117Routine Description: 118 Perform an two byte PCI config cycle read 119 120Arguments: 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 126Returns: 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 154UINT32 155PciRead32 ( 156 UINT8 Segment, 157 UINT8 Bus, 158 UINT8 DevFunc, 159 UINT8 Register 160 ) 161/*++ 162 163Routine Description: 164 Perform an four byte PCI config cycle read 165 166Arguments: 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 172Returns: 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 200VOID 201PciWrite8 ( 202 UINT8 Segment, 203 UINT8 Bus, 204 UINT8 DevFunc, 205 UINT8 Register, 206 UINT8 Data 207 ) 208/*++ 209 210Routine Description: 211 Perform an one byte PCI config cycle write 212 213Arguments: 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 220Returns: 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 245VOID 246PciWrite16 ( 247 UINT8 Segment, 248 UINT8 Bus, 249 UINT8 DevFunc, 250 UINT8 Register, 251 UINT16 Data 252 ) 253/*++ 254 255Routine Description: 256 Perform an two byte PCI config cycle write 257 258Arguments: 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 265Returns: 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 290VOID 291PciWrite32 ( 292 UINT8 Segment, 293 UINT8 Bus, 294 UINT8 DevFunc, 295 UINT8 Register, 296 UINT32 Data 297 ) 298/*++ 299 300Routine Description: 301 Perform an four byte PCI config cycle write 302 303Arguments: 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 310Returns: 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// 337VOID 338EfiStall ( 339 IN UINTN Microseconds 340 ) 341/*++ 342 343Routine Description: 344 Delay for at least the request number of microseconds 345 346Arguments: 347 Microseconds - Number of microseconds to delay. 348 349Returns: 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} 408