xref: /openbmc/u-boot/drivers/tpm/tpm2_tis_i2c.c (revision bf54cdd1)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright 2022 IBM Corp.
4  */
5 
6 #include <common.h>
7 #include <dm.h>
8 #include <fdtdec.h>
9 #include <i2c.h>
10 #include <log.h>
11 #include <tpm-v2.h>
12 #include <linux/bitops.h>
13 #include <linux/delay.h>
14 #include <linux/errno.h>
15 #include <linux/compiler.h>
16 #include <linux/types.h>
17 #include <linux/unaligned/be_byteshift.h>
18 #include <asm-generic/gpio.h>
19 
20 #include "tpm_tis.h"
21 #include "tpm_internal.h"
22 
23 struct tpm_tis_chip_data {
24 	unsigned int pcr_count;
25 	unsigned int pcr_select_min;
26 };
27 
28 static uint tpm_tis_i2c_address_to_register(u32 addr)
29 {
30 	addr &= 0xFFF;
31 
32 	/*
33 	 * Adapt register addresses that have changed compared to older TIS
34 	 * version.
35 	 */
36 	switch (addr) {
37 	case TPM_ACCESS(0):
38 		return 0x04;
39 	case TPM_DID_VID(0):
40 		return 0x48;
41 	case TPM_RID(0):
42 		return 0x4C;
43 	default:
44 		return addr;
45 	}
46 }
47 
48 static int tpm_tis_i2c_read(struct udevice *dev, u32 addr, u16 len, u8 *in)
49 {
50 	int rc;
51 	int count = 0;
52 	uint reg = tpm_tis_i2c_address_to_register(addr);
53 
54 	do {
55 		rc = dm_i2c_read(dev, reg, in, len);
56 		udelay(SLEEP_DURATION_US);
57 	} while (rc && count++ < MAX_COUNT);
58 
59 	return rc;
60 }
61 
62 static int tpm_tis_i2c_write(struct udevice *dev, u32 addr, u16 len,
63 			     const u8 *out)
64 {
65 	int rc;
66 	int count = 0;
67 	uint reg = tpm_tis_i2c_address_to_register(addr);
68 
69 	do {
70 		rc = dm_i2c_write(dev, reg, out, len);
71 		udelay(SLEEP_DURATION_US);
72 	} while (rc && count++ < MAX_COUNT);
73 
74 	return rc;
75 }
76 
77 static int tpm_tis_i2c_read32(struct udevice *dev, u32 addr, u32 *result)
78 {
79 	__le32 result_le;
80 	int rc;
81 
82 	rc = tpm_tis_i2c_read(dev, addr, sizeof(u32), (u8 *)&result_le);
83 	if (!rc)
84 		*result = le32_to_cpu(result_le);
85 
86 	return rc;
87 }
88 
89 static int tpm_tis_i2c_write32(struct udevice *dev, u32 addr, u32 value)
90 {
91 	__le32 value_le = cpu_to_le32(value);
92 
93 	return tpm_tis_i2c_write(dev, addr, sizeof(value), (u8 *)&value_le);
94 }
95 
96 static struct tpm_tis_phy_ops phy_ops = {
97 	.read_bytes = tpm_tis_i2c_read,
98 	.write_bytes = tpm_tis_i2c_write,
99 	.read32 = tpm_tis_i2c_read32,
100 	.write32 = tpm_tis_i2c_write32,
101 };
102 
103 static int tpm_tis_i2c_probe(struct udevice *udev)
104 {
105 	struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(udev);
106 	struct tpm_chip_priv *priv = dev_get_uclass_priv(udev);
107 	int rc;
108 	u8 loc = 0;
109 
110 	tpm_tis_ops_register(udev, &phy_ops);
111 
112 	/*
113 	 * Force locality 0. The core driver doesn't actually write the
114 	 * locality register and instead just reads/writes various access
115 	 * bits of the selected locality.
116 	 */
117 	rc = dm_i2c_write(udev, 0, &loc, 1);
118 	if (rc)
119 		return rc;
120 
121 	rc = tpm_tis_init(udev);
122 	if (rc)
123 		return rc;
124 
125 	priv->pcr_count = drv_data->pcr_count;
126 	priv->pcr_select_min = drv_data->pcr_select_min;
127 	priv->version = TPM_V2;
128 
129 	return 0;
130 }
131 
132 static int tpm_tis_i2c_remove(struct udevice *udev)
133 {
134 	return tpm_tis_cleanup(udev);
135 }
136 
137 static const struct tpm_ops tpm_tis_i2c_ops = {
138 	.open = tpm_tis_open,
139 	.close = tpm_tis_close,
140 	.get_desc = tpm_tis_get_desc,
141 	.send = tpm_tis_send,
142 	.recv = tpm_tis_recv,
143 	.cleanup = tpm_tis_cleanup,
144 };
145 
146 static const struct tpm_tis_chip_data tpm_tis_std_chip_data = {
147 	.pcr_count = 24,
148 	.pcr_select_min = 3,
149 };
150 
151 static const struct udevice_id tpm_tis_i2c_ids[] = {
152 	{
153 		.compatible = "nuvoton,npct75x",
154 		.data = (ulong)&tpm_tis_std_chip_data,
155 	},
156 	{
157 		.compatible = "tcg,tpm-tis-i2c",
158 		.data = (ulong)&tpm_tis_std_chip_data,
159 	},
160 	{ }
161 };
162 
163 U_BOOT_DRIVER(tpm_tis_i2c) = {
164 	.name = "tpm_tis_i2c",
165 	.id = UCLASS_TPM,
166 	.of_match = tpm_tis_i2c_ids,
167 	.ops = &tpm_tis_i2c_ops,
168 	.probe = tpm_tis_i2c_probe,
169 	.remove = tpm_tis_i2c_remove,
170 	.priv_auto_alloc_size = sizeof(struct tpm_chip),
171 };
172