blob: 324438ec6bd6f5822e3c26d18652d6d3f1b9ded6 [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>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010030#include <elog.h>
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020031#include <arch/acpigen.h>
32#include <drivers/intel/gma/i915.h>
33#include <cbmem.h>
Vladimir Serbinenko7309c642014-10-05 11:07:33 +020034#include <string.h>
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +020035#include <cpu/x86/smm.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030036#include "chip.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
Vladimir Serbinenko46957052013-11-26 01:16:20 +010045typedef struct southbridge_intel_ibexpeak_config config_t;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010046
47/**
48 * Set miscellanous static southbridge features.
49 *
50 * @param dev PCI device with I/O APIC control registers
51 */
52static void pch_enable_ioapic(struct device *dev)
53{
54 u32 reg32;
55
56 /* Enable ACPI I/O range decode */
57 pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
58
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080059 set_ioapic_id(VIO_APIC_VADDR, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010060 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080061 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
62 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010063
64 /*
65 * Select Boot Configuration register (0x03) and
66 * use Processor System Bus (0x01) to deliver interrupts.
67 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080068 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010069}
70
71static void pch_enable_serial_irqs(struct device *dev)
72{
73 /* Set packet length and toggle silent mode bit for one frame. */
74 pci_write_config8(dev, SERIRQ_CNTL,
75 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080076#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010077 pci_write_config8(dev, SERIRQ_CNTL,
78 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
79#endif
80}
81
82/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
83 * 0x00 - 0000 = Reserved
84 * 0x01 - 0001 = Reserved
85 * 0x02 - 0010 = Reserved
86 * 0x03 - 0011 = IRQ3
87 * 0x04 - 0100 = IRQ4
88 * 0x05 - 0101 = IRQ5
89 * 0x06 - 0110 = IRQ6
90 * 0x07 - 0111 = IRQ7
91 * 0x08 - 1000 = Reserved
92 * 0x09 - 1001 = IRQ9
93 * 0x0A - 1010 = IRQ10
94 * 0x0B - 1011 = IRQ11
95 * 0x0C - 1100 = IRQ12
96 * 0x0D - 1101 = Reserved
97 * 0x0E - 1110 = IRQ14
98 * 0x0F - 1111 = IRQ15
99 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
100 * 0x80 - The PIRQ is not routed.
101 */
102
Elyes HAOUASbe841402018-05-13 13:40:39 +0200103static void pch_pirq_init(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100104{
Elyes HAOUASbe841402018-05-13 13:40:39 +0200105 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200106 /* Interrupt 11 is not used by legacy devices and so can always be used for
107 PCI interrupts. Full legacy IRQ routing is complicated and hard to
108 get right. Fortunately all modern OS use MSI and so it's not that big of
109 an issue anyway. Still we have to provide a reasonable default. Using
110 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
111 move it to any interrupt and others will just leave them at default.
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100112 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200113 const u8 pirq_routing = 11;
114
115 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
116 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
117 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
118 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
119
120 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
121 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
122 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
123 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100124
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200125 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200126 u8 int_pin=0;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100127
128 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
129 continue;
130
131 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
132
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200133 if (int_pin == 0)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100134 continue;
135
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200136 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100137 }
138}
139
Elyes HAOUASbe841402018-05-13 13:40:39 +0200140static void pch_gpi_routing(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100141{
142 /* Get the chip configuration */
143 config_t *config = dev->chip_info;
144 u32 reg32 = 0;
145
146 /* An array would be much nicer here, or some
147 * other method of doing this.
148 */
149 reg32 |= (config->gpi0_routing & 0x03) << 0;
150 reg32 |= (config->gpi1_routing & 0x03) << 2;
151 reg32 |= (config->gpi2_routing & 0x03) << 4;
152 reg32 |= (config->gpi3_routing & 0x03) << 6;
153 reg32 |= (config->gpi4_routing & 0x03) << 8;
154 reg32 |= (config->gpi5_routing & 0x03) << 10;
155 reg32 |= (config->gpi6_routing & 0x03) << 12;
156 reg32 |= (config->gpi7_routing & 0x03) << 14;
157 reg32 |= (config->gpi8_routing & 0x03) << 16;
158 reg32 |= (config->gpi9_routing & 0x03) << 18;
159 reg32 |= (config->gpi10_routing & 0x03) << 20;
160 reg32 |= (config->gpi11_routing & 0x03) << 22;
161 reg32 |= (config->gpi12_routing & 0x03) << 24;
162 reg32 |= (config->gpi13_routing & 0x03) << 26;
163 reg32 |= (config->gpi14_routing & 0x03) << 28;
164 reg32 |= (config->gpi15_routing & 0x03) << 30;
165
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200166 pci_write_config32(dev, GPIO_ROUT, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100167}
168
Elyes HAOUASbe841402018-05-13 13:40:39 +0200169static void pch_power_options(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100170{
171 u8 reg8;
172 u16 reg16, pmbase;
173 u32 reg32;
174 const char *state;
175 /* Get the chip configuration */
176 config_t *config = dev->chip_info;
177
Nico Huber9faae2b2018-11-14 00:00:35 +0100178 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100179 int nmi_option;
180
181 /* Which state do we want to goto after g3 (power restored)?
182 * 0 == S0 Full On
183 * 1 == S5 Soft Off
184 *
185 * If the option is not existent (Laptops), use Kconfig setting.
186 */
187 get_option(&pwr_on, "power_on_after_fail");
188
189 reg16 = pci_read_config16(dev, GEN_PMCON_3);
190 reg16 &= 0xfffe;
191 switch (pwr_on) {
192 case MAINBOARD_POWER_OFF:
193 reg16 |= 1;
194 state = "off";
195 break;
196 case MAINBOARD_POWER_ON:
197 reg16 &= ~1;
198 state = "on";
199 break;
200 case MAINBOARD_POWER_KEEP:
201 reg16 &= ~1;
202 state = "state keep";
203 break;
204 default:
205 state = "undefined";
206 }
207
208 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
209 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
210
211 reg16 &= ~(1 << 10);
212 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
213
214 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
215
216 pci_write_config16(dev, GEN_PMCON_3, reg16);
217 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
218
219 /* Set up NMI on errors. */
220 reg8 = inb(0x61);
221 reg8 &= 0x0f; /* Higher Nibble must be 0 */
222 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
223 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
224 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
225 outb(reg8, 0x61);
226
227 reg8 = inb(0x70);
228 nmi_option = NMI_OFF;
229 get_option(&nmi_option, "nmi");
230 if (nmi_option) {
231 printk(BIOS_INFO, "NMI sources enabled.\n");
232 reg8 &= ~(1 << 7); /* Set NMI. */
233 } else {
234 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200235 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100236 }
237 outb(reg8, 0x70);
238
239 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
240 reg16 = pci_read_config16(dev, GEN_PMCON_1);
241 reg16 &= ~(3 << 0); // SMI# rate 1 minute
242 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
243#if DEBUG_PERIODIC_SMIS
244 /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
245 * periodic SMIs.
246 */
247 reg16 |= (3 << 0); // Periodic SMI every 8s
248#endif
249 pci_write_config16(dev, GEN_PMCON_1, reg16);
250
251 // Set the board's GPI routing.
252 pch_gpi_routing(dev);
253
254 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
255
256 outl(config->gpe0_en, pmbase + GPE0_EN);
257 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
258
259 /* Set up power management block and determine sleep mode */
260 reg32 = inl(pmbase + 0x04); // PM1_CNT
261 reg32 &= ~(7 << 10); // SLP_TYP
262 reg32 |= (1 << 0); // SCI_EN
263 outl(reg32, pmbase + 0x04);
264
265 /* Clear magic status bits to prevent unexpected wake */
Angel Pons42b4e4e2019-09-18 10:58:53 +0200266 reg32 = RCBA32(PRSTS);
267 reg32 |= (1 << 5) | (1 << 4) | (1 << 0);
268 RCBA32(PRSTS) = reg32;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100269
Angel Pons42b4e4e2019-09-18 10:58:53 +0200270 /* FIXME: Does this even exist? */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100271 reg32 = RCBA32(0x3f02);
272 reg32 &= ~0xf;
273 RCBA32(0x3f02) = reg32;
274}
275
276static void pch_rtc_init(struct device *dev)
277{
278 u8 reg8;
279 int rtc_failed;
280
281 reg8 = pci_read_config8(dev, GEN_PMCON_3);
282 rtc_failed = reg8 & RTC_BATTERY_DEAD;
283 if (rtc_failed) {
284 reg8 &= ~RTC_BATTERY_DEAD;
285 pci_write_config8(dev, GEN_PMCON_3, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100286 elog_add_event(ELOG_TYPE_RTC_RESET);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100287 }
288 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
289
Gabe Blackb3f08c62014-04-30 17:12:25 -0700290 cmos_init(rtc_failed);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100291}
292
293static void mobile5_pm_init(struct device *dev)
294{
295 int i;
296
297 printk(BIOS_DEBUG, "Mobile 5 PM init\n");
298 pci_write_config8(dev, 0xa9, 0x47);
299
300 RCBA32 (0x1d44) = 0x00000000;
301 (void) RCBA32 (0x1d44);
302 RCBA32 (0x1d48) = 0x00030000;
303 (void) RCBA32 (0x1d48);
304 RCBA32 (0x1e80) = 0x000c0801;
305 (void) RCBA32 (0x1e80);
306 RCBA32 (0x1e84) = 0x000200f0;
307 (void) RCBA32 (0x1e84);
308
309 const u32 rcba2010[] =
310 {
311 /* 2010: */ 0x00188200, 0x14000016, 0xbc4abcb5, 0x00000000,
312 /* 2020: */ 0xf0c9605b, 0x13683040, 0x04c8f16e, 0x09e90170
313 };
Elyes HAOUAS035df002016-10-03 21:54:16 +0200314 for (i = 0; i < sizeof(rcba2010) / sizeof(rcba2010[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100315 {
316 RCBA32 (0x2010 + 4 * i) = rcba2010[i];
317 RCBA32 (0x2010 + 4 * i);
318 }
319
320 RCBA32 (0x2100) = 0x00000000;
321 (void) RCBA32 (0x2100);
322 RCBA32 (0x2104) = 0x00000757;
323 (void) RCBA32 (0x2104);
324 RCBA32 (0x2108) = 0x00170001;
325 (void) RCBA32 (0x2108);
326
327 RCBA32 (0x211c) = 0x00000000;
328 (void) RCBA32 (0x211c);
329 RCBA32 (0x2120) = 0x00010000;
330 (void) RCBA32 (0x2120);
331
332 RCBA32 (0x21fc) = 0x00000000;
333 (void) RCBA32 (0x21fc);
334 RCBA32 (0x2200) = 0x20000044;
335 (void) RCBA32 (0x2200);
336 RCBA32 (0x2204) = 0x00000001;
337 (void) RCBA32 (0x2204);
338 RCBA32 (0x2208) = 0x00003457;
339 (void) RCBA32 (0x2208);
340
341 const u32 rcba2210[] =
342 {
343 /* 2210 */ 0x00000000, 0x00000001, 0xa0fff210, 0x0000df00,
344 /* 2220 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
345 /* 2230 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
346 /* 2240 */ 0x00002301, 0x36000000, 0x00010107, 0x00160000,
347 /* 2250 */ 0x00001b01, 0x36000000, 0x00010107, 0x00160000,
348 /* 2260 */ 0x00000601, 0x16000000, 0x00010107, 0x00160000,
349 /* 2270 */ 0x00001c01, 0x16000000, 0x00010107, 0x00160000
350 };
351
Elyes HAOUAS035df002016-10-03 21:54:16 +0200352 for (i = 0; i < sizeof(rcba2210) / sizeof(rcba2210[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100353 {
354 RCBA32 (0x2210 + 4 * i) = rcba2210[i];
355 RCBA32 (0x2210 + 4 * i);
356 }
357
358 const u32 rcba2300[] =
359 {
360 /* 2300: */ 0x00000000, 0x40000000, 0x4646827b, 0x6e803131,
361 /* 2310: */ 0x32c77887, 0x00077733, 0x00007447, 0x00000040,
362 /* 2320: */ 0xcccc0cfc, 0x0fbb0fff
363 };
364
Elyes HAOUAS035df002016-10-03 21:54:16 +0200365 for (i = 0; i < sizeof(rcba2300) / sizeof(rcba2300[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100366 {
367 RCBA32 (0x2300 + 4 * i) = rcba2300[i];
368 RCBA32 (0x2300 + 4 * i);
369 }
370
371 RCBA32 (0x37fc) = 0x00000000;
372 (void) RCBA32 (0x37fc);
373 RCBA32 (0x3dfc) = 0x00000000;
374 (void) RCBA32 (0x3dfc);
375 RCBA32 (0x3e7c) = 0xffffffff;
376 (void) RCBA32 (0x3e7c);
377 RCBA32 (0x3efc) = 0x00000000;
378 (void) RCBA32 (0x3efc);
379 RCBA32 (0x3f00) = 0x0000010b;
380 (void) RCBA32 (0x3f00);
381}
382
383static void enable_hpet(void)
384{
385 u32 reg32;
386
387 /* Move HPET to default address 0xfed00000 and enable it */
388 reg32 = RCBA32(HPTC);
389 reg32 |= (1 << 7); // HPET Address Enable
390 reg32 &= ~(3 << 0);
391 RCBA32(HPTC) = reg32;
Arthur Heymans37e1d932019-10-02 14:33:34 +0200392 RCBA32(HPTC); /* Read back for it to work */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100393
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800394 write32((u32 *)0xfed00010, read32((u32 *)0xfed00010) | 1);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100395}
396
Elyes HAOUASbe841402018-05-13 13:40:39 +0200397static void enable_clock_gating(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100398{
399 u32 reg32;
400 u16 reg16;
401
402 RCBA32_AND_OR(0x2234, ~0UL, 0xf);
403
404 reg16 = pci_read_config16(dev, GEN_PMCON_1);
405 reg16 |= (1 << 2) | (1 << 11);
406 pci_write_config16(dev, GEN_PMCON_1, reg16);
407
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100408 reg32 = RCBA32(CG);
409 reg32 |= (1 << 31);
410 reg32 |= (1 << 29) | (1 << 28);
411 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
412 reg32 |= (1 << 16);
413 reg32 |= (1 << 17);
414 reg32 |= (1 << 18);
415 reg32 |= (1 << 22);
416 reg32 |= (1 << 23);
417 reg32 &= ~(1 << 20);
418 reg32 |= (1 << 19);
419 reg32 |= (1 << 0);
420 reg32 |= (0xf << 1);
421 RCBA32(CG) = reg32;
422
423 RCBA32_OR(0x38c0, 0x7);
424 RCBA32_OR(0x36d4, 0x6680c004);
425 RCBA32_OR(0x3564, 0x3);
426}
427
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200428static void pch_set_acpi_mode(void)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100429{
Julius Werner5d1f9a02019-03-07 17:07:26 -0800430 if (!acpi_is_wakeup_s3() && CONFIG(HAVE_SMI_HANDLER)) {
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100431 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200432 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100433 printk(BIOS_DEBUG, "done.\n");
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100434 }
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100435}
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100436
437static void pch_disable_smm_only_flashing(struct device *dev)
438{
439 u8 reg8;
440
441 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100442 reg8 = pci_read_config8(dev, BIOS_CNTL);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100443 reg8 &= ~(1 << 5);
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100444 pci_write_config8(dev, BIOS_CNTL, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100445}
446
447static void pch_fixups(struct device *dev)
448{
449 /*
450 * Enable DMI ASPM in the PCH
451 */
452 RCBA32_AND_OR(0x2304, ~(1 << 10), 0);
453 RCBA32_OR(0x21a4, (1 << 11)|(1 << 10));
454 RCBA32_OR(0x21a8, 0x3);
455}
456
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100457static void lpc_init(struct device *dev)
458{
459 printk(BIOS_DEBUG, "pch: lpc_init\n");
460
461 /* Set the value for PCI command register. */
462 pci_write_config16(dev, PCI_COMMAND, 0x000f);
463
464 /* IO APIC initialization. */
465 pch_enable_ioapic(dev);
466
467 pch_enable_serial_irqs(dev);
468
469 /* Setup the PIRQ. */
470 pch_pirq_init(dev);
471
472 /* Setup power options. */
473 pch_power_options(dev);
474
475 /* Initialize power management */
Arthur Heymansd0310fa2019-10-02 00:21:01 +0200476 mobile5_pm_init(dev);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100477
478 /* Set the state of the GPIO lines. */
479 //gpio_init(dev);
480
481 /* Initialize the real time clock. */
482 pch_rtc_init(dev);
483
484 /* Initialize ISA DMA. */
485 isa_dma_init();
486
487 /* Initialize the High Precision Event Timers, if present. */
488 enable_hpet();
489
490 /* Initialize Clock Gating */
491 enable_clock_gating(dev);
492
493 setup_i8259();
494
495 /* The OS should do this? */
496 /* Interrupt 9 should be level triggered (SCI) */
497 i8259_configure_irq_trigger(9, 1);
498
499 pch_disable_smm_only_flashing(dev);
500
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200501 pch_set_acpi_mode();
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100502
503 pch_fixups(dev);
504}
505
Elyes HAOUASbe841402018-05-13 13:40:39 +0200506static void pch_lpc_read_resources(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100507{
508 struct resource *res;
509 config_t *config = dev->chip_info;
510 u8 io_index = 0;
511
512 /* Get the normal PCI resources of this device. */
513 pci_dev_read_resources(dev);
514
515 /* Add an extra subtractive resource for both memory and I/O. */
516 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
517 res->base = 0;
518 res->size = 0x1000;
519 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
520 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
521
522 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
523 res->base = 0xff800000;
524 res->size = 0x00800000; /* 8 MB for flash */
525 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
526 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
527
528 res = new_resource(dev, 3); /* IOAPIC */
529 res->base = IO_APIC_ADDR;
530 res->size = 0x00001000;
531 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
532
533 /* Set PCH IO decode ranges if required.*/
534 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
535 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
536 res->base = config->gen1_dec & 0xFFFC;
537 res->size = (config->gen1_dec >> 16) & 0xFC;
538 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
539 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
540 }
541
542 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
543 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
544 res->base = config->gen2_dec & 0xFFFC;
545 res->size = (config->gen2_dec >> 16) & 0xFC;
546 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
547 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
548 }
549
550 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
551 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
552 res->base = config->gen3_dec & 0xFFFC;
553 res->size = (config->gen3_dec >> 16) & 0xFC;
554 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
555 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
556 }
557
558 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
559 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
560 res->base = config->gen4_dec & 0xFFFC;
561 res->size = (config->gen4_dec >> 16) & 0xFC;
562 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
563 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
564 }
565}
566
Elyes HAOUASbe841402018-05-13 13:40:39 +0200567static void pch_lpc_enable(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100568{
569 /* Enable PCH Display Port */
570 RCBA16(DISPBDF) = 0x0010;
571 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
572
573 pch_enable(dev);
574}
575
Elyes HAOUASbe841402018-05-13 13:40:39 +0200576static void southbridge_inject_dsdt(struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200577{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200578 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200579
580 if (gnvs) {
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100581 const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
Elyes HAOUAS035df002016-10-03 21:54:16 +0200582 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200583
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200584 acpi_create_gnvs(gnvs);
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200585
586 gnvs->apic = 1;
587 gnvs->mpen = 1; /* Enable Multi Processing */
588 gnvs->pcnt = dev_count_cpu();
Nico Huber744d6bd2019-01-12 14:58:20 +0100589
590 if (gfx) {
591 gnvs->ndid = gfx->ndid;
592 memcpy(gnvs->did, gfx->did, sizeof(gnvs->did));
593 }
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200594
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200595 /* And tell SMI about it */
596 smm_setup_structures(gnvs, NULL, NULL);
597
598 /* Add it to SSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100599 acpigen_write_scope("\\");
600 acpigen_write_name_dword("NVSA", (u32) gnvs);
601 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200602 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200603}
604
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200605void acpi_fill_fadt(acpi_fadt_t *fadt)
606{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300607 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200608 config_t *chip = dev->chip_info;
609 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
610 int c2_latency;
611
Elyes HAOUAS0d4de2a2019-02-28 13:04:29 +0100612 fadt->reserved = 0;
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200613
614 fadt->sci_int = 0x9;
615 fadt->smi_cmd = APM_CNT;
616 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
617 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
618 fadt->s4bios_req = 0x0;
619 fadt->pstate_cnt = 0;
620
621 fadt->pm1a_evt_blk = pmbase;
622 fadt->pm1b_evt_blk = 0x0;
623 fadt->pm1a_cnt_blk = pmbase + 0x4;
624 fadt->pm1b_cnt_blk = 0x0;
625 fadt->pm2_cnt_blk = pmbase + 0x50;
626 fadt->pm_tmr_blk = pmbase + 0x8;
627 fadt->gpe0_blk = pmbase + 0x20;
628 fadt->gpe1_blk = 0;
629
630 fadt->pm1_evt_len = 4;
631 fadt->pm1_cnt_len = 2;
632 fadt->pm2_cnt_len = 1;
633 fadt->pm_tmr_len = 4;
634 fadt->gpe0_blk_len = 16;
635 fadt->gpe1_blk_len = 0;
636 fadt->gpe1_base = 0;
637 fadt->cst_cnt = 0;
638 c2_latency = chip->c2_latency;
639 if (!c2_latency) {
640 c2_latency = 101; /* c2 unsupported */
641 }
642 fadt->p_lvl2_lat = c2_latency;
643 fadt->p_lvl3_lat = 87;
644 fadt->flush_size = 1024;
645 fadt->flush_stride = 16;
Patrick Rudolphb30a47b2019-07-15 18:04:23 +0200646 /* P_CNT not supported */
647 fadt->duty_offset = 0;
648 fadt->duty_width = 0;
649
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200650 fadt->day_alrm = 0xd;
651 fadt->mon_alrm = 0x00;
652 fadt->century = 0x32;
653 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
654
655 fadt->flags = ACPI_FADT_WBINVD |
656 ACPI_FADT_C1_SUPPORTED |
657 ACPI_FADT_SLEEP_BUTTON |
658 ACPI_FADT_RESET_REGISTER |
659 ACPI_FADT_S4_RTC_WAKE |
660 ACPI_FADT_PLATFORM_CLOCK;
661 if (chip->docking_supported) {
662 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
663 }
664 if (c2_latency < 100) {
665 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
666 }
667
668 fadt->reset_reg.space_id = 1;
669 fadt->reset_reg.bit_width = 8;
670 fadt->reset_reg.bit_offset = 0;
671 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
672 fadt->reset_reg.addrl = 0xcf9;
673 fadt->reset_reg.addrh = 0;
674
675 fadt->reset_value = 6;
676
677 fadt->x_pm1a_evt_blk.space_id = 1;
678 fadt->x_pm1a_evt_blk.bit_width = 32;
679 fadt->x_pm1a_evt_blk.bit_offset = 0;
680 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
681 fadt->x_pm1a_evt_blk.addrl = pmbase;
682 fadt->x_pm1a_evt_blk.addrh = 0x0;
683
684 fadt->x_pm1b_evt_blk.space_id = 1;
685 fadt->x_pm1b_evt_blk.bit_width = 0;
686 fadt->x_pm1b_evt_blk.bit_offset = 0;
687 fadt->x_pm1b_evt_blk.access_size = 0;
688 fadt->x_pm1b_evt_blk.addrl = 0x0;
689 fadt->x_pm1b_evt_blk.addrh = 0x0;
690
691 fadt->x_pm1a_cnt_blk.space_id = 1;
692 fadt->x_pm1a_cnt_blk.bit_width = 16;
693 fadt->x_pm1a_cnt_blk.bit_offset = 0;
694 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
695 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
696 fadt->x_pm1a_cnt_blk.addrh = 0x0;
697
698 fadt->x_pm1b_cnt_blk.space_id = 1;
699 fadt->x_pm1b_cnt_blk.bit_width = 0;
700 fadt->x_pm1b_cnt_blk.bit_offset = 0;
701 fadt->x_pm1b_cnt_blk.access_size = 0;
702 fadt->x_pm1b_cnt_blk.addrl = 0x0;
703 fadt->x_pm1b_cnt_blk.addrh = 0x0;
704
705 fadt->x_pm2_cnt_blk.space_id = 1;
706 fadt->x_pm2_cnt_blk.bit_width = 8;
707 fadt->x_pm2_cnt_blk.bit_offset = 0;
708 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
709 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
710 fadt->x_pm2_cnt_blk.addrh = 0x0;
711
712 fadt->x_pm_tmr_blk.space_id = 1;
713 fadt->x_pm_tmr_blk.bit_width = 32;
714 fadt->x_pm_tmr_blk.bit_offset = 0;
715 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
716 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
717 fadt->x_pm_tmr_blk.addrh = 0x0;
718
719 fadt->x_gpe0_blk.space_id = 1;
720 fadt->x_gpe0_blk.bit_width = 128;
721 fadt->x_gpe0_blk.bit_offset = 0;
722 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
723 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
724 fadt->x_gpe0_blk.addrh = 0x0;
725
726 fadt->x_gpe1_blk.space_id = 1;
727 fadt->x_gpe1_blk.bit_width = 0;
728 fadt->x_gpe1_blk.bit_offset = 0;
729 fadt->x_gpe1_blk.access_size = 0;
730 fadt->x_gpe1_blk.addrl = 0x0;
731 fadt->x_gpe1_blk.addrh = 0x0;
732}
733
Kyösti Mälkki90993952018-05-01 19:36:25 +0300734static const char *lpc_acpi_name(const struct device *dev)
735{
736 return "LPCB";
737}
738
Elyes HAOUASbe841402018-05-13 13:40:39 +0200739static void southbridge_fill_ssdt(struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100740{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300741 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100742 config_t *chip = dev->chip_info;
743
744 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Kyösti Mälkki90993952018-05-01 19:36:25 +0300745 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100746}
747
Bill XIEd533b162017-08-22 16:26:22 +0800748static void lpc_final(struct device *dev)
749{
Arthur Heymansaadd1d02019-05-28 13:39:20 +0200750 spi_finalize_ops();
751
Bill XIEd533b162017-08-22 16:26:22 +0800752 /* Call SMM finalize() handlers before resume */
Julius Wernercd49cce2019-03-05 16:53:33 -0800753 if (CONFIG(HAVE_SMI_HANDLER)) {
754 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
Bill XIEd533b162017-08-22 16:26:22 +0800755 acpi_is_wakeup_s3()) {
756 outb(APM_CNT_FINALIZE, APM_CNT);
757 }
758 }
759}
760
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100761static struct pci_operations pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530762 .set_subsystem = pci_dev_set_subsystem,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100763};
764
765static struct device_operations device_ops = {
766 .read_resources = pch_lpc_read_resources,
767 .set_resources = pci_dev_set_resources,
Arthur Heymans3b452e02019-10-03 09:16:10 +0200768 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenko334fd8e2014-10-05 11:10:35 +0200769 .acpi_inject_dsdt_generator = southbridge_inject_dsdt,
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100770 .acpi_fill_ssdt_generator = southbridge_fill_ssdt,
Kyösti Mälkki90993952018-05-01 19:36:25 +0300771 .acpi_name = lpc_acpi_name,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200772 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100773 .init = lpc_init,
Bill XIEd533b162017-08-22 16:26:22 +0800774 .final = lpc_final,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100775 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100776 .scan_bus = scan_static_bus,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100777 .ops_pci = &pci_ops,
778};
779
780
Vladimir Serbinenkob7d87882014-02-19 22:01:35 +0100781static const unsigned short pci_device_ids[] = { 0x3b07, 0x3b09, 0 };
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100782
783static const struct pci_driver pch_lpc __pci_driver = {
784 .ops = &device_ops,
785 .vendor = PCI_VENDOR_ID_INTEL,
786 .devices = pci_device_ids,
787};