From patchwork Fri Jul 2 12:52:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilias Apalodimas X-Patchwork-Id: 469524 Delivered-To: patch@linaro.org Received: by 2002:a02:c94a:0:0:0:0:0 with SMTP id u10csp1354052jao; Fri, 2 Jul 2021 05:52:46 -0700 (PDT) X-Google-Smtp-Source: ABdhPJw+b0jm+g4Cqmi8J3tuGxyGioKDGgXUwYUo0QvrCXbuDPLB8Srh/aAEUsQX5/yvu4ibudbF X-Received: by 2002:a05:6402:2813:: with SMTP id h19mr6510560ede.39.1625230366025; Fri, 02 Jul 2021 05:52:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1625230366; cv=none; d=google.com; s=arc-20160816; b=i7bV75EgtFmhrno4egrakjLRG1b4Gk0C2quUfkce+0oLqcE3HImGwtQ20/pGLPsRak bDNnTeQVEy0o+cdBPG+yjhhP5j3rXjBi9DQ2Czy2JMvG0hwisQNBWHGxQ5ZsU8Nflw5U ffwLmgwCpFkmg7HBhI1dx3RRVmq668vwX7jZTI6gqOcrEVzZ8UDneIc2lmqV8WI4ZZDT NRCtkpsUIXC9Vg3HoKvq5Y0EecOU3FdkT+46JTwXrrEd8xk0Nmf8KJXk+2fCumMeogRE 2m/9PwzjI0l9nDXL3Gw3faI89QGf33I55pWPLgfzU2UkV6r+xDYtDB7XC7vhp5AXx0pZ Rxtg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:message-id:date:subject:cc:to:from:dkim-signature; bh=cQxNObImswgwXR9mlN4d7YZwIgIDVSrLlPG82jz74KU=; b=OQh5Gz3/QLFfKH2mvSDcstCqMwjd84TEwvvLHm/X8UwDefxw5HY/3vGn57oVvu2YPR eOqZyGnrAsSEWZWGiuq1W3CtZAp1oZPKjLf8rLj0X4shciDRA5rpaDkECEZ7BZ3tIuqo lYLKdCNRwSCdiric6e86yoKHsRFUaZ8KczgHO+WxcVxbgFibTjewaxhhIKB2mg/iobGu WLgG+XokXWU6A0277KdYijmf9427cmxzGhyMbAf/YFgiUmz4gXhPNjdHarNMEHTQ1XAv CbcZ8O0gJ/Jr8E6DYH6w0fdPzZ2WB/c4ikh+nxftrGKon5oHkhJaI45dU2ncQBERgr1m ZR5A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=db69Ob+x; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [85.214.62.61]) by mx.google.com with ESMTPS id x4si3089294edd.296.2021.07.02.05.52.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Jul 2021 05:52:46 -0700 (PDT) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) client-ip=85.214.62.61; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=db69Ob+x; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id B8FDE81E14; Fri, 2 Jul 2021 14:52:43 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="db69Ob+x"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 8682E81ED0; Fri, 2 Jul 2021 14:52:42 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,SPF_HELO_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-wm1-x335.google.com (mail-wm1-x335.google.com [IPv6:2a00:1450:4864:20::335]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id F2869814A4 for ; Fri, 2 Jul 2021 14:52:38 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=ilias.apalodimas@linaro.org Received: by mail-wm1-x335.google.com with SMTP id k16-20020a05600c1c90b02901f4ed0fcfe7so5192884wms.5 for ; Fri, 02 Jul 2021 05:52:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=cQxNObImswgwXR9mlN4d7YZwIgIDVSrLlPG82jz74KU=; b=db69Ob+xfKAGFzLeADgGCjA9AmL0a6YsykO+boqD+Yxt1usGnNmQ2dD78MjUjhTaln 9Zh5InafCibH2tKD0mzL57yrv/fR13bEAPfgRQn9sGlqRuDBOmnewL7eUShHuQVLTgEk n2Ds5ezWZ1Hlik1LyrL15sK1m0HHeZbPgjrJCRKgHqU44D6EcqBngxJpOIU2/KoBoktQ REBnUDWNdrKdhenmNylFOYQPwwWEdT7FXhIOEzQ3pfQsItwD/JKnsLdHsm8vQyV6aVEd 8Giyth5LZH0taVyIpWNIlgvooOPxY3QdPilcweBWQe/8WYQcQezi2LlhHBKwCDeCsg7e C+7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=cQxNObImswgwXR9mlN4d7YZwIgIDVSrLlPG82jz74KU=; b=cloh3nP0c/MJelTsvNFFfcdfutgEk8D/FVls7VTmw1azBmM9qSHhKOCbLYazDNFqm4 Y64DztiW4JY+PAFofRMbyA+ldXdsCmr5faNwFfY+xxmaXcIJuZPl17RzBsRfzvI71LzW QR02slzAG1EGXJ2wKxnOMDYNYFkrqatFSNNeGjUyKHFnUfHUzsb9YNNyn96jhE+vE3d2 GixyycOl6/MFlUpTiOXWgedP8DZ11Gin9H8bcuEmui63jyqvpTKvb/to1qUjUZ+lSZze I90wrh7viMCf5jIVdiUIoEe/OSOaXnD+ErEs9MJY8C5axjlak/5lHRD+8PtXZQtoC7UH jJ2g== X-Gm-Message-State: AOAM532iyIXlJwpI5Vyz77MikRihCTLxun/fja6Y3H1r03zMkeRyfcDc ZvJPJpx1cZyySINbljvCEJyLPw== X-Received: by 2002:a05:600c:4ec6:: with SMTP id g6mr16926991wmq.0.1625230358487; Fri, 02 Jul 2021 05:52:38 -0700 (PDT) Received: from localhost.localdomain (ppp-94-66-242-227.home.otenet.gr. [94.66.242.227]) by smtp.gmail.com with ESMTPSA id c10sm2863657wmb.40.2021.07.02.05.52.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Jul 2021 05:52:38 -0700 (PDT) From: Ilias Apalodimas To: xypron.glpk@gmx.de Cc: Ilias Apalodimas , Simon Glass , Johannes Holland , Dhananjay Phadke , u-boot@lists.denx.de Subject: [PATCH 1/1] tpm2: Add a TPMv2 MMIO TIS driver Date: Fri, 2 Jul 2021 15:52:31 +0300 Message-Id: <20210702125234.19145-1-ilias.apalodimas@linaro.org> X-Mailer: git-send-email 2.32.0.rc0 MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean Add a TPMv2 TIS MMIO compatible driver. This useful for a couple of reasons. First of all we can support a TPMv2 on devices that have this hardware (e.g the newly added SynQuacer box). We can also use the driver in our QEMU setups and test the EFI TCG2 protocol, which cannot be tested with our sandbox. Ideally we should create an abstraction for all TIS compatible TPMs we support. Let's plug in the mmio driver first. Signed-off-by: Ilias Apalodimas --- drivers/tpm/Kconfig | 9 + drivers/tpm/Makefile | 1 + drivers/tpm/tpm2_tis_mmio.c | 516 ++++++++++++++++++++++++++++++++++++ drivers/tpm/tpm_tis.h | 8 + include/tpm-v2.h | 1 + 5 files changed, 535 insertions(+) create mode 100644 drivers/tpm/tpm2_tis_mmio.c -- 2.32.0.rc0 diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig index 9eebab5cfd90..406ee8716e1e 100644 --- a/drivers/tpm/Kconfig +++ b/drivers/tpm/Kconfig @@ -161,6 +161,15 @@ config TPM2_FTPM_TEE help This driver supports firmware TPM running in TEE. +config TPM2_MMIO + bool "MMIO based TPM2 Interface" + depends on TPM_V2 + help + This driver supports firmware TPM2.0 MMIO interface. + The usual TPM operations and the 'tpm' command can be used to talk + to the device using the standard TPM Interface Specification (TIS) + protocol. + endif # TPM_V2 endmenu diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile index f64d20067f88..42fca3315bff 100644 --- a/drivers/tpm/Makefile +++ b/drivers/tpm/Makefile @@ -14,3 +14,4 @@ obj-$(CONFIG_$(SPL_TPL_)TPM2_CR50_I2C) += cr50_i2c.o obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o obj-$(CONFIG_TPM2_TIS_SPI) += tpm2_tis_spi.o obj-$(CONFIG_TPM2_FTPM_TEE) += tpm2_ftpm_tee.o +obj-$(CONFIG_TPM2_MMIO) += tpm2_tis_mmio.o diff --git a/drivers/tpm/tpm2_tis_mmio.c b/drivers/tpm/tpm2_tis_mmio.c new file mode 100644 index 000000000000..422af4ff0b51 --- /dev/null +++ b/drivers/tpm/tpm2_tis_mmio.c @@ -0,0 +1,516 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * swtpm driver for TCG/TIS TPM (trusted platform module). + * Specifications at www.trustedcomputinggroup.org + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tpm_tis.h" +#include "tpm_internal.h" + +enum tis_int_flags { + TPM_GLOBAL_INT_ENABLE = 0x80000000, + TPM_INTF_BURST_COUNT_STATIC = 0x100, + TPM_INTF_CMD_READY_INT = 0x080, + TPM_INTF_INT_EDGE_FALLING = 0x040, + TPM_INTF_INT_EDGE_RISING = 0x020, + TPM_INTF_INT_LEVEL_LOW = 0x010, + TPM_INTF_INT_LEVEL_HIGH = 0x008, + TPM_INTF_LOCALITY_CHANGE_INT = 0x004, + TPM_INTF_STS_VALID_INT = 0x002, + TPM_INTF_DATA_AVAIL_INT = 0x001, +}; + +struct tpm_tis_chip_data { + unsigned int pcr_count; + unsigned int pcr_select_min; + unsigned int time_before_first_cmd_ms; + void __iomem *iobase; +}; + +static int tpm_tis_read_bytes(struct udevice *udev, u32 addr, u16 len, + u8 *result) +{ + struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(udev); + + while (len--) + *result++ = ioread8(drv_data->iobase + addr); + return 0; +} + +static int tpm_tis_write_bytes(struct udevice *udev, u32 addr, u16 len, + const u8 *value) +{ + struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(udev); + + while (len--) + iowrite8(*value++, drv_data->iobase + addr); + return 0; +} + +static __maybe_unused int tpm_tis_read16(struct udevice *udev, u32 addr, + u16 *result) +{ + struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(udev); + + *result = ioread16(drv_data->iobase + addr); + return 0; +} + +static int tpm_tis_read32(struct udevice *udev, u32 addr, u32 *result) +{ + struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(udev); + + *result = ioread32(drv_data->iobase + addr); + return 0; +} + +static int tpm_tis_write32(struct udevice *udev, u32 addr, u32 value) +{ + struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(udev); + + iowrite32(value, drv_data->iobase + addr); + return 0; +} + +static int tpm_tis_get_desc(struct udevice *udev, char *buf, int size) +{ + struct tpm_chip *chip = dev_get_priv(udev); + + if (size < 80) + return -ENOSPC; + + return snprintf(buf, size, + "%s v2.0: VendorID 0x%04x, DeviceID 0x%04x, RevisionID 0x%02x [%s]", + udev->name, chip->vend_dev & 0xFFFF, + chip->vend_dev >> 16, chip->rid, + (chip->is_open ? "open" : "closed")); +} + +static bool tpm_tis_check_locality(struct udevice *udev, int loc) +{ + struct tpm_chip *chip = dev_get_priv(udev); + u8 locality; + + tpm_tis_read_bytes(udev, TPM_ACCESS(loc), 1, &locality); + if ((locality & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID | + TPM_ACCESS_REQUEST_USE)) == + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) { + chip->locality = loc; + return true; + } + + return false; +} + +static int tpm_tis_request_locality(struct udevice *udev, int loc) +{ + struct tpm_chip *chip = dev_get_priv(udev); + u8 buf = TPM_ACCESS_REQUEST_USE; + unsigned long start, stop; + + if (tpm_tis_check_locality(udev, loc)) + return 0; + + tpm_tis_write_bytes(udev, TPM_ACCESS(loc), 1, &buf); + start = get_timer(0); + stop = chip->timeout_a; + do { + if (tpm_tis_check_locality(udev, loc)) + return 0; + mdelay(TPM_TIMEOUT_MS); + } while (get_timer(start) < stop); + + return -1; +} + +static int tpm_tis_status(struct udevice *udev, u8 *status) +{ + struct tpm_chip *chip = dev_get_priv(udev); + + if (chip->locality < 0) + return -EINVAL; + + tpm_tis_read_bytes(udev, TPM_STS(chip->locality), 1, status); + + if ((*status & TPM_STS_READ_ZERO)) { + log_err("TPM returned invalid status\n"); + return -EINVAL; + } + + return 0; +} + +static int tpm_tis_release_locality(struct udevice *udev, int loc) +{ + struct tpm_chip *chip = dev_get_priv(udev); + u8 buf = TPM_ACCESS_ACTIVE_LOCALITY; + int ret; + + if (chip->locality < 0) + return 0; + + ret = tpm_tis_write_bytes(udev, TPM_ACCESS(loc), 1, &buf); + chip->locality = -1; + + return ret; +} + +static int tpm_tis_wait_for_stat(struct udevice *udev, u8 mask, + unsigned long timeout, u8 *status) +{ + unsigned long start = get_timer(0); + unsigned long stop = timeout; + int ret; + + do { + mdelay(TPM_TIMEOUT_MS); + ret = tpm_tis_status(udev, status); + if (ret) + return ret; + + if ((*status & mask) == mask) + return 0; + } while (get_timer(start) < stop); + + return -ETIMEDOUT; +} + +static int tpm_tis_get_burstcount(struct udevice *udev, size_t *burstcount) +{ + struct tpm_chip *chip = dev_get_priv(udev); + unsigned long start, stop; + u32 burst; + + if (chip->locality < 0) + return -EINVAL; + + /* wait for burstcount */ + start = get_timer(0); + /* + * This is the TPMv2 defined timeout. Change this in case you want to + * make the driver compatile to TPMv1 + */ + stop = chip->timeout_a; + do { + tpm_tis_read32(udev, TPM_STS(chip->locality), &burst); + *burstcount = (burst >> 8) & 0xFFFF; + if (*burstcount) + return 0; + + mdelay(TPM_TIMEOUT_MS); + } while (get_timer(start) < stop); + + return -ETIMEDOUT; +} + +static int tpm_tis_ready(struct udevice *udev) +{ + struct tpm_chip *chip = dev_get_priv(udev); + u8 data = TPM_STS_COMMAND_READY; + + /* This will cancel any pending commands */ + return tpm_tis_write_bytes(udev, TPM_STS(chip->locality), 1, &data); +} + +static int tpm_tis_send(struct udevice *udev, const u8 *buf, size_t len) +{ + struct tpm_chip *chip = dev_get_priv(udev); + size_t burstcnt, wr_size, sent = 0; + u8 data = TPM_STS_GO; + u8 status; + int ret; + + if (!chip) + return -ENODEV; + + ret = tpm_tis_request_locality(udev, 0); + if (ret < 0) + return -EBUSY; + + ret = tpm_tis_status(udev, &status); + if (ret) + goto release_locality; + + if (!(status & TPM_STS_COMMAND_READY)) { + ret = tpm_tis_ready(udev); + if (ret) { + log_err("Can't cancel previous TPM operation\n"); + goto release_locality; + } + ret = tpm_tis_wait_for_stat(udev, TPM_STS_COMMAND_READY, + chip->timeout_b, &status); + if (ret) { + log_err("TPM not ready\n"); + goto release_locality; + } + } + + while (len > 0) { + ret = tpm_tis_get_burstcount(udev, &burstcnt); + if (ret) + goto release_locality; + + wr_size = min(len, burstcnt); + ret = tpm_tis_write_bytes(udev, TPM_DATA_FIFO(chip->locality), + wr_size, buf + sent); + if (ret < 0) + goto release_locality; + + ret = tpm_tis_wait_for_stat(udev, TPM_STS_VALID, + chip->timeout_c, &status); + if (ret) + goto release_locality; + + sent += wr_size; + len -= wr_size; + /* make sure the TPM expects more data */ + if (len && !(status & TPM_STS_DATA_EXPECT)) { + ret = -EIO; + goto release_locality; + } + } + + /* + * Make a final check ensuring everything is ok and the TPM expects no + * more data + */ + ret = tpm_tis_wait_for_stat(udev, TPM_STS_VALID, chip->timeout_c, + &status); + if (ret) + goto release_locality; + + if (status & TPM_STS_DATA_EXPECT) { + ret = -EIO; + goto release_locality; + } + + ret = tpm_tis_write_bytes(udev, TPM_STS(chip->locality), 1, &data); + if (ret) + goto release_locality; + + tpm_tis_release_locality(udev, chip->locality); + return sent; + +release_locality: + tpm_tis_ready(udev); + tpm_tis_release_locality(udev, chip->locality); + + return ret; +} + +static int tpm_tis_recv_data(struct udevice *udev, u8 *buf, size_t count) +{ + struct tpm_chip *chip = dev_get_priv(udev); + int size = 0, len, ret; + size_t burstcnt; + u8 status; + + while (size < count && + tpm_tis_wait_for_stat(udev, TPM_STS_DATA_AVAIL | TPM_STS_VALID, + chip->timeout_c, &status) == 0) { + ret = tpm_tis_get_burstcount(udev, &burstcnt); + if (ret) + return burstcnt; + + len = min_t(int, burstcnt, count - size); + ret = tpm_tis_read_bytes(udev, TPM_DATA_FIFO(chip->locality), + len, buf + size); + if (ret < 0) + return ret; + + size += len; + } + + return size; +} + +static int tpm_tis_recv(struct udevice *udev, u8 *buf, size_t count) +{ + struct tpm_chip *chip = dev_get_priv(udev); + int ret; + int size, expected; + + if (!chip) + return -ENODEV; + + if (count < TPM_HEADER_SIZE) + return -E2BIG; + + ret = tpm_tis_request_locality(udev, 0); + if (ret < 0) + return -EBUSY; + + size = tpm_tis_recv_data(udev, buf, TPM_HEADER_SIZE); + if (size < TPM_HEADER_SIZE) { + log_err("TPM error, unable to read header\n"); + goto out; + } + + expected = get_unaligned_be32(buf + TPM_CMD_COUNT_OFFSET); + if (expected > count) { + size = -EIO; + log_warning("Too much data: %d > %zu\n", expected, count); + goto out; + } + + size += tpm_tis_recv_data(udev, &buf[TPM_HEADER_SIZE], + expected - TPM_HEADER_SIZE); + if (size < expected) { + log(LOGC_NONE, LOGL_ERR, + "TPM error, unable to read remaining bytes of result\n"); + size = -EIO; + goto out; + } + +out: + tpm_tis_ready(udev); + tpm_tis_release_locality(udev, chip->locality); + + return size; +} + +static int tpm_tis_probe(struct udevice *udev) +{ + struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(udev); + struct tpm_chip_priv *priv = dev_get_uclass_priv(udev); + struct tpm_chip *chip = dev_get_priv(udev); + int ret = 0; + fdt_addr_t ioaddr; + u32 tmp; + u64 sz; + + ioaddr = dev_read_addr(udev); + if (ioaddr == FDT_ADDR_T_NONE) + return -EINVAL; + + ret = dev_read_u64(udev, "reg", &sz); + if (ret) + return -EINVAL; + + drv_data->iobase = ioremap(ioaddr, sz); + log_info("Remapped TPM2 base: 0x%llx size: 0x%llx\n", ioaddr, sz); + + ret = tpm_tis_request_locality(udev, 0); + if (ret) + goto iounmap; + + chip->timeout_a = TIS_SHORT_TIMEOUT_MS; + chip->timeout_b = TIS_LONG_TIMEOUT_MS; + chip->timeout_c = TIS_SHORT_TIMEOUT_MS; + chip->timeout_d = TIS_SHORT_TIMEOUT_MS; + priv->pcr_count = drv_data->pcr_count; + priv->pcr_select_min = drv_data->pcr_select_min; + + /* Disable interrupts */ + tpm_tis_read32(udev, TPM_INT_ENABLE(chip->locality), &tmp); + tmp |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT | + TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT; + tmp &= ~TPM_GLOBAL_INT_ENABLE; + tpm_tis_write32(udev, TPM_INT_ENABLE(chip->locality), tmp); + + /* + * Although the driver probably works with a TPMv1 our Kconfig + * limits the driver to TPMv2 only + */ + priv->version = TPM_V2; + tpm_tis_read_bytes(udev, TPM_RID(chip->locality), 1, &chip->rid); + tpm_tis_read32(udev, TPM_DID_VID(chip->locality), &chip->vend_dev); + + tpm_tis_release_locality(udev, chip->locality); + + return ret; + +iounmap: + iounmap(drv_data->iobase); + return -EINVAL; +} + +static int tpm_tis_remove(struct udevice *udev) +{ + struct tpm_chip *chip = dev_get_priv(udev); + struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(udev); + + iounmap(drv_data->iobase); + return tpm_tis_release_locality(udev, chip->locality); +} + +static int tpm_tis_cleanup(struct udevice *udev) +{ + struct tpm_chip *chip = dev_get_priv(udev); + + tpm_tis_ready(udev); + tpm_tis_release_locality(udev, chip->locality); + + return 0; +} + +static int tpm_tis_open(struct udevice *udev) +{ + struct tpm_chip *chip = dev_get_priv(udev); + int ret; + + if (chip->is_open) + return -EBUSY; + + ret = tpm_tis_request_locality(udev, 0); + if (!ret) + chip->is_open = 1; + + return ret; +} + +static int tpm_tis_close(struct udevice *udev) +{ + struct tpm_chip *chip = dev_get_priv(udev); + int ret = 0; + + if (chip->is_open) { + ret = tpm_tis_release_locality(udev, chip->locality); + chip->is_open = 0; + } + + return ret; +} + +static const struct tpm_ops tpm_tis_ops = { + .open = tpm_tis_open, + .close = tpm_tis_close, + .get_desc = tpm_tis_get_desc, + .send = tpm_tis_send, + .recv = tpm_tis_recv, + .cleanup = tpm_tis_cleanup, +}; + +static const struct tpm_tis_chip_data tpm_tis_std_chip_data = { + .pcr_count = 24, + .pcr_select_min = 3, +}; + +static const struct udevice_id tpm_tis_ids[] = { + { + .compatible = "tcg,tpm-tis-mmio", + .data = (ulong)&tpm_tis_std_chip_data, + }, + { } +}; + +U_BOOT_DRIVER(tpm_tis_mmio) = { + .name = "tpm_tis_mmio", + .id = UCLASS_TPM, + .of_match = tpm_tis_ids, + .ops = &tpm_tis_ops, + .probe = tpm_tis_probe, + .remove = tpm_tis_remove, + .priv_auto = sizeof(struct tpm_chip), +}; diff --git a/drivers/tpm/tpm_tis.h b/drivers/tpm/tpm_tis.h index 2a160fe05c9a..a561aa37d45a 100644 --- a/drivers/tpm/tpm_tis.h +++ b/drivers/tpm/tpm_tis.h @@ -29,6 +29,14 @@ enum tpm_timeout { SLEEP_DURATION_LONG_US = 210, }; +#define TPM_ACCESS(l) (0x0000 | ((l) << 12)) +#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12)) +#define TPM_STS(l) (0x0018 | ((l) << 12)) +#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12)) +#define TPM_DID_VID(l) (0x0F00 | ((l) << 12)) +#define TPM_RID(l) (0x0F04 | ((l) << 12)) +#define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12)) + /* Size of external transmit buffer (used in tpm_transmit)*/ #define TPM_BUFSIZE 4096 diff --git a/include/tpm-v2.h b/include/tpm-v2.h index 7de7d6a57dca..b1710f28f5ad 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -360,6 +360,7 @@ enum { TPM_STS_DATA_EXPECT = 1 << 3, TPM_STS_SELF_TEST_DONE = 1 << 2, TPM_STS_RESPONSE_RETRY = 1 << 1, + TPM_STS_READ_ZERO = 0x23 }; enum {