blob: cc2eb287201836209798802ec2d85e8877d67fe8 [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/**
34 * Set miscellanous static southbridge features.
35 *
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
Paul Menzel9c50e6a2013-05-03 12:23:39 +020052 /*
53 * Select Boot Configuration register (0x03) and
54 * use Processor System Bus (0x01) to deliver interrupts.
55 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080056 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Stefan Reinauer8e073822012-04-04 00:07:22 +020057}
58
59static void pch_enable_serial_irqs(struct device *dev)
60{
61 /* Set packet length and toggle silent mode bit for one frame. */
62 pci_write_config8(dev, SERIRQ_CNTL,
63 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080064#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Stefan Reinauer8e073822012-04-04 00:07:22 +020065 pci_write_config8(dev, SERIRQ_CNTL,
66 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
67#endif
68}
69
70/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
71 * 0x00 - 0000 = Reserved
72 * 0x01 - 0001 = Reserved
73 * 0x02 - 0010 = Reserved
74 * 0x03 - 0011 = IRQ3
75 * 0x04 - 0100 = IRQ4
76 * 0x05 - 0101 = IRQ5
77 * 0x06 - 0110 = IRQ6
78 * 0x07 - 0111 = IRQ7
79 * 0x08 - 1000 = Reserved
80 * 0x09 - 1001 = IRQ9
81 * 0x0A - 1010 = IRQ10
82 * 0x0B - 1011 = IRQ11
83 * 0x0C - 1100 = IRQ12
84 * 0x0D - 1101 = Reserved
85 * 0x0E - 1110 = IRQ14
86 * 0x0F - 1111 = IRQ15
87 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
88 * 0x80 - The PIRQ is not routed.
89 */
90
Elyes HAOUAS4aec3402018-05-25 08:29:27 +020091static void pch_pirq_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020092{
Elyes HAOUAS4aec3402018-05-25 08:29:27 +020093 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020094 /* Interrupt 11 is not used by legacy devices and so can always be used for
95 PCI interrupts. Full legacy IRQ routing is complicated and hard to
96 get right. Fortunately all modern OS use MSI and so it's not that big of
97 an issue anyway. Still we have to provide a reasonable default. Using
98 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
99 move it to any interrupt and others will just leave them at default.
Stefan Reinauer8e073822012-04-04 00:07:22 +0200100 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200101 const u8 pirq_routing = 11;
102
103 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
104 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
105 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
106 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
107
108 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
109 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
110 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
111 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200112
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200113 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200114 u8 int_pin=0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200115
116 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
117 continue;
118
119 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
120
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200121 if (int_pin == 0)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200122 continue;
123
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200124 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200125 }
126}
127
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200128static void pch_gpi_routing(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200129{
130 /* Get the chip configuration */
131 config_t *config = dev->chip_info;
132 u32 reg32 = 0;
133
134 /* An array would be much nicer here, or some
135 * other method of doing this.
136 */
137 reg32 |= (config->gpi0_routing & 0x03) << 0;
138 reg32 |= (config->gpi1_routing & 0x03) << 2;
139 reg32 |= (config->gpi2_routing & 0x03) << 4;
140 reg32 |= (config->gpi3_routing & 0x03) << 6;
141 reg32 |= (config->gpi4_routing & 0x03) << 8;
142 reg32 |= (config->gpi5_routing & 0x03) << 10;
143 reg32 |= (config->gpi6_routing & 0x03) << 12;
144 reg32 |= (config->gpi7_routing & 0x03) << 14;
145 reg32 |= (config->gpi8_routing & 0x03) << 16;
146 reg32 |= (config->gpi9_routing & 0x03) << 18;
147 reg32 |= (config->gpi10_routing & 0x03) << 20;
148 reg32 |= (config->gpi11_routing & 0x03) << 22;
149 reg32 |= (config->gpi12_routing & 0x03) << 24;
150 reg32 |= (config->gpi13_routing & 0x03) << 26;
151 reg32 |= (config->gpi14_routing & 0x03) << 28;
152 reg32 |= (config->gpi15_routing & 0x03) << 30;
153
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200154 pci_write_config32(dev, GPIO_ROUT, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200155}
156
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200157static void pch_power_options(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200158{
159 u8 reg8;
160 u16 reg16, pmbase;
161 u32 reg32;
162 const char *state;
163 /* Get the chip configuration */
164 config_t *config = dev->chip_info;
165
Stefan Reinauer8e073822012-04-04 00:07:22 +0200166 /* Which state do we want to goto after g3 (power restored)?
167 * 0 == S0 Full On
168 * 1 == S5 Soft Off
169 *
170 * If the option is not existent (Laptops), use Kconfig setting.
171 */
Angel Pons88dcb312021-04-26 17:10:28 +0200172 const unsigned int pwr_on = get_uint_option("power_on_after_fail",
Angel Pons62719a32021-04-19 13:15:28 +0200173 CONFIG_MAINBOARD_POWER_FAILURE_STATE);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200174
175 reg16 = pci_read_config16(dev, GEN_PMCON_3);
176 reg16 &= 0xfffe;
177 switch (pwr_on) {
178 case MAINBOARD_POWER_OFF:
179 reg16 |= 1;
180 state = "off";
181 break;
182 case MAINBOARD_POWER_ON:
183 reg16 &= ~1;
184 state = "on";
185 break;
186 case MAINBOARD_POWER_KEEP:
187 reg16 &= ~1;
188 state = "state keep";
189 break;
190 default:
191 state = "undefined";
192 }
193
194 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
195 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
196
197 reg16 &= ~(1 << 10);
198 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
199
200 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
201
202 pci_write_config16(dev, GEN_PMCON_3, reg16);
203 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
204
205 /* Set up NMI on errors. */
206 reg8 = inb(0x61);
207 reg8 &= 0x0f; /* Higher Nibble must be 0 */
208 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
209 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
210 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
211 outb(reg8, 0x61);
212
213 reg8 = inb(0x70);
Angel Pons88dcb312021-04-26 17:10:28 +0200214 const unsigned int nmi_option = get_uint_option("nmi", NMI_OFF);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200215 if (nmi_option) {
216 printk(BIOS_INFO, "NMI sources enabled.\n");
217 reg8 &= ~(1 << 7); /* Set NMI. */
218 } else {
219 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200220 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200221 }
222 outb(reg8, 0x70);
223
224 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
225 reg16 = pci_read_config16(dev, GEN_PMCON_1);
226 reg16 &= ~(3 << 0); // SMI# rate 1 minute
227 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
Kyösti Mälkki94464472020-06-13 13:45:42 +0300228 if (CONFIG(DEBUG_PERIODIC_SMI))
229 reg16 |= (3 << 0); // Periodic SMI every 8s
Stefan Reinauer8e073822012-04-04 00:07:22 +0200230 pci_write_config16(dev, GEN_PMCON_1, reg16);
231
232 // Set the board's GPI routing.
233 pch_gpi_routing(dev);
234
235 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
236
237 outl(config->gpe0_en, pmbase + GPE0_EN);
238 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
239
240 /* Set up power management block and determine sleep mode */
241 reg32 = inl(pmbase + 0x04); // PM1_CNT
242 reg32 &= ~(7 << 10); // SLP_TYP
243 reg32 |= (1 << 0); // SCI_EN
244 outl(reg32, pmbase + 0x04);
245
246 /* Clear magic status bits to prevent unexpected wake */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200247 reg32 = RCBA32(PRSTS);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200248 reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200249 RCBA32(PRSTS) = reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200250
251 reg32 = RCBA32(0x3f02);
252 reg32 &= ~0xf;
253 RCBA32(0x3f02) = reg32;
254}
255
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700256/* CougarPoint PCH Power Management init */
257static void cpt_pm_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200258{
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700259 printk(BIOS_DEBUG, "CougarPoint PM init\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200260 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200261 RCBA32_AND_OR(CIR30, ~0U, (1 << 6)|(1 << 0));
262 RCBA32_AND_OR(CIR5, ~0U, (1 << 0));
263 RCBA16_AND_OR(CIR3, ~0U, (1 << 13)|(1 << 14));
264 RCBA16_AND_OR(CIR2, ~0U, (1 << 14));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200265 RCBA32(DMC) = 0xc0388400;
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200266 RCBA32_AND_OR(CIR6, ~0U, (1 << 5)|(1 << 18));
267 RCBA32_AND_OR(CIR9, ~0U, (1 << 15)|(1 << 1));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200268 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
269 RCBA32(PM_CFG) = 0x050f0000;
270 RCBA32(CIR8) = 0x04000000;
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200271 RCBA32_AND_OR(CIR10, ~0U, 0xfffff);
272 RCBA32_AND_OR(CIR11, ~0U, (1 << 1));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200273 RCBA32(CIR12) = 0x0001c000;
274 RCBA32(CIR14) = 0x00061100;
275 RCBA32(CIR15) = 0x7f8fdfff;
276 RCBA32(CIR13) = 0x000003fc;
277 RCBA32(CIR16) = 0x00001000;
278 RCBA32(CIR18) = 0x0001c000;
279 RCBA32(CIR17) = 0x00000800;
280 RCBA32(CIR23) = 0x00001000;
281 RCBA32(CIR19) = 0x00093900;
282 RCBA32(CIR20) = 0x24653002;
283 RCBA32(CIR21) = 0x062108fe;
284 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
285 RCBA32(CIR24) = 0x01010000;
286 RCBA32(CIR25) = 0x01010404;
287 RCBA32(CIR27) = 0x01041041;
288 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
289 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
290 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
291 RCBA32(CIR26) = 0x00000001;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200292 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
293 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200294 RCBA32(PMSYNC_CFG) = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200295 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
296}
297
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700298/* PantherPoint PCH Power Management init */
299static void ppt_pm_init(struct device *dev)
300{
301 printk(BIOS_DEBUG, "PantherPoint PM init\n");
302 pci_write_config8(dev, 0xa9, 0x47);
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200303 RCBA32_AND_OR(CIR30, ~0UL, (1 << 0));
304 RCBA32_AND_OR(CIR5, ~0UL, (1 << 0));
305 RCBA16_AND_OR(CIR3, ~0UL, (1 << 13)|(1 << 14));
306 RCBA16_AND_OR(CIR2, ~0UL, (1 << 14));
307 RCBA32(DMC) = 0xc03b8400;
308 RCBA32_AND_OR(CIR6, ~0UL, (1 << 5)|(1 << 18));
309 RCBA32_AND_OR(CIR9, ~0UL, (1 << 15)|(1 << 1));
310 RCBA32_AND_OR(CIR7, ~0x1f, 0xf);
311 RCBA32(PM_CFG) = 0x054f0000;
312 RCBA32(CIR8) = 0x04000000;
313 RCBA32_AND_OR(CIR10, ~0UL, 0xfffff);
314 RCBA32_AND_OR(CIR11, ~0UL, (1 << 1)|(1 << 0));
315 RCBA32(CIR12) = 0x0001c000;
316 RCBA32(CIR14) = 0x00061100;
317 RCBA32(CIR15) = 0x7f8fdfff;
318 RCBA32(CIR13) = 0x000003fd;
319 RCBA32(CIR16) = 0x00001000;
320 RCBA32(CIR18) = 0x0001c000;
321 RCBA32(CIR17) = 0x00000800;
322 RCBA32(CIR23) = 0x00001000;
323 RCBA32(CIR19) = 0x00093900;
324 RCBA32(CIR20) = 0x24653002;
325 RCBA32(CIR21) = 0x067388fe;
326 RCBA32_AND_OR(CIR22, 0xf000f000, 0x00670060);
327 RCBA32(CIR24) = 0x01010000;
328 RCBA32(CIR25) = 0x01010404;
329 RCBA32(CIR27) = 0x01040000;
330 RCBA32_AND_OR(CIR28, ~0x0000ffff, 0x00001001);
331 RCBA32_AND_OR(CIR28, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
332 RCBA32_AND_OR(CIR29, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
333 RCBA32(CIR26) = 0x00000001;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700334 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
335 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
336 RCBA32_AND_OR(0x33a4, ~0UL, (1 << 0));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200337 RCBA32(PMSYNC_CFG) = 0;
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700338 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
339}
340
Nico Huberb2dae792015-10-26 12:34:02 +0100341static void enable_hpet(struct device *const dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200342{
343 u32 reg32;
Nico Huberb2dae792015-10-26 12:34:02 +0100344 size_t i;
345
346 /* Assign unique bus/dev/fn for each HPET */
347 for (i = 0; i < 8; ++i)
348 pci_write_config16(dev, LPC_HnBDF(i),
349 PCH_HPET_PCI_BUS << 8 | PCH_HPET_PCI_SLOT << 3 | i);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200350
351 /* Move HPET to default address 0xfed00000 and enable it */
352 reg32 = RCBA32(HPTC);
353 reg32 |= (1 << 7); // HPET Address Enable
354 reg32 &= ~(3 << 0);
355 RCBA32(HPTC) = reg32;
356}
357
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200358static void enable_clock_gating(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200359{
360 u32 reg32;
361 u16 reg16;
362
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200363 RCBA32_AND_OR(DMIC, ~0UL, 0xf);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200364
365 reg16 = pci_read_config16(dev, GEN_PMCON_1);
Michał Żygowski9ff2af22020-04-13 20:37:36 +0200366 reg16 &= ~(3 << 2); /* Clear CLKRUN bits for mobile and desktop */
367 if (get_platform_type() == PLATFORM_MOBILE)
368 reg16 |= (1 << 2); /* CLKRUN_EN for mobile */
369 else if (get_platform_type() == PLATFORM_DESKTOP_SERVER)
370 reg16 |= (1 << 3); /* PSEUDO_CLKRUN_EN for desktop */
371 reg16 |= (1 << 11);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200372 pci_write_config16(dev, GEN_PMCON_1, reg16);
373
Patrick Rudolphb50b6a52020-08-20 16:50:01 +0200374 pch_iobp_update(0xEB007F07, ~0U, (1 << 31));
375 pch_iobp_update(0xEB004000, ~0U, (1 << 7));
376 pch_iobp_update(0xEC007F07, ~0U, (1 << 31));
377 pch_iobp_update(0xEC004000, ~0U, (1 << 7));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200378
379 reg32 = RCBA32(CG);
380 reg32 |= (1 << 31);
381 reg32 |= (1 << 29) | (1 << 28);
382 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
383 reg32 |= (1 << 16);
384 reg32 |= (1 << 17);
385 reg32 |= (1 << 18);
386 reg32 |= (1 << 22);
387 reg32 |= (1 << 23);
388 reg32 &= ~(1 << 20);
389 reg32 |= (1 << 19);
390 reg32 |= (1 << 0);
391 reg32 |= (0xf << 1);
392 RCBA32(CG) = reg32;
393
394 RCBA32_OR(0x38c0, 0x7);
395 RCBA32_OR(0x36d4, 0x6680c004);
396 RCBA32_OR(0x3564, 0x3);
397}
398
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200399static void pch_set_acpi_mode(void)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200400{
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300401 if (!acpi_is_wakeup_s3()) {
Kyösti Mälkkib6585482020-06-01 15:11:14 +0300402 apm_control(APM_CNT_ACPI_DISABLE);
Duncan Laurie95be1d62012-04-09 12:31:43 -0700403 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200404}
Stefan Reinauer8e073822012-04-04 00:07:22 +0200405
Stefan Reinauer8e073822012-04-04 00:07:22 +0200406static void pch_fixups(struct device *dev)
407{
Stefan Reinauer8e073822012-04-04 00:07:22 +0200408 /* Indicate DRAM init done for MRC S3 to know it can resume */
Angel Ponsc803f652020-06-07 22:09:01 +0200409 pci_or_config8(dev, GEN_PMCON_2, 1 << 7);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200410
411 /*
412 * Enable DMI ASPM in the PCH
413 */
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200414 RCBA32_AND_OR(DMC, ~(1 << 10), 0);
415 RCBA32_OR(LCAP, (1 << 11)|(1 << 10));
416 RCBA32_OR(LCTL, 0x3);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200417}
418
Nico Huber7b2f9f62015-10-01 19:00:51 +0200419static void pch_spi_init(const struct device *const dev)
420{
421 const config_t *const config = dev->chip_info;
422
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100423 printk(BIOS_DEBUG, "%s\n", __func__);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200424
425 if (config->spi_uvscc)
426 RCBA32(0x3800 + 0xc8) = config->spi_uvscc;
427 if (config->spi_lvscc)
428 RCBA32(0x3800 + 0xc4) = config->spi_lvscc;
429
430 if (config->spi_uvscc || config->spi_lvscc)
431 RCBA32_OR(0x3800 + 0xc4, 1 << 23); /* lock both UVSCC + LVSCC */
432}
433
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200434static const struct {
435 u16 dev_id;
436 const char *dev_name;
437} pch_table[] = {
438 /* 6-series PCI ids from
439 * Intel® 6 Series Chipset and
440 * Intel® C200 Series Chipset
441 * Specification Update - NDA
442 * October 2013
443 * CDI / IBP#: 440377
444 */
445 {0x1C41, "SFF Sample"},
446 {0x1C42, "Desktop Sample"},
447 {0x1C43, "Mobile Sample"},
448 {0x1C44, "Z68"},
449 {0x1C46, "P67"},
450 {0x1C47, "UM67"},
451 {0x1C49, "HM65"},
452 {0x1C4A, "H67"},
453 {0x1C4B, "HM67"},
454 {0x1C4C, "Q65"},
455 {0x1C4D, "QS67"},
456 {0x1C4E, "Q67"},
457 {0x1C4F, "QM67"},
458 {0x1C50, "B65"},
459 {0x1C52, "C202"},
460 {0x1C54, "C204"},
461 {0x1C56, "C206"},
462 {0x1C5C, "H61"},
463 /* 7-series PCI ids from Intel document 472178 */
464 {0x1E41, "Desktop Sample"},
465 {0x1E42, "Mobile Sample"},
466 {0x1E43, "SFF Sample"},
467 {0x1E44, "Z77"},
468 {0x1E45, "H71"},
469 {0x1E46, "Z75"},
470 {0x1E47, "Q77"},
471 {0x1E48, "Q75"},
472 {0x1E49, "B75"},
473 {0x1E4A, "H77"},
474 {0x1E53, "C216"},
475 {0x1E55, "QM77"},
476 {0x1E56, "QS77"},
477 {0x1E58, "UM77"},
478 {0x1E57, "HM77"},
479 {0x1E59, "HM76"},
480 {0x1E5D, "HM75"},
481 {0x1E5E, "HM70"},
482 {0x1E5F, "NM70"},
483};
484
485static void report_pch_info(struct device *dev)
486{
487 const u16 dev_id = pci_read_config16(dev, PCI_DEVICE_ID);
488 int i;
489
490 const char *pch_type = "Unknown";
491 for (i = 0; i < ARRAY_SIZE(pch_table); i++) {
492 if (pch_table[i].dev_id == dev_id) {
493 pch_type = pch_table[i].dev_name;
494 break;
495 }
496 }
497 printk(BIOS_INFO, "PCH: detected %s, device id: 0x%x, rev id 0x%x\n",
498 pch_type, dev_id, pci_read_config8(dev, PCI_CLASS_REVISION));
499}
500
Stefan Reinauer8e073822012-04-04 00:07:22 +0200501static void lpc_init(struct device *dev)
502{
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100503 printk(BIOS_DEBUG, "pch: %s\n", __func__);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200504
Patrick Rudolphef8c5592018-07-27 17:48:27 +0200505 /* Print detected platform */
506 report_pch_info(dev);
507
Stefan Reinauer8e073822012-04-04 00:07:22 +0200508 /* IO APIC initialization. */
Paul Menzel9c50e6a2013-05-03 12:23:39 +0200509 pch_enable_ioapic(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200510
511 pch_enable_serial_irqs(dev);
512
513 /* Setup the PIRQ. */
514 pch_pirq_init(dev);
515
516 /* Setup power options. */
517 pch_power_options(dev);
518
519 /* Initialize power management */
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700520 switch (pch_silicon_type()) {
521 case PCH_TYPE_CPT: /* CougarPoint */
522 cpt_pm_init(dev);
523 break;
524 case PCH_TYPE_PPT: /* PantherPoint */
525 ppt_pm_init(dev);
526 break;
527 default:
528 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
529 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200530
Stefan Reinauer8e073822012-04-04 00:07:22 +0200531 /* Initialize the real time clock. */
Patrick Rudolph6b931122018-11-01 17:48:37 +0100532 sb_rtc_init();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200533
534 /* Initialize ISA DMA. */
535 isa_dma_init();
536
537 /* Initialize the High Precision Event Timers, if present. */
Nico Huberb2dae792015-10-26 12:34:02 +0100538 enable_hpet(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200539
540 /* Initialize Clock Gating */
541 enable_clock_gating(dev);
542
543 setup_i8259();
544
545 /* The OS should do this? */
546 /* Interrupt 9 should be level triggered (SCI) */
547 i8259_configure_irq_trigger(9, 1);
548
Vladimir Serbinenkoa3e41c02015-05-28 16:04:17 +0200549 pch_set_acpi_mode();
Stefan Reinauer8e073822012-04-04 00:07:22 +0200550
551 pch_fixups(dev);
Nico Huber7b2f9f62015-10-01 19:00:51 +0200552
553 pch_spi_init(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200554}
555
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200556static void pch_lpc_read_resources(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200557{
558 struct resource *res;
Marc Jonesa0bec172012-07-13 14:14:34 -0600559 config_t *config = dev->chip_info;
560 u8 io_index = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200561
562 /* Get the normal PCI resources of this device. */
563 pci_dev_read_resources(dev);
564
565 /* Add an extra subtractive resource for both memory and I/O. */
Marc Jonesa0bec172012-07-13 14:14:34 -0600566 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200567 res->base = 0;
568 res->size = 0x1000;
569 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
570 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
571
Marc Jonesa0bec172012-07-13 14:14:34 -0600572 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Vladimir Serbinenko0650cd02014-02-05 15:03:50 +0100573 res->base = 0xff000000;
574 /* Some systems (e.g. X230) have 12 MiB flash.
575 SPI controller supports up to 2 x 16 MiB of flash but
576 address map limits this to 16MiB. */
577 res->size = 0x01000000; /* 16 MB for flash */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200578 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
579 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
580
581 res = new_resource(dev, 3); /* IOAPIC */
582 res->base = IO_APIC_ADDR;
583 res->size = 0x00001000;
584 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Marc Jonesa0bec172012-07-13 14:14:34 -0600585
586 /* Set PCH IO decode ranges if required.*/
587 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
588 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
589 res->base = config->gen1_dec & 0xFFFC;
590 res->size = (config->gen1_dec >> 16) & 0xFC;
591 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
592 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
593 }
594
595 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
596 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
597 res->base = config->gen2_dec & 0xFFFC;
598 res->size = (config->gen2_dec >> 16) & 0xFC;
599 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
600 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
601 }
602
603 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
604 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
605 res->base = config->gen3_dec & 0xFFFC;
606 res->size = (config->gen3_dec >> 16) & 0xFC;
607 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
608 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
609 }
610
611 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
612 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
613 res->base = config->gen4_dec & 0xFFFC;
614 res->size = (config->gen4_dec >> 16) & 0xFC;
615 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
616 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
617 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200618}
619
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200620static void pch_lpc_enable(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200621{
622 /* Enable PCH Display Port */
623 RCBA16(DISPBDF) = 0x0010;
624 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
625
626 pch_enable(dev);
627}
628
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600629static const char *lpc_acpi_name(const struct device *dev)
Patrick Rudolph604f6982017-06-07 09:46:52 +0200630{
631 return "LPCB";
632}
633
Furquan Shaikh7536a392020-04-24 21:59:21 -0700634static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100635{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300636 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100637 config_t *chip = dev->chip_info;
638
639 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Tobias Diedrich7f5efd92017-12-14 00:29:01 +0100640 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100641}
642
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200643static void lpc_final(struct device *dev)
644{
Arthur Heymansebf201b2019-05-28 13:51:36 +0200645 spi_finalize_ops();
Nico Huber8e50b6d2018-02-04 15:52:18 +0100646
Bill XIEd533b162017-08-22 16:26:22 +0800647 /* Call SMM finalize() handlers before resume */
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300648 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
649 acpi_is_wakeup_s3()) {
650 apm_control(APM_CNT_FINALIZE);
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200651 }
652}
653
Arthur Heymansebf201b2019-05-28 13:51:36 +0200654void intel_southbridge_override_spi(
655 struct intel_swseq_spi_config *spi_config)
656{
657 struct device *dev = pcidev_on_root(0x1f, 0);
658
659 if (!dev)
660 return;
661 /* Devicetree may override defaults. */
662 const config_t *const config = dev->chip_info;
663
664 if (!config)
665 return;
666
667 if (config->spi.ops[0].op != 0)
668 memcpy(spi_config, &config->spi, sizeof(*spi_config));
669}
670
Stefan Reinauer8e073822012-04-04 00:07:22 +0200671static struct device_operations device_ops = {
672 .read_resources = pch_lpc_read_resources,
673 .set_resources = pci_dev_set_resources,
Arthur Heymans3cde4942019-08-18 10:02:10 +0200674 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200675 .write_acpi_tables = acpi_write_hpet,
Nico Huber68680dd2020-03-31 17:34:52 +0200676 .acpi_fill_ssdt = southbridge_fill_ssdt,
Patrick Rudolph604f6982017-06-07 09:46:52 +0200677 .acpi_name = lpc_acpi_name,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200678 .init = lpc_init,
Vladimir Serbinenkob06a2492015-05-21 10:32:59 +0200679 .final = lpc_final,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200680 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100681 .scan_bus = scan_static_bus,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200682 .ops_pci = &pci_dev_ops_pci,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200683};
684
Kimarie Hoote6f459c2012-07-14 08:26:08 -0600685/* IDs for LPC device of Intel 6 Series Chipset, Intel 7 Series Chipset, and
686 * Intel C200 Series Chipset
Stefan Reinauer8e073822012-04-04 00:07:22 +0200687 */
688
Vladimir Serbinenko42d55e02016-01-02 01:47:26 +0100689static const unsigned short pci_device_ids[] = {
690 0x1c40, 0x1c41, 0x1c42, 0x1c43, 0x1c44, 0x1c45, 0x1c46, 0x1c47, 0x1c48,
691 0x1c49, 0x1c4a, 0x1c4b, 0x1c4c, 0x1c4d, 0x1c4e, 0x1c4f, 0x1c50, 0x1c51,
692 0x1c52, 0x1c53, 0x1c54, 0x1c55, 0x1c56, 0x1c57, 0x1c58, 0x1c59, 0x1c5a,
693 0x1c5b, 0x1c5c, 0x1c5d, 0x1c5e, 0x1c5f,
694
695 0x1e41, 0x1e42, 0x1e43, 0x1e44, 0x1e45, 0x1e46, 0x1e47, 0x1e48, 0x1e49,
696 0x1e4a, 0x1e4b, 0x1e4c, 0x1e4d, 0x1e4e, 0x1e4f, 0x1e50, 0x1e51, 0x1e52,
697 0x1e53, 0x1e54, 0x1e55, 0x1e56, 0x1e57, 0x1e58, 0x1e59, 0x1e5a, 0x1e5b,
698 0x1e5c, 0x1e5d, 0x1e5e, 0x1e5f,
699
700 0 };
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700701
702static const struct pci_driver pch_lpc __pci_driver = {
703 .ops = &device_ops,
704 .vendor = PCI_VENDOR_ID_INTEL,
705 .devices = pci_device_ids,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200706};