Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/char/tpm/tpm_i2c_atmel.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* ATMEL I2C TPM AT97SC3204T
4
*
5
* Copyright (C) 2012 V Lab Technologies
6
* Teddy Reed <[email protected]>
7
* Copyright (C) 2013, Obsidian Research Corp.
8
* Jason Gunthorpe <[email protected]>
9
* Device driver for ATMEL I2C TPMs.
10
*
11
* Teddy Reed determined the basic I2C command flow, unlike other I2C TPM
12
* devices the raw TCG formatted TPM command data is written via I2C and then
13
* raw TCG formatted TPM command data is returned via I2C.
14
*
15
* TGC status/locality/etc functions seen in the LPC implementation do not
16
* seem to be present.
17
*/
18
#include <linux/init.h>
19
#include <linux/module.h>
20
#include <linux/moduleparam.h>
21
#include <linux/slab.h>
22
#include <linux/i2c.h>
23
#include "tpm.h"
24
25
#define I2C_DRIVER_NAME "tpm_i2c_atmel"
26
27
#define TPM_I2C_SHORT_TIMEOUT 750 /* ms */
28
#define TPM_I2C_LONG_TIMEOUT 2000 /* 2 sec */
29
30
#define ATMEL_STS_OK 1
31
32
struct priv_data {
33
size_t len;
34
/* This is the amount we read on the first try. 25 was chosen to fit a
35
* fair number of read responses in the buffer so a 2nd retry can be
36
* avoided in small message cases. */
37
u8 buffer[sizeof(struct tpm_header) + 25];
38
};
39
40
static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz,
41
size_t len)
42
{
43
struct priv_data *priv = dev_get_drvdata(&chip->dev);
44
struct i2c_client *client = to_i2c_client(chip->dev.parent);
45
s32 status;
46
47
priv->len = 0;
48
49
if (len <= 2)
50
return -EIO;
51
52
status = i2c_master_send(client, buf, len);
53
54
dev_dbg(&chip->dev,
55
"%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__,
56
(int)min_t(size_t, 64, len), buf, len, status);
57
58
if (status < 0)
59
return status;
60
61
/* The upper layer does not support incomplete sends. */
62
if (status != len)
63
return -E2BIG;
64
65
return 0;
66
}
67
68
static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
69
{
70
struct priv_data *priv = dev_get_drvdata(&chip->dev);
71
struct i2c_client *client = to_i2c_client(chip->dev.parent);
72
struct tpm_header *hdr = (struct tpm_header *)priv->buffer;
73
u32 expected_len;
74
int rc;
75
76
if (priv->len == 0)
77
return -EIO;
78
79
/* Get the message size from the message header, if we didn't get the
80
* whole message in read_status then we need to re-read the
81
* message. */
82
expected_len = be32_to_cpu(hdr->length);
83
if (expected_len > count)
84
return -ENOMEM;
85
86
if (priv->len >= expected_len) {
87
dev_dbg(&chip->dev,
88
"%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
89
(int)min_t(size_t, 64, expected_len), buf, count,
90
expected_len);
91
memcpy(buf, priv->buffer, expected_len);
92
return expected_len;
93
}
94
95
rc = i2c_master_recv(client, buf, expected_len);
96
dev_dbg(&chip->dev,
97
"%s reread(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
98
(int)min_t(size_t, 64, expected_len), buf, count,
99
expected_len);
100
return rc;
101
}
102
103
static void i2c_atmel_cancel(struct tpm_chip *chip)
104
{
105
dev_err(&chip->dev, "TPM operation cancellation was requested, but is not supported");
106
}
107
108
static u8 i2c_atmel_read_status(struct tpm_chip *chip)
109
{
110
struct priv_data *priv = dev_get_drvdata(&chip->dev);
111
struct i2c_client *client = to_i2c_client(chip->dev.parent);
112
int rc;
113
114
/* The TPM fails the I2C read until it is ready, so we do the entire
115
* transfer here and buffer it locally. This way the common code can
116
* properly handle the timeouts. */
117
priv->len = 0;
118
memset(priv->buffer, 0, sizeof(priv->buffer));
119
120
121
/* Once the TPM has completed the command the command remains readable
122
* until another command is issued. */
123
rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer));
124
dev_dbg(&chip->dev,
125
"%s: sts=%d", __func__, rc);
126
if (rc <= 0)
127
return 0;
128
129
priv->len = rc;
130
131
return ATMEL_STS_OK;
132
}
133
134
static bool i2c_atmel_req_canceled(struct tpm_chip *chip, u8 status)
135
{
136
return false;
137
}
138
139
static const struct tpm_class_ops i2c_atmel = {
140
.flags = TPM_OPS_AUTO_STARTUP,
141
.status = i2c_atmel_read_status,
142
.recv = i2c_atmel_recv,
143
.send = i2c_atmel_send,
144
.cancel = i2c_atmel_cancel,
145
.req_complete_mask = ATMEL_STS_OK,
146
.req_complete_val = ATMEL_STS_OK,
147
.req_canceled = i2c_atmel_req_canceled,
148
};
149
150
static int i2c_atmel_probe(struct i2c_client *client)
151
{
152
struct tpm_chip *chip;
153
struct device *dev = &client->dev;
154
struct priv_data *priv;
155
156
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
157
return -ENODEV;
158
159
chip = tpmm_chip_alloc(dev, &i2c_atmel);
160
if (IS_ERR(chip))
161
return PTR_ERR(chip);
162
163
priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL);
164
if (!priv)
165
return -ENOMEM;
166
167
/* Default timeouts */
168
chip->timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT);
169
chip->timeout_b = msecs_to_jiffies(TPM_I2C_LONG_TIMEOUT);
170
chip->timeout_c = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT);
171
chip->timeout_d = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT);
172
173
dev_set_drvdata(&chip->dev, priv);
174
175
/* There is no known way to probe for this device, and all version
176
* information seems to be read via TPM commands. Thus we rely on the
177
* TPM startup process in the common code to detect the device. */
178
179
return tpm_chip_register(chip);
180
}
181
182
static void i2c_atmel_remove(struct i2c_client *client)
183
{
184
struct device *dev = &(client->dev);
185
struct tpm_chip *chip = dev_get_drvdata(dev);
186
tpm_chip_unregister(chip);
187
}
188
189
static const struct i2c_device_id i2c_atmel_id[] = {
190
{ I2C_DRIVER_NAME },
191
{}
192
};
193
MODULE_DEVICE_TABLE(i2c, i2c_atmel_id);
194
195
#ifdef CONFIG_OF
196
static const struct of_device_id i2c_atmel_of_match[] = {
197
{.compatible = "atmel,at97sc3204t"},
198
{},
199
};
200
MODULE_DEVICE_TABLE(of, i2c_atmel_of_match);
201
#endif
202
203
static SIMPLE_DEV_PM_OPS(i2c_atmel_pm_ops, tpm_pm_suspend, tpm_pm_resume);
204
205
static struct i2c_driver i2c_atmel_driver = {
206
.id_table = i2c_atmel_id,
207
.probe = i2c_atmel_probe,
208
.remove = i2c_atmel_remove,
209
.driver = {
210
.name = I2C_DRIVER_NAME,
211
.pm = &i2c_atmel_pm_ops,
212
.of_match_table = of_match_ptr(i2c_atmel_of_match),
213
},
214
};
215
216
module_i2c_driver(i2c_atmel_driver);
217
218
MODULE_AUTHOR("Jason Gunthorpe <[email protected]>");
219
MODULE_DESCRIPTION("Atmel TPM I2C Driver");
220
MODULE_LICENSE("GPL");
221
222