blob: 455e3b816c027357f10f4a82ef048f57d811d4db [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Patrick Georgie72a8a32012-11-06 11:05:09 +01002
3#include <console/console.h>
4#include <device/device.h>
5#include <device/pci.h>
6#include <device/pci_ids.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +02007#include <option.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +01008#include <pc80/mc146818rtc.h>
9#include <pc80/isa-dma.h>
10#include <pc80/i8259.h>
11#include <arch/io.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020012#include <device/pci_ops.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010013#include <arch/ioapic.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070014#include <acpi/acpi.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010015#include <cpu/x86/smm.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070016#include <acpi/acpigen.h>
Vladimir Serbinenko33769a52014-08-30 22:39:20 +020017#include <cbmem.h>
18#include <string.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030019#include "chip.h"
Patrick Georgie72a8a32012-11-06 11:05:09 +010020#include "i82801ix.h"
Vladimir Serbinenko33769a52014-08-30 22:39:20 +020021#include "nvs.h"
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010022#include <southbridge/intel/common/pciehp.h>
Arthur Heymanse798e6a2017-12-23 23:09:54 +010023#include <southbridge/intel/common/acpi_pirq_gen.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010024
25#define NMI_OFF 0
26
Patrick Georgie72a8a32012-11-06 11:05:09 +010027typedef struct southbridge_intel_i82801ix_config config_t;
28
29static void i82801ix_enable_apic(struct device *dev)
30{
Patrick Georgie72a8a32012-11-06 11:05:09 +010031 u32 reg32;
32 volatile u32 *ioapic_index = (volatile u32 *)(IO_APIC_ADDR);
33 volatile u32 *ioapic_data = (volatile u32 *)(IO_APIC_ADDR + 0x10);
34
35 /* Enable IOAPIC. Keep APIC Range Select at zero. */
36 RCBA8(0x31ff) = 0x03;
37 /* We have to read 0x31ff back if bit0 changed. */
Paul Menzeld0299e42013-10-21 09:28:19 +020038 RCBA8(0x31ff);
Patrick Georgie72a8a32012-11-06 11:05:09 +010039
40 /* Lock maximum redirection entries (MRE), R/WO register. */
41 *ioapic_index = 0x01;
42 reg32 = *ioapic_data;
43 *ioapic_index = 0x01;
44 *ioapic_data = reg32;
45
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080046 setup_ioapic(VIO_APIC_VADDR, 2); /* ICH7 code uses id 2. */
Patrick Georgie72a8a32012-11-06 11:05:09 +010047}
48
49static void i82801ix_enable_serial_irqs(struct device *dev)
50{
51 /* Set packet length and toggle silent mode bit for one frame. */
52 pci_write_config8(dev, D31F0_SERIRQ_CNTL,
53 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
54}
55
56/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
57 * 0x00 - 0000 = Reserved
58 * 0x01 - 0001 = Reserved
59 * 0x02 - 0010 = Reserved
60 * 0x03 - 0011 = IRQ3
61 * 0x04 - 0100 = IRQ4
62 * 0x05 - 0101 = IRQ5
63 * 0x06 - 0110 = IRQ6
64 * 0x07 - 0111 = IRQ7
65 * 0x08 - 1000 = Reserved
66 * 0x09 - 1001 = IRQ9
67 * 0x0A - 1010 = IRQ10
68 * 0x0B - 1011 = IRQ11
69 * 0x0C - 1100 = IRQ12
70 * 0x0D - 1101 = Reserved
71 * 0x0E - 1110 = IRQ14
72 * 0x0F - 1111 = IRQ15
73 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
74 * 0x80 - The PIRQ is not routed.
75 */
76
Elyes HAOUAS8aa50732018-05-13 13:34:58 +020077static void i82801ix_pirq_init(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +010078{
Elyes HAOUAS8aa50732018-05-13 13:34:58 +020079 struct device *irq_dev;
Patrick Georgie72a8a32012-11-06 11:05:09 +010080 /* Get the chip configuration */
81 config_t *config = dev->chip_info;
82
83 pci_write_config8(dev, D31F0_PIRQA_ROUT, config->pirqa_routing);
84 pci_write_config8(dev, D31F0_PIRQB_ROUT, config->pirqb_routing);
85 pci_write_config8(dev, D31F0_PIRQC_ROUT, config->pirqc_routing);
86 pci_write_config8(dev, D31F0_PIRQD_ROUT, config->pirqd_routing);
87
88 pci_write_config8(dev, D31F0_PIRQE_ROUT, config->pirqe_routing);
89 pci_write_config8(dev, D31F0_PIRQF_ROUT, config->pirqf_routing);
90 pci_write_config8(dev, D31F0_PIRQG_ROUT, config->pirqg_routing);
91 pci_write_config8(dev, D31F0_PIRQH_ROUT, config->pirqh_routing);
92
93 /* Eric Biederman once said we should let the OS do this.
94 * I am not so sure anymore he was right.
95 */
96
Elyes HAOUASba28e8d2016-08-31 19:22:16 +020097 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Patrick Georgie72a8a32012-11-06 11:05:09 +010098 u8 int_pin=0, int_line=0;
99
100 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
101 continue;
102
103 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
104
105 switch (int_pin) {
106 case 1: /* INTA# */ int_line = config->pirqa_routing; break;
107 case 2: /* INTB# */ int_line = config->pirqb_routing; break;
108 case 3: /* INTC# */ int_line = config->pirqc_routing; break;
109 case 4: /* INTD# */ int_line = config->pirqd_routing; break;
110 }
111
112 if (!int_line)
113 continue;
114
115 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line);
116 }
117}
118
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200119static void i82801ix_gpi_routing(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100120{
121 /* Get the chip configuration */
122 config_t *config = dev->chip_info;
123 u32 reg32 = 0;
124
125 /* An array would be much nicer here, or some
126 * other method of doing this.
127 */
128 reg32 |= (config->gpi0_routing & 0x03) << 0;
129 reg32 |= (config->gpi1_routing & 0x03) << 2;
130 reg32 |= (config->gpi2_routing & 0x03) << 4;
131 reg32 |= (config->gpi3_routing & 0x03) << 6;
132 reg32 |= (config->gpi4_routing & 0x03) << 8;
133 reg32 |= (config->gpi5_routing & 0x03) << 10;
134 reg32 |= (config->gpi6_routing & 0x03) << 12;
135 reg32 |= (config->gpi7_routing & 0x03) << 14;
136 reg32 |= (config->gpi8_routing & 0x03) << 16;
137 reg32 |= (config->gpi9_routing & 0x03) << 18;
138 reg32 |= (config->gpi10_routing & 0x03) << 20;
139 reg32 |= (config->gpi11_routing & 0x03) << 22;
140 reg32 |= (config->gpi12_routing & 0x03) << 24;
141 reg32 |= (config->gpi13_routing & 0x03) << 26;
142 reg32 |= (config->gpi14_routing & 0x03) << 28;
143 reg32 |= (config->gpi15_routing & 0x03) << 30;
144
145 pci_write_config32(dev, D31F0_GPIO_ROUT, reg32);
146}
147
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200148static void i82801ix_power_options(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100149{
150 u8 reg8;
151 u16 reg16, pmbase;
152 u32 reg32;
153 const char *state;
154 /* Get the chip configuration */
155 config_t *config = dev->chip_info;
156
Nico Huber9faae2b2018-11-14 00:00:35 +0100157 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Patrick Georgie72a8a32012-11-06 11:05:09 +0100158 int nmi_option;
159
160 /* BIOS must program... */
161 reg32 = pci_read_config32(dev, 0xac);
162 pci_write_config32(dev, 0xac, reg32 | (1 << 30) | (3 << 8));
163
164 /* Which state do we want to goto after g3 (power restored)?
165 * 0 == S0 Full On
166 * 1 == S5 Soft Off
167 *
168 * If the option is not existent (Laptops), use MAINBOARD_POWER_ON.
169 */
Varad Gautam06ef0462015-03-11 09:54:41 +0530170 pwr_on = MAINBOARD_POWER_ON;
171 get_option(&pwr_on, "power_on_after_fail");
Patrick Georgie72a8a32012-11-06 11:05:09 +0100172
173 reg8 = pci_read_config8(dev, D31F0_GEN_PMCON_3);
174 reg8 &= 0xfe;
175 switch (pwr_on) {
176 case MAINBOARD_POWER_OFF:
177 reg8 |= 1;
178 state = "off";
179 break;
180 case MAINBOARD_POWER_ON:
181 reg8 &= ~1;
182 state = "on";
183 break;
184 case MAINBOARD_POWER_KEEP:
185 reg8 &= ~1;
186 state = "state keep";
187 break;
188 default:
189 state = "undefined";
190 }
191
192 reg8 |= (3 << 4); /* avoid #S4 assertions */
193 reg8 &= ~(1 << 3); /* minimum asssertion is 1 to 2 RTCCLK */
194
195 pci_write_config8(dev, D31F0_GEN_PMCON_3, reg8);
196 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
197
198 /* Set up NMI on errors. */
199 reg8 = inb(0x61);
200 reg8 &= 0x0f; /* Higher Nibble must be 0 */
201 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
202 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
203 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
204 outb(reg8, 0x61);
205
206 reg8 = inb(0x74); /* Read from 0x74 as 0x70 is write only. */
207 nmi_option = NMI_OFF;
208 get_option(&nmi_option, "nmi");
209 if (nmi_option) {
210 printk(BIOS_INFO, "NMI sources enabled.\n");
211 reg8 &= ~(1 << 7); /* Set NMI. */
212 } else {
213 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200214 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Patrick Georgie72a8a32012-11-06 11:05:09 +0100215 }
216 outb(reg8, 0x70);
217
218 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
219 reg16 = pci_read_config16(dev, D31F0_GEN_PMCON_1);
220 reg16 &= ~(3 << 0); // SMI# rate 1 minute
221 reg16 |= (1 << 2); // CLKRUN_EN - Mobile/Ultra only
222 reg16 |= (1 << 3); // Speedstep Enable - Mobile/Ultra only
223 reg16 |= (1 << 5); // CPUSLP_EN Desktop only
224
225 if (config->c4onc3_enable)
226 reg16 |= (1 << 7);
227
228 // another laptop wants this?
229 // reg16 &= ~(1 << 10); // BIOS_PCI_EXP_EN - Desktop/Mobile only
230 reg16 |= (1 << 10); // BIOS_PCI_EXP_EN - Desktop/Mobile only
231#if DEBUG_PERIODIC_SMIS
232 /* Set DEBUG_PERIODIC_SMIS in i82801ix.h to debug using
233 * periodic SMIs.
234 */
235 reg16 |= (3 << 0); // Periodic SMI every 8s
236#endif
237 if (config->c5_enable)
238 reg16 |= (1 << 11); /* Enable C5, C6 and PMSYNC# */
239 pci_write_config16(dev, D31F0_GEN_PMCON_1, reg16);
240
241 /* Set exit timings for C5/C6. */
242 if (config->c5_enable) {
243 reg8 = pci_read_config8(dev, D31F0_C5_EXIT_TIMING);
244 reg8 &= ~((7 << 3) | (7 << 0));
245 if (config->c6_enable)
246 reg8 |= (5 << 3) | (3 << 0); /* 38-44us PMSYNC# to STPCLK#,
247 95-102us DPRSTP# to STP_CPU# */
248 else
249 reg8 |= (0 << 3) | (1 << 0); /* 16-17us PMSYNC# to STPCLK#,
250 34-40us DPRSTP# to STP_CPU# */
251 pci_write_config8(dev, D31F0_C5_EXIT_TIMING, reg8);
252 }
253
254 // Set the board's GPI routing.
255 i82801ix_gpi_routing(dev);
256
257 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
258
259 outl(config->gpe0_en, pmbase + 0x28);
260 outw(config->alt_gp_smi_en, pmbase + 0x38);
261
262 /* Set up power management block and determine sleep mode */
263 reg16 = inw(pmbase + 0x00); /* PM1_STS */
264 outw(reg16, pmbase + 0x00); /* Clear status bits. At least bit11 (power
265 button override) must be cleared or SCI
266 will be constantly fired and OSPM must
267 not know about it (ACPI spec says to
268 ignore the bit). */
Patrick Georgie72a8a32012-11-06 11:05:09 +0100269
270 /* Set duty cycle for hardware throttling (defaults to 0x0: 50%). */
271 reg32 = inl(pmbase + 0x10);
272 reg32 &= ~(7 << 5);
273 reg32 |= (config->throttle_duty & 7) << 5;
274 outl(reg32, pmbase + 0x10);
275}
276
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200277static void i82801ix_configure_cstates(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100278{
279 u8 reg8;
280
281 reg8 = pci_read_config8(dev, D31F0_CxSTATE_CNF);
282 reg8 |= (1 << 4) | (1 << 3) | (1 << 2); // Enable Popup & Popdown
283 pci_write_config8(dev, D31F0_CxSTATE_CNF, reg8);
284
285 // Set Deeper Sleep configuration to recommended values
286 reg8 = pci_read_config8(dev, D31F0_C4TIMING_CNT);
287 reg8 &= 0xf0;
288 reg8 |= (2 << 2); // Deeper Sleep to Stop CPU: 34-40us
289 reg8 |= (2 << 0); // Deeper Sleep to Sleep: 15us
290 pci_write_config8(dev, D31F0_C4TIMING_CNT, reg8);
291
292 /* We could enable slow-C4 exit here, if someone needs it? */
293}
294
295static void i82801ix_rtc_init(struct device *dev)
296{
297 u8 reg8;
298 int rtc_failed;
299
300 reg8 = pci_read_config8(dev, D31F0_GEN_PMCON_3);
301 rtc_failed = reg8 & RTC_BATTERY_DEAD;
302 if (rtc_failed) {
303 reg8 &= ~RTC_BATTERY_DEAD;
304 pci_write_config8(dev, D31F0_GEN_PMCON_3, reg8);
305 }
306 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
307
Gabe Blackb3f08c62014-04-30 17:12:25 -0700308 cmos_init(rtc_failed);
Patrick Georgie72a8a32012-11-06 11:05:09 +0100309}
310
311static void enable_hpet(void)
312{
313 u32 reg32;
314
315 /* Move HPET to default address 0xfed00000 and enable it */
316 reg32 = RCBA32(RCBA_HPTC);
317 reg32 |= (1 << 7); // HPET Address Enable
318 reg32 &= ~(3 << 0);
319 RCBA32(RCBA_HPTC) = reg32;
320}
321
322static void enable_clock_gating(void)
323{
324 u32 reg32;
325
326 /* Enable DMI dynamic clock gating. */
327 RCBA32(RCBA_DMIC) |= 3;
328
329 /* Enable Clock Gating for most devices. */
330 reg32 = RCBA32(RCBA_CG);
331 reg32 |= (1 << 31); /* LPC dynamic clock gating */
332 /* USB UHCI dynamic clock gating: */
333 reg32 |= (1 << 29) | (1 << 28);
334 /* SATA dynamic clock gating [0-3]: */
335 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
336 reg32 |= (1 << 23); /* LAN static clock gating (if LAN disabled) */
337 reg32 |= (1 << 22); /* HD audio dynamic clock gating */
338 reg32 &= ~(1 << 21); /* No HD audio static clock gating */
339 reg32 &= ~(1 << 20); /* No USB EHCI static clock gating */
340 reg32 |= (1 << 19); /* USB EHCI dynamic clock gating */
341 /* More SATA dynamic clock gating [4-5]: */
342 reg32 |= (1 << 18) | (1 << 17);
343 reg32 |= (1 << 16); /* PCI dynamic clock gating */
344 /* PCIe, DMI dynamic clock gating: */
345 reg32 |= (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1);
346 reg32 |= (1 << 0); /* PCIe root port static clock gating */
347 RCBA32(RCBA_CG) = reg32;
348
349 /* Enable SPI dynamic clock gating. */
350 RCBA32(0x38c0) |= 7;
351}
352
Kyösti Mälkki6feb4da2019-07-13 17:28:37 +0300353static void i82801ix_set_acpi_mode(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100354{
Kyösti Mälkki44da9e72019-10-09 12:32:16 +0300355 if (CONFIG(HAVE_SMI_HANDLER)) {
356 if (!acpi_is_wakeup_s3()) {
357 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
358 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
359 printk(BIOS_DEBUG, "done.\n");
360 } else {
361 printk(BIOS_DEBUG, "S3 wakeup, enabling ACPI via APMC\n");
362 outb(APM_CNT_ACPI_ENABLE, APM_CNT);
363 }
Patrick Georgie72a8a32012-11-06 11:05:09 +0100364 }
Patrick Georgie72a8a32012-11-06 11:05:09 +0100365}
Patrick Georgie72a8a32012-11-06 11:05:09 +0100366
367static void lpc_init(struct device *dev)
368{
369 printk(BIOS_DEBUG, "i82801ix: lpc_init\n");
370
371 /* Set the value for PCI command register. */
372 pci_write_config16(dev, PCI_COMMAND, 0x000f);
373
374 /* IO APIC initialization. */
375 i82801ix_enable_apic(dev);
376
377 i82801ix_enable_serial_irqs(dev);
378
379 /* Setup the PIRQ. */
380 i82801ix_pirq_init(dev);
381
382 /* Setup power options. */
383 i82801ix_power_options(dev);
384
385 /* Configure Cx state registers */
386 if (LPC_IS_MOBILE(dev))
387 i82801ix_configure_cstates(dev);
388
389 /* Initialize the real time clock. */
390 i82801ix_rtc_init(dev);
391
392 /* Initialize ISA DMA. */
393 isa_dma_init();
394
395 /* Initialize the High Precision Event Timers, if present. */
396 enable_hpet();
397
398 /* Initialize Clock Gating */
399 enable_clock_gating();
400
401 setup_i8259();
402
403 /* The OS should do this? */
404 /* Interrupt 9 should be level triggered (SCI) */
405 i8259_configure_irq_trigger(9, 1);
406
Kyösti Mälkki44da9e72019-10-09 12:32:16 +0300407 i82801ix_set_acpi_mode(dev);
Kyösti Mälkki6feb4da2019-07-13 17:28:37 +0300408
409 /* Don't allow evil boot loaders, kernels, or
410 * userspace applications to deceive us:
411 */
Kyösti Mälkkicd0b67b2019-10-09 07:52:40 +0300412 if (CONFIG(HAVE_SMI_HANDLER) && !CONFIG(PARALLEL_MP))
Kyösti Mälkki6feb4da2019-07-13 17:28:37 +0300413 aseg_smm_lock();
Patrick Georgie72a8a32012-11-06 11:05:09 +0100414}
415
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200416static void i82801ix_lpc_read_resources(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100417{
418 /*
419 * I/O Resources
420 *
421 * 0x0000 - 0x000f....ISA DMA
422 * 0x0010 - 0x001f....ISA DMA aliases
423 * 0x0020 ~ 0x003d....PIC
424 * 0x002e - 0x002f....Maybe Super I/O
425 * 0x0040 - 0x0043....Timer
426 * 0x004e - 0x004f....Maybe Super I/O
427 * 0x0050 - 0x0053....Timer aliases
428 * 0x0061.............NMI_SC
429 * 0x0070.............NMI_EN (readable in alternative access mode)
430 * 0x0070 - 0x0077....RTC
431 * 0x0080 - 0x008f....ISA DMA
432 * 0x0090 ~ 0x009f....ISA DMA aliases
433 * 0x0092.............Fast A20 and Init
434 * 0x00a0 ~ 0x00bd....PIC
435 * 0x00b2 - 0x00b3....APM
436 * 0x00c0 ~ 0x00de....ISA DMA
437 * 0x00c1 ~ 0x00df....ISA DMA aliases
438 * 0x00f0.............Coprocessor Error
439 * (0x0400-0x041f)....SMBus (SMBUS_IO_BASE, during raminit)
440 * 0x04d0 - 0x04d1....PIC
441 * 0x0500 - 0x057f....PM (DEFAULT_PMBASE)
442 * 0x0580 - 0x05bf....SB GPIO (DEFAULT_GPIOBASE)
443 * 0x05c0 - 0x05ff....SB GPIO cont. (mobile only)
444 * 0x0cf8 - 0x0cff....PCI
445 * 0x0cf9.............Reset Control
446 */
447
448 struct resource *res;
449
450 /* Get the normal PCI resources of this device. */
451 pci_dev_read_resources(dev);
452
453 /* Add an extra subtractive resource for both memory and I/O. */
454 res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
455 res->base = 0;
456 res->size = 0x1000;
457 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
458 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
459
460 res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
461 res->base = 0xff800000;
462 res->size = 0x00800000; /* 8 MB for flash */
463 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
464 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
465
466 res = new_resource(dev, 3); /* IOAPIC */
467 res->base = IO_APIC_ADDR;
468 res->size = 0x00001000;
469 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
470}
471
Furquan Shaikh338fd9a2020-04-24 22:57:05 -0700472static void southbridge_inject_dsdt(const struct device *dev)
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200473{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200474 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200475
476 if (gnvs) {
Elyes HAOUAS035df002016-10-03 21:54:16 +0200477 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200478 acpi_create_gnvs(gnvs);
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100479
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200480 /* And tell SMI about it */
481 smm_setup_structures(gnvs, NULL, NULL);
482
483 /* Add it to SSDT. */
Vladimir Serbinenkof7c75db2014-11-04 21:21:06 +0100484 acpigen_write_scope("\\");
Patrick Rudolph4af2add2018-11-26 15:56:11 +0100485 acpigen_write_name_dword("NVSA", (uintptr_t)gnvs);
Vladimir Serbinenkof7c75db2014-11-04 21:21:06 +0100486 acpigen_pop_len();
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200487 }
488}
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100489
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100490
491static const char *lpc_acpi_name(const struct device *dev)
492{
493 return "LPCB";
494}
495
Furquan Shaikh7536a392020-04-24 21:59:21 -0700496static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100497{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300498 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100499 config_t *chip = dev->chip_info;
500
501 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100502 intel_acpi_gen_def_acpi_pirq(device);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100503}
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200504
Patrick Georgie72a8a32012-11-06 11:05:09 +0100505static struct pci_operations pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530506 .set_subsystem = pci_dev_set_subsystem,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100507};
508
509static struct device_operations device_ops = {
510 .read_resources = i82801ix_lpc_read_resources,
511 .set_resources = pci_dev_set_resources,
512 .enable_resources = pci_dev_enable_resources,
Nico Huber68680dd2020-03-31 17:34:52 +0200513 .acpi_inject_dsdt = southbridge_inject_dsdt,
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200514 .write_acpi_tables = acpi_write_hpet,
Nico Huber68680dd2020-03-31 17:34:52 +0200515 .acpi_fill_ssdt = southbridge_fill_ssdt,
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100516 .acpi_name = lpc_acpi_name,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100517 .init = lpc_init,
Nico Huber51b75ae2019-03-14 16:02:05 +0100518 .scan_bus = scan_static_bus,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100519 .ops_pci = &pci_ops,
520};
521
522static const unsigned short pci_device_ids[] = {
Felix Singer7f8b0cd82019-11-10 11:04:08 +0100523 PCI_DEVICE_ID_INTEL_82801IH_LPC, /* ICH9DH */
524 PCI_DEVICE_ID_INTEL_82801IO_LPC, /* ICH9DO */
525 PCI_DEVICE_ID_INTEL_82801IR_LPC, /* ICH9R */
526 PCI_DEVICE_ID_INTEL_82801IEM_LPC, /* ICH9M-E */
527 PCI_DEVICE_ID_INTEL_82801IB_LPC, /* ICH9 */
528 PCI_DEVICE_ID_INTEL_82801IBM_LPC, /* ICH9M */
Patrick Georgie72a8a32012-11-06 11:05:09 +0100529 0
530};
531
532static const struct pci_driver ich9_lpc __pci_driver = {
533 .ops = &device_ops,
534 .vendor = PCI_VENDOR_ID_INTEL,
535 .devices = pci_device_ids,
536};