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