blob: 626016402e301a0a2e556bd3fb1261c8137aeeaf [file] [log] [blame]
Patrick Georgie72a8a32012-11-06 11:05:09 +01001/*
2 * This file is part of the coreboot project.
3 *
Patrick Georgie72a8a32012-11-06 11:05:09 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; version 2 of
8 * the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Patrick Georgie72a8a32012-11-06 11:05:09 +010014 */
15
16#include <console/console.h>
17#include <device/device.h>
18#include <device/pci.h>
19#include <device/pci_ids.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020020#include <option.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010021#include <pc80/mc146818rtc.h>
22#include <pc80/isa-dma.h>
23#include <pc80/i8259.h>
24#include <arch/io.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020025#include <device/pci_ops.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010026#include <arch/ioapic.h>
27#include <arch/acpi.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010028#include <cpu/x86/smm.h>
Vladimir Serbinenko33769a52014-08-30 22:39:20 +020029#include <arch/acpigen.h>
30#include <cbmem.h>
31#include <string.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030032#include "chip.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
Patrick Georgie72a8a32012-11-06 11:05:09 +010041typedef struct southbridge_intel_i82801ix_config config_t;
42
43static void i82801ix_enable_apic(struct device *dev)
44{
Patrick Georgie72a8a32012-11-06 11:05:09 +010045 u32 reg32;
46 volatile u32 *ioapic_index = (volatile u32 *)(IO_APIC_ADDR);
47 volatile u32 *ioapic_data = (volatile u32 *)(IO_APIC_ADDR + 0x10);
48
49 /* Enable IOAPIC. Keep APIC Range Select at zero. */
50 RCBA8(0x31ff) = 0x03;
51 /* We have to read 0x31ff back if bit0 changed. */
Paul Menzeld0299e42013-10-21 09:28:19 +020052 RCBA8(0x31ff);
Patrick Georgie72a8a32012-11-06 11:05:09 +010053
54 /* Lock maximum redirection entries (MRE), R/WO register. */
55 *ioapic_index = 0x01;
56 reg32 = *ioapic_data;
57 *ioapic_index = 0x01;
58 *ioapic_data = reg32;
59
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080060 setup_ioapic(VIO_APIC_VADDR, 2); /* ICH7 code uses id 2. */
Patrick Georgie72a8a32012-11-06 11:05:09 +010061}
62
63static void i82801ix_enable_serial_irqs(struct device *dev)
64{
65 /* Set packet length and toggle silent mode bit for one frame. */
66 pci_write_config8(dev, D31F0_SERIRQ_CNTL,
67 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
68}
69
70/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
71 * 0x00 - 0000 = Reserved
72 * 0x01 - 0001 = Reserved
73 * 0x02 - 0010 = Reserved
74 * 0x03 - 0011 = IRQ3
75 * 0x04 - 0100 = IRQ4
76 * 0x05 - 0101 = IRQ5
77 * 0x06 - 0110 = IRQ6
78 * 0x07 - 0111 = IRQ7
79 * 0x08 - 1000 = Reserved
80 * 0x09 - 1001 = IRQ9
81 * 0x0A - 1010 = IRQ10
82 * 0x0B - 1011 = IRQ11
83 * 0x0C - 1100 = IRQ12
84 * 0x0D - 1101 = Reserved
85 * 0x0E - 1110 = IRQ14
86 * 0x0F - 1111 = IRQ15
87 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
88 * 0x80 - The PIRQ is not routed.
89 */
90
Elyes HAOUAS8aa50732018-05-13 13:34:58 +020091static void i82801ix_pirq_init(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +010092{
Elyes HAOUAS8aa50732018-05-13 13:34:58 +020093 struct device *irq_dev;
Patrick Georgie72a8a32012-11-06 11:05:09 +010094 /* Get the chip configuration */
95 config_t *config = dev->chip_info;
96
97 pci_write_config8(dev, D31F0_PIRQA_ROUT, config->pirqa_routing);
98 pci_write_config8(dev, D31F0_PIRQB_ROUT, config->pirqb_routing);
99 pci_write_config8(dev, D31F0_PIRQC_ROUT, config->pirqc_routing);
100 pci_write_config8(dev, D31F0_PIRQD_ROUT, config->pirqd_routing);
101
102 pci_write_config8(dev, D31F0_PIRQE_ROUT, config->pirqe_routing);
103 pci_write_config8(dev, D31F0_PIRQF_ROUT, config->pirqf_routing);
104 pci_write_config8(dev, D31F0_PIRQG_ROUT, config->pirqg_routing);
105 pci_write_config8(dev, D31F0_PIRQH_ROUT, config->pirqh_routing);
106
107 /* Eric Biederman once said we should let the OS do this.
108 * I am not so sure anymore he was right.
109 */
110
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200111 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Patrick Georgie72a8a32012-11-06 11:05:09 +0100112 u8 int_pin=0, int_line=0;
113
114 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
115 continue;
116
117 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
118
119 switch (int_pin) {
120 case 1: /* INTA# */ int_line = config->pirqa_routing; break;
121 case 2: /* INTB# */ int_line = config->pirqb_routing; break;
122 case 3: /* INTC# */ int_line = config->pirqc_routing; break;
123 case 4: /* INTD# */ int_line = config->pirqd_routing; break;
124 }
125
126 if (!int_line)
127 continue;
128
129 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line);
130 }
131}
132
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200133static void i82801ix_gpi_routing(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100134{
135 /* Get the chip configuration */
136 config_t *config = dev->chip_info;
137 u32 reg32 = 0;
138
139 /* An array would be much nicer here, or some
140 * other method of doing this.
141 */
142 reg32 |= (config->gpi0_routing & 0x03) << 0;
143 reg32 |= (config->gpi1_routing & 0x03) << 2;
144 reg32 |= (config->gpi2_routing & 0x03) << 4;
145 reg32 |= (config->gpi3_routing & 0x03) << 6;
146 reg32 |= (config->gpi4_routing & 0x03) << 8;
147 reg32 |= (config->gpi5_routing & 0x03) << 10;
148 reg32 |= (config->gpi6_routing & 0x03) << 12;
149 reg32 |= (config->gpi7_routing & 0x03) << 14;
150 reg32 |= (config->gpi8_routing & 0x03) << 16;
151 reg32 |= (config->gpi9_routing & 0x03) << 18;
152 reg32 |= (config->gpi10_routing & 0x03) << 20;
153 reg32 |= (config->gpi11_routing & 0x03) << 22;
154 reg32 |= (config->gpi12_routing & 0x03) << 24;
155 reg32 |= (config->gpi13_routing & 0x03) << 26;
156 reg32 |= (config->gpi14_routing & 0x03) << 28;
157 reg32 |= (config->gpi15_routing & 0x03) << 30;
158
159 pci_write_config32(dev, D31F0_GPIO_ROUT, reg32);
160}
161
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200162static void i82801ix_power_options(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100163{
164 u8 reg8;
165 u16 reg16, pmbase;
166 u32 reg32;
167 const char *state;
168 /* Get the chip configuration */
169 config_t *config = dev->chip_info;
170
Nico Huber9faae2b2018-11-14 00:00:35 +0100171 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Patrick Georgie72a8a32012-11-06 11:05:09 +0100172 int nmi_option;
173
174 /* BIOS must program... */
175 reg32 = pci_read_config32(dev, 0xac);
176 pci_write_config32(dev, 0xac, reg32 | (1 << 30) | (3 << 8));
177
178 /* Which state do we want to goto after g3 (power restored)?
179 * 0 == S0 Full On
180 * 1 == S5 Soft Off
181 *
182 * If the option is not existent (Laptops), use MAINBOARD_POWER_ON.
183 */
Varad Gautam06ef0462015-03-11 09:54:41 +0530184 pwr_on = MAINBOARD_POWER_ON;
185 get_option(&pwr_on, "power_on_after_fail");
Patrick Georgie72a8a32012-11-06 11:05:09 +0100186
187 reg8 = pci_read_config8(dev, D31F0_GEN_PMCON_3);
188 reg8 &= 0xfe;
189 switch (pwr_on) {
190 case MAINBOARD_POWER_OFF:
191 reg8 |= 1;
192 state = "off";
193 break;
194 case MAINBOARD_POWER_ON:
195 reg8 &= ~1;
196 state = "on";
197 break;
198 case MAINBOARD_POWER_KEEP:
199 reg8 &= ~1;
200 state = "state keep";
201 break;
202 default:
203 state = "undefined";
204 }
205
206 reg8 |= (3 << 4); /* avoid #S4 assertions */
207 reg8 &= ~(1 << 3); /* minimum asssertion is 1 to 2 RTCCLK */
208
209 pci_write_config8(dev, D31F0_GEN_PMCON_3, reg8);
210 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
211
212 /* Set up NMI on errors. */
213 reg8 = inb(0x61);
214 reg8 &= 0x0f; /* Higher Nibble must be 0 */
215 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
216 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
217 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
218 outb(reg8, 0x61);
219
220 reg8 = inb(0x74); /* Read from 0x74 as 0x70 is write only. */
221 nmi_option = NMI_OFF;
222 get_option(&nmi_option, "nmi");
223 if (nmi_option) {
224 printk(BIOS_INFO, "NMI sources enabled.\n");
225 reg8 &= ~(1 << 7); /* Set NMI. */
226 } else {
227 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200228 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Patrick Georgie72a8a32012-11-06 11:05:09 +0100229 }
230 outb(reg8, 0x70);
231
232 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
233 reg16 = pci_read_config16(dev, D31F0_GEN_PMCON_1);
234 reg16 &= ~(3 << 0); // SMI# rate 1 minute
235 reg16 |= (1 << 2); // CLKRUN_EN - Mobile/Ultra only
236 reg16 |= (1 << 3); // Speedstep Enable - Mobile/Ultra only
237 reg16 |= (1 << 5); // CPUSLP_EN Desktop only
238
239 if (config->c4onc3_enable)
240 reg16 |= (1 << 7);
241
242 // another laptop wants this?
243 // reg16 &= ~(1 << 10); // BIOS_PCI_EXP_EN - Desktop/Mobile only
244 reg16 |= (1 << 10); // BIOS_PCI_EXP_EN - Desktop/Mobile only
245#if DEBUG_PERIODIC_SMIS
246 /* Set DEBUG_PERIODIC_SMIS in i82801ix.h to debug using
247 * periodic SMIs.
248 */
249 reg16 |= (3 << 0); // Periodic SMI every 8s
250#endif
251 if (config->c5_enable)
252 reg16 |= (1 << 11); /* Enable C5, C6 and PMSYNC# */
253 pci_write_config16(dev, D31F0_GEN_PMCON_1, reg16);
254
255 /* Set exit timings for C5/C6. */
256 if (config->c5_enable) {
257 reg8 = pci_read_config8(dev, D31F0_C5_EXIT_TIMING);
258 reg8 &= ~((7 << 3) | (7 << 0));
259 if (config->c6_enable)
260 reg8 |= (5 << 3) | (3 << 0); /* 38-44us PMSYNC# to STPCLK#,
261 95-102us DPRSTP# to STP_CPU# */
262 else
263 reg8 |= (0 << 3) | (1 << 0); /* 16-17us PMSYNC# to STPCLK#,
264 34-40us DPRSTP# to STP_CPU# */
265 pci_write_config8(dev, D31F0_C5_EXIT_TIMING, reg8);
266 }
267
268 // Set the board's GPI routing.
269 i82801ix_gpi_routing(dev);
270
271 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
272
273 outl(config->gpe0_en, pmbase + 0x28);
274 outw(config->alt_gp_smi_en, pmbase + 0x38);
275
276 /* Set up power management block and determine sleep mode */
277 reg16 = inw(pmbase + 0x00); /* PM1_STS */
278 outw(reg16, pmbase + 0x00); /* Clear status bits. At least bit11 (power
279 button override) must be cleared or SCI
280 will be constantly fired and OSPM must
281 not know about it (ACPI spec says to
282 ignore the bit). */
Patrick Georgie72a8a32012-11-06 11:05:09 +0100283
284 /* Set duty cycle for hardware throttling (defaults to 0x0: 50%). */
285 reg32 = inl(pmbase + 0x10);
286 reg32 &= ~(7 << 5);
287 reg32 |= (config->throttle_duty & 7) << 5;
288 outl(reg32, pmbase + 0x10);
289}
290
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200291static void i82801ix_configure_cstates(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100292{
293 u8 reg8;
294
295 reg8 = pci_read_config8(dev, D31F0_CxSTATE_CNF);
296 reg8 |= (1 << 4) | (1 << 3) | (1 << 2); // Enable Popup & Popdown
297 pci_write_config8(dev, D31F0_CxSTATE_CNF, reg8);
298
299 // Set Deeper Sleep configuration to recommended values
300 reg8 = pci_read_config8(dev, D31F0_C4TIMING_CNT);
301 reg8 &= 0xf0;
302 reg8 |= (2 << 2); // Deeper Sleep to Stop CPU: 34-40us
303 reg8 |= (2 << 0); // Deeper Sleep to Sleep: 15us
304 pci_write_config8(dev, D31F0_C4TIMING_CNT, reg8);
305
306 /* We could enable slow-C4 exit here, if someone needs it? */
307}
308
309static void i82801ix_rtc_init(struct device *dev)
310{
311 u8 reg8;
312 int rtc_failed;
313
314 reg8 = pci_read_config8(dev, D31F0_GEN_PMCON_3);
315 rtc_failed = reg8 & RTC_BATTERY_DEAD;
316 if (rtc_failed) {
317 reg8 &= ~RTC_BATTERY_DEAD;
318 pci_write_config8(dev, D31F0_GEN_PMCON_3, reg8);
319 }
320 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
321
Gabe Blackb3f08c62014-04-30 17:12:25 -0700322 cmos_init(rtc_failed);
Patrick Georgie72a8a32012-11-06 11:05:09 +0100323}
324
325static void enable_hpet(void)
326{
327 u32 reg32;
328
329 /* Move HPET to default address 0xfed00000 and enable it */
330 reg32 = RCBA32(RCBA_HPTC);
331 reg32 |= (1 << 7); // HPET Address Enable
332 reg32 &= ~(3 << 0);
333 RCBA32(RCBA_HPTC) = reg32;
334}
335
336static void enable_clock_gating(void)
337{
338 u32 reg32;
339
340 /* Enable DMI dynamic clock gating. */
341 RCBA32(RCBA_DMIC) |= 3;
342
343 /* Enable Clock Gating for most devices. */
344 reg32 = RCBA32(RCBA_CG);
345 reg32 |= (1 << 31); /* LPC dynamic clock gating */
346 /* USB UHCI dynamic clock gating: */
347 reg32 |= (1 << 29) | (1 << 28);
348 /* SATA dynamic clock gating [0-3]: */
349 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
350 reg32 |= (1 << 23); /* LAN static clock gating (if LAN disabled) */
351 reg32 |= (1 << 22); /* HD audio dynamic clock gating */
352 reg32 &= ~(1 << 21); /* No HD audio static clock gating */
353 reg32 &= ~(1 << 20); /* No USB EHCI static clock gating */
354 reg32 |= (1 << 19); /* USB EHCI dynamic clock gating */
355 /* More SATA dynamic clock gating [4-5]: */
356 reg32 |= (1 << 18) | (1 << 17);
357 reg32 |= (1 << 16); /* PCI dynamic clock gating */
358 /* PCIe, DMI dynamic clock gating: */
359 reg32 |= (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1);
360 reg32 |= (1 << 0); /* PCIe root port static clock gating */
361 RCBA32(RCBA_CG) = reg32;
362
363 /* Enable SPI dynamic clock gating. */
364 RCBA32(0x38c0) |= 7;
365}
366
Kyösti Mälkki6feb4da2019-07-13 17:28:37 +0300367static void i82801ix_set_acpi_mode(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100368{
Kyösti Mälkki44da9e72019-10-09 12:32:16 +0300369 if (CONFIG(HAVE_SMI_HANDLER)) {
370 if (!acpi_is_wakeup_s3()) {
371 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
372 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
373 printk(BIOS_DEBUG, "done.\n");
374 } else {
375 printk(BIOS_DEBUG, "S3 wakeup, enabling ACPI via APMC\n");
376 outb(APM_CNT_ACPI_ENABLE, APM_CNT);
377 }
Patrick Georgie72a8a32012-11-06 11:05:09 +0100378 }
Patrick Georgie72a8a32012-11-06 11:05:09 +0100379}
Patrick Georgie72a8a32012-11-06 11:05:09 +0100380
381static void lpc_init(struct device *dev)
382{
383 printk(BIOS_DEBUG, "i82801ix: lpc_init\n");
384
385 /* Set the value for PCI command register. */
386 pci_write_config16(dev, PCI_COMMAND, 0x000f);
387
388 /* IO APIC initialization. */
389 i82801ix_enable_apic(dev);
390
391 i82801ix_enable_serial_irqs(dev);
392
393 /* Setup the PIRQ. */
394 i82801ix_pirq_init(dev);
395
396 /* Setup power options. */
397 i82801ix_power_options(dev);
398
399 /* Configure Cx state registers */
400 if (LPC_IS_MOBILE(dev))
401 i82801ix_configure_cstates(dev);
402
403 /* Initialize the real time clock. */
404 i82801ix_rtc_init(dev);
405
406 /* Initialize ISA DMA. */
407 isa_dma_init();
408
409 /* Initialize the High Precision Event Timers, if present. */
410 enable_hpet();
411
412 /* Initialize Clock Gating */
413 enable_clock_gating();
414
415 setup_i8259();
416
417 /* The OS should do this? */
418 /* Interrupt 9 should be level triggered (SCI) */
419 i8259_configure_irq_trigger(9, 1);
420
Kyösti Mälkki44da9e72019-10-09 12:32:16 +0300421 i82801ix_set_acpi_mode(dev);
Kyösti Mälkki6feb4da2019-07-13 17:28:37 +0300422
423 /* Don't allow evil boot loaders, kernels, or
424 * userspace applications to deceive us:
425 */
Kyösti Mälkkicd0b67b2019-10-09 07:52:40 +0300426 if (CONFIG(HAVE_SMI_HANDLER) && !CONFIG(PARALLEL_MP))
Kyösti Mälkki6feb4da2019-07-13 17:28:37 +0300427 aseg_smm_lock();
Patrick Georgie72a8a32012-11-06 11:05:09 +0100428}
429
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200430static void i82801ix_lpc_read_resources(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100431{
432 /*
433 * I/O Resources
434 *
435 * 0x0000 - 0x000f....ISA DMA
436 * 0x0010 - 0x001f....ISA DMA aliases
437 * 0x0020 ~ 0x003d....PIC
438 * 0x002e - 0x002f....Maybe Super I/O
439 * 0x0040 - 0x0043....Timer
440 * 0x004e - 0x004f....Maybe Super I/O
441 * 0x0050 - 0x0053....Timer aliases
442 * 0x0061.............NMI_SC
443 * 0x0070.............NMI_EN (readable in alternative access mode)
444 * 0x0070 - 0x0077....RTC
445 * 0x0080 - 0x008f....ISA DMA
446 * 0x0090 ~ 0x009f....ISA DMA aliases
447 * 0x0092.............Fast A20 and Init
448 * 0x00a0 ~ 0x00bd....PIC
449 * 0x00b2 - 0x00b3....APM
450 * 0x00c0 ~ 0x00de....ISA DMA
451 * 0x00c1 ~ 0x00df....ISA DMA aliases
452 * 0x00f0.............Coprocessor Error
453 * (0x0400-0x041f)....SMBus (SMBUS_IO_BASE, during raminit)
454 * 0x04d0 - 0x04d1....PIC
455 * 0x0500 - 0x057f....PM (DEFAULT_PMBASE)
456 * 0x0580 - 0x05bf....SB GPIO (DEFAULT_GPIOBASE)
457 * 0x05c0 - 0x05ff....SB GPIO cont. (mobile only)
458 * 0x0cf8 - 0x0cff....PCI
459 * 0x0cf9.............Reset Control
460 */
461
462 struct resource *res;
463
464 /* Get the normal PCI resources of this device. */
465 pci_dev_read_resources(dev);
466
467 /* Add an extra subtractive resource for both memory and I/O. */
468 res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
469 res->base = 0;
470 res->size = 0x1000;
471 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
472 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
473
474 res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
475 res->base = 0xff800000;
476 res->size = 0x00800000; /* 8 MB for flash */
477 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
478 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
479
480 res = new_resource(dev, 3); /* IOAPIC */
481 res->base = IO_APIC_ADDR;
482 res->size = 0x00001000;
483 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
484}
485
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200486static void southbridge_inject_dsdt(struct device *dev)
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200487{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200488 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200489
490 if (gnvs) {
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100491 const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
Elyes HAOUAS035df002016-10-03 21:54:16 +0200492 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200493 acpi_create_gnvs(gnvs);
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100494
Nico Huber744d6bd2019-01-12 14:58:20 +0100495 if (gfx) {
496 gnvs->ndid = gfx->ndid;
497 memcpy(gnvs->did, gfx->did, sizeof(gnvs->did));
498 }
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100499
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200500 /* And tell SMI about it */
501 smm_setup_structures(gnvs, NULL, NULL);
502
503 /* Add it to SSDT. */
Vladimir Serbinenkof7c75db2014-11-04 21:21:06 +0100504 acpigen_write_scope("\\");
Patrick Rudolph4af2add2018-11-26 15:56:11 +0100505 acpigen_write_name_dword("NVSA", (uintptr_t)gnvs);
Vladimir Serbinenkof7c75db2014-11-04 21:21:06 +0100506 acpigen_pop_len();
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200507 }
508}
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100509
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100510
511static const char *lpc_acpi_name(const struct device *dev)
512{
513 return "LPCB";
514}
515
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200516static void southbridge_fill_ssdt(struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100517{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300518 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100519 config_t *chip = dev->chip_info;
520
521 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100522 intel_acpi_gen_def_acpi_pirq(device);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100523}
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200524
Patrick Georgie72a8a32012-11-06 11:05:09 +0100525static struct pci_operations pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530526 .set_subsystem = pci_dev_set_subsystem,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100527};
528
529static struct device_operations device_ops = {
530 .read_resources = i82801ix_lpc_read_resources,
531 .set_resources = pci_dev_set_resources,
532 .enable_resources = pci_dev_enable_resources,
Nico Huber68680dd2020-03-31 17:34:52 +0200533 .acpi_inject_dsdt = southbridge_inject_dsdt,
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200534 .write_acpi_tables = acpi_write_hpet,
Nico Huber68680dd2020-03-31 17:34:52 +0200535 .acpi_fill_ssdt = southbridge_fill_ssdt,
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100536 .acpi_name = lpc_acpi_name,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100537 .init = lpc_init,
Nico Huber51b75ae2019-03-14 16:02:05 +0100538 .scan_bus = scan_static_bus,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100539 .ops_pci = &pci_ops,
540};
541
542static const unsigned short pci_device_ids[] = {
Felix Singer7f8b0cd2019-11-10 11:04:08 +0100543 PCI_DEVICE_ID_INTEL_82801IH_LPC, /* ICH9DH */
544 PCI_DEVICE_ID_INTEL_82801IO_LPC, /* ICH9DO */
545 PCI_DEVICE_ID_INTEL_82801IR_LPC, /* ICH9R */
546 PCI_DEVICE_ID_INTEL_82801IEM_LPC, /* ICH9M-E */
547 PCI_DEVICE_ID_INTEL_82801IB_LPC, /* ICH9 */
548 PCI_DEVICE_ID_INTEL_82801IBM_LPC, /* ICH9M */
Patrick Georgie72a8a32012-11-06 11:05:09 +0100549 0
550};
551
552static const struct pci_driver ich9_lpc __pci_driver = {
553 .ops = &device_ops,
554 .vendor = PCI_VENDOR_ID_INTEL,
555 .devices = pci_device_ids,
556};