Add CONFIG_TPM_AUTOSTART, which runs the TPM startup and self-test
sequence from an EVT_LAST_STAGE_INIT handler. This is the same thing the
'tpm autostart' command does, but it does not depend on a boot script or
on the environment, so it cannot be skipped by a stale or edited env.

Today a TPM is only started automatically when either CONFIG_MEASURED_BOOT
is used (and then only from bootm) or when booting via EFI with
CONFIG_EFI_TCG2_PROTOCOL. A plain booti/bootm therefore leaves the chip
uninitialised and the OS has to start it itself, which Linux reports as
"A TPM error (256) occurred attempting the self test". Boards have worked
around this by putting 'tpm autostart' into their environment, see
board/xilinx/zynqmp/zynqmp_kria.env.

Boards that share one binary between variants with and without a TPM
fitted can enable this safely: when no TPM device is found the startup is
skipped silently.

Signed-off-by: Michael Haener <[email protected]>
---
 drivers/tpm/Kconfig         | 15 +++++++++++++++
 drivers/tpm/Makefile        |  1 +
 drivers/tpm/tpm_autostart.c | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 49 insertions(+)
 create mode 100644 drivers/tpm/tpm_autostart.c

diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig
index 219ea606b50..97979f39c7d 100644
--- a/drivers/tpm/Kconfig
+++ b/drivers/tpm/Kconfig
@@ -4,6 +4,21 @@
 
 menu "TPM support"
 
+config TPM_AUTOSTART
+       bool "Start the TPM during board initialisation"
+       depends on TPM
+       select EVENT
+       help
+         Run the TPM startup and self-test sequence from an EVT_LAST_STAGE_INIT
+         handler, which is the same thing the 'tpm autostart' command does.
+         Without this the chip is still uninitialised when the OS takes over
+         and the OS has to start it itself, which some kernels report as an
+         error.
+
+         Boards that share one binary between variants with and without a TPM
+         fitted can enable this safely: when no TPM device is found the
+         startup is skipped silently.
+
 config TPM_V1
        bool "TPMv1.x support"
        depends on TPM
diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile
index b83ce703ec0..c3bc6074b67 100644
--- a/drivers/tpm/Makefile
+++ b/drivers/tpm/Makefile
@@ -2,6 +2,7 @@
 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 
 obj-$(CONFIG_$(PHASE_)TPM) += tpm-uclass.o
+obj-$(CONFIG_$(PHASE_)TPM_AUTOSTART) += tpm_autostart.o
 
 obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o
 obj-$(CONFIG_TPM_TIS_INFINEON) += tpm_tis_infineon.o
diff --git a/drivers/tpm/tpm_autostart.c b/drivers/tpm/tpm_autostart.c
new file mode 100644
index 00000000000..23d8f3a53a6
--- /dev/null
+++ b/drivers/tpm/tpm_autostart.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Start the TPM during init, so that the OS does not have to do it.
+ *
+ * Copyright (c) 2026 Siemens AG
+ */
+
+#define LOG_CATEGORY UCLASS_TPM
+
+#include <dm.h>
+#include <event.h>
+#include <log.h>
+#include <tpm_api.h>
+
+static int tpm_evt_autostart(void)
+{
+       struct udevice *dev;
+       int ret;
+
+       /* A board may share one binary between variants without a TPM. */
+       ret = uclass_first_device_err(UCLASS_TPM, &dev);
+       if (ret) {
+               log_debug("No TPM found (err=%d)\n", ret);
+               return 0;
+       }
+
+       ret = tpm_auto_start(dev);
+       if (ret)
+               log_warning("TPM startup failed (err=%d)\n", ret);
+
+       return 0;
+}
+EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, tpm_evt_autostart);
-- 
2.55.0

Reply via email to