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 } 408