blob: 47823e895359eb5537628759d70a3250095595e3 [file] [log] [blame]
Stefan Reinauerd518c7a2013-11-04 17:38:32 -08001/*
2 * Copyright (C) 2011 Infineon Technologies
3 * Copyright 2013 Google Inc.
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but without any warranty; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <stdint.h>
25#include <string.h>
26#include <assert.h>
27#include <delay.h>
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080028#include <device/i2c.h>
Julius Werner9ff8f6f2015-02-23 14:31:09 -080029#include <endian.h>
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080030#include <tpm.h>
31#include "tpm.h"
Sourabh Banerjee8c916ec2015-01-20 15:18:40 +053032#include <timer.h>
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080033
34#include <console/console.h>
35
36/* global structure for tpm chip data */
37struct tpm_chip g_chip;
38
39#define TPM_CMD_COUNT_BYTE 2
40#define TPM_CMD_ORDINAL_BYTE 6
Sourabh Banerjee8c916ec2015-01-20 15:18:40 +053041#define TPM_VALID_STATUS (1 << 7)
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080042
43int tis_open(void)
44{
45 int rc;
46
47 if (g_chip.is_open) {
48 printk(BIOS_DEBUG, "tis_open() called twice.\n");
49 return -1;
50 }
51
52 rc = tpm_vendor_init(CONFIG_DRIVER_TPM_I2C_BUS,
53 CONFIG_DRIVER_TPM_I2C_ADDR);
54
55 if (rc < 0)
56 g_chip.is_open = 0;
57
58 if (rc) {
59 return -1;
60 }
61
62 return 0;
63}
64
65int tis_close(void)
66{
67 if (g_chip.is_open) {
68 tpm_vendor_cleanup(&g_chip);
69 g_chip.is_open = 0;
70 }
71
72 return 0;
73}
74
75int tis_init(void)
76{
77 int bus = CONFIG_DRIVER_TPM_I2C_BUS;
78 int chip = CONFIG_DRIVER_TPM_I2C_ADDR;
Sourabh Banerjee8c916ec2015-01-20 15:18:40 +053079 struct stopwatch sw;
80 uint8_t buf = 0;
81 int ret;
82 long sw_run_duration = 750;
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080083
84 /*
Sourabh Banerjee8c916ec2015-01-20 15:18:40 +053085 * Probe TPM. Check if the TPM_ACCESS register's ValidSts bit is set(1)
86 * If the bit remains clear(0) then claim that init has failed.
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080087 */
Sourabh Banerjee8c916ec2015-01-20 15:18:40 +053088 stopwatch_init_msecs_expire(&sw, sw_run_duration);
89 do {
90 ret = i2c_readb(bus, chip, 0, &buf);
91 if (!ret && (buf & TPM_VALID_STATUS)) {
92 sw_run_duration = stopwatch_duration_msecs(&sw);
93 break;
94 }
95 } while (!stopwatch_expired(&sw));
96
97 printk(BIOS_INFO,
98 "%s: ValidSts bit %s(%d) in TPM_ACCESS register after %ld ms\n",
99 __func__, (buf & TPM_VALID_STATUS) ? "set" : "clear",
100 (buf & TPM_VALID_STATUS) >> 7, sw_run_duration);
101
102 /*
103 * Claim failure if the ValidSts (bit 7) is clear.
104 */
105 if (!(buf & TPM_VALID_STATUS))
Stefan Reinauerd518c7a2013-11-04 17:38:32 -0800106 return -1;
107
108 return 0;
109}
110
111static ssize_t tpm_transmit(const uint8_t *buf, size_t bufsiz)
112{
113 int rc;
114 uint32_t count, ordinal;
115
116 struct tpm_chip *chip = &g_chip;
117
118 memcpy(&count, buf + TPM_CMD_COUNT_BYTE, sizeof(count));
119 count = be32_to_cpu(count);
120 memcpy(&ordinal, buf + TPM_CMD_ORDINAL_BYTE, sizeof(ordinal));
121 ordinal = be32_to_cpu(ordinal);
122
123 if (count == 0) {
124 printk(BIOS_DEBUG, "tpm_transmit: no data\n");
125 return -1;
126 }
127 if (count > bufsiz) {
128 printk(BIOS_DEBUG, "tpm_transmit: invalid count value %x %zx\n",
129 count, bufsiz);
130 return -1;
131 }
132
133 ASSERT(chip->vendor.send);
134 rc = chip->vendor.send(chip, (uint8_t *) buf, count);
135 if (rc < 0) {
136 printk(BIOS_DEBUG, "tpm_transmit: tpm_send error\n");
137 goto out;
138 }
139
140 if (chip->vendor.irq)
141 goto out_recv;
142
143 int timeout = 2 * 60 * 1000; /* two minutes timeout */
144 while (timeout) {
145 ASSERT(chip->vendor.status);
146 uint8_t status = chip->vendor.status(chip);
147 if ((status & chip->vendor.req_complete_mask) ==
148 chip->vendor.req_complete_val) {
149 goto out_recv;
150 }
151
152 if ((status == chip->vendor.req_canceled)) {
153 printk(BIOS_DEBUG, "tpm_transmit: Operation Canceled\n");
154 rc = -1;
155 goto out;
156 }
157 mdelay(TPM_TIMEOUT);
158 timeout--;
159 }
160
161 ASSERT(chip->vendor.cancel);
162 chip->vendor.cancel(chip);
163 printk(BIOS_DEBUG, "tpm_transmit: Operation Timed out\n");
164 rc = -1; //ETIME;
165 goto out;
166
167out_recv:
168
169 rc = chip->vendor.recv(chip, (uint8_t *) buf, TPM_BUFSIZE);
170 if (rc < 0)
Furquan Shaikh251eef12014-07-22 11:12:15 -0700171 printk(BIOS_DEBUG, "tpm_transmit: tpm_recv: error %d\n", rc);
Stefan Reinauerd518c7a2013-11-04 17:38:32 -0800172out:
173 return rc;
174}
175
176int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size,
177 uint8_t *recvbuf, size_t *rbuf_len)
178{
179 uint8_t buf[TPM_BUFSIZE];
180
181 if (sizeof(buf) < sbuf_size)
182 return -1;
183
184 memcpy(buf, sendbuf, sbuf_size);
185
186 int len = tpm_transmit(buf, sbuf_size);
187
188 if (len < 10) {
189 *rbuf_len = 0;
190 return -1;
191 }
192
193 if (len > *rbuf_len) {
194 *rbuf_len = len;
195 return -1;
196 }
197
198 memcpy(recvbuf, buf, len);
199 *rbuf_len = len;
200
201 return 0;
202}