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