summaryrefslogtreecommitdiff
path: root/src/drivers/pc80/tpm
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/pc80/tpm')
-rw-r--r--src/drivers/pc80/tpm/Kconfig9
-rw-r--r--src/drivers/pc80/tpm/Makefile.inc1
-rw-r--r--src/drivers/pc80/tpm/acpi/tpm.asl104
-rw-r--r--src/drivers/pc80/tpm/chip.h35
-rw-r--r--src/drivers/pc80/tpm/tpm.c108
5 files changed, 257 insertions, 0 deletions
diff --git a/src/drivers/pc80/tpm/Kconfig b/src/drivers/pc80/tpm/Kconfig
index fbb3b423f4..9630de2ac1 100644
--- a/src/drivers/pc80/tpm/Kconfig
+++ b/src/drivers/pc80/tpm/Kconfig
@@ -5,3 +5,12 @@ config LPC_TPM
Enable this option to enable LPC TPM support in coreboot.
If unsure, say N.
+
+config TPM_TIS_BASE_ADDRESS
+ hex "TPM Base Address"
+ default 0xfed40000
+ help
+ This can be used to adjust the TPM memory base address.
+ The default is specified by the TCG PC Client Specific TPM
+ Interface Specification 1.2 and should not be changed unless
+ the TPM being used does not conform to TPM TIS 1.2.
diff --git a/src/drivers/pc80/tpm/Makefile.inc b/src/drivers/pc80/tpm/Makefile.inc
index 6f973e12f1..c900fe8c1d 100644
--- a/src/drivers/pc80/tpm/Makefile.inc
+++ b/src/drivers/pc80/tpm/Makefile.inc
@@ -1 +1,2 @@
romstage-$(CONFIG_LPC_TPM) += tpm.c
+ramstage-$(CONFIG_LPC_TPM) += tpm.c
diff --git a/src/drivers/pc80/tpm/acpi/tpm.asl b/src/drivers/pc80/tpm/acpi/tpm.asl
new file mode 100644
index 0000000000..7500211570
--- /dev/null
+++ b/src/drivers/pc80/tpm/acpi/tpm.asl
@@ -0,0 +1,104 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Google Inc.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* Trusted Platform Module */
+
+Device (TPM)
+{
+ Name (_HID, EISAID ("PNP0C31"))
+ Name (_CID, 0x310cd041)
+ Name (_UID, 1)
+
+ Method (_STA, 0)
+ {
+ If (CONFIG_LPC_TPM) {
+ Return (0xf)
+ } Else {
+ Return (0x0)
+ }
+ }
+
+ Name (IBUF, ResourceTemplate ()
+ {
+ /* Updated based on TPM interrupt for Locality 0 */
+ Interrupt (ResourceConsumer, Edge, ActiveHigh,
+ Exclusive, , , TIRQ) { 0 }
+ })
+
+ Name (RBUF, ResourceTemplate ()
+ {
+ IO (Decode16, 0x2e, 0x2e, 0x01, 0x02)
+ Memory32Fixed (ReadWrite, CONFIG_TPM_TIS_BASE_ADDRESS, 0x5000)
+ })
+
+ Method (_CRS, 0, NotSerialized)
+ {
+ OperationRegion (TREG, SystemMemory,
+ CONFIG_TPM_TIS_BASE_ADDRESS, 0x5000)
+ Field (TREG, ByteAcc, NoLock, Preserve)
+ {
+ /* TPM_INT_ENABLE_0 */
+ Offset (0x0008),
+ , 3,
+ ITPL, 2, /* Interrupt type and polarity */
+
+ /* TPM_INT_VECTOR_0 */
+ Offset (0x000C),
+ IVEC, 4, /* SERIRQ vector */
+ }
+
+ If (LGreater (IVEC, 0)) {
+ /* Update interrupt vector */
+ CreateField (^IBUF, ^TIRQ._INT, 32, TVEC)
+ Store (IVEC, TVEC)
+
+ /* Update interrupt type and polarity */
+ CreateBitField (^IBUF, ^TIRQ._HE, TTYP)
+ CreateBitField (^IBUF, ^TIRQ._LL, TPOL)
+ CreateBitField (^IBUF, ^TIRQ._SHR, TSHR)
+
+ If (LEqual (ITPL, 0x0)) {
+ /* Active-High Level-Triggered Shared */
+ Store (Zero, TPOL)
+ Store (Zero, TTYP)
+ Store (One, TSHR)
+ } ElseIf (LEqual (ITPL, 0x1)) {
+ /* Active-Low Level-Triggered Shared */
+ Store (One, TPOL)
+ Store (Zero, TTYP)
+ Store (One, TSHR)
+ } ElseIf (LEqual (ITPL, 0x2)) {
+ /* Active-High Edge-Triggered Exclusive */
+ Store (Zero, TPOL)
+ Store (One, TTYP)
+ Store (Zero, TSHR)
+ } ElseIf (LEqual (ITPL, 0x3)) {
+ /* Active-Low Edge-Triggered Exclusive */
+ Store (One, TPOL)
+ Store (One, TTYP)
+ Store (Zero, TSHR)
+ }
+
+ /* Merge IRQ with base address */
+ Return (ConcatenateResTemplate (RBUF, IBUF))
+ } Else {
+ Return (RBUF)
+ }
+ }
+}
diff --git a/src/drivers/pc80/tpm/chip.h b/src/drivers/pc80/tpm/chip.h
new file mode 100644
index 0000000000..bcfb877dfa
--- /dev/null
+++ b/src/drivers/pc80/tpm/chip.h
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc. All Rights Reserved.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+#ifndef DRIVERS_PC80_TPM_CHIP_H
+#define DRIVERS_PC80_TPM_CHIP_H
+
+typedef struct drivers_pc80_tpm_config {
+ /*
+ * TPM Interrupt polarity:
+ *
+ * High Level 0
+ * Low Level 1
+ * Rising Edge 2
+ * Falling Edge 3
+ */
+ u8 irq_polarity;
+} tpm_config_t;
+
+#endif /* DRIVERS_PC80_TPM_CHIP_H */
diff --git a/src/drivers/pc80/tpm/tpm.c b/src/drivers/pc80/tpm/tpm.c
index c0429ddc9c..f1c5d97810 100644
--- a/src/drivers/pc80/tpm/tpm.c
+++ b/src/drivers/pc80/tpm/tpm.c
@@ -35,6 +35,8 @@
#include <console/console.h>
#include <tpm.h>
#include <arch/early_variables.h>
+#include <device/pnp.h>
+#include "chip.h"
#define PREFIX "lpc_tpm: "
@@ -211,6 +213,20 @@ static inline u32 tpm_read_did_vid(int locality)
return value;
}
+static inline void tpm_write_int_vector(int vector, int locality)
+{
+ TPM_DEBUG_IO_WRITE(TIS_REG_INT_VECTOR, vector);
+ writeb(vector & 0xf, TIS_REG(locality, TIS_REG_INT_VECTOR));
+}
+
+static inline void tpm_write_int_polarity(int polarity, int locality)
+{
+ /* Set polarity and leave all other bits at 0 */
+ u32 value = (polarity & 0x3) << 3;
+ TPM_DEBUG_IO_WRITE(TIS_REG_INT_ENABLE, value);
+ writel(value, TIS_REG(locality, TIS_REG_INT_ENABLE));
+}
+
/*
* tis_wait_sts()
*
@@ -673,3 +689,95 @@ int tis_sendrecv(const uint8_t *sendbuf, size_t send_size,
return tis_readresponse(recvbuf, recv_len);
}
+
+#ifdef __RAMSTAGE__
+
+/*
+ * tis_setup_interrupt()
+ *
+ * Set up the interrupt vector and polarity for locality 0 and
+ * disable all interrupts so they are unused in firmware but can
+ * be enabled by the OS.
+ *
+ * The values used here must match what is passed in the TPM ACPI
+ * device if ACPI is used on the platform.
+ *
+ * @vector - TPM interrupt vector
+ * @polarity - TPM interrupt polarity
+ *
+ * Returns 0 on success, TPM_DRIVER_ERR on failure.
+ */
+static int tis_setup_interrupt(int vector, int polarity)
+{
+ u8 locality = 0;
+ int has_access = tis_has_access(locality);
+
+ /* Open connection and request access if not already granted */
+ if (!has_access && tis_open() < 0)
+ return TPM_DRIVER_ERR;
+
+ /* Set TPM interrupt vector */
+ tpm_write_int_vector(vector, locality);
+
+ /* Set TPM interupt polarity and disable interrupts */
+ tpm_write_int_polarity(polarity, locality);
+
+ /* Close connection if it was opened */
+ if (!has_access && tis_close() < 0)
+ return TPM_DRIVER_ERR;
+
+ return 0;
+}
+
+static void lpc_tpm_read_resources(struct device *dev)
+{
+ /* Static 5K memory region specified in Kconfig */
+ mmio_resource(dev, 0, CONFIG_TPM_TIS_BASE_ADDRESS >> 10, 0x5000 >> 10);
+}
+
+static void lpc_tpm_set_resources(struct device *dev)
+{
+ tpm_config_t *config = (tpm_config_t *)dev->chip_info;
+ struct resource *res;
+
+ for (res = dev->resource_list; res; res = res->next) {
+ if (!(res->flags & IORESOURCE_ASSIGNED))
+ continue;
+
+ if (res->flags & IORESOURCE_IRQ) {
+ /* Set interrupt vector */
+ tis_setup_interrupt((int)res->base,
+ config->irq_polarity);
+ } else {
+ printk(BIOS_ERR,
+ "ERROR: %s %02lx unknown resource type\n",
+ dev_path(dev), res->index);
+ continue;
+ }
+
+ res->flags |= IORESOURCE_STORED;
+ report_resource_stored(dev, res, " <tpm>");
+ }
+}
+
+static struct device_operations lpc_tpm_ops = {
+ .read_resources = &lpc_tpm_read_resources,
+ .set_resources = &lpc_tpm_set_resources,
+};
+
+static struct pnp_info pnp_dev_info[] = {
+ { .flags = PNP_IRQ0 }
+};
+
+static void enable_dev(struct device *dev)
+{
+ pnp_enable_devices(dev, &lpc_tpm_ops,
+ ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
+}
+
+struct chip_operations drivers_pc80_tpm_ops = {
+ CHIP_NAME("LPC TPM")
+ .enable_dev = enable_dev
+};
+
+#endif /* __RAMSTAGE__ */