blob: dfebaf0dace1670e29c602a0be42ac2ab61916e9 [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{
Stefan Reinauer8e073822012-04-04 00:07:22 +020040 u32 reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +020041
Nico Huberb2dae792015-10-26 12:34:02 +010042 /* Assign unique bus/dev/fn for I/O APIC */
43 pci_write_config16(dev, LPC_IBDF,
44 PCH_IOAPIC_PCI_BUS << 8 | PCH_IOAPIC_PCI_SLOT << 3);
45
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080046 set_ioapic_id(VIO_APIC_VADDR, 0x02);
Stefan Reinauer8e073822012-04-04 00:07:22 +020047
48 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080049 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
50 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +020051}
52
53static void pch_enable_serial_irqs(struct device *dev)
54{
55 /* Set packet length and toggle silent mode bit for one frame. */
56 pci_write_config8(dev, SERIRQ_CNTL,
57 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080058#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Stefan Reinauer8e073822012-04-04 00:07:22 +020059 pci_write_config8(dev, SERIRQ_CNTL,
60 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
61#endif
62}
63
64/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
65 * 0x00 - 0000 = Reserved
66 * 0x01 - 0001 = Reserved
67 * 0x02 - 0010 = Reserved
68 * 0x03 - 0011 = IRQ3
69 * 0x04 - 0100 = IRQ4
70 * 0x05 - 0101 = IRQ5
71 * 0x06 - 0110 = IRQ6
72 * 0x07 - 0111 = IRQ7
73 * 0x08 - 1000 = Reserved
74 * 0x09 - 1001 = IRQ9
75 * 0x0A - 1010 = IRQ10
76 * 0x0B - 1011 = IRQ11
77 * 0x0C - 1100 = IRQ12
78 * 0x0D - 1101 = Reserved
79 * 0x0E - 1110 = IRQ14
80 * 0x0F - 1111 = IRQ15
81 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
82 * 0x80 - The PIRQ is not routed.
83 */
84
Elyes HAOUAS4aec3402018-05-25 08:29:27 +020085static void pch_pirq_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020086{
Elyes HAOUAS4aec3402018-05-25 08:29:27 +020087 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020088 /* Interrupt 11 is not used by legacy devices and so can always be used for
89 PCI interrupts. Full legacy IRQ routing is complicated and hard to
90 get right. Fortunately all modern OS use MSI and so it's not that big of
91 an issue anyway. Still we have to provide a reasonable default. Using
92 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
93 move it to any interrupt and others will just leave them at default.
Stefan Reinauer8e073822012-04-04 00:07:22 +020094 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020095 const u8 pirq_routing = 11;
96
97 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
98 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
99 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
100 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
101
102 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
103 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
104 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
105 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200106
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200107 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200108 u8 int_pin=0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200109
110 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
111 continue;
112
113 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
114
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200115 if (int_pin == 0)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200116 continue;
117
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200118 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200119 }
120}
121
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200122static void pch_gpi_routing(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200123{
124 /* Get the chip configuration */
125 config_t *config = dev->chip_info;
126 u32 reg32 = 0;
127
128 /* An array would be much nicer here, or some
129 * other method of doing this.
130 */
131 reg32 |= (config->gpi0_routing & 0x03) << 0;
132 reg32 |= (config->gpi1_routing & 0x03) << 2;
133 reg32 |= (config->gpi2_routing & 0x03) << 4;
134 reg32 |= (config->gpi3_routing & 0x03) << 6;
135 reg32 |= (config->gpi4_routing & 0x03) << 8;
136 reg32 |= (config->gpi5_routing & 0x03) << 10;
137 reg32 |= (config->gpi6_routing & 0x03) << 12;
138 reg32 |= (config->gpi7_routing & 0x03) << 14;
139 reg32 |= (config->gpi8_routing & 0x03) << 16;
140 reg32 |= (config->gpi9_routing & 0x03) << 18;
141 reg32 |= (config->gpi10_routing & 0x03) << 20;
142 reg32 |= (config->gpi11_routing & 0x03) << 22;
143 reg32 |= (config->gpi12_routing & 0x03) << 24;
144 reg32 |= (config->gpi13_routing & 0x03) << 26;
145 reg32 |= (config->gpi14_routing & 0x03) << 28;
146 reg32 |= (config->gpi15_routing & 0x03) << 30;
147
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200148 pci_write_config32(dev, GPIO_ROUT, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200149}
150
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200151static void pch_power_options(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200152{
153 u8 reg8;
154 u16 reg16, pmbase;
155 u32 reg32;
156 const char *state;
157 /* Get the chip configuration */
158 config_t *config = dev->chip_info;
159
Stefan Reinauer8e073822012-04-04 00:07:22 +0200160 /* Which state do we want to goto after g3 (power restored)?
161 * 0 == S0 Full On
162 * 1 == S5 Soft Off
163 *
164 * If the option is not existent (Laptops), use Kconfig setting.
165 */
Angel Pons88dcb312021-04-26 17:10:28 +0200166 const unsigned int pwr_on = get_uint_option("power_on_after_fail",
Angel Pons62719a32021-04-19 13:15:28 +0200167 CONFIG_MAINBOARD_POWER_FAILURE_STATE);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200168
169 reg16 = pci_read_config16(dev, GEN_PMCON_3);
170 reg16 &= 0xfffe;
171 switch (pwr_on) {
172 case MAINBOARD_POWER_OFF:
173 reg16 |= 1;
174 state = "off";
175 break;
176 case MAINBOARD_POWER_ON:
177 reg16 &= ~1;
178 state = "on";
179 break;
180 case MAINBOARD_POWER_KEEP:
181 reg16 &= ~1;
182 state = "state keep";
183 break;
184 default:
185 state = "undefined";
186 }
187
188 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
189 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
190
191 reg16 &= ~(1 << 10);
192 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
193
194 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
195
196 pci_write_config16(dev, GEN_PMCON_3, reg16);
197 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
198
199 /* Set up NMI on errors. */
200 reg8 = inb(0x61);
201 reg8 &= 0x0f; /* Higher Nibble must be 0 */
202 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
203 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
204 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
205 outb(reg8, 0x61);
206
207 reg8 = inb(0x70);
Angel Pons88dcb312021-04-26 17:10:28 +0200208 const unsigned int nmi_option = get_uint_option("nmi", NMI_OFF);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200209 if (nmi_option) {
210 printk(BIOS_INFO, "NMI sources enabled.\n");
211 reg8 &= ~(1 << 7); /* Set NMI. */
212 } else {
213 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200214 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200215 }
216 outb(reg8, 0x70);
217
218 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
219 reg16 = pci_read_config16(dev, GEN_PMCON_1);
220 reg16 &= ~(3 << 0); // SMI# rate 1 minute
221 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
Kyösti Mälkki94464472020-06-13 13:45:42 +0300222 if (CONFIG(DEBUG_PERIODIC_SMI))
223 reg16 |= (3 << 0); // Periodic SMI every 8s
Stefan Reinauer8e073822012-04-04 00:07:22 +0200224 pci_write_config16(dev, GEN_PMCON_1, reg16);
225
226 // Set the board's GPI routing.
227 pch_gpi_routing(dev);
228
229 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
230
231 outl(config->gpe0_en, pmbase + GPE0_EN);
232 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
233
234 /* Set up power management block and determine sleep mode */
235 reg32 = inl(pmbase + 0x04); // PM1_CNT
236 reg32 &= ~(7 << 10); // SLP_TYP
237 reg32 |= (1 << 0); // SCI_EN
238 outl(reg32, pmbase + 0x04);
239
240 /* Clear magic status bits to prevent unexpected wake */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200241 reg32 = RCBA32(PRSTS);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200242 reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200243 RCBA32(PRSTS) = reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200244
245 reg32 = RCBA32(0x3f02);
246 reg32 &= ~0xf;
247 RCBA32(0x3f02) = reg32;
248}
249
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700250/* CougarPoint PCH Power Management init */
251static void cpt_pm_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200252{
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700253 printk(BIOS_DEBUG, "CougarPoint PM init\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200254 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200255 RCBA32_AND_OR(CIR30, ~0U, (1 << 6)|(1 << 0));
256 RCBA32_AND_OR(CIR5, ~0U, (1 << 0));
257 RCBA16_AND_OR(CIR3, ~0U, (1 << 13)|(1 << 14));
258 RCBA16_AND_OR(CIR2, ~0U, (1 << 14));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200259 RCBA32(DMC) = 0xc0388400;
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200260 RCBA32_AND_OR(CIR6, ~0U, (1 << 5)|(1 << 18));
261 RCBA32_AND_OR(CIR9, ~0U, (1 << 15)|(1 << 1));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200262 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
263 RCBA32(PM_CFG) = 0x050f0000;
264 RCBA32(CIR8) = 0x04000000;
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200265 RCBA32_AND_OR(CIR10, ~0U, 0xfffff);
266 RCBA32_AND_OR(CIR11, ~0U, (1 << 1));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200267 RCBA32(CIR12) = 0x0001c000;
268 RCBA32(CIR14) = 0x00061100;
269 RCBA32(CIR15) = 0x7f8fdfff;
270 RCBA32(CIR13) = 0x000003fc;
271 RCBA32(CIR16) = 0x00001000;
272 RCBA32(CIR18) = 0x0001c000;
273 RCBA32(CIR17) = 0x00000800;
274 RCBA32(CIR23) = 0x00001000;
275 RCBA32(CIR19) = 0x00093900;
276 RCBA32(CIR20) = 0x24653002;
277 RCBA32(CIR21) = 0x062108fe;
278 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
279 RCBA32(CIR24) = 0x01010000;
280 RCBA32(CIR25) = 0x01010404;
281 RCBA32(CIR27) = 0x01041041;
282 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
283 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
284 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
285 RCBA32(CIR26) = 0x00000001;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200286 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
287 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200288 RCBA32(PMSYNC_CFG) = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200289 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
290}
291
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700292/* PantherPoint PCH Power Management init */
293static void ppt_pm_init(struct device *dev)
294{
295 printk(BIOS_DEBUG, "PantherPoint PM init\n");
296 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200297 RCBA32_AND_OR(CIR30, ~0UL, (1 << 0));
298 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
299 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
300 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
301 RCBA32(DMC) = 0xc03b8400;
302 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
303 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
304 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
305 RCBA32(PM_CFG) = 0x054f0000;
306 RCBA32(CIR8) = 0x04000000;
307 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
308 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1)|(1 << 0));
309 RCBA32(CIR12) = 0x0001c000;
310 RCBA32(CIR14) = 0x00061100;
311 RCBA32(CIR15) = 0x7f8fdfff;
312 RCBA32(CIR13) = 0x000003fd;
313 RCBA32(CIR16) = 0x00001000;
314 RCBA32(CIR18) = 0x0001c000;
315 RCBA32(CIR17) = 0x00000800;
316 RCBA32(CIR23) = 0x00001000;
317 RCBA32(CIR19) = 0x00093900;
318 RCBA32(CIR20) = 0x24653002;
319 RCBA32(CIR21) = 0x067388fe;
320 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
321 RCBA32(CIR24) = 0x01010000;
322 RCBA32(CIR25) = 0x01010404;
323 RCBA32(CIR27) = 0x01040000;
324 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
325 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
326 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
327 RCBA32(CIR26) = 0x00000001;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700328 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
329 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
330 RCBA32_AND_OR(0x33a4, ~0UL, (1 << 0));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200331 RCBA32(PMSYNC_CFG) = 0;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700332 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
333}
334
Nico Huberb2dae792015-10-26 12:34:02 +0100335static void enable_hpet(struct device *const dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200336{
337 u32 reg32;
Nico Huberb2dae792015-10-26 12:34:02 +0100338 size_t i;
339
340 /* Assign unique bus/dev/fn for each HPET */
341 for (i = 0; i < 8; ++i)
342 pci_write_config16(dev, LPC_HnBDF(i),
343 PCH_HPET_PCI_BUS << 8 | PCH_HPET_PCI_SLOT << 3 | i);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200344
345 /* Move HPET to default address 0xfed00000 and enable it */
346 reg32 = RCBA32(HPTC);
347 reg32 |= (1 << 7); // HPET Address Enable
348 reg32 &= ~(3 << 0);
349 RCBA32(HPTC) = reg32;
350}
351
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200352static void enable_clock_gating(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200353{
354 u32 reg32;
355 u16 reg16;
356
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200357 RCBA32_AND_OR(DMIC, ~0UL, 0xf);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200358
359 reg16 = pci_read_config16(dev, GEN_PMCON_1);
Michał Żygowski9ff2af22020-04-13 20:37:36 +0200360 reg16 &= ~(3 << 2); /* Clear CLKRUN bits for mobile and desktop */
361 if (get_platform_type() == PLATFORM_MOBILE)
362 reg16 |= (1 << 2); /* CLKRUN_EN for mobile */
363 else if (get_platform_type() == PLATFORM_DESKTOP_SERVER)
364 reg16 |= (1 << 3); /* PSEUDO_CLKRUN_EN for desktop */
365 reg16 |= (1 << 11);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200366 pci_write_config16(dev, GEN_PMCON_1, reg16);
367
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200368 pch_iobp_update(0xEB007F07, ~0U, (1 << 31));
369 pch_iobp_update(0xEB004000, ~0U, (1 << 7));
370 pch_iobp_update(0xEC007F07, ~0U, (1 << 31));
371 pch_iobp_update(0xEC004000, ~0U, (1 << 7));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200372
373 reg32 = RCBA32(CG);
374 reg32 |= (1 << 31);
375 reg32 |= (1 << 29) | (1 << 28);
376 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
377 reg32 |= (1 << 16);
378 reg32 |= (1 << 17);
379 reg32 |= (1 << 18);
380 reg32 |= (1 << 22);
381 reg32 |= (1 << 23);
382 reg32 &= ~(1 << 20);
383 reg32 |= (1 << 19);
384 reg32 |= (1 << 0);
385 reg32 |= (0xf << 1);
386 RCBA32(CG) = reg32;
387
388 RCBA32_OR(0x38c0, 0x7);
389 RCBA32_OR(0x36d4, 0x6680c004);
390 RCBA32_OR(0x3564, 0x3);
391}
392
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200393static void pch_set_acpi_mode(void)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200394{
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300395 if (!acpi_is_wakeup_s3()) {
Kyösti Mälkkib6585482020-06-01 15:11:14 +0300396 apm_control(APM_CNT_ACPI_DISABLE);
Duncan Laurie95be1d62012-04-09 12:31:43 -0700397 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200398}
Stefan Reinauer8e073822012-04-04 00:07:22 +0200399
Stefan Reinauer8e073822012-04-04 00:07:22 +0200400static void pch_fixups(struct device *dev)
401{
Stefan Reinauer8e073822012-04-04 00:07:22 +0200402 /* Indicate DRAM init done for MRC S3 to know it can resume */
Angel Ponsc803f652020-06-07 22:09:01 +0200403 pci_or_config8(dev, GEN_PMCON_2, 1 << 7);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200404
405 /*
406 * Enable DMI ASPM in the PCH
407 */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200408 RCBA32_AND_OR(DMC, ~(1 << 10), 0);
409 RCBA32_OR(LCAP, (1 << 11)|(1 << 10));
410 RCBA32_OR(LCTL, 0x3);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200411}
412
Nico Huber7b2f9f62015-10-01 19:00:51 +0200413static void pch_spi_init(const struct device *const dev)
414{
415 const config_t *const config = dev->chip_info;
416
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100417 printk(BIOS_DEBUG, "%s\n", __func__);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200418
419 if (config->spi_uvscc)
420 RCBA32(0x3800 + 0xc8) = config->spi_uvscc;
421 if (config->spi_lvscc)
422 RCBA32(0x3800 + 0xc4) = config->spi_lvscc;
423
424 if (config->spi_uvscc || config->spi_lvscc)
425 RCBA32_OR(0x3800 + 0xc4, 1 << 23); /* lock both UVSCC + LVSCC */
426}
427
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200428static const struct {
429 u16 dev_id;
430 const char *dev_name;
431} pch_table[] = {
432 /* 6-series PCI ids from
433 * Intel® 6 Series Chipset and
434 * Intel® C200 Series Chipset
435 * Specification Update - NDA
436 * October 2013
437 * CDI / IBP#: 440377
438 */
439 {0x1C41, "SFF Sample"},
440 {0x1C42, "Desktop Sample"},
441 {0x1C43, "Mobile Sample"},
442 {0x1C44, "Z68"},
443 {0x1C46, "P67"},
444 {0x1C47, "UM67"},
445 {0x1C49, "HM65"},
446 {0x1C4A, "H67"},
447 {0x1C4B, "HM67"},
448 {0x1C4C, "Q65"},
449 {0x1C4D, "QS67"},
450 {0x1C4E, "Q67"},
451 {0x1C4F, "QM67"},
452 {0x1C50, "B65"},
453 {0x1C52, "C202"},
454 {0x1C54, "C204"},
455 {0x1C56, "C206"},
456 {0x1C5C, "H61"},
457 /* 7-series PCI ids from Intel document 472178 */
458 {0x1E41, "Desktop Sample"},
459 {0x1E42, "Mobile Sample"},
460 {0x1E43, "SFF Sample"},
461 {0x1E44, "Z77"},
462 {0x1E45, "H71"},
463 {0x1E46, "Z75"},
464 {0x1E47, "Q77"},
465 {0x1E48, "Q75"},
466 {0x1E49, "B75"},
467 {0x1E4A, "H77"},
468 {0x1E53, "C216"},
469 {0x1E55, "QM77"},
470 {0x1E56, "QS77"},
471 {0x1E58, "UM77"},
472 {0x1E57, "HM77"},
473 {0x1E59, "HM76"},
474 {0x1E5D, "HM75"},
475 {0x1E5E, "HM70"},
476 {0x1E5F, "NM70"},
477};
478
479static void report_pch_info(struct device *dev)
480{
481 const u16 dev_id = pci_read_config16(dev, PCI_DEVICE_ID);
482 int i;
483
484 const char *pch_type = "Unknown";
485 for (i = 0; i < ARRAY_SIZE(pch_table); i++) {
486 if (pch_table[i].dev_id == dev_id) {
487 pch_type = pch_table[i].dev_name;
488 break;
489 }
490 }
491 printk(BIOS_INFO, "PCH: detected %s, device id: 0x%x, rev id 0x%x\n",
492 pch_type, dev_id, pci_read_config8(dev, PCI_CLASS_REVISION));
493}
494
Stefan Reinauer8e073822012-04-04 00:07:22 +0200495static void lpc_init(struct device *dev)
496{
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100497 printk(BIOS_DEBUG, "pch: %s\n", __func__);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200498
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200499 /* Print detected platform */
500 report_pch_info(dev);
501
Stefan Reinauer8e073822012-04-04 00:07:22 +0200502 /* IO APIC initialization. */
Paul Menzel9c50e6a2013-05-03 12:23:39 +0200503 pch_enable_ioapic(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200504
505 pch_enable_serial_irqs(dev);
506
507 /* Setup the PIRQ. */
508 pch_pirq_init(dev);
509
510 /* Setup power options. */
511 pch_power_options(dev);
512
513 /* Initialize power management */
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700514 switch (pch_silicon_type()) {
515 case PCH_TYPE_CPT: /* CougarPoint */
516 cpt_pm_init(dev);
517 break;
518 case PCH_TYPE_PPT: /* PantherPoint */
519 ppt_pm_init(dev);
520 break;
521 default:
522 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
523 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200524
Stefan Reinauer8e073822012-04-04 00:07:22 +0200525 /* Initialize the real time clock. */
Patrick Rudolph6b931122018-11-01 17:48:37 +0100526 sb_rtc_init();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200527
528 /* Initialize ISA DMA. */
529 isa_dma_init();
530
531 /* Initialize the High Precision Event Timers, if present. */
Nico Huberb2dae792015-10-26 12:34:02 +0100532 enable_hpet(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200533
534 /* Initialize Clock Gating */
535 enable_clock_gating(dev);
536
537 setup_i8259();
538
539 /* The OS should do this? */
540 /* Interrupt 9 should be level triggered (SCI) */
541 i8259_configure_irq_trigger(9, 1);
542
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200543 pch_set_acpi_mode();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200544
545 pch_fixups(dev);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200546
547 pch_spi_init(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200548}
549
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200550static void pch_lpc_read_resources(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200551{
552 struct resource *res;
Marc Jonesa0bec172012-07-13 14:14:34 -0600553 config_t *config = dev->chip_info;
554 u8 io_index = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200555
556 /* Get the normal PCI resources of this device. */
557 pci_dev_read_resources(dev);
558
559 /* Add an extra subtractive resource for both memory and I/O. */
Marc Jonesa0bec172012-07-13 14:14:34 -0600560 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200561 res->base = 0;
562 res->size = 0x1000;
563 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
564 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
565
Marc Jonesa0bec172012-07-13 14:14:34 -0600566 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Vladimir Serbinenko0650cd02014-02-05 15:03:50 +0100567 res->base = 0xff000000;
568 /* Some systems (e.g. X230) have 12 MiB flash.
569 SPI controller supports up to 2 x 16 MiB of flash but
570 address map limits this to 16MiB. */
571 res->size = 0x01000000; /* 16 MB for flash */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200572 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
573 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
574
575 res = new_resource(dev, 3); /* IOAPIC */
576 res->base = IO_APIC_ADDR;
577 res->size = 0x00001000;
578 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Marc Jonesa0bec172012-07-13 14:14:34 -0600579
580 /* Set PCH IO decode ranges if required.*/
581 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
582 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
583 res->base = config->gen1_dec & 0xFFFC;
584 res->size = (config->gen1_dec >> 16) & 0xFC;
585 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
586 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
587 }
588
589 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
590 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
591 res->base = config->gen2_dec & 0xFFFC;
592 res->size = (config->gen2_dec >> 16) & 0xFC;
593 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
594 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
595 }
596
597 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
598 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
599 res->base = config->gen3_dec & 0xFFFC;
600 res->size = (config->gen3_dec >> 16) & 0xFC;
601 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
602 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
603 }
604
605 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
606 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
607 res->base = config->gen4_dec & 0xFFFC;
608 res->size = (config->gen4_dec >> 16) & 0xFC;
609 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
610 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
611 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200612}
613
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200614static void pch_lpc_enable(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200615{
616 /* Enable PCH Display Port */
617 RCBA16(DISPBDF) = 0x0010;
618 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
619
620 pch_enable(dev);
621}
622
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600623static const char *lpc_acpi_name(const struct device *dev)
Patrick Rudolph604f6982017-06-07 09:46:52 +0200624{
625 return "LPCB";
626}
627
Furquan Shaikh7536a392020-04-24 21:59:21 -0700628static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100629{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300630 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100631 config_t *chip = dev->chip_info;
632
633 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Tobias Diedrich7f5efd92017-12-14 00:29:01 +0100634 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100635}
636
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200637static void lpc_final(struct device *dev)
638{
Arthur Heymansebf201b2019-05-28 13:51:36 +0200639 spi_finalize_ops();
Nico Huber8e50b6d2018-02-04 15:52:18 +0100640
Bill XIEd533b162017-08-22 16:26:22 +0800641 /* Call SMM finalize() handlers before resume */
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300642 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
643 acpi_is_wakeup_s3()) {
644 apm_control(APM_CNT_FINALIZE);
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200645 }
646}
647
Arthur Heymansebf201b2019-05-28 13:51:36 +0200648void intel_southbridge_override_spi(
649 struct intel_swseq_spi_config *spi_config)
650{
651 struct device *dev = pcidev_on_root(0x1f, 0);
652
653 if (!dev)
654 return;
655 /* Devicetree may override defaults. */
656 const config_t *const config = dev->chip_info;
657
658 if (!config)
659 return;
660
661 if (config->spi.ops[0].op != 0)
662 memcpy(spi_config, &config->spi, sizeof(*spi_config));
663}
664
Stefan Reinauer8e073822012-04-04 00:07:22 +0200665static struct device_operations device_ops = {
666 .read_resources = pch_lpc_read_resources,
667 .set_resources = pci_dev_set_resources,
Arthur Heymans3cde4942019-08-18 10:02:10 +0200668 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200669 .write_acpi_tables = acpi_write_hpet,
Nico Huber68680dd2020-03-31 17:34:52 +0200670 .acpi_fill_ssdt = southbridge_fill_ssdt,
Patrick Rudolph604f6982017-06-07 09:46:52 +0200671 .acpi_name = lpc_acpi_name,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200672 .init = lpc_init,
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200673 .final = lpc_final,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200674 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100675 .scan_bus = scan_static_bus,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200676 .ops_pci = &pci_dev_ops_pci,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200677};
678
Kimarie Hoote6f459c2012-07-14 08:26:08 -0600679/* IDs for LPC device of Intel 6 Series Chipset, Intel 7 Series Chipset, and
680 * Intel C200 Series Chipset
Stefan Reinauer8e073822012-04-04 00:07:22 +0200681 */
682
Vladimir Serbinenko42d55e02016-01-02 01:47:26 +0100683static const unsigned short pci_device_ids[] = {
684 0x1c40, 0x1c41, 0x1c42, 0x1c43, 0x1c44, 0x1c45, 0x1c46, 0x1c47, 0x1c48,
685 0x1c49, 0x1c4a, 0x1c4b, 0x1c4c, 0x1c4d, 0x1c4e, 0x1c4f, 0x1c50, 0x1c51,
686 0x1c52, 0x1c53, 0x1c54, 0x1c55, 0x1c56, 0x1c57, 0x1c58, 0x1c59, 0x1c5a,
687 0x1c5b, 0x1c5c, 0x1c5d, 0x1c5e, 0x1c5f,
688
689 0x1e41, 0x1e42, 0x1e43, 0x1e44, 0x1e45, 0x1e46, 0x1e47, 0x1e48, 0x1e49,
690 0x1e4a, 0x1e4b, 0x1e4c, 0x1e4d, 0x1e4e, 0x1e4f, 0x1e50, 0x1e51, 0x1e52,
691 0x1e53, 0x1e54, 0x1e55, 0x1e56, 0x1e57, 0x1e58, 0x1e59, 0x1e5a, 0x1e5b,
692 0x1e5c, 0x1e5d, 0x1e5e, 0x1e5f,
693
694 0 };
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700695
696static const struct pci_driver pch_lpc __pci_driver = {
697 .ops = &device_ops,
698 .vendor = PCI_VENDOR_ID_INTEL,
699 .devices = pci_device_ids,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200700};