/* SPDX-License-Identifier: GPL-2.0-only */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * SoC implementation * * Add all known fixed memory ranges for Host Controller/Memory * controller. */ void soc_add_fixed_mmio_resources(struct device *dev, int *index) { static const struct sa_mmio_descriptor soc_fixed_resources[] = { { MCHBAR, MCH_BASE_ADDRESS, MCH_BASE_SIZE, "MCHBAR" }, { DMIBAR, DMI_BASE_ADDRESS, DMI_BASE_SIZE, "DMIBAR" }, { EPBAR, EP_BASE_ADDRESS, EP_BASE_SIZE, "EPBAR" }, { REGBAR, REG_BASE_ADDRESS, REG_BASE_SIZE, "REGBAR" }, { EDRAMBAR, EDRAM_BASE_ADDRESS, EDRAM_BASE_SIZE, "EDRAMBAR" }, /* first field (sa_mmio_descriptor.index) is not used, setting to 0: */ { 0, CRAB_ABORT_BASE_ADDR, CRAB_ABORT_SIZE, "CRAB_ABORT" }, { 0, LT_SECURITY_BASE_ADDR, LT_SECURITY_SIZE, "LT_SECURITY" }, { 0, IO_APIC_ADDR, APIC_SIZE, "APIC" }, // PCH_PRESERVERD covers: // TraceHub SW BAR, PMC MBAR, SPI BAR0, SerialIo BAR in ACPI mode // eSPI LGMR BAR, eSPI2 SEGMR BAR, TraceHub MTB BAR, TraceHub FW BAR // IOE PMC BAR, Tracehub RTIT BAR (SOC), HECI{1,2,3} BAR0 // see fsp/ClientOneSiliconPkg/Fru/MtlSoc/Include/PchReservedResources.h { 0, PCH_PRESERVED_BASE_ADDRESS, PCH_PRESERVED_BASE_SIZE, "PCH_RESERVED" }, }; sa_add_fixed_mmio_resources(dev, index, soc_fixed_resources, ARRAY_SIZE(soc_fixed_resources)); /* Add Vt-d resources if VT-d is enabled */ if ((pci_read_config32(dev, CAPID0_A) & VTD_DISABLE)) return; sa_add_fixed_mmio_resources(dev, index, soc_vtd_resources, ARRAY_SIZE(soc_vtd_resources)); } /* * set MMIO resource's fields */ static void set_mmio_resource( struct sa_mmio_descriptor *resource, uint64_t base, uint64_t size, const char *description) { if (resource == NULL) { printk(BIOS_ERR, "%s: argument resource is NULL for %s\n", __func__, description); return; } resource->base = base; resource->size = size; resource->description = description; } int soc_get_uncore_prmmr_base_and_mask(uint64_t *prmrr_base, uint64_t *prmrr_mask) { msr_t msr; msr = rdmsr(MSR_PRMRR_BASE_0); *prmrr_base = (uint64_t)msr.hi << 32 | msr.lo; msr = rdmsr(MSR_PRMRR_PHYS_MASK); *prmrr_mask = (uint64_t)msr.hi << 32 | msr.lo; return 0; } /* * SoC implementation * * Add all known configurable memory ranges for Host Controller/Memory * controller. */ void soc_add_configurable_mmio_resources(struct device *dev, int *resource_cnt) { uint64_t size, base, tseg_base; int count = 0; struct sa_mmio_descriptor cfg_rsrc[6]; /* Increase size when adding more resources */ /* MMCONF */ size = get_mmcfg_size(dev); if (size > 0) set_mmio_resource(&(cfg_rsrc[count++]), CONFIG_ECAM_MMCONF_BASE_ADDRESS, size, "MMCONF"); /* DSM */ size = get_dsm_size(dev); if (size > 0) { base = pci_read_config32(dev, DSM_BASE_ADDR_REG) & 0xFFF00000; set_mmio_resource(&(cfg_rsrc[count++]), base, size, "DSM"); } /* TSEG */ size = sa_get_tseg_size(); tseg_base = sa_get_tseg_base(); if (size > 0) set_mmio_resource(&(cfg_rsrc[count++]), tseg_base, size, "TSEG"); /* PMRR */ size = get_valid_prmrr_size(); if (size > 0) { uint64_t mask; if (soc_get_uncore_prmmr_base_and_mask(&base, &mask) == 0) { base &= mask; set_mmio_resource(&(cfg_rsrc[count++]), base, size, "PMRR"); } else { printk(BIOS_ERR, "SA: Failed to get PRMRR base and mask\n"); } } /* GSM */ size = get_gsm_size(dev); if (size > 0) { base = sa_get_gsm_base(); set_mmio_resource(&(cfg_rsrc[count++]), base, size, "GSM"); } /* DPR */ size = get_dpr_size(dev); if (size > 0) { /* DPR just below TSEG: */ base = tseg_base - size; set_mmio_resource(&(cfg_rsrc[count++]), base, size, "DPR"); } /* Add all the above */ sa_add_fixed_mmio_resources(dev, resource_cnt, cfg_rsrc, count); } /* * SoC implementation * * Perform System Agent Initialization during Ramstage phase. */ void soc_systemagent_init(struct device *dev) { struct soc_power_limits_config *soc_config; struct device *sa; uint16_t sa_pci_id; config_t *config; /* Enable Power Aware Interrupt Routing */ enable_power_aware_intr(); config = config_of_soc(); /* Get System Agent PCI ID */ sa = pcidev_path_on_root(PCI_DEVFN_ROOT); sa_pci_id = sa ? pci_read_config16(sa, PCI_DEVICE_ID) : 0xFFFF; /* Choose a power limits configuration based on the SoC SKU type, * differentiated here based on SA PCI ID. */ switch (sa_pci_id) { case PCI_DID_INTEL_MTL_P_ID_1: soc_config = &config->power_limits_config[MTL_P_POWER_LIMITS_1]; break; case PCI_DID_INTEL_MTL_P_ID_2: soc_config = &config->power_limits_config[MTL_P_POWER_LIMITS_2]; break; case PCI_DID_INTEL_MTL_P_ID_3: soc_config = &config->power_limits_config[MTL_P_POWER_LIMITS_3]; break; case PCI_DID_INTEL_MTL_P_ID_4: soc_config = &config->power_limits_config[MTL_P_POWER_LIMITS_4]; break; default: printk(BIOS_ERR, "unknown SA ID: 0x%4x, skipping power limits configuration\n", sa_pci_id); return; } /* Remove once commented line below is enabled */ (void)soc_config; /* UPDATEME: Need to enable later */ //set_power_limits(MOBILE_SKU_PL1_TIME_SEC, soc_config); } uint32_t soc_systemagent_max_chan_capacity_mib(u8 capid0_a_ddrsz) { switch (capid0_a_ddrsz) { case 1: return 8192; case 2: return 4096; case 3: return 2048; default: return 65536; } } uint64_t get_mmcfg_size(const struct device *dev) { uint32_t pciexbar_reg; uint64_t mmcfg_length; if (!dev) { printk(BIOS_DEBUG, "%s : device is null\n", __func__); return 0; } pciexbar_reg = pci_read_config32(dev, PCIEXBAR); if (!(pciexbar_reg & (1 << 0))) { printk(BIOS_DEBUG, "%s : PCIEXBAR disabled\n", __func__); return 0; } switch ((pciexbar_reg & MASK_PCIEXBAR_LENGTH) >> PCIEXBAR_LENGTH_LSB) { case PCIEXBAR_LENGTH_4096MB: mmcfg_length = 4 * ((uint64_t)GiB); break; case PCIEXBAR_LENGTH_2048MB: mmcfg_length = 2 * ((uint64_t)GiB); break; case PCIEXBAR_LENGTH_1024MB: mmcfg_length = 1 * GiB; break; case PCIEXBAR_LENGTH_512MB: mmcfg_length = 512 * MiB; break; case PCIEXBAR_LENGTH_256MB: mmcfg_length = 256 * MiB; break; case PCIEXBAR_LENGTH_128MB: mmcfg_length = 128 * MiB; break; case PCIEXBAR_LENGTH_64MB: mmcfg_length = 64 * MiB; break; default: printk(BIOS_DEBUG, "%s : PCIEXBAR - invalid length (0x%x)\n", __func__, pciexbar_reg & MASK_PCIEXBAR_LENGTH); mmcfg_length = 0x0; break; } return mmcfg_length; } uint64_t get_dsm_size(const struct device *dev) { // - size : B0/D0/F0:R 50h [15:8] uint32_t reg32 = pci_read_config32(dev, GGC); uint64_t size; uint32_t size_field = (reg32 & MASK_DSM_LENGTH) >> MASK_DSM_LENGTH_LSB; if (size_field <= 0x10) { // 0x0 - 0x10 size = size_field * 32 * MiB; } else if ((size_field >= 0xF0) && (size_field >= 0xFE)) { size = ((uint64_t)size_field - 0xEF) * 4 * MiB; } else { switch (size_field) { case 0x20: size = 1 * GiB; break; case 0x30: size = 1536 * MiB; break; case 0x40: size = 2 * (uint64_t)GiB; break; default: printk(BIOS_DEBUG, "%s : DSM - invalid length (0x%x)\n", __func__, size_field); size = 0x0; break; } } return size; } uint64_t get_gsm_size(const struct device *dev) { const u32 gsm_size = pci_read_config32(dev, GGC); uint64_t size; uint32_t size_field = (gsm_size & MASK_GSM_LENGTH) >> MASK_GSM_LENGTH_LSB; switch (size_field) { case 0x0: size = 0; break; case 0x1: size = 2 * MiB; break; case 0x2: size = 4 * MiB; break; case 0x3: size = 8 * MiB; break; default: size = 0; break; } return size; } uint64_t get_dpr_size(const struct device *dev) { uint64_t size; uint32_t dpr_reg = pci_read_config32(dev, DPR_REG); uint32_t size_field = (dpr_reg & MASK_DPR_LENGTH) >> MASK_DPR_LENGTH_LSB; size = (uint64_t)size_field * MiB; return size; }