alder_lake_bios/Intel/AlderLake/AlderLakeChipsetPkg/PchXhciPei/PchXhci.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;
}