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