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