blob: 200463268f70d16c6cdbf095f0cc5ce9227008c2 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer8e073822012-04-04 00:07:22 +02002
3#include <console/console.h>
4#include <device/device.h>
5#include <device/pci.h>
6#include <device/pci_ids.h>
Patrick Rudolphe56189c2018-04-18 10:11:59 +02007#include <device/pci_ops.h>
Patrick Rudolphef8c5592018-07-27 17:48:27 +02008#include <device/pci_def.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +02009#include <option.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020010#include <pc80/isa-dma.h>
11#include <pc80/i8259.h>
12#include <arch/io.h>
13#include <arch/ioapic.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070014#include <acpi/acpi.h>
15#include <acpi/acpigen.h>
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +020016#include <cpu/x86/smm.h>
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020017#include <cbmem.h>
Vladimir Serbinenko7309c642014-10-05 11:07:33 +020018#include <string.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030019#include "chip.h"
Stefan Reinauer8e073822012-04-04 00:07:22 +020020#include "pch.h"
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020021#include "nvs.h"
Michał Żygowski9ff2af22020-04-13 20:37:36 +020022#include <northbridge/intel/sandybridge/sandybridge.h>
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010023#include <southbridge/intel/common/pciehp.h>
Tobias Diedrich7f5efd92017-12-14 00:29:01 +010024#include <southbridge/intel/common/acpi_pirq_gen.h>
Arthur Heymansa0508172018-01-25 11:30:22 +010025#include <southbridge/intel/common/pmutil.h>
Patrick Rudolph6b931122018-11-01 17:48:37 +010026#include <southbridge/intel/common/rtc.h>
Arthur Heymansebf201b2019-05-28 13:51:36 +020027#include <southbridge/intel/common/spi.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020028
29#define NMI_OFF 0
30
Stefan Reinauer8e073822012-04-04 00:07:22 +020031typedef struct southbridge_intel_bd82x6x_config config_t;
32
Paul Menzel9c50e6a2013-05-03 12:23:39 +020033/**
34 * Set miscellanous static southbridge features.
35 *
36 * @param dev PCI device with I/O APIC control registers
37 */
38static void pch_enable_ioapic(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020039{
Stefan Reinauer8e073822012-04-04 00:07:22 +020040 u32 reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +020041
Nico Huberb2dae792015-10-26 12:34:02 +010042 /* Assign unique bus/dev/fn for I/O APIC */
43 pci_write_config16(dev, LPC_IBDF,
44 PCH_IOAPIC_PCI_BUS << 8 | PCH_IOAPIC_PCI_SLOT << 3);
45
Paul Menzel9c50e6a2013-05-03 12:23:39 +020046 /* Enable ACPI I/O range decode */
47 pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
Stefan Reinauer8e073822012-04-04 00:07:22 +020048
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080049 set_ioapic_id(VIO_APIC_VADDR, 0x02);
Stefan Reinauer8e073822012-04-04 00:07:22 +020050
51 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080052 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
53 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +020054
Paul Menzel9c50e6a2013-05-03 12:23:39 +020055 /*
56 * Select Boot Configuration register (0x03) and
57 * use Processor System Bus (0x01) to deliver interrupts.
58 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080059 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Stefan Reinauer8e073822012-04-04 00:07:22 +020060}
61
62static void pch_enable_serial_irqs(struct device *dev)
63{
64 /* Set packet length and toggle silent mode bit for one frame. */
65 pci_write_config8(dev, SERIRQ_CNTL,
66 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080067#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Stefan Reinauer8e073822012-04-04 00:07:22 +020068 pci_write_config8(dev, SERIRQ_CNTL,
69 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
70#endif
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 HAOUAS4aec3402018-05-25 08:29:27 +020094static void pch_pirq_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020095{
Elyes HAOUAS4aec3402018-05-25 08:29:27 +020096 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020097 /* Interrupt 11 is not used by legacy devices and so can always be used for
98 PCI interrupts. Full legacy IRQ routing is complicated and hard to
99 get right. Fortunately all modern OS use MSI and so it's not that big of
100 an issue anyway. Still we have to provide a reasonable default. Using
101 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
102 move it to any interrupt and others will just leave them at default.
Stefan Reinauer8e073822012-04-04 00:07:22 +0200103 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200104 const u8 pirq_routing = 11;
105
106 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
107 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
108 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
109 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
110
111 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
112 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
113 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
114 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200115
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200116 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200117 u8 int_pin=0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200118
119 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
120 continue;
121
122 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
123
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200124 if (int_pin == 0)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200125 continue;
126
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200127 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200128 }
129}
130
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200131static void pch_gpi_routing(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200132{
133 /* Get the chip configuration */
134 config_t *config = dev->chip_info;
135 u32 reg32 = 0;
136
137 /* An array would be much nicer here, or some
138 * other method of doing this.
139 */
140 reg32 |= (config->gpi0_routing & 0x03) << 0;
141 reg32 |= (config->gpi1_routing & 0x03) << 2;
142 reg32 |= (config->gpi2_routing & 0x03) << 4;
143 reg32 |= (config->gpi3_routing & 0x03) << 6;
144 reg32 |= (config->gpi4_routing & 0x03) << 8;
145 reg32 |= (config->gpi5_routing & 0x03) << 10;
146 reg32 |= (config->gpi6_routing & 0x03) << 12;
147 reg32 |= (config->gpi7_routing & 0x03) << 14;
148 reg32 |= (config->gpi8_routing & 0x03) << 16;
149 reg32 |= (config->gpi9_routing & 0x03) << 18;
150 reg32 |= (config->gpi10_routing & 0x03) << 20;
151 reg32 |= (config->gpi11_routing & 0x03) << 22;
152 reg32 |= (config->gpi12_routing & 0x03) << 24;
153 reg32 |= (config->gpi13_routing & 0x03) << 26;
154 reg32 |= (config->gpi14_routing & 0x03) << 28;
155 reg32 |= (config->gpi15_routing & 0x03) << 30;
156
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200157 pci_write_config32(dev, GPIO_ROUT, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200158}
159
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200160static void pch_power_options(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200161{
162 u8 reg8;
163 u16 reg16, pmbase;
164 u32 reg32;
165 const char *state;
166 /* Get the chip configuration */
167 config_t *config = dev->chip_info;
168
Nico Huber9faae2b2018-11-14 00:00:35 +0100169 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200170 int nmi_option;
171
172 /* Which state do we want to goto after g3 (power restored)?
173 * 0 == S0 Full On
174 * 1 == S5 Soft Off
175 *
176 * If the option is not existent (Laptops), use Kconfig setting.
177 */
178 get_option(&pwr_on, "power_on_after_fail");
179
180 reg16 = pci_read_config16(dev, GEN_PMCON_3);
181 reg16 &= 0xfffe;
182 switch (pwr_on) {
183 case MAINBOARD_POWER_OFF:
184 reg16 |= 1;
185 state = "off";
186 break;
187 case MAINBOARD_POWER_ON:
188 reg16 &= ~1;
189 state = "on";
190 break;
191 case MAINBOARD_POWER_KEEP:
192 reg16 &= ~1;
193 state = "state keep";
194 break;
195 default:
196 state = "undefined";
197 }
198
199 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
200 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
201
202 reg16 &= ~(1 << 10);
203 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
204
205 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
206
207 pci_write_config16(dev, GEN_PMCON_3, reg16);
208 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
209
210 /* Set up NMI on errors. */
211 reg8 = inb(0x61);
212 reg8 &= 0x0f; /* Higher Nibble must be 0 */
213 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
214 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
215 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
216 outb(reg8, 0x61);
217
218 reg8 = inb(0x70);
219 nmi_option = NMI_OFF;
220 get_option(&nmi_option, "nmi");
221 if (nmi_option) {
222 printk(BIOS_INFO, "NMI sources enabled.\n");
223 reg8 &= ~(1 << 7); /* Set NMI. */
224 } else {
225 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200226 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200227 }
228 outb(reg8, 0x70);
229
230 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
231 reg16 = pci_read_config16(dev, GEN_PMCON_1);
232 reg16 &= ~(3 << 0); // SMI# rate 1 minute
233 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
Kyösti Mälkki94464472020-06-13 13:45:42 +0300234 if (CONFIG(DEBUG_PERIODIC_SMI))
235 reg16 |= (3 << 0); // Periodic SMI every 8s
Stefan Reinauer8e073822012-04-04 00:07:22 +0200236 pci_write_config16(dev, GEN_PMCON_1, reg16);
237
238 // Set the board's GPI routing.
239 pch_gpi_routing(dev);
240
241 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
242
243 outl(config->gpe0_en, pmbase + GPE0_EN);
244 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
245
246 /* Set up power management block and determine sleep mode */
247 reg32 = inl(pmbase + 0x04); // PM1_CNT
248 reg32 &= ~(7 << 10); // SLP_TYP
249 reg32 |= (1 << 0); // SCI_EN
250 outl(reg32, pmbase + 0x04);
251
252 /* Clear magic status bits to prevent unexpected wake */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200253 reg32 = RCBA32(PRSTS);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200254 reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200255 RCBA32(PRSTS) = reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200256
257 reg32 = RCBA32(0x3f02);
258 reg32 &= ~0xf;
259 RCBA32(0x3f02) = reg32;
260}
261
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700262/* CougarPoint PCH Power Management init */
263static void cpt_pm_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200264{
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700265 printk(BIOS_DEBUG, "CougarPoint PM init\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200266 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200267 RCBA32_AND_OR(CIR30, ~0UL, (1 << 6)|(1 << 0));
268 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
269 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
270 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
271 RCBA32(DMC) = 0xc0388400;
272 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
273 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
274 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
275 RCBA32(PM_CFG) = 0x050f0000;
276 RCBA32(CIR8) = 0x04000000;
277 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
278 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1));
279 RCBA32(CIR12) = 0x0001c000;
280 RCBA32(CIR14) = 0x00061100;
281 RCBA32(CIR15) = 0x7f8fdfff;
282 RCBA32(CIR13) = 0x000003fc;
283 RCBA32(CIR16) = 0x00001000;
284 RCBA32(CIR18) = 0x0001c000;
285 RCBA32(CIR17) = 0x00000800;
286 RCBA32(CIR23) = 0x00001000;
287 RCBA32(CIR19) = 0x00093900;
288 RCBA32(CIR20) = 0x24653002;
289 RCBA32(CIR21) = 0x062108fe;
290 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
291 RCBA32(CIR24) = 0x01010000;
292 RCBA32(CIR25) = 0x01010404;
293 RCBA32(CIR27) = 0x01041041;
294 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
295 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
296 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
297 RCBA32(CIR26) = 0x00000001;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200298 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
299 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200300 RCBA32(PMSYNC_CFG) = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200301 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
302}
303
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700304/* PantherPoint PCH Power Management init */
305static void ppt_pm_init(struct device *dev)
306{
307 printk(BIOS_DEBUG, "PantherPoint PM init\n");
308 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200309 RCBA32_AND_OR(CIR30, ~0UL, (1 << 0));
310 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
311 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
312 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
313 RCBA32(DMC) = 0xc03b8400;
314 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
315 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
316 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
317 RCBA32(PM_CFG) = 0x054f0000;
318 RCBA32(CIR8) = 0x04000000;
319 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
320 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1)|(1 << 0));
321 RCBA32(CIR12) = 0x0001c000;
322 RCBA32(CIR14) = 0x00061100;
323 RCBA32(CIR15) = 0x7f8fdfff;
324 RCBA32(CIR13) = 0x000003fd;
325 RCBA32(CIR16) = 0x00001000;
326 RCBA32(CIR18) = 0x0001c000;
327 RCBA32(CIR17) = 0x00000800;
328 RCBA32(CIR23) = 0x00001000;
329 RCBA32(CIR19) = 0x00093900;
330 RCBA32(CIR20) = 0x24653002;
331 RCBA32(CIR21) = 0x067388fe;
332 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
333 RCBA32(CIR24) = 0x01010000;
334 RCBA32(CIR25) = 0x01010404;
335 RCBA32(CIR27) = 0x01040000;
336 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
337 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
338 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
339 RCBA32(CIR26) = 0x00000001;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700340 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
341 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
342 RCBA32_AND_OR(0x33a4, ~0UL, (1 << 0));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200343 RCBA32(PMSYNC_CFG) = 0;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700344 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
345}
346
Nico Huberb2dae792015-10-26 12:34:02 +0100347static void enable_hpet(struct device *const dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200348{
349 u32 reg32;
Nico Huberb2dae792015-10-26 12:34:02 +0100350 size_t i;
351
352 /* Assign unique bus/dev/fn for each HPET */
353 for (i = 0; i < 8; ++i)
354 pci_write_config16(dev, LPC_HnBDF(i),
355 PCH_HPET_PCI_BUS << 8 | PCH_HPET_PCI_SLOT << 3 | i);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200356
357 /* Move HPET to default address 0xfed00000 and enable it */
358 reg32 = RCBA32(HPTC);
359 reg32 |= (1 << 7); // HPET Address Enable
360 reg32 &= ~(3 << 0);
361 RCBA32(HPTC) = reg32;
362}
363
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200364static void enable_clock_gating(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200365{
366 u32 reg32;
367 u16 reg16;
368
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200369 RCBA32_AND_OR(DMIC, ~0UL, 0xf);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200370
371 reg16 = pci_read_config16(dev, GEN_PMCON_1);
Michał Żygowski9ff2af22020-04-13 20:37:36 +0200372 reg16 &= ~(3 << 2); /* Clear CLKRUN bits for mobile and desktop */
373 if (get_platform_type() == PLATFORM_MOBILE)
374 reg16 |= (1 << 2); /* CLKRUN_EN for mobile */
375 else if (get_platform_type() == PLATFORM_DESKTOP_SERVER)
376 reg16 |= (1 << 3); /* PSEUDO_CLKRUN_EN for desktop */
377 reg16 |= (1 << 11);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200378 pci_write_config16(dev, GEN_PMCON_1, reg16);
379
380 pch_iobp_update(0xEB007F07, ~0UL, (1 << 31));
381 pch_iobp_update(0xEB004000, ~0UL, (1 << 7));
382 pch_iobp_update(0xEC007F07, ~0UL, (1 << 31));
383 pch_iobp_update(0xEC004000, ~0UL, (1 << 7));
384
385 reg32 = RCBA32(CG);
386 reg32 |= (1 << 31);
387 reg32 |= (1 << 29) | (1 << 28);
388 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
389 reg32 |= (1 << 16);
390 reg32 |= (1 << 17);
391 reg32 |= (1 << 18);
392 reg32 |= (1 << 22);
393 reg32 |= (1 << 23);
394 reg32 &= ~(1 << 20);
395 reg32 |= (1 << 19);
396 reg32 |= (1 << 0);
397 reg32 |= (0xf << 1);
398 RCBA32(CG) = reg32;
399
400 RCBA32_OR(0x38c0, 0x7);
401 RCBA32_OR(0x36d4, 0x6680c004);
402 RCBA32_OR(0x3564, 0x3);
403}
404
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200405static void pch_set_acpi_mode(void)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200406{
Julius Werner5d1f9a02019-03-07 17:07:26 -0800407 if (!acpi_is_wakeup_s3() && CONFIG(HAVE_SMI_HANDLER)) {
Kyösti Mälkkib6585482020-06-01 15:11:14 +0300408 apm_control(APM_CNT_ACPI_DISABLE);
Duncan Laurie95be1d62012-04-09 12:31:43 -0700409 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200410}
Stefan Reinauer8e073822012-04-04 00:07:22 +0200411
412static void pch_disable_smm_only_flashing(struct device *dev)
413{
Stefan Reinauer8e073822012-04-04 00:07:22 +0200414 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Angel Ponsc803f652020-06-07 22:09:01 +0200415
416 pci_and_config8(dev, BIOS_CNTL, ~(1 << 5));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200417}
418
419static void pch_fixups(struct device *dev)
420{
Stefan Reinauer8e073822012-04-04 00:07:22 +0200421 /* Indicate DRAM init done for MRC S3 to know it can resume */
Angel Ponsc803f652020-06-07 22:09:01 +0200422 pci_or_config8(dev, GEN_PMCON_2, 1 << 7);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200423
424 /*
425 * Enable DMI ASPM in the PCH
426 */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200427 RCBA32_AND_OR(DMC, ~(1 << 10), 0);
428 RCBA32_OR(LCAP, (1 << 11)|(1 << 10));
429 RCBA32_OR(LCTL, 0x3);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200430}
431
Nico Huber7b2f9f62015-10-01 19:00:51 +0200432static void pch_spi_init(const struct device *const dev)
433{
434 const config_t *const config = dev->chip_info;
435
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100436 printk(BIOS_DEBUG, "%s\n", __func__);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200437
438 if (config->spi_uvscc)
439 RCBA32(0x3800 + 0xc8) = config->spi_uvscc;
440 if (config->spi_lvscc)
441 RCBA32(0x3800 + 0xc4) = config->spi_lvscc;
442
443 if (config->spi_uvscc || config->spi_lvscc)
444 RCBA32_OR(0x3800 + 0xc4, 1 << 23); /* lock both UVSCC + LVSCC */
445}
446
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200447static const struct {
448 u16 dev_id;
449 const char *dev_name;
450} pch_table[] = {
451 /* 6-series PCI ids from
452 * Intel® 6 Series Chipset and
453 * Intel® C200 Series Chipset
454 * Specification Update - NDA
455 * October 2013
456 * CDI / IBP#: 440377
457 */
458 {0x1C41, "SFF Sample"},
459 {0x1C42, "Desktop Sample"},
460 {0x1C43, "Mobile Sample"},
461 {0x1C44, "Z68"},
462 {0x1C46, "P67"},
463 {0x1C47, "UM67"},
464 {0x1C49, "HM65"},
465 {0x1C4A, "H67"},
466 {0x1C4B, "HM67"},
467 {0x1C4C, "Q65"},
468 {0x1C4D, "QS67"},
469 {0x1C4E, "Q67"},
470 {0x1C4F, "QM67"},
471 {0x1C50, "B65"},
472 {0x1C52, "C202"},
473 {0x1C54, "C204"},
474 {0x1C56, "C206"},
475 {0x1C5C, "H61"},
476 /* 7-series PCI ids from Intel document 472178 */
477 {0x1E41, "Desktop Sample"},
478 {0x1E42, "Mobile Sample"},
479 {0x1E43, "SFF Sample"},
480 {0x1E44, "Z77"},
481 {0x1E45, "H71"},
482 {0x1E46, "Z75"},
483 {0x1E47, "Q77"},
484 {0x1E48, "Q75"},
485 {0x1E49, "B75"},
486 {0x1E4A, "H77"},
487 {0x1E53, "C216"},
488 {0x1E55, "QM77"},
489 {0x1E56, "QS77"},
490 {0x1E58, "UM77"},
491 {0x1E57, "HM77"},
492 {0x1E59, "HM76"},
493 {0x1E5D, "HM75"},
494 {0x1E5E, "HM70"},
495 {0x1E5F, "NM70"},
496};
497
498static void report_pch_info(struct device *dev)
499{
500 const u16 dev_id = pci_read_config16(dev, PCI_DEVICE_ID);
501 int i;
502
503 const char *pch_type = "Unknown";
504 for (i = 0; i < ARRAY_SIZE(pch_table); i++) {
505 if (pch_table[i].dev_id == dev_id) {
506 pch_type = pch_table[i].dev_name;
507 break;
508 }
509 }
510 printk(BIOS_INFO, "PCH: detected %s, device id: 0x%x, rev id 0x%x\n",
511 pch_type, dev_id, pci_read_config8(dev, PCI_CLASS_REVISION));
512}
513
Stefan Reinauer8e073822012-04-04 00:07:22 +0200514static void lpc_init(struct device *dev)
515{
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100516 printk(BIOS_DEBUG, "pch: %s\n", __func__);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200517
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200518 /* Print detected platform */
519 report_pch_info(dev);
520
Stefan Reinauer8e073822012-04-04 00:07:22 +0200521 /* Set the value for PCI command register. */
522 pci_write_config16(dev, PCI_COMMAND, 0x000f);
523
524 /* IO APIC initialization. */
Paul Menzel9c50e6a2013-05-03 12:23:39 +0200525 pch_enable_ioapic(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200526
527 pch_enable_serial_irqs(dev);
528
529 /* Setup the PIRQ. */
530 pch_pirq_init(dev);
531
532 /* Setup power options. */
533 pch_power_options(dev);
534
535 /* Initialize power management */
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700536 switch (pch_silicon_type()) {
537 case PCH_TYPE_CPT: /* CougarPoint */
538 cpt_pm_init(dev);
539 break;
540 case PCH_TYPE_PPT: /* PantherPoint */
541 ppt_pm_init(dev);
542 break;
543 default:
544 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
545 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200546
547 /* Set the state of the GPIO lines. */
548 //gpio_init(dev);
549
550 /* Initialize the real time clock. */
Patrick Rudolph6b931122018-11-01 17:48:37 +0100551 sb_rtc_init();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200552
553 /* Initialize ISA DMA. */
554 isa_dma_init();
555
556 /* Initialize the High Precision Event Timers, if present. */
Nico Huberb2dae792015-10-26 12:34:02 +0100557 enable_hpet(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200558
559 /* Initialize Clock Gating */
560 enable_clock_gating(dev);
561
562 setup_i8259();
563
564 /* The OS should do this? */
565 /* Interrupt 9 should be level triggered (SCI) */
566 i8259_configure_irq_trigger(9, 1);
567
568 pch_disable_smm_only_flashing(dev);
569
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200570 pch_set_acpi_mode();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200571
572 pch_fixups(dev);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200573
574 pch_spi_init(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200575}
576
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200577static void pch_lpc_read_resources(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200578{
579 struct resource *res;
Marc Jonesa0bec172012-07-13 14:14:34 -0600580 config_t *config = dev->chip_info;
581 u8 io_index = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200582
583 /* Get the normal PCI resources of this device. */
584 pci_dev_read_resources(dev);
585
586 /* Add an extra subtractive resource for both memory and I/O. */
Marc Jonesa0bec172012-07-13 14:14:34 -0600587 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200588 res->base = 0;
589 res->size = 0x1000;
590 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
591 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
592
Marc Jonesa0bec172012-07-13 14:14:34 -0600593 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Vladimir Serbinenko0650cd02014-02-05 15:03:50 +0100594 res->base = 0xff000000;
595 /* Some systems (e.g. X230) have 12 MiB flash.
596 SPI controller supports up to 2 x 16 MiB of flash but
597 address map limits this to 16MiB. */
598 res->size = 0x01000000; /* 16 MB for flash */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200599 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
600 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
601
602 res = new_resource(dev, 3); /* IOAPIC */
603 res->base = IO_APIC_ADDR;
604 res->size = 0x00001000;
605 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Marc Jonesa0bec172012-07-13 14:14:34 -0600606
607 /* Set PCH IO decode ranges if required.*/
608 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
609 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
610 res->base = config->gen1_dec & 0xFFFC;
611 res->size = (config->gen1_dec >> 16) & 0xFC;
612 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
613 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
614 }
615
616 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
617 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
618 res->base = config->gen2_dec & 0xFFFC;
619 res->size = (config->gen2_dec >> 16) & 0xFC;
620 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
621 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
622 }
623
624 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
625 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
626 res->base = config->gen3_dec & 0xFFFC;
627 res->size = (config->gen3_dec >> 16) & 0xFC;
628 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
629 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
630 }
631
632 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
633 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
634 res->base = config->gen4_dec & 0xFFFC;
635 res->size = (config->gen4_dec >> 16) & 0xFC;
636 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
637 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
638 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200639}
640
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200641static void pch_lpc_enable(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200642{
643 /* Enable PCH Display Port */
644 RCBA16(DISPBDF) = 0x0010;
645 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
646
647 pch_enable(dev);
648}
649
Furquan Shaikh338fd9a2020-04-24 22:57:05 -0700650static void southbridge_inject_dsdt(const struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200651{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200652 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200653
654 if (gnvs) {
Elyes HAOUAS035df002016-10-03 21:54:16 +0200655 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200656
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200657 acpi_create_gnvs(gnvs);
Vladimir Serbinenko06c788d2014-10-12 00:17:11 +0200658
659 gnvs->apic = 1;
660 gnvs->mpen = 1; /* Enable Multi Processing */
661 gnvs->pcnt = dev_count_cpu();
662
Julius Wernercd49cce2019-03-05 16:53:33 -0800663#if CONFIG(CHROMEOS)
Joel Kitching6fbd8742018-08-23 14:56:25 +0800664 chromeos_init_chromeos_acpi(&(gnvs->chromeos));
Vladimir Serbinenko06c788d2014-10-12 00:17:11 +0200665#endif
666
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200667 /* And tell SMI about it */
668 smm_setup_structures(gnvs, NULL, NULL);
669
Vladimir Serbinenko334fd8e2014-10-05 11:10:35 +0200670 /* Add it to DSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100671 acpigen_write_scope("\\");
672 acpigen_write_name_dword("NVSA", (u32) gnvs);
673 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200674 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200675}
676
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200677void acpi_fill_fadt(acpi_fadt_t *fadt)
678{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300679 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200680 config_t *chip = dev->chip_info;
681 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
682 int c2_latency;
683
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200684
685 fadt->sci_int = 0x9;
Kyösti Mälkkic328a682019-11-23 07:23:40 +0200686
Kyösti Mälkki0a9e72e2019-08-11 01:22:28 +0300687 if (permanent_smi_handler()) {
Kyösti Mälkkic328a682019-11-23 07:23:40 +0200688 fadt->smi_cmd = APM_CNT;
689 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
690 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
691 }
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200692
693 fadt->pm1a_evt_blk = pmbase;
694 fadt->pm1b_evt_blk = 0x0;
695 fadt->pm1a_cnt_blk = pmbase + 0x4;
696 fadt->pm1b_cnt_blk = 0x0;
697 fadt->pm2_cnt_blk = pmbase + 0x50;
698 fadt->pm_tmr_blk = pmbase + 0x8;
699 fadt->gpe0_blk = pmbase + 0x20;
700 fadt->gpe1_blk = 0;
701
702 fadt->pm1_evt_len = 4;
703 fadt->pm1_cnt_len = 2;
704 fadt->pm2_cnt_len = 1;
705 fadt->pm_tmr_len = 4;
706 fadt->gpe0_blk_len = 16;
707 fadt->gpe1_blk_len = 0;
708 fadt->gpe1_base = 0;
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200709 c2_latency = chip->c2_latency;
710 if (!c2_latency) {
711 c2_latency = 101; /* c2 unsupported */
712 }
713 fadt->p_lvl2_lat = c2_latency;
714 fadt->p_lvl3_lat = 87;
Patrick Rudolph78e8db12019-07-19 16:31:37 +0200715 /* flush_* is ignored if ACPI_FADT_WBINVD is set */
716 fadt->flush_size = 0;
717 fadt->flush_stride = 0;
Patrick Rudolphb30a47b2019-07-15 18:04:23 +0200718 /* P_CNT not supported */
719 fadt->duty_offset = 0;
720 fadt->duty_width = 0;
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200721 fadt->day_alrm = 0xd;
722 fadt->mon_alrm = 0x00;
723 fadt->century = 0x00;
724 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
725
726 fadt->flags = ACPI_FADT_WBINVD |
727 ACPI_FADT_C1_SUPPORTED |
728 ACPI_FADT_SLEEP_BUTTON |
729 ACPI_FADT_RESET_REGISTER |
730 ACPI_FADT_SEALED_CASE |
731 ACPI_FADT_S4_RTC_WAKE |
732 ACPI_FADT_PLATFORM_CLOCK;
733 if (chip->docking_supported) {
734 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
735 }
736 if (c2_latency < 100) {
737 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
738 }
739
740 fadt->reset_reg.space_id = 1;
741 fadt->reset_reg.bit_width = 8;
742 fadt->reset_reg.bit_offset = 0;
743 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
744 fadt->reset_reg.addrl = 0xcf9;
745 fadt->reset_reg.addrh = 0;
746
747 fadt->reset_value = 6;
748
749 fadt->x_pm1a_evt_blk.space_id = 1;
750 fadt->x_pm1a_evt_blk.bit_width = 32;
751 fadt->x_pm1a_evt_blk.bit_offset = 0;
752 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
753 fadt->x_pm1a_evt_blk.addrl = pmbase;
754 fadt->x_pm1a_evt_blk.addrh = 0x0;
755
756 fadt->x_pm1b_evt_blk.space_id = 1;
757 fadt->x_pm1b_evt_blk.bit_width = 0;
758 fadt->x_pm1b_evt_blk.bit_offset = 0;
759 fadt->x_pm1b_evt_blk.access_size = 0;
760 fadt->x_pm1b_evt_blk.addrl = 0x0;
761 fadt->x_pm1b_evt_blk.addrh = 0x0;
762
763 fadt->x_pm1a_cnt_blk.space_id = 1;
764 fadt->x_pm1a_cnt_blk.bit_width = 16;
765 fadt->x_pm1a_cnt_blk.bit_offset = 0;
766 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
767 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
768 fadt->x_pm1a_cnt_blk.addrh = 0x0;
769
770 fadt->x_pm1b_cnt_blk.space_id = 1;
771 fadt->x_pm1b_cnt_blk.bit_width = 0;
772 fadt->x_pm1b_cnt_blk.bit_offset = 0;
773 fadt->x_pm1b_cnt_blk.access_size = 0;
774 fadt->x_pm1b_cnt_blk.addrl = 0x0;
775 fadt->x_pm1b_cnt_blk.addrh = 0x0;
776
777 fadt->x_pm2_cnt_blk.space_id = 1;
778 fadt->x_pm2_cnt_blk.bit_width = 8;
779 fadt->x_pm2_cnt_blk.bit_offset = 0;
780 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
781 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
782 fadt->x_pm2_cnt_blk.addrh = 0x0;
783
784 fadt->x_pm_tmr_blk.space_id = 1;
785 fadt->x_pm_tmr_blk.bit_width = 32;
786 fadt->x_pm_tmr_blk.bit_offset = 0;
787 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
788 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
789 fadt->x_pm_tmr_blk.addrh = 0x0;
790
791 fadt->x_gpe0_blk.space_id = 1;
792 fadt->x_gpe0_blk.bit_width = 128;
793 fadt->x_gpe0_blk.bit_offset = 0;
794 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
795 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
796 fadt->x_gpe0_blk.addrh = 0x0;
797
798 fadt->x_gpe1_blk.space_id = 1;
799 fadt->x_gpe1_blk.bit_width = 0;
800 fadt->x_gpe1_blk.bit_offset = 0;
801 fadt->x_gpe1_blk.access_size = 0;
802 fadt->x_gpe1_blk.addrl = 0x0;
803 fadt->x_gpe1_blk.addrh = 0x0;
804}
805
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600806static const char *lpc_acpi_name(const struct device *dev)
Patrick Rudolph604f6982017-06-07 09:46:52 +0200807{
808 return "LPCB";
809}
810
Furquan Shaikh7536a392020-04-24 21:59:21 -0700811static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100812{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300813 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100814 config_t *chip = dev->chip_info;
815
816 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Tobias Diedrich7f5efd92017-12-14 00:29:01 +0100817 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100818}
819
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200820static void lpc_final(struct device *dev)
821{
Arthur Heymansebf201b2019-05-28 13:51:36 +0200822 spi_finalize_ops();
Nico Huber8e50b6d2018-02-04 15:52:18 +0100823
Bill XIEd533b162017-08-22 16:26:22 +0800824 /* Call SMM finalize() handlers before resume */
Julius Wernercd49cce2019-03-05 16:53:33 -0800825 if (CONFIG(HAVE_SMI_HANDLER)) {
826 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
Bill XIEd533b162017-08-22 16:26:22 +0800827 acpi_is_wakeup_s3()) {
Kyösti Mälkkib6585482020-06-01 15:11:14 +0300828 apm_control(APM_CNT_FINALIZE);
Bill XIEd533b162017-08-22 16:26:22 +0800829 }
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200830 }
831}
832
Arthur Heymansebf201b2019-05-28 13:51:36 +0200833void intel_southbridge_override_spi(
834 struct intel_swseq_spi_config *spi_config)
835{
836 struct device *dev = pcidev_on_root(0x1f, 0);
837
838 if (!dev)
839 return;
840 /* Devicetree may override defaults. */
841 const config_t *const config = dev->chip_info;
842
843 if (!config)
844 return;
845
846 if (config->spi.ops[0].op != 0)
847 memcpy(spi_config, &config->spi, sizeof(*spi_config));
848}
849
Stefan Reinauer8e073822012-04-04 00:07:22 +0200850static struct device_operations device_ops = {
851 .read_resources = pch_lpc_read_resources,
852 .set_resources = pci_dev_set_resources,
Arthur Heymans3cde4942019-08-18 10:02:10 +0200853 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200854 .write_acpi_tables = acpi_write_hpet,
Nico Huber68680dd2020-03-31 17:34:52 +0200855 .acpi_inject_dsdt = southbridge_inject_dsdt,
856 .acpi_fill_ssdt = southbridge_fill_ssdt,
Patrick Rudolph604f6982017-06-07 09:46:52 +0200857 .acpi_name = lpc_acpi_name,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200858 .init = lpc_init,
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200859 .final = lpc_final,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200860 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100861 .scan_bus = scan_static_bus,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200862 .ops_pci = &pci_dev_ops_pci,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200863};
864
865
Kimarie Hoote6f459c2012-07-14 08:26:08 -0600866/* IDs for LPC device of Intel 6 Series Chipset, Intel 7 Series Chipset, and
867 * Intel C200 Series Chipset
Stefan Reinauer8e073822012-04-04 00:07:22 +0200868 */
869
Vladimir Serbinenko42d55e02016-01-02 01:47:26 +0100870static const unsigned short pci_device_ids[] = {
871 0x1c40, 0x1c41, 0x1c42, 0x1c43, 0x1c44, 0x1c45, 0x1c46, 0x1c47, 0x1c48,
872 0x1c49, 0x1c4a, 0x1c4b, 0x1c4c, 0x1c4d, 0x1c4e, 0x1c4f, 0x1c50, 0x1c51,
873 0x1c52, 0x1c53, 0x1c54, 0x1c55, 0x1c56, 0x1c57, 0x1c58, 0x1c59, 0x1c5a,
874 0x1c5b, 0x1c5c, 0x1c5d, 0x1c5e, 0x1c5f,
875
876 0x1e41, 0x1e42, 0x1e43, 0x1e44, 0x1e45, 0x1e46, 0x1e47, 0x1e48, 0x1e49,
877 0x1e4a, 0x1e4b, 0x1e4c, 0x1e4d, 0x1e4e, 0x1e4f, 0x1e50, 0x1e51, 0x1e52,
878 0x1e53, 0x1e54, 0x1e55, 0x1e56, 0x1e57, 0x1e58, 0x1e59, 0x1e5a, 0x1e5b,
879 0x1e5c, 0x1e5d, 0x1e5e, 0x1e5f,
880
881 0 };
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700882
883static const struct pci_driver pch_lpc __pci_driver = {
884 .ops = &device_ops,
885 .vendor = PCI_VENDOR_ID_INTEL,
886 .devices = pci_device_ids,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200887};