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
13 Read EHCI capability register.
15 @param Ehc The EHCI device.
16 @param Offset Capability register address.
18 @return The register content read.
19 @retval If err, return 0xffff.
31 Status
= Ehc
->PciIo
->Mem
.Read (
40 if (EFI_ERROR (Status
)) {
41 DEBUG ((DEBUG_ERROR
, "EhcReadCapRegister: Pci Io read error - %r at %d\n", Status
, Offset
));
49 Read EHCI debug port register.
51 @param Ehc The EHCI device.
52 @param Offset Debug port register offset.
54 @return The register content read.
55 @retval If err, return 0xffff.
60 IN CONST USB2_HC_DEV
*Ehc
,
67 Status
= Ehc
->PciIo
->Mem
.Read (
71 Ehc
->DebugPortOffset
+ Offset
,
76 if (EFI_ERROR (Status
)) {
77 DEBUG ((DEBUG_ERROR
, "EhcReadDbgRegister: Pci Io read error - %r at %d\n", Status
, Offset
));
85 Check whether the host controller has an in-use debug port.
87 @param[in] Ehc The Enhanced Host Controller to query.
89 @param[in] PortNumber If PortNumber is not NULL, then query whether
90 PortNumber is an in-use debug port on Ehc. (PortNumber
91 is taken in UEFI notation, i.e., zero-based.)
92 Otherwise, query whether Ehc has any in-use debug
95 @retval TRUE PortNumber is an in-use debug port on Ehc (if PortNumber is
96 not NULL), or some port on Ehc is an in-use debug port
99 @retval FALSE PortNumber is not an in-use debug port on Ehc (if PortNumber
100 is not NULL), or no port on Ehc is an in-use debug port
104 EhcIsDebugPortInUse (
105 IN CONST USB2_HC_DEV
*Ehc
,
106 IN CONST UINT8
*PortNumber OPTIONAL
111 if (Ehc
->DebugPortNum
== 0) {
113 // The host controller has no debug port.
119 // The Debug Port Number field in HCSPARAMS is one-based.
121 if ((PortNumber
!= NULL
) && (*PortNumber
!= Ehc
->DebugPortNum
- 1)) {
123 // The caller specified a port, but it's not the debug port of the host
130 // Deduce usage from the Control Register.
132 State
= EhcReadDbgRegister (Ehc
, 0);
133 return (State
& USB_DEBUG_PORT_IN_USE_MASK
) == USB_DEBUG_PORT_IN_USE_MASK
;
137 Read EHCI Operation register.
139 @param Ehc The EHCI device.
140 @param Offset The operation register offset.
142 @return The register content read.
143 @retval If err, return 0xffff.
155 ASSERT (Ehc
->CapLen
!= 0);
157 Status
= Ehc
->PciIo
->Mem
.Read (
161 Ehc
->CapLen
+ Offset
,
166 if (EFI_ERROR (Status
)) {
167 DEBUG ((DEBUG_ERROR
, "EhcReadOpReg: Pci Io Read error - %r at %d\n", Status
, Offset
));
175 Write the data to the EHCI operation register.
177 @param Ehc The EHCI device.
178 @param Offset EHCI operation register offset.
179 @param Data The data to write.
191 ASSERT (Ehc
->CapLen
!= 0);
193 Status
= Ehc
->PciIo
->Mem
.Write (
197 Ehc
->CapLen
+ Offset
,
202 if (EFI_ERROR (Status
)) {
203 DEBUG ((DEBUG_ERROR
, "EhcWriteOpReg: Pci Io Write error: %r at %d\n", Status
, Offset
));
208 Set one bit of the operational register while keeping other bits.
210 @param Ehc The EHCI device.
211 @param Offset The offset of the operational register.
212 @param Bit The bit mask of the register to set.
224 Data
= EhcReadOpReg (Ehc
, Offset
);
226 EhcWriteOpReg (Ehc
, Offset
, Data
);
230 Clear one bit of the operational register while keeping other bits.
232 @param Ehc The EHCI device.
233 @param Offset The offset of the operational register.
234 @param Bit The bit mask of the register to clear.
246 Data
= EhcReadOpReg (Ehc
, Offset
);
248 EhcWriteOpReg (Ehc
, Offset
, Data
);
252 Wait the operation register's bit as specified by Bit
253 to become set (or clear).
255 @param Ehc The EHCI device.
256 @param Offset The offset of the operation register.
257 @param Bit The bit of the register to wait for.
258 @param WaitToSet Wait the bit to set or clear.
259 @param Timeout The time to wait before abort (in millisecond).
261 @retval EFI_SUCCESS The bit successfully changed by host controller.
262 @retval EFI_TIMEOUT The time out occurred.
270 IN BOOLEAN WaitToSet
,
276 for (Index
= 0; Index
< Timeout
/ EHC_SYNC_POLL_INTERVAL
+ 1; Index
++) {
277 if (EHC_REG_BIT_IS_SET (Ehc
, Offset
, Bit
) == WaitToSet
) {
281 gBS
->Stall (EHC_SYNC_POLL_INTERVAL
);
288 Add support for UEFI Over Legacy (UoL) feature, stop
289 the legacy USB SMI support.
291 @param Ehc The EHCI device.
295 EhcClearLegacySupport (
300 EFI_PCI_IO_PROTOCOL
*PciIo
;
304 DEBUG ((DEBUG_INFO
, "EhcClearLegacySupport: called to clear legacy support\n"));
307 ExtendCap
= (Ehc
->HcCapParams
>> 8) & 0xFF;
309 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
310 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
+ 0x4, 1, &Value
);
312 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
313 Value
|= (0x1 << 24);
314 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
317 while (TimeOut
-- != 0) {
320 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
322 if ((Value
& 0x01010000) == 0x01000000) {
327 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
328 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
+ 0x4, 1, &Value
);
332 Set door bell and wait it to be ACKed by host controller.
333 This function is used to synchronize with the hardware.
335 @param Ehc The EHCI device.
336 @param Timeout The time to wait before abort (in millisecond, ms).
338 @retval EFI_SUCCESS Synchronized with the hardware.
339 @retval EFI_TIMEOUT Time out happened while waiting door bell to set.
343 EhcSetAndWaitDoorBell (
351 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_IAAD
);
353 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_IAA
, TRUE
, Timeout
);
356 // ACK the IAA bit in USBSTS register. Make sure other
357 // interrupt bits are not ACKed. These bits are WC (Write Clean).
359 Data
= EhcReadOpReg (Ehc
, EHC_USBSTS_OFFSET
);
360 Data
&= ~USBSTS_INTACK_MASK
;
363 EhcWriteOpReg (Ehc
, EHC_USBSTS_OFFSET
, Data
);
369 Clear all the interrutp status bits, these bits
372 @param Ehc The EHCI device.
380 EhcWriteOpReg (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_INTACK_MASK
);
384 Enable the periodic schedule then wait EHC to
387 @param Ehc The EHCI device.
388 @param Timeout The time to wait before abort (in millisecond, ms).
390 @retval EFI_SUCCESS The periodical schedule is enabled.
391 @retval EFI_TIMEOUT Time out happened while enabling periodic schedule.
395 EhcEnablePeriodSchd (
402 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_ENABLE_PERIOD
);
404 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_PERIOD_ENABLED
, TRUE
, Timeout
);
409 Enable asynchrounous schedule.
411 @param Ehc The EHCI device.
412 @param Timeout Time to wait before abort.
414 @retval EFI_SUCCESS The EHCI asynchronous schedule is enabled.
415 @return Others Failed to enable the asynchronous scheudle.
426 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_ENABLE_ASYNC
);
428 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_ASYNC_ENABLED
, TRUE
, Timeout
);
433 Whether Ehc is halted.
435 @param Ehc The EHCI device.
437 @retval TRUE The controller is halted.
438 @retval FALSE It isn't halted.
446 return EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
);
450 Whether system error occurred.
452 @param Ehc The EHCI device.
454 @return TRUE System error happened.
455 @return FALSE No system error.
463 return EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_SYS_ERROR
);
467 Reset the host controller.
469 @param Ehc The EHCI device.
470 @param Timeout Time to wait before abort (in millisecond, ms).
472 @retval EFI_SUCCESS The host controller is reset.
473 @return Others Failed to reset the host.
485 // Host can only be reset when it is halt. If not so, halt it
487 if (!EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
)) {
488 Status
= EhcHaltHC (Ehc
, Timeout
);
490 if (EFI_ERROR (Status
)) {
495 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RESET
);
496 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RESET
, FALSE
, Timeout
);
501 Halt the host controller.
503 @param Ehc The EHCI device.
504 @param Timeout Time to wait before abort.
506 @retval EFI_SUCCESS The EHCI is halt.
507 @retval EFI_TIMEOUT Failed to halt the controller before Timeout.
518 EhcClearOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RUN
);
519 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
, TRUE
, Timeout
);
526 @param Ehc The EHCI device.
527 @param Timeout Time to wait before abort.
529 @retval EFI_SUCCESS The EHCI is running.
530 @return Others Failed to set the EHCI to run.
541 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RUN
);
542 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
, FALSE
, Timeout
);
547 Initialize the HC hardware.
548 EHCI spec lists the five things to do to initialize the hardware:
549 1. Program CTRLDSSEGMENT
550 2. Set USBINTR to enable interrupts
551 3. Set periodic list base
552 4. Set USBCMD, interrupt threshold, frame list size etc
553 5. Write 1 to CONFIGFLAG to route all ports to EHCI
555 @param Ehc The EHCI device.
557 @return EFI_SUCCESS The EHCI has come out of halt state.
558 @return EFI_TIMEOUT Time out happened.
570 // This ASSERT crashes the BeagleBoard. There is some issue in the USB stack.
571 // This ASSERT needs to be removed so the BeagleBoard will boot. When we fix
572 // the USB stack we can put this ASSERT back in
573 // ASSERT (EhcIsHalt (Ehc));
576 // Allocate the periodic frame and associated memeory
577 // management facilities if not already done.
579 if (Ehc
->PeriodFrame
!= NULL
) {
583 Status
= EhcInitSched (Ehc
);
585 if (EFI_ERROR (Status
)) {
590 // 1. Clear USBINTR to disable all the interrupt. UEFI works by polling
592 EhcWriteOpReg (Ehc
, EHC_USBINTR_OFFSET
, 0);
595 // 2. Start the Host Controller
597 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RUN
);
600 // 3. Power up all ports if EHCI has Port Power Control (PPC) support
602 if (Ehc
->HcStructParams
& HCSP_PPC
) {
603 for (Index
= 0; Index
< (UINT8
)(Ehc
->HcStructParams
& HCSP_NPORTS
); Index
++) {
605 // Do not clear port status bits on initialization. Otherwise devices will
606 // not enumerate properly at startup.
608 RegVal
= EhcReadOpReg (Ehc
, (UINT32
)(EHC_PORT_STAT_OFFSET
+ (4 * Index
)));
609 RegVal
&= ~PORTSC_CHANGE_MASK
;
610 RegVal
|= PORTSC_POWER
;
611 EhcWriteOpReg (Ehc
, (UINT32
)(EHC_PORT_STAT_OFFSET
+ (4 * Index
)), RegVal
);
616 // Wait roothub port power stable
618 gBS
->Stall (EHC_ROOT_PORT_RECOVERY_STALL
);
621 // 4. Set all ports routing to EHC
623 EhcSetOpRegBit (Ehc
, EHC_CONFIG_FLAG_OFFSET
, CONFIGFLAG_ROUTE_EHC
);
625 Status
= EhcEnablePeriodSchd (Ehc
, EHC_GENERIC_TIMEOUT
);
627 if (EFI_ERROR (Status
)) {
628 DEBUG ((DEBUG_ERROR
, "EhcInitHC: failed to enable period schedule\n"));
632 Status
= EhcEnableAsyncSchd (Ehc
, EHC_GENERIC_TIMEOUT
);
634 if (EFI_ERROR (Status
)) {
635 DEBUG ((DEBUG_ERROR
, "EhcInitHC: failed to enable async schedule\n"));