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