From cf5ecb71b1bda3bee9c9795db9b188cd8a590c33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=BBygowski?= Date: Mon, 4 May 2026 16:39:31 +0200 Subject: [PATCH 1/6] xUSL/PROM: Add PROM IP block with parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Żygowski --- Include/xSIM-api.h | 1 + xSIM/SoC/F19M70/IpBlkListF19M70Tp1.c | 11 +- xUSL/Include/SilCommon.h | 4 +- xUSL/PROM/Common/PromClassDflts.c | 319 +++++++++++++++++++++++++++ xUSL/PROM/Common/PromInit.c | 112 ++++++++++ xUSL/PROM/Common/PromInit.h | 33 +++ xUSL/PROM/Common/meson.build | 7 + xUSL/PROM/PROM21/Prom21Init.c | 50 +++++ xUSL/PROM/PROM21/Prom21Init.h | 19 ++ xUSL/PROM/PROM21/meson.build | 7 + xUSL/PROM/PromClass-api.h | 170 ++++++++++++++ xUSL/PROM/meson.build | 7 + xUSL/meson.build | 1 + 13 files changed, 739 insertions(+), 2 deletions(-) create mode 100644 xUSL/PROM/Common/PromClassDflts.c create mode 100644 xUSL/PROM/Common/PromInit.c create mode 100644 xUSL/PROM/Common/PromInit.h create mode 100644 xUSL/PROM/Common/meson.build create mode 100644 xUSL/PROM/PROM21/Prom21Init.c create mode 100644 xUSL/PROM/PROM21/Prom21Init.h create mode 100644 xUSL/PROM/PROM21/meson.build create mode 100644 xUSL/PROM/PromClass-api.h create mode 100644 xUSL/PROM/meson.build diff --git a/Include/xSIM-api.h b/Include/xSIM-api.h index 7a30090..570dace 100644 --- a/Include/xSIM-api.h +++ b/Include/xSIM-api.h @@ -70,6 +70,7 @@ typedef enum { SilId_RasClass, SilId_ApobClass, SilId_GfxClass, + SilId_PromClass, // Add new elements above this line ^^^ SilId_ListEnd ///< Value to bound the list } SIL_DATA_BLOCK_ID; diff --git a/xSIM/SoC/F19M70/IpBlkListF19M70Tp1.c b/xSIM/SoC/F19M70/IpBlkListF19M70Tp1.c index d148b50..6690d56 100644 --- a/xSIM/SoC/F19M70/IpBlkListF19M70Tp1.c +++ b/xSIM/SoC/F19M70/IpBlkListF19M70Tp1.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include /** @@ -59,7 +61,7 @@ * - MPIO: MPIO firmware initializes and trains the PCIe links * (required for CXL). Due to this dependency, * MPIO is initialized prior to CXL IP block. - * - CXL: CXL is dependent on MPIO and is initialized after MPIO. + * - Prom: PROM21 is dependent on MPIO and is initialized after MPIO. */ const SOC_IP_TABLE SocIpTblF19M70Tp1 = { AMD_FAMILY_19_PHX, // This is the 'Client' F19M70 a.k.a. Phoenix @@ -174,6 +176,13 @@ const SOC_IP_TABLE SocIpTblF19M70Tp1 = { InitializeMpioPhxTp1, InitializeApiMpioPhx }, + { + SilId_PromClass, + PROMCLASS_DATA_SIZE, + PromClassSetInputBlock, + InitializePromTp1, + NULL, + }, { SilId_CcxClass, CCX_DATA_SIZE_ZEN4_PHX, diff --git a/xUSL/Include/SilCommon.h b/xUSL/Include/SilCommon.h index 74c1fd6..5e063ec 100644 --- a/xUSL/Include/SilCommon.h +++ b/xUSL/Include/SilCommon.h @@ -76,6 +76,7 @@ #define DEBUG_FILTER_CXL 0x00000200UL #define DEBUG_FILTER_RCMGR 0x00000800UL #define DEBUG_FILTER_GFX 0x00001000UL +#define DEBUG_FILTER_PROM 0x00002000UL // set the default Module filter, allowing the Host to pre-define #ifndef SIL_DEBUG_MODULE_FILTER #define SIL_DEBUG_MODULE_FILTER ( DEBUG_FILTER_APOB | \ @@ -88,7 +89,8 @@ DEBUG_FILTER_FCH | \ DEBUG_FILTER_CXL | \ DEBUG_FILTER_RCMGR | \ - DEBUG_FILTER_GFX ) + DEBUG_FILTER_GFX | \ + DEBUG_FILTER_PROM) #endif /** Message type enables diff --git a/xUSL/PROM/Common/PromClassDflts.c b/xUSL/PROM/Common/PromClassDflts.c new file mode 100644 index 0000000..86ca934 --- /dev/null +++ b/xUSL/PROM/Common/PromClassDflts.c @@ -0,0 +1,319 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ + +/** + * @file Prom21ClassDflts.c + * @brief This file holds the platform default values for the PROM Input Block + * + */ + +#include + +/// Default values for PROM configuration data +const PROMCLASS_DATA_BLK PromClassDflts = { + .PT21FwInRamAddress = 0x0B000000, + .PT21GpioID = 0x00000000, + .PT21FwVersion = 0x0000000000000000, + .PT21UsbPortLateDisable = 0xf, + .PT21TempBusNum = 0x10, + .PT21RootBridgeNum = 0x00, + .PT21PcieTargetSpeed = 0x04, + .PT21IoHcBusNum = 0x00, + .PT21IohcBridgeCntl = 0x00000000, + .PT21FWLoading = 0x1, + .PT21DbgLoadFw = 0x00, + .PT21DisableUnusedPciePort = 0xf, + .PT21SecondPortNumber = 0xf, + .PT21Revision = 0x2, + .PT21TogglePerst = 0xf, + .PT21RuninRam = 0x0, + .PT21ClkPMEnable = 0xf, + .PT21L1Enable = 0x1, + .PT21L1ssEnable = 0xf, + .PT21ReadThermal = 0xf, + .PT21GpioPerstEnable = 0xf, + .PT21GpioTestEnable = 0xf, + .PT21DelayAfterFWLoading = 0xf, + .PT21XhciPmeEn = 0xf, + .PT21CorrErrMask = 0x6000, + .Primary = { + .PT21PciePortLaneRev = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }, + .PT21SIProgEnable = 0xf, + .PT21ThermalThrottle = 0xf, + .PT21ThermalThreshold = 0xC0, + .PT21LtrSmallEnable = 0xf, + .PT21PcieGen1SwingEnable = 0xf, + .PT21PcieGen1Swing = { 0x1f, 0x1f, 0x1f, 0x1f, 0xf, 0xf, 0xf, 0xf, 0x1f, 0x1f, 0x1f, 0x1f }, + .PT21EqPreset = 0xf, + .PT21PcieClkreqPinSelect = { 0x8, 0x4, 0x0, 0x2, 0x3, 0xE }, + .PT21PcieClkreqMode = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x2 }, + .PT21PciePortTargetSpeed = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }, + .PT21PciePortEnable = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }, + .PT21Usb3GenSelect = 0xf, + .PT21XhciPortGen = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }, + .PT21L4Usb3Port = { 0xf, 0xf, 0xf, 0xf }, + .PT21L4Usb2Port = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }, + .PT21Usb3ort = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }, + .PT21Usb2Port = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }, + .PT21SataPhy[0] = { + .PT21SataPortGen1Swing = 0x3, + .PT21SataPortGen2Swing = 0x3, + .PT21SataPortGen3Swing = 0xf, + .PT21SataPortGen1EmpLevel = 0x1, + .PT21SataPortGen2EmpLevel = 0x1, + .PT21SataPortGen3EmpLevel = 0xa, + }, + .PT21SataPhy[1] = { + .PT21SataPortGen1Swing = 0x3, + .PT21SataPortGen2Swing = 0x3, + .PT21SataPortGen3Swing = 0xf, + .PT21SataPortGen1EmpLevel = 0x1, + .PT21SataPortGen2EmpLevel = 0x1, + .PT21SataPortGen3EmpLevel = 0xa, + }, + .PT21SataPhy[2] = { + .PT21SataPortGen1Swing = 0x3, + .PT21SataPortGen2Swing = 0x3, + .PT21SataPortGen3Swing = 0xf, + .PT21SataPortGen1EmpLevel = 0x1, + .PT21SataPortGen2EmpLevel = 0x1, + .PT21SataPortGen3EmpLevel = 0xa, + }, + .PT21SataPhy[3] = { + .PT21SataPortGen1Swing = 0x3, + .PT21SataPortGen2Swing = 0x3, + .PT21SataPortGen3Swing = 0xf, + .PT21SataPortGen1EmpLevel = 0x1, + .PT21SataPortGen2EmpLevel = 0x1, + .PT21SataPortGen3EmpLevel = 0xa, + }, + .PT21USB3Phy[0] = { + .PT21USB3PortGen1Swing = 0xf, + .PT21USB3PortGen1EmpLevelEn = 0x1, + .PT21USB3PortGen1EmpLevel = 0x3, + .PT21USB3PortGen1PreshootEn = 0x0, + .PT21USB3PortGen1Preshoot = 0x0, + .PT21USB3PortGen2Swing = 0xf, + .PT21USB3PortGen2Cp0EmpLevelEn = 0x1, + .PT21USB3PortGen2Cp0EmpLevel = 0x3, + .PT21USB3PortGen2Cp0PreshootEn = 0x1, + .PT21USB3PortGen2Cp0Preshoot = 0x0, + .PT21USB3PortGen2Cp13EmpLevelEn = 0x0, + .PT21USB3PortGen2Cp13EmpLevel = 0x3, + .PT21USB3PortGen2Cp13PreshootEn = 0x1, + .PT21USB3PortGen2Cp13Preshoot = 0x0, + .PT21USB3PortGen2Cp14EmpLevelEn = 0x1, + .PT21USB3PortGen2Cp14EmpLevel = 0x3, + .PT21USB3PortGen2Cp14PreshootEn = 0x0, + .PT21USB3PortGen2Cp14Preshoot = 0x0, + .PT21USB3PortGen2Cp15EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp15EmpLevel = 0x3, + .PT21USB3PortGen2Cp15PreshootEn = 0x0, + .PT21USB3PortGen2Cp15Preshoot = 0x0, + .PT21USB3PortGen2Cp16EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp16EmpLevel = 0x3, + .PT21USB3PortGen2Cp16PreshootEn = 0x0, + .PT21USB3PortGen2Cp16Preshoot = 0x0, + }, + .PT21USB3Phy[1] = { + .PT21USB3PortGen1Swing = 0xf, + .PT21USB3PortGen1EmpLevelEn = 0x1, + .PT21USB3PortGen1EmpLevel = 0x3, + .PT21USB3PortGen1PreshootEn = 0x0, + .PT21USB3PortGen1Preshoot = 0x0, + .PT21USB3PortGen2Swing = 0xf, + .PT21USB3PortGen2Cp0EmpLevelEn = 0x1, + .PT21USB3PortGen2Cp0EmpLevel = 0x3, + .PT21USB3PortGen2Cp0PreshootEn = 0x1, + .PT21USB3PortGen2Cp0Preshoot = 0x0, + .PT21USB3PortGen2Cp13EmpLevelEn = 0x0, + .PT21USB3PortGen2Cp13EmpLevel = 0x3, + .PT21USB3PortGen2Cp13PreshootEn = 0x1, + .PT21USB3PortGen2Cp13Preshoot = 0x0, + .PT21USB3PortGen2Cp14EmpLevelEn = 0x1, + .PT21USB3PortGen2Cp14EmpLevel = 0x3, + .PT21USB3PortGen2Cp14PreshootEn = 0x0, + .PT21USB3PortGen2Cp14Preshoot = 0x0, + .PT21USB3PortGen2Cp15EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp15EmpLevel = 0x3, + .PT21USB3PortGen2Cp15PreshootEn = 0x0, + .PT21USB3PortGen2Cp15Preshoot = 0x0, + .PT21USB3PortGen2Cp16EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp16EmpLevel = 0x3, + .PT21USB3PortGen2Cp16PreshootEn = 0x0, + .PT21USB3PortGen2Cp16Preshoot = 0x0, + }, + .PT21USB3Phy[2] = { + .PT21USB3PortGen1Swing = 0xf, + .PT21USB3PortGen1EmpLevelEn = 0x1, + .PT21USB3PortGen1EmpLevel = 0x3, + .PT21USB3PortGen1PreshootEn = 0x0, + .PT21USB3PortGen1Preshoot = 0x0, + .PT21USB3PortGen2Swing = 0xf, + .PT21USB3PortGen2Cp0EmpLevelEn = 0x1, + .PT21USB3PortGen2Cp0EmpLevel = 0x3, + .PT21USB3PortGen2Cp0PreshootEn = 0x1, + .PT21USB3PortGen2Cp0Preshoot = 0x0, + .PT21USB3PortGen2Cp13EmpLevelEn = 0x0, + .PT21USB3PortGen2Cp13EmpLevel = 0x3, + .PT21USB3PortGen2Cp13PreshootEn = 0x1, + .PT21USB3PortGen2Cp13Preshoot = 0x0, + .PT21USB3PortGen2Cp14EmpLevelEn = 0x1, + .PT21USB3PortGen2Cp14EmpLevel = 0x3, + .PT21USB3PortGen2Cp14PreshootEn = 0x0, + .PT21USB3PortGen2Cp14Preshoot = 0x0, + .PT21USB3PortGen2Cp15EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp15EmpLevel = 0x3, + .PT21USB3PortGen2Cp15PreshootEn = 0x0, + .PT21USB3PortGen2Cp15Preshoot = 0x0, + .PT21USB3PortGen2Cp16EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp16EmpLevel = 0x3, + .PT21USB3PortGen2Cp16PreshootEn = 0x0, + .PT21USB3PortGen2Cp16Preshoot = 0x0, + }, + .PT21USB3Phy[3] = { + .PT21USB3PortGen1Swing = 0xf, + .PT21USB3PortGen1EmpLevelEn = 0x1, + .PT21USB3PortGen1EmpLevel = 0x3, + .PT21USB3PortGen1PreshootEn = 0x0, + .PT21USB3PortGen1Preshoot = 0x0, + .PT21USB3PortGen2Swing = 0xf, + .PT21USB3PortGen2Cp0EmpLevelEn = 0x1, + .PT21USB3PortGen2Cp0EmpLevel = 0x3, + .PT21USB3PortGen2Cp0PreshootEn = 0x1, + .PT21USB3PortGen2Cp0Preshoot = 0x0, + .PT21USB3PortGen2Cp13EmpLevelEn = 0x0, + .PT21USB3PortGen2Cp13EmpLevel = 0x3, + .PT21USB3PortGen2Cp13PreshootEn = 0x1, + .PT21USB3PortGen2Cp13Preshoot = 0x0, + .PT21USB3PortGen2Cp14EmpLevelEn = 0x1, + .PT21USB3PortGen2Cp14EmpLevel = 0x3, + .PT21USB3PortGen2Cp14PreshootEn = 0x0, + .PT21USB3PortGen2Cp14Preshoot = 0x0, + .PT21USB3PortGen2Cp15EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp15EmpLevel = 0x3, + .PT21USB3PortGen2Cp15PreshootEn = 0x0, + .PT21USB3PortGen2Cp15Preshoot = 0x0, + .PT21USB3PortGen2Cp16EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp16EmpLevel = 0x3, + .PT21USB3PortGen2Cp16PreshootEn = 0x0, + .PT21USB3PortGen2Cp16Preshoot = 0x0, + }, + .PT21USB3Phy[4] = { + .PT21USB3PortGen1Swing = 0xf, + .PT21USB3PortGen1EmpLevelEn = 0x1, + .PT21USB3PortGen1EmpLevel = 0x3, + .PT21USB3PortGen1PreshootEn = 0x0, + .PT21USB3PortGen1Preshoot = 0x0, + .PT21USB3PortGen2Swing = 0xf, + .PT21USB3PortGen2Cp0EmpLevelEn = 0x1, + .PT21USB3PortGen2Cp0EmpLevel = 0x3, + .PT21USB3PortGen2Cp0PreshootEn = 0x1, + .PT21USB3PortGen2Cp0Preshoot = 0x0, + .PT21USB3PortGen2Cp13EmpLevelEn = 0x0, + .PT21USB3PortGen2Cp13EmpLevel = 0x3, + .PT21USB3PortGen2Cp13PreshootEn = 0x1, + .PT21USB3PortGen2Cp13Preshoot = 0x0, + .PT21USB3PortGen2Cp14EmpLevelEn = 0x1, + .PT21USB3PortGen2Cp14EmpLevel = 0x3, + .PT21USB3PortGen2Cp14PreshootEn = 0x0, + .PT21USB3PortGen2Cp14Preshoot = 0x0, + .PT21USB3PortGen2Cp15EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp15EmpLevel = 0x3, + .PT21USB3PortGen2Cp15PreshootEn = 0x0, + .PT21USB3PortGen2Cp15Preshoot = 0x0, + .PT21USB3PortGen2Cp16EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp16EmpLevel = 0x3, + .PT21USB3PortGen2Cp16PreshootEn = 0x0, + .PT21USB3PortGen2Cp16Preshoot = 0x0, + }, + .PT21USB3Phy[5] = { + .PT21USB3PortGen1Swing = 0xf, + .PT21USB3PortGen1EmpLevelEn = 0x1, + .PT21USB3PortGen1EmpLevel = 0x3, + .PT21USB3PortGen1PreshootEn = 0x0, + .PT21USB3PortGen1Preshoot = 0x0, + .PT21USB3PortGen2Swing = 0xf, + .PT21USB3PortGen2Cp0EmpLevelEn = 0x1, + .PT21USB3PortGen2Cp0EmpLevel = 0x3, + .PT21USB3PortGen2Cp0PreshootEn = 0x1, + .PT21USB3PortGen2Cp0Preshoot = 0x0, + .PT21USB3PortGen2Cp13EmpLevelEn = 0x0, + .PT21USB3PortGen2Cp13EmpLevel = 0x3, + .PT21USB3PortGen2Cp13PreshootEn = 0x1, + .PT21USB3PortGen2Cp13Preshoot = 0x0, + .PT21USB3PortGen2Cp14EmpLevelEn = 0x1, + .PT21USB3PortGen2Cp14EmpLevel = 0x3, + .PT21USB3PortGen2Cp14PreshootEn = 0x0, + .PT21USB3PortGen2Cp14Preshoot = 0x0, + .PT21USB3PortGen2Cp15EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp15EmpLevel = 0x3, + .PT21USB3PortGen2Cp15PreshootEn = 0x0, + .PT21USB3PortGen2Cp15Preshoot = 0x0, + .PT21USB3PortGen2Cp16EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp16EmpLevel = 0x3, + .PT21USB3PortGen2Cp16PreshootEn = 0x0, + .PT21USB3PortGen2Cp16Preshoot = 0x0, + }, + .PT21USB2Phy[0] = { + .PT21USB2P0SlewRate = 0x2, + .PT21USB2P0DrivingCurrent = 0x0, + .PT21USB2P0Termination = 0x3, + }, + .PT21USB2Phy[1] = { + .PT21USB2P0SlewRate = 0x2, + .PT21USB2P0DrivingCurrent = 0x0, + .PT21USB2P0Termination = 0x3, + }, + .PT21USB2Phy[2] = { + .PT21USB2P0SlewRate = 0x2, + .PT21USB2P0DrivingCurrent = 0x0, + .PT21USB2P0Termination = 0x3, + }, + .PT21USB2Phy[3] = { + .PT21USB2P0SlewRate = 0x2, + .PT21USB2P0DrivingCurrent = 0x0, + .PT21USB2P0Termination = 0x3, + }, + .PT21USB2Phy[4] = { + .PT21USB2P0SlewRate = 0x2, + .PT21USB2P0DrivingCurrent = 0x0, + .PT21USB2P0Termination = 0x3, + }, + .PT21USB2Phy[5] = { + .PT21USB2P0SlewRate = 0x2, + .PT21USB2P0DrivingCurrent = 0x0, + .PT21USB2P0Termination = 0x3, + }, + .PT21SataMode = 0x00, + .PT21SataAggressiveDevSlp = { 0xf, 0xf, 0xf, 0xf }, + .PT21SataAggrLinkPmCap = 0xf, + .PT21SataPscCap = 0xf, + .PT21SataSscCap = 0xf, + .PT21SataPortMdPort = { 0xf, 0xf, 0xf, 0xf }, + .PT21SataHotPlug = 0xf, + .PT21SataPTSataCCCSCap = 0xf, + .PT21AhciMsiCap = 0xf, + .PT21SataPortEnable = { 0xf, 0xf, 0xf, 0xf }, + .PT21Msi = 0xf, + .PT21Msix = 0xf, + .PT21HW_LPM = 0xf, + .PT21DbC = 0xf, + .PT21XHC_PME = 0xf, + .PT21Lock = 0x01, + .PT21XhciLock = 0x00, + .PT21XhciID = 0x00000000, + .PT21GppPcieAddress = 0x00000000, + .PT21XhciMmio = 0x00000000, + .PT21GpioMmio = 0x00000000, + .PT21PcieDspSsid = 0x33281B21, + .PT21PcieDspXhciSsid = 0x33281B21, + .PT21PcieDspAhciSsid = 0x33281B21, + .PT21SsidOverride = 0xf, + .PT21XhciSsid = 0x11421B21, + .PT21AhciSsid = 0x10621B21, + .PT21PcieUspSsid = 0x33281B21 + } + // Will be copied from Primary in PromClassSetInputBlock + // .Secondary = { } +}; diff --git a/xUSL/PROM/Common/PromInit.c b/xUSL/PROM/Common/PromInit.c new file mode 100644 index 0000000..94073a2 --- /dev/null +++ b/xUSL/PROM/Common/PromInit.c @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ + +/** + * @file PromInit.c + * @brief Promontory21 related functions + */ + +#include +#include +#include +#include +#include +#include +#include "PromInit.h" + +#define PROMCLASS_MAJOR_REV 0 +#define PROMCLASS_MINOR_REV 1 +#define PROMCLASS_INSTANCE 0 + +/**-------------------------------------------------------------------- + * InitializePromTp1 + * + * @brief This function initializes the PROM IP during timepoint 1 (pre-Pcie phase). + * + * @details This is an IP private function, not visible to the Host. + * The PROM Silicon block is initialized by calling this function + * in the IP block list. + * + * @param SilContext A context structure through which host firmware defined data + * can be passed to openSIL. The host firmware is responsible + * for initializing the SIL_CONTEXT structure. + * @return SIL_STATUS + * @retval SilPass - everything is OK + * @retval SilNotFound - Something went wrong + */ +SIL_STATUS +InitializePromTp1 ( + SIL_CONTEXT *SilContext + ) +{ + PROMCLASS_DATA_BLK *SilData; + SIL_STATUS Status; + + Status = SilPass; + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + /* + * Get IP block data + */ + SilData = (PROMCLASS_DATA_BLK *)xUslFindStructure(SilContext, SilId_PromClass, 0); + if (SilData == NULL) { + PROM_TRACEPOINT(SIL_TRACE_INFO, "PROM IP block not found\n"); + return SilNotFound; + } + + if (!ISSOCPHXAM5) { + PROM_TRACEPOINT(SIL_TRACE_INFO, "PROM IP block supported only on AM5, skipping\n"); + return SilPass; + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, "PROM IP block is located at %x\n", SilData); + + Status = InitializePromontoryChipset(SilContext, SilData); + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); + + return Status; +} + +/**-------------------------------------------------------------------- + * PromClassSetInputBlock + * + * @brief Establish PROM input defaults + * + * @details This function is called by the xSIM core to populate the IP's input + * block with its default values. Each block established by the IP must + * have a unique header.ID and its header.size set to the single block + * only - so as to allow the FindStruct() to traverse the block chain. + * + * This is an IP private function, not visible to the Host. + * + * @param SilContext A context structure through which host firmware defined data + * can be passed to openSIL. The host firmware is responsible + * for initializing the SIL_CONTEXT structure. + * @return SIL_STATUS. + * @retval SilPass - everything is OK + * @retval SilAborted - Something went wrong + */ +SIL_STATUS PromClassSetInputBlock ( + SIL_CONTEXT *SilContext + ) +{ + PROMCLASS_DATA_BLK *PromConfigData; + + PromConfigData = (PROMCLASS_DATA_BLK *)SilCreateInfoBlock(SilContext, + SilId_CxlClass, + sizeof (PROMCLASS_DATA_BLK), + PROMCLASS_INSTANCE, + PROMCLASS_MAJOR_REV, + PROMCLASS_MINOR_REV + ); + PROM_TRACEPOINT(SIL_TRACE_INFO, "PromSetInputBlk at: 0x%x \n", PromConfigData); + if (PromConfigData == NULL) { + return SilAborted; + } + // fill PROM IP data structure with defaults + memcpy(PromConfigData, &PromClassDflts, sizeof (PROMCLASS_DATA_BLK)); + memcpy(&PromConfigData->Secondary, &PromClassDflts.Primary, sizeof (PROM21_DATA_BLK)); + + return SilPass; +} diff --git a/xUSL/PROM/Common/PromInit.h b/xUSL/PROM/Common/PromInit.h new file mode 100644 index 0000000..aeec682 --- /dev/null +++ b/xUSL/PROM/Common/PromInit.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ + +/** + * @file PromInit.h + * @brief All PROM related defines and structures + */ + +#pragma once + +#include +#include +#include + +extern const PROMCLASS_DATA_BLK PromClassDflts; + +#define PROM_TRACEPOINT(MsgLevel, Message, ...) \ + do { \ + if (DEBUG_FILTER_PROM & SIL_DEBUG_MODULE_FILTER) { \ + XUSL_TRACEPOINT(MsgLevel, Message, ## __VA_ARGS__); \ + } \ + } while (0) + +SIL_STATUS +PromClassSetInputBlock ( + SIL_CONTEXT *SilContext + ); + +SIL_STATUS +InitializePromTp1 ( + SIL_CONTEXT *SilContext + ); + diff --git a/xUSL/PROM/Common/meson.build b/xUSL/PROM/Common/meson.build new file mode 100644 index 0000000..805d547 --- /dev/null +++ b/xUSL/PROM/Common/meson.build @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT +# Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. + + + +xusl += files([ 'PromClassDflts.c', 'PromInit.c' ]) + diff --git a/xUSL/PROM/PROM21/Prom21Init.c b/xUSL/PROM/PROM21/Prom21Init.c new file mode 100644 index 0000000..1c01a2a --- /dev/null +++ b/xUSL/PROM/PROM21/Prom21Init.c @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ + +/** + * @file PromInit.c + * @brief Promontory21 related functions + */ + +#include +#include +#include +#include +#include +#include +#include "Prom21Init.h" + + +/**-------------------------------------------------------------------- + * InitializePromontoryChipset + * + * @brief This function initializes the PROM21 IP during timepoint 1 (pre-Pcie phase). + * + * @details This is an IP private function, not visible to the Host. + * The PROM Silicon block is initialized by calling this function + * in the IP block list. + * + * @param SilContext A context structure through which host firmware defined data + * can be passed to openSIL. The host firmware is responsible + * for initializing the SIL_CONTEXT structure. + * @param PromInputBlk A pointer to the PROM configuration data. + * @return SIL_STATUS + * @retval SilPass - everything is OK + * @retval SilNotFound - Something went wrong + */ +SIL_STATUS +InitializePromontoryChipset ( + SIL_CONTEXT *SilContext, + PROMCLASS_DATA_BLK *PromInputBlk + ) +{ + SIL_STATUS Status; + + Status = SilPass; + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); + + return Status; +} diff --git a/xUSL/PROM/PROM21/Prom21Init.h b/xUSL/PROM/PROM21/Prom21Init.h new file mode 100644 index 0000000..61416b6 --- /dev/null +++ b/xUSL/PROM/PROM21/Prom21Init.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ + +/** + * @file Prom21Init.h + * @brief All PROM related defines and structures + */ + +#pragma once + +#include +#include +#include + +SIL_STATUS +InitializePromontoryChipset ( + SIL_CONTEXT *SilContext, + PROMCLASS_DATA_BLK *PromInputBlk + ); diff --git a/xUSL/PROM/PROM21/meson.build b/xUSL/PROM/PROM21/meson.build new file mode 100644 index 0000000..1cc7719 --- /dev/null +++ b/xUSL/PROM/PROM21/meson.build @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT +# Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. + + + +xusl += files([ 'Prom21Init.c' ]) + diff --git a/xUSL/PROM/PromClass-api.h b/xUSL/PROM/PromClass-api.h new file mode 100644 index 0000000..ad08f4d --- /dev/null +++ b/xUSL/PROM/PromClass-api.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: MIT */ +/********************************************************************* + * Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. + ********************************************************************/ + +/** + * @file PromClass-api.h + * @brief openSIL-Host PROM IP interface + * + * @details The Promontory21 (PROM) API adds the capability + * to initialize PROM devices on the PCIe bus. + * MPIO firmware is responsible for link training the PROM chipset. + * + * This file provides the structures details for the Host to configure the + * PROM operations. + */ + +/** @cond API_Doc + * @ingroup MODULES_IP + * @page PROM PROM IP api + * + * The Promontory (PROM) OpenSIL module initializes Promontory21 chipset. + * + * See the 'Files - @ref PromClass-api.h' section of this document for + * details. + * + * + * @endcond + */ +#pragma once + +#include +#include + +#define PROMCLASS_DATA_SIZE sizeof(PROMCLASS_DATA_BLK) + +#define PROM21_NUM_PCIE_LANES 12 +#define PROM21_NUM_PCIE_CLKREQ 6 +#define PROM21_NUM_SATA_PORTS 4 +#define PROM21_XHCI_NUM_USB3_PORTS 6 +#define PROM21_XHCI_NUM_USB2_PORTS 12 +#define PROM21L4_XHCI_NUM_USB3_PORTS 4 +#define PROM21L4_XHCI_NUM_USB2_PORTS 10 + +typedef struct { + uint8_t PT21SataPortGen1Swing; // 0x3 + uint8_t PT21SataPortGen2Swing; // 0x3 + uint8_t PT21SataPortGen3Swing; // 0xf + uint8_t PT21SataPortGen1EmpLevel; // 0x1 + uint8_t PT21SataPortGen2EmpLevel; // 0x1 + uint8_t PT21SataPortGen3EmpLevel; // 0xa +} PROM21_SATA_PHY_TUNING; + +typedef struct { + uint8_t PT21USB3PortGen1Swing; // 0xf + uint8_t PT21USB3PortGen1EmpLevelEn; // 0x1 + uint8_t PT21USB3PortGen1EmpLevel; // 0x3 + uint8_t PT21USB3PortGen1PreshootEn; // 0x0 + uint8_t PT21USB3PortGen1Preshoot; // 0x0 + uint8_t PT21USB3PortGen2Swing; // 0xf + uint8_t PT21USB3PortGen2Cp0EmpLevelEn; // 0x1 + uint8_t PT21USB3PortGen2Cp0EmpLevel; // 0x3 + uint8_t PT21USB3PortGen2Cp0PreshootEn; // 0x1 + uint8_t PT21USB3PortGen2Cp0Preshoot; // 0x0 + uint8_t PT21USB3PortGen2Cp13EmpLevelEn; // 0x0 + uint8_t PT21USB3PortGen2Cp13EmpLevel; // 0x3 + uint8_t PT21USB3PortGen2Cp13PreshootEn; // 0x1 + uint8_t PT21USB3PortGen2Cp13Preshoot; // 0x0 + uint8_t PT21USB3PortGen2Cp14EmpLevelEn; // 0x1 + uint8_t PT21USB3PortGen2Cp14EmpLevel; // 0x3 + uint8_t PT21USB3PortGen2Cp14PreshootEn; // 0x0 + uint8_t PT21USB3PortGen2Cp14Preshoot; // 0x0 + uint8_t PT21USB3PortGen2Cp15EmpLevelEn; // 0x3 + uint8_t PT21USB3PortGen2Cp15EmpLevel; // 0x3 + uint8_t PT21USB3PortGen2Cp15PreshootEn; // 0x0 + uint8_t PT21USB3PortGen2Cp15Preshoot; // 0x0 + uint8_t PT21USB3PortGen2Cp16EmpLevelEn; // 0x3 + uint8_t PT21USB3PortGen2Cp16EmpLevel; // 0x3 + uint8_t PT21USB3PortGen2Cp16PreshootEn; // 0x0 + uint8_t PT21USB3PortGen2Cp16Preshoot; // 0x0 +} PROM21_USB3_PHY_TUNING; + +typedef struct { + uint8_t PT21USB2P0SlewRate; // 0x2 + uint8_t PT21USB2P0DrivingCurrent; // 0x0 + uint8_t PT21USB2P0Termination; // 0x3 +} PROM21_USB2_PHY_TUNING; + +typedef struct { + uint8_t PT21PciePortLaneRev[PROM21_NUM_PCIE_LANES / 2]; // 0xf + uint8_t PT21SIProgEnable; // 0xf + uint8_t PT21ThermalThrottle; // 0xf + uint8_t PT21ThermalThreshold; // 0xC0 + uint8_t PT21LtrSmallEnable; // 0xf + uint8_t PT21PcieGen1SwingEnable; // 0xf + uint8_t PT21PcieGen1Swing[PROM21_NUM_PCIE_LANES]; // {0x1f, 0x1f, 0x1f, 0x1f, 0xf, 0xf, 0xf, 0xf, 0x1f, 0x1f, 0x1f, 0x1f} + uint8_t PT21EqPreset; // 0xf + uint8_t PT21PcieClkreqPinSelect[PROM21_NUM_PCIE_CLKREQ]; // { 0x8, 0x4, 0x0, 0x2, 0x3, 0xE } + uint8_t PT21PcieClkreqMode[PROM21_NUM_PCIE_CLKREQ]; // { 0x0, 0x0, 0x0, 0x0, 0x0, 0x2 } + uint8_t PT21PciePortTargetSpeed[PROM21_NUM_PCIE_LANES]; // { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf } + uint8_t PT21PciePortEnable[PROM21_NUM_PCIE_LANES]; // { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf } + uint8_t PT21Usb3GenSelect; // 0xf + uint8_t PT21XhciPortGen[PROM21_XHCI_NUM_USB3_PORTS]; // { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf } + uint8_t PT21L4Usb3Port[PROM21L4_XHCI_NUM_USB3_PORTS]; // { 0xf, 0xf, 0xf, 0xf } + uint8_t PT21L4Usb2Port[PROM21L4_XHCI_NUM_USB2_PORTS]; // { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf } + uint8_t PT21Usb3ort[PROM21_XHCI_NUM_USB3_PORTS]; // { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf } + uint8_t PT21Usb2Port[PROM21_XHCI_NUM_USB2_PORTS]; // { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf } + PROM21_SATA_PHY_TUNING PT21SataPhy[PROM21_NUM_SATA_PORTS]; + PROM21_USB3_PHY_TUNING PT21USB3Phy[PROM21_XHCI_NUM_USB3_PORTS]; + PROM21_USB2_PHY_TUNING PT21USB2Phy[PROM21_XHCI_NUM_USB2_PORTS / 2]; + uint8_t PT21SataMode; // 0x00 + uint8_t PT21SataAggressiveDevSlp[PROM21_NUM_SATA_PORTS]; // { 0xf, 0xf, 0xf, 0xf } + uint8_t PT21SataAggrLinkPmCap; // 0xf + uint8_t PT21SataPscCap; // 0xf + uint8_t PT21SataSscCap; // 0xf + uint8_t PT21SataPortMdPort[PROM21_NUM_SATA_PORTS]; // { 0xf, 0xf, 0xf, 0xf } + uint8_t PT21SataHotPlug; // 0xf + uint8_t PT21SataPTSataCCCSCap; // 0xf + uint8_t PT21AhciMsiCap; // 0xf + uint8_t PT21SataPortEnable[PROM21_NUM_SATA_PORTS]; // { 0xf, 0xf, 0xf, 0xf } + uint8_t PT21Msi; // 0xf + uint8_t PT21Msix; // 0xf + uint8_t PT21HW_LPM; // 0xf + uint8_t PT21DbC; // 0xf + uint8_t PT21XHC_PME; // 0xf + uint8_t PT21Lock; // 0x01 + uint8_t PT21XhciLock; // 0x00 + uint32_t PT21XhciID; // 0x00000000 + uint32_t PT21GppPcieAddress; // 0x00000000 + uint32_t PT21XhciMmio; // 0x00000000 + uint32_t PT21GpioMmio; // 0x00000000 + uint32_t PT21PcieDspSsid; // 0x33281B21 + uint32_t PT21PcieDspXhciSsid; // 0x33281B21 + uint32_t PT21PcieDspAhciSsid; // 0x33281B21 + uint8_t PT21SsidOverride; // 0xf + uint32_t PT21XhciSsid; // 0x11421B21 + uint32_t PT21AhciSsid; // 0x10621B21 + uint32_t PT21PcieUspSsid; // 0x33281B21 +} PROM21_DATA_BLK; + +/// PROM openSIL Input Block +typedef struct { + uint32_t PT21FwInRamAddress; // 0x0B000000 + uint32_t PT21GpioID; // 0x00000000 + uint64_t PT21FwVersion; // 0x0000000000000000 + uint8_t PT21UsbPortLateDisable; // 0xf + uint8_t PT21TempBusNum; // 0x10 + uint8_t PT21RootBridgeNum; // 0x00 + uint8_t PT21PcieTargetSpeed; // 0x04 + uint8_t PT21IoHcBusNum; // 0x00 + uint32_t PT21IohcBridgeCntl; // 0x00000000 + uint8_t PT21FWLoading; // 0x1 + uint8_t PT21DbgLoadFw; // 0x00 + uint8_t PT21DisableUnusedPciePort; // 0xf + uint8_t PT21SecondPortNumber; // 0xf + uint8_t PT21Revision; // 0x2 + uint8_t PT21TogglePerst; // 0xf + uint8_t PT21RuninRam; // 0x0 + uint8_t PT21ClkPMEnable; // 0xf + uint8_t PT21L1Enable; // 0x1 + uint8_t PT21L1ssEnable; // 0xf + uint8_t PT21ReadThermal; // 0xf + uint8_t PT21GpioPerstEnable; // 0xf + uint8_t PT21GpioTestEnable; // 0xf + uint8_t PT21DelayAfterFWLoading; // 0xf + uint8_t PT21XhciPmeEn; // 0xf + uint32_t PT21CorrErrMask; // 0x6000 + PROM21_DATA_BLK Primary; + PROM21_DATA_BLK Secondary; +} PROMCLASS_DATA_BLK; diff --git a/xUSL/PROM/meson.build b/xUSL/PROM/meson.build new file mode 100644 index 0000000..badf6c4 --- /dev/null +++ b/xUSL/PROM/meson.build @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT +# Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. + +subdir('Common') +subdir('PROM21') + +incdir += include_directories( '.' ) diff --git a/xUSL/meson.build b/xUSL/meson.build index 16e94aa..ca00fd4 100644 --- a/xUSL/meson.build +++ b/xUSL/meson.build @@ -26,6 +26,7 @@ subdir('Nbio') subdir('GFX') subdir('SMU') subdir('RcMgr') +subdir('PROM') # Select the proper group of ASM files for this build if BUILD_IS_32BIT From dba09a01d4ff3f48fb49a09f19abd3fd15b2a54c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=BBygowski?= Date: Fri, 8 May 2026 09:24:55 +0200 Subject: [PATCH 2/6] xUSL/FCH/Common/FchCommon.c: Drop SilFchStall debug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Żygowski --- xUSL/FCH/Common/FchCommon.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/xUSL/FCH/Common/FchCommon.c b/xUSL/FCH/Common/FchCommon.c index 86ef314..076a736 100644 --- a/xUSL/FCH/Common/FchCommon.c +++ b/xUSL/FCH/Common/FchCommon.c @@ -29,7 +29,6 @@ SilFchStall ( uint16_t TimerAddr; uint32_t StartTime; uint32_t ElapsedTime; - FCH_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); SilFchReadPmio(FCH_PM_ACPIPMTMRBLK, AccessWidth16, (uint8_t *)&TimerAddr); if ((TimerAddr == 0) || (TimerAddr == 0xFFFF)) { @@ -52,7 +51,6 @@ SilFchStall ( } } } - FCH_TRACEPOINT(SIL_TRACE_EXIT, "\n"); } /** From 38d27bc348ebfcb7e3f7012a22adb203d51d094a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=BBygowski?= Date: Fri, 8 May 2026 09:29:41 +0200 Subject: [PATCH 3/6] xUSL/Mpio: Add GetEarlyLinkConfig Xfer API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Żygowski --- xUSL/Mpio/Common/MpioCmn2Rev.h | 15 +++++++ xUSL/Mpio/Phx/MpioCmn2Phx.c | 3 +- xUSL/Mpio/Phx/MpioCmn2Phx.h | 10 ++++- xUSL/Mpio/Phx/MpioInitPhx.c | 73 +++++++++++++++++++++++++++++++++- 4 files changed, 97 insertions(+), 4 deletions(-) diff --git a/xUSL/Mpio/Common/MpioCmn2Rev.h b/xUSL/Mpio/Common/MpioCmn2Rev.h index 718b461..e2078b7 100644 --- a/xUSL/Mpio/Common/MpioCmn2Rev.h +++ b/xUSL/Mpio/Common/MpioCmn2Rev.h @@ -168,6 +168,20 @@ typedef SIL_STATUS (*MPIO_PCIE_SET_SPEED) ( uint8_t TargetSpeed ); +typedef struct { + bool EarlyLinkStatus; + uint8_t PhysicalRootBridge; + uint8_t LogicalRootBridge; + uint8_t RootPortBus; + uint8_t RootPortDevice; + uint8_t RootPortFunction; +} EARLY_LINK_STATUS; + +typedef SIL_STATUS (*MPIO_GET_EARLY_LINK_CONFIG) ( + SIL_CONTEXT *SilContext, + EARLY_LINK_STATUS *EarlyLinkStatus + ); + // Define the Cmn2Rev xfer table containing pointers to these functions typedef struct { @@ -200,4 +214,5 @@ typedef struct { MPIO_GET_PORT_ID MpioGetPortId; MPIO_REMOVE_CXL_LINKS MpioRemoveCxlLinks; MPIO_PCIE_SET_SPEED MpioPcieSetSpeed; + MPIO_GET_EARLY_LINK_CONFIG MpioGetEarlyLinkConfig; } MPIO_COMMON_2_REV_XFER_BLOCK; diff --git a/xUSL/Mpio/Phx/MpioCmn2Phx.c b/xUSL/Mpio/Phx/MpioCmn2Phx.c index 02cb027..9ca3f65 100644 --- a/xUSL/Mpio/Phx/MpioCmn2Phx.c +++ b/xUSL/Mpio/Phx/MpioCmn2Phx.c @@ -38,5 +38,6 @@ MPIO_COMMON_2_REV_XFER_BLOCK MpioXferPhx = { .MpioReleasePort = MpioReleasePortPhx, .MpioGetPortId = MpioGetPortIdPhx, .MpioRemoveCxlLinks = MpioRemoveCxlLinksPhx, - .MpioPcieSetSpeed = MpioPcieSetSpeed + .MpioPcieSetSpeed = MpioPcieSetSpeed, + .MpioGetEarlyLinkConfig = MpioGetEarlyLinkConfig }; diff --git a/xUSL/Mpio/Phx/MpioCmn2Phx.h b/xUSL/Mpio/Phx/MpioCmn2Phx.h index c0c345e..ca91352 100644 --- a/xUSL/Mpio/Phx/MpioCmn2Phx.h +++ b/xUSL/Mpio/Phx/MpioCmn2Phx.h @@ -11,9 +11,9 @@ #include #include +#include #include - void MpioCfgGlobalConfigPhx ( SIL_CONTEXT *SilContext, @@ -205,4 +205,10 @@ MpioPcieSetSpeed ( uint8_t PciDevice, uint8_t PciFunction, uint8_t TargetSpeed - ); \ No newline at end of file + ); + +SIL_STATUS +MpioGetEarlyLinkConfig ( + SIL_CONTEXT *SilContext, + EARLY_LINK_STATUS *EarlyLinkStatus + ); diff --git a/xUSL/Mpio/Phx/MpioInitPhx.c b/xUSL/Mpio/Phx/MpioInitPhx.c index ad2261d..0f8e763 100644 --- a/xUSL/Mpio/Phx/MpioInitPhx.c +++ b/xUSL/Mpio/Phx/MpioInitPhx.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -616,7 +617,7 @@ MpioPcieSetSpeed ( StartLaneId = 0xFF; EndLaneId = 0xFF; - PcieWrapper = (PCIe_WRAPPER_CONFIG *) NbioIp2Ip->PcieConfigGetChild(DESCRIPTOR_ALL_WRAPPERS, &Pcie->Header); + PcieWrapper = (PCIe_WRAPPER_CONFIG *) NbioIp2Ip->PcieConfigGetChild(DESCRIPTOR_ALL_WRAPPERS, &(GnbHandle->Header)); while (PcieWrapper != NULL) { PcieEngine =(PCIe_ENGINE_CONFIG *)(NbioIp2Ip->PcieConfigGetChild(DESCRIPTOR_ALL_ENGINES, &(PcieWrapper->Header))); while (PcieEngine != NULL) { @@ -655,3 +656,73 @@ MpioPcieSetSpeed ( return Status; } + +static void +FindEarlyLink ( + SIL_CONTEXT *SilContext, + PCIe_ENGINE_CONFIG *Engine, + void *Buffer, + PCIe_PLATFORM_CONFIG *Pcie + ) +{ + GNB_HANDLE *GnbHandle; + EARLY_LINK_STATUS *EarlyLinkStatus; + + if (Engine->Type.Port.PortData.MiscControls.SbLink == 1) { + if (Engine->InitStatus == INIT_STATUS_PCIE_TRAINING_SUCCESS) { + EarlyLinkStatus = (EARLY_LINK_STATUS *)Buffer; + EarlyLinkStatus->EarlyLinkStatus = true; + GnbHandle = (GNB_HANDLE *)PcieConfigGetParentSilicon(Engine); + EarlyLinkStatus->PhysicalRootBridge = GnbHandle->RBIndex; + EarlyLinkStatus->LogicalRootBridge = GnbHandle->LogicalRBIndex; + EarlyLinkStatus->RootPortBus = (uint8_t) GnbHandle->Address.Address.Bus; + EarlyLinkStatus->RootPortDevice = Engine->Type.Port.PortData.DeviceNumber; + EarlyLinkStatus->RootPortFunction = Engine->Type.Port.PortData.FunctionNumber; + } + } +} + +SIL_STATUS +MpioGetEarlyLinkConfig ( + SIL_CONTEXT *SilContext, + EARLY_LINK_STATUS *EarlyLinkStatus + ) +{ + PCIe_PLATFORM_CONFIG *Pcie; + NBIO_IP2IP_API *NbioIp2Ip; + NORTH_BRIDGE_PCIE_SIB *NbPcieData; + + MPIO_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + if (SilGetIp2IpApi(SilContext, SilId_NbioClass, (void **)(&NbioIp2Ip)) != SilPass) { + MPIO_TRACEPOINT(SIL_TRACE_ERROR, " NBIO API is not found.\n"); + return SilNotFound; + } + NbPcieData = (NORTH_BRIDGE_PCIE_SIB *)xUslFindStructure(SilContext, + SilId_NbioClass, + NBIOPCIECLASS_INSTANCE); + if (NbPcieData == NULL) { + MPIO_TRACEPOINT(SIL_TRACE_ERROR, " NBIO Pcie config not found.\n"); + return SilNotFound; + } + + Pcie = &NbPcieData->PciePlatformConfig; + + EarlyLinkStatus->EarlyLinkStatus = false; + EarlyLinkStatus->PhysicalRootBridge = 0; + EarlyLinkStatus->LogicalRootBridge = 0; + EarlyLinkStatus->RootPortBus = 0; + EarlyLinkStatus->RootPortDevice = 0; + EarlyLinkStatus->RootPortFunction = 0; + + NbioIp2Ip->PcieConfigRunProcForAllEngines(SilContext, + DESCRIPTOR_ALLOCATED | DESCRIPTOR_PCIE_ENGINE, + FindEarlyLink, + EarlyLinkStatus, + Pcie + ); + + MPIO_TRACEPOINT(SIL_TRACE_EXIT, "\n"); + + return SilPass; +} From d2f4cca04720921a760c1c63043bc7771ce42521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=BBygowski?= Date: Fri, 8 May 2026 09:30:11 +0200 Subject: [PATCH 4/6] xUSL/PROM: Add Promontory21 initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Żygowski --- xUSL/Include/Pci.h | 16 +- xUSL/PROM/Common/PromAccess.c | 685 ++++++++++++++ xUSL/PROM/Common/PromAccess.h | 107 +++ xUSL/PROM/Common/PromClassDflts.c | 107 ++- xUSL/PROM/Common/PromInit.c | 10 +- xUSL/PROM/Common/meson.build | 5 +- xUSL/PROM/PROM21/Prom21.c | 513 +++++++++++ xUSL/PROM/PROM21/Prom21.h | 374 ++++++++ xUSL/PROM/PROM21/Prom21Gpio.c | 426 +++++++++ xUSL/PROM/PROM21/Prom21Gpio.h | 38 + xUSL/PROM/PROM21/Prom21Init.c | 504 ++++++++++- xUSL/PROM/PROM21/Prom21Init.h | 4 +- xUSL/PROM/PROM21/Prom21LoadFw.c | 1392 +++++++++++++++++++++++++++++ xUSL/PROM/PROM21/Prom21PreInit.c | 876 ++++++++++++++++++ xUSL/PROM/PROM21/Prom21Sata.c | 479 ++++++++++ xUSL/PROM/PROM21/Prom21Xhci.c | 77 ++ xUSL/PROM/PROM21/meson.build | 10 +- xUSL/PROM/PromClass-api.h | 278 +++--- 18 files changed, 5711 insertions(+), 190 deletions(-) create mode 100644 xUSL/PROM/Common/PromAccess.c create mode 100644 xUSL/PROM/Common/PromAccess.h create mode 100644 xUSL/PROM/PROM21/Prom21.c create mode 100644 xUSL/PROM/PROM21/Prom21.h create mode 100644 xUSL/PROM/PROM21/Prom21Gpio.c create mode 100644 xUSL/PROM/PROM21/Prom21Gpio.h create mode 100644 xUSL/PROM/PROM21/Prom21LoadFw.c create mode 100644 xUSL/PROM/PROM21/Prom21PreInit.c create mode 100644 xUSL/PROM/PROM21/Prom21Sata.c create mode 100644 xUSL/PROM/PROM21/Prom21Xhci.c diff --git a/xUSL/Include/Pci.h b/xUSL/Include/Pci.h index 5e0e010..40905e9 100644 --- a/xUSL/Include/Pci.h +++ b/xUSL/Include/Pci.h @@ -12,8 +12,6 @@ #include "stdint.h" -#define PCIE_CAP_ID 0x10 - #define MAKE_SBDFO(Seg, Bus, Dev, Fun, Off) ((((uint32_t) (Seg)) << 28) | (((uint32_t) (Bus)) << 20) | \ (((uint32_t)(Dev)) << 15) | (((uint32_t)(Fun)) << 12) | ((uint32_t)(Off))) @@ -87,3 +85,17 @@ void xUSLPciWrite (uint32_t Address, ACCESS_WIDTH Width, void *Value); #define PCI_HEADER_TYPE_REG (0x0E) #define MULTI_FUNC_DEVICE_MASK (BIT_32(7)) #define PCI_REVISION_ID_REG (0x08) + +// +// PCI Express Capability Structure +// +#define PCIE_CAP_ID 0x10 + +#define PCIE_LINK_CAP_REG 0x0C // Link Capabilities Register (Offset 0Ch) +#define PCIE_LINK_CONTROL_REG 0x10 // Link Control Register (Offset 10h) +#define PCIE_LINK_STATUS_REG 0x12 // Link Status Register (Offset 12h) +#define PCIE_SLOT_STATUS_REG 0x1A // Slot Status Register (Offset 1Ah) + +#define PCIE_DEVICE_CAP2_REG 0x24 // Device Capabilities 2 Register (Offset 24h) +#define PCIE_DEVICE_CONTROL2_REG 0x28 // Device Control 2 Register (Offset 28h) +#define PCIE_LINK_CONTROL2_REG 0x30 // Link Control 2 Register (Offset 30h) diff --git a/xUSL/PROM/Common/PromAccess.c b/xUSL/PROM/Common/PromAccess.c new file mode 100644 index 0000000..449f708 --- /dev/null +++ b/xUSL/PROM/Common/PromAccess.c @@ -0,0 +1,685 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ + +/** + * @file PromAccess.c + * @brief Promontory21 helper functions + */ + +#include +#include +#include +#include +#include +#include +#include "PromAccess.h" +#include "PromInit.h" + +static void CheckPcieWriteCycleV2 ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint32_t XhciMmio, + uint8_t Address, + uint8_t Offset + ) +{ + uint8_t Data; + uint8_t Counter; + PROM_PCI_SAVE_RESTORE_TABLE PtPciTable[2]; + + Counter = 0; + do { + Data = xUSLMemRead8((void *)(size_t)(XhciMmio + 0x3009)); + if (Data == 0xFF) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT reset itself --%u-- !!!\n", Offset); + if (PromDataBlk->PromInputBlk.PT21Revision < 2) { + if (XhciMmio == PromDataBlk->PromOutputBlk.PT21XhciMmio[0]) { + SaveInitPromBus(PromDataBlk, PtPciTable, 0x00BB); + } else { + SaveInitPromBus(PromDataBlk, PtPciTable, 0xBBBB); + } + } + xUSLMemWrite8((void *)(size_t)(XhciMmio + 0x3002 - Offset), Address); + } else if (Data & BIT_8(7)) { + Counter++; + if (Counter == 100) { + SilFchStall(200 * 1000); + Counter = 0; + } + } + } while (Data & BIT_8(7)); +} + +static void +Prom21XhciSetAddressV2 ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint32_t XhciMmio, + uint32_t Address + ) +{ + xUSLMemWrite8((void *)(size_t)(XhciMmio + 0x3002), (Address >> 16) & 0xFF); + CheckPcieWriteCycleV2(PromDataBlk, XhciMmio, (Address >> 16) & 0xFF, 0); + + xUSLMemWrite8((void *)(size_t)(XhciMmio + 0x3001), (Address >> 8) & 0xFF); + CheckPcieWriteCycleV2(PromDataBlk, XhciMmio, (Address >> 8) & 0xFF, 1); + + xUSLMemWrite8((void *)(size_t)(XhciMmio + 0x3000), Address & 0xFF); + CheckPcieWriteCycleV2(PromDataBlk, XhciMmio, Address & 0xFF, 2); +} + +uint8_t +Prom21XhciReadByteV2 ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint32_t XhciMmio, + uint32_t Address + ) +{ + Prom21XhciSetAddressV2(PromDataBlk, XhciMmio, Address); + return xUSLMemRead8((void *)(size_t)(XhciMmio + 0x3008)); +} + +static void CheckPcieWriteCycle ( + uint32_t XhciMmio + ) +{ + while (xUSLMemRead8((void *)(size_t)(XhciMmio + 0x3009)) & BIT_8(7)); +} + +static void +Prom21XhciSetAddress ( + uint32_t XhciMmio, + uint32_t Address + ) +{ + xUSLMemWrite8((void *)(size_t)(XhciMmio + 0x3002), ((Address >> 16) & 0xFF)); + CheckPcieWriteCycle(XhciMmio); + + xUSLMemWrite8((void *)(size_t)(XhciMmio + 0x3001), ((Address >> 8) & 0xFF)); + CheckPcieWriteCycle(XhciMmio); + + xUSLMemWrite8((void *)(size_t)(XhciMmio + 0x3000), (Address & 0xFF)); + CheckPcieWriteCycle(XhciMmio); +} + +uint8_t +Prom21XhciReadByte ( + uint32_t XhciMmio, + uint32_t Address + ) +{ + xUSLMemRead8((void *)(size_t)(XhciMmio + 0x3009)); // check + Prom21XhciSetAddress(XhciMmio, Address); + return xUSLMemRead8((void *)(size_t)(XhciMmio + 0x3008)); +} + +uint16_t +Prom21XhciReadWord ( + uint32_t XhciMmio, + uint32_t Address + ) +{ + uint8_t DataByte; + uint16_t DataWord = 0; + + xUSLMemRead8((void *)(size_t)(XhciMmio + 0x3009)); // check + + for (uint32_t i = 0; i < sizeof(DataWord); i++) { + Prom21XhciSetAddress(XhciMmio, Address + i); + DataByte = xUSLMemRead8((void *)(size_t)(XhciMmio + 0x3008)); + DataWord |= ((uint16_t)DataByte) << (8 * i); + } + + return DataWord; +} + +uint32_t +Prom21XhciReadDWord ( + uint32_t XhciMmio, + uint32_t Address + ) +{ + uint8_t DataByte; + uint32_t DataDWord = 0; + + xUSLMemRead8((void *)(size_t)(XhciMmio + 0x3009)); // check + + for (uint32_t i = 0; i < sizeof(DataDWord); i++) { + Prom21XhciSetAddress(XhciMmio, Address + i); + DataByte = xUSLMemRead8((void *)(size_t)(XhciMmio + 0x3008)); + DataDWord |= ((uint32_t)DataByte) << (8 * i); + } + + return DataDWord; +} + +void +Prom21XhciWriteByte ( + uint32_t XhciMmio, + uint32_t Address, + uint8_t Data + ) +{ + xUSLMemRead8((void *)(size_t)(XhciMmio + 0x3009)); // check + Prom21XhciSetAddress(XhciMmio, Address); + xUSLMemWrite8((void *)(size_t)(XhciMmio + 0x3004), Data); + CheckPcieWriteCycle(XhciMmio); +} + +void +Prom21XhciWriteWord ( + uint32_t XhciMmio, + uint32_t Address, + uint16_t Data + ) +{ + xUSLMemRead8((void *)(size_t)(XhciMmio + 0x3009)); // check + + for (uint32_t i = 0; i < sizeof(Data); i++) { + Prom21XhciSetAddress(XhciMmio, Address + i); + xUSLMemWrite8((void *)(size_t)(XhciMmio + 0x3004), ((Data >> (8 * i)) & 0xFF)); + CheckPcieWriteCycle(XhciMmio); + } +} + +void +Prom21XhciWriteDWord ( + uint32_t XhciMmio, + uint32_t Address, + uint32_t Data + ) +{ + xUSLMemRead8((void *)(size_t)(XhciMmio + 0x3009)); // check + for (uint32_t i = 0; i < sizeof(Data); i++) { + Prom21XhciSetAddress(XhciMmio, Address + i); + xUSLMemWrite8((void *)(size_t)(XhciMmio + 0x3004), ((Data >> (8 * i)) & 0xFF)); + CheckPcieWriteCycle(XhciMmio); + } +} + +static void +SaveInitSingleProm ( + PROMCLASS_DATA_BLK *PromDataBlk, + PROM_PCI_SAVE_RESTORE_TABLE *PtPciTable, + uint8_t CheckBit, + bool IsPrimary + ) +{ + uint16_t GppBus; + uint8_t GppDev; + uint8_t GppFun; + uint32_t GppPcieAddress; + uint32_t XhciMmio; + uint32_t SecXhciMmio; + uint32_t PciAddr; + uint32_t PromAddr; + uint32_t XhciDspAddr; + uint32_t SataDspAddr; + uint32_t XhciAddr; + uint32_t SataAddr; + + if (IsPrimary) { + GppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[0]; + } else { + GppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[1]; + } + + XhciMmio = PromDataBlk->PromOutputBlk.PT21XhciMmio[0]; + SecXhciMmio = PromDataBlk->PromOutputBlk.PT21XhciMmio[1]; + + GppBus = (uint16_t) ((GppPcieAddress >> 20) & 0xFFF); + GppDev = (uint8_t) ((GppPcieAddress >> 15) & 0x1F); + GppFun = (uint8_t) ((GppPcieAddress >> 12) & 0x07); + + if (GppPcieAddress == 0) { + return; + } + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, " Save Init %s PROM21" + "-%s" + "-%s" + "-%s" + "-%s" + "-%s" + "-%s" + "-%s" + "-%s\n", + IsPrimary ? "Primary" : "Secondary", + (CheckBit & BIT_8(0)) ? "UspBus" : " ", + (CheckBit & BIT_8(1)) ? "XhciBus" : " ", + (CheckBit & BIT_8(2)) ? "SataBus" : " ", + (CheckBit & BIT_8(3)) ? "XhciMmio" : " ", + (CheckBit & BIT_8(4)) ? "UspCmd" : " ", + (CheckBit & BIT_8(5)) ? "XhciCmd" : " ", + (CheckBit & BIT_8(6)) ? "SataCmd" : " ", + (CheckBit & BIT_8(7)) ? "ASPM" : " " + ); + + PciAddr = PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0); + PromAddr = PCI_LIB_ADDRESS(PtPciTable->PromBus, 0, 0, 0); + XhciDspAddr = PCI_LIB_ADDRESS(PtPciTable->PromBus + 1, PROM21_XHCI_DSP_DEV, 0, 0); + SataDspAddr = PCI_LIB_ADDRESS(PtPciTable->PromBus + 1, PROM21_SATA_DSP_DEV, 0, 0); + XhciAddr = PCI_LIB_ADDRESS(PtPciTable->PromBus + 2, 0, 0, 0); + SataAddr = PCI_LIB_ADDRESS(PtPciTable->PromBus + 3, 0, 0, 0); + + + if (CheckBit & (BIT_8(7) + BIT_8(2) + BIT_8(1) + BIT_8(0))) { + PtPciTable->GppBus = xUSLPciRead32(PciAddr + 0x18); + xUSLPciWrite8(PciAddr + 0x18, (uint8_t)GppBus); + xUSLPciWrite8(PciAddr + 0x19, (uint8_t)PtPciTable->PromBus); + xUSLPciWrite8(PciAddr + 0x1A, (uint8_t)(PtPciTable->PromBus + 7)); + + PtPciTable->UspBus = xUSLPciRead32(PromAddr + 0x18); + xUSLPciWrite8(PromAddr + 0x18, (uint8_t)PtPciTable->PromBus); + xUSLPciWrite8(PromAddr + 0x19, (uint8_t)(PtPciTable->PromBus + 1)); + xUSLPciWrite8(PromAddr + 0x1A, (uint8_t)(PtPciTable->PromBus + 7)); + } + + if (CheckBit & (BIT_8(7) + BIT_8(1))) { + PtPciTable->XhciDspBus = xUSLPciRead32(XhciDspAddr + 0x18); + xUSLPciWrite8(XhciDspAddr + 0x18, (uint8_t)PtPciTable->PromBus + 1); + xUSLPciWrite8(XhciDspAddr + 0x19, (uint8_t)PtPciTable->PromBus + 2); + xUSLPciWrite8(XhciDspAddr + 0x1A, (uint8_t)PtPciTable->PromBus + 2); + } + + if (CheckBit & (BIT_8(7) + BIT_8(2))) { + PtPciTable->SataDspBus = xUSLPciRead32(SataDspAddr + 0x18); + xUSLPciWrite8(SataDspAddr + 0x18, (uint8_t)(PtPciTable->PromBus + 1)); + xUSLPciWrite8(SataDspAddr + 0x19, (uint8_t)(PtPciTable->PromBus + 3)); + xUSLPciWrite8(SataDspAddr + 0x1A, (uint8_t)(PtPciTable->PromBus + 3)); + } + + if ((CheckBit & BIT_8(3))) { + PtPciTable->GppMmio = xUSLPciRead32(PciAddr + 0x20); + xUSLPciWrite16(PciAddr + 0x20, (uint16_t)(XhciMmio >> 16)); + xUSLPciWrite16(PciAddr + 0x22, (uint16_t)(SecXhciMmio >> 16)); + + PtPciTable->UspMmio = xUSLPciRead32(PromAddr + 0x20); + xUSLPciWrite16(PromAddr + 0x20, (uint16_t)(XhciMmio >> 16)); + xUSLPciWrite16(PromAddr + 0x22, (uint16_t)(SecXhciMmio >> 16)); + + PtPciTable->XhciDspMmio = xUSLPciRead32(XhciDspAddr + 0x20); + xUSLPciWrite16(XhciDspAddr + 0x20, (uint16_t)(XhciMmio >> 16)); + xUSLPciWrite16(XhciDspAddr + 0x22, (uint16_t)(XhciMmio >> 16)); + + PtPciTable->XhciMmio = xUSLPciRead32(XhciAddr + 0x10) & 0xFFFFFF00; + xUSLPciWrite32(XhciAddr + 0x10, XhciMmio); + } + + if ((CheckBit & (BIT_8(6) + BIT_8(5) + BIT_8(4)))) { + PtPciTable->GppCmd = xUSLPciRead8(PciAddr + 0x04); + xUSLPciWrite8(PciAddr + 0x04, 6); + + PtPciTable->UspCmd = xUSLPciRead8(PromAddr + 0x04); + xUSLPciWrite8(PromAddr + 0x04, 6); + } + + if ((CheckBit & BIT_8(5))) { + PtPciTable->XhciDspCmd = xUSLPciRead8(XhciDspAddr + 0x04); + xUSLPciWrite8(XhciDspAddr + 0x04, 6); + + PtPciTable->XhciCmd = xUSLPciRead8(XhciAddr + 0x04); + xUSLPciWrite8(XhciAddr + 0x04, 6); + } + + if ((CheckBit & BIT_8(6))) { + PtPciTable->SataDspCmd = xUSLPciRead8(SataDspAddr + 0x04); + xUSLPciWrite8(SataDspAddr + 0x04, 6); + + PtPciTable->SataCmd = xUSLPciRead8(SataAddr + 0x04); + xUSLPciWrite8(SataAddr + 0x04, 6); + } + + if ((CheckBit & BIT_8(7)) == BIT_8(7)) { + PtPciTable->GppAspm = xUSLPciRead8(PciAddr + 0x68); + xUSLPciWrite8(PciAddr + 0x68, PtPciTable->GppAspm & 0xFC); + + PtPciTable->UspAspm = xUSLPciRead8(PromAddr + 0x90); + xUSLPciWrite8(PromAddr + 0x90, PtPciTable->UspAspm & 0xFC); + + PtPciTable->XhciDspAspm = xUSLPciRead8(XhciDspAddr + 0x90); + xUSLPciWrite8(XhciDspAddr + 0x90, PtPciTable->XhciDspAspm & 0xFC); + + PtPciTable->SataDspAspm = xUSLPciRead8(SataDspAddr + 0x90); + xUSLPciWrite8(SataDspAddr + 0x90, PtPciTable->SataDspAspm & 0xFC); + + PtPciTable->XhciAspm = xUSLPciRead8(XhciAddr + 0x90); + xUSLPciWrite8(XhciAddr + 0x90, PtPciTable->XhciAspm & 0xFC); + + PtPciTable->SataAspm = xUSLPciRead8(SataAddr + 0x90); + xUSLPciWrite8(SataAddr + 0x90, PtPciTable->SataAspm & 0xFC); + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + +static void +SaveInitPromBusNumbers ( + PROMCLASS_DATA_BLK *PromDataBlk, + PROM_PCI_SAVE_RESTORE_TABLE *PtPciTable, + uint16_t CheckBit + ) +{ + uint16_t GppBus = (uint16_t) ((PromDataBlk->PromOutputBlk.PT21GppPcieAddress[0] >> 20) & 0xFFF); + + PtPciTable[0].PromBus = 0; + PtPciTable[1].PromBus = 0; + + if (CheckBit & 0xff) { + PtPciTable[0].PromBus = PromDataBlk->PromInputBlk.PT21TempBusNum + GppBus; + } + + if (CheckBit & 0xff00) { + PtPciTable[1].PromBus = PtPciTable->PromBus + 4; + } +} + +/** + * SaveInitPromBus + * + * @brief Save and Init Prom Bus/Command/Mmio/Aspm + * + * @param PtPciTable Save Restore Table location + * @param CheckBit Bit0 = 1 - Save and Init UspBus + * Bit1 = 1 - Save and Init XhciBus + * Bit2 = 1 - Save and Init SataBus + * Bit3 = 1 - Save and Init XhciMmio + * Bit4 = 1 - Save and Init UspCmd + * Bit5 = 1 - Save and Init XhciCmd + * Bit6 = 1 - Save and Init SataCmd + * Bit7 = 1 - Save and Disable ASPM + * Bit8 = 1 - Save and Init SecUspBus + * Bit9 = 1 - Save and Init SecXhciBus + * Bit10 = 1 - Save and Init SecSataBus + * Bit11 = 1 - Save and Init SecXhciMmio + * Bit12 = 1 - Save and Init SecUspCmd + * Bit13 = 1 - Save and Init SecXhciCmd + * Bit14 = 1 - Save and Init SecSataCmd + * Bit15 = 1 - Save and Disable Secondary ASPM + */ +void +SaveInitPromBus ( + PROMCLASS_DATA_BLK *PromDataBlk, + PROM_PCI_SAVE_RESTORE_TABLE *PtPciTable, + uint16_t CheckBit + ) +{ + SaveInitPromBusNumbers(PromDataBlk, PtPciTable, CheckBit); + SaveInitSingleProm(PromDataBlk, &PtPciTable[0], CheckBit & 0xff, true); + SaveInitSingleProm(PromDataBlk, &PtPciTable[1], CheckBit >> 8, false); +} + +static void +RestoreSingleProm ( + PROMCLASS_DATA_BLK *PromDataBlk, + PROM_PCI_SAVE_RESTORE_TABLE *PtPciTable, + uint8_t CheckBit, + bool IsPrimary + ) +{ + uint16_t GppBus; + uint8_t GppDev; + uint8_t GppFun; + uint32_t GppPcieAddress; + uint32_t PciAddr; + uint32_t PromAddr; + uint32_t XhciDspAddr; + uint32_t SataDspAddr; + uint32_t XhciAddr; + uint32_t SataAddr; + + if (IsPrimary) { + GppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[0]; + } else { + GppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[1]; + } + + GppBus = (uint16_t) ((GppPcieAddress >> 20) & 0xFFF); + GppDev = (uint8_t) ((GppPcieAddress >> 15) & 0x1F); + GppFun = (uint8_t) ((GppPcieAddress >> 12) & 0x07); + + if (GppPcieAddress == 0) { + return; + } + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, " Restore %s PROM21" + "-%s" + "-%s" + "-%s" + "-%s" + "-%s" + "-%s" + "-%s" + "-%s\n", + IsPrimary ? "Primary" : "Secondary", + (CheckBit & BIT_8(0)) ? "UspBus" : " ", + (CheckBit & BIT_8(1)) ? "XhciBus" : " ", + (CheckBit & BIT_8(2)) ? "SataBus" : " ", + (CheckBit & BIT_8(3)) ? "XhciMmio" : " ", + (CheckBit & BIT_8(4)) ? "UspCmd" : " ", + (CheckBit & BIT_8(5)) ? "XhciCmd" : " ", + (CheckBit & BIT_8(6)) ? "SataCmd" : " ", + (CheckBit & BIT_8(7)) ? "ASPM" : " " + ); + + PciAddr = PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0); + PromAddr = PCI_LIB_ADDRESS(PtPciTable->PromBus, 0, 0, 0); + XhciDspAddr = PCI_LIB_ADDRESS(PtPciTable->PromBus + 1, PROM21_XHCI_DSP_DEV, 0, 0); + SataDspAddr = PCI_LIB_ADDRESS(PtPciTable->PromBus + 1, PROM21_SATA_DSP_DEV, 0, 0); + XhciAddr = PCI_LIB_ADDRESS(PtPciTable->PromBus + 2, 0, 0, 0); + SataAddr = PCI_LIB_ADDRESS(PtPciTable->PromBus + 3, 0, 0, 0); + + if (CheckBit & BIT_8(7)) { + xUSLPciWrite8(XhciAddr + 0x90, PtPciTable->XhciAspm); + xUSLPciWrite8(SataAddr + 0x90, PtPciTable->SataAspm); + xUSLPciWrite8(XhciDspAddr + 0x90, PtPciTable->XhciDspAspm); + xUSLPciWrite8(SataDspAddr + 0x90, PtPciTable->SataDspAspm); + xUSLPciWrite8(PromAddr + 0x90, PtPciTable->UspAspm); + xUSLPciWrite8(PciAddr + 0x68, PtPciTable->GppAspm); + } + + if (CheckBit & BIT_8(5)) { + xUSLPciWrite8(XhciAddr + 0x04, PtPciTable->XhciCmd); + xUSLPciWrite8(XhciDspAddr + 0x04, PtPciTable->XhciDspCmd); + } + + if (CheckBit & BIT_8(6)) { + xUSLPciWrite8(SataAddr + 0x04, PtPciTable->SataCmd); + xUSLPciWrite8(SataDspAddr + 0x04, PtPciTable->SataDspCmd); + } + + if (CheckBit & (BIT_8(6) + BIT_8(5) + BIT_8(4))) { + xUSLPciWrite8(PromAddr + 0x04, PtPciTable->UspCmd); + xUSLPciWrite8(PciAddr + 0x04, PtPciTable->GppCmd); + } + + if (CheckBit & BIT_8(3)) { + xUSLPciWrite32(XhciAddr + 0x10, PtPciTable->XhciMmio); + xUSLPciWrite32(XhciDspAddr + 0x20, PtPciTable->XhciDspMmio); + xUSLPciWrite32(PromAddr + 0x20, PtPciTable->UspMmio); + xUSLPciWrite32(PciAddr + 0x20, PtPciTable->GppMmio); + } + + if (CheckBit & (BIT_8(7) + BIT_8(1))) { + xUSLPciWrite32(XhciDspAddr + 0x18, PtPciTable->XhciDspBus); + } + + if (CheckBit & (BIT_8(7) + BIT_8(2))) { + xUSLPciWrite32(SataDspAddr + 0x18, PtPciTable->SataDspBus); + } + + if (CheckBit & (BIT_8(7) + BIT_8(2) + BIT_8(1) + BIT_8(0))) { + xUSLPciWrite32(PromAddr + 0x18, PtPciTable->UspBus); + xUSLPciWrite32(PciAddr + 0x18, PtPciTable->GppBus); + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + + +/** + * RestorePromBus + * + * @brief Restore Prom Bus/Command/Mmio/Aspm + * + * @param PtPciTable Save Restore Table location + * @param CheckBit Bit0 = 1 - Restore Original UspBus + * Bit1 = 1 - Restore Original XhciBus + * Bit2 = 1 - Restore Original SataBus + * Bit3 = 1 - Restore Original XhciMmio + * Bit4 = 1 - Restore Original UspCmd + * Bit5 = 1 - Restore Original XhciCmd + * Bit6 = 1 - Restore Original SataCmd + * Bit7 = 1 - Restore Original ASPM + * Bit8 = 1 - Restore Original SecUspBus + * Bit9 = 1 - Restore Original SecXhciBus + * Bit10 = 1 - Restore Original SecSataBus + * Bit11 = 1 - Restore Original SecXhciMmio + * Bit12 = 1 - Restore Original SecUspCmd + * Bit13 = 1 - Restore Original SecXhciCmd + * Bit14 = 1 - Restore Original SecSataCmd + * Bit15 = 1 - Restore Original Secondary ASPM + */ +void +RestorePromBus ( + PROMCLASS_DATA_BLK *PromDataBlk, + PROM_PCI_SAVE_RESTORE_TABLE *PtPciTable, + uint16_t CheckBit + ) +{ + RestoreSingleProm(PromDataBlk, &PtPciTable[1], CheckBit >> 8, false); + RestoreSingleProm(PromDataBlk, &PtPciTable[0], CheckBit & 0xFF, true); +} + +SIL_STATUS +Prom21RetrainSpeed ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint16_t Bus, + uint8_t Dev, + uint8_t Func, + uint32_t XhciMmio, + uint8_t Speed, + bool LinkDisable + ) +{ + SIL_STATUS Status; + uint16_t LinkStatus; + uint8_t TargetSpeed; + uint8_t CurrentSpeed; + uint8_t CapBaseAddr; + size_t Counter; + uint8_t AssertPin; + uint32_t Address; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "[%04X:%02X:%02X] at Speed %d\n", Bus, Dev, Func, Speed); + + Status = SilDeviceError; + Address = PCI_LIB_ADDRESS(Bus, Dev, Func, 0); + + CapBaseAddr = xUSLPciLibFindPciCapability(Address, PCIE_CAP_ID); + if ((CapBaseAddr == 0) || (CapBaseAddr == 0xFF)) { + return Status; + } + + Status = SilPass; + CurrentSpeed = xUSLPciRead8(Address + CapBaseAddr + PCIE_LINK_STATUS_REG); + + PROM_TRACEPOINT(SIL_TRACE_INFO, "PCIe Link Width & Link Speed is x%d Gen%d LinkDisable (%d)\n", + CurrentSpeed >> 4, CurrentSpeed & 0xF, LinkDisable); + + if (LinkDisable) { + LinkStatus = xUSLPciRead16(Address + CapBaseAddr + PCIE_LINK_CONTROL_REG); + LinkStatus |= BIT_16(4); + xUSLPciWrite16(Address + CapBaseAddr + PCIE_LINK_CONTROL_REG, LinkStatus); + + if (XhciMmio != 0) { + SilFchStall(5 * 1000); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Assert GPP PERST# before link disabled\n"); + AssertPin = Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x2E20F); + AssertPin |= BIT_8(4); + Prom21XhciWriteByte(XhciMmio, 0x2E20F, AssertPin); + SilFchStall(20 * 1000); + } + do { + LinkStatus = xUSLPciRead16(Address + CapBaseAddr + PCIE_LINK_STATUS_REG); + } while (LinkStatus & BIT_16(13)); + + TargetSpeed = xUSLPciRead8(Address + CapBaseAddr + PCIE_LINK_CONTROL2_REG); + TargetSpeed &= 0xF0; + TargetSpeed |= Speed & 0x0F; + xUSLPciWrite8(Address + CapBaseAddr + PCIE_LINK_CONTROL2_REG, TargetSpeed); + + LinkStatus = xUSLPciRead16(Address + CapBaseAddr + PCIE_LINK_CONTROL_REG); + LinkStatus &= ~BIT_16(4); + xUSLPciWrite16(Address + CapBaseAddr + PCIE_LINK_CONTROL_REG, LinkStatus); + + SilFchStall(50 * 1000); + if (XhciMmio != 0) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " De-assert GPP PERST# before DL ACTIVE\n"); + AssertPin = Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x2E20F); + AssertPin &= ~BIT_8(4); + Prom21XhciWriteByte(XhciMmio, 0x2E20F, AssertPin); + } + + SilFchStall(50 * 1000); + for (Counter = 0; Counter < 100; Counter++) { + LinkStatus = xUSLPciRead16(Address + CapBaseAddr + PCIE_LINK_STATUS_REG); + if (LinkStatus & BIT_16(13)) { + break; + } + SilFchStall(2 * 1000); + } + } else { + if (Speed == 0x4) { + if ((CurrentSpeed & 0xF) < 0x3) { + TargetSpeed = xUSLPciRead8(Address + CapBaseAddr + PCIE_LINK_CONTROL2_REG); + TargetSpeed &= 0xF0; + TargetSpeed |= 0x3 & 0x0F; + xUSLPciWrite8(Address + CapBaseAddr + PCIE_LINK_CONTROL2_REG, TargetSpeed); + + LinkStatus = xUSLPciRead16(Address + CapBaseAddr + PCIE_LINK_CONTROL_REG); + LinkStatus |= BIT_16(5); + xUSLPciWrite16(Address + CapBaseAddr + PCIE_LINK_CONTROL_REG, LinkStatus); + + SilFchStall(20 * 1000); + for (Counter = 0; Counter < 100; Counter++) { + TargetSpeed = xUSLPciRead8(Address + CapBaseAddr + PCIE_LINK_STATUS_REG); + if ((TargetSpeed & 0x0F) == (0x3 & 0x0F)) { + break; + } + SilFchStall(2 * 1000); + } + } + } + + TargetSpeed = xUSLPciRead8(Address + CapBaseAddr + PCIE_LINK_CONTROL2_REG); + TargetSpeed &= 0xF0; + TargetSpeed |= Speed & 0x0F; + xUSLPciWrite8(Address + CapBaseAddr + PCIE_LINK_CONTROL2_REG, TargetSpeed); + + LinkStatus = xUSLPciRead16(Address + CapBaseAddr + PCIE_LINK_CONTROL_REG); + LinkStatus |= BIT_16(5); + xUSLPciWrite16(Address + CapBaseAddr + PCIE_LINK_CONTROL_REG, LinkStatus); + } + + SilFchStall(20 * 1000); + for (Counter = 0; Counter < 100; Counter++) { + TargetSpeed = xUSLPciRead8(Address + CapBaseAddr + PCIE_LINK_STATUS_REG); + if ((TargetSpeed & 0x0F) == (Speed & 0x0F)) { + break; + } + SilFchStall(2 * 1000); + } + + CurrentSpeed = xUSLPciRead8(Address + CapBaseAddr + PCIE_LINK_STATUS_REG); + PROM_TRACEPOINT(SIL_TRACE_INFO, "PCIe Link Width & Link Speed is x%d Gen%d Counter = %d\n", + CurrentSpeed >> 4, CurrentSpeed & 0xF, Counter); + + if ((CurrentSpeed & 0x0F) == (Speed & 0x0F)) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Restore PCIe link speed to Gen%d Success !!!\n", + CurrentSpeed & 0x0F); + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Restore PCIe link speed to Gen%d Fail !!! It's Gen%d now\n", + Speed & 0x0F, CurrentSpeed & 0x0F); + } + + return Status; +} \ No newline at end of file diff --git a/xUSL/PROM/Common/PromAccess.h b/xUSL/PROM/Common/PromAccess.h new file mode 100644 index 0000000..332b750 --- /dev/null +++ b/xUSL/PROM/Common/PromAccess.h @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ + +/** + * @file PromInit.h + * @brief All PROM related defines and structures + */ + +#pragma once + +#include +#include + +typedef struct { + uint32_t GppBus; + uint32_t UspBus; + uint32_t XhciDspBus; + uint32_t SataDspBus; + uint32_t GppMmio; + uint32_t UspMmio; + uint32_t XhciDspMmio; + uint32_t XhciMmio; + uint8_t GppCmd; + uint8_t UspCmd; + uint8_t XhciDspCmd; + uint8_t SataDspCmd; + uint8_t XhciCmd; + uint8_t SataCmd; + uint8_t GppAspm; + uint8_t UspAspm; + uint8_t XhciDspAspm; + uint8_t SataDspAspm; + uint8_t XhciAspm; + uint8_t SataAspm; + uint16_t PromBus; +} PROM_PCI_SAVE_RESTORE_TABLE; + +uint8_t +Prom21XhciReadByteV2 ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint32_t XhciMmio, + uint32_t Address + ); + +uint8_t +Prom21XhciReadByte ( + uint32_t XhciMmio, + uint32_t Address + ); + +uint16_t +Prom21XhciReadWord ( + uint32_t XhciMmio, + uint32_t Address + ); + +uint32_t +Prom21XhciReadDWord ( + uint32_t XhciMmio, + uint32_t Address + ); + +void +Prom21XhciWriteByte ( + uint32_t XhciMmio, + uint32_t Address, + uint8_t Data + ); + +void +Prom21XhciWriteWord ( + uint32_t XhciMmio, + uint32_t Address, + uint16_t Data + ); + +void +Prom21XhciWriteDWord ( + uint32_t XhciMmio, + uint32_t Address, + uint32_t Data + ); + +void +SaveInitPromBus ( + PROMCLASS_DATA_BLK *PromDataBlk, + PROM_PCI_SAVE_RESTORE_TABLE *PtPciTable, + uint16_t CheckBit + ); + +void +RestorePromBus ( + PROMCLASS_DATA_BLK *PromDataBlk, + PROM_PCI_SAVE_RESTORE_TABLE *PtPciTable, + uint16_t CheckBit + ); + +SIL_STATUS +Prom21RetrainSpeed ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint16_t Bus, + uint8_t Dev, + uint8_t Func, + uint32_t XhciMmio, + uint8_t Speed, + bool LinkDisable + ); diff --git a/xUSL/PROM/Common/PromClassDflts.c b/xUSL/PROM/Common/PromClassDflts.c index 86ca934..0404c7d 100644 --- a/xUSL/PROM/Common/PromClassDflts.c +++ b/xUSL/PROM/Common/PromClassDflts.c @@ -10,32 +10,34 @@ #include /// Default values for PROM configuration data -const PROMCLASS_DATA_BLK PromClassDflts = { - .PT21FwInRamAddress = 0x0B000000, - .PT21GpioID = 0x00000000, - .PT21FwVersion = 0x0000000000000000, - .PT21UsbPortLateDisable = 0xf, +const PROMCLASS_INPUT_BLK PromClassDflts = { + .BootMode = 0x0, .PT21TempBusNum = 0x10, - .PT21RootBridgeNum = 0x00, .PT21PcieTargetSpeed = 0x04, - .PT21IoHcBusNum = 0x00, - .PT21IohcBridgeCntl = 0x00000000, .PT21FWLoading = 0x1, .PT21DbgLoadFw = 0x00, .PT21DisableUnusedPciePort = 0xf, .PT21SecondPortNumber = 0xf, - .PT21Revision = 0x2, + .PT21Revision = 0xf, .PT21TogglePerst = 0xf, .PT21RuninRam = 0x0, .PT21ClkPMEnable = 0xf, .PT21L1Enable = 0x1, .PT21L1ssEnable = 0xf, .PT21ReadThermal = 0xf, - .PT21GpioPerstEnable = 0xf, .PT21GpioTestEnable = 0xf, .PT21DelayAfterFWLoading = 0xf, .PT21XhciPmeEn = 0xf, .PT21CorrErrMask = 0x6000, + .PT21FwInRamAddress = 0x00000000, + .PT21ForceGppPcieAddress = 0x0, + .PT21GpioInitTable = { + .GpioCommon.Raw = 0, + .GpioList[0] = { + .Pin = 0xff, + .Setting.Raw = 0, + } + }, .Primary = { .PT21PciePortLaneRev = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }, .PT21SIProgEnable = 0xf, @@ -45,15 +47,15 @@ const PROMCLASS_DATA_BLK PromClassDflts = { .PT21PcieGen1SwingEnable = 0xf, .PT21PcieGen1Swing = { 0x1f, 0x1f, 0x1f, 0x1f, 0xf, 0xf, 0xf, 0xf, 0x1f, 0x1f, 0x1f, 0x1f }, .PT21EqPreset = 0xf, + .PT21GpioPerstEnable = 0xf, + .PT21UsbPortLateDisable = 0xf, .PT21PcieClkreqPinSelect = { 0x8, 0x4, 0x0, 0x2, 0x3, 0xE }, .PT21PcieClkreqMode = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x2 }, .PT21PciePortTargetSpeed = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }, .PT21PciePortEnable = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }, .PT21Usb3GenSelect = 0xf, .PT21XhciPortGen = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }, - .PT21L4Usb3Port = { 0xf, 0xf, 0xf, 0xf }, - .PT21L4Usb2Port = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }, - .PT21Usb3ort = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }, + .PT21Usb3Port = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }, .PT21Usb2Port = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }, .PT21SataPhy[0] = { .PT21SataPortGen1Swing = 0x3, @@ -106,11 +108,11 @@ const PROMCLASS_DATA_BLK PromClassDflts = { .PT21USB3PortGen2Cp14EmpLevel = 0x3, .PT21USB3PortGen2Cp14PreshootEn = 0x0, .PT21USB3PortGen2Cp14Preshoot = 0x0, - .PT21USB3PortGen2Cp15EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp15EmpLevelEn = 0x1, .PT21USB3PortGen2Cp15EmpLevel = 0x3, - .PT21USB3PortGen2Cp15PreshootEn = 0x0, + .PT21USB3PortGen2Cp15PreshootEn = 0x1, .PT21USB3PortGen2Cp15Preshoot = 0x0, - .PT21USB3PortGen2Cp16EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp16EmpLevelEn = 0x0, .PT21USB3PortGen2Cp16EmpLevel = 0x3, .PT21USB3PortGen2Cp16PreshootEn = 0x0, .PT21USB3PortGen2Cp16Preshoot = 0x0, @@ -134,11 +136,11 @@ const PROMCLASS_DATA_BLK PromClassDflts = { .PT21USB3PortGen2Cp14EmpLevel = 0x3, .PT21USB3PortGen2Cp14PreshootEn = 0x0, .PT21USB3PortGen2Cp14Preshoot = 0x0, - .PT21USB3PortGen2Cp15EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp15EmpLevelEn = 0x1, .PT21USB3PortGen2Cp15EmpLevel = 0x3, - .PT21USB3PortGen2Cp15PreshootEn = 0x0, + .PT21USB3PortGen2Cp15PreshootEn = 0x1, .PT21USB3PortGen2Cp15Preshoot = 0x0, - .PT21USB3PortGen2Cp16EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp16EmpLevelEn = 0x0, .PT21USB3PortGen2Cp16EmpLevel = 0x3, .PT21USB3PortGen2Cp16PreshootEn = 0x0, .PT21USB3PortGen2Cp16Preshoot = 0x0, @@ -162,11 +164,11 @@ const PROMCLASS_DATA_BLK PromClassDflts = { .PT21USB3PortGen2Cp14EmpLevel = 0x3, .PT21USB3PortGen2Cp14PreshootEn = 0x0, .PT21USB3PortGen2Cp14Preshoot = 0x0, - .PT21USB3PortGen2Cp15EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp15EmpLevelEn = 0x1, .PT21USB3PortGen2Cp15EmpLevel = 0x3, - .PT21USB3PortGen2Cp15PreshootEn = 0x0, + .PT21USB3PortGen2Cp15PreshootEn = 0x1, .PT21USB3PortGen2Cp15Preshoot = 0x0, - .PT21USB3PortGen2Cp16EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp16EmpLevelEn = 0x0, .PT21USB3PortGen2Cp16EmpLevel = 0x3, .PT21USB3PortGen2Cp16PreshootEn = 0x0, .PT21USB3PortGen2Cp16Preshoot = 0x0, @@ -190,11 +192,11 @@ const PROMCLASS_DATA_BLK PromClassDflts = { .PT21USB3PortGen2Cp14EmpLevel = 0x3, .PT21USB3PortGen2Cp14PreshootEn = 0x0, .PT21USB3PortGen2Cp14Preshoot = 0x0, - .PT21USB3PortGen2Cp15EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp15EmpLevelEn = 0x1, .PT21USB3PortGen2Cp15EmpLevel = 0x3, - .PT21USB3PortGen2Cp15PreshootEn = 0x0, + .PT21USB3PortGen2Cp15PreshootEn = 0x1, .PT21USB3PortGen2Cp15Preshoot = 0x0, - .PT21USB3PortGen2Cp16EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp16EmpLevelEn = 0x0, .PT21USB3PortGen2Cp16EmpLevel = 0x3, .PT21USB3PortGen2Cp16PreshootEn = 0x0, .PT21USB3PortGen2Cp16Preshoot = 0x0, @@ -218,11 +220,11 @@ const PROMCLASS_DATA_BLK PromClassDflts = { .PT21USB3PortGen2Cp14EmpLevel = 0x3, .PT21USB3PortGen2Cp14PreshootEn = 0x0, .PT21USB3PortGen2Cp14Preshoot = 0x0, - .PT21USB3PortGen2Cp15EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp15EmpLevelEn = 0x1, .PT21USB3PortGen2Cp15EmpLevel = 0x3, - .PT21USB3PortGen2Cp15PreshootEn = 0x0, + .PT21USB3PortGen2Cp15PreshootEn = 0x1, .PT21USB3PortGen2Cp15Preshoot = 0x0, - .PT21USB3PortGen2Cp16EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp16EmpLevelEn = 0x0, .PT21USB3PortGen2Cp16EmpLevel = 0x3, .PT21USB3PortGen2Cp16PreshootEn = 0x0, .PT21USB3PortGen2Cp16Preshoot = 0x0, @@ -246,45 +248,46 @@ const PROMCLASS_DATA_BLK PromClassDflts = { .PT21USB3PortGen2Cp14EmpLevel = 0x3, .PT21USB3PortGen2Cp14PreshootEn = 0x0, .PT21USB3PortGen2Cp14Preshoot = 0x0, - .PT21USB3PortGen2Cp15EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp15EmpLevelEn = 0x1, .PT21USB3PortGen2Cp15EmpLevel = 0x3, - .PT21USB3PortGen2Cp15PreshootEn = 0x0, + .PT21USB3PortGen2Cp15PreshootEn = 0x1, .PT21USB3PortGen2Cp15Preshoot = 0x0, - .PT21USB3PortGen2Cp16EmpLevelEn = 0x3, + .PT21USB3PortGen2Cp16EmpLevelEn = 0x0, .PT21USB3PortGen2Cp16EmpLevel = 0x3, .PT21USB3PortGen2Cp16PreshootEn = 0x0, .PT21USB3PortGen2Cp16Preshoot = 0x0, }, .PT21USB2Phy[0] = { - .PT21USB2P0SlewRate = 0x2, - .PT21USB2P0DrivingCurrent = 0x0, - .PT21USB2P0Termination = 0x3, + .PT21USB2SlewRate = 0x2, + .PT21USB2DrivingCurrent = 0x0, + .PT21USB2Termination = 0x3, }, .PT21USB2Phy[1] = { - .PT21USB2P0SlewRate = 0x2, - .PT21USB2P0DrivingCurrent = 0x0, - .PT21USB2P0Termination = 0x3, + .PT21USB2SlewRate = 0x2, + .PT21USB2DrivingCurrent = 0x0, + .PT21USB2Termination = 0x3, }, .PT21USB2Phy[2] = { - .PT21USB2P0SlewRate = 0x2, - .PT21USB2P0DrivingCurrent = 0x0, - .PT21USB2P0Termination = 0x3, + .PT21USB2SlewRate = 0x2, + .PT21USB2DrivingCurrent = 0x0, + .PT21USB2Termination = 0x3, }, .PT21USB2Phy[3] = { - .PT21USB2P0SlewRate = 0x2, - .PT21USB2P0DrivingCurrent = 0x0, - .PT21USB2P0Termination = 0x3, + .PT21USB2SlewRate = 0x2, + .PT21USB2DrivingCurrent = 0x0, + .PT21USB2Termination = 0x3, }, .PT21USB2Phy[4] = { - .PT21USB2P0SlewRate = 0x2, - .PT21USB2P0DrivingCurrent = 0x0, - .PT21USB2P0Termination = 0x3, + .PT21USB2SlewRate = 0x2, + .PT21USB2DrivingCurrent = 0x0, + .PT21USB2Termination = 0x3, }, .PT21USB2Phy[5] = { - .PT21USB2P0SlewRate = 0x2, - .PT21USB2P0DrivingCurrent = 0x0, - .PT21USB2P0Termination = 0x3, + .PT21USB2SlewRate = 0x2, + .PT21USB2DrivingCurrent = 0x0, + .PT21USB2Termination = 0x3, }, + .PT21SataEnable = 0xf, .PT21SataMode = 0x00, .PT21SataAggressiveDevSlp = { 0xf, 0xf, 0xf, 0xf }, .PT21SataAggrLinkPmCap = 0xf, @@ -300,12 +303,6 @@ const PROMCLASS_DATA_BLK PromClassDflts = { .PT21HW_LPM = 0xf, .PT21DbC = 0xf, .PT21XHC_PME = 0xf, - .PT21Lock = 0x01, - .PT21XhciLock = 0x00, - .PT21XhciID = 0x00000000, - .PT21GppPcieAddress = 0x00000000, - .PT21XhciMmio = 0x00000000, - .PT21GpioMmio = 0x00000000, .PT21PcieDspSsid = 0x33281B21, .PT21PcieDspXhciSsid = 0x33281B21, .PT21PcieDspAhciSsid = 0x33281B21, diff --git a/xUSL/PROM/Common/PromInit.c b/xUSL/PROM/Common/PromInit.c index 94073a2..a0402fb 100644 --- a/xUSL/PROM/Common/PromInit.c +++ b/xUSL/PROM/Common/PromInit.c @@ -94,7 +94,7 @@ SIL_STATUS PromClassSetInputBlock ( PROMCLASS_DATA_BLK *PromConfigData; PromConfigData = (PROMCLASS_DATA_BLK *)SilCreateInfoBlock(SilContext, - SilId_CxlClass, + SilId_PromClass, sizeof (PROMCLASS_DATA_BLK), PROMCLASS_INSTANCE, PROMCLASS_MAJOR_REV, @@ -104,9 +104,13 @@ SIL_STATUS PromClassSetInputBlock ( if (PromConfigData == NULL) { return SilAborted; } + // fill PROM IP data structure with defaults - memcpy(PromConfigData, &PromClassDflts, sizeof (PROMCLASS_DATA_BLK)); - memcpy(&PromConfigData->Secondary, &PromClassDflts.Primary, sizeof (PROM21_DATA_BLK)); + memcpy(&PromConfigData->PromInputBlk, &PromClassDflts, sizeof(PROMCLASS_INPUT_BLK)); + memcpy(&PromConfigData->PromInputBlk.Secondary, + &PromClassDflts.PromInputBlk.Primary, + sizeof(PROM21_DATA_BLK)); + memset(&PromConfigData->PromOutputBlk, 0, sizeof(PROMCLASS_OUTPUT_BLK)); return SilPass; } diff --git a/xUSL/PROM/Common/meson.build b/xUSL/PROM/Common/meson.build index 805d547..891c841 100644 --- a/xUSL/PROM/Common/meson.build +++ b/xUSL/PROM/Common/meson.build @@ -1,7 +1,4 @@ # SPDX-License-Identifier: MIT # Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. - - -xusl += files([ 'PromClassDflts.c', 'PromInit.c' ]) - +xusl += files([ 'PromAccess.c', 'PromClassDflts.c', 'PromInit.c' ]) diff --git a/xUSL/PROM/PROM21/Prom21.c b/xUSL/PROM/PROM21/Prom21.c new file mode 100644 index 0000000..a2fad53 --- /dev/null +++ b/xUSL/PROM/PROM21/Prom21.c @@ -0,0 +1,513 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright(C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ + +/** + * @file Prom21.c + * @brief Promontory21 related functions + */ + +#include +#include +#include +#include +#include +#include "Prom21.h" + +static void +Prom21SvidSsid ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciMmio + ) +{ + uint16_t Value; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X\n", XhciMmio); + + Prom21XhciWriteByte(XhciMmio, 0x24788, 0x86); + + if (PromDataBlk->PT21XhciSsid != 0x11421B21) { + Value = (uint16_t)PromDataBlk->PT21XhciSsid; + PROM_TRACEPOINT(SIL_TRACE_INFO, "XhciSvid = 0x%08X\n", Value); + Prom21XhciWriteWord(XhciMmio, 0x2475A, Value); + + Value = (uint16_t)(PromDataBlk->PT21XhciSsid >> 16); + PROM_TRACEPOINT(SIL_TRACE_INFO, "XhciSsid = 0x%08X\n", Value); + Prom21XhciWriteWord(XhciMmio, 0x2474A, Value); + } + + if (PromDataBlk->PT21AhciSsid != 0x10621B21) { + Value = (uint16_t)PromDataBlk->PT21AhciSsid; + PROM_TRACEPOINT(SIL_TRACE_INFO, "AhciSvid = 0x%08X\n", Value); + Prom21XhciWriteWord(XhciMmio, 0x2475C, Value); + + Value = (uint16_t)(PromDataBlk->PT21AhciSsid >> 16); + PROM_TRACEPOINT(SIL_TRACE_INFO, "AhciSsid = 0x%08X\n", Value); + Prom21XhciWriteWord(XhciMmio, 0x2474C, Value); + } + + if (PromDataBlk->PT21PcieUspSsid != 0x33281B21) { + Value = (uint16_t)PromDataBlk->PT21PcieUspSsid; + PROM_TRACEPOINT(SIL_TRACE_INFO, "PcieUspSvid = 0x%08X\n", Value); + Prom21XhciWriteWord(XhciMmio, 0x24750, Value); + + Value = (uint16_t)(PromDataBlk->PT21PcieUspSsid >> 16); + PROM_TRACEPOINT(SIL_TRACE_INFO, "PcieUspSsid = 0x%08X\n", Value); + Prom21XhciWriteWord(XhciMmio, 0x24740, Value); + } + + if (PromDataBlk->PT21PcieDspSsid != 0x33281B21) { + Value = (uint16_t)PromDataBlk->PT21PcieDspSsid; + PROM_TRACEPOINT(SIL_TRACE_INFO, "PcieDspSvid = 0x%08X\n", Value); + Prom21XhciWriteWord(XhciMmio, 0x24752, Value); + + Value = (uint16_t)(PromDataBlk->PT21PcieDspSsid >> 16); + PROM_TRACEPOINT(SIL_TRACE_INFO, "PcieDspSsid = 0x%08X\n", Value); + Prom21XhciWriteWord(XhciMmio, 0x24742, Value); + } + + if (PromDataBlk->PT21PcieDspXhciSsid != 0x33281B21) { + Value = (uint16_t)PromDataBlk->PT21PcieDspXhciSsid; + PROM_TRACEPOINT(SIL_TRACE_INFO, "PcieDspXhciSvid = 0x%08X\n", Value); + Prom21XhciWriteWord(XhciMmio, 0x24756, Value); + + Value = (uint16_t)(PromDataBlk->PT21PcieDspXhciSsid >> 16); + PROM_TRACEPOINT(SIL_TRACE_INFO, "PcieDspXhciSsid = 0x%08X\n", Value); + Prom21XhciWriteWord(XhciMmio, 0x24746, Value); + } + + if (PromDataBlk->PT21PcieDspAhciSsid != 0x33281B21) { + Value = (uint16_t)PromDataBlk->PT21PcieDspAhciSsid; + PROM_TRACEPOINT(SIL_TRACE_INFO, "PcieDspAhciSvid = 0x%08X\n", Value); + Prom21XhciWriteWord(XhciMmio, 0x24758, Value); + + Value = (uint16_t)(PromDataBlk->PT21PcieDspAhciSsid >> 16); + PROM_TRACEPOINT(SIL_TRACE_INFO, "PcieDspAhciSsid = 0x%08X\n", Value); + Prom21XhciWriteWord(XhciMmio, 0x24748, Value); + } + + Prom21XhciWriteByte(XhciMmio, 0x24788, 0x0); + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + +static void +Prom21ThermalSetting ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciMmio + ) +{ + uint8_t RegMisc; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X\n", XhciMmio); + + if (PromDataBlk->PT21ThermalThrottle != 0xf) { + if (PromDataBlk->PT21ThermalThrottle == 1) { + Prom21XhciWriteDWord(XhciMmio, 0x1C520, 0x12345678); + Prom21XhciWriteByte(XhciMmio, 0x1E521, PromDataBlk->PT21ThermalThreshold); + RegMisc = Prom21XhciReadByte(XhciMmio, 0x1C51F); + Prom21XhciWriteByte(XhciMmio, 0x1C51F, RegMisc | BIT_8(1)); + } else { + Prom21XhciWriteDWord(XhciMmio, 0x1C520, 0x12345678); + RegMisc = Prom21XhciReadByte(XhciMmio, 0x1C51F); + Prom21XhciWriteByte(XhciMmio, 0x1C51F, RegMisc & ~BIT_8(1)); + } + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + +static void +Prom21Gen1Swing ( + uint32_t XhciMmio, + uint8_t PortNum, + uint8_t Value + ) +{ + uint32_t Address; + uint8_t Data8; + + Address = 0x2C001 + (PortNum << 8); + Data8 = Prom21XhciReadByte(XhciMmio, Address); + + switch(PortNum) + { + case 0: + case 1: + case 2: + case 3: + case 8: + case 9: + case 10: + case 11: + Data8 &= 0xE0; + break; + case 4: + case 5: + case 6: + case 7: + Data8 &= 0xF0; + break; + default: + break; + } + Data8 |= Value; + + Prom21XhciWriteByte(XhciMmio, Address, Value); +} + +static void +Prom21PcieSIConfig ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciMmio +) +{ + uint8_t *PcieGen1Ptr; + uint8_t Data8; + uint8_t i; + + PcieGen1Ptr = PromDataBlk->PT21PcieGen1Swing; + if (PcieGen1Ptr == NULL) { + return; + } + + for(i = 0; i < PROM21_NUM_PCIE_LANES; i++) { + PROM_TRACEPOINT(SIL_TRACE_INFO, "[Prom21] Port %d: Gen1Swing Value = %x\n", i, *PcieGen1Ptr); + Prom21Gen1Swing(XhciMmio, i, *PcieGen1Ptr); + PcieGen1Ptr++; + } + + Data8 = Prom21XhciReadByte(XhciMmio, 0x1C51F); + Data8 |= BIT_8(2); + Prom21XhciWriteByte(XhciMmio, 0x1C51F, Data8); + +} + +static void +Prom21DSPortSetting ( + uint32_t XhciMmio, + bool Enable, + uint32_t PortNum +) +{ + uint32_t Address; + uint16_t Data16; + + if (PortNum > PROM21_MAX_DSP_NUMBER) { + return; + } + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X\n", XhciMmio); + + Prom21XhciWriteByte(XhciMmio, 0x24788, 0x86); + + Address = 0x24734; + Data16 = Prom21XhciReadWord(XhciMmio, Address); + + if (Enable) { + Data16 |= BIT_16(PortNum); + } else { + Data16 &= ~BIT_16(PortNum); + } + + Prom21XhciWriteWord(XhciMmio, Address, Data16); + Prom21XhciWriteByte(XhciMmio, 0x24788, 0x0); + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + +static void +Prom21PcieTargetSpeedConfig ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint16_t UspBus, + uint8_t PortNum, + uint8_t TargetSpeed + ) +{ + uint16_t DspBus; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + if (xUSLPciRead32(PCI_LIB_ADDRESS(UspBus, 0, 0, 0)) == PT21_USP_ID) { + DspBus = (uint16_t)xUSLPciRead8(PCI_LIB_ADDRESS(UspBus, 0, 0, 0x19)) | (UspBus & 0xFF00); + if (DspBus != 0){ + Prom21RetrainSpeed(PromDataBlk, DspBus, PortNum, 0, 0, TargetSpeed, false); + } + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + +static void +Prom21DspStatusCheck ( + uint32_t XhciMmio, + uint32_t PortNum + ) +{ + uint32_t Address; + uint16_t Data16; + + if (PortNum > PROM21_MAX_DSP_NUMBER) { + return; + } + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X\n", XhciMmio); + + Prom21XhciWriteByte(XhciMmio, 0x24788, 0x86); + + Address = 0x24734; + Data16 = Prom21XhciReadWord(XhciMmio, Address); + + Prom21XhciWriteByte(XhciMmio, 0x24788, 0x0); + + if (Data16 & ((uint16_t)(1 << PortNum))) { + PROM_TRACEPOINT(SIL_TRACE_INFO, "Port %d is default value\n", PortNum); + } else { + Prom21DSPortSetting(XhciMmio, 1, PortNum); + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + +static void +Prom21PcieConfig ( + PROMCLASS_DATA_BLK *PromClassBlk, + PROM21_DATA_BLK *PromDataBlk, + uint16_t UspBus, + uint32_t XhciMmio + ) +{ + uint8_t PortNum; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "UspBus=%x XhciMmio=0x%08x\n", UspBus , XhciMmio); + + for (PortNum = 0; PortNum < PROM21_NUM_PCIE_LANES; PortNum++) { + if (PromDataBlk->PT21PciePortEnable[PortNum] != 0xf) { + if (PromDataBlk->PT21PciePortEnable[PortNum] == 1) { + Prom21DSPortSetting(XhciMmio, 1, PortNum); + if (PromDataBlk->PT21PciePortTargetSpeed[PortNum] != 0xf) { + Prom21PcieTargetSpeedConfig(PromClassBlk, + UspBus, + 0, + PromDataBlk->PT21PciePortTargetSpeed[PortNum] + ); + } + } else { + Prom21DSPortSetting(XhciMmio, 0, PortNum); + } + } else { + Prom21DspStatusCheck(XhciMmio, PortNum); + } + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + +static void +Prom21DisableUnusedPciePorts ( + uint32_t GppPcieAddress, + uint32_t XhciMmio + ) +{ + uint32_t VidDid; + uint8_t DevNum; + uint8_t SlotStatus; + uint8_t HotPlugCapable; + uint16_t GppBus; + uint8_t GppDev; + uint8_t GppFun; + uint16_t PtUspBus; + uint16_t PtDspBus; + uint8_t CapBase; + uint32_t UspDev; + uint32_t DspDev; + + GppBus = (uint16_t)((GppPcieAddress >> 20) & 0xFFF); + GppDev = (uint8_t)((GppPcieAddress >> 15) & 0x1F); + GppFun = (uint8_t)((GppPcieAddress >> 12) & 0x07); + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "[%04X:%02X:%02X]\n", GppBus, GppDev, GppFun); + + PtUspBus = (uint16_t) xUSLPciRead8(GppPcieAddress + 0x19) | (GppBus & 0xFF00); + UspDev = PCI_LIB_ADDRESS(PtUspBus, 0, 0, 0x00); + VidDid = xUSLPciRead32(UspDev); + PROM_TRACEPOINT(SIL_TRACE_INFO, "PtUspBus %x, VidDid %x\n", PtUspBus, VidDid); + + if (VidDid == PT21_USP_ID) { + PtDspBus = (uint16_t) xUSLPciRead8(UspDev + 0x19) | (PtUspBus & 0xFF00); + for (DevNum = 0; DevNum <= PROM21_MAX_DSP_NUMBER; DevNum ++) { + DspDev = PCI_LIB_ADDRESS(PtDspBus, DevNum, 0, 0x00); + VidDid = xUSLPciRead32(DspDev); + PROM_TRACEPOINT(SIL_TRACE_INFO, "PtDspBus %x, VidDid %x\n", PtDspBus, VidDid); + if (VidDid == PT21_DSP_ID) { + CapBase = xUSLPciLibFindPciCapability(DspDev, PCIE_CAP_ID); + if ((CapBase == 0) || (CapBase == 0xff)) { + continue; + } + + SlotStatus = xUSLPciRead8(DspDev + CapBase + PCIE_SLOT_STATUS_REG); + HotPlugCapable = xUSLPciRead8(DspDev +CapBase + PCIE_LINK_STATUS_REG + 2); + PROM_TRACEPOINT(SIL_TRACE_INFO, "SlotStatus %x, HotPlugCapable %x at Dev 0x%x\n", + SlotStatus, HotPlugCapable, DevNum); + + if (((SlotStatus & BIT_8(6)) != BIT_8(6)) && + ((HotPlugCapable & BIT_8(6)) != BIT_8(6))) { + Prom21DSPortSetting(XhciMmio, 0, DevNum); + } + } else { + Prom21DSPortSetting(XhciMmio, 0, DevNum); + } + } + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + +SIL_STATUS +Prom21Setting ( + SIL_CONTEXT *SilContext, + PROMCLASS_DATA_BLK *PromDataBlk + ) +{ + uint32_t XhciMmio; + uint32_t SecXhciMmio; + uint8_t Data8; + PROM_PCI_SAVE_RESTORE_TABLE PtPciTable[2]; + uint32_t SecGppPcieAddress; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + if (PromDataBlk->PromOutputBlk.PT21XhciID[0] == 0) { + PROM_TRACEPOINT(SIL_TRACE_ERROR, "Promontory is NOT FOUND!!\n"); + return SilNotFound; + } + + if (PromDataBlk->PromInputBlk.BootMode == 0x20) { + PROM_TRACEPOINT(SIL_TRACE_INFO, "Boot in Recovery mode!!\n"); + return SilPass;; + } + + XhciMmio = PromDataBlk->PromOutputBlk.PT21XhciMmio[0]; + SecGppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[1]; + SecXhciMmio = 0; + + if (SecGppPcieAddress) { + SaveInitPromBus(PromDataBlk, PtPciTable, 0x3B3B); + SecXhciMmio = PromDataBlk->PromOutputBlk.PT21XhciMmio[1]; + } else { + SaveInitPromBus(PromDataBlk, PtPciTable, 0x3B); + } + + //if (PromDataBlk->PromInputBlk.BootMode == 0x11 /* BOOT_ON_S3_RESUME */) + { + PROM_TRACEPOINT(SIL_TRACE_INFO, " BootMode == BOOT_ON_S3_RESUME\n"); + if (PromDataBlk->PromOutputBlk.PT21XhciLock[0]) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Lock PT for S3 Resume !!!\n"); + Data8 = Prom21XhciReadByte(XhciMmio, 0x15087); + Prom21XhciWriteByte(XhciMmio, 0x15087, Data8 & ~BIT_8(4)); + } + if (PromDataBlk->PromOutputBlk.PT21XhciLock[1]) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Lock Secondary PT for S3 Resume !!!\n"); + Data8 = Prom21XhciReadByte(SecXhciMmio, 0x15087); + Prom21XhciWriteByte(SecXhciMmio, 0x15087, Data8 & ~BIT_8(4)); + } + } + + Prom21UsbSetting(&PromDataBlk->PromInputBlk.Primary, + XhciMmio, + PromDataBlk->PromInputBlk.BootMode); + Prom21PcieConfig(PromDataBlk, + &PromDataBlk->PromInputBlk.Primary, + PtPciTable[0].PromBus, + XhciMmio + ); + + if (PromDataBlk->PromInputBlk.Primary.PT21PcieGen1SwingEnable == 1) { + Prom21PcieSIConfig(&PromDataBlk->PromInputBlk.Primary, XhciMmio); + } + + if (PromDataBlk->PromInputBlk.Primary.PT21SsidOverride == 1) { + Prom21SvidSsid(&PromDataBlk->PromInputBlk.Primary, XhciMmio); + } + + Prom21SataSetting(PromDataBlk); + Prom21ThermalSetting(&PromDataBlk->PromInputBlk.Primary, XhciMmio); + + if (SecXhciMmio != 0) { + Prom21UsbSetting(&PromDataBlk->PromInputBlk.Secondary, + SecXhciMmio, + PromDataBlk->PromInputBlk.BootMode); + Prom21PcieConfig(PromDataBlk, + &PromDataBlk->PromInputBlk.Secondary, + PtPciTable[1].PromBus, + SecXhciMmio + ); + + if (PromDataBlk->PromInputBlk.Secondary.PT21PcieGen1SwingEnable == 1) { + Prom21PcieSIConfig(&PromDataBlk->PromInputBlk.Secondary, SecXhciMmio); + } + + if (PromDataBlk->PromInputBlk.Secondary.PT21SsidOverride == 1) { + Prom21SvidSsid(&PromDataBlk->PromInputBlk.Secondary, SecXhciMmio); + } + + Prom21ThermalSetting(&PromDataBlk->PromInputBlk.Secondary, SecXhciMmio); + } + + if (SecGppPcieAddress) { + RestorePromBus(PromDataBlk, PtPciTable, 0x3B3B); + } else { + RestorePromBus(PromDataBlk, PtPciTable, 0x3B); + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); + return SilPass; +} + +SIL_STATUS +Prom21LateSetting ( + SIL_CONTEXT *SilContext, + PROMCLASS_DATA_BLK *PromDataBlk + ) +{ + PROM_PCI_SAVE_RESTORE_TABLE PtPciTable[2]; + uint32_t XhciMmio; + uint32_t SecXhciMmio; + uint32_t GppPcieAddress; + uint32_t SecGppPcieAddress; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + XhciMmio = PromDataBlk->PromOutputBlk.PT21XhciMmio[0]; + GppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[0]; + SecGppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[1]; + SecXhciMmio = 0; + + PROM_TRACEPOINT(SIL_TRACE_INFO, "XhciMmio = %x, GppPcieAddress = %x, SecGppPcieAddress = %x\n", + XhciMmio, GppPcieAddress, SecGppPcieAddress); + + if (PromDataBlk->PromInputBlk.PT21DisableUnusedPciePort != 0xf) { + if (PromDataBlk->PromInputBlk.PT21DisableUnusedPciePort == 1) { + if (SecGppPcieAddress) { + SaveInitPromBus(PromDataBlk, PtPciTable, 0x3B3B); + SecXhciMmio = PromDataBlk->PromOutputBlk.PT21XhciMmio[1]; + } else { + SaveInitPromBus(PromDataBlk, PtPciTable, 0x3B); + } + + if (GppPcieAddress) { + Prom21DisableUnusedPciePorts(GppPcieAddress, XhciMmio); + } + if (SecGppPcieAddress) { + Prom21DisableUnusedPciePorts(SecGppPcieAddress, SecXhciMmio); + } + + if (SecGppPcieAddress) { + RestorePromBus(PromDataBlk, PtPciTable, 0x3B3B); + } else { + RestorePromBus(PromDataBlk, PtPciTable, 0x3B); + } + } + } + + return SilPass; +} diff --git a/xUSL/PROM/PROM21/Prom21.h b/xUSL/PROM/PROM21/Prom21.h new file mode 100644 index 0000000..90cf344 --- /dev/null +++ b/xUSL/PROM/PROM21/Prom21.h @@ -0,0 +1,374 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ + +/** + * @file Prom21.h + * @brief Promontory21 related defines + */ + +#pragma once + +#include +#include + +#define PT_SATA_AHCI_DID 0x43F6 +#define PT_SATA_RAID_DID 0x43BD + +#define PT_SATA_AHCI_CLASS_CODE 0x010601 +#define PT_SATA_RAID_CLASS_CODE 0x010400 + +#define PROM21_MIN_SATA_SPEED 1 +#define PROM21_MAX_SATA_SPEED 3 + +#define PROM21_MAX_DSP_NUMBER 13 +#define PROM21_MAX_LANE_REVERSAL_DSP_NUMBER 11 + +#define PROM21_XHCI_DSP_DEV 12 +#define PROM21_SATA_DSP_DEV 13 + +#define PT21_SATA_ID 0x43F61022 + +#define PT21_XHCI_ID_L1 0x43F71022 +#define PT21_XHCI_ID_L2 0x43F81022 +#define PT21_XHCI_ID_L3 0x43F91022 +#define PT21_XHCI_ID_L4 0x43FA1022 +#define PT21_XHCI_ID_L5 0x43FB1022 +#define PT21_XHCI_ID_L6 0x43FC1022 +#define PT21_XHCI_ID_L7 0x43FD1022 +#define PT21_XHCI_ID_L8 0x43FE1022 + +#define PT21_XHCI_DID_L1 0x43F7 +#define PT21_XHCI_DID_L2 0x43F8 +#define PT21_XHCI_DID_L3 0x43F9 +#define PT21_XHCI_DID_L4 0x43FA +#define PT21_XHCI_DID_L5 0x43FB +#define PT21_XHCI_DID_L6 0x43FC +#define PT21_XHCI_DID_L7 0x43FD +#define PT21_XHCI_DID_L8 0x43FE + +#define PT21_USP_ID 0x43F41022 +#define PT21_DSP_ID 0x43F51022 + +#define PORM21_LANE_REVERSAL_REG(a) (0x28003L + (a * 0x400)) + +typedef union { + struct { + uint8_t SubVersion[3]; + uint8_t Day; + uint8_t Month; + uint8_t Year; + uint8_t unused[2]; + } Fields; + uint64_t Raw; +} PROM21_FW_VERSION; + +static const uint32_t r_warm_rst_assert[] = { + 0x19220, + 0x1A220, + 0x1B220, + 0x1C220, + 0x1D220, + 0x1E220 +}; + +static const uint32_t r_force_superspeed[] = { + 0x19211, + 0x1A211, + 0x1B211, + 0x1C211, + 0x1D211, + 0x1E211 +}; + +static const uint32_t hw_lpm_en[] = { + 0x1A58C, + 0x1C58C, + 0x1E58C +}; + +static const uint32_t SATA_gen1gen2_swing[] = { + 0x2D188, + 0x2D388, + 0x2D588, + 0x2D788 +}; + +static const uint32_t SATA_gen3_swing[] = { + 0x2D189, + 0x2D389, + 0x2D589, + 0x2D789 +}; + +static const uint32_t SATA_gen1_emphasis[] = { + 0x2D18B, + 0x2D38B, + 0x2D58B, + 0x2D78B +}; + +static const uint32_t SATA_gen2_emphasis[] = { + 0x2D18C, + 0x2D38C, + 0x2D58C, + 0x2D78C +}; + +static const uint32_t SATA_gen3_emphasis[] = { + 0x2D18D, + 0x2D38D, + 0x2D58D, + 0x2D78D +}; + +static const uint32_t SATA_gen_reg[] = { + 0x2D12BL, + 0x2D32BL, + 0x2D52BL, + 0x2D72BL +}; + +static const uint32_t USB3_gen1_swing[] = { + 0x19490, + 0x1A490, + 0x1B490, + 0x1C490, + 0x1D490, + 0x1E490 +}; + +typedef enum { + TxEmphasis = 0, + TxPreshoot, + TxSquelch +} USB3_TX; + +static const uint32_t USB3_gen1_emphasis_preshoot[] = { + 0x19250, + 0x1A250, + 0x1B250, + 0x1C250, + 0x1D250, + 0x1E250 +}; + +static const uint32_t USB3_gen1_squelch[] = { + 0x19480 +}; + +static const uint32_t USB3_gen2_swing[] = { + 0x194A0, + 0x1A4A0, + 0x1B4A0, + 0x1C4A0, + 0x1D4A0, + 0x1E4A0 +}; + +typedef enum { + Usb3_Cp0_Cp9 = 0, + Usb3_Cp13 = 13, + Usb3_Cp14, + Usb3_Cp15, + Usb3_Cp16 +} USB3_COMPLIANCE_PATTERN; + +static const uint32_t USB3_gen2_cp0_cp9_emphasis_preshoot[] = { + 0x19252, + 0x1A252, + 0x1B252, + 0x1C252, + 0x1D252, + 0x1E252 +}; + +static const uint32_t USB3_gen2_cp13_emphasis_preshoot[] = { + 0x1925C, + 0x1A25C, + 0x1B25C, + 0x1C25C, + 0x1D25C, + 0x1E25C +}; + +static const uint32_t USB3_gen2_cp14_emphasis_preshoot[] = { + 0x1925E, + 0x1A25E, + 0x1B25E, + 0x1C25E, + 0x1D25E, + 0x1E25E +}; + +static const uint32_t USB3_gen2_cp15_emphasis_preshoot[] = { + 0x19260, + 0x1A260, + 0x1B260, + 0x1C260, + 0x1D260, + 0x1E260 +}; + +static const uint32_t USB3_gen2_cp16_emphasis_preshoot[] = { + 0x19262, + 0x1A262, + 0x1B262, + 0x1C262, + 0x1D262, + 0x1E262 +}; + +static const uint32_t USB2_tx_reg[] = { + 0x1A598, + 0x1A599, + 0x1A598, + 0x1A59A, + 0x1C598, + 0x1C599, + 0x1C598, + 0x1C59A, + 0x1E598, + 0x1E599, + 0x1E598, + 0x1E59A +}; + +typedef enum { + SlewRate = 0, + DrivingCurrent, + Termination +} USB2_TX; + +typedef enum { + PTSataAhci = 0, + PTSataRaid +} SATA_CLASS; + +typedef enum { + Usb3Port0 = 0, + Usb3Port1, + Usb3Port2, + Usb3Port3, + Usb3Port4, + Usb3Port5, + Usb2Port0, + Usb2Port1, + Usb2Port2, + Usb2Port3, + Usb2Port4, + Usb2Port5, + Usb2Port6, + Usb2Port7, + Usb2Port8, + Usb2Port9, + Usb2Port10, + Usb2Port11 +} USB_PORTS; + +static const uint8_t USBGen2by2_port_mapping[] = { + BIT_8(1), BIT_8(2), BIT_8(3), BIT_8(4), BIT_8(5), BIT_8(6), + BIT_8(0), BIT_8(2), BIT_8(3), BIT_8(4), BIT_8(5), BIT_8(6), BIT_8(7), + BIT_8(0), BIT_8(1), BIT_8(2), + BIT_8(1), + BIT_8(3) +}; + +static const uint8_t USBGen2by1_port_mapping[] = { + BIT_8(1), BIT_8(2), BIT_8(3), BIT_8(4), BIT_8(5), BIT_8(6), + BIT_8(0), BIT_8(1), BIT_8(2), BIT_8(3), BIT_8(4), BIT_8(5), BIT_8(6), BIT_8(7), + BIT_8(0), BIT_8(1), BIT_8(2), BIT_8(3) +}; + +static const uint8_t USBL4_port_mapping[] = { + BIT_8(1), BIT_8(2), BIT_8(3), BIT_8(4), BIT_8(5), BIT_8(6), + BIT_8(0), BIT_8(1), BIT_8(2), BIT_8(3), BIT_8(6), BIT_8(7), + BIT_8(0), BIT_8(1), BIT_8(2), BIT_8(3) +}; + +typedef enum { + PcieEndPoint, + LegacyPcieEndPoint, + PcieRootPort = 0x4, + PcieUpstreamPort = 0x5, + PcieDownstreamPort = 0x6, + PcieBridge = 0x8 +} PCIE_TYPE; + +void +Prom21AhciMsiCap ( + uint32_t XhciMmio, + bool Enable + ); + +void +Prom21AhciPortSataSpeed ( + uint32_t XhciMmio, + uint8_t PortNum, + uint8_t Speed + ); + +void +Prom21XhciGen ( + uint32_t XhciMmio, + uint8_t XhciGen, + uint8_t PortNum + ); + +void +Prom21UsbPortSetting ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciId, + uint32_t XhciMmio, + uint8_t BootMode + ); + +void +Prom21UsbSetting ( + PROM21_DATA_BLK *DataBlk, + uint32_t XhciMmio, + uint8_t BootMode + ); + +void +Prom21SataSetting ( + PROMCLASS_DATA_BLK *PromDataBlk + ); + +SIL_STATUS +Prom21Setting ( + SIL_CONTEXT *SilContext, + PROMCLASS_DATA_BLK *PromDataBlk + ); + +SIL_STATUS +Prom21LateSetting ( + SIL_CONTEXT *SilContext, + PROMCLASS_DATA_BLK *PromDataBlk + ); + +void +Prom21SIConfig ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciMmio + ); + +void +ScanSecXhciDidVid ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint16_t GppBus, + uint8_t GppDev, + uint8_t GppFun, + uint16_t TempBusNum + ); + +SIL_STATUS +AmdProm21FwLoad ( + SIL_CONTEXT *SilContext, + PROMCLASS_DATA_BLK *PromDataBlk + ); + +SIL_STATUS +AmdProm21FwLoadA1 ( + SIL_CONTEXT *SilContext, + PROMCLASS_DATA_BLK *PromDataBlk + ); diff --git a/xUSL/PROM/PROM21/Prom21Gpio.c b/xUSL/PROM/PROM21/Prom21Gpio.c new file mode 100644 index 0000000..7369ad6 --- /dev/null +++ b/xUSL/PROM/PROM21/Prom21Gpio.c @@ -0,0 +1,426 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ + +/** + * @file Prom21Gpio.c + * @brief Promontory21 GPIO related functions + */ + +#include +#include +#include +#include +#include +#include +#include "Prom21.h" +#include "Prom21Gpio.h" +#include "Prom21Init.h" + +SIL_STATUS +Prom21GpioWrite ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint8_t Pin, + uint8_t Value + ) +{ + SIL_STATUS Status; + PROM_PCI_SAVE_RESTORE_TABLE PtPciTable[2]; + uint32_t SecGppPcieAddress; + uint32_t GpioMmioAddr; + uint32_t SecGpioMmioAddr; + uint32_t MmioAddr; + PT_GPIO_REG PtGpioReg; + bool FoundSecondary; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, " Pin %d = %x\n", Pin, Value); + + Status = SilNotFound; + MmioAddr = 0; + FoundSecondary = PromDataBlk->PromOutputBlk.SecondaryPTPresent; + SecGppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[1]; + + if (SecGppPcieAddress) { + SaveInitPromBus(PromDataBlk, PtPciTable, 0x1111); + } else { + SaveInitPromBus(PromDataBlk, PtPciTable, 0x11); + } + + if (xUSLPciRead32(PCI_LIB_ADDRESS(PtPciTable[1].PromBus, 0, 0, 0)) == PT21_USP_ID) { + SecGpioMmioAddr = xUSLPciRead32(PCI_LIB_ADDRESS(PtPciTable[1].PromBus, 0, 0, 0x40)); + SecGpioMmioAddr &= 0xFFFFFFF0; + } else { + RestorePromBus(PromDataBlk, PtPciTable, 0x1100); + FoundSecondary = false; + } + + GpioMmioAddr = xUSLPciRead32(PCI_LIB_ADDRESS(PtPciTable[0].PromBus, 0, 0, 0x40)); + GpioMmioAddr &= 0xFFFFFFF0; + + if (Pin < PROM21_MAX_GPIO_PIN_NUMBER) { + MmioAddr = GpioMmioAddr; + } else { + if (FoundSecondary) { + if (Pin < (PROM21_MAX_GPIO_PIN_NUMBER << 1)) { + Pin -= PROM21_MAX_GPIO_PIN_NUMBER; + MmioAddr = SecGpioMmioAddr; + } + } else { + return Status; + } + } + + if (MmioAddr) { + PtGpioReg.GpioPinDir = xUSLMemRead32((void *)(size_t)(MmioAddr)); + if (PtGpioReg.GpioPinDir & BIT_32(Pin)) { + PtGpioReg.GpioOutputData = xUSLMemRead32((void *)(size_t)(MmioAddr + 0x8)); + if (Value) { + PtGpioReg.GpioOutputData |= BIT_32(Pin); + } else { + PtGpioReg.GpioOutputData &= ~BIT_32(Pin); + } + xUSLMemWrite32((void *)(size_t)(MmioAddr + 0x8), PtGpioReg.GpioOutputData); + } + Status = SilPass; + } + + if (FoundSecondary) { + RestorePromBus(PromDataBlk, PtPciTable, 0x1111); + } else { + RestorePromBus(PromDataBlk, PtPciTable, 0x11); + } + + return Status; +} + +SIL_STATUS +Prom21GpioRead ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint8_t Pin, + uint8_t *Value + ) +{ + SIL_STATUS Status; + PROM_PCI_SAVE_RESTORE_TABLE PtPciTable[2]; + uint32_t SecGppPcieAddress; + uint32_t GpioMmioAddr; + uint32_t SecGpioMmioAddr; + uint32_t MmioAddr; + PT_GPIO_REG PtGpioReg; + bool FoundSecondary; + + Status = SilNotFound; + FoundSecondary = PromDataBlk->PromOutputBlk.SecondaryPTPresent; + SecGppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[1]; + MmioAddr = 0; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, " Pin %d\n", Pin, Value); + + if (SecGppPcieAddress) { + SaveInitPromBus(PromDataBlk, PtPciTable, 0x1111); + } else { + SaveInitPromBus(PromDataBlk, PtPciTable, 0x11); + } + + if (xUSLPciRead32(PCI_LIB_ADDRESS(PtPciTable[1].PromBus, 0, 0, 0)) == PT21_USP_ID) { + SecGpioMmioAddr = xUSLPciRead32(PCI_LIB_ADDRESS(PtPciTable[1].PromBus, 0, 0, 0x40)); + SecGpioMmioAddr &= 0xFFFFFFF0; + } else { + RestorePromBus(PromDataBlk, PtPciTable, 0x1100); + FoundSecondary = false; + } + + GpioMmioAddr = xUSLPciRead32(PCI_LIB_ADDRESS(PtPciTable[0].PromBus, 0, 0, 0x40)); + GpioMmioAddr &= 0xFFFFFFF0; + + if (Pin < PROM21_MAX_GPIO_PIN_NUMBER) { + MmioAddr = GpioMmioAddr; + } else { + if (FoundSecondary) { + if (Pin < (PROM21_MAX_GPIO_PIN_NUMBER << 1)) { + Pin -= PROM21_MAX_GPIO_PIN_NUMBER; + MmioAddr = SecGpioMmioAddr; + } + } else { + return Status; + } + } + + if (MmioAddr) { + PtGpioReg.GpioPinDir = xUSLMemRead32((void *)(size_t)(MmioAddr)); + if (PtGpioReg.GpioPinDir & BIT_32(Pin)) { + PtGpioReg.GpioOutputData = xUSLMemRead32((void *)(size_t)(MmioAddr + 0x8)); + PROM_TRACEPOINT(SIL_TRACE_INFO, "GpioOutputData 0x%x , %x\n", + PtGpioReg.GpioOutputData, PtGpioReg.GpioOutputData & BIT_32(Pin)); + if (PtGpioReg.GpioOutputData & BIT_32(Pin)) { + *Value = 0x1; + PROM_TRACEPOINT(SIL_TRACE_INFO, "GpioOutputData High (%d)\n", *Value); + } else { + *Value = 0x0; + PROM_TRACEPOINT(SIL_TRACE_INFO, "GpioOutputData Low (%d)\n", *Value); + } + } else { + PtGpioReg.GpioInputData = xUSLMemRead32((void *)(size_t)(MmioAddr + 0x4)); + PROM_TRACEPOINT(SIL_TRACE_INFO, "GpioInputData 0x%x , %x\n", PtGpioReg.GpioInputData, PtGpioReg.GpioInputData & BIT_32(Pin)); + if (PtGpioReg.GpioInputData & BIT_32(Pin)) { + *Value = 0x1; + PROM_TRACEPOINT(SIL_TRACE_INFO, "GpioInputData High (%d)\n", *Value); + } else { + *Value = 0x0; + PROM_TRACEPOINT(SIL_TRACE_INFO, "GpioInputData Low (%d)\n", *Value); + } + } + Status = SilPass; + } + + if (FoundSecondary) { + RestorePromBus(PromDataBlk, PtPciTable, 0x1111); + } else { + RestorePromBus(PromDataBlk, PtPciTable, 0x11); + } + + return Status; +} + +static void +Prom21GpioInitial ( + PROMCLASS_DATA_BLK *PromDataBlk + ) +{ + uint32_t GpioPin; + uint32_t GpioMmio; + uint32_t SecGpioMmio; + uint32_t Data32; + uint16_t MaxGpioPin; + uint16_t PinNum; + PT_GPIO_REG GpioReg; + PT_GPIO_REG GpioRegData; + PT_GPIO_REG SecGpioReg; + PT_GPIO_REG SecGpioRegData; + PROM21_GPIO_INIT_TABLE *PTGpioDataPtr; + PROM21_GPIO_ITEM *TablePtr; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + GpioMmio = PromDataBlk->PromOutputBlk.PT21GpioMmio[0]; + SecGpioMmio = PromDataBlk->PromOutputBlk.PT21GpioMmio[1]; + Data32 = 0; + + GpioReg.GpioPinDir = 0; + GpioReg.GpioInputData = 0; + GpioReg.GpioOutputData = 0; + + SecGpioReg.GpioPinDir = 0; + SecGpioReg.GpioInputData = 0; + SecGpioReg.GpioOutputData = 0; + + PTGpioDataPtr = (PROM21_GPIO_INIT_TABLE *)&PromDataBlk->PromInputBlk.PT21GpioInitTable; + + if (PromDataBlk->PromOutputBlk.SecondaryPTPresent) { + MaxGpioPin = PROM21_MAX_GPIO_PIN_NUMBER << 1; + } else { + MaxGpioPin = PROM21_MAX_GPIO_PIN_NUMBER; + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, "PT-MaxGpioPin = %d\n", MaxGpioPin); + + if (PTGpioDataPtr) { + TablePtr = &PTGpioDataPtr->GpioList[0]; + + while ((TablePtr->Pin != 0xFF) && (TablePtr->Pin < MaxGpioPin)) { + PinNum = TablePtr->Pin; + if (PinNum < PROM21_MAX_GPIO_PIN_NUMBER) { + GpioPin = BIT_32(PinNum); + PROM_TRACEPOINT(SIL_TRACE_INFO, "Primary PT GPIO Pin-%d Setting = %d (0x%x)\n", + PinNum, TablePtr->Pin, GpioPin); + if (TablePtr->Setting.Gpio.OutEnB) { + GpioReg.GpioPinDir |= GpioPin; + if (TablePtr->Setting.Gpio.Out) { + GpioReg.GpioOutputData |= GpioPin; + } else { + GpioReg.GpioOutputData &= ~GpioPin; + } + } else { + GpioReg.GpioPinDir &= ~GpioPin; + } + } else { + PinNum -= PROM21_MAX_GPIO_PIN_NUMBER; + GpioPin = BIT_32(PinNum); + PROM_TRACEPOINT(SIL_TRACE_INFO, "Secondary PT GPIO Pin-%d Setting = %d (0x%x)\n", + PinNum, TablePtr->Pin, GpioPin); + if (TablePtr->Setting.Gpio.OutEnB) { + SecGpioReg.GpioPinDir |= GpioPin; + if (TablePtr->Setting.Gpio.Out) { + SecGpioReg.GpioOutputData |= GpioPin; + } else { + SecGpioReg.GpioOutputData &= ~GpioPin; + } + } else { + SecGpioReg.GpioPinDir &= ~GpioPin; + } + } + TablePtr++; + } + + GpioRegData.GpioOutputData = xUSLMemRead32((void *)(size_t)(GpioMmio + 0x8)); + xUSLMemWrite32((void *)(size_t)(GpioMmio + 0x8), (Data32 | GpioReg.GpioOutputData)); + + GpioRegData.GpioPinDir = xUSLMemRead32((void *)(size_t)(GpioMmio)); + xUSLMemWrite32((void *)(size_t)(GpioMmio), (Data32 | GpioReg.GpioPinDir)); + + GpioRegData.GpioInputData = xUSLMemRead32((void *)(size_t)(GpioMmio + 0x4)); + + PROM_TRACEPOINT(SIL_TRACE_INFO, "PT GPIO Pin Setting = 0x%x, 0x%x\n", + GpioRegData.GpioPinDir, GpioRegData.GpioOutputData); + PROM_TRACEPOINT(SIL_TRACE_INFO, "PT GPIO Pin New Setting = %x, %x\n", + GpioReg.GpioPinDir, GpioReg.GpioOutputData); + + if (PromDataBlk->PromOutputBlk.SecondaryPTPresent) { + SecGpioRegData.GpioOutputData = xUSLMemRead32((void *)(size_t)(SecGpioMmio + 0x8)); + xUSLMemWrite32((void *)(size_t)(SecGpioMmio + 0x8), SecGpioReg.GpioOutputData); + + SecGpioRegData.GpioPinDir = xUSLMemRead32((void *)(size_t)(SecGpioMmio)); + xUSLMemWrite32((void *)(size_t)(SecGpioMmio), SecGpioReg.GpioPinDir); + + SecGpioRegData.GpioInputData = xUSLMemRead32((void *)(size_t)(SecGpioMmio + 0x4)); + PROM_TRACEPOINT(SIL_TRACE_INFO, "Sec PT GPIO Pin Setting = 0x%x, 0x%x\n", + SecGpioRegData.GpioPinDir, SecGpioRegData.GpioOutputData); + PROM_TRACEPOINT(SIL_TRACE_INFO, "Sec PT GPIO Pin New Setting = 0x%x, 0x%x\n", + SecGpioReg.GpioPinDir, SecGpioReg.GpioOutputData); + } + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + +SIL_STATUS +Prom21ProgramGpiosInitial ( + PROMCLASS_DATA_BLK *PromDataBlk + ) +{ + uint16_t GppBus; + uint8_t GppDev; + uint8_t GppFun; + uint16_t SecGppBus; + uint8_t SecGppDev; + uint8_t SecGppFun; + uint16_t SecUspBus; + uint32_t Value32; + uint16_t IoHcBus; + uint32_t IohcBridgeCntlSmnReg; + uint32_t GppPcieAddress; + uint32_t SecGppPcieAddress; + PROM_PCI_SAVE_RESTORE_TABLE PtPciTable[2]; + bool SecondaryFound; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + if (PromDataBlk->PromOutputBlk.PT21XhciID[0] == 0) { + PROM_TRACEPOINT(SIL_TRACE_ERROR," Promontory is NOT FOUND !!\n"); + return SilNotFound; + } + + if (PromDataBlk->PromInputBlk.BootMode == 0x20 /* BOOT_IN_RECOVERY_MODE */) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " In Recovery mode!\n"); + return SilPass; + } + + if (PromDataBlk->PromOutputBlk.PT21GpioID == 0) { + PROM_TRACEPOINT(SIL_TRACE_ERROR, "PT GPIO is NOT FOUND!\n"); + return SilNotFound; + } + + SecondaryFound = PromDataBlk->PromOutputBlk.SecondaryPTPresent; + GppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[0]; + SecGppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[1]; + IoHcBus = (uint16_t) PromDataBlk->PromOutputBlk.PT21IoHcBusNum | + (uint16_t) ((GppPcieAddress >> 20) & 0xF00); + + if (SecGppPcieAddress) { + SaveInitPromBus(PromDataBlk, PtPciTable, 0x1111); + } else { + SaveInitPromBus(PromDataBlk, PtPciTable, 0x11); + } + + if (PtPciTable[0].PromBus != 0) { + if (xUSLPciRead32(PCI_LIB_ADDRESS(PtPciTable[0].PromBus, 0, 0, 0)) != PT21_USP_ID) { + RestorePromBus(PromDataBlk, PtPciTable, 0x11); + PROM_TRACEPOINT(SIL_TRACE_ERROR, "PT GPIO device NOT FOUND!\n"); + return SilNotFound; + } + } + + if (PtPciTable[1].PromBus != 0) { + if (xUSLPciRead32(PCI_LIB_ADDRESS(PtPciTable[1].PromBus, 0, 0, 0)) != PT21_USP_ID) { + RestorePromBus(PromDataBlk, PtPciTable, 0x1100); + PROM_TRACEPOINT(SIL_TRACE_ERROR, "Secondary PT GPIO device NOT FOUND!\n"); + SecondaryFound = false; + } + } + + IohcBridgeCntlSmnReg = PromDataBlk->PromOutputBlk.PT21IohcBridgeCntl; + xUSLPciWrite32(PCI_LIB_ADDRESS(IoHcBus, 0, 0, 0x60), IohcBridgeCntlSmnReg); + Value32 = xUSLPciRead32(PCI_LIB_ADDRESS(IoHcBus, 0, 0, 0x64)); + Value32 &= 0x007FFFFF; + Value32 |= ((((PromDataBlk->PromOutputBlk.PT21GpioMmio[0] >> 12) & 0xFF) << 24) + (1 << 23)); + xUSLPciWrite32(PCI_LIB_ADDRESS(IoHcBus, 0, 0, 0x64), Value32); + + Value32 = PromDataBlk->PromOutputBlk.PT21GpioMmio[0]; + + xUSLPciWrite32(PCI_LIB_ADDRESS(PtPciTable[0].PromBus, 0, 0, 0x40), Value32); + Value32 = 0x0; + xUSLPciWrite32(PCI_LIB_ADDRESS(PtPciTable[0].PromBus, 0, 0, 0x44), Value32); + + Value32 = xUSLPciRead32(PCI_LIB_ADDRESS(PtPciTable[0].PromBus, 0, 0, 0x48)); + Value32 |= 0x01; + xUSLPciWrite32(PCI_LIB_ADDRESS(PtPciTable[0].PromBus, 0, 0, 0x48), Value32); + + if (PromDataBlk->PromOutputBlk.SecondaryPTPresent) { + GppBus = (uint16_t) ((GppPcieAddress >> 20) & 0xFFF); + GppDev = (uint8_t) ((GppPcieAddress >> 15) & 0x1F); + GppFun = (uint8_t) ((GppPcieAddress >> 12) & 0x07); + + SecGppBus = (uint16_t) ((SecGppPcieAddress >> 20) & 0xFFF); + SecGppDev = (uint8_t) ((SecGppPcieAddress >> 15) & 0x1F); + SecGppFun = (uint8_t) ((SecGppPcieAddress >> 12) & 0x07); + SecUspBus = (uint16_t) xUSLPciRead8( + PCI_LIB_ADDRESS(SecGppBus, SecGppDev, SecGppFun, 0x19)) | + (SecGppBus & 0xFF00); + + PROM_TRACEPOINT(SIL_TRACE_INFO, "PT @ Bus %x, Dev %x, Func %x\n", + GppBus, GppDev, GppFun); + PROM_TRACEPOINT(SIL_TRACE_INFO, "Sec PT @ Bus %x, Dev %x, Func %x, Usp %x\n", + SecGppBus, SecGppDev, SecGppFun, SecUspBus); + + Value32 = PromDataBlk->PromOutputBlk.PT21GpioMmio[1]; + + xUSLPciWrite16(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x20), + (uint16_t)(Value32 >> 16)); + xUSLPciWrite16(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x22), + (uint16_t)(Value32 >> 16)); + + xUSLPciWrite16(PCI_LIB_ADDRESS(SecGppBus, SecGppDev, SecGppFun, 0x20), + (uint16_t)(Value32 >> 16)); + xUSLPciWrite16(PCI_LIB_ADDRESS(SecGppBus, SecGppDev, SecGppFun, 0x22), + (uint16_t)(Value32 >> 16)); + + xUSLPciWrite32(PCI_LIB_ADDRESS(SecUspBus, 0, 0, 0x40), Value32); + Value32 = 0x0; + xUSLPciWrite32(PCI_LIB_ADDRESS(SecUspBus, 0, 0, 0x44), Value32); + + Value32 = xUSLPciRead32(PCI_LIB_ADDRESS(SecUspBus, 0, 0, 0x48)); + Value32 |= 0x01; + xUSLPciWrite32(PCI_LIB_ADDRESS(SecUspBus, 0, 0, 0x48), Value32); + } + + Prom21GpioInitial(PromDataBlk); + + if (SecGppPcieAddress && SecondaryFound) { + RestorePromBus(PromDataBlk, PtPciTable, 0x1111); + } else { + RestorePromBus(PromDataBlk, PtPciTable, 0x11); + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, "\n"); + + return SilPass; +} diff --git a/xUSL/PROM/PROM21/Prom21Gpio.h b/xUSL/PROM/PROM21/Prom21Gpio.h new file mode 100644 index 0000000..2b84639 --- /dev/null +++ b/xUSL/PROM/PROM21/Prom21Gpio.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ + +/** + * @file Prom21Gpio.h + * @brief Promontory21 GPIO related defines + */ + + +#pragma once + +#include +#include + +typedef struct { + uint32_t GpioPinDir; + uint32_t GpioInputData; + uint32_t GpioOutputData; +} PT_GPIO_REG; + +SIL_STATUS +Prom21GpioWrite ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint8_t Pin, + uint8_t Value + ); + +SIL_STATUS +Prom21GpioRead ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint8_t Pin, + uint8_t *Value + ); + +SIL_STATUS +Prom21ProgramGpiosInitial ( + PROMCLASS_DATA_BLK *PromDataBlk + ); diff --git a/xUSL/PROM/PROM21/Prom21Init.c b/xUSL/PROM/PROM21/Prom21Init.c index 1c01a2a..2a1b684 100644 --- a/xUSL/PROM/PROM21/Prom21Init.c +++ b/xUSL/PROM/PROM21/Prom21Init.c @@ -2,7 +2,7 @@ /* Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ /** - * @file PromInit.c + * @file Prom21Init.c * @brief Promontory21 related functions */ @@ -10,10 +10,471 @@ #include #include #include -#include +#include +#include +#include +#include +#include #include +#include +#include "Prom21.h" +#include "Prom21Gpio.h" #include "Prom21Init.h" +void +ScanSecXhciDidVid ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint16_t GppBus, + uint8_t GppDev, + uint8_t GppFun, + uint16_t TempBusNum + ) +{ + uint32_t DidVid = 0; + uint32_t PtDspBusData = 0; + uint32_t SecPtUspBusData = 0; + uint32_t SecPtDspBusData = 0; + uint32_t GppPcieAddress = 0; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY," PT DSP [%04X:%02X:%02X]\n", GppBus, GppDev, GppFun); + + DidVid = xUSLPciRead32(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x00)); + if (DidVid == 0xFFFFFFFF) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT DSP [%04X:%02X:%02X] is not present\n", + GppBus, GppDev, GppFun); + return; + } + + DidVid = xUSLPciRead32(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x08)); + if ((DidVid >> 16) != 0x0604) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT DSP [%04X:%02X:%02X] is not a PCIE bridge\n", + GppBus, GppDev, GppFun); + return; + } + + DidVid = xUSLPciRead32(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x98)); + if ((DidVid & BIT_32(22)) == 0) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT DSP [%04X:%02X:%02X] EP device is not present\n", + GppBus, GppDev, GppFun); + return; + } + + PtDspBusData = xUSLPciRead32(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x18)); + + xUSLPciWrite8(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x18), (uint8_t)GppBus); + xUSLPciWrite8(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x19), (uint8_t)TempBusNum); + xUSLPciWrite8(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x1A), (uint8_t)TempBusNum + 3); + + DidVid = xUSLPciRead32(PCI_LIB_ADDRESS(TempBusNum, 0, 0, 0x08)); + if ((DidVid >> 16) != 0x0604) { + xUSLPciWrite32(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x18), PtDspBusData); + PROM_TRACEPOINT(SIL_TRACE_INFO, " SEC PT USP [%04X:%02X:%02X] is not a PCIE bridge\n", + TempBusNum, 0, 0); + return; + } + + SecPtUspBusData = xUSLPciRead32(PCI_LIB_ADDRESS(TempBusNum, 0, 0, 0x18)); + + xUSLPciWrite8(PCI_LIB_ADDRESS(TempBusNum, 0, 0, 0x18), (uint8_t)TempBusNum); + xUSLPciWrite8(PCI_LIB_ADDRESS(TempBusNum, 0, 0, 0x19), (uint8_t)TempBusNum + 1); + xUSLPciWrite8(PCI_LIB_ADDRESS(TempBusNum, 0, 0, 0x1A), (uint8_t)TempBusNum + 3); + + DidVid = xUSLPciRead32(PCI_LIB_ADDRESS(TempBusNum + 1, PROM21_XHCI_DSP_DEV, 0, 0x08)); + if ((DidVid >> 16) != 0x0604) { + xUSLPciWrite32(PCI_LIB_ADDRESS(TempBusNum, 0, 0, 0x18), SecPtUspBusData); + xUSLPciWrite32(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x18), PtDspBusData); + PROM_TRACEPOINT(SIL_TRACE_INFO, " SEC XHCI DSP [%04X:%02X:%02X] is not a PCIE bridge\n", + TempBusNum + 1, PROM21_XHCI_DSP_DEV, 0); + return; + } + + SecPtDspBusData = xUSLPciRead32(PCI_LIB_ADDRESS(TempBusNum + 1, PROM21_XHCI_DSP_DEV, 0, 0x18)); + + xUSLPciWrite8(PCI_LIB_ADDRESS(TempBusNum + 1, PROM21_XHCI_DSP_DEV, 0, 0x18), + (uint8_t)TempBusNum + 1); + xUSLPciWrite8(PCI_LIB_ADDRESS(TempBusNum + 1, PROM21_XHCI_DSP_DEV, 0, 0x19), + (uint8_t)TempBusNum + 2); + xUSLPciWrite8(PCI_LIB_ADDRESS(TempBusNum + 1, PROM21_XHCI_DSP_DEV, 0, 0x1A), + (uint8_t)TempBusNum + 2); + + DidVid = xUSLPciRead32(PCI_LIB_ADDRESS(TempBusNum + 2, 0, 0, 0)); + + PROM_TRACEPOINT(SIL_TRACE_INFO, " EndPoint DidVid = 0x%08X\n", DidVid); + + if ((DidVid == PT21_XHCI_ID_L1) || (DidVid == PT21_XHCI_ID_L2) || + (DidVid == PT21_XHCI_ID_L3) || (DidVid == PT21_XHCI_ID_L4) || + (DidVid == PT21_XHCI_ID_L5) || (DidVid == PT21_XHCI_ID_L6) || + (DidVid == PT21_XHCI_ID_L7) || (DidVid == PT21_XHCI_ID_L8)) { + GppPcieAddress = PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0); + PromDataBlk->PromOutputBlk.PT21XhciID[1] = DidVid; + PromDataBlk->PromOutputBlk.PT21GppPcieAddress[1] = GppPcieAddress; + } + + xUSLPciWrite32(PCI_LIB_ADDRESS(TempBusNum + 1, PROM21_XHCI_DSP_DEV, 0, 0x18), + SecPtDspBusData); + xUSLPciWrite32(PCI_LIB_ADDRESS(TempBusNum, 0, 0, 0x18), + SecPtUspBusData); + xUSLPciWrite32(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x18), + PtDspBusData); + + if (GppPcieAddress != 0) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Found Second Promontory!\n"); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set Secondary PT21XhciID = 0x%08X\n", + PromDataBlk->PromOutputBlk.PT21XhciID[1]); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set Secondary PT21GppPcieAddress = 0x%08X\n", + PromDataBlk->PromOutputBlk.PT21GppPcieAddress[1]); + PromDataBlk->PromOutputBlk.SecondaryPTPresent = true; + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " It's not Second Promontory!\n"); + } + + return; +} + +static void +ScanXhciDidVid ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint16_t GppBus, + uint8_t GppDev, + uint8_t GppFun, + uint16_t TempBusNum + ) +{ + uint32_t DidVid = 0; + uint32_t GpioDidVid = 0; + uint32_t GppBusData = 0; + uint32_t UspBusData = 0; + uint32_t DspBusData = 0; + uint32_t GppPcieAddress = 0; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY," GPP [%04X:%02X:%02X]\n", GppBus, GppDev, GppFun); + DidVid = xUSLPciRead32(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x00)); + if (DidVid == 0xFFFFFFFF) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " GPP [%04X:%02X:%02X] is not present\n", GppBus, GppDev, GppFun); + return; + } + + DidVid = xUSLPciRead32(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x08)); + if ((DidVid >> 16) != 0x0604) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " GPP [%04X:%02X:%02X] is not a PCIE bridge\n", + GppBus, GppDev, GppFun); + return; + } + + DidVid = xUSLPciRead32(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x70)); + if ((DidVid & BIT_32(22)) == 0) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " GPP [%04X:%02X:%02X] endpoint device is not present\n", + GppBus, GppDev, GppFun); + return; + } + + GppBusData = xUSLPciRead32(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x18)); + xUSLPciWrite8(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x18), (uint8_t)GppBus); + xUSLPciWrite8(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x19), (uint8_t)TempBusNum); + xUSLPciWrite8(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x1A), (uint8_t)TempBusNum + 7); + + DidVid = xUSLPciRead32(PCI_LIB_ADDRESS(TempBusNum, 0, 0, 0x08)); + if ((DidVid >> 16) != 0x0604) { + xUSLPciWrite32(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x18), GppBusData); + PROM_TRACEPOINT(SIL_TRACE_INFO, " USP [%04X:%02X:%02X] is not a PCIE bridge\n", + TempBusNum, 0, 0); + return; + } + + UspBusData = xUSLPciRead32(PCI_LIB_ADDRESS(TempBusNum, 0, 0, 0x18)); + xUSLPciWrite8(PCI_LIB_ADDRESS(TempBusNum, 0, 0, 0x18), (uint8_t)TempBusNum); + xUSLPciWrite8(PCI_LIB_ADDRESS(TempBusNum, 0, 0, 0x19), (uint8_t)TempBusNum + 1); + xUSLPciWrite8(PCI_LIB_ADDRESS(TempBusNum, 0, 0, 0x1A), (uint8_t)TempBusNum + 7); + + DidVid = xUSLPciRead32(PCI_LIB_ADDRESS(TempBusNum + 1, PROM21_XHCI_DSP_DEV, 0, 0x08)); + if ((DidVid >> 16) != 0x0604) { + xUSLPciWrite32(PCI_LIB_ADDRESS(TempBusNum, 0, 0, 0x18), UspBusData); + xUSLPciWrite32(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x18), GppBusData); + PROM_TRACEPOINT(SIL_TRACE_INFO, " XHCI DSP [%02X:%02X:%02X] is not a PCIE bridge\n", + TempBusNum + 1, PROM21_XHCI_DSP_DEV, 0); + return; + } + + DspBusData = xUSLPciRead32(PCI_LIB_ADDRESS(TempBusNum + 1, PROM21_XHCI_DSP_DEV, 0, 0x18)); + xUSLPciWrite8(PCI_LIB_ADDRESS(TempBusNum + 1, PROM21_XHCI_DSP_DEV, 0, 0x18), + (uint8_t)TempBusNum + 1); + xUSLPciWrite8(PCI_LIB_ADDRESS(TempBusNum + 1, PROM21_XHCI_DSP_DEV, 0, 0x19), + (uint8_t)TempBusNum + 2); + xUSLPciWrite8(PCI_LIB_ADDRESS(TempBusNum + 1, PROM21_XHCI_DSP_DEV, 0, 0x1A), + (uint8_t)TempBusNum + 2); + + + DidVid = xUSLPciRead32(PCI_LIB_ADDRESS(TempBusNum + 2, 0, 0, 0)); + GpioDidVid = xUSLPciRead32(PCI_LIB_ADDRESS(TempBusNum, 0, 0, 0)); + PROM_TRACEPOINT(SIL_TRACE_INFO, " EndPoint DidVid = 0x%08X\n", DidVid); + + if ((DidVid == PT21_XHCI_ID_L1) || (DidVid == PT21_XHCI_ID_L2) || + (DidVid == PT21_XHCI_ID_L3) || (DidVid == PT21_XHCI_ID_L4) || + (DidVid == PT21_XHCI_ID_L5) || (DidVid == PT21_XHCI_ID_L6) || + (DidVid == PT21_XHCI_ID_L7) || (DidVid == PT21_XHCI_ID_L8) ) { + GppPcieAddress = PCI_LIB_ADDRESS (GppBus, GppDev, GppFun, 0); + GppPcieAddress |= ((uint32_t) (GppBus & 0xFF00) << 20); + PromDataBlk->PromOutputBlk.PT21GpioID = GpioDidVid; + PromDataBlk->PromOutputBlk.PT21XhciID[0] = DidVid; + PromDataBlk->PromOutputBlk.PT21GppPcieAddress[0] = GppPcieAddress; + if (DidVid == PT21_XHCI_ID_L4) { + if (PromDataBlk->PromInputBlk.PT21PcieTargetSpeed >= 0x4) { + PromDataBlk->PromInputBlk.PT21PcieTargetSpeed = 0x3; + } + } + } + + xUSLPciWrite32(PCI_LIB_ADDRESS(TempBusNum + 1, PROM21_XHCI_DSP_DEV, 0, 0x18), DspBusData); + xUSLPciWrite32(PCI_LIB_ADDRESS(TempBusNum, 0, 0, 0x18), UspBusData); + xUSLPciWrite32(PCI_LIB_ADDRESS(GppBus, GppDev, GppFun, 0x18), GppBusData); + + if (GppPcieAddress != 0) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Found Promontory!\n"); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set PT21XhciID = 0x%08X\n", + PromDataBlk->PromOutputBlk.PT21XhciID[0]); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set PT21GpioID = 0x%08X\n", + PromDataBlk->PromOutputBlk.PT21GpioID); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set PT21GppPcieAddress = 0x%08X\n", + PromDataBlk->PromOutputBlk.PT21GppPcieAddress[0]); + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " It's not Promontory!\n"); + } + + return; +} + +static void +GetIohcBridgeControl ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint16_t GppBus, + uint8_t GppDev, + uint8_t GppFun, + uint8_t NbioNum + ) +{ + uint32_t IohcBridgeCntl = 0; + uint32_t Index; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, " GPP [%04X:%02X:%02X] NBIO[%d]\n", + GppBus, GppDev, GppFun, NbioNum); + + if (SocFamilyIdCheck (AMD_FAMILY_PHX)) { + static const uint8_t PhxIohcBrightNumbering[17] = { + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x19, 0x1A, 0x1B, 0x1C, 0x21 + }; + + for (Index = 0; Index < 17; Index++) { + if (PhxIohcBrightNumbering[Index] == ((GppDev << 3) + GppFun)) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " F19_PHX IohcBrightNumbering Index = %d\n", Index); + break; + } + } + if (Index < 17) { + if (Index >= 6) { + Index += 2; + if (Index >= 14) { + Index += 2; + if (Index >= 20) { + Index += 4; + } + } + } + Index <<= 10; + IohcBridgeCntl = Index + IOHCx13b31004; + } + } + + if (IohcBridgeCntl > 0) { + PromDataBlk->PromOutputBlk.PT21IohcBridgeCntl = IohcBridgeCntl; + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set PT21IohcBridgeCntl = 0x%08X\n", IohcBridgeCntl); + } +} + +static SIL_STATUS +SearchProm ( + SIL_CONTEXT *SilContext, + PROMCLASS_DATA_BLK *PromDataBlk + ) +{ + SIL_STATUS Status; + EARLY_LINK_STATUS NbioPtLinkData; + FABRIC_TARGET MmioTarget; + FABRIC_MMIO_ATTRIBUTE MmioAttr; + PROM_PCI_SAVE_RESTORE_TABLE PtPciTable[2]; + uint32_t NumberOfSocket; + uint32_t NumberOfRootBridgeOnDie; + uint32_t NumberOfDie; + uint32_t SocketLoop; + uint32_t DieLoop; + uint32_t RootBridgeLoop; + uint32_t BusNumberBase; + uint32_t PhysicalRootBridgeNumber; + uint64_t MmioSize; + uint64_t MmioBase; + uint16_t GppBus = 0; + uint8_t GppDev = 0; + uint8_t GppFun = 0; + uint8_t NbioNum = 0; + uint16_t TempBusNum; + uint8_t RootBridgeNum = 0; + uint8_t eFuseValue8 = 0; + uint32_t ForceGppPcieAddress; + uint32_t XhciMmio; + uint32_t SecXhciMmio; + MPIO_COMMON_2_REV_XFER_BLOCK *MpioXferTable; + DF_IP2IP_API *DfIp2IpApi; + RCMGR_IP2IP_API *RcMgrIp2Ip; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY,"\n"); + + if (SilGetCommon2RevXferTable(SilContext, SilId_MpioClass, (void **)(&MpioXferTable)) != SilPass) { + return SilNotFound; + } + + if (SilGetIp2IpApi(SilContext, SilId_DfClass, (void **)(&DfIp2IpApi)) != SilPass) { + return SilNotFound; + } + + if (SilGetIp2IpApi(SilContext, SilId_RcManager, (void **)(&RcMgrIp2Ip)) != SilPass) { + return SilNotFound; + } + + MmioTarget.PciBusNum = 0; + MmioTarget.PciSegNum = 0; + MmioTarget.RbNum = 0; + MmioTarget.SocketNum = 0; + MmioTarget.TgtType = 0; + + TempBusNum = (uint16_t) PromDataBlk->PromInputBlk.PT21TempBusNum; + ForceGppPcieAddress = PromDataBlk->PromInputBlk.PT21ForceGppPcieAddress; + + if (ForceGppPcieAddress == 0) { + Status = MpioXferTable->MpioGetEarlyLinkConfig(SilContext, &NbioPtLinkData); + if (Status == SilPass) { + if (NbioPtLinkData.EarlyLinkStatus) { + NbioNum = NbioPtLinkData.PhysicalRootBridge; + RootBridgeNum = NbioPtLinkData.LogicalRootBridge; + DfIp2IpApi->DfGetSystemInfo(SilContext, &NumberOfSocket, NULL, NULL, NULL, NULL); + for (SocketLoop = 0; SocketLoop < NumberOfSocket; SocketLoop++) { + DfIp2IpApi->DfGetProcessorInfo(SilContext, SocketLoop, &NumberOfDie, NULL); + for (DieLoop = 0; DieLoop < NumberOfDie; DieLoop++) { + DfIp2IpApi->DfGetDieInfo(SilContext, + SocketLoop, + DieLoop, + &NumberOfRootBridgeOnDie, + NULL, + NULL + ); + for (RootBridgeLoop = 0; + RootBridgeLoop < NumberOfRootBridgeOnDie; + RootBridgeLoop++) { + DfIp2IpApi->DfGetRootBridgeInfo(SilContext, + SocketLoop, + DieLoop, + RootBridgeLoop, + NULL, + &BusNumberBase, + NULL, + &PhysicalRootBridgeNumber, + NULL, + NULL + ); + if (PhysicalRootBridgeNumber == NbioNum) { + GppBus = (uint16_t)BusNumberBase; + } + } + } + } + GppDev = NbioPtLinkData.RootPortDevice; + GppFun = NbioPtLinkData.RootPortFunction; + TempBusNum += GppBus; + PromDataBlk->PromOutputBlk.PT21RootBridgeNum = RootBridgeNum; + PromDataBlk->PromOutputBlk.PT21IoHcBusNum = (uint8_t)GppBus; + PROM_TRACEPOINT(SIL_TRACE_INFO, " [%04X:%02X:%02X]\n", GppBus, GppDev, GppFun); + PROM_TRACEPOINT(SIL_TRACE_INFO, " NbioNum = %x, RootBridgeNum = %x, TempBusNum = %x\n", + NbioNum, RootBridgeNum, TempBusNum); + + ScanXhciDidVid(PromDataBlk, GppBus, GppDev, GppFun, TempBusNum); + GetIohcBridgeControl(PromDataBlk, GppBus, GppDev, GppFun, NbioNum); + } + } + } else { + NbioNum = (uint8_t)((ForceGppPcieAddress >> 20) & 0xFF); + RootBridgeNum = (uint8_t)((ForceGppPcieAddress >> 20) & 0xFF); + GppBus = (uint16_t)((ForceGppPcieAddress >> 20) & 0xFFF); + GppDev = (uint8_t)((ForceGppPcieAddress >> 15) & 0x1F); + GppFun = (uint8_t)((ForceGppPcieAddress >> 12) & 0x07); + TempBusNum += GppBus; + PromDataBlk->PromOutputBlk.PT21RootBridgeNum = RootBridgeNum; + PROM_TRACEPOINT(SIL_TRACE_INFO, " Force PT21 GPP to [%04X:%02X:%02X]\n", + GppBus, GppDev, GppFun); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Force PT21 GPP to NbioNum = %x, RootBridgeNum = %x, TempBusNum = %x\n", + NbioNum, RootBridgeNum, TempBusNum); + + ScanXhciDidVid(PromDataBlk, GppBus, GppDev, GppFun, TempBusNum); + GetIohcBridgeControl(PromDataBlk, GppBus, GppDev, GppFun, NbioNum); + } + + if (PromDataBlk->PromOutputBlk.PT21XhciID[0] == 0) { + Status = SilDeviceError; + } else { + Status = SilPass; + } + + if (Status == SilPass) { + MmioTarget.TgtType = TARGET_RB; + MmioTarget.SocketNum = 0; + MmioTarget.RbNum = RootBridgeNum; + + MmioSize = 0x200000; // 2MB + MmioAttr.MmioType = NON_PCI_DEVICE_BELOW_4G; + Status = RcMgrIp2Ip->FabricReserveMmio(SilContext, + &MmioBase, + &MmioSize, + ALIGN_1M, + MmioTarget, + &MmioAttr); + if (Status != SilPass) { + PROM_TRACEPOINT(SIL_TRACE_ERROR, " Failed to allocate DF MMIO for PT XHCI.\n"); + return Status; + } + + XhciMmio = (uint32_t)MmioBase; + SecXhciMmio = (uint32_t)(MmioBase + 0x100000); + + PromDataBlk->PromOutputBlk.PT21XhciMmio[0] = XhciMmio; + PromDataBlk->PromOutputBlk.PT21XhciMmio[1] = SecXhciMmio; + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Allocate MMIO resources from Fabric 0x%08X Size 0x%08X\n", + XhciMmio, MmioSize); + + PromDataBlk->PromOutputBlk.PT21GpioMmio[0] = 0xFEC40000; + PromDataBlk->PromOutputBlk.PT21GpioMmio[0] = 0xFEC50000; + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Enable DF MMIO specific decode.\n"); + PROM_TRACEPOINT(SIL_TRACE_INFO, " XHCI MMIO set, start to read efuse value\n"); + + SaveInitPromBus(PromDataBlk, PtPciTable, 0xBB); + + if (PromDataBlk->PromInputBlk.PT21Revision == 0xf) { + eFuseValue8 = Prom21XhciReadByte (XhciMmio, 0x2E37B); + if((eFuseValue8 & BIT_8(3)) == BIT_8(3)) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Using A2 now\n"); + PromDataBlk->PromInputBlk.PT21Revision = 0x2; + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Using A0/A1 now\n"); + PromDataBlk->PromInputBlk.PT21Revision = 0x1; + } + } + + RestorePromBus(PromDataBlk, PtPciTable, 0xBB); + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "Status = %x\n", Status); + return Status; +} /**-------------------------------------------------------------------- * InitializePromontoryChipset @@ -27,7 +488,7 @@ * @param SilContext A context structure through which host firmware defined data * can be passed to openSIL. The host firmware is responsible * for initializing the SIL_CONTEXT structure. - * @param PromInputBlk A pointer to the PROM configuration data. + * @param PromDataBlk A pointer to the PROM configuration data. * @return SIL_STATUS * @retval SilPass - everything is OK * @retval SilNotFound - Something went wrong @@ -35,7 +496,7 @@ SIL_STATUS InitializePromontoryChipset ( SIL_CONTEXT *SilContext, - PROMCLASS_DATA_BLK *PromInputBlk + PROMCLASS_DATA_BLK *PromDataBlk ) { SIL_STATUS Status; @@ -43,6 +504,41 @@ InitializePromontoryChipset ( Status = SilPass; PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + Status = SearchProm(SilContext, PromDataBlk); + if (Status != SilPass) { + PROM_TRACEPOINT(SIL_TRACE_ERROR, " Search for Prom21 Failed!\n"); + return Status; + } + + if (PromDataBlk->PromInputBlk.PT21Revision < 2) { + Status = AmdProm21FwLoadA1(SilContext, PromDataBlk); + } else { + Status = AmdProm21FwLoad(SilContext, PromDataBlk); + } + + if (Status != SilPass) { + PROM_TRACEPOINT(SIL_TRACE_ERROR, " Prom21 FW Loading Failed!\n"); + return Status; + } + + if (PromDataBlk->PromOutputBlk.PT21XhciLock[0] == 1) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " XHCI is locked == Skip Prom21Setting!\n"); + } else { + Status = Prom21Setting(SilContext, PromDataBlk); + if (Status != SilPass) { + PROM_TRACEPOINT(SIL_TRACE_ERROR, " Prom21Setting fail!\n"); + } + + Status = Prom21ProgramGpiosInitial(PromDataBlk); + if (Status != SilPass) { + PROM_TRACEPOINT(SIL_TRACE_ERROR, " Prom21ProgramGpiosInitial fail!\n"); + } + + Status = Prom21LateSetting (SilContext, PromDataBlk); + if (Status != SilPass) { + PROM_TRACEPOINT(SIL_TRACE_ERROR, " Prom21LateSetting fail!\n"); + } + } PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); diff --git a/xUSL/PROM/PROM21/Prom21Init.h b/xUSL/PROM/PROM21/Prom21Init.h index 61416b6..03a5eed 100644 --- a/xUSL/PROM/PROM21/Prom21Init.h +++ b/xUSL/PROM/PROM21/Prom21Init.h @@ -3,7 +3,7 @@ /** * @file Prom21Init.h - * @brief All PROM related defines and structures + * @brief Promontory21 related defines and structures */ #pragma once @@ -15,5 +15,5 @@ SIL_STATUS InitializePromontoryChipset ( SIL_CONTEXT *SilContext, - PROMCLASS_DATA_BLK *PromInputBlk + PROMCLASS_DATA_BLK *PromDataBlk ); diff --git a/xUSL/PROM/PROM21/Prom21LoadFw.c b/xUSL/PROM/PROM21/Prom21LoadFw.c new file mode 100644 index 0000000..68aaf66 --- /dev/null +++ b/xUSL/PROM/PROM21/Prom21LoadFw.c @@ -0,0 +1,1392 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ + +/** + * @file Prom21LoadFw.c + * @brief Promontory21 firmware loading functions + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Prom21.h" +#include "Prom21Init.h" + +static void +Prom21DspLaneReversal ( + uint32_t XhciMmio, + uint8_t Enable, + uint8_t PortNum + ) +{ + uint32_t Address; + uint8_t Value; + + if(PortNum > PROM21_MAX_LANE_REVERSAL_DSP_NUMBER) { + return; + } + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + Address = PORM21_LANE_REVERSAL_REG(PortNum); + + Value = Prom21XhciReadByte(XhciMmio, Address); + + switch (Enable) { + case 0: + Value |= BIT_8(0); + break; + case 1: + Value &= (~BIT_8(0)); + break; + default: + Value |= BIT_8(0); + break; + } + + Prom21XhciWriteByte(XhciMmio, Address, Value); +} + + +static void +Prom21DspLaneConfig ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciMmio + ) +{ + for (uint8_t PortNum = 0; PortNum < PROM21_NUM_PCIE_LANES; PortNum += 2) { + if(PromDataBlk->PT21PciePortLaneRev[PortNum / 2] != 0xf) { + Prom21DspLaneReversal(XhciMmio, + PromDataBlk->PT21PciePortLaneRev[PortNum / 2], + PortNum); + } + } +} + +static uint32_t +FwChecksum ( + uint8_t *PtFwAddress, + uint32_t PtFwSize + ) +{ + uint32_t Counter; + uint32_t Checksum = 0; + + for (Counter = 0; Counter < (PtFwSize - 0x4C); Counter++) { + Checksum += (uint32_t) *(PtFwAddress + 0x0C + Counter); + } + + return Checksum; +} + +static SIL_STATUS +Prom21LoadFwDoneNew ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint32_t XhciMmio + ) +{ + SIL_STATUS Status; + uint32_t Loop; + uint8_t Value; + uint8_t WriteValue; + + Status = SilDeviceError; + Loop = 0; + + do { + Value = Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x1E51C); + if (Value & BIT_8(6)) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Prom21LoadFwDoneNew Ready (%x) @loop %d takes %d(ms)\n", + Value, Loop, (Loop * 2)); + do { + Value &= ~BIT_8(6); + WriteValue = Value; + Prom21XhciWriteByte(XhciMmio, 0x1E51C, WriteValue); + Value = Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x1E51C); + } while(Value != WriteValue); + Status = SilPass; + break; + } + SilFchStall(2 * 1000); + Loop++; + } while (Loop < 500); + + return Status; +} + +static SIL_STATUS +Prom21CheckLoadFwStatus ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint32_t XhciMmio + ) +{ + SIL_STATUS Status; + uint8_t FwVersion; + uint32_t Loop; + uint32_t Address; + uint8_t Value; + uint8_t BitMask; + + Status = SilDeviceError; + FwVersion = Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x1847A); + + Loop = 0; + Address = 0x28025; + BitMask = BIT_8(7); + + PROM_TRACEPOINT(SIL_TRACE_INFO, "Fw version: Major Version Year = 0x%x\n", FwVersion); + + if (FwVersion >= 0x24) { + Status = Prom21LoadFwDoneNew(PromDataBlk, XhciMmio); + } else { + do { + Value = Prom21XhciReadByteV2(PromDataBlk, XhciMmio, Address); + if (Value & BitMask) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Prom21CheckLoadFwStatus Ready (%x) @loop %d takes %d(ms)\n", + Value, Loop, (Loop * 2)); + Status = SilPass; + break; + } + SilFchStall(2 * 1000); + Loop++; + } while (Loop < 200); + } + + return Status; +} + +static uint64_t +GetProm21FwVersion ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint32_t XhciMmio + ) +{ + uint64_t PtFwVersionRam; + + PtFwVersionRam = ((uint64_t) Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x1847F)); + PtFwVersionRam |= ((uint64_t) Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x1847E)) << 8; + PtFwVersionRam |= ((uint64_t) Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x1847D)) << 16; + PtFwVersionRam |= ((uint64_t) Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x1847C)) << 24; + PtFwVersionRam |= ((uint64_t) Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x1847B)) << 32; + PtFwVersionRam |= ((uint64_t) Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x1847A)) << 40; + + PROM_TRACEPOINT(SIL_TRACE_INFO, " GetProm21FwVersion = 0x%016LX\n", PtFwVersionRam); + + return PtFwVersionRam; +} + +static bool +Prom21FwVersionMatch ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint32_t XhciMmio + ) +{ + uint64_t FwVersion; + + FwVersion = GetProm21FwVersion(PromDataBlk, XhciMmio); + + if (FwVersion == PromDataBlk->PromOutputBlk.PT21FwVersion) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Prom21 fw is the same\n"); + return true; + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Prom21 fw is NOT the same\n"); + return false; +} + +static uint8_t +Prom21RunsInRamCode ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint32_t XhciMmio + ) +{ + uint8_t CpuInRam; + uint8_t Value8; + + CpuInRam = 0; + + Value8 = Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x15041); + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT21 CPU runs in %s code\n", + (Value8 & BIT_8(0)) ? "RAM" : "ROM"); + + if (Value8 & BIT_8(0)) { + CpuInRam = 1; + } + + return CpuInRam; +} + +static void +Prom21SpecificFeatures ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciId, + uint32_t XhciMmio, + uint8_t PtCpuMode, + uint8_t BootMode, + bool IsPrimary + ) +{ + uint8_t Data8; + size_t Loop; + bool NeedUpdate; + + Loop = 0; + NeedUpdate = false; + + if (PtCpuMode == 1) { // in RAM code + if ((PromDataBlk->PT21SIProgEnable == 0x1) || + (PromDataBlk->PT21SataPortMdPort[0] != 0xf) || + (PromDataBlk->PT21SataPortMdPort[1] != 0xf) || + (PromDataBlk->PT21SataPortMdPort[2] != 0xf) || + (PromDataBlk->PT21SataPortMdPort[3] != 0xf) || + (PromDataBlk->PT21AhciMsiCap != 0xf) || + (PromDataBlk->PT21XhciPortGen[0] != 0xf) || (PromDataBlk->PT21XhciPortGen[1] != 0xf) || + (PromDataBlk->PT21XhciPortGen[2] != 0xf) || (PromDataBlk->PT21XhciPortGen[3] != 0xf) || + (PromDataBlk->PT21XhciPortGen[4] != 0xf) || (PromDataBlk->PT21XhciPortGen[5] != 0xf) || + (PromDataBlk->PT21Msi != 0xf) || + (PromDataBlk->PT21Msix != 0xf) || + (PromDataBlk->PT21Usb3GenSelect != 0xf) || + (PromDataBlk->PT21UsbPortLateDisable == 0x1) || + (PromDataBlk->PT21Usb3Port[0] != 0xf) || (PromDataBlk->PT21Usb3Port[1] != 0xf) || + (PromDataBlk->PT21Usb3Port[2] != 0xf) || (PromDataBlk->PT21Usb3Port[3] != 0xf) || + (PromDataBlk->PT21Usb3Port[4] != 0xf) || (PromDataBlk->PT21Usb3Port[5] != 0xf) || + (PromDataBlk->PT21Usb2Port[0] != 0xf) || (PromDataBlk->PT21Usb2Port[1] != 0xf) || + (PromDataBlk->PT21Usb2Port[2] != 0xf) || (PromDataBlk->PT21Usb2Port[3] != 0xf) || + (PromDataBlk->PT21Usb2Port[4] != 0xf) || (PromDataBlk->PT21Usb2Port[5] != 0xf) || + (PromDataBlk->PT21Usb2Port[6] != 0xf) || (PromDataBlk->PT21Usb2Port[7] != 0xf) || + (PromDataBlk->PT21Usb2Port[8] != 0xf) || (PromDataBlk->PT21Usb2Port[9] != 0xf) || + (PromDataBlk->PT21Usb2Port[10] != 0xf) || (PromDataBlk->PT21Usb2Port[11] != 0xf)) { + do { + Data8 = Prom21XhciReadByte(XhciMmio, 0x1E51D); + if (!(Data8 & BIT_8(3))) { + NeedUpdate = true; + break; + } + Loop ++; + SilFchStall(100 * 1000); + } while (Loop <= 100); + } + } + + if (PromDataBlk->PT21SIProgEnable == 0x1) { + Prom21SIConfig(PromDataBlk, XhciMmio); + } + + if (IsPrimary) { + if (PromDataBlk->PT21GpioPerstEnable == 0x1) { + Data8 = Prom21XhciReadByte(XhciMmio, 0x1C51F); + Data8 |= BIT_8(4); + Prom21XhciWriteByte(XhciMmio, 0x1C51F, Data8); + } + + if (PromDataBlk->PT21LtrSmallEnable == 0x1) { + Prom21XhciWriteDWord (XhciMmio, 0x1C520, 0x12345678); + Data8 = Prom21XhciReadByte(XhciMmio, 0x1C51F); + Data8 |= BIT_8(3); + Prom21XhciWriteByte(XhciMmio, 0x1C51F, Data8); + } + + if (PromDataBlk->PT21EqPreset != 0xf) { + if(PromDataBlk->PT21EqPreset <= 0x3) { + Data8 = Prom21XhciReadByte(XhciMmio, 0x1E51C); + Data8 &= (~0x3); + Data8 |= PromDataBlk->PT21EqPreset; + Prom21XhciWriteByte(XhciMmio, 0x1E51C, Data8); + } + } + } + + for (uint8_t PortNum = 0; PortNum < PROM21_NUM_SATA_PORTS; PortNum++) { + if (PromDataBlk->PT21SataPortMdPort[PortNum] != 0xf) { + Prom21AhciPortSataSpeed (XhciMmio, PortNum, PromDataBlk->PT21SataPortMdPort[PortNum]); + } + } + + if (PromDataBlk->PT21AhciMsiCap != 0xf) { + Prom21AhciMsiCap(XhciMmio, PromDataBlk->PT21AhciMsiCap); + } + + for (uint8_t PortNum = 0; PortNum < PROM21_XHCI_NUM_USB3_PORTS; PortNum++) { + if (PromDataBlk->PT21XhciPortGen[PortNum] != 0xf) { + Prom21XhciGen(XhciMmio, PromDataBlk->PT21XhciPortGen[PortNum], PortNum); + } + } + + if (PromDataBlk->PT21Msi != 0xf) { + if (PromDataBlk->PT21Msi != 0) { + Prom21XhciWriteByte(XhciMmio, 0x23834, 0x50); + } else { + Prom21XhciWriteByte(XhciMmio, 0x23834, 0x68); + } + } + + if (PromDataBlk->PT21Msix != 0xf) { + if (PromDataBlk->PT21Msix != 0) { + Prom21XhciWriteByte(XhciMmio, 0x23851, 0x68); + } else { + Prom21XhciWriteByte(XhciMmio, 0x23851, 0x78); + } + } + + Prom21UsbPortSetting(PromDataBlk, XhciId, XhciMmio, BootMode); + + if (NeedUpdate) { + Data8 = Prom21XhciReadByte(XhciMmio, 0x1E51D); + Data8 |= BIT_8(2); + Prom21XhciWriteByte(XhciMmio, 0x1E51D, Data8); + } +} + +static SIL_STATUS +LpPtXhciProceedFwLoad ( + PROMCLASS_DATA_BLK *PromDataBlk, + uint8_t *PtFwInRamPtr, + uint16_t XhciBus, + uint8_t XhciDev, + uint8_t XhciFun, + uint32_t XhciMmio, + bool LoadStatusCheck + ) +{ + uint8_t DSResult; + uint8_t Parameter; + uint8_t Data8; + uint16_t wPrg_Addr; + uint32_t Data32; + uint32_t UsbCmd; + uint32_t Address; + uint32_t Counter; + uint32_t FirstCounter; + uint32_t LoadCounter; + SIL_STATUS Status; + + if (PromDataBlk->PromInputBlk.PT21DbgLoadFw == 1) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Using on-board PT21 fw\n"); + return SilPass; + } + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "PtFwInRamPtr 0x%08X, [%04X:%02X:%02X], XhciMmio 0x%08X\n", + PtFwInRamPtr, XhciBus, XhciDev, XhciFun, XhciMmio); + + + if (PromDataBlk->PromInputBlk.PT21TogglePerst == 0) { + Data8 = Prom21XhciReadByte(XhciMmio, 0x1E51C); + Data8 |= BIT_8(4); + Prom21XhciWriteByte(XhciMmio, 0x1E51C, Data8); + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Program Digital Signature Parameter 1 Offset 0x%08X = 0x%X\n", + PtFwInRamPtr + 0x20002, *(PtFwInRamPtr + 0x20002)); + Parameter = Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x15180); + Parameter &= 0x0F; + Parameter |= ((*(PtFwInRamPtr + 0x20002) & 0x3C) << 2); + Prom21XhciWriteByte(XhciMmio, 0x15180, Parameter); + + Address = PCI_LIB_ADDRESS(XhciBus, XhciDev, XhciFun, 0xE2); + LoadCounter = 0; + do { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Loading PT FW Starts LoadCounter = %d !!!\n", + LoadCounter); + + FirstCounter = 0; + do { + Parameter = Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x15040); + Parameter &= 0xFC; + Parameter |= 0x02; + Prom21XhciWriteByte(XhciMmio, 0x15040, Parameter); + + // Reset CPU + Parameter = Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x15042); + Parameter &= 0xFE; + Parameter |= 0x01; + Prom21XhciWriteByte(XhciMmio, 0x15042, Parameter); + + Counter = 0; + do { + UsbCmd = xUSLMemRead32((void *)(size_t)(XhciMmio + 0x20)); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Usb Status (Before) = 0x%X Counter = %d\n", + UsbCmd, Counter); + if (UsbCmd & BIT_32(1)) { + SilFchStall(2 * 1000); // Delay 2ms + } + Counter++; + } while ((UsbCmd & BIT_32(1)) && (Counter < 100)); + + Parameter = Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x15041); + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT CPU runs in %s code\n", + (Parameter & BIT_8(0)) ? "RAM" : "ROM"); + + FirstCounter++; + } while (((UsbCmd & BIT_32(1)) || (Parameter & BIT_8(0))) && (FirstCounter < 10)); + + + if (FirstCounter == 10) { + Counter = 1; + LoadCounter = 10; + } else { + Data32 = 0x2001F; + Data32 += (uint32_t) ((*(PtFwInRamPtr + 0x20001) & 0x7E) >> 1); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set Digital Signature Parameter 2 Offset 0x%08X = 0x%X -> Address = 0x%08X\n", + PtFwInRamPtr + 0x20001, *(PtFwInRamPtr + 0x20001), Data32); + for (Counter = 0; Counter < 32; Counter++) { + Prom21XhciWriteByte(XhciMmio, 0x15140 + Counter, *(PtFwInRamPtr + Data32 - Counter)); + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Write the first 64K FW data to RAM\n"); + xUSLPciWrite16(Address, 0); + while (xUSLPciRead16(Address) != 0) {} + + for (Counter = 0; Counter <= 0x3FFF ; Counter++) { + wPrg_Addr = (uint16_t) (Counter << 1); + + Data32 = *(PtFwInRamPtr + wPrg_Addr + 0); + Data32 |= *(PtFwInRamPtr + wPrg_Addr + 1) << 8; + Data32 |= *(PtFwInRamPtr + wPrg_Addr + 0x8000) << 16; + Data32 |= *(PtFwInRamPtr + wPrg_Addr + 0x8001) << 24; + xUSLMemWrite32((void *)(size_t)(XhciMmio + 0x3010), Data32); + while (xUSLPciRead16(Address) == wPrg_Addr) {} + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Write the second 64K FW data to RAM\n"); + xUSLPciWrite16(Address, 0x8000); + while (xUSLPciRead16(Address) != 0x8000) {} + + for (Counter = 0x4000; Counter <= 0x7FFF; Counter++) { + wPrg_Addr = (uint16_t) (Counter << 1); + + Data32 = *(PtFwInRamPtr + wPrg_Addr + 0x08000); + Data32 |= *(PtFwInRamPtr + wPrg_Addr + 0x08001) << 8; + Data32 |= *(PtFwInRamPtr + wPrg_Addr + 0x10000) << 16; + Data32 |= *(PtFwInRamPtr + wPrg_Addr + 0x10001) << 24; + xUSLMemWrite32((void *)(size_t)(XhciMmio + 0x3010), Data32); + while (xUSLPciRead16(Address) == wPrg_Addr) {} + } + + Counter = 0; + do { + DSResult = Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x1A51C); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Digital Signature Verification Result = %s\n", + (DSResult & BIT_8(5)) ? "Success" : "Fail"); + + UsbCmd = xUSLMemRead32((void *)(size_t)(XhciMmio + 0x20)); + PROM_TRACEPOINT(SIL_TRACE_INFO, " UsbCmd (After) = 0x%X Counter = %d\n", + UsbCmd, Counter); + SilFchStall(2 * 1000); + + Parameter = Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x15041); + PROM_TRACEPOINT(SIL_TRACE_INFO, " CPU runs in %s code\n", + (Parameter & BIT_8(0)) ? "RAM" : "ROM"); + + Counter++; + } while (((UsbCmd & BIT_32(1)) || ((Parameter & BIT_8(0)) == 0) || + ((DSResult & BIT_8(5)) == 0)) && (Counter < 500)); + LoadCounter++; + } + } while ((Counter == 10) && (LoadCounter < 10)); + + + if ((Counter == 10) && (LoadCounter == 10)) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Loading PT FW Fail !!!\n"); + Status = SilUnsupported; + } else { + if (PromDataBlk->PromInputBlk.PT21SecondPortNumber != 0xE) { + if (LoadStatusCheck) { + Status = Prom21CheckLoadFwStatus(PromDataBlk, XhciMmio); + } else { + SilFchStall(200 * 1000); + Status = SilPass; + } + } else { + if (PromDataBlk->PromInputBlk.PT21DelayAfterFWLoading == 0x1) { + SilFchStall(200 * 1000); + } + Status = Prom21CheckLoadFwStatus (PromDataBlk, XhciMmio); + } + PROM_TRACEPOINT(SIL_TRACE_INFO, " Loading PT FW Done. Status: %x !!!\n", Status); + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); + return Status; +} + +typedef struct { + uint32_t OperationCode; + uint32_t AvailableMemoryAddress; + uint32_t AvailableMemorySize; +} LOAD_FW_CONFIG_DATA; + +typedef struct { + uint32_t TotalSize; + uint32_t Status; +} MBOX_BUFFER_HEADER; + +typedef struct { + MBOX_BUFFER_HEADER Header; + LOAD_FW_CONFIG_DATA LoadFwConfigData; +} MBOX_LOAD_FW_CONFIG_BUFFER; + +static SIL_STATUS +PspMboxBiosCmdLoadFwConfig ( + LOAD_FW_CONFIG_DATA * FwConfigBuf + ) +{ + return SilNotFound; +} + +SIL_STATUS +AmdProm21FwLoad ( + SIL_CONTEXT *SilContext, + PROMCLASS_DATA_BLK *PromDataBlk + ) +{ + uint16_t GppBus; + uint8_t GppDev; + uint8_t GppFun; + uint16_t SecGppBus; + uint8_t SecGppDev; + uint8_t SecGppFun; + uint16_t UspBus; + uint16_t DspBus; + uint8_t CurrentSpeed; + uint8_t SecCurrentSpeed; + uint8_t XhciLock; + uint8_t PtCpuMode; + uint8_t PTTargetSpeed; + uint8_t SecPortNum; + uint8_t CapBase; + uint8_t *PtFwInRamPtr; + uint32_t PTFwSize; + uint32_t PtFwChecksum; + uint32_t Checksum; + uint32_t XhciMmio; + uint32_t SecXhciMmio; + uint32_t GppPcieAddress; + uint32_t SecGppPcieAddress; + uint32_t Counter; + uint32_t UsbCmd; + uint64_t FwVersion; + SIL_STATUS Status; + LOAD_FW_CONFIG_DATA FwConfigBuf; + PROM_PCI_SAVE_RESTORE_TABLE PtPciTable[2]; + MPIO_COMMON_2_REV_XFER_BLOCK *MpioXferTable; + NORTH_BRIDGE_PCIE_SIB *NbPcieData; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + if (SilGetCommon2RevXferTable(SilContext, SilId_MpioClass, (void **)(&MpioXferTable)) != SilPass) { + return SilNotFound; + } + + NbPcieData = (NORTH_BRIDGE_PCIE_SIB *)xUslFindStructure(SilContext, + SilId_NbioClass, + NBIOPCIECLASS_INSTANCE); + if (NbPcieData == NULL) { + MPIO_TRACEPOINT(SIL_TRACE_ERROR, " NBIO Pcie config not found.\n"); + return SilNotFound; + } + + SecPortNum = 0; + PtCpuMode = 0; + PtFwInRamPtr = (uint8_t *)(uintptr_t)PromDataBlk->PromInputBlk.PT21FwInRamAddress; + + { + PROM_TRACEPOINT(SIL_TRACE_INFO, " BootMode != BOOT_ON_S3_RESUME, copy PT FW from Rom to Ram !!!\n"); + + if (PromDataBlk->PromInputBlk.PT21FWLoading == 1) { + if (PromDataBlk->PromInputBlk.PT21FwInRamAddress == 0) { + PROM_TRACEPOINT(SIL_TRACE_ERROR, "PT21FWLoading = 1 and PT21FwInRamAddress not provided\n"); + return SilUnsupported; + } + FwConfigBuf.OperationCode = 0x01; + FwConfigBuf.AvailableMemoryAddress = PromDataBlk->PromInputBlk.PT21FwInRamAddress; + FwConfigBuf.AvailableMemorySize = (128 + 4) * 1024; + Status = PspMboxBiosCmdLoadFwConfig(&FwConfigBuf); + if (Status != SilPass) { + PROM_TRACEPOINT(SIL_TRACE_ERROR, "Get PT FW from PSP Directory FAIL !!!\n"); + return Status; + } + } else { + if (PromDataBlk->PromInputBlk.PT21FwInRamAddress == 0) { + PROM_TRACEPOINT(SIL_TRACE_ERROR, "PT21FWLoading = 0 unsupported and PT21FwInRamAddress not provided\n"); + return SilUnsupported; + } + } + } + + PtFwInRamPtr = (uint8_t *)(uintptr_t)PromDataBlk->PromInputBlk.PT21FwInRamAddress; + PTFwSize = ((uint32_t) *(PtFwInRamPtr + 0x07)) << 24; + PTFwSize |= ((uint32_t) *(PtFwInRamPtr + 0x06)) << 16; + PTFwSize |= ((uint32_t) *(PtFwInRamPtr + 0x05)) << 8; + PTFwSize |= ((uint32_t) *(PtFwInRamPtr + 0x04)) << 0; + + PtFwChecksum = ((uint32_t) *(PtFwInRamPtr + 0x0B)) << 24; + PtFwChecksum |= ((uint32_t) *(PtFwInRamPtr + 0x0A)) << 16; + PtFwChecksum |= ((uint32_t) *(PtFwInRamPtr + 0x09)) << 8; + PtFwChecksum |= ((uint32_t) *(PtFwInRamPtr + 0x08)) << 0; + + Checksum = FwChecksum(PtFwInRamPtr, PTFwSize); + + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT FW Ram Address = 0x%08X\n", PtFwInRamPtr); + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT FW Size = 0x%08X\n", PTFwSize); + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT FW Checksum = 0x%08X\n", PtFwChecksum); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Checksum Calculation = 0x%08X\n", Checksum); + + if (PtFwChecksum != Checksum) { + PROM_TRACEPOINT(SIL_TRACE_ERROR, "ERROR: PT FW Checksum ERROR !!!\n"); + return SilUnsupported; + } + + FwVersion = ((uint64_t)*(PtFwInRamPtr + 0x8C)) << 40; + FwVersion |= ((uint64_t)*(PtFwInRamPtr + 0x8D)) << 32; + FwVersion |= ((uint64_t)*(PtFwInRamPtr + 0x8E)) << 24; + FwVersion |= ((uint64_t)*(PtFwInRamPtr + 0x8F)) << 16; + FwVersion |= ((uint64_t)*(PtFwInRamPtr + 0x90)) << 8; + FwVersion |= ((uint64_t)*(PtFwInRamPtr + 0x91)) << 0; + PromDataBlk->PromOutputBlk.PT21FwVersion = FwVersion; + PROM_TRACEPOINT(SIL_TRACE_INFO, " Promontory FwVersion = 0x%016LX ()\n", FwVersion); + + GppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[0]; + GppBus = (uint16_t) ((GppPcieAddress >> 20) & 0xFFF); + GppDev = (uint8_t) ((GppPcieAddress >> 15) & 0x1F); + GppFun = (uint8_t) ((GppPcieAddress >> 12) & 0x07); + + XhciMmio = PromDataBlk->PromOutputBlk.PT21XhciMmio[0]; + if ((XhciMmio == 0x0) || (XhciMmio == 0xffffffff)) { + return SilNotFound; + } + + SaveInitPromBus(PromDataBlk, PtPciTable, 0x00BB); + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Check USB status before read PT\n"); + Counter = 0; + do { + UsbCmd = xUSLMemRead32((void *)(size_t)(XhciMmio + 0x20)); + PROM_TRACEPOINT(SIL_TRACE_INFO, " UsbCmd = 0x%X Counter = %d\n", UsbCmd, Counter); + if (UsbCmd & BIT_32(1)) { + SilFchStall(2 * 1000); + } + Counter++; + } while ((UsbCmd & BIT_32(1)) && (Counter < 100)); + + XhciLock = Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x15087); + if ((XhciLock & BIT_8(4)) == 0) { + PromDataBlk->PromOutputBlk.PT21XhciLock[0] = 1; + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set PcdPT21XhciLock = %d\n", + PromDataBlk->PromOutputBlk.PT21XhciLock[0]); + } + + if (XhciLock & BIT_8(4)) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " XHCI is unlocked\n"); + + CurrentSpeed = xUSLPciRead8(GppPcieAddress + 0x6A); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Before set PT speed GEN1: current speed x%d Gen%d\n", + CurrentSpeed >> 4, CurrentSpeed & 0xF); + if ((CurrentSpeed & 0x0F) != PcieGen1) { + MpioXferTable->MpioPcieSetSpeed(SilContext, + &NbPcieData->PciePlatformConfig, + GppDev, + GppFun, + PcieGen1); + do { + CurrentSpeed = xUSLPciRead8(GppPcieAddress + 0x6B); + } while ((CurrentSpeed & (BIT_8(5) + BIT_8(3))) != BIT_8(5)); + + CurrentSpeed = xUSLPciRead8(GppPcieAddress + 0x6A); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set PT speed to x%d Gen%d\n", + CurrentSpeed >> 4, CurrentSpeed & 0xF); + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT speed is Gen1 already\n"); + } + + PtCpuMode = Prom21RunsInRamCode(PromDataBlk, XhciMmio); + Prom21DspLaneConfig(&PromDataBlk->PromInputBlk.Primary, XhciMmio); + Prom21SpecificFeatures(&PromDataBlk->PromInputBlk.Primary, + PromDataBlk->PromOutputBlk.PT21XhciID[0], + XhciMmio, + PtCpuMode, + PromDataBlk->PromInputBlk.BootMode, + true + ); + + + if ((PtCpuMode == 0) || !Prom21FwVersionMatch(PromDataBlk, XhciMmio)) { + Status = LpPtXhciProceedFwLoad(PromDataBlk, + PtFwInRamPtr + 0x0C, + PtPciTable[0].PromBus + 2, 0, 0, + XhciMmio, + false + ); + if (Status == SilPass) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT load FW success\n"); + } + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT Runs in RAM code, not load fw\n"); + } + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " XHCI is lock: bypass PT code !!!\n"); + } + + CapBase = xUSLPciLibFindPciCapability(GppPcieAddress, PCIE_CAP_ID); + if ((CapBase == 0) || (CapBase == 0xff)) { + PROM_TRACEPOINT(SIL_TRACE_ERROR, " PT PCIe capability not found!\n"); + return SilNotFound; + } + + CurrentSpeed = xUSLPciRead8(GppPcieAddress + CapBase + 0x12); + PROM_TRACEPOINT(SIL_TRACE_INFO, " After 1st fw loading: Current Speed x%d Gen%d\n", + CurrentSpeed >> 4, CurrentSpeed & 0xF); + + PTTargetSpeed = PromDataBlk->PromInputBlk.PT21PcieTargetSpeed; + if ((CurrentSpeed & 0xF) != PTTargetSpeed) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set PT Target Link Speed to Gen%d\n", PTTargetSpeed); + MpioXferTable->MpioPcieSetSpeed(SilContext, + &NbPcieData->PciePlatformConfig, + GppDev, + GppFun, + PTTargetSpeed); + do { + CurrentSpeed = xUSLPciRead8(GppPcieAddress + 0x6B); + } while ((CurrentSpeed & (BIT_8(5) + BIT_8(3))) != BIT_8(5)); + CurrentSpeed = xUSLPciRead8(GppPcieAddress + 0x6A); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Current Speed is 0x%x x%d Gen%d\n", + CurrentSpeed, CurrentSpeed >> 4, CurrentSpeed & 0xF); + + if ((CurrentSpeed & 0xF) != PTTargetSpeed) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " MPIO service failed, current speed is Gen%d\n", + (CurrentSpeed & 0xF)); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set PT Target Link Speed to Gen%d\n", PTTargetSpeed); + Prom21RetrainSpeed(PromDataBlk, GppBus, GppDev, GppFun, 0, PTTargetSpeed, false); + } + } + + if(PromDataBlk->PromInputBlk.PT21SecondPortNumber == 0xf) { + SecPortNum = 0x8; + } else { + SecPortNum = PromDataBlk->PromInputBlk.PT21SecondPortNumber; + } + + if (PromDataBlk->PromInputBlk.PT21SecondPortNumber != 0xE) { + UspBus = xUSLPciRead8(GppPcieAddress + 0x19); + DspBus = xUSLPciRead8(PCI_LIB_ADDRESS(UspBus, 0, 0, 0x19)); + + if (PromDataBlk->PromInputBlk.PT21TogglePerst == 0x1) { + Status = Prom21RetrainSpeed(PromDataBlk, DspBus, SecPortNum, 0, XhciMmio, 0x1, true); + } else { + Status = Prom21RetrainSpeed(PromDataBlk, DspBus, SecPortNum, 0, 0, 0x1, true); + } + + if (Status == SilPass) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT UspBus = 0x%x DspBus = 0x%x, Port %x \n", + UspBus, DspBus, SecPortNum); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Check USB status before scan second PT\n"); + Counter = 0; + do { + UsbCmd = xUSLMemRead32((void *)(size_t)(XhciMmio + 0x20)); + PROM_TRACEPOINT(SIL_TRACE_INFO, " UsbCmd = 0x%X Counter = %d\n", UsbCmd, Counter); + if (UsbCmd & BIT_32(1)) { + SilFchStall(2 * 1000); + } + Counter++; + } while ((UsbCmd & BIT_32(1)) && (Counter < 100)); + + ScanSecXhciDidVid(PromDataBlk, + PtPciTable[0].PromBus + 1, + SecPortNum, + 0, + PtPciTable[0].PromBus + 4 + ); + + if (PromDataBlk->PromOutputBlk.PT21GppPcieAddress[1]) { + RestorePromBus(PromDataBlk, PtPciTable, 0x00BB); + + SecGppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[1]; + + SecGppBus = (uint16_t)((SecGppPcieAddress >> 20) & 0xFFF); + SecGppDev = (uint8_t)((SecGppPcieAddress >> 15) & 0x1F); + SecGppFun = (uint8_t)((SecGppPcieAddress >> 12) & 0x07); + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Secondary PT is at 0x%x - B%d D% F%d\n", + SecGppPcieAddress, SecGppBus, SecGppDev, SecGppFun); + + if (PromDataBlk->PromInputBlk.PT21Revision >= 2) { + SaveInitPromBus(PromDataBlk, PtPciTable, 0xBBBB); + } + + SecXhciMmio = PromDataBlk->PromOutputBlk.PT21XhciMmio[1]; + if ((SecXhciMmio == 0x0) || (SecXhciMmio == 0xffffffff)) { + if (PromDataBlk->PromInputBlk.PT21Revision >= 2) { + RestorePromBus(PromDataBlk, PtPciTable, 0xBBBB); + } + return SilNotFound; + } + + if (PromDataBlk->PromInputBlk.PT21Revision < 2) { + SaveInitPromBus(PromDataBlk, PtPciTable, 0xBBBB); + } + + XhciLock = Prom21XhciReadByteV2(PromDataBlk, SecXhciMmio, 0x15087); + if ((XhciLock & BIT_8(4)) == 0) { + PromDataBlk->PromOutputBlk.PT21XhciLock[1] = 1; + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set SecPT21XhciLock = %d\n", + PromDataBlk->PromOutputBlk.PT21XhciLock[1]); + } + + if ((Status == SilPass) && (XhciLock & BIT_8(4))) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Secondary PT XHCI is unlock\n"); + + PtCpuMode = Prom21RunsInRamCode(PromDataBlk, SecXhciMmio); + Prom21DspLaneConfig(&PromDataBlk->PromInputBlk.Secondary, SecXhciMmio); + Prom21SpecificFeatures(&PromDataBlk->PromInputBlk.Secondary, + PromDataBlk->PromOutputBlk.PT21XhciID[1], + SecXhciMmio, + PtCpuMode, + PromDataBlk->PromInputBlk.BootMode, + false + ); + + if ((PtCpuMode == 0) || !Prom21FwVersionMatch(PromDataBlk, SecXhciMmio)) { + Status = LpPtXhciProceedFwLoad (PromDataBlk, + PtFwInRamPtr + 0x0C, + PtPciTable[0].PromBus + 6, 0, 0, + SecXhciMmio, + true + ); + + if (Status == SilPass) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " 2nd PT load FW success\n"); + } + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " 2nd PT runs in RAM code, not load fw\n"); + } + Prom21RetrainSpeed(PromDataBlk, + SecGppBus, + SecGppDev, + SecGppFun, + 0, + PromDataBlk->PromInputBlk.PT21PcieTargetSpeed, + false + ); + + SecCurrentSpeed = xUSLPciRead8(SecGppPcieAddress + 0x92); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Secondary PT USP PCIe Link Width & Link Speed is x%d Gen%d\n", + SecCurrentSpeed >> 4, SecCurrentSpeed & 0xF); + if ((SecCurrentSpeed & 0x0F) == (PromDataBlk->PromInputBlk.PT21PcieTargetSpeed & 0x0F)) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Restore Secondary PT DSP speed to Gen%d Success !!!\n", + SecCurrentSpeed & 0x0F); + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Restore Secondary PT DSP speed to Gen%d Fail !!! It's Gen%d now\n", + PromDataBlk->PromInputBlk.PT21PcieTargetSpeed & 0x0F, SecCurrentSpeed & 0x0F); + } + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Secondary PT XHCI is lock: bypass PT code !!!\n"); + } + + Prom21RetrainSpeed(PromDataBlk, + DspBus, + SecPortNum, + 0, + 0, + PromDataBlk->PromInputBlk.PT21PcieTargetSpeed, + false + ); + RestorePromBus(PromDataBlk, PtPciTable, 0xBBBB); + } else { + Prom21RetrainSpeed(PromDataBlk, + DspBus, + SecPortNum, + 0, + 0, + PromDataBlk->PromInputBlk.PT21PcieTargetSpeed, + false + ); + RestorePromBus(PromDataBlk, PtPciTable, 0x00BB); + } + } else { + RestorePromBus(PromDataBlk, PtPciTable, 0x00BB); + Status = SilPass; + } + } else { + RestorePromBus(PromDataBlk, PtPciTable, 0x00BB); + Status = SilPass; + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); + + return Status; +} + +static uint8_t +FindPcieRootPortNumber ( + uint16_t RootBridge, + uint8_t RootPortDevice, + uint8_t RootPortFunction + ) +{ + uint32_t Ioapic0CfgAddress; + uint32_t RootPortAddress; + uint8_t Counter; + + Ioapic0CfgAddress = 0x14301000ul; + RootPortAddress = ((uint32_t) (RootPortDevice & 0x1F) << 3) + (uint32_t) (RootPortFunction & 0x7); + + for (Counter = 0; Counter < 24; Counter++) { + if (RootPortAddress == xUSLSmnRead(0, 0, Ioapic0CfgAddress + (uint32_t) Counter * 4)) { + break; + } + } + + return Counter; +} + +static uint32_t +FindPcieRegisterAddress ( + uint16_t RootBridge, + uint8_t RootPortDevice, + uint8_t RootPortFunction, + uint8_t RegisterSelection + ) +{ + uint32_t RootPortNumber; + uint32_t RcCfgAddress; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, " (0x%04X, 0x%02X, 0x%02X, 0x%02X)\n", + RootBridge, RootPortDevice, RootPortFunction, RegisterSelection); + + if (!SocFamilyIdCheck(AMD_FAMILY_PHX)) { + return 0; + } + + RootPortNumber = (uint32_t) FindPcieRootPortNumber (RootBridge, RootPortDevice, RootPortFunction); + PROM_TRACEPOINT(SIL_TRACE_INFO, " PCIe Root Port Number = %d\n", RootPortNumber); + + RcCfgAddress = 0x11100000ul; + + if (RootPortNumber < 5) { + RcCfgAddress += (RegisterSelection << 16) + (RootPortNumber << 12); + } else if (RootPortNumber < 11) { + RcCfgAddress += (1 << 20) + (RegisterSelection << 16) + ((RootPortNumber - 5) << 12); + } else if (RootPortNumber == 11) { + RcCfgAddress += (2 << 20) + (RegisterSelection << 16); + } else if (RootPortNumber == 12) { + RcCfgAddress += (3 << 20) + (RegisterSelection << 16); + } + + if (RegisterSelection == 0x8) { + RcCfgAddress &= 0xFFFF0FFF; + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, " PCIe Register Address = 0x%08X\n", RcCfgAddress); + return RcCfgAddress; +} + +SIL_STATUS +AmdProm21FwLoadA1 ( + SIL_CONTEXT *SilContext, + PROMCLASS_DATA_BLK *PromDataBlk + ) +{ + uint16_t GppBus; + uint8_t GppDev; + uint8_t GppFun; + uint16_t SecGppBus; + uint8_t SecGppDev; + uint8_t SecGppFun; + uint16_t UspBus; + uint16_t DspBus; + uint8_t CurrentSpeed; + uint8_t SecCurrentSpeed; + uint8_t XhciLock; + uint8_t PTTargetSpeed; + uint8_t SecTargetSpeed; + uint8_t DspTargetSpeed; + uint8_t SecPortNum; + uint8_t *PtFwInRamPtr; + uint32_t PTFwSize; + uint32_t PtFwChecksum; + uint32_t Checksum; + uint32_t XhciMmio; + uint32_t SecXhciMmio; + uint32_t GppPcieAddress; + uint32_t SecGppPcieAddress; + uint32_t Counter; + uint32_t LcResetLinkAddress; + uint32_t UsbCmd; + uint32_t Value; + SIL_STATUS Status; + LOAD_FW_CONFIG_DATA FwConfigBuf; + PROM_PCI_SAVE_RESTORE_TABLE PtPciTable[2]; + MPIO_COMMON_2_REV_XFER_BLOCK *MpioXferTable; + NORTH_BRIDGE_PCIE_SIB *NbPcieData; + PROM21_FW_VERSION FwVersion; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + if (SilGetCommon2RevXferTable(SilContext, SilId_MpioClass, (void **)(&MpioXferTable)) != SilPass) { + return SilNotFound; + } + + NbPcieData = (NORTH_BRIDGE_PCIE_SIB *)xUslFindStructure(SilContext, + SilId_NbioClass, + NBIOPCIECLASS_INSTANCE); + if (NbPcieData == NULL) { + MPIO_TRACEPOINT(SIL_TRACE_ERROR, " NBIO Pcie config not found.\n"); + return SilNotFound; + } + + SecPortNum = 0; + DspBus = 0; + PtFwInRamPtr = (uint8_t *)(uintptr_t)PromDataBlk->PromInputBlk.PT21FwInRamAddress; + + { + PROM_TRACEPOINT(SIL_TRACE_INFO, " BootMode != BOOT_ON_S3_RESUME, copy PT FW from Rom to Ram !!!\n"); + + if (PromDataBlk->PromInputBlk.PT21FWLoading == 1) { + FwConfigBuf.OperationCode = 0x01; + FwConfigBuf.AvailableMemoryAddress = PromDataBlk->PromInputBlk.PT21FwInRamAddress; + FwConfigBuf.AvailableMemorySize = (128 + 4) * 1024; + Status = PspMboxBiosCmdLoadFwConfig(&FwConfigBuf); + if (Status != SilPass) { + PROM_TRACEPOINT(SIL_TRACE_ERROR, "Get PT FW from PSP Directory FAIL !!!\n"); + return Status; + } + } else { + PROM_TRACEPOINT(SIL_TRACE_ERROR, "PT21FWLoading = 0 unsupported\n"); + return SilUnsupported; + } + } + + PtFwInRamPtr = (uint8_t *)(uintptr_t)PromDataBlk->PromInputBlk.PT21FwInRamAddress; + PTFwSize = ((uint32_t) *(PtFwInRamPtr + 0x07)) << 24; + PTFwSize |= ((uint32_t) *(PtFwInRamPtr + 0x06)) << 16; + PTFwSize |= ((uint32_t) *(PtFwInRamPtr + 0x05)) << 8; + PTFwSize |= ((uint32_t) *(PtFwInRamPtr + 0x04)) << 0; + + PtFwChecksum = ((uint32_t) *(PtFwInRamPtr + 0x0B)) << 24; + PtFwChecksum |= ((uint32_t) *(PtFwInRamPtr + 0x0A)) << 16; + PtFwChecksum |= ((uint32_t) *(PtFwInRamPtr + 0x09)) << 8; + PtFwChecksum |= ((uint32_t) *(PtFwInRamPtr + 0x08)) << 0; + + Checksum = FwChecksum(PtFwInRamPtr, PTFwSize); + + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT FW Ram Address = 0x%08X\n", PtFwInRamPtr); + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT FW Size = 0x%08X\n", PTFwSize); + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT FW Checksum = 0x%08X\n", PtFwChecksum); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Checksum Calculation = 0x%08X\n", Checksum); + + if (PtFwChecksum != Checksum) { + PROM_TRACEPOINT(SIL_TRACE_ERROR, "ERROR: PT FW Checksum ERROR !!!\n"); + return SilUnsupported; + } + + FwVersion.Raw = ((uint64_t)*(PtFwInRamPtr + 0x8C)) << 40; + FwVersion.Raw |= ((uint64_t)*(PtFwInRamPtr + 0x8D)) << 32; + FwVersion.Raw |= ((uint64_t)*(PtFwInRamPtr + 0x8E)) << 24; + FwVersion.Raw |= ((uint64_t)*(PtFwInRamPtr + 0x8F)) << 16; + FwVersion.Raw |= ((uint64_t)*(PtFwInRamPtr + 0x90)) << 8; + FwVersion.Raw |= ((uint64_t)*(PtFwInRamPtr + 0x91)) << 0; + PromDataBlk->PromOutputBlk.PT21FwVersion = FwVersion.Raw; + PROM_TRACEPOINT(SIL_TRACE_INFO, " Promontory FwVersion = 0x%016LX (%u%u%u%u%u%u_%02x.%02x.%02x)\n", + FwVersion.Raw, + FwVersion.Fields.Year >> 4 & 0xf, FwVersion.Fields.Year & 0xf, + FwVersion.Fields.Month >> 4 & 0xf, FwVersion.Fields.Month & 0xf, + FwVersion.Fields.Day >> 4 & 0xf, FwVersion.Fields.Day & 0xf, + FwVersion.Fields.SubVersion[2], FwVersion.Fields.SubVersion[1], + FwVersion.Fields.SubVersion[0] + ); + + GppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[0]; + SecGppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[1]; + + GppBus = (uint16_t) ((GppPcieAddress >> 20) & 0xFFF); + GppDev = (uint8_t) ((GppPcieAddress >> 15) & 0x1F); + GppFun = (uint8_t) ((GppPcieAddress >> 12) & 0x07); + + XhciMmio = PromDataBlk->PromOutputBlk.PT21XhciMmio[0]; + if ((XhciMmio == 0x0) || (XhciMmio == 0xffffffff)) { + return SilNotFound; + } + + SaveInitPromBus(PromDataBlk, PtPciTable, 0x00BB); + + XhciLock = Prom21XhciReadByteV2(PromDataBlk, XhciMmio, 0x15087); + if ((XhciLock & BIT_8(4)) == 0) { + PromDataBlk->PromOutputBlk.PT21XhciLock[0] = 1; + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set PcdPT21XhciLock = %d\n", + PromDataBlk->PromOutputBlk.PT21XhciLock[0]); + } + + if (XhciLock & BIT_8(4)) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " XHCI is unlocked\n"); + + CurrentSpeed = xUSLPciRead8(GppPcieAddress + 0x6A); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Before set PT speed GEN1: current speed x%d Gen%d\n", + CurrentSpeed >> 4, CurrentSpeed & 0xF); + if ((CurrentSpeed & 0x0F) != PcieGen1) { + MpioXferTable->MpioPcieSetSpeed(SilContext, + &NbPcieData->PciePlatformConfig, + GppDev, + GppFun, + PcieGen1); + do { + CurrentSpeed = xUSLPciRead8(GppPcieAddress + 0x6B); + } while ((CurrentSpeed & (BIT_8(5) + BIT_8(3))) != BIT_8(5)); + + CurrentSpeed = xUSLPciRead8(GppPcieAddress + 0x6A); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set PT speed to x%d Gen%d\n", + CurrentSpeed >> 4, CurrentSpeed & 0xF); + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT speed is Gen1 already\n"); + } + + Status = LpPtXhciProceedFwLoad(PromDataBlk, + PtFwInRamPtr + 0x0C, + PtPciTable[0].PromBus + 2, 0, 0, + XhciMmio, + false + ); + if (Status == SilPass) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT load FW success\n"); + } + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " XHCI is lock: bypass PT code !!!\n"); + } + + RestorePromBus(PromDataBlk, PtPciTable, 0x00BB); + + CurrentSpeed = xUSLPciRead8(GppPcieAddress + 0x6A); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Before set DSP port to GEN1 for 2nd PT: Current Speed x%d Gen%d\n", + CurrentSpeed >> 4, CurrentSpeed & 0xF); + + if(PromDataBlk->PromInputBlk.PT21SecondPortNumber == 0xf) { + SecPortNum = 0x8; + } else { + SecPortNum = PromDataBlk->PromInputBlk.PT21SecondPortNumber; + } + + // force DSP port 0 and port 8 to GEN1 for loading Secondary PROM21 + if ((SecGppPcieAddress == 0) && (PromDataBlk->PromInputBlk.PT21SecondPortNumber != 0xE)) { + SaveInitPromBus (PromDataBlk, PtPciTable, 0x00BB); + if (PromDataBlk->PromInputBlk.PT21RuninRam == 0x0) { + UspBus = (uint16_t)xUSLPciRead8(GppPcieAddress + 0x19) | (GppBus & 0xFF00); + DspBus = (uint16_t)xUSLPciRead8(PCI_LIB_ADDRESS(UspBus, 0, 0, 0x19)) | (UspBus & 0xFF00); + + DspTargetSpeed = xUSLPciRead8(PCI_LIB_ADDRESS(DspBus, SecPortNum, 0, 0xB0)); + DspTargetSpeed &= 0xF0; + DspTargetSpeed |= 0x1; + xUSLPciWrite8(PCI_LIB_ADDRESS(DspBus, SecPortNum, 0, 0xB0), DspTargetSpeed); + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT UspBus = 0x%x DspBus = 0x%x, Port %x DspTargetSpeed = 0x%x\n", + UspBus, DspBus, SecPortNum, DspTargetSpeed); + } + } + + // Link down WA + LcResetLinkAddress = FindPcieRegisterAddress(GppBus, GppDev, GppFun, 4) + 0x280; + if (LcResetLinkAddress == 0) { + if ((SecGppPcieAddress == 0) && (PromDataBlk->PromInputBlk.PT21SecondPortNumber != 0xE)) { + RestorePromBus (PromDataBlk, PtPciTable, 0x00BB); + } + PROM_TRACEPOINT(SIL_TRACE_ERROR, " PT USP PCIe LC_RESET_LINK SMN Address not found!\n"); + return SilNotFound; + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, " PT USP PCIe LC_RESET_LINK SMN Address is 0x%08X\n", + LcResetLinkAddress); + + Value = xUSLSmnRead(0, 0, LcResetLinkAddress); + xUSLSmnWrite(0, 0, LcResetLinkAddress, Value | BIT_32(3)); + SilFchStall(20 * 1000); + xUSLSmnWrite(0, 0, LcResetLinkAddress, Value); + + do { + CurrentSpeed = xUSLPciRead8(GppPcieAddress + 0x6B); + } while ((CurrentSpeed & (BIT_8(5) + BIT_8(3))) != BIT_8(5)); + + CurrentSpeed = xUSLPciRead8(GppPcieAddress + 0x6A); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Before set Target speed: Current Speed x%d Gen%d\n", + CurrentSpeed >> 4, CurrentSpeed & 0xF); + + PTTargetSpeed = PromDataBlk->PromInputBlk.PT21PcieTargetSpeed; + if ((CurrentSpeed & 0xF) != PTTargetSpeed) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set PT Target Link Speed to Gen%d\n", PTTargetSpeed); + MpioXferTable->MpioPcieSetSpeed(SilContext, + &NbPcieData->PciePlatformConfig, + GppDev, + GppFun, + PTTargetSpeed); + do { + CurrentSpeed = xUSLPciRead8(GppPcieAddress + 0x6B); + } while ((CurrentSpeed & (BIT_8(5) + BIT_8(3))) != BIT_8(5)); + CurrentSpeed = xUSLPciRead8(GppPcieAddress + 0x6A); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Current Speed is 0x%x x%d Gen%d\n", + CurrentSpeed, CurrentSpeed >> 4, CurrentSpeed & 0xF); + + if ((CurrentSpeed & 0xF) != PTTargetSpeed) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " MPIO service failed, current speed is Gen%d\n", + (CurrentSpeed & 0xF)); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set PT Target Link Speed to Gen%d\n", PTTargetSpeed); + Prom21RetrainSpeed(PromDataBlk, GppBus, GppDev, GppFun, 0, PTTargetSpeed, false); + } + } + + // Load Secondary PT21 + if ((SecGppPcieAddress == 0) && (PromDataBlk->PromInputBlk.PT21SecondPortNumber != 0xE)) { + if (PromDataBlk->PromInputBlk.PT21RuninRam == 0x0) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Check USB status before scan second PT\n"); + Counter = 0; + do { + UsbCmd = xUSLMemRead32((void *)(size_t)(XhciMmio + 0x20)); + PROM_TRACEPOINT(SIL_TRACE_INFO, " UsbCmd = 0x%X Counter = %d\n", UsbCmd, Counter); + if (UsbCmd & BIT_32(1)) { + SilFchStall(2 * 1000); + } + Counter++; + } while ((UsbCmd & BIT_32(1)) && (Counter < 100)); + + ScanSecXhciDidVid(PromDataBlk, + PtPciTable[0].PromBus + 1, + SecPortNum, + 0, + PtPciTable[0].PromBus + 4 + ); + + SecGppPcieAddress = PromDataBlk->PromOutputBlk.PT21GppPcieAddress[1]; + + if (SecGppPcieAddress) { + RestorePromBus(PromDataBlk, PtPciTable, 0x00BB); + + SecGppBus = (uint16_t)((SecGppPcieAddress >> 20) & 0xFFF); + SecGppDev = (uint8_t)((SecGppPcieAddress >> 15) & 0x1F); + SecGppFun = (uint8_t)((SecGppPcieAddress >> 12) & 0x07); + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Secondary PT is at 0x%x - B%d D% F%d\n", + SecGppPcieAddress, SecGppBus, SecGppDev, SecGppFun); + + SecXhciMmio = PromDataBlk->PromOutputBlk.PT21XhciMmio[1]; + if ((SecXhciMmio == 0x0) || (SecXhciMmio == 0xffffffff)) { + if (PromDataBlk->PromInputBlk.PT21Revision >= 2) { + RestorePromBus(PromDataBlk, PtPciTable, 0xBBBB); + } + return SilNotFound; + } + + SaveInitPromBus(PromDataBlk, PtPciTable, 0xBBBB); + + XhciLock = Prom21XhciReadByteV2(PromDataBlk, SecXhciMmio, 0x15087); + if ((XhciLock & BIT_8(4)) == 0) { + PromDataBlk->PromOutputBlk.PT21XhciLock[1] = 1; + PROM_TRACEPOINT(SIL_TRACE_INFO, " Set SecPT21XhciLock = %d\n", + PromDataBlk->PromOutputBlk.PT21XhciLock[1]); + } + + if ((Status == SilPass) && (XhciLock & BIT_8(4))) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Secondary PT XHCI is unlock\n"); + + // Force PT DSP Gen1 before load Secondary FW + SecCurrentSpeed = xUSLPciRead8(SecGppPcieAddress + 0x92); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Secondary PT USP PCIe Link Width & Link Speed is x%d Gen%d\n", + SecCurrentSpeed >> 4, SecCurrentSpeed & 0xF); + if ((SecCurrentSpeed & 0x0F) == PcieGen1) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Secondary PT DSP set to Gen1 Success !!!\n"); + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Secondary PT DSP set to Gen1 Fail !!!\n"); + } + + Status = LpPtXhciProceedFwLoad (PromDataBlk, + PtFwInRamPtr + 0x0C, + PtPciTable[0].PromBus + 6, 0, 0, + SecXhciMmio, + true + ); + if (Status == SilPass) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " 2nd PT load FW success\n"); + } + + SecCurrentSpeed = xUSLPciRead8(SecGppPcieAddress + 0x92); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Secondary PT USP PCIe Link Width & Link Speed is x%d Gen%d\n", + SecCurrentSpeed >> 4, SecCurrentSpeed & 0xF); + + SecCurrentSpeed = xUSLPciRead8(SecGppPcieAddress + 0x90); + xUSLPciWrite8(SecGppPcieAddress + 0x90, SecCurrentSpeed | BIT_8(4)); + SilFchStall(10 * 1000); + SecTargetSpeed = xUSLPciRead8(SecGppPcieAddress + 0x3E); + xUSLPciWrite8(SecGppPcieAddress + 0x3E, SecTargetSpeed | BIT_8(6)); + SilFchStall(10 * 1000); + xUSLPciWrite8(SecGppPcieAddress + 0x3E, SecTargetSpeed); + SilFchStall(10 * 1000); + xUSLPciWrite8(SecGppPcieAddress + 0x90, SecCurrentSpeed); + + do { + SecTargetSpeed = xUSLPciRead8(SecGppPcieAddress + 0x93); + } while ((SecTargetSpeed & (BIT_8(5) + BIT_8(3))) != BIT_8(5)); + + SecCurrentSpeed = xUSLPciRead8(SecGppPcieAddress + 0x92); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Secondary PT USP PCIe Link Width & Link Speed is x%d Gen%d\n", + SecCurrentSpeed >> 4, SecCurrentSpeed & 0xF); + + if ((SecCurrentSpeed & 0x0F) != (PromDataBlk->PromInputBlk.PT21PcieTargetSpeed & 0x0F)) { + SecTargetSpeed = xUSLPciRead8(SecGppPcieAddress + 0xB0); + SecTargetSpeed &= 0xF0; + SecTargetSpeed |= PromDataBlk->PromInputBlk.PT21PcieTargetSpeed & 0x0F; + xUSLPciWrite8(SecGppPcieAddress + 0xB0, SecTargetSpeed); + + SecTargetSpeed = xUSLPciRead8(SecGppPcieAddress + 0x90); + xUSLPciWrite8(SecGppPcieAddress + 0x90, SecTargetSpeed | BIT_8(5)); + + for (Counter = 0; Counter < 50; Counter++) { + SecTargetSpeed = xUSLPciRead8(SecGppPcieAddress + 0x92); + if ((SecTargetSpeed & 0x0F) == (PromDataBlk->PromInputBlk.PT21PcieTargetSpeed & 0x0F)) { + break; + } + SilFchStall(20 * 1000); + } + + SecCurrentSpeed = xUSLPciRead8(SecGppPcieAddress + 0x92); + PROM_TRACEPOINT(SIL_TRACE_INFO, " Secondary PT USP PCIe Link Width & Link Speed is x%d Gen%d\n", + SecCurrentSpeed >> 4, SecCurrentSpeed & 0xF); + + if ((SecCurrentSpeed & 0x0F) == (PromDataBlk->PromInputBlk.PT21PcieTargetSpeed & 0x0F)) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Restore Secondary PT DSP speed to Gen%d Success !!!\n", + SecCurrentSpeed & 0x0F); + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Restore Secondary PT DSP speed to Gen%d Fail !!! It's Gen%d now\n", + PromDataBlk->PromInputBlk.PT21PcieTargetSpeed & 0x0F, SecCurrentSpeed & 0x0F); + } + } + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Secondary PT XHCI is lock: bypass PT code !!!\n"); + } + RestorePromBus(PromDataBlk, PtPciTable, 0xBBBB); + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " Bus %x is NOT Second PT, retrain to target speed\n", DspBus); + Prom21RetrainSpeed(PromDataBlk, + DspBus, + SecPortNum, + 0, + 0, + PromDataBlk->PromInputBlk.PT21PcieTargetSpeed, + false + ); + RestorePromBus(PromDataBlk, PtPciTable, 0x00BB); + } + } else { + ScanSecXhciDidVid(PromDataBlk, + PtPciTable[0].PromBus + 1, + SecPortNum, + 0, + PtPciTable[0].PromBus + 4 + ); + RestorePromBus(PromDataBlk, PtPciTable, 0x00BB); + Status = SilPass; + } + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); + + return Status; +} diff --git a/xUSL/PROM/PROM21/Prom21PreInit.c b/xUSL/PROM/PROM21/Prom21PreInit.c new file mode 100644 index 0000000..4588105 --- /dev/null +++ b/xUSL/PROM/PROM21/Prom21PreInit.c @@ -0,0 +1,876 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ + +/** + * @file PromPreInit.c + * @brief Promontory21 early initialization + */ + +#include +#include +#include +#include +#include +#include "Prom21.h" +#include "Prom21Init.h" + +#define SET_BITS(value, mask, shift) (((value) & (mask)) << (shift)) + +static void +Prom21XhciGenSelect ( + uint32_t XhciMmio, + uint8_t GenSelect + ) +{ + uint8_t Value; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "Gen%d\n", GenSelect); + + Value = Prom21XhciReadByte(XhciMmio, 0x1C51C); + + Value &= (~BIT_8(0)); + + switch(GenSelect) { + case 0: + Value |= 0x0; + break; + case 1: + Value |= 0x1; + break; + default: + Value |= 0x1; + break; + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Write Value = 0x%x\n", Value); + + Prom21XhciWriteDWord(XhciMmio, 0x1C520, 0x12345678); + Prom21XhciWriteByte(XhciMmio, 0x1C51C, Value); +} + +static void +Prom21XhciCtrl ( + uint32_t XhciMmio, + bool Enable, + uint32_t PortNum, + uint8_t GenSel + ) +{ + uint32_t Address; + uint8_t Value8; + uint8_t BitMask; + + Value8 = 0; + Address = 0; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "P%dGenx%x\n", + PortNum, GenSel); + + if (GenSel == 0x1) { + BitMask = USBGen2by1_port_mapping[PortNum]; + + switch(PortNum) + { + case Usb3Port0: + case Usb3Port1: + case Usb3Port2: + case Usb3Port3: + case Usb3Port4: + case Usb3Port5: + Address = 0x1C51C; + break; + case Usb2Port0: + case Usb2Port1: + case Usb2Port2: + case Usb2Port3: + case Usb2Port4: + case Usb2Port5: + case Usb2Port6: + case Usb2Port7: + Address = 0x1C51D; + break; + case Usb2Port8: + case Usb2Port9: + case Usb2Port10: + case Usb2Port11: + Address = 0x1C51E; + break; + default: + break; + } + }else if (GenSel == 0xE) { + BitMask = USBL4_port_mapping[PortNum]; + + switch (PortNum) { + case Usb3Port0: + case Usb3Port1: + case Usb3Port2: + case Usb3Port3: + Address = 0x1C51C; + break; + case Usb2Port0: + case Usb2Port1: + case Usb2Port2: + case Usb2Port3: + case Usb2Port4: + case Usb2Port5: + Address = 0x1C51D; + break; + case Usb2Port6: + case Usb2Port7: + case Usb2Port8: + case Usb2Port9: + Address = 0x1C51E; + break; + default: + break; + } + }else { + BitMask = USBGen2by2_port_mapping[PortNum]; + + switch (PortNum) { + case Usb3Port1: + return; + case Usb3Port0: + case Usb3Port2: + case Usb3Port3: + case Usb3Port4: + case Usb3Port5: + Address = 0x1C51C; + break; + case Usb2Port0: + case Usb2Port1: + case Usb2Port2: + case Usb2Port3: + case Usb2Port4: + case Usb2Port5: + case Usb2Port6: + case Usb2Port10: + Address = 0x1C51D; + break; + case Usb2Port7: + case Usb2Port8: + case Usb2Port9: + case Usb2Port11: + Address = 0x1C51E; + break; + default: + break; + } + } + + Value8 = Prom21XhciReadByte(XhciMmio, Address); + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Read Value = 0x%x, Address = 0x%x with BitMask %x\n", + Value8, Address, BitMask); + + if (Enable) { + Value8 &= ~(uint8_t)(BitMask); + } else { + Value8 |= (uint8_t)(BitMask); + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Write Value = 0x%x, Address = 0x%x\n", + Value8, Address); + + Prom21XhciWriteDWord(XhciMmio, 0x1C520, 0x12345678); + Prom21XhciWriteByte(XhciMmio, Address, Value8); +} + +void +Prom21UsbPortSetting ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciId, + uint32_t XhciMmio, + uint8_t BootMode + ) +{ + uint8_t GenSelect; + uint8_t MaxUsb2Ports; + uint8_t MaxUsb3Ports; + uint8_t PromVariant; + + GenSelect = 0; + PromVariant = 0; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + PROM_TRACEPOINT(SIL_TRACE_INFO, " XHCI XhciId == 0x%04X, ", XhciId); + switch (XhciId) { + case PT21_XHCI_ID_L1: PromVariant = 1; break; + case PT21_XHCI_ID_L2: PromVariant = 2; break; + case PT21_XHCI_ID_L3: PromVariant = 3; break; + case PT21_XHCI_ID_L4: PromVariant = 4; break; + case PT21_XHCI_ID_L5: PromVariant = 5; break; + case PT21_XHCI_ID_L6: PromVariant = 6; break; + case PT21_XHCI_ID_L7: PromVariant = 7; break; + case PT21_XHCI_ID_L8: PromVariant = 8; break; + default: break; + } + + if (PromVariant != 0) { + PROM_TRACEPOINT(SIL_TRACE_INFO, " XHCI XhciId == 0x%04X, PT21 L.%d\n", PromVariant); + } else { + PROM_TRACEPOINT(SIL_TRACE_INFO, " XHCI XhciId == 0x%04X, PT21 Unknown\n"); + return; + } + + if (XhciId != PT21_XHCI_ID_L4) { + MaxUsb2Ports = PROM21_XHCI_NUM_USB2_PORTS; + MaxUsb3Ports = PROM21_XHCI_NUM_USB3_PORTS; + if (PromDataBlk->PT21Usb3GenSelect != 0xf) { + GenSelect = PromDataBlk->PT21Usb3GenSelect; + Prom21XhciGenSelect (XhciMmio, GenSelect); + } + } else { + MaxUsb2Ports = PROM21L4_XHCI_NUM_USB2_PORTS; + MaxUsb3Ports = PROM21L4_XHCI_NUM_USB3_PORTS; + GenSelect = 0xE; + Prom21XhciGenSelect (XhciMmio, GenSelect); + } + + if ((PromDataBlk->PT21UsbPortLateDisable != 0x1) || (SilFchReadSleepType () == 0x3)) { + for (uint8_t PortNum = 0; PortNum < MaxUsb3Ports; PortNum++) { + if (PromDataBlk->PT21Usb3Port[PortNum] != 0xf) { + Prom21XhciCtrl(XhciMmio, PromDataBlk->PT21Usb3Port[PortNum], Usb3Port0 + PortNum, GenSelect); + } + } + for (uint8_t PortNum = 0; PortNum < MaxUsb2Ports; PortNum++) { + if (PromDataBlk->PT21Usb2Port[PortNum] != 0xf) { + Prom21XhciCtrl(XhciMmio, PromDataBlk->PT21Usb3Port[PortNum], Usb2Port0 + PortNum, GenSelect); + } + } + } else { + for (uint8_t PortNum = 0; PortNum < MaxUsb3Ports; PortNum++) { + if (PromDataBlk->PT21Usb3Port[PortNum] != 0xf) { + Prom21XhciCtrl(XhciMmio, 1, Usb3Port0 + PortNum, GenSelect); + } + } + for (uint8_t PortNum = 0; PortNum < MaxUsb2Ports; PortNum++) { + if (PromDataBlk->PT21Usb2Port[PortNum] != 0xf) { + Prom21XhciCtrl(XhciMmio, 1, Usb2Port0 + PortNum, GenSelect); + } + } + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, "\n"); +} + +void +Prom21XhciGen ( + uint32_t XhciMmio, + uint8_t XhciGen, + uint8_t PortNum + ) +{ + uint32_t Address; + uint8_t Data; + uint8_t Value; + size_t Count; + + Count = 5; + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "P%d %s\n", + PortNum, (XhciGen == 0) ? "Gen1x1" : "Gen2x2"); + + Address = r_force_superspeed[PortNum]; + + Data = Prom21XhciReadByte(XhciMmio, Address); + Data &= (~0x7); + + switch(XhciGen) + { + case 1: + // Gen2x2 + Data |= 0x7; + break; + case 0: + // Gen1x1 + Data |= 0x4; + break; + default: + // Gen2x2 + Data |= 0x7; + break; + } + + do { + Prom21XhciWriteByte(XhciMmio, Address, Data); + Value = Prom21XhciReadByte(XhciMmio, Address); + Count--; + } while((Value != Data) && (Count > 0)); + + Address = r_warm_rst_assert[PortNum]; + + Value = Prom21XhciReadByte(XhciMmio, Address); + Value |= BIT_8(2); + + Prom21XhciWriteByte(XhciMmio, Address, Value); + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + +void +Prom21AhciMsiCap ( + uint32_t XhciMmio, + bool Enable + ) +{ + PROM_TRACEPOINT(SIL_TRACE_INFO, "%s\n", (Enable == 0) ? "Disable" : "Enable"); + Prom21XhciWriteByte(XhciMmio, 0x23C34, Enable ? 0x50 : 0x70); +} + +void +Prom21AhciPortSataSpeed ( + uint32_t XhciMmio, + uint8_t PortNum, + uint8_t Speed + ) +{ + uint32_t Address; + uint8_t Value; + + if((PortNum >= PROM21_NUM_SATA_PORTS) || + (Speed < PROM21_MIN_SATA_SPEED) || + (Speed > PROM21_MAX_SATA_SPEED)) { + return; + } + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "P%dGen%d\n", PortNum, Speed); + + Address = SATA_gen_reg[PortNum]; + + switch(Speed) + { + case 1: + Value = 0x90; + break; + case 2: + Value = 0xA0; + break; + case 3: + Value = 0xC0; + break; + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Write Value = 0x%x, Address = 0x%x\n", Value, Address); + + Prom21XhciWriteByte(XhciMmio, Address, Value); +} + +static void +Prom21Usb3Gen2PortTx ( + uint32_t XhciMmio, + uint8_t PortNum, + uint8_t Gen2Tx, + uint8_t CpValue, + uint8_t Value, + uint8_t Enable +) +{ + uint16_t Data; + uint32_t Address; + + Data = 0; + Address = 0; + Enable = (Enable == 0 ? 0 : 1); + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X, P%dGen2Cp%d %s: Value %x, Enable %x\n", + XhciMmio, PortNum, CpValue, + (Gen2Tx == 0) ? "TxEmphasis" : + (Gen2Tx == 1) ? "TxPreshoot" : "Unknown", + Value, Enable); + + switch(CpValue) + { + case Usb3_Cp0_Cp9: + Address = USB3_gen2_cp0_cp9_emphasis_preshoot[PortNum]; + break; + case Usb3_Cp13: + Address = USB3_gen2_cp13_emphasis_preshoot[PortNum]; + break; + case Usb3_Cp14: + Address = USB3_gen2_cp14_emphasis_preshoot[PortNum]; + break; + case Usb3_Cp15: + Address = USB3_gen2_cp15_emphasis_preshoot[PortNum]; + break; + case Usb3_Cp16: + Address = USB3_gen2_cp16_emphasis_preshoot[PortNum]; + break; + default: + break; + } + + Data = Prom21XhciReadWord (XhciMmio, Address); + + switch(Gen2Tx) + { + case TxEmphasis: + Data &= ~(0x1F0); + Data |= SET_BITS (Value, 0xf, 4); + Data |= (Enable << 8); + break; + case TxPreshoot: + Data &= ~(0xF); + Data |= SET_BITS (Value, 0x7, 0); + Data |= (Enable << 3); + break; + default: + break; + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Write Data %x to Address %x\n", Data, Address); + + Prom21XhciWriteWord (XhciMmio, Address, Data); +} + +static void +Prom21Usb3Gen1PortTx ( + uint32_t XhciMmio, + uint8_t PortNum, + uint8_t Gen1Tx, + uint8_t Value, + uint8_t Enable + ) +{ + uint16_t Data; + uint32_t Address; + + Data = 0; + Address = 0; + Enable = (Enable == 0 ? 0 : 1); + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X, P%dGen1 %s: Value 0x%x, Enable %x\n", + XhciMmio, PortNum, + (Gen1Tx == 0) ? L"TxEmphasis" : + (Gen1Tx == 1) ? L"TxPreshoot" : + (Gen1Tx == 2) ? L"TxSquelch" : L"Unknown", + Value, Enable); + + Address = USB3_gen1_emphasis_preshoot [PortNum]; + Data = Prom21XhciReadWord(XhciMmio, Address); + + switch(Gen1Tx) + { + case TxEmphasis: + Data &= ~(0x1F0); + Data |= SET_BITS (Value, 0xf, 4); + Data |= (Enable << 8); + break; + case TxPreshoot: + Data &= ~(0xF); + Data |= SET_BITS (Value, 0x7, 0); + Data |= (Enable << 3); + break; + case TxSquelch: + Address = USB3_gen1_squelch [PortNum]; + Data = Prom21XhciReadWord(XhciMmio, Address); + Data &= ~(0xC0); + Data |= SET_BITS(Value, 0x3, 6); + break; + default: + break; + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Write Data %x to Address %x\n", Data, Address); + + Prom21XhciWriteWord(XhciMmio, Address, Data); +} + +static void +Prom21Usb3PortTxSwing ( + uint32_t XhciMmio, + uint8_t PortNum, + uint8_t GenNum, + uint8_t Value + ) +{ + uint8_t Data; + uint32_t Address; + + Data = 0; + Address = 0; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X, P%dGen%d TxSwing: Value %x\n", + XhciMmio, PortNum, GenNum, Value); + + switch(GenNum) + { + case 0x1: + Address = USB3_gen1_swing[PortNum]; + break; + case 0x2: + Address = USB3_gen2_swing[PortNum]; + break; + default: + break; + } + + Data = Prom21XhciReadByte(XhciMmio, Address); + Data &= ~(0xF0); + Data |= SET_BITS(Value, 0xf, 4); + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Write Data %x to Address %x\n", Data, Address); + + Prom21XhciWriteByte(XhciMmio, Address, Data); +} + +static void +Prom21USB3SIConfig ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciMmio +) +{ + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X\n", XhciMmio); + + for (uint8_t Port = 0; Port < PROM21_XHCI_NUM_USB3_PORTS; Port++) { + if (PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen1Swing < 0x10) { + Prom21Usb3PortTxSwing(XhciMmio, + 0, 0x1, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen1Swing + ); + } + if (PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen1EmpLevel < 0x10) { + Prom21Usb3Gen1PortTx(XhciMmio, + 0, TxEmphasis, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen1EmpLevel, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen1EmpLevelEn + ); + } + if (PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen1Preshoot < 0x8) { + Prom21Usb3Gen1PortTx(XhciMmio, + 0, TxPreshoot, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen1Preshoot, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen1PreshootEn + ); + } + if (PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Swing < 0x10) { + Prom21Usb3PortTxSwing(XhciMmio, + 0, + 0x2, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Swing + ); + } + if (PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp0EmpLevel < 0x10) { + Prom21Usb3Gen2PortTx(XhciMmio, + 0, TxEmphasis, Usb3_Cp0_Cp9, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp0EmpLevel, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp0EmpLevelEn + ); + } + if (PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp0Preshoot < 0x8) { + Prom21Usb3Gen2PortTx(XhciMmio, + 0, TxPreshoot, Usb3_Cp0_Cp9, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp0Preshoot, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp0PreshootEn + ); + } + if (PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp13EmpLevel < 0x10) { + Prom21Usb3Gen2PortTx(XhciMmio, + 0, TxEmphasis, Usb3_Cp13, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp13EmpLevel, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp13EmpLevelEn + ); + } + if (PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp13Preshoot < 0x8) { + Prom21Usb3Gen2PortTx(XhciMmio, + 0, TxPreshoot, Usb3_Cp13, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp13Preshoot, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp13PreshootEn + ); + } + if (PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp14EmpLevel < 0x10) { + Prom21Usb3Gen2PortTx(XhciMmio, + 0, TxEmphasis, Usb3_Cp14, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp14EmpLevel, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp14EmpLevelEn + ); + } + if (PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp14Preshoot < 0x8) { + Prom21Usb3Gen2PortTx(XhciMmio, + 0, TxPreshoot, Usb3_Cp14, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp14Preshoot, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp14PreshootEn + ); + } + if (PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp15EmpLevel < 0x10) { + Prom21Usb3Gen2PortTx(XhciMmio, + 0, TxEmphasis, Usb3_Cp15, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp15EmpLevel, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp15EmpLevelEn + ); + } + if (PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp15Preshoot < 0x8) { + Prom21Usb3Gen2PortTx(XhciMmio, + 0, TxPreshoot, Usb3_Cp15, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp15Preshoot, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp15PreshootEn + ); + } + if (PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp16EmpLevel < 0x10) { + Prom21Usb3Gen2PortTx(XhciMmio, + 0, TxEmphasis, Usb3_Cp16, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp16EmpLevel, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp16EmpLevelEn + ); + } + if (PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp16Preshoot < 0x8) { + Prom21Usb3Gen2PortTx(XhciMmio, + 0, TxPreshoot, Usb3_Cp16, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp16Preshoot, + PromDataBlk->PT21USB3Phy[Port].PT21USB3PortGen2Cp16PreshootEn + ); + } + } +} + +static void +Prom21SIUSB2Tx ( + uint32_t XhciMmio, + uint8_t PortNum, + uint8_t TxSetting, + uint16_t Value +) +{ + uint8_t Data; + uint16_t Data16; + uint32_t Address; + + Data = 0; + Data16 = 0; + Address = 0; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X, Port%x-TxSet%d, Value %x\n", + XhciMmio, PortNum, TxSetting, Value); + + Address = USB2_tx_reg[PortNum]; + + Data = Prom21XhciReadByte(XhciMmio, Address); + Data16 = Prom21XhciReadWord(XhciMmio, Address); + + if ((PortNum % 2) == 0) { // Port 0/2/4/6/8/10 + switch (TxSetting) + { + case 0x0: + Data &= 0xFC; + break; + case 0x1: + Data &= 0xE3; + Value = (Value << 2); + break; + case 0x2: + Data &= 0x1F; + Value = (Value << 5); + break; + default: + break; + } + PROM_TRACEPOINT(SIL_TRACE_INFO, "Write Data %x, Value %x\n", Data, Value); + Data |= (uint8_t)Value; + Prom21XhciWriteByte(XhciMmio, Address, Data); + }else { + switch (TxSetting) + { + case 0x0: + Data &= 0xCF; + Data |= (Value << 4); + PROM_TRACEPOINT(SIL_TRACE_INFO, "Write Data %x, Value %x\n", Data, Value); + Prom21XhciWriteByte(XhciMmio, Address, Data); + break; + case 0x1: + Data16 &= 0xFE3F; + Value = (Value << 6); + Data16 |= Value; + PROM_TRACEPOINT(SIL_TRACE_INFO, "Write Data16 %x, Value %x\n", Data16, Value); + Prom21XhciWriteWord(XhciMmio, Address, Data16); + break; + case 0x2: + Data16 &= 0xF1FF; + Value = (Value << 9); + Data16 |= Value; + PROM_TRACEPOINT(SIL_TRACE_INFO, "Write Data16 %x, Value %x\n", Data16, Value); + Prom21XhciWriteWord(XhciMmio, Address, Data16); + break; + default: + break; + } + } +} + +static void +Prom21SIUSB2Config ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciMmio +) +{ + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X\n", XhciMmio); + + /* 0/2, 1/3, 4/6, 5/7, 8/10, 9/11 */ + uint8_t Usb2Ports[] = { 0, 1, 4, 5, 8, 9 }; + + for (uint8_t Port = 0; Port < PROM21_XHCI_NUM_USB2_PORTS / 2; Port++) { + if (PromDataBlk->PT21USB2Phy[Port].PT21USB2SlewRate != BIT_8(2)) { + Prom21SIUSB2Tx(XhciMmio, + Usb2Ports[Port], + 0x0, + PromDataBlk->PT21USB2Phy[Port].PT21USB2SlewRate + ); + } + if (PromDataBlk->PT21USB2Phy[Port].PT21USB2DrivingCurrent != BIT_8(3)) { + Prom21SIUSB2Tx(XhciMmio, + Usb2Ports[Port], + 0x1, + PromDataBlk->PT21USB2Phy[Port].PT21USB2DrivingCurrent + ); + } + if (PromDataBlk->PT21USB2Phy[Port].PT21USB2Termination != BIT_8(3)) { + Prom21SIUSB2Tx(XhciMmio, + Usb2Ports[Port], + 0x2, + PromDataBlk->PT21USB2Phy[Port].PT21USB2Termination + ); + } + } +} + +static void +Prom21SataPortTxEmp ( + uint32_t XhciMmio, + uint8_t PortNum, + uint8_t GenNum, + uint8_t Value + ) +{ + uint8_t Data; + uint32_t Address; + + Data = 0; + Address = 0; + + PROM_TRACEPOINT(SIL_TRACE_INFO, "XhciMmio 0x%08X, P%dGen%d: Value %x\n", + XhciMmio, PortNum, GenNum, Value); + + switch (GenNum) + { + case 0x1: + Address = SATA_gen1_emphasis[PortNum]; + break; + case 0x2: + Address = SATA_gen2_emphasis[PortNum]; + break; + case 0x3: + Address = SATA_gen3_emphasis[PortNum]; + break; + default: + break; + } + + Data = Prom21XhciReadByte(XhciMmio, Address); + Data &= ~(0x1F); + Data |= SET_BITS(Value, 0x1f, 0); + Data |= BIT_8(7); + + PROM_TRACEPOINT(SIL_TRACE_INFO, "Write Data %x to Address %x\n", Data, Address); + + Prom21XhciWriteByte(XhciMmio, Address, Data); +} + +static void +Prom21SataPortTxSwing ( + uint32_t XhciMmio, + uint8_t PortNum, + uint8_t GenNum, + uint8_t Value + ) +{ + uint8_t Data; + uint32_t Address; + + Data = 0; + Address = 0; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X, P%dGen%d: Value %x\n", + XhciMmio, PortNum, GenNum, Value); + + switch (GenNum) + { + case 0x1: + Address = SATA_gen1gen2_swing[PortNum]; + Data = Prom21XhciReadByte(XhciMmio, Address); + Data &= ~(0xF); + Data |= SET_BITS(Value, 0xf, 0); + break; + case 0x2: + Address = SATA_gen1gen2_swing[PortNum]; + Data = Prom21XhciReadByte(XhciMmio, Address); + Data &= ~(0xF0); + Data |= SET_BITS(Value, 0xf, 4); + break; + case 0x3: + Address = SATA_gen3_swing[PortNum]; + Data = Prom21XhciReadByte(XhciMmio, Address); + Data &= ~(0xF); + Data |= SET_BITS(Value, 0xf, 0); + break; + default: + break; + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, "Write Data %x to Address %x\n", Data, Address); + + Prom21XhciWriteByte(XhciMmio, Address, Data); +} + +static void +Prom21SISATAConfig ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciMmio + ) +{ + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X\n", XhciMmio); + + for (uint8_t Port = 0; Port < PROM21_NUM_SATA_PORTS; Port++) { + if (PromDataBlk->PT21SataPhy[Port].PT21SataPortGen1Swing != BIT_8(4)) { + Prom21SataPortTxSwing(XhciMmio, Port, 0x1, PromDataBlk->PT21SataPhy[Port].PT21SataPortGen1Swing); + } + if (PromDataBlk->PT21SataPhy[Port].PT21SataPortGen1EmpLevel != BIT_8(5)) { + Prom21SataPortTxEmp(XhciMmio, Port, 0x1, PromDataBlk->PT21SataPhy[Port].PT21SataPortGen1EmpLevel); + } + if (PromDataBlk->PT21SataPhy[Port].PT21SataPortGen2Swing != BIT_8(4)) { + Prom21SataPortTxSwing(XhciMmio, Port, 0x2, PromDataBlk->PT21SataPhy[Port].PT21SataPortGen2Swing); + } + if (PromDataBlk->PT21SataPhy[Port].PT21SataPortGen2EmpLevel != BIT_8(5)) { + Prom21SataPortTxEmp(XhciMmio, Port, 0x2, PromDataBlk->PT21SataPhy[Port].PT21SataPortGen2EmpLevel); + } + if (PromDataBlk->PT21SataPhy[Port].PT21SataPortGen3Swing != BIT_8(4)) { + Prom21SataPortTxSwing(XhciMmio, Port, 0x3, PromDataBlk->PT21SataPhy[Port].PT21SataPortGen3Swing); + } + if (PromDataBlk->PT21SataPhy[Port].PT21SataPortGen3EmpLevel != BIT_8(5)) { + Prom21SataPortTxEmp(XhciMmio, Port, 0x3, PromDataBlk->PT21SataPhy[Port].PT21SataPortGen3EmpLevel); + } + } +} + + +void +Prom21SIConfig ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciMmio + ) +{ + uint8_t Data; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X\n", XhciMmio); + + Prom21SISATAConfig(PromDataBlk, XhciMmio); + Prom21USB3SIConfig(PromDataBlk, XhciMmio); + Prom21SIUSB2Config(PromDataBlk, XhciMmio); + + Data = Prom21XhciReadByte(XhciMmio, 0x1C51F); + Data |= BIT_8(7); + Prom21XhciWriteByte(XhciMmio, 0x1C51F, Data); + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + + diff --git a/xUSL/PROM/PROM21/Prom21Sata.c b/xUSL/PROM/PROM21/Prom21Sata.c new file mode 100644 index 0000000..eae5174 --- /dev/null +++ b/xUSL/PROM/PROM21/Prom21Sata.c @@ -0,0 +1,479 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ + +/** + * @file Prom21Sata.c + * @brief Promontory21 SATA related functions + */ + +#include +#include +#include +#include +#include "Prom21.h" +#include "Prom21Init.h" + +static void +Prom21SetSataClassCode ( + uint32_t XhciMmio, + uint32_t ClassCode, + uint16_t DeviceId +) +{ + Prom21XhciWriteByte(XhciMmio, 0x24788, 0x86); + Prom21XhciWriteDWord(XhciMmio, 0x24714, ClassCode); + Prom21XhciWriteByte(XhciMmio, 0x24700, 0x2); + Prom21XhciWriteWord(XhciMmio, 0x24706, DeviceId); + Prom21XhciWriteByte(XhciMmio, 0x24788, 0x0); +} + +static void +Prom21SetSataMode ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciMmio +) +{ + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + if (PromDataBlk->PT21SataMode != 0xf) { + if (PromDataBlk->PT21SataMode == PTSataAhci) { + Prom21SetSataClassCode (XhciMmio, PT_SATA_AHCI_CLASS_CODE, PT_SATA_AHCI_DID); + } else { + Prom21SetSataClassCode (XhciMmio, PT_SATA_RAID_CLASS_CODE, PT_SATA_RAID_DID); + } + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + +static void +Prom21SataControllerEnable ( + uint32_t XhciMmio, + bool Enable + ) +{ + uint8_t Data8; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X, Enable %u\n", XhciMmio, Enable); + + Data8 = Prom21XhciReadByte (XhciMmio, 0x10151); + + if (Enable) { + if ((Data8 & 0x02) == 0) { + Data8 |= 0x02; + Prom21XhciWriteByte (XhciMmio, 0x10151, Data8); + } + } else { + if ((Data8 & 0x02) != 0) { + Data8 &= (~0x02); + Prom21XhciWriteByte (XhciMmio, 0x10151, Data8); + } + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); + return; +} + +static void +Prom21SataPortCtrl ( + uint32_t XhciMmio, + bool Enable, + uint8_t PortNum + ) +{ + uint8_t Value8; + + if (PortNum >= PROM21_NUM_SATA_PORTS) { + return; + } + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + Prom21XhciWriteByte (XhciMmio, 0x24788, 0x86); + + Value8 = Prom21XhciReadByte(XhciMmio, 0x2471C); + + if (Enable) { + Value8 |= BIT_8(PortNum); + } else { + Value8 &= ~BIT_8(PortNum); + } + + Prom21XhciWriteByte (XhciMmio, 0x2471C, Value8); + Prom21XhciWriteByte (XhciMmio, 0x24788, 0x0); + + Value8 = Prom21XhciReadByte(XhciMmio, 0x2E006); + + if (Enable) { + Value8 |= BIT_8(PortNum); + } else { + Value8 &= ~BIT_8(PortNum); + } + + Prom21XhciWriteByte (XhciMmio, 0x2E006, Value8); + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); + return; +} + +static void +Prom21GppClockOutput ( + uint32_t XhciMmio, + uint8_t ClkReqNum, + uint8_t ReqMode + ) +{ + uint32_t Address; + uint16_t Data16; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + if((ClkReqNum > PROM21_NUM_PCIE_CLKREQ) || (ReqMode > 3)) { + return; + } + + Prom21XhciWriteByte (XhciMmio, 0x24788, 0x86); + + Address = 0x24720; + Data16 = Prom21XhciReadWord (XhciMmio, Address); + + PROM_TRACEPOINT(SIL_TRACE_INFO, "Read Data16 = 0x%x @ Address 0x%x\n", Data16, Address); + + switch(ClkReqNum) + { + case 0: + Data16 &= ~(BIT_16(0) + BIT_16(1)); + Data16 |= ReqMode; + break; + case 1: + Data16 &= ~(BIT_16(2) + BIT_16(3)); + Data16 |= (ReqMode << 2); + break; + case 2: + Data16 &= ~(BIT_16(4) + BIT_16(5)); + Data16 |= (ReqMode << 4); + break; + case 3: + Data16 &= ~(BIT_16(6) + BIT_16(7)); + Data16 |= (ReqMode << 6); + break; + case 4: + Data16 &= ~(BIT_16(8) + BIT_16(9)); + Data16 |= (ReqMode << 8); + break; + case 5: + Data16 &= ~(BIT_16(10) + BIT_16(11)); + Data16 |= (ReqMode << 10); + break; + default: + break; + } + + Prom21XhciWriteWord(XhciMmio, Address, Data16); + PROM_TRACEPOINT(SIL_TRACE_INFO, "Write Data16 = 0x%x @ Address 0x%x\n", Data16, Address); + + Data16 = Prom21XhciReadWord (XhciMmio, Address); + + PROM_TRACEPOINT(SIL_TRACE_INFO, "Read back Data16 = 0x%x @ Address 0x%x\n", Data16, Address); + + Prom21XhciWriteByte (XhciMmio, 0x24788, 0x0); + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + + +static void +Prom21GppClockConfig ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciMmio + ) +{ + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08x\n", XhciMmio); + + for (uint8_t Clk = 0; Clk < PROM21_NUM_PCIE_CLKREQ; Clk++) { + if(PromDataBlk->PT21PcieClkreqMode[Clk] != 0xf) { + Prom21GppClockOutput(XhciMmio, Clk, PromDataBlk->PT21PcieClkreqMode[Clk]); + } + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + +static void +Prom21ClkReqPinSelect ( + uint32_t XhciMmio, + uint8_t ClkReqNum, + uint8_t PortNumSel + ) +{ + uint32_t Address; + uint32_t Data32; + + Data32 = 0; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "\n"); + + if ((ClkReqNum > PROM21_NUM_PCIE_CLKREQ) || (PortNumSel > 0xf)) { + return; + } + + Prom21XhciWriteByte (XhciMmio, 0x24788, 0x86); + + Address = 0x24724; + Data32 = Prom21XhciReadDWord (XhciMmio, Address); + + PROM_TRACEPOINT(SIL_TRACE_INFO, "Read Data32 = 0x%x @ Address 0x%x\n", Data32, Address); + + switch(ClkReqNum) + { + case 0: + Data32 &= 0xFFFFFFF0; + Data32 |= PortNumSel; + break; + case 1: + Data32 &= 0xFFFFFF0F; + Data32 |= (PortNumSel << 4); + break; + case 2: + Data32 &= 0xFFFFF0FF; + Data32 |= (PortNumSel << 8); + break; + case 3: + Data32 &= 0xFFFF0FFF; + Data32 |= (PortNumSel << 12); + break; + case 4: + Data32 &= 0xFFF0FFFF; + Data32 |= (PortNumSel << 16); + break; + case 5: + Data32 &= 0xFF0FFFFF; + Data32 |= (PortNumSel << 20); + break; + default: + break; + } + + + Prom21XhciWriteDWord (XhciMmio, Address, Data32); + + PROM_TRACEPOINT(SIL_TRACE_INFO, "Write Data32 = 0x%x @ Address 0x%x\n", Data32, Address); + + Data32 = Prom21XhciReadDWord (XhciMmio, Address); + + PROM_TRACEPOINT(SIL_TRACE_INFO, "Readback Data32 = 0x%x @ Address 0x%x\n", Data32, Address); + + Prom21XhciWriteByte (XhciMmio, 0x24788, 0x0); + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + +static void +Prom21ClkConfig ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciMmio + ) +{ + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08x\n", XhciMmio); + + for (uint8_t Clk = 0; Clk < PROM21_NUM_PCIE_CLKREQ; Clk++) { + if(PromDataBlk->PT21PcieClkreqPinSelect[Clk] != 0xf) { + Prom21ClkReqPinSelect(XhciMmio, Clk, PromDataBlk->PT21PcieClkreqPinSelect[Clk]); + } + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + +static void +Prom21SetAhciDevslp ( + uint32_t XhciMmio, + bool Enable, + uint8_t PortNum + ) +{ + uint32_t Address; + uint8_t Value8; + + if (PortNum >= PROM21_NUM_SATA_PORTS) { + return; + } + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "PortNum- %d -Enable(%d)\n", PortNum, Enable); + + Address = 0x2E00A; + Value8 = Prom21XhciReadByte(XhciMmio, Address); + PROM_TRACEPOINT(SIL_TRACE_INFO, "Read Value8 = 0x%x, Address = 0x%x\n", Value8, Address); + + if (Enable) { + Value8 |= BIT_8(PortNum); + } else { + Value8 &= ~BIT_8(PortNum); + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, "Write Value8 = 0x%x, Address = 0x%x\n", Value8, Address); + + Prom21XhciWriteByte (XhciMmio, Address, Value8); +} + +static void +Prom21SetAhciCapReg ( + uint32_t XhciMmio, + uint32_t Capreg, + bool Enable + ) +{ + uint32_t Address; + uint32_t Value32; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "Reg- 0x%x -Enable(%d)\n", Capreg, Enable); + + Address = 0x2E000; + Value32 = Prom21XhciReadDWord (XhciMmio, Address); + + PROM_TRACEPOINT(SIL_TRACE_INFO, "Read Value32 = 0x%x, Address = 0x%x\n", Value32, Address); + + if (Enable) { + Value32 |= Capreg; + } else { + Value32 &= (~Capreg); + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, "Write Value32 = 0x%x, Address = 0x%x\n", Value32, Address); + + Prom21XhciWriteDWord(XhciMmio, Address, Value32); +} + +static void +Prom21AhciPortHotplug ( + uint32_t XhciMmio, + uint8_t PortNum, + bool Enable + ) +{ + uint32_t Address; + uint8_t Value; + + if (PortNum >= PROM21_NUM_SATA_PORTS){ + return; + } + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "Port %d (%d)\n", PortNum, Enable); + + Address = 0x2E0C8 + PortNum; + + Value = Prom21XhciReadByte(XhciMmio, Address); + + if (Enable) { + Value |= BIT_8(3); + } else { + Value &= ~BIT_8(3); + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, "Write Value8 = 0x%x, Address = 0x%x\n", Value, Address); + + Prom21XhciWriteByte(XhciMmio, Address, Value); +} + +static void +Prom21SataConfigure ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciMmio + ) +{ + uint8_t i; + uint8_t SataPort = 0xFF; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X\n", XhciMmio); + + Prom21SetSataMode (PromDataBlk, XhciMmio); + + for (uint8_t Port = 0; Port < PROM21_NUM_SATA_PORTS; Port++) { + if (PromDataBlk->PT21SataPortEnable[Port] != 0xf) { + Prom21SataPortCtrl(XhciMmio, !!PromDataBlk->PT21SataPortEnable[Port], Port); + if (PromDataBlk->PT21SataPortEnable[Port] == 1) { + PROM_TRACEPOINT(SIL_TRACE_INFO, "PT21SataPort%uEnable = 1\n", Port); + } else { + SataPort &= ~BIT_8(Port); + } + + if (PromDataBlk->PT21SataAggressiveDevSlp[Port] != 0xf) { + Prom21SetAhciDevslp(XhciMmio, PromDataBlk->PT21SataAggressiveDevSlp[Port], Port); + } + } + } + + if (PromDataBlk->PT21SataAggrLinkPmCap != 0xf) { + Prom21SetAhciCapReg(XhciMmio, BIT_32(26), PromDataBlk->PT21SataAggrLinkPmCap); + } + + if (PromDataBlk->PT21SataPscCap != 0xf) { + Prom21SetAhciCapReg(XhciMmio, BIT_32(13), PromDataBlk->PT21SataPscCap); + } + + if (PromDataBlk->PT21SataPTSataCCCSCap != 0xf) { + Prom21SetAhciCapReg(XhciMmio, BIT_32(7), PromDataBlk->PT21SataPTSataCCCSCap); + } + + if (PromDataBlk->PT21SataSscCap != 0xf) { + Prom21SetAhciCapReg(XhciMmio, BIT_32(14), PromDataBlk->PT21SataSscCap); + } + + if (PromDataBlk->PT21SataHotPlug != 0xf) { + for (i = 0; i <= PROM21_NUM_SATA_PORTS; i++) { + Prom21AhciPortHotplug(XhciMmio, i, !!PromDataBlk->PT21SataHotPlug); + } + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} + +void +Prom21SataSetting ( + PROMCLASS_DATA_BLK *PromDataBlk + ) +{ + uint32_t XhciMmio = PromDataBlk->PromOutputBlk.PT21XhciMmio[0]; + uint32_t SecXhciMmio = PromDataBlk->PromOutputBlk.PT21XhciMmio[1]; + bool ProgramSecondary = (SecXhciMmio == 0x0) || (SecXhciMmio == 0xffffffff); + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "0x%08X, 0x%08X\n", XhciMmio, SecXhciMmio); + + if ((XhciMmio == 0x0) || (XhciMmio == 0xffffffff)) { + return; + } + + Prom21SataControllerEnable(XhciMmio, true); + Prom21SataConfigure(&PromDataBlk->PromInputBlk.Primary, XhciMmio); + + if (ProgramSecondary) { + Prom21SataControllerEnable(SecXhciMmio, true); + Prom21SataConfigure(&PromDataBlk->PromInputBlk.Secondary, SecXhciMmio); + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Select CLKREQ!\n"); + Prom21ClkConfig(&PromDataBlk->PromInputBlk.Primary, XhciMmio); + + if (ProgramSecondary) { + Prom21ClkConfig(&PromDataBlk->PromInputBlk.Secondary, SecXhciMmio); + } + + PROM_TRACEPOINT(SIL_TRACE_INFO, " Force GPP Clock Output\n"); + Prom21GppClockConfig(&PromDataBlk->PromInputBlk.Primary, XhciMmio); + + if (ProgramSecondary) { + Prom21GppClockConfig(&PromDataBlk->PromInputBlk.Secondary, SecXhciMmio); + } + + if ((PromDataBlk->PromInputBlk.Primary.PT21SataEnable != 0xf) && + (PromDataBlk->PromInputBlk.Primary.PT21SataEnable == 0)) { + Prom21SataControllerEnable(XhciMmio, false); + } + + if (ProgramSecondary) { + if ((PromDataBlk->PromInputBlk.Secondary.PT21SataEnable != 0xf) && + (PromDataBlk->PromInputBlk.Secondary.PT21SataEnable == 0)) { + Prom21SataControllerEnable(SecXhciMmio, false); + } + } +} diff --git a/xUSL/PROM/PROM21/Prom21Xhci.c b/xUSL/PROM/PROM21/Prom21Xhci.c new file mode 100644 index 0000000..1f1cd9e --- /dev/null +++ b/xUSL/PROM/PROM21/Prom21Xhci.c @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. */ + +/** + * @file Prom21Xhci.c + * @brief Promontory21 XHCI related functions + */ + +#include +#include +#include +#include +#include +#include +#include "Prom21.h" +#include "Prom21Init.h" + +void +Prom21UsbSetting ( + PROM21_DATA_BLK *PromDataBlk, + uint32_t XhciMmio, + uint8_t BootMode + ) +{ + uint8_t i; + uint8_t Data8; + uint32_t UsbCmd; + uint32_t UsbOpBase; + uint32_t Counter; + + PROM_TRACEPOINT(SIL_TRACE_ENTRY, "XhciMmio 0x%08X\n", XhciMmio); + + UsbOpBase = XhciMmio + 0x20; + + Counter = 0; + do { + UsbCmd = xUSLMemRead32((void *)(size_t)(UsbOpBase)); + PROM_TRACEPOINT(SIL_TRACE_INFO, "--> Usb Status = 0x%x\n", UsbCmd); + if (UsbCmd & BIT_8(1)) { + SilFchStall(2 * 1000); + } + } while ((UsbCmd & BIT_8(1)) && (Counter < 100)); + + if (PromDataBlk->PT21HW_LPM != 0xf) { + if (PromDataBlk->PT21HW_LPM == 1) { + for (i = 0; i < 3; i++) { + Data8 = Prom21XhciReadByte (XhciMmio, hw_lpm_en[i]); + Prom21XhciWriteByte (XhciMmio, hw_lpm_en[i], (Data8 | 0x1E)); + } + } else { + for (i = 0; i < 3; i++) { + Data8 = Prom21XhciReadByte (XhciMmio, hw_lpm_en[i]); + Prom21XhciWriteByte (XhciMmio, hw_lpm_en[i], (Data8 & (~0x1E))); + } + } + } + + if (PromDataBlk->PT21XHC_PME != 0xf) { + if (PromDataBlk->PT21XHC_PME == 1) { + Data8 = Prom21XhciReadByte (XhciMmio, 0x18515); + Prom21XhciWriteByte (XhciMmio, 0x18515, (Data8 & ~BIT_8(7))); + } else { + Data8 = Prom21XhciReadByte (XhciMmio, 0x18515); + Prom21XhciWriteByte (XhciMmio, 0x18515, (Data8 | BIT_8(7))); + } + } + + if (PromDataBlk->PT21DbC != 0xf) { + if (PromDataBlk->PT21DbC != 0) { + Prom21XhciWriteByte (XhciMmio, 0x18A61, 8); + } else { + Prom21XhciWriteByte (XhciMmio, 0x18A61, 16); + } + } + + PROM_TRACEPOINT(SIL_TRACE_EXIT, "\n"); +} diff --git a/xUSL/PROM/PROM21/meson.build b/xUSL/PROM/PROM21/meson.build index 1cc7719..7d7300a 100644 --- a/xUSL/PROM/PROM21/meson.build +++ b/xUSL/PROM/PROM21/meson.build @@ -2,6 +2,10 @@ # Copyright (C) 2021 - 2025 Advanced Micro Devices, Inc. All rights reserved. - -xusl += files([ 'Prom21Init.c' ]) - +xusl += files([ 'Prom21.c', + 'Prom21Init.c', + 'Prom21Gpio.c', + 'Prom21LoadFw.c', + 'Prom21PreInit.c', + 'Prom21Sata.c', + 'Prom21Xhci.c' ]) diff --git a/xUSL/PROM/PromClass-api.h b/xUSL/PROM/PromClass-api.h index ad08f4d..235d4d1 100644 --- a/xUSL/PROM/PromClass-api.h +++ b/xUSL/PROM/PromClass-api.h @@ -29,142 +29,186 @@ */ #pragma once -#include -#include +#include -#define PROMCLASS_DATA_SIZE sizeof(PROMCLASS_DATA_BLK) +#define PROMCLASS_DATA_SIZE sizeof(PROMCLASS_DATA_BLK) -#define PROM21_NUM_PCIE_LANES 12 -#define PROM21_NUM_PCIE_CLKREQ 6 -#define PROM21_NUM_SATA_PORTS 4 -#define PROM21_XHCI_NUM_USB3_PORTS 6 -#define PROM21_XHCI_NUM_USB2_PORTS 12 -#define PROM21L4_XHCI_NUM_USB3_PORTS 4 -#define PROM21L4_XHCI_NUM_USB2_PORTS 10 +#define PROM21_NUM_PCIE_LANES 12 +#define PROM21_NUM_PCIE_CLKREQ 6 +#define PROM21_NUM_SATA_PORTS 4 +#define PROM21_XHCI_NUM_USB3_PORTS 6 +#define PROM21_XHCI_NUM_USB2_PORTS 12 +#define PROM21L4_XHCI_NUM_USB3_PORTS 4 +#define PROM21L4_XHCI_NUM_USB2_PORTS 10 +#define PROM21_MAX_GPIO_PIN_NUMBER 24 + +typedef union { + struct { + uint16_t GpioDeBounceTimer:3; + uint16_t GpioDeBounceTimeoutTh:3; + uint16_t GpioInterruptOutputEn:1; + uint16_t GpioInterruptActLevel:1; + uint16_t GPIOInterruptMode:1; + uint16_t Reserved2:7; + } Common; + uint16_t Raw; +} PROM21_GPIO_COMMON_SETTING; + +typedef union { + struct { + uint16_t OutEnB:1; + uint16_t Out:1; + uint16_t interruptEnable:1; + uint16_t interruptLevelTrigType:1; + uint16_t interruptType:2; + uint16_t interruptMask:1; + uint16_t Reserved2:9; + } Gpio; + uint16_t Raw; +} PROM21_GPIO_SETTING; + +typedef struct { + uint16_t Pin; + PROM21_GPIO_SETTING Setting; +} PROM21_GPIO_ITEM; + +typedef struct { + PROM21_GPIO_COMMON_SETTING GpioCommon; // unused + PROM21_GPIO_ITEM GpioList[PROM21_MAX_GPIO_PIN_NUMBER * 2 + 1]; +} PROM21_GPIO_INIT_TABLE; typedef struct { - uint8_t PT21SataPortGen1Swing; // 0x3 - uint8_t PT21SataPortGen2Swing; // 0x3 - uint8_t PT21SataPortGen3Swing; // 0xf - uint8_t PT21SataPortGen1EmpLevel; // 0x1 - uint8_t PT21SataPortGen2EmpLevel; // 0x1 - uint8_t PT21SataPortGen3EmpLevel; // 0xa + uint8_t PT21SataPortGen1Swing; + uint8_t PT21SataPortGen2Swing; + uint8_t PT21SataPortGen3Swing; + uint8_t PT21SataPortGen1EmpLevel; + uint8_t PT21SataPortGen2EmpLevel; + uint8_t PT21SataPortGen3EmpLevel; } PROM21_SATA_PHY_TUNING; typedef struct { - uint8_t PT21USB3PortGen1Swing; // 0xf - uint8_t PT21USB3PortGen1EmpLevelEn; // 0x1 - uint8_t PT21USB3PortGen1EmpLevel; // 0x3 - uint8_t PT21USB3PortGen1PreshootEn; // 0x0 - uint8_t PT21USB3PortGen1Preshoot; // 0x0 - uint8_t PT21USB3PortGen2Swing; // 0xf - uint8_t PT21USB3PortGen2Cp0EmpLevelEn; // 0x1 - uint8_t PT21USB3PortGen2Cp0EmpLevel; // 0x3 - uint8_t PT21USB3PortGen2Cp0PreshootEn; // 0x1 - uint8_t PT21USB3PortGen2Cp0Preshoot; // 0x0 - uint8_t PT21USB3PortGen2Cp13EmpLevelEn; // 0x0 - uint8_t PT21USB3PortGen2Cp13EmpLevel; // 0x3 - uint8_t PT21USB3PortGen2Cp13PreshootEn; // 0x1 - uint8_t PT21USB3PortGen2Cp13Preshoot; // 0x0 - uint8_t PT21USB3PortGen2Cp14EmpLevelEn; // 0x1 - uint8_t PT21USB3PortGen2Cp14EmpLevel; // 0x3 - uint8_t PT21USB3PortGen2Cp14PreshootEn; // 0x0 - uint8_t PT21USB3PortGen2Cp14Preshoot; // 0x0 - uint8_t PT21USB3PortGen2Cp15EmpLevelEn; // 0x3 - uint8_t PT21USB3PortGen2Cp15EmpLevel; // 0x3 - uint8_t PT21USB3PortGen2Cp15PreshootEn; // 0x0 - uint8_t PT21USB3PortGen2Cp15Preshoot; // 0x0 - uint8_t PT21USB3PortGen2Cp16EmpLevelEn; // 0x3 - uint8_t PT21USB3PortGen2Cp16EmpLevel; // 0x3 - uint8_t PT21USB3PortGen2Cp16PreshootEn; // 0x0 - uint8_t PT21USB3PortGen2Cp16Preshoot; // 0x0 + uint8_t PT21USB3PortGen1Swing; + uint8_t PT21USB3PortGen1EmpLevelEn; + uint8_t PT21USB3PortGen1EmpLevel; + uint8_t PT21USB3PortGen1PreshootEn; + uint8_t PT21USB3PortGen1Preshoot; + uint8_t PT21USB3PortGen2Swing; + uint8_t PT21USB3PortGen2Cp0EmpLevelEn; + uint8_t PT21USB3PortGen2Cp0EmpLevel; + uint8_t PT21USB3PortGen2Cp0PreshootEn; + uint8_t PT21USB3PortGen2Cp0Preshoot; + uint8_t PT21USB3PortGen2Cp13EmpLevelEn; + uint8_t PT21USB3PortGen2Cp13EmpLevel; + uint8_t PT21USB3PortGen2Cp13PreshootEn; + uint8_t PT21USB3PortGen2Cp13Preshoot; + uint8_t PT21USB3PortGen2Cp14EmpLevelEn; + uint8_t PT21USB3PortGen2Cp14EmpLevel; + uint8_t PT21USB3PortGen2Cp14PreshootEn; + uint8_t PT21USB3PortGen2Cp14Preshoot; + uint8_t PT21USB3PortGen2Cp15EmpLevelEn; + uint8_t PT21USB3PortGen2Cp15EmpLevel; + uint8_t PT21USB3PortGen2Cp15PreshootEn; + uint8_t PT21USB3PortGen2Cp15Preshoot; + uint8_t PT21USB3PortGen2Cp16EmpLevelEn; + uint8_t PT21USB3PortGen2Cp16EmpLevel; + uint8_t PT21USB3PortGen2Cp16PreshootEn; + uint8_t PT21USB3PortGen2Cp16Preshoot; } PROM21_USB3_PHY_TUNING; typedef struct { - uint8_t PT21USB2P0SlewRate; // 0x2 - uint8_t PT21USB2P0DrivingCurrent; // 0x0 - uint8_t PT21USB2P0Termination; // 0x3 + uint8_t PT21USB2SlewRate; + uint8_t PT21USB2DrivingCurrent; + uint8_t PT21USB2Termination; } PROM21_USB2_PHY_TUNING; typedef struct { - uint8_t PT21PciePortLaneRev[PROM21_NUM_PCIE_LANES / 2]; // 0xf - uint8_t PT21SIProgEnable; // 0xf - uint8_t PT21ThermalThrottle; // 0xf - uint8_t PT21ThermalThreshold; // 0xC0 - uint8_t PT21LtrSmallEnable; // 0xf - uint8_t PT21PcieGen1SwingEnable; // 0xf - uint8_t PT21PcieGen1Swing[PROM21_NUM_PCIE_LANES]; // {0x1f, 0x1f, 0x1f, 0x1f, 0xf, 0xf, 0xf, 0xf, 0x1f, 0x1f, 0x1f, 0x1f} - uint8_t PT21EqPreset; // 0xf - uint8_t PT21PcieClkreqPinSelect[PROM21_NUM_PCIE_CLKREQ]; // { 0x8, 0x4, 0x0, 0x2, 0x3, 0xE } - uint8_t PT21PcieClkreqMode[PROM21_NUM_PCIE_CLKREQ]; // { 0x0, 0x0, 0x0, 0x0, 0x0, 0x2 } - uint8_t PT21PciePortTargetSpeed[PROM21_NUM_PCIE_LANES]; // { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf } - uint8_t PT21PciePortEnable[PROM21_NUM_PCIE_LANES]; // { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf } - uint8_t PT21Usb3GenSelect; // 0xf - uint8_t PT21XhciPortGen[PROM21_XHCI_NUM_USB3_PORTS]; // { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf } - uint8_t PT21L4Usb3Port[PROM21L4_XHCI_NUM_USB3_PORTS]; // { 0xf, 0xf, 0xf, 0xf } - uint8_t PT21L4Usb2Port[PROM21L4_XHCI_NUM_USB2_PORTS]; // { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf } - uint8_t PT21Usb3ort[PROM21_XHCI_NUM_USB3_PORTS]; // { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf } - uint8_t PT21Usb2Port[PROM21_XHCI_NUM_USB2_PORTS]; // { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf } + uint8_t PT21PciePortLaneRev[PROM21_NUM_PCIE_LANES / 2]; + uint8_t PT21SIProgEnable; + uint8_t PT21ThermalThrottle; + uint8_t PT21ThermalThreshold; + uint8_t PT21LtrSmallEnable; + uint8_t PT21PcieGen1SwingEnable; + uint8_t PT21PcieGen1Swing[PROM21_NUM_PCIE_LANES]; + uint8_t PT21EqPreset; + uint8_t PT21GpioPerstEnable; + uint8_t PT21UsbPortLateDisable; + uint8_t PT21PcieClkreqPinSelect[PROM21_NUM_PCIE_CLKREQ]; + uint8_t PT21PcieClkreqMode[PROM21_NUM_PCIE_CLKREQ]; + uint8_t PT21PciePortTargetSpeed[PROM21_NUM_PCIE_LANES]; + uint8_t PT21PciePortEnable[PROM21_NUM_PCIE_LANES]; + uint8_t PT21Usb3GenSelect; + uint8_t PT21XhciPortGen[PROM21_XHCI_NUM_USB3_PORTS]; + uint8_t PT21Usb3Port[PROM21_XHCI_NUM_USB3_PORTS]; + uint8_t PT21Usb2Port[PROM21_XHCI_NUM_USB2_PORTS]; PROM21_SATA_PHY_TUNING PT21SataPhy[PROM21_NUM_SATA_PORTS]; PROM21_USB3_PHY_TUNING PT21USB3Phy[PROM21_XHCI_NUM_USB3_PORTS]; PROM21_USB2_PHY_TUNING PT21USB2Phy[PROM21_XHCI_NUM_USB2_PORTS / 2]; - uint8_t PT21SataMode; // 0x00 - uint8_t PT21SataAggressiveDevSlp[PROM21_NUM_SATA_PORTS]; // { 0xf, 0xf, 0xf, 0xf } - uint8_t PT21SataAggrLinkPmCap; // 0xf - uint8_t PT21SataPscCap; // 0xf - uint8_t PT21SataSscCap; // 0xf - uint8_t PT21SataPortMdPort[PROM21_NUM_SATA_PORTS]; // { 0xf, 0xf, 0xf, 0xf } - uint8_t PT21SataHotPlug; // 0xf - uint8_t PT21SataPTSataCCCSCap; // 0xf - uint8_t PT21AhciMsiCap; // 0xf - uint8_t PT21SataPortEnable[PROM21_NUM_SATA_PORTS]; // { 0xf, 0xf, 0xf, 0xf } - uint8_t PT21Msi; // 0xf - uint8_t PT21Msix; // 0xf - uint8_t PT21HW_LPM; // 0xf - uint8_t PT21DbC; // 0xf - uint8_t PT21XHC_PME; // 0xf - uint8_t PT21Lock; // 0x01 - uint8_t PT21XhciLock; // 0x00 - uint32_t PT21XhciID; // 0x00000000 - uint32_t PT21GppPcieAddress; // 0x00000000 - uint32_t PT21XhciMmio; // 0x00000000 - uint32_t PT21GpioMmio; // 0x00000000 - uint32_t PT21PcieDspSsid; // 0x33281B21 - uint32_t PT21PcieDspXhciSsid; // 0x33281B21 - uint32_t PT21PcieDspAhciSsid; // 0x33281B21 - uint8_t PT21SsidOverride; // 0xf - uint32_t PT21XhciSsid; // 0x11421B21 - uint32_t PT21AhciSsid; // 0x10621B21 - uint32_t PT21PcieUspSsid; // 0x33281B21 + uint8_t PT21SataEnable; + uint8_t PT21SataMode; + uint8_t PT21SataAggressiveDevSlp[PROM21_NUM_SATA_PORTS]; + uint8_t PT21SataAggrLinkPmCap; + uint8_t PT21SataPscCap; + uint8_t PT21SataSscCap; + uint8_t PT21SataPortMdPort[PROM21_NUM_SATA_PORTS]; + uint8_t PT21SataHotPlug; + uint8_t PT21SataPTSataCCCSCap; + uint8_t PT21AhciMsiCap; + uint8_t PT21SataPortEnable[PROM21_NUM_SATA_PORTS]; + uint8_t PT21Msi; + uint8_t PT21Msix; + uint8_t PT21HW_LPM; + uint8_t PT21DbC; + uint8_t PT21XHC_PME; + uint32_t PT21PcieDspSsid; + uint32_t PT21PcieDspXhciSsid; + uint32_t PT21PcieDspAhciSsid; + uint8_t PT21SsidOverride; + uint32_t PT21XhciSsid; + uint32_t PT21AhciSsid; + uint32_t PT21PcieUspSsid; } PROM21_DATA_BLK; -/// PROM openSIL Input Block typedef struct { - uint32_t PT21FwInRamAddress; // 0x0B000000 - uint32_t PT21GpioID; // 0x00000000 - uint64_t PT21FwVersion; // 0x0000000000000000 - uint8_t PT21UsbPortLateDisable; // 0xf - uint8_t PT21TempBusNum; // 0x10 - uint8_t PT21RootBridgeNum; // 0x00 - uint8_t PT21PcieTargetSpeed; // 0x04 - uint8_t PT21IoHcBusNum; // 0x00 - uint32_t PT21IohcBridgeCntl; // 0x00000000 - uint8_t PT21FWLoading; // 0x1 - uint8_t PT21DbgLoadFw; // 0x00 - uint8_t PT21DisableUnusedPciePort; // 0xf - uint8_t PT21SecondPortNumber; // 0xf - uint8_t PT21Revision; // 0x2 - uint8_t PT21TogglePerst; // 0xf - uint8_t PT21RuninRam; // 0x0 - uint8_t PT21ClkPMEnable; // 0xf - uint8_t PT21L1Enable; // 0x1 - uint8_t PT21L1ssEnable; // 0xf - uint8_t PT21ReadThermal; // 0xf - uint8_t PT21GpioPerstEnable; // 0xf - uint8_t PT21GpioTestEnable; // 0xf - uint8_t PT21DelayAfterFWLoading; // 0xf - uint8_t PT21XhciPmeEn; // 0xf - uint32_t PT21CorrErrMask; // 0x6000 + uint8_t BootMode; + uint8_t PT21TempBusNum; + uint8_t PT21PcieTargetSpeed; + uint8_t PT21FWLoading; + uint8_t PT21DbgLoadFw; + uint8_t PT21DisableUnusedPciePort; + uint8_t PT21SecondPortNumber; + uint8_t PT21Revision; + uint8_t PT21TogglePerst; + uint8_t PT21RuninRam; + uint8_t PT21ClkPMEnable; + uint8_t PT21L1Enable; + uint8_t PT21L1ssEnable; + uint8_t PT21ReadThermal; + uint8_t PT21GpioTestEnable; + uint8_t PT21DelayAfterFWLoading; + uint8_t PT21XhciPmeEn; + uint32_t PT21CorrErrMask; + uint32_t PT21FwInRamAddress; + uint32_t PT21ForceGppPcieAddress; + PROM21_GPIO_INIT_TABLE PT21GpioInitTable; PROM21_DATA_BLK Primary; PROM21_DATA_BLK Secondary; +} PROMCLASS_INPUT_BLK; + +typedef struct { + bool SecondaryPTPresent; + bool PT21XhciLock[2]; + uint8_t PT21IoHcBusNum; + uint32_t PT21IohcBridgeCntl; + uint8_t PT21RootBridgeNum; + uint64_t PT21FwVersion; + uint32_t PT21GpioID; + uint32_t PT21XhciMmio[2]; + uint32_t PT21GpioMmio[2]; + uint32_t PT21XhciID[2]; + uint32_t PT21GppPcieAddress[2]; +} PROMCLASS_OUTPUT_BLK; + +typedef struct { + PROMCLASS_INPUT_BLK PromInputBlk; + PROMCLASS_OUTPUT_BLK PromOutputBlk; } PROMCLASS_DATA_BLK; From 0f946edc16e15381af6b9487cd71c1d7206e37c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=BBygowski?= Date: Fri, 8 May 2026 09:30:29 +0200 Subject: [PATCH 5/6] xSIM/SoC/F19M70/IpBlkListF19M70Tp1.c: Hook up PROM21 init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Żygowski --- xSIM/SoC/F19M70/IpBlkListF19M70Tp1.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/xSIM/SoC/F19M70/IpBlkListF19M70Tp1.c b/xSIM/SoC/F19M70/IpBlkListF19M70Tp1.c index 6690d56..16d74e3 100644 --- a/xSIM/SoC/F19M70/IpBlkListF19M70Tp1.c +++ b/xSIM/SoC/F19M70/IpBlkListF19M70Tp1.c @@ -61,7 +61,7 @@ * - MPIO: MPIO firmware initializes and trains the PCIe links * (required for CXL). Due to this dependency, * MPIO is initialized prior to CXL IP block. - * - Prom: PROM21 is dependent on MPIO and is initialized after MPIO. + * - PROM: PROM is dependent on MPIO and is initialized after MPIO. */ const SOC_IP_TABLE SocIpTblF19M70Tp1 = { AMD_FAMILY_19_PHX, // This is the 'Client' F19M70 a.k.a. Phoenix @@ -176,13 +176,6 @@ const SOC_IP_TABLE SocIpTblF19M70Tp1 = { InitializeMpioPhxTp1, InitializeApiMpioPhx }, - { - SilId_PromClass, - PROMCLASS_DATA_SIZE, - PromClassSetInputBlock, - InitializePromTp1, - NULL, - }, { SilId_CcxClass, CCX_DATA_SIZE_ZEN4_PHX, @@ -190,6 +183,13 @@ const SOC_IP_TABLE SocIpTblF19M70Tp1 = { InitializeCcxZen4PhxTp1, InitializeApiZen4Phx }, + { + SilId_PromClass, + PROMCLASS_DATA_SIZE, + PromClassSetInputBlock, + InitializePromTp1, + NULL, + }, {SilId_ListEnd, 0, NULL, NULL, NULL} // End of list marker } }; From aa8d9b6b50b80c2fae95802ae6094b37a6bf5ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=BBygowski?= Date: Tue, 19 May 2026 11:52:55 +0200 Subject: [PATCH 6/6] xUSL/Nbio: Add possibility to set fixed GNB IOAPIC address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Żygowski --- xUSL/Nbio/Common/Nbio.c | 11 +++++++++++ xUSL/Nbio/Common/NbioData.c | 1 + xUSL/Nbio/NbioClass-api.h | 1 + 3 files changed, 13 insertions(+) diff --git a/xUSL/Nbio/Common/Nbio.c b/xUSL/Nbio/Common/Nbio.c index 9613c68..528599a 100644 --- a/xUSL/Nbio/Common/Nbio.c +++ b/xUSL/Nbio/Common/Nbio.c @@ -383,6 +383,17 @@ NbioIoApicInit ( } } else { NBIO_TRACEPOINT(SIL_TRACE_INFO, "We don't need reserved IOAPIC MMIO space\n"); + if (NbioIpBlockData->NbioConfigData.CfgGnbIoapicAddress != 0) { + NBIO_TRACEPOINT(SIL_TRACE_INFO, "Using fixed IOAPIC MMIO address %x\n", + NbioIpBlockData->NbioConfigData.CfgGnbIoapicAddress); + GnbHandle = GetGnbHandle(SilContext); + if (GnbHandle) { + NbioXfer->NbioIoApicMmioAddress( + GnbHandle, + NbioIpBlockData->NbioConfigData.CfgGnbIoapicAddress + ); + } + } } if (NbioIpBlockData->NbioConfigData.IoApicIdPreDefineEn) { diff --git a/xUSL/Nbio/Common/NbioData.c b/xUSL/Nbio/Common/NbioData.c index a3a9f3f..e7c2dcb 100644 --- a/xUSL/Nbio/Common/NbioData.c +++ b/xUSL/Nbio/Common/NbioData.c @@ -18,6 +18,7 @@ const NBIO_CONFIG_DATA mNbioConfigDataDflts = { .IoApicMMIOAddressReservedEnable = CONFIG_IOAPIC_MMIO_ADDRESS_RESERVED_ENABLE, .IoApicIdPreDefineEn = CONFIG_IOAPIC_ID_PREDEFINE_EN, .IoApicIdBase = CONFIG_IOAPIC_ID_BASE, + .CfgGnbIoapicAddress = 0, .NbifMgcgHysteresis = CONFIG_NBIF_MGCG_HYSTERESIS, .SyshubMgcgHysteresis = CONFIG_SYSHUB_MGCG_HYSTERESIS, .IohcNonPCIBarInitSmu = CONFIG_IOHC_NONPCI_BAR_INIT_SMU, diff --git a/xUSL/Nbio/NbioClass-api.h b/xUSL/Nbio/NbioClass-api.h index d13093a..e034170 100644 --- a/xUSL/Nbio/NbioClass-api.h +++ b/xUSL/Nbio/NbioClass-api.h @@ -46,6 +46,7 @@ typedef struct { bool IoApicMMIOAddressReservedEnable; ///< Enable Ioapic MMIO reserved from GNB driver. 0:Disable bool IoApicIdPreDefineEn; ///< Enable assign IOAPIC ID uint8_t IoApicIdBase; ///< Base NBIO IOAPIC ID. ID assigned start from this value */ + uint64_t CfgGnbIoapicAddress; ///< Fixed Ioapic MMIO address if not reserved from RcMGr. 0:Disable uint8_t NbifMgcgHysteresis; ///< NBIF MGCG HYSTERESIS for gating count uint8_t SyshubMgcgHysteresis; ///< NBIF MGCG HYSTERESIS for gating count bool IohcNonPCIBarInitSmu; ///< Configure non pci device bar for SMU