blob: 4ba88637fbbfbe7e2cc2d62e42f9c48fe86e9f6a [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>
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/**
33 * Set miscellanous static southbridge features.
34 *
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{
Stefan Reinauer8e073822012-04-04 00:07:22 +020039 u32 reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +020040
Nico Huberb2dae792015-10-26 12:34:02 +010041 /* Assign unique bus/dev/fn for I/O APIC */
42 pci_write_config16(dev, LPC_IBDF,
43 PCH_IOAPIC_PCI_BUS << 8 | PCH_IOAPIC_PCI_SLOT << 3);
44
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080045 set_ioapic_id(VIO_APIC_VADDR, 0x02);
Stefan Reinauer8e073822012-04-04 00:07:22 +020046
47 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080048 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
49 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +020050
Paul Menzel9c50e6a2013-05-03 12:23:39 +020051 /*
52 * Select Boot Configuration register (0x03) and
53 * use Processor System Bus (0x01) to deliver interrupts.
54 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080055 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Stefan Reinauer8e073822012-04-04 00:07:22 +020056}
57
58static void pch_enable_serial_irqs(struct device *dev)
59{
60 /* Set packet length and toggle silent mode bit for one frame. */
61 pci_write_config8(dev, SERIRQ_CNTL,
62 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080063#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Stefan Reinauer8e073822012-04-04 00:07:22 +020064 pci_write_config8(dev, SERIRQ_CNTL,
65 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
66#endif
67}
68
69/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
70 * 0x00 - 0000 = Reserved
71 * 0x01 - 0001 = Reserved
72 * 0x02 - 0010 = Reserved
73 * 0x03 - 0011 = IRQ3
74 * 0x04 - 0100 = IRQ4
75 * 0x05 - 0101 = IRQ5
76 * 0x06 - 0110 = IRQ6
77 * 0x07 - 0111 = IRQ7
78 * 0x08 - 1000 = Reserved
79 * 0x09 - 1001 = IRQ9
80 * 0x0A - 1010 = IRQ10
81 * 0x0B - 1011 = IRQ11
82 * 0x0C - 1100 = IRQ12
83 * 0x0D - 1101 = Reserved
84 * 0x0E - 1110 = IRQ14
85 * 0x0F - 1111 = IRQ15
86 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
87 * 0x80 - The PIRQ is not routed.
88 */
89
Elyes HAOUAS4aec3402018-05-25 08:29:27 +020090static void pch_pirq_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020091{
Elyes HAOUAS4aec3402018-05-25 08:29:27 +020092 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020093 /* Interrupt 11 is not used by legacy devices and so can always be used for
94 PCI interrupts. Full legacy IRQ routing is complicated and hard to
95 get right. Fortunately all modern OS use MSI and so it's not that big of
96 an issue anyway. Still we have to provide a reasonable default. Using
97 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
98 move it to any interrupt and others will just leave them at default.
Stefan Reinauer8e073822012-04-04 00:07:22 +020099 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200100 const u8 pirq_routing = 11;
101
102 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
103 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
104 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
105 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
106
107 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
108 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
109 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
110 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200111
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200112 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200113 u8 int_pin=0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200114
115 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
116 continue;
117
118 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
119
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200120 if (int_pin == 0)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200121 continue;
122
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200123 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200124 }
125}
126
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200127static void pch_gpi_routing(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200128{
129 /* Get the chip configuration */
130 config_t *config = dev->chip_info;
131 u32 reg32 = 0;
132
133 /* An array would be much nicer here, or some
134 * other method of doing this.
135 */
136 reg32 |= (config->gpi0_routing & 0x03) << 0;
137 reg32 |= (config->gpi1_routing & 0x03) << 2;
138 reg32 |= (config->gpi2_routing & 0x03) << 4;
139 reg32 |= (config->gpi3_routing & 0x03) << 6;
140 reg32 |= (config->gpi4_routing & 0x03) << 8;
141 reg32 |= (config->gpi5_routing & 0x03) << 10;
142 reg32 |= (config->gpi6_routing & 0x03) << 12;
143 reg32 |= (config->gpi7_routing & 0x03) << 14;
144 reg32 |= (config->gpi8_routing & 0x03) << 16;
145 reg32 |= (config->gpi9_routing & 0x03) << 18;
146 reg32 |= (config->gpi10_routing & 0x03) << 20;
147 reg32 |= (config->gpi11_routing & 0x03) << 22;
148 reg32 |= (config->gpi12_routing & 0x03) << 24;
149 reg32 |= (config->gpi13_routing & 0x03) << 26;
150 reg32 |= (config->gpi14_routing & 0x03) << 28;
151 reg32 |= (config->gpi15_routing & 0x03) << 30;
152
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200153 pci_write_config32(dev, GPIO_ROUT, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200154}
155
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200156static void pch_power_options(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200157{
158 u8 reg8;
159 u16 reg16, pmbase;
160 u32 reg32;
161 const char *state;
162 /* Get the chip configuration */
163 config_t *config = dev->chip_info;
164
Stefan Reinauer8e073822012-04-04 00:07:22 +0200165 /* Which state do we want to goto after g3 (power restored)?
166 * 0 == S0 Full On
167 * 1 == S5 Soft Off
168 *
169 * If the option is not existent (Laptops), use Kconfig setting.
170 */
Angel Pons62719a32021-04-19 13:15:28 +0200171 const int pwr_on = get_int_option("power_on_after_fail",
172 CONFIG_MAINBOARD_POWER_FAILURE_STATE);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200173
174 reg16 = pci_read_config16(dev, GEN_PMCON_3);
175 reg16 &= 0xfffe;
176 switch (pwr_on) {
177 case MAINBOARD_POWER_OFF:
178 reg16 |= 1;
179 state = "off";
180 break;
181 case MAINBOARD_POWER_ON:
182 reg16 &= ~1;
183 state = "on";
184 break;
185 case MAINBOARD_POWER_KEEP:
186 reg16 &= ~1;
187 state = "state keep";
188 break;
189 default:
190 state = "undefined";
191 }
192
193 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
194 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
195
196 reg16 &= ~(1 << 10);
197 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
198
199 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
200
201 pci_write_config16(dev, GEN_PMCON_3, reg16);
202 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
203
204 /* Set up NMI on errors. */
205 reg8 = inb(0x61);
206 reg8 &= 0x0f; /* Higher Nibble must be 0 */
207 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
208 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
209 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
210 outb(reg8, 0x61);
211
212 reg8 = inb(0x70);
Angel Pons62719a32021-04-19 13:15:28 +0200213 const int nmi_option = get_int_option("nmi", NMI_OFF);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200214 if (nmi_option) {
215 printk(BIOS_INFO, "NMI sources enabled.\n");
216 reg8 &= ~(1 << 7); /* Set NMI. */
217 } else {
218 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200219 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200220 }
221 outb(reg8, 0x70);
222
223 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
224 reg16 = pci_read_config16(dev, GEN_PMCON_1);
225 reg16 &= ~(3 << 0); // SMI# rate 1 minute
226 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
Kyösti Mälkki94464472020-06-13 13:45:42 +0300227 if (CONFIG(DEBUG_PERIODIC_SMI))
228 reg16 |= (3 << 0); // Periodic SMI every 8s
Stefan Reinauer8e073822012-04-04 00:07:22 +0200229 pci_write_config16(dev, GEN_PMCON_1, reg16);
230
231 // Set the board's GPI routing.
232 pch_gpi_routing(dev);
233
234 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
235
236 outl(config->gpe0_en, pmbase + GPE0_EN);
237 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
238
239 /* Set up power management block and determine sleep mode */
240 reg32 = inl(pmbase + 0x04); // PM1_CNT
241 reg32 &= ~(7 << 10); // SLP_TYP
242 reg32 |= (1 << 0); // SCI_EN
243 outl(reg32, pmbase + 0x04);
244
245 /* Clear magic status bits to prevent unexpected wake */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200246 reg32 = RCBA32(PRSTS);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200247 reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200248 RCBA32(PRSTS) = reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200249
250 reg32 = RCBA32(0x3f02);
251 reg32 &= ~0xf;
252 RCBA32(0x3f02) = reg32;
253}
254
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700255/* CougarPoint PCH Power Management init */
256static void cpt_pm_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200257{
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700258 printk(BIOS_DEBUG, "CougarPoint PM init\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200259 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200260 RCBA32_AND_OR(CIR30, ~0UL, (1 << 6)|(1 << 0));
261 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
262 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
263 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
264 RCBA32(DMC) = 0xc0388400;
265 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
266 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
267 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
268 RCBA32(PM_CFG) = 0x050f0000;
269 RCBA32(CIR8) = 0x04000000;
270 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
271 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1));
272 RCBA32(CIR12) = 0x0001c000;
273 RCBA32(CIR14) = 0x00061100;
274 RCBA32(CIR15) = 0x7f8fdfff;
275 RCBA32(CIR13) = 0x000003fc;
276 RCBA32(CIR16) = 0x00001000;
277 RCBA32(CIR18) = 0x0001c000;
278 RCBA32(CIR17) = 0x00000800;
279 RCBA32(CIR23) = 0x00001000;
280 RCBA32(CIR19) = 0x00093900;
281 RCBA32(CIR20) = 0x24653002;
282 RCBA32(CIR21) = 0x062108fe;
283 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
284 RCBA32(CIR24) = 0x01010000;
285 RCBA32(CIR25) = 0x01010404;
286 RCBA32(CIR27) = 0x01041041;
287 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
288 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
289 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
290 RCBA32(CIR26) = 0x00000001;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200291 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
292 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200293 RCBA32(PMSYNC_CFG) = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200294 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
295}
296
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700297/* PantherPoint PCH Power Management init */
298static void ppt_pm_init(struct device *dev)
299{
300 printk(BIOS_DEBUG, "PantherPoint PM init\n");
301 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200302 RCBA32_AND_OR(CIR30, ~0UL, (1 << 0));
303 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
304 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
305 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
306 RCBA32(DMC) = 0xc03b8400;
307 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
308 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
309 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
310 RCBA32(PM_CFG) = 0x054f0000;
311 RCBA32(CIR8) = 0x04000000;
312 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
313 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1)|(1 << 0));
314 RCBA32(CIR12) = 0x0001c000;
315 RCBA32(CIR14) = 0x00061100;
316 RCBA32(CIR15) = 0x7f8fdfff;
317 RCBA32(CIR13) = 0x000003fd;
318 RCBA32(CIR16) = 0x00001000;
319 RCBA32(CIR18) = 0x0001c000;
320 RCBA32(CIR17) = 0x00000800;
321 RCBA32(CIR23) = 0x00001000;
322 RCBA32(CIR19) = 0x00093900;
323 RCBA32(CIR20) = 0x24653002;
324 RCBA32(CIR21) = 0x067388fe;
325 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
326 RCBA32(CIR24) = 0x01010000;
327 RCBA32(CIR25) = 0x01010404;
328 RCBA32(CIR27) = 0x01040000;
329 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
330 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
331 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
332 RCBA32(CIR26) = 0x00000001;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700333 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
334 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
335 RCBA32_AND_OR(0x33a4, ~0UL, (1 << 0));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200336 RCBA32(PMSYNC_CFG) = 0;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700337 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
338}
339
Nico Huberb2dae792015-10-26 12:34:02 +0100340static void enable_hpet(struct device *const dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200341{
342 u32 reg32;
Nico Huberb2dae792015-10-26 12:34:02 +0100343 size_t i;
344
345 /* Assign unique bus/dev/fn for each HPET */
346 for (i = 0; i < 8; ++i)
347 pci_write_config16(dev, LPC_HnBDF(i),
348 PCH_HPET_PCI_BUS << 8 | PCH_HPET_PCI_SLOT << 3 | i);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200349
350 /* Move HPET to default address 0xfed00000 and enable it */
351 reg32 = RCBA32(HPTC);
352 reg32 |= (1 << 7); // HPET Address Enable
353 reg32 &= ~(3 << 0);
354 RCBA32(HPTC) = reg32;
355}
356
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200357static void enable_clock_gating(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200358{
359 u32 reg32;
360 u16 reg16;
361
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200362 RCBA32_AND_OR(DMIC, ~0UL, 0xf);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200363
364 reg16 = pci_read_config16(dev, GEN_PMCON_1);
Michał Żygowski9ff2af22020-04-13 20:37:36 +0200365 reg16 &= ~(3 << 2); /* Clear CLKRUN bits for mobile and desktop */
366 if (get_platform_type() == PLATFORM_MOBILE)
367 reg16 |= (1 << 2); /* CLKRUN_EN for mobile */
368 else if (get_platform_type() == PLATFORM_DESKTOP_SERVER)
369 reg16 |= (1 << 3); /* PSEUDO_CLKRUN_EN for desktop */
370 reg16 |= (1 << 11);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200371 pci_write_config16(dev, GEN_PMCON_1, reg16);
372
373 pch_iobp_update(0xEB007F07, ~0UL, (1 << 31));
374 pch_iobp_update(0xEB004000, ~0UL, (1 << 7));
375 pch_iobp_update(0xEC007F07, ~0UL, (1 << 31));
376 pch_iobp_update(0xEC004000, ~0UL, (1 << 7));
377
378 reg32 = RCBA32(CG);
379 reg32 |= (1 << 31);
380 reg32 |= (1 << 29) | (1 << 28);
381 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
382 reg32 |= (1 << 16);
383 reg32 |= (1 << 17);
384 reg32 |= (1 << 18);
385 reg32 |= (1 << 22);
386 reg32 |= (1 << 23);
387 reg32 &= ~(1 << 20);
388 reg32 |= (1 << 19);
389 reg32 |= (1 << 0);
390 reg32 |= (0xf << 1);
391 RCBA32(CG) = reg32;
392
393 RCBA32_OR(0x38c0, 0x7);
394 RCBA32_OR(0x36d4, 0x6680c004);
395 RCBA32_OR(0x3564, 0x3);
396}
397
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200398static void pch_set_acpi_mode(void)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200399{
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300400 if (!acpi_is_wakeup_s3()) {
Kyösti Mälkkib6585482020-06-01 15:11:14 +0300401 apm_control(APM_CNT_ACPI_DISABLE);
Duncan Laurie95be1d62012-04-09 12:31:43 -0700402 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200403}
Stefan Reinauer8e073822012-04-04 00:07:22 +0200404
Stefan Reinauer8e073822012-04-04 00:07:22 +0200405static void pch_fixups(struct device *dev)
406{
Stefan Reinauer8e073822012-04-04 00:07:22 +0200407 /* Indicate DRAM init done for MRC S3 to know it can resume */
Angel Ponsc803f652020-06-07 22:09:01 +0200408 pci_or_config8(dev, GEN_PMCON_2, 1 << 7);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200409
410 /*
411 * Enable DMI ASPM in the PCH
412 */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200413 RCBA32_AND_OR(DMC, ~(1 << 10), 0);
414 RCBA32_OR(LCAP, (1 << 11)|(1 << 10));
415 RCBA32_OR(LCTL, 0x3);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200416}
417
Nico Huber7b2f9f62015-10-01 19:00:51 +0200418static void pch_spi_init(const struct device *const dev)
419{
420 const config_t *const config = dev->chip_info;
421
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100422 printk(BIOS_DEBUG, "%s\n", __func__);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200423
424 if (config->spi_uvscc)
425 RCBA32(0x3800 + 0xc8) = config->spi_uvscc;
426 if (config->spi_lvscc)
427 RCBA32(0x3800 + 0xc4) = config->spi_lvscc;
428
429 if (config->spi_uvscc || config->spi_lvscc)
430 RCBA32_OR(0x3800 + 0xc4, 1 << 23); /* lock both UVSCC + LVSCC */
431}
432
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200433static const struct {
434 u16 dev_id;
435 const char *dev_name;
436} pch_table[] = {
437 /* 6-series PCI ids from
438 * Intel® 6 Series Chipset and
439 * Intel® C200 Series Chipset
440 * Specification Update - NDA
441 * October 2013
442 * CDI / IBP#: 440377
443 */
444 {0x1C41, "SFF Sample"},
445 {0x1C42, "Desktop Sample"},
446 {0x1C43, "Mobile Sample"},
447 {0x1C44, "Z68"},
448 {0x1C46, "P67"},
449 {0x1C47, "UM67"},
450 {0x1C49, "HM65"},
451 {0x1C4A, "H67"},
452 {0x1C4B, "HM67"},
453 {0x1C4C, "Q65"},
454 {0x1C4D, "QS67"},
455 {0x1C4E, "Q67"},
456 {0x1C4F, "QM67"},
457 {0x1C50, "B65"},
458 {0x1C52, "C202"},
459 {0x1C54, "C204"},
460 {0x1C56, "C206"},
461 {0x1C5C, "H61"},
462 /* 7-series PCI ids from Intel document 472178 */
463 {0x1E41, "Desktop Sample"},
464 {0x1E42, "Mobile Sample"},
465 {0x1E43, "SFF Sample"},
466 {0x1E44, "Z77"},
467 {0x1E45, "H71"},
468 {0x1E46, "Z75"},
469 {0x1E47, "Q77"},
470 {0x1E48, "Q75"},
471 {0x1E49, "B75"},
472 {0x1E4A, "H77"},
473 {0x1E53, "C216"},
474 {0x1E55, "QM77"},
475 {0x1E56, "QS77"},
476 {0x1E58, "UM77"},
477 {0x1E57, "HM77"},
478 {0x1E59, "HM76"},
479 {0x1E5D, "HM75"},
480 {0x1E5E, "HM70"},
481 {0x1E5F, "NM70"},
482};
483
484static void report_pch_info(struct device *dev)
485{
486 const u16 dev_id = pci_read_config16(dev, PCI_DEVICE_ID);
487 int i;
488
489 const char *pch_type = "Unknown";
490 for (i = 0; i < ARRAY_SIZE(pch_table); i++) {
491 if (pch_table[i].dev_id == dev_id) {
492 pch_type = pch_table[i].dev_name;
493 break;
494 }
495 }
496 printk(BIOS_INFO, "PCH: detected %s, device id: 0x%x, rev id 0x%x\n",
497 pch_type, dev_id, pci_read_config8(dev, PCI_CLASS_REVISION));
498}
499
Stefan Reinauer8e073822012-04-04 00:07:22 +0200500static void lpc_init(struct device *dev)
501{
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100502 printk(BIOS_DEBUG, "pch: %s\n", __func__);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200503
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200504 /* Print detected platform */
505 report_pch_info(dev);
506
Stefan Reinauer8e073822012-04-04 00:07:22 +0200507 /* IO APIC initialization. */
Paul Menzel9c50e6a2013-05-03 12:23:39 +0200508 pch_enable_ioapic(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200509
510 pch_enable_serial_irqs(dev);
511
512 /* Setup the PIRQ. */
513 pch_pirq_init(dev);
514
515 /* Setup power options. */
516 pch_power_options(dev);
517
518 /* Initialize power management */
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700519 switch (pch_silicon_type()) {
520 case PCH_TYPE_CPT: /* CougarPoint */
521 cpt_pm_init(dev);
522 break;
523 case PCH_TYPE_PPT: /* PantherPoint */
524 ppt_pm_init(dev);
525 break;
526 default:
527 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
528 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200529
Stefan Reinauer8e073822012-04-04 00:07:22 +0200530 /* Initialize the real time clock. */
Patrick Rudolph6b931122018-11-01 17:48:37 +0100531 sb_rtc_init();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200532
533 /* Initialize ISA DMA. */
534 isa_dma_init();
535
536 /* Initialize the High Precision Event Timers, if present. */
Nico Huberb2dae792015-10-26 12:34:02 +0100537 enable_hpet(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200538
539 /* Initialize Clock Gating */
540 enable_clock_gating(dev);
541
542 setup_i8259();
543
544 /* The OS should do this? */
545 /* Interrupt 9 should be level triggered (SCI) */
546 i8259_configure_irq_trigger(9, 1);
547
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200548 pch_set_acpi_mode();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200549
550 pch_fixups(dev);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200551
552 pch_spi_init(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200553}
554
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200555static void pch_lpc_read_resources(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200556{
557 struct resource *res;
Marc Jonesa0bec172012-07-13 14:14:34 -0600558 config_t *config = dev->chip_info;
559 u8 io_index = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200560
561 /* Get the normal PCI resources of this device. */
562 pci_dev_read_resources(dev);
563
564 /* Add an extra subtractive resource for both memory and I/O. */
Marc Jonesa0bec172012-07-13 14:14:34 -0600565 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200566 res->base = 0;
567 res->size = 0x1000;
568 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
569 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
570
Marc Jonesa0bec172012-07-13 14:14:34 -0600571 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Vladimir Serbinenko0650cd02014-02-05 15:03:50 +0100572 res->base = 0xff000000;
573 /* Some systems (e.g. X230) have 12 MiB flash.
574 SPI controller supports up to 2 x 16 MiB of flash but
575 address map limits this to 16MiB. */
576 res->size = 0x01000000; /* 16 MB for flash */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200577 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
578 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
579
580 res = new_resource(dev, 3); /* IOAPIC */
581 res->base = IO_APIC_ADDR;
582 res->size = 0x00001000;
583 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Marc Jonesa0bec172012-07-13 14:14:34 -0600584
585 /* Set PCH IO decode ranges if required.*/
586 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
587 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
588 res->base = config->gen1_dec & 0xFFFC;
589 res->size = (config->gen1_dec >> 16) & 0xFC;
590 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
591 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
592 }
593
594 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
595 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
596 res->base = config->gen2_dec & 0xFFFC;
597 res->size = (config->gen2_dec >> 16) & 0xFC;
598 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
599 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
600 }
601
602 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
603 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
604 res->base = config->gen3_dec & 0xFFFC;
605 res->size = (config->gen3_dec >> 16) & 0xFC;
606 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
607 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
608 }
609
610 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
611 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
612 res->base = config->gen4_dec & 0xFFFC;
613 res->size = (config->gen4_dec >> 16) & 0xFC;
614 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
615 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
616 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200617}
618
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200619static void pch_lpc_enable(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200620{
621 /* Enable PCH Display Port */
622 RCBA16(DISPBDF) = 0x0010;
623 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
624
625 pch_enable(dev);
626}
627
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600628static const char *lpc_acpi_name(const struct device *dev)
Patrick Rudolph604f6982017-06-07 09:46:52 +0200629{
630 return "LPCB";
631}
632
Furquan Shaikh7536a392020-04-24 21:59:21 -0700633static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100634{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300635 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100636 config_t *chip = dev->chip_info;
637
638 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Tobias Diedrich7f5efd92017-12-14 00:29:01 +0100639 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100640}
641
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200642static void lpc_final(struct device *dev)
643{
Arthur Heymansebf201b2019-05-28 13:51:36 +0200644 spi_finalize_ops();
Nico Huber8e50b6d2018-02-04 15:52:18 +0100645
Bill XIEd533b162017-08-22 16:26:22 +0800646 /* Call SMM finalize() handlers before resume */
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300647 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
648 acpi_is_wakeup_s3()) {
649 apm_control(APM_CNT_FINALIZE);
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200650 }
651}
652
Arthur Heymansebf201b2019-05-28 13:51:36 +0200653void intel_southbridge_override_spi(
654 struct intel_swseq_spi_config *spi_config)
655{
656 struct device *dev = pcidev_on_root(0x1f, 0);
657
658 if (!dev)
659 return;
660 /* Devicetree may override defaults. */
661 const config_t *const config = dev->chip_info;
662
663 if (!config)
664 return;
665
666 if (config->spi.ops[0].op != 0)
667 memcpy(spi_config, &config->spi, sizeof(*spi_config));
668}
669
Stefan Reinauer8e073822012-04-04 00:07:22 +0200670static struct device_operations device_ops = {
671 .read_resources = pch_lpc_read_resources,
672 .set_resources = pci_dev_set_resources,
Arthur Heymans3cde4942019-08-18 10:02:10 +0200673 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200674 .write_acpi_tables = acpi_write_hpet,
Nico Huber68680dd2020-03-31 17:34:52 +0200675 .acpi_fill_ssdt = southbridge_fill_ssdt,
Patrick Rudolph604f6982017-06-07 09:46:52 +0200676 .acpi_name = lpc_acpi_name,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200677 .init = lpc_init,
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200678 .final = lpc_final,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200679 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100680 .scan_bus = scan_static_bus,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200681 .ops_pci = &pci_dev_ops_pci,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200682};
683
Kimarie Hoote6f459c2012-07-14 08:26:08 -0600684/* IDs for LPC device of Intel 6 Series Chipset, Intel 7 Series Chipset, and
685 * Intel C200 Series Chipset
Stefan Reinauer8e073822012-04-04 00:07:22 +0200686 */
687
Vladimir Serbinenko42d55e02016-01-02 01:47:26 +0100688static const unsigned short pci_device_ids[] = {
689 0x1c40, 0x1c41, 0x1c42, 0x1c43, 0x1c44, 0x1c45, 0x1c46, 0x1c47, 0x1c48,
690 0x1c49, 0x1c4a, 0x1c4b, 0x1c4c, 0x1c4d, 0x1c4e, 0x1c4f, 0x1c50, 0x1c51,
691 0x1c52, 0x1c53, 0x1c54, 0x1c55, 0x1c56, 0x1c57, 0x1c58, 0x1c59, 0x1c5a,
692 0x1c5b, 0x1c5c, 0x1c5d, 0x1c5e, 0x1c5f,
693
694 0x1e41, 0x1e42, 0x1e43, 0x1e44, 0x1e45, 0x1e46, 0x1e47, 0x1e48, 0x1e49,
695 0x1e4a, 0x1e4b, 0x1e4c, 0x1e4d, 0x1e4e, 0x1e4f, 0x1e50, 0x1e51, 0x1e52,
696 0x1e53, 0x1e54, 0x1e55, 0x1e56, 0x1e57, 0x1e58, 0x1e59, 0x1e5a, 0x1e5b,
697 0x1e5c, 0x1e5d, 0x1e5e, 0x1e5f,
698
699 0 };
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700700
701static const struct pci_driver pch_lpc __pci_driver = {
702 .ops = &device_ops,
703 .vendor = PCI_VENDOR_ID_INTEL,
704 .devices = pci_device_ids,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200705};