blob: d92e858d5359fcc87cc1de05c67388147cbfc539 [file] [log] [blame]
Aaron Durbin76c37002012-10-30 09:03:43 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2007-2009 coresystems GmbH
5 * Copyright (C) 2012 The Chromium OS Authors
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.
Aaron Durbin76c37002012-10-30 09:03:43 -050016 */
17
18#include <types.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050019#include <console/console.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050020#include <arch/acpi.h>
21#include <device/device.h>
22#include <device/pci.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020023#include <device/pci_ops.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050024#include "haswell.h"
Matt DeVillier85d98d92018-03-04 01:41:23 -060025#include <southbridge/intel/lynxpoint/pch.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050026
27unsigned long acpi_fill_mcfg(unsigned long current)
28{
Elyes HAOUAS77f7a6e2018-05-09 17:47:59 +020029 struct device *dev;
Aaron Durbin76c37002012-10-30 09:03:43 -050030 u32 pciexbar = 0;
31 u32 pciexbar_reg;
32 int max_buses;
Ryan Salsamendib9bc2572017-07-04 13:35:06 -070033 u32 mask;
Aaron Durbin76c37002012-10-30 09:03:43 -050034
Kyösti Mälkkic70eed12018-05-22 02:18:00 +030035 dev = pcidev_on_root(0, 0);
Aaron Durbin76c37002012-10-30 09:03:43 -050036 if (!dev)
37 return current;
38
Elyes HAOUAS69d658f2016-09-17 20:32:07 +020039 pciexbar_reg = pci_read_config32(dev, PCIEXBAR);
Aaron Durbin76c37002012-10-30 09:03:43 -050040
41 // MMCFG not supported or not enabled.
42 if (!(pciexbar_reg & (1 << 0)))
43 return current;
44
Ryan Salsamendib9bc2572017-07-04 13:35:06 -070045 mask = (1UL << 31) | (1 << 30) | (1 << 29) | (1 << 28);
Aaron Durbin76c37002012-10-30 09:03:43 -050046 switch ((pciexbar_reg >> 1) & 3) {
47 case 0: // 256MB
Ryan Salsamendib9bc2572017-07-04 13:35:06 -070048 pciexbar = pciexbar_reg & mask;
Aaron Durbin76c37002012-10-30 09:03:43 -050049 max_buses = 256;
50 break;
51 case 1: // 128M
Ryan Salsamendib9bc2572017-07-04 13:35:06 -070052 mask |= (1 << 27);
53 pciexbar = pciexbar_reg & mask;
Aaron Durbin76c37002012-10-30 09:03:43 -050054 max_buses = 128;
55 break;
56 case 2: // 64M
Ryan Salsamendib9bc2572017-07-04 13:35:06 -070057 mask |= (1 << 27) | (1 << 26);
58 pciexbar = pciexbar_reg & mask;
Aaron Durbin76c37002012-10-30 09:03:43 -050059 max_buses = 64;
60 break;
61 default: // RSVD
62 return current;
63 }
64
65 if (!pciexbar)
66 return current;
67
68 current += acpi_create_mcfg_mmconfig((acpi_mcfg_mmconfig_t *) current,
69 pciexbar, 0x0, 0x0, max_buses - 1);
70
71 return current;
72}
Matt DeVillier85d98d92018-03-04 01:41:23 -060073
74static unsigned long acpi_fill_dmar(unsigned long current)
75{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +030076 struct device *const igfx_dev = pcidev_on_root(2, 0);
Matt DeVillier85d98d92018-03-04 01:41:23 -060077 const u32 gfxvtbar = MCHBAR32(GFXVTBAR) & ~0xfff;
78 const u32 vtvc0bar = MCHBAR32(VTVC0BAR) & ~0xfff;
79 const bool gfxvten = MCHBAR32(GFXVTBAR) & 0x1;
80 const bool vtvc0en = MCHBAR32(VTVC0BAR) & 0x1;
81
82 /* iGFX has to be enabled; GFXVTBAR set, enabled, in 32-bit space */
83 if (igfx_dev && igfx_dev->enabled && gfxvtbar
84 && gfxvten && !MCHBAR32(GFXVTBAR + 4)) {
85 const unsigned long tmp = current;
86
87 current += acpi_create_dmar_drhd(current, 0, 0, gfxvtbar);
Matt DeVillier7866d492018-03-29 14:59:57 +020088 current += acpi_create_dmar_ds_pci(current, 0, 2, 0);
Matt DeVillier85d98d92018-03-04 01:41:23 -060089
90 acpi_dmar_drhd_fixup(tmp, current);
91 }
92
93 /* VTVC0BAR has to be set, enabled, and in 32-bit space */
94 if (vtvc0bar && vtvc0en && !MCHBAR32(VTVC0BAR + 4)) {
95 const unsigned long tmp = current;
96 current += acpi_create_dmar_drhd(current,
97 DRHD_INCLUDE_PCI_ALL, 0, vtvc0bar);
Matt DeVillier7866d492018-03-29 14:59:57 +020098 current += acpi_create_dmar_ds_ioapic(current,
Matt DeVillier85d98d92018-03-04 01:41:23 -060099 2, PCH_IOAPIC_PCI_BUS, PCH_IOAPIC_PCI_SLOT, 0);
100 size_t i;
101 for (i = 0; i < 8; ++i)
Matt DeVillier7866d492018-03-29 14:59:57 +0200102 current += acpi_create_dmar_ds_msi_hpet(current,
Matt DeVillier85d98d92018-03-04 01:41:23 -0600103 0, PCH_HPET_PCI_BUS,
104 PCH_HPET_PCI_SLOT, i);
105 acpi_dmar_drhd_fixup(tmp, current);
106 }
107
108 return current;
109}
110
111unsigned long northbridge_write_acpi_tables(struct device *const dev,
112 unsigned long current,
113 struct acpi_rsdp *const rsdp)
114{
115 /* Create DMAR table only if we have VT-d capability. */
116 const u32 capid0_a = pci_read_config32(dev, CAPID0_A);
117 if (capid0_a & VTD_DISABLE)
118 return current;
119
120 acpi_dmar_t *const dmar = (acpi_dmar_t *)current;
121 printk(BIOS_DEBUG, "ACPI: * DMAR\n");
122 acpi_create_dmar(dmar, DMAR_INTR_REMAP, acpi_fill_dmar);
123 current += dmar->header.length;
124 current = acpi_align_current(current);
125 acpi_add_table(rsdp, dmar);
126
127 return current;
128}