1 /** @file 2 * 3 * Copyright (c) 2016, Hisilicon Limited. All rights reserved. 4 * Copyright (c) 2016, Linaro Limited. All rights reserved. 5 * 6 * This program and the accompanying materials 7 * are licensed and made available under the terms and conditions of the BSD License 8 * which accompanies this distribution. The full text of the license may be found at 9 * http://opensource.org/licenses/bsd-license.php 10 * 11 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 * 14 **/ 15 16 #include "VirtualEhciPciIo.h" 17 #include <Protocol/PciRootBridgeIo.h> 18 19 UINT32 mUsbMemBase; 20 UINTN mSegmentNumber = 0; 21 // Use 0xFF for the virtual PCI devices 22 UINTN mBusNumber = 0xFF; 23 UINTN mDeviceNumber = 0; 24 UINTN mFunctionNumber = 0; 25 26 typedef struct { 27 EFI_PHYSICAL_ADDRESS HostAddress; 28 EFI_PHYSICAL_ADDRESS DeviceAddress; 29 UINTN NumberOfBytes; 30 EFI_PCI_IO_PROTOCOL_OPERATION Operation; 31 BOOLEAN DoubleBuffer; 32 } MEM_MAP_INFO_INSTANCE; 33 34 35 EFI_CPU_ARCH_PROTOCOL *gCpu; 36 37 38 EHCI_PCI_CONFIG mEhciPciConfig = { 39 { 40 0x00,//UINT16 VendorId; 41 0x00,//UINT16 DeviceId; 42 0x00,//UINT16 Command; 43 0x0010,//UINT16 Status; 44 0x00,//UINT8 RevisionID; 45 { 46 PCI_IF_EHCI,//UINT8 ClassCode[3]; 47 PCI_CLASS_SERIAL_USB, 48 PCI_CLASS_SERIAL 49 }, 50 0x00,//UINT8 CacheLineSize; 51 0x00,//UINT8 LatencyTimer; 52 0x00,//UINT8 HeaderType; 53 0x00//UINT8 BIST; 54 }, 55 { 56 { 57 0x00,//UINT32 Bar[6]; 58 0x00, 59 0x00, 60 0x00, 61 0x00, 62 0x00 63 }, 64 0x00,//UINT32 CISPtr; 65 0x00,//UINT16 SubsystemVendorID; 66 0x00,//UINT16 SubsystemID; 67 0x00,//UINT32 ExpansionRomBar; 68 0x40,//UINT8 CapabilityPtr; 69 { 70 0x00,//UINT8 Reserved1[3]; 71 0x00, 72 0x00 73 }, 74 0x00,//UINT32 Reserved2; 75 0x00,//UINT8 InterruptLine; 76 0x00,//UINT8 InterruptPin; 77 0x00,//UINT8 MinGnt; 78 0x00//UINT8 MaxLat; 79 }, 80 0x0A,// UINT8 CapabilityID offset 0x40 81 0x00,// UINT8 NextItemPtr 82 0x2000 //UINT16 DebugPort 83 }; 84 85 86 87 EFI_STATUS 88 EhciPciIoPollMem ( 89 IN EFI_PCI_IO_PROTOCOL *This, 90 IN EFI_PCI_IO_PROTOCOL_WIDTH Width, 91 IN UINT8 BarIndex, 92 IN UINT64 Offset, 93 IN UINT64 Mask, 94 IN UINT64 Value, 95 IN UINT64 Delay, 96 OUT UINT64 *Result 97 ) 98 { 99 ASSERT (FALSE); 100 return EFI_UNSUPPORTED; 101 } 102 103 EFI_STATUS 104 EhciPciIoPollIo ( 105 IN EFI_PCI_IO_PROTOCOL *This, 106 IN EFI_PCI_IO_PROTOCOL_WIDTH Width, 107 IN UINT8 BarIndex, 108 IN UINT64 Offset, 109 IN UINT64 Mask, 110 IN UINT64 Value, 111 IN UINT64 Delay, 112 OUT UINT64 *Result 113 ) 114 { 115 ASSERT (FALSE); 116 return EFI_UNSUPPORTED; 117 } 118 119 EFI_STATUS 120 EhciPciIoMemRead ( 121 IN EFI_PCI_IO_PROTOCOL *This, 122 IN EFI_PCI_IO_PROTOCOL_WIDTH Width, 123 IN UINT8 BarIndex, 124 IN UINT64 Offset, 125 IN UINTN Count, 126 IN OUT VOID *Buffer 127 ) 128 { 129 UINT32 i; 130 131 if ((UINT32)Width >= EfiPciIoWidthMaximum) { 132 return EFI_INVALID_PARAMETER; 133 } 134 135 if (Buffer == NULL) { 136 return EFI_INVALID_PARAMETER; 137 } 138 139 if (BarIndex != 0) { 140 return EFI_INVALID_PARAMETER; 141 } 142 143 Width = Width & 0x03; 144 145 // 146 // Loop for each iteration and move the data 147 // 148 switch (Width) { 149 case EfiPciWidthUint8: 150 for (i = 0; i < Count; i++){ 151 *((UINT8 *)Buffer + i)= MmioRead8(mUsbMemBase + Offset + i); 152 } 153 break; 154 case EfiPciWidthUint16: 155 for (i = 0; i < Count; i++){ 156 *((UINT16 *)Buffer + i)= MmioRead16(mUsbMemBase + Offset + i * 2); 157 } 158 break; 159 case EfiPciWidthUint32: 160 for (i = 0; i < Count; i++){ 161 *((UINT32 *)Buffer + i)= MmioRead32(mUsbMemBase + Offset + i * 4); 162 } 163 break; 164 case EfiPciWidthUint64: 165 for (i = 0; i < Count; i++){ 166 *((UINT64 *)Buffer + i)= MmioRead64(mUsbMemBase + Offset + i * 8); 167 } 168 break; 169 default: 170 return EFI_INVALID_PARAMETER; 171 } 172 173 return EFI_SUCCESS; 174 } 175 176 EFI_STATUS 177 EhciPciIoMemWrite ( 178 IN EFI_PCI_IO_PROTOCOL *This, 179 IN EFI_PCI_IO_PROTOCOL_WIDTH Width, 180 IN UINT8 BarIndex, 181 IN UINT64 Offset, 182 IN UINTN Count, 183 IN OUT VOID *Buffer 184 ) 185 { 186 UINT32 i; 187 188 if ((UINT32)Width >= EfiPciIoWidthMaximum) { 189 return EFI_INVALID_PARAMETER; 190 } 191 192 if (Buffer == NULL) { 193 return EFI_INVALID_PARAMETER; 194 } 195 196 Width = Width & 0x03; 197 198 // 199 // Loop for each iteration and move the data 200 // 201 switch (Width) { 202 case EfiPciWidthUint8: 203 for (i = 0; i < Count; i++){ 204 MmioWrite8(mUsbMemBase + Offset + i, *((UINT8 *)Buffer + i)); 205 } 206 break; 207 case EfiPciWidthUint16: 208 for (i = 0; i < Count; i++){ 209 MmioWrite16(mUsbMemBase + Offset + i * 2, *((UINT16 *)Buffer + i)); 210 } 211 break; 212 case EfiPciWidthUint32: 213 for (i = 0; i < Count; i++){ 214 MmioWrite32(mUsbMemBase + Offset + i * 4, *((UINT32 *)Buffer + i)); 215 } 216 break; 217 case EfiPciWidthUint64: 218 for (i = 0; i < Count; i++){ 219 MmioWrite64(mUsbMemBase + Offset + i * 8, *((UINT64 *)Buffer + i)); 220 } 221 break; 222 default: 223 return EFI_INVALID_PARAMETER; 224 } 225 226 return EFI_SUCCESS; 227 228 } 229 230 EFI_STATUS 231 EhciPciIoIoRead ( 232 IN EFI_PCI_IO_PROTOCOL *This, 233 IN EFI_PCI_IO_PROTOCOL_WIDTH Width, 234 IN UINT8 BarIndex, 235 IN UINT64 Offset, 236 IN UINTN Count, 237 IN OUT VOID *Buffer 238 ) 239 { 240 ASSERT (FALSE); 241 return EFI_UNSUPPORTED; 242 } 243 244 EFI_STATUS 245 EhciPciIoIoWrite ( 246 IN EFI_PCI_IO_PROTOCOL *This, 247 IN EFI_PCI_IO_PROTOCOL_WIDTH Width, 248 IN UINT8 BarIndex, 249 IN UINT64 Offset, 250 IN UINTN Count, 251 IN OUT VOID *Buffer 252 ) 253 { 254 ASSERT (FALSE); 255 return EFI_UNSUPPORTED; 256 } 257 258 EFI_STATUS 259 EhciPciIoPciRead ( 260 IN EFI_PCI_IO_PROTOCOL *This, 261 IN EFI_PCI_IO_PROTOCOL_WIDTH Width, 262 IN UINT32 Offset, 263 IN UINTN Count, 264 IN OUT VOID *Buffer 265 ) 266 { 267 UINT32 i; 268 UINT8 *DataPtr; 269 270 Width = Width & 0x03; 271 272 if (Offset < sizeof (EHCI_PCI_CONFIG) / sizeof (UINT8)){ 273 274 DataPtr = (UINT8 *)(&mEhciPciConfig) + Offset; 275 276 switch (Width) { 277 case EfiPciWidthUint8: 278 for (i = 0; i < Count; i++){ 279 *((UINT8 *)Buffer + i)= *(DataPtr + i); 280 } 281 break; 282 case EfiPciWidthUint16: 283 for (i = 0; i < Count; i++){ 284 *((UINT16 *)Buffer + i)= *((UINT16 *)DataPtr + i); 285 } 286 break; 287 case EfiPciWidthUint32: 288 for (i = 0; i < Count; i++){ 289 *(UINT32 *)(Buffer + i)= *((UINT32 *)DataPtr + i); 290 } 291 break; 292 case EfiPciWidthUint64: 293 for (i = 0; i < Count; i++){ 294 *(UINT64 *)(Buffer + i)= *((UINT64 *)DataPtr + i); 295 } 296 break; 297 default: 298 return EFI_INVALID_PARAMETER; 299 } 300 301 } else { 302 switch (Width) { 303 case EfiPciWidthUint8: 304 *(UINT8 *)Buffer = 0xFF; 305 break; 306 case EfiPciWidthUint16: 307 *(UINT16 *)Buffer = 0xFFFF; 308 break; 309 case EfiPciWidthUint32: 310 *(UINT32 *)Buffer = 0xFFFFFFFF; 311 break; 312 case EfiPciWidthUint64: 313 *(UINT64 *)Buffer = 0xFFFFFFFFFFFFFFFF; 314 break; 315 default: 316 return EFI_INVALID_PARAMETER; 317 } 318 } 319 320 return EFI_SUCCESS; 321 } 322 323 EFI_STATUS 324 EhciPciIoPciWrite ( 325 IN EFI_PCI_IO_PROTOCOL *This, 326 IN EFI_PCI_IO_PROTOCOL_WIDTH Width, 327 IN UINT32 Offset, 328 IN UINTN Count, 329 IN OUT VOID *Buffer 330 ) 331 { 332 333 return EFI_SUCCESS; 334 } 335 336 EFI_STATUS 337 EhciPciIoCopyMem ( 338 IN EFI_PCI_IO_PROTOCOL *This, 339 IN EFI_PCI_IO_PROTOCOL_WIDTH Width, 340 IN UINT8 DestBarIndex, 341 IN UINT64 DestOffset, 342 IN UINT8 SrcBarIndex, 343 IN UINT64 SrcOffset, 344 IN UINTN Count 345 ) 346 { 347 ASSERT (FALSE); 348 return EFI_UNSUPPORTED; 349 } 350 351 EFI_STATUS 352 EhciPciIoMap ( 353 IN EFI_PCI_IO_PROTOCOL *This, 354 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation, 355 IN VOID *HostAddress, 356 IN OUT UINTN *NumberOfBytes, 357 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, 358 OUT VOID **Mapping 359 ) 360 { 361 EFI_STATUS Status; 362 MEM_MAP_INFO_INSTANCE *Map; 363 VOID *Buffer; 364 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; 365 366 if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) { 367 return EFI_INVALID_PARAMETER; 368 } 369 370 if ((UINT32)Operation >= EfiPciIoOperationMaximum) { 371 return EFI_INVALID_PARAMETER; 372 } 373 374 *DeviceAddress = ConvertToPhysicalAddress (HostAddress); 375 376 // Remember range so we can flush on the other side 377 Map = AllocatePool (sizeof (MEM_MAP_INFO_INSTANCE)); 378 if (Map == NULL) { 379 return EFI_OUT_OF_RESOURCES; 380 } 381 382 *Mapping = Map; 383 384 if ((((UINTN)HostAddress & (EFI_PAGE_SIZE - 1)) != 0) || 385 ((*NumberOfBytes % EFI_PAGE_SIZE) != 0)) { 386 387 // Get the cacheability of the region 388 Status = gDS->GetMemorySpaceDescriptor (*DeviceAddress, &GcdDescriptor); 389 if (EFI_ERROR(Status)) { 390 return Status; 391 } 392 393 // If the mapped buffer is not an uncached buffer 394 if ( (GcdDescriptor.Attributes != EFI_MEMORY_WC) && 395 (GcdDescriptor.Attributes != EFI_MEMORY_UC) ) 396 { 397 // 398 // If the buffer does not fill entire cache lines we must double buffer into 399 // uncached memory. Device (PCI) address becomes uncached page. 400 // 401 Map->DoubleBuffer = TRUE; 402 Buffer = UncachedAllocatePages(EFI_SIZE_TO_PAGES (*NumberOfBytes)); 403 404 if (Buffer == NULL) { 405 return EFI_OUT_OF_RESOURCES; 406 } 407 408 CopyMem (Buffer, HostAddress, *NumberOfBytes); 409 *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer; 410 } else { 411 Map->DoubleBuffer = FALSE; 412 } 413 } else { 414 Map->DoubleBuffer = FALSE; 415 416 // Flush the Data Cache (should not have any effect if the memory region is uncached) 417 gCpu->FlushDataCache (gCpu, *DeviceAddress, *NumberOfBytes, EfiCpuFlushTypeWriteBackInvalidate); 418 419 Status = gDS->SetMemorySpaceAttributes (*DeviceAddress & ~(BASE_4KB - 1), ALIGN_VALUE (*NumberOfBytes, BASE_4KB), EFI_MEMORY_WC); 420 if (EFI_ERROR (Status)) { 421 DEBUG((EFI_D_ERROR, "[%a]:[%dL] SetMemorySpaceAttributes Fail. %r\n", __FUNCTION__, __LINE__, Status)); 422 } 423 } 424 425 Map->HostAddress = (UINTN)HostAddress; 426 Map->DeviceAddress = *DeviceAddress; 427 Map->NumberOfBytes = *NumberOfBytes; 428 Map->Operation = Operation; 429 430 return EFI_SUCCESS; 431 } 432 433 EFI_STATUS 434 EhciPciIoUnmap ( 435 IN EFI_PCI_IO_PROTOCOL *This, 436 IN VOID *Mapping 437 ) 438 { 439 MEM_MAP_INFO_INSTANCE *Map; 440 441 if (Mapping == NULL) { 442 return EFI_INVALID_PARAMETER; 443 } 444 445 Map = (MEM_MAP_INFO_INSTANCE *)Mapping; 446 447 if (Map->DoubleBuffer) { 448 if ((Map->Operation == EfiPciIoOperationBusMasterWrite) || (Map->Operation == EfiPciIoOperationBusMasterCommonBuffer)) { 449 CopyMem ((VOID *)(UINTN)Map->HostAddress, (VOID *)(UINTN)Map->DeviceAddress, Map->NumberOfBytes); 450 } 451 452 if((VOID *)(UINTN)Map->DeviceAddress != NULL) { 453 UncachedFreePages ((VOID *)(UINTN)Map->DeviceAddress, EFI_SIZE_TO_PAGES (Map->NumberOfBytes)); 454 } 455 456 457 } else { 458 if (Map->Operation == EfiPciIoOperationBusMasterWrite) { 459 // 460 // Make sure we read buffer from uncached memory and not the cache 461 // 462 gCpu->FlushDataCache (gCpu, Map->HostAddress, Map->NumberOfBytes, EfiCpuFlushTypeInvalidate); 463 } 464 } 465 466 FreePool (Map); 467 468 return EFI_SUCCESS; 469 } 470 471 472 473 EFI_STATUS 474 EhciPciIoAllocateBuffer ( 475 IN EFI_PCI_IO_PROTOCOL *This, 476 IN EFI_ALLOCATE_TYPE Type, 477 IN EFI_MEMORY_TYPE MemoryType, 478 IN UINTN Pages, 479 OUT VOID **HostAddress, 480 IN UINT64 Attributes 481 ) 482 { 483 UINT32 HcCapParams; 484 485 if (Attributes & 486 (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | 487 EFI_PCI_ATTRIBUTE_MEMORY_CACHED ))) { 488 return EFI_UNSUPPORTED; 489 } 490 491 if (HostAddress == NULL) { 492 return EFI_INVALID_PARAMETER; 493 } 494 495 if (MemoryType == EfiBootServicesData) { 496 HcCapParams = MmioRead32(mUsbMemBase + EHC_HCCPARAMS_OFFSET); 497 if ((BOOLEAN)(((HcCapParams) & (HCCP_64BIT)) == (HCCP_64BIT))){ 498 *HostAddress = UncachedAllocatePages(Pages); 499 } else { 500 // TODO: We need support allocating UC memory below 4GB strictly 501 *HostAddress = UncachedAllocatePages(Pages); 502 } 503 504 }else{ 505 return EFI_INVALID_PARAMETER; 506 } 507 508 return EFI_SUCCESS; 509 } 510 511 512 EFI_STATUS 513 EhciPciIoFreeBuffer ( 514 IN EFI_PCI_IO_PROTOCOL *This, 515 IN UINTN Pages, 516 IN VOID *HostAddress 517 ) 518 { 519 UncachedFreePages (HostAddress, Pages); 520 return EFI_SUCCESS; 521 } 522 523 EFI_STATUS 524 EhciPciIoFlush ( 525 IN EFI_PCI_IO_PROTOCOL *This 526 ) 527 { 528 return EFI_SUCCESS; 529 } 530 531 EFI_STATUS 532 EhciPciIoGetLocation ( 533 IN EFI_PCI_IO_PROTOCOL *This, 534 OUT UINTN *SegmentNumber, 535 OUT UINTN *BusNumber, 536 OUT UINTN *DeviceNumber, 537 OUT UINTN *FunctionNumber 538 ) 539 { 540 541 *SegmentNumber = mSegmentNumber; 542 *BusNumber = mBusNumber; 543 *DeviceNumber = mDeviceNumber; 544 *FunctionNumber = mFunctionNumber; 545 546 return EFI_SUCCESS; 547 } 548 549 550 EFI_STATUS 551 EhciPciIoAttributes ( 552 IN EFI_PCI_IO_PROTOCOL *This, 553 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, 554 IN UINT64 Attributes, 555 OUT UINT64 *Result OPTIONAL 556 ) 557 { 558 if (Result != NULL) { 559 *Result = 0; 560 } 561 return EFI_SUCCESS; 562 } 563 564 EFI_STATUS 565 EhciPciIoGetBarAttributes ( 566 IN EFI_PCI_IO_PROTOCOL *This, 567 IN UINT8 BarIndex, 568 OUT UINT64 *Supports, OPTIONAL 569 OUT VOID **Resources OPTIONAL 570 ) 571 { 572 ASSERT (FALSE); 573 return EFI_UNSUPPORTED; 574 } 575 576 EFI_STATUS 577 EhciPciIoSetBarAttributes ( 578 IN EFI_PCI_IO_PROTOCOL *This, 579 IN UINT64 Attributes, 580 IN UINT8 BarIndex, 581 IN OUT UINT64 *Offset, 582 IN OUT UINT64 *Length 583 ) 584 { 585 ASSERT (FALSE); 586 return EFI_UNSUPPORTED; 587 } 588 589 // 590 // Pci Io Protocol Interface 591 // 592 EFI_PCI_IO_PROTOCOL mEhciPciIoInterface = { 593 EhciPciIoPollMem, 594 EhciPciIoPollIo, 595 { 596 EhciPciIoMemRead, 597 EhciPciIoMemWrite 598 }, 599 { 600 EhciPciIoIoRead, 601 EhciPciIoIoWrite 602 }, 603 { 604 EhciPciIoPciRead, 605 EhciPciIoPciWrite 606 }, 607 EhciPciIoCopyMem, 608 EhciPciIoMap, 609 EhciPciIoUnmap, 610 EhciPciIoAllocateBuffer, 611 EhciPciIoFreeBuffer, 612 EhciPciIoFlush, 613 EhciPciIoGetLocation, 614 EhciPciIoAttributes, 615 EhciPciIoGetBarAttributes, 616 EhciPciIoSetBarAttributes, 617 0, 618 NULL 619 }; 620 621 622 EFI_STATUS 623 EFIAPI 624 EhciVirtualPciIoInitialize ( 625 IN EFI_HANDLE ImageHandle, 626 IN EFI_SYSTEM_TABLE *SystemTable 627 ) 628 { 629 EFI_STATUS Status; 630 EFI_HANDLE Handle; 631 EFI_DEV_PATH EndNode; 632 EFI_DEV_PATH Node; 633 EFI_DEVICE_PATH_PROTOCOL *DevicePath = NULL; 634 635 mUsbMemBase = PlatformGetEhciBase (); 636 637 DEBUG ((EFI_D_ERROR, "mUsbMemBase: 0x%x\n", mUsbMemBase)); 638 639 // Get the Cpu protocol for later use 640 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu); 641 642 // 643 // Install the pciio protocol, device path protocol 644 // 645 Handle = NULL; 646 647 Status = gBS->InstallMultipleProtocolInterfaces ( 648 &Handle, 649 &gEfiPciIoProtocolGuid, 650 &mEhciPciIoInterface, 651 NULL 652 ); 653 if (EFI_ERROR (Status)) { 654 return Status; 655 } 656 657 (void)ZeroMem (&Node, sizeof (Node)); 658 Node.DevPath.Type = HARDWARE_DEVICE_PATH; 659 Node.DevPath.SubType = HW_PCI_DP; 660 (void)SetDevicePathNodeLength (&Node.DevPath, sizeof (PCI_DEVICE_PATH)); 661 // Make USB controller device path different from built-in SATA controller 662 Node.Pci.Function = 1; 663 Node.Pci.Device = 0; 664 665 SetDevicePathEndNode (&EndNode.DevPath); 666 667 DevicePath = AppendDevicePathNode (&EndNode.DevPath, &Node.DevPath); 668 669 Status = gBS->InstallProtocolInterface ( 670 &Handle, 671 &gEfiDevicePathProtocolGuid, 672 EFI_NATIVE_INTERFACE, 673 DevicePath 674 ); 675 if(EFI_ERROR(Status)) 676 { 677 DEBUG((EFI_D_ERROR, "[%a]:[%dL] InstallProtocolInterface fail. %r\n", __FUNCTION__, __LINE__, Status)); 678 } 679 680 681 return EFI_SUCCESS; 682 } 683