blob: 608dbc620b18d3d032e610a9ab3661733792aaab [file] [log] [blame]
Christophe Ricardf042a312015-03-08 11:17:15 +01001/*
2 * STMicroelectronics TPM SPI Linux driver for TPM ST33ZP24
Christophe RICARD8bb273f2016-02-13 16:15:31 +01003 * Copyright (C) 2009 - 2016 STMicroelectronics
Christophe Ricardf042a312015-03-08 11:17:15 +01004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/module.h>
20#include <linux/spi/spi.h>
21#include <linux/gpio.h>
Christophe RICARD86ff2052016-02-23 22:25:49 +010022#include <linux/gpio/consumer.h>
Christophe Ricardf042a312015-03-08 11:17:15 +010023#include <linux/of_irq.h>
24#include <linux/of_gpio.h>
Christophe RICARD86ff2052016-02-23 22:25:49 +010025#include <linux/acpi.h>
Christophe Ricardf042a312015-03-08 11:17:15 +010026#include <linux/tpm.h>
27#include <linux/platform_data/st33zp24.h>
28
29#include "st33zp24.h"
30
31#define TPM_DATA_FIFO 0x24
32#define TPM_INTF_CAPABILITY 0x14
33
34#define TPM_DUMMY_BYTE 0x00
35
36#define MAX_SPI_LATENCY 15
37#define LOCALITY0 0
38
39#define ST33ZP24_OK 0x5A
40#define ST33ZP24_UNDEFINED_ERR 0x80
41#define ST33ZP24_BADLOCALITY 0x81
42#define ST33ZP24_TISREGISTER_UKNOWN 0x82
43#define ST33ZP24_LOCALITY_NOT_ACTIVATED 0x83
44#define ST33ZP24_HASH_END_BEFORE_HASH_START 0x84
45#define ST33ZP24_BAD_COMMAND_ORDER 0x85
46#define ST33ZP24_INCORECT_RECEIVED_LENGTH 0x86
47#define ST33ZP24_TPM_FIFO_OVERFLOW 0x89
48#define ST33ZP24_UNEXPECTED_READ_FIFO 0x8A
49#define ST33ZP24_UNEXPECTED_WRITE_FIFO 0x8B
50#define ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END 0x90
51#define ST33ZP24_DUMMY_BYTES 0x00
52
53/*
54 * TPM command can be up to 2048 byte, A TPM response can be up to
55 * 1024 byte.
56 * Between command and response, there are latency byte (up to 15
57 * usually on st33zp24 2 are enough).
58 *
59 * Overall when sending a command and expecting an answer we need if
60 * worst case:
61 * 2048 (for the TPM command) + 1024 (for the TPM answer). We need
62 * some latency byte before the answer is available (max 15).
63 * We have 2048 + 1024 + 15.
64 */
65#define ST33ZP24_SPI_BUFFER_SIZE (TPM_BUFSIZE + (TPM_BUFSIZE / 2) +\
66 MAX_SPI_LATENCY)
67
68
69struct st33zp24_spi_phy {
70 struct spi_device *spi_device;
Christophe RICARDa5392e92016-02-13 16:15:27 +010071
Christophe Ricardf042a312015-03-08 11:17:15 +010072 u8 tx_buf[ST33ZP24_SPI_BUFFER_SIZE];
73 u8 rx_buf[ST33ZP24_SPI_BUFFER_SIZE];
74
75 int io_lpcpd;
76 int latency;
77};
78
79static int st33zp24_status_to_errno(u8 code)
80{
81 switch (code) {
82 case ST33ZP24_OK:
83 return 0;
84 case ST33ZP24_UNDEFINED_ERR:
85 case ST33ZP24_BADLOCALITY:
86 case ST33ZP24_TISREGISTER_UKNOWN:
87 case ST33ZP24_LOCALITY_NOT_ACTIVATED:
88 case ST33ZP24_HASH_END_BEFORE_HASH_START:
89 case ST33ZP24_BAD_COMMAND_ORDER:
90 case ST33ZP24_UNEXPECTED_READ_FIFO:
91 case ST33ZP24_UNEXPECTED_WRITE_FIFO:
92 case ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END:
93 return -EPROTO;
94 case ST33ZP24_INCORECT_RECEIVED_LENGTH:
95 case ST33ZP24_TPM_FIFO_OVERFLOW:
96 return -EMSGSIZE;
97 case ST33ZP24_DUMMY_BYTES:
98 return -ENOSYS;
99 }
100 return code;
101}
102
103/*
104 * st33zp24_spi_send
105 * Send byte to the TIS register according to the ST33ZP24 SPI protocol.
106 * @param: phy_id, the phy description
107 * @param: tpm_register, the tpm tis register where the data should be written
108 * @param: tpm_data, the tpm_data to write inside the tpm_register
109 * @param: tpm_size, The length of the data
110 * @return: should be zero if success else a negative error code.
111 */
112static int st33zp24_spi_send(void *phy_id, u8 tpm_register, u8 *tpm_data,
113 int tpm_size)
114{
Christophe RICARD9feaab52016-02-13 16:15:24 +0100115 int total_length = 0, ret = 0;
Christophe Ricardf042a312015-03-08 11:17:15 +0100116 struct st33zp24_spi_phy *phy = phy_id;
117 struct spi_device *dev = phy->spi_device;
Christophe RICARDa5392e92016-02-13 16:15:27 +0100118 struct spi_transfer spi_xfer = {
119 .tx_buf = phy->tx_buf,
120 .rx_buf = phy->rx_buf,
121 };
Christophe Ricardf042a312015-03-08 11:17:15 +0100122
123 /* Pre-Header */
Christophe RICARDa5392e92016-02-13 16:15:27 +0100124 phy->tx_buf[total_length++] = TPM_WRITE_DIRECTION | LOCALITY0;
125 phy->tx_buf[total_length++] = tpm_register;
Christophe Ricardf042a312015-03-08 11:17:15 +0100126
127 if (tpm_size > 0 && tpm_register == TPM_DATA_FIFO) {
Christophe RICARDa5392e92016-02-13 16:15:27 +0100128 phy->tx_buf[total_length++] = tpm_size >> 8;
129 phy->tx_buf[total_length++] = tpm_size;
Christophe Ricardf042a312015-03-08 11:17:15 +0100130 }
131
Christophe RICARDa5392e92016-02-13 16:15:27 +0100132 memcpy(&phy->tx_buf[total_length], tpm_data, tpm_size);
Christophe Ricardf042a312015-03-08 11:17:15 +0100133 total_length += tpm_size;
134
Christophe RICARDa5392e92016-02-13 16:15:27 +0100135 memset(&phy->tx_buf[total_length], TPM_DUMMY_BYTE, phy->latency);
Christophe Ricardf042a312015-03-08 11:17:15 +0100136
Christophe RICARDa5392e92016-02-13 16:15:27 +0100137 spi_xfer.len = total_length + phy->latency;
Christophe Ricardf042a312015-03-08 11:17:15 +0100138
Christophe RICARDa5392e92016-02-13 16:15:27 +0100139 ret = spi_sync_transfer(dev, &spi_xfer, 1);
Christophe Ricardf042a312015-03-08 11:17:15 +0100140 if (ret == 0)
Christophe RICARDa5392e92016-02-13 16:15:27 +0100141 ret = phy->rx_buf[total_length + phy->latency - 1];
Christophe Ricardf042a312015-03-08 11:17:15 +0100142
143 return st33zp24_status_to_errno(ret);
144} /* st33zp24_spi_send() */
145
146/*
Christophe RICARD8a745002016-02-13 16:15:25 +0100147 * st33zp24_spi_read8_recv
Christophe Ricardf042a312015-03-08 11:17:15 +0100148 * Recv byte from the TIS register according to the ST33ZP24 SPI protocol.
149 * @param: phy_id, the phy description
150 * @param: tpm_register, the tpm tis register where the data should be read
151 * @param: tpm_data, the TPM response
152 * @param: tpm_size, tpm TPM response size to read.
153 * @return: should be zero if success else a negative error code.
154 */
Christophe RICARD8a745002016-02-13 16:15:25 +0100155static int st33zp24_spi_read8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data,
156 int tpm_size)
Christophe Ricardf042a312015-03-08 11:17:15 +0100157{
Christophe RICARD9feaab52016-02-13 16:15:24 +0100158 int total_length = 0, ret;
Christophe Ricardf042a312015-03-08 11:17:15 +0100159 struct st33zp24_spi_phy *phy = phy_id;
160 struct spi_device *dev = phy->spi_device;
Christophe RICARDa5392e92016-02-13 16:15:27 +0100161 struct spi_transfer spi_xfer = {
162 .tx_buf = phy->tx_buf,
163 .rx_buf = phy->rx_buf,
164 };
Christophe Ricardf042a312015-03-08 11:17:15 +0100165
166 /* Pre-Header */
Christophe RICARDa5392e92016-02-13 16:15:27 +0100167 phy->tx_buf[total_length++] = LOCALITY0;
168 phy->tx_buf[total_length++] = tpm_register;
Christophe Ricardf042a312015-03-08 11:17:15 +0100169
Christophe RICARDa5392e92016-02-13 16:15:27 +0100170 memset(&phy->tx_buf[total_length], TPM_DUMMY_BYTE,
Christophe RICARD9feaab52016-02-13 16:15:24 +0100171 phy->latency + tpm_size);
Christophe Ricardf042a312015-03-08 11:17:15 +0100172
Christophe RICARDa5392e92016-02-13 16:15:27 +0100173 spi_xfer.len = total_length + phy->latency + tpm_size;
Christophe Ricardf042a312015-03-08 11:17:15 +0100174
175 /* header + status byte + size of the data + status byte */
Christophe RICARDa5392e92016-02-13 16:15:27 +0100176 ret = spi_sync_transfer(dev, &spi_xfer, 1);
Christophe Ricardf042a312015-03-08 11:17:15 +0100177 if (tpm_size > 0 && ret == 0) {
Christophe RICARDa5392e92016-02-13 16:15:27 +0100178 ret = phy->rx_buf[total_length + phy->latency - 1];
Christophe Ricardf042a312015-03-08 11:17:15 +0100179
Christophe RICARDa5392e92016-02-13 16:15:27 +0100180 memcpy(tpm_data, phy->rx_buf + total_length + phy->latency,
Christophe Ricardf042a312015-03-08 11:17:15 +0100181 tpm_size);
182 }
183
184 return ret;
Christophe RICARD8a745002016-02-13 16:15:25 +0100185} /* st33zp24_spi_read8_reg() */
Christophe Ricardf042a312015-03-08 11:17:15 +0100186
187/*
188 * st33zp24_spi_recv
189 * Recv byte from the TIS register according to the ST33ZP24 SPI protocol.
190 * @param: phy_id, the phy description
191 * @param: tpm_register, the tpm tis register where the data should be read
192 * @param: tpm_data, the TPM response
193 * @param: tpm_size, tpm TPM response size to read.
194 * @return: number of byte read successfully: should be one if success.
195 */
196static int st33zp24_spi_recv(void *phy_id, u8 tpm_register, u8 *tpm_data,
197 int tpm_size)
198{
199 int ret;
200
Christophe RICARD8a745002016-02-13 16:15:25 +0100201 ret = st33zp24_spi_read8_reg(phy_id, tpm_register, tpm_data, tpm_size);
Christophe Ricardf042a312015-03-08 11:17:15 +0100202 if (!st33zp24_status_to_errno(ret))
203 return tpm_size;
204 return ret;
205} /* st33zp24_spi_recv() */
206
Christophe RICARD8a745002016-02-13 16:15:25 +0100207static int st33zp24_spi_evaluate_latency(void *phy_id)
Christophe Ricardf042a312015-03-08 11:17:15 +0100208{
209 struct st33zp24_spi_phy *phy = phy_id;
210 int latency = 1, status = 0;
211 u8 data = 0;
212
213 while (!status && latency < MAX_SPI_LATENCY) {
214 phy->latency = latency;
Christophe RICARD8a745002016-02-13 16:15:25 +0100215 status = st33zp24_spi_read8_reg(phy_id, TPM_INTF_CAPABILITY,
216 &data, 1);
Christophe Ricardf042a312015-03-08 11:17:15 +0100217 latency++;
218 }
Christophe RICARD4ef2aa32016-02-13 16:15:30 +0100219 if (status < 0)
220 return status;
221 if (latency == MAX_SPI_LATENCY)
222 return -ENODEV;
223
Christophe Ricardf042a312015-03-08 11:17:15 +0100224 return latency - 1;
225} /* evaluate_latency() */
226
227static const struct st33zp24_phy_ops spi_phy_ops = {
228 .send = st33zp24_spi_send,
229 .recv = st33zp24_spi_recv,
230};
231
Christophe RICARD4d8007e2016-02-23 22:25:51 +0100232static int st33zp24_spi_acpi_request_resources(struct spi_device *spi_dev)
Christophe RICARD86ff2052016-02-23 22:25:49 +0100233{
Christophe RICARD4d8007e2016-02-23 22:25:51 +0100234 struct st33zp24_spi_phy *phy = spi_get_drvdata(spi_dev);
Christophe RICARD86ff2052016-02-23 22:25:49 +0100235 struct gpio_desc *gpiod_lpcpd;
Christophe Ricard20ab99f2016-03-23 08:55:33 +0100236 struct device *dev = &spi_dev->dev;
Christophe RICARD86ff2052016-02-23 22:25:49 +0100237
238 /* Get LPCPD GPIO from ACPI */
239 gpiod_lpcpd = devm_gpiod_get_index(dev, "TPM IO LPCPD", 1,
240 GPIOD_OUT_HIGH);
241 if (IS_ERR(gpiod_lpcpd)) {
242 dev_err(dev, "Failed to retrieve lpcpd-gpios from acpi.\n");
243 phy->io_lpcpd = -1;
244 /*
245 * lpcpd pin is not specified. This is not an issue as
246 * power management can be also managed by TPM specific
247 * commands. So leave with a success status code.
248 */
249 return 0;
250 }
251
252 phy->io_lpcpd = desc_to_gpio(gpiod_lpcpd);
253
254 return 0;
255}
256
Christophe RICARD4d8007e2016-02-23 22:25:51 +0100257static int st33zp24_spi_of_request_resources(struct spi_device *spi_dev)
Christophe RICARD160beb42016-02-23 22:25:49 +0100258{
Christophe RICARD4d8007e2016-02-23 22:25:51 +0100259 struct st33zp24_spi_phy *phy = spi_get_drvdata(spi_dev);
Christophe Ricardf042a312015-03-08 11:17:15 +0100260 struct device_node *pp;
Christophe Ricardf042a312015-03-08 11:17:15 +0100261 int gpio;
262 int ret;
263
Christophe RICARD4d8007e2016-02-23 22:25:51 +0100264 pp = spi_dev->dev.of_node;
Christophe Ricardf042a312015-03-08 11:17:15 +0100265 if (!pp) {
Christophe RICARD4d8007e2016-02-23 22:25:51 +0100266 dev_err(&spi_dev->dev, "No platform data\n");
Christophe Ricardf042a312015-03-08 11:17:15 +0100267 return -ENODEV;
268 }
269
270 /* Get GPIO from device tree */
271 gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0);
272 if (gpio < 0) {
Christophe RICARD4d8007e2016-02-23 22:25:51 +0100273 dev_err(&spi_dev->dev,
Christophe Ricardf042a312015-03-08 11:17:15 +0100274 "Failed to retrieve lpcpd-gpios from dts.\n");
275 phy->io_lpcpd = -1;
276 /*
277 * lpcpd pin is not specified. This is not an issue as
278 * power management can be also managed by TPM specific
279 * commands. So leave with a success status code.
280 */
281 return 0;
282 }
283 /* GPIO request and configuration */
Christophe RICARD4d8007e2016-02-23 22:25:51 +0100284 ret = devm_gpio_request_one(&spi_dev->dev, gpio,
Christophe Ricardf042a312015-03-08 11:17:15 +0100285 GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD");
286 if (ret) {
Christophe RICARD4d8007e2016-02-23 22:25:51 +0100287 dev_err(&spi_dev->dev, "Failed to request lpcpd pin\n");
Christophe Ricardf042a312015-03-08 11:17:15 +0100288 return -ENODEV;
289 }
290 phy->io_lpcpd = gpio;
291
292 return 0;
293}
Christophe RICARD604e5782016-02-13 16:15:24 +0100294
Christophe RICARD4d8007e2016-02-23 22:25:51 +0100295static int st33zp24_spi_request_resources(struct spi_device *dev)
Christophe RICARD604e5782016-02-13 16:15:24 +0100296{
Christophe RICARD4d8007e2016-02-23 22:25:51 +0100297 struct st33zp24_spi_phy *phy = spi_get_drvdata(dev);
Christophe Ricardf042a312015-03-08 11:17:15 +0100298 struct st33zp24_platform_data *pdata;
299 int ret;
300
301 pdata = dev->dev.platform_data;
302 if (!pdata) {
303 dev_err(&dev->dev, "No platform data\n");
304 return -ENODEV;
305 }
306
307 /* store for late use */
308 phy->io_lpcpd = pdata->io_lpcpd;
309
310 if (gpio_is_valid(pdata->io_lpcpd)) {
311 ret = devm_gpio_request_one(&dev->dev,
312 pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH,
313 "TPM IO_LPCPD");
314 if (ret) {
315 dev_err(&dev->dev, "%s : reset gpio_request failed\n",
316 __FILE__);
317 return ret;
318 }
319 }
320
321 return 0;
322}
323
324/*
Christophe RICARD8a745002016-02-13 16:15:25 +0100325 * st33zp24_spi_probe initialize the TPM device
Christophe Ricardf042a312015-03-08 11:17:15 +0100326 * @param: dev, the spi_device drescription (TPM SPI description).
327 * @return: 0 in case of success.
328 * or a negative value describing the error.
329 */
Christophe RICARD8a745002016-02-13 16:15:25 +0100330static int st33zp24_spi_probe(struct spi_device *dev)
Christophe Ricardf042a312015-03-08 11:17:15 +0100331{
332 int ret;
333 struct st33zp24_platform_data *pdata;
334 struct st33zp24_spi_phy *phy;
335
336 /* Check SPI platform functionnalities */
337 if (!dev) {
338 pr_info("%s: dev is NULL. Device is not accessible.\n",
339 __func__);
340 return -ENODEV;
341 }
342
343 phy = devm_kzalloc(&dev->dev, sizeof(struct st33zp24_spi_phy),
344 GFP_KERNEL);
345 if (!phy)
346 return -ENOMEM;
347
348 phy->spi_device = dev;
Christophe RICARD4d8007e2016-02-23 22:25:51 +0100349
350 spi_set_drvdata(dev, phy);
351
Christophe Ricardf042a312015-03-08 11:17:15 +0100352 pdata = dev->dev.platform_data;
353 if (!pdata && dev->dev.of_node) {
Christophe RICARD4d8007e2016-02-23 22:25:51 +0100354 ret = st33zp24_spi_of_request_resources(dev);
Christophe Ricardf042a312015-03-08 11:17:15 +0100355 if (ret)
356 return ret;
357 } else if (pdata) {
Christophe RICARD4d8007e2016-02-23 22:25:51 +0100358 ret = st33zp24_spi_request_resources(dev);
Christophe RICARD160beb42016-02-23 22:25:49 +0100359 if (ret)
360 return ret;
Christophe RICARD86ff2052016-02-23 22:25:49 +0100361 } else if (ACPI_HANDLE(&dev->dev)) {
Christophe RICARD4d8007e2016-02-23 22:25:51 +0100362 ret = st33zp24_spi_acpi_request_resources(dev);
Christophe RICARD86ff2052016-02-23 22:25:49 +0100363 if (ret)
364 return ret;
Christophe Ricardf042a312015-03-08 11:17:15 +0100365 }
366
Christophe RICARD8a745002016-02-13 16:15:25 +0100367 phy->latency = st33zp24_spi_evaluate_latency(phy);
Christophe Ricardf042a312015-03-08 11:17:15 +0100368 if (phy->latency <= 0)
369 return -ENODEV;
370
371 return st33zp24_probe(phy, &spi_phy_ops, &dev->dev, dev->irq,
372 phy->io_lpcpd);
373}
374
375/*
Christophe RICARD8a745002016-02-13 16:15:25 +0100376 * st33zp24_spi_remove remove the TPM device
Christophe Ricardf042a312015-03-08 11:17:15 +0100377 * @param: client, the spi_device drescription (TPM SPI description).
378 * @return: 0 in case of success.
379 */
Christophe RICARD8a745002016-02-13 16:15:25 +0100380static int st33zp24_spi_remove(struct spi_device *dev)
Christophe Ricardf042a312015-03-08 11:17:15 +0100381{
382 struct tpm_chip *chip = spi_get_drvdata(dev);
383
384 return st33zp24_remove(chip);
385}
386
Christophe Ricard1018bc22015-03-23 22:29:58 +0100387static const struct spi_device_id st33zp24_spi_id[] = {
388 {TPM_ST33_SPI, 0},
389 {}
390};
391MODULE_DEVICE_TABLE(spi, st33zp24_spi_id);
392
Christophe Ricardf042a312015-03-08 11:17:15 +0100393static const struct of_device_id of_st33zp24_spi_match[] = {
394 { .compatible = "st,st33zp24-spi", },
395 {}
396};
397MODULE_DEVICE_TABLE(of, of_st33zp24_spi_match);
Christophe RICARD160beb42016-02-23 22:25:49 +0100398
Christophe RICARD86ff2052016-02-23 22:25:49 +0100399static const struct acpi_device_id st33zp24_spi_acpi_match[] = {
400 {"SMO3324"},
401 {}
402};
403MODULE_DEVICE_TABLE(acpi, st33zp24_spi_acpi_match);
404
Christophe Ricardf042a312015-03-08 11:17:15 +0100405static SIMPLE_DEV_PM_OPS(st33zp24_spi_ops, st33zp24_pm_suspend,
406 st33zp24_pm_resume);
407
Christophe RICARD8a745002016-02-13 16:15:25 +0100408static struct spi_driver st33zp24_spi_driver = {
Christophe Ricardf042a312015-03-08 11:17:15 +0100409 .driver = {
Christophe Ricardf042a312015-03-08 11:17:15 +0100410 .name = TPM_ST33_SPI,
411 .pm = &st33zp24_spi_ops,
412 .of_match_table = of_match_ptr(of_st33zp24_spi_match),
Christophe RICARD86ff2052016-02-23 22:25:49 +0100413 .acpi_match_table = ACPI_PTR(st33zp24_spi_acpi_match),
Christophe Ricardf042a312015-03-08 11:17:15 +0100414 },
Christophe RICARD8a745002016-02-13 16:15:25 +0100415 .probe = st33zp24_spi_probe,
416 .remove = st33zp24_spi_remove,
Christophe Ricard1018bc22015-03-23 22:29:58 +0100417 .id_table = st33zp24_spi_id,
Christophe Ricardf042a312015-03-08 11:17:15 +0100418};
419
Christophe RICARD8a745002016-02-13 16:15:25 +0100420module_spi_driver(st33zp24_spi_driver);
Christophe Ricardf042a312015-03-08 11:17:15 +0100421
422MODULE_AUTHOR("TPM support (TPMsupport@list.st.com)");
423MODULE_DESCRIPTION("STM TPM 1.2 SPI ST33 Driver");
424MODULE_VERSION("1.3.0");
425MODULE_LICENSE("GPL");