blob: 07dba86faea4aa60ca8f7afdfb30a32d21bea8f6 [file] [log] [blame]
Angel Pons4b429832020-04-02 23:48:50 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Patrick Georgi2efc8802012-11-06 11:03:53 +01002
Arthur Heymans022d2352022-05-06 12:10:39 +02003#include <acpi/acpi.h>
4#include <acpi/acpigen.h>
5#include <boot/tables.h>
Arthur Heymans17ad4592018-08-06 15:35:28 +02006#include <cbmem.h>
Angel Ponsb9bbed22020-08-03 15:11:55 +02007#include <commonlib/helpers.h>
Patrick Georgi2efc8802012-11-06 11:03:53 +01008#include <console/console.h>
Arthur Heymans022d2352022-05-06 12:10:39 +02009#include <cpu/cpu.h>
Arthur Heymans98c92572022-11-07 11:39:58 +010010#include <cpu/intel/speedstep.h>
Arthur Heymans022d2352022-05-06 12:10:39 +020011#include <cpu/intel/smm_reloc.h>
Arthur Heymansf06e9932023-07-05 08:25:55 +020012#include <cpu/x86/smm.h>
Arthur Heymans022d2352022-05-06 12:10:39 +020013#include <device/device.h>
Elyes HAOUAS748caed2019-12-19 17:02:08 +010014#include <device/pci_def.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020015#include <device/pci_ops.h>
Patrick Georgi2efc8802012-11-06 11:03:53 +010016#include <stdint.h>
Elyes HAOUASa1e22b82019-03-18 22:49:36 +010017
Patrick Georgi2efc8802012-11-06 11:03:53 +010018#include "chip.h"
19#include "gm45.h"
20
Arthur Heymans022d2352022-05-06 12:10:39 +020021static uint64_t get_touud(void)
22{
23 uint64_t touud = pci_read_config16(__pci_0_00_0, D0F0_TOUUD);
24 touud <<= 20;
25 return touud;
26}
27
Elyes HAOUAS6dcdaaf2018-02-09 07:44:31 +010028static void mch_domain_read_resources(struct device *dev)
Patrick Georgi2efc8802012-11-06 11:03:53 +010029{
30 u64 tom, touud;
Arthur Heymansf06e9932023-07-05 08:25:55 +020031 u32 tolud;
Kyösti Mälkkic1d4d0b2021-06-26 19:09:05 +030032 int idx = 3;
Patrick Georgi2efc8802012-11-06 11:03:53 +010033
34 /* Total Memory 2GB example:
35 *
36 * 00000000 0000MB-2014MB 2014MB RAM (writeback)
37 * 7de00000 2014MB-2016MB 2MB GFX GTT (uncached)
38 * 7e000000 2016MB-2048MB 32MB GFX UMA (uncached)
39 * 80000000 2048MB TOLUD
40 * 80000000 2048MB TOM
41 *
42 * Total Memory 4GB example:
43 *
44 * 00000000 0000MB-3038MB 3038MB RAM (writeback)
45 * bde00000 3038MB-3040MB 2MB GFX GTT (uncached)
46 * be000000 3040MB-3072MB 32MB GFX UMA (uncached)
47 * be000000 3072MB TOLUD
48 * 100000000 4096MB TOM
49 * 100000000 4096MB-5120MB 1024MB RAM (writeback)
50 * 140000000 5120MB TOUUD
51 */
52
53 pci_domain_read_resources(dev);
54
Kyösti Mälkkic70eed12018-05-22 02:18:00 +030055 struct device *mch = pcidev_on_root(0, 0);
Arthur Heymans89089312018-06-26 21:01:40 +020056
Patrick Georgi2efc8802012-11-06 11:03:53 +010057 /* Top of Upper Usable DRAM, including remap */
Arthur Heymans022d2352022-05-06 12:10:39 +020058 touud = get_touud();
Patrick Georgi2efc8802012-11-06 11:03:53 +010059
60 /* Top of Lower Usable DRAM */
Arthur Heymans89089312018-06-26 21:01:40 +020061 tolud = pci_read_config16(mch, D0F0_TOLUD) & 0xfff0;
Patrick Georgi2efc8802012-11-06 11:03:53 +010062 tolud <<= 16;
63
64 /* Top of Memory - does not account for any UMA */
Arthur Heymans89089312018-06-26 21:01:40 +020065 tom = pci_read_config16(mch, D0F0_TOM) & 0x1ff;
Patrick Georgi2efc8802012-11-06 11:03:53 +010066 tom <<= 27;
67
68 printk(BIOS_DEBUG, "TOUUD 0x%llx TOLUD 0x%08x TOM 0x%llx\n",
69 touud, tolud, tom);
70
Nico Huber58ba83f2021-01-17 21:50:55 +010071 /* Report lowest memory region */
Arthur Heymansf06e9932023-07-05 08:25:55 +020072 ram_range(dev, idx++, 0, 0xa0000);
Nico Huber58ba83f2021-01-17 21:50:55 +010073
74 /*
75 * Reserve everything between A segment and 1MB:
76 *
77 * 0xa0000 - 0xbffff: Legacy VGA
78 * 0xc0000 - 0xfffff: RAM
79 */
Arthur Heymansf06e9932023-07-05 08:25:55 +020080 mmio_from_to(dev, idx++, 0xa0000, 0xc0000);
81 reserved_ram_from_to(dev, idx++, 0xc0000, 1*MiB);
Nico Huber58ba83f2021-01-17 21:50:55 +010082
83 /* Report < 4GB memory */
Arthur Heymansf06e9932023-07-05 08:25:55 +020084 ram_range(dev, idx++, 1*MiB, (uintptr_t)cbmem_top());
85
86 /* TSEG */
87 uintptr_t tseg_base;
88 size_t tseg_size;
89 smm_region(&tseg_base, &tseg_size);
90 mmio_range(dev, idx++, tseg_base, tseg_size);
91
92 /* cbmem_top can be shifted downwards due to alignment.
93 Mark the region between cbmem_top and tseg_base as unusable */
94 if ((uintptr_t)cbmem_top() < tseg_base) {
95 printk(BIOS_DEBUG, "Unused RAM between cbmem_top and TOM: 0x%lx\n",
96 tseg_base - (uintptr_t)cbmem_top());
97 mmio_from_to(dev, idx++, (uintptr_t)cbmem_top(), tseg_base);
98 }
99
100 /* graphic memory above TSEG */
101 if (tseg_base + tseg_size < tolud)
102 mmio_from_to(dev, idx++, tseg_base + tseg_size, tolud);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100103
104 /*
105 * If >= 4GB installed then memory from TOLUD to 4GB
106 * is remapped above TOM, TOUUD will account for both
107 */
Kyösti Mälkki0a18d642021-06-28 21:43:31 +0300108 upper_ram_end(dev, idx++, touud);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100109
Kyösti Mälkkic1d4d0b2021-06-26 19:09:05 +0300110 mmconf_resource(dev, idx++);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100111}
112
Elyes HAOUAS6dcdaaf2018-02-09 07:44:31 +0100113static void mch_domain_set_resources(struct device *dev)
Patrick Georgi2efc8802012-11-06 11:03:53 +0100114{
115 struct resource *resource;
116 int i;
117
Nico Huber58ba83f2021-01-17 21:50:55 +0100118 for (i = 3; i <= 9; ++i) {
Patrick Georgi2efc8802012-11-06 11:03:53 +0100119 /* Report read resources. */
Vladimir Serbinenko40412c62014-11-12 00:09:20 +0100120 resource = probe_resource(dev, i);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100121 if (resource)
122 report_resource_stored(dev, resource, "");
123 }
124
125 assign_resources(dev->link_list);
126}
127
Elyes HAOUAS6dcdaaf2018-02-09 07:44:31 +0100128static void mch_domain_init(struct device *dev)
Patrick Georgi2efc8802012-11-06 11:03:53 +0100129{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300130 struct device *mch = pcidev_on_root(0, 0);
Arthur Heymans89089312018-06-26 21:01:40 +0200131
Patrick Georgi2efc8802012-11-06 11:03:53 +0100132 /* Enable SERR */
Elyes HAOUAS5ac723e2020-04-29 09:09:12 +0200133 pci_or_config16(mch, PCI_COMMAND, PCI_COMMAND_SERR);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100134}
135
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100136static const char *northbridge_acpi_name(const struct device *dev)
137{
138 if (dev->path.type == DEVICE_PATH_DOMAIN)
139 return "PCI0";
140
Fabio Aiuto61ed4ef2022-09-30 14:55:53 +0200141 if (!is_pci_dev_on_bus(dev, 0))
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100142 return NULL;
143
144 switch (dev->path.pci.devfn) {
145 case PCI_DEVFN(0, 0):
146 return "MCHC";
147 }
148
149 return NULL;
150}
151
Arthur Heymansaade90e2018-01-25 00:33:45 +0100152void northbridge_write_smram(u8 smram)
153{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300154 struct device *dev = pcidev_on_root(0, 0);
Arthur Heymans48fa9222018-11-19 13:08:01 +0100155
Elyes Haouas5e6b0f02022-09-13 09:55:49 +0200156 if (!dev)
Arthur Heymans48fa9222018-11-19 13:08:01 +0100157 die("could not find pci 00:00.0!\n");
158
159 pci_write_config8(dev, D0F0_SMRAM, smram);
Arthur Heymansaade90e2018-01-25 00:33:45 +0100160}
161
Arthur Heymans022d2352022-05-06 12:10:39 +0200162static void set_above_4g_pci(const struct device *dev)
163{
164 const uint64_t touud = get_touud();
165 const uint64_t len = POWER_OF_2(cpu_phys_address_size()) - touud;
166
167 const char *scope = acpi_device_path(dev);
168 acpigen_write_scope(scope);
169 acpigen_write_name_qword("A4GB", touud);
170 acpigen_write_name_qword("A4GS", len);
171 acpigen_pop_len();
172
173 printk(BIOS_DEBUG, "PCI space above 4GB MMIO is at 0x%llx, len = 0x%llx\n", touud, len);
174}
175
176static void pci_domain_ssdt(const struct device *dev)
177{
178 generate_cpu_entries(dev);
179 set_above_4g_pci(dev);
180}
181
Arthur Heymans2fb6f682022-11-07 09:45:19 +0100182struct device_operations gm45_pci_domain_ops = {
Patrick Georgi2efc8802012-11-06 11:03:53 +0100183 .read_resources = mch_domain_read_resources,
184 .set_resources = mch_domain_set_resources,
Patrick Georgi2efc8802012-11-06 11:03:53 +0100185 .init = mch_domain_init,
186 .scan_bus = pci_domain_scan_bus,
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200187 .write_acpi_tables = northbridge_write_acpi_tables,
Arthur Heymans022d2352022-05-06 12:10:39 +0200188 .acpi_fill_ssdt = pci_domain_ssdt,
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100189 .acpi_name = northbridge_acpi_name,
Patrick Georgi2efc8802012-11-06 11:03:53 +0100190};
191
Arthur Heymans2fb6f682022-11-07 09:45:19 +0100192struct device_operations gm45_cpu_bus_ops = {
Nico Huber2f8ba692020-04-05 14:05:24 +0200193 .read_resources = noop_read_resources,
194 .set_resources = noop_set_resources,
Kyösti Mälkkib3267e02019-08-13 16:44:04 +0300195 .init = mp_cpu_bus_init,
Patrick Georgi2efc8802012-11-06 11:03:53 +0100196};
197
Patrick Georgi2efc8802012-11-06 11:03:53 +0100198static void gm45_init(void *const chip_info)
199{
200 int dev, fn, bit_base;
201
Kyösti Mälkki98a91742018-05-21 21:29:16 +0300202 struct device *const d0f0 = pcidev_on_root(0x0, 0);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100203
204 /* Hide internal functions based on devicetree info. */
205 for (dev = 3; dev > 0; --dev) {
206 switch (dev) {
207 case 3: /* ME */
208 fn = 3;
209 bit_base = 6;
210 break;
211 case 2: /* IGD */
212 fn = 1;
213 bit_base = 3;
214 break;
215 case 1: /* PEG */
216 fn = 0;
217 bit_base = 1;
218 break;
219 }
220 for (; fn >= 0; --fn) {
Angel Ponsb0535832020-06-08 11:46:58 +0200221 const struct device *const d = pcidev_on_root(dev, fn);
222 if (!d || d->enabled)
223 continue;
224 /* FIXME: Using bitwise ops changes the binary */
Patrick Georgi2efc8802012-11-06 11:03:53 +0100225 pci_write_config32(d0f0, D0F0_DEVEN,
Angel Ponsb0535832020-06-08 11:46:58 +0200226 pci_read_config32(d0f0, D0F0_DEVEN) & ~(1 << (bit_base + fn)));
Patrick Georgi2efc8802012-11-06 11:03:53 +0100227 }
228 }
229
230 const u32 deven = pci_read_config32(d0f0, D0F0_DEVEN);
231 if (!(deven & (0xf << 6)))
232 pci_write_config32(d0f0, D0F0_DEVEN, deven & ~(1 << 14));
233}
234
235struct chip_operations northbridge_intel_gm45_ops = {
236 CHIP_NAME("Intel GM45 Northbridge")
Patrick Georgi2efc8802012-11-06 11:03:53 +0100237 .init = gm45_init,
238};
Arthur Heymans98c92572022-11-07 11:39:58 +0100239
240bool northbridge_support_slfm(void)
241{
242 struct device *gmch = __pci_0_00_0;
243 struct northbridge_intel_gm45_config *config = gmch->chip_info;
244 return config->slfm == 1;
245}