blob: 5d1a7bf68abcda89969d244774a4406610fa96d3 [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>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +02008#include <option.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +02009#include <pc80/isa-dma.h>
10#include <pc80/i8259.h>
11#include <arch/io.h>
12#include <arch/ioapic.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070013#include <acpi/acpi.h>
14#include <acpi/acpigen.h>
Vladimir Serbinenko5b044ae2014-10-25 15:20:55 +020015#include <cpu/x86/smm.h>
Vladimir Serbinenko7309c642014-10-05 11:07:33 +020016#include <string.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030017#include "chip.h"
Stefan Reinauer8e073822012-04-04 00:07:22 +020018#include "pch.h"
Michał Żygowski9ff2af22020-04-13 20:37:36 +020019#include <northbridge/intel/sandybridge/sandybridge.h>
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010020#include <southbridge/intel/common/pciehp.h>
Tobias Diedrich7f5efd92017-12-14 00:29:01 +010021#include <southbridge/intel/common/acpi_pirq_gen.h>
Arthur Heymansa0508172018-01-25 11:30:22 +010022#include <southbridge/intel/common/pmutil.h>
Tim Wawrzynczakf62c4942021-02-26 10:30:52 -070023#include <southbridge/intel/common/rcba_pirq.h>
Patrick Rudolph6b931122018-11-01 17:48:37 +010024#include <southbridge/intel/common/rtc.h>
Arthur Heymansebf201b2019-05-28 13:51:36 +020025#include <southbridge/intel/common/spi.h>
Elyes HAOUAS608a75c2021-02-12 08:09:58 +010026#include <types.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020027
28#define NMI_OFF 0
29
Stefan Reinauer8e073822012-04-04 00:07:22 +020030typedef struct southbridge_intel_bd82x6x_config config_t;
31
Paul Menzel9c50e6a2013-05-03 12:23:39 +020032/**
Martin Roth26f97f92021-10-01 14:53:22 -060033 * Set miscellaneous static southbridge features.
Paul Menzel9c50e6a2013-05-03 12:23:39 +020034 *
35 * @param dev PCI device with I/O APIC control registers
36 */
37static void pch_enable_ioapic(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020038{
Nico Huberb2dae792015-10-26 12:34:02 +010039 /* Assign unique bus/dev/fn for I/O APIC */
40 pci_write_config16(dev, LPC_IBDF,
41 PCH_IOAPIC_PCI_BUS << 8 | PCH_IOAPIC_PCI_SLOT << 3);
42
Stefan Reinauer8e073822012-04-04 00:07:22 +020043 /* affirm full set of redirection table entries ("write once") */
Kyösti Mälkki04a40372021-06-06 08:04:28 +030044 ioapic_lock_max_vectors(VIO_APIC_VADDR);
Kyösti Mälkkiea6d12a2021-06-08 11:25:29 +030045
Kyösti Mälkkid1653572021-06-08 11:31:19 +030046 register_new_ioapic_gsi0(VIO_APIC_VADDR);
Stefan Reinauer8e073822012-04-04 00:07:22 +020047}
48
49static void pch_enable_serial_irqs(struct device *dev)
50{
51 /* Set packet length and toggle silent mode bit for one frame. */
52 pci_write_config8(dev, SERIRQ_CNTL,
53 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080054#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Stefan Reinauer8e073822012-04-04 00:07:22 +020055 pci_write_config8(dev, SERIRQ_CNTL,
56 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
57#endif
58}
59
60/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
61 * 0x00 - 0000 = Reserved
62 * 0x01 - 0001 = Reserved
63 * 0x02 - 0010 = Reserved
64 * 0x03 - 0011 = IRQ3
65 * 0x04 - 0100 = IRQ4
66 * 0x05 - 0101 = IRQ5
67 * 0x06 - 0110 = IRQ6
68 * 0x07 - 0111 = IRQ7
69 * 0x08 - 1000 = Reserved
70 * 0x09 - 1001 = IRQ9
71 * 0x0A - 1010 = IRQ10
72 * 0x0B - 1011 = IRQ11
73 * 0x0C - 1100 = IRQ12
74 * 0x0D - 1101 = Reserved
75 * 0x0E - 1110 = IRQ14
76 * 0x0F - 1111 = IRQ15
77 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
78 * 0x80 - The PIRQ is not routed.
79 */
80
Elyes HAOUAS4aec3402018-05-25 08:29:27 +020081static void pch_pirq_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020082{
Elyes HAOUAS4aec3402018-05-25 08:29:27 +020083 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020084 /* Interrupt 11 is not used by legacy devices and so can always be used for
85 PCI interrupts. Full legacy IRQ routing is complicated and hard to
86 get right. Fortunately all modern OS use MSI and so it's not that big of
87 an issue anyway. Still we have to provide a reasonable default. Using
88 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
89 move it to any interrupt and others will just leave them at default.
Stefan Reinauer8e073822012-04-04 00:07:22 +020090 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020091 const u8 pirq_routing = 11;
92
93 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
94 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
95 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
96 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
97
98 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
99 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
100 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
101 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200102
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200103 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200104 u8 int_pin=0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200105
Fabio Aiutod835da92022-09-30 11:25:28 +0200106 if (!is_enabled_pci(irq_dev))
Stefan Reinauer8e073822012-04-04 00:07:22 +0200107 continue;
108
109 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
110
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200111 if (int_pin == 0)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200112 continue;
113
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200114 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200115 }
116}
117
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200118static void pch_gpi_routing(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200119{
120 /* Get the chip configuration */
121 config_t *config = dev->chip_info;
122 u32 reg32 = 0;
123
124 /* An array would be much nicer here, or some
125 * other method of doing this.
126 */
127 reg32 |= (config->gpi0_routing & 0x03) << 0;
128 reg32 |= (config->gpi1_routing & 0x03) << 2;
129 reg32 |= (config->gpi2_routing & 0x03) << 4;
130 reg32 |= (config->gpi3_routing & 0x03) << 6;
131 reg32 |= (config->gpi4_routing & 0x03) << 8;
132 reg32 |= (config->gpi5_routing & 0x03) << 10;
133 reg32 |= (config->gpi6_routing & 0x03) << 12;
134 reg32 |= (config->gpi7_routing & 0x03) << 14;
135 reg32 |= (config->gpi8_routing & 0x03) << 16;
136 reg32 |= (config->gpi9_routing & 0x03) << 18;
137 reg32 |= (config->gpi10_routing & 0x03) << 20;
138 reg32 |= (config->gpi11_routing & 0x03) << 22;
139 reg32 |= (config->gpi12_routing & 0x03) << 24;
140 reg32 |= (config->gpi13_routing & 0x03) << 26;
141 reg32 |= (config->gpi14_routing & 0x03) << 28;
142 reg32 |= (config->gpi15_routing & 0x03) << 30;
143
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200144 pci_write_config32(dev, GPIO_ROUT, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200145}
146
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200147static void pch_power_options(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200148{
149 u8 reg8;
150 u16 reg16, pmbase;
151 u32 reg32;
152 const char *state;
153 /* Get the chip configuration */
154 config_t *config = dev->chip_info;
155
Stefan Reinauer8e073822012-04-04 00:07:22 +0200156 /* Which state do we want to goto after g3 (power restored)?
157 * 0 == S0 Full On
158 * 1 == S5 Soft Off
159 *
160 * If the option is not existent (Laptops), use Kconfig setting.
161 */
Angel Pons88dcb312021-04-26 17:10:28 +0200162 const unsigned int pwr_on = get_uint_option("power_on_after_fail",
Angel Pons62719a32021-04-19 13:15:28 +0200163 CONFIG_MAINBOARD_POWER_FAILURE_STATE);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200164
165 reg16 = pci_read_config16(dev, GEN_PMCON_3);
166 reg16 &= 0xfffe;
167 switch (pwr_on) {
168 case MAINBOARD_POWER_OFF:
169 reg16 |= 1;
170 state = "off";
171 break;
172 case MAINBOARD_POWER_ON:
173 reg16 &= ~1;
174 state = "on";
175 break;
176 case MAINBOARD_POWER_KEEP:
177 reg16 &= ~1;
178 state = "state keep";
179 break;
180 default:
181 state = "undefined";
182 }
183
184 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
185 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
186
187 reg16 &= ~(1 << 10);
188 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
189
190 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
191
192 pci_write_config16(dev, GEN_PMCON_3, reg16);
193 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
194
195 /* Set up NMI on errors. */
196 reg8 = inb(0x61);
197 reg8 &= 0x0f; /* Higher Nibble must be 0 */
198 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
199 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
200 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
201 outb(reg8, 0x61);
202
203 reg8 = inb(0x70);
Angel Pons88dcb312021-04-26 17:10:28 +0200204 const unsigned int nmi_option = get_uint_option("nmi", NMI_OFF);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200205 if (nmi_option) {
206 printk(BIOS_INFO, "NMI sources enabled.\n");
207 reg8 &= ~(1 << 7); /* Set NMI. */
208 } else {
209 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200210 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200211 }
212 outb(reg8, 0x70);
213
214 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
215 reg16 = pci_read_config16(dev, GEN_PMCON_1);
216 reg16 &= ~(3 << 0); // SMI# rate 1 minute
217 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
Kyösti Mälkki94464472020-06-13 13:45:42 +0300218 if (CONFIG(DEBUG_PERIODIC_SMI))
219 reg16 |= (3 << 0); // Periodic SMI every 8s
Stefan Reinauer8e073822012-04-04 00:07:22 +0200220 pci_write_config16(dev, GEN_PMCON_1, reg16);
221
222 // Set the board's GPI routing.
223 pch_gpi_routing(dev);
224
225 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
226
227 outl(config->gpe0_en, pmbase + GPE0_EN);
228 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
229
230 /* Set up power management block and determine sleep mode */
231 reg32 = inl(pmbase + 0x04); // PM1_CNT
232 reg32 &= ~(7 << 10); // SLP_TYP
233 reg32 |= (1 << 0); // SCI_EN
234 outl(reg32, pmbase + 0x04);
235
236 /* Clear magic status bits to prevent unexpected wake */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200237 reg32 = RCBA32(PRSTS);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200238 reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200239 RCBA32(PRSTS) = reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200240
241 reg32 = RCBA32(0x3f02);
242 reg32 &= ~0xf;
243 RCBA32(0x3f02) = reg32;
244}
245
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700246/* CougarPoint PCH Power Management init */
247static void cpt_pm_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200248{
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700249 printk(BIOS_DEBUG, "CougarPoint PM init\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200250 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200251 RCBA32_AND_OR(CIR30, ~0U, (1 << 6)|(1 << 0));
252 RCBA32_AND_OR(CIR5, ~0U, (1 << 0));
253 RCBA16_AND_OR(CIR3, ~0U, (1 << 13)|(1 << 14));
254 RCBA16_AND_OR(CIR2, ~0U, (1 << 14));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200255 RCBA32(DMC) = 0xc0388400;
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200256 RCBA32_AND_OR(CIR6, ~0U, (1 << 5)|(1 << 18));
257 RCBA32_AND_OR(CIR9, ~0U, (1 << 15)|(1 << 1));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200258 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
259 RCBA32(PM_CFG) = 0x050f0000;
260 RCBA32(CIR8) = 0x04000000;
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200261 RCBA32_AND_OR(CIR10, ~0U, 0xfffff);
262 RCBA32_AND_OR(CIR11, ~0U, (1 << 1));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200263 RCBA32(CIR12) = 0x0001c000;
264 RCBA32(CIR14) = 0x00061100;
265 RCBA32(CIR15) = 0x7f8fdfff;
266 RCBA32(CIR13) = 0x000003fc;
267 RCBA32(CIR16) = 0x00001000;
268 RCBA32(CIR18) = 0x0001c000;
269 RCBA32(CIR17) = 0x00000800;
270 RCBA32(CIR23) = 0x00001000;
271 RCBA32(CIR19) = 0x00093900;
272 RCBA32(CIR20) = 0x24653002;
273 RCBA32(CIR21) = 0x062108fe;
274 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
275 RCBA32(CIR24) = 0x01010000;
276 RCBA32(CIR25) = 0x01010404;
277 RCBA32(CIR27) = 0x01041041;
278 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
279 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
280 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
281 RCBA32(CIR26) = 0x00000001;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200282 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
283 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200284 RCBA32(PMSYNC_CFG) = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200285 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
286}
287
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700288/* PantherPoint PCH Power Management init */
289static void ppt_pm_init(struct device *dev)
290{
291 printk(BIOS_DEBUG, "PantherPoint PM init\n");
292 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200293 RCBA32_AND_OR(CIR30, ~0UL, (1 << 0));
294 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
295 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
296 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
297 RCBA32(DMC) = 0xc03b8400;
298 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
299 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
300 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
301 RCBA32(PM_CFG) = 0x054f0000;
302 RCBA32(CIR8) = 0x04000000;
303 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
304 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1)|(1 << 0));
305 RCBA32(CIR12) = 0x0001c000;
306 RCBA32(CIR14) = 0x00061100;
307 RCBA32(CIR15) = 0x7f8fdfff;
308 RCBA32(CIR13) = 0x000003fd;
309 RCBA32(CIR16) = 0x00001000;
310 RCBA32(CIR18) = 0x0001c000;
311 RCBA32(CIR17) = 0x00000800;
312 RCBA32(CIR23) = 0x00001000;
313 RCBA32(CIR19) = 0x00093900;
314 RCBA32(CIR20) = 0x24653002;
315 RCBA32(CIR21) = 0x067388fe;
316 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
317 RCBA32(CIR24) = 0x01010000;
318 RCBA32(CIR25) = 0x01010404;
319 RCBA32(CIR27) = 0x01040000;
320 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
321 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
322 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
323 RCBA32(CIR26) = 0x00000001;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700324 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
325 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
326 RCBA32_AND_OR(0x33a4, ~0UL, (1 << 0));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200327 RCBA32(PMSYNC_CFG) = 0;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700328 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
329}
330
Nico Huberb2dae792015-10-26 12:34:02 +0100331static void enable_hpet(struct device *const dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200332{
333 u32 reg32;
Nico Huberb2dae792015-10-26 12:34:02 +0100334 size_t i;
335
336 /* Assign unique bus/dev/fn for each HPET */
337 for (i = 0; i < 8; ++i)
338 pci_write_config16(dev, LPC_HnBDF(i),
339 PCH_HPET_PCI_BUS << 8 | PCH_HPET_PCI_SLOT << 3 | i);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200340
341 /* Move HPET to default address 0xfed00000 and enable it */
342 reg32 = RCBA32(HPTC);
343 reg32 |= (1 << 7); // HPET Address Enable
344 reg32 &= ~(3 << 0);
345 RCBA32(HPTC) = reg32;
346}
347
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200348static void enable_clock_gating(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200349{
350 u32 reg32;
351 u16 reg16;
352
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200353 RCBA32_AND_OR(DMIC, ~0UL, 0xf);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200354
355 reg16 = pci_read_config16(dev, GEN_PMCON_1);
Michał Żygowski9ff2af22020-04-13 20:37:36 +0200356 reg16 &= ~(3 << 2); /* Clear CLKRUN bits for mobile and desktop */
357 if (get_platform_type() == PLATFORM_MOBILE)
358 reg16 |= (1 << 2); /* CLKRUN_EN for mobile */
359 else if (get_platform_type() == PLATFORM_DESKTOP_SERVER)
360 reg16 |= (1 << 3); /* PSEUDO_CLKRUN_EN for desktop */
361 reg16 |= (1 << 11);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200362 pci_write_config16(dev, GEN_PMCON_1, reg16);
363
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200364 pch_iobp_update(0xEB007F07, ~0U, (1 << 31));
365 pch_iobp_update(0xEB004000, ~0U, (1 << 7));
366 pch_iobp_update(0xEC007F07, ~0U, (1 << 31));
367 pch_iobp_update(0xEC004000, ~0U, (1 << 7));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200368
369 reg32 = RCBA32(CG);
370 reg32 |= (1 << 31);
371 reg32 |= (1 << 29) | (1 << 28);
372 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
373 reg32 |= (1 << 16);
374 reg32 |= (1 << 17);
375 reg32 |= (1 << 18);
376 reg32 |= (1 << 22);
377 reg32 |= (1 << 23);
378 reg32 &= ~(1 << 20);
379 reg32 |= (1 << 19);
380 reg32 |= (1 << 0);
381 reg32 |= (0xf << 1);
382 RCBA32(CG) = reg32;
383
384 RCBA32_OR(0x38c0, 0x7);
385 RCBA32_OR(0x36d4, 0x6680c004);
386 RCBA32_OR(0x3564, 0x3);
387}
388
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200389static void pch_set_acpi_mode(void)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200390{
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300391 if (!acpi_is_wakeup_s3()) {
Kyösti Mälkkib6585482020-06-01 15:11:14 +0300392 apm_control(APM_CNT_ACPI_DISABLE);
Duncan Laurie95be1d62012-04-09 12:31:43 -0700393 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200394}
Stefan Reinauer8e073822012-04-04 00:07:22 +0200395
Stefan Reinauer8e073822012-04-04 00:07:22 +0200396static void pch_fixups(struct device *dev)
397{
Stefan Reinauer8e073822012-04-04 00:07:22 +0200398 /* Indicate DRAM init done for MRC S3 to know it can resume */
Angel Ponsc803f652020-06-07 22:09:01 +0200399 pci_or_config8(dev, GEN_PMCON_2, 1 << 7);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200400
401 /*
402 * Enable DMI ASPM in the PCH
403 */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200404 RCBA32_AND_OR(DMC, ~(1 << 10), 0);
405 RCBA32_OR(LCAP, (1 << 11)|(1 << 10));
406 RCBA32_OR(LCTL, 0x3);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200407}
408
Nico Huber7b2f9f62015-10-01 19:00:51 +0200409static void pch_spi_init(const struct device *const dev)
410{
411 const config_t *const config = dev->chip_info;
412
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100413 printk(BIOS_DEBUG, "%s\n", __func__);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200414
415 if (config->spi_uvscc)
416 RCBA32(0x3800 + 0xc8) = config->spi_uvscc;
417 if (config->spi_lvscc)
418 RCBA32(0x3800 + 0xc4) = config->spi_lvscc;
419
420 if (config->spi_uvscc || config->spi_lvscc)
421 RCBA32_OR(0x3800 + 0xc4, 1 << 23); /* lock both UVSCC + LVSCC */
422}
423
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200424static const struct {
425 u16 dev_id;
426 const char *dev_name;
427} pch_table[] = {
428 /* 6-series PCI ids from
429 * Intel® 6 Series Chipset and
430 * Intel® C200 Series Chipset
431 * Specification Update - NDA
432 * October 2013
433 * CDI / IBP#: 440377
434 */
435 {0x1C41, "SFF Sample"},
436 {0x1C42, "Desktop Sample"},
437 {0x1C43, "Mobile Sample"},
438 {0x1C44, "Z68"},
439 {0x1C46, "P67"},
440 {0x1C47, "UM67"},
441 {0x1C49, "HM65"},
442 {0x1C4A, "H67"},
443 {0x1C4B, "HM67"},
444 {0x1C4C, "Q65"},
445 {0x1C4D, "QS67"},
446 {0x1C4E, "Q67"},
447 {0x1C4F, "QM67"},
448 {0x1C50, "B65"},
449 {0x1C52, "C202"},
450 {0x1C54, "C204"},
451 {0x1C56, "C206"},
452 {0x1C5C, "H61"},
453 /* 7-series PCI ids from Intel document 472178 */
454 {0x1E41, "Desktop Sample"},
455 {0x1E42, "Mobile Sample"},
456 {0x1E43, "SFF Sample"},
457 {0x1E44, "Z77"},
458 {0x1E45, "H71"},
459 {0x1E46, "Z75"},
460 {0x1E47, "Q77"},
461 {0x1E48, "Q75"},
462 {0x1E49, "B75"},
463 {0x1E4A, "H77"},
464 {0x1E53, "C216"},
465 {0x1E55, "QM77"},
466 {0x1E56, "QS77"},
467 {0x1E58, "UM77"},
468 {0x1E57, "HM77"},
469 {0x1E59, "HM76"},
470 {0x1E5D, "HM75"},
471 {0x1E5E, "HM70"},
472 {0x1E5F, "NM70"},
473};
474
475static void report_pch_info(struct device *dev)
476{
477 const u16 dev_id = pci_read_config16(dev, PCI_DEVICE_ID);
478 int i;
479
480 const char *pch_type = "Unknown";
481 for (i = 0; i < ARRAY_SIZE(pch_table); i++) {
482 if (pch_table[i].dev_id == dev_id) {
483 pch_type = pch_table[i].dev_name;
484 break;
485 }
486 }
487 printk(BIOS_INFO, "PCH: detected %s, device id: 0x%x, rev id 0x%x\n",
488 pch_type, dev_id, pci_read_config8(dev, PCI_CLASS_REVISION));
489}
490
Stefan Reinauer8e073822012-04-04 00:07:22 +0200491static void lpc_init(struct device *dev)
492{
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100493 printk(BIOS_DEBUG, "pch: %s\n", __func__);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200494
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200495 /* Print detected platform */
496 report_pch_info(dev);
497
Stefan Reinauer8e073822012-04-04 00:07:22 +0200498 /* IO APIC initialization. */
Paul Menzel9c50e6a2013-05-03 12:23:39 +0200499 pch_enable_ioapic(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200500
501 pch_enable_serial_irqs(dev);
502
503 /* Setup the PIRQ. */
504 pch_pirq_init(dev);
505
506 /* Setup power options. */
507 pch_power_options(dev);
508
509 /* Initialize power management */
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700510 switch (pch_silicon_type()) {
511 case PCH_TYPE_CPT: /* CougarPoint */
512 cpt_pm_init(dev);
513 break;
514 case PCH_TYPE_PPT: /* PantherPoint */
515 ppt_pm_init(dev);
516 break;
517 default:
518 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
519 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200520
Stefan Reinauer8e073822012-04-04 00:07:22 +0200521 /* Initialize the real time clock. */
Patrick Rudolph6b931122018-11-01 17:48:37 +0100522 sb_rtc_init();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200523
524 /* Initialize ISA DMA. */
525 isa_dma_init();
526
527 /* Initialize the High Precision Event Timers, if present. */
Nico Huberb2dae792015-10-26 12:34:02 +0100528 enable_hpet(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200529
530 /* Initialize Clock Gating */
531 enable_clock_gating(dev);
532
533 setup_i8259();
534
535 /* The OS should do this? */
536 /* Interrupt 9 should be level triggered (SCI) */
537 i8259_configure_irq_trigger(9, 1);
538
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200539 pch_set_acpi_mode();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200540
541 pch_fixups(dev);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200542
543 pch_spi_init(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200544}
545
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200546static void pch_lpc_read_resources(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200547{
548 struct resource *res;
Marc Jonesa0bec172012-07-13 14:14:34 -0600549 config_t *config = dev->chip_info;
550 u8 io_index = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200551
552 /* Get the normal PCI resources of this device. */
553 pci_dev_read_resources(dev);
554
555 /* Add an extra subtractive resource for both memory and I/O. */
Marc Jonesa0bec172012-07-13 14:14:34 -0600556 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200557 res->base = 0;
558 res->size = 0x1000;
559 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
560 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
561
Marc Jonesa0bec172012-07-13 14:14:34 -0600562 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Vladimir Serbinenko0650cd02014-02-05 15:03:50 +0100563 res->base = 0xff000000;
564 /* Some systems (e.g. X230) have 12 MiB flash.
565 SPI controller supports up to 2 x 16 MiB of flash but
566 address map limits this to 16MiB. */
567 res->size = 0x01000000; /* 16 MB for flash */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200568 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
569 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
570
571 res = new_resource(dev, 3); /* IOAPIC */
572 res->base = IO_APIC_ADDR;
573 res->size = 0x00001000;
574 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Marc Jonesa0bec172012-07-13 14:14:34 -0600575
576 /* Set PCH IO decode ranges if required.*/
577 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
578 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
579 res->base = config->gen1_dec & 0xFFFC;
580 res->size = (config->gen1_dec >> 16) & 0xFC;
581 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
582 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
583 }
584
585 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
586 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
587 res->base = config->gen2_dec & 0xFFFC;
588 res->size = (config->gen2_dec >> 16) & 0xFC;
589 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
590 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
591 }
592
593 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
594 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
595 res->base = config->gen3_dec & 0xFFFC;
596 res->size = (config->gen3_dec >> 16) & 0xFC;
597 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
598 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
599 }
600
601 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
602 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
603 res->base = config->gen4_dec & 0xFFFC;
604 res->size = (config->gen4_dec >> 16) & 0xFC;
605 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
606 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
607 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200608}
609
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200610static void pch_lpc_enable(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200611{
612 /* Enable PCH Display Port */
613 RCBA16(DISPBDF) = 0x0010;
614 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
615
616 pch_enable(dev);
617}
618
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600619static const char *lpc_acpi_name(const struct device *dev)
Patrick Rudolph604f6982017-06-07 09:46:52 +0200620{
621 return "LPCB";
622}
623
Furquan Shaikh7536a392020-04-24 21:59:21 -0700624static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100625{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300626 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100627 config_t *chip = dev->chip_info;
628
629 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Tobias Diedrich7f5efd92017-12-14 00:29:01 +0100630 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100631}
632
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200633static void lpc_final(struct device *dev)
634{
Arthur Heymansebf201b2019-05-28 13:51:36 +0200635 spi_finalize_ops();
Nico Huber8e50b6d2018-02-04 15:52:18 +0100636
Bill XIEd533b162017-08-22 16:26:22 +0800637 /* Call SMM finalize() handlers before resume */
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300638 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
639 acpi_is_wakeup_s3()) {
640 apm_control(APM_CNT_FINALIZE);
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200641 }
642}
643
Arthur Heymansebf201b2019-05-28 13:51:36 +0200644void intel_southbridge_override_spi(
645 struct intel_swseq_spi_config *spi_config)
646{
647 struct device *dev = pcidev_on_root(0x1f, 0);
648
649 if (!dev)
650 return;
651 /* Devicetree may override defaults. */
652 const config_t *const config = dev->chip_info;
653
654 if (!config)
655 return;
656
657 if (config->spi.ops[0].op != 0)
658 memcpy(spi_config, &config->spi, sizeof(*spi_config));
659}
660
Felix Held372dfe02023-11-18 17:47:22 +0100661struct device_operations bd82x6x_lpc_bridge_ops = {
Stefan Reinauer8e073822012-04-04 00:07:22 +0200662 .read_resources = pch_lpc_read_resources,
663 .set_resources = pci_dev_set_resources,
Arthur Heymans3cde4942019-08-18 10:02:10 +0200664 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200665 .write_acpi_tables = acpi_write_hpet,
Nico Huber68680dd2020-03-31 17:34:52 +0200666 .acpi_fill_ssdt = southbridge_fill_ssdt,
Patrick Rudolph604f6982017-06-07 09:46:52 +0200667 .acpi_name = lpc_acpi_name,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200668 .init = lpc_init,
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200669 .final = lpc_final,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200670 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100671 .scan_bus = scan_static_bus,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200672 .ops_pci = &pci_dev_ops_pci,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200673};