blob: 5f7631322b26c61ac211305811f8cb03b76675b0 [file] [log] [blame]
Vladimir Serbinenko888d5592013-11-13 17:53:38 +01001/*
2 * This file is part of the coreboot project.
3 *
Vladimir Serbinenko888d5592013-11-13 17:53:38 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; version 2 of
8 * the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010014 */
15
16#include <console/console.h>
17#include <device/device.h>
18#include <device/pci.h>
19#include <device/pci_ids.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020020#include <option.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010021#include <pc80/mc146818rtc.h>
22#include <pc80/isa-dma.h>
23#include <pc80/i8259.h>
24#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020025#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020026#include <device/pci_ops.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010027#include <arch/ioapic.h>
28#include <arch/acpi.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010029#include <elog.h>
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020030#include <arch/acpigen.h>
31#include <drivers/intel/gma/i915.h>
32#include <cbmem.h>
Vladimir Serbinenko7309c642014-10-05 11:07:33 +020033#include <string.h>
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +020034#include <cpu/x86/smm.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030035#include "chip.h"
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010036#include "pch.h"
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020037#include "nvs.h"
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010038#include <southbridge/intel/common/pciehp.h>
Kyösti Mälkki90993952018-05-01 19:36:25 +030039#include <southbridge/intel/common/acpi_pirq_gen.h>
Arthur Heymansaadd1d02019-05-28 13:39:20 +020040#include <southbridge/intel/common/spi.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010041
42#define NMI_OFF 0
43
Vladimir Serbinenko46957052013-11-26 01:16:20 +010044typedef struct southbridge_intel_ibexpeak_config config_t;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010045
46/**
47 * Set miscellanous static southbridge features.
48 *
49 * @param dev PCI device with I/O APIC control registers
50 */
51static void pch_enable_ioapic(struct device *dev)
52{
53 u32 reg32;
54
55 /* Enable ACPI I/O range decode */
56 pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
57
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080058 set_ioapic_id(VIO_APIC_VADDR, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010059 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080060 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
61 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010062
63 /*
64 * Select Boot Configuration register (0x03) and
65 * use Processor System Bus (0x01) to deliver interrupts.
66 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080067 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010068}
69
70static void pch_enable_serial_irqs(struct device *dev)
71{
72 /* Set packet length and toggle silent mode bit for one frame. */
73 pci_write_config8(dev, SERIRQ_CNTL,
74 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080075#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010076 pci_write_config8(dev, SERIRQ_CNTL,
77 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
78#endif
79}
80
81/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
82 * 0x00 - 0000 = Reserved
83 * 0x01 - 0001 = Reserved
84 * 0x02 - 0010 = Reserved
85 * 0x03 - 0011 = IRQ3
86 * 0x04 - 0100 = IRQ4
87 * 0x05 - 0101 = IRQ5
88 * 0x06 - 0110 = IRQ6
89 * 0x07 - 0111 = IRQ7
90 * 0x08 - 1000 = Reserved
91 * 0x09 - 1001 = IRQ9
92 * 0x0A - 1010 = IRQ10
93 * 0x0B - 1011 = IRQ11
94 * 0x0C - 1100 = IRQ12
95 * 0x0D - 1101 = Reserved
96 * 0x0E - 1110 = IRQ14
97 * 0x0F - 1111 = IRQ15
98 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
99 * 0x80 - The PIRQ is not routed.
100 */
101
Elyes HAOUASbe841402018-05-13 13:40:39 +0200102static void pch_pirq_init(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100103{
Elyes HAOUASbe841402018-05-13 13:40:39 +0200104 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200105 /* Interrupt 11 is not used by legacy devices and so can always be used for
106 PCI interrupts. Full legacy IRQ routing is complicated and hard to
107 get right. Fortunately all modern OS use MSI and so it's not that big of
108 an issue anyway. Still we have to provide a reasonable default. Using
109 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
110 move it to any interrupt and others will just leave them at default.
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100111 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200112 const u8 pirq_routing = 11;
113
114 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
115 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
116 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
117 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
118
119 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
120 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
121 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
122 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100123
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200124 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200125 u8 int_pin=0;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100126
127 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
128 continue;
129
130 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
131
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200132 if (int_pin == 0)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100133 continue;
134
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200135 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100136 }
137}
138
Elyes HAOUASbe841402018-05-13 13:40:39 +0200139static void pch_gpi_routing(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100140{
141 /* Get the chip configuration */
142 config_t *config = dev->chip_info;
143 u32 reg32 = 0;
144
145 /* An array would be much nicer here, or some
146 * other method of doing this.
147 */
148 reg32 |= (config->gpi0_routing & 0x03) << 0;
149 reg32 |= (config->gpi1_routing & 0x03) << 2;
150 reg32 |= (config->gpi2_routing & 0x03) << 4;
151 reg32 |= (config->gpi3_routing & 0x03) << 6;
152 reg32 |= (config->gpi4_routing & 0x03) << 8;
153 reg32 |= (config->gpi5_routing & 0x03) << 10;
154 reg32 |= (config->gpi6_routing & 0x03) << 12;
155 reg32 |= (config->gpi7_routing & 0x03) << 14;
156 reg32 |= (config->gpi8_routing & 0x03) << 16;
157 reg32 |= (config->gpi9_routing & 0x03) << 18;
158 reg32 |= (config->gpi10_routing & 0x03) << 20;
159 reg32 |= (config->gpi11_routing & 0x03) << 22;
160 reg32 |= (config->gpi12_routing & 0x03) << 24;
161 reg32 |= (config->gpi13_routing & 0x03) << 26;
162 reg32 |= (config->gpi14_routing & 0x03) << 28;
163 reg32 |= (config->gpi15_routing & 0x03) << 30;
164
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200165 pci_write_config32(dev, GPIO_ROUT, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100166}
167
Elyes HAOUASbe841402018-05-13 13:40:39 +0200168static void pch_power_options(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100169{
170 u8 reg8;
171 u16 reg16, pmbase;
172 u32 reg32;
173 const char *state;
174 /* Get the chip configuration */
175 config_t *config = dev->chip_info;
176
Nico Huber9faae2b2018-11-14 00:00:35 +0100177 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100178 int nmi_option;
179
180 /* Which state do we want to goto after g3 (power restored)?
181 * 0 == S0 Full On
182 * 1 == S5 Soft Off
183 *
184 * If the option is not existent (Laptops), use Kconfig setting.
185 */
186 get_option(&pwr_on, "power_on_after_fail");
187
188 reg16 = pci_read_config16(dev, GEN_PMCON_3);
189 reg16 &= 0xfffe;
190 switch (pwr_on) {
191 case MAINBOARD_POWER_OFF:
192 reg16 |= 1;
193 state = "off";
194 break;
195 case MAINBOARD_POWER_ON:
196 reg16 &= ~1;
197 state = "on";
198 break;
199 case MAINBOARD_POWER_KEEP:
200 reg16 &= ~1;
201 state = "state keep";
202 break;
203 default:
204 state = "undefined";
205 }
206
207 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
208 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
209
210 reg16 &= ~(1 << 10);
211 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
212
213 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
214
215 pci_write_config16(dev, GEN_PMCON_3, reg16);
216 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
217
218 /* Set up NMI on errors. */
219 reg8 = inb(0x61);
220 reg8 &= 0x0f; /* Higher Nibble must be 0 */
221 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
222 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
223 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
224 outb(reg8, 0x61);
225
226 reg8 = inb(0x70);
227 nmi_option = NMI_OFF;
228 get_option(&nmi_option, "nmi");
229 if (nmi_option) {
230 printk(BIOS_INFO, "NMI sources enabled.\n");
231 reg8 &= ~(1 << 7); /* Set NMI. */
232 } else {
233 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200234 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100235 }
236 outb(reg8, 0x70);
237
238 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
239 reg16 = pci_read_config16(dev, GEN_PMCON_1);
240 reg16 &= ~(3 << 0); // SMI# rate 1 minute
241 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
242#if DEBUG_PERIODIC_SMIS
243 /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
244 * periodic SMIs.
245 */
246 reg16 |= (3 << 0); // Periodic SMI every 8s
247#endif
248 pci_write_config16(dev, GEN_PMCON_1, reg16);
249
250 // Set the board's GPI routing.
251 pch_gpi_routing(dev);
252
253 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
254
255 outl(config->gpe0_en, pmbase + GPE0_EN);
256 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
257
258 /* Set up power management block and determine sleep mode */
259 reg32 = inl(pmbase + 0x04); // PM1_CNT
260 reg32 &= ~(7 << 10); // SLP_TYP
261 reg32 |= (1 << 0); // SCI_EN
262 outl(reg32, pmbase + 0x04);
263
264 /* Clear magic status bits to prevent unexpected wake */
Angel Pons42b4e4e2019-09-18 10:58:53 +0200265 reg32 = RCBA32(PRSTS);
266 reg32 |= (1 << 5) | (1 << 4) | (1 << 0);
267 RCBA32(PRSTS) = reg32;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100268
Angel Pons42b4e4e2019-09-18 10:58:53 +0200269 /* FIXME: Does this even exist? */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100270 reg32 = RCBA32(0x3f02);
271 reg32 &= ~0xf;
272 RCBA32(0x3f02) = reg32;
273}
274
275static void pch_rtc_init(struct device *dev)
276{
277 u8 reg8;
278 int rtc_failed;
279
280 reg8 = pci_read_config8(dev, GEN_PMCON_3);
281 rtc_failed = reg8 & RTC_BATTERY_DEAD;
282 if (rtc_failed) {
283 reg8 &= ~RTC_BATTERY_DEAD;
284 pci_write_config8(dev, GEN_PMCON_3, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100285 elog_add_event(ELOG_TYPE_RTC_RESET);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100286 }
287 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
288
Gabe Blackb3f08c62014-04-30 17:12:25 -0700289 cmos_init(rtc_failed);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100290}
291
292static void mobile5_pm_init(struct device *dev)
293{
294 int i;
295
296 printk(BIOS_DEBUG, "Mobile 5 PM init\n");
297 pci_write_config8(dev, 0xa9, 0x47);
298
299 RCBA32 (0x1d44) = 0x00000000;
300 (void) RCBA32 (0x1d44);
301 RCBA32 (0x1d48) = 0x00030000;
302 (void) RCBA32 (0x1d48);
303 RCBA32 (0x1e80) = 0x000c0801;
304 (void) RCBA32 (0x1e80);
305 RCBA32 (0x1e84) = 0x000200f0;
306 (void) RCBA32 (0x1e84);
307
308 const u32 rcba2010[] =
309 {
310 /* 2010: */ 0x00188200, 0x14000016, 0xbc4abcb5, 0x00000000,
311 /* 2020: */ 0xf0c9605b, 0x13683040, 0x04c8f16e, 0x09e90170
312 };
Elyes HAOUAS035df002016-10-03 21:54:16 +0200313 for (i = 0; i < sizeof(rcba2010) / sizeof(rcba2010[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100314 {
315 RCBA32 (0x2010 + 4 * i) = rcba2010[i];
316 RCBA32 (0x2010 + 4 * i);
317 }
318
319 RCBA32 (0x2100) = 0x00000000;
320 (void) RCBA32 (0x2100);
321 RCBA32 (0x2104) = 0x00000757;
322 (void) RCBA32 (0x2104);
323 RCBA32 (0x2108) = 0x00170001;
324 (void) RCBA32 (0x2108);
325
326 RCBA32 (0x211c) = 0x00000000;
327 (void) RCBA32 (0x211c);
328 RCBA32 (0x2120) = 0x00010000;
329 (void) RCBA32 (0x2120);
330
331 RCBA32 (0x21fc) = 0x00000000;
332 (void) RCBA32 (0x21fc);
333 RCBA32 (0x2200) = 0x20000044;
334 (void) RCBA32 (0x2200);
335 RCBA32 (0x2204) = 0x00000001;
336 (void) RCBA32 (0x2204);
337 RCBA32 (0x2208) = 0x00003457;
338 (void) RCBA32 (0x2208);
339
340 const u32 rcba2210[] =
341 {
342 /* 2210 */ 0x00000000, 0x00000001, 0xa0fff210, 0x0000df00,
343 /* 2220 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
344 /* 2230 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
345 /* 2240 */ 0x00002301, 0x36000000, 0x00010107, 0x00160000,
346 /* 2250 */ 0x00001b01, 0x36000000, 0x00010107, 0x00160000,
347 /* 2260 */ 0x00000601, 0x16000000, 0x00010107, 0x00160000,
348 /* 2270 */ 0x00001c01, 0x16000000, 0x00010107, 0x00160000
349 };
350
Elyes HAOUAS035df002016-10-03 21:54:16 +0200351 for (i = 0; i < sizeof(rcba2210) / sizeof(rcba2210[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100352 {
353 RCBA32 (0x2210 + 4 * i) = rcba2210[i];
354 RCBA32 (0x2210 + 4 * i);
355 }
356
357 const u32 rcba2300[] =
358 {
359 /* 2300: */ 0x00000000, 0x40000000, 0x4646827b, 0x6e803131,
360 /* 2310: */ 0x32c77887, 0x00077733, 0x00007447, 0x00000040,
361 /* 2320: */ 0xcccc0cfc, 0x0fbb0fff
362 };
363
Elyes HAOUAS035df002016-10-03 21:54:16 +0200364 for (i = 0; i < sizeof(rcba2300) / sizeof(rcba2300[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100365 {
366 RCBA32 (0x2300 + 4 * i) = rcba2300[i];
367 RCBA32 (0x2300 + 4 * i);
368 }
369
370 RCBA32 (0x37fc) = 0x00000000;
371 (void) RCBA32 (0x37fc);
372 RCBA32 (0x3dfc) = 0x00000000;
373 (void) RCBA32 (0x3dfc);
374 RCBA32 (0x3e7c) = 0xffffffff;
375 (void) RCBA32 (0x3e7c);
376 RCBA32 (0x3efc) = 0x00000000;
377 (void) RCBA32 (0x3efc);
378 RCBA32 (0x3f00) = 0x0000010b;
379 (void) RCBA32 (0x3f00);
380}
381
382static void enable_hpet(void)
383{
384 u32 reg32;
385
386 /* Move HPET to default address 0xfed00000 and enable it */
387 reg32 = RCBA32(HPTC);
388 reg32 |= (1 << 7); // HPET Address Enable
389 reg32 &= ~(3 << 0);
390 RCBA32(HPTC) = reg32;
Arthur Heymans37e1d932019-10-02 14:33:34 +0200391 RCBA32(HPTC); /* Read back for it to work */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100392
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800393 write32((u32 *)0xfed00010, read32((u32 *)0xfed00010) | 1);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100394}
395
Elyes HAOUASbe841402018-05-13 13:40:39 +0200396static void enable_clock_gating(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100397{
398 u32 reg32;
399 u16 reg16;
400
401 RCBA32_AND_OR(0x2234, ~0UL, 0xf);
402
403 reg16 = pci_read_config16(dev, GEN_PMCON_1);
404 reg16 |= (1 << 2) | (1 << 11);
405 pci_write_config16(dev, GEN_PMCON_1, reg16);
406
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100407 reg32 = RCBA32(CG);
408 reg32 |= (1 << 31);
409 reg32 |= (1 << 29) | (1 << 28);
410 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
411 reg32 |= (1 << 16);
412 reg32 |= (1 << 17);
413 reg32 |= (1 << 18);
414 reg32 |= (1 << 22);
415 reg32 |= (1 << 23);
416 reg32 &= ~(1 << 20);
417 reg32 |= (1 << 19);
418 reg32 |= (1 << 0);
419 reg32 |= (0xf << 1);
420 RCBA32(CG) = reg32;
421
422 RCBA32_OR(0x38c0, 0x7);
423 RCBA32_OR(0x36d4, 0x6680c004);
424 RCBA32_OR(0x3564, 0x3);
425}
426
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200427static void pch_set_acpi_mode(void)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100428{
Julius Werner5d1f9a02019-03-07 17:07:26 -0800429 if (!acpi_is_wakeup_s3() && CONFIG(HAVE_SMI_HANDLER)) {
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100430 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200431 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100432 printk(BIOS_DEBUG, "done.\n");
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100433 }
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100434}
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100435
436static void pch_disable_smm_only_flashing(struct device *dev)
437{
438 u8 reg8;
439
440 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100441 reg8 = pci_read_config8(dev, BIOS_CNTL);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100442 reg8 &= ~(1 << 5);
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100443 pci_write_config8(dev, BIOS_CNTL, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100444}
445
446static void pch_fixups(struct device *dev)
447{
448 /*
449 * Enable DMI ASPM in the PCH
450 */
451 RCBA32_AND_OR(0x2304, ~(1 << 10), 0);
452 RCBA32_OR(0x21a4, (1 << 11)|(1 << 10));
453 RCBA32_OR(0x21a8, 0x3);
454}
455
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100456static void lpc_init(struct device *dev)
457{
458 printk(BIOS_DEBUG, "pch: lpc_init\n");
459
460 /* Set the value for PCI command register. */
461 pci_write_config16(dev, PCI_COMMAND, 0x000f);
462
463 /* IO APIC initialization. */
464 pch_enable_ioapic(dev);
465
466 pch_enable_serial_irqs(dev);
467
468 /* Setup the PIRQ. */
469 pch_pirq_init(dev);
470
471 /* Setup power options. */
472 pch_power_options(dev);
473
474 /* Initialize power management */
Arthur Heymansd0310fa2019-10-02 00:21:01 +0200475 mobile5_pm_init(dev);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100476
477 /* Set the state of the GPIO lines. */
478 //gpio_init(dev);
479
480 /* Initialize the real time clock. */
481 pch_rtc_init(dev);
482
483 /* Initialize ISA DMA. */
484 isa_dma_init();
485
486 /* Initialize the High Precision Event Timers, if present. */
487 enable_hpet();
488
489 /* Initialize Clock Gating */
490 enable_clock_gating(dev);
491
492 setup_i8259();
493
494 /* The OS should do this? */
495 /* Interrupt 9 should be level triggered (SCI) */
496 i8259_configure_irq_trigger(9, 1);
497
498 pch_disable_smm_only_flashing(dev);
499
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200500 pch_set_acpi_mode();
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100501
502 pch_fixups(dev);
503}
504
Elyes HAOUASbe841402018-05-13 13:40:39 +0200505static void pch_lpc_read_resources(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100506{
507 struct resource *res;
508 config_t *config = dev->chip_info;
509 u8 io_index = 0;
510
511 /* Get the normal PCI resources of this device. */
512 pci_dev_read_resources(dev);
513
514 /* Add an extra subtractive resource for both memory and I/O. */
515 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
516 res->base = 0;
517 res->size = 0x1000;
518 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
519 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
520
521 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
522 res->base = 0xff800000;
523 res->size = 0x00800000; /* 8 MB for flash */
524 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
525 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
526
527 res = new_resource(dev, 3); /* IOAPIC */
528 res->base = IO_APIC_ADDR;
529 res->size = 0x00001000;
530 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
531
532 /* Set PCH IO decode ranges if required.*/
533 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
534 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
535 res->base = config->gen1_dec & 0xFFFC;
536 res->size = (config->gen1_dec >> 16) & 0xFC;
537 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
538 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
539 }
540
541 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
542 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
543 res->base = config->gen2_dec & 0xFFFC;
544 res->size = (config->gen2_dec >> 16) & 0xFC;
545 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
546 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
547 }
548
549 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
550 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
551 res->base = config->gen3_dec & 0xFFFC;
552 res->size = (config->gen3_dec >> 16) & 0xFC;
553 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
554 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
555 }
556
557 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
558 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
559 res->base = config->gen4_dec & 0xFFFC;
560 res->size = (config->gen4_dec >> 16) & 0xFC;
561 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
562 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
563 }
564}
565
Elyes HAOUASbe841402018-05-13 13:40:39 +0200566static void pch_lpc_enable(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100567{
568 /* Enable PCH Display Port */
569 RCBA16(DISPBDF) = 0x0010;
570 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
571
572 pch_enable(dev);
573}
574
Elyes HAOUASbe841402018-05-13 13:40:39 +0200575static void southbridge_inject_dsdt(struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200576{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200577 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200578
579 if (gnvs) {
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100580 const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
Elyes HAOUAS035df002016-10-03 21:54:16 +0200581 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200582
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200583 acpi_create_gnvs(gnvs);
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200584
585 gnvs->apic = 1;
586 gnvs->mpen = 1; /* Enable Multi Processing */
587 gnvs->pcnt = dev_count_cpu();
Nico Huber744d6bd2019-01-12 14:58:20 +0100588
589 if (gfx) {
590 gnvs->ndid = gfx->ndid;
591 memcpy(gnvs->did, gfx->did, sizeof(gnvs->did));
592 }
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200593
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200594 /* And tell SMI about it */
595 smm_setup_structures(gnvs, NULL, NULL);
596
597 /* Add it to SSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100598 acpigen_write_scope("\\");
599 acpigen_write_name_dword("NVSA", (u32) gnvs);
600 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200601 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200602}
603
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200604void acpi_fill_fadt(acpi_fadt_t *fadt)
605{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300606 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200607 config_t *chip = dev->chip_info;
608 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
609 int c2_latency;
610
Elyes HAOUAS0d4de2a2019-02-28 13:04:29 +0100611 fadt->reserved = 0;
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200612
613 fadt->sci_int = 0x9;
614 fadt->smi_cmd = APM_CNT;
615 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
616 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
617 fadt->s4bios_req = 0x0;
618 fadt->pstate_cnt = 0;
619
620 fadt->pm1a_evt_blk = pmbase;
621 fadt->pm1b_evt_blk = 0x0;
622 fadt->pm1a_cnt_blk = pmbase + 0x4;
623 fadt->pm1b_cnt_blk = 0x0;
624 fadt->pm2_cnt_blk = pmbase + 0x50;
625 fadt->pm_tmr_blk = pmbase + 0x8;
626 fadt->gpe0_blk = pmbase + 0x20;
627 fadt->gpe1_blk = 0;
628
629 fadt->pm1_evt_len = 4;
630 fadt->pm1_cnt_len = 2;
631 fadt->pm2_cnt_len = 1;
632 fadt->pm_tmr_len = 4;
633 fadt->gpe0_blk_len = 16;
634 fadt->gpe1_blk_len = 0;
635 fadt->gpe1_base = 0;
636 fadt->cst_cnt = 0;
637 c2_latency = chip->c2_latency;
638 if (!c2_latency) {
639 c2_latency = 101; /* c2 unsupported */
640 }
641 fadt->p_lvl2_lat = c2_latency;
642 fadt->p_lvl3_lat = 87;
643 fadt->flush_size = 1024;
644 fadt->flush_stride = 16;
Patrick Rudolphb30a47b2019-07-15 18:04:23 +0200645 /* P_CNT not supported */
646 fadt->duty_offset = 0;
647 fadt->duty_width = 0;
648
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200649 fadt->day_alrm = 0xd;
650 fadt->mon_alrm = 0x00;
651 fadt->century = 0x32;
652 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
653
654 fadt->flags = ACPI_FADT_WBINVD |
655 ACPI_FADT_C1_SUPPORTED |
656 ACPI_FADT_SLEEP_BUTTON |
657 ACPI_FADT_RESET_REGISTER |
658 ACPI_FADT_S4_RTC_WAKE |
659 ACPI_FADT_PLATFORM_CLOCK;
660 if (chip->docking_supported) {
661 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
662 }
663 if (c2_latency < 100) {
664 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
665 }
666
667 fadt->reset_reg.space_id = 1;
668 fadt->reset_reg.bit_width = 8;
669 fadt->reset_reg.bit_offset = 0;
670 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
671 fadt->reset_reg.addrl = 0xcf9;
672 fadt->reset_reg.addrh = 0;
673
674 fadt->reset_value = 6;
675
676 fadt->x_pm1a_evt_blk.space_id = 1;
677 fadt->x_pm1a_evt_blk.bit_width = 32;
678 fadt->x_pm1a_evt_blk.bit_offset = 0;
679 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
680 fadt->x_pm1a_evt_blk.addrl = pmbase;
681 fadt->x_pm1a_evt_blk.addrh = 0x0;
682
683 fadt->x_pm1b_evt_blk.space_id = 1;
684 fadt->x_pm1b_evt_blk.bit_width = 0;
685 fadt->x_pm1b_evt_blk.bit_offset = 0;
686 fadt->x_pm1b_evt_blk.access_size = 0;
687 fadt->x_pm1b_evt_blk.addrl = 0x0;
688 fadt->x_pm1b_evt_blk.addrh = 0x0;
689
690 fadt->x_pm1a_cnt_blk.space_id = 1;
691 fadt->x_pm1a_cnt_blk.bit_width = 16;
692 fadt->x_pm1a_cnt_blk.bit_offset = 0;
693 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
694 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
695 fadt->x_pm1a_cnt_blk.addrh = 0x0;
696
697 fadt->x_pm1b_cnt_blk.space_id = 1;
698 fadt->x_pm1b_cnt_blk.bit_width = 0;
699 fadt->x_pm1b_cnt_blk.bit_offset = 0;
700 fadt->x_pm1b_cnt_blk.access_size = 0;
701 fadt->x_pm1b_cnt_blk.addrl = 0x0;
702 fadt->x_pm1b_cnt_blk.addrh = 0x0;
703
704 fadt->x_pm2_cnt_blk.space_id = 1;
705 fadt->x_pm2_cnt_blk.bit_width = 8;
706 fadt->x_pm2_cnt_blk.bit_offset = 0;
707 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
708 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
709 fadt->x_pm2_cnt_blk.addrh = 0x0;
710
711 fadt->x_pm_tmr_blk.space_id = 1;
712 fadt->x_pm_tmr_blk.bit_width = 32;
713 fadt->x_pm_tmr_blk.bit_offset = 0;
714 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
715 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
716 fadt->x_pm_tmr_blk.addrh = 0x0;
717
718 fadt->x_gpe0_blk.space_id = 1;
719 fadt->x_gpe0_blk.bit_width = 128;
720 fadt->x_gpe0_blk.bit_offset = 0;
721 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
722 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
723 fadt->x_gpe0_blk.addrh = 0x0;
724
725 fadt->x_gpe1_blk.space_id = 1;
726 fadt->x_gpe1_blk.bit_width = 0;
727 fadt->x_gpe1_blk.bit_offset = 0;
728 fadt->x_gpe1_blk.access_size = 0;
729 fadt->x_gpe1_blk.addrl = 0x0;
730 fadt->x_gpe1_blk.addrh = 0x0;
731}
732
Kyösti Mälkki90993952018-05-01 19:36:25 +0300733static const char *lpc_acpi_name(const struct device *dev)
734{
735 return "LPCB";
736}
737
Elyes HAOUASbe841402018-05-13 13:40:39 +0200738static void southbridge_fill_ssdt(struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100739{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300740 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100741 config_t *chip = dev->chip_info;
742
743 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Kyösti Mälkki90993952018-05-01 19:36:25 +0300744 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100745}
746
Bill XIEd533b162017-08-22 16:26:22 +0800747static void lpc_final(struct device *dev)
748{
Arthur Heymansaadd1d02019-05-28 13:39:20 +0200749 spi_finalize_ops();
750
Bill XIEd533b162017-08-22 16:26:22 +0800751 /* Call SMM finalize() handlers before resume */
Julius Wernercd49cce2019-03-05 16:53:33 -0800752 if (CONFIG(HAVE_SMI_HANDLER)) {
753 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
Bill XIEd533b162017-08-22 16:26:22 +0800754 acpi_is_wakeup_s3()) {
755 outb(APM_CNT_FINALIZE, APM_CNT);
756 }
757 }
758}
759
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100760static struct pci_operations pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530761 .set_subsystem = pci_dev_set_subsystem,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100762};
763
764static struct device_operations device_ops = {
765 .read_resources = pch_lpc_read_resources,
766 .set_resources = pci_dev_set_resources,
Arthur Heymans3b452e02019-10-03 09:16:10 +0200767 .enable_resources = pci_dev_enable_resources,
Nico Huber68680dd2020-03-31 17:34:52 +0200768 .acpi_inject_dsdt = southbridge_inject_dsdt,
769 .acpi_fill_ssdt = southbridge_fill_ssdt,
Kyösti Mälkki90993952018-05-01 19:36:25 +0300770 .acpi_name = lpc_acpi_name,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200771 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100772 .init = lpc_init,
Bill XIEd533b162017-08-22 16:26:22 +0800773 .final = lpc_final,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100774 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100775 .scan_bus = scan_static_bus,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100776 .ops_pci = &pci_ops,
777};
778
779
Felix Singer838fbc72019-11-21 21:23:32 +0100780static const unsigned short pci_device_ids[] = {
781 PCI_DID_INTEL_IBEXPEAK_LPC_QM57,
782 PCI_DID_INTEL_IBEXPEAK_LPC_HM55,
783 0
784};
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100785
786static const struct pci_driver pch_lpc __pci_driver = {
787 .ops = &device_ops,
788 .vendor = PCI_VENDOR_ID_INTEL,
789 .devices = pci_device_ids,
790};