xref: /aosp_15_r20/external/coreboot/src/northbridge/intel/x4x/northbridge.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <cbmem.h>
4 #include <console/console.h>
5 #include <device/pci_def.h>
6 #include <device/pci_ops.h>
7 #include <stdint.h>
8 #include <device/device.h>
9 #include <boot/tables.h>
10 #include <acpi/acpi.h>
11 #include <northbridge/intel/x4x/memmap.h>
12 #include <northbridge/intel/x4x/chip.h>
13 #include <northbridge/intel/x4x/x4x.h>
14 #include <cpu/intel/smm_reloc.h>
15 #include <cpu/intel/speedstep.h>
16 #include <cpu/x86/smm.h>
17 
mch_domain_read_resources(struct device * dev)18 static void mch_domain_read_resources(struct device *dev)
19 {
20 	u8 index;
21 	u64 tom, touud;
22 	u32 tolud;
23 
24 	index = 3;
25 
26 	pci_domain_read_resources(dev);
27 
28 	struct device *mch = pcidev_on_root(0, 0);
29 
30 	/* Top of Upper Usable DRAM, including remap */
31 	touud = pci_read_config16(mch, D0F0_TOUUD);
32 	touud <<= 20;
33 
34 	/* Top of Lower Usable DRAM */
35 	tolud = pci_read_config16(mch, D0F0_TOLUD) & 0xfff0;
36 	tolud <<= 16;
37 
38 	/* Top of Memory - does not account for any UMA */
39 	tom = pci_read_config16(mch, D0F0_TOM) & 0x01ff;
40 	tom <<= 26;
41 
42 	printk(BIOS_DEBUG, "TOUUD 0x%llx TOLUD 0x%08x TOM 0x%llx\n", touud, tolud, tom);
43 
44 	/* Report the memory regions */
45 	ram_from_to(dev, index++, 0, 0xa0000);
46 	mmio_from_to(dev, index++, 0xa0000, 0xc0000);
47 	reserved_ram_from_to(dev, index++, 0xc0000, 1 * MiB);
48 	ram_from_to(dev, index++, 1 * MiB, cbmem_top());
49 
50 	/*
51 	 * If >= 4GB installed then memory from TOLUD to 4GB
52 	 * is remapped above TOM, TOUUD will account for both
53 	 */
54 	upper_ram_end(dev, index++, touud);
55 
56 	uintptr_t tseg_base;
57 	size_t tseg_size;
58 	smm_region(&tseg_base, &tseg_size);
59 	mmio_from_to(dev, index++, tseg_base, tolud);
60 	reserved_ram_from_to(dev, index++, cbmem_top(), tseg_base);
61 
62 	/* Reserve high memory where the NB BARs are up to 4GiB */
63 	mmio_from_to(dev, index++, DEFAULT_HECIBAR, 4ull * GiB);
64 
65 	mmconf_resource(dev, index++);
66 }
67 
mch_domain_set_resources(struct device * dev)68 static void mch_domain_set_resources(struct device *dev)
69 {
70 	struct resource *res;
71 
72 	for (res = dev->resource_list; res; res = res->next)
73 		report_resource_stored(dev, res, "");
74 
75 	assign_resources(dev->downstream);
76 }
77 
mch_domain_init(struct device * dev)78 static void mch_domain_init(struct device *dev)
79 {
80 	/* Enable SERR */
81 	pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_SERR);
82 }
83 
northbridge_acpi_name(const struct device * dev)84 static const char *northbridge_acpi_name(const struct device *dev)
85 {
86 	if (dev->path.type == DEVICE_PATH_DOMAIN)
87 		return "PCI0";
88 
89 	if (!is_pci_dev_on_bus(dev, 0))
90 		return NULL;
91 
92 	switch (dev->path.pci.devfn) {
93 	case PCI_DEVFN(0, 0):
94 		return "MCHC";
95 	}
96 
97 	return NULL;
98 }
99 
northbridge_write_smram(u8 smram)100 void northbridge_write_smram(u8 smram)
101 {
102 	struct device *dev = pcidev_on_root(0, 0);
103 
104 	if (!dev)
105 		die("could not find pci 00:00.0!\n");
106 
107 	pci_write_config8(dev, D0F0_SMRAM, smram);
108 }
109 
110 struct device_operations x4x_pci_domain_ops = {
111 	.read_resources   = mch_domain_read_resources,
112 	.set_resources    = mch_domain_set_resources,
113 	.init             = mch_domain_init,
114 	.scan_bus         = pci_host_bridge_scan_bus,
115 	.write_acpi_tables = northbridge_write_acpi_tables,
116 	.acpi_fill_ssdt   = generate_cpu_entries,
117 	.acpi_name        = northbridge_acpi_name,
118 };
119 
120 struct device_operations x4x_cpu_bus_ops = {
121 	.read_resources   = noop_read_resources,
122 	.set_resources    = noop_set_resources,
123 	.init             = mp_cpu_bus_init,
124 };
125 
hide_pci_fn(const int dev_bit_base,const struct device * dev)126 static void hide_pci_fn(const int dev_bit_base, const struct device *dev)
127 {
128 	if (!dev || dev->enabled)
129 		return;
130 	const unsigned int fn = PCI_FUNC(dev->path.pci.devfn);
131 	const struct device *const d0f0 = pcidev_on_root(0, 0);
132 	pci_update_config32(d0f0, D0F0_DEVEN, ~(1 << (dev_bit_base + fn)), 0);
133 }
134 
hide_pci_dev(const int dev,int functions,const int dev_bit_base)135 static void hide_pci_dev(const int dev, int functions, const int dev_bit_base)
136 {
137 	for (; functions >= 0; functions--)
138 		hide_pci_fn(dev_bit_base, pcidev_on_root(dev, functions));
139 }
140 
x4x_init(void * const chip_info)141 static void x4x_init(void *const chip_info)
142 {
143 	struct device *const d0f0 = pcidev_on_root(0x0, 0);
144 
145 	/* Hide internal functions based on devicetree info. */
146 	hide_pci_dev(6, 0, 13); /* PEG1: only on P45 */
147 	hide_pci_dev(3, 3, 6); /* ME */
148 	hide_pci_dev(2, 1, 3); /* IGD */
149 	hide_pci_dev(1, 0, 1); /* PEG0 */
150 
151 	const u32 deven = pci_read_config32(d0f0, D0F0_DEVEN);
152 	if (!(deven & (0xf << 6)))
153 		pci_write_config32(d0f0, D0F0_DEVEN, deven & ~(1 << 14));
154 }
155 
156 struct chip_operations northbridge_intel_x4x_ops = {
157 	.name = "Intel 4-Series Northbridge",
158 	.init = x4x_init,
159 };
160 
northbridge_support_slfm(void)161 bool northbridge_support_slfm(void)
162 {
163 	return false;
164 }
165