190899cc0SChe-liang Chiou /* 290899cc0SChe-liang Chiou * Copyright (c) 2011 The Chromium OS Authors. 390899cc0SChe-liang Chiou * 41a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 590899cc0SChe-liang Chiou */ 690899cc0SChe-liang Chiou 790899cc0SChe-liang Chiou /* 890899cc0SChe-liang Chiou * The code in this file is based on the article "Writing a TPM Device Driver" 990899cc0SChe-liang Chiou * published on http://ptgmedia.pearsoncmg.com. 1090899cc0SChe-liang Chiou * 1190899cc0SChe-liang Chiou * One principal difference is that in the simplest config the other than 0 1290899cc0SChe-liang Chiou * TPM localities do not get mapped by some devices (for instance, by Infineon 1390899cc0SChe-liang Chiou * slb9635), so this driver provides access to locality 0 only. 1490899cc0SChe-liang Chiou */ 1590899cc0SChe-liang Chiou 1690899cc0SChe-liang Chiou #include <common.h> 17d616ba5fSSimon Glass #include <dm.h> 18d616ba5fSSimon Glass #include <mapmem.h> 1990899cc0SChe-liang Chiou #include <tpm.h> 20d616ba5fSSimon Glass #include <asm/io.h> 2190899cc0SChe-liang Chiou 2290899cc0SChe-liang Chiou #define PREFIX "lpc_tpm: " 2390899cc0SChe-liang Chiou 24*a982b6f5SGeorge McCollister enum i2c_chip_type { 25*a982b6f5SGeorge McCollister SLB9635, 26*a982b6f5SGeorge McCollister AT97SC3204, 27*a982b6f5SGeorge McCollister }; 28*a982b6f5SGeorge McCollister 29*a982b6f5SGeorge McCollister static const char * const chip_name[] = { 30*a982b6f5SGeorge McCollister [SLB9635] = "Infineon SLB9635 TT 1.2", 31*a982b6f5SGeorge McCollister [AT97SC3204] = "Atmel AT97SC3204", 32*a982b6f5SGeorge McCollister }; 33*a982b6f5SGeorge McCollister 34*a982b6f5SGeorge McCollister static const u32 chip_didvid[] = { 35*a982b6f5SGeorge McCollister [SLB9635] = 0xb15d1, 36*a982b6f5SGeorge McCollister [AT97SC3204] = 0x32041114, 37*a982b6f5SGeorge McCollister }; 38*a982b6f5SGeorge McCollister 3990899cc0SChe-liang Chiou struct tpm_locality { 4090899cc0SChe-liang Chiou u32 access; 4190899cc0SChe-liang Chiou u8 padding0[4]; 4290899cc0SChe-liang Chiou u32 int_enable; 4390899cc0SChe-liang Chiou u8 vector; 4490899cc0SChe-liang Chiou u8 padding1[3]; 4590899cc0SChe-liang Chiou u32 int_status; 4690899cc0SChe-liang Chiou u32 int_capability; 4790899cc0SChe-liang Chiou u32 tpm_status; 4890899cc0SChe-liang Chiou u8 padding2[8]; 4990899cc0SChe-liang Chiou u8 data; 5090899cc0SChe-liang Chiou u8 padding3[3803]; 5190899cc0SChe-liang Chiou u32 did_vid; 5290899cc0SChe-liang Chiou u8 rid; 5390899cc0SChe-liang Chiou u8 padding4[251]; 5490899cc0SChe-liang Chiou }; 5590899cc0SChe-liang Chiou 56d616ba5fSSimon Glass struct tpm_tis_lpc_priv { 57d616ba5fSSimon Glass struct tpm_locality *regs; 58d616ba5fSSimon Glass }; 59d616ba5fSSimon Glass 6090899cc0SChe-liang Chiou /* 6190899cc0SChe-liang Chiou * This pointer refers to the TPM chip, 5 of its localities are mapped as an 6290899cc0SChe-liang Chiou * array. 6390899cc0SChe-liang Chiou */ 6490899cc0SChe-liang Chiou #define TPM_TOTAL_LOCALITIES 5 6590899cc0SChe-liang Chiou 6690899cc0SChe-liang Chiou /* Some registers' bit field definitions */ 6790899cc0SChe-liang Chiou #define TIS_STS_VALID (1 << 7) /* 0x80 */ 6890899cc0SChe-liang Chiou #define TIS_STS_COMMAND_READY (1 << 6) /* 0x40 */ 6990899cc0SChe-liang Chiou #define TIS_STS_TPM_GO (1 << 5) /* 0x20 */ 7090899cc0SChe-liang Chiou #define TIS_STS_DATA_AVAILABLE (1 << 4) /* 0x10 */ 7190899cc0SChe-liang Chiou #define TIS_STS_EXPECT (1 << 3) /* 0x08 */ 7290899cc0SChe-liang Chiou #define TIS_STS_RESPONSE_RETRY (1 << 1) /* 0x02 */ 7390899cc0SChe-liang Chiou 7490899cc0SChe-liang Chiou #define TIS_ACCESS_TPM_REG_VALID_STS (1 << 7) /* 0x80 */ 7590899cc0SChe-liang Chiou #define TIS_ACCESS_ACTIVE_LOCALITY (1 << 5) /* 0x20 */ 7690899cc0SChe-liang Chiou #define TIS_ACCESS_BEEN_SEIZED (1 << 4) /* 0x10 */ 7790899cc0SChe-liang Chiou #define TIS_ACCESS_SEIZE (1 << 3) /* 0x08 */ 7890899cc0SChe-liang Chiou #define TIS_ACCESS_PENDING_REQUEST (1 << 2) /* 0x04 */ 7990899cc0SChe-liang Chiou #define TIS_ACCESS_REQUEST_USE (1 << 1) /* 0x02 */ 8090899cc0SChe-liang Chiou #define TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0) /* 0x01 */ 8190899cc0SChe-liang Chiou 8290899cc0SChe-liang Chiou #define TIS_STS_BURST_COUNT_MASK (0xffff) 8390899cc0SChe-liang Chiou #define TIS_STS_BURST_COUNT_SHIFT (8) 8490899cc0SChe-liang Chiou 8590899cc0SChe-liang Chiou /* 1 second is plenty for anything TPM does. */ 8690899cc0SChe-liang Chiou #define MAX_DELAY_US (1000 * 1000) 8790899cc0SChe-liang Chiou 8890899cc0SChe-liang Chiou /* Retrieve burst count value out of the status register contents. */ 8990899cc0SChe-liang Chiou static u16 burst_count(u32 status) 9090899cc0SChe-liang Chiou { 91d616ba5fSSimon Glass return (status >> TIS_STS_BURST_COUNT_SHIFT) & 92d616ba5fSSimon Glass TIS_STS_BURST_COUNT_MASK; 9390899cc0SChe-liang Chiou } 9490899cc0SChe-liang Chiou 9590899cc0SChe-liang Chiou /* TPM access wrappers to support tracing */ 96d616ba5fSSimon Glass static u8 tpm_read_byte(struct tpm_tis_lpc_priv *priv, const u8 *ptr) 9790899cc0SChe-liang Chiou { 9890899cc0SChe-liang Chiou u8 ret = readb(ptr); 9990899cc0SChe-liang Chiou debug(PREFIX "Read reg 0x%4.4x returns 0x%2.2x\n", 100d616ba5fSSimon Glass (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, ret); 10190899cc0SChe-liang Chiou return ret; 10290899cc0SChe-liang Chiou } 10390899cc0SChe-liang Chiou 104d616ba5fSSimon Glass static u32 tpm_read_word(struct tpm_tis_lpc_priv *priv, const u32 *ptr) 10590899cc0SChe-liang Chiou { 10690899cc0SChe-liang Chiou u32 ret = readl(ptr); 10790899cc0SChe-liang Chiou debug(PREFIX "Read reg 0x%4.4x returns 0x%8.8x\n", 108d616ba5fSSimon Glass (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, ret); 10990899cc0SChe-liang Chiou return ret; 11090899cc0SChe-liang Chiou } 11190899cc0SChe-liang Chiou 112d616ba5fSSimon Glass static void tpm_write_byte(struct tpm_tis_lpc_priv *priv, u8 value, u8 *ptr) 11390899cc0SChe-liang Chiou { 11490899cc0SChe-liang Chiou debug(PREFIX "Write reg 0x%4.4x with 0x%2.2x\n", 115d616ba5fSSimon Glass (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, value); 11690899cc0SChe-liang Chiou writeb(value, ptr); 11790899cc0SChe-liang Chiou } 11890899cc0SChe-liang Chiou 119d616ba5fSSimon Glass static void tpm_write_word(struct tpm_tis_lpc_priv *priv, u32 value, 120d616ba5fSSimon Glass u32 *ptr) 12190899cc0SChe-liang Chiou { 12290899cc0SChe-liang Chiou debug(PREFIX "Write reg 0x%4.4x with 0x%8.8x\n", 123d616ba5fSSimon Glass (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, value); 12490899cc0SChe-liang Chiou writel(value, ptr); 12590899cc0SChe-liang Chiou } 12690899cc0SChe-liang Chiou 12790899cc0SChe-liang Chiou /* 12890899cc0SChe-liang Chiou * tis_wait_reg() 12990899cc0SChe-liang Chiou * 13090899cc0SChe-liang Chiou * Wait for at least a second for a register to change its state to match the 13190899cc0SChe-liang Chiou * expected state. Normally the transition happens within microseconds. 13290899cc0SChe-liang Chiou * 13390899cc0SChe-liang Chiou * @reg - pointer to the TPM register 13490899cc0SChe-liang Chiou * @mask - bitmask for the bitfield(s) to watch 13590899cc0SChe-liang Chiou * @expected - value the field(s) are supposed to be set to 13690899cc0SChe-liang Chiou * 13790899cc0SChe-liang Chiou * Returns the register contents in case the expected value was found in the 138d616ba5fSSimon Glass * appropriate register bits, or -ETIMEDOUT on timeout. 13990899cc0SChe-liang Chiou */ 140d616ba5fSSimon Glass static int tis_wait_reg(struct tpm_tis_lpc_priv *priv, u32 *reg, u8 mask, 141d616ba5fSSimon Glass u8 expected) 14290899cc0SChe-liang Chiou { 14390899cc0SChe-liang Chiou u32 time_us = MAX_DELAY_US; 14490899cc0SChe-liang Chiou 14590899cc0SChe-liang Chiou while (time_us > 0) { 146d616ba5fSSimon Glass u32 value = tpm_read_word(priv, reg); 14790899cc0SChe-liang Chiou if ((value & mask) == expected) 14890899cc0SChe-liang Chiou return value; 14990899cc0SChe-liang Chiou udelay(1); /* 1 us */ 15090899cc0SChe-liang Chiou time_us--; 15190899cc0SChe-liang Chiou } 152d616ba5fSSimon Glass 153d616ba5fSSimon Glass return -ETIMEDOUT; 15490899cc0SChe-liang Chiou } 15590899cc0SChe-liang Chiou 15690899cc0SChe-liang Chiou /* 15790899cc0SChe-liang Chiou * Probe the TPM device and try determining its manufacturer/device name. 15890899cc0SChe-liang Chiou * 159d616ba5fSSimon Glass * Returns 0 on success, -ve on error 16090899cc0SChe-liang Chiou */ 161d616ba5fSSimon Glass static int tpm_tis_lpc_probe(struct udevice *dev) 16290899cc0SChe-liang Chiou { 163d616ba5fSSimon Glass struct tpm_tis_lpc_priv *priv = dev_get_priv(dev); 164d616ba5fSSimon Glass fdt_addr_t addr; 165d616ba5fSSimon Glass u32 didvid; 166*a982b6f5SGeorge McCollister ulong chip_type = dev_get_driver_data(dev); 16790899cc0SChe-liang Chiou 168d616ba5fSSimon Glass addr = dev_get_addr(dev); 169d616ba5fSSimon Glass if (addr == FDT_ADDR_T_NONE) 170d616ba5fSSimon Glass return -EINVAL; 171d616ba5fSSimon Glass priv->regs = map_sysmem(addr, 0); 172d616ba5fSSimon Glass didvid = tpm_read_word(priv, &priv->regs[0].did_vid); 17390899cc0SChe-liang Chiou 174*a982b6f5SGeorge McCollister if (didvid != chip_didvid[chip_type]) { 175*a982b6f5SGeorge McCollister u32 vid, did; 17690899cc0SChe-liang Chiou vid = didvid & 0xffff; 17790899cc0SChe-liang Chiou did = (didvid >> 16) & 0xffff; 178d616ba5fSSimon Glass debug("Invalid vendor/device ID %04x/%04x\n", vid, did); 179*a982b6f5SGeorge McCollister return -ENODEV; 18090899cc0SChe-liang Chiou } 18190899cc0SChe-liang Chiou 182*a982b6f5SGeorge McCollister debug("Found TPM: %s\n", chip_name[chip_type]); 183d616ba5fSSimon Glass 18490899cc0SChe-liang Chiou return 0; 18590899cc0SChe-liang Chiou } 18690899cc0SChe-liang Chiou 18790899cc0SChe-liang Chiou /* 18890899cc0SChe-liang Chiou * tis_senddata() 18990899cc0SChe-liang Chiou * 19090899cc0SChe-liang Chiou * send the passed in data to the TPM device. 19190899cc0SChe-liang Chiou * 19290899cc0SChe-liang Chiou * @data - address of the data to send, byte by byte 19390899cc0SChe-liang Chiou * @len - length of the data to send 19490899cc0SChe-liang Chiou * 195d616ba5fSSimon Glass * Returns 0 on success, -ve on error (in case the device does not accept 196d616ba5fSSimon Glass * the entire command). 19790899cc0SChe-liang Chiou */ 198d616ba5fSSimon Glass static int tis_senddata(struct udevice *dev, const u8 *data, size_t len) 19990899cc0SChe-liang Chiou { 200d616ba5fSSimon Glass struct tpm_tis_lpc_priv *priv = dev_get_priv(dev); 201d616ba5fSSimon Glass struct tpm_locality *regs = priv->regs; 20290899cc0SChe-liang Chiou u32 offset = 0; 20390899cc0SChe-liang Chiou u16 burst = 0; 20490899cc0SChe-liang Chiou u32 max_cycles = 0; 20590899cc0SChe-liang Chiou u8 locality = 0; 20690899cc0SChe-liang Chiou u32 value; 20790899cc0SChe-liang Chiou 208d616ba5fSSimon Glass value = tis_wait_reg(priv, ®s[locality].tpm_status, 20990899cc0SChe-liang Chiou TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY); 210d616ba5fSSimon Glass if (value == -ETIMEDOUT) { 21190899cc0SChe-liang Chiou printf("%s:%d - failed to get 'command_ready' status\n", 21290899cc0SChe-liang Chiou __FILE__, __LINE__); 213d616ba5fSSimon Glass return value; 21490899cc0SChe-liang Chiou } 21590899cc0SChe-liang Chiou burst = burst_count(value); 21690899cc0SChe-liang Chiou 21790899cc0SChe-liang Chiou while (1) { 21890899cc0SChe-liang Chiou unsigned count; 21990899cc0SChe-liang Chiou 22090899cc0SChe-liang Chiou /* Wait till the device is ready to accept more data. */ 22190899cc0SChe-liang Chiou while (!burst) { 22290899cc0SChe-liang Chiou if (max_cycles++ == MAX_DELAY_US) { 22322230e91SSimon Glass printf("%s:%d failed to feed %zd bytes of %zd\n", 22490899cc0SChe-liang Chiou __FILE__, __LINE__, len - offset, len); 225d616ba5fSSimon Glass return -ETIMEDOUT; 22690899cc0SChe-liang Chiou } 22790899cc0SChe-liang Chiou udelay(1); 228d616ba5fSSimon Glass burst = burst_count(tpm_read_word(priv, 229d616ba5fSSimon Glass ®s[locality].tpm_status)); 23090899cc0SChe-liang Chiou } 23190899cc0SChe-liang Chiou 23290899cc0SChe-liang Chiou max_cycles = 0; 23390899cc0SChe-liang Chiou 23490899cc0SChe-liang Chiou /* 23590899cc0SChe-liang Chiou * Calculate number of bytes the TPM is ready to accept in one 23690899cc0SChe-liang Chiou * shot. 23790899cc0SChe-liang Chiou * 23890899cc0SChe-liang Chiou * We want to send the last byte outside of the loop (hence 23990899cc0SChe-liang Chiou * the -1 below) to make sure that the 'expected' status bit 24090899cc0SChe-liang Chiou * changes to zero exactly after the last byte is fed into the 24190899cc0SChe-liang Chiou * FIFO. 24290899cc0SChe-liang Chiou */ 24322230e91SSimon Glass count = min((size_t)burst, len - offset - 1); 24490899cc0SChe-liang Chiou while (count--) 245d616ba5fSSimon Glass tpm_write_byte(priv, data[offset++], 246d616ba5fSSimon Glass ®s[locality].data); 24790899cc0SChe-liang Chiou 248d616ba5fSSimon Glass value = tis_wait_reg(priv, ®s[locality].tpm_status, 24990899cc0SChe-liang Chiou TIS_STS_VALID, TIS_STS_VALID); 25090899cc0SChe-liang Chiou 251d616ba5fSSimon Glass if ((value == -ETIMEDOUT) || !(value & TIS_STS_EXPECT)) { 25290899cc0SChe-liang Chiou printf("%s:%d TPM command feed overflow\n", 25390899cc0SChe-liang Chiou __FILE__, __LINE__); 254d616ba5fSSimon Glass return value == -ETIMEDOUT ? value : -EIO; 25590899cc0SChe-liang Chiou } 25690899cc0SChe-liang Chiou 25790899cc0SChe-liang Chiou burst = burst_count(value); 25890899cc0SChe-liang Chiou if ((offset == (len - 1)) && burst) { 25990899cc0SChe-liang Chiou /* 26090899cc0SChe-liang Chiou * We need to be able to send the last byte to the 26190899cc0SChe-liang Chiou * device, so burst size must be nonzero before we 26290899cc0SChe-liang Chiou * break out. 26390899cc0SChe-liang Chiou */ 26490899cc0SChe-liang Chiou break; 26590899cc0SChe-liang Chiou } 26690899cc0SChe-liang Chiou } 26790899cc0SChe-liang Chiou 26890899cc0SChe-liang Chiou /* Send the last byte. */ 269d616ba5fSSimon Glass tpm_write_byte(priv, data[offset++], ®s[locality].data); 27090899cc0SChe-liang Chiou /* 27190899cc0SChe-liang Chiou * Verify that TPM does not expect any more data as part of this 27290899cc0SChe-liang Chiou * command. 27390899cc0SChe-liang Chiou */ 274d616ba5fSSimon Glass value = tis_wait_reg(priv, ®s[locality].tpm_status, 27590899cc0SChe-liang Chiou TIS_STS_VALID, TIS_STS_VALID); 276d616ba5fSSimon Glass if ((value == -ETIMEDOUT) || (value & TIS_STS_EXPECT)) { 27790899cc0SChe-liang Chiou printf("%s:%d unexpected TPM status 0x%x\n", 27890899cc0SChe-liang Chiou __FILE__, __LINE__, value); 279d616ba5fSSimon Glass return value == -ETIMEDOUT ? value : -EIO; 28090899cc0SChe-liang Chiou } 28190899cc0SChe-liang Chiou 28290899cc0SChe-liang Chiou /* OK, sitting pretty, let's start the command execution. */ 283d616ba5fSSimon Glass tpm_write_word(priv, TIS_STS_TPM_GO, ®s[locality].tpm_status); 28490899cc0SChe-liang Chiou return 0; 28590899cc0SChe-liang Chiou } 28690899cc0SChe-liang Chiou 28790899cc0SChe-liang Chiou /* 28890899cc0SChe-liang Chiou * tis_readresponse() 28990899cc0SChe-liang Chiou * 29090899cc0SChe-liang Chiou * read the TPM device response after a command was issued. 29190899cc0SChe-liang Chiou * 29290899cc0SChe-liang Chiou * @buffer - address where to read the response, byte by byte. 29390899cc0SChe-liang Chiou * @len - pointer to the size of buffer 29490899cc0SChe-liang Chiou * 29590899cc0SChe-liang Chiou * On success stores the number of received bytes to len and returns 0. On 29690899cc0SChe-liang Chiou * errors (misformatted TPM data or synchronization problems) returns 297d616ba5fSSimon Glass * -ve value. 29890899cc0SChe-liang Chiou */ 299d616ba5fSSimon Glass static int tis_readresponse(struct udevice *dev, u8 *buffer, size_t len) 30090899cc0SChe-liang Chiou { 301d616ba5fSSimon Glass struct tpm_tis_lpc_priv *priv = dev_get_priv(dev); 302d616ba5fSSimon Glass struct tpm_locality *regs = priv->regs; 30390899cc0SChe-liang Chiou u16 burst; 30490899cc0SChe-liang Chiou u32 value; 30590899cc0SChe-liang Chiou u32 offset = 0; 30690899cc0SChe-liang Chiou u8 locality = 0; 30790899cc0SChe-liang Chiou const u32 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID; 308d616ba5fSSimon Glass u32 expected_count = len; 30990899cc0SChe-liang Chiou int max_cycles = 0; 31090899cc0SChe-liang Chiou 31190899cc0SChe-liang Chiou /* Wait for the TPM to process the command. */ 312d616ba5fSSimon Glass value = tis_wait_reg(priv, ®s[locality].tpm_status, 31390899cc0SChe-liang Chiou has_data, has_data); 314d616ba5fSSimon Glass if (value == -ETIMEDOUT) { 31590899cc0SChe-liang Chiou printf("%s:%d failed processing command\n", 31690899cc0SChe-liang Chiou __FILE__, __LINE__); 317d616ba5fSSimon Glass return value; 31890899cc0SChe-liang Chiou } 31990899cc0SChe-liang Chiou 32090899cc0SChe-liang Chiou do { 32190899cc0SChe-liang Chiou while ((burst = burst_count(value)) == 0) { 32290899cc0SChe-liang Chiou if (max_cycles++ == MAX_DELAY_US) { 32390899cc0SChe-liang Chiou printf("%s:%d TPM stuck on read\n", 32490899cc0SChe-liang Chiou __FILE__, __LINE__); 325d616ba5fSSimon Glass return -EIO; 32690899cc0SChe-liang Chiou } 32790899cc0SChe-liang Chiou udelay(1); 328d616ba5fSSimon Glass value = tpm_read_word(priv, ®s[locality].tpm_status); 32990899cc0SChe-liang Chiou } 33090899cc0SChe-liang Chiou 33190899cc0SChe-liang Chiou max_cycles = 0; 33290899cc0SChe-liang Chiou 33390899cc0SChe-liang Chiou while (burst-- && (offset < expected_count)) { 334d616ba5fSSimon Glass buffer[offset++] = tpm_read_byte(priv, 335d616ba5fSSimon Glass ®s[locality].data); 33690899cc0SChe-liang Chiou 33790899cc0SChe-liang Chiou if (offset == 6) { 33890899cc0SChe-liang Chiou /* 33990899cc0SChe-liang Chiou * We got the first six bytes of the reply, 34090899cc0SChe-liang Chiou * let's figure out how many bytes to expect 34190899cc0SChe-liang Chiou * total - it is stored as a 4 byte number in 34290899cc0SChe-liang Chiou * network order, starting with offset 2 into 34390899cc0SChe-liang Chiou * the body of the reply. 34490899cc0SChe-liang Chiou */ 34590899cc0SChe-liang Chiou u32 real_length; 34690899cc0SChe-liang Chiou memcpy(&real_length, 34790899cc0SChe-liang Chiou buffer + 2, 34890899cc0SChe-liang Chiou sizeof(real_length)); 34990899cc0SChe-liang Chiou expected_count = be32_to_cpu(real_length); 35090899cc0SChe-liang Chiou 35190899cc0SChe-liang Chiou if ((expected_count < offset) || 352d616ba5fSSimon Glass (expected_count > len)) { 35390899cc0SChe-liang Chiou printf("%s:%d bad response size %d\n", 35490899cc0SChe-liang Chiou __FILE__, __LINE__, 35590899cc0SChe-liang Chiou expected_count); 356d616ba5fSSimon Glass return -ENOSPC; 35790899cc0SChe-liang Chiou } 35890899cc0SChe-liang Chiou } 35990899cc0SChe-liang Chiou } 36090899cc0SChe-liang Chiou 36190899cc0SChe-liang Chiou /* Wait for the next portion. */ 362d616ba5fSSimon Glass value = tis_wait_reg(priv, ®s[locality].tpm_status, 36390899cc0SChe-liang Chiou TIS_STS_VALID, TIS_STS_VALID); 364d616ba5fSSimon Glass if (value == -ETIMEDOUT) { 36590899cc0SChe-liang Chiou printf("%s:%d failed to read response\n", 36690899cc0SChe-liang Chiou __FILE__, __LINE__); 367d616ba5fSSimon Glass return value; 36890899cc0SChe-liang Chiou } 36990899cc0SChe-liang Chiou 37090899cc0SChe-liang Chiou if (offset == expected_count) 37190899cc0SChe-liang Chiou break; /* We got all we needed. */ 37290899cc0SChe-liang Chiou 37390899cc0SChe-liang Chiou } while ((value & has_data) == has_data); 37490899cc0SChe-liang Chiou 37590899cc0SChe-liang Chiou /* 37690899cc0SChe-liang Chiou * Make sure we indeed read all there was. The TIS_STS_VALID bit is 37790899cc0SChe-liang Chiou * known to be set. 37890899cc0SChe-liang Chiou */ 37990899cc0SChe-liang Chiou if (value & TIS_STS_DATA_AVAILABLE) { 38090899cc0SChe-liang Chiou printf("%s:%d wrong receive status %x\n", 38190899cc0SChe-liang Chiou __FILE__, __LINE__, value); 382d616ba5fSSimon Glass return -EBADMSG; 38390899cc0SChe-liang Chiou } 38490899cc0SChe-liang Chiou 38590899cc0SChe-liang Chiou /* Tell the TPM that we are done. */ 386d616ba5fSSimon Glass tpm_write_word(priv, TIS_STS_COMMAND_READY, 387d616ba5fSSimon Glass ®s[locality].tpm_status); 388d616ba5fSSimon Glass 389d616ba5fSSimon Glass return offset; 39090899cc0SChe-liang Chiou } 39190899cc0SChe-liang Chiou 392d616ba5fSSimon Glass static int tpm_tis_lpc_open(struct udevice *dev) 39390899cc0SChe-liang Chiou { 394d616ba5fSSimon Glass struct tpm_tis_lpc_priv *priv = dev_get_priv(dev); 395d616ba5fSSimon Glass struct tpm_locality *regs = priv->regs; 39690899cc0SChe-liang Chiou u8 locality = 0; /* we use locality zero for everything. */ 397d616ba5fSSimon Glass int ret; 39890899cc0SChe-liang Chiou 39990899cc0SChe-liang Chiou /* now request access to locality. */ 400d616ba5fSSimon Glass tpm_write_word(priv, TIS_ACCESS_REQUEST_USE, ®s[locality].access); 40190899cc0SChe-liang Chiou 40290899cc0SChe-liang Chiou /* did we get a lock? */ 403d616ba5fSSimon Glass ret = tis_wait_reg(priv, ®s[locality].access, 40490899cc0SChe-liang Chiou TIS_ACCESS_ACTIVE_LOCALITY, 405d616ba5fSSimon Glass TIS_ACCESS_ACTIVE_LOCALITY); 406d616ba5fSSimon Glass if (ret == -ETIMEDOUT) { 40790899cc0SChe-liang Chiou printf("%s:%d - failed to lock locality %d\n", 40890899cc0SChe-liang Chiou __FILE__, __LINE__, locality); 409d616ba5fSSimon Glass return ret; 41090899cc0SChe-liang Chiou } 41190899cc0SChe-liang Chiou 412d616ba5fSSimon Glass tpm_write_word(priv, TIS_STS_COMMAND_READY, 413d616ba5fSSimon Glass ®s[locality].tpm_status); 41490899cc0SChe-liang Chiou return 0; 41590899cc0SChe-liang Chiou } 41690899cc0SChe-liang Chiou 417d616ba5fSSimon Glass static int tpm_tis_lpc_close(struct udevice *dev) 41890899cc0SChe-liang Chiou { 419d616ba5fSSimon Glass struct tpm_tis_lpc_priv *priv = dev_get_priv(dev); 420d616ba5fSSimon Glass struct tpm_locality *regs = priv->regs; 42190899cc0SChe-liang Chiou u8 locality = 0; 42290899cc0SChe-liang Chiou 423d616ba5fSSimon Glass if (tpm_read_word(priv, ®s[locality].access) & 42490899cc0SChe-liang Chiou TIS_ACCESS_ACTIVE_LOCALITY) { 425d616ba5fSSimon Glass tpm_write_word(priv, TIS_ACCESS_ACTIVE_LOCALITY, 426d616ba5fSSimon Glass ®s[locality].access); 42790899cc0SChe-liang Chiou 428d616ba5fSSimon Glass if (tis_wait_reg(priv, ®s[locality].access, 429d616ba5fSSimon Glass TIS_ACCESS_ACTIVE_LOCALITY, 0) == -ETIMEDOUT) { 43090899cc0SChe-liang Chiou printf("%s:%d - failed to release locality %d\n", 43190899cc0SChe-liang Chiou __FILE__, __LINE__, locality); 432d616ba5fSSimon Glass return -ETIMEDOUT; 43390899cc0SChe-liang Chiou } 43490899cc0SChe-liang Chiou } 43590899cc0SChe-liang Chiou return 0; 43690899cc0SChe-liang Chiou } 43790899cc0SChe-liang Chiou 438d616ba5fSSimon Glass static int tpm_tis_get_desc(struct udevice *dev, char *buf, int size) 43990899cc0SChe-liang Chiou { 440*a982b6f5SGeorge McCollister ulong chip_type = dev_get_driver_data(dev); 441*a982b6f5SGeorge McCollister 442d616ba5fSSimon Glass if (size < 50) 443d616ba5fSSimon Glass return -ENOSPC; 444d616ba5fSSimon Glass 445*a982b6f5SGeorge McCollister return snprintf(buf, size, "1.2 TPM (%s)", 446*a982b6f5SGeorge McCollister chip_name[chip_type]); 44790899cc0SChe-liang Chiou } 44890899cc0SChe-liang Chiou 449d616ba5fSSimon Glass 450d616ba5fSSimon Glass static const struct tpm_ops tpm_tis_lpc_ops = { 451d616ba5fSSimon Glass .open = tpm_tis_lpc_open, 452d616ba5fSSimon Glass .close = tpm_tis_lpc_close, 453d616ba5fSSimon Glass .get_desc = tpm_tis_get_desc, 454d616ba5fSSimon Glass .send = tis_senddata, 455d616ba5fSSimon Glass .recv = tis_readresponse, 456d616ba5fSSimon Glass }; 457d616ba5fSSimon Glass 458d616ba5fSSimon Glass static const struct udevice_id tpm_tis_lpc_ids[] = { 459*a982b6f5SGeorge McCollister { .compatible = "infineon,slb9635lpc", .data = SLB9635 }, 460*a982b6f5SGeorge McCollister { .compatible = "atmel,at97sc3204", .data = AT97SC3204 }, 461d616ba5fSSimon Glass { } 462d616ba5fSSimon Glass }; 463d616ba5fSSimon Glass 464d616ba5fSSimon Glass U_BOOT_DRIVER(tpm_tis_lpc) = { 465d616ba5fSSimon Glass .name = "tpm_tis_lpc", 466d616ba5fSSimon Glass .id = UCLASS_TPM, 467d616ba5fSSimon Glass .of_match = tpm_tis_lpc_ids, 468d616ba5fSSimon Glass .ops = &tpm_tis_lpc_ops, 469d616ba5fSSimon Glass .probe = tpm_tis_lpc_probe, 470d616ba5fSSimon Glass .priv_auto_alloc_size = sizeof(struct tpm_tis_lpc_priv), 471d616ba5fSSimon Glass }; 472