blob: 5524b315c5c8fbde00fd116e426f9862e6b0af65 [file] [log] [blame]
/* 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 "i945.h"
static void mch_domain_read_resources(struct device *dev)
{
uint32_t pci_tolm, tseg_sizek, cbmem_topk, delta_cbmem;
uint8_t tolud;
uint16_t reg16;
unsigned long long tomk, tomk_stolen;
uint64_t uma_memory_base = 0, uma_memory_size = 0;
uint64_t tseg_memory_base = 0, tseg_memory_size = 0;
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);
printk(BIOS_SPEW, "Top of Low Used DRAM: 0x%08x\n", tolud << 24);
tomk = tolud << 14;
tomk_stolen = tomk;
/* Note: subtract IGD device and TSEG */
reg16 = pci_read_config16(d0f0, GGC);
if (!(reg16 & 2)) {
printk(BIOS_DEBUG, "IGD decoded, subtracting ");
int uma_size = decode_igd_memory_size((reg16 >> 4) & 7);
printk(BIOS_DEBUG, "%dM UMA\n", uma_size / KiB);
tomk_stolen -= uma_size;
/* For reserving UMA memory in the memory map */
uma_memory_base = tomk_stolen * 1024ULL;
uma_memory_size = uma_size * 1024ULL;
printk(BIOS_SPEW, "Base of stolen memory: 0x%08x\n",
(unsigned int)uma_memory_base);
}
tseg_sizek = decode_tseg_size(pci_read_config8(d0f0, ESMRAMC)) / KiB;
printk(BIOS_DEBUG, "TSEG decoded, subtracting %dM\n", tseg_sizek / KiB);
tomk_stolen -= tseg_sizek;
tseg_memory_base = tomk_stolen * 1024ULL;
tseg_memory_size = tseg_sizek * 1024ULL;
/* cbmem_top can be shifted downwards due to alignment.
Mark the region between cbmem_top and tomk as unusable */
cbmem_topk = ((uintptr_t)cbmem_top() / KiB);
delta_cbmem = tomk_stolen - cbmem_topk;
tomk_stolen -= delta_cbmem;
printk(BIOS_DEBUG, "Unused RAM between cbmem_top and TOM: 0x%xK\n", delta_cbmem);
/* The following needs to be 2 lines, otherwise the second
* number is always 0
*/
printk(BIOS_INFO, "Available memory: %dK", (uint32_t)tomk_stolen);
printk(BIOS_INFO, " (%dM)\n", (uint32_t)(tomk_stolen / KiB));
/* Report the memory regions */
ram_resource_kb(dev, idx++, 0, 0xa0000 / KiB);
ram_resource_kb(dev, idx++, 1 * MiB / KiB, (tomk - 1 * MiB / KiB));
uma_resource_kb(dev, idx++, uma_memory_base / KiB, uma_memory_size / KiB);
mmio_resource_kb(dev, idx++, tseg_memory_base / KiB, tseg_memory_size / KiB);
uma_resource_kb(dev, idx++, cbmem_topk, delta_cbmem);
/* legacy VGA memory */
mmio_resource_kb(dev, idx++, 0xa0000 / KiB, (0xc0000 - 0xa0000) / KiB);
/* RAM to be used for option roms and BIOS */
reserved_ram_resource_kb(dev, idx++, 0xc0000 / KiB, (1 * MiB - 0xc0000) / KiB);
}
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 (dev->path.type != DEVICE_PATH_PCI || dev->bus->secondary != 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 == NULL)
die("could not find pci 00:00.0!\n");
pci_write_config8(dev, SMRAM, smram);
}
static struct device_operations pci_domain_ops = {
.read_resources = mch_domain_read_resources,
.set_resources = mch_domain_set_resources,
.scan_bus = pci_domain_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,
};
static struct device_operations cpu_bus_ops = {
.read_resources = noop_read_resources,
.set_resources = noop_set_resources,
.init = mp_cpu_bus_init,
};
static void enable_dev(struct device *dev)
{
/* Set the operations if it is a special bus type */
if (dev->path.type == DEVICE_PATH_DOMAIN)
dev->ops = &pci_domain_ops;
else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER)
dev->ops = &cpu_bus_ops;
}
struct chip_operations northbridge_intel_i945_ops = {
CHIP_NAME("Intel i945 Northbridge")
.enable_dev = enable_dev,
};