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