Message ID | 1368626291-2056-1-git-send-email-mathias.leblanc@st.com |
---|---|
State | Superseded |
Delegated to: | Simon Glass |
Headers | show |
Hi Mathias, On Wed, May 15, 2013 at 7:58 AM, Mathias leblanc <mathias.leblanc@st.com> wrote: > From: Mathias Leblanc <mathias.leblanc@st.com> > > * STMicroelectronics version 1.2.0, Copyright (C) 2013 > * This is free software, and you are welcome to redistribute it. > > This is the u-boot driver for TPM chip from ST Microelectronics. > > If you have a TPM security chip from STMicroelectronics working with > an I2C, read the README file and add the correct defines regarding > the tpm in the configuration file of your board. > This file is located in include/configs/your_board.h > > The tpm command will be accessible from within uboot terminal. > > Signed-off-by: Mathias Leblanc <mathias.leblanc@st.com> It would be good to apply this patch in this merge window. Can you please do a few tidy-ups? > --- > README | 14 +- > common/cmd_tpm.c | 122 ++++++++ > drivers/tpm/Makefile | 1 + > drivers/tpm/slb9635_i2c/tpm.c | 20 ++ > drivers/tpm/slb9635_i2c/tpm.h | 1 + > drivers/tpm/tis_i2c.c | 37 +++ > drivers/tpm/tpm_i2c_st.c | 599 ++++++++++++++++++++++++++++++++++++++++ > include/configs/omap3_beagle.h | 8 + Please split the driver, command change (cmd_tpm.c) and the CONFIG change (this file) into three separate patches. > include/tpm.h | 18 ++ > 9 files changed, 819 insertions(+), 1 deletion(-) > create mode 100644 drivers/tpm/tpm_i2c_st.c > > diff --git a/README b/README > index 0d37d56..a72b570 100644 > --- a/README > +++ b/README > @@ -1208,7 +1208,7 @@ The following options need to be configured: > If this option is set, the driver enables cache flush. > > - TPM Support: > - CONFIG_GENERIC_LPC_TPM > + CONFIG_TPM > Support for generic parallel port TPM devices. Only one device > per system is supported at this time. > > @@ -1217,6 +1217,18 @@ The following options need to be configured: > to. Contemporary x86 systems usually map it at > 0xfed40000. > > + CONFIG_ST_TPM_I2C > + Define to compile the ST TPM I2C DRIVER. > + > + CONFIG_TPM_I2C_BUS > + Define the bus number of the board. > + > + CONFIG_TPM_I2C_ADDR > + Define the address of the TPM. > + > + CONFIG_CMD_TPM > + Define to use some TPM u-boot commands. > + > - USB Support: > At the moment only the UHCI host controller is > supported (PIP405, MIP405, MPC5200); define > diff --git a/common/cmd_tpm.c b/common/cmd_tpm.c > index 46fae18..fba1fe7 100644 > --- a/common/cmd_tpm.c > +++ b/common/cmd_tpm.c > @@ -27,6 +27,14 @@ > #include <asm/unaligned.h> > #include <linux/string.h> > > +#define MAX_TRANSACTION_SIZE 30 > +#define CHECK(exp) do { \ > + int _rv = exp; \ > + if (_rv) { \ > + printf("CHECK: %s %d %x\n", #exp, __LINE__, _rv);\ > + } \ > + } while (0) > + > /** > * Print a byte string in hexdecimal format, 16-bytes per line. > * > @@ -546,6 +554,118 @@ static int do_tpm_nv_write(cmd_tbl_t *cmdtp, int flag, > return convert_return_code(err); > } > > +static int do_tpm_hash(cmd_tbl_t *cmdtp, int flag, int argc, > +char * const argv[]) > +{ > + u8 tpm_buffer[MAX_TRANSACTION_SIZE]; > + u32 write_size, read_size; > + char *p; > + int rv = -1; > + argc -= 1; > + argv += 1; > + uint8_t response[1024]; > + size_t rlength = MAX_TRANSACTION_SIZE; > + > + u8 startup[] = { > + 0x00, 0xc1, > + 0x00, 0x00, 0x00, 0x0c, > + 0x00, 0x00, 0x00, 0x99, > + 0x00, 0x01 > + }; > + > + u8 selftestfull[] = { > + 0x00, 0xc1, > + 0x00, 0x00, 0x00, 0x0a, > + 0x00, 0x00, 0x00, 0x50 > + }; > + > + u8 readpcr17[] = { > + 0x00, 0xc1, > + 0x00, 0x00, 0x00, 0x0e, > + 0x00, 0x00, 0x00, 0x15, > + 0x00, 0x00, 0x00, 0x11 > + }; > + > + for (write_size = 0; write_size < argc; write_size++) { > + u32 datum = kstrtoul(argv[write_size], &p, 0); > + if (*p || (datum > 0xff)) { > + printf("\n%s: bad data value\n\n", argv[write_size]); > + cmd_usage(cmdtp); > + return rv; > + } > + tpm_buffer[write_size] = (u8)datum; > + } > + > + if (tis_init()) { > + puts("tis_init() failed!\n"); > + return -1; > + } > + > + if (tis_open()) { > + puts("tis_open() failed!\n"); > + return -1; > + } > + > + rv = tis_sendrecv(startup, sizeof(startup), response, &rlength); > + if (rv) { > + printf("tpm test startup failed\n"); > + CHECK(tis_close()); > + } > + > + rv = tis_sendrecv(selftestfull, sizeof(selftestfull), response, > + &rlength); > + if (rv) { > + printf("tpm test selftestfull failed\n"); > + CHECK(tis_close()); > + } > + > + if (! > + tis_sendrecv(readpcr17, sizeof(readpcr17), response, &read_size)) { > + int i; Blank line between declarations and body of function. Please fix globally. > + puts("TPM Read PCR 17:\n"); > + for (i = 10; i < read_size; i++) > + printf(" %2.2x", response[i]); > + puts("\n"); > + rv = 0; > + } else { Suspect indenting here, please fix globally. > + printf("tpm test readpcr17 failed\n"); > + CHECK(tis_close()); > + } > + > + read_size = sizeof(tpm_buffer); > + if (! Remove newline here. Please fix below also. > + tis_sendrecv_hash(tpm_buffer, write_size, tpm_buffer, &read_size)) { > + int i; > + puts("Got TPM Hash response:\n"); > + for (i = 0; i < read_size; i++) > + printf(" %2.2x", tpm_buffer[i]); > + puts("\n"); > + rv = 0; > + } else { > + puts("tpm hash command failed\n"); > + } > + > + if (! > + tis_sendrecv(readpcr17, sizeof(readpcr17), response, &read_size)) { > + int i; > + puts("TPM Read PCR 17 after hash:\n"); > + for (i = 10; i < read_size; i++) > + printf(" %2.2x", response[i]); > + puts("\n"); > + rv = 0; > + } else { > + printf("tpm test readpcr17 failed\n"); > + CHECK(tis_close()); > + } > + > + if (tis_close()) { > + puts("tis_close() failed!\n"); > + rv = -1; > + } > + > + return rv; > +} > + > #define MAKE_TPM_CMD_ENTRY(cmd) \ > U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "") > > @@ -590,6 +710,8 @@ static cmd_tbl_t tpm_commands[] = { > do_tpm_nv_read, "", ""), > U_BOOT_CMD_MKENT(nv_write, 0, 1, > do_tpm_nv_write, "", ""), > + U_BOOT_CMD_MKENT(hash, 0, 1, > + do_tpm_hash, "", ""), > }; > > static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) > diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile > index e8c159c..cbececf 100644 > --- a/drivers/tpm/Makefile > +++ b/drivers/tpm/Makefile > @@ -28,6 +28,7 @@ $(shell mkdir -p $(obj)slb9635_i2c) > COBJS-$(CONFIG_GENERIC_LPC_TPM) = generic_lpc_tpm.o > COBJS-$(CONFIG_INFINEON_TPM_I2C) += tis_i2c.o slb9635_i2c/tpm.o > COBJS-$(CONFIG_INFINEON_TPM_I2C) += slb9635_i2c/tpm_tis_i2c.o > +COBJS-$(CONFIG_ST_TPM_I2C) = tis_i2c.o tpm_i2c_st.o slb9635_i2c/tpm.o > > COBJS := $(COBJS-y) > SRCS := $(COBJS:.o=.c) > diff --git a/drivers/tpm/slb9635_i2c/tpm.c b/drivers/tpm/slb9635_i2c/tpm.c > index 496c48e..c92bd06 100644 > --- a/drivers/tpm/slb9635_i2c/tpm.c > +++ b/drivers/tpm/slb9635_i2c/tpm.c > @@ -444,6 +444,26 @@ int tpm_open(uint32_t dev_addr) > return rc; > } > > +ssize_t tpm_transmit_hash(const unsigned char *buf, size_t bufsiz) > +{ > + ssize_t rc; > + > + struct tpm_chip *chip = &g_chip; > + > + rc = chip->vendor.send_hash(chip, (u8 *)buf, bufsiz); > + if (rc < 0) { > + dev_err(chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc); > + goto out; > + } > + > + dbg_printf("out_recv: reading response...\n"); > + rc = chip->vendor.recv(chip, (u8 *)buf, TPM_BUFSIZE); > + if (rc < 0) > + dev_err(chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); > +out: > + return rc; > +} > + > void tpm_close(void) > { > if (g_chip.is_open) { > diff --git a/drivers/tpm/slb9635_i2c/tpm.h b/drivers/tpm/slb9635_i2c/tpm.h > index 9ddee86..88e0c07 100644 > --- a/drivers/tpm/slb9635_i2c/tpm.h > +++ b/drivers/tpm/slb9635_i2c/tpm.h > @@ -64,6 +64,7 @@ struct tpm_vendor_specific { > int irq; > int (*recv) (struct tpm_chip *, u8 *, size_t); > int (*send) (struct tpm_chip *, u8 *, size_t); > + int (*send_hash) (struct tpm_chip *, u8 *, size_t); > void (*cancel) (struct tpm_chip *); > u8(*status) (struct tpm_chip *); > int locality; > diff --git a/drivers/tpm/tis_i2c.c b/drivers/tpm/tis_i2c.c > index e818fba..36ae544 100644 > --- a/drivers/tpm/tis_i2c.c > +++ b/drivers/tpm/tis_i2c.c > @@ -82,8 +82,13 @@ static int tpm_decode_config(struct tpm *dev) > dev->i2c_bus = i2c_bus; > dev->slave_addr = fdtdec_get_addr(blob, node, "reg"); > #else > + #ifdef CONFIG_INFINEON_TPM_I2C_BUS > dev->i2c_bus = CONFIG_INFINEON_TPM_I2C_BUS; > dev->slave_addr = CONFIG_INFINEON_TPM_I2C_ADDR; > + #else > + dev->i2c_bus = CONFIG_TPM_I2C_BUS; > + dev->slave_addr = CONFIG_TPM_I2C_ADDR; > + #endif > #endif > return 0; > } > @@ -179,3 +184,35 @@ int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size, > > return 0; > } > + > +int tis_sendrecv_hash(const uint8_t *sendbuf, size_t sbuf_size, > + uint8_t *recvbuf, size_t *rbuf_len) > +{ > + int len; > + uint8_t buf[TPM_BUFSIZE]; > + > + if (!tpm.inited) > + return -1; > + > + if (sizeof(buf) < sbuf_size) > + return -1; > + > + memcpy(buf, sendbuf, sbuf_size); > + > + if (tpm_select()) > + return -1; > + > + len = tpm_transmit_hash(buf, sbuf_size); > + > + tpm_deselect(); > + > + if (len < 10) { > + *rbuf_len = 0; > + return -1; > + } > + > + memcpy(recvbuf, buf, len); > + *rbuf_len = len; > + > + return 0; > +} > diff --git a/drivers/tpm/tpm_i2c_st.c b/drivers/tpm/tpm_i2c_st.c > new file mode 100644 > index 0000000..16753f8 > --- /dev/null > +++ b/drivers/tpm/tpm_i2c_st.c > @@ -0,0 +1,599 @@ > +/* > + * STMicroelectronics TPM I2C UBOOT Linux driver for TPM ST33ZP24 > + * Copyright (C) 2013 STMicroelectronics > + * > + * (c) Copyright 2013 Mathias Leblanc <mathias.leblanc@st.com> > + * This file is released under the terms of GPL v2 and any later version > + * See the file COPYING in the root directory of the source tree for details > + * > + * Description: > + * Device driver for TCG/TCPA TPM (trusted platform module). > + * Specifications at www.trustedcomputinggroup.org > + * > + * This device driver implements the TPM interface as defined in > + * the TCG TPM Interface Spec version 1.2, revision 1.0 and the > + * STMicroelectronics I2C Protocol Stack Specification version 1.2.0. > + * > + * It is based on the Linux I2C TPM driver from Peter Huewe, modified > + * from the original tpm > + * device drivers from Leendert van Dorn, Dave Safford, Reiner Sailer > + * and Kyleen Hall. > + * > + * See file CREDITS for list of people who contributed to this > + * project. > + * > + * 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., 59 Temple Place, Suite 330, Boston, > + * MA 02111-1307 USA > + * > + * @Author: Mathias Leblanc tpmsupport@st.com > + * > + * @File: tpm_i2c_st.c > + * > + */ > + > +#include <common.h> > +#include <i2c.h> > +#include <linux/types.h> > + > +#include "slb9635_i2c/compatibility.h" > +#include "slb9635_i2c/tpm.h" > + > +/* max. buffer size supported by our tpm */ > +#ifdef TPM_BUFSIZE > +#undef TPM_BUFSIZE > +#endif What are these for? > + > +#define MINOR_NUM_I2C 224 > + > +#define TPM_ACCESS (0x0) > +#define TPM_STS (0x18) > +#define TPM_HASH_END (0x20) > +#define TPM_DATA_FIFO (0x24) > +#define TPM_HASH_DATA (0x24) > +#define TPM_HASH_START (0x28) > +#define TPM_INTF_CAPABILITY (0x14) > +#define TPM_INT_STATUS (0x10) > +#define TPM_INT_ENABLE (0x08) Don't need () around these > + > +#define TPM_DUMMY_BYTE 0xAA > +#define TPM_WRITE_DIRECTION 0x80 > +#define TPM_HEADER_SIZE 10 > +#define TPM_BUFSIZE 2048 > + > +#define LOCALITY0 0 > +#define LOCALITY4 4 > + > +struct st_tpm_hash { > + int size; > + u8 *data; > +}; > + > +enum stm33zp24_access { > + TPM_ACCESS_VALID = 0x80, > + TPM_ACCESS_ACTIVE_LOCALITY = 0x20, > + TPM_ACCESS_REQUEST_PENDING = 0x04, > + TPM_ACCESS_REQUEST_USE = 0x02, > +}; > + > +enum stm33zp24_status { > + TPM_STS_VALID = 0x80, > + TPM_STS_COMMAND_READY = 0x40, > + TPM_STS_GO = 0x20, > + TPM_STS_DATA_AVAIL = 0x10, > + TPM_STS_DATA_EXPECT = 0x08, > +}; > + > +enum stm33zp24_int_flags { > + TPM_GLOBAL_INT_ENABLE = 0x80, > + TPM_INTF_CMD_READY_INT = 0x080, > + TPM_INTF_FIFO_AVALAIBLE_INT = 0x040, > + TPM_INTF_WAKE_UP_READY_INT = 0x020, > + TPM_INTF_LOC4SOFTRELEASE_INT = 0x008, > + TPM_INTF_LOCALITY_CHANGE_INT = 0x004, > + TPM_INTF_STS_VALID_INT = 0x002, > + TPM_INTF_DATA_AVAIL_INT = 0x001, > +}; > + > +enum tis_defaults { > + TIS_SHORT_TIMEOUT = 750, /* ms */ > + TIS_LONG_TIMEOUT = 2000, /* 2 sec */ > +}; > + > +struct tpm_i2c_ST_dev { > + uint addr; > + u8 buf[TPM_BUFSIZE]; > +}; > + > +static struct tpm_i2c_ST_dev tpm_dev = { > + /* Note: replace with defined addr from board configuration */ > + .addr = CONFIG_TPM_I2C_ADDR > +}; > + > +/* > + * write8_reg > + * Send byte to the TIS register according to the ST33ZP24 I2C protocol. > + * @param: tpm_register, the tpm tis register where the data should be written > + * @param: tpm_data, the tpm_data to write inside the tpm_register > + * @param: tpm_size, The length of the data > + * @return: Returns zero in case of success else the negative error code. > + */ > +static int write8_reg(u8 addr, u8 tpm_register, > + u8 *tpm_data, u16 tpm_size) > +{ > + u8 data; > + data = tpm_register; > + memcpy(&(tpm_dev.buf[0]), &data, sizeof(data)); > + memcpy(&(tpm_dev.buf[0])+1, tpm_data, tpm_size); > + > + return i2c_write(addr, 0, 0, &tpm_dev.buf[0], > + tpm_size + 1); > + > +} /* write8_reg() */ > + > +/* > +* read8_reg > +* Recv byte from the TIS register according to the ST33ZP24 I2C protocol. > +* @param: tpm_register, the tpm tis register where the data should be read > +* @param: tpm_data, the TPM response > +* @param: tpm_size, tpm TPM response size to read. > +* @return: Returns zero in case of success else the negative error code. > +*/ > +static int read8_reg(u8 addr, u8 tpm_register, > +u8 *tpm_data, int tpm_size) > +{ > + u8 status = 0; > + u8 data; > + data = TPM_DUMMY_BYTE; > + status = write8_reg(addr, tpm_register, &data, 1); > + if (status == 0) > + status = i2c_read(addr, 0, 0, tpm_data, tpm_size); > +return status; > +} /* read8_reg() */ > + > +/* > + * I2C_WRITE_DATA > + * Send byte to the TIS register according to the ST33ZP24 I2C protocol. > + * @param: client, the chip description > + * @param: tpm_register, the tpm tis register where the data should be written > + * @param: tpm_data, the tpm_data to write inside the tpm_register > + * @param: tpm_size, The length of the data > + * @return: Returns zero in case of success else the negative error code. > + */ > +#define I2C_WRITE_DATA(client, tpm_register, tpm_data, tpm_size)\ > + (write8_reg(client, tpm_register | \ > + TPM_WRITE_DIRECTION, tpm_data, tpm_size)) > + > +/* > + * I2C_READ_DATA > + * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. > + * @param: tpm, the chip description > + * @param: tpm_register, the tpm tis register where the data should be read > + * @param: tpm_data, the TPM response > + * @param: tpm_size, tpm TPM response size to read. > + * @return: Returns zero in case of success else the negative error code. > + */ > +#define I2C_READ_DATA(client, tpm_register, tpm_data, tpm_size)\ > + (read8_reg(client, tpm_register, tpm_data, tpm_size)) Either remove these macros or just make them static functions. > + > +/* > + * release_locality release the active locality > + * @param: chip, the tpm chip description. > + */ > +static void release_locality(struct tpm_chip *chip) > +{ > + u8 data = TPM_ACCESS_ACTIVE_LOCALITY; > + > + I2C_WRITE_DATA(tpm_dev.addr, TPM_ACCESS, &data, 1); > +} > + > +/* > + * clear_interruption > + * clear the TPM interrupt register. > + * @param: tpm, the chip description > + */ > +static void clear_interruption(u8 addr) > +{ > + u8 interrupt; > + I2C_READ_DATA(tpm_dev.addr, TPM_INT_STATUS, &interrupt, 1); > + I2C_WRITE_DATA(tpm_dev.addr, TPM_INT_STATUS, &interrupt, 1); > + I2C_READ_DATA(tpm_dev.addr, TPM_INT_STATUS, &interrupt, 1); > +} /* clear_interruption() */ > + > +int wait_for_serirq_timeout(struct tpm_chip *chip, int condition, > + unsigned long timeout) > +{ > + int status = 2; > + > + clear_interruption(tpm_dev.addr); > + if (condition) > + status = 1; > + > + return status; > +} > + > +/* > + * check_locality if the locality is active > + * @param: chip, the tpm chip description > + * @return: the active locality or -EACCESS. > + */ > +static int check_locality(struct tpm_chip *chip) > +{ > + u8 data; > + u8 status; > + status = I2C_READ_DATA(tpm_dev.addr, TPM_ACCESS, &data, 1); > + > + if ((status == 0) && (data & > + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == > + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) > + return chip->vendor.locality; > + > + return -EACCES; > + > +} /* check_locality() */ > + > +/* > + * request_locality request the TPM locality > + * @param: chip, the chip description > + * @return: the active locality or EACCESS. > + */ > +static int request_locality(struct tpm_chip *chip) > +{ > + unsigned long start, stop; > + long rc; > + u8 data; > + if (check_locality(chip) == chip->vendor.locality) > + return chip->vendor.locality; > + > + data = TPM_ACCESS_REQUEST_USE; > + rc = I2C_WRITE_DATA(tpm_dev.addr, TPM_ACCESS, &data, 1); > + if (rc < 0) > + goto end; > + > + if (chip->vendor.irq) { > + rc = wait_for_serirq_timeout(chip, (check_locality > + (chip) >= 0), > + chip->vendor.timeout_a); > + if (rc > 0) > + return chip->vendor.locality; > + } else{ > + /* wait for locality activated */ > + start = get_timer(0); > + stop = chip->vendor.timeout_a; > + do { > + if (check_locality(chip) >= 0) > + return chip->vendor.locality; > + > + msleep(TPM_TIMEOUT); > + } while (get_timer(start) < stop); > + } > + rc = -EACCES; > +end: > + return rc; > +} /* request_locality() */ > + > +/* > + * tpm_stm_i2c_cancel, cancel is not implemented. > + * @param: chip, tpm_chip description. > + */ > +static void tpm_stm_i2c_cancel(struct tpm_chip *chip) > +{ > + u8 data; > + > + data = TPM_STS_COMMAND_READY; > + I2C_WRITE_DATA(tpm_dev.addr, TPM_STS, &data, 1); > + if (chip->vendor.irq) > + wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a); > +} /* tpm_stm_i2c_cancel() */ > + > +/* > + * tpm_stm_spi_status return the TPM_STS register > + * @param: chip, the tpm chip description > + * @return: the TPM_STS register value. > + */ > +static u8 tpm_stm_i2c_status(struct tpm_chip *chip) > +{ > + u8 data; > + I2C_READ_DATA(tpm_dev.addr, TPM_STS, &data, 1); > + return data; > +} /* tpm_stm_i2c_status() */ > + > +/* > + * get_burstcount return the burstcount address 0x19 0x1A > + * @param: chip, the chip description > + * return: the burstcount. > + */ > +static int get_burstcount(struct tpm_chip *chip) > +{ > + unsigned long start, stop; > + int burstcnt, status; > + u8 tpm_reg, temp; > + > + /* wait for burstcount */ > + /* which timeout value, spec has 2 answers (c & d) */ > + start = get_timer(0); > + stop = chip->vendor.timeout_d; > + do { > + tpm_reg = TPM_STS + 1; > + status = I2C_READ_DATA(tpm_dev.addr, tpm_reg, &temp, 1); > + if (status < 0) > + goto end; > + > + tpm_reg = tpm_reg + 1; > + burstcnt = temp; > + status = I2C_READ_DATA(tpm_dev.addr, tpm_reg, &temp, 1); > + if (status < 0) > + goto end; > + > + burstcnt |= temp << 8; > + if (burstcnt) > + return burstcnt; > + > + msleep(TPM_TIMEOUT); > + } while (get_timer(start) < stop); > + > +end: > + return -EBUSY; > +} /* get_burstcount() */ > + > + > +/* > + * recv_data receive data > + * @param: chip, the tpm chip description > + * @param: buf, the buffer where the data are received > + * @param: count, the number of data to receive > + * @return: the number of bytes read from TPM FIFO. > + */ > +static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) > +{ > + int size = 0, burstcnt, len; > + > + while (size < count) { > + burstcnt = get_burstcount(chip); > + len = count - size; > + if ((len) > burstcnt) > + len = burstcnt; > + if ( > + I2C_READ_DATA(tpm_dev.addr, TPM_DATA_FIFO, buf + size, len) == 0) > + size += len; > + else > + break; > + } > + return size; > +} /* recv_data() */ > + > +/* > + * tpm_stm_i2c_recv received TPM response through the I2C bus. > + * @param: chip, tpm_chip description. > + * @param: buf, the buffer to store datas. > + * @param: count, the number of bytes to send. > + * @return: Returns zero in case of success else the negative error code. > + */ > +static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, > + size_t count) > +{ > + int size = 0; > + int expected; > + > + if (chip == NULL) > + return -EBUSY; > + > + if (count < TPM_HEADER_SIZE) { > + size = -EIO; > + goto out; > + } > + > + size = recv_data(chip, buf, TPM_HEADER_SIZE); > + if (size < TPM_HEADER_SIZE) { > + dev_err(chip->dev, "Unable to read header\n"); > + goto out; > + } > + > + > + expected = get_unaligned_be32(buf + TPM_RSP_SIZE_BYTE); > + if (expected > count) { > + size = -EIO; > + goto out; > + } > + > + size += recv_data(chip, &buf[TPM_HEADER_SIZE], > + expected - TPM_HEADER_SIZE); > + if (size < expected) { > + dev_err(chip->dev, "Unable to read remainder of result\n"); > + size = -ETIME; > + goto out; > + } > + > +out: > + chip->vendor.cancel(chip); > + release_locality(chip); > + return size; > +} /* tpm_stm_i2c_recv() */ > + > +/* > + * tpm_stm_i2c_send send TPM commands through the I2C bus. > + * > + * @param: chip, tpm_chip description. > + * @param: buf, the buffer to send. > + * @param: len, the number of bytes to send. > + * @return: Returns zero in case of success else the negative error code. > + */ > +static int tpm_stm_i2c_send(struct tpm_chip *chip, u8 *buf, > + size_t len) > +{ > + u32 ret = 0, > + status, > + burstcnt = 0, i, size; > + u8 data; > + > + if (chip == NULL) > + return -EBUSY; > + if (len < TPM_HEADER_SIZE) > + return -EBUSY; > + > + ret = request_locality(chip); > + if (ret < 0) > + return ret; > + > + status = tpm_stm_i2c_status(chip); > + if ((status & TPM_STS_COMMAND_READY) == 0) > + tpm_stm_i2c_cancel(chip); > + > + for (i = 0; i < len - 1;) { > + burstcnt = get_burstcount(chip); > + size = len - i - 1; > + if ((size) > burstcnt) > + size = burstcnt; > + ret = I2C_WRITE_DATA(tpm_dev.addr, TPM_DATA_FIFO, buf, size); > + if (ret < 0) > + goto out_err; > + > + i += size; > + } > + > + status = tpm_stm_i2c_status(chip); > + if ((status & TPM_STS_DATA_EXPECT) == 0) { > + ret = -EIO; > + goto out_err; > + } > + > + ret = I2C_WRITE_DATA(tpm_dev.addr, TPM_DATA_FIFO, buf + len - 1, 1); > + if (ret < 0) > + goto out_err; > + > + status = tpm_stm_i2c_status(chip); > + if ((status & TPM_STS_DATA_EXPECT) != 0) { > + ret = -EIO; > + goto out_err; > + } > + > + data = TPM_STS_GO; > + I2C_WRITE_DATA(tpm_dev.addr, TPM_STS, &data, 1); > + > + return len; > +out_err: > + tpm_stm_i2c_cancel(chip); > + release_locality(chip); Add debug() on error path? > + return ret; > +} /* tpm_stm_i2c_send() */ > + > +/* > + * tpm_stm_i2c_send_hash send TPM locality 4 hash datas through the I2C bus > + * to update the PCR[17]. > + * @param: chip, the tpm_chip description. > + * @param: buf, the data buffer to send. > + * @param: len, the number of bytes to send. > + * @return: Returns zero in case of success else the negative error code. > + */ > +static int tpm_stm_i2c_send_hash(struct tpm_chip *chip, unsigned char *buf, > + size_t len) > +{ > + u32 ret = 0; > + u8 data; > + > + if (chip == NULL) > + return -EBUSY; Why does NULL mean busy? Shouldn't it be -ENODEV? > + > + release_locality(chip); > + > + tpm_dev.addr = 0x1B; > + chip->vendor.locality = LOCALITY4; > + > + data = TPM_DUMMY_BYTE; > + ret = I2C_WRITE_DATA(tpm_dev.addr, TPM_HASH_START, &data, 1); > + if (ret < 0) > + goto end; > + ret = I2C_WRITE_DATA(tpm_dev.addr, TPM_DATA_FIFO, buf, len); > + if (ret < 0) > + goto end; > + > +end: > + I2C_WRITE_DATA(tpm_dev.addr, TPM_HASH_END, &data, 1); > + release_locality(chip); > + chip->vendor.locality = LOCALITY0; > + tpm_dev.addr = 0x13; > + ret = request_locality(chip); > + return ret; > +} /* tpm_stm_i2c_send_hash */ > + > +static struct tpm_vendor_specific st_i2c_tpm = { > + .send = tpm_stm_i2c_send, > + .send_hash = tpm_stm_i2c_send_hash, > + .recv = tpm_stm_i2c_recv, > + .cancel = tpm_stm_i2c_cancel, > + .status = tpm_stm_i2c_status, > + .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, > + .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, > + .req_canceled = TPM_STS_COMMAND_READY, > +}; > + > +/* > + * tpm_vendor_init initialize the TPM device > + * @param: dev_addr, the i2c address of the tpm. > + * @return: 0 in case of success. > + * -1 in other case. > + */ > +int tpm_vendor_init(uint32_t dev_addr) > +{ > + u32 vendor; > + uint old_addr; > + int rc = 0; > + struct tpm_chip *chip; > + > + old_addr = tpm_dev.addr; > + if (dev_addr != 0) > + tpm_dev.addr = dev_addr; > + > + chip = tpm_register_hardware(&st_i2c_tpm); > + > + if (chip < 0) { > + rc = -ENODEV; > + goto out_err; > + } > + > + /* Default timeouts */ > + chip->vendor.timeout_a = TIS_SHORT_TIMEOUT; > + chip->vendor.timeout_b = TIS_LONG_TIMEOUT; > + chip->vendor.timeout_c = TIS_SHORT_TIMEOUT; > + chip->vendor.timeout_d = TIS_SHORT_TIMEOUT; > + > + chip->vendor.locality = LOCALITY0; > + > + if (request_locality(chip) != 0) { > + rc = -ENODEV; > + goto out_err; > + } > + > + vendor = be32_to_cpu(vendor); > + > + > + dev_info(dev, "1.2 TPM STMicroelectronics"); > + /* > + * A timeout query to TPM can be placed here. > + * Standard timeout values are used so far > + */ > + > + return 0; > + > +out_err: > + tpm_dev.addr = old_addr; > + return rc; > +} /* tpm_vendor_init() */ > + > + > + > +void tpm_vendor_cleanup(struct tpm_chip *chip) > +{ > + release_locality(chip); > +} /* tpm_vendor_cleanup() */ > diff --git a/include/configs/omap3_beagle.h b/include/configs/omap3_beagle.h > index 48ce4c0..ef381f8 100644 > --- a/include/configs/omap3_beagle.h > +++ b/include/configs/omap3_beagle.h > @@ -111,6 +111,14 @@ > #define STATUS_LED_BOOT STATUS_LED_BIT > #define STATUS_LED_GREEN STATUS_LED_BIT1 > > +/* TPM */ > +#define CONFIG_CMD_TPM > +#define CONFIG_TPM > +#define CONFIG_ST_TPM_DEBUG > +#define CONFIG_ST_TPM_I2C > +#define CONFIG_TPM_I2C_BUS 1 > +#define CONFIG_TPM_I2C_ADDR 0x13 > + > /* Enable Multi Bus support for I2C */ > #define CONFIG_I2C_MULTI_BUS 1 > > diff --git a/include/tpm.h b/include/tpm.h > index 7219b73..36ba0bb 100644 > --- a/include/tpm.h > +++ b/include/tpm.h > @@ -201,4 +201,22 @@ uint32_t tpm_physical_set_deactivated(uint8_t state); > uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap, > void *cap, size_t count); > > +/* > + * tis_sendrecv_hash() > + * > + * Send the requested data to the TPM for hash in LOC 4 > + * and then try to get its response > + * > + * @sendbuf - buffer of the data to hash > + * @send_size size of the data to send > + * @recvbuf - memory to save the response to > + * @recv_len - pointer to the size of the response buffer > + * > + * Returns 0 on success (and places the number of response bytes at recv_len) > + * or -1 on failure. > + */ > +int tis_sendrecv_hash(const uint8_t *sendbuf, size_t send_size, > + uint8_t *recvbuf, > + size_t *recv_len); > + > #endif /* __TPM_H */ > -- > 1.7.9.5 > Regards, Simon
Hi, On 22 October 2013 09:48, Simon Glass <sjg@chromium.org> wrote: > Hi Mathias, > > On Wed, May 15, 2013 at 7:58 AM, Mathias leblanc <mathias.leblanc@st.com> wrote: >> From: Mathias Leblanc <mathias.leblanc@st.com> >> >> * STMicroelectronics version 1.2.0, Copyright (C) 2013 >> * This is free software, and you are welcome to redistribute it. >> >> This is the u-boot driver for TPM chip from ST Microelectronics. >> >> If you have a TPM security chip from STMicroelectronics working with >> an I2C, read the README file and add the correct defines regarding >> the tpm in the configuration file of your board. >> This file is located in include/configs/your_board.h >> >> The tpm command will be accessible from within uboot terminal. >> >> Signed-off-by: Mathias Leblanc <mathias.leblanc@st.com> > > It would be good to apply this patch in this merge window. Can you > please do a few tidy-ups? I have not had a response back - it seems that Mathias has moved on. So I am dropping this patch. If anyone wants to pick it up and finish it, please go ahead. Regards, Simon
On 16 February 2014 15:46, Simon Glass <sjg@chromium.org> wrote: > Hi, > > On 22 October 2013 09:48, Simon Glass <sjg@chromium.org> wrote: >> Hi Mathias, >> >> On Wed, May 15, 2013 at 7:58 AM, Mathias leblanc <mathias.leblanc@st.com> wrote: >>> From: Mathias Leblanc <mathias.leblanc@st.com> >>> >>> * STMicroelectronics version 1.2.0, Copyright (C) 2013 >>> * This is free software, and you are welcome to redistribute it. >>> >>> This is the u-boot driver for TPM chip from ST Microelectronics. >>> >>> If you have a TPM security chip from STMicroelectronics working with >>> an I2C, read the README file and add the correct defines regarding >>> the tpm in the configuration file of your board. >>> This file is located in include/configs/your_board.h >>> >>> The tpm command will be accessible from within uboot terminal. >>> >>> Signed-off-by: Mathias Leblanc <mathias.leblanc@st.com> >> >> It would be good to apply this patch in this merge window. Can you >> please do a few tidy-ups? > > I have not had a response back - it seems that Mathias has moved on. > So I am dropping this patch. If anyone wants to pick it up and finish > it, please go ahead. Adding Benoit as suggested. > > Regards, > Simon
Hi Jean-Luc, On 22 October 2013 09:48, Simon Glass <sjg@chromium.org> wrote: > Hi Mathias, > > On Wed, May 15, 2013 at 7:58 AM, Mathias leblanc <mathias.leblanc@st.com> wrote: >> From: Mathias Leblanc <mathias.leblanc@st.com> >> >> * STMicroelectronics version 1.2.0, Copyright (C) 2013 >> * This is free software, and you are welcome to redistribute it. >> >> This is the u-boot driver for TPM chip from ST Microelectronics. >> >> If you have a TPM security chip from STMicroelectronics working with >> an I2C, read the README file and add the correct defines regarding >> the tpm in the configuration file of your board. >> This file is located in include/configs/your_board.h >> >> The tpm command will be accessible from within uboot terminal. >> >> Signed-off-by: Mathias Leblanc <mathias.leblanc@st.com> > > It would be good to apply this patch in this merge window. Can you > please do a few tidy-ups? This is the email with my comments. > >> --- >> README | 14 +- >> common/cmd_tpm.c | 122 ++++++++ >> drivers/tpm/Makefile | 1 + >> drivers/tpm/slb9635_i2c/tpm.c | 20 ++ >> drivers/tpm/slb9635_i2c/tpm.h | 1 + >> drivers/tpm/tis_i2c.c | 37 +++ >> drivers/tpm/tpm_i2c_st.c | 599 ++++++++++++++++++++++++++++++++++++++++ >> include/configs/omap3_beagle.h | 8 + > > Please split the driver, command change (cmd_tpm.c) and the CONFIG > change (this file) into three separate patches. > >> include/tpm.h | 18 ++ >> 9 files changed, 819 insertions(+), 1 deletion(-) >> create mode 100644 drivers/tpm/tpm_i2c_st.c >> >> diff --git a/README b/README >> index 0d37d56..a72b570 100644 >> --- a/README >> +++ b/README >> @@ -1208,7 +1208,7 @@ The following options need to be configured: >> If this option is set, the driver enables cache flush. >> >> - TPM Support: >> - CONFIG_GENERIC_LPC_TPM >> + CONFIG_TPM >> Support for generic parallel port TPM devices. Only one device >> per system is supported at this time. >> >> @@ -1217,6 +1217,18 @@ The following options need to be configured: >> to. Contemporary x86 systems usually map it at >> 0xfed40000. >> >> + CONFIG_ST_TPM_I2C >> + Define to compile the ST TPM I2C DRIVER. >> + >> + CONFIG_TPM_I2C_BUS >> + Define the bus number of the board. >> + >> + CONFIG_TPM_I2C_ADDR >> + Define the address of the TPM. >> + >> + CONFIG_CMD_TPM >> + Define to use some TPM u-boot commands. >> + >> - USB Support: >> At the moment only the UHCI host controller is >> supported (PIP405, MIP405, MPC5200); define >> diff --git a/common/cmd_tpm.c b/common/cmd_tpm.c >> index 46fae18..fba1fe7 100644 >> --- a/common/cmd_tpm.c >> +++ b/common/cmd_tpm.c >> @@ -27,6 +27,14 @@ >> #include <asm/unaligned.h> >> #include <linux/string.h> >> >> +#define MAX_TRANSACTION_SIZE 30 >> +#define CHECK(exp) do { \ >> + int _rv = exp; \ >> + if (_rv) { \ >> + printf("CHECK: %s %d %x\n", #exp, __LINE__, _rv);\ >> + } \ >> + } while (0) >> + >> /** >> * Print a byte string in hexdecimal format, 16-bytes per line. >> * >> @@ -546,6 +554,118 @@ static int do_tpm_nv_write(cmd_tbl_t *cmdtp, int flag, >> return convert_return_code(err); >> } >> >> +static int do_tpm_hash(cmd_tbl_t *cmdtp, int flag, int argc, >> +char * const argv[]) >> +{ >> + u8 tpm_buffer[MAX_TRANSACTION_SIZE]; >> + u32 write_size, read_size; >> + char *p; >> + int rv = -1; >> + argc -= 1; >> + argv += 1; >> + uint8_t response[1024]; >> + size_t rlength = MAX_TRANSACTION_SIZE; >> + >> + u8 startup[] = { >> + 0x00, 0xc1, >> + 0x00, 0x00, 0x00, 0x0c, >> + 0x00, 0x00, 0x00, 0x99, >> + 0x00, 0x01 >> + }; >> + >> + u8 selftestfull[] = { >> + 0x00, 0xc1, >> + 0x00, 0x00, 0x00, 0x0a, >> + 0x00, 0x00, 0x00, 0x50 >> + }; >> + >> + u8 readpcr17[] = { >> + 0x00, 0xc1, >> + 0x00, 0x00, 0x00, 0x0e, >> + 0x00, 0x00, 0x00, 0x15, >> + 0x00, 0x00, 0x00, 0x11 >> + }; >> + >> + for (write_size = 0; write_size < argc; write_size++) { >> + u32 datum = kstrtoul(argv[write_size], &p, 0); >> + if (*p || (datum > 0xff)) { >> + printf("\n%s: bad data value\n\n", argv[write_size]); >> + cmd_usage(cmdtp); >> + return rv; >> + } >> + tpm_buffer[write_size] = (u8)datum; >> + } >> + >> + if (tis_init()) { >> + puts("tis_init() failed!\n"); >> + return -1; >> + } >> + >> + if (tis_open()) { >> + puts("tis_open() failed!\n"); >> + return -1; >> + } >> + >> + rv = tis_sendrecv(startup, sizeof(startup), response, &rlength); >> + if (rv) { >> + printf("tpm test startup failed\n"); >> + CHECK(tis_close()); >> + } >> + >> + rv = tis_sendrecv(selftestfull, sizeof(selftestfull), response, >> + &rlength); >> + if (rv) { >> + printf("tpm test selftestfull failed\n"); >> + CHECK(tis_close()); >> + } >> + >> + if (! >> + tis_sendrecv(readpcr17, sizeof(readpcr17), response, &read_size)) { >> + int i; > > Blank line between declarations and body of function. Please fix globally. > >> + puts("TPM Read PCR 17:\n"); >> + for (i = 10; i < read_size; i++) >> + printf(" %2.2x", response[i]); >> + puts("\n"); >> + rv = 0; >> + } else { > > Suspect indenting here, please fix globally. > >> + printf("tpm test readpcr17 failed\n"); >> + CHECK(tis_close()); >> + } >> + >> + read_size = sizeof(tpm_buffer); >> + if (! > > Remove newline here. Please fix below also. > >> + tis_sendrecv_hash(tpm_buffer, write_size, tpm_buffer, &read_size)) { >> + int i; >> + puts("Got TPM Hash response:\n"); >> + for (i = 0; i < read_size; i++) >> + printf(" %2.2x", tpm_buffer[i]); >> + puts("\n"); >> + rv = 0; >> + } else { >> + puts("tpm hash command failed\n"); >> + } >> + >> + if (! >> + tis_sendrecv(readpcr17, sizeof(readpcr17), response, &read_size)) { >> + int i; >> + puts("TPM Read PCR 17 after hash:\n"); >> + for (i = 10; i < read_size; i++) >> + printf(" %2.2x", response[i]); >> + puts("\n"); >> + rv = 0; >> + } else { >> + printf("tpm test readpcr17 failed\n"); >> + CHECK(tis_close()); >> + } >> + >> + if (tis_close()) { >> + puts("tis_close() failed!\n"); >> + rv = -1; >> + } >> + >> + return rv; >> +} >> + >> #define MAKE_TPM_CMD_ENTRY(cmd) \ >> U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "") >> >> @@ -590,6 +710,8 @@ static cmd_tbl_t tpm_commands[] = { >> do_tpm_nv_read, "", ""), >> U_BOOT_CMD_MKENT(nv_write, 0, 1, >> do_tpm_nv_write, "", ""), >> + U_BOOT_CMD_MKENT(hash, 0, 1, >> + do_tpm_hash, "", ""), >> }; >> >> static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) >> diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile >> index e8c159c..cbececf 100644 >> --- a/drivers/tpm/Makefile >> +++ b/drivers/tpm/Makefile >> @@ -28,6 +28,7 @@ $(shell mkdir -p $(obj)slb9635_i2c) >> COBJS-$(CONFIG_GENERIC_LPC_TPM) = generic_lpc_tpm.o >> COBJS-$(CONFIG_INFINEON_TPM_I2C) += tis_i2c.o slb9635_i2c/tpm.o >> COBJS-$(CONFIG_INFINEON_TPM_I2C) += slb9635_i2c/tpm_tis_i2c.o >> +COBJS-$(CONFIG_ST_TPM_I2C) = tis_i2c.o tpm_i2c_st.o slb9635_i2c/tpm.o >> >> COBJS := $(COBJS-y) >> SRCS := $(COBJS:.o=.c) >> diff --git a/drivers/tpm/slb9635_i2c/tpm.c b/drivers/tpm/slb9635_i2c/tpm.c >> index 496c48e..c92bd06 100644 >> --- a/drivers/tpm/slb9635_i2c/tpm.c >> +++ b/drivers/tpm/slb9635_i2c/tpm.c >> @@ -444,6 +444,26 @@ int tpm_open(uint32_t dev_addr) >> return rc; >> } >> >> +ssize_t tpm_transmit_hash(const unsigned char *buf, size_t bufsiz) >> +{ >> + ssize_t rc; >> + >> + struct tpm_chip *chip = &g_chip; >> + >> + rc = chip->vendor.send_hash(chip, (u8 *)buf, bufsiz); >> + if (rc < 0) { >> + dev_err(chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc); >> + goto out; >> + } >> + >> + dbg_printf("out_recv: reading response...\n"); >> + rc = chip->vendor.recv(chip, (u8 *)buf, TPM_BUFSIZE); >> + if (rc < 0) >> + dev_err(chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); >> +out: >> + return rc; >> +} >> + >> void tpm_close(void) >> { >> if (g_chip.is_open) { >> diff --git a/drivers/tpm/slb9635_i2c/tpm.h b/drivers/tpm/slb9635_i2c/tpm.h >> index 9ddee86..88e0c07 100644 >> --- a/drivers/tpm/slb9635_i2c/tpm.h >> +++ b/drivers/tpm/slb9635_i2c/tpm.h >> @@ -64,6 +64,7 @@ struct tpm_vendor_specific { >> int irq; >> int (*recv) (struct tpm_chip *, u8 *, size_t); >> int (*send) (struct tpm_chip *, u8 *, size_t); >> + int (*send_hash) (struct tpm_chip *, u8 *, size_t); >> void (*cancel) (struct tpm_chip *); >> u8(*status) (struct tpm_chip *); >> int locality; >> diff --git a/drivers/tpm/tis_i2c.c b/drivers/tpm/tis_i2c.c >> index e818fba..36ae544 100644 >> --- a/drivers/tpm/tis_i2c.c >> +++ b/drivers/tpm/tis_i2c.c >> @@ -82,8 +82,13 @@ static int tpm_decode_config(struct tpm *dev) >> dev->i2c_bus = i2c_bus; >> dev->slave_addr = fdtdec_get_addr(blob, node, "reg"); >> #else >> + #ifdef CONFIG_INFINEON_TPM_I2C_BUS >> dev->i2c_bus = CONFIG_INFINEON_TPM_I2C_BUS; >> dev->slave_addr = CONFIG_INFINEON_TPM_I2C_ADDR; >> + #else >> + dev->i2c_bus = CONFIG_TPM_I2C_BUS; >> + dev->slave_addr = CONFIG_TPM_I2C_ADDR; >> + #endif >> #endif >> return 0; >> } >> @@ -179,3 +184,35 @@ int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size, >> >> return 0; >> } >> + >> +int tis_sendrecv_hash(const uint8_t *sendbuf, size_t sbuf_size, >> + uint8_t *recvbuf, size_t *rbuf_len) >> +{ >> + int len; >> + uint8_t buf[TPM_BUFSIZE]; >> + >> + if (!tpm.inited) >> + return -1; >> + >> + if (sizeof(buf) < sbuf_size) >> + return -1; >> + >> + memcpy(buf, sendbuf, sbuf_size); >> + >> + if (tpm_select()) >> + return -1; >> + >> + len = tpm_transmit_hash(buf, sbuf_size); >> + >> + tpm_deselect(); >> + >> + if (len < 10) { >> + *rbuf_len = 0; >> + return -1; >> + } >> + >> + memcpy(recvbuf, buf, len); >> + *rbuf_len = len; >> + >> + return 0; >> +} >> diff --git a/drivers/tpm/tpm_i2c_st.c b/drivers/tpm/tpm_i2c_st.c >> new file mode 100644 >> index 0000000..16753f8 >> --- /dev/null >> +++ b/drivers/tpm/tpm_i2c_st.c >> @@ -0,0 +1,599 @@ >> +/* >> + * STMicroelectronics TPM I2C UBOOT Linux driver for TPM ST33ZP24 >> + * Copyright (C) 2013 STMicroelectronics >> + * >> + * (c) Copyright 2013 Mathias Leblanc <mathias.leblanc@st.com> >> + * This file is released under the terms of GPL v2 and any later version >> + * See the file COPYING in the root directory of the source tree for details >> + * >> + * Description: >> + * Device driver for TCG/TCPA TPM (trusted platform module). >> + * Specifications at www.trustedcomputinggroup.org >> + * >> + * This device driver implements the TPM interface as defined in >> + * the TCG TPM Interface Spec version 1.2, revision 1.0 and the >> + * STMicroelectronics I2C Protocol Stack Specification version 1.2.0. >> + * >> + * It is based on the Linux I2C TPM driver from Peter Huewe, modified >> + * from the original tpm >> + * device drivers from Leendert van Dorn, Dave Safford, Reiner Sailer >> + * and Kyleen Hall. >> + * >> + * See file CREDITS for list of people who contributed to this >> + * project. >> + * >> + * 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., 59 Temple Place, Suite 330, Boston, >> + * MA 02111-1307 USA >> + * >> + * @Author: Mathias Leblanc tpmsupport@st.com >> + * >> + * @File: tpm_i2c_st.c >> + * >> + */ >> + >> +#include <common.h> >> +#include <i2c.h> >> +#include <linux/types.h> >> + >> +#include "slb9635_i2c/compatibility.h" >> +#include "slb9635_i2c/tpm.h" >> + >> +/* max. buffer size supported by our tpm */ >> +#ifdef TPM_BUFSIZE >> +#undef TPM_BUFSIZE >> +#endif > > What are these for? > >> + >> +#define MINOR_NUM_I2C 224 >> + >> +#define TPM_ACCESS (0x0) >> +#define TPM_STS (0x18) >> +#define TPM_HASH_END (0x20) >> +#define TPM_DATA_FIFO (0x24) >> +#define TPM_HASH_DATA (0x24) >> +#define TPM_HASH_START (0x28) >> +#define TPM_INTF_CAPABILITY (0x14) >> +#define TPM_INT_STATUS (0x10) >> +#define TPM_INT_ENABLE (0x08) > > Don't need () around these > >> + >> +#define TPM_DUMMY_BYTE 0xAA >> +#define TPM_WRITE_DIRECTION 0x80 >> +#define TPM_HEADER_SIZE 10 >> +#define TPM_BUFSIZE 2048 >> + >> +#define LOCALITY0 0 >> +#define LOCALITY4 4 >> + >> +struct st_tpm_hash { >> + int size; >> + u8 *data; >> +}; >> + >> +enum stm33zp24_access { >> + TPM_ACCESS_VALID = 0x80, >> + TPM_ACCESS_ACTIVE_LOCALITY = 0x20, >> + TPM_ACCESS_REQUEST_PENDING = 0x04, >> + TPM_ACCESS_REQUEST_USE = 0x02, >> +}; >> + >> +enum stm33zp24_status { >> + TPM_STS_VALID = 0x80, >> + TPM_STS_COMMAND_READY = 0x40, >> + TPM_STS_GO = 0x20, >> + TPM_STS_DATA_AVAIL = 0x10, >> + TPM_STS_DATA_EXPECT = 0x08, >> +}; >> + >> +enum stm33zp24_int_flags { >> + TPM_GLOBAL_INT_ENABLE = 0x80, >> + TPM_INTF_CMD_READY_INT = 0x080, >> + TPM_INTF_FIFO_AVALAIBLE_INT = 0x040, >> + TPM_INTF_WAKE_UP_READY_INT = 0x020, >> + TPM_INTF_LOC4SOFTRELEASE_INT = 0x008, >> + TPM_INTF_LOCALITY_CHANGE_INT = 0x004, >> + TPM_INTF_STS_VALID_INT = 0x002, >> + TPM_INTF_DATA_AVAIL_INT = 0x001, >> +}; >> + >> +enum tis_defaults { >> + TIS_SHORT_TIMEOUT = 750, /* ms */ >> + TIS_LONG_TIMEOUT = 2000, /* 2 sec */ >> +}; >> + >> +struct tpm_i2c_ST_dev { >> + uint addr; >> + u8 buf[TPM_BUFSIZE]; >> +}; >> + >> +static struct tpm_i2c_ST_dev tpm_dev = { >> + /* Note: replace with defined addr from board configuration */ >> + .addr = CONFIG_TPM_I2C_ADDR >> +}; >> + >> +/* >> + * write8_reg >> + * Send byte to the TIS register according to the ST33ZP24 I2C protocol. >> + * @param: tpm_register, the tpm tis register where the data should be written >> + * @param: tpm_data, the tpm_data to write inside the tpm_register >> + * @param: tpm_size, The length of the data >> + * @return: Returns zero in case of success else the negative error code. >> + */ >> +static int write8_reg(u8 addr, u8 tpm_register, >> + u8 *tpm_data, u16 tpm_size) >> +{ >> + u8 data; >> + data = tpm_register; >> + memcpy(&(tpm_dev.buf[0]), &data, sizeof(data)); >> + memcpy(&(tpm_dev.buf[0])+1, tpm_data, tpm_size); >> + >> + return i2c_write(addr, 0, 0, &tpm_dev.buf[0], >> + tpm_size + 1); >> + >> +} /* write8_reg() */ >> + >> +/* >> +* read8_reg >> +* Recv byte from the TIS register according to the ST33ZP24 I2C protocol. >> +* @param: tpm_register, the tpm tis register where the data should be read >> +* @param: tpm_data, the TPM response >> +* @param: tpm_size, tpm TPM response size to read. >> +* @return: Returns zero in case of success else the negative error code. >> +*/ >> +static int read8_reg(u8 addr, u8 tpm_register, >> +u8 *tpm_data, int tpm_size) >> +{ >> + u8 status = 0; >> + u8 data; >> + data = TPM_DUMMY_BYTE; >> + status = write8_reg(addr, tpm_register, &data, 1); >> + if (status == 0) >> + status = i2c_read(addr, 0, 0, tpm_data, tpm_size); >> +return status; >> +} /* read8_reg() */ >> + >> +/* >> + * I2C_WRITE_DATA >> + * Send byte to the TIS register according to the ST33ZP24 I2C protocol. >> + * @param: client, the chip description >> + * @param: tpm_register, the tpm tis register where the data should be written >> + * @param: tpm_data, the tpm_data to write inside the tpm_register >> + * @param: tpm_size, The length of the data >> + * @return: Returns zero in case of success else the negative error code. >> + */ >> +#define I2C_WRITE_DATA(client, tpm_register, tpm_data, tpm_size)\ >> + (write8_reg(client, tpm_register | \ >> + TPM_WRITE_DIRECTION, tpm_data, tpm_size)) >> + >> +/* >> + * I2C_READ_DATA >> + * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. >> + * @param: tpm, the chip description >> + * @param: tpm_register, the tpm tis register where the data should be read >> + * @param: tpm_data, the TPM response >> + * @param: tpm_size, tpm TPM response size to read. >> + * @return: Returns zero in case of success else the negative error code. >> + */ >> +#define I2C_READ_DATA(client, tpm_register, tpm_data, tpm_size)\ >> + (read8_reg(client, tpm_register, tpm_data, tpm_size)) > > Either remove these macros or just make them static functions. > >> + >> +/* >> + * release_locality release the active locality >> + * @param: chip, the tpm chip description. >> + */ >> +static void release_locality(struct tpm_chip *chip) >> +{ >> + u8 data = TPM_ACCESS_ACTIVE_LOCALITY; >> + >> + I2C_WRITE_DATA(tpm_dev.addr, TPM_ACCESS, &data, 1); >> +} >> + >> +/* >> + * clear_interruption >> + * clear the TPM interrupt register. >> + * @param: tpm, the chip description >> + */ >> +static void clear_interruption(u8 addr) >> +{ >> + u8 interrupt; >> + I2C_READ_DATA(tpm_dev.addr, TPM_INT_STATUS, &interrupt, 1); >> + I2C_WRITE_DATA(tpm_dev.addr, TPM_INT_STATUS, &interrupt, 1); >> + I2C_READ_DATA(tpm_dev.addr, TPM_INT_STATUS, &interrupt, 1); >> +} /* clear_interruption() */ >> + >> +int wait_for_serirq_timeout(struct tpm_chip *chip, int condition, >> + unsigned long timeout) >> +{ >> + int status = 2; >> + >> + clear_interruption(tpm_dev.addr); >> + if (condition) >> + status = 1; >> + >> + return status; >> +} >> + >> +/* >> + * check_locality if the locality is active >> + * @param: chip, the tpm chip description >> + * @return: the active locality or -EACCESS. >> + */ >> +static int check_locality(struct tpm_chip *chip) >> +{ >> + u8 data; >> + u8 status; >> + status = I2C_READ_DATA(tpm_dev.addr, TPM_ACCESS, &data, 1); >> + >> + if ((status == 0) && (data & >> + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == >> + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) >> + return chip->vendor.locality; >> + >> + return -EACCES; >> + >> +} /* check_locality() */ >> + >> +/* >> + * request_locality request the TPM locality >> + * @param: chip, the chip description >> + * @return: the active locality or EACCESS. >> + */ >> +static int request_locality(struct tpm_chip *chip) >> +{ >> + unsigned long start, stop; >> + long rc; >> + u8 data; >> + if (check_locality(chip) == chip->vendor.locality) >> + return chip->vendor.locality; >> + >> + data = TPM_ACCESS_REQUEST_USE; >> + rc = I2C_WRITE_DATA(tpm_dev.addr, TPM_ACCESS, &data, 1); >> + if (rc < 0) >> + goto end; >> + >> + if (chip->vendor.irq) { >> + rc = wait_for_serirq_timeout(chip, (check_locality >> + (chip) >= 0), >> + chip->vendor.timeout_a); >> + if (rc > 0) >> + return chip->vendor.locality; >> + } else{ >> + /* wait for locality activated */ >> + start = get_timer(0); >> + stop = chip->vendor.timeout_a; >> + do { >> + if (check_locality(chip) >= 0) >> + return chip->vendor.locality; >> + >> + msleep(TPM_TIMEOUT); >> + } while (get_timer(start) < stop); >> + } >> + rc = -EACCES; >> +end: >> + return rc; >> +} /* request_locality() */ >> + >> +/* >> + * tpm_stm_i2c_cancel, cancel is not implemented. >> + * @param: chip, tpm_chip description. >> + */ >> +static void tpm_stm_i2c_cancel(struct tpm_chip *chip) >> +{ >> + u8 data; >> + >> + data = TPM_STS_COMMAND_READY; >> + I2C_WRITE_DATA(tpm_dev.addr, TPM_STS, &data, 1); >> + if (chip->vendor.irq) >> + wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a); >> +} /* tpm_stm_i2c_cancel() */ >> + >> +/* >> + * tpm_stm_spi_status return the TPM_STS register >> + * @param: chip, the tpm chip description >> + * @return: the TPM_STS register value. >> + */ >> +static u8 tpm_stm_i2c_status(struct tpm_chip *chip) >> +{ >> + u8 data; >> + I2C_READ_DATA(tpm_dev.addr, TPM_STS, &data, 1); >> + return data; >> +} /* tpm_stm_i2c_status() */ >> + >> +/* >> + * get_burstcount return the burstcount address 0x19 0x1A >> + * @param: chip, the chip description >> + * return: the burstcount. >> + */ >> +static int get_burstcount(struct tpm_chip *chip) >> +{ >> + unsigned long start, stop; >> + int burstcnt, status; >> + u8 tpm_reg, temp; >> + >> + /* wait for burstcount */ >> + /* which timeout value, spec has 2 answers (c & d) */ >> + start = get_timer(0); >> + stop = chip->vendor.timeout_d; >> + do { >> + tpm_reg = TPM_STS + 1; >> + status = I2C_READ_DATA(tpm_dev.addr, tpm_reg, &temp, 1); >> + if (status < 0) >> + goto end; >> + >> + tpm_reg = tpm_reg + 1; >> + burstcnt = temp; >> + status = I2C_READ_DATA(tpm_dev.addr, tpm_reg, &temp, 1); >> + if (status < 0) >> + goto end; >> + >> + burstcnt |= temp << 8; >> + if (burstcnt) >> + return burstcnt; >> + >> + msleep(TPM_TIMEOUT); >> + } while (get_timer(start) < stop); >> + >> +end: >> + return -EBUSY; >> +} /* get_burstcount() */ >> + >> + >> +/* >> + * recv_data receive data >> + * @param: chip, the tpm chip description >> + * @param: buf, the buffer where the data are received >> + * @param: count, the number of data to receive >> + * @return: the number of bytes read from TPM FIFO. >> + */ >> +static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) >> +{ >> + int size = 0, burstcnt, len; >> + >> + while (size < count) { >> + burstcnt = get_burstcount(chip); >> + len = count - size; >> + if ((len) > burstcnt) >> + len = burstcnt; >> + if ( >> + I2C_READ_DATA(tpm_dev.addr, TPM_DATA_FIFO, buf + size, len) == 0) >> + size += len; >> + else >> + break; >> + } >> + return size; >> +} /* recv_data() */ >> + >> +/* >> + * tpm_stm_i2c_recv received TPM response through the I2C bus. >> + * @param: chip, tpm_chip description. >> + * @param: buf, the buffer to store datas. >> + * @param: count, the number of bytes to send. >> + * @return: Returns zero in case of success else the negative error code. >> + */ >> +static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, >> + size_t count) >> +{ >> + int size = 0; >> + int expected; >> + >> + if (chip == NULL) >> + return -EBUSY; >> + >> + if (count < TPM_HEADER_SIZE) { >> + size = -EIO; >> + goto out; >> + } >> + >> + size = recv_data(chip, buf, TPM_HEADER_SIZE); >> + if (size < TPM_HEADER_SIZE) { >> + dev_err(chip->dev, "Unable to read header\n"); >> + goto out; >> + } >> + >> + >> + expected = get_unaligned_be32(buf + TPM_RSP_SIZE_BYTE); >> + if (expected > count) { >> + size = -EIO; >> + goto out; >> + } >> + >> + size += recv_data(chip, &buf[TPM_HEADER_SIZE], >> + expected - TPM_HEADER_SIZE); >> + if (size < expected) { >> + dev_err(chip->dev, "Unable to read remainder of result\n"); >> + size = -ETIME; >> + goto out; >> + } >> + >> +out: >> + chip->vendor.cancel(chip); >> + release_locality(chip); >> + return size; >> +} /* tpm_stm_i2c_recv() */ >> + >> +/* >> + * tpm_stm_i2c_send send TPM commands through the I2C bus. >> + * >> + * @param: chip, tpm_chip description. >> + * @param: buf, the buffer to send. >> + * @param: len, the number of bytes to send. >> + * @return: Returns zero in case of success else the negative error code. >> + */ >> +static int tpm_stm_i2c_send(struct tpm_chip *chip, u8 *buf, >> + size_t len) >> +{ >> + u32 ret = 0, >> + status, >> + burstcnt = 0, i, size; >> + u8 data; >> + >> + if (chip == NULL) >> + return -EBUSY; >> + if (len < TPM_HEADER_SIZE) >> + return -EBUSY; >> + >> + ret = request_locality(chip); >> + if (ret < 0) >> + return ret; >> + >> + status = tpm_stm_i2c_status(chip); >> + if ((status & TPM_STS_COMMAND_READY) == 0) >> + tpm_stm_i2c_cancel(chip); >> + >> + for (i = 0; i < len - 1;) { >> + burstcnt = get_burstcount(chip); >> + size = len - i - 1; >> + if ((size) > burstcnt) >> + size = burstcnt; >> + ret = I2C_WRITE_DATA(tpm_dev.addr, TPM_DATA_FIFO, buf, size); >> + if (ret < 0) >> + goto out_err; >> + >> + i += size; >> + } >> + >> + status = tpm_stm_i2c_status(chip); >> + if ((status & TPM_STS_DATA_EXPECT) == 0) { >> + ret = -EIO; >> + goto out_err; >> + } >> + >> + ret = I2C_WRITE_DATA(tpm_dev.addr, TPM_DATA_FIFO, buf + len - 1, 1); >> + if (ret < 0) >> + goto out_err; >> + >> + status = tpm_stm_i2c_status(chip); >> + if ((status & TPM_STS_DATA_EXPECT) != 0) { >> + ret = -EIO; >> + goto out_err; >> + } >> + >> + data = TPM_STS_GO; >> + I2C_WRITE_DATA(tpm_dev.addr, TPM_STS, &data, 1); >> + >> + return len; >> +out_err: >> + tpm_stm_i2c_cancel(chip); >> + release_locality(chip); > > Add debug() on error path? > >> + return ret; >> +} /* tpm_stm_i2c_send() */ >> + >> +/* >> + * tpm_stm_i2c_send_hash send TPM locality 4 hash datas through the I2C bus >> + * to update the PCR[17]. >> + * @param: chip, the tpm_chip description. >> + * @param: buf, the data buffer to send. >> + * @param: len, the number of bytes to send. >> + * @return: Returns zero in case of success else the negative error code. >> + */ >> +static int tpm_stm_i2c_send_hash(struct tpm_chip *chip, unsigned char *buf, >> + size_t len) >> +{ >> + u32 ret = 0; >> + u8 data; >> + >> + if (chip == NULL) >> + return -EBUSY; > > Why does NULL mean busy? Shouldn't it be -ENODEV? > >> + >> + release_locality(chip); >> + >> + tpm_dev.addr = 0x1B; >> + chip->vendor.locality = LOCALITY4; >> + >> + data = TPM_DUMMY_BYTE; >> + ret = I2C_WRITE_DATA(tpm_dev.addr, TPM_HASH_START, &data, 1); >> + if (ret < 0) >> + goto end; >> + ret = I2C_WRITE_DATA(tpm_dev.addr, TPM_DATA_FIFO, buf, len); >> + if (ret < 0) >> + goto end; >> + >> +end: >> + I2C_WRITE_DATA(tpm_dev.addr, TPM_HASH_END, &data, 1); >> + release_locality(chip); >> + chip->vendor.locality = LOCALITY0; >> + tpm_dev.addr = 0x13; >> + ret = request_locality(chip); >> + return ret; >> +} /* tpm_stm_i2c_send_hash */ >> + >> +static struct tpm_vendor_specific st_i2c_tpm = { >> + .send = tpm_stm_i2c_send, >> + .send_hash = tpm_stm_i2c_send_hash, >> + .recv = tpm_stm_i2c_recv, >> + .cancel = tpm_stm_i2c_cancel, >> + .status = tpm_stm_i2c_status, >> + .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, >> + .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, >> + .req_canceled = TPM_STS_COMMAND_READY, >> +}; >> + >> +/* >> + * tpm_vendor_init initialize the TPM device >> + * @param: dev_addr, the i2c address of the tpm. >> + * @return: 0 in case of success. >> + * -1 in other case. >> + */ >> +int tpm_vendor_init(uint32_t dev_addr) >> +{ >> + u32 vendor; >> + uint old_addr; >> + int rc = 0; >> + struct tpm_chip *chip; >> + >> + old_addr = tpm_dev.addr; >> + if (dev_addr != 0) >> + tpm_dev.addr = dev_addr; >> + >> + chip = tpm_register_hardware(&st_i2c_tpm); >> + >> + if (chip < 0) { >> + rc = -ENODEV; >> + goto out_err; >> + } >> + >> + /* Default timeouts */ >> + chip->vendor.timeout_a = TIS_SHORT_TIMEOUT; >> + chip->vendor.timeout_b = TIS_LONG_TIMEOUT; >> + chip->vendor.timeout_c = TIS_SHORT_TIMEOUT; >> + chip->vendor.timeout_d = TIS_SHORT_TIMEOUT; >> + >> + chip->vendor.locality = LOCALITY0; >> + >> + if (request_locality(chip) != 0) { >> + rc = -ENODEV; >> + goto out_err; >> + } >> + >> + vendor = be32_to_cpu(vendor); >> + >> + >> + dev_info(dev, "1.2 TPM STMicroelectronics"); >> + /* >> + * A timeout query to TPM can be placed here. >> + * Standard timeout values are used so far >> + */ >> + >> + return 0; >> + >> +out_err: >> + tpm_dev.addr = old_addr; >> + return rc; >> +} /* tpm_vendor_init() */ >> + >> + >> + >> +void tpm_vendor_cleanup(struct tpm_chip *chip) >> +{ >> + release_locality(chip); >> +} /* tpm_vendor_cleanup() */ >> diff --git a/include/configs/omap3_beagle.h b/include/configs/omap3_beagle.h >> index 48ce4c0..ef381f8 100644 >> --- a/include/configs/omap3_beagle.h >> +++ b/include/configs/omap3_beagle.h >> @@ -111,6 +111,14 @@ >> #define STATUS_LED_BOOT STATUS_LED_BIT >> #define STATUS_LED_GREEN STATUS_LED_BIT1 >> >> +/* TPM */ >> +#define CONFIG_CMD_TPM >> +#define CONFIG_TPM >> +#define CONFIG_ST_TPM_DEBUG >> +#define CONFIG_ST_TPM_I2C >> +#define CONFIG_TPM_I2C_BUS 1 >> +#define CONFIG_TPM_I2C_ADDR 0x13 >> + >> /* Enable Multi Bus support for I2C */ >> #define CONFIG_I2C_MULTI_BUS 1 >> >> diff --git a/include/tpm.h b/include/tpm.h >> index 7219b73..36ba0bb 100644 >> --- a/include/tpm.h >> +++ b/include/tpm.h >> @@ -201,4 +201,22 @@ uint32_t tpm_physical_set_deactivated(uint8_t state); >> uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap, >> void *cap, size_t count); >> >> +/* >> + * tis_sendrecv_hash() >> + * >> + * Send the requested data to the TPM for hash in LOC 4 >> + * and then try to get its response >> + * >> + * @sendbuf - buffer of the data to hash >> + * @send_size size of the data to send >> + * @recvbuf - memory to save the response to >> + * @recv_len - pointer to the size of the response buffer >> + * >> + * Returns 0 on success (and places the number of response bytes at recv_len) >> + * or -1 on failure. >> + */ >> +int tis_sendrecv_hash(const uint8_t *sendbuf, size_t send_size, >> + uint8_t *recvbuf, >> + size_t *recv_len); >> + >> #endif /* __TPM_H */ >> -- >> 1.7.9.5 Regards, Simon
Hi Jean-Luc, On 31 March 2014 02:44, Jean-Luc BLANC <jean-luc.blanc@st.com> wrote: > Hi Simon, > > I rewrote the patch. A complete different version will be pushed soon. > Sounds good, thanks. Please cc me when you are ready. Regards, Simon
diff --git a/README b/README index 0d37d56..a72b570 100644 --- a/README +++ b/README @@ -1208,7 +1208,7 @@ The following options need to be configured: If this option is set, the driver enables cache flush. - TPM Support: - CONFIG_GENERIC_LPC_TPM + CONFIG_TPM Support for generic parallel port TPM devices. Only one device per system is supported at this time. @@ -1217,6 +1217,18 @@ The following options need to be configured: to. Contemporary x86 systems usually map it at 0xfed40000. + CONFIG_ST_TPM_I2C + Define to compile the ST TPM I2C DRIVER. + + CONFIG_TPM_I2C_BUS + Define the bus number of the board. + + CONFIG_TPM_I2C_ADDR + Define the address of the TPM. + + CONFIG_CMD_TPM + Define to use some TPM u-boot commands. + - USB Support: At the moment only the UHCI host controller is supported (PIP405, MIP405, MPC5200); define diff --git a/common/cmd_tpm.c b/common/cmd_tpm.c index 46fae18..fba1fe7 100644 --- a/common/cmd_tpm.c +++ b/common/cmd_tpm.c @@ -27,6 +27,14 @@ #include <asm/unaligned.h> #include <linux/string.h> +#define MAX_TRANSACTION_SIZE 30 +#define CHECK(exp) do { \ + int _rv = exp; \ + if (_rv) { \ + printf("CHECK: %s %d %x\n", #exp, __LINE__, _rv);\ + } \ + } while (0) + /** * Print a byte string in hexdecimal format, 16-bytes per line. * @@ -546,6 +554,118 @@ static int do_tpm_nv_write(cmd_tbl_t *cmdtp, int flag, return convert_return_code(err); } +static int do_tpm_hash(cmd_tbl_t *cmdtp, int flag, int argc, +char * const argv[]) +{ + u8 tpm_buffer[MAX_TRANSACTION_SIZE]; + u32 write_size, read_size; + char *p; + int rv = -1; + argc -= 1; + argv += 1; + uint8_t response[1024]; + size_t rlength = MAX_TRANSACTION_SIZE; + + u8 startup[] = { + 0x00, 0xc1, + 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x99, + 0x00, 0x01 + }; + + u8 selftestfull[] = { + 0x00, 0xc1, + 0x00, 0x00, 0x00, 0x0a, + 0x00, 0x00, 0x00, 0x50 + }; + + u8 readpcr17[] = { + 0x00, 0xc1, + 0x00, 0x00, 0x00, 0x0e, + 0x00, 0x00, 0x00, 0x15, + 0x00, 0x00, 0x00, 0x11 + }; + + for (write_size = 0; write_size < argc; write_size++) { + u32 datum = kstrtoul(argv[write_size], &p, 0); + if (*p || (datum > 0xff)) { + printf("\n%s: bad data value\n\n", argv[write_size]); + cmd_usage(cmdtp); + return rv; + } + tpm_buffer[write_size] = (u8)datum; + } + + if (tis_init()) { + puts("tis_init() failed!\n"); + return -1; + } + + if (tis_open()) { + puts("tis_open() failed!\n"); + return -1; + } + + rv = tis_sendrecv(startup, sizeof(startup), response, &rlength); + if (rv) { + printf("tpm test startup failed\n"); + CHECK(tis_close()); + } + + rv = tis_sendrecv(selftestfull, sizeof(selftestfull), response, + &rlength); + if (rv) { + printf("tpm test selftestfull failed\n"); + CHECK(tis_close()); + } + + if (! + tis_sendrecv(readpcr17, sizeof(readpcr17), response, &read_size)) { + int i; + puts("TPM Read PCR 17:\n"); + for (i = 10; i < read_size; i++) + printf(" %2.2x", response[i]); + puts("\n"); + rv = 0; + } else { + printf("tpm test readpcr17 failed\n"); + CHECK(tis_close()); + } + + read_size = sizeof(tpm_buffer); + if (! + tis_sendrecv_hash(tpm_buffer, write_size, tpm_buffer, &read_size)) { + int i; + puts("Got TPM Hash response:\n"); + for (i = 0; i < read_size; i++) + printf(" %2.2x", tpm_buffer[i]); + puts("\n"); + rv = 0; + } else { + puts("tpm hash command failed\n"); + } + + if (! + tis_sendrecv(readpcr17, sizeof(readpcr17), response, &read_size)) { + int i; + puts("TPM Read PCR 17 after hash:\n"); + for (i = 10; i < read_size; i++) + printf(" %2.2x", response[i]); + puts("\n"); + rv = 0; + } else { + printf("tpm test readpcr17 failed\n"); + CHECK(tis_close()); + } + + if (tis_close()) { + puts("tis_close() failed!\n"); + rv = -1; + } + + return rv; +} + #define MAKE_TPM_CMD_ENTRY(cmd) \ U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "") @@ -590,6 +710,8 @@ static cmd_tbl_t tpm_commands[] = { do_tpm_nv_read, "", ""), U_BOOT_CMD_MKENT(nv_write, 0, 1, do_tpm_nv_write, "", ""), + U_BOOT_CMD_MKENT(hash, 0, 1, + do_tpm_hash, "", ""), }; static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile index e8c159c..cbececf 100644 --- a/drivers/tpm/Makefile +++ b/drivers/tpm/Makefile @@ -28,6 +28,7 @@ $(shell mkdir -p $(obj)slb9635_i2c) COBJS-$(CONFIG_GENERIC_LPC_TPM) = generic_lpc_tpm.o COBJS-$(CONFIG_INFINEON_TPM_I2C) += tis_i2c.o slb9635_i2c/tpm.o COBJS-$(CONFIG_INFINEON_TPM_I2C) += slb9635_i2c/tpm_tis_i2c.o +COBJS-$(CONFIG_ST_TPM_I2C) = tis_i2c.o tpm_i2c_st.o slb9635_i2c/tpm.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/tpm/slb9635_i2c/tpm.c b/drivers/tpm/slb9635_i2c/tpm.c index 496c48e..c92bd06 100644 --- a/drivers/tpm/slb9635_i2c/tpm.c +++ b/drivers/tpm/slb9635_i2c/tpm.c @@ -444,6 +444,26 @@ int tpm_open(uint32_t dev_addr) return rc; } +ssize_t tpm_transmit_hash(const unsigned char *buf, size_t bufsiz) +{ + ssize_t rc; + + struct tpm_chip *chip = &g_chip; + + rc = chip->vendor.send_hash(chip, (u8 *)buf, bufsiz); + if (rc < 0) { + dev_err(chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc); + goto out; + } + + dbg_printf("out_recv: reading response...\n"); + rc = chip->vendor.recv(chip, (u8 *)buf, TPM_BUFSIZE); + if (rc < 0) + dev_err(chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); +out: + return rc; +} + void tpm_close(void) { if (g_chip.is_open) { diff --git a/drivers/tpm/slb9635_i2c/tpm.h b/drivers/tpm/slb9635_i2c/tpm.h index 9ddee86..88e0c07 100644 --- a/drivers/tpm/slb9635_i2c/tpm.h +++ b/drivers/tpm/slb9635_i2c/tpm.h @@ -64,6 +64,7 @@ struct tpm_vendor_specific { int irq; int (*recv) (struct tpm_chip *, u8 *, size_t); int (*send) (struct tpm_chip *, u8 *, size_t); + int (*send_hash) (struct tpm_chip *, u8 *, size_t); void (*cancel) (struct tpm_chip *); u8(*status) (struct tpm_chip *); int locality; diff --git a/drivers/tpm/tis_i2c.c b/drivers/tpm/tis_i2c.c index e818fba..36ae544 100644 --- a/drivers/tpm/tis_i2c.c +++ b/drivers/tpm/tis_i2c.c @@ -82,8 +82,13 @@ static int tpm_decode_config(struct tpm *dev) dev->i2c_bus = i2c_bus; dev->slave_addr = fdtdec_get_addr(blob, node, "reg"); #else + #ifdef CONFIG_INFINEON_TPM_I2C_BUS dev->i2c_bus = CONFIG_INFINEON_TPM_I2C_BUS; dev->slave_addr = CONFIG_INFINEON_TPM_I2C_ADDR; + #else + dev->i2c_bus = CONFIG_TPM_I2C_BUS; + dev->slave_addr = CONFIG_TPM_I2C_ADDR; + #endif #endif return 0; } @@ -179,3 +184,35 @@ int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size, return 0; } + +int tis_sendrecv_hash(const uint8_t *sendbuf, size_t sbuf_size, + uint8_t *recvbuf, size_t *rbuf_len) +{ + int len; + uint8_t buf[TPM_BUFSIZE]; + + if (!tpm.inited) + return -1; + + if (sizeof(buf) < sbuf_size) + return -1; + + memcpy(buf, sendbuf, sbuf_size); + + if (tpm_select()) + return -1; + + len = tpm_transmit_hash(buf, sbuf_size); + + tpm_deselect(); + + if (len < 10) { + *rbuf_len = 0; + return -1; + } + + memcpy(recvbuf, buf, len); + *rbuf_len = len; + + return 0; +} diff --git a/drivers/tpm/tpm_i2c_st.c b/drivers/tpm/tpm_i2c_st.c new file mode 100644 index 0000000..16753f8 --- /dev/null +++ b/drivers/tpm/tpm_i2c_st.c @@ -0,0 +1,599 @@ +/* + * STMicroelectronics TPM I2C UBOOT Linux driver for TPM ST33ZP24 + * Copyright (C) 2013 STMicroelectronics + * + * (c) Copyright 2013 Mathias Leblanc <mathias.leblanc@st.com> + * This file is released under the terms of GPL v2 and any later version + * See the file COPYING in the root directory of the source tree for details + * + * Description: + * Device driver for TCG/TCPA TPM (trusted platform module). + * Specifications at www.trustedcomputinggroup.org + * + * This device driver implements the TPM interface as defined in + * the TCG TPM Interface Spec version 1.2, revision 1.0 and the + * STMicroelectronics I2C Protocol Stack Specification version 1.2.0. + * + * It is based on the Linux I2C TPM driver from Peter Huewe, modified + * from the original tpm + * device drivers from Leendert van Dorn, Dave Safford, Reiner Sailer + * and Kyleen Hall. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * @Author: Mathias Leblanc tpmsupport@st.com + * + * @File: tpm_i2c_st.c + * + */ + +#include <common.h> +#include <i2c.h> +#include <linux/types.h> + +#include "slb9635_i2c/compatibility.h" +#include "slb9635_i2c/tpm.h" + +/* max. buffer size supported by our tpm */ +#ifdef TPM_BUFSIZE +#undef TPM_BUFSIZE +#endif + +#define MINOR_NUM_I2C 224 + +#define TPM_ACCESS (0x0) +#define TPM_STS (0x18) +#define TPM_HASH_END (0x20) +#define TPM_DATA_FIFO (0x24) +#define TPM_HASH_DATA (0x24) +#define TPM_HASH_START (0x28) +#define TPM_INTF_CAPABILITY (0x14) +#define TPM_INT_STATUS (0x10) +#define TPM_INT_ENABLE (0x08) + +#define TPM_DUMMY_BYTE 0xAA +#define TPM_WRITE_DIRECTION 0x80 +#define TPM_HEADER_SIZE 10 +#define TPM_BUFSIZE 2048 + +#define LOCALITY0 0 +#define LOCALITY4 4 + +struct st_tpm_hash { + int size; + u8 *data; +}; + +enum stm33zp24_access { + TPM_ACCESS_VALID = 0x80, + TPM_ACCESS_ACTIVE_LOCALITY = 0x20, + TPM_ACCESS_REQUEST_PENDING = 0x04, + TPM_ACCESS_REQUEST_USE = 0x02, +}; + +enum stm33zp24_status { + TPM_STS_VALID = 0x80, + TPM_STS_COMMAND_READY = 0x40, + TPM_STS_GO = 0x20, + TPM_STS_DATA_AVAIL = 0x10, + TPM_STS_DATA_EXPECT = 0x08, +}; + +enum stm33zp24_int_flags { + TPM_GLOBAL_INT_ENABLE = 0x80, + TPM_INTF_CMD_READY_INT = 0x080, + TPM_INTF_FIFO_AVALAIBLE_INT = 0x040, + TPM_INTF_WAKE_UP_READY_INT = 0x020, + TPM_INTF_LOC4SOFTRELEASE_INT = 0x008, + TPM_INTF_LOCALITY_CHANGE_INT = 0x004, + TPM_INTF_STS_VALID_INT = 0x002, + TPM_INTF_DATA_AVAIL_INT = 0x001, +}; + +enum tis_defaults { + TIS_SHORT_TIMEOUT = 750, /* ms */ + TIS_LONG_TIMEOUT = 2000, /* 2 sec */ +}; + +struct tpm_i2c_ST_dev { + uint addr; + u8 buf[TPM_BUFSIZE]; +}; + +static struct tpm_i2c_ST_dev tpm_dev = { + /* Note: replace with defined addr from board configuration */ + .addr = CONFIG_TPM_I2C_ADDR +}; + +/* + * write8_reg + * Send byte to the TIS register according to the ST33ZP24 I2C protocol. + * @param: tpm_register, the tpm tis register where the data should be written + * @param: tpm_data, the tpm_data to write inside the tpm_register + * @param: tpm_size, The length of the data + * @return: Returns zero in case of success else the negative error code. + */ +static int write8_reg(u8 addr, u8 tpm_register, + u8 *tpm_data, u16 tpm_size) +{ + u8 data; + data = tpm_register; + memcpy(&(tpm_dev.buf[0]), &data, sizeof(data)); + memcpy(&(tpm_dev.buf[0])+1, tpm_data, tpm_size); + + return i2c_write(addr, 0, 0, &tpm_dev.buf[0], + tpm_size + 1); + +} /* write8_reg() */ + +/* +* read8_reg +* Recv byte from the TIS register according to the ST33ZP24 I2C protocol. +* @param: tpm_register, the tpm tis register where the data should be read +* @param: tpm_data, the TPM response +* @param: tpm_size, tpm TPM response size to read. +* @return: Returns zero in case of success else the negative error code. +*/ +static int read8_reg(u8 addr, u8 tpm_register, +u8 *tpm_data, int tpm_size) +{ + u8 status = 0; + u8 data; + data = TPM_DUMMY_BYTE; + status = write8_reg(addr, tpm_register, &data, 1); + if (status == 0) + status = i2c_read(addr, 0, 0, tpm_data, tpm_size); +return status; +} /* read8_reg() */ + +/* + * I2C_WRITE_DATA + * Send byte to the TIS register according to the ST33ZP24 I2C protocol. + * @param: client, the chip description + * @param: tpm_register, the tpm tis register where the data should be written + * @param: tpm_data, the tpm_data to write inside the tpm_register + * @param: tpm_size, The length of the data + * @return: Returns zero in case of success else the negative error code. + */ +#define I2C_WRITE_DATA(client, tpm_register, tpm_data, tpm_size)\ + (write8_reg(client, tpm_register | \ + TPM_WRITE_DIRECTION, tpm_data, tpm_size)) + +/* + * I2C_READ_DATA + * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. + * @param: tpm, the chip description + * @param: tpm_register, the tpm tis register where the data should be read + * @param: tpm_data, the TPM response + * @param: tpm_size, tpm TPM response size to read. + * @return: Returns zero in case of success else the negative error code. + */ +#define I2C_READ_DATA(client, tpm_register, tpm_data, tpm_size)\ + (read8_reg(client, tpm_register, tpm_data, tpm_size)) + +/* + * release_locality release the active locality + * @param: chip, the tpm chip description. + */ +static void release_locality(struct tpm_chip *chip) +{ + u8 data = TPM_ACCESS_ACTIVE_LOCALITY; + + I2C_WRITE_DATA(tpm_dev.addr, TPM_ACCESS, &data, 1); +} + +/* + * clear_interruption + * clear the TPM interrupt register. + * @param: tpm, the chip description + */ +static void clear_interruption(u8 addr) +{ + u8 interrupt; + I2C_READ_DATA(tpm_dev.addr, TPM_INT_STATUS, &interrupt, 1); + I2C_WRITE_DATA(tpm_dev.addr, TPM_INT_STATUS, &interrupt, 1); + I2C_READ_DATA(tpm_dev.addr, TPM_INT_STATUS, &interrupt, 1); +} /* clear_interruption() */ + +int wait_for_serirq_timeout(struct tpm_chip *chip, int condition, + unsigned long timeout) +{ + int status = 2; + + clear_interruption(tpm_dev.addr); + if (condition) + status = 1; + + return status; +} + +/* + * check_locality if the locality is active + * @param: chip, the tpm chip description + * @return: the active locality or -EACCESS. + */ +static int check_locality(struct tpm_chip *chip) +{ + u8 data; + u8 status; + status = I2C_READ_DATA(tpm_dev.addr, TPM_ACCESS, &data, 1); + + if ((status == 0) && (data & + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) + return chip->vendor.locality; + + return -EACCES; + +} /* check_locality() */ + +/* + * request_locality request the TPM locality + * @param: chip, the chip description + * @return: the active locality or EACCESS. + */ +static int request_locality(struct tpm_chip *chip) +{ + unsigned long start, stop; + long rc; + u8 data; + if (check_locality(chip) == chip->vendor.locality) + return chip->vendor.locality; + + data = TPM_ACCESS_REQUEST_USE; + rc = I2C_WRITE_DATA(tpm_dev.addr, TPM_ACCESS, &data, 1); + if (rc < 0) + goto end; + + if (chip->vendor.irq) { + rc = wait_for_serirq_timeout(chip, (check_locality + (chip) >= 0), + chip->vendor.timeout_a); + if (rc > 0) + return chip->vendor.locality; + } else{ + /* wait for locality activated */ + start = get_timer(0); + stop = chip->vendor.timeout_a; + do { + if (check_locality(chip) >= 0) + return chip->vendor.locality; + + msleep(TPM_TIMEOUT); + } while (get_timer(start) < stop); + } + rc = -EACCES; +end: + return rc; +} /* request_locality() */ + +/* + * tpm_stm_i2c_cancel, cancel is not implemented. + * @param: chip, tpm_chip description. + */ +static void tpm_stm_i2c_cancel(struct tpm_chip *chip) +{ + u8 data; + + data = TPM_STS_COMMAND_READY; + I2C_WRITE_DATA(tpm_dev.addr, TPM_STS, &data, 1); + if (chip->vendor.irq) + wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a); +} /* tpm_stm_i2c_cancel() */ + +/* + * tpm_stm_spi_status return the TPM_STS register + * @param: chip, the tpm chip description + * @return: the TPM_STS register value. + */ +static u8 tpm_stm_i2c_status(struct tpm_chip *chip) +{ + u8 data; + I2C_READ_DATA(tpm_dev.addr, TPM_STS, &data, 1); + return data; +} /* tpm_stm_i2c_status() */ + +/* + * get_burstcount return the burstcount address 0x19 0x1A + * @param: chip, the chip description + * return: the burstcount. + */ +static int get_burstcount(struct tpm_chip *chip) +{ + unsigned long start, stop; + int burstcnt, status; + u8 tpm_reg, temp; + + /* wait for burstcount */ + /* which timeout value, spec has 2 answers (c & d) */ + start = get_timer(0); + stop = chip->vendor.timeout_d; + do { + tpm_reg = TPM_STS + 1; + status = I2C_READ_DATA(tpm_dev.addr, tpm_reg, &temp, 1); + if (status < 0) + goto end; + + tpm_reg = tpm_reg + 1; + burstcnt = temp; + status = I2C_READ_DATA(tpm_dev.addr, tpm_reg, &temp, 1); + if (status < 0) + goto end; + + burstcnt |= temp << 8; + if (burstcnt) + return burstcnt; + + msleep(TPM_TIMEOUT); + } while (get_timer(start) < stop); + +end: + return -EBUSY; +} /* get_burstcount() */ + + +/* + * recv_data receive data + * @param: chip, the tpm chip description + * @param: buf, the buffer where the data are received + * @param: count, the number of data to receive + * @return: the number of bytes read from TPM FIFO. + */ +static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) +{ + int size = 0, burstcnt, len; + + while (size < count) { + burstcnt = get_burstcount(chip); + len = count - size; + if ((len) > burstcnt) + len = burstcnt; + if ( + I2C_READ_DATA(tpm_dev.addr, TPM_DATA_FIFO, buf + size, len) == 0) + size += len; + else + break; + } + return size; +} /* recv_data() */ + +/* + * tpm_stm_i2c_recv received TPM response through the I2C bus. + * @param: chip, tpm_chip description. + * @param: buf, the buffer to store datas. + * @param: count, the number of bytes to send. + * @return: Returns zero in case of success else the negative error code. + */ +static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, + size_t count) +{ + int size = 0; + int expected; + + if (chip == NULL) + return -EBUSY; + + if (count < TPM_HEADER_SIZE) { + size = -EIO; + goto out; + } + + size = recv_data(chip, buf, TPM_HEADER_SIZE); + if (size < TPM_HEADER_SIZE) { + dev_err(chip->dev, "Unable to read header\n"); + goto out; + } + + + expected = get_unaligned_be32(buf + TPM_RSP_SIZE_BYTE); + if (expected > count) { + size = -EIO; + goto out; + } + + size += recv_data(chip, &buf[TPM_HEADER_SIZE], + expected - TPM_HEADER_SIZE); + if (size < expected) { + dev_err(chip->dev, "Unable to read remainder of result\n"); + size = -ETIME; + goto out; + } + +out: + chip->vendor.cancel(chip); + release_locality(chip); + return size; +} /* tpm_stm_i2c_recv() */ + +/* + * tpm_stm_i2c_send send TPM commands through the I2C bus. + * + * @param: chip, tpm_chip description. + * @param: buf, the buffer to send. + * @param: len, the number of bytes to send. + * @return: Returns zero in case of success else the negative error code. + */ +static int tpm_stm_i2c_send(struct tpm_chip *chip, u8 *buf, + size_t len) +{ + u32 ret = 0, + status, + burstcnt = 0, i, size; + u8 data; + + if (chip == NULL) + return -EBUSY; + if (len < TPM_HEADER_SIZE) + return -EBUSY; + + ret = request_locality(chip); + if (ret < 0) + return ret; + + status = tpm_stm_i2c_status(chip); + if ((status & TPM_STS_COMMAND_READY) == 0) + tpm_stm_i2c_cancel(chip); + + for (i = 0; i < len - 1;) { + burstcnt = get_burstcount(chip); + size = len - i - 1; + if ((size) > burstcnt) + size = burstcnt; + ret = I2C_WRITE_DATA(tpm_dev.addr, TPM_DATA_FIFO, buf, size); + if (ret < 0) + goto out_err; + + i += size; + } + + status = tpm_stm_i2c_status(chip); + if ((status & TPM_STS_DATA_EXPECT) == 0) { + ret = -EIO; + goto out_err; + } + + ret = I2C_WRITE_DATA(tpm_dev.addr, TPM_DATA_FIFO, buf + len - 1, 1); + if (ret < 0) + goto out_err; + + status = tpm_stm_i2c_status(chip); + if ((status & TPM_STS_DATA_EXPECT) != 0) { + ret = -EIO; + goto out_err; + } + + data = TPM_STS_GO; + I2C_WRITE_DATA(tpm_dev.addr, TPM_STS, &data, 1); + + return len; +out_err: + tpm_stm_i2c_cancel(chip); + release_locality(chip); + return ret; +} /* tpm_stm_i2c_send() */ + +/* + * tpm_stm_i2c_send_hash send TPM locality 4 hash datas through the I2C bus + * to update the PCR[17]. + * @param: chip, the tpm_chip description. + * @param: buf, the data buffer to send. + * @param: len, the number of bytes to send. + * @return: Returns zero in case of success else the negative error code. + */ +static int tpm_stm_i2c_send_hash(struct tpm_chip *chip, unsigned char *buf, + size_t len) +{ + u32 ret = 0; + u8 data; + + if (chip == NULL) + return -EBUSY; + + release_locality(chip); + + tpm_dev.addr = 0x1B; + chip->vendor.locality = LOCALITY4; + + data = TPM_DUMMY_BYTE; + ret = I2C_WRITE_DATA(tpm_dev.addr, TPM_HASH_START, &data, 1); + if (ret < 0) + goto end; + ret = I2C_WRITE_DATA(tpm_dev.addr, TPM_DATA_FIFO, buf, len); + if (ret < 0) + goto end; + +end: + I2C_WRITE_DATA(tpm_dev.addr, TPM_HASH_END, &data, 1); + release_locality(chip); + chip->vendor.locality = LOCALITY0; + tpm_dev.addr = 0x13; + ret = request_locality(chip); + return ret; +} /* tpm_stm_i2c_send_hash */ + +static struct tpm_vendor_specific st_i2c_tpm = { + .send = tpm_stm_i2c_send, + .send_hash = tpm_stm_i2c_send_hash, + .recv = tpm_stm_i2c_recv, + .cancel = tpm_stm_i2c_cancel, + .status = tpm_stm_i2c_status, + .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, + .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, + .req_canceled = TPM_STS_COMMAND_READY, +}; + +/* + * tpm_vendor_init initialize the TPM device + * @param: dev_addr, the i2c address of the tpm. + * @return: 0 in case of success. + * -1 in other case. + */ +int tpm_vendor_init(uint32_t dev_addr) +{ + u32 vendor; + uint old_addr; + int rc = 0; + struct tpm_chip *chip; + + old_addr = tpm_dev.addr; + if (dev_addr != 0) + tpm_dev.addr = dev_addr; + + chip = tpm_register_hardware(&st_i2c_tpm); + + if (chip < 0) { + rc = -ENODEV; + goto out_err; + } + + /* Default timeouts */ + chip->vendor.timeout_a = TIS_SHORT_TIMEOUT; + chip->vendor.timeout_b = TIS_LONG_TIMEOUT; + chip->vendor.timeout_c = TIS_SHORT_TIMEOUT; + chip->vendor.timeout_d = TIS_SHORT_TIMEOUT; + + chip->vendor.locality = LOCALITY0; + + if (request_locality(chip) != 0) { + rc = -ENODEV; + goto out_err; + } + + vendor = be32_to_cpu(vendor); + + + dev_info(dev, "1.2 TPM STMicroelectronics"); + /* + * A timeout query to TPM can be placed here. + * Standard timeout values are used so far + */ + + return 0; + +out_err: + tpm_dev.addr = old_addr; + return rc; +} /* tpm_vendor_init() */ + + + +void tpm_vendor_cleanup(struct tpm_chip *chip) +{ + release_locality(chip); +} /* tpm_vendor_cleanup() */ diff --git a/include/configs/omap3_beagle.h b/include/configs/omap3_beagle.h index 48ce4c0..ef381f8 100644 --- a/include/configs/omap3_beagle.h +++ b/include/configs/omap3_beagle.h @@ -111,6 +111,14 @@ #define STATUS_LED_BOOT STATUS_LED_BIT #define STATUS_LED_GREEN STATUS_LED_BIT1 +/* TPM */ +#define CONFIG_CMD_TPM +#define CONFIG_TPM +#define CONFIG_ST_TPM_DEBUG +#define CONFIG_ST_TPM_I2C +#define CONFIG_TPM_I2C_BUS 1 +#define CONFIG_TPM_I2C_ADDR 0x13 + /* Enable Multi Bus support for I2C */ #define CONFIG_I2C_MULTI_BUS 1 diff --git a/include/tpm.h b/include/tpm.h index 7219b73..36ba0bb 100644 --- a/include/tpm.h +++ b/include/tpm.h @@ -201,4 +201,22 @@ uint32_t tpm_physical_set_deactivated(uint8_t state); uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap, void *cap, size_t count); +/* + * tis_sendrecv_hash() + * + * Send the requested data to the TPM for hash in LOC 4 + * and then try to get its response + * + * @sendbuf - buffer of the data to hash + * @send_size size of the data to send + * @recvbuf - memory to save the response to + * @recv_len - pointer to the size of the response buffer + * + * Returns 0 on success (and places the number of response bytes at recv_len) + * or -1 on failure. + */ +int tis_sendrecv_hash(const uint8_t *sendbuf, size_t send_size, + uint8_t *recvbuf, + size_t *recv_len); + #endif /* __TPM_H */