mb/purism/librem_l1um_v2: Add support for Purism Librem L1UM v2

This adds support for booting the Librem L1UM v2 mainboard with
coreboot, using binaries from the original BIOS.

The following features have been tested on PureOS:
- USB: front USB3, rear USB3, USB2 header on board
- SATA: 8x SATA ports, one M.2 M-key shared with SATA0
- PCIe: two PEG slots, one PCIe slot from PCH, and one M.2 M-key
- Network: 2x GbE
- Video: BMC VGA and IPMI
- Serial: Physical serial port, provided by BMC SuperIO
- Hardware monitor
- POST code display
- TPM2

These binaries are extracted from the original BIOS:
- Intel Management Engine
- Intel Firmware Descriptor

This was developed and tested on a Librem L1UM v2 using a Core i7-9700
CPU.  Native graphics init works for the Aspeed AST2500 BMC.

For development, the serial port console works from bootblock.  Early
init waits for the BMC to finish booting since this is required for
serial port output.

Change-Id: I990f6024d65098a9553d7d1fe7f36614cc55ea19
Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/75090
Reviewed-by: Matt DeVillier <matt.devillier@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/mainboard/purism/librem_l1um_v2/Kconfig b/src/mainboard/purism/librem_l1um_v2/Kconfig
new file mode 100644
index 0000000..6f5369a
--- /dev/null
+++ b/src/mainboard/purism/librem_l1um_v2/Kconfig
@@ -0,0 +1,39 @@
+config BOARD_PURISM_BASEBOARD_LIBREM_L1UM_V2
+	def_bool n
+	select BOARD_ROMSIZE_KB_32768
+	select DRIVERS_ASPEED_AST2050
+	select DRIVERS_ASPEED_AST_COMMON
+	select DRIVERS_GENERIC_CBFS_SERIAL
+	select DRIVERS_UART_8250IO
+	select DRIVERS_USB_ACPI
+	select GENERATE_SMBIOS_TABLES
+	select HAVE_ACPI_TABLES
+	select IPMI_KCS
+	select MAINBOARD_HAS_TPM2
+	select MEMORY_MAPPED_TPM
+	select SMBIOS_TYPE41_PROVIDED_BY_DEVTREE
+	select SOC_INTEL_CANNONLAKE_PCH_H
+	select SOC_INTEL_COFFEELAKE
+	select SUPERIO_ASPEED_AST2400
+	select SUPERIO_ASPEED_COMMON_PRE_RAM
+	select SUPERIO_NUVOTON_NCT6791D # This board has two SuperIOs
+
+config BOARD_PURISM_LIBREM_L1UM_V2
+	select BOARD_PURISM_BASEBOARD_LIBREM_L1UM_V2
+
+if BOARD_PURISM_BASEBOARD_LIBREM_L1UM_V2
+
+config MAINBOARD_DIR
+	default "purism/librem_l1um_v2"
+
+config MAINBOARD_FAMILY
+	string
+	default "Librem L1UM v2"
+
+config MAINBOARD_PART_NUMBER
+	default "Librem L1UM v2"
+
+config CBFS_SIZE
+	default 0x1000000
+
+endif
diff --git a/src/mainboard/purism/librem_l1um_v2/Kconfig.name b/src/mainboard/purism/librem_l1um_v2/Kconfig.name
new file mode 100644
index 0000000..77302fc
--- /dev/null
+++ b/src/mainboard/purism/librem_l1um_v2/Kconfig.name
@@ -0,0 +1,2 @@
+config BOARD_PURISM_LIBREM_L1UM_V2
+	bool "Librem L1UM v2"
diff --git a/src/mainboard/purism/librem_l1um_v2/Makefile.inc b/src/mainboard/purism/librem_l1um_v2/Makefile.inc
new file mode 100644
index 0000000..836733c
--- /dev/null
+++ b/src/mainboard/purism/librem_l1um_v2/Makefile.inc
@@ -0,0 +1,4 @@
+## SPDX-License-Identifier: GPL-2.0-only
+
+bootblock-y += bootblock.c
+ramstage-y += ramstage.c
diff --git a/src/mainboard/purism/librem_l1um_v2/board_info.txt b/src/mainboard/purism/librem_l1um_v2/board_info.txt
new file mode 100644
index 0000000..b6a1dd8
--- /dev/null
+++ b/src/mainboard/purism/librem_l1um_v2/board_info.txt
@@ -0,0 +1,8 @@
+Vendor name: Purism
+Board name: Librem L1UM v2
+Category: server
+Release year: 2023
+ROM package: SOIC-16
+ROM protocol: SPI
+ROM socketed: y
+Flashrom support: y
diff --git a/src/mainboard/purism/librem_l1um_v2/bootblock.c b/src/mainboard/purism/librem_l1um_v2/bootblock.c
new file mode 100644
index 0000000..d815669
--- /dev/null
+++ b/src/mainboard/purism/librem_l1um_v2/bootblock.c
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <bootblock_common.h>
+#include <superio/nuvoton/common/nuvoton.h>
+#include <superio/nuvoton/nct6791d/nct6791d.h>
+#include <superio/aspeed/common/aspeed.h>
+#include <superio/aspeed/ast2400/ast2400.h>
+#include <console/uart.h>
+#include <console/console.h>
+#include <device/pnp_ops.h>
+#include <delay.h>
+#include "gpio.h"
+#include <gpio.h>
+#include <timer.h>
+#include <delay.h>
+
+static int64_t bmc_ready_elapsed = 0;
+
+void bootblock_mainboard_early_init(void)
+{
+	gpio_configure_pads(early_gpio_table, ARRAY_SIZE(early_gpio_table));
+
+	/*
+	 * We must wait for the BMC firmware to be ready before proceeding past
+	 * early init:
+	 * - The BMC UART (the physical serial port) won't work until the BMC is
+	 *   configured
+	 * - The BMC will reset the TPM configuration during startup,
+	 *   coreboot must not configure or communicate with the TPM before then
+	 *
+	 * This usually takes about 30 seconds for a boot right after power on.
+	 */
+	struct stopwatch sw;
+	stopwatch_init_msecs_expire(&sw, 120 * 1000);
+	while (!stopwatch_expired(&sw)) {
+		/* Wait for J2 to go low - BMC ready signal from BMC firmware */
+		if (!gpio_get(GPP_J2))
+			break;
+		mdelay(1000);
+	}
+	/* Trace the time spent later once the console is up */
+	if (stopwatch_expired(&sw))
+		bmc_ready_elapsed = -1;
+	else
+		bmc_ready_elapsed = stopwatch_duration_msecs(&sw);
+
+	/*
+	 * Disable the Nuvoton NCT6791D SuperIO UART1.  It is enabled by
+	 * default, but the AST2500's is connected to the serial port.
+	 */
+	const pnp_devfn_t nvt_serial_dev = PNP_DEV(0x2E, NCT6791D_SP1);
+	nuvoton_pnp_enter_conf_state(nvt_serial_dev);
+	pnp_set_logical_device(nvt_serial_dev);
+	pnp_set_enable(nvt_serial_dev, 0);
+	nuvoton_pnp_exit_conf_state(nvt_serial_dev);
+
+	/* Enable AST2500 SuperIO UART1 */
+	const pnp_devfn_t ast_serial_dev = PNP_DEV(0x4E, AST2400_SUART1);
+	aspeed_enable_serial(ast_serial_dev, CONFIG_TTYS0_BASE);
+}
+
+void bootblock_mainboard_init(void)
+{
+	if (bmc_ready_elapsed >= 0) {
+		printk(BIOS_INFO, "BMC became ready in early init after %lld ms\n",
+			bmc_ready_elapsed);
+	} else {
+		/* Better to boot than to render the system unusable, but some
+		   peripherals may not work */
+		printk(BIOS_ERR, "BMC was not ready within timeout, booting anyway\n");
+	}
+}
diff --git a/src/mainboard/purism/librem_l1um_v2/devicetree.cb b/src/mainboard/purism/librem_l1um_v2/devicetree.cb
new file mode 100644
index 0000000..0144f22
--- /dev/null
+++ b/src/mainboard/purism/librem_l1um_v2/devicetree.cb
@@ -0,0 +1,394 @@
+chip soc/intel/cannonlake
+
+	register "SaGv" = "SaGv_FixedHigh"
+
+	register "PcieClkSrcClkReq[0]" = "PCIE_CLK_NOTUSED"
+	register "PcieClkSrcClkReq[1]" = "PCIE_CLK_NOTUSED"
+	register "PcieClkSrcClkReq[2]" = "PCIE_CLK_NOTUSED"
+	register "PcieClkSrcClkReq[3]" = "PCIE_CLK_NOTUSED"
+	register "PcieClkSrcClkReq[4]" = "PCIE_CLK_NOTUSED"
+	register "PcieClkSrcClkReq[5]" = "PCIE_CLK_NOTUSED"
+	register "PcieClkSrcClkReq[6]" = "PCIE_CLK_NOTUSED"
+	register "PcieClkSrcClkReq[7]" = "PCIE_CLK_NOTUSED"
+	register "PcieClkSrcClkReq[8]" = "PCIE_CLK_NOTUSED"
+	register "PcieClkSrcClkReq[9]" = "PCIE_CLK_NOTUSED"
+	register "PcieClkSrcClkReq[10]" = "PCIE_CLK_NOTUSED"
+	register "PcieClkSrcClkReq[11]" = "PCIE_CLK_NOTUSED"
+	register "PcieClkSrcClkReq[12]" = "PCIE_CLK_NOTUSED"
+	register "PcieClkSrcClkReq[13]" = "PCIE_CLK_NOTUSED"
+	register "PcieClkSrcClkReq[14]" = "PCIE_CLK_NOTUSED"
+	register "PcieClkSrcClkReq[15]" = "PCIE_CLK_NOTUSED"
+
+	register "s0ix_enable" = "0"
+
+	register "eist_enable" = "1"
+
+	register "SerialIoDevMode" = "{
+		[PchSerialIoIndexI2C0]  = PchSerialIoDisabled,
+		[PchSerialIoIndexI2C1]  = PchSerialIoDisabled,
+		[PchSerialIoIndexI2C2]  = PchSerialIoDisabled,
+		[PchSerialIoIndexI2C3]  = PchSerialIoDisabled,
+		[PchSerialIoIndexSPI0]  = PchSerialIoDisabled,
+		[PchSerialIoIndexSPI1]  = PchSerialIoDisabled,
+		[PchSerialIoIndexUART0] = PchSerialIoDisabled,
+		[PchSerialIoIndexUART1] = PchSerialIoDisabled,
+		[PchSerialIoIndexUART2] = PchSerialIoDisabled,
+	}"
+
+	register "DisableHeciRetry" = "1"
+
+	device cpu_cluster 0 on end
+
+	device domain 0 on
+		device pci 00.0 on  end # Host Bridge
+		device pci 01.0 on      # PCIE6 - x16 or x8
+			register "PcieClkSrcUsage[3]" = "0x40"
+			smbios_slot_desc "SlotTypePciExpressGen3X16" "SlotLengthOther" "PCIE6" "SlotDataBusWidth16X"
+		end
+		device pci 01.1 on      # PCIE4 - x8
+			register "PcieClkSrcUsage[4]" = "0x41"
+			smbios_slot_desc "SlotTypePciExpressGen3X8" "SlotLengthOther" "PCIE4" "SlotDataBusWidth8X"
+		end
+		device pci 02.0 on  end # Integrated Graphics Device
+		device pci 04.0 off end # SA Thermal Device
+		device pci 08.0 on  end # Gaussian Mixture
+		device pci 12.0 on  end # Thermal Subsystem
+		device pci 14.0 on      # USB xHCI
+			register "usb2_ports[0]" = "USB2_PORT_MID(OC_SKIP)"	# USB 3.1 front left
+			register "usb2_ports[1]" = "USB2_PORT_MID(OC_SKIP)"	# USB 3.1 front right
+			register "usb2_ports[2]" = "USB2_PORT_MID(OC_SKIP)"	# USB_1_2 header port A
+			register "usb2_ports[3]" = "USB2_PORT_MID(OC_SKIP)"	# USB_1_2 header port B
+			register "usb2_ports[4]" = "USB2_PORT_MID(OC_SKIP)"	# USB 3.1 rear top-right
+			register "usb2_ports[6]" = "USB2_PORT_MID(OC_SKIP)"	# USB 3.1 rear bottom-right
+			register "usb2_ports[7]" = "USB2_PORT_MID(OC_SKIP)"	# BMC port A
+			register "usb2_ports[8]" = "USB2_PORT_MID(OC_SKIP)"	# USB 3.1 rear bottom-left
+			register "usb2_ports[9]" = "USB2_PORT_MID(OC_SKIP)"	# BMC port B (seems to be unused)
+			register "usb2_ports[10]" = "USB2_PORT_MID(OC_SKIP)"	# USB 3.1 rear top-left
+
+			register "usb3_ports[0]" = "USB3_PORT_DEFAULT(OC_SKIP)"	# USB 3.1 rear bottom-right
+			register "usb3_ports[1]" = "USB3_PORT_DEFAULT(OC_SKIP)"	# USB 3.1 rear top-right
+			register "usb3_ports[2]" = "USB3_PORT_DEFAULT(OC_SKIP)"	# USB 3.1 rear bottom-left
+			register "usb3_ports[3]" = "USB3_PORT_DEFAULT(OC_SKIP)"	# USB 3.1 rear top-left
+			register "usb3_ports[4]" = "USB3_PORT_DEFAULT(OC_SKIP)"	# USB 3.1 front left
+			register "usb3_ports[5]" = "USB3_PORT_DEFAULT(OC_SKIP)"	# USB 3.1 front right
+
+			chip drivers/usb/acpi
+				device usb 0.0 on
+					chip drivers/usb/acpi
+						register "desc" = ""USB 2.0 Type-A Front Left""
+						register "type" = "UPC_TYPE_A"
+						register "group" = "ACPI_PLD_GROUP(0, 0)"
+						device usb 2.0 on end
+					end
+					chip drivers/usb/acpi
+						register "desc" = ""USB 2.0 Type-A Front Right""
+						register "type" = "UPC_TYPE_A"
+						register "group" = "ACPI_PLD_GROUP(0, 1)"
+						device usb 2.1 on end
+					end
+					chip drivers/usb/acpi
+						register "desc" = ""USB 2.0 USB_1_2 Header Port A""
+						register "type" = "UPC_TYPE_INTERNAL"
+						register "group" = "ACPI_PLD_GROUP(1, 0)"
+						device usb 2.2 on end
+					end
+					chip drivers/usb/acpi
+						register "desc" = ""USB 2.0 USB_1_2 Header Port B""
+						register "type" = "UPC_TYPE_INTERNAL"
+						register "group" = "ACPI_PLD_GROUP(1, 1)"
+						device usb 2.3 on end
+					end
+					chip drivers/usb/acpi
+						register "desc" = ""USB 2.0 Type-A Rear Right Upper""
+						register "type" = "UPC_TYPE_A"
+						register "group" = "ACPI_PLD_GROUP(2, 0)"
+						device usb 2.4 on end
+					end
+					chip drivers/usb/acpi
+						device usb 2.5 off end
+					end
+					chip drivers/usb/acpi
+						register "desc" = ""USB 2.0 Type-A Rear Right Lower""
+						register "type" = "UPC_TYPE_A"
+						register "group" = "ACPI_PLD_GROUP(2, 1)"
+						device usb 2.6 on end
+					end
+					chip drivers/usb/acpi
+						register "desc" = ""USB 2.0 BMC Port A""
+						register "type" = "UPC_TYPE_INTERNAL"
+						register "group" = "ACPI_PLD_GROUP(3, 0)"
+						device usb 2.7 on end
+					end
+					chip drivers/usb/acpi
+						register "desc" = ""USB 2.0 Type-A Rear Left Lower""
+						register "type" = "UPC_TYPE_A"
+						register "group" = "ACPI_PLD_GROUP(2, 2)"
+						device usb 2.8 on end
+					end
+					chip drivers/usb/acpi
+						register "desc" = ""USB 2.0 BMC Port B""
+						register "type" = "UPC_TYPE_INTERNAL"
+						register "group" = "ACPI_PLD_GROUP(3, 1)"
+						device usb 2.9 on end
+					end
+					chip drivers/usb/acpi
+						register "desc" = ""USB 2.0 Type-A Rear Left Upper""
+						register "type" = "UPC_TYPE_A"
+						register "group" = "ACPI_PLD_GROUP(2, 3)"
+						device usb 2.10 on end
+					end
+					chip drivers/usb/acpi
+						register "desc" = ""USB 3.1 Type-A Rear Right Lower""
+						register "type" = "UPC_TYPE_USB3_A"
+						register "group" = "ACPI_PLD_GROUP(2, 1)"
+						device usb 3.0 on end
+					end
+					chip drivers/usb/acpi
+						register "desc" = ""USB 3.1 Type-A Rear Right Upper""
+						register "type" = "UPC_TYPE_USB3_A"
+						register "group" = "ACPI_PLD_GROUP(2, 0)"
+						device usb 3.1 on end
+					end
+					chip drivers/usb/acpi
+						register "desc" = ""USB 3.1 Type-A Rear Left Lower""
+						register "type" = "UPC_TYPE_USB3_A"
+						register "group" = "ACPI_PLD_GROUP(2, 2)"
+						device usb 3.2 on end
+					end
+					chip drivers/usb/acpi
+						register "desc" = ""USB 3.1 Type-A Rear Left Upper""
+						register "type" = "UPC_TYPE_USB3_A"
+						register "group" = "ACPI_PLD_GROUP(2, 3)"
+						device usb 3.3 on end
+					end
+					chip drivers/usb/acpi
+						register "desc" = ""USB 3.1 Type-A Front Left""
+						register "type" = "UPC_TYPE_USB3_A"
+						register "group" = "ACPI_PLD_GROUP(0, 0)"
+						device usb 3.4 on end
+					end
+					chip drivers/usb/acpi
+						register "desc" = ""USB 3.1 Type-A Front Right""
+						register "type" = "UPC_TYPE_USB3_A"
+						register "group" = "ACPI_PLD_GROUP(0, 1)"
+						device usb 3.5 on end
+					end
+				end
+			end
+		end
+		device pci 14.1 off end # USB xDCI (OTG)
+		device pci 14.2 on  end # RAM controller
+		device pci 14.3 off end
+		device pci 14.5 off end # SDCard
+		device pci 15.0 off  end # I2C #0
+		device pci 15.1 off end # I2C #1
+		device pci 15.2 off end # I2C #2
+		device pci 15.3 off end # I2C #3
+		device pci 16.0 off end # Management Engine Interface 1
+		device pci 16.1 off end # Management Engine Interface 2
+		device pci 16.2 off end # Management Engine IDE Redirection
+		device pci 16.3 off end # Management Engine KT Redirection
+		device pci 16.4 off end # Management Engine Interface 3
+		device pci 17.0 on
+			register "satapwroptimize" = "1"
+
+			register "SataPortsEnable[0]" = "1"
+			register "SataPortsEnable[1]" = "1"
+			register "SataPortsEnable[2]" = "1"
+			register "SataPortsEnable[3]" = "1"
+			register "SataPortsEnable[4]" = "1"
+			register "SataPortsEnable[5]" = "1"
+			register "SataPortsEnable[6]" = "1"
+			register "SataPortsEnable[7]" = "1"
+
+			register "SataPortsHotPlug[0]" = "1"
+			register "SataPortsHotPlug[1]" = "1"
+			register "SataPortsHotPlug[2]" = "1"
+			register "SataPortsHotPlug[3]" = "1"
+			register "SataPortsHotPlug[4]" = "1"
+			register "SataPortsHotPlug[5]" = "1"
+			register "SataPortsHotPlug[6]" = "1"
+			register "SataPortsHotPlug[7]" = "1"
+		end # SATA
+		device pci 1b.4 on	# PCI Express Port 21 - PCIE5
+			register "PcieRpSlotImplemented[20]" = "1"
+			register "PcieRpEnable[20]" = "1"
+			register "PcieRpLtrEnable[20]" = "1"
+			register "PcieClkSrcUsage[10]" = "20"
+			smbios_slot_desc "SlotTypePciExpressGen3X4" "SlotLengthOther" "PCIE5" "SlotDataBusWidth4X"
+		end
+		device pci 1c.0 on	# PCI Express Port 1 - M2_1
+			register "PcieRpSlotImplemented[0]" = "1"
+			register "PcieRpEnable[0]" = "1"
+			register "PcieRpLtrEnable[0]" = "1"
+			register "PcieClkSrcUsage[1]" = "0x80"
+			smbios_slot_desc "SlotTypeM2Socket3" "SlotLengthOther" "M2_1" "SlotDataBusWidth4X"
+		end
+		device pci 1d.0 on	# PCI Express Port 9 - GbE #1
+			register "PcieRpEnable[8]" = "1"
+			register "PcieRpLtrEnable[8]" = "1"
+			register "PcieClkSrcUsage[14]" = "8"
+			# Type indexes are needed for systemd to use "onboard" names by default
+			# (eno0, eno1).  Otherwise it uses "slot" names that can change if any
+			# of the preceding PCIe slots are populated/unpopulated.  Numbering 1/2
+			# (rather than 0/1) is consistent with the mainboard manual and vendor
+			# firmware.
+			device pci 00.0 on
+				smbios_dev_info 1
+			end
+		end
+		device pci 1d.1 on	# PCI Express Port 10 - BMC video
+			register "PcieRpEnable[9]" = "1"
+			register "PcieRpLtrEnable[9]" = "1"
+			register "PcieClkSrcUsage[8]" = "9"
+		end
+		device pci 1d.2 on	# PCI Express Port 11 - GbE #2
+			register "PcieRpEnable[10]" = "1"
+			register "PcieRpLtrEnable[10]" = "1"
+			register "PcieClkSrcUsage[11]" = "10"
+			device pci 00.0 on
+				smbios_dev_info 2
+			end
+		end
+		device pci 1e.0 off end # UART #0
+		device pci 1e.1 off end # UART #1
+		device pci 1e.2 off end # GSPI #0
+		device pci 1e.3 off end # GSPI #1
+		device pci 1f.0 on      # LPC Interface
+			# This board has a lot of SuperIO LDNs with I/O BARs, the LPC generic
+			# I/O ranges must be configured manually.
+			register "gen1_dec" = "0x000c0ca1"	# IPMI: ca0-caf
+			register "gen2_dec" = "0x007c0a01"	# ASpeed SuperIO SWC and mailbox: a00-a7f
+			register "gen3_dec" = "0x00040291"	# Nuvoton SuperIO HW monitor: 290-297
+
+			# AST2500 Super IO UART1 requires continuous mode
+			register "serirq_mode" = "SERIRQ_CONTINUOUS"
+
+			chip drivers/ipmi # BMC KCS
+				device pnp ca2.0 on end
+				register "bmc_i2c_address" = "0x10"
+			end
+			# Nuvoton SuperIO
+			chip superio/common
+				# This board has two SuperIOs.  The BMC's SuperIO is SIO0
+				# since it is used for most normal SuperIO functionality.
+				register "acpi_name" = ""SIO1""
+				device pnp 2e.0 on
+					chip superio/nuvoton/nct6791d
+						device pnp 2e.1 off end	# Parallel port
+						device pnp 2e.2 off end	# UART A
+						device pnp 2e.3 off end	# UART B, IR
+						device pnp 2e.5 off end	# Keyboard Controller
+						device pnp 2e.6 off end	# Consumer IR
+						device pnp 2e.7 off end	# GPIO 6
+						device pnp 2e.107 off end	# GPIO 7
+						device pnp 2e.207 off end	# GPIO 8
+						device pnp 2e.8 off end # WDT
+						device pnp 2e.108 off end # GPIO0
+						device pnp 2e.308 off end # GPIO base address mode
+						device pnp 2e.408 off end # WDT_MEM
+						device pnp 2e.708 alias nvt_superio_gpio1 on	# GPIO1
+							# Global Control Registers
+							# IRQ Polarity
+							irq 0x13 = 0xff
+							irq 0x14 = 0xff
+							# Multi Function Selection
+							irq 0x1a = 0x44
+							irq 0x1b = 0x66
+							irq 0x1c = 0x10
+							irq 0x1d = 0x00
+							irq 0x2a = 0xe0
+							irq 0x2b = 0x00
+							irq 0x2c = 0x00
+							irq 0x2d = 0x00
+
+							# GPIO1
+							irq 0xf0 = 0x08
+							irq 0xf4 = 0xf7
+						end
+						device pnp 2e.9 on	# GPIO2
+							irq 0xe0 = 0xbf
+							irq 0xe9 = 0xbf
+						end
+						device pnp 2e.109 on	# GPIO3
+							irq 0xe4 = 0x11
+							irq 0xe5 = 0x01
+							irq 0xe6 = 0x00
+							irq 0xea = 0x6e
+							irq 0xfe = 0x00
+						end
+						device pnp 2e.209 on	# GPIO4
+							irq 0xf0 = 0x44
+							irq 0xee = 0xbb
+						end
+						device pnp 2e.309 off end	# GPIO5
+						device pnp 2e.a on	# ACPI
+							# Bit 4 is "power-loss last state flag", in RTC well.
+							# 1=off (default), 0=on.
+							# This might be automatic power on for this board
+							irq 0xe6 = 0x0a
+							irq 0xed = 0x01
+						end
+						device pnp 2e.b on	# Hardware Monitor, Front Panel LED
+							io 0x60 = 0x0290	# HM IO base
+							io 0x62 = 0x0000	# SB-TSI IO base
+							irq 0x70 = 0x00		# HM IRQ
+						end
+						device pnp 2e.d off end	# BCLK, WDT2, WDT_MEM
+						device pnp 2e.e off end	# CIR Wake-up
+						device pnp 2e.f on end	# GPIO push-pull / open-drain
+						device pnp 2e.14 on end	# SVID, Port 80 UART
+						device pnp 2e.16 off end	# DS5
+						device pnp 2e.116 off end	# DS3
+						device pnp 2e.316 off end	# PCHDSW
+						device pnp 2e.416 off end	# DSWWOPT
+						device pnp 2e.516 on end	# DS3OPT
+						device pnp 2e.616 off end	# DSDSS
+						device pnp 2e.716 off end	# DSPU
+					end
+				end
+			end
+			# AST2500 SuperIO
+			chip superio/common
+				device pnp 4e.0 on
+					chip superio/aspeed/ast2400
+						device pnp 4e.2 on	# SUART1
+							io 0x60 = 0x3f8
+							irq 0x70 = 0x04
+							drq 0xf0 = 0x00
+						end
+						device pnp 4e.3 off end # SUART2
+						device pnp 4e.4 off	 # SWC
+							io 0x60 = 0xa00
+							io 0x62 = 0xa10
+							io 0x64 = 0xa20
+							io 0x66 = 0xa30
+							irq 0x70 = 0x09
+						end
+						device pnp 4e.5 off end	# KBC
+						device pnp 4e.7 off end	# GPIO
+						device pnp 4e.b off end	# SUART3
+						device pnp 4e.c off end	# SUART4
+						device pnp 4e.d on	# iLPC2AHB
+							irq 0x70 = 0x00
+						end
+						device pnp 4e.e on	# Mailbox
+							io 0x60 = 0xa40
+							irq 0x70 = 0x00
+						end
+					end
+				end
+			end
+			chip drivers/pc80/tpm
+				# The TPM header has SERIRQ#, but it is not
+				# connected on the TPM module - no TPM IRQ.
+				device pnp 0c31.0 on end
+			end
+		end
+		device pci 1f.1 off end # P2SB
+		device pci 1f.2 hidden end # PMC
+		device pci 1f.3 off end # Intel HDA
+		device pci 1f.4 on  end # SMBus
+		device pci 1f.5 on  end # SPI
+	end
+end
diff --git a/src/mainboard/purism/librem_l1um_v2/dsdt.asl b/src/mainboard/purism/librem_l1um_v2/dsdt.asl
new file mode 100644
index 0000000..cb0922a
--- /dev/null
+++ b/src/mainboard/purism/librem_l1um_v2/dsdt.asl
@@ -0,0 +1,25 @@
+/* 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/platform.asl>
+	#include <soc/intel/common/block/acpi/acpi/globalnvs.asl>
+	#include <cpu/intel/common/acpi/cpu.asl>
+
+	Device (\_SB.PCI0)
+	{
+		#include <soc/intel/common/block/acpi/acpi/northbridge.asl>
+		#include <soc/intel/cannonlake/acpi/southbridge.asl>
+	}
+
+	#include <southbridge/intel/common/acpi/sleepstates.asl>
+}
diff --git a/src/mainboard/purism/librem_l1um_v2/gpio.h b/src/mainboard/purism/librem_l1um_v2/gpio.h
new file mode 100644
index 0000000..8325b69
--- /dev/null
+++ b/src/mainboard/purism/librem_l1um_v2/gpio.h
@@ -0,0 +1,295 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef CFG_GPIO_H
+#define CFG_GPIO_H
+
+#include <gpio.h>
+
+/* Early GPIOs in bootblock:
+ * - LPC interface (for UART/BMC/POST)
+ * - GPP_J2 (BMC ready input)
+ */
+static const struct pad_config early_gpio_table[] = {
+	PAD_CFG_NF(GPP_A0, NONE, DEEP, NF1),	/* RCIN# */
+	PAD_CFG_NF(GPP_A1, NONE, DEEP, NF1),	/* LAD0 */
+	PAD_CFG_NF(GPP_A2, NONE, DEEP, NF1),	/* LAD1 */
+	PAD_CFG_NF(GPP_A3, NONE, DEEP, NF1),	/* LAD2 */
+	PAD_CFG_NF(GPP_A4, NONE, DEEP, NF1),	/* LAD3 */
+	PAD_CFG_NF(GPP_A5, NONE, DEEP, NF1),	/* LFRAME# */
+	PAD_CFG_NF(GPP_A6, NONE, DEEP, NF1),	/* SERIRQ */
+	PAD_CFG_NF(GPP_A8, NONE, DEEP, NF1),	/* CLKRUN# */
+	PAD_CFG_NF(GPP_A9, NONE, DEEP, NF1),	/* CLKOUT_LPC0 */
+	PAD_CFG_NF(GPP_A10, NONE, DEEP, NF1),	/* CLKOUT_LPC1 */
+	PAD_CFG_GPI_TRIG_OWN(GPP_J2, NONE, DEEP, OFF, ACPI),	/* GPIO */
+};
+
+/* Pad configuration was generated automatically using intelp2m utility */
+static const struct pad_config gpio_table[] = {
+
+	/* ------- GPIO Community 0 ------- */
+
+	/* ------- GPIO Group GPP_A ------- */
+	/* A0-A6, A8-A10 are configured in bootblock */
+	PAD_CFG_NF(GPP_A7, NONE, DEEP, NF1),	/* PIRQA# */
+	PAD_CFG_NF(GPP_A11, NONE, DEEP, NF1),	/* PME# */
+	PAD_CFG_GPI_TRIG_OWN(GPP_A12, NONE, PLTRST, LEVEL, ACPI),	/* GPIO */
+	PAD_CFG_NF(GPP_A13, NONE, DEEP, NF1),	/* SUSWARN#/SUSPWRDNACK */
+	PAD_CFG_NF(GPP_A14, NONE, DEEP, NF1),	/* SUS_STAT# */
+	PAD_CFG_NF(GPP_A15, NONE, DEEP, NF1),	/* SUSACK# */
+	PAD_CFG_NF(GPP_A16, NONE, DEEP, NF1),	/* CLKOUT_48 */
+	PAD_CFG_GPI_TRIG_OWN(GPP_A17, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_A18, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	/* GPP_A19 - RESERVED */
+	PAD_CFG_GPI_TRIG_OWN(GPP_A20, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_NC(GPP_A21, NONE),	/* GPIO */
+	PAD_NC(GPP_A22, NONE),	/* GPIO */
+	PAD_NC(GPP_A23, NONE),	/* GPIO */
+
+	/* ------- GPIO Group GPP_B ------- */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B0, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B1, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B2, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B3, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B4, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B5, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_NC(GPP_B6, NONE),	/* GPIO */
+	PAD_CFG_NF(GPP_B7, NONE, DEEP, NF1),	/* SRCCLKREQ2# */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B8, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B9, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B10, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	/* GPP_B11 - RESERVED */
+	PAD_CFG_NF(GPP_B12, NONE, DEEP, NF1),	/* SLP_S0# */
+	PAD_CFG_NF(GPP_B13, NONE, DEEP, NF1),	/* PLTRST# */
+	PAD_CFG_NF(GPP_B14, NONE, DEEP, NF1),	/* SPKR */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B15, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B16, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B17, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B18, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B19, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPO(GPP_B20, 0, DEEP),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B21, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_B22, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	/* GPP_B23 - RESERVED */
+
+	/* ------- GPIO Community 1 ------- */
+
+	/* ------- GPIO Group GPP_C ------- */
+	/* GPP_C0 - RESERVED */
+	/* GPP_C1 - RESERVED */
+	PAD_CFG_GPI_TRIG_OWN(GPP_C2, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	/* GPP_C3 - RESERVED */
+	/* GPP_C4 - RESERVED */
+	PAD_CFG_GPO(GPP_C5, 0, DEEP),	/* GPIO */
+	/* GPP_C6 - RESERVED */
+	/* GPP_C7 - RESERVED */
+	PAD_CFG_GPI_TRIG_OWN(GPP_C8, NONE, PLTRST, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_C9, NONE, PLTRST, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPO(GPP_C10, 1, DEEP),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_C11, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_C12, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_C13, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_C14, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_C15, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_NF(GPP_C16, NONE, DEEP, NF1),	/* I2C0_SDA */
+	PAD_CFG_NF(GPP_C17, NONE, DEEP, NF1),	/* I2C0_SCL */
+	PAD_CFG_NF(GPP_C18, NONE, DEEP, NF1),	/* I2C1_SDA */
+	PAD_CFG_NF(GPP_C19, NONE, DEEP, NF1),	/* I2C1_SCL */
+	/* GPP_C20 - RESERVED */
+	PAD_CFG_GPO(GPP_C21, 1, DEEP),	/* GPIO */
+	PAD_CFG_GPI_SMI(GPP_C22, NONE, DEEP, EDGE_SINGLE, INVERT),	/* GPIO */
+	PAD_CFG_GPI_SCI(GPP_C23, NONE, DEEP, LEVEL, INVERT),	/* GPIO */
+
+	/* ------- GPIO Group GPP_D ------- */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D0, NONE, PLTRST, LEVEL, ACPI),	/* GPIO */
+	PAD_CFG_GPO(GPP_D1, 0, PLTRST),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D2, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D3, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D4, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPO(GPP_D5, 0, DEEP),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D6, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D7, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D8, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D9, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D10, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D11, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D12, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D13, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D14, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D15, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D16, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D17, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D18, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D19, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D20, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D21, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D22, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_D23, NONE, DEEP, OFF, ACPI),	/* GPIO */
+
+	/* ------- GPIO Group GPP_G ------- */
+	PAD_CFG_GPO(GPP_G0, 1, DEEP),	/* GPIO */
+	PAD_CFG_GPO(GPP_G1, 1, DEEP),	/* GPIO */
+	PAD_CFG_GPO(GPP_G2, 1, DEEP),	/* GPIO */
+	PAD_CFG_GPO(GPP_G3, 1, DEEP),	/* GPIO */
+	PAD_CFG_GPO(GPP_G4, 1, DEEP),	/* GPIO */
+	PAD_CFG_GPO(GPP_G5, 1, DEEP),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_G6, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_G7, NONE, DEEP, OFF, ACPI),	/* GPIO */
+
+	/* ------- GPIO Group AZA ------- */
+
+	/* ------- GPIO Group VGPIO_0 ------- */
+
+	/* ------- GPIO Group VGPIO_1 ------- */
+
+	/* ------- GPIO Community 2 ------- */
+
+	/* ------- GPIO Group GPD ------- */
+	PAD_CFG_NF(GPD0, NONE, DEEP, NF1),	/* BATLOW# */
+	PAD_CFG_NF(GPD1, NONE, DEEP, NF1),	/* ACPRESENT */
+	PAD_CFG_NF(GPD2, NONE, DEEP, NF1),	/* LAN_WAKE# */
+	PAD_CFG_NF(GPD3, NONE, DEEP, NF1),	/* PRWBTN# */
+	PAD_CFG_NF(GPD4, NONE, DEEP, NF1),	/* SLP_S3# */
+	PAD_CFG_NF(GPD5, NONE, DEEP, NF1),	/* SLP_S4# */
+	PAD_CFG_NF(GPD6, NONE, DEEP, NF1),	/* SLP_A# */
+	PAD_CFG_GPI_TRIG_OWN(GPD7, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_NF(GPD8, NONE, DEEP, NF1),	/* SUSCLK */
+	PAD_CFG_GPI_TRIG_OWN(GPD9, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_NF(GPD10, NONE, DEEP, NF1),	/* SLP_S5# */
+	PAD_CFG_GPI_TRIG_OWN(GPD11, NONE, DEEP, OFF, ACPI),	/* GPIO */
+
+	/* ------- GPIO Community 3 ------- */
+
+	/* ------- GPIO Group GPP_K ------- */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K0, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K1, NONE, RSMRST, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K2, NONE, RSMRST, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K3, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K4, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K5, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K6, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K7, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K8, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K9, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K10, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K11, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K12, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K13, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K14, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K15, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K16, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K17, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_NF(GPP_K18, NONE, DEEP, NF1),	/* NMI# */
+	PAD_CFG_NF(GPP_K19, NONE, DEEP, NF1),	/* SMI# */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K20, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K21, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_K22, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_NC(GPP_K23, NONE),	/* GPIO */
+
+	/* ------- GPIO Group GPP_H ------- */
+	PAD_NC(GPP_H0, NONE),	/* GPIO */
+	PAD_NC(GPP_H1, NONE),	/* GPIO */
+	PAD_NC(GPP_H2, NONE),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_H3, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_H4, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	/* GPP_H5 - RESERVED */
+	PAD_CFG_NF(GPP_H6, NONE, DEEP, NF1),	/* SRCCLKREQ12# */
+	PAD_CFG_GPI_TRIG_OWN(GPP_H7, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_H8, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_H9, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	/* GPP_H10 - RESERVED */
+	/* GPP_H11 - RESERVED */
+	PAD_CFG_GPO(GPP_H12, 1, PLTRST),	/* GPIO */
+	/* GPP_H13 - RESERVED */
+	/* GPP_H14 - RESERVED */
+	PAD_CFG_GPI_TRIG_OWN(GPP_H15, NONE, PLTRST, OFF, ACPI),	/* GPIO */
+	/* GPP_H16 - RESERVED */
+	/* GPP_H17 - RESERVED */
+	PAD_CFG_GPI_TRIG_OWN(GPP_H18, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPO(GPP_H19, 1, DEEP),	/* GPIO */
+	PAD_CFG_GPO(GPP_H20, 1, DEEP),	/* GPIO */
+	PAD_CFG_GPO(GPP_H21, 1, DEEP),	/* GPIO */
+	PAD_CFG_GPO(GPP_H22, 1, DEEP),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_H23, NONE, DEEP, OFF, ACPI),	/* GPIO */
+
+	/* ------- GPIO Group GPP_E ------- */
+	PAD_CFG_NF(GPP_E0, NONE, DEEP, NF1),	/* SATAXPCIE0 */
+	PAD_CFG_NF(GPP_E1, NONE, DEEP, NF1),	/* SATAXPCIE1 */
+	PAD_CFG_GPI_TRIG_OWN(GPP_E2, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_E3, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_E4, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_NC(GPP_E5, NONE),	/* GPIO */
+	PAD_CFG_GPI_NMI(GPP_E6, NONE, PLTRST, LEVEL, INVERT),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_E7, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_NF(GPP_E8, NONE, DEEP, NF1),	/* SATALED# */
+	PAD_CFG_NF(GPP_E9, NONE, DEEP, NF1),	/* USB2_OC0# */
+	PAD_CFG_GPI_TRIG_OWN(GPP_E10, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_E11, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_E12, NONE, DEEP, OFF, ACPI),	/* GPIO */
+
+	/* ------- GPIO Group GPP_F ------- */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F0, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F1, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F2, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F3, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F4, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F5, NONE, PLTRST, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F6, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F7, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F8, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F9, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_NF(GPP_F10, NONE, DEEP, NF1),	/* SATA_SCLOCK */
+	PAD_CFG_NF(GPP_F11, NONE, DEEP, NF1),	/* SATA_SLOAD */
+	PAD_CFG_NF(GPP_F12, NONE, DEEP, NF1),	/* SATA_SDATAOUT1 */
+	PAD_CFG_NF(GPP_F13, NONE, DEEP, NF1),	/* SATA_SDATAOUT0 */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F14, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F15, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F16, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F17, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F18, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F19, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F20, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F21, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F22, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_F23, NONE, DEEP, OFF, ACPI),	/* GPIO */
+
+	/* ------- GPIO Group SPI ------- */
+
+	/* ------- GPIO Community 4 ------- */
+
+	/* ------- GPIO Group CPU ------- */
+
+	/* ------- GPIO Group JTAG ------- */
+
+	/* ------- GPIO Group GPP_I ------- */
+	PAD_CFG_NF(GPP_I0, NONE, DEEP, NF1),	/* DDPB_HPD0 */
+	PAD_CFG_NF(GPP_I1, NONE, DEEP, NF1),	/* DDPB_HPD1 */
+	PAD_CFG_GPI_TRIG_OWN(GPP_I2, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_I3, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_I4, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPO(GPP_I5, 1, DEEP),	/* GPIO */
+	PAD_CFG_GPO(GPP_I6, 1, DEEP),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_I7, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_I8, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_I9, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_I10, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_I11, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_I12, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_I13, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_I14, NONE, DEEP, OFF, ACPI),	/* GPIO */
+
+	/* ------- GPIO Group GPP_J ------- */
+	PAD_CFG_GPI_TRIG_OWN(GPP_J0, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_NF(GPP_J1, NONE, DEEP, NF2),	/* CPU_C10_GATE# */
+	/* J2 configured in bootblock */
+	PAD_CFG_GPI_TRIG_OWN(GPP_J3, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_J4, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_J5, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_J6, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_J7, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_J8, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_J9, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_J10, NONE, DEEP, OFF, ACPI),	/* GPIO */
+	PAD_CFG_GPI_TRIG_OWN(GPP_J11, NONE, DEEP, OFF, ACPI),	/* GPIO */
+};
+
+#endif /* CFG_GPIO_H */
diff --git a/src/mainboard/purism/librem_l1um_v2/ramstage.c b/src/mainboard/purism/librem_l1um_v2/ramstage.c
new file mode 100644
index 0000000..87b7822
--- /dev/null
+++ b/src/mainboard/purism/librem_l1um_v2/ramstage.c
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <soc/ramstage.h>
+#include <superio/hwm5_conf.h>
+#include <superio/nuvoton/common/hwm.h>
+#include "gpio.h"
+#include "static.h"
+
+void mainboard_silicon_init_params(FSPS_UPD *supd)
+{
+	gpio_configure_pads(gpio_table, ARRAY_SIZE(gpio_table));
+}
+
+static void mainboard_final(void *chip_info)
+{
+	const u16 hwm_base = 0x290;
+	nuvoton_hwm_select_bank(hwm_base, 0);
+	/* Configure CPU temperature sensor for this board */
+	/* VBAT_MONITOR_CONTROL = 0 */
+	pnp_write_hwm5_index(hwm_base, 0x5d, 0x00);
+	/* CURRENT_MODE_ENABLE = 0 */
+	pnp_write_hwm5_index(hwm_base, 0x5e, 0x00);
+
+	/*
+	 * Turn off the POST display at end of POST.  This is in a GCR (Global
+	 * Control Register), but we have to use one of the LDNs as the device
+	 * because the chip ops are only assigned to the LDNs.
+	 */
+	pnp_enter_conf_mode(_dev_nvt_superio_gpio1_ptr);
+	printk(BIOS_DEBUG, "GCR 0x2f was: %02X\n",
+		pnp_read_config(_dev_nvt_superio_gpio1_ptr, 0x2f));
+	pnp_write_config(_dev_nvt_superio_gpio1_ptr, 0x2f, 0x00);
+	printk(BIOS_DEBUG, "GCR 0x2f is now: %02X\n",
+		pnp_read_config(_dev_nvt_superio_gpio1_ptr, 0x2f));
+	pnp_exit_conf_mode(_dev_nvt_superio_gpio1_ptr);
+}
+
+struct chip_operations mainboard_ops = {
+	.final = mainboard_final,
+};
diff --git a/src/mainboard/purism/librem_l1um_v2/romstage.c b/src/mainboard/purism/librem_l1um_v2/romstage.c
new file mode 100644
index 0000000..6cceba3
--- /dev/null
+++ b/src/mainboard/purism/librem_l1um_v2/romstage.c
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <console/console.h>
+#include <soc/cnl_memcfg_init.h>
+#include <soc/romstage.h>
+#include <spd_bin.h>
+#include <spd_cache.h>
+
+void mainboard_memory_init_params(FSPM_UPD *memupd)
+{
+	struct cnl_mb_cfg memcfg = {
+		/* Access memory info through SMBUS. */
+		.spd[0] = {
+			.read_type = READ_SMBUS,
+			.spd_spec = {.spd_smbus_address = 0xa0}
+		},
+		.spd[1] = {
+			.read_type = READ_SMBUS,
+			.spd_spec = {.spd_smbus_address = 0xa2}
+		},
+		.spd[2] = {
+			.read_type = READ_SMBUS,
+			.spd_spec = {.spd_smbus_address = 0xa4}
+		},
+		.spd[3] = {
+			.read_type = READ_SMBUS,
+			.spd_spec = {.spd_smbus_address = 0xa6}
+		},
+
+		/* Rcomp resistors on CFL-S are located on the CPU itself */
+		.rcomp_resistor = {121, 75, 100},
+
+		/* Rcomp target values for CFL-S, DDR4 and 2 DIMMs per channel */
+		.rcomp_targets = {60, 26, 20, 20, 26},
+
+		/* Baseboard is an interleaved design */
+		.dq_pins_interleaved = 1,
+
+		/* Baseboard is using config 2 for vref_ca */
+		.vref_ca_config = 2,
+
+		/* Disable Early Command Training */
+		.ect = 0,
+	};
+
+	memupd->FspmConfig.UserBd = BOARD_TYPE_SERVER;
+	/*
+	 * Disabling SendDidMsg is necessary because the IFD for this board
+	 * sets the HAP bit.  Otherwise, attempting to shut down causes a global
+	 * reset, and occasionally FSP-S freezes during boot.
+	 */
+	memupd->FspmTestConfig.SendDidMsg = 0;
+	cannonlake_memcfg_init(&memupd->FspmConfig, &memcfg);
+}