blob: 5f0dd8c299de2cedb15f236b5600764a978b8006 [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>
Stefan Reinauer8e073822012-04-04 00:07:22 +020023#include <pc80/mc146818rtc.h>
24#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>
Elyes HAOUASd2b9ec12018-10-27 09:41:02 +020029#include <arch/cpu.h>
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020030#include <arch/acpigen.h>
31#include <drivers/intel/gma/i915.h>
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +020032#include <cpu/x86/smm.h>
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020033#include <cbmem.h>
Vladimir Serbinenko7309c642014-10-05 11:07:33 +020034#include <string.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030035#include "chip.h"
Stefan Reinauer8e073822012-04-04 00:07:22 +020036#include "pch.h"
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020037#include "nvs.h"
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010038#include <southbridge/intel/common/pciehp.h>
Tobias Diedrich7f5efd92017-12-14 00:29:01 +010039#include <southbridge/intel/common/acpi_pirq_gen.h>
Arthur Heymansa0508172018-01-25 11:30:22 +010040#include <southbridge/intel/common/pmutil.h>
Patrick Rudolph6b931122018-11-01 17:48:37 +010041#include <southbridge/intel/common/rtc.h>
Arthur Heymansebf201b2019-05-28 13:51:36 +020042#include <southbridge/intel/common/spi.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020043
44#define NMI_OFF 0
45
46#define ENABLE_ACPI_MODE_IN_COREBOOT 0
Stefan Reinauer8e073822012-04-04 00:07:22 +020047
48typedef struct southbridge_intel_bd82x6x_config config_t;
49
Paul Menzel9c50e6a2013-05-03 12:23:39 +020050/**
51 * Set miscellanous static southbridge features.
52 *
53 * @param dev PCI device with I/O APIC control registers
54 */
55static void pch_enable_ioapic(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020056{
Stefan Reinauer8e073822012-04-04 00:07:22 +020057 u32 reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +020058
Nico Huberb2dae792015-10-26 12:34:02 +010059 /* Assign unique bus/dev/fn for I/O APIC */
60 pci_write_config16(dev, LPC_IBDF,
61 PCH_IOAPIC_PCI_BUS << 8 | PCH_IOAPIC_PCI_SLOT << 3);
62
Paul Menzel9c50e6a2013-05-03 12:23:39 +020063 /* Enable ACPI I/O range decode */
64 pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
Stefan Reinauer8e073822012-04-04 00:07:22 +020065
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080066 set_ioapic_id(VIO_APIC_VADDR, 0x02);
Stefan Reinauer8e073822012-04-04 00:07:22 +020067
68 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080069 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
70 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +020071
Paul Menzel9c50e6a2013-05-03 12:23:39 +020072 /*
73 * Select Boot Configuration register (0x03) and
74 * use Processor System Bus (0x01) to deliver interrupts.
75 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080076 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Stefan Reinauer8e073822012-04-04 00:07:22 +020077}
78
79static void pch_enable_serial_irqs(struct device *dev)
80{
81 /* Set packet length and toggle silent mode bit for one frame. */
82 pci_write_config8(dev, SERIRQ_CNTL,
83 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080084#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Stefan Reinauer8e073822012-04-04 00:07:22 +020085 pci_write_config8(dev, SERIRQ_CNTL,
86 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
87#endif
88}
89
90/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
91 * 0x00 - 0000 = Reserved
92 * 0x01 - 0001 = Reserved
93 * 0x02 - 0010 = Reserved
94 * 0x03 - 0011 = IRQ3
95 * 0x04 - 0100 = IRQ4
96 * 0x05 - 0101 = IRQ5
97 * 0x06 - 0110 = IRQ6
98 * 0x07 - 0111 = IRQ7
99 * 0x08 - 1000 = Reserved
100 * 0x09 - 1001 = IRQ9
101 * 0x0A - 1010 = IRQ10
102 * 0x0B - 1011 = IRQ11
103 * 0x0C - 1100 = IRQ12
104 * 0x0D - 1101 = Reserved
105 * 0x0E - 1110 = IRQ14
106 * 0x0F - 1111 = IRQ15
107 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
108 * 0x80 - The PIRQ is not routed.
109 */
110
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200111static void pch_pirq_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200112{
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200113 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200114 /* Interrupt 11 is not used by legacy devices and so can always be used for
115 PCI interrupts. Full legacy IRQ routing is complicated and hard to
116 get right. Fortunately all modern OS use MSI and so it's not that big of
117 an issue anyway. Still we have to provide a reasonable default. Using
118 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
119 move it to any interrupt and others will just leave them at default.
Stefan Reinauer8e073822012-04-04 00:07:22 +0200120 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200121 const u8 pirq_routing = 11;
122
123 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
124 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
125 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
126 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
127
128 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
129 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
130 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
131 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200132
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200133 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200134 u8 int_pin=0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200135
136 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
137 continue;
138
139 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
140
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200141 if (int_pin == 0)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200142 continue;
143
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200144 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200145 }
146}
147
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200148static void pch_gpi_routing(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200149{
150 /* Get the chip configuration */
151 config_t *config = dev->chip_info;
152 u32 reg32 = 0;
153
154 /* An array would be much nicer here, or some
155 * other method of doing this.
156 */
157 reg32 |= (config->gpi0_routing & 0x03) << 0;
158 reg32 |= (config->gpi1_routing & 0x03) << 2;
159 reg32 |= (config->gpi2_routing & 0x03) << 4;
160 reg32 |= (config->gpi3_routing & 0x03) << 6;
161 reg32 |= (config->gpi4_routing & 0x03) << 8;
162 reg32 |= (config->gpi5_routing & 0x03) << 10;
163 reg32 |= (config->gpi6_routing & 0x03) << 12;
164 reg32 |= (config->gpi7_routing & 0x03) << 14;
165 reg32 |= (config->gpi8_routing & 0x03) << 16;
166 reg32 |= (config->gpi9_routing & 0x03) << 18;
167 reg32 |= (config->gpi10_routing & 0x03) << 20;
168 reg32 |= (config->gpi11_routing & 0x03) << 22;
169 reg32 |= (config->gpi12_routing & 0x03) << 24;
170 reg32 |= (config->gpi13_routing & 0x03) << 26;
171 reg32 |= (config->gpi14_routing & 0x03) << 28;
172 reg32 |= (config->gpi15_routing & 0x03) << 30;
173
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200174 pci_write_config32(dev, GPIO_ROUT, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200175}
176
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200177static void pch_power_options(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200178{
179 u8 reg8;
180 u16 reg16, pmbase;
181 u32 reg32;
182 const char *state;
183 /* Get the chip configuration */
184 config_t *config = dev->chip_info;
185
Nico Huber9faae2b2018-11-14 00:00:35 +0100186 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200187 int nmi_option;
188
189 /* Which state do we want to goto after g3 (power restored)?
190 * 0 == S0 Full On
191 * 1 == S5 Soft Off
192 *
193 * If the option is not existent (Laptops), use Kconfig setting.
194 */
195 get_option(&pwr_on, "power_on_after_fail");
196
197 reg16 = pci_read_config16(dev, GEN_PMCON_3);
198 reg16 &= 0xfffe;
199 switch (pwr_on) {
200 case MAINBOARD_POWER_OFF:
201 reg16 |= 1;
202 state = "off";
203 break;
204 case MAINBOARD_POWER_ON:
205 reg16 &= ~1;
206 state = "on";
207 break;
208 case MAINBOARD_POWER_KEEP:
209 reg16 &= ~1;
210 state = "state keep";
211 break;
212 default:
213 state = "undefined";
214 }
215
216 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
217 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
218
219 reg16 &= ~(1 << 10);
220 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
221
222 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
223
224 pci_write_config16(dev, GEN_PMCON_3, reg16);
225 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
226
227 /* Set up NMI on errors. */
228 reg8 = inb(0x61);
229 reg8 &= 0x0f; /* Higher Nibble must be 0 */
230 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
231 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
232 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
233 outb(reg8, 0x61);
234
235 reg8 = inb(0x70);
236 nmi_option = NMI_OFF;
237 get_option(&nmi_option, "nmi");
238 if (nmi_option) {
239 printk(BIOS_INFO, "NMI sources enabled.\n");
240 reg8 &= ~(1 << 7); /* Set NMI. */
241 } else {
242 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200243 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200244 }
245 outb(reg8, 0x70);
246
247 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
248 reg16 = pci_read_config16(dev, GEN_PMCON_1);
249 reg16 &= ~(3 << 0); // SMI# rate 1 minute
250 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
251#if DEBUG_PERIODIC_SMIS
252 /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
253 * periodic SMIs.
254 */
255 reg16 |= (3 << 0); // Periodic SMI every 8s
256#endif
257 pci_write_config16(dev, GEN_PMCON_1, reg16);
258
259 // Set the board's GPI routing.
260 pch_gpi_routing(dev);
261
262 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
263
264 outl(config->gpe0_en, pmbase + GPE0_EN);
265 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
266
267 /* Set up power management block and determine sleep mode */
268 reg32 = inl(pmbase + 0x04); // PM1_CNT
269 reg32 &= ~(7 << 10); // SLP_TYP
270 reg32 |= (1 << 0); // SCI_EN
271 outl(reg32, pmbase + 0x04);
272
273 /* Clear magic status bits to prevent unexpected wake */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200274 reg32 = RCBA32(PRSTS);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200275 reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200276 RCBA32(PRSTS) = reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200277
278 reg32 = RCBA32(0x3f02);
279 reg32 &= ~0xf;
280 RCBA32(0x3f02) = reg32;
281}
282
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700283/* CougarPoint PCH Power Management init */
284static void cpt_pm_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200285{
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700286 printk(BIOS_DEBUG, "CougarPoint PM init\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200287 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200288 RCBA32_AND_OR(CIR30, ~0UL, (1 << 6)|(1 << 0));
289 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
290 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
291 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
292 RCBA32(DMC) = 0xc0388400;
293 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
294 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
295 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
296 RCBA32(PM_CFG) = 0x050f0000;
297 RCBA32(CIR8) = 0x04000000;
298 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
299 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1));
300 RCBA32(CIR12) = 0x0001c000;
301 RCBA32(CIR14) = 0x00061100;
302 RCBA32(CIR15) = 0x7f8fdfff;
303 RCBA32(CIR13) = 0x000003fc;
304 RCBA32(CIR16) = 0x00001000;
305 RCBA32(CIR18) = 0x0001c000;
306 RCBA32(CIR17) = 0x00000800;
307 RCBA32(CIR23) = 0x00001000;
308 RCBA32(CIR19) = 0x00093900;
309 RCBA32(CIR20) = 0x24653002;
310 RCBA32(CIR21) = 0x062108fe;
311 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
312 RCBA32(CIR24) = 0x01010000;
313 RCBA32(CIR25) = 0x01010404;
314 RCBA32(CIR27) = 0x01041041;
315 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
316 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
317 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
318 RCBA32(CIR26) = 0x00000001;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200319 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
320 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200321 RCBA32(PMSYNC_CFG) = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200322 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
323}
324
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700325/* PantherPoint PCH Power Management init */
326static void ppt_pm_init(struct device *dev)
327{
328 printk(BIOS_DEBUG, "PantherPoint PM init\n");
329 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200330 RCBA32_AND_OR(CIR30, ~0UL, (1 << 0));
331 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
332 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
333 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
334 RCBA32(DMC) = 0xc03b8400;
335 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
336 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
337 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
338 RCBA32(PM_CFG) = 0x054f0000;
339 RCBA32(CIR8) = 0x04000000;
340 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
341 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1)|(1 << 0));
342 RCBA32(CIR12) = 0x0001c000;
343 RCBA32(CIR14) = 0x00061100;
344 RCBA32(CIR15) = 0x7f8fdfff;
345 RCBA32(CIR13) = 0x000003fd;
346 RCBA32(CIR16) = 0x00001000;
347 RCBA32(CIR18) = 0x0001c000;
348 RCBA32(CIR17) = 0x00000800;
349 RCBA32(CIR23) = 0x00001000;
350 RCBA32(CIR19) = 0x00093900;
351 RCBA32(CIR20) = 0x24653002;
352 RCBA32(CIR21) = 0x067388fe;
353 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
354 RCBA32(CIR24) = 0x01010000;
355 RCBA32(CIR25) = 0x01010404;
356 RCBA32(CIR27) = 0x01040000;
357 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
358 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
359 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
360 RCBA32(CIR26) = 0x00000001;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700361 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
362 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
363 RCBA32_AND_OR(0x33a4, ~0UL, (1 << 0));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200364 RCBA32(PMSYNC_CFG) = 0;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700365 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
366}
367
Nico Huberb2dae792015-10-26 12:34:02 +0100368static void enable_hpet(struct device *const dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200369{
370 u32 reg32;
Nico Huberb2dae792015-10-26 12:34:02 +0100371 size_t i;
372
373 /* Assign unique bus/dev/fn for each HPET */
374 for (i = 0; i < 8; ++i)
375 pci_write_config16(dev, LPC_HnBDF(i),
376 PCH_HPET_PCI_BUS << 8 | PCH_HPET_PCI_SLOT << 3 | i);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200377
378 /* Move HPET to default address 0xfed00000 and enable it */
379 reg32 = RCBA32(HPTC);
380 reg32 |= (1 << 7); // HPET Address Enable
381 reg32 &= ~(3 << 0);
382 RCBA32(HPTC) = reg32;
383}
384
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200385static void enable_clock_gating(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200386{
387 u32 reg32;
388 u16 reg16;
389
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200390 RCBA32_AND_OR(DMIC, ~0UL, 0xf);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200391
392 reg16 = pci_read_config16(dev, GEN_PMCON_1);
393 reg16 |= (1 << 2) | (1 << 11);
394 pci_write_config16(dev, GEN_PMCON_1, reg16);
395
396 pch_iobp_update(0xEB007F07, ~0UL, (1 << 31));
397 pch_iobp_update(0xEB004000, ~0UL, (1 << 7));
398 pch_iobp_update(0xEC007F07, ~0UL, (1 << 31));
399 pch_iobp_update(0xEC004000, ~0UL, (1 << 7));
400
401 reg32 = RCBA32(CG);
402 reg32 |= (1 << 31);
403 reg32 |= (1 << 29) | (1 << 28);
404 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
405 reg32 |= (1 << 16);
406 reg32 |= (1 << 17);
407 reg32 |= (1 << 18);
408 reg32 |= (1 << 22);
409 reg32 |= (1 << 23);
410 reg32 &= ~(1 << 20);
411 reg32 |= (1 << 19);
412 reg32 |= (1 << 0);
413 reg32 |= (0xf << 1);
414 RCBA32(CG) = reg32;
415
416 RCBA32_OR(0x38c0, 0x7);
417 RCBA32_OR(0x36d4, 0x6680c004);
418 RCBA32_OR(0x3564, 0x3);
419}
420
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200421static void pch_set_acpi_mode(void)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200422{
Julius Werner5d1f9a02019-03-07 17:07:26 -0800423 if (!acpi_is_wakeup_s3() && CONFIG(HAVE_SMI_HANDLER)) {
Stefan Reinauer8e073822012-04-04 00:07:22 +0200424#if ENABLE_ACPI_MODE_IN_COREBOOT
Duncan Laurie95be1d62012-04-09 12:31:43 -0700425 printk(BIOS_DEBUG, "Enabling ACPI via APMC:\n");
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200426 outb(APM_CNT_ACPI_ENABLE, APM_CNT); // Enable ACPI mode
Duncan Laurie95be1d62012-04-09 12:31:43 -0700427 printk(BIOS_DEBUG, "done.\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200428#else
Duncan Laurie95be1d62012-04-09 12:31:43 -0700429 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200430 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
Duncan Laurie95be1d62012-04-09 12:31:43 -0700431 printk(BIOS_DEBUG, "done.\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200432#endif
Duncan Laurie95be1d62012-04-09 12:31:43 -0700433 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200434}
Stefan Reinauer8e073822012-04-04 00:07:22 +0200435
436static void pch_disable_smm_only_flashing(struct device *dev)
437{
438 u8 reg8;
439
440 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100441 reg8 = pci_read_config8(dev, BIOS_CNTL);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200442 reg8 &= ~(1 << 5);
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100443 pci_write_config8(dev, BIOS_CNTL, reg8);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200444}
445
446static void pch_fixups(struct device *dev)
447{
448 u8 gen_pmcon_2;
449
450 /* Indicate DRAM init done for MRC S3 to know it can resume */
451 gen_pmcon_2 = pci_read_config8(dev, GEN_PMCON_2);
452 gen_pmcon_2 |= (1 << 7);
453 pci_write_config8(dev, GEN_PMCON_2, gen_pmcon_2);
454
455 /*
456 * Enable DMI ASPM in the PCH
457 */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200458 RCBA32_AND_OR(DMC, ~(1 << 10), 0);
459 RCBA32_OR(LCAP, (1 << 11)|(1 << 10));
460 RCBA32_OR(LCTL, 0x3);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200461}
462
Nico Huber7b2f9f62015-10-01 19:00:51 +0200463static void pch_spi_init(const struct device *const dev)
464{
465 const config_t *const config = dev->chip_info;
466
467 printk(BIOS_DEBUG, "pch_spi_init\n");
468
469 if (config->spi_uvscc)
470 RCBA32(0x3800 + 0xc8) = config->spi_uvscc;
471 if (config->spi_lvscc)
472 RCBA32(0x3800 + 0xc4) = config->spi_lvscc;
473
474 if (config->spi_uvscc || config->spi_lvscc)
475 RCBA32_OR(0x3800 + 0xc4, 1 << 23); /* lock both UVSCC + LVSCC */
476}
477
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200478static const struct {
479 u16 dev_id;
480 const char *dev_name;
481} pch_table[] = {
482 /* 6-series PCI ids from
483 * Intel® 6 Series Chipset and
484 * Intel® C200 Series Chipset
485 * Specification Update - NDA
486 * October 2013
487 * CDI / IBP#: 440377
488 */
489 {0x1C41, "SFF Sample"},
490 {0x1C42, "Desktop Sample"},
491 {0x1C43, "Mobile Sample"},
492 {0x1C44, "Z68"},
493 {0x1C46, "P67"},
494 {0x1C47, "UM67"},
495 {0x1C49, "HM65"},
496 {0x1C4A, "H67"},
497 {0x1C4B, "HM67"},
498 {0x1C4C, "Q65"},
499 {0x1C4D, "QS67"},
500 {0x1C4E, "Q67"},
501 {0x1C4F, "QM67"},
502 {0x1C50, "B65"},
503 {0x1C52, "C202"},
504 {0x1C54, "C204"},
505 {0x1C56, "C206"},
506 {0x1C5C, "H61"},
507 /* 7-series PCI ids from Intel document 472178 */
508 {0x1E41, "Desktop Sample"},
509 {0x1E42, "Mobile Sample"},
510 {0x1E43, "SFF Sample"},
511 {0x1E44, "Z77"},
512 {0x1E45, "H71"},
513 {0x1E46, "Z75"},
514 {0x1E47, "Q77"},
515 {0x1E48, "Q75"},
516 {0x1E49, "B75"},
517 {0x1E4A, "H77"},
518 {0x1E53, "C216"},
519 {0x1E55, "QM77"},
520 {0x1E56, "QS77"},
521 {0x1E58, "UM77"},
522 {0x1E57, "HM77"},
523 {0x1E59, "HM76"},
524 {0x1E5D, "HM75"},
525 {0x1E5E, "HM70"},
526 {0x1E5F, "NM70"},
527};
528
529static void report_pch_info(struct device *dev)
530{
531 const u16 dev_id = pci_read_config16(dev, PCI_DEVICE_ID);
532 int i;
533
534 const char *pch_type = "Unknown";
535 for (i = 0; i < ARRAY_SIZE(pch_table); i++) {
536 if (pch_table[i].dev_id == dev_id) {
537 pch_type = pch_table[i].dev_name;
538 break;
539 }
540 }
541 printk(BIOS_INFO, "PCH: detected %s, device id: 0x%x, rev id 0x%x\n",
542 pch_type, dev_id, pci_read_config8(dev, PCI_CLASS_REVISION));
543}
544
Stefan Reinauer8e073822012-04-04 00:07:22 +0200545static void lpc_init(struct device *dev)
546{
547 printk(BIOS_DEBUG, "pch: lpc_init\n");
548
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200549 /* Print detected platform */
550 report_pch_info(dev);
551
Stefan Reinauer8e073822012-04-04 00:07:22 +0200552 /* Set the value for PCI command register. */
553 pci_write_config16(dev, PCI_COMMAND, 0x000f);
554
555 /* IO APIC initialization. */
Paul Menzel9c50e6a2013-05-03 12:23:39 +0200556 pch_enable_ioapic(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200557
558 pch_enable_serial_irqs(dev);
559
560 /* Setup the PIRQ. */
561 pch_pirq_init(dev);
562
563 /* Setup power options. */
564 pch_power_options(dev);
565
566 /* Initialize power management */
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700567 switch (pch_silicon_type()) {
568 case PCH_TYPE_CPT: /* CougarPoint */
569 cpt_pm_init(dev);
570 break;
571 case PCH_TYPE_PPT: /* PantherPoint */
572 ppt_pm_init(dev);
573 break;
574 default:
575 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
576 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200577
578 /* Set the state of the GPIO lines. */
579 //gpio_init(dev);
580
581 /* Initialize the real time clock. */
Patrick Rudolph6b931122018-11-01 17:48:37 +0100582 sb_rtc_init();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200583
584 /* Initialize ISA DMA. */
585 isa_dma_init();
586
587 /* Initialize the High Precision Event Timers, if present. */
Nico Huberb2dae792015-10-26 12:34:02 +0100588 enable_hpet(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200589
590 /* Initialize Clock Gating */
591 enable_clock_gating(dev);
592
593 setup_i8259();
594
595 /* The OS should do this? */
596 /* Interrupt 9 should be level triggered (SCI) */
597 i8259_configure_irq_trigger(9, 1);
598
599 pch_disable_smm_only_flashing(dev);
600
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200601 pch_set_acpi_mode();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200602
603 pch_fixups(dev);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200604
605 pch_spi_init(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200606}
607
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200608static void pch_lpc_read_resources(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200609{
610 struct resource *res;
Marc Jonesa0bec172012-07-13 14:14:34 -0600611 config_t *config = dev->chip_info;
612 u8 io_index = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200613
614 /* Get the normal PCI resources of this device. */
615 pci_dev_read_resources(dev);
616
617 /* Add an extra subtractive resource for both memory and I/O. */
Marc Jonesa0bec172012-07-13 14:14:34 -0600618 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200619 res->base = 0;
620 res->size = 0x1000;
621 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
622 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
623
Marc Jonesa0bec172012-07-13 14:14:34 -0600624 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Vladimir Serbinenko0650cd02014-02-05 15:03:50 +0100625 res->base = 0xff000000;
626 /* Some systems (e.g. X230) have 12 MiB flash.
627 SPI controller supports up to 2 x 16 MiB of flash but
628 address map limits this to 16MiB. */
629 res->size = 0x01000000; /* 16 MB for flash */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200630 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
631 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
632
633 res = new_resource(dev, 3); /* IOAPIC */
634 res->base = IO_APIC_ADDR;
635 res->size = 0x00001000;
636 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Marc Jonesa0bec172012-07-13 14:14:34 -0600637
638 /* Set PCH IO decode ranges if required.*/
639 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
640 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
641 res->base = config->gen1_dec & 0xFFFC;
642 res->size = (config->gen1_dec >> 16) & 0xFC;
643 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
644 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
645 }
646
647 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
648 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
649 res->base = config->gen2_dec & 0xFFFC;
650 res->size = (config->gen2_dec >> 16) & 0xFC;
651 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
652 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
653 }
654
655 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
656 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
657 res->base = config->gen3_dec & 0xFFFC;
658 res->size = (config->gen3_dec >> 16) & 0xFC;
659 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
660 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
661 }
662
663 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
664 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
665 res->base = config->gen4_dec & 0xFFFC;
666 res->size = (config->gen4_dec >> 16) & 0xFC;
667 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
668 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
669 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200670}
671
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200672static void pch_lpc_enable(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200673{
674 /* Enable PCH Display Port */
675 RCBA16(DISPBDF) = 0x0010;
676 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
677
678 pch_enable(dev);
679}
680
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200681static void southbridge_inject_dsdt(struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200682{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200683 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200684
685 if (gnvs) {
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100686 const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
Elyes HAOUAS035df002016-10-03 21:54:16 +0200687 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200688
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200689 acpi_create_gnvs(gnvs);
Vladimir Serbinenko06c788d2014-10-12 00:17:11 +0200690
691 gnvs->apic = 1;
692 gnvs->mpen = 1; /* Enable Multi Processing */
693 gnvs->pcnt = dev_count_cpu();
694
Nico Huber744d6bd2019-01-12 14:58:20 +0100695 if (gfx) {
696 gnvs->ndid = gfx->ndid;
697 memcpy(gnvs->did, gfx->did, sizeof(gnvs->did));
698 }
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100699
Julius Wernercd49cce2019-03-05 16:53:33 -0800700#if CONFIG(CHROMEOS)
Joel Kitching6fbd8742018-08-23 14:56:25 +0800701 chromeos_init_chromeos_acpi(&(gnvs->chromeos));
Vladimir Serbinenko06c788d2014-10-12 00:17:11 +0200702#endif
703
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200704 /* And tell SMI about it */
705 smm_setup_structures(gnvs, NULL, NULL);
706
Vladimir Serbinenko334fd8e2014-10-05 11:10:35 +0200707 /* Add it to DSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100708 acpigen_write_scope("\\");
709 acpigen_write_name_dword("NVSA", (u32) gnvs);
710 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200711 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200712}
713
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200714void acpi_fill_fadt(acpi_fadt_t *fadt)
715{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300716 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200717 config_t *chip = dev->chip_info;
718 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
719 int c2_latency;
720
Elyes HAOUAS0d4de2a2019-02-28 13:04:29 +0100721 fadt->reserved = 0;
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200722
723 fadt->sci_int = 0x9;
724 fadt->smi_cmd = APM_CNT;
725 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
726 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
727 fadt->s4bios_req = 0x0;
728 fadt->pstate_cnt = 0;
729
730 fadt->pm1a_evt_blk = pmbase;
731 fadt->pm1b_evt_blk = 0x0;
732 fadt->pm1a_cnt_blk = pmbase + 0x4;
733 fadt->pm1b_cnt_blk = 0x0;
734 fadt->pm2_cnt_blk = pmbase + 0x50;
735 fadt->pm_tmr_blk = pmbase + 0x8;
736 fadt->gpe0_blk = pmbase + 0x20;
737 fadt->gpe1_blk = 0;
738
739 fadt->pm1_evt_len = 4;
740 fadt->pm1_cnt_len = 2;
741 fadt->pm2_cnt_len = 1;
742 fadt->pm_tmr_len = 4;
743 fadt->gpe0_blk_len = 16;
744 fadt->gpe1_blk_len = 0;
745 fadt->gpe1_base = 0;
746 fadt->cst_cnt = 0;
747 c2_latency = chip->c2_latency;
748 if (!c2_latency) {
749 c2_latency = 101; /* c2 unsupported */
750 }
751 fadt->p_lvl2_lat = c2_latency;
752 fadt->p_lvl3_lat = 87;
753 fadt->flush_size = 1024;
754 fadt->flush_stride = 16;
Patrick Rudolphb30a47b2019-07-15 18:04:23 +0200755 /* P_CNT not supported */
756 fadt->duty_offset = 0;
757 fadt->duty_width = 0;
758
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200759 fadt->day_alrm = 0xd;
760 fadt->mon_alrm = 0x00;
761 fadt->century = 0x00;
762 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
763
764 fadt->flags = ACPI_FADT_WBINVD |
765 ACPI_FADT_C1_SUPPORTED |
766 ACPI_FADT_SLEEP_BUTTON |
767 ACPI_FADT_RESET_REGISTER |
768 ACPI_FADT_SEALED_CASE |
769 ACPI_FADT_S4_RTC_WAKE |
770 ACPI_FADT_PLATFORM_CLOCK;
771 if (chip->docking_supported) {
772 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
773 }
774 if (c2_latency < 100) {
775 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
776 }
777
778 fadt->reset_reg.space_id = 1;
779 fadt->reset_reg.bit_width = 8;
780 fadt->reset_reg.bit_offset = 0;
781 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
782 fadt->reset_reg.addrl = 0xcf9;
783 fadt->reset_reg.addrh = 0;
784
785 fadt->reset_value = 6;
786
787 fadt->x_pm1a_evt_blk.space_id = 1;
788 fadt->x_pm1a_evt_blk.bit_width = 32;
789 fadt->x_pm1a_evt_blk.bit_offset = 0;
790 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
791 fadt->x_pm1a_evt_blk.addrl = pmbase;
792 fadt->x_pm1a_evt_blk.addrh = 0x0;
793
794 fadt->x_pm1b_evt_blk.space_id = 1;
795 fadt->x_pm1b_evt_blk.bit_width = 0;
796 fadt->x_pm1b_evt_blk.bit_offset = 0;
797 fadt->x_pm1b_evt_blk.access_size = 0;
798 fadt->x_pm1b_evt_blk.addrl = 0x0;
799 fadt->x_pm1b_evt_blk.addrh = 0x0;
800
801 fadt->x_pm1a_cnt_blk.space_id = 1;
802 fadt->x_pm1a_cnt_blk.bit_width = 16;
803 fadt->x_pm1a_cnt_blk.bit_offset = 0;
804 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
805 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
806 fadt->x_pm1a_cnt_blk.addrh = 0x0;
807
808 fadt->x_pm1b_cnt_blk.space_id = 1;
809 fadt->x_pm1b_cnt_blk.bit_width = 0;
810 fadt->x_pm1b_cnt_blk.bit_offset = 0;
811 fadt->x_pm1b_cnt_blk.access_size = 0;
812 fadt->x_pm1b_cnt_blk.addrl = 0x0;
813 fadt->x_pm1b_cnt_blk.addrh = 0x0;
814
815 fadt->x_pm2_cnt_blk.space_id = 1;
816 fadt->x_pm2_cnt_blk.bit_width = 8;
817 fadt->x_pm2_cnt_blk.bit_offset = 0;
818 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
819 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
820 fadt->x_pm2_cnt_blk.addrh = 0x0;
821
822 fadt->x_pm_tmr_blk.space_id = 1;
823 fadt->x_pm_tmr_blk.bit_width = 32;
824 fadt->x_pm_tmr_blk.bit_offset = 0;
825 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
826 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
827 fadt->x_pm_tmr_blk.addrh = 0x0;
828
829 fadt->x_gpe0_blk.space_id = 1;
830 fadt->x_gpe0_blk.bit_width = 128;
831 fadt->x_gpe0_blk.bit_offset = 0;
832 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
833 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
834 fadt->x_gpe0_blk.addrh = 0x0;
835
836 fadt->x_gpe1_blk.space_id = 1;
837 fadt->x_gpe1_blk.bit_width = 0;
838 fadt->x_gpe1_blk.bit_offset = 0;
839 fadt->x_gpe1_blk.access_size = 0;
840 fadt->x_gpe1_blk.addrl = 0x0;
841 fadt->x_gpe1_blk.addrh = 0x0;
842}
843
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600844static const char *lpc_acpi_name(const struct device *dev)
Patrick Rudolph604f6982017-06-07 09:46:52 +0200845{
846 return "LPCB";
847}
848
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200849static void southbridge_fill_ssdt(struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100850{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300851 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100852 config_t *chip = dev->chip_info;
853
854 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Tobias Diedrich7f5efd92017-12-14 00:29:01 +0100855 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100856}
857
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200858static void lpc_final(struct device *dev)
859{
Arthur Heymansebf201b2019-05-28 13:51:36 +0200860 spi_finalize_ops();
Nico Huber8e50b6d2018-02-04 15:52:18 +0100861
Bill XIEd533b162017-08-22 16:26:22 +0800862 /* Call SMM finalize() handlers before resume */
Julius Wernercd49cce2019-03-05 16:53:33 -0800863 if (CONFIG(HAVE_SMI_HANDLER)) {
864 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
Bill XIEd533b162017-08-22 16:26:22 +0800865 acpi_is_wakeup_s3()) {
866 outb(APM_CNT_FINALIZE, APM_CNT);
867 }
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200868 }
869}
870
Arthur Heymansebf201b2019-05-28 13:51:36 +0200871void intel_southbridge_override_spi(
872 struct intel_swseq_spi_config *spi_config)
873{
874 struct device *dev = pcidev_on_root(0x1f, 0);
875
876 if (!dev)
877 return;
878 /* Devicetree may override defaults. */
879 const config_t *const config = dev->chip_info;
880
881 if (!config)
882 return;
883
884 if (config->spi.ops[0].op != 0)
885 memcpy(spi_config, &config->spi, sizeof(*spi_config));
886}
887
Stefan Reinauer8e073822012-04-04 00:07:22 +0200888static struct pci_operations pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530889 .set_subsystem = pci_dev_set_subsystem,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200890};
891
892static struct device_operations device_ops = {
893 .read_resources = pch_lpc_read_resources,
894 .set_resources = pci_dev_set_resources,
Arthur Heymans3cde4942019-08-18 10:02:10 +0200895 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200896 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko334fd8e2014-10-05 11:10:35 +0200897 .acpi_inject_dsdt_generator = southbridge_inject_dsdt,
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100898 .acpi_fill_ssdt_generator = southbridge_fill_ssdt,
Patrick Rudolph604f6982017-06-07 09:46:52 +0200899 .acpi_name = lpc_acpi_name,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200900 .init = lpc_init,
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200901 .final = lpc_final,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200902 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100903 .scan_bus = scan_static_bus,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200904 .ops_pci = &pci_ops,
905};
906
907
Kimarie Hoote6f459c2012-07-14 08:26:08 -0600908/* IDs for LPC device of Intel 6 Series Chipset, Intel 7 Series Chipset, and
909 * Intel C200 Series Chipset
Stefan Reinauer8e073822012-04-04 00:07:22 +0200910 */
911
Vladimir Serbinenko42d55e02016-01-02 01:47:26 +0100912static const unsigned short pci_device_ids[] = {
913 0x1c40, 0x1c41, 0x1c42, 0x1c43, 0x1c44, 0x1c45, 0x1c46, 0x1c47, 0x1c48,
914 0x1c49, 0x1c4a, 0x1c4b, 0x1c4c, 0x1c4d, 0x1c4e, 0x1c4f, 0x1c50, 0x1c51,
915 0x1c52, 0x1c53, 0x1c54, 0x1c55, 0x1c56, 0x1c57, 0x1c58, 0x1c59, 0x1c5a,
916 0x1c5b, 0x1c5c, 0x1c5d, 0x1c5e, 0x1c5f,
917
918 0x1e41, 0x1e42, 0x1e43, 0x1e44, 0x1e45, 0x1e46, 0x1e47, 0x1e48, 0x1e49,
919 0x1e4a, 0x1e4b, 0x1e4c, 0x1e4d, 0x1e4e, 0x1e4f, 0x1e50, 0x1e51, 0x1e52,
920 0x1e53, 0x1e54, 0x1e55, 0x1e56, 0x1e57, 0x1e58, 0x1e59, 0x1e5a, 0x1e5b,
921 0x1e5c, 0x1e5d, 0x1e5e, 0x1e5f,
922
923 0 };
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700924
925static const struct pci_driver pch_lpc __pci_driver = {
926 .ops = &device_ops,
927 .vendor = PCI_VENDOR_ID_INTEL,
928 .devices = pci_device_ids,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200929};