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