git: c2e9c5bbf022 - main - tpm: Refactor TIS and add a SPI attachment

From: Justin Hibbits <jhibbits_at_FreeBSD.org>
Date: Fri, 03 May 2024 20:32:43 UTC
The branch main has been updated by jhibbits:

URL: https://cgit.FreeBSD.org/src/commit/?id=c2e9c5bbf02294376988f3e7eba82b8e078cdf30

commit c2e9c5bbf02294376988f3e7eba82b8e078cdf30
Author:     Justin Hibbits <jhibbits@FreeBSD.org>
AuthorDate: 2023-11-13 16:33:44 +0000
Commit:     Justin Hibbits <jhibbits@FreeBSD.org>
CommitDate: 2024-05-03 20:26:11 +0000

    tpm: Refactor TIS and add a SPI attachment
    
    Summary:
    Though mostly used in x86 devices, TPM can be used on others, with a
    direct SPI attachment.  Refactor the TPM 2.0 driver set to use an
    attachment interface, and implement a SPI bus interface.
    
    Test Plan:
    Tested on a Raspberry Pi 4, with a GeeekPi TPM2.0 module (SLB9670
    TPM) using security/tpm2-tools tpm2_getcaps for very light testing against the
    spibus attachment.
    
    Reviewed by:    kd
    Obtained from:  Juniper Networks, Inc.
    Differential Revision: https://reviews.freebsd.org/D45069
---
 sys/conf/files                            |   7 ++
 sys/conf/files.amd64                      |   2 -
 sys/dev/tpm/tpm20.c                       |   6 +-
 sys/dev/tpm/tpm20.h                       |  53 ++++------
 sys/dev/tpm/tpm_bus.c                     |  99 ++++++++++++++++++
 sys/dev/tpm/tpm_crb.c                     |  66 ++++++------
 sys/dev/tpm/tpm_if.m                      |  76 ++++++++++++++
 sys/dev/tpm/tpm_spibus.c                  | 166 ++++++++++++++++++++++++++++++
 sys/dev/tpm/tpm_tis_acpi.c                |  86 ++++++++++++++++
 sys/dev/tpm/{tpm_tis.c => tpm_tis_core.c} | 118 ++++++++-------------
 sys/dev/tpm/tpm_tis_spibus.c              |  91 ++++++++++++++++
 sys/modules/Makefile                      |   3 +-
 sys/modules/tpm/Makefile                  |  21 +++-
 13 files changed, 640 insertions(+), 154 deletions(-)

diff --git a/sys/conf/files b/sys/conf/files
index f68567aa9023..4d7f28ceaaf1 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3194,6 +3194,13 @@ dev/syscons/warp/warp_saver.c	optional warp_saver
 dev/tcp_log/tcp_log_dev.c	optional tcp_blackbox inet | tcp_blackbox inet6
 dev/tdfx/tdfx_pci.c		optional tdfx pci
 dev/ti/if_ti.c			optional ti pci
+dev/tpm/tpm20.c			optional	tpm
+dev/tpm/tpm_bus.c		optional tpm acpi
+dev/tpm/tpm_if.m		optional tpm
+dev/tpm/tpm_spibus.c		optional tpm spibus fdt
+dev/tpm/tpm_tis_acpi.c		optional tpm acpi
+dev/tpm/tpm_tis_core.c		optional tpm
+dev/tpm/tpm_tis_spibus.c	optional tpm spibus fdt
 dev/tws/tws.c			optional tws
 dev/tws/tws_cam.c		optional tws
 dev/tws/tws_hdm.c		optional tws
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index 6322837c887b..18dec5ed47b0 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -372,9 +372,7 @@ dev/smartpqi/smartpqi_sis.c     optional 	smartpqi
 dev/smartpqi/smartpqi_tag.c     optional 	smartpqi
 dev/sume/if_sume.c		optional	sume
 dev/syscons/apm/apm_saver.c	optional	apm_saver apm
-dev/tpm/tpm20.c			optional	tpm
 dev/tpm/tpm_crb.c		optional	tpm acpi
-dev/tpm/tpm_tis.c		optional	tpm acpi
 dev/tpm/tpm_acpi.c		optional	tpm acpi
 dev/tpm/tpm_isa.c		optional	tpm isa
 dev/p2sb/p2sb.c			optional	p2sb pci
diff --git a/sys/dev/tpm/tpm20.c b/sys/dev/tpm/tpm20.c
index da090bc068c9..3399e17f53aa 100644
--- a/sys/dev/tpm/tpm20.c
+++ b/sys/dev/tpm/tpm20.c
@@ -127,7 +127,7 @@ tpm20_write(struct cdev *dev, struct uio *uio, int flags)
 		return (result);
 	}
 
-	result = sc->transmit(sc, byte_count);
+	result = TPM_TRANSMIT(sc->dev, byte_count);
 
 	if (result == 0) {
 		callout_reset(&sc->discard_buffer_callout,
@@ -267,7 +267,7 @@ tpm20_harvest(void *arg, int unused)
 		cv_wait(&sc->buf_cv, &sc->dev_lock);
 
 	memcpy(sc->buf, cmd, sizeof(cmd));
-	result = sc->transmit(sc, sizeof(cmd));
+	result = TPM_TRANSMIT(sc->dev, sizeof(cmd));
 	if (result != 0) {
 		sx_xunlock(&sc->dev_lock);
 		return;
@@ -319,7 +319,7 @@ tpm20_save_state(device_t dev, bool suspend)
 	sx_xlock(&sc->dev_lock);
 
 	memcpy(sc->buf, save_cmd, sizeof(save_cmd));
-	sc->transmit(sc, sizeof(save_cmd));
+	TPM_TRANSMIT(sc->dev, sizeof(save_cmd));
 
 	sx_xunlock(&sc->dev_lock);
 
diff --git a/sys/dev/tpm/tpm20.h b/sys/dev/tpm/tpm20.h
index 14f89de3e84e..683cd7549bd4 100644
--- a/sys/dev/tpm/tpm20.h
+++ b/sys/dev/tpm/tpm20.h
@@ -28,6 +28,7 @@
 #ifndef _TPM20_H_
 #define	_TPM20_H_
 
+#include "opt_acpi.h"
 #include <sys/cdefs.h>
 #include <sys/endian.h>
 #include <sys/param.h>
@@ -39,6 +40,7 @@
 #include <sys/bus.h>
 #include <sys/callout.h>
 #include <sys/conf.h>
+#include <sys/lock.h>
 #include <sys/module.h>
 #include <sys/rman.h>
 #include <sys/sx.h>
@@ -49,12 +51,14 @@
 #include <machine/md_var.h>
 #include <machine/resource.h>
 
+#ifdef	DEV_ACPI
 #include <contrib/dev/acpica/include/acpi.h>
 #include <contrib/dev/acpica/include/accommon.h>
 #include <dev/acpica/acpivar.h>
-#include "opt_acpi.h"
+#endif
 
 #include "opt_tpm.h"
+#include "tpm_if.h"
 
 #define	BIT(x) (1 << (x))
 
@@ -136,55 +140,36 @@ int32_t tpm20_get_timeout(uint32_t command);
 int tpm20_init(struct tpm_sc *sc);
 void tpm20_release(struct tpm_sc *sc);
 
-/* Small helper routines for io ops */
-static inline uint8_t
-RD1(struct tpm_sc *sc, bus_size_t off)
-{
-
-	return (bus_read_1(sc->mem_res, off));
-}
-static inline uint32_t
-RD4(struct tpm_sc *sc, bus_size_t off)
-{
-
-	return (bus_read_4(sc->mem_res, off));
-}
-#ifdef __amd64__
-static inline uint64_t
-RD8(struct tpm_sc *sc, bus_size_t off)
-{
+/* Mode driver types */
+DECLARE_CLASS(tpmtis_driver);
+int tpmtis_attach(device_t dev);
 
-	return (bus_read_8(sc->mem_res, off));
-}
-#endif
-static inline void
-WR1(struct tpm_sc *sc, bus_size_t off, uint8_t val)
-{
+DECLARE_CLASS(tpmcrb_driver);
 
-	bus_write_1(sc->mem_res, off, val);
-}
-static inline void
-WR4(struct tpm_sc *sc, bus_size_t off, uint32_t val)
-{
+/* Bus driver types */
+DECLARE_CLASS(tpm_bus_driver);
+DECLARE_CLASS(tpm_spi_driver);
 
-	bus_write_4(sc->mem_res, off, val);
-}
+/* Small helper routines for io ops */
 static inline void
 AND4(struct tpm_sc *sc, bus_size_t off, uint32_t val)
 {
+	uint32_t v = TPM_READ_4(sc->dev, off);
 
-	WR4(sc, off, RD4(sc, off) & val);
+	TPM_WRITE_4(sc->dev, off, v & val);
 }
 static inline void
 OR1(struct tpm_sc *sc, bus_size_t off, uint8_t val)
 {
+	uint8_t v = TPM_READ_1(sc->dev, off);
 
-	WR1(sc, off, RD1(sc, off) | val);
+	TPM_WRITE_1(sc->dev, off, v | val);
 }
 static inline void
 OR4(struct tpm_sc *sc, bus_size_t off, uint32_t val)
 {
+	uint32_t v = TPM_READ_1(sc->dev, off);
 
-	WR4(sc, off, RD4(sc, off) | val);
+	TPM_WRITE_4(sc->dev, off, v | val);
 }
 #endif	/* _TPM20_H_ */
diff --git a/sys/dev/tpm/tpm_bus.c b/sys/dev/tpm/tpm_bus.c
new file mode 100644
index 000000000000..f0d3c26c33f1
--- /dev/null
+++ b/sys/dev/tpm/tpm_bus.c
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 2023 Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/bus.h>
+#include "tpm_if.h"
+#include "tpm20.h"
+
+/* Override accessors */
+static uint8_t
+tpm_read_1(device_t dev, bus_size_t off)
+{
+	struct tpm_sc *sc = device_get_softc(dev);
+
+	return (bus_read_1(sc->mem_res, off));
+}
+
+static uint32_t
+tpm_read_4(device_t dev, bus_size_t off)
+{
+	struct tpm_sc *sc = device_get_softc(dev);
+
+	return (bus_read_4(sc->mem_res, off));
+}
+
+/*
+ * Only i386 is missing bus_space_read_8.
+ */
+#ifndef __i386__
+static uint64_t
+tpm_read_8(device_t dev, bus_size_t off)
+{
+	struct tpm_sc *sc = device_get_softc(dev);
+
+	return (bus_read_8(sc->mem_res, off));
+}
+#endif
+
+static void
+tpm_write_1(device_t dev, bus_size_t off, uint8_t val)
+{
+	struct tpm_sc *sc = device_get_softc(dev);
+
+	bus_write_1(sc->mem_res, off, val);
+}
+
+static void
+tpm_write_4(device_t dev, bus_size_t off, uint32_t val)
+{
+	struct tpm_sc *sc = device_get_softc(dev);
+
+	bus_write_4(sc->mem_res, off, val);
+}
+
+static void
+tpm_write_barrier(device_t dev, bus_addr_t off, bus_size_t length)
+{
+	struct tpm_sc *sc = device_get_softc(dev);
+
+	bus_barrier(sc->mem_res, off, length, BUS_SPACE_BARRIER_WRITE);
+}
+
+static device_method_t tpm_bus_methods[] = {
+	DEVMETHOD(tpm_read_1,	tpm_read_1),
+	DEVMETHOD(tpm_read_4,	tpm_read_4),
+#ifndef __i386__
+	DEVMETHOD(tpm_read_8,	tpm_read_8),
+#endif
+	DEVMETHOD(tpm_write_1,	tpm_write_1),
+	DEVMETHOD(tpm_write_4,	tpm_write_4),
+	DEVMETHOD(tpm_write_barrier,	tpm_write_barrier),
+	DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(tpm_lbc, tpm_bus_driver, tpm_bus_methods, sizeof(struct tpm_sc));
diff --git a/sys/dev/tpm/tpm_crb.c b/sys/dev/tpm/tpm_crb.c
index bb4df82e613b..b9ddcf0dd3e1 100644
--- a/sys/dev/tpm/tpm_crb.c
+++ b/sys/dev/tpm/tpm_crb.c
@@ -83,7 +83,7 @@ struct tpmcrb_sc {
 	size_t		rsp_buf_size;
 };
 
-int tpmcrb_transmit(struct tpm_sc *sc, size_t size);
+int tpmcrb_transmit(device_t dev, size_t size);
 
 static int tpmcrb_acpi_probe(device_t dev);
 static int tpmcrb_attach(device_t dev);
@@ -185,15 +185,15 @@ tpmcrb_attach(device_t dev)
 	 * stored in a single 8 byte one.
 	 */
 #ifdef __amd64__
-	crb_sc->rsp_off = RD8(sc, TPM_CRB_CTRL_RSP_ADDR);
+	crb_sc->rsp_off = TPM_READ_8(sc->dev, TPM_CRB_CTRL_RSP_ADDR);
 #else
-	crb_sc->rsp_off = RD4(sc, TPM_CRB_CTRL_RSP_ADDR);
-	crb_sc->rsp_off |= ((uint64_t) RD4(sc, TPM_CRB_CTRL_RSP_HADDR) << 32);
+	crb_sc->rsp_off = TPM_READ_4(sc->dev, TPM_CRB_CTRL_RSP_ADDR);
+	crb_sc->rsp_off |= ((uint64_t) TPM_READ_4(sc->dev, TPM_CRB_CTRL_RSP_HADDR) << 32);
 #endif
-	crb_sc->cmd_off = RD4(sc, TPM_CRB_CTRL_CMD_LADDR);
-	crb_sc->cmd_off |= ((uint64_t) RD4(sc, TPM_CRB_CTRL_CMD_HADDR) << 32);
-	crb_sc->cmd_buf_size = RD4(sc, TPM_CRB_CTRL_CMD_SIZE);
-	crb_sc->rsp_buf_size = RD4(sc, TPM_CRB_CTRL_RSP_SIZE);
+	crb_sc->cmd_off = TPM_READ_4(sc->dev, TPM_CRB_CTRL_CMD_LADDR);
+	crb_sc->cmd_off |= ((uint64_t) TPM_READ_4(sc->dev, TPM_CRB_CTRL_CMD_HADDR) << 32);
+	crb_sc->cmd_buf_size = TPM_READ_4(sc->dev, TPM_CRB_CTRL_CMD_SIZE);
+	crb_sc->rsp_buf_size = TPM_READ_4(sc->dev, TPM_CRB_CTRL_RSP_SIZE);
 
 	tpmcrb_relinquish_locality(sc);
 
@@ -218,8 +218,6 @@ tpmcrb_attach(device_t dev)
 		}
 	}
 
-	sc->transmit = tpmcrb_transmit;
-
 	result = tpm20_init(sc);
 	if (result != 0)
 		tpmcrb_detach(dev);
@@ -248,11 +246,11 @@ tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off, uint32_t mask, uint32_t val,
 {
 
 	/* Check for condition */
-	if ((RD4(sc, off) & mask) == val)
+	if ((TPM_READ_4(sc->dev, off) & mask) == val)
 		return (true);
 
 	while (timeout > 0) {
-		if ((RD4(sc, off) & mask) == val)
+		if ((TPM_READ_4(sc->dev, off) & mask) == val)
 			return (true);
 
 		pause("TPM in polling mode", 1);
@@ -291,7 +289,7 @@ tpmcrb_cancel_cmd(struct tpm_sc *sc)
 {
 	uint32_t mask = ~0;
 
-	WR4(sc, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CMD);
+	TPM_WRITE_4(sc->dev, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CMD);
 	if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_START,
 		    mask, ~mask, TPM_TIMEOUT_B)) {
 		device_printf(sc->dev,
@@ -299,48 +297,50 @@ tpmcrb_cancel_cmd(struct tpm_sc *sc)
 		return (false);
 	}
 
-	WR4(sc, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CLEAR);
+	TPM_WRITE_4(sc->dev, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CLEAR);
 	return (true);
 }
 
 int
-tpmcrb_transmit(struct tpm_sc *sc, size_t length)
+tpmcrb_transmit(device_t dev, size_t length)
 {
 	struct tpmcrb_sc *crb_sc;
+	struct tpm_sc *sc;
 	uint32_t mask, curr_cmd;
 	int timeout, bytes_available;
 
-	crb_sc = (struct tpmcrb_sc *)sc;
+	crb_sc = device_get_softc(dev);
+	sc = &crb_sc->base;
 
 	sx_assert(&sc->dev_lock, SA_XLOCKED);
 
 	if (length > crb_sc->cmd_buf_size) {
-		device_printf(sc->dev,
+		device_printf(dev,
 		    "Requested transfer is bigger than buffer size\n");
 		return (E2BIG);
 	}
 
-	if (RD4(sc, TPM_CRB_CTRL_STS) & TPM_CRB_CTRL_STS_ERR_BIT) {
-		device_printf(sc->dev,
+	if (TPM_READ_4(dev, TPM_CRB_CTRL_STS) & TPM_CRB_CTRL_STS_ERR_BIT) {
+		device_printf(dev,
 		    "Device has Error bit set\n");
 		return (EIO);
 	}
 	if (!tpmcrb_request_locality(sc, 0)) {
-		device_printf(sc->dev,
+		device_printf(dev,
 		    "Failed to obtain locality\n");
 		return (EIO);
 	}
 	/* Clear cancellation bit */
-	WR4(sc, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CLEAR);
+	TPM_WRITE_4(dev, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CLEAR);
 
 	/* Switch device to idle state if necessary */
-	if (!(RD4(sc, TPM_CRB_CTRL_STS) & TPM_CRB_CTRL_STS_IDLE_BIT)) {
+	if (!(TPM_READ_4(dev, TPM_CRB_CTRL_STS) & TPM_CRB_CTRL_STS_IDLE_BIT)) {
 		OR4(sc, TPM_CRB_CTRL_REQ, TPM_CRB_CTRL_REQ_GO_IDLE);
 
 		mask = TPM_CRB_CTRL_STS_IDLE_BIT;
 		if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_STS,
 			    mask, mask, TPM_TIMEOUT_C)) {
-			device_printf(sc->dev,
+			device_printf(dev,
 			    "Failed to transition to idle state\n");
 			return (EIO);
 		}
@@ -351,7 +351,7 @@ tpmcrb_transmit(struct tpm_sc *sc, size_t length)
 	mask = TPM_CRB_CTRL_REQ_GO_READY;
 	if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_STS,
 		    mask, !mask, TPM_TIMEOUT_C)) {
-		device_printf(sc->dev,
+		device_printf(dev,
 		    "Failed to transition to ready state\n");
 		return (EIO);
 	}
@@ -366,16 +366,14 @@ tpmcrb_transmit(struct tpm_sc *sc, size_t length)
 	/* Send command and tell device to process it. */
 	bus_write_region_stream_1(sc->mem_res, crb_sc->cmd_off,
 	    sc->buf, length);
-	bus_barrier(sc->mem_res, crb_sc->cmd_off,
-	    length, BUS_SPACE_BARRIER_WRITE);
+	TPM_WRITE_BARRIER(dev, crb_sc->cmd_off, length);
 
-	WR4(sc, TPM_CRB_CTRL_START, TPM_CRB_CTRL_START_CMD);
-	bus_barrier(sc->mem_res, TPM_CRB_CTRL_START,
-	    4, BUS_SPACE_BARRIER_WRITE);
+	TPM_WRITE_4(dev, TPM_CRB_CTRL_START, TPM_CRB_CTRL_START_CMD);
+	TPM_WRITE_BARRIER(dev, TPM_CRB_CTRL_START, 4);
 
 	mask = ~0;
 	if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_START, mask, ~mask, timeout)) {
-		device_printf(sc->dev,
+		device_printf(dev,
 		    "Timeout while waiting for device to process cmd\n");
 		if (!tpmcrb_cancel_cmd(sc))
 			return (EIO);
@@ -387,7 +385,7 @@ tpmcrb_transmit(struct tpm_sc *sc, size_t length)
 	bytes_available = be32toh(*(uint32_t *) (&sc->buf[2]));
 
 	if (bytes_available > TPM_BUFSIZE || bytes_available < TPM_HEADER_SIZE) {
-		device_printf(sc->dev,
+		device_printf(dev,
 		    "Incorrect response size: %d\n",
 		    bytes_available);
 		return (EIO);
@@ -411,11 +409,11 @@ static device_method_t	tpmcrb_methods[] = {
 	DEVMETHOD(device_detach,	tpmcrb_detach),
 	DEVMETHOD(device_shutdown,	tpm20_shutdown),
 	DEVMETHOD(device_suspend,	tpm20_suspend),
+	DEVMETHOD(tpm_transmit,		tpmcrb_transmit),
 	{0, 0}
 };
 
-static driver_t	tpmcrb_driver = {
-	"tpmcrb", tpmcrb_methods, sizeof(struct tpmcrb_sc),
-};
+DEFINE_CLASS_1(tpmcrb, tpmcrb_driver, tpmcrb_methods, sizeof(struct tpmcrb_sc),
+    tpm_bus_driver);
 
 DRIVER_MODULE(tpmcrb, acpi, tpmcrb_driver, 0, 0);
diff --git a/sys/dev/tpm/tpm_if.m b/sys/dev/tpm/tpm_if.m
new file mode 100644
index 000000000000..2b6afe22f3e8
--- /dev/null
+++ b/sys/dev/tpm/tpm_if.m
@@ -0,0 +1,76 @@
+#-
+# Copyright (c) 2023 Juniper Networks, Inc.
+# All Rights Reserved
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#
+
+#include <sys/bus.h>
+#include <dev/tpm/tpm20.h>
+
+INTERFACE tpm;
+
+#
+# Transfer data to the TPM data buffer
+#
+METHOD int transmit {
+	device_t dev;
+	size_t length;
+};
+
+
+METHOD uint64_t read_8 {
+	device_t dev;
+	bus_addr_t addr;
+}
+
+#
+# Read 4 bytes (host endian) from a TPM register
+#
+METHOD uint32_t read_4 {
+	device_t dev;
+	bus_addr_t addr;
+};
+
+METHOD uint8_t read_1 {
+	device_t dev;
+	bus_addr_t addr;
+};
+
+METHOD void write_4 {
+	device_t dev;
+	bus_addr_t addr;
+	uint32_t value;
+};
+
+METHOD void write_1 {
+	device_t dev;
+	bus_addr_t addr;
+	uint8_t value;
+};
+
+METHOD void write_barrier {
+	device_t dev;
+	bus_addr_t off;
+	bus_size_t length;
+}
diff --git a/sys/dev/tpm/tpm_spibus.c b/sys/dev/tpm/tpm_spibus.c
new file mode 100644
index 000000000000..f83ff42d77b1
--- /dev/null
+++ b/sys/dev/tpm/tpm_spibus.c
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 2023 Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/bus.h>
+
+#include <dev/spibus/spi.h>
+#include "spibus_if.h"
+#include "tpm_if.h"
+#include "tpm20.h"
+
+#define	TPM_BASE_ADDR		0xD40000
+#define	TPM_SPI_HEADER_SIZE	4
+#define	TPM_WAIT_STATES		50
+
+static void
+tpm_insert_wait(device_t dev)
+{
+	device_t parent = device_get_parent(dev);
+	int wait = TPM_WAIT_STATES;
+	struct spi_command spic = SPI_COMMAND_INITIALIZER;
+
+	uint8_t txb = 0;
+	uint8_t rxb = 0;
+
+	spic.tx_cmd = &txb;
+	spic.rx_cmd = &rxb;
+	spic.tx_cmd_sz = 1;
+	spic.rx_cmd_sz = 1;
+	spic.flags = SPI_FLAG_KEEP_CS;
+	do {
+		SPIBUS_TRANSFER(parent, dev, &spic);
+	} while (--wait > 0 && (rxb & 0x1) == 0);
+}
+
+static inline int
+tpm_spi_read_n(device_t dev, bus_size_t off, void *buf, size_t size)
+{
+	struct spi_command spic = SPI_COMMAND_INITIALIZER;
+	uint8_t tx[4] = {0};
+	uint8_t rx[4] = {0};
+	int err;
+
+	if (size > sizeof(rx))
+		return (EINVAL);
+	off += TPM_BASE_ADDR;
+	tx[0] = 0x80 | (size - 1); /* Write (size) bytes */
+	tx[1] = (off >> 16) & 0xff;
+	tx[2] = (off >> 8) & 0xff;
+	tx[3] = off & 0xff;
+
+	spic.tx_cmd = tx;
+	spic.tx_cmd_sz = sizeof(tx);
+	spic.rx_cmd = rx;
+	spic.rx_cmd_sz = sizeof(tx);
+	spic.flags = SPI_FLAG_KEEP_CS;
+
+	err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &spic);
+
+	if (!(rx[3] & 0x1)) {
+		tpm_insert_wait(dev);
+	}
+	memset(tx, 0, sizeof(tx));
+	spic.tx_cmd_sz = spic.rx_cmd_sz = size;
+	spic.flags = 0;
+	err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &spic);
+	memcpy(buf, &rx[0], size);
+
+	return (err);
+}
+
+static inline int
+tpm_spi_write_n(device_t dev, bus_size_t off, void *buf, size_t size)
+{
+	struct spi_command spic = SPI_COMMAND_INITIALIZER;
+	uint8_t tx[8] = {0};
+	uint8_t rx[8] = {0};
+	int err;
+
+	off += TPM_BASE_ADDR;
+	tx[0] = 0x00 | (size - 1); /* Write (size) bytes */
+	tx[1] = (off >> 16) & 0xff;
+	tx[2] = (off >> 8) & 0xff;
+	tx[3] = off & 0xff;
+
+	memcpy(&tx[4], buf, size);
+
+	spic.tx_cmd = tx;
+	spic.tx_cmd_sz = size + TPM_SPI_HEADER_SIZE;
+	spic.rx_cmd = rx;
+	spic.rx_cmd_sz = size + TPM_SPI_HEADER_SIZE;
+
+	err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &spic);
+
+	return (err);
+}
+
+/* Override accessors */
+static inline uint8_t
+spi_read_1(device_t dev, bus_size_t off)
+{
+	uint8_t rx_byte;
+
+	tpm_spi_read_n(dev, off, &rx_byte, 1);
+
+	return (rx_byte);
+}
+
+static inline uint32_t
+spi_read_4(device_t dev, bus_size_t off)
+{
+	uint32_t rx_word = 0;
+
+	tpm_spi_read_n(dev, off, &rx_word, 4);
+	rx_word = le32toh(rx_word);
+
+	return (rx_word);
+}
+
+static inline void
+spi_write_1(device_t dev, bus_size_t off, uint8_t val)
+{
+	tpm_spi_write_n(dev, off, &val, 1);
+}
+
+static inline void
+spi_write_4(device_t dev, bus_size_t off, uint32_t val)
+{
+	uint32_t tmp = htole32(val);
+	tpm_spi_write_n(dev, off, &tmp, 4);
+}
+
+static device_method_t tpm_spibus_methods[] = {
+	DEVMETHOD(tpm_read_4,	spi_read_4),
+	DEVMETHOD(tpm_read_1,	spi_read_1),
+	DEVMETHOD(tpm_write_4,	spi_write_4),
+	DEVMETHOD(tpm_write_1,	spi_write_1),
+	DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(tpm_spi, tpm_spi_driver, tpm_spibus_methods,
+    sizeof(struct tpm_sc));
diff --git a/sys/dev/tpm/tpm_tis_acpi.c b/sys/dev/tpm/tpm_tis_acpi.c
new file mode 100644
index 000000000000..32c73e5f2483
--- /dev/null
+++ b/sys/dev/tpm/tpm_tis_acpi.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 2018 Stormshield.
+ * Copyright (c) 2018 Semihalf.
+ * Copyright (c) 2023 Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include "tpm20.h"
+#include "tpm_if.h"
+
+static int tpmtis_acpi_probe(device_t dev);
+
+char *tpmtis_ids[] = {"MSFT0101", NULL};
+
+static int
+tpmtis_acpi_probe(device_t dev)
+{
+	int err;
+	ACPI_TABLE_TPM23 *tbl;
+	ACPI_STATUS status;
+
+	err = ACPI_ID_PROBE(device_get_parent(dev), dev, tpmtis_ids, NULL);
+	if (err > 0)
+		return (err);
+	/*Find TPM2 Header*/
+	status = AcpiGetTable(ACPI_SIG_TPM2, 1, (ACPI_TABLE_HEADER **) &tbl);
+	if(ACPI_FAILURE(status) ||
+	   tbl->StartMethod != TPM2_START_METHOD_TIS)
+	    err = ENXIO;
+
+	device_set_desc(dev, "Trusted Platform Module 2.0, FIFO mode");
+	return (err);
+}
+
+static int
+tpmtis_acpi_attach(device_t dev)
+{
+	struct tpm_sc *sc = device_get_softc(dev);
+
+	sc->mem_rid = 0;
+	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
+		    RF_ACTIVE);
+	if (sc->mem_res == NULL) {
+		return (ENXIO);
+	}
+
+	/*
+	 * If tpmtis_attach() fails, tpmtis_detach() will automatically free
+	 * sc->mem_res (not-NULL).
+	 */
+	return (tpmtis_attach(dev));
+}
+
+/* ACPI Driver */
+static device_method_t tpmtis_methods[] = {
+	DEVMETHOD(device_attach,	tpmtis_acpi_attach),
+	DEVMETHOD(device_probe,		tpmtis_acpi_probe),
+	DEVMETHOD_END
+};
+
+DEFINE_CLASS_2(tpmtis, tpmtis_acpi_driver, tpmtis_methods,
+    sizeof(struct tpm_sc), tpmtis_driver, tpm_bus_driver);
+
+DRIVER_MODULE(tpmtis, acpi, tpmtis_driver, 0, 0);
diff --git a/sys/dev/tpm/tpm_tis.c b/sys/dev/tpm/tpm_tis_core.c
similarity index 82%
rename from sys/dev/tpm/tpm_tis.c
rename to sys/dev/tpm/tpm_tis_core.c
index b97d7ab3f8e8..230eb12d2acd 100644
--- a/sys/dev/tpm/tpm_tis.c
+++ b/sys/dev/tpm/tpm_tis_core.c
@@ -27,6 +27,7 @@
 
 #include <sys/cdefs.h>
 #include "tpm20.h"
+#include "tpm_if.h"
 
 /*
  * TIS register space as defined in
@@ -72,10 +73,8 @@
 #define	TPM_STS_BURST_MASK		0xFFFF00
 #define	TPM_STS_BURST_OFFSET		0x8
 
-static int tpmtis_transmit(struct tpm_sc *sc, size_t length);
+static int tpmtis_transmit(device_t dev, size_t length);
 
-static int tpmtis_acpi_probe(device_t dev);
-static int tpmtis_attach(device_t dev);
 static int tpmtis_detach(device_t dev);
 
 static void tpmtis_intr_handler(void *arg);
@@ -93,29 +92,7 @@ static bool tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off,
 
 static uint16_t tpmtis_wait_for_burst(struct tpm_sc *sc);
 
-char *tpmtis_ids[] = {"MSFT0101", NULL};
-
-static int
-tpmtis_acpi_probe(device_t dev)
-{
-	int err;
-	ACPI_TABLE_TPM23 *tbl;
-	ACPI_STATUS status;
-
-	err = ACPI_ID_PROBE(device_get_parent(dev), dev, tpmtis_ids, NULL);
-	if (err > 0)
-		return (err);
-	/*Find TPM2 Header*/
-	status = AcpiGetTable(ACPI_SIG_TPM2, 1, (ACPI_TABLE_HEADER **) &tbl);
-	if(ACPI_FAILURE(status) ||
-	   tbl->StartMethod != TPM2_START_METHOD_TIS)
-	    err = ENXIO;
-
-	device_set_desc(dev, "Trusted Platform Module 2.0, FIFO mode");
-	return (err);
-}
-
-static int
+int
 tpmtis_attach(device_t dev)
 {
 	struct tpm_sc *sc;
@@ -123,20 +100,11 @@ tpmtis_attach(device_t dev)
 
 	sc = device_get_softc(dev);
 	sc->dev = dev;
-	sc->transmit = tpmtis_transmit;
 	sc->intr_type = -1;
 
 	sx_init(&sc->dev_lock, "TPM driver lock");
 	sc->buf = malloc(TPM_BUFSIZE, M_TPM20, M_WAITOK);
 
-	sc->mem_rid = 0;
-	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
-		    RF_ACTIVE);
-	if (sc->mem_res == NULL) {
-		tpmtis_detach(dev);
-		return (ENXIO);
-	}
-
 	sc->irq_rid = 0;
 	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
 		    RF_ACTIVE | RF_SHAREABLE);
@@ -198,7 +166,7 @@ tpmtis_test_intr(struct tpm_sc *sc)
 
 	sx_xlock(&sc->dev_lock);
 	memcpy(sc->buf, cmd, sizeof(cmd));
-	tpmtis_transmit(sc, sizeof(cmd));
+	tpmtis_transmit(sc->dev, sizeof(cmd));
 	sc->pending_data_length = 0;
 	sx_xunlock(&sc->dev_lock);
 }
@@ -222,19 +190,19 @@ tpmtis_setup_intr(struct tpm_sc *sc)
 	if(!tpmtis_request_locality(sc, 0))
 		sc->interrupts = false;
 
-	WR1(sc, TPM_INT_VECTOR, irq);
+	TPM_WRITE_1(sc->dev, TPM_INT_VECTOR, irq);
 
 	/* Clear all pending interrupts. */
-	reg = RD4(sc, TPM_INT_STS);
-	WR4(sc, TPM_INT_STS, reg);
+	reg = TPM_READ_4(sc->dev, TPM_INT_STS);
+	TPM_WRITE_4(sc->dev, TPM_INT_STS, reg);
 
-	reg = RD4(sc, TPM_INT_ENABLE);
+	reg = TPM_READ_4(sc->dev, TPM_INT_ENABLE);
 	reg |= TPM_INT_ENABLE_GLOBAL_ENABLE |
 	    TPM_INT_ENABLE_DATA_AVAIL |
 	    TPM_INT_ENABLE_LOC_CHANGE |
 	    TPM_INT_ENABLE_CMD_RDY |
 	    TPM_INT_ENABLE_STS_VALID;
-	WR4(sc, TPM_INT_ENABLE, reg);
+	TPM_WRITE_4(sc->dev, TPM_INT_ENABLE, reg);
 
 	tpmtis_relinquish_locality(sc);
 	tpmtis_test_intr(sc);
@@ -247,9 +215,9 @@ tpmtis_intr_handler(void *arg)
 	uint32_t status;
 
 	sc = (struct tpm_sc *)arg;
-	status = RD4(sc, TPM_INT_STS);
+	status = TPM_READ_4(sc->dev, TPM_INT_STS);
 
-	WR4(sc, TPM_INT_STS, status);
+	TPM_WRITE_4(sc->dev, TPM_INT_STS, status);
 
 	/* Check for stray interrupts. */
 	if (sc->intr_type == -1 || (sc->intr_type & status) == 0)
@@ -265,7 +233,7 @@ tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off, uint32_t mask, uint32_t val,
 {
 
 	/* Check for condition */
-	if ((RD4(sc, off) & mask) == val)
+	if ((TPM_READ_4(sc->dev, off) & mask) == val)
 		return (true);
 
 	/* If interrupts are enabled sleep for timeout duration */
@@ -273,12 +241,12 @@ tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off, uint32_t mask, uint32_t val,
 		tsleep(sc, PWAIT, "TPM WITH INTERRUPTS", timeout / tick);
 
 		sc->intr_type = -1;
-		return ((RD4(sc, off) & mask) == val);
+		return ((TPM_READ_4(sc->dev, off) & mask) == val);
 	}
 
*** 335 LINES SKIPPED ***