blob: a96b7ff089d90f8b1e28f64755011af42fa3d7ce [file] [log] [blame]
Vladimir Serbinenko888d5592013-11-13 17:53:38 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008-2009 coresystems GmbH
5 * Copyright (C) 2013 Vladimir Serbinenko
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; version 2 of
10 * the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010016 */
17
18#include <console/console.h>
19#include <device/device.h>
20#include <device/pci.h>
21#include <device/pci_ids.h>
22#include <pc80/mc146818rtc.h>
23#include <pc80/isa-dma.h>
24#include <pc80/i8259.h>
25#include <arch/io.h>
26#include <arch/ioapic.h>
27#include <arch/acpi.h>
Elyes HAOUASd2b9ec12018-10-27 09:41:02 +020028#include <arch/cpu.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010029#include <elog.h>
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020030#include <arch/acpigen.h>
31#include <drivers/intel/gma/i915.h>
32#include <cbmem.h>
Vladimir Serbinenko7309c642014-10-05 11:07:33 +020033#include <string.h>
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +020034#include <cpu/x86/smm.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010035#include "pch.h"
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020036#include "nvs.h"
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010037#include <southbridge/intel/common/pciehp.h>
Kyösti Mälkki90993952018-05-01 19:36:25 +030038#include <southbridge/intel/common/acpi_pirq_gen.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010039
40#define NMI_OFF 0
41
42#define ENABLE_ACPI_MODE_IN_COREBOOT 0
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010043
Vladimir Serbinenko46957052013-11-26 01:16:20 +010044typedef struct southbridge_intel_ibexpeak_config config_t;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010045
46/**
47 * Set miscellanous static southbridge features.
48 *
49 * @param dev PCI device with I/O APIC control registers
50 */
51static void pch_enable_ioapic(struct device *dev)
52{
53 u32 reg32;
54
55 /* Enable ACPI I/O range decode */
56 pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
57
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080058 set_ioapic_id(VIO_APIC_VADDR, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010059 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080060 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
61 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010062
63 /*
64 * Select Boot Configuration register (0x03) and
65 * use Processor System Bus (0x01) to deliver interrupts.
66 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080067 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010068}
69
70static void pch_enable_serial_irqs(struct device *dev)
71{
72 /* Set packet length and toggle silent mode bit for one frame. */
73 pci_write_config8(dev, SERIRQ_CNTL,
74 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Martin Roth7a1a3ad2017-06-24 21:29:38 -060075#if !IS_ENABLED(CONFIG_SERIRQ_CONTINUOUS_MODE)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010076 pci_write_config8(dev, SERIRQ_CNTL,
77 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
78#endif
79}
80
81/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
82 * 0x00 - 0000 = Reserved
83 * 0x01 - 0001 = Reserved
84 * 0x02 - 0010 = Reserved
85 * 0x03 - 0011 = IRQ3
86 * 0x04 - 0100 = IRQ4
87 * 0x05 - 0101 = IRQ5
88 * 0x06 - 0110 = IRQ6
89 * 0x07 - 0111 = IRQ7
90 * 0x08 - 1000 = Reserved
91 * 0x09 - 1001 = IRQ9
92 * 0x0A - 1010 = IRQ10
93 * 0x0B - 1011 = IRQ11
94 * 0x0C - 1100 = IRQ12
95 * 0x0D - 1101 = Reserved
96 * 0x0E - 1110 = IRQ14
97 * 0x0F - 1111 = IRQ15
98 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
99 * 0x80 - The PIRQ is not routed.
100 */
101
Elyes HAOUASbe841402018-05-13 13:40:39 +0200102static void pch_pirq_init(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100103{
Elyes HAOUASbe841402018-05-13 13:40:39 +0200104 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200105 /* Interrupt 11 is not used by legacy devices and so can always be used for
106 PCI interrupts. Full legacy IRQ routing is complicated and hard to
107 get right. Fortunately all modern OS use MSI and so it's not that big of
108 an issue anyway. Still we have to provide a reasonable default. Using
109 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
110 move it to any interrupt and others will just leave them at default.
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100111 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200112 const u8 pirq_routing = 11;
113
114 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
115 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
116 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
117 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
118
119 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
120 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
121 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
122 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100123
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200124 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200125 u8 int_pin=0;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100126
127 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
128 continue;
129
130 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
131
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200132 if (int_pin == 0)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100133 continue;
134
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200135 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100136 }
137}
138
Elyes HAOUASbe841402018-05-13 13:40:39 +0200139static void pch_gpi_routing(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100140{
141 /* Get the chip configuration */
142 config_t *config = dev->chip_info;
143 u32 reg32 = 0;
144
145 /* An array would be much nicer here, or some
146 * other method of doing this.
147 */
148 reg32 |= (config->gpi0_routing & 0x03) << 0;
149 reg32 |= (config->gpi1_routing & 0x03) << 2;
150 reg32 |= (config->gpi2_routing & 0x03) << 4;
151 reg32 |= (config->gpi3_routing & 0x03) << 6;
152 reg32 |= (config->gpi4_routing & 0x03) << 8;
153 reg32 |= (config->gpi5_routing & 0x03) << 10;
154 reg32 |= (config->gpi6_routing & 0x03) << 12;
155 reg32 |= (config->gpi7_routing & 0x03) << 14;
156 reg32 |= (config->gpi8_routing & 0x03) << 16;
157 reg32 |= (config->gpi9_routing & 0x03) << 18;
158 reg32 |= (config->gpi10_routing & 0x03) << 20;
159 reg32 |= (config->gpi11_routing & 0x03) << 22;
160 reg32 |= (config->gpi12_routing & 0x03) << 24;
161 reg32 |= (config->gpi13_routing & 0x03) << 26;
162 reg32 |= (config->gpi14_routing & 0x03) << 28;
163 reg32 |= (config->gpi15_routing & 0x03) << 30;
164
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200165 pci_write_config32(dev, GPIO_ROUT, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100166}
167
Elyes HAOUASbe841402018-05-13 13:40:39 +0200168static void pch_power_options(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100169{
170 u8 reg8;
171 u16 reg16, pmbase;
172 u32 reg32;
173 const char *state;
174 /* Get the chip configuration */
175 config_t *config = dev->chip_info;
176
Nico Huber9faae2b2018-11-14 00:00:35 +0100177 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100178 int nmi_option;
179
180 /* Which state do we want to goto after g3 (power restored)?
181 * 0 == S0 Full On
182 * 1 == S5 Soft Off
183 *
184 * If the option is not existent (Laptops), use Kconfig setting.
185 */
186 get_option(&pwr_on, "power_on_after_fail");
187
188 reg16 = pci_read_config16(dev, GEN_PMCON_3);
189 reg16 &= 0xfffe;
190 switch (pwr_on) {
191 case MAINBOARD_POWER_OFF:
192 reg16 |= 1;
193 state = "off";
194 break;
195 case MAINBOARD_POWER_ON:
196 reg16 &= ~1;
197 state = "on";
198 break;
199 case MAINBOARD_POWER_KEEP:
200 reg16 &= ~1;
201 state = "state keep";
202 break;
203 default:
204 state = "undefined";
205 }
206
207 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
208 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
209
210 reg16 &= ~(1 << 10);
211 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
212
213 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
214
215 pci_write_config16(dev, GEN_PMCON_3, reg16);
216 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
217
218 /* Set up NMI on errors. */
219 reg8 = inb(0x61);
220 reg8 &= 0x0f; /* Higher Nibble must be 0 */
221 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
222 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
223 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
224 outb(reg8, 0x61);
225
226 reg8 = inb(0x70);
227 nmi_option = NMI_OFF;
228 get_option(&nmi_option, "nmi");
229 if (nmi_option) {
230 printk(BIOS_INFO, "NMI sources enabled.\n");
231 reg8 &= ~(1 << 7); /* Set NMI. */
232 } else {
233 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200234 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100235 }
236 outb(reg8, 0x70);
237
238 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
239 reg16 = pci_read_config16(dev, GEN_PMCON_1);
240 reg16 &= ~(3 << 0); // SMI# rate 1 minute
241 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
242#if DEBUG_PERIODIC_SMIS
243 /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
244 * periodic SMIs.
245 */
246 reg16 |= (3 << 0); // Periodic SMI every 8s
247#endif
248 pci_write_config16(dev, GEN_PMCON_1, reg16);
249
250 // Set the board's GPI routing.
251 pch_gpi_routing(dev);
252
253 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
254
255 outl(config->gpe0_en, pmbase + GPE0_EN);
256 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
257
258 /* Set up power management block and determine sleep mode */
259 reg32 = inl(pmbase + 0x04); // PM1_CNT
260 reg32 &= ~(7 << 10); // SLP_TYP
261 reg32 |= (1 << 0); // SCI_EN
262 outl(reg32, pmbase + 0x04);
263
264 /* Clear magic status bits to prevent unexpected wake */
265 reg32 = RCBA32(0x3310);
266 reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
267 RCBA32(0x3310) = reg32;
268
269 reg32 = RCBA32(0x3f02);
270 reg32 &= ~0xf;
271 RCBA32(0x3f02) = reg32;
272}
273
274static void pch_rtc_init(struct device *dev)
275{
276 u8 reg8;
277 int rtc_failed;
278
279 reg8 = pci_read_config8(dev, GEN_PMCON_3);
280 rtc_failed = reg8 & RTC_BATTERY_DEAD;
281 if (rtc_failed) {
282 reg8 &= ~RTC_BATTERY_DEAD;
283 pci_write_config8(dev, GEN_PMCON_3, reg8);
Martin Roth7a1a3ad2017-06-24 21:29:38 -0600284#if IS_ENABLED(CONFIG_ELOG)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100285 elog_add_event(ELOG_TYPE_RTC_RESET);
286#endif
287 }
288 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
289
Gabe Blackb3f08c62014-04-30 17:12:25 -0700290 cmos_init(rtc_failed);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100291}
292
293static void mobile5_pm_init(struct device *dev)
294{
295 int i;
296
297 printk(BIOS_DEBUG, "Mobile 5 PM init\n");
298 pci_write_config8(dev, 0xa9, 0x47);
299
300 RCBA32 (0x1d44) = 0x00000000;
301 (void) RCBA32 (0x1d44);
302 RCBA32 (0x1d48) = 0x00030000;
303 (void) RCBA32 (0x1d48);
304 RCBA32 (0x1e80) = 0x000c0801;
305 (void) RCBA32 (0x1e80);
306 RCBA32 (0x1e84) = 0x000200f0;
307 (void) RCBA32 (0x1e84);
308
309 const u32 rcba2010[] =
310 {
311 /* 2010: */ 0x00188200, 0x14000016, 0xbc4abcb5, 0x00000000,
312 /* 2020: */ 0xf0c9605b, 0x13683040, 0x04c8f16e, 0x09e90170
313 };
Elyes HAOUAS035df002016-10-03 21:54:16 +0200314 for (i = 0; i < sizeof(rcba2010) / sizeof(rcba2010[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100315 {
316 RCBA32 (0x2010 + 4 * i) = rcba2010[i];
317 RCBA32 (0x2010 + 4 * i);
318 }
319
320 RCBA32 (0x2100) = 0x00000000;
321 (void) RCBA32 (0x2100);
322 RCBA32 (0x2104) = 0x00000757;
323 (void) RCBA32 (0x2104);
324 RCBA32 (0x2108) = 0x00170001;
325 (void) RCBA32 (0x2108);
326
327 RCBA32 (0x211c) = 0x00000000;
328 (void) RCBA32 (0x211c);
329 RCBA32 (0x2120) = 0x00010000;
330 (void) RCBA32 (0x2120);
331
332 RCBA32 (0x21fc) = 0x00000000;
333 (void) RCBA32 (0x21fc);
334 RCBA32 (0x2200) = 0x20000044;
335 (void) RCBA32 (0x2200);
336 RCBA32 (0x2204) = 0x00000001;
337 (void) RCBA32 (0x2204);
338 RCBA32 (0x2208) = 0x00003457;
339 (void) RCBA32 (0x2208);
340
341 const u32 rcba2210[] =
342 {
343 /* 2210 */ 0x00000000, 0x00000001, 0xa0fff210, 0x0000df00,
344 /* 2220 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
345 /* 2230 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
346 /* 2240 */ 0x00002301, 0x36000000, 0x00010107, 0x00160000,
347 /* 2250 */ 0x00001b01, 0x36000000, 0x00010107, 0x00160000,
348 /* 2260 */ 0x00000601, 0x16000000, 0x00010107, 0x00160000,
349 /* 2270 */ 0x00001c01, 0x16000000, 0x00010107, 0x00160000
350 };
351
Elyes HAOUAS035df002016-10-03 21:54:16 +0200352 for (i = 0; i < sizeof(rcba2210) / sizeof(rcba2210[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100353 {
354 RCBA32 (0x2210 + 4 * i) = rcba2210[i];
355 RCBA32 (0x2210 + 4 * i);
356 }
357
358 const u32 rcba2300[] =
359 {
360 /* 2300: */ 0x00000000, 0x40000000, 0x4646827b, 0x6e803131,
361 /* 2310: */ 0x32c77887, 0x00077733, 0x00007447, 0x00000040,
362 /* 2320: */ 0xcccc0cfc, 0x0fbb0fff
363 };
364
Elyes HAOUAS035df002016-10-03 21:54:16 +0200365 for (i = 0; i < sizeof(rcba2300) / sizeof(rcba2300[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100366 {
367 RCBA32 (0x2300 + 4 * i) = rcba2300[i];
368 RCBA32 (0x2300 + 4 * i);
369 }
370
371 RCBA32 (0x37fc) = 0x00000000;
372 (void) RCBA32 (0x37fc);
373 RCBA32 (0x3dfc) = 0x00000000;
374 (void) RCBA32 (0x3dfc);
375 RCBA32 (0x3e7c) = 0xffffffff;
376 (void) RCBA32 (0x3e7c);
377 RCBA32 (0x3efc) = 0x00000000;
378 (void) RCBA32 (0x3efc);
379 RCBA32 (0x3f00) = 0x0000010b;
380 (void) RCBA32 (0x3f00);
381}
382
383static void enable_hpet(void)
384{
385 u32 reg32;
386
387 /* Move HPET to default address 0xfed00000 and enable it */
388 reg32 = RCBA32(HPTC);
389 reg32 |= (1 << 7); // HPET Address Enable
390 reg32 &= ~(3 << 0);
391 RCBA32(HPTC) = reg32;
392
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800393 write32((u32 *)0xfed00010, read32((u32 *)0xfed00010) | 1);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100394}
395
Elyes HAOUASbe841402018-05-13 13:40:39 +0200396static void enable_clock_gating(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100397{
398 u32 reg32;
399 u16 reg16;
400
401 RCBA32_AND_OR(0x2234, ~0UL, 0xf);
402
403 reg16 = pci_read_config16(dev, GEN_PMCON_1);
404 reg16 |= (1 << 2) | (1 << 11);
405 pci_write_config16(dev, GEN_PMCON_1, reg16);
406
407 pch_iobp_update(0xEB007F07, ~0UL, (1 << 31));
408 pch_iobp_update(0xEB004000, ~0UL, (1 << 7));
409 pch_iobp_update(0xEC007F07, ~0UL, (1 << 31));
410 pch_iobp_update(0xEC004000, ~0UL, (1 << 7));
411
412 reg32 = RCBA32(CG);
413 reg32 |= (1 << 31);
414 reg32 |= (1 << 29) | (1 << 28);
415 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
416 reg32 |= (1 << 16);
417 reg32 |= (1 << 17);
418 reg32 |= (1 << 18);
419 reg32 |= (1 << 22);
420 reg32 |= (1 << 23);
421 reg32 &= ~(1 << 20);
422 reg32 |= (1 << 19);
423 reg32 |= (1 << 0);
424 reg32 |= (0xf << 1);
425 RCBA32(CG) = reg32;
426
427 RCBA32_OR(0x38c0, 0x7);
428 RCBA32_OR(0x36d4, 0x6680c004);
429 RCBA32_OR(0x3564, 0x3);
430}
431
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200432static void pch_set_acpi_mode(void)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100433{
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200434 if (!acpi_is_wakeup_s3() && CONFIG_HAVE_SMI_HANDLER) {
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100435#if ENABLE_ACPI_MODE_IN_COREBOOT
436 printk(BIOS_DEBUG, "Enabling ACPI via APMC:\n");
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200437 outb(APM_CNT_ACPI_ENABLE, APM_CNT); // Enable ACPI mode
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100438 printk(BIOS_DEBUG, "done.\n");
439#else
440 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200441 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100442 printk(BIOS_DEBUG, "done.\n");
443#endif
444 }
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100445}
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100446
447static void pch_disable_smm_only_flashing(struct device *dev)
448{
449 u8 reg8;
450
451 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
452 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
453 reg8 &= ~(1 << 5);
454 pci_write_config8(dev, 0xdc, reg8);
455}
456
457static void pch_fixups(struct device *dev)
458{
459 /*
460 * Enable DMI ASPM in the PCH
461 */
462 RCBA32_AND_OR(0x2304, ~(1 << 10), 0);
463 RCBA32_OR(0x21a4, (1 << 11)|(1 << 10));
464 RCBA32_OR(0x21a8, 0x3);
465}
466
467static void pch_decode_init(struct device *dev)
468{
469 config_t *config = dev->chip_info;
470
471 printk(BIOS_DEBUG, "pch_decode_init\n");
472
473 pci_write_config32(dev, LPC_GEN1_DEC, config->gen1_dec);
474 pci_write_config32(dev, LPC_GEN2_DEC, config->gen2_dec);
475 pci_write_config32(dev, LPC_GEN3_DEC, config->gen3_dec);
476 pci_write_config32(dev, LPC_GEN4_DEC, config->gen4_dec);
477}
478
479static void lpc_init(struct device *dev)
480{
481 printk(BIOS_DEBUG, "pch: lpc_init\n");
482
483 /* Set the value for PCI command register. */
484 pci_write_config16(dev, PCI_COMMAND, 0x000f);
485
486 /* IO APIC initialization. */
487 pch_enable_ioapic(dev);
488
489 pch_enable_serial_irqs(dev);
490
491 /* Setup the PIRQ. */
492 pch_pirq_init(dev);
493
494 /* Setup power options. */
495 pch_power_options(dev);
496
497 /* Initialize power management */
498 switch (pch_silicon_type()) {
499 case PCH_TYPE_MOBILE5:
500 mobile5_pm_init (dev);
501 break;
502 default:
503 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
504 }
505
506 /* Set the state of the GPIO lines. */
507 //gpio_init(dev);
508
509 /* Initialize the real time clock. */
510 pch_rtc_init(dev);
511
512 /* Initialize ISA DMA. */
513 isa_dma_init();
514
515 /* Initialize the High Precision Event Timers, if present. */
516 enable_hpet();
517
518 /* Initialize Clock Gating */
519 enable_clock_gating(dev);
520
521 setup_i8259();
522
523 /* The OS should do this? */
524 /* Interrupt 9 should be level triggered (SCI) */
525 i8259_configure_irq_trigger(9, 1);
526
527 pch_disable_smm_only_flashing(dev);
528
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200529 pch_set_acpi_mode();
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100530
531 pch_fixups(dev);
532}
533
Elyes HAOUASbe841402018-05-13 13:40:39 +0200534static void pch_lpc_read_resources(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100535{
536 struct resource *res;
537 config_t *config = dev->chip_info;
538 u8 io_index = 0;
539
540 /* Get the normal PCI resources of this device. */
541 pci_dev_read_resources(dev);
542
543 /* Add an extra subtractive resource for both memory and I/O. */
544 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
545 res->base = 0;
546 res->size = 0x1000;
547 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
548 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
549
550 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
551 res->base = 0xff800000;
552 res->size = 0x00800000; /* 8 MB for flash */
553 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
554 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
555
556 res = new_resource(dev, 3); /* IOAPIC */
557 res->base = IO_APIC_ADDR;
558 res->size = 0x00001000;
559 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
560
561 /* Set PCH IO decode ranges if required.*/
562 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
563 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
564 res->base = config->gen1_dec & 0xFFFC;
565 res->size = (config->gen1_dec >> 16) & 0xFC;
566 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
567 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
568 }
569
570 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
571 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
572 res->base = config->gen2_dec & 0xFFFC;
573 res->size = (config->gen2_dec >> 16) & 0xFC;
574 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
575 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
576 }
577
578 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
579 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
580 res->base = config->gen3_dec & 0xFFFC;
581 res->size = (config->gen3_dec >> 16) & 0xFC;
582 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
583 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
584 }
585
586 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
587 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
588 res->base = config->gen4_dec & 0xFFFC;
589 res->size = (config->gen4_dec >> 16) & 0xFC;
590 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
591 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
592 }
593}
594
Elyes HAOUASbe841402018-05-13 13:40:39 +0200595static void pch_lpc_enable_resources(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100596{
597 pch_decode_init(dev);
598 return pci_dev_enable_resources(dev);
599}
600
Elyes HAOUASbe841402018-05-13 13:40:39 +0200601static void pch_lpc_enable(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100602{
603 /* Enable PCH Display Port */
604 RCBA16(DISPBDF) = 0x0010;
605 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
606
607 pch_enable(dev);
608}
609
Elyes HAOUASbe841402018-05-13 13:40:39 +0200610static void set_subsystem(struct device *dev, unsigned vendor,
611 unsigned device)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100612{
613 if (!vendor || !device) {
614 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
615 pci_read_config32(dev, PCI_VENDOR_ID));
616 } else {
617 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
618 ((device & 0xffff) << 16) | (vendor & 0xffff));
619 }
620}
621
Elyes HAOUASbe841402018-05-13 13:40:39 +0200622static void southbridge_inject_dsdt(struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200623{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200624 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200625
626 if (gnvs) {
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100627 const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
Elyes HAOUAS035df002016-10-03 21:54:16 +0200628 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200629
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200630 acpi_create_gnvs(gnvs);
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200631
632 gnvs->apic = 1;
633 gnvs->mpen = 1; /* Enable Multi Processing */
634 gnvs->pcnt = dev_count_cpu();
Nico Huber744d6bd2019-01-12 14:58:20 +0100635
636 if (gfx) {
637 gnvs->ndid = gfx->ndid;
638 memcpy(gnvs->did, gfx->did, sizeof(gnvs->did));
639 }
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200640
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200641 /* And tell SMI about it */
642 smm_setup_structures(gnvs, NULL, NULL);
643
644 /* Add it to SSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100645 acpigen_write_scope("\\");
646 acpigen_write_name_dword("NVSA", (u32) gnvs);
647 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200648 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200649}
650
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200651void acpi_fill_fadt(acpi_fadt_t *fadt)
652{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300653 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200654 config_t *chip = dev->chip_info;
655 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
656 int c2_latency;
657
658 fadt->model = 1;
659
660 fadt->sci_int = 0x9;
661 fadt->smi_cmd = APM_CNT;
662 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
663 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
664 fadt->s4bios_req = 0x0;
665 fadt->pstate_cnt = 0;
666
667 fadt->pm1a_evt_blk = pmbase;
668 fadt->pm1b_evt_blk = 0x0;
669 fadt->pm1a_cnt_blk = pmbase + 0x4;
670 fadt->pm1b_cnt_blk = 0x0;
671 fadt->pm2_cnt_blk = pmbase + 0x50;
672 fadt->pm_tmr_blk = pmbase + 0x8;
673 fadt->gpe0_blk = pmbase + 0x20;
674 fadt->gpe1_blk = 0;
675
676 fadt->pm1_evt_len = 4;
677 fadt->pm1_cnt_len = 2;
678 fadt->pm2_cnt_len = 1;
679 fadt->pm_tmr_len = 4;
680 fadt->gpe0_blk_len = 16;
681 fadt->gpe1_blk_len = 0;
682 fadt->gpe1_base = 0;
683 fadt->cst_cnt = 0;
684 c2_latency = chip->c2_latency;
685 if (!c2_latency) {
686 c2_latency = 101; /* c2 unsupported */
687 }
688 fadt->p_lvl2_lat = c2_latency;
689 fadt->p_lvl3_lat = 87;
690 fadt->flush_size = 1024;
691 fadt->flush_stride = 16;
692 fadt->duty_offset = 1;
693 if (chip->p_cnt_throttling_supported) {
694 fadt->duty_width = 3;
695 } else {
696 fadt->duty_width = 0;
697 }
698 fadt->day_alrm = 0xd;
699 fadt->mon_alrm = 0x00;
700 fadt->century = 0x32;
701 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
702
703 fadt->flags = ACPI_FADT_WBINVD |
704 ACPI_FADT_C1_SUPPORTED |
705 ACPI_FADT_SLEEP_BUTTON |
706 ACPI_FADT_RESET_REGISTER |
707 ACPI_FADT_S4_RTC_WAKE |
708 ACPI_FADT_PLATFORM_CLOCK;
709 if (chip->docking_supported) {
710 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
711 }
712 if (c2_latency < 100) {
713 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
714 }
715
716 fadt->reset_reg.space_id = 1;
717 fadt->reset_reg.bit_width = 8;
718 fadt->reset_reg.bit_offset = 0;
719 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
720 fadt->reset_reg.addrl = 0xcf9;
721 fadt->reset_reg.addrh = 0;
722
723 fadt->reset_value = 6;
724
725 fadt->x_pm1a_evt_blk.space_id = 1;
726 fadt->x_pm1a_evt_blk.bit_width = 32;
727 fadt->x_pm1a_evt_blk.bit_offset = 0;
728 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
729 fadt->x_pm1a_evt_blk.addrl = pmbase;
730 fadt->x_pm1a_evt_blk.addrh = 0x0;
731
732 fadt->x_pm1b_evt_blk.space_id = 1;
733 fadt->x_pm1b_evt_blk.bit_width = 0;
734 fadt->x_pm1b_evt_blk.bit_offset = 0;
735 fadt->x_pm1b_evt_blk.access_size = 0;
736 fadt->x_pm1b_evt_blk.addrl = 0x0;
737 fadt->x_pm1b_evt_blk.addrh = 0x0;
738
739 fadt->x_pm1a_cnt_blk.space_id = 1;
740 fadt->x_pm1a_cnt_blk.bit_width = 16;
741 fadt->x_pm1a_cnt_blk.bit_offset = 0;
742 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
743 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
744 fadt->x_pm1a_cnt_blk.addrh = 0x0;
745
746 fadt->x_pm1b_cnt_blk.space_id = 1;
747 fadt->x_pm1b_cnt_blk.bit_width = 0;
748 fadt->x_pm1b_cnt_blk.bit_offset = 0;
749 fadt->x_pm1b_cnt_blk.access_size = 0;
750 fadt->x_pm1b_cnt_blk.addrl = 0x0;
751 fadt->x_pm1b_cnt_blk.addrh = 0x0;
752
753 fadt->x_pm2_cnt_blk.space_id = 1;
754 fadt->x_pm2_cnt_blk.bit_width = 8;
755 fadt->x_pm2_cnt_blk.bit_offset = 0;
756 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
757 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
758 fadt->x_pm2_cnt_blk.addrh = 0x0;
759
760 fadt->x_pm_tmr_blk.space_id = 1;
761 fadt->x_pm_tmr_blk.bit_width = 32;
762 fadt->x_pm_tmr_blk.bit_offset = 0;
763 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
764 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
765 fadt->x_pm_tmr_blk.addrh = 0x0;
766
767 fadt->x_gpe0_blk.space_id = 1;
768 fadt->x_gpe0_blk.bit_width = 128;
769 fadt->x_gpe0_blk.bit_offset = 0;
770 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
771 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
772 fadt->x_gpe0_blk.addrh = 0x0;
773
774 fadt->x_gpe1_blk.space_id = 1;
775 fadt->x_gpe1_blk.bit_width = 0;
776 fadt->x_gpe1_blk.bit_offset = 0;
777 fadt->x_gpe1_blk.access_size = 0;
778 fadt->x_gpe1_blk.addrl = 0x0;
779 fadt->x_gpe1_blk.addrh = 0x0;
780}
781
Kyösti Mälkki90993952018-05-01 19:36:25 +0300782static const char *lpc_acpi_name(const struct device *dev)
783{
784 return "LPCB";
785}
786
Elyes HAOUASbe841402018-05-13 13:40:39 +0200787static void southbridge_fill_ssdt(struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100788{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300789 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100790 config_t *chip = dev->chip_info;
791
792 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Kyösti Mälkki90993952018-05-01 19:36:25 +0300793 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100794}
795
Bill XIEd533b162017-08-22 16:26:22 +0800796static void lpc_final(struct device *dev)
797{
798 /* Call SMM finalize() handlers before resume */
799 if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER)) {
800 if (IS_ENABLED(CONFIG_INTEL_CHIPSET_LOCKDOWN) ||
801 acpi_is_wakeup_s3()) {
802 outb(APM_CNT_FINALIZE, APM_CNT);
803 }
804 }
805}
806
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100807static struct pci_operations pci_ops = {
808 .set_subsystem = set_subsystem,
809};
810
811static struct device_operations device_ops = {
812 .read_resources = pch_lpc_read_resources,
813 .set_resources = pci_dev_set_resources,
814 .enable_resources = pch_lpc_enable_resources,
Vladimir Serbinenko334fd8e2014-10-05 11:10:35 +0200815 .acpi_inject_dsdt_generator = southbridge_inject_dsdt,
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100816 .acpi_fill_ssdt_generator = southbridge_fill_ssdt,
Kyösti Mälkki90993952018-05-01 19:36:25 +0300817 .acpi_name = lpc_acpi_name,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200818 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100819 .init = lpc_init,
Bill XIEd533b162017-08-22 16:26:22 +0800820 .final = lpc_final,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100821 .enable = pch_lpc_enable,
Kyösti Mälkkid0e212c2015-02-26 20:47:47 +0200822 .scan_bus = scan_lpc_bus,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100823 .ops_pci = &pci_ops,
824};
825
826
Vladimir Serbinenkob7d87882014-02-19 22:01:35 +0100827static const unsigned short pci_device_ids[] = { 0x3b07, 0x3b09, 0 };
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100828
829static const struct pci_driver pch_lpc __pci_driver = {
830 .ops = &device_ops,
831 .vendor = PCI_VENDOR_ID_INTEL,
832 .devices = pci_device_ids,
833};