/* SPDX-License-Identifier: GPL-2.0-only */ #include #include #include #include #include #include #include #include #include #include #include #include #include "i945.h" static void mch_domain_read_resources(struct device *dev) { uint32_t pci_tolm; uintptr_t tolud; struct device *const d0f0 = pcidev_on_root(0, 0); int idx = 3; pci_domain_read_resources(dev); /* Can we find out how much memory we can use at most * this way? */ pci_tolm = find_pci_tolm(dev->downstream); printk(BIOS_DEBUG, "pci_tolm: 0x%x\n", pci_tolm); tolud = pci_read_config8(d0f0, TOLUD) << 24; printk(BIOS_SPEW, "Top of Low Used DRAM: 0x%08lx\n", tolud); /* Report the memory regions */ ram_range(dev, idx++, 0, 0xa0000); ram_from_to(dev, idx++, 1 * MiB, (uintptr_t)cbmem_top()); /* TSEG */ uintptr_t tseg_base; size_t tseg_size; smm_region(&tseg_base, &tseg_size); mmio_range(dev, idx++, tseg_base, tseg_size); /* cbmem_top can be shifted downwards due to alignment. Mark the region between cbmem_top and tseg_base as unusable */ if ((uintptr_t)cbmem_top() < tseg_base) { printk(BIOS_DEBUG, "Unused RAM between cbmem_top and TOM: 0x%lx\n", tseg_base - (uintptr_t)cbmem_top()); mmio_from_to(dev, idx++, (uintptr_t)cbmem_top(), tseg_base); } if (tseg_base + tseg_size < tolud) mmio_from_to(dev, idx++, tseg_base + tseg_size, tolud); /* legacy VGA memory */ mmio_from_to(dev, idx++, 0xa0000, 0xc0000); /* RAM to be used for option roms and BIOS */ reserved_ram_from_to(dev, idx++, 0xc0000, 1 * MiB); } static void mch_domain_set_resources(struct device *dev) { struct resource *res; for (res = dev->resource_list; res; res = res->next) report_resource_stored(dev, res, ""); assign_resources(dev->downstream); } static const char *northbridge_acpi_name(const struct device *dev) { if (dev->path.type == DEVICE_PATH_DOMAIN) return "PCI0"; if (!is_pci_dev_on_bus(dev, 0)) return NULL; switch (dev->path.pci.devfn) { case PCI_DEVFN(0, 0): return "MCHC"; } return NULL; } void northbridge_write_smram(u8 smram) { struct device *dev = pcidev_on_root(0, 0); if (!dev) die("could not find pci 00:00.0!\n"); pci_write_config8(dev, SMRAM, smram); } struct device_operations i945_pci_domain_ops = { .read_resources = mch_domain_read_resources, .set_resources = mch_domain_set_resources, .scan_bus = pci_host_bridge_scan_bus, .acpi_name = northbridge_acpi_name, }; static void mc_read_resources(struct device *dev) { pci_dev_read_resources(dev); mmconf_resource(dev, PCIEXBAR); } static struct device_operations mc_ops = { .read_resources = mc_read_resources, .set_resources = pci_dev_set_resources, .enable_resources = pci_dev_enable_resources, .acpi_fill_ssdt = generate_cpu_entries, .ops_pci = &pci_dev_ops_pci, }; static const unsigned short pci_device_ids[] = { 0x2770, /* desktop */ 0x27a0, 0x27ac, /* mobile */ 0 }; static const struct pci_driver mc_driver __pci_driver = { .ops = &mc_ops, .vendor = PCI_VID_INTEL, .devices = pci_device_ids, }; struct device_operations i945_cpu_bus_ops = { .read_resources = noop_read_resources, .set_resources = noop_set_resources, .init = mp_cpu_bus_init, }; struct chip_operations northbridge_intel_i945_ops = { .name = "Intel i945 Northbridge", }; bool northbridge_support_slfm(void) { return false; }