blob: e818fbaf541808953c60c62e7b348b7f002b055e [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) {
71 debug("%s: Node not found\n", __func__);
72 return -1;
73 }
74 parent = fdt_parent_offset(blob, node);
75 if (parent < 0) {
76 debug("%s: Cannot find node parent\n", __func__);
77 return -1;
78 }
79 i2c_bus = i2c_get_bus_num_fdt(parent);
80 if (i2c_bus < 0)
81 return -1;
82 dev->i2c_bus = i2c_bus;
83 dev->slave_addr = fdtdec_get_addr(blob, node, "reg");
84#else
85 dev->i2c_bus = CONFIG_INFINEON_TPM_I2C_BUS;
86 dev->slave_addr = CONFIG_INFINEON_TPM_I2C_ADDR;
87#endif
88 return 0;
89}
90
91int tis_init(void)
92{
93 if (tpm.inited)
94 return 0;
95
96 if (tpm_decode_config(&tpm))
97 return -1;
98
99 if (tpm_select())
100 return -1;
101
102 /*
103 * Probe TPM twice; the first probing might fail because TPM is asleep,
104 * and the probing can wake up TPM.
105 */
106 if (i2c_probe(tpm.slave_addr) && i2c_probe(tpm.slave_addr)) {
107 debug("%s: fail to probe i2c addr 0x%x\n", __func__,
108 tpm.slave_addr);
109 return -1;
110 }
111
112 tpm_deselect();
113
114 tpm.inited = 1;
115
116 return 0;
117}
118
119int tis_open(void)
120{
121 int rc;
122
123 if (!tpm.inited)
124 return -1;
125
126 if (tpm_select())
127 return -1;
128
129 rc = tpm_open(tpm.slave_addr);
130
131 tpm_deselect();
132
133 return rc;
134}
135
136int tis_close(void)
137{
138 if (!tpm.inited)
139 return -1;
140
141 if (tpm_select())
142 return -1;
143
144 tpm_close();
145
146 tpm_deselect();
147
148 return 0;
149}
150
151int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size,
152 uint8_t *recvbuf, size_t *rbuf_len)
153{
154 int len;
155 uint8_t buf[4096];
156
157 if (!tpm.inited)
158 return -1;
159
160 if (sizeof(buf) < sbuf_size)
161 return -1;
162
163 memcpy(buf, sendbuf, sbuf_size);
164
165 if (tpm_select())
166 return -1;
167
168 len = tpm_transmit(buf, sbuf_size);
169
170 tpm_deselect();
171
172 if (len < 10) {
173 *rbuf_len = 0;
174 return -1;
175 }
176
177 memcpy(recvbuf, buf, len);
178 *rbuf_len = len;
179
180 return 0;
181}