/** @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 #include #include #include #include #include // // Driver Produced PPI Prototypes // #include // // Driver Consumed PPI Prototypes // #include #include #include #include #include #include #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; }