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