blob: 9aa138fa46dda91dc83a5f0074ef113eb3cc4d1e [file] [log] [blame]
/** @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
);
}