]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciPei / XhcPeim.c
... / ...
CommitLineData
1/** @file\r
2PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
3which is used to enable recovery function from USB Drivers.\r
4\r
5Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>\r
6\r
7SPDX-License-Identifier: BSD-2-Clause-Patent\r
8\r
9**/\r
10\r
11#include "XhcPeim.h"\r
12\r
13//\r
14// Two arrays used to translate the XHCI port state (change)\r
15// to the UEFI protocol's port state (change).\r
16//\r
17USB_PORT_STATE_MAP mUsbPortStateMap[] = {\r
18 { XHC_PORTSC_CCS, USB_PORT_STAT_CONNECTION },\r
19 { XHC_PORTSC_PED, USB_PORT_STAT_ENABLE },\r
20 { XHC_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT },\r
21 { XHC_PORTSC_PP, USB_PORT_STAT_POWER },\r
22 { XHC_PORTSC_RESET, USB_PORT_STAT_RESET }\r
23};\r
24\r
25USB_PORT_STATE_MAP mUsbPortChangeMap[] = {\r
26 { XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION },\r
27 { XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE },\r
28 { XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT },\r
29 { XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET }\r
30};\r
31\r
32USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {\r
33 { XHC_PORTSC_CSC, EfiUsbPortConnectChange },\r
34 { XHC_PORTSC_PEC, EfiUsbPortEnableChange },\r
35 { XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange },\r
36 { XHC_PORTSC_PRC, EfiUsbPortResetChange }\r
37};\r
38\r
39USB_PORT_STATE_MAP mUsbHubPortStateMap[] = {\r
40 { XHC_HUB_PORTSC_CCS, USB_PORT_STAT_CONNECTION },\r
41 { XHC_HUB_PORTSC_PED, USB_PORT_STAT_ENABLE },\r
42 { XHC_HUB_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT },\r
43 { XHC_HUB_PORTSC_PP, USB_PORT_STAT_POWER },\r
44 { XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET }\r
45};\r
46\r
47USB_PORT_STATE_MAP mUsbHubPortChangeMap[] = {\r
48 { XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION },\r
49 { XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE },\r
50 { XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT },\r
51 { XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET }\r
52};\r
53\r
54USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {\r
55 { XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange },\r
56 { XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange },\r
57 { XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange },\r
58 { XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange },\r
59 { XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange }\r
60};\r
61\r
62/**\r
63 Read XHCI Operation register.\r
64\r
65 @param Xhc The XHCI device.\r
66 @param Offset The operation register offset.\r
67\r
68 @retval the register content read.\r
69\r
70**/\r
71UINT32\r
72XhcPeiReadOpReg (\r
73 IN PEI_XHC_DEV *Xhc,\r
74 IN UINT32 Offset\r
75 )\r
76{\r
77 UINT32 Data;\r
78\r
79 ASSERT (Xhc->CapLength != 0);\r
80\r
81 Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset);\r
82 return Data;\r
83}\r
84\r
85/**\r
86 Write the data to the XHCI operation register.\r
87\r
88 @param Xhc The XHCI device.\r
89 @param Offset The operation register offset.\r
90 @param Data The data to write.\r
91\r
92**/\r
93VOID\r
94XhcPeiWriteOpReg (\r
95 IN PEI_XHC_DEV *Xhc,\r
96 IN UINT32 Offset,\r
97 IN UINT32 Data\r
98 )\r
99{\r
100 ASSERT (Xhc->CapLength != 0);\r
101\r
102 MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset, Data);\r
103}\r
104\r
105/**\r
106 Set one bit of the operational register while keeping other bits.\r
107\r
108 @param Xhc The XHCI device.\r
109 @param Offset The offset of the operational register.\r
110 @param Bit The bit mask of the register to set.\r
111\r
112**/\r
113VOID\r
114XhcPeiSetOpRegBit (\r
115 IN PEI_XHC_DEV *Xhc,\r
116 IN UINT32 Offset,\r
117 IN UINT32 Bit\r
118 )\r
119{\r
120 UINT32 Data;\r
121\r
122 Data = XhcPeiReadOpReg (Xhc, Offset);\r
123 Data |= Bit;\r
124 XhcPeiWriteOpReg (Xhc, Offset, Data);\r
125}\r
126\r
127/**\r
128 Clear one bit of the operational register while keeping other bits.\r
129\r
130 @param Xhc The XHCI device.\r
131 @param Offset The offset of the operational register.\r
132 @param Bit The bit mask of the register to clear.\r
133\r
134**/\r
135VOID\r
136XhcPeiClearOpRegBit (\r
137 IN PEI_XHC_DEV *Xhc,\r
138 IN UINT32 Offset,\r
139 IN UINT32 Bit\r
140 )\r
141{\r
142 UINT32 Data;\r
143\r
144 Data = XhcPeiReadOpReg (Xhc, Offset);\r
145 Data &= ~Bit;\r
146 XhcPeiWriteOpReg (Xhc, Offset, Data);\r
147}\r
148\r
149/**\r
150 Wait the operation register's bit as specified by Bit\r
151 to become set (or clear).\r
152\r
153 @param Xhc The XHCI device.\r
154 @param Offset The offset of the operational register.\r
155 @param Bit The bit mask of the register to wait for.\r
156 @param WaitToSet Wait the bit to set or clear.\r
157 @param Timeout The time to wait before abort (in millisecond, ms).\r
158\r
159 @retval EFI_SUCCESS The bit successfully changed by host controller.\r
160 @retval EFI_TIMEOUT The time out occurred.\r
161\r
162**/\r
163EFI_STATUS\r
164XhcPeiWaitOpRegBit (\r
165 IN PEI_XHC_DEV *Xhc,\r
166 IN UINT32 Offset,\r
167 IN UINT32 Bit,\r
168 IN BOOLEAN WaitToSet,\r
169 IN UINT32 Timeout\r
170 )\r
171{\r
172 UINT64 Index;\r
173\r
174 for (Index = 0; Index < Timeout * XHC_1_MILLISECOND; Index++) {\r
175 if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {\r
176 return EFI_SUCCESS;\r
177 }\r
178\r
179 MicroSecondDelay (XHC_1_MICROSECOND);\r
180 }\r
181\r
182 return EFI_TIMEOUT;\r
183}\r
184\r
185/**\r
186 Read XHCI capability register.\r
187\r
188 @param Xhc The XHCI device.\r
189 @param Offset Capability register address.\r
190\r
191 @retval the register content read.\r
192\r
193**/\r
194UINT32\r
195XhcPeiReadCapRegister (\r
196 IN PEI_XHC_DEV *Xhc,\r
197 IN UINT32 Offset\r
198 )\r
199{\r
200 UINT32 Data;\r
201\r
202 Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Offset);\r
203\r
204 return Data;\r
205}\r
206\r
207/**\r
208 Write the data to the XHCI door bell register.\r
209\r
210 @param Xhc The XHCI device.\r
211 @param Offset The offset of the door bell register.\r
212 @param Data The data to write.\r
213\r
214**/\r
215VOID\r
216XhcPeiWriteDoorBellReg (\r
217 IN PEI_XHC_DEV *Xhc,\r
218 IN UINT32 Offset,\r
219 IN UINT32 Data\r
220 )\r
221{\r
222 ASSERT (Xhc->DBOff != 0);\r
223\r
224 MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->DBOff + Offset, Data);\r
225}\r
226\r
227/**\r
228 Read XHCI runtime register.\r
229\r
230 @param Xhc The XHCI device.\r
231 @param Offset The offset of the runtime register.\r
232\r
233 @return The register content read\r
234\r
235**/\r
236UINT32\r
237XhcPeiReadRuntimeReg (\r
238 IN PEI_XHC_DEV *Xhc,\r
239 IN UINT32 Offset\r
240 )\r
241{\r
242 UINT32 Data;\r
243\r
244 ASSERT (Xhc->RTSOff != 0);\r
245\r
246 Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset);\r
247\r
248 return Data;\r
249}\r
250\r
251/**\r
252 Write the data to the XHCI runtime register.\r
253\r
254 @param Xhc The XHCI device.\r
255 @param Offset The offset of the runtime register.\r
256 @param Data The data to write.\r
257\r
258**/\r
259VOID\r
260XhcPeiWriteRuntimeReg (\r
261 IN PEI_XHC_DEV *Xhc,\r
262 IN UINT32 Offset,\r
263 IN UINT32 Data\r
264 )\r
265{\r
266 ASSERT (Xhc->RTSOff != 0);\r
267\r
268 MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset, Data);\r
269}\r
270\r
271/**\r
272 Set one bit of the runtime register while keeping other bits.\r
273\r
274 @param Xhc The XHCI device.\r
275 @param Offset The offset of the runtime register.\r
276 @param Bit The bit mask of the register to set.\r
277\r
278**/\r
279VOID\r
280XhcPeiSetRuntimeRegBit (\r
281 IN PEI_XHC_DEV *Xhc,\r
282 IN UINT32 Offset,\r
283 IN UINT32 Bit\r
284 )\r
285{\r
286 UINT32 Data;\r
287\r
288 Data = XhcPeiReadRuntimeReg (Xhc, Offset);\r
289 Data |= Bit;\r
290 XhcPeiWriteRuntimeReg (Xhc, Offset, Data);\r
291}\r
292\r
293/**\r
294 Clear one bit of the runtime register while keeping other bits.\r
295\r
296 @param Xhc The XHCI device.\r
297 @param Offset The offset of the runtime register.\r
298 @param Bit The bit mask of the register to set.\r
299\r
300**/\r
301VOID\r
302XhcPeiClearRuntimeRegBit (\r
303 IN PEI_XHC_DEV *Xhc,\r
304 IN UINT32 Offset,\r
305 IN UINT32 Bit\r
306 )\r
307{\r
308 UINT32 Data;\r
309\r
310 Data = XhcPeiReadRuntimeReg (Xhc, Offset);\r
311 Data &= ~Bit;\r
312 XhcPeiWriteRuntimeReg (Xhc, Offset, Data);\r
313}\r
314\r
315/**\r
316 Check whether Xhc is halted.\r
317\r
318 @param Xhc The XHCI device.\r
319\r
320 @retval TRUE The controller is halted.\r
321 @retval FALSE The controller isn't halted.\r
322\r
323**/\r
324BOOLEAN\r
325XhcPeiIsHalt (\r
326 IN PEI_XHC_DEV *Xhc\r
327 )\r
328{\r
329 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT);\r
330}\r
331\r
332/**\r
333 Check whether system error occurred.\r
334\r
335 @param Xhc The XHCI device.\r
336\r
337 @retval TRUE System error happened.\r
338 @retval FALSE No system error.\r
339\r
340**/\r
341BOOLEAN\r
342XhcPeiIsSysError (\r
343 IN PEI_XHC_DEV *Xhc\r
344 )\r
345{\r
346 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);\r
347}\r
348\r
349/**\r
350 Reset the host controller.\r
351\r
352 @param Xhc The XHCI device.\r
353 @param Timeout Time to wait before abort (in millisecond, ms).\r
354\r
355 @retval EFI_TIMEOUT The transfer failed due to time out.\r
356 @retval Others Failed to reset the host.\r
357\r
358**/\r
359EFI_STATUS\r
360XhcPeiResetHC (\r
361 IN PEI_XHC_DEV *Xhc,\r
362 IN UINT32 Timeout\r
363 )\r
364{\r
365 EFI_STATUS Status;\r
366\r
367 //\r
368 // Host can only be reset when it is halt. If not so, halt it\r
369 //\r
370 if (!XhcPeiIsHalt (Xhc)) {\r
371 Status = XhcPeiHaltHC (Xhc, Timeout);\r
372\r
373 if (EFI_ERROR (Status)) {\r
374 goto ON_EXIT;\r
375 }\r
376 }\r
377\r
378 XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);\r
379 //\r
380 // Some XHCI host controllers require to have extra 1ms delay before accessing any MMIO register during reset.\r
381 // Otherwise there may have the timeout case happened.\r
382 // The below is a workaround to solve such problem.\r
383 //\r
384 MicroSecondDelay (1000);\r
385 Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);\r
386ON_EXIT:\r
387 DEBUG ((DEBUG_INFO, "XhcPeiResetHC: %r\n", Status));\r
388 return Status;\r
389}\r
390\r
391/**\r
392 Halt the host controller.\r
393\r
394 @param Xhc The XHCI device.\r
395 @param Timeout Time to wait before abort.\r
396\r
397 @retval EFI_TIMEOUT Failed to halt the controller before Timeout.\r
398 @retval EFI_SUCCESS The XHCI is halt.\r
399\r
400**/\r
401EFI_STATUS\r
402XhcPeiHaltHC (\r
403 IN PEI_XHC_DEV *Xhc,\r
404 IN UINT32 Timeout\r
405 )\r
406{\r
407 EFI_STATUS Status;\r
408\r
409 XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);\r
410 Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);\r
411 DEBUG ((DEBUG_INFO, "XhcPeiHaltHC: %r\n", Status));\r
412 return Status;\r
413}\r
414\r
415/**\r
416 Set the XHCI to run.\r
417\r
418 @param Xhc The XHCI device.\r
419 @param Timeout Time to wait before abort.\r
420\r
421 @retval EFI_SUCCESS The XHCI is running.\r
422 @retval Others Failed to set the XHCI to run.\r
423\r
424**/\r
425EFI_STATUS\r
426XhcPeiRunHC (\r
427 IN PEI_XHC_DEV *Xhc,\r
428 IN UINT32 Timeout\r
429 )\r
430{\r
431 EFI_STATUS Status;\r
432\r
433 XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);\r
434 Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);\r
435 DEBUG ((DEBUG_INFO, "XhcPeiRunHC: %r\n", Status));\r
436 return Status;\r
437}\r
438\r
439/**\r
440 Submits control transfer to a target USB device.\r
441\r
442 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
443 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
444 @param DeviceAddress The target device address.\r
445 @param DeviceSpeed Target device speed.\r
446 @param MaximumPacketLength Maximum packet size the default control transfer\r
447 endpoint is capable of sending or receiving.\r
448 @param Request USB device request to send.\r
449 @param TransferDirection Specifies the data direction for the data stage.\r
450 @param Data Data buffer to be transmitted or received from USB device.\r
451 @param DataLength The size (in bytes) of the data buffer.\r
452 @param TimeOut Indicates the maximum timeout, in millisecond.\r
453 If Timeout is 0, then the caller must wait for the function\r
454 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.\r
455 @param Translator Transaction translator to be used by this device.\r
456 @param TransferResult Return the result of this control transfer.\r
457\r
458 @retval EFI_SUCCESS Transfer was completed successfully.\r
459 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
460 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
461 @retval EFI_TIMEOUT Transfer failed due to timeout.\r
462 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
463\r
464**/\r
465EFI_STATUS\r
466EFIAPI\r
467XhcPeiControlTransfer (\r
468 IN EFI_PEI_SERVICES **PeiServices,\r
469 IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
470 IN UINT8 DeviceAddress,\r
471 IN UINT8 DeviceSpeed,\r
472 IN UINTN MaximumPacketLength,\r
473 IN EFI_USB_DEVICE_REQUEST *Request,\r
474 IN EFI_USB_DATA_DIRECTION TransferDirection,\r
475 IN OUT VOID *Data,\r
476 IN OUT UINTN *DataLength,\r
477 IN UINTN TimeOut,\r
478 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
479 OUT UINT32 *TransferResult\r
480 )\r
481{\r
482 PEI_XHC_DEV *Xhc;\r
483 URB *Urb;\r
484 UINT8 Endpoint;\r
485 UINT8 Index;\r
486 UINT8 DescriptorType;\r
487 UINT8 SlotId;\r
488 UINT8 TTT;\r
489 UINT8 MTT;\r
490 UINT32 MaxPacket0;\r
491 EFI_USB_HUB_DESCRIPTOR *HubDesc;\r
492 EFI_STATUS Status;\r
493 EFI_STATUS RecoveryStatus;\r
494 UINTN MapSize;\r
495 EFI_USB_PORT_STATUS PortStatus;\r
496 UINT32 State;\r
497 EFI_USB_DEVICE_REQUEST ClearPortRequest;\r
498 UINTN Len;\r
499\r
500 //\r
501 // Validate parameters\r
502 //\r
503 if ((Request == NULL) || (TransferResult == NULL)) {\r
504 return EFI_INVALID_PARAMETER;\r
505 }\r
506\r
507 if ((TransferDirection != EfiUsbDataIn) &&\r
508 (TransferDirection != EfiUsbDataOut) &&\r
509 (TransferDirection != EfiUsbNoData))\r
510 {\r
511 return EFI_INVALID_PARAMETER;\r
512 }\r
513\r
514 if ((TransferDirection == EfiUsbNoData) &&\r
515 ((Data != NULL) || (*DataLength != 0)))\r
516 {\r
517 return EFI_INVALID_PARAMETER;\r
518 }\r
519\r
520 if ((TransferDirection != EfiUsbNoData) &&\r
521 ((Data == NULL) || (*DataLength == 0)))\r
522 {\r
523 return EFI_INVALID_PARAMETER;\r
524 }\r
525\r
526 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&\r
527 (MaximumPacketLength != 32) && (MaximumPacketLength != 64) &&\r
528 (MaximumPacketLength != 512)\r
529 )\r
530 {\r
531 return EFI_INVALID_PARAMETER;\r
532 }\r
533\r
534 if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {\r
535 return EFI_INVALID_PARAMETER;\r
536 }\r
537\r
538 if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) {\r
539 return EFI_INVALID_PARAMETER;\r
540 }\r
541\r
542 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
543\r
544 Status = EFI_DEVICE_ERROR;\r
545 *TransferResult = EFI_USB_ERR_SYSTEM;\r
546 Len = 0;\r
547\r
548 if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {\r
549 DEBUG ((DEBUG_ERROR, "XhcPeiControlTransfer: HC is halted or has system error\n"));\r
550 goto ON_EXIT;\r
551 }\r
552\r
553 //\r
554 // Check if the device is still enabled before every transaction.\r
555 //\r
556 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);\r
557 if (SlotId == 0) {\r
558 goto ON_EXIT;\r
559 }\r
560\r
561 //\r
562 // Hook the Set_Address request from UsbBus.\r
563 // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.\r
564 //\r
565 if ((Request->Request == USB_REQ_SET_ADDRESS) &&\r
566 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)))\r
567 {\r
568 //\r
569 // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.\r
570 // This way is used to clean the history to avoid using wrong device address afterwards.\r
571 //\r
572 for (Index = 0; Index < 255; Index++) {\r
573 if (!Xhc->UsbDevContext[Index + 1].Enabled &&\r
574 (Xhc->UsbDevContext[Index + 1].SlotId == 0) &&\r
575 (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8)Request->Value))\r
576 {\r
577 Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;\r
578 }\r
579 }\r
580\r
581 if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {\r
582 goto ON_EXIT;\r
583 }\r
584\r
585 //\r
586 // The actual device address has been assigned by XHCI during initializing the device slot.\r
587 // So we just need establish the mapping relationship between the device address requested from UsbBus\r
588 // and the actual device address assigned by XHCI. The following invocations through EFI_USB2_HC_PROTOCOL interface\r
589 // can find out the actual device address by it.\r
590 //\r
591 Xhc->UsbDevContext[SlotId].BusDevAddr = (UINT8)Request->Value;\r
592 Status = EFI_SUCCESS;\r
593 goto ON_EXIT;\r
594 }\r
595\r
596 //\r
597 // Create a new URB, insert it into the asynchronous\r
598 // schedule list, then poll the execution status.\r
599 // Note that we encode the direction in address although default control\r
600 // endpoint is bidirectional. XhcPeiCreateUrb expects this\r
601 // combination of Ep addr and its direction.\r
602 //\r
603 Endpoint = (UINT8)(0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));\r
604 Urb = XhcPeiCreateUrb (\r
605 Xhc,\r
606 DeviceAddress,\r
607 Endpoint,\r
608 DeviceSpeed,\r
609 MaximumPacketLength,\r
610 XHC_CTRL_TRANSFER,\r
611 Request,\r
612 Data,\r
613 *DataLength,\r
614 NULL,\r
615 NULL\r
616 );\r
617\r
618 if (Urb == NULL) {\r
619 DEBUG ((DEBUG_ERROR, "XhcPeiControlTransfer: failed to create URB"));\r
620 Status = EFI_OUT_OF_RESOURCES;\r
621 goto ON_EXIT;\r
622 }\r
623\r
624 Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);\r
625\r
626 //\r
627 // Get the status from URB. The result is updated in XhcPeiCheckUrbResult\r
628 // which is called by XhcPeiExecTransfer\r
629 //\r
630 *TransferResult = Urb->Result;\r
631 *DataLength = Urb->Completed;\r
632\r
633 if (Status == EFI_TIMEOUT) {\r
634 //\r
635 // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
636 //\r
637 RecoveryStatus = XhcPeiDequeueTrbFromEndpoint (Xhc, Urb);\r
638 if (EFI_ERROR (RecoveryStatus)) {\r
639 DEBUG ((DEBUG_ERROR, "XhcPeiControlTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));\r
640 }\r
641\r
642 XhcPeiFreeUrb (Xhc, Urb);\r
643 goto ON_EXIT;\r
644 } else {\r
645 if (*TransferResult == EFI_USB_NOERROR) {\r
646 Status = EFI_SUCCESS;\r
647 } else if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {\r
648 RecoveryStatus = XhcPeiRecoverHaltedEndpoint (Xhc, Urb);\r
649 if (EFI_ERROR (RecoveryStatus)) {\r
650 DEBUG ((DEBUG_ERROR, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));\r
651 }\r
652\r
653 Status = EFI_DEVICE_ERROR;\r
654 XhcPeiFreeUrb (Xhc, Urb);\r
655 goto ON_EXIT;\r
656 } else {\r
657 XhcPeiFreeUrb (Xhc, Urb);\r
658 goto ON_EXIT;\r
659 }\r
660 }\r
661\r
662 //\r
663 // Unmap data before consume.\r
664 //\r
665 XhcPeiFreeUrb (Xhc, Urb);\r
666\r
667 //\r
668 // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.\r
669 // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.\r
670 // Hook Set_Config request from UsbBus as we need configure device endpoint.\r
671 //\r
672 if ((Request->Request == USB_REQ_GET_DESCRIPTOR) &&\r
673 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||\r
674 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE)))))\r
675 {\r
676 DescriptorType = (UINT8)(Request->Value >> 8);\r
677 if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {\r
678 ASSERT (Data != NULL);\r
679 //\r
680 // Store a copy of device scriptor as hub device need this info to configure endpoint.\r
681 //\r
682 CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);\r
683 if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB >= 0x0300) {\r
684 //\r
685 // If it's a usb3.0 device, then its max packet size is a 2^n.\r
686 //\r
687 MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;\r
688 } else {\r
689 MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;\r
690 }\r
691\r
692 Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));\r
693 if (Xhc->UsbDevContext[SlotId].ConfDesc == NULL) {\r
694 Status = EFI_OUT_OF_RESOURCES;\r
695 goto ON_EXIT;\r
696 }\r
697\r
698 if (Xhc->HcCParams.Data.Csz == 0) {\r
699 Status = XhcPeiEvaluateContext (Xhc, SlotId, MaxPacket0);\r
700 } else {\r
701 Status = XhcPeiEvaluateContext64 (Xhc, SlotId, MaxPacket0);\r
702 }\r
703 } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {\r
704 ASSERT (Data != NULL);\r
705 if (*DataLength == ((UINT16 *)Data)[1]) {\r
706 //\r
707 // Get configuration value from request, store the configuration descriptor for Configure_Endpoint cmd.\r
708 //\r
709 Index = (UINT8)Request->Value;\r
710 ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);\r
711 Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool (*DataLength);\r
712 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] == NULL) {\r
713 Status = EFI_OUT_OF_RESOURCES;\r
714 goto ON_EXIT;\r
715 }\r
716\r
717 CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);\r
718 }\r
719 } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||\r
720 (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2))\r
721 {\r
722 ASSERT (Data != NULL);\r
723 HubDesc = (EFI_USB_HUB_DESCRIPTOR *)Data;\r
724 ASSERT (HubDesc->NumPorts <= 15);\r
725 //\r
726 // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.\r
727 //\r
728 TTT = (UINT8)((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);\r
729 if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {\r
730 //\r
731 // Don't support multi-TT feature for super speed hub now.\r
732 //\r
733 MTT = 0;\r
734 DEBUG ((DEBUG_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));\r
735 } else {\r
736 MTT = 0;\r
737 }\r
738\r
739 if (Xhc->HcCParams.Data.Csz == 0) {\r
740 Status = XhcPeiConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);\r
741 } else {\r
742 Status = XhcPeiConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);\r
743 }\r
744 }\r
745 } else if ((Request->Request == USB_REQ_SET_CONFIG) &&\r
746 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)))\r
747 {\r
748 //\r
749 // Hook Set_Config request from UsbBus as we need configure device endpoint.\r
750 //\r
751 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
752 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {\r
753 if (Xhc->HcCParams.Data.Csz == 0) {\r
754 Status = XhcPeiSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
755 } else {\r
756 Status = XhcPeiSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
757 }\r
758\r
759 break;\r
760 }\r
761 }\r
762 } else if ((Request->Request == USB_REQ_GET_STATUS) &&\r
763 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER)))\r
764 {\r
765 ASSERT (Data != NULL);\r
766 //\r
767 // Hook Get_Status request from UsbBus to keep track of the port status change.\r
768 //\r
769 State = *(UINT32 *)Data;\r
770 PortStatus.PortStatus = 0;\r
771 PortStatus.PortChangeStatus = 0;\r
772\r
773 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
774 //\r
775 // For super speed hub, its bit10~12 presents the attached device speed.\r
776 //\r
777 if ((State & XHC_PORTSC_PS) >> 10 == 0) {\r
778 PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
779 }\r
780 } else {\r
781 //\r
782 // For high or full/low speed hub, its bit9~10 presents the attached device speed.\r
783 //\r
784 if (XHC_BIT_IS_SET (State, BIT9)) {\r
785 PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
786 } else if (XHC_BIT_IS_SET (State, BIT10)) {\r
787 PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
788 }\r
789 }\r
790\r
791 //\r
792 // Convert the XHCI port/port change state to UEFI status\r
793 //\r
794 MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
795 for (Index = 0; Index < MapSize; Index++) {\r
796 if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {\r
797 PortStatus.PortStatus = (UINT16)(PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);\r
798 }\r
799 }\r
800\r
801 MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
802 for (Index = 0; Index < MapSize; Index++) {\r
803 if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {\r
804 PortStatus.PortChangeStatus = (UINT16)(PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);\r
805 }\r
806 }\r
807\r
808 MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);\r
809\r
810 for (Index = 0; Index < MapSize; Index++) {\r
811 if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {\r
812 ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
813 ClearPortRequest.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);\r
814 ClearPortRequest.Request = (UINT8)USB_REQ_CLEAR_FEATURE;\r
815 ClearPortRequest.Value = mUsbHubClearPortChangeMap[Index].Selector;\r
816 ClearPortRequest.Index = Request->Index;\r
817 ClearPortRequest.Length = 0;\r
818\r
819 XhcPeiControlTransfer (\r
820 PeiServices,\r
821 This,\r
822 DeviceAddress,\r
823 DeviceSpeed,\r
824 MaximumPacketLength,\r
825 &ClearPortRequest,\r
826 EfiUsbNoData,\r
827 NULL,\r
828 &Len,\r
829 TimeOut,\r
830 Translator,\r
831 TransferResult\r
832 );\r
833 }\r
834 }\r
835\r
836 XhcPeiPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);\r
837\r
838 *(UINT32 *)Data = *(UINT32 *)&PortStatus;\r
839 }\r
840\r
841ON_EXIT:\r
842\r
843 if (EFI_ERROR (Status)) {\r
844 DEBUG ((DEBUG_ERROR, "XhcPeiControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
845 }\r
846\r
847 return Status;\r
848}\r
849\r
850/**\r
851 Submits bulk transfer to a bulk endpoint of a USB device.\r
852\r
853 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
854 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
855 @param DeviceAddress Target device address.\r
856 @param EndPointAddress Endpoint number and its direction in bit 7.\r
857 @param DeviceSpeed Device speed, Low speed device doesn't support\r
858 bulk transfer.\r
859 @param MaximumPacketLength Maximum packet size the endpoint is capable of\r
860 sending or receiving.\r
861 @param Data Array of pointers to the buffers of data to transmit\r
862 from or receive into.\r
863 @param DataLength The lenght of the data buffer.\r
864 @param DataToggle On input, the initial data toggle for the transfer;\r
865 On output, it is updated to to next data toggle to use of\r
866 the subsequent bulk transfer.\r
867 @param TimeOut Indicates the maximum time, in millisecond, which the\r
868 transfer is allowed to complete.\r
869 If Timeout is 0, then the caller must wait for the function\r
870 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.\r
871 @param Translator A pointr to the transaction translator data.\r
872 @param TransferResult A pointer to the detailed result information of the\r
873 bulk transfer.\r
874\r
875 @retval EFI_SUCCESS The transfer was completed successfully.\r
876 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
877 @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
878 @retval EFI_TIMEOUT The transfer failed due to timeout.\r
879 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
880\r
881**/\r
882EFI_STATUS\r
883EFIAPI\r
884XhcPeiBulkTransfer (\r
885 IN EFI_PEI_SERVICES **PeiServices,\r
886 IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
887 IN UINT8 DeviceAddress,\r
888 IN UINT8 EndPointAddress,\r
889 IN UINT8 DeviceSpeed,\r
890 IN UINTN MaximumPacketLength,\r
891 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
892 IN OUT UINTN *DataLength,\r
893 IN OUT UINT8 *DataToggle,\r
894 IN UINTN TimeOut,\r
895 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
896 OUT UINT32 *TransferResult\r
897 )\r
898{\r
899 PEI_XHC_DEV *Xhc;\r
900 URB *Urb;\r
901 UINT8 SlotId;\r
902 EFI_STATUS Status;\r
903 EFI_STATUS RecoveryStatus;\r
904\r
905 //\r
906 // Validate the parameters\r
907 //\r
908 if ((DataLength == NULL) || (*DataLength == 0) ||\r
909 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL))\r
910 {\r
911 return EFI_INVALID_PARAMETER;\r
912 }\r
913\r
914 if ((*DataToggle != 0) && (*DataToggle != 1)) {\r
915 return EFI_INVALID_PARAMETER;\r
916 }\r
917\r
918 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||\r
919 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
920 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 512)) ||\r
921 ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength > 1024)))\r
922 {\r
923 return EFI_INVALID_PARAMETER;\r
924 }\r
925\r
926 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
927\r
928 *TransferResult = EFI_USB_ERR_SYSTEM;\r
929 Status = EFI_DEVICE_ERROR;\r
930\r
931 if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {\r
932 DEBUG ((DEBUG_ERROR, "XhcPeiBulkTransfer: HC is halted or has system error\n"));\r
933 goto ON_EXIT;\r
934 }\r
935\r
936 //\r
937 // Check if the device is still enabled before every transaction.\r
938 //\r
939 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);\r
940 if (SlotId == 0) {\r
941 goto ON_EXIT;\r
942 }\r
943\r
944 //\r
945 // Create a new URB, insert it into the asynchronous\r
946 // schedule list, then poll the execution status.\r
947 //\r
948 Urb = XhcPeiCreateUrb (\r
949 Xhc,\r
950 DeviceAddress,\r
951 EndPointAddress,\r
952 DeviceSpeed,\r
953 MaximumPacketLength,\r
954 XHC_BULK_TRANSFER,\r
955 NULL,\r
956 Data[0],\r
957 *DataLength,\r
958 NULL,\r
959 NULL\r
960 );\r
961\r
962 if (Urb == NULL) {\r
963 DEBUG ((DEBUG_ERROR, "XhcPeiBulkTransfer: failed to create URB\n"));\r
964 Status = EFI_OUT_OF_RESOURCES;\r
965 goto ON_EXIT;\r
966 }\r
967\r
968 Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);\r
969\r
970 *TransferResult = Urb->Result;\r
971 *DataLength = Urb->Completed;\r
972\r
973 if (Status == EFI_TIMEOUT) {\r
974 //\r
975 // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
976 //\r
977 RecoveryStatus = XhcPeiDequeueTrbFromEndpoint (Xhc, Urb);\r
978 if (EFI_ERROR (RecoveryStatus)) {\r
979 DEBUG ((DEBUG_ERROR, "XhcPeiBulkTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));\r
980 }\r
981 } else {\r
982 if (*TransferResult == EFI_USB_NOERROR) {\r
983 Status = EFI_SUCCESS;\r
984 } else if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {\r
985 RecoveryStatus = XhcPeiRecoverHaltedEndpoint (Xhc, Urb);\r
986 if (EFI_ERROR (RecoveryStatus)) {\r
987 DEBUG ((DEBUG_ERROR, "XhcPeiBulkTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));\r
988 }\r
989\r
990 Status = EFI_DEVICE_ERROR;\r
991 }\r
992 }\r
993\r
994 XhcPeiFreeUrb (Xhc, Urb);\r
995\r
996ON_EXIT:\r
997\r
998 if (EFI_ERROR (Status)) {\r
999 DEBUG ((DEBUG_ERROR, "XhcPeiBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
1000 }\r
1001\r
1002 return Status;\r
1003}\r
1004\r
1005/**\r
1006 Retrieves the number of root hub ports.\r
1007\r
1008 @param[in] PeiServices The pointer to the PEI Services Table.\r
1009 @param[in] This The pointer to this instance of the\r
1010 PEI_USB2_HOST_CONTROLLER_PPI.\r
1011 @param[out] PortNumber The pointer to the number of the root hub ports.\r
1012\r
1013 @retval EFI_SUCCESS The port number was retrieved successfully.\r
1014 @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
1015\r
1016**/\r
1017EFI_STATUS\r
1018EFIAPI\r
1019XhcPeiGetRootHubPortNumber (\r
1020 IN EFI_PEI_SERVICES **PeiServices,\r
1021 IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
1022 OUT UINT8 *PortNumber\r
1023 )\r
1024{\r
1025 PEI_XHC_DEV *XhcDev;\r
1026\r
1027 XhcDev = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
1028\r
1029 if (PortNumber == NULL) {\r
1030 return EFI_INVALID_PARAMETER;\r
1031 }\r
1032\r
1033 *PortNumber = XhcDev->HcSParams1.Data.MaxPorts;\r
1034 DEBUG ((DEBUG_INFO, "XhcPeiGetRootHubPortNumber: PortNumber = %x\n", *PortNumber));\r
1035 return EFI_SUCCESS;\r
1036}\r
1037\r
1038/**\r
1039 Clears a feature for the specified root hub port.\r
1040\r
1041 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
1042 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
1043 @param PortNumber Specifies the root hub port whose feature\r
1044 is requested to be cleared.\r
1045 @param PortFeature Indicates the feature selector associated with the\r
1046 feature clear request.\r
1047\r
1048 @retval EFI_SUCCESS The feature specified by PortFeature was cleared\r
1049 for the USB root hub port specified by PortNumber.\r
1050 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
1051\r
1052**/\r
1053EFI_STATUS\r
1054EFIAPI\r
1055XhcPeiClearRootHubPortFeature (\r
1056 IN EFI_PEI_SERVICES **PeiServices,\r
1057 IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
1058 IN UINT8 PortNumber,\r
1059 IN EFI_USB_PORT_FEATURE PortFeature\r
1060 )\r
1061{\r
1062 PEI_XHC_DEV *Xhc;\r
1063 UINT32 Offset;\r
1064 UINT32 State;\r
1065 EFI_STATUS Status;\r
1066\r
1067 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
1068 Status = EFI_SUCCESS;\r
1069\r
1070 if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {\r
1071 Status = EFI_INVALID_PARAMETER;\r
1072 goto ON_EXIT;\r
1073 }\r
1074\r
1075 Offset = (UINT32)(XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
1076 State = XhcPeiReadOpReg (Xhc, Offset);\r
1077 DEBUG ((DEBUG_INFO, "XhcPeiClearRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));\r
1078\r
1079 //\r
1080 // Mask off the port status change bits, these bits are\r
1081 // write clean bits\r
1082 //\r
1083 State &= ~(BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);\r
1084\r
1085 switch (PortFeature) {\r
1086 case EfiUsbPortEnable:\r
1087 //\r
1088 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.\r
1089 // A port may be disabled by software writing a '1' to this flag.\r
1090 //\r
1091 State |= XHC_PORTSC_PED;\r
1092 State &= ~XHC_PORTSC_RESET;\r
1093 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1094 break;\r
1095\r
1096 case EfiUsbPortSuspend:\r
1097 State |= XHC_PORTSC_LWS;\r
1098 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1099 State &= ~XHC_PORTSC_PLS;\r
1100 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1101 break;\r
1102\r
1103 case EfiUsbPortReset:\r
1104 //\r
1105 // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:\r
1106 // Register bits indicate status when read, a clear bit may be set by\r
1107 // writing a '1'. Writing a '0' to RW1S bits has no effect.\r
1108 //\r
1109 break;\r
1110\r
1111 case EfiUsbPortPower:\r
1112 if (Xhc->HcCParams.Data.Ppc) {\r
1113 //\r
1114 // Port Power Control supported\r
1115 //\r
1116 State &= ~XHC_PORTSC_PP;\r
1117 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1118 }\r
1119\r
1120 break;\r
1121\r
1122 case EfiUsbPortOwner:\r
1123 //\r
1124 // XHCI root hub port don't has the owner bit, ignore the operation\r
1125 //\r
1126 break;\r
1127\r
1128 case EfiUsbPortConnectChange:\r
1129 //\r
1130 // Clear connect status change\r
1131 //\r
1132 State |= XHC_PORTSC_CSC;\r
1133 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1134 break;\r
1135\r
1136 case EfiUsbPortEnableChange:\r
1137 //\r
1138 // Clear enable status change\r
1139 //\r
1140 State |= XHC_PORTSC_PEC;\r
1141 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1142 break;\r
1143\r
1144 case EfiUsbPortOverCurrentChange:\r
1145 //\r
1146 // Clear PortOverCurrent change\r
1147 //\r
1148 State |= XHC_PORTSC_OCC;\r
1149 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1150 break;\r
1151\r
1152 case EfiUsbPortResetChange:\r
1153 //\r
1154 // Clear Port Reset change\r
1155 //\r
1156 State |= XHC_PORTSC_PRC;\r
1157 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1158 break;\r
1159\r
1160 case EfiUsbPortSuspendChange:\r
1161 //\r
1162 // Not supported or not related operation\r
1163 //\r
1164 break;\r
1165\r
1166 default:\r
1167 Status = EFI_INVALID_PARAMETER;\r
1168 break;\r
1169 }\r
1170\r
1171ON_EXIT:\r
1172 DEBUG ((DEBUG_INFO, "XhcPeiClearRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));\r
1173 return Status;\r
1174}\r
1175\r
1176/**\r
1177 Sets a feature for the specified root hub port.\r
1178\r
1179 @param PeiServices The pointer of EFI_PEI_SERVICES\r
1180 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI\r
1181 @param PortNumber Root hub port to set.\r
1182 @param PortFeature Feature to set.\r
1183\r
1184 @retval EFI_SUCCESS The feature specified by PortFeature was set.\r
1185 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
1186 @retval EFI_TIMEOUT The time out occurred.\r
1187\r
1188**/\r
1189EFI_STATUS\r
1190EFIAPI\r
1191XhcPeiSetRootHubPortFeature (\r
1192 IN EFI_PEI_SERVICES **PeiServices,\r
1193 IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
1194 IN UINT8 PortNumber,\r
1195 IN EFI_USB_PORT_FEATURE PortFeature\r
1196 )\r
1197{\r
1198 PEI_XHC_DEV *Xhc;\r
1199 UINT32 Offset;\r
1200 UINT32 State;\r
1201 EFI_STATUS Status;\r
1202\r
1203 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
1204 Status = EFI_SUCCESS;\r
1205\r
1206 if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {\r
1207 Status = EFI_INVALID_PARAMETER;\r
1208 goto ON_EXIT;\r
1209 }\r
1210\r
1211 Offset = (UINT32)(XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
1212 State = XhcPeiReadOpReg (Xhc, Offset);\r
1213 DEBUG ((DEBUG_INFO, "XhcPeiSetRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));\r
1214\r
1215 //\r
1216 // Mask off the port status change bits, these bits are\r
1217 // write clean bits\r
1218 //\r
1219 State &= ~(BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);\r
1220\r
1221 switch (PortFeature) {\r
1222 case EfiUsbPortEnable:\r
1223 //\r
1224 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.\r
1225 // A port may be disabled by software writing a '1' to this flag.\r
1226 //\r
1227 break;\r
1228\r
1229 case EfiUsbPortSuspend:\r
1230 State |= XHC_PORTSC_LWS;\r
1231 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1232 State &= ~XHC_PORTSC_PLS;\r
1233 State |= (3 << 5);\r
1234 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1235 break;\r
1236\r
1237 case EfiUsbPortReset:\r
1238 //\r
1239 // Make sure Host Controller not halt before reset it\r
1240 //\r
1241 if (XhcPeiIsHalt (Xhc)) {\r
1242 Status = XhcPeiRunHC (Xhc, XHC_GENERIC_TIMEOUT);\r
1243 if (EFI_ERROR (Status)) {\r
1244 break;\r
1245 }\r
1246 }\r
1247\r
1248 //\r
1249 // 4.3.1 Resetting a Root Hub Port\r
1250 // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.\r
1251 // 2) Wait for a successful Port Status Change Event for the port, where the Port Reset Change (PRC)\r
1252 // bit in the PORTSC field is set to '1'.\r
1253 //\r
1254 State |= XHC_PORTSC_RESET;\r
1255 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1256 XhcPeiWaitOpRegBit (Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);\r
1257 break;\r
1258\r
1259 case EfiUsbPortPower:\r
1260 if (Xhc->HcCParams.Data.Ppc) {\r
1261 //\r
1262 // Port Power Control supported\r
1263 //\r
1264 State |= XHC_PORTSC_PP;\r
1265 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1266 }\r
1267\r
1268 break;\r
1269\r
1270 case EfiUsbPortOwner:\r
1271 //\r
1272 // XHCI root hub port don't has the owner bit, ignore the operation\r
1273 //\r
1274 break;\r
1275\r
1276 default:\r
1277 Status = EFI_INVALID_PARAMETER;\r
1278 }\r
1279\r
1280ON_EXIT:\r
1281 DEBUG ((DEBUG_INFO, "XhcPeiSetRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));\r
1282 return Status;\r
1283}\r
1284\r
1285/**\r
1286 Retrieves the current status of a USB root hub port.\r
1287\r
1288 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
1289 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
1290 @param PortNumber The root hub port to retrieve the state from.\r
1291 @param PortStatus Variable to receive the port state.\r
1292\r
1293 @retval EFI_SUCCESS The status of the USB root hub port specified.\r
1294 by PortNumber was returned in PortStatus.\r
1295 @retval EFI_INVALID_PARAMETER PortNumber is invalid.\r
1296\r
1297**/\r
1298EFI_STATUS\r
1299EFIAPI\r
1300XhcPeiGetRootHubPortStatus (\r
1301 IN EFI_PEI_SERVICES **PeiServices,\r
1302 IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
1303 IN UINT8 PortNumber,\r
1304 OUT EFI_USB_PORT_STATUS *PortStatus\r
1305 )\r
1306{\r
1307 PEI_XHC_DEV *Xhc;\r
1308 UINT32 Offset;\r
1309 UINT32 State;\r
1310 UINTN Index;\r
1311 UINTN MapSize;\r
1312 USB_DEV_ROUTE ParentRouteChart;\r
1313\r
1314 if (PortStatus == NULL) {\r
1315 return EFI_INVALID_PARAMETER;\r
1316 }\r
1317\r
1318 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
1319\r
1320 if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {\r
1321 return EFI_INVALID_PARAMETER;\r
1322 }\r
1323\r
1324 //\r
1325 // Clear port status.\r
1326 //\r
1327 PortStatus->PortStatus = 0;\r
1328 PortStatus->PortChangeStatus = 0;\r
1329\r
1330 Offset = (UINT32)(XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
1331 State = XhcPeiReadOpReg (Xhc, Offset);\r
1332 DEBUG ((DEBUG_INFO, "XhcPeiGetRootHubPortStatus: Port: %x State: %x\n", PortNumber, State));\r
1333\r
1334 //\r
1335 // According to XHCI 1.1 spec November 2017,\r
1336 // bit 10~13 of the root port status register identifies the speed of the attached device.\r
1337 //\r
1338 switch ((State & XHC_PORTSC_PS) >> 10) {\r
1339 case 2:\r
1340 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
1341 break;\r
1342\r
1343 case 3:\r
1344 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
1345 break;\r
1346\r
1347 case 4:\r
1348 case 5:\r
1349 PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
1350 break;\r
1351\r
1352 default:\r
1353 break;\r
1354 }\r
1355\r
1356 //\r
1357 // Convert the XHCI port/port change state to UEFI status\r
1358 //\r
1359 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
1360\r
1361 for (Index = 0; Index < MapSize; Index++) {\r
1362 if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {\r
1363 PortStatus->PortStatus = (UINT16)(PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);\r
1364 }\r
1365 }\r
1366\r
1367 //\r
1368 // Bit5~8 reflects its current link state.\r
1369 //\r
1370 if ((State & XHC_PORTSC_PLS) >> 5 == 3) {\r
1371 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
1372 }\r
1373\r
1374 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
1375\r
1376 for (Index = 0; Index < MapSize; Index++) {\r
1377 if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {\r
1378 PortStatus->PortChangeStatus = (UINT16)(PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);\r
1379 }\r
1380 }\r
1381\r
1382 MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);\r
1383\r
1384 for (Index = 0; Index < MapSize; Index++) {\r
1385 if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {\r
1386 XhcPeiClearRootHubPortFeature (PeiServices, This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);\r
1387 }\r
1388 }\r
1389\r
1390 //\r
1391 // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.\r
1392 // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.\r
1393 //\r
1394 ParentRouteChart.Dword = 0;\r
1395 XhcPeiPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);\r
1396\r
1397 DEBUG ((DEBUG_INFO, "XhcPeiGetRootHubPortStatus: PortChangeStatus: %x PortStatus: %x\n", PortStatus->PortChangeStatus, PortStatus->PortStatus));\r
1398 return EFI_SUCCESS;\r
1399}\r
1400\r
1401/**\r
1402 One notified function to stop the Host Controller at the end of PEI\r
1403\r
1404 @param[in] PeiServices Pointer to PEI Services Table.\r
1405 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification event that\r
1406 caused this function to execute.\r
1407 @param[in] Ppi Pointer to the PPI data associated with this function.\r
1408\r
1409 @retval EFI_SUCCESS The function completes successfully\r
1410 @retval others\r
1411**/\r
1412EFI_STATUS\r
1413EFIAPI\r
1414XhcEndOfPei (\r
1415 IN EFI_PEI_SERVICES **PeiServices,\r
1416 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
1417 IN VOID *Ppi\r
1418 )\r
1419{\r
1420 PEI_XHC_DEV *Xhc;\r
1421\r
1422 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS_NOTIFY (NotifyDescriptor);\r
1423\r
1424 XhcPeiHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
1425\r
1426 XhcPeiFreeSched (Xhc);\r
1427\r
1428 return EFI_SUCCESS;\r
1429}\r
1430\r
1431/**\r
1432 @param FileHandle Handle of the file being invoked.\r
1433 @param PeiServices Describes the list of possible PEI Services.\r
1434\r
1435 @retval EFI_SUCCESS PPI successfully installed.\r
1436\r
1437**/\r
1438EFI_STATUS\r
1439EFIAPI\r
1440XhcPeimEntry (\r
1441 IN EFI_PEI_FILE_HANDLE FileHandle,\r
1442 IN CONST EFI_PEI_SERVICES **PeiServices\r
1443 )\r
1444{\r
1445 PEI_USB_CONTROLLER_PPI *UsbControllerPpi;\r
1446 EFI_STATUS Status;\r
1447 UINT8 Index;\r
1448 UINTN ControllerType;\r
1449 UINTN BaseAddress;\r
1450 UINTN MemPages;\r
1451 PEI_XHC_DEV *XhcDev;\r
1452 EFI_PHYSICAL_ADDRESS TempPtr;\r
1453 UINT32 PageSize;\r
1454\r
1455 //\r
1456 // Shadow this PEIM to run from memory.\r
1457 //\r
1458 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
1459 return EFI_SUCCESS;\r
1460 }\r
1461\r
1462 Status = PeiServicesLocatePpi (\r
1463 &gPeiUsbControllerPpiGuid,\r
1464 0,\r
1465 NULL,\r
1466 (VOID **)&UsbControllerPpi\r
1467 );\r
1468 if (EFI_ERROR (Status)) {\r
1469 return EFI_UNSUPPORTED;\r
1470 }\r
1471\r
1472 IoMmuInit ();\r
1473\r
1474 Index = 0;\r
1475 while (TRUE) {\r
1476 Status = UsbControllerPpi->GetUsbController (\r
1477 (EFI_PEI_SERVICES **)PeiServices,\r
1478 UsbControllerPpi,\r
1479 Index,\r
1480 &ControllerType,\r
1481 &BaseAddress\r
1482 );\r
1483 //\r
1484 // When status is error, it means no controller is found.\r
1485 //\r
1486 if (EFI_ERROR (Status)) {\r
1487 break;\r
1488 }\r
1489\r
1490 //\r
1491 // This PEIM is for XHC type controller.\r
1492 //\r
1493 if (ControllerType != PEI_XHCI_CONTROLLER) {\r
1494 Index++;\r
1495 continue;\r
1496 }\r
1497\r
1498 MemPages = EFI_SIZE_TO_PAGES (sizeof (PEI_XHC_DEV));\r
1499 Status = PeiServicesAllocatePages (\r
1500 EfiBootServicesData,\r
1501 MemPages,\r
1502 &TempPtr\r
1503 );\r
1504 if (EFI_ERROR (Status)) {\r
1505 return EFI_OUT_OF_RESOURCES;\r
1506 }\r
1507\r
1508 ZeroMem ((VOID *)(UINTN)TempPtr, EFI_PAGES_TO_SIZE (MemPages));\r
1509 XhcDev = (PEI_XHC_DEV *)((UINTN)TempPtr);\r
1510\r
1511 XhcDev->Signature = USB_XHC_DEV_SIGNATURE;\r
1512 XhcDev->UsbHostControllerBaseAddress = (UINT32)BaseAddress;\r
1513 XhcDev->CapLength = (UINT8)(XhcPeiReadCapRegister (XhcDev, XHC_CAPLENGTH_OFFSET) & 0x0FF);\r
1514 XhcDev->HcSParams1.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS1_OFFSET);\r
1515 XhcDev->HcSParams2.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS2_OFFSET);\r
1516 XhcDev->HcCParams.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCCPARAMS_OFFSET);\r
1517 XhcDev->DBOff = XhcPeiReadCapRegister (XhcDev, XHC_DBOFF_OFFSET);\r
1518 XhcDev->RTSOff = XhcPeiReadCapRegister (XhcDev, XHC_RTSOFF_OFFSET);\r
1519\r
1520 //\r
1521 // This PageSize field defines the page size supported by the xHC implementation.\r
1522 // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,\r
1523 // if bit 0 is Set, the xHC supports 4k byte page sizes.\r
1524 //\r
1525 PageSize = XhcPeiReadOpReg (XhcDev, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK;\r
1526 XhcDev->PageSize = 1 << (HighBitSet32 (PageSize) + 12);\r
1527\r
1528 DEBUG ((DEBUG_INFO, "XhciPei: UsbHostControllerBaseAddress: %x\n", XhcDev->UsbHostControllerBaseAddress));\r
1529 DEBUG ((DEBUG_INFO, "XhciPei: CapLength: %x\n", XhcDev->CapLength));\r
1530 DEBUG ((DEBUG_INFO, "XhciPei: HcSParams1: %x\n", XhcDev->HcSParams1.Dword));\r
1531 DEBUG ((DEBUG_INFO, "XhciPei: HcSParams2: %x\n", XhcDev->HcSParams2.Dword));\r
1532 DEBUG ((DEBUG_INFO, "XhciPei: HcCParams: %x\n", XhcDev->HcCParams.Dword));\r
1533 DEBUG ((DEBUG_INFO, "XhciPei: DBOff: %x\n", XhcDev->DBOff));\r
1534 DEBUG ((DEBUG_INFO, "XhciPei: RTSOff: %x\n", XhcDev->RTSOff));\r
1535 DEBUG ((DEBUG_INFO, "XhciPei: PageSize: %x\n", XhcDev->PageSize));\r
1536\r
1537 XhcPeiResetHC (XhcDev, XHC_RESET_TIMEOUT);\r
1538 ASSERT (XhcPeiIsHalt (XhcDev));\r
1539\r
1540 //\r
1541 // Initialize the schedule\r
1542 //\r
1543 XhcPeiInitSched (XhcDev);\r
1544\r
1545 //\r
1546 // Start the Host Controller\r
1547 //\r
1548 XhcPeiRunHC (XhcDev, XHC_GENERIC_TIMEOUT);\r
1549\r
1550 //\r
1551 // Wait for root port state stable\r
1552 //\r
1553 MicroSecondDelay (XHC_ROOT_PORT_STATE_STABLE);\r
1554\r
1555 XhcDev->Usb2HostControllerPpi.ControlTransfer = XhcPeiControlTransfer;\r
1556 XhcDev->Usb2HostControllerPpi.BulkTransfer = XhcPeiBulkTransfer;\r
1557 XhcDev->Usb2HostControllerPpi.GetRootHubPortNumber = XhcPeiGetRootHubPortNumber;\r
1558 XhcDev->Usb2HostControllerPpi.GetRootHubPortStatus = XhcPeiGetRootHubPortStatus;\r
1559 XhcDev->Usb2HostControllerPpi.SetRootHubPortFeature = XhcPeiSetRootHubPortFeature;\r
1560 XhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature = XhcPeiClearRootHubPortFeature;\r
1561\r
1562 XhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
1563 XhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;\r
1564 XhcDev->PpiDescriptor.Ppi = &XhcDev->Usb2HostControllerPpi;\r
1565\r
1566 XhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
1567 XhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;\r
1568 XhcDev->EndOfPeiNotifyList.Notify = XhcEndOfPei;\r
1569\r
1570 PeiServicesInstallPpi (&XhcDev->PpiDescriptor);\r
1571 PeiServicesNotifyPpi (&XhcDev->EndOfPeiNotifyList);\r
1572\r
1573 Index++;\r
1574 }\r
1575\r
1576 return EFI_SUCCESS;\r
1577}\r