]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / XhciReg.c
1 /** @file
2
3 The XHCI register operation routines.
4
5 Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "Xhci.h"
11
12 /**
13 Read 1-byte width XHCI capability register.
14
15 @param Xhc The XHCI Instance.
16 @param Offset The offset of the 1-byte width capability register.
17
18 @return The register content read.
19 @retval If err, return 0xFF.
20
21 **/
22 UINT8
23 XhcReadCapReg8 (
24 IN USB_XHCI_INSTANCE *Xhc,
25 IN UINT32 Offset
26 )
27 {
28 UINT8 Data;
29 EFI_STATUS Status;
30
31 Status = Xhc->PciIo->Mem.Read (
32 Xhc->PciIo,
33 EfiPciIoWidthUint8,
34 XHC_BAR_INDEX,
35 (UINT64)Offset,
36 1,
37 &Data
38 );
39
40 if (EFI_ERROR (Status)) {
41 DEBUG ((DEBUG_ERROR, "XhcReadCapReg: Pci Io read error - %r at %d\n", Status, Offset));
42 Data = 0xFF;
43 }
44
45 return Data;
46 }
47
48 /**
49 Read 4-bytes width XHCI capability register.
50
51 @param Xhc The XHCI Instance.
52 @param Offset The offset of the 4-bytes width capability register.
53
54 @return The register content read.
55 @retval If err, return 0xFFFFFFFF.
56
57 **/
58 UINT32
59 XhcReadCapReg (
60 IN USB_XHCI_INSTANCE *Xhc,
61 IN UINT32 Offset
62 )
63 {
64 UINT32 Data;
65 EFI_STATUS Status;
66
67 Status = Xhc->PciIo->Mem.Read (
68 Xhc->PciIo,
69 EfiPciIoWidthUint32,
70 XHC_BAR_INDEX,
71 (UINT64)Offset,
72 1,
73 &Data
74 );
75
76 if (EFI_ERROR (Status)) {
77 DEBUG ((DEBUG_ERROR, "XhcReadCapReg: Pci Io read error - %r at %d\n", Status, Offset));
78 Data = 0xFFFFFFFF;
79 }
80
81 return Data;
82 }
83
84 /**
85 Read 4-bytes width XHCI Operational register.
86
87 @param Xhc The XHCI Instance.
88 @param Offset The offset of the 4-bytes width operational register.
89
90 @return The register content read.
91 @retval If err, return 0xFFFFFFFF.
92
93 **/
94 UINT32
95 XhcReadOpReg (
96 IN USB_XHCI_INSTANCE *Xhc,
97 IN UINT32 Offset
98 )
99 {
100 UINT32 Data;
101 EFI_STATUS Status;
102
103 ASSERT (Xhc->CapLength != 0);
104
105 Status = Xhc->PciIo->Mem.Read (
106 Xhc->PciIo,
107 EfiPciIoWidthUint32,
108 XHC_BAR_INDEX,
109 Xhc->CapLength + Offset,
110 1,
111 &Data
112 );
113
114 if (EFI_ERROR (Status)) {
115 DEBUG ((DEBUG_ERROR, "XhcReadOpReg: Pci Io Read error - %r at %d\n", Status, Offset));
116 Data = 0xFFFFFFFF;
117 }
118
119 return Data;
120 }
121
122 /**
123 Write the data to the 4-bytes width XHCI operational register.
124
125 @param Xhc The XHCI Instance.
126 @param Offset The offset of the 4-bytes width operational register.
127 @param Data The data to write.
128
129 **/
130 VOID
131 XhcWriteOpReg (
132 IN USB_XHCI_INSTANCE *Xhc,
133 IN UINT32 Offset,
134 IN UINT32 Data
135 )
136 {
137 EFI_STATUS Status;
138
139 ASSERT (Xhc->CapLength != 0);
140
141 Status = Xhc->PciIo->Mem.Write (
142 Xhc->PciIo,
143 EfiPciIoWidthUint32,
144 XHC_BAR_INDEX,
145 Xhc->CapLength + Offset,
146 1,
147 &Data
148 );
149
150 if (EFI_ERROR (Status)) {
151 DEBUG ((DEBUG_ERROR, "XhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));
152 }
153 }
154
155 /**
156 Write the data to the XHCI door bell register.
157
158 @param Xhc The XHCI Instance.
159 @param Offset The offset of the door bell register.
160 @param Data The data to write.
161
162 **/
163 VOID
164 XhcWriteDoorBellReg (
165 IN USB_XHCI_INSTANCE *Xhc,
166 IN UINT32 Offset,
167 IN UINT32 Data
168 )
169 {
170 EFI_STATUS Status;
171
172 ASSERT (Xhc->DBOff != 0);
173
174 Status = Xhc->PciIo->Mem.Write (
175 Xhc->PciIo,
176 EfiPciIoWidthUint32,
177 XHC_BAR_INDEX,
178 Xhc->DBOff + Offset,
179 1,
180 &Data
181 );
182
183 if (EFI_ERROR (Status)) {
184 DEBUG ((DEBUG_ERROR, "XhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));
185 }
186 }
187
188 /**
189 Read XHCI runtime register.
190
191 @param Xhc The XHCI Instance.
192 @param Offset The offset of the runtime register.
193
194 @return The register content read
195
196 **/
197 UINT32
198 XhcReadRuntimeReg (
199 IN USB_XHCI_INSTANCE *Xhc,
200 IN UINT32 Offset
201 )
202 {
203 UINT32 Data;
204 EFI_STATUS Status;
205
206 ASSERT (Xhc->RTSOff != 0);
207
208 Status = Xhc->PciIo->Mem.Read (
209 Xhc->PciIo,
210 EfiPciIoWidthUint32,
211 XHC_BAR_INDEX,
212 Xhc->RTSOff + Offset,
213 1,
214 &Data
215 );
216
217 if (EFI_ERROR (Status)) {
218 DEBUG ((DEBUG_ERROR, "XhcReadRuntimeReg: Pci Io Read error - %r at %d\n", Status, Offset));
219 Data = 0xFFFFFFFF;
220 }
221
222 return Data;
223 }
224
225 /**
226 Write the data to the XHCI runtime register.
227
228 @param Xhc The XHCI Instance.
229 @param Offset The offset of the runtime register.
230 @param Data The data to write.
231
232 **/
233 VOID
234 XhcWriteRuntimeReg (
235 IN USB_XHCI_INSTANCE *Xhc,
236 IN UINT32 Offset,
237 IN UINT32 Data
238 )
239 {
240 EFI_STATUS Status;
241
242 ASSERT (Xhc->RTSOff != 0);
243
244 Status = Xhc->PciIo->Mem.Write (
245 Xhc->PciIo,
246 EfiPciIoWidthUint32,
247 XHC_BAR_INDEX,
248 Xhc->RTSOff + Offset,
249 1,
250 &Data
251 );
252
253 if (EFI_ERROR (Status)) {
254 DEBUG ((DEBUG_ERROR, "XhcWriteRuntimeReg: Pci Io Write error: %r at %d\n", Status, Offset));
255 }
256 }
257
258 /**
259 Read XHCI extended capability register.
260
261 @param Xhc The XHCI Instance.
262 @param Offset The offset of the extended capability register.
263
264 @return The register content read
265
266 **/
267 UINT32
268 XhcReadExtCapReg (
269 IN USB_XHCI_INSTANCE *Xhc,
270 IN UINT32 Offset
271 )
272 {
273 UINT32 Data;
274 EFI_STATUS Status;
275
276 ASSERT (Xhc->ExtCapRegBase != 0);
277
278 Status = Xhc->PciIo->Mem.Read (
279 Xhc->PciIo,
280 EfiPciIoWidthUint32,
281 XHC_BAR_INDEX,
282 Xhc->ExtCapRegBase + Offset,
283 1,
284 &Data
285 );
286
287 if (EFI_ERROR (Status)) {
288 DEBUG ((DEBUG_ERROR, "XhcReadExtCapReg: Pci Io Read error - %r at %d\n", Status, Offset));
289 Data = 0xFFFFFFFF;
290 }
291
292 return Data;
293 }
294
295 /**
296 Write the data to the XHCI extended capability register.
297
298 @param Xhc The XHCI Instance.
299 @param Offset The offset of the extended capability register.
300 @param Data The data to write.
301
302 **/
303 VOID
304 XhcWriteExtCapReg (
305 IN USB_XHCI_INSTANCE *Xhc,
306 IN UINT32 Offset,
307 IN UINT32 Data
308 )
309 {
310 EFI_STATUS Status;
311
312 ASSERT (Xhc->ExtCapRegBase != 0);
313
314 Status = Xhc->PciIo->Mem.Write (
315 Xhc->PciIo,
316 EfiPciIoWidthUint32,
317 XHC_BAR_INDEX,
318 Xhc->ExtCapRegBase + Offset,
319 1,
320 &Data
321 );
322
323 if (EFI_ERROR (Status)) {
324 DEBUG ((DEBUG_ERROR, "XhcWriteExtCapReg: Pci Io Write error: %r at %d\n", Status, Offset));
325 }
326 }
327
328 /**
329 Set one bit of the runtime register while keeping other bits.
330
331 @param Xhc The XHCI Instance.
332 @param Offset The offset of the runtime register.
333 @param Bit The bit mask of the register to set.
334
335 **/
336 VOID
337 XhcSetRuntimeRegBit (
338 IN USB_XHCI_INSTANCE *Xhc,
339 IN UINT32 Offset,
340 IN UINT32 Bit
341 )
342 {
343 UINT32 Data;
344
345 Data = XhcReadRuntimeReg (Xhc, Offset);
346 Data |= Bit;
347 XhcWriteRuntimeReg (Xhc, Offset, Data);
348 }
349
350 /**
351 Clear one bit of the runtime register while keeping other bits.
352
353 @param Xhc The XHCI Instance.
354 @param Offset The offset of the runtime register.
355 @param Bit The bit mask of the register to set.
356
357 **/
358 VOID
359 XhcClearRuntimeRegBit (
360 IN USB_XHCI_INSTANCE *Xhc,
361 IN UINT32 Offset,
362 IN UINT32 Bit
363 )
364 {
365 UINT32 Data;
366
367 Data = XhcReadRuntimeReg (Xhc, Offset);
368 Data &= ~Bit;
369 XhcWriteRuntimeReg (Xhc, Offset, Data);
370 }
371
372 /**
373 Set one bit of the operational register while keeping other bits.
374
375 @param Xhc The XHCI Instance.
376 @param Offset The offset of the operational register.
377 @param Bit The bit mask of the register to set.
378
379 **/
380 VOID
381 XhcSetOpRegBit (
382 IN USB_XHCI_INSTANCE *Xhc,
383 IN UINT32 Offset,
384 IN UINT32 Bit
385 )
386 {
387 UINT32 Data;
388
389 Data = XhcReadOpReg (Xhc, Offset);
390 Data |= Bit;
391 XhcWriteOpReg (Xhc, Offset, Data);
392 }
393
394 /**
395 Clear one bit of the operational register while keeping other bits.
396
397 @param Xhc The XHCI Instance.
398 @param Offset The offset of the operational register.
399 @param Bit The bit mask of the register to clear.
400
401 **/
402 VOID
403 XhcClearOpRegBit (
404 IN USB_XHCI_INSTANCE *Xhc,
405 IN UINT32 Offset,
406 IN UINT32 Bit
407 )
408 {
409 UINT32 Data;
410
411 Data = XhcReadOpReg (Xhc, Offset);
412 Data &= ~Bit;
413 XhcWriteOpReg (Xhc, Offset, Data);
414 }
415
416 /**
417 Wait the operation register's bit as specified by Bit
418 to become set (or clear).
419
420 @param Xhc The XHCI Instance.
421 @param Offset The offset of the operation register.
422 @param Bit The bit of the register to wait for.
423 @param WaitToSet Wait the bit to set or clear.
424 @param Timeout The time to wait before abort (in millisecond, ms).
425
426 @retval EFI_SUCCESS The bit successfully changed by host controller.
427 @retval EFI_TIMEOUT The time out occurred.
428 @retval EFI_OUT_OF_RESOURCES Memory for the timer event could not be allocated.
429
430 **/
431 EFI_STATUS
432 XhcWaitOpRegBit (
433 IN USB_XHCI_INSTANCE *Xhc,
434 IN UINT32 Offset,
435 IN UINT32 Bit,
436 IN BOOLEAN WaitToSet,
437 IN UINT32 Timeout
438 )
439 {
440 EFI_STATUS Status;
441 EFI_EVENT TimeoutEvent;
442
443 TimeoutEvent = NULL;
444
445 if (Timeout == 0) {
446 return EFI_TIMEOUT;
447 }
448
449 Status = gBS->CreateEvent (
450 EVT_TIMER,
451 TPL_CALLBACK,
452 NULL,
453 NULL,
454 &TimeoutEvent
455 );
456
457 if (EFI_ERROR (Status)) {
458 goto DONE;
459 }
460
461 Status = gBS->SetTimer (
462 TimeoutEvent,
463 TimerRelative,
464 EFI_TIMER_PERIOD_MILLISECONDS (Timeout)
465 );
466
467 if (EFI_ERROR (Status)) {
468 goto DONE;
469 }
470
471 do {
472 if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {
473 Status = EFI_SUCCESS;
474 goto DONE;
475 }
476
477 gBS->Stall (XHC_1_MICROSECOND);
478 } while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent)));
479
480 Status = EFI_TIMEOUT;
481
482 DONE:
483 if (TimeoutEvent != NULL) {
484 gBS->CloseEvent (TimeoutEvent);
485 }
486
487 return Status;
488 }
489
490 /**
491 Set Bios Ownership
492
493 @param Xhc The XHCI Instance.
494
495 **/
496 VOID
497 XhcSetBiosOwnership (
498 IN USB_XHCI_INSTANCE *Xhc
499 )
500 {
501 UINT32 Buffer;
502
503 if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) {
504 return;
505 }
506
507 DEBUG ((DEBUG_INFO, "XhcSetBiosOwnership: called to set BIOS ownership\n"));
508
509 Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);
510 Buffer = ((Buffer & (~USBLEGSP_OS_SEMAPHORE)) | USBLEGSP_BIOS_SEMAPHORE);
511 XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer);
512 }
513
514 /**
515 Clear Bios Ownership
516
517 @param Xhc The XHCI Instance.
518
519 **/
520 VOID
521 XhcClearBiosOwnership (
522 IN USB_XHCI_INSTANCE *Xhc
523 )
524 {
525 UINT32 Buffer;
526
527 if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) {
528 return;
529 }
530
531 DEBUG ((DEBUG_INFO, "XhcClearBiosOwnership: called to clear BIOS ownership\n"));
532
533 Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);
534 Buffer = ((Buffer & (~USBLEGSP_BIOS_SEMAPHORE)) | USBLEGSP_OS_SEMAPHORE);
535 XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer);
536 }
537
538 /**
539 Calculate the offset of the XHCI capability.
540
541 @param Xhc The XHCI Instance.
542 @param CapId The XHCI Capability ID.
543
544 @return The offset of XHCI legacy support capability register.
545
546 **/
547 UINT32
548 XhcGetCapabilityAddr (
549 IN USB_XHCI_INSTANCE *Xhc,
550 IN UINT8 CapId
551 )
552 {
553 UINT32 ExtCapOffset;
554 UINT8 NextExtCapReg;
555 UINT32 Data;
556
557 ExtCapOffset = 0;
558
559 do {
560 //
561 // Check if the extended capability register's capability id is USB Legacy Support.
562 //
563 Data = XhcReadExtCapReg (Xhc, ExtCapOffset);
564 if ((Data & 0xFF) == CapId) {
565 return ExtCapOffset;
566 }
567
568 //
569 // If not, then traverse all of the ext capability registers till finding out it.
570 //
571 NextExtCapReg = (UINT8)((Data >> 8) & 0xFF);
572 ExtCapOffset += (NextExtCapReg << 2);
573 } while (NextExtCapReg != 0);
574
575 return 0xFFFFFFFF;
576 }
577
578 /**
579 Calculate the offset of the xHCI Supported Protocol Capability.
580
581 @param Xhc The XHCI Instance.
582 @param MajorVersion The USB Major Version in xHCI Support Protocol Capability Field
583
584 @return The offset of xHCI Supported Protocol capability register.
585
586 **/
587 UINT32
588 XhcGetSupportedProtocolCapabilityAddr (
589 IN USB_XHCI_INSTANCE *Xhc,
590 IN UINT8 MajorVersion
591 )
592 {
593 UINT32 ExtCapOffset;
594 UINT8 NextExtCapReg;
595 UINT32 Data;
596 UINT32 NameString;
597 XHC_SUPPORTED_PROTOCOL_DW0 UsbSupportDw0;
598
599 if (Xhc == NULL) {
600 return 0;
601 }
602
603 ExtCapOffset = 0;
604
605 do {
606 //
607 // Check if the extended capability register's capability id is USB Legacy Support.
608 //
609 Data = XhcReadExtCapReg (Xhc, ExtCapOffset);
610 UsbSupportDw0.Dword = Data;
611 if ((Data & 0xFF) == XHC_CAP_USB_SUPPORTED_PROTOCOL) {
612 if (UsbSupportDw0.Data.RevMajor == MajorVersion) {
613 NameString = XhcReadExtCapReg (Xhc, ExtCapOffset + XHC_SUPPORTED_PROTOCOL_NAME_STRING_OFFSET);
614 if (NameString == XHC_SUPPORTED_PROTOCOL_NAME_STRING_VALUE) {
615 //
616 // Ensure Name String field is xHCI supported protocols in xHCI Supported Protocol Capability Offset 04h
617 //
618 return ExtCapOffset;
619 }
620 }
621 }
622
623 //
624 // If not, then traverse all of the ext capability registers till finding out it.
625 //
626 NextExtCapReg = (UINT8)((Data >> 8) & 0xFF);
627 ExtCapOffset += (NextExtCapReg << 2);
628 } while (NextExtCapReg != 0);
629
630 return 0xFFFFFFFF;
631 }
632
633 /**
634 Find PortSpeed value match Protocol Speed ID Value (PSIV).
635
636 @param Xhc The XHCI Instance.
637 @param ExtCapOffset The USB Major Version in xHCI Support Protocol Capability Field
638 @param PortSpeed The Port Speed Field in USB PortSc register
639 @param PortNumber The Port Number (0-indexed)
640
641 @return The Protocol Speed ID (PSI) from xHCI Supported Protocol capability register.
642
643 **/
644 UINT32
645 XhciPsivGetPsid (
646 IN USB_XHCI_INSTANCE *Xhc,
647 IN UINT32 ExtCapOffset,
648 IN UINT8 PortSpeed,
649 IN UINT8 PortNumber
650 )
651 {
652 XHC_SUPPORTED_PROTOCOL_DW2 PortId;
653 XHC_SUPPORTED_PROTOCOL_PROTOCOL_SPEED_ID Reg;
654 UINT32 Count;
655 UINT32 MinPortIndex;
656 UINT32 MaxPortIndex;
657
658 if ((Xhc == NULL) || (ExtCapOffset == 0xFFFFFFFF)) {
659 return 0;
660 }
661
662 //
663 // According to XHCI 1.1 spec November 2017,
664 // Section 7.2 xHCI Supported Protocol Capability
665 // 1. Get the PSIC(Protocol Speed ID Count) value.
666 // 2. The PSID register boundary should be Base address + PSIC * 0x04
667 //
668 PortId.Dword = XhcReadExtCapReg (Xhc, ExtCapOffset + XHC_SUPPORTED_PROTOCOL_DW2_OFFSET);
669
670 //
671 // According to XHCI 1.1 spec November 2017, valid values
672 // for CompPortOffset are 1 to CompPortCount - 1.
673 //
674 // PortNumber is zero-indexed, so subtract 1.
675 //
676 if ((PortId.Data.CompPortOffset == 0) || (PortId.Data.CompPortCount == 0)) {
677 return 0;
678 }
679
680 MinPortIndex = PortId.Data.CompPortOffset - 1;
681 MaxPortIndex = MinPortIndex + PortId.Data.CompPortCount - 1;
682
683 if ((PortNumber < MinPortIndex) || (PortNumber > MaxPortIndex)) {
684 return 0;
685 }
686
687 for (Count = 0; Count < PortId.Data.Psic; Count++) {
688 Reg.Dword = XhcReadExtCapReg (Xhc, ExtCapOffset + XHC_SUPPORTED_PROTOCOL_PSI_OFFSET + (Count << 2));
689 if (Reg.Data.Psiv == PortSpeed) {
690 return Reg.Dword;
691 }
692 }
693
694 return 0;
695 }
696
697 /**
698 Find PortSpeed value match case in XHCI Supported Protocol Capability
699
700 @param Xhc The XHCI Instance.
701 @param PortSpeed The Port Speed Field in USB PortSc register
702 @param PortNumber The Port Number (0-indexed)
703
704 @return The USB Port Speed.
705
706 **/
707 UINT16
708 XhcCheckUsbPortSpeedUsedPsic (
709 IN USB_XHCI_INSTANCE *Xhc,
710 IN UINT8 PortSpeed,
711 IN UINT8 PortNumber
712 )
713 {
714 XHC_SUPPORTED_PROTOCOL_PROTOCOL_SPEED_ID SpField;
715 UINT16 UsbSpeedIdMap;
716
717 if (Xhc == NULL) {
718 return 0;
719 }
720
721 SpField.Dword = 0;
722 UsbSpeedIdMap = 0;
723
724 //
725 // Check xHCI Supported Protocol Capability, find the PSIV field to match
726 // PortSpeed definition when the Major Revision is 03h.
727 //
728 if (Xhc->Usb3SupOffset != 0xFFFFFFFF) {
729 SpField.Dword = XhciPsivGetPsid (Xhc, Xhc->Usb3SupOffset, PortSpeed, PortNumber);
730 if (SpField.Dword != 0) {
731 //
732 // Found the corresponding PORTSC value in PSIV field of USB3 offset.
733 //
734 UsbSpeedIdMap = USB_PORT_STAT_SUPER_SPEED;
735 }
736 }
737
738 //
739 // Check xHCI Supported Protocol Capability, find the PSIV field to match
740 // PortSpeed definition when the Major Revision is 02h.
741 //
742 if ((UsbSpeedIdMap == 0) && (Xhc->Usb2SupOffset != 0xFFFFFFFF)) {
743 SpField.Dword = XhciPsivGetPsid (Xhc, Xhc->Usb2SupOffset, PortSpeed, PortNumber);
744 if (SpField.Dword != 0) {
745 //
746 // Found the corresponding PORTSC value in PSIV field of USB2 offset.
747 //
748 if (SpField.Data.Psie == 2) {
749 //
750 // According to XHCI 1.1 spec November 2017,
751 // Section 7.2.1 the Protocol Speed ID Exponent (PSIE) field definition,
752 // PSIE value shall be applied to Protocol Speed ID Mantissa when calculating, value 2 shall represent bit rate in Mb/s
753 //
754 if (SpField.Data.Psim == XHC_SUPPORTED_PROTOCOL_USB2_HIGH_SPEED_PSIM) {
755 //
756 // PSIM shows as default High-speed protocol, apply to High-speed mapping
757 //
758 UsbSpeedIdMap = USB_PORT_STAT_HIGH_SPEED;
759 }
760 } else if (SpField.Data.Psie == 1) {
761 //
762 // According to XHCI 1.1 spec November 2017,
763 // Section 7.2.1 the Protocol Speed ID Exponent (PSIE) field definition,
764 // PSIE value shall be applied to Protocol Speed ID Mantissa when calculating, value 1 shall represent bit rate in Kb/s
765 //
766 if (SpField.Data.Psim == XHC_SUPPORTED_PROTOCOL_USB2_LOW_SPEED_PSIM) {
767 //
768 // PSIM shows as default Low-speed protocol, apply to Low-speed mapping
769 //
770 UsbSpeedIdMap = USB_PORT_STAT_LOW_SPEED;
771 }
772 }
773 }
774 }
775
776 return UsbSpeedIdMap;
777 }
778
779 /**
780 Whether the XHCI host controller is halted.
781
782 @param Xhc The XHCI Instance.
783
784 @retval TRUE The controller is halted.
785 @retval FALSE It isn't halted.
786
787 **/
788 BOOLEAN
789 XhcIsHalt (
790 IN USB_XHCI_INSTANCE *Xhc
791 )
792 {
793 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT);
794 }
795
796 /**
797 Whether system error occurred.
798
799 @param Xhc The XHCI Instance.
800
801 @retval TRUE System error happened.
802 @retval FALSE No system error.
803
804 **/
805 BOOLEAN
806 XhcIsSysError (
807 IN USB_XHCI_INSTANCE *Xhc
808 )
809 {
810 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);
811 }
812
813 /**
814 Set USBCMD Host System Error Enable(HSEE) Bit if PCICMD SERR# Enable Bit is set.
815
816 The USBCMD HSEE Bit will be reset to default 0 by USBCMD Host Controller Reset(HCRST).
817 This function is to set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.
818
819 @param Xhc The XHCI Instance.
820
821 **/
822 VOID
823 XhcSetHsee (
824 IN USB_XHCI_INSTANCE *Xhc
825 )
826 {
827 EFI_STATUS Status;
828 EFI_PCI_IO_PROTOCOL *PciIo;
829 UINT16 XhciCmd;
830
831 PciIo = Xhc->PciIo;
832 Status = PciIo->Pci.Read (
833 PciIo,
834 EfiPciIoWidthUint16,
835 PCI_COMMAND_OFFSET,
836 sizeof (XhciCmd) / sizeof (UINT16),
837 &XhciCmd
838 );
839 if (!EFI_ERROR (Status)) {
840 if ((XhciCmd & EFI_PCI_COMMAND_SERR) != 0) {
841 XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_HSEE);
842 }
843 }
844 }
845
846 /**
847 Reset the XHCI host controller.
848
849 @param Xhc The XHCI Instance.
850 @param Timeout Time to wait before abort (in millisecond, ms).
851
852 @retval EFI_SUCCESS The XHCI host controller is reset.
853 @return Others Failed to reset the XHCI before Timeout.
854
855 **/
856 EFI_STATUS
857 XhcResetHC (
858 IN USB_XHCI_INSTANCE *Xhc,
859 IN UINT32 Timeout
860 )
861 {
862 EFI_STATUS Status;
863
864 Status = EFI_SUCCESS;
865
866 DEBUG ((DEBUG_INFO, "XhcResetHC!\n"));
867 //
868 // Host can only be reset when it is halt. If not so, halt it
869 //
870 if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {
871 Status = XhcHaltHC (Xhc, Timeout);
872
873 if (EFI_ERROR (Status)) {
874 return Status;
875 }
876 }
877
878 if ((Xhc->DebugCapSupOffset == 0xFFFFFFFF) || ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) != XHC_CAP_USB_DEBUG) ||
879 ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) == 0))
880 {
881 XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);
882 //
883 // Some XHCI host controllers require to have extra 1ms delay before accessing any MMIO register during reset.
884 // Otherwise there may have the timeout case happened.
885 // The below is a workaround to solve such problem.
886 //
887 gBS->Stall (XHC_1_MILLISECOND);
888 Status = XhcWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);
889
890 if (!EFI_ERROR (Status)) {
891 //
892 // The USBCMD HSEE Bit will be reset to default 0 by USBCMD HCRST.
893 // Set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.
894 //
895 XhcSetHsee (Xhc);
896 }
897 }
898
899 return Status;
900 }
901
902 /**
903 Halt the XHCI host controller.
904
905 @param Xhc The XHCI Instance.
906 @param Timeout Time to wait before abort (in millisecond, ms).
907
908 @return EFI_SUCCESS The XHCI host controller is halt.
909 @return EFI_TIMEOUT Failed to halt the XHCI before Timeout.
910
911 **/
912 EFI_STATUS
913 XhcHaltHC (
914 IN USB_XHCI_INSTANCE *Xhc,
915 IN UINT32 Timeout
916 )
917 {
918 EFI_STATUS Status;
919
920 XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
921 Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);
922 return Status;
923 }
924
925 /**
926 Set the XHCI host controller to run.
927
928 @param Xhc The XHCI Instance.
929 @param Timeout Time to wait before abort (in millisecond, ms).
930
931 @return EFI_SUCCESS The XHCI host controller is running.
932 @return EFI_TIMEOUT Failed to set the XHCI to run before Timeout.
933
934 **/
935 EFI_STATUS
936 XhcRunHC (
937 IN USB_XHCI_INSTANCE *Xhc,
938 IN UINT32 Timeout
939 )
940 {
941 EFI_STATUS Status;
942
943 XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
944 Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);
945 return Status;
946 }