xref: /OK3568_Linux_fs/u-boot/drivers/tpm/tpm_tis_lpc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2011 The Chromium OS Authors.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun /*
8*4882a593Smuzhiyun  * The code in this file is based on the article "Writing a TPM Device Driver"
9*4882a593Smuzhiyun  * published on http://ptgmedia.pearsoncmg.com.
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * One principal difference is that in the simplest config the other than 0
12*4882a593Smuzhiyun  * TPM localities do not get mapped by some devices (for instance, by Infineon
13*4882a593Smuzhiyun  * slb9635), so this driver provides access to locality 0 only.
14*4882a593Smuzhiyun  */
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <common.h>
17*4882a593Smuzhiyun #include <dm.h>
18*4882a593Smuzhiyun #include <mapmem.h>
19*4882a593Smuzhiyun #include <tpm.h>
20*4882a593Smuzhiyun #include <asm/io.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define PREFIX "lpc_tpm: "
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun enum i2c_chip_type {
25*4882a593Smuzhiyun 	SLB9635,
26*4882a593Smuzhiyun 	AT97SC3204,
27*4882a593Smuzhiyun };
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun static const char * const chip_name[] = {
30*4882a593Smuzhiyun 	[SLB9635] = "Infineon SLB9635 TT 1.2",
31*4882a593Smuzhiyun 	[AT97SC3204] = "Atmel AT97SC3204",
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun static const u32 chip_didvid[] = {
35*4882a593Smuzhiyun 	[SLB9635] = 0xb15d1,
36*4882a593Smuzhiyun 	[AT97SC3204] = 0x32041114,
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun struct tpm_locality {
40*4882a593Smuzhiyun 	u32 access;
41*4882a593Smuzhiyun 	u8 padding0[4];
42*4882a593Smuzhiyun 	u32 int_enable;
43*4882a593Smuzhiyun 	u8 vector;
44*4882a593Smuzhiyun 	u8 padding1[3];
45*4882a593Smuzhiyun 	u32 int_status;
46*4882a593Smuzhiyun 	u32 int_capability;
47*4882a593Smuzhiyun 	u32 tpm_status;
48*4882a593Smuzhiyun 	u8 padding2[8];
49*4882a593Smuzhiyun 	u8 data;
50*4882a593Smuzhiyun 	u8 padding3[3803];
51*4882a593Smuzhiyun 	u32 did_vid;
52*4882a593Smuzhiyun 	u8 rid;
53*4882a593Smuzhiyun 	u8 padding4[251];
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun struct tpm_tis_lpc_priv {
57*4882a593Smuzhiyun 	struct tpm_locality *regs;
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun /*
61*4882a593Smuzhiyun  * This pointer refers to the TPM chip, 5 of its localities are mapped as an
62*4882a593Smuzhiyun  * array.
63*4882a593Smuzhiyun  */
64*4882a593Smuzhiyun #define TPM_TOTAL_LOCALITIES	5
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun /* Some registers' bit field definitions */
67*4882a593Smuzhiyun #define TIS_STS_VALID                  (1 << 7) /* 0x80 */
68*4882a593Smuzhiyun #define TIS_STS_COMMAND_READY          (1 << 6) /* 0x40 */
69*4882a593Smuzhiyun #define TIS_STS_TPM_GO                 (1 << 5) /* 0x20 */
70*4882a593Smuzhiyun #define TIS_STS_DATA_AVAILABLE         (1 << 4) /* 0x10 */
71*4882a593Smuzhiyun #define TIS_STS_EXPECT                 (1 << 3) /* 0x08 */
72*4882a593Smuzhiyun #define TIS_STS_RESPONSE_RETRY         (1 << 1) /* 0x02 */
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun #define TIS_ACCESS_TPM_REG_VALID_STS   (1 << 7) /* 0x80 */
75*4882a593Smuzhiyun #define TIS_ACCESS_ACTIVE_LOCALITY     (1 << 5) /* 0x20 */
76*4882a593Smuzhiyun #define TIS_ACCESS_BEEN_SEIZED         (1 << 4) /* 0x10 */
77*4882a593Smuzhiyun #define TIS_ACCESS_SEIZE               (1 << 3) /* 0x08 */
78*4882a593Smuzhiyun #define TIS_ACCESS_PENDING_REQUEST     (1 << 2) /* 0x04 */
79*4882a593Smuzhiyun #define TIS_ACCESS_REQUEST_USE         (1 << 1) /* 0x02 */
80*4882a593Smuzhiyun #define TIS_ACCESS_TPM_ESTABLISHMENT   (1 << 0) /* 0x01 */
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun #define TIS_STS_BURST_COUNT_MASK       (0xffff)
83*4882a593Smuzhiyun #define TIS_STS_BURST_COUNT_SHIFT      (8)
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun  /* 1 second is plenty for anything TPM does. */
86*4882a593Smuzhiyun #define MAX_DELAY_US	(1000 * 1000)
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun /* Retrieve burst count value out of the status register contents. */
burst_count(u32 status)89*4882a593Smuzhiyun static u16 burst_count(u32 status)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	return (status >> TIS_STS_BURST_COUNT_SHIFT) &
92*4882a593Smuzhiyun 			TIS_STS_BURST_COUNT_MASK;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun /* TPM access wrappers to support tracing */
tpm_read_byte(struct tpm_tis_lpc_priv * priv,const u8 * ptr)96*4882a593Smuzhiyun static u8 tpm_read_byte(struct tpm_tis_lpc_priv *priv, const u8 *ptr)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	u8  ret = readb(ptr);
99*4882a593Smuzhiyun 	debug(PREFIX "Read reg 0x%4.4x returns 0x%2.2x\n",
100*4882a593Smuzhiyun 	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, ret);
101*4882a593Smuzhiyun 	return ret;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
tpm_read_word(struct tpm_tis_lpc_priv * priv,const u32 * ptr)104*4882a593Smuzhiyun static u32 tpm_read_word(struct tpm_tis_lpc_priv *priv, const u32 *ptr)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun 	u32  ret = readl(ptr);
107*4882a593Smuzhiyun 	debug(PREFIX "Read reg 0x%4.4x returns 0x%8.8x\n",
108*4882a593Smuzhiyun 	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, ret);
109*4882a593Smuzhiyun 	return ret;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
tpm_write_byte(struct tpm_tis_lpc_priv * priv,u8 value,u8 * ptr)112*4882a593Smuzhiyun static void tpm_write_byte(struct tpm_tis_lpc_priv *priv, u8 value, u8 *ptr)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	debug(PREFIX "Write reg 0x%4.4x with 0x%2.2x\n",
115*4882a593Smuzhiyun 	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, value);
116*4882a593Smuzhiyun 	writeb(value, ptr);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
tpm_write_word(struct tpm_tis_lpc_priv * priv,u32 value,u32 * ptr)119*4882a593Smuzhiyun static void tpm_write_word(struct tpm_tis_lpc_priv *priv, u32 value,
120*4882a593Smuzhiyun 			   u32 *ptr)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	debug(PREFIX "Write reg 0x%4.4x with 0x%8.8x\n",
123*4882a593Smuzhiyun 	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, value);
124*4882a593Smuzhiyun 	writel(value, ptr);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun /*
128*4882a593Smuzhiyun  * tis_wait_reg()
129*4882a593Smuzhiyun  *
130*4882a593Smuzhiyun  * Wait for at least a second for a register to change its state to match the
131*4882a593Smuzhiyun  * expected state. Normally the transition happens within microseconds.
132*4882a593Smuzhiyun  *
133*4882a593Smuzhiyun  * @reg - pointer to the TPM register
134*4882a593Smuzhiyun  * @mask - bitmask for the bitfield(s) to watch
135*4882a593Smuzhiyun  * @expected - value the field(s) are supposed to be set to
136*4882a593Smuzhiyun  *
137*4882a593Smuzhiyun  * Returns the register contents in case the expected value was found in the
138*4882a593Smuzhiyun  * appropriate register bits, or -ETIMEDOUT on timeout.
139*4882a593Smuzhiyun  */
tis_wait_reg(struct tpm_tis_lpc_priv * priv,u32 * reg,u8 mask,u8 expected)140*4882a593Smuzhiyun static int tis_wait_reg(struct tpm_tis_lpc_priv *priv, u32 *reg, u8 mask,
141*4882a593Smuzhiyun 			u8 expected)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	u32 time_us = MAX_DELAY_US;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	while (time_us > 0) {
146*4882a593Smuzhiyun 		u32 value = tpm_read_word(priv, reg);
147*4882a593Smuzhiyun 		if ((value & mask) == expected)
148*4882a593Smuzhiyun 			return value;
149*4882a593Smuzhiyun 		udelay(1); /* 1 us */
150*4882a593Smuzhiyun 		time_us--;
151*4882a593Smuzhiyun 	}
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	return -ETIMEDOUT;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun /*
157*4882a593Smuzhiyun  * Probe the TPM device and try determining its manufacturer/device name.
158*4882a593Smuzhiyun  *
159*4882a593Smuzhiyun  * Returns 0 on success, -ve on error
160*4882a593Smuzhiyun  */
tpm_tis_lpc_probe(struct udevice * dev)161*4882a593Smuzhiyun static int tpm_tis_lpc_probe(struct udevice *dev)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun 	struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
164*4882a593Smuzhiyun 	fdt_addr_t addr;
165*4882a593Smuzhiyun 	u32 didvid;
166*4882a593Smuzhiyun 	ulong chip_type = dev_get_driver_data(dev);
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	addr = devfdt_get_addr(dev);
169*4882a593Smuzhiyun 	if (addr == FDT_ADDR_T_NONE)
170*4882a593Smuzhiyun 		return -EINVAL;
171*4882a593Smuzhiyun 	priv->regs = map_sysmem(addr, 0);
172*4882a593Smuzhiyun 	didvid = tpm_read_word(priv, &priv->regs[0].did_vid);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	if (didvid != chip_didvid[chip_type]) {
175*4882a593Smuzhiyun 		u32 vid, did;
176*4882a593Smuzhiyun 		vid = didvid & 0xffff;
177*4882a593Smuzhiyun 		did = (didvid >> 16) & 0xffff;
178*4882a593Smuzhiyun 		debug("Invalid vendor/device ID %04x/%04x\n", vid, did);
179*4882a593Smuzhiyun 		return -ENODEV;
180*4882a593Smuzhiyun 	}
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	debug("Found TPM: %s\n", chip_name[chip_type]);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	return 0;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun /*
188*4882a593Smuzhiyun  * tis_senddata()
189*4882a593Smuzhiyun  *
190*4882a593Smuzhiyun  * send the passed in data to the TPM device.
191*4882a593Smuzhiyun  *
192*4882a593Smuzhiyun  * @data - address of the data to send, byte by byte
193*4882a593Smuzhiyun  * @len - length of the data to send
194*4882a593Smuzhiyun  *
195*4882a593Smuzhiyun  * Returns 0 on success, -ve on error (in case the device does not accept
196*4882a593Smuzhiyun  * the entire command).
197*4882a593Smuzhiyun  */
tis_senddata(struct udevice * dev,const u8 * data,size_t len)198*4882a593Smuzhiyun static int tis_senddata(struct udevice *dev, const u8 *data, size_t len)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun 	struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
201*4882a593Smuzhiyun 	struct tpm_locality *regs = priv->regs;
202*4882a593Smuzhiyun 	u32 offset = 0;
203*4882a593Smuzhiyun 	u16 burst = 0;
204*4882a593Smuzhiyun 	u32 max_cycles = 0;
205*4882a593Smuzhiyun 	u8 locality = 0;
206*4882a593Smuzhiyun 	u32 value;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	value = tis_wait_reg(priv, &regs[locality].tpm_status,
209*4882a593Smuzhiyun 			     TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY);
210*4882a593Smuzhiyun 	if (value == -ETIMEDOUT) {
211*4882a593Smuzhiyun 		printf("%s:%d - failed to get 'command_ready' status\n",
212*4882a593Smuzhiyun 		       __FILE__, __LINE__);
213*4882a593Smuzhiyun 		return value;
214*4882a593Smuzhiyun 	}
215*4882a593Smuzhiyun 	burst = burst_count(value);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	while (1) {
218*4882a593Smuzhiyun 		unsigned count;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 		/* Wait till the device is ready to accept more data. */
221*4882a593Smuzhiyun 		while (!burst) {
222*4882a593Smuzhiyun 			if (max_cycles++ == MAX_DELAY_US) {
223*4882a593Smuzhiyun 				printf("%s:%d failed to feed %zd bytes of %zd\n",
224*4882a593Smuzhiyun 				       __FILE__, __LINE__, len - offset, len);
225*4882a593Smuzhiyun 				return -ETIMEDOUT;
226*4882a593Smuzhiyun 			}
227*4882a593Smuzhiyun 			udelay(1);
228*4882a593Smuzhiyun 			burst = burst_count(tpm_read_word(priv,
229*4882a593Smuzhiyun 					&regs[locality].tpm_status));
230*4882a593Smuzhiyun 		}
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 		max_cycles = 0;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 		/*
235*4882a593Smuzhiyun 		 * Calculate number of bytes the TPM is ready to accept in one
236*4882a593Smuzhiyun 		 * shot.
237*4882a593Smuzhiyun 		 *
238*4882a593Smuzhiyun 		 * We want to send the last byte outside of the loop (hence
239*4882a593Smuzhiyun 		 * the -1 below) to make sure that the 'expected' status bit
240*4882a593Smuzhiyun 		 * changes to zero exactly after the last byte is fed into the
241*4882a593Smuzhiyun 		 * FIFO.
242*4882a593Smuzhiyun 		 */
243*4882a593Smuzhiyun 		count = min((size_t)burst, len - offset - 1);
244*4882a593Smuzhiyun 		while (count--)
245*4882a593Smuzhiyun 			tpm_write_byte(priv, data[offset++],
246*4882a593Smuzhiyun 				       &regs[locality].data);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 		value = tis_wait_reg(priv, &regs[locality].tpm_status,
249*4882a593Smuzhiyun 				     TIS_STS_VALID, TIS_STS_VALID);
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 		if ((value == -ETIMEDOUT) || !(value & TIS_STS_EXPECT)) {
252*4882a593Smuzhiyun 			printf("%s:%d TPM command feed overflow\n",
253*4882a593Smuzhiyun 			       __FILE__, __LINE__);
254*4882a593Smuzhiyun 			return value == -ETIMEDOUT ? value : -EIO;
255*4882a593Smuzhiyun 		}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 		burst = burst_count(value);
258*4882a593Smuzhiyun 		if ((offset == (len - 1)) && burst) {
259*4882a593Smuzhiyun 			/*
260*4882a593Smuzhiyun 			 * We need to be able to send the last byte to the
261*4882a593Smuzhiyun 			 * device, so burst size must be nonzero before we
262*4882a593Smuzhiyun 			 * break out.
263*4882a593Smuzhiyun 			 */
264*4882a593Smuzhiyun 			break;
265*4882a593Smuzhiyun 		}
266*4882a593Smuzhiyun 	}
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	/* Send the last byte. */
269*4882a593Smuzhiyun 	tpm_write_byte(priv, data[offset++], &regs[locality].data);
270*4882a593Smuzhiyun 	/*
271*4882a593Smuzhiyun 	 * Verify that TPM does not expect any more data as part of this
272*4882a593Smuzhiyun 	 * command.
273*4882a593Smuzhiyun 	 */
274*4882a593Smuzhiyun 	value = tis_wait_reg(priv, &regs[locality].tpm_status,
275*4882a593Smuzhiyun 			     TIS_STS_VALID, TIS_STS_VALID);
276*4882a593Smuzhiyun 	if ((value == -ETIMEDOUT) || (value & TIS_STS_EXPECT)) {
277*4882a593Smuzhiyun 		printf("%s:%d unexpected TPM status 0x%x\n",
278*4882a593Smuzhiyun 		       __FILE__, __LINE__, value);
279*4882a593Smuzhiyun 		return value == -ETIMEDOUT ? value : -EIO;
280*4882a593Smuzhiyun 	}
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	/* OK, sitting pretty, let's start the command execution. */
283*4882a593Smuzhiyun 	tpm_write_word(priv, TIS_STS_TPM_GO, &regs[locality].tpm_status);
284*4882a593Smuzhiyun 	return 0;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun /*
288*4882a593Smuzhiyun  * tis_readresponse()
289*4882a593Smuzhiyun  *
290*4882a593Smuzhiyun  * read the TPM device response after a command was issued.
291*4882a593Smuzhiyun  *
292*4882a593Smuzhiyun  * @buffer - address where to read the response, byte by byte.
293*4882a593Smuzhiyun  * @len - pointer to the size of buffer
294*4882a593Smuzhiyun  *
295*4882a593Smuzhiyun  * On success stores the number of received bytes to len and returns 0. On
296*4882a593Smuzhiyun  * errors (misformatted TPM data or synchronization problems) returns
297*4882a593Smuzhiyun  * -ve value.
298*4882a593Smuzhiyun  */
tis_readresponse(struct udevice * dev,u8 * buffer,size_t len)299*4882a593Smuzhiyun static int tis_readresponse(struct udevice *dev, u8 *buffer, size_t len)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun 	struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
302*4882a593Smuzhiyun 	struct tpm_locality *regs = priv->regs;
303*4882a593Smuzhiyun 	u16 burst;
304*4882a593Smuzhiyun 	u32 value;
305*4882a593Smuzhiyun 	u32 offset = 0;
306*4882a593Smuzhiyun 	u8 locality = 0;
307*4882a593Smuzhiyun 	const u32 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID;
308*4882a593Smuzhiyun 	u32 expected_count = len;
309*4882a593Smuzhiyun 	int max_cycles = 0;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	/* Wait for the TPM to process the command. */
312*4882a593Smuzhiyun 	value = tis_wait_reg(priv, &regs[locality].tpm_status,
313*4882a593Smuzhiyun 			      has_data, has_data);
314*4882a593Smuzhiyun 	if (value == -ETIMEDOUT) {
315*4882a593Smuzhiyun 		printf("%s:%d failed processing command\n",
316*4882a593Smuzhiyun 		       __FILE__, __LINE__);
317*4882a593Smuzhiyun 		return value;
318*4882a593Smuzhiyun 	}
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	do {
321*4882a593Smuzhiyun 		while ((burst = burst_count(value)) == 0) {
322*4882a593Smuzhiyun 			if (max_cycles++ == MAX_DELAY_US) {
323*4882a593Smuzhiyun 				printf("%s:%d TPM stuck on read\n",
324*4882a593Smuzhiyun 				       __FILE__, __LINE__);
325*4882a593Smuzhiyun 				return -EIO;
326*4882a593Smuzhiyun 			}
327*4882a593Smuzhiyun 			udelay(1);
328*4882a593Smuzhiyun 			value = tpm_read_word(priv, &regs[locality].tpm_status);
329*4882a593Smuzhiyun 		}
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 		max_cycles = 0;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 		while (burst-- && (offset < expected_count)) {
334*4882a593Smuzhiyun 			buffer[offset++] = tpm_read_byte(priv,
335*4882a593Smuzhiyun 						&regs[locality].data);
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 			if (offset == 6) {
338*4882a593Smuzhiyun 				/*
339*4882a593Smuzhiyun 				 * We got the first six bytes of the reply,
340*4882a593Smuzhiyun 				 * let's figure out how many bytes to expect
341*4882a593Smuzhiyun 				 * total - it is stored as a 4 byte number in
342*4882a593Smuzhiyun 				 * network order, starting with offset 2 into
343*4882a593Smuzhiyun 				 * the body of the reply.
344*4882a593Smuzhiyun 				 */
345*4882a593Smuzhiyun 				u32 real_length;
346*4882a593Smuzhiyun 				memcpy(&real_length,
347*4882a593Smuzhiyun 				       buffer + 2,
348*4882a593Smuzhiyun 				       sizeof(real_length));
349*4882a593Smuzhiyun 				expected_count = be32_to_cpu(real_length);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 				if ((expected_count < offset) ||
352*4882a593Smuzhiyun 				    (expected_count > len)) {
353*4882a593Smuzhiyun 					printf("%s:%d bad response size %d\n",
354*4882a593Smuzhiyun 					       __FILE__, __LINE__,
355*4882a593Smuzhiyun 					       expected_count);
356*4882a593Smuzhiyun 					return -ENOSPC;
357*4882a593Smuzhiyun 				}
358*4882a593Smuzhiyun 			}
359*4882a593Smuzhiyun 		}
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 		/* Wait for the next portion. */
362*4882a593Smuzhiyun 		value = tis_wait_reg(priv, &regs[locality].tpm_status,
363*4882a593Smuzhiyun 				     TIS_STS_VALID, TIS_STS_VALID);
364*4882a593Smuzhiyun 		if (value == -ETIMEDOUT) {
365*4882a593Smuzhiyun 			printf("%s:%d failed to read response\n",
366*4882a593Smuzhiyun 			       __FILE__, __LINE__);
367*4882a593Smuzhiyun 			return value;
368*4882a593Smuzhiyun 		}
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 		if (offset == expected_count)
371*4882a593Smuzhiyun 			break;	/* We got all we needed. */
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	} while ((value & has_data) == has_data);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	/*
376*4882a593Smuzhiyun 	 * Make sure we indeed read all there was. The TIS_STS_VALID bit is
377*4882a593Smuzhiyun 	 * known to be set.
378*4882a593Smuzhiyun 	 */
379*4882a593Smuzhiyun 	if (value & TIS_STS_DATA_AVAILABLE) {
380*4882a593Smuzhiyun 		printf("%s:%d wrong receive status %x\n",
381*4882a593Smuzhiyun 		       __FILE__, __LINE__, value);
382*4882a593Smuzhiyun 		return -EBADMSG;
383*4882a593Smuzhiyun 	}
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	/* Tell the TPM that we are done. */
386*4882a593Smuzhiyun 	tpm_write_word(priv, TIS_STS_COMMAND_READY,
387*4882a593Smuzhiyun 		       &regs[locality].tpm_status);
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	return offset;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun 
tpm_tis_lpc_open(struct udevice * dev)392*4882a593Smuzhiyun static int tpm_tis_lpc_open(struct udevice *dev)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun 	struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
395*4882a593Smuzhiyun 	struct tpm_locality *regs = priv->regs;
396*4882a593Smuzhiyun 	u8 locality = 0; /* we use locality zero for everything. */
397*4882a593Smuzhiyun 	int ret;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	/* now request access to locality. */
400*4882a593Smuzhiyun 	tpm_write_word(priv, TIS_ACCESS_REQUEST_USE, &regs[locality].access);
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	/* did we get a lock? */
403*4882a593Smuzhiyun 	ret = tis_wait_reg(priv, &regs[locality].access,
404*4882a593Smuzhiyun 			 TIS_ACCESS_ACTIVE_LOCALITY,
405*4882a593Smuzhiyun 			 TIS_ACCESS_ACTIVE_LOCALITY);
406*4882a593Smuzhiyun 	if (ret == -ETIMEDOUT) {
407*4882a593Smuzhiyun 		printf("%s:%d - failed to lock locality %d\n",
408*4882a593Smuzhiyun 		       __FILE__, __LINE__, locality);
409*4882a593Smuzhiyun 		return ret;
410*4882a593Smuzhiyun 	}
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	tpm_write_word(priv, TIS_STS_COMMAND_READY,
413*4882a593Smuzhiyun 		       &regs[locality].tpm_status);
414*4882a593Smuzhiyun 	return 0;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun 
tpm_tis_lpc_close(struct udevice * dev)417*4882a593Smuzhiyun static int tpm_tis_lpc_close(struct udevice *dev)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun 	struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
420*4882a593Smuzhiyun 	struct tpm_locality *regs = priv->regs;
421*4882a593Smuzhiyun 	u8 locality = 0;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	if (tpm_read_word(priv, &regs[locality].access) &
424*4882a593Smuzhiyun 	    TIS_ACCESS_ACTIVE_LOCALITY) {
425*4882a593Smuzhiyun 		tpm_write_word(priv, TIS_ACCESS_ACTIVE_LOCALITY,
426*4882a593Smuzhiyun 			       &regs[locality].access);
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 		if (tis_wait_reg(priv, &regs[locality].access,
429*4882a593Smuzhiyun 				 TIS_ACCESS_ACTIVE_LOCALITY, 0) == -ETIMEDOUT) {
430*4882a593Smuzhiyun 			printf("%s:%d - failed to release locality %d\n",
431*4882a593Smuzhiyun 			       __FILE__, __LINE__, locality);
432*4882a593Smuzhiyun 			return -ETIMEDOUT;
433*4882a593Smuzhiyun 		}
434*4882a593Smuzhiyun 	}
435*4882a593Smuzhiyun 	return 0;
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun 
tpm_tis_get_desc(struct udevice * dev,char * buf,int size)438*4882a593Smuzhiyun static int tpm_tis_get_desc(struct udevice *dev, char *buf, int size)
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun 	ulong chip_type = dev_get_driver_data(dev);
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	if (size < 50)
443*4882a593Smuzhiyun 		return -ENOSPC;
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	return snprintf(buf, size, "1.2 TPM (%s)",
446*4882a593Smuzhiyun 			chip_name[chip_type]);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun static const struct tpm_ops tpm_tis_lpc_ops = {
451*4882a593Smuzhiyun 	.open		= tpm_tis_lpc_open,
452*4882a593Smuzhiyun 	.close		= tpm_tis_lpc_close,
453*4882a593Smuzhiyun 	.get_desc	= tpm_tis_get_desc,
454*4882a593Smuzhiyun 	.send		= tis_senddata,
455*4882a593Smuzhiyun 	.recv		= tis_readresponse,
456*4882a593Smuzhiyun };
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun static const struct udevice_id tpm_tis_lpc_ids[] = {
459*4882a593Smuzhiyun 	{ .compatible = "infineon,slb9635lpc", .data = SLB9635 },
460*4882a593Smuzhiyun 	{ .compatible = "atmel,at97sc3204", .data = AT97SC3204 },
461*4882a593Smuzhiyun 	{ }
462*4882a593Smuzhiyun };
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun U_BOOT_DRIVER(tpm_tis_lpc) = {
465*4882a593Smuzhiyun 	.name   = "tpm_tis_lpc",
466*4882a593Smuzhiyun 	.id     = UCLASS_TPM,
467*4882a593Smuzhiyun 	.of_match = tpm_tis_lpc_ids,
468*4882a593Smuzhiyun 	.ops    = &tpm_tis_lpc_ops,
469*4882a593Smuzhiyun 	.probe	= tpm_tis_lpc_probe,
470*4882a593Smuzhiyun 	.priv_auto_alloc_size = sizeof(struct tpm_tis_lpc_priv),
471*4882a593Smuzhiyun };
472