blob: e9f14854c44bb2072e84a4da70dd358b9f0b4c47 [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
Elyes HAOUAS361a9352019-12-18 21:26:33 +010024#include <commonlib/helpers.h>
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070025#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>
Duncan Lauriedd281ed2014-10-30 15:20:19 -070034#include <device/pnp.h>
35#include "chip.h"
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070036
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070037#define PREFIX "lpc_tpm: "
Naresh G Solanki80ff0382016-11-15 11:01:33 +053038/* TCG Physical Presence Interface */
39#define TPM_PPI_UUID "3dddfaa6-361b-4eb4-a424-8d10089d1653"
40/* TCG Memory Clear Interface */
41#define TPM_MCI_UUID "376054ed-cc13-4675-901c-4756d7f2d45d"
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070042/* coreboot wrapper for TPM driver (start) */
43#define TPM_DEBUG(fmt, args...) \
Julius Wernercd49cce2019-03-05 16:53:33 -080044 if (CONFIG(DEBUG_TPM)) { \
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070045 printk(BIOS_DEBUG, PREFIX); \
Elyes HAOUASa342f392018-10-17 10:56:26 +020046 printk(BIOS_DEBUG, fmt, ##args); \
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070047 }
Aaron Durbinc4220022013-07-24 16:02:14 -050048#define TPM_DEBUG_IO_READ(reg_, val_) \
49 TPM_DEBUG("Read reg 0x%x returns 0x%x\n", (reg_), (val_))
50#define TPM_DEBUG_IO_WRITE(reg_, val_) \
51 TPM_DEBUG("Write reg 0x%x with 0x%x\n", (reg_), (val_))
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070052#define printf(x...) printk(BIOS_ERR, x)
53
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070054/* coreboot wrapper for TPM driver (end) */
55
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070056/* the macro accepts the locality value, but only locality 0 is operational */
57#define TIS_REG(LOCALITY, REG) \
Martin Rothb9810a42017-07-23 20:00:04 -060058 (void *)(CONFIG_TPM_TIS_BASE_ADDRESS + (LOCALITY << 12) + REG)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070059
60/* hardware registers' offsets */
61#define TIS_REG_ACCESS 0x0
62#define TIS_REG_INT_ENABLE 0x8
63#define TIS_REG_INT_VECTOR 0xc
64#define TIS_REG_INT_STATUS 0x10
65#define TIS_REG_INTF_CAPABILITY 0x14
66#define TIS_REG_STS 0x18
Aaron Durbinc4220022013-07-24 16:02:14 -050067#define TIS_REG_BURST_COUNT 0x19
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070068#define TIS_REG_DATA_FIFO 0x24
69#define TIS_REG_DID_VID 0xf00
70#define TIS_REG_RID 0xf04
71
72/* Some registers' bit field definitions */
73#define TIS_STS_VALID (1 << 7) /* 0x80 */
74#define TIS_STS_COMMAND_READY (1 << 6) /* 0x40 */
75#define TIS_STS_TPM_GO (1 << 5) /* 0x20 */
76#define TIS_STS_DATA_AVAILABLE (1 << 4) /* 0x10 */
77#define TIS_STS_EXPECT (1 << 3) /* 0x08 */
78#define TIS_STS_RESPONSE_RETRY (1 << 1) /* 0x02 */
79
80#define TIS_ACCESS_TPM_REG_VALID_STS (1 << 7) /* 0x80 */
81#define TIS_ACCESS_ACTIVE_LOCALITY (1 << 5) /* 0x20 */
82#define TIS_ACCESS_BEEN_SEIZED (1 << 4) /* 0x10 */
83#define TIS_ACCESS_SEIZE (1 << 3) /* 0x08 */
84#define TIS_ACCESS_PENDING_REQUEST (1 << 2) /* 0x04 */
85#define TIS_ACCESS_REQUEST_USE (1 << 1) /* 0x02 */
86#define TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0) /* 0x01 */
87
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070088/*
89 * Error value returned if a tpm register does not enter the expected state
90 * after continuous polling. No actual TPM register reading ever returns ~0,
91 * so this value is a safe error indication to be mixed with possible status
92 * register values.
93 */
94#define TPM_TIMEOUT_ERR (~0)
95
96/* Error value returned on various TPM driver errors */
97#define TPM_DRIVER_ERR (~0)
98
99 /* 1 second is plenty for anything TPM does.*/
100#define MAX_DELAY_US (1000 * 1000)
101
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700102/*
103 * Structures defined below allow creating descriptions of TPM vendor/device
104 * ID information for run time discovery. The only device the system knows
105 * about at this time is Infineon slb9635
106 */
107struct device_name {
108 u16 dev_id;
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200109 const char *const dev_name;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700110};
111
112struct vendor_name {
113 u16 vendor_id;
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200114 const char *vendor_name;
115 const struct device_name *dev_names;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700116};
117
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700118static const struct device_name atmel_devices[] = {
119 {0x3204, "AT97SC3204"},
120 {0xffff}
121};
122
Stefan Reinauerc668af72011-10-27 21:28:25 +0000123static const struct device_name infineon_devices[] = {
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700124 {0x000b, "SLB9635 TT 1.2"},
Julius Wernercd49cce2019-03-05 16:53:33 -0800125#if CONFIG(TPM2)
Kamil Wcislobf5ccfd2017-10-12 13:12:11 +0200126 {0x001a, "SLB9665 TT 2.0"},
Subrata Banik5b8c4a72016-11-11 09:28:45 +0530127 {0x001b, "SLB9670 TT 2.0"},
128#else
Kamil Wcislobf5ccfd2017-10-12 13:12:11 +0200129 {0x001a, "SLB9660 TT 1.2"},
Wenkai Du641529b2015-05-29 10:54:27 -0700130 {0x001b, "SLB9670 TT 1.2"},
Subrata Banik5b8c4a72016-11-11 09:28:45 +0530131#endif
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700132 {0xffff}
133};
134
135static const struct device_name nuvoton_devices[] = {
136 {0x00fe, "NPCT420AA V2"},
137 {0xffff}
138};
139
140static const struct device_name stmicro_devices[] = {
141 {0x0000, "ST33ZP24" },
142 {0xffff}
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700143};
144
Tsung Ho Wu804a0432019-06-07 15:03:49 -0700145static const struct device_name swtpm_devices[] = {
146#if CONFIG(TPM2)
147 {0x0001, "SwTPM 2.0" },
148#endif
149 {0xffff}
150};
151
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700152static const struct vendor_name vendor_names[] = {
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700153 {0x1114, "Atmel", atmel_devices},
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700154 {0x15d1, "Infineon", infineon_devices},
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700155 {0x1050, "Nuvoton", nuvoton_devices},
Tsung Ho Wu804a0432019-06-07 15:03:49 -0700156 {0x1014, "TPM Emulator", swtpm_devices},
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700157 {0x104a, "ST Microelectronics", stmicro_devices},
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700158};
159
160/*
161 * Cached vendor/device ID pair to indicate that the device has been already
162 * discovered
163 */
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100164static u32 vendor_dev_id;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700165
Aaron Durbinc4220022013-07-24 16:02:14 -0500166static inline u8 tpm_read_status(int locality)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700167{
Julius Werner2f37bd62015-02-19 14:51:15 -0800168 u8 value = read8(TIS_REG(locality, TIS_REG_STS));
Aaron Durbinc4220022013-07-24 16:02:14 -0500169 TPM_DEBUG_IO_READ(TIS_REG_STS, value);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700170 return value;
171}
172
Aaron Durbinc4220022013-07-24 16:02:14 -0500173static inline void tpm_write_status(u8 sts, int locality)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700174{
Aaron Durbinc4220022013-07-24 16:02:14 -0500175 TPM_DEBUG_IO_WRITE(TIS_REG_STS, sts);
Julius Werner2f37bd62015-02-19 14:51:15 -0800176 write8(TIS_REG(locality, TIS_REG_STS), sts);
Aaron Durbinc4220022013-07-24 16:02:14 -0500177}
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700178
Aaron Durbinc4220022013-07-24 16:02:14 -0500179static inline u8 tpm_read_data(int locality)
180{
Julius Werner2f37bd62015-02-19 14:51:15 -0800181 u8 value = read8(TIS_REG(locality, TIS_REG_DATA_FIFO));
Aaron Durbinc4220022013-07-24 16:02:14 -0500182 TPM_DEBUG_IO_READ(TIS_REG_DATA_FIFO, value);
183 return value;
184}
185
186static inline void tpm_write_data(u8 data, int locality)
187{
188 TPM_DEBUG_IO_WRITE(TIS_REG_STS, data);
Julius Werner2f37bd62015-02-19 14:51:15 -0800189 write8(TIS_REG(locality, TIS_REG_DATA_FIFO), data);
Aaron Durbinc4220022013-07-24 16:02:14 -0500190}
191
192static inline u16 tpm_read_burst_count(int locality)
193{
194 u16 count;
Julius Werner2f37bd62015-02-19 14:51:15 -0800195 count = read8(TIS_REG(locality, TIS_REG_BURST_COUNT));
196 count |= read8(TIS_REG(locality, TIS_REG_BURST_COUNT + 1)) << 8;
Aaron Durbinc4220022013-07-24 16:02:14 -0500197 TPM_DEBUG_IO_READ(TIS_REG_BURST_COUNT, count);
198 return count;
199}
200
201static inline u8 tpm_read_access(int locality)
202{
Julius Werner2f37bd62015-02-19 14:51:15 -0800203 u8 value = read8(TIS_REG(locality, TIS_REG_ACCESS));
Aaron Durbinc4220022013-07-24 16:02:14 -0500204 TPM_DEBUG_IO_READ(TIS_REG_ACCESS, value);
205 return value;
206}
207
208static inline void tpm_write_access(u8 data, int locality)
209{
210 TPM_DEBUG_IO_WRITE(TIS_REG_ACCESS, data);
Julius Werner2f37bd62015-02-19 14:51:15 -0800211 write8(TIS_REG(locality, TIS_REG_ACCESS), data);
Aaron Durbinc4220022013-07-24 16:02:14 -0500212}
213
214static inline u32 tpm_read_did_vid(int locality)
215{
Julius Werner2f37bd62015-02-19 14:51:15 -0800216 u32 value = read32(TIS_REG(locality, TIS_REG_DID_VID));
Aaron Durbinc4220022013-07-24 16:02:14 -0500217 TPM_DEBUG_IO_READ(TIS_REG_DID_VID, value);
218 return value;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700219}
220
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700221static inline void tpm_write_int_vector(int vector, int locality)
222{
223 TPM_DEBUG_IO_WRITE(TIS_REG_INT_VECTOR, vector);
Julius Werner2f37bd62015-02-19 14:51:15 -0800224 write8(TIS_REG(locality, TIS_REG_INT_VECTOR), vector & 0xf);
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700225}
226
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530227static inline u8 tpm_read_int_vector(int locality)
228{
229 u8 value = read8(TIS_REG(locality, TIS_REG_INT_VECTOR));
230 TPM_DEBUG_IO_READ(TIS_REG_INT_VECTOR, value);
231 return value;
232}
233
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700234static inline void tpm_write_int_polarity(int polarity, int locality)
235{
236 /* Set polarity and leave all other bits at 0 */
237 u32 value = (polarity & 0x3) << 3;
238 TPM_DEBUG_IO_WRITE(TIS_REG_INT_ENABLE, value);
Julius Werner2f37bd62015-02-19 14:51:15 -0800239 write32(TIS_REG(locality, TIS_REG_INT_ENABLE), value);
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700240}
241
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530242static inline u32 tpm_read_int_polarity(int locality)
243{
244 /* Get polarity and leave all other bits */
245 u32 value = read8(TIS_REG(locality, TIS_REG_INT_ENABLE));
246 value = (value >> 3) & 0x3;
247 TPM_DEBUG_IO_READ(TIS_REG_INT_ENABLE, value);
248 return value;
249}
250
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700251/*
Aaron Durbinc4220022013-07-24 16:02:14 -0500252 * tis_wait_sts()
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700253 *
Aaron Durbinc4220022013-07-24 16:02:14 -0500254 * Wait for at least a second for a status to change its state to match the
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700255 * expected state. Normally the transition happens within microseconds.
256 *
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700257 * @locality - locality
258 * @mask - bitmask for the bitfield(s) to watch
259 * @expected - value the field(s) are supposed to be set to
260 *
Aaron Durbinc4220022013-07-24 16:02:14 -0500261 * Returns 0 on success or TPM_TIMEOUT_ERR on timeout.
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700262 */
Aaron Durbinc4220022013-07-24 16:02:14 -0500263static int tis_wait_sts(int locality, u8 mask, u8 expected)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700264{
265 u32 time_us = MAX_DELAY_US;
266 while (time_us > 0) {
Aaron Durbinc4220022013-07-24 16:02:14 -0500267 u8 value = tpm_read_status(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700268 if ((value & mask) == expected)
Aaron Durbinc4220022013-07-24 16:02:14 -0500269 return 0;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700270 udelay(1); /* 1 us */
271 time_us--;
272 }
273 return TPM_TIMEOUT_ERR;
274}
275
Aaron Durbinc4220022013-07-24 16:02:14 -0500276static inline int tis_wait_ready(int locality)
277{
278 return tis_wait_sts(locality, TIS_STS_COMMAND_READY,
279 TIS_STS_COMMAND_READY);
280}
281
282static inline int tis_wait_valid(int locality)
283{
284 return tis_wait_sts(locality, TIS_STS_VALID, TIS_STS_VALID);
285}
286
287static inline int tis_wait_valid_data(int locality)
288{
289 const u8 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID;
290 return tis_wait_sts(locality, has_data, has_data);
291}
292
293static inline int tis_has_valid_data(int locality)
294{
295 const u8 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID;
296 return (tpm_read_status(locality) & has_data) == has_data;
297}
298
299static inline int tis_expect_data(int locality)
300{
301 return !!(tpm_read_status(locality) & TIS_STS_EXPECT);
302}
303
304/*
305 * tis_wait_access()
306 *
307 * Wait for at least a second for a access to change its state to match the
308 * expected state. Normally the transition happens within microseconds.
309 *
310 * @locality - locality
311 * @mask - bitmask for the bitfield(s) to watch
312 * @expected - value the field(s) are supposed to be set to
313 *
314 * Returns 0 on success or TPM_TIMEOUT_ERR on timeout.
315 */
316static int tis_wait_access(int locality, u8 mask, u8 expected)
317{
318 u32 time_us = MAX_DELAY_US;
319 while (time_us > 0) {
320 u8 value = tpm_read_access(locality);
321 if ((value & mask) == expected)
322 return 0;
323 udelay(1); /* 1 us */
324 time_us--;
325 }
326 return TPM_TIMEOUT_ERR;
327}
328
329static inline int tis_wait_dropped_access(int locality)
330{
331 return tis_wait_access(locality, TIS_ACCESS_ACTIVE_LOCALITY, 0);
332}
333
334static inline int tis_wait_received_access(int locality)
335{
336 return tis_wait_access(locality, TIS_ACCESS_ACTIVE_LOCALITY,
337 TIS_ACCESS_ACTIVE_LOCALITY);
338}
339
340static inline int tis_has_access(int locality)
341{
342 return !!(tpm_read_access(locality) & TIS_ACCESS_ACTIVE_LOCALITY);
343}
344
345static inline void tis_request_access(int locality)
346{
347 tpm_write_access(TIS_ACCESS_REQUEST_USE, locality);
348}
349
350static inline void tis_drop_access(int locality)
351{
352 tpm_write_access(TIS_ACCESS_ACTIVE_LOCALITY, locality);
353}
354
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700355/*
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700356 * PC Client Specific TPM Interface Specification section 11.2.12:
357 *
358 * Software must be prepared to send two writes of a "1" to command ready
359 * field: the first to indicate successful read of all the data, thus
360 * clearing the data from the ReadFIFO and freeing the TPM's resources,
361 * and the second to indicate to the TPM it is about to send a new command.
362 *
363 * In practice not all TPMs behave the same so it is necessary to be
364 * flexible when trying to set command ready.
365 *
366 * Returns 0 on success if the TPM is ready for transactions.
367 * Returns TPM_TIMEOUT_ERR if the command ready bit does not get set.
368 */
369static int tis_command_ready(u8 locality)
370{
371 u32 status;
372
373 /* 1st attempt to set command ready */
Aaron Durbinc4220022013-07-24 16:02:14 -0500374 tpm_write_status(TIS_STS_COMMAND_READY, locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700375
376 /* Wait for response */
Aaron Durbinc4220022013-07-24 16:02:14 -0500377 status = tpm_read_status(locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700378
379 /* Check if command ready is set yet */
380 if (status & TIS_STS_COMMAND_READY)
381 return 0;
382
383 /* 2nd attempt to set command ready */
Aaron Durbinc4220022013-07-24 16:02:14 -0500384 tpm_write_status(TIS_STS_COMMAND_READY, locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700385
Aaron Durbinc4220022013-07-24 16:02:14 -0500386 return tis_wait_ready(locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700387}
388
389/*
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700390 * Probe the TPM device and try determining its manufacturer/device name.
391 *
392 * Returns 0 on success (the device is found or was found during an earlier
393 * invocation) or TPM_DRIVER_ERR if the device is not found.
394 */
395static u32 tis_probe(void)
396{
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700397 const char *device_name = "unknown";
398 const char *vendor_name = device_name;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700399 const struct device_name *dev;
400 u32 didvid;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700401 u16 vid, did;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700402 int i;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700403
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100404 if (vendor_dev_id)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700405 return 0; /* Already probed. */
406
Aaron Durbinc4220022013-07-24 16:02:14 -0500407 didvid = tpm_read_did_vid(0);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700408 if (!didvid || (didvid == 0xffffffff)) {
409 printf("%s: No TPM device found\n", __FUNCTION__);
410 return TPM_DRIVER_ERR;
411 }
412
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100413 vendor_dev_id = didvid;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700414
415 vid = didvid & 0xffff;
416 did = (didvid >> 16) & 0xffff;
417 for (i = 0; i < ARRAY_SIZE(vendor_names); i++) {
418 int j = 0;
419 u16 known_did;
420 if (vid == vendor_names[i].vendor_id) {
421 vendor_name = vendor_names[i].vendor_name;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700422 } else {
423 continue;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700424 }
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700425 dev = &vendor_names[i].dev_names[j];
426 while ((known_did = dev->dev_id) != 0xffff) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700427 if (known_did == did) {
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700428 device_name = dev->dev_name;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700429 break;
430 }
431 j++;
Subrata41b08d92015-05-14 14:38:07 +0530432 dev = &vendor_names[i].dev_names[j];
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700433 }
434 break;
435 }
436 /* this will have to be converted into debug printout */
Duncan Laurie17ba9442015-09-03 16:00:49 -0700437 printk(BIOS_INFO, "Found TPM %s by %s\n", device_name, vendor_name);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700438 return 0;
439}
440
441/*
442 * tis_senddata()
443 *
444 * send the passed in data to the TPM device.
445 *
446 * @data - address of the data to send, byte by byte
447 * @len - length of the data to send
448 *
449 * Returns 0 on success, TPM_DRIVER_ERR on error (in case the device does
450 * not accept the entire command).
451 */
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200452static u32 tis_senddata(const u8 *const data, u32 len)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700453{
454 u32 offset = 0;
455 u16 burst = 0;
456 u32 max_cycles = 0;
457 u8 locality = 0;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700458
Aaron Durbinc4220022013-07-24 16:02:14 -0500459 if (tis_wait_ready(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700460 printf("%s:%d - failed to get 'command_ready' status\n",
461 __FILE__, __LINE__);
462 return TPM_DRIVER_ERR;
463 }
Aaron Durbinc4220022013-07-24 16:02:14 -0500464 burst = tpm_read_burst_count(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700465
466 while (1) {
Martin Roth38ddbfb2019-10-23 21:41:00 -0600467 unsigned int count;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700468
469 /* Wait till the device is ready to accept more data. */
470 while (!burst) {
471 if (max_cycles++ == MAX_DELAY_US) {
472 printf("%s:%d failed to feed %d bytes of %d\n",
473 __FILE__, __LINE__, len - offset, len);
474 return TPM_DRIVER_ERR;
475 }
476 udelay(1);
Aaron Durbinc4220022013-07-24 16:02:14 -0500477 burst = tpm_read_burst_count(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700478 }
479
480 max_cycles = 0;
481
482 /*
483 * Calculate number of bytes the TPM is ready to accept in one
484 * shot.
485 *
486 * We want to send the last byte outside of the loop (hence
487 * the -1 below) to make sure that the 'expected' status bit
488 * changes to zero exactly after the last byte is fed into the
489 * FIFO.
490 */
Elyes HAOUAS361a9352019-12-18 21:26:33 +0100491 count = MIN(burst, len - offset - 1);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700492 while (count--)
Aaron Durbinc4220022013-07-24 16:02:14 -0500493 tpm_write_data(data[offset++], locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700494
Aaron Durbinc4220022013-07-24 16:02:14 -0500495 if (tis_wait_valid(locality) || !tis_expect_data(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700496 printf("%s:%d TPM command feed overflow\n",
497 __FILE__, __LINE__);
498 return TPM_DRIVER_ERR;
499 }
500
Aaron Durbinc4220022013-07-24 16:02:14 -0500501 burst = tpm_read_burst_count(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700502 if ((offset == (len - 1)) && burst)
503 /*
504 * We need to be able to send the last byte to the
505 * device, so burst size must be nonzero before we
506 * break out.
507 */
508 break;
509 }
510
511 /* Send the last byte. */
Aaron Durbinc4220022013-07-24 16:02:14 -0500512 tpm_write_data(data[offset++], locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700513
514 /*
515 * Verify that TPM does not expect any more data as part of this
516 * command.
517 */
Aaron Durbinc4220022013-07-24 16:02:14 -0500518 if (tis_wait_valid(locality) || tis_expect_data(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700519 printf("%s:%d unexpected TPM status 0x%x\n",
Aaron Durbinc4220022013-07-24 16:02:14 -0500520 __FILE__, __LINE__, tpm_read_status(locality));
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700521 return TPM_DRIVER_ERR;
522 }
523
524 /* OK, sitting pretty, let's start the command execution. */
Aaron Durbinc4220022013-07-24 16:02:14 -0500525 tpm_write_status(TIS_STS_TPM_GO, locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700526
527 return 0;
528}
529
530/*
531 * tis_readresponse()
532 *
533 * read the TPM device response after a command was issued.
534 *
535 * @buffer - address where to read the response, byte by byte.
536 * @len - pointer to the size of buffer
537 *
538 * On success stores the number of received bytes to len and returns 0. On
539 * errors (misformatted TPM data or synchronization problems) returns
540 * TPM_DRIVER_ERR.
541 */
542static u32 tis_readresponse(u8 *buffer, size_t *len)
543{
544 u16 burst_count;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700545 u32 offset = 0;
546 u8 locality = 0;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700547 u32 expected_count = *len;
548 int max_cycles = 0;
549
550 /* Wait for the TPM to process the command */
Aaron Durbinc4220022013-07-24 16:02:14 -0500551 if (tis_wait_valid_data(locality)) {
552 printf("%s:%d failed processing command\n", __FILE__, __LINE__);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700553 return TPM_DRIVER_ERR;
554 }
555
556 do {
Aaron Durbinc4220022013-07-24 16:02:14 -0500557 while ((burst_count = tpm_read_burst_count(locality)) == 0) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700558 if (max_cycles++ == MAX_DELAY_US) {
559 printf("%s:%d TPM stuck on read\n",
560 __FILE__, __LINE__);
561 return TPM_DRIVER_ERR;
562 }
563 udelay(1);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700564 }
565
566 max_cycles = 0;
567
568 while (burst_count-- && (offset < expected_count)) {
Aaron Durbinc4220022013-07-24 16:02:14 -0500569 buffer[offset++] = tpm_read_data(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700570 if (offset == 6) {
571 /*
572 * We got the first six bytes of the reply,
573 * let's figure out how many bytes to expect
574 * total - it is stored as a 4 byte number in
575 * network order, starting with offset 2 into
576 * the body of the reply.
577 */
578 u32 real_length;
579 memcpy(&real_length,
580 buffer + 2,
581 sizeof(real_length));
582 expected_count = be32_to_cpu(real_length);
583
584 if ((expected_count < offset) ||
585 (expected_count > *len)) {
586 printf("%s:%d bad response size %d\n",
587 __FILE__, __LINE__,
588 expected_count);
589 return TPM_DRIVER_ERR;
590 }
591 }
592 }
593
594 /* Wait for the next portion */
Aaron Durbinc4220022013-07-24 16:02:14 -0500595 if (tis_wait_valid(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700596 printf("%s:%d failed to read response\n",
597 __FILE__, __LINE__);
598 return TPM_DRIVER_ERR;
599 }
600
601 if (offset == expected_count)
602 break; /* We got all we need */
603
Bill XIEa4bf0b72018-03-22 17:07:43 +0800604 /*
605 * Certain TPMs seem to need some delay between tis_wait_valid()
606 * and tis_has_valid_data(), or some race-condition-related
607 * issue will occur.
608 */
Julius Wernercd49cce2019-03-05 16:53:33 -0800609 if (CONFIG(TPM_RDRESP_NEED_DELAY))
Bill XIEa4bf0b72018-03-22 17:07:43 +0800610 udelay(10);
611
Aaron Durbinc4220022013-07-24 16:02:14 -0500612 } while (tis_has_valid_data(locality));
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700613
Aaron Durbinc4220022013-07-24 16:02:14 -0500614 /* * Make sure we indeed read all there was. */
615 if (tis_has_valid_data(locality)) {
616 printf("%s:%d wrong receive status: %x %d bytes left\n",
617 __FILE__, __LINE__, tpm_read_status(locality),
618 tpm_read_burst_count(locality));
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700619 return TPM_DRIVER_ERR;
620 }
621
622 /* Tell the TPM that we are done. */
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700623 if (tis_command_ready(locality) == TPM_TIMEOUT_ERR)
624 return TPM_DRIVER_ERR;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700625
626 *len = offset;
627 return 0;
628}
629
630/*
631 * tis_init()
632 *
633 * Initialize the TPM device. Returns 0 on success or TPM_DRIVER_ERR on
634 * failure (in case device probing did not succeed).
635 */
636int tis_init(void)
637{
638 if (tis_probe())
639 return TPM_DRIVER_ERR;
640 return 0;
641}
642
643/*
644 * tis_open()
645 *
646 * Requests access to locality 0 for the caller. After all commands have been
647 * completed the caller is supposed to call tis_close().
648 *
649 * Returns 0 on success, TPM_DRIVER_ERR on failure.
650 */
651int tis_open(void)
652{
653 u8 locality = 0; /* we use locality zero for everything */
654
655 if (tis_close())
656 return TPM_DRIVER_ERR;
657
658 /* now request access to locality */
Aaron Durbinc4220022013-07-24 16:02:14 -0500659 tis_request_access(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700660
661 /* did we get a lock? */
Aaron Durbinc4220022013-07-24 16:02:14 -0500662 if (tis_wait_received_access(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700663 printf("%s:%d - failed to lock locality %d\n",
664 __FILE__, __LINE__, locality);
665 return TPM_DRIVER_ERR;
666 }
667
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700668 /* Certain TPMs seem to need some delay here or they hang... */
669 udelay(10);
670
671 if (tis_command_ready(locality) == TPM_TIMEOUT_ERR)
672 return TPM_DRIVER_ERR;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700673
674 return 0;
675}
676
677/*
678 * tis_close()
679 *
Martin Roth56889792013-07-09 21:39:46 -0600680 * terminate the current session with the TPM by releasing the locked
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700681 * locality. Returns 0 on success of TPM_DRIVER_ERR on failure (in case lock
682 * removal did not succeed).
683 */
684int tis_close(void)
685{
686 u8 locality = 0;
Aaron Durbinc4220022013-07-24 16:02:14 -0500687 if (tis_has_access(locality)) {
688 tis_drop_access(locality);
689 if (tis_wait_dropped_access(locality)) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700690 printf("%s:%d - failed to release locality %d\n",
691 __FILE__, __LINE__, locality);
692 return TPM_DRIVER_ERR;
693 }
694 }
695 return 0;
696}
697
698/*
699 * tis_sendrecv()
700 *
701 * Send the requested data to the TPM and then try to get its response
702 *
703 * @sendbuf - buffer of the data to send
704 * @send_size size of the data to send
705 * @recvbuf - memory to save the response to
706 * @recv_len - pointer to the size of the response buffer
707 *
708 * Returns 0 on success (and places the number of response bytes at recv_len)
709 * or TPM_DRIVER_ERR on failure.
710 */
711int tis_sendrecv(const uint8_t *sendbuf, size_t send_size,
712 uint8_t *recvbuf, size_t *recv_len)
713{
714 if (tis_senddata(sendbuf, send_size)) {
715 printf("%s:%d failed sending data to TPM\n",
716 __FILE__, __LINE__);
717 return TPM_DRIVER_ERR;
718 }
719
720 return tis_readresponse(recvbuf, recv_len);
721}
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700722
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700723/*
724 * tis_setup_interrupt()
725 *
726 * Set up the interrupt vector and polarity for locality 0 and
727 * disable all interrupts so they are unused in firmware but can
728 * be enabled by the OS.
729 *
730 * The values used here must match what is passed in the TPM ACPI
731 * device if ACPI is used on the platform.
732 *
733 * @vector - TPM interrupt vector
734 * @polarity - TPM interrupt polarity
735 *
736 * Returns 0 on success, TPM_DRIVER_ERR on failure.
737 */
738static int tis_setup_interrupt(int vector, int polarity)
739{
740 u8 locality = 0;
741 int has_access = tis_has_access(locality);
742
743 /* Open connection and request access if not already granted */
744 if (!has_access && tis_open() < 0)
745 return TPM_DRIVER_ERR;
746
747 /* Set TPM interrupt vector */
748 tpm_write_int_vector(vector, locality);
749
Elyes HAOUAS18958382018-08-07 12:23:16 +0200750 /* Set TPM interrupt polarity and disable interrupts */
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700751 tpm_write_int_polarity(polarity, locality);
752
753 /* Close connection if it was opened */
754 if (!has_access && tis_close() < 0)
755 return TPM_DRIVER_ERR;
756
757 return 0;
758}
759
760static void lpc_tpm_read_resources(struct device *dev)
761{
762 /* Static 5K memory region specified in Kconfig */
763 mmio_resource(dev, 0, CONFIG_TPM_TIS_BASE_ADDRESS >> 10, 0x5000 >> 10);
764}
765
766static void lpc_tpm_set_resources(struct device *dev)
767{
768 tpm_config_t *config = (tpm_config_t *)dev->chip_info;
Kyösti Mälkkibaa16e92019-11-05 18:38:00 +0200769 DEVTREE_CONST struct resource *res;
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700770
771 for (res = dev->resource_list; res; res = res->next) {
772 if (!(res->flags & IORESOURCE_ASSIGNED))
773 continue;
774
775 if (res->flags & IORESOURCE_IRQ) {
776 /* Set interrupt vector */
777 tis_setup_interrupt((int)res->base,
778 config->irq_polarity);
779 } else {
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700780 continue;
781 }
782
Kyösti Mälkkibaa16e92019-11-05 18:38:00 +0200783#if !DEVTREE_EARLY
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700784 res->flags |= IORESOURCE_STORED;
785 report_resource_stored(dev, res, " <tpm>");
Kyösti Mälkkibaa16e92019-11-05 18:38:00 +0200786#endif
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700787 }
788}
789
Julius Wernercd49cce2019-03-05 16:53:33 -0800790#if CONFIG(HAVE_ACPI_TABLES)
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530791
792static void tpm_ppi_func0_cb(void *arg)
793{
794 /* Functions 1-8. */
795 u8 buf[] = {0xff, 0x01};
796 acpigen_write_return_byte_buffer(buf, 2);
797}
798
799static void tpm_ppi_func1_cb(void *arg)
800{
Julius Wernercd49cce2019-03-05 16:53:33 -0800801 if (CONFIG(TPM2))
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530802 /* Interface version: 2.0 */
803 acpigen_write_return_string("2.0");
804 else
805 /* Interface version: 1.2 */
806 acpigen_write_return_string("1.2");
807}
808
809static void tpm_ppi_func2_cb(void *arg)
810{
811 /* Submit operations: drop on the floor and return success. */
812 acpigen_write_return_byte(0);
813}
814
815static void tpm_ppi_func3_cb(void *arg)
816{
817 /* Pending operation: none. */
818 acpigen_emit_byte(RETURN_OP);
819 acpigen_write_package(2);
820 acpigen_write_byte(0);
821 acpigen_write_byte(0);
822 acpigen_pop_len();
823}
824static void tpm_ppi_func4_cb(void *arg)
825{
826 /* Pre-OS transition method: reboot. */
827 acpigen_write_return_byte(2);
828}
829static void tpm_ppi_func5_cb(void *arg)
830{
831 /* Operation response: no operation executed. */
832 acpigen_emit_byte(RETURN_OP);
833 acpigen_write_package(3);
834 acpigen_write_byte(0);
835 acpigen_write_byte(0);
836 acpigen_write_byte(0);
837 acpigen_pop_len();
838}
839static void tpm_ppi_func6_cb(void *arg)
840{
841 /*
842 * Set preferred user language: deprecated and must return 3 aka
843 * "not implemented".
844 */
845 acpigen_write_return_byte(3);
846}
847static void tpm_ppi_func7_cb(void *arg)
848{
849 /* Submit operations: deny. */
850 acpigen_write_return_byte(3);
851}
852static void tpm_ppi_func8_cb(void *arg)
853{
854 /* All actions are forbidden. */
855 acpigen_write_return_byte(1);
856}
857static void (*tpm_ppi_callbacks[])(void *) = {
858 tpm_ppi_func0_cb,
859 tpm_ppi_func1_cb,
860 tpm_ppi_func2_cb,
861 tpm_ppi_func3_cb,
862 tpm_ppi_func4_cb,
863 tpm_ppi_func5_cb,
864 tpm_ppi_func6_cb,
865 tpm_ppi_func7_cb,
866 tpm_ppi_func8_cb,
867};
868
869static void tpm_mci_func0_cb(void *arg)
870{
871 /* Function 1. */
872 acpigen_write_return_singleton_buffer(0x3);
873}
874static void tpm_mci_func1_cb(void *arg)
875{
876 /* Just return success. */
877 acpigen_write_return_byte(0);
878}
879
880static void (*tpm_mci_callbacks[])(void *) = {
881 tpm_mci_func0_cb,
882 tpm_mci_func1_cb,
883};
884
885static void lpc_tpm_fill_ssdt(struct device *dev)
886{
887 const char *path = acpi_device_path(dev->bus->dev);
888 u32 arg;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530889
Philipp Deppenwiese3a1fbea2016-12-14 01:06:55 +0100890 if (!path) {
Tobias Diedrich36537f12017-02-10 00:28:45 +0100891 path = "\\_SB_.PCI0.LPCB";
Philipp Deppenwiese3a1fbea2016-12-14 01:06:55 +0100892 printk(BIOS_DEBUG, "Using default TPM ACPI path: '%s'\n", path);
893 }
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530894
895 /* Device */
896 acpigen_write_scope(path);
897 acpigen_write_device(acpi_device_name(dev));
898
899 acpigen_write_name("_HID");
900 acpigen_emit_eisaid("PNP0C31");
901
902 acpigen_write_name("_CID");
903 acpigen_emit_eisaid("PNP0C31");
904
905 acpigen_write_name_integer("_UID", 1);
906
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530907 u32 did_vid = tpm_read_did_vid(0);
908 if (did_vid > 0 && did_vid < 0xffffffff)
909 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
910 else
911 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_OFF);
912
Kevin Cody-Littlec97b5af2018-05-09 14:14:59 -0400913 u16 port = dev->path.pnp.port;
914
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530915 /* Resources */
916 acpigen_write_name("_CRS");
917 acpigen_write_resourcetemplate_header();
918 acpigen_write_mem32fixed(1, CONFIG_TPM_TIS_BASE_ADDRESS, 0x5000);
Frans Hendriks6cc937e2018-10-29 14:30:58 +0100919 if (port)
920 acpigen_write_io16(port, port, 1, 2, 1);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530921
922 if (CONFIG_TPM_PIRQ) {
923 /*
924 * PIRQ: Update interrupt vector with configured PIRQ
925 * Active-Low Level-Triggered Shared
926 */
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800927 struct acpi_irq tpm_irq_a = ACPI_IRQ_LEVEL_LOW(CONFIG_TPM_PIRQ);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530928 acpi_device_write_interrupt(&tpm_irq_a);
929 } else if (tpm_read_int_vector(0) > 0) {
930 u8 int_vec = tpm_read_int_vector(0);
931 u8 int_pol = tpm_read_int_polarity(0);
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800932 struct acpi_irq tpm_irq = ACPI_IRQ_LEVEL_LOW(int_vec);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530933
934 if (int_pol & 1)
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800935 tpm_irq.polarity = ACPI_IRQ_ACTIVE_LOW;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530936 else
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800937 tpm_irq.polarity = ACPI_IRQ_ACTIVE_HIGH;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530938
939 if (int_pol & 2)
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800940 tpm_irq.mode = ACPI_IRQ_EDGE_TRIGGERED;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530941 else
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800942 tpm_irq.mode = ACPI_IRQ_LEVEL_TRIGGERED;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530943
944 acpi_device_write_interrupt(&tpm_irq);
945 }
946
947 acpigen_write_resourcetemplate_footer();
948
Julius Wernercd49cce2019-03-05 16:53:33 -0800949 if (!CONFIG(CHROMEOS)) {
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530950 /*
951 * _DSM method
952 */
953 struct dsm_uuid ids[] = {
954 /* Physical presence interface.
955 * This is used to submit commands like "Clear TPM" to
956 * be run at next reboot provided that user confirms
957 * them. Spec allows user to cancel all commands and/or
958 * configure BIOS to reject commands. So we pretend that
959 * user did just this: cancelled everything. If user
960 * really wants to clear TPM the only option now is to
961 * do it manually in payload.
962 */
963 DSM_UUID(TPM_PPI_UUID, &tpm_ppi_callbacks[0],
964 ARRAY_SIZE(tpm_ppi_callbacks), (void *) &arg),
965 /* Memory clearing on boot: just a dummy. */
966 DSM_UUID(TPM_MCI_UUID, &tpm_mci_callbacks[0],
967 ARRAY_SIZE(tpm_mci_callbacks), (void *) &arg),
968 };
969
970 acpigen_write_dsm_uuid_arr(ids, ARRAY_SIZE(ids));
971 }
972 acpigen_pop_len(); /* Device */
973 acpigen_pop_len(); /* Scope */
974
Kyösti Mälkkibaa16e92019-11-05 18:38:00 +0200975#if !DEVTREE_EARLY
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530976 printk(BIOS_INFO, "%s.%s: %s %s\n", path, acpi_device_name(dev),
977 dev->chip_ops->name, dev_path(dev));
Kyösti Mälkkibaa16e92019-11-05 18:38:00 +0200978#endif
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530979}
980
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600981static const char *lpc_tpm_acpi_name(const struct device *dev)
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530982{
983 return "TPM";
984}
985#endif
986
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700987static struct device_operations lpc_tpm_ops = {
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +0100988 .read_resources = lpc_tpm_read_resources,
989 .set_resources = lpc_tpm_set_resources,
Julius Wernercd49cce2019-03-05 16:53:33 -0800990#if CONFIG(HAVE_ACPI_TABLES)
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +0100991 .acpi_name = lpc_tpm_acpi_name,
992 .acpi_fill_ssdt_generator = lpc_tpm_fill_ssdt,
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530993#endif
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700994};
995
996static struct pnp_info pnp_dev_info[] = {
997 { .flags = PNP_IRQ0 }
998};
999
1000static void enable_dev(struct device *dev)
1001{
1002 pnp_enable_devices(dev, &lpc_tpm_ops,
1003 ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
1004}
1005
1006struct chip_operations drivers_pc80_tpm_ops = {
1007 CHIP_NAME("LPC TPM")
1008 .enable_dev = enable_dev
1009};