blob: bc45b9ddc1c0068179a351a67ba5c2e06c359fb4 [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>
26#include <arch/ioapic.h>
27#include <arch/acpi.h>
28#include <cpu/cpu.h>
29#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>
Patrick Georgie72a8a32012-11-06 11:05:09 +010037
38#define NMI_OFF 0
39
40#define ENABLE_ACPI_MODE_IN_COREBOOT 0
41#define TEST_SMM_FLASH_LOCKDOWN 0
42
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
93static void i82801ix_pirq_init(device_t dev)
94{
95 device_t irq_dev;
96 /* 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
135static void i82801ix_gpi_routing(device_t dev)
136{
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
164static void i82801ix_power_options(device_t dev)
165{
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
173 int pwr_on=CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
174 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");
230 reg8 |= ( 1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
231 }
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). */
285 reg32 = inl(pmbase + 0x04); // PM1_CNT
286 reg32 &= ~(7 << 10); // SLP_TYP
287 outl(reg32, pmbase + 0x04);
288
289 /* Set duty cycle for hardware throttling (defaults to 0x0: 50%). */
290 reg32 = inl(pmbase + 0x10);
291 reg32 &= ~(7 << 5);
292 reg32 |= (config->throttle_duty & 7) << 5;
293 outl(reg32, pmbase + 0x10);
294}
295
296static void i82801ix_configure_cstates(device_t dev)
297{
298 u8 reg8;
299
300 reg8 = pci_read_config8(dev, D31F0_CxSTATE_CNF);
301 reg8 |= (1 << 4) | (1 << 3) | (1 << 2); // Enable Popup & Popdown
302 pci_write_config8(dev, D31F0_CxSTATE_CNF, reg8);
303
304 // Set Deeper Sleep configuration to recommended values
305 reg8 = pci_read_config8(dev, D31F0_C4TIMING_CNT);
306 reg8 &= 0xf0;
307 reg8 |= (2 << 2); // Deeper Sleep to Stop CPU: 34-40us
308 reg8 |= (2 << 0); // Deeper Sleep to Sleep: 15us
309 pci_write_config8(dev, D31F0_C4TIMING_CNT, reg8);
310
311 /* We could enable slow-C4 exit here, if someone needs it? */
312}
313
314static void i82801ix_rtc_init(struct device *dev)
315{
316 u8 reg8;
317 int rtc_failed;
318
319 reg8 = pci_read_config8(dev, D31F0_GEN_PMCON_3);
320 rtc_failed = reg8 & RTC_BATTERY_DEAD;
321 if (rtc_failed) {
322 reg8 &= ~RTC_BATTERY_DEAD;
323 pci_write_config8(dev, D31F0_GEN_PMCON_3, reg8);
324 }
325 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
326
Gabe Blackb3f08c62014-04-30 17:12:25 -0700327 cmos_init(rtc_failed);
Patrick Georgie72a8a32012-11-06 11:05:09 +0100328}
329
330static void enable_hpet(void)
331{
332 u32 reg32;
333
334 /* Move HPET to default address 0xfed00000 and enable it */
335 reg32 = RCBA32(RCBA_HPTC);
336 reg32 |= (1 << 7); // HPET Address Enable
337 reg32 &= ~(3 << 0);
338 RCBA32(RCBA_HPTC) = reg32;
339}
340
341static void enable_clock_gating(void)
342{
343 u32 reg32;
344
345 /* Enable DMI dynamic clock gating. */
346 RCBA32(RCBA_DMIC) |= 3;
347
348 /* Enable Clock Gating for most devices. */
349 reg32 = RCBA32(RCBA_CG);
350 reg32 |= (1 << 31); /* LPC dynamic clock gating */
351 /* USB UHCI dynamic clock gating: */
352 reg32 |= (1 << 29) | (1 << 28);
353 /* SATA dynamic clock gating [0-3]: */
354 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
355 reg32 |= (1 << 23); /* LAN static clock gating (if LAN disabled) */
356 reg32 |= (1 << 22); /* HD audio dynamic clock gating */
357 reg32 &= ~(1 << 21); /* No HD audio static clock gating */
358 reg32 &= ~(1 << 20); /* No USB EHCI static clock gating */
359 reg32 |= (1 << 19); /* USB EHCI dynamic clock gating */
360 /* More SATA dynamic clock gating [4-5]: */
361 reg32 |= (1 << 18) | (1 << 17);
362 reg32 |= (1 << 16); /* PCI dynamic clock gating */
363 /* PCIe, DMI dynamic clock gating: */
364 reg32 |= (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1);
365 reg32 |= (1 << 0); /* PCIe root port static clock gating */
366 RCBA32(RCBA_CG) = reg32;
367
368 /* Enable SPI dynamic clock gating. */
369 RCBA32(0x38c0) |= 7;
370}
371
Martin Roth7a1a3ad2017-06-24 21:29:38 -0600372#if IS_ENABLED(CONFIG_HAVE_SMI_HANDLER)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100373static void i82801ix_lock_smm(struct device *dev)
374{
375#if TEST_SMM_FLASH_LOCKDOWN
376 u8 reg8;
377#endif
378
Kyösti Mälkkic3ed8862014-06-19 19:50:51 +0300379 if (!acpi_is_wakeup_s3()) {
Patrick Georgie72a8a32012-11-06 11:05:09 +0100380#if ENABLE_ACPI_MODE_IN_COREBOOT
381 printk(BIOS_DEBUG, "Enabling ACPI via APMC:\n");
382 outb(APM_CNT_ACPI_ENABLE, APM_CNT); // Enable ACPI mode
383 printk(BIOS_DEBUG, "done.\n");
384#else
385 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
386 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
387 printk(BIOS_DEBUG, "done.\n");
388#endif
389 } else {
390 printk(BIOS_DEBUG, "S3 wakeup, enabling ACPI via APMC\n");
391 outb(APM_CNT_ACPI_ENABLE, APM_CNT);
392 }
393 /* Don't allow evil boot loaders, kernels, or
394 * userspace applications to deceive us:
395 */
396 smm_lock();
397
398#if TEST_SMM_FLASH_LOCKDOWN
399 /* Now try this: */
400 printk(BIOS_DEBUG, "Locking BIOS to RO... ");
401 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
402 printk(BIOS_DEBUG, " BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
403 (reg8&1)?"rw":"ro");
404 reg8 &= ~(1 << 0); /* clear BIOSWE */
405 pci_write_config8(dev, 0xdc, reg8);
406 reg8 |= (1 << 1); /* set BLE */
407 pci_write_config8(dev, 0xdc, reg8);
408 printk(BIOS_DEBUG, "ok.\n");
409 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
410 printk(BIOS_DEBUG, " BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
411 (reg8&1)?"rw":"ro");
412
413 printk(BIOS_DEBUG, "Writing:\n");
414 *(volatile u8 *)0xfff00000 = 0x00;
415 printk(BIOS_DEBUG, "Testing:\n");
416 reg8 |= (1 << 0); /* set BIOSWE */
417 pci_write_config8(dev, 0xdc, reg8);
418
419 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
420 printk(BIOS_DEBUG, " BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
421 (reg8&1)?"rw":"ro");
422 printk(BIOS_DEBUG, "Done.\n");
423#endif
424}
425#endif
426
427static void lpc_init(struct device *dev)
428{
429 printk(BIOS_DEBUG, "i82801ix: lpc_init\n");
430
431 /* Set the value for PCI command register. */
432 pci_write_config16(dev, PCI_COMMAND, 0x000f);
433
434 /* IO APIC initialization. */
435 i82801ix_enable_apic(dev);
436
437 i82801ix_enable_serial_irqs(dev);
438
439 /* Setup the PIRQ. */
440 i82801ix_pirq_init(dev);
441
442 /* Setup power options. */
443 i82801ix_power_options(dev);
444
445 /* Configure Cx state registers */
446 if (LPC_IS_MOBILE(dev))
447 i82801ix_configure_cstates(dev);
448
449 /* Initialize the real time clock. */
450 i82801ix_rtc_init(dev);
451
452 /* Initialize ISA DMA. */
453 isa_dma_init();
454
455 /* Initialize the High Precision Event Timers, if present. */
456 enable_hpet();
457
458 /* Initialize Clock Gating */
459 enable_clock_gating();
460
461 setup_i8259();
462
463 /* The OS should do this? */
464 /* Interrupt 9 should be level triggered (SCI) */
465 i8259_configure_irq_trigger(9, 1);
466
Martin Roth7a1a3ad2017-06-24 21:29:38 -0600467#if IS_ENABLED(CONFIG_HAVE_SMI_HANDLER)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100468 i82801ix_lock_smm(dev);
469#endif
470}
471
472static void i82801ix_lpc_read_resources(device_t dev)
473{
474 /*
475 * I/O Resources
476 *
477 * 0x0000 - 0x000f....ISA DMA
478 * 0x0010 - 0x001f....ISA DMA aliases
479 * 0x0020 ~ 0x003d....PIC
480 * 0x002e - 0x002f....Maybe Super I/O
481 * 0x0040 - 0x0043....Timer
482 * 0x004e - 0x004f....Maybe Super I/O
483 * 0x0050 - 0x0053....Timer aliases
484 * 0x0061.............NMI_SC
485 * 0x0070.............NMI_EN (readable in alternative access mode)
486 * 0x0070 - 0x0077....RTC
487 * 0x0080 - 0x008f....ISA DMA
488 * 0x0090 ~ 0x009f....ISA DMA aliases
489 * 0x0092.............Fast A20 and Init
490 * 0x00a0 ~ 0x00bd....PIC
491 * 0x00b2 - 0x00b3....APM
492 * 0x00c0 ~ 0x00de....ISA DMA
493 * 0x00c1 ~ 0x00df....ISA DMA aliases
494 * 0x00f0.............Coprocessor Error
495 * (0x0400-0x041f)....SMBus (SMBUS_IO_BASE, during raminit)
496 * 0x04d0 - 0x04d1....PIC
497 * 0x0500 - 0x057f....PM (DEFAULT_PMBASE)
498 * 0x0580 - 0x05bf....SB GPIO (DEFAULT_GPIOBASE)
499 * 0x05c0 - 0x05ff....SB GPIO cont. (mobile only)
500 * 0x0cf8 - 0x0cff....PCI
501 * 0x0cf9.............Reset Control
502 */
503
504 struct resource *res;
505
506 /* Get the normal PCI resources of this device. */
507 pci_dev_read_resources(dev);
508
509 /* Add an extra subtractive resource for both memory and I/O. */
510 res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
511 res->base = 0;
512 res->size = 0x1000;
513 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
514 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
515
516 res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
517 res->base = 0xff800000;
518 res->size = 0x00800000; /* 8 MB for flash */
519 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
520 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
521
522 res = new_resource(dev, 3); /* IOAPIC */
523 res->base = IO_APIC_ADDR;
524 res->size = 0x00001000;
525 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
526}
527
528static void set_subsystem(device_t dev, unsigned vendor, unsigned device)
529{
530 if (!vendor || !device) {
531 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
532 pci_read_config32(dev, PCI_VENDOR_ID));
533 } else {
534 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
535 ((device & 0xffff) << 16) | (vendor & 0xffff));
536 }
537}
538
Alexander Couzensa90dad12015-04-12 21:49:46 +0200539static void southbridge_inject_dsdt(device_t dev)
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200540{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200541 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200542
543 if (gnvs) {
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100544 const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
Elyes HAOUAS035df002016-10-03 21:54:16 +0200545 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200546 acpi_create_gnvs(gnvs);
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100547
548 gnvs->ndid = gfx->ndid;
549 memcpy(gnvs->did, gfx->did, sizeof(gnvs->did));
550
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200551 /* And tell SMI about it */
552 smm_setup_structures(gnvs, NULL, NULL);
553
554 /* Add it to SSDT. */
Vladimir Serbinenkof7c75db2014-11-04 21:21:06 +0100555 acpigen_write_scope("\\");
556 acpigen_write_name_dword("NVSA", (u32) gnvs);
557 acpigen_pop_len();
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200558 }
559}
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100560
Alexander Couzens5eea4582015-04-12 22:18:55 +0200561static void southbridge_fill_ssdt(device_t device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100562{
563 device_t dev = dev_find_slot(0, PCI_DEVFN(0x1f,0));
564 config_t *chip = dev->chip_info;
565
566 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
567}
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200568
Patrick Georgie72a8a32012-11-06 11:05:09 +0100569static struct pci_operations pci_ops = {
570 .set_subsystem = set_subsystem,
571};
572
573static struct device_operations device_ops = {
574 .read_resources = i82801ix_lpc_read_resources,
575 .set_resources = pci_dev_set_resources,
576 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200577 .acpi_inject_dsdt_generator = southbridge_inject_dsdt,
578 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100579 .acpi_fill_ssdt_generator = southbridge_fill_ssdt,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100580 .init = lpc_init,
Kyösti Mälkkid0e212c2015-02-26 20:47:47 +0200581 .scan_bus = scan_lpc_bus,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100582 .ops_pci = &pci_ops,
583};
584
585static const unsigned short pci_device_ids[] = {
586 0x2912, /* ICH9DH */
587 0x2914, /* ICH9DO */
588 0x2916, /* ICH9R */
589 0x2918, /* ICH9 */
590 0x2917, /* ICH9M-E */
591 0x2919, /* ICH9M */
592 0
593};
594
595static const struct pci_driver ich9_lpc __pci_driver = {
596 .ops = &device_ops,
597 .vendor = PCI_VENDOR_ID_INTEL,
598 .devices = pci_device_ids,
599};