]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / EhciPei / EhcPeim.c
1 /** @file
2 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
4
5 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "EhcPeim.h"
12
13 //
14 // Two arrays used to translate the EHCI port state (change)
15 // to the UEFI protocol's port state (change).
16 //
17 USB_PORT_STATE_MAP mUsbPortStateMap[] = {
18 { PORTSC_CONN, USB_PORT_STAT_CONNECTION },
19 { PORTSC_ENABLED, USB_PORT_STAT_ENABLE },
20 { PORTSC_SUSPEND, USB_PORT_STAT_SUSPEND },
21 { PORTSC_OVERCUR, USB_PORT_STAT_OVERCURRENT },
22 { PORTSC_RESET, USB_PORT_STAT_RESET },
23 { PORTSC_POWER, USB_PORT_STAT_POWER },
24 { PORTSC_OWNER, USB_PORT_STAT_OWNER }
25 };
26
27 USB_PORT_STATE_MAP mUsbPortChangeMap[] = {
28 { PORTSC_CONN_CHANGE, USB_PORT_STAT_C_CONNECTION },
29 { PORTSC_ENABLE_CHANGE, USB_PORT_STAT_C_ENABLE },
30 { PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT }
31 };
32
33 /**
34 Read Ehc Operation register.
35
36 @param Ehc The EHCI device.
37 @param Offset The operation register offset.
38
39 @retval the register content read.
40
41 **/
42 UINT32
43 EhcReadOpReg (
44 IN PEI_USB2_HC_DEV *Ehc,
45 IN UINT32 Offset
46 )
47 {
48 UINT32 Data;
49
50 ASSERT (Ehc->CapLen != 0);
51
52 Data = MmioRead32 (Ehc->UsbHostControllerBaseAddress + Ehc->CapLen + Offset);
53
54 return Data;
55 }
56
57 /**
58 Write the data to the EHCI operation register.
59
60 @param Ehc The EHCI device.
61 @param Offset EHCI operation register offset.
62 @param Data The data to write.
63
64 **/
65 VOID
66 EhcWriteOpReg (
67 IN PEI_USB2_HC_DEV *Ehc,
68 IN UINT32 Offset,
69 IN UINT32 Data
70 )
71 {
72 ASSERT (Ehc->CapLen != 0);
73
74 MmioWrite32 (Ehc->UsbHostControllerBaseAddress + Ehc->CapLen + Offset, Data);
75 }
76
77 /**
78 Set one bit of the operational register while keeping other bits.
79
80 @param Ehc The EHCI device.
81 @param Offset The offset of the operational register.
82 @param Bit The bit mask of the register to set.
83
84 **/
85 VOID
86 EhcSetOpRegBit (
87 IN PEI_USB2_HC_DEV *Ehc,
88 IN UINT32 Offset,
89 IN UINT32 Bit
90 )
91 {
92 UINT32 Data;
93
94 Data = EhcReadOpReg (Ehc, Offset);
95 Data |= Bit;
96 EhcWriteOpReg (Ehc, Offset, Data);
97 }
98
99 /**
100 Clear one bit of the operational register while keeping other bits.
101
102 @param Ehc The EHCI device.
103 @param Offset The offset of the operational register.
104 @param Bit The bit mask of the register to clear.
105
106 **/
107 VOID
108 EhcClearOpRegBit (
109 IN PEI_USB2_HC_DEV *Ehc,
110 IN UINT32 Offset,
111 IN UINT32 Bit
112 )
113 {
114 UINT32 Data;
115
116 Data = EhcReadOpReg (Ehc, Offset);
117 Data &= ~Bit;
118 EhcWriteOpReg (Ehc, Offset, Data);
119 }
120
121 /**
122 Wait the operation register's bit as specified by Bit
123 to become set (or clear).
124
125 @param Ehc The EHCI device.
126 @param Offset The offset of the operational register.
127 @param Bit The bit mask of the register to wait for.
128 @param WaitToSet Wait the bit to set or clear.
129 @param Timeout The time to wait before abort (in millisecond).
130
131 @retval EFI_SUCCESS The bit successfully changed by host controller.
132 @retval EFI_TIMEOUT The time out occurred.
133
134 **/
135 EFI_STATUS
136 EhcWaitOpRegBit (
137 IN PEI_USB2_HC_DEV *Ehc,
138 IN UINT32 Offset,
139 IN UINT32 Bit,
140 IN BOOLEAN WaitToSet,
141 IN UINT32 Timeout
142 )
143 {
144 UINT32 Index;
145
146 for (Index = 0; Index < Timeout / EHC_SYNC_POLL_INTERVAL + 1; Index++) {
147 if (EHC_REG_BIT_IS_SET (Ehc, Offset, Bit) == WaitToSet) {
148 return EFI_SUCCESS;
149 }
150
151 MicroSecondDelay (EHC_SYNC_POLL_INTERVAL);
152 }
153
154 return EFI_TIMEOUT;
155 }
156
157 /**
158 Read EHCI capability register.
159
160 @param Ehc The EHCI device.
161 @param Offset Capability register address.
162
163 @retval the register content read.
164
165 **/
166 UINT32
167 EhcReadCapRegister (
168 IN PEI_USB2_HC_DEV *Ehc,
169 IN UINT32 Offset
170 )
171 {
172 UINT32 Data;
173
174 Data = MmioRead32 (Ehc->UsbHostControllerBaseAddress + Offset);
175
176 return Data;
177 }
178
179 /**
180 Set door bell and wait it to be ACKed by host controller.
181 This function is used to synchronize with the hardware.
182
183 @param Ehc The EHCI device.
184 @param Timeout The time to wait before abort (in millisecond, ms).
185
186 @retval EFI_TIMEOUT Time out happened while waiting door bell to set.
187 @retval EFI_SUCCESS Synchronized with the hardware.
188
189 **/
190 EFI_STATUS
191 EhcSetAndWaitDoorBell (
192 IN PEI_USB2_HC_DEV *Ehc,
193 IN UINT32 Timeout
194 )
195 {
196 EFI_STATUS Status;
197 UINT32 Data;
198
199 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_IAAD);
200
201 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_IAA, TRUE, Timeout);
202
203 //
204 // ACK the IAA bit in USBSTS register. Make sure other
205 // interrupt bits are not ACKed. These bits are WC (Write Clean).
206 //
207 Data = EhcReadOpReg (Ehc, EHC_USBSTS_OFFSET);
208 Data &= ~USBSTS_INTACK_MASK;
209 Data |= USBSTS_IAA;
210
211 EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, Data);
212
213 return Status;
214 }
215
216 /**
217 Clear all the interrutp status bits, these bits
218 are Write-Clean.
219
220 @param Ehc The EHCI device.
221
222 **/
223 VOID
224 EhcAckAllInterrupt (
225 IN PEI_USB2_HC_DEV *Ehc
226 )
227 {
228 EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, USBSTS_INTACK_MASK);
229 }
230
231 /**
232 Enable the periodic schedule then wait EHC to
233 actually enable it.
234
235 @param Ehc The EHCI device.
236 @param Timeout The time to wait before abort (in millisecond, ms).
237
238 @retval EFI_TIMEOUT Time out happened while enabling periodic schedule.
239 @retval EFI_SUCCESS The periodical schedule is enabled.
240
241 **/
242 EFI_STATUS
243 EhcEnablePeriodSchd (
244 IN PEI_USB2_HC_DEV *Ehc,
245 IN UINT32 Timeout
246 )
247 {
248 EFI_STATUS Status;
249
250 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_PERIOD);
251
252 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_PERIOD_ENABLED, TRUE, Timeout);
253 return Status;
254 }
255
256 /**
257 Enable asynchrounous schedule.
258
259 @param Ehc The EHCI device.
260 @param Timeout Time to wait before abort.
261
262 @retval EFI_SUCCESS The EHCI asynchronous schedule is enabled.
263 @retval Others Failed to enable the asynchronous scheudle.
264
265 **/
266 EFI_STATUS
267 EhcEnableAsyncSchd (
268 IN PEI_USB2_HC_DEV *Ehc,
269 IN UINT32 Timeout
270 )
271 {
272 EFI_STATUS Status;
273
274 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_ASYNC);
275
276 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_ASYNC_ENABLED, TRUE, Timeout);
277 return Status;
278 }
279
280 /**
281 Check whether Ehc is halted.
282
283 @param Ehc The EHCI device.
284
285 @retval TRUE The controller is halted.
286 @retval FALSE The controller isn't halted.
287
288 **/
289 BOOLEAN
290 EhcIsHalt (
291 IN PEI_USB2_HC_DEV *Ehc
292 )
293 {
294 return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT);
295 }
296
297 /**
298 Check whether system error occurred.
299
300 @param Ehc The EHCI device.
301
302 @retval TRUE System error happened.
303 @retval FALSE No system error.
304
305 **/
306 BOOLEAN
307 EhcIsSysError (
308 IN PEI_USB2_HC_DEV *Ehc
309 )
310 {
311 return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR);
312 }
313
314 /**
315 Reset the host controller.
316
317 @param Ehc The EHCI device.
318 @param Timeout Time to wait before abort (in millisecond, ms).
319
320 @retval EFI_TIMEOUT The transfer failed due to time out.
321 @retval Others Failed to reset the host.
322
323 **/
324 EFI_STATUS
325 EhcResetHC (
326 IN PEI_USB2_HC_DEV *Ehc,
327 IN UINT32 Timeout
328 )
329 {
330 EFI_STATUS Status;
331
332 //
333 // Host can only be reset when it is halt. If not so, halt it
334 //
335 if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {
336 Status = EhcHaltHC (Ehc, Timeout);
337
338 if (EFI_ERROR (Status)) {
339 return Status;
340 }
341 }
342
343 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET);
344 Status = EhcWaitOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET, FALSE, Timeout);
345 return Status;
346 }
347
348 /**
349 Halt the host controller.
350
351 @param Ehc The EHCI device.
352 @param Timeout Time to wait before abort.
353
354 @retval EFI_TIMEOUT Failed to halt the controller before Timeout.
355 @retval EFI_SUCCESS The EHCI is halt.
356
357 **/
358 EFI_STATUS
359 EhcHaltHC (
360 IN PEI_USB2_HC_DEV *Ehc,
361 IN UINT32 Timeout
362 )
363 {
364 EFI_STATUS Status;
365
366 EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
367 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, TRUE, Timeout);
368 return Status;
369 }
370
371 /**
372 Set the EHCI to run.
373
374 @param Ehc The EHCI device.
375 @param Timeout Time to wait before abort.
376
377 @retval EFI_SUCCESS The EHCI is running.
378 @retval Others Failed to set the EHCI to run.
379
380 **/
381 EFI_STATUS
382 EhcRunHC (
383 IN PEI_USB2_HC_DEV *Ehc,
384 IN UINT32 Timeout
385 )
386 {
387 EFI_STATUS Status;
388
389 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
390 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, FALSE, Timeout);
391 return Status;
392 }
393
394 /**
395 Power On All EHCI Ports.
396
397 @param Ehc The EHCI device.
398
399 **/
400 VOID
401 EhcPowerOnAllPorts (
402 IN PEI_USB2_HC_DEV *Ehc
403 )
404 {
405 UINT8 PortNumber;
406 UINT8 Index;
407 UINT32 RegVal;
408
409 PortNumber = (UINT8)(Ehc->HcStructParams & HCSP_NPORTS);
410 for (Index = 0; Index < PortNumber; Index++) {
411 //
412 // Do not clear port status bits on initialization. Otherwise devices will
413 // not enumerate properly at startup.
414 //
415 RegVal = EhcReadOpReg (Ehc, EHC_PORT_STAT_OFFSET + 4 * Index);
416 RegVal &= ~PORTSC_CHANGE_MASK;
417 RegVal |= PORTSC_POWER;
418 EhcWriteOpReg (Ehc, EHC_PORT_STAT_OFFSET + 4 * Index, RegVal);
419 }
420 }
421
422 /**
423 Initialize the HC hardware.
424 EHCI spec lists the five things to do to initialize the hardware.
425 1. Program CTRLDSSEGMENT.
426 2. Set USBINTR to enable interrupts.
427 3. Set periodic list base.
428 4. Set USBCMD, interrupt threshold, frame list size etc.
429 5. Write 1 to CONFIGFLAG to route all ports to EHCI.
430
431 @param Ehc The EHCI device.
432
433 @retval EFI_SUCCESS The EHCI has come out of halt state.
434 @retval EFI_TIMEOUT Time out happened.
435
436 **/
437 EFI_STATUS
438 EhcInitHC (
439 IN PEI_USB2_HC_DEV *Ehc
440 )
441 {
442 EFI_STATUS Status;
443 EFI_PHYSICAL_ADDRESS TempPtr;
444 UINTN PageNumber;
445
446 ASSERT (EhcIsHalt (Ehc));
447
448 //
449 // Allocate the periodic frame and associated memeory
450 // management facilities if not already done.
451 //
452 if (Ehc->PeriodFrame != NULL) {
453 EhcFreeSched (Ehc);
454 }
455
456 PageNumber = sizeof (PEI_URB)/PAGESIZE +1;
457 Status = PeiServicesAllocatePages (
458 EfiBootServicesCode,
459 PageNumber,
460 &TempPtr
461 );
462 Ehc->Urb = (PEI_URB *)((UINTN)TempPtr);
463 if (Ehc->Urb == NULL) {
464 return Status;
465 }
466
467 EhcPowerOnAllPorts (Ehc);
468 MicroSecondDelay (EHC_ROOT_PORT_RECOVERY_STALL);
469
470 Status = EhcInitSched (Ehc);
471
472 if (EFI_ERROR (Status)) {
473 return Status;
474 }
475
476 //
477 // 1. Program the CTRLDSSEGMENT register with the high 32 bit addr
478 //
479 EhcWriteOpReg (Ehc, EHC_CTRLDSSEG_OFFSET, Ehc->High32bitAddr);
480
481 //
482 // 2. Clear USBINTR to disable all the interrupt. UEFI works by polling
483 //
484 EhcWriteOpReg (Ehc, EHC_USBINTR_OFFSET, 0);
485
486 //
487 // 3. Program periodic frame list, already done in EhcInitSched
488 // 4. Start the Host Controller
489 //
490 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
491
492 //
493 // 5. Set all ports routing to EHC
494 //
495 EhcSetOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);
496
497 //
498 // Wait roothub port power stable
499 //
500 MicroSecondDelay (EHC_ROOT_PORT_RECOVERY_STALL);
501
502 Status = EhcEnablePeriodSchd (Ehc, EHC_GENERIC_TIMEOUT);
503
504 if (EFI_ERROR (Status)) {
505 return Status;
506 }
507
508 Status = EhcEnableAsyncSchd (Ehc, EHC_GENERIC_TIMEOUT);
509
510 if (EFI_ERROR (Status)) {
511 return Status;
512 }
513
514 return EFI_SUCCESS;
515 }
516
517 /**
518 Submits bulk transfer to a bulk endpoint of a USB device.
519
520 @param PeiServices The pointer of EFI_PEI_SERVICES.
521 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
522 @param DeviceAddress Target device address.
523 @param EndPointAddress Endpoint number and its direction in bit 7.
524 @param DeviceSpeed Device speed, Low speed device doesn't support
525 bulk transfer.
526 @param MaximumPacketLength Maximum packet size the endpoint is capable of
527 sending or receiving.
528 @param Data Array of pointers to the buffers of data to transmit
529 from or receive into.
530 @param DataLength The lenght of the data buffer.
531 @param DataToggle On input, the initial data toggle for the transfer;
532 On output, it is updated to to next data toggle to use of
533 the subsequent bulk transfer.
534 @param TimeOut Indicates the maximum time, in millisecond, which the
535 transfer is allowed to complete.
536 If Timeout is 0, then the caller must wait for the function
537 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
538 @param Translator A pointr to the transaction translator data.
539 @param TransferResult A pointer to the detailed result information of the
540 bulk transfer.
541
542 @retval EFI_SUCCESS The transfer was completed successfully.
543 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
544 @retval EFI_INVALID_PARAMETER Parameters are invalid.
545 @retval EFI_TIMEOUT The transfer failed due to timeout.
546 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
547
548 **/
549 EFI_STATUS
550 EFIAPI
551 EhcBulkTransfer (
552 IN EFI_PEI_SERVICES **PeiServices,
553 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
554 IN UINT8 DeviceAddress,
555 IN UINT8 EndPointAddress,
556 IN UINT8 DeviceSpeed,
557 IN UINTN MaximumPacketLength,
558 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
559 IN OUT UINTN *DataLength,
560 IN OUT UINT8 *DataToggle,
561 IN UINTN TimeOut,
562 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
563 OUT UINT32 *TransferResult
564 )
565 {
566 PEI_USB2_HC_DEV *Ehc;
567 PEI_URB *Urb;
568 EFI_STATUS Status;
569
570 //
571 // Validate the parameters
572 //
573 if ((DataLength == NULL) || (*DataLength == 0) ||
574 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL))
575 {
576 return EFI_INVALID_PARAMETER;
577 }
578
579 if ((*DataToggle != 0) && (*DataToggle != 1)) {
580 return EFI_INVALID_PARAMETER;
581 }
582
583 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
584 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
585 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512)))
586 {
587 return EFI_INVALID_PARAMETER;
588 }
589
590 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
591 *TransferResult = EFI_USB_ERR_SYSTEM;
592 Status = EFI_DEVICE_ERROR;
593
594 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
595 EhcAckAllInterrupt (Ehc);
596 goto ON_EXIT;
597 }
598
599 EhcAckAllInterrupt (Ehc);
600
601 //
602 // Create a new URB, insert it into the asynchronous
603 // schedule list, then poll the execution status.
604 //
605 Urb = EhcCreateUrb (
606 Ehc,
607 DeviceAddress,
608 EndPointAddress,
609 DeviceSpeed,
610 *DataToggle,
611 MaximumPacketLength,
612 Translator,
613 EHC_BULK_TRANSFER,
614 NULL,
615 Data[0],
616 *DataLength,
617 NULL,
618 NULL,
619 1
620 );
621
622 if (Urb == NULL) {
623 Status = EFI_OUT_OF_RESOURCES;
624 goto ON_EXIT;
625 }
626
627 EhcLinkQhToAsync (Ehc, Urb->Qh);
628 Status = EhcExecTransfer (Ehc, Urb, TimeOut);
629 EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
630
631 *TransferResult = Urb->Result;
632 *DataLength = Urb->Completed;
633 *DataToggle = Urb->DataToggle;
634
635 if (*TransferResult == EFI_USB_NOERROR) {
636 Status = EFI_SUCCESS;
637 }
638
639 EhcAckAllInterrupt (Ehc);
640 EhcFreeUrb (Ehc, Urb);
641
642 ON_EXIT:
643 return Status;
644 }
645
646 /**
647 Retrieves the number of root hub ports.
648
649 @param[in] PeiServices The pointer to the PEI Services Table.
650 @param[in] This The pointer to this instance of the
651 PEI_USB2_HOST_CONTROLLER_PPI.
652 @param[out] PortNumber The pointer to the number of the root hub ports.
653
654 @retval EFI_SUCCESS The port number was retrieved successfully.
655 @retval EFI_INVALID_PARAMETER PortNumber is NULL.
656
657 **/
658 EFI_STATUS
659 EFIAPI
660 EhcGetRootHubPortNumber (
661 IN EFI_PEI_SERVICES **PeiServices,
662 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
663 OUT UINT8 *PortNumber
664 )
665 {
666 PEI_USB2_HC_DEV *EhcDev;
667
668 EhcDev = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
669
670 if (PortNumber == NULL) {
671 return EFI_INVALID_PARAMETER;
672 }
673
674 *PortNumber = (UINT8)(EhcDev->HcStructParams & HCSP_NPORTS);
675 return EFI_SUCCESS;
676 }
677
678 /**
679 Clears a feature for the specified root hub port.
680
681 @param PeiServices The pointer of EFI_PEI_SERVICES.
682 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
683 @param PortNumber Specifies the root hub port whose feature
684 is requested to be cleared.
685 @param PortFeature Indicates the feature selector associated with the
686 feature clear request.
687
688 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
689 for the USB root hub port specified by PortNumber.
690 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
691
692 **/
693 EFI_STATUS
694 EFIAPI
695 EhcClearRootHubPortFeature (
696 IN EFI_PEI_SERVICES **PeiServices,
697 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
698 IN UINT8 PortNumber,
699 IN EFI_USB_PORT_FEATURE PortFeature
700 )
701 {
702 PEI_USB2_HC_DEV *Ehc;
703 UINT32 Offset;
704 UINT32 State;
705 UINT32 TotalPort;
706 EFI_STATUS Status;
707
708 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
709 Status = EFI_SUCCESS;
710
711 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
712
713 if (PortNumber >= TotalPort) {
714 Status = EFI_INVALID_PARAMETER;
715 goto ON_EXIT;
716 }
717
718 Offset = EHC_PORT_STAT_OFFSET + (4 * PortNumber);
719 State = EhcReadOpReg (Ehc, Offset);
720 State &= ~PORTSC_CHANGE_MASK;
721
722 switch (PortFeature) {
723 case EfiUsbPortEnable:
724 //
725 // Clear PORT_ENABLE feature means disable port.
726 //
727 State &= ~PORTSC_ENABLED;
728 EhcWriteOpReg (Ehc, Offset, State);
729 break;
730
731 case EfiUsbPortSuspend:
732 //
733 // A write of zero to this bit is ignored by the host
734 // controller. The host controller will unconditionally
735 // set this bit to a zero when:
736 // 1. software sets the Forct Port Resume bit to a zero from a one.
737 // 2. software sets the Port Reset bit to a one frome a zero.
738 //
739 State &= ~PORSTSC_RESUME;
740 EhcWriteOpReg (Ehc, Offset, State);
741 break;
742
743 case EfiUsbPortReset:
744 //
745 // Clear PORT_RESET means clear the reset signal.
746 //
747 State &= ~PORTSC_RESET;
748 EhcWriteOpReg (Ehc, Offset, State);
749 break;
750
751 case EfiUsbPortOwner:
752 //
753 // Clear port owner means this port owned by EHC
754 //
755 State &= ~PORTSC_OWNER;
756 EhcWriteOpReg (Ehc, Offset, State);
757 break;
758
759 case EfiUsbPortConnectChange:
760 //
761 // Clear connect status change
762 //
763 State |= PORTSC_CONN_CHANGE;
764 EhcWriteOpReg (Ehc, Offset, State);
765 break;
766
767 case EfiUsbPortEnableChange:
768 //
769 // Clear enable status change
770 //
771 State |= PORTSC_ENABLE_CHANGE;
772 EhcWriteOpReg (Ehc, Offset, State);
773 break;
774
775 case EfiUsbPortOverCurrentChange:
776 //
777 // Clear PortOverCurrent change
778 //
779 State |= PORTSC_OVERCUR_CHANGE;
780 EhcWriteOpReg (Ehc, Offset, State);
781 break;
782
783 case EfiUsbPortPower:
784 case EfiUsbPortSuspendChange:
785 case EfiUsbPortResetChange:
786 //
787 // Not supported or not related operation
788 //
789 break;
790
791 default:
792 Status = EFI_INVALID_PARAMETER;
793 break;
794 }
795
796 ON_EXIT:
797 return Status;
798 }
799
800 /**
801 Sets a feature for the specified root hub port.
802
803 @param PeiServices The pointer of EFI_PEI_SERVICES
804 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI
805 @param PortNumber Root hub port to set.
806 @param PortFeature Feature to set.
807
808 @retval EFI_SUCCESS The feature specified by PortFeature was set.
809 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
810 @retval EFI_TIMEOUT The time out occurred.
811
812 **/
813 EFI_STATUS
814 EFIAPI
815 EhcSetRootHubPortFeature (
816 IN EFI_PEI_SERVICES **PeiServices,
817 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
818 IN UINT8 PortNumber,
819 IN EFI_USB_PORT_FEATURE PortFeature
820 )
821 {
822 PEI_USB2_HC_DEV *Ehc;
823 UINT32 Offset;
824 UINT32 State;
825 UINT32 TotalPort;
826 EFI_STATUS Status;
827
828 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
829 Status = EFI_SUCCESS;
830
831 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
832
833 if (PortNumber >= TotalPort) {
834 Status = EFI_INVALID_PARAMETER;
835 goto ON_EXIT;
836 }
837
838 Offset = (UINT32)(EHC_PORT_STAT_OFFSET + (4 * PortNumber));
839 State = EhcReadOpReg (Ehc, Offset);
840
841 //
842 // Mask off the port status change bits, these bits are
843 // write clean bit
844 //
845 State &= ~PORTSC_CHANGE_MASK;
846
847 switch (PortFeature) {
848 case EfiUsbPortEnable:
849 //
850 // Sofeware can't set this bit, Port can only be enable by
851 // EHCI as a part of the reset and enable
852 //
853 State |= PORTSC_ENABLED;
854 EhcWriteOpReg (Ehc, Offset, State);
855 break;
856
857 case EfiUsbPortSuspend:
858 State |= PORTSC_SUSPEND;
859 EhcWriteOpReg (Ehc, Offset, State);
860 break;
861
862 case EfiUsbPortReset:
863 //
864 // Make sure Host Controller not halt before reset it
865 //
866 if (EhcIsHalt (Ehc)) {
867 Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);
868
869 if (EFI_ERROR (Status)) {
870 break;
871 }
872 }
873
874 //
875 // Set one to PortReset bit must also set zero to PortEnable bit
876 //
877 State |= PORTSC_RESET;
878 State &= ~PORTSC_ENABLED;
879 EhcWriteOpReg (Ehc, Offset, State);
880 break;
881
882 case EfiUsbPortPower:
883 //
884 // Not supported, ignore the operation
885 //
886 Status = EFI_SUCCESS;
887 break;
888
889 case EfiUsbPortOwner:
890 State |= PORTSC_OWNER;
891 EhcWriteOpReg (Ehc, Offset, State);
892 break;
893
894 default:
895 Status = EFI_INVALID_PARAMETER;
896 }
897
898 ON_EXIT:
899 return Status;
900 }
901
902 /**
903 Retrieves the current status of a USB root hub port.
904
905 @param PeiServices The pointer of EFI_PEI_SERVICES.
906 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
907 @param PortNumber The root hub port to retrieve the state from.
908 @param PortStatus Variable to receive the port state.
909
910 @retval EFI_SUCCESS The status of the USB root hub port specified.
911 by PortNumber was returned in PortStatus.
912 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
913
914 **/
915 EFI_STATUS
916 EFIAPI
917 EhcGetRootHubPortStatus (
918 IN EFI_PEI_SERVICES **PeiServices,
919 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
920 IN UINT8 PortNumber,
921 OUT EFI_USB_PORT_STATUS *PortStatus
922 )
923 {
924 PEI_USB2_HC_DEV *Ehc;
925 UINT32 Offset;
926 UINT32 State;
927 UINT32 TotalPort;
928 UINTN Index;
929 UINTN MapSize;
930 EFI_STATUS Status;
931
932 if (PortStatus == NULL) {
933 return EFI_INVALID_PARAMETER;
934 }
935
936 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
937 Status = EFI_SUCCESS;
938
939 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
940
941 if (PortNumber >= TotalPort) {
942 Status = EFI_INVALID_PARAMETER;
943 goto ON_EXIT;
944 }
945
946 Offset = (UINT32)(EHC_PORT_STAT_OFFSET + (4 * PortNumber));
947 PortStatus->PortStatus = 0;
948 PortStatus->PortChangeStatus = 0;
949
950 State = EhcReadOpReg (Ehc, Offset);
951
952 //
953 // Identify device speed. If in K state, it is low speed.
954 // If the port is enabled after reset, the device is of
955 // high speed. The USB bus driver should retrieve the actual
956 // port speed after reset.
957 //
958 if (EHC_BIT_IS_SET (State, PORTSC_LINESTATE_K)) {
959 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
960 } else if (EHC_BIT_IS_SET (State, PORTSC_ENABLED)) {
961 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
962 }
963
964 //
965 // Convert the EHCI port/port change state to UEFI status
966 //
967 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
968
969 for (Index = 0; Index < MapSize; Index++) {
970 if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
971 PortStatus->PortStatus = (UINT16)(PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
972 }
973 }
974
975 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
976
977 for (Index = 0; Index < MapSize; Index++) {
978 if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
979 PortStatus->PortChangeStatus = (UINT16)(PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
980 }
981 }
982
983 ON_EXIT:
984 return Status;
985 }
986
987 /**
988 Submits control transfer to a target USB device.
989
990 @param PeiServices The pointer of EFI_PEI_SERVICES.
991 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
992 @param DeviceAddress The target device address.
993 @param DeviceSpeed Target device speed.
994 @param MaximumPacketLength Maximum packet size the default control transfer
995 endpoint is capable of sending or receiving.
996 @param Request USB device request to send.
997 @param TransferDirection Specifies the data direction for the data stage.
998 @param Data Data buffer to be transmitted or received from USB device.
999 @param DataLength The size (in bytes) of the data buffer.
1000 @param TimeOut Indicates the maximum timeout, in millisecond.
1001 If Timeout is 0, then the caller must wait for the function
1002 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
1003 @param Translator Transaction translator to be used by this device.
1004 @param TransferResult Return the result of this control transfer.
1005
1006 @retval EFI_SUCCESS Transfer was completed successfully.
1007 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
1008 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
1009 @retval EFI_TIMEOUT Transfer failed due to timeout.
1010 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
1011
1012 **/
1013 EFI_STATUS
1014 EFIAPI
1015 EhcControlTransfer (
1016 IN EFI_PEI_SERVICES **PeiServices,
1017 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
1018 IN UINT8 DeviceAddress,
1019 IN UINT8 DeviceSpeed,
1020 IN UINTN MaximumPacketLength,
1021 IN EFI_USB_DEVICE_REQUEST *Request,
1022 IN EFI_USB_DATA_DIRECTION TransferDirection,
1023 IN OUT VOID *Data,
1024 IN OUT UINTN *DataLength,
1025 IN UINTN TimeOut,
1026 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1027 OUT UINT32 *TransferResult
1028 )
1029 {
1030 PEI_USB2_HC_DEV *Ehc;
1031 PEI_URB *Urb;
1032 UINT8 Endpoint;
1033 EFI_STATUS Status;
1034
1035 //
1036 // Validate parameters
1037 //
1038 if ((Request == NULL) || (TransferResult == NULL)) {
1039 return EFI_INVALID_PARAMETER;
1040 }
1041
1042 if ((TransferDirection != EfiUsbDataIn) &&
1043 (TransferDirection != EfiUsbDataOut) &&
1044 (TransferDirection != EfiUsbNoData))
1045 {
1046 return EFI_INVALID_PARAMETER;
1047 }
1048
1049 if ((TransferDirection == EfiUsbNoData) &&
1050 ((Data != NULL) || (*DataLength != 0)))
1051 {
1052 return EFI_INVALID_PARAMETER;
1053 }
1054
1055 if ((TransferDirection != EfiUsbNoData) &&
1056 ((Data == NULL) || (*DataLength == 0)))
1057 {
1058 return EFI_INVALID_PARAMETER;
1059 }
1060
1061 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
1062 (MaximumPacketLength != 32) && (MaximumPacketLength != 64))
1063 {
1064 return EFI_INVALID_PARAMETER;
1065 }
1066
1067 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
1068 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
1069 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512)))
1070 {
1071 return EFI_INVALID_PARAMETER;
1072 }
1073
1074 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
1075
1076 Status = EFI_DEVICE_ERROR;
1077 *TransferResult = EFI_USB_ERR_SYSTEM;
1078
1079 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
1080 EhcAckAllInterrupt (Ehc);
1081 goto ON_EXIT;
1082 }
1083
1084 EhcAckAllInterrupt (Ehc);
1085
1086 //
1087 // Create a new URB, insert it into the asynchronous
1088 // schedule list, then poll the execution status.
1089 //
1090 //
1091 // Encode the direction in address, although default control
1092 // endpoint is bidirectional. EhcCreateUrb expects this
1093 // combination of Ep addr and its direction.
1094 //
1095 Endpoint = (UINT8)(0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
1096 Urb = EhcCreateUrb (
1097 Ehc,
1098 DeviceAddress,
1099 Endpoint,
1100 DeviceSpeed,
1101 0,
1102 MaximumPacketLength,
1103 Translator,
1104 EHC_CTRL_TRANSFER,
1105 Request,
1106 Data,
1107 *DataLength,
1108 NULL,
1109 NULL,
1110 1
1111 );
1112
1113 if (Urb == NULL) {
1114 Status = EFI_OUT_OF_RESOURCES;
1115 goto ON_EXIT;
1116 }
1117
1118 EhcLinkQhToAsync (Ehc, Urb->Qh);
1119 Status = EhcExecTransfer (Ehc, Urb, TimeOut);
1120 EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
1121
1122 //
1123 // Get the status from URB. The result is updated in EhcCheckUrbResult
1124 // which is called by EhcExecTransfer
1125 //
1126 *TransferResult = Urb->Result;
1127 *DataLength = Urb->Completed;
1128
1129 if (*TransferResult == EFI_USB_NOERROR) {
1130 Status = EFI_SUCCESS;
1131 }
1132
1133 EhcAckAllInterrupt (Ehc);
1134 EhcFreeUrb (Ehc, Urb);
1135
1136 ON_EXIT:
1137 return Status;
1138 }
1139
1140 /**
1141 One notified function to stop the Host Controller at the end of PEI
1142
1143 @param[in] PeiServices Pointer to PEI Services Table.
1144 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification event that
1145 caused this function to execute.
1146 @param[in] Ppi Pointer to the PPI data associated with this function.
1147
1148 @retval EFI_SUCCESS The function completes successfully
1149 @retval others
1150 **/
1151 EFI_STATUS
1152 EFIAPI
1153 EhcEndOfPei (
1154 IN EFI_PEI_SERVICES **PeiServices,
1155 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
1156 IN VOID *Ppi
1157 )
1158 {
1159 PEI_USB2_HC_DEV *Ehc;
1160
1161 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_THIS_NOTIFY (NotifyDescriptor);
1162
1163 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
1164
1165 EhcFreeSched (Ehc);
1166
1167 return EFI_SUCCESS;
1168 }
1169
1170 /**
1171 @param FileHandle Handle of the file being invoked.
1172 @param PeiServices Describes the list of possible PEI Services.
1173
1174 @retval EFI_SUCCESS PPI successfully installed.
1175
1176 **/
1177 EFI_STATUS
1178 EFIAPI
1179 EhcPeimEntry (
1180 IN EFI_PEI_FILE_HANDLE FileHandle,
1181 IN CONST EFI_PEI_SERVICES **PeiServices
1182 )
1183 {
1184 PEI_USB_CONTROLLER_PPI *ChipSetUsbControllerPpi;
1185 EFI_STATUS Status;
1186 UINT8 Index;
1187 UINTN ControllerType;
1188 UINTN BaseAddress;
1189 UINTN MemPages;
1190 PEI_USB2_HC_DEV *EhcDev;
1191 EFI_PHYSICAL_ADDRESS TempPtr;
1192
1193 //
1194 // Shadow this PEIM to run from memory
1195 //
1196 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
1197 return EFI_SUCCESS;
1198 }
1199
1200 Status = PeiServicesLocatePpi (
1201 &gPeiUsbControllerPpiGuid,
1202 0,
1203 NULL,
1204 (VOID **)&ChipSetUsbControllerPpi
1205 );
1206 if (EFI_ERROR (Status)) {
1207 return EFI_UNSUPPORTED;
1208 }
1209
1210 Index = 0;
1211 while (TRUE) {
1212 Status = ChipSetUsbControllerPpi->GetUsbController (
1213 (EFI_PEI_SERVICES **)PeiServices,
1214 ChipSetUsbControllerPpi,
1215 Index,
1216 &ControllerType,
1217 &BaseAddress
1218 );
1219 //
1220 // When status is error, meant no controller is found
1221 //
1222 if (EFI_ERROR (Status)) {
1223 break;
1224 }
1225
1226 //
1227 // This PEIM is for UHC type controller.
1228 //
1229 if (ControllerType != PEI_EHCI_CONTROLLER) {
1230 Index++;
1231 continue;
1232 }
1233
1234 MemPages = sizeof (PEI_USB2_HC_DEV) / PAGESIZE + 1;
1235 Status = PeiServicesAllocatePages (
1236 EfiBootServicesCode,
1237 MemPages,
1238 &TempPtr
1239 );
1240 if (EFI_ERROR (Status)) {
1241 return EFI_OUT_OF_RESOURCES;
1242 }
1243
1244 ZeroMem ((VOID *)(UINTN)TempPtr, MemPages*PAGESIZE);
1245 EhcDev = (PEI_USB2_HC_DEV *)((UINTN)TempPtr);
1246
1247 EhcDev->Signature = USB2_HC_DEV_SIGNATURE;
1248
1249 IoMmuInit (&EhcDev->IoMmu);
1250
1251 EhcDev->UsbHostControllerBaseAddress = (UINT32)BaseAddress;
1252
1253 EhcDev->HcStructParams = EhcReadCapRegister (EhcDev, EHC_HCSPARAMS_OFFSET);
1254 EhcDev->HcCapParams = EhcReadCapRegister (EhcDev, EHC_HCCPARAMS_OFFSET);
1255 EhcDev->CapLen = EhcReadCapRegister (EhcDev, EHC_CAPLENGTH_OFFSET) & 0x0FF;
1256 //
1257 // Initialize Uhc's hardware
1258 //
1259 Status = InitializeUsbHC (EhcDev);
1260 if (EFI_ERROR (Status)) {
1261 return Status;
1262 }
1263
1264 EhcDev->Usb2HostControllerPpi.ControlTransfer = EhcControlTransfer;
1265 EhcDev->Usb2HostControllerPpi.BulkTransfer = EhcBulkTransfer;
1266 EhcDev->Usb2HostControllerPpi.GetRootHubPortNumber = EhcGetRootHubPortNumber;
1267 EhcDev->Usb2HostControllerPpi.GetRootHubPortStatus = EhcGetRootHubPortStatus;
1268 EhcDev->Usb2HostControllerPpi.SetRootHubPortFeature = EhcSetRootHubPortFeature;
1269 EhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature = EhcClearRootHubPortFeature;
1270
1271 EhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
1272 EhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;
1273 EhcDev->PpiDescriptor.Ppi = &EhcDev->Usb2HostControllerPpi;
1274
1275 Status = PeiServicesInstallPpi (&EhcDev->PpiDescriptor);
1276 if (EFI_ERROR (Status)) {
1277 Index++;
1278 continue;
1279 }
1280
1281 EhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
1282 EhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;
1283 EhcDev->EndOfPeiNotifyList.Notify = EhcEndOfPei;
1284
1285 PeiServicesNotifyPpi (&EhcDev->EndOfPeiNotifyList);
1286
1287 Index++;
1288 }
1289
1290 return EFI_SUCCESS;
1291 }
1292
1293 /**
1294 @param EhcDev EHCI Device.
1295
1296 @retval EFI_SUCCESS EHCI successfully initialized.
1297 @retval EFI_ABORTED EHCI was failed to be initialized.
1298
1299 **/
1300 EFI_STATUS
1301 InitializeUsbHC (
1302 IN PEI_USB2_HC_DEV *EhcDev
1303 )
1304 {
1305 EFI_STATUS Status;
1306
1307 EhcResetHC (EhcDev, EHC_RESET_TIMEOUT);
1308
1309 Status = EhcInitHC (EhcDev);
1310
1311 if (EFI_ERROR (Status)) {
1312 return EFI_ABORTED;
1313 }
1314
1315 return EFI_SUCCESS;
1316 }