blob: 987db360e2fb7eb85c7ea7c6c899b6125e71d212 [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
234#if DEBUG_PERIODIC_SMIS
235 /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
236 * periodic SMIs.
237 */
238 reg16 |= (3 << 0); // Periodic SMI every 8s
239#endif
240 pci_write_config16(dev, GEN_PMCON_1, reg16);
241
242 // Set the board's GPI routing.
243 pch_gpi_routing(dev);
244
245 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
246
247 outl(config->gpe0_en, pmbase + GPE0_EN);
248 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
249
250 /* Set up power management block and determine sleep mode */
251 reg32 = inl(pmbase + 0x04); // PM1_CNT
252 reg32 &= ~(7 << 10); // SLP_TYP
253 reg32 |= (1 << 0); // SCI_EN
254 outl(reg32, pmbase + 0x04);
255
256 /* Clear magic status bits to prevent unexpected wake */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200257 reg32 = RCBA32(PRSTS);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200258 reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200259 RCBA32(PRSTS) = reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200260
261 reg32 = RCBA32(0x3f02);
262 reg32 &= ~0xf;
263 RCBA32(0x3f02) = reg32;
264}
265
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700266/* CougarPoint PCH Power Management init */
267static void cpt_pm_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200268{
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700269 printk(BIOS_DEBUG, "CougarPoint PM init\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200270 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200271 RCBA32_AND_OR(CIR30, ~0UL, (1 << 6)|(1 << 0));
272 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
273 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
274 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
275 RCBA32(DMC) = 0xc0388400;
276 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
277 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
278 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
279 RCBA32(PM_CFG) = 0x050f0000;
280 RCBA32(CIR8) = 0x04000000;
281 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
282 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1));
283 RCBA32(CIR12) = 0x0001c000;
284 RCBA32(CIR14) = 0x00061100;
285 RCBA32(CIR15) = 0x7f8fdfff;
286 RCBA32(CIR13) = 0x000003fc;
287 RCBA32(CIR16) = 0x00001000;
288 RCBA32(CIR18) = 0x0001c000;
289 RCBA32(CIR17) = 0x00000800;
290 RCBA32(CIR23) = 0x00001000;
291 RCBA32(CIR19) = 0x00093900;
292 RCBA32(CIR20) = 0x24653002;
293 RCBA32(CIR21) = 0x062108fe;
294 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
295 RCBA32(CIR24) = 0x01010000;
296 RCBA32(CIR25) = 0x01010404;
297 RCBA32(CIR27) = 0x01041041;
298 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
299 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
300 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
301 RCBA32(CIR26) = 0x00000001;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200302 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
303 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200304 RCBA32(PMSYNC_CFG) = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200305 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
306}
307
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700308/* PantherPoint PCH Power Management init */
309static void ppt_pm_init(struct device *dev)
310{
311 printk(BIOS_DEBUG, "PantherPoint PM init\n");
312 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200313 RCBA32_AND_OR(CIR30, ~0UL, (1 << 0));
314 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
315 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
316 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
317 RCBA32(DMC) = 0xc03b8400;
318 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
319 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
320 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
321 RCBA32(PM_CFG) = 0x054f0000;
322 RCBA32(CIR8) = 0x04000000;
323 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
324 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1)|(1 << 0));
325 RCBA32(CIR12) = 0x0001c000;
326 RCBA32(CIR14) = 0x00061100;
327 RCBA32(CIR15) = 0x7f8fdfff;
328 RCBA32(CIR13) = 0x000003fd;
329 RCBA32(CIR16) = 0x00001000;
330 RCBA32(CIR18) = 0x0001c000;
331 RCBA32(CIR17) = 0x00000800;
332 RCBA32(CIR23) = 0x00001000;
333 RCBA32(CIR19) = 0x00093900;
334 RCBA32(CIR20) = 0x24653002;
335 RCBA32(CIR21) = 0x067388fe;
336 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
337 RCBA32(CIR24) = 0x01010000;
338 RCBA32(CIR25) = 0x01010404;
339 RCBA32(CIR27) = 0x01040000;
340 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
341 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
342 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
343 RCBA32(CIR26) = 0x00000001;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700344 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
345 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
346 RCBA32_AND_OR(0x33a4, ~0UL, (1 << 0));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200347 RCBA32(PMSYNC_CFG) = 0;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700348 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
349}
350
Nico Huberb2dae792015-10-26 12:34:02 +0100351static void enable_hpet(struct device *const dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200352{
353 u32 reg32;
Nico Huberb2dae792015-10-26 12:34:02 +0100354 size_t i;
355
356 /* Assign unique bus/dev/fn for each HPET */
357 for (i = 0; i < 8; ++i)
358 pci_write_config16(dev, LPC_HnBDF(i),
359 PCH_HPET_PCI_BUS << 8 | PCH_HPET_PCI_SLOT << 3 | i);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200360
361 /* Move HPET to default address 0xfed00000 and enable it */
362 reg32 = RCBA32(HPTC);
363 reg32 |= (1 << 7); // HPET Address Enable
364 reg32 &= ~(3 << 0);
365 RCBA32(HPTC) = reg32;
366}
367
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200368static void enable_clock_gating(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200369{
370 u32 reg32;
371 u16 reg16;
372
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200373 RCBA32_AND_OR(DMIC, ~0UL, 0xf);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200374
375 reg16 = pci_read_config16(dev, GEN_PMCON_1);
Michał Żygowski9ff2af22020-04-13 20:37:36 +0200376 reg16 &= ~(3 << 2); /* Clear CLKRUN bits for mobile and desktop */
377 if (get_platform_type() == PLATFORM_MOBILE)
378 reg16 |= (1 << 2); /* CLKRUN_EN for mobile */
379 else if (get_platform_type() == PLATFORM_DESKTOP_SERVER)
380 reg16 |= (1 << 3); /* PSEUDO_CLKRUN_EN for desktop */
381 reg16 |= (1 << 11);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200382 pci_write_config16(dev, GEN_PMCON_1, reg16);
383
384 pch_iobp_update(0xEB007F07, ~0UL, (1 << 31));
385 pch_iobp_update(0xEB004000, ~0UL, (1 << 7));
386 pch_iobp_update(0xEC007F07, ~0UL, (1 << 31));
387 pch_iobp_update(0xEC004000, ~0UL, (1 << 7));
388
389 reg32 = RCBA32(CG);
390 reg32 |= (1 << 31);
391 reg32 |= (1 << 29) | (1 << 28);
392 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
393 reg32 |= (1 << 16);
394 reg32 |= (1 << 17);
395 reg32 |= (1 << 18);
396 reg32 |= (1 << 22);
397 reg32 |= (1 << 23);
398 reg32 &= ~(1 << 20);
399 reg32 |= (1 << 19);
400 reg32 |= (1 << 0);
401 reg32 |= (0xf << 1);
402 RCBA32(CG) = reg32;
403
404 RCBA32_OR(0x38c0, 0x7);
405 RCBA32_OR(0x36d4, 0x6680c004);
406 RCBA32_OR(0x3564, 0x3);
407}
408
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200409static void pch_set_acpi_mode(void)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200410{
Julius Werner5d1f9a02019-03-07 17:07:26 -0800411 if (!acpi_is_wakeup_s3() && CONFIG(HAVE_SMI_HANDLER)) {
Duncan Laurie95be1d62012-04-09 12:31:43 -0700412 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200413 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
Duncan Laurie95be1d62012-04-09 12:31:43 -0700414 printk(BIOS_DEBUG, "done.\n");
Duncan Laurie95be1d62012-04-09 12:31:43 -0700415 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200416}
Stefan Reinauer8e073822012-04-04 00:07:22 +0200417
418static void pch_disable_smm_only_flashing(struct device *dev)
419{
420 u8 reg8;
421
422 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100423 reg8 = pci_read_config8(dev, BIOS_CNTL);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200424 reg8 &= ~(1 << 5);
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100425 pci_write_config8(dev, BIOS_CNTL, reg8);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200426}
427
428static void pch_fixups(struct device *dev)
429{
430 u8 gen_pmcon_2;
431
432 /* Indicate DRAM init done for MRC S3 to know it can resume */
433 gen_pmcon_2 = pci_read_config8(dev, GEN_PMCON_2);
434 gen_pmcon_2 |= (1 << 7);
435 pci_write_config8(dev, GEN_PMCON_2, gen_pmcon_2);
436
437 /*
438 * Enable DMI ASPM in the PCH
439 */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200440 RCBA32_AND_OR(DMC, ~(1 << 10), 0);
441 RCBA32_OR(LCAP, (1 << 11)|(1 << 10));
442 RCBA32_OR(LCTL, 0x3);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200443}
444
Nico Huber7b2f9f62015-10-01 19:00:51 +0200445static void pch_spi_init(const struct device *const dev)
446{
447 const config_t *const config = dev->chip_info;
448
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100449 printk(BIOS_DEBUG, "%s\n", __func__);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200450
451 if (config->spi_uvscc)
452 RCBA32(0x3800 + 0xc8) = config->spi_uvscc;
453 if (config->spi_lvscc)
454 RCBA32(0x3800 + 0xc4) = config->spi_lvscc;
455
456 if (config->spi_uvscc || config->spi_lvscc)
457 RCBA32_OR(0x3800 + 0xc4, 1 << 23); /* lock both UVSCC + LVSCC */
458}
459
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200460static const struct {
461 u16 dev_id;
462 const char *dev_name;
463} pch_table[] = {
464 /* 6-series PCI ids from
465 * Intel® 6 Series Chipset and
466 * Intel® C200 Series Chipset
467 * Specification Update - NDA
468 * October 2013
469 * CDI / IBP#: 440377
470 */
471 {0x1C41, "SFF Sample"},
472 {0x1C42, "Desktop Sample"},
473 {0x1C43, "Mobile Sample"},
474 {0x1C44, "Z68"},
475 {0x1C46, "P67"},
476 {0x1C47, "UM67"},
477 {0x1C49, "HM65"},
478 {0x1C4A, "H67"},
479 {0x1C4B, "HM67"},
480 {0x1C4C, "Q65"},
481 {0x1C4D, "QS67"},
482 {0x1C4E, "Q67"},
483 {0x1C4F, "QM67"},
484 {0x1C50, "B65"},
485 {0x1C52, "C202"},
486 {0x1C54, "C204"},
487 {0x1C56, "C206"},
488 {0x1C5C, "H61"},
489 /* 7-series PCI ids from Intel document 472178 */
490 {0x1E41, "Desktop Sample"},
491 {0x1E42, "Mobile Sample"},
492 {0x1E43, "SFF Sample"},
493 {0x1E44, "Z77"},
494 {0x1E45, "H71"},
495 {0x1E46, "Z75"},
496 {0x1E47, "Q77"},
497 {0x1E48, "Q75"},
498 {0x1E49, "B75"},
499 {0x1E4A, "H77"},
500 {0x1E53, "C216"},
501 {0x1E55, "QM77"},
502 {0x1E56, "QS77"},
503 {0x1E58, "UM77"},
504 {0x1E57, "HM77"},
505 {0x1E59, "HM76"},
506 {0x1E5D, "HM75"},
507 {0x1E5E, "HM70"},
508 {0x1E5F, "NM70"},
509};
510
511static void report_pch_info(struct device *dev)
512{
513 const u16 dev_id = pci_read_config16(dev, PCI_DEVICE_ID);
514 int i;
515
516 const char *pch_type = "Unknown";
517 for (i = 0; i < ARRAY_SIZE(pch_table); i++) {
518 if (pch_table[i].dev_id == dev_id) {
519 pch_type = pch_table[i].dev_name;
520 break;
521 }
522 }
523 printk(BIOS_INFO, "PCH: detected %s, device id: 0x%x, rev id 0x%x\n",
524 pch_type, dev_id, pci_read_config8(dev, PCI_CLASS_REVISION));
525}
526
Stefan Reinauer8e073822012-04-04 00:07:22 +0200527static void lpc_init(struct device *dev)
528{
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100529 printk(BIOS_DEBUG, "pch: %s\n", __func__);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200530
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200531 /* Print detected platform */
532 report_pch_info(dev);
533
Stefan Reinauer8e073822012-04-04 00:07:22 +0200534 /* Set the value for PCI command register. */
535 pci_write_config16(dev, PCI_COMMAND, 0x000f);
536
537 /* IO APIC initialization. */
Paul Menzel9c50e6a2013-05-03 12:23:39 +0200538 pch_enable_ioapic(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200539
540 pch_enable_serial_irqs(dev);
541
542 /* Setup the PIRQ. */
543 pch_pirq_init(dev);
544
545 /* Setup power options. */
546 pch_power_options(dev);
547
548 /* Initialize power management */
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700549 switch (pch_silicon_type()) {
550 case PCH_TYPE_CPT: /* CougarPoint */
551 cpt_pm_init(dev);
552 break;
553 case PCH_TYPE_PPT: /* PantherPoint */
554 ppt_pm_init(dev);
555 break;
556 default:
557 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
558 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200559
560 /* Set the state of the GPIO lines. */
561 //gpio_init(dev);
562
563 /* Initialize the real time clock. */
Patrick Rudolph6b931122018-11-01 17:48:37 +0100564 sb_rtc_init();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200565
566 /* Initialize ISA DMA. */
567 isa_dma_init();
568
569 /* Initialize the High Precision Event Timers, if present. */
Nico Huberb2dae792015-10-26 12:34:02 +0100570 enable_hpet(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200571
572 /* Initialize Clock Gating */
573 enable_clock_gating(dev);
574
575 setup_i8259();
576
577 /* The OS should do this? */
578 /* Interrupt 9 should be level triggered (SCI) */
579 i8259_configure_irq_trigger(9, 1);
580
581 pch_disable_smm_only_flashing(dev);
582
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200583 pch_set_acpi_mode();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200584
585 pch_fixups(dev);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200586
587 pch_spi_init(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200588}
589
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200590static void pch_lpc_read_resources(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200591{
592 struct resource *res;
Marc Jonesa0bec172012-07-13 14:14:34 -0600593 config_t *config = dev->chip_info;
594 u8 io_index = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200595
596 /* Get the normal PCI resources of this device. */
597 pci_dev_read_resources(dev);
598
599 /* Add an extra subtractive resource for both memory and I/O. */
Marc Jonesa0bec172012-07-13 14:14:34 -0600600 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200601 res->base = 0;
602 res->size = 0x1000;
603 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
604 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
605
Marc Jonesa0bec172012-07-13 14:14:34 -0600606 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Vladimir Serbinenko0650cd02014-02-05 15:03:50 +0100607 res->base = 0xff000000;
608 /* Some systems (e.g. X230) have 12 MiB flash.
609 SPI controller supports up to 2 x 16 MiB of flash but
610 address map limits this to 16MiB. */
611 res->size = 0x01000000; /* 16 MB for flash */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200612 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
613 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
614
615 res = new_resource(dev, 3); /* IOAPIC */
616 res->base = IO_APIC_ADDR;
617 res->size = 0x00001000;
618 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Marc Jonesa0bec172012-07-13 14:14:34 -0600619
620 /* Set PCH IO decode ranges if required.*/
621 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
622 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
623 res->base = config->gen1_dec & 0xFFFC;
624 res->size = (config->gen1_dec >> 16) & 0xFC;
625 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
626 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
627 }
628
629 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
630 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
631 res->base = config->gen2_dec & 0xFFFC;
632 res->size = (config->gen2_dec >> 16) & 0xFC;
633 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
634 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
635 }
636
637 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
638 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
639 res->base = config->gen3_dec & 0xFFFC;
640 res->size = (config->gen3_dec >> 16) & 0xFC;
641 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
642 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
643 }
644
645 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
646 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
647 res->base = config->gen4_dec & 0xFFFC;
648 res->size = (config->gen4_dec >> 16) & 0xFC;
649 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
650 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
651 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200652}
653
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200654static void pch_lpc_enable(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200655{
656 /* Enable PCH Display Port */
657 RCBA16(DISPBDF) = 0x0010;
658 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
659
660 pch_enable(dev);
661}
662
Furquan Shaikh338fd9a2020-04-24 22:57:05 -0700663static void southbridge_inject_dsdt(const struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200664{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200665 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200666
667 if (gnvs) {
Elyes HAOUAS035df002016-10-03 21:54:16 +0200668 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200669
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200670 acpi_create_gnvs(gnvs);
Vladimir Serbinenko06c788d2014-10-12 00:17:11 +0200671
672 gnvs->apic = 1;
673 gnvs->mpen = 1; /* Enable Multi Processing */
674 gnvs->pcnt = dev_count_cpu();
675
Julius Wernercd49cce2019-03-05 16:53:33 -0800676#if CONFIG(CHROMEOS)
Joel Kitching6fbd8742018-08-23 14:56:25 +0800677 chromeos_init_chromeos_acpi(&(gnvs->chromeos));
Vladimir Serbinenko06c788d2014-10-12 00:17:11 +0200678#endif
679
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200680 /* And tell SMI about it */
681 smm_setup_structures(gnvs, NULL, NULL);
682
Vladimir Serbinenko334fd8e2014-10-05 11:10:35 +0200683 /* Add it to DSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100684 acpigen_write_scope("\\");
685 acpigen_write_name_dword("NVSA", (u32) gnvs);
686 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200687 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200688}
689
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200690void acpi_fill_fadt(acpi_fadt_t *fadt)
691{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300692 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200693 config_t *chip = dev->chip_info;
694 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
695 int c2_latency;
696
Elyes HAOUAS0d4de2a2019-02-28 13:04:29 +0100697 fadt->reserved = 0;
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200698
699 fadt->sci_int = 0x9;
700 fadt->smi_cmd = APM_CNT;
701 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
702 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
703 fadt->s4bios_req = 0x0;
704 fadt->pstate_cnt = 0;
705
706 fadt->pm1a_evt_blk = pmbase;
707 fadt->pm1b_evt_blk = 0x0;
708 fadt->pm1a_cnt_blk = pmbase + 0x4;
709 fadt->pm1b_cnt_blk = 0x0;
710 fadt->pm2_cnt_blk = pmbase + 0x50;
711 fadt->pm_tmr_blk = pmbase + 0x8;
712 fadt->gpe0_blk = pmbase + 0x20;
713 fadt->gpe1_blk = 0;
714
715 fadt->pm1_evt_len = 4;
716 fadt->pm1_cnt_len = 2;
717 fadt->pm2_cnt_len = 1;
718 fadt->pm_tmr_len = 4;
719 fadt->gpe0_blk_len = 16;
720 fadt->gpe1_blk_len = 0;
721 fadt->gpe1_base = 0;
722 fadt->cst_cnt = 0;
723 c2_latency = chip->c2_latency;
724 if (!c2_latency) {
725 c2_latency = 101; /* c2 unsupported */
726 }
727 fadt->p_lvl2_lat = c2_latency;
728 fadt->p_lvl3_lat = 87;
729 fadt->flush_size = 1024;
730 fadt->flush_stride = 16;
Patrick Rudolphb30a47b2019-07-15 18:04:23 +0200731 /* P_CNT not supported */
732 fadt->duty_offset = 0;
733 fadt->duty_width = 0;
734
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200735 fadt->day_alrm = 0xd;
736 fadt->mon_alrm = 0x00;
737 fadt->century = 0x00;
738 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
739
740 fadt->flags = ACPI_FADT_WBINVD |
741 ACPI_FADT_C1_SUPPORTED |
742 ACPI_FADT_SLEEP_BUTTON |
743 ACPI_FADT_RESET_REGISTER |
744 ACPI_FADT_SEALED_CASE |
745 ACPI_FADT_S4_RTC_WAKE |
746 ACPI_FADT_PLATFORM_CLOCK;
747 if (chip->docking_supported) {
748 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
749 }
750 if (c2_latency < 100) {
751 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
752 }
753
754 fadt->reset_reg.space_id = 1;
755 fadt->reset_reg.bit_width = 8;
756 fadt->reset_reg.bit_offset = 0;
757 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
758 fadt->reset_reg.addrl = 0xcf9;
759 fadt->reset_reg.addrh = 0;
760
761 fadt->reset_value = 6;
762
763 fadt->x_pm1a_evt_blk.space_id = 1;
764 fadt->x_pm1a_evt_blk.bit_width = 32;
765 fadt->x_pm1a_evt_blk.bit_offset = 0;
766 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
767 fadt->x_pm1a_evt_blk.addrl = pmbase;
768 fadt->x_pm1a_evt_blk.addrh = 0x0;
769
770 fadt->x_pm1b_evt_blk.space_id = 1;
771 fadt->x_pm1b_evt_blk.bit_width = 0;
772 fadt->x_pm1b_evt_blk.bit_offset = 0;
773 fadt->x_pm1b_evt_blk.access_size = 0;
774 fadt->x_pm1b_evt_blk.addrl = 0x0;
775 fadt->x_pm1b_evt_blk.addrh = 0x0;
776
777 fadt->x_pm1a_cnt_blk.space_id = 1;
778 fadt->x_pm1a_cnt_blk.bit_width = 16;
779 fadt->x_pm1a_cnt_blk.bit_offset = 0;
780 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
781 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
782 fadt->x_pm1a_cnt_blk.addrh = 0x0;
783
784 fadt->x_pm1b_cnt_blk.space_id = 1;
785 fadt->x_pm1b_cnt_blk.bit_width = 0;
786 fadt->x_pm1b_cnt_blk.bit_offset = 0;
787 fadt->x_pm1b_cnt_blk.access_size = 0;
788 fadt->x_pm1b_cnt_blk.addrl = 0x0;
789 fadt->x_pm1b_cnt_blk.addrh = 0x0;
790
791 fadt->x_pm2_cnt_blk.space_id = 1;
792 fadt->x_pm2_cnt_blk.bit_width = 8;
793 fadt->x_pm2_cnt_blk.bit_offset = 0;
794 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
795 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
796 fadt->x_pm2_cnt_blk.addrh = 0x0;
797
798 fadt->x_pm_tmr_blk.space_id = 1;
799 fadt->x_pm_tmr_blk.bit_width = 32;
800 fadt->x_pm_tmr_blk.bit_offset = 0;
801 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
802 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
803 fadt->x_pm_tmr_blk.addrh = 0x0;
804
805 fadt->x_gpe0_blk.space_id = 1;
806 fadt->x_gpe0_blk.bit_width = 128;
807 fadt->x_gpe0_blk.bit_offset = 0;
808 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
809 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
810 fadt->x_gpe0_blk.addrh = 0x0;
811
812 fadt->x_gpe1_blk.space_id = 1;
813 fadt->x_gpe1_blk.bit_width = 0;
814 fadt->x_gpe1_blk.bit_offset = 0;
815 fadt->x_gpe1_blk.access_size = 0;
816 fadt->x_gpe1_blk.addrl = 0x0;
817 fadt->x_gpe1_blk.addrh = 0x0;
818}
819
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600820static const char *lpc_acpi_name(const struct device *dev)
Patrick Rudolph604f6982017-06-07 09:46:52 +0200821{
822 return "LPCB";
823}
824
Furquan Shaikh7536a392020-04-24 21:59:21 -0700825static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100826{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300827 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100828 config_t *chip = dev->chip_info;
829
830 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Tobias Diedrich7f5efd92017-12-14 00:29:01 +0100831 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100832}
833
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200834static void lpc_final(struct device *dev)
835{
Arthur Heymansebf201b2019-05-28 13:51:36 +0200836 spi_finalize_ops();
Nico Huber8e50b6d2018-02-04 15:52:18 +0100837
Bill XIEd533b162017-08-22 16:26:22 +0800838 /* Call SMM finalize() handlers before resume */
Julius Wernercd49cce2019-03-05 16:53:33 -0800839 if (CONFIG(HAVE_SMI_HANDLER)) {
840 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
Bill XIEd533b162017-08-22 16:26:22 +0800841 acpi_is_wakeup_s3()) {
842 outb(APM_CNT_FINALIZE, APM_CNT);
843 }
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200844 }
845}
846
Arthur Heymansebf201b2019-05-28 13:51:36 +0200847void intel_southbridge_override_spi(
848 struct intel_swseq_spi_config *spi_config)
849{
850 struct device *dev = pcidev_on_root(0x1f, 0);
851
852 if (!dev)
853 return;
854 /* Devicetree may override defaults. */
855 const config_t *const config = dev->chip_info;
856
857 if (!config)
858 return;
859
860 if (config->spi.ops[0].op != 0)
861 memcpy(spi_config, &config->spi, sizeof(*spi_config));
862}
863
Stefan Reinauer8e073822012-04-04 00:07:22 +0200864static struct pci_operations pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530865 .set_subsystem = pci_dev_set_subsystem,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200866};
867
868static struct device_operations device_ops = {
869 .read_resources = pch_lpc_read_resources,
870 .set_resources = pci_dev_set_resources,
Arthur Heymans3cde4942019-08-18 10:02:10 +0200871 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200872 .write_acpi_tables = acpi_write_hpet,
Nico Huber68680dd2020-03-31 17:34:52 +0200873 .acpi_inject_dsdt = southbridge_inject_dsdt,
874 .acpi_fill_ssdt = southbridge_fill_ssdt,
Patrick Rudolph604f6982017-06-07 09:46:52 +0200875 .acpi_name = lpc_acpi_name,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200876 .init = lpc_init,
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200877 .final = lpc_final,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200878 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100879 .scan_bus = scan_static_bus,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200880 .ops_pci = &pci_ops,
881};
882
883
Kimarie Hoote6f459c2012-07-14 08:26:08 -0600884/* IDs for LPC device of Intel 6 Series Chipset, Intel 7 Series Chipset, and
885 * Intel C200 Series Chipset
Stefan Reinauer8e073822012-04-04 00:07:22 +0200886 */
887
Vladimir Serbinenko42d55e02016-01-02 01:47:26 +0100888static const unsigned short pci_device_ids[] = {
889 0x1c40, 0x1c41, 0x1c42, 0x1c43, 0x1c44, 0x1c45, 0x1c46, 0x1c47, 0x1c48,
890 0x1c49, 0x1c4a, 0x1c4b, 0x1c4c, 0x1c4d, 0x1c4e, 0x1c4f, 0x1c50, 0x1c51,
891 0x1c52, 0x1c53, 0x1c54, 0x1c55, 0x1c56, 0x1c57, 0x1c58, 0x1c59, 0x1c5a,
892 0x1c5b, 0x1c5c, 0x1c5d, 0x1c5e, 0x1c5f,
893
894 0x1e41, 0x1e42, 0x1e43, 0x1e44, 0x1e45, 0x1e46, 0x1e47, 0x1e48, 0x1e49,
895 0x1e4a, 0x1e4b, 0x1e4c, 0x1e4d, 0x1e4e, 0x1e4f, 0x1e50, 0x1e51, 0x1e52,
896 0x1e53, 0x1e54, 0x1e55, 0x1e56, 0x1e57, 0x1e58, 0x1e59, 0x1e5a, 0x1e5b,
897 0x1e5c, 0x1e5d, 0x1e5e, 0x1e5f,
898
899 0 };
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700900
901static const struct pci_driver pch_lpc __pci_driver = {
902 .ops = &device_ops,
903 .vendor = PCI_VENDOR_ID_INTEL,
904 .devices = pci_device_ids,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200905};