/** @file | |
The UHCI register operation routines. | |
Copyright (c) 2007, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "Uhci.h" | |
/** | |
Read a UHCI register. | |
@param PciIo The EFI_PCI_IO_PROTOCOL to use. | |
@param Offset Register offset to USB_BAR_INDEX. | |
@return Content of register. | |
**/ | |
UINT16 | |
UhciReadReg ( | |
IN EFI_PCI_IO_PROTOCOL *PciIo, | |
IN UINT32 Offset | |
) | |
{ | |
UINT16 Data; | |
EFI_STATUS Status; | |
Status = PciIo->Io.Read ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
USB_BAR_INDEX, | |
Offset, | |
1, | |
&Data | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "UhciReadReg: PciIo Io.Read error: %r at offset %d\n", Status, Offset)); | |
Data = 0xFFFF; | |
} | |
return Data; | |
} | |
/** | |
Write data to UHCI register. | |
@param PciIo The EFI_PCI_IO_PROTOCOL to use. | |
@param Offset Register offset to USB_BAR_INDEX. | |
@param Data Data to write. | |
**/ | |
VOID | |
UhciWriteReg ( | |
IN EFI_PCI_IO_PROTOCOL *PciIo, | |
IN UINT32 Offset, | |
IN UINT16 Data | |
) | |
{ | |
EFI_STATUS Status; | |
Status = PciIo->Io.Write ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
USB_BAR_INDEX, | |
Offset, | |
1, | |
&Data | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "UhciWriteReg: PciIo Io.Write error: %r at offset %d\n", Status, Offset)); | |
} | |
} | |
/** | |
Set a bit of the UHCI Register. | |
@param PciIo The EFI_PCI_IO_PROTOCOL to use. | |
@param Offset Register offset to USB_BAR_INDEX. | |
@param Bit The bit to set. | |
**/ | |
VOID | |
UhciSetRegBit ( | |
IN EFI_PCI_IO_PROTOCOL *PciIo, | |
IN UINT32 Offset, | |
IN UINT16 Bit | |
) | |
{ | |
UINT16 Data; | |
Data = UhciReadReg (PciIo, Offset); | |
Data = (UINT16)(Data |Bit); | |
UhciWriteReg (PciIo, Offset, Data); | |
} | |
/** | |
Clear a bit of the UHCI Register. | |
@param PciIo The PCI_IO protocol to access the PCI. | |
@param Offset Register offset to USB_BAR_INDEX. | |
@param Bit The bit to clear. | |
**/ | |
VOID | |
UhciClearRegBit ( | |
IN EFI_PCI_IO_PROTOCOL *PciIo, | |
IN UINT32 Offset, | |
IN UINT16 Bit | |
) | |
{ | |
UINT16 Data; | |
Data = UhciReadReg (PciIo, Offset); | |
Data = (UINT16)(Data & ~Bit); | |
UhciWriteReg (PciIo, Offset, Data); | |
} | |
/** | |
Clear all the interrutp status bits, these bits | |
are Write-Clean. | |
@param Uhc The UHCI device. | |
**/ | |
VOID | |
UhciAckAllInterrupt ( | |
IN USB_HC_DEV *Uhc | |
) | |
{ | |
UhciWriteReg (Uhc->PciIo, USBSTS_OFFSET, 0x3F); | |
// | |
// If current HC is halted, re-enable it. Host Controller Process Error | |
// is a temporary error status. | |
// | |
if (!UhciIsHcWorking (Uhc->PciIo)) { | |
DEBUG ((DEBUG_ERROR, "UhciAckAllInterrupt: re-enable the UHCI from system error\n")); | |
Uhc->Usb2Hc.SetState (&Uhc->Usb2Hc, EfiUsbHcStateOperational); | |
} | |
} | |
/** | |
Stop the host controller. | |
@param Uhc The UHCI device. | |
@param Timeout Max time allowed. | |
@retval EFI_SUCCESS The host controller is stopped. | |
@retval EFI_TIMEOUT Failed to stop the host controller. | |
**/ | |
EFI_STATUS | |
UhciStopHc ( | |
IN USB_HC_DEV *Uhc, | |
IN UINTN Timeout | |
) | |
{ | |
UINT16 UsbSts; | |
UINTN Index; | |
UhciClearRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS); | |
// | |
// ensure the HC is in halt status after send the stop command | |
// Timeout is in us unit. | |
// | |
for (Index = 0; Index < (Timeout / 50) + 1; Index++) { | |
UsbSts = UhciReadReg (Uhc->PciIo, USBSTS_OFFSET); | |
if ((UsbSts & USBSTS_HCH) == USBSTS_HCH) { | |
return EFI_SUCCESS; | |
} | |
gBS->Stall (50); | |
} | |
return EFI_TIMEOUT; | |
} | |
/** | |
Check whether the host controller operates well. | |
@param PciIo The PCI_IO protocol to use. | |
@retval TRUE Host controller is working. | |
@retval FALSE Host controller is halted or system error. | |
**/ | |
BOOLEAN | |
UhciIsHcWorking ( | |
IN EFI_PCI_IO_PROTOCOL *PciIo | |
) | |
{ | |
UINT16 UsbSts; | |
UsbSts = UhciReadReg (PciIo, USBSTS_OFFSET); | |
if ((UsbSts & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) != 0) { | |
DEBUG ((DEBUG_ERROR, "UhciIsHcWorking: current USB state is %x\n", UsbSts)); | |
return FALSE; | |
} | |
return TRUE; | |
} | |
/** | |
Set the UHCI frame list base address. It can't use | |
UhciWriteReg which access memory in UINT16. | |
@param PciIo The EFI_PCI_IO_PROTOCOL to use. | |
@param Addr Address to set. | |
**/ | |
VOID | |
UhciSetFrameListBaseAddr ( | |
IN EFI_PCI_IO_PROTOCOL *PciIo, | |
IN VOID *Addr | |
) | |
{ | |
EFI_STATUS Status; | |
UINT32 Data; | |
Data = (UINT32)((UINTN)Addr & 0xFFFFF000); | |
Status = PciIo->Io.Write ( | |
PciIo, | |
EfiPciIoWidthUint32, | |
USB_BAR_INDEX, | |
(UINT64)USB_FRAME_BASE_OFFSET, | |
1, | |
&Data | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "UhciSetFrameListBaseAddr: PciIo Io.Write error: %r\n", Status)); | |
} | |
} | |
/** | |
Disable USB Emulation. | |
@param PciIo The EFI_PCI_IO_PROTOCOL protocol to use. | |
**/ | |
VOID | |
UhciTurnOffUsbEmulation ( | |
IN EFI_PCI_IO_PROTOCOL *PciIo | |
) | |
{ | |
UINT16 Command; | |
Command = 0; | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
USB_EMULATION_OFFSET, | |
1, | |
&Command | |
); | |
} |