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