sb/intel/common: Create a common PCH finalise implementation

The common finalise code is used by bd82x6x, Lynx Point, and Ibex Peak.

Lynx Point now benefits from being able to write-protect the flash chip.

For Lynx Point, writing the SPI OPMENU now happens in ramstage, as done
in bd82x6x.

Tested on an ASRock H81M-HDS (Lynx Point). When write-protection is
configured, flashrom reports all flash regions as read-only, and does
not manage to alter the contents of the flash chip.

Also tested on an ASUS P8H61-M LX (Cougar Point). Everything seems to
work as before.

Change-Id: I781082b1ed507b00815d1e85aec3e56ae5a4bef2
Signed-off-by: Tristan Corrick <tristan@corrick.kiwi>
Reviewed-on: https://review.coreboot.org/c/29977
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nico Huber <nico.h@gmx.de>
diff --git a/src/southbridge/intel/common/Kconfig b/src/southbridge/intel/common/Kconfig
index 957faa5..ba53f68 100644
--- a/src/southbridge/intel/common/Kconfig
+++ b/src/southbridge/intel/common/Kconfig
@@ -33,6 +33,9 @@
 config SOUTHBRIDGE_INTEL_COMMON_ACPI_MADT
 	bool
 
+config SOUTHBRIDGE_INTEL_COMMON_FINALIZE
+	bool
+
 config INTEL_DESCRIPTOR_MODE_CAPABLE
 	def_bool n
 	help
@@ -55,3 +58,42 @@
 	  locked down on each normal boot path (done by either coreboot or payload)
 	  and S3 resume (always done by coreboot). Select this to let coreboot
 	  to do this on normal boot path.
+
+if SOUTHBRIDGE_INTEL_COMMON_FINALIZE
+
+choice
+	prompt "Flash locking during chipset lockdown"
+	default LOCK_SPI_FLASH_NONE
+
+config LOCK_SPI_FLASH_NONE
+	bool "Don't lock flash sections"
+
+config LOCK_SPI_FLASH_RO
+	bool "Write-protect all flash sections"
+	help
+	  Select this if you want to write-protect the whole firmware flash
+	  chip. The locking will take place during the chipset lockdown, which
+	  is either triggered by coreboot (when INTEL_CHIPSET_LOCKDOWN is set)
+	  or has to be triggered later (e.g. by the payload or the OS).
+
+	        NOTE: If you trigger the chipset lockdown unconditionally,
+	        you won't be able to write to the flash chip using the
+	        internal programmer any more.
+
+config LOCK_SPI_FLASH_NO_ACCESS
+	bool "Write-protect all flash sections and read-protect non-BIOS sections"
+	help
+	  Select this if you want to protect the firmware flash against all
+	  further accesses (with the exception of the memory mapped BIOS re-
+	  gion which is always readable). The locking will take place during
+	  the chipset lockdown, which is either triggered by coreboot (when
+	  INTEL_CHIPSET_LOCKDOWN is set) or has to be triggered later (e.g.
+	  by the payload or the OS).
+
+	        NOTE: If you trigger the chipset lockdown unconditionally,
+	        you won't be able to write to the flash chip using the
+	        internal programmer any more.
+
+endchoice
+
+endif
diff --git a/src/southbridge/intel/common/Makefile.inc b/src/southbridge/intel/common/Makefile.inc
index b87354c..1a509b1 100644
--- a/src/southbridge/intel/common/Makefile.inc
+++ b/src/southbridge/intel/common/Makefile.inc
@@ -54,6 +54,8 @@
 
 ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_ACPI_MADT) += madt.c
 
+smm-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_FINALIZE) += finalize.c
+
 romstage-y += rtc.c
 ramstage-y += rtc.c
 postcar-y += rtc.c
diff --git a/src/southbridge/intel/common/finalize.c b/src/southbridge/intel/common/finalize.c
new file mode 100644
index 0000000..f1c33b9
--- /dev/null
+++ b/src/southbridge/intel/common/finalize.c
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2012 The Chromium OS Authors. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of
+ * the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <arch/io.h>
+#include <console/post_codes.h>
+#include <device/pci_ops.h>
+#include <southbridge/intel/common/pmbase.h>
+#include <southbridge/intel/common/pmutil.h>
+#include <southbridge/intel/common/rcba.h>
+#include <spi-generic.h>
+
+#include "finalize.h"
+
+void intel_pch_finalize_smm(void)
+{
+	const pci_devfn_t lpc_dev = PCI_DEV(0, 0x1f, 0);
+
+	if (IS_ENABLED(CONFIG_LOCK_SPI_FLASH_RO) ||
+	    IS_ENABLED(CONFIG_LOCK_SPI_FLASH_NO_ACCESS)) {
+		int i;
+		u32 lockmask = 1UL << 31;
+		if (IS_ENABLED(CONFIG_LOCK_SPI_FLASH_NO_ACCESS))
+			lockmask |= 1 << 15;
+		for (i = 0; i < 20; i += 4)
+			RCBA32(0x3874 + i) = RCBA32(0x3854 + i) | lockmask;
+	}
+
+	/* Lock SPIBAR */
+	RCBA32_OR(0x3804, (1 << 15));
+
+	if (IS_ENABLED(CONFIG_SPI_FLASH_SMM))
+		/* Re-init SPI driver to handle locked BAR */
+		spi_init();
+
+	/* TCLOCKDN: TC Lockdown */
+	RCBA32_OR(0x0050, (1UL << 31));
+
+	/* BIOS Interface Lockdown */
+	RCBA32_OR(0x3410, (1 << 0));
+
+	/* Function Disable SUS Well Lockdown */
+	RCBA_AND_OR(8, 0x3420, ~0U, (1 << 7));
+
+	pci_or_config16(lpc_dev, D31F0_GEN_PMCON_1, SMI_LOCK);
+
+	pci_or_config8(lpc_dev, D31F0_GEN_PMCON_LOCK,
+		       ACPI_BASE_LOCK | SLP_STR_POL_LOCK);
+
+	pci_update_config32(lpc_dev, D31F0_ETR3, ~ETR3_CF9GR, ETR3_CF9LOCK);
+
+	if (IS_ENABLED(CONFIG_SOUTHBRIDGE_INTEL_LYNXPOINT))
+		/* PMSYNC */
+		RCBA32_OR(0x33c4, (1UL << 31));
+
+	/* R/WO registers */
+	RCBA32(0x21a4) = RCBA32(0x21a4);
+	pci_write_config32(PCI_DEV(0, 27, 0), 0x74,
+		    pci_read_config32(PCI_DEV(0, 27, 0), 0x74));
+
+	write_pmbase16(TCO1_CNT, read_pmbase16(TCO1_CNT) | TCO_LOCK);
+
+	outb(POST_OS_BOOT, CONFIG_POST_IO_PORT);
+}
diff --git a/src/southbridge/intel/common/finalize.h b/src/southbridge/intel/common/finalize.h
new file mode 100644
index 0000000..4a8cbc0
--- /dev/null
+++ b/src/southbridge/intel/common/finalize.h
@@ -0,0 +1,22 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2018 Tristan Corrick <tristan@corrick.kiwi>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SOUTHBRIDGE_INTEL_COMMON_FINALIZE_H
+#define SOUTHBRIDGE_INTEL_COMMON_FINALIZE_H
+
+void intel_pch_finalize_smm(void);
+
+#endif /* SOUTHBRIDGE_INTEL_COMMON_FINALIZE_H */
diff --git a/src/southbridge/intel/common/pmutil.h b/src/southbridge/intel/common/pmutil.h
index 2e761cc..47813f7 100644
--- a/src/southbridge/intel/common/pmutil.h
+++ b/src/southbridge/intel/common/pmutil.h
@@ -20,10 +20,20 @@
 #include <cpu/x86/smm.h>
 
 #define D31F0_PMBASE		0x40
+#define D31F0_GEN_PMCON_1	0xa0
+#define   SMI_LOCK		(1 << 4)
+#define D31F0_GEN_PMCON_2	0xa2
 #define D31F0_GEN_PMCON_3	0xa4
 #define   RTC_BATTERY_DEAD		(1 << 2)
 #define   RTC_POWER_FAILED		(1 << 1)
 #define   SLEEP_AFTER_POWER_FAIL	(1 << 0)
+#define D31F0_GEN_PMCON_LOCK	0xa6
+#define   ACPI_BASE_LOCK	(1 << 1)
+#define   SLP_STR_POL_LOCK	(1 << 2)
+#define D31F0_ETR3		0xac
+#define   ETR3_CWORWRE		(1 << 18)
+#define   ETR3_CF9GR		(1 << 20)
+#define   ETR3_CF9LOCK		(1 << 31)
 #define D31F0_GPIO_ROUT		0xb8
 #define  GPI_DISABLE		0x00
 #define  GPI_IS_SMI		0x01