3 The EHCI register operation routines.
5 Copyright (c) 2007 - 2012, 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.
75 Status
= Ehc
->PciIo
->Mem
.Read (
79 (UINT64
) (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 Read EHCI Operation register.
96 @param Ehc The EHCI device.
97 @param Offset The operation register offset.
99 @return The register content read.
100 @retval If err, return 0xffff.
112 ASSERT (Ehc
->CapLen
!= 0);
114 Status
= Ehc
->PciIo
->Mem
.Read (
118 (UINT64
) (Ehc
->CapLen
+ Offset
),
123 if (EFI_ERROR (Status
)) {
124 DEBUG ((EFI_D_ERROR
, "EhcReadOpReg: Pci Io Read error - %r at %d\n", Status
, Offset
));
133 Write the data to the EHCI operation register.
135 @param Ehc The EHCI device.
136 @param Offset EHCI operation register offset.
137 @param Data The data to write.
149 ASSERT (Ehc
->CapLen
!= 0);
151 Status
= Ehc
->PciIo
->Mem
.Write (
155 (UINT64
) (Ehc
->CapLen
+ Offset
),
160 if (EFI_ERROR (Status
)) {
161 DEBUG ((EFI_D_ERROR
, "EhcWriteOpReg: Pci Io Write error: %r at %d\n", Status
, Offset
));
167 Set one bit of the operational register while keeping other bits.
169 @param Ehc The EHCI device.
170 @param Offset The offset of the operational register.
171 @param Bit The bit mask of the register to set.
183 Data
= EhcReadOpReg (Ehc
, Offset
);
185 EhcWriteOpReg (Ehc
, Offset
, Data
);
190 Clear one bit of the operational register while keeping other bits.
192 @param Ehc The EHCI device.
193 @param Offset The offset of the operational register.
194 @param Bit The bit mask of the register to clear.
206 Data
= EhcReadOpReg (Ehc
, Offset
);
208 EhcWriteOpReg (Ehc
, Offset
, Data
);
213 Wait the operation register's bit as specified by Bit
214 to become set (or clear).
216 @param Ehc The EHCI device.
217 @param Offset The offset of the operation register.
218 @param Bit The bit of the register to wait for.
219 @param WaitToSet Wait the bit to set or clear.
220 @param Timeout The time to wait before abort (in millisecond).
222 @retval EFI_SUCCESS The bit successfully changed by host controller.
223 @retval EFI_TIMEOUT The time out occurred.
231 IN BOOLEAN WaitToSet
,
237 for (Index
= 0; Index
< Timeout
/ EHC_SYNC_POLL_INTERVAL
+ 1; Index
++) {
238 if (EHC_REG_BIT_IS_SET (Ehc
, Offset
, Bit
) == WaitToSet
) {
242 gBS
->Stall (EHC_SYNC_POLL_INTERVAL
);
250 Add support for UEFI Over Legacy (UoL) feature, stop
251 the legacy USB SMI support.
253 @param Ehc The EHCI device.
257 EhcClearLegacySupport (
262 EFI_PCI_IO_PROTOCOL
*PciIo
;
266 DEBUG ((EFI_D_INFO
, "EhcClearLegacySupport: called to clear legacy support\n"));
269 ExtendCap
= (Ehc
->HcCapParams
>> 8) & 0xFF;
271 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
272 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
+ 0x4, 1, &Value
);
274 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
275 Value
|= (0x1 << 24);
276 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
279 while (TimeOut
-- != 0) {
282 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
284 if ((Value
& 0x01010000) == 0x01000000) {
289 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
, 1, &Value
);
290 PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, ExtendCap
+ 0x4, 1, &Value
);
296 Set door bell and wait it to be ACKed by host controller.
297 This function is used to synchronize with the hardware.
299 @param Ehc The EHCI device.
300 @param Timeout The time to wait before abort (in millisecond, ms).
302 @retval EFI_SUCCESS Synchronized with the hardware.
303 @retval EFI_TIMEOUT Time out happened while waiting door bell to set.
307 EhcSetAndWaitDoorBell (
315 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_IAAD
);
317 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_IAA
, TRUE
, Timeout
);
320 // ACK the IAA bit in USBSTS register. Make sure other
321 // interrupt bits are not ACKed. These bits are WC (Write Clean).
323 Data
= EhcReadOpReg (Ehc
, EHC_USBSTS_OFFSET
);
324 Data
&= ~USBSTS_INTACK_MASK
;
327 EhcWriteOpReg (Ehc
, EHC_USBSTS_OFFSET
, Data
);
334 Clear all the interrutp status bits, these bits
337 @param Ehc The EHCI device.
345 EhcWriteOpReg (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_INTACK_MASK
);
350 Enable the periodic schedule then wait EHC to
353 @param Ehc The EHCI device.
354 @param Timeout The time to wait before abort (in millisecond, ms).
356 @retval EFI_SUCCESS The periodical schedule is enabled.
357 @retval EFI_TIMEOUT Time out happened while enabling periodic schedule.
361 EhcEnablePeriodSchd (
368 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_ENABLE_PERIOD
);
370 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_PERIOD_ENABLED
, TRUE
, Timeout
);
376 Disable periodic schedule.
378 @param Ehc The EHCI device.
379 @param Timeout Time to wait before abort (in millisecond, ms).
381 @retval EFI_SUCCESS Periodic schedule is disabled.
382 @retval EFI_DEVICE_ERROR Fail to disable periodic schedule.
386 EhcDisablePeriodSchd (
393 EhcClearOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_ENABLE_PERIOD
);
395 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_PERIOD_ENABLED
, FALSE
, Timeout
);
402 Enable asynchrounous schedule.
404 @param Ehc The EHCI device.
405 @param Timeout Time to wait before abort.
407 @retval EFI_SUCCESS The EHCI asynchronous schedule is enabled.
408 @return Others Failed to enable the asynchronous scheudle.
419 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_ENABLE_ASYNC
);
421 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_ASYNC_ENABLED
, TRUE
, Timeout
);
428 Disable asynchrounous schedule.
430 @param Ehc The EHCI device.
431 @param Timeout Time to wait before abort (in millisecond, ms).
433 @retval EFI_SUCCESS The asynchronous schedule is disabled.
434 @return Others Failed to disable the asynchronous schedule.
438 EhcDisableAsyncSchd (
445 EhcClearOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_ENABLE_ASYNC
);
447 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_ASYNC_ENABLED
, FALSE
, Timeout
);
454 Whether Ehc is halted.
456 @param Ehc The EHCI device.
458 @retval TRUE The controller is halted.
459 @retval FALSE It isn't halted.
467 return EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
);
472 Whether system error occurred.
474 @param Ehc The EHCI device.
476 @return TRUE System error happened.
477 @return FALSE No system error.
485 return EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_SYS_ERROR
);
490 Reset the host controller.
492 @param Ehc The EHCI device.
493 @param Timeout Time to wait before abort (in millisecond, ms).
495 @retval EFI_SUCCESS The host controller is reset.
496 @return Others Failed to reset the host.
508 // Host can only be reset when it is halt. If not so, halt it
510 if (!EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
)) {
511 Status
= EhcHaltHC (Ehc
, Timeout
);
513 if (EFI_ERROR (Status
)) {
518 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RESET
);
519 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RESET
, FALSE
, Timeout
);
525 Halt the host controller.
527 @param Ehc The EHCI device.
528 @param Timeout Time to wait before abort.
530 @retval EFI_SUCCESS The EHCI is halt.
531 @retval EFI_TIMEOUT Failed to halt the controller before Timeout.
542 EhcClearOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RUN
);
543 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
, TRUE
, Timeout
);
551 @param Ehc The EHCI device.
552 @param Timeout Time to wait before abort.
554 @retval EFI_SUCCESS The EHCI is running.
555 @return Others Failed to set the EHCI to run.
566 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RUN
);
567 Status
= EhcWaitOpRegBit (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
, FALSE
, Timeout
);
573 Initialize the HC hardware.
574 EHCI spec lists the five things to do to initialize the hardware:
575 1. Program CTRLDSSEGMENT
576 2. Set USBINTR to enable interrupts
577 3. Set periodic list base
578 4. Set USBCMD, interrupt threshold, frame list size etc
579 5. Write 1 to CONFIGFLAG to route all ports to EHCI
581 @param Ehc The EHCI device.
583 @return EFI_SUCCESS The EHCI has come out of halt state.
584 @return EFI_TIMEOUT Time out happened.
595 // This ASSERT crashes the BeagleBoard. There is some issue in the USB stack.
596 // This ASSERT needs to be removed so the BeagleBoard will boot. When we fix
597 // the USB stack we can put this ASSERT back in
598 // ASSERT (EhcIsHalt (Ehc));
601 // Allocate the periodic frame and associated memeory
602 // management facilities if not already done.
604 if (Ehc
->PeriodFrame
!= NULL
) {
608 Status
= EhcInitSched (Ehc
);
610 if (EFI_ERROR (Status
)) {
615 // 1. Clear USBINTR to disable all the interrupt. UEFI works by polling
617 EhcWriteOpReg (Ehc
, EHC_USBINTR_OFFSET
, 0);
620 // 2. Start the Host Controller
622 EhcSetOpRegBit (Ehc
, EHC_USBCMD_OFFSET
, USBCMD_RUN
);
625 // 3. Power up all ports if EHCI has Port Power Control (PPC) support
627 if (Ehc
->HcStructParams
& HCSP_PPC
) {
628 for (Index
= 0; Index
< (UINT8
) (Ehc
->HcStructParams
& HCSP_NPORTS
); Index
++) {
629 EhcSetOpRegBit (Ehc
, (UINT32
) (EHC_PORT_STAT_OFFSET
+ (4 * Index
)), PORTSC_POWER
);
634 // Wait roothub port power stable
636 gBS
->Stall (EHC_ROOT_PORT_RECOVERY_STALL
);
639 // 4. Set all ports routing to EHC
641 EhcSetOpRegBit (Ehc
, EHC_CONFIG_FLAG_OFFSET
, CONFIGFLAG_ROUTE_EHC
);
643 Status
= EhcEnablePeriodSchd (Ehc
, EHC_GENERIC_TIMEOUT
);
645 if (EFI_ERROR (Status
)) {
646 DEBUG ((EFI_D_ERROR
, "EhcInitHC: failed to enable period schedule\n"));
650 Status
= EhcEnableAsyncSchd (Ehc
, EHC_GENERIC_TIMEOUT
);
652 if (EFI_ERROR (Status
)) {
653 DEBUG ((EFI_D_ERROR
, "EhcInitHC: failed to enable async schedule\n"));