mirror of https://github.com/acidanthera/audk.git
1731 lines
29 KiB
C
1731 lines
29 KiB
C
/*++
|
|
|
|
Copyright (c) 2006, Intel Corporation
|
|
All rights reserved. This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
Module Name:
|
|
|
|
Ehchlp.c
|
|
|
|
Abstract:
|
|
|
|
|
|
Revision History
|
|
--*/
|
|
|
|
#include "Ehci.h"
|
|
|
|
|
|
VOID
|
|
HostReset (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
{
|
|
UINT32 Value;
|
|
UINT32 TimeOut;
|
|
|
|
ReadEhcOperationalReg (
|
|
HcDev,
|
|
USBCMD,
|
|
&Value
|
|
);
|
|
|
|
Value = Value & (~USBCMD_RS);
|
|
WriteEhcOperationalReg (
|
|
HcDev,
|
|
USBCMD,
|
|
Value
|
|
);
|
|
|
|
TimeOut = 40;
|
|
while (TimeOut --) {
|
|
gBS->Stall (500);
|
|
ReadEhcOperationalReg (
|
|
HcDev,
|
|
USBSTS,
|
|
&Value
|
|
);
|
|
if ((Value & USBSTS_HCH) != 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (TimeOut == 0) {
|
|
DEBUG((gEHCErrorLevel, "TimeOut for clearing Run/Stop bit\n"));
|
|
}
|
|
|
|
ReadEhcOperationalReg (
|
|
HcDev,
|
|
USBCMD,
|
|
&Value
|
|
);
|
|
Value = Value | USBCMD_HCRESET;
|
|
WriteEhcOperationalReg (
|
|
HcDev,
|
|
USBCMD,
|
|
Value
|
|
);
|
|
|
|
TimeOut = 40;
|
|
while (TimeOut --) {
|
|
gBS->Stall (500);
|
|
ReadEhcOperationalReg (
|
|
HcDev,
|
|
USBCMD,
|
|
&Value
|
|
);
|
|
if ((Value & USBCMD_HCRESET) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (TimeOut == 0) {
|
|
DEBUG((gEHCErrorLevel, "TimeOut for Host Reset\n"));
|
|
}
|
|
|
|
}
|
|
|
|
EFI_STATUS
|
|
ReadEhcCapabiltiyReg (
|
|
IN USB2_HC_DEV *HcDev,
|
|
IN UINT32 CapabiltiyRegAddr,
|
|
IN OUT UINT32 *Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read Ehc Capabitlity register
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
CapabiltiyRegAddr - Ehc Capability register address
|
|
Data - A pointer to data read from register
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
return HcDev->PciIo->Mem.Read (
|
|
HcDev->PciIo,
|
|
EfiPciIoWidthUint32,
|
|
USB_BAR_INDEX,
|
|
(UINT64) CapabiltiyRegAddr,
|
|
1,
|
|
Data
|
|
);
|
|
}
|
|
|
|
EFI_STATUS
|
|
ReadEhcOperationalReg (
|
|
IN USB2_HC_DEV *HcDev,
|
|
IN UINT32 OperationalRegAddr,
|
|
IN OUT UINT32 *Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read Ehc Operation register
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
OperationalRegAddr - Ehc Operation register address
|
|
Data - A pointer to data read from register
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
ASSERT (HcDev->UsbCapabilityLen);
|
|
return HcDev->PciIo->Mem.Read (
|
|
HcDev->PciIo,
|
|
EfiPciIoWidthUint32,
|
|
USB_BAR_INDEX,
|
|
(UINT64) (OperationalRegAddr + HcDev->UsbCapabilityLen),
|
|
1,
|
|
Data
|
|
);
|
|
}
|
|
|
|
EFI_STATUS
|
|
WriteEhcOperationalReg (
|
|
IN USB2_HC_DEV *HcDev,
|
|
IN UINT32 OperationalRegAddr,
|
|
IN UINT32 Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write Ehc Operation register
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
OperationalRegAddr - Ehc Operation register address
|
|
Data - 32bit write to register
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
ASSERT (HcDev->UsbCapabilityLen);
|
|
return HcDev->PciIo->Mem.Write (
|
|
HcDev->PciIo,
|
|
EfiPciIoWidthUint32,
|
|
USB_BAR_INDEX,
|
|
(UINT64) (OperationalRegAddr + HcDev->UsbCapabilityLen),
|
|
1,
|
|
&Data
|
|
);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
ClearLegacySupport (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stop the legacy USB SMI
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
UINT32 EECP;
|
|
UINT32 Value;
|
|
UINT32 TimeOut;
|
|
|
|
ReadEhcCapabiltiyReg (
|
|
HcDev,
|
|
HCCPARAMS,
|
|
&EECP
|
|
);
|
|
|
|
EECP = (EECP >> 8) & 0xFF;
|
|
|
|
DEBUG ((gEHCDebugLevel, "EHCI: EECPBase = 0x%x\n", EECP));
|
|
|
|
|
|
HcDev->PciIo->Pci.Read (
|
|
HcDev->PciIo,
|
|
EfiPciIoWidthUint32,
|
|
EECP,
|
|
1,
|
|
&Value
|
|
);
|
|
|
|
DEBUG((gEHCDebugLevel, "EECP[0] = 0x%x\n", Value));
|
|
|
|
HcDev->PciIo->Pci.Read (
|
|
HcDev->PciIo,
|
|
EfiPciIoWidthUint32,
|
|
EECP + 0x4,
|
|
1,
|
|
&Value
|
|
);
|
|
|
|
DEBUG((gEHCDebugLevel, "EECP[4] = 0x%x\n", Value));
|
|
|
|
HcDev->PciIo->Pci.Read (
|
|
HcDev->PciIo,
|
|
EfiPciIoWidthUint32,
|
|
EECP,
|
|
1,
|
|
&Value
|
|
);
|
|
|
|
Value = Value | (0x1 << 24);
|
|
DEBUG((gEHCErrorLevel, "Value Written = 0x%x\n", Value));
|
|
|
|
HcDev->PciIo->Pci.Write (
|
|
HcDev->PciIo,
|
|
EfiPciIoWidthUint32,
|
|
EECP,
|
|
1,
|
|
&Value
|
|
);
|
|
|
|
TimeOut = 40;
|
|
while (TimeOut --) {
|
|
gBS->Stall (500);
|
|
|
|
HcDev->PciIo->Pci.Read (
|
|
HcDev->PciIo,
|
|
EfiPciIoWidthUint32,
|
|
EECP,
|
|
1,
|
|
&Value
|
|
);
|
|
if ((Value & 0x01010000) == 0x01000000) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (TimeOut == 0) {
|
|
DEBUG((gEHCErrorLevel, "Timeout for getting HC OS Owned Semaphore\n" ));
|
|
}
|
|
|
|
DEBUG((gEHCErrorLevel, "After Release Value\n" ));
|
|
|
|
HcDev->PciIo->Pci.Read (
|
|
HcDev->PciIo,
|
|
EfiPciIoWidthUint32,
|
|
EECP,
|
|
1,
|
|
&Value
|
|
);
|
|
|
|
DEBUG((gEHCDebugLevel, "EECP[0] = 0x%x\n", Value));
|
|
|
|
HcDev->PciIo->Pci.Read (
|
|
HcDev->PciIo,
|
|
EfiPciIoWidthUint32,
|
|
EECP + 0x4,
|
|
1,
|
|
&Value
|
|
);
|
|
|
|
DEBUG((gEHCDebugLevel, "EECP[4] = 0x%x\n", Value));
|
|
|
|
|
|
}
|
|
|
|
EFI_STATUS
|
|
GetCapabilityLen (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the length of capability register
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 CapabilityLenAddr;
|
|
|
|
CapabilityLenAddr = CAPLENGTH;
|
|
|
|
Status = ReadEhcCapabiltiyReg (
|
|
HcDev,
|
|
CapabilityLenAddr,
|
|
&(HcDev->UsbCapabilityLen)
|
|
);
|
|
HcDev->UsbCapabilityLen = (UINT8) HcDev->UsbCapabilityLen;
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
SetFrameListLen (
|
|
IN USB2_HC_DEV *HcDev,
|
|
IN UINTN Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the length of Frame List
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
Length - the required length of frame list
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_INVALID_PARAMETER Invalid parameter
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 UsbCommandAddr;
|
|
UINT32 UsbCommandReg;
|
|
|
|
UsbCommandAddr = USBCMD;
|
|
|
|
if (256 != Length && 512 != Length) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
|
|
Status = ReadEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
&UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto exit;
|
|
}
|
|
|
|
if (256 == Length) {
|
|
UsbCommandReg |= USBCMD_FLS_256;
|
|
} else {
|
|
UsbCommandReg |= USBCMD_FLS_512;
|
|
}
|
|
|
|
Status = WriteEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
exit:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
SetFrameListBaseAddr (
|
|
IN USB2_HC_DEV *HcDev,
|
|
IN UINT32 FrameBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set base address of frame list first entry
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
FrameBuffer - base address of first entry of frame list
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 PeriodicListBaseAddr;
|
|
UINT32 PeriodicListBaseReg;
|
|
|
|
Status = EFI_SUCCESS;
|
|
PeriodicListBaseAddr = PERIODICLISTBASE;
|
|
PeriodicListBaseReg = FrameBuffer & 0xfffff000;
|
|
|
|
if (IsEhcHalted (HcDev)) {
|
|
|
|
Status = WriteEhcOperationalReg (
|
|
HcDev,
|
|
PeriodicListBaseAddr,
|
|
PeriodicListBaseReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto exit;
|
|
}
|
|
|
|
}
|
|
|
|
exit:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
SetAsyncListAddr (
|
|
IN USB2_HC_DEV *HcDev,
|
|
IN EHCI_QH_ENTITY *QhPtr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set address of first Async schedule Qh
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
QhPtr - A pointer to first Qh in the Async schedule
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 AsyncListAddr;
|
|
UINT32 AsyncListReg;
|
|
|
|
AsyncListAddr = ASYNCLISTADDR;
|
|
AsyncListReg = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh));
|
|
|
|
Status = WriteEhcOperationalReg (
|
|
HcDev,
|
|
AsyncListAddr,
|
|
AsyncListReg
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
SetCtrlDataStructSeg (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set register of control and data structure segment
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 CtrlDsSegmentAddr;
|
|
UINT32 CtrlDsSegmentReg;
|
|
|
|
CtrlDsSegmentAddr = CTRLDSSGMENT;
|
|
CtrlDsSegmentReg = HcDev->High32BitAddr;
|
|
|
|
Status = WriteEhcOperationalReg (
|
|
HcDev,
|
|
CtrlDsSegmentAddr,
|
|
CtrlDsSegmentReg
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
SetPortRoutingEhc (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set Ehc port routing bit
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 ConfigFlagAddr;
|
|
UINT32 ConfigFlagReg;
|
|
|
|
ConfigFlagAddr = CONFIGFLAG;
|
|
|
|
Status = ReadEhcOperationalReg (
|
|
HcDev,
|
|
ConfigFlagAddr,
|
|
&ConfigFlagReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto exit;
|
|
}
|
|
|
|
ConfigFlagReg |= CONFIGFLAG_CF;
|
|
Status = WriteEhcOperationalReg (
|
|
HcDev,
|
|
ConfigFlagAddr,
|
|
ConfigFlagReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
exit:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
SetEhcDoorbell (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set Ehc door bell bit
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 UsbCommandAddr;
|
|
UINT32 UsbCommandReg;
|
|
|
|
UsbCommandAddr = USBCMD;
|
|
|
|
Status = ReadEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
&UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto exit;
|
|
}
|
|
|
|
UsbCommandReg |= USBCMD_IAAD;
|
|
Status = WriteEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
exit:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ClearEhcAllStatus (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Clear Ehc all status bits
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
UINT32 UsbStatusAddr;
|
|
|
|
UsbStatusAddr = USBSTS;
|
|
|
|
return WriteEhcOperationalReg (
|
|
HcDev,
|
|
UsbStatusAddr,
|
|
0x003F
|
|
);
|
|
}
|
|
|
|
EFI_STATUS
|
|
EnablePeriodicSchedule (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enable periodic schedule
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 UsbCommandAddr;
|
|
UINT32 UsbCommandReg;
|
|
|
|
UsbCommandAddr = USBCMD;
|
|
|
|
Status = ReadEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
&UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto exit;
|
|
}
|
|
|
|
UsbCommandReg |= USBCMD_PSE;
|
|
Status = WriteEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
exit:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
DisablePeriodicSchedule (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Disable periodic schedule
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 UsbCommandAddr;
|
|
UINT32 UsbCommandReg;
|
|
|
|
UsbCommandAddr = USBCMD;
|
|
|
|
Status = ReadEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
&UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
UsbCommandReg &= ~USBCMD_PSE;
|
|
Status = WriteEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EnableAsynchronousSchedule (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enable asynchrounous schedule
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 UsbCommandAddr;
|
|
UINT32 UsbCommandReg;
|
|
|
|
UsbCommandAddr = USBCMD;
|
|
|
|
Status = ReadEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
&UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto exit;
|
|
}
|
|
|
|
UsbCommandReg |= USBCMD_ASE;
|
|
Status = WriteEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
exit:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
DisableAsynchronousSchedule (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Disable asynchrounous schedule
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 UsbCommandAddr;
|
|
UINT32 UsbCommandReg;
|
|
|
|
UsbCommandAddr = USBCMD;
|
|
|
|
Status = ReadEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
&UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
UsbCommandReg &= ~USBCMD_ASE;
|
|
Status = WriteEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ResetEhc (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reset Ehc
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 UsbCommandAddr;
|
|
UINT32 UsbCommandReg;
|
|
|
|
UsbCommandAddr = USBCMD;
|
|
|
|
Status = ReadEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
&UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto exit;
|
|
}
|
|
|
|
UsbCommandReg |= USBCMD_HCRESET;
|
|
Status = WriteEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
exit:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
StartScheduleExecution (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Start Ehc schedule execution
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_DEVICE_ERROR Fail
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 UsbCommandAddr;
|
|
UINT32 UsbCommandReg;
|
|
|
|
UsbCommandAddr = USBCMD;
|
|
|
|
Status = ReadEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
&UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto exit;
|
|
}
|
|
|
|
UsbCommandReg |= USBCMD_RS;
|
|
Status = WriteEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
exit:
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsFrameListProgrammable (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Whether frame list is programmable
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
TRUE Programmable
|
|
FALSE Unprogrammable
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Value;
|
|
UINT32 HcCapParamsAddr;
|
|
UINT32 HcCapParamsReg;
|
|
|
|
HcCapParamsAddr = HCCPARAMS;
|
|
|
|
ReadEhcCapabiltiyReg(
|
|
HcDev,
|
|
HcCapParamsAddr,
|
|
&HcCapParamsReg
|
|
);
|
|
|
|
if (HcCapParamsReg & HCCP_PFLF) {
|
|
Value = TRUE;
|
|
} else {
|
|
Value = FALSE;
|
|
}
|
|
|
|
return Value;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsPeriodicScheduleEnabled (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Whether periodic schedule is enabled
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
TRUE Enabled
|
|
FALSE Disabled
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Value;
|
|
UINT32 UsbStatusAddr;
|
|
UINT32 UsbStatusReg;
|
|
|
|
UsbStatusAddr = USBSTS;
|
|
|
|
ReadEhcOperationalReg (
|
|
HcDev,
|
|
UsbStatusAddr,
|
|
&UsbStatusReg
|
|
);
|
|
|
|
if (UsbStatusReg & USBSTS_PSS) {
|
|
Value = TRUE;
|
|
} else {
|
|
Value = FALSE;
|
|
}
|
|
|
|
return Value;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsAsyncScheduleEnabled (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Whether asynchronous schedule is enabled
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
TRUE Enabled
|
|
FALSE Disabled
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Value;
|
|
UINT32 UsbStatusAddr;
|
|
UINT32 UsbStatusReg;
|
|
|
|
UsbStatusAddr = USBSTS;
|
|
|
|
ReadEhcOperationalReg (
|
|
HcDev,
|
|
UsbStatusAddr,
|
|
&UsbStatusReg
|
|
);
|
|
|
|
if (UsbStatusReg & USBSTS_ASS) {
|
|
Value = TRUE;
|
|
} else {
|
|
Value = FALSE;
|
|
}
|
|
|
|
return Value;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsEhcPortEnabled (
|
|
IN USB2_HC_DEV *HcDev,
|
|
IN UINT8 PortNum
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Whether port is enabled
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
TRUE Enabled
|
|
FALSE Disabled
|
|
|
|
--*/
|
|
{
|
|
UINT32 PortStatusControlAddr;
|
|
UINT32 PortStatusControlReg;
|
|
|
|
PortStatusControlAddr = (UINT32) (PORTSC + (4 * PortNum));
|
|
|
|
ReadEhcOperationalReg (
|
|
HcDev,
|
|
PortStatusControlAddr,
|
|
&PortStatusControlReg
|
|
);
|
|
|
|
return ((BOOLEAN) ((PortStatusControlReg & PORTSC_PED) ? TRUE : FALSE));
|
|
}
|
|
|
|
BOOLEAN
|
|
IsEhcReseted (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Whether Ehc is reseted
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
TRUE Reseted
|
|
FALSE Unreseted
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Value;
|
|
UINT32 UsbCommandAddr;
|
|
UINT32 UsbCommandReg;
|
|
|
|
UsbCommandAddr = USBCMD;
|
|
|
|
ReadEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
&UsbCommandReg
|
|
);
|
|
|
|
if (UsbCommandReg & USBCMD_HCRESET) {
|
|
Value = FALSE;
|
|
} else {
|
|
Value = TRUE;
|
|
}
|
|
|
|
return Value;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsEhcHalted (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Whether Ehc is halted
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
TRUE Halted
|
|
FALSE Not halted
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Value;
|
|
UINT32 UsbStatusAddr;
|
|
UINT32 UsbStatusReg;
|
|
|
|
UsbStatusAddr = USBSTS;
|
|
|
|
ReadEhcOperationalReg (
|
|
HcDev,
|
|
UsbStatusAddr,
|
|
&UsbStatusReg
|
|
);
|
|
|
|
if (UsbStatusReg & USBSTS_HCH) {
|
|
Value = TRUE;
|
|
} else {
|
|
Value = FALSE;
|
|
}
|
|
|
|
return Value;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsEhcSysError (
|
|
IN USB2_HC_DEV *HcDev
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Whether Ehc is system error
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
TRUE System error
|
|
FALSE No system error
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Value;
|
|
UINT32 UsbStatusAddr;
|
|
UINT32 UsbStatusReg;
|
|
|
|
UsbStatusAddr = USBSTS;
|
|
|
|
ReadEhcOperationalReg (
|
|
HcDev,
|
|
UsbStatusAddr,
|
|
&UsbStatusReg
|
|
);
|
|
|
|
if (UsbStatusReg & USBSTS_HSE) {
|
|
Value = TRUE;
|
|
} else {
|
|
Value = FALSE;
|
|
}
|
|
|
|
return Value;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsHighSpeedDevice (
|
|
IN EFI_USB2_HC_PROTOCOL *This,
|
|
IN UINT8 PortNum
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Whether high speed device attached
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
|
|
Returns:
|
|
|
|
TRUE High speed
|
|
FALSE Full speed
|
|
|
|
--*/
|
|
{
|
|
USB2_HC_DEV *HcDev;
|
|
UINT32 PortStatusControlAddr;
|
|
UINT32 PortStatusControlReg;
|
|
|
|
HcDev = USB2_HC_DEV_FROM_THIS (This);
|
|
PortStatusControlAddr = (UINT32) (PORTSC + (4 * PortNum));
|
|
|
|
//
|
|
// Set port reset bit
|
|
//
|
|
ReadEhcOperationalReg (
|
|
HcDev,
|
|
PortStatusControlAddr,
|
|
&PortStatusControlReg
|
|
);
|
|
//
|
|
// Make sure Host Controller not halt before reset it
|
|
//
|
|
if (IsEhcHalted (HcDev)) {
|
|
StartScheduleExecution (HcDev);
|
|
WaitForEhcNotHalt (HcDev, EHCI_GENERIC_TIMEOUT);
|
|
}
|
|
PortStatusControlReg &= 0xffffffd5;
|
|
PortStatusControlReg |= PORTSC_PR;
|
|
//
|
|
// Set one to PortReset bit must also set zero to PortEnable bit
|
|
//
|
|
PortStatusControlReg &= ~PORTSC_PED;
|
|
WriteEhcOperationalReg (
|
|
HcDev,
|
|
PortStatusControlAddr,
|
|
PortStatusControlReg
|
|
);
|
|
|
|
//
|
|
// Set Port reset recovery time
|
|
//
|
|
gBS->Stall (EHCI_SET_PORT_RESET_RECOVERY_TIME);
|
|
|
|
//
|
|
// Clear port reset bit
|
|
//
|
|
ReadEhcOperationalReg (
|
|
HcDev,
|
|
PortStatusControlAddr,
|
|
&PortStatusControlReg
|
|
);
|
|
PortStatusControlReg &= 0xffffffd5;
|
|
PortStatusControlReg &= ~PORTSC_PR;
|
|
WriteEhcOperationalReg (
|
|
HcDev,
|
|
PortStatusControlAddr,
|
|
PortStatusControlReg
|
|
);
|
|
|
|
//
|
|
// Clear port reset recovery time
|
|
//
|
|
gBS->Stall (EHCI_CLEAR_PORT_RESET_RECOVERY_TIME);
|
|
|
|
return ((BOOLEAN) (IsEhcPortEnabled (HcDev, PortNum) ? TRUE : FALSE));
|
|
}
|
|
|
|
EFI_STATUS
|
|
WaitForEhcReset (
|
|
IN USB2_HC_DEV *HcDev,
|
|
IN UINTN Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
wait for Ehc reset or timeout
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
Timeout - timeout threshold
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_TIMEOUT Timeout
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Delay;
|
|
|
|
//
|
|
// Timeout is in US unit
|
|
//
|
|
Delay = (Timeout / 50) + 1;
|
|
do {
|
|
|
|
if (IsEhcReseted (HcDev)) {
|
|
Status = EFI_SUCCESS;
|
|
goto exit;
|
|
}
|
|
gBS->Stall (EHCI_GENERIC_RECOVERY_TIME);
|
|
|
|
} while (Delay--);
|
|
|
|
Status = EFI_TIMEOUT;
|
|
|
|
exit:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
WaitForEhcHalt (
|
|
IN USB2_HC_DEV *HcDev,
|
|
IN UINTN Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
wait for Ehc halt or timeout
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
Timeout - timeout threshold
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_TIMEOUT Timeout
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Delay;
|
|
|
|
//
|
|
// Timeout is in US unit
|
|
//
|
|
Delay = (Timeout / 50) + 1;
|
|
do {
|
|
|
|
if (IsEhcHalted (HcDev)) {
|
|
Status = EFI_SUCCESS;
|
|
goto exit;
|
|
}
|
|
gBS->Stall (EHCI_GENERIC_RECOVERY_TIME);
|
|
|
|
} while (Delay--);
|
|
|
|
Status = EFI_TIMEOUT;
|
|
|
|
exit:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
WaitForEhcNotHalt (
|
|
IN USB2_HC_DEV *HcDev,
|
|
IN UINTN Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
wait for Ehc not halt or timeout
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
Timeout - timeout threshold
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_TIMEOUT Timeout
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Delay;
|
|
|
|
//
|
|
// Timeout is in US unit
|
|
//
|
|
Delay = (Timeout / 50) + 1;
|
|
do {
|
|
|
|
if (!IsEhcHalted (HcDev)) {
|
|
Status = EFI_SUCCESS;
|
|
goto exit;
|
|
}
|
|
gBS->Stall (EHCI_GENERIC_RECOVERY_TIME);
|
|
|
|
} while (Delay--);
|
|
|
|
Status = EFI_TIMEOUT;
|
|
|
|
exit:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
WaitForAsyncScheduleEnable (
|
|
IN USB2_HC_DEV *HcDev,
|
|
IN UINTN Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wait for Ehc asynchronous schedule enable or timeout
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
Timeout - timeout threshold
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_TIMEOUT Timeout
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Delay;
|
|
|
|
//
|
|
// Timeout is in US unit
|
|
//
|
|
Delay = (Timeout / 50) + 1;
|
|
do {
|
|
|
|
if (IsAsyncScheduleEnabled (HcDev)) {
|
|
Status = EFI_SUCCESS;
|
|
goto exit;
|
|
}
|
|
gBS->Stall (EHCI_GENERIC_RECOVERY_TIME);
|
|
|
|
} while (Delay--);
|
|
|
|
Status = EFI_TIMEOUT;
|
|
|
|
exit:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
WaitForAsyncScheduleDisable (
|
|
IN USB2_HC_DEV *HcDev,
|
|
IN UINTN Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wait for Ehc asynchronous schedule disable or timeout
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
Timeout - timeout threshold
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_TIMEOUT Timeout
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Delay;
|
|
|
|
//
|
|
// Timeout is in US unit
|
|
//
|
|
Delay = (Timeout / 50) + 1;
|
|
do {
|
|
|
|
if (!IsAsyncScheduleEnabled (HcDev)) {
|
|
Status = EFI_SUCCESS;
|
|
goto exit;
|
|
}
|
|
gBS->Stall (EHCI_GENERIC_RECOVERY_TIME);
|
|
|
|
} while (Delay--);
|
|
|
|
Status = EFI_TIMEOUT;
|
|
|
|
exit:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
WaitForPeriodicScheduleEnable (
|
|
IN USB2_HC_DEV *HcDev,
|
|
IN UINTN Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wait for Ehc periodic schedule enable or timeout
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
Timeout - timeout threshold
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_TIMEOUT Timeout
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Delay;
|
|
|
|
//
|
|
// Timeout is in US unit
|
|
//
|
|
Delay = (Timeout / 50) + 1;
|
|
do {
|
|
|
|
if (IsPeriodicScheduleEnabled (HcDev)) {
|
|
Status = EFI_SUCCESS;
|
|
goto exit;
|
|
}
|
|
gBS->Stall (EHCI_GENERIC_RECOVERY_TIME);
|
|
|
|
} while (Delay--);
|
|
|
|
Status = EFI_TIMEOUT;
|
|
|
|
exit:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
WaitForPeriodicScheduleDisable (
|
|
IN USB2_HC_DEV *HcDev,
|
|
IN UINTN Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wait for periodic schedule disable or timeout
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
Timeout - timeout threshold
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_TIMEOUT Timeout
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Delay;
|
|
|
|
//
|
|
// Timeout is in US unit
|
|
//
|
|
Delay = (Timeout / 50) + 1;
|
|
do {
|
|
|
|
if (!IsPeriodicScheduleEnabled (HcDev)) {
|
|
Status = EFI_SUCCESS;
|
|
goto exit;
|
|
}
|
|
gBS->Stall (EHCI_GENERIC_RECOVERY_TIME);
|
|
|
|
} while (Delay--);
|
|
|
|
Status = EFI_TIMEOUT;
|
|
|
|
exit:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
WaitForEhcDoorbell (
|
|
IN USB2_HC_DEV *HcDev,
|
|
IN UINTN Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wait for periodic schedule disable or timeout
|
|
|
|
Arguments:
|
|
|
|
HcDev - USB2_HC_DEV
|
|
Timeout - timeout threshold
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS Success
|
|
EFI_TIMEOUT Timeout
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 UsbCommandAddr;
|
|
UINT32 UsbCommandReg;
|
|
UINTN Delay;
|
|
|
|
UsbCommandAddr = USBCMD;
|
|
Delay = (Timeout / 50) + 1;
|
|
|
|
do {
|
|
Status = ReadEhcOperationalReg (
|
|
HcDev,
|
|
UsbCommandAddr,
|
|
&UsbCommandReg
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto exit;
|
|
}
|
|
if (!(UsbCommandReg & USBCMD_IAAD)) {
|
|
break;
|
|
}
|
|
|
|
} while (--Delay);
|
|
|
|
if (0 == Delay) {
|
|
Status = EFI_TIMEOUT;
|
|
}
|
|
|
|
exit:
|
|
return Status;
|
|
}
|