XhciReg.c 24 KB

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