3 The EHCI register operation routines.
5 Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
15 Read EHCI capability register.
17 @param Ehc The EHCI device.
18 @param Offset Capability register address.
20 @return The register content read.
21 @retval If err, return 0xffff.
33 Status
= Ehc
->PciIo
->Mem
.Read (
42 if (EFI_ERROR (Status
)) {
43 DEBUG ((EFI_D_ERROR
, "EhcReadCapRegister: Pci Io read error - %r at %d\n", Status
, Offset
));
51 Read EHCI debug port register.
53 @param Ehc The EHCI device.
54 @param Offset Debug port register offset.
56 @return The register content read.
57 @retval If err, return 0xffff.
62 IN CONST USB2_HC_DEV
*Ehc
,
69 Status
= Ehc
->PciIo
->Mem
.Read (
73 Ehc
->DebugPortOffset
+ Offset
,
78 if (EFI_ERROR (Status
)) {
79 DEBUG ((EFI_D_ERROR
, "EhcReadDbgRegister: Pci Io read error - %r at %d\n", Status
, Offset
));
88 Check whether the host controller has an in-use debug port.
90 @param[in] Ehc The Enhanced Host Controller to query.
92 @param[in] PortNumber If PortNumber is not NULL, then query whether
93 PortNumber is an in-use debug port on Ehc. (PortNumber
94 is taken in UEFI notation, i.e., zero-based.)
95 Otherwise, query whether Ehc has any in-use debug
98 @retval TRUE PortNumber is an in-use debug port on Ehc (if PortNumber is
99 not NULL), or some port on Ehc is an in-use debug port
102 @retval FALSE PortNumber is not an in-use debug port on Ehc (if PortNumber
103 is not NULL), or no port on Ehc is an in-use debug port
107 EhcIsDebugPortInUse (
108 IN CONST USB2_HC_DEV
*Ehc
,
109 IN CONST UINT8
*PortNumber OPTIONAL
114 if (Ehc
->DebugPortNum
== 0) {
116 // The host controller has no debug port.
122 // The Debug Port Number field in HCSPARAMS is one-based.
124 if (PortNumber
!= NULL
&& *PortNumber
!= Ehc
->DebugPortNum
- 1) {
126 // The caller specified a port, but it's not the debug port of the host
133 // Deduce usage from the Control Register.
135 State
= EhcReadDbgRegister(Ehc
, 0);
136 return (State
& USB_DEBUG_PORT_IN_USE_MASK
) == USB_DEBUG_PORT_IN_USE_MASK
;
141 Read EHCI Operation register.
143 @param Ehc The EHCI device.
144 @param Offset The operation register offset.
146 @return The register content read.
147 @retval If err, return 0xffff.
159 ASSERT (Ehc
->CapLen
!= 0);
161 Status
= Ehc
->PciIo
->Mem
.Read (
165 Ehc
->CapLen
+ Offset
,
170 if (EFI_ERROR (Status
)) {
171 DEBUG ((EFI_D_ERROR
, "EhcReadOpReg: Pci Io Read error - %r at %d\n", Status
, Offset
));
180 Write the data to the EHCI operation register.
182 @param Ehc The EHCI device.
183 @param Offset EHCI operation register offset.
184 @param Data The data to write.
196 ASSERT (Ehc
->CapLen
!= 0);
198 Status
= Ehc
->PciIo
->Mem
.Write (
202 Ehc
->CapLen
+ Offset
,
207 if (EFI_ERROR (Status
)) {
208 DEBUG ((EFI_D_ERROR
, "EhcWriteOpReg: Pci Io Write error: %r at %d\n", Status
, Offset
));
214 Set one bit of the operational register while keeping other bits.
216 @param Ehc The EHCI device.
217 @param Offset The offset of the operational register.
218 @param Bit The bit mask of the register to set.
230 Data
= EhcReadOpReg (Ehc
, Offset
);
232 EhcWriteOpReg (Ehc
, Offset
, Data
);
237 Clear one bit of the operational register while keeping other bits.
239 @param Ehc The EHCI device.
240 @param Offset The offset of the operational register.
241 @param Bit The bit mask of the register to clear.
253 Data
= EhcReadOpReg (Ehc
, Offset
);
255 EhcWriteOpReg (Ehc
, Offset
, Data
);
260 Wait the operation register's bit as specified by Bit
261 to become set (or clear).
263 @param Ehc The EHCI device.
264 @param Offset The offset of the operation register.
265 @param Bit The bit of the register to wait for.
266 @param WaitToSet Wait the bit to set or clear.
267 @param Timeout The time to wait before abort (in millisecond).
269 @retval EFI_SUCCESS The bit successfully changed by host controller.
270 @retval EFI_TIMEOUT The time out occurred.
278 IN BOOLEAN WaitToSet
,
284 for (Index
= 0; Index
< Timeout
/ EHC_SYNC_POLL_INTERVAL
+ 1; Index
++) {
285 if (EHC_REG_BIT_IS_SET (Ehc
, Offset
, Bit
) == WaitToSet
) {
289 gBS
->Stall (EHC_SYNC_POLL_INTERVAL
);
297 Add support for UEFI Over Legacy (UoL) feature, stop
298 the legacy USB SMI support.
300 @param Ehc The EHCI device.
304 EhcClearLegacySupport (
309 EFI_PCI_IO_PROTOCOL
*PciIo
;
313 DEBUG ((EFI_D_INFO
, "EhcClearLegacySupport: called to clear legacy support\n"));
316 ExtendCap
= (Ehc
->HcCapParams
>> 8) & 0xFF;
318 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
319 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
+ 0x4, 1, &Value
);
321 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
322 Value
|= (0x1 << 24);
323 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
326 while (TimeOut
-- != 0) {
329 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
331 if ((Value
& 0x01010000) == 0x01000000) {
336 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
337 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
+ 0x4, 1, &Value
);
343 Set door bell and wait it to be ACKed by host controller.
344 This function is used to synchronize with the hardware.
346 @param Ehc The EHCI device.
347 @param Timeout The time to wait before abort (in millisecond, ms).
349 @retval EFI_SUCCESS Synchronized with the hardware.
350 @retval EFI_TIMEOUT Time out happened while waiting door bell to set.
354 EhcSetAndWaitDoorBell (
362 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_IAAD
);
364 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_IAA
, TRUE
, Timeout
);
367 // ACK the IAA bit in USBSTS register. Make sure other
368 // interrupt bits are not ACKed. These bits are WC (Write Clean).
370 Data
= EhcReadOpReg (Ehc
, EHC_USBSTS_OFFSET
);
371 Data
&= ~USBSTS_INTACK_MASK
;
374 EhcWriteOpReg (Ehc
, EHC_USBSTS_OFFSET
, Data
);
381 Clear all the interrutp status bits, these bits
384 @param Ehc The EHCI device.
392 EhcWriteOpReg (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_INTACK_MASK
);
397 Enable the periodic schedule then wait EHC to
400 @param Ehc The EHCI device.
401 @param Timeout The time to wait before abort (in millisecond, ms).
403 @retval EFI_SUCCESS The periodical schedule is enabled.
404 @retval EFI_TIMEOUT Time out happened while enabling periodic schedule.
408 EhcEnablePeriodSchd (
415 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_ENABLE_PERIOD
);
417 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_PERIOD_ENABLED
, TRUE
, Timeout
);
427 Enable asynchrounous schedule.
429 @param Ehc The EHCI device.
430 @param Timeout Time to wait before abort.
432 @retval EFI_SUCCESS The EHCI asynchronous schedule is enabled.
433 @return Others Failed to enable the asynchronous scheudle.
444 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_ENABLE_ASYNC
);
446 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_ASYNC_ENABLED
, TRUE
, Timeout
);
457 Whether Ehc is halted.
459 @param Ehc The EHCI device.
461 @retval TRUE The controller is halted.
462 @retval FALSE It isn't halted.
470 return EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
);
475 Whether system error occurred.
477 @param Ehc The EHCI device.
479 @return TRUE System error happened.
480 @return FALSE No system error.
488 return EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_SYS_ERROR
);
493 Reset the host controller.
495 @param Ehc The EHCI device.
496 @param Timeout Time to wait before abort (in millisecond, ms).
498 @retval EFI_SUCCESS The host controller is reset.
499 @return Others Failed to reset the host.
511 // Host can only be reset when it is halt. If not so, halt it
513 if (!EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
)) {
514 Status
= EhcHaltHC (Ehc
, Timeout
);
516 if (EFI_ERROR (Status
)) {
521 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RESET
);
522 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RESET
, FALSE
, Timeout
);
528 Halt the host controller.
530 @param Ehc The EHCI device.
531 @param Timeout Time to wait before abort.
533 @retval EFI_SUCCESS The EHCI is halt.
534 @retval EFI_TIMEOUT Failed to halt the controller before Timeout.
545 EhcClearOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RUN
);
546 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
, TRUE
, Timeout
);
554 @param Ehc The EHCI device.
555 @param Timeout Time to wait before abort.
557 @retval EFI_SUCCESS The EHCI is running.
558 @return Others Failed to set the EHCI to run.
569 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RUN
);
570 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
, FALSE
, Timeout
);
576 Initialize the HC hardware.
577 EHCI spec lists the five things to do to initialize the hardware:
578 1. Program CTRLDSSEGMENT
579 2. Set USBINTR to enable interrupts
580 3. Set periodic list base
581 4. Set USBCMD, interrupt threshold, frame list size etc
582 5. Write 1 to CONFIGFLAG to route all ports to EHCI
584 @param Ehc The EHCI device.
586 @return EFI_SUCCESS The EHCI has come out of halt state.
587 @return EFI_TIMEOUT Time out happened.
599 // This ASSERT crashes the BeagleBoard. There is some issue in the USB stack.
600 // This ASSERT needs to be removed so the BeagleBoard will boot. When we fix
601 // the USB stack we can put this ASSERT back in
602 // ASSERT (EhcIsHalt (Ehc));
605 // Allocate the periodic frame and associated memeory
606 // management facilities if not already done.
608 if (Ehc
->PeriodFrame
!= NULL
) {
612 Status
= EhcInitSched (Ehc
);
614 if (EFI_ERROR (Status
)) {
619 // 1. Clear USBINTR to disable all the interrupt. UEFI works by polling
621 EhcWriteOpReg (Ehc
, EHC_USBINTR_OFFSET
, 0);
624 // 2. Start the Host Controller
626 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RUN
);
629 // 3. Power up all ports if EHCI has Port Power Control (PPC) support
631 if (Ehc
->HcStructParams
& HCSP_PPC
) {
632 for (Index
= 0; Index
< (UINT8
) (Ehc
->HcStructParams
& HCSP_NPORTS
); Index
++) {
634 // Do not clear port status bits on initialization. Otherwise devices will
635 // not enumerate properly at startup.
637 RegVal
= EhcReadOpReg(Ehc
, (UINT32
)(EHC_PORT_STAT_OFFSET
+ (4 * Index
)));
638 RegVal
&= ~PORTSC_CHANGE_MASK
;
639 RegVal
|= PORTSC_POWER
;
640 EhcWriteOpReg (Ehc
, (UINT32
) (EHC_PORT_STAT_OFFSET
+ (4 * Index
)), RegVal
);
645 // Wait roothub port power stable
647 gBS
->Stall (EHC_ROOT_PORT_RECOVERY_STALL
);
650 // 4. Set all ports routing to EHC
652 EhcSetOpRegBit (Ehc
, EHC_CONFIG_FLAG_OFFSET
, CONFIGFLAG_ROUTE_EHC
);
654 Status
= EhcEnablePeriodSchd (Ehc
, EHC_GENERIC_TIMEOUT
);
656 if (EFI_ERROR (Status
)) {
657 DEBUG ((EFI_D_ERROR
, "EhcInitHC: failed to enable period schedule\n"));
661 Status
= EhcEnableAsyncSchd (Ehc
, EHC_GENERIC_TIMEOUT
);
663 if (EFI_ERROR (Status
)) {
664 DEBUG ((EFI_D_ERROR
, "EhcInitHC: failed to enable async schedule\n"));