blob: 1fba61a12fe353cac413059575a8e4370ed0d9ac [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Stefan Reinauerd518c7a2013-11-04 17:38:32 -08002
3#include <stdint.h>
4#include <string.h>
5#include <assert.h>
Lee Leahye0668e42017-01-08 11:38:14 -08006#include <commonlib/endian.h>
Elyes HAOUASadd76f92019-03-21 09:55:49 +01007#include <console/console.h>
Stefan Reinauerd518c7a2013-11-04 17:38:32 -08008#include <delay.h>
Nico Huber0f2dd1e2017-08-01 14:02:40 +02009#include <device/i2c_simple.h>
Julius Werner9ff8f6f2015-02-23 14:31:09 -080010#include <endian.h>
Lee Leahye0668e42017-01-08 11:38:14 -080011#include <lib.h>
Philipp Deppenwiesed88fb362017-10-18 20:26:18 +020012#include <security/tpm/tis.h>
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080013
Elyes HAOUASadd76f92019-03-21 09:55:49 +010014#include "tpm.h"
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080015
16/* global structure for tpm chip data */
Patrick Georgic9b13592019-11-29 11:47:47 +010017static struct tpm_chip chip;
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080018
19#define TPM_CMD_COUNT_BYTE 2
20#define TPM_CMD_ORDINAL_BYTE 6
21
Aaron Durbin92190192017-03-27 16:20:17 -050022static ssize_t tpm_transmit(const uint8_t *sbuf, size_t sbufsiz, void *rbuf,
23 size_t rbufsiz)
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080024{
Jon Murphyd7b8dc92023-09-05 11:36:43 -060025 int rc = -1;
Aaron Durbin9b878442017-03-27 16:40:03 -050026 uint32_t count;
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080027
Aaron Durbin92190192017-03-27 16:20:17 -050028 memcpy(&count, sbuf + TPM_CMD_COUNT_BYTE, sizeof(count));
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080029 count = be32_to_cpu(count);
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080030
Sergii Dmytruk86f845a2022-10-29 18:55:24 +030031 if (!chip.send || !chip.status || !chip.cancel)
Jon Murphyd7b8dc92023-09-05 11:36:43 -060032 goto out;
Duncan Laurie112ab912016-09-02 14:45:53 -070033
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080034 if (count == 0) {
Elyes HAOUAS421285e2021-01-16 17:30:08 +010035 printk(BIOS_DEBUG, "%s: no data\n", __func__);
Jon Murphyd7b8dc92023-09-05 11:36:43 -060036 goto out;
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080037 }
Aaron Durbin92190192017-03-27 16:20:17 -050038 if (count > sbufsiz) {
Jon Murphy53fc6672023-09-26 21:05:37 -060039 printk(BIOS_DEBUG, "%s: invalid count value %#x %zx\n", __func__,
Aaron Durbin92190192017-03-27 16:20:17 -050040 count, sbufsiz);
Jon Murphyd7b8dc92023-09-05 11:36:43 -060041 goto out;
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080042 }
43
Sergii Dmytruk86f845a2022-10-29 18:55:24 +030044 ASSERT(chip.send);
45 rc = chip.send((uint8_t *)sbuf, count);
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080046 if (rc < 0) {
Elyes HAOUAS421285e2021-01-16 17:30:08 +010047 printk(BIOS_DEBUG, "%s: tpm_send error\n", __func__);
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080048 goto out;
49 }
50
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080051 int timeout = 2 * 60 * 1000; /* two minutes timeout */
52 while (timeout) {
Sergii Dmytruk86f845a2022-10-29 18:55:24 +030053 ASSERT(chip.status);
54 uint8_t status = chip.status();
55 if ((status & chip.req_complete_mask) == chip.req_complete_val) {
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080056 goto out_recv;
57 }
58
Sergii Dmytruk86f845a2022-10-29 18:55:24 +030059 if (status == chip.req_canceled) {
Lee Leahy52ab30b2017-03-15 09:22:11 -070060 printk(BIOS_DEBUG,
Elyes HAOUAS421285e2021-01-16 17:30:08 +010061 "%s: Operation Canceled\n", __func__);
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080062 rc = -1;
63 goto out;
64 }
65 mdelay(TPM_TIMEOUT);
66 timeout--;
67 }
68
Sergii Dmytruk86f845a2022-10-29 18:55:24 +030069 ASSERT(chip.cancel);
70 chip.cancel();
Elyes HAOUAS421285e2021-01-16 17:30:08 +010071 printk(BIOS_DEBUG, "%s: Operation Timed out\n", __func__);
Jon Murphyd7b8dc92023-09-05 11:36:43 -060072 rc = -1;
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080073 goto out;
74
75out_recv:
Sergii Dmytruk86f845a2022-10-29 18:55:24 +030076 rc = chip.recv((uint8_t *)rbuf, rbufsiz);
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080077 if (rc < 0)
Elyes HAOUAS421285e2021-01-16 17:30:08 +010078 printk(BIOS_DEBUG, "%s: tpm_recv: error %d\n", __func__, rc);
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080079out:
80 return rc;
81}
82
Sergii Dmytruk963f7b92022-10-29 20:42:28 +030083static tpm_result_t i2c_tpm_sendrecv(const uint8_t *sendbuf, size_t sbuf_size,
84 uint8_t *recvbuf, size_t *rbuf_len)
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080085{
Lee Leahye0668e42017-01-08 11:38:14 -080086 ASSERT(sbuf_size >= 10);
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080087
Lee Leahye0668e42017-01-08 11:38:14 -080088 /* Display the TPM command */
Julius Wernercd49cce2019-03-05 16:53:33 -080089 if (CONFIG(DRIVER_TPM_DISPLAY_TIS_BYTES)) {
Lee Leahye0668e42017-01-08 11:38:14 -080090 printk(BIOS_DEBUG, "TPM Command: 0x%08x\n",
91 read_at_be32(sendbuf, sizeof(uint16_t)
92 + sizeof(uint32_t)));
93 hexdump(sendbuf, sbuf_size);
94 }
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080095
Aaron Durbin92190192017-03-27 16:20:17 -050096 int len = tpm_transmit(sendbuf, sbuf_size, recvbuf, *rbuf_len);
Stefan Reinauerd518c7a2013-11-04 17:38:32 -080097
98 if (len < 10) {
99 *rbuf_len = 0;
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600100 return TPM_CB_FAIL;
Stefan Reinauerd518c7a2013-11-04 17:38:32 -0800101 }
102
103 if (len > *rbuf_len) {
104 *rbuf_len = len;
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600105 return TPM_CB_FAIL;
Stefan Reinauerd518c7a2013-11-04 17:38:32 -0800106 }
107
Stefan Reinauerd518c7a2013-11-04 17:38:32 -0800108 *rbuf_len = len;
109
Lee Leahye0668e42017-01-08 11:38:14 -0800110 /* Display the TPM response */
Julius Wernercd49cce2019-03-05 16:53:33 -0800111 if (CONFIG(DRIVER_TPM_DISPLAY_TIS_BYTES)) {
Lee Leahye0668e42017-01-08 11:38:14 -0800112 printk(BIOS_DEBUG, "TPM Response: 0x%08x\n",
113 read_at_be32(recvbuf, sizeof(uint16_t)
114 + sizeof(uint32_t)));
115 hexdump(recvbuf, *rbuf_len);
116 }
117
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600118 return TPM_SUCCESS;
Stefan Reinauerd518c7a2013-11-04 17:38:32 -0800119}
Sergii Dmytruk963f7b92022-10-29 20:42:28 +0300120
Sergii Dmytruk3e5cefc2022-11-01 00:48:43 +0200121tis_sendrecv_fn i2c_tis_probe(enum tpm_family *family)
Sergii Dmytruk963f7b92022-10-29 20:42:28 +0300122{
Sergii Dmytrukfebf9b92022-10-31 15:30:15 +0200123 if (tpm_vendor_probe(CONFIG_DRIVER_TPM_I2C_BUS, CONFIG_DRIVER_TPM_I2C_ADDR, family))
Sergii Dmytruk963f7b92022-10-29 20:42:28 +0300124 return NULL;
125
126 if (tpm_vendor_init(&chip, CONFIG_DRIVER_TPM_I2C_BUS, CONFIG_DRIVER_TPM_I2C_ADDR))
127 return NULL;
128
129 return &i2c_tpm_sendrecv;
130}