From 01dc3723d965bda1e6fc6a0e675ab2196944354c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 May 2015 11:30:59 -0600 Subject: [PATCH] tpm: Support using driver model with I2C As a first step towards converting the TPM system to driver model, allow it to work with CONFIG_DM_I2C. Signed-off-by: Simon Glass --- drivers/tpm/tpm.c | 89 +++++++++++++++++++++---- drivers/tpm/tpm_private.h | 3 + drivers/tpm/tpm_tis_i2c.c | 134 +++++++++++++++++++++++++------------- 3 files changed, 170 insertions(+), 56 deletions(-) diff --git a/drivers/tpm/tpm.c b/drivers/tpm/tpm.c index 31761ec338..a650892f09 100644 --- a/drivers/tpm/tpm.c +++ b/drivers/tpm/tpm.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -48,10 +49,14 @@ DECLARE_GLOBAL_DATA_PTR; /* TPM configuration */ struct tpm { +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#else int i2c_bus; int slave_addr; - char inited; int old_bus; +#endif + char inited; } tpm; /* Global structure for tpm chip data */ @@ -372,7 +377,7 @@ static unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) { - ssize_t rc; + int rc; u32 count, ordinal; unsigned long start, stop; @@ -391,9 +396,11 @@ static ssize_t tpm_transmit(const unsigned char *buf, size_t 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 %zd\n", rc); + error("tpm_transmit: tpm_send: error %d\n", rc); goto out; } @@ -403,7 +410,7 @@ static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) start = get_timer(0); stop = tpm_calc_ordinal_duration(chip, ordinal); do { - debug("waiting for status...\n"); + 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) { @@ -428,15 +435,30 @@ 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 %zd\n", rc); + error("tpm_transmit: tpm_recv: error %d\n", rc); out: return rc; } +#ifdef CONFIG_DM_I2C +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(dev); + if (rc < 0) + g_chip.is_open = 0; + return rc; +} +#else static int tpm_open(uint32_t dev_addr) { int rc; + if (g_chip.is_open) return -EBUSY; rc = tpm_vendor_init(dev_addr); @@ -444,7 +466,7 @@ static int tpm_open(uint32_t dev_addr) g_chip.is_open = 0; return rc; } - +#endif static void tpm_close(void) { if (g_chip.is_open) { @@ -455,6 +477,7 @@ static void tpm_close(void) static int tpm_select(void) { +#ifndef CONFIG_DM_I2C int ret; tpm.old_bus = i2c_get_bus_num(); @@ -466,11 +489,13 @@ static int tpm_select(void) return -1; } } +#endif return 0; } static int tpm_deselect(void) { +#ifndef CONFIG_DM_I2C int ret; if (tpm.old_bus != i2c_get_bus_num()) { @@ -482,6 +507,7 @@ static int tpm_deselect(void) } } tpm.old_bus = -1; +#endif return 0; } @@ -493,10 +519,9 @@ static int tpm_deselect(void) */ static int tpm_decode_config(struct tpm *dev) { -#ifdef CONFIG_OF_CONTROL const void *blob = gd->fdt_blob; - int node, parent; - int i2c_bus; + int parent; + int node; node = fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM); if (node < 0) { @@ -512,15 +537,48 @@ static int tpm_decode_config(struct tpm *dev) debug("%s: Cannot find node parent\n", __func__); return -1; } +#ifdef CONFIG_DM_I2C + struct udevice *bus; + int chip_addr; + int ret; + + /* + * TODO(sjg@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@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; + } +#else + int i2c_bus; + i2c_bus = i2c_get_bus_num_fdt(parent); if (i2c_bus < 0) return -1; dev->i2c_bus = i2c_bus; dev->slave_addr = fdtdec_get_addr(blob, node, "reg"); -#else - dev->i2c_bus = CONFIG_TPM_TIS_I2C_BUS_NUMBER; - dev->slave_addr = CONFIG_TPM_TIS_I2C_SLAVE_ADDRESS; #endif + return 0; } @@ -547,6 +605,7 @@ int tis_init(void) if (tpm_select()) return -1; +#ifndef CONFIG_DM_I2C /* * Probe TPM twice; the first probing might fail because TPM is asleep, * and the probing can wake up TPM. @@ -556,8 +615,10 @@ int tis_init(void) tpm.slave_addr); return -1; } +#endif tpm_deselect(); + debug("%s: done\n", __func__); tpm.inited = 1; @@ -574,7 +635,11 @@ int tis_open(void) if (tpm_select()) return -1; +#ifdef CONFIG_DM_I2C + rc = tpm_open_dev(tpm.dev); +#else rc = tpm_open(tpm.slave_addr); +#endif tpm_deselect(); diff --git a/drivers/tpm/tpm_private.h b/drivers/tpm/tpm_private.h index 888a074d35..8894c98e6a 100644 --- a/drivers/tpm/tpm_private.h +++ b/drivers/tpm/tpm_private.h @@ -131,6 +131,9 @@ struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *); int tpm_vendor_init(uint32_t dev_addr); +struct udevice; +int tpm_vendor_init_dev(struct udevice *dev); + void tpm_vendor_cleanup(struct tpm_chip *chip); diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c index c1bbed4eb5..ee4dfeae44 100644 --- a/drivers/tpm/tpm_tis_i2c.c +++ b/drivers/tpm/tpm_tis_i2c.c @@ -37,6 +37,7 @@ */ #include +#include #include #include #include @@ -122,13 +123,19 @@ static const char * const chip_name[] = { /* Structure to store I2C TPM specific stuff */ struct tpm_dev { +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#else uint addr; +#endif u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */ enum i2c_chip_type chip_type; }; static struct tpm_dev tpm_dev = { +#ifndef CONFIG_DM_I2C .addr = TPM_I2C_ADDR +#endif }; static struct tpm_dev tpm_dev; @@ -156,8 +163,12 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) if ((tpm_dev.chip_type == SLB9635) || (tpm_dev.chip_type == UNKNOWN)) { /* slb9635 protocol should work in both cases */ for (count = 0; count < MAX_COUNT; count++) { +#ifdef CONFIG_DM_I2C + rc = dm_i2c_write(tpm_dev.dev, 0, (uchar *)&addrbuf, 1); +#else rc = i2c_write(tpm_dev.addr, 0, 0, (uchar *)&addrbuf, 1); +#endif if (rc == 0) break; /* Success, break to skip sleep */ udelay(SLEEP_DURATION); @@ -171,7 +182,11 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) */ for (count = 0; count < MAX_COUNT; count++) { udelay(SLEEP_DURATION); +#ifdef CONFIG_DM_I2C + rc = dm_i2c_read(tpm_dev.dev, 0, buffer, len); +#else rc = i2c_read(tpm_dev.addr, 0, 0, buffer, len); +#endif if (rc == 0) break; /* success, break to skip sleep */ } @@ -184,7 +199,11 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) * be safe on the safe side. */ for (count = 0; count < MAX_COUNT; count++) { +#ifdef CONFIG_DM_I2C + rc = dm_i2c_read(tpm_dev.dev, addr, buffer, len); +#else rc = i2c_read(tpm_dev.addr, addr, 1, buffer, len); +#endif if (rc == 0) break; /* break here to skip sleep */ udelay(SLEEP_DURATION); @@ -206,18 +225,26 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, int count; /* Prepare send buffer */ +#ifndef CONFIG_DM_I2C tpm_dev.buf[0] = addr; memcpy(&(tpm_dev.buf[1]), buffer, len); + buffer = tpm_dev.buf; + len++; +#endif for (count = 0; count < max_count; count++) { - rc = i2c_write(tpm_dev.addr, 0, 0, tpm_dev.buf, len + 1); +#ifdef CONFIG_DM_I2C + rc = dm_i2c_write(tpm_dev.dev, addr, buffer, len); +#else + rc = i2c_write(tpm_dev.addr, 0, 0, buffer, len); +#endif if (rc == 0) break; /* Success, break to skip sleep */ udelay(sleep_time); } /* take care of 'guard time' */ - udelay(SLEEP_DURATION); + udelay(sleep_time); if (rc) return -rc; @@ -292,11 +319,14 @@ static int request_locality(struct tpm_chip *chip, int loc) { unsigned long start, stop; u8 buf = TPM_ACCESS_REQUEST_USE; + int rc; if (check_locality(chip, loc) >= 0) return loc; /* We already have the locality */ - iic_tpm_write(TPM_ACCESS(loc), &buf, 1); + rc = iic_tpm_write(TPM_ACCESS(loc), &buf, 1); + if (rc) + return rc; /* Wait for burstcount */ start = get_timer(0); @@ -323,10 +353,15 @@ static u8 tpm_tis_i2c_status(struct tpm_chip *chip) static void tpm_tis_i2c_ready(struct tpm_chip *chip) { + int rc; + /* This causes the current command to be aborted */ u8 buf = TPM_STS_COMMAND_READY; - iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1); + debug("%s\n", __func__); + rc = iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1); + if (rc) + debug("%s: rc=%d\n", __func__, rc); } static ssize_t get_burstcount(struct tpm_chip *chip) @@ -422,6 +457,8 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) expected = get_unaligned_be32(buf + TPM_RSP_SIZE_BYTE); if ((size_t)expected > count) { + error("Error size=%x, expected=%x, count=%x\n", size, expected, + count); size = -EIO; goto out; } @@ -456,11 +493,12 @@ out: static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) { int rc, status; - ssize_t burstcnt; + size_t burstcnt; size_t count = 0; int retry = 0; u8 sts = TPM_STS_GO; + debug("%s: len=%d\n", __func__, len); if (len > TPM_DEV_BUFSIZE) return -E2BIG; /* Command is too long for our tpm, sorry */ @@ -483,9 +521,10 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) if (burstcnt < 0) return burstcnt; - while (count < len - 1) { - if (burstcnt > len - 1 - count) - burstcnt = len - 1 - count; + while (count < len) { + udelay(300); + if (burstcnt > len - count) + burstcnt = len - count; #ifdef CONFIG_TPM_TIS_I2C_BURST_LIMITATION if (retry && burstcnt > CONFIG_TPM_TIS_I2C_BURST_LIMITATION) @@ -497,9 +536,15 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) if (rc == 0) count += burstcnt; else { - retry++; - wait_for_stat(chip, TPM_STS_VALID, - chip->vendor.timeout_c, &status); + debug("%s: error\n", __func__); + if (retry++ > 10) { + rc = -EIO; + goto out_err; + } + rc = wait_for_stat(chip, TPM_STS_VALID, + chip->vendor.timeout_c, &status); + if (rc) + goto out_err; if ((status & TPM_STS_DATA_EXPECT) == 0) { rc = -EIO; @@ -508,20 +553,14 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) } } - /* Write last byte */ - iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), &(buf[count]), 1); - wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); - if ((status & TPM_STS_DATA_EXPECT) != 0) { - rc = -EIO; - goto out_err; - } - /* Go and do it */ iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1); + debug("done\n"); return len; out_err: + debug("%s: out_err\n", __func__); tpm_tis_i2c_ready(chip); /* * The TPM needs some time to clean up here, @@ -558,26 +597,17 @@ static enum i2c_chip_type tpm_vendor_chip_type(void) return UNKNOWN; } -/* Initialisation of i2c tpm */ -int tpm_vendor_init(uint32_t dev_addr) +static int tpm_vendor_init_common(void) { + struct tpm_chip *chip; u32 vendor; u32 expected_did_vid; - uint old_addr; - int rc = 0; - struct tpm_chip *chip; - - old_addr = tpm_dev.addr; - if (dev_addr != 0) - tpm_dev.addr = dev_addr; tpm_dev.chip_type = tpm_vendor_chip_type(); chip = tpm_register_hardware(&tpm_tis_i2c); - if (chip < 0) { - rc = -ENODEV; - goto out_err; - } + if (chip < 0) + return -ENODEV; /* Disable interrupts (not supported) */ chip->vendor.irq = 0; @@ -588,15 +618,13 @@ int tpm_vendor_init(uint32_t dev_addr) chip->vendor.timeout_c = TIS_SHORT_TIMEOUT; chip->vendor.timeout_d = TIS_SHORT_TIMEOUT; - if (request_locality(chip, 0) < 0) { - rc = -ENODEV; - goto out_err; - } + if (request_locality(chip, 0) < 0) + return -ENODEV; /* Read four bytes from DID_VID register */ if (iic_tpm_read(TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) { - rc = -EIO; - goto out_release; + release_locality(chip, 0, 1); + return -EIO; } if (tpm_dev.chip_type == SLB9635) { @@ -609,8 +637,7 @@ int tpm_vendor_init(uint32_t dev_addr) if (tpm_dev.chip_type != UNKNOWN && vendor != expected_did_vid) { error("Vendor id did not match! ID was %08x\n", vendor); - rc = -ENODEV; - goto out_release; + return -ENODEV; } debug("1.2 TPM (chip type %s device-id 0x%X)\n", @@ -622,14 +649,33 @@ int tpm_vendor_init(uint32_t dev_addr) */ return 0; +} + +#ifdef CONFIG_DM_I2C +/* Initialisation of i2c tpm */ +int tpm_vendor_init_dev(struct udevice *dev) +{ + tpm_dev.dev = dev; + return tpm_vendor_init_common(); +} +#else +/* Initialisation of i2c tpm */ +int tpm_vendor_init(uint32_t dev_addr) +{ + uint old_addr; + int rc = 0; -out_release: - release_locality(chip, 0, 1); + old_addr = tpm_dev.addr; + if (dev_addr != 0) + tpm_dev.addr = dev_addr; + + rc = tpm_vendor_init_common(); + if (rc) + tpm_dev.addr = old_addr; -out_err: - tpm_dev.addr = old_addr; return rc; } +#endif void tpm_vendor_cleanup(struct tpm_chip *chip) { -- 2.39.2