blob: ee416c1753f6b758e2c37ed57abcfe9d4190b5e9 [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
Nico Huber9faae2b2018-11-14 00:00:35 +0100165 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200166 int nmi_option;
167
168 /* Which state do we want to goto after g3 (power restored)?
169 * 0 == S0 Full On
170 * 1 == S5 Soft Off
171 *
172 * If the option is not existent (Laptops), use Kconfig setting.
173 */
174 get_option(&pwr_on, "power_on_after_fail");
175
176 reg16 = pci_read_config16(dev, GEN_PMCON_3);
177 reg16 &= 0xfffe;
178 switch (pwr_on) {
179 case MAINBOARD_POWER_OFF:
180 reg16 |= 1;
181 state = "off";
182 break;
183 case MAINBOARD_POWER_ON:
184 reg16 &= ~1;
185 state = "on";
186 break;
187 case MAINBOARD_POWER_KEEP:
188 reg16 &= ~1;
189 state = "state keep";
190 break;
191 default:
192 state = "undefined";
193 }
194
195 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
196 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
197
198 reg16 &= ~(1 << 10);
199 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
200
201 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
202
203 pci_write_config16(dev, GEN_PMCON_3, reg16);
204 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
205
206 /* Set up NMI on errors. */
207 reg8 = inb(0x61);
208 reg8 &= 0x0f; /* Higher Nibble must be 0 */
209 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
210 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
211 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
212 outb(reg8, 0x61);
213
214 reg8 = inb(0x70);
215 nmi_option = NMI_OFF;
216 get_option(&nmi_option, "nmi");
217 if (nmi_option) {
218 printk(BIOS_INFO, "NMI sources enabled.\n");
219 reg8 &= ~(1 << 7); /* Set NMI. */
220 } else {
221 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200222 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200223 }
224 outb(reg8, 0x70);
225
226 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
227 reg16 = pci_read_config16(dev, GEN_PMCON_1);
228 reg16 &= ~(3 << 0); // SMI# rate 1 minute
229 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
Kyösti Mälkki94464472020-06-13 13:45:42 +0300230 if (CONFIG(DEBUG_PERIODIC_SMI))
231 reg16 |= (3 << 0); // Periodic SMI every 8s
Stefan Reinauer8e073822012-04-04 00:07:22 +0200232 pci_write_config16(dev, GEN_PMCON_1, reg16);
233
234 // Set the board's GPI routing.
235 pch_gpi_routing(dev);
236
237 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
238
239 outl(config->gpe0_en, pmbase + GPE0_EN);
240 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
241
242 /* Set up power management block and determine sleep mode */
243 reg32 = inl(pmbase + 0x04); // PM1_CNT
244 reg32 &= ~(7 << 10); // SLP_TYP
245 reg32 |= (1 << 0); // SCI_EN
246 outl(reg32, pmbase + 0x04);
247
248 /* Clear magic status bits to prevent unexpected wake */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200249 reg32 = RCBA32(PRSTS);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200250 reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200251 RCBA32(PRSTS) = reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200252
253 reg32 = RCBA32(0x3f02);
254 reg32 &= ~0xf;
255 RCBA32(0x3f02) = reg32;
256}
257
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700258/* CougarPoint PCH Power Management init */
259static void cpt_pm_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200260{
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700261 printk(BIOS_DEBUG, "CougarPoint PM init\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200262 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200263 RCBA32_AND_OR(CIR30, ~0UL, (1 << 6)|(1 << 0));
264 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
265 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
266 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
267 RCBA32(DMC) = 0xc0388400;
268 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
269 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
270 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
271 RCBA32(PM_CFG) = 0x050f0000;
272 RCBA32(CIR8) = 0x04000000;
273 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
274 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1));
275 RCBA32(CIR12) = 0x0001c000;
276 RCBA32(CIR14) = 0x00061100;
277 RCBA32(CIR15) = 0x7f8fdfff;
278 RCBA32(CIR13) = 0x000003fc;
279 RCBA32(CIR16) = 0x00001000;
280 RCBA32(CIR18) = 0x0001c000;
281 RCBA32(CIR17) = 0x00000800;
282 RCBA32(CIR23) = 0x00001000;
283 RCBA32(CIR19) = 0x00093900;
284 RCBA32(CIR20) = 0x24653002;
285 RCBA32(CIR21) = 0x062108fe;
286 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
287 RCBA32(CIR24) = 0x01010000;
288 RCBA32(CIR25) = 0x01010404;
289 RCBA32(CIR27) = 0x01041041;
290 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
291 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
292 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
293 RCBA32(CIR26) = 0x00000001;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200294 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
295 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200296 RCBA32(PMSYNC_CFG) = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200297 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
298}
299
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700300/* PantherPoint PCH Power Management init */
301static void ppt_pm_init(struct device *dev)
302{
303 printk(BIOS_DEBUG, "PantherPoint PM init\n");
304 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200305 RCBA32_AND_OR(CIR30, ~0UL, (1 << 0));
306 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
307 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
308 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
309 RCBA32(DMC) = 0xc03b8400;
310 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
311 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
312 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
313 RCBA32(PM_CFG) = 0x054f0000;
314 RCBA32(CIR8) = 0x04000000;
315 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
316 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1)|(1 << 0));
317 RCBA32(CIR12) = 0x0001c000;
318 RCBA32(CIR14) = 0x00061100;
319 RCBA32(CIR15) = 0x7f8fdfff;
320 RCBA32(CIR13) = 0x000003fd;
321 RCBA32(CIR16) = 0x00001000;
322 RCBA32(CIR18) = 0x0001c000;
323 RCBA32(CIR17) = 0x00000800;
324 RCBA32(CIR23) = 0x00001000;
325 RCBA32(CIR19) = 0x00093900;
326 RCBA32(CIR20) = 0x24653002;
327 RCBA32(CIR21) = 0x067388fe;
328 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
329 RCBA32(CIR24) = 0x01010000;
330 RCBA32(CIR25) = 0x01010404;
331 RCBA32(CIR27) = 0x01040000;
332 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
333 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
334 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
335 RCBA32(CIR26) = 0x00000001;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700336 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
337 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
338 RCBA32_AND_OR(0x33a4, ~0UL, (1 << 0));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200339 RCBA32(PMSYNC_CFG) = 0;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700340 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
341}
342
Nico Huberb2dae792015-10-26 12:34:02 +0100343static void enable_hpet(struct device *const dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200344{
345 u32 reg32;
Nico Huberb2dae792015-10-26 12:34:02 +0100346 size_t i;
347
348 /* Assign unique bus/dev/fn for each HPET */
349 for (i = 0; i < 8; ++i)
350 pci_write_config16(dev, LPC_HnBDF(i),
351 PCH_HPET_PCI_BUS << 8 | PCH_HPET_PCI_SLOT << 3 | i);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200352
353 /* Move HPET to default address 0xfed00000 and enable it */
354 reg32 = RCBA32(HPTC);
355 reg32 |= (1 << 7); // HPET Address Enable
356 reg32 &= ~(3 << 0);
357 RCBA32(HPTC) = reg32;
358}
359
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200360static void enable_clock_gating(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200361{
362 u32 reg32;
363 u16 reg16;
364
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200365 RCBA32_AND_OR(DMIC, ~0UL, 0xf);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200366
367 reg16 = pci_read_config16(dev, GEN_PMCON_1);
Michał Żygowski9ff2af22020-04-13 20:37:36 +0200368 reg16 &= ~(3 << 2); /* Clear CLKRUN bits for mobile and desktop */
369 if (get_platform_type() == PLATFORM_MOBILE)
370 reg16 |= (1 << 2); /* CLKRUN_EN for mobile */
371 else if (get_platform_type() == PLATFORM_DESKTOP_SERVER)
372 reg16 |= (1 << 3); /* PSEUDO_CLKRUN_EN for desktop */
373 reg16 |= (1 << 11);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200374 pci_write_config16(dev, GEN_PMCON_1, reg16);
375
376 pch_iobp_update(0xEB007F07, ~0UL, (1 << 31));
377 pch_iobp_update(0xEB004000, ~0UL, (1 << 7));
378 pch_iobp_update(0xEC007F07, ~0UL, (1 << 31));
379 pch_iobp_update(0xEC004000, ~0UL, (1 << 7));
380
381 reg32 = RCBA32(CG);
382 reg32 |= (1 << 31);
383 reg32 |= (1 << 29) | (1 << 28);
384 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
385 reg32 |= (1 << 16);
386 reg32 |= (1 << 17);
387 reg32 |= (1 << 18);
388 reg32 |= (1 << 22);
389 reg32 |= (1 << 23);
390 reg32 &= ~(1 << 20);
391 reg32 |= (1 << 19);
392 reg32 |= (1 << 0);
393 reg32 |= (0xf << 1);
394 RCBA32(CG) = reg32;
395
396 RCBA32_OR(0x38c0, 0x7);
397 RCBA32_OR(0x36d4, 0x6680c004);
398 RCBA32_OR(0x3564, 0x3);
399}
400
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200401static void pch_set_acpi_mode(void)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200402{
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300403 if (!acpi_is_wakeup_s3()) {
Kyösti Mälkkib6585482020-06-01 15:11:14 +0300404 apm_control(APM_CNT_ACPI_DISABLE);
Duncan Laurie95be1d62012-04-09 12:31:43 -0700405 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200406}
Stefan Reinauer8e073822012-04-04 00:07:22 +0200407
Stefan Reinauer8e073822012-04-04 00:07:22 +0200408static void pch_fixups(struct device *dev)
409{
Stefan Reinauer8e073822012-04-04 00:07:22 +0200410 /* Indicate DRAM init done for MRC S3 to know it can resume */
Angel Ponsc803f652020-06-07 22:09:01 +0200411 pci_or_config8(dev, GEN_PMCON_2, 1 << 7);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200412
413 /*
414 * Enable DMI ASPM in the PCH
415 */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200416 RCBA32_AND_OR(DMC, ~(1 << 10), 0);
417 RCBA32_OR(LCAP, (1 << 11)|(1 << 10));
418 RCBA32_OR(LCTL, 0x3);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200419}
420
Nico Huber7b2f9f62015-10-01 19:00:51 +0200421static void pch_spi_init(const struct device *const dev)
422{
423 const config_t *const config = dev->chip_info;
424
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100425 printk(BIOS_DEBUG, "%s\n", __func__);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200426
427 if (config->spi_uvscc)
428 RCBA32(0x3800 + 0xc8) = config->spi_uvscc;
429 if (config->spi_lvscc)
430 RCBA32(0x3800 + 0xc4) = config->spi_lvscc;
431
432 if (config->spi_uvscc || config->spi_lvscc)
433 RCBA32_OR(0x3800 + 0xc4, 1 << 23); /* lock both UVSCC + LVSCC */
434}
435
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200436static const struct {
437 u16 dev_id;
438 const char *dev_name;
439} pch_table[] = {
440 /* 6-series PCI ids from
441 * Intel® 6 Series Chipset and
442 * Intel® C200 Series Chipset
443 * Specification Update - NDA
444 * October 2013
445 * CDI / IBP#: 440377
446 */
447 {0x1C41, "SFF Sample"},
448 {0x1C42, "Desktop Sample"},
449 {0x1C43, "Mobile Sample"},
450 {0x1C44, "Z68"},
451 {0x1C46, "P67"},
452 {0x1C47, "UM67"},
453 {0x1C49, "HM65"},
454 {0x1C4A, "H67"},
455 {0x1C4B, "HM67"},
456 {0x1C4C, "Q65"},
457 {0x1C4D, "QS67"},
458 {0x1C4E, "Q67"},
459 {0x1C4F, "QM67"},
460 {0x1C50, "B65"},
461 {0x1C52, "C202"},
462 {0x1C54, "C204"},
463 {0x1C56, "C206"},
464 {0x1C5C, "H61"},
465 /* 7-series PCI ids from Intel document 472178 */
466 {0x1E41, "Desktop Sample"},
467 {0x1E42, "Mobile Sample"},
468 {0x1E43, "SFF Sample"},
469 {0x1E44, "Z77"},
470 {0x1E45, "H71"},
471 {0x1E46, "Z75"},
472 {0x1E47, "Q77"},
473 {0x1E48, "Q75"},
474 {0x1E49, "B75"},
475 {0x1E4A, "H77"},
476 {0x1E53, "C216"},
477 {0x1E55, "QM77"},
478 {0x1E56, "QS77"},
479 {0x1E58, "UM77"},
480 {0x1E57, "HM77"},
481 {0x1E59, "HM76"},
482 {0x1E5D, "HM75"},
483 {0x1E5E, "HM70"},
484 {0x1E5F, "NM70"},
485};
486
487static void report_pch_info(struct device *dev)
488{
489 const u16 dev_id = pci_read_config16(dev, PCI_DEVICE_ID);
490 int i;
491
492 const char *pch_type = "Unknown";
493 for (i = 0; i < ARRAY_SIZE(pch_table); i++) {
494 if (pch_table[i].dev_id == dev_id) {
495 pch_type = pch_table[i].dev_name;
496 break;
497 }
498 }
499 printk(BIOS_INFO, "PCH: detected %s, device id: 0x%x, rev id 0x%x\n",
500 pch_type, dev_id, pci_read_config8(dev, PCI_CLASS_REVISION));
501}
502
Stefan Reinauer8e073822012-04-04 00:07:22 +0200503static void lpc_init(struct device *dev)
504{
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100505 printk(BIOS_DEBUG, "pch: %s\n", __func__);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200506
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200507 /* Print detected platform */
508 report_pch_info(dev);
509
Stefan Reinauer8e073822012-04-04 00:07:22 +0200510 /* IO APIC initialization. */
Paul Menzel9c50e6a2013-05-03 12:23:39 +0200511 pch_enable_ioapic(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200512
513 pch_enable_serial_irqs(dev);
514
515 /* Setup the PIRQ. */
516 pch_pirq_init(dev);
517
518 /* Setup power options. */
519 pch_power_options(dev);
520
521 /* Initialize power management */
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700522 switch (pch_silicon_type()) {
523 case PCH_TYPE_CPT: /* CougarPoint */
524 cpt_pm_init(dev);
525 break;
526 case PCH_TYPE_PPT: /* PantherPoint */
527 ppt_pm_init(dev);
528 break;
529 default:
530 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
531 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200532
Stefan Reinauer8e073822012-04-04 00:07:22 +0200533 /* Initialize the real time clock. */
Patrick Rudolph6b931122018-11-01 17:48:37 +0100534 sb_rtc_init();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200535
536 /* Initialize ISA DMA. */
537 isa_dma_init();
538
539 /* Initialize the High Precision Event Timers, if present. */
Nico Huberb2dae792015-10-26 12:34:02 +0100540 enable_hpet(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200541
542 /* Initialize Clock Gating */
543 enable_clock_gating(dev);
544
545 setup_i8259();
546
547 /* The OS should do this? */
548 /* Interrupt 9 should be level triggered (SCI) */
549 i8259_configure_irq_trigger(9, 1);
550
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200551 pch_set_acpi_mode();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200552
553 pch_fixups(dev);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200554
555 pch_spi_init(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200556}
557
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200558static void pch_lpc_read_resources(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200559{
560 struct resource *res;
Marc Jonesa0bec172012-07-13 14:14:34 -0600561 config_t *config = dev->chip_info;
562 u8 io_index = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200563
564 /* Get the normal PCI resources of this device. */
565 pci_dev_read_resources(dev);
566
567 /* Add an extra subtractive resource for both memory and I/O. */
Marc Jonesa0bec172012-07-13 14:14:34 -0600568 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200569 res->base = 0;
570 res->size = 0x1000;
571 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
572 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
573
Marc Jonesa0bec172012-07-13 14:14:34 -0600574 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Vladimir Serbinenko0650cd02014-02-05 15:03:50 +0100575 res->base = 0xff000000;
576 /* Some systems (e.g. X230) have 12 MiB flash.
577 SPI controller supports up to 2 x 16 MiB of flash but
578 address map limits this to 16MiB. */
579 res->size = 0x01000000; /* 16 MB for flash */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200580 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
581 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
582
583 res = new_resource(dev, 3); /* IOAPIC */
584 res->base = IO_APIC_ADDR;
585 res->size = 0x00001000;
586 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Marc Jonesa0bec172012-07-13 14:14:34 -0600587
588 /* Set PCH IO decode ranges if required.*/
589 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
590 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
591 res->base = config->gen1_dec & 0xFFFC;
592 res->size = (config->gen1_dec >> 16) & 0xFC;
593 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
594 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
595 }
596
597 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
598 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
599 res->base = config->gen2_dec & 0xFFFC;
600 res->size = (config->gen2_dec >> 16) & 0xFC;
601 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
602 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
603 }
604
605 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
606 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
607 res->base = config->gen3_dec & 0xFFFC;
608 res->size = (config->gen3_dec >> 16) & 0xFC;
609 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
610 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
611 }
612
613 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
614 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
615 res->base = config->gen4_dec & 0xFFFC;
616 res->size = (config->gen4_dec >> 16) & 0xFC;
617 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
618 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
619 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200620}
621
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200622static void pch_lpc_enable(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200623{
624 /* Enable PCH Display Port */
625 RCBA16(DISPBDF) = 0x0010;
626 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
627
628 pch_enable(dev);
629}
630
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600631static const char *lpc_acpi_name(const struct device *dev)
Patrick Rudolph604f6982017-06-07 09:46:52 +0200632{
633 return "LPCB";
634}
635
Furquan Shaikh7536a392020-04-24 21:59:21 -0700636static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100637{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300638 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100639 config_t *chip = dev->chip_info;
640
641 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Tobias Diedrich7f5efd92017-12-14 00:29:01 +0100642 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100643}
644
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200645static void lpc_final(struct device *dev)
646{
Arthur Heymansebf201b2019-05-28 13:51:36 +0200647 spi_finalize_ops();
Nico Huber8e50b6d2018-02-04 15:52:18 +0100648
Bill XIEd533b162017-08-22 16:26:22 +0800649 /* Call SMM finalize() handlers before resume */
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300650 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
651 acpi_is_wakeup_s3()) {
652 apm_control(APM_CNT_FINALIZE);
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200653 }
654}
655
Arthur Heymansebf201b2019-05-28 13:51:36 +0200656void intel_southbridge_override_spi(
657 struct intel_swseq_spi_config *spi_config)
658{
659 struct device *dev = pcidev_on_root(0x1f, 0);
660
661 if (!dev)
662 return;
663 /* Devicetree may override defaults. */
664 const config_t *const config = dev->chip_info;
665
666 if (!config)
667 return;
668
669 if (config->spi.ops[0].op != 0)
670 memcpy(spi_config, &config->spi, sizeof(*spi_config));
671}
672
Stefan Reinauer8e073822012-04-04 00:07:22 +0200673static struct device_operations device_ops = {
674 .read_resources = pch_lpc_read_resources,
675 .set_resources = pci_dev_set_resources,
Arthur Heymans3cde4942019-08-18 10:02:10 +0200676 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200677 .write_acpi_tables = acpi_write_hpet,
Nico Huber68680dd2020-03-31 17:34:52 +0200678 .acpi_fill_ssdt = southbridge_fill_ssdt,
Patrick Rudolph604f6982017-06-07 09:46:52 +0200679 .acpi_name = lpc_acpi_name,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200680 .init = lpc_init,
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200681 .final = lpc_final,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200682 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100683 .scan_bus = scan_static_bus,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200684 .ops_pci = &pci_dev_ops_pci,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200685};
686
Kimarie Hoote6f459c2012-07-14 08:26:08 -0600687/* IDs for LPC device of Intel 6 Series Chipset, Intel 7 Series Chipset, and
688 * Intel C200 Series Chipset
Stefan Reinauer8e073822012-04-04 00:07:22 +0200689 */
690
Vladimir Serbinenko42d55e02016-01-02 01:47:26 +0100691static const unsigned short pci_device_ids[] = {
692 0x1c40, 0x1c41, 0x1c42, 0x1c43, 0x1c44, 0x1c45, 0x1c46, 0x1c47, 0x1c48,
693 0x1c49, 0x1c4a, 0x1c4b, 0x1c4c, 0x1c4d, 0x1c4e, 0x1c4f, 0x1c50, 0x1c51,
694 0x1c52, 0x1c53, 0x1c54, 0x1c55, 0x1c56, 0x1c57, 0x1c58, 0x1c59, 0x1c5a,
695 0x1c5b, 0x1c5c, 0x1c5d, 0x1c5e, 0x1c5f,
696
697 0x1e41, 0x1e42, 0x1e43, 0x1e44, 0x1e45, 0x1e46, 0x1e47, 0x1e48, 0x1e49,
698 0x1e4a, 0x1e4b, 0x1e4c, 0x1e4d, 0x1e4e, 0x1e4f, 0x1e50, 0x1e51, 0x1e52,
699 0x1e53, 0x1e54, 0x1e55, 0x1e56, 0x1e57, 0x1e58, 0x1e59, 0x1e5a, 0x1e5b,
700 0x1e5c, 0x1e5d, 0x1e5e, 0x1e5f,
701
702 0 };
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700703
704static const struct pci_driver pch_lpc __pci_driver = {
705 .ops = &device_ops,
706 .vendor = PCI_VENDOR_ID_INTEL,
707 .devices = pci_device_ids,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200708};