| /* SPDX-License-Identifier: GPL-2.0-only */ |
| |
| #include <cbmem.h> |
| #include <commonlib/helpers.h> |
| #include <console/console.h> |
| #include <device/pci_ops.h> |
| #include <stdint.h> |
| #include <device/device.h> |
| #include <device/pci.h> |
| #include <device/pci_ids.h> |
| #include <acpi/acpi.h> |
| #include <cpu/intel/smm_reloc.h> |
| #include <cpu/intel/speedstep.h> |
| #include <cpu/x86/smm.h> |
| #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->link_list); |
| 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->link_list); |
| } |
| |
| 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 = { |
| CHIP_NAME("Intel i945 Northbridge") |
| }; |
| |
| bool northbridge_support_slfm(void) |
| { |
| return false; |
| } |