diff options
Diffstat (limited to 'src/drivers/pc80')
-rw-r--r-- | src/drivers/pc80/tpm/Kconfig | 9 | ||||
-rw-r--r-- | src/drivers/pc80/tpm/Makefile.inc | 1 | ||||
-rw-r--r-- | src/drivers/pc80/tpm/acpi/tpm.asl | 104 | ||||
-rw-r--r-- | src/drivers/pc80/tpm/chip.h | 35 | ||||
-rw-r--r-- | src/drivers/pc80/tpm/tpm.c | 108 |
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__ */ |