blob: 5927377d159b0bd9edd3b3d83bab9e6b0d72da4b [file] [log] [blame]
Stefan Reinauer3008bbad2011-10-11 14:46:25 -07001/*
2 * This file is part of the coreboot project.
3 *
Stefan Reinauer3008bbad2011-10-11 14:46:25 -07004 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070012 */
13
14/*
15 * The code in this file has been heavily based on the article "Writing a TPM
16 * Device Driver" published on http://ptgmedia.pearsoncmg.com and the
17 * submission by Stefan Berger on Qemu-devel mailing list.
18 *
19 * One principal difference is that in the simplest config the other than 0
20 * TPM localities do not get mapped by some devices (for instance, by
21 * Infineon slb9635), so this driver provides access to locality 0 only.
22 */
23
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070024#include <stdlib.h>
25#include <string.h>
26#include <delay.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020027#include <device/mmio.h>
Naresh G Solanki80ff0382016-11-15 11:01:33 +053028#include <arch/acpi.h>
29#include <arch/acpigen.h>
30#include <arch/acpi_device.h>
31#include <device/device.h>
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070032#include <console/console.h>
Philipp Deppenwiesed88fb362017-10-18 20:26:18 +020033#include <security/tpm/tis.h>
Stefan Reinauerfd4f4132013-06-19 12:25:44 -070034#include <arch/early_variables.h>
Duncan Lauriedd281ed2014-10-30 15:20:19 -070035#include <device/pnp.h>
36#include "chip.h"
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070037
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070038#define PREFIX "lpc_tpm: "
Naresh G Solanki80ff0382016-11-15 11:01:33 +053039/* TCG Physical Presence Interface */
40#define TPM_PPI_UUID "3dddfaa6-361b-4eb4-a424-8d10089d1653"
41/* TCG Memory Clear Interface */
42#define TPM_MCI_UUID "376054ed-cc13-4675-901c-4756d7f2d45d"
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070043/* coreboot wrapper for TPM driver (start) */
44#define TPM_DEBUG(fmt, args...) \
Julius Wernercd49cce2019-03-05 16:53:33 -080045 if (CONFIG(DEBUG_TPM)) { \
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070046 printk(BIOS_DEBUG, PREFIX); \
Elyes HAOUASa342f392018-10-17 10:56:26 +020047 printk(BIOS_DEBUG, fmt, ##args); \
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070048 }
Aaron Durbinc4220022013-07-24 16:02:14 -050049#define TPM_DEBUG_IO_READ(reg_, val_) \
50 TPM_DEBUG("Read reg 0x%x returns 0x%x\n", (reg_), (val_))
51#define TPM_DEBUG_IO_WRITE(reg_, val_) \
52 TPM_DEBUG("Write reg 0x%x with 0x%x\n", (reg_), (val_))
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070053#define printf(x...) printk(BIOS_ERR, x)
54
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070055/* coreboot wrapper for TPM driver (end) */
56
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070057/* the macro accepts the locality value, but only locality 0 is operational */
58#define TIS_REG(LOCALITY, REG) \
Martin Rothb9810a42017-07-23 20:00:04 -060059 (void *)(CONFIG_TPM_TIS_BASE_ADDRESS + (LOCALITY << 12) + REG)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070060
61/* hardware registers' offsets */
62#define TIS_REG_ACCESS 0x0
63#define TIS_REG_INT_ENABLE 0x8
64#define TIS_REG_INT_VECTOR 0xc
65#define TIS_REG_INT_STATUS 0x10
66#define TIS_REG_INTF_CAPABILITY 0x14
67#define TIS_REG_STS 0x18
Aaron Durbinc4220022013-07-24 16:02:14 -050068#define TIS_REG_BURST_COUNT 0x19
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070069#define TIS_REG_DATA_FIFO 0x24
70#define TIS_REG_DID_VID 0xf00
71#define TIS_REG_RID 0xf04
72
73/* Some registers' bit field definitions */
74#define TIS_STS_VALID (1 << 7) /* 0x80 */
75#define TIS_STS_COMMAND_READY (1 << 6) /* 0x40 */
76#define TIS_STS_TPM_GO (1 << 5) /* 0x20 */
77#define TIS_STS_DATA_AVAILABLE (1 << 4) /* 0x10 */
78#define TIS_STS_EXPECT (1 << 3) /* 0x08 */
79#define TIS_STS_RESPONSE_RETRY (1 << 1) /* 0x02 */
80
81#define TIS_ACCESS_TPM_REG_VALID_STS (1 << 7) /* 0x80 */
82#define TIS_ACCESS_ACTIVE_LOCALITY (1 << 5) /* 0x20 */
83#define TIS_ACCESS_BEEN_SEIZED (1 << 4) /* 0x10 */
84#define TIS_ACCESS_SEIZE (1 << 3) /* 0x08 */
85#define TIS_ACCESS_PENDING_REQUEST (1 << 2) /* 0x04 */
86#define TIS_ACCESS_REQUEST_USE (1 << 1) /* 0x02 */
87#define TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0) /* 0x01 */
88
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070089/*
90 * Error value returned if a tpm register does not enter the expected state
91 * after continuous polling. No actual TPM register reading ever returns ~0,
92 * so this value is a safe error indication to be mixed with possible status
93 * register values.
94 */
95#define TPM_TIMEOUT_ERR (~0)
96
97/* Error value returned on various TPM driver errors */
98#define TPM_DRIVER_ERR (~0)
99
100 /* 1 second is plenty for anything TPM does.*/
101#define MAX_DELAY_US (1000 * 1000)
102
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700103/*
104 * Structures defined below allow creating descriptions of TPM vendor/device
105 * ID information for run time discovery. The only device the system knows
106 * about at this time is Infineon slb9635
107 */
108struct device_name {
109 u16 dev_id;
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200110 const char *const dev_name;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700111};
112
113struct vendor_name {
114 u16 vendor_id;
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200115 const char *vendor_name;
116 const struct device_name *dev_names;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700117};
118
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700119static const struct device_name atmel_devices[] = {
120 {0x3204, "AT97SC3204"},
121 {0xffff}
122};
123
Stefan Reinauerc668af72011-10-27 21:28:25 +0000124static const struct device_name infineon_devices[] = {
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700125 {0x000b, "SLB9635 TT 1.2"},
Julius Wernercd49cce2019-03-05 16:53:33 -0800126#if CONFIG(TPM2)
Kamil Wcislobf5ccfd2017-10-12 13:12:11 +0200127 {0x001a, "SLB9665 TT 2.0"},
Subrata Banik5b8c4a72016-11-11 09:28:45 +0530128 {0x001b, "SLB9670 TT 2.0"},
129#else
Kamil Wcislobf5ccfd2017-10-12 13:12:11 +0200130 {0x001a, "SLB9660 TT 1.2"},
Wenkai Du641529b2015-05-29 10:54:27 -0700131 {0x001b, "SLB9670 TT 1.2"},
Subrata Banik5b8c4a72016-11-11 09:28:45 +0530132#endif
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700133 {0xffff}
134};
135
136static const struct device_name nuvoton_devices[] = {
137 {0x00fe, "NPCT420AA V2"},
138 {0xffff}
139};
140
141static const struct device_name stmicro_devices[] = {
142 {0x0000, "ST33ZP24" },
143 {0xffff}
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700144};
145
Tsung Ho Wu804a0432019-06-07 15:03:49 -0700146static const struct device_name swtpm_devices[] = {
147#if CONFIG(TPM2)
148 {0x0001, "SwTPM 2.0" },
149#endif
150 {0xffff}
151};
152
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700153static const struct vendor_name vendor_names[] = {
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700154 {0x1114, "Atmel", atmel_devices},
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700155 {0x15d1, "Infineon", infineon_devices},
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700156 {0x1050, "Nuvoton", nuvoton_devices},
Tsung Ho Wu804a0432019-06-07 15:03:49 -0700157 {0x1014, "TPM Emulator", swtpm_devices},
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700158 {0x104a, "ST Microelectronics", stmicro_devices},
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700159};
160
161/*
162 * Cached vendor/device ID pair to indicate that the device has been already
163 * discovered
164 */
Stefan Reinauerc668af72011-10-27 21:28:25 +0000165static u32 vendor_dev_id CAR_GLOBAL;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700166
Aaron Durbinc4220022013-07-24 16:02:14 -0500167static inline u8 tpm_read_status(int locality)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700168{
Julius Werner2f37bd62015-02-19 14:51:15 -0800169 u8 value = read8(TIS_REG(locality, TIS_REG_STS));
Aaron Durbinc4220022013-07-24 16:02:14 -0500170 TPM_DEBUG_IO_READ(TIS_REG_STS, value);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700171 return value;
172}
173
Aaron Durbinc4220022013-07-24 16:02:14 -0500174static inline void tpm_write_status(u8 sts, int locality)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700175{
Aaron Durbinc4220022013-07-24 16:02:14 -0500176 TPM_DEBUG_IO_WRITE(TIS_REG_STS, sts);
Julius Werner2f37bd62015-02-19 14:51:15 -0800177 write8(TIS_REG(locality, TIS_REG_STS), sts);
Aaron Durbinc4220022013-07-24 16:02:14 -0500178}
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700179
Aaron Durbinc4220022013-07-24 16:02:14 -0500180static inline u8 tpm_read_data(int locality)
181{
Julius Werner2f37bd62015-02-19 14:51:15 -0800182 u8 value = read8(TIS_REG(locality, TIS_REG_DATA_FIFO));
Aaron Durbinc4220022013-07-24 16:02:14 -0500183 TPM_DEBUG_IO_READ(TIS_REG_DATA_FIFO, value);
184 return value;
185}
186
187static inline void tpm_write_data(u8 data, int locality)
188{
189 TPM_DEBUG_IO_WRITE(TIS_REG_STS, data);
Julius Werner2f37bd62015-02-19 14:51:15 -0800190 write8(TIS_REG(locality, TIS_REG_DATA_FIFO), data);
Aaron Durbinc4220022013-07-24 16:02:14 -0500191}
192
193static inline u16 tpm_read_burst_count(int locality)
194{
195 u16 count;
Julius Werner2f37bd62015-02-19 14:51:15 -0800196 count = read8(TIS_REG(locality, TIS_REG_BURST_COUNT));
197 count |= read8(TIS_REG(locality, TIS_REG_BURST_COUNT + 1)) << 8;
Aaron Durbinc4220022013-07-24 16:02:14 -0500198 TPM_DEBUG_IO_READ(TIS_REG_BURST_COUNT, count);
199 return count;
200}
201
202static inline u8 tpm_read_access(int locality)
203{
Julius Werner2f37bd62015-02-19 14:51:15 -0800204 u8 value = read8(TIS_REG(locality, TIS_REG_ACCESS));
Aaron Durbinc4220022013-07-24 16:02:14 -0500205 TPM_DEBUG_IO_READ(TIS_REG_ACCESS, value);
206 return value;
207}
208
209static inline void tpm_write_access(u8 data, int locality)
210{
211 TPM_DEBUG_IO_WRITE(TIS_REG_ACCESS, data);
Julius Werner2f37bd62015-02-19 14:51:15 -0800212 write8(TIS_REG(locality, TIS_REG_ACCESS), data);
Aaron Durbinc4220022013-07-24 16:02:14 -0500213}
214
215static inline u32 tpm_read_did_vid(int locality)
216{
Julius Werner2f37bd62015-02-19 14:51:15 -0800217 u32 value = read32(TIS_REG(locality, TIS_REG_DID_VID));
Aaron Durbinc4220022013-07-24 16:02:14 -0500218 TPM_DEBUG_IO_READ(TIS_REG_DID_VID, value);
219 return value;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700220}
221
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700222static inline void tpm_write_int_vector(int vector, int locality)
223{
224 TPM_DEBUG_IO_WRITE(TIS_REG_INT_VECTOR, vector);
Julius Werner2f37bd62015-02-19 14:51:15 -0800225 write8(TIS_REG(locality, TIS_REG_INT_VECTOR), vector & 0xf);
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700226}
227
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530228static inline u8 tpm_read_int_vector(int locality)
229{
230 u8 value = read8(TIS_REG(locality, TIS_REG_INT_VECTOR));
231 TPM_DEBUG_IO_READ(TIS_REG_INT_VECTOR, value);
232 return value;
233}
234
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700235static inline void tpm_write_int_polarity(int polarity, int locality)
236{
237 /* Set polarity and leave all other bits at 0 */
238 u32 value = (polarity & 0x3) << 3;
239 TPM_DEBUG_IO_WRITE(TIS_REG_INT_ENABLE, value);
Julius Werner2f37bd62015-02-19 14:51:15 -0800240 write32(TIS_REG(locality, TIS_REG_INT_ENABLE), value);
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700241}
242
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530243static inline u32 tpm_read_int_polarity(int locality)
244{
245 /* Get polarity and leave all other bits */
246 u32 value = read8(TIS_REG(locality, TIS_REG_INT_ENABLE));
247 value = (value >> 3) & 0x3;
248 TPM_DEBUG_IO_READ(TIS_REG_INT_ENABLE, value);
249 return value;
250}
251
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700252/*
Aaron Durbinc4220022013-07-24 16:02:14 -0500253 * tis_wait_sts()
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700254 *
Aaron Durbinc4220022013-07-24 16:02:14 -0500255 * Wait for at least a second for a status to change its state to match the
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700256 * expected state. Normally the transition happens within microseconds.
257 *
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700258 * @locality - locality
259 * @mask - bitmask for the bitfield(s) to watch
260 * @expected - value the field(s) are supposed to be set to
261 *
Aaron Durbinc4220022013-07-24 16:02:14 -0500262 * Returns 0 on success or TPM_TIMEOUT_ERR on timeout.
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700263 */
Aaron Durbinc4220022013-07-24 16:02:14 -0500264static int tis_wait_sts(int locality, u8 mask, u8 expected)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700265{
266 u32 time_us = MAX_DELAY_US;
267 while (time_us > 0) {
Aaron Durbinc4220022013-07-24 16:02:14 -0500268 u8 value = tpm_read_status(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700269 if ((value & mask) == expected)
Aaron Durbinc4220022013-07-24 16:02:14 -0500270 return 0;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700271 udelay(1); /* 1 us */
272 time_us--;
273 }
274 return TPM_TIMEOUT_ERR;
275}
276
Aaron Durbinc4220022013-07-24 16:02:14 -0500277static inline int tis_wait_ready(int locality)
278{
279 return tis_wait_sts(locality, TIS_STS_COMMAND_READY,
280 TIS_STS_COMMAND_READY);
281}
282
283static inline int tis_wait_valid(int locality)
284{
285 return tis_wait_sts(locality, TIS_STS_VALID, TIS_STS_VALID);
286}
287
288static inline int tis_wait_valid_data(int locality)
289{
290 const u8 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID;
291 return tis_wait_sts(locality, has_data, has_data);
292}
293
294static inline int tis_has_valid_data(int locality)
295{
296 const u8 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID;
297 return (tpm_read_status(locality) & has_data) == has_data;
298}
299
300static inline int tis_expect_data(int locality)
301{
302 return !!(tpm_read_status(locality) & TIS_STS_EXPECT);
303}
304
305/*
306 * tis_wait_access()
307 *
308 * Wait for at least a second for a access to change its state to match the
309 * expected state. Normally the transition happens within microseconds.
310 *
311 * @locality - locality
312 * @mask - bitmask for the bitfield(s) to watch
313 * @expected - value the field(s) are supposed to be set to
314 *
315 * Returns 0 on success or TPM_TIMEOUT_ERR on timeout.
316 */
317static int tis_wait_access(int locality, u8 mask, u8 expected)
318{
319 u32 time_us = MAX_DELAY_US;
320 while (time_us > 0) {
321 u8 value = tpm_read_access(locality);
322 if ((value & mask) == expected)
323 return 0;
324 udelay(1); /* 1 us */
325 time_us--;
326 }
327 return TPM_TIMEOUT_ERR;
328}
329
330static inline int tis_wait_dropped_access(int locality)
331{
332 return tis_wait_access(locality, TIS_ACCESS_ACTIVE_LOCALITY, 0);
333}
334
335static inline int tis_wait_received_access(int locality)
336{
337 return tis_wait_access(locality, TIS_ACCESS_ACTIVE_LOCALITY,
338 TIS_ACCESS_ACTIVE_LOCALITY);
339}
340
341static inline int tis_has_access(int locality)
342{
343 return !!(tpm_read_access(locality) & TIS_ACCESS_ACTIVE_LOCALITY);
344}
345
346static inline void tis_request_access(int locality)
347{
348 tpm_write_access(TIS_ACCESS_REQUEST_USE, locality);
349}
350
351static inline void tis_drop_access(int locality)
352{
353 tpm_write_access(TIS_ACCESS_ACTIVE_LOCALITY, locality);
354}
355
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700356/*
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700357 * PC Client Specific TPM Interface Specification section 11.2.12:
358 *
359 * Software must be prepared to send two writes of a "1" to command ready
360 * field: the first to indicate successful read of all the data, thus
361 * clearing the data from the ReadFIFO and freeing the TPM's resources,
362 * and the second to indicate to the TPM it is about to send a new command.
363 *
364 * In practice not all TPMs behave the same so it is necessary to be
365 * flexible when trying to set command ready.
366 *
367 * Returns 0 on success if the TPM is ready for transactions.
368 * Returns TPM_TIMEOUT_ERR if the command ready bit does not get set.
369 */
370static int tis_command_ready(u8 locality)
371{
372 u32 status;
373
374 /* 1st attempt to set command ready */
Aaron Durbinc4220022013-07-24 16:02:14 -0500375 tpm_write_status(TIS_STS_COMMAND_READY, locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700376
377 /* Wait for response */
Aaron Durbinc4220022013-07-24 16:02:14 -0500378 status = tpm_read_status(locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700379
380 /* Check if command ready is set yet */
381 if (status & TIS_STS_COMMAND_READY)
382 return 0;
383
384 /* 2nd attempt to set command ready */
Aaron Durbinc4220022013-07-24 16:02:14 -0500385 tpm_write_status(TIS_STS_COMMAND_READY, locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700386
Aaron Durbinc4220022013-07-24 16:02:14 -0500387 return tis_wait_ready(locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700388}
389
390/*
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700391 * Probe the TPM device and try determining its manufacturer/device name.
392 *
393 * Returns 0 on success (the device is found or was found during an earlier
394 * invocation) or TPM_DRIVER_ERR if the device is not found.
395 */
396static u32 tis_probe(void)
397{
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700398 const char *device_name = "unknown";
399 const char *vendor_name = device_name;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700400 const struct device_name *dev;
401 u32 didvid;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700402 u16 vid, did;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700403 int i;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700404
Aaron Durbincb997d32013-05-10 00:40:56 -0500405 if (car_get_var(vendor_dev_id))
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700406 return 0; /* Already probed. */
407
Aaron Durbinc4220022013-07-24 16:02:14 -0500408 didvid = tpm_read_did_vid(0);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700409 if (!didvid || (didvid == 0xffffffff)) {
410 printf("%s: No TPM device found\n", __FUNCTION__);
411 return TPM_DRIVER_ERR;
412 }
413
Aaron Durbincb997d32013-05-10 00:40:56 -0500414 car_set_var(vendor_dev_id, didvid);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700415
416 vid = didvid & 0xffff;
417 did = (didvid >> 16) & 0xffff;
418 for (i = 0; i < ARRAY_SIZE(vendor_names); i++) {
419 int j = 0;
420 u16 known_did;
421 if (vid == vendor_names[i].vendor_id) {
422 vendor_name = vendor_names[i].vendor_name;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700423 } else {
424 continue;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700425 }
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700426 dev = &vendor_names[i].dev_names[j];
427 while ((known_did = dev->dev_id) != 0xffff) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700428 if (known_did == did) {
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700429 device_name = dev->dev_name;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700430 break;
431 }
432 j++;
Subrata41b08d92015-05-14 14:38:07 +0530433 dev = &vendor_names[i].dev_names[j];
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700434 }
435 break;
436 }
437 /* this will have to be converted into debug printout */
Duncan Laurie17ba9442015-09-03 16:00:49 -0700438 printk(BIOS_INFO, "Found TPM %s by %s\n", device_name, vendor_name);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700439 return 0;
440}
441
442/*
443 * tis_senddata()
444 *
445 * send the passed in data to the TPM device.
446 *
447 * @data - address of the data to send, byte by byte
448 * @len - length of the data to send
449 *
450 * Returns 0 on success, TPM_DRIVER_ERR on error (in case the device does
451 * not accept the entire command).
452 */
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200453static u32 tis_senddata(const u8 *const data, u32 len)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700454{
455 u32 offset = 0;
456 u16 burst = 0;
457 u32 max_cycles = 0;
458 u8 locality = 0;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700459
Aaron Durbinc4220022013-07-24 16:02:14 -0500460 if (tis_wait_ready(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700461 printf("%s:%d - failed to get 'command_ready' status\n",
462 __FILE__, __LINE__);
463 return TPM_DRIVER_ERR;
464 }
Aaron Durbinc4220022013-07-24 16:02:14 -0500465 burst = tpm_read_burst_count(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700466
467 while (1) {
Martin Roth38ddbfb2019-10-23 21:41:00 -0600468 unsigned int count;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700469
470 /* Wait till the device is ready to accept more data. */
471 while (!burst) {
472 if (max_cycles++ == MAX_DELAY_US) {
473 printf("%s:%d failed to feed %d bytes of %d\n",
474 __FILE__, __LINE__, len - offset, len);
475 return TPM_DRIVER_ERR;
476 }
477 udelay(1);
Aaron Durbinc4220022013-07-24 16:02:14 -0500478 burst = tpm_read_burst_count(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700479 }
480
481 max_cycles = 0;
482
483 /*
484 * Calculate number of bytes the TPM is ready to accept in one
485 * shot.
486 *
487 * We want to send the last byte outside of the loop (hence
488 * the -1 below) to make sure that the 'expected' status bit
489 * changes to zero exactly after the last byte is fed into the
490 * FIFO.
491 */
492 count = min(burst, len - offset - 1);
493 while (count--)
Aaron Durbinc4220022013-07-24 16:02:14 -0500494 tpm_write_data(data[offset++], locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700495
Aaron Durbinc4220022013-07-24 16:02:14 -0500496 if (tis_wait_valid(locality) || !tis_expect_data(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700497 printf("%s:%d TPM command feed overflow\n",
498 __FILE__, __LINE__);
499 return TPM_DRIVER_ERR;
500 }
501
Aaron Durbinc4220022013-07-24 16:02:14 -0500502 burst = tpm_read_burst_count(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700503 if ((offset == (len - 1)) && burst)
504 /*
505 * We need to be able to send the last byte to the
506 * device, so burst size must be nonzero before we
507 * break out.
508 */
509 break;
510 }
511
512 /* Send the last byte. */
Aaron Durbinc4220022013-07-24 16:02:14 -0500513 tpm_write_data(data[offset++], locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700514
515 /*
516 * Verify that TPM does not expect any more data as part of this
517 * command.
518 */
Aaron Durbinc4220022013-07-24 16:02:14 -0500519 if (tis_wait_valid(locality) || tis_expect_data(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700520 printf("%s:%d unexpected TPM status 0x%x\n",
Aaron Durbinc4220022013-07-24 16:02:14 -0500521 __FILE__, __LINE__, tpm_read_status(locality));
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700522 return TPM_DRIVER_ERR;
523 }
524
525 /* OK, sitting pretty, let's start the command execution. */
Aaron Durbinc4220022013-07-24 16:02:14 -0500526 tpm_write_status(TIS_STS_TPM_GO, locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700527
528 return 0;
529}
530
531/*
532 * tis_readresponse()
533 *
534 * read the TPM device response after a command was issued.
535 *
536 * @buffer - address where to read the response, byte by byte.
537 * @len - pointer to the size of buffer
538 *
539 * On success stores the number of received bytes to len and returns 0. On
540 * errors (misformatted TPM data or synchronization problems) returns
541 * TPM_DRIVER_ERR.
542 */
543static u32 tis_readresponse(u8 *buffer, size_t *len)
544{
545 u16 burst_count;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700546 u32 offset = 0;
547 u8 locality = 0;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700548 u32 expected_count = *len;
549 int max_cycles = 0;
550
551 /* Wait for the TPM to process the command */
Aaron Durbinc4220022013-07-24 16:02:14 -0500552 if (tis_wait_valid_data(locality)) {
553 printf("%s:%d failed processing command\n", __FILE__, __LINE__);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700554 return TPM_DRIVER_ERR;
555 }
556
557 do {
Aaron Durbinc4220022013-07-24 16:02:14 -0500558 while ((burst_count = tpm_read_burst_count(locality)) == 0) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700559 if (max_cycles++ == MAX_DELAY_US) {
560 printf("%s:%d TPM stuck on read\n",
561 __FILE__, __LINE__);
562 return TPM_DRIVER_ERR;
563 }
564 udelay(1);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700565 }
566
567 max_cycles = 0;
568
569 while (burst_count-- && (offset < expected_count)) {
Aaron Durbinc4220022013-07-24 16:02:14 -0500570 buffer[offset++] = tpm_read_data(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700571 if (offset == 6) {
572 /*
573 * We got the first six bytes of the reply,
574 * let's figure out how many bytes to expect
575 * total - it is stored as a 4 byte number in
576 * network order, starting with offset 2 into
577 * the body of the reply.
578 */
579 u32 real_length;
580 memcpy(&real_length,
581 buffer + 2,
582 sizeof(real_length));
583 expected_count = be32_to_cpu(real_length);
584
585 if ((expected_count < offset) ||
586 (expected_count > *len)) {
587 printf("%s:%d bad response size %d\n",
588 __FILE__, __LINE__,
589 expected_count);
590 return TPM_DRIVER_ERR;
591 }
592 }
593 }
594
595 /* Wait for the next portion */
Aaron Durbinc4220022013-07-24 16:02:14 -0500596 if (tis_wait_valid(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700597 printf("%s:%d failed to read response\n",
598 __FILE__, __LINE__);
599 return TPM_DRIVER_ERR;
600 }
601
602 if (offset == expected_count)
603 break; /* We got all we need */
604
Bill XIEa4bf0b72018-03-22 17:07:43 +0800605 /*
606 * Certain TPMs seem to need some delay between tis_wait_valid()
607 * and tis_has_valid_data(), or some race-condition-related
608 * issue will occur.
609 */
Julius Wernercd49cce2019-03-05 16:53:33 -0800610 if (CONFIG(TPM_RDRESP_NEED_DELAY))
Bill XIEa4bf0b72018-03-22 17:07:43 +0800611 udelay(10);
612
Aaron Durbinc4220022013-07-24 16:02:14 -0500613 } while (tis_has_valid_data(locality));
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700614
Aaron Durbinc4220022013-07-24 16:02:14 -0500615 /* * Make sure we indeed read all there was. */
616 if (tis_has_valid_data(locality)) {
617 printf("%s:%d wrong receive status: %x %d bytes left\n",
618 __FILE__, __LINE__, tpm_read_status(locality),
619 tpm_read_burst_count(locality));
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700620 return TPM_DRIVER_ERR;
621 }
622
623 /* Tell the TPM that we are done. */
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700624 if (tis_command_ready(locality) == TPM_TIMEOUT_ERR)
625 return TPM_DRIVER_ERR;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700626
627 *len = offset;
628 return 0;
629}
630
631/*
632 * tis_init()
633 *
634 * Initialize the TPM device. Returns 0 on success or TPM_DRIVER_ERR on
635 * failure (in case device probing did not succeed).
636 */
637int tis_init(void)
638{
639 if (tis_probe())
640 return TPM_DRIVER_ERR;
641 return 0;
642}
643
644/*
645 * tis_open()
646 *
647 * Requests access to locality 0 for the caller. After all commands have been
648 * completed the caller is supposed to call tis_close().
649 *
650 * Returns 0 on success, TPM_DRIVER_ERR on failure.
651 */
652int tis_open(void)
653{
654 u8 locality = 0; /* we use locality zero for everything */
655
656 if (tis_close())
657 return TPM_DRIVER_ERR;
658
659 /* now request access to locality */
Aaron Durbinc4220022013-07-24 16:02:14 -0500660 tis_request_access(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700661
662 /* did we get a lock? */
Aaron Durbinc4220022013-07-24 16:02:14 -0500663 if (tis_wait_received_access(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700664 printf("%s:%d - failed to lock locality %d\n",
665 __FILE__, __LINE__, locality);
666 return TPM_DRIVER_ERR;
667 }
668
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700669 /* Certain TPMs seem to need some delay here or they hang... */
670 udelay(10);
671
672 if (tis_command_ready(locality) == TPM_TIMEOUT_ERR)
673 return TPM_DRIVER_ERR;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700674
675 return 0;
676}
677
678/*
679 * tis_close()
680 *
Martin Roth56889792013-07-09 21:39:46 -0600681 * terminate the current session with the TPM by releasing the locked
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700682 * locality. Returns 0 on success of TPM_DRIVER_ERR on failure (in case lock
683 * removal did not succeed).
684 */
685int tis_close(void)
686{
687 u8 locality = 0;
Aaron Durbinc4220022013-07-24 16:02:14 -0500688 if (tis_has_access(locality)) {
689 tis_drop_access(locality);
690 if (tis_wait_dropped_access(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700691 printf("%s:%d - failed to release locality %d\n",
692 __FILE__, __LINE__, locality);
693 return TPM_DRIVER_ERR;
694 }
695 }
696 return 0;
697}
698
699/*
700 * tis_sendrecv()
701 *
702 * Send the requested data to the TPM and then try to get its response
703 *
704 * @sendbuf - buffer of the data to send
705 * @send_size size of the data to send
706 * @recvbuf - memory to save the response to
707 * @recv_len - pointer to the size of the response buffer
708 *
709 * Returns 0 on success (and places the number of response bytes at recv_len)
710 * or TPM_DRIVER_ERR on failure.
711 */
712int tis_sendrecv(const uint8_t *sendbuf, size_t send_size,
713 uint8_t *recvbuf, size_t *recv_len)
714{
715 if (tis_senddata(sendbuf, send_size)) {
716 printf("%s:%d failed sending data to TPM\n",
717 __FILE__, __LINE__);
718 return TPM_DRIVER_ERR;
719 }
720
721 return tis_readresponse(recvbuf, recv_len);
722}
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700723
724#ifdef __RAMSTAGE__
725
726/*
727 * tis_setup_interrupt()
728 *
729 * Set up the interrupt vector and polarity for locality 0 and
730 * disable all interrupts so they are unused in firmware but can
731 * be enabled by the OS.
732 *
733 * The values used here must match what is passed in the TPM ACPI
734 * device if ACPI is used on the platform.
735 *
736 * @vector - TPM interrupt vector
737 * @polarity - TPM interrupt polarity
738 *
739 * Returns 0 on success, TPM_DRIVER_ERR on failure.
740 */
741static int tis_setup_interrupt(int vector, int polarity)
742{
743 u8 locality = 0;
744 int has_access = tis_has_access(locality);
745
746 /* Open connection and request access if not already granted */
747 if (!has_access && tis_open() < 0)
748 return TPM_DRIVER_ERR;
749
750 /* Set TPM interrupt vector */
751 tpm_write_int_vector(vector, locality);
752
Elyes HAOUAS18958382018-08-07 12:23:16 +0200753 /* Set TPM interrupt polarity and disable interrupts */
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700754 tpm_write_int_polarity(polarity, locality);
755
756 /* Close connection if it was opened */
757 if (!has_access && tis_close() < 0)
758 return TPM_DRIVER_ERR;
759
760 return 0;
761}
762
763static void lpc_tpm_read_resources(struct device *dev)
764{
765 /* Static 5K memory region specified in Kconfig */
766 mmio_resource(dev, 0, CONFIG_TPM_TIS_BASE_ADDRESS >> 10, 0x5000 >> 10);
767}
768
769static void lpc_tpm_set_resources(struct device *dev)
770{
771 tpm_config_t *config = (tpm_config_t *)dev->chip_info;
772 struct resource *res;
773
774 for (res = dev->resource_list; res; res = res->next) {
775 if (!(res->flags & IORESOURCE_ASSIGNED))
776 continue;
777
778 if (res->flags & IORESOURCE_IRQ) {
779 /* Set interrupt vector */
780 tis_setup_interrupt((int)res->base,
781 config->irq_polarity);
782 } else {
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700783 continue;
784 }
785
786 res->flags |= IORESOURCE_STORED;
787 report_resource_stored(dev, res, " <tpm>");
788 }
789}
790
Julius Wernercd49cce2019-03-05 16:53:33 -0800791#if CONFIG(HAVE_ACPI_TABLES)
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530792
793static void tpm_ppi_func0_cb(void *arg)
794{
795 /* Functions 1-8. */
796 u8 buf[] = {0xff, 0x01};
797 acpigen_write_return_byte_buffer(buf, 2);
798}
799
800static void tpm_ppi_func1_cb(void *arg)
801{
Julius Wernercd49cce2019-03-05 16:53:33 -0800802 if (CONFIG(TPM2))
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530803 /* Interface version: 2.0 */
804 acpigen_write_return_string("2.0");
805 else
806 /* Interface version: 1.2 */
807 acpigen_write_return_string("1.2");
808}
809
810static void tpm_ppi_func2_cb(void *arg)
811{
812 /* Submit operations: drop on the floor and return success. */
813 acpigen_write_return_byte(0);
814}
815
816static void tpm_ppi_func3_cb(void *arg)
817{
818 /* Pending operation: none. */
819 acpigen_emit_byte(RETURN_OP);
820 acpigen_write_package(2);
821 acpigen_write_byte(0);
822 acpigen_write_byte(0);
823 acpigen_pop_len();
824}
825static void tpm_ppi_func4_cb(void *arg)
826{
827 /* Pre-OS transition method: reboot. */
828 acpigen_write_return_byte(2);
829}
830static void tpm_ppi_func5_cb(void *arg)
831{
832 /* Operation response: no operation executed. */
833 acpigen_emit_byte(RETURN_OP);
834 acpigen_write_package(3);
835 acpigen_write_byte(0);
836 acpigen_write_byte(0);
837 acpigen_write_byte(0);
838 acpigen_pop_len();
839}
840static void tpm_ppi_func6_cb(void *arg)
841{
842 /*
843 * Set preferred user language: deprecated and must return 3 aka
844 * "not implemented".
845 */
846 acpigen_write_return_byte(3);
847}
848static void tpm_ppi_func7_cb(void *arg)
849{
850 /* Submit operations: deny. */
851 acpigen_write_return_byte(3);
852}
853static void tpm_ppi_func8_cb(void *arg)
854{
855 /* All actions are forbidden. */
856 acpigen_write_return_byte(1);
857}
858static void (*tpm_ppi_callbacks[])(void *) = {
859 tpm_ppi_func0_cb,
860 tpm_ppi_func1_cb,
861 tpm_ppi_func2_cb,
862 tpm_ppi_func3_cb,
863 tpm_ppi_func4_cb,
864 tpm_ppi_func5_cb,
865 tpm_ppi_func6_cb,
866 tpm_ppi_func7_cb,
867 tpm_ppi_func8_cb,
868};
869
870static void tpm_mci_func0_cb(void *arg)
871{
872 /* Function 1. */
873 acpigen_write_return_singleton_buffer(0x3);
874}
875static void tpm_mci_func1_cb(void *arg)
876{
877 /* Just return success. */
878 acpigen_write_return_byte(0);
879}
880
881static void (*tpm_mci_callbacks[])(void *) = {
882 tpm_mci_func0_cb,
883 tpm_mci_func1_cb,
884};
885
886static void lpc_tpm_fill_ssdt(struct device *dev)
887{
888 const char *path = acpi_device_path(dev->bus->dev);
889 u32 arg;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530890
Philipp Deppenwiese3a1fbea2016-12-14 01:06:55 +0100891 if (!path) {
Tobias Diedrich36537f12017-02-10 00:28:45 +0100892 path = "\\_SB_.PCI0.LPCB";
Philipp Deppenwiese3a1fbea2016-12-14 01:06:55 +0100893 printk(BIOS_DEBUG, "Using default TPM ACPI path: '%s'\n", path);
894 }
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530895
896 /* Device */
897 acpigen_write_scope(path);
898 acpigen_write_device(acpi_device_name(dev));
899
900 acpigen_write_name("_HID");
901 acpigen_emit_eisaid("PNP0C31");
902
903 acpigen_write_name("_CID");
904 acpigen_emit_eisaid("PNP0C31");
905
906 acpigen_write_name_integer("_UID", 1);
907
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530908 u32 did_vid = tpm_read_did_vid(0);
909 if (did_vid > 0 && did_vid < 0xffffffff)
910 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
911 else
912 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_OFF);
913
Kevin Cody-Littlec97b5af2018-05-09 14:14:59 -0400914 u16 port = dev->path.pnp.port;
915
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530916 /* Resources */
917 acpigen_write_name("_CRS");
918 acpigen_write_resourcetemplate_header();
919 acpigen_write_mem32fixed(1, CONFIG_TPM_TIS_BASE_ADDRESS, 0x5000);
Frans Hendriks6cc937e2018-10-29 14:30:58 +0100920 if (port)
921 acpigen_write_io16(port, port, 1, 2, 1);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530922
923 if (CONFIG_TPM_PIRQ) {
924 /*
925 * PIRQ: Update interrupt vector with configured PIRQ
926 * Active-Low Level-Triggered Shared
927 */
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800928 struct acpi_irq tpm_irq_a = ACPI_IRQ_LEVEL_LOW(CONFIG_TPM_PIRQ);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530929 acpi_device_write_interrupt(&tpm_irq_a);
930 } else if (tpm_read_int_vector(0) > 0) {
931 u8 int_vec = tpm_read_int_vector(0);
932 u8 int_pol = tpm_read_int_polarity(0);
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800933 struct acpi_irq tpm_irq = ACPI_IRQ_LEVEL_LOW(int_vec);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530934
935 if (int_pol & 1)
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800936 tpm_irq.polarity = ACPI_IRQ_ACTIVE_LOW;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530937 else
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800938 tpm_irq.polarity = ACPI_IRQ_ACTIVE_HIGH;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530939
940 if (int_pol & 2)
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800941 tpm_irq.mode = ACPI_IRQ_EDGE_TRIGGERED;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530942 else
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800943 tpm_irq.mode = ACPI_IRQ_LEVEL_TRIGGERED;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530944
945 acpi_device_write_interrupt(&tpm_irq);
946 }
947
948 acpigen_write_resourcetemplate_footer();
949
Julius Wernercd49cce2019-03-05 16:53:33 -0800950 if (!CONFIG(CHROMEOS)) {
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530951 /*
952 * _DSM method
953 */
954 struct dsm_uuid ids[] = {
955 /* Physical presence interface.
956 * This is used to submit commands like "Clear TPM" to
957 * be run at next reboot provided that user confirms
958 * them. Spec allows user to cancel all commands and/or
959 * configure BIOS to reject commands. So we pretend that
960 * user did just this: cancelled everything. If user
961 * really wants to clear TPM the only option now is to
962 * do it manually in payload.
963 */
964 DSM_UUID(TPM_PPI_UUID, &tpm_ppi_callbacks[0],
965 ARRAY_SIZE(tpm_ppi_callbacks), (void *) &arg),
966 /* Memory clearing on boot: just a dummy. */
967 DSM_UUID(TPM_MCI_UUID, &tpm_mci_callbacks[0],
968 ARRAY_SIZE(tpm_mci_callbacks), (void *) &arg),
969 };
970
971 acpigen_write_dsm_uuid_arr(ids, ARRAY_SIZE(ids));
972 }
973 acpigen_pop_len(); /* Device */
974 acpigen_pop_len(); /* Scope */
975
976 printk(BIOS_INFO, "%s.%s: %s %s\n", path, acpi_device_name(dev),
977 dev->chip_ops->name, dev_path(dev));
978}
979
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600980static const char *lpc_tpm_acpi_name(const struct device *dev)
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530981{
982 return "TPM";
983}
984#endif
985
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700986static struct device_operations lpc_tpm_ops = {
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +0100987 .read_resources = lpc_tpm_read_resources,
988 .set_resources = lpc_tpm_set_resources,
Julius Wernercd49cce2019-03-05 16:53:33 -0800989#if CONFIG(HAVE_ACPI_TABLES)
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +0100990 .acpi_name = lpc_tpm_acpi_name,
991 .acpi_fill_ssdt_generator = lpc_tpm_fill_ssdt,
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530992#endif
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700993};
994
995static struct pnp_info pnp_dev_info[] = {
996 { .flags = PNP_IRQ0 }
997};
998
999static void enable_dev(struct device *dev)
1000{
1001 pnp_enable_devices(dev, &lpc_tpm_ops,
1002 ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
1003}
1004
1005struct chip_operations drivers_pc80_tpm_ops = {
1006 CHIP_NAME("LPC TPM")
1007 .enable_dev = enable_dev
1008};
1009
1010#endif /* __RAMSTAGE__ */