blob: 8c0a181d0c2d7674f1ce521d63bcf66f974fed4a [file] [log] [blame]
Mariusz Szafranskia4041332017-08-02 17:28:17 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2014 - 2017 Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of 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.
14 *
15 */
16
17#include <console/console.h>
18#include <device/device.h>
19#include <device/pci.h>
20#include <device/pci_ids.h>
21#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020022#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020023#include <device/pci_ops.h>
Mariusz Szafranskia4041332017-08-02 17:28:17 +020024#include <arch/ioapic.h>
25#include <arch/acpi.h>
Mariusz Szafranskia4041332017-08-02 17:28:17 +020026#include <cpu/x86/smm.h>
27#include <bootstate.h>
28
29#include <soc/lpc.h>
30#include <soc/pci_devs.h>
31#include <soc/ramstage.h>
32#include <soc/iomap.h>
33#include <soc/pcr.h>
34#include <soc/p2sb.h>
35#include <soc/acpi.h>
36
37#include "chip.h"
38
39/* PCH-LP redirection entries */
40#define PCH_LP_REDIR_ETR 120
41
42/**
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +010043 * Set miscellaneous static southbridge features.
Mariusz Szafranskia4041332017-08-02 17:28:17 +020044 *
45 * @param dev PCI device with I/O APIC control registers
46 */
47static void pch_enable_ioapic(struct device *dev)
48{
49 u32 reg32;
50
51 set_ioapic_id((void *)IO_APIC_ADDR, IO_APIC0);
52
53 /* affirm full set of redirection table entries ("write once") */
54 reg32 = io_apic_read((void *)IO_APIC_ADDR, 0x01);
55
56 reg32 &= ~0x00ff0000;
57 reg32 |= (PCH_LP_REDIR_ETR - 1) << 16;
58
59 io_apic_write((void *)IO_APIC_ADDR, 0x01, reg32);
60
61 /*
62 * Select Boot Configuration register (0x03) and
63 * use Processor System Bus (0x01) to deliver interrupts.
64 */
65 io_apic_write((void *)IO_APIC_ADDR, 0x03, 0x01);
66}
67
Stephen Douthit56a74bc2019-08-05 12:49:08 -040068/* interrupt router lookup for internal devices */
69struct dnv_ir_lut {
70 /* (dev << 3) | fn */
71 u8 devfn;
72 u8 ir;
73};
74
75#define DEVFN(dev, fn) ((dev << 3) | (fn))
76
77static const struct dnv_ir_lut dnv_ir_lut[] = {
78 {.devfn = DEVFN(0x05, 0), .ir = 3}, /* RCEC */
79 {.devfn = DEVFN(0x06, 0), .ir = 4}, /* Virtual RP to QAT */
80 {.devfn = DEVFN(0x09, 0), .ir = 7}, /* PCIe RP0 */
81 {.devfn = DEVFN(0x0a, 0), .ir = 7}, /* PCIe RP1 */
82 {.devfn = DEVFN(0x0b, 0), .ir = 7}, /* PCIe RP2 */
83 {.devfn = DEVFN(0x0c, 0), .ir = 7}, /* PCIe RP3 */
84 {.devfn = DEVFN(0x0e, 0), .ir = 8}, /* PCIe RP4 */
85 {.devfn = DEVFN(0x0f, 0), .ir = 8}, /* PCIe RP5 */
86 {.devfn = DEVFN(0x10, 0), .ir = 8}, /* PCIe RP6 */
87 {.devfn = DEVFN(0x11, 0), .ir = 8}, /* PCIe RP7 */
88 {.devfn = DEVFN(0x12, 0), .ir = 10}, /* SMBus - Host */
89 {.devfn = DEVFN(0x13, 0), .ir = 6}, /* AHCI0 */
90 {.devfn = DEVFN(0x14, 0), .ir = 11}, /* AHCI1 */
91 {.devfn = DEVFN(0x15, 0), .ir = 9}, /* USB */
92 {.devfn = DEVFN(0x16, 0), .ir = 1}, /* Virtual RP to LAN0 */
93 {.devfn = DEVFN(0x17, 0), .ir = 2}, /* Virtual RP to LAN1 */
94 {.devfn = DEVFN(0x18, 0), .ir = 5}, /* ME HECI1 */
95 {.devfn = DEVFN(0x18, 1), .ir = 5}, /* ME HECI1 */
96 {.devfn = DEVFN(0x18, 2), .ir = 5}, /* ME PTIO-IDER */
97 {.devfn = DEVFN(0x18, 3), .ir = 5}, /* ME PTIO-KT */
98 {.devfn = DEVFN(0x18, 4), .ir = 5}, /* ME HECI3 */
99 {.devfn = DEVFN(0x1a, 0), .ir = 10}, /* HSUART0 */
100 {.devfn = DEVFN(0x1a, 1), .ir = 10}, /* HSUART1 */
101 {.devfn = DEVFN(0x1a, 2), .ir = 10}, /* HSUART2 */
102 {.devfn = DEVFN(0x1b, 0), .ir = 12}, /* IE HECI1 */
103 {.devfn = DEVFN(0x1b, 1), .ir = 12}, /* IE HECI1 */
104 {.devfn = DEVFN(0x1b, 2), .ir = 12}, /* IE PTIO-IDER */
105 {.devfn = DEVFN(0x1b, 3), .ir = 12}, /* IE PTIO-KT */
106 {.devfn = DEVFN(0x1b, 4), .ir = 12}, /* IE HECI3 */
107 {.devfn = DEVFN(0x1c, 0), .ir = 12}, /* SDHCI */
108 {.devfn = DEVFN(0x1f, 0), .ir = 0}, /* LPC */
109 {.devfn = DEVFN(0x1f, 1), .ir = 0}, /* PS2B */
110 {.devfn = DEVFN(0x1f, 4), .ir = 0}, /* SMBus - Legacy */
111 {.devfn = DEVFN(0x1f, 7), .ir = 0}, /* Trace Hub */
112};
113
114/*
115 * Only 6 of the 8 root ports have swizzling, return '1' if this bdf is one of
116 * them, '0' otherwise
117 */
118static int is_dnv_swizzled_rp(uint16_t bdf)
119{
120 switch (bdf) {
121 case DEVFN(10, 0):
122 case DEVFN(11, 0):
123 case DEVFN(12, 0):
124 case DEVFN(15, 0):
125 case DEVFN(16, 0):
126 case DEVFN(17, 0):
127 return 1;
128 }
129
130 return 0;
131}
132
133/*
134 * Figure out which upstream interrupt pin a downstream device gets swizzled to
135 *
136 * config - pointer to chip_info containing routing info
137 * devfn - device/function of root port to check swizzling for
138 * pin - interrupt pin 1-4 = A-D
139 *
140 * Return new pin mapping, 0 if invalid pin
141 */
142static int dnv_get_swizzled_pin(config_t *config, u8 devfn, u8 pin)
143{
144 if (pin < 1 || pin > 4)
145 return 0;
146
147 devfn >>= 3;
148 if (devfn < 13)
149 devfn -= 9;
150 else
151 devfn -= 14;
152
153 return ((pin - 1 + devfn) % 4) + 1;
154}
155
156/*
157 * Figure out which upstream interrupt pin a downstream device gets swizzled to
158 *
159 * config - pointer to chip_info containing routing info
160 * devfn - device/function of root port to check swizzling for
161 * pin - interrupt pin 1-4 = A-D
162 *
163 * Return new pin mapping, 0 if invalid pin
164 */
165static int dnv_get_ir(config_t *config, u8 devfn, u8 pin)
166{
167 int i = 0;
168 int line = 0xff;
169 u16 ir = 0xffff;
170
171 /* The only valid pin values are 1-4 for A-D */
172 if (pin < 1 || pin > 4) {
173 printk(BIOS_WARNING, "%s: pin %d is invalid\n", __func__, pin);
174 goto dnv_get_ir_done;
175 }
176
177 for (i = 0; i < ARRAY_SIZE(dnv_ir_lut); i++) {
178 if (dnv_ir_lut[i].devfn == devfn)
179 break;
180 }
181
182 if (i == ARRAY_SIZE(dnv_ir_lut)) {
183 printk(BIOS_WARNING, "%s: no entry\n", __func__);
184 goto dnv_get_ir_done;
185 }
186
187 switch (dnv_ir_lut[i].ir) {
188 case 0:
189 ir = config->ir00_routing;
190 break;
191 case 1:
192 ir = config->ir01_routing;
193 break;
194 case 2:
195 ir = config->ir02_routing;
196 break;
197 case 3:
198 ir = config->ir03_routing;
199 break;
200 case 4:
201 ir = config->ir04_routing;
202 break;
203 case 5:
204 ir = config->ir05_routing;
205 break;
206 case 6:
207 ir = config->ir06_routing;
208 break;
209 case 7:
210 ir = config->ir07_routing;
211 break;
212 case 8:
213 ir = config->ir08_routing;
214 break;
215 case 9:
216 ir = config->ir09_routing;
217 break;
218 case 10:
219 ir = config->ir10_routing;
220 break;
221 case 11:
222 ir = config->ir11_routing;
223 break;
224 case 12:
225 ir = config->ir12_routing;
226 break;
227 default:
228 printk(BIOS_ERR, "%s: invalid ir %d for entry %d\n", __func__, dnv_ir_lut[i].ir,
229 i);
230 goto dnv_get_ir_done;
231 }
232
233 ir >>= (pin - 1) * 4;
234 ir &= 0xf;
235 switch (ir) {
236 case 0:
237 line = config->pirqa_routing;
238 break;
239 case 1:
240 line = config->pirqb_routing;
241 break;
242 case 2:
243 line = config->pirqc_routing;
244 break;
245 case 3:
246 line = config->pirqd_routing;
247 break;
248 case 4:
249 line = config->pirqe_routing;
250 break;
251 case 5:
252 line = config->pirqf_routing;
253 break;
254 case 6:
255 line = config->pirqg_routing;
256 break;
257 case 7:
258 line = config->pirqh_routing;
259 break;
260 default:
261 printk(BIOS_ERR, "%s: invalid ir pirq %d for entry %d\n", __func__, ir, i);
262 break;
263 }
264
265dnv_get_ir_done:
266 return line;
267}
268
269/*
270 * PCI devices have the INT_LINE (0x3C) and INT_PIN (0x3D) registers which
271 * report interrupt routing information to operating systems and drivers. The
272 * INT_PIN register is generally read only and reports which interrupt pin
273 * A - D it uses. The INT_LINE register is configurable and reports which IRQ
274 * (generally the PIC IRQs 1 - 15) it will use. This needs to take interrupt
275 * pin swizzling on devices that are downstream on a PCI bridge into account.
276 */
277static u8 dnv_get_int_line(struct device *irq_dev)
278{
279 config_t *config;
280 struct device *targ_dev = NULL;
281 uint16_t parent_bdf = 0;
282 int8_t original_int_pin = 0, new_int_pin = 0, swiz_int_pin = 0;
283 uint8_t int_line = 0xff;
284
285 if (irq_dev->path.type != DEVICE_PATH_PCI || !irq_dev->enabled) {
286 printk(BIOS_ERR, "%s for non pci device?\n", __func__);
287 goto dnv_get_int_line_done;
288 }
289
290 /*
291 * Get the INT_PIN swizzled up to the root port if necessary
292 * using the existing coreboot pci_device code
293 */
294 original_int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
295 new_int_pin = get_pci_irq_pins(irq_dev, &targ_dev);
296 if (targ_dev == NULL || new_int_pin < 1)
297 goto dnv_get_int_line_done;
298
299 printk(BIOS_DEBUG, "%s: irq_dev %s, targ_dev %s:\n", __func__, dev_path(irq_dev),
300 dev_path(targ_dev));
301 printk(BIOS_DEBUG, "%s: std swizzle %s from %c to %c\n", __func__, dev_path(targ_dev),
302 '@' + original_int_pin, '@' + new_int_pin);
303
304 /* Swizzle this device if needed */
305 config = targ_dev->chip_info;
306 parent_bdf = targ_dev->path.pci.devfn | targ_dev->bus->secondary << 8;
307 if (is_dnv_swizzled_rp(parent_bdf) && irq_dev != targ_dev) {
308 swiz_int_pin = dnv_get_swizzled_pin(config, parent_bdf, new_int_pin);
309 printk(BIOS_DEBUG, "%s: dnv swizzle %s from %c to %c\n", __func__,
310 dev_path(targ_dev), '@' + new_int_pin, '@' + swiz_int_pin);
311 } else {
312 swiz_int_pin = new_int_pin;
313 }
314
315 /* Look up the routing for the pin */
316 int_line = dnv_get_ir(config, parent_bdf, swiz_int_pin);
317
318dnv_get_int_line_done:
319 printk(BIOS_DEBUG, "\tINT_LINE\t\t: %d\n", int_line);
320 return int_line;
321}
322
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200323/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
324 * 0x00 - 0000 = Reserved
325 * 0x01 - 0001 = Reserved
326 * 0x02 - 0010 = Reserved
327 * 0x03 - 0011 = IRQ3
328 * 0x04 - 0100 = IRQ4
329 * 0x05 - 0101 = IRQ5
330 * 0x06 - 0110 = IRQ6
331 * 0x07 - 0111 = IRQ7
332 * 0x08 - 1000 = Reserved
333 * 0x09 - 1001 = IRQ9
334 * 0x0A - 1010 = IRQ10
335 * 0x0B - 1011 = IRQ11
336 * 0x0C - 1100 = IRQ12
337 * 0x0D - 1101 = Reserved
338 * 0x0E - 1110 = IRQ14
339 * 0x0F - 1111 = IRQ15
340 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
341 * 0x80 - The PIRQ is not routed.
342 */
343
Elyes HAOUAS2ec41832018-05-27 17:40:58 +0200344static void pch_pirq_init(struct device *dev)
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200345{
Elyes HAOUAS2ec41832018-05-27 17:40:58 +0200346 struct device *irq_dev;
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200347 /* Get the chip configuration */
Kyösti Mälkki8950cfb2019-07-13 22:16:25 +0300348 config_t *config = config_of(dev);
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200349
350 /* Initialize PIRQ Routings */
351 write8((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIRQA_ROUT),
352 config->pirqa_routing);
353 write8((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIRQB_ROUT),
354 config->pirqb_routing);
355 write8((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIRQC_ROUT),
356 config->pirqc_routing);
357 write8((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIRQD_ROUT),
358 config->pirqd_routing);
359
360 write8((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIRQE_ROUT),
361 config->pirqe_routing);
362 write8((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIRQF_ROUT),
363 config->pirqf_routing);
364 write8((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIRQG_ROUT),
365 config->pirqg_routing);
366 write8((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIRQH_ROUT),
367 config->pirqh_routing);
368
369 /* Initialize device's Interrupt Routings */
370 write16((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIR00),
371 config->ir00_routing);
372 write16((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIR01),
373 config->ir01_routing);
374 write16((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIR02),
375 config->ir02_routing);
376 write16((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIR03),
377 config->ir03_routing);
378 write16((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIR04),
379 config->ir04_routing);
380 write16((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIR05),
381 config->ir05_routing);
382 write16((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIR06),
383 config->ir06_routing);
384 write16((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIR07),
385 config->ir07_routing);
386 write16((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIR08),
387 config->ir08_routing);
388 write16((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIR09),
389 config->ir09_routing);
390 write16((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIR10),
391 config->ir10_routing);
392 write16((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIR11),
393 config->ir11_routing);
394 write16((void *)PCH_PCR_ADDRESS(PID_ITSS, PCR_ITSS_PIR12),
395 config->ir12_routing);
396
397 /* Initialize device's Interrupt Polarity Control */
398 write32((void *)PCH_PCR_ADDRESS(PID_ITSS, PCH_PCR_ITSS_IPC0),
399 config->ipc0);
400 write32((void *)PCH_PCR_ADDRESS(PID_ITSS, PCH_PCR_ITSS_IPC1),
401 config->ipc1);
402 write32((void *)PCH_PCR_ADDRESS(PID_ITSS, PCH_PCR_ITSS_IPC2),
403 config->ipc2);
404 write32((void *)PCH_PCR_ADDRESS(PID_ITSS, PCH_PCR_ITSS_IPC3),
405 config->ipc3);
406
407 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Stephen Douthit56a74bc2019-08-05 12:49:08 -0400408 int devfn = irq_dev->path.pci.devfn;
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200409 u8 int_pin = 0, int_line = 0;
410
411 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
412 continue;
413
414 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
415
Stephen Douthit56a74bc2019-08-05 12:49:08 -0400416 int_line = dnv_get_int_line(irq_dev);
417 printk(BIOS_DEBUG, "%s: %02x:%02x.%d pin %d int line %d\n", __func__,
418 irq_dev->bus->secondary, devfn >> 3, devfn & 0x7, int_pin, int_line);
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200419
420 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line);
421 }
422}
423
Elyes HAOUAS2ec41832018-05-27 17:40:58 +0200424static void pci_p2sb_read_resources(struct device *dev)
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200425{
426 struct resource *res;
427
428 /* Add MMIO resource
429 * Use 0xda as an unused index for PCR BAR.
430 */
431 res = new_resource(dev, 0xda);
432 res->base = DEFAULT_PCR_BASE;
433 res->size = 16 * 1024 * 1024; /* 16MB PCR config space */
434 res->flags = IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED |
435 IORESOURCE_ASSIGNED;
436 printk(BIOS_DEBUG,
437 "Adding P2SB PCR config space BAR 0x%08lx-0x%08lx.\n",
438 (unsigned long)(res->base),
439 (unsigned long)(res->base + res->size));
440
441 /* Add MMIO resource
442 * Use 0xdb as an unused index for IOAPIC.
443 */
444 res = new_resource(dev, 0xdb); /* IOAPIC */
445 res->base = IO_APIC_ADDR;
446 res->size = 0x00001000;
447 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
448}
449
450static void pch_enable_serial_irqs(struct device *dev)
451{
452 /* Set packet length and toggle silent mode bit for one frame. */
453 pci_write_config8(dev, SERIRQ_CNTL,
454 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -0800455#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200456 pci_write_config8(dev, SERIRQ_CNTL,
457 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
458#endif
459}
460
461static void lpc_init(struct device *dev)
462{
463 printk(BIOS_DEBUG, "pch: lpc_init\n");
464
465 /* Get the base address */
466
467 /* Set the value for PCI command register. */
468 pci_write_config16(dev, PCI_COMMAND,
469 PCI_COMMAND_SPECIAL | PCI_COMMAND_MASTER |
470 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
471
472 /* Serial IRQ initialization. */
473 pch_enable_serial_irqs(dev);
474
475 /* IO APIC initialization. */
476 pch_enable_ioapic(dev);
477
478 /* Setup the PIRQ. */
479 pch_pirq_init(dev);
480}
481
Elyes HAOUAS2ec41832018-05-27 17:40:58 +0200482static void pch_lpc_add_mmio_resources(struct device *dev) { /* TODO */ }
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200483
Elyes HAOUAS2ec41832018-05-27 17:40:58 +0200484static void pch_lpc_add_io_resources(struct device *dev)
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200485{
486 struct resource *res;
487 u8 io_index = 0;
488
489 /* Add an extra subtractive resource for both memory and I/O. */
490 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
491 res->base = 0;
492 res->size = 0x1000;
493 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
494 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
495
496 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
497 res->base = 0xff000000;
498 res->size = 0x01000000; /* 16 MB for flash */
499 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
500 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
501}
502
Elyes HAOUAS2ec41832018-05-27 17:40:58 +0200503static void lpc_read_resources(struct device *dev)
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200504{
505 /* Get the normal PCI resources of this device. */
506 pci_dev_read_resources(dev);
507
508 /* Add non-standard MMIO resources. */
509 pch_lpc_add_mmio_resources(dev);
510
511 /* Add IO resources. */
512 pch_lpc_add_io_resources(dev);
513
514 /* Add MMIO resource for IOAPIC. */
515 pci_p2sb_read_resources(dev);
516}
517
518static void pch_decode_init(struct device *dev) { /* TODO */ }
519
Elyes HAOUAS2ec41832018-05-27 17:40:58 +0200520static void lpc_enable_resources(struct device *dev)
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200521{
522 pch_decode_init(dev);
523 pci_dev_enable_resources(dev);
524}
525
526/* Set bit in Function Disable register to hide this device */
527static void pch_hide_devfn(uint32_t devfn) { /* TODO */ }
528
Elyes HAOUAS2ec41832018-05-27 17:40:58 +0200529void southcluster_enable_dev(struct device *dev)
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200530{
531 u32 reg32;
532
533 if (!dev->enabled) {
534 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
535
536 /* Ensure memory, io, and bus master are all disabled */
537 reg32 = pci_read_config32(dev, PCI_COMMAND);
538 reg32 &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
539 PCI_COMMAND_IO);
540 pci_write_config32(dev, PCI_COMMAND, reg32);
541
542 /* Hide this device if possible */
543 pch_hide_devfn(dev->path.pci.devfn);
544 } else {
545 /* Enable SERR */
546 reg32 = pci_read_config32(dev, PCI_COMMAND);
547 reg32 |= PCI_COMMAND_SERR;
548 pci_write_config32(dev, PCI_COMMAND, reg32);
549 }
550}
551
552static struct device_operations device_ops = {
553 .read_resources = lpc_read_resources,
554 .set_resources = pci_dev_set_resources,
Julius Wernercd49cce2019-03-05 16:53:33 -0800555#if CONFIG(HAVE_ACPI_TABLES)
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200556 .acpi_inject_dsdt_generator = southcluster_inject_dsdt,
557 .write_acpi_tables = southcluster_write_acpi_tables,
558#endif
559 .enable_resources = lpc_enable_resources,
560 .init = lpc_init,
561 .enable = southcluster_enable_dev,
Nico Huber51b75ae2019-03-14 16:02:05 +0100562 .scan_bus = scan_static_bus,
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200563 .ops_pci = &soc_pci_ops,
564};
565
566static const struct pci_driver lpc_driver __pci_driver = {
567 .ops = &device_ops,
568 .vendor = PCI_VENDOR_ID_INTEL,
Felix Singerdbc90df2019-11-22 00:10:20 +0100569 .device = PCI_DEVICE_ID_INTEL_DENVERTON_LPC,
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200570};
571
572static void finalize_chipset(void *unused)
573{
574 printk(BIOS_DEBUG, "Finalizing SMM.\n");
575 outb(APM_CNT_FINALIZE, APM_CNT);
576}
577
578BOOT_STATE_INIT_ENTRY(BS_OS_RESUME, BS_ON_ENTRY, finalize_chipset, NULL);
579BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_EXIT, finalize_chipset, NULL);