Module Name:    src
Committed By:   maxv
Date:           Sat Jun 22 12:57:41 UTC 2019

Modified Files:
        src/sys/dev/acpi: tpm_acpi.c
        src/sys/dev/ic: tpm.c tpmreg.h tpmvar.h
        src/sys/dev/isa: tpm_isa.c

Log Message:
Revamp the TPM driver

 * Fix several bugs, and clean up.
 * Drop the "legacy" interface, it relied on an undocumented global
   variable that was never initialized. It likely had never been tested
   either, so good riddance.
 * Add support for TPM 2.0 chips via ACPI. For these we use the TIS1.2
   interface, same as TPM 1.2.
 * Provide an ioctl to fetch TPM information from the driver.

Tested on a Lenovo desktop with ACPI-TPM2.0, an HP laptop ACPI-TPM2.0, a
Dell laptop with ISA-TPM1.2.


To generate a diff of this commit:
cvs rdiff -u -r1.7 -r1.8 src/sys/dev/acpi/tpm_acpi.c
cvs rdiff -u -r1.12 -r1.13 src/sys/dev/ic/tpm.c
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/ic/tpmreg.h src/sys/dev/ic/tpmvar.h
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/isa/tpm_isa.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/acpi/tpm_acpi.c
diff -u src/sys/dev/acpi/tpm_acpi.c:1.7 src/sys/dev/acpi/tpm_acpi.c:1.8
--- src/sys/dev/acpi/tpm_acpi.c:1.7	Sun Dec  9 11:12:58 2018
+++ src/sys/dev/acpi/tpm_acpi.c	Sat Jun 22 12:57:40 2019
@@ -1,11 +1,11 @@
-/* $NetBSD: tpm_acpi.c,v 1.7 2018/12/09 11:12:58 jdolecek Exp $ */
+/* $NetBSD: tpm_acpi.c,v 1.8 2019/06/22 12:57:40 maxv Exp $ */
 
-/*-
- * Copyright (c) 2012 The NetBSD Foundation, Inc.
+/*
+ * Copyright (c) 2012, 2019 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
- * by Christos Zoulas.
+ * by Christos Zoulas and Maxime Villard.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,31 +28,9 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
-/*
- * Copyright (c) 2008, 2009 Michael Shalayeff
- * Copyright (c) 2009, 2010 Hans-Jörg Höxer
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
- * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
- * ACPI attachment for the Infineon SLD 9630 TT 1.1 and SLB 9635 TT 1.2
- * trusted platform module. See www.trustedcomputinggroup.org
- */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tpm_acpi.c,v 1.7 2018/12/09 11:12:58 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tpm_acpi.c,v 1.8 2019/06/22 12:57:40 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -71,44 +49,48 @@ __KERNEL_RCSID(0, "$NetBSD: tpm_acpi.c,v
 
 #include "ioconf.h"
 
-#define _COMPONENT          ACPI_RESOURCE_COMPONENT
-ACPI_MODULE_NAME            ("tpm_acpi")
+#define _COMPONENT	ACPI_RESOURCE_COMPONENT
+ACPI_MODULE_NAME	("tpm_acpi")
 
 static int	tpm_acpi_match(device_t, cfdata_t, void *);
 static void	tpm_acpi_attach(device_t, device_t, void *);
 
-
 CFATTACH_DECL_NEW(tpm_acpi, sizeof(struct tpm_softc), tpm_acpi_match,
     tpm_acpi_attach, NULL, NULL);
 
 /*
- * Supported device IDs
+ * Supported TPM 2.0 devices.
  */
-
-#ifdef notyet
-static const char * const tpm_acpi_ids[] = {
-	"IFX0101",
-	"IFX0102",
+static const char * const tpm2_acpi_ids[] = {
+	"MSFT0101",
 	NULL
 };
-#endif
 
 static int
 tpm_acpi_match(device_t parent, cfdata_t match, void *aux)
 {
 	struct acpi_attach_args *aa = aux;
+	ACPI_TABLE_TPM2 *tpm2;
+	ACPI_STATUS rv;
 
 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
 		return 0;
 
-	/* There can be only one. */
+	/* We support only one TPM. */
 	if (tpm_cd.cd_devs && tpm_cd.cd_devs[0])
 		return 0;
-#ifdef notyet
-	return acpi_match_hid(aa->aa_node->ad_devinfo, tpm_acpi_ids);
-#else
-	return 0;
-#endif
+
+	if (!acpi_match_hid(aa->aa_node->ad_devinfo, tpm2_acpi_ids))
+		return 0;
+
+	/* Make sure it uses TIS, and not CRB. */
+	rv = AcpiGetTable(ACPI_SIG_TPM2, 1, (ACPI_TABLE_HEADER **)&tpm2);
+	if (ACPI_FAILURE(rv))
+		return 0;
+	if (tpm2->StartMethod != ACPI_TPM2_MEMORY_MAPPED)
+		return 0;
+
+	return 1;
 }
 
 static void
@@ -117,7 +99,6 @@ tpm_acpi_attach(device_t parent, device_
 	struct tpm_softc *sc = device_private(self);
 	struct acpi_attach_args *aa = aux;
 	struct acpi_resources res;
-	struct acpi_io *io;
 	struct acpi_mem *mem;
 	struct acpi_irq *irq;
 	bus_addr_t base;
@@ -125,59 +106,43 @@ tpm_acpi_attach(device_t parent, device_
 	int rv, inum;
 
 	sc->sc_dev = self;
+	sc->sc_ver = TPM_2_0;
 
-        /* Parse our resources */
-        rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS", &res,
-            &acpi_resource_parse_ops_default);
-
-        if (ACPI_FAILURE(rv)) {
+	rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS", &res,
+	    &acpi_resource_parse_ops_default);
+	if (ACPI_FAILURE(rv)) {
 		aprint_error_dev(sc->sc_dev, "cannot parse resources %d\n", rv);
-                return;
+		return;
 	}
 
-	io = acpi_res_io(&res, 0);
-	if (io && tpm_legacy_probe(aa->aa_iot, io->ar_base)) {
-		sc->sc_bt = aa->aa_iot;
-		base = io->ar_base;
-		size = io->ar_length;
-		sc->sc_batm = aa->aa_iot;
-		sc->sc_init = tpm_legacy_init;
-		sc->sc_start = tpm_legacy_start;
-		sc->sc_read = tpm_legacy_read;
-		sc->sc_write = tpm_legacy_write;
-		sc->sc_end = tpm_legacy_end;
-		mem = NULL;
-	} else {
-		mem = acpi_res_mem(&res, 0);
-		if (mem == NULL) {
-			aprint_error_dev(sc->sc_dev, "cannot find mem\n");
-			goto out;
-		}
-
-		if (mem->ar_length != TPM_SIZE) {
-			aprint_error_dev(sc->sc_dev,
-			    "wrong size mem %"PRIu64" != %u\n",
-			    (uint64_t)mem->ar_length, TPM_SIZE);
-			goto out;
-		}
-
-		base = mem->ar_base;
-		size = mem->ar_length;
-		sc->sc_bt = aa->aa_memt;
-		sc->sc_init = tpm_tis12_init;
-		sc->sc_start = tpm_tis12_start;
-		sc->sc_read = tpm_tis12_read;
-		sc->sc_write = tpm_tis12_write;
-		sc->sc_end = tpm_tis12_end;
+	mem = acpi_res_mem(&res, 0);
+	if (mem == NULL) {
+		aprint_error_dev(sc->sc_dev, "cannot find mem\n");
+		goto out;
+	}
+	if (mem->ar_length != TPM_SPACE_SIZE) {
+		aprint_error_dev(sc->sc_dev,
+		    "wrong size mem %"PRIu64" != %u\n",
+		    (uint64_t)mem->ar_length, TPM_SPACE_SIZE);
+		goto out;
 	}
 
+	base = mem->ar_base;
+	size = mem->ar_length;
+	sc->sc_bt = aa->aa_memt;
+	sc->sc_init = tpm_tis12_init;
+	sc->sc_start = tpm_tis12_start;
+	sc->sc_read = tpm_tis12_read;
+	sc->sc_write = tpm_tis12_write;
+	sc->sc_end = tpm_tis12_end;
+
 	if (bus_space_map(sc->sc_bt, base, size, 0, &sc->sc_bh)) {
 		aprint_error_dev(sc->sc_dev, "cannot map registers\n");
 		goto out;
 	}
 
-	if (mem && !tpm_tis12_probe(sc->sc_bt, sc->sc_bh)) {
-		aprint_error_dev(sc->sc_dev, "1.2 probe failed\n");
+	if (!tpm_tis12_probe(sc->sc_bt, sc->sc_bh)) {
+		aprint_error_dev(sc->sc_dev, "TIS1.2 probe failed\n");
 		goto out1;
 	}
 
@@ -187,7 +152,7 @@ tpm_acpi_attach(device_t parent, device_
 	else
 		inum = irq->ar_irq;
 
-	if ((rv = (*sc->sc_init)(sc, inum, device_xname(sc->sc_dev))) != 0) {
+	if ((rv = (*sc->sc_init)(sc, inum)) != 0) {
 		aprint_error_dev(sc->sc_dev, "cannot init device %d\n", rv);
 		goto out1;
 	}
@@ -199,9 +164,9 @@ tpm_acpi_attach(device_t parent, device_
 		goto out1;
 	}
 
-	if (!pmf_device_register(sc->sc_dev, tpm_suspend, tpm_resume))
-		aprint_error_dev(sc->sc_dev, "Cannot set power mgmt handler\n");
+	acpi_resource_cleanup(&res);
 	return;
+
 out1:
 	bus_space_unmap(sc->sc_bt, sc->sc_bh, size);
 out:

Index: src/sys/dev/ic/tpm.c
diff -u src/sys/dev/ic/tpm.c:1.12 src/sys/dev/ic/tpm.c:1.13
--- src/sys/dev/ic/tpm.c:1.12	Sat Oct 28 04:53:55 2017
+++ src/sys/dev/ic/tpm.c	Sat Jun 22 12:57:41 2019
@@ -1,7 +1,37 @@
-/*	$NetBSD: tpm.c,v 1.12 2017/10/28 04:53:55 riastradh Exp $	*/
+/*	$NetBSD: tpm.c,v 1.13 2019/06/22 12:57:41 maxv Exp $	*/
+
+/*
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Maxime Villard.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
 /*
  * Copyright (c) 2008, 2009 Michael Shalayeff
- * Copyright (c) 2009, 2010 Hans-Jörg Höxer
+ * Copyright (c) 2009, 2010 Hans-Joerg Hoexer
  * All rights reserved.
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -18,12 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.12 2017/10/28 04:53:55 riastradh Exp $");
-
-#if 0
-#define	TPM_DEBUG 
-#define aprint_debug_dev aprint_error_dev
-#endif
+__KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.13 2019/06/22 12:57:41 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -40,12 +65,23 @@ __KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.12
 
 #include "ioconf.h"
 
-/* Set when enabling legacy interface in host bridge. */
-int tpm_enabled;
+#define TPM_BUFSIZ	1024
+#define TPM_HDRSIZE	10
+#define TPM_PARAM_SIZE	0x0001	/* that's a flag */
+
+/* Timeouts. */
+#define TPM_ACCESS_TMO	2000	/* 2sec */
+#define TPM_READY_TMO	2000	/* 2sec */
+#define TPM_READ_TMO	2000	/* 2sec */
+#define TPM_BURST_TMO	2000	/* 2sec */
+
+#define TPM_CAPS_REQUIRED \
+	(TPM_INTF_DATA_AVAIL_INT|TPM_INTF_LOCALITY_CHANGE_INT| \
+	 TPM_INTF_INT_LEVEL_LOW)
 
-const struct {
+static const struct {
 	uint32_t devid;
-	char name[32];
+	const char *name;
 	int flags;
 #define TPM_DEV_NOINTS	0x0001
 } tpm_devs[] = {
@@ -60,177 +96,18 @@ const struct {
 	{ 0, "", TPM_DEV_NOINTS },
 };
 
-int tpm_tis12_irqinit(struct tpm_softc *, int, int);
-
-int tpm_waitfor_poll(struct tpm_softc *, uint8_t, int, void *);
-int tpm_waitfor_int(struct tpm_softc *, uint8_t, int, void *, int);
-int tpm_waitfor(struct tpm_softc *, uint8_t, int, void *);
-int tpm_request_locality(struct tpm_softc *, int);
-int tpm_getburst(struct tpm_softc *);
-uint8_t tpm_status(struct tpm_softc *);
-int tpm_tmotohz(int);
-
-static dev_type_open(tpmopen);
-static dev_type_close(tpmclose); 
-static dev_type_read(tpmread); 
-static dev_type_read(tpmwrite); 
-static dev_type_ioctl(tpmioctl);
-
-#define TPMUNIT(a)	minor(a)
- 
-const struct cdevsw tpm_cdevsw = {
-	.d_open = tpmopen,
-	.d_close = tpmclose,
-	.d_read = tpmread,
-	.d_write = tpmwrite,
-	.d_ioctl = tpmioctl,
-	.d_stop = nostop,
-	.d_tty = notty,
-	.d_poll = nopoll,
-	.d_mmap = nommap,
-	.d_kqfilter = nokqfilter,
-	.d_discard = nodiscard,
-	.d_flag = D_OTHER,
-}; 
-
-/* Probe TPM using TIS 1.2 interface. */
-int
-tpm_tis12_probe(bus_space_tag_t bt, bus_space_handle_t bh)
-{
-	uint32_t r;
-	uint8_t save, reg;
-
-	r = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITIES);
-	if (r == 0xffffffff)
-		return 0;
-
-#ifdef TPM_DEBUG
-	char buf[128];
-	snprintb(buf, sizeof(buf), TPM_CAPBITS, r);
-	printf("%s: caps=%s\n", __func__, buf);
-#endif
-	if ((r & TPM_CAPSREQ) != TPM_CAPSREQ ||
-	    !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) {
-#ifdef TPM_DEBUG
-		printf("%s: caps too low (caps=%s)\n", __func__, buf);
-#endif
-		return 0;
-	}
-
-	save = bus_space_read_1(bt, bh, TPM_ACCESS);
-	bus_space_write_1(bt, bh, TPM_ACCESS, TPM_ACCESS_REQUEST_USE);
-	reg = bus_space_read_1(bt, bh, TPM_ACCESS);
-	if ((reg & TPM_ACCESS_VALID) && (reg & TPM_ACCESS_ACTIVE_LOCALITY) &&
-	    bus_space_read_4(bt, bh, TPM_ID) != 0xffffffff)
-		return 1;
-
-	bus_space_write_1(bt, bh, TPM_ACCESS, save);
-	return 0;
-}
-
-/*
- * Setup interrupt vector if one is provided and interrupts are know to
- * work on that particular chip.
- */
-int
-tpm_tis12_irqinit(struct tpm_softc *sc, int irq, int idx)
-{
-	uint32_t r;
-
-	if ((irq == -1) || (tpm_devs[idx].flags & TPM_DEV_NOINTS)) {
-		sc->sc_vector = -1;
-		return 0;
-	}
-
-	/* Ack and disable all interrupts. */
-	r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE);
-	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
-	    r & ~TPM_GLOBAL_INT_ENABLE);
-	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS,
-	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS));
-#ifdef TPM_DEBUG
-	char buf[128];
-	snprintb(buf, sizeof(buf), TPM_INTERRUPT_ENABLE_BITS, r);
-	aprint_debug_dev(sc->sc_dev, "%s: before ien %s\n", __func__, buf);
-#endif
-
-	/* Program interrupt vector. */
-	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_INT_VECTOR, irq);
-	sc->sc_vector = irq;
-
-	/* Program interrupt type. */
-	r &= ~(TPM_INT_EDGE_RISING|TPM_INT_EDGE_FALLING|TPM_INT_LEVEL_HIGH|
-	    TPM_INT_LEVEL_LOW);
-	r |= TPM_GLOBAL_INT_ENABLE|TPM_CMD_READY_INT|TPM_LOCALITY_CHANGE_INT|
-	    TPM_STS_VALID_INT|TPM_DATA_AVAIL_INT;
-	if (sc->sc_capabilities & TPM_INTF_INT_EDGE_RISING)
-		r |= TPM_INT_EDGE_RISING;
-	else if (sc->sc_capabilities & TPM_INTF_INT_EDGE_FALLING)
-		r |= TPM_INT_EDGE_FALLING;
-	else if (sc->sc_capabilities & TPM_INTF_INT_LEVEL_HIGH)
-		r |= TPM_INT_LEVEL_HIGH;
-	else
-		r |= TPM_INT_LEVEL_LOW;
-
-	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, r);
-#ifdef TPM_DEBUG
-	snprintb(buf, sizeof(buf), TPM_INTERRUPT_ENABLE_BITS, r);
-	aprint_debug_dev(sc->sc_dev, "%s: after ien %s\n", __func__, buf);
-#endif
-
-	return 0;
-}
-
-/* Setup TPM using TIS 1.2 interface. */
-int
-tpm_tis12_init(struct tpm_softc *sc, int irq, const char *name)
+static inline int
+tpm_tmotohz(int tmo)
 {
-	uint32_t r;
-	int i;
-
-	r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTF_CAPABILITIES);
-#ifdef TPM_DEBUG
-	char cbuf[128];
-	snprintb(cbuf, sizeof(cbuf), TPM_CAPBITS, r);
-	aprint_debug_dev(sc->sc_dev, "%s: caps=%s ", __func__, cbuf);
-#endif
-	if ((r & TPM_CAPSREQ) != TPM_CAPSREQ ||
-	    !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) {
-		char buf[128];
-		snprintb(buf, sizeof(buf), TPM_CAPBITS, r);
-		aprint_error_dev(sc->sc_dev, "capabilities too low (caps=%s)\n",
-		    buf);
-		return 1;
-	}
-	sc->sc_capabilities = r;
-
-	sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID);
-	sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV);
-
-	for (i = 0; tpm_devs[i].devid; i++)
-		if (tpm_devs[i].devid == sc->sc_devid)
-			break;
-
-	if (tpm_devs[i].devid)
-		aprint_normal(": %s rev 0x%x\n",
-		    tpm_devs[i].name, sc->sc_rev);
-	else
-		aprint_normal(": device 0x%08x rev 0x%x\n",
-		    sc->sc_devid, sc->sc_rev);
-
-	if (tpm_tis12_irqinit(sc, irq, i))
-		return 1;
-
-	if (tpm_request_locality(sc, 0))
-		return 1;
+	struct timeval tv;
 
-	/* Abort whatever it thought it was doing. */
-	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY);
+	tv.tv_sec = tmo / 1000;
+	tv.tv_usec = 1000 * (tmo % 1000);
 
-	return 0;
+	return tvtohz(&tv);
 }
 
-int
+static int
 tpm_request_locality(struct tpm_softc *sc, int l)
 {
 	uint32_t r;
@@ -253,48 +130,34 @@ tpm_request_locality(struct tpm_softc *s
 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) {
 		rv = tsleep(sc->sc_init, PRIBIO | PCATCH, "tpm_locality", 1);
-		if (rv &&  rv != EWOULDBLOCK) {
-#ifdef TPM_DEBUG
-			aprint_debug_dev(sc->sc_dev, "%s: interrupted %d\n",
-			    __func__, rv);
-#endif
+		if (rv && rv != EWOULDBLOCK) {
 			return rv;
 		}
 	}
 
 	if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
-#ifdef TPM_DEBUG
-		char buf[128];
-		snprintb(buf, sizeof(buf), TPM_ACCESS_BITS, r);
-		aprint_debug_dev(sc->sc_dev, "%s: access %s\n", __func__, buf);
-#endif
 		return EBUSY;
 	}
 
 	return 0;
 }
 
-int
+static int
 tpm_getburst(struct tpm_softc *sc)
 {
 	int burst, to, rv;
 
 	to = tpm_tmotohz(TPM_BURST_TMO);
 
-	burst = 0;
-	while (burst == 0 && to--) {
+	while (to--) {
 		/*
-		 * Burst count has to be read from bits 8 to 23 without
-		 * touching any other bits, eg. the actual status bits 0
-		 * to 7.
+		 * Burst count is in bits 23:8, so read the two higher bytes.
 		 */
 		burst = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 1);
 		burst |= bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 2)
 		    << 8;
-#ifdef TPM_DEBUG
-		aprint_debug_dev(sc->sc_dev, "%s: read %d\n", __func__, burst);
-#endif
+
 		if (burst)
 			return burst;
 
@@ -307,77 +170,56 @@ tpm_getburst(struct tpm_softc *sc)
 	return 0;
 }
 
-uint8_t
+static inline uint8_t
 tpm_status(struct tpm_softc *sc)
 {
-	return bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS) & TPM_STS_MASK;
+	return bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS) &
+	    TPM_STS_STATUS_BITS;
 }
 
-int
-tpm_tmotohz(int tmo)
-{
-	struct timeval tv;
-
-	tv.tv_sec = tmo / 1000;
-	tv.tv_usec = 1000 * (tmo % 1000);
+/* -------------------------------------------------------------------------- */
 
-	return tvtohz(&tv);
-}
+/*
+ * Save TPM state on suspend. On resume we don't do anything, since the BIOS
+ * is supposed to restore the previously saved state.
+ */
 
-/* Save TPM state on suspend. */
 bool
-tpm_suspend(device_t dev, const pmf_qual_t *qual)
+tpm12_suspend(device_t dev, const pmf_qual_t *qual)
 {
 	struct tpm_softc *sc = device_private(dev);
 	static const uint8_t command[] = {
-	    0, 193,		/* TPM_TAG_RQU_COMMAND */
-	    0, 0, 0, 10,	/* Length in bytes */
-	    0, 0, 0, 156	/* TPM_ORD_SaveStates */
+		0, 193,		/* TPM_TAG_RQU_COMMAND */
+		0, 0, 0, 10,	/* Length in bytes */
+		0, 0, 0, 156	/* TPM_ORD_SaveStates */
 	};
 	uint8_t scratch[sizeof(command)];
 
-	/*
-	 * Power down:  We have to issue the SaveStates command.
-	 */
 	(*sc->sc_write)(sc, &command, sizeof(command));
-	(*sc->sc_read)(sc, &scratch, sizeof(scratch), NULL, TPM_HDRSIZE);
-#ifdef TPM_DEBUG
-	aprint_debug_dev(sc->sc_dev, "%s: power down\n", __func__);
-#endif
+	(*sc->sc_read)(sc, &scratch, sizeof(scratch), NULL, 0);
+
 	return true;
 }
 
-/*
- * Handle resume event.  Actually nothing to do as the BIOS is supposed
- * to restore the previously saved state.
- */
 bool
-tpm_resume(device_t dev, const pmf_qual_t *qual)
+tpm12_resume(device_t dev, const pmf_qual_t *qual)
 {
-#ifdef TPM_DEBUG
-	struct tpm_softc *sc = device_private(dev);
-	aprint_debug_dev(sc->sc_dev, "%s: resume\n", __func__);
-#endif
 	return true;
 }
 
-/* Wait for given status bits using polling. */
-int
-tpm_waitfor_poll(struct tpm_softc *sc, uint8_t mask, int tmo, void *c)
+/* -------------------------------------------------------------------------- */
+
+/*
+ * Wait for given status bits using polling.
+ */
+static int
+tpm_waitfor_poll(struct tpm_softc *sc, uint8_t mask, int to, wchan_t chan)
 {
 	int rv;
 
-	/*
-	 * Poll until either the requested condition or a time out is
-	 * met.
-	 */
-	while (((sc->sc_stat = tpm_status(sc)) & mask) != mask && tmo--) {
-		rv = tsleep(c, PRIBIO | PCATCH, "tpm_poll", 1);
+	while (((sc->sc_status = tpm_status(sc)) & mask) != mask && to--) {
+		rv = tsleep(chan, PRIBIO | PCATCH, "tpm_poll", 1);
 		if (rv && rv != EWOULDBLOCK) {
-#ifdef TPM_DEBUG
-			aprint_debug_dev(sc->sc_dev,
-			    "%s: interrupted %d\n", __func__, rv);
-#endif
 			return rv;
 		}
 	}
@@ -385,16 +227,17 @@ tpm_waitfor_poll(struct tpm_softc *sc, u
 	return 0;
 }
 
-/* Wait for given status bits using interrupts. */
-int
-tpm_waitfor_int(struct tpm_softc *sc, uint8_t mask, int tmo, void *c,
+/*
+ * Wait for given status bits using interrupts.
+ */
+static int
+tpm_waitfor_int(struct tpm_softc *sc, uint8_t mask, int tmo, wchan_t chan,
     int inttype)
 {
 	int rv, to;
 
-	/* Poll and return when condition is already met. */
-	sc->sc_stat = tpm_status(sc);
-	if ((sc->sc_stat & mask) == mask)
+	sc->sc_status = tpm_status(sc);
+	if ((sc->sc_status & mask) == mask)
 		return 0;
 
 	/*
@@ -402,147 +245,120 @@ tpm_waitfor_int(struct tpm_softc *sc, ui
 	 * level (SPL_TTY) are disabled (see tpm{read,write} et al) and
 	 * will not be delivered to the cpu until we call tsleep(9) below.
 	 */
-	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
-	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) |
+	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE,
+	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) |
 	    inttype);
-	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
-	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) |
+	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE,
+	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) |
 	    TPM_GLOBAL_INT_ENABLE);
 
-	/*
-	 * Poll once more to remedy the race between previous polling
-	 * and enabling interrupts on the tpm chip.
-	 */
-	sc->sc_stat = tpm_status(sc);
-	if ((sc->sc_stat & mask) == mask) {
+	sc->sc_status = tpm_status(sc);
+	if ((sc->sc_status & mask) == mask) {
 		rv = 0;
 		goto out;
 	}
 
 	to = tpm_tmotohz(tmo);
-#ifdef TPM_DEBUG
-	aprint_debug_dev(sc->sc_dev,
-	    "%s: sleeping for %d ticks on %p\n", __func__, to, c);
-#endif
+
 	/*
 	 * tsleep(9) enables interrupts on the cpu and returns after
 	 * wake up with interrupts disabled again.  Note that interrupts
 	 * generated by the tpm chip while being at SPL_TTY are not lost
 	 * but held and delivered as soon as the cpu goes below SPL_TTY.
 	 */
-	rv = tsleep(c, PRIBIO | PCATCH, "tpm_wait", to);
+	rv = tsleep(chan, PRIBIO | PCATCH, "tpm_wait", to);
 
-	sc->sc_stat = tpm_status(sc);
-#ifdef TPM_DEBUG
-	char buf[128];
-	snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat);
-	aprint_debug_dev(sc->sc_dev,
-	    "%s: woke up with rv %d stat %s\n", __func__, rv, buf);
-#endif
-	if ((sc->sc_stat & mask) == mask)
+	sc->sc_status = tpm_status(sc);
+	if ((sc->sc_status & mask) == mask)
 		rv = 0;
 
+out:
 	/* Disable interrupts on tpm chip again. */
-out:	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
-	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) &
+	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE,
+	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) &
 	    ~TPM_GLOBAL_INT_ENABLE);
-	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
-	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) &
+	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE,
+	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) &
 	    ~inttype);
 
 	return rv;
 }
 
 /*
- * Wait on given status bits, uses interrupts where possible, otherwise polls.
+ * Wait on given status bits, use interrupts where possible, otherwise poll.
  */
-int
-tpm_waitfor(struct tpm_softc *sc, uint8_t b0, int tmo, void *c)
+static int
+tpm_waitfor(struct tpm_softc *sc, uint8_t bits, int tmo, wchan_t chan)
 {
-	uint8_t b;
-	int re, to, rv;
-
-#ifdef TPM_DEBUG
-	char buf[128];
-	snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat);
-	aprint_debug_dev(sc->sc_dev, "%s: b0 %s\n", __func__, buf);
-#endif
+	int retry, to, rv;
+	uint8_t todo;
 
 	/*
-	 * If possible, use interrupts, otherwise poll.
-	 *
-	 * We use interrupts for TPM_STS_VALID and TPM_STS_DATA_AVAIL (if
-	 * the tpm chips supports them) as waiting for those can take
-	 * really long.  The other TPM_STS* are not needed very often
-	 * so we do not support them.
+	 * We use interrupts for TPM_STS_DATA_AVAIL and TPM_STS_VALID (if the
+	 * TPM chip supports them) as waiting for those can take really long.
+	 * The other TPM_STS* are not needed very often so we do not support
+	 * them.
 	 */
 	if (sc->sc_vector != -1) {
-		b = b0;
+		todo = bits;
 
 		/*
-		 * Wait for data ready.  This interrupt only occures
-		 * when both TPM_STS_VALID and TPM_STS_DATA_AVAIL are asserted.
-		 * Thus we don't have to bother with TPM_STS_VALID
-		 * separately and can just return.
+		 * Wait for data ready. This interrupt only occurs when both
+		 * TPM_STS_VALID and TPM_STS_DATA_AVAIL are asserted. Thus we
+		 * don't have to bother with TPM_STS_VALID separately and can
+		 * just return.
 		 *
-		 * This only holds for interrupts!  When using polling
-		 * both flags have to be waited for, see below.
+		 * This only holds for interrupts! When using polling both
+		 * flags have to be waited for, see below.
 		 */
-		if ((b & TPM_STS_DATA_AVAIL) && (sc->sc_capabilities &
-		    TPM_INTF_DATA_AVAIL_INT))
-			return tpm_waitfor_int(sc, b, tmo, c,
+		if ((bits & TPM_STS_DATA_AVAIL) &&
+		    (sc->sc_capabilities & TPM_INTF_DATA_AVAIL_INT))
+			return tpm_waitfor_int(sc, bits, tmo, chan,
 			    TPM_DATA_AVAIL_INT);
 
 		/* Wait for status valid bit. */
-		if ((b & TPM_STS_VALID) && (sc->sc_capabilities &
-		    TPM_INTF_STS_VALID_INT)) {
-			rv = tpm_waitfor_int(sc, b, tmo, c, TPM_STS_VALID_INT);
-			if (rv != 0)
+		if ((bits & TPM_STS_VALID) &&
+		    (sc->sc_capabilities & TPM_INTF_STS_VALID_INT)) {
+			rv = tpm_waitfor_int(sc, bits, tmo, chan,
+			    TPM_STS_VALID_INT);
+			if (rv)
 				return rv;
-			else
-				b = b0 & ~TPM_STS_VALID;
+			todo = bits & ~TPM_STS_VALID;
 		}
 
 		/*
-		 * When all flags are taken care of, return.  Otherwise
-		 * use polling for eg. TPM_STS_CMD_READY.
+		 * When all flags have been taken care of, return. Otherwise
+		 * use polling for eg TPM_STS_CMD_READY.
 		 */
-		if (b == 0)
+		if (todo == 0)
 			return 0;
 	}
 
-	re = 3;
+	retry = 3;
+
 restart:
 	/*
-	 * If requested wait for TPM_STS_VALID before dealing with
-	 * any other flag.  Eg. when both TPM_STS_DATA_AVAIL and TPM_STS_VALID
-	 * are requested, wait for the latter first.
+	 * If requested, wait for TPM_STS_VALID before dealing with any other
+	 * flag. Eg when both TPM_STS_DATA_AVAIL and TPM_STS_VALID are
+	 * requested, wait for the latter first.
 	 */
-	b = b0;
-	if (b0 & TPM_STS_VALID)
-		b = TPM_STS_VALID;
-
+	todo = bits;
+	if (bits & TPM_STS_VALID)
+		todo = TPM_STS_VALID;
 	to = tpm_tmotohz(tmo);
 again:
-	if ((rv = tpm_waitfor_poll(sc, b, to, c)) != 0)
+	if ((rv = tpm_waitfor_poll(sc, todo, to, chan)) != 0)
 		return rv;
 
-	if ((b & sc->sc_stat) == TPM_STS_VALID) {
+	if ((todo & sc->sc_status) == TPM_STS_VALID) {
 		/* Now wait for other flags. */
-		b = b0 & ~TPM_STS_VALID;
+		todo = bits & ~TPM_STS_VALID;
 		to++;
 		goto again;
 	}
 
-	if ((sc->sc_stat & b) != b) {
-#ifdef TPM_DEBUG
-		char bbuf[128], cbuf[128];
-		snprintb(bbuf, sizeof(bbuf), TPM_STS_BITS, b);
-		snprintb(cbuf, sizeof(cbuf), TPM_STS_BITS, sc->sc_stat);
-		aprint_debug_dev(sc->sc_dev,
-		    "%s: timeout: stat=%s b=%s\n", __func__, cbuf, bbuf);
-#endif
-		if (re-- && (b0 & TPM_STS_VALID)) {
+	if ((todo & sc->sc_status) != todo) {
+		if (retry-- && (bits & TPM_STS_VALID)) {
 			bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
 			    TPM_STS_RESP_RETRY);
 			goto restart;
@@ -553,7 +369,147 @@ again:
 	return 0;
 }
 
-/* Start transaction. */
+int
+tpm_intr(void *v)
+{
+	struct tpm_softc *sc = v;
+	uint32_t reg;
+
+	reg = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS);
+	if (!(reg & (TPM_CMD_READY_INT | TPM_LOCALITY_CHANGE_INT |
+	    TPM_STS_VALID_INT | TPM_DATA_AVAIL_INT)))
+		return 0;
+
+	if (reg & TPM_STS_VALID_INT)
+		wakeup(sc);
+	if (reg & TPM_CMD_READY_INT)
+		wakeup(sc->sc_write);
+	if (reg & TPM_DATA_AVAIL_INT)
+		wakeup(sc->sc_read);
+	if (reg & TPM_LOCALITY_CHANGE_INT)
+		wakeup(sc->sc_init);
+
+	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS, reg);
+
+	return 1;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * TPM using TIS 1.2 interface.
+ */
+
+int
+tpm_tis12_probe(bus_space_tag_t bt, bus_space_handle_t bh)
+{
+	uint32_t cap;
+	uint8_t reg;
+	int tmo;
+
+	cap = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITY);
+	if (cap == 0xffffffff)
+		return 0;
+	if ((cap & TPM_CAPS_REQUIRED) != TPM_CAPS_REQUIRED)
+		return 0;
+	if (!(cap & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW)))
+		return 0;
+
+	/* Request locality 0. */
+	bus_space_write_1(bt, bh, TPM_ACCESS, TPM_ACCESS_REQUEST_USE);
+
+	/* Wait for it to become active. */
+	tmo = TPM_ACCESS_TMO; /* Milliseconds. */
+	while ((reg = bus_space_read_1(bt, bh, TPM_ACCESS) &
+	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
+	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && tmo--) {
+		DELAY(1000); /* 1 millisecond. */
+	}
+	if ((reg & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
+	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
+		return 0;
+	}
+
+	if (bus_space_read_4(bt, bh, TPM_ID) == 0xffffffff)
+		return 0;
+
+	return 1;
+}
+
+static int
+tpm_tis12_irqinit(struct tpm_softc *sc, int irq, int idx)
+{
+	uint32_t reg;
+
+	if ((irq == -1) || (tpm_devs[idx].flags & TPM_DEV_NOINTS)) {
+		sc->sc_vector = -1;
+		return 0;
+	}
+
+	/* Ack and disable all interrupts. */
+	reg = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE);
+	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE,
+	    reg & ~TPM_GLOBAL_INT_ENABLE);
+	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS,
+	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS));
+
+	/* Program interrupt vector. */
+	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_INT_VECTOR, irq);
+	sc->sc_vector = irq;
+
+	/* Program interrupt type. */
+	reg &= ~(TPM_INT_EDGE_RISING|TPM_INT_EDGE_FALLING|TPM_INT_LEVEL_HIGH|
+	    TPM_INT_LEVEL_LOW);
+	reg |= TPM_GLOBAL_INT_ENABLE|TPM_CMD_READY_INT|TPM_LOCALITY_CHANGE_INT|
+	    TPM_STS_VALID_INT|TPM_DATA_AVAIL_INT;
+	if (sc->sc_capabilities & TPM_INTF_INT_EDGE_RISING)
+		reg |= TPM_INT_EDGE_RISING;
+	else if (sc->sc_capabilities & TPM_INTF_INT_EDGE_FALLING)
+		reg |= TPM_INT_EDGE_FALLING;
+	else if (sc->sc_capabilities & TPM_INTF_INT_LEVEL_HIGH)
+		reg |= TPM_INT_LEVEL_HIGH;
+	else
+		reg |= TPM_INT_LEVEL_LOW;
+
+	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE, reg);
+
+	return 0;
+}
+
+int
+tpm_tis12_init(struct tpm_softc *sc, int irq)
+{
+	int i;
+
+	sc->sc_capabilities = bus_space_read_4(sc->sc_bt, sc->sc_bh,
+	    TPM_INTF_CAPABILITY);
+	sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID);
+	sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV);
+
+	for (i = 0; tpm_devs[i].devid; i++) {
+		if (tpm_devs[i].devid == sc->sc_devid)
+			break;
+	}
+
+	if (tpm_devs[i].devid)
+		aprint_normal_dev(sc->sc_dev, "%s rev 0x%x\n",
+		    tpm_devs[i].name, sc->sc_rev);
+	else
+		aprint_normal_dev(sc->sc_dev, "device 0x%08x rev 0x%x\n",
+		    sc->sc_devid, sc->sc_rev);
+
+	if (tpm_tis12_irqinit(sc, irq, i))
+		return 1;
+
+	if (tpm_request_locality(sc, 0))
+		return 1;
+
+	/* Abort whatever it thought it was doing. */
+	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY);
+
+	return 0;
+}
+
 int
 tpm_tis12_start(struct tpm_softc *sc, int flag)
 {
@@ -565,41 +521,19 @@ tpm_tis12_start(struct tpm_softc *sc, in
 		return rv;
 	}
 
-	/* Own our (0th) locality. */
+	/* Request the 0th locality. */
 	if ((rv = tpm_request_locality(sc, 0)) != 0)
 		return rv;
 
-	sc->sc_stat = tpm_status(sc);
-	if (sc->sc_stat & TPM_STS_CMD_READY) {
-#ifdef TPM_DEBUG
-		char buf[128];
-		snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat);
-		aprint_debug_dev(sc->sc_dev, "%s: UIO_WRITE status %s\n",
-		    __func__, buf);
-#endif
+	sc->sc_status = tpm_status(sc);
+	if (sc->sc_status & TPM_STS_CMD_READY)
 		return 0;
-	}
-
-#ifdef TPM_DEBUG
-	aprint_debug_dev(sc->sc_dev,
-	    "%s: UIO_WRITE readying chip\n", __func__);
-#endif
 
 	/* Abort previous and restart. */
 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY);
-	if ((rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READY_TMO,
-	    sc->sc_write))) {
-#ifdef TPM_DEBUG
-		aprint_debug_dev(sc->sc_dev,
-		    "%s: UIO_WRITE readying failed %d\n", __func__, rv);
-#endif
+	rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READY_TMO, sc->sc_write);
+	if (rv)
 		return rv;
-	}
-
-#ifdef TPM_DEBUG
-	aprint_debug_dev(sc->sc_dev,
-	    "%s: UIO_WRITE readying done\n", __func__);
-#endif
 
 	return 0;
 }
@@ -612,21 +546,16 @@ tpm_tis12_read(struct tpm_softc *sc, voi
 	size_t cnt;
 	int rv, n, bcnt;
 
-#ifdef TPM_DEBUG
-	aprint_debug_dev(sc->sc_dev, "%s: len %zu\n", __func__, len);
-#endif
 	cnt = 0;
 	while (len > 0) {
-		if ((rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
-		    TPM_READ_TMO, sc->sc_read)))
+		rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+		    TPM_READ_TMO, sc->sc_read);
+		if (rv)
 			return rv;
 
 		bcnt = tpm_getburst(sc);
 		n = MIN(len, bcnt);
-#ifdef TPM_DEBUG
-		aprint_debug_dev(sc->sc_dev,
-		    "%s: fetching %d, burst is %d\n", __func__, n, bcnt);
-#endif
+
 		for (; n--; len--) {
 			*p++ = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_DATA);
 			cnt++;
@@ -635,10 +564,6 @@ tpm_tis12_read(struct tpm_softc *sc, voi
 		if ((flags & TPM_PARAM_SIZE) == 0 && cnt >= 6)
 			break;
 	}
-#ifdef TPM_DEBUG
-	aprint_debug_dev(sc->sc_dev,
-	    "%s: read %zu bytes, len %zu\n", __func__, cnt, len);
-#endif
 
 	if (count)
 		*count = cnt;
@@ -653,13 +578,8 @@ tpm_tis12_write(struct tpm_softc *sc, co
 	size_t cnt;
 	int rv, r;
 
-#ifdef TPM_DEBUG
-	aprint_debug_dev(sc->sc_dev,
-	    "%s: sc %p buf %p len %zu\n", __func__, sc, buf, len);
-#endif
 	if (len == 0)
 		return 0;
-
 	if ((rv = tpm_request_locality(sc, 0)) != 0)
 		return rv;
 
@@ -670,20 +590,10 @@ tpm_tis12_write(struct tpm_softc *sc, co
 			cnt++;
 		}
 		if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) {
-#ifdef TPM_DEBUG
-			aprint_debug_dev(sc->sc_dev,
-			    "%s: failed burst rv %d\n", __func__, rv);
-#endif
 			return rv;
 		}
-		sc->sc_stat = tpm_status(sc);
-		if (!(sc->sc_stat & TPM_STS_DATA_EXPECT)) {
-#ifdef TPM_DEBUG
-			char sbuf[128];
-			snprintb(sbuf, sizeof(sbuf), TPM_STS_BITS, sc->sc_stat);
-			aprint_debug_dev(sc->sc_dev,
-			    "%s: failed rv %d stat=%s\n", __func__, rv, sbuf);
-#endif
+		sc->sc_status = tpm_status(sc);
+		if (!(sc->sc_status & TPM_STS_DATA_EXPECT)) {
 			return EIO;
 		}
 	}
@@ -692,69 +602,42 @@ tpm_tis12_write(struct tpm_softc *sc, co
 	cnt++;
 
 	if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) {
-#ifdef TPM_DEBUG
-		aprint_debug_dev(sc->sc_dev, "%s: failed last byte rv %d\n",
-		    __func__, rv);
-#endif
 		return rv;
 	}
-	if ((sc->sc_stat & TPM_STS_DATA_EXPECT) != 0) {
-#ifdef TPM_DEBUG
-		char sbuf[128];
-		snprintb(sbuf, sizeof(sbuf), TPM_STS_BITS, sc->sc_stat);
-		aprint_debug_dev(sc->sc_dev,
-		    "%s: failed rv %d stat=%s\n", __func__, rv, sbuf);
-#endif
+	if ((sc->sc_status & TPM_STS_DATA_EXPECT) != 0) {
 		return EIO;
 	}
 
-#ifdef TPM_DEBUG
-	aprint_debug_dev(sc->sc_dev, "%s: wrote %zu byte\n", __func__, cnt);
-#endif
-
 	return 0;
 }
 
-/* Finish transaction. */
 int
 tpm_tis12_end(struct tpm_softc *sc, int flag, int err)
 {
 	int rv = 0;
 
 	if (flag == UIO_READ) {
-		if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO,
-		    sc->sc_read)))
+		rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc->sc_read);
+		if (rv)
 			return rv;
 
 		/* Still more data? */
-		sc->sc_stat = tpm_status(sc);
-		if (!err && ((sc->sc_stat & TPM_STS_DATA_AVAIL)
-		    == TPM_STS_DATA_AVAIL)) {
-#ifdef TPM_DEBUG
-			char buf[128];
-			snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat);
-			aprint_debug_dev(sc->sc_dev,
-			    "%s: read failed stat=%s\n", __func__, buf);
-#endif
+		sc->sc_status = tpm_status(sc);
+		if (!err && ((sc->sc_status & TPM_STS_DATA_AVAIL) ==
+		    TPM_STS_DATA_AVAIL)) {
 			rv = EIO;
 		}
 
 		bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
 		    TPM_STS_CMD_READY);
 
-		/* Release our (0th) locality. */
-		bus_space_write_1(sc->sc_bt, sc->sc_bh,TPM_ACCESS,
+		/* Release the 0th locality. */
+		bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
 		    TPM_ACCESS_ACTIVE_LOCALITY);
 	} else {
 		/* Hungry for more? */
-		sc->sc_stat = tpm_status(sc);
-		if (!err && (sc->sc_stat & TPM_STS_DATA_EXPECT)) {
-#ifdef TPM_DEBUG
-			char buf[128];
-			snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat);
-			aprint_debug_dev(sc->sc_dev,
-			    "%s: write failed stat=%s\n", __func__, buf);
-#endif
+		sc->sc_status = tpm_status(sc);
+		if (!err && (sc->sc_status & TPM_STS_DATA_EXPECT)) {
 			rv = EIO;
 		}
 
@@ -765,247 +648,38 @@ tpm_tis12_end(struct tpm_softc *sc, int 
 	return rv;
 }
 
-int
-tpm_intr(void *v)
-{
-	struct tpm_softc *sc = v;
-	uint32_t r;
-#ifdef TPM_DEBUG
-	static int cnt = 0;
-#endif
-
-	r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS);
-#ifdef TPM_DEBUG
-	if (r != 0) {
-		char buf[128];
-		snprintb(buf, sizeof(buf), TPM_INTERRUPT_ENABLE_BITS, r);
-		aprint_debug_dev(sc->sc_dev, "%s: int=%s (%d)\n", __func__,
-		    buf, cnt);
-	} else
-		cnt++;
-#endif
-	if (!(r & (TPM_CMD_READY_INT | TPM_LOCALITY_CHANGE_INT |
-	    TPM_STS_VALID_INT | TPM_DATA_AVAIL_INT)))
-#ifdef __FreeBSD__
-		return;
-#else
-		return 0;
-#endif
-	if (r & TPM_STS_VALID_INT)
-		wakeup(sc);
-
-	if (r & TPM_CMD_READY_INT)
-		wakeup(sc->sc_write);
-
-	if (r & TPM_DATA_AVAIL_INT)
-		wakeup(sc->sc_read);
-
-	if (r & TPM_LOCALITY_CHANGE_INT)
-		wakeup(sc->sc_init);
-
-	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS, r);
-
-	return 1;
-}
-
-/* Read single byte using legacy interface. */
-static inline uint8_t
-tpm_legacy_in(bus_space_tag_t iot, bus_space_handle_t ioh, int reg)
-{
-	bus_space_write_1(iot, ioh, 0, reg);
-	return bus_space_read_1(iot, ioh, 1);
-}
-
-/* Probe for TPM using legacy interface. */
-int
-tpm_legacy_probe(bus_space_tag_t iot, bus_addr_t iobase)
-{
-	bus_space_handle_t ioh;
-	uint8_t r, v;
-	int i, rv = 0;
-	char id[8];
-
-	if (!tpm_enabled || iobase == -1)
-		return 0;
-
-	if (bus_space_map(iot, iobase, 2, 0, &ioh))
-		return 0;
-
-	v = bus_space_read_1(iot, ioh, 0);
-	if (v == 0xff) {
-		bus_space_unmap(iot, ioh, 2);
-		return 0;
-	}
-	r = bus_space_read_1(iot, ioh, 1);
-
-	for (i = sizeof(id); i--; )
-		id[i] = tpm_legacy_in(iot, ioh, TPM_ID + i);
-
-#ifdef TPM_DEBUG
-	printf("tpm_legacy_probe %.4s %d.%d.%d.%d\n",
-	    &id[4], id[0], id[1], id[2], id[3]);
-#endif
-	/*
-	 * The only chips using the legacy interface we are aware of are
-	 * by Atmel.  For other chips more signature would have to be added.
-	 */
-	if (!bcmp(&id[4], "ATML", 4))
-		rv = 1;
-
-	if (!rv) {
-		bus_space_write_1(iot, ioh, r, 1);
-		bus_space_write_1(iot, ioh, v, 0);
-	}
-	bus_space_unmap(iot, ioh, 2);
-
-	return rv;
-}
-
-/* Setup TPM using legacy interface. */
-int
-tpm_legacy_init(struct tpm_softc *sc, int irq, const char *name)
-{
-	char id[8];
-	int i;
-
-	if ((i = bus_space_map(sc->sc_batm, tpm_enabled, 2, 0, &sc->sc_bahm))) {
-		aprint_debug_dev(sc->sc_dev, "cannot map tpm registers (%d)\n",
-		    i);
-		tpm_enabled = 0;
-		return 1;
-	}
-
-	for (i = sizeof(id); i--; )
-		id[i] = tpm_legacy_in(sc->sc_bt, sc->sc_bh, TPM_ID + i);
-
-	aprint_debug_dev(sc->sc_dev, "%.4s %d.%d @0x%x\n", &id[4], id[0],
-	    id[1], tpm_enabled);
-	tpm_enabled = 0;
-
-	return 0;
-}
-
-/* Start transaction. */
-int
-tpm_legacy_start(struct tpm_softc *sc, int flag)
-{
-	struct timeval tv;
-	uint8_t bits, r;
-	int to, rv;
-
-	bits = flag == UIO_READ ? TPM_LEGACY_DA : 0;
-	tv.tv_sec = TPM_LEGACY_TMO;
-	tv.tv_usec = 0;
-	to = tvtohz(&tv) / TPM_LEGACY_SLEEP;
-	while (((r = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1)) &
-	    (TPM_LEGACY_BUSY|bits)) != bits && to--) {
-		rv = tsleep(sc, PRIBIO | PCATCH, "legacy_tpm_start",
-		    TPM_LEGACY_SLEEP);
-		if (rv && rv != EWOULDBLOCK)
-			return rv;
-	}
-
-#if defined(TPM_DEBUG) && !defined(__FreeBSD__)
-	char buf[128];
-	snprintb(buf, sizeof(buf), TPM_LEGACY_BITS, r);
-	aprint_debug_dev(sc->sc_dev, "%s: bits %s\n", device_xname(sc->sc_dev),
-	    buf);
-#endif
-	if ((r & (TPM_LEGACY_BUSY|bits)) != bits)
-		return EIO;
-
-	return 0;
-}
-
-int
-tpm_legacy_read(struct tpm_softc *sc, void *buf, size_t len, size_t *count,
-    int flags)
-{
-	uint8_t *p;
-	size_t cnt;
-	int to, rv;
-
-	cnt = rv = 0;
-	for (p = buf; !rv && len > 0; len--) {
-		for (to = 1000;
-		    !(bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1) &
-		    TPM_LEGACY_DA); DELAY(1))
-			if (!to--)
-				return EIO;
-
-		DELAY(TPM_LEGACY_DELAY);
-		*p++ = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 0);
-		cnt++;
-	}
-
-	*count = cnt;
-	return 0;
-}
-
-int
-tpm_legacy_write(struct tpm_softc *sc, const void *buf, size_t len)
-{
-	const uint8_t *p;
-	size_t n;
-
-	for (p = buf, n = len; n--; DELAY(TPM_LEGACY_DELAY)) {
-		if (!n && len != TPM_BUFSIZ) {
-			bus_space_write_1(sc->sc_batm, sc->sc_bahm, 1,
-			    TPM_LEGACY_LAST);
-			DELAY(TPM_LEGACY_DELAY);
-		}
-		bus_space_write_1(sc->sc_batm, sc->sc_bahm, 0, *p++);
-	}
-
-	return 0;
-}
-
-/* Finish transaction. */
-int
-tpm_legacy_end(struct tpm_softc *sc, int flag, int rv)
-{
-	struct timeval tv;
-	uint8_t r;
-	int to;
-
-	if (rv || flag == UIO_READ)
-		bus_space_write_1(sc->sc_batm, sc->sc_bahm, 1, TPM_LEGACY_ABRT);
-	else {
-		tv.tv_sec = TPM_LEGACY_TMO;
-		tv.tv_usec = 0;
-		to = tvtohz(&tv) / TPM_LEGACY_SLEEP;
-		while(((r = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1)) &
-		    TPM_LEGACY_BUSY) && to--) {
-			rv = tsleep(sc, PRIBIO | PCATCH, "legacy_tpm_end",
-			    TPM_LEGACY_SLEEP);
-			if (rv && rv != EWOULDBLOCK)
-				return rv;
-		}
+/* -------------------------------------------------------------------------- */
 
-#if defined(TPM_DEBUG) && !defined(__FreeBSD__)
-		char buf[128];
-		snprintb(buf, sizeof(buf), TPM_LEGACY_BITS, r);
-		aprint_debug_dev(sc->sc_dev, "%s: bits %s\n",
-		    device_xname(sc->sc_dev), buf);
-#endif
-		if (r & TPM_LEGACY_BUSY)
-			return EIO;
+static dev_type_open(tpmopen);
+static dev_type_close(tpmclose);
+static dev_type_read(tpmread);
+static dev_type_write(tpmwrite);
+static dev_type_ioctl(tpmioctl);
 
-		if (r & TPM_LEGACY_RE)
-			return EIO;	/* XXX Retry the loop? */
-	}
+const struct cdevsw tpm_cdevsw = {
+	.d_open = tpmopen,
+	.d_close = tpmclose,
+	.d_read = tpmread,
+	.d_write = tpmwrite,
+	.d_ioctl = tpmioctl,
+	.d_stop = nostop,
+	.d_tty = notty,
+	.d_poll = nopoll,
+	.d_mmap = nommap,
+	.d_kqfilter = nokqfilter,
+	.d_discard = nodiscard,
+	.d_flag = D_OTHER,
+};
 
-	return rv;
-}
+#define TPMUNIT(a)	minor(a)
 
-int
+static int
 tpmopen(dev_t dev, int flag, int mode, struct lwp *l)
 {
 	struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
 
-	if (!sc)
+	if (sc == NULL)
 		return ENXIO;
-
 	if (sc->sc_flags & TPM_OPEN)
 		return EBUSY;
 
@@ -1014,14 +688,13 @@ tpmopen(dev_t dev, int flag, int mode, s
 	return 0;
 }
 
-int
+static int
 tpmclose(dev_t dev, int flag, int mode, struct lwp *l)
 {
 	struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
 
-	if (!sc)
+	if (sc == NULL)
 		return ENXIO;
-
 	if (!(sc->sc_flags & TPM_OPEN))
 		return EINVAL;
 
@@ -1030,7 +703,7 @@ tpmclose(dev_t dev, int flag, int mode, 
 	return 0;
 }
 
-int
+static int
 tpmread(dev_t dev, struct uio *uio, int flags)
 {
 	struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
@@ -1038,43 +711,27 @@ tpmread(dev_t dev, struct uio *uio, int 
 	size_t cnt, len, n;
 	int  rv, s;
 
-	if (!sc)
+	if (sc == NULL)
 		return ENXIO;
 
 	s = spltty();
 	if ((rv = (*sc->sc_start)(sc, UIO_READ)))
 		goto out;
 
-#ifdef TPM_DEBUG
-	aprint_debug_dev(sc->sc_dev, "%s: getting header\n", __func__);
-#endif
 	if ((rv = (*sc->sc_read)(sc, buf, TPM_HDRSIZE, &cnt, 0))) {
 		(*sc->sc_end)(sc, UIO_READ, rv);
 		goto out;
 	}
 
 	len = (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | buf[5];
-#ifdef TPM_DEBUG
-	aprint_debug_dev(sc->sc_dev, "%s: len %zu, io count %zu\n", __func__,
-	    len, uio->uio_resid);
-#endif
 	if (len > uio->uio_resid) {
 		rv = EIO;
 		(*sc->sc_end)(sc, UIO_READ, rv);
-#ifdef TPM_DEBUG
-		aprint_debug_dev(sc->sc_dev,
-		    "%s: bad residual io count 0x%zx\n", __func__,
-		    uio->uio_resid);
-#endif
 		goto out;
 	}
 
 	/* Copy out header. */
 	if ((rv = uiomove(buf, cnt, uio))) {
-#ifdef TPM_DEBUG
-		aprint_debug_dev(sc->sc_dev,
-		    "%s: uiomove failed %d\n", __func__, rv);
-#endif
 		(*sc->sc_end)(sc, UIO_READ, rv);
 		goto out;
 	}
@@ -1083,20 +740,12 @@ tpmread(dev_t dev, struct uio *uio, int 
 	for (len -= cnt, p = buf, n = sizeof(buf); len > 0; p = buf, len -= n,
 	    n = sizeof(buf)) {
 		n = MIN(n, len);
-#ifdef TPM_DEBUG
-		aprint_debug_dev(sc->sc_dev, "%s: n %zu len %zu\n", __func__,
-		    n, len);
-#endif
 		if ((rv = (*sc->sc_read)(sc, p, n, NULL, TPM_PARAM_SIZE))) {
 			(*sc->sc_end)(sc, UIO_READ, rv);
 			goto out;
 		}
 		p += n;
 		if ((rv = uiomove(buf, p - buf, uio))) {
-#ifdef TPM_DEBUG
-			aprint_debug_dev(sc->sc_dev,
-			    "%s: uiomove failed %d\n", __func__, rv);
-#endif
 			(*sc->sc_end)(sc, UIO_READ, rv);
 			goto out;
 		}
@@ -1108,50 +757,56 @@ out:
 	return rv;
 }
 
-int
+static int
 tpmwrite(dev_t dev, struct uio *uio, int flags)
 {
 	struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
 	uint8_t buf[TPM_BUFSIZ];
 	int n, rv, s;
 
-	if (!sc)
+	if (sc == NULL)
 		return ENXIO;
 
 	s = spltty();
 
-#ifdef TPM_DEBUG
-	aprint_debug_dev(sc->sc_dev, "%s: io count %zu\n", __func__,
-	    uio->uio_resid);
-#endif
-
 	n = MIN(sizeof(buf), uio->uio_resid);
 	if ((rv = uiomove(buf, n, uio))) {
-#ifdef TPM_DEBUG
-		aprint_debug_dev(sc->sc_dev,
-		    "%s: uiomove failed %d\n", __func__, rv);
-#endif
-		splx(s);
-		return rv;
+		goto out;
 	}
-
 	if ((rv = (*sc->sc_start)(sc, UIO_WRITE))) {
-		splx(s);
-		return rv;
+		goto out;
 	}
-
 	if ((rv = (*sc->sc_write)(sc, buf, n))) {
-		splx(s);
-		return rv;
+		goto out;
 	}
 
 	rv = (*sc->sc_end)(sc, UIO_WRITE, rv);
+out:
 	splx(s);
 	return rv;
 }
 
-int
-tpmioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
+static int
+tpmioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
 {
+	struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
+	struct tpm_ioc_getinfo *info;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	switch (cmd) {
+	case TPM_IOC_GETINFO:
+		info = addr;
+		info->api_version = TPM_API_VERSION;
+		info->tpm_version = sc->sc_ver;
+		info->device_id = sc->sc_devid;
+		info->device_rev = sc->sc_rev;
+		info->device_caps = sc->sc_capabilities;
+		return 0;
+	default:
+		break;
+	}
+
 	return ENOTTY;
 }

Index: src/sys/dev/ic/tpmreg.h
diff -u src/sys/dev/ic/tpmreg.h:1.3 src/sys/dev/ic/tpmreg.h:1.4
--- src/sys/dev/ic/tpmreg.h:1.3	Mon Jan 23 04:12:26 2012
+++ src/sys/dev/ic/tpmreg.h	Sat Jun 22 12:57:41 2019
@@ -1,100 +1,90 @@
-/*	$NetBSD: tpmreg.h,v 1.3 2012/01/23 04:12:26 christos Exp $	*/
+/*	$NetBSD: tpmreg.h,v 1.4 2019/06/22 12:57:41 maxv Exp $	*/
 
 /*
- * Copyright (c) 2008, 2009 Michael Shalayeff
- * Copyright (c) 2009, 2010 Hans-Jörg Höxer
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Maxime Villard.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
- * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
  */
 
-#define	TPM_BUFSIZ	1024
-
-#define TPM_HDRSIZE	10
+/*
+ * TPM Interface Specification 1.2 (TIS12).
+ */
 
-#define TPM_PARAM_SIZE	0x0001
+#define	TPM_ACCESS			0x0000	/* 8bit register */
+#define		TPM_ACCESS_VALID		__BIT(7)
+#define		TPM_ACCESS_ACTIVE_LOCALITY	__BIT(5)
+#define		TPM_ACCESS_BEEN_SEIZED		__BIT(4)
+#define		TPM_ACCESS_SEIZE		__BIT(3)
+#define		TPM_ACCESS_PENDING_REQUEST	__BIT(2)
+#define		TPM_ACCESS_REQUEST_USE		__BIT(1)
+#define		TPM_ACCESS_ESTABLISHMENT	__BIT(0)
+
+#define	TPM_INT_ENABLE			0x0008	/* 32bit register */
+#define		TPM_GLOBAL_INT_ENABLE		__BIT(31)
+#define		TPM_CMD_READY_INT		__BIT(7)
+#define		TPM_TYPE_POLARITY		__BITS(4,3)
+#define		TPM_INT_LEVEL_HIGH		__SHIFTIN(0, TPM_TYPE_POLARITY)
+#define		TPM_INT_LEVEL_LOW		__SHIFTIN(1, TPM_TYPE_POLARITY)
+#define		TPM_INT_EDGE_RISING		__SHIFTIN(2, TPM_TYPE_POLARITY)
+#define		TPM_INT_EDGE_FALLING		__SHIFTIN(3, TPM_TYPE_POLARITY)
+#define		TPM_LOCALITY_CHANGE_INT		__BIT(2)
+#define		TPM_STS_VALID_INT		__BIT(1)
+#define		TPM_DATA_AVAIL_INT		__BIT(0)
+
+#define	TPM_INT_VECTOR			0x000c	/* 8bit register */
+#define	TPM_INT_STATUS			0x0010	/* 32bit register */
+
+#define	TPM_INTF_CAPABILITY		0x0014	/* 32bit register */
+#define		TPM_INTF_BURST_COUNT_STATIC	__BIT(8)
+#define		TPM_INTF_CMD_READY_INT		__BIT(7)
+#define		TPM_INTF_INT_EDGE_FALLING	__BIT(6)
+#define		TPM_INTF_INT_EDGE_RISING	__BIT(5)
+#define		TPM_INTF_INT_LEVEL_LOW		__BIT(4)
+#define		TPM_INTF_INT_LEVEL_HIGH		__BIT(3)
+#define		TPM_INTF_LOCALITY_CHANGE_INT	__BIT(2)
+#define		TPM_INTF_STS_VALID_INT		__BIT(1)
+#define		TPM_INTF_DATA_AVAIL_INT		__BIT(0)
+#define	TPM_INTF_CAPABILITY_BITS \
+    "\020\01IDRDY\02ISTSV\03ILOCH\04IHIGH\05ILOW\06IRISE\07IFALL\010IRDY\011BCST"
+
+#define	TPM_STS				0x0018	/* 24bit register */
+#define		TPM_STS_BURST_COUNT		__BITS(23,8)
+#define		TPM_STS_STATUS_BITS		__BITS(7,0)
+#define		TPM_STS_VALID			__BIT(7)
+#define		TPM_STS_CMD_READY		__BIT(6)
+#define		TPM_STS_GO			__BIT(5)
+#define		TPM_STS_DATA_AVAIL		__BIT(4)
+#define		TPM_STS_DATA_EXPECT		__BIT(3)
+#define		TPM_STS_RESP_RETRY		__BIT(1)
+
+#define	TPM_DATA			0x0024	/* 32bit register */
+#define	TPM_ID				0x0f00	/* 32bit register */
+#define	TPM_REV				0x0f04	/* 8bit register */
 
-#define	TPM_ACCESS			0x0000	/* access register */
-#define	TPM_ACCESS_ESTABLISHMENT	0x01	/* establishment */
-#define	TPM_ACCESS_REQUEST_USE		0x02	/* request using locality */
-#define	TPM_ACCESS_REQUEST_PENDING	0x04	/* pending request */
-#define	TPM_ACCESS_SEIZE		0x08	/* request locality seize */
-#define	TPM_ACCESS_SEIZED		0x10	/* locality has been seized */
-#define	TPM_ACCESS_ACTIVE_LOCALITY	0x20	/* locality is active */
-#define	TPM_ACCESS_VALID		0x80	/* bits are valid */
-#define	TPM_ACCESS_BITS	\
-    "\020\01EST\02REQ\03PEND\04SEIZE\05SEIZED\06ACT\010VALID"
-
-#define	TPM_INTERRUPT_ENABLE	0x0008
-#define	TPM_GLOBAL_INT_ENABLE	0x80000000	/* enable ints */
-#define	TPM_CMD_READY_INT	0x00000080	/* cmd ready enable */
-#define	TPM_INT_EDGE_FALLING	0x00000018
-#define	TPM_INT_EDGE_RISING	0x00000010
-#define	TPM_INT_LEVEL_LOW	0x00000008
-#define	TPM_INT_LEVEL_HIGH	0x00000000
-#define	TPM_LOCALITY_CHANGE_INT	0x00000004	/* locality change enable */
-#define	TPM_STS_VALID_INT	0x00000002	/* int on TPM_STS_VALID is set */
-#define	TPM_DATA_AVAIL_INT	0x00000001	/* int on TPM_STS_DATA_AVAIL is set */
-#define	TPM_INTERRUPT_ENABLE_BITS \
-    "\177\020b\0DRDY\0b\1STSVALID\0b\2LOCCHG\0" \
-    "F\3\2:\0HIGH\0:\1LOW\0:\2RISE\0:\3FALL\0" \
-    "b\7IRDY\0b\x1fGIENABLE\0"
-
-#define	TPM_INT_VECTOR		0x000c	/* 8 bit reg for 4 bit irq vector */
-#define	TPM_INT_STATUS		0x0010	/* bits are & 0x87 from TPM_INTERRUPT_ENABLE */
-
-#define	TPM_INTF_CAPABILITIES		0x0014	/* capability register */
-#define	TPM_INTF_BURST_COUNT_STATIC	0x0100	/* TPM_STS_BMASK static */
-#define	TPM_INTF_CMD_READY_INT		0x0080	/* int on ready supported */
-#define	TPM_INTF_INT_EDGE_FALLING	0x0040	/* falling edge ints supported */
-#define	TPM_INTF_INT_EDGE_RISING	0x0020	/* rising edge ints supported */
-#define	TPM_INTF_INT_LEVEL_LOW		0x0010	/* level-low ints supported */
-#define	TPM_INTF_INT_LEVEL_HIGH		0x0008	/* level-high ints supported */
-#define	TPM_INTF_LOCALITY_CHANGE_INT	0x0004	/* locality-change int (mb 1) */
-#define	TPM_INTF_STS_VALID_INT		0x0002	/* TPM_STS_VALID int supported */
-#define	TPM_INTF_DATA_AVAIL_INT		0x0001	/* TPM_STS_DATA_AVAIL int supported (mb 1) */
-#define	TPM_CAPSREQ \
-  (TPM_INTF_DATA_AVAIL_INT|TPM_INTF_LOCALITY_CHANGE_INT|TPM_INTF_INT_LEVEL_LOW)
-#define	TPM_CAPBITS \
-  "\020\01IDRDY\02ISTSV\03ILOCH\04IHIGH\05ILOW\06IRISE\07IFALL\010IRDY\011BCST"
-
-#define	TPM_STS			0x0018		/* status register */
-#define TPM_STS_MASK		0x000000ff	/* status bits */
-#define	TPM_STS_BMASK		0x00ffff00	/* ro io burst size */
-#define	TPM_STS_VALID		0x00000080	/* ro other bits are valid */
-#define	TPM_STS_CMD_READY	0x00000040	/* rw chip/signal ready */
-#define	TPM_STS_GO		0x00000020	/* wo start the command */
-#define	TPM_STS_DATA_AVAIL	0x00000010	/* ro data available */
-#define	TPM_STS_DATA_EXPECT	0x00000008	/* ro more data to be written */
-#define	TPM_STS_RESP_RETRY	0x00000002	/* wo resend the response */
-#define	TPM_STS_BITS	"\020\010VALID\07RDY\06GO\05DRDY\04EXPECT\02RETRY"
-
-#define	TPM_DATA	0x0024
-#define	TPM_ID		0x0f00
-#define	TPM_REV		0x0f04
-#define	TPM_SIZE	0x5000		/* five pages of the above */
-
-#define	TPM_ACCESS_TMO	2000		/* 2sec */
-#define	TPM_READY_TMO	2000		/* 2sec */
-#define	TPM_READ_TMO	2000		/* 2sec */
-#define TPM_BURST_TMO	2000		/* 2sec */
-
-#define	TPM_LEGACY_BUSY	0x01
-#define	TPM_LEGACY_ABRT	0x01
-#define	TPM_LEGACY_DA	0x02
-#define	TPM_LEGACY_RE	0x04
-#define	TPM_LEGACY_LAST	0x04
-#define	TPM_LEGACY_BITS	"\020\01BUSY\2DA\3RE\4LAST"
-#define	TPM_LEGACY_TMO		(2*60)	/* sec */
-#define	TPM_LEGACY_SLEEP	5	/* ticks */
-#define	TPM_LEGACY_DELAY	100
+/*
+ * Five localities, 4K per locality.
+ */
+#define	TPM_SPACE_SIZE	0x5000
Index: src/sys/dev/ic/tpmvar.h
diff -u src/sys/dev/ic/tpmvar.h:1.3 src/sys/dev/ic/tpmvar.h:1.4
--- src/sys/dev/ic/tpmvar.h:1.3	Sat Oct 27 17:18:23 2012
+++ src/sys/dev/ic/tpmvar.h	Sat Jun 22 12:57:41 2019
@@ -1,7 +1,37 @@
-/*	$NetBSD: tpmvar.h,v 1.3 2012/10/27 17:18:23 chs Exp $	*/
+/*	$NetBSD: tpmvar.h,v 1.4 2019/06/22 12:57:41 maxv Exp $	*/
+
+/*
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Maxime Villard.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
 /*
  * Copyright (c) 2008, 2009 Michael Shalayeff
- * Copyright (c) 2009, 2010 Hans-Jörg Höxer
+ * Copyright (c) 2009, 2010 Hans-Joerg Hoexer
  * All rights reserved.
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -17,45 +47,61 @@
  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#define TPM_API_VERSION		1
+
+enum tpm_version {
+	TPM_1_2,
+	TPM_2_0
+};
+
+struct tpm_ioc_getinfo {
+	uint32_t api_version;
+
+	uint32_t tpm_version;
+	uint32_t device_id;
+	uint32_t device_rev;
+	uint32_t device_caps;
+};
+
+#define TPM_IOC_GETINFO		_IOR ('N',  0, struct tpm_ioc_getinfo)
+
+#ifdef _KERNEL
+
 struct tpm_softc {
 	device_t sc_dev;
+	enum tpm_version sc_ver;
 	void *sc_ih;
 
-	int	(*sc_init)(struct tpm_softc *, int, const char *);
-	int	(*sc_start)(struct tpm_softc *, int);
-	int	(*sc_read)(struct tpm_softc *, void *, size_t, size_t *, int);
-	int	(*sc_write)(struct tpm_softc *, const void *, size_t);
-	int	(*sc_end)(struct tpm_softc *, int, int);
+	int (*sc_init)(struct tpm_softc *, int);
+	int (*sc_start)(struct tpm_softc *, int);
+	int (*sc_read)(struct tpm_softc *, void *, size_t, size_t *, int);
+	int (*sc_write)(struct tpm_softc *, const void *, size_t);
+	int (*sc_end)(struct tpm_softc *, int, int);
 
 	bus_space_tag_t sc_bt, sc_batm;
 	bus_space_handle_t sc_bh, sc_bahm;
 
-	u_int32_t sc_devid;
-	u_int32_t sc_rev;
-	u_int32_t sc_stat;
-	u_int32_t sc_capabilities;
+	uint32_t sc_devid;
+	uint32_t sc_rev;
+	uint32_t sc_status;
+	uint32_t sc_capabilities;
 
 	int sc_flags;
 #define	TPM_OPEN	0x0001
 
-	int	 sc_vector;
+	int sc_vector;
 };
 
 int tpm_intr(void *);
 
-bool tpm_suspend(device_t, const pmf_qual_t *);
-bool tpm_resume(device_t, const pmf_qual_t *);
+bool tpm12_suspend(device_t, const pmf_qual_t *);
+bool tpm12_resume(device_t, const pmf_qual_t *);
 
 int tpm_tis12_probe(bus_space_tag_t, bus_space_handle_t);
-int tpm_tis12_init(struct tpm_softc *, int, const char *);
+int tpm_tis12_init(struct tpm_softc *, int);
 int tpm_tis12_start(struct tpm_softc *, int);
 int tpm_tis12_read(struct tpm_softc *, void *, size_t, size_t *, int);
 int tpm_tis12_write(struct tpm_softc *, const void *, size_t);
 int tpm_tis12_end(struct tpm_softc *, int, int);
 
-int tpm_legacy_probe(bus_space_tag_t, bus_addr_t);
-int tpm_legacy_init(struct tpm_softc *, int, const char *);
-int tpm_legacy_start(struct tpm_softc *, int);
-int tpm_legacy_read(struct tpm_softc *, void *, size_t, size_t *, int);
-int tpm_legacy_write(struct tpm_softc *, const void *, size_t);
-int tpm_legacy_end(struct tpm_softc *, int, int);
+#endif

Index: src/sys/dev/isa/tpm_isa.c
diff -u src/sys/dev/isa/tpm_isa.c:1.3 src/sys/dev/isa/tpm_isa.c:1.4
--- src/sys/dev/isa/tpm_isa.c:1.3	Thu Apr 27 10:01:53 2017
+++ src/sys/dev/isa/tpm_isa.c	Sat Jun 22 12:57:41 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: tpm_isa.c,v 1.3 2017/04/27 10:01:53 msaitoh Exp $	*/
+/*	$NetBSD: tpm_isa.c,v 1.4 2019/06/22 12:57:41 maxv Exp $	*/
 
 /*
  * Copyright (c) 2008, 2009 Michael Shalayeff
@@ -19,7 +19,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tpm_isa.c,v 1.3 2017/04/27 10:01:53 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tpm_isa.c,v 1.4 2019/06/22 12:57:41 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -56,27 +56,22 @@ tpm_isa_match(device_t parent, cfdata_t 
 	if (tpm_cd.cd_devs && tpm_cd.cd_devs[0])
 		return 0;
 
-	if (tpm_legacy_probe(ia->ia_iot, ia->ia_io[0].ir_addr)) {
-		ia->ia_io[0].ir_size = 2;
-		return 1;
-	}
-
 	if (ia->ia_iomem[0].ir_addr == ISA_UNKNOWN_IOMEM)
 		return 0;
 
 	/* XXX: integer locator sign extension */
-	if (bus_space_map(bt, (unsigned int)ia->ia_iomem[0].ir_addr, TPM_SIZE,
+	if (bus_space_map(bt, (unsigned int)ia->ia_iomem[0].ir_addr, TPM_SPACE_SIZE,
 	    0, &bh))
 		return 0;
 
 	if ((rv = tpm_tis12_probe(bt, bh))) {
 		ia->ia_nio = 0;
 		ia->ia_io[0].ir_size = 0;
-		ia->ia_iomem[0].ir_size = TPM_SIZE;
+		ia->ia_iomem[0].ir_size = TPM_SPACE_SIZE;
 	}
 	ia->ia_ndrq = 0;
 
-	bus_space_unmap(bt, bh, TPM_SIZE);
+	bus_space_unmap(bt, bh, TPM_SPACE_SIZE);
 	return rv;
 }
 
@@ -90,35 +85,23 @@ tpm_isa_attach(device_t parent, device_t
 	int rv;
 
 	sc->sc_dev = self;
+	sc->sc_ver = TPM_1_2;
 
-	if (tpm_legacy_probe(ia->ia_iot, ia->ia_io[0].ir_addr)) {
-		sc->sc_bt = ia->ia_iot;
-		iobase = (unsigned int)ia->ia_io[0].ir_addr;
-		size = ia->ia_io[0].ir_size;
-		sc->sc_batm = ia->ia_iot;
-		sc->sc_init = tpm_legacy_init;
-		sc->sc_start = tpm_legacy_start;
-		sc->sc_read = tpm_legacy_read;
-		sc->sc_write = tpm_legacy_write;
-		sc->sc_end = tpm_legacy_end;
-	} else {
-		sc->sc_bt = ia->ia_memt;
-		iobase = (unsigned int)ia->ia_iomem[0].ir_addr;
-		size = TPM_SIZE;
-		sc->sc_init = tpm_tis12_init;
-		sc->sc_start = tpm_tis12_start;
-		sc->sc_read = tpm_tis12_read;
-		sc->sc_write = tpm_tis12_write;
-		sc->sc_end = tpm_tis12_end;
-	}
+	sc->sc_bt = ia->ia_memt;
+	iobase = (unsigned int)ia->ia_iomem[0].ir_addr;
+	size = TPM_SPACE_SIZE;
+	sc->sc_init = tpm_tis12_init;
+	sc->sc_start = tpm_tis12_start;
+	sc->sc_read = tpm_tis12_read;
+	sc->sc_write = tpm_tis12_write;
+	sc->sc_end = tpm_tis12_end;
 
 	if (bus_space_map(sc->sc_bt, iobase, size, 0, &sc->sc_bh)) {
 		aprint_error_dev(sc->sc_dev, "cannot map registers\n");
 		return;
 	}
 
-	if ((rv = (*sc->sc_init)(sc, ia->ia_irq[0].ir_irq,
-	    device_xname(sc->sc_dev))) != 0) {
+	if ((rv = (*sc->sc_init)(sc, ia->ia_irq[0].ir_irq)) != 0) {
 		bus_space_unmap(sc->sc_bt, sc->sc_bh, size);
 		return;
 	}
@@ -132,11 +115,11 @@ tpm_isa_attach(device_t parent, device_t
 	    (sc->sc_ih = isa_intr_establish_xname(ia->ia_ic,
 	     ia->ia_irq[0].ir_irq, IST_EDGE, IPL_TTY, tpm_intr, sc,
 	     device_xname(sc->sc_dev))) == NULL) {
-		bus_space_unmap(sc->sc_bt, sc->sc_bh, TPM_SIZE);
+		bus_space_unmap(sc->sc_bt, sc->sc_bh, TPM_SPACE_SIZE);
 		aprint_error_dev(sc->sc_dev, "cannot establish interrupt\n");
 		return;
 	}
 
-	if (!pmf_device_register(sc->sc_dev, tpm_suspend, tpm_resume))
-		aprint_error_dev(sc->sc_dev, "Cannot set power mgmt handler\n");
+	if (!pmf_device_register(sc->sc_dev, tpm12_suspend, tpm12_resume))
+		aprint_error_dev(sc->sc_dev, "cannot set power mgmt handler\n");
 }

Reply via email to