blob: b2e6344143a17a1aa835adbf41179cb1d6a8b488 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer8e073822012-04-04 00:07:22 +02002
3#include <console/console.h>
4#include <device/device.h>
5#include <device/pci.h>
6#include <device/pci_ids.h>
Patrick Rudolphe56189c2018-04-18 10:11:59 +02007#include <device/pci_ops.h>
Patrick Rudolphef8c5592018-07-27 17:48:27 +02008#include <device/pci_def.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +02009#include <option.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020010#include <pc80/isa-dma.h>
11#include <pc80/i8259.h>
12#include <arch/io.h>
13#include <arch/ioapic.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070014#include <acpi/acpi.h>
15#include <acpi/acpigen.h>
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +020016#include <cpu/x86/smm.h>
Vladimir Serbinenko7309c642014-10-05 11:07:33 +020017#include <string.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030018#include "chip.h"
Stefan Reinauer8e073822012-04-04 00:07:22 +020019#include "pch.h"
Michał Żygowski9ff2af22020-04-13 20:37:36 +020020#include <northbridge/intel/sandybridge/sandybridge.h>
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010021#include <southbridge/intel/common/pciehp.h>
Tobias Diedrich7f5efd92017-12-14 00:29:01 +010022#include <southbridge/intel/common/acpi_pirq_gen.h>
Arthur Heymansa0508172018-01-25 11:30:22 +010023#include <southbridge/intel/common/pmutil.h>
Tim Wawrzynczakf62c4942021-02-26 10:30:52 -070024#include <southbridge/intel/common/rcba_pirq.h>
Patrick Rudolph6b931122018-11-01 17:48:37 +010025#include <southbridge/intel/common/rtc.h>
Arthur Heymansebf201b2019-05-28 13:51:36 +020026#include <southbridge/intel/common/spi.h>
Elyes HAOUAS608a75c2021-02-12 08:09:58 +010027#include <types.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020028
29#define NMI_OFF 0
30
Stefan Reinauer8e073822012-04-04 00:07:22 +020031typedef struct southbridge_intel_bd82x6x_config config_t;
32
Paul Menzel9c50e6a2013-05-03 12:23:39 +020033/**
Martin Roth26f97f92021-10-01 14:53:22 -060034 * Set miscellaneous static southbridge features.
Paul Menzel9c50e6a2013-05-03 12:23:39 +020035 *
36 * @param dev PCI device with I/O APIC control registers
37 */
38static void pch_enable_ioapic(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020039{
Nico Huberb2dae792015-10-26 12:34:02 +010040 /* Assign unique bus/dev/fn for I/O APIC */
41 pci_write_config16(dev, LPC_IBDF,
42 PCH_IOAPIC_PCI_BUS << 8 | PCH_IOAPIC_PCI_SLOT << 3);
43
Stefan Reinauer8e073822012-04-04 00:07:22 +020044 /* affirm full set of redirection table entries ("write once") */
Kyösti Mälkki04a40372021-06-06 08:04:28 +030045 ioapic_lock_max_vectors(VIO_APIC_VADDR);
Kyösti Mälkkiea6d12a2021-06-08 11:25:29 +030046
Kyösti Mälkki682613f2021-06-08 11:31:19 +030047 setup_ioapic(VIO_APIC_VADDR, 0x02);
Stefan Reinauer8e073822012-04-04 00:07:22 +020048}
49
50static void pch_enable_serial_irqs(struct device *dev)
51{
52 /* Set packet length and toggle silent mode bit for one frame. */
53 pci_write_config8(dev, SERIRQ_CNTL,
54 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080055#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Stefan Reinauer8e073822012-04-04 00:07:22 +020056 pci_write_config8(dev, SERIRQ_CNTL,
57 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
58#endif
59}
60
61/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
62 * 0x00 - 0000 = Reserved
63 * 0x01 - 0001 = Reserved
64 * 0x02 - 0010 = Reserved
65 * 0x03 - 0011 = IRQ3
66 * 0x04 - 0100 = IRQ4
67 * 0x05 - 0101 = IRQ5
68 * 0x06 - 0110 = IRQ6
69 * 0x07 - 0111 = IRQ7
70 * 0x08 - 1000 = Reserved
71 * 0x09 - 1001 = IRQ9
72 * 0x0A - 1010 = IRQ10
73 * 0x0B - 1011 = IRQ11
74 * 0x0C - 1100 = IRQ12
75 * 0x0D - 1101 = Reserved
76 * 0x0E - 1110 = IRQ14
77 * 0x0F - 1111 = IRQ15
78 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
79 * 0x80 - The PIRQ is not routed.
80 */
81
Elyes HAOUAS4aec3402018-05-25 08:29:27 +020082static void pch_pirq_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020083{
Elyes HAOUAS4aec3402018-05-25 08:29:27 +020084 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020085 /* Interrupt 11 is not used by legacy devices and so can always be used for
86 PCI interrupts. Full legacy IRQ routing is complicated and hard to
87 get right. Fortunately all modern OS use MSI and so it's not that big of
88 an issue anyway. Still we have to provide a reasonable default. Using
89 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
90 move it to any interrupt and others will just leave them at default.
Stefan Reinauer8e073822012-04-04 00:07:22 +020091 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020092 const u8 pirq_routing = 11;
93
94 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
95 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
96 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
97 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
98
99 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
100 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
101 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
102 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200103
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200104 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200105 u8 int_pin=0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200106
107 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
108 continue;
109
110 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
111
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200112 if (int_pin == 0)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200113 continue;
114
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200115 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200116 }
117}
118
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200119static void pch_gpi_routing(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200120{
121 /* Get the chip configuration */
122 config_t *config = dev->chip_info;
123 u32 reg32 = 0;
124
125 /* An array would be much nicer here, or some
126 * other method of doing this.
127 */
128 reg32 |= (config->gpi0_routing & 0x03) << 0;
129 reg32 |= (config->gpi1_routing & 0x03) << 2;
130 reg32 |= (config->gpi2_routing & 0x03) << 4;
131 reg32 |= (config->gpi3_routing & 0x03) << 6;
132 reg32 |= (config->gpi4_routing & 0x03) << 8;
133 reg32 |= (config->gpi5_routing & 0x03) << 10;
134 reg32 |= (config->gpi6_routing & 0x03) << 12;
135 reg32 |= (config->gpi7_routing & 0x03) << 14;
136 reg32 |= (config->gpi8_routing & 0x03) << 16;
137 reg32 |= (config->gpi9_routing & 0x03) << 18;
138 reg32 |= (config->gpi10_routing & 0x03) << 20;
139 reg32 |= (config->gpi11_routing & 0x03) << 22;
140 reg32 |= (config->gpi12_routing & 0x03) << 24;
141 reg32 |= (config->gpi13_routing & 0x03) << 26;
142 reg32 |= (config->gpi14_routing & 0x03) << 28;
143 reg32 |= (config->gpi15_routing & 0x03) << 30;
144
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200145 pci_write_config32(dev, GPIO_ROUT, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200146}
147
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200148static void pch_power_options(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200149{
150 u8 reg8;
151 u16 reg16, pmbase;
152 u32 reg32;
153 const char *state;
154 /* Get the chip configuration */
155 config_t *config = dev->chip_info;
156
Stefan Reinauer8e073822012-04-04 00:07:22 +0200157 /* Which state do we want to goto after g3 (power restored)?
158 * 0 == S0 Full On
159 * 1 == S5 Soft Off
160 *
161 * If the option is not existent (Laptops), use Kconfig setting.
162 */
Angel Pons88dcb312021-04-26 17:10:28 +0200163 const unsigned int pwr_on = get_uint_option("power_on_after_fail",
Angel Pons62719a32021-04-19 13:15:28 +0200164 CONFIG_MAINBOARD_POWER_FAILURE_STATE);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200165
166 reg16 = pci_read_config16(dev, GEN_PMCON_3);
167 reg16 &= 0xfffe;
168 switch (pwr_on) {
169 case MAINBOARD_POWER_OFF:
170 reg16 |= 1;
171 state = "off";
172 break;
173 case MAINBOARD_POWER_ON:
174 reg16 &= ~1;
175 state = "on";
176 break;
177 case MAINBOARD_POWER_KEEP:
178 reg16 &= ~1;
179 state = "state keep";
180 break;
181 default:
182 state = "undefined";
183 }
184
185 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
186 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
187
188 reg16 &= ~(1 << 10);
189 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
190
191 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
192
193 pci_write_config16(dev, GEN_PMCON_3, reg16);
194 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
195
196 /* Set up NMI on errors. */
197 reg8 = inb(0x61);
198 reg8 &= 0x0f; /* Higher Nibble must be 0 */
199 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
200 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
201 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
202 outb(reg8, 0x61);
203
204 reg8 = inb(0x70);
Angel Pons88dcb312021-04-26 17:10:28 +0200205 const unsigned int nmi_option = get_uint_option("nmi", NMI_OFF);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200206 if (nmi_option) {
207 printk(BIOS_INFO, "NMI sources enabled.\n");
208 reg8 &= ~(1 << 7); /* Set NMI. */
209 } else {
210 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200211 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200212 }
213 outb(reg8, 0x70);
214
215 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
216 reg16 = pci_read_config16(dev, GEN_PMCON_1);
217 reg16 &= ~(3 << 0); // SMI# rate 1 minute
218 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
Kyösti Mälkki94464472020-06-13 13:45:42 +0300219 if (CONFIG(DEBUG_PERIODIC_SMI))
220 reg16 |= (3 << 0); // Periodic SMI every 8s
Stefan Reinauer8e073822012-04-04 00:07:22 +0200221 pci_write_config16(dev, GEN_PMCON_1, reg16);
222
223 // Set the board's GPI routing.
224 pch_gpi_routing(dev);
225
226 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
227
228 outl(config->gpe0_en, pmbase + GPE0_EN);
229 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
230
231 /* Set up power management block and determine sleep mode */
232 reg32 = inl(pmbase + 0x04); // PM1_CNT
233 reg32 &= ~(7 << 10); // SLP_TYP
234 reg32 |= (1 << 0); // SCI_EN
235 outl(reg32, pmbase + 0x04);
236
237 /* Clear magic status bits to prevent unexpected wake */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200238 reg32 = RCBA32(PRSTS);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200239 reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200240 RCBA32(PRSTS) = reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200241
242 reg32 = RCBA32(0x3f02);
243 reg32 &= ~0xf;
244 RCBA32(0x3f02) = reg32;
245}
246
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700247/* CougarPoint PCH Power Management init */
248static void cpt_pm_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200249{
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700250 printk(BIOS_DEBUG, "CougarPoint PM init\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200251 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200252 RCBA32_AND_OR(CIR30, ~0U, (1 << 6)|(1 << 0));
253 RCBA32_AND_OR(CIR5, ~0U, (1 << 0));
254 RCBA16_AND_OR(CIR3, ~0U, (1 << 13)|(1 << 14));
255 RCBA16_AND_OR(CIR2, ~0U, (1 << 14));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200256 RCBA32(DMC) = 0xc0388400;
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200257 RCBA32_AND_OR(CIR6, ~0U, (1 << 5)|(1 << 18));
258 RCBA32_AND_OR(CIR9, ~0U, (1 << 15)|(1 << 1));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200259 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
260 RCBA32(PM_CFG) = 0x050f0000;
261 RCBA32(CIR8) = 0x04000000;
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200262 RCBA32_AND_OR(CIR10, ~0U, 0xfffff);
263 RCBA32_AND_OR(CIR11, ~0U, (1 << 1));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200264 RCBA32(CIR12) = 0x0001c000;
265 RCBA32(CIR14) = 0x00061100;
266 RCBA32(CIR15) = 0x7f8fdfff;
267 RCBA32(CIR13) = 0x000003fc;
268 RCBA32(CIR16) = 0x00001000;
269 RCBA32(CIR18) = 0x0001c000;
270 RCBA32(CIR17) = 0x00000800;
271 RCBA32(CIR23) = 0x00001000;
272 RCBA32(CIR19) = 0x00093900;
273 RCBA32(CIR20) = 0x24653002;
274 RCBA32(CIR21) = 0x062108fe;
275 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
276 RCBA32(CIR24) = 0x01010000;
277 RCBA32(CIR25) = 0x01010404;
278 RCBA32(CIR27) = 0x01041041;
279 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
280 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
281 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
282 RCBA32(CIR26) = 0x00000001;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200283 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
284 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200285 RCBA32(PMSYNC_CFG) = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200286 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
287}
288
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700289/* PantherPoint PCH Power Management init */
290static void ppt_pm_init(struct device *dev)
291{
292 printk(BIOS_DEBUG, "PantherPoint PM init\n");
293 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200294 RCBA32_AND_OR(CIR30, ~0UL, (1 << 0));
295 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
296 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
297 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
298 RCBA32(DMC) = 0xc03b8400;
299 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
300 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
301 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
302 RCBA32(PM_CFG) = 0x054f0000;
303 RCBA32(CIR8) = 0x04000000;
304 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
305 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1)|(1 << 0));
306 RCBA32(CIR12) = 0x0001c000;
307 RCBA32(CIR14) = 0x00061100;
308 RCBA32(CIR15) = 0x7f8fdfff;
309 RCBA32(CIR13) = 0x000003fd;
310 RCBA32(CIR16) = 0x00001000;
311 RCBA32(CIR18) = 0x0001c000;
312 RCBA32(CIR17) = 0x00000800;
313 RCBA32(CIR23) = 0x00001000;
314 RCBA32(CIR19) = 0x00093900;
315 RCBA32(CIR20) = 0x24653002;
316 RCBA32(CIR21) = 0x067388fe;
317 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
318 RCBA32(CIR24) = 0x01010000;
319 RCBA32(CIR25) = 0x01010404;
320 RCBA32(CIR27) = 0x01040000;
321 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
322 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
323 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
324 RCBA32(CIR26) = 0x00000001;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700325 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
326 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
327 RCBA32_AND_OR(0x33a4, ~0UL, (1 << 0));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200328 RCBA32(PMSYNC_CFG) = 0;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700329 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
330}
331
Nico Huberb2dae792015-10-26 12:34:02 +0100332static void enable_hpet(struct device *const dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200333{
334 u32 reg32;
Nico Huberb2dae792015-10-26 12:34:02 +0100335 size_t i;
336
337 /* Assign unique bus/dev/fn for each HPET */
338 for (i = 0; i < 8; ++i)
339 pci_write_config16(dev, LPC_HnBDF(i),
340 PCH_HPET_PCI_BUS << 8 | PCH_HPET_PCI_SLOT << 3 | i);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200341
342 /* Move HPET to default address 0xfed00000 and enable it */
343 reg32 = RCBA32(HPTC);
344 reg32 |= (1 << 7); // HPET Address Enable
345 reg32 &= ~(3 << 0);
346 RCBA32(HPTC) = reg32;
347}
348
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200349static void enable_clock_gating(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200350{
351 u32 reg32;
352 u16 reg16;
353
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200354 RCBA32_AND_OR(DMIC, ~0UL, 0xf);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200355
356 reg16 = pci_read_config16(dev, GEN_PMCON_1);
Michał Żygowski9ff2af22020-04-13 20:37:36 +0200357 reg16 &= ~(3 << 2); /* Clear CLKRUN bits for mobile and desktop */
358 if (get_platform_type() == PLATFORM_MOBILE)
359 reg16 |= (1 << 2); /* CLKRUN_EN for mobile */
360 else if (get_platform_type() == PLATFORM_DESKTOP_SERVER)
361 reg16 |= (1 << 3); /* PSEUDO_CLKRUN_EN for desktop */
362 reg16 |= (1 << 11);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200363 pci_write_config16(dev, GEN_PMCON_1, reg16);
364
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200365 pch_iobp_update(0xEB007F07, ~0U, (1 << 31));
366 pch_iobp_update(0xEB004000, ~0U, (1 << 7));
367 pch_iobp_update(0xEC007F07, ~0U, (1 << 31));
368 pch_iobp_update(0xEC004000, ~0U, (1 << 7));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200369
370 reg32 = RCBA32(CG);
371 reg32 |= (1 << 31);
372 reg32 |= (1 << 29) | (1 << 28);
373 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
374 reg32 |= (1 << 16);
375 reg32 |= (1 << 17);
376 reg32 |= (1 << 18);
377 reg32 |= (1 << 22);
378 reg32 |= (1 << 23);
379 reg32 &= ~(1 << 20);
380 reg32 |= (1 << 19);
381 reg32 |= (1 << 0);
382 reg32 |= (0xf << 1);
383 RCBA32(CG) = reg32;
384
385 RCBA32_OR(0x38c0, 0x7);
386 RCBA32_OR(0x36d4, 0x6680c004);
387 RCBA32_OR(0x3564, 0x3);
388}
389
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200390static void pch_set_acpi_mode(void)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200391{
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300392 if (!acpi_is_wakeup_s3()) {
Kyösti Mälkkib6585482020-06-01 15:11:14 +0300393 apm_control(APM_CNT_ACPI_DISABLE);
Duncan Laurie95be1d62012-04-09 12:31:43 -0700394 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200395}
Stefan Reinauer8e073822012-04-04 00:07:22 +0200396
Stefan Reinauer8e073822012-04-04 00:07:22 +0200397static void pch_fixups(struct device *dev)
398{
Stefan Reinauer8e073822012-04-04 00:07:22 +0200399 /* Indicate DRAM init done for MRC S3 to know it can resume */
Angel Ponsc803f652020-06-07 22:09:01 +0200400 pci_or_config8(dev, GEN_PMCON_2, 1 << 7);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200401
402 /*
403 * Enable DMI ASPM in the PCH
404 */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200405 RCBA32_AND_OR(DMC, ~(1 << 10), 0);
406 RCBA32_OR(LCAP, (1 << 11)|(1 << 10));
407 RCBA32_OR(LCTL, 0x3);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200408}
409
Nico Huber7b2f9f62015-10-01 19:00:51 +0200410static void pch_spi_init(const struct device *const dev)
411{
412 const config_t *const config = dev->chip_info;
413
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100414 printk(BIOS_DEBUG, "%s\n", __func__);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200415
416 if (config->spi_uvscc)
417 RCBA32(0x3800 + 0xc8) = config->spi_uvscc;
418 if (config->spi_lvscc)
419 RCBA32(0x3800 + 0xc4) = config->spi_lvscc;
420
421 if (config->spi_uvscc || config->spi_lvscc)
422 RCBA32_OR(0x3800 + 0xc4, 1 << 23); /* lock both UVSCC + LVSCC */
423}
424
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200425static const struct {
426 u16 dev_id;
427 const char *dev_name;
428} pch_table[] = {
429 /* 6-series PCI ids from
430 * Intel® 6 Series Chipset and
431 * Intel® C200 Series Chipset
432 * Specification Update - NDA
433 * October 2013
434 * CDI / IBP#: 440377
435 */
436 {0x1C41, "SFF Sample"},
437 {0x1C42, "Desktop Sample"},
438 {0x1C43, "Mobile Sample"},
439 {0x1C44, "Z68"},
440 {0x1C46, "P67"},
441 {0x1C47, "UM67"},
442 {0x1C49, "HM65"},
443 {0x1C4A, "H67"},
444 {0x1C4B, "HM67"},
445 {0x1C4C, "Q65"},
446 {0x1C4D, "QS67"},
447 {0x1C4E, "Q67"},
448 {0x1C4F, "QM67"},
449 {0x1C50, "B65"},
450 {0x1C52, "C202"},
451 {0x1C54, "C204"},
452 {0x1C56, "C206"},
453 {0x1C5C, "H61"},
454 /* 7-series PCI ids from Intel document 472178 */
455 {0x1E41, "Desktop Sample"},
456 {0x1E42, "Mobile Sample"},
457 {0x1E43, "SFF Sample"},
458 {0x1E44, "Z77"},
459 {0x1E45, "H71"},
460 {0x1E46, "Z75"},
461 {0x1E47, "Q77"},
462 {0x1E48, "Q75"},
463 {0x1E49, "B75"},
464 {0x1E4A, "H77"},
465 {0x1E53, "C216"},
466 {0x1E55, "QM77"},
467 {0x1E56, "QS77"},
468 {0x1E58, "UM77"},
469 {0x1E57, "HM77"},
470 {0x1E59, "HM76"},
471 {0x1E5D, "HM75"},
472 {0x1E5E, "HM70"},
473 {0x1E5F, "NM70"},
474};
475
476static void report_pch_info(struct device *dev)
477{
478 const u16 dev_id = pci_read_config16(dev, PCI_DEVICE_ID);
479 int i;
480
481 const char *pch_type = "Unknown";
482 for (i = 0; i < ARRAY_SIZE(pch_table); i++) {
483 if (pch_table[i].dev_id == dev_id) {
484 pch_type = pch_table[i].dev_name;
485 break;
486 }
487 }
488 printk(BIOS_INFO, "PCH: detected %s, device id: 0x%x, rev id 0x%x\n",
489 pch_type, dev_id, pci_read_config8(dev, PCI_CLASS_REVISION));
490}
491
Stefan Reinauer8e073822012-04-04 00:07:22 +0200492static void lpc_init(struct device *dev)
493{
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100494 printk(BIOS_DEBUG, "pch: %s\n", __func__);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200495
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200496 /* Print detected platform */
497 report_pch_info(dev);
498
Stefan Reinauer8e073822012-04-04 00:07:22 +0200499 /* IO APIC initialization. */
Paul Menzel9c50e6a2013-05-03 12:23:39 +0200500 pch_enable_ioapic(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200501
502 pch_enable_serial_irqs(dev);
503
504 /* Setup the PIRQ. */
505 pch_pirq_init(dev);
506
507 /* Setup power options. */
508 pch_power_options(dev);
509
510 /* Initialize power management */
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700511 switch (pch_silicon_type()) {
512 case PCH_TYPE_CPT: /* CougarPoint */
513 cpt_pm_init(dev);
514 break;
515 case PCH_TYPE_PPT: /* PantherPoint */
516 ppt_pm_init(dev);
517 break;
518 default:
519 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
520 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200521
Stefan Reinauer8e073822012-04-04 00:07:22 +0200522 /* Initialize the real time clock. */
Patrick Rudolph6b931122018-11-01 17:48:37 +0100523 sb_rtc_init();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200524
525 /* Initialize ISA DMA. */
526 isa_dma_init();
527
528 /* Initialize the High Precision Event Timers, if present. */
Nico Huberb2dae792015-10-26 12:34:02 +0100529 enable_hpet(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200530
531 /* Initialize Clock Gating */
532 enable_clock_gating(dev);
533
534 setup_i8259();
535
536 /* The OS should do this? */
537 /* Interrupt 9 should be level triggered (SCI) */
538 i8259_configure_irq_trigger(9, 1);
539
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200540 pch_set_acpi_mode();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200541
542 pch_fixups(dev);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200543
544 pch_spi_init(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200545}
546
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200547static void pch_lpc_read_resources(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200548{
549 struct resource *res;
Marc Jonesa0bec172012-07-13 14:14:34 -0600550 config_t *config = dev->chip_info;
551 u8 io_index = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200552
553 /* Get the normal PCI resources of this device. */
554 pci_dev_read_resources(dev);
555
556 /* Add an extra subtractive resource for both memory and I/O. */
Marc Jonesa0bec172012-07-13 14:14:34 -0600557 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200558 res->base = 0;
559 res->size = 0x1000;
560 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
561 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
562
Marc Jonesa0bec172012-07-13 14:14:34 -0600563 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Vladimir Serbinenko0650cd02014-02-05 15:03:50 +0100564 res->base = 0xff000000;
565 /* Some systems (e.g. X230) have 12 MiB flash.
566 SPI controller supports up to 2 x 16 MiB of flash but
567 address map limits this to 16MiB. */
568 res->size = 0x01000000; /* 16 MB for flash */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200569 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
570 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
571
572 res = new_resource(dev, 3); /* IOAPIC */
573 res->base = IO_APIC_ADDR;
574 res->size = 0x00001000;
575 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Marc Jonesa0bec172012-07-13 14:14:34 -0600576
577 /* Set PCH IO decode ranges if required.*/
578 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
579 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
580 res->base = config->gen1_dec & 0xFFFC;
581 res->size = (config->gen1_dec >> 16) & 0xFC;
582 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
583 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
584 }
585
586 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
587 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
588 res->base = config->gen2_dec & 0xFFFC;
589 res->size = (config->gen2_dec >> 16) & 0xFC;
590 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
591 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
592 }
593
594 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
595 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
596 res->base = config->gen3_dec & 0xFFFC;
597 res->size = (config->gen3_dec >> 16) & 0xFC;
598 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
599 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
600 }
601
602 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
603 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
604 res->base = config->gen4_dec & 0xFFFC;
605 res->size = (config->gen4_dec >> 16) & 0xFC;
606 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
607 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
608 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200609}
610
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200611static void pch_lpc_enable(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200612{
613 /* Enable PCH Display Port */
614 RCBA16(DISPBDF) = 0x0010;
615 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
616
617 pch_enable(dev);
618}
619
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600620static const char *lpc_acpi_name(const struct device *dev)
Patrick Rudolph604f6982017-06-07 09:46:52 +0200621{
622 return "LPCB";
623}
624
Furquan Shaikh7536a392020-04-24 21:59:21 -0700625static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100626{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300627 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100628 config_t *chip = dev->chip_info;
629
630 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Tobias Diedrich7f5efd92017-12-14 00:29:01 +0100631 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100632}
633
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200634static void lpc_final(struct device *dev)
635{
Arthur Heymansebf201b2019-05-28 13:51:36 +0200636 spi_finalize_ops();
Nico Huber8e50b6d2018-02-04 15:52:18 +0100637
Bill XIEd533b162017-08-22 16:26:22 +0800638 /* Call SMM finalize() handlers before resume */
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300639 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
640 acpi_is_wakeup_s3()) {
641 apm_control(APM_CNT_FINALIZE);
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200642 }
643}
644
Arthur Heymansebf201b2019-05-28 13:51:36 +0200645void intel_southbridge_override_spi(
646 struct intel_swseq_spi_config *spi_config)
647{
648 struct device *dev = pcidev_on_root(0x1f, 0);
649
650 if (!dev)
651 return;
652 /* Devicetree may override defaults. */
653 const config_t *const config = dev->chip_info;
654
655 if (!config)
656 return;
657
658 if (config->spi.ops[0].op != 0)
659 memcpy(spi_config, &config->spi, sizeof(*spi_config));
660}
661
Stefan Reinauer8e073822012-04-04 00:07:22 +0200662static struct device_operations device_ops = {
663 .read_resources = pch_lpc_read_resources,
664 .set_resources = pci_dev_set_resources,
Arthur Heymans3cde4942019-08-18 10:02:10 +0200665 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200666 .write_acpi_tables = acpi_write_hpet,
Nico Huber68680dd2020-03-31 17:34:52 +0200667 .acpi_fill_ssdt = southbridge_fill_ssdt,
Patrick Rudolph604f6982017-06-07 09:46:52 +0200668 .acpi_name = lpc_acpi_name,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200669 .init = lpc_init,
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200670 .final = lpc_final,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200671 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100672 .scan_bus = scan_static_bus,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200673 .ops_pci = &pci_dev_ops_pci,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200674};
675
Kimarie Hoote6f459c2012-07-14 08:26:08 -0600676/* IDs for LPC device of Intel 6 Series Chipset, Intel 7 Series Chipset, and
677 * Intel C200 Series Chipset
Stefan Reinauer8e073822012-04-04 00:07:22 +0200678 */
679
Vladimir Serbinenko42d55e02016-01-02 01:47:26 +0100680static const unsigned short pci_device_ids[] = {
681 0x1c40, 0x1c41, 0x1c42, 0x1c43, 0x1c44, 0x1c45, 0x1c46, 0x1c47, 0x1c48,
682 0x1c49, 0x1c4a, 0x1c4b, 0x1c4c, 0x1c4d, 0x1c4e, 0x1c4f, 0x1c50, 0x1c51,
683 0x1c52, 0x1c53, 0x1c54, 0x1c55, 0x1c56, 0x1c57, 0x1c58, 0x1c59, 0x1c5a,
684 0x1c5b, 0x1c5c, 0x1c5d, 0x1c5e, 0x1c5f,
685
686 0x1e41, 0x1e42, 0x1e43, 0x1e44, 0x1e45, 0x1e46, 0x1e47, 0x1e48, 0x1e49,
687 0x1e4a, 0x1e4b, 0x1e4c, 0x1e4d, 0x1e4e, 0x1e4f, 0x1e50, 0x1e51, 0x1e52,
688 0x1e53, 0x1e54, 0x1e55, 0x1e56, 0x1e57, 0x1e58, 0x1e59, 0x1e5a, 0x1e5b,
689 0x1e5c, 0x1e5d, 0x1e5e, 0x1e5f,
690
691 0 };
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700692
693static const struct pci_driver pch_lpc __pci_driver = {
694 .ops = &device_ops,
Felix Singer43b7f412022-03-07 04:34:52 +0100695 .vendor = PCI_VID_INTEL,
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700696 .devices = pci_device_ids,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200697};