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