diff options
author | Tristan Corrick <tristan@corrick.kiwi> | 2018-12-17 22:10:21 +1300 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2019-01-03 18:11:54 +0000 |
commit | 334be3289d6ca16e806bd1e2aef87637cebb3122 (patch) | |
tree | e9e50ce6ab73cd5d146be5aa0f7f25b584ac3c7f /src/northbridge/intel | |
parent | 05b75241565ae91d0b8ee8b45eb2d8ac55291297 (diff) |
nb/intel/haswell: Add support for PEG
This means that any PCIe device placed in a PEG slot should now work.
During S3 resume, link training sometimes does not complete before
device enumeration. However, no tangible issues have been observed.
Fixing it would introduce a rather large delay in S3 resume.
There are a few minor shortcomings:
- Using PEG for display output is not yet supported.
- Only PEG2 is supported. An extra (unknown) training sequence is said to
be needed for PEG3.
- The ACPI _PRT method is not yet generated, so legacy interrupt routing
doesn't work for devices with multiple functions.
Tested on an ASRock H81M-HDS. Using a Radeon HD 6450 graphics card works
under GNU/Linux, with PRIME [1]. An x1 PCIe card was also tested in the
PEG slot, and it appears functional.
[1]: https://wiki.archlinux.org/index.php/PRIME
Change-Id: I786ecb6eccad8de89778af7e736ed664323e220e
Signed-off-by: Tristan Corrick <tristan@corrick.kiwi>
Reviewed-on: https://review.coreboot.org/c/30272
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Diffstat (limited to 'src/northbridge/intel')
-rw-r--r-- | src/northbridge/intel/haswell/early_init.c | 70 | ||||
-rw-r--r-- | src/northbridge/intel/haswell/haswell.h | 1 |
2 files changed, 68 insertions, 3 deletions
diff --git a/src/northbridge/intel/haswell/early_init.c b/src/northbridge/intel/haswell/early_init.c index e31bb0e72c..75fc7a240d 100644 --- a/src/northbridge/intel/haswell/early_init.c +++ b/src/northbridge/intel/haswell/early_init.c @@ -19,9 +19,12 @@ #include <console/console.h> #include <arch/io.h> #include <device/pci_def.h> +#include <device/pci_ops.h> #include <elog.h> #include "haswell.h" +static bool peg_hidden[3]; + static void haswell_setup_bars(void) { printk(BIOS_DEBUG, "Setting up static northbridge registers..."); @@ -45,13 +48,13 @@ static void haswell_setup_bars(void) printk(BIOS_DEBUG, " done.\n"); } -static void haswell_setup_graphics(void) +static void haswell_setup_igd(void) { bool igd_enabled; u16 ggc; u8 reg8; - printk(BIOS_DEBUG, "Initializing Graphics...\n"); + printk(BIOS_DEBUG, "Initializing IGD...\n"); igd_enabled = !!(pci_read_config32(PCI_DEV(0, 0, 0), DEVEN) & DEVEN_D2EN); @@ -79,6 +82,66 @@ static void haswell_setup_graphics(void) pci_write_config8(PCI_DEV(0, 2, 0), MSAC, reg8); } +static void start_peg2_link_training(const pci_devfn_t dev) +{ + u32 mask; + + switch (dev) { + case PCI_DEV(0, 1, 2): + mask = DEVEN_D1F2EN; + break; + case PCI_DEV(0, 1, 1): + mask = DEVEN_D1F1EN; + break; + case PCI_DEV(0, 1, 0): + mask = DEVEN_D1F0EN; + break; + default: + printk(BIOS_ERR, "Link training tried on a non-PEG device!\n"); + return; + } + + pci_update_config32(dev, 0xc24, ~(1 << 16), 1 << 5); + printk(BIOS_DEBUG, "Started PEG1%d link training.\n", PCI_FUNC(dev)); + + /* + * The PEG device is hidden while the MRC runs. This is because the + * MRC makes configurations that are not ideal if it sees a VGA + * device in a PEG slot, and it locks registers preventing changes + * to these configurations. + */ + pci_update_config32(PCI_DEV(0, 0, 0), DEVEN, ~mask, 0); + peg_hidden[PCI_FUNC(dev)] = true; + printk(BIOS_DEBUG, "Temporarily hiding PEG1%d.\n", PCI_FUNC(dev)); +} + +void haswell_unhide_peg(void) +{ + u32 deven = pci_read_config32(PCI_DEV(0, 0, 0), DEVEN); + + for (u8 fn = 0; fn <= 2; fn++) { + if (peg_hidden[fn]) { + deven |= DEVEN_D1F0EN >> fn; + peg_hidden[fn] = false; + printk(BIOS_DEBUG, "Unhiding PEG1%d.\n", fn); + } + } + + pci_write_config32(PCI_DEV(0, 0, 0), DEVEN, deven); +} + +static void haswell_setup_peg(void) +{ + u32 deven = pci_read_config32(PCI_DEV(0, 0, 0), DEVEN); + + if (deven & DEVEN_D1F2EN) + start_peg2_link_training(PCI_DEV(0, 1, 2)); + if (deven & DEVEN_D1F1EN) + start_peg2_link_training(PCI_DEV(0, 1, 1)); + if (deven & DEVEN_D1F0EN) + start_peg2_link_training(PCI_DEV(0, 1, 0)); +} + static void haswell_setup_misc(void) { u32 reg32; @@ -140,7 +203,8 @@ void haswell_early_initialization(int chipset_type) /* Setup IOMMU BARs */ haswell_setup_iommu(); - haswell_setup_graphics(); + haswell_setup_peg(); + haswell_setup_igd(); haswell_setup_misc(); } diff --git a/src/northbridge/intel/haswell/haswell.h b/src/northbridge/intel/haswell/haswell.h index bc2fc60e40..f67995d4e9 100644 --- a/src/northbridge/intel/haswell/haswell.h +++ b/src/northbridge/intel/haswell/haswell.h @@ -221,6 +221,7 @@ void intel_northbridge_haswell_finalize_smm(void); void haswell_early_initialization(int chipset_type); void haswell_late_initialization(void); void set_translation_table(int start, int end, u64 base, int inc); +void haswell_unhide_peg(void); /* debugging functions */ void print_pci_devices(void); |