/** @file The UHCI register operation routines. Copyright (c) 2007, Intel Corporation. All rights reserved.
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 ); }