Angel Pons has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/48551 )
Change subject: WIP ......................................................................
WIP
Change-Id: Ieb0a18b64a9d6218a300ee646185fe75b7a8e5aa Signed-off-by: Angel Pons th3fanbus@gmail.com --- M src/northbridge/intel/sandybridge/Makefile.inc M src/northbridge/intel/sandybridge/early_init.c A src/northbridge/intel/sandybridge/early_peg.c M src/northbridge/intel/sandybridge/sandybridge.h 4 files changed, 284 insertions(+), 3 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/51/48551/1
diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index 6380681..02a4744 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -20,6 +20,7 @@ romstage-y += raminit_shared.c ifeq ($(CONFIG_USE_NATIVE_RAMINIT),y) romstage-y += early_dmi.c +romstage-y += early_peg.c romstage-y += raminit.c romstage-y += raminit_common.c romstage-y += raminit_iosav.c diff --git a/src/northbridge/intel/sandybridge/early_init.c b/src/northbridge/intel/sandybridge/early_init.c index 45b5b8f..2a8b6f4 100644 --- a/src/northbridge/intel/sandybridge/early_init.c +++ b/src/northbridge/intel/sandybridge/early_init.c @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-only */
+#include <arch/cpu.h> #include <console/console.h> +#include <cpu/intel/model_206ax/model_206ax.h> #include <device/mmio.h> #include <device/device.h> #include <device/pci_ops.h> @@ -121,8 +123,6 @@
static void start_peg_link_training(void) { - u32 deven; - const u16 base_rev = pci_read_config16(HOST_BRIDGE, PCI_DEVICE_ID) & BASE_REV_MASK; /* * PEG on IvyBridge+ needs a special startup sequence. @@ -131,7 +131,10 @@ if ((base_rev != BASE_REV_IVB) || CONFIG(HAVE_MRC)) return;
- deven = pci_read_config32(HOST_BRIDGE, DEVEN); + const u32 deven = pci_read_config32(HOST_BRIDGE, DEVEN); + + if (deven & DEVEN_PEG10) + init_peg_pre(PCI_DEV(0, 1, 0));
/* * For each PEG device, set bit 5 to use three retries for OC (Offset Calibration). @@ -148,6 +151,9 @@
if (deven & DEVEN_PEG60) pci_update_config32(PCI_DEV(0, 6, 0), AFE_PWRON, ~(1 << 16), 1 << 5); + + if (deven & DEVEN_PEG10) + init_peg_post(PCI_DEV(0, 1, 0)); }
void systemagent_early_init(void) diff --git a/src/northbridge/intel/sandybridge/early_peg.c b/src/northbridge/intel/sandybridge/early_peg.c new file mode 100644 index 0000000..30eb934 --- /dev/null +++ b/src/northbridge/intel/sandybridge/early_peg.c @@ -0,0 +1,270 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/cpu.h> +#include <console/console.h> +#include <cpu/intel/model_206ax/model_206ax.h> +#include <delay.h> +#include <device/mmio.h> +#include <device/device.h> +#include <device/pci_ops.h> +#include <device/pci_def.h> +#include <northbridge/intel/sandybridge/sandybridge.h> + +static void peg_update_field( + const pci_devfn_t dev, + const u32 offset, + const u32 mask, + const u32 value, + const u8 shift) +{ + pci_update_config32(dev, offset, ~(mask << shift), value << shift); +} + +static void peg_update_bundles( + const pci_devfn_t dev, + const u32 offset, + const u32 mask, + const u32 val, + const u8 shift) +{ + for (int i = 0; i < 8; i++) + peg_update_field(dev, offset + (i << 5), mask, val, shift); +} + +static void peg_update_lanes( + const pci_devfn_t dev, + const u32 offset, + const u32 mask, + const u32 val, + const u8 shift) +{ + for (int i = 0; i < 16; i++) + peg_update_field(dev, offset + (i << 4), mask, val, shift); +} + +static void peg_recipe(const pci_devfn_t dev) +{ + const u32 cpuid = cpu_get_cpuid(); + const u8 stepping = cpuid & 0xf; + + u32 value; + + /* E1 PWRFSM fix */ + if (stepping == IVB_STEP_E1) + peg_update_bundles(dev, 0x914, 1, 1, 31); + + /* UneqMM steps */ + peg_update_lanes(dev, 0xa00, 3, 0, 26); + peg_update_lanes(dev, 0xa04, 1, 1, 11); + + /* UneqMM Gen3 FIXME: PEG10 only */ + if (stepping >= IVB_STEP_C0) + peg_update_bundles(dev, 0x700, 7, 4, 10); + + /* Disable the 2nd order loop */ + peg_update_bundles(dev, 0x904, 7, 0, 22); + peg_update_bundles(dev, 0x90c, 7, 0, 17); + + /* fixrtermoffset */ + peg_update_bundles(dev, 0x90c, 0xf, 5, 21); + + /* Sampler Calibration step is done separately */ + + /* setcdrpg (PGACQ and PGTRK) */ + peg_update_bundles(dev, 0x904, 0x3f, 0x18, 16); + peg_update_bundles(dev, 0x90c, 0x3f, 0x09, 5); + + /* setl0sfixes */ + if (stepping >= IVB_STEP_C0) + peg_update_bundles(dev, 0x700, 1, 1, 15); + + /* setdfemfc */ + peg_update_lanes(dev, 0xa04, 3, 1, 17); + + /* setdfegainacq */ + peg_update_bundles(dev, 0x904, 3, 1, 29); + + /* setg2rxctlepeak */ + peg_update_bundles(dev, 0x910, 0xf, 0, 10); + + /* setg3rxctlepeak */ + value = stepping <= IVB_STEP_B0 ? 0 : 12; + peg_update_bundles(dev, 0x910, 0xf, value, 6); + + /* setVrefAdap */ + peg_update_lanes(dev, 0xa00, 0x1f, 12, 1); + + /* setctleoc */ + value = stepping >= IVB_STEP_C0 ? 1 : 0; + peg_update_lanes(dev, 0xa04, 1, value, 12); + + if (stepping >= IVB_STEP_C0) { + /* setdfelsbsel */ + peg_update_bundles(dev, 0x900, 3, 0, 26); + + /* setagcgainacq */ + peg_update_bundles(dev, 0x908, 3, 2, 27); + + /* setagcacqlen */ + peg_update_lanes(dev, 0xa00, 3, 2, 17); + + /* setsampleratspeedcal */ + peg_update_bundles(dev, 0x700, 1, 1, 3); + + /* setoffcorgain */ + peg_update_bundles(dev, 0x904, 3, 1, 10); + + /* setdfesumctl */ + peg_update_lanes(dev, 0xa00, 3, 3, 24); + } + + /* setrxvcmdssel */ + peg_update_bundles(dev, 0x908, 3, 1, 30); + + /* Swing Control: Reduced */ + if (stepping >= IVB_STEP_C0) { + /* setpegirefctl */ + peg_update_bundles(dev, 0x904, 0x1f, 0x05, 0); + + /* setpegtxvref */ + peg_update_bundles(dev, 0x904, 0x1f, 0x14, 5); + } + + /* fixtxrtermoffset = -3 */ + peg_update_bundles(dev, 0x90c, 0x1f, 0x7, 25); + + if (stepping >= IVB_STEP_K0) { + /* setK0ctocfix */ + peg_update_bundles(dev, 0x700, 1, 1, 21); + + /* setK0l0sfreezefix */ + peg_update_bundles(dev, 0x700, 3, 1, 24); + + /* setK0samplerfix */ + peg_update_bundles(dev, 0x700, 1, 1, 19); + + /* setK0resetalignfix */ + peg_update_bundles(dev, 0x700, 1, 1, 23); + + /* setK0cdcprotfix */ + peg_update_bundles(dev, 0x700, 1, 1, 22); + } + + /* setctleocgen2 */ + if (stepping >= IVB_STEP_D0) + peg_update_bundles(dev, 0x914, 1, 1, 9); + + /* + * ECO(3621419): Aggresive Rx L0s freeze resulting in Rx + * errors since AGC is in open loop for long time (L0s Exit) + */ + if (stepping >= IVB_STEP_E0) + peg_update_bundles(dev, 0x914, 1, 1, 27); + + if (stepping >= IVB_STEP_D0) { + /* setctleocgen3 */ + peg_update_bundles(dev, 0x914, 1, 1, 10); + + /* setD0dfemfcgen3 */ + peg_update_bundles(dev, 0x700, 3, 1, 27); + + /* setD0dfemfcctlegaingen3 */ + peg_update_bundles(dev, 0x700, 7, 0, 29); + + /* afeln0cfg0_d1f0.useerrd */ + peg_update_lanes(dev, 0xa00, 1, 1, 21); + } + + /* setD0disableL1exitfix */ + if (stepping >= IVB_STEP_D0) + peg_update_field(dev, 0xc38, 1, 1, 27); + + if (stepping >= IVB_STEP_D0) { + /* setD0dfeidacpdgen1 */ + peg_update_bundles(dev, 0x904, 0xf, 5, 25); + + /* setD0dfeidacpdgen2 */ + peg_update_bundles(dev, 0x914, 0xf, 0xd, 13); + + /* setD0dfeidacpdgen3 */ + peg_update_bundles(dev, 0x914, 0xf, 5, 8); + } + + pci_update_config32(dev, 0x308, ~0x7fff, 0x126c); + pci_update_config32(dev, 0x314, ~(0x7f << 16), 0x13 << 16); +} + +static void do_peg_gen3_equalization(const pci_devfn_t dev) +{ + u8 RootPortPreset[16]; + u8 EndPointPreset[16]; + u8 EndPointHint[16]; + + pci_or_config32(dev, 0xdd8, 3 << 14); + + for (int i = 0; i < 16; i++) { + RootPortPreset[i] = 8; + EndPointPreset[i] = 7; + EndPointHint[i] = 2; + } + + for (int i = 0; i < 8; ++i) { + pci_update_config32(dev, 0xDA0 + i * 4, 0x80F080F0, + RootPortPreset[2 * i] | + (EndPointPreset[2 * i] << 8) | + (EndPointHint[2 * i] << 12) | + (RootPortPreset[2 * i + 1] << 16) | + (EndPointPreset[2 * i + 1] << 24) | + (EndPointHint[2 * i + 1] << 28)); + } +} + +static void retrain_peg(const pci_devfn_t dev) +{ + pci_or_config8(dev, 0xb0, 1 << 5); + + //while (pci_read_config16(dev, 0xb2) & (1 << 11)) + // ; +} + +static void additional_peg_steps(const pci_devfn_t dev) +{ + peg_update_field(dev, 0x1fc, 1, 1, 21); + + /* Update the N_FTS values, requires link retrain */ + peg_update_field(dev, 0x22c, 0xffff, 0x403c, 0); + peg_update_field(dev, 0x228, 0x00ff, 0x001c, 0); + + retrain_peg(dev); +} + +void init_peg_pre(const pci_devfn_t dev) +{ + const bool gen3_capable = !(pci_read_config32(HOST_BRIDGE, CAPID0_B) & 1 << 20); + + pci_or_config32(dev, 0x250, 1 << 2); + + peg_recipe(dev); + + if (gen3_capable) + do_peg_gen3_equalization(dev); + + const u32 link_speed = gen3_capable ? 3 : 2; + + const u32 link_width = 16; + + pci_update_config32(dev, 0xac, ~0x3ff, (link_width - 1) << 4 | link_speed); + pci_update_config16(dev, 0xd0, ~0xf, link_speed); +} + +void init_peg_post(const pci_devfn_t dev) +{ + mdelay(100); + + pci_and_config32(dev, 0x250, ~(1 << 2)); + + /* Disable PEG Debug Align Message */ + peg_update_field(dev, 0x258, 1, 1, 29); + + additional_peg_steps(dev); +} diff --git a/src/northbridge/intel/sandybridge/sandybridge.h b/src/northbridge/intel/sandybridge/sandybridge.h index 235ca0e..80e62a3 100644 --- a/src/northbridge/intel/sandybridge/sandybridge.h +++ b/src/northbridge/intel/sandybridge/sandybridge.h @@ -84,6 +84,10 @@ void northbridge_romstage_finalize(int s3resume); void early_init_dmi(void);
+#include <device/pci_type.h> +void init_peg_pre(const pci_devfn_t dev); +void init_peg_post(const pci_devfn_t dev); + /* mainboard_early_init: Optional callback, run after console init but before raminit. */ void mainboard_early_init(int s3resume); int mainboard_should_reset_usb(int s3resume);