[U-Boot] [PATCH 06/25] tpm: Move the I2C TPM code into one file

christophe.ricard
2015-08-11T21:42:16Z

Hi Simon,

I would basically disagree with this one.
The code from tpm.c you are merging into tpm_tis_i2c may not only be
used by tpm_tis_i2c as it is using data from TPM standards (e.g: Trusted
computing group) that should be used by other TPM drivers.
You can find in chapter 17 how the table tpm_protected_ordinal_duration,
tpm_ordinal_duration were build.
(https://www.trustedcomputinggroup.org/files/resource_files/E14876A3-1A4B-B294-D086297A1ED38F96/mainP2Structrev103.pdf).

This come from a Linux port.

As a result, we can imagine tis_sendrecv as a generic function where
tpm_transmit manage the way tpm commands are sent following
specification giving the hand to drivers thanks to the
tpm_vendor_specific field {send,recv} for handling the communication
over a specified or proprietary transport protocol.
As an example in tpm_tis_lpc, a 1s command duration might be too short
or too long for some commands and might be really hard to debug in case
someone decide to had a new TPM command support in u-boot.
Also 1s might be enought for the current commands or for evaluated TPM
but it may require a longer duration for some other.
By reading the duration TPM capability, that will be just generic.

Also tpm_tis_i2c is Infineon specific and does not fit to any TCG
standard for TPM1.2, i would recommand to rename this driver
tpm_i2c_infineon to be inline with Linux naming and not confuse a future
user on what it support.

At the end from my delivery tentative, a Linux port as well, you may see
that i also rely on those functions. However I am not doing any check on
the command duration. This is to be improved...

May you prefer an approach that would not lead to duplicated code ?

Best Regards
Christophe
On 11/08/2015 16:47, Simon Glass wrote:
> The current Infineon I2C TPM driver is written in two parts, intended to
> support use with other I2C devices. However we don't have any users and the
> Atmel I2C TPM device does not use this file.
>
> We should simplify this and remove the unused abstration. As a first step,
> move the code into one file.
>
> Also the name tpm_private.h suggests that the header file is generic to all
> TPMs but it is not. Rename it indicate that it relates only to this driver
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
>
> drivers/tpm/Makefile | 2 -
> drivers/tpm/tpm.c | 594 ---------------------------
> drivers/tpm/tpm_tis_i2c.c | 548 +++++++++++++++++++++++-
> drivers/tpm/{tpm_private.h => tpm_tis_i2c.h} | 24 +-
> 4 files changed, 550 insertions(+), 618 deletions(-)
> delete mode 100644 drivers/tpm/tpm.c
> rename drivers/tpm/{tpm_private.h => tpm_tis_i2c.h} (73%)
>
> diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile
> index 150570e..597966c 100644
> --- a/drivers/tpm/Makefile
> +++ b/drivers/tpm/Makefile
> @@ -3,9 +3,7 @@
> # SPDX-License-Identifier: GPL-2.0+
> #
>
> -# TODO: Merge tpm_tis_lpc.c with tpm.c
> obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o
> -obj-$(CONFIG_TPM_TIS_I2C) += tpm.o
> obj-$(CONFIG_TPM_TIS_I2C) += tpm_tis_i2c.o
> obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o
> obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o
> diff --git a/drivers/tpm/tpm.c b/drivers/tpm/tpm.c
> deleted file mode 100644
> index 24997f6..0000000
> --- a/drivers/tpm/tpm.c
> +++ /dev/null
> @@ -1,594 +0,0 @@
> -/*
> - * Copyright (C) 2011 Infineon Technologies
> - *
> - * Authors:
> - * Peter Huewe <huewe.external@infineon.com>
> - *
> - * Description:
> - * Device driver for TCG/TCPA TPM (trusted platform module).
> - * Specifications at www.trustedcomputinggroup.org
> - *
> - * It is based on the Linux kernel driver tpm.c from Leendert van
> - * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall.
> - *
> - * Version: 2.1.1
> - *
> - * See file CREDITS for list of people who contributed to this
> - * project.
> - *
> - * This program is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU General Public License as
> - * published by the Free Software Foundation, version 2 of the
> - * License.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program; if not, write to the Free Software
> - * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> - * MA 02111-1307 USA
> - */
> -
> -#include <config.h>
> -#include <common.h>
> -#include <dm.h>
> -#include <linux/compiler.h>
> -#include <fdtdec.h>
> -#include <i2c.h>
> -#include <tpm.h>
> -#include <asm-generic/errno.h>
> -#include <linux/types.h>
> -#include <linux/unaligned/be_byteshift.h>
> -
> -#include "tpm_private.h"
> -
> -DECLARE_GLOBAL_DATA_PTR;
> -
> -/* TPM configuration */
> -struct tpm {
> - struct udevice *dev;
> - char inited;
> -} tpm;
> -
> -/* Global structure for tpm chip data */
> -static struct tpm_chip g_chip;
> -
> -enum tpm_duration {
> - TPM_SHORT = 0,
> - TPM_MEDIUM = 1,
> - TPM_LONG = 2,
> - TPM_UNDEFINED,
> -};
> -
> -/* Extended error numbers from linux (see errno.h) */
> -#define ECANCELED 125 /* Operation Canceled */
> -
> -/* Timer frequency. Corresponds to msec timer resolution*/
> -#define HZ 1000
> -
> -#define TPM_MAX_ORDINAL 243
> -#define TPM_MAX_PROTECTED_ORDINAL 12
> -#define TPM_PROTECTED_ORDINAL_MASK 0xFF
> -
> -#define TPM_CMD_COUNT_BYTE 2
> -#define TPM_CMD_ORDINAL_BYTE 6
> -
> -/*
> - * Array with one entry per ordinal defining the maximum amount
> - * of time the chip could take to return the result. The ordinal
> - * designation of short, medium or long is defined in a table in
> - * TCG Specification TPM Main Part 2 TPM Structures Section 17. The
> - * values of the SHORT, MEDIUM, and LONG durations are retrieved
> - * from the chip during initialization with a call to tpm_get_timeouts.
> - */
> -static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
> - TPM_UNDEFINED, /* 0 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED, /* 5 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_SHORT, /* 10 */
> - TPM_SHORT,
> -};
> -
> -static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
> - TPM_UNDEFINED, /* 0 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED, /* 5 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_SHORT, /* 10 */
> - TPM_SHORT,
> - TPM_MEDIUM,
> - TPM_LONG,
> - TPM_LONG,
> - TPM_MEDIUM, /* 15 */
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_MEDIUM,
> - TPM_LONG,
> - TPM_SHORT, /* 20 */
> - TPM_SHORT,
> - TPM_MEDIUM,
> - TPM_MEDIUM,
> - TPM_MEDIUM,
> - TPM_SHORT, /* 25 */
> - TPM_SHORT,
> - TPM_MEDIUM,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_MEDIUM, /* 30 */
> - TPM_LONG,
> - TPM_MEDIUM,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_SHORT, /* 35 */
> - TPM_MEDIUM,
> - TPM_MEDIUM,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_MEDIUM, /* 40 */
> - TPM_LONG,
> - TPM_MEDIUM,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_SHORT, /* 45 */
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_LONG,
> - TPM_MEDIUM, /* 50 */
> - TPM_MEDIUM,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED, /* 55 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_MEDIUM, /* 60 */
> - TPM_MEDIUM,
> - TPM_MEDIUM,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_MEDIUM, /* 65 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_SHORT, /* 70 */
> - TPM_SHORT,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED, /* 75 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_LONG, /* 80 */
> - TPM_UNDEFINED,
> - TPM_MEDIUM,
> - TPM_LONG,
> - TPM_SHORT,
> - TPM_UNDEFINED, /* 85 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_SHORT, /* 90 */
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_UNDEFINED, /* 95 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_MEDIUM, /* 100 */
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED, /* 105 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_SHORT, /* 110 */
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_SHORT, /* 115 */
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_LONG, /* 120 */
> - TPM_LONG,
> - TPM_MEDIUM,
> - TPM_UNDEFINED,
> - TPM_SHORT,
> - TPM_SHORT, /* 125 */
> - TPM_SHORT,
> - TPM_LONG,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_SHORT, /* 130 */
> - TPM_MEDIUM,
> - TPM_UNDEFINED,
> - TPM_SHORT,
> - TPM_MEDIUM,
> - TPM_UNDEFINED, /* 135 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_SHORT, /* 140 */
> - TPM_SHORT,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED, /* 145 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_SHORT, /* 150 */
> - TPM_MEDIUM,
> - TPM_MEDIUM,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_UNDEFINED, /* 155 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_SHORT, /* 160 */
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED, /* 165 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_LONG, /* 170 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED, /* 175 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_MEDIUM, /* 180 */
> - TPM_SHORT,
> - TPM_MEDIUM,
> - TPM_MEDIUM,
> - TPM_MEDIUM,
> - TPM_MEDIUM, /* 185 */
> - TPM_SHORT,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED, /* 190 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED, /* 195 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_SHORT, /* 200 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_SHORT,
> - TPM_SHORT, /* 205 */
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_MEDIUM, /* 210 */
> - TPM_UNDEFINED,
> - TPM_MEDIUM,
> - TPM_MEDIUM,
> - TPM_MEDIUM,
> - TPM_UNDEFINED, /* 215 */
> - TPM_MEDIUM,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_SHORT,
> - TPM_SHORT, /* 220 */
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_SHORT,
> - TPM_UNDEFINED, /* 225 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_SHORT, /* 230 */
> - TPM_LONG,
> - TPM_MEDIUM,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED, /* 235 */
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_UNDEFINED,
> - TPM_SHORT, /* 240 */
> - TPM_UNDEFINED,
> - TPM_MEDIUM,
> -};
> -
> -/* Returns max number of milliseconds to wait */
> -static unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
> - u32 ordinal)
> -{
> - int duration_idx = TPM_UNDEFINED;
> - int duration = 0;
> -
> - if (ordinal < TPM_MAX_ORDINAL) {
> - duration_idx = tpm_ordinal_duration[ordinal];
> - } else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
> - TPM_MAX_PROTECTED_ORDINAL) {
> - duration_idx = tpm_protected_ordinal_duration[
> - ordinal & TPM_PROTECTED_ORDINAL_MASK];
> - }
> -
> - if (duration_idx != TPM_UNDEFINED)
> - duration = chip->vendor.duration[duration_idx];
> -
> - if (duration <= 0)
> - return 2 * 60 * HZ; /* Two minutes timeout */
> - else
> - return duration;
> -}
> -
> -static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz)
> -{
> - int rc;
> - u32 count, ordinal;
> - unsigned long start, stop;
> -
> - struct tpm_chip *chip = &g_chip;
> -
> - /* switch endianess: big->little */
> - count = get_unaligned_be32(buf + TPM_CMD_COUNT_BYTE);
> - ordinal = get_unaligned_be32(buf + TPM_CMD_ORDINAL_BYTE);
> -
> - if (count == 0) {
> - error("no data\n");
> - return -ENODATA;
> - }
> - if (count > bufsiz) {
> - error("invalid count value %x %zx\n", count, bufsiz);
> - return -E2BIG;
> - }
> -
> - debug("Calling send\n");
> - rc = chip->vendor.send(chip, (u8 *)buf, count);
> - debug(" ... done calling send\n");
> - if (rc < 0) {
> - error("tpm_transmit: tpm_send: error %d\n", rc);
> - goto out;
> - }
> -
> - if (chip->vendor.irq)
> - goto out_recv;
> -
> - start = get_timer(0);
> - stop = tpm_calc_ordinal_duration(chip, ordinal);
> - do {
> - debug("waiting for status... %ld %ld\n", start, stop);
> - u8 status = chip->vendor.status(chip);
> - if ((status & chip->vendor.req_complete_mask) ==
> - chip->vendor.req_complete_val) {
> - debug("...got it;\n");
> - goto out_recv;
> - }
> -
> - if (status == chip->vendor.req_canceled) {
> - error("Operation Canceled\n");
> - rc = -ECANCELED;
> - goto out;
> - }
> - udelay(TPM_TIMEOUT * 1000);
> - } while (get_timer(start) < stop);
> -
> - chip->vendor.cancel(chip);
> - error("Operation Timed out\n");
> - rc = -ETIME;
> - goto out;
> -
> -out_recv:
> - debug("out_recv: reading response...\n");
> - rc = chip->vendor.recv(chip, (u8 *)buf, TPM_BUFSIZE);
> - if (rc < 0)
> - error("tpm_transmit: tpm_recv: error %d\n", rc);
> -
> -out:
> - return rc;
> -}
> -
> -static int tpm_open_dev(struct udevice *dev)
> -{
> - int rc;
> -
> - debug("%s: start\n", __func__);
> - if (g_chip.is_open)
> - return -EBUSY;
> - rc = tpm_vendor_init(dev);
> - if (rc < 0)
> - g_chip.is_open = 0;
> - return rc;
> -}
> -
> -static void tpm_close(void)
> -{
> - if (g_chip.is_open) {
> - tpm_vendor_cleanup(&g_chip);
> - g_chip.is_open = 0;
> - }
> -}
> -
> -/**
> - * Decode TPM configuration.
> - *
> - * @param dev Returns a configuration of TPM device
> - * @return 0 if ok, -1 on error
> - */
> -static int tpm_decode_config(struct tpm *dev)
> -{
> - const void *blob = gd->fdt_blob;
> - struct udevice *bus;
> - int chip_addr;
> - int parent;
> - int node;
> - int ret;
> -
> - node = fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM);
> - if (node < 0) {
> - node = fdtdec_next_compatible(blob, 0,
> - COMPAT_INFINEON_SLB9645_TPM);
> - }
> - if (node < 0) {
> - debug("%s: Node not found\n", __func__);
> - return -1;
> - }
> - parent = fdt_parent_offset(blob, node);
> - if (parent < 0) {
> - debug("%s: Cannot find node parent\n", __func__);
> - return -1;
> - }
> -
> - /*
> - * TODO(sjg at chromium.org): Remove this when driver model supports
> - * TPMs
> - */
> - ret = uclass_get_device_by_of_offset(UCLASS_I2C, parent, &bus);
> - if (ret) {
> - debug("Cannot find bus for node '%s: ret=%d'\n",
> - fdt_get_name(blob, parent, NULL), ret);
> - return ret;
> - }
> -
> - chip_addr = fdtdec_get_int(blob, node, "reg", -1);
> - if (chip_addr == -1) {
> - debug("Cannot find reg property for node '%s: ret=%d'\n",
> - fdt_get_name(blob, node, NULL), ret);
> - return ret;
> - }
> - /*
> - * TODO(sjg at chromium.org): Older TPMs will need to use the older method
> - * in iic_tpm_read() so the offset length needs to be 0 here.
> - */
> - ret = i2c_get_chip(bus, chip_addr, 1, &dev->dev);
> - if (ret) {
> - debug("Cannot find device for node '%s: ret=%d'\n",
> - fdt_get_name(blob, node, NULL), ret);
> - return ret;
> - }
> -
> - return 0;
> -}
> -
> -struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *entry)
> -{
> - struct tpm_chip *chip;
> -
> - /* Driver specific per-device data */
> - chip = &g_chip;
> - memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
> - chip->is_open = 1;
> -
> - return chip;
> -}
> -
> -int tis_init(void)
> -{
> - if (tpm.inited)
> - return 0;
> -
> - if (tpm_decode_config(&tpm))
> - return -1;
> -
> - debug("%s: done\n", __func__);
> -
> - tpm.inited = 1;
> -
> - return 0;
> -}
> -
> -int tis_open(void)
> -{
> - int rc;
> -
> - if (!tpm.inited)
> - return -1;
> -
> - rc = tpm_open_dev(tpm.dev);
> -
> - return rc;
> -}
> -
> -int tis_close(void)
> -{
> - if (!tpm.inited)
> - return -1;
> -
> - tpm_close();
> -
> - return 0;
> -}
> -
> -int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size,
> - uint8_t *recvbuf, size_t *rbuf_len)
> -{
> - int len;
> - uint8_t buf[4096];
> -
> - if (!tpm.inited)
> - return -1;
> -
> - if (sizeof(buf) < sbuf_size)
> - return -1;
> -
> - memcpy(buf, sendbuf, sbuf_size);
> -
> - len = tpm_transmit(buf, sbuf_size);
> -
> - if (len < 10) {
> - *rbuf_len = 0;
> - return -1;
> - }
> -
> - memcpy(recvbuf, buf, len);
> - *rbuf_len = len;
> -
> - return 0;
> -}
> diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c
> index a43e80d..2b3ce8c 100644
> --- a/drivers/tpm/tpm_tis_i2c.c
> +++ b/drivers/tpm/tpm_tis_i2c.c
> @@ -30,7 +30,7 @@
> #include <linux/types.h>
> #include <linux/unaligned/be_byteshift.h>
>
> -#include "tpm_private.h"
> +#include "tpm_tis_i2c.h"
>
> DECLARE_GLOBAL_DATA_PTR;
>
> @@ -95,6 +95,304 @@ static const char * const chip_name[] = {
> #define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4))
> #define TPM_DID_VID(l) (0x0006 | ((l) << 4))
>
> +enum tpm_duration {
> + TPM_SHORT = 0,
> + TPM_MEDIUM = 1,
> + TPM_LONG = 2,
> + TPM_UNDEFINED,
> +};
> +
> +/* Extended error numbers from linux (see errno.h) */
> +#define ECANCELED 125 /* Operation Canceled */
> +
> +/* Timer frequency. Corresponds to msec timer resolution*/
> +#define HZ 1000
> +
> +#define TPM_MAX_ORDINAL 243
> +#define TPM_MAX_PROTECTED_ORDINAL 12
> +#define TPM_PROTECTED_ORDINAL_MASK 0xFF
> +
> +#define TPM_CMD_COUNT_BYTE 2
> +#define TPM_CMD_ORDINAL_BYTE 6
> +
> +/*
> + * Array with one entry per ordinal defining the maximum amount
> + * of time the chip could take to return the result. The ordinal
> + * designation of short, medium or long is defined in a table in
> + * TCG Specification TPM Main Part 2 TPM Structures Section 17. The
> + * values of the SHORT, MEDIUM, and LONG durations are retrieved
> + * from the chip during initialization with a call to tpm_get_timeouts.
> + */
> +static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
> + TPM_UNDEFINED, /* 0 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED, /* 5 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_SHORT, /* 10 */
> + TPM_SHORT,
> +};
> +
> +static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
> + TPM_UNDEFINED, /* 0 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED, /* 5 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_SHORT, /* 10 */
> + TPM_SHORT,
> + TPM_MEDIUM,
> + TPM_LONG,
> + TPM_LONG,
> + TPM_MEDIUM, /* 15 */
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_MEDIUM,
> + TPM_LONG,
> + TPM_SHORT, /* 20 */
> + TPM_SHORT,
> + TPM_MEDIUM,
> + TPM_MEDIUM,
> + TPM_MEDIUM,
> + TPM_SHORT, /* 25 */
> + TPM_SHORT,
> + TPM_MEDIUM,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_MEDIUM, /* 30 */
> + TPM_LONG,
> + TPM_MEDIUM,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_SHORT, /* 35 */
> + TPM_MEDIUM,
> + TPM_MEDIUM,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_MEDIUM, /* 40 */
> + TPM_LONG,
> + TPM_MEDIUM,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_SHORT, /* 45 */
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_LONG,
> + TPM_MEDIUM, /* 50 */
> + TPM_MEDIUM,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED, /* 55 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_MEDIUM, /* 60 */
> + TPM_MEDIUM,
> + TPM_MEDIUM,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_MEDIUM, /* 65 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_SHORT, /* 70 */
> + TPM_SHORT,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED, /* 75 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_LONG, /* 80 */
> + TPM_UNDEFINED,
> + TPM_MEDIUM,
> + TPM_LONG,
> + TPM_SHORT,
> + TPM_UNDEFINED, /* 85 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_SHORT, /* 90 */
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_UNDEFINED, /* 95 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_MEDIUM, /* 100 */
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED, /* 105 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_SHORT, /* 110 */
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_SHORT, /* 115 */
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_LONG, /* 120 */
> + TPM_LONG,
> + TPM_MEDIUM,
> + TPM_UNDEFINED,
> + TPM_SHORT,
> + TPM_SHORT, /* 125 */
> + TPM_SHORT,
> + TPM_LONG,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_SHORT, /* 130 */
> + TPM_MEDIUM,
> + TPM_UNDEFINED,
> + TPM_SHORT,
> + TPM_MEDIUM,
> + TPM_UNDEFINED, /* 135 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_SHORT, /* 140 */
> + TPM_SHORT,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED, /* 145 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_SHORT, /* 150 */
> + TPM_MEDIUM,
> + TPM_MEDIUM,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_UNDEFINED, /* 155 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_SHORT, /* 160 */
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED, /* 165 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_LONG, /* 170 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED, /* 175 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_MEDIUM, /* 180 */
> + TPM_SHORT,
> + TPM_MEDIUM,
> + TPM_MEDIUM,
> + TPM_MEDIUM,
> + TPM_MEDIUM, /* 185 */
> + TPM_SHORT,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED, /* 190 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED, /* 195 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_SHORT, /* 200 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_SHORT,
> + TPM_SHORT, /* 205 */
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_MEDIUM, /* 210 */
> + TPM_UNDEFINED,
> + TPM_MEDIUM,
> + TPM_MEDIUM,
> + TPM_MEDIUM,
> + TPM_UNDEFINED, /* 215 */
> + TPM_MEDIUM,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_SHORT,
> + TPM_SHORT, /* 220 */
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_SHORT,
> + TPM_UNDEFINED, /* 225 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_SHORT, /* 230 */
> + TPM_LONG,
> + TPM_MEDIUM,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED, /* 235 */
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_UNDEFINED,
> + TPM_SHORT, /* 240 */
> + TPM_UNDEFINED,
> + TPM_MEDIUM,
> +};
> +
> +/* TPM configuration */
> +struct tpm {
> + struct udevice *dev;
> + char inited;
> +} tpm;
> +
> +/* Global structure for tpm chip data */
> +static struct tpm_chip g_chip;
> +
> /* Structure to store I2C TPM specific stuff */
> struct tpm_dev {
> struct udevice *dev;
> @@ -595,3 +893,251 @@ void tpm_vendor_cleanup(struct tpm_chip *chip)
> {
> release_locality(chip, chip->vendor.locality, 1);
> }
> +
> +/* Returns max number of milliseconds to wait */
> +static unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
> + u32 ordinal)
> +{
> + int duration_idx = TPM_UNDEFINED;
> + int duration = 0;
> +
> + if (ordinal < TPM_MAX_ORDINAL) {
> + duration_idx = tpm_ordinal_duration[ordinal];
> + } else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
> + TPM_MAX_PROTECTED_ORDINAL) {
> + duration_idx = tpm_protected_ordinal_duration[
> + ordinal & TPM_PROTECTED_ORDINAL_MASK];
> + }
> +
> + if (duration_idx != TPM_UNDEFINED)
> + duration = chip->vendor.duration[duration_idx];
> +
> + if (duration <= 0)
> + return 2 * 60 * HZ; /* Two minutes timeout */
> + else
> + return duration;
> +}
> +
> +static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz)
> +{
> + int rc;
> + u32 count, ordinal;
> + unsigned long start, stop;
> +
> + struct tpm_chip *chip = &g_chip;
> +
> + /* switch endianess: big->little */
> + count = get_unaligned_be32(buf + TPM_CMD_COUNT_BYTE);
> + ordinal = get_unaligned_be32(buf + TPM_CMD_ORDINAL_BYTE);
> +
> + if (count == 0) {
> + error("no data\n");
> + return -ENODATA;
> + }
> + if (count > bufsiz) {
> + error("invalid count value %x %zx\n", count, bufsiz);
> + return -E2BIG;
> + }
> +
> + debug("Calling send\n");
> + rc = chip->vendor.send(chip, (u8 *)buf, count);
> + debug(" ... done calling send\n");
> + if (rc < 0) {
> + error("tpm_transmit: tpm_send: error %d\n", rc);
> + goto out;
> + }
> +
> + if (chip->vendor.irq)
> + goto out_recv;
> +
> + start = get_timer(0);
> + stop = tpm_calc_ordinal_duration(chip, ordinal);
> + do {
> + debug("waiting for status... %ld %ld\n", start, stop);
> + u8 status = chip->vendor.status(chip);
> + if ((status & chip->vendor.req_complete_mask) ==
> + chip->vendor.req_complete_val) {
> + debug("...got it;\n");
> + goto out_recv;
> + }
> +
> + if (status == chip->vendor.req_canceled) {
> + error("Operation Canceled\n");
> + rc = -ECANCELED;
> + goto out;
> + }
> + udelay(TPM_TIMEOUT * 1000);
> + } while (get_timer(start) < stop);
> +
> + chip->vendor.cancel(chip);
> + error("Operation Timed out\n");
> + rc = -ETIME;
> + goto out;
> +
> +out_recv:
> + debug("out_recv: reading response...\n");
> + rc = chip->vendor.recv(chip, (u8 *)buf, TPM_BUFSIZE);
> + if (rc < 0)
> + error("tpm_transmit: tpm_recv: error %d\n", rc);
> +
> +out:
> + return rc;
> +}
> +
> +static int tpm_open_dev(struct udevice *dev)
> +{
> + int rc;
> +
> + debug("%s: start\n", __func__);
> + if (g_chip.is_open)
> + return -EBUSY;
> + rc = tpm_vendor_init(dev);
> + if (rc < 0)
> + g_chip.is_open = 0;
> + return rc;
> +}
> +
> +static void tpm_close(void)
> +{
> + if (g_chip.is_open) {
> + tpm_vendor_cleanup(&g_chip);
> + g_chip.is_open = 0;
> + }
> +}
> +
> +/**
> + * Decode TPM configuration.
> + *
> + * @param dev Returns a configuration of TPM device
> + * @return 0 if ok, -1 on error
> + */
> +static int tpm_decode_config(struct tpm *dev)
> +{
> + const void *blob = gd->fdt_blob;
> + struct udevice *bus;
> + int chip_addr;
> + int parent;
> + int node;
> + int ret;
> +
> + node = fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM);
> + if (node < 0) {
> + node = fdtdec_next_compatible(blob, 0,
> + COMPAT_INFINEON_SLB9645_TPM);
> + }
> + if (node < 0) {
> + debug("%s: Node not found\n", __func__);
> + return -1;
> + }
> + parent = fdt_parent_offset(blob, node);
> + if (parent < 0) {
> + debug("%s: Cannot find node parent\n", __func__);
> + return -1;
> + }
> +
> + /*
> + * TODO(sjg at chromium.org): Remove this when driver model supports
> + * TPMs
> + */
> + ret = uclass_get_device_by_of_offset(UCLASS_I2C, parent, &bus);
> + if (ret) {
> + debug("Cannot find bus for node '%s: ret=%d'\n",
> + fdt_get_name(blob, parent, NULL), ret);
> + return ret;
> + }
> +
> + chip_addr = fdtdec_get_int(blob, node, "reg", -1);
> + if (chip_addr == -1) {
> + debug("Cannot find reg property for node '%s: ret=%d'\n",
> + fdt_get_name(blob, node, NULL), ret);
> + return ret;
> + }
> + /*
> + * TODO(sjg at chromium.org): Older TPMs will need to use the older method
> + * in iic_tpm_read() so the offset length needs to be 0 here.
> + */
> + ret = i2c_get_chip(bus, chip_addr, 1, &dev->dev);
> + if (ret) {
> + debug("Cannot find device for node '%s: ret=%d'\n",
> + fdt_get_name(blob, node, NULL), ret);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *entry)
> +{
> + struct tpm_chip *chip;
> +
> + /* Driver specific per-device data */
> + chip = &g_chip;
> + memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
> + chip->is_open = 1;
> +
> + return chip;
> +}
> +
> +int tis_init(void)
> +{
> + if (tpm.inited)
> + return 0;
> +
> + if (tpm_decode_config(&tpm))
> + return -1;
> +
> + debug("%s: done\n", __func__);
> +
> + tpm.inited = 1;
> +
> + return 0;
> +}
> +
> +int tis_open(void)
> +{
> + int rc;
> +
> + if (!tpm.inited)
> + return -1;
> +
> + rc = tpm_open_dev(tpm.dev);
> +
> + return rc;
> +}
> +
> +int tis_close(void)
> +{
> + if (!tpm.inited)
> + return -1;
> +
> + tpm_close();
> +
> + return 0;
> +}
> +
> +int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size,
> + uint8_t *recvbuf, size_t *rbuf_len)
> +{
> + int len;
> + uint8_t buf[4096];
> +
> + if (!tpm.inited)
> + return -1;
> +
> + if (sizeof(buf) < sbuf_size)
> + return -1;
> +
> + memcpy(buf, sendbuf, sbuf_size);
> +
> + len = tpm_transmit(buf, sbuf_size);
> +
> + if (len < 10) {
> + *rbuf_len = 0;
> + return -1;
> + }
> +
> + memcpy(recvbuf, buf, len);
> + *rbuf_len = len;
> +
> + return 0;
> +}
> diff --git a/drivers/tpm/tpm_private.h b/drivers/tpm/tpm_tis_i2c.h
> similarity index 73%
> rename from drivers/tpm/tpm_private.h
> rename to drivers/tpm/tpm_tis_i2c.h
> index daaf8b8..75fa829 100644
> --- a/drivers/tpm/tpm_private.h
> +++ b/drivers/tpm/tpm_tis_i2c.h
> @@ -13,28 +13,11 @@
> * It is based on the Linux kernel driver tpm.c from Leendert van
> * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall.
> *
> - *
> - * See file CREDITS for list of people who contributed to this
> - * project.
> - *
> - * This program is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU General Public License as
> - * published by the Free Software Foundation, version 2 of the
> - * License.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program; if not, write to the Free Software
> - * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> - * MA 02111-1307 USA
> + * SPDX-License-Identifier: GPL-2.0
> */
>
> -#ifndef _TPM_PRIVATE_H_
> -#define _TPM_PRIVATE_H_
> +#ifndef _TPM_TIS_I2C_H
> +#define _TPM_TIS_I2C_H
>
> #include <linux/compiler.h>
> #include <linux/types.h>
> @@ -134,5 +117,4 @@ int tpm_vendor_init(struct udevice *dev);
>
> void tpm_vendor_cleanup(struct tpm_chip *chip);
>
> -
> #endif