xref: /openbsd-src/sys/dev/acpi/tpm.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /* $OpenBSD: tpm.c,v 1.9 2019/05/15 21:28:21 tedu 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 	NULL
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 	printf("\n");
272 	sc->sc_enabled = 1;
273 }
274 
275 int
276 tpm_parse_crs(int crsidx, union acpi_resource *crs, void *arg)
277 {
278 	struct tpm_crs *sc_crs = arg;
279 
280 	switch (AML_CRSTYPE(crs)) {
281 	case LR_MEM32:
282 		sc_crs->addr_min = letoh32(crs->lr_m32._min);
283 		sc_crs->addr_len = letoh32(crs->lr_m32._len);
284 		break;
285 
286 	case LR_MEM32FIXED:
287 		sc_crs->addr_bas = letoh32(crs->lr_m32fixed._bas);
288 		sc_crs->addr_len = letoh32(crs->lr_m32fixed._len);
289 		break;
290 
291 	case SR_IOPORT:
292 	case SR_IRQ:
293 	case LR_EXTIRQ:
294 	case LR_GPIO:
295 		break;
296 
297 	default:
298 		DPRINTF(("%s: unknown resource type %d\n", __func__,
299 		    AML_CRSTYPE(crs)));
300 	}
301 
302 	return 0;
303 }
304 
305 int
306 tpm_activate(struct device *self, int act)
307 {
308 	struct tpm_softc	*sc = (struct tpm_softc *)self;
309 
310 	switch (act) {
311 	case DVACT_SUSPEND:
312 		if (!sc->sc_enabled) {
313 			DPRINTF(("%s: suspend, but not enabled\n",
314 			    sc->sc_dev.dv_xname));
315 			return 0;
316 		}
317 		tpm_suspend(sc);
318 		break;
319 
320 	case DVACT_WAKEUP:
321 		if (!sc->sc_enabled) {
322 			DPRINTF(("%s: wakeup, but not enabled\n",
323 			    sc->sc_dev.dv_xname));
324 			return 0;
325 		}
326 		tpm_resume(sc);
327 		break;
328 	}
329 
330 	return 0;
331 }
332 
333 int
334 tpm_suspend(struct tpm_softc *sc)
335 {
336 	uint8_t command[] = {
337 	    0, 0xc1,		/* TPM_TAG_RQU_COMMAND */
338 	    0, 0, 0, 10,	/* Length in bytes */
339 	    0, 0, 0, 0x98	/* TPM_ORD_SaveStates */
340 	};
341 
342 	DPRINTF(("%s: saving state preparing for suspend\n",
343 	    sc->sc_dev.dv_xname));
344 
345 	/*
346 	 * Tell the chip to save its state so the BIOS can then restore it upon
347 	 * resume.
348 	 */
349 	tpm_write(sc, &command, sizeof(command));
350 	tpm_read(sc, &command, sizeof(command), NULL, TPM_HDRSIZE);
351 
352 	return 0;
353 }
354 
355 int
356 tpm_resume(struct tpm_softc *sc)
357 {
358 	/*
359 	 * TODO: The BIOS should have restored the chip's state for us already,
360 	 * but we should tell the chip to do a self-test here (according to the
361 	 * Linux driver).
362 	 */
363 
364 	DPRINTF(("%s: resume\n", sc->sc_dev.dv_xname));
365 	return 0;
366 }
367 
368 int
369 tpm_probe(bus_space_tag_t bt, bus_space_handle_t bh)
370 {
371 	uint32_t r;
372 	int tries = 10000;
373 
374 	/* wait for chip to settle */
375 	while (tries--) {
376 		if (bus_space_read_1(bt, bh, TPM_ACCESS) & TPM_ACCESS_VALID)
377 			break;
378 		else if (!tries) {
379 			printf(": timed out waiting for validity\n");
380 			return 1;
381 		}
382 
383 		DELAY(10);
384 	}
385 
386 	r = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITIES);
387 	if (r == 0xffffffff)
388 		return 0;
389 
390 	return 1;
391 }
392 
393 int
394 tpm_init(struct tpm_softc *sc)
395 {
396 	uint32_t r, intmask;
397 	int i;
398 
399 	r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTF_CAPABILITIES);
400 	if ((r & TPM_CAPSREQ) != TPM_CAPSREQ ||
401 	    !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) {
402 		DPRINTF((": caps too low (caps=%b)\n", r, TPM_CAPBITS));
403 		return 0;
404 	}
405 
406 	/* ack and disable all interrupts, we'll be using polling only */
407 	intmask = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE);
408 	intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT |
409 	    TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT;
410 	intmask &= ~TPM_GLOBAL_INT_ENABLE;
411 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, intmask);
412 
413 	if (tpm_request_locality(sc, 0)) {
414 		printf(", requesting locality failed\n");
415 		return 1;
416 	}
417 
418 	sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID);
419 	sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV);
420 
421 	for (i = 0; tpm_devs[i].devid; i++)
422 		if (tpm_devs[i].devid == sc->sc_devid)
423 			break;
424 
425 	if (tpm_devs[i].devid)
426 		printf(", %s rev 0x%x", tpm_devs[i].name, sc->sc_rev);
427 	else
428 		printf(", device 0x%08x rev 0x%x", sc->sc_devid, sc->sc_rev);
429 
430 	return 0;
431 }
432 
433 int
434 tpm_request_locality(struct tpm_softc *sc, int l)
435 {
436 	uint32_t r;
437 	int to;
438 
439 	if (l != 0)
440 		return EINVAL;
441 
442 	if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
443 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) ==
444 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY))
445 		return 0;
446 
447 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
448 	    TPM_ACCESS_REQUEST_USE);
449 
450 	to = tpm_tmotohz(TPM_ACCESS_TMO);
451 
452 	while ((r = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
453 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
454 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) {
455 		DELAY(10);
456 	}
457 
458 	if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
459 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
460 		DPRINTF(("%s: %s: access %b\n", sc->sc_dev.dv_xname, __func__,
461 		    r, TPM_ACCESS_BITS));
462 		return EBUSY;
463 	}
464 
465 	return 0;
466 }
467 
468 void
469 tpm_release_locality(struct tpm_softc *sc)
470 {
471 	if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
472 	    (TPM_ACCESS_REQUEST_PENDING|TPM_ACCESS_VALID)) ==
473 	    (TPM_ACCESS_REQUEST_PENDING|TPM_ACCESS_VALID)) {
474 		DPRINTF(("%s: releasing locality\n", sc->sc_dev.dv_xname));
475 		bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
476 		    TPM_ACCESS_ACTIVE_LOCALITY);
477 	}
478 }
479 
480 int
481 tpm_getburst(struct tpm_softc *sc)
482 {
483 	int burst, burst2, to;
484 
485 	to = tpm_tmotohz(TPM_BURST_TMO);
486 
487 	burst = 0;
488 	while (burst == 0 && to--) {
489 		/*
490 		 * Burst count has to be read from bits 8 to 23 without
491 		 * touching any other bits, eg. the actual status bits 0 to 7.
492 		 */
493 		burst = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 1);
494 		DPRINTF(("%s: %s: read1(0x%x): 0x%x\n", sc->sc_dev.dv_xname,
495 		    __func__, TPM_STS + 1, burst));
496 		burst2 = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 2);
497 		DPRINTF(("%s: %s: read1(0x%x): 0x%x\n", sc->sc_dev.dv_xname,
498 		    __func__, TPM_STS + 2, burst2));
499 		burst |= burst2 << 8;
500 		if (burst)
501 			return burst;
502 
503 		DELAY(10);
504 	}
505 
506 	DPRINTF(("%s: getburst timed out\n", sc->sc_dev.dv_xname));
507 
508 	return 0;
509 }
510 
511 uint8_t
512 tpm_status(struct tpm_softc *sc)
513 {
514 	return bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS) & TPM_STS_MASK;
515 }
516 
517 int
518 tpm_tmotohz(int tmo)
519 {
520 	struct timeval tv;
521 
522 	tv.tv_sec = tmo / 1000;
523 	tv.tv_usec = 1000 * (tmo % 1000);
524 
525 	return tvtohz(&tv);
526 }
527 
528 int
529 tpm_waitfor(struct tpm_softc *sc, uint8_t mask, int tries)
530 {
531 	uint8_t status;
532 
533 	while (((status = tpm_status(sc)) & mask) != mask) {
534 		if (tries == 0) {
535 			DPRINTF(("%s: %s: timed out, status 0x%x != 0x%x\n",
536 			    sc->sc_dev.dv_xname, __func__, status, mask));
537 			return status;
538 		}
539 
540 		tries--;
541 		DELAY(1);
542 	}
543 
544 	return 0;
545 }
546 
547 int
548 tpm_read(struct tpm_softc *sc, void *buf, int len, size_t *count,
549     int flags)
550 {
551 	uint8_t *p = buf;
552 	uint8_t c;
553 	size_t cnt;
554 	int rv, n, bcnt;
555 
556 	DPRINTF(("%s: %s %d:", sc->sc_dev.dv_xname, __func__, len));
557 
558 	cnt = 0;
559 	while (len > 0) {
560 		if ((rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
561 		    TPM_READ_TMO)))
562 			return rv;
563 
564 		bcnt = tpm_getburst(sc);
565 		n = MIN(len, bcnt);
566 
567 		for (; n--; len--) {
568 			c = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_DATA);
569 			DPRINTF((" %02x", c));
570 			*p++ = c;
571 			cnt++;
572 		}
573 
574 		if ((flags & TPM_PARAM_SIZE) == 0 && cnt >= 6)
575 			break;
576 	}
577 
578 	DPRINTF(("\n"));
579 
580 	if (count)
581 		*count = cnt;
582 
583 	return 0;
584 }
585 
586 int
587 tpm_write(struct tpm_softc *sc, void *buf, int len)
588 {
589 	uint8_t *p = buf;
590 	uint8_t status;
591 	size_t count = 0;
592 	int rv, r;
593 
594 	if ((rv = tpm_request_locality(sc, 0)) != 0)
595 		return rv;
596 
597 	DPRINTF(("%s: %s %d:", sc->sc_dev.dv_xname, __func__, len));
598 	for (r = 0; r < len; r++)
599 		DPRINTF((" %02x", (uint8_t)(*(p + r))));
600 	DPRINTF(("\n"));
601 
602 	/* read status */
603 	status = tpm_status(sc);
604 	if ((status & TPM_STS_CMD_READY) == 0) {
605 		/* abort! */
606 		bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
607 		    TPM_STS_CMD_READY);
608 		if ((rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READ_TMO))) {
609 			DPRINTF(("%s: failed waiting for ready after abort "
610 			    "(0x%x)\n", sc->sc_dev.dv_xname, rv));
611 			return rv;
612 		}
613 	}
614 
615 	while (count < len - 1) {
616 		for (r = tpm_getburst(sc); r > 0 && count < len - 1; r--) {
617 			DPRINTF(("%s: %s: write1(0x%x, 0x%x)\n",
618 			    sc->sc_dev.dv_xname, __func__, TPM_DATA, *p));
619 			bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++);
620 			count++;
621 		}
622 		if ((rv = tpm_waitfor(sc, TPM_STS_VALID | TPM_STS_DATA_EXPECT,
623 		    TPM_READ_TMO))) {
624 			DPRINTF(("%s: %s: failed waiting for next byte (%d)\n",
625 			    sc->sc_dev.dv_xname, __func__, rv));
626 			return rv;
627 		}
628 	}
629 
630 	DPRINTF(("%s: %s: write1(0x%x, 0x%x)\n", sc->sc_dev.dv_xname, __func__,
631 	    TPM_DATA, *p));
632 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p);
633 	count++;
634 
635 	if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO))) {
636 		DPRINTF(("%s: %s: failed after last byte (%d)\n",
637 		    sc->sc_dev.dv_xname, __func__, rv));
638 		return rv;
639 	}
640 
641 	if ((status = tpm_status(sc)) & TPM_STS_DATA_EXPECT) {
642 		DPRINTF(("%s: %s: final status still expecting data: %b\n",
643 		    sc->sc_dev.dv_xname, __func__, status, TPM_STS_BITS));
644 		return status;
645 	}
646 
647 	DPRINTF(("%s: final status after write: %b\n", sc->sc_dev.dv_xname,
648 	    status, TPM_STS_BITS));
649 
650 	/* XXX: are we ever sending non-command data? */
651 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_GO);
652 
653 	return 0;
654 }
655