blob: 23de003b47619ab3df0f2cb51c284a4452215b59 [file] [log] [blame]
Stefan Reinauer3008bbad2011-10-11 14:46:25 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2011 The Chromium OS Authors. All rights reserved.
Frans Hendriks6cc937e2018-10-29 14:30:58 +01005 * Copyright (C) 2018 Eltan B.V.
Stefan Reinauer3008bbad2011-10-11 14:46:25 -07006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070015 */
16
17/*
18 * The code in this file has been heavily based on the article "Writing a TPM
19 * Device Driver" published on http://ptgmedia.pearsoncmg.com and the
20 * submission by Stefan Berger on Qemu-devel mailing list.
21 *
22 * One principal difference is that in the simplest config the other than 0
23 * TPM localities do not get mapped by some devices (for instance, by
24 * Infineon slb9635), so this driver provides access to locality 0 only.
25 */
26
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070027#include <stdlib.h>
28#include <string.h>
29#include <delay.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020030#include <device/mmio.h>
Naresh G Solanki80ff0382016-11-15 11:01:33 +053031#include <arch/acpi.h>
32#include <arch/acpigen.h>
33#include <arch/acpi_device.h>
34#include <device/device.h>
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070035#include <console/console.h>
Philipp Deppenwiesed88fb362017-10-18 20:26:18 +020036#include <security/tpm/tis.h>
Stefan Reinauerfd4f4132013-06-19 12:25:44 -070037#include <arch/early_variables.h>
Duncan Lauriedd281ed2014-10-30 15:20:19 -070038#include <device/pnp.h>
39#include "chip.h"
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070040
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070041#define PREFIX "lpc_tpm: "
Naresh G Solanki80ff0382016-11-15 11:01:33 +053042/* TCG Physical Presence Interface */
43#define TPM_PPI_UUID "3dddfaa6-361b-4eb4-a424-8d10089d1653"
44/* TCG Memory Clear Interface */
45#define TPM_MCI_UUID "376054ed-cc13-4675-901c-4756d7f2d45d"
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070046/* coreboot wrapper for TPM driver (start) */
47#define TPM_DEBUG(fmt, args...) \
Julius Wernercd49cce2019-03-05 16:53:33 -080048 if (CONFIG(DEBUG_TPM)) { \
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070049 printk(BIOS_DEBUG, PREFIX); \
Elyes HAOUASa342f392018-10-17 10:56:26 +020050 printk(BIOS_DEBUG, fmt, ##args); \
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070051 }
Aaron Durbinc4220022013-07-24 16:02:14 -050052#define TPM_DEBUG_IO_READ(reg_, val_) \
53 TPM_DEBUG("Read reg 0x%x returns 0x%x\n", (reg_), (val_))
54#define TPM_DEBUG_IO_WRITE(reg_, val_) \
55 TPM_DEBUG("Write reg 0x%x with 0x%x\n", (reg_), (val_))
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070056#define printf(x...) printk(BIOS_ERR, x)
57
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070058/* coreboot wrapper for TPM driver (end) */
59
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070060/* the macro accepts the locality value, but only locality 0 is operational */
61#define TIS_REG(LOCALITY, REG) \
Martin Rothb9810a42017-07-23 20:00:04 -060062 (void *)(CONFIG_TPM_TIS_BASE_ADDRESS + (LOCALITY << 12) + REG)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070063
64/* hardware registers' offsets */
65#define TIS_REG_ACCESS 0x0
66#define TIS_REG_INT_ENABLE 0x8
67#define TIS_REG_INT_VECTOR 0xc
68#define TIS_REG_INT_STATUS 0x10
69#define TIS_REG_INTF_CAPABILITY 0x14
70#define TIS_REG_STS 0x18
Aaron Durbinc4220022013-07-24 16:02:14 -050071#define TIS_REG_BURST_COUNT 0x19
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070072#define TIS_REG_DATA_FIFO 0x24
73#define TIS_REG_DID_VID 0xf00
74#define TIS_REG_RID 0xf04
75
76/* Some registers' bit field definitions */
77#define TIS_STS_VALID (1 << 7) /* 0x80 */
78#define TIS_STS_COMMAND_READY (1 << 6) /* 0x40 */
79#define TIS_STS_TPM_GO (1 << 5) /* 0x20 */
80#define TIS_STS_DATA_AVAILABLE (1 << 4) /* 0x10 */
81#define TIS_STS_EXPECT (1 << 3) /* 0x08 */
82#define TIS_STS_RESPONSE_RETRY (1 << 1) /* 0x02 */
83
84#define TIS_ACCESS_TPM_REG_VALID_STS (1 << 7) /* 0x80 */
85#define TIS_ACCESS_ACTIVE_LOCALITY (1 << 5) /* 0x20 */
86#define TIS_ACCESS_BEEN_SEIZED (1 << 4) /* 0x10 */
87#define TIS_ACCESS_SEIZE (1 << 3) /* 0x08 */
88#define TIS_ACCESS_PENDING_REQUEST (1 << 2) /* 0x04 */
89#define TIS_ACCESS_REQUEST_USE (1 << 1) /* 0x02 */
90#define TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0) /* 0x01 */
91
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070092/*
93 * Error value returned if a tpm register does not enter the expected state
94 * after continuous polling. No actual TPM register reading ever returns ~0,
95 * so this value is a safe error indication to be mixed with possible status
96 * register values.
97 */
98#define TPM_TIMEOUT_ERR (~0)
99
100/* Error value returned on various TPM driver errors */
101#define TPM_DRIVER_ERR (~0)
102
103 /* 1 second is plenty for anything TPM does.*/
104#define MAX_DELAY_US (1000 * 1000)
105
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700106/*
107 * Structures defined below allow creating descriptions of TPM vendor/device
108 * ID information for run time discovery. The only device the system knows
109 * about at this time is Infineon slb9635
110 */
111struct device_name {
112 u16 dev_id;
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200113 const char *const dev_name;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700114};
115
116struct vendor_name {
117 u16 vendor_id;
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200118 const char *vendor_name;
119 const struct device_name *dev_names;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700120};
121
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700122static const struct device_name atmel_devices[] = {
123 {0x3204, "AT97SC3204"},
124 {0xffff}
125};
126
Stefan Reinauerc668af72011-10-27 21:28:25 +0000127static const struct device_name infineon_devices[] = {
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700128 {0x000b, "SLB9635 TT 1.2"},
Julius Wernercd49cce2019-03-05 16:53:33 -0800129#if CONFIG(TPM2)
Kamil Wcislobf5ccfd2017-10-12 13:12:11 +0200130 {0x001a, "SLB9665 TT 2.0"},
Subrata Banik5b8c4a72016-11-11 09:28:45 +0530131 {0x001b, "SLB9670 TT 2.0"},
132#else
Kamil Wcislobf5ccfd2017-10-12 13:12:11 +0200133 {0x001a, "SLB9660 TT 1.2"},
Wenkai Du641529b2015-05-29 10:54:27 -0700134 {0x001b, "SLB9670 TT 1.2"},
Subrata Banik5b8c4a72016-11-11 09:28:45 +0530135#endif
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700136 {0xffff}
137};
138
139static const struct device_name nuvoton_devices[] = {
140 {0x00fe, "NPCT420AA V2"},
141 {0xffff}
142};
143
144static const struct device_name stmicro_devices[] = {
145 {0x0000, "ST33ZP24" },
146 {0xffff}
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700147};
148
Tsung Ho Wu804a0432019-06-07 15:03:49 -0700149static const struct device_name swtpm_devices[] = {
150#if CONFIG(TPM2)
151 {0x0001, "SwTPM 2.0" },
152#endif
153 {0xffff}
154};
155
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700156static const struct vendor_name vendor_names[] = {
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700157 {0x1114, "Atmel", atmel_devices},
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700158 {0x15d1, "Infineon", infineon_devices},
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700159 {0x1050, "Nuvoton", nuvoton_devices},
Tsung Ho Wu804a0432019-06-07 15:03:49 -0700160 {0x1014, "TPM Emulator", swtpm_devices},
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700161 {0x104a, "ST Microelectronics", stmicro_devices},
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700162};
163
164/*
165 * Cached vendor/device ID pair to indicate that the device has been already
166 * discovered
167 */
Stefan Reinauerc668af72011-10-27 21:28:25 +0000168static u32 vendor_dev_id CAR_GLOBAL;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700169
Aaron Durbinc4220022013-07-24 16:02:14 -0500170static inline u8 tpm_read_status(int locality)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700171{
Julius Werner2f37bd62015-02-19 14:51:15 -0800172 u8 value = read8(TIS_REG(locality, TIS_REG_STS));
Aaron Durbinc4220022013-07-24 16:02:14 -0500173 TPM_DEBUG_IO_READ(TIS_REG_STS, value);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700174 return value;
175}
176
Aaron Durbinc4220022013-07-24 16:02:14 -0500177static inline void tpm_write_status(u8 sts, int locality)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700178{
Aaron Durbinc4220022013-07-24 16:02:14 -0500179 TPM_DEBUG_IO_WRITE(TIS_REG_STS, sts);
Julius Werner2f37bd62015-02-19 14:51:15 -0800180 write8(TIS_REG(locality, TIS_REG_STS), sts);
Aaron Durbinc4220022013-07-24 16:02:14 -0500181}
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700182
Aaron Durbinc4220022013-07-24 16:02:14 -0500183static inline u8 tpm_read_data(int locality)
184{
Julius Werner2f37bd62015-02-19 14:51:15 -0800185 u8 value = read8(TIS_REG(locality, TIS_REG_DATA_FIFO));
Aaron Durbinc4220022013-07-24 16:02:14 -0500186 TPM_DEBUG_IO_READ(TIS_REG_DATA_FIFO, value);
187 return value;
188}
189
190static inline void tpm_write_data(u8 data, int locality)
191{
192 TPM_DEBUG_IO_WRITE(TIS_REG_STS, data);
Julius Werner2f37bd62015-02-19 14:51:15 -0800193 write8(TIS_REG(locality, TIS_REG_DATA_FIFO), data);
Aaron Durbinc4220022013-07-24 16:02:14 -0500194}
195
196static inline u16 tpm_read_burst_count(int locality)
197{
198 u16 count;
Julius Werner2f37bd62015-02-19 14:51:15 -0800199 count = read8(TIS_REG(locality, TIS_REG_BURST_COUNT));
200 count |= read8(TIS_REG(locality, TIS_REG_BURST_COUNT + 1)) << 8;
Aaron Durbinc4220022013-07-24 16:02:14 -0500201 TPM_DEBUG_IO_READ(TIS_REG_BURST_COUNT, count);
202 return count;
203}
204
205static inline u8 tpm_read_access(int locality)
206{
Julius Werner2f37bd62015-02-19 14:51:15 -0800207 u8 value = read8(TIS_REG(locality, TIS_REG_ACCESS));
Aaron Durbinc4220022013-07-24 16:02:14 -0500208 TPM_DEBUG_IO_READ(TIS_REG_ACCESS, value);
209 return value;
210}
211
212static inline void tpm_write_access(u8 data, int locality)
213{
214 TPM_DEBUG_IO_WRITE(TIS_REG_ACCESS, data);
Julius Werner2f37bd62015-02-19 14:51:15 -0800215 write8(TIS_REG(locality, TIS_REG_ACCESS), data);
Aaron Durbinc4220022013-07-24 16:02:14 -0500216}
217
218static inline u32 tpm_read_did_vid(int locality)
219{
Julius Werner2f37bd62015-02-19 14:51:15 -0800220 u32 value = read32(TIS_REG(locality, TIS_REG_DID_VID));
Aaron Durbinc4220022013-07-24 16:02:14 -0500221 TPM_DEBUG_IO_READ(TIS_REG_DID_VID, value);
222 return value;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700223}
224
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700225static inline void tpm_write_int_vector(int vector, int locality)
226{
227 TPM_DEBUG_IO_WRITE(TIS_REG_INT_VECTOR, vector);
Julius Werner2f37bd62015-02-19 14:51:15 -0800228 write8(TIS_REG(locality, TIS_REG_INT_VECTOR), vector & 0xf);
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700229}
230
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530231static inline u8 tpm_read_int_vector(int locality)
232{
233 u8 value = read8(TIS_REG(locality, TIS_REG_INT_VECTOR));
234 TPM_DEBUG_IO_READ(TIS_REG_INT_VECTOR, value);
235 return value;
236}
237
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700238static inline void tpm_write_int_polarity(int polarity, int locality)
239{
240 /* Set polarity and leave all other bits at 0 */
241 u32 value = (polarity & 0x3) << 3;
242 TPM_DEBUG_IO_WRITE(TIS_REG_INT_ENABLE, value);
Julius Werner2f37bd62015-02-19 14:51:15 -0800243 write32(TIS_REG(locality, TIS_REG_INT_ENABLE), value);
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700244}
245
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530246static inline u32 tpm_read_int_polarity(int locality)
247{
248 /* Get polarity and leave all other bits */
249 u32 value = read8(TIS_REG(locality, TIS_REG_INT_ENABLE));
250 value = (value >> 3) & 0x3;
251 TPM_DEBUG_IO_READ(TIS_REG_INT_ENABLE, value);
252 return value;
253}
254
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700255/*
Aaron Durbinc4220022013-07-24 16:02:14 -0500256 * tis_wait_sts()
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700257 *
Aaron Durbinc4220022013-07-24 16:02:14 -0500258 * Wait for at least a second for a status to change its state to match the
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700259 * expected state. Normally the transition happens within microseconds.
260 *
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700261 * @locality - locality
262 * @mask - bitmask for the bitfield(s) to watch
263 * @expected - value the field(s) are supposed to be set to
264 *
Aaron Durbinc4220022013-07-24 16:02:14 -0500265 * Returns 0 on success or TPM_TIMEOUT_ERR on timeout.
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700266 */
Aaron Durbinc4220022013-07-24 16:02:14 -0500267static int tis_wait_sts(int locality, u8 mask, u8 expected)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700268{
269 u32 time_us = MAX_DELAY_US;
270 while (time_us > 0) {
Aaron Durbinc4220022013-07-24 16:02:14 -0500271 u8 value = tpm_read_status(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700272 if ((value & mask) == expected)
Aaron Durbinc4220022013-07-24 16:02:14 -0500273 return 0;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700274 udelay(1); /* 1 us */
275 time_us--;
276 }
277 return TPM_TIMEOUT_ERR;
278}
279
Aaron Durbinc4220022013-07-24 16:02:14 -0500280static inline int tis_wait_ready(int locality)
281{
282 return tis_wait_sts(locality, TIS_STS_COMMAND_READY,
283 TIS_STS_COMMAND_READY);
284}
285
286static inline int tis_wait_valid(int locality)
287{
288 return tis_wait_sts(locality, TIS_STS_VALID, TIS_STS_VALID);
289}
290
291static inline int tis_wait_valid_data(int locality)
292{
293 const u8 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID;
294 return tis_wait_sts(locality, has_data, has_data);
295}
296
297static inline int tis_has_valid_data(int locality)
298{
299 const u8 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID;
300 return (tpm_read_status(locality) & has_data) == has_data;
301}
302
303static inline int tis_expect_data(int locality)
304{
305 return !!(tpm_read_status(locality) & TIS_STS_EXPECT);
306}
307
308/*
309 * tis_wait_access()
310 *
311 * Wait for at least a second for a access to change its state to match the
312 * expected state. Normally the transition happens within microseconds.
313 *
314 * @locality - locality
315 * @mask - bitmask for the bitfield(s) to watch
316 * @expected - value the field(s) are supposed to be set to
317 *
318 * Returns 0 on success or TPM_TIMEOUT_ERR on timeout.
319 */
320static int tis_wait_access(int locality, u8 mask, u8 expected)
321{
322 u32 time_us = MAX_DELAY_US;
323 while (time_us > 0) {
324 u8 value = tpm_read_access(locality);
325 if ((value & mask) == expected)
326 return 0;
327 udelay(1); /* 1 us */
328 time_us--;
329 }
330 return TPM_TIMEOUT_ERR;
331}
332
333static inline int tis_wait_dropped_access(int locality)
334{
335 return tis_wait_access(locality, TIS_ACCESS_ACTIVE_LOCALITY, 0);
336}
337
338static inline int tis_wait_received_access(int locality)
339{
340 return tis_wait_access(locality, TIS_ACCESS_ACTIVE_LOCALITY,
341 TIS_ACCESS_ACTIVE_LOCALITY);
342}
343
344static inline int tis_has_access(int locality)
345{
346 return !!(tpm_read_access(locality) & TIS_ACCESS_ACTIVE_LOCALITY);
347}
348
349static inline void tis_request_access(int locality)
350{
351 tpm_write_access(TIS_ACCESS_REQUEST_USE, locality);
352}
353
354static inline void tis_drop_access(int locality)
355{
356 tpm_write_access(TIS_ACCESS_ACTIVE_LOCALITY, locality);
357}
358
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700359/*
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700360 * PC Client Specific TPM Interface Specification section 11.2.12:
361 *
362 * Software must be prepared to send two writes of a "1" to command ready
363 * field: the first to indicate successful read of all the data, thus
364 * clearing the data from the ReadFIFO and freeing the TPM's resources,
365 * and the second to indicate to the TPM it is about to send a new command.
366 *
367 * In practice not all TPMs behave the same so it is necessary to be
368 * flexible when trying to set command ready.
369 *
370 * Returns 0 on success if the TPM is ready for transactions.
371 * Returns TPM_TIMEOUT_ERR if the command ready bit does not get set.
372 */
373static int tis_command_ready(u8 locality)
374{
375 u32 status;
376
377 /* 1st attempt to set command ready */
Aaron Durbinc4220022013-07-24 16:02:14 -0500378 tpm_write_status(TIS_STS_COMMAND_READY, locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700379
380 /* Wait for response */
Aaron Durbinc4220022013-07-24 16:02:14 -0500381 status = tpm_read_status(locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700382
383 /* Check if command ready is set yet */
384 if (status & TIS_STS_COMMAND_READY)
385 return 0;
386
387 /* 2nd attempt to set command ready */
Aaron Durbinc4220022013-07-24 16:02:14 -0500388 tpm_write_status(TIS_STS_COMMAND_READY, locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700389
Aaron Durbinc4220022013-07-24 16:02:14 -0500390 return tis_wait_ready(locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700391}
392
393/*
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700394 * Probe the TPM device and try determining its manufacturer/device name.
395 *
396 * Returns 0 on success (the device is found or was found during an earlier
397 * invocation) or TPM_DRIVER_ERR if the device is not found.
398 */
399static u32 tis_probe(void)
400{
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700401 const char *device_name = "unknown";
402 const char *vendor_name = device_name;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700403 const struct device_name *dev;
404 u32 didvid;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700405 u16 vid, did;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700406 int i;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700407
Aaron Durbincb997d32013-05-10 00:40:56 -0500408 if (car_get_var(vendor_dev_id))
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700409 return 0; /* Already probed. */
410
Aaron Durbinc4220022013-07-24 16:02:14 -0500411 didvid = tpm_read_did_vid(0);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700412 if (!didvid || (didvid == 0xffffffff)) {
413 printf("%s: No TPM device found\n", __FUNCTION__);
414 return TPM_DRIVER_ERR;
415 }
416
Aaron Durbincb997d32013-05-10 00:40:56 -0500417 car_set_var(vendor_dev_id, didvid);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700418
419 vid = didvid & 0xffff;
420 did = (didvid >> 16) & 0xffff;
421 for (i = 0; i < ARRAY_SIZE(vendor_names); i++) {
422 int j = 0;
423 u16 known_did;
424 if (vid == vendor_names[i].vendor_id) {
425 vendor_name = vendor_names[i].vendor_name;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700426 } else {
427 continue;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700428 }
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700429 dev = &vendor_names[i].dev_names[j];
430 while ((known_did = dev->dev_id) != 0xffff) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700431 if (known_did == did) {
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700432 device_name = dev->dev_name;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700433 break;
434 }
435 j++;
Subrata41b08d92015-05-14 14:38:07 +0530436 dev = &vendor_names[i].dev_names[j];
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700437 }
438 break;
439 }
440 /* this will have to be converted into debug printout */
Duncan Laurie17ba9442015-09-03 16:00:49 -0700441 printk(BIOS_INFO, "Found TPM %s by %s\n", device_name, vendor_name);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700442 return 0;
443}
444
445/*
446 * tis_senddata()
447 *
448 * send the passed in data to the TPM device.
449 *
450 * @data - address of the data to send, byte by byte
451 * @len - length of the data to send
452 *
453 * Returns 0 on success, TPM_DRIVER_ERR on error (in case the device does
454 * not accept the entire command).
455 */
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200456static u32 tis_senddata(const u8 *const data, u32 len)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700457{
458 u32 offset = 0;
459 u16 burst = 0;
460 u32 max_cycles = 0;
461 u8 locality = 0;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700462
Aaron Durbinc4220022013-07-24 16:02:14 -0500463 if (tis_wait_ready(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700464 printf("%s:%d - failed to get 'command_ready' status\n",
465 __FILE__, __LINE__);
466 return TPM_DRIVER_ERR;
467 }
Aaron Durbinc4220022013-07-24 16:02:14 -0500468 burst = tpm_read_burst_count(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700469
470 while (1) {
471 unsigned count;
472
473 /* Wait till the device is ready to accept more data. */
474 while (!burst) {
475 if (max_cycles++ == MAX_DELAY_US) {
476 printf("%s:%d failed to feed %d bytes of %d\n",
477 __FILE__, __LINE__, len - offset, len);
478 return TPM_DRIVER_ERR;
479 }
480 udelay(1);
Aaron Durbinc4220022013-07-24 16:02:14 -0500481 burst = tpm_read_burst_count(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700482 }
483
484 max_cycles = 0;
485
486 /*
487 * Calculate number of bytes the TPM is ready to accept in one
488 * shot.
489 *
490 * We want to send the last byte outside of the loop (hence
491 * the -1 below) to make sure that the 'expected' status bit
492 * changes to zero exactly after the last byte is fed into the
493 * FIFO.
494 */
495 count = min(burst, len - offset - 1);
496 while (count--)
Aaron Durbinc4220022013-07-24 16:02:14 -0500497 tpm_write_data(data[offset++], locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700498
Aaron Durbinc4220022013-07-24 16:02:14 -0500499 if (tis_wait_valid(locality) || !tis_expect_data(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700500 printf("%s:%d TPM command feed overflow\n",
501 __FILE__, __LINE__);
502 return TPM_DRIVER_ERR;
503 }
504
Aaron Durbinc4220022013-07-24 16:02:14 -0500505 burst = tpm_read_burst_count(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700506 if ((offset == (len - 1)) && burst)
507 /*
508 * We need to be able to send the last byte to the
509 * device, so burst size must be nonzero before we
510 * break out.
511 */
512 break;
513 }
514
515 /* Send the last byte. */
Aaron Durbinc4220022013-07-24 16:02:14 -0500516 tpm_write_data(data[offset++], locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700517
518 /*
519 * Verify that TPM does not expect any more data as part of this
520 * command.
521 */
Aaron Durbinc4220022013-07-24 16:02:14 -0500522 if (tis_wait_valid(locality) || tis_expect_data(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700523 printf("%s:%d unexpected TPM status 0x%x\n",
Aaron Durbinc4220022013-07-24 16:02:14 -0500524 __FILE__, __LINE__, tpm_read_status(locality));
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700525 return TPM_DRIVER_ERR;
526 }
527
528 /* OK, sitting pretty, let's start the command execution. */
Aaron Durbinc4220022013-07-24 16:02:14 -0500529 tpm_write_status(TIS_STS_TPM_GO, locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700530
531 return 0;
532}
533
534/*
535 * tis_readresponse()
536 *
537 * read the TPM device response after a command was issued.
538 *
539 * @buffer - address where to read the response, byte by byte.
540 * @len - pointer to the size of buffer
541 *
542 * On success stores the number of received bytes to len and returns 0. On
543 * errors (misformatted TPM data or synchronization problems) returns
544 * TPM_DRIVER_ERR.
545 */
546static u32 tis_readresponse(u8 *buffer, size_t *len)
547{
548 u16 burst_count;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700549 u32 offset = 0;
550 u8 locality = 0;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700551 u32 expected_count = *len;
552 int max_cycles = 0;
553
554 /* Wait for the TPM to process the command */
Aaron Durbinc4220022013-07-24 16:02:14 -0500555 if (tis_wait_valid_data(locality)) {
556 printf("%s:%d failed processing command\n", __FILE__, __LINE__);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700557 return TPM_DRIVER_ERR;
558 }
559
560 do {
Aaron Durbinc4220022013-07-24 16:02:14 -0500561 while ((burst_count = tpm_read_burst_count(locality)) == 0) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700562 if (max_cycles++ == MAX_DELAY_US) {
563 printf("%s:%d TPM stuck on read\n",
564 __FILE__, __LINE__);
565 return TPM_DRIVER_ERR;
566 }
567 udelay(1);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700568 }
569
570 max_cycles = 0;
571
572 while (burst_count-- && (offset < expected_count)) {
Aaron Durbinc4220022013-07-24 16:02:14 -0500573 buffer[offset++] = tpm_read_data(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700574 if (offset == 6) {
575 /*
576 * We got the first six bytes of the reply,
577 * let's figure out how many bytes to expect
578 * total - it is stored as a 4 byte number in
579 * network order, starting with offset 2 into
580 * the body of the reply.
581 */
582 u32 real_length;
583 memcpy(&real_length,
584 buffer + 2,
585 sizeof(real_length));
586 expected_count = be32_to_cpu(real_length);
587
588 if ((expected_count < offset) ||
589 (expected_count > *len)) {
590 printf("%s:%d bad response size %d\n",
591 __FILE__, __LINE__,
592 expected_count);
593 return TPM_DRIVER_ERR;
594 }
595 }
596 }
597
598 /* Wait for the next portion */
Aaron Durbinc4220022013-07-24 16:02:14 -0500599 if (tis_wait_valid(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700600 printf("%s:%d failed to read response\n",
601 __FILE__, __LINE__);
602 return TPM_DRIVER_ERR;
603 }
604
605 if (offset == expected_count)
606 break; /* We got all we need */
607
Bill XIEa4bf0b72018-03-22 17:07:43 +0800608 /*
609 * Certain TPMs seem to need some delay between tis_wait_valid()
610 * and tis_has_valid_data(), or some race-condition-related
611 * issue will occur.
612 */
Julius Wernercd49cce2019-03-05 16:53:33 -0800613 if (CONFIG(TPM_RDRESP_NEED_DELAY))
Bill XIEa4bf0b72018-03-22 17:07:43 +0800614 udelay(10);
615
Aaron Durbinc4220022013-07-24 16:02:14 -0500616 } while (tis_has_valid_data(locality));
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700617
Aaron Durbinc4220022013-07-24 16:02:14 -0500618 /* * Make sure we indeed read all there was. */
619 if (tis_has_valid_data(locality)) {
620 printf("%s:%d wrong receive status: %x %d bytes left\n",
621 __FILE__, __LINE__, tpm_read_status(locality),
622 tpm_read_burst_count(locality));
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700623 return TPM_DRIVER_ERR;
624 }
625
626 /* Tell the TPM that we are done. */
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700627 if (tis_command_ready(locality) == TPM_TIMEOUT_ERR)
628 return TPM_DRIVER_ERR;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700629
630 *len = offset;
631 return 0;
632}
633
634/*
635 * tis_init()
636 *
637 * Initialize the TPM device. Returns 0 on success or TPM_DRIVER_ERR on
638 * failure (in case device probing did not succeed).
639 */
640int tis_init(void)
641{
642 if (tis_probe())
643 return TPM_DRIVER_ERR;
644 return 0;
645}
646
647/*
648 * tis_open()
649 *
650 * Requests access to locality 0 for the caller. After all commands have been
651 * completed the caller is supposed to call tis_close().
652 *
653 * Returns 0 on success, TPM_DRIVER_ERR on failure.
654 */
655int tis_open(void)
656{
657 u8 locality = 0; /* we use locality zero for everything */
658
659 if (tis_close())
660 return TPM_DRIVER_ERR;
661
662 /* now request access to locality */
Aaron Durbinc4220022013-07-24 16:02:14 -0500663 tis_request_access(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700664
665 /* did we get a lock? */
Aaron Durbinc4220022013-07-24 16:02:14 -0500666 if (tis_wait_received_access(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700667 printf("%s:%d - failed to lock locality %d\n",
668 __FILE__, __LINE__, locality);
669 return TPM_DRIVER_ERR;
670 }
671
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700672 /* Certain TPMs seem to need some delay here or they hang... */
673 udelay(10);
674
675 if (tis_command_ready(locality) == TPM_TIMEOUT_ERR)
676 return TPM_DRIVER_ERR;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700677
678 return 0;
679}
680
681/*
682 * tis_close()
683 *
Martin Roth56889792013-07-09 21:39:46 -0600684 * terminate the current session with the TPM by releasing the locked
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700685 * locality. Returns 0 on success of TPM_DRIVER_ERR on failure (in case lock
686 * removal did not succeed).
687 */
688int tis_close(void)
689{
690 u8 locality = 0;
Aaron Durbinc4220022013-07-24 16:02:14 -0500691 if (tis_has_access(locality)) {
692 tis_drop_access(locality);
693 if (tis_wait_dropped_access(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700694 printf("%s:%d - failed to release locality %d\n",
695 __FILE__, __LINE__, locality);
696 return TPM_DRIVER_ERR;
697 }
698 }
699 return 0;
700}
701
702/*
703 * tis_sendrecv()
704 *
705 * Send the requested data to the TPM and then try to get its response
706 *
707 * @sendbuf - buffer of the data to send
708 * @send_size size of the data to send
709 * @recvbuf - memory to save the response to
710 * @recv_len - pointer to the size of the response buffer
711 *
712 * Returns 0 on success (and places the number of response bytes at recv_len)
713 * or TPM_DRIVER_ERR on failure.
714 */
715int tis_sendrecv(const uint8_t *sendbuf, size_t send_size,
716 uint8_t *recvbuf, size_t *recv_len)
717{
718 if (tis_senddata(sendbuf, send_size)) {
719 printf("%s:%d failed sending data to TPM\n",
720 __FILE__, __LINE__);
721 return TPM_DRIVER_ERR;
722 }
723
724 return tis_readresponse(recvbuf, recv_len);
725}
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700726
727#ifdef __RAMSTAGE__
728
729/*
730 * tis_setup_interrupt()
731 *
732 * Set up the interrupt vector and polarity for locality 0 and
733 * disable all interrupts so they are unused in firmware but can
734 * be enabled by the OS.
735 *
736 * The values used here must match what is passed in the TPM ACPI
737 * device if ACPI is used on the platform.
738 *
739 * @vector - TPM interrupt vector
740 * @polarity - TPM interrupt polarity
741 *
742 * Returns 0 on success, TPM_DRIVER_ERR on failure.
743 */
744static int tis_setup_interrupt(int vector, int polarity)
745{
746 u8 locality = 0;
747 int has_access = tis_has_access(locality);
748
749 /* Open connection and request access if not already granted */
750 if (!has_access && tis_open() < 0)
751 return TPM_DRIVER_ERR;
752
753 /* Set TPM interrupt vector */
754 tpm_write_int_vector(vector, locality);
755
Elyes HAOUAS18958382018-08-07 12:23:16 +0200756 /* Set TPM interrupt polarity and disable interrupts */
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700757 tpm_write_int_polarity(polarity, locality);
758
759 /* Close connection if it was opened */
760 if (!has_access && tis_close() < 0)
761 return TPM_DRIVER_ERR;
762
763 return 0;
764}
765
766static void lpc_tpm_read_resources(struct device *dev)
767{
768 /* Static 5K memory region specified in Kconfig */
769 mmio_resource(dev, 0, CONFIG_TPM_TIS_BASE_ADDRESS >> 10, 0x5000 >> 10);
770}
771
772static void lpc_tpm_set_resources(struct device *dev)
773{
774 tpm_config_t *config = (tpm_config_t *)dev->chip_info;
775 struct resource *res;
776
777 for (res = dev->resource_list; res; res = res->next) {
778 if (!(res->flags & IORESOURCE_ASSIGNED))
779 continue;
780
781 if (res->flags & IORESOURCE_IRQ) {
782 /* Set interrupt vector */
783 tis_setup_interrupt((int)res->base,
784 config->irq_polarity);
785 } else {
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700786 continue;
787 }
788
789 res->flags |= IORESOURCE_STORED;
790 report_resource_stored(dev, res, " <tpm>");
791 }
792}
793
Julius Wernercd49cce2019-03-05 16:53:33 -0800794#if CONFIG(HAVE_ACPI_TABLES)
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530795
796static void tpm_ppi_func0_cb(void *arg)
797{
798 /* Functions 1-8. */
799 u8 buf[] = {0xff, 0x01};
800 acpigen_write_return_byte_buffer(buf, 2);
801}
802
803static void tpm_ppi_func1_cb(void *arg)
804{
Julius Wernercd49cce2019-03-05 16:53:33 -0800805 if (CONFIG(TPM2))
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530806 /* Interface version: 2.0 */
807 acpigen_write_return_string("2.0");
808 else
809 /* Interface version: 1.2 */
810 acpigen_write_return_string("1.2");
811}
812
813static void tpm_ppi_func2_cb(void *arg)
814{
815 /* Submit operations: drop on the floor and return success. */
816 acpigen_write_return_byte(0);
817}
818
819static void tpm_ppi_func3_cb(void *arg)
820{
821 /* Pending operation: none. */
822 acpigen_emit_byte(RETURN_OP);
823 acpigen_write_package(2);
824 acpigen_write_byte(0);
825 acpigen_write_byte(0);
826 acpigen_pop_len();
827}
828static void tpm_ppi_func4_cb(void *arg)
829{
830 /* Pre-OS transition method: reboot. */
831 acpigen_write_return_byte(2);
832}
833static void tpm_ppi_func5_cb(void *arg)
834{
835 /* Operation response: no operation executed. */
836 acpigen_emit_byte(RETURN_OP);
837 acpigen_write_package(3);
838 acpigen_write_byte(0);
839 acpigen_write_byte(0);
840 acpigen_write_byte(0);
841 acpigen_pop_len();
842}
843static void tpm_ppi_func6_cb(void *arg)
844{
845 /*
846 * Set preferred user language: deprecated and must return 3 aka
847 * "not implemented".
848 */
849 acpigen_write_return_byte(3);
850}
851static void tpm_ppi_func7_cb(void *arg)
852{
853 /* Submit operations: deny. */
854 acpigen_write_return_byte(3);
855}
856static void tpm_ppi_func8_cb(void *arg)
857{
858 /* All actions are forbidden. */
859 acpigen_write_return_byte(1);
860}
861static void (*tpm_ppi_callbacks[])(void *) = {
862 tpm_ppi_func0_cb,
863 tpm_ppi_func1_cb,
864 tpm_ppi_func2_cb,
865 tpm_ppi_func3_cb,
866 tpm_ppi_func4_cb,
867 tpm_ppi_func5_cb,
868 tpm_ppi_func6_cb,
869 tpm_ppi_func7_cb,
870 tpm_ppi_func8_cb,
871};
872
873static void tpm_mci_func0_cb(void *arg)
874{
875 /* Function 1. */
876 acpigen_write_return_singleton_buffer(0x3);
877}
878static void tpm_mci_func1_cb(void *arg)
879{
880 /* Just return success. */
881 acpigen_write_return_byte(0);
882}
883
884static void (*tpm_mci_callbacks[])(void *) = {
885 tpm_mci_func0_cb,
886 tpm_mci_func1_cb,
887};
888
889static void lpc_tpm_fill_ssdt(struct device *dev)
890{
891 const char *path = acpi_device_path(dev->bus->dev);
892 u32 arg;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530893
Philipp Deppenwiese3a1fbea2016-12-14 01:06:55 +0100894 if (!path) {
Tobias Diedrich36537f12017-02-10 00:28:45 +0100895 path = "\\_SB_.PCI0.LPCB";
Philipp Deppenwiese3a1fbea2016-12-14 01:06:55 +0100896 printk(BIOS_DEBUG, "Using default TPM ACPI path: '%s'\n", path);
897 }
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530898
899 /* Device */
900 acpigen_write_scope(path);
901 acpigen_write_device(acpi_device_name(dev));
902
903 acpigen_write_name("_HID");
904 acpigen_emit_eisaid("PNP0C31");
905
906 acpigen_write_name("_CID");
907 acpigen_emit_eisaid("PNP0C31");
908
909 acpigen_write_name_integer("_UID", 1);
910
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530911 u32 did_vid = tpm_read_did_vid(0);
912 if (did_vid > 0 && did_vid < 0xffffffff)
913 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
914 else
915 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_OFF);
916
Kevin Cody-Littlec97b5af2018-05-09 14:14:59 -0400917 u16 port = dev->path.pnp.port;
918
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530919 /* Resources */
920 acpigen_write_name("_CRS");
921 acpigen_write_resourcetemplate_header();
922 acpigen_write_mem32fixed(1, CONFIG_TPM_TIS_BASE_ADDRESS, 0x5000);
Frans Hendriks6cc937e2018-10-29 14:30:58 +0100923 if (port)
924 acpigen_write_io16(port, port, 1, 2, 1);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530925
926 if (CONFIG_TPM_PIRQ) {
927 /*
928 * PIRQ: Update interrupt vector with configured PIRQ
929 * Active-Low Level-Triggered Shared
930 */
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800931 struct acpi_irq tpm_irq_a = ACPI_IRQ_LEVEL_LOW(CONFIG_TPM_PIRQ);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530932 acpi_device_write_interrupt(&tpm_irq_a);
933 } else if (tpm_read_int_vector(0) > 0) {
934 u8 int_vec = tpm_read_int_vector(0);
935 u8 int_pol = tpm_read_int_polarity(0);
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800936 struct acpi_irq tpm_irq = ACPI_IRQ_LEVEL_LOW(int_vec);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530937
938 if (int_pol & 1)
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800939 tpm_irq.polarity = ACPI_IRQ_ACTIVE_LOW;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530940 else
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800941 tpm_irq.polarity = ACPI_IRQ_ACTIVE_HIGH;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530942
943 if (int_pol & 2)
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800944 tpm_irq.mode = ACPI_IRQ_EDGE_TRIGGERED;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530945 else
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800946 tpm_irq.mode = ACPI_IRQ_LEVEL_TRIGGERED;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530947
948 acpi_device_write_interrupt(&tpm_irq);
949 }
950
951 acpigen_write_resourcetemplate_footer();
952
Julius Wernercd49cce2019-03-05 16:53:33 -0800953 if (!CONFIG(CHROMEOS)) {
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530954 /*
955 * _DSM method
956 */
957 struct dsm_uuid ids[] = {
958 /* Physical presence interface.
959 * This is used to submit commands like "Clear TPM" to
960 * be run at next reboot provided that user confirms
961 * them. Spec allows user to cancel all commands and/or
962 * configure BIOS to reject commands. So we pretend that
963 * user did just this: cancelled everything. If user
964 * really wants to clear TPM the only option now is to
965 * do it manually in payload.
966 */
967 DSM_UUID(TPM_PPI_UUID, &tpm_ppi_callbacks[0],
968 ARRAY_SIZE(tpm_ppi_callbacks), (void *) &arg),
969 /* Memory clearing on boot: just a dummy. */
970 DSM_UUID(TPM_MCI_UUID, &tpm_mci_callbacks[0],
971 ARRAY_SIZE(tpm_mci_callbacks), (void *) &arg),
972 };
973
974 acpigen_write_dsm_uuid_arr(ids, ARRAY_SIZE(ids));
975 }
976 acpigen_pop_len(); /* Device */
977 acpigen_pop_len(); /* Scope */
978
979 printk(BIOS_INFO, "%s.%s: %s %s\n", path, acpi_device_name(dev),
980 dev->chip_ops->name, dev_path(dev));
981}
982
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600983static const char *lpc_tpm_acpi_name(const struct device *dev)
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530984{
985 return "TPM";
986}
987#endif
988
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700989static struct device_operations lpc_tpm_ops = {
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +0100990 .read_resources = lpc_tpm_read_resources,
991 .set_resources = lpc_tpm_set_resources,
Julius Wernercd49cce2019-03-05 16:53:33 -0800992#if CONFIG(HAVE_ACPI_TABLES)
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +0100993 .acpi_name = lpc_tpm_acpi_name,
994 .acpi_fill_ssdt_generator = lpc_tpm_fill_ssdt,
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530995#endif
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700996};
997
998static struct pnp_info pnp_dev_info[] = {
999 { .flags = PNP_IRQ0 }
1000};
1001
1002static void enable_dev(struct device *dev)
1003{
1004 pnp_enable_devices(dev, &lpc_tpm_ops,
1005 ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
1006}
1007
1008struct chip_operations drivers_pc80_tpm_ops = {
1009 CHIP_NAME("LPC TPM")
1010 .enable_dev = enable_dev
1011};
1012
1013#endif /* __RAMSTAGE__ */