blob: bd12944adff1ce9ddb78ddbb4a20f3ab1db2c9e5 [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>
28#include <cpu/cpu.h>
29#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>
Arthur Heymansd2d2aef2018-01-16 14:19:37 +010039#include <southbridge/intel/common/rcba.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010040
41#define NMI_OFF 0
42
43#define ENABLE_ACPI_MODE_IN_COREBOOT 0
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010044
Vladimir Serbinenko46957052013-11-26 01:16:20 +010045typedef struct southbridge_intel_ibexpeak_config config_t;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010046
47/**
48 * Set miscellanous static southbridge features.
49 *
50 * @param dev PCI device with I/O APIC control registers
51 */
52static void pch_enable_ioapic(struct device *dev)
53{
54 u32 reg32;
55
56 /* Enable ACPI I/O range decode */
57 pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
58
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080059 set_ioapic_id(VIO_APIC_VADDR, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010060 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080061 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
62 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010063
64 /*
65 * Select Boot Configuration register (0x03) and
66 * use Processor System Bus (0x01) to deliver interrupts.
67 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080068 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010069}
70
71static void pch_enable_serial_irqs(struct device *dev)
72{
73 /* Set packet length and toggle silent mode bit for one frame. */
74 pci_write_config8(dev, SERIRQ_CNTL,
75 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Martin Roth7a1a3ad2017-06-24 21:29:38 -060076#if !IS_ENABLED(CONFIG_SERIRQ_CONTINUOUS_MODE)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010077 pci_write_config8(dev, SERIRQ_CNTL,
78 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
79#endif
80}
81
82/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
83 * 0x00 - 0000 = Reserved
84 * 0x01 - 0001 = Reserved
85 * 0x02 - 0010 = Reserved
86 * 0x03 - 0011 = IRQ3
87 * 0x04 - 0100 = IRQ4
88 * 0x05 - 0101 = IRQ5
89 * 0x06 - 0110 = IRQ6
90 * 0x07 - 0111 = IRQ7
91 * 0x08 - 1000 = Reserved
92 * 0x09 - 1001 = IRQ9
93 * 0x0A - 1010 = IRQ10
94 * 0x0B - 1011 = IRQ11
95 * 0x0C - 1100 = IRQ12
96 * 0x0D - 1101 = Reserved
97 * 0x0E - 1110 = IRQ14
98 * 0x0F - 1111 = IRQ15
99 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
100 * 0x80 - The PIRQ is not routed.
101 */
102
103static void pch_pirq_init(device_t dev)
104{
105 device_t irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200106 /* Interrupt 11 is not used by legacy devices and so can always be used for
107 PCI interrupts. Full legacy IRQ routing is complicated and hard to
108 get right. Fortunately all modern OS use MSI and so it's not that big of
109 an issue anyway. Still we have to provide a reasonable default. Using
110 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
111 move it to any interrupt and others will just leave them at default.
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100112 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200113 const u8 pirq_routing = 11;
114
115 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
116 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
117 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
118 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
119
120 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
121 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
122 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
123 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100124
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200125 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200126 u8 int_pin=0;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100127
128 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
129 continue;
130
131 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
132
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200133 if (int_pin == 0)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100134 continue;
135
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200136 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100137 }
138}
139
140static void pch_gpi_routing(device_t dev)
141{
142 /* Get the chip configuration */
143 config_t *config = dev->chip_info;
144 u32 reg32 = 0;
145
146 /* An array would be much nicer here, or some
147 * other method of doing this.
148 */
149 reg32 |= (config->gpi0_routing & 0x03) << 0;
150 reg32 |= (config->gpi1_routing & 0x03) << 2;
151 reg32 |= (config->gpi2_routing & 0x03) << 4;
152 reg32 |= (config->gpi3_routing & 0x03) << 6;
153 reg32 |= (config->gpi4_routing & 0x03) << 8;
154 reg32 |= (config->gpi5_routing & 0x03) << 10;
155 reg32 |= (config->gpi6_routing & 0x03) << 12;
156 reg32 |= (config->gpi7_routing & 0x03) << 14;
157 reg32 |= (config->gpi8_routing & 0x03) << 16;
158 reg32 |= (config->gpi9_routing & 0x03) << 18;
159 reg32 |= (config->gpi10_routing & 0x03) << 20;
160 reg32 |= (config->gpi11_routing & 0x03) << 22;
161 reg32 |= (config->gpi12_routing & 0x03) << 24;
162 reg32 |= (config->gpi13_routing & 0x03) << 26;
163 reg32 |= (config->gpi14_routing & 0x03) << 28;
164 reg32 |= (config->gpi15_routing & 0x03) << 30;
165
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200166 pci_write_config32(dev, GPIO_ROUT, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100167}
168
169static void pch_power_options(device_t dev)
170{
171 u8 reg8;
172 u16 reg16, pmbase;
173 u32 reg32;
174 const char *state;
175 /* Get the chip configuration */
176 config_t *config = dev->chip_info;
177
178 int pwr_on=CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
179 int nmi_option;
180
181 /* Which state do we want to goto after g3 (power restored)?
182 * 0 == S0 Full On
183 * 1 == S5 Soft Off
184 *
185 * If the option is not existent (Laptops), use Kconfig setting.
186 */
187 get_option(&pwr_on, "power_on_after_fail");
188
189 reg16 = pci_read_config16(dev, GEN_PMCON_3);
190 reg16 &= 0xfffe;
191 switch (pwr_on) {
192 case MAINBOARD_POWER_OFF:
193 reg16 |= 1;
194 state = "off";
195 break;
196 case MAINBOARD_POWER_ON:
197 reg16 &= ~1;
198 state = "on";
199 break;
200 case MAINBOARD_POWER_KEEP:
201 reg16 &= ~1;
202 state = "state keep";
203 break;
204 default:
205 state = "undefined";
206 }
207
208 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
209 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
210
211 reg16 &= ~(1 << 10);
212 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
213
214 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
215
216 pci_write_config16(dev, GEN_PMCON_3, reg16);
217 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
218
219 /* Set up NMI on errors. */
220 reg8 = inb(0x61);
221 reg8 &= 0x0f; /* Higher Nibble must be 0 */
222 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
223 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
224 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
225 outb(reg8, 0x61);
226
227 reg8 = inb(0x70);
228 nmi_option = NMI_OFF;
229 get_option(&nmi_option, "nmi");
230 if (nmi_option) {
231 printk(BIOS_INFO, "NMI sources enabled.\n");
232 reg8 &= ~(1 << 7); /* Set NMI. */
233 } else {
234 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200235 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100236 }
237 outb(reg8, 0x70);
238
239 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
240 reg16 = pci_read_config16(dev, GEN_PMCON_1);
241 reg16 &= ~(3 << 0); // SMI# rate 1 minute
242 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
243#if DEBUG_PERIODIC_SMIS
244 /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
245 * periodic SMIs.
246 */
247 reg16 |= (3 << 0); // Periodic SMI every 8s
248#endif
249 pci_write_config16(dev, GEN_PMCON_1, reg16);
250
251 // Set the board's GPI routing.
252 pch_gpi_routing(dev);
253
254 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
255
256 outl(config->gpe0_en, pmbase + GPE0_EN);
257 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
258
259 /* Set up power management block and determine sleep mode */
260 reg32 = inl(pmbase + 0x04); // PM1_CNT
261 reg32 &= ~(7 << 10); // SLP_TYP
262 reg32 |= (1 << 0); // SCI_EN
263 outl(reg32, pmbase + 0x04);
264
265 /* Clear magic status bits to prevent unexpected wake */
266 reg32 = RCBA32(0x3310);
267 reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
268 RCBA32(0x3310) = reg32;
269
270 reg32 = RCBA32(0x3f02);
271 reg32 &= ~0xf;
272 RCBA32(0x3f02) = reg32;
273}
274
275static void pch_rtc_init(struct device *dev)
276{
277 u8 reg8;
278 int rtc_failed;
279
280 reg8 = pci_read_config8(dev, GEN_PMCON_3);
281 rtc_failed = reg8 & RTC_BATTERY_DEAD;
282 if (rtc_failed) {
283 reg8 &= ~RTC_BATTERY_DEAD;
284 pci_write_config8(dev, GEN_PMCON_3, reg8);
Martin Roth7a1a3ad2017-06-24 21:29:38 -0600285#if IS_ENABLED(CONFIG_ELOG)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100286 elog_add_event(ELOG_TYPE_RTC_RESET);
287#endif
288 }
289 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
290
Gabe Blackb3f08c62014-04-30 17:12:25 -0700291 cmos_init(rtc_failed);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100292}
293
294static void mobile5_pm_init(struct device *dev)
295{
296 int i;
297
298 printk(BIOS_DEBUG, "Mobile 5 PM init\n");
299 pci_write_config8(dev, 0xa9, 0x47);
300
301 RCBA32 (0x1d44) = 0x00000000;
302 (void) RCBA32 (0x1d44);
303 RCBA32 (0x1d48) = 0x00030000;
304 (void) RCBA32 (0x1d48);
305 RCBA32 (0x1e80) = 0x000c0801;
306 (void) RCBA32 (0x1e80);
307 RCBA32 (0x1e84) = 0x000200f0;
308 (void) RCBA32 (0x1e84);
309
310 const u32 rcba2010[] =
311 {
312 /* 2010: */ 0x00188200, 0x14000016, 0xbc4abcb5, 0x00000000,
313 /* 2020: */ 0xf0c9605b, 0x13683040, 0x04c8f16e, 0x09e90170
314 };
Elyes HAOUAS035df002016-10-03 21:54:16 +0200315 for (i = 0; i < sizeof(rcba2010) / sizeof(rcba2010[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100316 {
317 RCBA32 (0x2010 + 4 * i) = rcba2010[i];
318 RCBA32 (0x2010 + 4 * i);
319 }
320
321 RCBA32 (0x2100) = 0x00000000;
322 (void) RCBA32 (0x2100);
323 RCBA32 (0x2104) = 0x00000757;
324 (void) RCBA32 (0x2104);
325 RCBA32 (0x2108) = 0x00170001;
326 (void) RCBA32 (0x2108);
327
328 RCBA32 (0x211c) = 0x00000000;
329 (void) RCBA32 (0x211c);
330 RCBA32 (0x2120) = 0x00010000;
331 (void) RCBA32 (0x2120);
332
333 RCBA32 (0x21fc) = 0x00000000;
334 (void) RCBA32 (0x21fc);
335 RCBA32 (0x2200) = 0x20000044;
336 (void) RCBA32 (0x2200);
337 RCBA32 (0x2204) = 0x00000001;
338 (void) RCBA32 (0x2204);
339 RCBA32 (0x2208) = 0x00003457;
340 (void) RCBA32 (0x2208);
341
342 const u32 rcba2210[] =
343 {
344 /* 2210 */ 0x00000000, 0x00000001, 0xa0fff210, 0x0000df00,
345 /* 2220 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
346 /* 2230 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
347 /* 2240 */ 0x00002301, 0x36000000, 0x00010107, 0x00160000,
348 /* 2250 */ 0x00001b01, 0x36000000, 0x00010107, 0x00160000,
349 /* 2260 */ 0x00000601, 0x16000000, 0x00010107, 0x00160000,
350 /* 2270 */ 0x00001c01, 0x16000000, 0x00010107, 0x00160000
351 };
352
Elyes HAOUAS035df002016-10-03 21:54:16 +0200353 for (i = 0; i < sizeof(rcba2210) / sizeof(rcba2210[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100354 {
355 RCBA32 (0x2210 + 4 * i) = rcba2210[i];
356 RCBA32 (0x2210 + 4 * i);
357 }
358
359 const u32 rcba2300[] =
360 {
361 /* 2300: */ 0x00000000, 0x40000000, 0x4646827b, 0x6e803131,
362 /* 2310: */ 0x32c77887, 0x00077733, 0x00007447, 0x00000040,
363 /* 2320: */ 0xcccc0cfc, 0x0fbb0fff
364 };
365
Elyes HAOUAS035df002016-10-03 21:54:16 +0200366 for (i = 0; i < sizeof(rcba2300) / sizeof(rcba2300[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100367 {
368 RCBA32 (0x2300 + 4 * i) = rcba2300[i];
369 RCBA32 (0x2300 + 4 * i);
370 }
371
372 RCBA32 (0x37fc) = 0x00000000;
373 (void) RCBA32 (0x37fc);
374 RCBA32 (0x3dfc) = 0x00000000;
375 (void) RCBA32 (0x3dfc);
376 RCBA32 (0x3e7c) = 0xffffffff;
377 (void) RCBA32 (0x3e7c);
378 RCBA32 (0x3efc) = 0x00000000;
379 (void) RCBA32 (0x3efc);
380 RCBA32 (0x3f00) = 0x0000010b;
381 (void) RCBA32 (0x3f00);
382}
383
384static void enable_hpet(void)
385{
386 u32 reg32;
387
388 /* Move HPET to default address 0xfed00000 and enable it */
389 reg32 = RCBA32(HPTC);
390 reg32 |= (1 << 7); // HPET Address Enable
391 reg32 &= ~(3 << 0);
392 RCBA32(HPTC) = reg32;
393
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800394 write32((u32 *)0xfed00010, read32((u32 *)0xfed00010) | 1);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100395}
396
397static void enable_clock_gating(device_t dev)
398{
399 u32 reg32;
400 u16 reg16;
401
402 RCBA32_AND_OR(0x2234, ~0UL, 0xf);
403
404 reg16 = pci_read_config16(dev, GEN_PMCON_1);
405 reg16 |= (1 << 2) | (1 << 11);
406 pci_write_config16(dev, GEN_PMCON_1, reg16);
407
408 pch_iobp_update(0xEB007F07, ~0UL, (1 << 31));
409 pch_iobp_update(0xEB004000, ~0UL, (1 << 7));
410 pch_iobp_update(0xEC007F07, ~0UL, (1 << 31));
411 pch_iobp_update(0xEC004000, ~0UL, (1 << 7));
412
413 reg32 = RCBA32(CG);
414 reg32 |= (1 << 31);
415 reg32 |= (1 << 29) | (1 << 28);
416 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
417 reg32 |= (1 << 16);
418 reg32 |= (1 << 17);
419 reg32 |= (1 << 18);
420 reg32 |= (1 << 22);
421 reg32 |= (1 << 23);
422 reg32 &= ~(1 << 20);
423 reg32 |= (1 << 19);
424 reg32 |= (1 << 0);
425 reg32 |= (0xf << 1);
426 RCBA32(CG) = reg32;
427
428 RCBA32_OR(0x38c0, 0x7);
429 RCBA32_OR(0x36d4, 0x6680c004);
430 RCBA32_OR(0x3564, 0x3);
431}
432
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200433static void pch_set_acpi_mode(void)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100434{
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200435 if (!acpi_is_wakeup_s3() && CONFIG_HAVE_SMI_HANDLER) {
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100436#if ENABLE_ACPI_MODE_IN_COREBOOT
437 printk(BIOS_DEBUG, "Enabling ACPI via APMC:\n");
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200438 outb(APM_CNT_ACPI_ENABLE, APM_CNT); // Enable ACPI mode
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100439 printk(BIOS_DEBUG, "done.\n");
440#else
441 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200442 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100443 printk(BIOS_DEBUG, "done.\n");
444#endif
445 }
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100446}
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100447
448static void pch_disable_smm_only_flashing(struct device *dev)
449{
450 u8 reg8;
451
452 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
453 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
454 reg8 &= ~(1 << 5);
455 pci_write_config8(dev, 0xdc, reg8);
456}
457
458static void pch_fixups(struct device *dev)
459{
460 /*
461 * Enable DMI ASPM in the PCH
462 */
463 RCBA32_AND_OR(0x2304, ~(1 << 10), 0);
464 RCBA32_OR(0x21a4, (1 << 11)|(1 << 10));
465 RCBA32_OR(0x21a8, 0x3);
466}
467
468static void pch_decode_init(struct device *dev)
469{
470 config_t *config = dev->chip_info;
471
472 printk(BIOS_DEBUG, "pch_decode_init\n");
473
474 pci_write_config32(dev, LPC_GEN1_DEC, config->gen1_dec);
475 pci_write_config32(dev, LPC_GEN2_DEC, config->gen2_dec);
476 pci_write_config32(dev, LPC_GEN3_DEC, config->gen3_dec);
477 pci_write_config32(dev, LPC_GEN4_DEC, config->gen4_dec);
478}
479
480static void lpc_init(struct device *dev)
481{
482 printk(BIOS_DEBUG, "pch: lpc_init\n");
483
484 /* Set the value for PCI command register. */
485 pci_write_config16(dev, PCI_COMMAND, 0x000f);
486
487 /* IO APIC initialization. */
488 pch_enable_ioapic(dev);
489
490 pch_enable_serial_irqs(dev);
491
492 /* Setup the PIRQ. */
493 pch_pirq_init(dev);
494
495 /* Setup power options. */
496 pch_power_options(dev);
497
498 /* Initialize power management */
499 switch (pch_silicon_type()) {
500 case PCH_TYPE_MOBILE5:
501 mobile5_pm_init (dev);
502 break;
503 default:
504 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
505 }
506
507 /* Set the state of the GPIO lines. */
508 //gpio_init(dev);
509
510 /* Initialize the real time clock. */
511 pch_rtc_init(dev);
512
513 /* Initialize ISA DMA. */
514 isa_dma_init();
515
516 /* Initialize the High Precision Event Timers, if present. */
517 enable_hpet();
518
519 /* Initialize Clock Gating */
520 enable_clock_gating(dev);
521
522 setup_i8259();
523
524 /* The OS should do this? */
525 /* Interrupt 9 should be level triggered (SCI) */
526 i8259_configure_irq_trigger(9, 1);
527
528 pch_disable_smm_only_flashing(dev);
529
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200530 pch_set_acpi_mode();
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100531
532 pch_fixups(dev);
533}
534
535static void pch_lpc_read_resources(device_t dev)
536{
537 struct resource *res;
538 config_t *config = dev->chip_info;
539 u8 io_index = 0;
540
541 /* Get the normal PCI resources of this device. */
542 pci_dev_read_resources(dev);
543
544 /* Add an extra subtractive resource for both memory and I/O. */
545 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
546 res->base = 0;
547 res->size = 0x1000;
548 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
549 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
550
551 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
552 res->base = 0xff800000;
553 res->size = 0x00800000; /* 8 MB for flash */
554 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
555 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
556
557 res = new_resource(dev, 3); /* IOAPIC */
558 res->base = IO_APIC_ADDR;
559 res->size = 0x00001000;
560 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
561
562 /* Set PCH IO decode ranges if required.*/
563 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
564 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
565 res->base = config->gen1_dec & 0xFFFC;
566 res->size = (config->gen1_dec >> 16) & 0xFC;
567 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
568 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
569 }
570
571 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
572 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
573 res->base = config->gen2_dec & 0xFFFC;
574 res->size = (config->gen2_dec >> 16) & 0xFC;
575 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
576 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
577 }
578
579 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
580 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
581 res->base = config->gen3_dec & 0xFFFC;
582 res->size = (config->gen3_dec >> 16) & 0xFC;
583 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
584 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
585 }
586
587 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
588 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
589 res->base = config->gen4_dec & 0xFFFC;
590 res->size = (config->gen4_dec >> 16) & 0xFC;
591 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
592 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
593 }
594}
595
596static void pch_lpc_enable_resources(device_t dev)
597{
598 pch_decode_init(dev);
599 return pci_dev_enable_resources(dev);
600}
601
602static void pch_lpc_enable(device_t dev)
603{
604 /* Enable PCH Display Port */
605 RCBA16(DISPBDF) = 0x0010;
606 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
607
608 pch_enable(dev);
609}
610
611static void set_subsystem(device_t dev, unsigned vendor, unsigned device)
612{
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
Alexander Couzensa90dad12015-04-12 21:49:46 +0200622static void southbridge_inject_dsdt(device_t 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();
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100635 gnvs->ndid = gfx->ndid;
636 memcpy(gnvs->did, gfx->did, sizeof(gnvs->did));
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200637
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200638 /* And tell SMI about it */
639 smm_setup_structures(gnvs, NULL, NULL);
640
641 /* Add it to SSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100642 acpigen_write_scope("\\");
643 acpigen_write_name_dword("NVSA", (u32) gnvs);
644 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200645 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200646}
647
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200648void acpi_fill_fadt(acpi_fadt_t *fadt)
649{
650 device_t dev = dev_find_slot(0, PCI_DEVFN(0x1f,0));
651 config_t *chip = dev->chip_info;
652 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
653 int c2_latency;
654
655 fadt->model = 1;
656
657 fadt->sci_int = 0x9;
658 fadt->smi_cmd = APM_CNT;
659 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
660 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
661 fadt->s4bios_req = 0x0;
662 fadt->pstate_cnt = 0;
663
664 fadt->pm1a_evt_blk = pmbase;
665 fadt->pm1b_evt_blk = 0x0;
666 fadt->pm1a_cnt_blk = pmbase + 0x4;
667 fadt->pm1b_cnt_blk = 0x0;
668 fadt->pm2_cnt_blk = pmbase + 0x50;
669 fadt->pm_tmr_blk = pmbase + 0x8;
670 fadt->gpe0_blk = pmbase + 0x20;
671 fadt->gpe1_blk = 0;
672
673 fadt->pm1_evt_len = 4;
674 fadt->pm1_cnt_len = 2;
675 fadt->pm2_cnt_len = 1;
676 fadt->pm_tmr_len = 4;
677 fadt->gpe0_blk_len = 16;
678 fadt->gpe1_blk_len = 0;
679 fadt->gpe1_base = 0;
680 fadt->cst_cnt = 0;
681 c2_latency = chip->c2_latency;
682 if (!c2_latency) {
683 c2_latency = 101; /* c2 unsupported */
684 }
685 fadt->p_lvl2_lat = c2_latency;
686 fadt->p_lvl3_lat = 87;
687 fadt->flush_size = 1024;
688 fadt->flush_stride = 16;
689 fadt->duty_offset = 1;
690 if (chip->p_cnt_throttling_supported) {
691 fadt->duty_width = 3;
692 } else {
693 fadt->duty_width = 0;
694 }
695 fadt->day_alrm = 0xd;
696 fadt->mon_alrm = 0x00;
697 fadt->century = 0x32;
698 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
699
700 fadt->flags = ACPI_FADT_WBINVD |
701 ACPI_FADT_C1_SUPPORTED |
702 ACPI_FADT_SLEEP_BUTTON |
703 ACPI_FADT_RESET_REGISTER |
704 ACPI_FADT_S4_RTC_WAKE |
705 ACPI_FADT_PLATFORM_CLOCK;
706 if (chip->docking_supported) {
707 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
708 }
709 if (c2_latency < 100) {
710 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
711 }
712
713 fadt->reset_reg.space_id = 1;
714 fadt->reset_reg.bit_width = 8;
715 fadt->reset_reg.bit_offset = 0;
716 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
717 fadt->reset_reg.addrl = 0xcf9;
718 fadt->reset_reg.addrh = 0;
719
720 fadt->reset_value = 6;
721
722 fadt->x_pm1a_evt_blk.space_id = 1;
723 fadt->x_pm1a_evt_blk.bit_width = 32;
724 fadt->x_pm1a_evt_blk.bit_offset = 0;
725 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
726 fadt->x_pm1a_evt_blk.addrl = pmbase;
727 fadt->x_pm1a_evt_blk.addrh = 0x0;
728
729 fadt->x_pm1b_evt_blk.space_id = 1;
730 fadt->x_pm1b_evt_blk.bit_width = 0;
731 fadt->x_pm1b_evt_blk.bit_offset = 0;
732 fadt->x_pm1b_evt_blk.access_size = 0;
733 fadt->x_pm1b_evt_blk.addrl = 0x0;
734 fadt->x_pm1b_evt_blk.addrh = 0x0;
735
736 fadt->x_pm1a_cnt_blk.space_id = 1;
737 fadt->x_pm1a_cnt_blk.bit_width = 16;
738 fadt->x_pm1a_cnt_blk.bit_offset = 0;
739 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
740 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
741 fadt->x_pm1a_cnt_blk.addrh = 0x0;
742
743 fadt->x_pm1b_cnt_blk.space_id = 1;
744 fadt->x_pm1b_cnt_blk.bit_width = 0;
745 fadt->x_pm1b_cnt_blk.bit_offset = 0;
746 fadt->x_pm1b_cnt_blk.access_size = 0;
747 fadt->x_pm1b_cnt_blk.addrl = 0x0;
748 fadt->x_pm1b_cnt_blk.addrh = 0x0;
749
750 fadt->x_pm2_cnt_blk.space_id = 1;
751 fadt->x_pm2_cnt_blk.bit_width = 8;
752 fadt->x_pm2_cnt_blk.bit_offset = 0;
753 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
754 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
755 fadt->x_pm2_cnt_blk.addrh = 0x0;
756
757 fadt->x_pm_tmr_blk.space_id = 1;
758 fadt->x_pm_tmr_blk.bit_width = 32;
759 fadt->x_pm_tmr_blk.bit_offset = 0;
760 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
761 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
762 fadt->x_pm_tmr_blk.addrh = 0x0;
763
764 fadt->x_gpe0_blk.space_id = 1;
765 fadt->x_gpe0_blk.bit_width = 128;
766 fadt->x_gpe0_blk.bit_offset = 0;
767 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
768 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
769 fadt->x_gpe0_blk.addrh = 0x0;
770
771 fadt->x_gpe1_blk.space_id = 1;
772 fadt->x_gpe1_blk.bit_width = 0;
773 fadt->x_gpe1_blk.bit_offset = 0;
774 fadt->x_gpe1_blk.access_size = 0;
775 fadt->x_gpe1_blk.addrl = 0x0;
776 fadt->x_gpe1_blk.addrh = 0x0;
777}
778
Kyösti Mälkki90993952018-05-01 19:36:25 +0300779static const char *lpc_acpi_name(const struct device *dev)
780{
781 return "LPCB";
782}
783
Alexander Couzens5eea4582015-04-12 22:18:55 +0200784static void southbridge_fill_ssdt(device_t device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100785{
786 device_t dev = dev_find_slot(0, PCI_DEVFN(0x1f,0));
787 config_t *chip = dev->chip_info;
788
789 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Kyösti Mälkki90993952018-05-01 19:36:25 +0300790 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100791}
792
Bill XIEd533b162017-08-22 16:26:22 +0800793static void lpc_final(struct device *dev)
794{
795 /* Call SMM finalize() handlers before resume */
796 if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER)) {
797 if (IS_ENABLED(CONFIG_INTEL_CHIPSET_LOCKDOWN) ||
798 acpi_is_wakeup_s3()) {
799 outb(APM_CNT_FINALIZE, APM_CNT);
800 }
801 }
802}
803
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100804static struct pci_operations pci_ops = {
805 .set_subsystem = set_subsystem,
806};
807
808static struct device_operations device_ops = {
809 .read_resources = pch_lpc_read_resources,
810 .set_resources = pci_dev_set_resources,
811 .enable_resources = pch_lpc_enable_resources,
Vladimir Serbinenko334fd8e2014-10-05 11:10:35 +0200812 .acpi_inject_dsdt_generator = southbridge_inject_dsdt,
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100813 .acpi_fill_ssdt_generator = southbridge_fill_ssdt,
Kyösti Mälkki90993952018-05-01 19:36:25 +0300814 .acpi_name = lpc_acpi_name,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200815 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100816 .init = lpc_init,
Bill XIEd533b162017-08-22 16:26:22 +0800817 .final = lpc_final,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100818 .enable = pch_lpc_enable,
Kyösti Mälkkid0e212c2015-02-26 20:47:47 +0200819 .scan_bus = scan_lpc_bus,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100820 .ops_pci = &pci_ops,
821};
822
823
Vladimir Serbinenkob7d87882014-02-19 22:01:35 +0100824static const unsigned short pci_device_ids[] = { 0x3b07, 0x3b09, 0 };
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100825
826static const struct pci_driver pch_lpc __pci_driver = {
827 .ops = &device_ops,
828 .vendor = PCI_VENDOR_ID_INTEL,
829 .devices = pci_device_ids,
830};