]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c
89f073e1d83f89037d7f4b35cae4a77eed48ca39
[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 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "Xhci.h"
17
18 /**
19 Read 1-byte width XHCI capability register.
20
21 @param Xhc The XHCI Instance.
22 @param Offset The offset of the 1-byte width capability register.
23
24 @return The register content read.
25 @retval If err, return 0xFF.
26
27 **/
28 UINT8
29 XhcReadCapReg8 (
30 IN USB_XHCI_INSTANCE *Xhc,
31 IN UINT32 Offset
32 )
33 {
34 UINT8 Data;
35 EFI_STATUS Status;
36
37 Status = Xhc->PciIo->Mem.Read (
38 Xhc->PciIo,
39 EfiPciIoWidthUint8,
40 XHC_BAR_INDEX,
41 (UINT64) Offset,
42 1,
43 &Data
44 );
45
46 if (EFI_ERROR (Status)) {
47 DEBUG ((EFI_D_ERROR, "XhcReadCapReg: Pci Io read error - %r at %d\n", Status, Offset));
48 Data = 0xFF;
49 }
50
51 return Data;
52 }
53
54 /**
55 Read 4-bytes width XHCI capability register.
56
57 @param Xhc The XHCI Instance.
58 @param Offset The offset of the 4-bytes width capability register.
59
60 @return The register content read.
61 @retval If err, return 0xFFFFFFFF.
62
63 **/
64 UINT32
65 XhcReadCapReg (
66 IN USB_XHCI_INSTANCE *Xhc,
67 IN UINT32 Offset
68 )
69 {
70 UINT32 Data;
71 EFI_STATUS Status;
72
73 Status = Xhc->PciIo->Mem.Read (
74 Xhc->PciIo,
75 EfiPciIoWidthUint32,
76 XHC_BAR_INDEX,
77 (UINT64) Offset,
78 1,
79 &Data
80 );
81
82 if (EFI_ERROR (Status)) {
83 DEBUG ((EFI_D_ERROR, "XhcReadCapReg: Pci Io read error - %r at %d\n", Status, Offset));
84 Data = 0xFFFFFFFF;
85 }
86
87 return Data;
88 }
89
90 /**
91 Read 4-bytes width XHCI Operational register.
92
93 @param Xhc The XHCI Instance.
94 @param Offset The offset of the 4-bytes width operational register.
95
96 @return The register content read.
97 @retval If err, return 0xFFFFFFFF.
98
99 **/
100 UINT32
101 XhcReadOpReg (
102 IN USB_XHCI_INSTANCE *Xhc,
103 IN UINT32 Offset
104 )
105 {
106 UINT32 Data;
107 EFI_STATUS Status;
108
109 ASSERT (Xhc->CapLength != 0);
110
111 Status = Xhc->PciIo->Mem.Read (
112 Xhc->PciIo,
113 EfiPciIoWidthUint32,
114 XHC_BAR_INDEX,
115 Xhc->CapLength + Offset,
116 1,
117 &Data
118 );
119
120 if (EFI_ERROR (Status)) {
121 DEBUG ((EFI_D_ERROR, "XhcReadOpReg: Pci Io Read error - %r at %d\n", Status, Offset));
122 Data = 0xFFFFFFFF;
123 }
124
125 return Data;
126 }
127
128 /**
129 Write the data to the 4-bytes width XHCI operational register.
130
131 @param Xhc The XHCI Instance.
132 @param Offset The offset of the 4-bytes width operational register.
133 @param Data The data to write.
134
135 **/
136 VOID
137 XhcWriteOpReg (
138 IN USB_XHCI_INSTANCE *Xhc,
139 IN UINT32 Offset,
140 IN UINT32 Data
141 )
142 {
143 EFI_STATUS Status;
144
145 ASSERT (Xhc->CapLength != 0);
146
147 Status = Xhc->PciIo->Mem.Write (
148 Xhc->PciIo,
149 EfiPciIoWidthUint32,
150 XHC_BAR_INDEX,
151 Xhc->CapLength + Offset,
152 1,
153 &Data
154 );
155
156 if (EFI_ERROR (Status)) {
157 DEBUG ((EFI_D_ERROR, "XhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));
158 }
159 }
160
161
162
163
164
165 /**
166 Write the data to the XHCI door bell register.
167
168 @param Xhc The XHCI Instance.
169 @param Offset The offset of the door bell register.
170 @param Data The data to write.
171
172 **/
173 VOID
174 XhcWriteDoorBellReg (
175 IN USB_XHCI_INSTANCE *Xhc,
176 IN UINT32 Offset,
177 IN UINT32 Data
178 )
179 {
180 EFI_STATUS Status;
181
182 ASSERT (Xhc->DBOff != 0);
183
184 Status = Xhc->PciIo->Mem.Write (
185 Xhc->PciIo,
186 EfiPciIoWidthUint32,
187 XHC_BAR_INDEX,
188 Xhc->DBOff + Offset,
189 1,
190 &Data
191 );
192
193 if (EFI_ERROR (Status)) {
194 DEBUG ((EFI_D_ERROR, "XhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));
195 }
196 }
197
198 /**
199 Read XHCI runtime register.
200
201 @param Xhc The XHCI Instance.
202 @param Offset The offset of the runtime register.
203
204 @return The register content read
205
206 **/
207 UINT32
208 XhcReadRuntimeReg (
209 IN USB_XHCI_INSTANCE *Xhc,
210 IN UINT32 Offset
211 )
212 {
213 UINT32 Data;
214 EFI_STATUS Status;
215
216 ASSERT (Xhc->RTSOff != 0);
217
218 Status = Xhc->PciIo->Mem.Read (
219 Xhc->PciIo,
220 EfiPciIoWidthUint32,
221 XHC_BAR_INDEX,
222 Xhc->RTSOff + Offset,
223 1,
224 &Data
225 );
226
227 if (EFI_ERROR (Status)) {
228 DEBUG ((EFI_D_ERROR, "XhcReadRuntimeReg: Pci Io Read error - %r at %d\n", Status, Offset));
229 Data = 0xFFFFFFFF;
230 }
231
232 return Data;
233 }
234
235 /**
236 Write the data to the XHCI runtime register.
237
238 @param Xhc The XHCI Instance.
239 @param Offset The offset of the runtime register.
240 @param Data The data to write.
241
242 **/
243 VOID
244 XhcWriteRuntimeReg (
245 IN USB_XHCI_INSTANCE *Xhc,
246 IN UINT32 Offset,
247 IN UINT32 Data
248 )
249 {
250 EFI_STATUS Status;
251
252 ASSERT (Xhc->RTSOff != 0);
253
254 Status = Xhc->PciIo->Mem.Write (
255 Xhc->PciIo,
256 EfiPciIoWidthUint32,
257 XHC_BAR_INDEX,
258 Xhc->RTSOff + Offset,
259 1,
260 &Data
261 );
262
263 if (EFI_ERROR (Status)) {
264 DEBUG ((EFI_D_ERROR, "XhcWriteRuntimeReg: Pci Io Write error: %r at %d\n", Status, Offset));
265 }
266 }
267
268 /**
269 Read XHCI extended capability register.
270
271 @param Xhc The XHCI Instance.
272 @param Offset The offset of the extended capability register.
273
274 @return The register content read
275
276 **/
277 UINT32
278 XhcReadExtCapReg (
279 IN USB_XHCI_INSTANCE *Xhc,
280 IN UINT32 Offset
281 )
282 {
283 UINT32 Data;
284 EFI_STATUS Status;
285
286 ASSERT (Xhc->ExtCapRegBase != 0);
287
288 Status = Xhc->PciIo->Mem.Read (
289 Xhc->PciIo,
290 EfiPciIoWidthUint32,
291 XHC_BAR_INDEX,
292 Xhc->ExtCapRegBase + Offset,
293 1,
294 &Data
295 );
296
297 if (EFI_ERROR (Status)) {
298 DEBUG ((EFI_D_ERROR, "XhcReadExtCapReg: Pci Io Read error - %r at %d\n", Status, Offset));
299 Data = 0xFFFFFFFF;
300 }
301
302 return Data;
303 }
304
305 /**
306 Write the data to the XHCI extended capability register.
307
308 @param Xhc The XHCI Instance.
309 @param Offset The offset of the extended capability register.
310 @param Data The data to write.
311
312 **/
313 VOID
314 XhcWriteExtCapReg (
315 IN USB_XHCI_INSTANCE *Xhc,
316 IN UINT32 Offset,
317 IN UINT32 Data
318 )
319 {
320 EFI_STATUS Status;
321
322 ASSERT (Xhc->ExtCapRegBase != 0);
323
324 Status = Xhc->PciIo->Mem.Write (
325 Xhc->PciIo,
326 EfiPciIoWidthUint32,
327 XHC_BAR_INDEX,
328 Xhc->ExtCapRegBase + Offset,
329 1,
330 &Data
331 );
332
333 if (EFI_ERROR (Status)) {
334 DEBUG ((EFI_D_ERROR, "XhcWriteExtCapReg: Pci Io Write error: %r at %d\n", Status, Offset));
335 }
336 }
337
338
339 /**
340 Set one bit of the runtime register while keeping other bits.
341
342 @param Xhc The XHCI Instance.
343 @param Offset The offset of the runtime register.
344 @param Bit The bit mask of the register to set.
345
346 **/
347 VOID
348 XhcSetRuntimeRegBit (
349 IN USB_XHCI_INSTANCE *Xhc,
350 IN UINT32 Offset,
351 IN UINT32 Bit
352 )
353 {
354 UINT32 Data;
355
356 Data = XhcReadRuntimeReg (Xhc, Offset);
357 Data |= Bit;
358 XhcWriteRuntimeReg (Xhc, Offset, Data);
359 }
360
361 /**
362 Clear one bit of the runtime register while keeping other bits.
363
364 @param Xhc The XHCI Instance.
365 @param Offset The offset of the runtime register.
366 @param Bit The bit mask of the register to set.
367
368 **/
369 VOID
370 XhcClearRuntimeRegBit (
371 IN USB_XHCI_INSTANCE *Xhc,
372 IN UINT32 Offset,
373 IN UINT32 Bit
374 )
375 {
376 UINT32 Data;
377
378 Data = XhcReadRuntimeReg (Xhc, Offset);
379 Data &= ~Bit;
380 XhcWriteRuntimeReg (Xhc, Offset, Data);
381 }
382
383 /**
384 Set one bit of the operational register while keeping other bits.
385
386 @param Xhc The XHCI Instance.
387 @param Offset The offset of the operational register.
388 @param Bit The bit mask of the register to set.
389
390 **/
391 VOID
392 XhcSetOpRegBit (
393 IN USB_XHCI_INSTANCE *Xhc,
394 IN UINT32 Offset,
395 IN UINT32 Bit
396 )
397 {
398 UINT32 Data;
399
400 Data = XhcReadOpReg (Xhc, Offset);
401 Data |= Bit;
402 XhcWriteOpReg (Xhc, Offset, Data);
403 }
404
405
406 /**
407 Clear one bit of the operational register while keeping other bits.
408
409 @param Xhc The XHCI Instance.
410 @param Offset The offset of the operational register.
411 @param Bit The bit mask of the register to clear.
412
413 **/
414 VOID
415 XhcClearOpRegBit (
416 IN USB_XHCI_INSTANCE *Xhc,
417 IN UINT32 Offset,
418 IN UINT32 Bit
419 )
420 {
421 UINT32 Data;
422
423 Data = XhcReadOpReg (Xhc, Offset);
424 Data &= ~Bit;
425 XhcWriteOpReg (Xhc, Offset, Data);
426 }
427
428 /**
429 Wait the operation register's bit as specified by Bit
430 to become set (or clear).
431
432 @param Xhc The XHCI Instance.
433 @param Offset The offset of the operation register.
434 @param Bit The bit of the register to wait for.
435 @param WaitToSet Wait the bit to set or clear.
436 @param Timeout The time to wait before abort (in millisecond, ms).
437
438 @retval EFI_SUCCESS The bit successfully changed by host controller.
439 @retval EFI_TIMEOUT The time out occurred.
440
441 **/
442 EFI_STATUS
443 XhcWaitOpRegBit (
444 IN USB_XHCI_INSTANCE *Xhc,
445 IN UINT32 Offset,
446 IN UINT32 Bit,
447 IN BOOLEAN WaitToSet,
448 IN UINT32 Timeout
449 )
450 {
451 UINT32 Index;
452 UINT64 Loop;
453
454 Loop = Timeout * XHC_1_MILLISECOND;
455
456 for (Index = 0; Index < Loop; Index++) {
457 if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {
458 return EFI_SUCCESS;
459 }
460
461 gBS->Stall (XHC_1_MICROSECOND);
462 }
463
464 return EFI_TIMEOUT;
465 }
466
467 /**
468 Set Bios Ownership
469
470 @param Xhc The XHCI Instance.
471
472 **/
473 VOID
474 XhcSetBiosOwnership (
475 IN USB_XHCI_INSTANCE *Xhc
476 )
477 {
478 UINT32 Buffer;
479
480 if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) {
481 return;
482 }
483
484 DEBUG ((EFI_D_INFO, "XhcSetBiosOwnership: called to set BIOS ownership\n"));
485
486 Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);
487 Buffer = ((Buffer & (~USBLEGSP_OS_SEMAPHORE)) | USBLEGSP_BIOS_SEMAPHORE);
488 XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer);
489 }
490
491 /**
492 Clear Bios Ownership
493
494 @param Xhc The XHCI Instance.
495
496 **/
497 VOID
498 XhcClearBiosOwnership (
499 IN USB_XHCI_INSTANCE *Xhc
500 )
501 {
502 UINT32 Buffer;
503
504 if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) {
505 return;
506 }
507
508 DEBUG ((EFI_D_INFO, "XhcClearBiosOwnership: called to clear BIOS ownership\n"));
509
510 Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);
511 Buffer = ((Buffer & (~USBLEGSP_BIOS_SEMAPHORE)) | USBLEGSP_OS_SEMAPHORE);
512 XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer);
513 }
514
515 /**
516 Calculate the offset of the XHCI capability.
517
518 @param Xhc The XHCI Instance.
519 @param CapId The XHCI Capability ID.
520
521 @return The offset of XHCI legacy support capability register.
522
523 **/
524 UINT32
525 XhcGetCapabilityAddr (
526 IN USB_XHCI_INSTANCE *Xhc,
527 IN UINT8 CapId
528 )
529 {
530 UINT32 ExtCapOffset;
531 UINT8 NextExtCapReg;
532 UINT32 Data;
533
534 ExtCapOffset = 0;
535
536 do {
537 //
538 // Check if the extended capability register's capability id is USB Legacy Support.
539 //
540 Data = XhcReadExtCapReg (Xhc, ExtCapOffset);
541 if ((Data & 0xFF) == CapId) {
542 return ExtCapOffset;
543 }
544 //
545 // If not, then traverse all of the ext capability registers till finding out it.
546 //
547 NextExtCapReg = (UINT8)((Data >> 8) & 0xFF);
548 ExtCapOffset += (NextExtCapReg << 2);
549 } while (NextExtCapReg != 0);
550
551 return 0xFFFFFFFF;
552 }
553
554 /**
555 Whether the XHCI host controller is halted.
556
557 @param Xhc The XHCI Instance.
558
559 @retval TRUE The controller is halted.
560 @retval FALSE It isn't halted.
561
562 **/
563 BOOLEAN
564 XhcIsHalt (
565 IN USB_XHCI_INSTANCE *Xhc
566 )
567 {
568 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT);
569 }
570
571
572 /**
573 Whether system error occurred.
574
575 @param Xhc The XHCI Instance.
576
577 @retval TRUE System error happened.
578 @retval FALSE No system error.
579
580 **/
581 BOOLEAN
582 XhcIsSysError (
583 IN USB_XHCI_INSTANCE *Xhc
584 )
585 {
586 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);
587 }
588
589 /**
590 Set USBCMD Host System Error Enable(HSEE) Bit if PCICMD SERR# Enable Bit is set.
591
592 The USBCMD HSEE Bit will be reset to default 0 by USBCMD Host Controller Reset(HCRST).
593 This function is to set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.
594
595 @param Xhc The XHCI Instance.
596
597 **/
598 VOID
599 XhcSetHsee (
600 IN USB_XHCI_INSTANCE *Xhc
601 )
602 {
603 EFI_STATUS Status;
604 EFI_PCI_IO_PROTOCOL *PciIo;
605 UINT16 XhciCmd;
606
607 PciIo = Xhc->PciIo;
608 Status = PciIo->Pci.Read (
609 PciIo,
610 EfiPciIoWidthUint16,
611 PCI_COMMAND_OFFSET,
612 sizeof (XhciCmd),
613 &XhciCmd
614 );
615 if (!EFI_ERROR (Status)) {
616 if ((XhciCmd & EFI_PCI_COMMAND_SERR) != 0) {
617 XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_HSEE);
618 }
619 }
620 }
621
622 /**
623 Reset the XHCI host controller.
624
625 @param Xhc The XHCI Instance.
626 @param Timeout Time to wait before abort (in millisecond, ms).
627
628 @retval EFI_SUCCESS The XHCI host controller is reset.
629 @return Others Failed to reset the XHCI before Timeout.
630
631 **/
632 EFI_STATUS
633 XhcResetHC (
634 IN USB_XHCI_INSTANCE *Xhc,
635 IN UINT32 Timeout
636 )
637 {
638 EFI_STATUS Status;
639
640 Status = EFI_SUCCESS;
641
642 DEBUG ((EFI_D_INFO, "XhcResetHC!\n"));
643 //
644 // Host can only be reset when it is halt. If not so, halt it
645 //
646 if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {
647 Status = XhcHaltHC (Xhc, Timeout);
648
649 if (EFI_ERROR (Status)) {
650 return Status;
651 }
652 }
653
654 if ((Xhc->DebugCapSupOffset == 0xFFFFFFFF) || ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) != XHC_CAP_USB_DEBUG) ||
655 ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) == 0)) {
656 XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);
657 //
658 // Some XHCI host controllers require to have extra 1ms delay before accessing any MMIO register during reset.
659 // Otherwise there may have the timeout case happened.
660 // The below is a workaround to solve such problem.
661 //
662 gBS->Stall (XHC_1_MILLISECOND);
663 Status = XhcWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);
664
665 if (!EFI_ERROR (Status)) {
666 //
667 // The USBCMD HSEE Bit will be reset to default 0 by USBCMD HCRST.
668 // Set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.
669 //
670 XhcSetHsee (Xhc);
671 }
672 }
673
674 return Status;
675 }
676
677
678 /**
679 Halt the XHCI host controller.
680
681 @param Xhc The XHCI Instance.
682 @param Timeout Time to wait before abort (in millisecond, ms).
683
684 @return EFI_SUCCESS The XHCI host controller is halt.
685 @return EFI_TIMEOUT Failed to halt the XHCI before Timeout.
686
687 **/
688 EFI_STATUS
689 XhcHaltHC (
690 IN USB_XHCI_INSTANCE *Xhc,
691 IN UINT32 Timeout
692 )
693 {
694 EFI_STATUS Status;
695
696 XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
697 Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);
698 return Status;
699 }
700
701
702 /**
703 Set the XHCI host controller to run.
704
705 @param Xhc The XHCI Instance.
706 @param Timeout Time to wait before abort (in millisecond, ms).
707
708 @return EFI_SUCCESS The XHCI host controller is running.
709 @return EFI_TIMEOUT Failed to set the XHCI to run before Timeout.
710
711 **/
712 EFI_STATUS
713 XhcRunHC (
714 IN USB_XHCI_INSTANCE *Xhc,
715 IN UINT32 Timeout
716 )
717 {
718 EFI_STATUS Status;
719
720 XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
721 Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);
722 return Status;
723 }
724