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