vboot/tpm2: enable nvmem commits on cr50 when writing firmware secdata

cr50 by default delays nvmem commits internally from the point of
reset to accumulate change state. However, the factory process can
put a board into dev mode through the recovery screen. This state
is stored in the TPM's nvmem space. When the factory process is
complete a disable_dev_request and battery_cutoff_request is performed.
This leads to disabling the dev mode in TPM, but the battery is
subsequently cut off so the nvmem contents never stick. Therefore,
whenever antirollback_write_space_firmware() is called we know there
was a change in secdata so request cr50 to immediately enable nvmem
commits going forward. This allows state changes to happen immediately.

The fallout from this is that when secdata is changed that current
boot will take longer because every transaction that writes to TPM
nvmem space will perform a write synchronously. All subsequent boots
do not have that effect.

It should also be noted that this approach to the implementation is
a pretty severe layering violation. However, the current TPM APIs
don't lend themselves well to extending commands or re-using code
outside of the current routines which inherently assume all knowledge
of every command (in conflict with vendor commands since those are
vendor-specific by definition).

BUG=b:35775104
BRANCH=reef
TEST=Confirmed disablement of dev mode sticks in the presence of:
crossystem disable_dev_request=1; crossystem
battery_cutoff_request=1; reboot;

Change-Id: I3395db9cbdfea45da1f5cb994c6570978593b944
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: https://review.coreboot.org/18681
Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
Tested-by: build bot (Jenkins)
diff --git a/src/lib/tpm2_tlcl.c b/src/lib/tpm2_tlcl.c
index 3d65a95..86cc74d 100644
--- a/src/lib/tpm2_tlcl.c
+++ b/src/lib/tpm2_tlcl.c
@@ -385,3 +385,23 @@
 
 	return TPM_SUCCESS;
 }
+
+uint32_t tlcl_cr50_enable_nvcommits(void)
+{
+	uint16_t sub_command = TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS;
+	struct tpm2_response *response;
+
+	printk(BIOS_INFO, "Enabling cr50 nvmem commmits\n");
+
+	response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, &sub_command);
+
+	if (response == NULL || (response && response->hdr.tpm_code)) {
+		if (response)
+			printk(BIOS_INFO, "%s: failed %x\n", __func__,
+				response->hdr.tpm_code);
+		else
+			printk(BIOS_INFO, "%s: failed\n", __func__);
+		return TPM_E_IOERROR;
+	}
+	return TPM_SUCCESS;
+}