blob: c0f62bd7fbd3a714b7c2bb94817c155ee55bceb1 [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{
Stefan Reinauer8e073822012-04-04 00:07:22 +0200420 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Angel Ponsc803f652020-06-07 22:09:01 +0200421
422 pci_and_config8(dev, BIOS_CNTL, ~(1 << 5));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200423}
424
425static void pch_fixups(struct device *dev)
426{
Stefan Reinauer8e073822012-04-04 00:07:22 +0200427 /* Indicate DRAM init done for MRC S3 to know it can resume */
Angel Ponsc803f652020-06-07 22:09:01 +0200428 pci_or_config8(dev, GEN_PMCON_2, 1 << 7);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200429
430 /*
431 * Enable DMI ASPM in the PCH
432 */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200433 RCBA32_AND_OR(DMC, ~(1 << 10), 0);
434 RCBA32_OR(LCAP, (1 << 11)|(1 << 10));
435 RCBA32_OR(LCTL, 0x3);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200436}
437
Nico Huber7b2f9f62015-10-01 19:00:51 +0200438static void pch_spi_init(const struct device *const dev)
439{
440 const config_t *const config = dev->chip_info;
441
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100442 printk(BIOS_DEBUG, "%s\n", __func__);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200443
444 if (config->spi_uvscc)
445 RCBA32(0x3800 + 0xc8) = config->spi_uvscc;
446 if (config->spi_lvscc)
447 RCBA32(0x3800 + 0xc4) = config->spi_lvscc;
448
449 if (config->spi_uvscc || config->spi_lvscc)
450 RCBA32_OR(0x3800 + 0xc4, 1 << 23); /* lock both UVSCC + LVSCC */
451}
452
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200453static const struct {
454 u16 dev_id;
455 const char *dev_name;
456} pch_table[] = {
457 /* 6-series PCI ids from
458 * Intel® 6 Series Chipset and
459 * Intel® C200 Series Chipset
460 * Specification Update - NDA
461 * October 2013
462 * CDI / IBP#: 440377
463 */
464 {0x1C41, "SFF Sample"},
465 {0x1C42, "Desktop Sample"},
466 {0x1C43, "Mobile Sample"},
467 {0x1C44, "Z68"},
468 {0x1C46, "P67"},
469 {0x1C47, "UM67"},
470 {0x1C49, "HM65"},
471 {0x1C4A, "H67"},
472 {0x1C4B, "HM67"},
473 {0x1C4C, "Q65"},
474 {0x1C4D, "QS67"},
475 {0x1C4E, "Q67"},
476 {0x1C4F, "QM67"},
477 {0x1C50, "B65"},
478 {0x1C52, "C202"},
479 {0x1C54, "C204"},
480 {0x1C56, "C206"},
481 {0x1C5C, "H61"},
482 /* 7-series PCI ids from Intel document 472178 */
483 {0x1E41, "Desktop Sample"},
484 {0x1E42, "Mobile Sample"},
485 {0x1E43, "SFF Sample"},
486 {0x1E44, "Z77"},
487 {0x1E45, "H71"},
488 {0x1E46, "Z75"},
489 {0x1E47, "Q77"},
490 {0x1E48, "Q75"},
491 {0x1E49, "B75"},
492 {0x1E4A, "H77"},
493 {0x1E53, "C216"},
494 {0x1E55, "QM77"},
495 {0x1E56, "QS77"},
496 {0x1E58, "UM77"},
497 {0x1E57, "HM77"},
498 {0x1E59, "HM76"},
499 {0x1E5D, "HM75"},
500 {0x1E5E, "HM70"},
501 {0x1E5F, "NM70"},
502};
503
504static void report_pch_info(struct device *dev)
505{
506 const u16 dev_id = pci_read_config16(dev, PCI_DEVICE_ID);
507 int i;
508
509 const char *pch_type = "Unknown";
510 for (i = 0; i < ARRAY_SIZE(pch_table); i++) {
511 if (pch_table[i].dev_id == dev_id) {
512 pch_type = pch_table[i].dev_name;
513 break;
514 }
515 }
516 printk(BIOS_INFO, "PCH: detected %s, device id: 0x%x, rev id 0x%x\n",
517 pch_type, dev_id, pci_read_config8(dev, PCI_CLASS_REVISION));
518}
519
Stefan Reinauer8e073822012-04-04 00:07:22 +0200520static void lpc_init(struct device *dev)
521{
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100522 printk(BIOS_DEBUG, "pch: %s\n", __func__);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200523
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200524 /* Print detected platform */
525 report_pch_info(dev);
526
Stefan Reinauer8e073822012-04-04 00:07:22 +0200527 /* Set the value for PCI command register. */
528 pci_write_config16(dev, PCI_COMMAND, 0x000f);
529
530 /* IO APIC initialization. */
Paul Menzel9c50e6a2013-05-03 12:23:39 +0200531 pch_enable_ioapic(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200532
533 pch_enable_serial_irqs(dev);
534
535 /* Setup the PIRQ. */
536 pch_pirq_init(dev);
537
538 /* Setup power options. */
539 pch_power_options(dev);
540
541 /* Initialize power management */
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700542 switch (pch_silicon_type()) {
543 case PCH_TYPE_CPT: /* CougarPoint */
544 cpt_pm_init(dev);
545 break;
546 case PCH_TYPE_PPT: /* PantherPoint */
547 ppt_pm_init(dev);
548 break;
549 default:
550 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
551 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200552
553 /* Set the state of the GPIO lines. */
554 //gpio_init(dev);
555
556 /* Initialize the real time clock. */
Patrick Rudolph6b931122018-11-01 17:48:37 +0100557 sb_rtc_init();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200558
559 /* Initialize ISA DMA. */
560 isa_dma_init();
561
562 /* Initialize the High Precision Event Timers, if present. */
Nico Huberb2dae792015-10-26 12:34:02 +0100563 enable_hpet(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200564
565 /* Initialize Clock Gating */
566 enable_clock_gating(dev);
567
568 setup_i8259();
569
570 /* The OS should do this? */
571 /* Interrupt 9 should be level triggered (SCI) */
572 i8259_configure_irq_trigger(9, 1);
573
574 pch_disable_smm_only_flashing(dev);
575
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200576 pch_set_acpi_mode();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200577
578 pch_fixups(dev);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200579
580 pch_spi_init(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200581}
582
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200583static void pch_lpc_read_resources(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200584{
585 struct resource *res;
Marc Jonesa0bec172012-07-13 14:14:34 -0600586 config_t *config = dev->chip_info;
587 u8 io_index = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200588
589 /* Get the normal PCI resources of this device. */
590 pci_dev_read_resources(dev);
591
592 /* Add an extra subtractive resource for both memory and I/O. */
Marc Jonesa0bec172012-07-13 14:14:34 -0600593 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200594 res->base = 0;
595 res->size = 0x1000;
596 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
597 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
598
Marc Jonesa0bec172012-07-13 14:14:34 -0600599 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Vladimir Serbinenko0650cd02014-02-05 15:03:50 +0100600 res->base = 0xff000000;
601 /* Some systems (e.g. X230) have 12 MiB flash.
602 SPI controller supports up to 2 x 16 MiB of flash but
603 address map limits this to 16MiB. */
604 res->size = 0x01000000; /* 16 MB for flash */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200605 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
606 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
607
608 res = new_resource(dev, 3); /* IOAPIC */
609 res->base = IO_APIC_ADDR;
610 res->size = 0x00001000;
611 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Marc Jonesa0bec172012-07-13 14:14:34 -0600612
613 /* Set PCH IO decode ranges if required.*/
614 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
615 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
616 res->base = config->gen1_dec & 0xFFFC;
617 res->size = (config->gen1_dec >> 16) & 0xFC;
618 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
619 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
620 }
621
622 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
623 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
624 res->base = config->gen2_dec & 0xFFFC;
625 res->size = (config->gen2_dec >> 16) & 0xFC;
626 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
627 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
628 }
629
630 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
631 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
632 res->base = config->gen3_dec & 0xFFFC;
633 res->size = (config->gen3_dec >> 16) & 0xFC;
634 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
635 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
636 }
637
638 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
639 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
640 res->base = config->gen4_dec & 0xFFFC;
641 res->size = (config->gen4_dec >> 16) & 0xFC;
642 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
643 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
644 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200645}
646
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200647static void pch_lpc_enable(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200648{
649 /* Enable PCH Display Port */
650 RCBA16(DISPBDF) = 0x0010;
651 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
652
653 pch_enable(dev);
654}
655
Furquan Shaikh338fd9a2020-04-24 22:57:05 -0700656static void southbridge_inject_dsdt(const struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200657{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200658 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200659
660 if (gnvs) {
Elyes HAOUAS035df002016-10-03 21:54:16 +0200661 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200662
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200663 acpi_create_gnvs(gnvs);
Vladimir Serbinenko06c788d2014-10-12 00:17:11 +0200664
665 gnvs->apic = 1;
666 gnvs->mpen = 1; /* Enable Multi Processing */
667 gnvs->pcnt = dev_count_cpu();
668
Julius Wernercd49cce2019-03-05 16:53:33 -0800669#if CONFIG(CHROMEOS)
Joel Kitching6fbd8742018-08-23 14:56:25 +0800670 chromeos_init_chromeos_acpi(&(gnvs->chromeos));
Vladimir Serbinenko06c788d2014-10-12 00:17:11 +0200671#endif
672
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200673 /* And tell SMI about it */
674 smm_setup_structures(gnvs, NULL, NULL);
675
Vladimir Serbinenko334fd8e2014-10-05 11:10:35 +0200676 /* Add it to DSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100677 acpigen_write_scope("\\");
678 acpigen_write_name_dword("NVSA", (u32) gnvs);
679 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200680 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200681}
682
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200683void acpi_fill_fadt(acpi_fadt_t *fadt)
684{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300685 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200686 config_t *chip = dev->chip_info;
687 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
688 int c2_latency;
689
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200690
691 fadt->sci_int = 0x9;
Kyösti Mälkkic328a682019-11-23 07:23:40 +0200692
Kyösti Mälkki0a9e72e2019-08-11 01:22:28 +0300693 if (permanent_smi_handler()) {
Kyösti Mälkkic328a682019-11-23 07:23:40 +0200694 fadt->smi_cmd = APM_CNT;
695 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
696 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
697 }
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200698
699 fadt->pm1a_evt_blk = pmbase;
700 fadt->pm1b_evt_blk = 0x0;
701 fadt->pm1a_cnt_blk = pmbase + 0x4;
702 fadt->pm1b_cnt_blk = 0x0;
703 fadt->pm2_cnt_blk = pmbase + 0x50;
704 fadt->pm_tmr_blk = pmbase + 0x8;
705 fadt->gpe0_blk = pmbase + 0x20;
706 fadt->gpe1_blk = 0;
707
708 fadt->pm1_evt_len = 4;
709 fadt->pm1_cnt_len = 2;
710 fadt->pm2_cnt_len = 1;
711 fadt->pm_tmr_len = 4;
712 fadt->gpe0_blk_len = 16;
713 fadt->gpe1_blk_len = 0;
714 fadt->gpe1_base = 0;
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200715 c2_latency = chip->c2_latency;
716 if (!c2_latency) {
717 c2_latency = 101; /* c2 unsupported */
718 }
719 fadt->p_lvl2_lat = c2_latency;
720 fadt->p_lvl3_lat = 87;
Patrick Rudolph78e8db12019-07-19 16:31:37 +0200721 /* flush_* is ignored if ACPI_FADT_WBINVD is set */
722 fadt->flush_size = 0;
723 fadt->flush_stride = 0;
Patrick Rudolphb30a47b2019-07-15 18:04:23 +0200724 /* P_CNT not supported */
725 fadt->duty_offset = 0;
726 fadt->duty_width = 0;
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200727 fadt->day_alrm = 0xd;
728 fadt->mon_alrm = 0x00;
729 fadt->century = 0x00;
730 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
731
732 fadt->flags = ACPI_FADT_WBINVD |
733 ACPI_FADT_C1_SUPPORTED |
734 ACPI_FADT_SLEEP_BUTTON |
735 ACPI_FADT_RESET_REGISTER |
736 ACPI_FADT_SEALED_CASE |
737 ACPI_FADT_S4_RTC_WAKE |
738 ACPI_FADT_PLATFORM_CLOCK;
739 if (chip->docking_supported) {
740 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
741 }
742 if (c2_latency < 100) {
743 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
744 }
745
746 fadt->reset_reg.space_id = 1;
747 fadt->reset_reg.bit_width = 8;
748 fadt->reset_reg.bit_offset = 0;
749 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
750 fadt->reset_reg.addrl = 0xcf9;
751 fadt->reset_reg.addrh = 0;
752
753 fadt->reset_value = 6;
754
755 fadt->x_pm1a_evt_blk.space_id = 1;
756 fadt->x_pm1a_evt_blk.bit_width = 32;
757 fadt->x_pm1a_evt_blk.bit_offset = 0;
758 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
759 fadt->x_pm1a_evt_blk.addrl = pmbase;
760 fadt->x_pm1a_evt_blk.addrh = 0x0;
761
762 fadt->x_pm1b_evt_blk.space_id = 1;
763 fadt->x_pm1b_evt_blk.bit_width = 0;
764 fadt->x_pm1b_evt_blk.bit_offset = 0;
765 fadt->x_pm1b_evt_blk.access_size = 0;
766 fadt->x_pm1b_evt_blk.addrl = 0x0;
767 fadt->x_pm1b_evt_blk.addrh = 0x0;
768
769 fadt->x_pm1a_cnt_blk.space_id = 1;
770 fadt->x_pm1a_cnt_blk.bit_width = 16;
771 fadt->x_pm1a_cnt_blk.bit_offset = 0;
772 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
773 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
774 fadt->x_pm1a_cnt_blk.addrh = 0x0;
775
776 fadt->x_pm1b_cnt_blk.space_id = 1;
777 fadt->x_pm1b_cnt_blk.bit_width = 0;
778 fadt->x_pm1b_cnt_blk.bit_offset = 0;
779 fadt->x_pm1b_cnt_blk.access_size = 0;
780 fadt->x_pm1b_cnt_blk.addrl = 0x0;
781 fadt->x_pm1b_cnt_blk.addrh = 0x0;
782
783 fadt->x_pm2_cnt_blk.space_id = 1;
784 fadt->x_pm2_cnt_blk.bit_width = 8;
785 fadt->x_pm2_cnt_blk.bit_offset = 0;
786 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
787 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
788 fadt->x_pm2_cnt_blk.addrh = 0x0;
789
790 fadt->x_pm_tmr_blk.space_id = 1;
791 fadt->x_pm_tmr_blk.bit_width = 32;
792 fadt->x_pm_tmr_blk.bit_offset = 0;
793 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
794 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
795 fadt->x_pm_tmr_blk.addrh = 0x0;
796
797 fadt->x_gpe0_blk.space_id = 1;
798 fadt->x_gpe0_blk.bit_width = 128;
799 fadt->x_gpe0_blk.bit_offset = 0;
800 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
801 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
802 fadt->x_gpe0_blk.addrh = 0x0;
803
804 fadt->x_gpe1_blk.space_id = 1;
805 fadt->x_gpe1_blk.bit_width = 0;
806 fadt->x_gpe1_blk.bit_offset = 0;
807 fadt->x_gpe1_blk.access_size = 0;
808 fadt->x_gpe1_blk.addrl = 0x0;
809 fadt->x_gpe1_blk.addrh = 0x0;
810}
811
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600812static const char *lpc_acpi_name(const struct device *dev)
Patrick Rudolph604f6982017-06-07 09:46:52 +0200813{
814 return "LPCB";
815}
816
Furquan Shaikh7536a392020-04-24 21:59:21 -0700817static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100818{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300819 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100820 config_t *chip = dev->chip_info;
821
822 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Tobias Diedrich7f5efd92017-12-14 00:29:01 +0100823 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100824}
825
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200826static void lpc_final(struct device *dev)
827{
Arthur Heymansebf201b2019-05-28 13:51:36 +0200828 spi_finalize_ops();
Nico Huber8e50b6d2018-02-04 15:52:18 +0100829
Bill XIEd533b162017-08-22 16:26:22 +0800830 /* Call SMM finalize() handlers before resume */
Julius Wernercd49cce2019-03-05 16:53:33 -0800831 if (CONFIG(HAVE_SMI_HANDLER)) {
832 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
Bill XIEd533b162017-08-22 16:26:22 +0800833 acpi_is_wakeup_s3()) {
834 outb(APM_CNT_FINALIZE, APM_CNT);
835 }
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200836 }
837}
838
Arthur Heymansebf201b2019-05-28 13:51:36 +0200839void intel_southbridge_override_spi(
840 struct intel_swseq_spi_config *spi_config)
841{
842 struct device *dev = pcidev_on_root(0x1f, 0);
843
844 if (!dev)
845 return;
846 /* Devicetree may override defaults. */
847 const config_t *const config = dev->chip_info;
848
849 if (!config)
850 return;
851
852 if (config->spi.ops[0].op != 0)
853 memcpy(spi_config, &config->spi, sizeof(*spi_config));
854}
855
Stefan Reinauer8e073822012-04-04 00:07:22 +0200856static struct device_operations device_ops = {
857 .read_resources = pch_lpc_read_resources,
858 .set_resources = pci_dev_set_resources,
Arthur Heymans3cde4942019-08-18 10:02:10 +0200859 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200860 .write_acpi_tables = acpi_write_hpet,
Nico Huber68680dd2020-03-31 17:34:52 +0200861 .acpi_inject_dsdt = southbridge_inject_dsdt,
862 .acpi_fill_ssdt = southbridge_fill_ssdt,
Patrick Rudolph604f6982017-06-07 09:46:52 +0200863 .acpi_name = lpc_acpi_name,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200864 .init = lpc_init,
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200865 .final = lpc_final,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200866 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100867 .scan_bus = scan_static_bus,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200868 .ops_pci = &pci_dev_ops_pci,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200869};
870
871
Kimarie Hoote6f459c2012-07-14 08:26:08 -0600872/* IDs for LPC device of Intel 6 Series Chipset, Intel 7 Series Chipset, and
873 * Intel C200 Series Chipset
Stefan Reinauer8e073822012-04-04 00:07:22 +0200874 */
875
Vladimir Serbinenko42d55e02016-01-02 01:47:26 +0100876static const unsigned short pci_device_ids[] = {
877 0x1c40, 0x1c41, 0x1c42, 0x1c43, 0x1c44, 0x1c45, 0x1c46, 0x1c47, 0x1c48,
878 0x1c49, 0x1c4a, 0x1c4b, 0x1c4c, 0x1c4d, 0x1c4e, 0x1c4f, 0x1c50, 0x1c51,
879 0x1c52, 0x1c53, 0x1c54, 0x1c55, 0x1c56, 0x1c57, 0x1c58, 0x1c59, 0x1c5a,
880 0x1c5b, 0x1c5c, 0x1c5d, 0x1c5e, 0x1c5f,
881
882 0x1e41, 0x1e42, 0x1e43, 0x1e44, 0x1e45, 0x1e46, 0x1e47, 0x1e48, 0x1e49,
883 0x1e4a, 0x1e4b, 0x1e4c, 0x1e4d, 0x1e4e, 0x1e4f, 0x1e50, 0x1e51, 0x1e52,
884 0x1e53, 0x1e54, 0x1e55, 0x1e56, 0x1e57, 0x1e58, 0x1e59, 0x1e5a, 0x1e5b,
885 0x1e5c, 0x1e5d, 0x1e5e, 0x1e5f,
886
887 0 };
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700888
889static const struct pci_driver pch_lpc __pci_driver = {
890 .ops = &device_ops,
891 .vendor = PCI_VENDOR_ID_INTEL,
892 .devices = pci_device_ids,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200893};