blob: bd3c993912ac86039249ad07982b7d82659b2636 [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>
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>
Stefan Reinauer8e073822012-04-04 00:07:22 +020041
42#define NMI_OFF 0
43
44#define ENABLE_ACPI_MODE_IN_COREBOOT 0
Stefan Reinauer8e073822012-04-04 00:07:22 +020045
46typedef struct southbridge_intel_bd82x6x_config config_t;
47
Paul Menzel9c50e6a2013-05-03 12:23:39 +020048/**
49 * Set miscellanous static southbridge features.
50 *
51 * @param dev PCI device with I/O APIC control registers
52 */
53static void pch_enable_ioapic(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020054{
Stefan Reinauer8e073822012-04-04 00:07:22 +020055 u32 reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +020056
Nico Huberb2dae792015-10-26 12:34:02 +010057 /* Assign unique bus/dev/fn for I/O APIC */
58 pci_write_config16(dev, LPC_IBDF,
59 PCH_IOAPIC_PCI_BUS << 8 | PCH_IOAPIC_PCI_SLOT << 3);
60
Paul Menzel9c50e6a2013-05-03 12:23:39 +020061 /* Enable ACPI I/O range decode */
62 pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
Stefan Reinauer8e073822012-04-04 00:07:22 +020063
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080064 set_ioapic_id(VIO_APIC_VADDR, 0x02);
Stefan Reinauer8e073822012-04-04 00:07:22 +020065
66 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080067 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
68 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +020069
Paul Menzel9c50e6a2013-05-03 12:23:39 +020070 /*
71 * Select Boot Configuration register (0x03) and
72 * use Processor System Bus (0x01) to deliver interrupts.
73 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080074 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Stefan Reinauer8e073822012-04-04 00:07:22 +020075}
76
77static void pch_enable_serial_irqs(struct device *dev)
78{
79 /* Set packet length and toggle silent mode bit for one frame. */
80 pci_write_config8(dev, SERIRQ_CNTL,
81 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080082#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Stefan Reinauer8e073822012-04-04 00:07:22 +020083 pci_write_config8(dev, SERIRQ_CNTL,
84 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
85#endif
86}
87
88/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
89 * 0x00 - 0000 = Reserved
90 * 0x01 - 0001 = Reserved
91 * 0x02 - 0010 = Reserved
92 * 0x03 - 0011 = IRQ3
93 * 0x04 - 0100 = IRQ4
94 * 0x05 - 0101 = IRQ5
95 * 0x06 - 0110 = IRQ6
96 * 0x07 - 0111 = IRQ7
97 * 0x08 - 1000 = Reserved
98 * 0x09 - 1001 = IRQ9
99 * 0x0A - 1010 = IRQ10
100 * 0x0B - 1011 = IRQ11
101 * 0x0C - 1100 = IRQ12
102 * 0x0D - 1101 = Reserved
103 * 0x0E - 1110 = IRQ14
104 * 0x0F - 1111 = IRQ15
105 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
106 * 0x80 - The PIRQ is not routed.
107 */
108
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200109static void pch_pirq_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200110{
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200111 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200112 /* Interrupt 11 is not used by legacy devices and so can always be used for
113 PCI interrupts. Full legacy IRQ routing is complicated and hard to
114 get right. Fortunately all modern OS use MSI and so it's not that big of
115 an issue anyway. Still we have to provide a reasonable default. Using
116 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
117 move it to any interrupt and others will just leave them at default.
Stefan Reinauer8e073822012-04-04 00:07:22 +0200118 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200119 const u8 pirq_routing = 11;
120
121 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
122 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
123 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
124 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
125
126 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
127 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
128 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
129 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200130
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200131 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200132 u8 int_pin=0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200133
134 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
135 continue;
136
137 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
138
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200139 if (int_pin == 0)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200140 continue;
141
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200142 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200143 }
144}
145
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200146static void pch_gpi_routing(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200147{
148 /* Get the chip configuration */
149 config_t *config = dev->chip_info;
150 u32 reg32 = 0;
151
152 /* An array would be much nicer here, or some
153 * other method of doing this.
154 */
155 reg32 |= (config->gpi0_routing & 0x03) << 0;
156 reg32 |= (config->gpi1_routing & 0x03) << 2;
157 reg32 |= (config->gpi2_routing & 0x03) << 4;
158 reg32 |= (config->gpi3_routing & 0x03) << 6;
159 reg32 |= (config->gpi4_routing & 0x03) << 8;
160 reg32 |= (config->gpi5_routing & 0x03) << 10;
161 reg32 |= (config->gpi6_routing & 0x03) << 12;
162 reg32 |= (config->gpi7_routing & 0x03) << 14;
163 reg32 |= (config->gpi8_routing & 0x03) << 16;
164 reg32 |= (config->gpi9_routing & 0x03) << 18;
165 reg32 |= (config->gpi10_routing & 0x03) << 20;
166 reg32 |= (config->gpi11_routing & 0x03) << 22;
167 reg32 |= (config->gpi12_routing & 0x03) << 24;
168 reg32 |= (config->gpi13_routing & 0x03) << 26;
169 reg32 |= (config->gpi14_routing & 0x03) << 28;
170 reg32 |= (config->gpi15_routing & 0x03) << 30;
171
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200172 pci_write_config32(dev, GPIO_ROUT, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200173}
174
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200175static void pch_power_options(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200176{
177 u8 reg8;
178 u16 reg16, pmbase;
179 u32 reg32;
180 const char *state;
181 /* Get the chip configuration */
182 config_t *config = dev->chip_info;
183
Nico Huber9faae2b2018-11-14 00:00:35 +0100184 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200185 int nmi_option;
186
187 /* Which state do we want to goto after g3 (power restored)?
188 * 0 == S0 Full On
189 * 1 == S5 Soft Off
190 *
191 * If the option is not existent (Laptops), use Kconfig setting.
192 */
193 get_option(&pwr_on, "power_on_after_fail");
194
195 reg16 = pci_read_config16(dev, GEN_PMCON_3);
196 reg16 &= 0xfffe;
197 switch (pwr_on) {
198 case MAINBOARD_POWER_OFF:
199 reg16 |= 1;
200 state = "off";
201 break;
202 case MAINBOARD_POWER_ON:
203 reg16 &= ~1;
204 state = "on";
205 break;
206 case MAINBOARD_POWER_KEEP:
207 reg16 &= ~1;
208 state = "state keep";
209 break;
210 default:
211 state = "undefined";
212 }
213
214 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
215 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
216
217 reg16 &= ~(1 << 10);
218 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
219
220 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
221
222 pci_write_config16(dev, GEN_PMCON_3, reg16);
223 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
224
225 /* Set up NMI on errors. */
226 reg8 = inb(0x61);
227 reg8 &= 0x0f; /* Higher Nibble must be 0 */
228 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
229 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
230 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
231 outb(reg8, 0x61);
232
233 reg8 = inb(0x70);
234 nmi_option = NMI_OFF;
235 get_option(&nmi_option, "nmi");
236 if (nmi_option) {
237 printk(BIOS_INFO, "NMI sources enabled.\n");
238 reg8 &= ~(1 << 7); /* Set NMI. */
239 } else {
240 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200241 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200242 }
243 outb(reg8, 0x70);
244
245 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
246 reg16 = pci_read_config16(dev, GEN_PMCON_1);
247 reg16 &= ~(3 << 0); // SMI# rate 1 minute
248 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
249#if DEBUG_PERIODIC_SMIS
250 /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
251 * periodic SMIs.
252 */
253 reg16 |= (3 << 0); // Periodic SMI every 8s
254#endif
255 pci_write_config16(dev, GEN_PMCON_1, reg16);
256
257 // Set the board's GPI routing.
258 pch_gpi_routing(dev);
259
260 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
261
262 outl(config->gpe0_en, pmbase + GPE0_EN);
263 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
264
265 /* Set up power management block and determine sleep mode */
266 reg32 = inl(pmbase + 0x04); // PM1_CNT
267 reg32 &= ~(7 << 10); // SLP_TYP
268 reg32 |= (1 << 0); // SCI_EN
269 outl(reg32, pmbase + 0x04);
270
271 /* Clear magic status bits to prevent unexpected wake */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200272 reg32 = RCBA32(PRSTS);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200273 reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200274 RCBA32(PRSTS) = reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200275
276 reg32 = RCBA32(0x3f02);
277 reg32 &= ~0xf;
278 RCBA32(0x3f02) = reg32;
279}
280
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700281/* CougarPoint PCH Power Management init */
282static void cpt_pm_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200283{
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700284 printk(BIOS_DEBUG, "CougarPoint PM init\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200285 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200286 RCBA32_AND_OR(CIR30, ~0UL, (1 << 6)|(1 << 0));
287 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
288 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
289 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
290 RCBA32(DMC) = 0xc0388400;
291 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
292 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
293 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
294 RCBA32(PM_CFG) = 0x050f0000;
295 RCBA32(CIR8) = 0x04000000;
296 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
297 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1));
298 RCBA32(CIR12) = 0x0001c000;
299 RCBA32(CIR14) = 0x00061100;
300 RCBA32(CIR15) = 0x7f8fdfff;
301 RCBA32(CIR13) = 0x000003fc;
302 RCBA32(CIR16) = 0x00001000;
303 RCBA32(CIR18) = 0x0001c000;
304 RCBA32(CIR17) = 0x00000800;
305 RCBA32(CIR23) = 0x00001000;
306 RCBA32(CIR19) = 0x00093900;
307 RCBA32(CIR20) = 0x24653002;
308 RCBA32(CIR21) = 0x062108fe;
309 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
310 RCBA32(CIR24) = 0x01010000;
311 RCBA32(CIR25) = 0x01010404;
312 RCBA32(CIR27) = 0x01041041;
313 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
314 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
315 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
316 RCBA32(CIR26) = 0x00000001;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200317 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
318 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200319 RCBA32(PMSYNC_CFG) = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200320 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
321}
322
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700323/* PantherPoint PCH Power Management init */
324static void ppt_pm_init(struct device *dev)
325{
326 printk(BIOS_DEBUG, "PantherPoint PM init\n");
327 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200328 RCBA32_AND_OR(CIR30, ~0UL, (1 << 0));
329 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
330 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
331 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
332 RCBA32(DMC) = 0xc03b8400;
333 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
334 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
335 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
336 RCBA32(PM_CFG) = 0x054f0000;
337 RCBA32(CIR8) = 0x04000000;
338 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
339 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1)|(1 << 0));
340 RCBA32(CIR12) = 0x0001c000;
341 RCBA32(CIR14) = 0x00061100;
342 RCBA32(CIR15) = 0x7f8fdfff;
343 RCBA32(CIR13) = 0x000003fd;
344 RCBA32(CIR16) = 0x00001000;
345 RCBA32(CIR18) = 0x0001c000;
346 RCBA32(CIR17) = 0x00000800;
347 RCBA32(CIR23) = 0x00001000;
348 RCBA32(CIR19) = 0x00093900;
349 RCBA32(CIR20) = 0x24653002;
350 RCBA32(CIR21) = 0x067388fe;
351 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
352 RCBA32(CIR24) = 0x01010000;
353 RCBA32(CIR25) = 0x01010404;
354 RCBA32(CIR27) = 0x01040000;
355 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
356 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
357 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
358 RCBA32(CIR26) = 0x00000001;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700359 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
360 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
361 RCBA32_AND_OR(0x33a4, ~0UL, (1 << 0));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200362 RCBA32(PMSYNC_CFG) = 0;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700363 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
364}
365
Nico Huberb2dae792015-10-26 12:34:02 +0100366static void enable_hpet(struct device *const dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200367{
368 u32 reg32;
Nico Huberb2dae792015-10-26 12:34:02 +0100369 size_t i;
370
371 /* Assign unique bus/dev/fn for each HPET */
372 for (i = 0; i < 8; ++i)
373 pci_write_config16(dev, LPC_HnBDF(i),
374 PCH_HPET_PCI_BUS << 8 | PCH_HPET_PCI_SLOT << 3 | i);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200375
376 /* Move HPET to default address 0xfed00000 and enable it */
377 reg32 = RCBA32(HPTC);
378 reg32 |= (1 << 7); // HPET Address Enable
379 reg32 &= ~(3 << 0);
380 RCBA32(HPTC) = reg32;
381}
382
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200383static void enable_clock_gating(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200384{
385 u32 reg32;
386 u16 reg16;
387
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200388 RCBA32_AND_OR(DMIC, ~0UL, 0xf);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200389
390 reg16 = pci_read_config16(dev, GEN_PMCON_1);
391 reg16 |= (1 << 2) | (1 << 11);
392 pci_write_config16(dev, GEN_PMCON_1, reg16);
393
394 pch_iobp_update(0xEB007F07, ~0UL, (1 << 31));
395 pch_iobp_update(0xEB004000, ~0UL, (1 << 7));
396 pch_iobp_update(0xEC007F07, ~0UL, (1 << 31));
397 pch_iobp_update(0xEC004000, ~0UL, (1 << 7));
398
399 reg32 = RCBA32(CG);
400 reg32 |= (1 << 31);
401 reg32 |= (1 << 29) | (1 << 28);
402 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
403 reg32 |= (1 << 16);
404 reg32 |= (1 << 17);
405 reg32 |= (1 << 18);
406 reg32 |= (1 << 22);
407 reg32 |= (1 << 23);
408 reg32 &= ~(1 << 20);
409 reg32 |= (1 << 19);
410 reg32 |= (1 << 0);
411 reg32 |= (0xf << 1);
412 RCBA32(CG) = reg32;
413
414 RCBA32_OR(0x38c0, 0x7);
415 RCBA32_OR(0x36d4, 0x6680c004);
416 RCBA32_OR(0x3564, 0x3);
417}
418
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200419static void pch_set_acpi_mode(void)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200420{
Julius Werner5d1f9a02019-03-07 17:07:26 -0800421 if (!acpi_is_wakeup_s3() && CONFIG(HAVE_SMI_HANDLER)) {
Stefan Reinauer8e073822012-04-04 00:07:22 +0200422#if ENABLE_ACPI_MODE_IN_COREBOOT
Duncan Laurie95be1d62012-04-09 12:31:43 -0700423 printk(BIOS_DEBUG, "Enabling ACPI via APMC:\n");
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200424 outb(APM_CNT_ACPI_ENABLE, APM_CNT); // Enable ACPI mode
Duncan Laurie95be1d62012-04-09 12:31:43 -0700425 printk(BIOS_DEBUG, "done.\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200426#else
Duncan Laurie95be1d62012-04-09 12:31:43 -0700427 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200428 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
Duncan Laurie95be1d62012-04-09 12:31:43 -0700429 printk(BIOS_DEBUG, "done.\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200430#endif
Duncan Laurie95be1d62012-04-09 12:31:43 -0700431 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200432}
Stefan Reinauer8e073822012-04-04 00:07:22 +0200433
434static void pch_disable_smm_only_flashing(struct device *dev)
435{
436 u8 reg8;
437
438 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100439 reg8 = pci_read_config8(dev, BIOS_CNTL);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200440 reg8 &= ~(1 << 5);
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100441 pci_write_config8(dev, BIOS_CNTL, reg8);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200442}
443
444static void pch_fixups(struct device *dev)
445{
446 u8 gen_pmcon_2;
447
448 /* Indicate DRAM init done for MRC S3 to know it can resume */
449 gen_pmcon_2 = pci_read_config8(dev, GEN_PMCON_2);
450 gen_pmcon_2 |= (1 << 7);
451 pci_write_config8(dev, GEN_PMCON_2, gen_pmcon_2);
452
453 /*
454 * Enable DMI ASPM in the PCH
455 */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200456 RCBA32_AND_OR(DMC, ~(1 << 10), 0);
457 RCBA32_OR(LCAP, (1 << 11)|(1 << 10));
458 RCBA32_OR(LCTL, 0x3);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200459}
460
461static void pch_decode_init(struct device *dev)
462{
463 config_t *config = dev->chip_info;
464
465 printk(BIOS_DEBUG, "pch_decode_init\n");
466
467 pci_write_config32(dev, LPC_GEN1_DEC, config->gen1_dec);
468 pci_write_config32(dev, LPC_GEN2_DEC, config->gen2_dec);
469 pci_write_config32(dev, LPC_GEN3_DEC, config->gen3_dec);
470 pci_write_config32(dev, LPC_GEN4_DEC, config->gen4_dec);
471}
472
Nico Huber7b2f9f62015-10-01 19:00:51 +0200473static void pch_spi_init(const struct device *const dev)
474{
475 const config_t *const config = dev->chip_info;
476
477 printk(BIOS_DEBUG, "pch_spi_init\n");
478
479 if (config->spi_uvscc)
480 RCBA32(0x3800 + 0xc8) = config->spi_uvscc;
481 if (config->spi_lvscc)
482 RCBA32(0x3800 + 0xc4) = config->spi_lvscc;
483
484 if (config->spi_uvscc || config->spi_lvscc)
485 RCBA32_OR(0x3800 + 0xc4, 1 << 23); /* lock both UVSCC + LVSCC */
486}
487
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200488static const struct {
489 u16 dev_id;
490 const char *dev_name;
491} pch_table[] = {
492 /* 6-series PCI ids from
493 * Intel® 6 Series Chipset and
494 * Intel® C200 Series Chipset
495 * Specification Update - NDA
496 * October 2013
497 * CDI / IBP#: 440377
498 */
499 {0x1C41, "SFF Sample"},
500 {0x1C42, "Desktop Sample"},
501 {0x1C43, "Mobile Sample"},
502 {0x1C44, "Z68"},
503 {0x1C46, "P67"},
504 {0x1C47, "UM67"},
505 {0x1C49, "HM65"},
506 {0x1C4A, "H67"},
507 {0x1C4B, "HM67"},
508 {0x1C4C, "Q65"},
509 {0x1C4D, "QS67"},
510 {0x1C4E, "Q67"},
511 {0x1C4F, "QM67"},
512 {0x1C50, "B65"},
513 {0x1C52, "C202"},
514 {0x1C54, "C204"},
515 {0x1C56, "C206"},
516 {0x1C5C, "H61"},
517 /* 7-series PCI ids from Intel document 472178 */
518 {0x1E41, "Desktop Sample"},
519 {0x1E42, "Mobile Sample"},
520 {0x1E43, "SFF Sample"},
521 {0x1E44, "Z77"},
522 {0x1E45, "H71"},
523 {0x1E46, "Z75"},
524 {0x1E47, "Q77"},
525 {0x1E48, "Q75"},
526 {0x1E49, "B75"},
527 {0x1E4A, "H77"},
528 {0x1E53, "C216"},
529 {0x1E55, "QM77"},
530 {0x1E56, "QS77"},
531 {0x1E58, "UM77"},
532 {0x1E57, "HM77"},
533 {0x1E59, "HM76"},
534 {0x1E5D, "HM75"},
535 {0x1E5E, "HM70"},
536 {0x1E5F, "NM70"},
537};
538
539static void report_pch_info(struct device *dev)
540{
541 const u16 dev_id = pci_read_config16(dev, PCI_DEVICE_ID);
542 int i;
543
544 const char *pch_type = "Unknown";
545 for (i = 0; i < ARRAY_SIZE(pch_table); i++) {
546 if (pch_table[i].dev_id == dev_id) {
547 pch_type = pch_table[i].dev_name;
548 break;
549 }
550 }
551 printk(BIOS_INFO, "PCH: detected %s, device id: 0x%x, rev id 0x%x\n",
552 pch_type, dev_id, pci_read_config8(dev, PCI_CLASS_REVISION));
553}
554
Stefan Reinauer8e073822012-04-04 00:07:22 +0200555static void lpc_init(struct device *dev)
556{
557 printk(BIOS_DEBUG, "pch: lpc_init\n");
558
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200559 /* Print detected platform */
560 report_pch_info(dev);
561
Stefan Reinauer8e073822012-04-04 00:07:22 +0200562 /* Set the value for PCI command register. */
563 pci_write_config16(dev, PCI_COMMAND, 0x000f);
564
565 /* IO APIC initialization. */
Paul Menzel9c50e6a2013-05-03 12:23:39 +0200566 pch_enable_ioapic(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200567
568 pch_enable_serial_irqs(dev);
569
570 /* Setup the PIRQ. */
571 pch_pirq_init(dev);
572
573 /* Setup power options. */
574 pch_power_options(dev);
575
576 /* Initialize power management */
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700577 switch (pch_silicon_type()) {
578 case PCH_TYPE_CPT: /* CougarPoint */
579 cpt_pm_init(dev);
580 break;
581 case PCH_TYPE_PPT: /* PantherPoint */
582 ppt_pm_init(dev);
583 break;
584 default:
585 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
586 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200587
588 /* Set the state of the GPIO lines. */
589 //gpio_init(dev);
590
591 /* Initialize the real time clock. */
Patrick Rudolph6b931122018-11-01 17:48:37 +0100592 sb_rtc_init();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200593
594 /* Initialize ISA DMA. */
595 isa_dma_init();
596
597 /* Initialize the High Precision Event Timers, if present. */
Nico Huberb2dae792015-10-26 12:34:02 +0100598 enable_hpet(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200599
600 /* Initialize Clock Gating */
601 enable_clock_gating(dev);
602
603 setup_i8259();
604
605 /* The OS should do this? */
606 /* Interrupt 9 should be level triggered (SCI) */
607 i8259_configure_irq_trigger(9, 1);
608
609 pch_disable_smm_only_flashing(dev);
610
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200611 pch_set_acpi_mode();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200612
613 pch_fixups(dev);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200614
615 pch_spi_init(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200616}
617
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200618static void pch_lpc_read_resources(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200619{
620 struct resource *res;
Marc Jonesa0bec172012-07-13 14:14:34 -0600621 config_t *config = dev->chip_info;
622 u8 io_index = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200623
624 /* Get the normal PCI resources of this device. */
625 pci_dev_read_resources(dev);
626
627 /* Add an extra subtractive resource for both memory and I/O. */
Marc Jonesa0bec172012-07-13 14:14:34 -0600628 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200629 res->base = 0;
630 res->size = 0x1000;
631 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
632 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
633
Marc Jonesa0bec172012-07-13 14:14:34 -0600634 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Vladimir Serbinenko0650cd02014-02-05 15:03:50 +0100635 res->base = 0xff000000;
636 /* Some systems (e.g. X230) have 12 MiB flash.
637 SPI controller supports up to 2 x 16 MiB of flash but
638 address map limits this to 16MiB. */
639 res->size = 0x01000000; /* 16 MB for flash */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200640 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
641 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
642
643 res = new_resource(dev, 3); /* IOAPIC */
644 res->base = IO_APIC_ADDR;
645 res->size = 0x00001000;
646 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Marc Jonesa0bec172012-07-13 14:14:34 -0600647
648 /* Set PCH IO decode ranges if required.*/
649 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
650 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
651 res->base = config->gen1_dec & 0xFFFC;
652 res->size = (config->gen1_dec >> 16) & 0xFC;
653 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
654 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
655 }
656
657 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
658 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
659 res->base = config->gen2_dec & 0xFFFC;
660 res->size = (config->gen2_dec >> 16) & 0xFC;
661 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
662 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
663 }
664
665 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
666 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
667 res->base = config->gen3_dec & 0xFFFC;
668 res->size = (config->gen3_dec >> 16) & 0xFC;
669 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
670 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
671 }
672
673 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
674 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
675 res->base = config->gen4_dec & 0xFFFC;
676 res->size = (config->gen4_dec >> 16) & 0xFC;
677 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
678 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
679 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200680}
681
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200682static void pch_lpc_enable_resources(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200683{
684 pch_decode_init(dev);
685 return pci_dev_enable_resources(dev);
686}
687
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200688static void pch_lpc_enable(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200689{
690 /* Enable PCH Display Port */
691 RCBA16(DISPBDF) = 0x0010;
692 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
693
694 pch_enable(dev);
695}
696
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200697static void southbridge_inject_dsdt(struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200698{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200699 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200700
701 if (gnvs) {
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100702 const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
Elyes HAOUAS035df002016-10-03 21:54:16 +0200703 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200704
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200705 acpi_create_gnvs(gnvs);
Vladimir Serbinenko06c788d2014-10-12 00:17:11 +0200706
707 gnvs->apic = 1;
708 gnvs->mpen = 1; /* Enable Multi Processing */
709 gnvs->pcnt = dev_count_cpu();
710
Nico Huber744d6bd2019-01-12 14:58:20 +0100711 if (gfx) {
712 gnvs->ndid = gfx->ndid;
713 memcpy(gnvs->did, gfx->did, sizeof(gnvs->did));
714 }
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100715
Julius Wernercd49cce2019-03-05 16:53:33 -0800716#if CONFIG(CHROMEOS)
Joel Kitching6fbd8742018-08-23 14:56:25 +0800717 chromeos_init_chromeos_acpi(&(gnvs->chromeos));
Vladimir Serbinenko06c788d2014-10-12 00:17:11 +0200718#endif
719
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200720 /* And tell SMI about it */
721 smm_setup_structures(gnvs, NULL, NULL);
722
Vladimir Serbinenko334fd8e2014-10-05 11:10:35 +0200723 /* Add it to DSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100724 acpigen_write_scope("\\");
725 acpigen_write_name_dword("NVSA", (u32) gnvs);
726 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200727 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200728}
729
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200730void acpi_fill_fadt(acpi_fadt_t *fadt)
731{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300732 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200733 config_t *chip = dev->chip_info;
734 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
735 int c2_latency;
736
Elyes HAOUAS0d4de2a2019-02-28 13:04:29 +0100737 fadt->reserved = 0;
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200738
739 fadt->sci_int = 0x9;
740 fadt->smi_cmd = APM_CNT;
741 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
742 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
743 fadt->s4bios_req = 0x0;
744 fadt->pstate_cnt = 0;
745
746 fadt->pm1a_evt_blk = pmbase;
747 fadt->pm1b_evt_blk = 0x0;
748 fadt->pm1a_cnt_blk = pmbase + 0x4;
749 fadt->pm1b_cnt_blk = 0x0;
750 fadt->pm2_cnt_blk = pmbase + 0x50;
751 fadt->pm_tmr_blk = pmbase + 0x8;
752 fadt->gpe0_blk = pmbase + 0x20;
753 fadt->gpe1_blk = 0;
754
755 fadt->pm1_evt_len = 4;
756 fadt->pm1_cnt_len = 2;
757 fadt->pm2_cnt_len = 1;
758 fadt->pm_tmr_len = 4;
759 fadt->gpe0_blk_len = 16;
760 fadt->gpe1_blk_len = 0;
761 fadt->gpe1_base = 0;
762 fadt->cst_cnt = 0;
763 c2_latency = chip->c2_latency;
764 if (!c2_latency) {
765 c2_latency = 101; /* c2 unsupported */
766 }
767 fadt->p_lvl2_lat = c2_latency;
768 fadt->p_lvl3_lat = 87;
769 fadt->flush_size = 1024;
770 fadt->flush_stride = 16;
Patrick Rudolphb30a47b2019-07-15 18:04:23 +0200771 /* P_CNT not supported */
772 fadt->duty_offset = 0;
773 fadt->duty_width = 0;
774
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +0200775 fadt->day_alrm = 0xd;
776 fadt->mon_alrm = 0x00;
777 fadt->century = 0x00;
778 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
779
780 fadt->flags = ACPI_FADT_WBINVD |
781 ACPI_FADT_C1_SUPPORTED |
782 ACPI_FADT_SLEEP_BUTTON |
783 ACPI_FADT_RESET_REGISTER |
784 ACPI_FADT_SEALED_CASE |
785 ACPI_FADT_S4_RTC_WAKE |
786 ACPI_FADT_PLATFORM_CLOCK;
787 if (chip->docking_supported) {
788 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
789 }
790 if (c2_latency < 100) {
791 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
792 }
793
794 fadt->reset_reg.space_id = 1;
795 fadt->reset_reg.bit_width = 8;
796 fadt->reset_reg.bit_offset = 0;
797 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
798 fadt->reset_reg.addrl = 0xcf9;
799 fadt->reset_reg.addrh = 0;
800
801 fadt->reset_value = 6;
802
803 fadt->x_pm1a_evt_blk.space_id = 1;
804 fadt->x_pm1a_evt_blk.bit_width = 32;
805 fadt->x_pm1a_evt_blk.bit_offset = 0;
806 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
807 fadt->x_pm1a_evt_blk.addrl = pmbase;
808 fadt->x_pm1a_evt_blk.addrh = 0x0;
809
810 fadt->x_pm1b_evt_blk.space_id = 1;
811 fadt->x_pm1b_evt_blk.bit_width = 0;
812 fadt->x_pm1b_evt_blk.bit_offset = 0;
813 fadt->x_pm1b_evt_blk.access_size = 0;
814 fadt->x_pm1b_evt_blk.addrl = 0x0;
815 fadt->x_pm1b_evt_blk.addrh = 0x0;
816
817 fadt->x_pm1a_cnt_blk.space_id = 1;
818 fadt->x_pm1a_cnt_blk.bit_width = 16;
819 fadt->x_pm1a_cnt_blk.bit_offset = 0;
820 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
821 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
822 fadt->x_pm1a_cnt_blk.addrh = 0x0;
823
824 fadt->x_pm1b_cnt_blk.space_id = 1;
825 fadt->x_pm1b_cnt_blk.bit_width = 0;
826 fadt->x_pm1b_cnt_blk.bit_offset = 0;
827 fadt->x_pm1b_cnt_blk.access_size = 0;
828 fadt->x_pm1b_cnt_blk.addrl = 0x0;
829 fadt->x_pm1b_cnt_blk.addrh = 0x0;
830
831 fadt->x_pm2_cnt_blk.space_id = 1;
832 fadt->x_pm2_cnt_blk.bit_width = 8;
833 fadt->x_pm2_cnt_blk.bit_offset = 0;
834 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
835 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
836 fadt->x_pm2_cnt_blk.addrh = 0x0;
837
838 fadt->x_pm_tmr_blk.space_id = 1;
839 fadt->x_pm_tmr_blk.bit_width = 32;
840 fadt->x_pm_tmr_blk.bit_offset = 0;
841 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
842 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
843 fadt->x_pm_tmr_blk.addrh = 0x0;
844
845 fadt->x_gpe0_blk.space_id = 1;
846 fadt->x_gpe0_blk.bit_width = 128;
847 fadt->x_gpe0_blk.bit_offset = 0;
848 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
849 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
850 fadt->x_gpe0_blk.addrh = 0x0;
851
852 fadt->x_gpe1_blk.space_id = 1;
853 fadt->x_gpe1_blk.bit_width = 0;
854 fadt->x_gpe1_blk.bit_offset = 0;
855 fadt->x_gpe1_blk.access_size = 0;
856 fadt->x_gpe1_blk.addrl = 0x0;
857 fadt->x_gpe1_blk.addrh = 0x0;
858}
859
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600860static const char *lpc_acpi_name(const struct device *dev)
Patrick Rudolph604f6982017-06-07 09:46:52 +0200861{
862 return "LPCB";
863}
864
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200865static void southbridge_fill_ssdt(struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100866{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300867 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100868 config_t *chip = dev->chip_info;
869
870 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Tobias Diedrich7f5efd92017-12-14 00:29:01 +0100871 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100872}
873
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200874static void lpc_final(struct device *dev)
875{
Nico Huber8e50b6d2018-02-04 15:52:18 +0100876 u16 spi_opprefix = SPI_OPPREFIX;
877 u16 spi_optype = SPI_OPTYPE;
878 u32 spi_opmenu[2] = { SPI_OPMENU_LOWER, SPI_OPMENU_UPPER };
879
880 /* Configure SPI opcode menu; devicetree may override defaults. */
881 const config_t *const config = dev->chip_info;
882 if (config && config->spi.ops[0].op) {
883 unsigned int i;
884
885 spi_opprefix = 0;
886 spi_optype = 0;
887 spi_opmenu[0] = 0;
888 spi_opmenu[1] = 0;
889 for (i = 0; i < sizeof(spi_opprefix); ++i)
890 spi_opprefix |= config->spi.opprefixes[i] << i * 8;
891 for (i = 0; i < sizeof(spi_opmenu); ++i) {
892 spi_optype |=
893 config->spi.ops[i].is_write << 2 * i |
894 config->spi.ops[i].needs_address << (2 * i + 1);
895 spi_opmenu[i / 4] |=
896 config->spi.ops[i].op << (i % 4) * 8;
897 }
898 }
899 RCBA16(0x3894) = spi_opprefix;
900 RCBA16(0x3896) = spi_optype;
901 RCBA32(0x3898) = spi_opmenu[0];
902 RCBA32(0x389c) = spi_opmenu[1];
903
Bill XIEd533b162017-08-22 16:26:22 +0800904 /* Call SMM finalize() handlers before resume */
Julius Wernercd49cce2019-03-05 16:53:33 -0800905 if (CONFIG(HAVE_SMI_HANDLER)) {
906 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
Bill XIEd533b162017-08-22 16:26:22 +0800907 acpi_is_wakeup_s3()) {
908 outb(APM_CNT_FINALIZE, APM_CNT);
909 }
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200910 }
911}
912
Stefan Reinauer8e073822012-04-04 00:07:22 +0200913static struct pci_operations pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530914 .set_subsystem = pci_dev_set_subsystem,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200915};
916
917static struct device_operations device_ops = {
918 .read_resources = pch_lpc_read_resources,
919 .set_resources = pci_dev_set_resources,
920 .enable_resources = pch_lpc_enable_resources,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200921 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko334fd8e2014-10-05 11:10:35 +0200922 .acpi_inject_dsdt_generator = southbridge_inject_dsdt,
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100923 .acpi_fill_ssdt_generator = southbridge_fill_ssdt,
Patrick Rudolph604f6982017-06-07 09:46:52 +0200924 .acpi_name = lpc_acpi_name,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200925 .init = lpc_init,
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200926 .final = lpc_final,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200927 .enable = pch_lpc_enable,
Kyösti Mälkkid0e212c2015-02-26 20:47:47 +0200928 .scan_bus = scan_lpc_bus,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200929 .ops_pci = &pci_ops,
930};
931
932
Kimarie Hoote6f459c2012-07-14 08:26:08 -0600933/* IDs for LPC device of Intel 6 Series Chipset, Intel 7 Series Chipset, and
934 * Intel C200 Series Chipset
Stefan Reinauer8e073822012-04-04 00:07:22 +0200935 */
936
Vladimir Serbinenko42d55e02016-01-02 01:47:26 +0100937static const unsigned short pci_device_ids[] = {
938 0x1c40, 0x1c41, 0x1c42, 0x1c43, 0x1c44, 0x1c45, 0x1c46, 0x1c47, 0x1c48,
939 0x1c49, 0x1c4a, 0x1c4b, 0x1c4c, 0x1c4d, 0x1c4e, 0x1c4f, 0x1c50, 0x1c51,
940 0x1c52, 0x1c53, 0x1c54, 0x1c55, 0x1c56, 0x1c57, 0x1c58, 0x1c59, 0x1c5a,
941 0x1c5b, 0x1c5c, 0x1c5d, 0x1c5e, 0x1c5f,
942
943 0x1e41, 0x1e42, 0x1e43, 0x1e44, 0x1e45, 0x1e46, 0x1e47, 0x1e48, 0x1e49,
944 0x1e4a, 0x1e4b, 0x1e4c, 0x1e4d, 0x1e4e, 0x1e4f, 0x1e50, 0x1e51, 0x1e52,
945 0x1e53, 0x1e54, 0x1e55, 0x1e56, 0x1e57, 0x1e58, 0x1e59, 0x1e5a, 0x1e5b,
946 0x1e5c, 0x1e5d, 0x1e5e, 0x1e5f,
947
948 0 };
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700949
950static const struct pci_driver pch_lpc __pci_driver = {
951 .ops = &device_ops,
952 .vendor = PCI_VENDOR_ID_INTEL,
953 .devices = pci_device_ids,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200954};