blob: 22554e1456b345fa5511131616dec7469d86caa3 [file] [log] [blame]
Rong Changf6267992013-04-12 10:44:57 +00001/*
2 * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <config.h>
8#include <common.h>
9#include <fdtdec.h>
10#include <i2c.h>
11#include "slb9635_i2c/tpm.h"
12
13DECLARE_GLOBAL_DATA_PTR;
14
15/* TPM configuration */
16struct tpm {
17 int i2c_bus;
18 int slave_addr;
19 char inited;
20 int old_bus;
21} tpm;
22
23
24static int tpm_select(void)
25{
26 int ret;
27
28 tpm.old_bus = i2c_get_bus_num();
29 if (tpm.old_bus != tpm.i2c_bus) {
30 ret = i2c_set_bus_num(tpm.i2c_bus);
31 if (ret) {
32 debug("%s: Fail to set i2c bus %d\n", __func__,
33 tpm.i2c_bus);
34 return -1;
35 }
36 }
37 return 0;
38}
39
40static int tpm_deselect(void)
41{
42 int ret;
43
44 if (tpm.old_bus != i2c_get_bus_num()) {
45 ret = i2c_set_bus_num(tpm.old_bus);
46 if (ret) {
47 debug("%s: Fail to restore i2c bus %d\n",
48 __func__, tpm.old_bus);
49 return -1;
50 }
51 }
52 tpm.old_bus = -1;
53 return 0;
54}
55
56/**
57 * Decode TPM configuration.
58 *
59 * @param dev Returns a configuration of TPM device
60 * @return 0 if ok, -1 on error
61 */
62static int tpm_decode_config(struct tpm *dev)
63{
64#ifdef CONFIG_OF_CONTROL
65 const void *blob = gd->fdt_blob;
66 int node, parent;
67 int i2c_bus;
68
69 node = fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM);
70 if (node < 0) {
Vincent Palatinec34fa52013-04-12 11:04:36 +000071 node = fdtdec_next_compatible(blob, 0,
72 COMPAT_INFINEON_SLB9645_TPM);
73 }
74 if (node < 0) {
Rong Changf6267992013-04-12 10:44:57 +000075 debug("%s: Node not found\n", __func__);
76 return -1;
77 }
78 parent = fdt_parent_offset(blob, node);
79 if (parent < 0) {
80 debug("%s: Cannot find node parent\n", __func__);
81 return -1;
82 }
83 i2c_bus = i2c_get_bus_num_fdt(parent);
84 if (i2c_bus < 0)
85 return -1;
86 dev->i2c_bus = i2c_bus;
87 dev->slave_addr = fdtdec_get_addr(blob, node, "reg");
88#else
89 dev->i2c_bus = CONFIG_INFINEON_TPM_I2C_BUS;
90 dev->slave_addr = CONFIG_INFINEON_TPM_I2C_ADDR;
91#endif
92 return 0;
93}
94
95int tis_init(void)
96{
97 if (tpm.inited)
98 return 0;
99
100 if (tpm_decode_config(&tpm))
101 return -1;
102
103 if (tpm_select())
104 return -1;
105
106 /*
107 * Probe TPM twice; the first probing might fail because TPM is asleep,
108 * and the probing can wake up TPM.
109 */
110 if (i2c_probe(tpm.slave_addr) && i2c_probe(tpm.slave_addr)) {
111 debug("%s: fail to probe i2c addr 0x%x\n", __func__,
112 tpm.slave_addr);
113 return -1;
114 }
115
116 tpm_deselect();
117
118 tpm.inited = 1;
119
120 return 0;
121}
122
123int tis_open(void)
124{
125 int rc;
126
127 if (!tpm.inited)
128 return -1;
129
130 if (tpm_select())
131 return -1;
132
133 rc = tpm_open(tpm.slave_addr);
134
135 tpm_deselect();
136
137 return rc;
138}
139
140int tis_close(void)
141{
142 if (!tpm.inited)
143 return -1;
144
145 if (tpm_select())
146 return -1;
147
148 tpm_close();
149
150 tpm_deselect();
151
152 return 0;
153}
154
155int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size,
156 uint8_t *recvbuf, size_t *rbuf_len)
157{
158 int len;
159 uint8_t buf[4096];
160
161 if (!tpm.inited)
162 return -1;
163
164 if (sizeof(buf) < sbuf_size)
165 return -1;
166
167 memcpy(buf, sendbuf, sbuf_size);
168
169 if (tpm_select())
170 return -1;
171
172 len = tpm_transmit(buf, sbuf_size);
173
174 tpm_deselect();
175
176 if (len < 10) {
177 *rbuf_len = 0;
178 return -1;
179 }
180
181 memcpy(recvbuf, buf, len);
182 *rbuf_len = len;
183
184 return 0;
185}