blob: 4f576c4e3d7f8c59051dfe8e76b09a16d4e13a69 [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.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
Paul Menzela46a7122013-02-23 18:37:27 +010019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Patrick Georgie72a8a32012-11-06 11:05:09 +010020 */
21
22#include <console/console.h>
23#include <device/device.h>
24#include <device/pci.h>
25#include <device/pci_ids.h>
26#include <pc80/mc146818rtc.h>
27#include <pc80/isa-dma.h>
28#include <pc80/i8259.h>
29#include <arch/io.h>
30#include <arch/ioapic.h>
31#include <arch/acpi.h>
32#include <cpu/cpu.h>
33#include <cpu/x86/smm.h>
Vladimir Serbinenko33769a52014-08-30 22:39:20 +020034#include <arch/acpigen.h>
35#include <cbmem.h>
36#include <string.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010037#include "i82801ix.h"
Vladimir Serbinenko33769a52014-08-30 22:39:20 +020038#include "nvs.h"
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010039#include <southbridge/intel/common/pciehp.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010040
41#define NMI_OFF 0
42
43#define ENABLE_ACPI_MODE_IN_COREBOOT 0
44#define TEST_SMM_FLASH_LOCKDOWN 0
45
46typedef struct southbridge_intel_i82801ix_config config_t;
47
48static void i82801ix_enable_apic(struct device *dev)
49{
Patrick Georgie72a8a32012-11-06 11:05:09 +010050 u32 reg32;
51 volatile u32 *ioapic_index = (volatile u32 *)(IO_APIC_ADDR);
52 volatile u32 *ioapic_data = (volatile u32 *)(IO_APIC_ADDR + 0x10);
53
54 /* Enable IOAPIC. Keep APIC Range Select at zero. */
55 RCBA8(0x31ff) = 0x03;
56 /* We have to read 0x31ff back if bit0 changed. */
Paul Menzeld0299e42013-10-21 09:28:19 +020057 RCBA8(0x31ff);
Patrick Georgie72a8a32012-11-06 11:05:09 +010058
59 /* Lock maximum redirection entries (MRE), R/WO register. */
60 *ioapic_index = 0x01;
61 reg32 = *ioapic_data;
62 *ioapic_index = 0x01;
63 *ioapic_data = reg32;
64
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080065 setup_ioapic(VIO_APIC_VADDR, 2); /* ICH7 code uses id 2. */
Patrick Georgie72a8a32012-11-06 11:05:09 +010066}
67
68static void i82801ix_enable_serial_irqs(struct device *dev)
69{
70 /* Set packet length and toggle silent mode bit for one frame. */
71 pci_write_config8(dev, D31F0_SERIRQ_CNTL,
72 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
73}
74
75/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
76 * 0x00 - 0000 = Reserved
77 * 0x01 - 0001 = Reserved
78 * 0x02 - 0010 = Reserved
79 * 0x03 - 0011 = IRQ3
80 * 0x04 - 0100 = IRQ4
81 * 0x05 - 0101 = IRQ5
82 * 0x06 - 0110 = IRQ6
83 * 0x07 - 0111 = IRQ7
84 * 0x08 - 1000 = Reserved
85 * 0x09 - 1001 = IRQ9
86 * 0x0A - 1010 = IRQ10
87 * 0x0B - 1011 = IRQ11
88 * 0x0C - 1100 = IRQ12
89 * 0x0D - 1101 = Reserved
90 * 0x0E - 1110 = IRQ14
91 * 0x0F - 1111 = IRQ15
92 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
93 * 0x80 - The PIRQ is not routed.
94 */
95
96static void i82801ix_pirq_init(device_t dev)
97{
98 device_t irq_dev;
99 /* Get the chip configuration */
100 config_t *config = dev->chip_info;
101
102 pci_write_config8(dev, D31F0_PIRQA_ROUT, config->pirqa_routing);
103 pci_write_config8(dev, D31F0_PIRQB_ROUT, config->pirqb_routing);
104 pci_write_config8(dev, D31F0_PIRQC_ROUT, config->pirqc_routing);
105 pci_write_config8(dev, D31F0_PIRQD_ROUT, config->pirqd_routing);
106
107 pci_write_config8(dev, D31F0_PIRQE_ROUT, config->pirqe_routing);
108 pci_write_config8(dev, D31F0_PIRQF_ROUT, config->pirqf_routing);
109 pci_write_config8(dev, D31F0_PIRQG_ROUT, config->pirqg_routing);
110 pci_write_config8(dev, D31F0_PIRQH_ROUT, config->pirqh_routing);
111
112 /* Eric Biederman once said we should let the OS do this.
113 * I am not so sure anymore he was right.
114 */
115
116 for(irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
117 u8 int_pin=0, int_line=0;
118
119 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
120 continue;
121
122 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
123
124 switch (int_pin) {
125 case 1: /* INTA# */ int_line = config->pirqa_routing; break;
126 case 2: /* INTB# */ int_line = config->pirqb_routing; break;
127 case 3: /* INTC# */ int_line = config->pirqc_routing; break;
128 case 4: /* INTD# */ int_line = config->pirqd_routing; break;
129 }
130
131 if (!int_line)
132 continue;
133
134 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line);
135 }
136}
137
138static void i82801ix_gpi_routing(device_t dev)
139{
140 /* Get the chip configuration */
141 config_t *config = dev->chip_info;
142 u32 reg32 = 0;
143
144 /* An array would be much nicer here, or some
145 * other method of doing this.
146 */
147 reg32 |= (config->gpi0_routing & 0x03) << 0;
148 reg32 |= (config->gpi1_routing & 0x03) << 2;
149 reg32 |= (config->gpi2_routing & 0x03) << 4;
150 reg32 |= (config->gpi3_routing & 0x03) << 6;
151 reg32 |= (config->gpi4_routing & 0x03) << 8;
152 reg32 |= (config->gpi5_routing & 0x03) << 10;
153 reg32 |= (config->gpi6_routing & 0x03) << 12;
154 reg32 |= (config->gpi7_routing & 0x03) << 14;
155 reg32 |= (config->gpi8_routing & 0x03) << 16;
156 reg32 |= (config->gpi9_routing & 0x03) << 18;
157 reg32 |= (config->gpi10_routing & 0x03) << 20;
158 reg32 |= (config->gpi11_routing & 0x03) << 22;
159 reg32 |= (config->gpi12_routing & 0x03) << 24;
160 reg32 |= (config->gpi13_routing & 0x03) << 26;
161 reg32 |= (config->gpi14_routing & 0x03) << 28;
162 reg32 |= (config->gpi15_routing & 0x03) << 30;
163
164 pci_write_config32(dev, D31F0_GPIO_ROUT, reg32);
165}
166
167static void i82801ix_power_options(device_t dev)
168{
169 u8 reg8;
170 u16 reg16, pmbase;
171 u32 reg32;
172 const char *state;
173 /* Get the chip configuration */
174 config_t *config = dev->chip_info;
175
176 int pwr_on=CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
177 int nmi_option;
178
179 /* BIOS must program... */
180 reg32 = pci_read_config32(dev, 0xac);
181 pci_write_config32(dev, 0xac, reg32 | (1 << 30) | (3 << 8));
182
183 /* Which state do we want to goto after g3 (power restored)?
184 * 0 == S0 Full On
185 * 1 == S5 Soft Off
186 *
187 * If the option is not existent (Laptops), use MAINBOARD_POWER_ON.
188 */
Varad Gautam06ef0462015-03-11 09:54:41 +0530189 pwr_on = MAINBOARD_POWER_ON;
190 get_option(&pwr_on, "power_on_after_fail");
Patrick Georgie72a8a32012-11-06 11:05:09 +0100191
192 reg8 = pci_read_config8(dev, D31F0_GEN_PMCON_3);
193 reg8 &= 0xfe;
194 switch (pwr_on) {
195 case MAINBOARD_POWER_OFF:
196 reg8 |= 1;
197 state = "off";
198 break;
199 case MAINBOARD_POWER_ON:
200 reg8 &= ~1;
201 state = "on";
202 break;
203 case MAINBOARD_POWER_KEEP:
204 reg8 &= ~1;
205 state = "state keep";
206 break;
207 default:
208 state = "undefined";
209 }
210
211 reg8 |= (3 << 4); /* avoid #S4 assertions */
212 reg8 &= ~(1 << 3); /* minimum asssertion is 1 to 2 RTCCLK */
213
214 pci_write_config8(dev, D31F0_GEN_PMCON_3, reg8);
215 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
216
217 /* Set up NMI on errors. */
218 reg8 = inb(0x61);
219 reg8 &= 0x0f; /* Higher Nibble must be 0 */
220 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
221 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
222 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
223 outb(reg8, 0x61);
224
225 reg8 = inb(0x74); /* Read from 0x74 as 0x70 is write only. */
226 nmi_option = NMI_OFF;
227 get_option(&nmi_option, "nmi");
228 if (nmi_option) {
229 printk(BIOS_INFO, "NMI sources enabled.\n");
230 reg8 &= ~(1 << 7); /* Set NMI. */
231 } else {
232 printk(BIOS_INFO, "NMI sources disabled.\n");
233 reg8 |= ( 1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
234 }
235 outb(reg8, 0x70);
236
237 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
238 reg16 = pci_read_config16(dev, D31F0_GEN_PMCON_1);
239 reg16 &= ~(3 << 0); // SMI# rate 1 minute
240 reg16 |= (1 << 2); // CLKRUN_EN - Mobile/Ultra only
241 reg16 |= (1 << 3); // Speedstep Enable - Mobile/Ultra only
242 reg16 |= (1 << 5); // CPUSLP_EN Desktop only
243
244 if (config->c4onc3_enable)
245 reg16 |= (1 << 7);
246
247 // another laptop wants this?
248 // reg16 &= ~(1 << 10); // BIOS_PCI_EXP_EN - Desktop/Mobile only
249 reg16 |= (1 << 10); // BIOS_PCI_EXP_EN - Desktop/Mobile only
250#if DEBUG_PERIODIC_SMIS
251 /* Set DEBUG_PERIODIC_SMIS in i82801ix.h to debug using
252 * periodic SMIs.
253 */
254 reg16 |= (3 << 0); // Periodic SMI every 8s
255#endif
256 if (config->c5_enable)
257 reg16 |= (1 << 11); /* Enable C5, C6 and PMSYNC# */
258 pci_write_config16(dev, D31F0_GEN_PMCON_1, reg16);
259
260 /* Set exit timings for C5/C6. */
261 if (config->c5_enable) {
262 reg8 = pci_read_config8(dev, D31F0_C5_EXIT_TIMING);
263 reg8 &= ~((7 << 3) | (7 << 0));
264 if (config->c6_enable)
265 reg8 |= (5 << 3) | (3 << 0); /* 38-44us PMSYNC# to STPCLK#,
266 95-102us DPRSTP# to STP_CPU# */
267 else
268 reg8 |= (0 << 3) | (1 << 0); /* 16-17us PMSYNC# to STPCLK#,
269 34-40us DPRSTP# to STP_CPU# */
270 pci_write_config8(dev, D31F0_C5_EXIT_TIMING, reg8);
271 }
272
273 // Set the board's GPI routing.
274 i82801ix_gpi_routing(dev);
275
276 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
277
278 outl(config->gpe0_en, pmbase + 0x28);
279 outw(config->alt_gp_smi_en, pmbase + 0x38);
280
281 /* Set up power management block and determine sleep mode */
282 reg16 = inw(pmbase + 0x00); /* PM1_STS */
283 outw(reg16, pmbase + 0x00); /* Clear status bits. At least bit11 (power
284 button override) must be cleared or SCI
285 will be constantly fired and OSPM must
286 not know about it (ACPI spec says to
287 ignore the bit). */
288 reg32 = inl(pmbase + 0x04); // PM1_CNT
289 reg32 &= ~(7 << 10); // SLP_TYP
290 outl(reg32, pmbase + 0x04);
291
292 /* Set duty cycle for hardware throttling (defaults to 0x0: 50%). */
293 reg32 = inl(pmbase + 0x10);
294 reg32 &= ~(7 << 5);
295 reg32 |= (config->throttle_duty & 7) << 5;
296 outl(reg32, pmbase + 0x10);
297}
298
299static void i82801ix_configure_cstates(device_t dev)
300{
301 u8 reg8;
302
303 reg8 = pci_read_config8(dev, D31F0_CxSTATE_CNF);
304 reg8 |= (1 << 4) | (1 << 3) | (1 << 2); // Enable Popup & Popdown
305 pci_write_config8(dev, D31F0_CxSTATE_CNF, reg8);
306
307 // Set Deeper Sleep configuration to recommended values
308 reg8 = pci_read_config8(dev, D31F0_C4TIMING_CNT);
309 reg8 &= 0xf0;
310 reg8 |= (2 << 2); // Deeper Sleep to Stop CPU: 34-40us
311 reg8 |= (2 << 0); // Deeper Sleep to Sleep: 15us
312 pci_write_config8(dev, D31F0_C4TIMING_CNT, reg8);
313
314 /* We could enable slow-C4 exit here, if someone needs it? */
315}
316
317static void i82801ix_rtc_init(struct device *dev)
318{
319 u8 reg8;
320 int rtc_failed;
321
322 reg8 = pci_read_config8(dev, D31F0_GEN_PMCON_3);
323 rtc_failed = reg8 & RTC_BATTERY_DEAD;
324 if (rtc_failed) {
325 reg8 &= ~RTC_BATTERY_DEAD;
326 pci_write_config8(dev, D31F0_GEN_PMCON_3, reg8);
327 }
328 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
329
Gabe Blackb3f08c62014-04-30 17:12:25 -0700330 cmos_init(rtc_failed);
Patrick Georgie72a8a32012-11-06 11:05:09 +0100331}
332
333static void enable_hpet(void)
334{
335 u32 reg32;
336
337 /* Move HPET to default address 0xfed00000 and enable it */
338 reg32 = RCBA32(RCBA_HPTC);
339 reg32 |= (1 << 7); // HPET Address Enable
340 reg32 &= ~(3 << 0);
341 RCBA32(RCBA_HPTC) = reg32;
342}
343
344static void enable_clock_gating(void)
345{
346 u32 reg32;
347
348 /* Enable DMI dynamic clock gating. */
349 RCBA32(RCBA_DMIC) |= 3;
350
351 /* Enable Clock Gating for most devices. */
352 reg32 = RCBA32(RCBA_CG);
353 reg32 |= (1 << 31); /* LPC dynamic clock gating */
354 /* USB UHCI dynamic clock gating: */
355 reg32 |= (1 << 29) | (1 << 28);
356 /* SATA dynamic clock gating [0-3]: */
357 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
358 reg32 |= (1 << 23); /* LAN static clock gating (if LAN disabled) */
359 reg32 |= (1 << 22); /* HD audio dynamic clock gating */
360 reg32 &= ~(1 << 21); /* No HD audio static clock gating */
361 reg32 &= ~(1 << 20); /* No USB EHCI static clock gating */
362 reg32 |= (1 << 19); /* USB EHCI dynamic clock gating */
363 /* More SATA dynamic clock gating [4-5]: */
364 reg32 |= (1 << 18) | (1 << 17);
365 reg32 |= (1 << 16); /* PCI dynamic clock gating */
366 /* PCIe, DMI dynamic clock gating: */
367 reg32 |= (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1);
368 reg32 |= (1 << 0); /* PCIe root port static clock gating */
369 RCBA32(RCBA_CG) = reg32;
370
371 /* Enable SPI dynamic clock gating. */
372 RCBA32(0x38c0) |= 7;
373}
374
375#if CONFIG_HAVE_SMI_HANDLER
376static void i82801ix_lock_smm(struct device *dev)
377{
378#if TEST_SMM_FLASH_LOCKDOWN
379 u8 reg8;
380#endif
381
Kyösti Mälkkic3ed8862014-06-19 19:50:51 +0300382 if (!acpi_is_wakeup_s3()) {
Patrick Georgie72a8a32012-11-06 11:05:09 +0100383#if ENABLE_ACPI_MODE_IN_COREBOOT
384 printk(BIOS_DEBUG, "Enabling ACPI via APMC:\n");
385 outb(APM_CNT_ACPI_ENABLE, APM_CNT); // Enable ACPI mode
386 printk(BIOS_DEBUG, "done.\n");
387#else
388 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
389 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
390 printk(BIOS_DEBUG, "done.\n");
391#endif
392 } else {
393 printk(BIOS_DEBUG, "S3 wakeup, enabling ACPI via APMC\n");
394 outb(APM_CNT_ACPI_ENABLE, APM_CNT);
395 }
396 /* Don't allow evil boot loaders, kernels, or
397 * userspace applications to deceive us:
398 */
399 smm_lock();
400
401#if TEST_SMM_FLASH_LOCKDOWN
402 /* Now try this: */
403 printk(BIOS_DEBUG, "Locking BIOS to RO... ");
404 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
405 printk(BIOS_DEBUG, " BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
406 (reg8&1)?"rw":"ro");
407 reg8 &= ~(1 << 0); /* clear BIOSWE */
408 pci_write_config8(dev, 0xdc, reg8);
409 reg8 |= (1 << 1); /* set BLE */
410 pci_write_config8(dev, 0xdc, reg8);
411 printk(BIOS_DEBUG, "ok.\n");
412 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
413 printk(BIOS_DEBUG, " BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
414 (reg8&1)?"rw":"ro");
415
416 printk(BIOS_DEBUG, "Writing:\n");
417 *(volatile u8 *)0xfff00000 = 0x00;
418 printk(BIOS_DEBUG, "Testing:\n");
419 reg8 |= (1 << 0); /* set BIOSWE */
420 pci_write_config8(dev, 0xdc, reg8);
421
422 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
423 printk(BIOS_DEBUG, " BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
424 (reg8&1)?"rw":"ro");
425 printk(BIOS_DEBUG, "Done.\n");
426#endif
427}
428#endif
429
430static void lpc_init(struct device *dev)
431{
432 printk(BIOS_DEBUG, "i82801ix: lpc_init\n");
433
434 /* Set the value for PCI command register. */
435 pci_write_config16(dev, PCI_COMMAND, 0x000f);
436
437 /* IO APIC initialization. */
438 i82801ix_enable_apic(dev);
439
440 i82801ix_enable_serial_irqs(dev);
441
442 /* Setup the PIRQ. */
443 i82801ix_pirq_init(dev);
444
445 /* Setup power options. */
446 i82801ix_power_options(dev);
447
448 /* Configure Cx state registers */
449 if (LPC_IS_MOBILE(dev))
450 i82801ix_configure_cstates(dev);
451
452 /* Initialize the real time clock. */
453 i82801ix_rtc_init(dev);
454
455 /* Initialize ISA DMA. */
456 isa_dma_init();
457
458 /* Initialize the High Precision Event Timers, if present. */
459 enable_hpet();
460
461 /* Initialize Clock Gating */
462 enable_clock_gating();
463
464 setup_i8259();
465
466 /* The OS should do this? */
467 /* Interrupt 9 should be level triggered (SCI) */
468 i8259_configure_irq_trigger(9, 1);
469
470#if CONFIG_HAVE_SMI_HANDLER
471 i82801ix_lock_smm(dev);
472#endif
473}
474
475static void i82801ix_lpc_read_resources(device_t dev)
476{
477 /*
478 * I/O Resources
479 *
480 * 0x0000 - 0x000f....ISA DMA
481 * 0x0010 - 0x001f....ISA DMA aliases
482 * 0x0020 ~ 0x003d....PIC
483 * 0x002e - 0x002f....Maybe Super I/O
484 * 0x0040 - 0x0043....Timer
485 * 0x004e - 0x004f....Maybe Super I/O
486 * 0x0050 - 0x0053....Timer aliases
487 * 0x0061.............NMI_SC
488 * 0x0070.............NMI_EN (readable in alternative access mode)
489 * 0x0070 - 0x0077....RTC
490 * 0x0080 - 0x008f....ISA DMA
491 * 0x0090 ~ 0x009f....ISA DMA aliases
492 * 0x0092.............Fast A20 and Init
493 * 0x00a0 ~ 0x00bd....PIC
494 * 0x00b2 - 0x00b3....APM
495 * 0x00c0 ~ 0x00de....ISA DMA
496 * 0x00c1 ~ 0x00df....ISA DMA aliases
497 * 0x00f0.............Coprocessor Error
498 * (0x0400-0x041f)....SMBus (SMBUS_IO_BASE, during raminit)
499 * 0x04d0 - 0x04d1....PIC
500 * 0x0500 - 0x057f....PM (DEFAULT_PMBASE)
501 * 0x0580 - 0x05bf....SB GPIO (DEFAULT_GPIOBASE)
502 * 0x05c0 - 0x05ff....SB GPIO cont. (mobile only)
503 * 0x0cf8 - 0x0cff....PCI
504 * 0x0cf9.............Reset Control
505 */
506
507 struct resource *res;
508
509 /* Get the normal PCI resources of this device. */
510 pci_dev_read_resources(dev);
511
512 /* Add an extra subtractive resource for both memory and I/O. */
513 res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
514 res->base = 0;
515 res->size = 0x1000;
516 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
517 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
518
519 res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
520 res->base = 0xff800000;
521 res->size = 0x00800000; /* 8 MB for flash */
522 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
523 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
524
525 res = new_resource(dev, 3); /* IOAPIC */
526 res->base = IO_APIC_ADDR;
527 res->size = 0x00001000;
528 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
529}
530
531static void set_subsystem(device_t dev, unsigned vendor, unsigned device)
532{
533 if (!vendor || !device) {
534 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
535 pci_read_config32(dev, PCI_VENDOR_ID));
536 } else {
537 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
538 ((device & 0xffff) << 16) | (vendor & 0xffff));
539 }
540}
541
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200542static void southbridge_inject_dsdt(void)
543{
544 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof (*gnvs));
545
546 if (gnvs) {
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200547 memset(gnvs, 0, sizeof (*gnvs));
548 acpi_create_gnvs(gnvs);
549 /* And tell SMI about it */
550 smm_setup_structures(gnvs, NULL, NULL);
551
552 /* Add it to SSDT. */
Vladimir Serbinenkof7c75db2014-11-04 21:21:06 +0100553 acpigen_write_scope("\\");
554 acpigen_write_name_dword("NVSA", (u32) gnvs);
555 acpigen_pop_len();
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200556 }
557}
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100558
559static void southbridge_fill_ssdt(void)
560{
561 device_t dev = dev_find_slot(0, PCI_DEVFN(0x1f,0));
562 config_t *chip = dev->chip_info;
563
564 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
565}
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200566
Patrick Georgie72a8a32012-11-06 11:05:09 +0100567static struct pci_operations pci_ops = {
568 .set_subsystem = set_subsystem,
569};
570
571static struct device_operations device_ops = {
572 .read_resources = i82801ix_lpc_read_resources,
573 .set_resources = pci_dev_set_resources,
574 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200575 .acpi_inject_dsdt_generator = southbridge_inject_dsdt,
576 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100577 .acpi_fill_ssdt_generator = southbridge_fill_ssdt,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100578 .init = lpc_init,
579 .scan_bus = scan_static_bus,
580 .ops_pci = &pci_ops,
581};
582
583static const unsigned short pci_device_ids[] = {
584 0x2912, /* ICH9DH */
585 0x2914, /* ICH9DO */
586 0x2916, /* ICH9R */
587 0x2918, /* ICH9 */
588 0x2917, /* ICH9M-E */
589 0x2919, /* ICH9M */
590 0
591};
592
593static const struct pci_driver ich9_lpc __pci_driver = {
594 .ops = &device_ops,
595 .vendor = PCI_VENDOR_ID_INTEL,
596 .devices = pci_device_ids,
597};