blob: 546fbced778dc50438104ca810dabd698b402f5c [file] [log] [blame]
Patrick Georgie72a8a32012-11-06 11:05:09 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008-2009 coresystems GmbH
5 * 2012 secunet Security Networks AG
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; version 2 of
10 * the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
Patrick Georgie72a8a32012-11-06 11:05:09 +010016 */
17
18#include <console/console.h>
19#include <device/device.h>
20#include <device/pci.h>
21#include <device/pci_ids.h>
22#include <pc80/mc146818rtc.h>
23#include <pc80/isa-dma.h>
24#include <pc80/i8259.h>
25#include <arch/io.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020026#include <device/pci_ops.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010027#include <arch/ioapic.h>
28#include <arch/acpi.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010029#include <cpu/x86/smm.h>
Vladimir Serbinenko33769a52014-08-30 22:39:20 +020030#include <arch/acpigen.h>
31#include <cbmem.h>
32#include <string.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010033#include "i82801ix.h"
Vladimir Serbinenko33769a52014-08-30 22:39:20 +020034#include "nvs.h"
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010035#include <southbridge/intel/common/pciehp.h>
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +010036#include <drivers/intel/gma/i915.h>
Arthur Heymanse798e6a2017-12-23 23:09:54 +010037#include <southbridge/intel/common/acpi_pirq_gen.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010038
39#define NMI_OFF 0
40
41#define ENABLE_ACPI_MODE_IN_COREBOOT 0
Patrick Georgie72a8a32012-11-06 11:05:09 +010042
43typedef struct southbridge_intel_i82801ix_config config_t;
44
45static void i82801ix_enable_apic(struct device *dev)
46{
Patrick Georgie72a8a32012-11-06 11:05:09 +010047 u32 reg32;
48 volatile u32 *ioapic_index = (volatile u32 *)(IO_APIC_ADDR);
49 volatile u32 *ioapic_data = (volatile u32 *)(IO_APIC_ADDR + 0x10);
50
51 /* Enable IOAPIC. Keep APIC Range Select at zero. */
52 RCBA8(0x31ff) = 0x03;
53 /* We have to read 0x31ff back if bit0 changed. */
Paul Menzeld0299e42013-10-21 09:28:19 +020054 RCBA8(0x31ff);
Patrick Georgie72a8a32012-11-06 11:05:09 +010055
56 /* Lock maximum redirection entries (MRE), R/WO register. */
57 *ioapic_index = 0x01;
58 reg32 = *ioapic_data;
59 *ioapic_index = 0x01;
60 *ioapic_data = reg32;
61
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080062 setup_ioapic(VIO_APIC_VADDR, 2); /* ICH7 code uses id 2. */
Patrick Georgie72a8a32012-11-06 11:05:09 +010063}
64
65static void i82801ix_enable_serial_irqs(struct device *dev)
66{
67 /* Set packet length and toggle silent mode bit for one frame. */
68 pci_write_config8(dev, D31F0_SERIRQ_CNTL,
69 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
70}
71
72/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
73 * 0x00 - 0000 = Reserved
74 * 0x01 - 0001 = Reserved
75 * 0x02 - 0010 = Reserved
76 * 0x03 - 0011 = IRQ3
77 * 0x04 - 0100 = IRQ4
78 * 0x05 - 0101 = IRQ5
79 * 0x06 - 0110 = IRQ6
80 * 0x07 - 0111 = IRQ7
81 * 0x08 - 1000 = Reserved
82 * 0x09 - 1001 = IRQ9
83 * 0x0A - 1010 = IRQ10
84 * 0x0B - 1011 = IRQ11
85 * 0x0C - 1100 = IRQ12
86 * 0x0D - 1101 = Reserved
87 * 0x0E - 1110 = IRQ14
88 * 0x0F - 1111 = IRQ15
89 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
90 * 0x80 - The PIRQ is not routed.
91 */
92
Elyes HAOUAS8aa50732018-05-13 13:34:58 +020093static void i82801ix_pirq_init(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +010094{
Elyes HAOUAS8aa50732018-05-13 13:34:58 +020095 struct device *irq_dev;
Patrick Georgie72a8a32012-11-06 11:05:09 +010096 /* Get the chip configuration */
97 config_t *config = dev->chip_info;
98
99 pci_write_config8(dev, D31F0_PIRQA_ROUT, config->pirqa_routing);
100 pci_write_config8(dev, D31F0_PIRQB_ROUT, config->pirqb_routing);
101 pci_write_config8(dev, D31F0_PIRQC_ROUT, config->pirqc_routing);
102 pci_write_config8(dev, D31F0_PIRQD_ROUT, config->pirqd_routing);
103
104 pci_write_config8(dev, D31F0_PIRQE_ROUT, config->pirqe_routing);
105 pci_write_config8(dev, D31F0_PIRQF_ROUT, config->pirqf_routing);
106 pci_write_config8(dev, D31F0_PIRQG_ROUT, config->pirqg_routing);
107 pci_write_config8(dev, D31F0_PIRQH_ROUT, config->pirqh_routing);
108
109 /* Eric Biederman once said we should let the OS do this.
110 * I am not so sure anymore he was right.
111 */
112
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200113 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Patrick Georgie72a8a32012-11-06 11:05:09 +0100114 u8 int_pin=0, int_line=0;
115
116 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
117 continue;
118
119 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
120
121 switch (int_pin) {
122 case 1: /* INTA# */ int_line = config->pirqa_routing; break;
123 case 2: /* INTB# */ int_line = config->pirqb_routing; break;
124 case 3: /* INTC# */ int_line = config->pirqc_routing; break;
125 case 4: /* INTD# */ int_line = config->pirqd_routing; break;
126 }
127
128 if (!int_line)
129 continue;
130
131 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line);
132 }
133}
134
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200135static void i82801ix_gpi_routing(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100136{
137 /* Get the chip configuration */
138 config_t *config = dev->chip_info;
139 u32 reg32 = 0;
140
141 /* An array would be much nicer here, or some
142 * other method of doing this.
143 */
144 reg32 |= (config->gpi0_routing & 0x03) << 0;
145 reg32 |= (config->gpi1_routing & 0x03) << 2;
146 reg32 |= (config->gpi2_routing & 0x03) << 4;
147 reg32 |= (config->gpi3_routing & 0x03) << 6;
148 reg32 |= (config->gpi4_routing & 0x03) << 8;
149 reg32 |= (config->gpi5_routing & 0x03) << 10;
150 reg32 |= (config->gpi6_routing & 0x03) << 12;
151 reg32 |= (config->gpi7_routing & 0x03) << 14;
152 reg32 |= (config->gpi8_routing & 0x03) << 16;
153 reg32 |= (config->gpi9_routing & 0x03) << 18;
154 reg32 |= (config->gpi10_routing & 0x03) << 20;
155 reg32 |= (config->gpi11_routing & 0x03) << 22;
156 reg32 |= (config->gpi12_routing & 0x03) << 24;
157 reg32 |= (config->gpi13_routing & 0x03) << 26;
158 reg32 |= (config->gpi14_routing & 0x03) << 28;
159 reg32 |= (config->gpi15_routing & 0x03) << 30;
160
161 pci_write_config32(dev, D31F0_GPIO_ROUT, reg32);
162}
163
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200164static void i82801ix_power_options(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100165{
166 u8 reg8;
167 u16 reg16, pmbase;
168 u32 reg32;
169 const char *state;
170 /* Get the chip configuration */
171 config_t *config = dev->chip_info;
172
Nico Huber9faae2b2018-11-14 00:00:35 +0100173 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Patrick Georgie72a8a32012-11-06 11:05:09 +0100174 int nmi_option;
175
176 /* BIOS must program... */
177 reg32 = pci_read_config32(dev, 0xac);
178 pci_write_config32(dev, 0xac, reg32 | (1 << 30) | (3 << 8));
179
180 /* Which state do we want to goto after g3 (power restored)?
181 * 0 == S0 Full On
182 * 1 == S5 Soft Off
183 *
184 * If the option is not existent (Laptops), use MAINBOARD_POWER_ON.
185 */
Varad Gautam06ef0462015-03-11 09:54:41 +0530186 pwr_on = MAINBOARD_POWER_ON;
187 get_option(&pwr_on, "power_on_after_fail");
Patrick Georgie72a8a32012-11-06 11:05:09 +0100188
189 reg8 = pci_read_config8(dev, D31F0_GEN_PMCON_3);
190 reg8 &= 0xfe;
191 switch (pwr_on) {
192 case MAINBOARD_POWER_OFF:
193 reg8 |= 1;
194 state = "off";
195 break;
196 case MAINBOARD_POWER_ON:
197 reg8 &= ~1;
198 state = "on";
199 break;
200 case MAINBOARD_POWER_KEEP:
201 reg8 &= ~1;
202 state = "state keep";
203 break;
204 default:
205 state = "undefined";
206 }
207
208 reg8 |= (3 << 4); /* avoid #S4 assertions */
209 reg8 &= ~(1 << 3); /* minimum asssertion is 1 to 2 RTCCLK */
210
211 pci_write_config8(dev, D31F0_GEN_PMCON_3, reg8);
212 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
213
214 /* Set up NMI on errors. */
215 reg8 = inb(0x61);
216 reg8 &= 0x0f; /* Higher Nibble must be 0 */
217 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
218 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
219 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
220 outb(reg8, 0x61);
221
222 reg8 = inb(0x74); /* Read from 0x74 as 0x70 is write only. */
223 nmi_option = NMI_OFF;
224 get_option(&nmi_option, "nmi");
225 if (nmi_option) {
226 printk(BIOS_INFO, "NMI sources enabled.\n");
227 reg8 &= ~(1 << 7); /* Set NMI. */
228 } else {
229 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200230 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Patrick Georgie72a8a32012-11-06 11:05:09 +0100231 }
232 outb(reg8, 0x70);
233
234 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
235 reg16 = pci_read_config16(dev, D31F0_GEN_PMCON_1);
236 reg16 &= ~(3 << 0); // SMI# rate 1 minute
237 reg16 |= (1 << 2); // CLKRUN_EN - Mobile/Ultra only
238 reg16 |= (1 << 3); // Speedstep Enable - Mobile/Ultra only
239 reg16 |= (1 << 5); // CPUSLP_EN Desktop only
240
241 if (config->c4onc3_enable)
242 reg16 |= (1 << 7);
243
244 // another laptop wants this?
245 // reg16 &= ~(1 << 10); // BIOS_PCI_EXP_EN - Desktop/Mobile only
246 reg16 |= (1 << 10); // BIOS_PCI_EXP_EN - Desktop/Mobile only
247#if DEBUG_PERIODIC_SMIS
248 /* Set DEBUG_PERIODIC_SMIS in i82801ix.h to debug using
249 * periodic SMIs.
250 */
251 reg16 |= (3 << 0); // Periodic SMI every 8s
252#endif
253 if (config->c5_enable)
254 reg16 |= (1 << 11); /* Enable C5, C6 and PMSYNC# */
255 pci_write_config16(dev, D31F0_GEN_PMCON_1, reg16);
256
257 /* Set exit timings for C5/C6. */
258 if (config->c5_enable) {
259 reg8 = pci_read_config8(dev, D31F0_C5_EXIT_TIMING);
260 reg8 &= ~((7 << 3) | (7 << 0));
261 if (config->c6_enable)
262 reg8 |= (5 << 3) | (3 << 0); /* 38-44us PMSYNC# to STPCLK#,
263 95-102us DPRSTP# to STP_CPU# */
264 else
265 reg8 |= (0 << 3) | (1 << 0); /* 16-17us PMSYNC# to STPCLK#,
266 34-40us DPRSTP# to STP_CPU# */
267 pci_write_config8(dev, D31F0_C5_EXIT_TIMING, reg8);
268 }
269
270 // Set the board's GPI routing.
271 i82801ix_gpi_routing(dev);
272
273 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
274
275 outl(config->gpe0_en, pmbase + 0x28);
276 outw(config->alt_gp_smi_en, pmbase + 0x38);
277
278 /* Set up power management block and determine sleep mode */
279 reg16 = inw(pmbase + 0x00); /* PM1_STS */
280 outw(reg16, pmbase + 0x00); /* Clear status bits. At least bit11 (power
281 button override) must be cleared or SCI
282 will be constantly fired and OSPM must
283 not know about it (ACPI spec says to
284 ignore the bit). */
Patrick Georgie72a8a32012-11-06 11:05:09 +0100285
286 /* Set duty cycle for hardware throttling (defaults to 0x0: 50%). */
287 reg32 = inl(pmbase + 0x10);
288 reg32 &= ~(7 << 5);
289 reg32 |= (config->throttle_duty & 7) << 5;
290 outl(reg32, pmbase + 0x10);
291}
292
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200293static void i82801ix_configure_cstates(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100294{
295 u8 reg8;
296
297 reg8 = pci_read_config8(dev, D31F0_CxSTATE_CNF);
298 reg8 |= (1 << 4) | (1 << 3) | (1 << 2); // Enable Popup & Popdown
299 pci_write_config8(dev, D31F0_CxSTATE_CNF, reg8);
300
301 // Set Deeper Sleep configuration to recommended values
302 reg8 = pci_read_config8(dev, D31F0_C4TIMING_CNT);
303 reg8 &= 0xf0;
304 reg8 |= (2 << 2); // Deeper Sleep to Stop CPU: 34-40us
305 reg8 |= (2 << 0); // Deeper Sleep to Sleep: 15us
306 pci_write_config8(dev, D31F0_C4TIMING_CNT, reg8);
307
308 /* We could enable slow-C4 exit here, if someone needs it? */
309}
310
311static void i82801ix_rtc_init(struct device *dev)
312{
313 u8 reg8;
314 int rtc_failed;
315
316 reg8 = pci_read_config8(dev, D31F0_GEN_PMCON_3);
317 rtc_failed = reg8 & RTC_BATTERY_DEAD;
318 if (rtc_failed) {
319 reg8 &= ~RTC_BATTERY_DEAD;
320 pci_write_config8(dev, D31F0_GEN_PMCON_3, reg8);
321 }
322 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
323
Gabe Blackb3f08c62014-04-30 17:12:25 -0700324 cmos_init(rtc_failed);
Patrick Georgie72a8a32012-11-06 11:05:09 +0100325}
326
327static void enable_hpet(void)
328{
329 u32 reg32;
330
331 /* Move HPET to default address 0xfed00000 and enable it */
332 reg32 = RCBA32(RCBA_HPTC);
333 reg32 |= (1 << 7); // HPET Address Enable
334 reg32 &= ~(3 << 0);
335 RCBA32(RCBA_HPTC) = reg32;
336}
337
338static void enable_clock_gating(void)
339{
340 u32 reg32;
341
342 /* Enable DMI dynamic clock gating. */
343 RCBA32(RCBA_DMIC) |= 3;
344
345 /* Enable Clock Gating for most devices. */
346 reg32 = RCBA32(RCBA_CG);
347 reg32 |= (1 << 31); /* LPC dynamic clock gating */
348 /* USB UHCI dynamic clock gating: */
349 reg32 |= (1 << 29) | (1 << 28);
350 /* SATA dynamic clock gating [0-3]: */
351 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
352 reg32 |= (1 << 23); /* LAN static clock gating (if LAN disabled) */
353 reg32 |= (1 << 22); /* HD audio dynamic clock gating */
354 reg32 &= ~(1 << 21); /* No HD audio static clock gating */
355 reg32 &= ~(1 << 20); /* No USB EHCI static clock gating */
356 reg32 |= (1 << 19); /* USB EHCI dynamic clock gating */
357 /* More SATA dynamic clock gating [4-5]: */
358 reg32 |= (1 << 18) | (1 << 17);
359 reg32 |= (1 << 16); /* PCI dynamic clock gating */
360 /* PCIe, DMI dynamic clock gating: */
361 reg32 |= (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1);
362 reg32 |= (1 << 0); /* PCIe root port static clock gating */
363 RCBA32(RCBA_CG) = reg32;
364
365 /* Enable SPI dynamic clock gating. */
366 RCBA32(0x38c0) |= 7;
367}
368
Patrick Georgie72a8a32012-11-06 11:05:09 +0100369static void i82801ix_lock_smm(struct device *dev)
370{
Kyösti Mälkkic3ed8862014-06-19 19:50:51 +0300371 if (!acpi_is_wakeup_s3()) {
Patrick Georgie72a8a32012-11-06 11:05:09 +0100372#if ENABLE_ACPI_MODE_IN_COREBOOT
373 printk(BIOS_DEBUG, "Enabling ACPI via APMC:\n");
374 outb(APM_CNT_ACPI_ENABLE, APM_CNT); // Enable ACPI mode
375 printk(BIOS_DEBUG, "done.\n");
376#else
377 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
378 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
379 printk(BIOS_DEBUG, "done.\n");
380#endif
381 } else {
382 printk(BIOS_DEBUG, "S3 wakeup, enabling ACPI via APMC\n");
383 outb(APM_CNT_ACPI_ENABLE, APM_CNT);
384 }
385 /* Don't allow evil boot loaders, kernels, or
386 * userspace applications to deceive us:
387 */
Julius Wernercd49cce2019-03-05 16:53:33 -0800388 if (!CONFIG(PARALLEL_MP))
Kyösti Mälkki571b7b22019-07-08 23:25:05 +0300389 aseg_smm_lock();
Patrick Georgie72a8a32012-11-06 11:05:09 +0100390}
Patrick Georgie72a8a32012-11-06 11:05:09 +0100391
392static void lpc_init(struct device *dev)
393{
394 printk(BIOS_DEBUG, "i82801ix: lpc_init\n");
395
396 /* Set the value for PCI command register. */
397 pci_write_config16(dev, PCI_COMMAND, 0x000f);
398
399 /* IO APIC initialization. */
400 i82801ix_enable_apic(dev);
401
402 i82801ix_enable_serial_irqs(dev);
403
404 /* Setup the PIRQ. */
405 i82801ix_pirq_init(dev);
406
407 /* Setup power options. */
408 i82801ix_power_options(dev);
409
410 /* Configure Cx state registers */
411 if (LPC_IS_MOBILE(dev))
412 i82801ix_configure_cstates(dev);
413
414 /* Initialize the real time clock. */
415 i82801ix_rtc_init(dev);
416
417 /* Initialize ISA DMA. */
418 isa_dma_init();
419
420 /* Initialize the High Precision Event Timers, if present. */
421 enable_hpet();
422
423 /* Initialize Clock Gating */
424 enable_clock_gating();
425
426 setup_i8259();
427
428 /* The OS should do this? */
429 /* Interrupt 9 should be level triggered (SCI) */
430 i8259_configure_irq_trigger(9, 1);
431
Kyösti Mälkki571b7b22019-07-08 23:25:05 +0300432 if (CONFIG(HAVE_SMI_HANDLER))
433 i82801ix_lock_smm(dev);
Patrick Georgie72a8a32012-11-06 11:05:09 +0100434}
435
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200436static void i82801ix_lpc_read_resources(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100437{
438 /*
439 * I/O Resources
440 *
441 * 0x0000 - 0x000f....ISA DMA
442 * 0x0010 - 0x001f....ISA DMA aliases
443 * 0x0020 ~ 0x003d....PIC
444 * 0x002e - 0x002f....Maybe Super I/O
445 * 0x0040 - 0x0043....Timer
446 * 0x004e - 0x004f....Maybe Super I/O
447 * 0x0050 - 0x0053....Timer aliases
448 * 0x0061.............NMI_SC
449 * 0x0070.............NMI_EN (readable in alternative access mode)
450 * 0x0070 - 0x0077....RTC
451 * 0x0080 - 0x008f....ISA DMA
452 * 0x0090 ~ 0x009f....ISA DMA aliases
453 * 0x0092.............Fast A20 and Init
454 * 0x00a0 ~ 0x00bd....PIC
455 * 0x00b2 - 0x00b3....APM
456 * 0x00c0 ~ 0x00de....ISA DMA
457 * 0x00c1 ~ 0x00df....ISA DMA aliases
458 * 0x00f0.............Coprocessor Error
459 * (0x0400-0x041f)....SMBus (SMBUS_IO_BASE, during raminit)
460 * 0x04d0 - 0x04d1....PIC
461 * 0x0500 - 0x057f....PM (DEFAULT_PMBASE)
462 * 0x0580 - 0x05bf....SB GPIO (DEFAULT_GPIOBASE)
463 * 0x05c0 - 0x05ff....SB GPIO cont. (mobile only)
464 * 0x0cf8 - 0x0cff....PCI
465 * 0x0cf9.............Reset Control
466 */
467
468 struct resource *res;
469
470 /* Get the normal PCI resources of this device. */
471 pci_dev_read_resources(dev);
472
473 /* Add an extra subtractive resource for both memory and I/O. */
474 res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
475 res->base = 0;
476 res->size = 0x1000;
477 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
478 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
479
480 res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
481 res->base = 0xff800000;
482 res->size = 0x00800000; /* 8 MB for flash */
483 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
484 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
485
486 res = new_resource(dev, 3); /* IOAPIC */
487 res->base = IO_APIC_ADDR;
488 res->size = 0x00001000;
489 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
490}
491
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200492static void southbridge_inject_dsdt(struct device *dev)
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200493{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200494 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200495
496 if (gnvs) {
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100497 const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
Elyes HAOUAS035df002016-10-03 21:54:16 +0200498 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200499 acpi_create_gnvs(gnvs);
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100500
Nico Huber744d6bd2019-01-12 14:58:20 +0100501 if (gfx) {
502 gnvs->ndid = gfx->ndid;
503 memcpy(gnvs->did, gfx->did, sizeof(gnvs->did));
504 }
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100505
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200506 /* And tell SMI about it */
507 smm_setup_structures(gnvs, NULL, NULL);
508
509 /* Add it to SSDT. */
Vladimir Serbinenkof7c75db2014-11-04 21:21:06 +0100510 acpigen_write_scope("\\");
Patrick Rudolph4af2add2018-11-26 15:56:11 +0100511 acpigen_write_name_dword("NVSA", (uintptr_t)gnvs);
Vladimir Serbinenkof7c75db2014-11-04 21:21:06 +0100512 acpigen_pop_len();
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200513 }
514}
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100515
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100516
517static const char *lpc_acpi_name(const struct device *dev)
518{
519 return "LPCB";
520}
521
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200522static void southbridge_fill_ssdt(struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100523{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300524 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100525 config_t *chip = dev->chip_info;
526
527 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100528 intel_acpi_gen_def_acpi_pirq(device);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100529}
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200530
Patrick Georgie72a8a32012-11-06 11:05:09 +0100531static struct pci_operations pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530532 .set_subsystem = pci_dev_set_subsystem,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100533};
534
535static struct device_operations device_ops = {
536 .read_resources = i82801ix_lpc_read_resources,
537 .set_resources = pci_dev_set_resources,
538 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200539 .acpi_inject_dsdt_generator = southbridge_inject_dsdt,
540 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100541 .acpi_fill_ssdt_generator = southbridge_fill_ssdt,
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100542 .acpi_name = lpc_acpi_name,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100543 .init = lpc_init,
Kyösti Mälkkid0e212c2015-02-26 20:47:47 +0200544 .scan_bus = scan_lpc_bus,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100545 .ops_pci = &pci_ops,
546};
547
548static const unsigned short pci_device_ids[] = {
549 0x2912, /* ICH9DH */
550 0x2914, /* ICH9DO */
551 0x2916, /* ICH9R */
552 0x2918, /* ICH9 */
553 0x2917, /* ICH9M-E */
554 0x2919, /* ICH9M */
555 0
556};
557
558static const struct pci_driver ich9_lpc __pci_driver = {
559 .ops = &device_ops,
560 .vendor = PCI_VENDOR_ID_INTEL,
561 .devices = pci_device_ids,
562};