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