]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciPei / XhcPeim.c
1 /** @file
2 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
4
5 Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "XhcPeim.h"
12
13 //
14 // Two arrays used to translate the XHCI port state (change)
15 // to the UEFI protocol's port state (change).
16 //
17 USB_PORT_STATE_MAP mUsbPortStateMap[] = {
18 {XHC_PORTSC_CCS, USB_PORT_STAT_CONNECTION},
19 {XHC_PORTSC_PED, USB_PORT_STAT_ENABLE},
20 {XHC_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT},
21 {XHC_PORTSC_PP, USB_PORT_STAT_POWER},
22 {XHC_PORTSC_RESET, USB_PORT_STAT_RESET}
23 };
24
25 USB_PORT_STATE_MAP mUsbPortChangeMap[] = {
26 {XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},
27 {XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},
28 {XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},
29 {XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}
30 };
31
32 USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {
33 {XHC_PORTSC_CSC, EfiUsbPortConnectChange},
34 {XHC_PORTSC_PEC, EfiUsbPortEnableChange},
35 {XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange},
36 {XHC_PORTSC_PRC, EfiUsbPortResetChange}
37 };
38
39 USB_PORT_STATE_MAP mUsbHubPortStateMap[] = {
40 {XHC_HUB_PORTSC_CCS, USB_PORT_STAT_CONNECTION},
41 {XHC_HUB_PORTSC_PED, USB_PORT_STAT_ENABLE},
42 {XHC_HUB_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT},
43 {XHC_HUB_PORTSC_PP, USB_PORT_STAT_POWER},
44 {XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET}
45 };
46
47 USB_PORT_STATE_MAP mUsbHubPortChangeMap[] = {
48 {XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},
49 {XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},
50 {XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},
51 {XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET}
52 };
53
54 USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {
55 {XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange},
56 {XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange},
57 {XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange},
58 {XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange},
59 {XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange}
60 };
61
62 /**
63 Read XHCI Operation register.
64
65 @param Xhc The XHCI device.
66 @param Offset The operation register offset.
67
68 @retval the register content read.
69
70 **/
71 UINT32
72 XhcPeiReadOpReg (
73 IN PEI_XHC_DEV *Xhc,
74 IN UINT32 Offset
75 )
76 {
77 UINT32 Data;
78
79 ASSERT (Xhc->CapLength != 0);
80
81 Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset);
82 return Data;
83 }
84
85 /**
86 Write the data to the XHCI operation register.
87
88 @param Xhc The XHCI device.
89 @param Offset The operation register offset.
90 @param Data The data to write.
91
92 **/
93 VOID
94 XhcPeiWriteOpReg (
95 IN PEI_XHC_DEV *Xhc,
96 IN UINT32 Offset,
97 IN UINT32 Data
98 )
99 {
100 ASSERT (Xhc->CapLength != 0);
101
102 MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset, Data);
103 }
104
105 /**
106 Set one bit of the operational register while keeping other bits.
107
108 @param Xhc The XHCI device.
109 @param Offset The offset of the operational register.
110 @param Bit The bit mask of the register to set.
111
112 **/
113 VOID
114 XhcPeiSetOpRegBit (
115 IN PEI_XHC_DEV *Xhc,
116 IN UINT32 Offset,
117 IN UINT32 Bit
118 )
119 {
120 UINT32 Data;
121
122 Data = XhcPeiReadOpReg (Xhc, Offset);
123 Data |= Bit;
124 XhcPeiWriteOpReg (Xhc, Offset, Data);
125 }
126
127 /**
128 Clear one bit of the operational register while keeping other bits.
129
130 @param Xhc The XHCI device.
131 @param Offset The offset of the operational register.
132 @param Bit The bit mask of the register to clear.
133
134 **/
135 VOID
136 XhcPeiClearOpRegBit (
137 IN PEI_XHC_DEV *Xhc,
138 IN UINT32 Offset,
139 IN UINT32 Bit
140 )
141 {
142 UINT32 Data;
143
144 Data = XhcPeiReadOpReg (Xhc, Offset);
145 Data &= ~Bit;
146 XhcPeiWriteOpReg (Xhc, Offset, Data);
147 }
148
149 /**
150 Wait the operation register's bit as specified by Bit
151 to become set (or clear).
152
153 @param Xhc The XHCI device.
154 @param Offset The offset of the operational register.
155 @param Bit The bit mask of the register to wait for.
156 @param WaitToSet Wait the bit to set or clear.
157 @param Timeout The time to wait before abort (in millisecond, ms).
158
159 @retval EFI_SUCCESS The bit successfully changed by host controller.
160 @retval EFI_TIMEOUT The time out occurred.
161
162 **/
163 EFI_STATUS
164 XhcPeiWaitOpRegBit (
165 IN PEI_XHC_DEV *Xhc,
166 IN UINT32 Offset,
167 IN UINT32 Bit,
168 IN BOOLEAN WaitToSet,
169 IN UINT32 Timeout
170 )
171 {
172 UINT64 Index;
173
174 for (Index = 0; Index < Timeout * XHC_1_MILLISECOND; Index++) {
175 if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {
176 return EFI_SUCCESS;
177 }
178
179 MicroSecondDelay (XHC_1_MICROSECOND);
180 }
181
182 return EFI_TIMEOUT;
183 }
184
185 /**
186 Read XHCI capability register.
187
188 @param Xhc The XHCI device.
189 @param Offset Capability register address.
190
191 @retval the register content read.
192
193 **/
194 UINT32
195 XhcPeiReadCapRegister (
196 IN PEI_XHC_DEV *Xhc,
197 IN UINT32 Offset
198 )
199 {
200 UINT32 Data;
201
202 Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Offset);
203
204 return Data;
205 }
206
207
208
209 /**
210 Write the data to the XHCI door bell register.
211
212 @param Xhc The XHCI device.
213 @param Offset The offset of the door bell register.
214 @param Data The data to write.
215
216 **/
217 VOID
218 XhcPeiWriteDoorBellReg (
219 IN PEI_XHC_DEV *Xhc,
220 IN UINT32 Offset,
221 IN UINT32 Data
222 )
223 {
224 ASSERT (Xhc->DBOff != 0);
225
226 MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->DBOff + Offset, Data);
227 }
228
229 /**
230 Read XHCI runtime register.
231
232 @param Xhc The XHCI device.
233 @param Offset The offset of the runtime register.
234
235 @return The register content read
236
237 **/
238 UINT32
239 XhcPeiReadRuntimeReg (
240 IN PEI_XHC_DEV *Xhc,
241 IN UINT32 Offset
242 )
243 {
244 UINT32 Data;
245
246 ASSERT (Xhc->RTSOff != 0);
247
248 Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset);
249
250 return Data;
251 }
252
253 /**
254 Write the data to the XHCI runtime register.
255
256 @param Xhc The XHCI device.
257 @param Offset The offset of the runtime register.
258 @param Data The data to write.
259
260 **/
261 VOID
262 XhcPeiWriteRuntimeReg (
263 IN PEI_XHC_DEV *Xhc,
264 IN UINT32 Offset,
265 IN UINT32 Data
266 )
267 {
268 ASSERT (Xhc->RTSOff != 0);
269
270 MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset, Data);
271 }
272
273 /**
274 Set one bit of the runtime register while keeping other bits.
275
276 @param Xhc The XHCI device.
277 @param Offset The offset of the runtime register.
278 @param Bit The bit mask of the register to set.
279
280 **/
281 VOID
282 XhcPeiSetRuntimeRegBit (
283 IN PEI_XHC_DEV *Xhc,
284 IN UINT32 Offset,
285 IN UINT32 Bit
286 )
287 {
288 UINT32 Data;
289
290 Data = XhcPeiReadRuntimeReg (Xhc, Offset);
291 Data |= Bit;
292 XhcPeiWriteRuntimeReg (Xhc, Offset, Data);
293 }
294
295 /**
296 Clear one bit of the runtime register while keeping other bits.
297
298 @param Xhc The XHCI device.
299 @param Offset The offset of the runtime register.
300 @param Bit The bit mask of the register to set.
301
302 **/
303 VOID
304 XhcPeiClearRuntimeRegBit (
305 IN PEI_XHC_DEV *Xhc,
306 IN UINT32 Offset,
307 IN UINT32 Bit
308 )
309 {
310 UINT32 Data;
311
312 Data = XhcPeiReadRuntimeReg (Xhc, Offset);
313 Data &= ~Bit;
314 XhcPeiWriteRuntimeReg (Xhc, Offset, Data);
315 }
316
317 /**
318 Check whether Xhc is halted.
319
320 @param Xhc The XHCI device.
321
322 @retval TRUE The controller is halted.
323 @retval FALSE The controller isn't halted.
324
325 **/
326 BOOLEAN
327 XhcPeiIsHalt (
328 IN PEI_XHC_DEV *Xhc
329 )
330 {
331 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT);
332 }
333
334 /**
335 Check whether system error occurred.
336
337 @param Xhc The XHCI device.
338
339 @retval TRUE System error happened.
340 @retval FALSE No system error.
341
342 **/
343 BOOLEAN
344 XhcPeiIsSysError (
345 IN PEI_XHC_DEV *Xhc
346 )
347 {
348 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);
349 }
350
351 /**
352 Reset the host controller.
353
354 @param Xhc The XHCI device.
355 @param Timeout Time to wait before abort (in millisecond, ms).
356
357 @retval EFI_TIMEOUT The transfer failed due to time out.
358 @retval Others Failed to reset the host.
359
360 **/
361 EFI_STATUS
362 XhcPeiResetHC (
363 IN PEI_XHC_DEV *Xhc,
364 IN UINT32 Timeout
365 )
366 {
367 EFI_STATUS Status;
368
369 //
370 // Host can only be reset when it is halt. If not so, halt it
371 //
372 if (!XhcPeiIsHalt (Xhc)) {
373 Status = XhcPeiHaltHC (Xhc, Timeout);
374
375 if (EFI_ERROR (Status)) {
376 goto ON_EXIT;
377 }
378 }
379
380 XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);
381 //
382 // Some XHCI host controllers require to have extra 1ms delay before accessing any MMIO register during reset.
383 // Otherwise there may have the timeout case happened.
384 // The below is a workaround to solve such problem.
385 //
386 MicroSecondDelay (1000);
387 Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);
388 ON_EXIT:
389 DEBUG ((EFI_D_INFO, "XhcPeiResetHC: %r\n", Status));
390 return Status;
391 }
392
393 /**
394 Halt the host controller.
395
396 @param Xhc The XHCI device.
397 @param Timeout Time to wait before abort.
398
399 @retval EFI_TIMEOUT Failed to halt the controller before Timeout.
400 @retval EFI_SUCCESS The XHCI is halt.
401
402 **/
403 EFI_STATUS
404 XhcPeiHaltHC (
405 IN PEI_XHC_DEV *Xhc,
406 IN UINT32 Timeout
407 )
408 {
409 EFI_STATUS Status;
410
411 XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
412 Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);
413 DEBUG ((EFI_D_INFO, "XhcPeiHaltHC: %r\n", Status));
414 return Status;
415 }
416
417 /**
418 Set the XHCI to run.
419
420 @param Xhc The XHCI device.
421 @param Timeout Time to wait before abort.
422
423 @retval EFI_SUCCESS The XHCI is running.
424 @retval Others Failed to set the XHCI to run.
425
426 **/
427 EFI_STATUS
428 XhcPeiRunHC (
429 IN PEI_XHC_DEV *Xhc,
430 IN UINT32 Timeout
431 )
432 {
433 EFI_STATUS Status;
434
435 XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
436 Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);
437 DEBUG ((EFI_D_INFO, "XhcPeiRunHC: %r\n", Status));
438 return Status;
439 }
440
441 /**
442 Submits control transfer to a target USB device.
443
444 @param PeiServices The pointer of EFI_PEI_SERVICES.
445 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
446 @param DeviceAddress The target device address.
447 @param DeviceSpeed Target device speed.
448 @param MaximumPacketLength Maximum packet size the default control transfer
449 endpoint is capable of sending or receiving.
450 @param Request USB device request to send.
451 @param TransferDirection Specifies the data direction for the data stage.
452 @param Data Data buffer to be transmitted or received from USB device.
453 @param DataLength The size (in bytes) of the data buffer.
454 @param TimeOut Indicates the maximum timeout, in millisecond.
455 If Timeout is 0, then the caller must wait for the function
456 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
457 @param Translator Transaction translator to be used by this device.
458 @param TransferResult Return the result of this control transfer.
459
460 @retval EFI_SUCCESS Transfer was completed successfully.
461 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
462 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
463 @retval EFI_TIMEOUT Transfer failed due to timeout.
464 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
465
466 **/
467 EFI_STATUS
468 EFIAPI
469 XhcPeiControlTransfer (
470 IN EFI_PEI_SERVICES **PeiServices,
471 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
472 IN UINT8 DeviceAddress,
473 IN UINT8 DeviceSpeed,
474 IN UINTN MaximumPacketLength,
475 IN EFI_USB_DEVICE_REQUEST *Request,
476 IN EFI_USB_DATA_DIRECTION TransferDirection,
477 IN OUT VOID *Data,
478 IN OUT UINTN *DataLength,
479 IN UINTN TimeOut,
480 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
481 OUT UINT32 *TransferResult
482 )
483 {
484 PEI_XHC_DEV *Xhc;
485 URB *Urb;
486 UINT8 Endpoint;
487 UINT8 Index;
488 UINT8 DescriptorType;
489 UINT8 SlotId;
490 UINT8 TTT;
491 UINT8 MTT;
492 UINT32 MaxPacket0;
493 EFI_USB_HUB_DESCRIPTOR *HubDesc;
494 EFI_STATUS Status;
495 EFI_STATUS RecoveryStatus;
496 UINTN MapSize;
497 EFI_USB_PORT_STATUS PortStatus;
498 UINT32 State;
499 EFI_USB_DEVICE_REQUEST ClearPortRequest;
500 UINTN Len;
501
502 //
503 // Validate parameters
504 //
505 if ((Request == NULL) || (TransferResult == NULL)) {
506 return EFI_INVALID_PARAMETER;
507 }
508
509 if ((TransferDirection != EfiUsbDataIn) &&
510 (TransferDirection != EfiUsbDataOut) &&
511 (TransferDirection != EfiUsbNoData)) {
512 return EFI_INVALID_PARAMETER;
513 }
514
515 if ((TransferDirection == EfiUsbNoData) &&
516 ((Data != NULL) || (*DataLength != 0))) {
517 return EFI_INVALID_PARAMETER;
518 }
519
520 if ((TransferDirection != EfiUsbNoData) &&
521 ((Data == NULL) || (*DataLength == 0))) {
522 return EFI_INVALID_PARAMETER;
523 }
524
525 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
526 (MaximumPacketLength != 32) && (MaximumPacketLength != 64) &&
527 (MaximumPacketLength != 512)
528 ) {
529 return EFI_INVALID_PARAMETER;
530 }
531
532 if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {
533 return EFI_INVALID_PARAMETER;
534 }
535
536 if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) {
537 return EFI_INVALID_PARAMETER;
538 }
539
540 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
541
542 Status = EFI_DEVICE_ERROR;
543 *TransferResult = EFI_USB_ERR_SYSTEM;
544 Len = 0;
545
546 if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
547 DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: HC is halted or has system error\n"));
548 goto ON_EXIT;
549 }
550
551 //
552 // Check if the device is still enabled before every transaction.
553 //
554 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);
555 if (SlotId == 0) {
556 goto ON_EXIT;
557 }
558
559 //
560 // Hook the Set_Address request from UsbBus.
561 // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.
562 //
563 if ((Request->Request == USB_REQ_SET_ADDRESS) &&
564 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
565 //
566 // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.
567 // This way is used to clean the history to avoid using wrong device address afterwards.
568 //
569 for (Index = 0; Index < 255; Index++) {
570 if (!Xhc->UsbDevContext[Index + 1].Enabled &&
571 (Xhc->UsbDevContext[Index + 1].SlotId == 0) &&
572 (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8) Request->Value)) {
573 Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;
574 }
575 }
576
577 if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {
578 goto ON_EXIT;
579 }
580 //
581 // The actual device address has been assigned by XHCI during initializing the device slot.
582 // So we just need establish the mapping relationship between the device address requested from UsbBus
583 // and the actual device address assigned by XHCI. The following invocations through EFI_USB2_HC_PROTOCOL interface
584 // can find out the actual device address by it.
585 //
586 Xhc->UsbDevContext[SlotId].BusDevAddr = (UINT8) Request->Value;
587 Status = EFI_SUCCESS;
588 goto ON_EXIT;
589 }
590
591 //
592 // Create a new URB, insert it into the asynchronous
593 // schedule list, then poll the execution status.
594 // Note that we encode the direction in address although default control
595 // endpoint is bidirectional. XhcPeiCreateUrb expects this
596 // combination of Ep addr and its direction.
597 //
598 Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
599 Urb = XhcPeiCreateUrb (
600 Xhc,
601 DeviceAddress,
602 Endpoint,
603 DeviceSpeed,
604 MaximumPacketLength,
605 XHC_CTRL_TRANSFER,
606 Request,
607 Data,
608 *DataLength,
609 NULL,
610 NULL
611 );
612
613 if (Urb == NULL) {
614 DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: failed to create URB"));
615 Status = EFI_OUT_OF_RESOURCES;
616 goto ON_EXIT;
617 }
618
619 Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);
620
621 //
622 // Get the status from URB. The result is updated in XhcPeiCheckUrbResult
623 // which is called by XhcPeiExecTransfer
624 //
625 *TransferResult = Urb->Result;
626 *DataLength = Urb->Completed;
627
628 if (Status == EFI_TIMEOUT) {
629 //
630 // The transfer timed out. Abort the transfer by dequeueing of the TD.
631 //
632 RecoveryStatus = XhcPeiDequeueTrbFromEndpoint(Xhc, Urb);
633 if (EFI_ERROR(RecoveryStatus)) {
634 DEBUG((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));
635 }
636 XhcPeiFreeUrb (Xhc, Urb);
637 goto ON_EXIT;
638 } else {
639 if (*TransferResult == EFI_USB_NOERROR) {
640 Status = EFI_SUCCESS;
641 } else if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {
642 RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);
643 if (EFI_ERROR (RecoveryStatus)) {
644 DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));
645 }
646 Status = EFI_DEVICE_ERROR;
647 XhcPeiFreeUrb (Xhc, Urb);
648 goto ON_EXIT;
649 } else {
650 XhcPeiFreeUrb (Xhc, Urb);
651 goto ON_EXIT;
652 }
653 }
654 //
655 // Unmap data before consume.
656 //
657 XhcPeiFreeUrb (Xhc, Urb);
658
659 //
660 // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.
661 // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.
662 // Hook Set_Config request from UsbBus as we need configure device endpoint.
663 //
664 if ((Request->Request == USB_REQ_GET_DESCRIPTOR) &&
665 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||
666 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) {
667 DescriptorType = (UINT8) (Request->Value >> 8);
668 if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {
669 ASSERT (Data != NULL);
670 //
671 // Store a copy of device scriptor as hub device need this info to configure endpoint.
672 //
673 CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);
674 if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB >= 0x0300) {
675 //
676 // If it's a usb3.0 device, then its max packet size is a 2^n.
677 //
678 MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
679 } else {
680 MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
681 }
682 Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));
683 if (Xhc->UsbDevContext[SlotId].ConfDesc == NULL) {
684 Status = EFI_OUT_OF_RESOURCES;
685 goto ON_EXIT;
686 }
687 if (Xhc->HcCParams.Data.Csz == 0) {
688 Status = XhcPeiEvaluateContext (Xhc, SlotId, MaxPacket0);
689 } else {
690 Status = XhcPeiEvaluateContext64 (Xhc, SlotId, MaxPacket0);
691 }
692 } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {
693 ASSERT (Data != NULL);
694 if (*DataLength == ((UINT16 *) Data)[1]) {
695 //
696 // Get configuration value from request, store the configuration descriptor for Configure_Endpoint cmd.
697 //
698 Index = (UINT8) Request->Value;
699 ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);
700 Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool (*DataLength);
701 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] == NULL) {
702 Status = EFI_OUT_OF_RESOURCES;
703 goto ON_EXIT;
704 }
705 CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);
706 }
707 } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||
708 (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2)) {
709 ASSERT (Data != NULL);
710 HubDesc = (EFI_USB_HUB_DESCRIPTOR *) Data;
711 ASSERT (HubDesc->NumPorts <= 15);
712 //
713 // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.
714 //
715 TTT = (UINT8) ((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);
716 if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {
717 //
718 // Don't support multi-TT feature for super speed hub now.
719 //
720 MTT = 0;
721 DEBUG ((EFI_D_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));
722 } else {
723 MTT = 0;
724 }
725
726 if (Xhc->HcCParams.Data.Csz == 0) {
727 Status = XhcPeiConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
728 } else {
729 Status = XhcPeiConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
730 }
731 }
732 } else if ((Request->Request == USB_REQ_SET_CONFIG) &&
733 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
734 //
735 // Hook Set_Config request from UsbBus as we need configure device endpoint.
736 //
737 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
738 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {
739 if (Xhc->HcCParams.Data.Csz == 0) {
740 Status = XhcPeiSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
741 } else {
742 Status = XhcPeiSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
743 }
744 break;
745 }
746 }
747 } else if ((Request->Request == USB_REQ_GET_STATUS) &&
748 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER))) {
749 ASSERT (Data != NULL);
750 //
751 // Hook Get_Status request from UsbBus to keep track of the port status change.
752 //
753 State = *(UINT32 *) Data;
754 PortStatus.PortStatus = 0;
755 PortStatus.PortChangeStatus = 0;
756
757 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
758 //
759 // For super speed hub, its bit10~12 presents the attached device speed.
760 //
761 if ((State & XHC_PORTSC_PS) >> 10 == 0) {
762 PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;
763 }
764 } else {
765 //
766 // For high or full/low speed hub, its bit9~10 presents the attached device speed.
767 //
768 if (XHC_BIT_IS_SET (State, BIT9)) {
769 PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;
770 } else if (XHC_BIT_IS_SET (State, BIT10)) {
771 PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;
772 }
773 }
774
775 //
776 // Convert the XHCI port/port change state to UEFI status
777 //
778 MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);
779 for (Index = 0; Index < MapSize; Index++) {
780 if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {
781 PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);
782 }
783 }
784
785 MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
786 for (Index = 0; Index < MapSize; Index++) {
787 if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {
788 PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);
789 }
790 }
791
792 MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
793
794 for (Index = 0; Index < MapSize; Index++) {
795 if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {
796 ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));
797 ClearPortRequest.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);
798 ClearPortRequest.Request = (UINT8) USB_REQ_CLEAR_FEATURE;
799 ClearPortRequest.Value = mUsbHubClearPortChangeMap[Index].Selector;
800 ClearPortRequest.Index = Request->Index;
801 ClearPortRequest.Length = 0;
802
803 XhcPeiControlTransfer (
804 PeiServices,
805 This,
806 DeviceAddress,
807 DeviceSpeed,
808 MaximumPacketLength,
809 &ClearPortRequest,
810 EfiUsbNoData,
811 NULL,
812 &Len,
813 TimeOut,
814 Translator,
815 TransferResult
816 );
817 }
818 }
819
820 XhcPeiPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);
821
822 *(UINT32 *) Data = *(UINT32 *) &PortStatus;
823 }
824
825 ON_EXIT:
826
827 if (EFI_ERROR (Status)) {
828 DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
829 }
830
831 return Status;
832 }
833
834 /**
835 Submits bulk transfer to a bulk endpoint of a USB device.
836
837 @param PeiServices The pointer of EFI_PEI_SERVICES.
838 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
839 @param DeviceAddress Target device address.
840 @param EndPointAddress Endpoint number and its direction in bit 7.
841 @param DeviceSpeed Device speed, Low speed device doesn't support
842 bulk transfer.
843 @param MaximumPacketLength Maximum packet size the endpoint is capable of
844 sending or receiving.
845 @param Data Array of pointers to the buffers of data to transmit
846 from or receive into.
847 @param DataLength The lenght of the data buffer.
848 @param DataToggle On input, the initial data toggle for the transfer;
849 On output, it is updated to to next data toggle to use of
850 the subsequent bulk transfer.
851 @param TimeOut Indicates the maximum time, in millisecond, which the
852 transfer is allowed to complete.
853 If Timeout is 0, then the caller must wait for the function
854 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
855 @param Translator A pointr to the transaction translator data.
856 @param TransferResult A pointer to the detailed result information of the
857 bulk transfer.
858
859 @retval EFI_SUCCESS The transfer was completed successfully.
860 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
861 @retval EFI_INVALID_PARAMETER Parameters are invalid.
862 @retval EFI_TIMEOUT The transfer failed due to timeout.
863 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
864
865 **/
866 EFI_STATUS
867 EFIAPI
868 XhcPeiBulkTransfer (
869 IN EFI_PEI_SERVICES **PeiServices,
870 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
871 IN UINT8 DeviceAddress,
872 IN UINT8 EndPointAddress,
873 IN UINT8 DeviceSpeed,
874 IN UINTN MaximumPacketLength,
875 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
876 IN OUT UINTN *DataLength,
877 IN OUT UINT8 *DataToggle,
878 IN UINTN TimeOut,
879 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
880 OUT UINT32 *TransferResult
881 )
882 {
883 PEI_XHC_DEV *Xhc;
884 URB *Urb;
885 UINT8 SlotId;
886 EFI_STATUS Status;
887 EFI_STATUS RecoveryStatus;
888
889 //
890 // Validate the parameters
891 //
892 if ((DataLength == NULL) || (*DataLength == 0) ||
893 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {
894 return EFI_INVALID_PARAMETER;
895 }
896
897 if ((*DataToggle != 0) && (*DataToggle != 1)) {
898 return EFI_INVALID_PARAMETER;
899 }
900
901 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
902 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
903 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 512)) ||
904 ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength > 1024))) {
905 return EFI_INVALID_PARAMETER;
906 }
907
908 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
909
910 *TransferResult = EFI_USB_ERR_SYSTEM;
911 Status = EFI_DEVICE_ERROR;
912
913 if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
914 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: HC is halted or has system error\n"));
915 goto ON_EXIT;
916 }
917
918 //
919 // Check if the device is still enabled before every transaction.
920 //
921 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);
922 if (SlotId == 0) {
923 goto ON_EXIT;
924 }
925
926 //
927 // Create a new URB, insert it into the asynchronous
928 // schedule list, then poll the execution status.
929 //
930 Urb = XhcPeiCreateUrb (
931 Xhc,
932 DeviceAddress,
933 EndPointAddress,
934 DeviceSpeed,
935 MaximumPacketLength,
936 XHC_BULK_TRANSFER,
937 NULL,
938 Data[0],
939 *DataLength,
940 NULL,
941 NULL
942 );
943
944 if (Urb == NULL) {
945 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: failed to create URB\n"));
946 Status = EFI_OUT_OF_RESOURCES;
947 goto ON_EXIT;
948 }
949
950 Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);
951
952 *TransferResult = Urb->Result;
953 *DataLength = Urb->Completed;
954
955 if (Status == EFI_TIMEOUT) {
956 //
957 // The transfer timed out. Abort the transfer by dequeueing of the TD.
958 //
959 RecoveryStatus = XhcPeiDequeueTrbFromEndpoint(Xhc, Urb);
960 if (EFI_ERROR(RecoveryStatus)) {
961 DEBUG((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));
962 }
963 } else {
964 if (*TransferResult == EFI_USB_NOERROR) {
965 Status = EFI_SUCCESS;
966 } else if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {
967 RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);
968 if (EFI_ERROR (RecoveryStatus)) {
969 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));
970 }
971 Status = EFI_DEVICE_ERROR;
972 }
973 }
974
975 XhcPeiFreeUrb (Xhc, Urb);
976
977 ON_EXIT:
978
979 if (EFI_ERROR (Status)) {
980 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
981 }
982
983 return Status;
984 }
985
986 /**
987 Retrieves the number of root hub ports.
988
989 @param[in] PeiServices The pointer to the PEI Services Table.
990 @param[in] This The pointer to this instance of the
991 PEI_USB2_HOST_CONTROLLER_PPI.
992 @param[out] PortNumber The pointer to the number of the root hub ports.
993
994 @retval EFI_SUCCESS The port number was retrieved successfully.
995 @retval EFI_INVALID_PARAMETER PortNumber is NULL.
996
997 **/
998 EFI_STATUS
999 EFIAPI
1000 XhcPeiGetRootHubPortNumber (
1001 IN EFI_PEI_SERVICES **PeiServices,
1002 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
1003 OUT UINT8 *PortNumber
1004 )
1005 {
1006 PEI_XHC_DEV *XhcDev;
1007 XhcDev = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1008
1009 if (PortNumber == NULL) {
1010 return EFI_INVALID_PARAMETER;
1011 }
1012
1013 *PortNumber = XhcDev->HcSParams1.Data.MaxPorts;
1014 DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortNumber: PortNumber = %x\n", *PortNumber));
1015 return EFI_SUCCESS;
1016 }
1017
1018 /**
1019 Clears a feature for the specified root hub port.
1020
1021 @param PeiServices The pointer of EFI_PEI_SERVICES.
1022 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
1023 @param PortNumber Specifies the root hub port whose feature
1024 is requested to be cleared.
1025 @param PortFeature Indicates the feature selector associated with the
1026 feature clear request.
1027
1028 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
1029 for the USB root hub port specified by PortNumber.
1030 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
1031
1032 **/
1033 EFI_STATUS
1034 EFIAPI
1035 XhcPeiClearRootHubPortFeature (
1036 IN EFI_PEI_SERVICES **PeiServices,
1037 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
1038 IN UINT8 PortNumber,
1039 IN EFI_USB_PORT_FEATURE PortFeature
1040 )
1041 {
1042 PEI_XHC_DEV *Xhc;
1043 UINT32 Offset;
1044 UINT32 State;
1045 EFI_STATUS Status;
1046
1047 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1048 Status = EFI_SUCCESS;
1049
1050 if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
1051 Status = EFI_INVALID_PARAMETER;
1052 goto ON_EXIT;
1053 }
1054
1055 Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
1056 State = XhcPeiReadOpReg (Xhc, Offset);
1057 DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));
1058
1059 //
1060 // Mask off the port status change bits, these bits are
1061 // write clean bits
1062 //
1063 State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
1064
1065 switch (PortFeature) {
1066 case EfiUsbPortEnable:
1067 //
1068 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
1069 // A port may be disabled by software writing a '1' to this flag.
1070 //
1071 State |= XHC_PORTSC_PED;
1072 State &= ~XHC_PORTSC_RESET;
1073 XhcPeiWriteOpReg (Xhc, Offset, State);
1074 break;
1075
1076 case EfiUsbPortSuspend:
1077 State |= XHC_PORTSC_LWS;
1078 XhcPeiWriteOpReg (Xhc, Offset, State);
1079 State &= ~XHC_PORTSC_PLS;
1080 XhcPeiWriteOpReg (Xhc, Offset, State);
1081 break;
1082
1083 case EfiUsbPortReset:
1084 //
1085 // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:
1086 // Register bits indicate status when read, a clear bit may be set by
1087 // writing a '1'. Writing a '0' to RW1S bits has no effect.
1088 //
1089 break;
1090
1091 case EfiUsbPortPower:
1092 if (Xhc->HcCParams.Data.Ppc) {
1093 //
1094 // Port Power Control supported
1095 //
1096 State &= ~XHC_PORTSC_PP;
1097 XhcPeiWriteOpReg (Xhc, Offset, State);
1098 }
1099 break;
1100
1101 case EfiUsbPortOwner:
1102 //
1103 // XHCI root hub port don't has the owner bit, ignore the operation
1104 //
1105 break;
1106
1107 case EfiUsbPortConnectChange:
1108 //
1109 // Clear connect status change
1110 //
1111 State |= XHC_PORTSC_CSC;
1112 XhcPeiWriteOpReg (Xhc, Offset, State);
1113 break;
1114
1115 case EfiUsbPortEnableChange:
1116 //
1117 // Clear enable status change
1118 //
1119 State |= XHC_PORTSC_PEC;
1120 XhcPeiWriteOpReg (Xhc, Offset, State);
1121 break;
1122
1123 case EfiUsbPortOverCurrentChange:
1124 //
1125 // Clear PortOverCurrent change
1126 //
1127 State |= XHC_PORTSC_OCC;
1128 XhcPeiWriteOpReg (Xhc, Offset, State);
1129 break;
1130
1131 case EfiUsbPortResetChange:
1132 //
1133 // Clear Port Reset change
1134 //
1135 State |= XHC_PORTSC_PRC;
1136 XhcPeiWriteOpReg (Xhc, Offset, State);
1137 break;
1138
1139 case EfiUsbPortSuspendChange:
1140 //
1141 // Not supported or not related operation
1142 //
1143 break;
1144
1145 default:
1146 Status = EFI_INVALID_PARAMETER;
1147 break;
1148 }
1149
1150 ON_EXIT:
1151 DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));
1152 return Status;
1153 }
1154
1155 /**
1156 Sets a feature for the specified root hub port.
1157
1158 @param PeiServices The pointer of EFI_PEI_SERVICES
1159 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI
1160 @param PortNumber Root hub port to set.
1161 @param PortFeature Feature to set.
1162
1163 @retval EFI_SUCCESS The feature specified by PortFeature was set.
1164 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
1165 @retval EFI_TIMEOUT The time out occurred.
1166
1167 **/
1168 EFI_STATUS
1169 EFIAPI
1170 XhcPeiSetRootHubPortFeature (
1171 IN EFI_PEI_SERVICES **PeiServices,
1172 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
1173 IN UINT8 PortNumber,
1174 IN EFI_USB_PORT_FEATURE PortFeature
1175 )
1176 {
1177 PEI_XHC_DEV *Xhc;
1178 UINT32 Offset;
1179 UINT32 State;
1180 EFI_STATUS Status;
1181
1182 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1183 Status = EFI_SUCCESS;
1184
1185 if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
1186 Status = EFI_INVALID_PARAMETER;
1187 goto ON_EXIT;
1188 }
1189
1190 Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
1191 State = XhcPeiReadOpReg (Xhc, Offset);
1192 DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));
1193
1194 //
1195 // Mask off the port status change bits, these bits are
1196 // write clean bits
1197 //
1198 State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
1199
1200 switch (PortFeature) {
1201 case EfiUsbPortEnable:
1202 //
1203 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
1204 // A port may be disabled by software writing a '1' to this flag.
1205 //
1206 break;
1207
1208 case EfiUsbPortSuspend:
1209 State |= XHC_PORTSC_LWS;
1210 XhcPeiWriteOpReg (Xhc, Offset, State);
1211 State &= ~XHC_PORTSC_PLS;
1212 State |= (3 << 5) ;
1213 XhcPeiWriteOpReg (Xhc, Offset, State);
1214 break;
1215
1216 case EfiUsbPortReset:
1217 //
1218 // Make sure Host Controller not halt before reset it
1219 //
1220 if (XhcPeiIsHalt (Xhc)) {
1221 Status = XhcPeiRunHC (Xhc, XHC_GENERIC_TIMEOUT);
1222 if (EFI_ERROR (Status)) {
1223 break;
1224 }
1225 }
1226
1227 //
1228 // 4.3.1 Resetting a Root Hub Port
1229 // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
1230 // 2) Wait for a successful Port Status Change Event for the port, where the Port Reset Change (PRC)
1231 // bit in the PORTSC field is set to '1'.
1232 //
1233 State |= XHC_PORTSC_RESET;
1234 XhcPeiWriteOpReg (Xhc, Offset, State);
1235 XhcPeiWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);
1236 break;
1237
1238 case EfiUsbPortPower:
1239 if (Xhc->HcCParams.Data.Ppc) {
1240 //
1241 // Port Power Control supported
1242 //
1243 State |= XHC_PORTSC_PP;
1244 XhcPeiWriteOpReg (Xhc, Offset, State);
1245 }
1246 break;
1247
1248 case EfiUsbPortOwner:
1249 //
1250 // XHCI root hub port don't has the owner bit, ignore the operation
1251 //
1252 break;
1253
1254 default:
1255 Status = EFI_INVALID_PARAMETER;
1256 }
1257
1258 ON_EXIT:
1259 DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));
1260 return Status;
1261 }
1262
1263 /**
1264 Retrieves the current status of a USB root hub port.
1265
1266 @param PeiServices The pointer of EFI_PEI_SERVICES.
1267 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
1268 @param PortNumber The root hub port to retrieve the state from.
1269 @param PortStatus Variable to receive the port state.
1270
1271 @retval EFI_SUCCESS The status of the USB root hub port specified.
1272 by PortNumber was returned in PortStatus.
1273 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
1274
1275 **/
1276 EFI_STATUS
1277 EFIAPI
1278 XhcPeiGetRootHubPortStatus (
1279 IN EFI_PEI_SERVICES **PeiServices,
1280 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
1281 IN UINT8 PortNumber,
1282 OUT EFI_USB_PORT_STATUS *PortStatus
1283 )
1284 {
1285 PEI_XHC_DEV *Xhc;
1286 UINT32 Offset;
1287 UINT32 State;
1288 UINTN Index;
1289 UINTN MapSize;
1290 USB_DEV_ROUTE ParentRouteChart;
1291
1292 if (PortStatus == NULL) {
1293 return EFI_INVALID_PARAMETER;
1294 }
1295
1296 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1297
1298 if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
1299 return EFI_INVALID_PARAMETER;
1300 }
1301
1302 //
1303 // Clear port status.
1304 //
1305 PortStatus->PortStatus = 0;
1306 PortStatus->PortChangeStatus = 0;
1307
1308 Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
1309 State = XhcPeiReadOpReg (Xhc, Offset);
1310 DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: Port: %x State: %x\n", PortNumber, State));
1311
1312 //
1313 // According to XHCI 1.1 spec November 2017,
1314 // bit 10~13 of the root port status register identifies the speed of the attached device.
1315 //
1316 switch ((State & XHC_PORTSC_PS) >> 10) {
1317 case 2:
1318 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
1319 break;
1320
1321 case 3:
1322 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
1323 break;
1324
1325 case 4:
1326 case 5:
1327 PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;
1328 break;
1329
1330 default:
1331 break;
1332 }
1333
1334 //
1335 // Convert the XHCI port/port change state to UEFI status
1336 //
1337 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
1338
1339 for (Index = 0; Index < MapSize; Index++) {
1340 if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
1341 PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
1342 }
1343 }
1344 //
1345 // Bit5~8 reflects its current link state.
1346 //
1347 if ((State & XHC_PORTSC_PLS) >> 5 == 3) {
1348 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
1349 }
1350
1351 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
1352
1353 for (Index = 0; Index < MapSize; Index++) {
1354 if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
1355 PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
1356 }
1357 }
1358
1359 MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
1360
1361 for (Index = 0; Index < MapSize; Index++) {
1362 if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {
1363 XhcPeiClearRootHubPortFeature (PeiServices, This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);
1364 }
1365 }
1366
1367 //
1368 // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.
1369 // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.
1370 //
1371 ParentRouteChart.Dword = 0;
1372 XhcPeiPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);
1373
1374 DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: PortChangeStatus: %x PortStatus: %x\n", PortStatus->PortChangeStatus, PortStatus->PortStatus));
1375 return EFI_SUCCESS;
1376 }
1377
1378 /**
1379 One notified function to stop the Host Controller at the end of PEI
1380
1381 @param[in] PeiServices Pointer to PEI Services Table.
1382 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification event that
1383 caused this function to execute.
1384 @param[in] Ppi Pointer to the PPI data associated with this function.
1385
1386 @retval EFI_SUCCESS The function completes successfully
1387 @retval others
1388 **/
1389 EFI_STATUS
1390 EFIAPI
1391 XhcEndOfPei (
1392 IN EFI_PEI_SERVICES **PeiServices,
1393 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
1394 IN VOID *Ppi
1395 )
1396 {
1397 PEI_XHC_DEV *Xhc;
1398
1399 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS_NOTIFY(NotifyDescriptor);
1400
1401 XhcPeiHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
1402
1403 XhcPeiFreeSched (Xhc);
1404
1405 return EFI_SUCCESS;
1406 }
1407
1408 /**
1409 @param FileHandle Handle of the file being invoked.
1410 @param PeiServices Describes the list of possible PEI Services.
1411
1412 @retval EFI_SUCCESS PPI successfully installed.
1413
1414 **/
1415 EFI_STATUS
1416 EFIAPI
1417 XhcPeimEntry (
1418 IN EFI_PEI_FILE_HANDLE FileHandle,
1419 IN CONST EFI_PEI_SERVICES **PeiServices
1420 )
1421 {
1422 PEI_USB_CONTROLLER_PPI *UsbControllerPpi;
1423 EFI_STATUS Status;
1424 UINT8 Index;
1425 UINTN ControllerType;
1426 UINTN BaseAddress;
1427 UINTN MemPages;
1428 PEI_XHC_DEV *XhcDev;
1429 EFI_PHYSICAL_ADDRESS TempPtr;
1430 UINT32 PageSize;
1431
1432 //
1433 // Shadow this PEIM to run from memory.
1434 //
1435 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
1436 return EFI_SUCCESS;
1437 }
1438
1439 Status = PeiServicesLocatePpi (
1440 &gPeiUsbControllerPpiGuid,
1441 0,
1442 NULL,
1443 (VOID **) &UsbControllerPpi
1444 );
1445 if (EFI_ERROR (Status)) {
1446 return EFI_UNSUPPORTED;
1447 }
1448
1449 IoMmuInit ();
1450
1451 Index = 0;
1452 while (TRUE) {
1453 Status = UsbControllerPpi->GetUsbController (
1454 (EFI_PEI_SERVICES **) PeiServices,
1455 UsbControllerPpi,
1456 Index,
1457 &ControllerType,
1458 &BaseAddress
1459 );
1460 //
1461 // When status is error, it means no controller is found.
1462 //
1463 if (EFI_ERROR (Status)) {
1464 break;
1465 }
1466
1467 //
1468 // This PEIM is for XHC type controller.
1469 //
1470 if (ControllerType != PEI_XHCI_CONTROLLER) {
1471 Index++;
1472 continue;
1473 }
1474
1475 MemPages = EFI_SIZE_TO_PAGES (sizeof (PEI_XHC_DEV));
1476 Status = PeiServicesAllocatePages (
1477 EfiBootServicesData,
1478 MemPages,
1479 &TempPtr
1480 );
1481 if (EFI_ERROR (Status)) {
1482 return EFI_OUT_OF_RESOURCES;
1483 }
1484 ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (MemPages));
1485 XhcDev = (PEI_XHC_DEV *) ((UINTN) TempPtr);
1486
1487 XhcDev->Signature = USB_XHC_DEV_SIGNATURE;
1488 XhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
1489 XhcDev->CapLength = (UINT8) (XhcPeiReadCapRegister (XhcDev, XHC_CAPLENGTH_OFFSET) & 0x0FF);
1490 XhcDev->HcSParams1.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS1_OFFSET);
1491 XhcDev->HcSParams2.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS2_OFFSET);
1492 XhcDev->HcCParams.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCCPARAMS_OFFSET);
1493 XhcDev->DBOff = XhcPeiReadCapRegister (XhcDev, XHC_DBOFF_OFFSET);
1494 XhcDev->RTSOff = XhcPeiReadCapRegister (XhcDev, XHC_RTSOFF_OFFSET);
1495
1496 //
1497 // This PageSize field defines the page size supported by the xHC implementation.
1498 // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
1499 // if bit 0 is Set, the xHC supports 4k byte page sizes.
1500 //
1501 PageSize = XhcPeiReadOpReg (XhcDev, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK;
1502 XhcDev->PageSize = 1 << (HighBitSet32 (PageSize) + 12);
1503
1504 DEBUG ((EFI_D_INFO, "XhciPei: UsbHostControllerBaseAddress: %x\n", XhcDev->UsbHostControllerBaseAddress));
1505 DEBUG ((EFI_D_INFO, "XhciPei: CapLength: %x\n", XhcDev->CapLength));
1506 DEBUG ((EFI_D_INFO, "XhciPei: HcSParams1: %x\n", XhcDev->HcSParams1.Dword));
1507 DEBUG ((EFI_D_INFO, "XhciPei: HcSParams2: %x\n", XhcDev->HcSParams2.Dword));
1508 DEBUG ((EFI_D_INFO, "XhciPei: HcCParams: %x\n", XhcDev->HcCParams.Dword));
1509 DEBUG ((EFI_D_INFO, "XhciPei: DBOff: %x\n", XhcDev->DBOff));
1510 DEBUG ((EFI_D_INFO, "XhciPei: RTSOff: %x\n", XhcDev->RTSOff));
1511 DEBUG ((EFI_D_INFO, "XhciPei: PageSize: %x\n", XhcDev->PageSize));
1512
1513 XhcPeiResetHC (XhcDev, XHC_RESET_TIMEOUT);
1514 ASSERT (XhcPeiIsHalt (XhcDev));
1515
1516 //
1517 // Initialize the schedule
1518 //
1519 XhcPeiInitSched (XhcDev);
1520
1521 //
1522 // Start the Host Controller
1523 //
1524 XhcPeiRunHC (XhcDev, XHC_GENERIC_TIMEOUT);
1525
1526 //
1527 // Wait for root port state stable
1528 //
1529 MicroSecondDelay (XHC_ROOT_PORT_STATE_STABLE);
1530
1531 XhcDev->Usb2HostControllerPpi.ControlTransfer = XhcPeiControlTransfer;
1532 XhcDev->Usb2HostControllerPpi.BulkTransfer = XhcPeiBulkTransfer;
1533 XhcDev->Usb2HostControllerPpi.GetRootHubPortNumber = XhcPeiGetRootHubPortNumber;
1534 XhcDev->Usb2HostControllerPpi.GetRootHubPortStatus = XhcPeiGetRootHubPortStatus;
1535 XhcDev->Usb2HostControllerPpi.SetRootHubPortFeature = XhcPeiSetRootHubPortFeature;
1536 XhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature = XhcPeiClearRootHubPortFeature;
1537
1538 XhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
1539 XhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;
1540 XhcDev->PpiDescriptor.Ppi = &XhcDev->Usb2HostControllerPpi;
1541
1542 XhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
1543 XhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;
1544 XhcDev->EndOfPeiNotifyList.Notify = XhcEndOfPei;
1545
1546 PeiServicesInstallPpi (&XhcDev->PpiDescriptor);
1547 PeiServicesNotifyPpi (&XhcDev->EndOfPeiNotifyList);
1548
1549 Index++;
1550 }
1551
1552 return EFI_SUCCESS;
1553 }
1554