blob: 1f921936d91b703496996dd08231ea2421044fff [file] [log] [blame]
Stefan Reinauer8e073822012-04-04 00:07:22 +02001/*
2 * This file is part of the coreboot project.
3 *
Stefan Reinauer8e073822012-04-04 00:07:22 +02004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; version 2 of
8 * the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Stefan Reinauer8e073822012-04-04 00:07:22 +020014 */
15
16#include <console/console.h>
17#include <device/device.h>
18#include <device/pci.h>
19#include <device/pci_ids.h>
Patrick Rudolphe56189c2018-04-18 10:11:59 +020020#include <device/pci_ops.h>
Patrick Rudolphef8c5592018-07-27 17:48:27 +020021#include <device/pci_def.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020022#include <option.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020023#include <pc80/isa-dma.h>
24#include <pc80/i8259.h>
25#include <arch/io.h>
26#include <arch/ioapic.h>
27#include <arch/acpi.h>
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020028#include <arch/acpigen.h>
29#include <drivers/intel/gma/i915.h>
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +020030#include <cpu/x86/smm.h>
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020031#include <cbmem.h>
Vladimir Serbinenko7309c642014-10-05 11:07:33 +020032#include <string.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030033#include "chip.h"
Stefan Reinauer8e073822012-04-04 00:07:22 +020034#include "pch.h"
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020035#include "nvs.h"
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010036#include <southbridge/intel/common/pciehp.h>
Tobias Diedrich7f5efd92017-12-14 00:29:01 +010037#include <southbridge/intel/common/acpi_pirq_gen.h>
Arthur Heymansa0508172018-01-25 11:30:22 +010038#include <southbridge/intel/common/pmutil.h>
Patrick Rudolph6b931122018-11-01 17:48:37 +010039#include <southbridge/intel/common/rtc.h>
Arthur Heymansebf201b2019-05-28 13:51:36 +020040#include <southbridge/intel/common/spi.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020041
42#define NMI_OFF 0
43
Stefan Reinauer8e073822012-04-04 00:07:22 +020044typedef struct southbridge_intel_bd82x6x_config config_t;
45
Paul Menzel9c50e6a2013-05-03 12:23:39 +020046/**
47 * Set miscellanous static southbridge features.
48 *
49 * @param dev PCI device with I/O APIC control registers
50 */
51static void pch_enable_ioapic(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020052{
Stefan Reinauer8e073822012-04-04 00:07:22 +020053 u32 reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +020054
Nico Huberb2dae792015-10-26 12:34:02 +010055 /* Assign unique bus/dev/fn for I/O APIC */
56 pci_write_config16(dev, LPC_IBDF,
57 PCH_IOAPIC_PCI_BUS << 8 | PCH_IOAPIC_PCI_SLOT << 3);
58
Paul Menzel9c50e6a2013-05-03 12:23:39 +020059 /* Enable ACPI I/O range decode */
60 pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
Stefan Reinauer8e073822012-04-04 00:07:22 +020061
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080062 set_ioapic_id(VIO_APIC_VADDR, 0x02);
Stefan Reinauer8e073822012-04-04 00:07:22 +020063
64 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080065 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
66 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +020067
Paul Menzel9c50e6a2013-05-03 12:23:39 +020068 /*
69 * Select Boot Configuration register (0x03) and
70 * use Processor System Bus (0x01) to deliver interrupts.
71 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080072 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Stefan Reinauer8e073822012-04-04 00:07:22 +020073}
74
75static void pch_enable_serial_irqs(struct device *dev)
76{
77 /* Set packet length and toggle silent mode bit for one frame. */
78 pci_write_config8(dev, SERIRQ_CNTL,
79 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080080#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Stefan Reinauer8e073822012-04-04 00:07:22 +020081 pci_write_config8(dev, SERIRQ_CNTL,
82 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
83#endif
84}
85
86/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
87 * 0x00 - 0000 = Reserved
88 * 0x01 - 0001 = Reserved
89 * 0x02 - 0010 = Reserved
90 * 0x03 - 0011 = IRQ3
91 * 0x04 - 0100 = IRQ4
92 * 0x05 - 0101 = IRQ5
93 * 0x06 - 0110 = IRQ6
94 * 0x07 - 0111 = IRQ7
95 * 0x08 - 1000 = Reserved
96 * 0x09 - 1001 = IRQ9
97 * 0x0A - 1010 = IRQ10
98 * 0x0B - 1011 = IRQ11
99 * 0x0C - 1100 = IRQ12
100 * 0x0D - 1101 = Reserved
101 * 0x0E - 1110 = IRQ14
102 * 0x0F - 1111 = IRQ15
103 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
104 * 0x80 - The PIRQ is not routed.
105 */
106
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200107static void pch_pirq_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200108{
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200109 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200110 /* Interrupt 11 is not used by legacy devices and so can always be used for
111 PCI interrupts. Full legacy IRQ routing is complicated and hard to
112 get right. Fortunately all modern OS use MSI and so it's not that big of
113 an issue anyway. Still we have to provide a reasonable default. Using
114 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
115 move it to any interrupt and others will just leave them at default.
Stefan Reinauer8e073822012-04-04 00:07:22 +0200116 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200117 const u8 pirq_routing = 11;
118
119 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
120 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
121 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
122 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
123
124 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
125 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
126 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
127 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200128
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200129 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200130 u8 int_pin=0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200131
132 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
133 continue;
134
135 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
136
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200137 if (int_pin == 0)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200138 continue;
139
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200140 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200141 }
142}
143
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200144static void pch_gpi_routing(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200145{
146 /* Get the chip configuration */
147 config_t *config = dev->chip_info;
148 u32 reg32 = 0;
149
150 /* An array would be much nicer here, or some
151 * other method of doing this.
152 */
153 reg32 |= (config->gpi0_routing & 0x03) << 0;
154 reg32 |= (config->gpi1_routing & 0x03) << 2;
155 reg32 |= (config->gpi2_routing & 0x03) << 4;
156 reg32 |= (config->gpi3_routing & 0x03) << 6;
157 reg32 |= (config->gpi4_routing & 0x03) << 8;
158 reg32 |= (config->gpi5_routing & 0x03) << 10;
159 reg32 |= (config->gpi6_routing & 0x03) << 12;
160 reg32 |= (config->gpi7_routing & 0x03) << 14;
161 reg32 |= (config->gpi8_routing & 0x03) << 16;
162 reg32 |= (config->gpi9_routing & 0x03) << 18;
163 reg32 |= (config->gpi10_routing & 0x03) << 20;
164 reg32 |= (config->gpi11_routing & 0x03) << 22;
165 reg32 |= (config->gpi12_routing & 0x03) << 24;
166 reg32 |= (config->gpi13_routing & 0x03) << 26;
167 reg32 |= (config->gpi14_routing & 0x03) << 28;
168 reg32 |= (config->gpi15_routing & 0x03) << 30;
169
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200170 pci_write_config32(dev, GPIO_ROUT, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200171}
172
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200173static void pch_power_options(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200174{
175 u8 reg8;
176 u16 reg16, pmbase;
177 u32 reg32;
178 const char *state;
179 /* Get the chip configuration */
180 config_t *config = dev->chip_info;
181
Nico Huber9faae2b2018-11-14 00:00:35 +0100182 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200183 int nmi_option;
184
185 /* Which state do we want to goto after g3 (power restored)?
186 * 0 == S0 Full On
187 * 1 == S5 Soft Off
188 *
189 * If the option is not existent (Laptops), use Kconfig setting.
190 */
191 get_option(&pwr_on, "power_on_after_fail");
192
193 reg16 = pci_read_config16(dev, GEN_PMCON_3);
194 reg16 &= 0xfffe;
195 switch (pwr_on) {
196 case MAINBOARD_POWER_OFF:
197 reg16 |= 1;
198 state = "off";
199 break;
200 case MAINBOARD_POWER_ON:
201 reg16 &= ~1;
202 state = "on";
203 break;
204 case MAINBOARD_POWER_KEEP:
205 reg16 &= ~1;
206 state = "state keep";
207 break;
208 default:
209 state = "undefined";
210 }
211
212 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
213 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
214
215 reg16 &= ~(1 << 10);
216 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
217
218 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
219
220 pci_write_config16(dev, GEN_PMCON_3, reg16);
221 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
222
223 /* Set up NMI on errors. */
224 reg8 = inb(0x61);
225 reg8 &= 0x0f; /* Higher Nibble must be 0 */
226 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
227 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
228 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
229 outb(reg8, 0x61);
230
231 reg8 = inb(0x70);
232 nmi_option = NMI_OFF;
233 get_option(&nmi_option, "nmi");
234 if (nmi_option) {
235 printk(BIOS_INFO, "NMI sources enabled.\n");
236 reg8 &= ~(1 << 7); /* Set NMI. */
237 } else {
238 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200239 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200240 }
241 outb(reg8, 0x70);
242
243 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
244 reg16 = pci_read_config16(dev, GEN_PMCON_1);
245 reg16 &= ~(3 << 0); // SMI# rate 1 minute
246 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
247#if DEBUG_PERIODIC_SMIS
248 /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
249 * periodic SMIs.
250 */
251 reg16 |= (3 << 0); // Periodic SMI every 8s
252#endif
253 pci_write_config16(dev, GEN_PMCON_1, reg16);
254
255 // Set the board's GPI routing.
256 pch_gpi_routing(dev);
257
258 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
259
260 outl(config->gpe0_en, pmbase + GPE0_EN);
261 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
262
263 /* Set up power management block and determine sleep mode */
264 reg32 = inl(pmbase + 0x04); // PM1_CNT
265 reg32 &= ~(7 << 10); // SLP_TYP
266 reg32 |= (1 << 0); // SCI_EN
267 outl(reg32, pmbase + 0x04);
268
269 /* Clear magic status bits to prevent unexpected wake */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200270 reg32 = RCBA32(PRSTS);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200271 reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200272 RCBA32(PRSTS) = reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200273
274 reg32 = RCBA32(0x3f02);
275 reg32 &= ~0xf;
276 RCBA32(0x3f02) = reg32;
277}
278
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700279/* CougarPoint PCH Power Management init */
280static void cpt_pm_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200281{
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700282 printk(BIOS_DEBUG, "CougarPoint PM init\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200283 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200284 RCBA32_AND_OR(CIR30, ~0UL, (1 << 6)|(1 << 0));
285 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
286 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
287 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
288 RCBA32(DMC) = 0xc0388400;
289 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
290 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
291 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
292 RCBA32(PM_CFG) = 0x050f0000;
293 RCBA32(CIR8) = 0x04000000;
294 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
295 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1));
296 RCBA32(CIR12) = 0x0001c000;
297 RCBA32(CIR14) = 0x00061100;
298 RCBA32(CIR15) = 0x7f8fdfff;
299 RCBA32(CIR13) = 0x000003fc;
300 RCBA32(CIR16) = 0x00001000;
301 RCBA32(CIR18) = 0x0001c000;
302 RCBA32(CIR17) = 0x00000800;
303 RCBA32(CIR23) = 0x00001000;
304 RCBA32(CIR19) = 0x00093900;
305 RCBA32(CIR20) = 0x24653002;
306 RCBA32(CIR21) = 0x062108fe;
307 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
308 RCBA32(CIR24) = 0x01010000;
309 RCBA32(CIR25) = 0x01010404;
310 RCBA32(CIR27) = 0x01041041;
311 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
312 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
313 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
314 RCBA32(CIR26) = 0x00000001;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200315 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
316 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200317 RCBA32(PMSYNC_CFG) = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200318 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
319}
320
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700321/* PantherPoint PCH Power Management init */
322static void ppt_pm_init(struct device *dev)
323{
324 printk(BIOS_DEBUG, "PantherPoint PM init\n");
325 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200326 RCBA32_AND_OR(CIR30, ~0UL, (1 << 0));
327 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
328 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
329 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
330 RCBA32(DMC) = 0xc03b8400;
331 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
332 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
333 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
334 RCBA32(PM_CFG) = 0x054f0000;
335 RCBA32(CIR8) = 0x04000000;
336 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
337 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1)|(1 << 0));
338 RCBA32(CIR12) = 0x0001c000;
339 RCBA32(CIR14) = 0x00061100;
340 RCBA32(CIR15) = 0x7f8fdfff;
341 RCBA32(CIR13) = 0x000003fd;
342 RCBA32(CIR16) = 0x00001000;
343 RCBA32(CIR18) = 0x0001c000;
344 RCBA32(CIR17) = 0x00000800;
345 RCBA32(CIR23) = 0x00001000;
346 RCBA32(CIR19) = 0x00093900;
347 RCBA32(CIR20) = 0x24653002;
348 RCBA32(CIR21) = 0x067388fe;
349 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
350 RCBA32(CIR24) = 0x01010000;
351 RCBA32(CIR25) = 0x01010404;
352 RCBA32(CIR27) = 0x01040000;
353 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
354 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
355 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
356 RCBA32(CIR26) = 0x00000001;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700357 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
358 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
359 RCBA32_AND_OR(0x33a4, ~0UL, (1 << 0));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200360 RCBA32(PMSYNC_CFG) = 0;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700361 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
362}
363
Nico Huberb2dae792015-10-26 12:34:02 +0100364static void enable_hpet(struct device *const dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200365{
366 u32 reg32;
Nico Huberb2dae792015-10-26 12:34:02 +0100367 size_t i;
368
369 /* Assign unique bus/dev/fn for each HPET */
370 for (i = 0; i < 8; ++i)
371 pci_write_config16(dev, LPC_HnBDF(i),
372 PCH_HPET_PCI_BUS << 8 | PCH_HPET_PCI_SLOT << 3 | i);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200373
374 /* Move HPET to default address 0xfed00000 and enable it */
375 reg32 = RCBA32(HPTC);
376 reg32 |= (1 << 7); // HPET Address Enable
377 reg32 &= ~(3 << 0);
378 RCBA32(HPTC) = reg32;
379}
380
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200381static void enable_clock_gating(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200382{
383 u32 reg32;
384 u16 reg16;
385
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200386 RCBA32_AND_OR(DMIC, ~0UL, 0xf);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200387
388 reg16 = pci_read_config16(dev, GEN_PMCON_1);
389 reg16 |= (1 << 2) | (1 << 11);
390 pci_write_config16(dev, GEN_PMCON_1, reg16);
391
392 pch_iobp_update(0xEB007F07, ~0UL, (1 << 31));
393 pch_iobp_update(0xEB004000, ~0UL, (1 << 7));
394 pch_iobp_update(0xEC007F07, ~0UL, (1 << 31));
395 pch_iobp_update(0xEC004000, ~0UL, (1 << 7));
396
397 reg32 = RCBA32(CG);
398 reg32 |= (1 << 31);
399 reg32 |= (1 << 29) | (1 << 28);
400 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
401 reg32 |= (1 << 16);
402 reg32 |= (1 << 17);
403 reg32 |= (1 << 18);
404 reg32 |= (1 << 22);
405 reg32 |= (1 << 23);
406 reg32 &= ~(1 << 20);
407 reg32 |= (1 << 19);
408 reg32 |= (1 << 0);
409 reg32 |= (0xf << 1);
410 RCBA32(CG) = reg32;
411
412 RCBA32_OR(0x38c0, 0x7);
413 RCBA32_OR(0x36d4, 0x6680c004);
414 RCBA32_OR(0x3564, 0x3);
415}
416
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200417static void pch_set_acpi_mode(void)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200418{
Julius Werner5d1f9a02019-03-07 17:07:26 -0800419 if (!acpi_is_wakeup_s3() && CONFIG(HAVE_SMI_HANDLER)) {
Duncan Laurie95be1d62012-04-09 12:31:43 -0700420 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200421 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
Duncan Laurie95be1d62012-04-09 12:31:43 -0700422 printk(BIOS_DEBUG, "done.\n");
Duncan Laurie95be1d62012-04-09 12:31:43 -0700423 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200424}
Stefan Reinauer8e073822012-04-04 00:07:22 +0200425
426static void pch_disable_smm_only_flashing(struct device *dev)
427{
428 u8 reg8;
429
430 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100431 reg8 = pci_read_config8(dev, BIOS_CNTL);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200432 reg8 &= ~(1 << 5);
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100433 pci_write_config8(dev, BIOS_CNTL, reg8);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200434}
435
436static void pch_fixups(struct device *dev)
437{
438 u8 gen_pmcon_2;
439
440 /* Indicate DRAM init done for MRC S3 to know it can resume */
441 gen_pmcon_2 = pci_read_config8(dev, GEN_PMCON_2);
442 gen_pmcon_2 |= (1 << 7);
443 pci_write_config8(dev, GEN_PMCON_2, gen_pmcon_2);
444
445 /*
446 * Enable DMI ASPM in the PCH
447 */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200448 RCBA32_AND_OR(DMC, ~(1 << 10), 0);
449 RCBA32_OR(LCAP, (1 << 11)|(1 << 10));
450 RCBA32_OR(LCTL, 0x3);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200451}
452
Nico Huber7b2f9f62015-10-01 19:00:51 +0200453static void pch_spi_init(const struct device *const dev)
454{
455 const config_t *const config = dev->chip_info;
456
457 printk(BIOS_DEBUG, "pch_spi_init\n");
458
459 if (config->spi_uvscc)
460 RCBA32(0x3800 + 0xc8) = config->spi_uvscc;
461 if (config->spi_lvscc)
462 RCBA32(0x3800 + 0xc4) = config->spi_lvscc;
463
464 if (config->spi_uvscc || config->spi_lvscc)
465 RCBA32_OR(0x3800 + 0xc4, 1 << 23); /* lock both UVSCC + LVSCC */
466}
467
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200468static const struct {
469 u16 dev_id;
470 const char *dev_name;
471} pch_table[] = {
472 /* 6-series PCI ids from
473 * Intel® 6 Series Chipset and
474 * Intel® C200 Series Chipset
475 * Specification Update - NDA
476 * October 2013
477 * CDI / IBP#: 440377
478 */
479 {0x1C41, "SFF Sample"},
480 {0x1C42, "Desktop Sample"},
481 {0x1C43, "Mobile Sample"},
482 {0x1C44, "Z68"},
483 {0x1C46, "P67"},
484 {0x1C47, "UM67"},
485 {0x1C49, "HM65"},
486 {0x1C4A, "H67"},
487 {0x1C4B, "HM67"},
488 {0x1C4C, "Q65"},
489 {0x1C4D, "QS67"},
490 {0x1C4E, "Q67"},
491 {0x1C4F, "QM67"},
492 {0x1C50, "B65"},
493 {0x1C52, "C202"},
494 {0x1C54, "C204"},
495 {0x1C56, "C206"},
496 {0x1C5C, "H61"},
497 /* 7-series PCI ids from Intel document 472178 */
498 {0x1E41, "Desktop Sample"},
499 {0x1E42, "Mobile Sample"},
500 {0x1E43, "SFF Sample"},
501 {0x1E44, "Z77"},
502 {0x1E45, "H71"},
503 {0x1E46, "Z75"},
504 {0x1E47, "Q77"},
505 {0x1E48, "Q75"},
506 {0x1E49, "B75"},
507 {0x1E4A, "H77"},
508 {0x1E53, "C216"},
509 {0x1E55, "QM77"},
510 {0x1E56, "QS77"},
511 {0x1E58, "UM77"},
512 {0x1E57, "HM77"},
513 {0x1E59, "HM76"},
514 {0x1E5D, "HM75"},
515 {0x1E5E, "HM70"},
516 {0x1E5F, "NM70"},
517};
518
519static void report_pch_info(struct device *dev)
520{
521 const u16 dev_id = pci_read_config16(dev, PCI_DEVICE_ID);
522 int i;
523
524 const char *pch_type = "Unknown";
525 for (i = 0; i < ARRAY_SIZE(pch_table); i++) {
526 if (pch_table[i].dev_id == dev_id) {
527 pch_type = pch_table[i].dev_name;
528 break;
529 }
530 }
531 printk(BIOS_INFO, "PCH: detected %s, device id: 0x%x, rev id 0x%x\n",
532 pch_type, dev_id, pci_read_config8(dev, PCI_CLASS_REVISION));
533}
534
Stefan Reinauer8e073822012-04-04 00:07:22 +0200535static void lpc_init(struct device *dev)
536{
537 printk(BIOS_DEBUG, "pch: lpc_init\n");
538
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200539 /* Print detected platform */
540 report_pch_info(dev);
541
Stefan Reinauer8e073822012-04-04 00:07:22 +0200542 /* Set the value for PCI command register. */
543 pci_write_config16(dev, PCI_COMMAND, 0x000f);
544
545 /* IO APIC initialization. */
Paul Menzel9c50e6a2013-05-03 12:23:39 +0200546 pch_enable_ioapic(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200547
548 pch_enable_serial_irqs(dev);
549
550 /* Setup the PIRQ. */
551 pch_pirq_init(dev);
552
553 /* Setup power options. */
554 pch_power_options(dev);
555
556 /* Initialize power management */
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700557 switch (pch_silicon_type()) {
558 case PCH_TYPE_CPT: /* CougarPoint */
559 cpt_pm_init(dev);
560 break;
561 case PCH_TYPE_PPT: /* PantherPoint */
562 ppt_pm_init(dev);
563 break;
564 default:
565 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
566 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200567
568 /* Set the state of the GPIO lines. */
569 //gpio_init(dev);
570
571 /* Initialize the real time clock. */
Patrick Rudolph6b931122018-11-01 17:48:37 +0100572 sb_rtc_init();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200573
574 /* Initialize ISA DMA. */
575 isa_dma_init();
576
577 /* Initialize the High Precision Event Timers, if present. */
Nico Huberb2dae792015-10-26 12:34:02 +0100578 enable_hpet(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200579
580 /* Initialize Clock Gating */
581 enable_clock_gating(dev);
582
583 setup_i8259();
584
585 /* The OS should do this? */
586 /* Interrupt 9 should be level triggered (SCI) */
587 i8259_configure_irq_trigger(9, 1);
588
589 pch_disable_smm_only_flashing(dev);
590
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200591 pch_set_acpi_mode();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200592
593 pch_fixups(dev);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200594
595 pch_spi_init(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200596}
597
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200598static void pch_lpc_read_resources(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200599{
600 struct resource *res;
Marc Jonesa0bec172012-07-13 14:14:34 -0600601 config_t *config = dev->chip_info;
602 u8 io_index = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200603
604 /* Get the normal PCI resources of this device. */
605 pci_dev_read_resources(dev);
606
607 /* Add an extra subtractive resource for both memory and I/O. */
Marc Jonesa0bec172012-07-13 14:14:34 -0600608 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200609 res->base = 0;
610 res->size = 0x1000;
611 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
612 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
613
Marc Jonesa0bec172012-07-13 14:14:34 -0600614 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Vladimir Serbinenko0650cd02014-02-05 15:03:50 +0100615 res->base = 0xff000000;
616 /* Some systems (e.g. X230) have 12 MiB flash.
617 SPI controller supports up to 2 x 16 MiB of flash but
618 address map limits this to 16MiB. */
619 res->size = 0x01000000; /* 16 MB for flash */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200620 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
621 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
622
623 res = new_resource(dev, 3); /* IOAPIC */
624 res->base = IO_APIC_ADDR;
625 res->size = 0x00001000;
626 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Marc Jonesa0bec172012-07-13 14:14:34 -0600627
628 /* Set PCH IO decode ranges if required.*/
629 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
630 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
631 res->base = config->gen1_dec & 0xFFFC;
632 res->size = (config->gen1_dec >> 16) & 0xFC;
633 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
634 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
635 }
636
637 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
638 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
639 res->base = config->gen2_dec & 0xFFFC;
640 res->size = (config->gen2_dec >> 16) & 0xFC;
641 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
642 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
643 }
644
645 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
646 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
647 res->base = config->gen3_dec & 0xFFFC;
648 res->size = (config->gen3_dec >> 16) & 0xFC;
649 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
650 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
651 }
652
653 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
654 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
655 res->base = config->gen4_dec & 0xFFFC;
656 res->size = (config->gen4_dec >> 16) & 0xFC;
657 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
658 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
659 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200660}
661
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200662static void pch_lpc_enable(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200663{
664 /* Enable PCH Display Port */
665 RCBA16(DISPBDF) = 0x0010;
666 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
667
668 pch_enable(dev);
669}
670
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200671static void southbridge_inject_dsdt(struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200672{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200673 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200674
675 if (gnvs) {
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100676 const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
Elyes HAOUAS035df002016-10-03 21:54:16 +0200677 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200678
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200679 acpi_create_gnvs(gnvs);
Vladimir Serbinenko06c788d2014-10-12 00:17:11 +0200680
681 gnvs->apic = 1;
682 gnvs->mpen = 1; /* Enable Multi Processing */
683 gnvs->pcnt = dev_count_cpu();
684
Nico Huber744d6bd2019-01-12 14:58:20 +0100685 if (gfx) {
686 gnvs->ndid = gfx->ndid;
687 memcpy(gnvs->did, gfx->did, sizeof(gnvs->did));
688 }
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100689
Julius Wernercd49cce2019-03-05 16:53:33 -0800690#if CONFIG(CHROMEOS)
Joel Kitching6fbd8742018-08-23 14:56:25 +0800691 chromeos_init_chromeos_acpi(&(gnvs->chromeos));
Vladimir Serbinenko06c788d2014-10-12 00:17:11 +0200692#endif
693
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200694 /* And tell SMI about it */
695 smm_setup_structures(gnvs, NULL, NULL);
696
Vladimir Serbinenko334fd8e2014-10-05 11:10:35 +0200697 /* Add it to DSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100698 acpigen_write_scope("\\");
699 acpigen_write_name_dword("NVSA", (u32) gnvs);
700 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200701 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200702}
703
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200704void acpi_fill_fadt(acpi_fadt_t *fadt)
705{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300706 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200707 config_t *chip = dev->chip_info;
708 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
709 int c2_latency;
710
Elyes HAOUAS0d4de2a2019-02-28 13:04:29 +0100711 fadt->reserved = 0;
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200712
713 fadt->sci_int = 0x9;
714 fadt->smi_cmd = APM_CNT;
715 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
716 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
717 fadt->s4bios_req = 0x0;
718 fadt->pstate_cnt = 0;
719
720 fadt->pm1a_evt_blk = pmbase;
721 fadt->pm1b_evt_blk = 0x0;
722 fadt->pm1a_cnt_blk = pmbase + 0x4;
723 fadt->pm1b_cnt_blk = 0x0;
724 fadt->pm2_cnt_blk = pmbase + 0x50;
725 fadt->pm_tmr_blk = pmbase + 0x8;
726 fadt->gpe0_blk = pmbase + 0x20;
727 fadt->gpe1_blk = 0;
728
729 fadt->pm1_evt_len = 4;
730 fadt->pm1_cnt_len = 2;
731 fadt->pm2_cnt_len = 1;
732 fadt->pm_tmr_len = 4;
733 fadt->gpe0_blk_len = 16;
734 fadt->gpe1_blk_len = 0;
735 fadt->gpe1_base = 0;
736 fadt->cst_cnt = 0;
737 c2_latency = chip->c2_latency;
738 if (!c2_latency) {
739 c2_latency = 101; /* c2 unsupported */
740 }
741 fadt->p_lvl2_lat = c2_latency;
742 fadt->p_lvl3_lat = 87;
743 fadt->flush_size = 1024;
744 fadt->flush_stride = 16;
Patrick Rudolphb30a47b2019-07-15 18:04:23 +0200745 /* P_CNT not supported */
746 fadt->duty_offset = 0;
747 fadt->duty_width = 0;
748
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200749 fadt->day_alrm = 0xd;
750 fadt->mon_alrm = 0x00;
751 fadt->century = 0x00;
752 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
753
754 fadt->flags = ACPI_FADT_WBINVD |
755 ACPI_FADT_C1_SUPPORTED |
756 ACPI_FADT_SLEEP_BUTTON |
757 ACPI_FADT_RESET_REGISTER |
758 ACPI_FADT_SEALED_CASE |
759 ACPI_FADT_S4_RTC_WAKE |
760 ACPI_FADT_PLATFORM_CLOCK;
761 if (chip->docking_supported) {
762 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
763 }
764 if (c2_latency < 100) {
765 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
766 }
767
768 fadt->reset_reg.space_id = 1;
769 fadt->reset_reg.bit_width = 8;
770 fadt->reset_reg.bit_offset = 0;
771 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
772 fadt->reset_reg.addrl = 0xcf9;
773 fadt->reset_reg.addrh = 0;
774
775 fadt->reset_value = 6;
776
777 fadt->x_pm1a_evt_blk.space_id = 1;
778 fadt->x_pm1a_evt_blk.bit_width = 32;
779 fadt->x_pm1a_evt_blk.bit_offset = 0;
780 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
781 fadt->x_pm1a_evt_blk.addrl = pmbase;
782 fadt->x_pm1a_evt_blk.addrh = 0x0;
783
784 fadt->x_pm1b_evt_blk.space_id = 1;
785 fadt->x_pm1b_evt_blk.bit_width = 0;
786 fadt->x_pm1b_evt_blk.bit_offset = 0;
787 fadt->x_pm1b_evt_blk.access_size = 0;
788 fadt->x_pm1b_evt_blk.addrl = 0x0;
789 fadt->x_pm1b_evt_blk.addrh = 0x0;
790
791 fadt->x_pm1a_cnt_blk.space_id = 1;
792 fadt->x_pm1a_cnt_blk.bit_width = 16;
793 fadt->x_pm1a_cnt_blk.bit_offset = 0;
794 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
795 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
796 fadt->x_pm1a_cnt_blk.addrh = 0x0;
797
798 fadt->x_pm1b_cnt_blk.space_id = 1;
799 fadt->x_pm1b_cnt_blk.bit_width = 0;
800 fadt->x_pm1b_cnt_blk.bit_offset = 0;
801 fadt->x_pm1b_cnt_blk.access_size = 0;
802 fadt->x_pm1b_cnt_blk.addrl = 0x0;
803 fadt->x_pm1b_cnt_blk.addrh = 0x0;
804
805 fadt->x_pm2_cnt_blk.space_id = 1;
806 fadt->x_pm2_cnt_blk.bit_width = 8;
807 fadt->x_pm2_cnt_blk.bit_offset = 0;
808 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
809 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
810 fadt->x_pm2_cnt_blk.addrh = 0x0;
811
812 fadt->x_pm_tmr_blk.space_id = 1;
813 fadt->x_pm_tmr_blk.bit_width = 32;
814 fadt->x_pm_tmr_blk.bit_offset = 0;
815 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
816 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
817 fadt->x_pm_tmr_blk.addrh = 0x0;
818
819 fadt->x_gpe0_blk.space_id = 1;
820 fadt->x_gpe0_blk.bit_width = 128;
821 fadt->x_gpe0_blk.bit_offset = 0;
822 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
823 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
824 fadt->x_gpe0_blk.addrh = 0x0;
825
826 fadt->x_gpe1_blk.space_id = 1;
827 fadt->x_gpe1_blk.bit_width = 0;
828 fadt->x_gpe1_blk.bit_offset = 0;
829 fadt->x_gpe1_blk.access_size = 0;
830 fadt->x_gpe1_blk.addrl = 0x0;
831 fadt->x_gpe1_blk.addrh = 0x0;
832}
833
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600834static const char *lpc_acpi_name(const struct device *dev)
Patrick Rudolph604f6982017-06-07 09:46:52 +0200835{
836 return "LPCB";
837}
838
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200839static void southbridge_fill_ssdt(struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100840{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300841 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100842 config_t *chip = dev->chip_info;
843
844 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Tobias Diedrich7f5efd92017-12-14 00:29:01 +0100845 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100846}
847
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200848static void lpc_final(struct device *dev)
849{
Arthur Heymansebf201b2019-05-28 13:51:36 +0200850 spi_finalize_ops();
Nico Huber8e50b6d2018-02-04 15:52:18 +0100851
Bill XIEd533b162017-08-22 16:26:22 +0800852 /* Call SMM finalize() handlers before resume */
Julius Wernercd49cce2019-03-05 16:53:33 -0800853 if (CONFIG(HAVE_SMI_HANDLER)) {
854 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
Bill XIEd533b162017-08-22 16:26:22 +0800855 acpi_is_wakeup_s3()) {
856 outb(APM_CNT_FINALIZE, APM_CNT);
857 }
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200858 }
859}
860
Arthur Heymansebf201b2019-05-28 13:51:36 +0200861void intel_southbridge_override_spi(
862 struct intel_swseq_spi_config *spi_config)
863{
864 struct device *dev = pcidev_on_root(0x1f, 0);
865
866 if (!dev)
867 return;
868 /* Devicetree may override defaults. */
869 const config_t *const config = dev->chip_info;
870
871 if (!config)
872 return;
873
874 if (config->spi.ops[0].op != 0)
875 memcpy(spi_config, &config->spi, sizeof(*spi_config));
876}
877
Stefan Reinauer8e073822012-04-04 00:07:22 +0200878static struct pci_operations pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530879 .set_subsystem = pci_dev_set_subsystem,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200880};
881
882static struct device_operations device_ops = {
883 .read_resources = pch_lpc_read_resources,
884 .set_resources = pci_dev_set_resources,
Arthur Heymans3cde4942019-08-18 10:02:10 +0200885 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200886 .write_acpi_tables = acpi_write_hpet,
Nico Huber68680dd2020-03-31 17:34:52 +0200887 .acpi_inject_dsdt = southbridge_inject_dsdt,
888 .acpi_fill_ssdt = southbridge_fill_ssdt,
Patrick Rudolph604f6982017-06-07 09:46:52 +0200889 .acpi_name = lpc_acpi_name,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200890 .init = lpc_init,
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200891 .final = lpc_final,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200892 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100893 .scan_bus = scan_static_bus,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200894 .ops_pci = &pci_ops,
895};
896
897
Kimarie Hoote6f459c2012-07-14 08:26:08 -0600898/* IDs for LPC device of Intel 6 Series Chipset, Intel 7 Series Chipset, and
899 * Intel C200 Series Chipset
Stefan Reinauer8e073822012-04-04 00:07:22 +0200900 */
901
Vladimir Serbinenko42d55e02016-01-02 01:47:26 +0100902static const unsigned short pci_device_ids[] = {
903 0x1c40, 0x1c41, 0x1c42, 0x1c43, 0x1c44, 0x1c45, 0x1c46, 0x1c47, 0x1c48,
904 0x1c49, 0x1c4a, 0x1c4b, 0x1c4c, 0x1c4d, 0x1c4e, 0x1c4f, 0x1c50, 0x1c51,
905 0x1c52, 0x1c53, 0x1c54, 0x1c55, 0x1c56, 0x1c57, 0x1c58, 0x1c59, 0x1c5a,
906 0x1c5b, 0x1c5c, 0x1c5d, 0x1c5e, 0x1c5f,
907
908 0x1e41, 0x1e42, 0x1e43, 0x1e44, 0x1e45, 0x1e46, 0x1e47, 0x1e48, 0x1e49,
909 0x1e4a, 0x1e4b, 0x1e4c, 0x1e4d, 0x1e4e, 0x1e4f, 0x1e50, 0x1e51, 0x1e52,
910 0x1e53, 0x1e54, 0x1e55, 0x1e56, 0x1e57, 0x1e58, 0x1e59, 0x1e5a, 0x1e5b,
911 0x1e5c, 0x1e5d, 0x1e5e, 0x1e5f,
912
913 0 };
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700914
915static const struct pci_driver pch_lpc __pci_driver = {
916 .ops = &device_ops,
917 .vendor = PCI_VENDOR_ID_INTEL,
918 .devices = pci_device_ids,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200919};