blob: ba2b0282e5455d0ef9f515b98737a8e3de3f9fdf [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
Kyösti Mälkki6feb4da2019-07-13 17:28:37 +0300369static void i82801ix_set_acpi_mode(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100370{
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 }
Patrick Georgie72a8a32012-11-06 11:05:09 +0100385}
Patrick Georgie72a8a32012-11-06 11:05:09 +0100386
387static void lpc_init(struct device *dev)
388{
389 printk(BIOS_DEBUG, "i82801ix: lpc_init\n");
390
391 /* Set the value for PCI command register. */
392 pci_write_config16(dev, PCI_COMMAND, 0x000f);
393
394 /* IO APIC initialization. */
395 i82801ix_enable_apic(dev);
396
397 i82801ix_enable_serial_irqs(dev);
398
399 /* Setup the PIRQ. */
400 i82801ix_pirq_init(dev);
401
402 /* Setup power options. */
403 i82801ix_power_options(dev);
404
405 /* Configure Cx state registers */
406 if (LPC_IS_MOBILE(dev))
407 i82801ix_configure_cstates(dev);
408
409 /* Initialize the real time clock. */
410 i82801ix_rtc_init(dev);
411
412 /* Initialize ISA DMA. */
413 isa_dma_init();
414
415 /* Initialize the High Precision Event Timers, if present. */
416 enable_hpet();
417
418 /* Initialize Clock Gating */
419 enable_clock_gating();
420
421 setup_i8259();
422
423 /* The OS should do this? */
424 /* Interrupt 9 should be level triggered (SCI) */
425 i8259_configure_irq_trigger(9, 1);
426
Kyösti Mälkki571b7b22019-07-08 23:25:05 +0300427 if (CONFIG(HAVE_SMI_HANDLER))
Kyösti Mälkki6feb4da2019-07-13 17:28:37 +0300428 i82801ix_set_acpi_mode(dev);
429
430 /* Don't allow evil boot loaders, kernels, or
431 * userspace applications to deceive us:
432 */
433 if (CONFIG(HAVE_SMI_HANDLER) && CONFIG(SMM_ASEG))
434 aseg_smm_lock();
Patrick Georgie72a8a32012-11-06 11:05:09 +0100435}
436
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200437static void i82801ix_lpc_read_resources(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100438{
439 /*
440 * I/O Resources
441 *
442 * 0x0000 - 0x000f....ISA DMA
443 * 0x0010 - 0x001f....ISA DMA aliases
444 * 0x0020 ~ 0x003d....PIC
445 * 0x002e - 0x002f....Maybe Super I/O
446 * 0x0040 - 0x0043....Timer
447 * 0x004e - 0x004f....Maybe Super I/O
448 * 0x0050 - 0x0053....Timer aliases
449 * 0x0061.............NMI_SC
450 * 0x0070.............NMI_EN (readable in alternative access mode)
451 * 0x0070 - 0x0077....RTC
452 * 0x0080 - 0x008f....ISA DMA
453 * 0x0090 ~ 0x009f....ISA DMA aliases
454 * 0x0092.............Fast A20 and Init
455 * 0x00a0 ~ 0x00bd....PIC
456 * 0x00b2 - 0x00b3....APM
457 * 0x00c0 ~ 0x00de....ISA DMA
458 * 0x00c1 ~ 0x00df....ISA DMA aliases
459 * 0x00f0.............Coprocessor Error
460 * (0x0400-0x041f)....SMBus (SMBUS_IO_BASE, during raminit)
461 * 0x04d0 - 0x04d1....PIC
462 * 0x0500 - 0x057f....PM (DEFAULT_PMBASE)
463 * 0x0580 - 0x05bf....SB GPIO (DEFAULT_GPIOBASE)
464 * 0x05c0 - 0x05ff....SB GPIO cont. (mobile only)
465 * 0x0cf8 - 0x0cff....PCI
466 * 0x0cf9.............Reset Control
467 */
468
469 struct resource *res;
470
471 /* Get the normal PCI resources of this device. */
472 pci_dev_read_resources(dev);
473
474 /* Add an extra subtractive resource for both memory and I/O. */
475 res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
476 res->base = 0;
477 res->size = 0x1000;
478 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
479 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
480
481 res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
482 res->base = 0xff800000;
483 res->size = 0x00800000; /* 8 MB for flash */
484 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
485 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
486
487 res = new_resource(dev, 3); /* IOAPIC */
488 res->base = IO_APIC_ADDR;
489 res->size = 0x00001000;
490 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
491}
492
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200493static void southbridge_inject_dsdt(struct device *dev)
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200494{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200495 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200496
497 if (gnvs) {
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100498 const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
Elyes HAOUAS035df002016-10-03 21:54:16 +0200499 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200500 acpi_create_gnvs(gnvs);
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100501
Nico Huber744d6bd2019-01-12 14:58:20 +0100502 if (gfx) {
503 gnvs->ndid = gfx->ndid;
504 memcpy(gnvs->did, gfx->did, sizeof(gnvs->did));
505 }
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100506
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200507 /* And tell SMI about it */
508 smm_setup_structures(gnvs, NULL, NULL);
509
510 /* Add it to SSDT. */
Vladimir Serbinenkof7c75db2014-11-04 21:21:06 +0100511 acpigen_write_scope("\\");
Patrick Rudolph4af2add2018-11-26 15:56:11 +0100512 acpigen_write_name_dword("NVSA", (uintptr_t)gnvs);
Vladimir Serbinenkof7c75db2014-11-04 21:21:06 +0100513 acpigen_pop_len();
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200514 }
515}
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100516
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100517
518static const char *lpc_acpi_name(const struct device *dev)
519{
520 return "LPCB";
521}
522
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200523static void southbridge_fill_ssdt(struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100524{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300525 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100526 config_t *chip = dev->chip_info;
527
528 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100529 intel_acpi_gen_def_acpi_pirq(device);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100530}
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200531
Patrick Georgie72a8a32012-11-06 11:05:09 +0100532static struct pci_operations pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530533 .set_subsystem = pci_dev_set_subsystem,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100534};
535
536static struct device_operations device_ops = {
537 .read_resources = i82801ix_lpc_read_resources,
538 .set_resources = pci_dev_set_resources,
539 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200540 .acpi_inject_dsdt_generator = southbridge_inject_dsdt,
541 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100542 .acpi_fill_ssdt_generator = southbridge_fill_ssdt,
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100543 .acpi_name = lpc_acpi_name,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100544 .init = lpc_init,
Kyösti Mälkkid0e212c2015-02-26 20:47:47 +0200545 .scan_bus = scan_lpc_bus,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100546 .ops_pci = &pci_ops,
547};
548
549static const unsigned short pci_device_ids[] = {
550 0x2912, /* ICH9DH */
551 0x2914, /* ICH9DO */
552 0x2916, /* ICH9R */
553 0x2918, /* ICH9 */
554 0x2917, /* ICH9M-E */
555 0x2919, /* ICH9M */
556 0
557};
558
559static const struct pci_driver ich9_lpc __pci_driver = {
560 .ops = &device_ops,
561 .vendor = PCI_VENDOR_ID_INTEL,
562 .devices = pci_device_ids,
563};