blob: 1100544707a47af3d470cb3bf46522722637bdb6 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Stefan Reinauer8e073822012-04-04 00:07:22 +02003
4#include <console/console.h>
5#include <device/device.h>
6#include <device/pci.h>
7#include <device/pci_ids.h>
Patrick Rudolphe56189c2018-04-18 10:11:59 +02008#include <device/pci_ops.h>
Patrick Rudolphef8c5592018-07-27 17:48:27 +02009#include <device/pci_def.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020010#include <option.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020011#include <pc80/isa-dma.h>
12#include <pc80/i8259.h>
13#include <arch/io.h>
14#include <arch/ioapic.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070015#include <acpi/acpi.h>
16#include <acpi/acpigen.h>
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +020017#include <cpu/x86/smm.h>
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020018#include <cbmem.h>
Vladimir Serbinenko7309c642014-10-05 11:07:33 +020019#include <string.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030020#include "chip.h"
Stefan Reinauer8e073822012-04-04 00:07:22 +020021#include "pch.h"
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020022#include "nvs.h"
Michał Żygowski9ff2af22020-04-13 20:37:36 +020023#include <northbridge/intel/sandybridge/sandybridge.h>
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010024#include <southbridge/intel/common/pciehp.h>
Tobias Diedrich7f5efd92017-12-14 00:29:01 +010025#include <southbridge/intel/common/acpi_pirq_gen.h>
Arthur Heymansa0508172018-01-25 11:30:22 +010026#include <southbridge/intel/common/pmutil.h>
Patrick Rudolph6b931122018-11-01 17:48:37 +010027#include <southbridge/intel/common/rtc.h>
Arthur Heymansebf201b2019-05-28 13:51:36 +020028#include <southbridge/intel/common/spi.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020029
30#define NMI_OFF 0
31
Stefan Reinauer8e073822012-04-04 00:07:22 +020032typedef struct southbridge_intel_bd82x6x_config config_t;
33
Paul Menzel9c50e6a2013-05-03 12:23:39 +020034/**
35 * Set miscellanous static southbridge features.
36 *
37 * @param dev PCI device with I/O APIC control registers
38 */
39static void pch_enable_ioapic(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020040{
Stefan Reinauer8e073822012-04-04 00:07:22 +020041 u32 reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +020042
Nico Huberb2dae792015-10-26 12:34:02 +010043 /* Assign unique bus/dev/fn for I/O APIC */
44 pci_write_config16(dev, LPC_IBDF,
45 PCH_IOAPIC_PCI_BUS << 8 | PCH_IOAPIC_PCI_SLOT << 3);
46
Paul Menzel9c50e6a2013-05-03 12:23:39 +020047 /* Enable ACPI I/O range decode */
48 pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
Stefan Reinauer8e073822012-04-04 00:07:22 +020049
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080050 set_ioapic_id(VIO_APIC_VADDR, 0x02);
Stefan Reinauer8e073822012-04-04 00:07:22 +020051
52 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080053 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
54 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +020055
Paul Menzel9c50e6a2013-05-03 12:23:39 +020056 /*
57 * Select Boot Configuration register (0x03) and
58 * use Processor System Bus (0x01) to deliver interrupts.
59 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080060 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Stefan Reinauer8e073822012-04-04 00:07:22 +020061}
62
63static void pch_enable_serial_irqs(struct device *dev)
64{
65 /* Set packet length and toggle silent mode bit for one frame. */
66 pci_write_config8(dev, SERIRQ_CNTL,
67 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080068#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Stefan Reinauer8e073822012-04-04 00:07:22 +020069 pci_write_config8(dev, SERIRQ_CNTL,
70 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
71#endif
72}
73
74/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
75 * 0x00 - 0000 = Reserved
76 * 0x01 - 0001 = Reserved
77 * 0x02 - 0010 = Reserved
78 * 0x03 - 0011 = IRQ3
79 * 0x04 - 0100 = IRQ4
80 * 0x05 - 0101 = IRQ5
81 * 0x06 - 0110 = IRQ6
82 * 0x07 - 0111 = IRQ7
83 * 0x08 - 1000 = Reserved
84 * 0x09 - 1001 = IRQ9
85 * 0x0A - 1010 = IRQ10
86 * 0x0B - 1011 = IRQ11
87 * 0x0C - 1100 = IRQ12
88 * 0x0D - 1101 = Reserved
89 * 0x0E - 1110 = IRQ14
90 * 0x0F - 1111 = IRQ15
91 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
92 * 0x80 - The PIRQ is not routed.
93 */
94
Elyes HAOUAS4aec3402018-05-25 08:29:27 +020095static void pch_pirq_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020096{
Elyes HAOUAS4aec3402018-05-25 08:29:27 +020097 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020098 /* Interrupt 11 is not used by legacy devices and so can always be used for
99 PCI interrupts. Full legacy IRQ routing is complicated and hard to
100 get right. Fortunately all modern OS use MSI and so it's not that big of
101 an issue anyway. Still we have to provide a reasonable default. Using
102 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
103 move it to any interrupt and others will just leave them at default.
Stefan Reinauer8e073822012-04-04 00:07:22 +0200104 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200105 const u8 pirq_routing = 11;
106
107 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
108 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
109 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
110 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
111
112 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
113 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
114 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
115 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200116
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200117 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200118 u8 int_pin=0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200119
120 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
121 continue;
122
123 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
124
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200125 if (int_pin == 0)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200126 continue;
127
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200128 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200129 }
130}
131
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200132static void pch_gpi_routing(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200133{
134 /* Get the chip configuration */
135 config_t *config = dev->chip_info;
136 u32 reg32 = 0;
137
138 /* An array would be much nicer here, or some
139 * other method of doing this.
140 */
141 reg32 |= (config->gpi0_routing & 0x03) << 0;
142 reg32 |= (config->gpi1_routing & 0x03) << 2;
143 reg32 |= (config->gpi2_routing & 0x03) << 4;
144 reg32 |= (config->gpi3_routing & 0x03) << 6;
145 reg32 |= (config->gpi4_routing & 0x03) << 8;
146 reg32 |= (config->gpi5_routing & 0x03) << 10;
147 reg32 |= (config->gpi6_routing & 0x03) << 12;
148 reg32 |= (config->gpi7_routing & 0x03) << 14;
149 reg32 |= (config->gpi8_routing & 0x03) << 16;
150 reg32 |= (config->gpi9_routing & 0x03) << 18;
151 reg32 |= (config->gpi10_routing & 0x03) << 20;
152 reg32 |= (config->gpi11_routing & 0x03) << 22;
153 reg32 |= (config->gpi12_routing & 0x03) << 24;
154 reg32 |= (config->gpi13_routing & 0x03) << 26;
155 reg32 |= (config->gpi14_routing & 0x03) << 28;
156 reg32 |= (config->gpi15_routing & 0x03) << 30;
157
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200158 pci_write_config32(dev, GPIO_ROUT, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200159}
160
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200161static void pch_power_options(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200162{
163 u8 reg8;
164 u16 reg16, pmbase;
165 u32 reg32;
166 const char *state;
167 /* Get the chip configuration */
168 config_t *config = dev->chip_info;
169
Nico Huber9faae2b2018-11-14 00:00:35 +0100170 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200171 int nmi_option;
172
173 /* Which state do we want to goto after g3 (power restored)?
174 * 0 == S0 Full On
175 * 1 == S5 Soft Off
176 *
177 * If the option is not existent (Laptops), use Kconfig setting.
178 */
179 get_option(&pwr_on, "power_on_after_fail");
180
181 reg16 = pci_read_config16(dev, GEN_PMCON_3);
182 reg16 &= 0xfffe;
183 switch (pwr_on) {
184 case MAINBOARD_POWER_OFF:
185 reg16 |= 1;
186 state = "off";
187 break;
188 case MAINBOARD_POWER_ON:
189 reg16 &= ~1;
190 state = "on";
191 break;
192 case MAINBOARD_POWER_KEEP:
193 reg16 &= ~1;
194 state = "state keep";
195 break;
196 default:
197 state = "undefined";
198 }
199
200 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
201 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
202
203 reg16 &= ~(1 << 10);
204 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
205
206 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
207
208 pci_write_config16(dev, GEN_PMCON_3, reg16);
209 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
210
211 /* Set up NMI on errors. */
212 reg8 = inb(0x61);
213 reg8 &= 0x0f; /* Higher Nibble must be 0 */
214 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
215 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
216 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
217 outb(reg8, 0x61);
218
219 reg8 = inb(0x70);
220 nmi_option = NMI_OFF;
221 get_option(&nmi_option, "nmi");
222 if (nmi_option) {
223 printk(BIOS_INFO, "NMI sources enabled.\n");
224 reg8 &= ~(1 << 7); /* Set NMI. */
225 } else {
226 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200227 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200228 }
229 outb(reg8, 0x70);
230
231 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
232 reg16 = pci_read_config16(dev, GEN_PMCON_1);
233 reg16 &= ~(3 << 0); // SMI# rate 1 minute
234 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
235#if DEBUG_PERIODIC_SMIS
236 /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
237 * periodic SMIs.
238 */
239 reg16 |= (3 << 0); // Periodic SMI every 8s
240#endif
241 pci_write_config16(dev, GEN_PMCON_1, reg16);
242
243 // Set the board's GPI routing.
244 pch_gpi_routing(dev);
245
246 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
247
248 outl(config->gpe0_en, pmbase + GPE0_EN);
249 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
250
251 /* Set up power management block and determine sleep mode */
252 reg32 = inl(pmbase + 0x04); // PM1_CNT
253 reg32 &= ~(7 << 10); // SLP_TYP
254 reg32 |= (1 << 0); // SCI_EN
255 outl(reg32, pmbase + 0x04);
256
257 /* Clear magic status bits to prevent unexpected wake */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200258 reg32 = RCBA32(PRSTS);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200259 reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200260 RCBA32(PRSTS) = reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200261
262 reg32 = RCBA32(0x3f02);
263 reg32 &= ~0xf;
264 RCBA32(0x3f02) = reg32;
265}
266
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700267/* CougarPoint PCH Power Management init */
268static void cpt_pm_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200269{
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700270 printk(BIOS_DEBUG, "CougarPoint PM init\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200271 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200272 RCBA32_AND_OR(CIR30, ~0UL, (1 << 6)|(1 << 0));
273 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
274 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
275 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
276 RCBA32(DMC) = 0xc0388400;
277 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
278 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
279 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
280 RCBA32(PM_CFG) = 0x050f0000;
281 RCBA32(CIR8) = 0x04000000;
282 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
283 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1));
284 RCBA32(CIR12) = 0x0001c000;
285 RCBA32(CIR14) = 0x00061100;
286 RCBA32(CIR15) = 0x7f8fdfff;
287 RCBA32(CIR13) = 0x000003fc;
288 RCBA32(CIR16) = 0x00001000;
289 RCBA32(CIR18) = 0x0001c000;
290 RCBA32(CIR17) = 0x00000800;
291 RCBA32(CIR23) = 0x00001000;
292 RCBA32(CIR19) = 0x00093900;
293 RCBA32(CIR20) = 0x24653002;
294 RCBA32(CIR21) = 0x062108fe;
295 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
296 RCBA32(CIR24) = 0x01010000;
297 RCBA32(CIR25) = 0x01010404;
298 RCBA32(CIR27) = 0x01041041;
299 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
300 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
301 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
302 RCBA32(CIR26) = 0x00000001;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200303 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
304 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200305 RCBA32(PMSYNC_CFG) = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200306 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
307}
308
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700309/* PantherPoint PCH Power Management init */
310static void ppt_pm_init(struct device *dev)
311{
312 printk(BIOS_DEBUG, "PantherPoint PM init\n");
313 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200314 RCBA32_AND_OR(CIR30, ~0UL, (1 << 0));
315 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
316 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
317 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
318 RCBA32(DMC) = 0xc03b8400;
319 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
320 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
321 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
322 RCBA32(PM_CFG) = 0x054f0000;
323 RCBA32(CIR8) = 0x04000000;
324 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
325 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1)|(1 << 0));
326 RCBA32(CIR12) = 0x0001c000;
327 RCBA32(CIR14) = 0x00061100;
328 RCBA32(CIR15) = 0x7f8fdfff;
329 RCBA32(CIR13) = 0x000003fd;
330 RCBA32(CIR16) = 0x00001000;
331 RCBA32(CIR18) = 0x0001c000;
332 RCBA32(CIR17) = 0x00000800;
333 RCBA32(CIR23) = 0x00001000;
334 RCBA32(CIR19) = 0x00093900;
335 RCBA32(CIR20) = 0x24653002;
336 RCBA32(CIR21) = 0x067388fe;
337 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
338 RCBA32(CIR24) = 0x01010000;
339 RCBA32(CIR25) = 0x01010404;
340 RCBA32(CIR27) = 0x01040000;
341 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
342 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
343 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
344 RCBA32(CIR26) = 0x00000001;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700345 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
346 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
347 RCBA32_AND_OR(0x33a4, ~0UL, (1 << 0));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200348 RCBA32(PMSYNC_CFG) = 0;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700349 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
350}
351
Nico Huberb2dae792015-10-26 12:34:02 +0100352static void enable_hpet(struct device *const dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200353{
354 u32 reg32;
Nico Huberb2dae792015-10-26 12:34:02 +0100355 size_t i;
356
357 /* Assign unique bus/dev/fn for each HPET */
358 for (i = 0; i < 8; ++i)
359 pci_write_config16(dev, LPC_HnBDF(i),
360 PCH_HPET_PCI_BUS << 8 | PCH_HPET_PCI_SLOT << 3 | i);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200361
362 /* Move HPET to default address 0xfed00000 and enable it */
363 reg32 = RCBA32(HPTC);
364 reg32 |= (1 << 7); // HPET Address Enable
365 reg32 &= ~(3 << 0);
366 RCBA32(HPTC) = reg32;
367}
368
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200369static void enable_clock_gating(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200370{
371 u32 reg32;
372 u16 reg16;
373
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200374 RCBA32_AND_OR(DMIC, ~0UL, 0xf);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200375
376 reg16 = pci_read_config16(dev, GEN_PMCON_1);
Michał Żygowski9ff2af22020-04-13 20:37:36 +0200377 reg16 &= ~(3 << 2); /* Clear CLKRUN bits for mobile and desktop */
378 if (get_platform_type() == PLATFORM_MOBILE)
379 reg16 |= (1 << 2); /* CLKRUN_EN for mobile */
380 else if (get_platform_type() == PLATFORM_DESKTOP_SERVER)
381 reg16 |= (1 << 3); /* PSEUDO_CLKRUN_EN for desktop */
382 reg16 |= (1 << 11);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200383 pci_write_config16(dev, GEN_PMCON_1, reg16);
384
385 pch_iobp_update(0xEB007F07, ~0UL, (1 << 31));
386 pch_iobp_update(0xEB004000, ~0UL, (1 << 7));
387 pch_iobp_update(0xEC007F07, ~0UL, (1 << 31));
388 pch_iobp_update(0xEC004000, ~0UL, (1 << 7));
389
390 reg32 = RCBA32(CG);
391 reg32 |= (1 << 31);
392 reg32 |= (1 << 29) | (1 << 28);
393 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
394 reg32 |= (1 << 16);
395 reg32 |= (1 << 17);
396 reg32 |= (1 << 18);
397 reg32 |= (1 << 22);
398 reg32 |= (1 << 23);
399 reg32 &= ~(1 << 20);
400 reg32 |= (1 << 19);
401 reg32 |= (1 << 0);
402 reg32 |= (0xf << 1);
403 RCBA32(CG) = reg32;
404
405 RCBA32_OR(0x38c0, 0x7);
406 RCBA32_OR(0x36d4, 0x6680c004);
407 RCBA32_OR(0x3564, 0x3);
408}
409
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200410static void pch_set_acpi_mode(void)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200411{
Julius Werner5d1f9a02019-03-07 17:07:26 -0800412 if (!acpi_is_wakeup_s3() && CONFIG(HAVE_SMI_HANDLER)) {
Duncan Laurie95be1d62012-04-09 12:31:43 -0700413 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200414 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
Duncan Laurie95be1d62012-04-09 12:31:43 -0700415 printk(BIOS_DEBUG, "done.\n");
Duncan Laurie95be1d62012-04-09 12:31:43 -0700416 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200417}
Stefan Reinauer8e073822012-04-04 00:07:22 +0200418
419static void pch_disable_smm_only_flashing(struct device *dev)
420{
421 u8 reg8;
422
423 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100424 reg8 = pci_read_config8(dev, BIOS_CNTL);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200425 reg8 &= ~(1 << 5);
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100426 pci_write_config8(dev, BIOS_CNTL, reg8);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200427}
428
429static void pch_fixups(struct device *dev)
430{
431 u8 gen_pmcon_2;
432
433 /* Indicate DRAM init done for MRC S3 to know it can resume */
434 gen_pmcon_2 = pci_read_config8(dev, GEN_PMCON_2);
435 gen_pmcon_2 |= (1 << 7);
436 pci_write_config8(dev, GEN_PMCON_2, gen_pmcon_2);
437
438 /*
439 * Enable DMI ASPM in the PCH
440 */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200441 RCBA32_AND_OR(DMC, ~(1 << 10), 0);
442 RCBA32_OR(LCAP, (1 << 11)|(1 << 10));
443 RCBA32_OR(LCTL, 0x3);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200444}
445
Nico Huber7b2f9f62015-10-01 19:00:51 +0200446static void pch_spi_init(const struct device *const dev)
447{
448 const config_t *const config = dev->chip_info;
449
450 printk(BIOS_DEBUG, "pch_spi_init\n");
451
452 if (config->spi_uvscc)
453 RCBA32(0x3800 + 0xc8) = config->spi_uvscc;
454 if (config->spi_lvscc)
455 RCBA32(0x3800 + 0xc4) = config->spi_lvscc;
456
457 if (config->spi_uvscc || config->spi_lvscc)
458 RCBA32_OR(0x3800 + 0xc4, 1 << 23); /* lock both UVSCC + LVSCC */
459}
460
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200461static const struct {
462 u16 dev_id;
463 const char *dev_name;
464} pch_table[] = {
465 /* 6-series PCI ids from
466 * Intel® 6 Series Chipset and
467 * Intel® C200 Series Chipset
468 * Specification Update - NDA
469 * October 2013
470 * CDI / IBP#: 440377
471 */
472 {0x1C41, "SFF Sample"},
473 {0x1C42, "Desktop Sample"},
474 {0x1C43, "Mobile Sample"},
475 {0x1C44, "Z68"},
476 {0x1C46, "P67"},
477 {0x1C47, "UM67"},
478 {0x1C49, "HM65"},
479 {0x1C4A, "H67"},
480 {0x1C4B, "HM67"},
481 {0x1C4C, "Q65"},
482 {0x1C4D, "QS67"},
483 {0x1C4E, "Q67"},
484 {0x1C4F, "QM67"},
485 {0x1C50, "B65"},
486 {0x1C52, "C202"},
487 {0x1C54, "C204"},
488 {0x1C56, "C206"},
489 {0x1C5C, "H61"},
490 /* 7-series PCI ids from Intel document 472178 */
491 {0x1E41, "Desktop Sample"},
492 {0x1E42, "Mobile Sample"},
493 {0x1E43, "SFF Sample"},
494 {0x1E44, "Z77"},
495 {0x1E45, "H71"},
496 {0x1E46, "Z75"},
497 {0x1E47, "Q77"},
498 {0x1E48, "Q75"},
499 {0x1E49, "B75"},
500 {0x1E4A, "H77"},
501 {0x1E53, "C216"},
502 {0x1E55, "QM77"},
503 {0x1E56, "QS77"},
504 {0x1E58, "UM77"},
505 {0x1E57, "HM77"},
506 {0x1E59, "HM76"},
507 {0x1E5D, "HM75"},
508 {0x1E5E, "HM70"},
509 {0x1E5F, "NM70"},
510};
511
512static void report_pch_info(struct device *dev)
513{
514 const u16 dev_id = pci_read_config16(dev, PCI_DEVICE_ID);
515 int i;
516
517 const char *pch_type = "Unknown";
518 for (i = 0; i < ARRAY_SIZE(pch_table); i++) {
519 if (pch_table[i].dev_id == dev_id) {
520 pch_type = pch_table[i].dev_name;
521 break;
522 }
523 }
524 printk(BIOS_INFO, "PCH: detected %s, device id: 0x%x, rev id 0x%x\n",
525 pch_type, dev_id, pci_read_config8(dev, PCI_CLASS_REVISION));
526}
527
Stefan Reinauer8e073822012-04-04 00:07:22 +0200528static void lpc_init(struct device *dev)
529{
530 printk(BIOS_DEBUG, "pch: lpc_init\n");
531
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200532 /* Print detected platform */
533 report_pch_info(dev);
534
Stefan Reinauer8e073822012-04-04 00:07:22 +0200535 /* Set the value for PCI command register. */
536 pci_write_config16(dev, PCI_COMMAND, 0x000f);
537
538 /* IO APIC initialization. */
Paul Menzel9c50e6a2013-05-03 12:23:39 +0200539 pch_enable_ioapic(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200540
541 pch_enable_serial_irqs(dev);
542
543 /* Setup the PIRQ. */
544 pch_pirq_init(dev);
545
546 /* Setup power options. */
547 pch_power_options(dev);
548
549 /* Initialize power management */
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700550 switch (pch_silicon_type()) {
551 case PCH_TYPE_CPT: /* CougarPoint */
552 cpt_pm_init(dev);
553 break;
554 case PCH_TYPE_PPT: /* PantherPoint */
555 ppt_pm_init(dev);
556 break;
557 default:
558 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
559 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200560
561 /* Set the state of the GPIO lines. */
562 //gpio_init(dev);
563
564 /* Initialize the real time clock. */
Patrick Rudolph6b931122018-11-01 17:48:37 +0100565 sb_rtc_init();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200566
567 /* Initialize ISA DMA. */
568 isa_dma_init();
569
570 /* Initialize the High Precision Event Timers, if present. */
Nico Huberb2dae792015-10-26 12:34:02 +0100571 enable_hpet(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200572
573 /* Initialize Clock Gating */
574 enable_clock_gating(dev);
575
576 setup_i8259();
577
578 /* The OS should do this? */
579 /* Interrupt 9 should be level triggered (SCI) */
580 i8259_configure_irq_trigger(9, 1);
581
582 pch_disable_smm_only_flashing(dev);
583
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200584 pch_set_acpi_mode();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200585
586 pch_fixups(dev);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200587
588 pch_spi_init(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200589}
590
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200591static void pch_lpc_read_resources(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200592{
593 struct resource *res;
Marc Jonesa0bec172012-07-13 14:14:34 -0600594 config_t *config = dev->chip_info;
595 u8 io_index = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200596
597 /* Get the normal PCI resources of this device. */
598 pci_dev_read_resources(dev);
599
600 /* Add an extra subtractive resource for both memory and I/O. */
Marc Jonesa0bec172012-07-13 14:14:34 -0600601 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200602 res->base = 0;
603 res->size = 0x1000;
604 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
605 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
606
Marc Jonesa0bec172012-07-13 14:14:34 -0600607 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Vladimir Serbinenko0650cd02014-02-05 15:03:50 +0100608 res->base = 0xff000000;
609 /* Some systems (e.g. X230) have 12 MiB flash.
610 SPI controller supports up to 2 x 16 MiB of flash but
611 address map limits this to 16MiB. */
612 res->size = 0x01000000; /* 16 MB for flash */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200613 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
614 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
615
616 res = new_resource(dev, 3); /* IOAPIC */
617 res->base = IO_APIC_ADDR;
618 res->size = 0x00001000;
619 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Marc Jonesa0bec172012-07-13 14:14:34 -0600620
621 /* Set PCH IO decode ranges if required.*/
622 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
623 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
624 res->base = config->gen1_dec & 0xFFFC;
625 res->size = (config->gen1_dec >> 16) & 0xFC;
626 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
627 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
628 }
629
630 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
631 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
632 res->base = config->gen2_dec & 0xFFFC;
633 res->size = (config->gen2_dec >> 16) & 0xFC;
634 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
635 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
636 }
637
638 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
639 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
640 res->base = config->gen3_dec & 0xFFFC;
641 res->size = (config->gen3_dec >> 16) & 0xFC;
642 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
643 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
644 }
645
646 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
647 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
648 res->base = config->gen4_dec & 0xFFFC;
649 res->size = (config->gen4_dec >> 16) & 0xFC;
650 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
651 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
652 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200653}
654
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200655static void pch_lpc_enable(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200656{
657 /* Enable PCH Display Port */
658 RCBA16(DISPBDF) = 0x0010;
659 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
660
661 pch_enable(dev);
662}
663
Furquan Shaikh338fd9a2020-04-24 22:57:05 -0700664static void southbridge_inject_dsdt(const struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200665{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200666 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200667
668 if (gnvs) {
Elyes HAOUAS035df002016-10-03 21:54:16 +0200669 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200670
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200671 acpi_create_gnvs(gnvs);
Vladimir Serbinenko06c788d2014-10-12 00:17:11 +0200672
673 gnvs->apic = 1;
674 gnvs->mpen = 1; /* Enable Multi Processing */
675 gnvs->pcnt = dev_count_cpu();
676
Julius Wernercd49cce2019-03-05 16:53:33 -0800677#if CONFIG(CHROMEOS)
Joel Kitching6fbd8742018-08-23 14:56:25 +0800678 chromeos_init_chromeos_acpi(&(gnvs->chromeos));
Vladimir Serbinenko06c788d2014-10-12 00:17:11 +0200679#endif
680
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200681 /* And tell SMI about it */
682 smm_setup_structures(gnvs, NULL, NULL);
683
Vladimir Serbinenko334fd8e2014-10-05 11:10:35 +0200684 /* Add it to DSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100685 acpigen_write_scope("\\");
686 acpigen_write_name_dword("NVSA", (u32) gnvs);
687 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200688 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200689}
690
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200691void acpi_fill_fadt(acpi_fadt_t *fadt)
692{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300693 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200694 config_t *chip = dev->chip_info;
695 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
696 int c2_latency;
697
Elyes HAOUAS0d4de2a2019-02-28 13:04:29 +0100698 fadt->reserved = 0;
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200699
700 fadt->sci_int = 0x9;
701 fadt->smi_cmd = APM_CNT;
702 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
703 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
704 fadt->s4bios_req = 0x0;
705 fadt->pstate_cnt = 0;
706
707 fadt->pm1a_evt_blk = pmbase;
708 fadt->pm1b_evt_blk = 0x0;
709 fadt->pm1a_cnt_blk = pmbase + 0x4;
710 fadt->pm1b_cnt_blk = 0x0;
711 fadt->pm2_cnt_blk = pmbase + 0x50;
712 fadt->pm_tmr_blk = pmbase + 0x8;
713 fadt->gpe0_blk = pmbase + 0x20;
714 fadt->gpe1_blk = 0;
715
716 fadt->pm1_evt_len = 4;
717 fadt->pm1_cnt_len = 2;
718 fadt->pm2_cnt_len = 1;
719 fadt->pm_tmr_len = 4;
720 fadt->gpe0_blk_len = 16;
721 fadt->gpe1_blk_len = 0;
722 fadt->gpe1_base = 0;
723 fadt->cst_cnt = 0;
724 c2_latency = chip->c2_latency;
725 if (!c2_latency) {
726 c2_latency = 101; /* c2 unsupported */
727 }
728 fadt->p_lvl2_lat = c2_latency;
729 fadt->p_lvl3_lat = 87;
730 fadt->flush_size = 1024;
731 fadt->flush_stride = 16;
Patrick Rudolphb30a47b2019-07-15 18:04:23 +0200732 /* P_CNT not supported */
733 fadt->duty_offset = 0;
734 fadt->duty_width = 0;
735
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200736 fadt->day_alrm = 0xd;
737 fadt->mon_alrm = 0x00;
738 fadt->century = 0x00;
739 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
740
741 fadt->flags = ACPI_FADT_WBINVD |
742 ACPI_FADT_C1_SUPPORTED |
743 ACPI_FADT_SLEEP_BUTTON |
744 ACPI_FADT_RESET_REGISTER |
745 ACPI_FADT_SEALED_CASE |
746 ACPI_FADT_S4_RTC_WAKE |
747 ACPI_FADT_PLATFORM_CLOCK;
748 if (chip->docking_supported) {
749 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
750 }
751 if (c2_latency < 100) {
752 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
753 }
754
755 fadt->reset_reg.space_id = 1;
756 fadt->reset_reg.bit_width = 8;
757 fadt->reset_reg.bit_offset = 0;
758 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
759 fadt->reset_reg.addrl = 0xcf9;
760 fadt->reset_reg.addrh = 0;
761
762 fadt->reset_value = 6;
763
764 fadt->x_pm1a_evt_blk.space_id = 1;
765 fadt->x_pm1a_evt_blk.bit_width = 32;
766 fadt->x_pm1a_evt_blk.bit_offset = 0;
767 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
768 fadt->x_pm1a_evt_blk.addrl = pmbase;
769 fadt->x_pm1a_evt_blk.addrh = 0x0;
770
771 fadt->x_pm1b_evt_blk.space_id = 1;
772 fadt->x_pm1b_evt_blk.bit_width = 0;
773 fadt->x_pm1b_evt_blk.bit_offset = 0;
774 fadt->x_pm1b_evt_blk.access_size = 0;
775 fadt->x_pm1b_evt_blk.addrl = 0x0;
776 fadt->x_pm1b_evt_blk.addrh = 0x0;
777
778 fadt->x_pm1a_cnt_blk.space_id = 1;
779 fadt->x_pm1a_cnt_blk.bit_width = 16;
780 fadt->x_pm1a_cnt_blk.bit_offset = 0;
781 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
782 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
783 fadt->x_pm1a_cnt_blk.addrh = 0x0;
784
785 fadt->x_pm1b_cnt_blk.space_id = 1;
786 fadt->x_pm1b_cnt_blk.bit_width = 0;
787 fadt->x_pm1b_cnt_blk.bit_offset = 0;
788 fadt->x_pm1b_cnt_blk.access_size = 0;
789 fadt->x_pm1b_cnt_blk.addrl = 0x0;
790 fadt->x_pm1b_cnt_blk.addrh = 0x0;
791
792 fadt->x_pm2_cnt_blk.space_id = 1;
793 fadt->x_pm2_cnt_blk.bit_width = 8;
794 fadt->x_pm2_cnt_blk.bit_offset = 0;
795 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
796 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
797 fadt->x_pm2_cnt_blk.addrh = 0x0;
798
799 fadt->x_pm_tmr_blk.space_id = 1;
800 fadt->x_pm_tmr_blk.bit_width = 32;
801 fadt->x_pm_tmr_blk.bit_offset = 0;
802 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
803 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
804 fadt->x_pm_tmr_blk.addrh = 0x0;
805
806 fadt->x_gpe0_blk.space_id = 1;
807 fadt->x_gpe0_blk.bit_width = 128;
808 fadt->x_gpe0_blk.bit_offset = 0;
809 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
810 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
811 fadt->x_gpe0_blk.addrh = 0x0;
812
813 fadt->x_gpe1_blk.space_id = 1;
814 fadt->x_gpe1_blk.bit_width = 0;
815 fadt->x_gpe1_blk.bit_offset = 0;
816 fadt->x_gpe1_blk.access_size = 0;
817 fadt->x_gpe1_blk.addrl = 0x0;
818 fadt->x_gpe1_blk.addrh = 0x0;
819}
820
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600821static const char *lpc_acpi_name(const struct device *dev)
Patrick Rudolph604f6982017-06-07 09:46:52 +0200822{
823 return "LPCB";
824}
825
Furquan Shaikh7536a392020-04-24 21:59:21 -0700826static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100827{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300828 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100829 config_t *chip = dev->chip_info;
830
831 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Tobias Diedrich7f5efd92017-12-14 00:29:01 +0100832 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100833}
834
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200835static void lpc_final(struct device *dev)
836{
Arthur Heymansebf201b2019-05-28 13:51:36 +0200837 spi_finalize_ops();
Nico Huber8e50b6d2018-02-04 15:52:18 +0100838
Bill XIEd533b162017-08-22 16:26:22 +0800839 /* Call SMM finalize() handlers before resume */
Julius Wernercd49cce2019-03-05 16:53:33 -0800840 if (CONFIG(HAVE_SMI_HANDLER)) {
841 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
Bill XIEd533b162017-08-22 16:26:22 +0800842 acpi_is_wakeup_s3()) {
843 outb(APM_CNT_FINALIZE, APM_CNT);
844 }
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200845 }
846}
847
Arthur Heymansebf201b2019-05-28 13:51:36 +0200848void intel_southbridge_override_spi(
849 struct intel_swseq_spi_config *spi_config)
850{
851 struct device *dev = pcidev_on_root(0x1f, 0);
852
853 if (!dev)
854 return;
855 /* Devicetree may override defaults. */
856 const config_t *const config = dev->chip_info;
857
858 if (!config)
859 return;
860
861 if (config->spi.ops[0].op != 0)
862 memcpy(spi_config, &config->spi, sizeof(*spi_config));
863}
864
Stefan Reinauer8e073822012-04-04 00:07:22 +0200865static struct pci_operations pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530866 .set_subsystem = pci_dev_set_subsystem,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200867};
868
869static struct device_operations device_ops = {
870 .read_resources = pch_lpc_read_resources,
871 .set_resources = pci_dev_set_resources,
Arthur Heymans3cde4942019-08-18 10:02:10 +0200872 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200873 .write_acpi_tables = acpi_write_hpet,
Nico Huber68680dd2020-03-31 17:34:52 +0200874 .acpi_inject_dsdt = southbridge_inject_dsdt,
875 .acpi_fill_ssdt = southbridge_fill_ssdt,
Patrick Rudolph604f6982017-06-07 09:46:52 +0200876 .acpi_name = lpc_acpi_name,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200877 .init = lpc_init,
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200878 .final = lpc_final,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200879 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100880 .scan_bus = scan_static_bus,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200881 .ops_pci = &pci_ops,
882};
883
884
Kimarie Hoote6f459c2012-07-14 08:26:08 -0600885/* IDs for LPC device of Intel 6 Series Chipset, Intel 7 Series Chipset, and
886 * Intel C200 Series Chipset
Stefan Reinauer8e073822012-04-04 00:07:22 +0200887 */
888
Vladimir Serbinenko42d55e02016-01-02 01:47:26 +0100889static const unsigned short pci_device_ids[] = {
890 0x1c40, 0x1c41, 0x1c42, 0x1c43, 0x1c44, 0x1c45, 0x1c46, 0x1c47, 0x1c48,
891 0x1c49, 0x1c4a, 0x1c4b, 0x1c4c, 0x1c4d, 0x1c4e, 0x1c4f, 0x1c50, 0x1c51,
892 0x1c52, 0x1c53, 0x1c54, 0x1c55, 0x1c56, 0x1c57, 0x1c58, 0x1c59, 0x1c5a,
893 0x1c5b, 0x1c5c, 0x1c5d, 0x1c5e, 0x1c5f,
894
895 0x1e41, 0x1e42, 0x1e43, 0x1e44, 0x1e45, 0x1e46, 0x1e47, 0x1e48, 0x1e49,
896 0x1e4a, 0x1e4b, 0x1e4c, 0x1e4d, 0x1e4e, 0x1e4f, 0x1e50, 0x1e51, 0x1e52,
897 0x1e53, 0x1e54, 0x1e55, 0x1e56, 0x1e57, 0x1e58, 0x1e59, 0x1e5a, 0x1e5b,
898 0x1e5c, 0x1e5d, 0x1e5e, 0x1e5f,
899
900 0 };
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700901
902static const struct pci_driver pch_lpc __pci_driver = {
903 .ops = &device_ops,
904 .vendor = PCI_VENDOR_ID_INTEL,
905 .devices = pci_device_ids,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200906};