]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c
MdeModulePkg: Change use of EFI_D_* to DEBUG_*
[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
157
158
159 /**
160 Write the data to the XHCI door bell register.
161
162 @param Xhc The XHCI Instance.
163 @param Offset The offset of the door bell register.
164 @param Data The data to write.
165
166 **/
167 VOID
168 XhcWriteDoorBellReg (
169 IN USB_XHCI_INSTANCE *Xhc,
170 IN UINT32 Offset,
171 IN UINT32 Data
172 )
173 {
174 EFI_STATUS Status;
175
176 ASSERT (Xhc->DBOff != 0);
177
178 Status = Xhc->PciIo->Mem.Write (
179 Xhc->PciIo,
180 EfiPciIoWidthUint32,
181 XHC_BAR_INDEX,
182 Xhc->DBOff + Offset,
183 1,
184 &Data
185 );
186
187 if (EFI_ERROR (Status)) {
188 DEBUG ((DEBUG_ERROR, "XhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));
189 }
190 }
191
192 /**
193 Read XHCI runtime register.
194
195 @param Xhc The XHCI Instance.
196 @param Offset The offset of the runtime register.
197
198 @return The register content read
199
200 **/
201 UINT32
202 XhcReadRuntimeReg (
203 IN USB_XHCI_INSTANCE *Xhc,
204 IN UINT32 Offset
205 )
206 {
207 UINT32 Data;
208 EFI_STATUS Status;
209
210 ASSERT (Xhc->RTSOff != 0);
211
212 Status = Xhc->PciIo->Mem.Read (
213 Xhc->PciIo,
214 EfiPciIoWidthUint32,
215 XHC_BAR_INDEX,
216 Xhc->RTSOff + Offset,
217 1,
218 &Data
219 );
220
221 if (EFI_ERROR (Status)) {
222 DEBUG ((DEBUG_ERROR, "XhcReadRuntimeReg: Pci Io Read error - %r at %d\n", Status, Offset));
223 Data = 0xFFFFFFFF;
224 }
225
226 return Data;
227 }
228
229 /**
230 Write the data to the XHCI runtime register.
231
232 @param Xhc The XHCI Instance.
233 @param Offset The offset of the runtime register.
234 @param Data The data to write.
235
236 **/
237 VOID
238 XhcWriteRuntimeReg (
239 IN USB_XHCI_INSTANCE *Xhc,
240 IN UINT32 Offset,
241 IN UINT32 Data
242 )
243 {
244 EFI_STATUS Status;
245
246 ASSERT (Xhc->RTSOff != 0);
247
248 Status = Xhc->PciIo->Mem.Write (
249 Xhc->PciIo,
250 EfiPciIoWidthUint32,
251 XHC_BAR_INDEX,
252 Xhc->RTSOff + Offset,
253 1,
254 &Data
255 );
256
257 if (EFI_ERROR (Status)) {
258 DEBUG ((DEBUG_ERROR, "XhcWriteRuntimeReg: Pci Io Write error: %r at %d\n", Status, Offset));
259 }
260 }
261
262 /**
263 Read XHCI extended capability register.
264
265 @param Xhc The XHCI Instance.
266 @param Offset The offset of the extended capability register.
267
268 @return The register content read
269
270 **/
271 UINT32
272 XhcReadExtCapReg (
273 IN USB_XHCI_INSTANCE *Xhc,
274 IN UINT32 Offset
275 )
276 {
277 UINT32 Data;
278 EFI_STATUS Status;
279
280 ASSERT (Xhc->ExtCapRegBase != 0);
281
282 Status = Xhc->PciIo->Mem.Read (
283 Xhc->PciIo,
284 EfiPciIoWidthUint32,
285 XHC_BAR_INDEX,
286 Xhc->ExtCapRegBase + Offset,
287 1,
288 &Data
289 );
290
291 if (EFI_ERROR (Status)) {
292 DEBUG ((DEBUG_ERROR, "XhcReadExtCapReg: Pci Io Read error - %r at %d\n", Status, Offset));
293 Data = 0xFFFFFFFF;
294 }
295
296 return Data;
297 }
298
299 /**
300 Write the data to the XHCI extended capability register.
301
302 @param Xhc The XHCI Instance.
303 @param Offset The offset of the extended capability register.
304 @param Data The data to write.
305
306 **/
307 VOID
308 XhcWriteExtCapReg (
309 IN USB_XHCI_INSTANCE *Xhc,
310 IN UINT32 Offset,
311 IN UINT32 Data
312 )
313 {
314 EFI_STATUS Status;
315
316 ASSERT (Xhc->ExtCapRegBase != 0);
317
318 Status = Xhc->PciIo->Mem.Write (
319 Xhc->PciIo,
320 EfiPciIoWidthUint32,
321 XHC_BAR_INDEX,
322 Xhc->ExtCapRegBase + Offset,
323 1,
324 &Data
325 );
326
327 if (EFI_ERROR (Status)) {
328 DEBUG ((DEBUG_ERROR, "XhcWriteExtCapReg: Pci Io Write error: %r at %d\n", Status, Offset));
329 }
330 }
331
332
333 /**
334 Set one bit of the runtime register while keeping other bits.
335
336 @param Xhc The XHCI Instance.
337 @param Offset The offset of the runtime register.
338 @param Bit The bit mask of the register to set.
339
340 **/
341 VOID
342 XhcSetRuntimeRegBit (
343 IN USB_XHCI_INSTANCE *Xhc,
344 IN UINT32 Offset,
345 IN UINT32 Bit
346 )
347 {
348 UINT32 Data;
349
350 Data = XhcReadRuntimeReg (Xhc, Offset);
351 Data |= Bit;
352 XhcWriteRuntimeReg (Xhc, Offset, Data);
353 }
354
355 /**
356 Clear one bit of the runtime register while keeping other bits.
357
358 @param Xhc The XHCI Instance.
359 @param Offset The offset of the runtime register.
360 @param Bit The bit mask of the register to set.
361
362 **/
363 VOID
364 XhcClearRuntimeRegBit (
365 IN USB_XHCI_INSTANCE *Xhc,
366 IN UINT32 Offset,
367 IN UINT32 Bit
368 )
369 {
370 UINT32 Data;
371
372 Data = XhcReadRuntimeReg (Xhc, Offset);
373 Data &= ~Bit;
374 XhcWriteRuntimeReg (Xhc, Offset, Data);
375 }
376
377 /**
378 Set one bit of the operational register while keeping other bits.
379
380 @param Xhc The XHCI Instance.
381 @param Offset The offset of the operational register.
382 @param Bit The bit mask of the register to set.
383
384 **/
385 VOID
386 XhcSetOpRegBit (
387 IN USB_XHCI_INSTANCE *Xhc,
388 IN UINT32 Offset,
389 IN UINT32 Bit
390 )
391 {
392 UINT32 Data;
393
394 Data = XhcReadOpReg (Xhc, Offset);
395 Data |= Bit;
396 XhcWriteOpReg (Xhc, Offset, Data);
397 }
398
399
400 /**
401 Clear one bit of the operational register while keeping other bits.
402
403 @param Xhc The XHCI Instance.
404 @param Offset The offset of the operational register.
405 @param Bit The bit mask of the register to clear.
406
407 **/
408 VOID
409 XhcClearOpRegBit (
410 IN USB_XHCI_INSTANCE *Xhc,
411 IN UINT32 Offset,
412 IN UINT32 Bit
413 )
414 {
415 UINT32 Data;
416
417 Data = XhcReadOpReg (Xhc, Offset);
418 Data &= ~Bit;
419 XhcWriteOpReg (Xhc, Offset, Data);
420 }
421
422 /**
423 Wait the operation register's bit as specified by Bit
424 to become set (or clear).
425
426 @param Xhc The XHCI Instance.
427 @param Offset The offset of the operation register.
428 @param Bit The bit of the register to wait for.
429 @param WaitToSet Wait the bit to set or clear.
430 @param Timeout The time to wait before abort (in millisecond, ms).
431
432 @retval EFI_SUCCESS The bit successfully changed by host controller.
433 @retval EFI_TIMEOUT The time out occurred.
434 @retval EFI_OUT_OF_RESOURCES Memory for the timer event could not be allocated.
435
436 **/
437 EFI_STATUS
438 XhcWaitOpRegBit (
439 IN USB_XHCI_INSTANCE *Xhc,
440 IN UINT32 Offset,
441 IN UINT32 Bit,
442 IN BOOLEAN WaitToSet,
443 IN UINT32 Timeout
444 )
445 {
446 EFI_STATUS Status;
447 EFI_EVENT TimeoutEvent;
448
449 TimeoutEvent = NULL;
450
451 if (Timeout == 0) {
452 return EFI_TIMEOUT;
453 }
454
455 Status = gBS->CreateEvent (
456 EVT_TIMER,
457 TPL_CALLBACK,
458 NULL,
459 NULL,
460 &TimeoutEvent
461 );
462
463 if (EFI_ERROR(Status)) {
464 goto DONE;
465 }
466
467 Status = gBS->SetTimer (TimeoutEvent,
468 TimerRelative,
469 EFI_TIMER_PERIOD_MILLISECONDS(Timeout));
470
471 if (EFI_ERROR(Status)) {
472 goto DONE;
473 }
474
475 do {
476 if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {
477 Status = EFI_SUCCESS;
478 goto DONE;
479 }
480
481 gBS->Stall (XHC_1_MICROSECOND);
482 } while (EFI_ERROR(gBS->CheckEvent (TimeoutEvent)));
483
484 Status = EFI_TIMEOUT;
485
486 DONE:
487 if (TimeoutEvent != NULL) {
488 gBS->CloseEvent (TimeoutEvent);
489 }
490
491 return Status;
492 }
493
494 /**
495 Set Bios Ownership
496
497 @param Xhc The XHCI Instance.
498
499 **/
500 VOID
501 XhcSetBiosOwnership (
502 IN USB_XHCI_INSTANCE *Xhc
503 )
504 {
505 UINT32 Buffer;
506
507 if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) {
508 return;
509 }
510
511 DEBUG ((DEBUG_INFO, "XhcSetBiosOwnership: called to set BIOS ownership\n"));
512
513 Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);
514 Buffer = ((Buffer & (~USBLEGSP_OS_SEMAPHORE)) | USBLEGSP_BIOS_SEMAPHORE);
515 XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer);
516 }
517
518 /**
519 Clear Bios Ownership
520
521 @param Xhc The XHCI Instance.
522
523 **/
524 VOID
525 XhcClearBiosOwnership (
526 IN USB_XHCI_INSTANCE *Xhc
527 )
528 {
529 UINT32 Buffer;
530
531 if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) {
532 return;
533 }
534
535 DEBUG ((DEBUG_INFO, "XhcClearBiosOwnership: called to clear BIOS ownership\n"));
536
537 Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);
538 Buffer = ((Buffer & (~USBLEGSP_BIOS_SEMAPHORE)) | USBLEGSP_OS_SEMAPHORE);
539 XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer);
540 }
541
542 /**
543 Calculate the offset of the XHCI capability.
544
545 @param Xhc The XHCI Instance.
546 @param CapId The XHCI Capability ID.
547
548 @return The offset of XHCI legacy support capability register.
549
550 **/
551 UINT32
552 XhcGetCapabilityAddr (
553 IN USB_XHCI_INSTANCE *Xhc,
554 IN UINT8 CapId
555 )
556 {
557 UINT32 ExtCapOffset;
558 UINT8 NextExtCapReg;
559 UINT32 Data;
560
561 ExtCapOffset = 0;
562
563 do {
564 //
565 // Check if the extended capability register's capability id is USB Legacy Support.
566 //
567 Data = XhcReadExtCapReg (Xhc, ExtCapOffset);
568 if ((Data & 0xFF) == CapId) {
569 return ExtCapOffset;
570 }
571 //
572 // If not, then traverse all of the ext capability registers till finding out it.
573 //
574 NextExtCapReg = (UINT8)((Data >> 8) & 0xFF);
575 ExtCapOffset += (NextExtCapReg << 2);
576 } while (NextExtCapReg != 0);
577
578 return 0xFFFFFFFF;
579 }
580
581 /**
582 Whether the XHCI host controller is halted.
583
584 @param Xhc The XHCI Instance.
585
586 @retval TRUE The controller is halted.
587 @retval FALSE It isn't halted.
588
589 **/
590 BOOLEAN
591 XhcIsHalt (
592 IN USB_XHCI_INSTANCE *Xhc
593 )
594 {
595 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT);
596 }
597
598
599 /**
600 Whether system error occurred.
601
602 @param Xhc The XHCI Instance.
603
604 @retval TRUE System error happened.
605 @retval FALSE No system error.
606
607 **/
608 BOOLEAN
609 XhcIsSysError (
610 IN USB_XHCI_INSTANCE *Xhc
611 )
612 {
613 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);
614 }
615
616 /**
617 Set USBCMD Host System Error Enable(HSEE) Bit if PCICMD SERR# Enable Bit is set.
618
619 The USBCMD HSEE Bit will be reset to default 0 by USBCMD Host Controller Reset(HCRST).
620 This function is to set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.
621
622 @param Xhc The XHCI Instance.
623
624 **/
625 VOID
626 XhcSetHsee (
627 IN USB_XHCI_INSTANCE *Xhc
628 )
629 {
630 EFI_STATUS Status;
631 EFI_PCI_IO_PROTOCOL *PciIo;
632 UINT16 XhciCmd;
633
634 PciIo = Xhc->PciIo;
635 Status = PciIo->Pci.Read (
636 PciIo,
637 EfiPciIoWidthUint16,
638 PCI_COMMAND_OFFSET,
639 sizeof (XhciCmd) / sizeof (UINT16),
640 &XhciCmd
641 );
642 if (!EFI_ERROR (Status)) {
643 if ((XhciCmd & EFI_PCI_COMMAND_SERR) != 0) {
644 XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_HSEE);
645 }
646 }
647 }
648
649 /**
650 Reset the XHCI host controller.
651
652 @param Xhc The XHCI Instance.
653 @param Timeout Time to wait before abort (in millisecond, ms).
654
655 @retval EFI_SUCCESS The XHCI host controller is reset.
656 @return Others Failed to reset the XHCI before Timeout.
657
658 **/
659 EFI_STATUS
660 XhcResetHC (
661 IN USB_XHCI_INSTANCE *Xhc,
662 IN UINT32 Timeout
663 )
664 {
665 EFI_STATUS Status;
666
667 Status = EFI_SUCCESS;
668
669 DEBUG ((DEBUG_INFO, "XhcResetHC!\n"));
670 //
671 // Host can only be reset when it is halt. If not so, halt it
672 //
673 if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {
674 Status = XhcHaltHC (Xhc, Timeout);
675
676 if (EFI_ERROR (Status)) {
677 return Status;
678 }
679 }
680
681 if ((Xhc->DebugCapSupOffset == 0xFFFFFFFF) || ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) != XHC_CAP_USB_DEBUG) ||
682 ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) == 0)) {
683 XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);
684 //
685 // Some XHCI host controllers require to have extra 1ms delay before accessing any MMIO register during reset.
686 // Otherwise there may have the timeout case happened.
687 // The below is a workaround to solve such problem.
688 //
689 gBS->Stall (XHC_1_MILLISECOND);
690 Status = XhcWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);
691
692 if (!EFI_ERROR (Status)) {
693 //
694 // The USBCMD HSEE Bit will be reset to default 0 by USBCMD HCRST.
695 // Set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.
696 //
697 XhcSetHsee (Xhc);
698 }
699 }
700
701 return Status;
702 }
703
704
705 /**
706 Halt the XHCI host controller.
707
708 @param Xhc The XHCI Instance.
709 @param Timeout Time to wait before abort (in millisecond, ms).
710
711 @return EFI_SUCCESS The XHCI host controller is halt.
712 @return EFI_TIMEOUT Failed to halt the XHCI before Timeout.
713
714 **/
715 EFI_STATUS
716 XhcHaltHC (
717 IN USB_XHCI_INSTANCE *Xhc,
718 IN UINT32 Timeout
719 )
720 {
721 EFI_STATUS Status;
722
723 XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
724 Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);
725 return Status;
726 }
727
728
729 /**
730 Set the XHCI host controller to run.
731
732 @param Xhc The XHCI Instance.
733 @param Timeout Time to wait before abort (in millisecond, ms).
734
735 @return EFI_SUCCESS The XHCI host controller is running.
736 @return EFI_TIMEOUT Failed to set the XHCI to run before Timeout.
737
738 **/
739 EFI_STATUS
740 XhcRunHC (
741 IN USB_XHCI_INSTANCE *Xhc,
742 IN UINT32 Timeout
743 )
744 {
745 EFI_STATUS Status;
746
747 XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
748 Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);
749 return Status;
750 }