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