3 The EHCI register operation routines.
5 Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 Read EHCI capability register.
23 @param Ehc The EHCI device.
24 @param Offset Capability register address.
26 @return The register content read.
27 @retval If err, return 0xffff.
39 Status
= Ehc
->PciIo
->Mem
.Read (
48 if (EFI_ERROR (Status
)) {
49 DEBUG ((EFI_D_ERROR
, "EhcReadCapRegister: Pci Io read error - %r at %d\n", Status
, Offset
));
57 Read EHCI debug port register.
59 @param Ehc The EHCI device.
60 @param Offset Debug port register offset.
62 @return The register content read.
63 @retval If err, return 0xffff.
68 IN CONST USB2_HC_DEV
*Ehc
,
75 Status
= Ehc
->PciIo
->Mem
.Read (
79 Ehc
->DebugPortOffset
+ Offset
,
84 if (EFI_ERROR (Status
)) {
85 DEBUG ((EFI_D_ERROR
, "EhcReadDbgRegister: Pci Io read error - %r at %d\n", Status
, Offset
));
94 Check whether the host controller has an in-use debug port.
96 @param[in] Ehc The Enhanced Host Controller to query.
98 @param[in] PortNumber If PortNumber is not NULL, then query whether
99 PortNumber is an in-use debug port on Ehc. (PortNumber
100 is taken in UEFI notation, i.e., zero-based.)
101 Otherwise, query whether Ehc has any in-use debug
104 @retval TRUE PortNumber is an in-use debug port on Ehc (if PortNumber is
105 not NULL), or some port on Ehc is an in-use debug port
108 @retval FALSE PortNumber is not an in-use debug port on Ehc (if PortNumber
109 is not NULL), or no port on Ehc is an in-use debug port
113 EhcIsDebugPortInUse (
114 IN CONST USB2_HC_DEV
*Ehc
,
115 IN CONST UINT8
*PortNumber OPTIONAL
120 if (Ehc
->DebugPortNum
== 0) {
122 // The host controller has no debug port.
128 // The Debug Port Number field in HCSPARAMS is one-based.
130 if (PortNumber
!= NULL
&& *PortNumber
!= Ehc
->DebugPortNum
- 1) {
132 // The caller specified a port, but it's not the debug port of the host
139 // Deduce usage from the Control Register.
141 State
= EhcReadDbgRegister(Ehc
, 0);
142 return (State
& USB_DEBUG_PORT_IN_USE_MASK
) == USB_DEBUG_PORT_IN_USE_MASK
;
147 Read EHCI Operation register.
149 @param Ehc The EHCI device.
150 @param Offset The operation register offset.
152 @return The register content read.
153 @retval If err, return 0xffff.
165 ASSERT (Ehc
->CapLen
!= 0);
167 Status
= Ehc
->PciIo
->Mem
.Read (
171 Ehc
->CapLen
+ Offset
,
176 if (EFI_ERROR (Status
)) {
177 DEBUG ((EFI_D_ERROR
, "EhcReadOpReg: Pci Io Read error - %r at %d\n", Status
, Offset
));
186 Write the data to the EHCI operation register.
188 @param Ehc The EHCI device.
189 @param Offset EHCI operation register offset.
190 @param Data The data to write.
202 ASSERT (Ehc
->CapLen
!= 0);
204 Status
= Ehc
->PciIo
->Mem
.Write (
208 Ehc
->CapLen
+ Offset
,
213 if (EFI_ERROR (Status
)) {
214 DEBUG ((EFI_D_ERROR
, "EhcWriteOpReg: Pci Io Write error: %r at %d\n", Status
, Offset
));
220 Set one bit of the operational register while keeping other bits.
222 @param Ehc The EHCI device.
223 @param Offset The offset of the operational register.
224 @param Bit The bit mask of the register to set.
236 Data
= EhcReadOpReg (Ehc
, Offset
);
238 EhcWriteOpReg (Ehc
, Offset
, Data
);
243 Clear one bit of the operational register while keeping other bits.
245 @param Ehc The EHCI device.
246 @param Offset The offset of the operational register.
247 @param Bit The bit mask of the register to clear.
259 Data
= EhcReadOpReg (Ehc
, Offset
);
261 EhcWriteOpReg (Ehc
, Offset
, Data
);
266 Wait the operation register's bit as specified by Bit
267 to become set (or clear).
269 @param Ehc The EHCI device.
270 @param Offset The offset of the operation register.
271 @param Bit The bit of the register to wait for.
272 @param WaitToSet Wait the bit to set or clear.
273 @param Timeout The time to wait before abort (in millisecond).
275 @retval EFI_SUCCESS The bit successfully changed by host controller.
276 @retval EFI_TIMEOUT The time out occurred.
284 IN BOOLEAN WaitToSet
,
290 for (Index
= 0; Index
< Timeout
/ EHC_SYNC_POLL_INTERVAL
+ 1; Index
++) {
291 if (EHC_REG_BIT_IS_SET (Ehc
, Offset
, Bit
) == WaitToSet
) {
295 gBS
->Stall (EHC_SYNC_POLL_INTERVAL
);
303 Add support for UEFI Over Legacy (UoL) feature, stop
304 the legacy USB SMI support.
306 @param Ehc The EHCI device.
310 EhcClearLegacySupport (
315 EFI_PCI_IO_PROTOCOL
*PciIo
;
319 DEBUG ((EFI_D_INFO
, "EhcClearLegacySupport: called to clear legacy support\n"));
322 ExtendCap
= (Ehc
->HcCapParams
>> 8) & 0xFF;
324 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
325 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
+ 0x4, 1, &Value
);
327 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
328 Value
|= (0x1 << 24);
329 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
332 while (TimeOut
-- != 0) {
335 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
337 if ((Value
& 0x01010000) == 0x01000000) {
342 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
343 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
+ 0x4, 1, &Value
);
349 Set door bell and wait it to be ACKed by host controller.
350 This function is used to synchronize with the hardware.
352 @param Ehc The EHCI device.
353 @param Timeout The time to wait before abort (in millisecond, ms).
355 @retval EFI_SUCCESS Synchronized with the hardware.
356 @retval EFI_TIMEOUT Time out happened while waiting door bell to set.
360 EhcSetAndWaitDoorBell (
368 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_IAAD
);
370 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_IAA
, TRUE
, Timeout
);
373 // ACK the IAA bit in USBSTS register. Make sure other
374 // interrupt bits are not ACKed. These bits are WC (Write Clean).
376 Data
= EhcReadOpReg (Ehc
, EHC_USBSTS_OFFSET
);
377 Data
&= ~USBSTS_INTACK_MASK
;
380 EhcWriteOpReg (Ehc
, EHC_USBSTS_OFFSET
, Data
);
387 Clear all the interrutp status bits, these bits
390 @param Ehc The EHCI device.
398 EhcWriteOpReg (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_INTACK_MASK
);
403 Enable the periodic schedule then wait EHC to
406 @param Ehc The EHCI device.
407 @param Timeout The time to wait before abort (in millisecond, ms).
409 @retval EFI_SUCCESS The periodical schedule is enabled.
410 @retval EFI_TIMEOUT Time out happened while enabling periodic schedule.
414 EhcEnablePeriodSchd (
421 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_ENABLE_PERIOD
);
423 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_PERIOD_ENABLED
, TRUE
, Timeout
);
433 Enable asynchrounous schedule.
435 @param Ehc The EHCI device.
436 @param Timeout Time to wait before abort.
438 @retval EFI_SUCCESS The EHCI asynchronous schedule is enabled.
439 @return Others Failed to enable the asynchronous scheudle.
450 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_ENABLE_ASYNC
);
452 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_ASYNC_ENABLED
, TRUE
, Timeout
);
463 Whether Ehc is halted.
465 @param Ehc The EHCI device.
467 @retval TRUE The controller is halted.
468 @retval FALSE It isn't halted.
476 return EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
);
481 Whether system error occurred.
483 @param Ehc The EHCI device.
485 @return TRUE System error happened.
486 @return FALSE No system error.
494 return EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_SYS_ERROR
);
499 Reset the host controller.
501 @param Ehc The EHCI device.
502 @param Timeout Time to wait before abort (in millisecond, ms).
504 @retval EFI_SUCCESS The host controller is reset.
505 @return Others Failed to reset the host.
517 // Host can only be reset when it is halt. If not so, halt it
519 if (!EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
)) {
520 Status
= EhcHaltHC (Ehc
, Timeout
);
522 if (EFI_ERROR (Status
)) {
527 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RESET
);
528 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RESET
, FALSE
, Timeout
);
534 Halt the host controller.
536 @param Ehc The EHCI device.
537 @param Timeout Time to wait before abort.
539 @retval EFI_SUCCESS The EHCI is halt.
540 @retval EFI_TIMEOUT Failed to halt the controller before Timeout.
551 EhcClearOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RUN
);
552 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
, TRUE
, Timeout
);
560 @param Ehc The EHCI device.
561 @param Timeout Time to wait before abort.
563 @retval EFI_SUCCESS The EHCI is running.
564 @return Others Failed to set the EHCI to run.
575 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RUN
);
576 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
, FALSE
, Timeout
);
582 Initialize the HC hardware.
583 EHCI spec lists the five things to do to initialize the hardware:
584 1. Program CTRLDSSEGMENT
585 2. Set USBINTR to enable interrupts
586 3. Set periodic list base
587 4. Set USBCMD, interrupt threshold, frame list size etc
588 5. Write 1 to CONFIGFLAG to route all ports to EHCI
590 @param Ehc The EHCI device.
592 @return EFI_SUCCESS The EHCI has come out of halt state.
593 @return EFI_TIMEOUT Time out happened.
605 // This ASSERT crashes the BeagleBoard. There is some issue in the USB stack.
606 // This ASSERT needs to be removed so the BeagleBoard will boot. When we fix
607 // the USB stack we can put this ASSERT back in
608 // ASSERT (EhcIsHalt (Ehc));
611 // Allocate the periodic frame and associated memeory
612 // management facilities if not already done.
614 if (Ehc
->PeriodFrame
!= NULL
) {
618 Status
= EhcInitSched (Ehc
);
620 if (EFI_ERROR (Status
)) {
625 // 1. Clear USBINTR to disable all the interrupt. UEFI works by polling
627 EhcWriteOpReg (Ehc
, EHC_USBINTR_OFFSET
, 0);
630 // 2. Start the Host Controller
632 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RUN
);
635 // 3. Power up all ports if EHCI has Port Power Control (PPC) support
637 if (Ehc
->HcStructParams
& HCSP_PPC
) {
638 for (Index
= 0; Index
< (UINT8
) (Ehc
->HcStructParams
& HCSP_NPORTS
); Index
++) {
640 // Do not clear port status bits on initialization. Otherwise devices will
641 // not enumerate properly at startup.
643 RegVal
= EhcReadOpReg(Ehc
, (UINT32
)(EHC_PORT_STAT_OFFSET
+ (4 * Index
)));
644 RegVal
&= ~PORTSC_CHANGE_MASK
;
645 RegVal
|= PORTSC_POWER
;
646 EhcWriteOpReg (Ehc
, (UINT32
) (EHC_PORT_STAT_OFFSET
+ (4 * Index
)), RegVal
);
651 // Wait roothub port power stable
653 gBS
->Stall (EHC_ROOT_PORT_RECOVERY_STALL
);
656 // 4. Set all ports routing to EHC
658 EhcSetOpRegBit (Ehc
, EHC_CONFIG_FLAG_OFFSET
, CONFIGFLAG_ROUTE_EHC
);
660 Status
= EhcEnablePeriodSchd (Ehc
, EHC_GENERIC_TIMEOUT
);
662 if (EFI_ERROR (Status
)) {
663 DEBUG ((EFI_D_ERROR
, "EhcInitHC: failed to enable period schedule\n"));
667 Status
= EhcEnableAsyncSchd (Ehc
, EHC_GENERIC_TIMEOUT
);
669 if (EFI_ERROR (Status
)) {
670 DEBUG ((EFI_D_ERROR
, "EhcInitHC: failed to enable async schedule\n"));