blob: 9afe46c1e90c28cd7f321be876eaf51c447260f8 [file] [log] [blame]
Rong Chang8faa9452013-04-12 10:44:57 +00001/*
2 * Copyright (C) 2011 Infineon Technologies
3 *
4 * Authors:
5 * Peter Huewe <huewe.external@infineon.com>
6 *
7 * Description:
8 * Device driver for TCG/TCPA TPM (trusted platform module).
9 * Specifications at www.trustedcomputinggroup.org
10 *
11 * This device driver implements the TPM interface as defined in
12 * the TCG TPM Interface Spec version 1.2, revision 1.0 and the
13 * Infineon I2C Protocol Stack Specification v0.20.
14 *
15 * It is based on the Linux kernel driver tpm.c from Leendert van
16 * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall.
17 *
18 * Version: 2.1.1
19 *
Simon Glassc98f7fe2015-08-22 18:31:21 -060020 * SPDX-License-Identifier: GPL-2.0
Rong Chang8faa9452013-04-12 10:44:57 +000021 */
22
23#include <common.h>
Simon Glassc9a3e842015-05-04 11:30:59 -060024#include <dm.h>
Vincent Palatin06883eb2013-04-12 11:04:36 +000025#include <fdtdec.h>
Rong Chang8faa9452013-04-12 10:44:57 +000026#include <i2c.h>
Simon Glass6c7a2322015-08-22 18:31:31 -060027#include <tis.h>
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +000028#include <tpm.h>
29#include <asm-generic/errno.h>
Simon Glasscd8cc672015-08-22 18:31:38 -060030#include <linux/compiler.h>
Rong Chang8faa9452013-04-12 10:44:57 +000031#include <linux/types.h>
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +000032#include <linux/unaligned/be_byteshift.h>
Rong Chang8faa9452013-04-12 10:44:57 +000033
Simon Glass94576272015-08-22 18:31:22 -060034#include "tpm_tis_i2c.h"
Simon Glass6c7a2322015-08-22 18:31:31 -060035#include "tpm_internal.h"
Rong Chang8faa9452013-04-12 10:44:57 +000036
Vincent Palatin06883eb2013-04-12 11:04:36 +000037DECLARE_GLOBAL_DATA_PTR;
38
Vincent Palatin06883eb2013-04-12 11:04:36 +000039static const char * const chip_name[] = {
40 [SLB9635] = "slb9635tt",
41 [SLB9645] = "slb9645tt",
42 [UNKNOWN] = "unknown/fallback to slb9635",
43};
Rong Chang8faa9452013-04-12 10:44:57 +000044
Rong Chang8faa9452013-04-12 10:44:57 +000045/*
Simon Glass7ccebaf2015-08-22 18:31:29 -060046 * tpm_tis_i2c_read() - read from TPM register
Rong Chang8faa9452013-04-12 10:44:57 +000047 * @addr: register address to read from
48 * @buffer: provided by caller
49 * @len: number of bytes to read
50 *
51 * Read len bytes from TPM register and put them into
52 * buffer (little-endian format, i.e. first byte is put into buffer[0]).
53 *
54 * NOTE: TPM is big-endian for multi-byte values. Multi-byte
55 * values have to be swapped.
56 *
57 * Return -EIO on error, 0 on success.
58 */
Simon Glasscd8cc672015-08-22 18:31:38 -060059static int tpm_tis_i2c_read(struct udevice *dev, u8 addr, u8 *buffer,
60 size_t len)
Rong Chang8faa9452013-04-12 10:44:57 +000061{
Simon Glasscd8cc672015-08-22 18:31:38 -060062 struct tpm_chip *chip = dev_get_priv(dev);
Rong Chang8faa9452013-04-12 10:44:57 +000063 int rc;
64 int count;
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +000065 uint32_t addrbuf = addr;
Rong Chang8faa9452013-04-12 10:44:57 +000066
Simon Glasscd8cc672015-08-22 18:31:38 -060067 if ((chip->chip_type == SLB9635) || (chip->chip_type == UNKNOWN)) {
Vincent Palatin06883eb2013-04-12 11:04:36 +000068 /* slb9635 protocol should work in both cases */
69 for (count = 0; count < MAX_COUNT; count++) {
Simon Glasscd8cc672015-08-22 18:31:38 -060070 rc = dm_i2c_write(dev, 0, (uchar *)&addrbuf, 1);
Vincent Palatin06883eb2013-04-12 11:04:36 +000071 if (rc == 0)
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +000072 break; /* Success, break to skip sleep */
Simon Glassa57bcee2015-08-22 18:31:30 -060073 udelay(SLEEP_DURATION_US);
Vincent Palatin06883eb2013-04-12 11:04:36 +000074 }
Vincent Palatin06883eb2013-04-12 11:04:36 +000075 if (rc)
Simon Glasscd8cc672015-08-22 18:31:38 -060076 return rc;
Rong Chang8faa9452013-04-12 10:44:57 +000077
Vincent Palatin06883eb2013-04-12 11:04:36 +000078 /* After the TPM has successfully received the register address
79 * it needs some time, thus we're sleeping here again, before
80 * retrieving the data
81 */
82 for (count = 0; count < MAX_COUNT; count++) {
Simon Glassa57bcee2015-08-22 18:31:30 -060083 udelay(SLEEP_DURATION_US);
Simon Glasscd8cc672015-08-22 18:31:38 -060084 rc = dm_i2c_read(dev, 0, buffer, len);
Vincent Palatin06883eb2013-04-12 11:04:36 +000085 if (rc == 0)
86 break; /* success, break to skip sleep */
87 }
88 } else {
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +000089 /*
90 * Use a combined read for newer chips.
91 * Unfortunately the smbus functions are not suitable due to
Vincent Palatin06883eb2013-04-12 11:04:36 +000092 * the 32 byte limit of the smbus.
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +000093 * Retries should usually not be needed, but are kept just to
Vincent Palatin06883eb2013-04-12 11:04:36 +000094 * be safe on the safe side.
95 */
96 for (count = 0; count < MAX_COUNT; count++) {
Simon Glasscd8cc672015-08-22 18:31:38 -060097 rc = dm_i2c_read(dev, addr, buffer, len);
Vincent Palatin06883eb2013-04-12 11:04:36 +000098 if (rc == 0)
99 break; /* break here to skip sleep */
Simon Glassa57bcee2015-08-22 18:31:30 -0600100 udelay(SLEEP_DURATION_US);
Vincent Palatin06883eb2013-04-12 11:04:36 +0000101 }
Rong Chang8faa9452013-04-12 10:44:57 +0000102 }
103
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000104 /* Take care of 'guard time' */
Simon Glassa57bcee2015-08-22 18:31:30 -0600105 udelay(SLEEP_DURATION_US);
Rong Chang8faa9452013-04-12 10:44:57 +0000106 if (rc)
Simon Glasscd8cc672015-08-22 18:31:38 -0600107 return rc;
Rong Chang8faa9452013-04-12 10:44:57 +0000108
109 return 0;
110}
111
Simon Glasscd8cc672015-08-22 18:31:38 -0600112static int tpm_tis_i2c_write_generic(struct udevice *dev, u8 addr,
113 const u8 *buffer, size_t len,
Simon Glassa57bcee2015-08-22 18:31:30 -0600114 unsigned int sleep_time_us, u8 max_count)
Rong Chang8faa9452013-04-12 10:44:57 +0000115{
Simon Glasscd8cc672015-08-22 18:31:38 -0600116 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
117 struct tpm_chip *chip = dev_get_priv(dev);
Rong Chang8faa9452013-04-12 10:44:57 +0000118 int rc = 0;
119 int count;
120
Simon Glasscd8cc672015-08-22 18:31:38 -0600121 if (chip->chip_type == SLB9635) {
122 /* Prepare send buffer to include the address */
123 priv->buf[0] = addr;
124 memcpy(&(priv->buf[1]), buffer, len);
125 buffer = priv->buf;
126 len++;
127 addr = 0;
128 }
129
Rong Chang8faa9452013-04-12 10:44:57 +0000130 for (count = 0; count < max_count; count++) {
Simon Glasscd8cc672015-08-22 18:31:38 -0600131 rc = dm_i2c_write(dev, addr, buffer, len);
Rong Chang8faa9452013-04-12 10:44:57 +0000132 if (rc == 0)
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000133 break; /* Success, break to skip sleep */
Simon Glassa57bcee2015-08-22 18:31:30 -0600134 udelay(sleep_time_us);
Rong Chang8faa9452013-04-12 10:44:57 +0000135 }
136
Vincent Palatin06883eb2013-04-12 11:04:36 +0000137 /* take care of 'guard time' */
Simon Glassa57bcee2015-08-22 18:31:30 -0600138 udelay(sleep_time_us);
Rong Chang8faa9452013-04-12 10:44:57 +0000139 if (rc)
Simon Glasscd8cc672015-08-22 18:31:38 -0600140 return rc;
Rong Chang8faa9452013-04-12 10:44:57 +0000141
142 return 0;
143}
144
145/*
Simon Glass7ccebaf2015-08-22 18:31:29 -0600146 * tpm_tis_i2c_write() - write to TPM register
Rong Chang8faa9452013-04-12 10:44:57 +0000147 * @addr: register address to write to
148 * @buffer: containing data to be written
149 * @len: number of bytes to write
150 *
151 * Write len bytes from provided buffer to TPM register (little
152 * endian format, i.e. buffer[0] is written as first byte).
153 *
154 * NOTE: TPM is big-endian for multi-byte values. Multi-byte
155 * values have to be swapped.
156 *
Simon Glass7ccebaf2015-08-22 18:31:29 -0600157 * NOTE: use this function instead of the tpm_tis_i2c_write_generic function.
Rong Chang8faa9452013-04-12 10:44:57 +0000158 *
159 * Return -EIO on error, 0 on success
160 */
Simon Glasscd8cc672015-08-22 18:31:38 -0600161static int tpm_tis_i2c_write(struct udevice *dev, u8 addr, const u8 *buffer,
162 size_t len)
Rong Chang8faa9452013-04-12 10:44:57 +0000163{
Simon Glasscd8cc672015-08-22 18:31:38 -0600164 return tpm_tis_i2c_write_generic(dev, addr, buffer, len,
165 SLEEP_DURATION_US, MAX_COUNT);
Rong Chang8faa9452013-04-12 10:44:57 +0000166}
167
168/*
169 * This function is needed especially for the cleanup situation after
170 * sending TPM_READY
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000171 */
Simon Glasscd8cc672015-08-22 18:31:38 -0600172static int tpm_tis_i2c_write_long(struct udevice *dev, u8 addr, u8 *buffer,
173 size_t len)
Rong Chang8faa9452013-04-12 10:44:57 +0000174{
Simon Glasscd8cc672015-08-22 18:31:38 -0600175 return tpm_tis_i2c_write_generic(dev, addr, buffer, len,
Simon Glassa57bcee2015-08-22 18:31:30 -0600176 SLEEP_DURATION_LONG_US,
177 MAX_COUNT_LONG);
Rong Chang8faa9452013-04-12 10:44:57 +0000178}
179
Simon Glasscd8cc672015-08-22 18:31:38 -0600180static int tpm_tis_i2c_check_locality(struct udevice *dev, int loc)
Rong Chang8faa9452013-04-12 10:44:57 +0000181{
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000182 const u8 mask = TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID;
Simon Glasscd8cc672015-08-22 18:31:38 -0600183 struct tpm_chip *chip = dev_get_priv(dev);
Rong Chang8faa9452013-04-12 10:44:57 +0000184 u8 buf;
185 int rc;
186
Simon Glasscd8cc672015-08-22 18:31:38 -0600187 rc = tpm_tis_i2c_read(dev, TPM_ACCESS(loc), &buf, 1);
Rong Chang8faa9452013-04-12 10:44:57 +0000188 if (rc < 0)
189 return rc;
190
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000191 if ((buf & mask) == mask) {
Simon Glassab79b002015-08-22 18:31:24 -0600192 chip->locality = loc;
Rong Chang8faa9452013-04-12 10:44:57 +0000193 return loc;
194 }
195
Simon Glasscd8cc672015-08-22 18:31:38 -0600196 return -ENOENT;
Rong Chang8faa9452013-04-12 10:44:57 +0000197}
198
Simon Glasscd8cc672015-08-22 18:31:38 -0600199static void tpm_tis_i2c_release_locality(struct udevice *dev, int loc,
Simon Glass7ccebaf2015-08-22 18:31:29 -0600200 int force)
Rong Chang8faa9452013-04-12 10:44:57 +0000201{
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000202 const u8 mask = TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID;
Rong Chang8faa9452013-04-12 10:44:57 +0000203 u8 buf;
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000204
Simon Glasscd8cc672015-08-22 18:31:38 -0600205 if (tpm_tis_i2c_read(dev, TPM_ACCESS(loc), &buf, 1) < 0)
Rong Chang8faa9452013-04-12 10:44:57 +0000206 return;
207
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000208 if (force || (buf & mask) == mask) {
Rong Chang8faa9452013-04-12 10:44:57 +0000209 buf = TPM_ACCESS_ACTIVE_LOCALITY;
Simon Glasscd8cc672015-08-22 18:31:38 -0600210 tpm_tis_i2c_write(dev, TPM_ACCESS(loc), &buf, 1);
Rong Chang8faa9452013-04-12 10:44:57 +0000211 }
212}
213
Simon Glasscd8cc672015-08-22 18:31:38 -0600214static int tpm_tis_i2c_request_locality(struct udevice *dev, int loc)
Rong Chang8faa9452013-04-12 10:44:57 +0000215{
Simon Glasscd8cc672015-08-22 18:31:38 -0600216 struct tpm_chip *chip = dev_get_priv(dev);
Rong Chang8faa9452013-04-12 10:44:57 +0000217 unsigned long start, stop;
218 u8 buf = TPM_ACCESS_REQUEST_USE;
Simon Glassc9a3e842015-05-04 11:30:59 -0600219 int rc;
Rong Chang8faa9452013-04-12 10:44:57 +0000220
Simon Glasscd8cc672015-08-22 18:31:38 -0600221 rc = tpm_tis_i2c_check_locality(dev, loc);
222 if (rc >= 0) {
223 debug("%s: Already have locality\n", __func__);
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000224 return loc; /* We already have the locality */
Simon Glasscd8cc672015-08-22 18:31:38 -0600225 } else if (rc != -ENOENT) {
226 debug("%s: Failed to get locality: %d\n", __func__, rc);
227 return rc;
228 }
Rong Chang8faa9452013-04-12 10:44:57 +0000229
Simon Glasscd8cc672015-08-22 18:31:38 -0600230 rc = tpm_tis_i2c_write(dev, TPM_ACCESS(loc), &buf, 1);
231 if (rc) {
232 debug("%s: Failed to write to TPM: %d\n", __func__, rc);
Simon Glassc9a3e842015-05-04 11:30:59 -0600233 return rc;
Simon Glasscd8cc672015-08-22 18:31:38 -0600234 }
Rong Chang8faa9452013-04-12 10:44:57 +0000235
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000236 /* Wait for burstcount */
Rong Chang8faa9452013-04-12 10:44:57 +0000237 start = get_timer(0);
Simon Glassab79b002015-08-22 18:31:24 -0600238 stop = chip->timeout_a;
Rong Chang8faa9452013-04-12 10:44:57 +0000239 do {
Simon Glasscd8cc672015-08-22 18:31:38 -0600240 rc = tpm_tis_i2c_check_locality(dev, loc);
241 if (rc >= 0) {
242 debug("%s: Have locality\n", __func__);
Rong Chang8faa9452013-04-12 10:44:57 +0000243 return loc;
Simon Glasscd8cc672015-08-22 18:31:38 -0600244 } else if (rc != -ENOENT) {
245 debug("%s: Failed to get locality: %d\n", __func__, rc);
246 return rc;
247 }
Simon Glassa57bcee2015-08-22 18:31:30 -0600248 mdelay(TPM_TIMEOUT_MS);
Rong Chang8faa9452013-04-12 10:44:57 +0000249 } while (get_timer(start) < stop);
Simon Glasscd8cc672015-08-22 18:31:38 -0600250 debug("%s: Timeout getting locality: %d\n", __func__, rc);
Rong Chang8faa9452013-04-12 10:44:57 +0000251
Simon Glasscd8cc672015-08-22 18:31:38 -0600252 return rc;
Rong Chang8faa9452013-04-12 10:44:57 +0000253}
254
Simon Glasscd8cc672015-08-22 18:31:38 -0600255static u8 tpm_tis_i2c_status(struct udevice *dev)
Rong Chang8faa9452013-04-12 10:44:57 +0000256{
Simon Glasscd8cc672015-08-22 18:31:38 -0600257 struct tpm_chip *chip = dev_get_priv(dev);
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000258 /* NOTE: Since i2c read may fail, return 0 in this case --> time-out */
Rong Chang8faa9452013-04-12 10:44:57 +0000259 u8 buf;
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000260
Simon Glasscd8cc672015-08-22 18:31:38 -0600261 if (tpm_tis_i2c_read(dev, TPM_STS(chip->locality), &buf, 1) < 0)
Rong Chang8faa9452013-04-12 10:44:57 +0000262 return 0;
263 else
264 return buf;
265}
266
Simon Glasscd8cc672015-08-22 18:31:38 -0600267static int tpm_tis_i2c_ready(struct udevice *dev)
Rong Chang8faa9452013-04-12 10:44:57 +0000268{
Simon Glasscd8cc672015-08-22 18:31:38 -0600269 struct tpm_chip *chip = dev_get_priv(dev);
Simon Glassc9a3e842015-05-04 11:30:59 -0600270 int rc;
271
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000272 /* This causes the current command to be aborted */
Rong Chang8faa9452013-04-12 10:44:57 +0000273 u8 buf = TPM_STS_COMMAND_READY;
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000274
Simon Glassc9a3e842015-05-04 11:30:59 -0600275 debug("%s\n", __func__);
Simon Glasscd8cc672015-08-22 18:31:38 -0600276 rc = tpm_tis_i2c_write_long(dev, TPM_STS(chip->locality), &buf, 1);
Simon Glassc9a3e842015-05-04 11:30:59 -0600277 if (rc)
278 debug("%s: rc=%d\n", __func__, rc);
Simon Glasscd8cc672015-08-22 18:31:38 -0600279
280 return rc;
Rong Chang8faa9452013-04-12 10:44:57 +0000281}
282
Simon Glasscd8cc672015-08-22 18:31:38 -0600283static ssize_t tpm_tis_i2c_get_burstcount(struct udevice *dev)
Rong Chang8faa9452013-04-12 10:44:57 +0000284{
Simon Glasscd8cc672015-08-22 18:31:38 -0600285 struct tpm_chip *chip = dev_get_priv(dev);
Rong Chang8faa9452013-04-12 10:44:57 +0000286 unsigned long start, stop;
287 ssize_t burstcnt;
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000288 u8 addr, buf[3];
Rong Chang8faa9452013-04-12 10:44:57 +0000289
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000290 /* Wait for burstcount */
291 /* XXX: Which timeout value? Spec has 2 answers (c & d) */
Rong Chang8faa9452013-04-12 10:44:57 +0000292 start = get_timer(0);
Simon Glassab79b002015-08-22 18:31:24 -0600293 stop = chip->timeout_d;
Rong Chang8faa9452013-04-12 10:44:57 +0000294 do {
295 /* Note: STS is little endian */
Simon Glassab79b002015-08-22 18:31:24 -0600296 addr = TPM_STS(chip->locality) + 1;
Simon Glasscd8cc672015-08-22 18:31:38 -0600297 if (tpm_tis_i2c_read(dev, addr, buf, 3) < 0)
Rong Chang8faa9452013-04-12 10:44:57 +0000298 burstcnt = 0;
299 else
300 burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0];
301
302 if (burstcnt)
303 return burstcnt;
Simon Glassa57bcee2015-08-22 18:31:30 -0600304 mdelay(TPM_TIMEOUT_MS);
Rong Chang8faa9452013-04-12 10:44:57 +0000305 } while (get_timer(start) < stop);
306
307 return -EBUSY;
308}
309
Simon Glasscd8cc672015-08-22 18:31:38 -0600310static int tpm_tis_i2c_wait_for_stat(struct udevice *dev, u8 mask,
Simon Glass7ccebaf2015-08-22 18:31:29 -0600311 unsigned long timeout, int *status)
Rong Chang8faa9452013-04-12 10:44:57 +0000312{
313 unsigned long start, stop;
314
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000315 /* Check current status */
Simon Glasscd8cc672015-08-22 18:31:38 -0600316 *status = tpm_tis_i2c_status(dev);
Rong Chang8faa9452013-04-12 10:44:57 +0000317 if ((*status & mask) == mask)
318 return 0;
319
320 start = get_timer(0);
321 stop = timeout;
322 do {
Simon Glassa57bcee2015-08-22 18:31:30 -0600323 mdelay(TPM_TIMEOUT_MS);
Simon Glasscd8cc672015-08-22 18:31:38 -0600324 *status = tpm_tis_i2c_status(dev);
Rong Chang8faa9452013-04-12 10:44:57 +0000325 if ((*status & mask) == mask)
326 return 0;
Rong Chang8faa9452013-04-12 10:44:57 +0000327 } while (get_timer(start) < stop);
328
Simon Glasscd8cc672015-08-22 18:31:38 -0600329 return -ETIMEDOUT;
Rong Chang8faa9452013-04-12 10:44:57 +0000330}
331
Simon Glasscd8cc672015-08-22 18:31:38 -0600332static int tpm_tis_i2c_recv_data(struct udevice *dev, u8 *buf, size_t count)
Rong Chang8faa9452013-04-12 10:44:57 +0000333{
Simon Glasscd8cc672015-08-22 18:31:38 -0600334 struct tpm_chip *chip = dev_get_priv(dev);
Rong Chang8faa9452013-04-12 10:44:57 +0000335 size_t size = 0;
336 ssize_t burstcnt;
337 int rc;
338
339 while (size < count) {
Simon Glasscd8cc672015-08-22 18:31:38 -0600340 burstcnt = tpm_tis_i2c_get_burstcount(dev);
Rong Chang8faa9452013-04-12 10:44:57 +0000341
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000342 /* burstcount < 0 -> tpm is busy */
Rong Chang8faa9452013-04-12 10:44:57 +0000343 if (burstcnt < 0)
344 return burstcnt;
345
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000346 /* Limit received data to max left */
Rong Chang8faa9452013-04-12 10:44:57 +0000347 if (burstcnt > (count - size))
348 burstcnt = count - size;
349
Simon Glasscd8cc672015-08-22 18:31:38 -0600350 rc = tpm_tis_i2c_read(dev, TPM_DATA_FIFO(chip->locality),
351 &(buf[size]), burstcnt);
Rong Chang8faa9452013-04-12 10:44:57 +0000352 if (rc == 0)
353 size += burstcnt;
354 }
355
356 return size;
357}
358
Simon Glasscd8cc672015-08-22 18:31:38 -0600359static int tpm_tis_i2c_recv(struct udevice *dev, u8 *buf, size_t count)
Rong Chang8faa9452013-04-12 10:44:57 +0000360{
Simon Glasscd8cc672015-08-22 18:31:38 -0600361 struct tpm_chip *chip = dev_get_priv(dev);
Rong Chang8faa9452013-04-12 10:44:57 +0000362 int size = 0;
363 int expected, status;
Simon Glasscd8cc672015-08-22 18:31:38 -0600364 int rc;
Rong Chang8faa9452013-04-12 10:44:57 +0000365
Simon Glasscd8cc672015-08-22 18:31:38 -0600366 status = tpm_tis_i2c_status(dev);
367 if (status == TPM_STS_COMMAND_READY)
368 return -EINTR;
369 if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) !=
370 (TPM_STS_DATA_AVAIL | TPM_STS_VALID))
371 return -EAGAIN;
372
373 debug("...got it;\n");
Rong Chang8faa9452013-04-12 10:44:57 +0000374
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000375 /* Read first 10 bytes, including tag, paramsize, and result */
Simon Glasscd8cc672015-08-22 18:31:38 -0600376 size = tpm_tis_i2c_recv_data(dev, buf, TPM_HEADER_SIZE);
Rong Chang8faa9452013-04-12 10:44:57 +0000377 if (size < TPM_HEADER_SIZE) {
Simon Glasscd8cc672015-08-22 18:31:38 -0600378 debug("Unable to read header\n");
379 return size < 0 ? size : -EIO;
Rong Chang8faa9452013-04-12 10:44:57 +0000380 }
381
382 expected = get_unaligned_be32(buf + TPM_RSP_SIZE_BYTE);
383 if ((size_t)expected > count) {
Simon Glasscd8cc672015-08-22 18:31:38 -0600384 debug("Error size=%x, expected=%x, count=%x\n", size, expected,
Simon Glassc9a3e842015-05-04 11:30:59 -0600385 count);
Simon Glasscd8cc672015-08-22 18:31:38 -0600386 return -ENOSPC;
Rong Chang8faa9452013-04-12 10:44:57 +0000387 }
388
Simon Glasscd8cc672015-08-22 18:31:38 -0600389 size += tpm_tis_i2c_recv_data(dev, &buf[TPM_HEADER_SIZE],
Simon Glass7ccebaf2015-08-22 18:31:29 -0600390 expected - TPM_HEADER_SIZE);
Rong Chang8faa9452013-04-12 10:44:57 +0000391 if (size < expected) {
Simon Glasscd8cc672015-08-22 18:31:38 -0600392 debug("Unable to read remainder of result\n");
393 return -ETIMEDOUT;
Rong Chang8faa9452013-04-12 10:44:57 +0000394 }
395
Simon Glasscd8cc672015-08-22 18:31:38 -0600396 rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID, chip->timeout_c,
397 &status);
398 if (rc)
399 return rc;
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000400 if (status & TPM_STS_DATA_AVAIL) { /* Retry? */
Simon Glasscd8cc672015-08-22 18:31:38 -0600401 debug("Error left over data\n");
402 return -EIO;
Rong Chang8faa9452013-04-12 10:44:57 +0000403 }
404
Rong Chang8faa9452013-04-12 10:44:57 +0000405 return size;
406}
407
Simon Glasscd8cc672015-08-22 18:31:38 -0600408static int tpm_tis_i2c_send(struct udevice *dev, const u8 *buf, size_t len)
Rong Chang8faa9452013-04-12 10:44:57 +0000409{
Simon Glasscd8cc672015-08-22 18:31:38 -0600410 struct tpm_chip *chip = dev_get_priv(dev);
Rong Chang8faa9452013-04-12 10:44:57 +0000411 int rc, status;
Simon Glassc9a3e842015-05-04 11:30:59 -0600412 size_t burstcnt;
Rong Chang8faa9452013-04-12 10:44:57 +0000413 size_t count = 0;
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000414 int retry = 0;
Rong Chang8faa9452013-04-12 10:44:57 +0000415 u8 sts = TPM_STS_GO;
416
Simon Glassc9a3e842015-05-04 11:30:59 -0600417 debug("%s: len=%d\n", __func__, len);
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000418 if (len > TPM_DEV_BUFSIZE)
419 return -E2BIG; /* Command is too long for our tpm, sorry */
Rong Chang8faa9452013-04-12 10:44:57 +0000420
Simon Glasscd8cc672015-08-22 18:31:38 -0600421 if (tpm_tis_i2c_request_locality(dev, 0) < 0)
Rong Chang8faa9452013-04-12 10:44:57 +0000422 return -EBUSY;
423
Simon Glasscd8cc672015-08-22 18:31:38 -0600424 status = tpm_tis_i2c_status(dev);
Rong Chang8faa9452013-04-12 10:44:57 +0000425 if ((status & TPM_STS_COMMAND_READY) == 0) {
Simon Glasscd8cc672015-08-22 18:31:38 -0600426 rc = tpm_tis_i2c_ready(dev);
427 if (rc)
428 return rc;
429 rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_COMMAND_READY,
430 chip->timeout_b, &status);
431 if (rc)
432 return rc;
Rong Chang8faa9452013-04-12 10:44:57 +0000433 }
434
Simon Glasscd8cc672015-08-22 18:31:38 -0600435 burstcnt = tpm_tis_i2c_get_burstcount(dev);
Rong Chang8faa9452013-04-12 10:44:57 +0000436
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000437 /* burstcount < 0 -> tpm is busy */
438 if (burstcnt < 0)
439 return burstcnt;
Rong Chang8faa9452013-04-12 10:44:57 +0000440
Simon Glassc9a3e842015-05-04 11:30:59 -0600441 while (count < len) {
442 udelay(300);
443 if (burstcnt > len - count)
444 burstcnt = len - count;
Rong Chang8faa9452013-04-12 10:44:57 +0000445
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000446#ifdef CONFIG_TPM_TIS_I2C_BURST_LIMITATION
Simon Glasscd8cc672015-08-22 18:31:38 -0600447 if (retry && burstcnt > CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN)
448 burstcnt = CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN;
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000449#endif /* CONFIG_TPM_TIS_I2C_BURST_LIMITATION */
Rong Chang8faa9452013-04-12 10:44:57 +0000450
Simon Glasscd8cc672015-08-22 18:31:38 -0600451 rc = tpm_tis_i2c_write(dev, TPM_DATA_FIFO(chip->locality),
452 &(buf[count]), burstcnt);
Rong Chang8faa9452013-04-12 10:44:57 +0000453 if (rc == 0)
454 count += burstcnt;
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000455 else {
Simon Glassc9a3e842015-05-04 11:30:59 -0600456 debug("%s: error\n", __func__);
Simon Glasscd8cc672015-08-22 18:31:38 -0600457 if (retry++ > 10)
458 return -EIO;
459 rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID,
Simon Glass7ccebaf2015-08-22 18:31:29 -0600460 chip->timeout_c,
461 &status);
Simon Glassc9a3e842015-05-04 11:30:59 -0600462 if (rc)
Simon Glasscd8cc672015-08-22 18:31:38 -0600463 return rc;
Rong Chang8faa9452013-04-12 10:44:57 +0000464
Simon Glasscd8cc672015-08-22 18:31:38 -0600465 if ((status & TPM_STS_DATA_EXPECT) == 0)
466 return -EIO;
Rong Chang8faa9452013-04-12 10:44:57 +0000467 }
468 }
469
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000470 /* Go and do it */
Simon Glasscd8cc672015-08-22 18:31:38 -0600471 rc = tpm_tis_i2c_write(dev, TPM_STS(chip->locality), &sts, 1);
472 if (rc < 0)
473 return rc;
474 debug("%s: done, rc=%d\n", __func__, rc);
Rong Chang8faa9452013-04-12 10:44:57 +0000475
476 return len;
Simon Glasscd8cc672015-08-22 18:31:38 -0600477}
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000478
Simon Glasscd8cc672015-08-22 18:31:38 -0600479static int tpm_tis_i2c_cleanup(struct udevice *dev)
480{
481 struct tpm_chip *chip = dev_get_priv(dev);
482
483 tpm_tis_i2c_ready(dev);
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000484 /*
485 * The TPM needs some time to clean up here,
Rong Chang8faa9452013-04-12 10:44:57 +0000486 * so we sleep rather than keeping the bus busy
487 */
Simon Glassa57bcee2015-08-22 18:31:30 -0600488 mdelay(2);
Simon Glasscd8cc672015-08-22 18:31:38 -0600489 tpm_tis_i2c_release_locality(dev, chip->locality, 0);
Vincent Palatin06883eb2013-04-12 11:04:36 +0000490
Simon Glasscd8cc672015-08-22 18:31:38 -0600491 return 0;
Vincent Palatin06883eb2013-04-12 11:04:36 +0000492}
493
Simon Glass1de4d582015-08-22 18:31:25 -0600494static int tpm_tis_i2c_init(struct udevice *dev)
Rong Chang8faa9452013-04-12 10:44:57 +0000495{
Simon Glasscd8cc672015-08-22 18:31:38 -0600496 struct tpm_chip *chip = dev_get_priv(dev);
Rong Chang8faa9452013-04-12 10:44:57 +0000497 u32 vendor;
Vincent Palatin06883eb2013-04-12 11:04:36 +0000498 u32 expected_did_vid;
Simon Glasscd8cc672015-08-22 18:31:38 -0600499 int rc;
Rong Chang8faa9452013-04-12 10:44:57 +0000500
Simon Glassab79b002015-08-22 18:31:24 -0600501 chip->is_open = 1;
Rong Chang8faa9452013-04-12 10:44:57 +0000502
Simon Glass7ccebaf2015-08-22 18:31:29 -0600503 /* Default timeouts - these could move to the device tree */
Simon Glassa57bcee2015-08-22 18:31:30 -0600504 chip->timeout_a = TIS_SHORT_TIMEOUT_MS;
505 chip->timeout_b = TIS_LONG_TIMEOUT_MS;
506 chip->timeout_c = TIS_SHORT_TIMEOUT_MS;
507 chip->timeout_d = TIS_SHORT_TIMEOUT_MS;
Rong Chang8faa9452013-04-12 10:44:57 +0000508
Simon Glasscd8cc672015-08-22 18:31:38 -0600509 rc = tpm_tis_i2c_request_locality(dev, 0);
510 if (rc < 0)
511 return rc;
Rong Chang8faa9452013-04-12 10:44:57 +0000512
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000513 /* Read four bytes from DID_VID register */
Simon Glasscd8cc672015-08-22 18:31:38 -0600514 if (tpm_tis_i2c_read(dev, TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) {
515 tpm_tis_i2c_release_locality(dev, 0, 1);
Simon Glassc9a3e842015-05-04 11:30:59 -0600516 return -EIO;
Rong Chang8faa9452013-04-12 10:44:57 +0000517 }
518
Simon Glasscd8cc672015-08-22 18:31:38 -0600519 if (chip->chip_type == SLB9635) {
Vincent Palatin06883eb2013-04-12 11:04:36 +0000520 vendor = be32_to_cpu(vendor);
521 expected_did_vid = TPM_TIS_I2C_DID_VID_9635;
522 } else {
523 /* device id and byte order has changed for newer i2c tpms */
524 expected_did_vid = TPM_TIS_I2C_DID_VID_9645;
525 }
Rong Chang8faa9452013-04-12 10:44:57 +0000526
Simon Glasscd8cc672015-08-22 18:31:38 -0600527 if (chip->chip_type != UNKNOWN && vendor != expected_did_vid) {
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000528 error("Vendor id did not match! ID was %08x\n", vendor);
Simon Glassc9a3e842015-05-04 11:30:59 -0600529 return -ENODEV;
Rong Chang8faa9452013-04-12 10:44:57 +0000530 }
531
Simon Glasscd8cc672015-08-22 18:31:38 -0600532 chip->vend_dev = vendor;
Tom Wai-Hong Tame49fed52013-04-12 11:04:37 +0000533 debug("1.2 TPM (chip type %s device-id 0x%X)\n",
Simon Glasscd8cc672015-08-22 18:31:38 -0600534 chip_name[chip->chip_type], vendor >> 16);
Rong Chang8faa9452013-04-12 10:44:57 +0000535
536 /*
537 * A timeout query to TPM can be placed here.
538 * Standard timeout values are used so far
539 */
540
541 return 0;
Simon Glassc9a3e842015-05-04 11:30:59 -0600542}
Rong Chang8faa9452013-04-12 10:44:57 +0000543
Simon Glasscd8cc672015-08-22 18:31:38 -0600544static int tpm_tis_i2c_open(struct udevice *dev)
Simon Glass94576272015-08-22 18:31:22 -0600545{
Simon Glasscd8cc672015-08-22 18:31:38 -0600546 struct tpm_chip *chip = dev_get_priv(dev);
Simon Glass94576272015-08-22 18:31:22 -0600547 int rc;
Simon Glass94576272015-08-22 18:31:22 -0600548
Simon Glasscd8cc672015-08-22 18:31:38 -0600549 debug("%s: start\n", __func__);
550 if (chip->is_open)
551 return -EBUSY;
552 rc = tpm_tis_i2c_init(dev);
Simon Glass94576272015-08-22 18:31:22 -0600553 if (rc < 0)
Simon Glasscd8cc672015-08-22 18:31:38 -0600554 chip->is_open = 0;
Simon Glass94576272015-08-22 18:31:22 -0600555
Simon Glass94576272015-08-22 18:31:22 -0600556 return rc;
557}
558
Simon Glasscd8cc672015-08-22 18:31:38 -0600559static int tpm_tis_i2c_close(struct udevice *dev)
Simon Glass94576272015-08-22 18:31:22 -0600560{
Simon Glasscd8cc672015-08-22 18:31:38 -0600561 struct tpm_chip *chip = dev_get_priv(dev);
Simon Glass94576272015-08-22 18:31:22 -0600562
Simon Glasscd8cc672015-08-22 18:31:38 -0600563 if (chip->is_open) {
564 tpm_tis_i2c_release_locality(dev, chip->locality, 1);
565 chip->is_open = 0;
566 chip->vend_dev = 0;
Simon Glass94576272015-08-22 18:31:22 -0600567 }
568
Simon Glass94576272015-08-22 18:31:22 -0600569 return 0;
570}
571
Simon Glasscd8cc672015-08-22 18:31:38 -0600572static int tpm_tis_get_desc(struct udevice *dev, char *buf, int size)
Simon Glass94576272015-08-22 18:31:22 -0600573{
Simon Glasscd8cc672015-08-22 18:31:38 -0600574 struct tpm_chip *chip = dev_get_priv(dev);
Simon Glass94576272015-08-22 18:31:22 -0600575
Simon Glasscd8cc672015-08-22 18:31:38 -0600576 if (size < 50)
577 return -ENOSPC;
Simon Glass94576272015-08-22 18:31:22 -0600578
Simon Glasscd8cc672015-08-22 18:31:38 -0600579 return snprintf(buf, size, "1.2 TPM (%s, chip type %s device-id 0x%x)",
580 chip->is_open ? "open" : "closed",
581 chip_name[chip->chip_type],
582 chip->vend_dev >> 16);
Simon Glass94576272015-08-22 18:31:22 -0600583}
584
Simon Glasscd8cc672015-08-22 18:31:38 -0600585static int tpm_tis_i2c_probe(struct udevice *dev)
Simon Glass94576272015-08-22 18:31:22 -0600586{
Simon Glasscd8cc672015-08-22 18:31:38 -0600587 struct tpm_chip_priv *uc_priv = dev_get_uclass_priv(dev);
588 struct tpm_chip *chip = dev_get_priv(dev);
Simon Glass94576272015-08-22 18:31:22 -0600589
Simon Glasscd8cc672015-08-22 18:31:38 -0600590 chip->chip_type = dev_get_driver_data(dev);
Simon Glass94576272015-08-22 18:31:22 -0600591
Simon Glasscd8cc672015-08-22 18:31:38 -0600592 /* TODO: These need to be checked and tuned */
593 uc_priv->duration_ms[TPM_SHORT] = TIS_SHORT_TIMEOUT_MS;
594 uc_priv->duration_ms[TPM_MEDIUM] = TIS_LONG_TIMEOUT_MS;
595 uc_priv->duration_ms[TPM_LONG] = TIS_LONG_TIMEOUT_MS;
596 uc_priv->retry_time_ms = TPM_TIMEOUT_MS;
Simon Glass94576272015-08-22 18:31:22 -0600597
598 return 0;
599}
600
Simon Glasscd8cc672015-08-22 18:31:38 -0600601static const struct tpm_ops tpm_tis_i2c_ops = {
602 .open = tpm_tis_i2c_open,
603 .close = tpm_tis_i2c_close,
604 .get_desc = tpm_tis_get_desc,
605 .send = tpm_tis_i2c_send,
606 .recv = tpm_tis_i2c_recv,
607 .cleanup = tpm_tis_i2c_cleanup,
608};
Simon Glass94576272015-08-22 18:31:22 -0600609
Simon Glasscd8cc672015-08-22 18:31:38 -0600610static const struct udevice_id tpm_tis_i2c_ids[] = {
611 { .compatible = "infineon,slb9635tt", .data = SLB9635 },
612 { .compatible = "infineon,slb9645tt", .data = SLB9645 },
613 { }
614};
Simon Glass94576272015-08-22 18:31:22 -0600615
Simon Glasscd8cc672015-08-22 18:31:38 -0600616U_BOOT_DRIVER(tpm_tis_i2c) = {
617 .name = "tpm_tis_i2c",
618 .id = UCLASS_TPM,
619 .of_match = tpm_tis_i2c_ids,
620 .ops = &tpm_tis_i2c_ops,
621 .probe = tpm_tis_i2c_probe,
622 .priv_auto_alloc_size = sizeof(struct tpm_chip),
623};