blob: a2df123bc951ce6ad262c430b9c3f57e4c6a61a4 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Patrick Georgie72a8a32012-11-06 11:05:09 +01002
3#include <console/console.h>
4#include <device/device.h>
5#include <device/pci.h>
6#include <device/pci_ids.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +02007#include <option.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +01008#include <pc80/mc146818rtc.h>
9#include <pc80/isa-dma.h>
10#include <pc80/i8259.h>
11#include <arch/io.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020012#include <device/pci_ops.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010013#include <arch/ioapic.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070014#include <acpi/acpi.h>
Kyösti Mälkki0c1dd9c2020-06-17 23:37:49 +030015#include <acpi/acpi_gnvs.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010016#include <cpu/x86/smm.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070017#include <acpi/acpigen.h>
Vladimir Serbinenko33769a52014-08-30 22:39:20 +020018#include <cbmem.h>
19#include <string.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030020#include "chip.h"
Patrick Georgie72a8a32012-11-06 11:05:09 +010021#include "i82801ix.h"
Vladimir Serbinenko33769a52014-08-30 22:39:20 +020022#include "nvs.h"
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010023#include <southbridge/intel/common/pciehp.h>
Angel Ponse1a616c2020-06-21 17:02:43 +020024#include <southbridge/intel/common/pmutil.h>
Arthur Heymanse798e6a2017-12-23 23:09:54 +010025#include <southbridge/intel/common/acpi_pirq_gen.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010026
27#define NMI_OFF 0
28
Patrick Georgie72a8a32012-11-06 11:05:09 +010029typedef struct southbridge_intel_i82801ix_config config_t;
30
31static void i82801ix_enable_apic(struct device *dev)
32{
Patrick Georgie72a8a32012-11-06 11:05:09 +010033 u32 reg32;
34 volatile u32 *ioapic_index = (volatile u32 *)(IO_APIC_ADDR);
35 volatile u32 *ioapic_data = (volatile u32 *)(IO_APIC_ADDR + 0x10);
36
37 /* Enable IOAPIC. Keep APIC Range Select at zero. */
38 RCBA8(0x31ff) = 0x03;
39 /* We have to read 0x31ff back if bit0 changed. */
Paul Menzeld0299e42013-10-21 09:28:19 +020040 RCBA8(0x31ff);
Patrick Georgie72a8a32012-11-06 11:05:09 +010041
42 /* Lock maximum redirection entries (MRE), R/WO register. */
43 *ioapic_index = 0x01;
44 reg32 = *ioapic_data;
45 *ioapic_index = 0x01;
46 *ioapic_data = reg32;
47
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080048 setup_ioapic(VIO_APIC_VADDR, 2); /* ICH7 code uses id 2. */
Patrick Georgie72a8a32012-11-06 11:05:09 +010049}
50
51static void i82801ix_enable_serial_irqs(struct device *dev)
52{
53 /* Set packet length and toggle silent mode bit for one frame. */
54 pci_write_config8(dev, D31F0_SERIRQ_CNTL,
55 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
56}
57
58/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
59 * 0x00 - 0000 = Reserved
60 * 0x01 - 0001 = Reserved
61 * 0x02 - 0010 = Reserved
62 * 0x03 - 0011 = IRQ3
63 * 0x04 - 0100 = IRQ4
64 * 0x05 - 0101 = IRQ5
65 * 0x06 - 0110 = IRQ6
66 * 0x07 - 0111 = IRQ7
67 * 0x08 - 1000 = Reserved
68 * 0x09 - 1001 = IRQ9
69 * 0x0A - 1010 = IRQ10
70 * 0x0B - 1011 = IRQ11
71 * 0x0C - 1100 = IRQ12
72 * 0x0D - 1101 = Reserved
73 * 0x0E - 1110 = IRQ14
74 * 0x0F - 1111 = IRQ15
75 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
76 * 0x80 - The PIRQ is not routed.
77 */
78
Elyes HAOUAS8aa50732018-05-13 13:34:58 +020079static void i82801ix_pirq_init(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +010080{
Elyes HAOUAS8aa50732018-05-13 13:34:58 +020081 struct device *irq_dev;
Patrick Georgie72a8a32012-11-06 11:05:09 +010082 /* Get the chip configuration */
83 config_t *config = dev->chip_info;
84
85 pci_write_config8(dev, D31F0_PIRQA_ROUT, config->pirqa_routing);
86 pci_write_config8(dev, D31F0_PIRQB_ROUT, config->pirqb_routing);
87 pci_write_config8(dev, D31F0_PIRQC_ROUT, config->pirqc_routing);
88 pci_write_config8(dev, D31F0_PIRQD_ROUT, config->pirqd_routing);
89
90 pci_write_config8(dev, D31F0_PIRQE_ROUT, config->pirqe_routing);
91 pci_write_config8(dev, D31F0_PIRQF_ROUT, config->pirqf_routing);
92 pci_write_config8(dev, D31F0_PIRQG_ROUT, config->pirqg_routing);
93 pci_write_config8(dev, D31F0_PIRQH_ROUT, config->pirqh_routing);
94
95 /* Eric Biederman once said we should let the OS do this.
96 * I am not so sure anymore he was right.
97 */
98
Elyes HAOUASba28e8d2016-08-31 19:22:16 +020099 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Patrick Georgie72a8a32012-11-06 11:05:09 +0100100 u8 int_pin=0, int_line=0;
101
102 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
103 continue;
104
105 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
106
107 switch (int_pin) {
108 case 1: /* INTA# */ int_line = config->pirqa_routing; break;
109 case 2: /* INTB# */ int_line = config->pirqb_routing; break;
110 case 3: /* INTC# */ int_line = config->pirqc_routing; break;
111 case 4: /* INTD# */ int_line = config->pirqd_routing; break;
112 }
113
114 if (!int_line)
115 continue;
116
117 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line);
118 }
119}
120
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200121static void i82801ix_gpi_routing(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100122{
123 /* Get the chip configuration */
124 config_t *config = dev->chip_info;
125 u32 reg32 = 0;
126
127 /* An array would be much nicer here, or some
128 * other method of doing this.
129 */
130 reg32 |= (config->gpi0_routing & 0x03) << 0;
131 reg32 |= (config->gpi1_routing & 0x03) << 2;
132 reg32 |= (config->gpi2_routing & 0x03) << 4;
133 reg32 |= (config->gpi3_routing & 0x03) << 6;
134 reg32 |= (config->gpi4_routing & 0x03) << 8;
135 reg32 |= (config->gpi5_routing & 0x03) << 10;
136 reg32 |= (config->gpi6_routing & 0x03) << 12;
137 reg32 |= (config->gpi7_routing & 0x03) << 14;
138 reg32 |= (config->gpi8_routing & 0x03) << 16;
139 reg32 |= (config->gpi9_routing & 0x03) << 18;
140 reg32 |= (config->gpi10_routing & 0x03) << 20;
141 reg32 |= (config->gpi11_routing & 0x03) << 22;
142 reg32 |= (config->gpi12_routing & 0x03) << 24;
143 reg32 |= (config->gpi13_routing & 0x03) << 26;
144 reg32 |= (config->gpi14_routing & 0x03) << 28;
145 reg32 |= (config->gpi15_routing & 0x03) << 30;
146
147 pci_write_config32(dev, D31F0_GPIO_ROUT, reg32);
148}
149
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200150static void i82801ix_power_options(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100151{
152 u8 reg8;
153 u16 reg16, pmbase;
154 u32 reg32;
155 const char *state;
156 /* Get the chip configuration */
157 config_t *config = dev->chip_info;
158
Nico Huber9faae2b2018-11-14 00:00:35 +0100159 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Patrick Georgie72a8a32012-11-06 11:05:09 +0100160 int nmi_option;
161
162 /* BIOS must program... */
163 reg32 = pci_read_config32(dev, 0xac);
164 pci_write_config32(dev, 0xac, reg32 | (1 << 30) | (3 << 8));
165
166 /* Which state do we want to goto after g3 (power restored)?
167 * 0 == S0 Full On
168 * 1 == S5 Soft Off
169 *
170 * If the option is not existent (Laptops), use MAINBOARD_POWER_ON.
171 */
Varad Gautam06ef0462015-03-11 09:54:41 +0530172 pwr_on = MAINBOARD_POWER_ON;
173 get_option(&pwr_on, "power_on_after_fail");
Patrick Georgie72a8a32012-11-06 11:05:09 +0100174
175 reg8 = pci_read_config8(dev, D31F0_GEN_PMCON_3);
176 reg8 &= 0xfe;
177 switch (pwr_on) {
178 case MAINBOARD_POWER_OFF:
179 reg8 |= 1;
180 state = "off";
181 break;
182 case MAINBOARD_POWER_ON:
183 reg8 &= ~1;
184 state = "on";
185 break;
186 case MAINBOARD_POWER_KEEP:
187 reg8 &= ~1;
188 state = "state keep";
189 break;
190 default:
191 state = "undefined";
192 }
193
194 reg8 |= (3 << 4); /* avoid #S4 assertions */
195 reg8 &= ~(1 << 3); /* minimum asssertion is 1 to 2 RTCCLK */
196
197 pci_write_config8(dev, D31F0_GEN_PMCON_3, reg8);
198 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
199
200 /* Set up NMI on errors. */
201 reg8 = inb(0x61);
202 reg8 &= 0x0f; /* Higher Nibble must be 0 */
203 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
204 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
205 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
206 outb(reg8, 0x61);
207
208 reg8 = inb(0x74); /* Read from 0x74 as 0x70 is write only. */
209 nmi_option = NMI_OFF;
210 get_option(&nmi_option, "nmi");
211 if (nmi_option) {
212 printk(BIOS_INFO, "NMI sources enabled.\n");
213 reg8 &= ~(1 << 7); /* Set NMI. */
214 } else {
215 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200216 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Patrick Georgie72a8a32012-11-06 11:05:09 +0100217 }
218 outb(reg8, 0x70);
219
220 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
221 reg16 = pci_read_config16(dev, D31F0_GEN_PMCON_1);
222 reg16 &= ~(3 << 0); // SMI# rate 1 minute
223 reg16 |= (1 << 2); // CLKRUN_EN - Mobile/Ultra only
224 reg16 |= (1 << 3); // Speedstep Enable - Mobile/Ultra only
225 reg16 |= (1 << 5); // CPUSLP_EN Desktop only
226
227 if (config->c4onc3_enable)
228 reg16 |= (1 << 7);
229
230 // another laptop wants this?
231 // reg16 &= ~(1 << 10); // BIOS_PCI_EXP_EN - Desktop/Mobile only
232 reg16 |= (1 << 10); // BIOS_PCI_EXP_EN - Desktop/Mobile only
Kyösti Mälkki94464472020-06-13 13:45:42 +0300233 if (CONFIG(DEBUG_PERIODIC_SMI))
234 reg16 |= (3 << 0); // Periodic SMI every 8s
Patrick Georgie72a8a32012-11-06 11:05:09 +0100235 if (config->c5_enable)
236 reg16 |= (1 << 11); /* Enable C5, C6 and PMSYNC# */
237 pci_write_config16(dev, D31F0_GEN_PMCON_1, reg16);
238
239 /* Set exit timings for C5/C6. */
240 if (config->c5_enable) {
241 reg8 = pci_read_config8(dev, D31F0_C5_EXIT_TIMING);
242 reg8 &= ~((7 << 3) | (7 << 0));
243 if (config->c6_enable)
244 reg8 |= (5 << 3) | (3 << 0); /* 38-44us PMSYNC# to STPCLK#,
245 95-102us DPRSTP# to STP_CPU# */
246 else
247 reg8 |= (0 << 3) | (1 << 0); /* 16-17us PMSYNC# to STPCLK#,
248 34-40us DPRSTP# to STP_CPU# */
249 pci_write_config8(dev, D31F0_C5_EXIT_TIMING, reg8);
250 }
251
252 // Set the board's GPI routing.
253 i82801ix_gpi_routing(dev);
254
255 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
256
257 outl(config->gpe0_en, pmbase + 0x28);
258 outw(config->alt_gp_smi_en, pmbase + 0x38);
259
260 /* Set up power management block and determine sleep mode */
261 reg16 = inw(pmbase + 0x00); /* PM1_STS */
262 outw(reg16, pmbase + 0x00); /* Clear status bits. At least bit11 (power
263 button override) must be cleared or SCI
264 will be constantly fired and OSPM must
265 not know about it (ACPI spec says to
266 ignore the bit). */
Patrick Georgie72a8a32012-11-06 11:05:09 +0100267
268 /* Set duty cycle for hardware throttling (defaults to 0x0: 50%). */
269 reg32 = inl(pmbase + 0x10);
270 reg32 &= ~(7 << 5);
271 reg32 |= (config->throttle_duty & 7) << 5;
272 outl(reg32, pmbase + 0x10);
273}
274
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200275static void i82801ix_configure_cstates(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100276{
Angel Pons67406472020-06-08 11:13:42 +0200277 // Enable Popup & Popdown
278 pci_or_config8(dev, D31F0_CxSTATE_CNF, (1 << 4) | (1 << 3) | (1 << 2));
Patrick Georgie72a8a32012-11-06 11:05:09 +0100279
280 // Set Deeper Sleep configuration to recommended values
Angel Pons67406472020-06-08 11:13:42 +0200281 // Deeper Sleep to Stop CPU: 34-40us
282 // Deeper Sleep to Sleep: 15us
283 pci_update_config8(dev, D31F0_C4TIMING_CNT, ~0x0f, (2 << 2) | (2 << 0));
Patrick Georgie72a8a32012-11-06 11:05:09 +0100284
285 /* We could enable slow-C4 exit here, if someone needs it? */
286}
287
288static void i82801ix_rtc_init(struct device *dev)
289{
290 u8 reg8;
291 int rtc_failed;
292
293 reg8 = pci_read_config8(dev, D31F0_GEN_PMCON_3);
294 rtc_failed = reg8 & RTC_BATTERY_DEAD;
295 if (rtc_failed) {
296 reg8 &= ~RTC_BATTERY_DEAD;
297 pci_write_config8(dev, D31F0_GEN_PMCON_3, reg8);
298 }
299 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
300
Gabe Blackb3f08c62014-04-30 17:12:25 -0700301 cmos_init(rtc_failed);
Patrick Georgie72a8a32012-11-06 11:05:09 +0100302}
303
304static void enable_hpet(void)
305{
306 u32 reg32;
307
308 /* Move HPET to default address 0xfed00000 and enable it */
309 reg32 = RCBA32(RCBA_HPTC);
310 reg32 |= (1 << 7); // HPET Address Enable
311 reg32 &= ~(3 << 0);
312 RCBA32(RCBA_HPTC) = reg32;
313}
314
315static void enable_clock_gating(void)
316{
317 u32 reg32;
318
319 /* Enable DMI dynamic clock gating. */
320 RCBA32(RCBA_DMIC) |= 3;
321
322 /* Enable Clock Gating for most devices. */
323 reg32 = RCBA32(RCBA_CG);
324 reg32 |= (1 << 31); /* LPC dynamic clock gating */
325 /* USB UHCI dynamic clock gating: */
326 reg32 |= (1 << 29) | (1 << 28);
327 /* SATA dynamic clock gating [0-3]: */
328 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
329 reg32 |= (1 << 23); /* LAN static clock gating (if LAN disabled) */
330 reg32 |= (1 << 22); /* HD audio dynamic clock gating */
331 reg32 &= ~(1 << 21); /* No HD audio static clock gating */
332 reg32 &= ~(1 << 20); /* No USB EHCI static clock gating */
333 reg32 |= (1 << 19); /* USB EHCI dynamic clock gating */
334 /* More SATA dynamic clock gating [4-5]: */
335 reg32 |= (1 << 18) | (1 << 17);
336 reg32 |= (1 << 16); /* PCI dynamic clock gating */
337 /* PCIe, DMI dynamic clock gating: */
338 reg32 |= (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1);
339 reg32 |= (1 << 0); /* PCIe root port static clock gating */
340 RCBA32(RCBA_CG) = reg32;
341
342 /* Enable SPI dynamic clock gating. */
343 RCBA32(0x38c0) |= 7;
344}
345
Kyösti Mälkki6feb4da2019-07-13 17:28:37 +0300346static void i82801ix_set_acpi_mode(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100347{
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300348 if (!acpi_is_wakeup_s3()) {
349 apm_control(APM_CNT_ACPI_DISABLE);
350 } else {
351 apm_control(APM_CNT_ACPI_ENABLE);
Patrick Georgie72a8a32012-11-06 11:05:09 +0100352 }
Patrick Georgie72a8a32012-11-06 11:05:09 +0100353}
Patrick Georgie72a8a32012-11-06 11:05:09 +0100354
355static void lpc_init(struct device *dev)
356{
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100357 printk(BIOS_DEBUG, "i82801ix: %s\n", __func__);
Patrick Georgie72a8a32012-11-06 11:05:09 +0100358
359 /* Set the value for PCI command register. */
360 pci_write_config16(dev, PCI_COMMAND, 0x000f);
361
362 /* IO APIC initialization. */
363 i82801ix_enable_apic(dev);
364
365 i82801ix_enable_serial_irqs(dev);
366
367 /* Setup the PIRQ. */
368 i82801ix_pirq_init(dev);
369
370 /* Setup power options. */
371 i82801ix_power_options(dev);
372
373 /* Configure Cx state registers */
374 if (LPC_IS_MOBILE(dev))
375 i82801ix_configure_cstates(dev);
376
377 /* Initialize the real time clock. */
378 i82801ix_rtc_init(dev);
379
380 /* Initialize ISA DMA. */
381 isa_dma_init();
382
383 /* Initialize the High Precision Event Timers, if present. */
384 enable_hpet();
385
386 /* Initialize Clock Gating */
387 enable_clock_gating();
388
389 setup_i8259();
390
391 /* The OS should do this? */
392 /* Interrupt 9 should be level triggered (SCI) */
393 i8259_configure_irq_trigger(9, 1);
394
Kyösti Mälkki44da9e72019-10-09 12:32:16 +0300395 i82801ix_set_acpi_mode(dev);
Kyösti Mälkki6feb4da2019-07-13 17:28:37 +0300396
397 /* Don't allow evil boot loaders, kernels, or
398 * userspace applications to deceive us:
399 */
Kyösti Mälkkicd0b67b2019-10-09 07:52:40 +0300400 if (CONFIG(HAVE_SMI_HANDLER) && !CONFIG(PARALLEL_MP))
Kyösti Mälkki6feb4da2019-07-13 17:28:37 +0300401 aseg_smm_lock();
Patrick Georgie72a8a32012-11-06 11:05:09 +0100402}
403
Elyes HAOUAS8aa50732018-05-13 13:34:58 +0200404static void i82801ix_lpc_read_resources(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100405{
406 /*
407 * I/O Resources
408 *
409 * 0x0000 - 0x000f....ISA DMA
410 * 0x0010 - 0x001f....ISA DMA aliases
411 * 0x0020 ~ 0x003d....PIC
412 * 0x002e - 0x002f....Maybe Super I/O
413 * 0x0040 - 0x0043....Timer
414 * 0x004e - 0x004f....Maybe Super I/O
415 * 0x0050 - 0x0053....Timer aliases
416 * 0x0061.............NMI_SC
417 * 0x0070.............NMI_EN (readable in alternative access mode)
418 * 0x0070 - 0x0077....RTC
419 * 0x0080 - 0x008f....ISA DMA
420 * 0x0090 ~ 0x009f....ISA DMA aliases
421 * 0x0092.............Fast A20 and Init
422 * 0x00a0 ~ 0x00bd....PIC
423 * 0x00b2 - 0x00b3....APM
424 * 0x00c0 ~ 0x00de....ISA DMA
425 * 0x00c1 ~ 0x00df....ISA DMA aliases
426 * 0x00f0.............Coprocessor Error
Angel Ponsb21bffa2020-07-03 01:02:28 +0200427 * (0x0400-0x041f)....SMBus (CONFIG_FIXED_SMBUS_IO_BASE, during raminit)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100428 * 0x04d0 - 0x04d1....PIC
429 * 0x0500 - 0x057f....PM (DEFAULT_PMBASE)
430 * 0x0580 - 0x05bf....SB GPIO (DEFAULT_GPIOBASE)
431 * 0x05c0 - 0x05ff....SB GPIO cont. (mobile only)
432 * 0x0cf8 - 0x0cff....PCI
433 * 0x0cf9.............Reset Control
434 */
435
436 struct resource *res;
437
438 /* Get the normal PCI resources of this device. */
439 pci_dev_read_resources(dev);
440
441 /* Add an extra subtractive resource for both memory and I/O. */
442 res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
443 res->base = 0;
444 res->size = 0x1000;
445 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
446 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
447
448 res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
449 res->base = 0xff800000;
450 res->size = 0x00800000; /* 8 MB for flash */
451 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
452 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
453
454 res = new_resource(dev, 3); /* IOAPIC */
455 res->base = IO_APIC_ADDR;
456 res->size = 0x00001000;
457 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
458}
459
Kyösti Mälkki0c1dd9c2020-06-17 23:37:49 +0300460void southbridge_inject_dsdt(const struct device *dev)
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200461{
Kyösti Mälkki0c1dd9c2020-06-17 23:37:49 +0300462 struct global_nvs *gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200463
464 if (gnvs) {
Elyes HAOUAS035df002016-10-03 21:54:16 +0200465 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200466 acpi_create_gnvs(gnvs);
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100467
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200468 /* And tell SMI about it */
Kyösti Mälkkic3c55212020-06-17 10:34:26 +0300469 apm_control(APM_CNT_GNVS_UPDATE);
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200470
471 /* Add it to SSDT. */
Vladimir Serbinenkof7c75db2014-11-04 21:21:06 +0100472 acpigen_write_scope("\\");
Patrick Rudolph4af2add2018-11-26 15:56:11 +0100473 acpigen_write_name_dword("NVSA", (uintptr_t)gnvs);
Vladimir Serbinenkof7c75db2014-11-04 21:21:06 +0100474 acpigen_pop_len();
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200475 }
476}
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100477
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100478
479static const char *lpc_acpi_name(const struct device *dev)
480{
481 return "LPCB";
482}
483
Furquan Shaikh7536a392020-04-24 21:59:21 -0700484static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100485{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300486 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100487 config_t *chip = dev->chip_info;
488
489 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100490 intel_acpi_gen_def_acpi_pirq(device);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100491}
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200492
Patrick Georgie72a8a32012-11-06 11:05:09 +0100493static struct device_operations device_ops = {
494 .read_resources = i82801ix_lpc_read_resources,
495 .set_resources = pci_dev_set_resources,
496 .enable_resources = pci_dev_enable_resources,
Nico Huber68680dd2020-03-31 17:34:52 +0200497 .acpi_inject_dsdt = southbridge_inject_dsdt,
Vladimir Serbinenko33769a52014-08-30 22:39:20 +0200498 .write_acpi_tables = acpi_write_hpet,
Nico Huber68680dd2020-03-31 17:34:52 +0200499 .acpi_fill_ssdt = southbridge_fill_ssdt,
Arthur Heymanse798e6a2017-12-23 23:09:54 +0100500 .acpi_name = lpc_acpi_name,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100501 .init = lpc_init,
Nico Huber51b75ae2019-03-14 16:02:05 +0100502 .scan_bus = scan_static_bus,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200503 .ops_pci = &pci_dev_ops_pci,
Patrick Georgie72a8a32012-11-06 11:05:09 +0100504};
505
506static const unsigned short pci_device_ids[] = {
Felix Singer7f8b0cd2019-11-10 11:04:08 +0100507 PCI_DEVICE_ID_INTEL_82801IH_LPC, /* ICH9DH */
508 PCI_DEVICE_ID_INTEL_82801IO_LPC, /* ICH9DO */
509 PCI_DEVICE_ID_INTEL_82801IR_LPC, /* ICH9R */
510 PCI_DEVICE_ID_INTEL_82801IEM_LPC, /* ICH9M-E */
511 PCI_DEVICE_ID_INTEL_82801IB_LPC, /* ICH9 */
512 PCI_DEVICE_ID_INTEL_82801IBM_LPC, /* ICH9M */
Patrick Georgie72a8a32012-11-06 11:05:09 +0100513 0
514};
515
516static const struct pci_driver ich9_lpc __pci_driver = {
517 .ops = &device_ops,
518 .vendor = PCI_VENDOR_ID_INTEL,
519 .devices = pci_device_ids,
520};