1 /** @file 2 Usb Hub Request Support In PEI Phase 3 4 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions 8 of the BSD License which accompanies this distribution. The 9 full text of the license may be found at 10 http://opensource.org/licenses/bsd-license.php 11 12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15 **/ 16 17 #include "UsbPeim.h" 18 #include "HubPeim.h" 19 #include "PeiUsbLib.h" 20 21 /** 22 Get a given hub port status. 23 24 @param PeiServices General-purpose services that are available to every PEIM. 25 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. 26 @param Port Usb hub port number (starting from 1). 27 @param PortStatus Current Hub port status and change status. 28 29 @retval EFI_SUCCESS Port status is obtained successfully. 30 @retval EFI_DEVICE_ERROR Cannot get the port status due to a hardware error. 31 @retval Others Other failure occurs. 32 33 **/ 34 EFI_STATUS 35 PeiHubGetPortStatus ( 36 IN EFI_PEI_SERVICES **PeiServices, 37 IN PEI_USB_IO_PPI *UsbIoPpi, 38 IN UINT8 Port, 39 OUT UINT32 *PortStatus 40 ) 41 { 42 EFI_USB_DEVICE_REQUEST DeviceRequest; 43 44 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); 45 46 // 47 // Fill Device request packet 48 // 49 DeviceRequest.RequestType = USB_HUB_GET_PORT_STATUS_REQ_TYPE; 50 DeviceRequest.Request = USB_HUB_GET_PORT_STATUS; 51 DeviceRequest.Index = Port; 52 DeviceRequest.Length = (UINT16) sizeof (UINT32); 53 54 55 return UsbIoPpi->UsbControlTransfer ( 56 PeiServices, 57 UsbIoPpi, 58 &DeviceRequest, 59 EfiUsbDataIn, 60 PcdGet32 (PcdUsbTransferTimeoutValue), 61 PortStatus, 62 sizeof (UINT32) 63 ); 64 65 } 66 67 /** 68 Set specified feature to a given hub port. 69 70 @param PeiServices General-purpose services that are available to every PEIM. 71 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. 72 @param Port Usb hub port number (starting from 1). 73 @param Value New feature value. 74 75 @retval EFI_SUCCESS Port feature is set successfully. 76 @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error. 77 @retval Others Other failure occurs. 78 79 **/ 80 EFI_STATUS 81 PeiHubSetPortFeature ( 82 IN EFI_PEI_SERVICES **PeiServices, 83 IN PEI_USB_IO_PPI *UsbIoPpi, 84 IN UINT8 Port, 85 IN UINT8 Value 86 ) 87 { 88 EFI_USB_DEVICE_REQUEST DeviceRequest; 89 90 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); 91 92 // 93 // Fill Device request packet 94 // 95 DeviceRequest.RequestType = USB_HUB_SET_PORT_FEATURE_REQ_TYPE; 96 DeviceRequest.Request = USB_HUB_SET_PORT_FEATURE; 97 DeviceRequest.Value = Value; 98 DeviceRequest.Index = Port; 99 100 return UsbIoPpi->UsbControlTransfer ( 101 PeiServices, 102 UsbIoPpi, 103 &DeviceRequest, 104 EfiUsbNoData, 105 PcdGet32 (PcdUsbTransferTimeoutValue), 106 NULL, 107 0 108 ); 109 } 110 111 /** 112 Clear specified feature on a given hub port. 113 114 @param PeiServices General-purpose services that are available to every PEIM. 115 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. 116 @param Port Usb hub port number (starting from 1). 117 @param Value Feature value that will be cleared from the hub port. 118 119 @retval EFI_SUCCESS Port feature is cleared successfully. 120 @retval EFI_DEVICE_ERROR Cannot clear the port feature due to a hardware error. 121 @retval Others Other failure occurs. 122 123 **/ 124 EFI_STATUS 125 PeiHubClearPortFeature ( 126 IN EFI_PEI_SERVICES **PeiServices, 127 IN PEI_USB_IO_PPI *UsbIoPpi, 128 IN UINT8 Port, 129 IN UINT8 Value 130 ) 131 { 132 EFI_USB_DEVICE_REQUEST DeviceRequest; 133 134 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); 135 136 // 137 // Fill Device request packet 138 // 139 DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE; 140 DeviceRequest.Request = USB_HUB_CLEAR_FEATURE_PORT; 141 DeviceRequest.Value = Value; 142 DeviceRequest.Index = Port; 143 144 return UsbIoPpi->UsbControlTransfer ( 145 PeiServices, 146 UsbIoPpi, 147 &DeviceRequest, 148 EfiUsbNoData, 149 PcdGet32 (PcdUsbTransferTimeoutValue), 150 NULL, 151 0 152 ); 153 } 154 155 /** 156 Get a given hub status. 157 158 @param PeiServices General-purpose services that are available to every PEIM. 159 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. 160 @param HubStatus Current Hub status and change status. 161 162 @retval EFI_SUCCESS Hub status is obtained successfully. 163 @retval EFI_DEVICE_ERROR Cannot get the hub status due to a hardware error. 164 @retval Others Other failure occurs. 165 166 **/ 167 EFI_STATUS 168 PeiHubGetHubStatus ( 169 IN EFI_PEI_SERVICES **PeiServices, 170 IN PEI_USB_IO_PPI *UsbIoPpi, 171 OUT UINT32 *HubStatus 172 ) 173 { 174 EFI_USB_DEVICE_REQUEST DeviceRequest; 175 176 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); 177 178 // 179 // Fill Device request packet 180 // 181 DeviceRequest.RequestType = USB_HUB_GET_HUB_STATUS_REQ_TYPE; 182 DeviceRequest.Request = USB_HUB_GET_HUB_STATUS; 183 DeviceRequest.Length = (UINT16) sizeof (UINT32); 184 185 return UsbIoPpi->UsbControlTransfer ( 186 PeiServices, 187 UsbIoPpi, 188 &DeviceRequest, 189 EfiUsbDataIn, 190 PcdGet32 (PcdUsbTransferTimeoutValue), 191 HubStatus, 192 sizeof (UINT32) 193 ); 194 } 195 196 /** 197 Set specified feature to a given hub. 198 199 @param PeiServices General-purpose services that are available to every PEIM. 200 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. 201 @param Value New feature value. 202 203 @retval EFI_SUCCESS Port feature is set successfully. 204 @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error. 205 @retval Others Other failure occurs. 206 207 **/ 208 EFI_STATUS 209 PeiHubSetHubFeature ( 210 IN EFI_PEI_SERVICES **PeiServices, 211 IN PEI_USB_IO_PPI *UsbIoPpi, 212 IN UINT8 Value 213 ) 214 { 215 EFI_USB_DEVICE_REQUEST DeviceRequest; 216 217 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); 218 219 // 220 // Fill Device request packet 221 // 222 DeviceRequest.RequestType = USB_HUB_SET_HUB_FEATURE_REQ_TYPE; 223 DeviceRequest.Request = USB_HUB_SET_HUB_FEATURE; 224 DeviceRequest.Value = Value; 225 226 return UsbIoPpi->UsbControlTransfer ( 227 PeiServices, 228 UsbIoPpi, 229 &DeviceRequest, 230 EfiUsbNoData, 231 PcdGet32 (PcdUsbTransferTimeoutValue), 232 NULL, 233 0 234 ); 235 } 236 237 /** 238 Clear specified feature on a given hub. 239 240 @param PeiServices General-purpose services that are available to every PEIM. 241 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. 242 @param Value Feature value that will be cleared from the hub port. 243 244 @retval EFI_SUCCESS Hub feature is cleared successfully. 245 @retval EFI_DEVICE_ERROR Cannot clear the hub feature due to a hardware error. 246 @retval Others Other failure occurs. 247 248 **/ 249 EFI_STATUS 250 PeiHubClearHubFeature ( 251 IN EFI_PEI_SERVICES **PeiServices, 252 IN PEI_USB_IO_PPI *UsbIoPpi, 253 IN UINT8 Value 254 ) 255 { 256 EFI_USB_DEVICE_REQUEST DeviceRequest; 257 258 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); 259 260 // 261 // Fill Device request packet 262 // 263 DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_REQ_TYPE; 264 DeviceRequest.Request = USB_HUB_CLEAR_FEATURE; 265 DeviceRequest.Value = Value; 266 267 return UsbIoPpi->UsbControlTransfer ( 268 PeiServices, 269 UsbIoPpi, 270 &DeviceRequest, 271 EfiUsbNoData, 272 PcdGet32 (PcdUsbTransferTimeoutValue), 273 NULL, 274 0 275 ); 276 } 277 278 /** 279 Get a given hub descriptor. 280 281 @param PeiServices General-purpose services that are available to every PEIM. 282 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. 283 @param DescriptorSize The length of Hub Descriptor buffer. 284 @param HubDescriptor Caller allocated buffer to store the hub descriptor if 285 successfully returned. 286 287 @retval EFI_SUCCESS Hub descriptor is obtained successfully. 288 @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error. 289 @retval Others Other failure occurs. 290 291 **/ 292 EFI_STATUS 293 PeiGetHubDescriptor ( 294 IN EFI_PEI_SERVICES **PeiServices, 295 IN PEI_USB_IO_PPI *UsbIoPpi, 296 IN UINTN DescriptorSize, 297 OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor 298 ) 299 { 300 EFI_USB_DEVICE_REQUEST DevReq; 301 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); 302 303 // 304 // Fill Device request packet 305 // 306 DevReq.RequestType = USB_RT_HUB | 0x80; 307 DevReq.Request = USB_HUB_GET_DESCRIPTOR; 308 DevReq.Value = USB_DT_HUB << 8; 309 DevReq.Length = (UINT16)DescriptorSize; 310 311 return UsbIoPpi->UsbControlTransfer ( 312 PeiServices, 313 UsbIoPpi, 314 &DevReq, 315 EfiUsbDataIn, 316 PcdGet32 (PcdUsbTransferTimeoutValue), 317 HubDescriptor, 318 (UINT16)DescriptorSize 319 ); 320 } 321 322 /** 323 Get a given SuperSpeed hub descriptor. 324 325 @param PeiServices General-purpose services that are available to every PEIM. 326 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. 327 @param HubDescriptor Caller allocated buffer to store the hub descriptor if 328 successfully returned. 329 330 @retval EFI_SUCCESS Hub descriptor is obtained successfully. 331 @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error. 332 @retval Others Other failure occurs. 333 334 **/ 335 EFI_STATUS 336 PeiGetSuperSpeedHubDesc ( 337 IN EFI_PEI_SERVICES **PeiServices, 338 IN PEI_USB_IO_PPI *UsbIoPpi, 339 OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor 340 ) 341 { 342 EFI_USB_DEVICE_REQUEST DevReq; 343 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); 344 345 // 346 // Fill Device request packet 347 // 348 DevReq.RequestType = USB_RT_HUB | 0x80; 349 DevReq.Request = USB_HUB_GET_DESCRIPTOR; 350 DevReq.Value = USB_DT_SUPERSPEED_HUB << 8; 351 DevReq.Length = 12; 352 353 return UsbIoPpi->UsbControlTransfer ( 354 PeiServices, 355 UsbIoPpi, 356 &DevReq, 357 EfiUsbDataIn, 358 PcdGet32 (PcdUsbTransferTimeoutValue), 359 HubDescriptor, 360 12 361 ); 362 } 363 364 /** 365 Read the whole usb hub descriptor. It is necessary 366 to do it in two steps because hub descriptor is of 367 variable length. 368 369 @param PeiServices General-purpose services that are available to every PEIM. 370 @param PeiUsbDevice Indicates the hub controller device. 371 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. 372 @param HubDescriptor Caller allocated buffer to store the hub descriptor if 373 successfully returned. 374 375 @retval EFI_SUCCESS Hub descriptor is obtained successfully. 376 @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error. 377 @retval Others Other failure occurs. 378 379 **/ 380 EFI_STATUS 381 PeiUsbHubReadDesc ( 382 IN EFI_PEI_SERVICES **PeiServices, 383 IN PEI_USB_DEVICE *PeiUsbDevice, 384 IN PEI_USB_IO_PPI *UsbIoPpi, 385 OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor 386 ) 387 { 388 EFI_STATUS Status; 389 390 if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) { 391 // 392 // Get the super speed hub descriptor 393 // 394 Status = PeiGetSuperSpeedHubDesc (PeiServices, UsbIoPpi, HubDescriptor); 395 } else { 396 397 // 398 // First get the hub descriptor length 399 // 400 Status = PeiGetHubDescriptor (PeiServices, UsbIoPpi, 2, HubDescriptor); 401 402 if (EFI_ERROR (Status)) { 403 return Status; 404 } 405 406 // 407 // Get the whole hub descriptor 408 // 409 Status = PeiGetHubDescriptor (PeiServices, UsbIoPpi, HubDescriptor->Length, HubDescriptor); 410 } 411 412 return Status; 413 } 414 415 /** 416 USB hub control transfer to set the hub depth. 417 418 @param PeiServices General-purpose services that are available to every PEIM. 419 @param PeiUsbDevice Indicates the hub controller device. 420 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. 421 422 @retval EFI_SUCCESS Depth of the hub is set. 423 @retval Others Failed to set the depth. 424 425 **/ 426 EFI_STATUS 427 PeiUsbHubCtrlSetHubDepth ( 428 IN EFI_PEI_SERVICES **PeiServices, 429 IN PEI_USB_DEVICE *PeiUsbDevice, 430 IN PEI_USB_IO_PPI *UsbIoPpi 431 ) 432 { 433 EFI_USB_DEVICE_REQUEST DevReq; 434 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); 435 436 // 437 // Fill Device request packet 438 // 439 DevReq.RequestType = USB_RT_HUB; 440 DevReq.Request = USB_HUB_REQ_SET_DEPTH; 441 DevReq.Value = PeiUsbDevice->Tier; 442 DevReq.Length = 0; 443 444 return UsbIoPpi->UsbControlTransfer ( 445 PeiServices, 446 UsbIoPpi, 447 &DevReq, 448 EfiUsbNoData, 449 PcdGet32 (PcdUsbTransferTimeoutValue), 450 NULL, 451 0 452 ); 453 } 454 455 /** 456 Configure a given hub. 457 458 @param PeiServices General-purpose services that are available to every PEIM. 459 @param PeiUsbDevice Indicating the hub controller device that will be configured 460 461 @retval EFI_SUCCESS Hub configuration is done successfully. 462 @retval EFI_DEVICE_ERROR Cannot configure the hub due to a hardware error. 463 464 **/ 465 EFI_STATUS 466 PeiDoHubConfig ( 467 IN EFI_PEI_SERVICES **PeiServices, 468 IN PEI_USB_DEVICE *PeiUsbDevice 469 ) 470 { 471 EFI_USB_HUB_DESCRIPTOR HubDescriptor; 472 EFI_STATUS Status; 473 EFI_USB_HUB_STATUS HubStatus; 474 UINTN Index; 475 PEI_USB_IO_PPI *UsbIoPpi; 476 477 ZeroMem (&HubDescriptor, sizeof (HubDescriptor)); 478 UsbIoPpi = &PeiUsbDevice->UsbIoPpi; 479 480 // 481 // Get the hub descriptor 482 // 483 Status = PeiUsbHubReadDesc ( 484 PeiServices, 485 PeiUsbDevice, 486 UsbIoPpi, 487 &HubDescriptor 488 ); 489 if (EFI_ERROR (Status)) { 490 return EFI_DEVICE_ERROR; 491 } 492 493 PeiUsbDevice->DownStreamPortNo = HubDescriptor.NbrPorts; 494 495 if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) { 496 DEBUG ((EFI_D_INFO, "PeiDoHubConfig: Set Hub Depth as 0x%x\n", PeiUsbDevice->Tier)); 497 PeiUsbHubCtrlSetHubDepth ( 498 PeiServices, 499 PeiUsbDevice, 500 UsbIoPpi 501 ); 502 } else { 503 // 504 // Power all the hub ports 505 // 506 for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) { 507 Status = PeiHubSetPortFeature ( 508 PeiServices, 509 UsbIoPpi, 510 (UINT8) (Index + 1), 511 EfiUsbPortPower 512 ); 513 if (EFI_ERROR (Status)) { 514 DEBUG (( EFI_D_ERROR, "PeiDoHubConfig: PeiHubSetPortFeature EfiUsbPortPower failed %x\n", Index)); 515 continue; 516 } 517 } 518 519 DEBUG (( EFI_D_INFO, "PeiDoHubConfig: HubDescriptor.PwrOn2PwrGood: 0x%x\n", HubDescriptor.PwrOn2PwrGood)); 520 if (HubDescriptor.PwrOn2PwrGood > 0) { 521 MicroSecondDelay (HubDescriptor.PwrOn2PwrGood * USB_SET_PORT_POWER_STALL); 522 } 523 524 // 525 // Clear Hub Status Change 526 // 527 Status = PeiHubGetHubStatus ( 528 PeiServices, 529 UsbIoPpi, 530 (UINT32 *) &HubStatus 531 ); 532 if (EFI_ERROR (Status)) { 533 return EFI_DEVICE_ERROR; 534 } else { 535 // 536 // Hub power supply change happens 537 // 538 if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) { 539 PeiHubClearHubFeature ( 540 PeiServices, 541 UsbIoPpi, 542 C_HUB_LOCAL_POWER 543 ); 544 } 545 // 546 // Hub change overcurrent happens 547 // 548 if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) { 549 PeiHubClearHubFeature ( 550 PeiServices, 551 UsbIoPpi, 552 C_HUB_OVER_CURRENT 553 ); 554 } 555 } 556 } 557 558 return EFI_SUCCESS; 559 } 560 561 /** 562 Send reset signal over the given root hub port. 563 564 @param PeiServices General-purpose services that are available to every PEIM. 565 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. 566 @param PortNum Usb hub port number (starting from 1). 567 568 **/ 569 VOID 570 PeiResetHubPort ( 571 IN EFI_PEI_SERVICES **PeiServices, 572 IN PEI_USB_IO_PPI *UsbIoPpi, 573 IN UINT8 PortNum 574 ) 575 { 576 EFI_STATUS Status; 577 UINTN Index; 578 EFI_USB_PORT_STATUS HubPortStatus; 579 580 MicroSecondDelay (100 * 1000); 581 582 // 583 // reset root port 584 // 585 PeiHubSetPortFeature ( 586 PeiServices, 587 UsbIoPpi, 588 PortNum, 589 EfiUsbPortReset 590 ); 591 592 // 593 // Drive the reset signal for worst 20ms. Check USB 2.0 Spec 594 // section 7.1.7.5 for timing requirements. 595 // 596 MicroSecondDelay (USB_SET_PORT_RESET_STALL); 597 598 // 599 // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done. 600 // 601 ZeroMem (&HubPortStatus, sizeof (EFI_USB_PORT_STATUS)); 602 603 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) { 604 Status = PeiHubGetPortStatus ( 605 PeiServices, 606 UsbIoPpi, 607 PortNum, 608 (UINT32 *) &HubPortStatus 609 ); 610 611 if (EFI_ERROR (Status)) { 612 return; 613 } 614 615 if (USB_BIT_IS_SET (HubPortStatus.PortChangeStatus, USB_PORT_STAT_C_RESET)) { 616 break; 617 } 618 619 MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL); 620 } 621 622 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) { 623 DEBUG ((EFI_D_ERROR, "PeiResetHubPort: reset not finished in time on port %d\n", PortNum)); 624 return; 625 } 626 627 // 628 // clear reset change root port 629 // 630 PeiHubClearPortFeature ( 631 PeiServices, 632 UsbIoPpi, 633 PortNum, 634 EfiUsbPortResetChange 635 ); 636 637 MicroSecondDelay (1 * 1000); 638 639 PeiHubClearPortFeature ( 640 PeiServices, 641 UsbIoPpi, 642 PortNum, 643 EfiUsbPortConnectChange 644 ); 645 646 // 647 // Set port enable 648 // 649 PeiHubSetPortFeature ( 650 PeiServices, 651 UsbIoPpi, 652 PortNum, 653 EfiUsbPortEnable 654 ); 655 656 // 657 // Clear any change status 658 // 659 660 PeiHubClearPortFeature ( 661 PeiServices, 662 UsbIoPpi, 663 PortNum, 664 EfiUsbPortEnableChange 665 ); 666 667 MicroSecondDelay (10 * 1000); 668 669 return; 670 } 671