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