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