blob: 99d1cf218dafc2fdc8e97b2841a3dbe6e7bf0510 [file] [log] [blame]
Eddie James805f7d82022-05-13 13:30:00 -05001// 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
23struct tpm_tis_chip_data {
24 unsigned int pcr_count;
25 unsigned int pcr_select_min;
26};
27
28static 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
48static 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
62static 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
77static 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
89static 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
96static 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
103static 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
132static int tpm_tis_i2c_remove(struct udevice *udev)
133{
134 return tpm_tis_cleanup(udev);
135}
136
137static 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
146static const struct tpm_tis_chip_data tpm_tis_std_chip_data = {
147 .pcr_count = 24,
148 .pcr_select_min = 3,
149};
150
151static 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
163U_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 = sizeof(struct tpm_chip),
171};