summaryrefslogtreecommitdiff
path: root/config/coreboot/default/patches
diff options
context:
space:
mode:
Diffstat (limited to 'config/coreboot/default/patches')
-rw-r--r--config/coreboot/default/patches/0001-add-c3-and-clockgen-to-apple-macbook21.patch4
-rw-r--r--config/coreboot/default/patches/0002-lenovo-t400-Enable-all-SATA-ports.patch4
-rw-r--r--config/coreboot/default/patches/0003-lenovo-x230-set-me_state-Disabled-in-cmos.default.patch4
-rw-r--r--config/coreboot/default/patches/0004-set-me_state-Disabled-on-all-cmos.default-files.patch4
-rw-r--r--config/coreboot/default/patches/0005-util-ifdtool-add-nuke-flag-all-0xFF-on-region.patch28
-rw-r--r--config/coreboot/default/patches/0006-mb-dell-e6400-Enable-01.0-device-in-devicetree-for-d.patch4
-rw-r--r--config/coreboot/default/patches/0007-Remove-warning-for-coreboot-images-built-without-a-p.patch4
-rw-r--r--config/coreboot/default/patches/0008-HACK-Disable-coreboot-related-BL31-features.patch (renamed from config/coreboot/default/patches/0018-HACK-Disable-coreboot-related-BL31-features.patch)8
-rw-r--r--config/coreboot/default/patches/0008-mb-dell-Add-Latitude-E6530-Ivy-Bridge.patch430
-rw-r--r--config/coreboot/default/patches/0009-dell-e6430-use-ME-Soft-Temporary-Disable.patch (renamed from config/coreboot/default/patches/0019-dell-e6430-use-ME-Soft-Temporary-Disable.patch)4
-rw-r--r--config/coreboot/default/patches/0009-mb-dell-Add-Latitude-E5530-Ivy-Bridge.patch430
-rw-r--r--config/coreboot/default/patches/0010-mb-dell-Add-Latitude-E6420-Sandy-Bridge.patch435
-rw-r--r--config/coreboot/default/patches/0010-mb-hp-Add-Compaq-Elite-8300-CMT-port.patch (renamed from config/coreboot/default/patches/0020-mb-hp-Add-Compaq-Elite-8300-CMT-port.patch)4
-rw-r--r--config/coreboot/default/patches/0011-mb-dell-Add-Latitude-E6520-Sandy-Bridge.patch449
-rw-r--r--config/coreboot/default/patches/0011-nb-intel-haswell-make-IOMMU-a-runtime-option.patch (renamed from config/coreboot/default/patches/0021-nb-intel-haswell-make-IOMMU-a-runtime-option.patch)4
-rw-r--r--config/coreboot/default/patches/0012-dell-optiplex_9020-Disable-IOMMU-by-default.patch (renamed from config/coreboot/default/patches/0022-dell-optiplex_9020-Disable-IOMMU-by-default.patch)4
-rw-r--r--config/coreboot/default/patches/0012-mb-dell-Add-Latitude-E5520-Sandy-Bridge.patch442
-rw-r--r--config/coreboot/default/patches/0013-mb-dell-Add-Latitude-E5420-Sandy-Bridge.patch442
-rw-r--r--config/coreboot/default/patches/0013-nb-haswell-Fully-disable-iGPU-when-dGPU-is-used.patch (renamed from config/coreboot/default/patches/0023-nb-haswell-Fully-disable-iGPU-when-dGPU-is-used.patch)4
-rw-r--r--config/coreboot/default/patches/0014-ec-dell-mec5035-Add-S3-suspend-SMI-handler.patch (renamed from config/coreboot/default/patches/0025-ec-dell-mec5035-Add-S3-suspend-SMI-handler.patch)4
-rw-r--r--config/coreboot/default/patches/0014-mb-dell-Add-Latitude-E6320-Sandy-Bridge.patch435
-rw-r--r--config/coreboot/default/patches/0015-mb-dell-Add-Latitude-E6220-Sandy-Bridge.patch438
-rw-r--r--config/coreboot/default/patches/0015-nb-haswell-lock-policy-regs-when-disabling-IOMMU.patch (renamed from config/coreboot/default/patches/0026-nb-haswell-lock-policy-regs-when-disabling-IOMMU.patch)4
-rw-r--r--config/coreboot/default/patches/0016-mb-dell-Add-Latitude-E6330-Ivy-Bridge.patch436
-rw-r--r--config/coreboot/default/patches/0016-nb-intel-gm45-Make-DDR2-raminit-work.patch (renamed from config/coreboot/default/patches/0027-nb-intel-gm45-Make-DDR2-raminit-work.patch)4
-rw-r--r--config/coreboot/default/patches/0017-mb-dell-Add-Latitude-E6230-Ivy-Bridge.patch440
-rw-r--r--config/coreboot/default/patches/0017-nb-gm45-Fix-Angel-s-DDR2-RCOMP-fix-on-DDR3-boards.patch (renamed from config/coreboot/default/patches/0028-nb-gm45-Fix-Angel-s-DDR2-RCOMP-fix-on-DDR3-boards.patch)4
-rw-r--r--config/coreboot/default/patches/0018-mb-dell-e6400-Use-100-MHz-reference-clock-for-displa.patch (renamed from config/coreboot/default/patches/0029-mb-dell-e6400-Use-100-MHz-reference-clock-for-displa.patch)6
-rw-r--r--config/coreboot/default/patches/0019-nb-x4x-define-INTEL_GMA_DPLL_REF_FREQ.patch (renamed from config/coreboot/default/patches/0047-nb-x4x-define-INTEL_GMA_DPLL_REF_FREQ.patch)6
-rw-r--r--config/coreboot/default/patches/0020-mb-dell-Convert-E6400-into-a-variant.patch (renamed from config/coreboot/default/patches/0048-mb-dell-Convert-E6400-into-a-variant.patch)4
-rw-r--r--config/coreboot/default/patches/0021-mb-dell-gm45_latitudes-Add-E4300-variant.patch (renamed from config/coreboot/default/patches/0049-mb-dell-gm45_latitudes-Add-E4300-variant.patch)4
-rw-r--r--config/coreboot/default/patches/0022-mb-dell-Add-S3-SMI-handler-for-Dell-Latitudes.patch (renamed from config/coreboot/default/patches/0050-mb-dell-Add-S3-SMI-handler-for-Dell-Latitudes.patch)4
-rw-r--r--config/coreboot/default/patches/0023-ec-dell-mec5035-Route-power-button-event-to-host.patch (renamed from config/coreboot/default/patches/0051-ec-dell-mec5035-Route-power-button-event-to-host.patch)4
-rw-r--r--config/coreboot/default/patches/0024-Disable-compression-on-refcode-insertion.patch (renamed from config/coreboot/default/patches/0052-Disable-compression-on-refcode-insertion.patch)8
-rw-r--r--config/coreboot/default/patches/0024-ec-dell-mec5035-Replace-defines-with-enums.patch91
-rw-r--r--config/coreboot/default/patches/0025-nb-intel-Disable-stack-overflow-debug-options.patch187
-rw-r--r--config/coreboot/default/patches/0026-soc-intel-skylake-configure-usb-acpi.patch94
-rw-r--r--config/coreboot/default/patches/0027-soc-intel-skylake-Enable-4E-4F-PNP-I-O-ports-in-boot.patch30
-rw-r--r--config/coreboot/default/patches/0028-mb-lenovo-Add-ThinkPad-T480-and-ThinkPad-T480s.patch2232
-rw-r--r--config/coreboot/default/patches/0029-mb-dell-Add-Optiplex-780-MT-x4x-ICH10.patch708
-rw-r--r--config/coreboot/default/patches/0030-haswell-NRI-Initialise-MPLL.patch348
-rw-r--r--config/coreboot/default/patches/0030-mb-dell-optiplex_780-Add-USFF-variant.patch326
-rw-r--r--config/coreboot/default/patches/0031-dell-3050micro-disable-nvme-hotplug.patch49
-rw-r--r--config/coreboot/default/patches/0031-haswell-NRI-Post-process-selected-timings.patch249
-rw-r--r--config/coreboot/default/patches/0032-haswell-NRI-Configure-initial-MC-settings.patch1594
-rw-r--r--config/coreboot/default/patches/0032-lenovo-Add-Kconfig-option-CONFIG_LENOVO_TBFW_BIN.patch78
-rw-r--r--config/coreboot/default/patches/0033-haswell-NRI-Add-timings-refresh-programming.patch541
-rw-r--r--config/coreboot/default/patches/0033-soc-intel-skylake-Don-t-compress-FSP-S.patch36
-rw-r--r--config/coreboot/default/patches/0034-haswell-NRI-Program-memory-map.patch263
-rw-r--r--config/coreboot/default/patches/0034-soc-intel-pmc-Hardcoded-poweroff-after-power-fail.patch82
-rw-r--r--config/coreboot/default/patches/0035-haswell-NRI-Add-DDR3-JEDEC-reset-and-init.patch1036
-rw-r--r--config/coreboot/default/patches/0035-src-intel-skylake-Disable-stack-overflow-debug-optio.patch61
-rw-r--r--config/coreboot/default/patches/0036-haswell-NRI-Add-pre-training-steps.patch392
-rw-r--r--config/coreboot/default/patches/0036-src-intel-x4x-Disable-stack-overflow-debug.patch33
-rw-r--r--config/coreboot/default/patches/0037-Conditional-TBFW-setting-for-T480-T480S.patch37
-rw-r--r--config/coreboot/default/patches/0037-haswell-NRI-Add-REUT-I-O-test-library.patch1130
-rw-r--r--config/coreboot/default/patches/0038-do-not-break-building-other-thinkpads-with-the-hacks.patch153
-rw-r--r--config/coreboot/default/patches/0038-haswell-NRI-Add-range-tracking-library.patch222
-rw-r--r--config/coreboot/default/patches/0039-haswell-NRI-Add-library-to-change-margins.patch294
-rw-r--r--config/coreboot/default/patches/0040-haswell-NRI-Add-RcvEn-training.patch708
-rw-r--r--config/coreboot/default/patches/0041-haswell-NRI-Add-function-to-change-margins.patch272
-rw-r--r--config/coreboot/default/patches/0042-haswell-NRI-Add-read-MPR-training.patch332
-rw-r--r--config/coreboot/default/patches/0043-haswell-NRI-Add-write-leveling.patch689
-rw-r--r--config/coreboot/default/patches/0044-haswell-NRI-Add-final-raminit-steps.patch570
-rw-r--r--config/coreboot/default/patches/0045-Haswell-NRI-Implement-fast-boot-path.patch722
-rw-r--r--config/coreboot/default/patches/0046-haswell-NRI-Do-sense-amplifier-offset-training.patch476
66 files changed, 4172 insertions, 14372 deletions
diff --git a/config/coreboot/default/patches/0001-add-c3-and-clockgen-to-apple-macbook21.patch b/config/coreboot/default/patches/0001-add-c3-and-clockgen-to-apple-macbook21.patch
index da4ab420..31c1bb30 100644
--- a/config/coreboot/default/patches/0001-add-c3-and-clockgen-to-apple-macbook21.patch
+++ b/config/coreboot/default/patches/0001-add-c3-and-clockgen-to-apple-macbook21.patch
@@ -1,7 +1,7 @@
-From f625e31ee3abb867e775ab0cb724550825699c36 Mon Sep 17 00:00:00 2001
+From bd959c38f6ee21db1ff8f4fbb0675e38bfbe1147 Mon Sep 17 00:00:00 2001
From: Vitali64 <5405891-vitali64yt@users.noreply.gitlab.com>
Date: Wed, 27 Oct 2021 13:36:01 +0200
-Subject: [PATCH 01/51] add c3 and clockgen to apple/macbook21
+Subject: [PATCH 01/37] add c3 and clockgen to apple/macbook21
---
src/mainboard/apple/macbook21/Kconfig | 1 +
diff --git a/config/coreboot/default/patches/0002-lenovo-t400-Enable-all-SATA-ports.patch b/config/coreboot/default/patches/0002-lenovo-t400-Enable-all-SATA-ports.patch
index ee605e58..0c2b080f 100644
--- a/config/coreboot/default/patches/0002-lenovo-t400-Enable-all-SATA-ports.patch
+++ b/config/coreboot/default/patches/0002-lenovo-t400-Enable-all-SATA-ports.patch
@@ -1,7 +1,7 @@
-From 8821f229d4fe48153ec7a45e0e04c3b2a3cd8c7c Mon Sep 17 00:00:00 2001
+From e5eab4c8043b89a325b4a28bf7da456d68475144 Mon Sep 17 00:00:00 2001
From: persmule <persmule@gmail.com>
Date: Sun, 31 Oct 2021 23:33:26 +0000
-Subject: [PATCH 02/51] lenovo/t400: Enable all SATA ports
+Subject: [PATCH 02/37] lenovo/t400: Enable all SATA ports
There are 2 SATA ports on the chassis of t400(s), but at least one dock for
t400 contains a port for (P/S)ATA device, and t400s has a eSATA port on its
diff --git a/config/coreboot/default/patches/0003-lenovo-x230-set-me_state-Disabled-in-cmos.default.patch b/config/coreboot/default/patches/0003-lenovo-x230-set-me_state-Disabled-in-cmos.default.patch
index a4b430fe..4ccde9a6 100644
--- a/config/coreboot/default/patches/0003-lenovo-x230-set-me_state-Disabled-in-cmos.default.patch
+++ b/config/coreboot/default/patches/0003-lenovo-x230-set-me_state-Disabled-in-cmos.default.patch
@@ -1,7 +1,7 @@
-From 0298639b6e80c8950fbb4484180b7195883ab8c1 Mon Sep 17 00:00:00 2001
+From fd398cc10600cccce3dd4931651a5294ffebde9a Mon Sep 17 00:00:00 2001
From: Leah Rowe <leah@libreboot.org>
Date: Mon, 3 Jan 2022 19:06:22 +0000
-Subject: [PATCH 03/51] lenovo/x230: set me_state=Disabled in cmos.default
+Subject: [PATCH 03/37] lenovo/x230: set me_state=Disabled in cmos.default
I only recently found out about this. It's possible to use me_cleaner to
do the same thing, but some people might just flash coreboot and not do
diff --git a/config/coreboot/default/patches/0004-set-me_state-Disabled-on-all-cmos.default-files.patch b/config/coreboot/default/patches/0004-set-me_state-Disabled-on-all-cmos.default-files.patch
index 71695404..39319d58 100644
--- a/config/coreboot/default/patches/0004-set-me_state-Disabled-on-all-cmos.default-files.patch
+++ b/config/coreboot/default/patches/0004-set-me_state-Disabled-on-all-cmos.default-files.patch
@@ -1,7 +1,7 @@
-From c697c90ace86edfe724c86bd6a680cf0ae0e4b58 Mon Sep 17 00:00:00 2001
+From 74230d8123cb7c31afd084658720084b1a5ac5d9 Mon Sep 17 00:00:00 2001
From: Leah Rowe <leah@libreboot.org>
Date: Wed, 2 Mar 2022 21:50:01 +0000
-Subject: [PATCH 04/51] set me_state=Disabled on all cmos.default files!
+Subject: [PATCH 04/37] set me_state=Disabled on all cmos.default files!
yeah. why the hell isn't this the default
diff --git a/config/coreboot/default/patches/0005-util-ifdtool-add-nuke-flag-all-0xFF-on-region.patch b/config/coreboot/default/patches/0005-util-ifdtool-add-nuke-flag-all-0xFF-on-region.patch
index b7b514cd..9c00ab79 100644
--- a/config/coreboot/default/patches/0005-util-ifdtool-add-nuke-flag-all-0xFF-on-region.patch
+++ b/config/coreboot/default/patches/0005-util-ifdtool-add-nuke-flag-all-0xFF-on-region.patch
@@ -1,7 +1,7 @@
-From d2f579b82921c2c35e4cf756db0ca476fbadfac1 Mon Sep 17 00:00:00 2001
+From f592ac32892d7f99fa2e68504bb147e5d06184ca Mon Sep 17 00:00:00 2001
From: Leah Rowe <info@minifree.org>
Date: Sun, 19 Feb 2023 18:21:43 +0000
-Subject: [PATCH 05/51] util/ifdtool: add --nuke flag (all 0xFF on region)
+Subject: [PATCH 05/37] util/ifdtool: add --nuke flag (all 0xFF on region)
When this option is used, the region's contents are overwritten
with all ones (0xFF).
@@ -20,10 +20,10 @@ Signed-off-by: Leah Rowe <leah@libreboot.org>
1 file changed, 83 insertions(+), 31 deletions(-)
diff --git a/util/ifdtool/ifdtool.c b/util/ifdtool/ifdtool.c
-index 32b2081d93..1473cf058b 100644
+index b21a89c0e1..fc91d4c239 100644
--- a/util/ifdtool/ifdtool.c
+++ b/util/ifdtool/ifdtool.c
-@@ -2204,6 +2204,7 @@ static void print_usage(const char *name)
+@@ -2230,6 +2230,7 @@ static void print_usage(const char *name)
" tgl - Tiger Lake\n"
" wbg - Wellsburg\n"
" -S | --setpchstrap Write a PCH strap\n"
@@ -31,7 +31,7 @@ index 32b2081d93..1473cf058b 100644
" -V | --newvalue The new value to write into PCH strap specified by -S\n"
" -v | --version: print the version\n"
" -h | --help: print this help\n\n"
-@@ -2212,6 +2213,60 @@ static void print_usage(const char *name)
+@@ -2238,6 +2239,60 @@ static void print_usage(const char *name)
"\n");
}
@@ -92,15 +92,15 @@ index 32b2081d93..1473cf058b 100644
int main(int argc, char *argv[])
{
int opt, option_index = 0;
-@@ -2219,6 +2274,7 @@ int main(int argc, char *argv[])
+@@ -2245,6 +2300,7 @@ int main(int argc, char *argv[])
int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
int mode_read = 0, mode_altmedisable = 0, altmedisable = 0, mode_fmap_template = 0;
+ int mode_nuke = 0;
int mode_gpr0_disable = 0, mode_gpr0_enable = 0, mode_gpr0_status = 0;
- char *region_type_string = NULL, *region_fname = NULL;
- const char *layout_fname = NULL;
-@@ -2254,6 +2310,7 @@ int main(int argc, char *argv[])
+ char *region_type_string = NULL, *region_fname = NULL, *layout_fname = NULL;
+ char *new_filename = NULL;
+@@ -2279,6 +2335,7 @@ int main(int argc, char *argv[])
{"validate", 0, NULL, 't'},
{"setpchstrap", 1, NULL, 'S'},
{"newvalue", 1, NULL, 'V'},
@@ -108,7 +108,7 @@ index 32b2081d93..1473cf058b 100644
{0, 0, 0, 0}
};
-@@ -2303,35 +2360,8 @@ int main(int argc, char *argv[])
+@@ -2328,35 +2385,8 @@ int main(int argc, char *argv[])
region_fname++;
// Descriptor, BIOS, ME, GbE, Platform
// valid type?
@@ -146,7 +146,7 @@ index 32b2081d93..1473cf058b 100644
fprintf(stderr, "No such region type: '%s'\n\n",
region_type_string);
fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
-@@ -2508,6 +2538,22 @@ int main(int argc, char *argv[])
+@@ -2533,6 +2563,22 @@ int main(int argc, char *argv[])
case 't':
mode_validate = 1;
break;
@@ -169,7 +169,7 @@ index 32b2081d93..1473cf058b 100644
case 'v':
print_version();
exit(EXIT_SUCCESS);
-@@ -2524,7 +2570,8 @@ int main(int argc, char *argv[])
+@@ -2552,7 +2598,8 @@ int main(int argc, char *argv[])
if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject +
mode_setstrap + mode_newlayout + (mode_spifreq | mode_em100 |
mode_unlocked | mode_locked) + mode_altmedisable + mode_validate +
@@ -179,7 +179,7 @@ index 32b2081d93..1473cf058b 100644
fprintf(stderr, "You may not specify more than one mode.\n\n");
fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
exit(EXIT_FAILURE);
-@@ -2533,7 +2580,8 @@ int main(int argc, char *argv[])
+@@ -2561,7 +2608,8 @@ int main(int argc, char *argv[])
if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject +
mode_setstrap + mode_newlayout + mode_spifreq + mode_em100 +
mode_locked + mode_unlocked + mode_density + mode_altmedisable +
@@ -189,7 +189,7 @@ index 32b2081d93..1473cf058b 100644
fprintf(stderr, "You need to specify a mode.\n\n");
fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
exit(EXIT_FAILURE);
-@@ -2646,6 +2694,10 @@ int main(int argc, char *argv[])
+@@ -2674,6 +2722,10 @@ int main(int argc, char *argv[])
write_image(new_filename, image, size);
}
diff --git a/config/coreboot/default/patches/0006-mb-dell-e6400-Enable-01.0-device-in-devicetree-for-d.patch b/config/coreboot/default/patches/0006-mb-dell-e6400-Enable-01.0-device-in-devicetree-for-d.patch
index 71f2f22d..ee60c3c8 100644
--- a/config/coreboot/default/patches/0006-mb-dell-e6400-Enable-01.0-device-in-devicetree-for-d.patch
+++ b/config/coreboot/default/patches/0006-mb-dell-e6400-Enable-01.0-device-in-devicetree-for-d.patch
@@ -1,7 +1,7 @@
-From a5bc59037dabd95b6595c5aaf38b83da2a91de54 Mon Sep 17 00:00:00 2001
+From 18069af7c0c6beedfadb615cca9127e82a0d8007 Mon Sep 17 00:00:00 2001
From: Nicholas Chin <nic.c3.14@gmail.com>
Date: Sat, 6 May 2023 15:53:41 -0600
-Subject: [PATCH 06/51] mb/dell/e6400: Enable 01.0 device in devicetree for
+Subject: [PATCH 06/37] mb/dell/e6400: Enable 01.0 device in devicetree for
dGPU models
Change-Id: I9b8e5d3cd1e1f64dc87b682b1e045b6342924aed
diff --git a/config/coreboot/default/patches/0007-Remove-warning-for-coreboot-images-built-without-a-p.patch b/config/coreboot/default/patches/0007-Remove-warning-for-coreboot-images-built-without-a-p.patch
index fa364ca1..525bd366 100644
--- a/config/coreboot/default/patches/0007-Remove-warning-for-coreboot-images-built-without-a-p.patch
+++ b/config/coreboot/default/patches/0007-Remove-warning-for-coreboot-images-built-without-a-p.patch
@@ -1,7 +1,7 @@
-From f883599a362f1383f3712b72516f76187d0a9cbe Mon Sep 17 00:00:00 2001
+From 9563c107a4b40e66b610d7205a21590c7c181c78 Mon Sep 17 00:00:00 2001
From: Nicholas Chin <nic.c3.14@gmail.com>
Date: Fri, 12 May 2023 19:55:15 -0600
-Subject: [PATCH 07/51] Remove warning for coreboot images built without a
+Subject: [PATCH 07/37] Remove warning for coreboot images built without a
payload
I added this in upstream to prevent people from accidentally flashing
diff --git a/config/coreboot/default/patches/0018-HACK-Disable-coreboot-related-BL31-features.patch b/config/coreboot/default/patches/0008-HACK-Disable-coreboot-related-BL31-features.patch
index 9592215d..bd2c56bd 100644
--- a/config/coreboot/default/patches/0018-HACK-Disable-coreboot-related-BL31-features.patch
+++ b/config/coreboot/default/patches/0008-HACK-Disable-coreboot-related-BL31-features.patch
@@ -1,7 +1,7 @@
-From ec27f5414c78d493ec7be4cd055ac877ce9ea178 Mon Sep 17 00:00:00 2001
+From 7f650a19d30fe6157b150c5248d6086007323d72 Mon Sep 17 00:00:00 2001
From: Alper Nebi Yasak <alpernebiyasak@gmail.com>
Date: Thu, 22 Jun 2023 16:44:27 +0300
-Subject: [PATCH 18/51] HACK: Disable coreboot related BL31 features
+Subject: [PATCH 08/37] HACK: Disable coreboot related BL31 features
I don't know why, but removing this BL31 make argument lets gru-kevin
power off properly when shut down from Linux. Needs investigation.
@@ -10,10 +10,10 @@ power off properly when shut down from Linux. Needs investigation.
1 file changed, 3 deletions(-)
diff --git a/src/arch/arm64/Makefile.mk b/src/arch/arm64/Makefile.mk
-index cb43897efd..a9e5ff399a 100644
+index f54c6d22fc..b075abfd42 100644
--- a/src/arch/arm64/Makefile.mk
+++ b/src/arch/arm64/Makefile.mk
-@@ -173,9 +173,6 @@ BL31_MAKEARGS += LOG_LEVEL=40
+@@ -162,9 +162,6 @@ BL31_MAKEARGS += LOG_LEVEL=40
# Always enable crash reporting, even on a release build
BL31_MAKEARGS += CRASH_REPORTING=1
diff --git a/config/coreboot/default/patches/0008-mb-dell-Add-Latitude-E6530-Ivy-Bridge.patch b/config/coreboot/default/patches/0008-mb-dell-Add-Latitude-E6530-Ivy-Bridge.patch
deleted file mode 100644
index 48b9d21e..00000000
--- a/config/coreboot/default/patches/0008-mb-dell-Add-Latitude-E6530-Ivy-Bridge.patch
+++ /dev/null
@@ -1,430 +0,0 @@
-From 40545928c415c27d3a30748e4bfdee7f9d8f82f9 Mon Sep 17 00:00:00 2001
-From: Nicholas Chin <nic.c3.14@gmail.com>
-Date: Sat, 19 Aug 2023 16:19:10 -0600
-Subject: [PATCH 08/51] mb/dell: Add Latitude E6530 (Ivy Bridge)
-
-Mainboard is QALA0/LA-7761P (UMA). The version with a Nvidia dGPU was
-not tested. I do not physically have this system; someone with physical
-access to one sent me the output of autoport which I then modified to
-produce this port.
-
-I was also sent the vbios obtained using intel_bios_dumper while running
-version A22 of the vendor firmware, which I then processed using
-`intelvbttool --inoprom vbios.bin --outvbt data.vbt` to obtain data.vbt.
-
-This was originally tested and found to be working as a standalone board
-port in Libreboot, though this variant based port in upstream coreboot
-has not been tested.
-
-This can be internally flashed by sending a command to the EC, which
-causes the EC to pull the FDO pin low and the firmware to skip setting
-up any chipset based write protections [1]. The EC is the SMSC MEC5055,
-which seems to be compatible with the existing MEC5035 code.
-
-[1] https://gitlab.com/nic3-14159/dell-flash-unlock
-
-Change-Id: I9fcd73416018574f8934962f92c8222d0101cb71
-Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>
----
- src/mainboard/dell/snb_ivb_latitude/Kconfig | 8 +
- .../dell/snb_ivb_latitude/Kconfig.name | 3 +
- .../snb_ivb_latitude/variants/e6530/data.vbt | Bin 0 -> 4280 bytes
- .../variants/e6530/early_init.c | 14 ++
- .../snb_ivb_latitude/variants/e6530/gpio.c | 192 ++++++++++++++++++
- .../variants/e6530/hda_verb.c | 32 +++
- .../variants/e6530/overridetree.cb | 37 ++++
- 7 files changed, 286 insertions(+)
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6530/data.vbt
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6530/early_init.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6530/gpio.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6530/hda_verb.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6530/overridetree.cb
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-index be9ac37845..03377275f0 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-@@ -23,6 +23,12 @@ config BOARD_DELL_LATITUDE_E6430
- select MAINBOARD_USES_IFD_GBE_REGION
- select SOUTHBRIDGE_INTEL_C216
-
-+config BOARD_DELL_LATITUDE_E6530
-+ select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
-+ select BOARD_ROMSIZE_KB_12288
-+ select MAINBOARD_USES_IFD_GBE_REGION
-+ select SOUTHBRIDGE_INTEL_C216
-+
- if BOARD_DELL_SNB_IVB_LATITUDE_COMMON
-
- config DRAM_RESET_GATE_GPIO
-@@ -33,6 +39,7 @@ config MAINBOARD_DIR
-
- config MAINBOARD_PART_NUMBER
- default "Latitude E6430" if BOARD_DELL_LATITUDE_E6430
-+ default "Latitude E6530" if BOARD_DELL_LATITUDE_E6530
-
- config OVERRIDE_DEVICETREE
- default "variants/\$(CONFIG_VARIANT_DIR)/overridetree.cb"
-@@ -42,6 +49,7 @@ config USBDEBUG_HCD_INDEX
-
- config VARIANT_DIR
- default "e6430" if BOARD_DELL_LATITUDE_E6430
-+ default "e6530" if BOARD_DELL_LATITUDE_E6530
-
- config VGA_BIOS_ID
- default "8086,0166"
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-index 183252630a..d89185d670 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-@@ -2,3 +2,6 @@
-
- config BOARD_DELL_LATITUDE_E6430
- bool "Latitude E6430"
-+
-+config BOARD_DELL_LATITUDE_E6530
-+ bool "Latitude E6530"
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6530/data.vbt b/src/mainboard/dell/snb_ivb_latitude/variants/e6530/data.vbt
-new file mode 100644
-index 0000000000000000000000000000000000000000..af64a913d521fe240ce30e114e90fe75d3841bbc
-GIT binary patch
-literal 4280
-zcmdT{U2GiH75-*te`aTAcGqJQY$rA+e`ZbWcy_TDH@NC}cbl$*NjAn^RtPm->J7GV
-zY_m3jN`RN*h9FvG3Do9+qP$c^s1;PLB3@br9>Ag%La5?TLP`-2DDaR65U2_)=g!QU
-zIJ+cPr4+cc-@WIad+wQY&YW{+c1J!nPPgn&^^N3Hy*D37jg0=7CSl@*=mXr>x75gi
-zTMlK0$A=H4Mh~QKqCa92jz_;d3rtFqp(o-4gCnzxrJ2}Rw@^!haWp<ahv&+aDb5_3
-zE0-vq=pkms7Ves!pD#^PA#PF^_wjBTO=oC(ayR{asyKURiBdh3?x76Ll#Z5WXklvl
-z@M5XFK#OxUXqrdzedca+l4WK~_tG8Hv&HgsX`$Za3pnYy`CpW$@0?nsSh|}MrfK#j
-z%y^t^lPNt{p5INwGcz<MWEN<wv`{J^Eluv$Rb2&6%ZgV5Bp(6~Lz2Eoz~@C!!B)bs
-z1x-OrK~}*8L07Po(5+xZL6I<}phTEf5QRsVJYHa{f^AXPFaoSsnJ0feXUdB=CJ>Fv
-zr&_=Q6YubieL}zoiJ0a+c+(bGwFN5g1pz;^rGP1sM+lHB@UAPM2&F=RB&yv@$caXF
-ze~Io&3CQe=cMHr!e{yiokd?~p&F&k`jg99Ex7}WO=$8*Kx8wXv4eSa_CJqKVkyRr&
-zCdcqs*@M5!gD84e@fW{|5B#mDGTH;JFw`h^stQcTjf@V3pNe8&f$=NG?-+klRGea*
-zX1vOHi}4@EM~qJyfuM>e#%9J&Mjzt`j5OnB#;uGZ<1WTMj3vgSj3*esXZY{I`KqUa
-zfbB~~a>piTMAVDNyHR<{<v-=}gXhE(15|emxueb8Kv%5>0{F7}8pool{7_h6u?7yg
-zlyNm>-Eq_&WjW{0$9ZHq6x?~W8l2#1g0CyrtN#R-nbWG(?>iNG1zRiZgj;Lm_%rVe
-zwZ6i{g#sR5xudpbj~5H9TNIQ3gMikIG@l(Z4IR@^2|Vu|LZteLF5@$KH5`Pr&3_vn
-z^!Fn27&z6hSPR+*;D*&lm-)OE=ZgjK*(X&XdBq7RDUd7>|Lou?UMNg6lVCB;TPz{Z
-zN4-~p*Rr=uq8OYdlAy38{}dt5%2}aUax{}zWzDRgmsn2|!)=Bp)U35;Ld3H+Ye=*_
-z4S&0{5*TVI!OU-SWz$XUwrrnb%9?NHau^uhn>&;%&X#8O7mt)SIJr8D$u?NS=rUW6
-zCmnxV&FgUDAWX}gZ+1AH&-C4Q=3sl5RX9=OWPfCtcRZi4tkX44YYfRH*@?H7T=Kz=
-zG*i-wU2jbJMK%ChTMTXZFJEm~k;KCj*D60g=j!2ns8Q`g%jSRK^?=IwL^|I5-K2zH
-z8*A0-mL%Q`R#xatM^u^E=IrX+2&bc;3rv!NipS^G*6zlIRAV(JJDU($OBHuptd&1(
-zoNu>t*Q}|siS8#MYavR6j7&(~AEL#OaV(^+gy>YrSPiLfgy{2-p=xT2Mtd}4R8#XB
-z-LDysYw8J&{-GJKYwEiif07x7u5QsOr5oeA`ZJxDb>p|XdQzvCb>nSaeP1UfY_x~f
-z9bwuRHf|5Ahr{&iu<>+QeI`t=g^e>|^=z1;5o23K?TP5uo%2>aXQWCKr#dH;Qr0*j
-z3LecKKarw5`Xblzd$&H4oP%y&l3egyUc<=<Azs)*u}X^*n$F~s2O<-paSF?q*HB+n
-zqBfj5;J|x@hM`M(QD20jrkwi8`y3l;8qO;#l8A#CMI8Kg9E{ERsT>TGXaGC^5Cz)J
-z4?eb?Kub*nWYdmhV-4?j<o}k#pt-{wK;b3U(B^+`s7-`HYOZOxv<+RG^LulAxKL|9
-z3NH#9{Lg*7U1&gy<zHSG$;LMHby+V=ENlGFVLKjt%kkph7kP1M8|vebT=K5)*E>JW
-zjd{Tu*o*CE*QO)}{_J>haU5zn+1QJ^eBg|d5n5-%|DwS@1+<Mtvat=iZ3BF??pZXh
-zth4PnnWL*s%}k43fbe34>yaZ_2@Kj<UGt)`2G5>K>)nIBR-xB@+1PQ2*c$lV?Z13o
-zbX%CHpm`!1Z4$d28~9k{rfu-0w@xg6{q!u2{)Dm_))4RK$?#7P*t7V+g_9d<V!MD`
-zaj`t-?uy6zsjzp<-IdM6g(XhQX2iF<+p?Kmw6?a+f^VMex*PuetNfqf+4_FpD%8TW
-eZvUbDHC^NLu5~gtzg|!EqSkX2ep9pg!tpEeo1jDh
-
-literal 0
-HcmV?d00001
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6530/early_init.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6530/early_init.c
-new file mode 100644
-index 0000000000..ff83db095b
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6530/early_init.c
-@@ -0,0 +1,14 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <bootblock_common.h>
-+#include <device/pci_ops.h>
-+#include <ec/dell/mec5035/mec5035.h>
-+#include <southbridge/intel/bd82x6x/pch.h>
-+
-+void bootblock_mainboard_early_init(void)
-+{
-+ pci_write_config16(PCH_LPC_DEV, LPC_EN, CNF1_LPC_EN | MC_LPC_EN
-+ | KBC_LPC_EN | FDD_LPC_EN | LPT_LPC_EN
-+ | COMB_LPC_EN | COMA_LPC_EN);
-+ mec5035_early_init();
-+}
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6530/gpio.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6530/gpio.c
-new file mode 100644
-index 0000000000..777570765a
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6530/gpio.c
-@@ -0,0 +1,192 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <southbridge/intel/common/gpio.h>
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_mode = {
-+ .gpio0 = GPIO_MODE_GPIO,
-+ .gpio1 = GPIO_MODE_GPIO,
-+ .gpio2 = GPIO_MODE_GPIO,
-+ .gpio3 = GPIO_MODE_GPIO,
-+ .gpio4 = GPIO_MODE_GPIO,
-+ .gpio5 = GPIO_MODE_NATIVE,
-+ .gpio6 = GPIO_MODE_GPIO,
-+ .gpio7 = GPIO_MODE_GPIO,
-+ .gpio8 = GPIO_MODE_GPIO,
-+ .gpio9 = GPIO_MODE_NATIVE,
-+ .gpio10 = GPIO_MODE_NATIVE,
-+ .gpio11 = GPIO_MODE_NATIVE,
-+ .gpio12 = GPIO_MODE_NATIVE,
-+ .gpio13 = GPIO_MODE_GPIO,
-+ .gpio14 = GPIO_MODE_GPIO,
-+ .gpio15 = GPIO_MODE_GPIO,
-+ .gpio16 = GPIO_MODE_GPIO,
-+ .gpio17 = GPIO_MODE_GPIO,
-+ .gpio18 = GPIO_MODE_NATIVE,
-+ .gpio19 = GPIO_MODE_GPIO,
-+ .gpio20 = GPIO_MODE_NATIVE,
-+ .gpio21 = GPIO_MODE_GPIO,
-+ .gpio22 = GPIO_MODE_GPIO,
-+ .gpio23 = GPIO_MODE_NATIVE,
-+ .gpio24 = GPIO_MODE_GPIO,
-+ .gpio25 = GPIO_MODE_NATIVE,
-+ .gpio26 = GPIO_MODE_NATIVE,
-+ .gpio27 = GPIO_MODE_GPIO,
-+ .gpio28 = GPIO_MODE_GPIO,
-+ .gpio29 = GPIO_MODE_GPIO,
-+ .gpio30 = GPIO_MODE_NATIVE,
-+ .gpio31 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_direction = {
-+ .gpio0 = GPIO_DIR_INPUT,
-+ .gpio1 = GPIO_DIR_INPUT,
-+ .gpio2 = GPIO_DIR_INPUT,
-+ .gpio3 = GPIO_DIR_INPUT,
-+ .gpio4 = GPIO_DIR_INPUT,
-+ .gpio6 = GPIO_DIR_INPUT,
-+ .gpio7 = GPIO_DIR_INPUT,
-+ .gpio8 = GPIO_DIR_INPUT,
-+ .gpio13 = GPIO_DIR_INPUT,
-+ .gpio14 = GPIO_DIR_INPUT,
-+ .gpio15 = GPIO_DIR_INPUT,
-+ .gpio16 = GPIO_DIR_INPUT,
-+ .gpio17 = GPIO_DIR_INPUT,
-+ .gpio19 = GPIO_DIR_INPUT,
-+ .gpio21 = GPIO_DIR_INPUT,
-+ .gpio22 = GPIO_DIR_INPUT,
-+ .gpio24 = GPIO_DIR_INPUT,
-+ .gpio27 = GPIO_DIR_INPUT,
-+ .gpio28 = GPIO_DIR_OUTPUT,
-+ .gpio29 = GPIO_DIR_INPUT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_level = {
-+ .gpio28 = GPIO_LEVEL_LOW,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_reset = {
-+ .gpio30 = GPIO_RESET_RSMRST,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_invert = {
-+ .gpio0 = GPIO_INVERT,
-+ .gpio8 = GPIO_INVERT,
-+ .gpio13 = GPIO_INVERT,
-+ .gpio14 = GPIO_INVERT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_blink = {
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_mode = {
-+ .gpio32 = GPIO_MODE_NATIVE,
-+ .gpio33 = GPIO_MODE_GPIO,
-+ .gpio34 = GPIO_MODE_GPIO,
-+ .gpio35 = GPIO_MODE_GPIO,
-+ .gpio36 = GPIO_MODE_GPIO,
-+ .gpio37 = GPIO_MODE_GPIO,
-+ .gpio38 = GPIO_MODE_GPIO,
-+ .gpio39 = GPIO_MODE_GPIO,
-+ .gpio40 = GPIO_MODE_NATIVE,
-+ .gpio41 = GPIO_MODE_NATIVE,
-+ .gpio42 = GPIO_MODE_NATIVE,
-+ .gpio43 = GPIO_MODE_NATIVE,
-+ .gpio44 = GPIO_MODE_NATIVE,
-+ .gpio45 = GPIO_MODE_GPIO,
-+ .gpio46 = GPIO_MODE_NATIVE,
-+ .gpio47 = GPIO_MODE_NATIVE,
-+ .gpio48 = GPIO_MODE_GPIO,
-+ .gpio49 = GPIO_MODE_GPIO,
-+ .gpio50 = GPIO_MODE_NATIVE,
-+ .gpio51 = GPIO_MODE_GPIO,
-+ .gpio52 = GPIO_MODE_GPIO,
-+ .gpio53 = GPIO_MODE_NATIVE,
-+ .gpio54 = GPIO_MODE_GPIO,
-+ .gpio55 = GPIO_MODE_NATIVE,
-+ .gpio56 = GPIO_MODE_NATIVE,
-+ .gpio57 = GPIO_MODE_GPIO,
-+ .gpio58 = GPIO_MODE_NATIVE,
-+ .gpio59 = GPIO_MODE_NATIVE,
-+ .gpio60 = GPIO_MODE_GPIO,
-+ .gpio61 = GPIO_MODE_NATIVE,
-+ .gpio62 = GPIO_MODE_NATIVE,
-+ .gpio63 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_direction = {
-+ .gpio33 = GPIO_DIR_INPUT,
-+ .gpio34 = GPIO_DIR_OUTPUT,
-+ .gpio35 = GPIO_DIR_INPUT,
-+ .gpio36 = GPIO_DIR_INPUT,
-+ .gpio37 = GPIO_DIR_INPUT,
-+ .gpio38 = GPIO_DIR_INPUT,
-+ .gpio39 = GPIO_DIR_INPUT,
-+ .gpio45 = GPIO_DIR_OUTPUT,
-+ .gpio48 = GPIO_DIR_INPUT,
-+ .gpio49 = GPIO_DIR_INPUT,
-+ .gpio51 = GPIO_DIR_INPUT,
-+ .gpio52 = GPIO_DIR_INPUT,
-+ .gpio54 = GPIO_DIR_INPUT,
-+ .gpio57 = GPIO_DIR_INPUT,
-+ .gpio60 = GPIO_DIR_OUTPUT,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_level = {
-+ .gpio34 = GPIO_LEVEL_HIGH,
-+ .gpio45 = GPIO_LEVEL_LOW,
-+ .gpio60 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_reset = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_mode = {
-+ .gpio64 = GPIO_MODE_NATIVE,
-+ .gpio65 = GPIO_MODE_NATIVE,
-+ .gpio66 = GPIO_MODE_NATIVE,
-+ .gpio67 = GPIO_MODE_NATIVE,
-+ .gpio68 = GPIO_MODE_GPIO,
-+ .gpio69 = GPIO_MODE_GPIO,
-+ .gpio70 = GPIO_MODE_GPIO,
-+ .gpio71 = GPIO_MODE_GPIO,
-+ .gpio72 = GPIO_MODE_NATIVE,
-+ .gpio73 = GPIO_MODE_NATIVE,
-+ .gpio74 = GPIO_MODE_NATIVE,
-+ .gpio75 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_direction = {
-+ .gpio68 = GPIO_DIR_INPUT,
-+ .gpio69 = GPIO_DIR_INPUT,
-+ .gpio70 = GPIO_DIR_INPUT,
-+ .gpio71 = GPIO_DIR_INPUT,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_level = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_reset = {
-+};
-+
-+const struct pch_gpio_map mainboard_gpio_map = {
-+ .set1 = {
-+ .mode = &pch_gpio_set1_mode,
-+ .direction = &pch_gpio_set1_direction,
-+ .level = &pch_gpio_set1_level,
-+ .blink = &pch_gpio_set1_blink,
-+ .invert = &pch_gpio_set1_invert,
-+ .reset = &pch_gpio_set1_reset,
-+ },
-+ .set2 = {
-+ .mode = &pch_gpio_set2_mode,
-+ .direction = &pch_gpio_set2_direction,
-+ .level = &pch_gpio_set2_level,
-+ .reset = &pch_gpio_set2_reset,
-+ },
-+ .set3 = {
-+ .mode = &pch_gpio_set3_mode,
-+ .direction = &pch_gpio_set3_direction,
-+ .level = &pch_gpio_set3_level,
-+ .reset = &pch_gpio_set3_reset,
-+ },
-+};
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6530/hda_verb.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6530/hda_verb.c
-new file mode 100644
-index 0000000000..3ebccff81d
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6530/hda_verb.c
-@@ -0,0 +1,32 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <device/azalia_device.h>
-+
-+const u32 cim_verb_data[] = {
-+ 0x111d76df, /* Codec Vendor / Device ID: IDT */
-+ 0x10280535, /* Subsystem ID */
-+ 11, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(0, 0x10280535),
-+ AZALIA_PIN_CFG(0, 0x0a, 0x03a11020),
-+ AZALIA_PIN_CFG(0, 0x0b, 0x0321101f),
-+ AZALIA_PIN_CFG(0, 0x0c, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x0d, 0x90170110),
-+ AZALIA_PIN_CFG(0, 0x0e, 0x23011050),
-+ AZALIA_PIN_CFG(0, 0x0f, 0x23a1102e),
-+ AZALIA_PIN_CFG(0, 0x10, 0x400000f3),
-+ AZALIA_PIN_CFG(0, 0x11, 0xd5a30130),
-+ AZALIA_PIN_CFG(0, 0x1f, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x20, 0x400000f0),
-+
-+ 0x80862806, /* Codec Vendor / Device ID: Intel */
-+ 0x80860101, /* Subsystem ID */
-+ 4, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(3, 0x80860101),
-+ AZALIA_PIN_CFG(3, 0x05, 0x18560010),
-+ AZALIA_PIN_CFG(3, 0x06, 0x18560020),
-+ AZALIA_PIN_CFG(3, 0x07, 0x18560030),
-+};
-+
-+const u32 pc_beep_verbs[0] = {};
-+
-+AZALIA_ARRAY_SIZES;
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6530/overridetree.cb b/src/mainboard/dell/snb_ivb_latitude/variants/e6530/overridetree.cb
-new file mode 100644
-index 0000000000..8b9c82fba4
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6530/overridetree.cb
-@@ -0,0 +1,37 @@
-+## SPDX-License-Identifier: GPL-2.0-or-later
-+
-+chip northbridge/intel/sandybridge
-+ device domain 0 on
-+ subsystemid 0x1028 0x0535 inherit
-+
-+ device ref igd on
-+ register "gpu_cpu_backlight" = "0x00000251"
-+ register "gpu_pch_backlight" = "0x13121312"
-+ end
-+
-+ chip southbridge/intel/bd82x6x
-+ register "usb_port_config" = "{
-+ { 1, 1, 0 },
-+ { 1, 1, 0 },
-+ { 1, 1, 1 },
-+ { 1, 1, 1 },
-+ { 1, 1, 2 },
-+ { 1, 1, 2 },
-+ { 1, 0, 3 },
-+ { 1, 1, 3 },
-+ { 1, 1, 4 },
-+ { 1, 1, 4 },
-+ { 1, 1, 5 },
-+ { 1, 1, 5 },
-+ { 1, 2, 6 },
-+ { 1, 2, 6 },
-+ }"
-+
-+ device ref xhci on
-+ register "superspeed_capable_ports" = "0x0000000f"
-+ register "xhci_overcurrent_mapping" = "0x00000c03"
-+ register "xhci_switchable_ports" = "0x0000000f"
-+ end
-+ end
-+ end
-+end
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0019-dell-e6430-use-ME-Soft-Temporary-Disable.patch b/config/coreboot/default/patches/0009-dell-e6430-use-ME-Soft-Temporary-Disable.patch
index b3d2d12c..ca3b6264 100644
--- a/config/coreboot/default/patches/0019-dell-e6430-use-ME-Soft-Temporary-Disable.patch
+++ b/config/coreboot/default/patches/0009-dell-e6430-use-ME-Soft-Temporary-Disable.patch
@@ -1,7 +1,7 @@
-From a15b59616e00c43c05d7853080859d4aefe26c5d Mon Sep 17 00:00:00 2001
+From 3f6f65ed6a435fe49534c8a0b5cb98c3eac71150 Mon Sep 17 00:00:00 2001
From: Leah Rowe <leah@libreboot.org>
Date: Sun, 5 Nov 2023 11:41:41 +0000
-Subject: [PATCH 19/51] dell/e6430: use ME Soft Temporary Disable
+Subject: [PATCH 09/37] dell/e6430: use ME Soft Temporary Disable
i overlooked this. it's set on other boards.
diff --git a/config/coreboot/default/patches/0009-mb-dell-Add-Latitude-E5530-Ivy-Bridge.patch b/config/coreboot/default/patches/0009-mb-dell-Add-Latitude-E5530-Ivy-Bridge.patch
deleted file mode 100644
index a2a13166..00000000
--- a/config/coreboot/default/patches/0009-mb-dell-Add-Latitude-E5530-Ivy-Bridge.patch
+++ /dev/null
@@ -1,430 +0,0 @@
-From 423e2e28618b08a4107aea0a2fbc1096f5a8be02 Mon Sep 17 00:00:00 2001
-From: Nicholas Chin <nic.c3.14@gmail.com>
-Date: Wed, 31 Jan 2024 22:57:07 -0700
-Subject: [PATCH 09/51] mb/dell: Add Latitude E5530 (Ivy Bridge)
-
-Mainboard is QXW10/LA-7902P (UMA). I do not physically have this board;
-someone with physical access to one sent me the output of autoport which
-I then modified to produce this port. I was also sent the VBT binary,
-which was obtained from `/sys/kernel/debug/dri/0/i915_vbt` while running
-version A21 of the vendor firmware.
-
-This was originally tested and found to be working as a standalone board
-port in Libreboot, but this variant based port in upstream coreboot has
-not been tested.
-
-This can be internally flashed by sending a command to the EC, which
-causes the EC to pull the FDO pin low and the firmware to skip setting
-up any chipset based write protections [1]. The EC is the SMSC MEC5055,
-which seems to be compatible with the existing MEC5035 code.
-
-Change-Id: Idaf6618df70aa19d8e60b2263088737712dec5f0
-Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>
----
- src/mainboard/dell/snb_ivb_latitude/Kconfig | 7 +
- .../dell/snb_ivb_latitude/Kconfig.name | 3 +
- .../snb_ivb_latitude/variants/e5530/data.vbt | Bin 0 -> 6144 bytes
- .../variants/e5530/early_init.c | 14 ++
- .../snb_ivb_latitude/variants/e5530/gpio.c | 194 ++++++++++++++++++
- .../variants/e5530/hda_verb.c | 32 +++
- .../variants/e5530/overridetree.cb | 39 ++++
- 7 files changed, 289 insertions(+)
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e5530/data.vbt
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e5530/early_init.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e5530/gpio.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e5530/hda_verb.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e5530/overridetree.cb
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-index 03377275f0..183a67bec3 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-@@ -17,6 +17,11 @@ config BOARD_DELL_SNB_IVB_LATITUDE_COMMON
- select SYSTEM_TYPE_LAPTOP
- select USE_NATIVE_RAMINIT
-
-+config BOARD_DELL_LATITUDE_E5530
-+ select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
-+ select BOARD_ROMSIZE_KB_12288
-+ select SOUTHBRIDGE_INTEL_C216
-+
- config BOARD_DELL_LATITUDE_E6430
- select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
- select BOARD_ROMSIZE_KB_12288
-@@ -38,6 +43,7 @@ config MAINBOARD_DIR
- default "dell/snb_ivb_latitude"
-
- config MAINBOARD_PART_NUMBER
-+ default "Latitude E5530" if BOARD_DELL_LATITUDE_E5530
- default "Latitude E6430" if BOARD_DELL_LATITUDE_E6430
- default "Latitude E6530" if BOARD_DELL_LATITUDE_E6530
-
-@@ -48,6 +54,7 @@ config USBDEBUG_HCD_INDEX
- default 2
-
- config VARIANT_DIR
-+ default "e5530" if BOARD_DELL_LATITUDE_E5530
- default "e6430" if BOARD_DELL_LATITUDE_E6430
- default "e6530" if BOARD_DELL_LATITUDE_E6530
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-index d89185d670..c15ef4028f 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-@@ -1,5 +1,8 @@
- ## SPDX-License-Identifier: GPL-2.0-only
-
-+config BOARD_DELL_LATITUDE_E5530
-+ bool "Latitude E5530"
-+
- config BOARD_DELL_LATITUDE_E6430
- bool "Latitude E6430"
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e5530/data.vbt b/src/mainboard/dell/snb_ivb_latitude/variants/e5530/data.vbt
-new file mode 100644
-index 0000000000000000000000000000000000000000..3c54b70be7856a6420d001112d7f17f8bab46ed3
-GIT binary patch
-literal 6144
-zcmeHKU2Gdg5dO}0w$JA~+qs02q)iz56C9e5vuQ#oL0l3O+%|395Q2peO{y4(2uX0t
-zuMja1N)bPb1cE+5)fYsCK!89MFQAGChyWpk5PuR<K|G+sLmxmOR4}u5=Rg`mj70g7
-zvgdDic6N4dW^QKhynd)>kS^cR)3#-(r*-?zo-O^C(kLvv8XM<+Y3tdt^YY!P?!oTe
-zJ^ed-x6w0Lh5fN#jsv5TWE#mtd*_yky}9xDK(kOwLt+C7_AQAd#iwr=o0`gvQZ`{x
-z6ZeT`x^^;8+a~jSa^o~PF@8J6N5;o#dhCwebaM;!_oisw1#O9K={qQM<@Oeu$lXeN
-z#wJGcW4Y<2)-A{Bot(NoKX%>qdnw-AOi9bKT9Z~HL5|7PJDHz4kGlEx143q+26EH6
-z{4KfB^9;?<fTOaiNPy%=@LovL&q<^d1Qdi+Xex9SvIM^ZLq%9cP{A1rE>#dw(WfA;
-zBCR3@pCS1a;A|CZW1h7H*l#mW{%y{bf)9ofiz!EHzyiac@{RpMzz>O-<~{hx5tw%b
-z3ZJWD4_g-`iF`tUJb}+Vfe;XI1T2Y4_Y!iVk<<T4ce(^PWKh<?N^a`t+}vgNr25iZ
-z`!fTBL)ojYF5G?3y|eW=`9>MLB9et&!A7LDDE7&5ye#|hn%s#IWgagDEPNHHMUhb-
-ztc9t?uz{bD#kh#kpsE;AO-wWHV?4olPStRPag^~k<737bjBgm<GlC%vRgBe)4U9I%
-zg^XUtcE**A5ylOSn;A2V2N;hso?--U#>t|ufS}_`LGs2bcSKCVBh4s0>G7ZR_@NWx
-zkph}GhP}~YR?roT!61GqzQ?gBsuv3jY}UXbmr|alv^VxUqbz5<`5=!hhpaa*7DK~4
-zP4ad6dhH!>nYpc4{J&G-w{UiWo$zXnTz{tAq0|?c_`QJ7pKmCwIpe7Uix$P?9}v*1
-z(aVR6OkMkQ6oM}*UC@j78!~>7=OZCVYXeu|u0SiI4}w$uw6&0P09LF%Hp}O&IA3gl
-z4@ap0NfAe+q(ZVm{Bwe*Do~kbCc$Q!x7b3Sk9tLgVmsR<Q4H=9Nl;mmf2xpY<*d*-
-z`yI_BR#`La=Oxxt#qgS`3pER^nh^CZ%*qlq2N9@uSAtz-C7AhduB_U|{>#oOrY`tq
-z%|?L!zRd2-$V6^@$H<Mj3MXf#F<J+^8%<X2{tnmQTI*aK*ageBrm9^|<Ked3j_s;%
-zva<(Dob)BOwdcj8Z67UhYUAjbk==Of9W#D7k!DJobLx$$fXD_wuZyD&Kk-$EIY~S`
-zan1ANbFUW8hZ0pUw5)y??*}!;chdgq|0X5;s;m`@YdY{zs4z#z8e;13T6b4tC7gy$
-zTwszEQhk0!U$`3=Qi)ZbY^*|bAyvF>@ml^iaX;uzoVB3JA(|h9tcNKXHdA43N0|18
-z&3$2QE=)(l=6qQDAWT1oO-<KoblR+&{kk@!)1A8ch^`&b>2=+FU)Mg<35IDJ+8Tp;
-z40F)Xt}$rVFdsLxLk7KRn4cKhmj<a3vp%A&kI>eLd38j)HbM_Y%!3i_aD?8An8za8
-z@d(AD=Gv&%5;e{}p%i?_q(T*^IwzEx*Eu1wKHV9=lVUvjqv!B@cWER!2fe%`IqO?q
-z!=Wf4kzGUaLX8`m#*P^uL?%M#6qc9Qu(YT|ZMb#7UzCc_(DkQYEG<G&Q*QkX`CS`I
-z8cwQnl8A#CMH~W79L&{2*Jof_MD5t{bPTAszWUa20yPzD=*wW8)wHSu?avDhffu^!
-zL>Q#%k_O0@^DN5S@MXi$D;acJ>#cTV-(U@Offv4ACp4hO4$Ll!WO)s3P4=t9vpWBC
-zSckhlcD?xUuX=Gx96Dx{IsQ23r&;o1*+^Cp2RA3nd$A-RIHP2Q7uitC>c67FIR*5}
-zB3a%B!?6K=TJ$W+SJv@*9Lms{mTvWmU4Zanj_Z*lSqOGISzYp?yawOqLhVhRt#-E6
-zd)YW~h&meh-5prIE}Cr&7f?MMi&cqTt_^%Fa?>k(=`9jVoIf@}{g+WX#TpWuc+!2v
-zPG^>A|NZ2GlGsKdGqN{7>Fr7+Hc_^3z}uBhC4?nzOQ*!QyVugGjkK_~$bvtfY`h79
-z9rOI3;Mt}9)_G{zXTAPw`8T@6=Ut0r9R5;0#Zy|#8F;v4^UAmqft3iXL|`QXD-l?U
-Jz~2*rUjdP?m;3+#
-
-literal 0
-HcmV?d00001
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e5530/early_init.c b/src/mainboard/dell/snb_ivb_latitude/variants/e5530/early_init.c
-new file mode 100644
-index 0000000000..ff83db095b
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e5530/early_init.c
-@@ -0,0 +1,14 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <bootblock_common.h>
-+#include <device/pci_ops.h>
-+#include <ec/dell/mec5035/mec5035.h>
-+#include <southbridge/intel/bd82x6x/pch.h>
-+
-+void bootblock_mainboard_early_init(void)
-+{
-+ pci_write_config16(PCH_LPC_DEV, LPC_EN, CNF1_LPC_EN | MC_LPC_EN
-+ | KBC_LPC_EN | FDD_LPC_EN | LPT_LPC_EN
-+ | COMB_LPC_EN | COMA_LPC_EN);
-+ mec5035_early_init();
-+}
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e5530/gpio.c b/src/mainboard/dell/snb_ivb_latitude/variants/e5530/gpio.c
-new file mode 100644
-index 0000000000..0599f13921
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e5530/gpio.c
-@@ -0,0 +1,194 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <southbridge/intel/common/gpio.h>
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_mode = {
-+ .gpio0 = GPIO_MODE_GPIO,
-+ .gpio1 = GPIO_MODE_GPIO,
-+ .gpio2 = GPIO_MODE_GPIO,
-+ .gpio3 = GPIO_MODE_GPIO,
-+ .gpio4 = GPIO_MODE_GPIO,
-+ .gpio5 = GPIO_MODE_NATIVE,
-+ .gpio6 = GPIO_MODE_GPIO,
-+ .gpio7 = GPIO_MODE_GPIO,
-+ .gpio8 = GPIO_MODE_GPIO,
-+ .gpio9 = GPIO_MODE_NATIVE,
-+ .gpio10 = GPIO_MODE_NATIVE,
-+ .gpio11 = GPIO_MODE_NATIVE,
-+ .gpio12 = GPIO_MODE_GPIO,
-+ .gpio13 = GPIO_MODE_GPIO,
-+ .gpio14 = GPIO_MODE_GPIO,
-+ .gpio15 = GPIO_MODE_GPIO,
-+ .gpio16 = GPIO_MODE_GPIO,
-+ .gpio17 = GPIO_MODE_GPIO,
-+ .gpio18 = GPIO_MODE_NATIVE,
-+ .gpio19 = GPIO_MODE_GPIO,
-+ .gpio20 = GPIO_MODE_NATIVE,
-+ .gpio21 = GPIO_MODE_GPIO,
-+ .gpio22 = GPIO_MODE_GPIO,
-+ .gpio23 = GPIO_MODE_NATIVE,
-+ .gpio24 = GPIO_MODE_GPIO,
-+ .gpio25 = GPIO_MODE_NATIVE,
-+ .gpio26 = GPIO_MODE_NATIVE,
-+ .gpio27 = GPIO_MODE_GPIO,
-+ .gpio28 = GPIO_MODE_GPIO,
-+ .gpio29 = GPIO_MODE_GPIO,
-+ .gpio30 = GPIO_MODE_NATIVE,
-+ .gpio31 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_direction = {
-+ .gpio0 = GPIO_DIR_INPUT,
-+ .gpio1 = GPIO_DIR_INPUT,
-+ .gpio2 = GPIO_DIR_INPUT,
-+ .gpio3 = GPIO_DIR_INPUT,
-+ .gpio4 = GPIO_DIR_INPUT,
-+ .gpio6 = GPIO_DIR_INPUT,
-+ .gpio7 = GPIO_DIR_INPUT,
-+ .gpio8 = GPIO_DIR_INPUT,
-+ .gpio12 = GPIO_DIR_OUTPUT,
-+ .gpio13 = GPIO_DIR_INPUT,
-+ .gpio14 = GPIO_DIR_INPUT,
-+ .gpio15 = GPIO_DIR_INPUT,
-+ .gpio16 = GPIO_DIR_INPUT,
-+ .gpio17 = GPIO_DIR_INPUT,
-+ .gpio19 = GPIO_DIR_INPUT,
-+ .gpio21 = GPIO_DIR_INPUT,
-+ .gpio22 = GPIO_DIR_INPUT,
-+ .gpio24 = GPIO_DIR_INPUT,
-+ .gpio27 = GPIO_DIR_INPUT,
-+ .gpio28 = GPIO_DIR_OUTPUT,
-+ .gpio29 = GPIO_DIR_INPUT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_level = {
-+ .gpio12 = GPIO_LEVEL_HIGH,
-+ .gpio28 = GPIO_LEVEL_LOW,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_reset = {
-+ .gpio30 = GPIO_RESET_RSMRST,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_invert = {
-+ .gpio0 = GPIO_INVERT,
-+ .gpio8 = GPIO_INVERT,
-+ .gpio13 = GPIO_INVERT,
-+ .gpio14 = GPIO_INVERT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_blink = {
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_mode = {
-+ .gpio32 = GPIO_MODE_NATIVE,
-+ .gpio33 = GPIO_MODE_GPIO,
-+ .gpio34 = GPIO_MODE_GPIO,
-+ .gpio35 = GPIO_MODE_GPIO,
-+ .gpio36 = GPIO_MODE_GPIO,
-+ .gpio37 = GPIO_MODE_GPIO,
-+ .gpio38 = GPIO_MODE_GPIO,
-+ .gpio39 = GPIO_MODE_GPIO,
-+ .gpio40 = GPIO_MODE_NATIVE,
-+ .gpio41 = GPIO_MODE_NATIVE,
-+ .gpio42 = GPIO_MODE_NATIVE,
-+ .gpio43 = GPIO_MODE_NATIVE,
-+ .gpio44 = GPIO_MODE_NATIVE,
-+ .gpio45 = GPIO_MODE_GPIO,
-+ .gpio46 = GPIO_MODE_NATIVE,
-+ .gpio47 = GPIO_MODE_NATIVE,
-+ .gpio48 = GPIO_MODE_GPIO,
-+ .gpio49 = GPIO_MODE_GPIO,
-+ .gpio50 = GPIO_MODE_NATIVE,
-+ .gpio51 = GPIO_MODE_GPIO,
-+ .gpio52 = GPIO_MODE_GPIO,
-+ .gpio53 = GPIO_MODE_GPIO,
-+ .gpio54 = GPIO_MODE_GPIO,
-+ .gpio55 = GPIO_MODE_NATIVE,
-+ .gpio56 = GPIO_MODE_NATIVE,
-+ .gpio57 = GPIO_MODE_GPIO,
-+ .gpio58 = GPIO_MODE_NATIVE,
-+ .gpio59 = GPIO_MODE_NATIVE,
-+ .gpio60 = GPIO_MODE_GPIO,
-+ .gpio61 = GPIO_MODE_NATIVE,
-+ .gpio62 = GPIO_MODE_NATIVE,
-+ .gpio63 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_direction = {
-+ .gpio33 = GPIO_DIR_INPUT,
-+ .gpio34 = GPIO_DIR_INPUT,
-+ .gpio35 = GPIO_DIR_INPUT,
-+ .gpio36 = GPIO_DIR_INPUT,
-+ .gpio37 = GPIO_DIR_INPUT,
-+ .gpio38 = GPIO_DIR_INPUT,
-+ .gpio39 = GPIO_DIR_INPUT,
-+ .gpio45 = GPIO_DIR_INPUT,
-+ .gpio48 = GPIO_DIR_INPUT,
-+ .gpio49 = GPIO_DIR_INPUT,
-+ .gpio51 = GPIO_DIR_INPUT,
-+ .gpio52 = GPIO_DIR_INPUT,
-+ .gpio53 = GPIO_DIR_INPUT,
-+ .gpio54 = GPIO_DIR_INPUT,
-+ .gpio57 = GPIO_DIR_INPUT,
-+ .gpio60 = GPIO_DIR_OUTPUT,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_level = {
-+ .gpio60 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_reset = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_mode = {
-+ .gpio64 = GPIO_MODE_NATIVE,
-+ .gpio65 = GPIO_MODE_NATIVE,
-+ .gpio66 = GPIO_MODE_NATIVE,
-+ .gpio67 = GPIO_MODE_NATIVE,
-+ .gpio68 = GPIO_MODE_GPIO,
-+ .gpio69 = GPIO_MODE_GPIO,
-+ .gpio70 = GPIO_MODE_GPIO,
-+ .gpio71 = GPIO_MODE_GPIO,
-+ .gpio72 = GPIO_MODE_NATIVE,
-+ .gpio73 = GPIO_MODE_NATIVE,
-+ .gpio74 = GPIO_MODE_GPIO,
-+ .gpio75 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_direction = {
-+ .gpio68 = GPIO_DIR_INPUT,
-+ .gpio69 = GPIO_DIR_INPUT,
-+ .gpio70 = GPIO_DIR_INPUT,
-+ .gpio71 = GPIO_DIR_INPUT,
-+ .gpio74 = GPIO_DIR_INPUT,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_level = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_reset = {
-+};
-+
-+const struct pch_gpio_map mainboard_gpio_map = {
-+ .set1 = {
-+ .mode = &pch_gpio_set1_mode,
-+ .direction = &pch_gpio_set1_direction,
-+ .level = &pch_gpio_set1_level,
-+ .blink = &pch_gpio_set1_blink,
-+ .invert = &pch_gpio_set1_invert,
-+ .reset = &pch_gpio_set1_reset,
-+ },
-+ .set2 = {
-+ .mode = &pch_gpio_set2_mode,
-+ .direction = &pch_gpio_set2_direction,
-+ .level = &pch_gpio_set2_level,
-+ .reset = &pch_gpio_set2_reset,
-+ },
-+ .set3 = {
-+ .mode = &pch_gpio_set3_mode,
-+ .direction = &pch_gpio_set3_direction,
-+ .level = &pch_gpio_set3_level,
-+ .reset = &pch_gpio_set3_reset,
-+ },
-+};
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e5530/hda_verb.c b/src/mainboard/dell/snb_ivb_latitude/variants/e5530/hda_verb.c
-new file mode 100644
-index 0000000000..3e89a6d75f
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e5530/hda_verb.c
-@@ -0,0 +1,32 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <device/azalia_device.h>
-+
-+const u32 cim_verb_data[] = {
-+ 0x111d76df, /* Codec Vendor / Device ID: IDT */
-+ 0x1028053d, /* Subsystem ID */
-+ 11, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(0, 0x1028053d),
-+ AZALIA_PIN_CFG(0, 0x0a, 0x04a11020),
-+ AZALIA_PIN_CFG(0, 0x0b, 0x0421101f),
-+ AZALIA_PIN_CFG(0, 0x0c, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x0d, 0x90170110),
-+ AZALIA_PIN_CFG(0, 0x0e, 0x23011050),
-+ AZALIA_PIN_CFG(0, 0x0f, 0x23a1102e),
-+ AZALIA_PIN_CFG(0, 0x10, 0x400000f3),
-+ AZALIA_PIN_CFG(0, 0x11, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x1f, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x20, 0xd5a301a0),
-+
-+ 0x80862806, /* Codec Vendor / Device ID: Intel */
-+ 0x80860101, /* Subsystem ID */
-+ 4, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(3, 0x80860101),
-+ AZALIA_PIN_CFG(3, 0x05, 0x18560010),
-+ AZALIA_PIN_CFG(3, 0x06, 0x18560020),
-+ AZALIA_PIN_CFG(3, 0x07, 0x18560030),
-+};
-+
-+const u32 pc_beep_verbs[0] = {};
-+
-+AZALIA_ARRAY_SIZES;
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e5530/overridetree.cb b/src/mainboard/dell/snb_ivb_latitude/variants/e5530/overridetree.cb
-new file mode 100644
-index 0000000000..85c448d010
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e5530/overridetree.cb
-@@ -0,0 +1,39 @@
-+## SPDX-License-Identifier: GPL-2.0-or-later
-+
-+chip northbridge/intel/sandybridge
-+ device domain 0 on
-+ subsystemid 0x1028 0x053d inherit
-+
-+ device ref igd on
-+ register "gpu_cpu_backlight" = "0x00000000"
-+ register "gpu_pch_backlight" = "0x03d003d0"
-+ end
-+
-+ chip southbridge/intel/bd82x6x
-+ register "usb_port_config" = "{
-+ { 1, 1, 0 },
-+ { 1, 1, 0 },
-+ { 1, 1, 1 },
-+ { 1, 1, 1 },
-+ { 1, 1, 2 },
-+ { 1, 1, 2 },
-+ { 1, 1, 3 },
-+ { 1, 0, 3 },
-+ { 1, 2, 4 },
-+ { 1, 1, 4 },
-+ { 1, 1, 5 },
-+ { 1, 1, 5 },
-+ { 1, 0, 6 },
-+ { 1, 1, 6 },
-+ }"
-+
-+ device ref xhci on
-+ register "superspeed_capable_ports" = "0x0000000f"
-+ register "xhci_overcurrent_mapping" = "0x00000c03"
-+ register "xhci_switchable_ports" = "0x0000000f"
-+ end
-+ device ref gbe off end
-+ device ref pcie_rp7 on end # BCM5761 Ethernet
-+ end
-+ end
-+end
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0010-mb-dell-Add-Latitude-E6420-Sandy-Bridge.patch b/config/coreboot/default/patches/0010-mb-dell-Add-Latitude-E6420-Sandy-Bridge.patch
deleted file mode 100644
index 80b2c147..00000000
--- a/config/coreboot/default/patches/0010-mb-dell-Add-Latitude-E6420-Sandy-Bridge.patch
+++ /dev/null
@@ -1,435 +0,0 @@
-From 200668a694f1c534a94a0bc8996416e246fe91b0 Mon Sep 17 00:00:00 2001
-From: Nicholas Chin <nic.c3.14@gmail.com>
-Date: Sun, 26 Nov 2023 17:08:52 -0700
-Subject: [PATCH 10/51] mb/dell: Add Latitude E6420 (Sandy Bridge)
-
-Mainboard is PAL50/LA-6591P (UMA). The version with an Nvidia dGPU was
-not tested. I do not physically have this system; someone with physical
-access to one sent me the output of autoport which I then modified to
-produce this port. I was also sent the VBT binary, which was obtained
-from `/sys/kernel/debug/dri/0/i915_vbt` while running version A25 of the
-vendor firmware.
-
-This was originally tested and found to be working as a standalone board
-port in Libreboot, but this variant based port in upstream coreboot has
-not been tested.
-
-This can be internally flashed by sending a command to the EC, which
-causes the EC to pull the FDO pin low and the firmware to skip setting
-up any chipset based write protections [1]. The EC is the SMSC MEC5055,
-which seems to be compatible with the existing MEC5035 code.
-
-[1] https://gitlab.com/nic3-14159/dell-flash-unlock
-
-Change-Id: Ic48d9ea58172a5b13958c8afebcb19c8929c4394
-Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>
----
- src/mainboard/dell/snb_ivb_latitude/Kconfig | 13 +-
- .../dell/snb_ivb_latitude/Kconfig.name | 3 +
- .../snb_ivb_latitude/variants/e6420/data.vbt | Bin 0 -> 6144 bytes
- .../variants/e6420/early_init.c | 14 ++
- .../snb_ivb_latitude/variants/e6420/gpio.c | 191 ++++++++++++++++++
- .../variants/e6420/hda_verb.c | 32 +++
- .../variants/e6420/overridetree.cb | 35 ++++
- 7 files changed, 287 insertions(+), 1 deletion(-)
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6420/data.vbt
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6420/early_init.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6420/gpio.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6420/hda_verb.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6420/overridetree.cb
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-index 183a67bec3..d2786970ee 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-@@ -17,6 +17,12 @@ config BOARD_DELL_SNB_IVB_LATITUDE_COMMON
- select SYSTEM_TYPE_LAPTOP
- select USE_NATIVE_RAMINIT
-
-+config BOARD_DELL_LATITUDE_E6420
-+ select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
-+ select BOARD_ROMSIZE_KB_10240
-+ select MAINBOARD_USES_IFD_GBE_REGION
-+ select SOUTHBRIDGE_INTEL_BD82X6X
-+
- config BOARD_DELL_LATITUDE_E5530
- select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
- select BOARD_ROMSIZE_KB_12288
-@@ -43,6 +49,7 @@ config MAINBOARD_DIR
- default "dell/snb_ivb_latitude"
-
- config MAINBOARD_PART_NUMBER
-+ default "Latitude E6420" if BOARD_DELL_LATITUDE_E6420
- default "Latitude E5530" if BOARD_DELL_LATITUDE_E5530
- default "Latitude E6430" if BOARD_DELL_LATITUDE_E6430
- default "Latitude E6530" if BOARD_DELL_LATITUDE_E6530
-@@ -54,11 +61,15 @@ config USBDEBUG_HCD_INDEX
- default 2
-
- config VARIANT_DIR
-+ default "e6420" if BOARD_DELL_LATITUDE_E6420
- default "e5530" if BOARD_DELL_LATITUDE_E5530
- default "e6430" if BOARD_DELL_LATITUDE_E6430
- default "e6530" if BOARD_DELL_LATITUDE_E6530
-
- config VGA_BIOS_ID
-- default "8086,0166"
-+ default "8086,0166" if BOARD_DELL_LATITUDE_E5530
-+ default "8086,0126" if BOARD_DELL_LATITUDE_E6420
-+ default "8086,0166" if BOARD_DELL_LATITUDE_E6430 \
-+ || BOARD_DELL_LATITUDE_E6530
-
- endif
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-index c15ef4028f..257d428a70 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-@@ -1,5 +1,8 @@
- ## SPDX-License-Identifier: GPL-2.0-only
-
-+config BOARD_DELL_LATITUDE_E6420
-+ bool "Latitude E6420"
-+
- config BOARD_DELL_LATITUDE_E5530
- bool "Latitude E5530"
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6420/data.vbt b/src/mainboard/dell/snb_ivb_latitude/variants/e6420/data.vbt
-new file mode 100644
-index 0000000000000000000000000000000000000000..d3662eea1bc78b60be6d0bd2cc38bb46b654afbd
-GIT binary patch
-literal 6144
-zcmeHKeQZ-z6hE);wSBvNZ|mO1=*HLC2BQN8uVX6{N9eY)75ORymb$R8!YYuAZEgeE
-zKk|S@Fen*n41W-viAF;r%)~^EkpLz-B{2q##)LmGAtoY;7*Qhv_1yPbw$TC$2}G0K
-z=6Ao&x#ym9?z!i_&TOh(kLzky2cN8MTpny#R<;VU4Rkn?rBIz(YL~BBw<%b&zGhSH
-z$~AQ>@D0d=Xx6RE0BwSxspWdrW9y<FZGD@&x3_JL;p$p!;!BVdcKLkht0=-%(Jj&T
-z_GkyztZ%>#t7^)^(T-R<7W?O6ZTI%A+j=`<Jw3Q%dk6N!da<_?7oyiU3)^<~_TiSk
-zE$y+=RK3PGQ`gzmXYPRBx>C|f*UP9{h|4>ANrAe~?ymV*)83AaT#FuTjP=C2cg5P~
-zt4w78r$t#300cWY_k)mevmAmFI3&oBfytoAAPQiYK$XEIgHwV@5-gJ-Q-*p8yfTDj
-zaDz=1Y!X1B3`OpQ&Ik}bM|0xHn0gYNZw0rT=7AXS2in-q8K^?)0|el+Z6geW7i7MM
-zv~!|>HqL-|Fk}EYOa@)R<X)VQ7c}d8R1b@RTn5rq(90|QRg0?wwZZz(6Dz}w>zg9Y
-z8;!mD_V*XSjT33~$`o`s>zEGBq8AQ`HaH?y!Fh2QiX1v@aCo4LaENf&DZ_cE2A2qb
-z5@cC}X)=S^1RvpXLWs~v*hqMau$!=t@B-mg!XV)|;eEm>!Z6`H;R4|&!d1d`f|S7^
-zli+B98*!TfPE&6~NVM5j3v{N3OTjpnm_L@BPh(}esd(J!gj?~iJP?n|OZZOiTqlql
-zg<NWR@g&-*W-E%A7|*1Z_`sVO$K&iAP+VIj9{<1hT%SXsK}IBk8!daftR`6-)EUiS
-zvv*HR(#-ZwhA~7wcmxbe4%E?Y7P0y{1q|nqR1L29UR8v@#No^g5MH)7!>{%-$T|cR
-zZx5|xm>Fl>;@$m};P{0WC>O~<Nl1`*PLgPN_hP2a^h+L$ls&SYrkDYr+&l*%%S?^Q
-ziPSdtHE<LNEnr7cs=ihL-C>-p>*$9CpHRLgN|POkqD^UP4nw|4nf0bc8MOBk<;%js
-zfpCAWNzqSPlz@X%j9CGrwZDKUl@K{g6pzqiIIARDQ)#@^RW&0pmNG;XZ?!SlHB?L#
-zKRAMgq(R;aQd%@Gy38-LS@ix)fR**(P3B9wI=Uk^&cWmmwB<vf21<0#LBA!;qtAh(
-zYe5g_T{+gw^mi8QzPPraBoH~8oCz%r=$nVi1A)`Y8IKqIdqm6MihqxtpFaTggaPxu
-zQP07nf#&kPkPp}Cmk$F1g7q7QK;kz~80i&oDN}~wYbPUI6AtG5H+$T!@f5FzUhp21
-z^XiPT3rb%B@sA9g!n88R7BOsLS|?+D3}0v3dyIX|@JFWo&e%<c#V)PV#g@7-=F*;V
-zvAr&Q+ogTvVxPM3XP5Smi`f;Nt7uCU)}Y`HMcbpW=M_AuXlE35PQl+4O{7m66&I@7
-zGL@}Sai^*sP}va`KTx$VRQ8REf2*1+lTFH0=UkNx+eN|1rVyipl)Du=h=@%w+iQZG
-zT6@-PdW^oyFb44AG`HMZWEnP{&OQ+jC`N4emoS)x;EPN}uaSFOf-Mn8JRRO&LTWJc
-zn6%=L94~PR)%Ua_HTZcfTXD<p{%8p|<N<;Efw$Zb4$}{m8@7c((~<7^thaau&@Wx#
-zVGNL)lmH@{o=h*{muXGc!;nXrVgpp3;1V1stMj=4AtxyzX+?SoB~zN}!*r?9Qvs1P
-zmV_(CTmt0sY&6=F=_M>E34GYvuh1uQF+BUdWyQC5SaEM1QvKlHBMs13C}n{0SwRxW
-ziekMa&kvRFruRcKCevGy5)TxUBDlur@E{TtQ^NQ>nO+Cgl)&Ga(PxqVW?e3TLH-UY
-zdL3T{z^xdd`$(STFUb8R*cKa}r>n{Wk+MXRH~o-hN}#9OF*>T#>rfhiRs(Wc-R^9@
-z%F=<}dn(E}ADc03zJ>JvZe;_8f+WFLL4%qNYs`_aa`a$Pl5H;iO^Wt*cP3W(d=(g}
-zZ%nKT1$|r-tAv8($u2-BI2Uiz#%OT&!Q3b~Ru2P2j;Gem!@wfPsTR%J>W{8z)oq^J
-k^Qm&?O@bFkw4CTocwoW<6CRlGz=Q`TJTT#bN9KWl0rH4|j{pDw
-
-literal 0
-HcmV?d00001
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6420/early_init.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6420/early_init.c
-new file mode 100644
-index 0000000000..ff83db095b
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6420/early_init.c
-@@ -0,0 +1,14 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <bootblock_common.h>
-+#include <device/pci_ops.h>
-+#include <ec/dell/mec5035/mec5035.h>
-+#include <southbridge/intel/bd82x6x/pch.h>
-+
-+void bootblock_mainboard_early_init(void)
-+{
-+ pci_write_config16(PCH_LPC_DEV, LPC_EN, CNF1_LPC_EN | MC_LPC_EN
-+ | KBC_LPC_EN | FDD_LPC_EN | LPT_LPC_EN
-+ | COMB_LPC_EN | COMA_LPC_EN);
-+ mec5035_early_init();
-+}
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6420/gpio.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6420/gpio.c
-new file mode 100644
-index 0000000000..943c743f48
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6420/gpio.c
-@@ -0,0 +1,191 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <southbridge/intel/common/gpio.h>
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_mode = {
-+ .gpio0 = GPIO_MODE_GPIO,
-+ .gpio1 = GPIO_MODE_NATIVE,
-+ .gpio2 = GPIO_MODE_GPIO,
-+ .gpio3 = GPIO_MODE_NATIVE,
-+ .gpio4 = GPIO_MODE_GPIO,
-+ .gpio5 = GPIO_MODE_NATIVE,
-+ .gpio6 = GPIO_MODE_GPIO,
-+ .gpio7 = GPIO_MODE_GPIO,
-+ .gpio8 = GPIO_MODE_GPIO,
-+ .gpio9 = GPIO_MODE_NATIVE,
-+ .gpio10 = GPIO_MODE_NATIVE,
-+ .gpio11 = GPIO_MODE_NATIVE,
-+ .gpio12 = GPIO_MODE_NATIVE,
-+ .gpio13 = GPIO_MODE_GPIO,
-+ .gpio14 = GPIO_MODE_GPIO,
-+ .gpio15 = GPIO_MODE_GPIO,
-+ .gpio16 = GPIO_MODE_GPIO,
-+ .gpio17 = GPIO_MODE_GPIO,
-+ .gpio18 = GPIO_MODE_NATIVE,
-+ .gpio19 = GPIO_MODE_GPIO,
-+ .gpio20 = GPIO_MODE_NATIVE,
-+ .gpio21 = GPIO_MODE_GPIO,
-+ .gpio22 = GPIO_MODE_GPIO,
-+ .gpio23 = GPIO_MODE_NATIVE,
-+ .gpio24 = GPIO_MODE_GPIO,
-+ .gpio25 = GPIO_MODE_NATIVE,
-+ .gpio26 = GPIO_MODE_NATIVE,
-+ .gpio27 = GPIO_MODE_GPIO,
-+ .gpio28 = GPIO_MODE_GPIO,
-+ .gpio29 = GPIO_MODE_GPIO,
-+ .gpio30 = GPIO_MODE_GPIO,
-+ .gpio31 = GPIO_MODE_GPIO,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_direction = {
-+ .gpio0 = GPIO_DIR_INPUT,
-+ .gpio2 = GPIO_DIR_INPUT,
-+ .gpio4 = GPIO_DIR_INPUT,
-+ .gpio6 = GPIO_DIR_INPUT,
-+ .gpio7 = GPIO_DIR_INPUT,
-+ .gpio8 = GPIO_DIR_INPUT,
-+ .gpio13 = GPIO_DIR_INPUT,
-+ .gpio14 = GPIO_DIR_INPUT,
-+ .gpio15 = GPIO_DIR_INPUT,
-+ .gpio16 = GPIO_DIR_INPUT,
-+ .gpio17 = GPIO_DIR_INPUT,
-+ .gpio19 = GPIO_DIR_INPUT,
-+ .gpio21 = GPIO_DIR_INPUT,
-+ .gpio22 = GPIO_DIR_INPUT,
-+ .gpio24 = GPIO_DIR_INPUT,
-+ .gpio27 = GPIO_DIR_INPUT,
-+ .gpio28 = GPIO_DIR_INPUT,
-+ .gpio29 = GPIO_DIR_INPUT,
-+ .gpio30 = GPIO_DIR_OUTPUT,
-+ .gpio31 = GPIO_DIR_INPUT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_level = {
-+ .gpio30 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_reset = {
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_invert = {
-+ .gpio0 = GPIO_INVERT,
-+ .gpio8 = GPIO_INVERT,
-+ .gpio14 = GPIO_INVERT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_blink = {
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_mode = {
-+ .gpio32 = GPIO_MODE_NATIVE,
-+ .gpio33 = GPIO_MODE_GPIO,
-+ .gpio34 = GPIO_MODE_GPIO,
-+ .gpio35 = GPIO_MODE_GPIO,
-+ .gpio36 = GPIO_MODE_GPIO,
-+ .gpio37 = GPIO_MODE_GPIO,
-+ .gpio38 = GPIO_MODE_GPIO,
-+ .gpio39 = GPIO_MODE_GPIO,
-+ .gpio40 = GPIO_MODE_NATIVE,
-+ .gpio41 = GPIO_MODE_NATIVE,
-+ .gpio42 = GPIO_MODE_NATIVE,
-+ .gpio43 = GPIO_MODE_NATIVE,
-+ .gpio44 = GPIO_MODE_NATIVE,
-+ .gpio45 = GPIO_MODE_GPIO,
-+ .gpio46 = GPIO_MODE_NATIVE,
-+ .gpio47 = GPIO_MODE_NATIVE,
-+ .gpio48 = GPIO_MODE_GPIO,
-+ .gpio49 = GPIO_MODE_GPIO,
-+ .gpio50 = GPIO_MODE_NATIVE,
-+ .gpio51 = GPIO_MODE_GPIO,
-+ .gpio52 = GPIO_MODE_GPIO,
-+ .gpio53 = GPIO_MODE_NATIVE,
-+ .gpio54 = GPIO_MODE_GPIO,
-+ .gpio55 = GPIO_MODE_NATIVE,
-+ .gpio56 = GPIO_MODE_NATIVE,
-+ .gpio57 = GPIO_MODE_GPIO,
-+ .gpio58 = GPIO_MODE_NATIVE,
-+ .gpio59 = GPIO_MODE_NATIVE,
-+ .gpio60 = GPIO_MODE_GPIO,
-+ .gpio61 = GPIO_MODE_NATIVE,
-+ .gpio62 = GPIO_MODE_NATIVE,
-+ .gpio63 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_direction = {
-+ .gpio33 = GPIO_DIR_INPUT,
-+ .gpio34 = GPIO_DIR_OUTPUT,
-+ .gpio35 = GPIO_DIR_INPUT,
-+ .gpio36 = GPIO_DIR_INPUT,
-+ .gpio37 = GPIO_DIR_INPUT,
-+ .gpio38 = GPIO_DIR_INPUT,
-+ .gpio39 = GPIO_DIR_INPUT,
-+ .gpio45 = GPIO_DIR_OUTPUT,
-+ .gpio48 = GPIO_DIR_INPUT,
-+ .gpio49 = GPIO_DIR_OUTPUT,
-+ .gpio51 = GPIO_DIR_INPUT,
-+ .gpio52 = GPIO_DIR_INPUT,
-+ .gpio54 = GPIO_DIR_INPUT,
-+ .gpio57 = GPIO_DIR_INPUT,
-+ .gpio60 = GPIO_DIR_OUTPUT,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_level = {
-+ .gpio34 = GPIO_LEVEL_HIGH,
-+ .gpio45 = GPIO_LEVEL_LOW,
-+ .gpio49 = GPIO_LEVEL_LOW,
-+ .gpio60 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_reset = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_mode = {
-+ .gpio64 = GPIO_MODE_NATIVE,
-+ .gpio65 = GPIO_MODE_NATIVE,
-+ .gpio66 = GPIO_MODE_NATIVE,
-+ .gpio67 = GPIO_MODE_NATIVE,
-+ .gpio68 = GPIO_MODE_GPIO,
-+ .gpio69 = GPIO_MODE_GPIO,
-+ .gpio70 = GPIO_MODE_GPIO,
-+ .gpio71 = GPIO_MODE_GPIO,
-+ .gpio72 = GPIO_MODE_NATIVE,
-+ .gpio73 = GPIO_MODE_NATIVE,
-+ .gpio74 = GPIO_MODE_NATIVE,
-+ .gpio75 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_direction = {
-+ .gpio68 = GPIO_DIR_INPUT,
-+ .gpio69 = GPIO_DIR_INPUT,
-+ .gpio70 = GPIO_DIR_INPUT,
-+ .gpio71 = GPIO_DIR_INPUT,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_level = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_reset = {
-+};
-+
-+const struct pch_gpio_map mainboard_gpio_map = {
-+ .set1 = {
-+ .mode = &pch_gpio_set1_mode,
-+ .direction = &pch_gpio_set1_direction,
-+ .level = &pch_gpio_set1_level,
-+ .blink = &pch_gpio_set1_blink,
-+ .invert = &pch_gpio_set1_invert,
-+ .reset = &pch_gpio_set1_reset,
-+ },
-+ .set2 = {
-+ .mode = &pch_gpio_set2_mode,
-+ .direction = &pch_gpio_set2_direction,
-+ .level = &pch_gpio_set2_level,
-+ .reset = &pch_gpio_set2_reset,
-+ },
-+ .set3 = {
-+ .mode = &pch_gpio_set3_mode,
-+ .direction = &pch_gpio_set3_direction,
-+ .level = &pch_gpio_set3_level,
-+ .reset = &pch_gpio_set3_reset,
-+ },
-+};
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6420/hda_verb.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6420/hda_verb.c
-new file mode 100644
-index 0000000000..ede8445aaf
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6420/hda_verb.c
-@@ -0,0 +1,32 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <device/azalia_device.h>
-+
-+const u32 cim_verb_data[] = {
-+ 0x111d76e7, /* Codec Vendor / Device ID: IDT */
-+ 0x10280493, /* Subsystem ID */
-+ 11, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(0, 0x10280493),
-+ AZALIA_PIN_CFG(0, 0x0a, 0x03a11020),
-+ AZALIA_PIN_CFG(0, 0x0b, 0x0321101f),
-+ AZALIA_PIN_CFG(0, 0x0c, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x0d, 0x90170110),
-+ AZALIA_PIN_CFG(0, 0x0e, 0x23011050),
-+ AZALIA_PIN_CFG(0, 0x0f, 0x23a1102e),
-+ AZALIA_PIN_CFG(0, 0x10, 0x400000f3),
-+ AZALIA_PIN_CFG(0, 0x11, 0xd5a30130),
-+ AZALIA_PIN_CFG(0, 0x1f, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x20, 0x400000f0),
-+
-+ 0x80862805, /* Codec Vendor / Device ID: Intel */
-+ 0x80860101, /* Subsystem ID */
-+ 4, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(3, 0x80860101),
-+ AZALIA_PIN_CFG(3, 0x05, 0x18560010),
-+ AZALIA_PIN_CFG(3, 0x06, 0x18560020),
-+ AZALIA_PIN_CFG(3, 0x07, 0x18560030),
-+};
-+
-+const u32 pc_beep_verbs[0] = {};
-+
-+AZALIA_ARRAY_SIZES;
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6420/overridetree.cb b/src/mainboard/dell/snb_ivb_latitude/variants/e6420/overridetree.cb
-new file mode 100644
-index 0000000000..3012a3177f
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6420/overridetree.cb
-@@ -0,0 +1,35 @@
-+## SPDX-License-Identifier: GPL-2.0-or-later
-+
-+chip northbridge/intel/sandybridge
-+ device domain 0 on
-+ subsystemid 0x1028 0x0493 inherit
-+
-+ device ref igd on
-+ register "gpu_cpu_backlight" = "0x0000054f"
-+ register "gpu_pch_backlight" = "0x13121312"
-+ end
-+
-+ chip southbridge/intel/bd82x6x
-+ register "usb_port_config" = "{
-+ { 1, 1, 0 },
-+ { 1, 1, 0 },
-+ { 1, 1, 1 },
-+ { 1, 1, 1 },
-+ { 1, 0, 2 },
-+ { 1, 1, 2 },
-+ { 1, 1, 3 },
-+ { 1, 1, 3 },
-+ { 1, 1, 5 },
-+ { 1, 1, 5 },
-+ { 1, 1, 7 },
-+ { 1, 1, 6 },
-+ { 1, 0, 6 },
-+ { 1, 0, 7 },
-+ }"
-+
-+ device ref sata1 on
-+ register "sata_port_map" = "0x3b"
-+ end
-+ end
-+ end
-+end
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0020-mb-hp-Add-Compaq-Elite-8300-CMT-port.patch b/config/coreboot/default/patches/0010-mb-hp-Add-Compaq-Elite-8300-CMT-port.patch
index 46e38925..2a7d5c17 100644
--- a/config/coreboot/default/patches/0020-mb-hp-Add-Compaq-Elite-8300-CMT-port.patch
+++ b/config/coreboot/default/patches/0010-mb-hp-Add-Compaq-Elite-8300-CMT-port.patch
@@ -1,7 +1,7 @@
-From 440ebbe1e10911dc3d8c53cf9eecb5519c2ecd67 Mon Sep 17 00:00:00 2001
+From b4d48233a8d829d7285501f662d999aad898be21 Mon Sep 17 00:00:00 2001
From: Riku Viitanen <riku.viitanen@protonmail.com>
Date: Sat, 23 Dec 2023 19:02:10 +0200
-Subject: [PATCH 20/51] mb/hp: Add Compaq Elite 8300 CMT port
+Subject: [PATCH 10/37] mb/hp: Add Compaq Elite 8300 CMT port
Based on autoport and Z220 SuperIO code.
diff --git a/config/coreboot/default/patches/0011-mb-dell-Add-Latitude-E6520-Sandy-Bridge.patch b/config/coreboot/default/patches/0011-mb-dell-Add-Latitude-E6520-Sandy-Bridge.patch
deleted file mode 100644
index 2b378406..00000000
--- a/config/coreboot/default/patches/0011-mb-dell-Add-Latitude-E6520-Sandy-Bridge.patch
+++ /dev/null
@@ -1,449 +0,0 @@
-From 53abe363f2fa038080a976f2d3a2c63ee8da9022 Mon Sep 17 00:00:00 2001
-From: Nicholas Chin <nic.c3.14@gmail.com>
-Date: Wed, 31 Jan 2024 22:07:25 -0700
-Subject: [PATCH 11/51] mb/dell: Add Latitude E6520 (Sandy Bridge)
-
-Mainboard is PAL60/LA-6562P (UMA). The version with an Nvidia dGPU was
-not tested. I do not physically have this system; someone with physical
-access to one sent me the output of autoport which I then modified to
-produce this port. I was also sent the VBT binary, which was obtained
-from `/sys/kernel/debug/dri/0/i915_vbt` while running version A08 of the
-vendor firmware.
-
-This was originally tested and found to be working as a standalone board
-port in Libreboot, but this variant based port in upstream coreboot has
-not been tested.
-
-This can be internally flashed by sending a command to the EC, which
-causes the EC to pull the FDO pin low and the firmware to skip setting
-up any chipset based write protections [1]. The EC is the SMSC MEC5055,
-which seems to be compatible with the existing MEC5035 code.
-
-[1] https://gitlab.com/nic3-14159/dell-flash-unlock
-
-Change-Id: Ibdd40cc15642b8d404159d5962670ccc4167a9ec
-Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>
----
- src/mainboard/dell/snb_ivb_latitude/Kconfig | 9 +
- .../dell/snb_ivb_latitude/Kconfig.name | 3 +
- .../snb_ivb_latitude/variants/e6520/data.vbt | Bin 0 -> 6144 bytes
- .../variants/e6520/early_init.c | 31 +++
- .../snb_ivb_latitude/variants/e6520/gpio.c | 190 ++++++++++++++++++
- .../variants/e6520/hda_verb.c | 32 +++
- .../variants/e6520/overridetree.cb | 35 ++++
- 7 files changed, 300 insertions(+)
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6520/data.vbt
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6520/early_init.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6520/gpio.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6520/hda_verb.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6520/overridetree.cb
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-index d2786970ee..72bdc96c0a 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-@@ -23,6 +23,12 @@ config BOARD_DELL_LATITUDE_E6420
- select MAINBOARD_USES_IFD_GBE_REGION
- select SOUTHBRIDGE_INTEL_BD82X6X
-
-+config BOARD_DELL_LATITUDE_E6520
-+ select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
-+ select BOARD_ROMSIZE_KB_10240
-+ select MAINBOARD_USES_IFD_GBE_REGION
-+ select SOUTHBRIDGE_INTEL_BD82X6X
-+
- config BOARD_DELL_LATITUDE_E5530
- select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
- select BOARD_ROMSIZE_KB_12288
-@@ -50,6 +56,7 @@ config MAINBOARD_DIR
-
- config MAINBOARD_PART_NUMBER
- default "Latitude E6420" if BOARD_DELL_LATITUDE_E6420
-+ default "Latitude E6520" if BOARD_DELL_LATITUDE_E6520
- default "Latitude E5530" if BOARD_DELL_LATITUDE_E5530
- default "Latitude E6430" if BOARD_DELL_LATITUDE_E6430
- default "Latitude E6530" if BOARD_DELL_LATITUDE_E6530
-@@ -62,11 +69,13 @@ config USBDEBUG_HCD_INDEX
-
- config VARIANT_DIR
- default "e6420" if BOARD_DELL_LATITUDE_E6420
-+ default "e6520" if BOARD_DELL_LATITUDE_E6520
- default "e5530" if BOARD_DELL_LATITUDE_E5530
- default "e6430" if BOARD_DELL_LATITUDE_E6430
- default "e6530" if BOARD_DELL_LATITUDE_E6530
-
- config VGA_BIOS_ID
-+ default "8086,0116" if BOARD_DELL_LATITUDE_E6520
- default "8086,0166" if BOARD_DELL_LATITUDE_E5530
- default "8086,0126" if BOARD_DELL_LATITUDE_E6420
- default "8086,0166" if BOARD_DELL_LATITUDE_E6430 \
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-index 257d428a70..c7665ac263 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-@@ -3,6 +3,9 @@
- config BOARD_DELL_LATITUDE_E6420
- bool "Latitude E6420"
-
-+config BOARD_DELL_LATITUDE_E6520
-+ bool "Latitude E6520"
-+
- config BOARD_DELL_LATITUDE_E5530
- bool "Latitude E5530"
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6520/data.vbt b/src/mainboard/dell/snb_ivb_latitude/variants/e6520/data.vbt
-new file mode 100644
-index 0000000000000000000000000000000000000000..0ef16ee7cb482d2cb91ea80c3f419759355f7ba0
-GIT binary patch
-literal 6144
-zcmeHKZ){Ul6hE);wSB#PZ|mL$bQ^!}HW(eF@H)0JafGfbqsZ9G21{L7Sg{or$5uN)
-z_QgG55e!O(8p8*oBhhF`l$n^QF%rN;rzFNqqcPzFCd5QSB1Y7RKt1=pmTk1aFo9^Y
-z+x+gi_nvdlJ@?#m&wZWW=G#bH>ze$J`&!oe*Q|E0r!)d89LYY8b$aowZEoG-uiIF+
-z#n;$ezm6V<nGnvtc?lrGaf)1_);!W0?uqnojdw-1MQM|dwy`OcF?M@A)KgVV*N2}7
-zcXx+--0R}IwzW3-+`f2k?^Av5V7MpRO-q(9rn_R1@Xlz2Ztdy`$Gf6^w6~|bKi!!7
-z9;xq*^~bxmZQn^<^<`+2s=BdSM%VW2#FguN<FO^QuDhGIFquBu677q|cSj>jWFixQ
-z)4V8f0Gt`D`+>9Fr~tnJ76EJ`5D_F1cn-`0$RgN9unI6kfYkzIiO?W`ON4+34lv1_
-zNdPDkq1cf$p8^EW;TS*O$CdzNo#1fbIG_Oi0T(ti0jwyt0le_p_HlvX^CFvr)>$b>
-zO-z8^CSU`w=mIK7Q)@9fR;XUzrFu{T=rRyygIZBpU9+Or>+?4R9%~G?Y-|g)Z`Sti
-z+do(U*Wb-xR~DzjS<75#=Us4sH^C9U2FCbND7L7u$>M|<;t=AnRfI9C0v8c~AVg7t
-zIU<3D2oK^>L;%r(*o=4*u?Mja@dDyi#4zFn;(f#^#3*76aUSs#;tJv#La-6YLRdQB
-zdcvfERkvH?k~GJlfM<HR476j(@nfm+47<!Ult@^ua5M3h6A}q=C0ognX9aX4mxq)U
-zXOhm=DbLene?C%_16Q)2NRV@Yacz`D;{V>Ve-1?&ZXy}n)YwnVAgNlz#zX;=IX)-F
-z)9LL3lbEdY5Co)LsK?vP)7s}G(5xduE!Y!#Wgh<IN3(3ey=-oWU(9aEJ_HzV53Jbq
-zj5B5RjzLUt>_T&xi$uUA#0e}X3D~`J(bHz;DgTa@GrpW6=>eZwJeNYYo*GjF=``;(
-zuoQ3|V5YoKd$j=KK{`uSX*DeU1oJg=+RT6)rLe6%2>Ci^!5ao=*gS}wFN=nUf`fTF
-zM?Gb5ycWjM7I?MJ!2;w|LFg=UoLq-ytr2iemG)AsW}bI4X9PK}T5UKsQi7anu=tD6
-zf|={kXkNeQBD>6bQ3taC8XJOJ^e40_ydyfr&a41L^1)jNrK<B_wV}+ZE`p;QK=rDz
-zTw`SJ+e`Oc*icaF4INF51Xg*~ts@m)@9ETt(*@N7yy0)Ddce%i9{^k2kbd8=Wns~P
-zWBD$~himxDharxF@f!ti^0$~9Zxt{tg`@Dbl_0Ki2Xp_MEw-<z6qgep;XYmR%Dl-F
-z%3cBfcN;Avikpz-gmw_6mymu!Unk0YgnUfsk3{*6kQ;=S*p(_fS!JhDyYh^k?6uRk
-z?8--W@~NHvY*+ra6SG9iC1s^V)<|@Rqzp*pd5NBslrs`JC(&Oeg~v}CnJ$x+)iP<8
-z=`LA0Ad@39{XkZ}kjXbP{YzHtS!70*yy%LcnJ#cz4u%*Wq!^d*AVMZdr&l=#Qgik~
-ze2l)cX+!kF9EaFhY;0^Uo_#VNC?7K2Tf=ZR1y5);b!mCGG?<cc#M0rtHKYeKi%BE?
-z@Y6|P8fx#li}c`Uv24UGyZaM0To;Ep<_AWZA1t~bFgI)uf}&Eq=L_Cs89=>wnT0Vx
-z-jp>o1ffJNommZ4?=TIPlePIw0hgQ706f*tBC`#pg>9&zRHe>J2%RxBTrOc6Adh9E
-ziJr`?VQH!N!_GkoKaoq|+3$^Ae0#sUxXlmM1Huq~g<=Ls?ILv+nQcH%PQedGOlH=Q
-z77rMcJlH4Mkc#U2(IDv>rsm1aHpsdL_RdT^i_ACcQUMIJcSus}*(?CIiy^#^=t=g1
-z+*^Zbh30&^#_bKclSy9pL$<B~pK8m*sLpIdnHM@W$nA7Ea@Z`x27K?aNK<@lCW(2L
-zb@kB3H8kKy4W3Hu)NN|kd!DL^o#iR9a{QYV-Wl&r&hmIFX{ezkIV<4zFiVUQ@K>ao
-z00DnFy~Uek!JRwhVX!of0)$Sa*X^S~LMQH0<E(UUx}L=|;Kgw(r(4q=nD)T52c|tR
-O?SW|zOncy=dEg(6JAK&z
-
-literal 0
-HcmV?d00001
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6520/early_init.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6520/early_init.c
-new file mode 100644
-index 0000000000..b6415a428b
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6520/early_init.c
-@@ -0,0 +1,31 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <bootblock_common.h>
-+#include <device/pci_ops.h>
-+#include <ec/dell/mec5035/mec5035.h>
-+#include <southbridge/intel/bd82x6x/pch.h>
-+
-+const struct southbridge_usb_port mainboard_usb_ports[] = {
-+ { 1, 1, 0 },
-+ { 1, 1, 0 },
-+ { 1, 1, 1 },
-+ { 1, 1, 1 },
-+ { 1, 0, 2 },
-+ { 1, 1, 2 },
-+ { 1, 0, 3 },
-+ { 1, 0, 3 },
-+ { 1, 1, 5 },
-+ { 1, 1, 5 },
-+ { 1, 1, 7 },
-+ { 1, 1, 6 },
-+ { 1, 0, 6 },
-+ { 1, 0, 7 },
-+};
-+
-+void bootblock_mainboard_early_init(void)
-+{
-+ pci_write_config16(PCH_LPC_DEV, LPC_EN, CNF1_LPC_EN | MC_LPC_EN
-+ | KBC_LPC_EN | FDD_LPC_EN | LPT_LPC_EN
-+ | COMB_LPC_EN | COMA_LPC_EN);
-+ mec5035_early_init();
-+}
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6520/gpio.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6520/gpio.c
-new file mode 100644
-index 0000000000..61f01816c4
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6520/gpio.c
-@@ -0,0 +1,190 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <southbridge/intel/common/gpio.h>
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_mode = {
-+ .gpio0 = GPIO_MODE_GPIO,
-+ .gpio1 = GPIO_MODE_NATIVE,
-+ .gpio2 = GPIO_MODE_GPIO,
-+ .gpio3 = GPIO_MODE_NATIVE,
-+ .gpio4 = GPIO_MODE_GPIO,
-+ .gpio5 = GPIO_MODE_NATIVE,
-+ .gpio6 = GPIO_MODE_GPIO,
-+ .gpio7 = GPIO_MODE_GPIO,
-+ .gpio8 = GPIO_MODE_GPIO,
-+ .gpio9 = GPIO_MODE_NATIVE,
-+ .gpio10 = GPIO_MODE_NATIVE,
-+ .gpio11 = GPIO_MODE_NATIVE,
-+ .gpio12 = GPIO_MODE_NATIVE,
-+ .gpio13 = GPIO_MODE_GPIO,
-+ .gpio14 = GPIO_MODE_GPIO,
-+ .gpio15 = GPIO_MODE_GPIO,
-+ .gpio16 = GPIO_MODE_GPIO,
-+ .gpio17 = GPIO_MODE_GPIO,
-+ .gpio18 = GPIO_MODE_NATIVE,
-+ .gpio19 = GPIO_MODE_GPIO,
-+ .gpio20 = GPIO_MODE_NATIVE,
-+ .gpio21 = GPIO_MODE_GPIO,
-+ .gpio22 = GPIO_MODE_GPIO,
-+ .gpio23 = GPIO_MODE_NATIVE,
-+ .gpio24 = GPIO_MODE_GPIO,
-+ .gpio25 = GPIO_MODE_NATIVE,
-+ .gpio26 = GPIO_MODE_NATIVE,
-+ .gpio27 = GPIO_MODE_GPIO,
-+ .gpio28 = GPIO_MODE_GPIO,
-+ .gpio29 = GPIO_MODE_GPIO,
-+ .gpio30 = GPIO_MODE_GPIO,
-+ .gpio31 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_direction = {
-+ .gpio0 = GPIO_DIR_INPUT,
-+ .gpio2 = GPIO_DIR_INPUT,
-+ .gpio4 = GPIO_DIR_INPUT,
-+ .gpio6 = GPIO_DIR_INPUT,
-+ .gpio7 = GPIO_DIR_INPUT,
-+ .gpio8 = GPIO_DIR_INPUT,
-+ .gpio13 = GPIO_DIR_INPUT,
-+ .gpio14 = GPIO_DIR_INPUT,
-+ .gpio15 = GPIO_DIR_INPUT,
-+ .gpio16 = GPIO_DIR_INPUT,
-+ .gpio17 = GPIO_DIR_INPUT,
-+ .gpio19 = GPIO_DIR_INPUT,
-+ .gpio21 = GPIO_DIR_INPUT,
-+ .gpio22 = GPIO_DIR_INPUT,
-+ .gpio24 = GPIO_DIR_INPUT,
-+ .gpio27 = GPIO_DIR_INPUT,
-+ .gpio28 = GPIO_DIR_INPUT,
-+ .gpio29 = GPIO_DIR_INPUT,
-+ .gpio30 = GPIO_DIR_OUTPUT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_level = {
-+ .gpio30 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_reset = {
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_invert = {
-+ .gpio0 = GPIO_INVERT,
-+ .gpio8 = GPIO_INVERT,
-+ .gpio14 = GPIO_INVERT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_blink = {
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_mode = {
-+ .gpio32 = GPIO_MODE_NATIVE,
-+ .gpio33 = GPIO_MODE_GPIO,
-+ .gpio34 = GPIO_MODE_GPIO,
-+ .gpio35 = GPIO_MODE_GPIO,
-+ .gpio36 = GPIO_MODE_GPIO,
-+ .gpio37 = GPIO_MODE_GPIO,
-+ .gpio38 = GPIO_MODE_GPIO,
-+ .gpio39 = GPIO_MODE_GPIO,
-+ .gpio40 = GPIO_MODE_NATIVE,
-+ .gpio41 = GPIO_MODE_NATIVE,
-+ .gpio42 = GPIO_MODE_NATIVE,
-+ .gpio43 = GPIO_MODE_NATIVE,
-+ .gpio44 = GPIO_MODE_NATIVE,
-+ .gpio45 = GPIO_MODE_GPIO,
-+ .gpio46 = GPIO_MODE_NATIVE,
-+ .gpio47 = GPIO_MODE_NATIVE,
-+ .gpio48 = GPIO_MODE_GPIO,
-+ .gpio49 = GPIO_MODE_GPIO,
-+ .gpio50 = GPIO_MODE_NATIVE,
-+ .gpio51 = GPIO_MODE_GPIO,
-+ .gpio52 = GPIO_MODE_GPIO,
-+ .gpio53 = GPIO_MODE_NATIVE,
-+ .gpio54 = GPIO_MODE_GPIO,
-+ .gpio55 = GPIO_MODE_NATIVE,
-+ .gpio56 = GPIO_MODE_NATIVE,
-+ .gpio57 = GPIO_MODE_GPIO,
-+ .gpio58 = GPIO_MODE_NATIVE,
-+ .gpio59 = GPIO_MODE_NATIVE,
-+ .gpio60 = GPIO_MODE_GPIO,
-+ .gpio61 = GPIO_MODE_NATIVE,
-+ .gpio62 = GPIO_MODE_NATIVE,
-+ .gpio63 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_direction = {
-+ .gpio33 = GPIO_DIR_INPUT,
-+ .gpio34 = GPIO_DIR_OUTPUT,
-+ .gpio35 = GPIO_DIR_INPUT,
-+ .gpio36 = GPIO_DIR_INPUT,
-+ .gpio37 = GPIO_DIR_INPUT,
-+ .gpio38 = GPIO_DIR_INPUT,
-+ .gpio39 = GPIO_DIR_INPUT,
-+ .gpio45 = GPIO_DIR_OUTPUT,
-+ .gpio48 = GPIO_DIR_INPUT,
-+ .gpio49 = GPIO_DIR_OUTPUT,
-+ .gpio51 = GPIO_DIR_INPUT,
-+ .gpio52 = GPIO_DIR_INPUT,
-+ .gpio54 = GPIO_DIR_INPUT,
-+ .gpio57 = GPIO_DIR_INPUT,
-+ .gpio60 = GPIO_DIR_OUTPUT,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_level = {
-+ .gpio34 = GPIO_LEVEL_HIGH,
-+ .gpio45 = GPIO_LEVEL_LOW,
-+ .gpio49 = GPIO_LEVEL_LOW,
-+ .gpio60 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_reset = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_mode = {
-+ .gpio64 = GPIO_MODE_NATIVE,
-+ .gpio65 = GPIO_MODE_NATIVE,
-+ .gpio66 = GPIO_MODE_NATIVE,
-+ .gpio67 = GPIO_MODE_NATIVE,
-+ .gpio68 = GPIO_MODE_GPIO,
-+ .gpio69 = GPIO_MODE_GPIO,
-+ .gpio70 = GPIO_MODE_GPIO,
-+ .gpio71 = GPIO_MODE_GPIO,
-+ .gpio72 = GPIO_MODE_NATIVE,
-+ .gpio73 = GPIO_MODE_NATIVE,
-+ .gpio74 = GPIO_MODE_NATIVE,
-+ .gpio75 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_direction = {
-+ .gpio68 = GPIO_DIR_INPUT,
-+ .gpio69 = GPIO_DIR_INPUT,
-+ .gpio70 = GPIO_DIR_INPUT,
-+ .gpio71 = GPIO_DIR_INPUT,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_level = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_reset = {
-+};
-+
-+const struct pch_gpio_map mainboard_gpio_map = {
-+ .set1 = {
-+ .mode = &pch_gpio_set1_mode,
-+ .direction = &pch_gpio_set1_direction,
-+ .level = &pch_gpio_set1_level,
-+ .blink = &pch_gpio_set1_blink,
-+ .invert = &pch_gpio_set1_invert,
-+ .reset = &pch_gpio_set1_reset,
-+ },
-+ .set2 = {
-+ .mode = &pch_gpio_set2_mode,
-+ .direction = &pch_gpio_set2_direction,
-+ .level = &pch_gpio_set2_level,
-+ .reset = &pch_gpio_set2_reset,
-+ },
-+ .set3 = {
-+ .mode = &pch_gpio_set3_mode,
-+ .direction = &pch_gpio_set3_direction,
-+ .level = &pch_gpio_set3_level,
-+ .reset = &pch_gpio_set3_reset,
-+ },
-+};
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6520/hda_verb.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6520/hda_verb.c
-new file mode 100644
-index 0000000000..ae376691e7
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6520/hda_verb.c
-@@ -0,0 +1,32 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <device/azalia_device.h>
-+
-+const u32 cim_verb_data[] = {
-+ 0x111d76e7, /* Codec Vendor / Device ID: IDT */
-+ 0x10280494, /* Subsystem ID */
-+ 11, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(0, 0x10280494),
-+ AZALIA_PIN_CFG(0, 0x0a, 0x03a11020),
-+ AZALIA_PIN_CFG(0, 0x0b, 0x0321101f),
-+ AZALIA_PIN_CFG(0, 0x0c, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x0d, 0x90170110),
-+ AZALIA_PIN_CFG(0, 0x0e, 0x23011050),
-+ AZALIA_PIN_CFG(0, 0x0f, 0x23a1102e),
-+ AZALIA_PIN_CFG(0, 0x10, 0x400000f3),
-+ AZALIA_PIN_CFG(0, 0x11, 0x400000f2),
-+ AZALIA_PIN_CFG(0, 0x1f, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x20, 0x400000f0),
-+
-+ 0x80862805, /* Codec Vendor / Device ID: Intel */
-+ 0x80860101, /* Subsystem ID */
-+ 4, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(3, 0x80860101),
-+ AZALIA_PIN_CFG(3, 0x05, 0x18560010),
-+ AZALIA_PIN_CFG(3, 0x06, 0x18560020),
-+ AZALIA_PIN_CFG(3, 0x07, 0x18560030),
-+};
-+
-+const u32 pc_beep_verbs[0] = {};
-+
-+AZALIA_ARRAY_SIZES;
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6520/overridetree.cb b/src/mainboard/dell/snb_ivb_latitude/variants/e6520/overridetree.cb
-new file mode 100644
-index 0000000000..f90f2dee1f
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6520/overridetree.cb
-@@ -0,0 +1,35 @@
-+## SPDX-License-Identifier: GPL-2.0-or-later
-+
-+chip northbridge/intel/sandybridge
-+ device domain 0 on
-+ subsystemid 0x1028 0x0494 inherit
-+
-+ device ref igd on
-+ register "gpu_cpu_backlight" = "0x00001312"
-+ register "gpu_pch_backlight" = "0x13121312"
-+ end
-+
-+ chip southbridge/intel/bd82x6x
-+ register "usb_port_config" = "{
-+ { 1, 1, 0 },
-+ { 1, 1, 0 },
-+ { 1, 1, 1 },
-+ { 1, 1, 1 },
-+ { 1, 0, 2 },
-+ { 1, 1, 2 },
-+ { 1, 1, 3 },
-+ { 1, 1, 3 },
-+ { 1, 1, 5 },
-+ { 1, 1, 5 },
-+ { 1, 1, 7 },
-+ { 1, 1, 6 },
-+ { 1, 0, 6 },
-+ { 1, 0, 7 },
-+ }"
-+
-+ device ref sata1 on
-+ register "sata_port_map" = "0x3b"
-+ end
-+ end
-+ end
-+end
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0021-nb-intel-haswell-make-IOMMU-a-runtime-option.patch b/config/coreboot/default/patches/0011-nb-intel-haswell-make-IOMMU-a-runtime-option.patch
index b3305e58..f8c56155 100644
--- a/config/coreboot/default/patches/0021-nb-intel-haswell-make-IOMMU-a-runtime-option.patch
+++ b/config/coreboot/default/patches/0011-nb-intel-haswell-make-IOMMU-a-runtime-option.patch
@@ -1,7 +1,7 @@
-From 4c7577314f19e934d690c4cce3642fe693400c07 Mon Sep 17 00:00:00 2001
+From a16ff494adb1f706d402a2e167d0d53c775d0897 Mon Sep 17 00:00:00 2001
From: Leah Rowe <info@minifree.org>
Date: Sat, 2 Mar 2024 22:51:09 +0000
-Subject: [PATCH 21/51] nb/intel/haswell: make IOMMU a runtime option
+Subject: [PATCH 11/37] nb/intel/haswell: make IOMMU a runtime option
When I tested graphics cards on a coreboot port for Dell
OptiPlex 9020 SFF, I could not use a graphics card unless
diff --git a/config/coreboot/default/patches/0022-dell-optiplex_9020-Disable-IOMMU-by-default.patch b/config/coreboot/default/patches/0012-dell-optiplex_9020-Disable-IOMMU-by-default.patch
index f18f119e..e578d22a 100644
--- a/config/coreboot/default/patches/0022-dell-optiplex_9020-Disable-IOMMU-by-default.patch
+++ b/config/coreboot/default/patches/0012-dell-optiplex_9020-Disable-IOMMU-by-default.patch
@@ -1,7 +1,7 @@
-From b5695d0f0dc44ed1eb1feac008e601040feda55d Mon Sep 17 00:00:00 2001
+From 4b0536ce7cd55eedc52d13497bea59d91e8924d8 Mon Sep 17 00:00:00 2001
From: Leah Rowe <info@minifree.org>
Date: Sat, 2 Mar 2024 23:00:09 +0000
-Subject: [PATCH 22/51] dell/optiplex_9020: Disable IOMMU by default
+Subject: [PATCH 12/37] dell/optiplex_9020: Disable IOMMU by default
Needed to make graphics cards work. Turning it on is
recommended if only using iGPU, otherwise leave it off
diff --git a/config/coreboot/default/patches/0012-mb-dell-Add-Latitude-E5520-Sandy-Bridge.patch b/config/coreboot/default/patches/0012-mb-dell-Add-Latitude-E5520-Sandy-Bridge.patch
deleted file mode 100644
index 4fd3bba2..00000000
--- a/config/coreboot/default/patches/0012-mb-dell-Add-Latitude-E5520-Sandy-Bridge.patch
+++ /dev/null
@@ -1,442 +0,0 @@
-From 3f8eade6150f582129332f6347e9a685f8a7b500 Mon Sep 17 00:00:00 2001
-From: Nicholas Chin <nic.c3.14@gmail.com>
-Date: Wed, 7 Feb 2024 10:23:38 -0700
-Subject: [PATCH 12/51] mb/dell: Add Latitude E5520 (Sandy Bridge)
-
-Mainboard is Krug 15". I do not physically have this system; someone
-with physical access to one sent me the output of autoport which I then
-modified to produce this port. I was also sent the VBT binary, which was
-obtained from `/sys/kernel/debug/dri/0/i915_vbt` while running version
-A14 of the vendor firmware.
-
-This was originally tested and found to be working as a standalone
-board port in Libreboot, but this variant based port in upstream
-coreboot has not been tested.
-
-This can be internally flashed by sending a command to the EC, which
-causes the EC to pull the FDO pin low and the firmware to skip setting
-up any chipset based write protections [1]. The EC is the SMSC MEC5055,
-which seems to be compatible with the existing MEC5035 code.
-
-[1] https://gitlab.com/nic3-14159/dell-flash-unlock
-
-Change-Id: Ic9bfc028d4b8ae01ccc019157bb53e7764671134
-Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>
----
- src/mainboard/dell/snb_ivb_latitude/Kconfig | 10 +-
- .../dell/snb_ivb_latitude/Kconfig.name | 3 +
- .../snb_ivb_latitude/variants/e5520/data.vbt | Bin 0 -> 6144 bytes
- .../variants/e5520/early_init.c | 14 ++
- .../snb_ivb_latitude/variants/e5520/gpio.c | 195 ++++++++++++++++++
- .../variants/e5520/hda_verb.c | 32 +++
- .../variants/e5520/overridetree.cb | 39 ++++
- 7 files changed, 292 insertions(+), 1 deletion(-)
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e5520/data.vbt
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e5520/early_init.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e5520/gpio.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e5520/hda_verb.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e5520/overridetree.cb
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-index 72bdc96c0a..4e94a7ef80 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-@@ -17,6 +17,11 @@ config BOARD_DELL_SNB_IVB_LATITUDE_COMMON
- select SYSTEM_TYPE_LAPTOP
- select USE_NATIVE_RAMINIT
-
-+config BOARD_DELL_LATITUDE_E5520
-+ select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
-+ select BOARD_ROMSIZE_KB_6144
-+ select SOUTHBRIDGE_INTEL_BD82X6X
-+
- config BOARD_DELL_LATITUDE_E6420
- select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
- select BOARD_ROMSIZE_KB_10240
-@@ -55,6 +60,7 @@ config MAINBOARD_DIR
- default "dell/snb_ivb_latitude"
-
- config MAINBOARD_PART_NUMBER
-+ default "Latitude E5520" if BOARD_DELL_LATITUDE_E5520
- default "Latitude E6420" if BOARD_DELL_LATITUDE_E6420
- default "Latitude E6520" if BOARD_DELL_LATITUDE_E6520
- default "Latitude E5530" if BOARD_DELL_LATITUDE_E5530
-@@ -68,6 +74,7 @@ config USBDEBUG_HCD_INDEX
- default 2
-
- config VARIANT_DIR
-+ default "e5520" if BOARD_DELL_LATITUDE_E5520
- default "e6420" if BOARD_DELL_LATITUDE_E6420
- default "e6520" if BOARD_DELL_LATITUDE_E6520
- default "e5530" if BOARD_DELL_LATITUDE_E5530
-@@ -77,7 +84,8 @@ config VARIANT_DIR
- config VGA_BIOS_ID
- default "8086,0116" if BOARD_DELL_LATITUDE_E6520
- default "8086,0166" if BOARD_DELL_LATITUDE_E5530
-- default "8086,0126" if BOARD_DELL_LATITUDE_E6420
-+ default "8086,0126" if BOARD_DELL_LATITUDE_E6420 \
-+ || BOARD_DELL_LATITUDE_E5520
- default "8086,0166" if BOARD_DELL_LATITUDE_E6430 \
- || BOARD_DELL_LATITUDE_E6530
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-index c7665ac263..7976691f21 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-@@ -1,5 +1,8 @@
- ## SPDX-License-Identifier: GPL-2.0-only
-
-+config BOARD_DELL_LATITUDE_E5520
-+ bool "Latitude E5520"
-+
- config BOARD_DELL_LATITUDE_E6420
- bool "Latitude E6420"
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e5520/data.vbt b/src/mainboard/dell/snb_ivb_latitude/variants/e5520/data.vbt
-new file mode 100644
-index 0000000000000000000000000000000000000000..b511e75262e37fa123d674e9a7b21a8dfe427729
-GIT binary patch
-literal 6144
-zcmeHKZ){Ul6hE);wSBvNZ|mL$bmQOM2BTvXUI!}^N9ejTij1vnu+)Wx6<c9(Y_%K6
-zzOV-@f<ehpWB5RHBpMBgG7}RuMuM2=l*E{6G$wq&gqTQ3#E2RZsOP@dvW*rP7>Fjj
-z&F`Lj?>YC}bI(2Z+}C+6zKyiGrosQXuW7A+&1%<rN+Y1ck(}dLrx)Ma#^x>lnvFGE
-zeD#gB>*#Tq4&j^|7Xcz1r^pp*)g#T}u1Me3ct>Pgls5Qi3!6e2W0%`a-Ic|3efWuR
-zXJ@#}wJyGMTXTcY<%@TBKh@(3hP$Gjv}E}rx-%9D_eLXhYe!c&-VyDg-Cdo1>Biji
-zNNsnlFW#|jdoOj?mZ43m>cVO%UE9@*E7x|%V~c4`XD4l9GCi~@+7pfMibfX8L?!^I
-zc~Rg1I5SxH1DAEZ0{jA41jrJBh#-l;b6^%g7QrThRe)&%tQH_!ggOD7A_PRRgGuI0
-z0zi=n#rCB66d-sO$M~^6wgeb$2fH1|0R`v}xUiWCU`4SF;Dyh&j|mK&6WJWJ&Pq9I
-zVgmFQfh+)vE}(KWwHA|Oh3fSkss|;2E(2i}s1?gRRV%8!K7U={vHD=s#+Fd)W^M1j
-z{R4$??VSvEWpgT=vCM&1-U$bI6CB~IV3Z$$Vv7o!EDnev4j~R(MHsazZ~^fLLKGF4
-zEfQFOa3dZ?1Q1P#&4?!vyAk^k&m&$z3?WV+-b0*1j37o4=MX<3E+eiYge(Ht2umAW
-zOPDmU>UL{flI9u|@JtVvfp#o8ek?VfVV9YP5(%pnZX~{PKq4WoWGmV8t$=Ri@{zLQ
-zNYYt4<$0Ry&qIoG;7s-t333)Nu8opN{NG!)&!I@eO(cVx8vBVEBvotJ7%yNl$7iQ_
-zI=xk30+V$ff`F6<wRoF(TK%j9nsr#H23umU%)_7jNOl%*FPU567qbg;4gtp711nj2
-z#+kHw`v4|5cA+`UMIvAl;slnH1nl0v=xH<al>1}ljxDE1dcda^&!do|r^eJkI?aC-
-zEQMSfm?<w*Unzumkj_w5>VYL6W4=aCiy4rk%xq~5LV?bi|GL2$G7li<%c7yd;6T34
-zQBN5huZ3~6`ChGkpb$Bg5ITb#2iK-qs|1`=sl6Dhn(Lj&8Agt?S{sTDmmtRj7Jm_1
-zFnt{w&FdFkWS3bl>OeL?eO+*i{)9G!cSI-InGt|U0eEYmRCOHm7|I;#LO8ksRIeJ#
-zGe+jTwPg4C4TYuN(9zULV3k+hI$YuPo=%N8oZ#u_4S!3Xelt6N0BmuC`hCNeg+&97
-z6*!>)uHvr%2004GZv?!_-y&|TRmil=9D%Q`1aXBsnD^gov3*UZI34&1_vn(B=T4kZ
-z_A>ClXVIBNaS^hd&^DrU6VgZMYeadMkdFxcktn|ra-Gl;n^I{bt86rCQ=YMry*B!$
-zP5ID9KDE)GZOY#^VwPyRq^y+48j0?ZlzxdkC()CV@`*&wO7vGr;qjA3rb}gIwM-gi
-zx>HsT$mEDj-<OpyWb%zn|B@A3Hkp<!FT5;hrt_SZiy?*wDaIu{h>%Ir=@rh7)SR;b
-zAEWQGv_X1)wq0y5Ha0c~&psIsln<Hiu3;#Lf;%*eI<@?p8cfMJV(IYi8q$NA#iS8`
-z_~|4t4b^wtMSAeFST^F8-Tm<zu8D&j^8=&I4;I}Im>aeSK~X8*^Z9SE44_`P#KIUL
-zf6^N2f>5HCPWM3N+f0MyWOV^kz~!-wVc4MRXOY>4Jsxd1RyBKEMzNf{RKhesKFdbq
-zJ(*d<l2Y#n?E?~iBA39P?~Pr2d#}5=#Sfl-VGzGUF$4U2KcqCIVlwkC(&7PQk_X!a
-z8}3Jgq-&U*Co|h1>l)ZQGyW_x->i#;FvQ*=Nv&nG0N5@D@jjv_Q}K}6MP?1A6`JGe
-zDwj9pN+x;T4>`I9e5x(uqdK#OGB31ikk@Xv=dxLb4fx(;ktX@rOb~M~?dYQQYiPia
-z8r;jUQ?sd2@3||-cb2Eb%JFYfxHsONoaJ^eqoKN{<g9?-%`7oWz+aJS0tEc!^d@hD
-z1-I{%hr!Y?0uVZpUbl__37xn@jkD6Z>3SATgBQlEoN7&ZV9Eni9+>jLln16fFy(=V
-H=7E0zE^L4Z
-
-literal 0
-HcmV?d00001
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e5520/early_init.c b/src/mainboard/dell/snb_ivb_latitude/variants/e5520/early_init.c
-new file mode 100644
-index 0000000000..ff83db095b
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e5520/early_init.c
-@@ -0,0 +1,14 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <bootblock_common.h>
-+#include <device/pci_ops.h>
-+#include <ec/dell/mec5035/mec5035.h>
-+#include <southbridge/intel/bd82x6x/pch.h>
-+
-+void bootblock_mainboard_early_init(void)
-+{
-+ pci_write_config16(PCH_LPC_DEV, LPC_EN, CNF1_LPC_EN | MC_LPC_EN
-+ | KBC_LPC_EN | FDD_LPC_EN | LPT_LPC_EN
-+ | COMB_LPC_EN | COMA_LPC_EN);
-+ mec5035_early_init();
-+}
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e5520/gpio.c b/src/mainboard/dell/snb_ivb_latitude/variants/e5520/gpio.c
-new file mode 100644
-index 0000000000..f76b93d9f0
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e5520/gpio.c
-@@ -0,0 +1,195 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <southbridge/intel/common/gpio.h>
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_mode = {
-+ .gpio0 = GPIO_MODE_GPIO,
-+ .gpio1 = GPIO_MODE_NATIVE,
-+ .gpio2 = GPIO_MODE_GPIO,
-+ .gpio3 = GPIO_MODE_GPIO,
-+ .gpio4 = GPIO_MODE_GPIO,
-+ .gpio5 = GPIO_MODE_NATIVE,
-+ .gpio6 = GPIO_MODE_GPIO,
-+ .gpio7 = GPIO_MODE_GPIO,
-+ .gpio8 = GPIO_MODE_GPIO,
-+ .gpio9 = GPIO_MODE_NATIVE,
-+ .gpio10 = GPIO_MODE_NATIVE,
-+ .gpio11 = GPIO_MODE_NATIVE,
-+ .gpio12 = GPIO_MODE_GPIO,
-+ .gpio13 = GPIO_MODE_GPIO,
-+ .gpio14 = GPIO_MODE_GPIO,
-+ .gpio15 = GPIO_MODE_GPIO,
-+ .gpio16 = GPIO_MODE_NATIVE,
-+ .gpio17 = GPIO_MODE_GPIO,
-+ .gpio18 = GPIO_MODE_NATIVE,
-+ .gpio19 = GPIO_MODE_GPIO,
-+ .gpio20 = GPIO_MODE_NATIVE,
-+ .gpio21 = GPIO_MODE_GPIO,
-+ .gpio22 = GPIO_MODE_GPIO,
-+ .gpio23 = GPIO_MODE_NATIVE,
-+ .gpio24 = GPIO_MODE_GPIO,
-+ .gpio25 = GPIO_MODE_NATIVE,
-+ .gpio26 = GPIO_MODE_NATIVE,
-+ .gpio27 = GPIO_MODE_GPIO,
-+ .gpio28 = GPIO_MODE_GPIO,
-+ .gpio29 = GPIO_MODE_GPIO,
-+ .gpio30 = GPIO_MODE_GPIO,
-+ .gpio31 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_direction = {
-+ .gpio0 = GPIO_DIR_INPUT,
-+ .gpio2 = GPIO_DIR_INPUT,
-+ .gpio3 = GPIO_DIR_INPUT,
-+ .gpio4 = GPIO_DIR_INPUT,
-+ .gpio6 = GPIO_DIR_INPUT,
-+ .gpio7 = GPIO_DIR_INPUT,
-+ .gpio8 = GPIO_DIR_INPUT,
-+ .gpio12 = GPIO_DIR_OUTPUT,
-+ .gpio13 = GPIO_DIR_INPUT,
-+ .gpio14 = GPIO_DIR_INPUT,
-+ .gpio15 = GPIO_DIR_INPUT,
-+ .gpio17 = GPIO_DIR_INPUT,
-+ .gpio19 = GPIO_DIR_INPUT,
-+ .gpio21 = GPIO_DIR_INPUT,
-+ .gpio22 = GPIO_DIR_INPUT,
-+ .gpio24 = GPIO_DIR_INPUT,
-+ .gpio27 = GPIO_DIR_INPUT,
-+ .gpio28 = GPIO_DIR_INPUT,
-+ .gpio29 = GPIO_DIR_INPUT,
-+ .gpio30 = GPIO_DIR_OUTPUT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_level = {
-+ .gpio12 = GPIO_LEVEL_HIGH,
-+ .gpio30 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_reset = {
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_invert = {
-+ .gpio0 = GPIO_INVERT,
-+ .gpio8 = GPIO_INVERT,
-+ .gpio14 = GPIO_INVERT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_blink = {
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_mode = {
-+ .gpio32 = GPIO_MODE_NATIVE,
-+ .gpio33 = GPIO_MODE_GPIO,
-+ .gpio34 = GPIO_MODE_GPIO,
-+ .gpio35 = GPIO_MODE_GPIO,
-+ .gpio36 = GPIO_MODE_GPIO,
-+ .gpio37 = GPIO_MODE_GPIO,
-+ .gpio38 = GPIO_MODE_GPIO,
-+ .gpio39 = GPIO_MODE_GPIO,
-+ .gpio40 = GPIO_MODE_NATIVE,
-+ .gpio41 = GPIO_MODE_NATIVE,
-+ .gpio42 = GPIO_MODE_NATIVE,
-+ .gpio43 = GPIO_MODE_NATIVE,
-+ .gpio44 = GPIO_MODE_NATIVE,
-+ .gpio45 = GPIO_MODE_NATIVE,
-+ .gpio46 = GPIO_MODE_GPIO,
-+ .gpio47 = GPIO_MODE_NATIVE,
-+ .gpio48 = GPIO_MODE_GPIO,
-+ .gpio49 = GPIO_MODE_NATIVE,
-+ .gpio50 = GPIO_MODE_GPIO,
-+ .gpio51 = GPIO_MODE_GPIO,
-+ .gpio52 = GPIO_MODE_GPIO,
-+ .gpio53 = GPIO_MODE_GPIO,
-+ .gpio54 = GPIO_MODE_GPIO,
-+ .gpio55 = GPIO_MODE_GPIO,
-+ .gpio56 = GPIO_MODE_GPIO,
-+ .gpio57 = GPIO_MODE_GPIO,
-+ .gpio58 = GPIO_MODE_NATIVE,
-+ .gpio59 = GPIO_MODE_NATIVE,
-+ .gpio60 = GPIO_MODE_GPIO,
-+ .gpio61 = GPIO_MODE_NATIVE,
-+ .gpio62 = GPIO_MODE_NATIVE,
-+ .gpio63 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_direction = {
-+ .gpio33 = GPIO_DIR_INPUT,
-+ .gpio34 = GPIO_DIR_OUTPUT,
-+ .gpio35 = GPIO_DIR_INPUT,
-+ .gpio36 = GPIO_DIR_INPUT,
-+ .gpio37 = GPIO_DIR_OUTPUT,
-+ .gpio38 = GPIO_DIR_INPUT,
-+ .gpio39 = GPIO_DIR_INPUT,
-+ .gpio46 = GPIO_DIR_OUTPUT,
-+ .gpio48 = GPIO_DIR_INPUT,
-+ .gpio50 = GPIO_DIR_OUTPUT,
-+ .gpio51 = GPIO_DIR_OUTPUT,
-+ .gpio52 = GPIO_DIR_INPUT,
-+ .gpio53 = GPIO_DIR_INPUT,
-+ .gpio54 = GPIO_DIR_INPUT,
-+ .gpio55 = GPIO_DIR_OUTPUT,
-+ .gpio56 = GPIO_DIR_INPUT,
-+ .gpio57 = GPIO_DIR_INPUT,
-+ .gpio60 = GPIO_DIR_OUTPUT,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_level = {
-+ .gpio34 = GPIO_LEVEL_LOW,
-+ .gpio37 = GPIO_LEVEL_LOW,
-+ .gpio46 = GPIO_LEVEL_HIGH,
-+ .gpio50 = GPIO_LEVEL_HIGH,
-+ .gpio51 = GPIO_LEVEL_LOW,
-+ .gpio55 = GPIO_LEVEL_LOW,
-+ .gpio60 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_reset = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_mode = {
-+ .gpio64 = GPIO_MODE_NATIVE,
-+ .gpio65 = GPIO_MODE_NATIVE,
-+ .gpio66 = GPIO_MODE_NATIVE,
-+ .gpio67 = GPIO_MODE_NATIVE,
-+ .gpio68 = GPIO_MODE_NATIVE,
-+ .gpio69 = GPIO_MODE_NATIVE,
-+ .gpio70 = GPIO_MODE_NATIVE,
-+ .gpio71 = GPIO_MODE_NATIVE,
-+ .gpio72 = GPIO_MODE_NATIVE,
-+ .gpio73 = GPIO_MODE_NATIVE,
-+ .gpio74 = GPIO_MODE_GPIO,
-+ .gpio75 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_direction = {
-+ .gpio74 = GPIO_DIR_INPUT,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_level = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_reset = {
-+};
-+
-+const struct pch_gpio_map mainboard_gpio_map = {
-+ .set1 = {
-+ .mode = &pch_gpio_set1_mode,
-+ .direction = &pch_gpio_set1_direction,
-+ .level = &pch_gpio_set1_level,
-+ .blink = &pch_gpio_set1_blink,
-+ .invert = &pch_gpio_set1_invert,
-+ .reset = &pch_gpio_set1_reset,
-+ },
-+ .set2 = {
-+ .mode = &pch_gpio_set2_mode,
-+ .direction = &pch_gpio_set2_direction,
-+ .level = &pch_gpio_set2_level,
-+ .reset = &pch_gpio_set2_reset,
-+ },
-+ .set3 = {
-+ .mode = &pch_gpio_set3_mode,
-+ .direction = &pch_gpio_set3_direction,
-+ .level = &pch_gpio_set3_level,
-+ .reset = &pch_gpio_set3_reset,
-+ },
-+};
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e5520/hda_verb.c b/src/mainboard/dell/snb_ivb_latitude/variants/e5520/hda_verb.c
-new file mode 100644
-index 0000000000..1373975352
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e5520/hda_verb.c
-@@ -0,0 +1,32 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <device/azalia_device.h>
-+
-+const u32 cim_verb_data[] = {
-+ 0x111d76e7, /* Codec Vendor / Device ID: IDT */
-+ 0x1028049a, /* Subsystem ID */
-+ 11, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(0, 0x1028049a),
-+ AZALIA_PIN_CFG(0, 0x0a, 0x04a11020),
-+ AZALIA_PIN_CFG(0, 0x0b, 0x0421101f),
-+ AZALIA_PIN_CFG(0, 0x0c, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x0d, 0x90170110),
-+ AZALIA_PIN_CFG(0, 0x0e, 0x23011050),
-+ AZALIA_PIN_CFG(0, 0x0f, 0x23a1102e),
-+ AZALIA_PIN_CFG(0, 0x10, 0x400000f3),
-+ AZALIA_PIN_CFG(0, 0x11, 0xd5a301a0),
-+ AZALIA_PIN_CFG(0, 0x1f, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x20, 0x400000f0),
-+
-+ 0x80862805, /* Codec Vendor / Device ID: Intel */
-+ 0x80860101, /* Subsystem ID */
-+ 4, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(3, 0x80860101),
-+ AZALIA_PIN_CFG(3, 0x05, 0x18560010),
-+ AZALIA_PIN_CFG(3, 0x06, 0x18560020),
-+ AZALIA_PIN_CFG(3, 0x07, 0x18560030),
-+};
-+
-+const u32 pc_beep_verbs[0] = {};
-+
-+AZALIA_ARRAY_SIZES;
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e5520/overridetree.cb b/src/mainboard/dell/snb_ivb_latitude/variants/e5520/overridetree.cb
-new file mode 100644
-index 0000000000..479d1b696e
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e5520/overridetree.cb
-@@ -0,0 +1,39 @@
-+## SPDX-License-Identifier: GPL-2.0-or-later
-+
-+chip northbridge/intel/sandybridge
-+ device domain 0 on
-+ subsystemid 0x1028 0x049a inherit
-+
-+ device ref igd on
-+ register "gpu_cpu_backlight" = "0x00000218"
-+ register "gpu_pch_backlight" = "0x13121312"
-+ end
-+
-+ chip southbridge/intel/bd82x6x
-+ register "pcie_hotplug_map" = "{ 0, 0, 1, 0, 0, 0, 1, 0 }"
-+ register "usb_port_config" = "{
-+ { 1, 1, 0 },
-+ { 1, 1, 0 },
-+ { 1, 1, 1 },
-+ { 1, 1, 1 },
-+ { 1, 1, 2 },
-+ { 1, 1, 2 },
-+ { 1, 1, 3 },
-+ { 1, 1, 3 },
-+ { 1, 1, 5 },
-+ { 1, 1, 5 },
-+ { 1, 1, 7 },
-+ { 1, 1, 6 },
-+ { 1, 1, 6 },
-+ { 1, 1, 7 },
-+ }"
-+
-+ device ref gbe off end
-+ device ref pcie_rp4 off end
-+ device ref pcie_rp7 on end # Broadcom BCM5761 Gigabit Ethernet
-+ device ref sata1 on
-+ register "sata_port_map" = "0x3b"
-+ end
-+ end
-+ end
-+end
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0013-mb-dell-Add-Latitude-E5420-Sandy-Bridge.patch b/config/coreboot/default/patches/0013-mb-dell-Add-Latitude-E5420-Sandy-Bridge.patch
deleted file mode 100644
index 5944535f..00000000
--- a/config/coreboot/default/patches/0013-mb-dell-Add-Latitude-E5420-Sandy-Bridge.patch
+++ /dev/null
@@ -1,442 +0,0 @@
-From bbcd6a7f09ee99f3b26b0931f1dcd70970242ee8 Mon Sep 17 00:00:00 2001
-From: Nicholas Chin <nic.c3.14@gmail.com>
-Date: Mon, 4 Mar 2024 18:05:43 -0700
-Subject: [PATCH 13/51] mb/dell: Add Latitude E5420 (Sandy Bridge)
-
-Mainboard is Krug 14". I do not physically have this system; someone
-with physical access to one sent me the output of autoport which I then
-modified to produce this port. I was also sent the VBT binary, which was
-obtained from `/sys/kernel/debug/dri/0/i915_vbt` while running version
-A02 of the vendor firmware.
-
-This was originally tested and found to be working as a standalone board
-port in Libreboot, but this variant based port in upstream coreboot has
-not been tested.
-
-This can be internally flashed by sending a command to the EC, which
-causes the EC to pull the FDO pin low and the firmware to skip setting
-up any chipset based write protections [1]. The EC is the SMSC MEC5055,
-which seems to be compatible with the existing MEC5035 code.
-
-[1] https://gitlab.com/nic3-14159/dell-flash-unlock
-
-Change-Id: I0283653156083768e1fd451bcf539b4e028589f4
-Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>
----
- src/mainboard/dell/snb_ivb_latitude/Kconfig | 10 +-
- .../dell/snb_ivb_latitude/Kconfig.name | 3 +
- .../snb_ivb_latitude/variants/e5420/data.vbt | Bin 0 -> 6144 bytes
- .../variants/e5420/early_init.c | 14 ++
- .../snb_ivb_latitude/variants/e5420/gpio.c | 195 ++++++++++++++++++
- .../variants/e5420/hda_verb.c | 32 +++
- .../variants/e5420/overridetree.cb | 39 ++++
- 7 files changed, 292 insertions(+), 1 deletion(-)
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e5420/data.vbt
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e5420/early_init.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e5420/gpio.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e5420/hda_verb.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e5420/overridetree.cb
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-index 4e94a7ef80..e6a21ffb99 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-@@ -17,6 +17,11 @@ config BOARD_DELL_SNB_IVB_LATITUDE_COMMON
- select SYSTEM_TYPE_LAPTOP
- select USE_NATIVE_RAMINIT
-
-+config BOARD_DELL_LATITUDE_E5420
-+ select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
-+ select BOARD_ROMSIZE_KB_6144
-+ select SOUTHBRIDGE_INTEL_BD82X6X
-+
- config BOARD_DELL_LATITUDE_E5520
- select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
- select BOARD_ROMSIZE_KB_6144
-@@ -60,6 +65,7 @@ config MAINBOARD_DIR
- default "dell/snb_ivb_latitude"
-
- config MAINBOARD_PART_NUMBER
-+ default "Latitude E5420" if BOARD_DELL_LATITUDE_E5420
- default "Latitude E5520" if BOARD_DELL_LATITUDE_E5520
- default "Latitude E6420" if BOARD_DELL_LATITUDE_E6420
- default "Latitude E6520" if BOARD_DELL_LATITUDE_E6520
-@@ -74,6 +80,7 @@ config USBDEBUG_HCD_INDEX
- default 2
-
- config VARIANT_DIR
-+ default "e5420" if BOARD_DELL_LATITUDE_E5420
- default "e5520" if BOARD_DELL_LATITUDE_E5520
- default "e6420" if BOARD_DELL_LATITUDE_E6420
- default "e6520" if BOARD_DELL_LATITUDE_E6520
-@@ -82,7 +89,8 @@ config VARIANT_DIR
- default "e6530" if BOARD_DELL_LATITUDE_E6530
-
- config VGA_BIOS_ID
-- default "8086,0116" if BOARD_DELL_LATITUDE_E6520
-+ default "8086,0116" if BOARD_DELL_LATITUDE_E6520 \
-+ || BOARD_DELL_LATITUDE_E5420
- default "8086,0166" if BOARD_DELL_LATITUDE_E5530
- default "8086,0126" if BOARD_DELL_LATITUDE_E6420 \
- || BOARD_DELL_LATITUDE_E5520
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-index 7976691f21..a3fa2b1837 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-@@ -1,5 +1,8 @@
- ## SPDX-License-Identifier: GPL-2.0-only
-
-+config BOARD_DELL_LATITUDE_E5420
-+ bool "Latitude E5420"
-+
- config BOARD_DELL_LATITUDE_E5520
- bool "Latitude E5520"
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e5420/data.vbt b/src/mainboard/dell/snb_ivb_latitude/variants/e5420/data.vbt
-new file mode 100644
-index 0000000000000000000000000000000000000000..98b82fe6110fd295b5749041ec7f8c084ace5f57
-GIT binary patch
-literal 6144
-zcmeHKeQZ-z6hE);wSBvNZ!2$ObQ^;MgV6zl*Rhp}BXnCCMZU^_r7jRwT!kfLo8?3H
-zk9)u(7?cb(hChhTM57@QFfmbMB!G!dNsO6BW5OSp5EGF^jHnTTdhUBI+h`e+1ft1q
-z^SfW?+;h)4_uO+|XEfEV$91)<gOArWE)OnSTD}Ug6?8a~vz+SmQn!4~y3N7b^|hPp
-zR<5aEfv-b8M00Lk251!oO|8(YA6XaeXzkt-Z)@Ee!_{@z#Fro^?DqN4SGjRIu8KYp
-zZEufuU@5MM@7jv%h;75FS}ezKv?JDzCH}d%tE)A-GuDb*+B%}~w%88r>}c;!*XQ5O
-z)OU7u$J@4U+lk)#GSW%c%c)v`%R6?`w)LIyu6bD7-j0o&X9qUMcEsYlW3BU4rZRvt
-zqAUpjf*qXuLCCsU0YM2I5@gB1WKd)f1+Yt?%HWd0DZxYumP(K<LxTif8A39+!KMl}
-z31FHG)7?qk5g>e?=ER{f^&}W<0k@mxff(?6+Stw+s6y%k1mM$cLk#^FWWI*9bE1GY
-z&VY9?WC1u#23^3^UYw5?H0x2S2gN`x18Fko6_x(#MKyuCU_<D!mEp$qO_An}#@>DV
-zdkf*li41yW3p$*0Oo3+63kO6S91*KwP#l2i4jnc)JkUirL^$k}VbH0;CBh#BS=OLf
-zW-yE3BRon75gG{_2~QIC5cUzCC%i)FCmbidM>tIwAPf>N5Pl?FC0r*+Sq!oXj!keQ
-zVKcyK>TL+gc7oLco$28+FpeeXkEP}_Sea=mk#IWUR^m$!BogvszLPu83FJm0k6K<l
-z$#$~YiXtY*GpHp#@FvHJ1UnBD*H%d+{_j24XE4nmBa*?5mOWiold28s3}>*}<HaeO
-z+1|-8g2)FCfkDZIdb-Ub);z0#;XEbPfGe?A72!{DAUg|$m+Z~(i@h9j4gtm611ni(
-z#u>ACcP}M4exU`*MKVwl5+t6JBpTkmm}xWflKUe~7}`!#%z#gAo{NxUrpDAndYktu
-zI0}VLU`J7^xmF1AFiz5S^uzp*DPI$%$qq!(ikh0kP+(GKzF|@N?Y%_#Vp@M+xHr$F
-z=%+18z`-fT%z)9-TS$~Dh@2yeN7!UIt0h`fWxUu`JvA_ra*8P48l%7KR0&c1;0R75
-z4f0oz(xQ3MWqz5>qW5M4tZWExHs8<H(e1G@4km@5wEzOOP^x<l`YmA|eKs6j3wl8B
-z%C%;uygh%<#kGZ{fymL+OlV0!-*T!V5IB>X@p!@CBU=7e{5^Jl{s7by`po-AJqM2l
-znk(=^0bHkF0rUw7)^7j;$=_UIs8`6P6b-;vPDZ#U9L)W1_PAYRDP9k~;5$stt5ZiV
-zD0>;i-?OlYY2}P9WVnfGos4xee2r=EGWHR}ADH$VV>cO=xU?!4TjIi)OMBYI_PX#b
-zm-eBHed5BOT-x6*W>;{IqAga~G6lCQT93k>Q}CpsomJR*1%FjEkv?fuT%c-8RklXO
-zU8;6KWk*zeU)4TW+1D!mrE0EhHZfbBeN{4S7X@Pig%};A99QTdA~wZruL*8y?K!jP
-zG5R*k=);S}Zn<T;W!Mxt`(!+z7_r@3LVpf|FESauM&4}+wqzXfba-zG>A}on(uzNF
-zyu>BcjA})C@bg%<;+Eh2;Sz4heFFCbZ@C{FrXMIbYzu>?Bi-|vZ}JSFU%JA>7$7et
-z0Yo%CnOVZm#ZA}4kWZOn15};h5*#OM3b+6vHzgruMP>=5MNJK1y42{YgveP-!j%#(
-z0rGe@8t%!=66Ti%K4|Gx=o7gFp83wQ;+s3H7+r^SKlpp3KKcr!3@|n;NCH_=qL=3T
-zq3WH?en`b+W-HR-fnrhw*9aZ%M}lHX7@H?E>!6wv_&YQFEHdA$%Z1R--yub>=c@p?
-z6@7Fc$&>sAxwiz{BE$1kb$K9Co=ozlA973y^i(^BM|EZ$$^y`0KyHiMJ%O*XbfEX1
-ziZaH>W(1pWL0bo|T!x__N$^$DpmxI=bL6WUK3JGyn?rw-qC4ZA$yGjIB}N(=ldD2O
-zAJ@bxp<qR-3lIv<!P~SE8r*#_Ckl?$0|1fZ>2>n}u*mUIYFd>}O_wuwBD^r9<#=!0
-X1LGbT_rSOZ#yv3ZfpHH!G!Og(1Xg~J
-
-literal 0
-HcmV?d00001
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e5420/early_init.c b/src/mainboard/dell/snb_ivb_latitude/variants/e5420/early_init.c
-new file mode 100644
-index 0000000000..ff83db095b
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e5420/early_init.c
-@@ -0,0 +1,14 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <bootblock_common.h>
-+#include <device/pci_ops.h>
-+#include <ec/dell/mec5035/mec5035.h>
-+#include <southbridge/intel/bd82x6x/pch.h>
-+
-+void bootblock_mainboard_early_init(void)
-+{
-+ pci_write_config16(PCH_LPC_DEV, LPC_EN, CNF1_LPC_EN | MC_LPC_EN
-+ | KBC_LPC_EN | FDD_LPC_EN | LPT_LPC_EN
-+ | COMB_LPC_EN | COMA_LPC_EN);
-+ mec5035_early_init();
-+}
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e5420/gpio.c b/src/mainboard/dell/snb_ivb_latitude/variants/e5420/gpio.c
-new file mode 100644
-index 0000000000..f76b93d9f0
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e5420/gpio.c
-@@ -0,0 +1,195 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <southbridge/intel/common/gpio.h>
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_mode = {
-+ .gpio0 = GPIO_MODE_GPIO,
-+ .gpio1 = GPIO_MODE_NATIVE,
-+ .gpio2 = GPIO_MODE_GPIO,
-+ .gpio3 = GPIO_MODE_GPIO,
-+ .gpio4 = GPIO_MODE_GPIO,
-+ .gpio5 = GPIO_MODE_NATIVE,
-+ .gpio6 = GPIO_MODE_GPIO,
-+ .gpio7 = GPIO_MODE_GPIO,
-+ .gpio8 = GPIO_MODE_GPIO,
-+ .gpio9 = GPIO_MODE_NATIVE,
-+ .gpio10 = GPIO_MODE_NATIVE,
-+ .gpio11 = GPIO_MODE_NATIVE,
-+ .gpio12 = GPIO_MODE_GPIO,
-+ .gpio13 = GPIO_MODE_GPIO,
-+ .gpio14 = GPIO_MODE_GPIO,
-+ .gpio15 = GPIO_MODE_GPIO,
-+ .gpio16 = GPIO_MODE_NATIVE,
-+ .gpio17 = GPIO_MODE_GPIO,
-+ .gpio18 = GPIO_MODE_NATIVE,
-+ .gpio19 = GPIO_MODE_GPIO,
-+ .gpio20 = GPIO_MODE_NATIVE,
-+ .gpio21 = GPIO_MODE_GPIO,
-+ .gpio22 = GPIO_MODE_GPIO,
-+ .gpio23 = GPIO_MODE_NATIVE,
-+ .gpio24 = GPIO_MODE_GPIO,
-+ .gpio25 = GPIO_MODE_NATIVE,
-+ .gpio26 = GPIO_MODE_NATIVE,
-+ .gpio27 = GPIO_MODE_GPIO,
-+ .gpio28 = GPIO_MODE_GPIO,
-+ .gpio29 = GPIO_MODE_GPIO,
-+ .gpio30 = GPIO_MODE_GPIO,
-+ .gpio31 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_direction = {
-+ .gpio0 = GPIO_DIR_INPUT,
-+ .gpio2 = GPIO_DIR_INPUT,
-+ .gpio3 = GPIO_DIR_INPUT,
-+ .gpio4 = GPIO_DIR_INPUT,
-+ .gpio6 = GPIO_DIR_INPUT,
-+ .gpio7 = GPIO_DIR_INPUT,
-+ .gpio8 = GPIO_DIR_INPUT,
-+ .gpio12 = GPIO_DIR_OUTPUT,
-+ .gpio13 = GPIO_DIR_INPUT,
-+ .gpio14 = GPIO_DIR_INPUT,
-+ .gpio15 = GPIO_DIR_INPUT,
-+ .gpio17 = GPIO_DIR_INPUT,
-+ .gpio19 = GPIO_DIR_INPUT,
-+ .gpio21 = GPIO_DIR_INPUT,
-+ .gpio22 = GPIO_DIR_INPUT,
-+ .gpio24 = GPIO_DIR_INPUT,
-+ .gpio27 = GPIO_DIR_INPUT,
-+ .gpio28 = GPIO_DIR_INPUT,
-+ .gpio29 = GPIO_DIR_INPUT,
-+ .gpio30 = GPIO_DIR_OUTPUT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_level = {
-+ .gpio12 = GPIO_LEVEL_HIGH,
-+ .gpio30 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_reset = {
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_invert = {
-+ .gpio0 = GPIO_INVERT,
-+ .gpio8 = GPIO_INVERT,
-+ .gpio14 = GPIO_INVERT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_blink = {
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_mode = {
-+ .gpio32 = GPIO_MODE_NATIVE,
-+ .gpio33 = GPIO_MODE_GPIO,
-+ .gpio34 = GPIO_MODE_GPIO,
-+ .gpio35 = GPIO_MODE_GPIO,
-+ .gpio36 = GPIO_MODE_GPIO,
-+ .gpio37 = GPIO_MODE_GPIO,
-+ .gpio38 = GPIO_MODE_GPIO,
-+ .gpio39 = GPIO_MODE_GPIO,
-+ .gpio40 = GPIO_MODE_NATIVE,
-+ .gpio41 = GPIO_MODE_NATIVE,
-+ .gpio42 = GPIO_MODE_NATIVE,
-+ .gpio43 = GPIO_MODE_NATIVE,
-+ .gpio44 = GPIO_MODE_NATIVE,
-+ .gpio45 = GPIO_MODE_NATIVE,
-+ .gpio46 = GPIO_MODE_GPIO,
-+ .gpio47 = GPIO_MODE_NATIVE,
-+ .gpio48 = GPIO_MODE_GPIO,
-+ .gpio49 = GPIO_MODE_NATIVE,
-+ .gpio50 = GPIO_MODE_GPIO,
-+ .gpio51 = GPIO_MODE_GPIO,
-+ .gpio52 = GPIO_MODE_GPIO,
-+ .gpio53 = GPIO_MODE_GPIO,
-+ .gpio54 = GPIO_MODE_GPIO,
-+ .gpio55 = GPIO_MODE_GPIO,
-+ .gpio56 = GPIO_MODE_GPIO,
-+ .gpio57 = GPIO_MODE_GPIO,
-+ .gpio58 = GPIO_MODE_NATIVE,
-+ .gpio59 = GPIO_MODE_NATIVE,
-+ .gpio60 = GPIO_MODE_GPIO,
-+ .gpio61 = GPIO_MODE_NATIVE,
-+ .gpio62 = GPIO_MODE_NATIVE,
-+ .gpio63 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_direction = {
-+ .gpio33 = GPIO_DIR_INPUT,
-+ .gpio34 = GPIO_DIR_OUTPUT,
-+ .gpio35 = GPIO_DIR_INPUT,
-+ .gpio36 = GPIO_DIR_INPUT,
-+ .gpio37 = GPIO_DIR_OUTPUT,
-+ .gpio38 = GPIO_DIR_INPUT,
-+ .gpio39 = GPIO_DIR_INPUT,
-+ .gpio46 = GPIO_DIR_OUTPUT,
-+ .gpio48 = GPIO_DIR_INPUT,
-+ .gpio50 = GPIO_DIR_OUTPUT,
-+ .gpio51 = GPIO_DIR_OUTPUT,
-+ .gpio52 = GPIO_DIR_INPUT,
-+ .gpio53 = GPIO_DIR_INPUT,
-+ .gpio54 = GPIO_DIR_INPUT,
-+ .gpio55 = GPIO_DIR_OUTPUT,
-+ .gpio56 = GPIO_DIR_INPUT,
-+ .gpio57 = GPIO_DIR_INPUT,
-+ .gpio60 = GPIO_DIR_OUTPUT,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_level = {
-+ .gpio34 = GPIO_LEVEL_LOW,
-+ .gpio37 = GPIO_LEVEL_LOW,
-+ .gpio46 = GPIO_LEVEL_HIGH,
-+ .gpio50 = GPIO_LEVEL_HIGH,
-+ .gpio51 = GPIO_LEVEL_LOW,
-+ .gpio55 = GPIO_LEVEL_LOW,
-+ .gpio60 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_reset = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_mode = {
-+ .gpio64 = GPIO_MODE_NATIVE,
-+ .gpio65 = GPIO_MODE_NATIVE,
-+ .gpio66 = GPIO_MODE_NATIVE,
-+ .gpio67 = GPIO_MODE_NATIVE,
-+ .gpio68 = GPIO_MODE_NATIVE,
-+ .gpio69 = GPIO_MODE_NATIVE,
-+ .gpio70 = GPIO_MODE_NATIVE,
-+ .gpio71 = GPIO_MODE_NATIVE,
-+ .gpio72 = GPIO_MODE_NATIVE,
-+ .gpio73 = GPIO_MODE_NATIVE,
-+ .gpio74 = GPIO_MODE_GPIO,
-+ .gpio75 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_direction = {
-+ .gpio74 = GPIO_DIR_INPUT,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_level = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_reset = {
-+};
-+
-+const struct pch_gpio_map mainboard_gpio_map = {
-+ .set1 = {
-+ .mode = &pch_gpio_set1_mode,
-+ .direction = &pch_gpio_set1_direction,
-+ .level = &pch_gpio_set1_level,
-+ .blink = &pch_gpio_set1_blink,
-+ .invert = &pch_gpio_set1_invert,
-+ .reset = &pch_gpio_set1_reset,
-+ },
-+ .set2 = {
-+ .mode = &pch_gpio_set2_mode,
-+ .direction = &pch_gpio_set2_direction,
-+ .level = &pch_gpio_set2_level,
-+ .reset = &pch_gpio_set2_reset,
-+ },
-+ .set3 = {
-+ .mode = &pch_gpio_set3_mode,
-+ .direction = &pch_gpio_set3_direction,
-+ .level = &pch_gpio_set3_level,
-+ .reset = &pch_gpio_set3_reset,
-+ },
-+};
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e5420/hda_verb.c b/src/mainboard/dell/snb_ivb_latitude/variants/e5420/hda_verb.c
-new file mode 100644
-index 0000000000..0bc6c35a63
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e5420/hda_verb.c
-@@ -0,0 +1,32 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <device/azalia_device.h>
-+
-+const u32 cim_verb_data[] = {
-+ 0x111d76e7, /* Codec Vendor / Device ID: IDT */
-+ 0x1028049b, /* Subsystem ID */
-+ 11, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(0, 0x1028049b),
-+ AZALIA_PIN_CFG(0, 0x0a, 0x04a11020),
-+ AZALIA_PIN_CFG(0, 0x0b, 0x0421101f),
-+ AZALIA_PIN_CFG(0, 0x0c, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x0d, 0x90170110),
-+ AZALIA_PIN_CFG(0, 0x0e, 0x23011050),
-+ AZALIA_PIN_CFG(0, 0x0f, 0x23a1102e),
-+ AZALIA_PIN_CFG(0, 0x10, 0x400000f3),
-+ AZALIA_PIN_CFG(0, 0x11, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x1f, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x20, 0xd5a30130),
-+
-+ 0x80862805, /* Codec Vendor / Device ID: Intel */
-+ 0x80860101, /* Subsystem ID */
-+ 4, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(3, 0x80860101),
-+ AZALIA_PIN_CFG(3, 0x05, 0x18560010),
-+ AZALIA_PIN_CFG(3, 0x06, 0x18560020),
-+ AZALIA_PIN_CFG(3, 0x07, 0x18560030),
-+};
-+
-+const u32 pc_beep_verbs[0] = {};
-+
-+AZALIA_ARRAY_SIZES;
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e5420/overridetree.cb b/src/mainboard/dell/snb_ivb_latitude/variants/e5420/overridetree.cb
-new file mode 100644
-index 0000000000..3f55bfd49d
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e5420/overridetree.cb
-@@ -0,0 +1,39 @@
-+## SPDX-License-Identifier: GPL-2.0-or-later
-+
-+chip northbridge/intel/sandybridge
-+ device domain 0 on
-+ subsystemid 0x1028 0x049b inherit
-+
-+ device ref igd on
-+ register "gpu_cpu_backlight" = "0x00000c31"
-+ register "gpu_pch_backlight" = "0x13121312"
-+ end
-+
-+ chip southbridge/intel/bd82x6x
-+ register "pcie_hotplug_map" = "{ 0, 0, 1, 0, 0, 0, 1, 0 }"
-+ register "usb_port_config" = "{
-+ { 1, 1, 0 },
-+ { 1, 1, 0 },
-+ { 1, 1, 1 },
-+ { 1, 1, 1 },
-+ { 1, 1, 2 },
-+ { 1, 1, 2 },
-+ { 1, 1, 3 },
-+ { 1, 1, 3 },
-+ { 1, 1, 5 },
-+ { 1, 1, 5 },
-+ { 1, 1, 7 },
-+ { 1, 1, 6 },
-+ { 1, 1, 6 },
-+ { 1, 1, 7 },
-+ }"
-+
-+ device ref gbe off end
-+ device ref pcie_rp4 off end
-+ device ref pcie_rp7 on end # Broadcom BCM5761 Gigabit Ethernet
-+ device ref sata1 on
-+ register "sata_port_map" = "0x3b"
-+ end
-+ end
-+ end
-+end
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0023-nb-haswell-Fully-disable-iGPU-when-dGPU-is-used.patch b/config/coreboot/default/patches/0013-nb-haswell-Fully-disable-iGPU-when-dGPU-is-used.patch
index f9d80b9f..89584d95 100644
--- a/config/coreboot/default/patches/0023-nb-haswell-Fully-disable-iGPU-when-dGPU-is-used.patch
+++ b/config/coreboot/default/patches/0013-nb-haswell-Fully-disable-iGPU-when-dGPU-is-used.patch
@@ -1,7 +1,7 @@
-From d86824305f11bc684f1e91e3826158b8c7d7e0ee Mon Sep 17 00:00:00 2001
+From c8329f84b2d06581dcbeecedc38b7c4715a9cba7 Mon Sep 17 00:00:00 2001
From: Leah Rowe <info@minifree.org>
Date: Sat, 6 Apr 2024 01:22:47 +0100
-Subject: [PATCH 23/51] nb/haswell: Fully disable iGPU when dGPU is used
+Subject: [PATCH 13/37] nb/haswell: Fully disable iGPU when dGPU is used
My earlier patch disabled decode *and* disabled the iGPU itself, but
a subsequent revision disabled only VGA decode. Upon revisiting, I
diff --git a/config/coreboot/default/patches/0025-ec-dell-mec5035-Add-S3-suspend-SMI-handler.patch b/config/coreboot/default/patches/0014-ec-dell-mec5035-Add-S3-suspend-SMI-handler.patch
index ed620a3e..70556090 100644
--- a/config/coreboot/default/patches/0025-ec-dell-mec5035-Add-S3-suspend-SMI-handler.patch
+++ b/config/coreboot/default/patches/0014-ec-dell-mec5035-Add-S3-suspend-SMI-handler.patch
@@ -1,7 +1,7 @@
-From 2fdd5bbb2bbec76c3c2238c4cd471b9b63073942 Mon Sep 17 00:00:00 2001
+From 73dbf291631fdbae2d8e8a761c147523c8d9e65c Mon Sep 17 00:00:00 2001
From: Nicholas Chin <nic.c3.14@gmail.com>
Date: Fri, 3 May 2024 11:03:32 -0600
-Subject: [PATCH 25/51] ec/dell/mec5035: Add S3 suspend SMI handler
+Subject: [PATCH 14/37] ec/dell/mec5035: Add S3 suspend SMI handler
This is necessary for S3 resume to work on SNB and newer Dell Latitude
laptops. If a command isn't sent, the EC cuts power to the DIMMs,
diff --git a/config/coreboot/default/patches/0014-mb-dell-Add-Latitude-E6320-Sandy-Bridge.patch b/config/coreboot/default/patches/0014-mb-dell-Add-Latitude-E6320-Sandy-Bridge.patch
deleted file mode 100644
index e8c46203..00000000
--- a/config/coreboot/default/patches/0014-mb-dell-Add-Latitude-E6320-Sandy-Bridge.patch
+++ /dev/null
@@ -1,435 +0,0 @@
-From cd6e699649459fa5ff2623018ccf3585eb3d3821 Mon Sep 17 00:00:00 2001
-From: Nicholas Chin <nic.c3.14@gmail.com>
-Date: Wed, 7 Feb 2024 15:23:46 -0700
-Subject: [PATCH 14/51] mb/dell: Add Latitude E6320 (Sandy Bridge)
-
-Mainboard is PAL70/LA-6611P. I do not physically have this system;
-someone with physical access to one sent me the output of autoport which
-I then modified to produce this port. I was also sent the VBT binary,
-which was obtained from `/sys/kernel/debug/dri/0/i915_vbt` while running
-version A22 of the vendor firmware. This port has not been tested.
-
-The EC is the SMSC MEC5055, which seems to be compatible with the
-existing MEC5035 code. As with the other Dell systems with this EC, this
-board is assumed to be internally flashable using an EC command that
-tells it to pull the FDO pin low on the next boot, which also tells the
-vendor firmware to disable all write protections to the flash [1].
-
-[1] https://gitlab.com/nic3-14159/dell-flash-unlock
-
-Change-Id: I5905f8c6a8dbad56e03bdeedc2179600d0c4ba46
-Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>
----
- src/mainboard/dell/snb_ivb_latitude/Kconfig | 11 +-
- .../dell/snb_ivb_latitude/Kconfig.name | 3 +
- .../snb_ivb_latitude/variants/e6320/data.vbt | Bin 0 -> 6144 bytes
- .../variants/e6320/early_init.c | 17 ++
- .../snb_ivb_latitude/variants/e6320/gpio.c | 190 ++++++++++++++++++
- .../variants/e6320/hda_verb.c | 32 +++
- .../variants/e6320/overridetree.cb | 35 ++++
- 7 files changed, 287 insertions(+), 1 deletion(-)
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6320/data.vbt
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6320/early_init.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6320/gpio.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6320/hda_verb.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6320/overridetree.cb
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-index e6a21ffb99..84ffe1d33a 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-@@ -27,6 +27,12 @@ config BOARD_DELL_LATITUDE_E5520
- select BOARD_ROMSIZE_KB_6144
- select SOUTHBRIDGE_INTEL_BD82X6X
-
-+config BOARD_DELL_LATITUDE_E6320
-+ select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
-+ select BOARD_ROMSIZE_KB_10240
-+ select MAINBOARD_USES_IFD_GBE_REGION
-+ select SOUTHBRIDGE_INTEL_BD82X6X
-+
- config BOARD_DELL_LATITUDE_E6420
- select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
- select BOARD_ROMSIZE_KB_10240
-@@ -67,6 +73,7 @@ config MAINBOARD_DIR
- config MAINBOARD_PART_NUMBER
- default "Latitude E5420" if BOARD_DELL_LATITUDE_E5420
- default "Latitude E5520" if BOARD_DELL_LATITUDE_E5520
-+ default "Latitude E6320" if BOARD_DELL_LATITUDE_E6320
- default "Latitude E6420" if BOARD_DELL_LATITUDE_E6420
- default "Latitude E6520" if BOARD_DELL_LATITUDE_E6520
- default "Latitude E5530" if BOARD_DELL_LATITUDE_E5530
-@@ -82,6 +89,7 @@ config USBDEBUG_HCD_INDEX
- config VARIANT_DIR
- default "e5420" if BOARD_DELL_LATITUDE_E5420
- default "e5520" if BOARD_DELL_LATITUDE_E5520
-+ default "e6320" if BOARD_DELL_LATITUDE_E6320
- default "e6420" if BOARD_DELL_LATITUDE_E6420
- default "e6520" if BOARD_DELL_LATITUDE_E6520
- default "e5530" if BOARD_DELL_LATITUDE_E5530
-@@ -93,7 +101,8 @@ config VGA_BIOS_ID
- || BOARD_DELL_LATITUDE_E5420
- default "8086,0166" if BOARD_DELL_LATITUDE_E5530
- default "8086,0126" if BOARD_DELL_LATITUDE_E6420 \
-- || BOARD_DELL_LATITUDE_E5520
-+ || BOARD_DELL_LATITUDE_E5520 \
-+ || BOARD_DELL_LATITUDE_E6320
- default "8086,0166" if BOARD_DELL_LATITUDE_E6430 \
- || BOARD_DELL_LATITUDE_E6530
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-index a3fa2b1837..ef6a1329a9 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-@@ -6,6 +6,9 @@ config BOARD_DELL_LATITUDE_E5420
- config BOARD_DELL_LATITUDE_E5520
- bool "Latitude E5520"
-
-+config BOARD_DELL_LATITUDE_E6320
-+ bool "Latitude E6320"
-+
- config BOARD_DELL_LATITUDE_E6420
- bool "Latitude E6420"
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6320/data.vbt b/src/mainboard/dell/snb_ivb_latitude/variants/e6320/data.vbt
-new file mode 100644
-index 0000000000000000000000000000000000000000..471a9e29da639dd496f3ecebd5d0754a9045c00b
-GIT binary patch
-literal 6144
-zcmeHKeP|p-6#wn*-rZ(yH@R-odPzTgZEU>S#_pv}j2iKhT+^%8_DtJw21|4GP8*0x
-zyw;EYW49Xozz<Rt@ek1mic(N32r8oZ0U9lcR8a)~s33wLV8yCftLK~DJJWb)8w-j;
-z=J?H<nfK<+n>TOX?48xuwV5_`Zb)3w)w?dSc1`nTL|NF_SMw&<<)v%g#!cH2otrzi
-zb*<mneJMSLdC1iK_7#v-6w7R}+t1&W8P4wBo*&F!lcNn?)F-EqWZV#oQEb%`x-4^5
-zW@sogOik1`n9Wc#r82|0A!=-0LD!FFGrMwG+CDg($q(js(#Y`8?s79ubEJD@ba#I6
-znjO0++P#czvh8NBR?)iQUA%txNPhHO>Kq!PUMaJadUHE-`5SWCb4_6i;5Aj(6hQGK
-zcq^2uUt5sS5YSMiL+CJcs0#cVOdTN|K@D>?tkF=dqenwjM^Z-^K2z~&z+xRs!o^Jx
-zkUGd?>QtXw8V(I09OiMb0DZy>`=tO^#BCssw{}bkOnj=#Ic!~!6!J*{`jbEv5O4)-
-zg-UBlIa$c9Pg4C;0_-wq3t+dbZfn1wBi@zhNnWx()w{Vb-G8OC_m*478gTrX3U*a1
-zHr@y<Lcbct?Wzy^)OH+FC$S`8V@n`{QN~@2dxJU-1ucBe_>rOO78dFPXES1q3mHj9
-zFXKwa)r^}Mw=nKzJjj?}>}NdBc$G29IK=pr@de`u;}}D$5~yYbw&Hlf=OF0X?I=Y$
-z$D`mgy>}U$hl}G6m&PmXveHnY5DenC!g~=E3i?HIrEpyk>_(-IsVtEqUEoqxrDFdq
-zrYwhOv0o^NgW$OKN}=$7Z-w5*Vuv?T3~uuFGwP92?Qr8n0iQp=u*7rep9Q8dW#?ZI
-zFly1ww^^l*+YC6t16l_{g}tVVpVZ0fDk%5+`|+*688vr-<Lw_SRc^+avHI{BCpdYb
-z70yLEI0-45%t;z||GKzov+|VFW6hab&NAG9FD+h6sBu$cX`r0eJ%T`kvK4+(wT`0=
-z$fxKG+om?Ge1-EhbNc*Xjy1opKZSaiv-EL~GvOa&&bx~z##3W;F2{b=<HQ4!<1CFk
-z17i)$X+`=C=0udOPOx3$IjzopqwQzLr*jT4C)(jmj2>uYP8$M=#caX6OWA1Ez395U
-z%x<yAs)6-Ascr5<x*>CIZibyRlE~I0-ianVaz~q|EMlL7hc1U5w?}Kekws6fyy@`e
-z4NdX%L#2`A#c_N4ftGmuwbDo=incwf=WnBJk6)fYz%6Cmy>HwK$Y|iP`Y7sgjDPhQ
-zR|wv367k}1g)-G@kXq(X;{Bjt998b9{cpD9zGhOQ5%$4OSMtc2(<dx@0O}7_G+$WF
-zLYyaPtFT6d*e&Q$VLd0r%Yr@=*7rjEDyT7JwT8sSA<BiU8$)7mh@K2tFNMULA^I|8
-z{Sp#>gO(fCMTS^w(6xrO#}IcK^sHgMZis^heP>uIf6|z=%Cy#)Vxvjdo7U~7*k{rU
-zruB{~J}~KL(+X9Kxz*-5M>NNGSaIfXi19({d4mrk?K50@R0%Wn*PP9d(MMIzI2~RX
-z)(4h&8(YL@UyKJ*)4o${n5ZGd(hDf+)cv8sSBxWen|f*u<-sgt(u+U-bkd}Tj+5@9
-zJosfSdvPo8zGnluemJg=E7A{=N<Rc#KYYEg?^p`+_?~aU(kEmFus{DshA~iA(onLY
-zvIfpBJt;KWP4n8&`n1##c($WnDo|=?rlHBz&}36&HPWwp8op_i8c-**(TSd{Y{SZ?
-z_=^K$27e+q;^vRNU3~a=cd;V{%O=iuo*&xwXyg19${Ap0yO@a|N-<e^7iIClF{vUn
-z&4$y_V7MA)=E=%7n63u!J9FY$RK8hXHDE%%Lx$ZgX902-<9r|4lkx>QwFch>PUO1w
-z=6JffnB-kQ)VLb>sSZdDrI@U2!?HLA9Mlek!*k>;&jx<)xfnBiY^I6DRt*l*`n8ly
-zu!h)b?sRV1==Nf*Cw9&&i7n^9Nts>wk>adaY&E5OdW*A?iI}v+E6GGlsR<+#%jpl^
-zGz<Q^vpj>qhDjj3zr60Bgh=l{NzJp$x#fCR%*8!ZR?fC&JuvHmSr5#5VAcb(9+>sO
-IzvhA80TAzedH?_b
-
-literal 0
-HcmV?d00001
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6320/early_init.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6320/early_init.c
-new file mode 100644
-index 0000000000..b0c4638858
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6320/early_init.c
-@@ -0,0 +1,17 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <bootblock_common.h>
-+#include <device/pci_ops.h>
-+#include <ec/dell/mec5035/mec5035.h>
-+#include <southbridge/intel/bd82x6x/pch.h>
-+
-+const struct southbridge_usb_port mainboard_usb_ports[] = {
-+};
-+
-+void bootblock_mainboard_early_init(void)
-+{
-+ pci_write_config16(PCH_LPC_DEV, LPC_EN, CNF1_LPC_EN | MC_LPC_EN
-+ | KBC_LPC_EN | FDD_LPC_EN | LPT_LPC_EN
-+ | COMB_LPC_EN | COMA_LPC_EN);
-+ mec5035_early_init();
-+}
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6320/gpio.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6320/gpio.c
-new file mode 100644
-index 0000000000..61f01816c4
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6320/gpio.c
-@@ -0,0 +1,190 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <southbridge/intel/common/gpio.h>
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_mode = {
-+ .gpio0 = GPIO_MODE_GPIO,
-+ .gpio1 = GPIO_MODE_NATIVE,
-+ .gpio2 = GPIO_MODE_GPIO,
-+ .gpio3 = GPIO_MODE_NATIVE,
-+ .gpio4 = GPIO_MODE_GPIO,
-+ .gpio5 = GPIO_MODE_NATIVE,
-+ .gpio6 = GPIO_MODE_GPIO,
-+ .gpio7 = GPIO_MODE_GPIO,
-+ .gpio8 = GPIO_MODE_GPIO,
-+ .gpio9 = GPIO_MODE_NATIVE,
-+ .gpio10 = GPIO_MODE_NATIVE,
-+ .gpio11 = GPIO_MODE_NATIVE,
-+ .gpio12 = GPIO_MODE_NATIVE,
-+ .gpio13 = GPIO_MODE_GPIO,
-+ .gpio14 = GPIO_MODE_GPIO,
-+ .gpio15 = GPIO_MODE_GPIO,
-+ .gpio16 = GPIO_MODE_GPIO,
-+ .gpio17 = GPIO_MODE_GPIO,
-+ .gpio18 = GPIO_MODE_NATIVE,
-+ .gpio19 = GPIO_MODE_GPIO,
-+ .gpio20 = GPIO_MODE_NATIVE,
-+ .gpio21 = GPIO_MODE_GPIO,
-+ .gpio22 = GPIO_MODE_GPIO,
-+ .gpio23 = GPIO_MODE_NATIVE,
-+ .gpio24 = GPIO_MODE_GPIO,
-+ .gpio25 = GPIO_MODE_NATIVE,
-+ .gpio26 = GPIO_MODE_NATIVE,
-+ .gpio27 = GPIO_MODE_GPIO,
-+ .gpio28 = GPIO_MODE_GPIO,
-+ .gpio29 = GPIO_MODE_GPIO,
-+ .gpio30 = GPIO_MODE_GPIO,
-+ .gpio31 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_direction = {
-+ .gpio0 = GPIO_DIR_INPUT,
-+ .gpio2 = GPIO_DIR_INPUT,
-+ .gpio4 = GPIO_DIR_INPUT,
-+ .gpio6 = GPIO_DIR_INPUT,
-+ .gpio7 = GPIO_DIR_INPUT,
-+ .gpio8 = GPIO_DIR_INPUT,
-+ .gpio13 = GPIO_DIR_INPUT,
-+ .gpio14 = GPIO_DIR_INPUT,
-+ .gpio15 = GPIO_DIR_INPUT,
-+ .gpio16 = GPIO_DIR_INPUT,
-+ .gpio17 = GPIO_DIR_INPUT,
-+ .gpio19 = GPIO_DIR_INPUT,
-+ .gpio21 = GPIO_DIR_INPUT,
-+ .gpio22 = GPIO_DIR_INPUT,
-+ .gpio24 = GPIO_DIR_INPUT,
-+ .gpio27 = GPIO_DIR_INPUT,
-+ .gpio28 = GPIO_DIR_INPUT,
-+ .gpio29 = GPIO_DIR_INPUT,
-+ .gpio30 = GPIO_DIR_OUTPUT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_level = {
-+ .gpio30 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_reset = {
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_invert = {
-+ .gpio0 = GPIO_INVERT,
-+ .gpio8 = GPIO_INVERT,
-+ .gpio14 = GPIO_INVERT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_blink = {
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_mode = {
-+ .gpio32 = GPIO_MODE_NATIVE,
-+ .gpio33 = GPIO_MODE_GPIO,
-+ .gpio34 = GPIO_MODE_GPIO,
-+ .gpio35 = GPIO_MODE_GPIO,
-+ .gpio36 = GPIO_MODE_GPIO,
-+ .gpio37 = GPIO_MODE_GPIO,
-+ .gpio38 = GPIO_MODE_GPIO,
-+ .gpio39 = GPIO_MODE_GPIO,
-+ .gpio40 = GPIO_MODE_NATIVE,
-+ .gpio41 = GPIO_MODE_NATIVE,
-+ .gpio42 = GPIO_MODE_NATIVE,
-+ .gpio43 = GPIO_MODE_NATIVE,
-+ .gpio44 = GPIO_MODE_NATIVE,
-+ .gpio45 = GPIO_MODE_GPIO,
-+ .gpio46 = GPIO_MODE_NATIVE,
-+ .gpio47 = GPIO_MODE_NATIVE,
-+ .gpio48 = GPIO_MODE_GPIO,
-+ .gpio49 = GPIO_MODE_GPIO,
-+ .gpio50 = GPIO_MODE_NATIVE,
-+ .gpio51 = GPIO_MODE_GPIO,
-+ .gpio52 = GPIO_MODE_GPIO,
-+ .gpio53 = GPIO_MODE_NATIVE,
-+ .gpio54 = GPIO_MODE_GPIO,
-+ .gpio55 = GPIO_MODE_NATIVE,
-+ .gpio56 = GPIO_MODE_NATIVE,
-+ .gpio57 = GPIO_MODE_GPIO,
-+ .gpio58 = GPIO_MODE_NATIVE,
-+ .gpio59 = GPIO_MODE_NATIVE,
-+ .gpio60 = GPIO_MODE_GPIO,
-+ .gpio61 = GPIO_MODE_NATIVE,
-+ .gpio62 = GPIO_MODE_NATIVE,
-+ .gpio63 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_direction = {
-+ .gpio33 = GPIO_DIR_INPUT,
-+ .gpio34 = GPIO_DIR_OUTPUT,
-+ .gpio35 = GPIO_DIR_INPUT,
-+ .gpio36 = GPIO_DIR_INPUT,
-+ .gpio37 = GPIO_DIR_INPUT,
-+ .gpio38 = GPIO_DIR_INPUT,
-+ .gpio39 = GPIO_DIR_INPUT,
-+ .gpio45 = GPIO_DIR_OUTPUT,
-+ .gpio48 = GPIO_DIR_INPUT,
-+ .gpio49 = GPIO_DIR_OUTPUT,
-+ .gpio51 = GPIO_DIR_INPUT,
-+ .gpio52 = GPIO_DIR_INPUT,
-+ .gpio54 = GPIO_DIR_INPUT,
-+ .gpio57 = GPIO_DIR_INPUT,
-+ .gpio60 = GPIO_DIR_OUTPUT,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_level = {
-+ .gpio34 = GPIO_LEVEL_HIGH,
-+ .gpio45 = GPIO_LEVEL_LOW,
-+ .gpio49 = GPIO_LEVEL_LOW,
-+ .gpio60 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_reset = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_mode = {
-+ .gpio64 = GPIO_MODE_NATIVE,
-+ .gpio65 = GPIO_MODE_NATIVE,
-+ .gpio66 = GPIO_MODE_NATIVE,
-+ .gpio67 = GPIO_MODE_NATIVE,
-+ .gpio68 = GPIO_MODE_GPIO,
-+ .gpio69 = GPIO_MODE_GPIO,
-+ .gpio70 = GPIO_MODE_GPIO,
-+ .gpio71 = GPIO_MODE_GPIO,
-+ .gpio72 = GPIO_MODE_NATIVE,
-+ .gpio73 = GPIO_MODE_NATIVE,
-+ .gpio74 = GPIO_MODE_NATIVE,
-+ .gpio75 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_direction = {
-+ .gpio68 = GPIO_DIR_INPUT,
-+ .gpio69 = GPIO_DIR_INPUT,
-+ .gpio70 = GPIO_DIR_INPUT,
-+ .gpio71 = GPIO_DIR_INPUT,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_level = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_reset = {
-+};
-+
-+const struct pch_gpio_map mainboard_gpio_map = {
-+ .set1 = {
-+ .mode = &pch_gpio_set1_mode,
-+ .direction = &pch_gpio_set1_direction,
-+ .level = &pch_gpio_set1_level,
-+ .blink = &pch_gpio_set1_blink,
-+ .invert = &pch_gpio_set1_invert,
-+ .reset = &pch_gpio_set1_reset,
-+ },
-+ .set2 = {
-+ .mode = &pch_gpio_set2_mode,
-+ .direction = &pch_gpio_set2_direction,
-+ .level = &pch_gpio_set2_level,
-+ .reset = &pch_gpio_set2_reset,
-+ },
-+ .set3 = {
-+ .mode = &pch_gpio_set3_mode,
-+ .direction = &pch_gpio_set3_direction,
-+ .level = &pch_gpio_set3_level,
-+ .reset = &pch_gpio_set3_reset,
-+ },
-+};
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6320/hda_verb.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6320/hda_verb.c
-new file mode 100644
-index 0000000000..2e3f7fa697
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6320/hda_verb.c
-@@ -0,0 +1,32 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <device/azalia_device.h>
-+
-+const u32 cim_verb_data[] = {
-+ 0x111d76e7, /* Codec Vendor / Device ID: IDT */
-+ 0x10280492, /* Subsystem ID */
-+ 11, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(0, 0x10280492),
-+ AZALIA_PIN_CFG(0, 0x0a, 0x03a11020),
-+ AZALIA_PIN_CFG(0, 0x0b, 0x0321101f),
-+ AZALIA_PIN_CFG(0, 0x0c, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x0d, 0x90170110),
-+ AZALIA_PIN_CFG(0, 0x0e, 0x23011050),
-+ AZALIA_PIN_CFG(0, 0x0f, 0x23a1102e),
-+ AZALIA_PIN_CFG(0, 0x10, 0x400000f3),
-+ AZALIA_PIN_CFG(0, 0x11, 0xd5a30130),
-+ AZALIA_PIN_CFG(0, 0x1f, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x20, 0x400000f0),
-+
-+ 0x80862805, /* Codec Vendor / Device ID: Intel */
-+ 0x80860101, /* Subsystem ID */
-+ 4, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(3, 0x80860101),
-+ AZALIA_PIN_CFG(3, 0x05, 0x18560010),
-+ AZALIA_PIN_CFG(3, 0x06, 0x18560020),
-+ AZALIA_PIN_CFG(3, 0x07, 0x18560030),
-+};
-+
-+const u32 pc_beep_verbs[0] = {};
-+
-+AZALIA_ARRAY_SIZES;
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6320/overridetree.cb b/src/mainboard/dell/snb_ivb_latitude/variants/e6320/overridetree.cb
-new file mode 100644
-index 0000000000..3bfe6b57ed
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6320/overridetree.cb
-@@ -0,0 +1,35 @@
-+## SPDX-License-Identifier: GPL-2.0-or-later
-+
-+chip northbridge/intel/sandybridge
-+ device domain 0 on
-+ subsystemid 0x1028 0x0492 inherit
-+
-+ device ref igd on
-+ register "gpu_cpu_backlight" = "0x00000622"
-+ register "gpu_pch_backlight" = "0x13121312"
-+ end
-+
-+ chip southbridge/intel/bd82x6x
-+ register "usb_port_config" = "{
-+ { 1, 1, 0 },
-+ { 1, 0, 0 },
-+ { 1, 1, 1 },
-+ { 1, 0, 1 },
-+ { 1, 1, 2 },
-+ { 1, 1, 2 },
-+ { 1, 1, 3 },
-+ { 1, 1, 3 },
-+ { 1, 0, 5 },
-+ { 1, 0, 5 },
-+ { 1, 1, 7 },
-+ { 1, 1, 6 },
-+ { 1, 0, 6 },
-+ { 1, 0, 7 },
-+ }"
-+
-+ device ref sata1 on
-+ register "sata_port_map" = "0x3b"
-+ end
-+ end
-+ end
-+end
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0015-mb-dell-Add-Latitude-E6220-Sandy-Bridge.patch b/config/coreboot/default/patches/0015-mb-dell-Add-Latitude-E6220-Sandy-Bridge.patch
deleted file mode 100644
index e2be42c9..00000000
--- a/config/coreboot/default/patches/0015-mb-dell-Add-Latitude-E6220-Sandy-Bridge.patch
+++ /dev/null
@@ -1,438 +0,0 @@
-From a32431d5f7574ffa6391221c7740f1739203eaa7 Mon Sep 17 00:00:00 2001
-From: Nicholas Chin <nic.c3.14@gmail.com>
-Date: Fri, 8 Mar 2024 09:27:36 -0700
-Subject: [PATCH 15/51] mb/dell: Add Latitude E6220 (Sandy Bridge)
-
-Mainboard is codenamed Vida. I do not physically have this system;
-someone with physical access to one sent me the output of autoport which
-I then modified to produce this port. The VBT was obtained using
-intelvbttool while running version A14 (latest available version) of the
-vendor firmware.
-
-Tested and found to boot as part of a libreboot build based on upstream
-coreboot commit b7341da191 with additional patches, though these do not
-appear to affect SNB/IVB. The base E6430 patch was tested against
-coreboot main.
-
-The EC is the SMSC MEC5055, which seems to be compatible with the
-existing MEC5035 code. As with the other Dell systems with this EC, this
-board is assumed to be internally flashable using an EC command that
-tells it to pull the FDO pin low on the next boot, which also tells the
-vendor firmware to disable all write protections to the flash [1].
-
-[1] https://gitlab.com/nic3-14159/dell-flash-unlock
-
-Change-Id: I570023b0837521b75aac6d5652c74030c06b8a4c
-Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>
----
- src/mainboard/dell/snb_ivb_latitude/Kconfig | 9 +
- .../dell/snb_ivb_latitude/Kconfig.name | 3 +
- .../snb_ivb_latitude/variants/e6220/data.vbt | Bin 0 -> 3985 bytes
- .../variants/e6220/early_init.c | 14 ++
- .../snb_ivb_latitude/variants/e6220/gpio.c | 192 ++++++++++++++++++
- .../variants/e6220/hda_verb.c | 32 +++
- .../variants/e6220/overridetree.cb | 37 ++++
- 7 files changed, 287 insertions(+)
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6220/data.vbt
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6220/early_init.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6220/gpio.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6220/hda_verb.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6220/overridetree.cb
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-index 84ffe1d33a..baa83baa41 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-@@ -27,6 +27,12 @@ config BOARD_DELL_LATITUDE_E5520
- select BOARD_ROMSIZE_KB_6144
- select SOUTHBRIDGE_INTEL_BD82X6X
-
-+config BOARD_DELL_LATITUDE_E6220
-+ select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
-+ select BOARD_ROMSIZE_KB_10240
-+ select MAINBOARD_USES_IFD_GBE_REGION
-+ select SOUTHBRIDGE_INTEL_BD82X6X
-+
- config BOARD_DELL_LATITUDE_E6320
- select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
- select BOARD_ROMSIZE_KB_10240
-@@ -73,6 +79,7 @@ config MAINBOARD_DIR
- config MAINBOARD_PART_NUMBER
- default "Latitude E5420" if BOARD_DELL_LATITUDE_E5420
- default "Latitude E5520" if BOARD_DELL_LATITUDE_E5520
-+ default "Latitude E6220" if BOARD_DELL_LATITUDE_E6220
- default "Latitude E6320" if BOARD_DELL_LATITUDE_E6320
- default "Latitude E6420" if BOARD_DELL_LATITUDE_E6420
- default "Latitude E6520" if BOARD_DELL_LATITUDE_E6520
-@@ -89,6 +96,7 @@ config USBDEBUG_HCD_INDEX
- config VARIANT_DIR
- default "e5420" if BOARD_DELL_LATITUDE_E5420
- default "e5520" if BOARD_DELL_LATITUDE_E5520
-+ default "e6220" if BOARD_DELL_LATITUDE_E6220
- default "e6320" if BOARD_DELL_LATITUDE_E6320
- default "e6420" if BOARD_DELL_LATITUDE_E6420
- default "e6520" if BOARD_DELL_LATITUDE_E6520
-@@ -102,6 +110,7 @@ config VGA_BIOS_ID
- default "8086,0166" if BOARD_DELL_LATITUDE_E5530
- default "8086,0126" if BOARD_DELL_LATITUDE_E6420 \
- || BOARD_DELL_LATITUDE_E5520 \
-+ || BOARD_DELL_LATITUDE_E6220 \
- || BOARD_DELL_LATITUDE_E6320
- default "8086,0166" if BOARD_DELL_LATITUDE_E6430 \
- || BOARD_DELL_LATITUDE_E6530
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-index ef6a1329a9..349ee7f79e 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-@@ -6,6 +6,9 @@ config BOARD_DELL_LATITUDE_E5420
- config BOARD_DELL_LATITUDE_E5520
- bool "Latitude E5520"
-
-+config BOARD_DELL_LATITUDE_E6220
-+ bool "Latitude E6220"
-+
- config BOARD_DELL_LATITUDE_E6320
- bool "Latitude E6320"
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6220/data.vbt b/src/mainboard/dell/snb_ivb_latitude/variants/e6220/data.vbt
-new file mode 100644
-index 0000000000000000000000000000000000000000..548075a74500b5d159108089ee29cff802d07db7
-GIT binary patch
-literal 3985
-zcmdT{eP|p-6#wn*-rZ(yH@R-odPzTgZQ6LXjonL|7&YQ0xu#d`$C=h}21|4GP8*0x
-zyjE@hv0Dv(P?c0g{G(_DMJZ@22r8oZ0U9lcR8a)~s33wOSg|T<^?b8?XBzL?#)6`A
-z{N~Nfd-LYan>TOv7WZ{+rcIq264!S1u1&02-MpSC3mf}u-r~BvbgkXEX=|c$bLZBs
-zbsM{{q9-s1nVR3f2C|A`nJsqvC7UwC+1=angV`H%w4sao<P?&OTVpYbtz1OwGuLN^
-zhBCv{M16zV3^h|KGn^Zu#@6L@%V;*UGnb`pgTtBpU~UJE3=i!tH{%>fx<^KL=Lc`x
-zzLTQeOW7vdZsuwwtsUOU>vxajM=zqzp&{y(GCQa@w<DLoHJ81}6s7=PS9MJR6hDG@
-zLaF+#1qlrS4OKdX4nv2kz^}p75z-OVFk8cF4b?h&G(>eIb%fzF6`uwy)UhaB+ynus
-zBRr-~^|__t=m5fD9tR81r@XLV3UEc-2I6>o`;@@MXS$rj)&)r+pA?|K2vh+9SHM=N
-zw3d{Uh1~iK)juV`E`v4?cFU@^_DehBU5TFLmFrTyoBPuJ*ExIdxO1!lC!eceSG8i}
-z&A<Zmt5Mvo`mkSZ$5C|>ivl*T2}Cf;*vEJvsN-nR!WWDm8M<y^zAkV9BgVLlk!18T
-zu4CN5*u}VmaUbIm#suRa;|0cRj7i2(#%GK#8OIsFFtjRxYDQoSP8NI)g09_;Qlzsy
-z3O>^Zmcltu96wMRudvHXLxn;xh~EqEM^Gr}m&=vHbwRKjl{%)fM2d8tOI4MM{l!dK
-z4$)%2P!LDJaqX2t;s4$Wy@Q1gZ=x97<n3qFBc<Bm#;F26e|~<6=hD9lOk>K<zaU`L
-zqML8CN*#9@aDs=m4ulGOO%*?>lhsvF9`g6&TYocZ_JQN=A1hUE#+kAD@E9jJd7%}~
-zMLIYMDVoel8h1}$+_YJF%DJ&-O)X~`ZoroouO-yDsj)OrPU{{+ph4LJKdD;Bi3a3T
-zbe?Tf8&<r^`I<R>elW+H+t;5$y~|nhq{o@?k1^-Hg%jhcu{xJyzvgk`0m*Te#GQe$
-z2IjOP{U&oF$`&WsuJN2!=fTnT^W)PwhnW-Ya3)3%H!`OUfy6?#V9r%+wCY}TU0!Cl
-z*kjeex}MZl_aWVoxhXfp&Ur~>>k;onlO4II%~KY!FT|r)!;agdwcf~rXIAVwc6CEj
-zJpE{CBzZ;L-gdYp9)G<w5{aU1kLvl`XxrnL=MQj88F%j+w*oR6c&t8(di=t_dW<Us
-z?>C8f@wZ%=YBfkLb0_gZP%us?_tgG3TXJ7BDbWb~V23Mt{QT(?mOc#ihbo#YtY#rD
-z7PLiJBSP#J^tiB|7vdE`p9|}IA$}9o7_wSJ;))RELe^~|u{T6dhpd-F;;j&U6|#N}
-z3BN(h4C``3tTE^&!`fqrdks2dSZ^5Oh(X^Omdc+rCapBB)uz~J(k-TSw<-3U^rC6K
-zYl;s|`q{KX)nazFdEs%*@f}l~SsY?~kb2(WgGl=fm!43<O#L+%@MH9Gl`~Gq=7;rx
-zMc&31@YxsRfz-6`>>4I&2(k1$iaK?FYVZ}~h~1{1T|;>=%b4`yk3XF>siEVHyC@HS
-z8OvVW%DeB`K&~H7>f?&^gQU_A0oM<l8+N5oZ4)iV>;p0b*k61j!x*S5X(-unS`9rZ
-zG}=vb+R*x})DSq-Q7;uJwKLPuG`Ej6G}#nch4dSqhHo0B2Gq%HbgCyS+pwZ3{?fph
-z!Jo*Dxcw7v7a#rIU2IRmVn4KE$x~88+a7J4zd|_!%xo9z$+P;Q6qA*AQ5FvzlPW^f
-zY&aJUhO1#_o~&$x>1qJKGpC+K<(u_&1197<WZ2zu79e*q&i9c$DPNGYYw%s_L~d?x
-zj;EW8N#6BCjjMs5>VVWxipk10ERAEpLG3^|JWI~<Y~c5vi!sB;W|~-R<=`-_TSLhN
-zYlyAlPUkfn-CnHq)Xv2vv1R->DYG*_Qk)fwt)g^KZ*f*K5tEj9C7Ea`HGyPe8U4wd
-nX2Iz@%Q6UTm;}-X%j^D0i1fiT)I6)4TdrsMY}`L(<y7krryzQ}
-
-literal 0
-HcmV?d00001
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6220/early_init.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6220/early_init.c
-new file mode 100644
-index 0000000000..ff83db095b
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6220/early_init.c
-@@ -0,0 +1,14 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <bootblock_common.h>
-+#include <device/pci_ops.h>
-+#include <ec/dell/mec5035/mec5035.h>
-+#include <southbridge/intel/bd82x6x/pch.h>
-+
-+void bootblock_mainboard_early_init(void)
-+{
-+ pci_write_config16(PCH_LPC_DEV, LPC_EN, CNF1_LPC_EN | MC_LPC_EN
-+ | KBC_LPC_EN | FDD_LPC_EN | LPT_LPC_EN
-+ | COMB_LPC_EN | COMA_LPC_EN);
-+ mec5035_early_init();
-+}
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6220/gpio.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6220/gpio.c
-new file mode 100644
-index 0000000000..2306e4cf0a
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6220/gpio.c
-@@ -0,0 +1,192 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <southbridge/intel/common/gpio.h>
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_mode = {
-+ .gpio0 = GPIO_MODE_GPIO,
-+ .gpio1 = GPIO_MODE_GPIO,
-+ .gpio2 = GPIO_MODE_GPIO,
-+ .gpio3 = GPIO_MODE_NATIVE,
-+ .gpio4 = GPIO_MODE_GPIO,
-+ .gpio5 = GPIO_MODE_NATIVE,
-+ .gpio6 = GPIO_MODE_GPIO,
-+ .gpio7 = GPIO_MODE_GPIO,
-+ .gpio8 = GPIO_MODE_GPIO,
-+ .gpio9 = GPIO_MODE_NATIVE,
-+ .gpio10 = GPIO_MODE_NATIVE,
-+ .gpio11 = GPIO_MODE_NATIVE,
-+ .gpio12 = GPIO_MODE_NATIVE,
-+ .gpio13 = GPIO_MODE_GPIO,
-+ .gpio14 = GPIO_MODE_GPIO,
-+ .gpio15 = GPIO_MODE_GPIO,
-+ .gpio16 = GPIO_MODE_GPIO,
-+ .gpio17 = GPIO_MODE_GPIO,
-+ .gpio18 = GPIO_MODE_NATIVE,
-+ .gpio19 = GPIO_MODE_GPIO,
-+ .gpio20 = GPIO_MODE_NATIVE,
-+ .gpio21 = GPIO_MODE_GPIO,
-+ .gpio22 = GPIO_MODE_GPIO,
-+ .gpio23 = GPIO_MODE_NATIVE,
-+ .gpio24 = GPIO_MODE_GPIO,
-+ .gpio25 = GPIO_MODE_NATIVE,
-+ .gpio26 = GPIO_MODE_NATIVE,
-+ .gpio27 = GPIO_MODE_GPIO,
-+ .gpio28 = GPIO_MODE_GPIO,
-+ .gpio29 = GPIO_MODE_GPIO,
-+ .gpio30 = GPIO_MODE_GPIO,
-+ .gpio31 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_direction = {
-+ .gpio0 = GPIO_DIR_INPUT,
-+ .gpio1 = GPIO_DIR_INPUT,
-+ .gpio2 = GPIO_DIR_INPUT,
-+ .gpio4 = GPIO_DIR_INPUT,
-+ .gpio6 = GPIO_DIR_INPUT,
-+ .gpio7 = GPIO_DIR_INPUT,
-+ .gpio8 = GPIO_DIR_INPUT,
-+ .gpio13 = GPIO_DIR_INPUT,
-+ .gpio14 = GPIO_DIR_INPUT,
-+ .gpio15 = GPIO_DIR_INPUT,
-+ .gpio16 = GPIO_DIR_INPUT,
-+ .gpio17 = GPIO_DIR_INPUT,
-+ .gpio19 = GPIO_DIR_INPUT,
-+ .gpio21 = GPIO_DIR_INPUT,
-+ .gpio22 = GPIO_DIR_INPUT,
-+ .gpio24 = GPIO_DIR_INPUT,
-+ .gpio27 = GPIO_DIR_INPUT,
-+ .gpio28 = GPIO_DIR_INPUT,
-+ .gpio29 = GPIO_DIR_INPUT,
-+ .gpio30 = GPIO_DIR_OUTPUT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_level = {
-+ .gpio30 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_reset = {
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_invert = {
-+ .gpio0 = GPIO_INVERT,
-+ .gpio1 = GPIO_INVERT,
-+ .gpio8 = GPIO_INVERT,
-+ .gpio14 = GPIO_INVERT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_blink = {
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_mode = {
-+ .gpio32 = GPIO_MODE_NATIVE,
-+ .gpio33 = GPIO_MODE_GPIO,
-+ .gpio34 = GPIO_MODE_GPIO,
-+ .gpio35 = GPIO_MODE_GPIO,
-+ .gpio36 = GPIO_MODE_GPIO,
-+ .gpio37 = GPIO_MODE_GPIO,
-+ .gpio38 = GPIO_MODE_GPIO,
-+ .gpio39 = GPIO_MODE_GPIO,
-+ .gpio40 = GPIO_MODE_NATIVE,
-+ .gpio41 = GPIO_MODE_NATIVE,
-+ .gpio42 = GPIO_MODE_NATIVE,
-+ .gpio43 = GPIO_MODE_NATIVE,
-+ .gpio44 = GPIO_MODE_NATIVE,
-+ .gpio45 = GPIO_MODE_GPIO,
-+ .gpio46 = GPIO_MODE_NATIVE,
-+ .gpio47 = GPIO_MODE_NATIVE,
-+ .gpio48 = GPIO_MODE_GPIO,
-+ .gpio49 = GPIO_MODE_GPIO,
-+ .gpio50 = GPIO_MODE_NATIVE,
-+ .gpio51 = GPIO_MODE_GPIO,
-+ .gpio52 = GPIO_MODE_GPIO,
-+ .gpio53 = GPIO_MODE_NATIVE,
-+ .gpio54 = GPIO_MODE_GPIO,
-+ .gpio55 = GPIO_MODE_NATIVE,
-+ .gpio56 = GPIO_MODE_NATIVE,
-+ .gpio57 = GPIO_MODE_GPIO,
-+ .gpio58 = GPIO_MODE_NATIVE,
-+ .gpio59 = GPIO_MODE_NATIVE,
-+ .gpio60 = GPIO_MODE_GPIO,
-+ .gpio61 = GPIO_MODE_NATIVE,
-+ .gpio62 = GPIO_MODE_NATIVE,
-+ .gpio63 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_direction = {
-+ .gpio33 = GPIO_DIR_INPUT,
-+ .gpio34 = GPIO_DIR_OUTPUT,
-+ .gpio35 = GPIO_DIR_INPUT,
-+ .gpio36 = GPIO_DIR_INPUT,
-+ .gpio37 = GPIO_DIR_INPUT,
-+ .gpio38 = GPIO_DIR_INPUT,
-+ .gpio39 = GPIO_DIR_INPUT,
-+ .gpio45 = GPIO_DIR_OUTPUT,
-+ .gpio48 = GPIO_DIR_INPUT,
-+ .gpio49 = GPIO_DIR_OUTPUT,
-+ .gpio51 = GPIO_DIR_INPUT,
-+ .gpio52 = GPIO_DIR_INPUT,
-+ .gpio54 = GPIO_DIR_INPUT,
-+ .gpio57 = GPIO_DIR_INPUT,
-+ .gpio60 = GPIO_DIR_OUTPUT,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_level = {
-+ .gpio34 = GPIO_LEVEL_HIGH,
-+ .gpio45 = GPIO_LEVEL_LOW,
-+ .gpio49 = GPIO_LEVEL_LOW,
-+ .gpio60 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_reset = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_mode = {
-+ .gpio64 = GPIO_MODE_NATIVE,
-+ .gpio65 = GPIO_MODE_NATIVE,
-+ .gpio66 = GPIO_MODE_NATIVE,
-+ .gpio67 = GPIO_MODE_NATIVE,
-+ .gpio68 = GPIO_MODE_GPIO,
-+ .gpio69 = GPIO_MODE_GPIO,
-+ .gpio70 = GPIO_MODE_GPIO,
-+ .gpio71 = GPIO_MODE_GPIO,
-+ .gpio72 = GPIO_MODE_NATIVE,
-+ .gpio73 = GPIO_MODE_NATIVE,
-+ .gpio74 = GPIO_MODE_NATIVE,
-+ .gpio75 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_direction = {
-+ .gpio68 = GPIO_DIR_INPUT,
-+ .gpio69 = GPIO_DIR_INPUT,
-+ .gpio70 = GPIO_DIR_INPUT,
-+ .gpio71 = GPIO_DIR_INPUT,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_level = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_reset = {
-+};
-+
-+const struct pch_gpio_map mainboard_gpio_map = {
-+ .set1 = {
-+ .mode = &pch_gpio_set1_mode,
-+ .direction = &pch_gpio_set1_direction,
-+ .level = &pch_gpio_set1_level,
-+ .blink = &pch_gpio_set1_blink,
-+ .invert = &pch_gpio_set1_invert,
-+ .reset = &pch_gpio_set1_reset,
-+ },
-+ .set2 = {
-+ .mode = &pch_gpio_set2_mode,
-+ .direction = &pch_gpio_set2_direction,
-+ .level = &pch_gpio_set2_level,
-+ .reset = &pch_gpio_set2_reset,
-+ },
-+ .set3 = {
-+ .mode = &pch_gpio_set3_mode,
-+ .direction = &pch_gpio_set3_direction,
-+ .level = &pch_gpio_set3_level,
-+ .reset = &pch_gpio_set3_reset,
-+ },
-+};
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6220/hda_verb.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6220/hda_verb.c
-new file mode 100644
-index 0000000000..0c69f0bd0e
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6220/hda_verb.c
-@@ -0,0 +1,32 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <device/azalia_device.h>
-+
-+const u32 cim_verb_data[] = {
-+ 0x111d76e7, /* Codec Vendor / Device ID: IDT */
-+ 0x102804a9, /* Subsystem ID */
-+ 11, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(0, 0x102804a9),
-+ AZALIA_PIN_CFG(0, 0x0a, 0x03a11020),
-+ AZALIA_PIN_CFG(0, 0x0b, 0x0321101f),
-+ AZALIA_PIN_CFG(0, 0x0c, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x0d, 0x90170110),
-+ AZALIA_PIN_CFG(0, 0x0e, 0x23011050),
-+ AZALIA_PIN_CFG(0, 0x0f, 0x23a1102e),
-+ AZALIA_PIN_CFG(0, 0x10, 0x400000f3),
-+ AZALIA_PIN_CFG(0, 0x11, 0xd5a30130),
-+ AZALIA_PIN_CFG(0, 0x1f, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x20, 0x400000f0),
-+
-+ 0x80862805, /* Codec Vendor / Device ID: Intel */
-+ 0x80860101, /* Subsystem ID */
-+ 4, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(3, 0x80860101),
-+ AZALIA_PIN_CFG(3, 0x05, 0x18560010),
-+ AZALIA_PIN_CFG(3, 0x06, 0x18560020),
-+ AZALIA_PIN_CFG(3, 0x07, 0x18560030),
-+};
-+
-+const u32 pc_beep_verbs[0] = {};
-+
-+AZALIA_ARRAY_SIZES;
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6220/overridetree.cb b/src/mainboard/dell/snb_ivb_latitude/variants/e6220/overridetree.cb
-new file mode 100644
-index 0000000000..9faf27e27b
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6220/overridetree.cb
-@@ -0,0 +1,37 @@
-+## SPDX-License-Identifier: GPL-2.0-or-later
-+
-+chip northbridge/intel/sandybridge
-+ device domain 0 on
-+ subsystemid 0x1028 0x04a9 inherit
-+
-+ device ref igd on
-+ register "gpu_cpu_backlight" = "0x0000046a"
-+ register "gpu_pch_backlight" = "0x13121312"
-+ end
-+
-+ chip southbridge/intel/bd82x6x
-+ register "pcie_hotplug_map" = "{ 0, 0, 1, 0, 0, 0, 0, 0 }"
-+ register "usb_port_config" = "{
-+ { 1, 1, 0 },
-+ { 1, 0, 0 },
-+ { 1, 1, 1 },
-+ { 1, 0, 1 },
-+ { 1, 1, 2 },
-+ { 1, 1, 2 },
-+ { 1, 1, 3 },
-+ { 1, 1, 3 },
-+ { 1, 0, 5 },
-+ { 1, 0, 5 },
-+ { 1, 1, 7 },
-+ { 1, 1, 6 },
-+ { 1, 0, 6 },
-+ { 1, 0, 7 },
-+ }"
-+
-+ device ref pcie_rp4 off end
-+ device ref sata1 on
-+ register "sata_port_map" = "0x3b"
-+ end
-+ end
-+ end
-+end
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0026-nb-haswell-lock-policy-regs-when-disabling-IOMMU.patch b/config/coreboot/default/patches/0015-nb-haswell-lock-policy-regs-when-disabling-IOMMU.patch
index fe9034b0..9525b8ce 100644
--- a/config/coreboot/default/patches/0026-nb-haswell-lock-policy-regs-when-disabling-IOMMU.patch
+++ b/config/coreboot/default/patches/0015-nb-haswell-lock-policy-regs-when-disabling-IOMMU.patch
@@ -1,7 +1,7 @@
-From ce7d65790b9b8656ebbaa0ca715adff6a9c25588 Mon Sep 17 00:00:00 2001
+From a507fe609a2e99c95218ec430916eaf4c3cb61d9 Mon Sep 17 00:00:00 2001
From: Leah Rowe <info@minifree.org>
Date: Sat, 4 May 2024 02:00:53 +0100
-Subject: [PATCH 26/51] nb/haswell: lock policy regs when disabling IOMMU
+Subject: [PATCH 15/37] nb/haswell: lock policy regs when disabling IOMMU
Angel Pons told me I should do it. See comments here:
https://review.coreboot.org/c/coreboot/+/81016
diff --git a/config/coreboot/default/patches/0016-mb-dell-Add-Latitude-E6330-Ivy-Bridge.patch b/config/coreboot/default/patches/0016-mb-dell-Add-Latitude-E6330-Ivy-Bridge.patch
deleted file mode 100644
index 7d2133ef..00000000
--- a/config/coreboot/default/patches/0016-mb-dell-Add-Latitude-E6330-Ivy-Bridge.patch
+++ /dev/null
@@ -1,436 +0,0 @@
-From 0889cc6b6f62cba616feff5ae8558be31f298069 Mon Sep 17 00:00:00 2001
-From: Nicholas Chin <nic.c3.14@gmail.com>
-Date: Fri, 8 Mar 2024 09:33:03 -0700
-Subject: [PATCH 16/51] mb/dell: Add Latitude E6330 (Ivy Bridge)
-
-Mainboard is QAL70/LA-7741P. I do not physically have this system;
-someone with physical access to one sent me the output of autoport which
-I then modified to produce this port. I was also sent the VBT binary,
-which was obtained from `/sys/kernel/debug/dri/0/i915_vbt` while running
-version A21 of the vendor firmware. This port has not been tested.
-
-The EC is the SMSC MEC5055, which seems to be compatible with the
-existing MEC5035 code. As with the other Dell systems with this EC, this
-board is assumed to be internally flashable using an EC command that
-tells it to pull the FDO pin low on the next boot, which also tells the
-vendor firmware to disable all write protections to the flash [1].
-
-[1] https://gitlab.com/nic3-14159/dell-flash-unlock
-
-Change-Id: I827826e9ff8a9a534c50250458b399104478e06c
-Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>
----
- src/mainboard/dell/snb_ivb_latitude/Kconfig | 11 +-
- .../dell/snb_ivb_latitude/Kconfig.name | 3 +
- .../snb_ivb_latitude/variants/e6330/data.vbt | Bin 0 -> 6144 bytes
- .../variants/e6330/early_init.c | 14 ++
- .../snb_ivb_latitude/variants/e6330/gpio.c | 192 ++++++++++++++++++
- .../variants/e6330/hda_verb.c | 32 +++
- .../variants/e6330/overridetree.cb | 37 ++++
- 7 files changed, 288 insertions(+), 1 deletion(-)
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6330/data.vbt
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6330/early_init.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6330/gpio.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6330/hda_verb.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6330/overridetree.cb
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-index baa83baa41..49bf225fe2 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-@@ -56,6 +56,12 @@ config BOARD_DELL_LATITUDE_E5530
- select BOARD_ROMSIZE_KB_12288
- select SOUTHBRIDGE_INTEL_C216
-
-+config BOARD_DELL_LATITUDE_E6330
-+ select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
-+ select BOARD_ROMSIZE_KB_12288
-+ select MAINBOARD_USES_IFD_GBE_REGION
-+ select SOUTHBRIDGE_INTEL_C216
-+
- config BOARD_DELL_LATITUDE_E6430
- select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
- select BOARD_ROMSIZE_KB_12288
-@@ -84,6 +90,7 @@ config MAINBOARD_PART_NUMBER
- default "Latitude E6420" if BOARD_DELL_LATITUDE_E6420
- default "Latitude E6520" if BOARD_DELL_LATITUDE_E6520
- default "Latitude E5530" if BOARD_DELL_LATITUDE_E5530
-+ default "Latitude E6330" if BOARD_DELL_LATITUDE_E6330
- default "Latitude E6430" if BOARD_DELL_LATITUDE_E6430
- default "Latitude E6530" if BOARD_DELL_LATITUDE_E6530
-
-@@ -101,13 +108,15 @@ config VARIANT_DIR
- default "e6420" if BOARD_DELL_LATITUDE_E6420
- default "e6520" if BOARD_DELL_LATITUDE_E6520
- default "e5530" if BOARD_DELL_LATITUDE_E5530
-+ default "e6330" if BOARD_DELL_LATITUDE_E6330
- default "e6430" if BOARD_DELL_LATITUDE_E6430
- default "e6530" if BOARD_DELL_LATITUDE_E6530
-
- config VGA_BIOS_ID
- default "8086,0116" if BOARD_DELL_LATITUDE_E6520 \
- || BOARD_DELL_LATITUDE_E5420
-- default "8086,0166" if BOARD_DELL_LATITUDE_E5530
-+ default "8086,0166" if BOARD_DELL_LATITUDE_E5530 \
-+ || BOARD_DELL_LATITUDE_E6330
- default "8086,0126" if BOARD_DELL_LATITUDE_E6420 \
- || BOARD_DELL_LATITUDE_E5520 \
- || BOARD_DELL_LATITUDE_E6220 \
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-index 349ee7f79e..d6fc8eb224 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-@@ -21,6 +21,9 @@ config BOARD_DELL_LATITUDE_E6520
- config BOARD_DELL_LATITUDE_E5530
- bool "Latitude E5530"
-
-+config BOARD_DELL_LATITUDE_E6330
-+ bool "Latitude E6330"
-+
- config BOARD_DELL_LATITUDE_E6430
- bool "Latitude E6430"
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6330/data.vbt b/src/mainboard/dell/snb_ivb_latitude/variants/e6330/data.vbt
-new file mode 100644
-index 0000000000000000000000000000000000000000..18856746656058651c571ecbb3708e0543b19d62
-GIT binary patch
-literal 6144
-zcmeHKU2GiH75-*tc6WAmW_LYygMSkDB*E^Q*zv5f7dLg)@$NQV2a{}!yImnfyvQ4D
-z;n-$v0!RpNi<_o@ktI-@2a590stC0zRi%iRR%stvi&hAs3R<K}X~hFddB_6@s8W`5
-zXJ!q~E{TOme<a`8@BW;7?l<?GIp@yo&H2<M-FZ0GKbBAR-Ekx}HvVOrhK1*2?{QsU
-zQe#K%JeC=q96gpAKa#$keu^D99ee*0FfB=@F_0J<9-Ch-&BZ5r1T6`{$;1%Fm+qfk
-zTr5pfAz@KB*NGlFzEGx2aqh%IxkQOuX*`{wy~+KQo+-}XSE7aaxko77OBtFgoh;4K
-z(#-7f<x+WxmKSK)vQFgtt^L+?s+Z<V57E7|^TqOPX{mn0n<VLl#Yf7s_suL*Jl#VB
-zmSyz~ScwEVTc-3vd2v6D&dt$;&{?91(o(5>vNXNl&<qW@AghW5NPYw#ha~-b0Dc7_
-z6}t(eHgpwn6<HNi1Vcp^p-07-iXve~MTs!0A_ku!`4nKciajxJYXsOYuuT4N%smA!
-zPazgl&bNRSrvAz|_6r3+B;r1=!7D;RUUw8Ke+vNt7E3`(BA-woPvJFBK^3Gzfh4Nk
-zOX!J0PJNB)Mk&Z_i?S2ez+iItz=)m79LydX&rM9`3wPaJ`T92=Uv0;g-!<4*M6z%+
-z*omwb#VI+CU&%iFS{_DGS;sE}7G4juqRMCww!+k6=+abJj4v>Dsr*z_6HAP5GJeST
-znX2JD;{xLa#;c6KGychVn-L6YXkv6Qx)}Y8&ok1DI~ZSM6dCt39%QUAzRh@o@gqjy
-zL0qZ&DhN8ZR3xu$a$Cd{oasU3DNp{CCl6f~PYlq!Hte;Ia0^wn8Vut7>Wl1)s`^E-
-z1DhGx<x<9D%6jd%)5>zr8&7h}dMJ3~YBe;)!vVf-T&?{PoMvvRR{!67;Xhz^g^loX
-zja+*c-KJJoxbsm3pTE4THs`cgD{Pt+ga3en-i$P#9Wsra(oqRMr;H$4{gxr)9eF(x
-zg0v@a7aj}rA^Kf#sNb*>at^>P)5li%ycOq*4e;3~RUj$i1e8=rHi&<Y^Hc>Y_gP4=
-zxz9^%q0dLXqC&Bq<&sDScZwvatjRxB=rcJJiYb?w#4Iy2KTk1F6T>T}E@(DNGa>5R
-z7&Yv)JdHrRI};pfsKLVj=FE=U*=*T4#ncVktknoGelT||SDY`+9WI_IZE<i@7SnC8
-zN6~Gyo=&><wpzE~>`_>@wb<-RI-lu(_~Oy_Zo6={Cdq!uw(fmyz_u^cB&~5IS7g`U
-zdUC}N$J5-C)|`CfUO+?xptr@*hJW$ZhBZk%JaMh_<8!ZGj)z*WU9fcg2`>dT##_?q
-z=Ksx}uxo3jTHTq%E1}97UECE@r}nt3I=3R(HOL7jNg>teSM-g$aU#`3jk}#qh;D?6
-zw=CYuA2#mS+vU%0P&u8RCn4)$8VH-2uy#01%VG0WSX&Fz`LMYj)?N<NyJ1t)wHBQY
-z=;pYt<#l>gH_zzWS)G2Pn=k3wYdU|DnWmxbG$>`5lZJMWL92%O14BD!(C-cNFNXFH
-zgVc!G9?@=&(4mNVcSJiLq3=b^rz6@k5qdFVUW{m$A{2|7d!kxz)VSrcQt@4sDoq^f
-z98hXm=YS~qbf<kwigD|YevaR}^`7Jy^x~4_g75ka=c0r}VJF2aEv{=ilPf-mNQBNI
-zEMK3YKB+`*xOu>iR|LbzHLa*mLXlH${^b4c9%>9%)HO-?LA1gT0mlz!M}8&;(;^x|
-z*H2<VyY>2;juB|7F+k?y(_2~3@STqQ@f^sqD2c8g3x>ciM%siMq~;pKwfE57kw2K@
-z!-ZN0QTVOP@aA5@fEGKjy2+D`t?2KzpPyRQ`JcmHJoc(<#h<UT;@W$t_d{|;S>vyF
-zewtgef*II~y;k>*B!+(8*blXsY-~kcJa9zG2yfcMCt+|-0ex$pY`h1<*#rEv=~*<+
-ztV``Um!q33-Aap9fUshX^N~GS2@X3^U9+MwgYQ74^?~6&yU^#oY#cvC9R_}P2d<wN
-zJvOE)Xr7A2n#3x14}2_g(YN^0+oYDbb#|V{ze3pzGb9FiF#6Ra&L}bT(ZOvswS7RY
-zxLjWFRwWXHR5&={t;%K+Vkd6NX2iF<SF)LXv@y472OmG!_W%Ni*ZDuev-S0%b!dfW
-wz4{IL!+uT9t2XI4@_L@?Ri*bc_<n8A+wHaowmq=zfo%_LdtloGpN<DU00~N<ApigX
-
-literal 0
-HcmV?d00001
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6330/early_init.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6330/early_init.c
-new file mode 100644
-index 0000000000..ff83db095b
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6330/early_init.c
-@@ -0,0 +1,14 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <bootblock_common.h>
-+#include <device/pci_ops.h>
-+#include <ec/dell/mec5035/mec5035.h>
-+#include <southbridge/intel/bd82x6x/pch.h>
-+
-+void bootblock_mainboard_early_init(void)
-+{
-+ pci_write_config16(PCH_LPC_DEV, LPC_EN, CNF1_LPC_EN | MC_LPC_EN
-+ | KBC_LPC_EN | FDD_LPC_EN | LPT_LPC_EN
-+ | COMB_LPC_EN | COMA_LPC_EN);
-+ mec5035_early_init();
-+}
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6330/gpio.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6330/gpio.c
-new file mode 100644
-index 0000000000..777570765a
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6330/gpio.c
-@@ -0,0 +1,192 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <southbridge/intel/common/gpio.h>
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_mode = {
-+ .gpio0 = GPIO_MODE_GPIO,
-+ .gpio1 = GPIO_MODE_GPIO,
-+ .gpio2 = GPIO_MODE_GPIO,
-+ .gpio3 = GPIO_MODE_GPIO,
-+ .gpio4 = GPIO_MODE_GPIO,
-+ .gpio5 = GPIO_MODE_NATIVE,
-+ .gpio6 = GPIO_MODE_GPIO,
-+ .gpio7 = GPIO_MODE_GPIO,
-+ .gpio8 = GPIO_MODE_GPIO,
-+ .gpio9 = GPIO_MODE_NATIVE,
-+ .gpio10 = GPIO_MODE_NATIVE,
-+ .gpio11 = GPIO_MODE_NATIVE,
-+ .gpio12 = GPIO_MODE_NATIVE,
-+ .gpio13 = GPIO_MODE_GPIO,
-+ .gpio14 = GPIO_MODE_GPIO,
-+ .gpio15 = GPIO_MODE_GPIO,
-+ .gpio16 = GPIO_MODE_GPIO,
-+ .gpio17 = GPIO_MODE_GPIO,
-+ .gpio18 = GPIO_MODE_NATIVE,
-+ .gpio19 = GPIO_MODE_GPIO,
-+ .gpio20 = GPIO_MODE_NATIVE,
-+ .gpio21 = GPIO_MODE_GPIO,
-+ .gpio22 = GPIO_MODE_GPIO,
-+ .gpio23 = GPIO_MODE_NATIVE,
-+ .gpio24 = GPIO_MODE_GPIO,
-+ .gpio25 = GPIO_MODE_NATIVE,
-+ .gpio26 = GPIO_MODE_NATIVE,
-+ .gpio27 = GPIO_MODE_GPIO,
-+ .gpio28 = GPIO_MODE_GPIO,
-+ .gpio29 = GPIO_MODE_GPIO,
-+ .gpio30 = GPIO_MODE_NATIVE,
-+ .gpio31 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_direction = {
-+ .gpio0 = GPIO_DIR_INPUT,
-+ .gpio1 = GPIO_DIR_INPUT,
-+ .gpio2 = GPIO_DIR_INPUT,
-+ .gpio3 = GPIO_DIR_INPUT,
-+ .gpio4 = GPIO_DIR_INPUT,
-+ .gpio6 = GPIO_DIR_INPUT,
-+ .gpio7 = GPIO_DIR_INPUT,
-+ .gpio8 = GPIO_DIR_INPUT,
-+ .gpio13 = GPIO_DIR_INPUT,
-+ .gpio14 = GPIO_DIR_INPUT,
-+ .gpio15 = GPIO_DIR_INPUT,
-+ .gpio16 = GPIO_DIR_INPUT,
-+ .gpio17 = GPIO_DIR_INPUT,
-+ .gpio19 = GPIO_DIR_INPUT,
-+ .gpio21 = GPIO_DIR_INPUT,
-+ .gpio22 = GPIO_DIR_INPUT,
-+ .gpio24 = GPIO_DIR_INPUT,
-+ .gpio27 = GPIO_DIR_INPUT,
-+ .gpio28 = GPIO_DIR_OUTPUT,
-+ .gpio29 = GPIO_DIR_INPUT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_level = {
-+ .gpio28 = GPIO_LEVEL_LOW,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_reset = {
-+ .gpio30 = GPIO_RESET_RSMRST,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_invert = {
-+ .gpio0 = GPIO_INVERT,
-+ .gpio8 = GPIO_INVERT,
-+ .gpio13 = GPIO_INVERT,
-+ .gpio14 = GPIO_INVERT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_blink = {
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_mode = {
-+ .gpio32 = GPIO_MODE_NATIVE,
-+ .gpio33 = GPIO_MODE_GPIO,
-+ .gpio34 = GPIO_MODE_GPIO,
-+ .gpio35 = GPIO_MODE_GPIO,
-+ .gpio36 = GPIO_MODE_GPIO,
-+ .gpio37 = GPIO_MODE_GPIO,
-+ .gpio38 = GPIO_MODE_GPIO,
-+ .gpio39 = GPIO_MODE_GPIO,
-+ .gpio40 = GPIO_MODE_NATIVE,
-+ .gpio41 = GPIO_MODE_NATIVE,
-+ .gpio42 = GPIO_MODE_NATIVE,
-+ .gpio43 = GPIO_MODE_NATIVE,
-+ .gpio44 = GPIO_MODE_NATIVE,
-+ .gpio45 = GPIO_MODE_GPIO,
-+ .gpio46 = GPIO_MODE_NATIVE,
-+ .gpio47 = GPIO_MODE_NATIVE,
-+ .gpio48 = GPIO_MODE_GPIO,
-+ .gpio49 = GPIO_MODE_GPIO,
-+ .gpio50 = GPIO_MODE_NATIVE,
-+ .gpio51 = GPIO_MODE_GPIO,
-+ .gpio52 = GPIO_MODE_GPIO,
-+ .gpio53 = GPIO_MODE_NATIVE,
-+ .gpio54 = GPIO_MODE_GPIO,
-+ .gpio55 = GPIO_MODE_NATIVE,
-+ .gpio56 = GPIO_MODE_NATIVE,
-+ .gpio57 = GPIO_MODE_GPIO,
-+ .gpio58 = GPIO_MODE_NATIVE,
-+ .gpio59 = GPIO_MODE_NATIVE,
-+ .gpio60 = GPIO_MODE_GPIO,
-+ .gpio61 = GPIO_MODE_NATIVE,
-+ .gpio62 = GPIO_MODE_NATIVE,
-+ .gpio63 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_direction = {
-+ .gpio33 = GPIO_DIR_INPUT,
-+ .gpio34 = GPIO_DIR_OUTPUT,
-+ .gpio35 = GPIO_DIR_INPUT,
-+ .gpio36 = GPIO_DIR_INPUT,
-+ .gpio37 = GPIO_DIR_INPUT,
-+ .gpio38 = GPIO_DIR_INPUT,
-+ .gpio39 = GPIO_DIR_INPUT,
-+ .gpio45 = GPIO_DIR_OUTPUT,
-+ .gpio48 = GPIO_DIR_INPUT,
-+ .gpio49 = GPIO_DIR_INPUT,
-+ .gpio51 = GPIO_DIR_INPUT,
-+ .gpio52 = GPIO_DIR_INPUT,
-+ .gpio54 = GPIO_DIR_INPUT,
-+ .gpio57 = GPIO_DIR_INPUT,
-+ .gpio60 = GPIO_DIR_OUTPUT,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_level = {
-+ .gpio34 = GPIO_LEVEL_HIGH,
-+ .gpio45 = GPIO_LEVEL_LOW,
-+ .gpio60 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_reset = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_mode = {
-+ .gpio64 = GPIO_MODE_NATIVE,
-+ .gpio65 = GPIO_MODE_NATIVE,
-+ .gpio66 = GPIO_MODE_NATIVE,
-+ .gpio67 = GPIO_MODE_NATIVE,
-+ .gpio68 = GPIO_MODE_GPIO,
-+ .gpio69 = GPIO_MODE_GPIO,
-+ .gpio70 = GPIO_MODE_GPIO,
-+ .gpio71 = GPIO_MODE_GPIO,
-+ .gpio72 = GPIO_MODE_NATIVE,
-+ .gpio73 = GPIO_MODE_NATIVE,
-+ .gpio74 = GPIO_MODE_NATIVE,
-+ .gpio75 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_direction = {
-+ .gpio68 = GPIO_DIR_INPUT,
-+ .gpio69 = GPIO_DIR_INPUT,
-+ .gpio70 = GPIO_DIR_INPUT,
-+ .gpio71 = GPIO_DIR_INPUT,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_level = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_reset = {
-+};
-+
-+const struct pch_gpio_map mainboard_gpio_map = {
-+ .set1 = {
-+ .mode = &pch_gpio_set1_mode,
-+ .direction = &pch_gpio_set1_direction,
-+ .level = &pch_gpio_set1_level,
-+ .blink = &pch_gpio_set1_blink,
-+ .invert = &pch_gpio_set1_invert,
-+ .reset = &pch_gpio_set1_reset,
-+ },
-+ .set2 = {
-+ .mode = &pch_gpio_set2_mode,
-+ .direction = &pch_gpio_set2_direction,
-+ .level = &pch_gpio_set2_level,
-+ .reset = &pch_gpio_set2_reset,
-+ },
-+ .set3 = {
-+ .mode = &pch_gpio_set3_mode,
-+ .direction = &pch_gpio_set3_direction,
-+ .level = &pch_gpio_set3_level,
-+ .reset = &pch_gpio_set3_reset,
-+ },
-+};
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6330/hda_verb.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6330/hda_verb.c
-new file mode 100644
-index 0000000000..804733b172
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6330/hda_verb.c
-@@ -0,0 +1,32 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <device/azalia_device.h>
-+
-+const u32 cim_verb_data[] = {
-+ 0x111d76df, /* Codec Vendor / Device ID: IDT */
-+ 0x10280533, /* Subsystem ID */
-+ 11, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(0, 0x10280533),
-+ AZALIA_PIN_CFG(0, 0x0a, 0x03a11020),
-+ AZALIA_PIN_CFG(0, 0x0b, 0x0321101f),
-+ AZALIA_PIN_CFG(0, 0x0c, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x0d, 0x90170110),
-+ AZALIA_PIN_CFG(0, 0x0e, 0x23011050),
-+ AZALIA_PIN_CFG(0, 0x0f, 0x23a1102e),
-+ AZALIA_PIN_CFG(0, 0x10, 0x400000f3),
-+ AZALIA_PIN_CFG(0, 0x11, 0xd5a30130),
-+ AZALIA_PIN_CFG(0, 0x1f, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x20, 0x400000f0),
-+
-+ 0x80862806, /* Codec Vendor / Device ID: Intel */
-+ 0x80860101, /* Subsystem ID */
-+ 4, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(3, 0x80860101),
-+ AZALIA_PIN_CFG(3, 0x05, 0x18560010),
-+ AZALIA_PIN_CFG(3, 0x06, 0x18560020),
-+ AZALIA_PIN_CFG(3, 0x07, 0x18560030),
-+};
-+
-+const u32 pc_beep_verbs[0] = {};
-+
-+AZALIA_ARRAY_SIZES;
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6330/overridetree.cb b/src/mainboard/dell/snb_ivb_latitude/variants/e6330/overridetree.cb
-new file mode 100644
-index 0000000000..4125159367
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6330/overridetree.cb
-@@ -0,0 +1,37 @@
-+## SPDX-License-Identifier: GPL-2.0-or-later
-+
-+chip northbridge/intel/sandybridge
-+ device domain 0 on
-+ subsystemid 0x1028 0x0533 inherit
-+
-+ device ref igd on
-+ register "gpu_cpu_backlight" = "0x00001312"
-+ register "gpu_pch_backlight" = "0x13121312"
-+ end
-+
-+ chip southbridge/intel/bd82x6x
-+ register "usb_port_config" = "{
-+ { 1, 2, 0 },
-+ { 1, 0, 0 },
-+ { 1, 0, 1 },
-+ { 1, 1, 1 },
-+ { 1, 1, 2 },
-+ { 1, 1, 2 },
-+ { 1, 2, 3 },
-+ { 1, 2, 3 },
-+ { 1, 2, 4 },
-+ { 1, 1, 4 },
-+ { 1, 1, 5 },
-+ { 1, 1, 5 },
-+ { 1, 2, 6 },
-+ { 1, 0, 6 },
-+ }"
-+
-+ device ref xhci on
-+ register "superspeed_capable_ports" = "0x0000000f"
-+ register "xhci_overcurrent_mapping" = "0x00000c03"
-+ register "xhci_switchable_ports" = "0x0000000f"
-+ end
-+ end
-+ end
-+end
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0027-nb-intel-gm45-Make-DDR2-raminit-work.patch b/config/coreboot/default/patches/0016-nb-intel-gm45-Make-DDR2-raminit-work.patch
index 28fc679f..091a15c4 100644
--- a/config/coreboot/default/patches/0027-nb-intel-gm45-Make-DDR2-raminit-work.patch
+++ b/config/coreboot/default/patches/0016-nb-intel-gm45-Make-DDR2-raminit-work.patch
@@ -1,7 +1,7 @@
-From c6181fe0c8b58cb5a4523d5763fc5fcdf61b3f10 Mon Sep 17 00:00:00 2001
+From 9e0a6aa376db81f9409eda92b6783a8262c1fedb Mon Sep 17 00:00:00 2001
From: Angel Pons <th3fanbus@gmail.com>
Date: Mon, 10 May 2021 22:40:59 +0200
-Subject: [PATCH 27/51] nb/intel/gm45: Make DDR2 raminit work
+Subject: [PATCH 16/37] nb/intel/gm45: Make DDR2 raminit work
List of changes:
- Update some timing and ODT values
diff --git a/config/coreboot/default/patches/0017-mb-dell-Add-Latitude-E6230-Ivy-Bridge.patch b/config/coreboot/default/patches/0017-mb-dell-Add-Latitude-E6230-Ivy-Bridge.patch
deleted file mode 100644
index 412b8471..00000000
--- a/config/coreboot/default/patches/0017-mb-dell-Add-Latitude-E6230-Ivy-Bridge.patch
+++ /dev/null
@@ -1,440 +0,0 @@
-From 84d7f3201eb4492acd7d290a02d19c4850c85791 Mon Sep 17 00:00:00 2001
-From: Nicholas Chin <nic.c3.14@gmail.com>
-Date: Thu, 26 Oct 2017 21:26:43 +0800
-Subject: [PATCH 17/51] mb/dell: Add Latitude E6230 (Ivy Bridge)
-
-This was adapted from CB:22693 from Iru Cai, which was based on
-autoport. I do not physically have this system. Someone with physical
-access to an E6230 running version A11 of the vendor firmware sent me
-the VBT after running the command `intelvbttool --inlegacy --outvbt
-data.vbt`. This new version of the port has not yet been tested.
-
-The EC is the SMSC MEC5055, which seems to be compatible with the
-existing MEC5035 code. As with the other Dell systems with this EC, this
-board is assumed to be internally flashable using an EC command that
-tells it to pull the FDO pin low on the next boot, which also tells the
-vendor firmware to disable all write protections to the flash [1].
-
-[1] https://gitlab.com/nic3-14159/dell-flash-unlock
-
-Original-Change-Id: I8cdc01e902e670310628809416290045c2102340
-Change-Id: I32927beea7c29b96a851ab77ed15b0160f16d369
-Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>
----
- src/mainboard/dell/snb_ivb_latitude/Kconfig | 11 +-
- .../dell/snb_ivb_latitude/Kconfig.name | 3 +
- .../snb_ivb_latitude/variants/e6230/data.vbt | Bin 0 -> 4280 bytes
- .../variants/e6230/early_init.c | 12 ++
- .../snb_ivb_latitude/variants/e6230/gpio.c | 193 ++++++++++++++++++
- .../variants/e6230/hda_verb.c | 32 +++
- .../variants/e6230/overridetree.cb | 40 ++++
- 7 files changed, 290 insertions(+), 1 deletion(-)
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6230/data.vbt
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6230/early_init.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6230/gpio.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6230/hda_verb.c
- create mode 100644 src/mainboard/dell/snb_ivb_latitude/variants/e6230/overridetree.cb
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-index 49bf225fe2..f6e097930b 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig
-@@ -56,6 +56,12 @@ config BOARD_DELL_LATITUDE_E5530
- select BOARD_ROMSIZE_KB_12288
- select SOUTHBRIDGE_INTEL_C216
-
-+config BOARD_DELL_LATITUDE_E6230
-+ select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
-+ select BOARD_ROMSIZE_KB_12288
-+ select MAINBOARD_USES_IFD_GBE_REGION
-+ select SOUTHBRIDGE_INTEL_C216
-+
- config BOARD_DELL_LATITUDE_E6330
- select BOARD_DELL_SNB_IVB_LATITUDE_COMMON
- select BOARD_ROMSIZE_KB_12288
-@@ -90,6 +96,7 @@ config MAINBOARD_PART_NUMBER
- default "Latitude E6420" if BOARD_DELL_LATITUDE_E6420
- default "Latitude E6520" if BOARD_DELL_LATITUDE_E6520
- default "Latitude E5530" if BOARD_DELL_LATITUDE_E5530
-+ default "Latitude E6230" if BOARD_DELL_LATITUDE_E6230
- default "Latitude E6330" if BOARD_DELL_LATITUDE_E6330
- default "Latitude E6430" if BOARD_DELL_LATITUDE_E6430
- default "Latitude E6530" if BOARD_DELL_LATITUDE_E6530
-@@ -108,6 +115,7 @@ config VARIANT_DIR
- default "e6420" if BOARD_DELL_LATITUDE_E6420
- default "e6520" if BOARD_DELL_LATITUDE_E6520
- default "e5530" if BOARD_DELL_LATITUDE_E5530
-+ default "e6230" if BOARD_DELL_LATITUDE_E6230
- default "e6330" if BOARD_DELL_LATITUDE_E6330
- default "e6430" if BOARD_DELL_LATITUDE_E6430
- default "e6530" if BOARD_DELL_LATITUDE_E6530
-@@ -121,7 +129,8 @@ config VGA_BIOS_ID
- || BOARD_DELL_LATITUDE_E5520 \
- || BOARD_DELL_LATITUDE_E6220 \
- || BOARD_DELL_LATITUDE_E6320
-- default "8086,0166" if BOARD_DELL_LATITUDE_E6430 \
-+ default "8086,0166" if BOARD_DELL_LATITUDE_E6230 \
-+ || BOARD_DELL_LATITUDE_E6430 \
- || BOARD_DELL_LATITUDE_E6530
-
- endif
-diff --git a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-index d6fc8eb224..cb7bbd5cdb 100644
---- a/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-+++ b/src/mainboard/dell/snb_ivb_latitude/Kconfig.name
-@@ -21,6 +21,9 @@ config BOARD_DELL_LATITUDE_E6520
- config BOARD_DELL_LATITUDE_E5530
- bool "Latitude E5530"
-
-+config BOARD_DELL_LATITUDE_E6230
-+ bool "Latitude E6230"
-+
- config BOARD_DELL_LATITUDE_E6330
- bool "Latitude E6330"
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6230/data.vbt b/src/mainboard/dell/snb_ivb_latitude/variants/e6230/data.vbt
-new file mode 100644
-index 0000000000000000000000000000000000000000..45ce8f435eea647a0bddaab3fd1e9282c87afc66
-GIT binary patch
-literal 4280
-zcmdT{Yiu0V75-*tAG5PFyX&zDekA7P<*tbx&o1`j23L%CmvkLWvN7(mLa6alZ?J`9
-zo3#m4YVlG`2;w12Ajppt<qra(R;8*G@uw*8gIcsg2vxi!q_pBkmGUD$s9IGi+jD1T
-zO`Kg43n@JA>~|mMp8L%`XU@4ZyCa_(r`z|Z`bP4p-rEkOMn-R;Ntk#o`b)0sOKRl6
-z?T0eM<HLtiqX*Kr(o5Kc<Iyk90h5ws=!y8i;K=M^X(l$-Eoeyyj>ZS*@LZWP#hD{>
-z<r2jcJ;b8e!oAb;^QB2D#7*krI^IpA=?ra8?xvqj6=&}$QL2a1J(QuD($UfkElf=x
-zUM!UtXmO4PP4h^;&)jWJvd(Pj0lIs7wpgAnE!1!MB1w8~{^#ZCd!`mCmhPs6X_~zW
-zGae^<%aoog&+n$;nHd@rItw&bS}2u|mL_-Ws;&ZOWW_51k`IALAW8pAz~@C!!B)bs
-z1x-OrK~}*8L07Po(5+xZL6I<}phTEf5QRsVJYHa{f^AWEV+2@lvrPVS%snsOn?N)w
-zpKbvwOnk&Q_6Y?aB;r1=!TYwts;yA@BnbFfECo!7JVJq7g^yhYMUV;wlBjksp(hI2
-z^<}E7r698{-pw!*{mH>SLslxYH@j~%H#VLx+<8~!;a@$n+>Q%xHrQ8KGI21_iL4sI
-zF*$}m$R7Mr9z@Z*ir@Q9eClsSmC+t(g`q~VQ&nIxZenav_^Buc78s8*o@e|<QE{4a
-zhVeGz1IFJN|784&5eTYiVstQeGWr-lWTY9lG45a#8TT^oXDl%uXFS9BHN$^DE>t}g
-z1Z-O>lG`>pEuvmL-HpmgSANo!2hWQq2B>Zua$8%tfvQ>!1n@=m9ri_4`H|Rx#SH9n
-zDdRF_-FDP&WjW`L$GK%a6x?yO8l2!^g0HJrtA7TknNzCO?|U!wCv2^-5pJ%LW6!+P
-z)anX%E>`gP%3Er4c6+J9x=Atk1{Abrr1|WSY3P`SO5j!R5F*vbbQ%AaSHnR_+x&Op
-zA%8C-Pk=-Hs+FL90B)E*y3FUTIA1J)&pxRF$tzAkNr7a6_-8v$@j~G~3keqYd5I<T
-z`Kb3Q@LKkANhE_aMG_R&<ewt+nVbp5l*3G7mYJEKr<kXS;TA&^G;5`q5b>;y8g^P<
-zfWO_D2@EyVVBxnpv*}hgTeeRzWz9BoISh>M%^k`WXG=5ti$_Wu99)~lWE-qubeXNk
-zla9Tu=Jhyn5T<3$H#?Hfm-`+(d$7IBDx9cEvNv1i-LEDr>r7438bfkPcKod+mwd22
-z%{^(w&NuG)MKl0fTMTXZFJEm~k;KCj*D60g=j!2jsP)<fOUGaEZa`&xE*)?FZuW#-
-z8!Of7<|N(^R#xcjmZ&nZ%~{pC5y_T*PB2LdDjuI#Te}-4Qccvj+u4N3TBx|oVy*mP
-z<9xfFziy4n?sPv3Sqo7jWMo3>{tzvOjAJ2nB}At~#%f4?FGT+d8LFnXXtYN&Mm06B
-z(JwUPX-z$$(d(M=uBLvh@h6#K=;~&jQo1p&t3TCgSvQ{3)l)jXr5hjW>fd!z!bW>o
-z-4UjJVdJi_dN@o^hK(1(>dRqzCv2PztLMTLjTqY^YEMMJ{=B#1IV)9~IMg|yl(NPF
-zQSfMX`?(b5)))B!zjy0B$ua20CCLTPl^IS&2=T&Zid9-1*K{VAJP?rxjYC+zGDCe*
-ziQI7VfF17@3`3W-qCN>lPC5CL_c?p0F<ekqB;g0q3P1R5KNubPsT>TGXaGB3i~{ZE
-zr=QtIprytDnU7C*Wj%x0k)O{Y%nUnl%}K%F|J_iVaD&ubW4Qbtx;pZEb9}f^Yd;Ea
-zI1Ha{7Yt~z{LAY++1QG{F6*_4WsUziY{x?%I9B}i5-Tphhk8FGm%J<d_0CUoV^%N&
-zTe02j+LXk=ZyWoe7L$#wsEY@VC>f!3d-ysG_9>uk%#)4xpxb+ZkJdel#+h}l9j9`1
-zt*M!5u?i4YtZ+WECo6$LJF06|G-mMZskGiV*lQJf-ItB+hltI<?{5E<^P=0rL<P+g
-z(P)!c<?MlvMK0O~UwZ4*;x|ms(&&#Vn_-4{KM#g~a=;$N2QD7mSX0{t<cf>sId@e&
-z-cN<SWA3VKCN6g3lx#+PySpWu*+pw}>vr(fgI)K*zkikg6TDJi?^}ghc*U*%A%EGg
-Y$$8Z}9a~<{Q@y10T!W`-d%n2+Kj)*Kg#Z8m
-
-literal 0
-HcmV?d00001
-
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6230/early_init.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6230/early_init.c
-new file mode 100644
-index 0000000000..24c1b32467
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6230/early_init.c
-@@ -0,0 +1,12 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <bootblock_common.h>
-+#include <device/pci_ops.h>
-+#include <ec/dell/mec5035/mec5035.h>
-+#include <southbridge/intel/bd82x6x/pch.h>
-+
-+void bootblock_mainboard_early_init(void)
-+{
-+ pci_write_config16(PCH_LPC_DEV, LPC_EN, CNF1_LPC_EN | MC_LPC_EN | KBC_LPC_EN);
-+ mec5035_early_init();
-+}
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6230/gpio.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6230/gpio.c
-new file mode 100644
-index 0000000000..c07e4b1c56
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6230/gpio.c
-@@ -0,0 +1,193 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <southbridge/intel/common/gpio.h>
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_mode = {
-+ .gpio0 = GPIO_MODE_GPIO,
-+ .gpio1 = GPIO_MODE_GPIO,
-+ .gpio2 = GPIO_MODE_GPIO,
-+ .gpio3 = GPIO_MODE_GPIO,
-+ .gpio4 = GPIO_MODE_GPIO,
-+ .gpio5 = GPIO_MODE_NATIVE,
-+ .gpio6 = GPIO_MODE_GPIO,
-+ .gpio7 = GPIO_MODE_GPIO,
-+ .gpio8 = GPIO_MODE_GPIO,
-+ .gpio9 = GPIO_MODE_NATIVE,
-+ .gpio10 = GPIO_MODE_NATIVE,
-+ .gpio11 = GPIO_MODE_NATIVE,
-+ .gpio12 = GPIO_MODE_NATIVE,
-+ .gpio13 = GPIO_MODE_GPIO,
-+ .gpio14 = GPIO_MODE_GPIO,
-+ .gpio15 = GPIO_MODE_GPIO,
-+ .gpio16 = GPIO_MODE_GPIO,
-+ .gpio17 = GPIO_MODE_GPIO,
-+ .gpio18 = GPIO_MODE_NATIVE,
-+ .gpio19 = GPIO_MODE_GPIO,
-+ .gpio20 = GPIO_MODE_NATIVE,
-+ .gpio21 = GPIO_MODE_GPIO,
-+ .gpio22 = GPIO_MODE_GPIO,
-+ .gpio23 = GPIO_MODE_NATIVE,
-+ .gpio24 = GPIO_MODE_GPIO,
-+ .gpio25 = GPIO_MODE_NATIVE,
-+ .gpio26 = GPIO_MODE_NATIVE,
-+ .gpio27 = GPIO_MODE_GPIO,
-+ .gpio28 = GPIO_MODE_GPIO,
-+ .gpio29 = GPIO_MODE_GPIO,
-+ .gpio30 = GPIO_MODE_NATIVE,
-+ .gpio31 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_direction = {
-+ .gpio0 = GPIO_DIR_INPUT,
-+ .gpio1 = GPIO_DIR_INPUT,
-+ .gpio2 = GPIO_DIR_INPUT,
-+ .gpio3 = GPIO_DIR_INPUT,
-+ .gpio4 = GPIO_DIR_INPUT,
-+ .gpio6 = GPIO_DIR_INPUT,
-+ .gpio7 = GPIO_DIR_INPUT,
-+ .gpio8 = GPIO_DIR_INPUT,
-+ .gpio13 = GPIO_DIR_INPUT,
-+ .gpio14 = GPIO_DIR_INPUT,
-+ .gpio15 = GPIO_DIR_INPUT,
-+ .gpio16 = GPIO_DIR_INPUT,
-+ .gpio17 = GPIO_DIR_OUTPUT,
-+ .gpio19 = GPIO_DIR_INPUT,
-+ .gpio21 = GPIO_DIR_INPUT,
-+ .gpio22 = GPIO_DIR_INPUT,
-+ .gpio24 = GPIO_DIR_INPUT,
-+ .gpio27 = GPIO_DIR_INPUT,
-+ .gpio28 = GPIO_DIR_OUTPUT,
-+ .gpio29 = GPIO_DIR_INPUT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_level = {
-+ .gpio17 = GPIO_LEVEL_HIGH,
-+ .gpio28 = GPIO_LEVEL_LOW,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_reset = {
-+ .gpio30 = GPIO_RESET_RSMRST,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_invert = {
-+ .gpio0 = GPIO_INVERT,
-+ .gpio8 = GPIO_INVERT,
-+ .gpio13 = GPIO_INVERT,
-+ .gpio14 = GPIO_INVERT,
-+};
-+
-+static const struct pch_gpio_set1 pch_gpio_set1_blink = {
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_mode = {
-+ .gpio32 = GPIO_MODE_NATIVE,
-+ .gpio33 = GPIO_MODE_GPIO,
-+ .gpio34 = GPIO_MODE_GPIO,
-+ .gpio35 = GPIO_MODE_GPIO,
-+ .gpio36 = GPIO_MODE_GPIO,
-+ .gpio37 = GPIO_MODE_GPIO,
-+ .gpio38 = GPIO_MODE_GPIO,
-+ .gpio39 = GPIO_MODE_GPIO,
-+ .gpio40 = GPIO_MODE_NATIVE,
-+ .gpio41 = GPIO_MODE_NATIVE,
-+ .gpio42 = GPIO_MODE_NATIVE,
-+ .gpio43 = GPIO_MODE_NATIVE,
-+ .gpio44 = GPIO_MODE_NATIVE,
-+ .gpio45 = GPIO_MODE_GPIO,
-+ .gpio46 = GPIO_MODE_NATIVE,
-+ .gpio47 = GPIO_MODE_NATIVE,
-+ .gpio48 = GPIO_MODE_GPIO,
-+ .gpio49 = GPIO_MODE_GPIO,
-+ .gpio50 = GPIO_MODE_NATIVE,
-+ .gpio51 = GPIO_MODE_GPIO,
-+ .gpio52 = GPIO_MODE_GPIO,
-+ .gpio53 = GPIO_MODE_NATIVE,
-+ .gpio54 = GPIO_MODE_GPIO,
-+ .gpio55 = GPIO_MODE_NATIVE,
-+ .gpio56 = GPIO_MODE_NATIVE,
-+ .gpio57 = GPIO_MODE_GPIO,
-+ .gpio58 = GPIO_MODE_NATIVE,
-+ .gpio59 = GPIO_MODE_NATIVE,
-+ .gpio60 = GPIO_MODE_GPIO,
-+ .gpio61 = GPIO_MODE_NATIVE,
-+ .gpio62 = GPIO_MODE_NATIVE,
-+ .gpio63 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_direction = {
-+ .gpio33 = GPIO_DIR_INPUT,
-+ .gpio34 = GPIO_DIR_OUTPUT,
-+ .gpio35 = GPIO_DIR_INPUT,
-+ .gpio36 = GPIO_DIR_INPUT,
-+ .gpio37 = GPIO_DIR_INPUT,
-+ .gpio38 = GPIO_DIR_INPUT,
-+ .gpio39 = GPIO_DIR_INPUT,
-+ .gpio45 = GPIO_DIR_OUTPUT,
-+ .gpio48 = GPIO_DIR_INPUT,
-+ .gpio49 = GPIO_DIR_INPUT,
-+ .gpio51 = GPIO_DIR_INPUT,
-+ .gpio52 = GPIO_DIR_INPUT,
-+ .gpio54 = GPIO_DIR_INPUT,
-+ .gpio57 = GPIO_DIR_INPUT,
-+ .gpio60 = GPIO_DIR_OUTPUT,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_level = {
-+ .gpio34 = GPIO_LEVEL_HIGH,
-+ .gpio45 = GPIO_LEVEL_LOW,
-+ .gpio60 = GPIO_LEVEL_HIGH,
-+};
-+
-+static const struct pch_gpio_set2 pch_gpio_set2_reset = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_mode = {
-+ .gpio64 = GPIO_MODE_NATIVE,
-+ .gpio65 = GPIO_MODE_NATIVE,
-+ .gpio66 = GPIO_MODE_NATIVE,
-+ .gpio67 = GPIO_MODE_NATIVE,
-+ .gpio68 = GPIO_MODE_GPIO,
-+ .gpio69 = GPIO_MODE_GPIO,
-+ .gpio70 = GPIO_MODE_GPIO,
-+ .gpio71 = GPIO_MODE_GPIO,
-+ .gpio72 = GPIO_MODE_NATIVE,
-+ .gpio73 = GPIO_MODE_NATIVE,
-+ .gpio74 = GPIO_MODE_NATIVE,
-+ .gpio75 = GPIO_MODE_NATIVE,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_direction = {
-+ .gpio68 = GPIO_DIR_INPUT,
-+ .gpio69 = GPIO_DIR_INPUT,
-+ .gpio70 = GPIO_DIR_INPUT,
-+ .gpio71 = GPIO_DIR_INPUT,
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_level = {
-+};
-+
-+static const struct pch_gpio_set3 pch_gpio_set3_reset = {
-+};
-+
-+const struct pch_gpio_map mainboard_gpio_map = {
-+ .set1 = {
-+ .mode = &pch_gpio_set1_mode,
-+ .direction = &pch_gpio_set1_direction,
-+ .level = &pch_gpio_set1_level,
-+ .blink = &pch_gpio_set1_blink,
-+ .invert = &pch_gpio_set1_invert,
-+ .reset = &pch_gpio_set1_reset,
-+ },
-+ .set2 = {
-+ .mode = &pch_gpio_set2_mode,
-+ .direction = &pch_gpio_set2_direction,
-+ .level = &pch_gpio_set2_level,
-+ .reset = &pch_gpio_set2_reset,
-+ },
-+ .set3 = {
-+ .mode = &pch_gpio_set3_mode,
-+ .direction = &pch_gpio_set3_direction,
-+ .level = &pch_gpio_set3_level,
-+ .reset = &pch_gpio_set3_reset,
-+ },
-+};
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6230/hda_verb.c b/src/mainboard/dell/snb_ivb_latitude/variants/e6230/hda_verb.c
-new file mode 100644
-index 0000000000..f6876f9e09
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6230/hda_verb.c
-@@ -0,0 +1,32 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#include <device/azalia_device.h>
-+
-+const u32 cim_verb_data[] = {
-+ 0x111d76df, /* Codec Vendor / Device ID: IDT */
-+ 0x10280532, /* Subsystem ID */
-+ 11, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(0, 0x10280532),
-+ AZALIA_PIN_CFG(0, 0x0a, 0x03a11020),
-+ AZALIA_PIN_CFG(0, 0x0b, 0x0321101f),
-+ AZALIA_PIN_CFG(0, 0x0c, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x0d, 0x90170110),
-+ AZALIA_PIN_CFG(0, 0x0e, 0x23011050),
-+ AZALIA_PIN_CFG(0, 0x0f, 0x23a1102e),
-+ AZALIA_PIN_CFG(0, 0x10, 0x400000f3),
-+ AZALIA_PIN_CFG(0, 0x11, 0xd5a30130),
-+ AZALIA_PIN_CFG(0, 0x1f, 0x400000f0),
-+ AZALIA_PIN_CFG(0, 0x20, 0x400000f0),
-+
-+ 0x80862806, /* Codec Vendor / Device ID: Intel */
-+ 0x80860101, /* Subsystem ID */
-+ 4, /* Number of 4 dword sets */
-+ AZALIA_SUBVENDOR(3, 0x80860101),
-+ AZALIA_PIN_CFG(3, 0x05, 0x18560010),
-+ AZALIA_PIN_CFG(3, 0x06, 0x18560020),
-+ AZALIA_PIN_CFG(3, 0x07, 0x18560030),
-+};
-+
-+const u32 pc_beep_verbs[0] = {};
-+
-+AZALIA_ARRAY_SIZES;
-diff --git a/src/mainboard/dell/snb_ivb_latitude/variants/e6230/overridetree.cb b/src/mainboard/dell/snb_ivb_latitude/variants/e6230/overridetree.cb
-new file mode 100644
-index 0000000000..3a0fa720da
---- /dev/null
-+++ b/src/mainboard/dell/snb_ivb_latitude/variants/e6230/overridetree.cb
-@@ -0,0 +1,40 @@
-+## SPDX-License-Identifier: GPL-2.0-or-later
-+
-+chip northbridge/intel/sandybridge
-+ device domain 0 on
-+ subsystemid 0x1028 0x0532 inherit
-+
-+ device ref igd on
-+ register "gpu_cpu_backlight" = "0x000009e9"
-+ register "gpu_pch_backlight" = "0x13121312"
-+ end
-+
-+ chip southbridge/intel/bd82x6x
-+ register "usb_port_config" = "{
-+ { 1, 1, 0 },
-+ { 1, 1, 0 },
-+ { 1, 0, 1 },
-+ { 1, 2, 1 },
-+ { 1, 0, 2 },
-+ { 1, 0, 2 },
-+ { 1, 0, 3 },
-+ { 1, 1, 3 },
-+ { 1, 2, 4 },
-+ { 1, 1, 4 },
-+ { 1, 1, 5 },
-+ { 1, 1, 5 },
-+ { 1, 2, 6 },
-+ { 1, 0, 6 },
-+ }"
-+
-+ device ref xhci on
-+ register "superspeed_capable_ports" = "0x0000000f"
-+ register "xhci_overcurrent_mapping" = "0x00000c03"
-+ register "xhci_switchable_ports" = "0x0000000f"
-+ end
-+ device ref sata1 on
-+ register "sata_port_map" = "0x31"
-+ end
-+ end
-+ end
-+end
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0028-nb-gm45-Fix-Angel-s-DDR2-RCOMP-fix-on-DDR3-boards.patch b/config/coreboot/default/patches/0017-nb-gm45-Fix-Angel-s-DDR2-RCOMP-fix-on-DDR3-boards.patch
index 92e59129..4ba74757 100644
--- a/config/coreboot/default/patches/0028-nb-gm45-Fix-Angel-s-DDR2-RCOMP-fix-on-DDR3-boards.patch
+++ b/config/coreboot/default/patches/0017-nb-gm45-Fix-Angel-s-DDR2-RCOMP-fix-on-DDR3-boards.patch
@@ -1,7 +1,7 @@
-From b6f75374fa38e0b097c9eadb4916112707cb6747 Mon Sep 17 00:00:00 2001
+From 6acc310c1d695d47c148296da9da189de21d58be Mon Sep 17 00:00:00 2001
From: Leah Rowe <info@minifree.org>
Date: Tue, 6 Aug 2024 00:50:24 +0100
-Subject: [PATCH 28/51] nb/gm45: Fix Angel's DDR2 RCOMP fix on DDR3 boards
+Subject: [PATCH 17/37] nb/gm45: Fix Angel's DDR2 RCOMP fix on DDR3 boards
We add this patch:
diff --git a/config/coreboot/default/patches/0029-mb-dell-e6400-Use-100-MHz-reference-clock-for-displa.patch b/config/coreboot/default/patches/0018-mb-dell-e6400-Use-100-MHz-reference-clock-for-displa.patch
index e31cb64c..1cf7c0ac 100644
--- a/config/coreboot/default/patches/0029-mb-dell-e6400-Use-100-MHz-reference-clock-for-displa.patch
+++ b/config/coreboot/default/patches/0018-mb-dell-e6400-Use-100-MHz-reference-clock-for-displa.patch
@@ -1,7 +1,7 @@
-From d3045b3dcebd94b78df2129cd81a20adf215e46a Mon Sep 17 00:00:00 2001
+From 7461210ecc7c8e41f3f941bd5ce7943e5f66c711 Mon Sep 17 00:00:00 2001
From: Nicholas Chin <nic.c3.14@gmail.com>
Date: Mon, 20 May 2024 10:24:16 -0600
-Subject: [PATCH 29/51] mb/dell/e6400: Use 100 MHz reference clock for display
+Subject: [PATCH 18/37] mb/dell/e6400: Use 100 MHz reference clock for display
The E6400 uses a 100 MHz reference clock for spread spectrum support on
LVDS, whereas libgfxinit previously assumed a 96 MHz input clock. For
@@ -33,7 +33,7 @@ index 417d95fd5d..6fe1b1c456 100644
default "dell/e6400"
diff --git a/src/northbridge/intel/gm45/Kconfig b/src/northbridge/intel/gm45/Kconfig
-index 8059e7ee80..5df5a93296 100644
+index fef0d735b3..fc5df8b11a 100644
--- a/src/northbridge/intel/gm45/Kconfig
+++ b/src/northbridge/intel/gm45/Kconfig
@@ -14,6 +14,10 @@ config NORTHBRIDGE_INTEL_GM45
diff --git a/config/coreboot/default/patches/0047-nb-x4x-define-INTEL_GMA_DPLL_REF_FREQ.patch b/config/coreboot/default/patches/0019-nb-x4x-define-INTEL_GMA_DPLL_REF_FREQ.patch
index 988ae4e6..2edfaae3 100644
--- a/config/coreboot/default/patches/0047-nb-x4x-define-INTEL_GMA_DPLL_REF_FREQ.patch
+++ b/config/coreboot/default/patches/0019-nb-x4x-define-INTEL_GMA_DPLL_REF_FREQ.patch
@@ -1,7 +1,7 @@
-From 53f2d47ee6ebaa8d47b076a6c2a1514c91247b95 Mon Sep 17 00:00:00 2001
+From a683dffd774dbbe25cc77c0f7d3853232c17c2bf Mon Sep 17 00:00:00 2001
From: Leah Rowe <info@minifree.org>
Date: Mon, 12 Aug 2024 02:15:24 +0100
-Subject: [PATCH 47/51] nb/x4x: define INTEL_GMA_DPLL_REF_FREQ
+Subject: [PATCH 19/37] nb/x4x: define INTEL_GMA_DPLL_REF_FREQ
set it to 96MHz. fixes the following build error when
building for x4x boards e.g. gigabyte ga-g41m-es2l:
@@ -33,7 +33,7 @@ Signed-off-by: Leah Rowe <info@minifree.org>
1 file changed, 4 insertions(+)
diff --git a/src/northbridge/intel/x4x/Kconfig b/src/northbridge/intel/x4x/Kconfig
-index 9af063819b..93ba575b95 100644
+index 097e11126c..6430319f6a 100644
--- a/src/northbridge/intel/x4x/Kconfig
+++ b/src/northbridge/intel/x4x/Kconfig
@@ -14,6 +14,10 @@ config NORTHBRIDGE_INTEL_X4X
diff --git a/config/coreboot/default/patches/0048-mb-dell-Convert-E6400-into-a-variant.patch b/config/coreboot/default/patches/0020-mb-dell-Convert-E6400-into-a-variant.patch
index 156d5c8d..a0068142 100644
--- a/config/coreboot/default/patches/0048-mb-dell-Convert-E6400-into-a-variant.patch
+++ b/config/coreboot/default/patches/0020-mb-dell-Convert-E6400-into-a-variant.patch
@@ -1,7 +1,7 @@
-From 92556743e92cc02524296b653de5241160876218 Mon Sep 17 00:00:00 2001
+From a48ba23bb4a24730fa49b5a10b56c9de873dea8a Mon Sep 17 00:00:00 2001
From: Nicholas Chin <nic.c3.14@gmail.com>
Date: Thu, 26 Sep 2024 19:48:26 -0600
-Subject: [PATCH 48/51] mb/dell: Convert E6400 into a variant
+Subject: [PATCH 20/37] mb/dell: Convert E6400 into a variant
All the GM45 Dell Latitudes should be nearly identical, so convert the
E6400 port into a variant so that future ports for the other systems can
diff --git a/config/coreboot/default/patches/0049-mb-dell-gm45_latitudes-Add-E4300-variant.patch b/config/coreboot/default/patches/0021-mb-dell-gm45_latitudes-Add-E4300-variant.patch
index 2cdcd499..af893982 100644
--- a/config/coreboot/default/patches/0049-mb-dell-gm45_latitudes-Add-E4300-variant.patch
+++ b/config/coreboot/default/patches/0021-mb-dell-gm45_latitudes-Add-E4300-variant.patch
@@ -1,7 +1,7 @@
-From ac8ac2543e3ebbc05f79f37d1460cde532a7ee1c Mon Sep 17 00:00:00 2001
+From b87e6774f0407ea48610c83ea54ab6a4b4a78a24 Mon Sep 17 00:00:00 2001
From: Nicholas Chin <nic.c3.14@gmail.com>
Date: Thu, 26 Sep 2024 19:51:25 -0600
-Subject: [PATCH 49/51] mb/dell/gm45_latitudes: Add E4300 variant
+Subject: [PATCH 21/37] mb/dell/gm45_latitudes: Add E4300 variant
Change-Id: I0f2059501b11be103187e3ce1a7c04ab85ae63d2
Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>
diff --git a/config/coreboot/default/patches/0050-mb-dell-Add-S3-SMI-handler-for-Dell-Latitudes.patch b/config/coreboot/default/patches/0022-mb-dell-Add-S3-SMI-handler-for-Dell-Latitudes.patch
index 71cc67c1..bbdce358 100644
--- a/config/coreboot/default/patches/0050-mb-dell-Add-S3-SMI-handler-for-Dell-Latitudes.patch
+++ b/config/coreboot/default/patches/0022-mb-dell-Add-S3-SMI-handler-for-Dell-Latitudes.patch
@@ -1,7 +1,7 @@
-From 5e8b899654c31fe771e4b1e96c74c93d4509c3b2 Mon Sep 17 00:00:00 2001
+From 0bc9ca409793836dcdb386db97b7a9464d92a973 Mon Sep 17 00:00:00 2001
From: Nicholas Chin <nic.c3.14@gmail.com>
Date: Fri, 3 May 2024 16:31:12 -0600
-Subject: [PATCH 50/51] mb/dell: Add S3 SMI handler for Dell Latitudes
+Subject: [PATCH 22/37] mb/dell: Add S3 SMI handler for Dell Latitudes
Integrate the previously added mec5035_smi_sleep() function into
mainboard code to fix S3 suspend on the SNB/IVB Latitudes and the E7240.
diff --git a/config/coreboot/default/patches/0051-ec-dell-mec5035-Route-power-button-event-to-host.patch b/config/coreboot/default/patches/0023-ec-dell-mec5035-Route-power-button-event-to-host.patch
index 65f90e2c..ab01c935 100644
--- a/config/coreboot/default/patches/0051-ec-dell-mec5035-Route-power-button-event-to-host.patch
+++ b/config/coreboot/default/patches/0023-ec-dell-mec5035-Route-power-button-event-to-host.patch
@@ -1,7 +1,7 @@
-From 1a342c20b8705bbea02d27a73e383ee2808f2558 Mon Sep 17 00:00:00 2001
+From d91dc168d6b8eca5e78aef9e48571d6edb156d45 Mon Sep 17 00:00:00 2001
From: Nicholas Chin <nic.c3.14@gmail.com>
Date: Tue, 18 Jun 2024 21:31:08 -0600
-Subject: [PATCH 51/51] ec/dell/mec5035: Route power button event to host
+Subject: [PATCH 23/37] ec/dell/mec5035: Route power button event to host
If command 0x3e with an argument of 1 isn't sent to the EC, pressing the
power button results in the EC powering off the system without letting
diff --git a/config/coreboot/default/patches/0052-Disable-compression-on-refcode-insertion.patch b/config/coreboot/default/patches/0024-Disable-compression-on-refcode-insertion.patch
index 1c089279..c557e9d7 100644
--- a/config/coreboot/default/patches/0052-Disable-compression-on-refcode-insertion.patch
+++ b/config/coreboot/default/patches/0024-Disable-compression-on-refcode-insertion.patch
@@ -1,7 +1,7 @@
-From 1e72e6df7f5d71fd41350e34d0a8bd5230349235 Mon Sep 17 00:00:00 2001
+From b6bd33b0430f72c2fce16a3b1e41927ef540923b Mon Sep 17 00:00:00 2001
From: Leah Rowe <info@minifree.org>
Date: Tue, 31 Dec 2024 14:42:24 +0000
-Subject: [PATCH 1/1] Disable compression on refcode insertion
+Subject: [PATCH 24/37] Disable compression on refcode insertion
Compression is not reliably reproducible. In an lbmk release
context, this means we cannot rely on vendorfile insertion.
@@ -14,10 +14,10 @@ Signed-off-by: Leah Rowe <info@minifree.org>
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile.mk b/Makefile.mk
-index e9ad2ccbb2..6a96d45a83 100644
+index 3969bfbd05..15346569f8 100644
--- a/Makefile.mk
+++ b/Makefile.mk
-@@ -1364,7 +1364,7 @@ endif
+@@ -1392,7 +1392,7 @@ endif
cbfs-files-$(CONFIG_HAVE_REFCODE_BLOB) += $(CONFIG_CBFS_PREFIX)/refcode
$(CONFIG_CBFS_PREFIX)/refcode-file := $(REFCODE_BLOB)
$(CONFIG_CBFS_PREFIX)/refcode-type := stage
diff --git a/config/coreboot/default/patches/0024-ec-dell-mec5035-Replace-defines-with-enums.patch b/config/coreboot/default/patches/0024-ec-dell-mec5035-Replace-defines-with-enums.patch
deleted file mode 100644
index 6c1118bb..00000000
--- a/config/coreboot/default/patches/0024-ec-dell-mec5035-Replace-defines-with-enums.patch
+++ /dev/null
@@ -1,91 +0,0 @@
-From a1566875789469ebd91e472301be4b359aac0a4c Mon Sep 17 00:00:00 2001
-From: Nicholas Chin <nic.c3.14@gmail.com>
-Date: Tue, 28 May 2024 17:23:21 -0600
-Subject: [PATCH 24/51] ec/dell/mec5035: Replace defines with enums
-
-Instead of using defines for command IDs and argument values, use enums
-to provide more type safety. This also has the effect of moving the
-command IDs to a more central location instead of defines spread out
-throughout the header.
-
-Change-Id: I788531e8b70e79541213853f177326d217235ef2
-Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>
-Reviewed-on: https://review.coreboot.org/c/coreboot/+/82998
-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
-Reviewed-by: Felix Singer <service+coreboot-gerrit@felixsinger.de>
----
- src/ec/dell/mec5035/mec5035.c | 10 +++++-----
- src/ec/dell/mec5035/mec5035.h | 20 ++++++++++++--------
- 2 files changed, 17 insertions(+), 13 deletions(-)
-
-diff --git a/src/ec/dell/mec5035/mec5035.c b/src/ec/dell/mec5035/mec5035.c
-index 68b6b2f7fb..dffbb7960c 100644
---- a/src/ec/dell/mec5035/mec5035.c
-+++ b/src/ec/dell/mec5035/mec5035.c
-@@ -66,17 +66,17 @@ static enum cb_err write_mailbox_regs(const u8 *data, u8 start, u8 count)
- return CB_SUCCESS;
- }
-
--static void ec_command(u8 cmd)
-+static void ec_command(enum mec5035_cmd cmd)
- {
- outb(0, MAILBOX_INDEX);
-- outb(cmd, MAILBOX_DATA);
-+ outb((u8)cmd, MAILBOX_DATA);
- wait_ec();
- }
-
--u8 mec5035_mouse_touchpad(u8 setting)
-+u8 mec5035_mouse_touchpad(enum ec_mouse_setting setting)
- {
-- u8 buf[15] = {0};
-- write_mailbox_regs(&setting, 2, 1);
-+ u8 buf[15] = {(u8)setting};
-+ write_mailbox_regs(buf, 2, 1);
- ec_command(CMD_MOUSE_TP);
- /* The vendor firmware reads 15 bytes starting at index 1, presumably
- to get some sort of return code. Though I don't know for sure if
-diff --git a/src/ec/dell/mec5035/mec5035.h b/src/ec/dell/mec5035/mec5035.h
-index fa15a9d621..32f791cb01 100644
---- a/src/ec/dell/mec5035/mec5035.h
-+++ b/src/ec/dell/mec5035/mec5035.h
-@@ -7,16 +7,20 @@
-
- #define NUM_REGISTERS 32
-
-+enum mec5035_cmd {
-+ CMD_MOUSE_TP = 0x1a,
-+ CMD_RADIO_CTRL = 0x2b,
-+ CMD_CPU_OK = 0xc2,
-+};
-+
- /* Touchpad (TP) and mouse related. The EC seems to
- default to 0 which results in the TP not working. */
--#define CMD_MOUSE_TP 0x1a
--#define SERIAL_MOUSE 0 /* Disable TP, force use of a serial mouse */
--#define PS2_MOUSE 1 /* Disable TP when using a PS/2 mouse */
--#define TP_PS2_MOUSE 2 /* Leave TP enabled when using a PS/2 mouse */
--
--#define CMD_CPU_OK 0xc2
-+enum ec_mouse_setting {
-+ SERIAL_MOUSE = 0, /* Disable TP, force use of a serial mouse */
-+ PS2_MOUSE, /* Disable TP when using a PS/2 mouse */
-+ TP_PS2_MOUSE /* Leave TP enabled when using a PS/2 mouse */
-+};
-
--#define CMD_RADIO_CTRL 0x2b
- #define RADIO_CTRL_NUM_ARGS 3
- enum ec_radio_dev {
- RADIO_WLAN = 0,
-@@ -29,7 +33,7 @@ enum ec_radio_state {
- RADIO_ON
- };
-
--u8 mec5035_mouse_touchpad(u8 setting);
-+u8 mec5035_mouse_touchpad(enum ec_mouse_setting setting);
- void mec5035_cpu_ok(void);
- void mec5035_early_init(void);
- void mec5035_control_radio(enum ec_radio_dev device, enum ec_radio_state state);
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0025-nb-intel-Disable-stack-overflow-debug-options.patch b/config/coreboot/default/patches/0025-nb-intel-Disable-stack-overflow-debug-options.patch
new file mode 100644
index 00000000..696be518
--- /dev/null
+++ b/config/coreboot/default/patches/0025-nb-intel-Disable-stack-overflow-debug-options.patch
@@ -0,0 +1,187 @@
+From fc4c65f3bb807b9fc766745a70f92729b0b8d99e Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Mon, 21 Apr 2025 02:58:47 +0100
+Subject: [PATCH 25/37] nb/intel/*: Disable stack overflow debug options
+
+Signed-off-by: Leah Rowe <leah@libreboot.org>
+---
+ src/northbridge/intel/e7505/Kconfig | 9 +++++++++
+ src/northbridge/intel/gm45/Kconfig | 9 +++++++++
+ src/northbridge/intel/haswell/Kconfig | 9 +++++++++
+ src/northbridge/intel/i440bx/Kconfig | 13 +++++++++++++
+ src/northbridge/intel/i945/Kconfig | 9 +++++++++
+ src/northbridge/intel/ironlake/Kconfig | 9 +++++++++
+ src/northbridge/intel/pineview/Kconfig | 9 +++++++++
+ src/northbridge/intel/sandybridge/Kconfig | 9 +++++++++
+ src/northbridge/intel/x4x/Kconfig | 9 +++++++++
+ 9 files changed, 85 insertions(+)
+
+diff --git a/src/northbridge/intel/e7505/Kconfig b/src/northbridge/intel/e7505/Kconfig
+index 039a7396f8..ddcb986f10 100644
+--- a/src/northbridge/intel/e7505/Kconfig
++++ b/src/northbridge/intel/e7505/Kconfig
+@@ -7,3 +7,12 @@ config NORTHBRIDGE_INTEL_E7505
+ select NO_CBFS_MCACHE
+ select SMM_TSEG
+ select NEED_SMALL_2MB_PAGE_TABLES
++
++# Override DEBUG Kconfig to avoid false alarm about stack overflow.
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS
++ bool
++ default n
++
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS_IN_ALL_STAGES
++ bool
++ default n
+diff --git a/src/northbridge/intel/gm45/Kconfig b/src/northbridge/intel/gm45/Kconfig
+index fc5df8b11a..95e3644b73 100644
+--- a/src/northbridge/intel/gm45/Kconfig
++++ b/src/northbridge/intel/gm45/Kconfig
+@@ -58,4 +58,13 @@ config FIXED_DMIBAR_MMIO_BASE
+ config FIXED_EPBAR_MMIO_BASE
+ default 0xfed19000
+
++# Override DEBUG Kconfig to avoid false alarm about stack overflow.
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS
++ bool
++ default n
++
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS_IN_ALL_STAGES
++ bool
++ default n
++
+ endif
+diff --git a/src/northbridge/intel/haswell/Kconfig b/src/northbridge/intel/haswell/Kconfig
+index 6191cb6ccf..0f5b5c7241 100644
+--- a/src/northbridge/intel/haswell/Kconfig
++++ b/src/northbridge/intel/haswell/Kconfig
+@@ -10,6 +10,15 @@ config NORTHBRIDGE_INTEL_HASWELL
+
+ if NORTHBRIDGE_INTEL_HASWELL
+
++# Override DEBUG Kconfig to avoid false alarm about stack overflow.
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS
++ bool
++ default n
++
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS_IN_ALL_STAGES
++ bool
++ default n
++
+ config USE_NATIVE_RAMINIT
+ bool "[NOT COMPLETE] Use native raminit"
+ default n
+diff --git a/src/northbridge/intel/i440bx/Kconfig b/src/northbridge/intel/i440bx/Kconfig
+index dbb2d7436b..5e9418b6a9 100644
+--- a/src/northbridge/intel/i440bx/Kconfig
++++ b/src/northbridge/intel/i440bx/Kconfig
+@@ -19,3 +19,16 @@ config SDRAMPWR_4DIMM
+ If your board has 4 DIMM slots, you must use select this option, in
+ your Kconfig file of the board. On boards with 3 DIMM slots,
+ do _not_ select this option.
++
++if NORTHBRIDGE_INTEL_I440BX
++
++# Override DEBUG Kconfig to avoid false alarm about stack overflow.
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS
++ bool
++ default n
++
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS_IN_ALL_STAGES
++ bool
++ default n
++
++endif
+diff --git a/src/northbridge/intel/i945/Kconfig b/src/northbridge/intel/i945/Kconfig
+index 32eff1a611..9479d75c07 100644
+--- a/src/northbridge/intel/i945/Kconfig
++++ b/src/northbridge/intel/i945/Kconfig
+@@ -89,4 +89,13 @@ config FIXED_DMIBAR_MMIO_BASE
+ config FIXED_EPBAR_MMIO_BASE
+ default 0xfed19000
+
++# Override DEBUG Kconfig to avoid false alarm about stack overflow.
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS
++ bool
++ default n
++
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS_IN_ALL_STAGES
++ bool
++ default n
++
+ endif
+diff --git a/src/northbridge/intel/ironlake/Kconfig b/src/northbridge/intel/ironlake/Kconfig
+index 2bafebf92e..16b81705bb 100644
+--- a/src/northbridge/intel/ironlake/Kconfig
++++ b/src/northbridge/intel/ironlake/Kconfig
+@@ -63,4 +63,13 @@ config FIXED_DMIBAR_MMIO_BASE
+ config FIXED_EPBAR_MMIO_BASE
+ default 0xfed19000
+
++# Override DEBUG Kconfig to avoid false alarm about stack overflow.
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS
++ bool
++ default n
++
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS_IN_ALL_STAGES
++ bool
++ default n
++
+ endif
+diff --git a/src/northbridge/intel/pineview/Kconfig b/src/northbridge/intel/pineview/Kconfig
+index 59cfcd5e0a..a3ad8d3425 100644
+--- a/src/northbridge/intel/pineview/Kconfig
++++ b/src/northbridge/intel/pineview/Kconfig
+@@ -42,4 +42,13 @@ config FIXED_EPBAR_MMIO_BASE
+ config DOMAIN_RESOURCE_32BIT_LIMIT
+ default 0xfec00000
+
++# Override DEBUG Kconfig to avoid false alarm about stack overflow.
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS
++ bool
++ default n
++
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS_IN_ALL_STAGES
++ bool
++ default n
++
+ endif
+diff --git a/src/northbridge/intel/sandybridge/Kconfig b/src/northbridge/intel/sandybridge/Kconfig
+index 973eed8bbd..6387cf926d 100644
+--- a/src/northbridge/intel/sandybridge/Kconfig
++++ b/src/northbridge/intel/sandybridge/Kconfig
+@@ -208,4 +208,13 @@ config IGD_DEFAULT_UMA_INDEX
+ default 2 if IGD_DEFAULT_UMA_SIZE_96MB
+ default 3 if IGD_DEFAULT_UMA_SIZE_128MB
+
++# Override DEBUG Kconfig to avoid false alarm about stack overflow.
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS
++ bool
++ default n
++
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS_IN_ALL_STAGES
++ bool
++ default n
++
+ endif
+diff --git a/src/northbridge/intel/x4x/Kconfig b/src/northbridge/intel/x4x/Kconfig
+index 6430319f6a..1803ef5733 100644
+--- a/src/northbridge/intel/x4x/Kconfig
++++ b/src/northbridge/intel/x4x/Kconfig
+@@ -53,4 +53,13 @@ config FIXED_DMIBAR_MMIO_BASE
+ config FIXED_EPBAR_MMIO_BASE
+ default 0xfed19000
+
++# Override DEBUG Kconfig to avoid false alarm about stack overflow.
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS
++ bool
++ default n
++
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS_IN_ALL_STAGES
++ bool
++ default n
++
+ endif
+--
+2.39.5
+
diff --git a/config/coreboot/default/patches/0026-soc-intel-skylake-configure-usb-acpi.patch b/config/coreboot/default/patches/0026-soc-intel-skylake-configure-usb-acpi.patch
new file mode 100644
index 00000000..c411c18b
--- /dev/null
+++ b/config/coreboot/default/patches/0026-soc-intel-skylake-configure-usb-acpi.patch
@@ -0,0 +1,94 @@
+From 14002b2575d73d3edbc72584502a463e6802cba6 Mon Sep 17 00:00:00 2001
+From: Felix Singer <felixsinger@posteo.net>
+Date: Wed, 26 Jun 2024 04:24:31 +0200
+Subject: [PATCH 26/37] soc/intel/skylake: configure usb acpi
+
+Change-Id: I53fc73046e4b107064fa8c3c617ba6d9b807b71d
+Signed-off-by: Felix Singer <felixsinger@posteo.net>
+---
+ src/soc/intel/skylake/Kconfig | 1 +
+ src/soc/intel/skylake/chipset.cb | 56 +++++++++++++++++++++++++++++++-
+ 2 files changed, 56 insertions(+), 1 deletion(-)
+
+diff --git a/src/soc/intel/skylake/Kconfig b/src/soc/intel/skylake/Kconfig
+index 4ad33496b2..9191ed0ff8 100644
+--- a/src/soc/intel/skylake/Kconfig
++++ b/src/soc/intel/skylake/Kconfig
+@@ -10,6 +10,7 @@ config SOC_INTEL_COMMON_SKYLAKE_BASE
+ select CPU_INTEL_COMMON
+ select CPU_INTEL_FIRMWARE_INTERFACE_TABLE
+ select CPU_SUPPORTS_PM_TIMER_EMULATION
++ select DRIVERS_USB_ACPI
+ select EDK2_CPU_TIMER_LIB if PAYLOAD_EDK2
+ select FSP_COMPRESS_FSP_S_LZ4
+ select FSP_M_XIP
+diff --git a/src/soc/intel/skylake/chipset.cb b/src/soc/intel/skylake/chipset.cb
+index 6538a1475b..dfb81d496e 100644
+--- a/src/soc/intel/skylake/chipset.cb
++++ b/src/soc/intel/skylake/chipset.cb
+@@ -13,7 +13,61 @@ chip soc/intel/skylake
+ device pci 07.0 alias chap off end
+ device pci 08.0 alias gmm off end # Gaussian Mixture Model
+ device pci 13.0 alias ish off end # SensorHub
+- device pci 14.0 alias south_xhci off ops usb_xhci_ops end
++ device pci 14.0 alias south_xhci off ops usb_xhci_ops
++ chip drivers/usb/acpi
++ register "type" = "UPC_TYPE_HUB"
++ device usb 0.0 alias xhci_root_hub off
++ chip drivers/usb/acpi
++ device usb 2.0 alias usb2_port1 off end
++ end
++ chip drivers/usb/acpi
++ device usb 2.1 alias usb2_port2 off end
++ end
++ chip drivers/usb/acpi
++ device usb 2.2 alias usb2_port3 off end
++ end
++ chip drivers/usb/acpi
++ device usb 2.3 alias usb2_port4 off end
++ end
++ chip drivers/usb/acpi
++ device usb 2.4 alias usb2_port5 off end
++ end
++ chip drivers/usb/acpi
++ device usb 2.5 alias usb2_port6 off end
++ end
++ chip drivers/usb/acpi
++ device usb 2.6 alias usb2_port7 off end
++ end
++ chip drivers/usb/acpi
++ device usb 2.7 alias usb2_port8 off end
++ end
++ chip drivers/usb/acpi
++ device usb 2.8 alias usb2_port9 off end
++ end
++ chip drivers/usb/acpi
++ device usb 2.9 alias usb2_port10 off end
++ end
++ chip drivers/usb/acpi
++ device usb 3.0 alias usb3_port1 off end
++ end
++ chip drivers/usb/acpi
++ device usb 3.1 alias usb3_port2 off end
++ end
++ chip drivers/usb/acpi
++ device usb 3.2 alias usb3_port3 off end
++ end
++ chip drivers/usb/acpi
++ device usb 3.3 alias usb3_port4 off end
++ end
++ chip drivers/usb/acpi
++ device usb 3.4 alias usb3_port5 off end
++ end
++ chip drivers/usb/acpi
++ device usb 3.5 alias usb3_port6 off end
++ end
++ end
++ end
++ end
+ device pci 14.1 alias south_xdci off ops usb_xdci_ops end
+ device pci 14.2 alias thermal off end
+ device pci 14.3 alias cio off end
+--
+2.39.5
+
diff --git a/config/coreboot/default/patches/0027-soc-intel-skylake-Enable-4E-4F-PNP-I-O-ports-in-boot.patch b/config/coreboot/default/patches/0027-soc-intel-skylake-Enable-4E-4F-PNP-I-O-ports-in-boot.patch
new file mode 100644
index 00000000..9d75cec6
--- /dev/null
+++ b/config/coreboot/default/patches/0027-soc-intel-skylake-Enable-4E-4F-PNP-I-O-ports-in-boot.patch
@@ -0,0 +1,30 @@
+From 3bb65b7f2a02ecb93e15ae037da38ad8f812747b Mon Sep 17 00:00:00 2001
+From: Mate Kukri <km@mkukri.xyz>
+Date: Fri, 22 Nov 2024 21:26:48 +0000
+Subject: [PATCH 27/37] soc/intel/skylake: Enable 4E/4F PNP I/O ports in
+ bootblock
+
+Change-Id: I57c9d8a9513a268e2ca6a0abd1306cd038598173
+Signed-off-by: Mate Kukri <km@mkukri.xyz>
+---
+ src/soc/intel/skylake/bootblock/pch.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/soc/intel/skylake/bootblock/pch.c b/src/soc/intel/skylake/bootblock/pch.c
+index df00bb85a9..beaece960b 100644
+--- a/src/soc/intel/skylake/bootblock/pch.c
++++ b/src/soc/intel/skylake/bootblock/pch.c
+@@ -100,8 +100,8 @@ static void soc_config_pwrmbase(void)
+
+ void pch_early_iorange_init(void)
+ {
+- uint16_t io_enables = LPC_IOE_SUPERIO_2E_2F | LPC_IOE_KBC_60_64 |
+- LPC_IOE_EC_62_66;
++ uint16_t io_enables = LPC_IOE_EC_4E_4F | LPC_IOE_SUPERIO_2E_2F |
++ LPC_IOE_KBC_60_64 | LPC_IOE_EC_62_66;
+
+ const config_t *config = config_of_soc();
+
+--
+2.39.5
+
diff --git a/config/coreboot/default/patches/0028-mb-lenovo-Add-ThinkPad-T480-and-ThinkPad-T480s.patch b/config/coreboot/default/patches/0028-mb-lenovo-Add-ThinkPad-T480-and-ThinkPad-T480s.patch
new file mode 100644
index 00000000..df71dc47
--- /dev/null
+++ b/config/coreboot/default/patches/0028-mb-lenovo-Add-ThinkPad-T480-and-ThinkPad-T480s.patch
@@ -0,0 +1,2232 @@
+From b515ba5b0cd02dc1771f27eaa716582b0827a638 Mon Sep 17 00:00:00 2001
+From: Mate Kukri <km@mkukri.xyz>
+Date: Tue, 31 Dec 2024 22:49:15 +0000
+Subject: [PATCH 28/37] mb/lenovo: Add ThinkPad T480 and ThinkPad T480s
+
+These machine have BootGuard fused and requires deguard to
+boot coreboot.
+
+Known issues:
+- Alpine Ridge Thunderbolt 3 controller does not work
+- Some Fn+F{1-12} keys aren't handled correctly
+- Nvidia dGPU is finicky
+ - Needs option ROM
+ - Power enable code is buggy
+ - Nouveau only works on linux 6.8-6.9
+- Headphone jack isn't detected as plugged in despite correct verbs
+
+Thanks to Leah Rowe for helping with the T480s.
+
+Signed-off-by: Mate Kukri <km@mkukri.xyz>
+Change-Id: I19d421412c771c1f242f6ff39453f824fa866163
+---
+ src/device/pci_rom.c | 4 +-
+ src/ec/lenovo/h8/acpi/ec.asl | 2 +-
+ src/ec/lenovo/h8/bluetooth.c | 6 +-
+ src/ec/lenovo/h8/wwan.c | 6 +-
+ src/mainboard/lenovo/sklkbl_thinkpad/Kconfig | 57 +++++
+ .../lenovo/sklkbl_thinkpad/Kconfig.name | 7 +
+ .../lenovo/sklkbl_thinkpad/Makefile.mk | 73 +++++++
+ .../lenovo/sklkbl_thinkpad/acpi/ec.asl | 12 ++
+ .../lenovo/sklkbl_thinkpad/acpi/superio.asl | 3 +
+ .../lenovo/sklkbl_thinkpad/bootblock.c | 60 ++++++
+ .../lenovo/sklkbl_thinkpad/devicetree.cb | 71 ++++++
+ src/mainboard/lenovo/sklkbl_thinkpad/dsdt.asl | 33 +++
+ src/mainboard/lenovo/sklkbl_thinkpad/ec.c | 153 +++++++++++++
+ src/mainboard/lenovo/sklkbl_thinkpad/ec.h | 99 +++++++++
+ src/mainboard/lenovo/sklkbl_thinkpad/gpio.h | 8 +
+ .../lenovo/sklkbl_thinkpad/ramstage.c | 105 +++++++++
+ .../sklkbl_thinkpad/variants/t480/data.vbt | Bin 0 -> 4106 bytes
+ .../variants/t480/gma-mainboard.ads | 19 ++
+ .../sklkbl_thinkpad/variants/t480/gpio.c | 203 ++++++++++++++++++
+ .../sklkbl_thinkpad/variants/t480/hda_verb.c | 90 ++++++++
+ .../variants/t480/memory_init_params.c | 20 ++
+ .../variants/t480/overridetree.cb | 103 +++++++++
+ .../sklkbl_thinkpad/variants/t480s/data.vbt | Bin 0 -> 4106 bytes
+ .../variants/t480s/gma-mainboard.ads | 19 ++
+ .../sklkbl_thinkpad/variants/t480s/gpio.c | 199 +++++++++++++++++
+ .../sklkbl_thinkpad/variants/t480s/hda_verb.c | 90 ++++++++
+ .../variants/t480s/memory_init_params.c | 44 ++++
+ .../variants/t480s/overridetree.cb | 103 +++++++++
+ .../variants/t480s/spd/spd_0.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_1.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_10.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_11.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_12.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_13.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_14.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_15.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_16.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_17.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_18.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_19.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_2.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_20.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_3.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_4.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_5.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_6.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_7.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_8.bin | Bin 0 -> 512 bytes
+ .../variants/t480s/spd/spd_9.bin | Bin 0 -> 512 bytes
+ 49 files changed, 1583 insertions(+), 6 deletions(-)
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/Kconfig
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/Kconfig.name
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/Makefile.mk
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/acpi/ec.asl
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/acpi/superio.asl
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/bootblock.c
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/devicetree.cb
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/dsdt.asl
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/ec.c
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/ec.h
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/gpio.h
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/ramstage.c
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/data.vbt
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/gma-mainboard.ads
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/gpio.c
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/hda_verb.c
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/memory_init_params.c
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/overridetree.cb
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/data.vbt
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/gma-mainboard.ads
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/gpio.c
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/hda_verb.c
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/memory_init_params.c
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/overridetree.cb
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_0.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_1.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_10.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_11.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_12.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_13.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_14.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_15.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_16.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_17.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_18.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_19.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_2.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_20.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_3.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_4.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_5.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_6.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_7.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_8.bin
+ create mode 100644 src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_9.bin
+
+diff --git a/src/device/pci_rom.c b/src/device/pci_rom.c
+index dc41ef14ce..bba98d9dea 100644
+--- a/src/device/pci_rom.c
++++ b/src/device/pci_rom.c
+@@ -396,14 +396,16 @@ void pci_rom_ssdt(const struct device *device)
+ rom = cbrom;
+ }
+
++#if 0
+ const char *scope = acpi_device_path(device);
+ if (!scope) {
+ printk(BIOS_ERR, "%s: Missing ACPI scope\n", dev_path(device));
+ return;
+ }
++#endif
+
+ /* write _ROM method */
+- acpigen_write_scope(scope);
++ acpigen_write_scope("\\_SB.PCI0.RP01.PEGP");
+ acpigen_write_rom((void *)rom, rom->size * 512);
+ acpigen_pop_len(); /* pop scope */
+ }
+diff --git a/src/ec/lenovo/h8/acpi/ec.asl b/src/ec/lenovo/h8/acpi/ec.asl
+index bc54d3b422..8f4a8e1986 100644
+--- a/src/ec/lenovo/h8/acpi/ec.asl
++++ b/src/ec/lenovo/h8/acpi/ec.asl
+@@ -331,7 +331,7 @@ Device(EC)
+ #include "sleepbutton.asl"
+ #include "lid.asl"
+ #include "beep.asl"
+-#include "thermal.asl"
++//#include "thermal.asl"
+ #include "systemstatus.asl"
+ #include "thinkpad.asl"
+ }
+diff --git a/src/ec/lenovo/h8/bluetooth.c b/src/ec/lenovo/h8/bluetooth.c
+index 16fc8dce39..be71a24ced 100644
+--- a/src/ec/lenovo/h8/bluetooth.c
++++ b/src/ec/lenovo/h8/bluetooth.c
+@@ -1,6 +1,6 @@
+ /* SPDX-License-Identifier: GPL-2.0-only */
+
+-#include <southbridge/intel/common/gpio.h>
++// #include <southbridge/intel/common/gpio.h>
+ #include <console/console.h>
+ #include <device/device.h>
+ #include <ec/acpi/ec.h>
+@@ -28,16 +28,18 @@ bool h8_has_bdc(const struct device *dev)
+ {
+ struct ec_lenovo_h8_config *conf = dev->chip_info;
+
+- if (!conf->has_bdc_detection) {
++ if (1 || !conf->has_bdc_detection) {
+ printk(BIOS_INFO, "H8: BDC detection not implemented. "
+ "Assuming BDC installed\n");
+ return true;
+ }
+
++#if 0
+ if (get_gpio(conf->bdc_gpio_num) == conf->bdc_gpio_lvl) {
+ printk(BIOS_INFO, "H8: BDC installed\n");
+ return true;
+ }
++#endif
+
+ printk(BIOS_INFO, "H8: BDC not installed\n");
+ return false;
+diff --git a/src/ec/lenovo/h8/wwan.c b/src/ec/lenovo/h8/wwan.c
+index 685886fcce..5cdcf77406 100644
+--- a/src/ec/lenovo/h8/wwan.c
++++ b/src/ec/lenovo/h8/wwan.c
+@@ -1,6 +1,6 @@
+ /* SPDX-License-Identifier: GPL-2.0-only */
+
+-#include <southbridge/intel/common/gpio.h>
++// #include <southbridge/intel/common/gpio.h>
+ #include <console/console.h>
+ #include <device/device.h>
+ #include <ec/acpi/ec.h>
+@@ -26,16 +26,18 @@ bool h8_has_wwan(const struct device *dev)
+ {
+ struct ec_lenovo_h8_config *conf = dev->chip_info;
+
+- if (!conf->has_wwan_detection) {
++ if (1 || !conf->has_wwan_detection) {
+ printk(BIOS_INFO, "H8: WWAN detection not implemented. "
+ "Assuming WWAN installed\n");
+ return true;
+ }
+
++#if 0
+ if (get_gpio(conf->wwan_gpio_num) == conf->wwan_gpio_lvl) {
+ printk(BIOS_INFO, "H8: WWAN installed\n");
+ return true;
+ }
++#endif
+
+ printk(BIOS_INFO, "H8: WWAN not installed\n");
+ return false;
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/Kconfig b/src/mainboard/lenovo/sklkbl_thinkpad/Kconfig
+new file mode 100644
+index 0000000000..4998672943
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/Kconfig
+@@ -0,0 +1,57 @@
++# SPDX-License-Identifier: GPL-2.0-only
++
++config BOARD_LENOVO_SKLKBL_THINKPAD_COMMON
++ bool
++ select BOARD_ROMSIZE_KB_16384
++ select EC_LENOVO_H8
++ select EC_LENOVO_PMH7
++ select H8_HAS_BAT_THRESHOLDS_IMPL
++ select H8_HAS_LEDLOGO
++ select H8_HAS_PRIMARY_FN_KEYS
++ select HAVE_ACPI_RESUME
++ select HAVE_ACPI_TABLES
++ select INTEL_GMA_HAVE_VBT
++ select INTEL_INT15
++ select MAINBOARD_HAS_LIBGFXINIT
++ select MAINBOARD_HAS_TPM2
++ select MAINBOARD_USES_IFD_GBE_REGION
++ select MEMORY_MAPPED_TPM
++ select SOC_INTEL_COMMON_BLOCK_HDA_VERB
++ select SOC_INTEL_KABYLAKE
++ select SPD_READ_BY_WORD
++ select SYSTEM_TYPE_LAPTOP
++
++config BOARD_LENOVO_T480
++ bool
++ select BOARD_LENOVO_SKLKBL_THINKPAD_COMMON
++
++config BOARD_LENOVO_T480S
++ bool
++ select BOARD_LENOVO_SKLKBL_THINKPAD_COMMON
++
++if BOARD_LENOVO_SKLKBL_THINKPAD_COMMON
++
++config MAINBOARD_DIR
++ default "lenovo/sklkbl_thinkpad"
++
++config VARIANT_DIR
++ default "t480" if BOARD_LENOVO_T480
++ default "t480s" if BOARD_LENOVO_T480S
++
++config OVERRIDE_DEVICETREE
++ default "variants/\$(CONFIG_VARIANT_DIR)/overridetree.cb"
++
++config MAINBOARD_PART_NUMBER
++ default "T480" if BOARD_LENOVO_T480
++ default "T480s" if BOARD_LENOVO_T480S
++
++config CBFS_SIZE
++ default 0x900000
++
++config DIMM_MAX
++ default 2
++
++config DIMM_SPD_SIZE
++ default 512 # DDR4
++
++endif
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/Kconfig.name b/src/mainboard/lenovo/sklkbl_thinkpad/Kconfig.name
+new file mode 100644
+index 0000000000..abc273f387
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/Kconfig.name
+@@ -0,0 +1,7 @@
++# SPDX-License-Identifier: GPL-2.0-only
++
++config BOARD_LENOVO_T480
++ bool "ThinkPad T480"
++
++config BOARD_LENOVO_T480S
++ bool "ThinkPad T480s"
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/Makefile.mk b/src/mainboard/lenovo/sklkbl_thinkpad/Makefile.mk
+new file mode 100644
+index 0000000000..c308239177
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/Makefile.mk
+@@ -0,0 +1,73 @@
++## SPDX-License-Identifier: GPL-2.0-only
++
++bootblock-y += bootblock.c ec.c
++
++romstage-y += variants/$(VARIANT_DIR)/memory_init_params.c
++
++ramstage-y += ramstage.c ec.c
++ramstage-y += variants/$(VARIANT_DIR)/gpio.c variants/$(VARIANT_DIR)/hda_verb.c
++ramstage-$(CONFIG_MAINBOARD_USE_LIBGFXINIT) += variants/$(VARIANT_DIR)/gma-mainboard.ads
++
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_0.bin
++spd_0.bin-file := variants/$(VARIANT_DIR)/spd/spd_0.bin
++spd_0.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_1.bin
++spd_1.bin-file := variants/$(VARIANT_DIR)/spd/spd_1.bin
++spd_1.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_2.bin
++spd_2.bin-file := variants/$(VARIANT_DIR)/spd/spd_2.bin
++spd_2.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_3.bin
++spd_3.bin-file := variants/$(VARIANT_DIR)/spd/spd_3.bin
++spd_3.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_4.bin
++spd_4.bin-file := variants/$(VARIANT_DIR)/spd/spd_4.bin
++spd_4.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_5.bin
++spd_5.bin-file := variants/$(VARIANT_DIR)/spd/spd_5.bin
++spd_5.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_6.bin
++spd_6.bin-file := variants/$(VARIANT_DIR)/spd/spd_6.bin
++spd_6.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_7.bin
++spd_7.bin-file := variants/$(VARIANT_DIR)/spd/spd_7.bin
++spd_7.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_8.bin
++spd_8.bin-file := variants/$(VARIANT_DIR)/spd/spd_8.bin
++spd_8.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_9.bin
++spd_9.bin-file := variants/$(VARIANT_DIR)/spd/spd_9.bin
++spd_9.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_10.bin
++spd_10.bin-file := variants/$(VARIANT_DIR)/spd/spd_10.bin
++spd_10.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_11.bin
++spd_11.bin-file := variants/$(VARIANT_DIR)/spd/spd_11.bin
++spd_11.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_12.bin
++spd_12.bin-file := variants/$(VARIANT_DIR)/spd/spd_12.bin
++spd_12.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_13.bin
++spd_13.bin-file := variants/$(VARIANT_DIR)/spd/spd_13.bin
++spd_13.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_14.bin
++spd_14.bin-file := variants/$(VARIANT_DIR)/spd/spd_14.bin
++spd_14.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_15.bin
++spd_15.bin-file := variants/$(VARIANT_DIR)/spd/spd_15.bin
++spd_15.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_16.bin
++spd_16.bin-file := variants/$(VARIANT_DIR)/spd/spd_16.bin
++spd_16.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_17.bin
++spd_17.bin-file := variants/$(VARIANT_DIR)/spd/spd_17.bin
++spd_17.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_18.bin
++spd_18.bin-file := variants/$(VARIANT_DIR)/spd/spd_18.bin
++spd_18.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_19.bin
++spd_19.bin-file := variants/$(VARIANT_DIR)/spd/spd_19.bin
++spd_19.bin-type := raw
++cbfs-files-$(CONFIG_BOARD_LENOVO_T480S) += spd_20.bin
++spd_20.bin-file := variants/$(VARIANT_DIR)/spd/spd_20.bin
++spd_20.bin-type := raw
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/acpi/ec.asl b/src/mainboard/lenovo/sklkbl_thinkpad/acpi/ec.asl
+new file mode 100644
+index 0000000000..3a949a2fca
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/acpi/ec.asl
+@@ -0,0 +1,12 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#define BRIGHTNESS_UP \_SB.PCI0.GFX0.INCB
++#define BRIGHTNESS_DOWN \_SB.PCI0.GFX0.DECB
++#define THINKPAD_EC_GPE 22
++
++Name(\TCRT, 100)
++Name(\TPSV, 90)
++Name(\FLVL, 0)
++
++#include <ec/lenovo/h8/acpi/ec.asl>
++#include <ec/lenovo/h8/acpi/thinkpad_bat_thresholds_b0.asl>
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/acpi/superio.asl b/src/mainboard/lenovo/sklkbl_thinkpad/acpi/superio.asl
+new file mode 100644
+index 0000000000..55b1db5b11
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/acpi/superio.asl
+@@ -0,0 +1,3 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#include <drivers/pc80/pc/ps2_controller.asl>
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/bootblock.c b/src/mainboard/lenovo/sklkbl_thinkpad/bootblock.c
+new file mode 100644
+index 0000000000..fb660dbdfa
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/bootblock.c
+@@ -0,0 +1,60 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#include <arch/io.h>
++#include <bootblock_common.h>
++#include <device/pci.h>
++#include <soc/pci_devs.h>
++#include "ec.h"
++
++static void configure_uart(uint16_t port, uint16_t iobase, uint8_t irqno)
++{
++ microchip_pnp_enter_conf_state(port);
++
++ // Select LPC I/F LDN
++ pnp_write(port, PNP_LDN_SELECT, LDN_LPCIF);
++ // Write UART BAR
++ pnp_write_le32(port, LPCIF_BAR_UART, (uint32_t) iobase << 16 | 0x8707);
++ // Set SIRQ4 to UART
++ pnp_write(port, LPCIF_SIRQ(irqno), LDN_UART);
++
++ // Configure UART LDN
++ pnp_write(port, PNP_LDN_SELECT, LDN_UART);
++ pnp_write(port, UART_ACTIVATE, 0x01);
++ pnp_write(port, UART_CONFIG_SELECT, 0x00);
++
++ microchip_pnp_exit_conf_state(port);
++
++#ifdef CONFIG_BOARD_LENOVO_T480
++ // Supply debug unlock key
++ debug_write_key(DEBUG_RW_KEY_IDX, debug_rw_key);
++
++ // Use debug writes to set UART_TX and UART_RX GPIOs
++ debug_write_dword(0xf0c400 + 0x110, 0x00001000);
++ debug_write_dword(0xf0c400 + 0x114, 0x00001000);
++#endif
++}
++
++
++#define UART_PORT 0x3f8
++#define UART_IRQ 4
++
++void bootblock_mainboard_early_init(void)
++{
++ // Tell EC via BIOS Debug Port 1 that the world isn't on fire
++
++ // Let the EC know that BIOS code is running
++ outb(0x11, 0x86);
++ outb(0x6e, 0x86);
++
++ // Enable accesses to EC1 interface
++ ec0_write(0, ec0_read(0) | 0x20);
++
++ // Reset LEDs to power on state
++ // (Without this warm reboot leaves LEDs off)
++ ec0_write(0x0c, 0x80);
++ ec0_write(0x0c, 0x07);
++ ec0_write(0x0c, 0x8a);
++
++ // Setup debug UART
++ configure_uart(EC_CFG_PORT, UART_PORT, UART_IRQ);
++}
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/devicetree.cb b/src/mainboard/lenovo/sklkbl_thinkpad/devicetree.cb
+new file mode 100644
+index 0000000000..c07d4d53ca
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/devicetree.cb
+@@ -0,0 +1,71 @@
++# SPDX-License-Identifier: GPL-2.0-only
++
++chip soc/intel/skylake
++ # IGD Displays
++ register "gfx" = "GMA_STATIC_DISPLAYS(0)"
++
++ register "panel_cfg" = "{
++ .up_delay_ms = 200,
++ .down_delay_ms = 50,
++ .cycle_delay_ms = 600,
++ .backlight_on_delay_ms = 1,
++ .backlight_off_delay_ms = 200,
++ .backlight_pwm_hz = 200,
++ }"
++
++ # Power
++ register "PmConfigSlpS3MinAssert" = "2" # 50ms
++ register "PmConfigSlpS4MinAssert" = "1" # 1s
++ register "PmConfigSlpSusMinAssert" = "3" # 500ms
++ register "PmConfigSlpAMinAssert" = "3" # 2s
++
++ device domain 0 on
++ device ref igpu on end
++ device ref sa_thermal on end
++ device ref thermal on end
++ device ref south_xhci on end
++ device ref lpc_espi on
++ register "serirq_mode" = "SERIRQ_CONTINUOUS"
++
++ register "gen1_dec" = "0x007c1601"
++ register "gen2_dec" = "0x000c15e1"
++
++ chip ec/lenovo/pmh7
++ register "backlight_enable" = "true"
++ register "dock_event_enable" = "true"
++ device pnp ff.1 on end # dummy
++ end
++
++ chip ec/lenovo/h8
++ register "beepmask0" = "0x00"
++ register "beepmask1" = "0x86"
++ register "config0" = "0xa6"
++ register "config1" = "0x0d"
++ register "config2" = "0xa8"
++ register "config3" = "0xc4"
++ register "has_keyboard_backlight" = "1"
++ register "event2_enable" = "0xff"
++ register "event3_enable" = "0xff"
++ register "event4_enable" = "0xd0"
++ register "event5_enable" = "0x3c"
++ register "event7_enable" = "0x01"
++ register "event8_enable" = "0x7b"
++ register "event9_enable" = "0xff"
++ register "eventc_enable" = "0xff"
++ register "eventd_enable" = "0xff"
++ register "evente_enable" = "0x9d"
++ device pnp ff.2 on # dummy
++ io 0x60 = 0x62
++ io 0x62 = 0x66
++ io 0x64 = 0x1600
++ io 0x66 = 0x1604
++ end
++ end
++
++ chip drivers/pc80/tpm
++ device pnp 0c31.0 on end
++ end
++ end
++ device ref hda on end
++ end
++end
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/dsdt.asl b/src/mainboard/lenovo/sklkbl_thinkpad/dsdt.asl
+new file mode 100644
+index 0000000000..aa4d4de2a6
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/dsdt.asl
+@@ -0,0 +1,33 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#include <acpi/acpi.h>
++DefinitionBlock(
++ "dsdt.aml",
++ "DSDT",
++ ACPI_DSDT_REV_2,
++ OEM_ID,
++ ACPI_TABLE_CREATOR,
++ 0x20110725
++)
++{
++ #include <acpi/dsdt_top.asl>
++ #include <soc/intel/common/block/acpi/acpi/globalnvs.asl>
++ #include <cpu/intel/common/acpi/cpu.asl>
++
++ Device (\_SB.PCI0)
++ {
++ #include <soc/intel/skylake/acpi/systemagent.asl>
++ #include <soc/intel/skylake/acpi/pch.asl>
++ #include <drivers/intel/gma/acpi/default_brightness_levels.asl>
++ }
++
++ Scope (\_SB.PCI0.RP01)
++ {
++ Device (PEGP)
++ {
++ Name (_ADR, Zero)
++ }
++ }
++
++ #include <southbridge/intel/common/acpi/sleepstates.asl>
++}
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/ec.c b/src/mainboard/lenovo/sklkbl_thinkpad/ec.c
+new file mode 100644
+index 0000000000..adb6a60324
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/ec.c
+@@ -0,0 +1,153 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#include <arch/io.h>
++#include "ec.h"
++
++#define MICROCHIP_CONFIGURATION_ENTRY_KEY 0x55
++#define MICROCHIP_CONFIGURATION_EXIT_KEY 0xaa
++
++void microchip_pnp_enter_conf_state(uint16_t port)
++{
++ outb(MICROCHIP_CONFIGURATION_ENTRY_KEY, port);
++}
++
++void microchip_pnp_exit_conf_state(uint16_t port)
++{
++ outb(MICROCHIP_CONFIGURATION_EXIT_KEY, port);
++}
++
++uint8_t pnp_read(uint16_t port, uint8_t index)
++{
++ outb(index, port);
++ return inb(port + 1);
++}
++
++uint32_t pnp_read_le32(uint16_t port, uint8_t index)
++{
++ return (uint32_t) pnp_read(port, index) |
++ (uint32_t) pnp_read(port, index + 1) << 8 |
++ (uint32_t) pnp_read(port, index + 2) << 16 |
++ (uint32_t) pnp_read(port, index + 3) << 24;
++}
++
++void pnp_write(uint16_t port, uint8_t index, uint8_t value)
++{
++ outb(index, port);
++ outb(value, port + 1);
++}
++
++void pnp_write_le32(uint16_t port, uint8_t index, uint32_t value)
++{
++ pnp_write(port, index, value & 0xff);
++ pnp_write(port, index + 1, value >> 8 & 0xff);
++ pnp_write(port, index + 2, value >> 16 & 0xff);
++ pnp_write(port, index + 3, value >> 24 & 0xff);
++}
++
++static void ecN_clear_out_queue(uint16_t cmd_port, uint16_t data_port)
++{
++ while (inb(cmd_port) & EC_OBF)
++ inb(data_port);
++}
++
++static void ecN_wait_to_send(uint16_t cmd_port, uint16_t data_port)
++{
++ while (inb(cmd_port) & EC_IBF)
++ ;
++}
++
++static void ecN_wait_to_recv(uint16_t cmd_port, uint16_t data_port)
++{
++ while (!(inb(cmd_port) & EC_OBF))
++ ;
++}
++
++uint8_t ecN_read(uint16_t cmd_port, uint16_t data_port, uint8_t addr)
++{
++ ecN_clear_out_queue(cmd_port, data_port);
++ ecN_wait_to_send(cmd_port, data_port);
++ outb(EC_READ, cmd_port);
++ ecN_wait_to_send(cmd_port, data_port);
++ outb(addr, data_port);
++ ecN_wait_to_recv(cmd_port, data_port);
++ return inb(data_port);
++}
++
++void ecN_write(uint16_t cmd_port, uint16_t data_port, uint8_t addr, uint8_t val)
++{
++ ecN_clear_out_queue(cmd_port, data_port);
++ ecN_wait_to_send(cmd_port, data_port);
++ outb(EC_WRITE, cmd_port);
++ ecN_wait_to_send(cmd_port, data_port);
++ outb(addr, data_port);
++ ecN_wait_to_send(cmd_port, data_port);
++ outb(val, data_port);
++}
++
++uint8_t eeprom_read(uint16_t addr)
++{
++ ecN_clear_out_queue(EC2_CMD, EC2_DATA);
++ ecN_wait_to_send(EC2_CMD, EC2_DATA);
++ outl(1, EC2_CMD);
++ ecN_wait_to_send(EC2_CMD, EC2_DATA);
++ outl(addr, EC2_DATA);
++ ecN_wait_to_recv(EC2_CMD, EC2_DATA);
++ return inl(EC2_DATA);
++}
++
++void eeprom_write(uint16_t addr, uint8_t val)
++{
++ ecN_clear_out_queue(EC2_CMD, EC2_DATA);
++ ecN_wait_to_send(EC2_CMD, EC2_DATA);
++ outl(2, EC2_CMD);
++ ecN_wait_to_send(EC2_CMD, EC2_DATA);
++ outl((uint32_t) addr | (uint32_t) val << 16, EC2_DATA);
++ ecN_wait_to_recv(EC2_CMD, EC2_DATA);
++ inl(EC2_DATA);
++}
++
++uint16_t debug_loaded_keys(void)
++{
++ return (uint16_t) ec0_read(0x87) << 8 | (uint16_t) ec0_read(0x86);
++}
++
++static void debug_cmd(uint8_t cmd)
++{
++ ec0_write(EC_DEBUG_CMD, cmd);
++ while (ec0_read(EC_DEBUG_CMD) & 0x80)
++ ;
++}
++
++void debug_read_key(uint8_t i, uint8_t *key)
++{
++ debug_cmd(0x80 | (i & 0xf));
++ for (int j = 0; j < 8; ++j)
++ key[j] = ec0_read(0x3e + j);
++}
++
++void debug_write_key(uint8_t i, const uint8_t *key)
++{
++ for (int j = 0; j < 8; ++j)
++ ec0_write(0x3e + j, key[j]);
++ debug_cmd(0xc0 | (i & 0xf));
++}
++
++uint32_t debug_read_dword(uint32_t addr)
++{
++ ecN_clear_out_queue(EC3_CMD, EC3_DATA);
++ ecN_wait_to_send(EC3_CMD, EC3_DATA);
++ outl(addr << 8 | 0xE2, EC3_DATA);
++ ecN_wait_to_recv(EC3_CMD, EC3_DATA);
++ return inl(EC3_DATA);
++}
++
++void debug_write_dword(uint32_t addr, uint32_t val)
++{
++ ecN_clear_out_queue(EC3_CMD, EC3_DATA);
++ ecN_wait_to_send(EC3_CMD, EC3_DATA);
++ outl(addr << 8 | 0xEA, EC3_DATA);
++ ecN_wait_to_send(EC3_CMD, EC3_DATA);
++ outl(val, EC3_DATA);
++}
++
++const uint8_t debug_rw_key[8] = { 0x7a, 0x41, 0xb1, 0x49, 0xfe, 0x21, 0x01, 0xcf };
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/ec.h b/src/mainboard/lenovo/sklkbl_thinkpad/ec.h
+new file mode 100644
+index 0000000000..d2963c8962
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/ec.h
+@@ -0,0 +1,99 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#ifndef SKLKBL_THINKPAD_EC_H
++#define SKLKBL_THINKPAD_EC_H
++
++// EC configuration base address
++#define EC_CFG_PORT 0x4e
++
++// Chip global registers
++#define PNP_LDN_SELECT 0x07
++# define LDN_UART 0x07
++# define LDN_LPCIF 0x0c
++#define EC_DEVICE_ID 0x20
++#define EC_DEVICE_REV 0x21
++
++// LPC I/F registers
++#define LPCIF_SIRQ(i) (0x40 + (i))
++
++#define LPCIF_BAR_CFG 0x60
++#define LPCIF_BAR_MAILBOX 0x64
++#define LPCIF_BAR_8042 0x68
++#define LPCIF_BAR_ACPI_EC0 0x6c
++#define LPCIF_BAR_ACPI_EC1 0x70
++#define LPCIF_BAR_ACPI_EC2 0x74
++#define LPCIF_BAR_ACPI_EC3 0x78
++#define LPCIF_BAR_ACPI_PM0 0x7c
++#define LPCIF_BAR_UART 0x80
++#define LPCIF_BAR_FAST_KYBD 0x84
++#define LPCIF_BAR_EMBED_FLASH 0x88
++#define LPCIF_BAR_GP_SPI 0x8c
++#define LPCIF_BAR_EMI 0x90
++#define LPCIF_BAR_PMH7 0x94
++#define LPCIF_BAR_PORT80_DBG0 0x98
++#define LPCIF_BAR_PORT80_DBG1 0x9c
++#define LPCIF_BAR_RTC 0xa0
++
++// UART registers
++#define UART_ACTIVATE 0x30
++#define UART_CONFIG_SELECT 0xf0
++
++void microchip_pnp_enter_conf_state(uint16_t port);
++void microchip_pnp_exit_conf_state(uint16_t port);
++uint8_t pnp_read(uint16_t port, uint8_t index);
++uint32_t pnp_read_le32(uint16_t port, uint8_t index);
++void pnp_write(uint16_t port, uint8_t index, uint8_t value);
++void pnp_write_le32(uint16_t port, uint8_t index, uint32_t value);
++
++#define EC0_CMD 0x0066
++#define EC0_DATA 0x0062
++#define EC1_CMD 0x1604
++#define EC1_DATA 0x1600
++#define EC2_CMD 0x1634
++#define EC2_DATA 0x1630
++#define EC3_CMD 0x161c
++#define EC3_DATA 0x1618
++
++#define EC_OBF (1 << 0)
++#define EC_IBF (1 << 1)
++
++#define EC_READ 0x80
++#define EC_WRITE 0x81
++
++uint8_t ecN_read(uint16_t cmd_port, uint16_t data_port, uint8_t addr);
++
++void ecN_write(uint16_t cmd_port, uint16_t data_port, uint8_t addr, uint8_t val);
++
++// EC0 and EC1 mostly are useful with the READ/WRITE commands
++#define ec0_read(addr) ecN_read(EC0_CMD, EC0_DATA, addr)
++#define ec0_write(addr, val) ecN_write(EC0_CMD, EC0_DATA, addr, val)
++#define ec1_read(addr) ecN_read(EC1_CMD, EC1_DATA, addr)
++#define ec1_write(addr, val) ecN_write(EC1_CMD, EC1_DATA, addr, val)
++
++// Read from the emulated EEPROM
++uint8_t eeprom_read(uint16_t addr);
++
++// Write to the emulated EEPROM
++void eeprom_write(uint16_t addr, uint8_t val);
++
++// Read loaded debug key mask
++uint16_t debug_loaded_keys(void);
++
++// The following location (via either EC0 or EC1) can be used to interact with the debug interface
++#define EC_DEBUG_CMD 0x3d
++
++void debug_read_key(uint8_t i, uint8_t *key);
++
++void debug_write_key(uint8_t i, const uint8_t *key);
++
++uint32_t debug_read_dword(uint32_t addr);
++
++void debug_write_dword(uint32_t addr, uint32_t val);
++
++// RW unlock key index
++#define DEBUG_RW_KEY_IDX 1
++
++// RW unlock key for EC version N24HT37W
++extern const uint8_t debug_rw_key[8];
++
++#endif
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/gpio.h b/src/mainboard/lenovo/sklkbl_thinkpad/gpio.h
+new file mode 100644
+index 0000000000..d89ed712d4
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/gpio.h
+@@ -0,0 +1,8 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#ifndef GPIO_H
++#define GPIO_H
++
++void variant_config_gpios(void);
++
++#endif
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/ramstage.c b/src/mainboard/lenovo/sklkbl_thinkpad/ramstage.c
+new file mode 100644
+index 0000000000..44c8578852
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/ramstage.c
+@@ -0,0 +1,105 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#include <arch/io.h>
++#include <device/device.h>
++#include <drivers/intel/gma/int15.h>
++#include <option.h>
++#include <soc/ramstage.h>
++#include "ec.h"
++#include "gpio.h"
++
++#define GPIO_GPU_RST GPP_E22 // active low
++#define GPIO_1R8VIDEO_AON_ON GPP_E23
++
++#define GPIO_DGFX_PWRGD GPP_F3
++
++#define GPIO_DISCRETE_PRESENCE GPP_D9 // active low
++#define GPIO_DGFX_VRAM_ID0 GPP_D11
++#define GPIO_DGFX_VRAM_ID1 GPP_D12
++
++void mainboard_silicon_init_params(FSP_SIL_UPD *params)
++{
++ static const char * const dgfx_vram_id_str[] = { "1GB", "2GB", "4GB", "N/A" };
++
++ int dgfx_vram_id;
++
++ // Setup GPIOs
++ variant_config_gpios();
++
++ // Detect and enable dGPU
++ if (gpio_get(GPIO_DISCRETE_PRESENCE) == 0) { // active low
++ dgfx_vram_id = gpio_get(GPIO_DGFX_VRAM_ID0) | gpio_get(GPIO_DGFX_VRAM_ID1) << 1;
++ printk(BIOS_DEBUG, "Discrete GPU present with %s VRAM\n", dgfx_vram_id_str[dgfx_vram_id]);
++
++ // NOTE: i pulled this GPU enable sequence from thin air
++ // it sometimes works but is buggy and the GPU disappears in some cases so disabling it by default.
++ // also unrelated to this enable sequence the nouveau driver only works on 6.8-6.9 kernels
++ if (get_uint_option("dgpu_enable", 0)) {
++ printk(BIOS_DEBUG, "Enabling discrete GPU\n");
++ gpio_set(GPIO_1R8VIDEO_AON_ON, 1); // Enable GPU power rail
++ while (!gpio_get(GPIO_DGFX_PWRGD)) // Wait for power good signal from GPU
++ ;
++ gpio_set(GPIO_GPU_RST, 1); // Release GPU from reset
++ } else {
++ printk(BIOS_DEBUG, "Discrete GPU will remain disabled\n");
++ }
++
++ } else {
++ printk(BIOS_DEBUG, "Discrete GPU not present\n");
++ }
++}
++
++static void dump_ec_cfg(uint16_t port)
++{
++ microchip_pnp_enter_conf_state(port);
++
++ // Device info
++ printk(BIOS_DEBUG, "Device id %02x\n", pnp_read(port, EC_DEVICE_ID));
++ printk(BIOS_DEBUG, "Device rev %02x\n", pnp_read(port, EC_DEVICE_REV));
++
++ // Switch to LPCIF LDN
++ pnp_write(port, PNP_LDN_SELECT, LDN_LPCIF);
++
++ // Dump SIRQs
++ for (int i = 0; i <= 15; i += 1)
++ printk(BIOS_DEBUG, "SIRQ%d = %02x\n", i, pnp_read(port, LPCIF_SIRQ(i)));
++
++ // Dump BARs
++ printk(BIOS_DEBUG, "BAR CFG = %08x\n", pnp_read_le32(port, LPCIF_BAR_CFG));
++ printk(BIOS_DEBUG, "BAR MAILBOX = %08x\n", pnp_read_le32(port, LPCIF_BAR_MAILBOX));
++ printk(BIOS_DEBUG, "BAR 8042 = %08x\n", pnp_read_le32(port, LPCIF_BAR_8042));
++ printk(BIOS_DEBUG, "BAR ACPI_EC0 = %08x\n", pnp_read_le32(port, LPCIF_BAR_ACPI_EC0));
++ printk(BIOS_DEBUG, "BAR ACPI_EC1 = %08x\n", pnp_read_le32(port, LPCIF_BAR_ACPI_EC1));
++ printk(BIOS_DEBUG, "BAR ACPI_EC2 = %08x\n", pnp_read_le32(port, LPCIF_BAR_ACPI_EC2));
++ printk(BIOS_DEBUG, "BAR ACPI_EC3 = %08x\n", pnp_read_le32(port, LPCIF_BAR_ACPI_EC3));
++ printk(BIOS_DEBUG, "BAR ACPI_PM0 = %08x\n", pnp_read_le32(port, LPCIF_BAR_ACPI_PM0));
++ printk(BIOS_DEBUG, "BAR UART = %08x\n", pnp_read_le32(port, LPCIF_BAR_UART));
++ printk(BIOS_DEBUG, "BAR FAST_KYBD = %08x\n", pnp_read_le32(port, LPCIF_BAR_FAST_KYBD));
++ printk(BIOS_DEBUG, "BAR EMBED_FLASH = %08x\n", pnp_read_le32(port, LPCIF_BAR_EMBED_FLASH));
++ printk(BIOS_DEBUG, "BAR GP_SPI = %08x\n", pnp_read_le32(port, LPCIF_BAR_GP_SPI));
++ printk(BIOS_DEBUG, "BAR EMI = %08x\n", pnp_read_le32(port, LPCIF_BAR_EMI));
++ printk(BIOS_DEBUG, "BAR PMH7 = %08x\n", pnp_read_le32(port, LPCIF_BAR_PMH7));
++ printk(BIOS_DEBUG, "BAR PORT80_DBG0 = %08x\n", pnp_read_le32(port, LPCIF_BAR_PORT80_DBG0));
++ printk(BIOS_DEBUG, "BAR PORT80_DBG1 = %08x\n", pnp_read_le32(port, LPCIF_BAR_PORT80_DBG1));
++ printk(BIOS_DEBUG, "BAR RTC = %08x\n", pnp_read_le32(port, LPCIF_BAR_RTC));
++
++ microchip_pnp_exit_conf_state(port);
++}
++
++static void mainboard_enable(struct device *dev)
++{
++ if (CONFIG(VGA_ROM_RUN))
++ install_intel_vga_int15_handler(GMA_INT15_ACTIVE_LFP_EDP,
++ GMA_INT15_PANEL_FIT_DEFAULT,
++ GMA_INT15_BOOT_DISPLAY_DEFAULT, 0);
++}
++
++static void mainboard_init(void *chip_info)
++{
++ dump_ec_cfg(EC_CFG_PORT);
++}
++
++struct chip_operations mainboard_ops = {
++ .enable_dev = mainboard_enable,
++ .init = mainboard_init,
++};
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/data.vbt b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/data.vbt
+new file mode 100644
+index 0000000000000000000000000000000000000000..4db4202961d0be67b75f52b28f2111d5655595c3
+GIT binary patch
+literal 4106
+zcmeHJU2GIp6h5=FKeKmc=rAo()>4l^U|XP_ZDGYy!|YE>mu}hZ4|PdQy1<TF-O}0?
+zDF)LeX(GlTYoZ2xkUp4bc(Fbi;|s>bV0gipVB&+pHzmFpc`=IXxii}qiqH*)7}PU+
+z?woV)x!<09?wNbfhQa6n_IK}3M!Gw&OgS)sY2Q$LJ4F+z{-JneATkt9refXr6+8sr
+zR{e1eASVcGl#mf_O&p%I^1;3af=xDeN0ZnydT=;zHOH-q=O;(UFda)^<j^52Z;c<A
+zv~t)#xI2OzS7p&7!}%QUJu-688gD}mM%EbG*3`NU(Fiq%!p$v4=y8%;+qQ?>LXW8|
+z-Vsanq!Y==Kq9plQ+*gu^hf&pJ9?tY{h01cbtR&SfsVM!_*!D4W5>papLuo?gRur|
+zF$`lX;f2t48Dpd4V@(*z=dq95OkkfiVU53N<(gE+=U)KHEdU4}@R=aMjTTTOcb8-a
+zC9IXSxZB*|#u~SlHnpsY25L#Sxy6ljl16gI)H0f>for?qaszCX;ESpG=pqROFWR~Z
+zTqQzcH(berra`9K(R~0OJ_eeA<Ovbd&vdN3&y}qtJ`q3y6wpP2V}*{Dbi8b357>=>
+z&R-)LYP^U3@%6h}+0)7m-mEOhOM92<j^WbYrTU_kNXz~GCDNT`I|IC3AsFzURKM6k
+zQdYbOof5*Zq``6G)5LxcgKFZn#G8mi#5;*Qh*QM-i4PHv5FaHzLHru=Tg2yx{aFHb
+z(R2S=c8RBfL#5J#E-BTphw@OA+GpyZ;G1*r11OzSMVJD%l2Wuxx^l~w*1QYefHUN4
+zpSM~1{wGHQJOdv7$#vPs;Ii+!aI*SVDadZ``zyQq-N$35E%P{WT}(AcpKmkH*)gyF
+z|NhTLpsow9_zOk6x>l32>zpvu-&@ZkPf<>~Bsv&Oy1O(`pbLUf3vt*0HIRk0U3EzI
+zIeSaIE9*jps%6qP7$EQo8=K#f^K_mFpy5prkNNSOU;oI@KK0}Ge*G6eyWz+6OyADf
+zE`}D<k1}?G;rmSggt5;V{>b#-81u-uS=OJB*=`v}WPMs@ugdtLtbZo6OEUf}>!QL`
+z1zQ!pLt!Zek0|;p3VTDrj}`q(g?+8yuZk|KY?X>TRlP@LPpbH`s-ITbSygS+Jq6cQ
+zp|Em=T_#B53Y|R}mtw!K3mUyWRhytxx_wi^(}HurDkx@L%OlKIA%rq@7%bE{p{Wl~
+zJJ%lV6&>fxBjnbA8G(&P?a8o%P#c~Wo$7|%1UE-$r;6jwt1uejOfMLwF-BDgC-Q+N
+za!Hx;1S&$9!rlNCTsI*IMZ0#Y5aEO7sjIz#jb`S|q7OpRYx`h&=PK}_YnN#poNF=7
+z3yTO|pc0N&G3cozl21Q6c)l0vjm~0uFL)%2_T5RYR1$~dO~u)4px!jFycZNnchPVA
+z!0+Vc_afL{m>rv2PY8{Cma`W{yG~JNJu?;L!#fSLmwRW{8R@gD7Z5~{xvZGpN)U`j
+z^I~=;XVmtVzgSv@Na@HC?lC8A1l2+CU<IqV7J%6_t~L}S#%I}a5R3FZk`D#n4m*-O
+z$?u%iuC_w$3p=)&nXQX^AwrdnK*hRu`Mqc`AzOgztfsBxvm77j5G7KQo#~<Ufx}jQ
+z?|~8PU!d?s-JLd{0Ph}c6J*Zsxd^=dPINEGPS4+NOQoUG&E#4_TUNoTPI5CrmHR%r
+VymGKbcpH8Yo8|ycF3<xZ{s}94r0@U$
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/gma-mainboard.ads b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/gma-mainboard.ads
+new file mode 100644
+index 0000000000..fcfbd75a92
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/gma-mainboard.ads
+@@ -0,0 +1,19 @@
++-- SPDX-License-Identifier: GPL-2.0-or-later
++
++with HW.GFX.GMA;
++with HW.GFX.GMA.Display_Probing;
++
++use HW.GFX.GMA;
++use HW.GFX.GMA.Display_Probing;
++
++private package GMA.Mainboard is
++
++ ports : constant Port_List :=
++ (eDP,
++ DP1,
++ DP2,
++ HDMI1,
++ HDMI2,
++ others => Disabled);
++
++end GMA.Mainboard;
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/gpio.c b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/gpio.c
+new file mode 100644
+index 0000000000..f7c29e1f39
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/gpio.c
+@@ -0,0 +1,203 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#include <soc/gpio.h>
++#include "../../gpio.h"
++
++/* FIXME: There are multiple GPIOs here that should be locked to prevent "TPM GPIO fail" style
++ * attacks. Unfortunately SKL/KBL GPIO locking *does not* work currently. */
++
++static const struct pad_config gpio_table[] = {
++
++ /* ------- GPIO Community 0 ------- */
++
++ /* ------- GPIO Group GPP_A ------- */
++ PAD_CFG_NF(GPP_A0, NONE, DEEP, NF1), /* -KBRC */
++ PAD_CFG_NF(GPP_A1, NATIVE, DEEP, NF1), /* LPC_AD0 */
++ PAD_CFG_NF(GPP_A2, NATIVE, DEEP, NF1), /* LPC_AD1 */
++ PAD_CFG_NF(GPP_A3, NATIVE, DEEP, NF1), /* LPC_AD2 */
++ PAD_CFG_NF(GPP_A4, NATIVE, DEEP, NF1), /* LPC_AD3 */
++ PAD_CFG_NF(GPP_A5, NONE, DEEP, NF1), /* -LPC_FRAME */
++ PAD_CFG_NF(GPP_A6, NONE, DEEP, NF1), /* IRQSER */
++ PAD_CFG_NF(GPP_A7, NONE, DEEP, NF1), /* -TPM_IRQ */
++ PAD_CFG_NF(GPP_A8, NONE, DEEP, NF1), /* -CLKRUN */
++ PAD_CFG_NF(GPP_A9, NATIVE, DEEP, NF1), /* LPCCLK_EC_24M */
++ PAD_CFG_NF(GPP_A10, NATIVE, DEEP, NF1), /* LPCCLK_DEBUG_24M */
++ PAD_NC(GPP_A11, NONE),
++ PAD_NC(GPP_A12, NONE),
++ PAD_CFG_NF(GPP_A13, NATIVE, DEEP, NF1), /* -SUSWARN */
++ PAD_CFG_NF(GPP_A14, NATIVE, DEEP, NF1), /* -SUS_STAT */
++ PAD_CFG_NF(GPP_A15, NATIVE, DEEP, NF1), /* -SUSWARN */
++ PAD_NC(GPP_A16, NONE),
++ PAD_NC(GPP_A17, NONE),
++ PAD_NC(GPP_A18, NONE),
++ PAD_NC(GPP_A19, NONE),
++ PAD_NC(GPP_A20, NONE),
++ PAD_NC(GPP_A21, NONE),
++ PAD_NC(GPP_A22, NONE),
++ PAD_NC(GPP_A23, NONE),
++
++ /* ------- GPIO Group GPP_B ------- */
++ PAD_NC(GPP_B0, NONE),
++ PAD_NC(GPP_B1, NONE),
++ PAD_NC(GPP_B2, NONE),
++ PAD_NC(GPP_B3, NONE),
++ PAD_CFG_GPI_SCI(GPP_B4, NONE, DEEP, EDGE_SINGLE, INVERT), /* -TBT_PLUG_EVENT */
++ PAD_CFG_NF(GPP_B5, NONE, DEEP, NF1), /* -CLKREQ_PCIE0 */
++ PAD_CFG_NF(GPP_B6, NONE, DEEP, NF1), /* -CLKREQ_PCIE4 */
++ PAD_CFG_NF(GPP_B7, NONE, DEEP, NF1), /* -CLKREQ_PCIE5 */
++ PAD_CFG_NF(GPP_B8, NONE, DEEP, NF1), /* -CLKREQ_PCIE6 */
++ PAD_CFG_NF(GPP_B9, NONE, DEEP, NF1), /* -CLKREQ_PCIE8 */
++ PAD_CFG_NF(GPP_B10, NONE, DEEP, NF1), /* -CLKREQ_PCIE10 */
++ PAD_NC(GPP_B11, NONE),
++ PAD_CFG_NF(GPP_B12, NONE, DEEP, NF1), /* -PCH_SLP_S0 */
++ PAD_CFG_NF(GPP_B13, NONE, DEEP, NF1), /* -PLTRST */
++ PAD_CFG_NF(GPP_B14, NATIVE, DEEP, NF1), /* PCH_SPKR */
++ PAD_CFG_GPO(GPP_B15, 1, DEEP), /* NFC_DLREQ */
++ PAD_NC(GPP_B16, NONE),
++ PAD_NC(GPP_B17, NONE),
++ PAD_NC(GPP_B18, NONE),
++ PAD_NC(GPP_B19, NONE),
++ PAD_NC(GPP_B20, NONE),
++ PAD_NC(GPP_B21, NONE),
++ PAD_NC(GPP_B22, NONE),
++ PAD_NC(GPP_B23, NONE),
++
++ /* ------- GPIO Community 1 ------- */
++
++ /* ------- GPIO Group GPP_C ------- */
++ PAD_CFG_NF(GPP_C0, NONE, DEEP, NF1), /* SMB_CLK */
++ PAD_CFG_NF(GPP_C1, NONE, DEEP, NF1), /* SMB_DATA */
++ PAD_NC(GPP_C2, NONE),
++ PAD_CFG_NF(GPP_C3, NONE, DEEP, NF1), /* SML0_CLK */
++ PAD_CFG_NF(GPP_C4, NONE, DEEP, NF1), /* SML0_DATA */
++ PAD_NC(GPP_C5, NONE),
++ PAD_CFG_NF(GPP_C6, NONE, DEEP, NF1), /* EC_SCL2 */
++ PAD_CFG_NF(GPP_C7, NONE, DEEP, NF1), /* EC_SDA2 */
++ PAD_NC(GPP_C8, NONE),
++ PAD_NC(GPP_C9, NONE),
++ PAD_NC(GPP_C10, NONE),
++ PAD_NC(GPP_C11, NONE),
++ PAD_NC(GPP_C12, NONE),
++ PAD_NC(GPP_C13, NONE),
++ PAD_NC(GPP_C14, NONE),
++ PAD_NC(GPP_C15, NONE),
++ PAD_CFG_NF(GPP_C16, NONE, DEEP, NF1), /* I2C0_DATA */
++ PAD_CFG_NF(GPP_C17, NONE, DEEP, NF1), /* I2C0_CLK */
++ PAD_NC(GPP_C18, NONE),
++ PAD_NC(GPP_C19, NONE),
++ PAD_CFG_GPO(GPP_C20, 0, DEEP), /* EPRIVACY_ON */
++ PAD_CFG_GPO(GPP_C21, 0, DEEP), /* TBT_FORCE_PWR */
++ PAD_CFG_GPI_SCI(GPP_C22, NONE, DEEP, EDGE_SINGLE, INVERT), /* -EC_SCI */
++ PAD_CFG_GPI_SCI(GPP_C23, NONE, DEEP, EDGE_SINGLE, INVERT), /* -EC_WAKE */
++
++ /* ------- GPIO Group GPP_D ------- */
++ PAD_NC(GPP_D0, NONE),
++ PAD_NC(GPP_D1, NONE),
++ PAD_NC(GPP_D2, NONE),
++ PAD_NC(GPP_D3, NONE),
++ PAD_NC(GPP_D4, NONE),
++ PAD_NC(GPP_D5, NONE),
++ PAD_NC(GPP_D6, NONE),
++ PAD_NC(GPP_D7, NONE),
++ PAD_NC(GPP_D8, NONE),
++ PAD_CFG_GPI_TRIG_OWN(GPP_D9, UP_20K, DEEP, OFF, ACPI), /* -DISCRETE_PRESENCE */
++ PAD_NC(GPP_D10, NONE),
++ PAD_CFG_GPI_TRIG_OWN(GPP_D11, UP_20K, DEEP, OFF, ACPI), /* DGFX_VRAM_ID0 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_D12, UP_20K, DEEP, OFF, ACPI), /* DGFX_VRAM_ID1 */
++ PAD_NC(GPP_D13, NONE),
++ PAD_NC(GPP_D14, NONE),
++ PAD_NC(GPP_D15, NONE),
++ PAD_NC(GPP_D16, NONE),
++ PAD_CFG_GPO(GPP_D17, 0, DEEP), /* DDI_PRIORITY1 */
++ PAD_NC(GPP_D18, NONE),
++ PAD_NC(GPP_D19, NONE),
++ PAD_NC(GPP_D20, NONE),
++ PAD_NC(GPP_D21, NONE),
++ PAD_CFG_GPI_TRIG_OWN(GPP_D22, UP_20K, DEEP, OFF, ACPI), /* -NFC_DTCT */
++ PAD_NC(GPP_D23, NONE),
++
++ /* ------- GPIO Group GPP_E ------- */
++ PAD_NC(GPP_E0, NONE),
++ PAD_CFG_NF(GPP_E1, NONE, DEEP, NF1), /* -WWAN_SATA_DTCT (always HIGH) */
++ PAD_CFG_NF(GPP_E2, NONE, DEEP, NF1), /* -PE_DTCT */
++ PAD_CFG_GPI_TRIG_OWN(GPP_E3, NONE, DEEP, EDGE_SINGLE, ACPI), /* -TBT_PLUG_EVENT */
++ PAD_CFG_GPO(GPP_E4, 1, DEEP), /* NFC_ON */
++ PAD_NC(GPP_E5, NONE),
++ PAD_CFG_NF(GPP_E6, NONE, RSMRST, NF1), /* SATA2_DEVSLP */
++ PAD_NC(GPP_E7, NONE),
++ PAD_NC(GPP_E8, NONE),
++ PAD_CFG_NF(GPP_E9, NONE, DEEP, NF1), /* -USB_PORT0_OC0 (AON port) */
++ PAD_CFG_NF(GPP_E10, NONE, DEEP, NF1), /* -USB_PORT1_OC1 (regular port) */
++ PAD_NC(GPP_E11, NONE),
++ PAD_CFG_GPI_APIC_HIGH(GPP_E12, NONE, DEEP), /* NFC_INT */
++ PAD_CFG_NF(GPP_E13, NONE, DEEP, NF1), /* DDIP1_HPD */
++ PAD_CFG_NF(GPP_E14, NONE, DEEP, NF1), /* DDIP2_HPD */
++ PAD_NC(GPP_E15, NONE),
++ PAD_NC(GPP_E16, NONE),
++ PAD_CFG_NF(GPP_E17, NONE, DEEP, NF1), /* EDP_HPD */
++ PAD_NC(GPP_E18, NONE),
++ PAD_NC(GPP_E19, NONE),
++ PAD_CFG_NF(GPP_E20, NONE, DEEP, NF1), /* DDIP2_CTRLCLK */
++ PAD_CFG_NF(GPP_E21, NONE, DEEP, NF1), /* DDIP2_CTRLDATA */
++ PAD_CFG_TERM_GPO(GPP_E22, 0, UP_20K, RSMRST), /* -GPU_RST */
++ PAD_CFG_TERM_GPO(GPP_E23, 0, UP_20K, RSMRST), /* 1R8VIDEO_AON_ON */
++
++ /* ------- GPIO Community 2 ------- */
++
++ /* -------- GPIO Group GPD -------- */
++ PAD_CFG_NF(GPD0, NONE, PWROK, NF1), /* -BATLOW */
++ PAD_CFG_NF(GPD1, NATIVE, PWROK, NF1), /* AC_PRESENT */
++ PAD_CFG_NF(GPD2, NATIVE, PWROK, NF1), /* -LANWAKE */
++ PAD_CFG_NF(GPD3, UP_20K, PWROK, NF1), /* -PWRSW_EC */
++ PAD_CFG_NF(GPD4, NONE, PWROK, NF1), /* -PCH_SLP_S3 */
++ PAD_CFG_NF(GPD5, NONE, PWROK, NF1), /* -PCH_SLP_S4 */
++ PAD_CFG_NF(GPD6, NONE, PWROK, NF1), /* -PCH_SLP_M */
++ PAD_NC(GPD7, NONE),
++ PAD_CFG_NF(GPD8, NONE, PWROK, NF1), /* SUSCLK_32K */
++ PAD_CFG_NF(GPD9, NONE, PWROK, NF1), /* -PCH_SLP_WLAN */
++ PAD_CFG_NF(GPD10, NONE, PWROK, NF1), /* -PCH_SLP_S5 */
++ PAD_CFG_NF(GPD11, NONE, PWROK, NF1), /* LANPHYPC */
++
++ /* ------- GPIO Community 3 ------- */
++
++ /* ------- GPIO Group GPP_F ------- */
++ PAD_NC(GPP_F0, NONE),
++ PAD_CFG_GPI_TRIG_OWN(GPP_F1, NONE, DEEP, OFF, ACPI), /* GC6_FB_EN */
++ PAD_CFG_GPO(GPP_F2, 1, DEEP), /* -GPU_EVENT */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F3, NONE, DEEP, OFF, ACPI), /* DGFX_PWRGD */
++ PAD_CFG_GPO(GPP_F4, 1, DEEP), /* -WWAN_RESET */
++ PAD_NC(GPP_F5, NONE),
++ PAD_CFG_GPI_TRIG_OWN(GPP_F6, UP_20K, DEEP, OFF, ACPI), /* -MIC_HW_EN (R961 to GND) */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F7, UP_20K, DEEP, OFF, ACPI), /* -INT_MIC_DTCT */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F8, UP_20K, DEEP, OFF, ACPI), /* WWAN_CFG0 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F9, UP_20K, DEEP, OFF, ACPI), /* WWAN_CFG1 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F10, UP_20K, DEEP, OFF, ACPI), /* WWAN_CFG2 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F11, UP_20K, DEEP, OFF, ACPI), /* WWAN_CFG3 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F12, UP_20K, DEEP, OFF, ACPI), /* PLANARID0 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F13, UP_20K, DEEP, OFF, ACPI), /* PLANARID1 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F14, UP_20K, DEEP, OFF, ACPI), /* PLANARID2 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F15, UP_20K, DEEP, OFF, ACPI), /* PLANARID3 */
++ PAD_NC(GPP_F16, NONE),
++ PAD_NC(GPP_F17, NONE),
++ PAD_NC(GPP_F18, NONE),
++ PAD_NC(GPP_F19, NONE),
++ PAD_NC(GPP_F20, NONE),
++ PAD_NC(GPP_F21, NONE),
++ PAD_CFG_GPI_TRIG_OWN(GPP_F22, UP_20K, DEEP, OFF, ACPI), /* -INTRUDER_PCH */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F23, UP_20K, DEEP, OFF, ACPI), /* -SC_DTCT */
++
++ /* ------- GPIO Group GPP_G ------- */
++ PAD_NC(GPP_G0, NONE),
++ PAD_NC(GPP_G1, NONE),
++ PAD_NC(GPP_G2, NONE),
++ PAD_NC(GPP_G3, NONE),
++ PAD_CFG_GPO(GPP_G4, 0, DEEP), /* TBT_RTD3_PWR_EN */
++ PAD_CFG_GPO(GPP_G5, 0, DEEP), /* TBT_FORCE_USB_PWR */
++ PAD_CFG_GPO(GPP_G6, 0, DEEP), /* -TBT_PERST */
++ PAD_CFG_GPI_SCI(GPP_G7, NONE, DEEP, LEVEL, INVERT), /* -TBT_PCIE_WAKE */
++};
++
++void variant_config_gpios(void)
++{
++ gpio_configure_pads(gpio_table, ARRAY_SIZE(gpio_table));
++}
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/hda_verb.c b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/hda_verb.c
+new file mode 100644
+index 0000000000..3a951ce0da
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/hda_verb.c
+@@ -0,0 +1,90 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#include <device/azalia_device.h>
++
++const u32 cim_verb_data[] = {
++ 0x10ec0257, // Vendor/Device ID: Realtek ALC257
++ 0x17aa225d, // Subsystem ID
++ 11,
++ AZALIA_SUBVENDOR(0, 0x17aa225d),
++
++ AZALIA_PIN_CFG(0, 0x12, AZALIA_PIN_DESC(
++ AZALIA_INTEGRATED,
++ AZALIA_INTERNAL,
++ AZALIA_MIC_IN,
++ AZALIA_OTHER_DIGITAL,
++ AZALIA_COLOR_UNKNOWN,
++ AZALIA_NO_JACK_PRESENCE_DETECT,
++ 2, 0
++ )),
++ AZALIA_PIN_CFG(0, 0x13, 0x40000000), // does not describe a jack or internal device
++ AZALIA_PIN_CFG(0, 0x14, AZALIA_PIN_DESC(
++ AZALIA_INTEGRATED,
++ AZALIA_INTERNAL,
++ AZALIA_SPEAKER,
++ AZALIA_OTHER_ANALOG,
++ AZALIA_COLOR_UNKNOWN,
++ AZALIA_NO_JACK_PRESENCE_DETECT,
++ 1, 0
++ )),
++ AZALIA_PIN_CFG(0, 0x18, AZALIA_PIN_CFG_NC(0)),
++ AZALIA_PIN_CFG(0, 0x19, AZALIA_PIN_DESC(
++ AZALIA_JACK,
++ AZALIA_EXTERNAL_PRIMARY_CHASSIS | AZALIA_RIGHT,
++ AZALIA_MIC_IN,
++ AZALIA_STEREO_MONO_1_8,
++ AZALIA_BLACK,
++ AZALIA_JACK_PRESENCE_DETECT,
++ 3, 0
++ )),
++ AZALIA_PIN_CFG(0, 0x1a, AZALIA_PIN_CFG_NC(0)),
++ AZALIA_PIN_CFG(0, 0x1b, AZALIA_PIN_CFG_NC(0)),
++ AZALIA_PIN_CFG(0, 0x1d, 0x40661b45), // does not describe a jack or internal device
++ AZALIA_PIN_CFG(0, 0x1e, AZALIA_PIN_CFG_NC(0)),
++ AZALIA_PIN_CFG(0, 0x21, AZALIA_PIN_DESC(
++ AZALIA_JACK,
++ AZALIA_EXTERNAL_PRIMARY_CHASSIS | AZALIA_RIGHT,
++ AZALIA_HP_OUT,
++ AZALIA_STEREO_MONO_1_8,
++ AZALIA_BLACK,
++ AZALIA_JACK_PRESENCE_DETECT,
++ 1, 15
++ )),
++
++ 0x8086280b, // Vendor/Device ID: Intel Kabylake HDMI
++ 0x80860101, // Subsystem ID
++ 4,
++ AZALIA_SUBVENDOR(2, 0x80860101),
++
++ AZALIA_PIN_CFG(2, 0x05, AZALIA_PIN_DESC(
++ AZALIA_JACK,
++ AZALIA_DIGITAL_DISPLAY,
++ AZALIA_DIGITAL_OTHER_OUT,
++ AZALIA_OTHER_DIGITAL,
++ AZALIA_COLOR_UNKNOWN,
++ AZALIA_JACK_PRESENCE_DETECT,
++ 1, 0
++ )),
++ AZALIA_PIN_CFG(2, 0x06, AZALIA_PIN_DESC(
++ AZALIA_JACK,
++ AZALIA_DIGITAL_DISPLAY,
++ AZALIA_DIGITAL_OTHER_OUT,
++ AZALIA_OTHER_DIGITAL,
++ AZALIA_COLOR_UNKNOWN,
++ AZALIA_JACK_PRESENCE_DETECT,
++ 2, 0
++ )),
++ AZALIA_PIN_CFG(2, 0x07, AZALIA_PIN_DESC(
++ AZALIA_JACK,
++ AZALIA_DIGITAL_DISPLAY,
++ AZALIA_DIGITAL_OTHER_OUT,
++ AZALIA_OTHER_DIGITAL,
++ AZALIA_COLOR_UNKNOWN,
++ AZALIA_JACK_PRESENCE_DETECT,
++ 3, 0
++ )),
++};
++
++const u32 pc_beep_verbs[] = {};
++
++AZALIA_ARRAY_SIZES;
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/memory_init_params.c b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/memory_init_params.c
+new file mode 100644
+index 0000000000..5252a402f9
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/memory_init_params.c
+@@ -0,0 +1,20 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#include <soc/romstage.h>
++#include <spd_bin.h>
++
++void mainboard_memory_init_params(FSPM_UPD *mupd)
++{
++ FSP_M_CONFIG *mem_cfg = &mupd->FspmConfig;
++ mem_cfg->DqPinsInterleaved = true; /* DDR_DQ in interleave mode */
++ mem_cfg->CaVrefConfig = 2; /* VREF_CA to CH_A and VREF_DQ_B to CH_B */
++ mem_cfg->MemorySpdDataLen = CONFIG_DIMM_SPD_SIZE;
++
++ /* Get SPD for memory slots */
++ struct spd_block blk = { .addr_map = { 0x50, 0x51, } };
++ get_spd_smbus(&blk);
++ dump_spd_info(&blk);
++
++ mem_cfg->MemorySpdPtr00 = (uintptr_t)blk.spd_array[0];
++ mem_cfg->MemorySpdPtr10 = (uintptr_t)blk.spd_array[1];
++}
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/overridetree.cb b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/overridetree.cb
+new file mode 100644
+index 0000000000..bf66bd3a69
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480/overridetree.cb
+@@ -0,0 +1,103 @@
++# SPDX-License-Identifier: GPL-2.0-only
++
++chip soc/intel/skylake
++ device domain 0 on
++ device ref south_xhci on
++ register "usb2_ports" = "{
++ [0] = USB2_PORT_MID(OC1), // USB-A
++ [1] = USB2_PORT_MID(OC0), // USB-A (always on)
++ [2] = USB2_PORT_MID(OC_SKIP), // JSC-1 (smartcard slot)
++ [3] = USB2_PORT_MID(OC_SKIP), // USB-C (charging port)
++ [4] = USB2_PORT_MID(OC_SKIP), // JCAM1 (IR camera)
++ [5] = USB2_PORT_MID(OC_SKIP), // JWWAN1 (M.2 WWAN USB)
++ [6] = USB2_PORT_MID(OC_SKIP), // JWLAN1 (M.2 WLAN USB)
++ [7] = USB2_PORT_MID(OC_SKIP), // JCAM1 (webcam)
++ [8] = USB2_PORT_MID(OC_SKIP), // JFPR1 (fingerprint reader)
++ [9] = USB2_PORT_MID(OC_SKIP), // JLCD1 (touch panel)
++ }"
++ register "usb3_ports" = "{
++ [0] = USB3_PORT_DEFAULT(OC1), // USB-A
++ [1] = USB3_PORT_DEFAULT(OC0), // USB-A (always on)
++ [2] = USB3_PORT_DEFAULT(OC_SKIP), // RTS5344S (SD card reader)
++ [3] = USB3_PORT_DEFAULT(OC_SKIP), // USB-C (charging port)
++ }"
++ end
++
++ device ref sata on
++ # SATA_2 - JHDD1 SATA SSD
++ register "SataPortsEnable[2]" = "1"
++ register "SataPortsDevSlp[2]" = "1"
++ end
++
++ # PCIe controller 1 - 1x4
++ # PCIE 1-4 - RP1 - dGPU - CLKOUT0 - CLKREQ0
++ #
++ # PCIe controller 2 - 2x1+1x2 (lane reversal)
++ # PCIE 5 - GBE - GBE - CLKOUT1 - CLKREQ1 (clobbers RP8)
++ # PCIE 6 - RP7 - WLAN - CLKOUT2 - CLKREQ2
++ # PCIE 7-8 - RP5 - WWAN - CLKOUT3 - CLKREQ3
++ #
++ # PCIe controller 3 - 2x2
++ # PCIE 9-10 - RP9 - TB3 - CLKOUT4 - CLKREQ4
++ # PCIE 11-12 - RP11 - SSD - CLKOUT5 - CLKREQ5
++
++ # dGPU - x4
++ device ref pcie_rp1 on
++ register "PcieRpEnable[0]" = "1"
++ register "PcieRpClkReqSupport[0]" = "1"
++ register "PcieRpClkReqNumber[0]" = "0"
++ register "PcieRpClkSrcNumber[0]" = "0"
++ register "PcieRpAdvancedErrorReporting[0]" = "1"
++ register "PcieRpLtrEnable[0]" = "1"
++ end
++
++ # Ethernet (clobbers RP8)
++ device ref gbe on
++ register "LanClkReqSupported" = "1"
++ register "LanClkReqNumber" = "1"
++ register "EnableLanLtr" = "1"
++ register "EnableLanK1Off" = "1"
++ end
++
++ # M.2 WLAN - x1
++ device ref pcie_rp7 on
++ register "PcieRpEnable[6]" = "1"
++ register "PcieRpClkReqSupport[6]" = "1"
++ register "PcieRpClkReqNumber[6]" = "2"
++ register "PcieRpClkSrcNumber[6]" = "2"
++ register "PcieRpAdvancedErrorReporting[6]" = "1"
++ register "PcieRpLtrEnable[6]" = "1"
++ end
++
++ # M.2 WWAN - x2
++ device ref pcie_rp5 on
++ register "PcieRpEnable[4]" = "1"
++ register "PcieRpClkReqSupport[4]" = "1"
++ register "PcieRpClkReqNumber[4]" = "3"
++ register "PcieRpClkSrcNumber[4]" = "3"
++ register "PcieRpAdvancedErrorReporting[4]" = "1"
++ register "PcieRpLtrEnable[4]" = "1"
++ end
++
++ # TB3 (Alpine Ridge LP) - x2
++ device ref pcie_rp9 on
++ register "PcieRpEnable[8]" = "1"
++ register "PcieRpClkReqSupport[8]" = "1"
++ register "PcieRpClkReqNumber[8]" = "4"
++ register "PcieRpClkSrcNumber[8]" = "4"
++ register "PcieRpAdvancedErrorReporting[8]" = "1"
++ register "PcieRpLtrEnable[8]" = "1"
++ register "PcieRpHotPlug[8]" = "1"
++ end
++
++ # M.2 2280 caddy - x2
++ device ref pcie_rp11 on
++ register "PcieRpEnable[10]" = "1"
++ register "PcieRpClkReqSupport[10]" = "1"
++ register "PcieRpClkReqNumber[10]" = "5"
++ register "PcieRpClkSrcNumber[10]" = "5"
++ register "PcieRpAdvancedErrorReporting[10]" = "1"
++ register "PcieRpLtrEnable[10]" = "1"
++ end
++ end
++end
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/data.vbt b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/data.vbt
+new file mode 100644
+index 0000000000000000000000000000000000000000..47732e37d5b2bad4e674fd10eafa605d26f97840
+GIT binary patch
+literal 4106
+zcmeHJUu+a*5TCu>yW9JAmoD2P<t%lC2CfC#y%tU^HSGOq>9tqx`iFWXCLD09R<E?S
+zMT)`nNScT-%9*GEA8a2?G`v`!jPV6yVlcd5OnC6Y;F}U&jJz1db9VRID@E)DLk#NN
+z&9^i2&Hiq_`R2ZF8ipf7IM{nI5$^585@kULrrx0OPKv~ngNI__q41$dA{p()ui+v1
+zw(9rm09lUPAP4nOTm0CRnF|aw5^SQSH<G}<u_Gfnvn6IuK0h@!j;UxI!$*&rIdkIh
+zl$piB;eBDWa1|CgK9bAg{^O%Z%!ziiz{neeJDb~fBI?1GV5p^44?a$ETl=n1d+;%Z
+z#X6(OzEnIB9*QUTV{!mv@xk!mU}s+>aS&4j$?kY0KGYdgn6;MZ*!anbk!PNr!a%eU
+zTXkLEL3ly5L&oUX#CS7?b2%Kad?s<goHQq1G_%bLv);c5qQC)gZtxnw!L3%1MWI_X
+z0wUImYD_R11gsI%l%Zw})KN_c#&!YgM3v;Up{7+s1=lXlB>-#@;mhg8>>>#S&)d2I
+zmP&-g0$k02szSQj(Y*j}YYtQnDH0;2ui<!ko-28Y){6ilAcrmz951v4RTWQ_ye!or
+z4xOJya#Sr7{o)%XFUfJCndM%KM(c^ol_hzlb*1h&uC%Vy%U(P!_qUfwcb4r;SmPQ_
+zhxf($vVo)we+jxogb`7NQ^aS9eQpNT#2bmX5(kO*5O)$Mi4PJVB_1U{L42C{HR894
+z=ZJk70(Q~o{*COiRR#_fix0XaS3?igAuo2!)<NF8ARGWF&M7=h16xZaS|UxpZA)w3
+z1CQUC@^&oxtbG2HGk&WA9=_qa;$?8fdy_j;eY+H3ciR5U?|$2?oT;mPoV=Dx&CwUf
+zv~zYWs{cR#vl*!ChO54O0k3UT#mpur4fXeCdE_aoNtZ|mgF!ck3Nmy<0BRuy4NwCa
+zNZDP7XrHsU<-0NyB2=wXwgEqZPukelExAY+hyWVj0{)~A=X~17KK7XpzxQcB``9fX
+zZf4pp#`ZEanRbG)(+odg+NX?t!SF|>{mPhI!flfFgv9nqI4Wr~5_?s`k0kALiCvcP
+zCrRUFrpVYPYn?Jn%6MGXUXj_GGJYa!U&-tn8Gn&ANnz_0+@olH3VTw)mlf@-!p<v7
+zljhF5u5tObYwR{boRI14NxNkGd6QG=>8{!e#p0ct5}M(h16D>p?OGjSz6v3juERjS
+z#z{?mXvVqrXs_rvUmYR40gNzg(QD6y9E94?4DWO|6eb83LI-smcVC6x1n2reH}rAp
+zLM);f=tWDCr``UF5T>!;PYu^H1g>EBP8A}2*fM>s-@nC3pDV|}6+CtfhG(II7`pcw
+z`jLfJ!?;*R@Bp=Nw2EPOC7FEs(cugIP_K6tN_$~tvS8nx6iOv|IMrO3&-m*N9ZP#b
+znG^~>I|l1cUVSeD9r^k3h0TP}WWD9=MZxY<<azgO1@-W5<NTHW*-d)t{Q4yX9_+?a
+zHawLe=uO6@%xqS#?JxafX%#$`BhkIqq>Z3B2yU!k71#YRpThOJtVheMDA50rV#s@U
+z+nKbA{O(olYR}icuzQD*-cjBQ9;%!eMDVP>7mWsF@=%>o)wSgq=n%DHNOYwRr4Ao6
+zbNdgEn*RdDS>Rud+fIY0N8JkP3q6;>8o%R(CE2n3?Xg%qP+U%~6|{XFyxv7Y#;J2Z
+XK$lk*wsY^m4}9|iz?mg_AjCfat$CyH
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/gma-mainboard.ads b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/gma-mainboard.ads
+new file mode 100644
+index 0000000000..fcfbd75a92
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/gma-mainboard.ads
+@@ -0,0 +1,19 @@
++-- SPDX-License-Identifier: GPL-2.0-or-later
++
++with HW.GFX.GMA;
++with HW.GFX.GMA.Display_Probing;
++
++use HW.GFX.GMA;
++use HW.GFX.GMA.Display_Probing;
++
++private package GMA.Mainboard is
++
++ ports : constant Port_List :=
++ (eDP,
++ DP1,
++ DP2,
++ HDMI1,
++ HDMI2,
++ others => Disabled);
++
++end GMA.Mainboard;
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/gpio.c b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/gpio.c
+new file mode 100644
+index 0000000000..a98dd2bc4e
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/gpio.c
+@@ -0,0 +1,199 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#include <soc/gpio.h>
++#include "../../gpio.h"
++
++static const struct pad_config gpio_table[] = {
++ /* ------- GPIO Community 0 ------- */
++
++ /* ------- GPIO Group GPP_A ------- */
++ PAD_CFG_NF(GPP_A0, NONE, DEEP, NF1), /* -KBRC */
++ PAD_CFG_NF(GPP_A1, NATIVE, DEEP, NF1), /* LPC_AD0 */
++ PAD_CFG_NF(GPP_A2, NATIVE, DEEP, NF1), /* LPC_AD1 */
++ PAD_CFG_NF(GPP_A3, NATIVE, DEEP, NF1), /* LPC_AD2 */
++ PAD_CFG_NF(GPP_A4, NATIVE, DEEP, NF1), /* LPC_AD3 */
++ PAD_CFG_NF(GPP_A5, NONE, DEEP, NF1), /* -LPC_FRAME */
++ PAD_CFG_NF(GPP_A6, NONE, DEEP, NF1), /* IRQSER */
++ PAD_CFG_NF(GPP_A7, NONE, DEEP, NF1), /* -TPM_IRQ */
++ PAD_CFG_NF(GPP_A8, NONE, DEEP, NF1), /* -CLKRUN */
++ PAD_CFG_NF(GPP_A9, DN_20K, DEEP, NF1), /* LPCCLK_EC_24M */
++ PAD_CFG_NF(GPP_A10, DN_20K, DEEP, NF1), /* LPCCLK_DEBUG_24M */
++ PAD_NC(GPP_A11, NONE),
++ PAD_NC(GPP_A12, NONE),
++ PAD_CFG_NF(GPP_A13, NONE, DEEP, NF1), /* -SUSWARN */
++ PAD_CFG_NF(GPP_A14, NONE, DEEP, NF1), /* -SUS_STAT */
++ PAD_CFG_NF(GPP_A15, UP_20K, DEEP, NF1), /* -SUSWARN */
++ PAD_NC(GPP_A16, NONE),
++ PAD_NC(GPP_A17, NONE),
++ PAD_NC(GPP_A18, NONE),
++ PAD_NC(GPP_A19, NONE),
++ PAD_NC(GPP_A20, NONE),
++ PAD_NC(GPP_A21, NONE),
++ PAD_NC(GPP_A22, NONE),
++ PAD_NC(GPP_A23, NONE),
++
++ /* ------- GPIO Group GPP_B ------- */
++ PAD_CFG_NF(GPP_B0, NONE, DEEP, NF1),
++ PAD_CFG_NF(GPP_B1, NONE, DEEP, NF1),
++ PAD_NC(GPP_B2, NONE),
++ PAD_NC(GPP_B3, NONE),
++ PAD_CFG_GPI_SCI(GPP_B4, NONE, DEEP, EDGE_SINGLE, INVERT), /* -TBT_PLUG_EVENT */
++ PAD_CFG_NF(GPP_B5, NONE, DEEP, NF1), /* -CLKREQ_PCIE0 (dGPU) */
++ PAD_CFG_NF(GPP_B6, NONE, DEEP, NF1), /* -CLKREQ_PCIE3 (WWAN) */
++ PAD_CFG_NF(GPP_B7, NONE, DEEP, NF1), /* -CLKREQ_PCIE4 (GBE) */
++ PAD_CFG_NF(GPP_B8, NONE, DEEP, NF1), /* -CLKREQ_PCIE5 (WLAN) */
++ PAD_CFG_NF(GPP_B9, NONE, DEEP, NF1), /* -CLKREQ_PCIE6 (TB3) */
++ PAD_CFG_NF(GPP_B10, NONE, DEEP, NF1), /* -CLKREQ_PCIE8 (SSD) */
++ PAD_NC(GPP_B11, NONE),
++ PAD_CFG_NF(GPP_B12, NONE, DEEP, NF1), /* -PCH_SLP_S0 */
++ PAD_CFG_NF(GPP_B13, NONE, DEEP, NF1), /* -PLTRST */
++ PAD_CFG_NF(GPP_B14, NONE, DEEP, NF1), /* PCH_SPKR */
++ PAD_CFG_GPO(GPP_B15, 0, DEEP), /* NFC_DLREQ */
++ PAD_NC(GPP_B16, NONE),
++ PAD_NC(GPP_B17, NONE),
++ PAD_NC(GPP_B18, NONE),
++ PAD_NC(GPP_B19, NONE),
++ PAD_NC(GPP_B20, NONE),
++ PAD_NC(GPP_B21, NONE),
++ PAD_NC(GPP_B22, NONE),
++ PAD_NC(GPP_B23, NONE),
++
++ /* ------- GPIO Community 1 ------- */
++
++ /* ------- GPIO Group GPP_C ------- */
++ PAD_CFG_NF(GPP_C0, NONE, DEEP, NF1), /* SMB_CLK */
++ PAD_CFG_NF(GPP_C1, NONE, DEEP, NF1), /* SMB_DATA */
++ PAD_CFG_GPO(GPP_C2, 1, DEEP),
++ PAD_CFG_NF(GPP_C3, NONE, DEEP, NF1), /* SML0_CLK */
++ PAD_CFG_NF(GPP_C4, NONE, DEEP, NF1), /* SML0_DATA */
++ PAD_NC(GPP_C5, NONE),
++ PAD_CFG_NF(GPP_C6, NONE, DEEP, NF1), /* EC_SCL2 */
++ PAD_CFG_NF(GPP_C7, NONE, DEEP, NF1), /* EC_SDA2 */
++ PAD_NC(GPP_C8, NONE),
++ PAD_NC(GPP_C9, NONE),
++ PAD_NC(GPP_C10, NONE),
++ PAD_NC(GPP_C11, NONE),
++ PAD_NC(GPP_C12, NONE),
++ PAD_NC(GPP_C13, NONE),
++ PAD_NC(GPP_C14, NONE),
++ PAD_NC(GPP_C15, NONE),
++ PAD_CFG_NF(GPP_C16, NONE, DEEP, NF1), /* I2C0_DATA */
++ PAD_CFG_NF(GPP_C17, NONE, DEEP, NF1), /* I2C0_CLK */
++ PAD_NC(GPP_C18, NONE),
++ PAD_NC(GPP_C19, NONE),
++ PAD_CFG_GPO(GPP_C20, 0, DEEP), /* EPRIVACY_ON */
++ PAD_CFG_GPO(GPP_C21, 0, DEEP), /* TBT_FORCE_PWR */
++ PAD_CFG_GPI_SCI(GPP_C22, NONE, DEEP, EDGE_SINGLE, INVERT), /* -EC_SCI */
++ PAD_CFG_GPI_SCI(GPP_C23, NONE, DEEP, EDGE_SINGLE, INVERT), /* -EC_WAKE */
++
++ /* ------- GPIO Group GPP_D ------- */
++ PAD_NC(GPP_D0, NONE),
++ PAD_NC(GPP_D1, NONE),
++ PAD_NC(GPP_D2, NONE),
++ PAD_NC(GPP_D3, NONE),
++ PAD_NC(GPP_D4, NONE),
++ PAD_NC(GPP_D5, NONE),
++ PAD_NC(GPP_D6, NONE),
++ PAD_NC(GPP_D7, NONE),
++ PAD_NC(GPP_D8, NONE),
++ PAD_CFG_GPI_TRIG_OWN(GPP_D9, UP_20K, DEEP, OFF, ACPI), /* -DISCRETE_PRESENCE */
++ PAD_NC(GPP_D10, NONE),
++ PAD_CFG_GPI_TRIG_OWN(GPP_D11, UP_20K, DEEP, OFF, ACPI), /* DGFX_VRAM_ID0 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_D12, UP_20K, DEEP, OFF, ACPI), /* DGFX_VRAM_ID1 */
++ PAD_NC(GPP_D13, NONE),
++ PAD_NC(GPP_D14, NONE),
++ PAD_NC(GPP_D15, NONE),
++ PAD_NC(GPP_D16, NONE),
++ PAD_CFG_GPO(GPP_D17, 0, DEEP), /* DDI_PRIORITY */
++ PAD_NC(GPP_D18, NONE),
++ PAD_NC(GPP_D19, NONE),
++ PAD_NC(GPP_D20, NONE),
++ PAD_NC(GPP_D21, NONE),
++ PAD_CFG_GPI_TRIG_OWN(GPP_D22, UP_20K, DEEP, OFF, ACPI), /* -NFC_DTCT */
++ PAD_NC(GPP_D23, NONE),
++
++ /* ------- GPIO Group GPP_E ------- */
++ PAD_CFG_GPO(GPP_E0, 1, DEEP), /* BDC_ON */
++ PAD_NC(GPP_E1, NONE),
++ PAD_CFG_NF(GPP_E2, NONE, DEEP, NF1), /* -SATA2_DTCT */
++ PAD_CFG_GPI_TRIG_OWN(GPP_E3, NONE, DEEP, EDGE_SINGLE, ACPI), /* -TBT_PLUG_EVENT */
++ PAD_CFG_GPO(GPP_E4, 1, DEEP), /* NFC_ON */
++ PAD_NC(GPP_E5, NONE),
++ PAD_CFG_NF(GPP_E6, NONE, RSMRST, NF1), /* SATA2_DEVSLP */
++ PAD_NC(GPP_E7, NONE),
++ PAD_NC(GPP_E8, NONE),
++ PAD_CFG_NF(GPP_E9, NONE, DEEP, NF1), /* -USB_PORT0_OC0 */
++ PAD_CFG_NF(GPP_E10, NONE, DEEP, NF1), /* -USB_PORT1_OC1 */
++ PAD_NC(GPP_E11, NONE),
++ PAD_CFG_GPI_APIC_HIGH(GPP_E12, NONE, DEEP), /* NFC_INT */
++ PAD_CFG_NF(GPP_E13, NONE, DEEP, NF1), /* DDIP1_HPD */
++ PAD_CFG_NF(GPP_E14, NONE, DEEP, NF1), /* DDIP2_HPD */
++ PAD_NC(GPP_E15, NONE),
++ PAD_NC(GPP_E16, NONE),
++ PAD_CFG_NF(GPP_E17, NONE, DEEP, NF1), /* EDP_HPD */
++ PAD_NC(GPP_E18, NONE),
++ PAD_CFG_GPO(GPP_E19, 0, DEEP),
++ PAD_CFG_NF(GPP_E20, NONE, DEEP, NF1), /* DDIP2_CTRLCLK */
++ PAD_CFG_NF(GPP_E21, NONE, DEEP, NF1), /* DDIP2_CTRLDATA */
++ PAD_CFG_TERM_GPO(GPP_E22, 0, UP_20K, RSMRST), /* -GPU_RST */
++ PAD_CFG_TERM_GPO(GPP_E23, 0, UP_20K, RSMRST), /* 1R8VIDEO_AON_ON */
++
++ /* ------- GPIO Community 2 ------- */
++
++ /* -------- GPIO Group GPD -------- */
++ PAD_CFG_NF(GPD0, NONE, PWROK, NF1), /* -BATLOW */
++ PAD_CFG_NF(GPD1, NATIVE, PWROK, NF1), /* AC_PRESENT */
++ PAD_CFG_NF(GPD2, NATIVE, PWROK, NF1), /* -LANWAKE */
++ PAD_CFG_NF(GPD3, UP_20K, PWROK, NF1), /* -PWRSW_EC */
++ PAD_CFG_NF(GPD4, NONE, PWROK, NF1), /* -PCH_SLP_S3 */
++ PAD_CFG_NF(GPD5, NONE, PWROK, NF1), /* -PCH_SLP_S4 */
++ PAD_CFG_NF(GPD6, NONE, PWROK, NF1), /* -PCH_SLP_M */
++ PAD_NC(GPD7, NONE),
++ PAD_CFG_NF(GPD8, NONE, PWROK, NF1), /* SUSCLK_32K */
++ PAD_CFG_NF(GPD9, NONE, PWROK, NF1), /* -PCH_SLP_WLAN */
++ PAD_CFG_NF(GPD10, NONE, PWROK, NF1), /* -PCH_SLP_S5 */
++ PAD_CFG_NF(GPD11, NONE, PWROK, NF1), /* LANPHYPC */
++
++ /* ------- GPIO Community 3 ------- */
++
++ /* ------- GPIO Group GPP_F ------- */
++ PAD_CFG_GPO(GPP_F0, 0, DEEP),
++ PAD_CFG_GPI_TRIG_OWN(GPP_F1, NONE, DEEP, OFF, ACPI), /* GC6_FB_EN */
++ PAD_CFG_GPO(GPP_F2, 1, DEEP), /* -GPU_EVENT */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F3, NONE, PLTRST, OFF, ACPI), /* DGFX_PWRGD */
++ PAD_NC(GPP_F4, NONE), /* -WWAN_RESET */
++ PAD_NC(GPP_F5, NONE),
++ PAD_CFG_GPI_TRIG_OWN(GPP_F6, UP_20K, DEEP, OFF, ACPI), /* -MIC_HW_EN (R37 to GND) */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F7, UP_20K, DEEP, OFF, ACPI), /* -INT_MIC_DTCT */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F8, UP_20K, DEEP, OFF, ACPI), /* WWAN_CFG0 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F9, UP_20K, DEEP, OFF, ACPI), /* WWAN_CFG1 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F10, UP_20K, DEEP, OFF, ACPI), /* WWAN_CFG2 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F11, UP_20K, DEEP, OFF, ACPI), /* WWAN_CFG3 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F12, UP_20K, DEEP, OFF, ACPI), /* PLANARID0 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F13, UP_20K, DEEP, OFF, ACPI), /* PLANARID1 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F14, UP_20K, DEEP, OFF, ACPI), /* PLANARID2 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F15, UP_20K, DEEP, OFF, ACPI), /* PLANARID3 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F16, UP_20K, DEEP, OFF, ACPI), /* MEMORYID0 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F17, UP_20K, DEEP, OFF, ACPI), /* MEMORYID1 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F18, UP_20K, DEEP, OFF, ACPI), /* MEMORYID2 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F19, UP_20K, DEEP, OFF, ACPI), /* MEMORYID3 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F20, UP_20K, DEEP, OFF, ACPI), /* MEMORYID4 */
++ PAD_NC(GPP_F21, NONE),
++ PAD_CFG_GPI_TRIG_OWN(GPP_F22, UP_20K, DEEP, OFF, ACPI), /* -TAMPER_SW_DTCT */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F23, UP_20K, DEEP, OFF, ACPI), /* -SC_DTCT */
++
++ /* ------- GPIO Group GPP_G ------- */
++ PAD_NC(GPP_G0, NONE),
++ PAD_NC(GPP_G1, NONE),
++ PAD_NC(GPP_G2, NONE),
++ PAD_NC(GPP_G3, NONE),
++ PAD_CFG_GPO(GPP_G4, 0, DEEP), /* TBT_RTD3_PWR_EN */
++ PAD_CFG_GPO(GPP_G5, 0, DEEP), /* TBT_FORCE_USB_PWR */
++ PAD_CFG_GPO(GPP_G6, 0, DEEP), /* -TBT_PERST */
++ PAD_CFG_GPI_SCI(GPP_G7, NONE, DEEP, LEVEL, INVERT), /* -TBT_PCIE_WAKE */
++};
++
++void variant_config_gpios(void)
++{
++ gpio_configure_pads(gpio_table, ARRAY_SIZE(gpio_table));
++}
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/hda_verb.c b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/hda_verb.c
+new file mode 100644
+index 0000000000..b1d96c5a76
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/hda_verb.c
+@@ -0,0 +1,90 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#include <device/azalia_device.h>
++
++const u32 cim_verb_data[] = {
++ 0x10ec0257, // Vendor/Device ID: Realtek ALC257
++ 0x17aa2258, // Subsystem ID
++ 11,
++ AZALIA_SUBVENDOR(0, 0x17aa2258),
++
++ AZALIA_PIN_CFG(0, 0x12, AZALIA_PIN_DESC(
++ AZALIA_INTEGRATED,
++ AZALIA_INTERNAL,
++ AZALIA_MIC_IN,
++ AZALIA_OTHER_DIGITAL,
++ AZALIA_COLOR_UNKNOWN,
++ AZALIA_NO_JACK_PRESENCE_DETECT,
++ 2, 0
++ )),
++ AZALIA_PIN_CFG(0, 0x13, 0x40000000), // does not describe a jack or internal device
++ AZALIA_PIN_CFG(0, 0x14, AZALIA_PIN_DESC(
++ AZALIA_INTEGRATED,
++ AZALIA_INTERNAL,
++ AZALIA_SPEAKER,
++ AZALIA_OTHER_ANALOG,
++ AZALIA_COLOR_UNKNOWN,
++ AZALIA_NO_JACK_PRESENCE_DETECT,
++ 1, 0
++ )),
++ AZALIA_PIN_CFG(0, 0x18, AZALIA_PIN_CFG_NC(0)),
++ AZALIA_PIN_CFG(0, 0x19, AZALIA_PIN_DESC(
++ AZALIA_JACK,
++ AZALIA_EXTERNAL_PRIMARY_CHASSIS | AZALIA_RIGHT,
++ AZALIA_MIC_IN,
++ AZALIA_STEREO_MONO_1_8,
++ AZALIA_BLACK,
++ AZALIA_JACK_PRESENCE_DETECT,
++ 3, 0
++ )),
++ AZALIA_PIN_CFG(0, 0x1a, AZALIA_PIN_CFG_NC(0)),
++ AZALIA_PIN_CFG(0, 0x1b, AZALIA_PIN_CFG_NC(0)),
++ AZALIA_PIN_CFG(0, 0x1d, 0x40661b45), // does not describe a jack or internal device
++ AZALIA_PIN_CFG(0, 0x1e, AZALIA_PIN_CFG_NC(0)),
++ AZALIA_PIN_CFG(0, 0x21, AZALIA_PIN_DESC(
++ AZALIA_JACK,
++ AZALIA_EXTERNAL_PRIMARY_CHASSIS | AZALIA_RIGHT,
++ AZALIA_HP_OUT,
++ AZALIA_STEREO_MONO_1_8,
++ AZALIA_BLACK,
++ AZALIA_JACK_PRESENCE_DETECT,
++ 1, 15
++ )),
++
++ 0x8086280b, // Vendor/Device ID: Intel Kabylake HDMI
++ 0x80860101, // Subsystem ID
++ 4,
++ AZALIA_SUBVENDOR(2, 0x80860101),
++
++ AZALIA_PIN_CFG(2, 0x05, AZALIA_PIN_DESC(
++ AZALIA_JACK,
++ AZALIA_DIGITAL_DISPLAY,
++ AZALIA_DIGITAL_OTHER_OUT,
++ AZALIA_OTHER_DIGITAL,
++ AZALIA_COLOR_UNKNOWN,
++ AZALIA_JACK_PRESENCE_DETECT,
++ 1, 0
++ )),
++ AZALIA_PIN_CFG(2, 0x06, AZALIA_PIN_DESC(
++ AZALIA_JACK,
++ AZALIA_DIGITAL_DISPLAY,
++ AZALIA_DIGITAL_OTHER_OUT,
++ AZALIA_OTHER_DIGITAL,
++ AZALIA_COLOR_UNKNOWN,
++ AZALIA_JACK_PRESENCE_DETECT,
++ 1, 0
++ )),
++ AZALIA_PIN_CFG(2, 0x07, AZALIA_PIN_DESC(
++ AZALIA_JACK,
++ AZALIA_DIGITAL_DISPLAY,
++ AZALIA_DIGITAL_OTHER_OUT,
++ AZALIA_OTHER_DIGITAL,
++ AZALIA_COLOR_UNKNOWN,
++ AZALIA_JACK_PRESENCE_DETECT,
++ 1, 0
++ )),
++};
++
++const u32 pc_beep_verbs[] = {};
++
++AZALIA_ARRAY_SIZES;
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/memory_init_params.c b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/memory_init_params.c
+new file mode 100644
+index 0000000000..001e934b3a
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/memory_init_params.c
+@@ -0,0 +1,44 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#include <cbfs.h>
++#include <gpio.h>
++#include <soc/gpio.h>
++#include <soc/romstage.h>
++#include <spd_bin.h>
++#include <stdio.h>
++
++static const struct pad_config memory_id_gpio_table[] = {
++ PAD_CFG_GPI_TRIG_OWN(GPP_F16, UP_20K, DEEP, OFF, ACPI), /* MEMORYID0 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F17, UP_20K, DEEP, OFF, ACPI), /* MEMORYID1 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F18, UP_20K, DEEP, OFF, ACPI), /* MEMORYID2 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F19, UP_20K, DEEP, OFF, ACPI), /* MEMORYID3 */
++ PAD_CFG_GPI_TRIG_OWN(GPP_F20, UP_20K, DEEP, OFF, ACPI), /* MEMORYID4 */
++};
++
++void mainboard_memory_init_params(FSPM_UPD *mupd)
++{
++ int spd_idx;
++ char spd_name[20];
++ size_t spd_size;
++
++ FSP_M_CONFIG *mem_cfg = &mupd->FspmConfig;
++ mem_cfg->DqPinsInterleaved = true; /* DDR_DQ in interleave mode */
++ mem_cfg->CaVrefConfig = 2; /* VREF_CA to CH_A and VREF_DQ_B to CH_B */
++ mem_cfg->MemorySpdDataLen = CONFIG_DIMM_SPD_SIZE;
++
++ /* Get SPD for soldered RAM SPD (CH A) */
++ gpio_configure_pads(memory_id_gpio_table, ARRAY_SIZE(memory_id_gpio_table));
++
++ spd_idx = gpio_get(GPP_F16) | gpio_get(GPP_F17) << 1 | gpio_get(GPP_F18) << 2 |
++ gpio_get(GPP_F19) << 3 | gpio_get(GPP_F20) << 4;
++ printk(BIOS_DEBUG, "Detected MEMORY_ID = %d\n", spd_idx);
++ snprintf(spd_name, sizeof(spd_name), "spd_%d.bin", spd_idx);
++ mem_cfg->MemorySpdPtr00 = (uintptr_t)cbfs_map(spd_name, &spd_size);
++
++ /* Get SPD for memory slot (CH B) */
++ struct spd_block blk = { .addr_map = { [1] = 0x51, } };
++ get_spd_smbus(&blk);
++ dump_spd_info(&blk);
++
++ mem_cfg->MemorySpdPtr10 = (uintptr_t)blk.spd_array[1];
++}
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/overridetree.cb b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/overridetree.cb
+new file mode 100644
+index 0000000000..d4afca20c4
+--- /dev/null
++++ b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/overridetree.cb
+@@ -0,0 +1,103 @@
++# SPDX-License-Identifier: GPL-2.0-only
++
++chip soc/intel/skylake
++ device domain 0 on
++ device ref south_xhci on
++ register "usb2_ports" = "{
++ [0] = USB2_PORT_MID(OC0), // JUSB1 (USB-A always on)
++ [1] = USB2_PORT_MID(OC1), // JUSB2 (USB-A)
++ [2] = USB2_PORT_MID(OC_SKIP), // JFPR (smartcard slot)
++ [3] = USB2_PORT_MID(OC_SKIP), // JUSBC (USB-C)
++ [4] = USB2_PORT_MID(OC_SKIP), // JCAM (IR camera)
++ [5] = USB2_PORT_MID(OC_SKIP), // JWWAN (M.2 WWAN USB)
++ [6] = USB2_PORT_MID(OC_SKIP), // JWLAN (M.2 WLAN USB)
++ [7] = USB2_PORT_MID(OC_SKIP), // JCAM (webcam)
++ [8] = USB2_PORT_MID(OC_SKIP), // JFPR (fingerprint reader)
++ [9] = USB2_PORT_MID(OC_SKIP), // JLCD (touch panel)
++ }"
++ register "usb3_ports" = "{
++ [0] = USB3_PORT_DEFAULT(OC0), // JUSB1 (USB-A always on)
++ [1] = USB3_PORT_DEFAULT(OC1), // JUSB2 (USB-A)
++ [2] = USB3_PORT_DEFAULT(OC_SKIP), // JSD (SD card reader)
++ [3] = USB3_PORT_DEFAULT(OC_SKIP), // JUSBC (USB-C)
++ }"
++ end
++
++ device ref sata on
++ # SATA_2 - Main M.2 SATA SSD
++ register "SataPortsEnable[2]" = "1"
++ register "SataPortsDevSlp[2]" = "1"
++ end
++
++ # PCIe controller 1 - 1x2+2x1
++ # PCIE 1-2 - RP1 - dGPU - CLKOUT0 - CLKREQ0
++ # PCIE 4 - RP4 - WWAN - CLKOUT1 - CLKREQ1
++ #
++ # PCIe controller 2 - 2x1+1x2 (lane reversal)
++ # PCIE 5 - GBE - GBE - CLKOUT2 - CLKREQ2 (clobbers RP8)
++ # PCIE 6 - RP7 - WLAN - CLKOUT3 - CLKREQ3
++ # PCIE 7-8 - RP5 - TB3 - CLKOUT4 - CLKREQ4
++ #
++ # PCIe controller 3 - 1x4 (lane reversal)
++ # PCIE 9-12 - RP9 - SSD - CLKOUT5 - CLKREQ5
++
++ # dGPU - x2
++ device ref pcie_rp1 on
++ register "PcieRpEnable[0]" = "1"
++ register "PcieRpClkReqSupport[0]" = "1"
++ register "PcieRpClkReqNumber[0]" = "0"
++ register "PcieRpClkSrcNumber[0]" = "0"
++ register "PcieRpAdvancedErrorReporting[0]" = "1"
++ register "PcieRpLtrEnable[0]" = "1"
++ end
++
++ # M.2 WWAN - x1
++ device ref pcie_rp4 on
++ register "PcieRpEnable[3]" = "1"
++ register "PcieRpClkReqSupport[3]" = "1"
++ register "PcieRpClkReqNumber[3]" = "1"
++ register "PcieRpClkSrcNumber[3]" = "1"
++ register "PcieRpAdvancedErrorReporting[3]" = "1"
++ register "PcieRpLtrEnable[3]" = "1"
++ end
++
++ # Ethernet (clobbers RP8)
++ device ref gbe on
++ register "LanClkReqSupported" = "1"
++ register "LanClkReqNumber" = "2"
++ register "EnableLanLtr" = "1"
++ register "EnableLanK1Off" = "1"
++ end
++
++ # M.2 WLAN - x1
++ device ref pcie_rp7 on
++ register "PcieRpEnable[6]" = "1"
++ register "PcieRpClkReqSupport[6]" = "1"
++ register "PcieRpClkReqNumber[6]" = "3"
++ register "PcieRpClkSrcNumber[6]" = "3"
++ register "PcieRpAdvancedErrorReporting[6]" = "1"
++ register "PcieRpLtrEnable[6]" = "1"
++ end
++
++ # TB3 (Alpine Ridge LP) - x2
++ device ref pcie_rp5 on
++ register "PcieRpEnable[4]" = "1"
++ register "PcieRpClkReqSupport[4]" = "1"
++ register "PcieRpClkReqNumber[4]" = "4"
++ register "PcieRpClkSrcNumber[4]" = "4"
++ register "PcieRpAdvancedErrorReporting[4]" = "1"
++ register "PcieRpLtrEnable[4]" = "1"
++ register "PcieRpHotPlug[4]" = "1"
++ end
++
++ # M.2 2280 SSD - x2
++ device ref pcie_rp9 on
++ register "PcieRpEnable[8]" = "1"
++ register "PcieRpClkReqSupport[8]" = "1"
++ register "PcieRpClkReqNumber[8]" = "5"
++ register "PcieRpClkSrcNumber[8]" = "5"
++ register "PcieRpAdvancedErrorReporting[8]" = "1"
++ register "PcieRpLtrEnable[8]" = "1"
++ end
++ end
++end
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_0.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_0.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..86f39ddb55ea9fb58d5e5699637636ef597c734e
+GIT binary patch
+literal 512
+zcmY!u;9+)EWZ+<6U|?oq29gXMJYRrxPEL*>N67~+1r7#Qh7a1t+8`-(puhlu3{YAD
+YT>%dM8_BI;nL`dsaHtp+rc($20I8n}l>h($
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_1.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_1.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..df0f6e58b79286a4aeb690c5027adf7a1f5f668b
+GIT binary patch
+literal 512
+zcmY!u;9+i6oWQ}rz`)GN3?vyic)kGXoSYm%j*<^t3LFfq3@hZcwLwzoK!E`Q8KATR
+Yx&j>hH(SqvWezd%<4`dwOs5b40B_I==>Px#
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_10.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_10.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..24f0d8992bc5244c62488da9633e4885f52f3e22
+GIT binary patch
+literal 512
+zcmY!u<Y9JIWZ+;(U|?oqW&i?q-XHu740(BZf(&^dxD+@TSQ$QOn`kgpFo@WI<Pkv3
+zjN25185j^Oge*SRoUI_)=hwI&^9wTJQ%GaE+Z>cy&~OfFg0G3Wp`)phiHWn5fv$6q
+PvjPw>z-1}5hGzN!nb#F$
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_11.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_11.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..59b6b9e78263c42aae367ab7d4a784d888f30efe
+GIT binary patch
+literal 512
+zcmY!u<Y8`AWZ+;(U|?osW&i?q-XHu740(BZf(&^dxD+@TSQ%DGYiKZ3Fo@WI<Pm^J
+zTbD)5RGF87L5G`J#gvCx7a@nAHD@bG{`ob#fBb?9_?6OB_I)U&#y6aUn&4|<Zs=&}
+YZDQ=?WT@*L<g5S$3~*UWt)ZEI0F{0fq5uE@
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_12.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_12.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..93be0ac94fc57222cd29e34eee11042d7842ac25
+GIT binary patch
+literal 512
+zcmY!u<Y9JIWZ+;(U|?oqW&i?q-XHu740(BZf(&^dxD+@TSQ$QOn`kgpFo@WI<Pkv3
+zjN25185j^Oge*SRoUI_)=hwI&^9wTJQ%GaE+Z>cy(6E*fVuXjUqlKwqu$iM<keQ!u
+VsD}a&Ff^?FkI#a;_$28g2LQ`x7jOUo
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_13.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_13.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..171a272bc734b72395622bf889d24972ef2d14f7
+GIT binary patch
+literal 512
+zcmY!u<Y8`AWZ+;(U|?osW&i?q-XHu740(BZf(&^dxD+@TSQ%DGYiKZ3Fo@WI<Pkv3
+zjN25185j^Oge*SRoUI_)=hr%!_!*h-DWtL7fk%{D(6E*fVuXjUqob)|u$iN8keQ!u
+VsD}a&Ff^?FkI#a;_$28g2LP>g7pDLK
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_14.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_14.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..a2a64a5e1adada3fc00b2e4edc60c77e610881a9
+GIT binary patch
+literal 512
+zcmY!u<Y9JIWZ+;(U|?oqW&i><-XH%N8S?V-1R3%^a4B#wurhqmHql_HU=XnZ$x{Q&
+z*$Oh{IYWaWKO+-03?$Qx1CPkm2-nu217(^xhPas;8kw1RMCls2o4FbS#SI&DT;VDQ
+GCj$V){1T)9
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_15.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_15.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..a2a64a5e1adada3fc00b2e4edc60c77e610881a9
+GIT binary patch
+literal 512
+zcmY!u<Y9JIWZ+;(U|?oqW&i><-XH%N8S?V-1R3%^a4B#wurhqmHql_HU=XnZ$x{Q&
+z*$Oh{IYWaWKO+-03?$Qx1CPkm2-nu217(^xhPas;8kw1RMCls2o4FbS#SI&DT;VDQ
+GCj$V){1T)9
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_16.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_16.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..a64a5a93fb4aef4d5f63d79cb2582731b9ac5063
+GIT binary patch
+literal 512
+NcmZQz7zHCa1ONg600961
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_17.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_17.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..5f23e86606094d3e5d2011db902ebd4a500bbffa
+GIT binary patch
+literal 512
+zcmY!u<Y9JIWZ+;(U|?oqW&i><-XHc140(BZf(&^dxD+@TSQ$QOn`kgpFo@WI<Pkv3
+zjN25185j^Oge*SRoUI_)=M3$7{ESTa6w+Akz#~d6Xjsb#F~Y;w(ZbX)*v#20$jnbS
+V%v%8n7#i08$7jJ^e3JB$0{}ZV7fApB
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_18.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_18.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..05633943eb5af166da66a2e1f4e74948f75782fb
+GIT binary patch
+literal 512
+zcmY!u<Y9JIoXEkDz`)GN%m4&zyg%$281nM+1R3%^a4B#wurhqmHql_HU=XnZ$s>T6
+z8Mi42GcX`n2w8lrIa@)p&l&!{<7bq|r;x^SwThHl(6E*fVuXjUqobjFu$i-OkeQ!u
+Vn70BDFf^?FkI#a;_$28g2LNS*7)Ag9
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_19.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_19.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..857da9c9828cdac842329f6cef4539283777268b
+GIT binary patch
+literal 512
+zcmY!u<Y9JIWZ+;(U|?oqW&i?K-XH(98S?V-1R3%^a4B#wurhqmHql_HU=XnZ$x{Q&
+z*$Oh{Il~1>enuv07)YiW2Og2B5w5L42g)>Y3~@6xG%_>sh|)E7H}WzBiW@fQc)?W;
+GP6hy+m=i1j
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_2.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_2.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..b5b14cf2dfa06ae183b0379da4dc825129e1589f
+GIT binary patch
+literal 512
+zcmY!u;9+)EWZ+<6U|?oq29gXMJU@VRUS6IcN7)B11r7#Qh7a1tdLSuupuhlu3{YAD
+XT>%b$v*cE=%%S%6I8=-Z(<uZ1pPdSg
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_20.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_20.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..a64a5a93fb4aef4d5f63d79cb2582731b9ac5063
+GIT binary patch
+literal 512
+NcmZQz7zHCa1ONg600961
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_3.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_3.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..d73736008af1eb67456b2fd66f7dec3b6669a442
+GIT binary patch
+literal 512
+zcmY!u;9+i&oWQ}rz`)GN3?vyic)kGXoSYm%juHh92G#;*h81$!dLSuupuhlu3{YAD
+YT>%b$+tzbnnL|62aHtp+rc($20QGqazW@LL
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_4.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_4.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..829f149547bc24859646c33d5926938d7a1b90cb
+GIT binary patch
+literal 512
+zcmY!u;9+)EWZ+<6U|?oq29gXMJYRrxPEL*>N67~+1r7#Qh7a1tdLSuupuhlu3{YAD
+XT>%b$o8(ro%%OI594bbI=@bG0z{d&v
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_5.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_5.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..a64a5a93fb4aef4d5f63d79cb2582731b9ac5063
+GIT binary patch
+literal 512
+NcmZQz7zHCa1ONg600961
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_6.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_6.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..a64a5a93fb4aef4d5f63d79cb2582731b9ac5063
+GIT binary patch
+literal 512
+NcmZQz7zHCa1ONg600961
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_7.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_7.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..940f1e3cd8e5bd9ea32a82a14edcdcbc8132d8c7
+GIT binary patch
+literal 512
+zcmY!u<Y8`AWZ+;(U|?osW&i><-XH%N8S?V-1R3%^a4B#wurjQW(9mG0U=XnZ$x{Q&
+z0UPq1A)%L_QJxwGl4(Y*BAFWD+8T7AOcTeDU_*B^6OSleBX=`bLy)jxgN`d)<=|uh
+E020*^DF6Tf
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_8.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_8.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..30c84410d417ef7afa8705c93cdb64a9f4e915a0
+GIT binary patch
+literal 512
+zcmY!u<Y9JIWZ+;(U|?oqW&i?q-XHZ040(BZf(&^dxD+@TSQ$QOn`kgpFo@WI<f#GX
+zYz3L}{MzzRenxp}7)YiWinU~FgllWifig`TL)=Uajm%6uqI8Yijh&1X6cmgabe!NS
+H2PXpn6CD!Q
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_9.bin b/src/mainboard/lenovo/sklkbl_thinkpad/variants/t480s/spd/spd_9.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..7facef55b93fe1f67411c00bab84862769461f63
+GIT binary patch
+literal 512
+zcmY!u<Y8`AWZ+;(U|?osW&i?q-XHZ040(BZf(&^dxD+@TSQ%DGYiKZ3Fo@WI<f#GX
+zYz3L}{F>W!enxp}7)YiWinU~FgllWifig`TLxK(6%}hL^bdB7N9Ss$Lz^FmT39fQ*
+FG5`?&65ap+
+
+literal 0
+HcmV?d00001
+
+--
+2.39.5
+
diff --git a/config/coreboot/default/patches/0029-mb-dell-Add-Optiplex-780-MT-x4x-ICH10.patch b/config/coreboot/default/patches/0029-mb-dell-Add-Optiplex-780-MT-x4x-ICH10.patch
new file mode 100644
index 00000000..eb9263b9
--- /dev/null
+++ b/config/coreboot/default/patches/0029-mb-dell-Add-Optiplex-780-MT-x4x-ICH10.patch
@@ -0,0 +1,708 @@
+From 75cc0ea09234064318046624845b0afc5afb0ce5 Mon Sep 17 00:00:00 2001
+From: Nicholas Chin <nic.c3.14@gmail.com>
+Date: Mon, 30 Sep 2024 20:44:38 -0400
+Subject: [PATCH 29/37] mb/dell: Add Optiplex 780 MT (x4x/ICH10)
+
+Change-Id: Idb45737ce95bfd26e978323c650de7d308b5079c
+Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>
+---
+ src/mainboard/dell/optiplex_780/Kconfig | 40 ++++
+ src/mainboard/dell/optiplex_780/Kconfig.name | 4 +
+ src/mainboard/dell/optiplex_780/Makefile.mk | 10 +
+ src/mainboard/dell/optiplex_780/acpi/ec.asl | 5 +
+ .../dell/optiplex_780/acpi/ich10_pci_irqs.asl | 32 ++++
+ .../dell/optiplex_780/acpi/superio.asl | 18 ++
+ .../dell/optiplex_780/board_info.txt | 6 +
+ src/mainboard/dell/optiplex_780/cmos.default | 8 +
+ src/mainboard/dell/optiplex_780/cmos.layout | 72 ++++++++
+ src/mainboard/dell/optiplex_780/cstates.c | 8 +
+ src/mainboard/dell/optiplex_780/devicetree.cb | 63 +++++++
+ src/mainboard/dell/optiplex_780/dsdt.asl | 26 +++
+ .../dell/optiplex_780/gma-mainboard.ads | 16 ++
+ .../optiplex_780/variants/780_mt/data.vbt | Bin 0 -> 1917 bytes
+ .../optiplex_780/variants/780_mt/early_init.c | 12 ++
+ .../dell/optiplex_780/variants/780_mt/gpio.c | 174 ++++++++++++++++++
+ .../optiplex_780/variants/780_mt/hda_verb.c | 26 +++
+ .../variants/780_mt/overridetree.cb | 10 +
+ 18 files changed, 530 insertions(+)
+ create mode 100644 src/mainboard/dell/optiplex_780/Kconfig
+ create mode 100644 src/mainboard/dell/optiplex_780/Kconfig.name
+ create mode 100644 src/mainboard/dell/optiplex_780/Makefile.mk
+ create mode 100644 src/mainboard/dell/optiplex_780/acpi/ec.asl
+ create mode 100644 src/mainboard/dell/optiplex_780/acpi/ich10_pci_irqs.asl
+ create mode 100644 src/mainboard/dell/optiplex_780/acpi/superio.asl
+ create mode 100644 src/mainboard/dell/optiplex_780/board_info.txt
+ create mode 100644 src/mainboard/dell/optiplex_780/cmos.default
+ create mode 100644 src/mainboard/dell/optiplex_780/cmos.layout
+ create mode 100644 src/mainboard/dell/optiplex_780/cstates.c
+ create mode 100644 src/mainboard/dell/optiplex_780/devicetree.cb
+ create mode 100644 src/mainboard/dell/optiplex_780/dsdt.asl
+ create mode 100644 src/mainboard/dell/optiplex_780/gma-mainboard.ads
+ create mode 100644 src/mainboard/dell/optiplex_780/variants/780_mt/data.vbt
+ create mode 100644 src/mainboard/dell/optiplex_780/variants/780_mt/early_init.c
+ create mode 100644 src/mainboard/dell/optiplex_780/variants/780_mt/gpio.c
+ create mode 100644 src/mainboard/dell/optiplex_780/variants/780_mt/hda_verb.c
+ create mode 100644 src/mainboard/dell/optiplex_780/variants/780_mt/overridetree.cb
+
+diff --git a/src/mainboard/dell/optiplex_780/Kconfig b/src/mainboard/dell/optiplex_780/Kconfig
+new file mode 100644
+index 0000000000..2d06c75c9a
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/Kconfig
+@@ -0,0 +1,40 @@
++## SPDX-License-Identifier: GPL-2.0-only
++
++config BOARD_DELL_OPTIPLEX_780_COMMON
++ def_bool n
++ select BOARD_ROMSIZE_KB_8192
++ select CPU_INTEL_SOCKET_LGA775
++ select DRIVERS_I2C_CK505
++ select HAVE_ACPI_RESUME
++ select HAVE_ACPI_TABLES
++ select HAVE_CMOS_DEFAULT
++ select HAVE_OPTION_TABLE
++ select INTEL_GMA_HAVE_VBT
++ select MAINBOARD_HAS_LIBGFXINIT
++ select MAINBOARD_USES_IFD_GBE_REGION
++ select NORTHBRIDGE_INTEL_X4X
++ select PCIEXP_ASPM
++ select PCIEXP_CLK_PM
++ select SOUTHBRIDGE_INTEL_I82801JX
++
++config BOARD_DELL_OPTIPLEX_780_MT
++ select BOARD_DELL_OPTIPLEX_780_COMMON
++
++if BOARD_DELL_OPTIPLEX_780_COMMON
++
++config VGA_BIOS_ID
++ default "8086,2e22"
++
++config MAINBOARD_DIR
++ default "dell/optiplex_780"
++
++config MAINBOARD_PART_NUMBER
++ default "OptiPlex 780 MT" if BOARD_DELL_OPTIPLEX_780_MT
++
++config OVERRIDE_DEVICETREE
++ default "variants/\$(CONFIG_VARIANT_DIR)/overridetree.cb"
++
++config VARIANT_DIR
++ default "780_mt" if BOARD_DELL_OPTIPLEX_780_MT
++
++endif # BOARD_DELL_OPTIPLEX_780_COMMON
+diff --git a/src/mainboard/dell/optiplex_780/Kconfig.name b/src/mainboard/dell/optiplex_780/Kconfig.name
+new file mode 100644
+index 0000000000..db7f2e8fe3
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/Kconfig.name
+@@ -0,0 +1,4 @@
++## SPDX-License-Identifier: GPL-2.0-only
++
++config BOARD_DELL_OPTIPLEX_780_MT
++ bool "OptiPlex 780 MT"
+diff --git a/src/mainboard/dell/optiplex_780/Makefile.mk b/src/mainboard/dell/optiplex_780/Makefile.mk
+new file mode 100644
+index 0000000000..d462995d75
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/Makefile.mk
+@@ -0,0 +1,10 @@
++# SPDX-License-Identifier: GPL-2.0-only
++
++ramstage-y += cstates.c
++romstage-y += variants/$(VARIANT_DIR)/gpio.c
++
++bootblock-y += variants/$(VARIANT_DIR)/early_init.c
++romstage-y += variants/$(VARIANT_DIR)/early_init.c
++
++ramstage-$(CONFIG_MAINBOARD_USE_LIBGFXINIT) += gma-mainboard.ads
++ramstage-y += variants/$(VARIANT_DIR)/hda_verb.c
+diff --git a/src/mainboard/dell/optiplex_780/acpi/ec.asl b/src/mainboard/dell/optiplex_780/acpi/ec.asl
+new file mode 100644
+index 0000000000..479296cb76
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/acpi/ec.asl
+@@ -0,0 +1,5 @@
++/* SPDX-License-Identifier: CC-PDDC */
++
++/* Please update the license if adding licensable material. */
++
++/* dummy */
+diff --git a/src/mainboard/dell/optiplex_780/acpi/ich10_pci_irqs.asl b/src/mainboard/dell/optiplex_780/acpi/ich10_pci_irqs.asl
+new file mode 100644
+index 0000000000..b7588dcc41
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/acpi/ich10_pci_irqs.asl
+@@ -0,0 +1,32 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++/* This is board specific information:
++ * IRQ routing for the 0:1e.0 PCI bridge of the ICH10
++ */
++
++If (PICM) {
++ Return (Package() {
++ /* PCI slot */
++ Package() { 0x0001ffff, 0, 0, 0x14},
++ Package() { 0x0001ffff, 1, 0, 0x15},
++ Package() { 0x0001ffff, 2, 0, 0x16},
++ Package() { 0x0001ffff, 3, 0, 0x17},
++
++ Package() { 0x0002ffff, 0, 0, 0x15},
++ Package() { 0x0002ffff, 1, 0, 0x16},
++ Package() { 0x0002ffff, 2, 0, 0x17},
++ Package() { 0x0002ffff, 3, 0, 0x14},
++ })
++} Else {
++ Return (Package() {
++ Package() { 0x0001ffff, 0, \_SB.PCI0.LPCB.LNKE, 0},
++ Package() { 0x0001ffff, 1, \_SB.PCI0.LPCB.LNKF, 0},
++ Package() { 0x0001ffff, 2, \_SB.PCI0.LPCB.LNKG, 0},
++ Package() { 0x0001ffff, 3, \_SB.PCI0.LPCB.LNKH, 0},
++
++ Package() { 0x0002ffff, 0, \_SB.PCI0.LPCB.LNKF, 0},
++ Package() { 0x0002ffff, 1, \_SB.PCI0.LPCB.LNKG, 0},
++ Package() { 0x0002ffff, 2, \_SB.PCI0.LPCB.LNKH, 0},
++ Package() { 0x0002ffff, 3, \_SB.PCI0.LPCB.LNKE, 0},
++ })
++}
+diff --git a/src/mainboard/dell/optiplex_780/acpi/superio.asl b/src/mainboard/dell/optiplex_780/acpi/superio.asl
+new file mode 100644
+index 0000000000..9f3900b86c
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/acpi/superio.asl
+@@ -0,0 +1,18 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#undef SUPERIO_DEV
++#undef SUPERIO_PNP_BASE
++#undef IT8720F_SHOW_SP1
++#undef IT8720F_SHOW_SP2
++#undef IT8720F_SHOW_EC
++#undef IT8720F_SHOW_KBCK
++#undef IT8720F_SHOW_KBCM
++#undef IT8720F_SHOW_GPIO
++#undef IT8720F_SHOW_CIR
++#define SUPERIO_DEV SIO0
++#define SUPERIO_PNP_BASE 0x2e
++#define IT8720F_SHOW_EC 1
++#define IT8720F_SHOW_KBCK 1
++#define IT8720F_SHOW_KBCM 1
++#define IT8720F_SHOW_GPIO 1
++#include <superio/ite/it8720f/acpi/superio.asl>
+diff --git a/src/mainboard/dell/optiplex_780/board_info.txt b/src/mainboard/dell/optiplex_780/board_info.txt
+new file mode 100644
+index 0000000000..aaf657b583
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/board_info.txt
+@@ -0,0 +1,6 @@
++Category: desktop
++Board URL: https://www.acer.com/ac/en/GB/content/support-product/1137?b=1
++ROM package: SOIC-8
++ROM protocol: SPI
++ROM socketed: n
++Flashrom support: y
+diff --git a/src/mainboard/dell/optiplex_780/cmos.default b/src/mainboard/dell/optiplex_780/cmos.default
+new file mode 100644
+index 0000000000..23f0e55f3e
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/cmos.default
+@@ -0,0 +1,8 @@
++## SPDX-License-Identifier: GPL-2.0-only
++
++boot_option=Fallback
++debug_level=Debug
++power_on_after_fail=Disable
++nmi=Enable
++sata_mode=AHCI
++gfx_uma_size=64M
+diff --git a/src/mainboard/dell/optiplex_780/cmos.layout b/src/mainboard/dell/optiplex_780/cmos.layout
+new file mode 100644
+index 0000000000..9f5012adb4
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/cmos.layout
+@@ -0,0 +1,72 @@
++## SPDX-License-Identifier: GPL-2.0-only
++
++# -----------------------------------------------------------------
++entries
++
++# -----------------------------------------------------------------
++0 120 r 0 reserved_memory
++
++# -----------------------------------------------------------------
++# RTC_BOOT_BYTE (coreboot hardcoded)
++384 1 e 4 boot_option
++388 4 h 0 reboot_counter
++
++# -----------------------------------------------------------------
++# coreboot config options: console
++395 4 e 6 debug_level
++
++# coreboot config options: southbridge
++408 1 e 10 sata_mode
++409 2 e 7 power_on_after_fail
++411 1 e 1 nmi
++
++# coreboot config options: cpu
++
++# coreboot config options: northbridge
++432 4 e 11 gfx_uma_size
++
++# coreboot config options: check sums
++984 16 h 0 check_sum
++
++# -----------------------------------------------------------------
++
++enumerations
++
++#ID value text
++1 0 Disable
++1 1 Enable
++2 0 Enable
++2 1 Disable
++4 0 Fallback
++4 1 Normal
++6 0 Emergency
++6 1 Alert
++6 2 Critical
++6 3 Error
++6 4 Warning
++6 5 Notice
++6 6 Info
++6 7 Debug
++6 8 Spew
++7 0 Disable
++7 1 Enable
++7 2 Keep
++10 0 AHCI
++10 1 Compatible
++11 1 4M
++11 2 8M
++11 3 16M
++11 4 32M
++11 5 48M
++11 6 64M
++11 7 128M
++11 8 256M
++11 9 96M
++11 10 160M
++11 11 224M
++11 12 352M
++
++# -----------------------------------------------------------------
++checksums
++
++checksum 392 983 984
+diff --git a/src/mainboard/dell/optiplex_780/cstates.c b/src/mainboard/dell/optiplex_780/cstates.c
+new file mode 100644
+index 0000000000..4adf0edc63
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/cstates.c
+@@ -0,0 +1,8 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#include <acpi/acpigen.h>
++
++int get_cst_entries(const acpi_cstate_t **entries)
++{
++ return 0;
++}
+diff --git a/src/mainboard/dell/optiplex_780/devicetree.cb b/src/mainboard/dell/optiplex_780/devicetree.cb
+new file mode 100644
+index 0000000000..95e3bd517c
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/devicetree.cb
+@@ -0,0 +1,63 @@
++# SPDX-License-Identifier: GPL-2.0-or-later
++
++chip northbridge/intel/x4x
++ device cpu_cluster 0 on ops x4x_cpu_bus_ops end # APIC cluster
++ device domain 0 on
++ ops x4x_pci_domain_ops # PCI domain
++ subsystemid 0x8086 0x0028 inherit
++ device pci 0.0 on end # Host Bridge
++ device pci 1.0 on end # PCIe x16 2.0 slot
++ device pci 2.0 on end # Integrated graphics controller
++ device pci 2.1 on end # Integrated graphics controller 2
++ device pci 3.0 off end # ME
++ device pci 3.1 off end # ME
++ chip southbridge/intel/i82801jx # ICH10
++ register "gpe0_en" = "0x40"
++
++ # Set AHCI mode.
++ register "sata_port_map" = "0x3f"
++ register "sata_clock_request" = "1"
++
++ # Enable PCIe ports 0,1 as slots.
++ register "pcie_slot_implemented" = "0x3"
++
++ device pci 19.0 on end # GBE
++ device pci 1a.0 on end # USB
++ device pci 1a.1 on end # USB
++ device pci 1a.2 on end # USB
++ device pci 1a.7 on end # USB
++ device pci 1b.0 on end # Audio
++ device pci 1c.0 off end # PCIe 1
++ device pci 1c.1 off end # PCIe 2
++ device pci 1c.2 off end # PCIe 3
++ device pci 1c.3 off end # PCIe 4
++ device pci 1c.4 off end # PCIe 5
++ device pci 1c.5 off end # PCIe 6
++ device pci 1d.0 on end # USB
++ device pci 1d.1 on end # USB
++ device pci 1d.2 on end # USB
++ device pci 1d.7 on end # USB
++ device pci 1e.0 on end # PCI bridge
++ device pci 1f.0 on end # LPC bridge
++ device pci 1f.2 on end # SATA (IDE: port 0-3, AHCI/RAID: 0-5)
++ device pci 1f.3 on # SMBus
++ chip drivers/i2c/ck505 # IDT CV194
++ register "mask" = "{ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff }"
++ register "regs" = "{ 0x15, 0x82, 0xff, 0xff,
++ 0xff, 0x00, 0x00, 0x95,
++ 0x00, 0x65, 0x7d, 0x56,
++ 0x13, 0xc0, 0x00, 0x07,
++ 0x01, 0x0a, 0x64 }"
++ device i2c 69 on end
++ end
++ end
++ device pci 1f.4 off end
++ device pci 1f.5 off end # SATA 2 (for port 4-5 in IDE mode)
++ device pci 1f.6 off end # Thermal Subsystem
++ end
++ end
++end
+diff --git a/src/mainboard/dell/optiplex_780/dsdt.asl b/src/mainboard/dell/optiplex_780/dsdt.asl
+new file mode 100644
+index 0000000000..9ad70469de
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/dsdt.asl
+@@ -0,0 +1,26 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#include <acpi/acpi.h>
++DefinitionBlock(
++ "dsdt.aml",
++ "DSDT",
++ ACPI_DSDT_REV_2,
++ OEM_ID,
++ ACPI_TABLE_CREATOR,
++ 0x20090811 // OEM revision
++)
++{
++ #include <acpi/dsdt_top.asl>
++
++ OSYS = 2002
++ // global NVS and variables
++ #include <southbridge/intel/common/acpi/platform.asl>
++
++ Device (\_SB.PCI0)
++ {
++ #include <northbridge/intel/x4x/acpi/x4x.asl>
++ #include <southbridge/intel/i82801jx/acpi/ich10.asl>
++ }
++
++ #include <southbridge/intel/common/acpi/sleepstates.asl>
++}
+diff --git a/src/mainboard/dell/optiplex_780/gma-mainboard.ads b/src/mainboard/dell/optiplex_780/gma-mainboard.ads
+new file mode 100644
+index 0000000000..bc81cf4a40
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/gma-mainboard.ads
+@@ -0,0 +1,16 @@
++-- SPDX-License-Identifier: GPL-2.0-or-later
++
++with HW.GFX.GMA;
++with HW.GFX.GMA.Display_Probing;
++
++use HW.GFX.GMA;
++use HW.GFX.GMA.Display_Probing;
++
++private package GMA.Mainboard is
++
++ ports : constant Port_List :=
++ (DP2,
++ Analog,
++ others => Disabled);
++
++end GMA.Mainboard;
+diff --git a/src/mainboard/dell/optiplex_780/variants/780_mt/data.vbt b/src/mainboard/dell/optiplex_780/variants/780_mt/data.vbt
+new file mode 100644
+index 0000000000000000000000000000000000000000..fefda9d6f226b88ab67c5b044de30a707df22fbf
+GIT binary patch
+literal 1917
+zcmd6nO>7%Q6vzLwGv0Mv$FUpJ*ik4iQd_wnX*X`M0y3~p?8a$~>ZXxZMU`4dc9RGb
+zTXq_i1Bwd~aNr{c4i)r(goF^M-nek+sY0sMa}Sk>xFFy_FTEfX^Y+7unt+OgkeJbX
+zznS;`v-5V=o<pVaS;}Q53%NpOI!8{cz{K0eVfK65_|*A}SF)Me%$4!N`H5-z90%~a
+zvGog3fe5LjnM&o#3$<#k{6>{ZwwmnN>gY?}>{`7^JBpP$l`EBIwbi0*k&aU)n@v)E
+znI_A1T57efS5MG<y}m-_+CrVKE#0VADDft%nb#Y<<ao9;Mf?!XvM)_$Xla>NN5_ut
+zt=x`G)EjR#mlhURC^2!A3p33TcBg4-d8JyTiF&hfk}|a#&Dfe2%~V^}=4!QavNzBh
+z0Pae^5`gfb?<R!YN+PQ)U7<%H;73qF3iyQT71$?W2s|f{69_4sRY(x>7Q)c(LsP)8
+zQy)2gw<F#IP`I}U>gG1S^>aw&0D}Z+-SCcJJF;s)yXJeQ|4N{SU?$I`#$HZa<Jq(M
+zbA{r}Z0XY6<@U{Y-d!KWR>9dWBuxA$6X;VK;%W?Y>I;0P`|*vwAK$S(VB2JSq6g4n
+z>oEf8XCt;_Y-iYBWz#<re{?il1^f{S#nht`VW!62^5R*KQ6_?#8e&Qw=9%`og2x!s
+z&J)wlZ=a<yoJkutfwu4%aVXlu?i^8v?R77IyGvKcD|M`CFG$6FUmK8q<|o>3T9EmJ
+z2x?*GPeN%?=Fj3+fv~4%I(nv~XF7VOqi5RsAt%13JtW>q=<<<Gei4)FzWqGEt6P8D
+zA9m}s>;0IkLPSUGL%_1h)2kjaZzuV;`43yCV;I=#Jcyyw@xKE8GGX39@am|0GKhH`
+zawsKv^FvHqm+<DDPT)%}_kZ8^eT88YGmG-#)X3=RRB|L^Uj_{yd%JeO<1HRZVz=Fz
+z+aqUCWdF3_={#Q&&k)eF1i=WV`AbSlzo*bP?x?ir5BVVO`R34f89jWL{Z}or^BwmG
+z-E;A_iWVUUWnWQl3L|~0xA@rHJRA-;7V)Y6B5=@E8R@?(?5{Eh23RefpSOGX_F{8A
+z1PtU+iNng^h#C7J<vufJ9>c8*FfFsu??w)Oed@;Mg~21%rCZ%d{x!>-zmv4AyWL1E
+xfz+CGUnQ7Y^TD}&c_cQRYlBC+`?m?k6Nuw??s04gg4@4`<@FO{XEbO(<xf!`#Pk3F
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/dell/optiplex_780/variants/780_mt/early_init.c b/src/mainboard/dell/optiplex_780/variants/780_mt/early_init.c
+new file mode 100644
+index 0000000000..e2fa05cd8f
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/variants/780_mt/early_init.c
+@@ -0,0 +1,12 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++
++#include <northbridge/intel/x4x/x4x.h>
++
++void mb_get_spd_map(u8 spd_map[4])
++{
++ // BTX form factor
++ spd_map[0] = 0x53;
++ spd_map[1] = 0x52;
++ spd_map[2] = 0x51;
++ spd_map[3] = 0x50;
++}
+diff --git a/src/mainboard/dell/optiplex_780/variants/780_mt/gpio.c b/src/mainboard/dell/optiplex_780/variants/780_mt/gpio.c
+new file mode 100644
+index 0000000000..9993f17c55
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/variants/780_mt/gpio.c
+@@ -0,0 +1,174 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#include <southbridge/intel/common/gpio.h>
++
++static const struct pch_gpio_set1 pch_gpio_set1_mode = {
++ .gpio0 = GPIO_MODE_NATIVE,
++ .gpio1 = GPIO_MODE_NATIVE,
++ .gpio2 = GPIO_MODE_GPIO,
++ .gpio3 = GPIO_MODE_GPIO,
++ .gpio4 = GPIO_MODE_GPIO,
++ .gpio5 = GPIO_MODE_GPIO,
++ .gpio6 = GPIO_MODE_GPIO,
++ .gpio7 = GPIO_MODE_NATIVE,
++ .gpio8 = GPIO_MODE_NATIVE,
++ .gpio9 = GPIO_MODE_GPIO,
++ .gpio10 = GPIO_MODE_GPIO,
++ .gpio11 = GPIO_MODE_NATIVE,
++ .gpio12 = GPIO_MODE_NATIVE,
++ .gpio13 = GPIO_MODE_GPIO,
++ .gpio14 = GPIO_MODE_GPIO,
++ .gpio15 = GPIO_MODE_NATIVE,
++ .gpio16 = GPIO_MODE_GPIO,
++ .gpio17 = GPIO_MODE_NATIVE,
++ .gpio18 = GPIO_MODE_GPIO,
++ .gpio19 = GPIO_MODE_GPIO,
++ .gpio20 = GPIO_MODE_GPIO,
++ .gpio21 = GPIO_MODE_GPIO,
++ .gpio22 = GPIO_MODE_GPIO,
++ .gpio23 = GPIO_MODE_NATIVE,
++ .gpio24 = GPIO_MODE_GPIO,
++ .gpio25 = GPIO_MODE_NATIVE,
++ .gpio26 = GPIO_MODE_NATIVE,
++ .gpio27 = GPIO_MODE_GPIO,
++ .gpio28 = GPIO_MODE_GPIO,
++ .gpio29 = GPIO_MODE_GPIO,
++ .gpio30 = GPIO_MODE_GPIO,
++ .gpio31 = GPIO_MODE_GPIO,
++};
++
++static const struct pch_gpio_set1 pch_gpio_set1_direction = {
++ .gpio2 = GPIO_DIR_INPUT,
++ .gpio3 = GPIO_DIR_INPUT,
++ .gpio4 = GPIO_DIR_INPUT,
++ .gpio5 = GPIO_DIR_INPUT,
++ .gpio6 = GPIO_DIR_INPUT,
++ .gpio9 = GPIO_DIR_OUTPUT,
++ .gpio10 = GPIO_DIR_INPUT,
++ .gpio13 = GPIO_DIR_INPUT,
++ .gpio14 = GPIO_DIR_INPUT,
++ .gpio16 = GPIO_DIR_INPUT,
++ .gpio18 = GPIO_DIR_OUTPUT,
++ .gpio19 = GPIO_DIR_INPUT,
++ .gpio20 = GPIO_DIR_OUTPUT,
++ .gpio21 = GPIO_DIR_INPUT,
++ .gpio22 = GPIO_DIR_INPUT,
++ .gpio24 = GPIO_DIR_INPUT,
++ .gpio27 = GPIO_DIR_INPUT,
++ .gpio28 = GPIO_DIR_OUTPUT,
++ .gpio29 = GPIO_DIR_INPUT,
++ .gpio30 = GPIO_DIR_INPUT,
++ .gpio31 = GPIO_DIR_INPUT,
++};
++
++static const struct pch_gpio_set1 pch_gpio_set1_level = {
++ .gpio9 = GPIO_LEVEL_HIGH,
++ .gpio18 = GPIO_LEVEL_HIGH,
++ .gpio20 = GPIO_LEVEL_HIGH,
++ .gpio28 = GPIO_LEVEL_LOW,
++};
++
++static const struct pch_gpio_set1 pch_gpio_set1_blink = {
++};
++
++static const struct pch_gpio_set1 pch_gpio_set1_invert = {
++ .gpio13 = GPIO_INVERT,
++};
++
++static const struct pch_gpio_set2 pch_gpio_set2_mode = {
++ .gpio32 = GPIO_MODE_GPIO,
++ .gpio33 = GPIO_MODE_GPIO,
++ .gpio34 = GPIO_MODE_GPIO,
++ .gpio35 = GPIO_MODE_GPIO,
++ .gpio36 = GPIO_MODE_GPIO,
++ .gpio37 = GPIO_MODE_GPIO,
++ .gpio38 = GPIO_MODE_GPIO,
++ .gpio39 = GPIO_MODE_GPIO,
++ .gpio40 = GPIO_MODE_NATIVE,
++ .gpio41 = GPIO_MODE_NATIVE,
++ .gpio42 = GPIO_MODE_NATIVE,
++ .gpio43 = GPIO_MODE_NATIVE,
++ .gpio44 = GPIO_MODE_NATIVE,
++ .gpio45 = GPIO_MODE_NATIVE,
++ .gpio46 = GPIO_MODE_NATIVE,
++ .gpio47 = GPIO_MODE_NATIVE,
++ .gpio48 = GPIO_MODE_GPIO,
++ .gpio49 = GPIO_MODE_GPIO,
++ .gpio50 = GPIO_MODE_NATIVE,
++ .gpio51 = GPIO_MODE_NATIVE,
++ .gpio52 = GPIO_MODE_NATIVE,
++ .gpio53 = GPIO_MODE_NATIVE,
++ .gpio54 = GPIO_MODE_GPIO,
++ .gpio55 = GPIO_MODE_NATIVE,
++ .gpio56 = GPIO_MODE_GPIO,
++ .gpio57 = GPIO_MODE_GPIO,
++ .gpio58 = GPIO_MODE_NATIVE,
++ .gpio59 = GPIO_MODE_NATIVE,
++ .gpio60 = GPIO_MODE_GPIO,
++ .gpio61 = GPIO_MODE_NATIVE,
++ .gpio62 = GPIO_MODE_NATIVE,
++ .gpio63 = GPIO_MODE_NATIVE,
++};
++
++static const struct pch_gpio_set2 pch_gpio_set2_direction = {
++ .gpio32 = GPIO_DIR_INPUT,
++ .gpio33 = GPIO_DIR_INPUT,
++ .gpio34 = GPIO_DIR_INPUT,
++ .gpio35 = GPIO_DIR_OUTPUT,
++ .gpio36 = GPIO_DIR_INPUT,
++ .gpio37 = GPIO_DIR_INPUT,
++ .gpio38 = GPIO_DIR_INPUT,
++ .gpio39 = GPIO_DIR_INPUT,
++ .gpio48 = GPIO_DIR_INPUT,
++ .gpio49 = GPIO_DIR_OUTPUT,
++ .gpio54 = GPIO_DIR_INPUT,
++ .gpio56 = GPIO_DIR_OUTPUT,
++ .gpio57 = GPIO_DIR_INPUT,
++ .gpio60 = GPIO_DIR_OUTPUT,
++};
++
++static const struct pch_gpio_set2 pch_gpio_set2_level = {
++ .gpio35 = GPIO_LEVEL_LOW,
++ .gpio49 = GPIO_LEVEL_HIGH,
++ .gpio56 = GPIO_LEVEL_HIGH,
++ .gpio60 = GPIO_LEVEL_LOW,
++};
++
++static const struct pch_gpio_set3 pch_gpio_set3_mode = {
++ .gpio64 = GPIO_MODE_NATIVE,
++ .gpio65 = GPIO_MODE_NATIVE,
++ .gpio66 = GPIO_MODE_NATIVE,
++ .gpio67 = GPIO_MODE_NATIVE,
++ .gpio68 = GPIO_MODE_NATIVE,
++ .gpio69 = GPIO_MODE_NATIVE,
++ .gpio70 = GPIO_MODE_NATIVE,
++ .gpio71 = GPIO_MODE_NATIVE,
++ .gpio72 = GPIO_MODE_GPIO,
++};
++
++static const struct pch_gpio_set3 pch_gpio_set3_direction = {
++ .gpio72 = GPIO_DIR_INPUT,
++};
++
++static const struct pch_gpio_set3 pch_gpio_set3_level = {
++};
++
++const struct pch_gpio_map mainboard_gpio_map = {
++ .set1 = {
++ .mode = &pch_gpio_set1_mode,
++ .direction = &pch_gpio_set1_direction,
++ .level = &pch_gpio_set1_level,
++ .blink = &pch_gpio_set1_blink,
++ .invert = &pch_gpio_set1_invert,
++ },
++ .set2 = {
++ .mode = &pch_gpio_set2_mode,
++ .direction = &pch_gpio_set2_direction,
++ .level = &pch_gpio_set2_level,
++ },
++ .set3 = {
++ .mode = &pch_gpio_set3_mode,
++ .direction = &pch_gpio_set3_direction,
++ .level = &pch_gpio_set3_level,
++ },
++};
+diff --git a/src/mainboard/dell/optiplex_780/variants/780_mt/hda_verb.c b/src/mainboard/dell/optiplex_780/variants/780_mt/hda_verb.c
+new file mode 100644
+index 0000000000..4158bcf899
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/variants/780_mt/hda_verb.c
+@@ -0,0 +1,26 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++
++#include <device/azalia_device.h>
++
++const u32 cim_verb_data[] = {
++ /* coreboot specific header */
++ 0x11d4194a, /* Analog Devices AD1984A */
++ 0xbfd40000, /* Subsystem ID */
++ 10, /* Number of entries */
++
++ /* Pin Widget Verb Table */
++ AZALIA_PIN_CFG(0, 0x11, 0x032140f0),
++ AZALIA_PIN_CFG(0, 0x12, 0x21214010),
++ AZALIA_PIN_CFG(0, 0x13, 0x901701f0),
++ AZALIA_PIN_CFG(0, 0x14, 0x03a190f0),
++ AZALIA_PIN_CFG(0, 0x15, 0xb7a70121),
++ AZALIA_PIN_CFG(0, 0x16, 0x9933012e),
++ AZALIA_PIN_CFG(0, 0x17, 0x97a601f0),
++ AZALIA_PIN_CFG(0, 0x1a, 0x90f301f0),
++ AZALIA_PIN_CFG(0, 0x1b, 0x014510f0),
++ AZALIA_PIN_CFG(0, 0x1c, 0x21a19020),
++};
++
++const u32 pc_beep_verbs[0] = {};
++
++AZALIA_ARRAY_SIZES;
+diff --git a/src/mainboard/dell/optiplex_780/variants/780_mt/overridetree.cb b/src/mainboard/dell/optiplex_780/variants/780_mt/overridetree.cb
+new file mode 100644
+index 0000000000..555b1c1f5c
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/variants/780_mt/overridetree.cb
+@@ -0,0 +1,10 @@
++## SPDX-License-Identifier: GPL-2.0-or-later
++
++chip northbridge/intel/x4x
++ device domain 0 on
++ chip southbridge/intel/i82801jx
++ device pci 1c.0 on end # PCIe 1
++ device pci 1c.1 on end # PCIe 2
++ end
++ end
++end
+--
+2.39.5
+
diff --git a/config/coreboot/default/patches/0030-haswell-NRI-Initialise-MPLL.patch b/config/coreboot/default/patches/0030-haswell-NRI-Initialise-MPLL.patch
deleted file mode 100644
index a1cf9b75..00000000
--- a/config/coreboot/default/patches/0030-haswell-NRI-Initialise-MPLL.patch
+++ /dev/null
@@ -1,348 +0,0 @@
-From 0966980e52286985fcd0fac6325bdd99f35ebcb8 Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Thu, 11 Apr 2024 17:25:07 +0200
-Subject: [PATCH 30/51] haswell NRI: Initialise MPLL
-
-Add code to initialise the MPLL (Memory PLL). The procedure is similar
-to the one for Sandy/Ivy Bridge, but it is not worth factoring out.
-
-Change-Id: I978c352de68f6d8cecc76f4ae3c12daaf4be9ed6
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../intel/haswell/native_raminit/Makefile.mk | 2 +
- .../intel/haswell/native_raminit/init_mpll.c | 210 ++++++++++++++++++
- .../haswell/native_raminit/io_comp_control.c | 22 ++
- .../haswell/native_raminit/raminit_main.c | 3 +-
- .../haswell/native_raminit/raminit_native.h | 11 +
- .../intel/haswell/registers/mchbar.h | 3 +
- 6 files changed, 250 insertions(+), 1 deletion(-)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/init_mpll.c
- create mode 100644 src/northbridge/intel/haswell/native_raminit/io_comp_control.c
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-index ebf7abc6ec..c125d84f0b 100644
---- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-@@ -1,5 +1,7 @@
- ## SPDX-License-Identifier: GPL-2.0-or-later
-
-+romstage-y += init_mpll.c
-+romstage-y += io_comp_control.c
- romstage-y += raminit_main.c
- romstage-y += raminit_native.c
- romstage-y += spd_bitmunching.c
-diff --git a/src/northbridge/intel/haswell/native_raminit/init_mpll.c b/src/northbridge/intel/haswell/native_raminit/init_mpll.c
-new file mode 100644
-index 0000000000..1f3f2c29a9
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/init_mpll.c
-@@ -0,0 +1,210 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <commonlib/bsd/clamp.h>
-+#include <console/console.h>
-+#include <delay.h>
-+#include <device/pci_ops.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <types.h>
-+
-+#include "raminit_native.h"
-+
-+static uint32_t get_mem_multiplier(const struct sysinfo *ctrl)
-+{
-+ const uint32_t mult = NS2MHZ_DIV256 / (ctrl->tCK * ctrl->base_freq);
-+
-+ if (ctrl->base_freq == 100)
-+ return clamp_u32(7, mult, 12);
-+
-+ if (ctrl->base_freq == 133)
-+ return clamp_u32(3, mult, 10);
-+
-+ die("Unsupported base frequency\n");
-+}
-+
-+static void normalize_tck(struct sysinfo *ctrl, const bool pll_ref100)
-+{
-+ /** TODO: Haswell supports up to DDR3-2600 **/
-+ if (ctrl->tCK <= TCK_1200MHZ) {
-+ ctrl->tCK = TCK_1200MHZ;
-+ ctrl->base_freq = 133;
-+ ctrl->mem_clock_mhz = 1200;
-+
-+ } else if (ctrl->tCK <= TCK_1100MHZ) {
-+ ctrl->tCK = TCK_1100MHZ;
-+ ctrl->base_freq = 100;
-+ ctrl->mem_clock_mhz = 1100;
-+
-+ } else if (ctrl->tCK <= TCK_1066MHZ) {
-+ ctrl->tCK = TCK_1066MHZ;
-+ ctrl->base_freq = 133;
-+ ctrl->mem_clock_mhz = 1066;
-+
-+ } else if (ctrl->tCK <= TCK_1000MHZ) {
-+ ctrl->tCK = TCK_1000MHZ;
-+ ctrl->base_freq = 100;
-+ ctrl->mem_clock_mhz = 1000;
-+
-+ } else if (ctrl->tCK <= TCK_933MHZ) {
-+ ctrl->tCK = TCK_933MHZ;
-+ ctrl->base_freq = 133;
-+ ctrl->mem_clock_mhz = 933;
-+
-+ } else if (ctrl->tCK <= TCK_900MHZ) {
-+ ctrl->tCK = TCK_900MHZ;
-+ ctrl->base_freq = 100;
-+ ctrl->mem_clock_mhz = 900;
-+
-+ } else if (ctrl->tCK <= TCK_800MHZ) {
-+ ctrl->tCK = TCK_800MHZ;
-+ ctrl->base_freq = 133;
-+ ctrl->mem_clock_mhz = 800;
-+
-+ } else if (ctrl->tCK <= TCK_700MHZ) {
-+ ctrl->tCK = TCK_700MHZ;
-+ ctrl->base_freq = 100;
-+ ctrl->mem_clock_mhz = 700;
-+
-+ } else if (ctrl->tCK <= TCK_666MHZ) {
-+ ctrl->tCK = TCK_666MHZ;
-+ ctrl->base_freq = 133;
-+ ctrl->mem_clock_mhz = 666;
-+
-+ } else if (ctrl->tCK <= TCK_533MHZ) {
-+ ctrl->tCK = TCK_533MHZ;
-+ ctrl->base_freq = 133;
-+ ctrl->mem_clock_mhz = 533;
-+
-+ } else if (ctrl->tCK <= TCK_400MHZ) {
-+ ctrl->tCK = TCK_400MHZ;
-+ ctrl->base_freq = 133;
-+ ctrl->mem_clock_mhz = 400;
-+
-+ } else {
-+ ctrl->tCK = 0;
-+ ctrl->base_freq = 1;
-+ ctrl->mem_clock_mhz = 0;
-+ return;
-+ }
-+ if (!pll_ref100 && ctrl->base_freq == 100) {
-+ /* Skip unsupported frequency */
-+ ctrl->tCK++;
-+ normalize_tck(ctrl, pll_ref100);
-+ }
-+}
-+
-+#define MIN_CAS 4
-+#define MAX_CAS 24
-+
-+static uint8_t find_compatible_cas(struct sysinfo *ctrl)
-+{
-+ printk(RAM_DEBUG, "With tCK %u, try CAS: ", ctrl->tCK);
-+ const uint8_t cas_lower = MAX(MIN_CAS, DIV_ROUND_UP(ctrl->tAA, ctrl->tCK));
-+ const uint8_t cas_upper = MIN(MAX_CAS, 19); /* JEDEC MR0 limit */
-+
-+ if (!(ctrl->cas_supported >> (cas_lower - MIN_CAS))) {
-+ printk(RAM_DEBUG, "DIMMs do not support CAS >= %u\n", cas_lower);
-+ ctrl->tCK++;
-+ return 0;
-+ }
-+ for (uint8_t cas = cas_lower; cas <= cas_upper; cas++) {
-+ printk(RAM_DEBUG, "%u ", cas);
-+ if (ctrl->cas_supported & BIT(cas - MIN_CAS)) {
-+ printk(RAM_DEBUG, "OK\n");
-+ return cas;
-+ }
-+ }
-+ return 0;
-+}
-+
-+static enum raminit_status find_cas_tck(struct sysinfo *ctrl)
-+{
-+ /** TODO: Honor all possible PLL_REF100_CFG values **/
-+ uint8_t pll_ref100 = (pci_read_config32(HOST_BRIDGE, CAPID0_B) >> 21) & 0x7;
-+ printk(RAM_DEBUG, "PLL_REF100_CFG value: 0x%x\n", pll_ref100);
-+ printk(RAM_DEBUG, "100MHz reference clock support: %s\n", pll_ref100 ? "yes" : "no");
-+
-+ uint8_t selected_cas;
-+ while (true) {
-+ /* Round tCK up so that it is a multiple of either 133 or 100 MHz */
-+ normalize_tck(ctrl, pll_ref100);
-+ if (!ctrl->tCK) {
-+ printk(BIOS_ERR, "Couldn't find compatible clock / CAS settings\n");
-+ return RAMINIT_STATUS_MPLL_INIT_FAILURE;
-+ }
-+ selected_cas = find_compatible_cas(ctrl);
-+ if (selected_cas)
-+ break;
-+
-+ ctrl->tCK++;
-+ }
-+ printk(BIOS_DEBUG, "Found compatible clock / CAS settings\n");
-+ printk(BIOS_DEBUG, "Selected DRAM frequency: %u MHz\n", NS2MHZ_DIV256 / ctrl->tCK);
-+ printk(BIOS_DEBUG, "Selected CAS latency : %uT\n", selected_cas);
-+ ctrl->multiplier = get_mem_multiplier(ctrl);
-+ return RAMINIT_STATUS_SUCCESS;
-+}
-+
-+enum raminit_status initialise_mpll(struct sysinfo *ctrl)
-+{
-+ if (ctrl->tCK > TCK_400MHZ) {
-+ printk(BIOS_ERR, "tCK is too slow. Increasing to 400 MHz as last resort\n");
-+ ctrl->tCK = TCK_400MHZ;
-+ }
-+ while (true) {
-+ if (!ctrl->qclkps) {
-+ const enum raminit_status status = find_cas_tck(ctrl);
-+ if (status)
-+ return status;
-+ }
-+
-+ /*
-+ * Unlike previous generations, Haswell's MPLL won't shut down if the
-+ * requested frequency isn't supported. But we cannot reinitialize it.
-+ * Another different thing: MPLL registers are 4-bit instead of 8-bit.
-+ */
-+
-+ /** FIXME: Obtain current clock frequency if we want to skip this **/
-+ //if (mchbar_read32(MC_BIOS_DATA) != 0)
-+ // break;
-+
-+ uint32_t mc_bios_req = ctrl->multiplier;
-+ if (ctrl->base_freq == 100) {
-+ /* Use 100 MHz reference clock */
-+ mc_bios_req |= BIT(4);
-+ }
-+ mc_bios_req |= BIT(31);
-+ printk(RAM_DEBUG, "MC_BIOS_REQ = 0x%08x\n", mc_bios_req);
-+ printk(BIOS_DEBUG, "MPLL busy... ");
-+ mchbar_write32(MC_BIOS_REQ, mc_bios_req);
-+
-+ for (unsigned int i = 0; i <= 5000; i++) {
-+ if (!(mchbar_read32(MC_BIOS_REQ) & BIT(31))) {
-+ printk(BIOS_DEBUG, "done in %u us\n", i);
-+ break;
-+ }
-+ udelay(1);
-+ }
-+ if (mchbar_read32(MC_BIOS_REQ) & BIT(31))
-+ printk(BIOS_DEBUG, "did not lock\n");
-+
-+ /* Verify locked frequency */
-+ const uint32_t mc_bios_data = mchbar_read32(MC_BIOS_DATA);
-+ printk(RAM_DEBUG, "MC_BIOS_DATA = 0x%08x\n", mc_bios_data);
-+ if ((mc_bios_data & 0xf) >= ctrl->multiplier)
-+ break;
-+
-+ printk(BIOS_DEBUG, "Retrying at a lower frequency\n\n");
-+ ctrl->tCK++;
-+ }
-+ if (!ctrl->mem_clock_mhz) {
-+ printk(BIOS_ERR, "Could not program MPLL frequency\n");
-+ return RAMINIT_STATUS_MPLL_INIT_FAILURE;
-+ }
-+ printk(BIOS_DEBUG, "MPLL frequency is set to: %u MHz ", ctrl->mem_clock_mhz);
-+ ctrl->mem_clock_fs = 1000000000 / ctrl->mem_clock_mhz;
-+ printk(BIOS_DEBUG, "(period: %u femtoseconds)\n", ctrl->mem_clock_fs);
-+ ctrl->qclkps = ctrl->mem_clock_fs / 2000;
-+ printk(BIOS_DEBUG, "Quadrature clock period: %u picoseconds\n", ctrl->qclkps);
-+ return wait_for_first_rcomp();
-+}
-diff --git a/src/northbridge/intel/haswell/native_raminit/io_comp_control.c b/src/northbridge/intel/haswell/native_raminit/io_comp_control.c
-new file mode 100644
-index 0000000000..d45b608dd3
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/io_comp_control.c
-@@ -0,0 +1,22 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <commonlib/bsd/clamp.h>
-+#include <console/console.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <timer.h>
-+#include <types.h>
-+
-+#include "raminit_native.h"
-+
-+enum raminit_status wait_for_first_rcomp(void)
-+{
-+ struct stopwatch timer;
-+ stopwatch_init_msecs_expire(&timer, 2000);
-+ do {
-+ if (mchbar_read32(RCOMP_TIMER) & BIT(16))
-+ return RAMINIT_STATUS_SUCCESS;
-+
-+ } while (!stopwatch_expired(&timer));
-+ printk(BIOS_ERR, "Timed out waiting for RCOMP to complete\n");
-+ return RAMINIT_STATUS_POLL_TIMEOUT;
-+}
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-index 19ec5859ac..bf745e943f 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-@@ -19,7 +19,8 @@ struct task_entry {
- };
-
- static const struct task_entry cold_boot[] = {
-- { collect_spd_info, true, "PROCSPD", },
-+ { collect_spd_info, true, "PROCSPD", },
-+ { initialise_mpll, true, "INITMPLL", },
- };
-
- /* Return a generic stepping value to make stepping checks simpler */
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index 8078c9c386..15a1550424 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -24,6 +24,8 @@ enum raminit_status {
- RAMINIT_STATUS_SUCCESS = 0,
- RAMINIT_STATUS_NO_MEMORY_INSTALLED,
- RAMINIT_STATUS_UNSUPPORTED_MEMORY,
-+ RAMINIT_STATUS_MPLL_INIT_FAILURE,
-+ RAMINIT_STATUS_POLL_TIMEOUT,
- RAMINIT_STATUS_UNSPECIFIED_ERROR, /** TODO: Deprecated in favor of specific values **/
- };
-
-@@ -83,10 +85,19 @@ struct sysinfo {
- uint8_t rankmap[NUM_CHANNELS];
- uint8_t rank_mirrored[NUM_CHANNELS];
- uint32_t channel_size_mb[NUM_CHANNELS];
-+
-+ uint8_t base_freq; /* Memory base frequency, either 100 or 133 MHz */
-+ uint32_t multiplier;
-+ uint32_t mem_clock_mhz;
-+ uint32_t mem_clock_fs; /* Memory clock period in femtoseconds */
-+ uint32_t qclkps; /* Quadrature clock period in picoseconds */
- };
-
- void raminit_main(enum raminit_boot_mode bootmode);
-
- enum raminit_status collect_spd_info(struct sysinfo *ctrl);
-+enum raminit_status initialise_mpll(struct sysinfo *ctrl);
-+
-+enum raminit_status wait_for_first_rcomp(void);
-
- #endif
-diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
-index 5610e7089a..45f8174995 100644
---- a/src/northbridge/intel/haswell/registers/mchbar.h
-+++ b/src/northbridge/intel/haswell/registers/mchbar.h
-@@ -13,6 +13,8 @@
- #define MC_INIT_STATE_G 0x5030
- #define MRC_REVISION 0x5034 /* MRC Revision */
-
-+#define RCOMP_TIMER 0x5084
-+
- #define MC_LOCK 0x50fc /* Memory Controller Lock register */
-
- #define GFXVTBAR 0x5400 /* Base address for IGD */
-@@ -61,6 +63,7 @@
-
- #define BIOS_RESET_CPL 0x5da8 /* 8-bit */
-
-+#define MC_BIOS_REQ 0x5e00 /* Memory frequency request register */
- #define MC_BIOS_DATA 0x5e04 /* Miscellaneous information for BIOS */
- #define SAPMCTL 0x5f00
-
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0030-mb-dell-optiplex_780-Add-USFF-variant.patch b/config/coreboot/default/patches/0030-mb-dell-optiplex_780-Add-USFF-variant.patch
new file mode 100644
index 00000000..8ce7471b
--- /dev/null
+++ b/config/coreboot/default/patches/0030-mb-dell-optiplex_780-Add-USFF-variant.patch
@@ -0,0 +1,326 @@
+From 6725ec0bb976c61cbe87e61bf0e8b02e38d14de9 Mon Sep 17 00:00:00 2001
+From: Nicholas Chin <nic.c3.14@gmail.com>
+Date: Wed, 30 Oct 2024 20:55:25 -0600
+Subject: [PATCH 30/37] mb/dell/optiplex_780: Add USFF variant
+
+Change-Id: I3aa21c743749f4a11a2501f4c121316bd2f1a103
+Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>
+---
+ src/mainboard/dell/optiplex_780/Kconfig | 5 +
+ src/mainboard/dell/optiplex_780/Kconfig.name | 3 +
+ .../optiplex_780/variants/780_usff/data.vbt | Bin 0 -> 1917 bytes
+ .../variants/780_usff/early_init.c | 9 +
+ .../optiplex_780/variants/780_usff/gpio.c | 166 ++++++++++++++++++
+ .../optiplex_780/variants/780_usff/hda_verb.c | 26 +++
+ .../variants/780_usff/overridetree.cb | 10 ++
+ 7 files changed, 219 insertions(+)
+ create mode 100644 src/mainboard/dell/optiplex_780/variants/780_usff/data.vbt
+ create mode 100644 src/mainboard/dell/optiplex_780/variants/780_usff/early_init.c
+ create mode 100644 src/mainboard/dell/optiplex_780/variants/780_usff/gpio.c
+ create mode 100644 src/mainboard/dell/optiplex_780/variants/780_usff/hda_verb.c
+ create mode 100644 src/mainboard/dell/optiplex_780/variants/780_usff/overridetree.cb
+
+diff --git a/src/mainboard/dell/optiplex_780/Kconfig b/src/mainboard/dell/optiplex_780/Kconfig
+index 2d06c75c9a..fc649e35d5 100644
+--- a/src/mainboard/dell/optiplex_780/Kconfig
++++ b/src/mainboard/dell/optiplex_780/Kconfig
+@@ -20,6 +20,9 @@ config BOARD_DELL_OPTIPLEX_780_COMMON
+ config BOARD_DELL_OPTIPLEX_780_MT
+ select BOARD_DELL_OPTIPLEX_780_COMMON
+
++config BOARD_DELL_OPTIPLEX_780_USFF
++ select BOARD_DELL_OPTIPLEX_780_COMMON
++
+ if BOARD_DELL_OPTIPLEX_780_COMMON
+
+ config VGA_BIOS_ID
+@@ -30,11 +33,13 @@ config MAINBOARD_DIR
+
+ config MAINBOARD_PART_NUMBER
+ default "OptiPlex 780 MT" if BOARD_DELL_OPTIPLEX_780_MT
++ default "OptiPlex 780 USFF" if BOARD_DELL_OPTIPLEX_780_USFF
+
+ config OVERRIDE_DEVICETREE
+ default "variants/\$(CONFIG_VARIANT_DIR)/overridetree.cb"
+
+ config VARIANT_DIR
+ default "780_mt" if BOARD_DELL_OPTIPLEX_780_MT
++ default "780_usff" if BOARD_DELL_OPTIPLEX_780_USFF
+
+ endif # BOARD_DELL_OPTIPLEX_780_COMMON
+diff --git a/src/mainboard/dell/optiplex_780/Kconfig.name b/src/mainboard/dell/optiplex_780/Kconfig.name
+index db7f2e8fe3..bc84c82a79 100644
+--- a/src/mainboard/dell/optiplex_780/Kconfig.name
++++ b/src/mainboard/dell/optiplex_780/Kconfig.name
+@@ -2,3 +2,6 @@
+
+ config BOARD_DELL_OPTIPLEX_780_MT
+ bool "OptiPlex 780 MT"
++
++config BOARD_DELL_OPTIPLEX_780_USFF
++ bool "OptiPlex 780 USFF"
+diff --git a/src/mainboard/dell/optiplex_780/variants/780_usff/data.vbt b/src/mainboard/dell/optiplex_780/variants/780_usff/data.vbt
+new file mode 100644
+index 0000000000000000000000000000000000000000..dbd764f285ed18f7ee9c54bc777560138bd9b5f7
+GIT binary patch
+literal 1917
+zcmd6nO>7%Q6vzLwGv3{}j$^l`v7@w1q*9sEq+2(b3K>`@c5#TSx@i<uQKf!)+gO;|
+zveT#>P+W+B10OwbsGtX=N(gc4jSGjKDkP+yIUo^nsel8$^ny^9H?td8Ra=EiCEn=G
+z@6DV4?!2AdojnUv^Rirgvs$heXUkGs9S+{Jc2WPhP0buTak^BTFP@&N9-E$(UtuSX
+zS{r`=b+EX|Ig`2a*^5oDdG>8jE-1BBxs`*jgrf_sj_fP;%L|PwURRcCFBMCroNRQv
+zmp$2TUhc}qJMB(u#jDG@x6(N85thC4%Z=8hiN}lj&zb2~``u3C;?lCrPQOTnInFqB
+zhvdwqWv?lxTb=fVEH;~RPHDPw&g*&|s$pU<Iv53Rb6YTgMPOY8;~P1Yglh^6Fgt1^
+zCTz|SVPcSpZ44F@&oNPUMO@&BE3y(57YP_Y!4SZhE?GXYa7k+b0(X|s7u3GDRf^1#
+zOd2ZCCPO|I&sHEt;p8UshhHtYQ>7!7x2m<d`Gu2<r+Qc4|6pwd8&zFboH_W7XE7uU
+zWW-@Cim&mdY2!O{JANR)OTJG2z>LBtAF!g>K`zPnkx!DpPHuk6{_zc*0qi7)Aet$T
+z1ks@8hWS#+6cI5)j1oD86{5PX8Zu2(^OC6M`<pE+J?KFZ=&_JVP1YL=#z<-Q*24K4
+zn+$YxrHNJJc`k?_8N=Kres26_#E8GLn2{jfW5P%ge`kL(Btkt=>xo)V)Ow=U6P12c
+z=U0uNC9T9v{)-|#h(mSX*hSA8)ZeocL7l4J&!{RSO{6~oTtyn535j!RQh#GA*wTF8
+zvasRbO~d!?*FbM3K`W?lHx=v*(jiARIhWyh4^io|;n?@1H>uqJy>0sjV-Dt)_=%bE
+zgNO3D@uE5m+7aqi?Y8b+inye%Z=HUmgBtaZ3Lc%OLt+bo+)5BjVwT<{mxT`nde$vb
+zV99s{>`r76L#Hr6XW6r|<iq#4Jr?XsxKyeJKEj7;e4SZ^1B12u&iV_9M0*Kem@fmn
+z1C>>HT47I`**Q#Vu0QW!^VP-9S{xXzpq_zS#9k-;aXz?b+S!Ne$Kkk6dq<Gj{q2D(
+z>&Hj-x+kx1W-4#E&beDT*S)=&NoSE?<-w!G@~aW()0ZN4O&=Q+nZa)p%Vd$k-_$a=
+T#w3FFBiyj<XAh$hb(enud`r7S
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/mainboard/dell/optiplex_780/variants/780_usff/early_init.c b/src/mainboard/dell/optiplex_780/variants/780_usff/early_init.c
+new file mode 100644
+index 0000000000..2a55fc3a6e
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/variants/780_usff/early_init.c
+@@ -0,0 +1,9 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++
++#include <northbridge/intel/x4x/x4x.h>
++
++void mb_get_spd_map(u8 spd_map[4])
++{
++ spd_map[0] = 0x50;
++ spd_map[2] = 0x52;
++}
+diff --git a/src/mainboard/dell/optiplex_780/variants/780_usff/gpio.c b/src/mainboard/dell/optiplex_780/variants/780_usff/gpio.c
+new file mode 100644
+index 0000000000..389f4077d7
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/variants/780_usff/gpio.c
+@@ -0,0 +1,166 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++
++#include <southbridge/intel/common/gpio.h>
++
++static const struct pch_gpio_set1 pch_gpio_set1_mode = {
++ .gpio0 = GPIO_MODE_NATIVE,
++ .gpio1 = GPIO_MODE_NATIVE,
++ .gpio2 = GPIO_MODE_GPIO,
++ .gpio3 = GPIO_MODE_GPIO,
++ .gpio4 = GPIO_MODE_GPIO,
++ .gpio5 = GPIO_MODE_GPIO,
++ .gpio6 = GPIO_MODE_GPIO,
++ .gpio7 = GPIO_MODE_NATIVE,
++ .gpio8 = GPIO_MODE_NATIVE,
++ .gpio9 = GPIO_MODE_GPIO,
++ .gpio10 = GPIO_MODE_GPIO,
++ .gpio11 = GPIO_MODE_NATIVE,
++ .gpio12 = GPIO_MODE_NATIVE,
++ .gpio13 = GPIO_MODE_GPIO,
++ .gpio14 = GPIO_MODE_GPIO,
++ .gpio15 = GPIO_MODE_NATIVE,
++ .gpio16 = GPIO_MODE_GPIO,
++ .gpio17 = GPIO_MODE_NATIVE,
++ .gpio18 = GPIO_MODE_GPIO,
++ .gpio19 = GPIO_MODE_GPIO,
++ .gpio20 = GPIO_MODE_GPIO,
++ .gpio21 = GPIO_MODE_GPIO,
++ .gpio22 = GPIO_MODE_GPIO,
++ .gpio23 = GPIO_MODE_NATIVE,
++ .gpio24 = GPIO_MODE_GPIO,
++ .gpio25 = GPIO_MODE_NATIVE,
++ .gpio26 = GPIO_MODE_NATIVE,
++ .gpio27 = GPIO_MODE_GPIO,
++ .gpio28 = GPIO_MODE_GPIO,
++ .gpio29 = GPIO_MODE_GPIO,
++ .gpio30 = GPIO_MODE_GPIO,
++ .gpio31 = GPIO_MODE_GPIO,
++};
++
++static const struct pch_gpio_set1 pch_gpio_set1_direction = {
++ .gpio2 = GPIO_DIR_INPUT,
++ .gpio3 = GPIO_DIR_INPUT,
++ .gpio4 = GPIO_DIR_INPUT,
++ .gpio5 = GPIO_DIR_INPUT,
++ .gpio6 = GPIO_DIR_INPUT,
++ .gpio9 = GPIO_DIR_OUTPUT,
++ .gpio10 = GPIO_DIR_INPUT,
++ .gpio13 = GPIO_DIR_INPUT,
++ .gpio14 = GPIO_DIR_INPUT,
++ .gpio16 = GPIO_DIR_INPUT,
++ .gpio18 = GPIO_DIR_OUTPUT,
++ .gpio19 = GPIO_DIR_INPUT,
++ .gpio20 = GPIO_DIR_OUTPUT,
++ .gpio21 = GPIO_DIR_INPUT,
++ .gpio22 = GPIO_DIR_INPUT,
++ .gpio24 = GPIO_DIR_INPUT,
++ .gpio27 = GPIO_DIR_INPUT,
++ .gpio28 = GPIO_DIR_OUTPUT,
++ .gpio29 = GPIO_DIR_INPUT,
++ .gpio30 = GPIO_DIR_INPUT,
++ .gpio31 = GPIO_DIR_INPUT,
++};
++
++static const struct pch_gpio_set1 pch_gpio_set1_level = {
++ .gpio9 = GPIO_LEVEL_HIGH,
++ .gpio18 = GPIO_LEVEL_HIGH,
++ .gpio20 = GPIO_LEVEL_HIGH,
++ .gpio28 = GPIO_LEVEL_HIGH,
++};
++
++static const struct pch_gpio_set1 pch_gpio_set1_blink = {
++};
++
++static const struct pch_gpio_set1 pch_gpio_set1_invert = {
++ .gpio13 = GPIO_INVERT,
++};
++
++static const struct pch_gpio_set2 pch_gpio_set2_mode = {
++ .gpio32 = GPIO_MODE_GPIO,
++ .gpio33 = GPIO_MODE_GPIO,
++ .gpio34 = GPIO_MODE_GPIO,
++ .gpio35 = GPIO_MODE_GPIO,
++ .gpio36 = GPIO_MODE_GPIO,
++ .gpio37 = GPIO_MODE_GPIO,
++ .gpio38 = GPIO_MODE_GPIO,
++ .gpio39 = GPIO_MODE_GPIO,
++ .gpio40 = GPIO_MODE_NATIVE,
++ .gpio41 = GPIO_MODE_NATIVE,
++ .gpio42 = GPIO_MODE_NATIVE,
++ .gpio43 = GPIO_MODE_NATIVE,
++ .gpio44 = GPIO_MODE_NATIVE,
++ .gpio45 = GPIO_MODE_NATIVE,
++ .gpio46 = GPIO_MODE_NATIVE,
++ .gpio47 = GPIO_MODE_NATIVE,
++ .gpio48 = GPIO_MODE_GPIO,
++ .gpio49 = GPIO_MODE_GPIO,
++ .gpio50 = GPIO_MODE_NATIVE,
++ .gpio51 = GPIO_MODE_NATIVE,
++ .gpio52 = GPIO_MODE_NATIVE,
++ .gpio53 = GPIO_MODE_NATIVE,
++ .gpio54 = GPIO_MODE_GPIO,
++ .gpio55 = GPIO_MODE_NATIVE,
++ .gpio56 = GPIO_MODE_GPIO,
++ .gpio57 = GPIO_MODE_GPIO,
++ .gpio58 = GPIO_MODE_NATIVE,
++ .gpio59 = GPIO_MODE_NATIVE,
++ .gpio60 = GPIO_MODE_GPIO,
++ .gpio61 = GPIO_MODE_NATIVE,
++ .gpio62 = GPIO_MODE_NATIVE,
++ .gpio63 = GPIO_MODE_NATIVE,
++};
++
++static const struct pch_gpio_set2 pch_gpio_set2_direction = {
++ .gpio32 = GPIO_DIR_INPUT,
++ .gpio33 = GPIO_DIR_INPUT,
++ .gpio34 = GPIO_DIR_INPUT,
++ .gpio35 = GPIO_DIR_OUTPUT,
++ .gpio36 = GPIO_DIR_INPUT,
++ .gpio37 = GPIO_DIR_INPUT,
++ .gpio38 = GPIO_DIR_INPUT,
++ .gpio39 = GPIO_DIR_INPUT,
++ .gpio48 = GPIO_DIR_INPUT,
++ .gpio49 = GPIO_DIR_OUTPUT,
++ .gpio54 = GPIO_DIR_INPUT,
++ .gpio56 = GPIO_DIR_OUTPUT,
++ .gpio57 = GPIO_DIR_INPUT,
++ .gpio60 = GPIO_DIR_OUTPUT,
++};
++
++static const struct pch_gpio_set2 pch_gpio_set2_level = {
++ .gpio35 = GPIO_LEVEL_LOW,
++ .gpio49 = GPIO_LEVEL_HIGH,
++ .gpio56 = GPIO_LEVEL_HIGH,
++ .gpio60 = GPIO_LEVEL_LOW,
++};
++
++static const struct pch_gpio_set3 pch_gpio_set3_mode = {
++ .gpio72 = GPIO_MODE_GPIO,
++};
++
++static const struct pch_gpio_set3 pch_gpio_set3_direction = {
++ .gpio72 = GPIO_DIR_INPUT,
++};
++
++static const struct pch_gpio_set3 pch_gpio_set3_level = {
++};
++
++const struct pch_gpio_map mainboard_gpio_map = {
++ .set1 = {
++ .mode = &pch_gpio_set1_mode,
++ .direction = &pch_gpio_set1_direction,
++ .level = &pch_gpio_set1_level,
++ .blink = &pch_gpio_set1_blink,
++ .invert = &pch_gpio_set1_invert,
++ },
++ .set2 = {
++ .mode = &pch_gpio_set2_mode,
++ .direction = &pch_gpio_set2_direction,
++ .level = &pch_gpio_set2_level,
++ },
++ .set3 = {
++ .mode = &pch_gpio_set3_mode,
++ .direction = &pch_gpio_set3_direction,
++ .level = &pch_gpio_set3_level,
++ },
++};
+diff --git a/src/mainboard/dell/optiplex_780/variants/780_usff/hda_verb.c b/src/mainboard/dell/optiplex_780/variants/780_usff/hda_verb.c
+new file mode 100644
+index 0000000000..c94e06b156
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/variants/780_usff/hda_verb.c
+@@ -0,0 +1,26 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++
++#include <device/azalia_device.h>
++
++const u32 cim_verb_data[] = {
++ /* coreboot specific header */
++ 0x11d4194a, /* Analog Devices AD1984A */
++ 0x10280420, /* Subsystem ID */
++ 10, /* Number of entries */
++
++ /* Pin Widget Verb Table */
++ AZALIA_PIN_CFG(0, 0x11, 0x02214040),
++ AZALIA_PIN_CFG(0, 0x12, 0x01014010),
++ AZALIA_PIN_CFG(0, 0x13, 0x991301f0),
++ AZALIA_PIN_CFG(0, 0x14, 0x02a19020),
++ AZALIA_PIN_CFG(0, 0x15, 0x01813030),
++ AZALIA_PIN_CFG(0, 0x16, 0x413301f0),
++ AZALIA_PIN_CFG(0, 0x17, 0x41a601f0),
++ AZALIA_PIN_CFG(0, 0x1a, 0x41f301f0),
++ AZALIA_PIN_CFG(0, 0x1b, 0x414501f0),
++ AZALIA_PIN_CFG(0, 0x1c, 0x413301f0),
++};
++
++const u32 pc_beep_verbs[0] = {};
++
++AZALIA_ARRAY_SIZES;
+diff --git a/src/mainboard/dell/optiplex_780/variants/780_usff/overridetree.cb b/src/mainboard/dell/optiplex_780/variants/780_usff/overridetree.cb
+new file mode 100644
+index 0000000000..555b1c1f5c
+--- /dev/null
++++ b/src/mainboard/dell/optiplex_780/variants/780_usff/overridetree.cb
+@@ -0,0 +1,10 @@
++## SPDX-License-Identifier: GPL-2.0-or-later
++
++chip northbridge/intel/x4x
++ device domain 0 on
++ chip southbridge/intel/i82801jx
++ device pci 1c.0 on end # PCIe 1
++ device pci 1c.1 on end # PCIe 2
++ end
++ end
++end
+--
+2.39.5
+
diff --git a/config/coreboot/default/patches/0031-dell-3050micro-disable-nvme-hotplug.patch b/config/coreboot/default/patches/0031-dell-3050micro-disable-nvme-hotplug.patch
new file mode 100644
index 00000000..c154a9a1
--- /dev/null
+++ b/config/coreboot/default/patches/0031-dell-3050micro-disable-nvme-hotplug.patch
@@ -0,0 +1,49 @@
+From 4ffaddc37d30d39f25faeaef73046a6e2ce525e8 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <info@minifree.org>
+Date: Wed, 11 Dec 2024 01:06:01 +0000
+Subject: [PATCH 31/37] dell/3050micro: disable nvme hotplug
+
+in my testing, when running my 3050micro for a few days,
+the nvme would sometimes randomly rename.
+
+e.g. nvme0n1 renamed to nvme0n2
+
+this might cause crashes in linux, if booting only from the
+nvme. in my case, i was booting from mdraid (sata+nvme) and
+every few days, the nvme would rename at least once, causing
+my RAID to become unsynced. since i'm using RAID1, this was
+OK and I could simply re-sync the array, but this is quite
+precarious indeed. if you're using raid0, that will potentially
+corrupt your RAID array indefinitely.
+
+this same issue manifested on the T480/T480 thinkpads, and
+S3 resume would break because of that, when booting from nvme,
+because the nvme would be "unplugged" and appear to linux as a
+new device (the one that you booted from).
+
+the fix there was to disable hotplugging on that pci-e slot
+for the nvme, so apply the same fix here for 3050 micro
+
+Signed-off-by: Leah Rowe <leah@libreboot.org>
+---
+ src/mainboard/dell/optiplex_3050/devicetree.cb | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/mainboard/dell/optiplex_3050/devicetree.cb b/src/mainboard/dell/optiplex_3050/devicetree.cb
+index da11085ab6..2a97306c5d 100644
+--- a/src/mainboard/dell/optiplex_3050/devicetree.cb
++++ b/src/mainboard/dell/optiplex_3050/devicetree.cb
+@@ -45,7 +45,9 @@ chip soc/intel/skylake
+ register "PcieRpAdvancedErrorReporting[20]" = "1"
+ register "PcieRpLtrEnable[20]" = "true"
+ register "PcieRpClkSrcNumber[20]" = "3"
+- register "PcieRpHotPlug[20]" = "1"
++# disable hotplug on nvme to prevent renaming e.g. nvme0n1 rename to nvme0n2,
++# which could cause crashes in linux if booting from nvme
++ register "PcieRpHotPlug[20]" = "0"
+ end
+
+ # Realtek LAN
+--
+2.39.5
+
diff --git a/config/coreboot/default/patches/0031-haswell-NRI-Post-process-selected-timings.patch b/config/coreboot/default/patches/0031-haswell-NRI-Post-process-selected-timings.patch
deleted file mode 100644
index 426cef35..00000000
--- a/config/coreboot/default/patches/0031-haswell-NRI-Post-process-selected-timings.patch
+++ /dev/null
@@ -1,249 +0,0 @@
-From 1dc22174b9b28b9ea9af59183ffd5d86d19a2721 Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Sat, 7 May 2022 16:29:55 +0200
-Subject: [PATCH 31/51] haswell NRI: Post-process selected timings
-
-Once the MPLL has been initialised, convert the timings from the SPD to
-be in DCLKs, which is what the hardware expects. In addition, calculate
-the values for tREFI and tXP.
-
-Change-Id: Id02caf858f75b9e08016762b3aefda282b274386
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../intel/haswell/native_raminit/Makefile.mk | 1 +
- .../haswell/native_raminit/lookup_timings.c | 62 +++++++++++
- .../haswell/native_raminit/raminit_main.c | 1 +
- .../haswell/native_raminit/raminit_native.h | 8 ++
- .../haswell/native_raminit/spd_bitmunching.c | 100 ++++++++++++++++++
- 5 files changed, 172 insertions(+)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/lookup_timings.c
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-index c125d84f0b..2769e0bbb4 100644
---- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-@@ -1,5 +1,6 @@
- ## SPDX-License-Identifier: GPL-2.0-or-later
-
-+romstage-y += lookup_timings.c
- romstage-y += init_mpll.c
- romstage-y += io_comp_control.c
- romstage-y += raminit_main.c
-diff --git a/src/northbridge/intel/haswell/native_raminit/lookup_timings.c b/src/northbridge/intel/haswell/native_raminit/lookup_timings.c
-new file mode 100644
-index 0000000000..8b81c7c341
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/lookup_timings.c
-@@ -0,0 +1,62 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <commonlib/bsd/clamp.h>
-+#include <types.h>
-+
-+#include "raminit_native.h"
-+
-+struct timing_lookup {
-+ uint32_t clock;
-+ uint32_t value;
-+};
-+
-+static uint32_t lookup_timing(
-+ const uint32_t mem_clock_mhz,
-+ const struct timing_lookup *const lookup,
-+ const size_t length)
-+{
-+ /* Fall back to the last index */
-+ size_t i;
-+ for (i = 0; i < length - 1; i++) {
-+ /* Account for imprecise frequency values */
-+ if ((mem_clock_mhz - 5) <= lookup[i].clock)
-+ break;
-+ }
-+ return lookup[i].value;
-+}
-+
-+static const uint32_t fmax = UINT32_MAX;
-+
-+uint8_t get_tCWL(const uint32_t mem_clock_mhz)
-+{
-+ const struct timing_lookup lut[] = {
-+ { 400, 5 },
-+ { 533, 6 },
-+ { 666, 7 },
-+ { 800, 8 },
-+ { 933, 9 },
-+ { 1066, 10 },
-+ { 1200, 11 },
-+ { fmax, 12 },
-+ };
-+ return lookup_timing(mem_clock_mhz, lut, ARRAY_SIZE(lut));
-+}
-+
-+/* tREFI = 7800 ns * DDR MHz */
-+uint32_t get_tREFI(const uint32_t mem_clock_mhz)
-+{
-+ return (mem_clock_mhz * 7800) / 1000;
-+}
-+
-+uint32_t get_tXP(const uint32_t mem_clock_mhz)
-+{
-+ const struct timing_lookup lut[] = {
-+ { 400, 3 },
-+ { 666, 4 },
-+ { 800, 5 },
-+ { 933, 6 },
-+ { 1066, 7 },
-+ { fmax, 8 },
-+ };
-+ return lookup_timing(mem_clock_mhz, lut, ARRAY_SIZE(lut));
-+}
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-index bf745e943f..2fea658415 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-@@ -21,6 +21,7 @@ struct task_entry {
- static const struct task_entry cold_boot[] = {
- { collect_spd_info, true, "PROCSPD", },
- { initialise_mpll, true, "INITMPLL", },
-+ { convert_timings, true, "CONVTIM", },
- };
-
- /* Return a generic stepping value to make stepping checks simpler */
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index 15a1550424..e0ebd3a2a7 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -79,6 +79,9 @@ struct sysinfo {
- uint32_t tCWL;
- uint32_t tCMD;
-
-+ uint32_t tREFI;
-+ uint32_t tXP;
-+
- uint8_t lanes; /* 8 or 9 */
- uint8_t chanmap;
- uint8_t dpc[NUM_CHANNELS]; /* DIMMs per channel */
-@@ -97,7 +100,12 @@ void raminit_main(enum raminit_boot_mode bootmode);
-
- enum raminit_status collect_spd_info(struct sysinfo *ctrl);
- enum raminit_status initialise_mpll(struct sysinfo *ctrl);
-+enum raminit_status convert_timings(struct sysinfo *ctrl);
-
- enum raminit_status wait_for_first_rcomp(void);
-
-+uint8_t get_tCWL(uint32_t mem_clock_mhz);
-+uint32_t get_tREFI(uint32_t mem_clock_mhz);
-+uint32_t get_tXP(uint32_t mem_clock_mhz);
-+
- #endif
-diff --git a/src/northbridge/intel/haswell/native_raminit/spd_bitmunching.c b/src/northbridge/intel/haswell/native_raminit/spd_bitmunching.c
-index eff993800b..4f7fe46494 100644
---- a/src/northbridge/intel/haswell/native_raminit/spd_bitmunching.c
-+++ b/src/northbridge/intel/haswell/native_raminit/spd_bitmunching.c
-@@ -204,3 +204,103 @@ enum raminit_status collect_spd_info(struct sysinfo *ctrl)
- get_spd_data(ctrl);
- return find_common_spd_parameters(ctrl);
- }
-+
-+#define MIN_CWL 5
-+#define MAX_CWL 12
-+
-+/* Except for tCK, hardware expects all timing values in DCLKs, not nanoseconds */
-+enum raminit_status convert_timings(struct sysinfo *ctrl)
-+{
-+ /*
-+ * Obtain all required timing values, in DCLKs.
-+ */
-+
-+ /* Convert primary timings from nanoseconds to DCLKs */
-+ ctrl->tAA = DIV_ROUND_UP(ctrl->tAA, ctrl->tCK);
-+ ctrl->tWR = DIV_ROUND_UP(ctrl->tWR, ctrl->tCK);
-+ ctrl->tRCD = DIV_ROUND_UP(ctrl->tRCD, ctrl->tCK);
-+ ctrl->tRRD = DIV_ROUND_UP(ctrl->tRRD, ctrl->tCK);
-+ ctrl->tRP = DIV_ROUND_UP(ctrl->tRP, ctrl->tCK);
-+ ctrl->tRAS = DIV_ROUND_UP(ctrl->tRAS, ctrl->tCK);
-+ ctrl->tRC = DIV_ROUND_UP(ctrl->tRC, ctrl->tCK);
-+ ctrl->tRFC = DIV_ROUND_UP(ctrl->tRFC, ctrl->tCK);
-+ ctrl->tWTR = DIV_ROUND_UP(ctrl->tWTR, ctrl->tCK);
-+ ctrl->tRTP = DIV_ROUND_UP(ctrl->tRTP, ctrl->tCK);
-+ ctrl->tFAW = DIV_ROUND_UP(ctrl->tFAW, ctrl->tCK);
-+ ctrl->tCWL = DIV_ROUND_UP(ctrl->tCWL, ctrl->tCK);
-+ ctrl->tCMD = DIV_ROUND_UP(ctrl->tCMD, ctrl->tCK);
-+
-+ /* Constrain primary timings to hardware limits */
-+ /** TODO: complain when clamping? **/
-+ ctrl->tAA = clamp_u32(4, ctrl->tAA, 24);
-+ ctrl->tWR = clamp_u32(5, ctrl->tWR, 16);
-+ ctrl->tRCD = clamp_u32(4, ctrl->tRCD, 20);
-+ ctrl->tRRD = clamp_u32(4, ctrl->tRRD, 65535);
-+ ctrl->tRP = clamp_u32(4, ctrl->tRP, 15);
-+ ctrl->tRAS = clamp_u32(10, ctrl->tRAS, 40);
-+ ctrl->tRC = clamp_u32(1, ctrl->tRC, 4095);
-+ ctrl->tRFC = clamp_u32(1, ctrl->tRFC, 511);
-+ ctrl->tWTR = clamp_u32(4, ctrl->tWTR, 10);
-+ ctrl->tRTP = clamp_u32(4, ctrl->tRTP, 15);
-+ ctrl->tFAW = clamp_u32(10, ctrl->tFAW, 54);
-+
-+ /** TODO: Honor tREFI from XMP **/
-+ ctrl->tREFI = get_tREFI(ctrl->mem_clock_mhz);
-+ ctrl->tXP = get_tXP(ctrl->mem_clock_mhz);
-+
-+ /*
-+ * Check some values, and adjust them if necessary.
-+ */
-+
-+ /* If tWR cannot be written into DDR3 MR0, adjust it */
-+ switch (ctrl->tWR) {
-+ case 9:
-+ case 11:
-+ case 13:
-+ case 15:
-+ ctrl->tWR++;
-+ }
-+
-+ /* If tCWL is not supported or unspecified, look up a reasonable default */
-+ if (ctrl->tCWL < MIN_CWL || ctrl->tCWL > MAX_CWL)
-+ ctrl->tCWL = get_tCWL(ctrl->mem_clock_mhz);
-+
-+ /* This is needed to support ODT properly on 2DPC */
-+ if (ctrl->tAA - ctrl->tCWL > 4)
-+ ctrl->tCWL = ctrl->tAA - 4;
-+
-+ /* If tCMD is invalid, use a guesstimate default */
-+ if (!ctrl->tCMD) {
-+ ctrl->tCMD = MAX(ctrl->dpc[0], ctrl->dpc[1]);
-+ printk(RAM_DEBUG, "tCMD was zero, picking a guesstimate value\n");
-+ }
-+ ctrl->tCMD = clamp_u32(1, ctrl->tCMD, 3);
-+
-+ /*
-+ * Print final timings.
-+ */
-+
-+ /* tCK is special */
-+ printk(BIOS_DEBUG, "Selected tCK : %u ps\n", ctrl->tCK * 1000 / 256);
-+
-+ /* Primary timings */
-+ printk(BIOS_DEBUG, "Selected tAA : %uT\n", ctrl->tAA);
-+ printk(BIOS_DEBUG, "Selected tWR : %uT\n", ctrl->tWR);
-+ printk(BIOS_DEBUG, "Selected tRCD : %uT\n", ctrl->tRCD);
-+ printk(BIOS_DEBUG, "Selected tRRD : %uT\n", ctrl->tRRD);
-+ printk(BIOS_DEBUG, "Selected tRP : %uT\n", ctrl->tRP);
-+ printk(BIOS_DEBUG, "Selected tRAS : %uT\n", ctrl->tRAS);
-+ printk(BIOS_DEBUG, "Selected tRC : %uT\n", ctrl->tRC);
-+ printk(BIOS_DEBUG, "Selected tRFC : %uT\n", ctrl->tRFC);
-+ printk(BIOS_DEBUG, "Selected tWTR : %uT\n", ctrl->tWTR);
-+ printk(BIOS_DEBUG, "Selected tRTP : %uT\n", ctrl->tRTP);
-+ printk(BIOS_DEBUG, "Selected tFAW : %uT\n", ctrl->tFAW);
-+ printk(BIOS_DEBUG, "Selected tCWL : %uT\n", ctrl->tCWL);
-+ printk(BIOS_DEBUG, "Selected tCMD : %uT\n", ctrl->tCMD);
-+
-+ /* Derived timings */
-+ printk(BIOS_DEBUG, "Selected tREFI : %uT\n", ctrl->tREFI);
-+ printk(BIOS_DEBUG, "Selected tXP : %uT\n", ctrl->tXP);
-+
-+ return RAMINIT_STATUS_SUCCESS;
-+}
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0032-haswell-NRI-Configure-initial-MC-settings.patch b/config/coreboot/default/patches/0032-haswell-NRI-Configure-initial-MC-settings.patch
deleted file mode 100644
index e16f4e3d..00000000
--- a/config/coreboot/default/patches/0032-haswell-NRI-Configure-initial-MC-settings.patch
+++ /dev/null
@@ -1,1594 +0,0 @@
-From a4f5deb78c2d4132bf857c57ffd53684f942ba62 Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Sat, 7 May 2022 17:22:07 +0200
-Subject: [PATCH 32/51] haswell NRI: Configure initial MC settings
-
-Program initial memory controller settings. Many of these values will be
-adjusted later during training.
-
-Change-Id: If33846b51cb1bab5d0458fe626e13afb1bdc900e
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../intel/haswell/native_raminit/Makefile.mk | 2 +
- .../haswell/native_raminit/configure_mc.c | 822 ++++++++++++++++++
- .../haswell/native_raminit/raminit_main.c | 2 +
- .../haswell/native_raminit/raminit_native.h | 101 +++
- .../haswell/native_raminit/reg_structs.h | 405 +++++++++
- .../haswell/native_raminit/timings_refresh.c | 13 +
- .../intel/haswell/registers/mchbar.h | 94 ++
- 7 files changed, 1439 insertions(+)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/configure_mc.c
- create mode 100644 src/northbridge/intel/haswell/native_raminit/reg_structs.h
- create mode 100644 src/northbridge/intel/haswell/native_raminit/timings_refresh.c
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-index 2769e0bbb4..fc55277a65 100644
---- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-@@ -1,8 +1,10 @@
- ## SPDX-License-Identifier: GPL-2.0-or-later
-
-+romstage-y += configure_mc.c
- romstage-y += lookup_timings.c
- romstage-y += init_mpll.c
- romstage-y += io_comp_control.c
- romstage-y += raminit_main.c
- romstage-y += raminit_native.c
- romstage-y += spd_bitmunching.c
-+romstage-y += timings_refresh.c
-diff --git a/src/northbridge/intel/haswell/native_raminit/configure_mc.c b/src/northbridge/intel/haswell/native_raminit/configure_mc.c
-new file mode 100644
-index 0000000000..88249725a7
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/configure_mc.c
-@@ -0,0 +1,822 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <assert.h>
-+#include <commonlib/bsd/clamp.h>
-+#include <console/console.h>
-+#include <delay.h>
-+#include <lib.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <string.h>
-+#include <types.h>
-+
-+#include "raminit_native.h"
-+
-+static void program_misc_control(struct sysinfo *ctrl)
-+{
-+ if (!is_hsw_ult())
-+ return;
-+
-+ const union ddr_scram_misc_control_reg ddr_scram_misc_ctrl = {
-+ .ddr_no_ch_interleave = !ctrl->dq_pins_interleaved,
-+ .lpddr_mode = ctrl->lpddr,
-+ .cke_mapping_ch0 = ctrl->lpddr ? ctrl->lpddr_cke_rank_map[0] : 0,
-+ .cke_mapping_ch1 = ctrl->lpddr ? ctrl->lpddr_cke_rank_map[1] : 0,
-+ };
-+ mchbar_write32(DDR_SCRAM_MISC_CONTROL, ddr_scram_misc_ctrl.raw);
-+}
-+
-+static void program_mrc_revision(void)
-+{
-+ mchbar_write32(MRC_REVISION, 0x01090000); /* MRC 1.9.0 Build 0 */
-+}
-+
-+static void program_ranks_used(struct sysinfo *ctrl)
-+{
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ mchbar_write8(MC_INIT_STATE_ch(channel), ctrl->rankmap[channel]);
-+ if (!does_ch_exist(ctrl, channel)) {
-+ mchbar_write32(DDR_CLK_ch_RANKS_USED(channel), 0);
-+ mchbar_write32(DDR_CTL_ch_CTL_RANKS_USED(channel), 0);
-+ mchbar_write32(DDR_CKE_ch_CTL_RANKS_USED(channel), 0);
-+ continue;
-+ }
-+ uint32_t clk_ranks_used = ctrl->rankmap[channel];
-+ if (ctrl->lpddr) {
-+ /* With LPDDR, the clock usage goes by group instead */
-+ clk_ranks_used = 0;
-+ for (uint8_t group = 0; group < NUM_GROUPS; group++) {
-+ if (ctrl->dq_byte_map[channel][CT_ITERATION_CLOCK][group])
-+ clk_ranks_used |= BIT(group);
-+ }
-+ }
-+ mchbar_write32(DDR_CLK_ch_RANKS_USED(channel), clk_ranks_used);
-+
-+ uint32_t ctl_ranks_used = ctrl->rankmap[channel];
-+ if (is_hsw_ult()) {
-+ /* Set ODT disable bits */
-+ /** TODO: May need to do this after JEDEC reset/init **/
-+ if (ctrl->lpddr && ctrl->lpddr_dram_odt)
-+ ctl_ranks_used |= 2 << 4; /* ODT is used on rank 0 */
-+ else
-+ ctl_ranks_used |= 3 << 4;
-+ }
-+ mchbar_write32(DDR_CTL_ch_CTL_RANKS_USED(channel), ctl_ranks_used);
-+
-+ uint32_t cke_ranks_used = ctrl->rankmap[channel];
-+ if (ctrl->lpddr) {
-+ /* Use CKE-to-rank mapping for LPDDR */
-+ const uint8_t cke_rank_map = ctrl->lpddr_cke_rank_map[channel];
-+ cke_ranks_used = 0;
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ /* ULT only has 2 ranks per channel */
-+ if (rank >= 2)
-+ break;
-+
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ for (uint8_t cke = 0; cke < 4; cke++) {
-+ if (rank == ((cke_rank_map >> cke) & 1))
-+ cke_ranks_used |= BIT(cke);
-+ }
-+ }
-+ }
-+ mchbar_write32(DDR_CKE_ch_CTL_RANKS_USED(channel), cke_ranks_used);
-+ }
-+}
-+
-+static const uint8_t rxb_trad[2][5][4] = {
-+ { /* Vdd low */
-+ /* 1067 MT/s, 1333 MT/s, 1600 MT/s, 1867 MT/s, 2133 MT/s, */
-+ {4, 3, 3, 2}, {4, 4, 3, 2}, {5, 4, 3, 3}, {5, 4, 4, 3}, {5, 4, 4, 3},
-+ },
-+ { /* Vdd hi */
-+ /* 1067 MT/s, 1333 MT/s, 1600 MT/s, 1867 MT/s, 2133 MT/s, */
-+ {4, 3, 3, 2}, {4, 4, 3, 2}, {5, 4, 3, 3}, {5, 4, 4, 3}, {4, 4, 3, 3},
-+ },
-+};
-+
-+static const uint8_t rxb_ultx[2][3][4] = {
-+ { /* Vdd low */
-+ /* 1067 MT/s, 1333 MT/s, 1600 MT/s, */
-+ {5, 6, 6, 5}, {5, 6, 6, 5}, {4, 6, 6, 6},
-+ },
-+ { /* Vdd hi */
-+ /* 1067 MT/s, 1333 MT/s, 1600 MT/s, */
-+ {7, 6, 6, 5}, {7, 6, 6, 5}, {7, 6, 6, 6},
-+ },
-+};
-+
-+uint8_t get_rx_bias(const struct sysinfo *ctrl)
-+{
-+ const bool is_ult = is_hsw_ult();
-+ const bool vddhi = ctrl->vdd_mv > 1350;
-+ const uint8_t max_rxf = is_ult ? ARRAY_SIZE(rxb_ultx[0]) : ARRAY_SIZE(rxb_trad[0]);
-+ const uint8_t ref_clk = ctrl->base_freq == 133 ? 4 : 6;
-+ const uint8_t rx_f = clamp_s8(0, ctrl->multiplier - ref_clk, max_rxf - 1);
-+ const uint8_t rx_cb = mchbar_read32(DDR_CLK_CB_STATUS) & 0x3;
-+ if (is_ult)
-+ return rxb_ultx[vddhi][rx_f][rx_cb];
-+ else
-+ return rxb_trad[vddhi][rx_f][rx_cb];
-+}
-+
-+static void program_ddr_data(struct sysinfo *ctrl, const bool dis_odt_static, const bool vddhi)
-+{
-+ const bool is_ult = is_hsw_ult();
-+
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (!does_rank_exist(ctrl, rank))
-+ continue;
-+
-+ const union ddr_data_rx_train_rank_reg rx_train = {
-+ .rcven = 64,
-+ .dqs_p = 32,
-+ .dqs_n = 32,
-+ };
-+ mchbar_write32(DDR_DATA_RX_TRAIN_RANK(rank), rx_train.raw);
-+ mchbar_write32(DDR_DATA_RX_PER_BIT_RANK(rank), 0x88888888);
-+
-+ const union ddr_data_tx_train_rank_reg tx_train = {
-+ .tx_eq = TXEQFULLDRV | 11,
-+ .dq_delay = 96,
-+ .dqs_delay = 64,
-+ };
-+ mchbar_write32(DDR_DATA_TX_TRAIN_RANK(rank), tx_train.raw);
-+ mchbar_write32(DDR_DATA_TX_PER_BIT_RANK(rank), 0x88888888);
-+
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ ctrl->tx_dq[channel][rank][byte] = tx_train.dq_delay;
-+ ctrl->txdqs[channel][rank][byte] = tx_train.dqs_delay;
-+ ctrl->tx_eq[channel][rank][byte] = tx_train.tx_eq;
-+
-+ ctrl->rcven[channel][rank][byte] = rx_train.rcven;
-+ ctrl->rxdqsp[channel][rank][byte] = rx_train.dqs_p;
-+ ctrl->rxdqsn[channel][rank][byte] = rx_train.dqs_n;
-+ ctrl->rx_eq[channel][rank][byte] = rx_train.rx_eq;
-+ }
-+ }
-+ }
-+ mchbar_write32(DDR_DATA_TX_XTALK, 0);
-+ mchbar_write32(DDR_DATA_RX_OFFSET_VDQ, 0x88888888);
-+ mchbar_write32(DDR_DATA_OFFSET_TRAIN, 0);
-+ mchbar_write32(DDR_DATA_OFFSET_COMP, 0);
-+
-+ const union ddr_data_control_0_reg data_control_0 = {
-+ .internal_clocks_on = !is_ult,
-+ .data_vccddq_hi = vddhi,
-+ .disable_odt_static = dis_odt_static,
-+ .lpddr_mode = ctrl->lpddr,
-+ .odt_samp_extend_en = ctrl->lpddr,
-+ .early_rleak_en = ctrl->lpddr && ctrl->stepping >= STEPPING_C0,
-+ };
-+ mchbar_write32(DDR_DATA_CONTROL_0, data_control_0.raw);
-+
-+ const union ddr_data_control_1_reg data_control_1 = {
-+ .dll_mask = 1,
-+ .rx_bias_ctl = get_rx_bias(ctrl),
-+ .odt_delay = -2,
-+ .odt_duration = 7,
-+ .sense_amp_delay = -2,
-+ .sense_amp_duration = 7,
-+ };
-+ mchbar_write32(DDR_DATA_CONTROL_1, data_control_1.raw);
-+
-+ clear_data_offset_train_all(ctrl);
-+
-+ /* Stagger byte turn-on to reduce dI/dT */
-+ const uint8_t byte_stagger[] = { 0, 4, 1, 5, 2, 6, 3, 7, 8 };
-+ const uint8_t latency = 2 * ctrl->tAA - 6;
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ union ddr_data_control_2_reg data_control_2 = {
-+ .raw = 0,
-+ };
-+ if (is_ult) {
-+ data_control_2.rx_dqs_amp_offset = 8;
-+ data_control_2.rx_clk_stg_num = 0x1f;
-+ data_control_2.leaker_comp = ctrl->lpddr ? 3 : 0;
-+ }
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ const uint8_t stg = latency * byte_stagger[byte] / ctrl->lanes;
-+ data_control_2.rx_stagger_ctl = stg & 0x1f;
-+ mchbar_write32(DQ_CONTROL_2(channel, byte), data_control_2.raw);
-+ ctrl->data_offset_comp[channel][byte] = 0;
-+ ctrl->dq_control_1[channel][byte] = data_control_1.raw;
-+ ctrl->dq_control_2[channel][byte] = data_control_2.raw;
-+ }
-+ ctrl->dq_control_0[channel] = data_control_0.raw;
-+ }
-+}
-+
-+static void program_vsshi_control(struct sysinfo *ctrl, const uint16_t vsshi_mv)
-+{
-+ const uint32_t vsshi_control_reg = is_hsw_ult() ? 0x366c : 0x306c;
-+ const union ddr_comp_vsshi_control_reg ddr_vsshi_control = {
-+ .vsshi_target = (vsshi_mv * 192) / ctrl->vdd_mv - 20,
-+ .hi_bw_divider = 1,
-+ .lo_bw_divider = 1,
-+ .bw_error = 2,
-+ .panic_driver_en = 1,
-+ .panic_voltage = 24 / 8, /* Voltage in 8mV steps */
-+ .gain_boost = 1,
-+ };
-+ mchbar_write32(vsshi_control_reg, ddr_vsshi_control.raw);
-+ mchbar_write32(DDR_COMP_VSSHI_CONTROL, ddr_vsshi_control.raw);
-+}
-+
-+static void calc_vt_slope_code(const uint16_t slope, uint8_t *best_a, uint8_t *best_b)
-+{
-+ const int16_t coding[] = {0, -125, -62, -31, 250, 125, 62, 31};
-+ *best_a = 0;
-+ *best_b = 0;
-+ int16_t best_err = slope;
-+ for (uint8_t b = 0; b < ARRAY_SIZE(coding); b++) {
-+ for (uint8_t a = b; a < ARRAY_SIZE(coding); a++) {
-+ int16_t error = slope - (coding[a] + coding[b]);
-+ if (error < 0)
-+ error = -error;
-+
-+ if (error < best_err) {
-+ best_err = error;
-+ *best_a = a;
-+ *best_b = b;
-+ }
-+ }
-+ }
-+}
-+
-+static void program_dimm_vref(struct sysinfo *ctrl, const uint16_t vccio_mv, const bool vddhi)
-+{
-+ const bool is_ult = is_hsw_ult();
-+
-+ /* Static values for ULT */
-+ uint8_t vt_slope_a = 4;
-+ uint8_t vt_slope_b = 0;
-+ if (!is_ult) {
-+ /* On non-ULT, compute best slope code */
-+ const uint16_t vt_slope = 1500 * vccio_mv / ctrl->vdd_mv - 1000;
-+ calc_vt_slope_code(vt_slope, &vt_slope_a, &vt_slope_b);
-+ }
-+ const union ddr_data_vref_control_reg ddr_vref_control = {
-+ .hi_bw_divider = is_ult ? 0 : 3,
-+ .lo_bw_divider = 3,
-+ .sample_divider = is_ult ? 1 : 3,
-+ .slow_bw_error = 1,
-+ .hi_bw_enable = 1,
-+ .vt_slope_b = vt_slope_b,
-+ .vt_slope_a = vt_slope_a,
-+ .vt_offset = 0,
-+ };
-+ mchbar_write32(is_ult ? 0xf68 : 0xf6c, ddr_vref_control.raw); /* Use CH1 byte 7 */
-+
-+ const union ddr_data_vref_adjust_reg ddr_vref_adjust = {
-+ .en_dimm_vref_ca = 1,
-+ .en_dimm_vref_ch0 = 1,
-+ .en_dimm_vref_ch1 = 1,
-+ .vccddq_hi_qnnn_h = vddhi,
-+ .hi_z_timer_ctrl = 3,
-+ };
-+ ctrl->dimm_vref = ddr_vref_adjust;
-+ mchbar_write32(DDR_DATA_VREF_ADJUST, ddr_vref_adjust.raw);
-+}
-+
-+static uint32_t pi_code(const uint32_t code)
-+{
-+ return code << 21 | code << 14 | code << 7 | code << 0;
-+}
-+
-+static void program_ddr_ca(struct sysinfo *ctrl, const bool vddhi)
-+{
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ const union ddr_clk_controls_reg ddr_clk_controls = {
-+ .dll_mask = 1,
-+ .vccddq_hi = vddhi,
-+ .lpddr_mode = ctrl->lpddr,
-+ };
-+ mchbar_write32(DDR_CLK_ch_CONTROLS(channel), ddr_clk_controls.raw);
-+
-+ const union ddr_cmd_controls_reg ddr_cmd_controls = {
-+ .dll_mask = 1,
-+ .vccddq_hi = vddhi,
-+ .lpddr_mode = ctrl->lpddr,
-+ .early_weak_drive = 3,
-+ .cmd_tx_eq = 1,
-+ };
-+ mchbar_write32(DDR_CMD_ch_CONTROLS(channel), ddr_cmd_controls.raw);
-+
-+ const union ddr_cke_ctl_controls_reg ddr_cke_controls = {
-+ .dll_mask = 1,
-+ .vccddq_hi = vddhi,
-+ .lpddr_mode = ctrl->lpddr,
-+ .early_weak_drive = 3,
-+ .cmd_tx_eq = 1,
-+ .ctl_tx_eq = 1,
-+ .ctl_sr_drv = 2,
-+ };
-+ mchbar_write32(DDR_CKE_ch_CTL_CONTROLS(channel), ddr_cke_controls.raw);
-+
-+ const union ddr_cke_ctl_controls_reg ddr_ctl_controls = {
-+ .dll_mask = 1,
-+ .vccddq_hi = vddhi,
-+ .lpddr_mode = ctrl->lpddr,
-+ .ctl_tx_eq = 1,
-+ .ctl_sr_drv = 2,
-+ .la_drv_en_ovrd = 1, /* Must be set on ULT */
-+ };
-+ mchbar_write32(DDR_CTL_ch_CTL_CONTROLS(channel), ddr_ctl_controls.raw);
-+
-+ const uint8_t cmd_pi = ctrl->lpddr ? 96 : 64;
-+ mchbar_write32(DDR_CMD_ch_PI_CODING(channel), pi_code(cmd_pi));
-+ mchbar_write32(DDR_CKE_ch_CMD_PI_CODING(channel), pi_code(cmd_pi));
-+ mchbar_write32(DDR_CKE_CTL_ch_CTL_PI_CODING(channel), pi_code(64));
-+ mchbar_write32(DDR_CLK_ch_PI_CODING(channel), pi_code(64));
-+
-+ mchbar_write32(DDR_CMD_ch_COMP_OFFSET(channel), 0);
-+ mchbar_write32(DDR_CLK_ch_COMP_OFFSET(channel), 0);
-+ mchbar_write32(DDR_CKE_CTL_ch_CTL_COMP_OFFSET(channel), 0);
-+
-+ for (uint8_t group = 0; group < NUM_GROUPS; group++) {
-+ ctrl->cke_cmd_pi_code[channel][group] = cmd_pi;
-+ ctrl->cmd_north_pi_code[channel][group] = cmd_pi;
-+ ctrl->cmd_south_pi_code[channel][group] = cmd_pi;
-+ }
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ ctrl->clk_pi_code[channel][rank] = 64;
-+ ctrl->ctl_pi_code[channel][rank] = 64;
-+ }
-+ }
-+}
-+
-+enum {
-+ RCOMP_RD_ODT = 0,
-+ RCOMP_WR_DS_DQ,
-+ RCOMP_WR_DS_CMD,
-+ RCOMP_WR_DS_CTL,
-+ RCOMP_WR_DS_CLK,
-+ RCOMP_MAX_CODES,
-+};
-+
-+struct rcomp_info {
-+ uint8_t resistor;
-+ uint8_t sz_steps;
-+ uint8_t target_r;
-+ int8_t result;
-+};
-+
-+static void program_rcomp_vref(struct sysinfo *ctrl, const bool dis_odt_static)
-+{
-+ const bool is_ult = is_hsw_ult();
-+ /*
-+ * +-------------------------------+
-+ * | Rcomp resistor values in ohms |
-+ * +-----------+------+------+-----+
-+ * | Ball name | Trad | ULTX | Use |
-+ * +-----------+------+------+-----+
-+ * | SM_RCOMP0 | 100 | 200 | CMD |
-+ * | SM_RCOMP1 | 75 | 120 | DQ |
-+ * | SM_RCOMP2 | 100 | 100 | ODT |
-+ * +-----------+------+------+-----+
-+ */
-+ struct rcomp_info rcomp_cfg[RCOMP_MAX_CODES] = {
-+ [RCOMP_RD_ODT] = {
-+ .resistor = 50,
-+ .sz_steps = 96,
-+ .target_r = 50,
-+ },
-+ [RCOMP_WR_DS_DQ] = {
-+ .resistor = 25,
-+ .sz_steps = 64,
-+ .target_r = 33,
-+ },
-+ [RCOMP_WR_DS_CMD] = {
-+ .resistor = 20,
-+ .sz_steps = 64,
-+ .target_r = 20,
-+ },
-+ [RCOMP_WR_DS_CTL] = {
-+ .resistor = 20,
-+ .sz_steps = 64,
-+ .target_r = 20,
-+ },
-+ [RCOMP_WR_DS_CLK] = {
-+ .resistor = 25,
-+ .sz_steps = 64,
-+ .target_r = 29,
-+ },
-+ };
-+ if (is_ult) {
-+ rcomp_cfg[RCOMP_WR_DS_DQ].resistor = 40;
-+ rcomp_cfg[RCOMP_WR_DS_DQ].target_r = 40;
-+ rcomp_cfg[RCOMP_WR_DS_CLK].resistor = 40;
-+ } else if (ctrl->dpc[0] == 2 || ctrl->dpc[1] == 2) {
-+ rcomp_cfg[RCOMP_RD_ODT].target_r = 60;
-+ }
-+ for (uint8_t i = 0; i < RCOMP_MAX_CODES; i++) {
-+ struct rcomp_info *const r = &rcomp_cfg[i];
-+ const int32_t div = 2 * (r->resistor + r->target_r);
-+ assert(div);
-+ const int32_t vref = (r->sz_steps * (r->resistor - r->target_r)) / div;
-+
-+ /* DqOdt is 5 bits wide, the other Rcomp targets are 4 bits wide */
-+ const int8_t comp_limit = i == RCOMP_RD_ODT ? 16 : 8;
-+ r->result = clamp_s32(-comp_limit, vref, comp_limit - 1);
-+ }
-+ const union ddr_comp_ctl_0_reg ddr_comp_ctl_0 = {
-+ .disable_odt_static = dis_odt_static,
-+ .dq_drv_vref = rcomp_cfg[RCOMP_WR_DS_DQ].result,
-+ .dq_odt_vref = rcomp_cfg[RCOMP_RD_ODT].result,
-+ .cmd_drv_vref = rcomp_cfg[RCOMP_WR_DS_CMD].result,
-+ .ctl_drv_vref = rcomp_cfg[RCOMP_WR_DS_CTL].result,
-+ .clk_drv_vref = rcomp_cfg[RCOMP_WR_DS_CLK].result,
-+ };
-+ ctrl->comp_ctl_0 = ddr_comp_ctl_0;
-+ mchbar_write32(DDR_COMP_CTL_0, ctrl->comp_ctl_0.raw);
-+}
-+
-+enum {
-+ SCOMP_DQ = 0,
-+ SCOMP_CMD,
-+ SCOMP_CTL,
-+ SCOMP_CLK,
-+ SCOMP_MAX_CODES,
-+};
-+
-+static void program_slew_rates(struct sysinfo *ctrl, const bool vddhi)
-+{
-+ const uint8_t min_cycle_delay[SCOMP_MAX_CODES] = { 46, 70, 70, 46 };
-+ uint8_t buffer_stage_delay_ps[SCOMP_MAX_CODES] = { 59, 53, 53, 53 };
-+ uint16_t comp_slew_rate_codes[SCOMP_MAX_CODES];
-+
-+ /* CMD Slew Rate = 1.8 for 2N */
-+ if (ctrl->tCMD == 2)
-+ buffer_stage_delay_ps[SCOMP_CMD] = 89;
-+
-+ /* CMD Slew Rate = 4 V/ns for double-pumped CMD bus */
-+ if (ctrl->lpddr)
-+ buffer_stage_delay_ps[SCOMP_CMD] = 63;
-+
-+ for (uint8_t i = 0; i < SCOMP_MAX_CODES; i++) {
-+ uint16_t stages = DIV_ROUND_CLOSEST(ctrl->qclkps, buffer_stage_delay_ps[i]);
-+ if (stages < 5)
-+ stages = 5;
-+
-+ bool dll_pc = buffer_stage_delay_ps[i] < min_cycle_delay[i] || stages > 16;
-+
-+ /* Lock DLL... */
-+ if (dll_pc)
-+ comp_slew_rate_codes[i] = stages / 2 - 1; /* to a phase */
-+ else
-+ comp_slew_rate_codes[i] = (stages - 1) | BIT(4); /* to a cycle */
-+ }
-+ union ddr_comp_ctl_1_reg ddr_comp_ctl_1 = {
-+ .dq_scomp = comp_slew_rate_codes[SCOMP_DQ],
-+ .cmd_scomp = comp_slew_rate_codes[SCOMP_CMD],
-+ .ctl_scomp = comp_slew_rate_codes[SCOMP_CTL],
-+ .clk_scomp = comp_slew_rate_codes[SCOMP_CLK],
-+ .vccddq_hi = vddhi,
-+ };
-+ ctrl->comp_ctl_1 = ddr_comp_ctl_1;
-+ mchbar_write32(DDR_COMP_CTL_1, ctrl->comp_ctl_1.raw);
-+}
-+
-+static uint32_t ln_x100(const uint32_t input_x100)
-+{
-+ uint32_t val = input_x100;
-+ uint32_t ret = 0;
-+ while (val > 271) {
-+ val = (val * 1000) / 2718;
-+ ret += 100;
-+ }
-+ return ret + (-16 * val * val + 11578 * val - 978860) / 10000;
-+}
-+
-+static uint32_t compute_vsshi_vref(struct sysinfo *ctrl, const uint32_t vsshi_tgt, bool up)
-+{
-+ const uint32_t delta = 15;
-+ const uint32_t c_die_vsshi = 2000;
-+ const uint32_t r_cmd_ref = 100 * 10;
-+ const uint32_t offset = up ? 64 : 0;
-+ const uint32_t ln_vsshi = ln_x100((100 * vsshi_tgt) / (vsshi_tgt - delta));
-+ const uint32_t r_target = (ctrl->qclkps * 2000) / (c_die_vsshi * ln_vsshi);
-+ const uint32_t r_dividend = 128 * (up ? r_cmd_ref : r_target);
-+ return r_dividend / (r_cmd_ref + r_target) - offset;
-+}
-+
-+static void program_vsshi(struct sysinfo *ctrl, const uint16_t vccio_mv, const uint16_t vsshi)
-+{
-+ const uint16_t vsshi_down = vsshi + 24; /* Panic threshold of 24 mV */
-+ const uint16_t vsshi_up = vccio_mv - vsshi_down;
-+ const union ddr_comp_vsshi_reg ddr_comp_vsshi = {
-+ .panic_drv_down_vref = compute_vsshi_vref(ctrl, vsshi_down, false),
-+ .panic_drv_up_vref = compute_vsshi_vref(ctrl, vsshi_up, true),
-+ .vt_offset = 128 * 450 / vccio_mv / 2,
-+ .vt_slope_a = 4,
-+ };
-+ mchbar_write32(DDR_COMP_VSSHI, ddr_comp_vsshi.raw);
-+}
-+
-+static void program_misc(struct sysinfo *ctrl)
-+{
-+ ctrl->misc_control_0.raw = mchbar_read32(DDR_SCRAM_MISC_CONTROL);
-+ ctrl->misc_control_0.weaklock_latency = 12;
-+ ctrl->misc_control_0.wl_sleep_cycles = 5;
-+ ctrl->misc_control_0.wl_wake_cycles = 2;
-+ mchbar_write32(DDR_SCRAM_MISC_CONTROL, ctrl->misc_control_0.raw);
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ /* Keep scrambling disabled for training */
-+ mchbar_write32(DDR_SCRAMBLE_ch(channel), 0);
-+ }
-+}
-+
-+/* Very weird, application-specific function */
-+static void override_comp(uint32_t value, uint32_t width, uint32_t shift, uint32_t offset)
-+{
-+ const uint32_t mask = (1 << width) - 1;
-+ uint32_t reg32 = mchbar_read32(offset);
-+ reg32 &= ~(mask << shift);
-+ reg32 |= (value << shift);
-+ mchbar_write32(offset, reg32);
-+}
-+
-+static void program_ls_comp(struct sysinfo *ctrl)
-+{
-+ /* Disable periodic COMP */
-+ const union pcu_comp_reg m_comp = {
-+ .comp_disable = 1,
-+ .comp_interval = COMP_INT,
-+ .comp_force = 1,
-+ };
-+ mchbar_write32(M_COMP, m_comp.raw);
-+ udelay(10);
-+
-+ /* Override level shifter compensation */
-+ const uint32_t ls_comp = 2;
-+ override_comp(ls_comp, 3, 28, DDR_DATA_RCOMP_DATA_1);
-+ override_comp(ls_comp, 3, 24, DDR_CMD_COMP);
-+ override_comp(ls_comp, 3, 24, DDR_CKE_CTL_COMP);
-+ override_comp(ls_comp, 3, 23, DDR_CLK_COMP);
-+ override_comp(ls_comp, 3, 28, DDR_COMP_DATA_COMP_1);
-+ override_comp(ls_comp, 3, 24, DDR_COMP_CMD_COMP);
-+ override_comp(ls_comp, 4, 24, DDR_COMP_CTL_COMP);
-+ override_comp(ls_comp, 4, 23, DDR_COMP_CLK_COMP);
-+ override_comp(ls_comp, 3, 24, DDR_COMP_OVERRIDE);
-+
-+ /* Manually update the COMP values */
-+ union ddr_scram_misc_control_reg ddr_scram_misc_ctrl = ctrl->misc_control_0;
-+ ddr_scram_misc_ctrl.force_comp_update = 1;
-+ mchbar_write32(DDR_SCRAM_MISC_CONTROL, ddr_scram_misc_ctrl.raw);
-+
-+ /* Use a fixed offset between ODT Up/Dn */
-+ const union ddr_comp_data_comp_1_reg data_comp_1 = {
-+ .raw = mchbar_read32(DDR_COMP_DATA_COMP_1),
-+ };
-+ const uint32_t odt_offset = data_comp_1.rcomp_odt_down - data_comp_1.rcomp_odt_up;
-+ ctrl->comp_ctl_0.odt_up_down_off = odt_offset;
-+ ctrl->comp_ctl_0.fixed_odt_offset = 1;
-+ mchbar_write32(DDR_COMP_CTL_0, ctrl->comp_ctl_0.raw);
-+}
-+
-+/** TODO: Deduplicate PCODE stuff, it's already implemented in CPU code **/
-+static bool pcode_ready(void)
-+{
-+ const unsigned int delay_step = 10;
-+ for (unsigned int i = 0; i < 1000; i += delay_step) {
-+ if (!(mchbar_read32(BIOS_MAILBOX_INTERFACE) & MAILBOX_RUN_BUSY))
-+ return true;
-+
-+ udelay(delay_step);
-+ };
-+ return false;
-+}
-+
-+static uint32_t pcode_mailbox_read(const uint32_t command)
-+{
-+ if (!pcode_ready()) {
-+ printk(BIOS_ERR, "PCODE: mailbox timeout on wait ready\n");
-+ return 0;
-+ }
-+ mchbar_write32(BIOS_MAILBOX_INTERFACE, command | MAILBOX_RUN_BUSY);
-+ if (!pcode_ready()) {
-+ printk(BIOS_ERR, "PCODE: mailbox timeout on completion\n");
-+ return 0;
-+ }
-+ return mchbar_read32(BIOS_MAILBOX_DATA);
-+}
-+
-+static int pcode_mailbox_write(const uint32_t command, const uint32_t data)
-+{
-+ if (!pcode_ready()) {
-+ printk(BIOS_ERR, "PCODE: mailbox timeout on wait ready\n");
-+ return -1;
-+ }
-+ mchbar_write32(BIOS_MAILBOX_DATA, data);
-+ mchbar_write32(BIOS_MAILBOX_INTERFACE, command | MAILBOX_RUN_BUSY);
-+ if (!pcode_ready()) {
-+ printk(BIOS_ERR, "PCODE: mailbox timeout on completion\n");
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+static void enable_2x_refresh(struct sysinfo *ctrl)
-+{
-+ if (!CONFIG(ENABLE_DDR_2X_REFRESH))
-+ return;
-+
-+ printk(BIOS_DEBUG, "Enabling 2x Refresh\n");
-+ const bool asr = ctrl->flags.asr;
-+ const bool lpddr = ctrl->lpddr;
-+
-+ /* Mutually exclusive */
-+ assert(!asr || !lpddr);
-+ if (!asr) {
-+ uint32_t reg32 = pcode_mailbox_read(MAILBOX_BIOS_CMD_READ_DDR_2X_REFRESH);
-+ if (!(reg32 & BIT(31))) { /** TODO: What to do if this is locked? **/
-+ reg32 |= BIT(0); /* Enable 2x refresh */
-+ reg32 |= BIT(31); /* Lock */
-+
-+ if (lpddr)
-+ reg32 |= 4 << 1; /* LPDDR MR4 1/2 tREFI */
-+
-+ if (pcode_mailbox_write(MAILBOX_BIOS_CMD_WRITE_DDR_2X_REFRESH, reg32))
-+ printk(BIOS_ERR, "Could not enable Mailbox 2x Refresh\n");
-+ }
-+ if (!lpddr)
-+ return;
-+ }
-+ assert(asr || lpddr);
-+ uint16_t refi_reduction = 50;
-+ if (lpddr) {
-+ refi_reduction = 97;
-+ mchbar_clrbits32(PCU_DDR_PTM_CTL, 1 << 7); /* DISABLE_DRAM_TS */
-+ }
-+ /** TODO: Remember why this is only done on cold boots **/
-+ if (ctrl->bootmode == BOOTMODE_COLD) {
-+ ctrl->tREFI *= refi_reduction;
-+ ctrl->tREFI /= 100;
-+ }
-+}
-+
-+static void set_pcu_ddr_voltage(const uint16_t vdd_mv)
-+{
-+ /** TODO: Handle other voltages? **/
-+ uint32_t pcu_ddr_voltage;
-+ switch (vdd_mv) {
-+ case 1200:
-+ pcu_ddr_voltage = 3;
-+ break;
-+ case 1350:
-+ pcu_ddr_voltage = 1;
-+ break;
-+ default:
-+ case 1500:
-+ pcu_ddr_voltage = 0;
-+ break;
-+ }
-+ /* Set bits 0..2 */
-+ mchbar_write32(PCU_DDR_VOLTAGE, pcu_ddr_voltage);
-+}
-+
-+static void program_scheduler(struct sysinfo *ctrl)
-+{
-+ /*
-+ * ZQ calibration needs to be serialized for LPDDR3. Otherwise,
-+ * the processor issues LPDDR3 ZQ calibration in parallel when
-+ * exiting Package C7 or deeper. This causes problems for dual
-+ * and quad die packages since all ranks share the same ZQ pin.
-+ *
-+ * Erratum HSM94: LPDDR3 ZQ Calibration Following Deep Package
-+ * C-state Exit May Lead to Unpredictable System Behavior
-+ */
-+ const union mcscheds_cbit_reg mcscheds_cbit = {
-+ .dis_write_gap = 1,
-+ .dis_odt = is_hsw_ult() && !(ctrl->lpddr && ctrl->lpddr_dram_odt),
-+ .serialize_zq = ctrl->lpddr,
-+ };
-+ mchbar_write32(MCSCHEDS_CBIT, mcscheds_cbit.raw);
-+ mchbar_write32(MCMNTS_SC_WDBWM, 0x553c3038);
-+ if (ctrl->lpddr) {
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ union mcmain_command_rate_limit_reg cmd_rate_limit = {
-+ .raw = mchbar_read32(COMMAND_RATE_LIMIT_ch(channel)),
-+ };
-+ cmd_rate_limit.enable_cmd_limit = 1;
-+ cmd_rate_limit.cmd_rate_limit = 3;
-+ mchbar_write32(COMMAND_RATE_LIMIT_ch(channel), cmd_rate_limit.raw);
-+ }
-+ }
-+}
-+
-+static uint8_t biggest_channel(const struct sysinfo *const ctrl)
-+{
-+ _Static_assert(NUM_CHANNELS == 2, "Code assumes exactly two channels");
-+ return !!(ctrl->channel_size_mb[0] < ctrl->channel_size_mb[1]);
-+}
-+
-+static void dram_zones(struct sysinfo *ctrl)
-+{
-+ /** TODO: Activate channel hash here, if enabled **/
-+ const uint8_t biggest = biggest_channel(ctrl);
-+ const uint8_t smaller = !biggest;
-+
-+ /** TODO: Use stacked mode if Memory Trace is enabled **/
-+ const union mad_chnl_reg mad_channel = {
-+ .ch_a = biggest,
-+ .ch_b = smaller,
-+ .ch_c = 2,
-+ .lpddr_mode = ctrl->lpddr,
-+ };
-+ mchbar_write32(MAD_CHNL, mad_channel.raw);
-+
-+ const uint8_t channel_b_zone_size = ctrl->channel_size_mb[smaller] / 256;
-+ const union mad_zr_reg mad_zr = {
-+ .ch_b_double = channel_b_zone_size * 2,
-+ .ch_b_single = channel_b_zone_size,
-+ };
-+ mchbar_write32(MAD_ZR, mad_zr.raw);
-+}
-+
-+static uint8_t biggest_dimm(const struct raminit_dimm_info *dimms)
-+{
-+ _Static_assert(NUM_SLOTS <= 2, "Code assumes at most two DIMMs per channel.");
-+ if (NUM_SLOTS == 1)
-+ return 0;
-+
-+ return !!(dimms[0].data.size_mb < dimms[1].data.size_mb);
-+}
-+
-+static void dram_dimm_mapping(struct sysinfo *ctrl)
-+{
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel)) {
-+ const union mad_dimm_reg mad_dimm = {
-+ .rank_interleave = 1,
-+ .enh_interleave = 1,
-+ };
-+ mchbar_write32(MAD_DIMM(channel), mad_dimm.raw);
-+ continue;
-+ }
-+ const uint8_t biggest = biggest_dimm(ctrl->dimms[channel]);
-+ const uint8_t smaller = !biggest;
-+ const struct dimm_attr_ddr3_st *dimm_a = &ctrl->dimms[channel][biggest].data;
-+ const struct dimm_attr_ddr3_st *dimm_b = &ctrl->dimms[channel][smaller].data;
-+ union mad_dimm_reg mad_dimm = {
-+ .dimm_a_size = dimm_a->size_mb / 256,
-+ .dimm_b_size = dimm_b->size_mb / 256,
-+ .dimm_a_sel = biggest,
-+ .dimm_a_ranks = dimm_a->ranks == 2,
-+ .dimm_b_ranks = dimm_b->ranks == 2,
-+ .dimm_a_width = dimm_a->width == 16,
-+ .dimm_b_width = dimm_b->width == 16,
-+ .rank_interleave = 1,
-+ .enh_interleave = 1,
-+ .ecc_mode = 0, /* Do not enable ECC yet */
-+ };
-+ if (is_hsw_ult())
-+ mad_dimm.dimm_b_width = mad_dimm.dimm_a_width;
-+
-+ mchbar_write32(MAD_DIMM(channel), mad_dimm.raw);
-+ if (ctrl->lpddr)
-+ die("%s: Missing LPDDR support (LPDDR_MR_PARAMS)\n", __func__);
-+ }
-+}
-+
-+enum raminit_status configure_mc(struct sysinfo *ctrl)
-+{
-+ const uint16_t vccio_mv = 1000;
-+ const uint16_t vsshi_mv = ctrl->vdd_mv - 950;
-+ const bool dis_odt_static = is_hsw_ult(); /* Disable static ODT legs on ULT */
-+ const bool vddhi = ctrl->vdd_mv > 1350;
-+
-+ program_misc_control(ctrl);
-+ program_mrc_revision();
-+ program_ranks_used(ctrl);
-+ program_ddr_data(ctrl, dis_odt_static, vddhi);
-+ program_vsshi_control(ctrl, vsshi_mv);
-+ program_dimm_vref(ctrl, vccio_mv, vddhi);
-+ program_ddr_ca(ctrl, vddhi);
-+ program_rcomp_vref(ctrl, dis_odt_static);
-+ program_slew_rates(ctrl, vddhi);
-+ program_vsshi(ctrl, vccio_mv, vsshi_mv);
-+ program_misc(ctrl);
-+ program_ls_comp(ctrl);
-+ enable_2x_refresh(ctrl);
-+ set_pcu_ddr_voltage(ctrl->vdd_mv);
-+ configure_timings(ctrl);
-+ configure_refresh(ctrl);
-+ program_scheduler(ctrl);
-+ dram_zones(ctrl);
-+ dram_dimm_mapping(ctrl);
-+
-+ return RAMINIT_STATUS_SUCCESS;
-+}
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-index 2fea658415..fcc981ad04 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-@@ -22,6 +22,7 @@ static const struct task_entry cold_boot[] = {
- { collect_spd_info, true, "PROCSPD", },
- { initialise_mpll, true, "INITMPLL", },
- { convert_timings, true, "CONVTIM", },
-+ { configure_mc, true, "CONFMC", },
- };
-
- /* Return a generic stepping value to make stepping checks simpler */
-@@ -53,6 +54,7 @@ static void initialize_ctrl(struct sysinfo *ctrl)
-
- ctrl->cpu = cpu_get_cpuid();
- ctrl->stepping = get_stepping(ctrl->cpu);
-+ ctrl->vdd_mv = is_hsw_ult() ? 1350 : 1500; /** FIXME: Hardcoded, does it matter? **/
- ctrl->dq_pins_interleaved = cfg->dq_pins_interleaved;
- ctrl->bootmode = bootmode;
- }
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index e0ebd3a2a7..fffa6d5450 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -3,16 +3,41 @@
- #ifndef HASWELL_RAMINIT_NATIVE_H
- #define HASWELL_RAMINIT_NATIVE_H
-
-+#include <assert.h>
- #include <device/dram/ddr3.h>
- #include <northbridge/intel/haswell/haswell.h>
-+#include <string.h>
-+#include <types.h>
-+
-+#include "reg_structs.h"
-
- /** TODO (Angel): Remove this after in-review patches are submitted **/
- #define SPD_LEN SPD_SIZE_MAX_DDR3
-
-+/* Each channel has 4 ranks, spread across 2 slots */
-+#define NUM_SLOTRANKS 4
-+
-+#define NUM_GROUPS 2
-+
- /* 8 data lanes + 1 ECC lane */
- #define NUM_LANES 9
- #define NUM_LANES_NO_ECC 8
-
-+#define COMP_INT 10
-+
-+/* Always use 12 legs for emphasis (not trained) */
-+#define TXEQFULLDRV (3 << 4)
-+
-+enum command_training_iteration {
-+ CT_ITERATION_CLOCK = 0,
-+ CT_ITERATION_CMD_NORTH,
-+ CT_ITERATION_CMD_SOUTH,
-+ CT_ITERATION_CKE,
-+ CT_ITERATION_CTL,
-+ CT_ITERATION_CMD_VREF,
-+ MAX_CT_ITERATION,
-+};
-+
- enum raminit_boot_mode {
- BOOTMODE_COLD,
- BOOTMODE_WARM,
-@@ -58,6 +83,9 @@ struct sysinfo {
- * LPDDR-specific functions have stubs which will halt upon execution.
- */
- bool lpddr;
-+ bool lpddr_dram_odt;
-+ uint8_t lpddr_cke_rank_map[NUM_CHANNELS];
-+ uint8_t dq_byte_map[NUM_CHANNELS][MAX_CT_ITERATION][2];
-
- struct raminit_dimm_info dimms[NUM_CHANNELS][NUM_SLOTS];
- union dimm_flags_ddr3_st flags;
-@@ -94,16 +122,89 @@ struct sysinfo {
- uint32_t mem_clock_mhz;
- uint32_t mem_clock_fs; /* Memory clock period in femtoseconds */
- uint32_t qclkps; /* Quadrature clock period in picoseconds */
-+
-+ uint16_t vdd_mv;
-+
-+ union ddr_scram_misc_control_reg misc_control_0;
-+
-+ union ddr_comp_ctl_0_reg comp_ctl_0;
-+ union ddr_comp_ctl_1_reg comp_ctl_1;
-+
-+ union ddr_data_vref_adjust_reg dimm_vref;
-+
-+ uint32_t data_offset_train[NUM_CHANNELS][NUM_LANES];
-+ uint32_t data_offset_comp[NUM_CHANNELS][NUM_LANES];
-+
-+ uint32_t dq_control_0[NUM_CHANNELS];
-+ uint32_t dq_control_1[NUM_CHANNELS][NUM_LANES];
-+ uint32_t dq_control_2[NUM_CHANNELS][NUM_LANES];
-+
-+ uint16_t tx_dq[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
-+ uint16_t txdqs[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
-+ uint8_t tx_eq[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
-+
-+ uint16_t rcven[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
-+ uint8_t rx_eq[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
-+ uint8_t rxdqsp[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
-+ uint8_t rxdqsn[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
-+ int8_t rxvref[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
-+
-+ uint8_t clk_pi_code[NUM_CHANNELS][NUM_SLOTRANKS];
-+ uint8_t ctl_pi_code[NUM_CHANNELS][NUM_SLOTRANKS];
-+ uint8_t cke_pi_code[NUM_CHANNELS][NUM_SLOTRANKS];
-+
-+ uint8_t cke_cmd_pi_code[NUM_CHANNELS][NUM_GROUPS];
-+ uint8_t cmd_north_pi_code[NUM_CHANNELS][NUM_GROUPS];
-+ uint8_t cmd_south_pi_code[NUM_CHANNELS][NUM_GROUPS];
- };
-
-+static inline bool is_hsw_ult(void)
-+{
-+ return CONFIG(INTEL_LYNXPOINT_LP);
-+}
-+
-+static inline bool rank_in_mask(uint8_t rank, uint8_t rankmask)
-+{
-+ assert(rank < NUM_SLOTRANKS);
-+ return !!(BIT(rank) & rankmask);
-+}
-+
-+static inline bool does_ch_exist(const struct sysinfo *ctrl, uint8_t channel)
-+{
-+ return !!ctrl->dpc[channel];
-+}
-+
-+static inline bool does_rank_exist(const struct sysinfo *ctrl, uint8_t rank)
-+{
-+ return rank_in_mask(rank, ctrl->rankmap[0] | ctrl->rankmap[1]);
-+}
-+
-+static inline bool rank_in_ch(const struct sysinfo *ctrl, uint8_t rank, uint8_t channel)
-+{
-+ assert(channel < NUM_CHANNELS);
-+ return rank_in_mask(rank, ctrl->rankmap[channel]);
-+}
-+
-+/** TODO: Handling of data_offset_train could be improved, also coupled with reg updates **/
-+static inline void clear_data_offset_train_all(struct sysinfo *ctrl)
-+{
-+ memset(ctrl->data_offset_train, 0, sizeof(ctrl->data_offset_train));
-+}
-+
- void raminit_main(enum raminit_boot_mode bootmode);
-
- enum raminit_status collect_spd_info(struct sysinfo *ctrl);
- enum raminit_status initialise_mpll(struct sysinfo *ctrl);
- enum raminit_status convert_timings(struct sysinfo *ctrl);
-+enum raminit_status configure_mc(struct sysinfo *ctrl);
-+
-+void configure_timings(struct sysinfo *ctrl);
-+void configure_refresh(struct sysinfo *ctrl);
-
- enum raminit_status wait_for_first_rcomp(void);
-
-+uint8_t get_rx_bias(const struct sysinfo *ctrl);
-+
- uint8_t get_tCWL(uint32_t mem_clock_mhz);
- uint32_t get_tREFI(uint32_t mem_clock_mhz);
- uint32_t get_tXP(uint32_t mem_clock_mhz);
-diff --git a/src/northbridge/intel/haswell/native_raminit/reg_structs.h b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-new file mode 100644
-index 0000000000..d11cda4b3d
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-@@ -0,0 +1,405 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#ifndef HASWELL_RAMINIT_REG_STRUCTS_H
-+#define HASWELL_RAMINIT_REG_STRUCTS_H
-+
-+union ddr_data_rx_train_rank_reg {
-+ struct __packed {
-+ uint32_t rcven : 9; // Bits 8:0
-+ uint32_t dqs_p : 6; // Bits 14:9
-+ uint32_t rx_eq : 5; // Bits 19:15
-+ uint32_t dqs_n : 6; // Bits 25:20
-+ int32_t vref : 6; // Bits 31:26
-+ };
-+ uint32_t raw;
-+};
-+
-+union ddr_data_tx_train_rank_reg {
-+ struct __packed {
-+ uint32_t dq_delay : 9; // Bits 8:0
-+ uint32_t dqs_delay : 9; // Bits 17:9
-+ uint32_t : 2; // Bits 19:18
-+ uint32_t tx_eq : 6; // Bits 25:20
-+ uint32_t : 6; // Bits 31:26
-+ };
-+ uint32_t raw;
-+};
-+
-+union ddr_data_control_0_reg {
-+ struct __packed {
-+ uint32_t rx_training_mode : 1; // Bits 0:0
-+ uint32_t wl_training_mode : 1; // Bits 1:1
-+ uint32_t rl_training_mode : 1; // Bits 2:2
-+ uint32_t samp_train_mode : 1; // Bits 3:3
-+ uint32_t tx_on : 1; // Bits 4:4
-+ uint32_t rf_on : 1; // Bits 5:5
-+ uint32_t rx_pi_on : 1; // Bits 6:6
-+ uint32_t tx_pi_on : 1; // Bits 7:7
-+ uint32_t internal_clocks_on : 1; // Bits 8:8
-+ uint32_t repeater_clocks_on : 1; // Bits 9:9
-+ uint32_t tx_disable : 1; // Bits 10:10
-+ uint32_t rx_disable : 1; // Bits 11:11
-+ uint32_t tx_long : 1; // Bits 12:12
-+ uint32_t rx_dqs_ctle : 2; // Bits 14:13
-+ uint32_t rx_read_pointer : 3; // Bits 17:15
-+ uint32_t driver_segment_enable : 1; // Bits 18:18
-+ uint32_t data_vccddq_hi : 1; // Bits 19:19
-+ uint32_t read_rf_rd : 1; // Bits 20:20
-+ uint32_t read_rf_wr : 1; // Bits 21:21
-+ uint32_t read_rf_rank : 2; // Bits 23:22
-+ uint32_t force_odt_on : 1; // Bits 24:24
-+ uint32_t odt_samp_off : 1; // Bits 25:25
-+ uint32_t disable_odt_static : 1; // Bits 26:26
-+ uint32_t ddr_cr_force_odt_on : 1; // Bits 27:27
-+ uint32_t lpddr_mode : 1; // Bits 28:28
-+ uint32_t en_read_preamble : 1; // Bits 29:29
-+ uint32_t odt_samp_extend_en : 1; // Bits 30:30
-+ uint32_t early_rleak_en : 1; // Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
-+union ddr_data_control_1_reg {
-+ struct __packed {
-+ int32_t ref_pi : 4; // Bits 3:0
-+ uint32_t dll_mask : 2; // Bits 5:4
-+ uint32_t dll_weaklock : 1; // Bits 6:6
-+ uint32_t sdll_segment_disable : 3; // Bits 9:7
-+ uint32_t rx_bias_ctl : 3; // Bits 12:10
-+ int32_t odt_delay : 4; // Bits 16:13
-+ uint32_t odt_duration : 3; // Bits 19:17
-+ int32_t sense_amp_delay : 4; // Bits 23:20
-+ uint32_t sense_amp_duration : 3; // Bits 26:24
-+ uint32_t burst_end_odt_delay : 3; // Bits 29:27 *** TODO: Check Broadwell ***
-+ uint32_t lpddr_long_odt_en : 1; // Bits 30:30
-+ uint32_t : 1; // Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
-+/* NOTE: Bits 31:19 are only valid for Broadwell onwards */
-+union ddr_data_control_2_reg {
-+ struct __packed {
-+ uint32_t rx_stagger_ctl : 5; // Bits 4:0
-+ uint32_t force_bias_on : 1; // Bits 5:5
-+ uint32_t force_rx_on : 1; // Bits 6:6
-+ uint32_t leaker_comp : 2; // Bits 8:7
-+ uint32_t rx_dqs_amp_offset : 4; // Bits 12:9
-+ uint32_t rx_clk_stg_num : 5; // Bits 17:13
-+ uint32_t wl_long_delay : 1; // Bits 18:18
-+ uint32_t enable_vref_pwrdn : 1; // Bits 19:19
-+ uint32_t ddr4_mode : 1; // Bits 20:20
-+ uint32_t en_vddq_odt : 1; // Bits 21:21
-+ uint32_t en_vtt_odt : 1; // Bits 22:22
-+ uint32_t en_const_z_eq_tx : 1; // Bits 23:23
-+ uint32_t tx_eq_dis : 1; // Bits 24:24
-+ uint32_t rx_vref_prog_mfc : 1; // Bits 25:25
-+ uint32_t cben : 3; // Bits 28:26
-+ uint32_t tx_deskew_disable : 1; // Bits 29:29
-+ uint32_t rx_deskew_disable : 1; // Bits 30:30
-+ uint32_t dq_slew_dly_byp : 1; // Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
-+union ddr_comp_data_comp_1_reg {
-+ struct __packed {
-+ uint32_t rcomp_odt_up : 6; // Bits 5:0
-+ uint32_t : 3; // Bits 8:6
-+ uint32_t rcomp_odt_down : 6; // Bits 14:9
-+ uint32_t : 1; // Bits 15:15
-+ uint32_t panic_drv_down : 6; // Bits 21:16
-+ uint32_t panic_drv_up : 6; // Bits 27:22
-+ uint32_t ls_comp : 3; // Bits 30:28
-+ uint32_t : 1; // Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
-+union ddr_comp_ctl_0_reg {
-+ struct __packed {
-+ uint32_t : 3; // Bits 2:0
-+ uint32_t disable_odt_static : 1; // Bits 3:3
-+ uint32_t odt_up_down_off : 6; // Bits 9:4
-+ uint32_t fixed_odt_offset : 1; // Bits 10:10
-+ int32_t dq_drv_vref : 4; // Bits 14:11
-+ int32_t dq_odt_vref : 5; // Bits 19:15
-+ int32_t cmd_drv_vref : 4; // Bits 23:20
-+ int32_t ctl_drv_vref : 4; // Bits 27:24
-+ int32_t clk_drv_vref : 4; // Bits 31:28
-+ };
-+ uint32_t raw;
-+};
-+
-+union ddr_comp_ctl_1_reg {
-+ struct __packed {
-+ uint32_t dq_scomp : 5; // Bits 4:0
-+ uint32_t cmd_scomp : 5; // Bits 9:5
-+ uint32_t ctl_scomp : 5; // Bits 14:10
-+ uint32_t clk_scomp : 5; // Bits 19:15
-+ uint32_t tco_cmd_offset : 4; // Bits 23:20
-+ uint32_t comp_clk_on : 1; // Bits 24:24
-+ uint32_t vccddq_hi : 1; // Bits 25:25
-+ uint32_t : 3; // Bits 28:26
-+ uint32_t dis_quick_comp : 1; // Bits 29:29
-+ uint32_t sin_step : 1; // Bits 30:30
-+ uint32_t sin_step_adv : 1; // Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
-+union ddr_data_vref_adjust_reg {
-+ struct __packed {
-+ int32_t ca_vref_ctrl : 7;// Bits 6:0
-+ int32_t ch1_vref_ctrl : 7;// Bits 13:7
-+ int32_t ch0_vref_ctrl : 7;// Bits 20:14
-+ uint32_t en_dimm_vref_ca : 1;// Bits 21:21
-+ uint32_t en_dimm_vref_ch1 : 1;// Bits 22:22
-+ uint32_t en_dimm_vref_ch0 : 1;// Bits 23:23
-+ uint32_t hi_z_timer_ctrl : 2;// Bits 25:24
-+ uint32_t vccddq_hi_qnnn_h : 1;// Bits 26:26
-+ uint32_t : 2;// Bits 28:27
-+ uint32_t ca_slow_bw : 1;// Bits 29:29
-+ uint32_t ch0_slow_bw : 1;// Bits 30:30
-+ uint32_t ch1_slow_bw : 1;// Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
-+union ddr_data_vref_control_reg {
-+ struct __packed {
-+ uint32_t hi_bw_divider : 2; // Bits 1:0
-+ uint32_t lo_bw_divider : 2; // Bits 3:2
-+ uint32_t sample_divider : 3; // Bits 6:4
-+ uint32_t open_loop : 1; // Bits 7:7
-+ uint32_t slow_bw_error : 2; // Bits 9:8
-+ uint32_t hi_bw_enable : 1; // Bits 10:10
-+ uint32_t : 1; // Bits 11:11
-+ uint32_t vt_slope_b : 3; // Bits 14:12
-+ uint32_t vt_slope_a : 3; // Bits 17:15
-+ uint32_t vt_offset : 3; // Bits 20:18
-+ uint32_t sel_code : 3; // Bits 23:21
-+ uint32_t output_code : 8; // Bits 31:24
-+ };
-+ uint32_t raw;
-+};
-+
-+union ddr_comp_vsshi_reg {
-+ struct __packed {
-+ uint32_t panic_drv_down_vref : 6; // Bits 5:0
-+ uint32_t panic_drv_up_vref : 6; // Bits 11:6
-+ uint32_t vt_offset : 5; // Bits 16:12
-+ uint32_t vt_slope_a : 3; // Bits 19:17
-+ uint32_t vt_slope_b : 3; // Bits 22:20
-+ uint32_t : 9; // Bits 31:23
-+ };
-+ uint32_t raw;
-+};
-+
-+union ddr_comp_vsshi_control_reg {
-+ struct __packed {
-+ uint32_t vsshi_target : 6; // Bits 5:0
-+ uint32_t hi_bw_divider : 2; // Bits 7:6
-+ uint32_t lo_bw_divider : 2; // Bits 9:8
-+ uint32_t sample_divider : 3; // Bits 12:10
-+ uint32_t open_loop : 1; // Bits 13:13
-+ uint32_t bw_error : 2; // Bits 15:14
-+ uint32_t panic_driver_en : 1; // Bits 16:16
-+ uint32_t : 1; // Bits 17:17
-+ uint32_t panic_voltage : 4; // Bits 21:18
-+ uint32_t gain_boost : 1; // Bits 22:22
-+ uint32_t sel_code : 1; // Bits 23:23
-+ uint32_t output_code : 8; // Bits 31:24
-+ };
-+ uint32_t raw;
-+};
-+
-+union ddr_clk_controls_reg {
-+ struct __packed {
-+ uint32_t ref_pi : 4; // Bits 3:0
-+ uint32_t dll_mask : 2; // Bits 5:4
-+ uint32_t : 1; // Bits 6:6
-+ uint32_t tx_on : 1; // Bits 7:7
-+ uint32_t internal_clocks_on : 1; // Bits 8:8
-+ uint32_t repeater_clocks_on : 1; // Bits 9:9
-+ uint32_t io_lb_ctl : 2; // Bits 11:10
-+ uint32_t odt_mode : 1; // Bits 12:12
-+ uint32_t : 8; // Bits 20:13
-+ uint32_t rx_vref : 6; // Bits 26:21
-+ uint32_t vccddq_hi : 1; // Bits 27:27
-+ uint32_t dll_weaklock : 1; // Bits 28:28
-+ uint32_t lpddr_mode : 1; // Bits 29:29
-+ uint32_t : 2; // Bits 31:30
-+ };
-+ uint32_t raw;
-+};
-+
-+union ddr_cmd_controls_reg {
-+ struct __packed {
-+ int32_t ref_pi : 4; // Bits 3:0
-+ uint32_t dll_mask : 2; // Bits 5:4
-+ uint32_t : 1; // Bits 6:6
-+ uint32_t tx_on : 1; // Bits 7:7
-+ uint32_t internal_clocks_on : 1; // Bits 8:8
-+ uint32_t repeater_clocks_on : 1; // Bits 9:9
-+ uint32_t io_lb_ctl : 2; // Bits 11:10
-+ uint32_t odt_mode : 1; // Bits 12:12
-+ uint32_t cmd_tx_eq : 2; // Bits 14:13
-+ uint32_t early_weak_drive : 2; // Bits 16:15
-+ uint32_t : 4; // Bits 20:17
-+ int32_t rx_vref : 6; // Bits 26:21
-+ uint32_t vccddq_hi : 1; // Bits 27:27
-+ uint32_t dll_weaklock : 1; // Bits 28:28
-+ uint32_t lpddr_mode : 1; // Bits 29:29
-+ uint32_t lpddr_ca_a_dis : 1; // Bits 30:30
-+ uint32_t lpddr_ca_b_dis : 1; // Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
-+/* Same register definition for CKE and CTL fubs */
-+union ddr_cke_ctl_controls_reg {
-+ struct __packed {
-+ int32_t ref_pi : 4; // Bits 3:0
-+ uint32_t dll_mask : 2; // Bits 5:4
-+ uint32_t : 1; // Bits 6:6
-+ uint32_t tx_on : 1; // Bits 7:7
-+ uint32_t internal_clocks_on : 1; // Bits 8:8
-+ uint32_t repeater_clocks_on : 1; // Bits 9:9
-+ uint32_t io_lb_ctl : 2; // Bits 11:10
-+ uint32_t odt_mode : 1; // Bits 12:12
-+ uint32_t cmd_tx_eq : 2; // Bits 14:13
-+ uint32_t early_weak_drive : 2; // Bits 16:15
-+ uint32_t ctl_tx_eq : 2; // Bits 18:17
-+ uint32_t ctl_sr_drv : 2; // Bits 20:19
-+ int32_t rx_vref : 6; // Bits 26:21
-+ uint32_t vccddq_hi : 1; // Bits 27:27
-+ uint32_t dll_weaklock : 1; // Bits 28:28
-+ uint32_t lpddr_mode : 1; // Bits 29:29
-+ uint32_t la_drv_en_ovrd : 1; // Bits 30:30
-+ uint32_t lpddr_ca_a_dis : 1; // Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
-+union ddr_scram_misc_control_reg {
-+ struct __packed {
-+ uint32_t wl_wake_cycles : 2; // Bits 1:0
-+ uint32_t wl_sleep_cycles : 3; // Bits 4:2
-+ uint32_t force_comp_update : 1; // Bits 5:5
-+ uint32_t weaklock_latency : 4; // Bits 9:6
-+ uint32_t ddr_no_ch_interleave : 1; // Bits 10:10
-+ uint32_t lpddr_mode : 1; // Bits 11:11
-+ uint32_t cke_mapping_ch0 : 4; // Bits 15:12
-+ uint32_t cke_mapping_ch1 : 4; // Bits 19:16
-+ uint32_t : 12; // Bits 31:20
-+ };
-+ uint32_t raw;
-+};
-+
-+union mcscheds_cbit_reg {
-+ struct __packed {
-+ uint32_t dis_opp_cas : 1; // Bits 0:0
-+ uint32_t dis_opp_is_cas : 1; // Bits 1:1
-+ uint32_t dis_opp_ras : 1; // Bits 2:2
-+ uint32_t dis_opp_is_ras : 1; // Bits 3:3
-+ uint32_t dis_1c_byp : 1; // Bits 4:4
-+ uint32_t dis_2c_byp : 1; // Bits 5:5
-+ uint32_t dis_deprd_opt : 1; // Bits 6:6
-+ uint32_t dis_pt_it : 1; // Bits 7:7
-+ uint32_t dis_prcnt_ring : 1; // Bits 8:8
-+ uint32_t dis_prcnt_sa : 1; // Bits 9:9
-+ uint32_t dis_blkr_ph : 1; // Bits 10:10
-+ uint32_t dis_blkr_pe : 1; // Bits 11:11
-+ uint32_t dis_blkr_pm : 1; // Bits 12:12
-+ uint32_t dis_odt : 1; // Bits 13:13
-+ uint32_t oe_always_off : 1; // Bits 14:14
-+ uint32_t : 1; // Bits 15:15
-+ uint32_t dis_aom : 1; // Bits 16:16
-+ uint32_t block_rpq : 1; // Bits 17:17
-+ uint32_t block_wpq : 1; // Bits 18:18
-+ uint32_t invert_align : 1; // Bits 19:19
-+ uint32_t dis_write_gap : 1; // Bits 20:20
-+ uint32_t dis_zq : 1; // Bits 21:21
-+ uint32_t dis_tt : 1; // Bits 22:22
-+ uint32_t dis_opp_ref : 1; // Bits 23:23
-+ uint32_t long_zq : 1; // Bits 24:24
-+ uint32_t dis_srx_zq : 1; // Bits 25:25
-+ uint32_t serialize_zq : 1; // Bits 26:26
-+ uint32_t zq_fast_exec : 1; // Bits 27:27
-+ uint32_t dis_drive_nop : 1; // Bits 28:28
-+ uint32_t pres_wdb_ent : 1; // Bits 29:29
-+ uint32_t dis_clk_gate : 1; // Bits 30:30
-+ uint32_t : 1; // Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
-+union mcmain_command_rate_limit_reg {
-+ struct __packed {
-+ uint32_t enable_cmd_limit : 1; // Bits 0:0
-+ uint32_t cmd_rate_limit : 3; // Bits 3:1
-+ uint32_t reset_on_command : 4; // Bits 7:4
-+ uint32_t reset_delay : 4; // Bits 11:8
-+ uint32_t ck_to_cke_delay : 2; // Bits 13:12
-+ uint32_t : 17; // Bits 30:14
-+ uint32_t init_mrw_2n_cs : 1; // Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
-+union mad_chnl_reg {
-+ struct __packed {
-+ uint32_t ch_a : 2; // Bits 1:0
-+ uint32_t ch_b : 2; // Bits 3:2
-+ uint32_t ch_c : 2; // Bits 5:4
-+ uint32_t stacked_mode : 1; // Bits 6:6
-+ uint32_t stkd_mode_bits : 3; // Bits 9:7
-+ uint32_t lpddr_mode : 1; // Bits 10:10
-+ uint32_t : 21; // Bits 31:11
-+ };
-+ uint32_t raw;
-+};
-+
-+union mad_dimm_reg {
-+ struct __packed {
-+ uint32_t dimm_a_size : 8; // Bits 7:0
-+ uint32_t dimm_b_size : 8; // Bits 15:8
-+ uint32_t dimm_a_sel : 1; // Bits 16:16
-+ uint32_t dimm_a_ranks : 1; // Bits 17:17
-+ uint32_t dimm_b_ranks : 1; // Bits 18:18
-+ uint32_t dimm_a_width : 1; // Bits 19:19
-+ uint32_t dimm_b_width : 1; // Bits 20:20
-+ uint32_t rank_interleave : 1; // Bits 21:21
-+ uint32_t enh_interleave : 1; // Bits 22:22
-+ uint32_t : 1; // Bits 23:23
-+ uint32_t ecc_mode : 2; // Bits 25:24
-+ uint32_t hori_mode : 1; // Bits 26:26
-+ uint32_t hori_address : 3; // Bits 29:27
-+ uint32_t : 2; // Bits 31:30
-+ };
-+ uint32_t raw;
-+};
-+
-+union mad_zr_reg {
-+ struct __packed {
-+ uint32_t : 16; // Bits 15:0
-+ uint32_t ch_b_double : 8; // Bits 23:16
-+ uint32_t ch_b_single : 8; // Bits 31:24
-+ };
-+ uint32_t raw;
-+};
-+
-+/* Same definition for P_COMP, M_COMP, D_COMP */
-+union pcu_comp_reg {
-+ struct __packed {
-+ uint32_t comp_disable : 1; // Bits 0:0
-+ uint32_t comp_interval : 4; // Bits 4:1
-+ uint32_t : 3; // Bits 7:5
-+ uint32_t comp_force : 1; // Bits 8:8
-+ uint32_t : 23; // Bits 31:9
-+ };
-+ uint32_t raw;
-+};
-+
-+#endif
-diff --git a/src/northbridge/intel/haswell/native_raminit/timings_refresh.c b/src/northbridge/intel/haswell/native_raminit/timings_refresh.c
-new file mode 100644
-index 0000000000..a9d960f31b
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/timings_refresh.c
-@@ -0,0 +1,13 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include "raminit_native.h"
-+
-+void configure_timings(struct sysinfo *ctrl)
-+{
-+ /** TODO: Stub **/
-+}
-+
-+void configure_refresh(struct sysinfo *ctrl)
-+{
-+ /** TODO: Stub **/
-+}
-diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
-index 45f8174995..4c3f399b5d 100644
---- a/src/northbridge/intel/haswell/registers/mchbar.h
-+++ b/src/northbridge/intel/haswell/registers/mchbar.h
-@@ -7,9 +7,98 @@
- #define NUM_CHANNELS 2
- #define NUM_SLOTS 2
-
-+/* Indexed register helper macros */
-+#define _DDRIO_C_R_B(r, ch, rank, byte) ((r) + 0x100 * (ch) + 0x4 * (rank) + 0x200 * (byte))
-+#define _MCMAIN_C_X(r, ch, x) ((r) + 0x400 * (ch) + 0x4 * (x))
-+#define _MCMAIN_C(r, ch) ((r) + 0x400 * (ch))
-+
- /* Register definitions */
-+
-+/* DDR DATA per-channel per-bytelane */
-+#define DQ_CONTROL_2(ch, byte) _DDRIO_C_R_B(0x0064, ch, 0, byte)
-+
-+/* DDR CKE per-channel */
-+#define DDR_CKE_ch_CMD_COMP_OFFSET(ch) _DDRIO_C_R_B(0x1204, ch, 0, 0)
-+#define DDR_CKE_ch_CMD_PI_CODING(ch) _DDRIO_C_R_B(0x1208, ch, 0, 0)
-+
-+#define DDR_CKE_ch_CTL_CONTROLS(ch) _DDRIO_C_R_B(0x121c, ch, 0, 0)
-+#define DDR_CKE_ch_CTL_RANKS_USED(ch) _DDRIO_C_R_B(0x1220, ch, 0, 0)
-+
-+/* DDR CTL per-channel */
-+#define DDR_CTL_ch_CTL_CONTROLS(ch) _DDRIO_C_R_B(0x1c1c, ch, 0, 0)
-+#define DDR_CTL_ch_CTL_RANKS_USED(ch) _DDRIO_C_R_B(0x1c20, ch, 0, 0)
-+
-+/* DDR CLK per-channel */
-+#define DDR_CLK_ch_RANKS_USED(ch) _DDRIO_C_R_B(0x1800, ch, 0, 0)
-+#define DDR_CLK_ch_COMP_OFFSET(ch) _DDRIO_C_R_B(0x1808, ch, 0, 0)
-+#define DDR_CLK_ch_PI_CODING(ch) _DDRIO_C_R_B(0x180c, ch, 0, 0)
-+#define DDR_CLK_ch_CONTROLS(ch) _DDRIO_C_R_B(0x1810, ch, 0, 0)
-+
-+/* DDR Scrambler */
-+#define DDR_SCRAMBLE_ch(ch) (0x2000 + 4 * (ch))
-+#define DDR_SCRAM_MISC_CONTROL 0x2008
-+
-+/* DDR CMDN/CMDS per-channel (writes go to both CMDN and CMDS fubs) */
-+#define DDR_CMD_ch_COMP_OFFSET(ch) _DDRIO_C_R_B(0x3204, ch, 0, 0)
-+#define DDR_CMD_ch_PI_CODING(ch) _DDRIO_C_R_B(0x3208, ch, 0, 0)
-+#define DDR_CMD_ch_CONTROLS(ch) _DDRIO_C_R_B(0x320c, ch, 0, 0)
-+
-+/* DDR CKE/CTL per-channel (writes go to both CKE and CTL fubs) */
-+#define DDR_CKE_CTL_ch_CTL_COMP_OFFSET(ch) _DDRIO_C_R_B(0x3414, ch, 0, 0)
-+#define DDR_CKE_CTL_ch_CTL_PI_CODING(ch) _DDRIO_C_R_B(0x3418, ch, 0, 0)
-+
-+/* DDR DATA broadcast */
-+#define DDR_DATA_RX_TRAIN_RANK(rank) _DDRIO_C_R_B(0x3600, 0, rank, 0)
-+#define DDR_DATA_RX_PER_BIT_RANK(rank) _DDRIO_C_R_B(0x3610, 0, rank, 0)
-+#define DDR_DATA_TX_TRAIN_RANK(rank) _DDRIO_C_R_B(0x3620, 0, rank, 0)
-+#define DDR_DATA_TX_PER_BIT_RANK(rank) _DDRIO_C_R_B(0x3630, 0, rank, 0)
-+
-+#define DDR_DATA_RCOMP_DATA_1 0x3644
-+#define DDR_DATA_TX_XTALK 0x3648
-+#define DDR_DATA_RX_OFFSET_VDQ 0x364c
-+#define DDR_DATA_OFFSET_COMP 0x365c
-+#define DDR_DATA_CONTROL_1 0x3660
-+
-+#define DDR_DATA_OFFSET_TRAIN 0x3670
-+#define DDR_DATA_CONTROL_0 0x3674
-+#define DDR_DATA_VREF_ADJUST 0x3678
-+
-+/* DDR CMD broadcast */
-+#define DDR_CMD_COMP 0x3700
-+
-+/* DDR CKE/CTL broadcast */
-+#define DDR_CKE_CTL_COMP 0x3810
-+
-+/* DDR CLK broadcast */
-+#define DDR_CLK_COMP 0x3904
-+#define DDR_CLK_CONTROLS 0x3910
-+#define DDR_CLK_CB_STATUS 0x3918
-+
-+/* DDR COMP (global) */
-+#define DDR_COMP_DATA_COMP_1 0x3a04
-+#define DDR_COMP_CMD_COMP 0x3a08
-+#define DDR_COMP_CTL_COMP 0x3a0c
-+#define DDR_COMP_CLK_COMP 0x3a10
-+#define DDR_COMP_CTL_0 0x3a14
-+#define DDR_COMP_CTL_1 0x3a18
-+#define DDR_COMP_VSSHI 0x3a1c
-+#define DDR_COMP_OVERRIDE 0x3a20
-+#define DDR_COMP_VSSHI_CONTROL 0x3a24
-+
-+/* MCMAIN per-channel */
-+#define COMMAND_RATE_LIMIT_ch(ch) _MCMAIN_C(0x4010, ch)
-+
-+#define MC_INIT_STATE_ch(ch) _MCMAIN_C(0x42a0, ch)
-+
-+/* MCMAIN broadcast */
-+#define MCSCHEDS_CBIT 0x4c20
-+
-+#define MCMNTS_SC_WDBWM 0x4f8c
-+
-+/* MCDECS */
- #define MAD_CHNL 0x5000 /* Address Decoder Channel Configuration */
- #define MAD_DIMM(ch) (0x5004 + (ch) * 4)
-+#define MAD_ZR 0x5014
- #define MC_INIT_STATE_G 0x5030
- #define MRC_REVISION 0x5034 /* MRC Revision */
-
-@@ -28,6 +117,8 @@
-
- #define PCU_DDR_PTM_CTL 0x5880
-
-+#define PCU_DDR_VOLTAGE 0x58a4
-+
- /* Some power MSRs are also represented in MCHBAR */
- #define MCH_PKG_POWER_LIMIT_LO 0x59a0
- #define MCH_PKG_POWER_LIMIT_HI 0x59a4
-@@ -48,6 +139,8 @@
- #define MAILBOX_BIOS_CMD_FSM_MEASURE_INTVL 0x909
- #define MAILBOX_BIOS_CMD_READ_PCH_POWER 0xa
- #define MAILBOX_BIOS_CMD_READ_PCH_POWER_EXT 0xb
-+#define MAILBOX_BIOS_CMD_READ_DDR_2X_REFRESH 0x17
-+#define MAILBOX_BIOS_CMD_WRITE_DDR_2X_REFRESH 0x18
- #define MAILBOX_BIOS_CMD_READ_C9C10_VOLTAGE 0x26
- #define MAILBOX_BIOS_CMD_WRITE_C9C10_VOLTAGE 0x27
-
-@@ -66,6 +159,7 @@
- #define MC_BIOS_REQ 0x5e00 /* Memory frequency request register */
- #define MC_BIOS_DATA 0x5e04 /* Miscellaneous information for BIOS */
- #define SAPMCTL 0x5f00
-+#define M_COMP 0x5f08
-
- #define HDAUDRID 0x6008
- #define UMAGFXCTL 0x6020
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0032-lenovo-Add-Kconfig-option-CONFIG_LENOVO_TBFW_BIN.patch b/config/coreboot/default/patches/0032-lenovo-Add-Kconfig-option-CONFIG_LENOVO_TBFW_BIN.patch
new file mode 100644
index 00000000..e60c102f
--- /dev/null
+++ b/config/coreboot/default/patches/0032-lenovo-Add-Kconfig-option-CONFIG_LENOVO_TBFW_BIN.patch
@@ -0,0 +1,78 @@
+From 5d8930edfa1d9537ba80e24c0cf8f0c9e4e9ec72 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <info@minifree.org>
+Date: Wed, 18 Dec 2024 02:06:18 +0000
+Subject: [PATCH 32/37] lenovo: Add Kconfig option CONFIG_LENOVO_TBFW_BIN
+
+This is used by lbmk to know where a tb.bin file goes,
+when extracting and padding TBT.bin from Lenovo ThunderBolt
+firmware updates on T480/T480s and other machines, grabbing
+Lenovo update files.
+
+Not used in any builds, so it's not relevant for ./mk inject
+
+However, the ThunderBolt firmware is now auto-downloaded on
+T480/T480s. This is not inserted, because it doesn't go in
+the main flash, but the resulting ROM image can be flashed
+on the TB controller's separate flash chip.
+
+Locations are as follows:
+
+vendorfiles/t480s/tb.bin
+vendorfiles/t480/tb.bin
+
+This can be used for other affected ThinkPads when they're
+added to Libreboot, but note that Lenovo provides different
+TB firmware files for each machine.
+
+Since I assume it's the same TB controller on all of those
+machines, I have to wonder: what difference is there between
+the various TBT.bin files provided by Lenovo, and how do they
+differ in terms of actual flashed configuration?
+
+We simply flash the padded TBT.bin when updating the firmware,
+flashing externally. That's what this patch is for, so that
+lbmk can auto-download them.
+
+Signed-off-by: Leah Rowe <info@minifree.org>
+---
+ src/mainboard/lenovo/Kconfig | 26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+diff --git a/src/mainboard/lenovo/Kconfig b/src/mainboard/lenovo/Kconfig
+index 2ffbaab85f..512b326381 100644
+--- a/src/mainboard/lenovo/Kconfig
++++ b/src/mainboard/lenovo/Kconfig
+@@ -18,4 +18,30 @@ config MAINBOARD_FAMILY
+ string
+ default MAINBOARD_PART_NUMBER
+
++config LENOVO_TBFW_BIN
++ string "Lenovo ThunderBolt firmware bin file"
++ default ""
++ help
++ ThunderBolt firmware for certain ThinkPad models e.g. T480.
++ Not used in the actual build. Libreboot's build system uses this
++ along with config/vendor/*/pkg.cfg entries defining a URL to the
++ Lenovo download link and hash. The resulting file when processed by
++ lbmk can be flashed to the ThunderBolt firmware's 25XX NOR device.
++ Earlier versions of this firmware had debug commands enabled that
++ sent logs to said flash IC, and it would quickly fill up, bricking
++ the ThunderBolt controller. With these updates, flashed externally,
++ you can fix the issue if present or otherwise prevent it. The benefit
++ here is that you then don't need to use Windows or a boot disk. You
++ can flash the TB firmware while flashing Libreboot firmware. Easy!
++ Look for these variables in lbmk:
++ TBFW_url TBFW_url_bkup TBFW_hash and look at how it handles that and
++ CONFIG_LENOVO_TBFW_BIN, in lbmk's include/vendor.sh file.
++ The path set by CONFIG_LENOVO_TBFW_BIN is used by lbmk when extracting
++ the firmware, putting it at that desired location. In this way, lbmk
++ can auto-download such firmware. E.g. ./mk -d coreboot t480_fsp_16mb
++ and it appears at vendorfiles/t480/tb.bin fully padded and everything!
++
++ Just leave this blank if you don't care about this option. It's not
++ useful for every ThinkPad, only certain models.
++
+ endif # VENDOR_LENOVO
+--
+2.39.5
+
diff --git a/config/coreboot/default/patches/0033-haswell-NRI-Add-timings-refresh-programming.patch b/config/coreboot/default/patches/0033-haswell-NRI-Add-timings-refresh-programming.patch
deleted file mode 100644
index 3ec3b57b..00000000
--- a/config/coreboot/default/patches/0033-haswell-NRI-Add-timings-refresh-programming.patch
+++ /dev/null
@@ -1,541 +0,0 @@
-From 8f94c0428eea2145a97de943b093dee29001c4f9 Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Sat, 7 May 2022 20:59:58 +0200
-Subject: [PATCH 33/51] haswell NRI: Add timings/refresh programming
-
-Program the registers with timing and refresh parameters.
-
-Change-Id: Id2ea339d2c9ea8b56c71d6e88ec76949653ff5c2
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../haswell/native_raminit/lookup_timings.c | 102 ++++++++
- .../haswell/native_raminit/raminit_native.h | 14 ++
- .../haswell/native_raminit/reg_structs.h | 93 +++++++
- .../haswell/native_raminit/timings_refresh.c | 233 +++++++++++++++++-
- .../intel/haswell/registers/mchbar.h | 12 +
- 5 files changed, 452 insertions(+), 2 deletions(-)
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/lookup_timings.c b/src/northbridge/intel/haswell/native_raminit/lookup_timings.c
-index 8b81c7c341..b8d6c1ef40 100644
---- a/src/northbridge/intel/haswell/native_raminit/lookup_timings.c
-+++ b/src/northbridge/intel/haswell/native_raminit/lookup_timings.c
-@@ -60,3 +60,105 @@ uint32_t get_tXP(const uint32_t mem_clock_mhz)
- };
- return lookup_timing(mem_clock_mhz, lut, ARRAY_SIZE(lut));
- }
-+
-+static uint32_t get_lpddr_tCKE(const uint32_t mem_clock_mhz)
-+{
-+ const struct timing_lookup lut[] = {
-+ { 533, 4 },
-+ { 666, 5 },
-+ { fmax, 6 },
-+ };
-+ return lookup_timing(mem_clock_mhz, lut, ARRAY_SIZE(lut));
-+}
-+
-+static uint32_t get_ddr_tCKE(const uint32_t mem_clock_mhz)
-+{
-+ const struct timing_lookup lut[] = {
-+ { 533, 3 },
-+ { 800, 4 },
-+ { 933, 5 },
-+ { 1200, 6 },
-+ { fmax, 7 },
-+ };
-+ return lookup_timing(mem_clock_mhz, lut, ARRAY_SIZE(lut));
-+}
-+
-+uint32_t get_tCKE(const uint32_t mem_clock_mhz, const bool lpddr)
-+{
-+ return lpddr ? get_lpddr_tCKE(mem_clock_mhz) : get_ddr_tCKE(mem_clock_mhz);
-+}
-+
-+uint32_t get_tXPDLL(const uint32_t mem_clock_mhz)
-+{
-+ const struct timing_lookup lut[] = {
-+ { 400, 10 },
-+ { 533, 13 },
-+ { 666, 16 },
-+ { 800, 20 },
-+ { 933, 23 },
-+ { 1066, 26 },
-+ { 1200, 29 },
-+ { fmax, 32 },
-+ };
-+ return lookup_timing(mem_clock_mhz, lut, ARRAY_SIZE(lut));
-+}
-+
-+uint32_t get_tAONPD(const uint32_t mem_clock_mhz)
-+{
-+ const struct timing_lookup lut[] = {
-+ { 400, 4 },
-+ { 533, 5 },
-+ { 666, 6 },
-+ { 800, 7 }, /* SNB had 8 */
-+ { 933, 8 },
-+ { 1066, 10 },
-+ { 1200, 11 },
-+ { fmax, 12 },
-+ };
-+ return lookup_timing(mem_clock_mhz, lut, ARRAY_SIZE(lut));
-+}
-+
-+uint32_t get_tMOD(const uint32_t mem_clock_mhz)
-+{
-+ const struct timing_lookup lut[] = {
-+ { 800, 12 },
-+ { 933, 14 },
-+ { 1066, 16 },
-+ { 1200, 18 },
-+ { fmax, 20 },
-+ };
-+ return lookup_timing(mem_clock_mhz, lut, ARRAY_SIZE(lut));
-+}
-+
-+uint32_t get_tXS_offset(const uint32_t mem_clock_mhz)
-+{
-+ return DIV_ROUND_UP(mem_clock_mhz, 100);
-+}
-+
-+static uint32_t get_lpddr_tZQOPER(const uint32_t mem_clock_mhz)
-+{
-+ return (mem_clock_mhz * 360) / 1000;
-+}
-+
-+static uint32_t get_ddr_tZQOPER(const uint32_t mem_clock_mhz)
-+{
-+ const struct timing_lookup lut[] = {
-+ { 800, 256 },
-+ { 933, 299 },
-+ { 1066, 342 },
-+ { 1200, 384 },
-+ { fmax, 427 },
-+ };
-+ return lookup_timing(mem_clock_mhz, lut, ARRAY_SIZE(lut));
-+}
-+
-+/* tZQOPER defines the period required for ZQCL after SR exit */
-+uint32_t get_tZQOPER(const uint32_t mem_clock_mhz, const bool lpddr)
-+{
-+ return lpddr ? get_lpddr_tZQOPER(mem_clock_mhz) : get_ddr_tZQOPER(mem_clock_mhz);
-+}
-+
-+uint32_t get_tZQCS(const uint32_t mem_clock_mhz, const bool lpddr)
-+{
-+ return DIV_ROUND_UP(get_tZQOPER(mem_clock_mhz, lpddr), 4);
-+}
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index fffa6d5450..5915a2bab0 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -156,6 +156,12 @@ struct sysinfo {
- uint8_t cke_cmd_pi_code[NUM_CHANNELS][NUM_GROUPS];
- uint8_t cmd_north_pi_code[NUM_CHANNELS][NUM_GROUPS];
- uint8_t cmd_south_pi_code[NUM_CHANNELS][NUM_GROUPS];
-+
-+ union tc_bank_reg tc_bank[NUM_CHANNELS];
-+ union tc_bank_rank_a_reg tc_bankrank_a[NUM_CHANNELS];
-+ union tc_bank_rank_b_reg tc_bankrank_b[NUM_CHANNELS];
-+ union tc_bank_rank_c_reg tc_bankrank_c[NUM_CHANNELS];
-+ union tc_bank_rank_d_reg tc_bankrank_d[NUM_CHANNELS];
- };
-
- static inline bool is_hsw_ult(void)
-@@ -201,6 +207,14 @@ enum raminit_status configure_mc(struct sysinfo *ctrl);
- void configure_timings(struct sysinfo *ctrl);
- void configure_refresh(struct sysinfo *ctrl);
-
-+uint32_t get_tCKE(uint32_t mem_clock_mhz, bool lpddr);
-+uint32_t get_tXPDLL(uint32_t mem_clock_mhz);
-+uint32_t get_tAONPD(uint32_t mem_clock_mhz);
-+uint32_t get_tMOD(uint32_t mem_clock_mhz);
-+uint32_t get_tXS_offset(uint32_t mem_clock_mhz);
-+uint32_t get_tZQOPER(uint32_t mem_clock_mhz, bool lpddr);
-+uint32_t get_tZQCS(uint32_t mem_clock_mhz, bool lpddr);
-+
- enum raminit_status wait_for_first_rcomp(void);
-
- uint8_t get_rx_bias(const struct sysinfo *ctrl);
-diff --git a/src/northbridge/intel/haswell/native_raminit/reg_structs.h b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-index d11cda4b3d..70487e1640 100644
---- a/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-+++ b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-@@ -335,6 +335,99 @@ union mcscheds_cbit_reg {
- uint32_t raw;
- };
-
-+union tc_bank_reg {
-+ struct __packed {
-+ uint32_t tRCD : 5; // Bits 4:0
-+ uint32_t tRP : 5; // Bits 9:5
-+ uint32_t tRAS : 6; // Bits 15:10
-+ uint32_t tRDPRE : 4; // Bits 19:16
-+ uint32_t tWRPRE : 6; // Bits 25:20
-+ uint32_t tRRD : 4; // Bits 29:26
-+ uint32_t tRPab_ext : 2; // Bits 31:30
-+ };
-+ uint32_t raw;
-+};
-+
-+union tc_bank_rank_a_reg {
-+ struct __packed {
-+ uint32_t tCKE : 4; // Bits 3:0
-+ uint32_t tFAW : 8; // Bits 11:4
-+ uint32_t tRDRD_sr : 3; // Bits 14:12
-+ uint32_t tRDRD_dr : 4; // Bits 18:15
-+ uint32_t tRDRD_dd : 4; // Bits 22:19
-+ uint32_t tRDPDEN : 5; // Bits 27:23
-+ uint32_t : 1; // Bits 28:28
-+ uint32_t cmd_3st_dis : 1; // Bits 29:29
-+ uint32_t cmd_stretch : 2; // Bits 31:30
-+ };
-+ uint32_t raw;
-+};
-+
-+union tc_bank_rank_b_reg {
-+ struct __packed {
-+ uint32_t tWRRD_sr : 6; // Bits 5:0
-+ uint32_t tWRRD_dr : 4; // Bits 9:6
-+ uint32_t tWRRD_dd : 4; // Bits 13:10
-+ uint32_t tWRWR_sr : 3; // Bits 16:14
-+ uint32_t tWRWR_dr : 4; // Bits 20:17
-+ uint32_t tWRWR_dd : 4; // Bits 24:21
-+ uint32_t tWRPDEN : 6; // Bits 30:25
-+ uint32_t dec_wrd : 1; // Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
-+union tc_bank_rank_c_reg {
-+ struct __packed {
-+ uint32_t tXPDLL : 6; // Bits 5:0
-+ uint32_t tXP : 4; // Bits 9:6
-+ uint32_t tAONPD : 4; // Bits 13:10
-+ uint32_t tRDWR_sr : 5; // Bits 18:14
-+ uint32_t tRDWR_dr : 5; // Bits 23:19
-+ uint32_t tRDWR_dd : 5; // Bits 28:24
-+ uint32_t : 3; // Bits 31:29
-+ };
-+ uint32_t raw;
-+};
-+
-+/* NOTE: Non-ULT only implements the lower 21 bits (odt_write_delay is 2 bits) */
-+union tc_bank_rank_d_reg {
-+ struct __packed {
-+ uint32_t tAA : 5; // Bits 4:0
-+ uint32_t tCWL : 5; // Bits 9:5
-+ uint32_t tCPDED : 2; // Bits 11:10
-+ uint32_t tPRPDEN : 2; // Bits 13:12
-+ uint32_t odt_read_delay : 3; // Bits 16:14
-+ uint32_t odt_read_duration : 2; // Bits 18:17
-+ uint32_t odt_write_duration : 3; // Bits 21:19
-+ uint32_t odt_write_delay : 3; // Bits 24:22
-+ uint32_t odt_always_rank_0 : 1; // Bits 25:25
-+ uint32_t cmd_delay : 2; // Bits 27:26
-+ uint32_t : 4; // Bits 31:28
-+ };
-+ uint32_t raw;
-+};
-+
-+union tc_rftp_reg {
-+ struct __packed {
-+ uint32_t tREFI : 16; // Bits 15:0
-+ uint32_t tRFC : 9; // Bits 24:16
-+ uint32_t tREFIx9 : 7; // Bits 31:25
-+ };
-+ uint32_t raw;
-+};
-+
-+union tc_srftp_reg {
-+ struct __packed {
-+ uint32_t tXSDLL : 12; // Bits 11:0
-+ uint32_t tXS_offset : 4; // Bits 15:12
-+ uint32_t tZQOPER : 10; // Bits 25:16
-+ uint32_t : 2; // Bits 27:26
-+ uint32_t tMOD : 4; // Bits 31:28
-+ };
-+ uint32_t raw;
-+};
-+
- union mcmain_command_rate_limit_reg {
- struct __packed {
- uint32_t enable_cmd_limit : 1; // Bits 0:0
-diff --git a/src/northbridge/intel/haswell/native_raminit/timings_refresh.c b/src/northbridge/intel/haswell/native_raminit/timings_refresh.c
-index a9d960f31b..54fee0121d 100644
---- a/src/northbridge/intel/haswell/native_raminit/timings_refresh.c
-+++ b/src/northbridge/intel/haswell/native_raminit/timings_refresh.c
-@@ -1,13 +1,242 @@
- /* SPDX-License-Identifier: GPL-2.0-or-later */
-
-+#include <assert.h>
-+#include <commonlib/bsd/clamp.h>
-+#include <console/console.h>
-+#include <delay.h>
-+#include <device/pci_ops.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+
- #include "raminit_native.h"
-
-+#define BL 8 /* Burst length */
-+#define tCCD 4
-+#define tRPRE 1
-+#define tWPRE 1
-+#define tDLLK 512
-+
-+static bool is_sodimm(const enum spd_dimm_type_ddr3 type)
-+{
-+ return type == SPD_DDR3_DIMM_TYPE_SO_DIMM || type == SPD_DDR3_DIMM_TYPE_72B_SO_UDIMM;
-+}
-+
-+static uint8_t get_odt_stretch(const struct sysinfo *const ctrl)
-+{
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ /* Only stretch with 2 DIMMs per channel */
-+ if (ctrl->dpc[channel] != 2)
-+ continue;
-+
-+ const struct raminit_dimm_info *dimms = ctrl->dimms[channel];
-+
-+ /* Only stretch when using SO-DIMMs */
-+ if (!is_sodimm(dimms[0].data.dimm_type) || !is_sodimm(dimms[1].data.dimm_type))
-+ continue;
-+
-+ /* Only stretch with mismatched card types */
-+ if (dimms[0].data.reference_card == dimms[1].data.reference_card)
-+ continue;
-+
-+ /* Stretch if one SO-DIMM is card F */
-+ for (uint8_t slot = 0; slot < NUM_SLOTS; slot++) {
-+ if (dimms[slot].data.reference_card == 5)
-+ return 1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+static union tc_bank_reg make_tc_bank(struct sysinfo *const ctrl)
-+{
-+ return (union tc_bank_reg) {
-+ .tRCD = ctrl->tRCD,
-+ .tRP = ctrl->tRP,
-+ .tRAS = ctrl->tRAS,
-+ .tRDPRE = ctrl->tRTP,
-+ .tWRPRE = 4 + ctrl->tCWL + ctrl->tWR,
-+ .tRRD = ctrl->tRRD,
-+ .tRPab_ext = 0, /** TODO: For LPDDR, this is ctrl->tRPab - ctrl->tRP **/
-+ };
-+}
-+
-+static union tc_bank_rank_a_reg make_tc_bankrank_a(struct sysinfo *ctrl, uint8_t odt_stretch)
-+{
-+ /* Use 3N mode for DDR during training, but always use 1N mode for LPDDR */
-+ const uint32_t tCMD = ctrl->lpddr ? 0 : 3;
-+ const uint32_t tRDRD_drdd = BL / 2 + 1 + tRPRE + odt_stretch + !!ctrl->lpddr;
-+
-+ return (union tc_bank_rank_a_reg) {
-+ .tCKE = get_tCKE(ctrl->mem_clock_mhz, ctrl->lpddr),
-+ .tFAW = ctrl->tFAW,
-+ .tRDRD_sr = tCCD,
-+ .tRDRD_dr = tRDRD_drdd,
-+ .tRDRD_dd = tRDRD_drdd,
-+ .tRDPDEN = ctrl->tAA + BL / 2 + 1,
-+ .cmd_3st_dis = 1, /* Disable command tri-state before training */
-+ .cmd_stretch = tCMD,
-+ };
-+}
-+
-+static union tc_bank_rank_b_reg make_tc_bankrank_b(struct sysinfo *const ctrl)
-+{
-+ const uint8_t tWRRD_drdd = ctrl->tCWL - ctrl->tAA + BL / 2 + 2 + tRPRE;
-+ const uint8_t tWRWR_drdd = BL / 2 + 2 + tWPRE;
-+
-+ return (union tc_bank_rank_b_reg) {
-+ .tWRRD_sr = tCCD + ctrl->tCWL + ctrl->tWTR + 2,
-+ .tWRRD_dr = ctrl->lpddr ? 8 : tWRRD_drdd,
-+ .tWRRD_dd = ctrl->lpddr ? 8 : tWRRD_drdd,
-+ .tWRWR_sr = tCCD,
-+ .tWRWR_dr = tWRWR_drdd,
-+ .tWRWR_dd = tWRWR_drdd,
-+ .tWRPDEN = ctrl->tWR + ctrl->tCWL + BL / 2,
-+ .dec_wrd = ctrl->tCWL >= 6,
-+ };
-+}
-+
-+static uint32_t get_tRDWR_sr(const struct sysinfo *ctrl)
-+{
-+ if (ctrl->lpddr) {
-+ const uint32_t tdqsck_max = DIV_ROUND_UP(5500, ctrl->qclkps * 2);
-+ return ctrl->tAA - ctrl->tCWL + tCCD + tWPRE + tdqsck_max + 1;
-+ } else {
-+ const bool fast_clock = ctrl->mem_clock_mhz > 666;
-+ return ctrl->tAA - ctrl->tCWL + tCCD + tWPRE + 2 + fast_clock;
-+ }
-+}
-+
-+static union tc_bank_rank_c_reg make_tc_bankrank_c(struct sysinfo *ctrl, uint8_t odt_stretch)
-+{
-+ const uint32_t tRDWR_sr = get_tRDWR_sr(ctrl);
-+ const uint32_t tRDWR_drdd = tRDWR_sr + odt_stretch;
-+
-+ return (union tc_bank_rank_c_reg) {
-+ .tXPDLL = get_tXPDLL(ctrl->mem_clock_mhz),
-+ .tXP = MAX(ctrl->tXP, 7), /* Use a higher tXP for training */
-+ .tAONPD = get_tAONPD(ctrl->mem_clock_mhz),
-+ .tRDWR_sr = tRDWR_sr,
-+ .tRDWR_dr = tRDWR_drdd,
-+ .tRDWR_dd = tRDWR_drdd,
-+ };
-+}
-+
-+static union tc_bank_rank_d_reg make_tc_bankrank_d(struct sysinfo *ctrl, uint8_t odt_stretch)
-+{
-+ const uint32_t odt_rd_delay = ctrl->tAA - ctrl->tCWL;
-+ if (!ctrl->lpddr) {
-+ return (union tc_bank_rank_d_reg) {
-+ .tAA = ctrl->tAA,
-+ .tCWL = ctrl->tCWL,
-+ .tCPDED = 1,
-+ .tPRPDEN = 1,
-+ .odt_read_delay = odt_rd_delay,
-+ .odt_read_duration = odt_stretch,
-+ };
-+ }
-+
-+ /* tCWL has 1 extra clock because of tDQSS, subtract it here */
-+ const uint32_t tCWL_lpddr = ctrl->tCWL - 1;
-+ const uint32_t odt_wr_delay = tCWL_lpddr + DIV_ROUND_UP(3500, ctrl->qclkps * 2);
-+ const uint32_t odt_wr_duration = DIV_ROUND_UP(3500 - 1750, ctrl->qclkps * 2) + 1;
-+
-+ return (union tc_bank_rank_d_reg) {
-+ .tAA = ctrl->tAA,
-+ .tCWL = tCWL_lpddr,
-+ .tCPDED = 2, /* Required by JEDEC LPDDR3 spec */
-+ .tPRPDEN = 1,
-+ .odt_read_delay = odt_rd_delay,
-+ .odt_read_duration = odt_stretch,
-+ .odt_write_delay = odt_wr_delay,
-+ .odt_write_duration = odt_wr_duration,
-+ .odt_always_rank_0 = ctrl->lpddr_dram_odt
-+ };
-+}
-+
-+/* ZQCS period values, in (tREFI * 128) units */
-+#define ZQCS_PERIOD_DDR3 128 /* tREFI * 128 = 7.8 us * 128 = 1ms */
-+#define ZQCS_PERIOD_LPDDR3 256 /* tREFI * 128 = 3.9 us * 128 = 0.5ms */
-+
-+static uint32_t make_tc_zqcal(const struct sysinfo *const ctrl)
-+{
-+ const uint32_t zqcs_period = ctrl->lpddr ? ZQCS_PERIOD_LPDDR3 : ZQCS_PERIOD_DDR3;
-+ const uint32_t tZQCS = get_tZQCS(ctrl->mem_clock_mhz, ctrl->lpddr);
-+ return tZQCS << (is_hsw_ult() ? 10 : 8) | zqcs_period;
-+}
-+
-+static union tc_rftp_reg make_tc_rftp(const struct sysinfo *const ctrl)
-+{
-+ /*
-+ * The tREFIx9 field should be programmed to minimum of 8.9 * tREFI (to allow
-+ * for possible delays from ZQ or isoc) and tRASmax (70us) divided by 1024.
-+ */
-+ return (union tc_rftp_reg) {
-+ .tREFI = ctrl->tREFI,
-+ .tRFC = ctrl->tRFC,
-+ .tREFIx9 = ctrl->tREFI * 89 / 10240,
-+ };
-+}
-+
-+static union tc_srftp_reg make_tc_srftp(const struct sysinfo *const ctrl)
-+{
-+ return (union tc_srftp_reg) {
-+ .tXSDLL = tDLLK,
-+ .tXS_offset = get_tXS_offset(ctrl->mem_clock_mhz),
-+ .tZQOPER = get_tZQOPER(ctrl->mem_clock_mhz, ctrl->lpddr),
-+ .tMOD = get_tMOD(ctrl->mem_clock_mhz) - 8,
-+ };
-+}
-+
- void configure_timings(struct sysinfo *ctrl)
- {
-- /** TODO: Stub **/
-+ if (ctrl->lpddr)
-+ die("%s: Missing support for LPDDR\n", __func__);
-+
-+ const uint8_t odt_stretch = get_odt_stretch(ctrl);
-+ const union tc_bank_reg tc_bank = make_tc_bank(ctrl);
-+ const union tc_bank_rank_a_reg tc_bank_rank_a = make_tc_bankrank_a(ctrl, odt_stretch);
-+ const union tc_bank_rank_b_reg tc_bank_rank_b = make_tc_bankrank_b(ctrl);
-+ const union tc_bank_rank_c_reg tc_bank_rank_c = make_tc_bankrank_c(ctrl, odt_stretch);
-+ const union tc_bank_rank_d_reg tc_bank_rank_d = make_tc_bankrank_d(ctrl, odt_stretch);
-+
-+ const uint8_t wr_delay = tc_bank_rank_b.dec_wrd + 1;
-+ uint8_t sc_wr_add_delay = 0;
-+ sc_wr_add_delay |= wr_delay << 0;
-+ sc_wr_add_delay |= wr_delay << 2;
-+ sc_wr_add_delay |= wr_delay << 4;
-+ sc_wr_add_delay |= wr_delay << 6;
-+
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ ctrl->tc_bank[channel] = tc_bank;
-+ ctrl->tc_bankrank_a[channel] = tc_bank_rank_a;
-+ ctrl->tc_bankrank_b[channel] = tc_bank_rank_b;
-+ ctrl->tc_bankrank_c[channel] = tc_bank_rank_c;
-+ ctrl->tc_bankrank_d[channel] = tc_bank_rank_d;
-+
-+ mchbar_write32(TC_BANK_ch(channel), ctrl->tc_bank[channel].raw);
-+ mchbar_write32(TC_BANK_RANK_A_ch(channel), ctrl->tc_bankrank_a[channel].raw);
-+ mchbar_write32(TC_BANK_RANK_B_ch(channel), ctrl->tc_bankrank_b[channel].raw);
-+ mchbar_write32(TC_BANK_RANK_C_ch(channel), ctrl->tc_bankrank_c[channel].raw);
-+ mchbar_write32(TC_BANK_RANK_D_ch(channel), ctrl->tc_bankrank_d[channel].raw);
-+ mchbar_write8(SC_WR_ADD_DELAY_ch(channel), sc_wr_add_delay);
-+ }
- }
-
- void configure_refresh(struct sysinfo *ctrl)
- {
-- /** TODO: Stub **/
-+ const union tc_srftp_reg tc_srftp = make_tc_srftp(ctrl);
-+ const union tc_rftp_reg tc_rftp = make_tc_rftp(ctrl);
-+ const uint32_t tc_zqcal = make_tc_zqcal(ctrl);
-+
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ mchbar_setbits32(TC_RFP_ch(channel), 0xff);
-+ mchbar_write32(TC_RFTP_ch(channel), tc_rftp.raw);
-+ mchbar_write32(TC_SRFTP_ch(channel), tc_srftp.raw);
-+ mchbar_write32(TC_ZQCAL_ch(channel), tc_zqcal);
-+ }
- }
-diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
-index 4c3f399b5d..2acc5cbbc8 100644
---- a/src/northbridge/intel/haswell/registers/mchbar.h
-+++ b/src/northbridge/intel/haswell/registers/mchbar.h
-@@ -86,9 +86,21 @@
- #define DDR_COMP_VSSHI_CONTROL 0x3a24
-
- /* MCMAIN per-channel */
-+#define TC_BANK_ch(ch) _MCMAIN_C(0x4000, ch)
-+#define TC_BANK_RANK_A_ch(ch) _MCMAIN_C(0x4004, ch)
-+#define TC_BANK_RANK_B_ch(ch) _MCMAIN_C(0x4008, ch)
-+#define TC_BANK_RANK_C_ch(ch) _MCMAIN_C(0x400c, ch)
- #define COMMAND_RATE_LIMIT_ch(ch) _MCMAIN_C(0x4010, ch)
-+#define TC_BANK_RANK_D_ch(ch) _MCMAIN_C(0x4014, ch)
-+#define SC_ROUNDT_LAT_ch(ch) _MCMAIN_C(0x4024, ch)
-
-+#define SC_WR_ADD_DELAY_ch(ch) _MCMAIN_C(0x40d0, ch)
-+
-+#define TC_ZQCAL_ch(ch) _MCMAIN_C(0x4290, ch)
-+#define TC_RFP_ch(ch) _MCMAIN_C(0x4294, ch)
-+#define TC_RFTP_ch(ch) _MCMAIN_C(0x4298, ch)
- #define MC_INIT_STATE_ch(ch) _MCMAIN_C(0x42a0, ch)
-+#define TC_SRFTP_ch(ch) _MCMAIN_C(0x42a4, ch)
-
- /* MCMAIN broadcast */
- #define MCSCHEDS_CBIT 0x4c20
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0033-soc-intel-skylake-Don-t-compress-FSP-S.patch b/config/coreboot/default/patches/0033-soc-intel-skylake-Don-t-compress-FSP-S.patch
new file mode 100644
index 00000000..a7ab5a96
--- /dev/null
+++ b/config/coreboot/default/patches/0033-soc-intel-skylake-Don-t-compress-FSP-S.patch
@@ -0,0 +1,36 @@
+From 49cee334bc7fe9a78b9355b5256a37984bac385a Mon Sep 17 00:00:00 2001
+From: Leah Rowe <info@minifree.org>
+Date: Thu, 26 Dec 2024 19:45:20 +0000
+Subject: [PATCH 33/37] soc/intel/skylake: Don't compress FSP-S
+
+Build systems like lbmk need to reproducibly insert
+certain vendor files on release images.
+
+Compression isn't always reproducible, and making it
+so costs a lot more time than simply disabling compression.
+
+With this change, the FSP-S module will now be inserted
+without compression, which means that there will now be
+about 40KB of extra space used in the flash.
+
+Signed-off-by: Leah Rowe <info@minifree.org>
+---
+ src/soc/intel/skylake/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/soc/intel/skylake/Kconfig b/src/soc/intel/skylake/Kconfig
+index 9191ed0ff8..d51ffaef7b 100644
+--- a/src/soc/intel/skylake/Kconfig
++++ b/src/soc/intel/skylake/Kconfig
+@@ -12,7 +12,7 @@ config SOC_INTEL_COMMON_SKYLAKE_BASE
+ select CPU_SUPPORTS_PM_TIMER_EMULATION
+ select DRIVERS_USB_ACPI
+ select EDK2_CPU_TIMER_LIB if PAYLOAD_EDK2
+- select FSP_COMPRESS_FSP_S_LZ4
++# select FSP_COMPRESS_FSP_S_LZ4
+ select FSP_M_XIP
+ select GENERIC_GPIO_LIB
+ select HAVE_FSP_GOP
+--
+2.39.5
+
diff --git a/config/coreboot/default/patches/0034-haswell-NRI-Program-memory-map.patch b/config/coreboot/default/patches/0034-haswell-NRI-Program-memory-map.patch
deleted file mode 100644
index bb3ed03d..00000000
--- a/config/coreboot/default/patches/0034-haswell-NRI-Program-memory-map.patch
+++ /dev/null
@@ -1,263 +0,0 @@
-From ded914f236f76715aa43cb439a3de7df9a3dfa11 Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Sat, 7 May 2022 21:24:50 +0200
-Subject: [PATCH 34/51] haswell NRI: Program memory map
-
-This is very similar to Sandy/Ivy Bridge, except that there's several
-registers to program in GDXCBAR. One of these GDXCBAR registers has a
-lock bit that must be set in order for the memory controller to allow
-normal access to DRAM. And it took me four months to realize this one
-bit was the only reason why native raminit did not work.
-
-Change-Id: I3af73a018a7ba948701a542e661e7fefd57591fe
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../intel/haswell/native_raminit/Makefile.mk | 1 +
- .../intel/haswell/native_raminit/memory_map.c | 183 ++++++++++++++++++
- .../haswell/native_raminit/raminit_main.c | 1 +
- .../haswell/native_raminit/raminit_native.h | 1 +
- .../intel/haswell/registers/host_bridge.h | 2 +
- 5 files changed, 188 insertions(+)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/memory_map.c
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-index fc55277a65..37d527e972 100644
---- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-@@ -4,6 +4,7 @@ romstage-y += configure_mc.c
- romstage-y += lookup_timings.c
- romstage-y += init_mpll.c
- romstage-y += io_comp_control.c
-+romstage-y += memory_map.c
- romstage-y += raminit_main.c
- romstage-y += raminit_native.c
- romstage-y += spd_bitmunching.c
-diff --git a/src/northbridge/intel/haswell/native_raminit/memory_map.c b/src/northbridge/intel/haswell/native_raminit/memory_map.c
-new file mode 100644
-index 0000000000..e3aded2b37
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/memory_map.c
-@@ -0,0 +1,183 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <device/pci_ops.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <southbridge/intel/lynxpoint/me.h>
-+#include <types.h>
-+
-+#include "raminit_native.h"
-+
-+/* GDXCBAR */
-+#define MPCOHTRK_GDXC_MOT_ADDRESS_LO 0x10
-+#define MPCOHTRK_GDXC_MOT_ADDRESS_HI 0x14
-+#define MPCOHTRK_GDXC_MOT_REGION 0x18
-+
-+#define MPCOHTRK_GDXC_OCLA_ADDRESS_LO 0x20
-+#define MPCOHTRK_GDXC_OCLA_ADDRESS_HI 0x24
-+#define MPCOHTRK_GDXC_OCLA_REGION 0x28
-+
-+/* This lock bit made me lose what little sanity I had left. - Angel Pons */
-+#define MPCOHTRK_GDXC_OCLA_ADDRESS_HI_LOCK BIT(2)
-+
-+static inline uint32_t gdxcbar_read32(const uintptr_t offset)
-+{
-+ return read32p((mchbar_read32(GDXCBAR) & ~1) + offset);
-+}
-+
-+static inline void gdxcbar_write32(const uintptr_t offset, const uint32_t value)
-+{
-+ write32p((mchbar_read32(GDXCBAR) & ~1) + offset, value);
-+}
-+
-+static inline void gdxcbar_clrsetbits32(const uintptr_t offset, uint32_t clear, uint32_t set)
-+{
-+ const uintptr_t address = (mchbar_read32(GDXCBAR) & ~1) + offset;
-+ clrsetbits32((void *)address, clear, set);
-+}
-+
-+#define gdxcbar_setbits32(offset, set) gdxcbar_clrsetbits32(offset, 0, set)
-+#define gdxcbar_clrbits32(offset, clear) gdxcbar_clrsetbits32(offset, clear, 0)
-+
-+/* All values stored in here (except the bool) are specified in MiB */
-+struct memory_map_data {
-+ uint32_t dpr_size;
-+ uint32_t tseg_size;
-+ uint32_t gtt_size;
-+ uint32_t gms_size;
-+ uint32_t me_stolen_size;
-+ uint32_t mmio_size;
-+ uint32_t touud;
-+ uint32_t remaplimit;
-+ uint32_t remapbase;
-+ uint32_t tom;
-+ uint32_t tom_minus_me;
-+ uint32_t tolud;
-+ uint32_t bdsm_base;
-+ uint32_t gtt_base;
-+ uint32_t tseg_base;
-+ bool reclaim_possible;
-+};
-+
-+static void compute_memory_map(struct memory_map_data *map)
-+{
-+ map->tom_minus_me = map->tom - map->me_stolen_size;
-+
-+ /*
-+ * MMIO size will actually be slightly smaller than computed,
-+ * but matches what MRC does and is more MTRR-friendly given
-+ * that TSEG is treated as WB, but SMRR makes TSEG UC anyway.
-+ */
-+ const uint32_t mmio_size = MIN(map->tom_minus_me, 4096) / 2;
-+ map->gtt_base = ALIGN_DOWN(mmio_size, map->tseg_size);
-+ map->tseg_base = map->gtt_base - map->tseg_size;
-+ map->bdsm_base = map->gtt_base + map->gtt_size;
-+ map->tolud = map->bdsm_base + map->gms_size;
-+ map->reclaim_possible = map->tom_minus_me > map->tolud;
-+
-+ if (map->reclaim_possible) {
-+ map->remapbase = MAX(4096, map->tom_minus_me);
-+ map->touud = MIN(4096, map->tom_minus_me) + map->remapbase - map->tolud;
-+ map->remaplimit = map->touud - 1;
-+ } else {
-+ map->remapbase = 0;
-+ map->remaplimit = 0;
-+ map->touud = map->tom_minus_me;
-+ }
-+}
-+
-+static void display_memory_map(const struct memory_map_data *map)
-+{
-+ if (!CONFIG(DEBUG_RAM_SETUP))
-+ return;
-+
-+ printk(BIOS_DEBUG, "============ MEMORY MAP ============\n");
-+ printk(BIOS_DEBUG, "\n");
-+ printk(BIOS_DEBUG, "dpr_size = %u MiB\n", map->dpr_size);
-+ printk(BIOS_DEBUG, "tseg_size = %u MiB\n", map->tseg_size);
-+ printk(BIOS_DEBUG, "gtt_size = %u MiB\n", map->gtt_size);
-+ printk(BIOS_DEBUG, "gms_size = %u MiB\n", map->gms_size);
-+ printk(BIOS_DEBUG, "me_stolen_size = %u MiB\n", map->me_stolen_size);
-+ printk(BIOS_DEBUG, "\n");
-+ printk(BIOS_DEBUG, "touud = %u MiB\n", map->touud);
-+ printk(BIOS_DEBUG, "remaplimit = %u MiB\n", map->remaplimit);
-+ printk(BIOS_DEBUG, "remapbase = %u MiB\n", map->remapbase);
-+ printk(BIOS_DEBUG, "tom = %u MiB\n", map->tom);
-+ printk(BIOS_DEBUG, "tom_minus_me = %u MiB\n", map->tom_minus_me);
-+ printk(BIOS_DEBUG, "tolud = %u MiB\n", map->tolud);
-+ printk(BIOS_DEBUG, "bdsm_base = %u MiB\n", map->bdsm_base);
-+ printk(BIOS_DEBUG, "gtt_base = %u MiB\n", map->gtt_base);
-+ printk(BIOS_DEBUG, "tseg_base = %u MiB\n", map->tseg_base);
-+ printk(BIOS_DEBUG, "\n");
-+ printk(BIOS_DEBUG, "reclaim_possible = %s\n", map->reclaim_possible ? "Yes" : "No");
-+}
-+
-+static void map_write_reg64(const uint16_t reg, const uint64_t size)
-+{
-+ const uint64_t value = size << 20;
-+ pci_write_config32(HOST_BRIDGE, reg + 4, value >> 32);
-+ pci_write_config32(HOST_BRIDGE, reg + 0, value >> 0);
-+}
-+
-+static void map_write_reg32(const uint16_t reg, const uint32_t size)
-+{
-+ const uint32_t value = size << 20;
-+ pci_write_config32(HOST_BRIDGE, reg, value);
-+}
-+
-+static void program_memory_map(const struct memory_map_data *map)
-+{
-+ map_write_reg64(TOUUD, map->touud);
-+ map_write_reg64(TOM, map->tom);
-+ if (map->reclaim_possible) {
-+ map_write_reg64(REMAPBASE, map->remapbase);
-+ map_write_reg64(REMAPLIMIT, map->remaplimit);
-+ }
-+ if (map->me_stolen_size) {
-+ map_write_reg64(MESEG_LIMIT, 0x80000 - map->me_stolen_size);
-+ map_write_reg64(MESEG_BASE, map->tom_minus_me);
-+ pci_or_config32(HOST_BRIDGE, MESEG_LIMIT, ME_STLEN_EN);
-+ }
-+ map_write_reg32(TOLUD, map->tolud);
-+ map_write_reg32(BDSM, map->bdsm_base);
-+ map_write_reg32(BGSM, map->gtt_base);
-+ map_write_reg32(TSEG, map->tseg_base);
-+
-+ const uint32_t dpr_reg = map->tseg_base << 20 | map->dpr_size << 4;
-+ pci_write_config32(HOST_BRIDGE, DPR, dpr_reg);
-+
-+ const uint16_t gfx_stolen_size = GGC_IGD_MEM_IN_32MB_UNITS(map->gms_size / 32);
-+ const uint16_t ggc = map->gtt_size << 8 | gfx_stolen_size;
-+ pci_write_config16(HOST_BRIDGE, GGC, ggc);
-+
-+ /** TODO: Do not hardcode these? GDXC has weird alignment requirements, though. **/
-+ gdxcbar_write32(MPCOHTRK_GDXC_MOT_ADDRESS_LO, 0);
-+ gdxcbar_write32(MPCOHTRK_GDXC_MOT_ADDRESS_HI, 0);
-+ gdxcbar_write32(MPCOHTRK_GDXC_MOT_REGION, 0);
-+
-+ gdxcbar_write32(MPCOHTRK_GDXC_OCLA_ADDRESS_LO, 0);
-+ gdxcbar_write32(MPCOHTRK_GDXC_OCLA_ADDRESS_HI, 0);
-+ gdxcbar_write32(MPCOHTRK_GDXC_OCLA_REGION, 0);
-+
-+ gdxcbar_setbits32(MPCOHTRK_GDXC_OCLA_ADDRESS_HI, MPCOHTRK_GDXC_OCLA_ADDRESS_HI_LOCK);
-+}
-+
-+enum raminit_status configure_memory_map(struct sysinfo *ctrl)
-+{
-+ struct memory_map_data memory_map = {
-+ .tom = ctrl->channel_size_mb[0] + ctrl->channel_size_mb[1],
-+ .dpr_size = CONFIG_INTEL_TXT_DPR_SIZE,
-+ .tseg_size = CONFIG_SMM_TSEG_SIZE >> 20,
-+ .me_stolen_size = intel_early_me_uma_size(),
-+ };
-+ /** FIXME: MRC hardcodes iGPU parameters, but we should not **/
-+ const bool igpu_on = pci_read_config32(HOST_BRIDGE, DEVEN) & DEVEN_D2EN;
-+ if (CONFIG(ONBOARD_VGA_IS_PRIMARY) || igpu_on) {
-+ memory_map.gtt_size = 2;
-+ memory_map.gms_size = 64;
-+ pci_or_config32(HOST_BRIDGE, DEVEN, DEVEN_D2EN);
-+ }
-+ compute_memory_map(&memory_map);
-+ display_memory_map(&memory_map);
-+ program_memory_map(&memory_map);
-+ return 0;
-+}
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-index fcc981ad04..559dfc3a4e 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-@@ -23,6 +23,7 @@ static const struct task_entry cold_boot[] = {
- { initialise_mpll, true, "INITMPLL", },
- { convert_timings, true, "CONVTIM", },
- { configure_mc, true, "CONFMC", },
-+ { configure_memory_map, true, "MEMMAP", },
- };
-
- /* Return a generic stepping value to make stepping checks simpler */
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index 5915a2bab0..8f937c4ccd 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -203,6 +203,7 @@ enum raminit_status collect_spd_info(struct sysinfo *ctrl);
- enum raminit_status initialise_mpll(struct sysinfo *ctrl);
- enum raminit_status convert_timings(struct sysinfo *ctrl);
- enum raminit_status configure_mc(struct sysinfo *ctrl);
-+enum raminit_status configure_memory_map(struct sysinfo *ctrl);
-
- void configure_timings(struct sysinfo *ctrl);
- void configure_refresh(struct sysinfo *ctrl);
-diff --git a/src/northbridge/intel/haswell/registers/host_bridge.h b/src/northbridge/intel/haswell/registers/host_bridge.h
-index 1ee0ab2890..0228cf6bb9 100644
---- a/src/northbridge/intel/haswell/registers/host_bridge.h
-+++ b/src/northbridge/intel/haswell/registers/host_bridge.h
-@@ -34,6 +34,8 @@
-
- #define MESEG_BASE 0x70 /* Management Engine Base */
- #define MESEG_LIMIT 0x78 /* Management Engine Limit */
-+#define MELCK (1 << 10) /* ME Range Lock */
-+#define ME_STLEN_EN (1 << 11) /* ME Stolen Memory Enable */
-
- #define PAM0 0x80
- #define PAM1 0x81
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0034-soc-intel-pmc-Hardcoded-poweroff-after-power-fail.patch b/config/coreboot/default/patches/0034-soc-intel-pmc-Hardcoded-poweroff-after-power-fail.patch
new file mode 100644
index 00000000..ceee75c4
--- /dev/null
+++ b/config/coreboot/default/patches/0034-soc-intel-pmc-Hardcoded-poweroff-after-power-fail.patch
@@ -0,0 +1,82 @@
+From 09740dc9d43a8dc24b7416b70476796515af6581 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <info@minifree.org>
+Date: Tue, 31 Dec 2024 01:40:42 +0000
+Subject: [PATCH 34/37] soc/intel/pmc: Hardcoded poweroff after power fail
+
+Coreboot can set the power state for power on after previous
+power failure, based on the option table. On the ThinkPad T480,
+we have no nvram and, due to coreboot's design, we therefore
+have no option table, so the default setting is enabled.
+
+In my testing, this seems to be that the system will turn on
+after a power failure. If your ThinkPad was previously in a state
+where it wouldn't turn on when plugging in the power, it'd be fine.
+
+If your battery ran out later on, this would be triggered and
+your ThinkPad would permanently turn on, when plugging in a charger,
+and there is currently no way to configure this behaviour.
+
+We currently only use the common SoC PMC code on the ThinkPad
+T480, T480s and the Dell OptiPlex 3050 Micro, at the time of
+this patch, and it is desirable that the system be set to power
+off after power fail anyway.
+
+In some cases, you might want the opposite, for example if you're
+running a server. This will be documented on the website, for that
+reason.
+
+Signed-off-by: Leah Rowe <info@minifree.org>
+---
+ src/soc/intel/common/block/pmc/pmclib.c | 36 +++----------------------
+ 1 file changed, 4 insertions(+), 32 deletions(-)
+
+diff --git a/src/soc/intel/common/block/pmc/pmclib.c b/src/soc/intel/common/block/pmc/pmclib.c
+index 64b9bb997c..7823775bcb 100644
+--- a/src/soc/intel/common/block/pmc/pmclib.c
++++ b/src/soc/intel/common/block/pmc/pmclib.c
+@@ -776,38 +776,10 @@ void pmc_clear_pmcon_sts(void)
+
+ void pmc_set_power_failure_state(const bool target_on)
+ {
+- const unsigned int state = get_uint_option("power_on_after_fail",
+- CONFIG_MAINBOARD_POWER_FAILURE_STATE);
+-
+- /*
+- * On the shutdown path (target_on == false), we only need to
+- * update the register for MAINBOARD_POWER_STATE_PREVIOUS. For
+- * all other cases, we don't write the register to avoid clob-
+- * bering the value set on the boot path. This is necessary,
+- * for instance, when we can't access the option backend in SMM.
+- */
+-
+- switch (state) {
+- case MAINBOARD_POWER_STATE_OFF:
+- if (!target_on)
+- break;
+- printk(BIOS_INFO, "Set power off after power failure.\n");
+- pmc_soc_set_afterg3_en(false);
+- break;
+- case MAINBOARD_POWER_STATE_ON:
+- if (!target_on)
+- break;
+- printk(BIOS_INFO, "Set power on after power failure.\n");
+- pmc_soc_set_afterg3_en(true);
+- break;
+- case MAINBOARD_POWER_STATE_PREVIOUS:
+- printk(BIOS_INFO, "Keep power state after power failure.\n");
+- pmc_soc_set_afterg3_en(target_on);
+- break;
+- default:
+- printk(BIOS_WARNING, "Unknown power-failure state: %d\n", state);
+- break;
+- }
++ if (!target_on)
++ return;
++ printk(BIOS_INFO, "Set power off after power failure.\n");
++ pmc_soc_set_afterg3_en(false);
+ }
+
+ /* This function returns the highest assertion duration of the SLP_Sx assertion widths */
+--
+2.39.5
+
diff --git a/config/coreboot/default/patches/0035-haswell-NRI-Add-DDR3-JEDEC-reset-and-init.patch b/config/coreboot/default/patches/0035-haswell-NRI-Add-DDR3-JEDEC-reset-and-init.patch
deleted file mode 100644
index 29bdec9f..00000000
--- a/config/coreboot/default/patches/0035-haswell-NRI-Add-DDR3-JEDEC-reset-and-init.patch
+++ /dev/null
@@ -1,1036 +0,0 @@
-From db2b383a8ee5a4fc45c9ce0003ae45f25ed51f86 Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Sat, 7 May 2022 21:49:40 +0200
-Subject: [PATCH 35/51] haswell NRI: Add DDR3 JEDEC reset and init
-
-Implement JEDEC reset and init sequence for DDR3. The MRS commands are
-issued through the REUT (Robust Electrical Unified Testing) hardware.
-
-Change-Id: I2a0c066537021b587599228086727cb1e041bff5
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../intel/haswell/native_raminit/Makefile.mk | 3 +
- .../intel/haswell/native_raminit/ddr3.c | 217 ++++++++++++++++++
- .../haswell/native_raminit/io_comp_control.c | 19 ++
- .../haswell/native_raminit/jedec_reset.c | 120 ++++++++++
- .../haswell/native_raminit/raminit_main.c | 2 +
- .../haswell/native_raminit/raminit_native.h | 99 ++++++++
- .../haswell/native_raminit/reg_structs.h | 154 +++++++++++++
- .../intel/haswell/native_raminit/reut.c | 196 ++++++++++++++++
- .../intel/haswell/registers/mchbar.h | 21 ++
- src/southbridge/intel/lynxpoint/pch.h | 2 +
- 10 files changed, 833 insertions(+)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/ddr3.c
- create mode 100644 src/northbridge/intel/haswell/native_raminit/jedec_reset.c
- create mode 100644 src/northbridge/intel/haswell/native_raminit/reut.c
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-index 37d527e972..e9212df9e6 100644
---- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-@@ -1,11 +1,14 @@
- ## SPDX-License-Identifier: GPL-2.0-or-later
-
- romstage-y += configure_mc.c
-+romstage-y += ddr3.c
-+romstage-y += jedec_reset.c
- romstage-y += lookup_timings.c
- romstage-y += init_mpll.c
- romstage-y += io_comp_control.c
- romstage-y += memory_map.c
- romstage-y += raminit_main.c
- romstage-y += raminit_native.c
-+romstage-y += reut.c
- romstage-y += spd_bitmunching.c
- romstage-y += timings_refresh.c
-diff --git a/src/northbridge/intel/haswell/native_raminit/ddr3.c b/src/northbridge/intel/haswell/native_raminit/ddr3.c
-new file mode 100644
-index 0000000000..6ddb11488b
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/ddr3.c
-@@ -0,0 +1,217 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <assert.h>
-+#include <console/console.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <types.h>
-+
-+#include "raminit_native.h"
-+
-+#define DDR3_RTTNOM(a, b, c) (((a) << 9) | ((b) << 6) | ((c) << 2))
-+
-+uint16_t encode_ddr3_rttnom(const uint32_t rttnom)
-+{
-+ switch (rttnom) {
-+ case 0: return DDR3_RTTNOM(0, 0, 0); /* RttNom is disabled */
-+ case 20: return DDR3_RTTNOM(1, 0, 0); /* RZQ/12 */
-+ case 30: return DDR3_RTTNOM(1, 0, 1); /* RZQ/8 */
-+ case 40: return DDR3_RTTNOM(0, 1, 1); /* RZQ/6 */
-+ case 60: return DDR3_RTTNOM(0, 0, 1); /* RZQ/4 */
-+ case 120: return DDR3_RTTNOM(0, 1, 0); /* RZQ/2 */
-+ }
-+ printk(BIOS_ERR, "%s: Invalid rtt_nom value %u\n", __func__, rttnom);
-+ return 0;
-+}
-+
-+static const uint8_t jedec_wr_t[12] = { 1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 0, 0 };
-+
-+static void ddr3_program_mr0(struct sysinfo *ctrl, const uint8_t dll_reset)
-+{
-+ assert(ctrl->tWR >= 5 && ctrl->tWR <= 16);
-+ assert(ctrl->tAA >= 4);
-+ const uint8_t jedec_cas = ctrl->tAA - 4;
-+ const union {
-+ struct __packed {
-+ uint16_t burst_length : 2; // Bits 1:0
-+ uint16_t cas_latency_msb : 1; // Bits 2:2
-+ uint16_t read_burst_type : 1; // Bits 3:3
-+ uint16_t cas_latency_low : 3; // Bits 6:4
-+ uint16_t test_mode : 1; // Bits 7:7
-+ uint16_t dll_reset : 1; // Bits 8:8
-+ uint16_t write_recovery : 3; // Bits 11:9
-+ uint16_t precharge_pd_dll : 1; // Bits 12:12
-+ uint16_t : 3; // Bits 15:13
-+ };
-+ uint16_t raw;
-+ } mr0reg = {
-+ .burst_length = 0,
-+ .cas_latency_msb = !!(jedec_cas & BIT(3)),
-+ .read_burst_type = 0,
-+ .cas_latency_low = jedec_cas & 0x7,
-+ .dll_reset = 1,
-+ .write_recovery = jedec_wr_t[ctrl->tWR - 5],
-+ .precharge_pd_dll = 0,
-+ };
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ for (uint8_t slot = 0; slot < NUM_SLOTS; slot++) {
-+ if (!rank_in_ch(ctrl, slot + slot, channel))
-+ continue;
-+
-+ if (!ctrl->restore_mrs)
-+ ctrl->mr0[channel][slot] = mr0reg.raw;
-+ }
-+ reut_issue_mrs_all(ctrl, channel, 0, ctrl->mr0[channel]);
-+ }
-+}
-+
-+void ddr3_program_mr1(struct sysinfo *ctrl, const uint8_t wl_mode, const uint8_t q_off)
-+{
-+ /*
-+ * JESD79-3F (JEDEC DDR3 spec) refers to bit 0 of MR1 as 'DLL Enable'.
-+ * However, its encoding is weird, and 'DLL Disable' makes more sense.
-+ *
-+ * Moreover, bit 5 is part of ODIC (Output Driver Impedance Control),
-+ * but all encodings where MR1 bit 5 is 1 are reserved. Thus, omit it.
-+ */
-+ union {
-+ struct __packed {
-+ uint16_t dll_disable : 1; // Bits 0:0
-+ uint16_t od_impedance_ctl : 1; // Bits 1:1
-+ uint16_t odt_rtt_nom_low : 1; // Bits 2:2
-+ uint16_t additive_latency : 2; // Bits 4:3
-+ uint16_t : 1; // Bits 5:5
-+ uint16_t odt_rtt_nom_mid : 1; // Bits 6:6
-+ uint16_t write_level_mode : 1; // Bits 7:7
-+ uint16_t : 1; // Bits 8:8
-+ uint16_t odt_rtt_nom_high : 1; // Bits 9:9
-+ uint16_t : 1; // Bits 10:10
-+ uint16_t t_dqs : 1; // Bits 11:11
-+ uint16_t q_off : 1; // Bits 12:12
-+ uint16_t : 3; // Bits 15:13
-+ };
-+ uint16_t raw;
-+ } mr1reg = {
-+ .dll_disable = 0,
-+ .od_impedance_ctl = 1, /* RZQ/7 */
-+ .additive_latency = 0,
-+ .write_level_mode = wl_mode,
-+ .t_dqs = 0,
-+ .q_off = q_off,
-+ };
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ mr1reg.raw &= ~RTTNOM_MASK;
-+ mr1reg.raw |= encode_ddr3_rttnom(ctrl->dpc[channel] == 2 ? 60 : 0);
-+ for (uint8_t slot = 0; slot < NUM_SLOTS; slot++) {
-+ if (!rank_in_ch(ctrl, slot + slot, channel))
-+ continue;
-+
-+ if (!ctrl->restore_mrs)
-+ ctrl->mr1[channel][slot] = mr1reg.raw;
-+ }
-+ reut_issue_mrs_all(ctrl, channel, 1, ctrl->mr1[channel]);
-+ }
-+}
-+
-+enum {
-+ RTT_WR_OFF = 0,
-+ RTT_WR_60 = 1,
-+ RTT_WR_120 = 2,
-+};
-+
-+static void ddr3_program_mr2(struct sysinfo *ctrl)
-+{
-+ assert(ctrl->tCWL >= 5);
-+ const bool dimm_srt = ctrl->flags.ext_temp_refresh && !ctrl->flags.asr;
-+
-+ const union {
-+ struct __packed {
-+ uint16_t partial_array_sr : 3; // Bits 0:2
-+ uint16_t cas_write_latency : 3; // Bits 5:3
-+ uint16_t auto_self_refresh : 1; // Bits 6:6
-+ uint16_t self_refresh_temp : 1; // Bits 7:7
-+ uint16_t : 1; // Bits 8:8
-+ uint16_t odt_rtt_wr : 2; // Bits 10:9
-+ uint16_t : 5; // Bits 15:11
-+ };
-+ uint16_t raw;
-+ } mr2reg = {
-+ .partial_array_sr = 0,
-+ .cas_write_latency = ctrl->tCWL - 5,
-+ .auto_self_refresh = ctrl->flags.asr,
-+ .self_refresh_temp = dimm_srt,
-+ .odt_rtt_wr = is_hsw_ult() ? RTT_WR_120 : RTT_WR_60,
-+ };
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ for (uint8_t slot = 0; slot < NUM_SLOTS; slot++) {
-+ if (!rank_in_ch(ctrl, slot + slot, channel))
-+ continue;
-+
-+ if (!ctrl->restore_mrs)
-+ ctrl->mr2[channel][slot] = mr2reg.raw;
-+ }
-+ /* MR2 shadow register is similar but not identical to MR2 */
-+ if (!ctrl->restore_mrs) {
-+ union tc_mr2_shadow_reg tc_mr2_shadow = {
-+ .raw = mr2reg.raw & 0x073f,
-+ };
-+ for (uint8_t slot = 0; slot < NUM_SLOTS; slot++) {
-+ if (!rank_in_ch(ctrl, slot + slot, channel))
-+ continue;
-+
-+ if (dimm_srt)
-+ tc_mr2_shadow.srt_available |= BIT(slot);
-+
-+ if (ctrl->rank_mirrored[channel] & BIT(slot + slot + 1))
-+ tc_mr2_shadow.addr_bit_swizzle |= BIT(slot);
-+ }
-+ mchbar_write32(TC_MR2_SHADOW_ch(channel), tc_mr2_shadow.raw);
-+ }
-+ reut_issue_mrs_all(ctrl, channel, 2, ctrl->mr2[channel]);
-+ }
-+}
-+
-+static void ddr3_program_mr3(struct sysinfo *ctrl, const uint8_t mpr_mode)
-+{
-+ const union {
-+ struct __packed {
-+ uint16_t mpr_loc : 2; // Bits 1:0
-+ uint16_t mpr_mode : 1; // Bits 2:2
-+ uint16_t : 13; // Bits 15:3
-+ };
-+ uint16_t raw;
-+ } mr3reg = {
-+ .mpr_loc = 0,
-+ .mpr_mode = mpr_mode,
-+ };
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ for (uint8_t slot = 0; slot < NUM_SLOTS; slot++) {
-+ if (!rank_in_ch(ctrl, slot + slot, channel))
-+ continue;
-+
-+ if (!ctrl->restore_mrs)
-+ ctrl->mr3[channel][slot] = mr3reg.raw;
-+ }
-+ reut_issue_mrs_all(ctrl, channel, 3, ctrl->mr3[channel]);
-+ }
-+}
-+
-+enum raminit_status ddr3_jedec_init(struct sysinfo *ctrl)
-+{
-+ ddr3_program_mr2(ctrl);
-+ ddr3_program_mr3(ctrl, 0);
-+ ddr3_program_mr1(ctrl, 0, 0);
-+ ddr3_program_mr0(ctrl, 1);
-+ return reut_issue_zq(ctrl, ctrl->chanmap, ZQ_INIT);
-+}
-diff --git a/src/northbridge/intel/haswell/native_raminit/io_comp_control.c b/src/northbridge/intel/haswell/native_raminit/io_comp_control.c
-index d45b608dd3..8a55fd81b2 100644
---- a/src/northbridge/intel/haswell/native_raminit/io_comp_control.c
-+++ b/src/northbridge/intel/haswell/native_raminit/io_comp_control.c
-@@ -8,6 +8,25 @@
-
- #include "raminit_native.h"
-
-+enum raminit_status io_reset(void)
-+{
-+ union mc_init_state_g_reg mc_init_state_g = {
-+ .raw = mchbar_read32(MC_INIT_STATE_G),
-+ };
-+ mc_init_state_g.reset_io = 1;
-+ mchbar_write32(MC_INIT_STATE_G, mc_init_state_g.raw);
-+ struct stopwatch timer;
-+ stopwatch_init_msecs_expire(&timer, 2000);
-+ do {
-+ mc_init_state_g.raw = mchbar_read32(MC_INIT_STATE_G);
-+ if (mc_init_state_g.reset_io == 0)
-+ return RAMINIT_STATUS_SUCCESS;
-+
-+ } while (!stopwatch_expired(&timer));
-+ printk(BIOS_ERR, "Timed out waiting for DDR I/O reset to complete\n");
-+ return RAMINIT_STATUS_POLL_TIMEOUT;
-+}
-+
- enum raminit_status wait_for_first_rcomp(void)
- {
- struct stopwatch timer;
-diff --git a/src/northbridge/intel/haswell/native_raminit/jedec_reset.c b/src/northbridge/intel/haswell/native_raminit/jedec_reset.c
-new file mode 100644
-index 0000000000..de0f676758
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/jedec_reset.c
-@@ -0,0 +1,120 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <console/console.h>
-+#include <delay.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <southbridge/intel/lynxpoint/pch.h>
-+#include <types.h>
-+#include <timer.h>
-+
-+#include "raminit_native.h"
-+
-+static void assert_reset(const bool do_reset)
-+{
-+ if (is_hsw_ult()) {
-+ uint32_t pm_cfg2 = RCBA32(PM_CFG2);
-+ if (do_reset)
-+ pm_cfg2 &= ~PM_CFG2_DRAM_RESET_CTL;
-+ else
-+ pm_cfg2 |= PM_CFG2_DRAM_RESET_CTL;
-+ RCBA32(PM_CFG2) = pm_cfg2;
-+ } else {
-+ union mc_init_state_g_reg mc_init_state_g = {
-+ .raw = mchbar_read32(MC_INIT_STATE_G),
-+ };
-+ mc_init_state_g.ddr_not_reset = !do_reset;
-+ mchbar_write32(MC_INIT_STATE_G, mc_init_state_g.raw);
-+ }
-+}
-+
-+/*
-+ * Perform JEDEC reset.
-+ *
-+ * If RTT_NOM is to be enabled in MR1, the ODT input signal must be
-+ * statically held low in our system since RTT_NOM is always enabled.
-+ */
-+static void jedec_reset(struct sysinfo *ctrl)
-+{
-+ if (is_hsw_ult())
-+ assert_reset(false);
-+
-+ union mc_init_state_g_reg mc_init_state_g = {
-+ .ddr_not_reset = 1,
-+ .safe_self_refresh = 1,
-+ };
-+ mchbar_write32(MC_INIT_STATE_G, mc_init_state_g.raw);
-+
-+ union reut_misc_cke_ctrl_reg reut_misc_cke_ctrl = {
-+ .cke_override = 0xf,
-+ .cke_on = 0,
-+ };
-+ mchbar_write32(REUT_MISC_CKE_CTRL, reut_misc_cke_ctrl.raw);
-+
-+ assert_reset(true);
-+
-+ /** TODO: check and switch DDR3 voltage here (mainboard-specific) **/
-+
-+ udelay(200);
-+
-+ assert_reset(false);
-+
-+ udelay(500);
-+
-+ mc_init_state_g.dclk_enable = 1;
-+ mchbar_write32(MC_INIT_STATE_G, mc_init_state_g.raw);
-+
-+ /* Delay at least 20 nanoseconds for tCKSRX */
-+ tick_delay(1);
-+
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ reut_misc_cke_ctrl.cke_on = ctrl->rankmap[channel];
-+ mchbar_write32(REUT_ch_MISC_CKE_CTRL(channel), reut_misc_cke_ctrl.raw);
-+ }
-+
-+ /*
-+ * Wait minimum of reset CKE exit time, tXPR.
-+ * Spec says MAX(tXS, 5 tCK). 5 tCK is 10 ns.
-+ */
-+ tick_delay(1);
-+}
-+
-+enum raminit_status do_jedec_init(struct sysinfo *ctrl)
-+{
-+ /* Never do a JEDEC reset in S3 resume */
-+ if (ctrl->bootmode == BOOTMODE_S3)
-+ return RAMINIT_STATUS_SUCCESS;
-+
-+ enum raminit_status status = io_reset();
-+ if (status)
-+ return status;
-+
-+ status = wait_for_first_rcomp();
-+ if (status)
-+ return status;
-+
-+ /* Force ODT low (JEDEC spec) */
-+ const union reut_misc_odt_ctrl_reg reut_misc_odt_ctrl = {
-+ .odt_override = 0xf,
-+ .odt_on = 0,
-+ };
-+ mchbar_write32(REUT_MISC_ODT_CTRL, reut_misc_odt_ctrl.raw);
-+
-+ /*
-+ * Note: Haswell MRC does not clear ODT override for LPDDR3. However,
-+ * Broadwell MRC does. Hell suspects this difference is important, as
-+ * there is an erratum in the specification update for Broadwell:
-+ *
-+ * Erratum BDM74: LPDDR3 Memory Training May Cause Platform Boot Failure
-+ */
-+ if (ctrl->lpddr)
-+ die("%s: LPDDR-specific JEDEC init not implemented\n", __func__);
-+
-+ jedec_reset(ctrl);
-+ status = ddr3_jedec_init(ctrl);
-+ if (!status)
-+ ctrl->restore_mrs = true;
-+
-+ /* Release ODT override */
-+ mchbar_write32(REUT_MISC_ODT_CTRL, 0);
-+ return status;
-+}
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-index 559dfc3a4e..94b268468c 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-@@ -24,6 +24,7 @@ static const struct task_entry cold_boot[] = {
- { convert_timings, true, "CONVTIM", },
- { configure_mc, true, "CONFMC", },
- { configure_memory_map, true, "MEMMAP", },
-+ { do_jedec_init, true, "JEDECINIT", },
- };
-
- /* Return a generic stepping value to make stepping checks simpler */
-@@ -57,6 +58,7 @@ static void initialize_ctrl(struct sysinfo *ctrl)
- ctrl->stepping = get_stepping(ctrl->cpu);
- ctrl->vdd_mv = is_hsw_ult() ? 1350 : 1500; /** FIXME: Hardcoded, does it matter? **/
- ctrl->dq_pins_interleaved = cfg->dq_pins_interleaved;
-+ ctrl->restore_mrs = false;
- ctrl->bootmode = bootmode;
- }
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index 8f937c4ccd..759d755d6d 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -28,6 +28,30 @@
- /* Always use 12 legs for emphasis (not trained) */
- #define TXEQFULLDRV (3 << 4)
-
-+/* DDR3 mode register bits */
-+#define MR0_DLL_RESET BIT(8)
-+
-+#define MR1_WL_ENABLE BIT(7)
-+#define MR1_QOFF_ENABLE BIT(12) /* If set, output buffers disabled */
-+
-+#define RTTNOM_MASK (BIT(9) | BIT(6) | BIT(2))
-+
-+/* ZQ calibration types */
-+enum {
-+ ZQ_INIT, /* DDR3: ZQCL with tZQinit, LPDDR3: ZQ Init with tZQinit */
-+ ZQ_LONG, /* DDR3: ZQCL with tZQoper, LPDDR3: ZQ Long with tZQCL */
-+ ZQ_SHORT, /* DDR3: ZQCS with tZQCS, LPDDR3: ZQ Short with tZQCS */
-+ ZQ_RESET, /* DDR3: not used, LPDDR3: ZQ Reset with tZQreset */
-+};
-+
-+/* REUT initialisation modes */
-+enum {
-+ REUT_MODE_IDLE = 0,
-+ REUT_MODE_TEST = 1,
-+ REUT_MODE_MRS = 2,
-+ REUT_MODE_NOP = 3, /* Normal operation mode */
-+};
-+
- enum command_training_iteration {
- CT_ITERATION_CLOCK = 0,
- CT_ITERATION_CMD_NORTH,
-@@ -51,6 +75,7 @@ enum raminit_status {
- RAMINIT_STATUS_UNSUPPORTED_MEMORY,
- RAMINIT_STATUS_MPLL_INIT_FAILURE,
- RAMINIT_STATUS_POLL_TIMEOUT,
-+ RAMINIT_STATUS_REUT_ERROR,
- RAMINIT_STATUS_UNSPECIFIED_ERROR, /** TODO: Deprecated in favor of specific values **/
- };
-
-@@ -73,6 +98,7 @@ struct sysinfo {
- uint32_t cpu; /* CPUID value */
-
- bool dq_pins_interleaved;
-+ bool restore_mrs;
-
- /** TODO: ECC support untested **/
- bool is_ecc;
-@@ -162,6 +188,11 @@ struct sysinfo {
- union tc_bank_rank_b_reg tc_bankrank_b[NUM_CHANNELS];
- union tc_bank_rank_c_reg tc_bankrank_c[NUM_CHANNELS];
- union tc_bank_rank_d_reg tc_bankrank_d[NUM_CHANNELS];
-+
-+ uint16_t mr0[NUM_CHANNELS][NUM_SLOTS];
-+ uint16_t mr1[NUM_CHANNELS][NUM_SLOTS];
-+ uint16_t mr2[NUM_CHANNELS][NUM_SLOTS];
-+ uint16_t mr3[NUM_CHANNELS][NUM_SLOTS];
- };
-
- static inline bool is_hsw_ult(void)
-@@ -197,6 +228,53 @@ static inline void clear_data_offset_train_all(struct sysinfo *ctrl)
- memset(ctrl->data_offset_train, 0, sizeof(ctrl->data_offset_train));
- }
-
-+/* Number of ticks to wait in units of 69.841279 ns (citation needed) */
-+static inline void tick_delay(const uint32_t delay)
-+{
-+ /* Just perform reads to a random register */
-+ for (uint32_t start = 0; start <= delay; start++)
-+ mchbar_read32(REUT_ERR_DATA_STATUS);
-+}
-+
-+/*
-+ * 64-bit MCHBAR registers need to be accessed atomically. If one uses
-+ * two 32-bit ops instead, there will be problems with the REUT's CADB
-+ * (Command Address Data Buffer): hardware automatically advances the
-+ * pointer into the register file after a write to the input register.
-+ */
-+static inline uint64_t mchbar_read64(const uintptr_t x)
-+{
-+ const uint64_t *offset = (uint64_t *)(CONFIG_FIXED_MCHBAR_MMIO_BASE + x);
-+ uint64_t mmxsave, v;
-+ asm volatile (
-+ "\n\t movq %%mm0, %0"
-+ "\n\t movq %2, %%mm0"
-+ "\n\t movq %%mm0, %1"
-+ "\n\t movq %3, %%mm0"
-+ "\n\t emms"
-+ : "=m"(mmxsave),
-+ "=m"(v)
-+ : "m"(offset[0]),
-+ "m"(mmxsave));
-+ return v;
-+}
-+
-+static inline void mchbar_write64(const uintptr_t x, const uint64_t v)
-+{
-+ const uint64_t *offset = (uint64_t *)(CONFIG_FIXED_MCHBAR_MMIO_BASE + x);
-+ uint64_t mmxsave;
-+ asm volatile (
-+ "\n\t movq %%mm0, %0"
-+ "\n\t movq %2, %%mm0"
-+ "\n\t movq %%mm0, %1"
-+ "\n\t movq %3, %%mm0"
-+ "\n\t emms"
-+ : "=m"(mmxsave)
-+ : "m"(offset[0]),
-+ "m"(v),
-+ "m"(mmxsave));
-+}
-+
- void raminit_main(enum raminit_boot_mode bootmode);
-
- enum raminit_status collect_spd_info(struct sysinfo *ctrl);
-@@ -204,6 +282,7 @@ enum raminit_status initialise_mpll(struct sysinfo *ctrl);
- enum raminit_status convert_timings(struct sysinfo *ctrl);
- enum raminit_status configure_mc(struct sysinfo *ctrl);
- enum raminit_status configure_memory_map(struct sysinfo *ctrl);
-+enum raminit_status do_jedec_init(struct sysinfo *ctrl);
-
- void configure_timings(struct sysinfo *ctrl);
- void configure_refresh(struct sysinfo *ctrl);
-@@ -216,8 +295,28 @@ uint32_t get_tXS_offset(uint32_t mem_clock_mhz);
- uint32_t get_tZQOPER(uint32_t mem_clock_mhz, bool lpddr);
- uint32_t get_tZQCS(uint32_t mem_clock_mhz, bool lpddr);
-
-+enum raminit_status io_reset(void);
- enum raminit_status wait_for_first_rcomp(void);
-
-+uint16_t encode_ddr3_rttnom(uint32_t rttnom);
-+void ddr3_program_mr1(struct sysinfo *ctrl, uint8_t wl_mode, uint8_t q_off);
-+enum raminit_status ddr3_jedec_init(struct sysinfo *ctrl);
-+
-+void reut_issue_mrs(
-+ struct sysinfo *ctrl,
-+ uint8_t channel,
-+ uint8_t rankmask,
-+ uint8_t mr,
-+ uint16_t val);
-+
-+void reut_issue_mrs_all(
-+ struct sysinfo *ctrl,
-+ uint8_t channel,
-+ uint8_t mr,
-+ const uint16_t val[NUM_SLOTS]);
-+
-+enum raminit_status reut_issue_zq(struct sysinfo *ctrl, uint8_t chanmask, uint8_t zq_type);
-+
- uint8_t get_rx_bias(const struct sysinfo *ctrl);
-
- uint8_t get_tCWL(uint32_t mem_clock_mhz);
-diff --git a/src/northbridge/intel/haswell/native_raminit/reg_structs.h b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-index 70487e1640..9929f617fe 100644
---- a/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-+++ b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-@@ -335,6 +335,127 @@ union mcscheds_cbit_reg {
- uint32_t raw;
- };
-
-+union reut_pat_cadb_prog_reg {
-+ struct __packed {
-+ uint32_t addr : 16; // Bits 15:0
-+ uint32_t : 8; // Bits 23:16
-+ uint32_t bank : 3; // Bits 26:24
-+ uint32_t : 5; // Bits 31:27
-+ uint32_t cs : 4; // Bits 35:32
-+ uint32_t : 4; // Bits 39:36
-+ uint32_t cmd : 3; // Bits 42:40
-+ uint32_t : 5; // Bits 47:43
-+ uint32_t odt : 4; // Bits 51:48
-+ uint32_t : 4; // Bits 55:52
-+ uint32_t cke : 4; // Bits 59:56
-+ uint32_t : 4; // Bits 63:60
-+ };
-+ uint64_t raw;
-+ uint32_t raw32[2];
-+};
-+
-+union reut_pat_cadb_mrs_reg {
-+ struct __packed {
-+ uint32_t delay_gap : 3; // Bits 2:0
-+ uint32_t : 5; // Bits 7:3
-+ uint32_t start_ptr : 3; // Bits 10:8
-+ uint32_t : 5; // Bits 15:11
-+ uint32_t end_ptr : 3; // Bits 18:16
-+ uint32_t : 5; // Bits 23:19
-+ uint32_t curr_ptr : 3; // Bits 26:24
-+ uint32_t : 5; // Bits 31:27
-+ };
-+ uint32_t raw;
-+};
-+
-+union reut_seq_cfg_reg {
-+ struct __packed {
-+ uint32_t : 3; // Bits 2:0
-+ uint32_t stop_base_seq_on_wrap_trigger : 1; // Bits 3:3
-+ uint32_t : 1; // Bits 4:4
-+ uint32_t address_update_rate_mode : 1; // Bits 5:5
-+ uint32_t : 1; // Bits 6:6
-+ uint32_t enable_dummy_reads : 1; // Bits 7:7
-+ uint32_t : 2; // Bits 9:8
-+ uint32_t enable_constant_write_strobe : 1; // Bits 10:10
-+ uint32_t global_control : 1; // Bits 11:11
-+ uint32_t initialization_mode : 2; // Bits 13:12
-+ uint32_t : 2; // Bits 15:14
-+ uint32_t early_steppings_loop_count : 5; // Bits 20:16 *** Not on C0 ***
-+ uint32_t : 3; // Bits 23:21
-+ uint32_t subsequence_start_pointer : 3; // Bits 26:24
-+ uint32_t : 1; // Bits 27:27
-+ uint32_t subsequence_end_pointer : 3; // Bits 30:28
-+ uint32_t : 1; // Bits 31:31
-+ uint32_t start_test_delay : 10; // Bits 41:32
-+ uint32_t : 22; // Bits 63:42
-+ };
-+ uint64_t raw;
-+ uint32_t raw32[2];
-+};
-+
-+union reut_seq_ctl_reg {
-+ struct __packed {
-+ uint32_t start_test : 1; // Bits 0:0
-+ uint32_t stop_test : 1; // Bits 1:1
-+ uint32_t clear_errors : 1; // Bits 2:2
-+ uint32_t : 1; // Bits 3:3
-+ uint32_t stop_on_error : 1; // Bits 4:4
-+ uint32_t : 27; // Bits 31:5
-+ };
-+ uint32_t raw;
-+};
-+
-+union reut_global_err_reg {
-+ struct __packed {
-+ uint32_t ch_error : 2; // Bits 1:0
-+ uint32_t : 14; // Bits 15:2
-+ uint32_t ch_test_done : 2; // Bits 17:16
-+ uint32_t : 14; // Bits 31:18
-+ };
-+ uint32_t raw;
-+};
-+
-+union reut_misc_cke_ctrl_reg {
-+ struct __packed {
-+ uint32_t cke_override : 4; // Bits 3:0
-+ uint32_t : 4; // Bits 7:4
-+ uint32_t cke_en_start_test_sync : 1; // Bits 8:8
-+ uint32_t : 7; // Bits 15:9
-+ uint32_t cke_on : 4; // Bits 19:16
-+ uint32_t : 12; // Bits 31:20
-+ };
-+ uint32_t raw;
-+};
-+
-+union reut_misc_odt_ctrl_reg {
-+ struct __packed {
-+ uint32_t odt_override : 4; // Bits 3:0
-+ uint32_t : 12; // Bits 15:4
-+ uint32_t odt_on : 4; // Bits 19:16
-+ uint32_t : 11; // Bits 30:20
-+ uint32_t mpr_train_ddr_on : 1; // Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
-+union mcscheds_dft_misc_reg {
-+ struct __packed {
-+ uint32_t wdar : 1; // Bits 0:0
-+ uint32_t safe_mask_sel : 3; // Bits 3:1
-+ uint32_t force_rcv_en : 1; // Bits 4:4
-+ uint32_t : 3; // Bits 7:5
-+ uint32_t ddr_qualifier : 2; // Bits 9:8
-+ uint32_t qualifier_length : 2; // Bits 11:10
-+ uint32_t wdb_block_en : 1; // Bits 12:12
-+ uint32_t rt_dft_read_ptr : 4; // Bits 16:13
-+ uint32_t rt_dft_read_enable : 1; // Bits 17:17
-+ uint32_t rt_dft_read_sel_addr : 1; // Bits 18:18
-+ uint32_t : 13; // Bits 31:19
-+ };
-+ uint32_t raw;
-+};
-+
- union tc_bank_reg {
- struct __packed {
- uint32_t tRCD : 5; // Bits 4:0
-@@ -428,6 +549,18 @@ union tc_srftp_reg {
- uint32_t raw;
- };
-
-+union tc_mr2_shadow_reg {
-+ struct __packed {
-+ uint32_t mr2_shadow_low : 6; // Bits 5:0
-+ uint32_t srt_available : 2; // Bits 7:6
-+ uint32_t mr2_shadow_high : 3; // Bits 10:8
-+ uint32_t : 3; // Bits 13:11
-+ uint32_t addr_bit_swizzle : 2; // Bits 15:14
-+ uint32_t : 16; // Bits 31:16
-+ };
-+ uint32_t raw;
-+};
-+
- union mcmain_command_rate_limit_reg {
- struct __packed {
- uint32_t enable_cmd_limit : 1; // Bits 0:0
-@@ -483,6 +616,27 @@ union mad_zr_reg {
- uint32_t raw;
- };
-
-+union mc_init_state_g_reg {
-+ struct __packed {
-+ uint32_t pu_mrc_done : 1; // Bits 0:0
-+ uint32_t ddr_not_reset : 1; // Bits 1:1
-+ uint32_t : 1; // Bits 2:2
-+ uint32_t refresh_enable : 1; // Bits 3:3
-+ uint32_t : 1; // Bits 4:4
-+ uint32_t mc_init_done_ack : 1; // Bits 5:5
-+ uint32_t : 1; // Bits 6:6
-+ uint32_t mrc_done : 1; // Bits 7:7
-+ uint32_t safe_self_refresh : 1; // Bits 8:8
-+ uint32_t : 1; // Bits 9:9
-+ uint32_t hvm_gate_ddr_reset : 1; // Bits 10:10
-+ uint32_t : 11; // Bits 21:11
-+ uint32_t dclk_enable : 1; // Bits 22:22
-+ uint32_t reset_io : 1; // Bits 23:23
-+ uint32_t : 8; // Bits 31:24
-+ };
-+ uint32_t raw;
-+};
-+
- /* Same definition for P_COMP, M_COMP, D_COMP */
- union pcu_comp_reg {
- struct __packed {
-diff --git a/src/northbridge/intel/haswell/native_raminit/reut.c b/src/northbridge/intel/haswell/native_raminit/reut.c
-new file mode 100644
-index 0000000000..31019f74a1
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/reut.c
-@@ -0,0 +1,196 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <console/console.h>
-+#include <delay.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <timer.h>
-+#include <types.h>
-+
-+#include "raminit_native.h"
-+
-+enum {
-+ CADB_CMD_MRS = 0,
-+ CADB_CMD_REF = 1,
-+ CADB_CMD_PRE = 2,
-+ CADB_CMD_ACT = 3,
-+ CADB_CMD_WR = 4,
-+ CADB_CMD_RD = 5,
-+ CADB_CMD_ZQ = 6,
-+ CADB_CMD_NOP = 7,
-+};
-+
-+/*
-+ * DDR3 rank mirror swaps the following pins: A3<->A4, A5<->A6, A7<->A8, BA0<->BA1
-+ *
-+ * Note that the swapped bits are contiguous. We can use some XOR magic to swap the bits.
-+ * Address lanes are at bits 0..15 and bank selects are at bits 24..26 on the REUT register.
-+ */
-+#define MIRROR_BITS (BIT(24) | BIT(7) | BIT(5) | BIT(3))
-+static uint64_t cadb_prog_rank_mirror(const uint64_t cadb_prog)
-+{
-+ /* First XOR: find which pairs of bits are different (need swapping) */
-+ const uint64_t tmp64 = (cadb_prog ^ (cadb_prog >> 1)) & MIRROR_BITS;
-+
-+ /* Second XOR: invert the pairs of bits that have different values */
-+ return cadb_prog ^ (tmp64 | tmp64 << 1);
-+}
-+
-+static enum raminit_status reut_write_cadb_cmd(
-+ struct sysinfo *ctrl,
-+ const uint8_t channel,
-+ const uint8_t rankmask,
-+ const uint8_t cmd,
-+ const uint8_t bank,
-+ const uint16_t valarr[NUM_SLOTRANKS],
-+ const uint8_t delay)
-+{
-+ union mcscheds_dft_misc_reg dft_misc = {
-+ .raw = mchbar_read32(MCSCHEDS_DFT_MISC),
-+ };
-+ dft_misc.ddr_qualifier = 0;
-+ mchbar_write32(MCSCHEDS_DFT_MISC, dft_misc.raw);
-+
-+ /* Pointer will be dynamically incremented after a write to CADB_PROG register */
-+ mchbar_write8(REUT_ch_PAT_CADB_WRITE_PTR(channel), 0);
-+
-+ uint8_t count = 0;
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (!(ctrl->rankmap[channel] & BIT(rank) & rankmask))
-+ continue;
-+
-+ union reut_pat_cadb_prog_reg reut_cadb_prog = {
-+ .addr = valarr[rank],
-+ .bank = bank,
-+ .cs = ~BIT(rank), /* CS is active low */
-+ .cmd = cmd,
-+ .cke = 0xf,
-+ };
-+ if (ctrl->rank_mirrored[channel] & BIT(rank))
-+ reut_cadb_prog.raw = cadb_prog_rank_mirror(reut_cadb_prog.raw);
-+
-+ mchbar_write64(REUT_ch_PAT_CADB_PROG(channel), reut_cadb_prog.raw);
-+ count++;
-+ }
-+ if (!count) {
-+ printk(BIOS_ERR, "%s: rankmask is invalid\n", __func__);
-+ return RAMINIT_STATUS_UNSPECIFIED_ERROR; /** FIXME: Is this needed? **/
-+ }
-+ const union reut_pat_cadb_mrs_reg reut_cadb_mrs = {
-+ .delay_gap = delay ? delay : 3,
-+ .end_ptr = count - 1,
-+ };
-+ mchbar_write32(REUT_ch_PAT_CADB_MRS(channel), reut_cadb_mrs.raw);
-+
-+ const uint32_t reut_seq_cfg_save = mchbar_read32(REUT_ch_SEQ_CFG(channel));
-+ union reut_seq_cfg_reg reut_seq_cfg = {
-+ .raw = reut_seq_cfg_save,
-+ };
-+ reut_seq_cfg.global_control = 0;
-+ reut_seq_cfg.initialization_mode = REUT_MODE_MRS;
-+ mchbar_write32(REUT_ch_SEQ_CFG(channel), reut_seq_cfg.raw);
-+ mchbar_write32(REUT_ch_SEQ_CTL(channel), (union reut_seq_ctl_reg) {
-+ .start_test = 1,
-+ .clear_errors = 1,
-+ }.raw);
-+ enum raminit_status status = RAMINIT_STATUS_SUCCESS;
-+ union reut_global_err_reg reut_global_err;
-+ struct stopwatch timer;
-+ stopwatch_init_msecs_expire(&timer, 100);
-+ do {
-+ reut_global_err.raw = mchbar_read32(REUT_GLOBAL_ERR);
-+ if (reut_global_err.ch_error & BIT(channel)) {
-+ printk(BIOS_ERR, "Unexpected REUT error for channel %u\n", channel);
-+ status = RAMINIT_STATUS_REUT_ERROR;
-+ break;
-+ }
-+ if (stopwatch_expired(&timer)) {
-+ printk(BIOS_ERR, "%s: REUT timed out!\n", __func__);
-+ status = RAMINIT_STATUS_POLL_TIMEOUT;
-+ break;
-+ }
-+ } while (!(reut_global_err.ch_test_done & BIT(channel)));
-+ mchbar_write32(REUT_ch_SEQ_CTL(channel), (union reut_seq_ctl_reg) {
-+ .clear_errors = 1,
-+ }.raw);
-+ mchbar_write32(REUT_ch_SEQ_CFG(channel), reut_seq_cfg_save);
-+ return status;
-+}
-+
-+static enum raminit_status reut_write_cadb_cmd_all(
-+ struct sysinfo *ctrl,
-+ const uint8_t channel,
-+ const uint8_t rankmask,
-+ const uint8_t cmd,
-+ const uint8_t bank,
-+ const uint16_t val,
-+ const uint8_t delay)
-+{
-+ const uint16_t valarr[NUM_SLOTRANKS] = { val, val, val, val };
-+ return reut_write_cadb_cmd(ctrl, channel, rankmask, cmd, bank, valarr, delay);
-+}
-+
-+void reut_issue_mrs(
-+ struct sysinfo *ctrl,
-+ const uint8_t channel,
-+ const uint8_t rankmask,
-+ const uint8_t mr,
-+ const uint16_t val)
-+{
-+ reut_write_cadb_cmd_all(ctrl, channel, rankmask, CADB_CMD_MRS, mr, val, 0);
-+}
-+
-+void reut_issue_mrs_all(
-+ struct sysinfo *ctrl,
-+ const uint8_t channel,
-+ const uint8_t mr,
-+ const uint16_t val[NUM_SLOTS])
-+{
-+ const uint16_t valarr[NUM_SLOTRANKS] = { val[0], val[0], val[1], val[1] };
-+ reut_write_cadb_cmd(ctrl, channel, 0xf, CADB_CMD_MRS, mr, valarr, 0);
-+}
-+
-+enum raminit_status reut_issue_zq(struct sysinfo *ctrl, uint8_t chanmask, uint8_t zq_type)
-+{
-+ /** TODO: Issuing ZQ commands differs for LPDDR **/
-+ if (ctrl->lpddr)
-+ die("%s: LPDDR not yet supported in ZQ calibration\n", __func__);
-+
-+ __maybe_unused uint8_t opcode; /* NOTE: Only used for LPDDR */
-+ uint16_t zq = 0;
-+ switch (zq_type) {
-+ case ZQ_INIT:
-+ zq = BIT(10);
-+ opcode = 0xff;
-+ break;
-+ case ZQ_LONG:
-+ zq = BIT(10);
-+ opcode = 0xab;
-+ break;
-+ case ZQ_SHORT:
-+ opcode = 0x56;
-+ break;
-+ case ZQ_RESET:
-+ opcode = 0xc3;
-+ break;
-+ default:
-+ die("%s: ZQ type %u is invalid\n", __func__, zq_type);
-+ }
-+
-+ /* ZQCS on single-channel needs a longer delay */
-+ const uint8_t delay = zq_type == ZQ_SHORT && (!ctrl->dpc[0] || !ctrl->dpc[1]) ? 7 : 1;
-+ enum raminit_status status = RAMINIT_STATUS_SUCCESS;
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!(BIT(channel) & chanmask) || !does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ status = reut_write_cadb_cmd_all(ctrl, channel, 0xf, CADB_CMD_ZQ, 0, zq, delay);
-+ if (status)
-+ break;
-+ }
-+
-+ /* Wait a bit after ZQ INIT and ZQCL commands */
-+ if (zq)
-+ udelay(1);
-+
-+ return status;
-+}
-diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
-index 2acc5cbbc8..4fc78a7f43 100644
---- a/src/northbridge/intel/haswell/registers/mchbar.h
-+++ b/src/northbridge/intel/haswell/registers/mchbar.h
-@@ -96,15 +96,36 @@
-
- #define SC_WR_ADD_DELAY_ch(ch) _MCMAIN_C(0x40d0, ch)
-
-+#define REUT_ch_MISC_CKE_CTRL(ch) _MCMAIN_C(0x4190, ch)
-+
-+#define REUT_ch_PAT_CADB_MRS(ch) _MCMAIN_C(0x419c, ch)
-+
-+#define REUT_ch_PAT_CADB_WRITE_PTR(ch) _MCMAIN_C(0x41bc, ch)
-+#define REUT_ch_PAT_CADB_PROG(ch) _MCMAIN_C(0x41c0, ch)
-+
- #define TC_ZQCAL_ch(ch) _MCMAIN_C(0x4290, ch)
- #define TC_RFP_ch(ch) _MCMAIN_C(0x4294, ch)
- #define TC_RFTP_ch(ch) _MCMAIN_C(0x4298, ch)
-+#define TC_MR2_SHADOW_ch(ch) _MCMAIN_C(0x429c, ch)
- #define MC_INIT_STATE_ch(ch) _MCMAIN_C(0x42a0, ch)
- #define TC_SRFTP_ch(ch) _MCMAIN_C(0x42a4, ch)
-
-+#define REUT_GLOBAL_ERR 0x4804
-+
-+#define REUT_ch_SEQ_CFG(ch) (0x48a8 + 8 * (ch))
-+
-+#define REUT_ch_SEQ_CTL(ch) (0x48b8 + 4 * (ch))
-+
- /* MCMAIN broadcast */
- #define MCSCHEDS_CBIT 0x4c20
-
-+#define MCSCHEDS_DFT_MISC 0x4c30
-+
-+#define REUT_ERR_DATA_STATUS 0x4ce0
-+
-+#define REUT_MISC_CKE_CTRL 0x4d90
-+#define REUT_MISC_ODT_CTRL 0x4d94
-+
- #define MCMNTS_SC_WDBWM 0x4f8c
-
- /* MCDECS */
-diff --git a/src/southbridge/intel/lynxpoint/pch.h b/src/southbridge/intel/lynxpoint/pch.h
-index 07f4b9dc16..5b3696347c 100644
---- a/src/southbridge/intel/lynxpoint/pch.h
-+++ b/src/southbridge/intel/lynxpoint/pch.h
-@@ -586,6 +586,8 @@ void mainboard_config_rcba(void);
- #define ACPIIRQEN 0x31e0 /* 32bit */
- #define OIC 0x31fe /* 16bit */
- #define PRSTS 0x3310 /* 32bit */
-+#define PM_CFG2 0x333c /* 32bit */
-+#define PM_CFG2_DRAM_RESET_CTL (1 << 26) /* ULT only */
- #define PMSYNC_CONFIG 0x33c4 /* 32bit */
- #define PMSYNC_CONFIG2 0x33cc /* 32bit */
- #define SOFT_RESET_CTRL 0x38f4
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0035-src-intel-skylake-Disable-stack-overflow-debug-optio.patch b/config/coreboot/default/patches/0035-src-intel-skylake-Disable-stack-overflow-debug-optio.patch
new file mode 100644
index 00000000..eb5f0028
--- /dev/null
+++ b/config/coreboot/default/patches/0035-src-intel-skylake-Disable-stack-overflow-debug-optio.patch
@@ -0,0 +1,61 @@
+From 18f4e970ebda43dd538f74398aea463a67040dd3 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Mon, 6 Jan 2025 01:36:23 +0000
+Subject: [PATCH 35/37] src/intel/skylake: Disable stack overflow debug options
+
+The option was appearing in T480/3050micro configs of lbmk,
+after updating on the coreboot/next uprev for 20241206 rev8:
+
+CONFIG_DEBUG_STACK_OVERFLOW_BREAKPOINTS=y
+
+I did some digging. See coreboot commit:
+
+commit 51cc2bacb6b07279b97e9934d079060475481fb6
+Author: Subrata Banik <subratabanik@google.com>
+Date: Fri Dec 13 13:07:28 2024 +0530
+
+ soc/intel/pantherlake: Disable stack overflow debug options
+
+Well now:
+
+I'm disabling this behaviour on Skylake, for the same
+behaviour, because I want as few behaviour changes in general,
+as possible, for the rev8 release.
+
+According to Subrata's patch, which was for Pantherlake,
+without this change, stack corruption can occur on verstage
+and romstage early on. Please look at that coreboot patch,
+referenced above, for clarity.
+
+I see no harm in disabling this option for Skylake, since
+the behaviour that it otherwise enables was not present
+before.
+
+Signed-off-by: Leah Rowe <leah@libreboot.org>
+---
+ src/soc/intel/skylake/Kconfig | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/src/soc/intel/skylake/Kconfig b/src/soc/intel/skylake/Kconfig
+index d51ffaef7b..42af82a5d8 100644
+--- a/src/soc/intel/skylake/Kconfig
++++ b/src/soc/intel/skylake/Kconfig
+@@ -129,6 +129,15 @@ config DCACHE_RAM_SIZE
+ The size of the cache-as-ram region required during bootblock
+ and/or romstage.
+
++# Override DEBUG Kconfig to avoid false alarm about stack overflow.
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS
++ bool
++ default n
++
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS_IN_ALL_STAGES
++ bool
++ default n
++
+ config DCACHE_BSP_STACK_SIZE
+ hex
+ default 0x20400 if FSP_USES_CB_STACK
+--
+2.39.5
+
diff --git a/config/coreboot/default/patches/0036-haswell-NRI-Add-pre-training-steps.patch b/config/coreboot/default/patches/0036-haswell-NRI-Add-pre-training-steps.patch
deleted file mode 100644
index 1b58a1f1..00000000
--- a/config/coreboot/default/patches/0036-haswell-NRI-Add-pre-training-steps.patch
+++ /dev/null
@@ -1,392 +0,0 @@
-From 19bc8d27c8f52b205df218d5917ae67ac4646024 Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Sat, 7 May 2022 23:12:18 +0200
-Subject: [PATCH 36/51] haswell NRI: Add pre-training steps
-
-Implement pre-training steps, which consist of enabling ECC I/O and
-filling the WDB (Write Data Buffer, stores test patterns) through a
-magic LDAT port.
-
-Change-Id: Ie2e09e3b218c4569ed8de5c5e1b05d491032e0f1
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../intel/haswell/native_raminit/Makefile.mk | 1 +
- .../haswell/native_raminit/raminit_main.c | 35 ++++
- .../haswell/native_raminit/raminit_native.h | 24 +++
- .../haswell/native_raminit/reg_structs.h | 45 +++++
- .../intel/haswell/native_raminit/setup_wdb.c | 159 ++++++++++++++++++
- .../intel/haswell/registers/mchbar.h | 9 +
- 6 files changed, 273 insertions(+)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/setup_wdb.c
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-index e9212df9e6..8d7d4e4db0 100644
---- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-@@ -10,5 +10,6 @@ romstage-y += memory_map.c
- romstage-y += raminit_main.c
- romstage-y += raminit_native.c
- romstage-y += reut.c
-+romstage-y += setup_wdb.c
- romstage-y += spd_bitmunching.c
- romstage-y += timings_refresh.c
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-index 94b268468c..5e4674957d 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-@@ -3,6 +3,7 @@
- #include <assert.h>
- #include <console/console.h>
- #include <cpu/intel/haswell/haswell.h>
-+#include <delay.h>
- #include <device/pci_ops.h>
- #include <northbridge/intel/haswell/chip.h>
- #include <northbridge/intel/haswell/haswell.h>
-@@ -12,6 +13,39 @@
-
- #include "raminit_native.h"
-
-+static enum raminit_status pre_training(struct sysinfo *ctrl)
-+{
-+ /* Skip on S3 resume */
-+ if (ctrl->bootmode == BOOTMODE_S3)
-+ return RAMINIT_STATUS_SUCCESS;
-+
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ for (uint8_t slot = 0; slot < NUM_SLOTS; slot++) {
-+ if (!rank_in_ch(ctrl, slot + slot, channel))
-+ continue;
-+
-+ printk(RAM_DEBUG, "C%uS%u:\n", channel, slot);
-+ printk(RAM_DEBUG, "\tMR0: 0x%04x\n", ctrl->mr0[channel][slot]);
-+ printk(RAM_DEBUG, "\tMR1: 0x%04x\n", ctrl->mr1[channel][slot]);
-+ printk(RAM_DEBUG, "\tMR2: 0x%04x\n", ctrl->mr2[channel][slot]);
-+ printk(RAM_DEBUG, "\tMR3: 0x%04x\n", ctrl->mr3[channel][slot]);
-+ printk(RAM_DEBUG, "\n");
-+ }
-+ if (ctrl->is_ecc) {
-+ union mad_dimm_reg mad_dimm = {
-+ .raw = mchbar_read32(MAD_DIMM(channel)),
-+ };
-+ /* Enable ECC I/O */
-+ mad_dimm.ecc_mode = 1;
-+ mchbar_write32(MAD_DIMM(channel), mad_dimm.raw);
-+ /* Wait 4 usec after enabling the ECC I/O, needed by HW */
-+ udelay(4);
-+ }
-+ }
-+ setup_wdb(ctrl);
-+ return RAMINIT_STATUS_SUCCESS;
-+}
-+
- struct task_entry {
- enum raminit_status (*task)(struct sysinfo *);
- bool is_enabled;
-@@ -25,6 +59,7 @@ static const struct task_entry cold_boot[] = {
- { configure_mc, true, "CONFMC", },
- { configure_memory_map, true, "MEMMAP", },
- { do_jedec_init, true, "JEDECINIT", },
-+ { pre_training, true, "PRETRAIN", },
- };
-
- /* Return a generic stepping value to make stepping checks simpler */
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index 759d755d6d..4d9487d79c 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -36,6 +36,13 @@
-
- #define RTTNOM_MASK (BIT(9) | BIT(6) | BIT(2))
-
-+#define BASIC_VA_PAT_SPREAD_8 0x01010101
-+
-+#define WDB_CACHE_LINE_SIZE 8
-+
-+#define NUM_WDB_CL_MUX_SEEDS 3
-+#define NUM_CADB_MUX_SEEDS 3
-+
- /* ZQ calibration types */
- enum {
- ZQ_INIT, /* DDR3: ZQCL with tZQinit, LPDDR3: ZQ Init with tZQinit */
-@@ -317,6 +324,23 @@ void reut_issue_mrs_all(
-
- enum raminit_status reut_issue_zq(struct sysinfo *ctrl, uint8_t chanmask, uint8_t zq_type);
-
-+void write_wdb_fixed_pat(
-+ const struct sysinfo *ctrl,
-+ const uint8_t patterns[],
-+ const uint8_t pat_mask[],
-+ uint8_t spread,
-+ uint16_t start);
-+
-+void write_wdb_va_pat(
-+ const struct sysinfo *ctrl,
-+ uint32_t agg_mask,
-+ uint32_t vic_mask,
-+ uint8_t vic_rot,
-+ uint16_t start);
-+
-+void program_wdb_lfsr(const struct sysinfo *ctrl, bool cleanup);
-+void setup_wdb(const struct sysinfo *ctrl);
-+
- uint8_t get_rx_bias(const struct sysinfo *ctrl);
-
- uint8_t get_tCWL(uint32_t mem_clock_mhz);
-diff --git a/src/northbridge/intel/haswell/native_raminit/reg_structs.h b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-index 9929f617fe..7aa8d8c8b2 100644
---- a/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-+++ b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-@@ -335,6 +335,18 @@ union mcscheds_cbit_reg {
- uint32_t raw;
- };
-
-+union reut_pat_cl_mux_lmn_reg {
-+ struct __packed {
-+ uint32_t l_data_select : 1; // Bits 0:0
-+ uint32_t en_sweep_freq : 1; // Bits 1:1
-+ uint32_t : 6; // Bits 7:2
-+ uint32_t l_counter : 8; // Bits 15:8
-+ uint32_t m_counter : 8; // Bits 23:16
-+ uint32_t n_counter : 8; // Bits 31:24
-+ };
-+ uint32_t raw;
-+};
-+
- union reut_pat_cadb_prog_reg {
- struct __packed {
- uint32_t addr : 16; // Bits 15:0
-@@ -439,6 +451,39 @@ union reut_misc_odt_ctrl_reg {
- uint32_t raw;
- };
-
-+union ldat_pdat_reg {
-+ struct __packed {
-+ uint32_t fast_addr : 12; // Bits 11:0
-+ uint32_t : 4; // Bits 15:12
-+ uint32_t addr_en : 1; // Bits 16:16
-+ uint32_t seq_en : 1; // Bits 17:17
-+ uint32_t pol_0 : 1; // Bits 18:18
-+ uint32_t pol_1 : 1; // Bits 19:19
-+ uint32_t cmd_a : 4; // Bits 23:20
-+ uint32_t cmd_b : 4; // Bits 27:24
-+ uint32_t cmd_c : 4; // Bits 31:28
-+ };
-+ uint32_t raw;
-+};
-+
-+union ldat_sdat_reg {
-+ struct __packed {
-+ uint32_t bank_sel : 4; // Bits 3:0
-+ uint32_t : 1; // Bits 4:4
-+ uint32_t array_sel : 5; // Bits 9:5
-+ uint32_t cmp : 1; // Bits 10:10
-+ uint32_t replicate : 1; // Bits 11:11
-+ uint32_t dword : 4; // Bits 15:12
-+ uint32_t mode : 2; // Bits 17:16
-+ uint32_t mpmap : 6; // Bits 23:18
-+ uint32_t mpb_offset : 4; // Bits 27:24
-+ uint32_t stage_en : 1; // Bits 28:28
-+ uint32_t shadow : 2; // Bits 30:29
-+ uint32_t : 1; // Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
- union mcscheds_dft_misc_reg {
- struct __packed {
- uint32_t wdar : 1; // Bits 0:0
-diff --git a/src/northbridge/intel/haswell/native_raminit/setup_wdb.c b/src/northbridge/intel/haswell/native_raminit/setup_wdb.c
-new file mode 100644
-index 0000000000..ec37c48415
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/setup_wdb.c
-@@ -0,0 +1,159 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <types.h>
-+
-+#include "raminit_native.h"
-+
-+static void ldat_write_cacheline(
-+ const struct sysinfo *const ctrl,
-+ const uint8_t chunk,
-+ const uint16_t start,
-+ const uint64_t data)
-+{
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ /*
-+ * Do not do a 64-bit write here. The register is not aligned
-+ * to a 64-bit boundary, which could potentially cause issues.
-+ */
-+ mchbar_write32(QCLK_ch_LDAT_DATA_IN_x(channel, 0), data & UINT32_MAX);
-+ mchbar_write32(QCLK_ch_LDAT_DATA_IN_x(channel, 1), data >> 32);
-+ /*
-+ * Set REPLICATE = 0 as you don't want to replicate the data.
-+ * Set BANK_SEL to the chunk you want to write the 64 bits to.
-+ * Set ARRAY_SEL = 0 (the MC WDB) and MODE = 1.
-+ */
-+ const union ldat_sdat_reg ldat_sdat = {
-+ .bank_sel = chunk,
-+ .mode = 1,
-+ };
-+ mchbar_write32(QCLK_ch_LDAT_SDAT(channel), ldat_sdat.raw);
-+ /*
-+ * Finally, write the PDAT register indicating which cacheline
-+ * of the WDB you want to write to by setting FAST_ADDR field
-+ * to one of the 64 cache lines. Also set CMD_B in the PDAT
-+ * register to 4'b1000, indicating that this is a LDAT write.
-+ */
-+ const union ldat_pdat_reg ldat_pdat = {
-+ .fast_addr = MIN(start, 0xfff),
-+ .cmd_b = 8,
-+ };
-+ mchbar_write32(QCLK_ch_LDAT_PDAT(channel), ldat_pdat.raw);
-+ }
-+}
-+
-+static void clear_ldat_mode(const struct sysinfo *const ctrl)
-+{
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++)
-+ mchbar_write32(QCLK_ch_LDAT_SDAT(channel), 0);
-+}
-+
-+void write_wdb_fixed_pat(
-+ const struct sysinfo *const ctrl,
-+ const uint8_t patterns[],
-+ const uint8_t pat_mask[],
-+ const uint8_t spread,
-+ const uint16_t start)
-+{
-+ for (uint8_t chunk = 0; chunk < WDB_CACHE_LINE_SIZE; chunk++) {
-+ uint64_t data = 0;
-+ for (uint8_t b = 0; b < 64; b++) {
-+ const uint8_t beff = b % spread;
-+ const uint8_t burst = patterns[pat_mask[beff]];
-+ if (burst & BIT(chunk))
-+ data |= 1ULL << b;
-+ }
-+ ldat_write_cacheline(ctrl, chunk, start, data);
-+ }
-+ clear_ldat_mode(ctrl);
-+}
-+
-+static inline uint32_t rol_u32(const uint32_t val)
-+{
-+ return (val << 1) | ((val >> 31) & 1);
-+}
-+
-+void write_wdb_va_pat(
-+ const struct sysinfo *const ctrl,
-+ const uint32_t agg_mask,
-+ const uint32_t vic_mask,
-+ const uint8_t vic_rot,
-+ const uint16_t start)
-+{
-+ static const uint8_t va_mask_to_compressed[4] = {0xaa, 0xc0, 0xcc, 0xf0};
-+ uint32_t v_mask = vic_mask;
-+ uint32_t a_mask = agg_mask;
-+ for (uint8_t v = 0; v < vic_rot; v++) {
-+ uint8_t compressed[32] = {0};
-+ /* Iterate through all 32 bits and create a compressed version of cacheline */
-+ for (uint8_t b = 0; b < ARRAY_SIZE(compressed); b++) {
-+ const uint8_t vic = !!(v_mask & BIT(b));
-+ const uint8_t agg = !!(a_mask & BIT(b));
-+ const uint8_t index = !vic << 1 | agg << 0;
-+ compressed[b] = va_mask_to_compressed[index];
-+ }
-+ for (uint8_t chunk = 0; chunk < WDB_CACHE_LINE_SIZE; chunk++) {
-+ uint32_t data = 0;
-+ for (uint8_t b = 0; b < ARRAY_SIZE(compressed); b++)
-+ data |= !!(compressed[b] & BIT(chunk)) << b;
-+
-+ const uint64_t data64 = (uint64_t)data << 32 | data;
-+ ldat_write_cacheline(ctrl, chunk, start + v, data64);
-+ }
-+ v_mask = rol_u32(v_mask);
-+ a_mask = rol_u32(a_mask);
-+ }
-+ clear_ldat_mode(ctrl);
-+}
-+
-+void program_wdb_lfsr(const struct sysinfo *ctrl, const bool cleanup)
-+{
-+ /* Cleanup LFSR seeds are sequential */
-+ const uint32_t cleanup_seeds[NUM_WDB_CL_MUX_SEEDS] = { 0xaaaaaa, 0xcccccc, 0xf0f0f0 };
-+ const uint32_t regular_seeds[NUM_WDB_CL_MUX_SEEDS] = { 0xa10ca1, 0xef0d08, 0xad0a1e };
-+ const uint32_t *seeds = cleanup ? cleanup_seeds : regular_seeds;
-+
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ for (uint8_t i = 0; i < NUM_WDB_CL_MUX_SEEDS; i++) {
-+ mchbar_write32(REUT_ch_PAT_WDB_CL_MUX_RD_x(channel, i), seeds[i]);
-+ mchbar_write32(REUT_ch_PAT_WDB_CL_MUX_WR_x(channel, i), seeds[i]);
-+ }
-+ }
-+}
-+
-+void setup_wdb(const struct sysinfo *ctrl)
-+{
-+ const uint32_t amask[9] = {
-+ 0x86186186, 0x18618618, 0x30c30c30,
-+ 0xa28a28a2, 0x8a28a28a, 0x14514514,
-+ 0x28a28a28, 0x92492492, 0x24924924,
-+ };
-+ const uint32_t vmask = 0x41041041;
-+
-+ /* Fill first 8 entries with simple 2-LFSR VA pattern */
-+ write_wdb_va_pat(ctrl, 0, BASIC_VA_PAT_SPREAD_8, 8, 0);
-+
-+ /* Fill next 54 entries with 3-LFSR VA pattern */
-+ for (uint8_t a = 0; a < ARRAY_SIZE(amask); a++)
-+ write_wdb_va_pat(ctrl, amask[a], vmask, 6, 8 + a * 6);
-+
-+ program_wdb_lfsr(ctrl, false);
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ const union reut_pat_cl_mux_lmn_reg wdb_cl_mux_lmn = {
-+ .en_sweep_freq = 1,
-+ .l_counter = 1,
-+ .m_counter = 1,
-+ .n_counter = 10,
-+ };
-+ mchbar_write32(REUT_ch_PAT_WDB_CL_MUX_LMN(channel), wdb_cl_mux_lmn.raw);
-+ }
-+}
-diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
-index 4fc78a7f43..f8408e51a0 100644
---- a/src/northbridge/intel/haswell/registers/mchbar.h
-+++ b/src/northbridge/intel/haswell/registers/mchbar.h
-@@ -94,6 +94,11 @@
- #define TC_BANK_RANK_D_ch(ch) _MCMAIN_C(0x4014, ch)
- #define SC_ROUNDT_LAT_ch(ch) _MCMAIN_C(0x4024, ch)
-
-+#define REUT_ch_PAT_WDB_CL_MUX_WR_x(ch, x) _MCMAIN_C_X(0x4048, ch, x) /* x in 0 .. 2 */
-+#define REUT_ch_PAT_WDB_CL_MUX_RD_x(ch, x) _MCMAIN_C_X(0x4054, ch, x) /* x in 0 .. 2 */
-+
-+#define REUT_ch_PAT_WDB_CL_MUX_LMN(ch) _MCMAIN_C(0x4078, ch)
-+
- #define SC_WR_ADD_DELAY_ch(ch) _MCMAIN_C(0x40d0, ch)
-
- #define REUT_ch_MISC_CKE_CTRL(ch) _MCMAIN_C(0x4190, ch)
-@@ -110,6 +115,10 @@
- #define MC_INIT_STATE_ch(ch) _MCMAIN_C(0x42a0, ch)
- #define TC_SRFTP_ch(ch) _MCMAIN_C(0x42a4, ch)
-
-+#define QCLK_ch_LDAT_PDAT(ch) _MCMAIN_C(0x42d0, ch)
-+#define QCLK_ch_LDAT_SDAT(ch) _MCMAIN_C(0x42d4, ch)
-+#define QCLK_ch_LDAT_DATA_IN_x(ch, x) _MCMAIN_C_X(0x42dc, ch, x) /* x in 0 .. 1 */
-+
- #define REUT_GLOBAL_ERR 0x4804
-
- #define REUT_ch_SEQ_CFG(ch) (0x48a8 + 8 * (ch))
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0036-src-intel-x4x-Disable-stack-overflow-debug.patch b/config/coreboot/default/patches/0036-src-intel-x4x-Disable-stack-overflow-debug.patch
new file mode 100644
index 00000000..2e06ad79
--- /dev/null
+++ b/config/coreboot/default/patches/0036-src-intel-x4x-Disable-stack-overflow-debug.patch
@@ -0,0 +1,33 @@
+From 8dcd86c34d92b9b17bcfe4c7c61793042dc97268 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Mon, 6 Jan 2025 01:53:53 +0000
+Subject: [PATCH 36/37] src/intel/x4x: Disable stack overflow debug
+
+Signed-off-by: Leah Rowe <leah@libreboot.org>
+---
+ src/northbridge/intel/x4x/Kconfig | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/src/northbridge/intel/x4x/Kconfig b/src/northbridge/intel/x4x/Kconfig
+index 1803ef5733..7129aabf72 100644
+--- a/src/northbridge/intel/x4x/Kconfig
++++ b/src/northbridge/intel/x4x/Kconfig
+@@ -32,6 +32,15 @@ config ECAM_MMCONF_BUS_NUMBER
+ int
+ default 256
+
++# Override DEBUG Kconfig to avoid false alarm about stack overflow.
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS
++ bool
++ default n
++
++config DEBUG_STACK_OVERFLOW_BREAKPOINTS_IN_ALL_STAGES
++ bool
++ default n
++
+ # This number must be equal or lower than what's reported in ACPI PCI _CRS
+ config DOMAIN_RESOURCE_32BIT_LIMIT
+ default 0xfec00000
+--
+2.39.5
+
diff --git a/config/coreboot/default/patches/0037-Conditional-TBFW-setting-for-T480-T480S.patch b/config/coreboot/default/patches/0037-Conditional-TBFW-setting-for-T480-T480S.patch
new file mode 100644
index 00000000..7bca06a7
--- /dev/null
+++ b/config/coreboot/default/patches/0037-Conditional-TBFW-setting-for-T480-T480S.patch
@@ -0,0 +1,37 @@
+From 9b547c2029611793f895117a807fa2d2c22a5332 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Mon, 21 Apr 2025 05:14:45 +0100
+Subject: [PATCH 37/37] Conditional TBFW setting for T480/T480S
+
+Otherwise, other boards will define it, which
+might trigger the vendor download script, and
+lead to a non-zero exit.
+
+Signed-off-by: Leah Rowe <leah@libreboot.org>
+---
+ src/mainboard/lenovo/Kconfig | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/src/mainboard/lenovo/Kconfig b/src/mainboard/lenovo/Kconfig
+index 512b326381..3d3490b35d 100644
+--- a/src/mainboard/lenovo/Kconfig
++++ b/src/mainboard/lenovo/Kconfig
+@@ -18,6 +18,8 @@ config MAINBOARD_FAMILY
+ string
+ default MAINBOARD_PART_NUMBER
+
++if BOARD_LENOVO_T480 || BOARD_LENOVO_T480S
++
+ config LENOVO_TBFW_BIN
+ string "Lenovo ThunderBolt firmware bin file"
+ default ""
+@@ -44,4 +46,6 @@ config LENOVO_TBFW_BIN
+ Just leave this blank if you don't care about this option. It's not
+ useful for every ThinkPad, only certain models.
+
++endif # BOARD LENOVO_T480 || BOARD_LENOVO_T480S
++
+ endif # VENDOR_LENOVO
+--
+2.39.5
+
diff --git a/config/coreboot/default/patches/0037-haswell-NRI-Add-REUT-I-O-test-library.patch b/config/coreboot/default/patches/0037-haswell-NRI-Add-REUT-I-O-test-library.patch
deleted file mode 100644
index eaafcde3..00000000
--- a/config/coreboot/default/patches/0037-haswell-NRI-Add-REUT-I-O-test-library.patch
+++ /dev/null
@@ -1,1130 +0,0 @@
-From 460a092b22c9800c5ee9d8c4198e8b241664693f Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Sun, 8 May 2022 00:11:29 +0200
-Subject: [PATCH 37/51] haswell NRI: Add REUT I/O test library
-
-Implement a library to run I/O tests using the REUT hardware.
-
-Change-Id: Id7b207cd0a3989ddd23c88c6b1f0cfa79d2c861f
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../intel/haswell/native_raminit/Makefile.mk | 1 +
- .../haswell/native_raminit/raminit_native.h | 110 +++
- .../haswell/native_raminit/reg_structs.h | 121 +++
- .../intel/haswell/native_raminit/testing_io.c | 744 ++++++++++++++++++
- .../intel/haswell/registers/mchbar.h | 30 +
- 5 files changed, 1006 insertions(+)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/testing_io.c
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-index 8d7d4e4db0..6e1b365602 100644
---- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-@@ -12,4 +12,5 @@ romstage-y += raminit_native.c
- romstage-y += reut.c
- romstage-y += setup_wdb.c
- romstage-y += spd_bitmunching.c
-+romstage-y += testing_io.c
- romstage-y += timings_refresh.c
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index 4d9487d79c..f029e7f076 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -59,6 +59,88 @@ enum {
- REUT_MODE_NOP = 3, /* Normal operation mode */
- };
-
-+/* REUT error counter control */
-+enum {
-+ COUNT_ERRORS_PER_CHANNEL = 0,
-+ COUNT_ERRORS_PER_LANE = 1,
-+ COUNT_ERRORS_PER_BYTE_GROUP = 2,
-+ COUNT_ERRORS_PER_CHUNK = 3,
-+};
-+
-+enum wdb_dq_pattern {
-+ BASIC_VA = 0,
-+ SEGMENT_WDB,
-+ CADB,
-+ TURN_AROUND,
-+ LMN_VA,
-+ TURN_AROUND_WR,
-+ TURN_AROUND_ODT,
-+ RD_RD_TA,
-+ RD_RD_TA_ALL,
-+};
-+
-+enum reut_cmd_pat {
-+ PAT_WR_RD,
-+ PAT_WR,
-+ PAT_RD,
-+ PAT_RD_WR_TA,
-+ PAT_WR_RD_TA,
-+ PAT_ODT_TA,
-+};
-+
-+/* REUT subsequence types (B = Base, O = Offset) */
-+enum {
-+ SUBSEQ_B_RD = 0 << 22,
-+ SUBSEQ_B_WR = 1 << 22,
-+ SUBSEQ_B_RD_WR = 2 << 22,
-+ SUBSEQ_B_WR_RD = 3 << 22,
-+ SUBSEQ_O_RD = 4 << 22,
-+ SUBSEQ_O_WR = 5 << 22,
-+};
-+
-+/* REUT mux control */
-+enum {
-+ REUT_MUX_LMN = 0,
-+ REUT_MUX_BTBUFFER = 1,
-+ REUT_MUX_LFSR = 2,
-+};
-+
-+/* Increment scale */
-+enum {
-+ SCALE_LOGARITHM = 0,
-+ SCALE_LINEAR = 1,
-+};
-+
-+enum test_stop {
-+ NSOE = 0, /* Never stop on error */
-+ NTHSOE = 1, /* Stop on the nth error (we use n = 1) */
-+ ABGSOE = 2, /* Stop on all byte groups error */
-+ ALSOE = 3, /* Stop on all lanes error */
-+};
-+
-+struct wdb_pat {
-+ uint32_t start_ptr; /* Starting pointer in WDB */
-+ uint32_t stop_ptr; /* Stopping pointer in WDB */
-+ uint16_t inc_rate; /* How quickly the WDB walks through cachelines */
-+ uint8_t dq_pattern; /* DQ pattern to use (see enum wdb_dq_pattern above) */
-+};
-+
-+struct reut_pole {
-+ uint16_t start;
-+ uint16_t stop;
-+ uint16_t order;
-+ uint32_t inc_rate;
-+ uint16_t inc_val;
-+ bool wrap_trigger;
-+};
-+
-+struct reut_box {
-+ struct reut_pole rank;
-+ struct reut_pole bank;
-+ struct reut_pole row;
-+ struct reut_pole col;
-+};
-+
- enum command_training_iteration {
- CT_ITERATION_CLOCK = 0,
- CT_ITERATION_CMD_NORTH,
-@@ -200,6 +282,10 @@ struct sysinfo {
- uint16_t mr1[NUM_CHANNELS][NUM_SLOTS];
- uint16_t mr2[NUM_CHANNELS][NUM_SLOTS];
- uint16_t mr3[NUM_CHANNELS][NUM_SLOTS];
-+
-+ uint8_t dq_pat;
-+
-+ uint8_t dq_pat_lc;
- };
-
- static inline bool is_hsw_ult(void)
-@@ -341,6 +427,30 @@ void write_wdb_va_pat(
- void program_wdb_lfsr(const struct sysinfo *ctrl, bool cleanup);
- void setup_wdb(const struct sysinfo *ctrl);
-
-+void program_seq_addr(uint8_t channel, const struct reut_box *reut_addr, bool log_seq_addr);
-+void program_loop_count(const struct sysinfo *ctrl, uint8_t channel, uint8_t lc_exp);
-+
-+void setup_io_test(
-+ struct sysinfo *ctrl,
-+ uint8_t chanmask,
-+ enum reut_cmd_pat cmd_pat,
-+ uint16_t num_cl,
-+ uint8_t lc,
-+ const struct reut_box *reut_addr,
-+ enum test_stop soe,
-+ const struct wdb_pat *pat,
-+ uint8_t en_cadb,
-+ uint8_t subseq_wait);
-+
-+void setup_io_test_cadb(struct sysinfo *ctrl, uint8_t chanmask, uint8_t lc, enum test_stop soe);
-+void setup_io_test_basic_va(struct sysinfo *ctrl, uint8_t chm, uint8_t lc, enum test_stop soe);
-+void setup_io_test_mpr(struct sysinfo *ctrl, uint8_t chanmask, uint8_t lc, enum test_stop soe);
-+
-+uint8_t select_reut_ranks(struct sysinfo *ctrl, uint8_t channel, uint8_t rankmask);
-+
-+void run_mpr_io_test(bool clear_errors);
-+uint8_t run_io_test(struct sysinfo *ctrl, uint8_t chanmask, uint8_t dq_pat, bool clear_errors);
-+
- uint8_t get_rx_bias(const struct sysinfo *ctrl);
-
- uint8_t get_tCWL(uint32_t mem_clock_mhz);
-diff --git a/src/northbridge/intel/haswell/native_raminit/reg_structs.h b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-index 7aa8d8c8b2..b943259b91 100644
---- a/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-+++ b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-@@ -347,6 +347,54 @@ union reut_pat_cl_mux_lmn_reg {
- uint32_t raw;
- };
-
-+union reut_err_ctl_reg {
-+ struct __packed {
-+ uint32_t stop_on_nth_error : 6; // Bits 5:0
-+ uint32_t : 6; // Bits 11:6
-+ uint32_t stop_on_error_control : 2; // Bits 13:12
-+ uint32_t : 2; // Bits 15:14
-+ uint32_t selective_err_enable_chunk : 8; // Bits 23:16
-+ uint32_t selective_err_enable_cacheline : 8; // Bits 31:24
-+ };
-+ uint32_t raw;
-+};
-+
-+union reut_pat_cadb_mux_ctrl_reg {
-+ struct __packed {
-+ uint32_t mux_0_ctrl : 2; // Bits 1:0
-+ uint32_t : 2; // Bits 3:2
-+ uint32_t mux_1_ctrl : 2; // Bits 5:4
-+ uint32_t : 2; // Bits 7:6
-+ uint32_t mux_2_ctrl : 2; // Bits 9:8
-+ uint32_t : 6; // Bits 15:10
-+ uint32_t sel_mux_0_ctrl : 2; // Bits 17:16
-+ uint32_t : 2; // Bits 19:18
-+ uint32_t sel_mux_1_ctrl : 2; // Bits 21:20
-+ uint32_t : 2; // Bits 23:22
-+ uint32_t sel_mux_2_ctrl : 2; // Bits 25:24
-+ uint32_t : 6; // Bits 31:26
-+ };
-+ uint32_t raw;
-+};
-+
-+union reut_pat_wdb_cl_mux_cfg_reg {
-+ struct __packed {
-+ uint32_t mux_0_control : 2; // Bits 1:0
-+ uint32_t : 1; // Bits 2:2
-+ uint32_t mux_1_control : 2; // Bits 4:3
-+ uint32_t : 1; // Bits 5:5
-+ uint32_t mux_2_control : 2; // Bits 7:6
-+ uint32_t : 6; // Bits 13:8
-+ uint32_t ecc_replace_byte_ctl : 1; // Bits 14:14
-+ uint32_t ecc_data_source_sel : 1; // Bits 15:15
-+ uint32_t save_lfsr_seed_rate : 6; // Bits 21:16
-+ uint32_t : 2; // Bits 23:22
-+ uint32_t reload_lfsr_seed_rate : 3; // Bits 26:24
-+ uint32_t : 5; // Bits 31:27
-+ };
-+ uint32_t raw;
-+};
-+
- union reut_pat_cadb_prog_reg {
- struct __packed {
- uint32_t addr : 16; // Bits 15:0
-@@ -366,6 +414,19 @@ union reut_pat_cadb_prog_reg {
- uint32_t raw32[2];
- };
-
-+union reut_pat_wdb_cl_ctrl_reg {
-+ struct __packed {
-+ uint32_t inc_rate : 5; // Bits 4:0
-+ uint32_t inc_scale : 1; // Bits 5:5
-+ uint32_t : 2; // Bits 7:6
-+ uint32_t start_ptr : 6; // Bits 13:8
-+ uint32_t : 2; // Bits 15:14
-+ uint32_t end_ptr : 6; // Bits 21:16
-+ uint32_t : 10; // Bits 31:22
-+ };
-+ uint32_t raw;
-+};
-+
- union reut_pat_cadb_mrs_reg {
- struct __packed {
- uint32_t delay_gap : 3; // Bits 2:0
-@@ -406,6 +467,66 @@ union reut_seq_cfg_reg {
- uint32_t raw32[2];
- };
-
-+union reut_seq_base_addr_reg {
-+ struct __packed {
-+ uint32_t : 3; // Bits 2:0
-+ uint32_t col_addr : 8; // Bits 10:3
-+ uint32_t : 13; // Bits 23:11
-+ uint32_t row_addr : 16; // Bits 39:24
-+ uint32_t : 8; // Bits 47:40
-+ uint32_t bank_addr : 3; // Bits 50:48
-+ uint32_t : 5; // Bits 55:51
-+ uint32_t rank_addr : 3; // Bits 58:56
-+ uint32_t : 5; // Bits 63:59
-+ };
-+ uint32_t raw32[2];
-+ uint64_t raw;
-+};
-+
-+union reut_seq_misc_ctl_reg {
-+ struct __packed {
-+ uint32_t col_addr_order : 2; // Bits 1:0
-+ uint32_t row_addr_order : 2; // Bits 3:2
-+ uint32_t bank_addr_order : 2; // Bits 5:4
-+ uint32_t rank_addr_order : 2; // Bits 7:6
-+ uint32_t : 5; // Bits 12:8
-+ uint32_t addr_invert_rate : 3; // Bits 15:13
-+ uint32_t : 4; // Bits 19:16
-+ uint32_t col_addr_invert_en : 1; // Bits 20:20
-+ uint32_t row_addr_invert_en : 1; // Bits 21:21
-+ uint32_t bank_addr_invert_en : 1; // Bits 22:22
-+ uint32_t rank_addr_invert_en : 1; // Bits 23:23
-+ uint32_t col_wrap_trigger_en : 1; // Bits 24:24
-+ uint32_t row_wrap_trigger_en : 1; // Bits 25:25
-+ uint32_t bank_wrap_trigger_en : 1; // Bits 26:26
-+ uint32_t rank_wrap_trigger_en : 1; // Bits 27:27
-+ uint32_t col_wrap_carry_en : 1; // Bits 28:28
-+ uint32_t row_wrap_carry_en : 1; // Bits 29:29
-+ uint32_t bank_wrap_carry_en : 1; // Bits 30:30
-+ uint32_t rank_wrap_carry_en : 1; // Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
-+union reut_seq_addr_inc_ctl_reg {
-+ struct __packed {
-+ uint32_t : 3; // Bits 2:0
-+ uint32_t col_addr_increment : 8; // Bits 10:3
-+ uint32_t : 1; // Bits 11:11
-+ uint32_t col_addr_update : 8; // Bits 19:12
-+ uint32_t row_addr_increment : 12; // Bits 31:20
-+ uint32_t row_addr_update : 6; // Bits 37:32
-+ uint32_t bank_addr_increment : 3; // Bits 40:38
-+ uint32_t : 3; // Bits 43:41
-+ uint32_t bank_addr_update : 8; // Bits 53:44
-+ uint32_t rank_addr_increment : 3; // Bits 54:52
-+ uint32_t : 1; // Bits 55:55
-+ uint32_t rank_addr_update : 8; // Bits 63:56
-+ };
-+ uint64_t raw;
-+ uint32_t raw32[2];
-+};
-+
- union reut_seq_ctl_reg {
- struct __packed {
- uint32_t start_test : 1; // Bits 0:0
-diff --git a/src/northbridge/intel/haswell/native_raminit/testing_io.c b/src/northbridge/intel/haswell/native_raminit/testing_io.c
-new file mode 100644
-index 0000000000..2632c238f8
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/testing_io.c
-@@ -0,0 +1,744 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <console/console.h>
-+#include <delay.h>
-+#include <lib.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <timer.h>
-+#include <types.h>
-+
-+#include "raminit_native.h"
-+
-+static void set_cadb_patterns(const uint8_t channel, const uint16_t seeds[NUM_CADB_MUX_SEEDS])
-+{
-+ for (uint8_t i = 0; i < NUM_CADB_MUX_SEEDS; i++)
-+ mchbar_write32(REUT_ch_PAT_CADB_MUX_x(channel, i), seeds[i]);
-+}
-+
-+static void setup_cadb(
-+ struct sysinfo *ctrl,
-+ const uint8_t channel,
-+ const uint8_t vic_spread,
-+ const uint8_t vic_bit)
-+{
-+ const bool lmn_en = false;
-+
-+ /*
-+ * Currently, always start writing at CADB row 0.
-+ * Could add a start point parameter in the future.
-+ */
-+ mchbar_write8(REUT_ch_PAT_CADB_WRITE_PTR(channel), 0);
-+ const uint8_t num_cadb_rows = 8;
-+ for (uint8_t row = 0; row < num_cadb_rows; row++) {
-+ const uint8_t lfsr0 = (row >> 0) & 1;
-+ const uint8_t lfsr1 = (row >> 1) & 1;
-+ uint64_t reg64 = 0;
-+ for (uint8_t bit = 0; bit < 22; bit++) {
-+ uint8_t bremap;
-+ if (bit >= 19) {
-+ /* (bremap in 40 .. 42) => CADB data control */
-+ bremap = bit + 21;
-+ } else if (bit >= 16) {
-+ /* (bremap in 24 .. 26) => CADB data bank */
-+ bremap = bit + 8;
-+ } else {
-+ /* (bremap in 0 .. 15) => CADB data address */
-+ bremap = bit;
-+ }
-+ const uint8_t fine = bit % vic_spread;
-+ reg64 |= ((uint64_t)(fine == vic_bit ? lfsr0 : lfsr1)) << bremap;
-+ }
-+ /*
-+ * Write row. CADB pointer is auto incremented after every write. This must be
-+ * a single 64-bit write, otherwise the CADB pointer will auto-increment twice.
-+ */
-+ mchbar_write64(REUT_ch_PAT_CADB_PROG(channel), reg64);
-+ }
-+ const union reut_pat_cadb_mux_ctrl_reg cadb_mux_ctrl = {
-+ .mux_0_ctrl = lmn_en ? REUT_MUX_LMN : REUT_MUX_LFSR,
-+ .mux_1_ctrl = REUT_MUX_LFSR,
-+ .mux_2_ctrl = REUT_MUX_LFSR,
-+ };
-+ mchbar_write32(REUT_ch_PAT_CADB_MUX_CTRL(channel), cadb_mux_ctrl.raw);
-+ const union reut_pat_cl_mux_lmn_reg cadb_cl_mux_lmn = {
-+ .en_sweep_freq = 1,
-+ .l_counter = 1,
-+ .m_counter = 1,
-+ .n_counter = 6,
-+ };
-+ mchbar_write32(REUT_ch_PAT_CADB_CL_MUX_LMN(channel), cadb_cl_mux_lmn.raw);
-+ const uint16_t cadb_mux_seeds[NUM_CADB_MUX_SEEDS] = { 0x0ea1, 0xbeef, 0xdead };
-+ set_cadb_patterns(channel, cadb_mux_seeds);
-+}
-+
-+static uint32_t calc_rate(const uint32_t rate, const uint32_t lim, const uint8_t scale_bit)
-+{
-+ return rate > lim ? log2_ceil(rate - 1) : BIT(scale_bit) | rate;
-+}
-+
-+void program_seq_addr(
-+ const uint8_t channel,
-+ const struct reut_box *reut_addr,
-+ const bool log_seq_addr)
-+{
-+ const int loglevel = log_seq_addr ? BIOS_ERR : BIOS_NEVER;
-+ const uint32_t div = 8;
-+ union reut_seq_base_addr_reg reut_seq_addr_start = {
-+ .col_addr = reut_addr->col.start / div,
-+ .row_addr = reut_addr->row.start,
-+ .bank_addr = reut_addr->bank.start,
-+ .rank_addr = reut_addr->rank.start,
-+ };
-+ mchbar_write64(REUT_ch_SEQ_ADDR_START(channel), reut_seq_addr_start.raw);
-+ reut_seq_addr_start.raw = mchbar_read64(REUT_ch_SEQ_ADDR_START(channel));
-+ printk(loglevel, "\tStart column: %u\n", reut_seq_addr_start.col_addr);
-+ printk(loglevel, "\tStart row: %u\n", reut_seq_addr_start.row_addr);
-+ printk(loglevel, "\tStart bank: %u\n", reut_seq_addr_start.bank_addr);
-+ printk(loglevel, "\tStart rank: %u\n", reut_seq_addr_start.rank_addr);
-+ printk(loglevel, "\n");
-+
-+ union reut_seq_base_addr_reg reut_seq_addr_stop = {
-+ .col_addr = reut_addr->col.stop / div,
-+ .row_addr = reut_addr->row.stop,
-+ .bank_addr = reut_addr->bank.stop,
-+ .rank_addr = reut_addr->rank.stop,
-+ };
-+ mchbar_write64(REUT_ch_SEQ_ADDR_WRAP(channel), reut_seq_addr_stop.raw);
-+ reut_seq_addr_stop.raw = mchbar_read64(REUT_ch_SEQ_ADDR_WRAP(channel));
-+ printk(loglevel, "\tStop column: %u\n", reut_seq_addr_stop.col_addr);
-+ printk(loglevel, "\tStop row: %u\n", reut_seq_addr_stop.row_addr);
-+ printk(loglevel, "\tStop bank: %u\n", reut_seq_addr_stop.bank_addr);
-+ printk(loglevel, "\tStop rank: %u\n", reut_seq_addr_stop.rank_addr);
-+ printk(loglevel, "\n");
-+
-+ union reut_seq_misc_ctl_reg reut_seq_misc_ctl = {
-+ .col_wrap_trigger_en = reut_addr->col.wrap_trigger,
-+ .row_wrap_trigger_en = reut_addr->row.wrap_trigger,
-+ .bank_wrap_trigger_en = reut_addr->bank.wrap_trigger,
-+ .rank_wrap_trigger_en = reut_addr->rank.wrap_trigger,
-+ };
-+ mchbar_write32(REUT_ch_SEQ_MISC_CTL(channel), reut_seq_misc_ctl.raw);
-+ printk(loglevel, "\tWrap column: %u\n", reut_addr->col.wrap_trigger);
-+ printk(loglevel, "\tWrap row: %u\n", reut_addr->row.wrap_trigger);
-+ printk(loglevel, "\tWrap bank: %u\n", reut_addr->bank.wrap_trigger);
-+ printk(loglevel, "\tWrap rank: %u\n", reut_addr->rank.wrap_trigger);
-+ printk(loglevel, "\n");
-+
-+ union reut_seq_addr_inc_ctl_reg reut_seq_addr_inc_ctl = {
-+ .col_addr_update = calc_rate(reut_addr->col.inc_rate, 31, 7),
-+ .row_addr_update = calc_rate(reut_addr->row.inc_rate, 15, 5),
-+ .bank_addr_update = calc_rate(reut_addr->bank.inc_rate, 31, 7),
-+ .rank_addr_update = calc_rate(reut_addr->rank.inc_rate, 31, 7),
-+ .col_addr_increment = reut_addr->col.inc_val,
-+ .row_addr_increment = reut_addr->row.inc_val,
-+ .bank_addr_increment = reut_addr->bank.inc_val,
-+ .rank_addr_increment = reut_addr->rank.inc_val,
-+ };
-+ printk(loglevel, "\tUpdRate column: %u\n", reut_addr->col.inc_rate);
-+ printk(loglevel, "\tUpdRate row: %u\n", reut_addr->row.inc_rate);
-+ printk(loglevel, "\tUpdRate bank: %u\n", reut_addr->bank.inc_rate);
-+ printk(loglevel, "\tUpdRate rank: %u\n", reut_addr->rank.inc_rate);
-+ printk(loglevel, "\n");
-+ printk(loglevel, "\tUpdRateCR column: %u\n", reut_seq_addr_inc_ctl.col_addr_update);
-+ printk(loglevel, "\tUpdRateCR row: %u\n", reut_seq_addr_inc_ctl.row_addr_update);
-+ printk(loglevel, "\tUpdRateCR bank: %u\n", reut_seq_addr_inc_ctl.bank_addr_update);
-+ printk(loglevel, "\tUpdRateCR rank: %u\n", reut_seq_addr_inc_ctl.rank_addr_update);
-+ printk(loglevel, "\n");
-+ printk(loglevel, "\tUpdInc column: %u\n", reut_seq_addr_inc_ctl.col_addr_increment);
-+ printk(loglevel, "\tUpdInc row: %u\n", reut_seq_addr_inc_ctl.row_addr_increment);
-+ printk(loglevel, "\tUpdInc bank: %u\n", reut_seq_addr_inc_ctl.bank_addr_increment);
-+ printk(loglevel, "\tUpdInc rank: %u\n", reut_seq_addr_inc_ctl.rank_addr_increment);
-+ printk(loglevel, "\n");
-+ mchbar_write64(REUT_ch_SEQ_ADDR_INC_CTL(channel), reut_seq_addr_inc_ctl.raw);
-+}
-+
-+/*
-+ * Early steppings take exponential (base 2) loopcount values,
-+ * but later steppings take linear loopcount values elsewhere.
-+ * Address the differences in register offset and format here.
-+ */
-+void program_loop_count(const struct sysinfo *ctrl, const uint8_t channel, const uint8_t lc_exp)
-+{
-+ if (ctrl->stepping >= STEPPING_C0) {
-+ const uint32_t loopcount = lc_exp >= 32 ? 0 : BIT(lc_exp);
-+ mchbar_write32(HSW_REUT_ch_SEQ_LOOP_COUNT(channel), loopcount);
-+ } else {
-+ const uint8_t loopcount = lc_exp >= 32 ? 0 : lc_exp + 1;
-+ union reut_seq_cfg_reg reut_seq_cfg = {
-+ .raw = mchbar_read64(REUT_ch_SEQ_CFG(channel)),
-+ };
-+ reut_seq_cfg.early_steppings_loop_count = loopcount;
-+ mchbar_write64(REUT_ch_SEQ_CFG(channel), reut_seq_cfg.raw);
-+ }
-+}
-+
-+static inline void write_subseq(const uint8_t channel, const uint8_t idx, const uint32_t ssq)
-+{
-+ mchbar_write32(REUT_ch_SUBSEQ_x_CTL(channel, idx), ssq);
-+}
-+
-+static void program_subseq(
-+ struct sysinfo *const ctrl,
-+ const uint8_t channel,
-+ const enum reut_cmd_pat cmd_pat,
-+ const uint32_t ss_a,
-+ const uint32_t ss_b)
-+{
-+ switch (cmd_pat) {
-+ case PAT_WR_RD_TA:
-+ write_subseq(channel, 0, ss_a | SUBSEQ_B_WR);
-+ for (uint8_t i = 1; i < 7; i++)
-+ write_subseq(channel, i, ss_b | SUBSEQ_B_RD_WR);
-+
-+ write_subseq(channel, 7, ss_a | SUBSEQ_B_RD);
-+ break;
-+ case PAT_RD_WR_TA:
-+ write_subseq(channel, 0, ss_b | SUBSEQ_B_WR_RD);
-+ break;
-+ case PAT_ODT_TA:
-+ write_subseq(channel, 0, ss_a | SUBSEQ_B_WR);
-+ write_subseq(channel, 1, ss_b | SUBSEQ_B_RD_WR);
-+ write_subseq(channel, 2, ss_a | SUBSEQ_B_RD);
-+ write_subseq(channel, 3, ss_b | SUBSEQ_B_WR_RD);
-+ break;
-+ default:
-+ write_subseq(channel, 0, ss_a | SUBSEQ_B_WR);
-+ write_subseq(channel, 1, ss_a | SUBSEQ_B_RD);
-+ break;
-+ }
-+}
-+
-+void setup_io_test(
-+ struct sysinfo *ctrl,
-+ const uint8_t chanmask,
-+ const enum reut_cmd_pat cmd_pat,
-+ const uint16_t num_cl,
-+ const uint8_t lc,
-+ const struct reut_box *const reut_addr,
-+ const enum test_stop soe,
-+ const struct wdb_pat *const pat,
-+ const uint8_t en_cadb,
-+ const uint8_t subseq_wait)
-+{
-+ if (!chanmask) {
-+ printk(BIOS_ERR, "\n%s: chanmask is invalid\n", __func__);
-+ return;
-+ }
-+
-+ /*
-+ * Prepare variables needed for both channels.
-+ * Check for the cases where this MUST be 1: when
-+ * we manually walk through subseq ODT and TA Wr.
-+ */
-+ uint8_t lc_exp = MAX(lc - log2_ceil(num_cl), 0);
-+ if (cmd_pat == PAT_WR_RD_TA || cmd_pat == PAT_ODT_TA)
-+ lc_exp = 0;
-+
-+ uint8_t num_clcr;
-+ if (num_cl > 127) {
-+ /* Assume exponential number */
-+ num_clcr = log2_ceil(num_cl);
-+ } else {
-+ /* Set number of cache lines as linear number */
-+ num_clcr = num_cl | BIT(7);
-+ }
-+
-+ const uint16_t num_cl2 = 2 * num_cl;
-+ uint8_t num_cl2cr;
-+ if (num_cl2 > 127) {
-+ /* Assume exponential number */
-+ num_cl2cr = log2_ceil(num_cl2);
-+ } else {
-+ /* Set number of cache lines as linear number */
-+ num_cl2cr = num_cl2 | BIT(7);
-+ }
-+
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!(chanmask & BIT(channel))) {
-+ union reut_seq_cfg_reg reut_seq_cfg = {
-+ .raw = mchbar_read64(REUT_ch_SEQ_CFG(channel)),
-+ };
-+ reut_seq_cfg.global_control = 0;
-+ mchbar_write64(REUT_ch_SEQ_CFG(channel), reut_seq_cfg.raw);
-+ continue;
-+ }
-+
-+ /*
-+ * Program CADB
-+ */
-+ mchbar_write8(REUT_ch_MISC_PAT_CADB_CTRL(channel), !!en_cadb);
-+ if (en_cadb)
-+ setup_cadb(ctrl, channel, 7, 8);
-+
-+ /*
-+ * Program sequence
-+ */
-+ uint8_t subseq_start = 0;
-+ uint8_t subseq_end = 0;
-+ switch (cmd_pat) {
-+ case PAT_WR_RD:
-+ subseq_end = 1;
-+ break;
-+ case PAT_WR:
-+ break;
-+ case PAT_RD:
-+ subseq_start = 1;
-+ subseq_end = 1;
-+ break;
-+ case PAT_RD_WR_TA:
-+ break;
-+ case PAT_WR_RD_TA:
-+ subseq_end = 7;
-+ break;
-+ case PAT_ODT_TA:
-+ subseq_end = 3;
-+ break;
-+ default:
-+ die("\n%s: Pattern type %u is invalid\n", __func__, cmd_pat);
-+ }
-+ const union reut_seq_cfg_reg reut_seq_cfg = {
-+ .global_control = 1,
-+ .initialization_mode = REUT_MODE_TEST,
-+ .subsequence_start_pointer = subseq_start,
-+ .subsequence_end_pointer = subseq_end,
-+ .start_test_delay = 2,
-+ };
-+ mchbar_write64(REUT_ch_SEQ_CFG(channel), reut_seq_cfg.raw);
-+ program_loop_count(ctrl, channel, lc_exp);
-+ mchbar_write32(REUT_ch_SEQ_CTL(channel), (union reut_seq_ctl_reg) {
-+ .clear_errors = 1,
-+ }.raw);
-+
-+ /*
-+ * Program subsequences
-+ */
-+ uint32_t subseq_a = 0;
-+
-+ /* Number of cachelines and scale */
-+ subseq_a |= (num_clcr & 0x00ff) << 0;
-+ subseq_a |= (subseq_wait & 0x3fff) << 8;
-+
-+ /* Reset current base address to start */
-+ subseq_a |= BIT(27);
-+
-+ uint32_t subseq_b = 0;
-+
-+ /* Number of cachelines and scale */
-+ subseq_b |= (num_cl2cr & 0x00ff) << 0;
-+ subseq_b |= (subseq_wait & 0x3fff) << 8;
-+
-+ /* Reset current base address to start */
-+ subseq_b |= BIT(27);
-+
-+ program_subseq(ctrl, channel, cmd_pat, subseq_a, subseq_b);
-+
-+ /* Program sequence address */
-+ program_seq_addr(channel, reut_addr, false);
-+
-+ /* Program WDB */
-+ const bool is_linear = pat->inc_rate < 32;
-+ mchbar_write32(REUT_ch_WDB_CL_CTRL(channel), (union reut_pat_wdb_cl_ctrl_reg) {
-+ .start_ptr = pat->start_ptr,
-+ .end_ptr = pat->stop_ptr,
-+ .inc_rate = is_linear ? pat->inc_rate : log2_ceil(pat->inc_rate),
-+ .inc_scale = is_linear,
-+ }.raw);
-+
-+ /* Enable LMN in LMN or CADB modes, used to create lots of supply noise */
-+ const bool use_lmn = pat->dq_pattern == LMN_VA || pat->dq_pattern == CADB;
-+ union reut_pat_wdb_cl_mux_cfg_reg pat_wdb_cl_mux_cfg = {
-+ .mux_0_control = use_lmn ? REUT_MUX_LMN : REUT_MUX_LFSR,
-+ .mux_1_control = REUT_MUX_LFSR,
-+ .mux_2_control = REUT_MUX_LFSR,
-+ .ecc_data_source_sel = 1,
-+ };
-+
-+ /* Program LFSR save/restore, too complex unless everything is power of 2 */
-+ if (cmd_pat == PAT_ODT_TA || cmd_pat == PAT_WR_RD_TA) {
-+ pat_wdb_cl_mux_cfg.reload_lfsr_seed_rate = log2_ceil(num_cl) + 1;
-+ pat_wdb_cl_mux_cfg.save_lfsr_seed_rate = 1;
-+ }
-+ mchbar_write32(REUT_ch_PAT_WDB_CL_MUX_CFG(channel), pat_wdb_cl_mux_cfg.raw);
-+
-+ /* Inversion mask is not used */
-+ mchbar_write32(REUT_ch_PAT_WDB_INV(channel), 0);
-+
-+ /* Program error checking */
-+ const union reut_err_ctl_reg reut_err_ctl = {
-+ .selective_err_enable_cacheline = 0xff,
-+ .selective_err_enable_chunk = 0xff,
-+ .stop_on_error_control = soe,
-+ .stop_on_nth_error = 1,
-+ };
-+ mchbar_write32(REUT_ch_ERR_CONTROL(channel), reut_err_ctl.raw);
-+ mchbar_write64(REUT_ch_ERR_DATA_MASK(channel), 0);
-+ mchbar_write8(REUT_ch_ERR_ECC_MASK(channel), 0);
-+ }
-+
-+ /* Always do a ZQ short before the beginning of a test */
-+ reut_issue_zq(ctrl, chanmask, ZQ_SHORT);
-+}
-+
-+void setup_io_test_cadb(
-+ struct sysinfo *ctrl,
-+ const uint8_t chanmask,
-+ const uint8_t lc,
-+ const enum test_stop soe)
-+{
-+ const struct reut_box reut_addr = {
-+ .rank = {
-+ .start = 0,
-+ .stop = 0,
-+ .inc_rate = 32,
-+ .inc_val = 1,
-+ },
-+ .bank = {
-+ .start = 0,
-+ .stop = 7,
-+ .inc_rate = 3,
-+ .inc_val = 1,
-+ },
-+ .row = {
-+ .start = 0,
-+ .stop = 2047,
-+ .inc_rate = 3,
-+ .inc_val = 73,
-+ },
-+ .col = {
-+ .start = 0,
-+ .stop = 1023,
-+ .inc_rate = 0,
-+ .inc_val = 53,
-+ },
-+ };
-+ const struct wdb_pat pattern = {
-+ .start_ptr = 0,
-+ .stop_ptr = 9,
-+ .inc_rate = 4,
-+ .dq_pattern = CADB,
-+ };
-+ setup_io_test(
-+ ctrl,
-+ chanmask,
-+ PAT_WR_RD,
-+ 128,
-+ lc,
-+ &reut_addr,
-+ soe,
-+ &pattern,
-+ 1,
-+ 0);
-+
-+ ctrl->dq_pat_lc = MAX(lc - 2 - 3, 0) + 1;
-+ ctrl->dq_pat = CADB;
-+}
-+
-+void setup_io_test_basic_va(
-+ struct sysinfo *ctrl,
-+ const uint8_t chanmask,
-+ const uint8_t lc,
-+ const enum test_stop soe)
-+{
-+ const uint32_t spread = 8;
-+ const struct reut_box reut_addr = {
-+ .rank = {
-+ .start = 0,
-+ .stop = 0,
-+ .inc_rate = 32,
-+ .inc_val = 1,
-+ },
-+ .col = {
-+ .start = 0,
-+ .stop = 1023,
-+ .inc_rate = 0,
-+ .inc_val = 1,
-+ },
-+ };
-+ const struct wdb_pat pattern = {
-+ .start_ptr = 0,
-+ .stop_ptr = spread - 1,
-+ .inc_rate = 4,
-+ .dq_pattern = BASIC_VA,
-+ };
-+ setup_io_test(
-+ ctrl,
-+ chanmask,
-+ PAT_WR_RD,
-+ 128,
-+ lc,
-+ &reut_addr,
-+ soe,
-+ &pattern,
-+ 0,
-+ 0);
-+
-+ ctrl->dq_pat_lc = MAX(lc - 8, 0) + 1;
-+ ctrl->dq_pat = BASIC_VA;
-+}
-+
-+void setup_io_test_mpr(
-+ struct sysinfo *ctrl,
-+ const uint8_t chanmask,
-+ const uint8_t lc,
-+ const enum test_stop soe)
-+{
-+ const struct reut_box reut_addr_ddr = {
-+ .rank = {
-+ .start = 0,
-+ .stop = 0,
-+ .inc_rate = 32,
-+ .inc_val = 1,
-+ },
-+ .col = {
-+ .start = 0,
-+ .stop = 1023,
-+ .inc_rate = 0,
-+ .inc_val = 1,
-+ },
-+ };
-+ const struct reut_box reut_addr_lpddr = {
-+ .bank = {
-+ .start = 4,
-+ .stop = 4,
-+ .inc_rate = 0,
-+ .inc_val = 0,
-+ },
-+ };
-+ const struct wdb_pat pattern = {
-+ .start_ptr = 0,
-+ .stop_ptr = 9,
-+ .inc_rate = 4,
-+ .dq_pattern = BASIC_VA,
-+ };
-+ setup_io_test(
-+ ctrl,
-+ chanmask,
-+ PAT_RD,
-+ 128,
-+ lc,
-+ ctrl->lpddr ? &reut_addr_lpddr : &reut_addr_ddr,
-+ soe,
-+ &pattern,
-+ 0,
-+ 0);
-+
-+ ctrl->dq_pat_lc = 1;
-+ ctrl->dq_pat = BASIC_VA;
-+}
-+
-+uint8_t select_reut_ranks(struct sysinfo *ctrl, const uint8_t channel, uint8_t rankmask)
-+{
-+ rankmask &= ctrl->rankmap[channel];
-+
-+ uint8_t rank_count = 0;
-+ uint32_t rank_log_to_phys = 0;
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (!rank_in_mask(rank, rankmask))
-+ continue;
-+
-+ rank_log_to_phys |= rank << (4 * rank_count);
-+ rank_count++;
-+ }
-+ mchbar_write32(REUT_ch_RANK_LOG_TO_PHYS(channel), rank_log_to_phys);
-+
-+ union reut_seq_cfg_reg reut_seq_cfg = {
-+ .raw = mchbar_read64(REUT_ch_SEQ_CFG(channel)),
-+ };
-+ if (!rank_count) {
-+ reut_seq_cfg.global_control = 0;
-+ mchbar_write64(REUT_ch_SEQ_CFG(channel), reut_seq_cfg.raw);
-+ return 0;
-+ }
-+ union reut_seq_base_addr_reg reut_seq_addr_stop = {
-+ .raw = mchbar_read64(REUT_ch_SEQ_ADDR_WRAP(channel)),
-+ };
-+ reut_seq_addr_stop.rank_addr = rank_count - 1;
-+ mchbar_write64(REUT_ch_SEQ_ADDR_WRAP(channel), reut_seq_addr_stop.raw);
-+
-+ reut_seq_cfg.global_control = 1;
-+ mchbar_write64(REUT_ch_SEQ_CFG(channel), reut_seq_cfg.raw);
-+ return BIT(channel);
-+}
-+
-+void run_mpr_io_test(const bool clear_errors)
-+{
-+ io_reset();
-+ mchbar_write32(REUT_GLOBAL_CTL, (union reut_seq_ctl_reg) {
-+ .start_test = 1,
-+ .clear_errors = clear_errors,
-+ }.raw);
-+ tick_delay(2);
-+ io_reset();
-+ tick_delay(2);
-+ mchbar_write32(REUT_GLOBAL_CTL, (union reut_seq_ctl_reg) {
-+ .stop_test = 1,
-+ }.raw);
-+}
-+
-+static uint8_t get_num_tests(const uint8_t dq_pat)
-+{
-+ switch (dq_pat) {
-+ case SEGMENT_WDB: return 4;
-+ case CADB: return 7;
-+ case TURN_AROUND_WR: return 8;
-+ case TURN_AROUND_ODT: return 4;
-+ case RD_RD_TA: return 2;
-+ case RD_RD_TA_ALL: return 8;
-+ default: return 1;
-+ }
-+}
-+
-+uint8_t run_io_test(
-+ struct sysinfo *const ctrl,
-+ const uint8_t chanmask,
-+ const uint8_t dq_pat,
-+ const bool clear_errors)
-+{
-+ /* SEGMENT_WDB only runs 4 tests */
-+ const uint8_t segment_wdb_lc[4] = { 0, 0, 4, 2 };
-+ const union reut_pat_wdb_cl_ctrl_reg pat_wdb_cl[4] = {
-+ [0] = {
-+ .start_ptr = 0,
-+ .end_ptr = 9,
-+ .inc_rate = 25,
-+ .inc_scale = SCALE_LINEAR,
-+ },
-+ [1] = {
-+ .start_ptr = 0,
-+ .end_ptr = 9,
-+ .inc_rate = 25,
-+ .inc_scale = SCALE_LINEAR,
-+ },
-+ [2] = {
-+ .start_ptr = 10,
-+ .end_ptr = 63,
-+ .inc_rate = 19,
-+ .inc_scale = SCALE_LINEAR,
-+ },
-+ [3] = {
-+ .start_ptr = 10,
-+ .end_ptr = 63,
-+ .inc_rate = 10,
-+ .inc_scale = SCALE_LINEAR,
-+ },
-+ };
-+ const bool is_turnaround = dq_pat == RD_RD_TA || dq_pat == RD_RD_TA_ALL;
-+ const uint8_t num_tests = get_num_tests(dq_pat);
-+ union tc_bank_rank_a_reg tc_bank_rank_a[NUM_CHANNELS] = { 0 };
-+ if (is_turnaround) {
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!(chanmask & BIT(channel)))
-+ continue;
-+
-+ tc_bank_rank_a[channel].raw = ctrl->tc_bankrank_a[channel].raw;
-+ }
-+ }
-+ for (uint8_t t = 0; t < num_tests; t++) {
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!(chanmask & BIT(channel)))
-+ continue;
-+
-+ if (dq_pat == SEGMENT_WDB) {
-+ mchbar_write32(REUT_ch_WDB_CL_CTRL(channel), pat_wdb_cl[t].raw);
-+ /*
-+ * Skip programming LFSR save/restore. Too complex
-+ * unless power of 2. Program desired loopcount.
-+ */
-+ const uint8_t pat_lc = ctrl->dq_pat_lc + segment_wdb_lc[t];
-+ program_loop_count(ctrl, channel, pat_lc);
-+ } else if (dq_pat == CADB) {
-+ setup_cadb(ctrl, channel, num_tests, t);
-+ } else if (dq_pat == TURN_AROUND_WR || dq_pat == TURN_AROUND_ODT) {
-+ union reut_seq_cfg_reg reut_seq_cfg = {
-+ .raw = mchbar_read64(REUT_ch_SEQ_CFG(channel)),
-+ };
-+ reut_seq_cfg.subsequence_start_pointer = t;
-+ reut_seq_cfg.subsequence_end_pointer = t;
-+ mchbar_write64(REUT_ch_SEQ_CFG(channel), reut_seq_cfg.raw);
-+ union reut_seq_addr_inc_ctl_reg addr_inc_ctl = {
-+ .raw = mchbar_read64(REUT_ch_SEQ_ADDR_INC_CTL(channel)),
-+ };
-+ uint8_t ta_inc_rate = 1;
-+ if (dq_pat == TURN_AROUND_WR && (t == 0 || t == 7))
-+ ta_inc_rate = 0;
-+ else if (dq_pat == TURN_AROUND_ODT && (t == 0 || t == 2))
-+ ta_inc_rate = 0;
-+
-+ /* Program increment rate as linear value */
-+ addr_inc_ctl.rank_addr_update = BIT(7) | ta_inc_rate;
-+ addr_inc_ctl.col_addr_update = BIT(7) | ta_inc_rate;
-+ mchbar_write64(REUT_ch_SEQ_ADDR_INC_CTL(channel),
-+ addr_inc_ctl.raw);
-+ } else if (dq_pat == RD_RD_TA) {
-+ tc_bank_rank_a[channel].tRDRD_sr = (t == 0) ? 4 : 5;
-+ mchbar_write32(TC_BANK_RANK_A_ch(channel),
-+ tc_bank_rank_a[channel].raw);
-+ } else if (dq_pat == RD_RD_TA_ALL) {
-+ /*
-+ * Program tRDRD for SR and DR. Run 8 tests, covering
-+ * tRDRD_sr = 4, 5, 6, 7 and tRDRD_dr = min, +1, +2, +3
-+ */
-+ const uint32_t tRDRD_dr = ctrl->tc_bankrank_a[channel].tRDRD_dr;
-+ tc_bank_rank_a[channel].tRDRD_sr = (t % 4) + 4;
-+ tc_bank_rank_a[channel].tRDRD_dr = (t % 4) + tRDRD_dr;
-+ mchbar_write32(TC_BANK_RANK_A_ch(channel),
-+ tc_bank_rank_a[channel].raw);
-+
-+ /* Program linear rank increment rate */
-+ union reut_seq_addr_inc_ctl_reg addr_inc_ctl = {
-+ .raw = mchbar_read64(REUT_ch_SEQ_ADDR_INC_CTL(channel)),
-+ };
-+ addr_inc_ctl.rank_addr_update = BIT(7) | (t / 4) ? 0 : 31;
-+ mchbar_write64(REUT_ch_SEQ_ADDR_INC_CTL(channel),
-+ addr_inc_ctl.raw);
-+ }
-+ }
-+ bool test_soe = false;
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!(chanmask & BIT(channel)))
-+ continue;
-+
-+ const union reut_err_ctl_reg reut_err_ctl = {
-+ .raw = mchbar_read32(REUT_ch_ERR_CONTROL(channel)),
-+ };
-+ const uint8_t soe = reut_err_ctl.stop_on_error_control;
-+ if (soe != NSOE) {
-+ test_soe = true;
-+ break;
-+ }
-+ }
-+ io_reset();
-+ mchbar_write32(REUT_GLOBAL_CTL, (union reut_seq_ctl_reg) {
-+ .start_test = 1,
-+ .clear_errors = clear_errors && t == 0,
-+ }.raw);
-+ struct mono_time prev, curr;
-+ timer_monotonic_get(&prev);
-+ union reut_global_err_reg global_err;
-+ do {
-+ global_err.raw = mchbar_read32(REUT_GLOBAL_ERR);
-+ /** TODO: Clean up this mess **/
-+ timer_monotonic_get(&curr);
-+ if (mono_time_diff_microseconds(&prev, &curr) > 1000 * 1000) {
-+ mchbar_write32(REUT_GLOBAL_CTL, (union reut_seq_ctl_reg) {
-+ .stop_test = 1,
-+ }.raw);
-+ printk(BIOS_ERR, "REUT timed out, ch_done: %x\n",
-+ global_err.ch_test_done);
-+ break;
-+ }
-+ } while ((global_err.ch_test_done & chanmask) != chanmask);
-+ if (test_soe && global_err.ch_error & chanmask)
-+ break;
-+ }
-+ if (is_turnaround) {
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!(chanmask & BIT(channel)))
-+ continue;
-+
-+ mchbar_write32(TC_BANK_RANK_A_ch(channel),
-+ ctrl->tc_bankrank_a[channel].raw);
-+ }
-+ }
-+ return ((union reut_global_err_reg)mchbar_read32(REUT_GLOBAL_ERR)).ch_error;
-+}
-diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
-index f8408e51a0..817a9f8bf8 100644
---- a/src/northbridge/intel/haswell/registers/mchbar.h
-+++ b/src/northbridge/intel/haswell/registers/mchbar.h
-@@ -94,20 +94,35 @@
- #define TC_BANK_RANK_D_ch(ch) _MCMAIN_C(0x4014, ch)
- #define SC_ROUNDT_LAT_ch(ch) _MCMAIN_C(0x4024, ch)
-
-+#define REUT_ch_PAT_WDB_CL_MUX_CFG(ch) _MCMAIN_C(0x4040, ch)
-+
- #define REUT_ch_PAT_WDB_CL_MUX_WR_x(ch, x) _MCMAIN_C_X(0x4048, ch, x) /* x in 0 .. 2 */
- #define REUT_ch_PAT_WDB_CL_MUX_RD_x(ch, x) _MCMAIN_C_X(0x4054, ch, x) /* x in 0 .. 2 */
-
- #define REUT_ch_PAT_WDB_CL_MUX_LMN(ch) _MCMAIN_C(0x4078, ch)
-
-+#define REUT_ch_PAT_WDB_INV(ch) _MCMAIN_C(0x4084, ch)
-+
-+#define REUT_ch_ERR_CONTROL(ch) _MCMAIN_C(0x4098, ch)
-+#define REUT_ch_ERR_ECC_MASK(ch) _MCMAIN_C(0x409c, ch)
-+
- #define SC_WR_ADD_DELAY_ch(ch) _MCMAIN_C(0x40d0, ch)
-
-+#define REUT_ch_ERR_DATA_MASK(ch) _MCMAIN_C(0x40d8, ch)
-+
- #define REUT_ch_MISC_CKE_CTRL(ch) _MCMAIN_C(0x4190, ch)
-
-+#define REUT_ch_MISC_PAT_CADB_CTRL(ch) _MCMAIN_C(0x4198, ch)
- #define REUT_ch_PAT_CADB_MRS(ch) _MCMAIN_C(0x419c, ch)
-+#define REUT_ch_PAT_CADB_MUX_CTRL(ch) _MCMAIN_C(0x41a0, ch)
-+#define REUT_ch_PAT_CADB_MUX_x(ch, x) _MCMAIN_C_X(0x41a4, ch, x) /* x in 0 .. 2 */
-
-+#define REUT_ch_PAT_CADB_CL_MUX_LMN(ch) _MCMAIN_C(0x41b0, ch)
- #define REUT_ch_PAT_CADB_WRITE_PTR(ch) _MCMAIN_C(0x41bc, ch)
- #define REUT_ch_PAT_CADB_PROG(ch) _MCMAIN_C(0x41c0, ch)
-
-+#define REUT_ch_WDB_CL_CTRL(ch) _MCMAIN_C(0x4200, ch)
-+
- #define TC_ZQCAL_ch(ch) _MCMAIN_C(0x4290, ch)
- #define TC_RFP_ch(ch) _MCMAIN_C(0x4294, ch)
- #define TC_RFTP_ch(ch) _MCMAIN_C(0x4298, ch)
-@@ -119,12 +134,27 @@
- #define QCLK_ch_LDAT_SDAT(ch) _MCMAIN_C(0x42d4, ch)
- #define QCLK_ch_LDAT_DATA_IN_x(ch, x) _MCMAIN_C_X(0x42dc, ch, x) /* x in 0 .. 1 */
-
-+#define REUT_GLOBAL_CTL 0x4800
- #define REUT_GLOBAL_ERR 0x4804
-
-+#define REUT_ch_SUBSEQ_x_CTL(ch, x) (0x4808 + 40 * (ch) + 4 * (x))
-+
- #define REUT_ch_SEQ_CFG(ch) (0x48a8 + 8 * (ch))
-
- #define REUT_ch_SEQ_CTL(ch) (0x48b8 + 4 * (ch))
-
-+#define REUT_ch_SEQ_ADDR_START(ch) (0x48d8 + 8 * (ch))
-+
-+#define REUT_ch_SEQ_ADDR_WRAP(ch) (0x48e8 + 8 * (ch))
-+
-+#define REUT_ch_SEQ_MISC_CTL(ch) (0x4908 + 4 * (ch))
-+
-+#define REUT_ch_SEQ_ADDR_INC_CTL(ch) (0x4910 + 8 * (ch))
-+
-+#define REUT_ch_RANK_LOG_TO_PHYS(ch) (0x4930 + 4 * (ch)) /* 4 bits per rank */
-+
-+#define HSW_REUT_ch_SEQ_LOOP_COUNT(ch) (0x4980 + 4 * (ch)) /* *** only on C0 *** */
-+
- /* MCMAIN broadcast */
- #define MCSCHEDS_CBIT 0x4c20
-
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0038-do-not-break-building-other-thinkpads-with-the-hacks.patch b/config/coreboot/default/patches/0038-do-not-break-building-other-thinkpads-with-the-hacks.patch
new file mode 100644
index 00000000..87cde056
--- /dev/null
+++ b/config/coreboot/default/patches/0038-do-not-break-building-other-thinkpads-with-the-hacks.patch
@@ -0,0 +1,153 @@
+From 49204919e885dca2be45ffbaf2f5af62109ec3a7 Mon Sep 17 00:00:00 2001
+From: gaspar-ilom <gasparilom@riseup.net>
+Date: Thu, 6 Mar 2025 23:00:00 +0000
+Subject: [PATCH 1/1] do not break building other thinkpads with the hacks for
+ the t480/s made Mate Kukri
+
+still not fixing things properly but at least it should now be possible to build older thinkpads without regressions.
+prior, some code was just commented or unreachable. now we make this explicit with preprocessor directives.
+heads should build all boards on this coreboot version from the same coreboot tree.
+
+Signed-off-by: gaspar-ilom <gasparilom@riseup.net>
+---
+ src/device/pci_rom.c | 9 ++++++---
+ src/ec/lenovo/h8/acpi/ec.asl | 4 +++-
+ src/ec/lenovo/h8/bluetooth.c | 14 ++++++++++----
+ src/ec/lenovo/h8/wwan.c | 14 ++++++++++----
+ 4 files changed, 29 insertions(+), 12 deletions(-)
+
+diff --git a/src/device/pci_rom.c b/src/device/pci_rom.c
+index bba98d9dea..db3dbbe2ce 100644
+--- a/src/device/pci_rom.c
++++ b/src/device/pci_rom.c
+@@ -396,16 +396,19 @@ void pci_rom_ssdt(const struct device *device)
+ rom = cbrom;
+ }
+
+-#if 0
++
++ #if CONFIG(BOARD_LENOVO_SKLKBL_THINKPAD_COMMON)
++ const char *scope = "\\_SB.PCI0.RP01.PEGP";
++ #else
+ const char *scope = acpi_device_path(device);
++ #endif
+ if (!scope) {
+ printk(BIOS_ERR, "%s: Missing ACPI scope\n", dev_path(device));
+ return;
+ }
+-#endif
+
+ /* write _ROM method */
+- acpigen_write_scope("\\_SB.PCI0.RP01.PEGP");
++ acpigen_write_scope(scope);
+ acpigen_write_rom((void *)rom, rom->size * 512);
+ acpigen_pop_len(); /* pop scope */
+ }
+diff --git a/src/ec/lenovo/h8/acpi/ec.asl b/src/ec/lenovo/h8/acpi/ec.asl
+index 8f4a8e1986..f80c15106c 100644
+--- a/src/ec/lenovo/h8/acpi/ec.asl
++++ b/src/ec/lenovo/h8/acpi/ec.asl
+@@ -331,7 +331,9 @@ Device(EC)
+ #include "sleepbutton.asl"
+ #include "lid.asl"
+ #include "beep.asl"
+-//#include "thermal.asl"
++#if !CONFIG(BOARD_LENOVO_SKLKBL_THINKPAD_COMMON)
++#include "thermal.asl"
++#endif
+ #include "systemstatus.asl"
+ #include "thinkpad.asl"
+ }
+diff --git a/src/ec/lenovo/h8/bluetooth.c b/src/ec/lenovo/h8/bluetooth.c
+index be71a24ced..e60b6c088c 100644
+--- a/src/ec/lenovo/h8/bluetooth.c
++++ b/src/ec/lenovo/h8/bluetooth.c
+@@ -1,6 +1,8 @@
+ /* SPDX-License-Identifier: GPL-2.0-only */
+
+-// #include <southbridge/intel/common/gpio.h>
++#if !CONFIG(BOARD_LENOVO_SKLKBL_THINKPAD_COMMON)
++#include <southbridge/intel/common/gpio.h>
++#endif
+ #include <console/console.h>
+ #include <device/device.h>
+ #include <ec/acpi/ec.h>
+@@ -26,23 +28,27 @@ void h8_bluetooth_enable(int on)
+ */
+ bool h8_has_bdc(const struct device *dev)
+ {
++ #if CONFIG(BOARD_LENOVO_SKLKBL_THINKPAD_COMMON)
++ printk(BIOS_INFO, "H8: BDC detection not implemented. "
++ "Assuming BDC installed\n");
++ return true;
++ #else
+ struct ec_lenovo_h8_config *conf = dev->chip_info;
+
+- if (1 || !conf->has_bdc_detection) {
++ if (!conf->has_bdc_detection) {
+ printk(BIOS_INFO, "H8: BDC detection not implemented. "
+ "Assuming BDC installed\n");
+ return true;
+ }
+
+-#if 0
+ if (get_gpio(conf->bdc_gpio_num) == conf->bdc_gpio_lvl) {
+ printk(BIOS_INFO, "H8: BDC installed\n");
+ return true;
+ }
+-#endif
+
+ printk(BIOS_INFO, "H8: BDC not installed\n");
+ return false;
++ #endif
+ }
+
+ /*
+diff --git a/src/ec/lenovo/h8/wwan.c b/src/ec/lenovo/h8/wwan.c
+index 5cdcf77406..b4f5787e01 100644
+--- a/src/ec/lenovo/h8/wwan.c
++++ b/src/ec/lenovo/h8/wwan.c
+@@ -1,6 +1,8 @@
+ /* SPDX-License-Identifier: GPL-2.0-only */
+
+-// #include <southbridge/intel/common/gpio.h>
++#if !CONFIG(BOARD_LENOVO_SKLKBL_THINKPAD_COMMON)
++#include <southbridge/intel/common/gpio.h>
++#endif
+ #include <console/console.h>
+ #include <device/device.h>
+ #include <ec/acpi/ec.h>
+@@ -24,23 +26,27 @@ void h8_wwan_enable(int on)
+ */
+ bool h8_has_wwan(const struct device *dev)
+ {
++ #if CONFIG(BOARD_LENOVO_SKLKBL_THINKPAD_COMMON)
++ printk(BIOS_INFO, "H8: WWAN detection not implemented. "
++ "Assuming WWAN installed\n");
++ return true;
++ #else
+ struct ec_lenovo_h8_config *conf = dev->chip_info;
+
+- if (1 || !conf->has_wwan_detection) {
++ if (!conf->has_wwan_detection) {
+ printk(BIOS_INFO, "H8: WWAN detection not implemented. "
+ "Assuming WWAN installed\n");
+ return true;
+ }
+
+-#if 0
+ if (get_gpio(conf->wwan_gpio_num) == conf->wwan_gpio_lvl) {
+ printk(BIOS_INFO, "H8: WWAN installed\n");
+ return true;
+ }
+-#endif
+
+ printk(BIOS_INFO, "H8: WWAN not installed\n");
+ return false;
++ #endif
+ }
+
+ /*
+--
+2.39.5
+
diff --git a/config/coreboot/default/patches/0038-haswell-NRI-Add-range-tracking-library.patch b/config/coreboot/default/patches/0038-haswell-NRI-Add-range-tracking-library.patch
deleted file mode 100644
index 45fdc951..00000000
--- a/config/coreboot/default/patches/0038-haswell-NRI-Add-range-tracking-library.patch
+++ /dev/null
@@ -1,222 +0,0 @@
-From 36b206a88281796458e6ebc30fe34a7c51c86548 Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Sun, 8 May 2022 00:56:00 +0200
-Subject: [PATCH 38/51] haswell NRI: Add range tracking library
-
-Implement a small library used to keep track of passing ranges. This
-will be used by 1D training algorithms when margining some parameter.
-
-Change-Id: I8718e85165160afd7c0c8e730b5ce6c9c00f8a60
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../intel/haswell/native_raminit/Makefile.mk | 1 +
- .../intel/haswell/native_raminit/ranges.c | 109 ++++++++++++++++++
- .../intel/haswell/native_raminit/ranges.h | 68 +++++++++++
- 3 files changed, 178 insertions(+)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/ranges.c
- create mode 100644 src/northbridge/intel/haswell/native_raminit/ranges.h
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-index 6e1b365602..2da950771d 100644
---- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-@@ -9,6 +9,7 @@ romstage-y += io_comp_control.c
- romstage-y += memory_map.c
- romstage-y += raminit_main.c
- romstage-y += raminit_native.c
-+romstage-y += ranges.c
- romstage-y += reut.c
- romstage-y += setup_wdb.c
- romstage-y += spd_bitmunching.c
-diff --git a/src/northbridge/intel/haswell/native_raminit/ranges.c b/src/northbridge/intel/haswell/native_raminit/ranges.c
-new file mode 100644
-index 0000000000..cdebc1fa66
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/ranges.c
-@@ -0,0 +1,109 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <types.h>
-+
-+#include "ranges.h"
-+
-+void linear_record_pass(
-+ struct linear_train_data *const data,
-+ const bool pass,
-+ const int32_t value,
-+ const int32_t start,
-+ const int32_t step)
-+{
-+ /* If this is the first time, initialize all values */
-+ if (value == start) {
-+ /*
-+ * If value passed, create a zero-length region for the current value,
-+ * which may be extended as long as the successive values are passing.
-+ *
-+ * Otherwise, create a zero-length range for the preceding value. This
-+ * range cannot be extended by other passing values, which is desired.
-+ */
-+ data->current.start = start - (pass ? 0 : step);
-+ data->current.end = data->current.start;
-+ data->largest = data->current;
-+ } else if (pass) {
-+ /* If this pass is not contiguous, it belongs to a new region */
-+ if (data->current.end != (value - step))
-+ data->current.start = value;
-+
-+ /* Update end of current region */
-+ data->current.end = value;
-+
-+ /* Update largest region */
-+ if (range_width(data->current) > range_width(data->largest))
-+ data->largest = data->current;
-+ }
-+}
-+
-+void phase_record_pass(
-+ struct phase_train_data *const data,
-+ const bool pass,
-+ const int32_t value,
-+ const int32_t start,
-+ const int32_t step)
-+{
-+ /* If this is the first time, initialize all values */
-+ if (value == start) {
-+ /*
-+ * If value passed, create a zero-length region for the current value,
-+ * which may be extended as long as the successive values are passing.
-+ *
-+ * Otherwise, create a zero-length range for the preceding value. This
-+ * range cannot be extended by other passing values, which is desired.
-+ */
-+ data->current.start = start - (pass ? 0 : step);
-+ data->current.end = data->current.start;
-+ data->largest = data->current;
-+ data->initial = data->current;
-+ return;
-+ }
-+ if (!pass)
-+ return;
-+
-+ /* Update initial region */
-+ if (data->initial.end == (value - step))
-+ data->initial.end = value;
-+
-+ /* If this pass is not contiguous, it belongs to a new region */
-+ if (data->current.end != (value - step))
-+ data->current.start = value;
-+
-+ /* Update end of current region */
-+ data->current.end = value;
-+
-+ /* Update largest region */
-+ if (range_width(data->current) > range_width(data->largest))
-+ data->largest = data->current;
-+}
-+
-+void phase_append_initial_to_current(
-+ struct phase_train_data *const data,
-+ const int32_t start,
-+ const int32_t step)
-+{
-+ /* If initial region is valid and does not overlap, append it */
-+ if (data->initial.start == start && data->initial.end != data->current.end)
-+ data->current.end += step + range_width(data->initial);
-+
-+ /* Update largest region */
-+ if (range_width(data->current) > range_width(data->largest))
-+ data->largest = data->current;
-+}
-+
-+void phase_append_current_to_initial(
-+ struct phase_train_data *const data,
-+ const int32_t start,
-+ const int32_t step)
-+{
-+ /* If initial region is valid and does not overlap, append it */
-+ if (data->initial.start == start && data->initial.end != data->current.end) {
-+ data->initial.start -= (step + range_width(data->current));
-+ data->current = data->initial;
-+ }
-+
-+ /* Update largest region */
-+ if (range_width(data->current) > range_width(data->largest))
-+ data->largest = data->current;
-+}
-diff --git a/src/northbridge/intel/haswell/native_raminit/ranges.h b/src/northbridge/intel/haswell/native_raminit/ranges.h
-new file mode 100644
-index 0000000000..235392df96
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/ranges.h
-@@ -0,0 +1,68 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#ifndef HASWELL_RAMINIT_RANGES_H
-+#define HASWELL_RAMINIT_RANGES_H
-+
-+#include <types.h>
-+
-+/*
-+ * Many algorithms shmoo some parameter to determine the largest passing
-+ * range. Provide a common implementation to avoid redundant boilerplate.
-+ */
-+struct passing_range {
-+ int32_t start;
-+ int32_t end;
-+};
-+
-+/* Structure for linear parameters, such as roundtrip delays */
-+struct linear_train_data {
-+ struct passing_range current;
-+ struct passing_range largest;
-+};
-+
-+/*
-+ * Phase ranges are "circular": the first and last indices are contiguous.
-+ * To correctly determine the largest passing range, one has to combine
-+ * the initial range and the current range when processing the last index.
-+ */
-+struct phase_train_data {
-+ struct passing_range initial;
-+ struct passing_range current;
-+ struct passing_range largest;
-+};
-+
-+static inline int32_t range_width(const struct passing_range range)
-+{
-+ return range.end - range.start;
-+}
-+
-+static inline int32_t range_center(const struct passing_range range)
-+{
-+ return range.start + range_width(range) / 2;
-+}
-+
-+void linear_record_pass(
-+ struct linear_train_data *data,
-+ bool pass,
-+ int32_t value,
-+ int32_t start,
-+ int32_t step);
-+
-+void phase_record_pass(
-+ struct phase_train_data *data,
-+ bool pass,
-+ int32_t value,
-+ int32_t start,
-+ int32_t step);
-+
-+void phase_append_initial_to_current(
-+ struct phase_train_data *data,
-+ int32_t start,
-+ int32_t step);
-+
-+void phase_append_current_to_initial(
-+ struct phase_train_data *data,
-+ int32_t start,
-+ int32_t step);
-+
-+#endif
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0039-haswell-NRI-Add-library-to-change-margins.patch b/config/coreboot/default/patches/0039-haswell-NRI-Add-library-to-change-margins.patch
deleted file mode 100644
index 401433ac..00000000
--- a/config/coreboot/default/patches/0039-haswell-NRI-Add-library-to-change-margins.patch
+++ /dev/null
@@ -1,294 +0,0 @@
-From 926b1af1033c26ad231587fd3a4506efb4b0d8a3 Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Sun, 8 May 2022 01:11:03 +0200
-Subject: [PATCH 39/51] haswell NRI: Add library to change margins
-
-Implement a library to change Rx/Tx margins. It will be expanded later.
-
-Change-Id: I0b55aba428d8b4d4e16d2fbdec57235ce3ce8adf
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../intel/haswell/native_raminit/Makefile.mk | 1 +
- .../haswell/native_raminit/change_margin.c | 154 ++++++++++++++++++
- .../haswell/native_raminit/raminit_native.h | 50 ++++++
- .../intel/haswell/registers/mchbar.h | 9 +
- 4 files changed, 214 insertions(+)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/change_margin.c
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-index 2da950771d..ebe9e9b762 100644
---- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-@@ -1,5 +1,6 @@
- ## SPDX-License-Identifier: GPL-2.0-or-later
-
-+romstage-y += change_margin.c
- romstage-y += configure_mc.c
- romstage-y += ddr3.c
- romstage-y += jedec_reset.c
-diff --git a/src/northbridge/intel/haswell/native_raminit/change_margin.c b/src/northbridge/intel/haswell/native_raminit/change_margin.c
-new file mode 100644
-index 0000000000..055c666eee
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/change_margin.c
-@@ -0,0 +1,154 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <commonlib/bsd/clamp.h>
-+#include <console/console.h>
-+#include <delay.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <timer.h>
-+
-+#include "raminit_native.h"
-+
-+void update_rxt(
-+ struct sysinfo *ctrl,
-+ const uint8_t channel,
-+ const uint8_t rank,
-+ const uint8_t byte,
-+ const enum rxt_subfield subfield,
-+ const int32_t value)
-+{
-+ union ddr_data_rx_train_rank_reg rxt = {
-+ .rcven = ctrl->rcven[channel][rank][byte],
-+ .dqs_p = ctrl->rxdqsp[channel][rank][byte],
-+ .rx_eq = ctrl->rx_eq[channel][rank][byte],
-+ .dqs_n = ctrl->rxdqsn[channel][rank][byte],
-+ .vref = ctrl->rxvref[channel][rank][byte],
-+ };
-+ int32_t new_value;
-+ switch (subfield) {
-+ case RXT_RCVEN:
-+ new_value = clamp_s32(0, value, 511);
-+ rxt.rcven = new_value;
-+ break;
-+ case RXT_RXDQS_P:
-+ new_value = clamp_s32(0, value, 63);
-+ rxt.dqs_p = new_value;
-+ break;
-+ case RXT_RX_EQ:
-+ new_value = clamp_s32(0, value, 31);
-+ rxt.rx_eq = new_value;
-+ break;
-+ case RXT_RXDQS_N:
-+ new_value = clamp_s32(0, value, 63);
-+ rxt.dqs_n = new_value;
-+ break;
-+ case RXT_RX_VREF:
-+ new_value = clamp_s32(-32, value, 31);
-+ rxt.vref = new_value;
-+ break;
-+ case RXT_RXDQS_BOTH:
-+ new_value = clamp_s32(0, value, 63);
-+ rxt.dqs_p = new_value;
-+ rxt.dqs_n = new_value;
-+ break;
-+ case RXT_RESTORE:
-+ new_value = value;
-+ break;
-+ default:
-+ die("%s: Unhandled subfield index %u\n", __func__, subfield);
-+ }
-+
-+ if (new_value != value) {
-+ printk(BIOS_ERR, "%s: Overflow for subfield %u: %d ---> %d\n",
-+ __func__, subfield, value, new_value);
-+ }
-+ mchbar_write32(RX_TRAIN_ch_r_b(channel, rank, byte), rxt.raw);
-+ download_regfile(ctrl, channel, false, rank, REG_FILE_USE_RANK, byte, true, false);
-+}
-+
-+void update_txt(
-+ struct sysinfo *ctrl,
-+ const uint8_t channel,
-+ const uint8_t rank,
-+ const uint8_t byte,
-+ const enum txt_subfield subfield,
-+ const int32_t value)
-+{
-+ union ddr_data_tx_train_rank_reg txt = {
-+ .dq_delay = ctrl->tx_dq[channel][rank][byte],
-+ .dqs_delay = ctrl->txdqs[channel][rank][byte],
-+ .tx_eq = ctrl->tx_eq[channel][rank][byte],
-+ };
-+ int32_t new_value;
-+ switch (subfield) {
-+ case TXT_TX_DQ:
-+ new_value = clamp_s32(0, value, 511);
-+ txt.dq_delay = new_value;
-+ break;
-+ case TXT_TXDQS:
-+ new_value = clamp_s32(0, value, 511);
-+ txt.dqs_delay = new_value;
-+ break;
-+ case TXT_TX_EQ:
-+ new_value = clamp_s32(0, value, 63);
-+ txt.tx_eq = new_value;
-+ break;
-+ case TXT_DQDQS_OFF:
-+ new_value = value;
-+ txt.dqs_delay += new_value;
-+ txt.dq_delay += new_value;
-+ break;
-+ case TXT_RESTORE:
-+ new_value = value;
-+ break;
-+ default:
-+ die("%s: Unhandled subfield index %u\n", __func__, subfield);
-+ }
-+ if (new_value != value) {
-+ printk(BIOS_ERR, "%s: Overflow for subfield %u: %d ---> %d\n",
-+ __func__, subfield, value, new_value);
-+ }
-+ mchbar_write32(TX_TRAIN_ch_r_b(channel, rank, byte), txt.raw);
-+ download_regfile(ctrl, channel, false, rank, REG_FILE_USE_RANK, byte, false, true);
-+}
-+
-+void download_regfile(
-+ struct sysinfo *ctrl,
-+ const uint8_t channel,
-+ const bool multicast,
-+ const uint8_t rank,
-+ const enum regfile_mode regfile,
-+ const uint8_t byte,
-+ const bool read_rf_rd,
-+ const bool read_rf_wr)
-+{
-+ union reut_seq_base_addr_reg reut_seq_base_addr;
-+ switch (regfile) {
-+ case REG_FILE_USE_START:
-+ reut_seq_base_addr.raw = mchbar_read64(REUT_ch_SEQ_ADDR_START(channel));
-+ break;
-+ case REG_FILE_USE_CURRENT:
-+ reut_seq_base_addr.raw = mchbar_read64(REUT_ch_SEQ_ADDR_CURRENT(channel));
-+ break;
-+ case REG_FILE_USE_RANK:
-+ reut_seq_base_addr.raw = 0;
-+ if (rank >= NUM_SLOTRANKS)
-+ die("%s: bad rank %u\n", __func__, rank);
-+ break;
-+ default:
-+ die("%s: Invalid regfile param %u\n", __func__, regfile);
-+ }
-+ uint8_t phys_rank = rank;
-+ if (reut_seq_base_addr.raw != 0) {
-+ /* Map REUT logical rank to physical rank */
-+ const uint32_t log_to_phys = mchbar_read32(REUT_ch_RANK_LOG_TO_PHYS(channel));
-+ phys_rank = log_to_phys >> (reut_seq_base_addr.rank_addr * 4) & 0x3;
-+ }
-+ uint32_t reg = multicast ? DDR_DATA_ch_CONTROL_0(channel) : DQ_CONTROL_0(channel, byte);
-+ union ddr_data_control_0_reg ddr_data_control_0 = {
-+ .raw = mchbar_read32(reg),
-+ };
-+ ddr_data_control_0.read_rf_rd = read_rf_rd;
-+ ddr_data_control_0.read_rf_wr = read_rf_wr;
-+ ddr_data_control_0.read_rf_rank = phys_rank;
-+ mchbar_write32(reg, ddr_data_control_0.raw);
-+}
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index f029e7f076..8707257b27 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -118,6 +118,30 @@ enum test_stop {
- ALSOE = 3, /* Stop on all lanes error */
- };
-
-+enum rxt_subfield {
-+ RXT_RCVEN = 0,
-+ RXT_RXDQS_P = 1,
-+ RXT_RX_EQ = 2,
-+ RXT_RXDQS_N = 3,
-+ RXT_RX_VREF = 4,
-+ RXT_RXDQS_BOTH = 5,
-+ RXT_RESTORE = 255,
-+};
-+
-+enum txt_subfield {
-+ TXT_TX_DQ = 0,
-+ TXT_TXDQS = 1,
-+ TXT_TX_EQ = 2,
-+ TXT_DQDQS_OFF = 3,
-+ TXT_RESTORE = 255,
-+};
-+
-+enum regfile_mode {
-+ REG_FILE_USE_RANK, /* Used when changing parameters for each rank */
-+ REG_FILE_USE_START, /* Used when changing parameters before the test */
-+ REG_FILE_USE_CURRENT, /* Used when changing parameters after the test */
-+};
-+
- struct wdb_pat {
- uint32_t start_ptr; /* Starting pointer in WDB */
- uint32_t stop_ptr; /* Stopping pointer in WDB */
-@@ -451,6 +475,32 @@ uint8_t select_reut_ranks(struct sysinfo *ctrl, uint8_t channel, uint8_t rankmas
- void run_mpr_io_test(bool clear_errors);
- uint8_t run_io_test(struct sysinfo *ctrl, uint8_t chanmask, uint8_t dq_pat, bool clear_errors);
-
-+void update_rxt(
-+ struct sysinfo *ctrl,
-+ uint8_t channel,
-+ uint8_t rank,
-+ uint8_t byte,
-+ enum rxt_subfield subfield,
-+ int32_t value);
-+
-+void update_txt(
-+ struct sysinfo *ctrl,
-+ uint8_t channel,
-+ uint8_t rank,
-+ uint8_t byte,
-+ enum txt_subfield subfield,
-+ int32_t value);
-+
-+void download_regfile(
-+ struct sysinfo *ctrl,
-+ uint8_t channel,
-+ bool multicast,
-+ uint8_t rank,
-+ enum regfile_mode regfile,
-+ uint8_t byte,
-+ bool read_rf_rd,
-+ bool read_rf_wr);
-+
- uint8_t get_rx_bias(const struct sysinfo *ctrl);
-
- uint8_t get_tCWL(uint32_t mem_clock_mhz);
-diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
-index 817a9f8bf8..a81559bb1e 100644
---- a/src/northbridge/intel/haswell/registers/mchbar.h
-+++ b/src/northbridge/intel/haswell/registers/mchbar.h
-@@ -15,7 +15,11 @@
- /* Register definitions */
-
- /* DDR DATA per-channel per-bytelane */
-+#define RX_TRAIN_ch_r_b(ch, rank, byte) _DDRIO_C_R_B(0x0000, ch, rank, byte)
-+#define TX_TRAIN_ch_r_b(ch, rank, byte) _DDRIO_C_R_B(0x0020, ch, rank, byte)
-+
- #define DQ_CONTROL_2(ch, byte) _DDRIO_C_R_B(0x0064, ch, 0, byte)
-+#define DQ_CONTROL_0(ch, byte) _DDRIO_C_R_B(0x0074, ch, 0, byte)
-
- /* DDR CKE per-channel */
- #define DDR_CKE_ch_CMD_COMP_OFFSET(ch) _DDRIO_C_R_B(0x1204, ch, 0, 0)
-@@ -38,6 +42,9 @@
- #define DDR_SCRAMBLE_ch(ch) (0x2000 + 4 * (ch))
- #define DDR_SCRAM_MISC_CONTROL 0x2008
-
-+/* DDR DATA per-channel multicast */
-+#define DDR_DATA_ch_CONTROL_0(ch) _DDRIO_C_R_B(0x3074, ch, 0, 0)
-+
- /* DDR CMDN/CMDS per-channel (writes go to both CMDN and CMDS fubs) */
- #define DDR_CMD_ch_COMP_OFFSET(ch) _DDRIO_C_R_B(0x3204, ch, 0, 0)
- #define DDR_CMD_ch_PI_CODING(ch) _DDRIO_C_R_B(0x3208, ch, 0, 0)
-@@ -147,6 +154,8 @@
-
- #define REUT_ch_SEQ_ADDR_WRAP(ch) (0x48e8 + 8 * (ch))
-
-+#define REUT_ch_SEQ_ADDR_CURRENT(ch) (0x48f8 + 8 * (ch))
-+
- #define REUT_ch_SEQ_MISC_CTL(ch) (0x4908 + 4 * (ch))
-
- #define REUT_ch_SEQ_ADDR_INC_CTL(ch) (0x4910 + 8 * (ch))
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0040-haswell-NRI-Add-RcvEn-training.patch b/config/coreboot/default/patches/0040-haswell-NRI-Add-RcvEn-training.patch
deleted file mode 100644
index a40ffa69..00000000
--- a/config/coreboot/default/patches/0040-haswell-NRI-Add-RcvEn-training.patch
+++ /dev/null
@@ -1,708 +0,0 @@
-From 61435822eb1d65b919bec45076737ce4ea91e1b1 Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Sun, 8 May 2022 00:05:41 +0200
-Subject: [PATCH 40/51] haswell NRI: Add RcvEn training
-
-Implement the RcvEn (Receive Enable) calibration procedure.
-
-Change-Id: Ifbfa520f3e0486c56d0988ce67af2ddb9cf29888
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../intel/haswell/native_raminit/Makefile.mk | 1 +
- .../haswell/native_raminit/raminit_main.c | 1 +
- .../haswell/native_raminit/raminit_native.h | 14 +
- .../haswell/native_raminit/reg_structs.h | 13 +
- .../native_raminit/train_receive_enable.c | 561 ++++++++++++++++++
- .../intel/haswell/registers/mchbar.h | 3 +
- 6 files changed, 593 insertions(+)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/train_receive_enable.c
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-index ebe9e9b762..e2fbfb4211 100644
---- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-@@ -16,3 +16,4 @@ romstage-y += setup_wdb.c
- romstage-y += spd_bitmunching.c
- romstage-y += testing_io.c
- romstage-y += timings_refresh.c
-+romstage-y += train_receive_enable.c
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-index 5e4674957d..7d444659c3 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-@@ -60,6 +60,7 @@ static const struct task_entry cold_boot[] = {
- { configure_memory_map, true, "MEMMAP", },
- { do_jedec_init, true, "JEDECINIT", },
- { pre_training, true, "PRETRAIN", },
-+ { train_receive_enable, true, "RCVET", },
- };
-
- /* Return a generic stepping value to make stepping checks simpler */
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index 8707257b27..eaaaedad1e 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -43,6 +43,9 @@
- #define NUM_WDB_CL_MUX_SEEDS 3
- #define NUM_CADB_MUX_SEEDS 3
-
-+/* Specified in PI ticks. 64 PI ticks == 1 qclk */
-+#define tDQSCK_DRIFT 64
-+
- /* ZQ calibration types */
- enum {
- ZQ_INIT, /* DDR3: ZQCL with tZQinit, LPDDR3: ZQ Init with tZQinit */
-@@ -189,6 +192,7 @@ enum raminit_status {
- RAMINIT_STATUS_MPLL_INIT_FAILURE,
- RAMINIT_STATUS_POLL_TIMEOUT,
- RAMINIT_STATUS_REUT_ERROR,
-+ RAMINIT_STATUS_RCVEN_FAILURE,
- RAMINIT_STATUS_UNSPECIFIED_ERROR, /** TODO: Deprecated in favor of specific values **/
- };
-
-@@ -271,6 +275,10 @@ struct sysinfo {
-
- union ddr_data_vref_adjust_reg dimm_vref;
-
-+ uint8_t io_latency[NUM_CHANNELS][NUM_SLOTRANKS];
-+ uint8_t rt_latency[NUM_CHANNELS][NUM_SLOTRANKS];
-+ uint32_t rt_io_comp[NUM_CHANNELS];
-+
- uint32_t data_offset_train[NUM_CHANNELS][NUM_LANES];
- uint32_t data_offset_comp[NUM_CHANNELS][NUM_LANES];
-
-@@ -345,6 +353,11 @@ static inline void clear_data_offset_train_all(struct sysinfo *ctrl)
- memset(ctrl->data_offset_train, 0, sizeof(ctrl->data_offset_train));
- }
-
-+static inline uint32_t get_data_train_feedback(const uint8_t channel, const uint8_t byte)
-+{
-+ return mchbar_read32(DDR_DATA_TRAIN_FEEDBACK(channel, byte));
-+}
-+
- /* Number of ticks to wait in units of 69.841279 ns (citation needed) */
- static inline void tick_delay(const uint32_t delay)
- {
-@@ -400,6 +413,7 @@ enum raminit_status convert_timings(struct sysinfo *ctrl);
- enum raminit_status configure_mc(struct sysinfo *ctrl);
- enum raminit_status configure_memory_map(struct sysinfo *ctrl);
- enum raminit_status do_jedec_init(struct sysinfo *ctrl);
-+enum raminit_status train_receive_enable(struct sysinfo *ctrl);
-
- void configure_timings(struct sysinfo *ctrl);
- void configure_refresh(struct sysinfo *ctrl);
-diff --git a/src/northbridge/intel/haswell/native_raminit/reg_structs.h b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-index b943259b91..b099f4bb82 100644
---- a/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-+++ b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-@@ -297,6 +297,19 @@ union ddr_scram_misc_control_reg {
- uint32_t raw;
- };
-
-+union sc_io_latency_reg {
-+ struct __packed {
-+ uint32_t iolat_rank0 : 4; // Bits 3:0
-+ uint32_t iolat_rank1 : 4; // Bits 7:4
-+ uint32_t iolat_rank2 : 4; // Bits 11:8
-+ uint32_t iolat_rank3 : 4; // Bits 15:12
-+ uint32_t rt_iocomp : 6; // Bits 21:16
-+ uint32_t : 9; // Bits 30:22
-+ uint32_t dis_rt_clk_gate : 1; // Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
- union mcscheds_cbit_reg {
- struct __packed {
- uint32_t dis_opp_cas : 1; // Bits 0:0
-diff --git a/src/northbridge/intel/haswell/native_raminit/train_receive_enable.c b/src/northbridge/intel/haswell/native_raminit/train_receive_enable.c
-new file mode 100644
-index 0000000000..576c6bc21e
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/train_receive_enable.c
-@@ -0,0 +1,561 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <console/console.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <types.h>
-+
-+#include "raminit_native.h"
-+#include "ranges.h"
-+
-+#define RCVEN_PLOT RAM_DEBUG
-+
-+static enum raminit_status change_rcven_timing(struct sysinfo *ctrl, const uint8_t channel)
-+{
-+ int16_t max_rcven = -4096;
-+ int16_t min_rcven = 4096;
-+ int16_t max_rcven_rank[NUM_SLOTRANKS];
-+ int16_t min_rcven_rank[NUM_SLOTRANKS];
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ max_rcven_rank[rank] = max_rcven;
-+ min_rcven_rank[rank] = min_rcven;
-+ }
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ int16_t new_rcven = ctrl->rcven[channel][rank][byte];
-+ new_rcven -= ctrl->io_latency[channel][rank] * 64;
-+ if (max_rcven_rank[rank] < new_rcven)
-+ max_rcven_rank[rank] = new_rcven;
-+
-+ if (min_rcven_rank[rank] > new_rcven)
-+ min_rcven_rank[rank] = new_rcven;
-+ }
-+ if (max_rcven < max_rcven_rank[rank])
-+ max_rcven = max_rcven_rank[rank];
-+
-+ if (min_rcven > min_rcven_rank[rank])
-+ min_rcven = min_rcven_rank[rank];
-+ }
-+
-+ /*
-+ * Determine how far we are from the ideal center point for RcvEn timing.
-+ * (PiIdeal - AveRcvEn) / 64 is the ideal number of cycles we should have
-+ * for IO latency. command training will reduce this by 64, so plan for
-+ * that now in the ideal value. Round to closest integer.
-+ */
-+ const int16_t rre_pi_ideal = 256 + 64;
-+ const int16_t pi_reserve = 64;
-+ const int16_t rcven_center = (max_rcven + min_rcven) / 2;
-+ const int8_t iolat_target = DIV_ROUND_CLOSEST(rre_pi_ideal - rcven_center, 64);
-+
-+ int8_t io_g_offset = 0;
-+ int8_t io_lat[NUM_SLOTRANKS] = { 0 };
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ io_lat[rank] = iolat_target;
-+
-+ /* Check for RcvEn underflow/overflow */
-+ const int16_t rcven_lower = 64 * io_lat[rank] + min_rcven_rank[rank];
-+ if (rcven_lower < pi_reserve)
-+ io_lat[rank] += DIV_ROUND_UP(pi_reserve - rcven_lower, 64);
-+
-+ const int16_t rcven_upper = 64 * io_lat[rank] + max_rcven_rank[rank];
-+ if (rcven_upper > 511 - pi_reserve)
-+ io_lat[rank] -= DIV_ROUND_UP(rcven_upper - (511 - pi_reserve), 64);
-+
-+ /* Check for IO latency over/underflow */
-+ if (io_lat[rank] - io_g_offset > 14)
-+ io_g_offset = io_lat[rank] - 14;
-+
-+ if (io_lat[rank] - io_g_offset < 1)
-+ io_g_offset = io_lat[rank] - 1;
-+
-+ const int8_t cycle_offset = io_lat[rank] - ctrl->io_latency[channel][rank];
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ ctrl->rcven[channel][rank][byte] += 64 * cycle_offset;
-+ update_rxt(ctrl, channel, rank, byte, RXT_RESTORE, 0);
-+ }
-+ }
-+
-+ /* Calculate new IO comp latency */
-+ union sc_io_latency_reg sc_io_lat = {
-+ .raw = mchbar_read32(SC_IO_LATENCY_ch(channel)),
-+ };
-+
-+ /* Check if we are underflowing or overflowing this field */
-+ if (io_g_offset < 0 && sc_io_lat.rt_iocomp < -io_g_offset) {
-+ printk(BIOS_ERR, "%s: IO COMP underflow\n", __func__);
-+ printk(BIOS_ERR, "io_g_offset: %d\n", io_g_offset);
-+ printk(BIOS_ERR, "rt_iocomp: %u\n", sc_io_lat.rt_iocomp);
-+ return RAMINIT_STATUS_RCVEN_FAILURE;
-+ }
-+ if (io_g_offset > 0 && io_g_offset > 0x3f - sc_io_lat.rt_iocomp) {
-+ printk(BIOS_ERR, "%s: IO COMP overflow\n", __func__);
-+ printk(BIOS_ERR, "io_g_offset: %d\n", io_g_offset);
-+ printk(BIOS_ERR, "rt_iocomp: %u\n", sc_io_lat.rt_iocomp);
-+ return RAMINIT_STATUS_RCVEN_FAILURE;
-+ }
-+ sc_io_lat.rt_iocomp += io_g_offset;
-+ ctrl->rt_io_comp[channel] = sc_io_lat.rt_iocomp;
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (ctrl->rankmap[channel] & BIT(rank))
-+ ctrl->io_latency[channel][rank] = io_lat[rank] - io_g_offset;
-+
-+ const uint8_t shift = rank * 4;
-+ sc_io_lat.raw &= ~(0xf << shift);
-+ sc_io_lat.raw |= ctrl->io_latency[channel][rank] << shift;
-+ }
-+ mchbar_write32(SC_IO_LATENCY_ch(channel), sc_io_lat.raw);
-+ return RAMINIT_STATUS_SUCCESS;
-+}
-+
-+#define RL_START (256 + 24)
-+#define RL_STOP (384 + 24)
-+#define RL_STEP 8
-+
-+#define RE_NUM_SAMPLES 6
-+
-+static enum raminit_status verify_high_region(const int32_t center, const int32_t lwidth)
-+{
-+ if (center > RL_STOP) {
-+ /* Check if center of high was found where it should be */
-+ printk(BIOS_ERR, "RcvEn: Center of high (%d) higher than expected\n", center);
-+ return RAMINIT_STATUS_RCVEN_FAILURE;
-+ }
-+ if (lwidth <= 32) {
-+ /* Check if width is large enough */
-+ printk(BIOS_ERR, "RcvEn: Width of high region (%d) too small\n", lwidth);
-+ return RAMINIT_STATUS_RCVEN_FAILURE;
-+ }
-+ if (lwidth >= 96) {
-+ /* Since we're calibrating a phase, a too large region is a problem */
-+ printk(BIOS_ERR, "RcvEn: Width of high region (%d) too large\n", lwidth);
-+ return RAMINIT_STATUS_RCVEN_FAILURE;
-+ }
-+ return RAMINIT_STATUS_SUCCESS;
-+}
-+
-+static void program_io_latency(struct sysinfo *ctrl, const uint8_t channel, const uint8_t rank)
-+{
-+ const uint8_t shift = rank * 4;
-+ const uint8_t iolat = ctrl->io_latency[channel][rank];
-+ mchbar_clrsetbits32(SC_IO_LATENCY_ch(channel), 0xf << shift, iolat << shift);
-+}
-+
-+static void program_rl_delays(struct sysinfo *ctrl, const uint8_t rank, const uint16_t rl_delay)
-+{
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ update_rxt(ctrl, channel, rank, byte, RXT_RCVEN, rl_delay);
-+ }
-+}
-+
-+static bool sample_dqs(const uint8_t channel, const uint8_t byte)
-+{
-+ return (get_data_train_feedback(channel, byte) & 0x1ff) >= BIT(RE_NUM_SAMPLES - 1);
-+}
-+
-+enum raminit_status train_receive_enable(struct sysinfo *ctrl)
-+{
-+ const struct reut_box reut_addr = {
-+ .col = {
-+ .start = 0,
-+ .stop = 1023,
-+ .inc_rate = 0,
-+ .inc_val = 1,
-+ },
-+ };
-+ const struct wdb_pat wdb_pattern = {
-+ .start_ptr = 0,
-+ .stop_ptr = 9,
-+ .inc_rate = 32,
-+ .dq_pattern = BASIC_VA,
-+ };
-+
-+ const uint16_t bytemask = BIT(ctrl->lanes) - 1;
-+ const uint8_t fine_step = 1;
-+
-+ const uint8_t rt_delta = is_hsw_ult() ? 4 : 2;
-+ const uint8_t rt_io_comp = 21 + rt_delta;
-+ const uint8_t rt_latency = 16 + rt_delta;
-+ setup_io_test(
-+ ctrl,
-+ ctrl->chanmap,
-+ PAT_RD,
-+ 2,
-+ RE_NUM_SAMPLES + 1,
-+ &reut_addr,
-+ 0,
-+ &wdb_pattern,
-+ 0,
-+ 8);
-+
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ union ddr_data_control_2_reg data_control_2 = {
-+ .raw = ctrl->dq_control_2[channel][byte],
-+ };
-+ data_control_2.force_rx_on = 1;
-+ mchbar_write32(DQ_CONTROL_2(channel, byte), data_control_2.raw);
-+ }
-+ union ddr_data_control_0_reg data_control_0 = {
-+ .raw = ctrl->dq_control_0[channel],
-+ };
-+ if (ctrl->lpddr) {
-+ /**
-+ * W/A for b4618574 - @todo: remove for HSW ULT C0
-+ * Can't have force_odt_on together with leaker, disable LPDDR
-+ * mode during this training step. lpddr_mode is restored
-+ * at the end of this function from the host structure.
-+ */
-+ data_control_0.lpddr_mode = 0;
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
-+ }
-+ data_control_0.force_odt_on = 1;
-+ data_control_0.rl_training_mode = 1;
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
-+ mchbar_write32(SC_IO_LATENCY_ch(channel), (union sc_io_latency_reg) {
-+ .rt_iocomp = rt_io_comp,
-+ }.raw);
-+ }
-+ enum raminit_status status = RAMINIT_STATUS_SUCCESS;
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (!does_rank_exist(ctrl, rank))
-+ continue;
-+
-+ /*
-+ * Set initial roundtrip latency values. Assume -4 QCLK for worst board
-+ * layout. This is calculated as HW_ROUNDT_LAT_DEFAULT_VALUE plus:
-+ *
-+ * DDR3: Default + (2 * tAA) + 4 QCLK + PI_CLK + N-mode value * 2
-+ * LPDDR3: Default + (2 * tAA) + 4 QCLK + PI_CLK + tDQSCK_max
-+ *
-+ * N-mode is 3 during training mode. Both channels use the same timings.
-+ */
-+ /** TODO: differs for LPDDR **/
-+ const uint32_t tmp = MAX(ctrl->multiplier, 4) + 5 + 2 * ctrl->tAA;
-+ const uint32_t initial_rt_latency = MIN(rt_latency + tmp, 0x3f);
-+
-+ uint8_t chanmask = 0;
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ chanmask |= select_reut_ranks(ctrl, channel, BIT(rank));
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ ctrl->io_latency[channel][rank] = 0;
-+ mchbar_write8(SC_ROUNDT_LAT_ch(channel) + rank, initial_rt_latency);
-+ ctrl->rt_latency[channel][rank] = initial_rt_latency;
-+ }
-+
-+ printk(BIOS_DEBUG, "Rank %u\n", rank);
-+ printk(BIOS_DEBUG, "Steps 1 and 2: Find middle of high region\n");
-+ printk(RCVEN_PLOT, "Byte");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(RCVEN_PLOT, "\t");
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ printk(RCVEN_PLOT, "%u ", byte);
-+ }
-+ printk(RCVEN_PLOT, "\nRcvEn\n");
-+ struct phase_train_data region_data[NUM_CHANNELS][NUM_LANES] = { 0 };
-+ for (uint16_t rl_delay = RL_START; rl_delay < RL_STOP; rl_delay += RL_STEP) {
-+ printk(RCVEN_PLOT, " % 3d", rl_delay);
-+ program_rl_delays(ctrl, rank, rl_delay);
-+ run_io_test(ctrl, chanmask, BASIC_VA, true);
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(RCVEN_PLOT, "\t");
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ const bool high = sample_dqs(channel, byte);
-+ printk(RCVEN_PLOT, high ? ". " : "# ");
-+ phase_record_pass(
-+ &region_data[channel][byte],
-+ high,
-+ rl_delay,
-+ RL_START,
-+ RL_STEP);
-+ }
-+ }
-+ printk(RCVEN_PLOT, "\n");
-+ }
-+ printk(RCVEN_PLOT, "\n");
-+ printk(BIOS_DEBUG, "Update RcvEn timing to be in the center of high region\n");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(BIOS_DEBUG, "C%u.R%u: \tLeft\tRight\tWidth\tCenter\n",
-+ channel, rank);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ struct phase_train_data *const curr_data =
-+ &region_data[channel][byte];
-+ phase_append_current_to_initial(curr_data, RL_START, RL_STEP);
-+ const int32_t lwidth = range_width(curr_data->largest);
-+ const int32_t center = range_center(curr_data->largest);
-+ printk(BIOS_DEBUG, " B%u: \t%d\t%d\t%d\t%d\n",
-+ byte,
-+ curr_data->largest.start,
-+ curr_data->largest.end,
-+ lwidth,
-+ center);
-+
-+ status = verify_high_region(center, lwidth);
-+ if (status) {
-+ printk(BIOS_ERR,
-+ "RcvEn problems on channel %u, byte %u\n",
-+ channel, byte);
-+ goto clean_up;
-+ }
-+ ctrl->rcven[channel][rank][byte] = center;
-+ update_rxt(ctrl, channel, rank, byte, RXT_RESTORE, 0);
-+ }
-+ printk(BIOS_DEBUG, "\n");
-+ }
-+
-+ printk(BIOS_DEBUG, "Step 3: Quarter preamble - Walk backwards\n");
-+ printk(RCVEN_PLOT, "Byte");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(RCVEN_PLOT, "\t");
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ printk(RCVEN_PLOT, "%u ", byte);
-+ }
-+ printk(RCVEN_PLOT, "\nIOLAT\n");
-+ bool done = false;
-+ while (!done) {
-+ run_io_test(ctrl, chanmask, BASIC_VA, true);
-+ done = true;
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(RCVEN_PLOT, " %2u\t", ctrl->io_latency[channel][rank]);
-+ uint16_t highs = 0;
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ const bool high = sample_dqs(channel, byte);
-+ printk(RCVEN_PLOT, high ? "H " : "L ");
-+ if (high)
-+ highs |= BIT(byte);
-+ }
-+ if (!highs)
-+ continue;
-+
-+ done = false;
-+
-+ /* If all bytes sample high, adjust timing globally */
-+ if (highs == bytemask && ctrl->io_latency[channel][rank] < 14) {
-+ ctrl->io_latency[channel][rank] += 2;
-+ ctrl->io_latency[channel][rank] %= 16;
-+ program_io_latency(ctrl, channel, rank);
-+ continue;
-+ }
-+
-+ /* Otherwise, adjust individual bytes */
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ if (!(highs & BIT(byte)))
-+ continue;
-+
-+ if (ctrl->rcven[channel][rank][byte] < 128) {
-+ printk(BIOS_ERR,
-+ "RcvEn underflow: walking backwards\n");
-+ printk(BIOS_ERR,
-+ "For channel %u, rank %u, byte %u\n",
-+ channel, rank, byte);
-+ status = RAMINIT_STATUS_RCVEN_FAILURE;
-+ goto clean_up;
-+ }
-+ ctrl->rcven[channel][rank][byte] -= 128;
-+ update_rxt(ctrl, channel, rank, byte, RXT_RESTORE, 0);
-+ }
-+ }
-+ printk(RCVEN_PLOT, "\n");
-+ }
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(BIOS_DEBUG, "\nC%u: Preamble\n", channel);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ printk(BIOS_DEBUG,
-+ " B%u: %u\n", byte, ctrl->rcven[channel][rank][byte]);
-+ }
-+ }
-+ printk(BIOS_DEBUG, "\n");
-+
-+ printk(BIOS_DEBUG, "Step 4: Add 1 qclk\n");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ ctrl->rcven[channel][rank][byte] += 64;
-+ update_rxt(ctrl, channel, rank, byte, RXT_RESTORE, 0);
-+ }
-+ }
-+ printk(BIOS_DEBUG, "\n");
-+
-+ printk(BIOS_DEBUG, "Step 5: Walk forward to find rising edge\n");
-+ printk(RCVEN_PLOT, "Byte");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(RCVEN_PLOT, "\t");
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ printk(RCVEN_PLOT, "%u ", byte);
-+ }
-+ printk(RCVEN_PLOT, "\n inc\n");
-+ uint16_t ch_result[NUM_CHANNELS] = { 0 };
-+ uint8_t inc_preamble[NUM_CHANNELS][NUM_LANES] = { 0 };
-+ for (uint8_t inc = 0; inc < 64; inc += fine_step) {
-+ printk(RCVEN_PLOT, " %2u\t", inc);
-+ run_io_test(ctrl, chanmask, BASIC_VA, true);
-+ done = true;
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ if (ch_result[channel] & BIT(byte)) {
-+ /* Skip bytes that are already done */
-+ printk(RCVEN_PLOT, ". ");
-+ continue;
-+ }
-+ const bool pass = sample_dqs(channel, byte);
-+ printk(RCVEN_PLOT, pass ? ". " : "# ");
-+ if (pass) {
-+ ch_result[channel] |= BIT(byte);
-+ continue;
-+ }
-+ ctrl->rcven[channel][rank][byte] += fine_step;
-+ update_rxt(ctrl, channel, rank, byte, RXT_RESTORE, 0);
-+ inc_preamble[channel][byte] = inc;
-+ }
-+ printk(RCVEN_PLOT, "\t");
-+ if (ch_result[channel] != bytemask)
-+ done = false;
-+ }
-+ printk(RCVEN_PLOT, "\n");
-+ if (done)
-+ break;
-+ }
-+ printk(BIOS_DEBUG, "\n");
-+ if (!done) {
-+ printk(BIOS_ERR, "Error: Preamble edge not found for all bytes\n");
-+ printk(BIOS_ERR, "The final RcvEn results are as follows:\n");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(BIOS_ERR, "Channel %u Rank %u: preamble\n",
-+ channel, rank);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ printk(BIOS_ERR, " Byte %u: %u%s\n", byte,
-+ ctrl->rcven[channel][rank][byte],
-+ (ch_result[channel] ^ bytemask) & BIT(byte)
-+ ? ""
-+ : " *** Check this byte! ***");
-+ }
-+ }
-+ status = RAMINIT_STATUS_RCVEN_FAILURE;
-+ goto clean_up;
-+ }
-+
-+ printk(BIOS_DEBUG, "Step 6: center on preamble and clean up rank\n");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(BIOS_DEBUG, "C%u: Preamble increment\n", channel);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ /*
-+ * For Traditional, pull in RcvEn by 64. For ULT, take the DQS
-+ * drift into account to the specified guardband: tDQSCK_DRIFT.
-+ */
-+ ctrl->rcven[channel][rank][byte] -= tDQSCK_DRIFT;
-+ update_rxt(ctrl, channel, rank, byte, RXT_RESTORE, 0);
-+ printk(BIOS_DEBUG, " B%u: %u %u\n", byte,
-+ ctrl->rcven[channel][rank][byte],
-+ inc_preamble[channel][byte]);
-+ }
-+ printk(BIOS_DEBUG, "\n");
-+ }
-+ printk(BIOS_DEBUG, "\n");
-+ }
-+
-+clean_up:
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ if (ctrl->lpddr) {
-+ /**
-+ * W/A for b4618574 - @todo: remove for HSW ULT C0
-+ * Can't have force_odt_on together with leaker, disable LPDDR mode for
-+ * this training step. This write will disable force_odt_on while still
-+ * keeping LPDDR mode disabled. Second write will restore LPDDR mode.
-+ */
-+ union ddr_data_control_0_reg data_control_0 = {
-+ .raw = ctrl->dq_control_0[channel],
-+ };
-+ data_control_0.lpddr_mode = 0;
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
-+ }
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), ctrl->dq_control_0[channel]);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ mchbar_write32(DQ_CONTROL_2(channel, byte),
-+ ctrl->dq_control_2[channel][byte]);
-+ }
-+ }
-+ io_reset();
-+ if (status)
-+ return status;
-+
-+ printk(BIOS_DEBUG, "Step 7: Sync IO latency across all ranks\n");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ status = change_rcven_timing(ctrl, channel);
-+ if (status)
-+ return status;
-+ }
-+ printk(BIOS_DEBUG, "\nFinal Receive Enable and IO latency settings:\n");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ const union sc_io_latency_reg sc_io_latency = {
-+ .raw = mchbar_read32(SC_IO_LATENCY_ch(channel)),
-+ };
-+ printk(BIOS_DEBUG, " C%u.R%u: IOLAT = %u rt_iocomp = %u\n", channel,
-+ rank, ctrl->io_latency[channel][rank], sc_io_latency.rt_iocomp);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ printk(BIOS_DEBUG, " B%u: %u\n", byte,
-+ ctrl->rcven[channel][rank][byte]);
-+ }
-+ printk(BIOS_DEBUG, "\n");
-+ }
-+ }
-+ return status;
-+}
-diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
-index a81559bb1e..9172d4f2b0 100644
---- a/src/northbridge/intel/haswell/registers/mchbar.h
-+++ b/src/northbridge/intel/haswell/registers/mchbar.h
-@@ -18,6 +18,8 @@
- #define RX_TRAIN_ch_r_b(ch, rank, byte) _DDRIO_C_R_B(0x0000, ch, rank, byte)
- #define TX_TRAIN_ch_r_b(ch, rank, byte) _DDRIO_C_R_B(0x0020, ch, rank, byte)
-
-+#define DDR_DATA_TRAIN_FEEDBACK(ch, byte) _DDRIO_C_R_B(0x0054, ch, 0, byte)
-+
- #define DQ_CONTROL_2(ch, byte) _DDRIO_C_R_B(0x0064, ch, 0, byte)
- #define DQ_CONTROL_0(ch, byte) _DDRIO_C_R_B(0x0074, ch, 0, byte)
-
-@@ -100,6 +102,7 @@
- #define COMMAND_RATE_LIMIT_ch(ch) _MCMAIN_C(0x4010, ch)
- #define TC_BANK_RANK_D_ch(ch) _MCMAIN_C(0x4014, ch)
- #define SC_ROUNDT_LAT_ch(ch) _MCMAIN_C(0x4024, ch)
-+#define SC_IO_LATENCY_ch(ch) _MCMAIN_C(0x4028, ch)
-
- #define REUT_ch_PAT_WDB_CL_MUX_CFG(ch) _MCMAIN_C(0x4040, ch)
-
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0041-haswell-NRI-Add-function-to-change-margins.patch b/config/coreboot/default/patches/0041-haswell-NRI-Add-function-to-change-margins.patch
deleted file mode 100644
index 296dbed6..00000000
--- a/config/coreboot/default/patches/0041-haswell-NRI-Add-function-to-change-margins.patch
+++ /dev/null
@@ -1,272 +0,0 @@
-From fc6c3edf561dd11eeb2ebe7f4cb93542e664935a Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Sun, 8 May 2022 11:58:59 +0200
-Subject: [PATCH 41/51] haswell NRI: Add function to change margins
-
-Implement a function to change margin parameters. Haswell provides a
-register to apply an offset to margin parameters during training, so
-make use of it. There are other margin parameters that have not been
-implemented yet, as they are not needed for now and special handling
-is needed to provide offset training functionality.
-
-Change-Id: I5392380e13de3c44e77b7bc9f3b819e2661d1e2d
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../haswell/native_raminit/change_margin.c | 136 ++++++++++++++++++
- .../haswell/native_raminit/raminit_native.h | 39 +++++
- .../haswell/native_raminit/reg_structs.h | 12 ++
- .../intel/haswell/registers/mchbar.h | 1 +
- 4 files changed, 188 insertions(+)
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/change_margin.c b/src/northbridge/intel/haswell/native_raminit/change_margin.c
-index 055c666eee..299c44a6b0 100644
---- a/src/northbridge/intel/haswell/native_raminit/change_margin.c
-+++ b/src/northbridge/intel/haswell/native_raminit/change_margin.c
-@@ -1,5 +1,6 @@
- /* SPDX-License-Identifier: GPL-2.0-or-later */
-
-+#include <assert.h>
- #include <commonlib/bsd/clamp.h>
- #include <console/console.h>
- #include <delay.h>
-@@ -152,3 +153,138 @@ void download_regfile(
- ddr_data_control_0.read_rf_rank = phys_rank;
- mchbar_write32(reg, ddr_data_control_0.raw);
- }
-+
-+static void update_data_offset_train(
-+ struct sysinfo *ctrl,
-+ const uint8_t param,
-+ const uint8_t en_multicast,
-+ const uint8_t channel_in,
-+ const uint8_t rank,
-+ const uint8_t byte_in,
-+ const bool update_ctrl,
-+ const enum regfile_mode regfile,
-+ const uint32_t value)
-+{
-+ bool is_rd = false;
-+ bool is_wr = false;
-+ switch (param) {
-+ case RdT:
-+ case RdV:
-+ case RcvEna:
-+ is_rd = true;
-+ break;
-+ case WrT:
-+ case WrDqsT:
-+ is_wr = true;
-+ break;
-+ default:
-+ die("%s: Invalid margin parameter %u\n", __func__, param);
-+ }
-+ if (en_multicast) {
-+ mchbar_write32(DDR_DATA_OFFSET_TRAIN, value);
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ download_regfile(ctrl, channel, true, rank, regfile, 0, is_rd, is_wr);
-+ if (update_ctrl) {
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ ctrl->data_offset_train[channel][byte] = value;
-+ }
-+ }
-+ } else {
-+ mchbar_write32(DDR_DATA_OFFSET_TRAIN_ch_b(channel_in, byte_in), value);
-+ download_regfile(ctrl, channel_in, false, rank, regfile, byte_in, is_rd, is_wr);
-+ if (update_ctrl)
-+ ctrl->data_offset_train[channel_in][byte_in] = value;
-+ }
-+}
-+
-+static uint32_t get_max_margin(const enum margin_parameter param)
-+{
-+ switch (param) {
-+ case RcvEna:
-+ case RdT:
-+ case WrT:
-+ case WrDqsT:
-+ return MAX_POSSIBLE_TIME;
-+ case RdV:
-+ return MAX_POSSIBLE_VREF;
-+ default:
-+ die("%s: Invalid margin parameter %u\n", __func__, param);
-+ }
-+}
-+
-+void change_margin(
-+ struct sysinfo *ctrl,
-+ const enum margin_parameter param,
-+ const int32_t value0,
-+ const bool en_multicast,
-+ const uint8_t channel,
-+ const uint8_t rank,
-+ const uint8_t byte,
-+ const bool update_ctrl,
-+ const enum regfile_mode regfile)
-+{
-+ /** FIXME: Remove this **/
-+ if (rank == 0xff)
-+ die("%s: rank is 0xff\n", __func__);
-+
-+ if (!en_multicast && !does_ch_exist(ctrl, channel))
-+ die("%s: Tried to change margin of empty channel %u\n", __func__, channel);
-+
-+ const uint32_t max_value = get_max_margin(param);
-+ const int32_t v0 = clamp_s32(-max_value, value0, max_value);
-+
-+ union ddr_data_offset_train_reg ddr_data_offset_train = {
-+ .raw = en_multicast ? 0 : ctrl->data_offset_train[channel][byte],
-+ };
-+ bool update_offset_train = false;
-+ switch (param) {
-+ case RcvEna:
-+ ddr_data_offset_train.rcven = v0;
-+ update_offset_train = true;
-+ break;
-+ case RdT:
-+ ddr_data_offset_train.rx_dqs = v0;
-+ update_offset_train = true;
-+ break;
-+ case WrT:
-+ ddr_data_offset_train.tx_dq = v0;
-+ update_offset_train = true;
-+ break;
-+ case WrDqsT:
-+ ddr_data_offset_train.tx_dqs = v0;
-+ update_offset_train = true;
-+ break;
-+ case RdV:
-+ ddr_data_offset_train.vref = v0;
-+ update_offset_train = true;
-+ break;
-+ default:
-+ die("%s: Invalid margin parameter %u\n", __func__, param);
-+ }
-+ if (update_offset_train) {
-+ update_data_offset_train(
-+ ctrl,
-+ param,
-+ en_multicast,
-+ channel,
-+ rank,
-+ byte,
-+ update_ctrl,
-+ regfile,
-+ ddr_data_offset_train.raw);
-+ }
-+}
-+
-+void change_1d_margin_multicast(
-+ struct sysinfo *ctrl,
-+ const enum margin_parameter param,
-+ const int32_t value0,
-+ const uint8_t rank,
-+ const bool update_ctrl,
-+ const enum regfile_mode regfile)
-+{
-+ change_margin(ctrl, param, value0, true, 0, rank, 0, update_ctrl, regfile);
-+}
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index eaaaedad1e..1c8473056b 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -36,6 +36,18 @@
-
- #define RTTNOM_MASK (BIT(9) | BIT(6) | BIT(2))
-
-+/* Margin parameter limits */
-+#define MAX_POSSIBLE_TIME 31
-+#define MAX_POSSIBLE_VREF 54
-+
-+#define MAX_POSSIBLE_BOTH MAX_POSSIBLE_VREF
-+
-+#define MIN_TIME (-MAX_POSSIBLE_TIME)
-+#define MAX_TIME (MAX_POSSIBLE_TIME)
-+
-+#define MIN_VREF (-MAX_POSSIBLE_VREF)
-+#define MAX_VREF (MAX_POSSIBLE_VREF)
-+
- #define BASIC_VA_PAT_SPREAD_8 0x01010101
-
- #define WDB_CACHE_LINE_SIZE 8
-@@ -46,6 +58,14 @@
- /* Specified in PI ticks. 64 PI ticks == 1 qclk */
- #define tDQSCK_DRIFT 64
-
-+enum margin_parameter {
-+ RcvEna,
-+ RdT,
-+ WrT,
-+ WrDqsT,
-+ RdV,
-+};
-+
- /* ZQ calibration types */
- enum {
- ZQ_INIT, /* DDR3: ZQCL with tZQinit, LPDDR3: ZQ Init with tZQinit */
-@@ -515,6 +535,25 @@ void download_regfile(
- bool read_rf_rd,
- bool read_rf_wr);
-
-+void change_margin(
-+ struct sysinfo *ctrl,
-+ const enum margin_parameter param,
-+ const int32_t value0,
-+ const bool en_multicast,
-+ const uint8_t channel,
-+ const uint8_t rank,
-+ const uint8_t byte,
-+ const bool update_ctrl,
-+ const enum regfile_mode regfile);
-+
-+void change_1d_margin_multicast(
-+ struct sysinfo *ctrl,
-+ const enum margin_parameter param,
-+ const int32_t value0,
-+ const uint8_t rank,
-+ const bool update_ctrl,
-+ const enum regfile_mode regfile);
-+
- uint8_t get_rx_bias(const struct sysinfo *ctrl);
-
- uint8_t get_tCWL(uint32_t mem_clock_mhz);
-diff --git a/src/northbridge/intel/haswell/native_raminit/reg_structs.h b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-index b099f4bb82..a0e36ed082 100644
---- a/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-+++ b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-@@ -25,6 +25,18 @@ union ddr_data_tx_train_rank_reg {
- uint32_t raw;
- };
-
-+union ddr_data_offset_train_reg {
-+ struct __packed {
-+ int32_t rcven : 6; // Bits 5:0
-+ int32_t rx_dqs : 6; // Bits 11:6
-+ int32_t tx_dq : 6; // Bits 17:12
-+ int32_t tx_dqs : 6; // Bits 23:18
-+ int32_t vref : 7; // Bits 30:24
-+ int32_t : 1; // Bits 31:31
-+ };
-+ uint32_t raw;
-+};
-+
- union ddr_data_control_0_reg {
- struct __packed {
- uint32_t rx_training_mode : 1; // Bits 0:0
-diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
-index 9172d4f2b0..0acafbc826 100644
---- a/src/northbridge/intel/haswell/registers/mchbar.h
-+++ b/src/northbridge/intel/haswell/registers/mchbar.h
-@@ -21,6 +21,7 @@
- #define DDR_DATA_TRAIN_FEEDBACK(ch, byte) _DDRIO_C_R_B(0x0054, ch, 0, byte)
-
- #define DQ_CONTROL_2(ch, byte) _DDRIO_C_R_B(0x0064, ch, 0, byte)
-+#define DDR_DATA_OFFSET_TRAIN_ch_b(ch, byte) _DDRIO_C_R_B(0x0070, ch, 0, byte)
- #define DQ_CONTROL_0(ch, byte) _DDRIO_C_R_B(0x0074, ch, 0, byte)
-
- /* DDR CKE per-channel */
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0042-haswell-NRI-Add-read-MPR-training.patch b/config/coreboot/default/patches/0042-haswell-NRI-Add-read-MPR-training.patch
deleted file mode 100644
index f2ccb7ad..00000000
--- a/config/coreboot/default/patches/0042-haswell-NRI-Add-read-MPR-training.patch
+++ /dev/null
@@ -1,332 +0,0 @@
-From 8f07ea076572dd3371dca7b3dbd5ff9c9b332c55 Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Sun, 8 May 2022 11:35:49 +0200
-Subject: [PATCH 42/51] haswell NRI: Add read MPR training
-
-Implement read training using DDR3 MPR (Multi-Purpose Register).
-
-Change-Id: Id17cb2c4c399ac9bcc937b595b58f863c152461b
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../intel/haswell/native_raminit/Makefile.mk | 1 +
- .../haswell/native_raminit/raminit_main.c | 1 +
- .../haswell/native_raminit/raminit_native.h | 4 +
- .../haswell/native_raminit/train_read_mpr.c | 241 ++++++++++++++++++
- .../intel/haswell/registers/mchbar.h | 2 +-
- 5 files changed, 248 insertions(+), 1 deletion(-)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/train_read_mpr.c
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-index e2fbfb4211..c442be0728 100644
---- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-@@ -16,4 +16,5 @@ romstage-y += setup_wdb.c
- romstage-y += spd_bitmunching.c
- romstage-y += testing_io.c
- romstage-y += timings_refresh.c
-+romstage-y += train_read_mpr.c
- romstage-y += train_receive_enable.c
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-index 7d444659c3..264d1468f5 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-@@ -61,6 +61,7 @@ static const struct task_entry cold_boot[] = {
- { do_jedec_init, true, "JEDECINIT", },
- { pre_training, true, "PRETRAIN", },
- { train_receive_enable, true, "RCVET", },
-+ { train_read_mpr, true, "RDMPRT", },
- };
-
- /* Return a generic stepping value to make stepping checks simpler */
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index 1c8473056b..7a486479ea 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -28,6 +28,8 @@
- /* Always use 12 legs for emphasis (not trained) */
- #define TXEQFULLDRV (3 << 4)
-
-+#define LOOPCOUNT_INFINITE 0xff
-+
- /* DDR3 mode register bits */
- #define MR0_DLL_RESET BIT(8)
-
-@@ -213,6 +215,7 @@ enum raminit_status {
- RAMINIT_STATUS_POLL_TIMEOUT,
- RAMINIT_STATUS_REUT_ERROR,
- RAMINIT_STATUS_RCVEN_FAILURE,
-+ RAMINIT_STATUS_RMPR_FAILURE,
- RAMINIT_STATUS_UNSPECIFIED_ERROR, /** TODO: Deprecated in favor of specific values **/
- };
-
-@@ -434,6 +437,7 @@ enum raminit_status configure_mc(struct sysinfo *ctrl);
- enum raminit_status configure_memory_map(struct sysinfo *ctrl);
- enum raminit_status do_jedec_init(struct sysinfo *ctrl);
- enum raminit_status train_receive_enable(struct sysinfo *ctrl);
-+enum raminit_status train_read_mpr(struct sysinfo *ctrl);
-
- void configure_timings(struct sysinfo *ctrl);
- void configure_refresh(struct sysinfo *ctrl);
-diff --git a/src/northbridge/intel/haswell/native_raminit/train_read_mpr.c b/src/northbridge/intel/haswell/native_raminit/train_read_mpr.c
-new file mode 100644
-index 0000000000..ade1e36148
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/train_read_mpr.c
-@@ -0,0 +1,241 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <commonlib/bsd/clamp.h>
-+#include <console/console.h>
-+#include <delay.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <types.h>
-+
-+#include "raminit_native.h"
-+#include "ranges.h"
-+
-+#define RMPR_START (-32)
-+#define RMPR_STOP (32)
-+#define RMPR_STEP 1
-+
-+#define RMPR_MIN_WIDTH 12
-+
-+#define RMPR_PLOT RAM_DEBUG
-+
-+/*
-+ * Clear rx_training_mode. For LPDDR, we first need to disable odt_samp_extend_en,
-+ * then disable rx_training_mode, and finally re-enable odt_samp_extend_en.
-+ */
-+static void clear_rx_training_mode(struct sysinfo *ctrl, const uint8_t channel)
-+{
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ mchbar_write32(DQ_CONTROL_2(channel, byte), ctrl->dq_control_2[channel][byte]);
-+
-+ if (ctrl->lpddr) {
-+ union ddr_data_control_0_reg data_control_0 = {
-+ .raw = mchbar_read32(DDR_DATA_ch_CONTROL_0(channel)),
-+ };
-+ data_control_0.odt_samp_extend_en = 0;
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
-+ tick_delay(1);
-+ data_control_0.rx_training_mode = 0;
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
-+ tick_delay(1);
-+ }
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), ctrl->dq_control_0[channel]);
-+}
-+
-+static void set_rxdqs_edges_to_midpoint(struct sysinfo *ctrl)
-+{
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ update_rxt(ctrl, channel, rank, byte, RXT_RXDQS_BOTH, 32);
-+ }
-+ }
-+}
-+
-+static void enter_mpr_train_ddr_mode(struct sysinfo *ctrl, const uint8_t rank)
-+{
-+ /* Program MR3 and mask RAS/WE to prevent scheduler from issuing non-read commands */
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ if (!ctrl->lpddr)
-+ reut_issue_mrs(ctrl, channel, BIT(rank), 3, 1 << 2);
-+
-+ union reut_misc_odt_ctrl_reg reut_misc_odt_ctrl = {
-+ .raw = mchbar_read32(REUT_ch_MISC_ODT_CTRL(channel)),
-+ };
-+ reut_misc_odt_ctrl.mpr_train_ddr_on = 1;
-+ mchbar_write32(REUT_ch_MISC_ODT_CTRL(channel), reut_misc_odt_ctrl.raw);
-+ }
-+}
-+
-+static void leave_mpr_train_ddr_mode(struct sysinfo *ctrl, const uint8_t rank)
-+{
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ /*
-+ * The mpr_train_ddr_on bit will force a special command.
-+ * Therefore, clear it before issuing the MRS command.
-+ */
-+ union reut_misc_odt_ctrl_reg reut_misc_odt_ctrl = {
-+ .raw = mchbar_read32(REUT_ch_MISC_ODT_CTRL(channel)),
-+ };
-+ reut_misc_odt_ctrl.mpr_train_ddr_on = 0;
-+ mchbar_write32(REUT_ch_MISC_ODT_CTRL(channel), reut_misc_odt_ctrl.raw);
-+ if (!ctrl->lpddr)
-+ reut_issue_mrs(ctrl, channel, BIT(rank), 3, 0 << 2);
-+ }
-+}
-+
-+enum raminit_status train_read_mpr(struct sysinfo *ctrl)
-+{
-+ set_rxdqs_edges_to_midpoint(ctrl);
-+ clear_data_offset_train_all(ctrl);
-+ setup_io_test_mpr(ctrl, ctrl->chanmap, LOOPCOUNT_INFINITE, NSOE);
-+ enum raminit_status status = RAMINIT_STATUS_SUCCESS;
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (!does_rank_exist(ctrl, rank))
-+ continue;
-+
-+ printk(BIOS_DEBUG, "Rank %u\n", rank);
-+ printk(RMPR_PLOT, "Channel");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(RMPR_PLOT, "\t%u\t\t", channel);
-+ }
-+ printk(RMPR_PLOT, "\nByte");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(RMPR_PLOT, "\t");
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ printk(RMPR_PLOT, "%u ", byte);
-+ }
-+ enter_mpr_train_ddr_mode(ctrl, rank);
-+ struct linear_train_data region_data[NUM_CHANNELS][NUM_LANES] = { 0 };
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++)
-+ select_reut_ranks(ctrl, channel, BIT(rank));
-+
-+ printk(RMPR_PLOT, "\nDqsDelay\n");
-+ int8_t dqs_delay;
-+ for (dqs_delay = RMPR_START; dqs_delay < RMPR_STOP; dqs_delay += RMPR_STEP) {
-+ printk(RMPR_PLOT, "% 5d", dqs_delay);
-+ const enum regfile_mode regfile = REG_FILE_USE_START;
-+ /* Looks like MRC uses rank 0 here, but it feels wrong */
-+ change_1d_margin_multicast(ctrl, RdT, dqs_delay, rank, false, regfile);
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ union ddr_data_control_2_reg data_control_2 = {
-+ .raw = ctrl->dq_control_2[channel][byte],
-+ };
-+ data_control_2.force_bias_on = 1;
-+ data_control_2.force_rx_on = 1;
-+ data_control_2.leaker_comp = 0;
-+ mchbar_write32(DQ_CONTROL_2(channel, byte),
-+ data_control_2.raw);
-+ }
-+ union ddr_data_control_0_reg data_control_0 = {
-+ .raw = ctrl->dq_control_0[channel],
-+ };
-+ data_control_0.rx_training_mode = 1;
-+ data_control_0.force_odt_on = !ctrl->lpddr;
-+ data_control_0.en_read_preamble = 0;
-+ data_control_0.odt_samp_extend_en = ctrl->lpddr;
-+ const uint32_t reg_offset = DDR_DATA_ch_CONTROL_0(channel);
-+ mchbar_write32(reg_offset, data_control_0.raw);
-+ }
-+ run_mpr_io_test(false);
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(RMPR_PLOT, "\t");
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ uint32_t fb = get_data_train_feedback(channel, byte);
-+ const bool pass = fb == 1;
-+ printk(RMPR_PLOT, pass ? ". " : "# ");
-+ linear_record_pass(
-+ &region_data[channel][byte],
-+ pass,
-+ dqs_delay,
-+ RMPR_START,
-+ RMPR_STEP);
-+ }
-+ }
-+ printk(RMPR_PLOT, "\n");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ clear_rx_training_mode(ctrl, channel);
-+ }
-+ io_reset();
-+ }
-+ printk(RMPR_PLOT, "\n");
-+ leave_mpr_train_ddr_mode(ctrl, rank);
-+ clear_data_offset_train_all(ctrl);
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(BIOS_DEBUG, "C%u.R%u: \tLeft\tRight\tWidth\tCenter\tRxDqsPN\n",
-+ channel, rank);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ struct linear_train_data *data = &region_data[channel][byte];
-+ const int32_t lwidth = range_width(data->largest);
-+ if (lwidth <= RMPR_MIN_WIDTH) {
-+ printk(BIOS_ERR,
-+ "Bad eye (lwidth %d <= min %d) for byte %u\n",
-+ lwidth, RMPR_MIN_WIDTH, byte);
-+ status = RAMINIT_STATUS_RMPR_FAILURE;
-+ }
-+ /*
-+ * The MPR center may not be ideal on certain platforms for
-+ * unknown reasons. If so, adjust it with a magical number.
-+ * For Haswell, the magical number is zero. Hell knows why.
-+ */
-+ const int32_t center = range_center(data->largest);
-+ ctrl->rxdqsp[channel][rank][byte] = center - RMPR_START;
-+ ctrl->rxdqsn[channel][rank][byte] = center - RMPR_START;
-+ printk(BIOS_DEBUG, " B%u: \t%d\t%d\t%d\t%d\t%u\n", byte,
-+ data->largest.start, data->largest.end, lwidth,
-+ center, ctrl->rxdqsp[channel][rank][byte]);
-+ }
-+ printk(BIOS_DEBUG, "\n");
-+ }
-+ }
-+
-+ /*
-+ * Now program the DQS center values on populated ranks. data is taken from
-+ * the host struct. We need to do it after all ranks are trained, because we
-+ * need to keep the same DQS value on all ranks during the training procedure.
-+ */
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ update_rxt(ctrl, channel, rank, byte, RXT_RESTORE, 0);
-+ }
-+ }
-+ change_1d_margin_multicast(ctrl, RdT, 0, 0, false, REG_FILE_USE_CURRENT);
-+ io_reset();
-+ return status;
-+}
-diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
-index 0acafbc826..6a31d3a32c 100644
---- a/src/northbridge/intel/haswell/registers/mchbar.h
-+++ b/src/northbridge/intel/haswell/registers/mchbar.h
-@@ -122,7 +122,7 @@
- #define REUT_ch_ERR_DATA_MASK(ch) _MCMAIN_C(0x40d8, ch)
-
- #define REUT_ch_MISC_CKE_CTRL(ch) _MCMAIN_C(0x4190, ch)
--
-+#define REUT_ch_MISC_ODT_CTRL(ch) _MCMAIN_C(0x4194, ch)
- #define REUT_ch_MISC_PAT_CADB_CTRL(ch) _MCMAIN_C(0x4198, ch)
- #define REUT_ch_PAT_CADB_MRS(ch) _MCMAIN_C(0x419c, ch)
- #define REUT_ch_PAT_CADB_MUX_CTRL(ch) _MCMAIN_C(0x41a0, ch)
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0043-haswell-NRI-Add-write-leveling.patch b/config/coreboot/default/patches/0043-haswell-NRI-Add-write-leveling.patch
deleted file mode 100644
index 0202ed1b..00000000
--- a/config/coreboot/default/patches/0043-haswell-NRI-Add-write-leveling.patch
+++ /dev/null
@@ -1,689 +0,0 @@
-From 6df4b7eb0512c24a5f53bc92e81ad6cf42cd28a7 Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Sun, 8 May 2022 12:56:04 +0200
-Subject: [PATCH 43/51] haswell NRI: Add write leveling
-
-Implement JEDEC write leveling, which is done in two steps. The first
-step uses the JEDEC procedure to do "fine" write leveling, i.e. align
-the DQS phase to the clock signal. The second step performs a regular
-read-write test to correct "coarse" cycle errors.
-
-Change-Id: I27678523fe22c38173a688e2a4751c259a20f009
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../intel/haswell/native_raminit/Makefile.mk | 1 +
- .../haswell/native_raminit/raminit_main.c | 1 +
- .../haswell/native_raminit/raminit_native.h | 10 +
- .../train_jedec_write_leveling.c | 581 ++++++++++++++++++
- .../intel/haswell/registers/mchbar.h | 2 +
- 5 files changed, 595 insertions(+)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/train_jedec_write_leveling.c
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-index c442be0728..40c2f5e014 100644
---- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-@@ -16,5 +16,6 @@ romstage-y += setup_wdb.c
- romstage-y += spd_bitmunching.c
- romstage-y += testing_io.c
- romstage-y += timings_refresh.c
-+romstage-y += train_jedec_write_leveling.c
- romstage-y += train_read_mpr.c
- romstage-y += train_receive_enable.c
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-index 264d1468f5..1ff23be615 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-@@ -62,6 +62,7 @@ static const struct task_entry cold_boot[] = {
- { pre_training, true, "PRETRAIN", },
- { train_receive_enable, true, "RCVET", },
- { train_read_mpr, true, "RDMPRT", },
-+ { train_jedec_write_leveling, true, "JWRL", },
- };
-
- /* Return a generic stepping value to make stepping checks simpler */
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index 7a486479ea..d6b11b9d3c 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -60,6 +60,9 @@
- /* Specified in PI ticks. 64 PI ticks == 1 qclk */
- #define tDQSCK_DRIFT 64
-
-+/* Maximum additional latency */
-+#define MAX_ADD_DELAY 2
-+
- enum margin_parameter {
- RcvEna,
- RdT,
-@@ -216,6 +219,7 @@ enum raminit_status {
- RAMINIT_STATUS_REUT_ERROR,
- RAMINIT_STATUS_RCVEN_FAILURE,
- RAMINIT_STATUS_RMPR_FAILURE,
-+ RAMINIT_STATUS_JWRL_FAILURE,
- RAMINIT_STATUS_UNSPECIFIED_ERROR, /** TODO: Deprecated in favor of specific values **/
- };
-
-@@ -381,6 +385,11 @@ static inline uint32_t get_data_train_feedback(const uint8_t channel, const uint
- return mchbar_read32(DDR_DATA_TRAIN_FEEDBACK(channel, byte));
- }
-
-+static inline uint16_t get_byte_group_errors(const uint8_t channel)
-+{
-+ return mchbar_read32(4 + REUT_ch_ERR_MISC_STATUS(channel)) & 0x1ff;
-+}
-+
- /* Number of ticks to wait in units of 69.841279 ns (citation needed) */
- static inline void tick_delay(const uint32_t delay)
- {
-@@ -438,6 +447,7 @@ enum raminit_status configure_memory_map(struct sysinfo *ctrl);
- enum raminit_status do_jedec_init(struct sysinfo *ctrl);
- enum raminit_status train_receive_enable(struct sysinfo *ctrl);
- enum raminit_status train_read_mpr(struct sysinfo *ctrl);
-+enum raminit_status train_jedec_write_leveling(struct sysinfo *ctrl);
-
- void configure_timings(struct sysinfo *ctrl);
- void configure_refresh(struct sysinfo *ctrl);
-diff --git a/src/northbridge/intel/haswell/native_raminit/train_jedec_write_leveling.c b/src/northbridge/intel/haswell/native_raminit/train_jedec_write_leveling.c
-new file mode 100644
-index 0000000000..ef6483e2bd
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/train_jedec_write_leveling.c
-@@ -0,0 +1,581 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <assert.h>
-+#include <console/console.h>
-+#include <delay.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <types.h>
-+
-+#include "raminit_native.h"
-+#include "ranges.h"
-+
-+#define JWLC_PLOT RAM_DEBUG
-+#define JWRL_PLOT RAM_DEBUG
-+
-+static void reset_dram_dll(struct sysinfo *ctrl, const uint8_t channel, const uint8_t rank)
-+{
-+ const uint16_t mr0reg = ctrl->mr0[channel][rank / 2];
-+ reut_issue_mrs(ctrl, channel, BIT(rank), 0, mr0reg | MR0_DLL_RESET);
-+}
-+
-+static void program_wdb_pattern(struct sysinfo *ctrl, const bool invert)
-+{
-+ /* Pattern to keep DQ-DQS simple but detect any failures. Same as NHM/WSM. */
-+ const uint8_t pat[4][2] = {
-+ { 0x00, 0xff },
-+ { 0xff, 0x00 },
-+ { 0xc3, 0x3c },
-+ { 0x3c, 0xc3 },
-+ };
-+ const uint8_t pmask[2][8] = {
-+ { 0, 0, 1, 1, 1, 1, 0, 0 },
-+ { 1, 1, 0, 0, 0, 0, 1, 1 },
-+ };
-+ for (uint8_t s = 0; s < ARRAY_SIZE(pat); s++)
-+ write_wdb_fixed_pat(ctrl, pat[s], pmask[invert], ARRAY_SIZE(pmask[invert]), s);
-+}
-+
-+static int16_t set_add_delay(uint32_t *add_delay, uint8_t rank, int8_t target_off)
-+{
-+ const uint8_t shift = rank * 2;
-+ if (target_off > MAX_ADD_DELAY) {
-+ *add_delay &= ~(3 << shift);
-+ *add_delay |= MAX_ADD_DELAY << shift;
-+ return 128 * (target_off - MAX_ADD_DELAY);
-+ } else if (target_off < 0) {
-+ *add_delay &= ~(3 << shift);
-+ *add_delay |= 0 << shift;
-+ return 128 * target_off;
-+ } else {
-+ *add_delay &= ~(3 << shift);
-+ *add_delay |= target_off << shift;
-+ return 0;
-+ }
-+}
-+
-+static enum raminit_status train_jedec_write_leveling_cleanup(struct sysinfo *ctrl)
-+{
-+ const struct reut_box reut_addr = {
-+ .col = {
-+ .start = 0,
-+ .stop = 1023,
-+ .inc_val = 1,
-+ },
-+ };
-+ const struct wdb_pat wdb_pattern = {
-+ .start_ptr = 0,
-+ .stop_ptr = 3,
-+ .inc_rate = 1,
-+ .dq_pattern = BASIC_VA,
-+ };
-+ const int8_t offsets[] = { 0, 1, -1, 2, 3 };
-+ const int8_t dq_offsets[] = { 0, -10, 10, -5, 5, -15, 15 };
-+ const uint8_t dq_offset_max = ARRAY_SIZE(dq_offsets);
-+
-+ /* Set LFSR seeds to be sequential */
-+ program_wdb_lfsr(ctrl, true);
-+ setup_io_test(
-+ ctrl,
-+ ctrl->chanmap,
-+ PAT_WR_RD,
-+ 2,
-+ 4,
-+ &reut_addr,
-+ NSOE,
-+ &wdb_pattern,
-+ 0,
-+ 0);
-+
-+ const union reut_pat_wdb_cl_mux_cfg_reg reut_wdb_cl_mux_cfg = {
-+ .mux_0_control = REUT_MUX_BTBUFFER,
-+ .mux_1_control = REUT_MUX_BTBUFFER,
-+ .mux_2_control = REUT_MUX_BTBUFFER,
-+ .ecc_data_source_sel = 1,
-+ };
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ mchbar_write32(REUT_ch_PAT_WDB_CL_MUX_CFG(channel), reut_wdb_cl_mux_cfg.raw);
-+ }
-+
-+ int8_t byte_off[NUM_CHANNELS][NUM_LANES] = { 0 };
-+ uint32_t add_delay[NUM_CHANNELS] = { 0 };
-+ enum raminit_status status = RAMINIT_STATUS_SUCCESS;
-+ bool invert = false;
-+ const uint16_t valid_byte_mask = BIT(ctrl->lanes) - 1;
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ uint8_t chanmask = 0;
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++)
-+ chanmask |= select_reut_ranks(ctrl, channel, BIT(rank));
-+
-+ if (!chanmask)
-+ continue;
-+
-+ printk(BIOS_DEBUG, "Rank %u\n", rank);
-+ printk(JWLC_PLOT, "Channel");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(JWLC_PLOT, "\t\t%u\t", channel);
-+ }
-+ printk(JWLC_PLOT, "\nByte\t");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(JWLC_PLOT, "\t");
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ printk(JWLC_PLOT, "%u ", byte);
-+ }
-+ printk(JWLC_PLOT, "\nDelay DqOffset");
-+ bool done = false;
-+ int8_t byte_sum[NUM_CHANNELS] = { 0 };
-+ uint16_t byte_pass[NUM_CHANNELS] = { 0 };
-+ for (uint8_t off = 0; off < ARRAY_SIZE(offsets); off++) {
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ const int16_t global_byte_off =
-+ set_add_delay(&add_delay[channel], rank, offsets[off]);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ update_txt(ctrl, channel, rank, byte, TXT_DQDQS_OFF,
-+ global_byte_off);
-+ }
-+ mchbar_write32(SC_WR_ADD_DELAY_ch(channel),
-+ add_delay[channel]);
-+ }
-+ /* Reset FIFOs and DRAM DLL (Micron workaround) */
-+ if (!ctrl->lpddr) {
-+ io_reset();
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ reset_dram_dll(ctrl, channel, rank);
-+ }
-+ udelay(1);
-+ }
-+ for (uint8_t dq_offset = 0; dq_offset < dq_offset_max; dq_offset++) {
-+ printk(JWLC_PLOT, "\n% 3d\t% 3d",
-+ offsets[off], dq_offsets[dq_offset]);
-+ change_1d_margin_multicast(
-+ ctrl,
-+ WrT,
-+ dq_offsets[dq_offset],
-+ rank,
-+ false,
-+ REG_FILE_USE_RANK);
-+
-+ /*
-+ * Re-program the WDB pattern. Change the pattern
-+ * for the next test to avoid false pass issues.
-+ */
-+ program_wdb_pattern(ctrl, invert);
-+ invert = !invert;
-+ run_io_test(ctrl, chanmask, BASIC_VA, true);
-+ done = true;
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(JWLC_PLOT, "\t");
-+ uint16_t result = get_byte_group_errors(channel);
-+ result &= valid_byte_mask;
-+
-+ /* Skip bytes that have failed or already passed */
-+ const uint16_t skip_me = result | byte_pass[channel];
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ const bool pass = result & BIT(byte);
-+ printk(JWLC_PLOT, pass ? "# " : ". ");
-+ if (skip_me & BIT(byte))
-+ continue;
-+
-+ byte_pass[channel] |= BIT(byte);
-+ byte_off[channel][byte] = offsets[off];
-+ byte_sum[channel] += offsets[off];
-+ }
-+ if (byte_pass[channel] != valid_byte_mask)
-+ done = false;
-+ }
-+ if (done)
-+ break;
-+ }
-+ if (done)
-+ break;
-+ }
-+ printk(BIOS_DEBUG, "\n\n");
-+ if (!done) {
-+ printk(BIOS_ERR, "JWLC: Could not find a pass for all bytes\n");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(BIOS_ERR, "Channel %u, rank %u fail:", channel, rank);
-+ const uint16_t passing_mask = byte_pass[channel];
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ if (BIT(byte) & passing_mask)
-+ continue;
-+
-+ printk(BIOS_ERR, " %u", byte);
-+ }
-+ printk(BIOS_ERR, "\n");
-+ }
-+ status = RAMINIT_STATUS_JWRL_FAILURE;
-+ break;
-+ }
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ /* Refine target offset to make sure it works for all bytes */
-+ int8_t target_off = DIV_ROUND_CLOSEST(byte_sum[channel], ctrl->lanes);
-+ int16_t global_byte_off = 0;
-+ uint8_t all_good_loops = 0;
-+ bool all_good = 0;
-+ while (!all_good) {
-+ global_byte_off =
-+ set_add_delay(&add_delay[channel], rank, target_off);
-+ all_good = true;
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ int16_t local_offset;
-+ local_offset = byte_off[channel][byte] - target_off;
-+ local_offset = local_offset * 128 + global_byte_off;
-+ const uint16_t tx_dq = ctrl->tx_dq[channel][rank][byte];
-+ if (tx_dq + local_offset >= (512 - 64)) {
-+ all_good = false;
-+ all_good_loops++;
-+ target_off++;
-+ break;
-+ }
-+ const uint16_t txdqs = ctrl->tx_dq[channel][rank][byte];
-+ if (txdqs + local_offset < 96) {
-+ all_good = false;
-+ all_good_loops++;
-+ target_off--;
-+ break;
-+ }
-+ }
-+ /* Avoid an infinite loop */
-+ if (all_good_loops > 3)
-+ break;
-+ }
-+ if (!all_good) {
-+ printk(BIOS_ERR, "JWLC: Target offset refining failed\n");
-+ status = RAMINIT_STATUS_JWRL_FAILURE;
-+ break;
-+ }
-+ printk(BIOS_DEBUG, "C%u.R%u: Offset\tFinalEdge\n", channel, rank);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ int16_t local_offset;
-+ local_offset = byte_off[channel][byte] - target_off;
-+ local_offset = local_offset * 128 + global_byte_off;
-+ ctrl->tx_dq[channel][rank][byte] += local_offset;
-+ ctrl->txdqs[channel][rank][byte] += local_offset;
-+ update_txt(ctrl, channel, rank, byte, TXT_RESTORE, 0);
-+ printk(BIOS_DEBUG, " B%u: %d\t%d\n", byte, local_offset,
-+ ctrl->txdqs[channel][rank][byte]);
-+ }
-+ mchbar_write32(SC_WR_ADD_DELAY_ch(channel), add_delay[channel]);
-+ if (!ctrl->lpddr) {
-+ reset_dram_dll(ctrl, channel, rank);
-+ udelay(1);
-+ }
-+ printk(BIOS_DEBUG, "\n");
-+ }
-+ printk(BIOS_DEBUG, "\n");
-+ }
-+
-+ /* Restore WDB after test */
-+ write_wdb_va_pat(ctrl, 0, BASIC_VA_PAT_SPREAD_8, 8, 0);
-+ program_wdb_lfsr(ctrl, false);
-+ mchbar_write32(DDR_DATA_OFFSET_TRAIN, 0);
-+
-+ /** TODO: Do full JEDEC init instead? **/
-+ io_reset();
-+ return status;
-+}
-+
-+static enum raminit_status verify_wl_width(const int32_t lwidth)
-+{
-+ if (lwidth <= 32) {
-+ /* Check if width is valid */
-+ printk(BIOS_ERR, "WrLevel: Width region (%d) too small\n", lwidth);
-+ return RAMINIT_STATUS_JWRL_FAILURE;
-+ }
-+ if (lwidth >= 96) {
-+ /* Since we're calibrating a phase, a too large region is a problem */
-+ printk(BIOS_ERR, "WrLevel: Width region (%d) too large\n", lwidth);
-+ return RAMINIT_STATUS_JWRL_FAILURE;
-+ }
-+ return 0;
-+}
-+
-+enum raminit_status train_jedec_write_leveling(struct sysinfo *ctrl)
-+{
-+ /*
-+ * Enabling WL mode causes DQS to toggle for 1024 QCLK.
-+ * Wait for this to stop. Round up to nearest microsecond.
-+ */
-+ const bool wl_long_delay = ctrl->lpddr;
-+ const uint32_t dqs_toggle_time = wl_long_delay ? 2048 : 1024;
-+ const uint32_t wait_time_us = DIV_ROUND_UP(ctrl->qclkps * dqs_toggle_time, 1000 * 1000);
-+
-+ const uint16_t wl_start = 192;
-+ const uint16_t wl_stop = 192 + 128;
-+ const uint16_t wl_step = 2;
-+
-+ /* Do not use cached MR values */
-+ const bool save_restore_mrs = ctrl->restore_mrs;
-+ ctrl->restore_mrs = 0;
-+
-+ /* Propagate delay values (without a write command) */
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ /* Propagate delay values from rank 0 to prevent assertion failures in RTL */
-+ union ddr_data_control_0_reg data_control_0 = {
-+ .raw = ctrl->dq_control_0[channel],
-+ };
-+ data_control_0.read_rf_rd = 0;
-+ data_control_0.read_rf_wr = 1;
-+ data_control_0.read_rf_rank = 0;
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ union ddr_data_control_2_reg data_control_2 = {
-+ .raw = ctrl->dq_control_2[channel][byte],
-+ };
-+ data_control_2.force_bias_on = 1;
-+ data_control_2.force_rx_on = 0;
-+ data_control_2.wl_long_delay = wl_long_delay;
-+ mchbar_write32(DQ_CONTROL_2(channel, byte), data_control_2.raw);
-+ }
-+ }
-+
-+ if (ctrl->lpddr)
-+ die("%s: Missing LPDDR support\n", __func__);
-+
-+ if (!ctrl->lpddr)
-+ ddr3_program_mr1(ctrl, 0, 1);
-+
-+ enum raminit_status status = RAMINIT_STATUS_SUCCESS;
-+ struct phase_train_data region_data[NUM_CHANNELS][NUM_LANES] = { 0 };
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (!does_rank_exist(ctrl, rank))
-+ continue;
-+
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ /** TODO: Differs for LPDDR **/
-+ uint16_t mr1reg = ctrl->mr1[channel][rank / 2];
-+ mr1reg &= ~MR1_QOFF_ENABLE;
-+ mr1reg |= MR1_WL_ENABLE;
-+ if (is_hsw_ult()) {
-+ mr1reg &= ~RTTNOM_MASK;
-+ mr1reg |= encode_ddr3_rttnom(120);
-+ } else if (ctrl->dpc[channel] == 2) {
-+ mr1reg &= ~RTTNOM_MASK;
-+ mr1reg |= encode_ddr3_rttnom(60);
-+ }
-+ reut_issue_mrs(ctrl, channel, BIT(rank), 1, mr1reg);
-+
-+ /* Assert ODT for myself */
-+ uint8_t odt_matrix = BIT(rank);
-+ if (ctrl->dpc[channel] == 2) {
-+ /* Assert ODT for non-target DIMM */
-+ const uint8_t other_dimm = ((rank + 2) / 2) & 1;
-+ odt_matrix |= BIT(2 * other_dimm);
-+ }
-+
-+ union reut_misc_odt_ctrl_reg reut_misc_odt_ctrl = {
-+ .raw = 0,
-+ };
-+ if (ctrl->lpddr) {
-+ /* Only one ODT pin for ULT */
-+ reut_misc_odt_ctrl.odt_on = 1;
-+ reut_misc_odt_ctrl.odt_override = 1;
-+ } else if (!is_hsw_ult()) {
-+ reut_misc_odt_ctrl.odt_on = odt_matrix;
-+ reut_misc_odt_ctrl.odt_override = 0xf;
-+ }
-+ mchbar_write32(REUT_ch_MISC_ODT_CTRL(channel), reut_misc_odt_ctrl.raw);
-+ }
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ /*
-+ * Enable write leveling mode in DDR and propagate delay
-+ * values (without a write command). Stay in WL mode.
-+ */
-+ union ddr_data_control_0_reg data_control_0 = {
-+ .raw = ctrl->dq_control_0[channel],
-+ };
-+ data_control_0.wl_training_mode = 1;
-+ data_control_0.tx_pi_on = 1;
-+ data_control_0.read_rf_rd = 0;
-+ data_control_0.read_rf_wr = 1;
-+ data_control_0.read_rf_rank = rank;
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
-+ }
-+ printk(BIOS_DEBUG, "\nRank %u\n", rank);
-+ printk(JWRL_PLOT, "Channel\t");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(JWRL_PLOT, "%u", channel);
-+ if (channel > 0)
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ printk(JWRL_PLOT, "\t");
-+ }
-+ printk(JWRL_PLOT, "\nByte");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ printk(JWRL_PLOT, "\t%u", byte);
-+ }
-+ printk(JWRL_PLOT, "\nWlDelay");
-+ for (uint16_t wl_delay = wl_start; wl_delay < wl_stop; wl_delay += wl_step) {
-+ printk(JWRL_PLOT, "\n %3u:", wl_delay);
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ update_txt(ctrl, channel, rank, byte, TXT_TXDQS,
-+ wl_delay);
-+ }
-+ }
-+ /* Wait for the first burst to finish */
-+ if (wl_delay == wl_start)
-+ udelay(wait_time_us);
-+
-+ io_reset();
-+ udelay(wait_time_us);
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ const uint32_t feedback =
-+ get_data_train_feedback(channel, byte);
-+ const bool pass = (feedback & 0x1ff) >= 16;
-+ printk(JWRL_PLOT, "\t%c%u", pass ? '.' : '#', feedback);
-+ phase_record_pass(
-+ &region_data[channel][byte],
-+ pass,
-+ wl_delay,
-+ wl_start,
-+ wl_step);
-+ }
-+ }
-+ }
-+ printk(JWRL_PLOT, "\n");
-+ printk(BIOS_DEBUG, "\n\tInitSt\tInitEn\tCurrSt\tCurrEn\tLargSt\tLargEn\n");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ printk(BIOS_DEBUG, "C%u\n", channel);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ struct phase_train_data *data = &region_data[channel][byte];
-+
-+ phase_append_initial_to_current(data, wl_start, wl_step);
-+ printk(BIOS_DEBUG, " B%u:\t%d\t%d\t%d\t%d\t%d\t%d\n",
-+ byte,
-+ data->initial.start,
-+ data->initial.end,
-+ data->current.start,
-+ data->current.end,
-+ data->largest.start,
-+ data->largest.end);
-+ }
-+ }
-+
-+ /*
-+ * Clean up after test. Very coarsely adjust for
-+ * any cycle errors. Program values for TxDQS.
-+ */
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ /* Clear ODT before MRS (JEDEC spec) */
-+ mchbar_write32(REUT_ch_MISC_ODT_CTRL(channel), 0);
-+
-+ /** TODO: Differs for LPDDR **/
-+ const uint16_t mr1reg = ctrl->mr1[channel][rank / 2] | MR1_QOFF_ENABLE;
-+ reut_issue_mrs(ctrl, channel, BIT(rank), 1, mr1reg);
-+
-+ printk(BIOS_DEBUG, "\nC%u.R%u: LftEdge Width\n", channel, rank);
-+ const bool rank_x16 = ctrl->dimms[channel][rank / 2].data.width == 16;
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ struct phase_train_data *data = &region_data[channel][byte];
-+ const int32_t lwidth = range_width(data->largest);
-+ int32_t tx_start = data->largest.start;
-+ printk(BIOS_DEBUG, " B%u: %d\t%d\n", byte, tx_start, lwidth);
-+ status = verify_wl_width(lwidth);
-+ if (status) {
-+ printk(BIOS_ERR,
-+ "WrLevel problems on channel %u, byte %u\n",
-+ channel, byte);
-+ goto clean_up;
-+ }
-+
-+ /* Align byte pairs if DIMM is x16 */
-+ if (rank_x16 && (byte & 1)) {
-+ const struct phase_train_data *const ref_data =
-+ &region_data[channel][byte - 1];
-+
-+ if (tx_start > ref_data->largest.start + 64)
-+ tx_start -= 128;
-+
-+ if (tx_start < ref_data->largest.start - 64)
-+ tx_start += 128;
-+ }
-+
-+ /* Fix for b4618067 - need to add 1 QCLK to DQS PI */
-+ if (is_hsw_ult())
-+ tx_start += 64;
-+
-+ assert(tx_start >= 0);
-+ ctrl->txdqs[channel][rank][byte] = tx_start;
-+ ctrl->tx_dq[channel][rank][byte] = tx_start + 32;
-+ update_txt(ctrl, channel, rank, byte, TXT_RESTORE, 0);
-+ }
-+ }
-+ printk(BIOS_DEBUG, "\n");
-+ }
-+
-+clean_up:
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), ctrl->dq_control_0[channel]);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ mchbar_write32(DQ_CONTROL_2(channel, byte),
-+ ctrl->dq_control_2[channel][byte]);
-+ }
-+ }
-+ if (!ctrl->lpddr)
-+ ddr3_program_mr1(ctrl, 0, 0);
-+
-+ ctrl->restore_mrs = save_restore_mrs;
-+
-+ if (status)
-+ return status;
-+
-+ /** TODO: If this step fails and dec_wrd is set, clear it and try again **/
-+ return train_jedec_write_leveling_cleanup(ctrl);
-+}
-diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
-index 6a31d3a32c..7c0b5a49de 100644
---- a/src/northbridge/intel/haswell/registers/mchbar.h
-+++ b/src/northbridge/intel/haswell/registers/mchbar.h
-@@ -121,6 +121,8 @@
-
- #define REUT_ch_ERR_DATA_MASK(ch) _MCMAIN_C(0x40d8, ch)
-
-+#define REUT_ch_ERR_MISC_STATUS(ch) _MCMAIN_C(0x40e8, ch)
-+
- #define REUT_ch_MISC_CKE_CTRL(ch) _MCMAIN_C(0x4190, ch)
- #define REUT_ch_MISC_ODT_CTRL(ch) _MCMAIN_C(0x4194, ch)
- #define REUT_ch_MISC_PAT_CADB_CTRL(ch) _MCMAIN_C(0x4198, ch)
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0044-haswell-NRI-Add-final-raminit-steps.patch b/config/coreboot/default/patches/0044-haswell-NRI-Add-final-raminit-steps.patch
deleted file mode 100644
index 62cae936..00000000
--- a/config/coreboot/default/patches/0044-haswell-NRI-Add-final-raminit-steps.patch
+++ /dev/null
@@ -1,570 +0,0 @@
-From 9d1b945702006db5678c5dc81699699bf6e6741a Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Sun, 8 May 2022 14:29:05 +0200
-Subject: [PATCH 44/51] haswell NRI: Add final raminit steps
-
-Implement the remaining raminit steps. Although many training steps are
-missing, this is enough to boot on the Asrock B85M Pro4.
-
-Change-Id: I94f3b65f0218d4da4fda4d84592dfd91f77f8f21
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- src/northbridge/intel/haswell/Kconfig | 4 +-
- .../intel/haswell/native_raminit/Makefile.mk | 1 +
- .../haswell/native_raminit/activate_mc.c | 388 ++++++++++++++++++
- .../haswell/native_raminit/raminit_main.c | 5 +-
- .../haswell/native_raminit/raminit_native.c | 5 +-
- .../haswell/native_raminit/raminit_native.h | 2 +
- .../haswell/native_raminit/reg_structs.h | 12 +
- .../intel/haswell/registers/mchbar.h | 7 +
- 8 files changed, 416 insertions(+), 8 deletions(-)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/activate_mc.c
-
-diff --git a/src/northbridge/intel/haswell/Kconfig b/src/northbridge/intel/haswell/Kconfig
-index 4b83a25bc1..c6ab27184e 100644
---- a/src/northbridge/intel/haswell/Kconfig
-+++ b/src/northbridge/intel/haswell/Kconfig
-@@ -11,12 +11,12 @@ config NORTHBRIDGE_INTEL_HASWELL
- if NORTHBRIDGE_INTEL_HASWELL
-
- config USE_NATIVE_RAMINIT
-- bool "[NOT WORKING] Use native raminit"
-+ bool "[NOT COMPLETE] Use native raminit"
- default n
- select HAVE_DEBUG_RAM_SETUP
- help
- Select if you want to use coreboot implementation of raminit rather than
-- MRC.bin. Currently incomplete and does not boot.
-+ MRC.bin. Currently incomplete and does not support S3 resume.
-
- config HASWELL_VBOOT_IN_BOOTBLOCK
- depends on VBOOT
-diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-index 40c2f5e014..d97da72890 100644
---- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-@@ -1,5 +1,6 @@
- ## SPDX-License-Identifier: GPL-2.0-or-later
-
-+romstage-y += activate_mc.c
- romstage-y += change_margin.c
- romstage-y += configure_mc.c
- romstage-y += ddr3.c
-diff --git a/src/northbridge/intel/haswell/native_raminit/activate_mc.c b/src/northbridge/intel/haswell/native_raminit/activate_mc.c
-new file mode 100644
-index 0000000000..78a7ad27ef
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/activate_mc.c
-@@ -0,0 +1,388 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <console/console.h>
-+#include <delay.h>
-+#include <device/pci_ops.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <timer.h>
-+#include <types.h>
-+
-+#include "raminit_native.h"
-+
-+static void update_internal_clocks_on(struct sysinfo *ctrl)
-+{
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ bool clocks_on = false;
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ const union ddr_data_control_1_reg data_control_1 = {
-+ .raw = ctrl->dq_control_1[channel][byte],
-+ };
-+ const int8_t o_on = data_control_1.odt_delay;
-+ const int8_t s_on = data_control_1.sense_amp_delay;
-+ const int8_t o_off = data_control_1.odt_duration;
-+ const int8_t s_off = data_control_1.sense_amp_duration;
-+ if (o_on + o_off >= 7 || s_on + s_off >= 7) {
-+ clocks_on = true;
-+ break;
-+ }
-+ }
-+ union ddr_data_control_0_reg data_control_0 = {
-+ .raw = ctrl->dq_control_0[channel],
-+ };
-+ data_control_0.internal_clocks_on = clocks_on;
-+ ctrl->dq_control_0[channel] = data_control_0.raw;
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
-+ }
-+}
-+
-+/* Switch off unused segments of the SDLL to save power */
-+static void update_sdll_length(struct sysinfo *ctrl)
-+{
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ uint8_t max_pi = 0;
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ const uint8_t rx_dqs_p = ctrl->rxdqsp[channel][rank][byte];
-+ const uint8_t rx_dqs_n = ctrl->rxdqsn[channel][rank][byte];
-+ max_pi = MAX(max_pi, MAX(rx_dqs_p, rx_dqs_n));
-+ }
-+ /* Update SDLL length for power savings */
-+ union ddr_data_control_1_reg data_control_1 = {
-+ .raw = ctrl->dq_control_1[channel][byte],
-+ };
-+ /* Calculate which segments to turn off */
-+ data_control_1.sdll_segment_disable = (7 - (max_pi >> 3)) & ~1;
-+ ctrl->dq_control_1[channel][byte] = data_control_1.raw;
-+ mchbar_write32(DQ_CONTROL_1(channel, byte), data_control_1.raw);
-+ }
-+ }
-+}
-+
-+static void set_rx_clk_stg_num(struct sysinfo *ctrl, const uint8_t channel)
-+{
-+ const uint8_t rcven_drift = ctrl->lpddr ? DIV_ROUND_UP(tDQSCK_DRIFT, ctrl->qclkps) : 1;
-+ uint8_t max_rcven = 0;
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ max_rcven = MAX(max_rcven, ctrl->rcven[channel][rank][byte] / 64);
-+ }
-+ const union ddr_data_control_1_reg ddr_data_control_1 = {
-+ .raw = ctrl->dq_control_1[channel][0],
-+ };
-+ const bool lpddr_long_odt = ddr_data_control_1.lpddr_long_odt_en;
-+ const uint8_t rcven_turnoff = max_rcven + 18 + 2 * rcven_drift + lpddr_long_odt;
-+ const union ddr_data_control_0_reg ddr_data_control_0 = {
-+ .raw = ctrl->dq_control_0[channel],
-+ };
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ union ddr_data_control_2_reg ddr_data_control_2 = {
-+ .raw = ctrl->dq_control_2[channel][byte],
-+ };
-+ if (ddr_data_control_0.odt_samp_extend_en) {
-+ if (ddr_data_control_2.rx_clk_stg_num < rcven_turnoff)
-+ ddr_data_control_2.rx_clk_stg_num = rcven_turnoff;
-+ } else {
-+ const int8_t o_on = ddr_data_control_1.odt_delay;
-+ const int8_t o_off = ddr_data_control_1.odt_duration;
-+ ddr_data_control_2.rx_clk_stg_num = MAX(17, o_on + o_off + 14);
-+ }
-+ ctrl->dq_control_2[channel][byte] = ddr_data_control_2.raw;
-+ mchbar_write32(DQ_CONTROL_2(channel, byte), ddr_data_control_2.raw);
-+ }
-+}
-+
-+#define SELF_REFRESH_IDLE_COUNT 0x200
-+
-+static void enter_sr(void)
-+{
-+ mchbar_write32(PM_SREF_CONFIG, SELF_REFRESH_IDLE_COUNT | BIT(16));
-+ udelay(1);
-+}
-+
-+enum power_down_mode {
-+ PDM_NO_PD = 0,
-+ PDM_APD = 1,
-+ PDM_PPD = 2,
-+ PDM_PPD_DLL_OFF = 6,
-+};
-+
-+static void power_down_config(struct sysinfo *ctrl)
-+{
-+ const enum power_down_mode pd_mode = ctrl->lpddr ? PDM_PPD : PDM_PPD_DLL_OFF;
-+ mchbar_write32(PM_PDWN_CONFIG, pd_mode << 12 | 0x40);
-+}
-+
-+static void train_power_modes_post(struct sysinfo *ctrl)
-+{
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ /* Adjust tCPDED and tPRPDEN */
-+ if (ctrl->mem_clock_mhz >= 933)
-+ ctrl->tc_bankrank_d[channel].tCPDED = 2;
-+
-+ if (ctrl->mem_clock_mhz >= 1066)
-+ ctrl->tc_bankrank_d[channel].tPRPDEN = 2;
-+
-+ mchbar_write32(TC_BANK_RANK_D_ch(channel), ctrl->tc_bankrank_d[channel].raw);
-+ }
-+ power_down_config(ctrl);
-+ mchbar_write32(MCDECS_CBIT, BIT(30)); /* dis_msg_clk_gate */
-+}
-+
-+static uint8_t compute_burst_end_odt_delay(const struct sysinfo *const ctrl)
-+{
-+ /* Must be disabled for LPDDR */
-+ if (ctrl->lpddr)
-+ return 0;
-+
-+ const uint8_t beod = MIN(7, DIV_ROUND_CLOSEST(14300 * 20 / 100, ctrl->qclkps));
-+ if (beod < 3)
-+ return 0;
-+
-+ if (beod < 4)
-+ return 4;
-+
-+ return beod;
-+}
-+
-+static void program_burst_end_odt_delay(struct sysinfo *ctrl)
-+{
-+ /* Program burst_end_odt_delay - it should be zero during training steps */
-+ const uint8_t beod = compute_burst_end_odt_delay(ctrl);
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ union ddr_data_control_1_reg ddr_data_control_1 = {
-+ .raw = ctrl->dq_control_1[channel][byte],
-+ };
-+ ddr_data_control_1.burst_end_odt_delay = beod;
-+ ctrl->dq_control_1[channel][byte] = ddr_data_control_1.raw;
-+ mchbar_write32(DQ_CONTROL_1(channel, byte), ddr_data_control_1.raw);
-+ }
-+ }
-+}
-+
-+/*
-+ * Return a random value to use for scrambler seeds. Try to use RDRAND
-+ * first and fall back to hardcoded values if RDRAND does not succeed.
-+ */
-+static uint16_t get_random_number(const uint8_t channel)
-+{
-+ /* The RDRAND instruction is only available 100k cycles after reset */
-+ for (size_t i = 0; i < 100000; i++) {
-+ uint32_t status;
-+ uint32_t random;
-+ /** TODO: Clean up asm **/
-+ __asm__ __volatile__(
-+ "\n\t .byte 0x0F, 0xC7, 0xF0"
-+ "\n\t movl %%eax, %0"
-+ "\n\t pushf"
-+ "\n\t pop %%eax"
-+ "\n\t movl %%eax, %1"
-+ : "=m"(random),
-+ "=m"(status)
-+ : /* No inputs */
-+ : "eax", "cc");
-+
-+ /* Only consider non-zero random values as valid */
-+ if (status & 1 && random)
-+ return random;
-+ }
-+
-+ /* https://xkcd.com/221 */
-+ if (channel)
-+ return 0x28f4;
-+ else
-+ return 0x893e;
-+}
-+
-+/* Work around "error: 'typeof' applied to a bit-field" */
-+static inline uint32_t max(const uint32_t a, const uint32_t b)
-+{
-+ return MAX(a, b);
-+}
-+
-+enum raminit_status activate_mc(struct sysinfo *ctrl)
-+{
-+ const bool enable_scrambling = true;
-+ const bool enable_cmd_tristate = true;
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ if (enable_scrambling && ctrl->stepping < STEPPING_C0) {
-+ /* Make sure tRDRD_(sr, dr, dd) are at least 6 for scrambler W/A */
-+ union tc_bank_rank_a_reg tc_bank_rank_a = {
-+ .raw = mchbar_read32(TC_BANK_RANK_A_ch(channel)),
-+ };
-+ tc_bank_rank_a.tRDRD_sr = max(tc_bank_rank_a.tRDRD_sr, 6);
-+ tc_bank_rank_a.tRDRD_dr = max(tc_bank_rank_a.tRDRD_dr, 6);
-+ tc_bank_rank_a.tRDRD_dd = max(tc_bank_rank_a.tRDRD_dd, 6);
-+ mchbar_write32(TC_BANK_RANK_A_ch(channel), tc_bank_rank_a.raw);
-+ }
-+ if (enable_scrambling) {
-+ const union ddr_scramble_reg ddr_scramble = {
-+ .scram_key = get_random_number(channel),
-+ .scram_en = 1,
-+ };
-+ mchbar_write32(DDR_SCRAMBLE_ch(channel), ddr_scramble.raw);
-+ }
-+ if (ctrl->tCMD == 1) {
-+ /* If we are in 1N mode, enable and set command rate limit to 3 */
-+ union mcmain_command_rate_limit_reg cmd_rate_limit = {
-+ .raw = mchbar_read32(COMMAND_RATE_LIMIT_ch(channel)),
-+ };
-+ cmd_rate_limit.enable_cmd_limit = 1;
-+ cmd_rate_limit.cmd_rate_limit = 3;
-+ mchbar_write32(COMMAND_RATE_LIMIT_ch(channel), cmd_rate_limit.raw);
-+ }
-+ if (enable_cmd_tristate) {
-+ /* Enable command tri-state at the end of training */
-+ union tc_bank_rank_a_reg tc_bank_rank_a = {
-+ .raw = mchbar_read32(TC_BANK_RANK_A_ch(channel)),
-+ };
-+ tc_bank_rank_a.cmd_3st_dis = 0;
-+ mchbar_write32(TC_BANK_RANK_A_ch(channel), tc_bank_rank_a.raw);
-+ }
-+ /* Set MC to normal mode and clean the ODT and CKE */
-+ mchbar_write32(REUT_ch_SEQ_CFG(channel), REUT_MODE_NOP << 12);
-+ /* Set again the rank occupancy */
-+ mchbar_write8(MC_INIT_STATE_ch(channel), ctrl->rankmap[channel]);
-+ if (ctrl->is_ecc) {
-+ /* Enable ECC I/O and logic */
-+ union mad_dimm_reg mad_dimm = {
-+ .raw = mchbar_read32(MAD_DIMM(channel)),
-+ };
-+ mad_dimm.ecc_mode = 3;
-+ mchbar_write32(MAD_DIMM(channel), mad_dimm.raw);
-+ }
-+ }
-+
-+ if (!is_hsw_ult())
-+ update_internal_clocks_on(ctrl);
-+
-+ update_sdll_length(ctrl);
-+
-+ program_burst_end_odt_delay(ctrl);
-+
-+ if (is_hsw_ult()) {
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ set_rx_clk_stg_num(ctrl, channel);
-+ }
-+ /** TODO: Program DDRPL_CR_DDR_TX_DELAY if Memory Trace is enabled **/
-+ }
-+
-+ /* Enable periodic COMP */
-+ mchbar_write32(M_COMP, (union pcu_comp_reg) {
-+ .comp_interval = COMP_INT,
-+ }.raw);
-+
-+ /* Enable the power mode before PCU starts working */
-+ train_power_modes_post(ctrl);
-+
-+ /* Set idle timer and self refresh enable bits */
-+ enter_sr();
-+
-+ /** FIXME: Do not hardcode power weights and RAPL settings **/
-+ mchbar_write32(0x5888, 0x00000d0d);
-+ mchbar_write32(0x5884, 0x00000004); /* 58.2 pJ */
-+
-+ mchbar_write32(0x58e0, 0);
-+ mchbar_write32(0x58e4, 0);
-+
-+ mchbar_write32(0x5890, 0xffff);
-+ mchbar_write32(0x5894, 0xffff);
-+ mchbar_write32(0x5898, 0xffff);
-+ mchbar_write32(0x589c, 0xffff);
-+ mchbar_write32(0x58d0, 0xffff);
-+ mchbar_write32(0x58d4, 0xffff);
-+ mchbar_write32(0x58d8, 0xffff);
-+ mchbar_write32(0x58dc, 0xffff);
-+
-+ /* Overwrite thermal parameters */
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ mchbar_write32(_MCMAIN_C(0x42ec, channel), 0x0000000f);
-+ mchbar_write32(_MCMAIN_C(0x42f0, channel), 0x00000009);
-+ mchbar_write32(_MCMAIN_C(0x42f4, channel), 0x00000093);
-+ mchbar_write32(_MCMAIN_C(0x42f8, channel), 0x00000087);
-+ mchbar_write32(_MCMAIN_C(0x42fc, channel), 0x000000de);
-+
-+ /** TODO: Differs for LPDDR **/
-+ mchbar_write32(PM_THRT_CKE_MIN_ch(channel), 0x30);
-+ }
-+ mchbar_write32(PCU_DDR_PTM_CTL, 0x40);
-+ return RAMINIT_STATUS_SUCCESS;
-+}
-+
-+static void mc_lockdown(void)
-+{
-+ /* Lock memory controller registers */
-+ mchbar_write32(MC_LOCK, 0x8f);
-+
-+ /* MPCOHTRK_GDXC_OCLA_ADDRESS_HI_LOCK is set when programming the memory map */
-+
-+ /* Lock memory map registers */
-+ pci_or_config16(HOST_BRIDGE, GGC, 1 << 0);
-+ pci_or_config32(HOST_BRIDGE, DPR, 1 << 0);
-+ pci_or_config32(HOST_BRIDGE, MESEG_LIMIT, 1 << 10);
-+ pci_or_config32(HOST_BRIDGE, REMAPBASE, 1 << 0);
-+ pci_or_config32(HOST_BRIDGE, REMAPLIMIT, 1 << 0);
-+ pci_or_config32(HOST_BRIDGE, TOM, 1 << 0);
-+ pci_or_config32(HOST_BRIDGE, TOUUD, 1 << 0);
-+ pci_or_config32(HOST_BRIDGE, BDSM, 1 << 0);
-+ pci_or_config32(HOST_BRIDGE, BGSM, 1 << 0);
-+ pci_or_config32(HOST_BRIDGE, TOLUD, 1 << 0);
-+}
-+
-+enum raminit_status raminit_done(struct sysinfo *ctrl)
-+{
-+ union mc_init_state_g_reg mc_init_state_g = {
-+ .raw = mchbar_read32(MC_INIT_STATE_G),
-+ };
-+ mc_init_state_g.refresh_enable = 1;
-+ mc_init_state_g.pu_mrc_done = 1;
-+ mc_init_state_g.mrc_done = 1;
-+ mchbar_write32(MC_INIT_STATE_G, mc_init_state_g.raw);
-+
-+ /* Lock the memory controller to enable normal operation */
-+ mc_lockdown();
-+
-+ /* Poll for mc_init_done_ack to make sure memory initialization is complete */
-+ printk(BIOS_DEBUG, "Waiting for mc_init_done acknowledgement... ");
-+
-+ struct stopwatch timer;
-+ stopwatch_init_msecs_expire(&timer, 2000);
-+ do {
-+ mc_init_state_g.raw = mchbar_read32(MC_INIT_STATE_G);
-+
-+ /* DRAM will NOT work without the acknowledgement. There is no hope. */
-+ if (stopwatch_expired(&timer))
-+ die("\nTimed out waiting for mc_init_done acknowledgement\n");
-+
-+ } while (mc_init_state_g.mc_init_done_ack == 0);
-+ printk(BIOS_DEBUG, "DONE!\n");
-+
-+ /* Provide some data for the graphics driver. Yes, it's hardcoded. */
-+ mchbar_write32(SSKPD + 0, 0x05a2404f);
-+ mchbar_write32(SSKPD + 4, 0x140000a0);
-+ return RAMINIT_STATUS_SUCCESS;
-+}
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-index 1ff23be615..3a65fb01fb 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-@@ -63,6 +63,8 @@ static const struct task_entry cold_boot[] = {
- { train_receive_enable, true, "RCVET", },
- { train_read_mpr, true, "RDMPRT", },
- { train_jedec_write_leveling, true, "JWRL", },
-+ { activate_mc, true, "ACTIVATE", },
-+ { raminit_done, true, "RAMINITEND", },
- };
-
- /* Return a generic stepping value to make stepping checks simpler */
-@@ -143,7 +145,4 @@ void raminit_main(const enum raminit_boot_mode bootmode)
-
- if (status != RAMINIT_STATUS_SUCCESS)
- die("Memory initialization was met with utmost failure and misery\n");
--
-- /** TODO: Implement the required magic **/
-- die("NATIVE RAMINIT: More Magic (tm) required.\n");
- }
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.c b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
-index 2fed93de5b..5f7ceec222 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.c
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
-@@ -199,8 +199,6 @@ void perform_raminit(const int s3resume)
- else
- me_status = ME_INIT_STATUS_SUCCESS;
-
-- /** TODO: Remove this once raminit is implemented **/
-- me_status = ME_INIT_STATUS_ERROR;
- intel_early_me_init_done(me_status);
- }
-
-@@ -214,7 +212,8 @@ void perform_raminit(const int s3resume)
- }
-
- /* Save training data on non-S3 resumes */
-- if (!s3resume)
-+ /** TODO: Enable this once training data is populated **/
-+ if (0 && !s3resume)
- save_mrc_data(&md);
-
- /** TODO: setup_sdram_meminfo **/
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index d6b11b9d3c..a0a913f926 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -448,6 +448,8 @@ enum raminit_status do_jedec_init(struct sysinfo *ctrl);
- enum raminit_status train_receive_enable(struct sysinfo *ctrl);
- enum raminit_status train_read_mpr(struct sysinfo *ctrl);
- enum raminit_status train_jedec_write_leveling(struct sysinfo *ctrl);
-+enum raminit_status activate_mc(struct sysinfo *ctrl);
-+enum raminit_status raminit_done(struct sysinfo *ctrl);
-
- void configure_timings(struct sysinfo *ctrl);
- void configure_refresh(struct sysinfo *ctrl);
-diff --git a/src/northbridge/intel/haswell/native_raminit/reg_structs.h b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-index a0e36ed082..0d9aaa1f7c 100644
---- a/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-+++ b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
-@@ -294,6 +294,18 @@ union ddr_cke_ctl_controls_reg {
- uint32_t raw;
- };
-
-+union ddr_scramble_reg {
-+ struct __packed {
-+ uint32_t scram_en : 1; // Bits 0:0
-+ uint32_t scram_key : 16; // Bits 16:1
-+ uint32_t clk_gate_ab : 2; // Bits 18:17
-+ uint32_t clk_gate_c : 2; // Bits 20:19
-+ uint32_t en_dbi_ab : 1; // Bits 21:21
-+ uint32_t : 10; // Bits 31:17
-+ };
-+ uint32_t raw;
-+};
-+
- union ddr_scram_misc_control_reg {
- struct __packed {
- uint32_t wl_wake_cycles : 2; // Bits 1:0
-diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
-index 7c0b5a49de..49a215aa71 100644
---- a/src/northbridge/intel/haswell/registers/mchbar.h
-+++ b/src/northbridge/intel/haswell/registers/mchbar.h
-@@ -20,6 +20,7 @@
-
- #define DDR_DATA_TRAIN_FEEDBACK(ch, byte) _DDRIO_C_R_B(0x0054, ch, 0, byte)
-
-+#define DQ_CONTROL_1(ch, byte) _DDRIO_C_R_B(0x0060, ch, 0, byte)
- #define DQ_CONTROL_2(ch, byte) _DDRIO_C_R_B(0x0064, ch, 0, byte)
- #define DDR_DATA_OFFSET_TRAIN_ch_b(ch, byte) _DDRIO_C_R_B(0x0070, ch, 0, byte)
- #define DQ_CONTROL_0(ch, byte) _DDRIO_C_R_B(0x0074, ch, 0, byte)
-@@ -147,6 +148,8 @@
- #define QCLK_ch_LDAT_SDAT(ch) _MCMAIN_C(0x42d4, ch)
- #define QCLK_ch_LDAT_DATA_IN_x(ch, x) _MCMAIN_C_X(0x42dc, ch, x) /* x in 0 .. 1 */
-
-+#define PM_THRT_CKE_MIN_ch(ch) _MCMAIN_C(0x4328, ch)
-+
- #define REUT_GLOBAL_CTL 0x4800
- #define REUT_GLOBAL_ERR 0x4804
-
-@@ -175,6 +178,8 @@
-
- #define MCSCHEDS_DFT_MISC 0x4c30
-
-+#define PM_PDWN_CONFIG 0x4cb0
-+
- #define REUT_ERR_DATA_STATUS 0x4ce0
-
- #define REUT_MISC_CKE_CTRL 0x4d90
-@@ -186,8 +191,10 @@
- #define MAD_CHNL 0x5000 /* Address Decoder Channel Configuration */
- #define MAD_DIMM(ch) (0x5004 + (ch) * 4)
- #define MAD_ZR 0x5014
-+#define MCDECS_CBIT 0x501c
- #define MC_INIT_STATE_G 0x5030
- #define MRC_REVISION 0x5034 /* MRC Revision */
-+#define PM_SREF_CONFIG 0x5060
-
- #define RCOMP_TIMER 0x5084
-
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0045-Haswell-NRI-Implement-fast-boot-path.patch b/config/coreboot/default/patches/0045-Haswell-NRI-Implement-fast-boot-path.patch
deleted file mode 100644
index af614a5f..00000000
--- a/config/coreboot/default/patches/0045-Haswell-NRI-Implement-fast-boot-path.patch
+++ /dev/null
@@ -1,722 +0,0 @@
-From b6b89013630d535b68a005cede9e2540f273f4e7 Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Sat, 13 Apr 2024 01:16:30 +0200
-Subject: [PATCH 45/51] Haswell NRI: Implement fast boot path
-
-When the memory configuration hasn't changed, there is no need to do
-full memory training. Instead, boot firmware can use saved training
-data to reinitialise the memory controller and memory.
-
-Unlike native RAM init for other platforms, Haswell does not save the
-main structure (the "mighty ctrl" struct) to flash. Instead, separate
-structures define the data to be saved, which can be smaller than the
-main structure.
-
-This makes S3 suspend and resume work: RAM contents MUST be preserved
-for a S3 resume to succeed, but RAM training destroys RAM contents.
-
-Change-Id: I06f6cd39ceecdca104fae89159f28e85cf7ff4e6
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../intel/haswell/native_raminit/Makefile.mk | 1 +
- .../haswell/native_raminit/activate_mc.c | 17 +
- .../intel/haswell/native_raminit/ddr3.c | 41 ++
- .../haswell/native_raminit/raminit_main.c | 34 +-
- .../haswell/native_raminit/raminit_native.c | 30 +-
- .../haswell/native_raminit/raminit_native.h | 18 +
- .../haswell/native_raminit/save_restore.c | 387 ++++++++++++++++++
- 7 files changed, 504 insertions(+), 24 deletions(-)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/save_restore.c
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-index d97da72890..8fdd17c542 100644
---- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-@@ -13,6 +13,7 @@ romstage-y += raminit_main.c
- romstage-y += raminit_native.c
- romstage-y += ranges.c
- romstage-y += reut.c
-+romstage-y += save_restore.c
- romstage-y += setup_wdb.c
- romstage-y += spd_bitmunching.c
- romstage-y += testing_io.c
-diff --git a/src/northbridge/intel/haswell/native_raminit/activate_mc.c b/src/northbridge/intel/haswell/native_raminit/activate_mc.c
-index 78a7ad27ef..0b3eb917da 100644
---- a/src/northbridge/intel/haswell/native_raminit/activate_mc.c
-+++ b/src/northbridge/intel/haswell/native_raminit/activate_mc.c
-@@ -333,6 +333,23 @@ enum raminit_status activate_mc(struct sysinfo *ctrl)
- return RAMINIT_STATUS_SUCCESS;
- }
-
-+enum raminit_status normal_state(struct sysinfo *ctrl)
-+{
-+ /* Enable periodic COMP */
-+ mchbar_write32(M_COMP, (union pcu_comp_reg) {
-+ .comp_interval = COMP_INT,
-+ }.raw);
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ /* Set MC to normal mode and clean the ODT and CKE */
-+ mchbar_write32(REUT_ch_SEQ_CFG(channel), REUT_MODE_NOP << 12);
-+ }
-+ power_down_config(ctrl);
-+ return RAMINIT_STATUS_SUCCESS;
-+}
-+
- static void mc_lockdown(void)
- {
- /* Lock memory controller registers */
-diff --git a/src/northbridge/intel/haswell/native_raminit/ddr3.c b/src/northbridge/intel/haswell/native_raminit/ddr3.c
-index 6ddb11488b..9b6368edb1 100644
---- a/src/northbridge/intel/haswell/native_raminit/ddr3.c
-+++ b/src/northbridge/intel/haswell/native_raminit/ddr3.c
-@@ -2,6 +2,7 @@
-
- #include <assert.h>
- #include <console/console.h>
-+#include <delay.h>
- #include <northbridge/intel/haswell/haswell.h>
- #include <types.h>
-
-@@ -215,3 +216,43 @@ enum raminit_status ddr3_jedec_init(struct sysinfo *ctrl)
- ddr3_program_mr0(ctrl, 1);
- return reut_issue_zq(ctrl, ctrl->chanmap, ZQ_INIT);
- }
-+
-+enum raminit_status exit_selfrefresh(struct sysinfo *ctrl)
-+{
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ /* Fields in ctrl aren't populated on a warm boot */
-+ union ddr_data_control_0_reg data_control_0 = {
-+ .raw = mchbar_read32(DQ_CONTROL_0(channel, 0)),
-+ };
-+ data_control_0.read_rf_rd = 1;
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ data_control_0.read_rf_rank = rank;
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
-+ }
-+ }
-+
-+ /* Time needed to stabilize the DCLK (~6 us) */
-+ udelay(6);
-+
-+ /* Pull the DIMMs out of self refresh by asserting CKE high */
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ const union reut_misc_cke_ctrl_reg reut_misc_cke_ctrl = {
-+ .cke_on = ctrl->rankmap[channel],
-+ };
-+ mchbar_write32(REUT_ch_MISC_CKE_CTRL(channel), reut_misc_cke_ctrl.raw);
-+ }
-+ mchbar_write32(REUT_MISC_ODT_CTRL, 0);
-+
-+ const enum raminit_status status = reut_issue_zq(ctrl, ctrl->chanmap, ZQ_LONG);
-+ if (status) {
-+ /* ZQCL errors don't seem to be a fatal problem here */
-+ printk(BIOS_ERR, "ZQ Long failed during S3 resume or warm reset flow\n");
-+ }
-+ return RAMINIT_STATUS_SUCCESS;
-+}
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-index 3a65fb01fb..056dde1adc 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-@@ -64,6 +64,22 @@ static const struct task_entry cold_boot[] = {
- { train_read_mpr, true, "RDMPRT", },
- { train_jedec_write_leveling, true, "JWRL", },
- { activate_mc, true, "ACTIVATE", },
-+ { save_training_values, true, "SAVE_TRAIN", },
-+ { save_non_training, true, "SAVE_NONT", },
-+ { raminit_done, true, "RAMINITEND", },
-+};
-+
-+static const struct task_entry fast_boot[] = {
-+ { collect_spd_info, true, "PROCSPD", },
-+ { restore_non_training, true, "RST_NONT", },
-+ { initialise_mpll, true, "INITMPLL", },
-+ { configure_mc, true, "CONFMC", },
-+ { configure_memory_map, true, "MEMMAP", },
-+ { do_jedec_init, true, "JEDECINIT", },
-+ { pre_training, true, "PRETRAIN", },
-+ { restore_training_values, true, "RST_TRAIN", },
-+ { exit_selfrefresh, true, "EXIT_SR", },
-+ { normal_state, true, "NORMALMODE", },
- { raminit_done, true, "RAMINITEND", },
- };
-
-@@ -102,11 +118,11 @@ static void initialize_ctrl(struct sysinfo *ctrl)
- ctrl->bootmode = bootmode;
- }
-
--static enum raminit_status try_raminit(struct sysinfo *ctrl)
-+static enum raminit_status try_raminit(
-+ struct sysinfo *ctrl,
-+ const struct task_entry *const schedule,
-+ const size_t length)
- {
-- const struct task_entry *const schedule = cold_boot;
-- const size_t length = ARRAY_SIZE(cold_boot);
--
- enum raminit_status status = RAMINIT_STATUS_UNSPECIFIED_ERROR;
-
- for (size_t i = 0; i < length; i++) {
-@@ -140,8 +156,16 @@ void raminit_main(const enum raminit_boot_mode bootmode)
- mighty_ctrl.bootmode = bootmode;
- initialize_ctrl(&mighty_ctrl);
-
-+ enum raminit_status status = RAMINIT_STATUS_UNSPECIFIED_ERROR;
-+
-+ if (bootmode != BOOTMODE_COLD) {
-+ status = try_raminit(&mighty_ctrl, fast_boot, ARRAY_SIZE(fast_boot));
-+ if (status == RAMINIT_STATUS_SUCCESS)
-+ return;
-+ }
-+
- /** TODO: Try more than once **/
-- enum raminit_status status = try_raminit(&mighty_ctrl);
-+ status = try_raminit(&mighty_ctrl, cold_boot, ARRAY_SIZE(cold_boot));
-
- if (status != RAMINIT_STATUS_SUCCESS)
- die("Memory initialization was met with utmost failure and misery\n");
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.c b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
-index 5f7ceec222..3ad8ce29e7 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.c
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
-@@ -54,23 +54,17 @@ static bool early_init_native(enum raminit_boot_mode bootmode)
- return cpu_replaced;
- }
-
--#define MRC_CACHE_VERSION 1
--
--struct mrc_data {
-- const void *buffer;
-- size_t buffer_len;
--};
--
--static void save_mrc_data(struct mrc_data *md)
-+static void save_mrc_data(void)
- {
-- mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION, md->buffer, md->buffer_len);
-+ mrc_cache_stash_data(MRC_TRAINING_DATA, reg_frame_rev(),
-+ reg_frame_ptr(), reg_frame_size());
- }
-
- static struct mrc_data prepare_mrc_cache(void)
- {
- struct mrc_data md = {0};
- md.buffer = mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
-- MRC_CACHE_VERSION,
-+ reg_frame_rev(),
- &md.buffer_len);
- return md;
- }
-@@ -94,14 +88,15 @@ static void raminit_reset(void)
- }
-
- static enum raminit_boot_mode do_actual_raminit(
-- struct mrc_data *md,
- const bool s3resume,
- const bool cpu_replaced,
- const enum raminit_boot_mode orig_bootmode)
- {
-+ struct mrc_data md = prepare_mrc_cache();
-+
- enum raminit_boot_mode bootmode = orig_bootmode;
-
-- bool save_data_valid = md->buffer && md->buffer_len == USHRT_MAX; /** TODO: sizeof() **/
-+ bool save_data_valid = md.buffer && md.buffer_len == reg_frame_size();
-
- if (s3resume) {
- if (bootmode == BOOTMODE_COLD) {
-@@ -154,7 +149,7 @@ static enum raminit_boot_mode do_actual_raminit(
- assert(save_data_valid != (bootmode == BOOTMODE_COLD));
- if (save_data_valid) {
- printk(BIOS_INFO, "Using cached memory parameters\n");
-- die("RAMINIT: Fast boot is not yet implemented\n");
-+ memcpy(reg_frame_ptr(), md.buffer, reg_frame_size());
- }
- printk(RAM_DEBUG, "Initial bootmode: %s\n", bm_names[orig_bootmode]);
- printk(RAM_DEBUG, "Current bootmode: %s\n", bm_names[bootmode]);
-@@ -181,10 +176,8 @@ void perform_raminit(const int s3resume)
- wait_txt_clear();
- wrmsr(0x2e6, (msr_t) {.lo = 0, .hi = 0});
-
-- struct mrc_data md = prepare_mrc_cache();
--
- const enum raminit_boot_mode bootmode =
-- do_actual_raminit(&md, s3resume, cpu_replaced, orig_bootmode);
-+ do_actual_raminit(s3resume, cpu_replaced, orig_bootmode);
-
- /** TODO: report_memory_config **/
-
-@@ -212,9 +205,8 @@ void perform_raminit(const int s3resume)
- }
-
- /* Save training data on non-S3 resumes */
-- /** TODO: Enable this once training data is populated **/
-- if (0 && !s3resume)
-- save_mrc_data(&md);
-+ if (!s3resume)
-+ save_mrc_data();
-
- /** TODO: setup_sdram_meminfo **/
- }
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index a0a913f926..2ac16eaad3 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -170,6 +170,8 @@ enum regfile_mode {
- REG_FILE_USE_CURRENT, /* Used when changing parameters after the test */
- };
-
-+struct register_save_frame;
-+
- struct wdb_pat {
- uint32_t start_ptr; /* Starting pointer in WDB */
- uint32_t stop_ptr; /* Stopping pointer in WDB */
-@@ -220,6 +222,7 @@ enum raminit_status {
- RAMINIT_STATUS_RCVEN_FAILURE,
- RAMINIT_STATUS_RMPR_FAILURE,
- RAMINIT_STATUS_JWRL_FAILURE,
-+ RAMINIT_STATUS_INVALID_CACHE,
- RAMINIT_STATUS_UNSPECIFIED_ERROR, /** TODO: Deprecated in favor of specific values **/
- };
-
-@@ -229,6 +232,11 @@ enum generic_stepping {
- STEPPING_C0 = 3,
- };
-
-+struct mrc_data {
-+ const void *buffer;
-+ size_t buffer_len;
-+};
-+
- struct raminit_dimm_info {
- spd_ddr3_raw_data raw_spd;
- struct dimm_attr_ddr3_st data;
-@@ -448,12 +456,22 @@ enum raminit_status do_jedec_init(struct sysinfo *ctrl);
- enum raminit_status train_receive_enable(struct sysinfo *ctrl);
- enum raminit_status train_read_mpr(struct sysinfo *ctrl);
- enum raminit_status train_jedec_write_leveling(struct sysinfo *ctrl);
-+enum raminit_status save_training_values(struct sysinfo *ctrl);
-+enum raminit_status restore_training_values(struct sysinfo *ctrl);
-+enum raminit_status save_non_training(struct sysinfo *ctrl);
-+enum raminit_status restore_non_training(struct sysinfo *ctrl);
-+enum raminit_status exit_selfrefresh(struct sysinfo *ctrl);
-+enum raminit_status normal_state(struct sysinfo *ctrl);
- enum raminit_status activate_mc(struct sysinfo *ctrl);
- enum raminit_status raminit_done(struct sysinfo *ctrl);
-
- void configure_timings(struct sysinfo *ctrl);
- void configure_refresh(struct sysinfo *ctrl);
-
-+struct register_save_frame *reg_frame_ptr(void);
-+size_t reg_frame_size(void);
-+uint32_t reg_frame_rev(void);
-+
- uint32_t get_tCKE(uint32_t mem_clock_mhz, bool lpddr);
- uint32_t get_tXPDLL(uint32_t mem_clock_mhz);
- uint32_t get_tAONPD(uint32_t mem_clock_mhz);
-diff --git a/src/northbridge/intel/haswell/native_raminit/save_restore.c b/src/northbridge/intel/haswell/native_raminit/save_restore.c
-new file mode 100644
-index 0000000000..f1f50e3ff8
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/save_restore.c
-@@ -0,0 +1,387 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <assert.h>
-+#include <console/console.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <types.h>
-+
-+#include "raminit_native.h"
-+
-+uint32_t reg_frame_rev(void)
-+{
-+ /*
-+ * Equivalent to MRC_CACHE_REVISION, but hidden via abstraction.
-+ * The structures that get saved to flash are contained within
-+ * this translation unit, so changes outside this file shouldn't
-+ * require invalidating the cache.
-+ */
-+ return 1;
-+}
-+
-+struct register_save {
-+ uint16_t lower;
-+ uint16_t upper;
-+};
-+
-+/** TODO: Haswell DDRIO aliases writes: 0x80 .. 0xff => 0x00 .. 0x7f **/
-+static const struct register_save ddrio_per_byte_list[] = {
-+ {0x0000, 0x003c}, /* 16 registers */
-+// {0x0048, 0x0084}, /* 16 registers */ /** TODO: BDW support **/
-+ {0x0048, 0x004c}, /* 2 registers */
-+ {0x005c, 0x0078}, /* 8 registers */
-+};
-+#define DDRIO_PER_BYTE_REGISTER_COUNT (16 + 2 + 8)
-+
-+static const struct register_save ddrio_per_ch_list[] = {
-+ /* CKE */
-+ {0x1204, 0x1208}, /* 2 registers */
-+ {0x1214, 0x121c}, /* 3 registers */
-+ /* CMD North */
-+ {0x1404, 0x140c}, /* 3 registers */
-+ /* CLK */
-+ {0x1808, 0x1810}, /* 3 registers */
-+ /* CMD South */
-+ {0x1a04, 0x1a0c}, /* 3 registers */
-+ /* CTL */
-+ {0x1c14, 0x1c1c}, /* 3 registers */
-+};
-+#define DDRIO_PER_CH_REGISTER_COUNT (2 + 3 * 5)
-+
-+static const struct register_save ddrio_common_list[] = {
-+ {0x2000, 0x2008}, /* 3 registers */
-+ {0x3a14, 0x3a1c}, /* 3 registers */
-+ {0x3a24, 0x3a24}, /* 1 registers */
-+};
-+
-+#define DDRIO_COMMON_REGISTER_COUNT (3 + 3 + 1)
-+
-+static const struct register_save mcmain_per_ch_list[] = {
-+ {0x4000, 0x4014}, /* 6 registers */
-+ {0x4024, 0x4028}, /* 2 registers */
-+ {0x40d0, 0x40d0}, /* 1 registers */
-+ {0x4220, 0x4224}, /* 2 registers */
-+ {0x4294, 0x4294}, /* 1 registers */
-+ {0x429c, 0x42a0}, /* 2 registers */
-+ {0x42ec, 0x42fc}, /* 5 registers */
-+ {0x4328, 0x4328}, /* 1 registers */
-+ {0x438c, 0x4390}, /* 2 registers */
-+};
-+#define MCMAIN_PER_CH_REGISTER_COUNT (6 + 2 + 1 + 2 + 1 + 2 + 5 + 1 + 2)
-+
-+static const struct register_save misc_common_list[] = {
-+ {0x5884, 0x5888}, /* 2 registers */
-+ {0x5890, 0x589c}, /* 4 registers */
-+ {0x58a4, 0x58a4}, /* 1 registers */
-+ {0x58d0, 0x58e4}, /* 6 registers */
-+ {0x5880, 0x5880}, /* 1 registers */
-+ {0x5000, 0x50dc}, /* 56 registers */
-+ {0x59b8, 0x59b8} /* 1 registers */
-+};
-+#define MISC_COMMON_REGISTER_COUNT (2 + 4 + 1 + 6 + 1 + 56 + 1)
-+
-+struct save_params {
-+ bool is_initialised;
-+
-+ /* Memory base frequency, either 100 or 133 MHz */
-+ uint8_t base_freq;
-+
-+ /* Multiplier */
-+ uint32_t multiplier;
-+
-+ /* Memory clock in MHz */
-+ uint32_t mem_clock_mhz;
-+
-+ /* Memory clock in femtoseconds */
-+ uint32_t mem_clock_fs;
-+
-+ /* Quadrature clock in picoseconds */
-+ uint16_t qclkps;
-+
-+ /* Bitfield of supported CAS latencies */
-+ uint16_t cas_supported;
-+
-+ /* CPUID value */
-+ uint32_t cpu;
-+
-+ /* Cached CPU stepping value */
-+ uint8_t stepping;
-+
-+ uint16_t vdd_mv;
-+
-+ union dimm_flags_ddr3_st flags;
-+
-+ /* Except for tCK, everything is stored in DCLKs */
-+ uint32_t tCK;
-+ uint32_t tAA;
-+ uint32_t tWR;
-+ uint32_t tRCD;
-+ uint32_t tRRD;
-+ uint32_t tRP;
-+ uint32_t tRAS;
-+ uint32_t tRC;
-+ uint32_t tRFC;
-+ uint32_t tWTR;
-+ uint32_t tRTP;
-+ uint32_t tFAW;
-+ uint32_t tCWL;
-+ uint32_t tCMD;
-+
-+ uint32_t tREFI;
-+ uint32_t tXP;
-+
-+ uint8_t lpddr_cke_rank_map[NUM_CHANNELS];
-+
-+ struct raminit_dimm_info dimms[NUM_CHANNELS][NUM_SLOTS];
-+
-+ uint8_t chanmap;
-+
-+ uint32_t channel_size_mb[NUM_CHANNELS];
-+
-+ /* DIMMs per channel */
-+ uint8_t dpc[NUM_CHANNELS];
-+
-+ uint8_t rankmap[NUM_CHANNELS];
-+
-+ /* Whether a rank is mirrored or not (only rank 1 of each DIMM can be) */
-+ uint8_t rank_mirrored[NUM_CHANNELS];
-+
-+ /*
-+ * FIXME: LPDDR support is incomplete. The largest chunks are missing,
-+ * but some LPDDR-specific variations in algorithms have been handled.
-+ * LPDDR-specific functions have stubs which will halt upon execution.
-+ */
-+ bool lpddr;
-+
-+ uint8_t lanes;
-+
-+ /* FIXME: ECC support missing */
-+ bool is_ecc;
-+};
-+
-+struct register_save_frame {
-+ uint32_t ddrio_per_byte[NUM_CHANNELS][NUM_LANES][DDRIO_PER_BYTE_REGISTER_COUNT];
-+ uint32_t ddrio_per_ch[NUM_CHANNELS][DDRIO_PER_CH_REGISTER_COUNT];
-+ uint32_t ddrio_common[DDRIO_COMMON_REGISTER_COUNT];
-+ uint32_t mcmain_per_ch[NUM_CHANNELS][MCMAIN_PER_CH_REGISTER_COUNT];
-+ uint32_t misc_common[MISC_COMMON_REGISTER_COUNT];
-+ struct save_params params;
-+};
-+
-+struct register_save_frame *reg_frame_ptr(void)
-+{
-+ /* The chonky register save frame struct, used for fast boot and S3 resume */
-+ static struct register_save_frame register_frame = { 0 };
-+ return &register_frame;
-+}
-+
-+size_t reg_frame_size(void)
-+{
-+ return sizeof(struct register_save_frame);
-+}
-+
-+typedef void (*reg_func_t)(const uint16_t offset, uint32_t *const value);
-+
-+static void save_value(const uint16_t offset, uint32_t *const value)
-+{
-+ *value = mchbar_read32(offset);
-+}
-+
-+static void restore_value(const uint16_t offset, uint32_t *const value)
-+{
-+ mchbar_write32(offset, *value);
-+}
-+
-+static void save_restore(
-+ uint32_t *reg_frame,
-+ const uint16_t g_offset,
-+ const struct register_save *reg_save_list,
-+ const size_t reg_save_length,
-+ reg_func_t handle_reg)
-+{
-+ for (size_t i = 0; i < reg_save_length; i++) {
-+ const struct register_save *entry = &reg_save_list[i];
-+ for (uint16_t offset = entry->lower; offset <= entry->upper; offset += 4) {
-+ handle_reg(offset + g_offset, reg_frame++);
-+ }
-+ }
-+}
-+
-+static void save_restore_all(struct register_save_frame *reg_frame, reg_func_t handle_reg)
-+{
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ for (uint8_t byte = 0; byte < NUM_LANES; byte++) {
-+ const uint16_t g_offset = _DDRIO_C_R_B(0, channel, 0, byte);
-+ save_restore(
-+ reg_frame->ddrio_per_byte[channel][byte],
-+ g_offset,
-+ ddrio_per_byte_list,
-+ ARRAY_SIZE(ddrio_per_byte_list),
-+ handle_reg);
-+ }
-+ }
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ const uint16_t g_offset = _DDRIO_C_R_B(0, channel, 0, 0);
-+ save_restore(
-+ reg_frame->ddrio_per_ch[channel],
-+ g_offset,
-+ ddrio_per_ch_list,
-+ ARRAY_SIZE(ddrio_per_ch_list),
-+ handle_reg);
-+ }
-+ save_restore(
-+ reg_frame->ddrio_common,
-+ 0,
-+ ddrio_common_list,
-+ ARRAY_SIZE(ddrio_common_list),
-+ handle_reg);
-+
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ const uint16_t g_offset = _MCMAIN_C(0, channel);
-+ save_restore(
-+ reg_frame->mcmain_per_ch[channel],
-+ g_offset,
-+ mcmain_per_ch_list,
-+ ARRAY_SIZE(mcmain_per_ch_list),
-+ handle_reg);
-+ }
-+ save_restore(
-+ reg_frame->misc_common,
-+ 0,
-+ misc_common_list,
-+ ARRAY_SIZE(misc_common_list),
-+ handle_reg);
-+}
-+
-+enum raminit_status save_training_values(struct sysinfo *ctrl)
-+{
-+ save_restore_all(reg_frame_ptr(), save_value);
-+ return RAMINIT_STATUS_SUCCESS;
-+}
-+
-+enum raminit_status restore_training_values(struct sysinfo *ctrl)
-+{
-+ save_restore_all(reg_frame_ptr(), restore_value);
-+ return RAMINIT_STATUS_SUCCESS;
-+}
-+
-+enum raminit_status save_non_training(struct sysinfo *ctrl)
-+{
-+ struct register_save_frame *reg_frame = reg_frame_ptr();
-+ struct save_params *params = &reg_frame->params;
-+
-+ params->is_initialised = true;
-+
-+ params->base_freq = ctrl->base_freq;
-+ params->multiplier = ctrl->multiplier;
-+ params->mem_clock_mhz = ctrl->mem_clock_mhz;
-+ params->mem_clock_fs = ctrl->mem_clock_fs;
-+ params->qclkps = ctrl->qclkps;
-+ params->cas_supported = ctrl->cas_supported;
-+ params->cpu = ctrl->cpu;
-+ params->stepping = ctrl->stepping;
-+ params->vdd_mv = ctrl->vdd_mv;
-+ params->flags = ctrl->flags;
-+
-+ params->tCK = ctrl->tCK;
-+ params->tAA = ctrl->tAA;
-+ params->tWR = ctrl->tWR;
-+ params->tRCD = ctrl->tRCD;
-+ params->tRRD = ctrl->tRRD;
-+ params->tRP = ctrl->tRP;
-+ params->tRAS = ctrl->tRAS;
-+ params->tRC = ctrl->tRC;
-+ params->tRFC = ctrl->tRFC;
-+ params->tWTR = ctrl->tWTR;
-+ params->tRTP = ctrl->tRTP;
-+ params->tFAW = ctrl->tFAW;
-+ params->tCWL = ctrl->tCWL;
-+ params->tCMD = ctrl->tCMD;
-+ params->tREFI = ctrl->tREFI;
-+ params->tXP = ctrl->tXP;
-+
-+ params->chanmap = ctrl->chanmap;
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ params->lpddr_cke_rank_map[channel] = ctrl->lpddr_cke_rank_map[channel];
-+ for (uint8_t slot = 0; slot < NUM_SLOTS; slot++)
-+ params->dimms[channel][slot] = ctrl->dimms[channel][slot];
-+ }
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ params->dpc[channel] = ctrl->dpc[channel];
-+ params->rankmap[channel] = ctrl->rankmap[channel];
-+ params->rank_mirrored[channel] = ctrl->rank_mirrored[channel];
-+ params->channel_size_mb[channel] = ctrl->channel_size_mb[channel];
-+ }
-+ params->lpddr = ctrl->lpddr;
-+ params->lanes = ctrl->lanes;
-+ params->is_ecc = ctrl->is_ecc;
-+ return RAMINIT_STATUS_SUCCESS;
-+}
-+
-+#define RAMINIT_COMPARE(_s1, _s2) \
-+ ((sizeof(_s1) == sizeof(_s2)) && !memcmp(_s1, _s2, sizeof(_s1)))
-+
-+enum raminit_status restore_non_training(struct sysinfo *ctrl)
-+{
-+ struct register_save_frame *reg_frame = reg_frame_ptr();
-+ struct save_params *params = &reg_frame->params;
-+
-+ if (!params->is_initialised) {
-+ printk(BIOS_WARNING, "Cannot fast boot: saved data is invalid\n");
-+ return RAMINIT_STATUS_INVALID_CACHE;
-+ }
-+
-+ if (!RAMINIT_COMPARE(ctrl->dimms, params->dimms)) {
-+ printk(BIOS_WARNING, "Cannot fast boot: DIMMs have changed\n");
-+ return RAMINIT_STATUS_INVALID_CACHE;
-+ }
-+
-+ if (ctrl->cpu != params->cpu) {
-+ printk(BIOS_WARNING, "Cannot fast boot: CPU has changed\n");
-+ return RAMINIT_STATUS_INVALID_CACHE;
-+ }
-+
-+ ctrl->base_freq = params->base_freq;
-+ ctrl->multiplier = params->multiplier;
-+ ctrl->mem_clock_mhz = params->mem_clock_mhz;
-+ ctrl->mem_clock_fs = params->mem_clock_fs;
-+ ctrl->qclkps = params->qclkps;
-+ ctrl->cas_supported = params->cas_supported;
-+ ctrl->cpu = params->cpu;
-+ ctrl->stepping = params->stepping;
-+ ctrl->vdd_mv = params->vdd_mv;
-+ ctrl->flags = params->flags;
-+
-+ ctrl->tCK = params->tCK;
-+ ctrl->tAA = params->tAA;
-+ ctrl->tWR = params->tWR;
-+ ctrl->tRCD = params->tRCD;
-+ ctrl->tRRD = params->tRRD;
-+ ctrl->tRP = params->tRP;
-+ ctrl->tRAS = params->tRAS;
-+ ctrl->tRC = params->tRC;
-+ ctrl->tRFC = params->tRFC;
-+ ctrl->tWTR = params->tWTR;
-+ ctrl->tRTP = params->tRTP;
-+ ctrl->tFAW = params->tFAW;
-+ ctrl->tCWL = params->tCWL;
-+ ctrl->tCMD = params->tCMD;
-+ ctrl->tREFI = params->tREFI;
-+ ctrl->tXP = params->tXP;
-+
-+ ctrl->chanmap = params->chanmap;
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ ctrl->lpddr_cke_rank_map[channel] = params->lpddr_cke_rank_map[channel];
-+ for (uint8_t slot = 0; slot < NUM_SLOTS; slot++)
-+ ctrl->dimms[channel][slot] = params->dimms[channel][slot];
-+ }
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ ctrl->dpc[channel] = params->dpc[channel];
-+ ctrl->rankmap[channel] = params->rankmap[channel];
-+ ctrl->rank_mirrored[channel] = params->rank_mirrored[channel];
-+ ctrl->channel_size_mb[channel] = params->channel_size_mb[channel];
-+ }
-+ ctrl->lpddr = params->lpddr;
-+ ctrl->lanes = params->lanes;
-+ ctrl->is_ecc = params->is_ecc;
-+ return RAMINIT_STATUS_SUCCESS;
-+}
---
-2.39.5
-
diff --git a/config/coreboot/default/patches/0046-haswell-NRI-Do-sense-amplifier-offset-training.patch b/config/coreboot/default/patches/0046-haswell-NRI-Do-sense-amplifier-offset-training.patch
deleted file mode 100644
index c0945df9..00000000
--- a/config/coreboot/default/patches/0046-haswell-NRI-Do-sense-amplifier-offset-training.patch
+++ /dev/null
@@ -1,476 +0,0 @@
-From 02aa0c5612388e35f5dd1ff9c5f7a7b5b48fb9c0 Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Wed, 17 Apr 2024 13:20:32 +0200
-Subject: [PATCH 46/51] haswell NRI: Do sense amplifier offset training
-
-Quoting Wikipedia:
-
- A sense amplifier is a circuit that is used to amplify and detect
- small signals in electronic systems. It is commonly used in memory
- circuits, such as dynamic random access memory (DRAM), to read and
- amplify the weak signals stored in memory cells.
-
-In this case, we're calibrating the sense amplifiers in the memory
-controller. This training procedure uses a magic "sense amp offset
-cancel" mode of the DDRIO to observe the sampled logic levels, and
-sweeps Vref to find the low-high transition for each bit lane. The
-procedure consists of two stages: the first stage centers per-byte
-Vref (to ensure per-bit Vref offsets are as small as possible) and
-the second stage centers per-bit Vref.
-
-Because this procedure uses the "sense amp offset cancel" mode, it
-does not rely on DRAM being trained. It is assumed that the memory
-controller simply makes sense amp output levels observable via the
-`DDR_DATA_TRAIN_FEEDBACK` register and that the memory bus is idle
-during this training step (so the lane voltage is Vdd / 2).
-
-Note: This procedure will need to be adapted for Broadwell because
-it has per-rank per-bit RxVref registers, whereas Haswell only has
-a single per-bit RxVref register for all ranks.
-
-Change-Id: Ia07db68763f90e9701c8a376e01279ada8dbbe07
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../intel/haswell/native_raminit/Makefile.mk | 1 +
- .../haswell/native_raminit/raminit_main.c | 1 +
- .../haswell/native_raminit/raminit_native.h | 12 +
- .../native_raminit/train_sense_amp_offset.c | 341 ++++++++++++++++++
- .../intel/haswell/registers/mchbar.h | 2 +
- 5 files changed, 357 insertions(+)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/train_sense_amp_offset.c
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-index 8fdd17c542..4bd668a2d6 100644
---- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
-@@ -21,3 +21,4 @@ romstage-y += timings_refresh.c
- romstage-y += train_jedec_write_leveling.c
- romstage-y += train_read_mpr.c
- romstage-y += train_receive_enable.c
-+romstage-y += train_sense_amp_offset.c
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-index 056dde1adc..ce637e2d03 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
-@@ -60,6 +60,7 @@ static const struct task_entry cold_boot[] = {
- { configure_memory_map, true, "MEMMAP", },
- { do_jedec_init, true, "JEDECINIT", },
- { pre_training, true, "PRETRAIN", },
-+ { train_sense_amp_offset, true, "SOT", },
- { train_receive_enable, true, "RCVET", },
- { train_read_mpr, true, "RDMPRT", },
- { train_jedec_write_leveling, true, "JWRL", },
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-index 2ac16eaad3..07eea98831 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
-@@ -23,6 +23,8 @@
- #define NUM_LANES 9
- #define NUM_LANES_NO_ECC 8
-
-+#define NUM_BITS 8
-+
- #define COMP_INT 10
-
- /* Always use 12 legs for emphasis (not trained) */
-@@ -219,6 +221,7 @@ enum raminit_status {
- RAMINIT_STATUS_MPLL_INIT_FAILURE,
- RAMINIT_STATUS_POLL_TIMEOUT,
- RAMINIT_STATUS_REUT_ERROR,
-+ RAMINIT_STATUS_SAMP_OFFSET_FAILURE,
- RAMINIT_STATUS_RCVEN_FAILURE,
- RAMINIT_STATUS_RMPR_FAILURE,
- RAMINIT_STATUS_JWRL_FAILURE,
-@@ -244,6 +247,12 @@ struct raminit_dimm_info {
- bool valid;
- };
-
-+struct vref_margin {
-+ uint8_t low;
-+ uint8_t center;
-+ uint8_t high;
-+};
-+
- struct sysinfo {
- enum raminit_boot_mode bootmode;
- enum generic_stepping stepping;
-@@ -331,6 +340,8 @@ struct sysinfo {
- uint8_t rxdqsn[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
- int8_t rxvref[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
-
-+ struct vref_margin rxdqvrefpb[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES][NUM_BITS];
-+
- uint8_t clk_pi_code[NUM_CHANNELS][NUM_SLOTRANKS];
- uint8_t ctl_pi_code[NUM_CHANNELS][NUM_SLOTRANKS];
- uint8_t cke_pi_code[NUM_CHANNELS][NUM_SLOTRANKS];
-@@ -453,6 +464,7 @@ enum raminit_status convert_timings(struct sysinfo *ctrl);
- enum raminit_status configure_mc(struct sysinfo *ctrl);
- enum raminit_status configure_memory_map(struct sysinfo *ctrl);
- enum raminit_status do_jedec_init(struct sysinfo *ctrl);
-+enum raminit_status train_sense_amp_offset(struct sysinfo *ctrl);
- enum raminit_status train_receive_enable(struct sysinfo *ctrl);
- enum raminit_status train_read_mpr(struct sysinfo *ctrl);
- enum raminit_status train_jedec_write_leveling(struct sysinfo *ctrl);
-diff --git a/src/northbridge/intel/haswell/native_raminit/train_sense_amp_offset.c b/src/northbridge/intel/haswell/native_raminit/train_sense_amp_offset.c
-new file mode 100644
-index 0000000000..d4f199fefb
---- /dev/null
-+++ b/src/northbridge/intel/haswell/native_raminit/train_sense_amp_offset.c
-@@ -0,0 +1,341 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <assert.h>
-+#include <commonlib/bsd/clamp.h>
-+#include <console/console.h>
-+#include <delay.h>
-+#include <lib.h>
-+#include <types.h>
-+
-+#include "raminit_native.h"
-+
-+#define VREF_OFFSET_PLOT RAM_DEBUG
-+#define SAMP_OFFSET_PLOT RAM_DEBUG
-+
-+struct vref_train_data {
-+ int8_t best_sum;
-+ int8_t best_vref;
-+ int8_t sum_bits;
-+ uint8_t high_mask;
-+ uint8_t low_mask;
-+};
-+
-+static enum raminit_status train_vref_offset(struct sysinfo *ctrl)
-+{
-+ const int8_t vref_start = -15;
-+ const int8_t vref_stop = 15;
-+ const struct vref_train_data initial_vref_values = {
-+ .best_sum = -NUM_LANES,
-+ .best_vref = 0,
-+ .high_mask = 0,
-+ .low_mask = 0xff,
-+ };
-+ struct vref_train_data vref_data[NUM_CHANNELS][NUM_LANES];
-+
-+ printk(VREF_OFFSET_PLOT, "Plot of sum_bits across Vref settings\nChannel");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ printk(VREF_OFFSET_PLOT, "\t%u\t\t", channel);
-+ }
-+
-+ printk(VREF_OFFSET_PLOT, "\nByte");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ printk(VREF_OFFSET_PLOT, "\t");
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ printk(VREF_OFFSET_PLOT, "%u ", byte);
-+ vref_data[channel][byte] = initial_vref_values;
-+ union ddr_data_control_2_reg data_control_2 = {
-+ .raw = ctrl->dq_control_2[channel][byte],
-+ };
-+ data_control_2.force_bias_on = 1;
-+ data_control_2.force_rx_on = 1;
-+ mchbar_write32(DQ_CONTROL_2(channel, byte), data_control_2.raw);
-+ }
-+ }
-+
-+ /* Sweep through Vref settings and find point SampOffset of +/- 7 passes */
-+ printk(VREF_OFFSET_PLOT, "\n1/2 Vref");
-+ for (int8_t vref = vref_start; vref <= vref_stop; vref++) {
-+ printk(VREF_OFFSET_PLOT, "\n% 3d", vref);
-+
-+ /*
-+ * To perform this test, enable offset cancel mode and enable ODT.
-+ * Check results and update variables. Ideal result is all zeroes.
-+ * Clear offset cancel mode at end of test to write RX_OFFSET_VDQ.
-+ */
-+ change_1d_margin_multicast(ctrl, RdV, vref, 0, false, REG_FILE_USE_RANK);
-+
-+ /* Program settings for Vref and SampOffset = 7 (8 + 7) */
-+ mchbar_write32(DDR_DATA_RX_OFFSET_VDQ, 0xffffffff);
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ /* Propagate delay values (without a read command) */
-+ union ddr_data_control_0_reg data_control_0 = {
-+ .raw = ctrl->dq_control_0[channel],
-+ };
-+ data_control_0.read_rf_rd = 1;
-+ data_control_0.read_rf_wr = 0;
-+ data_control_0.read_rf_rank = 0;
-+ data_control_0.force_odt_on = 1;
-+ data_control_0.samp_train_mode = 1;
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
-+ udelay(1);
-+ data_control_0.samp_train_mode = 0;
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ const uint8_t feedback = get_data_train_feedback(channel, byte);
-+ struct vref_train_data *curr_data = &vref_data[channel][byte];
-+ curr_data->low_mask &= feedback;
-+ curr_data->sum_bits = -popcnt(feedback);
-+ }
-+ }
-+
-+ /* Program settings for Vref and SampOffset = -7 (8 - 7) */
-+ mchbar_write32(DDR_DATA_RX_OFFSET_VDQ, 0x11111111);
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ /* Propagate delay values (without a read command) */
-+ union ddr_data_control_0_reg data_control_0 = {
-+ .raw = ctrl->dq_control_0[channel],
-+ };
-+ data_control_0.read_rf_rd = 1;
-+ data_control_0.read_rf_wr = 0;
-+ data_control_0.read_rf_rank = 0;
-+ data_control_0.force_odt_on = 1;
-+ data_control_0.samp_train_mode = 1;
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
-+ udelay(1);
-+ data_control_0.samp_train_mode = 0;
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
-+ printk(VREF_OFFSET_PLOT, "\t");
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ const uint8_t feedback = get_data_train_feedback(channel, byte);
-+ struct vref_train_data *curr_data = &vref_data[channel][byte];
-+ curr_data->high_mask |= feedback;
-+ curr_data->sum_bits += popcnt(feedback);
-+ printk(VREF_OFFSET_PLOT, "%d ", curr_data->sum_bits);
-+ if (curr_data->sum_bits > curr_data->best_sum) {
-+ curr_data->best_sum = curr_data->sum_bits;
-+ curr_data->best_vref = vref;
-+ ctrl->rxvref[channel][0][byte] = vref;
-+ } else if (curr_data->sum_bits == curr_data->best_sum) {
-+ curr_data->best_vref = vref;
-+ }
-+ }
-+ }
-+ }
-+ printk(BIOS_DEBUG, "\n\nHi-Lo (XOR):");
-+ enum raminit_status status = RAMINIT_STATUS_SUCCESS;
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ printk(BIOS_DEBUG, "\n C%u:", channel);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ struct vref_train_data *const curr_data = &vref_data[channel][byte];
-+ const uint8_t bit_xor = curr_data->high_mask ^ curr_data->low_mask;
-+ printk(BIOS_DEBUG, "\t0x%02x", bit_xor);
-+ if (bit_xor == 0xff)
-+ continue;
-+
-+ /* Report an error if any bit did not change */
-+ status = RAMINIT_STATUS_SAMP_OFFSET_FAILURE;
-+ }
-+ }
-+ if (status)
-+ printk(BIOS_ERR, "\nUnexpected bit error in Vref offset training\n");
-+
-+ printk(BIOS_DEBUG, "\n\nRdVref:");
-+ change_1d_margin_multicast(ctrl, RdV, 0, 0, false, REG_FILE_USE_RANK);
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ printk(BIOS_DEBUG, "\n C%u:", channel);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ struct vref_train_data *const curr_data = &vref_data[channel][byte];
-+ const int8_t vref_width =
-+ curr_data->best_vref - ctrl->rxvref[channel][0][byte];
-+
-+ /*
-+ * Step size for Rx Vref in DATA_OFFSET_TRAIN is about 3.9 mV
-+ * whereas Rx Vref step size in RX_TRAIN_RANK is about 7.8 mV
-+ */
-+ int8_t vref = ctrl->rxvref[channel][0][byte] + vref_width / 2;
-+ if (vref < 0)
-+ vref--;
-+ else
-+ vref++;
-+
-+ for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
-+ if (!rank_in_ch(ctrl, rank, channel))
-+ continue;
-+
-+ ctrl->rxvref[channel][rank][byte] = vref / 2;
-+ update_rxt(ctrl, channel, rank, byte, RXT_RESTORE, 0);
-+ }
-+ printk(BIOS_DEBUG, "\t% 4d", ctrl->rxvref[channel][0][byte]);
-+ }
-+ }
-+ printk(BIOS_DEBUG, "\n\n");
-+ return status;
-+}
-+
-+/**
-+ * LPDDR has an additional bit for DQS per each byte.
-+ *
-+ * TODO: The DQS value must be written into Data Control 2.
-+ */
-+#define NUM_OFFSET_TRAIN_BITS (NUM_BITS + 1)
-+
-+#define PLOT_CH_SPACE " "
-+
-+struct samp_train_data {
-+ uint8_t first_zero;
-+ uint8_t last_one;
-+};
-+
-+static void train_samp_offset(struct sysinfo *ctrl)
-+{
-+ const uint8_t max_train_bits = ctrl->lpddr ? NUM_OFFSET_TRAIN_BITS : NUM_BITS;
-+
-+ struct samp_train_data samp_data[NUM_CHANNELS][NUM_LANES][NUM_OFFSET_TRAIN_BITS] = {0};
-+
-+ printk(BIOS_DEBUG, "Channel ");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ printk(BIOS_DEBUG, "%u ", channel); /* Same length as PLOT_CH_SPACE */
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ printk(BIOS_DEBUG, " %s ", ctrl->lpddr ? " " : "");
-+ }
-+ printk(BIOS_DEBUG, "\nByte ");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ printk(BIOS_DEBUG, "%u %s ", byte, ctrl->lpddr ? " " : "");
-+
-+ printk(BIOS_DEBUG, PLOT_CH_SPACE);
-+ }
-+ printk(SAMP_OFFSET_PLOT, "\nBits ");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ printk(SAMP_OFFSET_PLOT, "01234567%s ", ctrl->lpddr ? "S" : "");
-+
-+ printk(SAMP_OFFSET_PLOT, PLOT_CH_SPACE);
-+ }
-+ printk(SAMP_OFFSET_PLOT, "\n SAmp\n");
-+ for (uint8_t samp_offset = 1; samp_offset <= 15; samp_offset++) {
-+ printk(SAMP_OFFSET_PLOT, "% 5d\t", samp_offset);
-+
-+ uint32_t rx_offset_vdq = 0;
-+ for (uint8_t bit = 0; bit < NUM_BITS; bit++) {
-+ rx_offset_vdq += samp_offset << (4 * bit);
-+ }
-+ mchbar_write32(DDR_DATA_RX_OFFSET_VDQ, rx_offset_vdq);
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ /* Propagate delay values (without a read command) */
-+ union ddr_data_control_0_reg data_control_0 = {
-+ .raw = ctrl->dq_control_0[channel],
-+ };
-+ data_control_0.read_rf_rd = 1;
-+ data_control_0.read_rf_wr = 0;
-+ data_control_0.read_rf_rank = 0;
-+ data_control_0.force_odt_on = 1;
-+ data_control_0.samp_train_mode = 1;
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
-+ udelay(1);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ const uint32_t feedback =
-+ get_data_train_feedback(channel, byte);
-+
-+ for (uint8_t bit = 0; bit < max_train_bits; bit++) {
-+ struct samp_train_data *const curr_data =
-+ &samp_data[channel][byte][bit];
-+ const bool result = feedback & BIT(bit);
-+ if (result) {
-+ curr_data->last_one = samp_offset;
-+ } else if (curr_data->first_zero == 0) {
-+ curr_data->first_zero = samp_offset;
-+ }
-+ printk(SAMP_OFFSET_PLOT, result ? "." : "#");
-+ }
-+ printk(SAMP_OFFSET_PLOT, " ");
-+ }
-+ printk(SAMP_OFFSET_PLOT, PLOT_CH_SPACE);
-+ data_control_0.samp_train_mode = 0;
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
-+ }
-+ printk(SAMP_OFFSET_PLOT, "\n");
-+ }
-+ printk(BIOS_DEBUG, "\nBitSAmp ");
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
-+ uint32_t rx_offset_vdq = 0;
-+ for (uint8_t bit = 0; bit < max_train_bits; bit++) {
-+ struct samp_train_data *const curr_data =
-+ &samp_data[channel][byte][bit];
-+
-+ uint8_t vref = curr_data->first_zero + curr_data->last_one;
-+ vref = clamp_u8(0, vref / 2, 15);
-+ /*
-+ * Check for saturation conditions to make sure
-+ * we are as close as possible to Vdd/2 (750 mV).
-+ */
-+ if (curr_data->first_zero == 0)
-+ vref = 15;
-+ if (curr_data->last_one == 0)
-+ vref = 0;
-+
-+ ctrl->rxdqvrefpb[channel][0][byte][bit].center = vref;
-+ rx_offset_vdq += vref & 0xf << (4 * bit);
-+ printk(BIOS_DEBUG, "%x", vref);
-+ }
-+ mchbar_write32(RX_OFFSET_VDQ(channel, byte), rx_offset_vdq);
-+ printk(BIOS_DEBUG, " ");
-+ download_regfile(ctrl, channel, 1, 0, REG_FILE_USE_RANK, 0, 1, 0);
-+ }
-+ printk(BIOS_DEBUG, PLOT_CH_SPACE);
-+ }
-+ printk(BIOS_DEBUG, "\n");
-+}
-+
-+enum raminit_status train_sense_amp_offset(struct sysinfo *ctrl)
-+{
-+ printk(BIOS_DEBUG, "Stage 1: Vref offset training\n");
-+ const enum raminit_status status = train_vref_offset(ctrl);
-+
-+ printk(BIOS_DEBUG, "Stage 2: Samp offset training\n");
-+ train_samp_offset(ctrl);
-+
-+ /* Clean up after test */
-+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
-+ if (!does_ch_exist(ctrl, channel))
-+ continue;
-+
-+ mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), ctrl->dq_control_0[channel]);
-+ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
-+ mchbar_write32(DQ_CONTROL_2(channel, byte),
-+ ctrl->dq_control_2[channel][byte]);
-+ }
-+ io_reset();
-+ return status;
-+}
-diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
-index 49a215aa71..1a168a3fc8 100644
---- a/src/northbridge/intel/haswell/registers/mchbar.h
-+++ b/src/northbridge/intel/haswell/registers/mchbar.h
-@@ -18,6 +18,8 @@
- #define RX_TRAIN_ch_r_b(ch, rank, byte) _DDRIO_C_R_B(0x0000, ch, rank, byte)
- #define TX_TRAIN_ch_r_b(ch, rank, byte) _DDRIO_C_R_B(0x0020, ch, rank, byte)
-
-+#define RX_OFFSET_VDQ(ch, byte) _DDRIO_C_R_B(0x004c, ch, 0, byte)
-+
- #define DDR_DATA_TRAIN_FEEDBACK(ch, byte) _DDRIO_C_R_B(0x0054, ch, 0, byte)
-
- #define DQ_CONTROL_1(ch, byte) _DDRIO_C_R_B(0x0060, ch, 0, byte)
---
-2.39.5
-