475 lines
13 KiB
C
475 lines
13 KiB
C
/** @file
|
|
Implementation of PchXhciPei module for Crisis Recovery
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2014-2021, Insyde Software Corporation. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
#include <PiPei.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/TimerLib.h>
|
|
#include <IndustryStandard/Pci.h>
|
|
//
|
|
// Driver Produced PPI Prototypes
|
|
//
|
|
#include <Ppi/UsbController.h>
|
|
|
|
//
|
|
// Driver Consumed PPI Prototypes
|
|
//
|
|
#include <Ppi/PciCfg2.h>
|
|
#include <Ppi/EndOfPeiPhase.h>
|
|
|
|
#include <Library/PcdLib.h>
|
|
#include <Library/PeiServicesLib.h>
|
|
|
|
#include <Library/HobLib.h>
|
|
#include <Guid/H2OPeiStorage.h>
|
|
|
|
#define PCH_DEVICE_ENABLE 1
|
|
|
|
#define CLASSCODE_REGISTER 0x08
|
|
#define XHCI_BASE_ADDRESS_REGISTER 0x10
|
|
|
|
#define XHCI_CLASSCODE 0x0C033000
|
|
#define XHCI_XHCC1_OFFSET 0x40
|
|
#define XHCI_ACCTRL_REGISTER BIT31
|
|
#define NUMBER_OF_PCIE_BRIDGES 1
|
|
#define ROOT_BRIDGE_BUS_REGISTER 0x18
|
|
#define ROOT_BRIDGE_ADDRESS_REGISTER 0x20
|
|
|
|
#define PEI_XHCI_SIGNATURE SIGNATURE_32 ('X', 'H', 'C', 'I')
|
|
|
|
//
|
|
// Please define All XHCI controllers into following structure.
|
|
//
|
|
typedef struct {
|
|
UINT32 PciAddress;
|
|
UINTN TempMemBase;
|
|
} XHCI_CONTROLLERS;
|
|
|
|
#define XHCI_MAX_COUNT 2
|
|
|
|
XHCI_CONTROLLERS mXhciController[XHCI_MAX_COUNT] = {
|
|
{0x00140000, FixedPcdGet32 (PcdXhciMemBaseAddress) },
|
|
{0x000D0000, FixedPcdGet32 (PcdCpuXhciMemBaseAddress)}
|
|
};
|
|
|
|
//
|
|
// The MdePkg/Include/Ppi/UsbController.h does not define PEI_XHCI_CONTROLLER
|
|
// It is defined here and is to be removed if it is defined in UsbController.h
|
|
//
|
|
#define PEI_XHCI_CONTROLLER 0x04
|
|
|
|
typedef struct {
|
|
UINTN Signature;
|
|
PEI_USB_CONTROLLER_PPI UsbControllerPpi;
|
|
EFI_PEI_PPI_DESCRIPTOR PpiList;
|
|
EFI_PEI_NOTIFY_DESCRIPTOR NotifyList;
|
|
EFI_PEI_PCI_CFG2_PPI *PciCfgPpi;
|
|
UINTN TotalUsbControllers;
|
|
UINTN MemBase[XHCI_MAX_COUNT];
|
|
UINTN RootBridge;
|
|
UINTN PciAddress[XHCI_MAX_COUNT];
|
|
} PEI_XHCI_DEVICE;
|
|
|
|
#define PEI_XHCI_DEVICE_FROM_THIS(a) CR(a, PEI_XHCI_DEVICE, UsbControllerPpi, PEI_XHCI_SIGNATURE)
|
|
#define PEI_XHCI_DEVICE_FROM_NOTIFY_DESC(a) CR(a, PEI_XHCI_DEVICE, NotifyList, PEI_XHCI_SIGNATURE)
|
|
|
|
EFI_STATUS
|
|
GetXhciController (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN PEI_USB_CONTROLLER_PPI *This,
|
|
IN UINT8 UsbControllerId,
|
|
IN UINTN *ControllerType,
|
|
IN UINTN *BaseAddress
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EndOfPeiPpiNotifyCallback (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
|
|
IN VOID *Ppi
|
|
);
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
PEI_USB_CONTROLLER_PPI mUsbControllerPpi = { GetXhciController };
|
|
|
|
EFI_PEI_PPI_DESCRIPTOR mPpiList = {
|
|
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
|
|
&gPeiUsbControllerPpiGuid,
|
|
NULL
|
|
};
|
|
|
|
EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {
|
|
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
|
|
&gEfiEndOfPeiSignalPpiGuid,
|
|
EndOfPeiPpiNotifyCallback
|
|
};
|
|
|
|
//
|
|
// Helper function
|
|
//
|
|
EFI_STATUS
|
|
EnableXhciController (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN PEI_XHCI_DEVICE *PeiPchXhciDev,
|
|
IN UINT8 UsbControllerId
|
|
);
|
|
|
|
/**
|
|
Decide whether to install usb stack.
|
|
|
|
@param None.
|
|
|
|
@retval TRUE Currently support USB on PEI phase.
|
|
@retval FALSE Currently not support USB on PEI phase.
|
|
|
|
**/
|
|
BOOLEAN
|
|
CheckUsbPolicy (
|
|
VOID
|
|
)
|
|
{
|
|
PEI_STORAGE_HOB_DATA *StorageData;
|
|
EFI_PEI_HOB_POINTERS GuidHob;
|
|
|
|
GuidHob.Raw = GetHobList ();
|
|
while ((GuidHob.Raw = GetNextGuidHob ( &gH2OPeiStorageHobGuid, GuidHob.Raw)) != NULL) {
|
|
StorageData = (PEI_STORAGE_HOB_DATA *)GET_GUID_HOB_DATA (GuidHob.Guid);
|
|
if (StorageData->Bits.UsbEnable == 1) {
|
|
DEBUG ((DEBUG_INFO, "[%a]Support USB stack on PEI phase\n", __FUNCTION__));
|
|
return TRUE;
|
|
}
|
|
GuidHob.Raw = GET_NEXT_HOB (GuidHob);
|
|
};
|
|
|
|
DEBUG ((DEBUG_INFO, "[%a]Can't support USB stack on PEI phase\n", __FUNCTION__));
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
|
|
@param [in] FfsHeader
|
|
@param [in] PeiServices
|
|
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InitializePchXhci (
|
|
IN EFI_PEI_FILE_HANDLE FileHandle,
|
|
IN CONST EFI_PEI_SERVICES **PeiServices
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_PEI_PCI_CFG2_PPI *PciCfgPpi;
|
|
PEI_XHCI_DEVICE *PeiPchXhciDev;
|
|
UINT8 Index;
|
|
UINT8 Index2;
|
|
|
|
DEBUG ((DEBUG_INFO, "InitializePchXhci\n"));
|
|
|
|
if (!CheckUsbPolicy()) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Get PciCfgPpi at first.
|
|
//
|
|
PciCfgPpi = (**PeiServices).PciCfg;
|
|
|
|
PeiPchXhciDev = (PEI_XHCI_DEVICE *)AllocatePages (1);
|
|
if (PeiPchXhciDev == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
ASSERT_EFI_ERROR (Status);
|
|
return Status;
|
|
}
|
|
ZeroMem (PeiPchXhciDev, sizeof(PeiPchXhciDev));
|
|
|
|
PeiPchXhciDev->Signature = PEI_XHCI_SIGNATURE;
|
|
PeiPchXhciDev->UsbControllerPpi = mUsbControllerPpi;
|
|
PeiPchXhciDev->PpiList = mPpiList;
|
|
PeiPchXhciDev->PpiList.Ppi = &PeiPchXhciDev->UsbControllerPpi;
|
|
PeiPchXhciDev->PciCfgPpi = PciCfgPpi;
|
|
PeiPchXhciDev->NotifyList = mNotifyList;
|
|
PeiPchXhciDev->TotalUsbControllers = XHCI_MAX_COUNT;
|
|
|
|
//
|
|
// Assign resources and enable XHCI controllers
|
|
//
|
|
for (Index = 0, Index2 = 0; Index < XHCI_MAX_COUNT; Index++) {
|
|
PeiPchXhciDev->MemBase[Index2] = mXhciController[Index].TempMemBase;
|
|
PeiPchXhciDev->PciAddress[Index2] = mXhciController[Index].PciAddress;
|
|
DEBUG ((EFI_D_ERROR | EFI_D_INFO, "XHCI(%d)_MEM_BASE_ADDRESS :%x\n", Index, PeiPchXhciDev->MemBase[Index2]));
|
|
Status = EnableXhciController (PeiServices, PeiPchXhciDev, Index2);
|
|
DEBUG ((EFI_D_ERROR | EFI_D_INFO, "EnableXhciController(%d) :%r\n", Index, Status));
|
|
if (EFI_ERROR(Status)) {
|
|
PeiPchXhciDev->TotalUsbControllers--;
|
|
if (PeiPchXhciDev->TotalUsbControllers == 0) {
|
|
return Status;
|
|
}
|
|
} else {
|
|
Index2++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Install USB Controller PPI
|
|
//
|
|
Status = PeiServicesInstallPpi (
|
|
&PeiPchXhciDev->PpiList
|
|
);
|
|
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "InstallPpi :%r\n",Status));
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "End PeimInitializePchXhci !\n"));
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Retrieve XHCI controller information
|
|
|
|
@param [in] PeiServices Pointer to the PEI Services Table.
|
|
@param [in] This Pointer to PEI_AHCI_CONTROLLER_PPI
|
|
@param [in] UsbControllerId USB Controller ID
|
|
@param [out] ControllerType Result USB controller type
|
|
@param [out] BaseAddress Result XHCI base address
|
|
|
|
@retval EFI_INVALID_PARAMETER Invalid AhciControllerId is given
|
|
@retval EFI_SUCCESS XHCI controller information is retrieved successfully
|
|
|
|
**/
|
|
EFI_STATUS
|
|
GetXhciController (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN PEI_USB_CONTROLLER_PPI *This,
|
|
IN UINT8 UsbControllerId,
|
|
OUT UINTN *ControllerType,
|
|
OUT UINTN *BaseAddress
|
|
)
|
|
{
|
|
PEI_XHCI_DEVICE *PeiPchXhciDev;
|
|
|
|
PeiPchXhciDev = PEI_XHCI_DEVICE_FROM_THIS (This);
|
|
|
|
if (UsbControllerId >= PeiPchXhciDev->TotalUsbControllers) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
*ControllerType = PEI_XHCI_CONTROLLER;
|
|
*BaseAddress = PeiPchXhciDev->MemBase[UsbControllerId];
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
GC_TODO: Add function description
|
|
|
|
@param [in] PeiServices GC_TODO: add argument description
|
|
@param [in] PeiPchXhciDev GC_TODO: add argument description
|
|
@param [in] UsbControllerId GC_TODO: add argument description
|
|
|
|
@retval EFI_INVALID_PARAMETER GC_TODO: Add description for return value
|
|
@retval EFI_SUCCESS GC_TODO: Add description for return value
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EnableXhciController (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN PEI_XHCI_DEVICE *PeiPchXhciDev,
|
|
IN UINT8 UsbControllerId
|
|
)
|
|
{
|
|
UINTN Index;
|
|
EFI_PEI_PCI_CFG2_PPI *PciCfgPpi;
|
|
UINT32 Address;
|
|
UINT32 Register;
|
|
|
|
if (UsbControllerId >= PeiPchXhciDev->TotalUsbControllers) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
PciCfgPpi = PeiPchXhciDev->PciCfgPpi;
|
|
//
|
|
// Discover XHCI through PCIE bridge
|
|
//
|
|
for (Index = 0; Index < NUMBER_OF_PCIE_BRIDGES; Index ++) {
|
|
//
|
|
// Discover XHCI
|
|
//
|
|
Address = PeiPchXhciDev->PciAddress[UsbControllerId];
|
|
Register = 0;
|
|
PciCfgPpi->Read (
|
|
PeiServices,
|
|
PciCfgPpi,
|
|
EfiPeiPciCfgWidthUint16,
|
|
Address,
|
|
&Register
|
|
);
|
|
if (Register == 0xffff) {
|
|
//
|
|
// XHCI not found, clear bus number to PCIE bridge
|
|
//
|
|
goto error;
|
|
}
|
|
//
|
|
// Check the class code
|
|
//
|
|
Register = 0;
|
|
PciCfgPpi->Read (
|
|
PeiServices,
|
|
PciCfgPpi,
|
|
EfiPeiPciCfgWidthUint32,
|
|
Address | CLASSCODE_REGISTER,
|
|
&Register
|
|
);
|
|
Register &= 0xffffff00;
|
|
if (Register != XHCI_CLASSCODE) {
|
|
//
|
|
// Not XHCI, clear bus number to PCIE bridge
|
|
//
|
|
goto error;
|
|
}
|
|
PeiPchXhciDev->RootBridge = 0;
|
|
//
|
|
// Assign base address register to XHCI
|
|
//
|
|
Register = PeiPchXhciDev->MemBase[UsbControllerId];
|
|
PciCfgPpi->Write (
|
|
PeiServices,
|
|
PciCfgPpi,
|
|
EfiPeiPciCfgWidthUint32,
|
|
Address | XHCI_BASE_ADDRESS_REGISTER,
|
|
&Register
|
|
);
|
|
//
|
|
// Set Access Control (ACCTRL) to locked state
|
|
//
|
|
Register = 0;
|
|
PciCfgPpi->Read (
|
|
PeiServices,
|
|
PciCfgPpi,
|
|
EfiPeiPciCfgWidthUint32,
|
|
Address | XHCI_XHCC1_OFFSET,
|
|
&Register
|
|
);
|
|
Register |= XHCI_ACCTRL_REGISTER;
|
|
PciCfgPpi->Write (
|
|
PeiServices,
|
|
PciCfgPpi,
|
|
EfiPeiPciCfgWidthUint32,
|
|
Address | XHCI_XHCC1_OFFSET,
|
|
&Register
|
|
);
|
|
//
|
|
// Enable XHCI
|
|
//
|
|
Register = 0;
|
|
PciCfgPpi->Read (
|
|
PeiServices,
|
|
PciCfgPpi,
|
|
EfiPeiPciCfgWidthUint16,
|
|
Address | PCI_COMMAND_OFFSET,
|
|
&Register
|
|
);
|
|
Register |= 0x06;
|
|
PciCfgPpi->Write (
|
|
PeiServices,
|
|
PciCfgPpi,
|
|
EfiPeiPciCfgWidthUint16,
|
|
Address | PCI_COMMAND_OFFSET,
|
|
&Register
|
|
);
|
|
return EFI_SUCCESS;
|
|
error:
|
|
Register = 0;
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Register notify ppi to reset the XHCI.
|
|
|
|
|
|
@param[in] PeiServices Pointer to the PEI Services Table.
|
|
@param[in] NotifyDescriptor Pointer to the notify descriptor
|
|
|
|
@retval EFI_SUCCESS
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EndOfPeiPpiNotifyCallback (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
|
|
IN VOID *Ppi
|
|
)
|
|
{
|
|
EFI_PEI_PCI_CFG2_PPI *PciCfgPpi;
|
|
UINT8 *BaseAddress;
|
|
UINT32 Register;
|
|
PEI_XHCI_DEVICE *PeiPchXhciDev;
|
|
UINT8 Index;
|
|
UINTN PciAddress;
|
|
|
|
PeiPchXhciDev = PEI_XHCI_DEVICE_FROM_NOTIFY_DESC (NotifyDescriptor);
|
|
|
|
for (Index = 0; Index < PeiPchXhciDev->TotalUsbControllers; Index ++) {
|
|
//
|
|
// Reset the HC
|
|
//
|
|
BaseAddress = (UINT8*)(PeiPchXhciDev->MemBase[Index]);
|
|
BaseAddress = BaseAddress + (*(UINT32*)(UINTN)BaseAddress & 0xff);
|
|
//
|
|
// Halt HC first
|
|
//
|
|
Register = *(UINT32*)(UINTN)BaseAddress;
|
|
Register &= ~0x01;
|
|
*(UINT32*)(UINTN)BaseAddress = Register;
|
|
|
|
MicroSecondDelay (1);
|
|
//
|
|
// HCReset
|
|
//
|
|
Register = *(UINT32*)(UINTN)BaseAddress;
|
|
Register |= 0x02;
|
|
*(UINT32*)(UINTN)BaseAddress = Register;
|
|
//
|
|
// Get PciCfgPpi at first.
|
|
//
|
|
PciCfgPpi = (**PeiServices).PciCfg;
|
|
//
|
|
// Disable XHCI
|
|
//
|
|
Register = 0;
|
|
PciAddress = PeiPchXhciDev->PciAddress[Index];
|
|
PciCfgPpi->Read (
|
|
PeiServices,
|
|
PciCfgPpi,
|
|
EfiPeiPciCfgWidthUint16,
|
|
PciAddress | PCI_COMMAND_OFFSET,
|
|
&Register
|
|
);
|
|
Register &= ~0x06;
|
|
PciCfgPpi->Write (
|
|
PeiServices,
|
|
PciCfgPpi,
|
|
EfiPeiPciCfgWidthUint16,
|
|
PciAddress | PCI_COMMAND_OFFSET,
|
|
&Register
|
|
);
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|