[Skiboot] [PATCH 11/15] libstb/drivers: Add I2C nuvoton driver for TPM 2.0

Claudio Carvalho cclaudio at linux.vnet.ibm.com
Thu Aug 11 15:23:53 AEST 2016


This adds a driver for the 'nuvoton,npct650' TPM 2.0. The driver was
ported and adapted from hostboot tpmdd.C.

Signed-off-by: Claudio Carvalho <cclaudio at linux.vnet.ibm.com>
---
 libstb/Makefile.inc              |   3 +-
 libstb/drivers/Makefile.inc      |  11 +
 libstb/drivers/tpm_i2c_nuvoton.c | 653 +++++++++++++++++++++++++++++++++++++++
 libstb/drivers/tpm_i2c_nuvoton.h |  22 ++
 libstb/status_codes.h            |   6 +
 libstb/tpm.c                     |   2 +
 6 files changed, 696 insertions(+), 1 deletion(-)
 create mode 100644 libstb/drivers/Makefile.inc
 create mode 100644 libstb/drivers/tpm_i2c_nuvoton.c
 create mode 100644 libstb/drivers/tpm_i2c_nuvoton.h

diff --git a/libstb/Makefile.inc b/libstb/Makefile.inc
index 4cffd54..693e888 100644
--- a/libstb/Makefile.inc
+++ b/libstb/Makefile.inc
@@ -8,6 +8,7 @@ LIBSTB_SRCS = container.c tpm.c
 LIBSTB_OBJS = $(LIBSTB_SRCS:%.c=%.o)
 LIBSTB = $(LIBSTB_DIR)/built-in.o
 
+include $(SRC)/$(LIBSTB_DIR)/drivers/Makefile.inc
 include $(SRC)/$(LIBSTB_DIR)/tss/Makefile.inc
 
-$(LIBSTB): $(LIBSTB_OBJS:%=$(LIBSTB_DIR)/%) $(TSS)
+$(LIBSTB): $(LIBSTB_OBJS:%=$(LIBSTB_DIR)/%) $(DRIVERS) $(TSS)
diff --git a/libstb/drivers/Makefile.inc b/libstb/drivers/Makefile.inc
new file mode 100644
index 0000000..12d8e82
--- /dev/null
+++ b/libstb/drivers/Makefile.inc
@@ -0,0 +1,11 @@
+# -*-Makefile-*-
+
+DRIVERS_DIR = libstb/drivers
+
+SUBDIRS += $(DRIVERS_DIR)
+
+DRIVERS_SRCS = tpm_i2c_nuvoton.c
+DRIVERS_OBJS = $(DRIVERS_SRCS:%.c=%.o)
+DRIVERS = $(DRIVERS_DIR)/built-in.o
+
+$(DRIVERS): $(DRIVERS_OBJS:%=$(DRIVERS_DIR)/%)
diff --git a/libstb/drivers/tpm_i2c_nuvoton.c b/libstb/drivers/tpm_i2c_nuvoton.c
new file mode 100644
index 0000000..b615347
--- /dev/null
+++ b/libstb/drivers/tpm_i2c_nuvoton.c
@@ -0,0 +1,653 @@
+/* Copyright 2013-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************
+ * THIS DRIVER WAS PORTED AND ADAPTED FROM:
+ * https://github.com/open-power/hostboot/blob/master-p8/src/usr/i2c/tpmdd.C
+ ****************************************************************************/
+
+#include <string.h>
+#include <timebase.h>
+#include <timer.h>
+#include <i2c.h>
+#include <skiboot.h>
+#include <opal-api.h>
+#include <device.h>
+
+#include "../status_codes.h"
+#include "../tpm.h"
+#include "tpm_i2c_nuvoton.h"
+
+//#define DBG(fmt, ...) prlog(PR_DEBUG, fmt, ##__VA_ARGS__)
+#define DBG(fmt, ...)
+
+#define DRIVER_NAME "i2c_tpm_nuvoton"
+
+/**
+ * Timings between various states or transitions within
+ * the interface protocol. See PTP spec for details.
+ */
+#define TCG_PTP_TIMEOUT_A	750
+#define TCG_PTP_TIMEOUT_B	2000
+#define TCG_PTP_TIMEOUT_C	200
+#define TCG_PTP_TIMEOUT_D	30
+
+/* I2C interface offsets */
+#define NUVOTON_TPM_STS			0x00
+#define NUVOTON_TPM_BURST_COUNT		0x01
+#define NUVOTON_TPM_DATA_FIFO_W		0x20
+#define NUVOTON_TPM_DATA_FIFO_R		0x40
+#define NUVOTON_TPM_VID_DID_RID		0x60
+
+/* Bit masks for the TPM STATUS register */
+#define TCG_PTP_STS_VALID		0x80
+#define TCG_PTP_STS_COMMAND_READY	0x40
+#define TCG_PTP_STS_GO			0x20
+#define TCG_PTP_STS_DATA_AVAIL		0x10
+#define TCG_PTP_STS_EXPECT		0x08
+#define TCG_PTP_STS_RESPONSE_RETRY	0x02
+#define TCG_PTP_STS_ERR_VAL		0x07
+
+/* from hw/p8-i2c.c */
+#define I2C_TIMEOUT_POLL_MS	4000  /* 4s/byte timeout */
+
+/* TPM Driver values */
+#define MAX_STSVALID_POLLS 	5   /* Max poll of 50ms (5*10ms) */
+#define TPM_TIMEOUT_INTERVAL	10
+#define TPM_MAX_NACK_RETRIES	2
+
+static struct tpm_dev *tpm_device = NULL;
+static const char* compat = "nuvoton,npct650";
+
+static void i2c_request_complete(int rc, struct i2c_request *req)
+{
+	*(int*)req->user_data = rc;
+}
+
+/**
+ * tpm_i2c_request_send - send request to i2c bus
+ * @read_write: SMBUS_READ or SMBUS_WRITE
+ * @offset: any of the I2C interface offset defined
+ * @offset_bytes: offset size in bytes
+ * @buf: data to be read or written
+ * @buflen: buf length
+ *
+ * This interacts with skiboot i2c API to send an I2C request to the tpm
+ * device
+ *
+ * Returns: Zero on success otherwise a negative error code
+ */
+static int tpm_i2c_request_send(int read_write, uint32_t offset,
+			    uint32_t offset_bytes, void* buf, size_t buflen)
+{
+	int rc, waited, retries, timeout;
+	struct i2c_request *req;
+	struct i2c_bus *bus;
+
+	bus = i2c_find_bus_by_id(tpm_device->bus_id);
+
+	if (!bus) {
+		/**
+		 * @fwts-label TPMI2CInvalidBusID
+		 * @fwts-advice tpm_i2c_request_send was passed an invalid bus
+		 * ID. This indicates a tb_init() bug.
+		 */
+		prlog(PR_ERR, "TPM: Invalid bus_id=%x\n", tpm_device->bus_id);
+		rc = STB_ARG_ERROR;
+		goto out;
+	}
+
+	req = i2c_alloc_req(bus);
+
+	if (!req) {
+		/**
+		 * @fwts-label TPMI2CAllocationFailed
+		 * @fwts-advice OPAL failed to allocate memory for an
+		 * i2c_request. This points to an OPAL bug as OPAL run out of
+		 * memory and this should never happen.
+		 */
+		prlog(PR_ERR, "TPM: i2c_alloc_req failed\n");
+		rc = STB_DRIVER_ERROR;
+		goto out;
+	}
+
+	req->dev_addr   = tpm_device->xscom_base;
+	req->op         = read_write;
+	req->offset     = offset;
+	req->offset_bytes = offset_bytes;
+	req->rw_buf     = (void*) buf;
+	req->rw_len     = buflen;
+	req->completion = i2c_request_complete;
+	req->user_data = &rc;
+
+	timeout = (buflen + offset_bytes + 2) * I2C_TIMEOUT_POLL_MS;
+
+	for (retries = 0; retries <= TPM_MAX_NACK_RETRIES; retries++)
+	{
+		rc = 1;
+		waited = 0;
+		i2c_queue_req(req);
+
+		do {
+			time_wait_ms(5);
+			waited += 5;
+		} while (waited < timeout && rc == 1);
+
+		if (rc == OPAL_I2C_NACK_RCVD)
+			continue;
+		else
+			/* error or success */
+			break;
+	}
+
+	DBG("%s tpm req op=%x offset=%x buf=%016llx buflen=%d delay=%d/%d,"
+	    "rc=%d\n",
+	    (rc) ? "!!!!" : "----", req->op, req->offset,
+	    *(uint64_t*) buf, req->rw_len, waited, timeout, rc);
+
+	i2c_free_req(req);
+
+	/* error */
+	if (rc)
+		rc = STB_DRIVER_ERROR;
+
+out:
+	return rc;
+}
+
+static int tpm_status_write_byte(uint8_t byte)
+{
+	uint8_t value = byte;
+	return tpm_i2c_request_send(SMBUS_WRITE, NUVOTON_TPM_STS, 1, &value,
+				sizeof(value));
+}
+
+static int tpm_read_sts_reg_valid(uint8_t* value)
+{
+	int polls, rc;
+
+	for(polls=0; polls<=MAX_STSVALID_POLLS; polls++)
+	{
+		rc = tpm_i2c_request_send(SMBUS_READ, NUVOTON_TPM_STS, 1, value,
+				      sizeof(uint8_t));
+
+		if (rc < 0)
+			return rc;
+
+		if (rc == 0  && ((*value &
+				  TCG_PTP_STS_VALID) == TCG_PTP_STS_VALID))
+			return STB_SUCCESS;
+
+		// wait tpm sts reg be settled
+		time_wait_ms(5);
+	}
+
+	value = 0;
+	/**
+	 * @fwts-label TPMValidBitTimeout
+	 * @fwts-advice The valid bit of the tpm status register is taking
+	 * longer to be settled. The wait time need to be increased or the TPM
+	 * device is not functional.
+	 */
+	prlog(PR_ERR, "TPM: valid bit not settled. Timeout.\n");
+
+	return STB_TPM_TIMEOUT;
+}
+
+static bool tpm_is_command_ready(int* rc)
+{
+	uint8_t value = 0;
+
+	*rc = tpm_i2c_request_send(SMBUS_READ, NUVOTON_TPM_STS, 1, &value,
+			       sizeof(value));
+
+	if (*rc == 0  &&
+	   ((value & TCG_PTP_STS_COMMAND_READY) == TCG_PTP_STS_COMMAND_READY)){
+		DBG("---- TPM is command ready\n");
+		return true;
+	}
+
+	return false;
+}
+
+static int tpm_poll_for_command_ready(void)
+{
+	int rc, polls, delay;
+
+	/**
+	 * The first write to command ready may just abort an
+	 * outstanding command, so we poll twice
+	 */
+	for (polls=0; polls<2; polls++)
+	{
+		rc = tpm_status_write_byte(TCG_PTP_STS_COMMAND_READY);
+		if (rc < 0) {
+			return rc;
+		}
+
+		for (delay = 0;
+		     delay < TCG_PTP_TIMEOUT_B;
+		     delay += TPM_TIMEOUT_INTERVAL)
+		{
+			if (tpm_is_command_ready(&rc))
+				return rc;
+
+			time_wait_ms(TPM_TIMEOUT_INTERVAL);
+		}
+		DBG("--- Command ready polling, delay %d/%d\n",
+		    delay, TCG_PTP_TIMEOUT_B);
+	}
+
+	/**
+	 * @fwts-label TPMCommandReadyBitTimeout
+	 * @fwts-advice The command ready bit of the tpm status register is
+	 * taking longer to be settled. The wait time need to be increased or
+	 * the TPM device is not functional.
+	 */
+	prlog(PR_ERR, "TPM: command ready polling timeout\n");
+	return STB_TPM_TIMEOUT;
+}
+
+static bool tpm_is_expecting(int* rc)
+{
+	uint8_t value = 0;
+
+	*rc = tpm_read_sts_reg_valid(&value);
+
+	if (*rc == 0  && (( value &
+			    TCG_PTP_STS_EXPECT) == TCG_PTP_STS_EXPECT))
+		return true;
+
+	return false;
+}
+
+static bool tpm_is_data_avail(int* rc)
+{
+	uint8_t value = 0;
+
+	*rc = tpm_read_sts_reg_valid(&value);
+
+	if (*rc == 0 && (( value &
+			   TCG_PTP_STS_DATA_AVAIL) == TCG_PTP_STS_DATA_AVAIL))
+		return true;
+
+	return false;
+}
+
+static int tpm_poll_for_data_avail(void)
+{
+	int delay, rc;
+
+	/* Operation TIMEOUT_A defined by TCG spec for data available */
+	for (delay = 0;
+	     delay < TCG_PTP_TIMEOUT_A;
+	     delay += TPM_TIMEOUT_INTERVAL)
+	{
+		if (tpm_is_data_avail(&rc)) {
+			DBG("---- read FIFO. Data available. delay=%d/%d\n",
+			    delay, TCG_PTP_TIMEOUT_A);
+			return rc;
+		}
+
+		time_wait_ms(TPM_TIMEOUT_INTERVAL);
+	}
+	/**
+	 * @fwts-label TPMDataAvailBitTimeout
+	 * @fwts-advice The data avail bit of the tpm status register is taking
+	 * longer to be settled. The wait time need to be increased or the TPM
+	 * device is not functional.
+	 */
+	prlog(PR_ERR, "TPM: read FIFO. Polling timeout, delay=%d/%d\n",
+	      delay, TCG_PTP_TIMEOUT_A);
+
+	return STB_TPM_TIMEOUT;
+}
+
+static int tpm_read_burst_count(uint8_t* burst_count)
+{
+	int rc = 0;
+
+	/* In i2C, burstCount is 1 byte */
+	rc = tpm_i2c_request_send(SMBUS_READ, NUVOTON_TPM_BURST_COUNT, 1,
+			      burst_count, sizeof(uint8_t));
+
+	DBG("---- burst_count=%d rc=%d\n", *burst_count, rc);
+
+	if (rc < 0)
+		*burst_count = 0;
+
+	return rc;
+}
+
+static int tpm_write_fifo(uint8_t* buf, size_t buflen)
+{
+	uint8_t burst_count = 0;
+	int delay = 0;
+	int rc;
+
+	size_t curByte = 0;
+	uint8_t* bytePtr = buf;
+	uint8_t* curBytePtr = NULL;
+
+	/**
+	 * We will transfer the command except for the last byte
+	 * that will be transfered separately to allow for
+	 * overflow checking
+	 */
+	size_t length = buflen - 1;
+	size_t tx_len = 0;
+
+	do
+	{
+		rc = tpm_read_burst_count(&burst_count);
+
+		if (rc < 0)
+			return rc;
+		else if (burst_count == 0)
+		{
+			/* Need to delay to allow the TPM time */
+			time_wait_ms(TPM_TIMEOUT_INTERVAL);
+			delay += TPM_TIMEOUT_INTERVAL;
+			continue;
+		}
+
+		/* Send in some data */
+		curBytePtr = &(bytePtr[curByte]);
+		tx_len = (curByte + burst_count > length ?
+				(length - curByte) :
+				burst_count);
+
+		rc = tpm_i2c_request_send(SMBUS_WRITE, NUVOTON_TPM_DATA_FIFO_W,
+					  1, curBytePtr, tx_len);
+
+		curByte += tx_len;
+		DBG("%s write FIFO sent %zd bytes."
+		    " burstcount polling delay=%d/%d, rc=%d\n",
+		    (rc) ? "!!!!" : "----", curByte, delay,
+		    TCG_PTP_TIMEOUT_D, rc);
+		delay = 0;
+
+		if (rc < 0)
+			return rc;
+
+		if (!tpm_is_expecting(&rc)) {
+			/**
+			 * @fwts-label TPMWriteFifoOverflow1
+			 * @fwts-advice We overflow to write to the TPM FIFO,
+			 * the TPM is not expecting more data. This indicates a bug
+			 * in the TPM device driver.
+			 */
+			prlog(PR_ERR, "TPM: write FIFO overflow1\n");
+			return STB_TPM_OVERFLOW;
+		}
+
+		/* Everything but the last byte sent? */
+		if (curByte >= length)
+			break;
+
+	/* Operation TIMEOUT_D defined by TCG spec for FIFO availability */
+	} while (delay < TCG_PTP_TIMEOUT_D);
+
+	if (delay < TCG_PTP_TIMEOUT_D)
+	{
+		delay = 0;
+
+		/* Send the final byte */
+		do
+		{
+			rc = tpm_read_burst_count(&burst_count);
+
+			if (rc < 0)
+				return rc;
+			else if (burst_count == 0)
+			{
+				/* Need to delay to allow the TPM time */
+				time_wait_ms(TPM_TIMEOUT_INTERVAL);
+				delay += TPM_TIMEOUT_INTERVAL;
+				continue;
+			}
+
+			/* Send in some data */
+			curBytePtr = &(bytePtr[curByte]);
+			rc = tpm_i2c_request_send(SMBUS_WRITE,
+					      NUVOTON_TPM_DATA_FIFO_W, 1,
+					      curBytePtr, 1);
+
+			DBG("%s write FIFO sent last byte, delay=%d/%d,"
+			    " rc=%d\n",
+			    (rc) ? "!!!!" : "----", delay,
+			    TCG_PTP_TIMEOUT_D, rc);
+
+			/* done */
+			break;
+
+			/**
+			 * Operation TIMEOUT_D defined by TCG spec for
+			 * FIFO availability
+			 */
+		} while (delay < TCG_PTP_TIMEOUT_D);
+
+	}
+
+	if (delay >= TCG_PTP_TIMEOUT_D) {
+		/**
+		 * @fwts-label TPMWriteBurstcountBitTimeout
+		 * @fwts-advice The burstcount bit of the tpm status register is
+		 * taking longer to be settled. The wait time need to be increased or
+		 * the TPM device is not functional.
+		 */
+		prlog(PR_ERR, "TPM: write FIFO, burstcount polling timeout."
+		      " delay=%d/%d\n", delay, TCG_PTP_TIMEOUT_D);
+		return STB_TPM_TIMEOUT;
+	}
+
+	if (rc == 0)
+	{
+		if (tpm_is_expecting(&rc)) {
+			 /**
+			 * @fwts-label TPMWriteFifoOverflow2
+			 * @fwts-advice We overflow to write to the TPM FIFO.
+			 * It is expecting more data even though we think we
+			 * are done. This indicates a bug in the TPM device
+			 * driver.
+			 */
+			prlog(PR_ERR, "TPM: write FIFO overflow2\n");
+			return STB_TPM_OVERFLOW;
+		}
+	}
+
+	return rc;
+}
+
+static int tpm_read_fifo(uint8_t* buf, size_t* buflen)
+{
+	int rc;
+	uint8_t burst_count;
+
+	int delay = 0;
+	size_t curByte = 0;
+	uint8_t* bytePtr = (uint8_t*)buf;
+	uint8_t* curBytePtr = NULL;
+
+	/* Verify whether the TPM has data waiting for us */
+	rc = tpm_poll_for_data_avail();
+
+	if (rc == 0)
+	{
+		do
+		{
+			rc = tpm_read_burst_count(&burst_count);
+
+			if (rc < 0)
+				break;
+			else if (burst_count == 0) {
+				/* Need to delay to allow the TPM time */
+				time_wait_ms(TPM_TIMEOUT_INTERVAL);
+				delay += TPM_TIMEOUT_INTERVAL;
+				continue;
+			}
+
+			/* Check for a buffer overflow */
+			if (curByte + burst_count > *buflen)
+			{
+				 /**
+				 * @fwts-label TPMReadFifoOverflow1
+				 * @fwts-advice We overflow to read the TPM FIFO. It is
+				 * expecting more data even though we think we are done.
+				 * This indicates a bug in the TPM device driver.
+				 */
+				prlog(PR_ERR, "TPM: read FIFO overflow1. delay %d/%d\n",
+					  delay, TCG_PTP_TIMEOUT_D);
+				rc = STB_TPM_OVERFLOW;
+			}
+
+			/* Read some data */
+			curBytePtr = &(bytePtr[curByte]);
+			rc = tpm_i2c_request_send(SMBUS_READ,
+					      NUVOTON_TPM_DATA_FIFO_R, 1,
+					      curBytePtr, burst_count);
+
+			curByte += burst_count;
+			DBG("%s read FIFO. received %zd bytes. burstcount"
+			    " polling delay=%d/%d, rc=%d\n",
+			    (rc) ? "!!!!" : "----", curByte, delay,
+			    TCG_PTP_TIMEOUT_D, rc);
+			delay = 0;
+
+			if (rc < 0)
+				break;
+
+			if (!tpm_is_data_avail(&rc))
+				break;
+
+		/* Operation TIMEOUT_D defined by TCG spec for
+		 * FIFO availability */
+		} while (delay < TCG_PTP_TIMEOUT_D);
+	}
+
+	if (rc == 0 && delay >= TCG_PTP_TIMEOUT_D) {
+		/**
+		 * @fwts-label TPMReadBurstcountBitTimeout
+		 * @fwts-advice The burstcount bit of the tpm status register is
+		 * taking longer to be settled. The wait time need to be increased or
+		 * the TPM device is not functional.
+		 */
+		prlog(PR_ERR, "TPM: read FIFO, burstcount polling timeout."
+			  " delay=%d/%d\n",
+			  delay, TCG_PTP_TIMEOUT_D);
+		return STB_TPM_TIMEOUT;
+	}
+
+	if (rc == 0) {
+		/* We read it properly tell the caller the result length */
+		*buflen = curByte;
+	}
+	else {
+		*buflen = 0;
+	}
+
+	return rc;
+}
+
+static int tpm_transmit(struct tpm_dev *dev, uint8_t* buf, size_t cmdlen,
+			size_t* buflen)
+{
+	int rc = STB_SUCCESS;
+
+	if (!dev) {
+		/**
+		 * @fwts-label TPMDeviceNotInitialized
+		 * @fwts-advice TPM device is not initialized. This indicates a
+		 * bug in the tpm_transmit() caller
+		 */
+		prlog(PR_ERR, "TPM: tpm device not initialized\n");
+		return STB_ARG_ERROR;
+	}
+
+	tpm_device = dev;
+
+	DBG("**** %s: dev %#x/%#x buf %016llx cmdlen %zu"
+	    " buflen %zu ****\n",
+	    __func__, dev->bus_id, dev->xscom_base, *(uint64_t*) buf,
+	    cmdlen, *buflen);
+
+	DBG("step 1/5: check command ready\n");
+	if (!tpm_is_command_ready(&rc)) {
+		if (rc < 0)
+			goto out;
+		rc = tpm_poll_for_command_ready();
+		if (rc < 0)
+			goto out;
+	}
+
+	DBG("step 2/5: write FIFO\n");
+	rc = tpm_write_fifo(buf, cmdlen);
+	if (rc < 0)
+		goto out;
+
+	DBG("step 3/5: write tpmgo\n");
+	rc = tpm_status_write_byte(TCG_PTP_STS_GO);
+	if (rc < 0)
+		goto out;
+
+	DBG("step 4/5: read FIFO\n");
+	rc = tpm_read_fifo(buf, buflen);
+	if (rc < 0)
+		goto out;
+
+	DBG("step 5/5: write command ready\n");
+	rc = tpm_status_write_byte(TCG_PTP_STS_COMMAND_READY);
+
+out:
+	DBG("**** tpm_transmit %s, rc=%d ****\n",
+	    (rc) ? "ERROR" : "SUCCESS", rc);
+	return rc;
+}
+
+static struct tpm_driver i2c_tpm_nuvoton_driver = {
+	.name     = DRIVER_NAME,
+	.transmit = tpm_transmit,
+};
+
+void i2c_nuvoton_probe(void)
+{
+	struct tpm_chip *tpm = NULL;
+	struct tpm_dev *tpm_device = NULL;
+	struct dt_node *node = NULL;
+
+	dt_for_each_compatible(dt_root, node, compat) {
+
+		tpm = tpm_allocate_chip(node);
+
+		if (!tpm)
+			continue;
+
+		/* TPM device */
+		tpm_device = (struct tpm_dev*) malloc(sizeof(struct tpm_dev));
+		assert(tpm_device);
+
+		tpm_device->xscom_base = dt_prop_get_u32(node, "reg");
+	        tpm_device->bus_id = dt_prop_get_u32(node->parent,
+						     "ibm,opal-id");
+		tpm->dev = tpm_device;
+
+		/* TPM driver */
+		tpm->driver = &i2c_tpm_nuvoton_driver;
+
+		tpm_register_chip(tpm);
+	}
+}
+
diff --git a/libstb/drivers/tpm_i2c_nuvoton.h b/libstb/drivers/tpm_i2c_nuvoton.h
new file mode 100644
index 0000000..e05f53b
--- /dev/null
+++ b/libstb/drivers/tpm_i2c_nuvoton.h
@@ -0,0 +1,22 @@
+/* Copyright 2013-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TPM_I2C_NUVOTON_H
+#define __TPM_I2C_NUVOTON_H
+
+extern void i2c_nuvoton_probe(void);
+
+#endif /* __TPM_I2C_NUVOTON_H */
diff --git a/libstb/status_codes.h b/libstb/status_codes.h
index 3a742c3..a1a71da 100644
--- a/libstb/status_codes.h
+++ b/libstb/status_codes.h
@@ -19,9 +19,15 @@
 
 /*  general return codes */
 #define STB_SUCCESS		 0
+#define STB_ARG_ERROR		-1
+#define STB_DRIVER_ERROR	-2
 
 /* trusted boot */
 #define STB_EVENTLOG_FAILED  		-200
 #define STB_PCR_EXTEND_FAILED 		-201
 
+/* TPM */
+#define STB_TPM_OVERFLOW	-300
+#define STB_TPM_TIMEOUT	-301
+
 #endif /* __STB_STATUS_CODES_H */
diff --git a/libstb/tpm.c b/libstb/tpm.c
index 26b411b..577341a 100644
--- a/libstb/tpm.c
+++ b/libstb/tpm.c
@@ -20,6 +20,7 @@
 
 #include "status_codes.h"
 #include "container.h"
+#include "drivers/tpm_i2c_nuvoton.h"
 #include "tss/trustedbootCmds.H"
 #include "tpm.h"
 
@@ -176,6 +177,7 @@ void tpm_init(void)
 	list_head_init(&tpm_list);
 
 	/* tpm drivers supported */
+	i2c_nuvoton_probe();
 
 	if (list_empty(&tpm_list)) {
 		/**
-- 
1.9.1



More information about the Skiboot mailing list