/** @file Pch common library for PCH INIT PEI/DXE/SMM modules Copyright (c) 2017, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern CONST PCH_PCIE_CONTROLLER_INFO mPchPcieControllerInfo[]; extern CONST UINT32 mPchPcieControllerInfoSize; #define PORT_PLS_TIMEOUT 100 ///< 100 * 10 us = 1ms timeout for USB3 PortSC PLS polling /** This function returns PID according to PCIe controller index @param[in] ControllerIndex PCIe controller index @retval PCH_SBI_PID Returns PID for SBI Access **/ PCH_SBI_PID PchGetPcieControllerSbiPid ( IN UINT32 ControllerIndex ) { ASSERT (ControllerIndex < mPchPcieControllerInfoSize); return mPchPcieControllerInfo[ControllerIndex].Pid; } /** This function returns PID according to Root Port Number @param[in] RpIndex Root Port Index (0-based) @retval PCH_SBI_PID Returns PID for SBI Access **/ PCH_SBI_PID GetRpSbiPid ( IN UINTN RpIndex ) { return PchGetPcieControllerSbiPid ((UINT32) (RpIndex / PCH_PCIE_CONTROLLER_PORTS)); } /** Calculate root port device number based on physical port index. @param[in] RpIndex Root port index (0-based). @retval Root port device number. **/ UINT32 PchGetPcieRpDevice ( IN UINT32 RpIndex ) { UINTN ControllerIndex; ControllerIndex = RpIndex / PCH_PCIE_CONTROLLER_PORTS; ASSERT (ControllerIndex < mPchPcieControllerInfoSize); return mPchPcieControllerInfo[ControllerIndex].DevNum; } /** This function reads Pci Config register via SBI Access @param[in] RpIndex Root Port Index (0-based) @param[in] Offset Offset of Config register @param[out] *Data32 Value of Config register @retval EFI_SUCCESS SBI Read successful. **/ EFI_STATUS PchSbiRpPciRead32 ( IN UINT32 RpIndex, IN UINT32 Offset, OUT UINT32 *Data32 ) { EFI_STATUS Status; UINT32 RpDevice; UINT8 Response; UINT16 Fid; RpDevice = PchGetPcieRpDevice (RpIndex); Fid = (UINT16) ((RpDevice << 3) | (RpIndex % 4 )); Status = PchSbiExecutionEx ( GetRpSbiPid (RpIndex), Offset, PciConfigRead, FALSE, 0xF, 0, Fid, Data32, &Response ); if (Status != EFI_SUCCESS) { DEBUG ((DEBUG_ERROR,"Sideband Read Failed\n")); ASSERT (FALSE); } return Status; } /** This function And then Or Pci Config register via SBI Access @param[in] RpIndex Root Port Index (0-based) @param[in] Offset Offset of Config register @param[in] Data32And Value of Config register to be And-ed @param[in] Data32AOr Value of Config register to be Or-ed @retval EFI_SUCCESS SBI Read and Write successful. **/ EFI_STATUS PchSbiRpPciAndThenOr32 ( IN UINT32 RpIndex, IN UINT32 Offset, IN UINT32 Data32And, IN UINT32 Data32Or ) { EFI_STATUS Status; UINT32 RpDevice; UINT32 Data32; UINT8 Response; UINT16 Fid; RpDevice = PchGetPcieRpDevice (RpIndex); Status = PchSbiRpPciRead32 (RpIndex, Offset, &Data32); if (Status == EFI_SUCCESS) { Data32 &= Data32And; Data32 |= Data32Or; Fid = (UINT16) ((RpDevice << 3) | (RpIndex % 4 )); Status = PchSbiExecutionEx ( GetRpSbiPid (RpIndex), Offset, PciConfigWrite, FALSE, 0xF, 0, Fid, &Data32, &Response ); if (Status != EFI_SUCCESS) { DEBUG ((DEBUG_ERROR,"Sideband Write Failed\n")); ASSERT (FALSE); } } else { ASSERT (FALSE); } return Status; } /** Check if RST PCIe Storage Remapping is enabled based on policy @param[in] RstPcieStorageRemap The PCH PCIe Storage remapping @retval TRUE RST PCIe Storage Remapping is enabled @retval FALSE RST PCIe Storage Remapping is disabled **/ BOOLEAN IsRstPcieStorageRemapEnabled ( IN CONST PCH_RST_PCIE_STORAGE_CONFIG *RstPcieStorageRemap ) { BOOLEAN RstPcieStorageRemapEnabled; UINTN Index; RstPcieStorageRemapEnabled = FALSE; DEBUG ((DEBUG_INFO, "IsRstPcieStorageRemapEnabled Started\n")); for (Index = 0; Index < PCH_MAX_RST_PCIE_STORAGE_CR; Index++) { if (RstPcieStorageRemap[Index].Enable == 1) { RstPcieStorageRemapEnabled = TRUE; } } DEBUG ((DEBUG_INFO, "IsRstPcieStorageRemapEnabled Ended\n")); return RstPcieStorageRemapEnabled; } /** Disable the RST remap address decoding range while RST is disabled. @param[in] AhciBar ABAR address **/ VOID DisableRstRemapDecoding ( UINT32 AhciBar ) { UINTN PciSataRegBase; UINT32 OrgAhciBar; UINT8 OrgCmd; if (AhciBar == 0) { DEBUG ((DEBUG_ERROR, "DisableRstRemapDecoding: Invalid AHCI BAR address.\n")); ASSERT (FALSE); return; } PciSataRegBase = MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_SATA, PCI_FUNCTION_NUMBER_PCH_SATA); OrgCmd = MmioRead8 (PciSataRegBase + PCI_COMMAND_OFFSET); OrgAhciBar = MmioRead32 (PciSataRegBase + R_PCH_SATA_AHCI_BAR); if (AhciBar != OrgAhciBar) { MmioWrite8 (PciSataRegBase + PCI_COMMAND_OFFSET, 0); MmioWrite32 (PciSataRegBase + R_PCH_SATA_AHCI_BAR, AhciBar); } MmioWrite8 (PciSataRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE); // // Program "NVM Remap Memory BAR Enable", AHCIBar offset A4h [0] to ['0b'] // Also set NRMO AHCIBar offset A4h [27:16] to 0x00F, and MSL AHCIBar offset A4h [12:1] to 0. // DEBUG ((DEBUG_INFO, "DisableRstRemapDecoding: Program AHCIBar offset A4h [27:16, 12:1, 0] to [0x00F, 0, 0] to disable remap decoding\n")); MmioWrite32 (AhciBar + R_PCH_SATA_VS_CAP, (0x00F << N_PCH_SATA_VS_CAP_NRMO)); if (AhciBar != OrgAhciBar) { MmioWrite8 (PciSataRegBase + PCI_COMMAND_OFFSET, 0); MmioWrite32 (PciSataRegBase + R_PCH_SATA_AHCI_BAR, OrgAhciBar); } MmioWrite8 (PciSataRegBase + PCI_COMMAND_OFFSET, OrgCmd); } /** This function lock down the P2sb SBI before going into OS. @param[in] SbiUnlock **/ VOID ConfigureP2sbSbiLock ( IN CONST BOOLEAN SbiUnlock ) { UINTN P2sbBase; BOOLEAN P2sbOrgStatus; if (SbiUnlock == FALSE) { P2sbBase = MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_P2SB, PCI_FUNCTION_NUMBER_PCH_P2SB); PchRevealP2sb (P2sbBase, &P2sbOrgStatus); /// /// Set P2SB PCI Offset 0xE0[31] to 1 to lock down SBI interface. /// @note: SbiLock is write once. Please make sure it's not touched earlier. /// MmioOr8 (P2sbBase + R_PCH_P2SB_E0 + 3, BIT7); if (!P2sbOrgStatus) { PchHideP2sb (P2sbBase); } } } /** Bios will remove the host accessing right to Sideband register range prior to any 3rd party code execution. 1) Set EPMASK5 Offset C4 (bits 29, 28, 27, 26, 17, 16 (PCH-LP only), 10, 1) to disable Sideband access for PSF and MIPI controller 2) Set EPMASK7 Offset CC (bits 6, 5) to disable Sideband access for XHCI controller 3) Set the "Endpoint Mask Lock!", P2SB PCI offset E2h bit[1] to 1. **/ VOID RemoveSidebandAccess ( VOID ) { UINTN P2sbBase; BOOLEAN P2sbOrgStatus; P2sbBase = MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_P2SB, PCI_FUNCTION_NUMBER_PCH_P2SB); PchRevealP2sb (P2sbBase, &P2sbOrgStatus); // // Set EPMASK for ports B1, B0, AA, A1 (bits 17, 16 (PCH-LP only), 10, 1) to disable Sideband access for MIPI controller // Set EPMASK for ports BD, BC, BB, BA (bits 29, 28, 27, 26) to disable Sideband access for PCI Root Bridge // if (GetPchSeries () == PchLp) { MmioOr32 (P2sbBase + R_PCH_P2SB_EPMASK5, BIT29 | BIT28 | BIT27 | BIT26 | BIT17 | BIT16 | BIT10 | BIT1); } else { MmioOr32 (P2sbBase + R_PCH_P2SB_EPMASK5, BIT29 | BIT28 | BIT27 | BIT26 | BIT17 | BIT10 | BIT1); } // // Set EPMASK for ports E6, E5 (bits 6, 5) to disable Sideband access for XHCI controller // MmioOr32(P2sbBase + R_PCH_P2SB_EPMASK7, BIT6 | BIT5); DEBUG((DEBUG_INFO, "Lock the EPMASK registers\n")); MmioOr8 (P2sbBase + R_PCH_P2SB_E0 + 2, BIT1); if (!P2sbOrgStatus) { PchHideP2sb (P2sbBase); } } /** Configure PMC static function disable lock **/ VOID ConfigurePmcStaticFunctionDisableLock ( VOID ) { UINT32 PchPwrmBase; PchPwrmBaseGet (&PchPwrmBase); MmioOr32 (PchPwrmBase + R_PCH_PWRM_ST_PG_FDIS_PMC_1, B_PCH_PWRM_ST_PG_FDIS_PMC_1_ST_FDIS_LK); } /** Print registers value @param[in] PrintMmioBase Mmio base address @param[in] PrintSize Number of registers @param[in] OffsetFromBase Offset from mmio base address @retval None **/ VOID PrintRegisters ( IN UINTN PrintMmioBase, IN UINT32 PrintSize, IN UINT32 OffsetFromBase ) { UINT32 Offset; DEBUG ((DEBUG_VERBOSE, " 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F")); for (Offset = 0; Offset < PrintSize; Offset++) { if ((Offset % 16) == 0) { DEBUG ((DEBUG_VERBOSE, "\n %04X: ", (Offset + OffsetFromBase) & 0xFFF0)); } DEBUG ((DEBUG_VERBOSE, "%02X ", MmioRead8 (PrintMmioBase + Offset))); } DEBUG ((DEBUG_VERBOSE, "\n")); } VOID PrintPchPciConfigSpace ( VOID ) { DEBUG ((DEBUG_VERBOSE, "[ 0 - 00 - 0 ] Host Bridge\n")); PrintRegisters (MmPciBase ( 0,0,0 ), 256, 0); DEBUG ((DEBUG_VERBOSE, "[ 0 - 01 - 0 ] PCI Bridge (0-1) x16@1 (x16)\n")); PrintRegisters (MmPciBase ( 0,1,0 ), 256, 0); DEBUG ((DEBUG_VERBOSE, "[ 0 - 02 - 0 ] IGD\n")); PrintRegisters (MmPciBase ( 0,2,0 ), 256, 0); DEBUG ((DEBUG_VERBOSE, "[ 0 - 03 - 0 ] High Def Audio\n")); PrintRegisters (MmPciBase (00, 03, 00), 256, 0); DEBUG ((DEBUG_VERBOSE, "[ 0 - 20(0x14) - 0 ] XHCI Controller\n")); PrintRegisters (MmPciBase (00, 20, 00), 256, 0); DEBUG ((DEBUG_VERBOSE, "[ 0 - 22(0x16) - 0 ] ME\n")); PrintRegisters (MmPciBase (00, 22, 00), 256, 0); DEBUG ((DEBUG_VERBOSE, "[ 0 - 22(0x16) - 2 ] ME IDER\n")); PrintRegisters (MmPciBase (00, 22, 02), 256, 0); DEBUG ((DEBUG_VERBOSE, "[ 0 - 22(0x16) - 3 ] ME SOL\n")); PrintRegisters (MmPciBase (00, 22, 03), 256, 0); DEBUG ((DEBUG_VERBOSE, "[ 0 - 25(0x19) - 0 ] LAN\n")); PrintRegisters (MmPciBase (00, 25, 00), 256, 0); DEBUG ((DEBUG_VERBOSE, "[ 0 - 26(0x1A) - 0 ] EHCI Controller\n")); PrintRegisters (MmPciBase (00, 26, 00), 256, 0); DEBUG ((DEBUG_VERBOSE, "[ 0 - 27(0x1B) - 0 ] High Def Audio\n")); PrintRegisters (MmPciBase (00, 27, 00), 256, 0); DEBUG ((DEBUG_VERBOSE, "[ 0 - 28(0x1C) - 0 ] PCI Bridge (0-2) x0@1 (x1)\n")); PrintRegisters (MmPciBase (00, 28, 00), 256, 0); DEBUG ((DEBUG_VERBOSE, "PCI Bridge: AECH\n")); PrintRegisters (MmPciBase (00, 28, 00) + 0x0100, 0x040,0x0100); DEBUG ((DEBUG_VERBOSE, "PCI Bridge: DFT\n")); PrintRegisters (MmPciBase (00, 28, 00) + 0x0310, 0x030,0x0310); DEBUG ((DEBUG_VERBOSE, "PCI Bridge: VC0\n")); PrintRegisters (MmPciBase (00, 28, 00) + 0x0340, 0x020,0x0340); DEBUG ((DEBUG_VERBOSE, "PCI Bridge: Port Configuration Extension\n")); PrintRegisters (MmPciBase (00, 28, 00) + 0x0400, 0x020,0x0400); DEBUG ((DEBUG_VERBOSE, "[ 0 - 28(0x1C) - 6 ] PCI Bridge (0-3:10) x0@1 (x1)\n")); PrintRegisters (MmPciBase (00, 28, 06), 256, 0); DEBUG ((DEBUG_VERBOSE, "[ 0 - 29(0x1D) - 0 ] EHCI Controller\n")); PrintRegisters (MmPciBase (00, 29, 00), 256, 0); DEBUG ((DEBUG_VERBOSE, "[ 0 - 31(0x1F) - 0 ] ISA Bridge\n")); PrintRegisters (MmPciBase (00, 31, 00), 256, 0); DEBUG ((DEBUG_VERBOSE, "[ 0 - 31(0x1F) - 2 ] SATA\n")); PrintRegisters (MmPciBase (00, 31, 02), 256, 0); DEBUG ((DEBUG_VERBOSE, "[ 0 - 31(0x1F) - 4 ] SMBus Controller\n")); PrintRegisters (MmPciBase (00, 31, 04), 256, 0); DEBUG ((DEBUG_VERBOSE, "\n\n")); } /** Program Xhci Port Disable Override @param[in] XhciMmioBase xHCI controller MBAR0 address @param[in] Usb2DisabledPorts Disabled USB2 ports where each port has its disabling bit @param[in] Usb3DisabledPorts Disabled USB3 ports where each port has its disabling bit @retval TRUE if platform reset is needed, otherwise FALSE is returned **/ BOOLEAN UsbPdoProgramming ( IN UINTN XhciMmioBase, IN UINT32 Usb2DisabledPorts, IN UINT32 Usb3DisabledPorts ) { UINT32 Index; UINT32 XhciUsb2Pdo; UINT32 XhciUsb3Pdo; UINT32 XhciUsb2PdoRd; UINT32 XhciUsb3PdoRd; UINT32 XhciUsb3PortScStartingOffset; UINT32 XhciUsb3PortScOffset; UINT32 XhciPlsTimeout; DEBUG ((DEBUG_INFO, "UsbPdoProgramming () start\n")); DEBUG ((DEBUG_INFO, "xHCI: Usb2DisabledPorts = 0x%x\n", Usb2DisabledPorts)); DEBUG ((DEBUG_INFO, "xHCI: Usb3DisabledPorts = 0x%x\n", Usb3DisabledPorts)); // // XHCI PDO for HS // if (GetPchSeries () == PchLp) { XhciUsb2Pdo = MmioRead32 (XhciMmioBase + R_PCH_XHCI_USB2PDO) & B_PCH_XHCI_LP_USB2PDO_MASK; } else { XhciUsb2Pdo = MmioRead32 (XhciMmioBase + R_PCH_XHCI_USB2PDO) & B_PCH_XHCI_H_USB2PDO_MASK; } XhciUsb2Pdo |= Usb2DisabledPorts; // // XHCI PDO for SS // if (GetPchSeries () == PchLp) { XhciUsb3Pdo = MmioRead32 (XhciMmioBase + R_PCH_XHCI_USB3PDO) & B_PCH_XHCI_LP_USB3PDO_MASK; XhciUsb3PortScStartingOffset = R_PCH_LP_XHCI_PORTSC01USB3; } else { XhciUsb3Pdo = MmioRead32 (XhciMmioBase + R_PCH_XHCI_USB3PDO) & B_PCH_XHCI_H_USB3PDO_MASK; XhciUsb3PortScStartingOffset = R_PCH_H_XHCI_PORTSC01USB3; } for (Index = 0; Index < GetPchXhciMaxUsb3PortNum (); Index++) { // Check if port should be disabled if ((Usb3DisabledPorts & (BIT0 << Index)) != 0) { // Check if PDO bit has not been set yet if (((XhciUsb3Pdo & (UINT32)(BIT0 << Index)) == 0)) { // Calculate port PortSC register offset in xHCI MMIO space XhciUsb3PortScOffset = (XhciUsb3PortScStartingOffset + (Index * 0x10)); // Disable port before setting PDO bit for it MmioOr32 (XhciMmioBase + XhciUsb3PortScOffset, B_PCH_XHCI_PORTSCXUSB3_PED); // Poll for PLS (PortSC[5:8]) to reach 0x4 before setting PDO for the port for (XhciPlsTimeout = 0; XhciPlsTimeout < PORT_PLS_TIMEOUT; XhciPlsTimeout++) { if ((MmioRead32 (XhciMmioBase + XhciUsb3PortScOffset) & B_PCH_XHCI_PORTSCXUSB3_PLS) == V_PCH_XHCI_PORTSCXUSB3_PLS_DISABLED) { break; } MicroSecondDelay (10); } if (XhciPlsTimeout == PORT_PLS_TIMEOUT) { DEBUG ((DEBUG_ERROR, "[xHCI PDO] PLS Polling for Disabled has timed out for port %d\n", Index + 1)); } // A '1' in a bit position prevents the corresponding USB3 port from reporting a Device Connection to the XHC XhciUsb3Pdo |= (UINT32) (B_PCH_XHCI_USB3PDO_DIS_PORT0 << Index); // Put port back to RxDetect state // Need to write LWS and PLS regs with same MMIO operation otherwise PLS write will be ignored MmioOr32 (XhciMmioBase + XhciUsb3PortScOffset, (B_PCH_XHCI_PORTSCXUSB3_LWS | V_PCH_XHCI_PORTSCXUSB3_PLS_RXDETECT)); } } } // // USB2PDO and USB3PDO are Write-Once registers and bits in them are in the SUS Well. // MmioWrite32 (XhciMmioBase + R_PCH_XHCI_USB2PDO, XhciUsb2Pdo); MmioWrite32 (XhciMmioBase + R_PCH_XHCI_USB3PDO, XhciUsb3Pdo); XhciUsb2PdoRd = MmioRead32 (XhciMmioBase + R_PCH_XHCI_USB2PDO); XhciUsb3PdoRd = MmioRead32 (XhciMmioBase + R_PCH_XHCI_USB3PDO); // // If USB2PDO and USB3PDO are not updated successfully perform Warm Reset to unlock RWO bits. // if ((XhciUsb2Pdo != XhciUsb2PdoRd) || (XhciUsb3Pdo != XhciUsb3PdoRd)) { DEBUG ((DEBUG_ERROR, "UsbPdoProgramming: PDO register locked. Performing Warm Reset\n")); return TRUE; } DEBUG ((DEBUG_INFO, "UsbPdoProgramming () end\n")); return FALSE; }