]> git.sur5r.net Git - u-boot/blob - drivers/tpm/tpm-uclass.c
serial: uniphier: rename struct uniphier_serial_private_data
[u-boot] / drivers / tpm / tpm-uclass.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2015 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <linux/unaligned/be_byteshift.h>
10 #if defined(CONFIG_TPM_V1)
11 #include <tpm-v1.h>
12 #elif defined(CONFIG_TPM_V2)
13 #include <tpm-v2.h>
14 #endif
15 #include "tpm_internal.h"
16
17 int tpm_open(struct udevice *dev)
18 {
19         struct tpm_ops *ops = tpm_get_ops(dev);
20
21         if (!ops->open)
22                 return -ENOSYS;
23
24         return ops->open(dev);
25 }
26
27 int tpm_close(struct udevice *dev)
28 {
29         struct tpm_ops *ops = tpm_get_ops(dev);
30
31         if (!ops->close)
32                 return -ENOSYS;
33
34         return ops->close(dev);
35 }
36
37 int tpm_get_desc(struct udevice *dev, char *buf, int size)
38 {
39         struct tpm_ops *ops = tpm_get_ops(dev);
40
41         if (!ops->get_desc)
42                 return -ENOSYS;
43
44         return ops->get_desc(dev, buf, size);
45 }
46
47 /* Returns max number of milliseconds to wait */
48 static ulong tpm_tis_i2c_calc_ordinal_duration(struct tpm_chip_priv *priv,
49                                                u32 ordinal)
50 {
51         int duration_idx = TPM_UNDEFINED;
52         int duration = 0;
53
54         if (ordinal < TPM_MAX_ORDINAL) {
55                 duration_idx = tpm_ordinal_duration[ordinal];
56         } else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
57                         TPM_MAX_PROTECTED_ORDINAL) {
58                 duration_idx = tpm_protected_ordinal_duration[
59                                 ordinal & TPM_PROTECTED_ORDINAL_MASK];
60         }
61
62         if (duration_idx != TPM_UNDEFINED)
63                 duration = priv->duration_ms[duration_idx];
64
65         if (duration <= 0)
66                 return 2 * 60 * 1000; /* Two minutes timeout */
67         else
68                 return duration;
69 }
70
71 int tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, size_t send_size,
72         uint8_t *recvbuf, size_t *recv_size)
73 {
74         struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
75         struct tpm_ops *ops = tpm_get_ops(dev);
76         ulong start, stop;
77         uint count, ordinal;
78         int ret, ret2;
79
80         if (ops->xfer)
81                 return ops->xfer(dev, sendbuf, send_size, recvbuf, recv_size);
82
83         if (!ops->send || !ops->recv)
84                 return -ENOSYS;
85
86         /* switch endianess: big->little */
87         count = get_unaligned_be32(sendbuf + TPM_CMD_COUNT_BYTE);
88         ordinal = get_unaligned_be32(sendbuf + TPM_CMD_ORDINAL_BYTE);
89
90         if (count == 0) {
91                 debug("no data\n");
92                 return -ENODATA;
93         }
94         if (count > send_size) {
95                 debug("invalid count value %x %zx\n", count, send_size);
96                 return -E2BIG;
97         }
98
99         debug("%s: Calling send\n", __func__);
100         ret = ops->send(dev, sendbuf, send_size);
101         if (ret < 0)
102                 return ret;
103
104         start = get_timer(0);
105         stop = tpm_tis_i2c_calc_ordinal_duration(priv, ordinal);
106         do {
107                 ret = ops->recv(dev, priv->buf, sizeof(priv->buf));
108                 if (ret >= 0) {
109                         if (ret > *recv_size)
110                                 return -ENOSPC;
111                         memcpy(recvbuf, priv->buf, ret);
112                         *recv_size = ret;
113                         ret = 0;
114                         break;
115                 } else if (ret != -EAGAIN) {
116                         return ret;
117                 }
118
119                 mdelay(priv->retry_time_ms);
120                 if (get_timer(start) > stop) {
121                         ret = -ETIMEDOUT;
122                         break;
123                 }
124         } while (ret);
125
126         ret2 = ops->cleanup ? ops->cleanup(dev) : 0;
127
128         return ret2 ? ret2 : ret;
129 }
130
131 UCLASS_DRIVER(tpm) = {
132         .id             = UCLASS_TPM,
133         .name           = "tpm",
134         .flags          = DM_UC_FLAG_SEQ_ALIAS,
135         .per_device_auto_alloc_size     = sizeof(struct tpm_chip_priv),
136 };