blob: 395919e676b35a493b91decf6644aa2fb7409209 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +01003
4#include <console/console.h>
5#include <device/device.h>
6#include <device/pci.h>
7#include <device/pci_ids.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +02008#include <option.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +01009#include <pc80/mc146818rtc.h>
10#include <pc80/isa-dma.h>
11#include <pc80/i8259.h>
12#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020013#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020014#include <device/pci_ops.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010015#include <arch/ioapic.h>
16#include <arch/acpi.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010017#include <elog.h>
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020018#include <arch/acpigen.h>
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020019#include <cbmem.h>
Vladimir Serbinenko7309c642014-10-05 11:07:33 +020020#include <string.h>
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +020021#include <cpu/x86/smm.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030022#include "chip.h"
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010023#include "pch.h"
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020024#include "nvs.h"
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010025#include <southbridge/intel/common/pciehp.h>
Kyösti Mälkki90993952018-05-01 19:36:25 +030026#include <southbridge/intel/common/acpi_pirq_gen.h>
Arthur Heymansaadd1d02019-05-28 13:39:20 +020027#include <southbridge/intel/common/spi.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010028
29#define NMI_OFF 0
30
Vladimir Serbinenko46957052013-11-26 01:16:20 +010031typedef struct southbridge_intel_ibexpeak_config config_t;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010032
33/**
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)
39{
40 u32 reg32;
41
42 /* Enable ACPI I/O range decode */
43 pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
44
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080045 set_ioapic_id(VIO_APIC_VADDR, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010046 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080047 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
48 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010049
50 /*
51 * Select Boot Configuration register (0x03) and
52 * use Processor System Bus (0x01) to deliver interrupts.
53 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080054 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010055}
56
57static void pch_enable_serial_irqs(struct device *dev)
58{
59 /* Set packet length and toggle silent mode bit for one frame. */
60 pci_write_config8(dev, SERIRQ_CNTL,
61 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080062#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010063 pci_write_config8(dev, SERIRQ_CNTL,
64 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
65#endif
66}
67
68/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
69 * 0x00 - 0000 = Reserved
70 * 0x01 - 0001 = Reserved
71 * 0x02 - 0010 = Reserved
72 * 0x03 - 0011 = IRQ3
73 * 0x04 - 0100 = IRQ4
74 * 0x05 - 0101 = IRQ5
75 * 0x06 - 0110 = IRQ6
76 * 0x07 - 0111 = IRQ7
77 * 0x08 - 1000 = Reserved
78 * 0x09 - 1001 = IRQ9
79 * 0x0A - 1010 = IRQ10
80 * 0x0B - 1011 = IRQ11
81 * 0x0C - 1100 = IRQ12
82 * 0x0D - 1101 = Reserved
83 * 0x0E - 1110 = IRQ14
84 * 0x0F - 1111 = IRQ15
85 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
86 * 0x80 - The PIRQ is not routed.
87 */
88
Elyes HAOUASbe841402018-05-13 13:40:39 +020089static void pch_pirq_init(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010090{
Elyes HAOUASbe841402018-05-13 13:40:39 +020091 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020092 /* Interrupt 11 is not used by legacy devices and so can always be used for
93 PCI interrupts. Full legacy IRQ routing is complicated and hard to
94 get right. Fortunately all modern OS use MSI and so it's not that big of
95 an issue anyway. Still we have to provide a reasonable default. Using
96 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
97 move it to any interrupt and others will just leave them at default.
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010098 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020099 const u8 pirq_routing = 11;
100
101 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
102 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
103 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
104 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
105
106 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
107 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
108 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
109 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100110
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200111 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200112 u8 int_pin=0;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100113
114 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
115 continue;
116
117 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
118
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200119 if (int_pin == 0)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100120 continue;
121
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200122 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100123 }
124}
125
Elyes HAOUASbe841402018-05-13 13:40:39 +0200126static void pch_gpi_routing(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100127{
128 /* Get the chip configuration */
129 config_t *config = dev->chip_info;
130 u32 reg32 = 0;
131
132 /* An array would be much nicer here, or some
133 * other method of doing this.
134 */
135 reg32 |= (config->gpi0_routing & 0x03) << 0;
136 reg32 |= (config->gpi1_routing & 0x03) << 2;
137 reg32 |= (config->gpi2_routing & 0x03) << 4;
138 reg32 |= (config->gpi3_routing & 0x03) << 6;
139 reg32 |= (config->gpi4_routing & 0x03) << 8;
140 reg32 |= (config->gpi5_routing & 0x03) << 10;
141 reg32 |= (config->gpi6_routing & 0x03) << 12;
142 reg32 |= (config->gpi7_routing & 0x03) << 14;
143 reg32 |= (config->gpi8_routing & 0x03) << 16;
144 reg32 |= (config->gpi9_routing & 0x03) << 18;
145 reg32 |= (config->gpi10_routing & 0x03) << 20;
146 reg32 |= (config->gpi11_routing & 0x03) << 22;
147 reg32 |= (config->gpi12_routing & 0x03) << 24;
148 reg32 |= (config->gpi13_routing & 0x03) << 26;
149 reg32 |= (config->gpi14_routing & 0x03) << 28;
150 reg32 |= (config->gpi15_routing & 0x03) << 30;
151
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200152 pci_write_config32(dev, GPIO_ROUT, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100153}
154
Elyes HAOUASbe841402018-05-13 13:40:39 +0200155static void pch_power_options(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100156{
157 u8 reg8;
158 u16 reg16, pmbase;
159 u32 reg32;
160 const char *state;
161 /* Get the chip configuration */
162 config_t *config = dev->chip_info;
163
Nico Huber9faae2b2018-11-14 00:00:35 +0100164 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100165 int nmi_option;
166
167 /* Which state do we want to goto after g3 (power restored)?
168 * 0 == S0 Full On
169 * 1 == S5 Soft Off
170 *
171 * If the option is not existent (Laptops), use Kconfig setting.
172 */
173 get_option(&pwr_on, "power_on_after_fail");
174
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);
214 nmi_option = NMI_OFF;
215 get_option(&nmi_option, "nmi");
216 if (nmi_option) {
217 printk(BIOS_INFO, "NMI sources enabled.\n");
218 reg8 &= ~(1 << 7); /* Set NMI. */
219 } else {
220 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200221 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100222 }
223 outb(reg8, 0x70);
224
225 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
226 reg16 = pci_read_config16(dev, GEN_PMCON_1);
227 reg16 &= ~(3 << 0); // SMI# rate 1 minute
228 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
229#if DEBUG_PERIODIC_SMIS
230 /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
231 * periodic SMIs.
232 */
233 reg16 |= (3 << 0); // Periodic SMI every 8s
234#endif
235 pci_write_config16(dev, GEN_PMCON_1, reg16);
236
237 // Set the board's GPI routing.
238 pch_gpi_routing(dev);
239
240 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
241
242 outl(config->gpe0_en, pmbase + GPE0_EN);
243 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
244
245 /* Set up power management block and determine sleep mode */
246 reg32 = inl(pmbase + 0x04); // PM1_CNT
247 reg32 &= ~(7 << 10); // SLP_TYP
248 reg32 |= (1 << 0); // SCI_EN
249 outl(reg32, pmbase + 0x04);
250
251 /* Clear magic status bits to prevent unexpected wake */
Angel Pons42b4e4e2019-09-18 10:58:53 +0200252 reg32 = RCBA32(PRSTS);
253 reg32 |= (1 << 5) | (1 << 4) | (1 << 0);
254 RCBA32(PRSTS) = reg32;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100255
Angel Pons42b4e4e2019-09-18 10:58:53 +0200256 /* FIXME: Does this even exist? */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100257 reg32 = RCBA32(0x3f02);
258 reg32 &= ~0xf;
259 RCBA32(0x3f02) = reg32;
260}
261
262static void pch_rtc_init(struct device *dev)
263{
264 u8 reg8;
265 int rtc_failed;
266
267 reg8 = pci_read_config8(dev, GEN_PMCON_3);
268 rtc_failed = reg8 & RTC_BATTERY_DEAD;
269 if (rtc_failed) {
270 reg8 &= ~RTC_BATTERY_DEAD;
271 pci_write_config8(dev, GEN_PMCON_3, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100272 elog_add_event(ELOG_TYPE_RTC_RESET);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100273 }
274 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
275
Gabe Blackb3f08c62014-04-30 17:12:25 -0700276 cmos_init(rtc_failed);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100277}
278
279static void mobile5_pm_init(struct device *dev)
280{
281 int i;
282
283 printk(BIOS_DEBUG, "Mobile 5 PM init\n");
284 pci_write_config8(dev, 0xa9, 0x47);
285
286 RCBA32 (0x1d44) = 0x00000000;
287 (void) RCBA32 (0x1d44);
288 RCBA32 (0x1d48) = 0x00030000;
289 (void) RCBA32 (0x1d48);
290 RCBA32 (0x1e80) = 0x000c0801;
291 (void) RCBA32 (0x1e80);
292 RCBA32 (0x1e84) = 0x000200f0;
293 (void) RCBA32 (0x1e84);
294
295 const u32 rcba2010[] =
296 {
297 /* 2010: */ 0x00188200, 0x14000016, 0xbc4abcb5, 0x00000000,
298 /* 2020: */ 0xf0c9605b, 0x13683040, 0x04c8f16e, 0x09e90170
299 };
Elyes HAOUAS035df002016-10-03 21:54:16 +0200300 for (i = 0; i < sizeof(rcba2010) / sizeof(rcba2010[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100301 {
302 RCBA32 (0x2010 + 4 * i) = rcba2010[i];
303 RCBA32 (0x2010 + 4 * i);
304 }
305
306 RCBA32 (0x2100) = 0x00000000;
307 (void) RCBA32 (0x2100);
308 RCBA32 (0x2104) = 0x00000757;
309 (void) RCBA32 (0x2104);
310 RCBA32 (0x2108) = 0x00170001;
311 (void) RCBA32 (0x2108);
312
313 RCBA32 (0x211c) = 0x00000000;
314 (void) RCBA32 (0x211c);
315 RCBA32 (0x2120) = 0x00010000;
316 (void) RCBA32 (0x2120);
317
318 RCBA32 (0x21fc) = 0x00000000;
319 (void) RCBA32 (0x21fc);
320 RCBA32 (0x2200) = 0x20000044;
321 (void) RCBA32 (0x2200);
322 RCBA32 (0x2204) = 0x00000001;
323 (void) RCBA32 (0x2204);
324 RCBA32 (0x2208) = 0x00003457;
325 (void) RCBA32 (0x2208);
326
327 const u32 rcba2210[] =
328 {
329 /* 2210 */ 0x00000000, 0x00000001, 0xa0fff210, 0x0000df00,
330 /* 2220 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
331 /* 2230 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
332 /* 2240 */ 0x00002301, 0x36000000, 0x00010107, 0x00160000,
333 /* 2250 */ 0x00001b01, 0x36000000, 0x00010107, 0x00160000,
334 /* 2260 */ 0x00000601, 0x16000000, 0x00010107, 0x00160000,
335 /* 2270 */ 0x00001c01, 0x16000000, 0x00010107, 0x00160000
336 };
337
Elyes HAOUAS035df002016-10-03 21:54:16 +0200338 for (i = 0; i < sizeof(rcba2210) / sizeof(rcba2210[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100339 {
340 RCBA32 (0x2210 + 4 * i) = rcba2210[i];
341 RCBA32 (0x2210 + 4 * i);
342 }
343
344 const u32 rcba2300[] =
345 {
346 /* 2300: */ 0x00000000, 0x40000000, 0x4646827b, 0x6e803131,
347 /* 2310: */ 0x32c77887, 0x00077733, 0x00007447, 0x00000040,
348 /* 2320: */ 0xcccc0cfc, 0x0fbb0fff
349 };
350
Elyes HAOUAS035df002016-10-03 21:54:16 +0200351 for (i = 0; i < sizeof(rcba2300) / sizeof(rcba2300[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100352 {
353 RCBA32 (0x2300 + 4 * i) = rcba2300[i];
354 RCBA32 (0x2300 + 4 * i);
355 }
356
357 RCBA32 (0x37fc) = 0x00000000;
358 (void) RCBA32 (0x37fc);
359 RCBA32 (0x3dfc) = 0x00000000;
360 (void) RCBA32 (0x3dfc);
361 RCBA32 (0x3e7c) = 0xffffffff;
362 (void) RCBA32 (0x3e7c);
363 RCBA32 (0x3efc) = 0x00000000;
364 (void) RCBA32 (0x3efc);
365 RCBA32 (0x3f00) = 0x0000010b;
366 (void) RCBA32 (0x3f00);
367}
368
369static void enable_hpet(void)
370{
371 u32 reg32;
372
373 /* Move HPET to default address 0xfed00000 and enable it */
374 reg32 = RCBA32(HPTC);
375 reg32 |= (1 << 7); // HPET Address Enable
376 reg32 &= ~(3 << 0);
377 RCBA32(HPTC) = reg32;
Arthur Heymans37e1d932019-10-02 14:33:34 +0200378 RCBA32(HPTC); /* Read back for it to work */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100379
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800380 write32((u32 *)0xfed00010, read32((u32 *)0xfed00010) | 1);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100381}
382
Elyes HAOUASbe841402018-05-13 13:40:39 +0200383static void enable_clock_gating(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100384{
385 u32 reg32;
386 u16 reg16;
387
388 RCBA32_AND_OR(0x2234, ~0UL, 0xf);
389
390 reg16 = pci_read_config16(dev, GEN_PMCON_1);
391 reg16 |= (1 << 2) | (1 << 11);
392 pci_write_config16(dev, GEN_PMCON_1, reg16);
393
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100394 reg32 = RCBA32(CG);
395 reg32 |= (1 << 31);
396 reg32 |= (1 << 29) | (1 << 28);
397 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
398 reg32 |= (1 << 16);
399 reg32 |= (1 << 17);
400 reg32 |= (1 << 18);
401 reg32 |= (1 << 22);
402 reg32 |= (1 << 23);
403 reg32 &= ~(1 << 20);
404 reg32 |= (1 << 19);
405 reg32 |= (1 << 0);
406 reg32 |= (0xf << 1);
407 RCBA32(CG) = reg32;
408
409 RCBA32_OR(0x38c0, 0x7);
410 RCBA32_OR(0x36d4, 0x6680c004);
411 RCBA32_OR(0x3564, 0x3);
412}
413
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200414static void pch_set_acpi_mode(void)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100415{
Julius Werner5d1f9a02019-03-07 17:07:26 -0800416 if (!acpi_is_wakeup_s3() && CONFIG(HAVE_SMI_HANDLER)) {
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100417 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200418 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100419 printk(BIOS_DEBUG, "done.\n");
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100420 }
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100421}
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100422
423static void pch_disable_smm_only_flashing(struct device *dev)
424{
425 u8 reg8;
426
427 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100428 reg8 = pci_read_config8(dev, BIOS_CNTL);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100429 reg8 &= ~(1 << 5);
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100430 pci_write_config8(dev, BIOS_CNTL, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100431}
432
433static void pch_fixups(struct device *dev)
434{
435 /*
436 * Enable DMI ASPM in the PCH
437 */
438 RCBA32_AND_OR(0x2304, ~(1 << 10), 0);
439 RCBA32_OR(0x21a4, (1 << 11)|(1 << 10));
440 RCBA32_OR(0x21a8, 0x3);
441}
442
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100443static void lpc_init(struct device *dev)
444{
445 printk(BIOS_DEBUG, "pch: lpc_init\n");
446
447 /* Set the value for PCI command register. */
448 pci_write_config16(dev, PCI_COMMAND, 0x000f);
449
450 /* IO APIC initialization. */
451 pch_enable_ioapic(dev);
452
453 pch_enable_serial_irqs(dev);
454
455 /* Setup the PIRQ. */
456 pch_pirq_init(dev);
457
458 /* Setup power options. */
459 pch_power_options(dev);
460
461 /* Initialize power management */
Arthur Heymansd0310fa2019-10-02 00:21:01 +0200462 mobile5_pm_init(dev);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100463
464 /* Set the state of the GPIO lines. */
465 //gpio_init(dev);
466
467 /* Initialize the real time clock. */
468 pch_rtc_init(dev);
469
470 /* Initialize ISA DMA. */
471 isa_dma_init();
472
473 /* Initialize the High Precision Event Timers, if present. */
474 enable_hpet();
475
476 /* Initialize Clock Gating */
477 enable_clock_gating(dev);
478
479 setup_i8259();
480
481 /* The OS should do this? */
482 /* Interrupt 9 should be level triggered (SCI) */
483 i8259_configure_irq_trigger(9, 1);
484
485 pch_disable_smm_only_flashing(dev);
486
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200487 pch_set_acpi_mode();
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100488
489 pch_fixups(dev);
490}
491
Elyes HAOUASbe841402018-05-13 13:40:39 +0200492static void pch_lpc_read_resources(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100493{
494 struct resource *res;
495 config_t *config = dev->chip_info;
496 u8 io_index = 0;
497
498 /* Get the normal PCI resources of this device. */
499 pci_dev_read_resources(dev);
500
501 /* Add an extra subtractive resource for both memory and I/O. */
502 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
503 res->base = 0;
504 res->size = 0x1000;
505 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
506 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
507
508 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
509 res->base = 0xff800000;
510 res->size = 0x00800000; /* 8 MB for flash */
511 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
512 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
513
514 res = new_resource(dev, 3); /* IOAPIC */
515 res->base = IO_APIC_ADDR;
516 res->size = 0x00001000;
517 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
518
519 /* Set PCH IO decode ranges if required.*/
520 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
521 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
522 res->base = config->gen1_dec & 0xFFFC;
523 res->size = (config->gen1_dec >> 16) & 0xFC;
524 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
525 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
526 }
527
528 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
529 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
530 res->base = config->gen2_dec & 0xFFFC;
531 res->size = (config->gen2_dec >> 16) & 0xFC;
532 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
533 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
534 }
535
536 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
537 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
538 res->base = config->gen3_dec & 0xFFFC;
539 res->size = (config->gen3_dec >> 16) & 0xFC;
540 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
541 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
542 }
543
544 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
545 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
546 res->base = config->gen4_dec & 0xFFFC;
547 res->size = (config->gen4_dec >> 16) & 0xFC;
548 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
549 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
550 }
551}
552
Elyes HAOUASbe841402018-05-13 13:40:39 +0200553static void pch_lpc_enable(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100554{
555 /* Enable PCH Display Port */
556 RCBA16(DISPBDF) = 0x0010;
557 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
558
559 pch_enable(dev);
560}
561
Elyes HAOUASbe841402018-05-13 13:40:39 +0200562static void southbridge_inject_dsdt(struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200563{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200564 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200565
566 if (gnvs) {
Elyes HAOUAS035df002016-10-03 21:54:16 +0200567 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200568
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200569 acpi_create_gnvs(gnvs);
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200570
571 gnvs->apic = 1;
572 gnvs->mpen = 1; /* Enable Multi Processing */
573 gnvs->pcnt = dev_count_cpu();
Nico Huber744d6bd2019-01-12 14:58:20 +0100574
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200575 /* And tell SMI about it */
576 smm_setup_structures(gnvs, NULL, NULL);
577
578 /* Add it to SSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100579 acpigen_write_scope("\\");
580 acpigen_write_name_dword("NVSA", (u32) gnvs);
581 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200582 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200583}
584
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200585void acpi_fill_fadt(acpi_fadt_t *fadt)
586{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300587 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200588 config_t *chip = dev->chip_info;
589 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
590 int c2_latency;
591
Elyes HAOUAS0d4de2a2019-02-28 13:04:29 +0100592 fadt->reserved = 0;
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200593
594 fadt->sci_int = 0x9;
595 fadt->smi_cmd = APM_CNT;
596 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
597 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
598 fadt->s4bios_req = 0x0;
599 fadt->pstate_cnt = 0;
600
601 fadt->pm1a_evt_blk = pmbase;
602 fadt->pm1b_evt_blk = 0x0;
603 fadt->pm1a_cnt_blk = pmbase + 0x4;
604 fadt->pm1b_cnt_blk = 0x0;
605 fadt->pm2_cnt_blk = pmbase + 0x50;
606 fadt->pm_tmr_blk = pmbase + 0x8;
607 fadt->gpe0_blk = pmbase + 0x20;
608 fadt->gpe1_blk = 0;
609
610 fadt->pm1_evt_len = 4;
611 fadt->pm1_cnt_len = 2;
612 fadt->pm2_cnt_len = 1;
613 fadt->pm_tmr_len = 4;
614 fadt->gpe0_blk_len = 16;
615 fadt->gpe1_blk_len = 0;
616 fadt->gpe1_base = 0;
617 fadt->cst_cnt = 0;
618 c2_latency = chip->c2_latency;
619 if (!c2_latency) {
620 c2_latency = 101; /* c2 unsupported */
621 }
622 fadt->p_lvl2_lat = c2_latency;
623 fadt->p_lvl3_lat = 87;
624 fadt->flush_size = 1024;
625 fadt->flush_stride = 16;
Patrick Rudolphb30a47b2019-07-15 18:04:23 +0200626 /* P_CNT not supported */
627 fadt->duty_offset = 0;
628 fadt->duty_width = 0;
629
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200630 fadt->day_alrm = 0xd;
631 fadt->mon_alrm = 0x00;
632 fadt->century = 0x32;
633 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
634
635 fadt->flags = ACPI_FADT_WBINVD |
636 ACPI_FADT_C1_SUPPORTED |
637 ACPI_FADT_SLEEP_BUTTON |
638 ACPI_FADT_RESET_REGISTER |
639 ACPI_FADT_S4_RTC_WAKE |
640 ACPI_FADT_PLATFORM_CLOCK;
641 if (chip->docking_supported) {
642 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
643 }
644 if (c2_latency < 100) {
645 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
646 }
647
648 fadt->reset_reg.space_id = 1;
649 fadt->reset_reg.bit_width = 8;
650 fadt->reset_reg.bit_offset = 0;
651 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
652 fadt->reset_reg.addrl = 0xcf9;
653 fadt->reset_reg.addrh = 0;
654
655 fadt->reset_value = 6;
656
657 fadt->x_pm1a_evt_blk.space_id = 1;
658 fadt->x_pm1a_evt_blk.bit_width = 32;
659 fadt->x_pm1a_evt_blk.bit_offset = 0;
660 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
661 fadt->x_pm1a_evt_blk.addrl = pmbase;
662 fadt->x_pm1a_evt_blk.addrh = 0x0;
663
664 fadt->x_pm1b_evt_blk.space_id = 1;
665 fadt->x_pm1b_evt_blk.bit_width = 0;
666 fadt->x_pm1b_evt_blk.bit_offset = 0;
667 fadt->x_pm1b_evt_blk.access_size = 0;
668 fadt->x_pm1b_evt_blk.addrl = 0x0;
669 fadt->x_pm1b_evt_blk.addrh = 0x0;
670
671 fadt->x_pm1a_cnt_blk.space_id = 1;
672 fadt->x_pm1a_cnt_blk.bit_width = 16;
673 fadt->x_pm1a_cnt_blk.bit_offset = 0;
674 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
675 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
676 fadt->x_pm1a_cnt_blk.addrh = 0x0;
677
678 fadt->x_pm1b_cnt_blk.space_id = 1;
679 fadt->x_pm1b_cnt_blk.bit_width = 0;
680 fadt->x_pm1b_cnt_blk.bit_offset = 0;
681 fadt->x_pm1b_cnt_blk.access_size = 0;
682 fadt->x_pm1b_cnt_blk.addrl = 0x0;
683 fadt->x_pm1b_cnt_blk.addrh = 0x0;
684
685 fadt->x_pm2_cnt_blk.space_id = 1;
686 fadt->x_pm2_cnt_blk.bit_width = 8;
687 fadt->x_pm2_cnt_blk.bit_offset = 0;
688 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
689 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
690 fadt->x_pm2_cnt_blk.addrh = 0x0;
691
692 fadt->x_pm_tmr_blk.space_id = 1;
693 fadt->x_pm_tmr_blk.bit_width = 32;
694 fadt->x_pm_tmr_blk.bit_offset = 0;
695 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
696 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
697 fadt->x_pm_tmr_blk.addrh = 0x0;
698
699 fadt->x_gpe0_blk.space_id = 1;
700 fadt->x_gpe0_blk.bit_width = 128;
701 fadt->x_gpe0_blk.bit_offset = 0;
702 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
703 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
704 fadt->x_gpe0_blk.addrh = 0x0;
705
706 fadt->x_gpe1_blk.space_id = 1;
707 fadt->x_gpe1_blk.bit_width = 0;
708 fadt->x_gpe1_blk.bit_offset = 0;
709 fadt->x_gpe1_blk.access_size = 0;
710 fadt->x_gpe1_blk.addrl = 0x0;
711 fadt->x_gpe1_blk.addrh = 0x0;
712}
713
Kyösti Mälkki90993952018-05-01 19:36:25 +0300714static const char *lpc_acpi_name(const struct device *dev)
715{
716 return "LPCB";
717}
718
Elyes HAOUASbe841402018-05-13 13:40:39 +0200719static void southbridge_fill_ssdt(struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100720{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300721 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100722 config_t *chip = dev->chip_info;
723
724 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Kyösti Mälkki90993952018-05-01 19:36:25 +0300725 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100726}
727
Bill XIEd533b162017-08-22 16:26:22 +0800728static void lpc_final(struct device *dev)
729{
Arthur Heymansaadd1d02019-05-28 13:39:20 +0200730 spi_finalize_ops();
731
Bill XIEd533b162017-08-22 16:26:22 +0800732 /* Call SMM finalize() handlers before resume */
Julius Wernercd49cce2019-03-05 16:53:33 -0800733 if (CONFIG(HAVE_SMI_HANDLER)) {
734 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
Bill XIEd533b162017-08-22 16:26:22 +0800735 acpi_is_wakeup_s3()) {
736 outb(APM_CNT_FINALIZE, APM_CNT);
737 }
738 }
739}
740
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100741static struct pci_operations pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530742 .set_subsystem = pci_dev_set_subsystem,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100743};
744
745static struct device_operations device_ops = {
746 .read_resources = pch_lpc_read_resources,
747 .set_resources = pci_dev_set_resources,
Arthur Heymans3b452e02019-10-03 09:16:10 +0200748 .enable_resources = pci_dev_enable_resources,
Nico Huber68680dd2020-03-31 17:34:52 +0200749 .acpi_inject_dsdt = southbridge_inject_dsdt,
750 .acpi_fill_ssdt = southbridge_fill_ssdt,
Kyösti Mälkki90993952018-05-01 19:36:25 +0300751 .acpi_name = lpc_acpi_name,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200752 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100753 .init = lpc_init,
Bill XIEd533b162017-08-22 16:26:22 +0800754 .final = lpc_final,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100755 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100756 .scan_bus = scan_static_bus,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100757 .ops_pci = &pci_ops,
758};
759
760
Felix Singer838fbc72019-11-21 21:23:32 +0100761static const unsigned short pci_device_ids[] = {
762 PCI_DID_INTEL_IBEXPEAK_LPC_QM57,
763 PCI_DID_INTEL_IBEXPEAK_LPC_HM55,
764 0
765};
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100766
767static const struct pci_driver pch_lpc __pci_driver = {
768 .ops = &device_ops,
769 .vendor = PCI_VENDOR_ID_INTEL,
770 .devices = pci_device_ids,
771};