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