From b7c51c9cf4864df6aabb99a1ae843becd577237c Mon Sep 17 00:00:00 2001 From: raywu Date: Fri, 15 Jun 2018 00:00:50 +0800 Subject: init. 1AQQW051 --- Core/EM/UsbRecovery/EhciPEI/EhciPei.c | 1847 ++++++++++++++++++++++++++++ Core/EM/UsbRecovery/EhciPEI/EhciPei.cif | 10 + Core/EM/UsbRecovery/EhciPEI/EhciPei.h | 592 +++++++++ Core/EM/UsbRecovery/EhciPEI/EhciPeiBoard.c | 108 ++ 4 files changed, 2557 insertions(+) create mode 100644 Core/EM/UsbRecovery/EhciPEI/EhciPei.c create mode 100644 Core/EM/UsbRecovery/EhciPEI/EhciPei.cif create mode 100644 Core/EM/UsbRecovery/EhciPEI/EhciPei.h create mode 100644 Core/EM/UsbRecovery/EhciPEI/EhciPeiBoard.c (limited to 'Core/EM/UsbRecovery/EhciPEI') diff --git a/Core/EM/UsbRecovery/EhciPEI/EhciPei.c b/Core/EM/UsbRecovery/EhciPEI/EhciPei.c new file mode 100644 index 0000000..a5f617f --- /dev/null +++ b/Core/EM/UsbRecovery/EhciPEI/EhciPei.c @@ -0,0 +1,1847 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2009, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// +// $Header: /Alaska/SOURCE/Modules/USBRecovery/EhciPei.c 14 11/24/12 5:44a Ryanchou $ +// +// $Revision: 14 $ +// +// $Date: 11/24/12 5:44a $ +// +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USBRecovery/EhciPei.c $ +// +// 14 11/24/12 5:44a Ryanchou +// [TAG] EIP103990 +// [Category] Improvement +// [Description] Synchronized with USB PEI module 4.6.3_USB_08.10.24. +// [Files] EhciPei.c, EhciPei.h, OhciPei.c, OhciPei.h, UhcPeim.c, +// BotPeim.c, BotPeim.h, PeiAtapi.c, UsbBotPeim.c, UsbBotPeim.h, +// HubPeim.c, UsbPeim.c, XhciPei.c, XhciPei.h, HubPeim.h, PeiUsbLib.c, +// PeiUsbLib.h, UsbPeim.h +// +// 13 9/28/12 2:56a Roberthsu +// [TAG] EIP99922 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] System hanged on CP:9C during USB Recovery from cold +// boot. +// [RootCause] Usb controller need reset when pei exit. +// [Solution] Reset usb controller when pei exit +// [Files] EhciPei.c +// +// 12 8/23/12 9:57p Wilsonlee +// [TAG] EIP97069 +// [Category] Improvement +// [Description] Reset root port algorythm update. +// [Files] EhciPei.c, EhciPei.h, OhciPei.c, OhciPei.h, UhcPeim.c, +// UhcPeim.h, UsbPeim.c, usb.h +// +// 11 8/09/11 4:59p Yul +// [TAG] EIP60439 +// [Category] Improvement +// [Description] Generically handle the assignments of MMIO base address +// from Rx and UsbRecovery modules. +// [Files] EhciPei.c +// +// 10 1/18/11 12:52a Ryanchou +// [TAG] EIP47931 +// [Category] Improvement +// [Description] Added USB 3.0 hub support. +// [Files] EhciPei.c, EhciPei.h, HubPeim.c, HubPeim.h, OhciPei.c, +// OhciPei.h, UhcPeim.c, UhcPeim.h, usb.h, UsbHostController.h, +// UsbIoPeim.c, UsbPeim.c, UsbPeim.h, XhciPei.c, XhciPei.h +// +// 9 1/11/11 11:12a Olegi +// [TAG] EIP51517 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] Recovery fails when using USB port behind HUB +// [RootCause] Port Power was not set +// [Solution] Set Port Power if Port Power Control bit is 1. +// [Files] EHCIPEI.C +// +// 8 10/11/10 4:51p Olegi +// XHCI support added. +// +// 7 4/26/10 4:16p Krishnakumarg +// DebugRx causes the system to hang in Recovery mode EIP#34401 +// +// 6 10/20/09 9:15a Olegi +// EIP#28255: EhciHcGetRootHubPortStatus returns proper status. +// +// 5 7/30/09 6:23p Krishnakumarg +// Symptom :During recovery,system hangs while entering setup. +// RootCause:USB Host controller Status registers are not cleared and HC +// is not HALTed after loading recovery capsule. +// Solution: HC is set to HALT state after loading recovery module so USB +// driver clears the status Registers. +// +// 4 4/29/09 1:56p Rameshr +// EHCIStopAsyncSchedule gets called always when the +// EHCIStartAsyncSchedule function is called +// +// 3 3/17/09 5:08p Olegi +// Added TransactionTranslator for slow/full speed devices behind USB2 +// hub. +// +// 2 3/04/09 11:56a Olegi +// +// 1 3/03/09 7:28p Olegi +// +//********************************************************************** + +// +//---------------------------------------------------------------------------- +// +// Name: EhciPei.c +// +// Description: +// This file is the main source file for the EHCI PEI USB +// recovery module. Its entry point at EhciPeiUsbEntryPoint +// will be executed from the UsbRecoveryInitialize INIT_LIST. +// +//---------------------------------------------------------------------------- +// + +#include +#include +#include +#include +#include +#include "Ppi\UsbHostController.h" +#include "UsbPeim.h" +#include "EhciPei.h" +#include "usb.h" + +extern EFI_GUID gPeiStallPpiGuid; +extern EFI_GUID gPeiUsbHostControllerPpiGuid; + +EFI_STATUS EhciPeiBoardInit ( + IN EFI_PEI_SERVICES **PeiServices, + EFI_PEI_PCI_CFG_PPI *PciCfgPpi, + EFI_PEI_STALL_PPI *StallPpi ); + +UINT32 gEhciControllerPciTable[] = PEI_EHCI_PCI_BDFS; +UINT16 gEhciControllerCount = \ + sizeof(gEhciControllerPciTable) / sizeof(UINT32); + +UINT32 gEhciControllerBaseAddress[] = PEI_EHCI_MEM_BASE_ADDRESSES; + +EFI_GUID guidEndOfPei = EFI_PEI_END_OF_PEI_PHASE_PPI_GUID; + +EFI_STATUS +EFIAPI NotifyOnRecoveryCapsuleLoaded ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, + IN VOID *InvokePpi ); + + +static EFI_PEI_NOTIFY_DESCRIPTOR lNotifyList = { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &guidEndOfPei, + NotifyOnRecoveryCapsuleLoaded +}; + +BOOLEAN EHCIDbg_PortUsed = FALSE; + +// +//--------------------------------------------------------------------------- +// +// Procedure: EhciGetOperationalRegisterBase +// +// Description: +// This function uses ControllerIndex and the global PCI_BUS_DEV_FUNCTION +// array to access a particular controller's PCI configuration space in +// order to obtain the Operational Register base address. +// +// Input: +// IN EFI_PEI_SERVICES **PeiServices +// -- PEI Sevices table pointer +// IN UINT16 ControllerIndex +// -- Index of the controller in the global +// PCI_BUS_DEV_FUNCTION array +// +// Output: +// UINT32 (Return Value) +// = Base address for this controller's operational +// registers. +// +//--------------------------------------------------------------------------- +// + +UINT32 EhciGetOperationalRegisterBase ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT16 ControllerIndex ) +{ + UINT32 EhciBaseAddress; + + (*PeiServices)->PciCfg->Read( + PeiServices, + (*PeiServices)->PciCfg, + EfiPeiPciCfgWidthUint32, + gEhciControllerPciTable[ControllerIndex] + EHCI_BASE_ADDR_REG, + &EhciBaseAddress + ); + + return EhciBaseAddress; +} + +// +//--------------------------------------------------------------------------- +// +// Procedure: Update_EHCIDbg_PortUsed +// +// Description: +// Check debugport of a controlller is in use or not. +// +// Input: +// IN EFI_PEI_SERVICES **PeiServices +// -- PEI Sevices table pointer +// IN UINT16 ControllerIndex +// -- Index of the controller in the global +// PCI_BUS_DEV_FUNCTION array +// +// Output : +// +// Note : EHCIDbg_PortUsed used to maintain the debugport usage of +// CURRENT processing controller. +//--------------------------------------------------------------------------- +// + +VOID Update_EHCIDbg_PortUsed(EFI_PEI_SERVICES **PeiServices,UINT8 Index) +{ + UINT8 CmdReg = 0; + UINT16 DebugBase = 0; + UINT32 EhciBaseMem = 0; + +// +// Read Command register and check MMIO enabled or not +// + (*PeiServices)->PciCfg->Read( PeiServices, (*PeiServices)->PciCfg, + EfiPeiPciCfgWidthUint8, + gEhciControllerPciTable[Index] + EHCI_CMD_REGISTER, + &CmdReg ); + + if(!(CmdReg & 2)){ //MMIO is disabled + EHCIDbg_PortUsed = FALSE; + return; + } +// +// Retrieve the debugport base offset address +// + (*PeiServices)->PciCfg->Read( PeiServices, (*PeiServices)->PciCfg, + EfiPeiPciCfgWidthUint16, + gEhciControllerPciTable[Index] + DEBUG_BASE, + &DebugBase ); + + DebugBase = DebugBase & 0x1FFF; // Bar number hardwired to 001b + + EhciBaseMem = EhciGetOperationalRegisterBase(PeiServices,Index); + +// +// Check ENABLED_CNT bit of DEBUG status register +// + if ((*(volatile UINT32*)(UINTN)(EhciBaseMem + DebugBase)) & BIT28){ + EHCIDbg_PortUsed = TRUE; + }else{ + EHCIDbg_PortUsed = FALSE; + } +} + +// +//--------------------------------------------------------------------------- +// +// Procedure: EhciPeiUsbEntryPoint +// +// Description: +// This is the entry point into the EHCI controller initialization +// subsystem. +// +// Input: +// IN EFI_FFS_FILE_HEADER *FfsHeader +// -- EFI_FFS_FILE_HEADER pointer +// IN EFI_PEI_SERVICES **PeiServices +// -- EFI_PEI_SERVICES pointer +// +// Output: +// EFI_STATUS (Return Value) +// = EFI_SUCCESS on successful completion +// or valid EFI error code +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS EhciPeiUsbEntryPoint ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices ) +{ + UINT8 Index; + UINTN MemPages; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS TempPtr; + PEI_EHCI_DEV *EhciDevPtr; + EFI_PEI_STALL_PPI *StallPpi; + UINT8 ByteData; + + //------------------------------------------- + // Initialize the EFI_PEI_STALL_PPI interface + //------------------------------------------- + Status = (**PeiServices).LocatePpi( PeiServices, &gPeiStallPpiGuid, + 0, NULL, &StallPpi ); + if ( EFI_ERROR( Status ) ) { + return EFI_UNSUPPORTED; + } + + //----------------------------------------- + // board specific initialization to program + // PCI bridges and enable MMIO + //----------------------------------------- + + Status = EhciPeiBoardInit( + PeiServices, + (*PeiServices)->PciCfg, + StallPpi ); + if ( EFI_ERROR( Status ) ) { + return EFI_UNSUPPORTED; + } + + //---------------------------------------------------------- + // Allocate EHCI DEVICE OBJECT that holds all necessary + // information for the Host Controller operational registers + // for each controller. Initialze the controller and setup + // data structures for ready for operation + //---------------------------------------------------------- + + for (Index = 0; Index < gEhciControllerCount; Index++) + { + + + if(!(EhciGetOperationalRegisterBase( PeiServices, Index ))){ + // Program PCI BAR and command register + (*PeiServices)->PciCfg->Write( PeiServices, (*PeiServices)->PciCfg, + EfiPeiPciCfgWidthUint32, + gEhciControllerPciTable[Index] + EHCI_BASE_ADDR_REG, + &gEhciControllerBaseAddress[Index] ); + } + + ByteData = 6; // Enable MMIO and BusMaster + (*PeiServices)->PciCfg->Write( PeiServices, (*PeiServices)->PciCfg, + EfiPeiPciCfgWidthUint8, + gEhciControllerPciTable[Index] + EHCI_CMD_REGISTER, + &ByteData ); + + + Update_EHCIDbg_PortUsed(PeiServices,Index); + + // PAGESIZE = 0x1000 + MemPages = sizeof (PEI_EHCI_DEV) / 0x1000 + 1; + Status = (**PeiServices).AllocatePages( + PeiServices, + EfiConventionalMemory, + MemPages, + &TempPtr + ); + if ( EFI_ERROR( Status ) ) + { + return EFI_OUT_OF_RESOURCES; + } + (**PeiServices).SetMem((VOID*)TempPtr, sizeof (PEI_EHCI_DEV), 0); + + EhciDevPtr = (PEI_EHCI_DEV *) ( (UINTN) TempPtr ); + EhciDevPtr->Signature = PEI_EHCI_DEV_SIGNATURE; + EhciDevPtr->PeiServices = PeiServices; + EhciDevPtr->CpuIoPpi = (*PeiServices)->CpuIo; + EhciDevPtr->StallPpi = StallPpi; + EhciDevPtr->PciCfgPpi = (*PeiServices)->PciCfg; + + EhciDevPtr->UsbHostControllerBaseAddress = + EhciGetOperationalRegisterBase( PeiServices, Index ); + + //Initialize the EHCI Controller for operation + + EhciInitHC( PeiServices, EhciDevPtr ); + + //Setup PPI entry point + EhciDevPtr->UsbHostControllerPpi.ControlTransfer = EhciHcControlTransfer; + EhciDevPtr->UsbHostControllerPpi.BulkTransfer = EhciHcBulkTransfer; + EhciDevPtr->UsbHostControllerPpi.GetRootHubPortNumber = EhciHcGetRootHubPortNumber; + EhciDevPtr->UsbHostControllerPpi.GetRootHubPortStatus = EhciHcGetRootHubPortStatus; + EhciDevPtr->UsbHostControllerPpi.SetRootHubPortFeature = EhciHcSetRootHubPortFeature; + EhciDevPtr->UsbHostControllerPpi.ClearRootHubPortFeature = EhciHcClearRootHubPortFeature; + + EhciDevPtr->UsbHostControllerPpi.DebugPortUsed = EHCIDbg_PortUsed; + EhciDevPtr->UsbHostControllerPpi.PreConfigureDevice = NULL; + EhciDevPtr->UsbHostControllerPpi.EnableEndpoints = NULL; + + EhciDevPtr->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); + EhciDevPtr->PpiDescriptor.Guid = &gPeiUsbHostControllerPpiGuid; + EhciDevPtr->PpiDescriptor.Ppi = &EhciDevPtr->UsbHostControllerPpi; + + //Now is the time to install the PPI + Status = (**PeiServices).InstallPpi( PeiServices, &EhciDevPtr->PpiDescriptor ); + if ( EFI_ERROR( Status ) ) + { + return EFI_NOT_FOUND; + } + + } + (**PeiServices).NotifyPpi (PeiServices, &lNotifyList); + + return EFI_SUCCESS; + +} + +// +//--------------------------------------------------------------------------- +// +// Procedure: EhciInitHC +// +// Description: EHCI controller initialization. +// +// Input: +// IN EFI_PEI_SERVICES **PeiServices +// -- EFI_PEI_SERVICES pointer +// IN PEI_EHCI_DEV *EhciDevPtr +// -- PEI_EHCI_DEV pointer +// IN UINT8 Index +// -- Index of this controller in the global +// PCI_BUS_DEV_FUNCTION array +// +// Output: +// VOID (Return Value) +// +// Note: +// EhciDevPtr->UsbHostControllerBaseAddress is is initialized +// +//--------------------------------------------------------------------------- +// + +VOID EhciInitHC ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_EHCI_DEV *EhciDevPtr) +{ + UINT8 *pPtr; + UINTN MemPages; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS TempPtr; + EHCI_HC_CAP_REG *EhciHcCapReg = + (EHCI_HC_CAP_REG *)(UINTN)EhciDevPtr->UsbHostControllerBaseAddress; + EHCI_HC_OPER_REG *EhciHcOpReg; + EHCI_DESC_PTRS *pstEHCIDescPtrs; + + + // Allocate memory for control transfers and bulk transfers + // Allocate a block of memory and define/initialize + // Setup Control and Bulk EDs/TDs + pstEHCIDescPtrs = &(EhciDevPtr->stEHCIDescPtrs); + + MemPages = (( 4 * sizeof (EHCI_QTD) ) + (2 * sizeof(EHCI_QH) )) / 0x1000 + 1; + Status = (**PeiServices).AllocatePages( + PeiServices, + EfiConventionalMemory, + MemPages, + &TempPtr + ); + + pPtr = (UINT8 *) ( (UINTN) TempPtr ); + if (pPtr == NULL) { + return; + } + MemSet( pPtr, 4 * sizeof (EHCI_QTD) + 2 * sizeof(EHCI_QH), 0 ); + + pstEHCIDescPtrs->fpQHControl = (EHCI_QH*) pPtr; + pPtr += sizeof (EHCI_QH); + pstEHCIDescPtrs->fpqTDControlSetup = (EHCI_QTD*) pPtr; + pPtr += sizeof (EHCI_QTD); + pstEHCIDescPtrs->fpqTDControlData = (EHCI_QTD*) pPtr; + pPtr += sizeof (EHCI_QTD); + pstEHCIDescPtrs->fpqTDControlStatus = (EHCI_QTD*) pPtr; + pPtr += sizeof (EHCI_QTD); + pstEHCIDescPtrs->fpQHBulk = (EHCI_QH*) pPtr; + pPtr += sizeof (EHCI_QH); + pstEHCIDescPtrs->fpqTDBulkData = (EHCI_QTD*) pPtr; + + // Store number of downstream ports into PEI_EHCI_DEV struct + EhciDevPtr->bNumPorts = (UINT8)(EhciHcCapReg->HcsParams.Field.NumberOfPorts); + + // Read the Capability Registers Length to find the Offset address for the + // beginning of the operational registers + EhciHcOpReg = (EHCI_HC_OPER_REG *)((UINTN)EhciHcCapReg + EhciHcCapReg->CapLength); + EhciDevPtr->EhciHcOpReg = EhciHcOpReg; + + EhciDevPtr->HcStatus = 0; + + // Do a Host Controller reset first + if(!EHCIDbg_PortUsed) + EhciHcReset( PeiServices, EhciDevPtr ); + + // Do not do any periodic schedule related initialization + + // Clear status register - all R/WC bits + EhciHcOpReg->UsbSts.AllBits = + (EHCI_USB_INTERRUPT | // Interrupt + EHCI_USB_ERROR_INTERRUPT | // Error interrupt + EHCI_PORT_CHANGE_DETECT | // Port Change Detect + EHCI_FRAME_LIST_ROLLOVER | // Frame List Rollover + EHCI_HOST_SYSTEM_ERROR | // Host System Error + EHCI_INT_ASYNC_ADVANCE); // Interrupt on Async Advance + + // Turn HC on + EhciHcOpReg->UsbCmd.AllBits = EHCI_RUNSTOP | EHCI_INTTHRESHOLD; + + // Disconnect all ports from companion HC (if any) and route them to EHCI + EhciHcOpReg->ConfigFlag = 1; + + EHCI_FIXED_DELAY_MS(EhciDevPtr, 100); // 100msec delay to stabilize + +} + + +// +//--------------------------------------------------------------------------- +// +// Procedure: EhciHcReset +// +// Description: +// This function performs a software reset of the host controller. +// +// Input: +// IN EFI_PEI_SERVICES **PeiServices +// -- EFI_PEI_SERVICES pointer +// IN PEI_EHCI_DEV *EhciDevPtr +// -- PEI_EHCI_DEV pointer +// +// Output: +// VOID (Return Value) +// +// Notes: +// It is assumed that all necessary operational register data has been +// saved prior to calling this function. +// +//--------------------------------------------------------------------------- +// + +VOID EhciHcReset ( + EFI_PEI_SERVICES **PeiServices, + PEI_EHCI_DEV *EhciDevPtr ) +{ + UINT32 UsbCmd; + UINT8 Count; + + // Check HC is halted: attempting to reset an actively running HC will + // result in undefined behavior. + if (EhciDevPtr->EhciHcOpReg->UsbSts.Field.HCHalted == 0) + { + PEI_TRACE ((EFI_D_ERROR, PeiServices, "EHCI HC RESET ERROR: HC is running.\n")); + EhciDevPtr->HcStatus = EHCI_RESET_ERROR; + return; + } + + // Issue reset + UsbCmd = EhciDevPtr->EhciHcOpReg->UsbCmd.AllBits | EHCI_HCRESET; + EhciDevPtr->EhciHcOpReg->UsbCmd.AllBits = UsbCmd; + + // EHCI_HCRESET bit is set to zero by the Host Controller when the reset + // process is complete. + for (Count = 0; Count < 10; Count++) + { + EHCI_FIXED_DELAY_MS( EhciDevPtr, 10); // 10msec delay + if (EhciDevPtr->EhciHcOpReg->UsbCmd.Field.HcReset == 0) + { + return; + } + } + + PEI_TRACE ((EFI_D_ERROR, PeiServices, "EHCI HC RESET ERROR: timeout.\n")); + EhciDevPtr->HcStatus = EHCI_RESET_ERROR; + + return; +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: EhciReleasePortOwner +// +// Description: +// +// Input: +// +// Output: None +// +//---------------------------------------------------------------------------- +// + +VOID +EhciReleasePortOwner ( + EFI_PEI_SERVICES **PeiServices, + PEI_EHCI_DEV *EhciDevPtr, + UINT8 PortNumber +) +{ + EHCI_PORTSC *PortScReg = &EhciDevPtr->EhciHcOpReg->PortSC[PortNumber - 1]; + UINT8 i = 0; + + // Clear connect status change bit + PortScReg->Field.ConnectStatusChange = 1; + + // Release port owner + PortScReg->Field.PortOwner = 1; + for (i = 0; i < 20; i++) { + if (PortScReg->Field.ConnectStatusChange != 0) { + break; + } + EHCI_FIXED_DELAY_MS( EhciDevPtr, 1); // 1 msec delay + } + + PortScReg->Field.ConnectStatusChange = 1; +} + +// +//--------------------------------------------------------------------------- +// +// Procedure: EhciHcGetRootHubPortStatus +// +// Description: +// This function obtains the port status and port change status for +// a port specified by PortNumber and updates the EFI_USB_PORT_STATUS +// data structure as specified the the PortStatus pointer parameter. +// +// Input: +// IN EFI_PEI_SERVICES **PeiServices +// -- EFI_PEI_SERVICES pointer +// IN PEI_USB_HOST_CONTROLLER_PPI *This +// -- PEI_USB_HOST_CONTROLLER_PPI pointer +// IN UINT8 PortNumber +// -- Port number for which status is requested +// OUT EFI_USB_PORT_STATUS *PortStatus +// -- EFI_USB_PORT_STATUS pointer's data is updated +// +// Output: +// EFI_STATUS (Return Value) +// = EFI_SUCCESS on successful completion +// or valid EFI error code +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS EhciHcGetRootHubPortStatus ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 PortNumber, + OUT EFI_USB_PORT_STATUS *PortStatus ) +{ + PEI_EHCI_DEV *EhciDevPtr = PEI_RECOVERY_USB_EHCI_DEV_FROM_THIS( This ); + EHCI_PORTSC *PortScReg = &EhciDevPtr->EhciHcOpReg->PortSC[PortNumber - 1]; + UINT8 i = 0; + + if (PortNumber > EhciDevPtr->bNumPorts) { + return EFI_INVALID_PARAMETER; + } + + //PEI_TRACE((-1, PeiServices, "EHCI port[%d] status: %08x\n", PortNumber, PortScReg->AllBits)); + PortStatus->PortStatus = 0; + PortStatus->PortChangeStatus = 0; + + if (PortScReg->Field.CurrentConnectStatus != 0 && + PortScReg->Field.PortEnable == 0 && + PortScReg->Field.LineStatus == 0x1) { + EhciReleasePortOwner(PeiServices, EhciDevPtr, PortNumber); + } + + if (PortScReg->Field.CurrentConnectStatus != 0) { + PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION; + if (PortScReg->Field.PortEnable != 0) { + PortStatus->PortStatus |= USB_PORT_STAT_ENABLE; + PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED; + } + } + if (PortScReg->Field.ConnectStatusChange != 0) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION; + } + if (PortScReg->Field.PortEnableChange != 0) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE; + } + if (PortScReg->Field.OvercurrentActive != 0) { + PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT; + } + if (PortScReg->Field.OvercurrentChange != 0) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT; + } + if (PortScReg->Field.Suspend != 0) { + PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND; + } + if (PortScReg->Field.PortReset != 0) { + PortStatus->PortStatus |= USB_PORT_STAT_RESET; + } + if (PortScReg->Field.PortPower != 0) { + PortStatus->PortStatus |= USB_PORT_STAT_POWER; + } + if (PortScReg->Field.PortOwner != 1) { + PortStatus->PortStatus |= USB_PORT_STAT_OWNER; + } + if (EhciDevPtr->PortResetStatusChangeMap & (1 << (PortNumber - 1))) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET; + } + + return EFI_SUCCESS; + +} + +// +//--------------------------------------------------------------------------- +// +// Procedure: EhciHcGetRootHubPortNumber +// +// Description: +// This function returns the number of downstream ports as specified +// in the HcRhDescriptorA operational register. +// +// Input: +// IN EFI_PEI_SERVICES **PeiServices +// -- EFI_PEI_SERVICES pointer +// IN PEI_USB_HOST_CONTROLLER_PPI *This +// -- PEI_USB_HOST_CONTROLLER_PPI pointer +// OUT UINT8 *PortNumber +// -- Number of downstream ports +// +// Output: +// EFI_STATUS (Return Value) +// = EFI_SUCCESS on successful completion +// or valid EFI error code +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS EhciHcGetRootHubPortNumber ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + OUT UINT8 *PortNumber ) +{ + + PEI_EHCI_DEV *EhciDevPtr = PEI_RECOVERY_USB_EHCI_DEV_FROM_THIS( This ); + + if (PortNumber == NULL) { + return EFI_INVALID_PARAMETER; + } + + *PortNumber = EhciDevPtr->bNumPorts; + + return EFI_SUCCESS; +} + + +// +//--------------------------------------------------------------------------- +// +// Procedure: EhciHcSetRootHubPortFeature +// +// Description: +// This function sets port feature as specified by +// PortFeature for the port specified by PortNumber. +// +// Input: +// IN EFI_PEI_SERVICES **PeiServices +// -- EFI_PEI_SERVICES pointer +// IN PEI_USB_HOST_CONTROLLER_PPI *This +// -- PEI_USB_HOST_CONTROLLER_PPI pointer +// IN UINT8 PortNumber +// -- Port number whose feature is to be set +// IN EFI_USB_PORT_FEATURE PortFeature +// -- Feature to set +// +// Output: +// EFI_STATUS (Return Value) +// = EFI_SUCCESS on successful completion +// or valid EFI error code +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS EhciHcSetRootHubPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature ) +{ + PEI_EHCI_DEV *EhciDevPtr = PEI_RECOVERY_USB_EHCI_DEV_FROM_THIS( This ); + EHCI_PORTSC *PortScReg = &EhciDevPtr->EhciHcOpReg->PortSC[PortNumber - 1]; + UINT32 PortSc = 0; + UINT8 i = 0; + + if (PortNumber > EhciDevPtr->bNumPorts) { + return EFI_INVALID_PARAMETER; + } + + PortSc = PortScReg->AllBits; + PortSc &= ~(EHCI_CONNECTSTATUSCHANGE | EHCI_PORTENABLESTATUSCHANGE | EHCI_OVERCURRENTCAHGE); + + switch (PortFeature) { + case EfiUsbPortEnable: + break; + + case EfiUsbPortSuspend: + PortSc |= EHCI_SUSPEND; + break; + + case EfiUsbPortReset: + PortSc = PortScReg->AllBits; + PortSc &= ~(EHCI_CONNECTSTATUSCHANGE | EHCI_PORTENABLESTATUSCHANGE | EHCI_OVERCURRENTCAHGE); + PortScReg->AllBits = (PortSc & ~EHCI_PORTENABLE) | EHCI_PORTRESET; + EHCI_FIXED_DELAY_MS( EhciDevPtr, 50); // 50 msec delay + + PortSc = PortScReg->AllBits; + PortSc &= ~(EHCI_PORTRESET | EHCI_CONNECTSTATUSCHANGE | EHCI_PORTENABLESTATUSCHANGE | + EHCI_OVERCURRENTCAHGE); + PortScReg->AllBits = PortSc; + + for (i = 0; i < 10; i++) { + if (PortScReg->Field.PortReset == 0) { + break; + } + EHCI_FIXED_DELAY_MS( EhciDevPtr, 1); // 50 msec delay + } + + if (PortScReg->Field.PortEnable != 0) { + EhciDevPtr->PortResetStatusChangeMap |= (1 << (PortNumber - 1)); + } else { + EhciReleasePortOwner(PeiServices, EhciDevPtr, PortNumber); + } + //break; + return EFI_SUCCESS; + + case EfiUsbPortPower: + PortSc |= EHCI_PORTPOWER; + break; + + default: + return EFI_INVALID_PARAMETER; + } + PortScReg->AllBits = PortSc; + + return EFI_SUCCESS; +} + + +// +//--------------------------------------------------------------------------- +// +// Procedure: EhciHcClearRootHubPortFeature +// +// Description: +// This function clears an EHCI specification port feature as specified +// by PortFeature for the port specified by PortNumber. +// +// Input: +// IN EFI_PEI_SERVICES **PeiServices +// -- EFI_PEI_SERVICES pointer +// IN PEI_USB_HOST_CONTROLLER_PPI *This +// -- PEI_USB_HOST_CONTROLLER_PPI pointer +// IN UINT8 PortNumber +// -- Port number whose feature is to be set +// IN EFI_USB_PORT_FEATURE PortFeature +// -- Feature to set +// +// Output: +// EFI_STATUS (Return Value) +// = EFI_SUCCESS on successful completion +// or valid EFI error code +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS EhciHcClearRootHubPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature ) +{ + PEI_EHCI_DEV *EhciDevPtr = PEI_RECOVERY_USB_EHCI_DEV_FROM_THIS( This ); + UINT32 PortSc = 0; + + if (PortNumber > EhciDevPtr->bNumPorts) { + return EFI_INVALID_PARAMETER; + } + + PortSc = EhciDevPtr->EhciHcOpReg->PortSC[PortNumber - 1].AllBits; + PortSc &= ~(EHCI_CONNECTSTATUSCHANGE | EHCI_PORTENABLESTATUSCHANGE | EHCI_OVERCURRENTCAHGE); + + switch (PortFeature) { + case EfiUsbPortEnable: + PortSc &= ~EHCI_PORTENABLE; + break; + + case EfiUsbPortSuspend: + PortSc |= EHCI_FORCEPORTRESUME; + break; + + case EfiUsbPortReset: + PortSc &= ~EHCI_PORTRESET; + break; + + case EfiUsbPortPower: + PortSc &= ~EHCI_PORTPOWER; + break; + + case EfiUsbPortOwner: + //PortSc |= EHCI_PORTOWNER; + EhciReleasePortOwner(PeiServices, EhciDevPtr, PortNumber); + //break; + return EFI_SUCCESS; + + case EfiUsbPortConnectChange: + PortSc |= EHCI_CONNECTSTATUSCHANGE; + break; + + case EfiUsbPortEnableChange: + PortSc |= EHCI_PORTENABLESTATUSCHANGE; + break; + + case EfiUsbPortSuspendChange: + break; + + case EfiUsbPortOverCurrentChange: + PortSc |= EHCI_OVERCURRENTCAHGE; + break; + + case EfiUsbPortResetChange: + EhciDevPtr->PortResetStatusChangeMap &= ~(1 << (PortNumber - 1)); + //break; + return EFI_SUCCESS; + + default: + return EFI_INVALID_PARAMETER; + } + EhciDevPtr->EhciHcOpReg->PortSC[PortNumber - 1].AllBits = PortSc; + + return EFI_SUCCESS; +} + + +// +//---------------------------------------------------------------------------- +// Procedure: EHCIInitializeQueueHead +// +// Description: This function initializes the queue head with default values +// +// Input: fpQH Pointer to queue head +// +//---------------------------------------------------------------------------- +// + +VOID +EHCIInitializeQueueHead(EHCI_QH *fpQH) +{ + fpQH->dNextqTDPtr = 1; + fpQH->dAltNextqTDPtr = 1; + fpQH->dCurqTDPtr = 1; + + fpQH->dEndPntCap = QH_ONE_XFER; + fpQH->dToken = 0; + fpQH->dEndPntCharac = 0; + fpQH->dBufferPtr0 = 0; + fpQH->dBufferPtr1 = 0; + fpQH->dBufferPtr2 = 0; + fpQH->dBufferPtr3 = 0; + fpQH->dBufferPtr4 = 0; + fpQH->bErrorStatus = 0; +} + + +// +//---------------------------------------------------------------------------- +// Procedure: EHCISetQTDBufferPointers +// +// Description: This function will set the 5 buffer pointer in the qTD +// appropriately depending upon the input size +// +// Input: fpQtd - Pointer to the qTD +// fpBuf - 32bit absolute buffer pointer +// wSize - Amount of data to be transferred +// +// Output: None +// +//---------------------------------------------------------------------------- +// + +VOID +EHCISetQTDBufferPointers( + EHCI_QTD *fpQtd, + UINT8 *fpBuf, + UINT32 dSize +) +{ + UINT16 wBufSize; + UINT8 *fpBuffer = fpBuf; + UINT32 *fpBufferPtr; + UINT16 w4KRemainder; + + // + // Fill the buffer pointers with 0s + // + fpQtd->dBufferPtr0 = 0; + fpQtd->dBufferPtr1 = 0; + fpQtd->dBufferPtr2 = 0; + fpQtd->dBufferPtr3 = 0; + fpQtd->dBufferPtr4 = 0; + fpQtd->dAltNextqTDPtr = 1; + + // + // If size to transfer is 0 skip updating pointers + // + if (!dSize) + { + return; + } + + // + // Make sure the amount of data to be xferred is 16K or less + // + wBufSize = (UINT16)((dSize > PEI_MAX_EHCI_DATA_SIZE) ? PEI_MAX_EHCI_DATA_SIZE : dSize); + + fpBufferPtr = &fpQtd->dBufferPtr0; + + for (;;) + { + *fpBufferPtr = (UINT32)(UINTN)fpBuffer; + // + // Calculate the number of bytes that can be transferred using current + // buffer pointer + // + w4KRemainder = (UINT16)((((UINT32)((UINTN)fpBuffer+0x1000)) & 0xFFFFF000) - + (UINT32)(UINTN)fpBuffer); + + // + // Check whether all the bytes can be accomadated in the current buffer + // + if (w4KRemainder >= wBufSize) + { + break; // Yes. Current Buffer is sufficient for the rest of data + } + + // + // We have more data to transfer - adjust data and store it in the next pointer + // + wBufSize = (UINT16)(wBufSize - w4KRemainder); // Amount of data remaining + fpBuffer = fpBuffer + w4KRemainder; // Adjust buffer (4K bound) + fpBufferPtr++; // Next buffer pointer + } +} + + +// +//---------------------------------------------------------------------------- +// +// Procedure: EHCIStartAsyncSchedule +// +// Description: This function starts the asynchronous schedule +// +//---------------------------------------------------------------------------- +// + +VOID EHCIStartAsyncSchedule( + EHCI_HC_OPER_REG *HcOpReg +) +{ + // Start the Async schedule + HcOpReg->UsbCmd.AllBits |= EHCI_ASYNC_SCHED_ENABLE; + + // Make sure the HC started the async. execution + for (;HcOpReg->UsbSts.Field.AsyncSheduleStatus == 0;) {} +} + + +// +//---------------------------------------------------------------------------- +// +// Procedure: EHCIStopAsyncSchedule +// +// Description: This function stops the asynchronous transfer and sets the +// asynchronous pointer to null +// +//---------------------------------------------------------------------------- +// + +VOID EHCIStopAsyncSchedule( + EHCI_HC_OPER_REG *HcOpReg +) +{ + // Stop the Async schedule + HcOpReg->UsbCmd.AllBits &= ~EHCI_ASYNC_SCHED_ENABLE; + + // Make sure the HC stopped the async. execution + for (;HcOpReg->UsbSts.Field.AsyncSheduleStatus != 0;) {} +} + + +// +//---------------------------------------------------------------------------- +// Procedure: EHCIProcessQH +// +// Description: This function whether all the TD's in the QH is completed +// +// Input: fpQH - Pointer to the QH which has to be completed +// +//---------------------------------------------------------------------------- +// + +VOID EHCIProcessQH( + EHCI_QH *fpQH +) +{ + EHCI_QTD *fpQTD = fpQH->fpFirstqTD; + + for (;;) { + // + // Check whether the qTD is active, if so. Exit! + // + if (fpQTD->dToken & QTD_ACTIVE) { + return; // Not complete + } + + // + // Check for halt condition, if halted - exit + // + if (fpQTD->dToken & QTD_HALTED) { + // + // Set the QH halted status + // + fpQH->bErrorStatus = QTD_HALTED; + // + // Set the QH as in-active + // + fpQH->bActive = FALSE; + + return; // Complete + } + // + // qTD is not active and not halted. That is it is completed successfully + // Check whether this qTD is the last one in the list + // + if (fpQTD->dNextqTDPtr & EHCI_TERMINATE) { + // + // Set the QH as in-active + // + fpQH->bActive = FALSE; + return; // Complete + } + // + // More qTDs are in the list. Process next qTD + // + fpQTD = (EHCI_QTD*)(UINTN)fpQTD->dNextqTDPtr; + } +} + + +// +//---------------------------------------------------------------------------- +// +// Procedure: EHCIWaitForAsyncTransferComplete +// +// Description: This function waits for asynchronous transfer completion. +// +//---------------------------------------------------------------------------- +// + +VOID EHCIWaitForAsyncTransferComplete ( + EFI_PEI_SERVICES **PeiServices, + PEI_EHCI_DEV *EhciDevPtr, + EHCI_QH *QHead +) +{ + UINT32 Count; + UINT32 TimeOut = 15000; // 5 sec + + for(Count = 0; Count < TimeOut; Count++) + { + EHCIProcessQH(QHead); + + if(QHead->bActive == FALSE) + { + return; + } + EHCI_FIXED_DELAY_MS( EhciDevPtr, 1); // 1 msec delay + } + + PEI_TRACE ((EFI_D_ERROR, PeiServices, "EHCI Time-Out:\n")); +} + + +// +//--------------------------------------------------------------------------- +// +// Procedure: EhciHcControlTransfer +// +// Description: +// This function intiates a USB control transfer and waits on it to +// complete. +// +// Input: +// IN EFI_PEI_SERVICES **PeiServices +// -- EFI_PEI_SERVICES pointer +// IN PEI_USB_HOST_CONTROLLER_PPI *This +// -- PEI_USB_HOST_CONTROLLER_PPI pointer +// IN UINT8 bDeviceAddress +// -- USB address of the device for which the control +// transfer is to be issued +// IN UINT8 DeviceSpeed +// -- Not used +// IN UINT8 MaximumPacketLength +// -- Maximum number of bytes that can be sent to or +// received from the endpoint in a single data packet +// IN EFI_USB_DEVICE_REQUEST *Request +// -- EFI_USB_DEVICE_REQUEST pointer +// IN EFI_USB_DATA_DIRECTION TransferDirection +// -- Direction of transfer +// OPTIONAL IN OUT VOID *DataBuffer +// -- Pointer to source or destination buffer +// OPTIONAL IN OUT UINTN *DataLength +// -- Length of buffer +// IN UINTN TimeOut +// -- Not used +// OUT UINT32 *TransferResult +// -- Not used +// +// Output: +// EFI_STATUS (Return Value) +// = EFI_SUCCESS on successful completion +// or valid EFI error code +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS EhciHcControlTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 bDeviceAddress, + IN UINT8 DeviceSpeed, + IN UINT8 MaximumPacketLength, + IN UINT16 TransactionTranslator OPTIONAL, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION TransferDirection, + IN OUT VOID *DataBuffer OPTIONAL, + IN OUT UINTN *DataLength OPTIONAL, + IN UINTN TimeOut, + OUT UINT32 *TransferResult ) +{ + UINT16 WordRequest; + UINT16 WordIndex; + UINT16 WordValue; + EFI_STATUS Status = EFI_SUCCESS; + + + PEI_EHCI_DEV *EhciDevPtr = PEI_RECOVERY_USB_EHCI_DEV_FROM_THIS( This ); + EHCI_HC_OPER_REG *HcOpReg = EhciDevPtr->EhciHcOpReg; + EHCI_DESC_PTRS *DescPtrs = &EhciDevPtr->stEHCIDescPtrs; + UINT16 wLength = (DataLength != NULL)? (UINT16) *DataLength : 0; + EHCI_QH *fpQHCtl; + EHCI_QTD *fpQTDCtlSetup, *fpQTDCtlData, *fpQTDCtlStatus; + + UINT32 dTmp, dTmp1; + + WordRequest = (Request->Request << 8) | Request->RequestType; + WordValue = Request->Value; + WordIndex = Request->Index; + + // + // Intialize the queue head with null pointers + // + fpQHCtl = DescPtrs->fpQHControl; + EHCIInitializeQueueHead(fpQHCtl); + + // + // Assume as a high speed device + // + dTmp = QH_HIGH_SPEED; // 10b - High speed + + if (DeviceSpeed != USB_HIGH_SPEED_DEVICE && TransactionTranslator != 0) + { + // Low/Full speed device OR device is connected to a root port + // DeviceSpeed = 1 (low) or 2 (full) + dTmp = (UINT32)((DeviceSpeed & 1) << 12); // Bit 12 = full/low speed flag + dTmp |= QH_CONTROL_ENDPOINT; + // + // Set the hub address and port number + // + dTmp1 = (TransactionTranslator << 16) | (BIT10+BIT11+BIT12); // Split complete Xaction + fpQHCtl->dEndPntCap |= dTmp1; + } + + dTmp |= (QH_USE_QTD_DT | QH_HEAD_OF_LIST); + dTmp |= (UINT32)bDeviceAddress; + + // + // dTmp[Bits 6:0] = Dev. Addr + // dTmp[Bit7] = I bit(0) + // dTmp[Bits11:8] = Endpoint (0) + // + dTmp1 = MaximumPacketLength; + dTmp |= (dTmp1 << 16); // Tmp[Bits26:16] = device's packet size + fpQHCtl->dEndPntCharac = dTmp; + + // + // Fill in various fields in the qTDControlSetup. + // + fpQTDCtlSetup = DescPtrs->fpqTDControlSetup; + + // + // The token field will be set so + // Direction PID = QTD_SETUP_TOKEN, + // Size = size of the data, + // Data Toggle = QTD_SETUP_TOGGLE, + // Error Count = QTD_NO_ERRORS, + // Status code = QTD_DO_OUT + QTD_ACTIVE + // The buffer pointers field will point to the aControlSetupData buffer + // which was before initialized to contain a DeviceRequest struc. + // The dNextqTDPtr field will point to the qTDControlData if data will + // be sent/received or to the qTDControlStatus if no data is expected. + // The dAltNextqTDPtr field will be set to EHCI_TERMINATE + // + fpQTDCtlSetup->dToken = QTD_SETUP_TOKEN | QTD_SETUP_TOGGLE | QTD_IOC_BIT | + QTD_NO_ERRORS | QTD_DO_OUT | QTD_ACTIVE | + (8 << 16); // Data size + + // + // Update buffer pointers + // + EHCISetQTDBufferPointers(fpQTDCtlSetup, + (UINT8*)Request, + 8); + fpQTDCtlData = DescPtrs->fpqTDControlData; + + if (wLength != 0 && DataBuffer != NULL) // br if no data to transfer + { + // + // Fill in various fields in the qTDControlData + // + // The token field will be set so + // Direction PID = QTD_OUT_TOKEN/QTD_IN_TOKEN, + // Size = size of the data, + // Data Toggle = QTD_DATA1_TOGGLE, + // Error Count = QTD_NO_ERRORS, + // Status code = QTD_DO_OUT(if it is out) + QTD_ACTIVE + // The buffer pointers field will point to the fpBuffer buffer + // which was before initialized to contain a DeviceRequest struc. + // The dNextqTDPtr field will point to the qTDControlSetup + // The dAltNextqTDPtr field will be set to EHCI_TERMINATE + // + fpQTDCtlData->dToken = QTD_IN_TOKEN | + QTD_DATA1_TOGGLE | QTD_IOC_BIT | + QTD_NO_ERRORS | QTD_ACTIVE; + if ((WordRequest & BIT7) == 0) // Br if host sending data to device (OUT) + { + fpQTDCtlData->dToken = QTD_OUT_TOKEN | + QTD_DATA1_TOGGLE | QTD_IOC_BIT | + QTD_NO_ERRORS | QTD_DO_OUT | QTD_ACTIVE; + } + + // + // Set length + // + fpQTDCtlData->dToken |= ((UINT32)wLength << 16); + + // + // Update buffer pointers + // + EHCISetQTDBufferPointers(fpQTDCtlData, + (UINT8*)DataBuffer, + (UINT32)wLength); + } + + // + // Fill in various fields in the qTDControlStatus + // + fpQTDCtlStatus = DescPtrs->fpqTDControlStatus; + + // + // The token field will be set so + // Direction PID = QTD_OUT_TOKEN/QTD_IN_TOKEN, + // Size = 0, + // Data Toggle = QTD_DATA1_TOGGLE, + // Error Count = QTD_NO_ERRORS, + // Status code = QTD_DO_OUT(if it is out) + QTD_ACTIVE + // The buffer pointers field will be 0 + // The dNextqTDPtr field will set to EHCI_TERMINATE + // The dAltNextqTDPtr field will be set to EHCI_TERMINATE + // + // For OUT control transfer status should be IN and + // for IN cotrol transfer, status should be OUT + // + fpQTDCtlStatus->dToken = QTD_IN_TOKEN | + QTD_DATA1_TOGGLE | QTD_IOC_BIT | + QTD_NO_ERRORS | QTD_ACTIVE; + if((WordRequest & BIT7) != 0) + { + fpQTDCtlStatus->dToken = QTD_OUT_TOKEN | + QTD_DATA1_TOGGLE | QTD_IOC_BIT | + QTD_NO_ERRORS | QTD_DO_OUT | QTD_ACTIVE; + } + + EHCISetQTDBufferPointers(fpQTDCtlStatus, NULL, 0); + + // + // Link the qTD formed now and connect them with the control queue head + // + fpQHCtl->fpFirstqTD = fpQTDCtlSetup; + fpQHCtl->dNextqTDPtr = (UINT32)(UINTN)fpQTDCtlSetup; + + if (wLength != 0) + { + fpQTDCtlSetup->dNextqTDPtr = (UINT32)(UINTN)fpQTDCtlData; + fpQTDCtlData->dNextqTDPtr = (UINT32)(UINTN)fpQTDCtlStatus; + } + else + { + fpQTDCtlSetup->dNextqTDPtr = (UINT32)(UINTN)fpQTDCtlStatus; + } + + fpQTDCtlStatus->dNextqTDPtr = EHCI_TERMINATE; + + // + // Set the ASYNCLISTADDR register to point to the QHControl + // + HcOpReg->AsyncListAddr = (UINT32)(UINTN)fpQHCtl; + + // + // Set next QH pointer to itself (circular link) + // + fpQHCtl->dLinkPointer = (UINT32)((UINTN)fpQHCtl | EHCI_QUEUE_HEAD); + fpQHCtl->bActive = TRUE; + + // + // Now put the control setup, data and status into the HC's schedule by + // setting the Async. schedule enabled field of USBCMD register + // This will cause the HC to execute the transaction in the next active frame. + // + EHCIStartAsyncSchedule(HcOpReg); + + EHCIWaitForAsyncTransferComplete(PeiServices, EhciDevPtr, fpQHCtl); + + // + // Stop the Async transfer + // + EHCIStopAsyncSchedule(HcOpReg); + + // + // Check whether the QH stopped or timed out + // + if (fpQHCtl->bActive == TRUE) + { + + fpQHCtl->bActive = FALSE; + } + else + { + // + // Check for the stall condition + // + if (fpQHCtl->bErrorStatus & QTD_HALTED) + { + // + // Command stalled set the error bit appropriately + // + Status = EFI_DEVICE_ERROR; + } + } + + fpQHCtl->fpFirstqTD = 0; + fpQHCtl->dNextqTDPtr = EHCI_TERMINATE; + + return Status; +} + + +// +//--------------------------------------------------------------------------- +// +// Procedure: EhciHcBulkTransfer +// +// Description: +// This function intiates a USB bulk transfer and waits on it to +// complete. +// +// Input: +// IN EFI_PEI_SERVICES **PeiServices +// -- EFI_PEI_SERVICES pointer +// IN PEI_USB_HOST_CONTROLLER_PPI *This +// -- PEI_USB_HOST_CONTROLLER_PPI pointer +// IN UINT8 DeviceAddress +// -- USB address of the device for which the control +// transfer is to be issued +// IN UINT8 EndPointAddress +// -- Particular endpoint for the device +// IN UINT8 MaximumPacketLength +// -- Maximum number of bytes that can be sent to or +// received from the endpoint in a single data packet +// OPTIONAL IN OUT VOID *DataBuffer +// -- Pointer to source or destination buffer +// OPTIONAL IN OUT UINTN *DataLength +// -- Length of buffer +// IN OUT UINT8 *DataToggle +// -- Used to update the control/status DataToggle field +// of the Transfer Descriptor +// IN UINTN TimeOut +// -- Not used +// OUT UINT32 *TransferResult +// -- Not used +// +// Output: +// EFI_STATUS (Return Value) +// = EFI_SUCCESS on successful completion +// or valid EFI error code +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS EhciHcBulkTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINT16 MaximumPacketLength, + IN UINT16 TransactionTranslator OPTIONAL, + IN OUT VOID *DataBuffer, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult ) +{ + PEI_EHCI_DEV *EhciDevPtr = PEI_RECOVERY_USB_EHCI_DEV_FROM_THIS( This ); + EHCI_HC_OPER_REG *HcOpReg = EhciDevPtr->EhciHcOpReg; + EHCI_DESC_PTRS *DescPtrs = &EhciDevPtr->stEHCIDescPtrs; + EFI_STATUS Status = EFI_SUCCESS; + UINT32 dBytesToTransfer; + UINT32 dTmp, dTmp1; + EHCI_QH *fpQHBulk; + EHCI_QTD *fpQTDBulkData; + +//PEI_TRACE ((EFI_D_ERROR, PeiServices, "bulk..%x, device address %d\n", *DataLength, DeviceAddress)); + + dBytesToTransfer = + (*DataLength < PEI_MAX_EHCI_DATA_SIZE)? (UINT32)*DataLength : PEI_MAX_EHCI_DATA_SIZE; + + // + // Set the QH's dNextqTDPtr field to bulk data qTD and dAltqTDPtr field to + // EHCI_TERMINATE. Also set QH's link pointer to itself + // + fpQHBulk = DescPtrs->fpQHBulk; + fpQTDBulkData = DescPtrs->fpqTDBulkData; + + // + // Intialize the queue head + // + EHCIInitializeQueueHead(fpQHBulk); + + // + // Set the first qTD pointer + // + fpQHBulk->fpFirstqTD = fpQTDBulkData; + fpQHBulk->dNextqTDPtr = (UINT32)(UINTN)fpQTDBulkData; + fpQHBulk->dLinkPointer = (UINT32)((UINTN)fpQHBulk | EHCI_QUEUE_HEAD); + + // + // Device address, Endpoint, max packet size, data toggle control + // + dTmp = (UINT32)(DeviceAddress | (EndPointAddress << 8)); + dTmp |= ((UINT32)MaximumPacketLength << 16); + dTmp |= (QH_USE_QTD_DT | QH_HEAD_OF_LIST); + + // + // Assume as a high speed device + // + dTmp |= QH_HIGH_SPEED; // 10b - High speed + + if (DeviceSpeed != USB_HIGH_SPEED_DEVICE && TransactionTranslator != 0) + { + // Note: low speed bulk endpoints are not supported + dTmp1 = BIT12; // Bit 12 = full speed flag + dTmp &= ~(QH_ENDPOINT_SPEED); + dTmp |= dTmp1; + // + // Set the hub address and port number + // + dTmp1 = (TransactionTranslator << 16) | BIT14; // Hispeed hub port number & device number + fpQHBulk->dEndPntCap |= dTmp1; // Split complete Xaction + } + + // + // Update the endpoint characteristcs field with the data formed + // + fpQHBulk->dEndPntCharac = dTmp; + + // + // Fill the bulk data qTD with relevant information + // + if ((EndPointAddress & BIT7) != 0) + { + fpQTDBulkData->dToken = QTD_IN_TOKEN | + QTD_IOC_BIT | + QTD_NO_ERRORS | QTD_ACTIVE; + } + else + { + fpQTDBulkData->dToken = QTD_OUT_TOKEN | + QTD_IOC_BIT | + QTD_NO_ERRORS | QTD_DO_OUT | QTD_ACTIVE; + } + + // + // Set the data toggle depending on the DatToggle value + // + fpQTDBulkData->dToken |= ((UINT32)(*DataToggle)) << 31; + + // + // Set length + // + fpQTDBulkData->dToken |= (dBytesToTransfer << 16); + + // + // Update buffer pointers + // + EHCISetQTDBufferPointers( + fpQTDBulkData, (UINT8*)DataBuffer, dBytesToTransfer); + + // + // Update next & alternate next qTD pointers + // + fpQTDBulkData->dNextqTDPtr = EHCI_TERMINATE; + fpQTDBulkData->dAltNextqTDPtr = EHCI_TERMINATE; + + // + // Set the ASYNCLISTADDR register to point to the QHBulk + // + HcOpReg->AsyncListAddr = (UINT32)(UINTN)fpQHBulk; + + fpQHBulk->bActive = TRUE; + + // + // Now put the bulk QH into the HC's schedule by + // setting the Async. schedule enabled field of USBCMD register + // This will cause the HC to execute the transaction in the next active frame. + // + EHCIStartAsyncSchedule(HcOpReg); + + EHCIWaitForAsyncTransferComplete(PeiServices, EhciDevPtr, fpQHBulk); + + // + // Stop the Async transfer + // + EHCIStopAsyncSchedule(HcOpReg); + + dTmp = 0; // Return value + + // + // Check whether the QH stopped or timed out + // + if(fpQHBulk->bActive == TRUE) + { + + fpQHBulk->bActive = FALSE; + + // + // TODO: Set time out status + // + Status = EFI_DEVICE_ERROR; + } + else + { + // + // Check for the error conditions - if possible recover from them + // + if (fpQHBulk->bErrorStatus & QTD_HALTED) + { + // + // TODO:: Indicate Stall condition + // + Status = EFI_DEVICE_ERROR; + } + else + { + dTmp = 0xFFFFFFFF; // Indicate success + } + } + if (dTmp != 0) + { + *DataToggle = (UINT8)(((fpQHBulk->dToken & QH_DATA_TOGGLE) >> 31) & 1); + // + // Get the size of data transferred + // + dTmp = (fpQTDBulkData->dToken & ~(QTD_DATA_TOGGLE)) >> 16; + dTmp = (dTmp != 0)? dBytesToTransfer-dTmp : dBytesToTransfer; + } + + fpQHBulk->fpFirstqTD = 0; + fpQHBulk->dNextqTDPtr = EHCI_TERMINATE; + + *DataLength = (UINTN)dTmp; + return Status; +} + + +// +//---------------------------------------------------------------------------- +// Procedure: DwordReadMem +// +// Description: This routine reads a DWORD from the specified Memory Address +// +// Input: dBaseAddr - Memory address to read +// bOffset - Offset of dBaseAddr +// +// Output: Value read +// +//---------------------------------------------------------------------------- +// + +UINT32 +DwordReadMem(UINT32 dBaseAddr, UINT16 wOffset) +{ + return *(volatile UINT32*)(UINTN)(dBaseAddr+wOffset); +} + + +// +//---------------------------------------------------------------------------- +// Procedure: DwordWriteMem +// +// Description: This routine writes a DWORD to a specified Memory Address +// +// Input: dBaseAddr - Memory address to write +// bOffset - Offset of dBaseAddr +// dValue - Data to write +// +//---------------------------------------------------------------------------- +// + +VOID +DwordWriteMem(UINT32 dBaseAddr, UINT16 wOffset, UINT32 dValue) +{ + *(volatile UINT32*)(UINTN)(dBaseAddr+wOffset) = dValue; +} + +// +//---------------------------------------------------------------------------- +// Procedure: NotifyOnRecoveryCapsuleLoaded +// +// Description: This routine halts the all available EHCI host controller +// +// Input: PeiServices +// dMemAddr - EHCI HC Mem_Base address +// +//---------------------------------------------------------------------------- +// +EFI_STATUS NotifyOnRecoveryCapsuleLoaded ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, + IN VOID *InvokePpi ) +{ + //(EIP99922)> + EFI_PEI_STALL_PPI *StallPpi = NULL; + EFI_GUID gPeiStallPpiGuid = EFI_PEI_STALL_PPI_GUID; + EFI_STATUS Status; + UINT8 ControllerIndex = 0; + EHCI_HC_CAP_REG *EhciHcCapReg; + EHCI_HC_OPER_REG *EhciHcOpReg; + UINTN i; + UINT8 ByteData; + UINT32 EhciBaseAddress; + + // Locate PeiStall + Status = (**PeiServices).LocatePpi ( + PeiServices, + &gPeiStallPpiGuid, + 0, + NULL, + &StallPpi + ); + + for ( ControllerIndex = 0; ControllerIndex < gEhciControllerCount; ControllerIndex++) { + + EhciBaseAddress = EhciGetOperationalRegisterBase(PeiServices, ControllerIndex); + + // + // Read the Capability Registers Length to find the Offset address for the + // beginning of the operational registers and set bMemAddr to its offset + // + EhciHcCapReg = (EHCI_HC_CAP_REG*)EhciBaseAddress; + EhciHcOpReg = (EHCI_HC_OPER_REG *)((UINTN)EhciHcCapReg + EhciHcCapReg->CapLength); + + // Stop periodic schedule + EhciHcOpReg->UsbCmd.AllBits &= ~EHCI_PER_SCHED_ENABLE; + for (i = 0; i < 100; i++) { + StallPpi->Stall (PeiServices, StallPpi, 10); // 10us delay + if (EhciHcOpReg->UsbSts.Field.PeriodicSheduleStatus == 0) { + break; + } + } + EhciHcOpReg->PeriodicListBase = 0; + + // Clear USB status register + EhciHcOpReg->UsbSts.AllBits = EhciHcOpReg->UsbSts.AllBits; + // + // Check HC is runnning, if so STOP before proceeding + // + if (EhciHcOpReg->UsbSts.Field.HCHalted == 0) { + EhciHcOpReg->UsbCmd.AllBits &= ~(EHCI_RUNSTOP | EHCI_PER_SCHED_ENABLE); + for (i = 0; i < 16; i++) { + StallPpi->Stall (PeiServices, StallPpi, 125); // 125us delay + if (EhciHcOpReg->UsbSts.Field.HCHalted) { + break; + } + } + } + + // Reset controller + EhciHcOpReg->UsbCmd.Field.HcReset = 1; + for (i = 0; i < 100; i++) { + StallPpi->Stall (PeiServices, StallPpi, 1000); // 1ms delay + if (EhciHcOpReg->UsbCmd.Field.HcReset == 0) { + break; + } + } + + ByteData= 0; + (*PeiServices)->PciCfg->Write( PeiServices, (*PeiServices)->PciCfg, + EfiPeiPciCfgWidthUint8, + gEhciControllerPciTable[ControllerIndex] + EHCI_CMD_REGISTER, + &ByteData); + + EhciBaseAddress = 0; + (*PeiServices)->PciCfg->Write( PeiServices, (*PeiServices)->PciCfg, + EfiPeiPciCfgWidthUint32, + gEhciControllerPciTable[ControllerIndex] + EHCI_BASE_ADDR_REG, + &EhciBaseAddress); + }//end of for + //<(EIP99922) + + return EFI_SUCCESS; +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2009, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** \ No newline at end of file diff --git a/Core/EM/UsbRecovery/EhciPEI/EhciPei.cif b/Core/EM/UsbRecovery/EhciPEI/EhciPei.cif new file mode 100644 index 0000000..6bc2930 --- /dev/null +++ b/Core/EM/UsbRecovery/EhciPEI/EhciPei.cif @@ -0,0 +1,10 @@ + + name = "EhciPei" + category = ModulePart + LocalRoot = "core\em\UsbRecovery\EhciPEI\" + RefName = "EhciPei" +[files] +"EhciPei.c" +"EhciPei.h" +"EhciPeiBoard.c" + diff --git a/Core/EM/UsbRecovery/EhciPEI/EhciPei.h b/Core/EM/UsbRecovery/EhciPEI/EhciPei.h new file mode 100644 index 0000000..7f7c2c6 --- /dev/null +++ b/Core/EM/UsbRecovery/EhciPEI/EhciPei.h @@ -0,0 +1,592 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2009, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// +// $Header: /Alaska/SOURCE/Modules/USBRecovery/EhciPei.h 8 11/24/12 5:44a Ryanchou $ +// +// $Revision: 8 $ +// +// $Date: 11/24/12 5:44a $ +// +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USBRecovery/EhciPei.h $ +// +// 8 11/24/12 5:44a Ryanchou +// [TAG] EIP103990 +// [Category] Improvement +// [Description] Synchronized with USB PEI module 4.6.3_USB_08.10.24. +// [Files] EhciPei.c, EhciPei.h, OhciPei.c, OhciPei.h, UhcPeim.c, +// BotPeim.c, BotPeim.h, PeiAtapi.c, UsbBotPeim.c, UsbBotPeim.h, +// HubPeim.c, UsbPeim.c, XhciPei.c, XhciPei.h, HubPeim.h, PeiUsbLib.c, +// PeiUsbLib.h, UsbPeim.h +// +// 7 8/23/12 9:58p Wilsonlee +// [TAG] EIP97069 +// [Category] Improvement +// [Description] Reset root port algorythm update. +// [Files] EhciPei.c, EhciPei.h, OhciPei.c, OhciPei.h, UhcPeim.c, +// UhcPeim.h, UsbPeim.c, usb.h +// +// 6 1/18/11 12:53a Ryanchou +// [TAG] EIP47931 +// [Category] Improvement +// [Description] Added USB 3.0 hub support. +// [Files] EhciPei.c, EhciPei.h, HubPeim.c, HubPeim.h, OhciPei.c, +// OhciPei.h, UhcPeim.c, UhcPeim.h, usb.h, UsbHostController.h, +// UsbIoPeim.c, UsbPeim.c, UsbPeim.h, XhciPei.c, XhciPei.h +// +// 5 4/26/10 4:16p Krishnakumarg +// DebugRx causes the system to hang in Recovery mode EIP#34401 +// +// 4 7/30/09 6:23p Krishnakumarg +// Symptom :During recovery,system hangs while entering setup. +// RootCause:USB Host controller Status registers are not cleared and HC +// is not HALTed after loading recovery capsule. +// Solution: HC is set to HALT state after loading recovery module so USB +// driver clears the status Registers. +// +// 3 5/01/09 9:27a Rameshr +// Symptom :Sometime system hang on recovery path. +// Issue: Optimization makes Usbstatus value not updated from memory +// everytime before checking it. +// Solution: UsbStatus made as Volatile to get the current data from +// memory before checking. +// +// 2 3/17/09 5:08p Olegi +// Added TransactionTranslator for slow/full speed devices behind USB2 +// hub. +// +// 1 3/03/09 7:28p Olegi +// +//********************************************************************** + +// +//---------------------------------------------------------------------------- +// +// Name: EhciPei.h +// +// Description: This file is the main header file for the EHCI PEI USB +// recovery module. It contains generic constant and type +// declarations/definitions. +// +//---------------------------------------------------------------------------- +// + +#ifndef _EHCIPEI_H +#define _EHCIPEI_H + +#include "Efi.h" +#include "Pei.h" +#include "Ppi\UsbHostController.h" +#include "AmiMapping.h" + +//---------------------------------------------------------------------------- +// EHCI_FIXED_DELAY_MS( EhciDevPtr, milliseconds ) +// +// invokes a delay specified in milliseconds using the PEI_EHCI_DEV.StallPpi +// member interface pointer, which is initialized from a EFI_PEI_STALL_PPI +// interface. +#define EHCI_FIXED_DELAY_MS( EhciDevPtr, milliseconds ) \ + EhciDevPtr->StallPpi->Stall( EhciDevPtr->PeiServices, \ + EhciDevPtr->StallPpi, milliseconds * 1000 ); + + +//---------------------------------------------------------------------------- +// PEI_RECOVERY_USB_EHCI_DEV_FROM_THIS( a ) +// +// uses the _CR macro to obtain a pointer to a PEI_EHCI_DEV structure from +// a PEI_USB_HOST_CONTROLLER_PPI interface pointer +#define _CR( Record, TYPE, Field ) \ + ( (TYPE *) ( (CHAR8 *) (Record) - (CHAR8 *) &( ( (TYPE *) 0 )->Field ) ) ) +#define PEI_RECOVERY_USB_EHCI_DEV_FROM_THIS( a ) \ + _CR( a, PEI_EHCI_DEV, UsbHostControllerPpi ) + + +//---------------------------------------------------------------------------- +// Constants +// +// Notes: +// 1) These constants are not associated with a particular structure +// and are used globally withing EHCI-specific code +//---------------------------------------------------------------------------- + + + +// Standard EHCI PCI configuration space registers +#define EHCI_BASE_ADDR_REG 0x10 // EHCI BAR register +#define EHCI_CMD_REGISTER 0x04 // EHCI command register +#define DEBUG_BASE 0x5A // DEBUG_BASE offset address + +// EHCI controller status definitions +#define EHCI_RESET_ERROR BIT0 +#define EHCI_VERCAPLENGTH 0 // Interface Version and Capability +#define EHCI_USBCMD_REG 0 // USB Command + +// Bit definition for queue transfer descriptor token fields +//------------------------------------------------------------------------- +#define QTD_DATA_TOGGLE 0x80000000 // BIT 31 + #define QTD_SETUP_TOGGLE 0x00000000 + #define QTD_DATA0_TOGGLE 0x00000000 + #define QTD_DATA1_TOGGLE 0x80000000 + #define QTD_STATUS_TOGGLE 0x80000000 +#define QTD_XFER_DATA_SIZE 0x7FFF0000 // BIT 30:16 +#define QTD_IOC_BIT 0x00008000 // BIT 15 +#define QTD_ERROR_COUNT 0x00000C00 + #define QTD_NO_ERRORS 0x00000000 + #define QTD_ONE_ERROR 0x00000400 + #define QTD_TWO_ERRORS 0x00000800 + #define QTD_THREE_ERRORS 0x00000C00 +#define QTD_DIRECTION_PID 0x00000300 + #define QTD_OUT_TOKEN 0x00000000 + #define QTD_IN_TOKEN 0x00000100 + #define QTD_SETUP_TOKEN 0x00000200 +#define QTD_STATUS_FIELD 0x000000FF + #define QTD_ACTIVE 0x00000080 + #define QTD_HALTED 0x00000040 + #define QTD_BUFFER_ERROR 0x00000020 + #define QTD_BABBLE 0x00000010 + #define QTD_XACT_ERROR 0x00000008 + #define QTD_MISSED_UFRAME 0x00000004 + #define QTD_SPLIT_XSTATE 0x00000002 + #define QTD_START_SPLIT 0x00000000 + #define QTD_COMPLETE_SPLIT 0x00000002 + #define QTD_SPLIT_ERROR 0x00000001 + #define QTD_PING_STATE 0x00000001 + #define QTD_DO_OUT 0x00000000 + #define QTD_DO_PING 0x00000001 +//------------------------------------------------------------------------- + +#define QH_I_BIT 0x00000080 // BIT 7 +#define QH_ENDPOINT_SPEED 0x00003000 // BIT 13:12 + #define QH_FULL_SPEED 0x00000000 + #define QH_LOW_SPEED 0x00001000 + #define QH_HIGH_SPEED 0x00002000 +#define QH_DATA_TOGGLE_CONTROL 0x00004000 // BIT 14 + #define QH_IGNORE_QTD_DT 0x00000000 + #define QH_USE_QTD_DT 0x00004000 +#define QH_HEAD_OF_LIST 0x00008000 // BIT 15 +#define QH_CONTROL_ENDPOINT 0x08000000 // BIT 27 +#define QH_DATA_TOGGLE 0x80000000 // BIT 31 + +#define QH_MULT_SETTING 0xC0000000 // BIT 31:30 + #define QH_ONE_XFER 0x40000000 + #define QH_TWO_XFER 0x80000000 + #define QH_THREE_XFER 0xC0000000 + +#define EHCI_QUEUE_HEAD 2 // Queue head id + + +#define EHCI_TERMINATE 1 + +//---------------------------------------------------------------------------- +// Structure types +// +// Notes: +// 1) Constants that are associated with a particular structure +// are defined locally within the structure to facilitate easier +// maintenance. +//---------------------------------------------------------------------------- + +#pragma pack(push,1) + + +// +// Notes: +// To ensure proper updating, follow these guidelines: +// +// 1) Write all bits using the AllBits union element +// (OR bit-constants if modifying multiple fields). +// +// * Writing individual bits may have adverse +// effects. +// +// 2) Typically you will read individual bits using the +// Field union element. +// +// 3) Writing a zero to any field in this register has +// no effect. +// + +typedef struct _EHCI_HCS_PARAMS +{ + union { + UINT32 AllBits; + #define EHCI_HCSP_N_PORTS (BIT0+BIT1+BIT2+BIT3) + #define EHCI_HCSP_PPC BIT4 + #define EHCI_HCSP_PRR BIT7 + #define EHCI_HCSP_N_PCC (BIT8+BIT9+BIT10+BIT11) + #define EHCI_N_CC (BIT12+BIT13+BIT14+BIT15) + #define EHCI_P_INDICATOR BIT16 + #define EHCI_DEBUG_N (BIT20+BIT21+BIT22+BIT23) + struct + { + UINT32 NumberOfPorts : 4; // [3:0] + UINT32 PortPowerControl : 1; // [4] + UINT32 Reserved1 : 2; // [6:5] + UINT32 PortRoutingRules : 1; // [7] + UINT32 PortPerCompanion : 4; // [11:8] + UINT32 NumberOfCompanions : 4; // [15:12] + UINT32 PortIndicators : 1; // [16] + UINT32 Reserved2 : 3; // [19:17] + UINT32 DebugPortNumber : 4; // [23:20] + UINT32 Reserved3 : 8; // [31:24] + } Field; + }; +} EHCI_HCS_PARAMS; + +typedef struct _EHCI_HCC_PARAMS +{ + union { + UINT32 AllBits; + #define EHCI_64BIT_CAP 0x01 // 64-bit addressing capability + #define EHCI_PFLFLAG 0x02 // Programmable Frame List Flag + #define EHCI_ASP_CAP 0x04 // Asynchronous Schedule Park Capability + #define EHCI_IST 0xF0 // Isochronous Scheduling Threshold + #define EHCI_EECP 0xFF00 // EHCI Extended Capabilities Pointer + struct + { + UINT32 AddressingCap64 : 1; // [0] + UINT32 FrameListFlag : 1; // [1] + UINT32 AsyncShedParkCap : 1; // [2] + UINT32 Reserved1 : 1; // [3] + UINT32 IsochShedThreshold : 4; // [7:4] + UINT32 ExtCapPointer : 8; // [15:8] + UINT32 Reserved2 : 16; // [31:8] + } Field; + }; +} EHCI_HCC_PARAMS; + +typedef struct _EHCI_HC_CAP_REG { + UINT8 CapLength; + UINT8 Reserved; + UINT16 HciVersion; + EHCI_HCS_PARAMS HcsParams; + EHCI_HCC_PARAMS HccParams; + UINT8 HcspPortRoute[15]; +} EHCI_HC_CAP_REG; + + +typedef struct _EHCI_USBCMD +{ + union { + UINT32 AllBits; + #define EHCI_RUNSTOP BIT0 + #define EHCI_HCRESET BIT1 + #define EHCI_FRM1024 0 // Reset BIT2 and BIT3 before + #define EHCI_FRM512 BIT2 // setting the new Frame List Size + #define EHCI_FRM256 BIT3 + #define EHCI_PER_SCHED_ENABLE BIT4 + #define EHCI_ASYNC_SCHED_ENABLE BIT5 + #define EHCI_INT_ASYNC_ADVANCE_ENABLE BIT6 + #define EHCI_INTTHRESHOLD (8 << 16) + struct + { + UINT32 RunStop : 1; // [0] + UINT32 HcReset : 1; // [1] + UINT32 FrameListSize : 2; // [3:2] + UINT32 PeriodicSheduleEnable : 1; // [4] + UINT32 AsyncSheduleEnable : 1; // [5] + UINT32 IntAsyncAdvDorbell : 1; // [6] + UINT32 LightHcReset : 1; // [7] + UINT32 Reserved1 : 8; // [16:8] + UINT32 IntThresholdCtl : 8; // [23:16] + UINT32 Reserved2 : 8; // [31:24] + } Field; + }; +} EHCI_USBCMD; + +typedef struct _EHCI_USBSTS +{ + union { + UINT32 AllBits; + #define EHCI_USB_INTERRUPT BIT0 // Interrupt + #define EHCI_USB_ERROR_INTERRUPT BIT1 // Error interrupt + #define EHCI_PORT_CHANGE_DETECT BIT2 // Port Change Detect + #define EHCI_FRAME_LIST_ROLLOVER BIT3 // Frame List Rollover + #define EHCI_HOST_SYSTEM_ERROR BIT4 // Host System Error + #define EHCI_INT_ASYNC_ADVANCE BIT5 // Interrupt on Async Advance + #define EHCI_HCHALTED BIT12 // HCHalted + #define EHCI_RECLAIM BIT13 // Reclamation + #define EHCI_PER_SCHED_STATUS BIT14 // Periodic Schedule Status + #define EHCI_ASYNC_SCHED_STATUS BIT15 // Asynchronous Schedule Status + struct + { + UINT32 UsbInt : 1; // [0] + UINT32 UsbErrInt : 1; // [1] + UINT32 PortChangeDetect : 1; // [2] + UINT32 FrameListRollover : 1; // [3] + UINT32 HostSystemError : 1; // [4] + UINT32 IntOnAsyncAdvance : 1; // [5] + UINT32 Reserved1 : 6; // [11:6] + UINT32 HCHalted : 1; // [12] + UINT32 Reclamation : 1; // [13] + UINT32 PeriodicSheduleStatus : 1; // [14] + UINT32 AsyncSheduleStatus : 1; // [15] + UINT32 Reserved2 : 16; // [31:16] + } Field; + }; +} EHCI_USBSTS; + +typedef struct _EHCI_USBINTR +{ + union { + UINT32 AllBits; + #define EHCI_USBINT_EN BIT0 // Interrupt Enable + #define EHCI_USBERRINT_EN BIT1 // Error Interrupt Enable + #define EHCI_PCDINT_EN BIT2 // Port Change Detect Interrupt Enable + #define EHCI_FLRINT_EN BIT3 // Frame List Rollover Interrupt Enable + #define EHCI_HSEINT_EN BIT4 // Host System Error Interrupt Enable + #define EHCI_IAAINT_EN BIT5 // Interrupt on Async Advance Enable + struct + { + UINT32 UsbIntEnable : 1; // [0] + UINT32 UsbErrIntEnable : 1; // [1] + UINT32 PortChangeIntEnable : 1; // [2] + UINT32 FrameListRolloverEnable : 1; // [3] + UINT32 HostSystemErrorEnable : 1; // [4] + UINT32 IntOnAsyncAdvanceEnable : 1; // [5] + UINT32 Reserved : 26; // [31:6] + } Field; + }; +} EHCI_USBINTR; + +typedef struct _EHCI_PORTSC +{ + union { + UINT32 AllBits; + #define EHCI_CURRENTCONNECTSTATUS BIT0 + #define EHCI_CONNECTSTATUSCHANGE BIT1 + #define EHCI_PORTENABLE BIT2 + #define EHCI_PORTENABLESTATUSCHANGE BIT3 + #define EHCI_OVERCURRENTACTIVE BIT4 + #define EHCI_OVERCURRENTCAHGE BIT5 + #define EHCI_FORCEPORTRESUME BIT6 + #define EHCI_SUSPEND BIT7 + #define EHCI_PORTRESET BIT8 + #define EHCI_DMINUSBIT BIT10 + #define EHCI_DPLUSBIT BIT11 + #define EHCI_PORTPOWER BIT12 + #define EHCI_PORTOWNER BIT13 + #define EHCI_WKCNNT_E BIT20 // Wake On Connect Enable + #define EHCI_WKDSCNNT_E BIT21 // Wake On Disconnect Enable + #define EHCI_WKOC_E BIT22 // Wake On Over-current Enable + struct + { + UINT32 CurrentConnectStatus : 1; // [0] + UINT32 ConnectStatusChange : 1; // [1] + UINT32 PortEnable : 1; // [2] + UINT32 PortEnableChange : 1; // [3] + UINT32 OvercurrentActive : 1; // [4] + UINT32 OvercurrentChange : 1; // [5] + UINT32 ForcePortResume : 1; // [6] + UINT32 Suspend : 1; // [7] + UINT32 PortReset : 1; // [8] + UINT32 Reserved1 : 1; // [9] + UINT32 LineStatus : 2; // [11:10] + UINT32 PortPower : 1; // [12] + UINT32 PortOwner : 1; // [13] + UINT32 PortIndicatorControl : 2; // [15:14] + UINT32 PortTestControl : 4; // [19:16] + UINT32 WakeOnConnectEnable : 1; // [20] + UINT32 WakeOnDisconnectEnable : 1; // [21] + UINT32 WakeOnOvercurrentEnable : 1; // [22] + UINT32 Reserved2 : 9; // [31:23] + } Field; + }; +} EHCI_PORTSC; + + + +typedef struct _EHCI_HC_OPER_REG { + EHCI_USBCMD UsbCmd; + volatile EHCI_USBSTS UsbSts; + EHCI_USBINTR UsbIntr; + UINT32 FrIndex; + UINT32 CtrlDsSegment; + UINT32 PeriodicListBase; + UINT32 AsyncListAddr; + UINT8 Reserved[36]; + UINT32 ConfigFlag; + EHCI_PORTSC PortSC[16]; +} EHCI_HC_OPER_REG; + + +typedef struct { + UINT32 dNextqTDPtr; + UINT32 dAltNextqTDPtr; + UINT32 dToken; + UINT32 dBufferPtr0; + UINT32 dBufferPtr1; + UINT32 dBufferPtr2; + UINT32 dBufferPtr3; + UINT32 dBufferPtr4; + UINT32 dReserved[8]; +} EHCI_QTD; + + +typedef struct { + UINT32 dLinkPointer; + UINT32 dEndPntCharac; + UINT32 dEndPntCap; + UINT32 dCurqTDPtr; + UINT32 dNextqTDPtr; + UINT32 dAltNextqTDPtr; + UINT32 dToken; + UINT32 dBufferPtr0; + UINT32 dBufferPtr1; + UINT32 dBufferPtr2; + UINT32 dBufferPtr3; + UINT32 dBufferPtr4; + UINT32 dReserved[8]; + VOID *fpCallBackFunc; + EHCI_QTD *fpFirstqTD; + UINT8 bActive; + UINT8 bErrorStatus; + UINT8 *fpDevInfoPtr; + UINT8 aDataBuffer[8]; + UINT8 Pad[38-3*sizeof(VOID*)]; // sizeof(EHCI_QH)should be divisible by 32 +} EHCI_QH; // because of 32 bin pointers; the size of + // the structure has to be 32 bytes aligned + +typedef struct _EHCI_DESC_PTRS_ +{ + EHCI_QH *fpQHControl; + EHCI_QTD *fpqTDControlSetup; + EHCI_QTD *fpqTDControlData; + EHCI_QTD *fpqTDControlStatus; + EHCI_QH *fpQHBulk; + EHCI_QTD *fpqTDBulkData; + +} EHCI_DESC_PTRS; + +typedef struct _PEI_EHCI_DEV +{ + UINTN Signature; + #define PEI_EHCI_DEV_SIGNATURE EFI_SIGNATURE_32( 'p', 'e', 'h', 'c' ) + EFI_PEI_SERVICES **PeiServices; + PEI_USB_HOST_CONTROLLER_PPI UsbHostControllerPpi; + EFI_PEI_PPI_DESCRIPTOR PpiDescriptor; + EFI_PEI_CPU_IO_PPI *CpuIoPpi; + EFI_PEI_STALL_PPI *StallPpi; + EFI_PEI_PCI_CFG_PPI *PciCfgPpi; + UINT32 UsbHostControllerBaseAddress; + EHCI_HC_OPER_REG *EhciHcOpReg; + UINT8 bNumPorts; + UINT32 HcStatus; + EHCI_DESC_PTRS stEHCIDescPtrs; + UINT16 PortResetStatusChangeMap; + UINT16 HiSpeedDevicesMap; + +} PEI_EHCI_DEV; + +#pragma pack(pop) + +#define PEI_MAX_EHCI_DATA_SIZE 20 * 1024 + +//---------------------------------------------------------------------------- +// Function prototypes +//---------------------------------------------------------------------------- + + + +EFI_STATUS InitializeUsbHC ( + PEI_EHCI_DEV *UhcDev ); + +VOID EhciInitHC ( + EFI_PEI_SERVICES **PeiServices, + PEI_EHCI_DEV *pEhcDev ); + +VOID EhciHcReset ( + EFI_PEI_SERVICES **PeiServices, + PEI_EHCI_DEV *pEhcDev ); + + +VOID EhciHcEnableRootHub ( + PEI_EHCI_DEV *EhciDevPtr, + UINT8 PortNumber ); + +VOID EHCIWaitForAsyncTransferComplete ( + EFI_PEI_SERVICES **PeiServices, + PEI_EHCI_DEV *EhciDevPtr, + EHCI_QH *QHead); + +EFI_STATUS EhciHcControlTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 DeviceAddress, + IN UINT8 DeviceSpeed, + IN UINT8 MaximumPacketLength, + IN UINT16 TransactionTranslator OPTIONAL, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION TransferDirection, + IN OUT VOID *Data OPTIONAL, + IN OUT UINTN *DataLength OPTIONAL, + IN UINTN TimeOut, + OUT UINT32 *TransferResult ); + +EFI_STATUS EhciHcBulkTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINT16 MaximumPacketLength, + IN UINT16 TransactionTranslator OPTIONAL, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult ); + +EFI_STATUS EhciHcGetRootHubPortNumber ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + OUT UINT8 *PortNumber ); + +EFI_STATUS EhciHcGetRootHubPortStatus ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 PortNumber, + OUT EFI_USB_PORT_STATUS *PortStatus ); + +EFI_STATUS EhciHcSetRootHubPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature ); + +EFI_STATUS EhciHcClearRootHubPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature ); + +#endif + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2009, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** \ No newline at end of file diff --git a/Core/EM/UsbRecovery/EhciPEI/EhciPeiBoard.c b/Core/EM/UsbRecovery/EhciPEI/EhciPeiBoard.c new file mode 100644 index 0000000..a883ac2 --- /dev/null +++ b/Core/EM/UsbRecovery/EhciPEI/EhciPeiBoard.c @@ -0,0 +1,108 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2009, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// +// $Header: /Alaska/SOURCE/Modules/USBRecovery/EhciPeiBoard.c 1 3/03/09 7:28p Olegi $ +// +// $Revision: 1 $ +// +// $Date: 3/03/09 7:28p $ +// +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USBRecovery/EhciPeiBoard.c $ +// +// 1 3/03/09 7:28p Olegi +//********************************************************************** + +// +//---------------------------------------------------------------------------- +// +// Name: EhciPeiBoard.c +// +// Description: This file contains routines that are board specific for +// initializing the EHCI controller in the USB Recovery module. +// +//---------------------------------------------------------------------------- +// + +#include +#include +#include +#include +#include +#include +#include "EhciPei.h" + + +//---------------------------------------------------------------------------- +// Porting Steps: +// +// 1) define/undefine the appropriate southbridge type +// 2) define registers and their set/clear bits for each register to be +// modified in each controller's PCI configuration space +// 3) do not do any generic initialization - programming of BAR and command +// register is done generically +// +//---------------------------------------------------------------------------- + + + +// +//---------------------------------------------------------------------------- +// +// Procedure: EhciPeiBoardInit +// +// Description: +// This is a porting hook for board-specific EHCI controller +// initialization +// +// Input: +// IN EFI_PEI_SERVICES **PeiServices - +// IN EFI_PEI_PCI_CFG_PPI *Pci - +// IN EFI_PEI_STALL_PPI *StallPpi - +// +// Output: +// VOID +// +//---------------------------------------------------------------------------- +// + +EFI_STATUS EhciPeiBoardInit ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_PCI_CFG_PPI *Pci, + IN EFI_PEI_STALL_PPI *StallPpi ) +{ + EFI_STATUS Status = EFI_SUCCESS; + + return Status; + +} + + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2009, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** \ No newline at end of file -- cgit v1.2.3