diff --git a/src/soc/intel/cannonlake/fsp_params.c b/src/soc/intel/cannonlake/fsp_params.c index 73b1bb53ed..dd9c806039 100644 --- a/src/soc/intel/cannonlake/fsp_params.c +++ b/src/soc/intel/cannonlake/fsp_params.c @@ -524,6 +524,53 @@ void platform_fsp_silicon_init_params_cb(FSPS_UPD *supd) params->PeiGraphicsPeimInit = 0; params->PavpEnable = CONFIG(PAVP); + + /* + * Prevent FSP from programming write-once subsystem IDs by providing + * a custom SSID table. Must have at least one entry for the FSP to + * use the table. + */ + struct svid_ssid_init_entry { + union { + struct { + uint64_t reg:12; /* Register offset */ + uint64_t function:3; + uint64_t device:5; + uint64_t bus:8; + uint64_t :4; + uint64_t segment:16; + uint64_t :16; + }; + uint64_t segbusdevfuncregister; + }; + struct { + uint16_t svid; + uint16_t ssid; + }; + uint32_t reserved; + }; + + /* + * The xHCI and HDA devices have RW/L rather than RW/O registers for + * subsystem IDs and so must be written before FspSiliconInit locks + * them with their default values. + */ + const pci_devfn_t devfn_table[] = { PCH_DEVFN_XHCI, PCH_DEVFN_HDA }; + static struct svid_ssid_init_entry ssid_table[ARRAY_SIZE(devfn_table)]; + + for (i = 0; i < ARRAY_SIZE(devfn_table); i++) { + ssid_table[i].reg = PCI_SUBSYSTEM_VENDOR_ID; + ssid_table[i].device = PCI_SLOT(devfn_table[i]); + ssid_table[i].function = PCI_FUNC(devfn_table[i]); + dev = pcidev_path_on_root(devfn_table[i]); + if (dev) { + ssid_table[i].svid = dev->subsystem_vendor; + ssid_table[i].ssid = dev->subsystem_device; + } + } + + params->SiSsidTablePtr = (uintptr_t)ssid_table; + params->SiNumberOfSsidTableEntry = ARRAY_SIZE(ssid_table); } /* Mainboard GPIO Configuration */