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
XhcReadCapReg8(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Offset)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 ((EFI_D_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
XhcReadCapReg(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Offset)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 ((EFI_D_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
XhcReadOpReg(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Offset)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 ((EFI_D_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
XhcWriteOpReg(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Offset,IN UINT32 Data)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 ((EFI_D_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
XhcWriteDoorBellReg(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Offset,IN UINT32 Data)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 ((EFI_D_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
XhcReadRuntimeReg(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Offset)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 ((EFI_D_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
XhcWriteRuntimeReg(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Offset,IN UINT32 Data)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 ((EFI_D_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
XhcReadExtCapReg(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Offset)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 ((EFI_D_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
XhcWriteExtCapReg(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Offset,IN UINT32 Data)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 ((EFI_D_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
XhcSetRuntimeRegBit(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Offset,IN UINT32 Bit)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
XhcClearRuntimeRegBit(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Offset,IN UINT32 Bit)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
XhcSetOpRegBit(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Offset,IN UINT32 Bit)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
XhcClearOpRegBit(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Offset,IN UINT32 Bit)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
435 **/
436 EFI_STATUS
XhcWaitOpRegBit(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Offset,IN UINT32 Bit,IN BOOLEAN WaitToSet,IN UINT32 Timeout)437 XhcWaitOpRegBit (
438 IN USB_XHCI_INSTANCE *Xhc,
439 IN UINT32 Offset,
440 IN UINT32 Bit,
441 IN BOOLEAN WaitToSet,
442 IN UINT32 Timeout
443 )
444 {
445 UINT32 Index;
446 UINT64 Loop;
447
448 Loop = Timeout * XHC_1_MILLISECOND;
449
450 for (Index = 0; Index < Loop; Index++) {
451 if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {
452 return EFI_SUCCESS;
453 }
454
455 gBS->Stall (XHC_1_MICROSECOND);
456 }
457
458 return EFI_TIMEOUT;
459 }
460
461 /**
462 Set Bios Ownership
463
464 @param Xhc The XHCI Instance.
465
466 **/
467 VOID
XhcSetBiosOwnership(IN USB_XHCI_INSTANCE * Xhc)468 XhcSetBiosOwnership (
469 IN USB_XHCI_INSTANCE *Xhc
470 )
471 {
472 UINT32 Buffer;
473
474 if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) {
475 return;
476 }
477
478 DEBUG ((EFI_D_INFO, "XhcSetBiosOwnership: called to set BIOS ownership\n"));
479
480 Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);
481 Buffer = ((Buffer & (~USBLEGSP_OS_SEMAPHORE)) | USBLEGSP_BIOS_SEMAPHORE);
482 XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer);
483 }
484
485 /**
486 Clear Bios Ownership
487
488 @param Xhc The XHCI Instance.
489
490 **/
491 VOID
XhcClearBiosOwnership(IN USB_XHCI_INSTANCE * Xhc)492 XhcClearBiosOwnership (
493 IN USB_XHCI_INSTANCE *Xhc
494 )
495 {
496 UINT32 Buffer;
497
498 if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) {
499 return;
500 }
501
502 DEBUG ((EFI_D_INFO, "XhcClearBiosOwnership: called to clear BIOS ownership\n"));
503
504 Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);
505 Buffer = ((Buffer & (~USBLEGSP_BIOS_SEMAPHORE)) | USBLEGSP_OS_SEMAPHORE);
506 XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer);
507 }
508
509 /**
510 Calculate the offset of the XHCI capability.
511
512 @param Xhc The XHCI Instance.
513 @param CapId The XHCI Capability ID.
514
515 @return The offset of XHCI legacy support capability register.
516
517 **/
518 UINT32
XhcGetCapabilityAddr(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 CapId)519 XhcGetCapabilityAddr (
520 IN USB_XHCI_INSTANCE *Xhc,
521 IN UINT8 CapId
522 )
523 {
524 UINT32 ExtCapOffset;
525 UINT8 NextExtCapReg;
526 UINT32 Data;
527
528 ExtCapOffset = 0;
529
530 do {
531 //
532 // Check if the extended capability register's capability id is USB Legacy Support.
533 //
534 Data = XhcReadExtCapReg (Xhc, ExtCapOffset);
535 if ((Data & 0xFF) == CapId) {
536 return ExtCapOffset;
537 }
538 //
539 // If not, then traverse all of the ext capability registers till finding out it.
540 //
541 NextExtCapReg = (UINT8)((Data >> 8) & 0xFF);
542 ExtCapOffset += (NextExtCapReg << 2);
543 } while (NextExtCapReg != 0);
544
545 return 0xFFFFFFFF;
546 }
547
548 /**
549 Whether the XHCI host controller is halted.
550
551 @param Xhc The XHCI Instance.
552
553 @retval TRUE The controller is halted.
554 @retval FALSE It isn't halted.
555
556 **/
557 BOOLEAN
XhcIsHalt(IN USB_XHCI_INSTANCE * Xhc)558 XhcIsHalt (
559 IN USB_XHCI_INSTANCE *Xhc
560 )
561 {
562 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT);
563 }
564
565
566 /**
567 Whether system error occurred.
568
569 @param Xhc The XHCI Instance.
570
571 @retval TRUE System error happened.
572 @retval FALSE No system error.
573
574 **/
575 BOOLEAN
XhcIsSysError(IN USB_XHCI_INSTANCE * Xhc)576 XhcIsSysError (
577 IN USB_XHCI_INSTANCE *Xhc
578 )
579 {
580 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);
581 }
582
583 /**
584 Set USBCMD Host System Error Enable(HSEE) Bit if PCICMD SERR# Enable Bit is set.
585
586 The USBCMD HSEE Bit will be reset to default 0 by USBCMD Host Controller Reset(HCRST).
587 This function is to set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.
588
589 @param Xhc The XHCI Instance.
590
591 **/
592 VOID
XhcSetHsee(IN USB_XHCI_INSTANCE * Xhc)593 XhcSetHsee (
594 IN USB_XHCI_INSTANCE *Xhc
595 )
596 {
597 EFI_STATUS Status;
598 EFI_PCI_IO_PROTOCOL *PciIo;
599 UINT16 XhciCmd;
600
601 PciIo = Xhc->PciIo;
602 Status = PciIo->Pci.Read (
603 PciIo,
604 EfiPciIoWidthUint16,
605 PCI_COMMAND_OFFSET,
606 sizeof (XhciCmd) / sizeof (UINT16),
607 &XhciCmd
608 );
609 if (!EFI_ERROR (Status)) {
610 if ((XhciCmd & EFI_PCI_COMMAND_SERR) != 0) {
611 XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_HSEE);
612 }
613 }
614 }
615
616 /**
617 Reset the XHCI host controller.
618
619 @param Xhc The XHCI Instance.
620 @param Timeout Time to wait before abort (in millisecond, ms).
621
622 @retval EFI_SUCCESS The XHCI host controller is reset.
623 @return Others Failed to reset the XHCI before Timeout.
624
625 **/
626 EFI_STATUS
XhcResetHC(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Timeout)627 XhcResetHC (
628 IN USB_XHCI_INSTANCE *Xhc,
629 IN UINT32 Timeout
630 )
631 {
632 EFI_STATUS Status;
633
634 Status = EFI_SUCCESS;
635
636 DEBUG ((EFI_D_INFO, "XhcResetHC!\n"));
637 //
638 // Host can only be reset when it is halt. If not so, halt it
639 //
640 if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {
641 Status = XhcHaltHC (Xhc, Timeout);
642
643 if (EFI_ERROR (Status)) {
644 return Status;
645 }
646 }
647
648 if ((Xhc->DebugCapSupOffset == 0xFFFFFFFF) || ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) != XHC_CAP_USB_DEBUG) ||
649 ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) == 0)) {
650 XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);
651 //
652 // Some XHCI host controllers require to have extra 1ms delay before accessing any MMIO register during reset.
653 // Otherwise there may have the timeout case happened.
654 // The below is a workaround to solve such problem.
655 //
656 gBS->Stall (XHC_1_MILLISECOND);
657 Status = XhcWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);
658
659 if (!EFI_ERROR (Status)) {
660 //
661 // The USBCMD HSEE Bit will be reset to default 0 by USBCMD HCRST.
662 // Set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.
663 //
664 XhcSetHsee (Xhc);
665 }
666 }
667
668 return Status;
669 }
670
671
672 /**
673 Halt the XHCI host controller.
674
675 @param Xhc The XHCI Instance.
676 @param Timeout Time to wait before abort (in millisecond, ms).
677
678 @return EFI_SUCCESS The XHCI host controller is halt.
679 @return EFI_TIMEOUT Failed to halt the XHCI before Timeout.
680
681 **/
682 EFI_STATUS
XhcHaltHC(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Timeout)683 XhcHaltHC (
684 IN USB_XHCI_INSTANCE *Xhc,
685 IN UINT32 Timeout
686 )
687 {
688 EFI_STATUS Status;
689
690 XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
691 Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);
692 return Status;
693 }
694
695
696 /**
697 Set the XHCI host controller to run.
698
699 @param Xhc The XHCI Instance.
700 @param Timeout Time to wait before abort (in millisecond, ms).
701
702 @return EFI_SUCCESS The XHCI host controller is running.
703 @return EFI_TIMEOUT Failed to set the XHCI to run before Timeout.
704
705 **/
706 EFI_STATUS
XhcRunHC(IN USB_XHCI_INSTANCE * Xhc,IN UINT32 Timeout)707 XhcRunHC (
708 IN USB_XHCI_INSTANCE *Xhc,
709 IN UINT32 Timeout
710 )
711 {
712 EFI_STATUS Status;
713
714 XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
715 Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);
716 return Status;
717 }
718
719