Angel Pons has uploaded this change for review.

View Change

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);

To view, visit change 48551. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: Ieb0a18b64a9d6218a300ee646185fe75b7a8e5aa
Gerrit-Change-Number: 48551
Gerrit-PatchSet: 1
Gerrit-Owner: Angel Pons <th3fanbus@gmail.com>
Gerrit-MessageType: newchange