blob: 019e4a1fe9fbcd906d2894f812f85031190825ad [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_) \
Jon Murphy53fc6672023-09-26 21:05:37 -060038 TPM_DEBUG("Read reg %#x returns %#x\n", (reg_), (val_))
Aaron Durbinc4220022013-07-24 16:02:14 -050039#define TPM_DEBUG_IO_WRITE(reg_, val_) \
Jon Murphy53fc6672023-09-26 21:05:37 -060040 TPM_DEBUG("Write reg %#x with %#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 /* 1 second is plenty for anything TPM does.*/
Werner Zeh92ab6112021-10-11 15:27:12 +020078#define MAX_DELAY_US USECS_PER_SEC
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070079
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070080/*
81 * Structures defined below allow creating descriptions of TPM vendor/device
Sergii Dmytruk025d20e2022-12-22 19:34:16 +020082 * ID information for run time discovery. The only device the system knows
83 * about at this time is Infineon slb9635
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070084 */
85struct device_name {
86 u16 dev_id;
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +020087 const char *const dev_name;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070088};
89
90struct vendor_name {
91 u16 vendor_id;
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +020092 const char *vendor_name;
93 const struct device_name *dev_names;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -070094};
95
Stefan Reinauerc908fc72012-04-30 16:33:44 -070096static const struct device_name atmel_devices[] = {
Sergii Dmytruk025d20e2022-12-22 19:34:16 +020097 {0x3204, "AT97SC3204"},
Stefan Reinauerc908fc72012-04-30 16:33:44 -070098 {0xffff}
99};
100
Stefan Reinauerc668af72011-10-27 21:28:25 +0000101static const struct device_name infineon_devices[] = {
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200102 {0x000b, "SLB9635 TT 1.2"},
103#if CONFIG(TPM2)
104 {0x001a, "SLB9665 TT 2.0"},
105 {0x001b, "SLB9670 TT 2.0"},
Tim Crawford64662812023-06-12 11:44:08 -0600106 {0x001d, "SLB9672 TT 2.0"},
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200107#else
108 {0x001a, "SLB9660 TT 1.2"},
109 {0x001b, "SLB9670 TT 1.2"},
110#endif
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700111 {0xffff}
112};
113
114static const struct device_name nuvoton_devices[] = {
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200115 {0x00fe, "NPCT420AA V2"},
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700116 {0xffff}
117};
118
119static const struct device_name stmicro_devices[] = {
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200120 {0x0000, "ST33ZP24" },
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700121 {0xffff}
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700122};
123
Tsung Ho Wu804a0432019-06-07 15:03:49 -0700124static const struct device_name swtpm_devices[] = {
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200125#if CONFIG(TPM2)
126 {0x0001, "SwTPM 2.0" },
127#endif
Tsung Ho Wu804a0432019-06-07 15:03:49 -0700128 {0xffff}
129};
130
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700131static const struct vendor_name vendor_names[] = {
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700132 {0x1114, "Atmel", atmel_devices},
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700133 {0x15d1, "Infineon", infineon_devices},
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700134 {0x1050, "Nuvoton", nuvoton_devices},
Tsung Ho Wu804a0432019-06-07 15:03:49 -0700135 {0x1014, "TPM Emulator", swtpm_devices},
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700136 {0x104a, "ST Microelectronics", stmicro_devices},
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700137};
138
139/*
140 * Cached vendor/device ID pair to indicate that the device has been already
141 * discovered
142 */
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100143static u32 vendor_dev_id;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700144
Aaron Durbinc4220022013-07-24 16:02:14 -0500145static inline u8 tpm_read_status(int locality)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700146{
Julius Werner2f37bd62015-02-19 14:51:15 -0800147 u8 value = read8(TIS_REG(locality, TIS_REG_STS));
Aaron Durbinc4220022013-07-24 16:02:14 -0500148 TPM_DEBUG_IO_READ(TIS_REG_STS, value);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700149 return value;
150}
151
Aaron Durbinc4220022013-07-24 16:02:14 -0500152static inline void tpm_write_status(u8 sts, int locality)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700153{
Aaron Durbinc4220022013-07-24 16:02:14 -0500154 TPM_DEBUG_IO_WRITE(TIS_REG_STS, sts);
Julius Werner2f37bd62015-02-19 14:51:15 -0800155 write8(TIS_REG(locality, TIS_REG_STS), sts);
Aaron Durbinc4220022013-07-24 16:02:14 -0500156}
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700157
Aaron Durbinc4220022013-07-24 16:02:14 -0500158static inline u8 tpm_read_data(int locality)
159{
Julius Werner2f37bd62015-02-19 14:51:15 -0800160 u8 value = read8(TIS_REG(locality, TIS_REG_DATA_FIFO));
Aaron Durbinc4220022013-07-24 16:02:14 -0500161 TPM_DEBUG_IO_READ(TIS_REG_DATA_FIFO, value);
162 return value;
163}
164
165static inline void tpm_write_data(u8 data, int locality)
166{
Werner Zeha31d6cd2021-10-07 07:15:38 +0200167 TPM_DEBUG_IO_WRITE(TIS_REG_DATA_FIFO, data);
Julius Werner2f37bd62015-02-19 14:51:15 -0800168 write8(TIS_REG(locality, TIS_REG_DATA_FIFO), data);
Aaron Durbinc4220022013-07-24 16:02:14 -0500169}
170
171static inline u16 tpm_read_burst_count(int locality)
172{
173 u16 count;
Julius Werner2f37bd62015-02-19 14:51:15 -0800174 count = read8(TIS_REG(locality, TIS_REG_BURST_COUNT));
175 count |= read8(TIS_REG(locality, TIS_REG_BURST_COUNT + 1)) << 8;
Aaron Durbinc4220022013-07-24 16:02:14 -0500176 TPM_DEBUG_IO_READ(TIS_REG_BURST_COUNT, count);
177 return count;
178}
179
180static inline u8 tpm_read_access(int locality)
181{
Julius Werner2f37bd62015-02-19 14:51:15 -0800182 u8 value = read8(TIS_REG(locality, TIS_REG_ACCESS));
Aaron Durbinc4220022013-07-24 16:02:14 -0500183 TPM_DEBUG_IO_READ(TIS_REG_ACCESS, value);
184 return value;
185}
186
187static inline void tpm_write_access(u8 data, int locality)
188{
189 TPM_DEBUG_IO_WRITE(TIS_REG_ACCESS, data);
Julius Werner2f37bd62015-02-19 14:51:15 -0800190 write8(TIS_REG(locality, TIS_REG_ACCESS), data);
Aaron Durbinc4220022013-07-24 16:02:14 -0500191}
192
193static inline u32 tpm_read_did_vid(int locality)
194{
Julius Werner2f37bd62015-02-19 14:51:15 -0800195 u32 value = read32(TIS_REG(locality, TIS_REG_DID_VID));
Aaron Durbinc4220022013-07-24 16:02:14 -0500196 TPM_DEBUG_IO_READ(TIS_REG_DID_VID, value);
197 return value;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700198}
199
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700200static inline void tpm_write_int_vector(int vector, int locality)
201{
202 TPM_DEBUG_IO_WRITE(TIS_REG_INT_VECTOR, vector);
Julius Werner2f37bd62015-02-19 14:51:15 -0800203 write8(TIS_REG(locality, TIS_REG_INT_VECTOR), vector & 0xf);
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700204}
205
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530206static inline u8 tpm_read_int_vector(int locality)
207{
208 u8 value = read8(TIS_REG(locality, TIS_REG_INT_VECTOR));
209 TPM_DEBUG_IO_READ(TIS_REG_INT_VECTOR, value);
210 return value;
211}
212
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700213static inline void tpm_write_int_polarity(int polarity, int locality)
214{
215 /* Set polarity and leave all other bits at 0 */
216 u32 value = (polarity & 0x3) << 3;
217 TPM_DEBUG_IO_WRITE(TIS_REG_INT_ENABLE, value);
Julius Werner2f37bd62015-02-19 14:51:15 -0800218 write32(TIS_REG(locality, TIS_REG_INT_ENABLE), value);
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700219}
220
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530221static inline u32 tpm_read_int_polarity(int locality)
222{
223 /* Get polarity and leave all other bits */
224 u32 value = read8(TIS_REG(locality, TIS_REG_INT_ENABLE));
225 value = (value >> 3) & 0x3;
226 TPM_DEBUG_IO_READ(TIS_REG_INT_ENABLE, value);
227 return value;
228}
229
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700230/*
Aaron Durbinc4220022013-07-24 16:02:14 -0500231 * tis_wait_sts()
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700232 *
Werner Zeh92ab6112021-10-11 15:27:12 +0200233 * Wait for at most a second for a status to change its state to match the
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700234 * expected state. Normally the transition happens within microseconds.
235 *
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700236 * @locality - locality
237 * @mask - bitmask for the bitfield(s) to watch
238 * @expected - value the field(s) are supposed to be set to
239 *
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600240 * Returns TPM_SUCCESS on success or TPM_CB_TIMEOUT on timeout.
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700241 */
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600242static tpm_result_t tis_wait_sts(int locality, u8 mask, u8 expected)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700243{
Werner Zeh92ab6112021-10-11 15:27:12 +0200244 struct stopwatch sw;
245
246 stopwatch_init_usecs_expire(&sw, MAX_DELAY_US);
247 do {
Aaron Durbinc4220022013-07-24 16:02:14 -0500248 u8 value = tpm_read_status(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700249 if ((value & mask) == expected)
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600250 return TPM_SUCCESS;
Werner Zeh92ab6112021-10-11 15:27:12 +0200251 udelay(1);
252 } while (!stopwatch_expired(&sw));
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600253 return TPM_CB_TIMEOUT;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700254}
255
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600256static inline tpm_result_t tis_wait_ready(int locality)
Aaron Durbinc4220022013-07-24 16:02:14 -0500257{
258 return tis_wait_sts(locality, TIS_STS_COMMAND_READY,
259 TIS_STS_COMMAND_READY);
260}
261
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600262static inline tpm_result_t tis_wait_valid(int locality)
Aaron Durbinc4220022013-07-24 16:02:14 -0500263{
264 return tis_wait_sts(locality, TIS_STS_VALID, TIS_STS_VALID);
265}
266
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600267static inline tpm_result_t tis_wait_valid_data(int locality)
Aaron Durbinc4220022013-07-24 16:02:14 -0500268{
269 const u8 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID;
270 return tis_wait_sts(locality, has_data, has_data);
271}
272
273static inline int tis_has_valid_data(int locality)
274{
275 const u8 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID;
276 return (tpm_read_status(locality) & has_data) == has_data;
277}
278
279static inline int tis_expect_data(int locality)
280{
281 return !!(tpm_read_status(locality) & TIS_STS_EXPECT);
282}
283
284/*
285 * tis_wait_access()
286 *
Werner Zeh92ab6112021-10-11 15:27:12 +0200287 * Wait for at most a second for a access to change its state to match the
Aaron Durbinc4220022013-07-24 16:02:14 -0500288 * expected state. Normally the transition happens within microseconds.
289 *
290 * @locality - locality
291 * @mask - bitmask for the bitfield(s) to watch
292 * @expected - value the field(s) are supposed to be set to
293 *
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600294 * Returns TPM_SUCCESS on success or TPM_CB_TIMEOUT on timeout.
Aaron Durbinc4220022013-07-24 16:02:14 -0500295 */
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600296static tpm_result_t tis_wait_access(int locality, u8 mask, u8 expected)
Aaron Durbinc4220022013-07-24 16:02:14 -0500297{
Werner Zeh92ab6112021-10-11 15:27:12 +0200298 struct stopwatch sw;
299
300 stopwatch_init_usecs_expire(&sw, MAX_DELAY_US);
301 do {
Aaron Durbinc4220022013-07-24 16:02:14 -0500302 u8 value = tpm_read_access(locality);
303 if ((value & mask) == expected)
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600304 return TPM_SUCCESS;
Werner Zeh92ab6112021-10-11 15:27:12 +0200305 udelay(1);
306 } while (!stopwatch_expired(&sw));
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600307 return TPM_CB_TIMEOUT;
Aaron Durbinc4220022013-07-24 16:02:14 -0500308}
309
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600310static inline tpm_result_t tis_wait_received_access(int locality)
Aaron Durbinc4220022013-07-24 16:02:14 -0500311{
312 return tis_wait_access(locality, TIS_ACCESS_ACTIVE_LOCALITY,
313 TIS_ACCESS_ACTIVE_LOCALITY);
314}
315
316static inline int tis_has_access(int locality)
317{
318 return !!(tpm_read_access(locality) & TIS_ACCESS_ACTIVE_LOCALITY);
319}
320
321static inline void tis_request_access(int locality)
322{
323 tpm_write_access(TIS_ACCESS_REQUEST_USE, locality);
324}
325
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700326/*
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700327 * PC Client Specific TPM Interface Specification section 11.2.12:
328 *
329 * Software must be prepared to send two writes of a "1" to command ready
330 * field: the first to indicate successful read of all the data, thus
331 * clearing the data from the ReadFIFO and freeing the TPM's resources,
332 * and the second to indicate to the TPM it is about to send a new command.
333 *
334 * In practice not all TPMs behave the same so it is necessary to be
335 * flexible when trying to set command ready.
336 *
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700337 */
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600338static tpm_result_t tis_command_ready(u8 locality)
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700339{
340 u32 status;
341
342 /* 1st attempt to set command ready */
Aaron Durbinc4220022013-07-24 16:02:14 -0500343 tpm_write_status(TIS_STS_COMMAND_READY, locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700344
345 /* Wait for response */
Aaron Durbinc4220022013-07-24 16:02:14 -0500346 status = tpm_read_status(locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700347
348 /* Check if command ready is set yet */
349 if (status & TIS_STS_COMMAND_READY)
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600350 return TPM_SUCCESS;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700351
352 /* 2nd attempt to set command ready */
Aaron Durbinc4220022013-07-24 16:02:14 -0500353 tpm_write_status(TIS_STS_COMMAND_READY, locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700354
Aaron Durbinc4220022013-07-24 16:02:14 -0500355 return tis_wait_ready(locality);
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700356}
357
358/*
Sergii Dmytruk963f7b92022-10-29 20:42:28 +0300359 * pc80_tis_probe()
Jon Murphya7c64d72023-09-15 07:58:08 -0600360 *
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700361 * Probe the TPM device and try determining its manufacturer/device name.
362 *
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600363 * Returns TPM_SUCCESS on success (the device is found or was found during
364 * an earlier invocation) or TPM_CB_FAIL if the device is not found.
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700365 */
Sergii Dmytruk963f7b92022-10-29 20:42:28 +0300366static tpm_result_t pc80_tis_probe(void)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700367{
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200368 const char *device_name = "unknown";
369 const char *vendor_name = device_name;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700370 const struct device_name *dev;
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200371 u32 didvid;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700372 u16 vid, did;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700373 int i;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700374
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100375 if (vendor_dev_id)
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600376 return TPM_SUCCESS; /* Already probed. */
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700377
Aaron Durbinc4220022013-07-24 16:02:14 -0500378 didvid = tpm_read_did_vid(0);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700379 if (!didvid || (didvid == 0xffffffff)) {
Angel Pons08e8cab2020-06-18 15:20:37 +0200380 printf("%s: No TPM device found\n", __func__);
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600381 return TPM_CB_FAIL;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700382 }
383
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100384 vendor_dev_id = didvid;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700385
386 vid = didvid & 0xffff;
387 did = (didvid >> 16) & 0xffff;
388 for (i = 0; i < ARRAY_SIZE(vendor_names); i++) {
389 int j = 0;
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200390 u16 known_did;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700391 if (vid == vendor_names[i].vendor_id) {
392 vendor_name = vendor_names[i].vendor_name;
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700393 } else {
394 continue;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700395 }
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700396 dev = &vendor_names[i].dev_names[j];
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200397 while ((known_did = dev->dev_id) != 0xffff) {
398 if (known_did == did) {
Stefan Reinauerc908fc72012-04-30 16:33:44 -0700399 device_name = dev->dev_name;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700400 break;
401 }
402 j++;
Subrata41b08d92015-05-14 14:38:07 +0530403 dev = &vendor_names[i].dev_names[j];
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700404 }
405 break;
406 }
Sergii Dmytruk025d20e2022-12-22 19:34:16 +0200407 /* this will have to be converted into debug printout */
408 printk(BIOS_INFO, "Found TPM %s by %s\n", device_name, vendor_name);
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600409 return TPM_SUCCESS;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700410}
411
412/*
413 * tis_senddata()
414 *
415 * send the passed in data to the TPM device.
416 *
417 * @data - address of the data to send, byte by byte
418 * @len - length of the data to send
419 *
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600420 * Returns TPM_SUCCESS on success, TPM_CB_FAIL on error (in case the device does
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700421 * not accept the entire command).
422 */
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600423static tpm_result_t tis_senddata(const u8 *const data, u32 len)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700424{
425 u32 offset = 0;
426 u16 burst = 0;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700427 u8 locality = 0;
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600428 tpm_result_t rc = TPM_SUCCESS;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700429
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600430 rc = tis_wait_ready(locality);
431 if (rc) {
432 printf("%s:%d - failed to get 'command_ready' status with error %#x\n",
433 __FILE__, __LINE__, rc);
434 return rc;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700435 }
Aaron Durbinc4220022013-07-24 16:02:14 -0500436 burst = tpm_read_burst_count(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700437
438 while (1) {
Martin Roth38ddbfb2019-10-23 21:41:00 -0600439 unsigned int count;
Werner Zeh92ab6112021-10-11 15:27:12 +0200440 struct stopwatch sw;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700441
442 /* Wait till the device is ready to accept more data. */
Werner Zeh92ab6112021-10-11 15:27:12 +0200443 stopwatch_init_usecs_expire(&sw, MAX_DELAY_US);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700444 while (!burst) {
Werner Zeh92ab6112021-10-11 15:27:12 +0200445 if (stopwatch_expired(&sw)) {
Werner Zeh66b2f202021-10-12 15:14:22 +0200446 printf("%s:%d failed to feed %u bytes of %u\n",
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700447 __FILE__, __LINE__, len - offset, len);
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600448 return TPM_CB_TIMEOUT;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700449 }
450 udelay(1);
Aaron Durbinc4220022013-07-24 16:02:14 -0500451 burst = tpm_read_burst_count(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700452 }
453
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700454 /*
455 * Calculate number of bytes the TPM is ready to accept in one
456 * shot.
457 *
458 * We want to send the last byte outside of the loop (hence
459 * the -1 below) to make sure that the 'expected' status bit
460 * changes to zero exactly after the last byte is fed into the
461 * FIFO.
462 */
Elyes HAOUAS361a9352019-12-18 21:26:33 +0100463 count = MIN(burst, len - offset - 1);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700464 while (count--)
Aaron Durbinc4220022013-07-24 16:02:14 -0500465 tpm_write_data(data[offset++], locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700466
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600467 rc = tis_wait_valid(locality);
468 if (rc || !tis_expect_data(locality)) {
469 printf("%s:%d TPM command feed overflow with error %#x\n",
470 __FILE__, __LINE__, rc);
471 return rc ? rc : TPM_CB_FAIL;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700472 }
473
Aaron Durbinc4220022013-07-24 16:02:14 -0500474 burst = tpm_read_burst_count(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700475 if ((offset == (len - 1)) && burst)
476 /*
477 * We need to be able to send the last byte to the
478 * device, so burst size must be nonzero before we
479 * break out.
480 */
481 break;
482 }
483
484 /* Send the last byte. */
Aaron Durbinc4220022013-07-24 16:02:14 -0500485 tpm_write_data(data[offset++], locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700486
487 /*
488 * Verify that TPM does not expect any more data as part of this
489 * command.
490 */
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600491 rc = tis_wait_valid(locality);
492 if (rc || tis_expect_data(locality)) {
493 printf("%s:%d unexpected TPM error %#x with status %#x\n",
494 __FILE__, __LINE__, rc, tpm_read_status(locality));
495 return rc ? rc : TPM_CB_FAIL;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700496 }
497
498 /* OK, sitting pretty, let's start the command execution. */
Aaron Durbinc4220022013-07-24 16:02:14 -0500499 tpm_write_status(TIS_STS_TPM_GO, locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700500
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600501 return TPM_SUCCESS;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700502}
503
504/*
505 * tis_readresponse()
506 *
507 * read the TPM device response after a command was issued.
508 *
509 * @buffer - address where to read the response, byte by byte.
510 * @len - pointer to the size of buffer
511 *
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600512 * On success stores the number of received bytes to len and returns
513 * TPM_SUCCESS. On errors (misformatted TPM data or synchronization
514 * problems) returns TPM_CB_FAIL.
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700515 */
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600516static tpm_result_t tis_readresponse(u8 *buffer, size_t *len)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700517{
518 u16 burst_count;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700519 u32 offset = 0;
520 u8 locality = 0;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700521 u32 expected_count = *len;
522 int max_cycles = 0;
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600523 tpm_result_t rc = TPM_SUCCESS;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700524
525 /* Wait for the TPM to process the command */
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600526 rc = tis_wait_valid_data(locality);
527 if (rc) {
528 printf("%s:%d failed processing command with error %#x\n",
529 __FILE__, __LINE__, rc);
530 return rc;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700531 }
532
533 do {
Aaron Durbinc4220022013-07-24 16:02:14 -0500534 while ((burst_count = tpm_read_burst_count(locality)) == 0) {
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700535 if (max_cycles++ == MAX_DELAY_US) {
536 printf("%s:%d TPM stuck on read\n",
537 __FILE__, __LINE__);
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600538 return TPM_CB_FAIL;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700539 }
540 udelay(1);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700541 }
542
543 max_cycles = 0;
544
545 while (burst_count-- && (offset < expected_count)) {
Aaron Durbinc4220022013-07-24 16:02:14 -0500546 buffer[offset++] = tpm_read_data(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700547 if (offset == 6) {
548 /*
549 * We got the first six bytes of the reply,
550 * let's figure out how many bytes to expect
551 * total - it is stored as a 4 byte number in
552 * network order, starting with offset 2 into
553 * the body of the reply.
554 */
555 u32 real_length;
556 memcpy(&real_length,
557 buffer + 2,
558 sizeof(real_length));
559 expected_count = be32_to_cpu(real_length);
560
561 if ((expected_count < offset) ||
562 (expected_count > *len)) {
Werner Zeh66b2f202021-10-12 15:14:22 +0200563 printf("%s:%d bad response size %u\n",
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700564 __FILE__, __LINE__,
565 expected_count);
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600566 return TPM_CB_FAIL;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700567 }
568 }
569 }
570
571 /* Wait for the next portion */
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600572 rc = tis_wait_valid(locality);
573 if (rc) {
574 printf("%s:%d failed to read response with error %#x\n",
575 __FILE__, __LINE__, rc);
576 return rc;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700577 }
578
579 if (offset == expected_count)
580 break; /* We got all we need */
581
Bill XIEa4bf0b72018-03-22 17:07:43 +0800582 /*
583 * Certain TPMs seem to need some delay between tis_wait_valid()
584 * and tis_has_valid_data(), or some race-condition-related
585 * issue will occur.
586 */
Julius Wernercd49cce2019-03-05 16:53:33 -0800587 if (CONFIG(TPM_RDRESP_NEED_DELAY))
Bill XIEa4bf0b72018-03-22 17:07:43 +0800588 udelay(10);
589
Aaron Durbinc4220022013-07-24 16:02:14 -0500590 } while (tis_has_valid_data(locality));
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700591
Aaron Durbinc4220022013-07-24 16:02:14 -0500592 /* * Make sure we indeed read all there was. */
593 if (tis_has_valid_data(locality)) {
Jon Murphy53fc6672023-09-26 21:05:37 -0600594 printf("%s:%d wrong receive status: %#x %u bytes left\n",
Aaron Durbinc4220022013-07-24 16:02:14 -0500595 __FILE__, __LINE__, tpm_read_status(locality),
596 tpm_read_burst_count(locality));
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600597 return TPM_CB_FAIL;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700598 }
599
600 /* Tell the TPM that we are done. */
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600601 rc = tis_command_ready(locality);
602 if (rc)
603 return rc;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700604
605 *len = offset;
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600606 return TPM_SUCCESS;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700607}
608
609/*
Sergii Dmytruk963f7b92022-10-29 20:42:28 +0300610 * pc80_tis_open()
Sergii Dmytruk4ee03172022-12-22 19:35:25 +0200611 *
Sergii Dmytruk0a89d522022-10-29 16:57:07 +0300612 * Requests access to locality 0 for the caller.
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700613 *
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600614 * Returns TPM_SUCCESS on success, TSS Error on failure.
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700615 */
Sergii Dmytruk963f7b92022-10-29 20:42:28 +0300616static tpm_result_t pc80_tis_open(void)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700617{
618 u8 locality = 0; /* we use locality zero for everything */
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600619 tpm_result_t rc = TPM_SUCCESS;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700620
Sergii Dmytruk0a89d522022-10-29 16:57:07 +0300621 if (!tis_has_access(locality)) {
622 /* request access to locality */
623 tis_request_access(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700624
Sergii Dmytruk0a89d522022-10-29 16:57:07 +0300625 /* did we get a lock? */
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600626 rc = tis_wait_received_access(locality);
627 if (rc) {
628 printf("%s:%d - failed to lock locality %u with error %#x\n",
629 __FILE__, __LINE__, locality, rc);
630 return rc;
Sergii Dmytruk0a89d522022-10-29 16:57:07 +0300631 }
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700632
Sergii Dmytruk0a89d522022-10-29 16:57:07 +0300633 /* Certain TPMs seem to need some delay here or they hang... */
634 udelay(10);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700635 }
636
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600637 return tis_command_ready(locality);
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700638}
639
640/*
Sergii Dmytruk4ee03172022-12-22 19:35:25 +0200641 * tis_sendrecv()
642 *
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700643 * Send the requested data to the TPM and then try to get its response
644 *
645 * @sendbuf - buffer of the data to send
646 * @send_size size of the data to send
647 * @recvbuf - memory to save the response to
648 * @recv_len - pointer to the size of the response buffer
649 *
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600650 * Returns TPM_SUCCESS on success (and places the number of response bytes
651 * at recv_len) or TPM_CB_FAIL on failure.
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700652 */
Sergii Dmytruk963f7b92022-10-29 20:42:28 +0300653static tpm_result_t pc80_tpm_sendrecv(const uint8_t *sendbuf, size_t send_size,
654 uint8_t *recvbuf, size_t *recv_len)
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700655{
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600656 tpm_result_t rc = tis_senddata(sendbuf, send_size);
657 if (rc) {
658 printf("%s:%d failed sending data to TPM with error %#x\n",
659 __FILE__, __LINE__, rc);
660 return rc;
Stefan Reinauer3008bbad2011-10-11 14:46:25 -0700661 }
662
663 return tis_readresponse(recvbuf, recv_len);
664}
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700665
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700666/*
Sergii Dmytruk963f7b92022-10-29 20:42:28 +0300667 * tis_probe()
668 *
669 * Probe for the TPM device and set it up for use within locality 0. Returns
670 * pointer to send-receive function on success or NULL on failure.
671 */
672tis_sendrecv_fn tis_probe(void)
673{
674 if (pc80_tis_probe())
675 return NULL;
676
677 if (pc80_tis_open())
678 return NULL;
679
680 return &pc80_tpm_sendrecv;
681}
682
683/*
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700684 * tis_setup_interrupt()
685 *
686 * Set up the interrupt vector and polarity for locality 0 and
687 * disable all interrupts so they are unused in firmware but can
688 * be enabled by the OS.
689 *
690 * The values used here must match what is passed in the TPM ACPI
691 * device if ACPI is used on the platform.
692 *
693 * @vector - TPM interrupt vector
694 * @polarity - TPM interrupt polarity
695 *
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600696 * Returns TPM_SUCCESS on success, TPM_CB_FAIL on failure.
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700697 */
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600698static tpm_result_t tis_setup_interrupt(int vector, int polarity)
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700699{
700 u8 locality = 0;
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600701 tpm_result_t rc = tlcl_lib_init();
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700702
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600703 if (rc)
704 return rc;
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700705
706 /* Set TPM interrupt vector */
707 tpm_write_int_vector(vector, locality);
708
Elyes HAOUAS18958382018-08-07 12:23:16 +0200709 /* Set TPM interrupt polarity and disable interrupts */
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700710 tpm_write_int_polarity(polarity, locality);
711
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600712 return TPM_SUCCESS;
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700713}
714
715static void lpc_tpm_read_resources(struct device *dev)
716{
717 /* Static 5K memory region specified in Kconfig */
Arthur Heymanse05693e2023-07-05 11:43:09 +0200718 mmio_range(dev, 0, CONFIG_TPM_TIS_BASE_ADDRESS, 0x5000);
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700719}
720
721static void lpc_tpm_set_resources(struct device *dev)
722{
723 tpm_config_t *config = (tpm_config_t *)dev->chip_info;
Kyösti Mälkkibaa16e92019-11-05 18:38:00 +0200724 DEVTREE_CONST struct resource *res;
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700725
726 for (res = dev->resource_list; res; res = res->next) {
727 if (!(res->flags & IORESOURCE_ASSIGNED))
728 continue;
729
730 if (res->flags & IORESOURCE_IRQ) {
731 /* Set interrupt vector */
732 tis_setup_interrupt((int)res->base,
733 config->irq_polarity);
734 } else {
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700735 continue;
736 }
737
Kyösti Mälkkibaa16e92019-11-05 18:38:00 +0200738#if !DEVTREE_EARLY
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700739 res->flags |= IORESOURCE_STORED;
740 report_resource_stored(dev, res, " <tpm>");
Kyösti Mälkkibaa16e92019-11-05 18:38:00 +0200741#endif
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700742 }
743}
744
Julius Wernercd49cce2019-03-05 16:53:33 -0800745#if CONFIG(HAVE_ACPI_TABLES)
Furquan Shaikh7536a392020-04-24 21:59:21 -0700746static void lpc_tpm_fill_ssdt(const struct device *dev)
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530747{
Michał Kopeća691cbd2022-02-22 12:30:22 +0100748 /* Windows 11 requires the following path for TPM to be detected */
749 const char *path = "\\_SB_.PCI0";
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530750
751 /* Device */
752 acpigen_write_scope(path);
753 acpigen_write_device(acpi_device_name(dev));
754
Michał Żygowski7b288012020-03-20 15:41:44 +0100755 if (CONFIG(TPM2)) {
756 acpigen_write_name_string("_HID", "MSFT0101");
757 acpigen_write_name_string("_CID", "MSFT0101");
758 } else {
759 acpigen_write_name("_HID");
760 acpigen_emit_eisaid("PNP0C31");
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530761
Michał Żygowski7b288012020-03-20 15:41:44 +0100762 acpigen_write_name("_CID");
763 acpigen_emit_eisaid("PNP0C31");
764 }
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530765
Patrick Rudolphc83bab62019-12-13 12:16:06 +0100766 acpi_device_write_uid(dev);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530767
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530768 u32 did_vid = tpm_read_did_vid(0);
769 if (did_vid > 0 && did_vid < 0xffffffff)
770 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
771 else
772 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_OFF);
773
Kevin Cody-Littlec97b5af2018-05-09 14:14:59 -0400774 u16 port = dev->path.pnp.port;
775
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530776 /* Resources */
777 acpigen_write_name("_CRS");
778 acpigen_write_resourcetemplate_header();
779 acpigen_write_mem32fixed(1, CONFIG_TPM_TIS_BASE_ADDRESS, 0x5000);
Frans Hendriks6cc937e2018-10-29 14:30:58 +0100780 if (port)
781 acpigen_write_io16(port, port, 1, 2, 1);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530782
783 if (CONFIG_TPM_PIRQ) {
784 /*
785 * PIRQ: Update interrupt vector with configured PIRQ
786 * Active-Low Level-Triggered Shared
787 */
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800788 struct acpi_irq tpm_irq_a = ACPI_IRQ_LEVEL_LOW(CONFIG_TPM_PIRQ);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530789 acpi_device_write_interrupt(&tpm_irq_a);
790 } else if (tpm_read_int_vector(0) > 0) {
791 u8 int_vec = tpm_read_int_vector(0);
792 u8 int_pol = tpm_read_int_polarity(0);
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800793 struct acpi_irq tpm_irq = ACPI_IRQ_LEVEL_LOW(int_vec);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530794
795 if (int_pol & 1)
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800796 tpm_irq.polarity = ACPI_IRQ_ACTIVE_LOW;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530797 else
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800798 tpm_irq.polarity = ACPI_IRQ_ACTIVE_HIGH;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530799
800 if (int_pol & 2)
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800801 tpm_irq.mode = ACPI_IRQ_EDGE_TRIGGERED;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530802 else
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800803 tpm_irq.mode = ACPI_IRQ_LEVEL_TRIGGERED;
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530804
805 acpi_device_write_interrupt(&tpm_irq);
806 }
807
Patrick Rudolphd8d8be12020-09-21 09:48:53 +0200808
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530809 acpigen_write_resourcetemplate_footer();
810
Patrick Rudolphd8d8be12020-09-21 09:48:53 +0200811 if (!CONFIG(CHROMEOS))
812 tpm_ppi_acpi_fill_ssdt(dev);
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530813
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530814 acpigen_pop_len(); /* Device */
815 acpigen_pop_len(); /* Scope */
816
Kyösti Mälkkibaa16e92019-11-05 18:38:00 +0200817#if !DEVTREE_EARLY
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530818 printk(BIOS_INFO, "%s.%s: %s %s\n", path, acpi_device_name(dev),
819 dev->chip_ops->name, dev_path(dev));
Kyösti Mälkkibaa16e92019-11-05 18:38:00 +0200820#endif
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530821}
822
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600823static const char *lpc_tpm_acpi_name(const struct device *dev)
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530824{
825 return "TPM";
826}
827#endif
828
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700829static struct device_operations lpc_tpm_ops = {
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +0100830 .read_resources = lpc_tpm_read_resources,
831 .set_resources = lpc_tpm_set_resources,
Julius Wernercd49cce2019-03-05 16:53:33 -0800832#if CONFIG(HAVE_ACPI_TABLES)
Nico Huber68680dd2020-03-31 17:34:52 +0200833 .acpi_name = lpc_tpm_acpi_name,
834 .acpi_fill_ssdt = lpc_tpm_fill_ssdt,
Naresh G Solanki80ff0382016-11-15 11:01:33 +0530835#endif
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700836};
837
Arthur Heymans04c49a52023-08-22 13:16:40 +0200838static struct device_operations noop_tpm_ops = {
839 .read_resources = noop_read_resources,
840 .set_resources = noop_set_resources,
841};
842
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700843static struct pnp_info pnp_dev_info[] = {
844 { .flags = PNP_IRQ0 }
845};
846
847static void enable_dev(struct device *dev)
848{
Kyösti Mälkkid2b2a182021-04-29 15:33:07 +0300849 if (CONFIG(TPM))
Kyösti Mälkki9cc64932020-05-29 19:42:07 +0300850 pnp_enable_devices(dev, &lpc_tpm_ops,
851 ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
Arthur Heymans04c49a52023-08-22 13:16:40 +0200852 else
853 pnp_enable_devices(dev, &noop_tpm_ops, ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
Duncan Lauriedd281ed2014-10-30 15:20:19 -0700854}
855
856struct chip_operations drivers_pc80_tpm_ops = {
857 CHIP_NAME("LPC TPM")
858 .enable_dev = enable_dev
859};