xref: /openbsd-src/sys/dev/acpi/tpm.c (revision dd9a9f1cbfd60caba77b54def94748aa6d06a898)
1 /* $OpenBSD: tpm.c,v 1.2 2016/10/25 06:48:58 pirofti Exp $ */
2 
3 /*
4  * Minimal interface to Trusted Platform Module chips implementing the
5  * TPM Interface Spec 1.2, just enough to tell the TPM to save state before
6  * a system suspend.
7  *
8  * Copyright (c) 2008, 2009 Michael Shalayeff
9  * Copyright (c) 2009, 2010 Hans-Joerg Hoexer
10  * Copyright (c) 2016 joshua stein <jcs@openbsd.org>
11  * All rights reserved.
12  *
13  * Permission to use, copy, modify, and distribute this software for any
14  * purpose with or without fee is hereby granted, provided that the above
15  * copyright notice and this permission notice appear in all copies.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
18  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
20  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
22  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
23  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24  */
25 
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/device.h>
29 #include <sys/malloc.h>
30 
31 #include <machine/bus.h>
32 #include <machine/apmvar.h>
33 
34 #include <dev/acpi/acpireg.h>
35 #include <dev/acpi/acpivar.h>
36 #include <dev/acpi/acpidev.h>
37 #include <dev/acpi/amltypes.h>
38 #include <dev/acpi/dsdt.h>
39 
40 /* #define TPM_DEBUG */
41 
42 #ifdef TPM_DEBUG
43 #define DPRINTF(x) printf x
44 #else
45 #define DPRINTF(x)
46 #endif
47 
48 #define TPM_BUFSIZ			1024
49 #define TPM_HDRSIZE			10
50 #define TPM_PARAM_SIZE			0x0001
51 
52 #define TPM_ACCESS			0x0000	/* access register */
53 #define TPM_ACCESS_ESTABLISHMENT	0x01	/* establishment */
54 #define TPM_ACCESS_REQUEST_USE		0x02	/* request using locality */
55 #define TPM_ACCESS_REQUEST_PENDING	0x04	/* pending request */
56 #define TPM_ACCESS_SEIZE		0x08	/* request locality seize */
57 #define TPM_ACCESS_SEIZED		0x10	/* locality has been seized */
58 #define TPM_ACCESS_ACTIVE_LOCALITY	0x20	/* locality is active */
59 #define TPM_ACCESS_VALID		0x80	/* bits are valid */
60 #define TPM_ACCESS_BITS	\
61     "\020\01EST\02REQ\03PEND\04SEIZE\05SEIZED\06ACT\010VALID"
62 
63 #define TPM_INTERRUPT_ENABLE		0x0008
64 #define TPM_GLOBAL_INT_ENABLE		0x80000000 /* enable ints */
65 #define TPM_CMD_READY_INT		0x00000080 /* cmd ready enable */
66 #define TPM_INT_EDGE_FALLING		0x00000018
67 #define TPM_INT_EDGE_RISING		0x00000010
68 #define TPM_INT_LEVEL_LOW		0x00000008
69 #define TPM_INT_LEVEL_HIGH		0x00000000
70 #define TPM_LOCALITY_CHANGE_INT		0x00000004 /* locality change enable */
71 #define TPM_STS_VALID_INT		0x00000002 /* int on TPM_STS_VALID is set */
72 #define TPM_DATA_AVAIL_INT		0x00000001 /* int on TPM_STS_DATA_AVAIL is set */
73 #define TPM_INTERRUPT_ENABLE_BITS \
74     "\020\040ENA\010RDY\03LOCH\02STSV\01DRDY"
75 
76 #define TPM_INT_VECTOR			0x000c	/* 8 bit reg for 4 bit irq vector */
77 #define TPM_INT_STATUS			0x0010	/* bits are & 0x87 from TPM_INTERRUPT_ENABLE */
78 
79 #define TPM_INTF_CAPABILITIES		0x0014	/* capability register */
80 #define TPM_INTF_BURST_COUNT_STATIC	0x0100	/* TPM_STS_BMASK static */
81 #define TPM_INTF_CMD_READY_INT		0x0080	/* int on ready supported */
82 #define TPM_INTF_INT_EDGE_FALLING	0x0040	/* falling edge ints supported */
83 #define TPM_INTF_INT_EDGE_RISING	0x0020	/* rising edge ints supported */
84 #define TPM_INTF_INT_LEVEL_LOW		0x0010	/* level-low ints supported */
85 #define TPM_INTF_INT_LEVEL_HIGH		0x0008	/* level-high ints supported */
86 #define TPM_INTF_LOCALITY_CHANGE_INT	0x0004	/* locality-change int (mb 1) */
87 #define TPM_INTF_STS_VALID_INT		0x0002	/* TPM_STS_VALID int supported */
88 #define TPM_INTF_DATA_AVAIL_INT		0x0001	/* TPM_STS_DATA_AVAIL int supported (mb 1) */
89 #define TPM_CAPSREQ \
90   (TPM_INTF_DATA_AVAIL_INT|TPM_INTF_LOCALITY_CHANGE_INT|TPM_INTF_INT_LEVEL_LOW)
91 #define TPM_CAPBITS \
92   "\020\01IDRDY\02ISTSV\03ILOCH\04IHIGH\05ILOW\06IEDGE\07IFALL\010IRDY\011BCST"
93 
94 #define TPM_STS				0x0018	   /* status register */
95 #define TPM_STS_MASK			0x000000ff /* status bits */
96 #define TPM_STS_BMASK			0x00ffff00 /* ro io burst size */
97 #define TPM_STS_VALID			0x00000080 /* ro other bits are valid */
98 #define TPM_STS_CMD_READY		0x00000040 /* rw chip/signal ready */
99 #define TPM_STS_GO			0x00000020 /* wo start the command */
100 #define TPM_STS_DATA_AVAIL		0x00000010 /* ro data available */
101 #define TPM_STS_DATA_EXPECT		0x00000008 /* ro more data to be written */
102 #define TPM_STS_RESP_RETRY		0x00000002 /* wo resend the response */
103 #define TPM_STS_BITS	"\020\010VALID\07RDY\06GO\05DRDY\04EXPECT\02RETRY"
104 
105 #define TPM_DATA			0x0024
106 #define TPM_ID				0x0f00
107 #define TPM_REV				0x0f04
108 #define TPM_SIZE			0x5000	/* five pages of the above */
109 
110 #define TPM_ACCESS_TMO			2000	/* 2sec */
111 #define TPM_READY_TMO			2000	/* 2sec */
112 #define TPM_READ_TMO			120000	/* 2 minutes */
113 #define TPM_BURST_TMO			2000	/* 2sec */
114 
115 struct tpm_softc {
116 	struct device		sc_dev;
117 
118 	bus_space_tag_t		sc_bt;
119 	bus_space_handle_t	sc_bh;
120 
121 	struct acpi_softc	*sc_acpi;
122 	struct aml_node		*sc_devnode;
123 
124 	uint32_t		sc_devid;
125 	uint32_t		sc_rev;
126 
127 	int			sc_enabled;
128 };
129 
130 struct tpm_crs {
131 	int irq_int;
132 	uint8_t irq_flags;
133 	uint32_t addr_min;
134 	uint32_t addr_bas;
135 	uint32_t addr_len;
136 	uint16_t i2c_addr;
137 	struct aml_node *devnode;
138 	struct aml_node *gpio_int_node;
139 	uint16_t gpio_int_pin;
140 	uint16_t gpio_int_flags;
141 };
142 
143 const struct {
144 	uint32_t devid;
145 	char name[32];
146 } tpm_devs[] = {
147 	{ 0x000615d1, "Infineon SLD9630 1.1" },
148 	{ 0x000b15d1, "Infineon SLB9635 1.2" },
149 	{ 0x100214e4, "Broadcom BCM0102" },
150 	{ 0x00fe1050, "WEC WPCT200" },
151 	{ 0x687119fa, "SNS SSX35" },
152 	{ 0x2e4d5453, "STM ST19WP18" },
153 	{ 0x32021114, "Atmel 97SC3203" },
154 	{ 0x10408086, "Intel INTC0102" },
155 	{ 0, "" },
156 };
157 
158 int	tpm_match(struct device *, void *, void *);
159 void	tpm_attach(struct device *, struct device *, void *);
160 int	tpm_activate(struct device *, int);
161 int	tpm_parse_crs(int, union acpi_resource *, void *);
162 
163 int	tpm_probe(bus_space_tag_t, bus_space_handle_t);
164 int	tpm_init(struct tpm_softc *);
165 int	tpm_read(struct tpm_softc *, void *, int, size_t *, int);
166 int	tpm_write(struct tpm_softc *, void *, int);
167 int	tpm_suspend(struct tpm_softc *);
168 int	tpm_resume(struct tpm_softc *);
169 
170 int	tpm_waitfor(struct tpm_softc *, uint8_t, int);
171 int	tpm_request_locality(struct tpm_softc *, int);
172 void	tpm_release_locality(struct tpm_softc *);
173 int	tpm_getburst(struct tpm_softc *);
174 uint8_t	tpm_status(struct tpm_softc *);
175 int	tpm_tmotohz(int);
176 
177 struct cfattach tpm_ca = {
178 	sizeof(struct tpm_softc),
179 	tpm_match,
180 	tpm_attach,
181 	NULL,
182 	tpm_activate
183 };
184 
185 struct cfdriver tpm_cd = {
186 	NULL, "tpm", DV_DULL
187 };
188 
189 const char *tpm_hids[] = {
190 	"PNP0C31",
191 	"ATM1200",
192 	"IFX0102",
193 	"BCM0101",
194 	"BCM0102",
195 	"NSC1200",
196 	"ICO0102",
197 	0
198 };
199 
200 int
201 tpm_match(struct device *parent, void *match, void *aux)
202 {
203 	struct acpi_attach_args	*aa = aux;
204 	struct cfdata		*cf = match;
205 
206 	return (acpi_matchhids(aa, tpm_hids, cf->cf_driver->cd_name));
207 }
208 
209 void
210 tpm_attach(struct device *parent, struct device *self, void *aux)
211 {
212 	struct tpm_softc	*sc = (struct tpm_softc *)self;
213 	struct acpi_attach_args *aa = aux;
214 	struct tpm_crs	crs;
215 	struct aml_value	res;
216 	int64_t			st;
217 
218 	sc->sc_acpi = (struct acpi_softc *)parent;
219 	sc->sc_devnode = aa->aaa_node;
220 	sc->sc_enabled = 0;
221 
222 	printf(": %s", sc->sc_devnode->name);
223 
224 	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &st))
225 		st = STA_PRESENT | STA_ENABLED | STA_DEV_OK;
226 	if ((st & (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) !=
227 	    (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) {
228 		printf(", not enabled\n");
229 		return;
230 	}
231 
232 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) {
233 		printf(", no _CRS method\n");
234 		return;
235 	}
236 	if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
237 		printf(", invalid _CRS object (type %d len %d)\n",
238 		    res.type, res.length);
239 		aml_freevalue(&res);
240 		return;
241 	}
242 	memset(&crs, 0, sizeof(crs));
243 	crs.devnode = sc->sc_devnode;
244 	aml_parse_resource(&res, tpm_parse_crs, &crs);
245 	aml_freevalue(&res);
246 
247 	if (crs.addr_bas == 0) {
248 		printf(", can't find address\n");
249 		return;
250 	}
251 
252 	printf(" addr 0x%x/0x%x", crs.addr_bas, crs.addr_len);
253 
254 	sc->sc_bt = aa->aaa_memt;
255 	if (bus_space_map(sc->sc_bt, crs.addr_bas, crs.addr_len, 0,
256 	    &sc->sc_bh)) {
257 		printf(", failed mapping at 0x%x\n", crs.addr_bas);
258 		return;
259 	}
260 
261 	if (!tpm_probe(sc->sc_bt, sc->sc_bh)) {
262 		printf(", probe failed\n");
263 		return;
264 	}
265 
266 	if (tpm_init(sc) != 0) {
267 		printf(", init failed\n");
268 		return;
269 	}
270 
271 	sc->sc_enabled = 1;
272 }
273 
274 int
275 tpm_parse_crs(int crsidx, union acpi_resource *crs, void *arg)
276 {
277 	struct tpm_crs *sc_crs = arg;
278 
279 	switch (AML_CRSTYPE(crs)) {
280 	case LR_MEM32:
281 		sc_crs->addr_min = letoh32(crs->lr_m32._min);
282 		sc_crs->addr_len = letoh32(crs->lr_m32._len);
283 		break;
284 
285 	case LR_MEM32FIXED:
286 		sc_crs->addr_bas = letoh32(crs->lr_m32fixed._bas);
287 		sc_crs->addr_len = letoh32(crs->lr_m32fixed._len);
288 		break;
289 
290 	case SR_IOPORT:
291 	case SR_IRQ:
292 	case LR_EXTIRQ:
293 	case LR_GPIO:
294 		break;
295 
296 	default:
297 		DPRINTF(("%s: unknown resource type %d\n", __func__,
298 		    AML_CRSTYPE(crs)));
299 	}
300 
301 	return 0;
302 }
303 
304 int
305 tpm_activate(struct device *self, int act)
306 {
307 	struct tpm_softc	*sc = (struct tpm_softc *)self;
308 
309 	switch (act) {
310 	case DVACT_SUSPEND:
311 		if (!sc->sc_enabled) {
312 			DPRINTF(("%s: suspend, but not enabled\n",
313 			    sc->sc_dev.dv_xname));
314 			return 0;
315 		}
316 		tpm_suspend(sc);
317 		break;
318 
319 	case DVACT_WAKEUP:
320 		if (!sc->sc_enabled) {
321 			DPRINTF(("%s: wakeup, but not enabled\n",
322 			    sc->sc_dev.dv_xname));
323 			return 0;
324 		}
325 		tpm_resume(sc);
326 		break;
327 	}
328 
329 	return 0;
330 }
331 
332 int
333 tpm_suspend(struct tpm_softc *sc)
334 {
335 	uint8_t command[] = {
336 	    0, 0xc1,		/* TPM_TAG_RQU_COMMAND */
337 	    0, 0, 0, 10,	/* Length in bytes */
338 	    0, 0, 0, 0x98	/* TPM_ORD_SaveStates */
339 	};
340 
341 	DPRINTF(("%s: saving state preparing for suspend\n",
342 	    sc->sc_dev.dv_xname));
343 
344 	/*
345 	 * Tell the chip to save its state so the BIOS can then restore it upon
346 	 * resume.
347 	 */
348 	tpm_write(sc, &command, sizeof(command));
349 	tpm_read(sc, &command, sizeof(command), NULL, TPM_HDRSIZE);
350 
351 	return 0;
352 }
353 
354 int
355 tpm_resume(struct tpm_softc *sc)
356 {
357 	/*
358 	 * TODO: The BIOS should have restored the chip's state for us already,
359 	 * but we should tell the chip to do a self-test here (according to the
360 	 * Linux driver).
361 	 */
362 
363 	DPRINTF(("%s: resume\n", sc->sc_dev.dv_xname));
364 	return 0;
365 }
366 
367 int
368 tpm_probe(bus_space_tag_t bt, bus_space_handle_t bh)
369 {
370 	uint32_t r;
371 	int tries = 10000;
372 
373 	/* wait for chip to settle */
374 	while (tries--) {
375 		if (bus_space_read_1(bt, bh, TPM_ACCESS) & TPM_ACCESS_VALID)
376 			break;
377 		else if (!tries) {
378 			printf(": timed out waiting for validity\n");
379 			return 1;
380 		}
381 
382 		DELAY(10);
383 	}
384 
385 	r = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITIES);
386 	if (r == 0xffffffff)
387 		return 0;
388 
389 	return 1;
390 }
391 
392 int
393 tpm_init(struct tpm_softc *sc)
394 {
395 	uint32_t r, intmask;
396 	int i;
397 
398 	r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTF_CAPABILITIES);
399 	if ((r & TPM_CAPSREQ) != TPM_CAPSREQ ||
400 	    !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) {
401 		DPRINTF((": caps too low (caps=%b)\n", r, TPM_CAPBITS));
402 		return 0;
403 	}
404 
405 	/* ack and disable all interrupts, we'll be using polling only */
406 	intmask = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE);
407 	intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT |
408 	    TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT;
409 	intmask &= ~TPM_GLOBAL_INT_ENABLE;
410 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, intmask);
411 
412 	if (tpm_request_locality(sc, 0)) {
413 		printf(", requesting locality failed\n");
414 		return 1;
415 	}
416 
417 	sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID);
418 	sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV);
419 
420 	for (i = 0; tpm_devs[i].devid; i++)
421 		if (tpm_devs[i].devid == sc->sc_devid)
422 			break;
423 
424 	if (tpm_devs[i].devid)
425 		printf(": %s rev 0x%x\n", tpm_devs[i].name, sc->sc_rev);
426 	else
427 		printf(": device 0x%08x rev 0x%x\n", sc->sc_devid, sc->sc_rev);
428 
429 	return 0;
430 }
431 
432 int
433 tpm_request_locality(struct tpm_softc *sc, int l)
434 {
435 	uint32_t r;
436 	int to;
437 
438 	if (l != 0)
439 		return EINVAL;
440 
441 	if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
442 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) ==
443 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY))
444 		return 0;
445 
446 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
447 	    TPM_ACCESS_REQUEST_USE);
448 
449 	to = tpm_tmotohz(TPM_ACCESS_TMO);
450 
451 	while ((r = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
452 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
453 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) {
454 		DELAY(10);
455 	}
456 
457 	if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
458 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
459 		DPRINTF(("%s: %s: access %b\n", sc->sc_dev.dv_xname, __func__,
460 		    r, TPM_ACCESS_BITS));
461 		return EBUSY;
462 	}
463 
464 	return 0;
465 }
466 
467 void
468 tpm_release_locality(struct tpm_softc *sc)
469 {
470 	if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
471 	    (TPM_ACCESS_REQUEST_PENDING|TPM_ACCESS_VALID)) ==
472 	    (TPM_ACCESS_REQUEST_PENDING|TPM_ACCESS_VALID)) {
473 		DPRINTF(("%s: releasing locality\n", sc->sc_dev.dv_xname));
474 		bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
475 		    TPM_ACCESS_ACTIVE_LOCALITY);
476 	}
477 }
478 
479 int
480 tpm_getburst(struct tpm_softc *sc)
481 {
482 	int burst, burst2, to;
483 
484 	to = tpm_tmotohz(TPM_BURST_TMO);
485 
486 	burst = 0;
487 	while (burst == 0 && to--) {
488 		/*
489 		 * Burst count has to be read from bits 8 to 23 without
490 		 * touching any other bits, eg. the actual status bits 0 to 7.
491 		 */
492 		burst = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 1);
493 		DPRINTF(("%s: %s: read1(0x%x): 0x%x\n", sc->sc_dev.dv_xname,
494 		    __func__, TPM_STS + 1, burst));
495 		burst2 = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 2);
496 		DPRINTF(("%s: %s: read1(0x%x): 0x%x\n", sc->sc_dev.dv_xname,
497 		    __func__, TPM_STS + 2, burst2));
498 		burst |= burst2 << 8;
499 		if (burst)
500 			return burst;
501 
502 		DELAY(10);
503 	}
504 
505 	DPRINTF(("%s: getburst timed out\n", sc->sc_dev.dv_xname));
506 
507 	return 0;
508 }
509 
510 uint8_t
511 tpm_status(struct tpm_softc *sc)
512 {
513 	return bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS) & TPM_STS_MASK;
514 }
515 
516 int
517 tpm_tmotohz(int tmo)
518 {
519 	struct timeval tv;
520 
521 	tv.tv_sec = tmo / 1000;
522 	tv.tv_usec = 1000 * (tmo % 1000);
523 
524 	return tvtohz(&tv);
525 }
526 
527 int
528 tpm_waitfor(struct tpm_softc *sc, uint8_t mask, int tries)
529 {
530 	uint8_t status;
531 
532 	while (((status = tpm_status(sc)) & mask) != mask) {
533 		if (tries == 0) {
534 			DPRINTF(("%s: %s: timed out, status 0x%x != 0x%x\n",
535 			    sc->sc_dev.dv_xname, __func__, status, mask));
536 			return status;
537 		}
538 
539 		tries--;
540 		DELAY(1);
541 	}
542 
543 	return 0;
544 }
545 
546 int
547 tpm_read(struct tpm_softc *sc, void *buf, int len, size_t *count,
548     int flags)
549 {
550 	uint8_t *p = buf;
551 	uint8_t c;
552 	size_t cnt;
553 	int rv, n, bcnt;
554 
555 	DPRINTF(("%s: %s %d:", sc->sc_dev.dv_xname, __func__, len));
556 
557 	cnt = 0;
558 	while (len > 0) {
559 		if ((rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
560 		    TPM_READ_TMO)))
561 			return rv;
562 
563 		bcnt = tpm_getburst(sc);
564 		n = MIN(len, bcnt);
565 
566 		for (; n--; len--) {
567 			c = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_DATA);
568 			DPRINTF((" %02x", c));
569 			*p++ = c;
570 			cnt++;
571 		}
572 
573 		if ((flags & TPM_PARAM_SIZE) == 0 && cnt >= 6)
574 			break;
575 	}
576 
577 	DPRINTF(("\n"));
578 
579 	if (count)
580 		*count = cnt;
581 
582 	return 0;
583 }
584 
585 int
586 tpm_write(struct tpm_softc *sc, void *buf, int len)
587 {
588 	uint8_t *p = buf;
589 	uint8_t status;
590 	size_t count = 0;
591 	int rv, r;
592 
593 	if ((rv = tpm_request_locality(sc, 0)) != 0)
594 		return rv;
595 
596 	DPRINTF(("%s: %s %d:", sc->sc_dev.dv_xname, __func__, len));
597 	for (r = 0; r < len; r++)
598 		DPRINTF((" %02x", (uint8_t)(*(p + r))));
599 	DPRINTF(("\n"));
600 
601 	/* read status */
602 	status = tpm_status(sc);
603 	if ((status & TPM_STS_CMD_READY) == 0) {
604 		/* abort! */
605 		bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
606 		    TPM_STS_CMD_READY);
607 		if ((rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READ_TMO))) {
608 			DPRINTF(("%s: failed waiting for ready after abort "
609 			    "(0x%x)\n", sc->sc_dev.dv_xname, rv));
610 			return rv;
611 		}
612 	}
613 
614 	while (count < len - 1) {
615 		for (r = tpm_getburst(sc); r > 0 && count < len - 1; r--) {
616 			DPRINTF(("%s: %s: write1(0x%x, 0x%x)\n",
617 			    sc->sc_dev.dv_xname, __func__, TPM_DATA, *p));
618 			bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++);
619 			count++;
620 		}
621 		if ((rv = tpm_waitfor(sc, TPM_STS_VALID | TPM_STS_DATA_EXPECT,
622 		    TPM_READ_TMO))) {
623 			DPRINTF(("%s: %s: failed waiting for next byte (%d)\n",
624 			    sc->sc_dev.dv_xname, __func__, rv));
625 			return rv;
626 		}
627 	}
628 
629 	DPRINTF(("%s: %s: write1(0x%x, 0x%x)\n", sc->sc_dev.dv_xname, __func__,
630 	    TPM_DATA, *p));
631 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p);
632 	count++;
633 
634 	if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO))) {
635 		DPRINTF(("%s: %s: failed after last byte (%d)\n",
636 		    sc->sc_dev.dv_xname, __func__, rv));
637 		return rv;
638 	}
639 
640 	if ((status = tpm_status(sc)) & TPM_STS_DATA_EXPECT) {
641 		DPRINTF(("%s: %s: final status still expecting data: %b\n",
642 		    sc->sc_dev.dv_xname, __func__, status, TPM_STS_BITS));
643 		return status;
644 	}
645 
646 	DPRINTF(("%s: final status after write: %b\n", sc->sc_dev.dv_xname,
647 	    status, TPM_STS_BITS));
648 
649 	/* XXX: are we ever sending non-command data? */
650 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_GO);
651 
652 	return 0;
653 }
654