blob: ce88ae012d7fc86910579230b4841bb8f4b2f785 [file] [log] [blame]
Angel Pons8a3453f2020-04-02 23:48:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer3008bbad2011-10-11 14:46:25 -07002
3/*
4 * The code in this file has been heavily based on the article "Writing a TPM
5 * Device Driver" published on http://ptgmedia.pearsoncmg.com and the
6 * submission by Stefan Berger on Qemu-devel mailing list.
7 *
8 * One principal difference is that in the simplest config the other than 0
9 * TPM localities do not get mapped by some devices (for instance, by
10 * Infineon slb9635), so this driver provides access to locality 0 only.
11 */
12
Elyes HAOUAS361a9352019-12-18 21:26:33 +010013#include <commonlib/helpers.h>
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070014#include <string.h>
15#include <delay.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020016#include <device/mmio.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070017#include <acpi/acpi.h>
18#include <acpi/acpigen.h>
19#include <acpi/acpi_device.h>
Naresh G Solanki80ff0382016-11-15 11:01:33 +053020#include <device/device.h>
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070021#include <console/console.h>
Philipp Deppenwiesed88fb362017-10-18 20:26:18 +020022#include <security/tpm/tis.h>
Sergii Dmytruk0a89d522022-10-29 16:57:07 +030023#include <security/tpm/tss.h>
Duncan Lauriedd281ed2014-10-30 15:20:19 -070024#include <device/pnp.h>
Patrick Rudolphd8d8be12020-09-21 09:48:53 +020025#include <drivers/tpm/tpm_ppi.h>
Werner Zeh92ab6112021-10-11 15:27:12 +020026#include <timer.h>
Duncan Lauriedd281ed2014-10-30 15:20:19 -070027#include "chip.h"
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070028
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070029#define PREFIX "lpc_tpm: "
Patrick Rudolphd8d8be12020-09-21 09:48:53 +020030
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070031/* coreboot wrapper for TPM driver (start) */
32#define TPM_DEBUG(fmt, args...) \
Julius Wernercd49cce2019-03-05 16:53:33 -080033 if (CONFIG(DEBUG_TPM)) { \
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070034 printk(BIOS_DEBUG, PREFIX); \
Elyes HAOUASa342f392018-10-17 10:56:26 +020035 printk(BIOS_DEBUG, fmt, ##args); \
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070036 }
Aaron Durbinc4220022013-07-24 16:02:14 -050037#define TPM_DEBUG_IO_READ(reg_, val_) \
38 TPM_DEBUG("Read reg 0x%x returns 0x%x\n", (reg_), (val_))
39#define TPM_DEBUG_IO_WRITE(reg_, val_) \
40 TPM_DEBUG("Write reg 0x%x with 0x%x\n", (reg_), (val_))
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070041#define printf(x...) printk(BIOS_ERR, x)
42
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070043/* coreboot wrapper for TPM driver (end) */
44
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070045/* the macro accepts the locality value, but only locality 0 is operational */
46#define TIS_REG(LOCALITY, REG) \
Patrick Rudolph56fdafb2020-07-01 20:07:08 +020047 (void *)(uintptr_t)(CONFIG_TPM_TIS_BASE_ADDRESS + (LOCALITY << 12) + REG)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070048
49/* hardware registers' offsets */
50#define TIS_REG_ACCESS 0x0
51#define TIS_REG_INT_ENABLE 0x8
52#define TIS_REG_INT_VECTOR 0xc
53#define TIS_REG_INT_STATUS 0x10
54#define TIS_REG_INTF_CAPABILITY 0x14
55#define TIS_REG_STS 0x18
Aaron Durbinc4220022013-07-24 16:02:14 -050056#define TIS_REG_BURST_COUNT 0x19
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070057#define TIS_REG_DATA_FIFO 0x24
58#define TIS_REG_DID_VID 0xf00
59#define TIS_REG_RID 0xf04
60
61/* Some registers' bit field definitions */
62#define TIS_STS_VALID (1 << 7) /* 0x80 */
63#define TIS_STS_COMMAND_READY (1 << 6) /* 0x40 */
64#define TIS_STS_TPM_GO (1 << 5) /* 0x20 */
65#define TIS_STS_DATA_AVAILABLE (1 << 4) /* 0x10 */
66#define TIS_STS_EXPECT (1 << 3) /* 0x08 */
67#define TIS_STS_RESPONSE_RETRY (1 << 1) /* 0x02 */
68
69#define TIS_ACCESS_TPM_REG_VALID_STS (1 << 7) /* 0x80 */
70#define TIS_ACCESS_ACTIVE_LOCALITY (1 << 5) /* 0x20 */
71#define TIS_ACCESS_BEEN_SEIZED (1 << 4) /* 0x10 */
72#define TIS_ACCESS_SEIZE (1 << 3) /* 0x08 */
73#define TIS_ACCESS_PENDING_REQUEST (1 << 2) /* 0x04 */
74#define TIS_ACCESS_REQUEST_USE (1 << 1) /* 0x02 */
75#define TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0) /* 0x01 */
76
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070077/*
78 * Error value returned if a tpm register does not enter the expected state
79 * after continuous polling. No actual TPM register reading ever returns ~0,
80 * so this value is a safe error indication to be mixed with possible status
81 * register values.
82 */
83#define TPM_TIMEOUT_ERR (~0)
84
85/* Error value returned on various TPM driver errors */
86#define TPM_DRIVER_ERR (~0)
87
88 /* 1 second is plenty for anything TPM does.*/
Werner Zeh92ab6112021-10-11 15:27:12 +020089#define MAX_DELAY_US USECS_PER_SEC
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070090
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070091/*
92 * Structures defined below allow creating descriptions of TPM vendor/device
Sergii Dmytruk025d20e2022-12-22 19:34:16 +020093 * ID information for run time discovery. The only device the system knows
94 * about at this time is Infineon slb9635
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070095 */
96struct device_name {
97 u16 dev_id;
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +020098 const char *const dev_name;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070099};
100
101struct vendor_name {
102 u16 vendor_id;
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200103 const char *vendor_name;
104 const struct device_name *dev_names;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700105};
106
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700107static const struct device_name atmel_devices[] = {
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200108 {0x3204, "AT97SC3204"},
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700109 {0xffff}
110};
111
Stefan Reinauerc668af72011-10-27 21:28:25 +0000112static const struct device_name infineon_devices[] = {
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200113 {0x000b, "SLB9635 TT 1.2"},
114#if CONFIG(TPM2)
115 {0x001a, "SLB9665 TT 2.0"},
116 {0x001b, "SLB9670 TT 2.0"},
117#else
118 {0x001a, "SLB9660 TT 1.2"},
119 {0x001b, "SLB9670 TT 1.2"},
120#endif
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700121 {0xffff}
122};
123
124static const struct device_name nuvoton_devices[] = {
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200125 {0x00fe, "NPCT420AA V2"},
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700126 {0xffff}
127};
128
129static const struct device_name stmicro_devices[] = {
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200130 {0x0000, "ST33ZP24" },
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700131 {0xffff}
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700132};
133
Tsung Ho Wu804a0432019-06-07 15:03:49 -0700134static const struct device_name swtpm_devices[] = {
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200135#if CONFIG(TPM2)
136 {0x0001, "SwTPM 2.0" },
137#endif
Tsung Ho Wu804a0432019-06-07 15:03:49 -0700138 {0xffff}
139};
140
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700141static const struct vendor_name vendor_names[] = {
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700142 {0x1114, "Atmel", atmel_devices},
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700143 {0x15d1, "Infineon", infineon_devices},
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700144 {0x1050, "Nuvoton", nuvoton_devices},
Tsung Ho Wu804a0432019-06-07 15:03:49 -0700145 {0x1014, "TPM Emulator", swtpm_devices},
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700146 {0x104a, "ST Microelectronics", stmicro_devices},
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700147};
148
149/*
150 * Cached vendor/device ID pair to indicate that the device has been already
151 * discovered
152 */
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100153static u32 vendor_dev_id;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700154
Aaron Durbinc4220022013-07-24 16:02:14 -0500155static inline u8 tpm_read_status(int locality)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700156{
Julius Werner2f37bd62015-02-19 14:51:15 -0800157 u8 value = read8(TIS_REG(locality, TIS_REG_STS));
Aaron Durbinc4220022013-07-24 16:02:14 -0500158 TPM_DEBUG_IO_READ(TIS_REG_STS, value);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700159 return value;
160}
161
Aaron Durbinc4220022013-07-24 16:02:14 -0500162static inline void tpm_write_status(u8 sts, int locality)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700163{
Aaron Durbinc4220022013-07-24 16:02:14 -0500164 TPM_DEBUG_IO_WRITE(TIS_REG_STS, sts);
Julius Werner2f37bd62015-02-19 14:51:15 -0800165 write8(TIS_REG(locality, TIS_REG_STS), sts);
Aaron Durbinc4220022013-07-24 16:02:14 -0500166}
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700167
Aaron Durbinc4220022013-07-24 16:02:14 -0500168static inline u8 tpm_read_data(int locality)
169{
Julius Werner2f37bd62015-02-19 14:51:15 -0800170 u8 value = read8(TIS_REG(locality, TIS_REG_DATA_FIFO));
Aaron Durbinc4220022013-07-24 16:02:14 -0500171 TPM_DEBUG_IO_READ(TIS_REG_DATA_FIFO, value);
172 return value;
173}
174
175static inline void tpm_write_data(u8 data, int locality)
176{
Werner Zeha31d6cd2021-10-07 07:15:38 +0200177 TPM_DEBUG_IO_WRITE(TIS_REG_DATA_FIFO, data);
Julius Werner2f37bd62015-02-19 14:51:15 -0800178 write8(TIS_REG(locality, TIS_REG_DATA_FIFO), data);
Aaron Durbinc4220022013-07-24 16:02:14 -0500179}
180
181static inline u16 tpm_read_burst_count(int locality)
182{
183 u16 count;
Julius Werner2f37bd62015-02-19 14:51:15 -0800184 count = read8(TIS_REG(locality, TIS_REG_BURST_COUNT));
185 count |= read8(TIS_REG(locality, TIS_REG_BURST_COUNT + 1)) << 8;
Aaron Durbinc4220022013-07-24 16:02:14 -0500186 TPM_DEBUG_IO_READ(TIS_REG_BURST_COUNT, count);
187 return count;
188}
189
190static inline u8 tpm_read_access(int locality)
191{
Julius Werner2f37bd62015-02-19 14:51:15 -0800192 u8 value = read8(TIS_REG(locality, TIS_REG_ACCESS));
Aaron Durbinc4220022013-07-24 16:02:14 -0500193 TPM_DEBUG_IO_READ(TIS_REG_ACCESS, value);
194 return value;
195}
196
197static inline void tpm_write_access(u8 data, int locality)
198{
199 TPM_DEBUG_IO_WRITE(TIS_REG_ACCESS, data);
Julius Werner2f37bd62015-02-19 14:51:15 -0800200 write8(TIS_REG(locality, TIS_REG_ACCESS), data);
Aaron Durbinc4220022013-07-24 16:02:14 -0500201}
202
203static inline u32 tpm_read_did_vid(int locality)
204{
Julius Werner2f37bd62015-02-19 14:51:15 -0800205 u32 value = read32(TIS_REG(locality, TIS_REG_DID_VID));
Aaron Durbinc4220022013-07-24 16:02:14 -0500206 TPM_DEBUG_IO_READ(TIS_REG_DID_VID, value);
207 return value;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700208}
209
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700210static inline void tpm_write_int_vector(int vector, int locality)
211{
212 TPM_DEBUG_IO_WRITE(TIS_REG_INT_VECTOR, vector);
Julius Werner2f37bd62015-02-19 14:51:15 -0800213 write8(TIS_REG(locality, TIS_REG_INT_VECTOR), vector & 0xf);
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700214}
215
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530216static inline u8 tpm_read_int_vector(int locality)
217{
218 u8 value = read8(TIS_REG(locality, TIS_REG_INT_VECTOR));
219 TPM_DEBUG_IO_READ(TIS_REG_INT_VECTOR, value);
220 return value;
221}
222
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700223static inline void tpm_write_int_polarity(int polarity, int locality)
224{
225 /* Set polarity and leave all other bits at 0 */
226 u32 value = (polarity & 0x3) << 3;
227 TPM_DEBUG_IO_WRITE(TIS_REG_INT_ENABLE, value);
Julius Werner2f37bd62015-02-19 14:51:15 -0800228 write32(TIS_REG(locality, TIS_REG_INT_ENABLE), value);
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700229}
230
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530231static inline u32 tpm_read_int_polarity(int locality)
232{
233 /* Get polarity and leave all other bits */
234 u32 value = read8(TIS_REG(locality, TIS_REG_INT_ENABLE));
235 value = (value >> 3) & 0x3;
236 TPM_DEBUG_IO_READ(TIS_REG_INT_ENABLE, value);
237 return value;
238}
239
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700240/*
Aaron Durbinc4220022013-07-24 16:02:14 -0500241 * tis_wait_sts()
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700242 *
Werner Zeh92ab6112021-10-11 15:27:12 +0200243 * Wait for at most a second for a status to change its state to match the
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700244 * expected state. Normally the transition happens within microseconds.
245 *
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700246 * @locality - locality
247 * @mask - bitmask for the bitfield(s) to watch
248 * @expected - value the field(s) are supposed to be set to
249 *
Aaron Durbinc4220022013-07-24 16:02:14 -0500250 * Returns 0 on success or TPM_TIMEOUT_ERR on timeout.
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700251 */
Aaron Durbinc4220022013-07-24 16:02:14 -0500252static int tis_wait_sts(int locality, u8 mask, u8 expected)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700253{
Werner Zeh92ab6112021-10-11 15:27:12 +0200254 struct stopwatch sw;
255
256 stopwatch_init_usecs_expire(&sw, MAX_DELAY_US);
257 do {
Aaron Durbinc4220022013-07-24 16:02:14 -0500258 u8 value = tpm_read_status(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700259 if ((value & mask) == expected)
Aaron Durbinc4220022013-07-24 16:02:14 -0500260 return 0;
Werner Zeh92ab6112021-10-11 15:27:12 +0200261 udelay(1);
262 } while (!stopwatch_expired(&sw));
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700263 return TPM_TIMEOUT_ERR;
264}
265
Aaron Durbinc4220022013-07-24 16:02:14 -0500266static inline int tis_wait_ready(int locality)
267{
268 return tis_wait_sts(locality, TIS_STS_COMMAND_READY,
269 TIS_STS_COMMAND_READY);
270}
271
272static inline int tis_wait_valid(int locality)
273{
274 return tis_wait_sts(locality, TIS_STS_VALID, TIS_STS_VALID);
275}
276
277static inline int tis_wait_valid_data(int locality)
278{
279 const u8 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID;
280 return tis_wait_sts(locality, has_data, has_data);
281}
282
283static inline int tis_has_valid_data(int locality)
284{
285 const u8 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID;
286 return (tpm_read_status(locality) & has_data) == has_data;
287}
288
289static inline int tis_expect_data(int locality)
290{
291 return !!(tpm_read_status(locality) & TIS_STS_EXPECT);
292}
293
294/*
295 * tis_wait_access()
296 *
Werner Zeh92ab6112021-10-11 15:27:12 +0200297 * Wait for at most a second for a access to change its state to match the
Aaron Durbinc4220022013-07-24 16:02:14 -0500298 * expected state. Normally the transition happens within microseconds.
299 *
300 * @locality - locality
301 * @mask - bitmask for the bitfield(s) to watch
302 * @expected - value the field(s) are supposed to be set to
303 *
304 * Returns 0 on success or TPM_TIMEOUT_ERR on timeout.
305 */
306static int tis_wait_access(int locality, u8 mask, u8 expected)
307{
Werner Zeh92ab6112021-10-11 15:27:12 +0200308 struct stopwatch sw;
309
310 stopwatch_init_usecs_expire(&sw, MAX_DELAY_US);
311 do {
Aaron Durbinc4220022013-07-24 16:02:14 -0500312 u8 value = tpm_read_access(locality);
313 if ((value & mask) == expected)
314 return 0;
Werner Zeh92ab6112021-10-11 15:27:12 +0200315 udelay(1);
316 } while (!stopwatch_expired(&sw));
Aaron Durbinc4220022013-07-24 16:02:14 -0500317 return TPM_TIMEOUT_ERR;
318}
319
Aaron Durbinc4220022013-07-24 16:02:14 -0500320static inline int tis_wait_received_access(int locality)
321{
322 return tis_wait_access(locality, TIS_ACCESS_ACTIVE_LOCALITY,
323 TIS_ACCESS_ACTIVE_LOCALITY);
324}
325
326static inline int tis_has_access(int locality)
327{
328 return !!(tpm_read_access(locality) & TIS_ACCESS_ACTIVE_LOCALITY);
329}
330
331static inline void tis_request_access(int locality)
332{
333 tpm_write_access(TIS_ACCESS_REQUEST_USE, locality);
334}
335
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700336/*
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700337 * PC Client Specific TPM Interface Specification section 11.2.12:
338 *
339 * Software must be prepared to send two writes of a "1" to command ready
340 * field: the first to indicate successful read of all the data, thus
341 * clearing the data from the ReadFIFO and freeing the TPM's resources,
342 * and the second to indicate to the TPM it is about to send a new command.
343 *
344 * In practice not all TPMs behave the same so it is necessary to be
345 * flexible when trying to set command ready.
346 *
347 * Returns 0 on success if the TPM is ready for transactions.
348 * Returns TPM_TIMEOUT_ERR if the command ready bit does not get set.
349 */
350static int tis_command_ready(u8 locality)
351{
352 u32 status;
353
354 /* 1st attempt to set command ready */
Aaron Durbinc4220022013-07-24 16:02:14 -0500355 tpm_write_status(TIS_STS_COMMAND_READY, locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700356
357 /* Wait for response */
Aaron Durbinc4220022013-07-24 16:02:14 -0500358 status = tpm_read_status(locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700359
360 /* Check if command ready is set yet */
361 if (status & TIS_STS_COMMAND_READY)
362 return 0;
363
364 /* 2nd attempt to set command ready */
Aaron Durbinc4220022013-07-24 16:02:14 -0500365 tpm_write_status(TIS_STS_COMMAND_READY, locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700366
Aaron Durbinc4220022013-07-24 16:02:14 -0500367 return tis_wait_ready(locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700368}
369
370/*
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700371 * Probe the TPM device and try determining its manufacturer/device name.
372 *
373 * Returns 0 on success (the device is found or was found during an earlier
374 * invocation) or TPM_DRIVER_ERR if the device is not found.
375 */
Sergii Dmytruk4ee03172022-12-22 19:35:25 +0200376static u32 tis_probe(void)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700377{
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200378 const char *device_name = "unknown";
379 const char *vendor_name = device_name;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700380 const struct device_name *dev;
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200381 u32 didvid;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700382 u16 vid, did;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700383 int i;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700384
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100385 if (vendor_dev_id)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700386 return 0; /* Already probed. */
387
Aaron Durbinc4220022013-07-24 16:02:14 -0500388 didvid = tpm_read_did_vid(0);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700389 if (!didvid || (didvid == 0xffffffff)) {
Angel Pons08e8cab2020-06-18 15:20:37 +0200390 printf("%s: No TPM device found\n", __func__);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700391 return TPM_DRIVER_ERR;
392 }
393
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100394 vendor_dev_id = didvid;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700395
396 vid = didvid & 0xffff;
397 did = (didvid >> 16) & 0xffff;
398 for (i = 0; i < ARRAY_SIZE(vendor_names); i++) {
399 int j = 0;
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200400 u16 known_did;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700401 if (vid == vendor_names[i].vendor_id) {
402 vendor_name = vendor_names[i].vendor_name;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700403 } else {
404 continue;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700405 }
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700406 dev = &vendor_names[i].dev_names[j];
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200407 while ((known_did = dev->dev_id) != 0xffff) {
408 if (known_did == did) {
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700409 device_name = dev->dev_name;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700410 break;
411 }
412 j++;
Subrata41b08d92015-05-14 14:38:07 +0530413 dev = &vendor_names[i].dev_names[j];
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700414 }
415 break;
416 }
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200417 /* this will have to be converted into debug printout */
418 printk(BIOS_INFO, "Found TPM %s by %s\n", device_name, vendor_name);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700419 return 0;
420}
421
422/*
423 * tis_senddata()
424 *
425 * send the passed in data to the TPM device.
426 *
427 * @data - address of the data to send, byte by byte
428 * @len - length of the data to send
429 *
430 * Returns 0 on success, TPM_DRIVER_ERR on error (in case the device does
431 * not accept the entire command).
432 */
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200433static u32 tis_senddata(const u8 *const data, u32 len)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700434{
435 u32 offset = 0;
436 u16 burst = 0;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700437 u8 locality = 0;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700438
Aaron Durbinc4220022013-07-24 16:02:14 -0500439 if (tis_wait_ready(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700440 printf("%s:%d - failed to get 'command_ready' status\n",
441 __FILE__, __LINE__);
442 return TPM_DRIVER_ERR;
443 }
Aaron Durbinc4220022013-07-24 16:02:14 -0500444 burst = tpm_read_burst_count(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700445
446 while (1) {
Martin Roth38ddbfb2019-10-23 21:41:00 -0600447 unsigned int count;
Werner Zeh92ab6112021-10-11 15:27:12 +0200448 struct stopwatch sw;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700449
450 /* Wait till the device is ready to accept more data. */
Werner Zeh92ab6112021-10-11 15:27:12 +0200451 stopwatch_init_usecs_expire(&sw, MAX_DELAY_US);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700452 while (!burst) {
Werner Zeh92ab6112021-10-11 15:27:12 +0200453 if (stopwatch_expired(&sw)) {
Werner Zeh66b2f202021-10-12 15:14:22 +0200454 printf("%s:%d failed to feed %u bytes of %u\n",
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700455 __FILE__, __LINE__, len - offset, len);
456 return TPM_DRIVER_ERR;
457 }
458 udelay(1);
Aaron Durbinc4220022013-07-24 16:02:14 -0500459 burst = tpm_read_burst_count(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700460 }
461
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700462 /*
463 * Calculate number of bytes the TPM is ready to accept in one
464 * shot.
465 *
466 * We want to send the last byte outside of the loop (hence
467 * the -1 below) to make sure that the 'expected' status bit
468 * changes to zero exactly after the last byte is fed into the
469 * FIFO.
470 */
Elyes HAOUAS361a9352019-12-18 21:26:33 +0100471 count = MIN(burst, len - offset - 1);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700472 while (count--)
Aaron Durbinc4220022013-07-24 16:02:14 -0500473 tpm_write_data(data[offset++], locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700474
Aaron Durbinc4220022013-07-24 16:02:14 -0500475 if (tis_wait_valid(locality) || !tis_expect_data(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700476 printf("%s:%d TPM command feed overflow\n",
477 __FILE__, __LINE__);
478 return TPM_DRIVER_ERR;
479 }
480
Aaron Durbinc4220022013-07-24 16:02:14 -0500481 burst = tpm_read_burst_count(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700482 if ((offset == (len - 1)) && burst)
483 /*
484 * We need to be able to send the last byte to the
485 * device, so burst size must be nonzero before we
486 * break out.
487 */
488 break;
489 }
490
491 /* Send the last byte. */
Aaron Durbinc4220022013-07-24 16:02:14 -0500492 tpm_write_data(data[offset++], locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700493
494 /*
495 * Verify that TPM does not expect any more data as part of this
496 * command.
497 */
Aaron Durbinc4220022013-07-24 16:02:14 -0500498 if (tis_wait_valid(locality) || tis_expect_data(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700499 printf("%s:%d unexpected TPM status 0x%x\n",
Aaron Durbinc4220022013-07-24 16:02:14 -0500500 __FILE__, __LINE__, tpm_read_status(locality));
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700501 return TPM_DRIVER_ERR;
502 }
503
504 /* OK, sitting pretty, let's start the command execution. */
Aaron Durbinc4220022013-07-24 16:02:14 -0500505 tpm_write_status(TIS_STS_TPM_GO, locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700506
507 return 0;
508}
509
510/*
511 * tis_readresponse()
512 *
513 * read the TPM device response after a command was issued.
514 *
515 * @buffer - address where to read the response, byte by byte.
516 * @len - pointer to the size of buffer
517 *
518 * On success stores the number of received bytes to len and returns 0. On
519 * errors (misformatted TPM data or synchronization problems) returns
520 * TPM_DRIVER_ERR.
521 */
522static u32 tis_readresponse(u8 *buffer, size_t *len)
523{
524 u16 burst_count;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700525 u32 offset = 0;
526 u8 locality = 0;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700527 u32 expected_count = *len;
528 int max_cycles = 0;
529
530 /* Wait for the TPM to process the command */
Aaron Durbinc4220022013-07-24 16:02:14 -0500531 if (tis_wait_valid_data(locality)) {
532 printf("%s:%d failed processing command\n", __FILE__, __LINE__);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700533 return TPM_DRIVER_ERR;
534 }
535
536 do {
Aaron Durbinc4220022013-07-24 16:02:14 -0500537 while ((burst_count = tpm_read_burst_count(locality)) == 0) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700538 if (max_cycles++ == MAX_DELAY_US) {
539 printf("%s:%d TPM stuck on read\n",
540 __FILE__, __LINE__);
541 return TPM_DRIVER_ERR;
542 }
543 udelay(1);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700544 }
545
546 max_cycles = 0;
547
548 while (burst_count-- && (offset < expected_count)) {
Aaron Durbinc4220022013-07-24 16:02:14 -0500549 buffer[offset++] = tpm_read_data(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700550 if (offset == 6) {
551 /*
552 * We got the first six bytes of the reply,
553 * let's figure out how many bytes to expect
554 * total - it is stored as a 4 byte number in
555 * network order, starting with offset 2 into
556 * the body of the reply.
557 */
558 u32 real_length;
559 memcpy(&real_length,
560 buffer + 2,
561 sizeof(real_length));
562 expected_count = be32_to_cpu(real_length);
563
564 if ((expected_count < offset) ||
565 (expected_count > *len)) {
Werner Zeh66b2f202021-10-12 15:14:22 +0200566 printf("%s:%d bad response size %u\n",
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700567 __FILE__, __LINE__,
568 expected_count);
569 return TPM_DRIVER_ERR;
570 }
571 }
572 }
573
574 /* Wait for the next portion */
Aaron Durbinc4220022013-07-24 16:02:14 -0500575 if (tis_wait_valid(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700576 printf("%s:%d failed to read response\n",
577 __FILE__, __LINE__);
578 return TPM_DRIVER_ERR;
579 }
580
581 if (offset == expected_count)
582 break; /* We got all we need */
583
Bill XIEa4bf0b72018-03-22 17:07:43 +0800584 /*
585 * Certain TPMs seem to need some delay between tis_wait_valid()
586 * and tis_has_valid_data(), or some race-condition-related
587 * issue will occur.
588 */
Julius Wernercd49cce2019-03-05 16:53:33 -0800589 if (CONFIG(TPM_RDRESP_NEED_DELAY))
Bill XIEa4bf0b72018-03-22 17:07:43 +0800590 udelay(10);
591
Aaron Durbinc4220022013-07-24 16:02:14 -0500592 } while (tis_has_valid_data(locality));
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700593
Aaron Durbinc4220022013-07-24 16:02:14 -0500594 /* * Make sure we indeed read all there was. */
595 if (tis_has_valid_data(locality)) {
Werner Zeh66b2f202021-10-12 15:14:22 +0200596 printf("%s:%d wrong receive status: %x %u bytes left\n",
Aaron Durbinc4220022013-07-24 16:02:14 -0500597 __FILE__, __LINE__, tpm_read_status(locality),
598 tpm_read_burst_count(locality));
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700599 return TPM_DRIVER_ERR;
600 }
601
602 /* Tell the TPM that we are done. */
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700603 if (tis_command_ready(locality) == TPM_TIMEOUT_ERR)
604 return TPM_DRIVER_ERR;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700605
606 *len = offset;
607 return 0;
608}
609
610/*
Sergii Dmytruk4ee03172022-12-22 19:35:25 +0200611 * tis_init()
612 *
613 * Initialize the TPM device. Returns 0 on success or TPM_DRIVER_ERR on
614 * failure (in case device probing did not succeed).
615 */
616int tis_init(void)
617{
618 if (tis_probe())
619 return TPM_DRIVER_ERR;
620 return 0;
621}
622
623/*
624 * tis_open()
625 *
Sergii Dmytruk0a89d522022-10-29 16:57:07 +0300626 * Requests access to locality 0 for the caller.
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700627 *
628 * Returns 0 on success, TPM_DRIVER_ERR on failure.
629 */
Sergii Dmytruk4ee03172022-12-22 19:35:25 +0200630int tis_open(void)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700631{
632 u8 locality = 0; /* we use locality zero for everything */
633
Sergii Dmytruk0a89d522022-10-29 16:57:07 +0300634 if (!tis_has_access(locality)) {
635 /* request access to locality */
636 tis_request_access(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700637
Sergii Dmytruk0a89d522022-10-29 16:57:07 +0300638 /* did we get a lock? */
639 if (tis_wait_received_access(locality)) {
640 printf("%s:%d - failed to lock locality %u\n",
641 __FILE__, __LINE__, locality);
642 return TPM_DRIVER_ERR;
643 }
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700644
Sergii Dmytruk0a89d522022-10-29 16:57:07 +0300645 /* Certain TPMs seem to need some delay here or they hang... */
646 udelay(10);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700647 }
648
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700649 if (tis_command_ready(locality) == TPM_TIMEOUT_ERR)
650 return TPM_DRIVER_ERR;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700651
652 return 0;
653}
654
655/*
Sergii Dmytruk4ee03172022-12-22 19:35:25 +0200656 * tis_sendrecv()
657 *
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700658 * Send the requested data to the TPM and then try to get its response
659 *
660 * @sendbuf - buffer of the data to send
661 * @send_size size of the data to send
662 * @recvbuf - memory to save the response to
663 * @recv_len - pointer to the size of the response buffer
664 *
665 * Returns 0 on success (and places the number of response bytes at recv_len)
666 * or TPM_DRIVER_ERR on failure.
667 */
Sergii Dmytruk4ee03172022-12-22 19:35:25 +0200668int tis_sendrecv(const uint8_t *sendbuf, size_t send_size,
669 uint8_t *recvbuf, size_t *recv_len)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700670{
671 if (tis_senddata(sendbuf, send_size)) {
672 printf("%s:%d failed sending data to TPM\n",
673 __FILE__, __LINE__);
674 return TPM_DRIVER_ERR;
675 }
676
677 return tis_readresponse(recvbuf, recv_len);
678}
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700679
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700680/*
681 * tis_setup_interrupt()
682 *
683 * Set up the interrupt vector and polarity for locality 0 and
684 * disable all interrupts so they are unused in firmware but can
685 * be enabled by the OS.
686 *
687 * The values used here must match what is passed in the TPM ACPI
688 * device if ACPI is used on the platform.
689 *
690 * @vector - TPM interrupt vector
691 * @polarity - TPM interrupt polarity
692 *
693 * Returns 0 on success, TPM_DRIVER_ERR on failure.
694 */
695static int tis_setup_interrupt(int vector, int polarity)
696{
697 u8 locality = 0;
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700698
Sergii Dmytruk0a89d522022-10-29 16:57:07 +0300699 if (tlcl_lib_init())
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700700 return TPM_DRIVER_ERR;
701
702 /* Set TPM interrupt vector */
703 tpm_write_int_vector(vector, locality);
704
Elyes HAOUAS18958382018-08-07 12:23:16 +0200705 /* Set TPM interrupt polarity and disable interrupts */
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700706 tpm_write_int_polarity(polarity, locality);
707
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700708 return 0;
709}
710
711static void lpc_tpm_read_resources(struct device *dev)
712{
713 /* Static 5K memory region specified in Kconfig */
Kyösti Mälkki27d62992022-05-24 20:25:58 +0300714 mmio_resource_kb(dev, 0, CONFIG_TPM_TIS_BASE_ADDRESS >> 10, 0x5000 >> 10);
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700715}
716
717static void lpc_tpm_set_resources(struct device *dev)
718{
719 tpm_config_t *config = (tpm_config_t *)dev->chip_info;
Kyösti Mälkkibaa16e92019-11-05 18:38:00 +0200720 DEVTREE_CONST struct resource *res;
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700721
722 for (res = dev->resource_list; res; res = res->next) {
723 if (!(res->flags & IORESOURCE_ASSIGNED))
724 continue;
725
726 if (res->flags & IORESOURCE_IRQ) {
727 /* Set interrupt vector */
728 tis_setup_interrupt((int)res->base,
729 config->irq_polarity);
730 } else {
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700731 continue;
732 }
733
Kyösti Mälkkibaa16e92019-11-05 18:38:00 +0200734#if !DEVTREE_EARLY
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700735 res->flags |= IORESOURCE_STORED;
736 report_resource_stored(dev, res, " <tpm>");
Kyösti Mälkkibaa16e92019-11-05 18:38:00 +0200737#endif
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700738 }
739}
740
Julius Wernercd49cce2019-03-05 16:53:33 -0800741#if CONFIG(HAVE_ACPI_TABLES)
Furquan Shaikh7536a392020-04-24 21:59:21 -0700742static void lpc_tpm_fill_ssdt(const struct device *dev)
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530743{
Michał Kopeća691cbd2022-02-22 12:30:22 +0100744 /* Windows 11 requires the following path for TPM to be detected */
745 const char *path = "\\_SB_.PCI0";
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530746
747 /* Device */
748 acpigen_write_scope(path);
749 acpigen_write_device(acpi_device_name(dev));
750
Michał Żygowski7b288012020-03-20 15:41:44 +0100751 if (CONFIG(TPM2)) {
752 acpigen_write_name_string("_HID", "MSFT0101");
753 acpigen_write_name_string("_CID", "MSFT0101");
754 } else {
755 acpigen_write_name("_HID");
756 acpigen_emit_eisaid("PNP0C31");
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530757
Michał Żygowski7b288012020-03-20 15:41:44 +0100758 acpigen_write_name("_CID");
759 acpigen_emit_eisaid("PNP0C31");
760 }
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530761
Patrick Rudolphc83bab62019-12-13 12:16:06 +0100762 acpi_device_write_uid(dev);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530763
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530764 u32 did_vid = tpm_read_did_vid(0);
765 if (did_vid > 0 && did_vid < 0xffffffff)
766 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
767 else
768 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_OFF);
769
Kevin Cody-Littlec97b5af2018-05-09 14:14:59 -0400770 u16 port = dev->path.pnp.port;
771
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530772 /* Resources */
773 acpigen_write_name("_CRS");
774 acpigen_write_resourcetemplate_header();
775 acpigen_write_mem32fixed(1, CONFIG_TPM_TIS_BASE_ADDRESS, 0x5000);
Frans Hendriks6cc937e2018-10-29 14:30:58 +0100776 if (port)
777 acpigen_write_io16(port, port, 1, 2, 1);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530778
779 if (CONFIG_TPM_PIRQ) {
780 /*
781 * PIRQ: Update interrupt vector with configured PIRQ
782 * Active-Low Level-Triggered Shared
783 */
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800784 struct acpi_irq tpm_irq_a = ACPI_IRQ_LEVEL_LOW(CONFIG_TPM_PIRQ);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530785 acpi_device_write_interrupt(&tpm_irq_a);
786 } else if (tpm_read_int_vector(0) > 0) {
787 u8 int_vec = tpm_read_int_vector(0);
788 u8 int_pol = tpm_read_int_polarity(0);
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800789 struct acpi_irq tpm_irq = ACPI_IRQ_LEVEL_LOW(int_vec);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530790
791 if (int_pol & 1)
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800792 tpm_irq.polarity = ACPI_IRQ_ACTIVE_LOW;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530793 else
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800794 tpm_irq.polarity = ACPI_IRQ_ACTIVE_HIGH;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530795
796 if (int_pol & 2)
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800797 tpm_irq.mode = ACPI_IRQ_EDGE_TRIGGERED;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530798 else
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800799 tpm_irq.mode = ACPI_IRQ_LEVEL_TRIGGERED;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530800
801 acpi_device_write_interrupt(&tpm_irq);
802 }
803
Patrick Rudolphd8d8be12020-09-21 09:48:53 +0200804
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530805 acpigen_write_resourcetemplate_footer();
806
Patrick Rudolphd8d8be12020-09-21 09:48:53 +0200807 if (!CONFIG(CHROMEOS))
808 tpm_ppi_acpi_fill_ssdt(dev);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530809
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530810 acpigen_pop_len(); /* Device */
811 acpigen_pop_len(); /* Scope */
812
Kyösti Mälkkibaa16e92019-11-05 18:38:00 +0200813#if !DEVTREE_EARLY
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530814 printk(BIOS_INFO, "%s.%s: %s %s\n", path, acpi_device_name(dev),
815 dev->chip_ops->name, dev_path(dev));
Kyösti Mälkkibaa16e92019-11-05 18:38:00 +0200816#endif
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530817}
818
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600819static const char *lpc_tpm_acpi_name(const struct device *dev)
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530820{
821 return "TPM";
822}
823#endif
824
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700825static struct device_operations lpc_tpm_ops = {
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +0100826 .read_resources = lpc_tpm_read_resources,
827 .set_resources = lpc_tpm_set_resources,
Julius Wernercd49cce2019-03-05 16:53:33 -0800828#if CONFIG(HAVE_ACPI_TABLES)
Nico Huber68680dd2020-03-31 17:34:52 +0200829 .acpi_name = lpc_tpm_acpi_name,
830 .acpi_fill_ssdt = lpc_tpm_fill_ssdt,
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530831#endif
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700832};
833
834static struct pnp_info pnp_dev_info[] = {
835 { .flags = PNP_IRQ0 }
836};
837
838static void enable_dev(struct device *dev)
839{
Kyösti Mälkkid2b2a182021-04-29 15:33:07 +0300840 if (CONFIG(TPM))
Kyösti Mälkki9cc64932020-05-29 19:42:07 +0300841 pnp_enable_devices(dev, &lpc_tpm_ops,
842 ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700843}
844
845struct chip_operations drivers_pc80_tpm_ops = {
846 CHIP_NAME("LPC TPM")
847 .enable_dev = enable_dev
848};