MSI PRO B850-P coreboot port: USB initialization and AM5 IP block porting

Introduction

This blog post continues the MSI PRO B850-P coreboot porting series. In Part 1 we brought up the bootblock and romstage and mapped all USB, SATA, and PCIe ports. In Part 2 we added the USB and PCIe devicetree descriptors and integrated Phoenix openSIL as a submodule. In Part 3 we ported the MPIO, SMU, NBIO, FCH SD, FCH ACPI, and RcMgr IP blocks, reaching a state where the platform almost booted into Linux.

This post covers the work that followed: porting the CCX and FCH IP blocks for the AM5 desktop variant of Phoenix and adding the missing USB initialization code in openSIL. The relevant coreboot changes are tracked in this pull request on the Dasharo coreboot downstream repository. The openSIL changes are split across two pull requests: first for CCX changes and second for FCH changes, both on the 3mdeb openSIL downstream repository.

The milestones covered in this post are:

Task 6. Port Phoenix AM5 specific code to OpenSIL:

  • Milestone b. Cover Phoenix mobile and desktop silicon initialization differences in OpenSIL (CCX, FCH, MEM)

    Most of the code is similar or identical between desktop and mobile parts. However, care must be taken for possible small differences. The goal is to analyze and compare the desktop and mobile differences. This milestone covers CCX, FCH and MEM blocks.

  • Milestone d. Cover Phoenix mobile and desktop silicon initialization differences in OpenSIL (DF, RcMgr, APOB)

    Most of the code is similar or identical between desktop and mobile parts. However, care must be taken for possible small differences. The goal is to analyze and compare the desktop and mobile differences. This milestone covers DF, RcMgr and APOB blocks.

Task 8. Validation & stabilization:

  • Milestone b. Test environment preparation for MSI PRO B850-P

    Prepare test environment and laboratory infrastructure for automated testing of MSI PRO B850-P platform.

Previous USB initialization failures

In the previous blog posts one could observe messages like:

1
2
xhci_resource_for_each_ext_cap: No extended capabilities defined
xhci_acpi_name: USB3 port 0 does not exist on xHC PCI: 00:0e:00.3

These errors came from inactive CPU-integrated USB controllers. When coreboot or the OS attempted to read the MMIO resources of an uninitialized controller, the hardware returned 0xFF bytes for all reads. Linux’s xHCI driver correctly interpreted this as the absence of extended capabilities and missing port definitions - but the root cause was that openSIL had never properly initialized the USB controllers in the first place.

The Phoenix PoC openSIL was written for mobile Phoenix CPUs, which do not expose all of the USB controllers that the desktop AM5 variant has. As a result, the USB initialization code was effectively absent for desktop parts. This made the SoC USB controllers invisible to the OS despite being physically present on the silicon.

To fix this, we had to implement the missing USB initialization logic in openSIL. The effort turned out to be substantially larger than anticipated - roughly 1000 lines of new code spread across the FCH USB subsystem. The FCH pull request is a single commit that adds the missing initialization for the USB controllers and several related FCH subsystems. The changes touch 14 files across the openSIL tree. From the finished work perspective, it almost seemed like only half of the necessary initialization was added to openSIL by AMD, despite it not being sufficient to properly enumerate USB devices or even start the USB controller. Not sure why the code was left in such a state nor if it was tested to work with EDK2 or any operating system.

HFP and HID controller initialization

Phoenix AM5 exposes three MMIO-mapped controllers that the mobile PoC never initialized: the Host Finger Print (HFP) controller at 0xFEC11000 and two HID (Human Interface Device) controllers at 0xFEC12000 and 0xFEC13000. The new code adds base address constants for these controllers:

1
2
3
4
#define FCH_HFP_BASE_ADDRESS   0xFEC11000ul
#define FCH_HID2_BASE_ADDRESS  0xFEC12000ul
#define FCH_HID_BASE_ADDRESS   0xFEC13000ul
#define HID_CONTROLLER_STEP    0x1000

Two new initialization functions, ProgramFchEnvHfpInit() and ProgramFchEnvHidInit(), are called from FchHwAcpiPrePcieInit(). For each HID controller, the helper FchHidInitPerCtrlr() configures the SPI read mode and speed. Without these calls, the HFP and HID devices would appear as MMIO holes and could confuse the OS during PCI resource allocation.

On the coreboot side, a corresponding commit declares the three devices in chipset_opensil.cb:

1
2
3
device mmio 0xfec11000 off end   # HFP
device mmio 0xfec12000 off end   # HID_2
device mmio 0xfec13000 off end   # HID

SPI TPM decode

A new lpc.c file for the Phoenix SoC implements soc_lpc_tpm_decode_spi(), which writes two registers to enable SPI TPM operation. This ensures the discrete SPI TPM on the MSI PRO B850-P is accessible to coreboot and the OS. Previously, while the address decode was programmed by coreboot, some silicon-specific settings to make the SPI TPM work properly were required. A similar situation occurred with the Turin platform.

USB initialization via SMU service

The most significant new function in the FCH PR is FchXhciUsbInitSmuService(), which initializes the xHCI USB controllers by sending initialization requests through the SMU (System Management Unit) communication channel. The SMU is the power management microcontroller embedded in the SoC, and on Phoenix AM5 it is responsible for enabling the USB controller power domains and clocking before the xHCI controllers become accessible.

Previously, the openSIL USB initialization flow skipped the SMU service call entirely on the PoC branch, which meant the controllers were powered down and returned garbage on MMIO reads. Adding FchXhciUsbInitSmuService() and integrating it into the post-MPIO (post PCI Express training) initialization sequence corrects this.

New USB-related register definitions were added for both USB3 and USB4 controllers, and a new Xfer function call type FCH_USB_AFTER_PCIE_TRAINING_DONE allows FCH USB initialization to be scheduled after PCIe training completes - the correct point at which USB4 ports can be brought up (because USB4 depends on PCIe ports to provide PCIe tunnelling).

USB configuration structures

The FCH PR also restructures the USB configuration interface. New structures and the USB_INIT_DATA give coreboot a clean set of mainboard-customizable variables to specify per-controller and per-port enablement, PHY tuning parameters, and overcurrent protection via the mainboard’s devicetree.

coreboot side: USB PHY configuration

With the openSIL FCH PR in place, the coreboot mainboard code can now provide meaningful USB PHY configuration. Commit 0c72118 in the coreboot PR adds the USB controller configuration to devicetree.cb, with tuned PHY parameters derived from vendor BIOS register dumps.

Eight USB 2.0 ports receive PHY tuning:

1
2
3
4
5
6
7
8
register "usb2[0]" = "{
    .compdistune  = 0x1,
    .pllbtune     = 0x1,
    .pllptune     = 0xc,
    .sqrxtune     = 0x2,
    .txpreempamptune = 0x3,
    .txvreftune   = 0x3,
}"

Three USB 3.0 ports receive transmitter configuration:

1
2
3
4
register "usb3[0]" = "{
    .tx_term_ctrl  = 0x2,
    .tx_vboost_lvl = 0x5,
}"

All three combo PHY ports are set to USB-only mode (USB_COMBO_PHY_MODE_USB_ONLY), disabling the PCIe/SATA multiplexing on those lanes. Ports 0 and 2 are forced to USB3 Gen1 speed to avoid link instability during bring-up.

The commit also adds detailed overcurrent protection pin mappings for both USB 2.0 and 3.0 controllers, matching the pin assignments found in the vendor BIOS.

CCX changes for AM5

The CCX pull request adds several Zen 4 / AM5 specific settings to the CCX IP block.

New CPU feature flags

Three new boolean fields are added to the CCX API structure and initialized with AM5-appropriate defaults:

Field Default Description
AmdEnableFSRM true Fast Short REP Move
AmdEnableERMS true Enhanced REP Move String
AmdStatisticalCorrectPredictor false Statistical Correct Predictor

FSRM and ERMS are string operation optimizations that are beneficial on modern CPUs. The SCP feature is disabled by default.

CPU pause delay configuration

A new switch statement in CcxMiscInit.c handles five pause delay modes (0–4) plus a default (0xFF), each writing a different value into MSRxC00110E2. Pause delay tuning affects CPU power management transitions and can impact latency in workloads that use spin-wait loops. Getting this right on a desktop part requires values different from what the mobile PoC had hardcoded.

APIC ID read fix

A subtle but important fix changes how the BSP (Bootstrap Processor) reads its own APIC ID during early initialization. The original code used CPUID leaf 0x00000001 and extracted the APIC ID from bits 31:24 of EBX. The corrected code uses CPUID leaf 0x0000000B (Extended Topology Enumeration) and reads the full 32-bit APIC ID from EDX:

1
2
3
4
5
6
7
// Before
CpuidResult = xUslGetRawIdOnExecutingCore(0x00000001, 0x0, ...);
apicId = (CpuidResult.ebx >> 24) & 0xFF;

// After
CpuidResult = xUslGetRawIdOnExecutingCore(0x0000000B, 0x0, ...);
apicId = CpuidResult.edx;

On desktop AM5 CPUs, CPUID leaf 0x1 only returns an 8-bit initial APIC ID, which is insufficient for systems with more than 255 logical CPUs. The 0xB leaf returns the full 32-bit x2APIC ID. While a single-socket consumer desktop is unlikely to exceed 255 logical CPUs, using the correct leaf ensures future compatibility and eliminates a potential source of mis-enumeration.

Zen 4 MSR table updates

CcxResetTablesZen4.c receives several MSR table adjustments:

  • MSR_LS_CFG mask is narrowed: 0x007C4000000000000x005C400000000000, removing a bit that should not be modified on desktop Phoenix parts
  • A new entry for MSR_C0011004 is added
  • MSR_FP_CFG entries are updated for Zen 4 variants

MEM IP block: no adaptation needed

A pleasant surprise during this phase was that the Memory (MEM) IP block required no changes for the AM5 desktop variant. After a careful analysis of the MEM initialization path in the Phoenix PoC, the code is sufficiently generic to handle both mobile and desktop memory topologies. This is consistent with what was observed during the Turin and Genoa porting work, where the memory subsystem was also largely common across socket types.

Since no budget was needed for MEM, the effort was redirected to the FCH IP block where the USB initialization gap was significantly larger than anticipated. Together with the CCX changes and the FCH changes, Milestone 6b is fully completed.

Data Fabric MMIO coverage: completing the RcMgr picture

In the previous blog post we made small changes to the Resource Manager (RcMgr) IP block. After a deeper analysis, it occurred that these changes complete the adaptation of the RcMgr IP block for AM5. The crucial fix was the coverage of MMIO space below the PCIe MMCONF base address, which was previously unallocated.

The RcMgr code missed a hardcoded macro, causing the code to assign a second MMIO entry for the primary root bridge - a somewhat underhanded workaround, especially given that the RcMgr code is otherwise written generically to support both small systems and complex servers. After the fix, the Data Fabric MMIO configuration registers show full coverage:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[SPEW ]  === Data Fabric MMIO configuration registers ===
[SPEW ]  idx             base            limit  control R W NP F-ID
[SPEW ]    0         f0000000         febfffff   130003 x x      13
[SPEW ]    1      10000000000     3ffcffffffff   130003 x x      13
[SPEW ]    2         c0000000         dfffffff   130003 x x      13
[SPEW ]    3                0             ffff   130000          13
[SPEW ]    4                0             ffff   130000          13
[SPEW ]    5                0             ffff   130000          13
[SPEW ]    6                0             ffff   130000          13
[SPEW ]    7                0             ffff   130000          13

Entry index 2 (0xc00000000xdfffffff) was not present before the RcMgr changes. Without it, PCI devices with 32-bit BARs were forced to fit in the range 0xf0000000 to 0xfebfffff, which in certain scenarios would not be sufficient (e.g. a desktop system with many add-on PCIe cards, like GPUs). Now the full MMIO space below 4 GiB is properly covered and the range from 0xc0000000 to 0xdfffffff is usable by PCI devices.

DF and APOB: no AM5-specific differences

The analysis of the Data Fabric (DF) and APOB (AMD Platform Onboarding Buffer) IP blocks revealed that there are no differences in initialization between the mobile Phoenix and the AM5 desktop platform. The DF initialization path is generic enough to handle both, and the APOB structures parsing code does not depend on socket/package type (at least for Phoenix processor family).

This is the same situation as with the MEM block: the PoC code generalizes well, and no porting effort was required. As a result, Milestone 6d is completed at 33% - RcMgr has been adapted (the most substantial piece), but the DF and APOB budget was redirected towards the GFX IP block, where the work remains.

GFX: new attempts, still blocked

Since the previous blog post, we tried two new approaches to bring up integrated graphics:

  1. Force 32-bit framebuffer resources. The UMA on Phoenix AM5 is allocated above 4 GiB. Attempting to force the GFX resources to be 32-bit to allow VBIOS access below the 4 GiB boundary was not sufficient. The UMA allocation is controlled by APCB, which is static in coreboot and cannot be changed without reconfiguring the APCB and rebuilding the firmware image. Attempts to reconfigure UMA below 4GiB in APCB also failed.

  2. Run the Phoenix VBIOS Option ROM in Yabel/x86emu. We attempted to execute the VBIOS via the x86 emulator (CONFIG_PCI_OPTION_ROM_RUN_YABEL) with verbose debug output enabled. The attempt required a build fix - the Yabel and x86emu debug headers were missing string.h and stdio.h, and the monotonic timer API used in debug macros was outdated. These build issues have been fixed in coreboot PR, but the VBIOS execution itself still did not succeed in initializing the display engine, nor did the debug output give us any hints about what was going wrong.

Despite the fixes enabling the VBIOS path to be exercised, the integrated graphics remain non-functional. GFX initialization will continue to be investigated in subsequent weeks. The remaining 20% budget from Milestone 6d and the CXL budget freed in the previous phase will be directed toward this effort, as stated in the part 3 post.

Boot progress: almost to the login prompt

The coreboot console log with all the changes from this phase applied demonstrates the clearest sign of progress yet. The platform no longer hangs during PCIe enumeration in Linux, an issue that had been present since Part 2 and was caused by the inactive CPU USB controllers returning 0xFF on MMIO reads, which confused the Linux kernel.

With proper USB controller initialization in place, PCIe enumeration completes and Linux continues booting. The platform now almost reaches the login prompt. The only component that reports hard faults is the Promontory B850 chipset, for which initialization has not been implemented yet:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
pci 0000:03:0a.0: PCI bridge to [bus 0a]
pci 0000:03:0a.0: enabling Extended Tags
pci 0000:03:0a.0: broken device, retraining non-functional downstream link at 2.5GT/s
pci 0000:03:0a.0: retraining failed
pci 0000:03:0a.0: PME# supported from D0 D3hot D3cold
pci 0000:03:0b.0: [1022:43f5] type 01 class 0x060400 PCIe Switch Downstream Port
pci 0000:03:0b.0: PCI bridge to [bus 0b]
pci 0000:03:0b.0: enabling Extended Tags
pci 0000:03:0b.0: broken device, retraining non-functional downstream link at 2.5GT/s
pci 0000:03:0b.0: retraining failed

This is expected - Promontory support is reserved for a dedicated milestone:

Task 6. Port Phoenix AM5 specific code to openSIL:

  • Milestone a. Port Promontory I/O expansion chipset support to OpenSIL

    The Phoenix OpenSIL support only covers mobile Phoenix CPUs. Board designs with desktop CPUs also use the Promontory chipset to provide additional I/O expansion on the board. The goal is to add Promontory 21 initialization to Phoenix OpenSIL by adding a new IP block and a Kconfig option to differentiate between mobile and desktop Phoenix CPUs.

Test environment integration

With the platform reaching an advanced state of boot, it is now practical to integrate the MSI PRO B850-P into an automated testing infrastructure. The open-source-firmware-validation pull request adds the relevant platform configuration to 3mdeb’s laboratory infrastructure for automated testing of the MSI PRO B850-P WIFI variant.

The initial test setup validates that the platform boots to the setup menu and parses the information printed on the main menu via serial console. Sample test results are available here (the content is raw HTML; save and open in a browser to view).

Early test results

Because the OS does not fully boot yet, the set of tests that can run is limited to early firmware-visible functionality: boot order, UEFI setup menu navigation, and serial console output parsing. Once Promontory chipset support is added, we believe the OS will boot fully, and the test set will be expanded significantly.

This fulfills Task 8 Milestone b, which is the foundation required to deliver Milestone 8c (automated test results for MSI PRO B850-P).

A note on PoC code quality

The work in this phase reinforced an observation about the Phoenix PoC openSIL code quality that deserves to be called out explicitly. The PoC code did not initialize the USB controllers almost at all. For many firmware engineers, USB controller initialization is table stakes - a basic requirement for a bootable system. Skipping it entirely could be considered a significant gap in the PoC scope.

This continues a trend we have observed across the entire Phoenix porting effort: many components require substantial amounts of new initialization code to reach a working state. The FCH USB work alone accounted for roughly 1000 lines of new code. We did not encounter gaps of this magnitude during the Turin project. We also have the GFX IP block initialization coming, which currently does nothing but dump PHY tuning values.

It is worth noting that the Phoenix PoC was released significantly later than the Turin PoC - over half a year of delay - which may reflect the difficulty of adapting the common openSIL infrastructure to a consumer desktop platform where the number of IP blocks and their interdependencies are different from a server platform. Without a sample UEFI board reference implementation for Phoenix (which exists for Turin and Genoa), the reference material available to guide the porting work is also more limited.

Summary

This post covered the fourth phase of the MSI PRO B850-P coreboot port:

  1. USB initialization in openSIL: Added approximately 1000 lines of missing USB initialization code to the FCH IP block, including xHCI controller bring-up via SMU service, HFP and HID controller initialization, and USB configuration structures. This resolves the xhci_resource_for_each_ext_cap and xhci_acpi_name errors seen in previous posts.

  2. CCX AM5 changes: Added FSRM, ERMS, and SCP CPU feature flags with AM5-appropriate defaults, fixed the APIC ID enumeration to use the correct CPUID leaf, and updated the Zen 4 MSR initialization tables.

  3. MEM IP block: No adaptation required; the existing code is generic enough for desktop AM5. Budget redirected to FCH USB work.

  4. USB configuration in coreboot: Added per-port PHY tuning, overcurrent protection pin mappings, and combo PHY mode configuration to the MSI PRO B850-P devicetree.

  5. SPI TPM decode: Added soc_lpc_tpm_decode_spi() for explicit SPI TPM address decode programming, and disabled USB PHY CMCLK Z-state gating to prevent link failures during initialization.

  6. RcMgr MMIO coverage: Confirmed and completed the MMIO space coverage fix from the previous phase. Data Fabric entry index 2 now covers 0xc00000000xdfffffff, ensuring sufficient MMIO space for 32-bit PCI devices.

  7. DF and APOB: No AM5-specific differences found. Budget redirected toward the GFX IP block.

  8. GFX: Two new approaches (forced 32-bit resources and Yabel VBIOS execution) were attempted without success. Investigation continues.

  9. Test infrastructure: MSI PRO B850-P WIFI has been integrated into 3mdeb’s automated testing infrastructure, fulfilling Milestone 8b.

The milestone completion status is as follows:

Task 6. Port Phoenix AM5 specific code to OpenSIL:

  • Milestone b. Cover Phoenix mobile and desktop silicon initialization differences in OpenSIL (CCX, FCH, MEM) - 100% complete
  • Milestone d. Cover Phoenix mobile and desktop silicon initialization differences in OpenSIL (DF, RcMgr, APOB) - 33% complete (RcMgr done; DF and APOB had no AM5 differences; remaining budget redirected to GFX)

Task 8. Validation & stabilization:

  • Milestone b. Test environment preparation for MSI PRO B850-P - 100% complete

The most visible proof of progress is that the platform no longer hangs during PCIe enumeration in Linux and almost reaches the login prompt - something that was not possible at the end of Part 3. The remaining blocker seems to be the Promontory B850 chipset, which will be addressed in the next dedicated milestone.

For OEMs & ODMs

If you are an OEM or ODM and see the value in AMD openSIL support for your products, our team can help make it a reality. Reach out to us via our contact form or email us at contact<at>3mdeb<dot>com to start the conversation.

Unlock the full potential of your hardware and secure your firmware with the experts at 3mdeb! If you’re looking to boost your product’s performance and protect it from potential security threats, our team is here to help. Schedule a call with us or drop us an email at contact<at>3mdeb<dot>com to start unlocking the hidden benefits of your hardware. And if you want to stay up-to-date on all things firmware security and optimization, be sure to sign up for our newsletter:

Huge kudos to the NLnet Foundation for sponsoring the project.

NLnet


Michał Żygowski
Firmware Engineer with networking background. Feels comfortable with low-level development using C/C++ and assembly. Interested in advanced hardware features, security and coreboot. Core developer of coreboot. Maintainer of Braswell SoC, PC Engines, Protectli and Libretrend platforms.