xref: /freebsd/sys/dev/tpm/tpm_spibus.c (revision c2e9c5bbf02294376988f3e7eba82b8e078cdf30)
1*c2e9c5bbSJustin Hibbits /*-
2*c2e9c5bbSJustin Hibbits  * Copyright (c) 2023 Juniper Networks, Inc.
3*c2e9c5bbSJustin Hibbits  * All rights reserved.
4*c2e9c5bbSJustin Hibbits  *
5*c2e9c5bbSJustin Hibbits  * Redistribution and use in source and binary forms, with or without
6*c2e9c5bbSJustin Hibbits  * modification, are permitted provided that the following conditions
7*c2e9c5bbSJustin Hibbits  * are met:
8*c2e9c5bbSJustin Hibbits  * 1. Redistributions of source code must retain the above copyright
9*c2e9c5bbSJustin Hibbits  *    notice, this list of conditions and the following disclaimer.
10*c2e9c5bbSJustin Hibbits  * 2. Redistributions in binary form must reproduce the above copyright
11*c2e9c5bbSJustin Hibbits  *    notice, this list of conditions and the following disclaimer in the
12*c2e9c5bbSJustin Hibbits  *    documentation and/or other materials provided with the distribution.
13*c2e9c5bbSJustin Hibbits  *
14*c2e9c5bbSJustin Hibbits  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15*c2e9c5bbSJustin Hibbits  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16*c2e9c5bbSJustin Hibbits  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17*c2e9c5bbSJustin Hibbits  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
18*c2e9c5bbSJustin Hibbits  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19*c2e9c5bbSJustin Hibbits  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20*c2e9c5bbSJustin Hibbits  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*c2e9c5bbSJustin Hibbits  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22*c2e9c5bbSJustin Hibbits  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
23*c2e9c5bbSJustin Hibbits  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24*c2e9c5bbSJustin Hibbits  * POSSIBILITY OF SUCH DAMAGE.
25*c2e9c5bbSJustin Hibbits  */
26*c2e9c5bbSJustin Hibbits 
27*c2e9c5bbSJustin Hibbits #include <sys/cdefs.h>
28*c2e9c5bbSJustin Hibbits #include <sys/types.h>
29*c2e9c5bbSJustin Hibbits #include <sys/bus.h>
30*c2e9c5bbSJustin Hibbits 
31*c2e9c5bbSJustin Hibbits #include <dev/spibus/spi.h>
32*c2e9c5bbSJustin Hibbits #include "spibus_if.h"
33*c2e9c5bbSJustin Hibbits #include "tpm_if.h"
34*c2e9c5bbSJustin Hibbits #include "tpm20.h"
35*c2e9c5bbSJustin Hibbits 
36*c2e9c5bbSJustin Hibbits #define	TPM_BASE_ADDR		0xD40000
37*c2e9c5bbSJustin Hibbits #define	TPM_SPI_HEADER_SIZE	4
38*c2e9c5bbSJustin Hibbits #define	TPM_WAIT_STATES		50
39*c2e9c5bbSJustin Hibbits 
40*c2e9c5bbSJustin Hibbits static void
41*c2e9c5bbSJustin Hibbits tpm_insert_wait(device_t dev)
42*c2e9c5bbSJustin Hibbits {
43*c2e9c5bbSJustin Hibbits 	device_t parent = device_get_parent(dev);
44*c2e9c5bbSJustin Hibbits 	int wait = TPM_WAIT_STATES;
45*c2e9c5bbSJustin Hibbits 	struct spi_command spic = SPI_COMMAND_INITIALIZER;
46*c2e9c5bbSJustin Hibbits 
47*c2e9c5bbSJustin Hibbits 	uint8_t txb = 0;
48*c2e9c5bbSJustin Hibbits 	uint8_t rxb = 0;
49*c2e9c5bbSJustin Hibbits 
50*c2e9c5bbSJustin Hibbits 	spic.tx_cmd = &txb;
51*c2e9c5bbSJustin Hibbits 	spic.rx_cmd = &rxb;
52*c2e9c5bbSJustin Hibbits 	spic.tx_cmd_sz = 1;
53*c2e9c5bbSJustin Hibbits 	spic.rx_cmd_sz = 1;
54*c2e9c5bbSJustin Hibbits 	spic.flags = SPI_FLAG_KEEP_CS;
55*c2e9c5bbSJustin Hibbits 	do {
56*c2e9c5bbSJustin Hibbits 		SPIBUS_TRANSFER(parent, dev, &spic);
57*c2e9c5bbSJustin Hibbits 	} while (--wait > 0 && (rxb & 0x1) == 0);
58*c2e9c5bbSJustin Hibbits }
59*c2e9c5bbSJustin Hibbits 
60*c2e9c5bbSJustin Hibbits static inline int
61*c2e9c5bbSJustin Hibbits tpm_spi_read_n(device_t dev, bus_size_t off, void *buf, size_t size)
62*c2e9c5bbSJustin Hibbits {
63*c2e9c5bbSJustin Hibbits 	struct spi_command spic = SPI_COMMAND_INITIALIZER;
64*c2e9c5bbSJustin Hibbits 	uint8_t tx[4] = {0};
65*c2e9c5bbSJustin Hibbits 	uint8_t rx[4] = {0};
66*c2e9c5bbSJustin Hibbits 	int err;
67*c2e9c5bbSJustin Hibbits 
68*c2e9c5bbSJustin Hibbits 	if (size > sizeof(rx))
69*c2e9c5bbSJustin Hibbits 		return (EINVAL);
70*c2e9c5bbSJustin Hibbits 	off += TPM_BASE_ADDR;
71*c2e9c5bbSJustin Hibbits 	tx[0] = 0x80 | (size - 1); /* Write (size) bytes */
72*c2e9c5bbSJustin Hibbits 	tx[1] = (off >> 16) & 0xff;
73*c2e9c5bbSJustin Hibbits 	tx[2] = (off >> 8) & 0xff;
74*c2e9c5bbSJustin Hibbits 	tx[3] = off & 0xff;
75*c2e9c5bbSJustin Hibbits 
76*c2e9c5bbSJustin Hibbits 	spic.tx_cmd = tx;
77*c2e9c5bbSJustin Hibbits 	spic.tx_cmd_sz = sizeof(tx);
78*c2e9c5bbSJustin Hibbits 	spic.rx_cmd = rx;
79*c2e9c5bbSJustin Hibbits 	spic.rx_cmd_sz = sizeof(tx);
80*c2e9c5bbSJustin Hibbits 	spic.flags = SPI_FLAG_KEEP_CS;
81*c2e9c5bbSJustin Hibbits 
82*c2e9c5bbSJustin Hibbits 	err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &spic);
83*c2e9c5bbSJustin Hibbits 
84*c2e9c5bbSJustin Hibbits 	if (!(rx[3] & 0x1)) {
85*c2e9c5bbSJustin Hibbits 		tpm_insert_wait(dev);
86*c2e9c5bbSJustin Hibbits 	}
87*c2e9c5bbSJustin Hibbits 	memset(tx, 0, sizeof(tx));
88*c2e9c5bbSJustin Hibbits 	spic.tx_cmd_sz = spic.rx_cmd_sz = size;
89*c2e9c5bbSJustin Hibbits 	spic.flags = 0;
90*c2e9c5bbSJustin Hibbits 	err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &spic);
91*c2e9c5bbSJustin Hibbits 	memcpy(buf, &rx[0], size);
92*c2e9c5bbSJustin Hibbits 
93*c2e9c5bbSJustin Hibbits 	return (err);
94*c2e9c5bbSJustin Hibbits }
95*c2e9c5bbSJustin Hibbits 
96*c2e9c5bbSJustin Hibbits static inline int
97*c2e9c5bbSJustin Hibbits tpm_spi_write_n(device_t dev, bus_size_t off, void *buf, size_t size)
98*c2e9c5bbSJustin Hibbits {
99*c2e9c5bbSJustin Hibbits 	struct spi_command spic = SPI_COMMAND_INITIALIZER;
100*c2e9c5bbSJustin Hibbits 	uint8_t tx[8] = {0};
101*c2e9c5bbSJustin Hibbits 	uint8_t rx[8] = {0};
102*c2e9c5bbSJustin Hibbits 	int err;
103*c2e9c5bbSJustin Hibbits 
104*c2e9c5bbSJustin Hibbits 	off += TPM_BASE_ADDR;
105*c2e9c5bbSJustin Hibbits 	tx[0] = 0x00 | (size - 1); /* Write (size) bytes */
106*c2e9c5bbSJustin Hibbits 	tx[1] = (off >> 16) & 0xff;
107*c2e9c5bbSJustin Hibbits 	tx[2] = (off >> 8) & 0xff;
108*c2e9c5bbSJustin Hibbits 	tx[3] = off & 0xff;
109*c2e9c5bbSJustin Hibbits 
110*c2e9c5bbSJustin Hibbits 	memcpy(&tx[4], buf, size);
111*c2e9c5bbSJustin Hibbits 
112*c2e9c5bbSJustin Hibbits 	spic.tx_cmd = tx;
113*c2e9c5bbSJustin Hibbits 	spic.tx_cmd_sz = size + TPM_SPI_HEADER_SIZE;
114*c2e9c5bbSJustin Hibbits 	spic.rx_cmd = rx;
115*c2e9c5bbSJustin Hibbits 	spic.rx_cmd_sz = size + TPM_SPI_HEADER_SIZE;
116*c2e9c5bbSJustin Hibbits 
117*c2e9c5bbSJustin Hibbits 	err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &spic);
118*c2e9c5bbSJustin Hibbits 
119*c2e9c5bbSJustin Hibbits 	return (err);
120*c2e9c5bbSJustin Hibbits }
121*c2e9c5bbSJustin Hibbits 
122*c2e9c5bbSJustin Hibbits /* Override accessors */
123*c2e9c5bbSJustin Hibbits static inline uint8_t
124*c2e9c5bbSJustin Hibbits spi_read_1(device_t dev, bus_size_t off)
125*c2e9c5bbSJustin Hibbits {
126*c2e9c5bbSJustin Hibbits 	uint8_t rx_byte;
127*c2e9c5bbSJustin Hibbits 
128*c2e9c5bbSJustin Hibbits 	tpm_spi_read_n(dev, off, &rx_byte, 1);
129*c2e9c5bbSJustin Hibbits 
130*c2e9c5bbSJustin Hibbits 	return (rx_byte);
131*c2e9c5bbSJustin Hibbits }
132*c2e9c5bbSJustin Hibbits 
133*c2e9c5bbSJustin Hibbits static inline uint32_t
134*c2e9c5bbSJustin Hibbits spi_read_4(device_t dev, bus_size_t off)
135*c2e9c5bbSJustin Hibbits {
136*c2e9c5bbSJustin Hibbits 	uint32_t rx_word = 0;
137*c2e9c5bbSJustin Hibbits 
138*c2e9c5bbSJustin Hibbits 	tpm_spi_read_n(dev, off, &rx_word, 4);
139*c2e9c5bbSJustin Hibbits 	rx_word = le32toh(rx_word);
140*c2e9c5bbSJustin Hibbits 
141*c2e9c5bbSJustin Hibbits 	return (rx_word);
142*c2e9c5bbSJustin Hibbits }
143*c2e9c5bbSJustin Hibbits 
144*c2e9c5bbSJustin Hibbits static inline void
145*c2e9c5bbSJustin Hibbits spi_write_1(device_t dev, bus_size_t off, uint8_t val)
146*c2e9c5bbSJustin Hibbits {
147*c2e9c5bbSJustin Hibbits 	tpm_spi_write_n(dev, off, &val, 1);
148*c2e9c5bbSJustin Hibbits }
149*c2e9c5bbSJustin Hibbits 
150*c2e9c5bbSJustin Hibbits static inline void
151*c2e9c5bbSJustin Hibbits spi_write_4(device_t dev, bus_size_t off, uint32_t val)
152*c2e9c5bbSJustin Hibbits {
153*c2e9c5bbSJustin Hibbits 	uint32_t tmp = htole32(val);
154*c2e9c5bbSJustin Hibbits 	tpm_spi_write_n(dev, off, &tmp, 4);
155*c2e9c5bbSJustin Hibbits }
156*c2e9c5bbSJustin Hibbits 
157*c2e9c5bbSJustin Hibbits static device_method_t tpm_spibus_methods[] = {
158*c2e9c5bbSJustin Hibbits 	DEVMETHOD(tpm_read_4,	spi_read_4),
159*c2e9c5bbSJustin Hibbits 	DEVMETHOD(tpm_read_1,	spi_read_1),
160*c2e9c5bbSJustin Hibbits 	DEVMETHOD(tpm_write_4,	spi_write_4),
161*c2e9c5bbSJustin Hibbits 	DEVMETHOD(tpm_write_1,	spi_write_1),
162*c2e9c5bbSJustin Hibbits 	DEVMETHOD_END
163*c2e9c5bbSJustin Hibbits };
164*c2e9c5bbSJustin Hibbits 
165*c2e9c5bbSJustin Hibbits DEFINE_CLASS_0(tpm_spi, tpm_spi_driver, tpm_spibus_methods,
166*c2e9c5bbSJustin Hibbits     sizeof(struct tpm_sc));
167