/** Reset the XHCI host controller. @param Xhc The XHCI Instance. @param Timeout Time to wait before abort (in microsecond, us). @retval EFI_SUCCESS The XHCI host controller is reset. @return Others Failed to reset the XHCI before Timeout. **/ EFI_STATUS XhcResetHC ( IN USB_XHCI_INSTANCE *Xhc, IN UINT32 Timeout ) { EFI_STATUS Status; Status = EFI_SUCCESS; DEBUG ((EFI_D_INFO, "XhcResetHC!\n")); // // Host can only be reset when it is halt. If not so, halt it // if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) { Status = XhcHaltHC (Xhc, Timeout); if (EFI_ERROR (Status)) { return Status; } } if ((Xhc->DebugCapSupOffset == 0xFFFFFFFF) || ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) != XHC_CAP_USB_DEBUG) || ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) == 0)) { XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET); Status = XhcWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout); } return Status; }
/** Calculate the XHCI legacy support capability register offset. @param Xhc The XHCI Instance. @return The offset of XHCI legacy support capability register. **/ UINT32 XhcGetLegSupCapAddr ( IN USB_XHCI_INSTANCE *Xhc ) { UINT32 ExtCapOffset; UINT8 NextExtCapReg; UINT32 Data; ExtCapOffset = 0; do { // // Check if the extended capability register's capability id is USB Legacy Support. // Data = XhcReadExtCapReg (Xhc, ExtCapOffset); if ((Data & 0xFF) == 0x1) { return ExtCapOffset; } // // If not, then traverse all of the ext capability registers till finding out it. // NextExtCapReg = (UINT8)((Data >> 8) & 0xFF); ExtCapOffset += (NextExtCapReg << 2); } while (NextExtCapReg != 0); return 0; }
/** Clear Bios Ownership @param Xhc The XHCI Instance. **/ VOID XhcClearBiosOwnership ( IN USB_XHCI_INSTANCE *Xhc ) { UINT32 Buffer; DEBUG ((EFI_D_INFO, "XhcClearBiosOwnership: called to clear BIOS ownership\n")); Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset); Buffer = ((Buffer & (~USBLEGSP_BIOS_SEMAPHORE)) | USBLEGSP_OS_SEMAPHORE); XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer); }
/** Reset the XHCI host controller. @param Xhc The XHCI Instance. @param Timeout Time to wait before abort (in millisecond, ms). @retval EFI_SUCCESS The XHCI host controller is reset. @return Others Failed to reset the XHCI before Timeout. **/ EFI_STATUS XhcResetHC ( IN USB_XHCI_INSTANCE *Xhc, IN UINT32 Timeout ) { EFI_STATUS Status; Status = EFI_SUCCESS; DEBUG ((EFI_D_INFO, "XhcResetHC!\n")); // // Host can only be reset when it is halt. If not so, halt it // if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) { Status = XhcHaltHC (Xhc, Timeout); if (EFI_ERROR (Status)) { return Status; } } if ((Xhc->DebugCapSupOffset == 0xFFFFFFFF) || ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) != XHC_CAP_USB_DEBUG) || ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) == 0)) { XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET); // // Some XHCI host controllers require to have extra 1ms delay before accessing any MMIO register during reset. // Otherwise there may have the timeout case happened. // The below is a workaround to solve such problem. // gBS->Stall (XHC_1_MILLISECOND); Status = XhcWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout); } return Status; }