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