xref: /openbmc/u-boot/drivers/tpm/tpm_tis_lpc.c (revision 90899cc0)
1*90899cc0SChe-liang Chiou /*
2*90899cc0SChe-liang Chiou  * Copyright (c) 2011 The Chromium OS Authors.
3*90899cc0SChe-liang Chiou  *
4*90899cc0SChe-liang Chiou  * See file CREDITS for list of people who contributed to this
5*90899cc0SChe-liang Chiou  * project.
6*90899cc0SChe-liang Chiou  *
7*90899cc0SChe-liang Chiou  * This program is free software; you can redistribute it and/or
8*90899cc0SChe-liang Chiou  * modify it under the terms of the GNU General Public License as
9*90899cc0SChe-liang Chiou  * published by the Free Software Foundation; either version 2 of
10*90899cc0SChe-liang Chiou  * the License, or (at your option) any later version.
11*90899cc0SChe-liang Chiou  *
12*90899cc0SChe-liang Chiou  * This program is distributed in the hope that it will be useful,
13*90899cc0SChe-liang Chiou  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*90899cc0SChe-liang Chiou  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*90899cc0SChe-liang Chiou  * GNU General Public License for more details.
16*90899cc0SChe-liang Chiou  *
17*90899cc0SChe-liang Chiou  * You should have received a copy of the GNU General Public License
18*90899cc0SChe-liang Chiou  * along with this program; if not, write to the Free Software
19*90899cc0SChe-liang Chiou  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20*90899cc0SChe-liang Chiou  * MA 02111-1307 USA
21*90899cc0SChe-liang Chiou  */
22*90899cc0SChe-liang Chiou 
23*90899cc0SChe-liang Chiou /*
24*90899cc0SChe-liang Chiou  * The code in this file is based on the article "Writing a TPM Device Driver"
25*90899cc0SChe-liang Chiou  * published on http://ptgmedia.pearsoncmg.com.
26*90899cc0SChe-liang Chiou  *
27*90899cc0SChe-liang Chiou  * One principal difference is that in the simplest config the other than 0
28*90899cc0SChe-liang Chiou  * TPM localities do not get mapped by some devices (for instance, by Infineon
29*90899cc0SChe-liang Chiou  * slb9635), so this driver provides access to locality 0 only.
30*90899cc0SChe-liang Chiou  */
31*90899cc0SChe-liang Chiou 
32*90899cc0SChe-liang Chiou #include <common.h>
33*90899cc0SChe-liang Chiou #include <asm/io.h>
34*90899cc0SChe-liang Chiou #include <tpm.h>
35*90899cc0SChe-liang Chiou 
36*90899cc0SChe-liang Chiou #define PREFIX "lpc_tpm: "
37*90899cc0SChe-liang Chiou 
38*90899cc0SChe-liang Chiou struct tpm_locality {
39*90899cc0SChe-liang Chiou 	u32 access;
40*90899cc0SChe-liang Chiou 	u8 padding0[4];
41*90899cc0SChe-liang Chiou 	u32 int_enable;
42*90899cc0SChe-liang Chiou 	u8 vector;
43*90899cc0SChe-liang Chiou 	u8 padding1[3];
44*90899cc0SChe-liang Chiou 	u32 int_status;
45*90899cc0SChe-liang Chiou 	u32 int_capability;
46*90899cc0SChe-liang Chiou 	u32 tpm_status;
47*90899cc0SChe-liang Chiou 	u8 padding2[8];
48*90899cc0SChe-liang Chiou 	u8 data;
49*90899cc0SChe-liang Chiou 	u8 padding3[3803];
50*90899cc0SChe-liang Chiou 	u32 did_vid;
51*90899cc0SChe-liang Chiou 	u8 rid;
52*90899cc0SChe-liang Chiou 	u8 padding4[251];
53*90899cc0SChe-liang Chiou };
54*90899cc0SChe-liang Chiou 
55*90899cc0SChe-liang Chiou /*
56*90899cc0SChe-liang Chiou  * This pointer refers to the TPM chip, 5 of its localities are mapped as an
57*90899cc0SChe-liang Chiou  * array.
58*90899cc0SChe-liang Chiou  */
59*90899cc0SChe-liang Chiou #define TPM_TOTAL_LOCALITIES	5
60*90899cc0SChe-liang Chiou static struct tpm_locality *lpc_tpm_dev =
61*90899cc0SChe-liang Chiou 	(struct tpm_locality *)CONFIG_TPM_TIS_BASE_ADDRESS;
62*90899cc0SChe-liang Chiou 
63*90899cc0SChe-liang Chiou /* Some registers' bit field definitions */
64*90899cc0SChe-liang Chiou #define TIS_STS_VALID                  (1 << 7) /* 0x80 */
65*90899cc0SChe-liang Chiou #define TIS_STS_COMMAND_READY          (1 << 6) /* 0x40 */
66*90899cc0SChe-liang Chiou #define TIS_STS_TPM_GO                 (1 << 5) /* 0x20 */
67*90899cc0SChe-liang Chiou #define TIS_STS_DATA_AVAILABLE         (1 << 4) /* 0x10 */
68*90899cc0SChe-liang Chiou #define TIS_STS_EXPECT                 (1 << 3) /* 0x08 */
69*90899cc0SChe-liang Chiou #define TIS_STS_RESPONSE_RETRY         (1 << 1) /* 0x02 */
70*90899cc0SChe-liang Chiou 
71*90899cc0SChe-liang Chiou #define TIS_ACCESS_TPM_REG_VALID_STS   (1 << 7) /* 0x80 */
72*90899cc0SChe-liang Chiou #define TIS_ACCESS_ACTIVE_LOCALITY     (1 << 5) /* 0x20 */
73*90899cc0SChe-liang Chiou #define TIS_ACCESS_BEEN_SEIZED         (1 << 4) /* 0x10 */
74*90899cc0SChe-liang Chiou #define TIS_ACCESS_SEIZE               (1 << 3) /* 0x08 */
75*90899cc0SChe-liang Chiou #define TIS_ACCESS_PENDING_REQUEST     (1 << 2) /* 0x04 */
76*90899cc0SChe-liang Chiou #define TIS_ACCESS_REQUEST_USE         (1 << 1) /* 0x02 */
77*90899cc0SChe-liang Chiou #define TIS_ACCESS_TPM_ESTABLISHMENT   (1 << 0) /* 0x01 */
78*90899cc0SChe-liang Chiou 
79*90899cc0SChe-liang Chiou #define TIS_STS_BURST_COUNT_MASK       (0xffff)
80*90899cc0SChe-liang Chiou #define TIS_STS_BURST_COUNT_SHIFT      (8)
81*90899cc0SChe-liang Chiou 
82*90899cc0SChe-liang Chiou /*
83*90899cc0SChe-liang Chiou  * Error value returned if a tpm register does not enter the expected state
84*90899cc0SChe-liang Chiou  * after continuous polling. No actual TPM register reading ever returns -1,
85*90899cc0SChe-liang Chiou  * so this value is a safe error indication to be mixed with possible status
86*90899cc0SChe-liang Chiou  * register values.
87*90899cc0SChe-liang Chiou  */
88*90899cc0SChe-liang Chiou #define TPM_TIMEOUT_ERR			(-1)
89*90899cc0SChe-liang Chiou 
90*90899cc0SChe-liang Chiou /* Error value returned on various TPM driver errors. */
91*90899cc0SChe-liang Chiou #define TPM_DRIVER_ERR		(1)
92*90899cc0SChe-liang Chiou 
93*90899cc0SChe-liang Chiou  /* 1 second is plenty for anything TPM does. */
94*90899cc0SChe-liang Chiou #define MAX_DELAY_US	(1000 * 1000)
95*90899cc0SChe-liang Chiou 
96*90899cc0SChe-liang Chiou /* Retrieve burst count value out of the status register contents. */
97*90899cc0SChe-liang Chiou static u16 burst_count(u32 status)
98*90899cc0SChe-liang Chiou {
99*90899cc0SChe-liang Chiou 	return (status >> TIS_STS_BURST_COUNT_SHIFT) & TIS_STS_BURST_COUNT_MASK;
100*90899cc0SChe-liang Chiou }
101*90899cc0SChe-liang Chiou 
102*90899cc0SChe-liang Chiou /*
103*90899cc0SChe-liang Chiou  * Structures defined below allow creating descriptions of TPM vendor/device
104*90899cc0SChe-liang Chiou  * ID information for run time discovery. The only device the system knows
105*90899cc0SChe-liang Chiou  * about at this time is Infineon slb9635.
106*90899cc0SChe-liang Chiou  */
107*90899cc0SChe-liang Chiou struct device_name {
108*90899cc0SChe-liang Chiou 	u16 dev_id;
109*90899cc0SChe-liang Chiou 	const char * const dev_name;
110*90899cc0SChe-liang Chiou };
111*90899cc0SChe-liang Chiou 
112*90899cc0SChe-liang Chiou struct vendor_name {
113*90899cc0SChe-liang Chiou 	u16 vendor_id;
114*90899cc0SChe-liang Chiou 	const char *vendor_name;
115*90899cc0SChe-liang Chiou 	const struct device_name *dev_names;
116*90899cc0SChe-liang Chiou };
117*90899cc0SChe-liang Chiou 
118*90899cc0SChe-liang Chiou static const struct device_name infineon_devices[] = {
119*90899cc0SChe-liang Chiou 	{0xb, "SLB9635 TT 1.2"},
120*90899cc0SChe-liang Chiou 	{0}
121*90899cc0SChe-liang Chiou };
122*90899cc0SChe-liang Chiou 
123*90899cc0SChe-liang Chiou static const struct vendor_name vendor_names[] = {
124*90899cc0SChe-liang Chiou 	{0x15d1, "Infineon", infineon_devices},
125*90899cc0SChe-liang Chiou };
126*90899cc0SChe-liang Chiou 
127*90899cc0SChe-liang Chiou /*
128*90899cc0SChe-liang Chiou  * Cached vendor/device ID pair to indicate that the device has been already
129*90899cc0SChe-liang Chiou  * discovered.
130*90899cc0SChe-liang Chiou  */
131*90899cc0SChe-liang Chiou static u32 vendor_dev_id;
132*90899cc0SChe-liang Chiou 
133*90899cc0SChe-liang Chiou /* TPM access wrappers to support tracing */
134*90899cc0SChe-liang Chiou static u8 tpm_read_byte(const u8 *ptr)
135*90899cc0SChe-liang Chiou {
136*90899cc0SChe-liang Chiou 	u8  ret = readb(ptr);
137*90899cc0SChe-liang Chiou 	debug(PREFIX "Read reg 0x%4.4x returns 0x%2.2x\n",
138*90899cc0SChe-liang Chiou 	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, ret);
139*90899cc0SChe-liang Chiou 	return ret;
140*90899cc0SChe-liang Chiou }
141*90899cc0SChe-liang Chiou 
142*90899cc0SChe-liang Chiou static u32 tpm_read_word(const u32 *ptr)
143*90899cc0SChe-liang Chiou {
144*90899cc0SChe-liang Chiou 	u32  ret = readl(ptr);
145*90899cc0SChe-liang Chiou 	debug(PREFIX "Read reg 0x%4.4x returns 0x%8.8x\n",
146*90899cc0SChe-liang Chiou 	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, ret);
147*90899cc0SChe-liang Chiou 	return ret;
148*90899cc0SChe-liang Chiou }
149*90899cc0SChe-liang Chiou 
150*90899cc0SChe-liang Chiou static void tpm_write_byte(u8 value, u8 *ptr)
151*90899cc0SChe-liang Chiou {
152*90899cc0SChe-liang Chiou 	debug(PREFIX "Write reg 0x%4.4x with 0x%2.2x\n",
153*90899cc0SChe-liang Chiou 	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, value);
154*90899cc0SChe-liang Chiou 	writeb(value, ptr);
155*90899cc0SChe-liang Chiou }
156*90899cc0SChe-liang Chiou 
157*90899cc0SChe-liang Chiou static void tpm_write_word(u32 value, u32 *ptr)
158*90899cc0SChe-liang Chiou {
159*90899cc0SChe-liang Chiou 	debug(PREFIX "Write reg 0x%4.4x with 0x%8.8x\n",
160*90899cc0SChe-liang Chiou 	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, value);
161*90899cc0SChe-liang Chiou 	writel(value, ptr);
162*90899cc0SChe-liang Chiou }
163*90899cc0SChe-liang Chiou 
164*90899cc0SChe-liang Chiou /*
165*90899cc0SChe-liang Chiou  * tis_wait_reg()
166*90899cc0SChe-liang Chiou  *
167*90899cc0SChe-liang Chiou  * Wait for at least a second for a register to change its state to match the
168*90899cc0SChe-liang Chiou  * expected state. Normally the transition happens within microseconds.
169*90899cc0SChe-liang Chiou  *
170*90899cc0SChe-liang Chiou  * @reg - pointer to the TPM register
171*90899cc0SChe-liang Chiou  * @mask - bitmask for the bitfield(s) to watch
172*90899cc0SChe-liang Chiou  * @expected - value the field(s) are supposed to be set to
173*90899cc0SChe-liang Chiou  *
174*90899cc0SChe-liang Chiou  * Returns the register contents in case the expected value was found in the
175*90899cc0SChe-liang Chiou  * appropriate register bits, or TPM_TIMEOUT_ERR on timeout.
176*90899cc0SChe-liang Chiou  */
177*90899cc0SChe-liang Chiou static u32 tis_wait_reg(u32 *reg, u8 mask, u8 expected)
178*90899cc0SChe-liang Chiou {
179*90899cc0SChe-liang Chiou 	u32 time_us = MAX_DELAY_US;
180*90899cc0SChe-liang Chiou 
181*90899cc0SChe-liang Chiou 	while (time_us > 0) {
182*90899cc0SChe-liang Chiou 		u32 value = tpm_read_word(reg);
183*90899cc0SChe-liang Chiou 		if ((value & mask) == expected)
184*90899cc0SChe-liang Chiou 			return value;
185*90899cc0SChe-liang Chiou 		udelay(1); /* 1 us */
186*90899cc0SChe-liang Chiou 		time_us--;
187*90899cc0SChe-liang Chiou 	}
188*90899cc0SChe-liang Chiou 	return TPM_TIMEOUT_ERR;
189*90899cc0SChe-liang Chiou }
190*90899cc0SChe-liang Chiou 
191*90899cc0SChe-liang Chiou /*
192*90899cc0SChe-liang Chiou  * Probe the TPM device and try determining its manufacturer/device name.
193*90899cc0SChe-liang Chiou  *
194*90899cc0SChe-liang Chiou  * Returns 0 on success (the device is found or was found during an earlier
195*90899cc0SChe-liang Chiou  * invocation) or TPM_DRIVER_ERR if the device is not found.
196*90899cc0SChe-liang Chiou  */
197*90899cc0SChe-liang Chiou int tis_init(void)
198*90899cc0SChe-liang Chiou {
199*90899cc0SChe-liang Chiou 	u32 didvid = tpm_read_word(&lpc_tpm_dev[0].did_vid);
200*90899cc0SChe-liang Chiou 	int i;
201*90899cc0SChe-liang Chiou 	const char *device_name = "unknown";
202*90899cc0SChe-liang Chiou 	const char *vendor_name = device_name;
203*90899cc0SChe-liang Chiou 	u16 vid, did;
204*90899cc0SChe-liang Chiou 
205*90899cc0SChe-liang Chiou 	if (vendor_dev_id)
206*90899cc0SChe-liang Chiou 		return 0;  /* Already probed. */
207*90899cc0SChe-liang Chiou 
208*90899cc0SChe-liang Chiou 	if (!didvid || (didvid == 0xffffffff)) {
209*90899cc0SChe-liang Chiou 		printf("%s: No TPM device found\n", __func__);
210*90899cc0SChe-liang Chiou 		return TPM_DRIVER_ERR;
211*90899cc0SChe-liang Chiou 	}
212*90899cc0SChe-liang Chiou 
213*90899cc0SChe-liang Chiou 	vendor_dev_id = didvid;
214*90899cc0SChe-liang Chiou 
215*90899cc0SChe-liang Chiou 	vid = didvid & 0xffff;
216*90899cc0SChe-liang Chiou 	did = (didvid >> 16) & 0xffff;
217*90899cc0SChe-liang Chiou 	for (i = 0; i < ARRAY_SIZE(vendor_names); i++) {
218*90899cc0SChe-liang Chiou 		int j = 0;
219*90899cc0SChe-liang Chiou 		u16 known_did;
220*90899cc0SChe-liang Chiou 
221*90899cc0SChe-liang Chiou 		if (vid == vendor_names[i].vendor_id)
222*90899cc0SChe-liang Chiou 			vendor_name = vendor_names[i].vendor_name;
223*90899cc0SChe-liang Chiou 
224*90899cc0SChe-liang Chiou 		while ((known_did = vendor_names[i].dev_names[j].dev_id) != 0) {
225*90899cc0SChe-liang Chiou 			if (known_did == did) {
226*90899cc0SChe-liang Chiou 				device_name =
227*90899cc0SChe-liang Chiou 					vendor_names[i].dev_names[j].dev_name;
228*90899cc0SChe-liang Chiou 				break;
229*90899cc0SChe-liang Chiou 			}
230*90899cc0SChe-liang Chiou 			j++;
231*90899cc0SChe-liang Chiou 		}
232*90899cc0SChe-liang Chiou 		break;
233*90899cc0SChe-liang Chiou 	}
234*90899cc0SChe-liang Chiou 
235*90899cc0SChe-liang Chiou 	printf("Found TPM %s by %s\n", device_name, vendor_name);
236*90899cc0SChe-liang Chiou 	return 0;
237*90899cc0SChe-liang Chiou }
238*90899cc0SChe-liang Chiou 
239*90899cc0SChe-liang Chiou /*
240*90899cc0SChe-liang Chiou  * tis_senddata()
241*90899cc0SChe-liang Chiou  *
242*90899cc0SChe-liang Chiou  * send the passed in data to the TPM device.
243*90899cc0SChe-liang Chiou  *
244*90899cc0SChe-liang Chiou  * @data - address of the data to send, byte by byte
245*90899cc0SChe-liang Chiou  * @len - length of the data to send
246*90899cc0SChe-liang Chiou  *
247*90899cc0SChe-liang Chiou  * Returns 0 on success, TPM_DRIVER_ERR on error (in case the device does
248*90899cc0SChe-liang Chiou  * not accept the entire command).
249*90899cc0SChe-liang Chiou  */
250*90899cc0SChe-liang Chiou static u32 tis_senddata(const u8 * const data, u32 len)
251*90899cc0SChe-liang Chiou {
252*90899cc0SChe-liang Chiou 	u32 offset = 0;
253*90899cc0SChe-liang Chiou 	u16 burst = 0;
254*90899cc0SChe-liang Chiou 	u32 max_cycles = 0;
255*90899cc0SChe-liang Chiou 	u8 locality = 0;
256*90899cc0SChe-liang Chiou 	u32 value;
257*90899cc0SChe-liang Chiou 
258*90899cc0SChe-liang Chiou 	value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
259*90899cc0SChe-liang Chiou 			     TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY);
260*90899cc0SChe-liang Chiou 	if (value == TPM_TIMEOUT_ERR) {
261*90899cc0SChe-liang Chiou 		printf("%s:%d - failed to get 'command_ready' status\n",
262*90899cc0SChe-liang Chiou 		       __FILE__, __LINE__);
263*90899cc0SChe-liang Chiou 		return TPM_DRIVER_ERR;
264*90899cc0SChe-liang Chiou 	}
265*90899cc0SChe-liang Chiou 	burst = burst_count(value);
266*90899cc0SChe-liang Chiou 
267*90899cc0SChe-liang Chiou 	while (1) {
268*90899cc0SChe-liang Chiou 		unsigned count;
269*90899cc0SChe-liang Chiou 
270*90899cc0SChe-liang Chiou 		/* Wait till the device is ready to accept more data. */
271*90899cc0SChe-liang Chiou 		while (!burst) {
272*90899cc0SChe-liang Chiou 			if (max_cycles++ == MAX_DELAY_US) {
273*90899cc0SChe-liang Chiou 				printf("%s:%d failed to feed %d bytes of %d\n",
274*90899cc0SChe-liang Chiou 				       __FILE__, __LINE__, len - offset, len);
275*90899cc0SChe-liang Chiou 				return TPM_DRIVER_ERR;
276*90899cc0SChe-liang Chiou 			}
277*90899cc0SChe-liang Chiou 			udelay(1);
278*90899cc0SChe-liang Chiou 			burst = burst_count(tpm_read_word(&lpc_tpm_dev
279*90899cc0SChe-liang Chiou 						     [locality].tpm_status));
280*90899cc0SChe-liang Chiou 		}
281*90899cc0SChe-liang Chiou 
282*90899cc0SChe-liang Chiou 		max_cycles = 0;
283*90899cc0SChe-liang Chiou 
284*90899cc0SChe-liang Chiou 		/*
285*90899cc0SChe-liang Chiou 		 * Calculate number of bytes the TPM is ready to accept in one
286*90899cc0SChe-liang Chiou 		 * shot.
287*90899cc0SChe-liang Chiou 		 *
288*90899cc0SChe-liang Chiou 		 * We want to send the last byte outside of the loop (hence
289*90899cc0SChe-liang Chiou 		 * the -1 below) to make sure that the 'expected' status bit
290*90899cc0SChe-liang Chiou 		 * changes to zero exactly after the last byte is fed into the
291*90899cc0SChe-liang Chiou 		 * FIFO.
292*90899cc0SChe-liang Chiou 		 */
293*90899cc0SChe-liang Chiou 		count = min(burst, len - offset - 1);
294*90899cc0SChe-liang Chiou 		while (count--)
295*90899cc0SChe-liang Chiou 			tpm_write_byte(data[offset++],
296*90899cc0SChe-liang Chiou 				  &lpc_tpm_dev[locality].data);
297*90899cc0SChe-liang Chiou 
298*90899cc0SChe-liang Chiou 		value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
299*90899cc0SChe-liang Chiou 				     TIS_STS_VALID, TIS_STS_VALID);
300*90899cc0SChe-liang Chiou 
301*90899cc0SChe-liang Chiou 		if ((value == TPM_TIMEOUT_ERR) || !(value & TIS_STS_EXPECT)) {
302*90899cc0SChe-liang Chiou 			printf("%s:%d TPM command feed overflow\n",
303*90899cc0SChe-liang Chiou 			       __FILE__, __LINE__);
304*90899cc0SChe-liang Chiou 			return TPM_DRIVER_ERR;
305*90899cc0SChe-liang Chiou 		}
306*90899cc0SChe-liang Chiou 
307*90899cc0SChe-liang Chiou 		burst = burst_count(value);
308*90899cc0SChe-liang Chiou 		if ((offset == (len - 1)) && burst) {
309*90899cc0SChe-liang Chiou 			/*
310*90899cc0SChe-liang Chiou 			 * We need to be able to send the last byte to the
311*90899cc0SChe-liang Chiou 			 * device, so burst size must be nonzero before we
312*90899cc0SChe-liang Chiou 			 * break out.
313*90899cc0SChe-liang Chiou 			 */
314*90899cc0SChe-liang Chiou 			break;
315*90899cc0SChe-liang Chiou 		}
316*90899cc0SChe-liang Chiou 	}
317*90899cc0SChe-liang Chiou 
318*90899cc0SChe-liang Chiou 	/* Send the last byte. */
319*90899cc0SChe-liang Chiou 	tpm_write_byte(data[offset++], &lpc_tpm_dev[locality].data);
320*90899cc0SChe-liang Chiou 	/*
321*90899cc0SChe-liang Chiou 	 * Verify that TPM does not expect any more data as part of this
322*90899cc0SChe-liang Chiou 	 * command.
323*90899cc0SChe-liang Chiou 	 */
324*90899cc0SChe-liang Chiou 	value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
325*90899cc0SChe-liang Chiou 			     TIS_STS_VALID, TIS_STS_VALID);
326*90899cc0SChe-liang Chiou 	if ((value == TPM_TIMEOUT_ERR) || (value & TIS_STS_EXPECT)) {
327*90899cc0SChe-liang Chiou 		printf("%s:%d unexpected TPM status 0x%x\n",
328*90899cc0SChe-liang Chiou 		       __FILE__, __LINE__, value);
329*90899cc0SChe-liang Chiou 		return TPM_DRIVER_ERR;
330*90899cc0SChe-liang Chiou 	}
331*90899cc0SChe-liang Chiou 
332*90899cc0SChe-liang Chiou 	/* OK, sitting pretty, let's start the command execution. */
333*90899cc0SChe-liang Chiou 	tpm_write_word(TIS_STS_TPM_GO, &lpc_tpm_dev[locality].tpm_status);
334*90899cc0SChe-liang Chiou 	return 0;
335*90899cc0SChe-liang Chiou }
336*90899cc0SChe-liang Chiou 
337*90899cc0SChe-liang Chiou /*
338*90899cc0SChe-liang Chiou  * tis_readresponse()
339*90899cc0SChe-liang Chiou  *
340*90899cc0SChe-liang Chiou  * read the TPM device response after a command was issued.
341*90899cc0SChe-liang Chiou  *
342*90899cc0SChe-liang Chiou  * @buffer - address where to read the response, byte by byte.
343*90899cc0SChe-liang Chiou  * @len - pointer to the size of buffer
344*90899cc0SChe-liang Chiou  *
345*90899cc0SChe-liang Chiou  * On success stores the number of received bytes to len and returns 0. On
346*90899cc0SChe-liang Chiou  * errors (misformatted TPM data or synchronization problems) returns
347*90899cc0SChe-liang Chiou  * TPM_DRIVER_ERR.
348*90899cc0SChe-liang Chiou  */
349*90899cc0SChe-liang Chiou static u32 tis_readresponse(u8 *buffer, u32 *len)
350*90899cc0SChe-liang Chiou {
351*90899cc0SChe-liang Chiou 	u16 burst;
352*90899cc0SChe-liang Chiou 	u32 value;
353*90899cc0SChe-liang Chiou 	u32 offset = 0;
354*90899cc0SChe-liang Chiou 	u8 locality = 0;
355*90899cc0SChe-liang Chiou 	const u32 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID;
356*90899cc0SChe-liang Chiou 	u32 expected_count = *len;
357*90899cc0SChe-liang Chiou 	int max_cycles = 0;
358*90899cc0SChe-liang Chiou 
359*90899cc0SChe-liang Chiou 	/* Wait for the TPM to process the command. */
360*90899cc0SChe-liang Chiou 	value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
361*90899cc0SChe-liang Chiou 			      has_data, has_data);
362*90899cc0SChe-liang Chiou 	if (value == TPM_TIMEOUT_ERR) {
363*90899cc0SChe-liang Chiou 		printf("%s:%d failed processing command\n",
364*90899cc0SChe-liang Chiou 		       __FILE__, __LINE__);
365*90899cc0SChe-liang Chiou 		return TPM_DRIVER_ERR;
366*90899cc0SChe-liang Chiou 	}
367*90899cc0SChe-liang Chiou 
368*90899cc0SChe-liang Chiou 	do {
369*90899cc0SChe-liang Chiou 		while ((burst = burst_count(value)) == 0) {
370*90899cc0SChe-liang Chiou 			if (max_cycles++ == MAX_DELAY_US) {
371*90899cc0SChe-liang Chiou 				printf("%s:%d TPM stuck on read\n",
372*90899cc0SChe-liang Chiou 				       __FILE__, __LINE__);
373*90899cc0SChe-liang Chiou 				return TPM_DRIVER_ERR;
374*90899cc0SChe-liang Chiou 			}
375*90899cc0SChe-liang Chiou 			udelay(1);
376*90899cc0SChe-liang Chiou 			value = tpm_read_word(&lpc_tpm_dev
377*90899cc0SChe-liang Chiou 					      [locality].tpm_status);
378*90899cc0SChe-liang Chiou 		}
379*90899cc0SChe-liang Chiou 
380*90899cc0SChe-liang Chiou 		max_cycles = 0;
381*90899cc0SChe-liang Chiou 
382*90899cc0SChe-liang Chiou 		while (burst-- && (offset < expected_count)) {
383*90899cc0SChe-liang Chiou 			buffer[offset++] = tpm_read_byte(&lpc_tpm_dev
384*90899cc0SChe-liang Chiou 							 [locality].data);
385*90899cc0SChe-liang Chiou 
386*90899cc0SChe-liang Chiou 			if (offset == 6) {
387*90899cc0SChe-liang Chiou 				/*
388*90899cc0SChe-liang Chiou 				 * We got the first six bytes of the reply,
389*90899cc0SChe-liang Chiou 				 * let's figure out how many bytes to expect
390*90899cc0SChe-liang Chiou 				 * total - it is stored as a 4 byte number in
391*90899cc0SChe-liang Chiou 				 * network order, starting with offset 2 into
392*90899cc0SChe-liang Chiou 				 * the body of the reply.
393*90899cc0SChe-liang Chiou 				 */
394*90899cc0SChe-liang Chiou 				u32 real_length;
395*90899cc0SChe-liang Chiou 				memcpy(&real_length,
396*90899cc0SChe-liang Chiou 				       buffer + 2,
397*90899cc0SChe-liang Chiou 				       sizeof(real_length));
398*90899cc0SChe-liang Chiou 				expected_count = be32_to_cpu(real_length);
399*90899cc0SChe-liang Chiou 
400*90899cc0SChe-liang Chiou 				if ((expected_count < offset) ||
401*90899cc0SChe-liang Chiou 				    (expected_count > *len)) {
402*90899cc0SChe-liang Chiou 					printf("%s:%d bad response size %d\n",
403*90899cc0SChe-liang Chiou 					       __FILE__, __LINE__,
404*90899cc0SChe-liang Chiou 					       expected_count);
405*90899cc0SChe-liang Chiou 					return TPM_DRIVER_ERR;
406*90899cc0SChe-liang Chiou 				}
407*90899cc0SChe-liang Chiou 			}
408*90899cc0SChe-liang Chiou 		}
409*90899cc0SChe-liang Chiou 
410*90899cc0SChe-liang Chiou 		/* Wait for the next portion. */
411*90899cc0SChe-liang Chiou 		value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
412*90899cc0SChe-liang Chiou 				     TIS_STS_VALID, TIS_STS_VALID);
413*90899cc0SChe-liang Chiou 		if (value == TPM_TIMEOUT_ERR) {
414*90899cc0SChe-liang Chiou 			printf("%s:%d failed to read response\n",
415*90899cc0SChe-liang Chiou 			       __FILE__, __LINE__);
416*90899cc0SChe-liang Chiou 			return TPM_DRIVER_ERR;
417*90899cc0SChe-liang Chiou 		}
418*90899cc0SChe-liang Chiou 
419*90899cc0SChe-liang Chiou 		if (offset == expected_count)
420*90899cc0SChe-liang Chiou 			break;	/* We got all we needed. */
421*90899cc0SChe-liang Chiou 
422*90899cc0SChe-liang Chiou 	} while ((value & has_data) == has_data);
423*90899cc0SChe-liang Chiou 
424*90899cc0SChe-liang Chiou 	/*
425*90899cc0SChe-liang Chiou 	 * Make sure we indeed read all there was. The TIS_STS_VALID bit is
426*90899cc0SChe-liang Chiou 	 * known to be set.
427*90899cc0SChe-liang Chiou 	 */
428*90899cc0SChe-liang Chiou 	if (value & TIS_STS_DATA_AVAILABLE) {
429*90899cc0SChe-liang Chiou 		printf("%s:%d wrong receive status %x\n",
430*90899cc0SChe-liang Chiou 		       __FILE__, __LINE__, value);
431*90899cc0SChe-liang Chiou 		return TPM_DRIVER_ERR;
432*90899cc0SChe-liang Chiou 	}
433*90899cc0SChe-liang Chiou 
434*90899cc0SChe-liang Chiou 	/* Tell the TPM that we are done. */
435*90899cc0SChe-liang Chiou 	tpm_write_word(TIS_STS_COMMAND_READY, &lpc_tpm_dev
436*90899cc0SChe-liang Chiou 		  [locality].tpm_status);
437*90899cc0SChe-liang Chiou 	*len = offset;
438*90899cc0SChe-liang Chiou 	return 0;
439*90899cc0SChe-liang Chiou }
440*90899cc0SChe-liang Chiou 
441*90899cc0SChe-liang Chiou int tis_open(void)
442*90899cc0SChe-liang Chiou {
443*90899cc0SChe-liang Chiou 	u8 locality = 0; /* we use locality zero for everything. */
444*90899cc0SChe-liang Chiou 
445*90899cc0SChe-liang Chiou 	if (tis_close())
446*90899cc0SChe-liang Chiou 		return TPM_DRIVER_ERR;
447*90899cc0SChe-liang Chiou 
448*90899cc0SChe-liang Chiou 	/* now request access to locality. */
449*90899cc0SChe-liang Chiou 	tpm_write_word(TIS_ACCESS_REQUEST_USE, &lpc_tpm_dev[locality].access);
450*90899cc0SChe-liang Chiou 
451*90899cc0SChe-liang Chiou 	/* did we get a lock? */
452*90899cc0SChe-liang Chiou 	if (tis_wait_reg(&lpc_tpm_dev[locality].access,
453*90899cc0SChe-liang Chiou 			 TIS_ACCESS_ACTIVE_LOCALITY,
454*90899cc0SChe-liang Chiou 			 TIS_ACCESS_ACTIVE_LOCALITY) == TPM_TIMEOUT_ERR) {
455*90899cc0SChe-liang Chiou 		printf("%s:%d - failed to lock locality %d\n",
456*90899cc0SChe-liang Chiou 		       __FILE__, __LINE__, locality);
457*90899cc0SChe-liang Chiou 		return TPM_DRIVER_ERR;
458*90899cc0SChe-liang Chiou 	}
459*90899cc0SChe-liang Chiou 
460*90899cc0SChe-liang Chiou 	tpm_write_word(TIS_STS_COMMAND_READY,
461*90899cc0SChe-liang Chiou 		       &lpc_tpm_dev[locality].tpm_status);
462*90899cc0SChe-liang Chiou 	return 0;
463*90899cc0SChe-liang Chiou }
464*90899cc0SChe-liang Chiou 
465*90899cc0SChe-liang Chiou int tis_close(void)
466*90899cc0SChe-liang Chiou {
467*90899cc0SChe-liang Chiou 	u8 locality = 0;
468*90899cc0SChe-liang Chiou 
469*90899cc0SChe-liang Chiou 	if (tpm_read_word(&lpc_tpm_dev[locality].access) &
470*90899cc0SChe-liang Chiou 	    TIS_ACCESS_ACTIVE_LOCALITY) {
471*90899cc0SChe-liang Chiou 		tpm_write_word(TIS_ACCESS_ACTIVE_LOCALITY,
472*90899cc0SChe-liang Chiou 			       &lpc_tpm_dev[locality].access);
473*90899cc0SChe-liang Chiou 
474*90899cc0SChe-liang Chiou 		if (tis_wait_reg(&lpc_tpm_dev[locality].access,
475*90899cc0SChe-liang Chiou 				 TIS_ACCESS_ACTIVE_LOCALITY, 0) ==
476*90899cc0SChe-liang Chiou 		    TPM_TIMEOUT_ERR) {
477*90899cc0SChe-liang Chiou 			printf("%s:%d - failed to release locality %d\n",
478*90899cc0SChe-liang Chiou 			       __FILE__, __LINE__, locality);
479*90899cc0SChe-liang Chiou 			return TPM_DRIVER_ERR;
480*90899cc0SChe-liang Chiou 		}
481*90899cc0SChe-liang Chiou 	}
482*90899cc0SChe-liang Chiou 	return 0;
483*90899cc0SChe-liang Chiou }
484*90899cc0SChe-liang Chiou 
485*90899cc0SChe-liang Chiou int tis_sendrecv(const u8 *sendbuf, size_t send_size,
486*90899cc0SChe-liang Chiou 		 u8 *recvbuf, size_t *recv_len)
487*90899cc0SChe-liang Chiou {
488*90899cc0SChe-liang Chiou 	if (tis_senddata(sendbuf, send_size)) {
489*90899cc0SChe-liang Chiou 		printf("%s:%d failed sending data to TPM\n",
490*90899cc0SChe-liang Chiou 		       __FILE__, __LINE__);
491*90899cc0SChe-liang Chiou 		return TPM_DRIVER_ERR;
492*90899cc0SChe-liang Chiou 	}
493*90899cc0SChe-liang Chiou 
494*90899cc0SChe-liang Chiou 	return tis_readresponse(recvbuf, (u32 *)recv_len);
495*90899cc0SChe-liang Chiou }
496