xref: /freebsd/sys/dev/tpm/tpm.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
197f24f66STakanori Watanabe /*
297f24f66STakanori Watanabe  * Copyright (c) 2008, 2009 Michael Shalayeff
397f24f66STakanori Watanabe  * Copyright (c) 2009, 2010 Hans-Joerg Hoexer
497f24f66STakanori Watanabe  * All rights reserved.
597f24f66STakanori Watanabe  *
697f24f66STakanori Watanabe  * Permission to use, copy, modify, and distribute this software for any
797f24f66STakanori Watanabe  * purpose with or without fee is hereby granted, provided that the above
897f24f66STakanori Watanabe  * copyright notice and this permission notice appear in all copies.
997f24f66STakanori Watanabe  *
1097f24f66STakanori Watanabe  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1197f24f66STakanori Watanabe  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1297f24f66STakanori Watanabe  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1397f24f66STakanori Watanabe  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1497f24f66STakanori Watanabe  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
1597f24f66STakanori Watanabe  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
1697f24f66STakanori Watanabe  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1797f24f66STakanori Watanabe  */
1897f24f66STakanori Watanabe 
1997f24f66STakanori Watanabe /* #define	TPM_DEBUG */
2097f24f66STakanori Watanabe 
2197f24f66STakanori Watanabe #include <sys/param.h>
2297f24f66STakanori Watanabe #include <sys/systm.h>
2397f24f66STakanori Watanabe #include <sys/kernel.h>
2497f24f66STakanori Watanabe #include <sys/malloc.h>
2597f24f66STakanori Watanabe #include <sys/proc.h>
2697f24f66STakanori Watanabe 
2797f24f66STakanori Watanabe #include <sys/module.h>
2897f24f66STakanori Watanabe #include <sys/conf.h>
2997f24f66STakanori Watanabe #include <sys/uio.h>
3097f24f66STakanori Watanabe #include <sys/bus.h>
3197f24f66STakanori Watanabe 
3297f24f66STakanori Watanabe #include <machine/bus.h>
3397f24f66STakanori Watanabe #include <sys/rman.h>
3497f24f66STakanori Watanabe #include <machine/resource.h>
3597f24f66STakanori Watanabe 
3697f24f66STakanori Watanabe #include <machine/md_var.h>
3797f24f66STakanori Watanabe 
3897f24f66STakanori Watanabe #include <isa/isareg.h>
3997f24f66STakanori Watanabe #include <isa/isavar.h>
4097f24f66STakanori Watanabe #include <dev/tpm/tpmvar.h>
4197f24f66STakanori Watanabe 
4297f24f66STakanori Watanabe 
4397f24f66STakanori Watanabe #define	TPM_BUFSIZ	1024
4497f24f66STakanori Watanabe 
4597f24f66STakanori Watanabe #define TPM_HDRSIZE	10
4697f24f66STakanori Watanabe 
4797f24f66STakanori Watanabe #define TPM_PARAM_SIZE	0x0001
4897f24f66STakanori Watanabe 
4997f24f66STakanori Watanabe #define IRQUNK	-1
5097f24f66STakanori Watanabe 
51*453130d9SPedro F. Giffuni #define	TPM_ACCESS			0x0000	/* access register */
5297f24f66STakanori Watanabe #define	TPM_ACCESS_ESTABLISHMENT	0x01	/* establishment */
5397f24f66STakanori Watanabe #define	TPM_ACCESS_REQUEST_USE		0x02	/* request using locality */
5497f24f66STakanori Watanabe #define	TPM_ACCESS_REQUEST_PENDING	0x04	/* pending request */
5597f24f66STakanori Watanabe #define	TPM_ACCESS_SEIZE		0x08	/* request locality seize */
5697f24f66STakanori Watanabe #define	TPM_ACCESS_SEIZED		0x10	/* locality has been seized */
5797f24f66STakanori Watanabe #define	TPM_ACCESS_ACTIVE_LOCALITY	0x20	/* locality is active */
5897f24f66STakanori Watanabe #define	TPM_ACCESS_VALID		0x80	/* bits are valid */
5997f24f66STakanori Watanabe #define	TPM_ACCESS_BITS	\
6097f24f66STakanori Watanabe     "\020\01EST\02REQ\03PEND\04SEIZE\05SEIZED\06ACT\010VALID"
6197f24f66STakanori Watanabe 
6297f24f66STakanori Watanabe #define	TPM_INTERRUPT_ENABLE	0x0008
6397f24f66STakanori Watanabe #define	TPM_GLOBAL_INT_ENABLE	0x80000000	/* enable ints */
6497f24f66STakanori Watanabe #define	TPM_CMD_READY_INT	0x00000080	/* cmd ready enable */
6597f24f66STakanori Watanabe #define	TPM_INT_EDGE_FALLING	0x00000018
6697f24f66STakanori Watanabe #define	TPM_INT_EDGE_RISING	0x00000010
6797f24f66STakanori Watanabe #define	TPM_INT_LEVEL_LOW	0x00000008
6897f24f66STakanori Watanabe #define	TPM_INT_LEVEL_HIGH	0x00000000
6997f24f66STakanori Watanabe #define	TPM_LOCALITY_CHANGE_INT	0x00000004	/* locality change enable */
7097f24f66STakanori Watanabe #define	TPM_STS_VALID_INT	0x00000002	/* int on TPM_STS_VALID is set */
7197f24f66STakanori Watanabe #define	TPM_DATA_AVAIL_INT	0x00000001	/* int on TPM_STS_DATA_AVAIL is set */
7297f24f66STakanori Watanabe #define	TPM_INTERRUPT_ENABLE_BITS \
7397f24f66STakanori Watanabe     "\020\040ENA\010RDY\03LOCH\02STSV\01DRDY"
7497f24f66STakanori Watanabe 
7597f24f66STakanori Watanabe #define	TPM_INT_VECTOR		0x000c	/* 8 bit reg for 4 bit irq vector */
7697f24f66STakanori Watanabe #define	TPM_INT_STATUS		0x0010	/* bits are & 0x87 from TPM_INTERRUPT_ENABLE */
7797f24f66STakanori Watanabe 
7897f24f66STakanori Watanabe #define	TPM_INTF_CAPABILITIES		0x0014	/* capability register */
7997f24f66STakanori Watanabe #define	TPM_INTF_BURST_COUNT_STATIC	0x0100	/* TPM_STS_BMASK static */
8097f24f66STakanori Watanabe #define	TPM_INTF_CMD_READY_INT		0x0080	/* int on ready supported */
8197f24f66STakanori Watanabe #define	TPM_INTF_INT_EDGE_FALLING	0x0040	/* falling edge ints supported */
8297f24f66STakanori Watanabe #define	TPM_INTF_INT_EDGE_RISING	0x0020	/* rising edge ints supported */
8397f24f66STakanori Watanabe #define	TPM_INTF_INT_LEVEL_LOW		0x0010	/* level-low ints supported */
8497f24f66STakanori Watanabe #define	TPM_INTF_INT_LEVEL_HIGH		0x0008	/* level-high ints supported */
8597f24f66STakanori Watanabe #define	TPM_INTF_LOCALITY_CHANGE_INT	0x0004	/* locality-change int (mb 1) */
8697f24f66STakanori Watanabe #define	TPM_INTF_STS_VALID_INT		0x0002	/* TPM_STS_VALID int supported */
8797f24f66STakanori Watanabe #define	TPM_INTF_DATA_AVAIL_INT		0x0001	/* TPM_STS_DATA_AVAIL int supported (mb 1) */
8897f24f66STakanori Watanabe #define	TPM_CAPSREQ \
8997f24f66STakanori Watanabe   (TPM_INTF_DATA_AVAIL_INT|TPM_INTF_LOCALITY_CHANGE_INT|TPM_INTF_INT_LEVEL_LOW)
9097f24f66STakanori Watanabe #define	TPM_CAPBITS \
9197f24f66STakanori Watanabe   "\020\01IDRDY\02ISTSV\03ILOCH\04IHIGH\05ILOW\06IEDGE\07IFALL\010IRDY\011BCST"
9297f24f66STakanori Watanabe 
9397f24f66STakanori Watanabe #define	TPM_STS			0x0018		/* status register */
9497f24f66STakanori Watanabe #define TPM_STS_MASK		0x000000ff	/* status bits */
9597f24f66STakanori Watanabe #define	TPM_STS_BMASK		0x00ffff00	/* ro io burst size */
9697f24f66STakanori Watanabe #define	TPM_STS_VALID		0x00000080	/* ro other bits are valid */
9797f24f66STakanori Watanabe #define	TPM_STS_CMD_READY	0x00000040	/* rw chip/signal ready */
9897f24f66STakanori Watanabe #define	TPM_STS_GO		0x00000020	/* wo start the command */
9997f24f66STakanori Watanabe #define	TPM_STS_DATA_AVAIL	0x00000010	/* ro data available */
10097f24f66STakanori Watanabe #define	TPM_STS_DATA_EXPECT	0x00000008	/* ro more data to be written */
10197f24f66STakanori Watanabe #define	TPM_STS_RESP_RETRY	0x00000002	/* wo resend the response */
10297f24f66STakanori Watanabe #define	TPM_STS_BITS	"\020\010VALID\07RDY\06GO\05DRDY\04EXPECT\02RETRY"
10397f24f66STakanori Watanabe 
10497f24f66STakanori Watanabe #define	TPM_DATA	0x0024
10597f24f66STakanori Watanabe #define	TPM_ID		0x0f00
10697f24f66STakanori Watanabe #define	TPM_REV		0x0f04
10797f24f66STakanori Watanabe #define	TPM_SIZE	0x5000		/* five pages of the above */
10897f24f66STakanori Watanabe 
10997f24f66STakanori Watanabe #define	TPM_ACCESS_TMO	2000		/* 2sec */
11097f24f66STakanori Watanabe #define	TPM_READY_TMO	2000		/* 2sec */
11197f24f66STakanori Watanabe #define	TPM_READ_TMO	120000		/* 2 minutes */
11297f24f66STakanori Watanabe #define TPM_BURST_TMO	2000		/* 2sec */
11397f24f66STakanori Watanabe 
11497f24f66STakanori Watanabe #define	TPM_LEGACY_BUSY	0x01
11597f24f66STakanori Watanabe #define	TPM_LEGACY_ABRT	0x01
11697f24f66STakanori Watanabe #define	TPM_LEGACY_DA	0x02
11797f24f66STakanori Watanabe #define	TPM_LEGACY_RE	0x04
11897f24f66STakanori Watanabe #define	TPM_LEGACY_LAST	0x04
11997f24f66STakanori Watanabe #define	TPM_LEGACY_BITS	"\020\01BUSY\2DA\3RE\4LAST"
12097f24f66STakanori Watanabe #define	TPM_LEGACY_TMO		(2*60)	/* sec */
12197f24f66STakanori Watanabe #define	TPM_LEGACY_SLEEP	5	/* ticks */
12297f24f66STakanori Watanabe #define	TPM_LEGACY_DELAY	100
12397f24f66STakanori Watanabe 
12497f24f66STakanori Watanabe /* Set when enabling legacy interface in host bridge. */
12597f24f66STakanori Watanabe int tpm_enabled;
12697f24f66STakanori Watanabe 
12797f24f66STakanori Watanabe #define	TPMSOFTC(dev) \
12897f24f66STakanori Watanabe 	((struct tpm_softc *)dev->si_drv1)
12997f24f66STakanori Watanabe 
13097f24f66STakanori Watanabe d_open_t	tpmopen;
13197f24f66STakanori Watanabe d_close_t	tpmclose;
13297f24f66STakanori Watanabe d_read_t	tpmread;
13397f24f66STakanori Watanabe d_write_t	tpmwrite;
13497f24f66STakanori Watanabe d_ioctl_t	tpmioctl;
13597f24f66STakanori Watanabe 
13697f24f66STakanori Watanabe static struct cdevsw tpm_cdevsw = {
13797f24f66STakanori Watanabe 	.d_version =	D_VERSION,
13897f24f66STakanori Watanabe 	.d_flags =	D_NEEDGIANT,
13997f24f66STakanori Watanabe 	.d_open =	tpmopen,
14097f24f66STakanori Watanabe 	.d_close =	tpmclose,
14197f24f66STakanori Watanabe 	.d_read =	tpmread,
14297f24f66STakanori Watanabe 	.d_write =	tpmwrite,
14397f24f66STakanori Watanabe 	.d_ioctl =	tpmioctl,
14497f24f66STakanori Watanabe 	.d_name =	"tpm",
14597f24f66STakanori Watanabe };
14697f24f66STakanori Watanabe 
14797f24f66STakanori Watanabe const struct {
14897f24f66STakanori Watanabe 	u_int32_t devid;
14997f24f66STakanori Watanabe 	char name[32];
15097f24f66STakanori Watanabe 	int flags;
15197f24f66STakanori Watanabe #define TPM_DEV_NOINTS	0x0001
15297f24f66STakanori Watanabe } tpm_devs[] = {
15397f24f66STakanori Watanabe 	{ 0x000615d1, "IFX SLD 9630 TT 1.1", 0 },
15497f24f66STakanori Watanabe 	{ 0x000b15d1, "IFX SLB 9635 TT 1.2", 0 },
15597f24f66STakanori Watanabe 	{ 0x100214e4, "Broadcom BCM0102", TPM_DEV_NOINTS },
15697f24f66STakanori Watanabe 	{ 0x00fe1050, "WEC WPCT200", 0 },
15797f24f66STakanori Watanabe 	{ 0x687119fa, "SNS SSX35", 0 },
15897f24f66STakanori Watanabe 	{ 0x2e4d5453, "STM ST19WP18", 0 },
15997f24f66STakanori Watanabe 	{ 0x32021114, "ATML 97SC3203", TPM_DEV_NOINTS },
16097f24f66STakanori Watanabe 	{ 0x10408086, "INTEL INTC0102", 0 },
16197f24f66STakanori Watanabe 	{ 0, "", TPM_DEV_NOINTS },
16297f24f66STakanori Watanabe };
16397f24f66STakanori Watanabe 
16497f24f66STakanori Watanabe int tpm_tis12_irqinit(struct tpm_softc *, int, int);
16597f24f66STakanori Watanabe int tpm_tis12_init(struct tpm_softc *, int, const char *);
16697f24f66STakanori Watanabe int tpm_tis12_start(struct tpm_softc *, int);
16797f24f66STakanori Watanabe int tpm_tis12_read(struct tpm_softc *, void *, int, size_t *, int);
16897f24f66STakanori Watanabe int tpm_tis12_write(struct tpm_softc *, void *, int);
16997f24f66STakanori Watanabe int tpm_tis12_end(struct tpm_softc *, int, int);
17097f24f66STakanori Watanabe 
17197f24f66STakanori Watanabe void tpm_intr(void *);
17297f24f66STakanori Watanabe 
17397f24f66STakanori Watanabe int tpm_waitfor_poll(struct tpm_softc *, u_int8_t, int, void *);
17497f24f66STakanori Watanabe int tpm_waitfor_int(struct tpm_softc *, u_int8_t, int, void *, int);
17597f24f66STakanori Watanabe int tpm_waitfor(struct tpm_softc *, u_int8_t, int, void *);
17697f24f66STakanori Watanabe int tpm_request_locality(struct tpm_softc *, int);
17797f24f66STakanori Watanabe int tpm_getburst(struct tpm_softc *);
17897f24f66STakanori Watanabe u_int8_t tpm_status(struct tpm_softc *);
17997f24f66STakanori Watanabe int tpm_tmotohz(int);
18097f24f66STakanori Watanabe 
18197f24f66STakanori Watanabe int tpm_legacy_probe(bus_space_tag_t, bus_addr_t);
18297f24f66STakanori Watanabe int tpm_legacy_init(struct tpm_softc *, int, const char *);
18397f24f66STakanori Watanabe int tpm_legacy_start(struct tpm_softc *, int);
18497f24f66STakanori Watanabe int tpm_legacy_read(struct tpm_softc *, void *, int, size_t *, int);
18597f24f66STakanori Watanabe int tpm_legacy_write(struct tpm_softc *, void *, int);
18697f24f66STakanori Watanabe int tpm_legacy_end(struct tpm_softc *, int, int);
18797f24f66STakanori Watanabe 
18897f24f66STakanori Watanabe 
18997f24f66STakanori Watanabe /*
19097f24f66STakanori Watanabe  * FreeBSD specific code for probing and attaching TPM to device tree.
19197f24f66STakanori Watanabe  */
19297f24f66STakanori Watanabe #if 0
19397f24f66STakanori Watanabe static void
19497f24f66STakanori Watanabe tpm_identify(driver_t *driver, device_t parent)
19597f24f66STakanori Watanabe {
19697f24f66STakanori Watanabe 	BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "tpm", 0);
19797f24f66STakanori Watanabe }
19897f24f66STakanori Watanabe #endif
19997f24f66STakanori Watanabe 
20097f24f66STakanori Watanabe int
tpm_attach(device_t dev)20197f24f66STakanori Watanabe tpm_attach(device_t dev)
20297f24f66STakanori Watanabe {
20397f24f66STakanori Watanabe 	struct tpm_softc *sc = device_get_softc(dev);
20497f24f66STakanori Watanabe 	int irq;
20597f24f66STakanori Watanabe 
20697f24f66STakanori Watanabe 	sc->mem_rid = 0;
20797f24f66STakanori Watanabe 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
20897f24f66STakanori Watanabe 	    RF_ACTIVE);
20997f24f66STakanori Watanabe 	if (sc->mem_res == NULL)
21097f24f66STakanori Watanabe 		return ENXIO;
21197f24f66STakanori Watanabe 
21297f24f66STakanori Watanabe 	sc->sc_bt = rman_get_bustag(sc->mem_res);
21397f24f66STakanori Watanabe 	sc->sc_bh = rman_get_bushandle(sc->mem_res);
21497f24f66STakanori Watanabe 
21597f24f66STakanori Watanabe 	sc->irq_rid = 0;
21697f24f66STakanori Watanabe 	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
21797f24f66STakanori Watanabe 	    RF_ACTIVE | RF_SHAREABLE);
21897f24f66STakanori Watanabe 	if (sc->irq_res != NULL)
21997f24f66STakanori Watanabe 		irq = rman_get_start(sc->irq_res);
22097f24f66STakanori Watanabe 	else
22197f24f66STakanori Watanabe 		irq = IRQUNK;
22297f24f66STakanori Watanabe 
22397f24f66STakanori Watanabe 	/* In case PnP probe this may contain some initialization. */
22497f24f66STakanori Watanabe 	tpm_tis12_probe(sc->sc_bt, sc->sc_bh);
22597f24f66STakanori Watanabe 
22697f24f66STakanori Watanabe 	if (tpm_legacy_probe(sc->sc_bt, sc->sc_bh)) {
22797f24f66STakanori Watanabe 		sc->sc_init = tpm_legacy_init;
22897f24f66STakanori Watanabe 		sc->sc_start = tpm_legacy_start;
22997f24f66STakanori Watanabe 		sc->sc_read = tpm_legacy_read;
23097f24f66STakanori Watanabe 		sc->sc_write = tpm_legacy_write;
23197f24f66STakanori Watanabe 		sc->sc_end = tpm_legacy_end;
23297f24f66STakanori Watanabe 	} else {
23397f24f66STakanori Watanabe 		sc->sc_init = tpm_tis12_init;
23497f24f66STakanori Watanabe 		sc->sc_start = tpm_tis12_start;
23597f24f66STakanori Watanabe 		sc->sc_read = tpm_tis12_read;
23697f24f66STakanori Watanabe 		sc->sc_write = tpm_tis12_write;
23797f24f66STakanori Watanabe 		sc->sc_end = tpm_tis12_end;
23897f24f66STakanori Watanabe 	}
23997f24f66STakanori Watanabe 
24097f24f66STakanori Watanabe 	printf("%s", device_get_name(dev));
24197f24f66STakanori Watanabe 	if ((sc->sc_init)(sc, irq, "tpm")) {
24297f24f66STakanori Watanabe 		tpm_detach(dev);
24397f24f66STakanori Watanabe 		return ENXIO;
24497f24f66STakanori Watanabe 	}
24597f24f66STakanori Watanabe 
24697f24f66STakanori Watanabe 	if (sc->sc_init == tpm_tis12_init && sc->irq_res != NULL &&
24797f24f66STakanori Watanabe 	    bus_setup_intr(dev, sc->irq_res, INTR_TYPE_TTY, NULL,
24897f24f66STakanori Watanabe 	    tpm_intr, sc, &sc->intr_cookie) != 0) {
24997f24f66STakanori Watanabe 		tpm_detach(dev);
25097f24f66STakanori Watanabe 		printf(": cannot establish interrupt\n");
25197f24f66STakanori Watanabe 		return 1;
25297f24f66STakanori Watanabe 	}
25397f24f66STakanori Watanabe 
25497f24f66STakanori Watanabe 	sc->sc_cdev = make_dev(&tpm_cdevsw, device_get_unit(dev),
25597f24f66STakanori Watanabe 			    UID_ROOT, GID_WHEEL, 0600, "tpm");
25697f24f66STakanori Watanabe 	sc->sc_cdev->si_drv1 = sc;
25797f24f66STakanori Watanabe 
25897f24f66STakanori Watanabe 	return 0;
25997f24f66STakanori Watanabe }
26097f24f66STakanori Watanabe 
26197f24f66STakanori Watanabe int
tpm_detach(device_t dev)26297f24f66STakanori Watanabe tpm_detach(device_t dev)
26397f24f66STakanori Watanabe {
26497f24f66STakanori Watanabe 	struct tpm_softc * sc = device_get_softc(dev);
26597f24f66STakanori Watanabe 
26697f24f66STakanori Watanabe 	if(sc->intr_cookie){
26797f24f66STakanori Watanabe 		bus_teardown_intr(dev, sc->irq_res, sc->intr_cookie);
26897f24f66STakanori Watanabe 	}
26997f24f66STakanori Watanabe 
27097f24f66STakanori Watanabe 	if(sc->mem_res){
27197f24f66STakanori Watanabe 		bus_release_resource(dev, SYS_RES_MEMORY,
27297f24f66STakanori Watanabe 				     sc->mem_rid, sc->mem_res);
27397f24f66STakanori Watanabe 	}
27497f24f66STakanori Watanabe 
27597f24f66STakanori Watanabe 	if(sc->irq_res){
27697f24f66STakanori Watanabe 		bus_release_resource(dev, SYS_RES_IRQ,
27797f24f66STakanori Watanabe 				     sc->irq_rid, sc->irq_res);
27897f24f66STakanori Watanabe 	}
27997f24f66STakanori Watanabe 	if(sc->sc_cdev){
28097f24f66STakanori Watanabe 		destroy_dev(sc->sc_cdev);
28197f24f66STakanori Watanabe 	}
28297f24f66STakanori Watanabe 
28397f24f66STakanori Watanabe 	return 0;
28497f24f66STakanori Watanabe }
28597f24f66STakanori Watanabe 
28697f24f66STakanori Watanabe 
28797f24f66STakanori Watanabe /* Probe TPM using TIS 1.2 interface. */
28897f24f66STakanori Watanabe int
tpm_tis12_probe(bus_space_tag_t bt,bus_space_handle_t bh)28997f24f66STakanori Watanabe tpm_tis12_probe(bus_space_tag_t bt, bus_space_handle_t bh)
29097f24f66STakanori Watanabe {
29197f24f66STakanori Watanabe 	u_int32_t r;
29297f24f66STakanori Watanabe 	u_int8_t save, reg;
29397f24f66STakanori Watanabe 
29497f24f66STakanori Watanabe 	r = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITIES);
29597f24f66STakanori Watanabe 	if (r == 0xffffffff)
29697f24f66STakanori Watanabe 		return 0;
29797f24f66STakanori Watanabe 
29897f24f66STakanori Watanabe #ifdef TPM_DEBUG
29997f24f66STakanori Watanabe 	printf("tpm: caps=%b\n", r, TPM_CAPBITS);
30097f24f66STakanori Watanabe #endif
30197f24f66STakanori Watanabe 	if ((r & TPM_CAPSREQ) != TPM_CAPSREQ ||
30297f24f66STakanori Watanabe 	    !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) {
30397f24f66STakanori Watanabe #ifdef TPM_DEBUG
30497f24f66STakanori Watanabe 		printf("tpm: caps too low (caps=%b)\n", r, TPM_CAPBITS);
30597f24f66STakanori Watanabe #endif
30697f24f66STakanori Watanabe 		return 0;
30797f24f66STakanori Watanabe 	}
30897f24f66STakanori Watanabe 
30997f24f66STakanori Watanabe 	save = bus_space_read_1(bt, bh, TPM_ACCESS);
31097f24f66STakanori Watanabe 	bus_space_write_1(bt, bh, TPM_ACCESS, TPM_ACCESS_REQUEST_USE);
31197f24f66STakanori Watanabe 	reg = bus_space_read_1(bt, bh, TPM_ACCESS);
31297f24f66STakanori Watanabe 	if ((reg & TPM_ACCESS_VALID) && (reg & TPM_ACCESS_ACTIVE_LOCALITY) &&
31397f24f66STakanori Watanabe 	    bus_space_read_4(bt, bh, TPM_ID) != 0xffffffff)
31497f24f66STakanori Watanabe 		return 1;
31597f24f66STakanori Watanabe 
31697f24f66STakanori Watanabe 	bus_space_write_1(bt, bh, TPM_ACCESS, save);
31797f24f66STakanori Watanabe 	return 0;
31897f24f66STakanori Watanabe }
31997f24f66STakanori Watanabe 
32097f24f66STakanori Watanabe /*
32197f24f66STakanori Watanabe  * Setup interrupt vector if one is provided and interrupts are know to
32297f24f66STakanori Watanabe  * work on that particular chip.
32397f24f66STakanori Watanabe  */
32497f24f66STakanori Watanabe int
tpm_tis12_irqinit(struct tpm_softc * sc,int irq,int idx)32597f24f66STakanori Watanabe tpm_tis12_irqinit(struct tpm_softc *sc, int irq, int idx)
32697f24f66STakanori Watanabe {
32797f24f66STakanori Watanabe 	u_int32_t r;
32897f24f66STakanori Watanabe 
32997f24f66STakanori Watanabe 	if ((irq == IRQUNK) || (tpm_devs[idx].flags & TPM_DEV_NOINTS)) {
33097f24f66STakanori Watanabe 		sc->sc_vector = IRQUNK;
33197f24f66STakanori Watanabe 		return 0;
33297f24f66STakanori Watanabe 	}
33397f24f66STakanori Watanabe 
33497f24f66STakanori Watanabe 	/* Ack and disable all interrupts. */
33597f24f66STakanori Watanabe 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
33697f24f66STakanori Watanabe 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) &
33797f24f66STakanori Watanabe 	    ~TPM_GLOBAL_INT_ENABLE);
33897f24f66STakanori Watanabe 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS,
33997f24f66STakanori Watanabe 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS));
34097f24f66STakanori Watanabe 
34197f24f66STakanori Watanabe 	/* Program interrupt vector. */
34297f24f66STakanori Watanabe 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_INT_VECTOR, irq);
34397f24f66STakanori Watanabe 	sc->sc_vector = irq;
34497f24f66STakanori Watanabe 
34597f24f66STakanori Watanabe 	/* Program interrupt type. */
34697f24f66STakanori Watanabe 	if (sc->sc_capabilities & TPM_INTF_INT_EDGE_RISING)
34797f24f66STakanori Watanabe 		r = TPM_INT_EDGE_RISING;
34897f24f66STakanori Watanabe 	else if (sc->sc_capabilities & TPM_INTF_INT_LEVEL_HIGH)
34997f24f66STakanori Watanabe 		r = TPM_INT_LEVEL_HIGH;
35097f24f66STakanori Watanabe 	else
35197f24f66STakanori Watanabe 		r = TPM_INT_LEVEL_LOW;
35297f24f66STakanori Watanabe 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, r);
35397f24f66STakanori Watanabe 
35497f24f66STakanori Watanabe 	return 0;
35597f24f66STakanori Watanabe }
35697f24f66STakanori Watanabe 
35797f24f66STakanori Watanabe /* Setup TPM using TIS 1.2 interface. */
35897f24f66STakanori Watanabe int
tpm_tis12_init(struct tpm_softc * sc,int irq,const char * name)35997f24f66STakanori Watanabe tpm_tis12_init(struct tpm_softc *sc, int irq, const char *name)
36097f24f66STakanori Watanabe {
36197f24f66STakanori Watanabe 	u_int32_t r;
36297f24f66STakanori Watanabe 	int i;
36397f24f66STakanori Watanabe 
36497f24f66STakanori Watanabe 	r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTF_CAPABILITIES);
36597f24f66STakanori Watanabe #ifdef TPM_DEBUG
36697f24f66STakanori Watanabe 	printf(" caps=%b ", r, TPM_CAPBITS);
36797f24f66STakanori Watanabe #endif
36897f24f66STakanori Watanabe 	if ((r & TPM_CAPSREQ) != TPM_CAPSREQ ||
36997f24f66STakanori Watanabe 	    !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) {
37097f24f66STakanori Watanabe 		printf(": capabilities too low (caps=%b)\n", r, TPM_CAPBITS);
37197f24f66STakanori Watanabe 		return 1;
37297f24f66STakanori Watanabe 	}
37397f24f66STakanori Watanabe 	sc->sc_capabilities = r;
37497f24f66STakanori Watanabe 
37597f24f66STakanori Watanabe 	sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID);
37697f24f66STakanori Watanabe 	sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV);
37797f24f66STakanori Watanabe 
37897f24f66STakanori Watanabe 	for (i = 0; tpm_devs[i].devid; i++)
37997f24f66STakanori Watanabe 		if (tpm_devs[i].devid == sc->sc_devid)
38097f24f66STakanori Watanabe 			break;
38197f24f66STakanori Watanabe 
38297f24f66STakanori Watanabe 	if (tpm_devs[i].devid)
38397f24f66STakanori Watanabe 		printf(": %s rev 0x%x\n", tpm_devs[i].name, sc->sc_rev);
38497f24f66STakanori Watanabe 	else
38597f24f66STakanori Watanabe 		printf(": device 0x%08x rev 0x%x\n", sc->sc_devid, sc->sc_rev);
38697f24f66STakanori Watanabe 
38797f24f66STakanori Watanabe 	if (tpm_tis12_irqinit(sc, irq, i))
38897f24f66STakanori Watanabe 		return 1;
38997f24f66STakanori Watanabe 
39097f24f66STakanori Watanabe 	if (tpm_request_locality(sc, 0))
39197f24f66STakanori Watanabe 		return 1;
39297f24f66STakanori Watanabe 
39397f24f66STakanori Watanabe 	/* Abort whatever it thought it was doing. */
39497f24f66STakanori Watanabe 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY);
39597f24f66STakanori Watanabe 
39697f24f66STakanori Watanabe 	return 0;
39797f24f66STakanori Watanabe }
39897f24f66STakanori Watanabe 
39997f24f66STakanori Watanabe int
tpm_request_locality(struct tpm_softc * sc,int l)40097f24f66STakanori Watanabe tpm_request_locality(struct tpm_softc *sc, int l)
40197f24f66STakanori Watanabe {
40297f24f66STakanori Watanabe 	u_int32_t r;
40397f24f66STakanori Watanabe 	int to, rv;
40497f24f66STakanori Watanabe 
40597f24f66STakanori Watanabe 	if (l != 0)
40697f24f66STakanori Watanabe 		return EINVAL;
40797f24f66STakanori Watanabe 
40897f24f66STakanori Watanabe 	if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
40997f24f66STakanori Watanabe 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) ==
41097f24f66STakanori Watanabe 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY))
41197f24f66STakanori Watanabe 		return 0;
41297f24f66STakanori Watanabe 
41397f24f66STakanori Watanabe 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
41497f24f66STakanori Watanabe 	    TPM_ACCESS_REQUEST_USE);
41597f24f66STakanori Watanabe 
41697f24f66STakanori Watanabe 	to = tpm_tmotohz(TPM_ACCESS_TMO);
41797f24f66STakanori Watanabe 
41897f24f66STakanori Watanabe 	while ((r = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
41997f24f66STakanori Watanabe 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
42097f24f66STakanori Watanabe 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) {
42197f24f66STakanori Watanabe 		rv = tsleep(sc->sc_init, PRIBIO | PCATCH, "tpm_locality", 1);
42297f24f66STakanori Watanabe 		if (rv &&  rv != EWOULDBLOCK) {
42397f24f66STakanori Watanabe #ifdef TPM_DEBUG
42497f24f66STakanori Watanabe 			printf("tpm_request_locality: interrupted %d\n", rv);
42597f24f66STakanori Watanabe #endif
42697f24f66STakanori Watanabe 			return rv;
42797f24f66STakanori Watanabe 		}
42897f24f66STakanori Watanabe 	}
42997f24f66STakanori Watanabe 
43097f24f66STakanori Watanabe 	if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
43197f24f66STakanori Watanabe 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
43297f24f66STakanori Watanabe #ifdef TPM_DEBUG
43397f24f66STakanori Watanabe 		printf("tpm_request_locality: access %b\n", r, TPM_ACCESS_BITS);
43497f24f66STakanori Watanabe #endif
43597f24f66STakanori Watanabe 		return EBUSY;
43697f24f66STakanori Watanabe 	}
43797f24f66STakanori Watanabe 
43897f24f66STakanori Watanabe 	return 0;
43997f24f66STakanori Watanabe }
44097f24f66STakanori Watanabe 
44197f24f66STakanori Watanabe int
tpm_getburst(struct tpm_softc * sc)44297f24f66STakanori Watanabe tpm_getburst(struct tpm_softc *sc)
44397f24f66STakanori Watanabe {
44497f24f66STakanori Watanabe 	int burst, to, rv;
44597f24f66STakanori Watanabe 
44697f24f66STakanori Watanabe 	to = tpm_tmotohz(TPM_BURST_TMO);
44797f24f66STakanori Watanabe 
44897f24f66STakanori Watanabe 	burst = 0;
44997f24f66STakanori Watanabe 	while (burst == 0 && to--) {
45097f24f66STakanori Watanabe 		/*
45197f24f66STakanori Watanabe 		 * Burst count has to be read from bits 8 to 23 without
45297f24f66STakanori Watanabe 		 * touching any other bits, eg. the actual status bits 0
45397f24f66STakanori Watanabe 		 * to 7.
45497f24f66STakanori Watanabe 		 */
45597f24f66STakanori Watanabe 		burst = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 1);
45697f24f66STakanori Watanabe 		burst |= bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 2)
45797f24f66STakanori Watanabe 		    << 8;
45897f24f66STakanori Watanabe #ifdef TPM_DEBUG
45997f24f66STakanori Watanabe 		printf("tpm_getburst: read %d\n", burst);
46097f24f66STakanori Watanabe #endif
46197f24f66STakanori Watanabe 		if (burst)
46297f24f66STakanori Watanabe 			return burst;
46397f24f66STakanori Watanabe 
46497f24f66STakanori Watanabe 		rv = tsleep(sc, PRIBIO | PCATCH, "tpm_getburst", 1);
46597f24f66STakanori Watanabe 		if (rv && rv != EWOULDBLOCK) {
46697f24f66STakanori Watanabe 			return 0;
46797f24f66STakanori Watanabe 		}
46897f24f66STakanori Watanabe 	}
46997f24f66STakanori Watanabe 
47097f24f66STakanori Watanabe 	return 0;
47197f24f66STakanori Watanabe }
47297f24f66STakanori Watanabe 
47397f24f66STakanori Watanabe u_int8_t
tpm_status(struct tpm_softc * sc)47497f24f66STakanori Watanabe tpm_status(struct tpm_softc *sc)
47597f24f66STakanori Watanabe {
47697f24f66STakanori Watanabe 	u_int8_t status;
47797f24f66STakanori Watanabe 
47897f24f66STakanori Watanabe 	status = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS) &
47997f24f66STakanori Watanabe 	    TPM_STS_MASK;
48097f24f66STakanori Watanabe 
48197f24f66STakanori Watanabe 	return status;
48297f24f66STakanori Watanabe }
48397f24f66STakanori Watanabe 
48497f24f66STakanori Watanabe int
tpm_tmotohz(int tmo)48597f24f66STakanori Watanabe tpm_tmotohz(int tmo)
48697f24f66STakanori Watanabe {
48797f24f66STakanori Watanabe 	struct timeval tv;
48897f24f66STakanori Watanabe 
48997f24f66STakanori Watanabe 	tv.tv_sec = tmo / 1000;
49097f24f66STakanori Watanabe 	tv.tv_usec = 1000 * (tmo % 1000);
49197f24f66STakanori Watanabe 
49297f24f66STakanori Watanabe 	return tvtohz(&tv);
49397f24f66STakanori Watanabe }
49497f24f66STakanori Watanabe 
49597f24f66STakanori Watanabe /* Save TPM state on suspend. */
49697f24f66STakanori Watanabe int
tpm_suspend(device_t dev)49797f24f66STakanori Watanabe tpm_suspend(device_t dev)
49897f24f66STakanori Watanabe {
49997f24f66STakanori Watanabe 	struct tpm_softc *sc = device_get_softc(dev);
50097f24f66STakanori Watanabe 	int why = 1;
50197f24f66STakanori Watanabe 	u_int8_t command[] = {
50297f24f66STakanori Watanabe 	    0, 193,		/* TPM_TAG_RQU_COMMAND */
50397f24f66STakanori Watanabe 	    0, 0, 0, 10,	/* Length in bytes */
50497f24f66STakanori Watanabe 	    0, 0, 0, 156	/* TPM_ORD_SaveStates */
50597f24f66STakanori Watanabe 	};
50697f24f66STakanori Watanabe 
50797f24f66STakanori Watanabe 	/*
50897f24f66STakanori Watanabe 	 * Power down:  We have to issue the SaveStates command.
50997f24f66STakanori Watanabe 	 */
51097f24f66STakanori Watanabe 	sc->sc_write(sc, &command, sizeof(command));
51197f24f66STakanori Watanabe 	sc->sc_read(sc, &command, sizeof(command), NULL, TPM_HDRSIZE);
51297f24f66STakanori Watanabe #ifdef TPM_DEBUG
51397f24f66STakanori Watanabe 	printf("tpm_suspend: power down: %d -> %d\n", sc->sc_suspend, why);
51497f24f66STakanori Watanabe #endif
51597f24f66STakanori Watanabe 	sc->sc_suspend = why;
51697f24f66STakanori Watanabe 
51797f24f66STakanori Watanabe 	return 0;
51897f24f66STakanori Watanabe }
51997f24f66STakanori Watanabe 
52097f24f66STakanori Watanabe /*
52197f24f66STakanori Watanabe  * Handle resume event.  Actually nothing to do as the BIOS is supposed
52297f24f66STakanori Watanabe  * to restore the previously saved state.
52397f24f66STakanori Watanabe  */
52497f24f66STakanori Watanabe int
tpm_resume(device_t dev)52597f24f66STakanori Watanabe tpm_resume(device_t dev)
52697f24f66STakanori Watanabe {
52797f24f66STakanori Watanabe 	struct tpm_softc *sc = device_get_softc(dev);
52897f24f66STakanori Watanabe 	int why = 0;
52997f24f66STakanori Watanabe #ifdef TPM_DEBUG
53097f24f66STakanori Watanabe 	printf("tpm_resume: resume: %d -> %d\n", sc->sc_suspend, why);
53197f24f66STakanori Watanabe #endif
53297f24f66STakanori Watanabe 	sc->sc_suspend = why;
53397f24f66STakanori Watanabe 
53497f24f66STakanori Watanabe 	return 0;
53597f24f66STakanori Watanabe }
53697f24f66STakanori Watanabe 
53797f24f66STakanori Watanabe /* Dispatch suspend and resume events. */
53897f24f66STakanori Watanabe 
53997f24f66STakanori Watanabe /* Wait for given status bits using polling. */
54097f24f66STakanori Watanabe int
tpm_waitfor_poll(struct tpm_softc * sc,u_int8_t mask,int tmo,void * c)54197f24f66STakanori Watanabe tpm_waitfor_poll(struct tpm_softc *sc, u_int8_t mask, int tmo, void *c)
54297f24f66STakanori Watanabe {
54397f24f66STakanori Watanabe 	int rv;
54497f24f66STakanori Watanabe 
54597f24f66STakanori Watanabe 	/*
54697f24f66STakanori Watanabe 	 * Poll until either the requested condition or a time out is
54797f24f66STakanori Watanabe 	 * met.
54897f24f66STakanori Watanabe 	 */
54997f24f66STakanori Watanabe 	while (((sc->sc_stat = tpm_status(sc)) & mask) != mask && tmo--) {
55097f24f66STakanori Watanabe 		rv = tsleep(c, PRIBIO | PCATCH, "tpm_poll", 1);
55197f24f66STakanori Watanabe 		if (rv && rv != EWOULDBLOCK) {
55297f24f66STakanori Watanabe #ifdef TPM_DEBUG
55397f24f66STakanori Watanabe 			printf("tpm_waitfor_poll: interrupted %d\n", rv);
55497f24f66STakanori Watanabe #endif
55597f24f66STakanori Watanabe 			return rv;
55697f24f66STakanori Watanabe 		}
55797f24f66STakanori Watanabe 	}
55897f24f66STakanori Watanabe 
55997f24f66STakanori Watanabe 	return 0;
56097f24f66STakanori Watanabe }
56197f24f66STakanori Watanabe 
56297f24f66STakanori Watanabe /* Wait for given status bits using interrupts. */
56397f24f66STakanori Watanabe int
tpm_waitfor_int(struct tpm_softc * sc,u_int8_t mask,int tmo,void * c,int inttype)56497f24f66STakanori Watanabe tpm_waitfor_int(struct tpm_softc *sc, u_int8_t mask, int tmo, void *c,
56597f24f66STakanori Watanabe     int inttype)
56697f24f66STakanori Watanabe {
56797f24f66STakanori Watanabe 	int rv, to;
56897f24f66STakanori Watanabe 
56997f24f66STakanori Watanabe 	/* Poll and return when condition is already met. */
57097f24f66STakanori Watanabe 	sc->sc_stat = tpm_status(sc);
57197f24f66STakanori Watanabe 	if ((sc->sc_stat & mask) == mask)
57297f24f66STakanori Watanabe 		return 0;
57397f24f66STakanori Watanabe 
57497f24f66STakanori Watanabe 	/*
57597f24f66STakanori Watanabe 	 * Enable interrupt on tpm chip.  Note that interrupts on our
57697f24f66STakanori Watanabe 	 * level (SPL_TTY) are disabled (see tpm{read,write} et al) and
57797f24f66STakanori Watanabe 	 * will not be delivered to the cpu until we call tsleep(9) below.
57897f24f66STakanori Watanabe 	 */
57997f24f66STakanori Watanabe 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
58097f24f66STakanori Watanabe 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) |
58197f24f66STakanori Watanabe 	    inttype);
58297f24f66STakanori Watanabe 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
58397f24f66STakanori Watanabe 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) |
58497f24f66STakanori Watanabe 	    TPM_GLOBAL_INT_ENABLE);
58597f24f66STakanori Watanabe 
58697f24f66STakanori Watanabe 	/*
58797f24f66STakanori Watanabe 	 * Poll once more to remedy the race between previous polling
58897f24f66STakanori Watanabe 	 * and enabling interrupts on the tpm chip.
58997f24f66STakanori Watanabe 	 */
59097f24f66STakanori Watanabe 	sc->sc_stat = tpm_status(sc);
59197f24f66STakanori Watanabe 	if ((sc->sc_stat & mask) == mask) {
59297f24f66STakanori Watanabe 		rv = 0;
59397f24f66STakanori Watanabe 		goto out;
59497f24f66STakanori Watanabe 	}
59597f24f66STakanori Watanabe 
59697f24f66STakanori Watanabe 	to = tpm_tmotohz(tmo);
59797f24f66STakanori Watanabe #ifdef TPM_DEBUG
59897f24f66STakanori Watanabe 	printf("tpm_waitfor_int: sleeping for %d ticks on %p\n", to, c);
59997f24f66STakanori Watanabe #endif
60097f24f66STakanori Watanabe 	/*
60197f24f66STakanori Watanabe 	 * tsleep(9) enables interrupts on the cpu and returns after
60297f24f66STakanori Watanabe 	 * wake up with interrupts disabled again.  Note that interrupts
60397f24f66STakanori Watanabe 	 * generated by the tpm chip while being at SPL_TTY are not lost
60497f24f66STakanori Watanabe 	 * but held and delivered as soon as the cpu goes below SPL_TTY.
60597f24f66STakanori Watanabe 	 */
60697f24f66STakanori Watanabe 	rv = tsleep(c, PRIBIO | PCATCH, "tpm_intr", to);
60797f24f66STakanori Watanabe 
60897f24f66STakanori Watanabe 	sc->sc_stat = tpm_status(sc);
60997f24f66STakanori Watanabe #ifdef TPM_DEBUG
61097f24f66STakanori Watanabe 	printf("tpm_waitfor_int: woke up with rv %d stat %b\n", rv,
61197f24f66STakanori Watanabe 	    sc->sc_stat, TPM_STS_BITS);
61297f24f66STakanori Watanabe #endif
61397f24f66STakanori Watanabe 	if ((sc->sc_stat & mask) == mask)
61497f24f66STakanori Watanabe 		rv = 0;
61597f24f66STakanori Watanabe 
61697f24f66STakanori Watanabe 	/* Disable interrupts on tpm chip again. */
61797f24f66STakanori Watanabe out:	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
61897f24f66STakanori Watanabe 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) &
61997f24f66STakanori Watanabe 	    ~TPM_GLOBAL_INT_ENABLE);
62097f24f66STakanori Watanabe 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
62197f24f66STakanori Watanabe 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) &
62297f24f66STakanori Watanabe 	    ~inttype);
62397f24f66STakanori Watanabe 
62497f24f66STakanori Watanabe 	return rv;
62597f24f66STakanori Watanabe }
62697f24f66STakanori Watanabe 
62797f24f66STakanori Watanabe /*
62897f24f66STakanori Watanabe  * Wait on given status bits, uses interrupts where possible, otherwise polls.
62997f24f66STakanori Watanabe  */
63097f24f66STakanori Watanabe int
tpm_waitfor(struct tpm_softc * sc,u_int8_t b0,int tmo,void * c)63197f24f66STakanori Watanabe tpm_waitfor(struct tpm_softc *sc, u_int8_t b0, int tmo, void *c)
63297f24f66STakanori Watanabe {
63397f24f66STakanori Watanabe 	u_int8_t b;
63497f24f66STakanori Watanabe 	int re, to, rv;
63597f24f66STakanori Watanabe 
63697f24f66STakanori Watanabe #ifdef TPM_DEBUG
63797f24f66STakanori Watanabe 	printf("tpm_waitfor: b0 %b\n", b0, TPM_STS_BITS);
63897f24f66STakanori Watanabe #endif
63997f24f66STakanori Watanabe 
64097f24f66STakanori Watanabe 	/*
64197f24f66STakanori Watanabe 	 * If possible, use interrupts, otherwise poll.
64297f24f66STakanori Watanabe 	 *
64397f24f66STakanori Watanabe 	 * We use interrupts for TPM_STS_VALID and TPM_STS_DATA_AVAIL (if
64497f24f66STakanori Watanabe 	 * the tpm chips supports them) as waiting for those can take
64597f24f66STakanori Watanabe 	 * really long.  The other TPM_STS* are not needed very often
64697f24f66STakanori Watanabe 	 * so we do not support them.
64797f24f66STakanori Watanabe 	 */
64897f24f66STakanori Watanabe 	if (sc->sc_vector != IRQUNK) {
64997f24f66STakanori Watanabe 		b = b0;
65097f24f66STakanori Watanabe 
65197f24f66STakanori Watanabe 		/*
652*453130d9SPedro F. Giffuni 		 * Wait for data ready.  This interrupt only occurs
65397f24f66STakanori Watanabe 		 * when both TPM_STS_VALID and TPM_STS_DATA_AVAIL are asserted.
65497f24f66STakanori Watanabe 		 * Thus we don't have to bother with TPM_STS_VALID
65597f24f66STakanori Watanabe 		 * separately and can just return.
65697f24f66STakanori Watanabe 		 *
65797f24f66STakanori Watanabe 		 * This only holds for interrupts!  When using polling
65897f24f66STakanori Watanabe 		 * both flags have to be waited for, see below.
65997f24f66STakanori Watanabe 		 */
66097f24f66STakanori Watanabe 		if ((b & TPM_STS_DATA_AVAIL) && (sc->sc_capabilities &
66197f24f66STakanori Watanabe 		    TPM_INTF_DATA_AVAIL_INT))
66297f24f66STakanori Watanabe 			return tpm_waitfor_int(sc, b, tmo, c,
66397f24f66STakanori Watanabe 			    TPM_DATA_AVAIL_INT);
66497f24f66STakanori Watanabe 
66597f24f66STakanori Watanabe 		/* Wait for status valid bit. */
66697f24f66STakanori Watanabe 		if ((b & TPM_STS_VALID) && (sc->sc_capabilities &
66797f24f66STakanori Watanabe 		    TPM_INTF_STS_VALID_INT)) {
66897f24f66STakanori Watanabe 			rv = tpm_waitfor_int(sc, b, tmo, c, TPM_STS_VALID_INT);
66997f24f66STakanori Watanabe 			if (rv != 0)
67097f24f66STakanori Watanabe 				return rv;
67197f24f66STakanori Watanabe 			else
67297f24f66STakanori Watanabe 				b = b0 & ~TPM_STS_VALID;
67397f24f66STakanori Watanabe 		}
67497f24f66STakanori Watanabe 
67597f24f66STakanori Watanabe 		/*
67697f24f66STakanori Watanabe 		 * When all flags are taken care of, return.  Otherwise
67797f24f66STakanori Watanabe 		 * use polling for eg. TPM_STS_CMD_READY.
67897f24f66STakanori Watanabe 		 */
67997f24f66STakanori Watanabe 		if (b == 0)
68097f24f66STakanori Watanabe 			return 0;
68197f24f66STakanori Watanabe 	}
68297f24f66STakanori Watanabe 
68397f24f66STakanori Watanabe 	re = 3;
68497f24f66STakanori Watanabe restart:
68597f24f66STakanori Watanabe 	/*
68697f24f66STakanori Watanabe 	 * If requested wait for TPM_STS_VALID before dealing with
68797f24f66STakanori Watanabe 	 * any other flag.  Eg. when both TPM_STS_DATA_AVAIL and TPM_STS_VALID
68897f24f66STakanori Watanabe 	 * are requested, wait for the latter first.
68997f24f66STakanori Watanabe 	 */
69097f24f66STakanori Watanabe 	b = b0;
69197f24f66STakanori Watanabe 	if (b0 & TPM_STS_VALID)
69297f24f66STakanori Watanabe 		b = TPM_STS_VALID;
69397f24f66STakanori Watanabe 
69497f24f66STakanori Watanabe 	to = tpm_tmotohz(tmo);
69597f24f66STakanori Watanabe again:
69697f24f66STakanori Watanabe 	if ((rv = tpm_waitfor_poll(sc, b, to, c)) != 0)
69797f24f66STakanori Watanabe 		return rv;
69897f24f66STakanori Watanabe 
69997f24f66STakanori Watanabe 	if ((b & sc->sc_stat) == TPM_STS_VALID) {
70097f24f66STakanori Watanabe 		/* Now wait for other flags. */
70197f24f66STakanori Watanabe 		b = b0 & ~TPM_STS_VALID;
70297f24f66STakanori Watanabe 		to++;
70397f24f66STakanori Watanabe 		goto again;
70497f24f66STakanori Watanabe 	}
70597f24f66STakanori Watanabe 
70697f24f66STakanori Watanabe 	if ((sc->sc_stat & b) != b) {
70797f24f66STakanori Watanabe #ifdef TPM_DEBUG
70897f24f66STakanori Watanabe 		printf("tpm_waitfor: timeout: stat=%b b=%b\n",
70997f24f66STakanori Watanabe 		    sc->sc_stat, TPM_STS_BITS, b, TPM_STS_BITS);
71097f24f66STakanori Watanabe #endif
71197f24f66STakanori Watanabe 		if (re-- && (b0 & TPM_STS_VALID)) {
71297f24f66STakanori Watanabe 			bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
71397f24f66STakanori Watanabe 			    TPM_STS_RESP_RETRY);
71497f24f66STakanori Watanabe 			goto restart;
71597f24f66STakanori Watanabe 		}
71697f24f66STakanori Watanabe 		return EIO;
71797f24f66STakanori Watanabe 	}
71897f24f66STakanori Watanabe 
71997f24f66STakanori Watanabe 	return 0;
72097f24f66STakanori Watanabe }
72197f24f66STakanori Watanabe 
72297f24f66STakanori Watanabe /* Start transaction. */
72397f24f66STakanori Watanabe int
tpm_tis12_start(struct tpm_softc * sc,int flag)72497f24f66STakanori Watanabe tpm_tis12_start(struct tpm_softc *sc, int flag)
72597f24f66STakanori Watanabe {
72697f24f66STakanori Watanabe 	int rv;
72797f24f66STakanori Watanabe 
72897f24f66STakanori Watanabe 	if (flag == UIO_READ) {
72997f24f66STakanori Watanabe 		rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
73097f24f66STakanori Watanabe 		    TPM_READ_TMO, sc->sc_read);
73197f24f66STakanori Watanabe 		return rv;
73297f24f66STakanori Watanabe 	}
73397f24f66STakanori Watanabe 
73497f24f66STakanori Watanabe 	/* Own our (0th) locality. */
73597f24f66STakanori Watanabe 	if ((rv = tpm_request_locality(sc, 0)) != 0)
73697f24f66STakanori Watanabe 		return rv;
73797f24f66STakanori Watanabe 
73897f24f66STakanori Watanabe 	sc->sc_stat = tpm_status(sc);
73997f24f66STakanori Watanabe 	if (sc->sc_stat & TPM_STS_CMD_READY) {
74097f24f66STakanori Watanabe #ifdef TPM_DEBUG
74197f24f66STakanori Watanabe 		printf("tpm_tis12_start: UIO_WRITE status %b\n", sc->sc_stat,
74297f24f66STakanori Watanabe 		   TPM_STS_BITS);
74397f24f66STakanori Watanabe #endif
74497f24f66STakanori Watanabe 		return 0;
74597f24f66STakanori Watanabe 	}
74697f24f66STakanori Watanabe 
74797f24f66STakanori Watanabe #ifdef TPM_DEBUG
74897f24f66STakanori Watanabe 	printf("tpm_tis12_start: UIO_WRITE readying chip\n");
74997f24f66STakanori Watanabe #endif
75097f24f66STakanori Watanabe 
75197f24f66STakanori Watanabe 	/* Abort previous and restart. */
75297f24f66STakanori Watanabe 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY);
75397f24f66STakanori Watanabe 	if ((rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READY_TMO,
75497f24f66STakanori Watanabe 	    sc->sc_write))) {
75597f24f66STakanori Watanabe #ifdef TPM_DEBUG
75697f24f66STakanori Watanabe 		printf("tpm_tis12_start: UIO_WRITE readying failed %d\n", rv);
75797f24f66STakanori Watanabe #endif
75897f24f66STakanori Watanabe 		return rv;
75997f24f66STakanori Watanabe 	}
76097f24f66STakanori Watanabe 
76197f24f66STakanori Watanabe #ifdef TPM_DEBUG
76297f24f66STakanori Watanabe 	printf("tpm_tis12_start: UIO_WRITE readying done\n");
76397f24f66STakanori Watanabe #endif
76497f24f66STakanori Watanabe 
76597f24f66STakanori Watanabe 	return 0;
76697f24f66STakanori Watanabe }
76797f24f66STakanori Watanabe 
76897f24f66STakanori Watanabe int
tpm_tis12_read(struct tpm_softc * sc,void * buf,int len,size_t * count,int flags)76997f24f66STakanori Watanabe tpm_tis12_read(struct tpm_softc *sc, void *buf, int len, size_t *count,
77097f24f66STakanori Watanabe     int flags)
77197f24f66STakanori Watanabe {
77297f24f66STakanori Watanabe 	u_int8_t *p = buf;
77397f24f66STakanori Watanabe 	size_t cnt;
77497f24f66STakanori Watanabe 	int rv, n, bcnt;
77597f24f66STakanori Watanabe 
77697f24f66STakanori Watanabe #ifdef TPM_DEBUG
77797f24f66STakanori Watanabe 	printf("tpm_tis12_read: len %d\n", len);
77897f24f66STakanori Watanabe #endif
77997f24f66STakanori Watanabe 	cnt = 0;
78097f24f66STakanori Watanabe 	while (len > 0) {
78197f24f66STakanori Watanabe 		if ((rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
78297f24f66STakanori Watanabe 		    TPM_READ_TMO, sc->sc_read)))
78397f24f66STakanori Watanabe 			return rv;
78497f24f66STakanori Watanabe 
78597f24f66STakanori Watanabe 		bcnt = tpm_getburst(sc);
78697f24f66STakanori Watanabe 		n = MIN(len, bcnt);
78797f24f66STakanori Watanabe #ifdef TPM_DEBUG
78897f24f66STakanori Watanabe 		printf("tpm_tis12_read: fetching %d, burst is %d\n", n, bcnt);
78997f24f66STakanori Watanabe #endif
79097f24f66STakanori Watanabe 		for (; n--; len--) {
79197f24f66STakanori Watanabe 			*p++ = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_DATA);
79297f24f66STakanori Watanabe 			cnt++;
79397f24f66STakanori Watanabe 		}
79497f24f66STakanori Watanabe 
79597f24f66STakanori Watanabe 		if ((flags & TPM_PARAM_SIZE) == 0 && cnt >= 6)
79697f24f66STakanori Watanabe 			break;
79797f24f66STakanori Watanabe 	}
79897f24f66STakanori Watanabe #ifdef TPM_DEBUG
79997f24f66STakanori Watanabe 	printf("tpm_tis12_read: read %zd bytes, len %d\n", cnt, len);
80097f24f66STakanori Watanabe #endif
80197f24f66STakanori Watanabe 
80297f24f66STakanori Watanabe 	if (count)
80397f24f66STakanori Watanabe 		*count = cnt;
80497f24f66STakanori Watanabe 
80597f24f66STakanori Watanabe 	return 0;
80697f24f66STakanori Watanabe }
80797f24f66STakanori Watanabe 
80897f24f66STakanori Watanabe int
tpm_tis12_write(struct tpm_softc * sc,void * buf,int len)80997f24f66STakanori Watanabe tpm_tis12_write(struct tpm_softc *sc, void *buf, int len)
81097f24f66STakanori Watanabe {
81197f24f66STakanori Watanabe 	u_int8_t *p = buf;
81297f24f66STakanori Watanabe 	size_t cnt;
81397f24f66STakanori Watanabe 	int rv, r;
81497f24f66STakanori Watanabe 
81597f24f66STakanori Watanabe #ifdef TPM_DEBUG
81697f24f66STakanori Watanabe 	printf("tpm_tis12_write: sc %p buf %p len %d\n", sc, buf, len);
81797f24f66STakanori Watanabe #endif
81897f24f66STakanori Watanabe 
81997f24f66STakanori Watanabe 	if ((rv = tpm_request_locality(sc, 0)) != 0)
82097f24f66STakanori Watanabe 		return rv;
82197f24f66STakanori Watanabe 
82297f24f66STakanori Watanabe 	cnt = 0;
82397f24f66STakanori Watanabe 	while (cnt < len - 1) {
82497f24f66STakanori Watanabe 		for (r = tpm_getburst(sc); r > 0 && cnt < len - 1; r--) {
82597f24f66STakanori Watanabe 			bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++);
82697f24f66STakanori Watanabe 			cnt++;
82797f24f66STakanori Watanabe 		}
82897f24f66STakanori Watanabe 		if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) {
82997f24f66STakanori Watanabe #ifdef TPM_DEBUG
83097f24f66STakanori Watanabe 			printf("tpm_tis12_write: failed burst rv %d\n", rv);
83197f24f66STakanori Watanabe #endif
83297f24f66STakanori Watanabe 			return rv;
83397f24f66STakanori Watanabe 		}
83497f24f66STakanori Watanabe 		sc->sc_stat = tpm_status(sc);
83597f24f66STakanori Watanabe 		if (!(sc->sc_stat & TPM_STS_DATA_EXPECT)) {
83697f24f66STakanori Watanabe #ifdef TPM_DEBUG
83797f24f66STakanori Watanabe 			printf("tpm_tis12_write: failed rv %d stat=%b\n", rv,
83897f24f66STakanori Watanabe 			    sc->sc_stat, TPM_STS_BITS);
83997f24f66STakanori Watanabe #endif
84097f24f66STakanori Watanabe 			return EIO;
84197f24f66STakanori Watanabe 		}
84297f24f66STakanori Watanabe 	}
84397f24f66STakanori Watanabe 
84497f24f66STakanori Watanabe 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++);
84597f24f66STakanori Watanabe 	cnt++;
84697f24f66STakanori Watanabe 
84797f24f66STakanori Watanabe 	if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) {
84897f24f66STakanori Watanabe #ifdef TPM_DEBUG
84997f24f66STakanori Watanabe 		printf("tpm_tis12_write: failed last byte rv %d\n", rv);
85097f24f66STakanori Watanabe #endif
85197f24f66STakanori Watanabe 		return rv;
85297f24f66STakanori Watanabe 	}
85397f24f66STakanori Watanabe 	if ((sc->sc_stat & TPM_STS_DATA_EXPECT) != 0) {
85497f24f66STakanori Watanabe #ifdef TPM_DEBUG
85597f24f66STakanori Watanabe 		printf("tpm_tis12_write: failed rv %d stat=%b\n", rv,
85697f24f66STakanori Watanabe 		    sc->sc_stat, TPM_STS_BITS);
85797f24f66STakanori Watanabe #endif
85897f24f66STakanori Watanabe 		return EIO;
85997f24f66STakanori Watanabe 	}
86097f24f66STakanori Watanabe 
86197f24f66STakanori Watanabe #ifdef TPM_DEBUG
86297f24f66STakanori Watanabe 	printf("tpm_tis12_write: wrote %d byte\n", cnt);
86397f24f66STakanori Watanabe #endif
86497f24f66STakanori Watanabe 
86597f24f66STakanori Watanabe 	return 0;
86697f24f66STakanori Watanabe }
86797f24f66STakanori Watanabe 
86897f24f66STakanori Watanabe /* Finish transaction. */
86997f24f66STakanori Watanabe int
tpm_tis12_end(struct tpm_softc * sc,int flag,int err)87097f24f66STakanori Watanabe tpm_tis12_end(struct tpm_softc *sc, int flag, int err)
87197f24f66STakanori Watanabe {
87297f24f66STakanori Watanabe 	int rv = 0;
87397f24f66STakanori Watanabe 
87497f24f66STakanori Watanabe 	if (flag == UIO_READ) {
87597f24f66STakanori Watanabe 		if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO,
87697f24f66STakanori Watanabe 		    sc->sc_read)))
87797f24f66STakanori Watanabe 			return rv;
87897f24f66STakanori Watanabe 
87997f24f66STakanori Watanabe 		/* Still more data? */
88097f24f66STakanori Watanabe 		sc->sc_stat = tpm_status(sc);
88197f24f66STakanori Watanabe 		if (!err && ((sc->sc_stat & TPM_STS_DATA_AVAIL) == TPM_STS_DATA_AVAIL)) {
88297f24f66STakanori Watanabe #ifdef TPM_DEBUG
88397f24f66STakanori Watanabe 			printf("tpm_tis12_end: read failed stat=%b\n",
88497f24f66STakanori Watanabe 			    sc->sc_stat, TPM_STS_BITS);
88597f24f66STakanori Watanabe #endif
88697f24f66STakanori Watanabe 			rv = EIO;
88797f24f66STakanori Watanabe 		}
88897f24f66STakanori Watanabe 
88997f24f66STakanori Watanabe 		bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
89097f24f66STakanori Watanabe 		    TPM_STS_CMD_READY);
89197f24f66STakanori Watanabe 
89297f24f66STakanori Watanabe 		/* Release our (0th) locality. */
89397f24f66STakanori Watanabe 		bus_space_write_1(sc->sc_bt, sc->sc_bh,TPM_ACCESS,
89497f24f66STakanori Watanabe 		    TPM_ACCESS_ACTIVE_LOCALITY);
89597f24f66STakanori Watanabe 	} else {
89697f24f66STakanori Watanabe 		/* Hungry for more? */
89797f24f66STakanori Watanabe 		sc->sc_stat = tpm_status(sc);
89897f24f66STakanori Watanabe 		if (!err && (sc->sc_stat & TPM_STS_DATA_EXPECT)) {
89997f24f66STakanori Watanabe #ifdef TPM_DEBUG
90097f24f66STakanori Watanabe 			printf("tpm_tis12_end: write failed stat=%b\n",
90197f24f66STakanori Watanabe 			    sc->sc_stat, TPM_STS_BITS);
90297f24f66STakanori Watanabe #endif
90397f24f66STakanori Watanabe 			rv = EIO;
90497f24f66STakanori Watanabe 		}
90597f24f66STakanori Watanabe 
90697f24f66STakanori Watanabe 		bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
90797f24f66STakanori Watanabe 		    err ? TPM_STS_CMD_READY : TPM_STS_GO);
90897f24f66STakanori Watanabe 	}
90997f24f66STakanori Watanabe 
91097f24f66STakanori Watanabe 	return rv;
91197f24f66STakanori Watanabe }
91297f24f66STakanori Watanabe 
91397f24f66STakanori Watanabe void
tpm_intr(void * v)91497f24f66STakanori Watanabe tpm_intr(void *v)
91597f24f66STakanori Watanabe {
91697f24f66STakanori Watanabe 	struct tpm_softc *sc = v;
91797f24f66STakanori Watanabe 	u_int32_t r;
91897f24f66STakanori Watanabe #ifdef TPM_DEBUG
91997f24f66STakanori Watanabe 	static int cnt = 0;
92097f24f66STakanori Watanabe #endif
92197f24f66STakanori Watanabe 
92297f24f66STakanori Watanabe 	r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS);
92397f24f66STakanori Watanabe #ifdef TPM_DEBUG
92497f24f66STakanori Watanabe 	if (r != 0)
92597f24f66STakanori Watanabe 		printf("tpm_intr: int=%b (%d)\n", r, TPM_INTERRUPT_ENABLE_BITS,
92697f24f66STakanori Watanabe 		    cnt);
92797f24f66STakanori Watanabe 	else
92897f24f66STakanori Watanabe 		cnt++;
92997f24f66STakanori Watanabe #endif
93097f24f66STakanori Watanabe 	if (!(r & (TPM_CMD_READY_INT | TPM_LOCALITY_CHANGE_INT |
93197f24f66STakanori Watanabe 	    TPM_STS_VALID_INT | TPM_DATA_AVAIL_INT)))
93297f24f66STakanori Watanabe 		return;
93397f24f66STakanori Watanabe 	if (r & TPM_STS_VALID_INT)
93497f24f66STakanori Watanabe 		wakeup(sc);
93597f24f66STakanori Watanabe 
93697f24f66STakanori Watanabe 	if (r & TPM_CMD_READY_INT)
93797f24f66STakanori Watanabe 		wakeup(sc->sc_write);
93897f24f66STakanori Watanabe 
93997f24f66STakanori Watanabe 	if (r & TPM_DATA_AVAIL_INT)
94097f24f66STakanori Watanabe 		wakeup(sc->sc_read);
94197f24f66STakanori Watanabe 
94297f24f66STakanori Watanabe 	if (r & TPM_LOCALITY_CHANGE_INT)
94397f24f66STakanori Watanabe 		wakeup(sc->sc_init);
94497f24f66STakanori Watanabe 
94597f24f66STakanori Watanabe 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS, r);
94697f24f66STakanori Watanabe 
94797f24f66STakanori Watanabe 	return;
94897f24f66STakanori Watanabe }
94997f24f66STakanori Watanabe 
95097f24f66STakanori Watanabe /* Read single byte using legacy interface. */
95197f24f66STakanori Watanabe static inline u_int8_t
tpm_legacy_in(bus_space_tag_t iot,bus_space_handle_t ioh,int reg)95297f24f66STakanori Watanabe tpm_legacy_in(bus_space_tag_t iot, bus_space_handle_t ioh, int reg)
95397f24f66STakanori Watanabe {
95497f24f66STakanori Watanabe 	bus_space_write_1(iot, ioh, 0, reg);
95597f24f66STakanori Watanabe 	return bus_space_read_1(iot, ioh, 1);
95697f24f66STakanori Watanabe }
95797f24f66STakanori Watanabe 
95829deb225SDimitry Andric #if 0
95997f24f66STakanori Watanabe /* Write single byte using legacy interface. */
96097f24f66STakanori Watanabe static inline void
96197f24f66STakanori Watanabe tpm_legacy_out(bus_space_tag_t iot, bus_space_handle_t ioh, int reg, u_int8_t v)
96297f24f66STakanori Watanabe {
96397f24f66STakanori Watanabe 	bus_space_write_1(iot, ioh, 0, reg);
96497f24f66STakanori Watanabe 	bus_space_write_1(iot, ioh, 1, v);
96597f24f66STakanori Watanabe }
96629deb225SDimitry Andric #endif
96797f24f66STakanori Watanabe 
96897f24f66STakanori Watanabe /* Probe for TPM using legacy interface. */
96997f24f66STakanori Watanabe int
tpm_legacy_probe(bus_space_tag_t iot,bus_addr_t iobase)97097f24f66STakanori Watanabe tpm_legacy_probe(bus_space_tag_t iot, bus_addr_t iobase)
97197f24f66STakanori Watanabe {
97297f24f66STakanori Watanabe 	bus_space_handle_t ioh;
97397f24f66STakanori Watanabe 	u_int8_t r, v;
97497f24f66STakanori Watanabe 	int i, rv = 0;
97597f24f66STakanori Watanabe 	char id[8];
97697f24f66STakanori Watanabe 
97797f24f66STakanori Watanabe 	if (!tpm_enabled || iobase == -1)
97897f24f66STakanori Watanabe 		return 0;
97997f24f66STakanori Watanabe 
98097f24f66STakanori Watanabe 	if (bus_space_map(iot, iobase, 2, 0, &ioh))
98197f24f66STakanori Watanabe 		return 0;
98297f24f66STakanori Watanabe 
98397f24f66STakanori Watanabe 	v = bus_space_read_1(iot, ioh, 0);
98497f24f66STakanori Watanabe 	if (v == 0xff) {
98597f24f66STakanori Watanabe 		bus_space_unmap(iot, ioh, 2);
98697f24f66STakanori Watanabe 		return 0;
98797f24f66STakanori Watanabe 	}
98897f24f66STakanori Watanabe 	r = bus_space_read_1(iot, ioh, 1);
98997f24f66STakanori Watanabe 
99097f24f66STakanori Watanabe 	for (i = sizeof(id); i--; )
99197f24f66STakanori Watanabe 		id[i] = tpm_legacy_in(iot, ioh, TPM_ID + i);
99297f24f66STakanori Watanabe 
99397f24f66STakanori Watanabe #ifdef TPM_DEBUG
99497f24f66STakanori Watanabe 	printf("tpm_legacy_probe %.4s %d.%d.%d.%d\n",
99597f24f66STakanori Watanabe 	    &id[4], id[0], id[1], id[2], id[3]);
99697f24f66STakanori Watanabe #endif
99797f24f66STakanori Watanabe 	/*
99897f24f66STakanori Watanabe 	 * The only chips using the legacy interface we are aware of are
99997f24f66STakanori Watanabe 	 * by Atmel.  For other chips more signature would have to be added.
100097f24f66STakanori Watanabe 	 */
100197f24f66STakanori Watanabe 	if (!bcmp(&id[4], "ATML", 4))
100297f24f66STakanori Watanabe 		rv = 1;
100397f24f66STakanori Watanabe 
100497f24f66STakanori Watanabe 	if (!rv) {
100597f24f66STakanori Watanabe 		bus_space_write_1(iot, ioh, r, 1);
100697f24f66STakanori Watanabe 		bus_space_write_1(iot, ioh, v, 0);
100797f24f66STakanori Watanabe 	}
100897f24f66STakanori Watanabe 	bus_space_unmap(iot, ioh, 2);
100997f24f66STakanori Watanabe 
101097f24f66STakanori Watanabe 	return rv;
101197f24f66STakanori Watanabe }
101297f24f66STakanori Watanabe 
101397f24f66STakanori Watanabe /* Setup TPM using legacy interface. */
101497f24f66STakanori Watanabe int
tpm_legacy_init(struct tpm_softc * sc,int irq,const char * name)101597f24f66STakanori Watanabe tpm_legacy_init(struct tpm_softc *sc, int irq, const char *name)
101697f24f66STakanori Watanabe {
101797f24f66STakanori Watanabe 	char id[8];
101897f24f66STakanori Watanabe 	int i;
101997f24f66STakanori Watanabe 
102097f24f66STakanori Watanabe 	if ((i = bus_space_map(sc->sc_batm, tpm_enabled, 2, 0, &sc->sc_bahm))) {
102197f24f66STakanori Watanabe 		printf(": cannot map tpm registers (%d)\n", i);
102297f24f66STakanori Watanabe 		tpm_enabled = 0;
102397f24f66STakanori Watanabe 		return 1;
102497f24f66STakanori Watanabe 	}
102597f24f66STakanori Watanabe 
102697f24f66STakanori Watanabe 	for (i = sizeof(id); i--; )
102797f24f66STakanori Watanabe 		id[i] = tpm_legacy_in(sc->sc_bt, sc->sc_bh, TPM_ID + i);
102897f24f66STakanori Watanabe 
102997f24f66STakanori Watanabe 	printf(": %.4s %d.%d @0x%x\n", &id[4], id[0], id[1], tpm_enabled);
103097f24f66STakanori Watanabe 	tpm_enabled = 0;
103197f24f66STakanori Watanabe 
103297f24f66STakanori Watanabe 	return 0;
103397f24f66STakanori Watanabe }
103497f24f66STakanori Watanabe 
103597f24f66STakanori Watanabe /* Start transaction. */
103697f24f66STakanori Watanabe int
tpm_legacy_start(struct tpm_softc * sc,int flag)103797f24f66STakanori Watanabe tpm_legacy_start(struct tpm_softc *sc, int flag)
103897f24f66STakanori Watanabe {
103997f24f66STakanori Watanabe 	struct timeval tv;
104097f24f66STakanori Watanabe 	u_int8_t bits, r;
104197f24f66STakanori Watanabe 	int to, rv;
104297f24f66STakanori Watanabe 
104397f24f66STakanori Watanabe 	bits = flag == UIO_READ ? TPM_LEGACY_DA : 0;
104497f24f66STakanori Watanabe 	tv.tv_sec = TPM_LEGACY_TMO;
104597f24f66STakanori Watanabe 	tv.tv_usec = 0;
104697f24f66STakanori Watanabe 	to = tvtohz(&tv) / TPM_LEGACY_SLEEP;
104797f24f66STakanori Watanabe 	while (((r = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1)) &
104897f24f66STakanori Watanabe 	    (TPM_LEGACY_BUSY|bits)) != bits && to--) {
104997f24f66STakanori Watanabe 		rv = tsleep(sc, PRIBIO | PCATCH, "legacy_tpm_start",
105097f24f66STakanori Watanabe 		    TPM_LEGACY_SLEEP);
105197f24f66STakanori Watanabe 		if (rv && rv != EWOULDBLOCK)
105297f24f66STakanori Watanabe 			return rv;
105397f24f66STakanori Watanabe 	}
105497f24f66STakanori Watanabe 
105597f24f66STakanori Watanabe 	if ((r & (TPM_LEGACY_BUSY|bits)) != bits)
105697f24f66STakanori Watanabe 		return EIO;
105797f24f66STakanori Watanabe 
105897f24f66STakanori Watanabe 	return 0;
105997f24f66STakanori Watanabe }
106097f24f66STakanori Watanabe 
106197f24f66STakanori Watanabe int
tpm_legacy_read(struct tpm_softc * sc,void * buf,int len,size_t * count,int flags)106297f24f66STakanori Watanabe tpm_legacy_read(struct tpm_softc *sc, void *buf, int len, size_t *count,
106397f24f66STakanori Watanabe     int flags)
106497f24f66STakanori Watanabe {
106597f24f66STakanori Watanabe 	u_int8_t *p;
106697f24f66STakanori Watanabe 	size_t cnt;
106797f24f66STakanori Watanabe 	int to, rv;
106897f24f66STakanori Watanabe 
106997f24f66STakanori Watanabe 	cnt = rv = 0;
107097f24f66STakanori Watanabe 	for (p = buf; !rv && len > 0; len--) {
107197f24f66STakanori Watanabe 		for (to = 1000;
107297f24f66STakanori Watanabe 		    !(bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1) &
107397f24f66STakanori Watanabe 		    TPM_LEGACY_DA); DELAY(1))
107497f24f66STakanori Watanabe 			if (!to--)
107597f24f66STakanori Watanabe 				return EIO;
107697f24f66STakanori Watanabe 
107797f24f66STakanori Watanabe 		DELAY(TPM_LEGACY_DELAY);
107897f24f66STakanori Watanabe 		*p++ = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 0);
107997f24f66STakanori Watanabe 		cnt++;
108097f24f66STakanori Watanabe 	}
108197f24f66STakanori Watanabe 
108297f24f66STakanori Watanabe 	*count = cnt;
108397f24f66STakanori Watanabe 	return 0;
108497f24f66STakanori Watanabe }
108597f24f66STakanori Watanabe 
108697f24f66STakanori Watanabe int
tpm_legacy_write(struct tpm_softc * sc,void * buf,int len)108797f24f66STakanori Watanabe tpm_legacy_write(struct tpm_softc *sc, void *buf, int len)
108897f24f66STakanori Watanabe {
108997f24f66STakanori Watanabe 	u_int8_t *p;
109097f24f66STakanori Watanabe 	int n;
109197f24f66STakanori Watanabe 
109297f24f66STakanori Watanabe 	for (p = buf, n = len; n--; DELAY(TPM_LEGACY_DELAY)) {
109397f24f66STakanori Watanabe 		if (!n && len != TPM_BUFSIZ) {
109497f24f66STakanori Watanabe 			bus_space_write_1(sc->sc_batm, sc->sc_bahm, 1,
109597f24f66STakanori Watanabe 			    TPM_LEGACY_LAST);
109697f24f66STakanori Watanabe 			DELAY(TPM_LEGACY_DELAY);
109797f24f66STakanori Watanabe 		}
109897f24f66STakanori Watanabe 		bus_space_write_1(sc->sc_batm, sc->sc_bahm, 0, *p++);
109997f24f66STakanori Watanabe 	}
110097f24f66STakanori Watanabe 
110197f24f66STakanori Watanabe 	return 0;
110297f24f66STakanori Watanabe }
110397f24f66STakanori Watanabe 
110497f24f66STakanori Watanabe /* Finish transaction. */
110597f24f66STakanori Watanabe int
tpm_legacy_end(struct tpm_softc * sc,int flag,int rv)110697f24f66STakanori Watanabe tpm_legacy_end(struct tpm_softc *sc, int flag, int rv)
110797f24f66STakanori Watanabe {
110897f24f66STakanori Watanabe 	struct timeval tv;
110997f24f66STakanori Watanabe 	u_int8_t r;
111097f24f66STakanori Watanabe 	int to;
111197f24f66STakanori Watanabe 
111297f24f66STakanori Watanabe 	if (rv || flag == UIO_READ)
111397f24f66STakanori Watanabe 		bus_space_write_1(sc->sc_batm, sc->sc_bahm, 1, TPM_LEGACY_ABRT);
111497f24f66STakanori Watanabe 	else {
111597f24f66STakanori Watanabe 		tv.tv_sec = TPM_LEGACY_TMO;
111697f24f66STakanori Watanabe 		tv.tv_usec = 0;
111797f24f66STakanori Watanabe 		to = tvtohz(&tv) / TPM_LEGACY_SLEEP;
111897f24f66STakanori Watanabe 		while(((r = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1)) &
111997f24f66STakanori Watanabe 		    TPM_LEGACY_BUSY) && to--) {
112097f24f66STakanori Watanabe 			rv = tsleep(sc, PRIBIO | PCATCH, "legacy_tpm_end",
112197f24f66STakanori Watanabe 			    TPM_LEGACY_SLEEP);
112297f24f66STakanori Watanabe 			if (rv && rv != EWOULDBLOCK)
112397f24f66STakanori Watanabe 				return rv;
112497f24f66STakanori Watanabe 		}
112597f24f66STakanori Watanabe 
112697f24f66STakanori Watanabe 		if (r & TPM_LEGACY_BUSY)
112797f24f66STakanori Watanabe 			return EIO;
112897f24f66STakanori Watanabe 
112997f24f66STakanori Watanabe 		if (r & TPM_LEGACY_RE)
113097f24f66STakanori Watanabe 			return EIO;	/* XXX Retry the loop? */
113197f24f66STakanori Watanabe 	}
113297f24f66STakanori Watanabe 
113397f24f66STakanori Watanabe 	return rv;
113497f24f66STakanori Watanabe }
113597f24f66STakanori Watanabe 
113697f24f66STakanori Watanabe int
tpmopen(struct cdev * dev,int flag,int mode,struct thread * td)113797f24f66STakanori Watanabe tpmopen(struct cdev *dev, int flag, int mode, struct thread *td)
113897f24f66STakanori Watanabe {
113997f24f66STakanori Watanabe 	struct tpm_softc *sc = TPMSOFTC(dev);
114097f24f66STakanori Watanabe 
114197f24f66STakanori Watanabe 	if (!sc)
114297f24f66STakanori Watanabe 		return ENXIO;
114397f24f66STakanori Watanabe 
114497f24f66STakanori Watanabe 	if (sc->sc_flags & TPM_OPEN)
114597f24f66STakanori Watanabe 		return EBUSY;
114697f24f66STakanori Watanabe 
114797f24f66STakanori Watanabe 	sc->sc_flags |= TPM_OPEN;
114897f24f66STakanori Watanabe 
114997f24f66STakanori Watanabe 	return 0;
115097f24f66STakanori Watanabe }
115197f24f66STakanori Watanabe 
115297f24f66STakanori Watanabe int
tpmclose(struct cdev * dev,int flag,int mode,struct thread * td)115397f24f66STakanori Watanabe tpmclose(struct cdev *dev, int flag, int mode, struct thread *td)
115497f24f66STakanori Watanabe {
115597f24f66STakanori Watanabe 	struct tpm_softc *sc = TPMSOFTC(dev);
115697f24f66STakanori Watanabe 
115797f24f66STakanori Watanabe 	if (!sc)
115897f24f66STakanori Watanabe 		return ENXIO;
115997f24f66STakanori Watanabe 
116097f24f66STakanori Watanabe 	if (!(sc->sc_flags & TPM_OPEN))
116197f24f66STakanori Watanabe 		return EINVAL;
116297f24f66STakanori Watanabe 
116397f24f66STakanori Watanabe 	sc->sc_flags &= ~TPM_OPEN;
116497f24f66STakanori Watanabe 
116597f24f66STakanori Watanabe 	return 0;
116697f24f66STakanori Watanabe }
116797f24f66STakanori Watanabe 
116897f24f66STakanori Watanabe int
tpmread(struct cdev * dev,struct uio * uio,int flags)116997f24f66STakanori Watanabe tpmread(struct cdev *dev, struct uio *uio, int flags)
117097f24f66STakanori Watanabe {
117197f24f66STakanori Watanabe 	struct tpm_softc *sc = TPMSOFTC(dev);
117297f24f66STakanori Watanabe 	u_int8_t buf[TPM_BUFSIZ], *p;
117397f24f66STakanori Watanabe 	size_t cnt;
117497f24f66STakanori Watanabe 	int n, len, rv, s;
117597f24f66STakanori Watanabe 
117697f24f66STakanori Watanabe 	if (!sc)
117797f24f66STakanori Watanabe 		return ENXIO;
117897f24f66STakanori Watanabe 
117997f24f66STakanori Watanabe 	s = spltty();
118097f24f66STakanori Watanabe 	if ((rv = (sc->sc_start)(sc, UIO_READ))) {
118197f24f66STakanori Watanabe 		splx(s);
118297f24f66STakanori Watanabe 		return rv;
118397f24f66STakanori Watanabe 	}
118497f24f66STakanori Watanabe 
118597f24f66STakanori Watanabe #ifdef TPM_DEBUG
118697f24f66STakanori Watanabe 	printf("tpmread: getting header\n");
118797f24f66STakanori Watanabe #endif
118897f24f66STakanori Watanabe 	if ((rv = (sc->sc_read)(sc, buf, TPM_HDRSIZE, &cnt, 0))) {
118997f24f66STakanori Watanabe 		(sc->sc_end)(sc, UIO_READ, rv);
119097f24f66STakanori Watanabe 		splx(s);
119197f24f66STakanori Watanabe 		return rv;
119297f24f66STakanori Watanabe 	}
119397f24f66STakanori Watanabe 
119497f24f66STakanori Watanabe 	len = (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | buf[5];
119597f24f66STakanori Watanabe #ifdef TPM_DEBUG
119697f24f66STakanori Watanabe 	printf("tpmread: len %d, io count %d\n", len, uio->uio_resid);
119797f24f66STakanori Watanabe #endif
119897f24f66STakanori Watanabe 	if (len > uio->uio_resid) {
119997f24f66STakanori Watanabe 		rv = EIO;
120097f24f66STakanori Watanabe 		(sc->sc_end)(sc, UIO_READ, rv);
120197f24f66STakanori Watanabe #ifdef TPM_DEBUG
120297f24f66STakanori Watanabe 		printf("tpmread: bad residual io count 0x%x\n", uio->uio_resid);
120397f24f66STakanori Watanabe #endif
120497f24f66STakanori Watanabe 		splx(s);
120597f24f66STakanori Watanabe 		return rv;
120697f24f66STakanori Watanabe 	}
120797f24f66STakanori Watanabe 
120897f24f66STakanori Watanabe 	/* Copy out header. */
120997f24f66STakanori Watanabe 	if ((rv = uiomove((caddr_t)buf, cnt, uio))) {
121097f24f66STakanori Watanabe 		(sc->sc_end)(sc, UIO_READ, rv);
121197f24f66STakanori Watanabe 		splx(s);
121297f24f66STakanori Watanabe 		return rv;
121397f24f66STakanori Watanabe 	}
121497f24f66STakanori Watanabe 
121597f24f66STakanori Watanabe 	/* Get remaining part of the answer (if anything is left). */
121697f24f66STakanori Watanabe 	for (len -= cnt, p = buf, n = sizeof(buf); len > 0; p = buf, len -= n,
121797f24f66STakanori Watanabe 	    n = sizeof(buf)) {
121897f24f66STakanori Watanabe 		n = MIN(n, len);
121997f24f66STakanori Watanabe #ifdef TPM_DEBUG
122097f24f66STakanori Watanabe 		printf("tpmread: n %d len %d\n", n, len);
122197f24f66STakanori Watanabe #endif
122297f24f66STakanori Watanabe 		if ((rv = (sc->sc_read)(sc, p, n, NULL, TPM_PARAM_SIZE))) {
122397f24f66STakanori Watanabe 			(sc->sc_end)(sc, UIO_READ, rv);
122497f24f66STakanori Watanabe 			splx(s);
122597f24f66STakanori Watanabe 			return rv;
122697f24f66STakanori Watanabe 		}
122797f24f66STakanori Watanabe 		p += n;
122897f24f66STakanori Watanabe 		if ((rv = uiomove((caddr_t)buf, p - buf, uio))) {
122997f24f66STakanori Watanabe 			(sc->sc_end)(sc, UIO_READ, rv);
123097f24f66STakanori Watanabe 			splx(s);
123197f24f66STakanori Watanabe 			return rv;
123297f24f66STakanori Watanabe 		}
123397f24f66STakanori Watanabe 	}
123497f24f66STakanori Watanabe 
123597f24f66STakanori Watanabe 	rv = (sc->sc_end)(sc, UIO_READ, rv);
123697f24f66STakanori Watanabe 	splx(s);
123797f24f66STakanori Watanabe 	return rv;
123897f24f66STakanori Watanabe }
123997f24f66STakanori Watanabe 
124097f24f66STakanori Watanabe int
tpmwrite(struct cdev * dev,struct uio * uio,int flags)124197f24f66STakanori Watanabe tpmwrite(struct cdev *dev, struct uio *uio, int flags)
124297f24f66STakanori Watanabe {
124397f24f66STakanori Watanabe 	struct tpm_softc *sc = TPMSOFTC(dev);
124497f24f66STakanori Watanabe 	u_int8_t buf[TPM_BUFSIZ];
124597f24f66STakanori Watanabe 	int n, rv, s;
124697f24f66STakanori Watanabe 
124797f24f66STakanori Watanabe 	if (!sc)
124897f24f66STakanori Watanabe 		return ENXIO;
124997f24f66STakanori Watanabe 
125097f24f66STakanori Watanabe 	s = spltty();
125197f24f66STakanori Watanabe 
125297f24f66STakanori Watanabe #ifdef TPM_DEBUG
125397f24f66STakanori Watanabe 	printf("tpmwrite: io count %d\n", uio->uio_resid);
125497f24f66STakanori Watanabe #endif
125597f24f66STakanori Watanabe 
125697f24f66STakanori Watanabe 	n = MIN(sizeof(buf), uio->uio_resid);
125797f24f66STakanori Watanabe 	if ((rv = uiomove((caddr_t)buf, n, uio))) {
125897f24f66STakanori Watanabe 		splx(s);
125997f24f66STakanori Watanabe 		return rv;
126097f24f66STakanori Watanabe 	}
126197f24f66STakanori Watanabe 
126297f24f66STakanori Watanabe 	if ((rv = (sc->sc_start)(sc, UIO_WRITE))) {
126397f24f66STakanori Watanabe 		splx(s);
126497f24f66STakanori Watanabe 		return rv;
126597f24f66STakanori Watanabe 	}
126697f24f66STakanori Watanabe 
126797f24f66STakanori Watanabe 	if ((rv = (sc->sc_write(sc, buf, n)))) {
126897f24f66STakanori Watanabe 		splx(s);
126997f24f66STakanori Watanabe 		return rv;
127097f24f66STakanori Watanabe 	}
127197f24f66STakanori Watanabe 
127297f24f66STakanori Watanabe 	rv = (sc->sc_end)(sc, UIO_WRITE, rv);
127397f24f66STakanori Watanabe 	splx(s);
127497f24f66STakanori Watanabe 	return rv;
127597f24f66STakanori Watanabe }
127697f24f66STakanori Watanabe 
127797f24f66STakanori Watanabe int
tpmioctl(struct cdev * dev,u_long cmd,caddr_t data,int flags,struct thread * td)127897f24f66STakanori Watanabe tpmioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags,
127997f24f66STakanori Watanabe     struct thread *td)
128097f24f66STakanori Watanabe {
128197f24f66STakanori Watanabe 	return ENOTTY;
128297f24f66STakanori Watanabe }
1283