blob: b007c7ec6fc9b332a30ebbc9bc6584bf8b019b77 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0
Rong Changf6267992013-04-12 10:44:57 +00002/*
3 * Copyright (C) 2011 Infineon Technologies
4 *
5 * Authors:
6 * Peter Huewe <huewe.external@infineon.com>
7 *
8 * Description:
9 * Device driver for TCG/TCPA TPM (trusted platform module).
10 * Specifications at www.trustedcomputinggroup.org
11 *
12 * This device driver implements the TPM interface as defined in
13 * the TCG TPM Interface Spec version 1.2, revision 1.0 and the
14 * Infineon I2C Protocol Stack Specification v0.20.
15 *
16 * It is based on the Linux kernel driver tpm.c from Leendert van
17 * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall.
18 *
19 * Version: 2.1.1
Rong Changf6267992013-04-12 10:44:57 +000020 */
21
22#include <common.h>
Simon Glassf90acf12015-05-04 11:30:59 -060023#include <dm.h>
Vincent Palatinec34fa52013-04-12 11:04:36 +000024#include <fdtdec.h>
Rong Changf6267992013-04-12 10:44:57 +000025#include <i2c.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060026#include <log.h>
Miquel Raynald677bfe2018-05-15 11:57:06 +020027#include <tpm-v1.h>
Masahiro Yamada5d97dff2016-09-21 11:28:57 +090028#include <linux/errno.h>
Simon Glassb697e0f2015-08-22 18:31:38 -060029#include <linux/compiler.h>
Rong Changf6267992013-04-12 10:44:57 +000030#include <linux/types.h>
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +000031#include <linux/unaligned/be_byteshift.h>
Rong Changf6267992013-04-12 10:44:57 +000032
Christophe Ricard1259dcd2016-01-21 23:27:12 +010033#include "tpm_tis.h"
Simon Glassf255d312015-08-22 18:31:31 -060034#include "tpm_internal.h"
Rong Changf6267992013-04-12 10:44:57 +000035
Christophe Ricard1259dcd2016-01-21 23:27:12 +010036enum i2c_chip_type {
37 SLB9635,
38 SLB9645,
39 UNKNOWN,
40};
41
42/* expected value for DIDVID register */
43#define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L
44#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L
45
Vincent Palatinec34fa52013-04-12 11:04:36 +000046static const char * const chip_name[] = {
47 [SLB9635] = "slb9635tt",
48 [SLB9645] = "slb9645tt",
49 [UNKNOWN] = "unknown/fallback to slb9635",
50};
Rong Changf6267992013-04-12 10:44:57 +000051
Christophe Ricard1259dcd2016-01-21 23:27:12 +010052#define TPM_ACCESS(l) (0x0000 | ((l) << 4))
53#define TPM_STS(l) (0x0001 | ((l) << 4))
54#define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4))
55#define TPM_DID_VID(l) (0x0006 | ((l) << 4))
56
Rong Changf6267992013-04-12 10:44:57 +000057/*
Simon Glasse56e20e2015-08-22 18:31:29 -060058 * tpm_tis_i2c_read() - read from TPM register
Rong Changf6267992013-04-12 10:44:57 +000059 * @addr: register address to read from
60 * @buffer: provided by caller
61 * @len: number of bytes to read
62 *
63 * Read len bytes from TPM register and put them into
64 * buffer (little-endian format, i.e. first byte is put into buffer[0]).
65 *
66 * NOTE: TPM is big-endian for multi-byte values. Multi-byte
67 * values have to be swapped.
68 *
69 * Return -EIO on error, 0 on success.
70 */
Simon Glassb697e0f2015-08-22 18:31:38 -060071static int tpm_tis_i2c_read(struct udevice *dev, u8 addr, u8 *buffer,
72 size_t len)
Rong Changf6267992013-04-12 10:44:57 +000073{
Simon Glassb697e0f2015-08-22 18:31:38 -060074 struct tpm_chip *chip = dev_get_priv(dev);
Rong Changf6267992013-04-12 10:44:57 +000075 int rc;
76 int count;
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +000077 uint32_t addrbuf = addr;
Rong Changf6267992013-04-12 10:44:57 +000078
Simon Glassb697e0f2015-08-22 18:31:38 -060079 if ((chip->chip_type == SLB9635) || (chip->chip_type == UNKNOWN)) {
Vincent Palatinec34fa52013-04-12 11:04:36 +000080 /* slb9635 protocol should work in both cases */
81 for (count = 0; count < MAX_COUNT; count++) {
Simon Glassb697e0f2015-08-22 18:31:38 -060082 rc = dm_i2c_write(dev, 0, (uchar *)&addrbuf, 1);
Vincent Palatinec34fa52013-04-12 11:04:36 +000083 if (rc == 0)
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +000084 break; /* Success, break to skip sleep */
Simon Glass42c8ec52015-08-22 18:31:30 -060085 udelay(SLEEP_DURATION_US);
Vincent Palatinec34fa52013-04-12 11:04:36 +000086 }
Vincent Palatinec34fa52013-04-12 11:04:36 +000087 if (rc)
Simon Glassb697e0f2015-08-22 18:31:38 -060088 return rc;
Vincent Palatinec34fa52013-04-12 11:04:36 +000089
90 /* After the TPM has successfully received the register address
91 * it needs some time, thus we're sleeping here again, before
92 * retrieving the data
93 */
94 for (count = 0; count < MAX_COUNT; count++) {
Simon Glass42c8ec52015-08-22 18:31:30 -060095 udelay(SLEEP_DURATION_US);
Simon Glassb697e0f2015-08-22 18:31:38 -060096 rc = dm_i2c_read(dev, 0, buffer, len);
Vincent Palatinec34fa52013-04-12 11:04:36 +000097 if (rc == 0)
98 break; /* success, break to skip sleep */
99 }
100 } else {
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000101 /*
102 * Use a combined read for newer chips.
103 * Unfortunately the smbus functions are not suitable due to
Vincent Palatinec34fa52013-04-12 11:04:36 +0000104 * the 32 byte limit of the smbus.
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000105 * Retries should usually not be needed, but are kept just to
Vincent Palatinec34fa52013-04-12 11:04:36 +0000106 * be safe on the safe side.
107 */
108 for (count = 0; count < MAX_COUNT; count++) {
Simon Glassb697e0f2015-08-22 18:31:38 -0600109 rc = dm_i2c_read(dev, addr, buffer, len);
Vincent Palatinec34fa52013-04-12 11:04:36 +0000110 if (rc == 0)
111 break; /* break here to skip sleep */
Simon Glass42c8ec52015-08-22 18:31:30 -0600112 udelay(SLEEP_DURATION_US);
Vincent Palatinec34fa52013-04-12 11:04:36 +0000113 }
Rong Changf6267992013-04-12 10:44:57 +0000114 }
115
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000116 /* Take care of 'guard time' */
Simon Glass42c8ec52015-08-22 18:31:30 -0600117 udelay(SLEEP_DURATION_US);
Rong Changf6267992013-04-12 10:44:57 +0000118 if (rc)
Simon Glassb697e0f2015-08-22 18:31:38 -0600119 return rc;
Rong Changf6267992013-04-12 10:44:57 +0000120
121 return 0;
122}
123
Simon Glassb697e0f2015-08-22 18:31:38 -0600124static int tpm_tis_i2c_write_generic(struct udevice *dev, u8 addr,
125 const u8 *buffer, size_t len,
Simon Glass42c8ec52015-08-22 18:31:30 -0600126 unsigned int sleep_time_us, u8 max_count)
Rong Changf6267992013-04-12 10:44:57 +0000127{
Simon Glassb697e0f2015-08-22 18:31:38 -0600128 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
129 struct tpm_chip *chip = dev_get_priv(dev);
Rong Changf6267992013-04-12 10:44:57 +0000130 int rc = 0;
131 int count;
132
Simon Glassb697e0f2015-08-22 18:31:38 -0600133 if (chip->chip_type == SLB9635) {
134 /* Prepare send buffer to include the address */
135 priv->buf[0] = addr;
136 memcpy(&(priv->buf[1]), buffer, len);
137 buffer = priv->buf;
138 len++;
139 addr = 0;
140 }
141
Rong Changf6267992013-04-12 10:44:57 +0000142 for (count = 0; count < max_count; count++) {
Simon Glassb697e0f2015-08-22 18:31:38 -0600143 rc = dm_i2c_write(dev, addr, buffer, len);
Rong Changf6267992013-04-12 10:44:57 +0000144 if (rc == 0)
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000145 break; /* Success, break to skip sleep */
Simon Glass42c8ec52015-08-22 18:31:30 -0600146 udelay(sleep_time_us);
Rong Changf6267992013-04-12 10:44:57 +0000147 }
148
Vincent Palatinec34fa52013-04-12 11:04:36 +0000149 /* take care of 'guard time' */
Simon Glass42c8ec52015-08-22 18:31:30 -0600150 udelay(sleep_time_us);
Rong Changf6267992013-04-12 10:44:57 +0000151 if (rc)
Simon Glassb697e0f2015-08-22 18:31:38 -0600152 return rc;
Rong Changf6267992013-04-12 10:44:57 +0000153
154 return 0;
155}
156
157/*
Simon Glasse56e20e2015-08-22 18:31:29 -0600158 * tpm_tis_i2c_write() - write to TPM register
Rong Changf6267992013-04-12 10:44:57 +0000159 * @addr: register address to write to
160 * @buffer: containing data to be written
161 * @len: number of bytes to write
162 *
163 * Write len bytes from provided buffer to TPM register (little
164 * endian format, i.e. buffer[0] is written as first byte).
165 *
166 * NOTE: TPM is big-endian for multi-byte values. Multi-byte
167 * values have to be swapped.
168 *
Simon Glasse56e20e2015-08-22 18:31:29 -0600169 * NOTE: use this function instead of the tpm_tis_i2c_write_generic function.
Rong Changf6267992013-04-12 10:44:57 +0000170 *
171 * Return -EIO on error, 0 on success
172 */
Simon Glassb697e0f2015-08-22 18:31:38 -0600173static int tpm_tis_i2c_write(struct udevice *dev, u8 addr, const u8 *buffer,
174 size_t len)
Rong Changf6267992013-04-12 10:44:57 +0000175{
Simon Glassb697e0f2015-08-22 18:31:38 -0600176 return tpm_tis_i2c_write_generic(dev, addr, buffer, len,
177 SLEEP_DURATION_US, MAX_COUNT);
Rong Changf6267992013-04-12 10:44:57 +0000178}
179
180/*
181 * This function is needed especially for the cleanup situation after
182 * sending TPM_READY
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000183 */
Simon Glassb697e0f2015-08-22 18:31:38 -0600184static int tpm_tis_i2c_write_long(struct udevice *dev, u8 addr, u8 *buffer,
185 size_t len)
Rong Changf6267992013-04-12 10:44:57 +0000186{
Simon Glassb697e0f2015-08-22 18:31:38 -0600187 return tpm_tis_i2c_write_generic(dev, addr, buffer, len,
Simon Glass42c8ec52015-08-22 18:31:30 -0600188 SLEEP_DURATION_LONG_US,
189 MAX_COUNT_LONG);
Rong Changf6267992013-04-12 10:44:57 +0000190}
191
Simon Glassb697e0f2015-08-22 18:31:38 -0600192static int tpm_tis_i2c_check_locality(struct udevice *dev, int loc)
Rong Changf6267992013-04-12 10:44:57 +0000193{
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000194 const u8 mask = TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID;
Simon Glassb697e0f2015-08-22 18:31:38 -0600195 struct tpm_chip *chip = dev_get_priv(dev);
Rong Changf6267992013-04-12 10:44:57 +0000196 u8 buf;
197 int rc;
198
Simon Glassb697e0f2015-08-22 18:31:38 -0600199 rc = tpm_tis_i2c_read(dev, TPM_ACCESS(loc), &buf, 1);
Rong Changf6267992013-04-12 10:44:57 +0000200 if (rc < 0)
201 return rc;
202
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000203 if ((buf & mask) == mask) {
Simon Glass7c735372015-08-22 18:31:24 -0600204 chip->locality = loc;
Rong Changf6267992013-04-12 10:44:57 +0000205 return loc;
206 }
207
Simon Glassb697e0f2015-08-22 18:31:38 -0600208 return -ENOENT;
Rong Changf6267992013-04-12 10:44:57 +0000209}
210
Simon Glassb697e0f2015-08-22 18:31:38 -0600211static void tpm_tis_i2c_release_locality(struct udevice *dev, int loc,
Simon Glasse56e20e2015-08-22 18:31:29 -0600212 int force)
Rong Changf6267992013-04-12 10:44:57 +0000213{
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000214 const u8 mask = TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID;
Rong Changf6267992013-04-12 10:44:57 +0000215 u8 buf;
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000216
Simon Glassb697e0f2015-08-22 18:31:38 -0600217 if (tpm_tis_i2c_read(dev, TPM_ACCESS(loc), &buf, 1) < 0)
Rong Changf6267992013-04-12 10:44:57 +0000218 return;
219
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000220 if (force || (buf & mask) == mask) {
Rong Changf6267992013-04-12 10:44:57 +0000221 buf = TPM_ACCESS_ACTIVE_LOCALITY;
Simon Glassb697e0f2015-08-22 18:31:38 -0600222 tpm_tis_i2c_write(dev, TPM_ACCESS(loc), &buf, 1);
Rong Changf6267992013-04-12 10:44:57 +0000223 }
224}
225
Simon Glassb697e0f2015-08-22 18:31:38 -0600226static int tpm_tis_i2c_request_locality(struct udevice *dev, int loc)
Rong Changf6267992013-04-12 10:44:57 +0000227{
Simon Glassb697e0f2015-08-22 18:31:38 -0600228 struct tpm_chip *chip = dev_get_priv(dev);
Rong Changf6267992013-04-12 10:44:57 +0000229 unsigned long start, stop;
230 u8 buf = TPM_ACCESS_REQUEST_USE;
Simon Glassf90acf12015-05-04 11:30:59 -0600231 int rc;
Rong Changf6267992013-04-12 10:44:57 +0000232
Simon Glassb697e0f2015-08-22 18:31:38 -0600233 rc = tpm_tis_i2c_check_locality(dev, loc);
234 if (rc >= 0) {
235 debug("%s: Already have locality\n", __func__);
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000236 return loc; /* We already have the locality */
Simon Glassb697e0f2015-08-22 18:31:38 -0600237 } else if (rc != -ENOENT) {
238 debug("%s: Failed to get locality: %d\n", __func__, rc);
Simon Glassf90acf12015-05-04 11:30:59 -0600239 return rc;
Simon Glassb697e0f2015-08-22 18:31:38 -0600240 }
241
242 rc = tpm_tis_i2c_write(dev, TPM_ACCESS(loc), &buf, 1);
243 if (rc) {
244 debug("%s: Failed to write to TPM: %d\n", __func__, rc);
245 return rc;
246 }
Rong Changf6267992013-04-12 10:44:57 +0000247
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000248 /* Wait for burstcount */
Rong Changf6267992013-04-12 10:44:57 +0000249 start = get_timer(0);
Simon Glass7c735372015-08-22 18:31:24 -0600250 stop = chip->timeout_a;
Rong Changf6267992013-04-12 10:44:57 +0000251 do {
Simon Glassb697e0f2015-08-22 18:31:38 -0600252 rc = tpm_tis_i2c_check_locality(dev, loc);
253 if (rc >= 0) {
254 debug("%s: Have locality\n", __func__);
Rong Changf6267992013-04-12 10:44:57 +0000255 return loc;
Simon Glassb697e0f2015-08-22 18:31:38 -0600256 } else if (rc != -ENOENT) {
257 debug("%s: Failed to get locality: %d\n", __func__, rc);
258 return rc;
259 }
Simon Glass42c8ec52015-08-22 18:31:30 -0600260 mdelay(TPM_TIMEOUT_MS);
Rong Changf6267992013-04-12 10:44:57 +0000261 } while (get_timer(start) < stop);
Simon Glassb697e0f2015-08-22 18:31:38 -0600262 debug("%s: Timeout getting locality: %d\n", __func__, rc);
Rong Changf6267992013-04-12 10:44:57 +0000263
Simon Glassb697e0f2015-08-22 18:31:38 -0600264 return rc;
Rong Changf6267992013-04-12 10:44:57 +0000265}
266
Simon Glassb697e0f2015-08-22 18:31:38 -0600267static u8 tpm_tis_i2c_status(struct udevice *dev)
Rong Changf6267992013-04-12 10:44:57 +0000268{
Simon Glassb697e0f2015-08-22 18:31:38 -0600269 struct tpm_chip *chip = dev_get_priv(dev);
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000270 /* NOTE: Since i2c read may fail, return 0 in this case --> time-out */
Rong Changf6267992013-04-12 10:44:57 +0000271 u8 buf;
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000272
Simon Glassb697e0f2015-08-22 18:31:38 -0600273 if (tpm_tis_i2c_read(dev, TPM_STS(chip->locality), &buf, 1) < 0)
Rong Changf6267992013-04-12 10:44:57 +0000274 return 0;
275 else
276 return buf;
277}
278
Simon Glassb697e0f2015-08-22 18:31:38 -0600279static int tpm_tis_i2c_ready(struct udevice *dev)
Rong Changf6267992013-04-12 10:44:57 +0000280{
Simon Glassb697e0f2015-08-22 18:31:38 -0600281 struct tpm_chip *chip = dev_get_priv(dev);
Simon Glassf90acf12015-05-04 11:30:59 -0600282 int rc;
283
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000284 /* This causes the current command to be aborted */
Rong Changf6267992013-04-12 10:44:57 +0000285 u8 buf = TPM_STS_COMMAND_READY;
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000286
Simon Glassf90acf12015-05-04 11:30:59 -0600287 debug("%s\n", __func__);
Simon Glassb697e0f2015-08-22 18:31:38 -0600288 rc = tpm_tis_i2c_write_long(dev, TPM_STS(chip->locality), &buf, 1);
Simon Glassf90acf12015-05-04 11:30:59 -0600289 if (rc)
290 debug("%s: rc=%d\n", __func__, rc);
Simon Glassb697e0f2015-08-22 18:31:38 -0600291
292 return rc;
Rong Changf6267992013-04-12 10:44:57 +0000293}
294
Simon Glassb697e0f2015-08-22 18:31:38 -0600295static ssize_t tpm_tis_i2c_get_burstcount(struct udevice *dev)
Rong Changf6267992013-04-12 10:44:57 +0000296{
Simon Glassb697e0f2015-08-22 18:31:38 -0600297 struct tpm_chip *chip = dev_get_priv(dev);
Rong Changf6267992013-04-12 10:44:57 +0000298 unsigned long start, stop;
299 ssize_t burstcnt;
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000300 u8 addr, buf[3];
Rong Changf6267992013-04-12 10:44:57 +0000301
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000302 /* Wait for burstcount */
303 /* XXX: Which timeout value? Spec has 2 answers (c & d) */
Rong Changf6267992013-04-12 10:44:57 +0000304 start = get_timer(0);
Simon Glass7c735372015-08-22 18:31:24 -0600305 stop = chip->timeout_d;
Rong Changf6267992013-04-12 10:44:57 +0000306 do {
307 /* Note: STS is little endian */
Simon Glass7c735372015-08-22 18:31:24 -0600308 addr = TPM_STS(chip->locality) + 1;
Simon Glassb697e0f2015-08-22 18:31:38 -0600309 if (tpm_tis_i2c_read(dev, addr, buf, 3) < 0)
Rong Changf6267992013-04-12 10:44:57 +0000310 burstcnt = 0;
311 else
312 burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0];
313
314 if (burstcnt)
315 return burstcnt;
Simon Glass42c8ec52015-08-22 18:31:30 -0600316 mdelay(TPM_TIMEOUT_MS);
Rong Changf6267992013-04-12 10:44:57 +0000317 } while (get_timer(start) < stop);
318
319 return -EBUSY;
320}
321
Simon Glassb697e0f2015-08-22 18:31:38 -0600322static int tpm_tis_i2c_wait_for_stat(struct udevice *dev, u8 mask,
Simon Glasse56e20e2015-08-22 18:31:29 -0600323 unsigned long timeout, int *status)
Rong Changf6267992013-04-12 10:44:57 +0000324{
325 unsigned long start, stop;
326
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000327 /* Check current status */
Simon Glassb697e0f2015-08-22 18:31:38 -0600328 *status = tpm_tis_i2c_status(dev);
Rong Changf6267992013-04-12 10:44:57 +0000329 if ((*status & mask) == mask)
330 return 0;
331
332 start = get_timer(0);
333 stop = timeout;
334 do {
Simon Glass42c8ec52015-08-22 18:31:30 -0600335 mdelay(TPM_TIMEOUT_MS);
Simon Glassb697e0f2015-08-22 18:31:38 -0600336 *status = tpm_tis_i2c_status(dev);
Rong Changf6267992013-04-12 10:44:57 +0000337 if ((*status & mask) == mask)
338 return 0;
Rong Changf6267992013-04-12 10:44:57 +0000339 } while (get_timer(start) < stop);
340
Simon Glassb697e0f2015-08-22 18:31:38 -0600341 return -ETIMEDOUT;
Rong Changf6267992013-04-12 10:44:57 +0000342}
343
Simon Glassb697e0f2015-08-22 18:31:38 -0600344static int tpm_tis_i2c_recv_data(struct udevice *dev, u8 *buf, size_t count)
Rong Changf6267992013-04-12 10:44:57 +0000345{
Simon Glassb697e0f2015-08-22 18:31:38 -0600346 struct tpm_chip *chip = dev_get_priv(dev);
Rong Changf6267992013-04-12 10:44:57 +0000347 size_t size = 0;
348 ssize_t burstcnt;
349 int rc;
350
351 while (size < count) {
Simon Glassb697e0f2015-08-22 18:31:38 -0600352 burstcnt = tpm_tis_i2c_get_burstcount(dev);
Rong Changf6267992013-04-12 10:44:57 +0000353
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000354 /* burstcount < 0 -> tpm is busy */
Rong Changf6267992013-04-12 10:44:57 +0000355 if (burstcnt < 0)
356 return burstcnt;
357
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000358 /* Limit received data to max left */
Rong Changf6267992013-04-12 10:44:57 +0000359 if (burstcnt > (count - size))
360 burstcnt = count - size;
361
Simon Glassb697e0f2015-08-22 18:31:38 -0600362 rc = tpm_tis_i2c_read(dev, TPM_DATA_FIFO(chip->locality),
363 &(buf[size]), burstcnt);
Rong Changf6267992013-04-12 10:44:57 +0000364 if (rc == 0)
365 size += burstcnt;
366 }
367
368 return size;
369}
370
Simon Glassb697e0f2015-08-22 18:31:38 -0600371static int tpm_tis_i2c_recv(struct udevice *dev, u8 *buf, size_t count)
Rong Changf6267992013-04-12 10:44:57 +0000372{
Simon Glassb697e0f2015-08-22 18:31:38 -0600373 struct tpm_chip *chip = dev_get_priv(dev);
Rong Changf6267992013-04-12 10:44:57 +0000374 int size = 0;
Jeremy Booneafe0e6b2018-02-12 17:56:36 -0500375 int status;
376 unsigned int expected;
Simon Glassb697e0f2015-08-22 18:31:38 -0600377 int rc;
Rong Changf6267992013-04-12 10:44:57 +0000378
Simon Glassb697e0f2015-08-22 18:31:38 -0600379 status = tpm_tis_i2c_status(dev);
380 if (status == TPM_STS_COMMAND_READY)
381 return -EINTR;
382 if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) !=
383 (TPM_STS_DATA_AVAIL | TPM_STS_VALID))
384 return -EAGAIN;
385
386 debug("...got it;\n");
Rong Changf6267992013-04-12 10:44:57 +0000387
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000388 /* Read first 10 bytes, including tag, paramsize, and result */
Simon Glassb697e0f2015-08-22 18:31:38 -0600389 size = tpm_tis_i2c_recv_data(dev, buf, TPM_HEADER_SIZE);
Rong Changf6267992013-04-12 10:44:57 +0000390 if (size < TPM_HEADER_SIZE) {
Simon Glassb697e0f2015-08-22 18:31:38 -0600391 debug("Unable to read header\n");
392 return size < 0 ? size : -EIO;
Rong Changf6267992013-04-12 10:44:57 +0000393 }
394
395 expected = get_unaligned_be32(buf + TPM_RSP_SIZE_BYTE);
Jeremy Booneafe0e6b2018-02-12 17:56:36 -0500396 if ((size_t)expected > count || (size_t)expected < TPM_HEADER_SIZE) {
Simon Glassb697e0f2015-08-22 18:31:38 -0600397 debug("Error size=%x, expected=%x, count=%x\n", size, expected,
Simon Glassf90acf12015-05-04 11:30:59 -0600398 count);
Simon Glassb697e0f2015-08-22 18:31:38 -0600399 return -ENOSPC;
Rong Changf6267992013-04-12 10:44:57 +0000400 }
401
Simon Glassb697e0f2015-08-22 18:31:38 -0600402 size += tpm_tis_i2c_recv_data(dev, &buf[TPM_HEADER_SIZE],
Simon Glasse56e20e2015-08-22 18:31:29 -0600403 expected - TPM_HEADER_SIZE);
Rong Changf6267992013-04-12 10:44:57 +0000404 if (size < expected) {
Simon Glassb697e0f2015-08-22 18:31:38 -0600405 debug("Unable to read remainder of result\n");
406 return -ETIMEDOUT;
Rong Changf6267992013-04-12 10:44:57 +0000407 }
408
Simon Glassb697e0f2015-08-22 18:31:38 -0600409 rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID, chip->timeout_c,
410 &status);
411 if (rc)
412 return rc;
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000413 if (status & TPM_STS_DATA_AVAIL) { /* Retry? */
Simon Glassb697e0f2015-08-22 18:31:38 -0600414 debug("Error left over data\n");
415 return -EIO;
Rong Changf6267992013-04-12 10:44:57 +0000416 }
417
Rong Changf6267992013-04-12 10:44:57 +0000418 return size;
419}
420
Simon Glassb697e0f2015-08-22 18:31:38 -0600421static int tpm_tis_i2c_send(struct udevice *dev, const u8 *buf, size_t len)
Rong Changf6267992013-04-12 10:44:57 +0000422{
Simon Glassb697e0f2015-08-22 18:31:38 -0600423 struct tpm_chip *chip = dev_get_priv(dev);
Rong Changf6267992013-04-12 10:44:57 +0000424 int rc, status;
Simon Glassf90acf12015-05-04 11:30:59 -0600425 size_t burstcnt;
Rong Changf6267992013-04-12 10:44:57 +0000426 size_t count = 0;
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000427 int retry = 0;
Rong Changf6267992013-04-12 10:44:57 +0000428 u8 sts = TPM_STS_GO;
429
Simon Glassf90acf12015-05-04 11:30:59 -0600430 debug("%s: len=%d\n", __func__, len);
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000431 if (len > TPM_DEV_BUFSIZE)
432 return -E2BIG; /* Command is too long for our tpm, sorry */
Rong Changf6267992013-04-12 10:44:57 +0000433
Simon Glassb697e0f2015-08-22 18:31:38 -0600434 if (tpm_tis_i2c_request_locality(dev, 0) < 0)
Rong Changf6267992013-04-12 10:44:57 +0000435 return -EBUSY;
436
Simon Glassb697e0f2015-08-22 18:31:38 -0600437 status = tpm_tis_i2c_status(dev);
Rong Changf6267992013-04-12 10:44:57 +0000438 if ((status & TPM_STS_COMMAND_READY) == 0) {
Simon Glassb697e0f2015-08-22 18:31:38 -0600439 rc = tpm_tis_i2c_ready(dev);
440 if (rc)
441 return rc;
442 rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_COMMAND_READY,
443 chip->timeout_b, &status);
444 if (rc)
445 return rc;
Rong Changf6267992013-04-12 10:44:57 +0000446 }
447
Simon Glassb697e0f2015-08-22 18:31:38 -0600448 burstcnt = tpm_tis_i2c_get_burstcount(dev);
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000449
450 /* burstcount < 0 -> tpm is busy */
451 if (burstcnt < 0)
452 return burstcnt;
453
Simon Glassf90acf12015-05-04 11:30:59 -0600454 while (count < len) {
455 udelay(300);
456 if (burstcnt > len - count)
457 burstcnt = len - count;
Rong Changf6267992013-04-12 10:44:57 +0000458
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000459#ifdef CONFIG_TPM_TIS_I2C_BURST_LIMITATION
Simon Glassb697e0f2015-08-22 18:31:38 -0600460 if (retry && burstcnt > CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN)
461 burstcnt = CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN;
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000462#endif /* CONFIG_TPM_TIS_I2C_BURST_LIMITATION */
Rong Changf6267992013-04-12 10:44:57 +0000463
Simon Glassb697e0f2015-08-22 18:31:38 -0600464 rc = tpm_tis_i2c_write(dev, TPM_DATA_FIFO(chip->locality),
465 &(buf[count]), burstcnt);
Rong Changf6267992013-04-12 10:44:57 +0000466 if (rc == 0)
467 count += burstcnt;
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000468 else {
Simon Glassf90acf12015-05-04 11:30:59 -0600469 debug("%s: error\n", __func__);
Simon Glassb697e0f2015-08-22 18:31:38 -0600470 if (retry++ > 10)
471 return -EIO;
472 rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID,
Simon Glasse56e20e2015-08-22 18:31:29 -0600473 chip->timeout_c,
474 &status);
Simon Glassf90acf12015-05-04 11:30:59 -0600475 if (rc)
Simon Glassb697e0f2015-08-22 18:31:38 -0600476 return rc;
Rong Changf6267992013-04-12 10:44:57 +0000477
Simon Glassb697e0f2015-08-22 18:31:38 -0600478 if ((status & TPM_STS_DATA_EXPECT) == 0)
479 return -EIO;
Rong Changf6267992013-04-12 10:44:57 +0000480 }
481 }
482
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000483 /* Go and do it */
Simon Glassb697e0f2015-08-22 18:31:38 -0600484 rc = tpm_tis_i2c_write(dev, TPM_STS(chip->locality), &sts, 1);
485 if (rc < 0)
486 return rc;
487 debug("%s: done, rc=%d\n", __func__, rc);
Rong Changf6267992013-04-12 10:44:57 +0000488
489 return len;
Simon Glassb697e0f2015-08-22 18:31:38 -0600490}
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000491
Simon Glassb697e0f2015-08-22 18:31:38 -0600492static int tpm_tis_i2c_cleanup(struct udevice *dev)
493{
494 struct tpm_chip *chip = dev_get_priv(dev);
495
496 tpm_tis_i2c_ready(dev);
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000497 /*
498 * The TPM needs some time to clean up here,
Rong Changf6267992013-04-12 10:44:57 +0000499 * so we sleep rather than keeping the bus busy
500 */
Simon Glass42c8ec52015-08-22 18:31:30 -0600501 mdelay(2);
Simon Glassb697e0f2015-08-22 18:31:38 -0600502 tpm_tis_i2c_release_locality(dev, chip->locality, 0);
Rong Changf6267992013-04-12 10:44:57 +0000503
Simon Glassb697e0f2015-08-22 18:31:38 -0600504 return 0;
Vincent Palatinec34fa52013-04-12 11:04:36 +0000505}
506
Simon Glass13932b02015-08-22 18:31:25 -0600507static int tpm_tis_i2c_init(struct udevice *dev)
Rong Changf6267992013-04-12 10:44:57 +0000508{
Simon Glassb697e0f2015-08-22 18:31:38 -0600509 struct tpm_chip *chip = dev_get_priv(dev);
Rong Changf6267992013-04-12 10:44:57 +0000510 u32 vendor;
Vincent Palatinec34fa52013-04-12 11:04:36 +0000511 u32 expected_did_vid;
Simon Glassb697e0f2015-08-22 18:31:38 -0600512 int rc;
Rong Changf6267992013-04-12 10:44:57 +0000513
Simon Glass7c735372015-08-22 18:31:24 -0600514 chip->is_open = 1;
Rong Changf6267992013-04-12 10:44:57 +0000515
Simon Glasse56e20e2015-08-22 18:31:29 -0600516 /* Default timeouts - these could move to the device tree */
Simon Glass42c8ec52015-08-22 18:31:30 -0600517 chip->timeout_a = TIS_SHORT_TIMEOUT_MS;
518 chip->timeout_b = TIS_LONG_TIMEOUT_MS;
519 chip->timeout_c = TIS_SHORT_TIMEOUT_MS;
520 chip->timeout_d = TIS_SHORT_TIMEOUT_MS;
Rong Changf6267992013-04-12 10:44:57 +0000521
Simon Glassb697e0f2015-08-22 18:31:38 -0600522 rc = tpm_tis_i2c_request_locality(dev, 0);
523 if (rc < 0)
524 return rc;
Rong Changf6267992013-04-12 10:44:57 +0000525
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000526 /* Read four bytes from DID_VID register */
Simon Glassb697e0f2015-08-22 18:31:38 -0600527 if (tpm_tis_i2c_read(dev, TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) {
528 tpm_tis_i2c_release_locality(dev, 0, 1);
Simon Glassf90acf12015-05-04 11:30:59 -0600529 return -EIO;
Rong Changf6267992013-04-12 10:44:57 +0000530 }
531
Simon Glassb697e0f2015-08-22 18:31:38 -0600532 if (chip->chip_type == SLB9635) {
Vincent Palatinec34fa52013-04-12 11:04:36 +0000533 vendor = be32_to_cpu(vendor);
534 expected_did_vid = TPM_TIS_I2C_DID_VID_9635;
535 } else {
536 /* device id and byte order has changed for newer i2c tpms */
537 expected_did_vid = TPM_TIS_I2C_DID_VID_9645;
538 }
Rong Changf6267992013-04-12 10:44:57 +0000539
Simon Glassb697e0f2015-08-22 18:31:38 -0600540 if (chip->chip_type != UNKNOWN && vendor != expected_did_vid) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900541 pr_err("Vendor id did not match! ID was %08x\n", vendor);
Simon Glassf90acf12015-05-04 11:30:59 -0600542 return -ENODEV;
Rong Changf6267992013-04-12 10:44:57 +0000543 }
544
Simon Glassb697e0f2015-08-22 18:31:38 -0600545 chip->vend_dev = vendor;
Tom Wai-Hong Tam1b393db2013-04-12 11:04:37 +0000546 debug("1.2 TPM (chip type %s device-id 0x%X)\n",
Simon Glassb697e0f2015-08-22 18:31:38 -0600547 chip_name[chip->chip_type], vendor >> 16);
Rong Changf6267992013-04-12 10:44:57 +0000548
549 /*
550 * A timeout query to TPM can be placed here.
551 * Standard timeout values are used so far
552 */
553
554 return 0;
Simon Glassf90acf12015-05-04 11:30:59 -0600555}
Rong Changf6267992013-04-12 10:44:57 +0000556
Simon Glassb697e0f2015-08-22 18:31:38 -0600557static int tpm_tis_i2c_open(struct udevice *dev)
Simon Glass4cd7b782015-08-22 18:31:22 -0600558{
Simon Glassb697e0f2015-08-22 18:31:38 -0600559 struct tpm_chip *chip = dev_get_priv(dev);
Simon Glass4cd7b782015-08-22 18:31:22 -0600560 int rc;
Simon Glass4cd7b782015-08-22 18:31:22 -0600561
Simon Glassa53b79a2015-08-22 18:31:28 -0600562 debug("%s: start\n", __func__);
Simon Glassb697e0f2015-08-22 18:31:38 -0600563 if (chip->is_open)
Simon Glassa53b79a2015-08-22 18:31:28 -0600564 return -EBUSY;
Simon Glassb697e0f2015-08-22 18:31:38 -0600565 rc = tpm_tis_i2c_init(dev);
Simon Glassa53b79a2015-08-22 18:31:28 -0600566 if (rc < 0)
Simon Glassb697e0f2015-08-22 18:31:38 -0600567 chip->is_open = 0;
Simon Glass4cd7b782015-08-22 18:31:22 -0600568
569 return rc;
570}
571
Simon Glassb697e0f2015-08-22 18:31:38 -0600572static int tpm_tis_i2c_close(struct udevice *dev)
Simon Glass4cd7b782015-08-22 18:31:22 -0600573{
Simon Glassb697e0f2015-08-22 18:31:38 -0600574 struct tpm_chip *chip = dev_get_priv(dev);
Simon Glass4cd7b782015-08-22 18:31:22 -0600575
Simon Glassb697e0f2015-08-22 18:31:38 -0600576 if (chip->is_open) {
577 tpm_tis_i2c_release_locality(dev, chip->locality, 1);
578 chip->is_open = 0;
579 chip->vend_dev = 0;
Simon Glassa53b79a2015-08-22 18:31:28 -0600580 }
Simon Glass4cd7b782015-08-22 18:31:22 -0600581
582 return 0;
583}
584
Simon Glassb697e0f2015-08-22 18:31:38 -0600585static int tpm_tis_get_desc(struct udevice *dev, char *buf, int size)
Simon Glass4cd7b782015-08-22 18:31:22 -0600586{
Simon Glassb697e0f2015-08-22 18:31:38 -0600587 struct tpm_chip *chip = dev_get_priv(dev);
Simon Glass4cd7b782015-08-22 18:31:22 -0600588
Simon Glassb697e0f2015-08-22 18:31:38 -0600589 if (size < 50)
590 return -ENOSPC;
Simon Glass4cd7b782015-08-22 18:31:22 -0600591
Simon Glassb697e0f2015-08-22 18:31:38 -0600592 return snprintf(buf, size, "1.2 TPM (%s, chip type %s device-id 0x%x)",
593 chip->is_open ? "open" : "closed",
594 chip_name[chip->chip_type],
595 chip->vend_dev >> 16);
596}
Simon Glass4cd7b782015-08-22 18:31:22 -0600597
Simon Glassb697e0f2015-08-22 18:31:38 -0600598static int tpm_tis_i2c_probe(struct udevice *dev)
599{
600 struct tpm_chip_priv *uc_priv = dev_get_uclass_priv(dev);
601 struct tpm_chip *chip = dev_get_priv(dev);
Simon Glass4cd7b782015-08-22 18:31:22 -0600602
Simon Glassb697e0f2015-08-22 18:31:38 -0600603 chip->chip_type = dev_get_driver_data(dev);
Simon Glass4cd7b782015-08-22 18:31:22 -0600604
Simon Glassb697e0f2015-08-22 18:31:38 -0600605 /* TODO: These need to be checked and tuned */
606 uc_priv->duration_ms[TPM_SHORT] = TIS_SHORT_TIMEOUT_MS;
607 uc_priv->duration_ms[TPM_MEDIUM] = TIS_LONG_TIMEOUT_MS;
608 uc_priv->duration_ms[TPM_LONG] = TIS_LONG_TIMEOUT_MS;
609 uc_priv->retry_time_ms = TPM_TIMEOUT_MS;
Simon Glass4cd7b782015-08-22 18:31:22 -0600610
611 return 0;
612}
Simon Glassb697e0f2015-08-22 18:31:38 -0600613
614static const struct tpm_ops tpm_tis_i2c_ops = {
615 .open = tpm_tis_i2c_open,
616 .close = tpm_tis_i2c_close,
617 .get_desc = tpm_tis_get_desc,
618 .send = tpm_tis_i2c_send,
619 .recv = tpm_tis_i2c_recv,
620 .cleanup = tpm_tis_i2c_cleanup,
621};
622
623static const struct udevice_id tpm_tis_i2c_ids[] = {
624 { .compatible = "infineon,slb9635tt", .data = SLB9635 },
625 { .compatible = "infineon,slb9645tt", .data = SLB9645 },
626 { }
627};
628
629U_BOOT_DRIVER(tpm_tis_i2c) = {
Christophe Ricard0766ad22015-10-06 22:54:41 +0200630 .name = "tpm_tis_infineon",
Simon Glassb697e0f2015-08-22 18:31:38 -0600631 .id = UCLASS_TPM,
632 .of_match = tpm_tis_i2c_ids,
633 .ops = &tpm_tis_i2c_ops,
634 .probe = tpm_tis_i2c_probe,
635 .priv_auto_alloc_size = sizeof(struct tpm_chip),
636};