Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/char/tpm/st33zp24/spi.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* STMicroelectronics TPM SPI Linux driver for TPM ST33ZP24
4
* Copyright (C) 2009 - 2016 STMicroelectronics
5
*/
6
7
#include <linux/module.h>
8
#include <linux/spi/spi.h>
9
#include <linux/of.h>
10
#include <linux/acpi.h>
11
#include <linux/tpm.h>
12
13
#include "../tpm.h"
14
#include "st33zp24.h"
15
16
#define TPM_DATA_FIFO 0x24
17
#define TPM_INTF_CAPABILITY 0x14
18
19
#define TPM_DUMMY_BYTE 0x00
20
21
#define MAX_SPI_LATENCY 15
22
#define LOCALITY0 0
23
24
#define ST33ZP24_OK 0x5A
25
#define ST33ZP24_UNDEFINED_ERR 0x80
26
#define ST33ZP24_BADLOCALITY 0x81
27
#define ST33ZP24_TISREGISTER_UNKNOWN 0x82
28
#define ST33ZP24_LOCALITY_NOT_ACTIVATED 0x83
29
#define ST33ZP24_HASH_END_BEFORE_HASH_START 0x84
30
#define ST33ZP24_BAD_COMMAND_ORDER 0x85
31
#define ST33ZP24_INCORECT_RECEIVED_LENGTH 0x86
32
#define ST33ZP24_TPM_FIFO_OVERFLOW 0x89
33
#define ST33ZP24_UNEXPECTED_READ_FIFO 0x8A
34
#define ST33ZP24_UNEXPECTED_WRITE_FIFO 0x8B
35
#define ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END 0x90
36
#define ST33ZP24_DUMMY_BYTES 0x00
37
38
/*
39
* TPM command can be up to 2048 byte, A TPM response can be up to
40
* 1024 byte.
41
* Between command and response, there are latency byte (up to 15
42
* usually on st33zp24 2 are enough).
43
*
44
* Overall when sending a command and expecting an answer we need if
45
* worst case:
46
* 2048 (for the TPM command) + 1024 (for the TPM answer). We need
47
* some latency byte before the answer is available (max 15).
48
* We have 2048 + 1024 + 15.
49
*/
50
#define ST33ZP24_SPI_BUFFER_SIZE (ST33ZP24_BUFSIZE + (ST33ZP24_BUFSIZE / 2) +\
51
MAX_SPI_LATENCY)
52
53
54
struct st33zp24_spi_phy {
55
struct spi_device *spi_device;
56
57
u8 tx_buf[ST33ZP24_SPI_BUFFER_SIZE];
58
u8 rx_buf[ST33ZP24_SPI_BUFFER_SIZE];
59
60
int latency;
61
};
62
63
static int st33zp24_status_to_errno(u8 code)
64
{
65
switch (code) {
66
case ST33ZP24_OK:
67
return 0;
68
case ST33ZP24_UNDEFINED_ERR:
69
case ST33ZP24_BADLOCALITY:
70
case ST33ZP24_TISREGISTER_UNKNOWN:
71
case ST33ZP24_LOCALITY_NOT_ACTIVATED:
72
case ST33ZP24_HASH_END_BEFORE_HASH_START:
73
case ST33ZP24_BAD_COMMAND_ORDER:
74
case ST33ZP24_UNEXPECTED_READ_FIFO:
75
case ST33ZP24_UNEXPECTED_WRITE_FIFO:
76
case ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END:
77
return -EPROTO;
78
case ST33ZP24_INCORECT_RECEIVED_LENGTH:
79
case ST33ZP24_TPM_FIFO_OVERFLOW:
80
return -EMSGSIZE;
81
case ST33ZP24_DUMMY_BYTES:
82
return -ENOSYS;
83
}
84
return code;
85
}
86
87
/*
88
* st33zp24_spi_send
89
* Send byte to the TIS register according to the ST33ZP24 SPI protocol.
90
* @param: phy_id, the phy description
91
* @param: tpm_register, the tpm tis register where the data should be written
92
* @param: tpm_data, the tpm_data to write inside the tpm_register
93
* @param: tpm_size, The length of the data
94
* @return: should be zero if success else a negative error code.
95
*/
96
static int st33zp24_spi_send(void *phy_id, u8 tpm_register, u8 *tpm_data,
97
int tpm_size)
98
{
99
int total_length = 0, ret = 0;
100
struct st33zp24_spi_phy *phy = phy_id;
101
struct spi_device *dev = phy->spi_device;
102
struct spi_transfer spi_xfer = {
103
.tx_buf = phy->tx_buf,
104
.rx_buf = phy->rx_buf,
105
};
106
107
/* Pre-Header */
108
phy->tx_buf[total_length++] = TPM_WRITE_DIRECTION | LOCALITY0;
109
phy->tx_buf[total_length++] = tpm_register;
110
111
if (tpm_size > 0 && tpm_register == TPM_DATA_FIFO) {
112
phy->tx_buf[total_length++] = tpm_size >> 8;
113
phy->tx_buf[total_length++] = tpm_size;
114
}
115
116
memcpy(&phy->tx_buf[total_length], tpm_data, tpm_size);
117
total_length += tpm_size;
118
119
memset(&phy->tx_buf[total_length], TPM_DUMMY_BYTE, phy->latency);
120
121
spi_xfer.len = total_length + phy->latency;
122
123
ret = spi_sync_transfer(dev, &spi_xfer, 1);
124
if (ret == 0)
125
ret = phy->rx_buf[total_length + phy->latency - 1];
126
127
return st33zp24_status_to_errno(ret);
128
} /* st33zp24_spi_send() */
129
130
/*
131
* st33zp24_spi_read8_recv
132
* Recv byte from the TIS register according to the ST33ZP24 SPI protocol.
133
* @param: phy_id, the phy description
134
* @param: tpm_register, the tpm tis register where the data should be read
135
* @param: tpm_data, the TPM response
136
* @param: tpm_size, tpm TPM response size to read.
137
* @return: should be zero if success else a negative error code.
138
*/
139
static int st33zp24_spi_read8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data,
140
int tpm_size)
141
{
142
int total_length = 0, ret;
143
struct st33zp24_spi_phy *phy = phy_id;
144
struct spi_device *dev = phy->spi_device;
145
struct spi_transfer spi_xfer = {
146
.tx_buf = phy->tx_buf,
147
.rx_buf = phy->rx_buf,
148
};
149
150
/* Pre-Header */
151
phy->tx_buf[total_length++] = LOCALITY0;
152
phy->tx_buf[total_length++] = tpm_register;
153
154
memset(&phy->tx_buf[total_length], TPM_DUMMY_BYTE,
155
phy->latency + tpm_size);
156
157
spi_xfer.len = total_length + phy->latency + tpm_size;
158
159
/* header + status byte + size of the data + status byte */
160
ret = spi_sync_transfer(dev, &spi_xfer, 1);
161
if (tpm_size > 0 && ret == 0) {
162
ret = phy->rx_buf[total_length + phy->latency - 1];
163
164
memcpy(tpm_data, phy->rx_buf + total_length + phy->latency,
165
tpm_size);
166
}
167
168
return ret;
169
} /* st33zp24_spi_read8_reg() */
170
171
/*
172
* st33zp24_spi_recv
173
* Recv byte from the TIS register according to the ST33ZP24 SPI protocol.
174
* @param: phy_id, the phy description
175
* @param: tpm_register, the tpm tis register where the data should be read
176
* @param: tpm_data, the TPM response
177
* @param: tpm_size, tpm TPM response size to read.
178
* @return: number of byte read successfully: should be one if success.
179
*/
180
static int st33zp24_spi_recv(void *phy_id, u8 tpm_register, u8 *tpm_data,
181
int tpm_size)
182
{
183
int ret;
184
185
ret = st33zp24_spi_read8_reg(phy_id, tpm_register, tpm_data, tpm_size);
186
if (!st33zp24_status_to_errno(ret))
187
return tpm_size;
188
return ret;
189
} /* st33zp24_spi_recv() */
190
191
static int st33zp24_spi_evaluate_latency(void *phy_id)
192
{
193
struct st33zp24_spi_phy *phy = phy_id;
194
int latency = 1, status = 0;
195
u8 data = 0;
196
197
while (!status && latency < MAX_SPI_LATENCY) {
198
phy->latency = latency;
199
status = st33zp24_spi_read8_reg(phy_id, TPM_INTF_CAPABILITY,
200
&data, 1);
201
latency++;
202
}
203
if (status < 0)
204
return status;
205
if (latency == MAX_SPI_LATENCY)
206
return -ENODEV;
207
208
return latency - 1;
209
} /* evaluate_latency() */
210
211
static const struct st33zp24_phy_ops spi_phy_ops = {
212
.send = st33zp24_spi_send,
213
.recv = st33zp24_spi_recv,
214
};
215
216
/*
217
* st33zp24_spi_probe initialize the TPM device
218
* @param: dev, the spi_device description (TPM SPI description).
219
* @return: 0 in case of success.
220
* or a negative value describing the error.
221
*/
222
static int st33zp24_spi_probe(struct spi_device *dev)
223
{
224
struct st33zp24_spi_phy *phy;
225
226
phy = devm_kzalloc(&dev->dev, sizeof(struct st33zp24_spi_phy),
227
GFP_KERNEL);
228
if (!phy)
229
return -ENOMEM;
230
231
phy->spi_device = dev;
232
233
phy->latency = st33zp24_spi_evaluate_latency(phy);
234
if (phy->latency <= 0)
235
return -ENODEV;
236
237
return st33zp24_probe(phy, &spi_phy_ops, &dev->dev, dev->irq);
238
}
239
240
/*
241
* st33zp24_spi_remove remove the TPM device
242
* @param: client, the spi_device description (TPM SPI description).
243
* @return: 0 in case of success.
244
*/
245
static void st33zp24_spi_remove(struct spi_device *dev)
246
{
247
struct tpm_chip *chip = spi_get_drvdata(dev);
248
249
st33zp24_remove(chip);
250
}
251
252
static const struct spi_device_id st33zp24_spi_id[] = {
253
{TPM_ST33_SPI, 0},
254
{}
255
};
256
MODULE_DEVICE_TABLE(spi, st33zp24_spi_id);
257
258
static const struct of_device_id of_st33zp24_spi_match[] __maybe_unused = {
259
{ .compatible = "st,st33zp24-spi", },
260
{}
261
};
262
MODULE_DEVICE_TABLE(of, of_st33zp24_spi_match);
263
264
static const struct acpi_device_id st33zp24_spi_acpi_match[] __maybe_unused = {
265
{"SMO3324"},
266
{}
267
};
268
MODULE_DEVICE_TABLE(acpi, st33zp24_spi_acpi_match);
269
270
static SIMPLE_DEV_PM_OPS(st33zp24_spi_ops, st33zp24_pm_suspend,
271
st33zp24_pm_resume);
272
273
static struct spi_driver st33zp24_spi_driver = {
274
.driver = {
275
.name = "st33zp24-spi",
276
.pm = &st33zp24_spi_ops,
277
.of_match_table = of_match_ptr(of_st33zp24_spi_match),
278
.acpi_match_table = ACPI_PTR(st33zp24_spi_acpi_match),
279
},
280
.probe = st33zp24_spi_probe,
281
.remove = st33zp24_spi_remove,
282
.id_table = st33zp24_spi_id,
283
};
284
285
module_spi_driver(st33zp24_spi_driver);
286
287
MODULE_AUTHOR("TPM support <[email protected]>");
288
MODULE_DESCRIPTION("STM TPM 1.2 SPI ST33 Driver");
289
MODULE_VERSION("1.3.0");
290
MODULE_LICENSE("GPL");
291
292