blob: e433530bae465ca2c81bbdcd29351ef46ea9988b [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>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030037#include "chip.h"
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010038#include "pch.h"
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020039#include "nvs.h"
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010040#include <southbridge/intel/common/pciehp.h>
Kyösti Mälkki90993952018-05-01 19:36:25 +030041#include <southbridge/intel/common/acpi_pirq_gen.h>
Arthur Heymansaadd1d02019-05-28 13:39:20 +020042#include <southbridge/intel/common/spi.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010043
44#define NMI_OFF 0
45
46#define ENABLE_ACPI_MODE_IN_COREBOOT 0
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010047
Vladimir Serbinenko46957052013-11-26 01:16:20 +010048typedef struct southbridge_intel_ibexpeak_config config_t;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010049
50/**
51 * Set miscellanous static southbridge features.
52 *
53 * @param dev PCI device with I/O APIC control registers
54 */
55static void pch_enable_ioapic(struct device *dev)
56{
57 u32 reg32;
58
59 /* Enable ACPI I/O range decode */
60 pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
61
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080062 set_ioapic_id(VIO_APIC_VADDR, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010063 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080064 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
65 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010066
67 /*
68 * Select Boot Configuration register (0x03) and
69 * use Processor System Bus (0x01) to deliver interrupts.
70 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080071 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010072}
73
74static void pch_enable_serial_irqs(struct device *dev)
75{
76 /* Set packet length and toggle silent mode bit for one frame. */
77 pci_write_config8(dev, SERIRQ_CNTL,
78 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080079#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010080 pci_write_config8(dev, SERIRQ_CNTL,
81 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
82#endif
83}
84
85/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
86 * 0x00 - 0000 = Reserved
87 * 0x01 - 0001 = Reserved
88 * 0x02 - 0010 = Reserved
89 * 0x03 - 0011 = IRQ3
90 * 0x04 - 0100 = IRQ4
91 * 0x05 - 0101 = IRQ5
92 * 0x06 - 0110 = IRQ6
93 * 0x07 - 0111 = IRQ7
94 * 0x08 - 1000 = Reserved
95 * 0x09 - 1001 = IRQ9
96 * 0x0A - 1010 = IRQ10
97 * 0x0B - 1011 = IRQ11
98 * 0x0C - 1100 = IRQ12
99 * 0x0D - 1101 = Reserved
100 * 0x0E - 1110 = IRQ14
101 * 0x0F - 1111 = IRQ15
102 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
103 * 0x80 - The PIRQ is not routed.
104 */
105
Elyes HAOUASbe841402018-05-13 13:40:39 +0200106static void pch_pirq_init(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100107{
Elyes HAOUASbe841402018-05-13 13:40:39 +0200108 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200109 /* Interrupt 11 is not used by legacy devices and so can always be used for
110 PCI interrupts. Full legacy IRQ routing is complicated and hard to
111 get right. Fortunately all modern OS use MSI and so it's not that big of
112 an issue anyway. Still we have to provide a reasonable default. Using
113 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
114 move it to any interrupt and others will just leave them at default.
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100115 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200116 const u8 pirq_routing = 11;
117
118 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
119 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
120 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
121 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
122
123 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
124 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
125 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
126 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100127
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200128 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200129 u8 int_pin=0;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100130
131 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
132 continue;
133
134 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
135
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200136 if (int_pin == 0)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100137 continue;
138
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200139 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100140 }
141}
142
Elyes HAOUASbe841402018-05-13 13:40:39 +0200143static void pch_gpi_routing(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100144{
145 /* Get the chip configuration */
146 config_t *config = dev->chip_info;
147 u32 reg32 = 0;
148
149 /* An array would be much nicer here, or some
150 * other method of doing this.
151 */
152 reg32 |= (config->gpi0_routing & 0x03) << 0;
153 reg32 |= (config->gpi1_routing & 0x03) << 2;
154 reg32 |= (config->gpi2_routing & 0x03) << 4;
155 reg32 |= (config->gpi3_routing & 0x03) << 6;
156 reg32 |= (config->gpi4_routing & 0x03) << 8;
157 reg32 |= (config->gpi5_routing & 0x03) << 10;
158 reg32 |= (config->gpi6_routing & 0x03) << 12;
159 reg32 |= (config->gpi7_routing & 0x03) << 14;
160 reg32 |= (config->gpi8_routing & 0x03) << 16;
161 reg32 |= (config->gpi9_routing & 0x03) << 18;
162 reg32 |= (config->gpi10_routing & 0x03) << 20;
163 reg32 |= (config->gpi11_routing & 0x03) << 22;
164 reg32 |= (config->gpi12_routing & 0x03) << 24;
165 reg32 |= (config->gpi13_routing & 0x03) << 26;
166 reg32 |= (config->gpi14_routing & 0x03) << 28;
167 reg32 |= (config->gpi15_routing & 0x03) << 30;
168
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200169 pci_write_config32(dev, GPIO_ROUT, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100170}
171
Elyes HAOUASbe841402018-05-13 13:40:39 +0200172static void pch_power_options(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100173{
174 u8 reg8;
175 u16 reg16, pmbase;
176 u32 reg32;
177 const char *state;
178 /* Get the chip configuration */
179 config_t *config = dev->chip_info;
180
Nico Huber9faae2b2018-11-14 00:00:35 +0100181 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100182 int nmi_option;
183
184 /* Which state do we want to goto after g3 (power restored)?
185 * 0 == S0 Full On
186 * 1 == S5 Soft Off
187 *
188 * If the option is not existent (Laptops), use Kconfig setting.
189 */
190 get_option(&pwr_on, "power_on_after_fail");
191
192 reg16 = pci_read_config16(dev, GEN_PMCON_3);
193 reg16 &= 0xfffe;
194 switch (pwr_on) {
195 case MAINBOARD_POWER_OFF:
196 reg16 |= 1;
197 state = "off";
198 break;
199 case MAINBOARD_POWER_ON:
200 reg16 &= ~1;
201 state = "on";
202 break;
203 case MAINBOARD_POWER_KEEP:
204 reg16 &= ~1;
205 state = "state keep";
206 break;
207 default:
208 state = "undefined";
209 }
210
211 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
212 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
213
214 reg16 &= ~(1 << 10);
215 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
216
217 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
218
219 pci_write_config16(dev, GEN_PMCON_3, reg16);
220 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
221
222 /* Set up NMI on errors. */
223 reg8 = inb(0x61);
224 reg8 &= 0x0f; /* Higher Nibble must be 0 */
225 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
226 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
227 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
228 outb(reg8, 0x61);
229
230 reg8 = inb(0x70);
231 nmi_option = NMI_OFF;
232 get_option(&nmi_option, "nmi");
233 if (nmi_option) {
234 printk(BIOS_INFO, "NMI sources enabled.\n");
235 reg8 &= ~(1 << 7); /* Set NMI. */
236 } else {
237 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200238 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100239 }
240 outb(reg8, 0x70);
241
242 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
243 reg16 = pci_read_config16(dev, GEN_PMCON_1);
244 reg16 &= ~(3 << 0); // SMI# rate 1 minute
245 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
246#if DEBUG_PERIODIC_SMIS
247 /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
248 * periodic SMIs.
249 */
250 reg16 |= (3 << 0); // Periodic SMI every 8s
251#endif
252 pci_write_config16(dev, GEN_PMCON_1, reg16);
253
254 // Set the board's GPI routing.
255 pch_gpi_routing(dev);
256
257 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
258
259 outl(config->gpe0_en, pmbase + GPE0_EN);
260 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
261
262 /* Set up power management block and determine sleep mode */
263 reg32 = inl(pmbase + 0x04); // PM1_CNT
264 reg32 &= ~(7 << 10); // SLP_TYP
265 reg32 |= (1 << 0); // SCI_EN
266 outl(reg32, pmbase + 0x04);
267
268 /* Clear magic status bits to prevent unexpected wake */
Angel Pons42b4e4e2019-09-18 10:58:53 +0200269 reg32 = RCBA32(PRSTS);
270 reg32 |= (1 << 5) | (1 << 4) | (1 << 0);
271 RCBA32(PRSTS) = reg32;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100272
Angel Pons42b4e4e2019-09-18 10:58:53 +0200273 /* FIXME: Does this even exist? */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100274 reg32 = RCBA32(0x3f02);
275 reg32 &= ~0xf;
276 RCBA32(0x3f02) = reg32;
277}
278
279static void pch_rtc_init(struct device *dev)
280{
281 u8 reg8;
282 int rtc_failed;
283
284 reg8 = pci_read_config8(dev, GEN_PMCON_3);
285 rtc_failed = reg8 & RTC_BATTERY_DEAD;
286 if (rtc_failed) {
287 reg8 &= ~RTC_BATTERY_DEAD;
288 pci_write_config8(dev, GEN_PMCON_3, reg8);
Julius Wernercd49cce2019-03-05 16:53:33 -0800289#if CONFIG(ELOG)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100290 elog_add_event(ELOG_TYPE_RTC_RESET);
291#endif
292 }
293 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
294
Gabe Blackb3f08c62014-04-30 17:12:25 -0700295 cmos_init(rtc_failed);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100296}
297
298static void mobile5_pm_init(struct device *dev)
299{
300 int i;
301
302 printk(BIOS_DEBUG, "Mobile 5 PM init\n");
303 pci_write_config8(dev, 0xa9, 0x47);
304
305 RCBA32 (0x1d44) = 0x00000000;
306 (void) RCBA32 (0x1d44);
307 RCBA32 (0x1d48) = 0x00030000;
308 (void) RCBA32 (0x1d48);
309 RCBA32 (0x1e80) = 0x000c0801;
310 (void) RCBA32 (0x1e80);
311 RCBA32 (0x1e84) = 0x000200f0;
312 (void) RCBA32 (0x1e84);
313
314 const u32 rcba2010[] =
315 {
316 /* 2010: */ 0x00188200, 0x14000016, 0xbc4abcb5, 0x00000000,
317 /* 2020: */ 0xf0c9605b, 0x13683040, 0x04c8f16e, 0x09e90170
318 };
Elyes HAOUAS035df002016-10-03 21:54:16 +0200319 for (i = 0; i < sizeof(rcba2010) / sizeof(rcba2010[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100320 {
321 RCBA32 (0x2010 + 4 * i) = rcba2010[i];
322 RCBA32 (0x2010 + 4 * i);
323 }
324
325 RCBA32 (0x2100) = 0x00000000;
326 (void) RCBA32 (0x2100);
327 RCBA32 (0x2104) = 0x00000757;
328 (void) RCBA32 (0x2104);
329 RCBA32 (0x2108) = 0x00170001;
330 (void) RCBA32 (0x2108);
331
332 RCBA32 (0x211c) = 0x00000000;
333 (void) RCBA32 (0x211c);
334 RCBA32 (0x2120) = 0x00010000;
335 (void) RCBA32 (0x2120);
336
337 RCBA32 (0x21fc) = 0x00000000;
338 (void) RCBA32 (0x21fc);
339 RCBA32 (0x2200) = 0x20000044;
340 (void) RCBA32 (0x2200);
341 RCBA32 (0x2204) = 0x00000001;
342 (void) RCBA32 (0x2204);
343 RCBA32 (0x2208) = 0x00003457;
344 (void) RCBA32 (0x2208);
345
346 const u32 rcba2210[] =
347 {
348 /* 2210 */ 0x00000000, 0x00000001, 0xa0fff210, 0x0000df00,
349 /* 2220 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
350 /* 2230 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
351 /* 2240 */ 0x00002301, 0x36000000, 0x00010107, 0x00160000,
352 /* 2250 */ 0x00001b01, 0x36000000, 0x00010107, 0x00160000,
353 /* 2260 */ 0x00000601, 0x16000000, 0x00010107, 0x00160000,
354 /* 2270 */ 0x00001c01, 0x16000000, 0x00010107, 0x00160000
355 };
356
Elyes HAOUAS035df002016-10-03 21:54:16 +0200357 for (i = 0; i < sizeof(rcba2210) / sizeof(rcba2210[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100358 {
359 RCBA32 (0x2210 + 4 * i) = rcba2210[i];
360 RCBA32 (0x2210 + 4 * i);
361 }
362
363 const u32 rcba2300[] =
364 {
365 /* 2300: */ 0x00000000, 0x40000000, 0x4646827b, 0x6e803131,
366 /* 2310: */ 0x32c77887, 0x00077733, 0x00007447, 0x00000040,
367 /* 2320: */ 0xcccc0cfc, 0x0fbb0fff
368 };
369
Elyes HAOUAS035df002016-10-03 21:54:16 +0200370 for (i = 0; i < sizeof(rcba2300) / sizeof(rcba2300[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100371 {
372 RCBA32 (0x2300 + 4 * i) = rcba2300[i];
373 RCBA32 (0x2300 + 4 * i);
374 }
375
376 RCBA32 (0x37fc) = 0x00000000;
377 (void) RCBA32 (0x37fc);
378 RCBA32 (0x3dfc) = 0x00000000;
379 (void) RCBA32 (0x3dfc);
380 RCBA32 (0x3e7c) = 0xffffffff;
381 (void) RCBA32 (0x3e7c);
382 RCBA32 (0x3efc) = 0x00000000;
383 (void) RCBA32 (0x3efc);
384 RCBA32 (0x3f00) = 0x0000010b;
385 (void) RCBA32 (0x3f00);
386}
387
388static void enable_hpet(void)
389{
390 u32 reg32;
391
392 /* Move HPET to default address 0xfed00000 and enable it */
393 reg32 = RCBA32(HPTC);
394 reg32 |= (1 << 7); // HPET Address Enable
395 reg32 &= ~(3 << 0);
396 RCBA32(HPTC) = reg32;
Arthur Heymans37e1d932019-10-02 14:33:34 +0200397 RCBA32(HPTC); /* Read back for it to work */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100398
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800399 write32((u32 *)0xfed00010, read32((u32 *)0xfed00010) | 1);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100400}
401
Elyes HAOUASbe841402018-05-13 13:40:39 +0200402static void enable_clock_gating(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100403{
404 u32 reg32;
405 u16 reg16;
406
407 RCBA32_AND_OR(0x2234, ~0UL, 0xf);
408
409 reg16 = pci_read_config16(dev, GEN_PMCON_1);
410 reg16 |= (1 << 2) | (1 << 11);
411 pci_write_config16(dev, GEN_PMCON_1, reg16);
412
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100413 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{
Julius Werner5d1f9a02019-03-07 17:07:26 -0800435 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... ");
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100453 reg8 = pci_read_config8(dev, BIOS_CNTL);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100454 reg8 &= ~(1 << 5);
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100455 pci_write_config8(dev, BIOS_CNTL, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100456}
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 */
Arthur Heymansd0310fa2019-10-02 00:21:01 +0200499 mobile5_pm_init(dev);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100500
501 /* Set the state of the GPIO lines. */
502 //gpio_init(dev);
503
504 /* Initialize the real time clock. */
505 pch_rtc_init(dev);
506
507 /* Initialize ISA DMA. */
508 isa_dma_init();
509
510 /* Initialize the High Precision Event Timers, if present. */
511 enable_hpet();
512
513 /* Initialize Clock Gating */
514 enable_clock_gating(dev);
515
516 setup_i8259();
517
518 /* The OS should do this? */
519 /* Interrupt 9 should be level triggered (SCI) */
520 i8259_configure_irq_trigger(9, 1);
521
522 pch_disable_smm_only_flashing(dev);
523
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200524 pch_set_acpi_mode();
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100525
526 pch_fixups(dev);
527}
528
Elyes HAOUASbe841402018-05-13 13:40:39 +0200529static void pch_lpc_read_resources(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100530{
531 struct resource *res;
532 config_t *config = dev->chip_info;
533 u8 io_index = 0;
534
535 /* Get the normal PCI resources of this device. */
536 pci_dev_read_resources(dev);
537
538 /* Add an extra subtractive resource for both memory and I/O. */
539 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
540 res->base = 0;
541 res->size = 0x1000;
542 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
543 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
544
545 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
546 res->base = 0xff800000;
547 res->size = 0x00800000; /* 8 MB for flash */
548 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
549 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
550
551 res = new_resource(dev, 3); /* IOAPIC */
552 res->base = IO_APIC_ADDR;
553 res->size = 0x00001000;
554 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
555
556 /* Set PCH IO decode ranges if required.*/
557 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
558 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
559 res->base = config->gen1_dec & 0xFFFC;
560 res->size = (config->gen1_dec >> 16) & 0xFC;
561 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
562 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
563 }
564
565 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
566 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
567 res->base = config->gen2_dec & 0xFFFC;
568 res->size = (config->gen2_dec >> 16) & 0xFC;
569 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
570 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
571 }
572
573 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
574 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
575 res->base = config->gen3_dec & 0xFFFC;
576 res->size = (config->gen3_dec >> 16) & 0xFC;
577 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
578 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
579 }
580
581 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
582 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
583 res->base = config->gen4_dec & 0xFFFC;
584 res->size = (config->gen4_dec >> 16) & 0xFC;
585 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
586 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
587 }
588}
589
Elyes HAOUASbe841402018-05-13 13:40:39 +0200590static void pch_lpc_enable_resources(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100591{
592 pch_decode_init(dev);
593 return pci_dev_enable_resources(dev);
594}
595
Elyes HAOUASbe841402018-05-13 13:40:39 +0200596static void pch_lpc_enable(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100597{
598 /* Enable PCH Display Port */
599 RCBA16(DISPBDF) = 0x0010;
600 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
601
602 pch_enable(dev);
603}
604
Elyes HAOUASbe841402018-05-13 13:40:39 +0200605static void southbridge_inject_dsdt(struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200606{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200607 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200608
609 if (gnvs) {
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100610 const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
Elyes HAOUAS035df002016-10-03 21:54:16 +0200611 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200612
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200613 acpi_create_gnvs(gnvs);
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200614
615 gnvs->apic = 1;
616 gnvs->mpen = 1; /* Enable Multi Processing */
617 gnvs->pcnt = dev_count_cpu();
Nico Huber744d6bd2019-01-12 14:58:20 +0100618
619 if (gfx) {
620 gnvs->ndid = gfx->ndid;
621 memcpy(gnvs->did, gfx->did, sizeof(gnvs->did));
622 }
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200623
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200624 /* And tell SMI about it */
625 smm_setup_structures(gnvs, NULL, NULL);
626
627 /* Add it to SSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100628 acpigen_write_scope("\\");
629 acpigen_write_name_dword("NVSA", (u32) gnvs);
630 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200631 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200632}
633
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200634void acpi_fill_fadt(acpi_fadt_t *fadt)
635{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300636 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200637 config_t *chip = dev->chip_info;
638 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
639 int c2_latency;
640
Elyes HAOUAS0d4de2a2019-02-28 13:04:29 +0100641 fadt->reserved = 0;
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200642
643 fadt->sci_int = 0x9;
644 fadt->smi_cmd = APM_CNT;
645 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
646 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
647 fadt->s4bios_req = 0x0;
648 fadt->pstate_cnt = 0;
649
650 fadt->pm1a_evt_blk = pmbase;
651 fadt->pm1b_evt_blk = 0x0;
652 fadt->pm1a_cnt_blk = pmbase + 0x4;
653 fadt->pm1b_cnt_blk = 0x0;
654 fadt->pm2_cnt_blk = pmbase + 0x50;
655 fadt->pm_tmr_blk = pmbase + 0x8;
656 fadt->gpe0_blk = pmbase + 0x20;
657 fadt->gpe1_blk = 0;
658
659 fadt->pm1_evt_len = 4;
660 fadt->pm1_cnt_len = 2;
661 fadt->pm2_cnt_len = 1;
662 fadt->pm_tmr_len = 4;
663 fadt->gpe0_blk_len = 16;
664 fadt->gpe1_blk_len = 0;
665 fadt->gpe1_base = 0;
666 fadt->cst_cnt = 0;
667 c2_latency = chip->c2_latency;
668 if (!c2_latency) {
669 c2_latency = 101; /* c2 unsupported */
670 }
671 fadt->p_lvl2_lat = c2_latency;
672 fadt->p_lvl3_lat = 87;
673 fadt->flush_size = 1024;
674 fadt->flush_stride = 16;
Patrick Rudolphb30a47b2019-07-15 18:04:23 +0200675 /* P_CNT not supported */
676 fadt->duty_offset = 0;
677 fadt->duty_width = 0;
678
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200679 fadt->day_alrm = 0xd;
680 fadt->mon_alrm = 0x00;
681 fadt->century = 0x32;
682 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
683
684 fadt->flags = ACPI_FADT_WBINVD |
685 ACPI_FADT_C1_SUPPORTED |
686 ACPI_FADT_SLEEP_BUTTON |
687 ACPI_FADT_RESET_REGISTER |
688 ACPI_FADT_S4_RTC_WAKE |
689 ACPI_FADT_PLATFORM_CLOCK;
690 if (chip->docking_supported) {
691 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
692 }
693 if (c2_latency < 100) {
694 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
695 }
696
697 fadt->reset_reg.space_id = 1;
698 fadt->reset_reg.bit_width = 8;
699 fadt->reset_reg.bit_offset = 0;
700 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
701 fadt->reset_reg.addrl = 0xcf9;
702 fadt->reset_reg.addrh = 0;
703
704 fadt->reset_value = 6;
705
706 fadt->x_pm1a_evt_blk.space_id = 1;
707 fadt->x_pm1a_evt_blk.bit_width = 32;
708 fadt->x_pm1a_evt_blk.bit_offset = 0;
709 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
710 fadt->x_pm1a_evt_blk.addrl = pmbase;
711 fadt->x_pm1a_evt_blk.addrh = 0x0;
712
713 fadt->x_pm1b_evt_blk.space_id = 1;
714 fadt->x_pm1b_evt_blk.bit_width = 0;
715 fadt->x_pm1b_evt_blk.bit_offset = 0;
716 fadt->x_pm1b_evt_blk.access_size = 0;
717 fadt->x_pm1b_evt_blk.addrl = 0x0;
718 fadt->x_pm1b_evt_blk.addrh = 0x0;
719
720 fadt->x_pm1a_cnt_blk.space_id = 1;
721 fadt->x_pm1a_cnt_blk.bit_width = 16;
722 fadt->x_pm1a_cnt_blk.bit_offset = 0;
723 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
724 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
725 fadt->x_pm1a_cnt_blk.addrh = 0x0;
726
727 fadt->x_pm1b_cnt_blk.space_id = 1;
728 fadt->x_pm1b_cnt_blk.bit_width = 0;
729 fadt->x_pm1b_cnt_blk.bit_offset = 0;
730 fadt->x_pm1b_cnt_blk.access_size = 0;
731 fadt->x_pm1b_cnt_blk.addrl = 0x0;
732 fadt->x_pm1b_cnt_blk.addrh = 0x0;
733
734 fadt->x_pm2_cnt_blk.space_id = 1;
735 fadt->x_pm2_cnt_blk.bit_width = 8;
736 fadt->x_pm2_cnt_blk.bit_offset = 0;
737 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
738 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
739 fadt->x_pm2_cnt_blk.addrh = 0x0;
740
741 fadt->x_pm_tmr_blk.space_id = 1;
742 fadt->x_pm_tmr_blk.bit_width = 32;
743 fadt->x_pm_tmr_blk.bit_offset = 0;
744 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
745 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
746 fadt->x_pm_tmr_blk.addrh = 0x0;
747
748 fadt->x_gpe0_blk.space_id = 1;
749 fadt->x_gpe0_blk.bit_width = 128;
750 fadt->x_gpe0_blk.bit_offset = 0;
751 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
752 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
753 fadt->x_gpe0_blk.addrh = 0x0;
754
755 fadt->x_gpe1_blk.space_id = 1;
756 fadt->x_gpe1_blk.bit_width = 0;
757 fadt->x_gpe1_blk.bit_offset = 0;
758 fadt->x_gpe1_blk.access_size = 0;
759 fadt->x_gpe1_blk.addrl = 0x0;
760 fadt->x_gpe1_blk.addrh = 0x0;
761}
762
Kyösti Mälkki90993952018-05-01 19:36:25 +0300763static const char *lpc_acpi_name(const struct device *dev)
764{
765 return "LPCB";
766}
767
Elyes HAOUASbe841402018-05-13 13:40:39 +0200768static void southbridge_fill_ssdt(struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100769{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300770 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100771 config_t *chip = dev->chip_info;
772
773 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Kyösti Mälkki90993952018-05-01 19:36:25 +0300774 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100775}
776
Bill XIEd533b162017-08-22 16:26:22 +0800777static void lpc_final(struct device *dev)
778{
Arthur Heymansaadd1d02019-05-28 13:39:20 +0200779 spi_finalize_ops();
780
Bill XIEd533b162017-08-22 16:26:22 +0800781 /* Call SMM finalize() handlers before resume */
Julius Wernercd49cce2019-03-05 16:53:33 -0800782 if (CONFIG(HAVE_SMI_HANDLER)) {
783 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
Bill XIEd533b162017-08-22 16:26:22 +0800784 acpi_is_wakeup_s3()) {
785 outb(APM_CNT_FINALIZE, APM_CNT);
786 }
787 }
788}
789
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100790static struct pci_operations pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530791 .set_subsystem = pci_dev_set_subsystem,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100792};
793
794static struct device_operations device_ops = {
795 .read_resources = pch_lpc_read_resources,
796 .set_resources = pci_dev_set_resources,
797 .enable_resources = pch_lpc_enable_resources,
Vladimir Serbinenko334fd8e2014-10-05 11:10:35 +0200798 .acpi_inject_dsdt_generator = southbridge_inject_dsdt,
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100799 .acpi_fill_ssdt_generator = southbridge_fill_ssdt,
Kyösti Mälkki90993952018-05-01 19:36:25 +0300800 .acpi_name = lpc_acpi_name,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200801 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100802 .init = lpc_init,
Bill XIEd533b162017-08-22 16:26:22 +0800803 .final = lpc_final,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100804 .enable = pch_lpc_enable,
Kyösti Mälkkid0e212c2015-02-26 20:47:47 +0200805 .scan_bus = scan_lpc_bus,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100806 .ops_pci = &pci_ops,
807};
808
809
Vladimir Serbinenkob7d87882014-02-19 22:01:35 +0100810static const unsigned short pci_device_ids[] = { 0x3b07, 0x3b09, 0 };
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100811
812static const struct pci_driver pch_lpc __pci_driver = {
813 .ops = &device_ops,
814 .vendor = PCI_VENDOR_ID_INTEL,
815 .devices = pci_device_ids,
816};