blob: 851f4f51eafcd189641e157e91c820037b957375 [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>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020022#include <option.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010023#include <pc80/mc146818rtc.h>
24#include <pc80/isa-dma.h>
25#include <pc80/i8259.h>
26#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020027#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020028#include <device/pci_ops.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010029#include <arch/ioapic.h>
30#include <arch/acpi.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
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 */
Angel Pons42b4e4e2019-09-18 10:58:53 +0200267 reg32 = RCBA32(PRSTS);
268 reg32 |= (1 << 5) | (1 << 4) | (1 << 0);
269 RCBA32(PRSTS) = reg32;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100270
Angel Pons42b4e4e2019-09-18 10:58:53 +0200271 /* FIXME: Does this even exist? */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100272 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);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100287 elog_add_event(ELOG_TYPE_RTC_RESET);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100288 }
289 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
290
Gabe Blackb3f08c62014-04-30 17:12:25 -0700291 cmos_init(rtc_failed);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100292}
293
294static void mobile5_pm_init(struct device *dev)
295{
296 int i;
297
298 printk(BIOS_DEBUG, "Mobile 5 PM init\n");
299 pci_write_config8(dev, 0xa9, 0x47);
300
301 RCBA32 (0x1d44) = 0x00000000;
302 (void) RCBA32 (0x1d44);
303 RCBA32 (0x1d48) = 0x00030000;
304 (void) RCBA32 (0x1d48);
305 RCBA32 (0x1e80) = 0x000c0801;
306 (void) RCBA32 (0x1e80);
307 RCBA32 (0x1e84) = 0x000200f0;
308 (void) RCBA32 (0x1e84);
309
310 const u32 rcba2010[] =
311 {
312 /* 2010: */ 0x00188200, 0x14000016, 0xbc4abcb5, 0x00000000,
313 /* 2020: */ 0xf0c9605b, 0x13683040, 0x04c8f16e, 0x09e90170
314 };
Elyes HAOUAS035df002016-10-03 21:54:16 +0200315 for (i = 0; i < sizeof(rcba2010) / sizeof(rcba2010[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100316 {
317 RCBA32 (0x2010 + 4 * i) = rcba2010[i];
318 RCBA32 (0x2010 + 4 * i);
319 }
320
321 RCBA32 (0x2100) = 0x00000000;
322 (void) RCBA32 (0x2100);
323 RCBA32 (0x2104) = 0x00000757;
324 (void) RCBA32 (0x2104);
325 RCBA32 (0x2108) = 0x00170001;
326 (void) RCBA32 (0x2108);
327
328 RCBA32 (0x211c) = 0x00000000;
329 (void) RCBA32 (0x211c);
330 RCBA32 (0x2120) = 0x00010000;
331 (void) RCBA32 (0x2120);
332
333 RCBA32 (0x21fc) = 0x00000000;
334 (void) RCBA32 (0x21fc);
335 RCBA32 (0x2200) = 0x20000044;
336 (void) RCBA32 (0x2200);
337 RCBA32 (0x2204) = 0x00000001;
338 (void) RCBA32 (0x2204);
339 RCBA32 (0x2208) = 0x00003457;
340 (void) RCBA32 (0x2208);
341
342 const u32 rcba2210[] =
343 {
344 /* 2210 */ 0x00000000, 0x00000001, 0xa0fff210, 0x0000df00,
345 /* 2220 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
346 /* 2230 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
347 /* 2240 */ 0x00002301, 0x36000000, 0x00010107, 0x00160000,
348 /* 2250 */ 0x00001b01, 0x36000000, 0x00010107, 0x00160000,
349 /* 2260 */ 0x00000601, 0x16000000, 0x00010107, 0x00160000,
350 /* 2270 */ 0x00001c01, 0x16000000, 0x00010107, 0x00160000
351 };
352
Elyes HAOUAS035df002016-10-03 21:54:16 +0200353 for (i = 0; i < sizeof(rcba2210) / sizeof(rcba2210[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100354 {
355 RCBA32 (0x2210 + 4 * i) = rcba2210[i];
356 RCBA32 (0x2210 + 4 * i);
357 }
358
359 const u32 rcba2300[] =
360 {
361 /* 2300: */ 0x00000000, 0x40000000, 0x4646827b, 0x6e803131,
362 /* 2310: */ 0x32c77887, 0x00077733, 0x00007447, 0x00000040,
363 /* 2320: */ 0xcccc0cfc, 0x0fbb0fff
364 };
365
Elyes HAOUAS035df002016-10-03 21:54:16 +0200366 for (i = 0; i < sizeof(rcba2300) / sizeof(rcba2300[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100367 {
368 RCBA32 (0x2300 + 4 * i) = rcba2300[i];
369 RCBA32 (0x2300 + 4 * i);
370 }
371
372 RCBA32 (0x37fc) = 0x00000000;
373 (void) RCBA32 (0x37fc);
374 RCBA32 (0x3dfc) = 0x00000000;
375 (void) RCBA32 (0x3dfc);
376 RCBA32 (0x3e7c) = 0xffffffff;
377 (void) RCBA32 (0x3e7c);
378 RCBA32 (0x3efc) = 0x00000000;
379 (void) RCBA32 (0x3efc);
380 RCBA32 (0x3f00) = 0x0000010b;
381 (void) RCBA32 (0x3f00);
382}
383
384static void enable_hpet(void)
385{
386 u32 reg32;
387
388 /* Move HPET to default address 0xfed00000 and enable it */
389 reg32 = RCBA32(HPTC);
390 reg32 |= (1 << 7); // HPET Address Enable
391 reg32 &= ~(3 << 0);
392 RCBA32(HPTC) = reg32;
Arthur Heymans37e1d932019-10-02 14:33:34 +0200393 RCBA32(HPTC); /* Read back for it to work */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100394
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
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100409 reg32 = RCBA32(CG);
410 reg32 |= (1 << 31);
411 reg32 |= (1 << 29) | (1 << 28);
412 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
413 reg32 |= (1 << 16);
414 reg32 |= (1 << 17);
415 reg32 |= (1 << 18);
416 reg32 |= (1 << 22);
417 reg32 |= (1 << 23);
418 reg32 &= ~(1 << 20);
419 reg32 |= (1 << 19);
420 reg32 |= (1 << 0);
421 reg32 |= (0xf << 1);
422 RCBA32(CG) = reg32;
423
424 RCBA32_OR(0x38c0, 0x7);
425 RCBA32_OR(0x36d4, 0x6680c004);
426 RCBA32_OR(0x3564, 0x3);
427}
428
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200429static void pch_set_acpi_mode(void)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100430{
Julius Werner5d1f9a02019-03-07 17:07:26 -0800431 if (!acpi_is_wakeup_s3() && CONFIG(HAVE_SMI_HANDLER)) {
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100432 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200433 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100434 printk(BIOS_DEBUG, "done.\n");
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100435 }
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100436}
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100437
438static void pch_disable_smm_only_flashing(struct device *dev)
439{
440 u8 reg8;
441
442 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100443 reg8 = pci_read_config8(dev, BIOS_CNTL);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100444 reg8 &= ~(1 << 5);
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100445 pci_write_config8(dev, BIOS_CNTL, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100446}
447
448static void pch_fixups(struct device *dev)
449{
450 /*
451 * Enable DMI ASPM in the PCH
452 */
453 RCBA32_AND_OR(0x2304, ~(1 << 10), 0);
454 RCBA32_OR(0x21a4, (1 << 11)|(1 << 10));
455 RCBA32_OR(0x21a8, 0x3);
456}
457
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100458static void lpc_init(struct device *dev)
459{
460 printk(BIOS_DEBUG, "pch: lpc_init\n");
461
462 /* Set the value for PCI command register. */
463 pci_write_config16(dev, PCI_COMMAND, 0x000f);
464
465 /* IO APIC initialization. */
466 pch_enable_ioapic(dev);
467
468 pch_enable_serial_irqs(dev);
469
470 /* Setup the PIRQ. */
471 pch_pirq_init(dev);
472
473 /* Setup power options. */
474 pch_power_options(dev);
475
476 /* Initialize power management */
Arthur Heymansd0310fa2019-10-02 00:21:01 +0200477 mobile5_pm_init(dev);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100478
479 /* Set the state of the GPIO lines. */
480 //gpio_init(dev);
481
482 /* Initialize the real time clock. */
483 pch_rtc_init(dev);
484
485 /* Initialize ISA DMA. */
486 isa_dma_init();
487
488 /* Initialize the High Precision Event Timers, if present. */
489 enable_hpet();
490
491 /* Initialize Clock Gating */
492 enable_clock_gating(dev);
493
494 setup_i8259();
495
496 /* The OS should do this? */
497 /* Interrupt 9 should be level triggered (SCI) */
498 i8259_configure_irq_trigger(9, 1);
499
500 pch_disable_smm_only_flashing(dev);
501
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200502 pch_set_acpi_mode();
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100503
504 pch_fixups(dev);
505}
506
Elyes HAOUASbe841402018-05-13 13:40:39 +0200507static void pch_lpc_read_resources(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100508{
509 struct resource *res;
510 config_t *config = dev->chip_info;
511 u8 io_index = 0;
512
513 /* Get the normal PCI resources of this device. */
514 pci_dev_read_resources(dev);
515
516 /* Add an extra subtractive resource for both memory and I/O. */
517 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
518 res->base = 0;
519 res->size = 0x1000;
520 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
521 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
522
523 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
524 res->base = 0xff800000;
525 res->size = 0x00800000; /* 8 MB for flash */
526 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
527 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
528
529 res = new_resource(dev, 3); /* IOAPIC */
530 res->base = IO_APIC_ADDR;
531 res->size = 0x00001000;
532 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
533
534 /* Set PCH IO decode ranges if required.*/
535 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
536 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
537 res->base = config->gen1_dec & 0xFFFC;
538 res->size = (config->gen1_dec >> 16) & 0xFC;
539 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
540 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
541 }
542
543 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
544 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
545 res->base = config->gen2_dec & 0xFFFC;
546 res->size = (config->gen2_dec >> 16) & 0xFC;
547 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
548 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
549 }
550
551 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
552 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
553 res->base = config->gen3_dec & 0xFFFC;
554 res->size = (config->gen3_dec >> 16) & 0xFC;
555 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
556 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
557 }
558
559 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
560 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
561 res->base = config->gen4_dec & 0xFFFC;
562 res->size = (config->gen4_dec >> 16) & 0xFC;
563 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
564 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
565 }
566}
567
Elyes HAOUASbe841402018-05-13 13:40:39 +0200568static void pch_lpc_enable(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100569{
570 /* Enable PCH Display Port */
571 RCBA16(DISPBDF) = 0x0010;
572 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
573
574 pch_enable(dev);
575}
576
Elyes HAOUASbe841402018-05-13 13:40:39 +0200577static void southbridge_inject_dsdt(struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200578{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200579 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200580
581 if (gnvs) {
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100582 const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
Elyes HAOUAS035df002016-10-03 21:54:16 +0200583 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200584
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200585 acpi_create_gnvs(gnvs);
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200586
587 gnvs->apic = 1;
588 gnvs->mpen = 1; /* Enable Multi Processing */
589 gnvs->pcnt = dev_count_cpu();
Nico Huber744d6bd2019-01-12 14:58:20 +0100590
591 if (gfx) {
592 gnvs->ndid = gfx->ndid;
593 memcpy(gnvs->did, gfx->did, sizeof(gnvs->did));
594 }
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200595
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200596 /* And tell SMI about it */
597 smm_setup_structures(gnvs, NULL, NULL);
598
599 /* Add it to SSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100600 acpigen_write_scope("\\");
601 acpigen_write_name_dword("NVSA", (u32) gnvs);
602 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200603 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200604}
605
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200606void acpi_fill_fadt(acpi_fadt_t *fadt)
607{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300608 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200609 config_t *chip = dev->chip_info;
610 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
611 int c2_latency;
612
Elyes HAOUAS0d4de2a2019-02-28 13:04:29 +0100613 fadt->reserved = 0;
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200614
615 fadt->sci_int = 0x9;
616 fadt->smi_cmd = APM_CNT;
617 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
618 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
619 fadt->s4bios_req = 0x0;
620 fadt->pstate_cnt = 0;
621
622 fadt->pm1a_evt_blk = pmbase;
623 fadt->pm1b_evt_blk = 0x0;
624 fadt->pm1a_cnt_blk = pmbase + 0x4;
625 fadt->pm1b_cnt_blk = 0x0;
626 fadt->pm2_cnt_blk = pmbase + 0x50;
627 fadt->pm_tmr_blk = pmbase + 0x8;
628 fadt->gpe0_blk = pmbase + 0x20;
629 fadt->gpe1_blk = 0;
630
631 fadt->pm1_evt_len = 4;
632 fadt->pm1_cnt_len = 2;
633 fadt->pm2_cnt_len = 1;
634 fadt->pm_tmr_len = 4;
635 fadt->gpe0_blk_len = 16;
636 fadt->gpe1_blk_len = 0;
637 fadt->gpe1_base = 0;
638 fadt->cst_cnt = 0;
639 c2_latency = chip->c2_latency;
640 if (!c2_latency) {
641 c2_latency = 101; /* c2 unsupported */
642 }
643 fadt->p_lvl2_lat = c2_latency;
644 fadt->p_lvl3_lat = 87;
645 fadt->flush_size = 1024;
646 fadt->flush_stride = 16;
Patrick Rudolphb30a47b2019-07-15 18:04:23 +0200647 /* P_CNT not supported */
648 fadt->duty_offset = 0;
649 fadt->duty_width = 0;
650
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200651 fadt->day_alrm = 0xd;
652 fadt->mon_alrm = 0x00;
653 fadt->century = 0x32;
654 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
655
656 fadt->flags = ACPI_FADT_WBINVD |
657 ACPI_FADT_C1_SUPPORTED |
658 ACPI_FADT_SLEEP_BUTTON |
659 ACPI_FADT_RESET_REGISTER |
660 ACPI_FADT_S4_RTC_WAKE |
661 ACPI_FADT_PLATFORM_CLOCK;
662 if (chip->docking_supported) {
663 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
664 }
665 if (c2_latency < 100) {
666 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
667 }
668
669 fadt->reset_reg.space_id = 1;
670 fadt->reset_reg.bit_width = 8;
671 fadt->reset_reg.bit_offset = 0;
672 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
673 fadt->reset_reg.addrl = 0xcf9;
674 fadt->reset_reg.addrh = 0;
675
676 fadt->reset_value = 6;
677
678 fadt->x_pm1a_evt_blk.space_id = 1;
679 fadt->x_pm1a_evt_blk.bit_width = 32;
680 fadt->x_pm1a_evt_blk.bit_offset = 0;
681 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
682 fadt->x_pm1a_evt_blk.addrl = pmbase;
683 fadt->x_pm1a_evt_blk.addrh = 0x0;
684
685 fadt->x_pm1b_evt_blk.space_id = 1;
686 fadt->x_pm1b_evt_blk.bit_width = 0;
687 fadt->x_pm1b_evt_blk.bit_offset = 0;
688 fadt->x_pm1b_evt_blk.access_size = 0;
689 fadt->x_pm1b_evt_blk.addrl = 0x0;
690 fadt->x_pm1b_evt_blk.addrh = 0x0;
691
692 fadt->x_pm1a_cnt_blk.space_id = 1;
693 fadt->x_pm1a_cnt_blk.bit_width = 16;
694 fadt->x_pm1a_cnt_blk.bit_offset = 0;
695 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
696 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
697 fadt->x_pm1a_cnt_blk.addrh = 0x0;
698
699 fadt->x_pm1b_cnt_blk.space_id = 1;
700 fadt->x_pm1b_cnt_blk.bit_width = 0;
701 fadt->x_pm1b_cnt_blk.bit_offset = 0;
702 fadt->x_pm1b_cnt_blk.access_size = 0;
703 fadt->x_pm1b_cnt_blk.addrl = 0x0;
704 fadt->x_pm1b_cnt_blk.addrh = 0x0;
705
706 fadt->x_pm2_cnt_blk.space_id = 1;
707 fadt->x_pm2_cnt_blk.bit_width = 8;
708 fadt->x_pm2_cnt_blk.bit_offset = 0;
709 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
710 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
711 fadt->x_pm2_cnt_blk.addrh = 0x0;
712
713 fadt->x_pm_tmr_blk.space_id = 1;
714 fadt->x_pm_tmr_blk.bit_width = 32;
715 fadt->x_pm_tmr_blk.bit_offset = 0;
716 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
717 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
718 fadt->x_pm_tmr_blk.addrh = 0x0;
719
720 fadt->x_gpe0_blk.space_id = 1;
721 fadt->x_gpe0_blk.bit_width = 128;
722 fadt->x_gpe0_blk.bit_offset = 0;
723 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
724 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
725 fadt->x_gpe0_blk.addrh = 0x0;
726
727 fadt->x_gpe1_blk.space_id = 1;
728 fadt->x_gpe1_blk.bit_width = 0;
729 fadt->x_gpe1_blk.bit_offset = 0;
730 fadt->x_gpe1_blk.access_size = 0;
731 fadt->x_gpe1_blk.addrl = 0x0;
732 fadt->x_gpe1_blk.addrh = 0x0;
733}
734
Kyösti Mälkki90993952018-05-01 19:36:25 +0300735static const char *lpc_acpi_name(const struct device *dev)
736{
737 return "LPCB";
738}
739
Elyes HAOUASbe841402018-05-13 13:40:39 +0200740static void southbridge_fill_ssdt(struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100741{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300742 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100743 config_t *chip = dev->chip_info;
744
745 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Kyösti Mälkki90993952018-05-01 19:36:25 +0300746 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100747}
748
Bill XIEd533b162017-08-22 16:26:22 +0800749static void lpc_final(struct device *dev)
750{
Arthur Heymansaadd1d02019-05-28 13:39:20 +0200751 spi_finalize_ops();
752
Bill XIEd533b162017-08-22 16:26:22 +0800753 /* Call SMM finalize() handlers before resume */
Julius Wernercd49cce2019-03-05 16:53:33 -0800754 if (CONFIG(HAVE_SMI_HANDLER)) {
755 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
Bill XIEd533b162017-08-22 16:26:22 +0800756 acpi_is_wakeup_s3()) {
757 outb(APM_CNT_FINALIZE, APM_CNT);
758 }
759 }
760}
761
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100762static struct pci_operations pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530763 .set_subsystem = pci_dev_set_subsystem,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100764};
765
766static struct device_operations device_ops = {
767 .read_resources = pch_lpc_read_resources,
768 .set_resources = pci_dev_set_resources,
Arthur Heymans3b452e02019-10-03 09:16:10 +0200769 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko334fd8e2014-10-05 11:10:35 +0200770 .acpi_inject_dsdt_generator = southbridge_inject_dsdt,
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100771 .acpi_fill_ssdt_generator = southbridge_fill_ssdt,
Kyösti Mälkki90993952018-05-01 19:36:25 +0300772 .acpi_name = lpc_acpi_name,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200773 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100774 .init = lpc_init,
Bill XIEd533b162017-08-22 16:26:22 +0800775 .final = lpc_final,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100776 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100777 .scan_bus = scan_static_bus,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100778 .ops_pci = &pci_ops,
779};
780
781
Vladimir Serbinenkob7d87882014-02-19 22:01:35 +0100782static const unsigned short pci_device_ids[] = { 0x3b07, 0x3b09, 0 };
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100783
784static const struct pci_driver pch_lpc __pci_driver = {
785 .ops = &device_ops,
786 .vendor = PCI_VENDOR_ID_INTEL,
787 .devices = pci_device_ids,
788};