183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 290899cc0SChe-liang Chiou /* 390899cc0SChe-liang Chiou * Copyright (c) 2011 The Chromium OS Authors. 490899cc0SChe-liang Chiou */ 590899cc0SChe-liang Chiou 690899cc0SChe-liang Chiou /* 790899cc0SChe-liang Chiou * The code in this file is based on the article "Writing a TPM Device Driver" 890899cc0SChe-liang Chiou * published on http://ptgmedia.pearsoncmg.com. 990899cc0SChe-liang Chiou * 1090899cc0SChe-liang Chiou * One principal difference is that in the simplest config the other than 0 1190899cc0SChe-liang Chiou * TPM localities do not get mapped by some devices (for instance, by Infineon 1290899cc0SChe-liang Chiou * slb9635), so this driver provides access to locality 0 only. 1390899cc0SChe-liang Chiou */ 1490899cc0SChe-liang Chiou 1590899cc0SChe-liang Chiou #include <common.h> 16d616ba5fSSimon Glass #include <dm.h> 17d616ba5fSSimon Glass #include <mapmem.h> 18d677bfe2SMiquel Raynal #include <tpm-v1.h> 19d616ba5fSSimon Glass #include <asm/io.h> 2090899cc0SChe-liang Chiou 2190899cc0SChe-liang Chiou #define PREFIX "lpc_tpm: " 2290899cc0SChe-liang Chiou 23a982b6f5SGeorge McCollister enum i2c_chip_type { 24a982b6f5SGeorge McCollister SLB9635, 25a982b6f5SGeorge McCollister AT97SC3204, 26a982b6f5SGeorge McCollister }; 27a982b6f5SGeorge McCollister 28a982b6f5SGeorge McCollister static const char * const chip_name[] = { 29a982b6f5SGeorge McCollister [SLB9635] = "Infineon SLB9635 TT 1.2", 30a982b6f5SGeorge McCollister [AT97SC3204] = "Atmel AT97SC3204", 31a982b6f5SGeorge McCollister }; 32a982b6f5SGeorge McCollister 33a982b6f5SGeorge McCollister static const u32 chip_didvid[] = { 34a982b6f5SGeorge McCollister [SLB9635] = 0xb15d1, 35a982b6f5SGeorge McCollister [AT97SC3204] = 0x32041114, 36a982b6f5SGeorge McCollister }; 37a982b6f5SGeorge McCollister 3890899cc0SChe-liang Chiou struct tpm_locality { 3990899cc0SChe-liang Chiou u32 access; 4090899cc0SChe-liang Chiou u8 padding0[4]; 4190899cc0SChe-liang Chiou u32 int_enable; 4290899cc0SChe-liang Chiou u8 vector; 4390899cc0SChe-liang Chiou u8 padding1[3]; 4490899cc0SChe-liang Chiou u32 int_status; 4590899cc0SChe-liang Chiou u32 int_capability; 4690899cc0SChe-liang Chiou u32 tpm_status; 4790899cc0SChe-liang Chiou u8 padding2[8]; 4890899cc0SChe-liang Chiou u8 data; 4990899cc0SChe-liang Chiou u8 padding3[3803]; 5090899cc0SChe-liang Chiou u32 did_vid; 5190899cc0SChe-liang Chiou u8 rid; 5290899cc0SChe-liang Chiou u8 padding4[251]; 5390899cc0SChe-liang Chiou }; 5490899cc0SChe-liang Chiou 55d616ba5fSSimon Glass struct tpm_tis_lpc_priv { 56d616ba5fSSimon Glass struct tpm_locality *regs; 57d616ba5fSSimon Glass }; 58d616ba5fSSimon Glass 5990899cc0SChe-liang Chiou /* 6090899cc0SChe-liang Chiou * This pointer refers to the TPM chip, 5 of its localities are mapped as an 6190899cc0SChe-liang Chiou * array. 6290899cc0SChe-liang Chiou */ 6390899cc0SChe-liang Chiou #define TPM_TOTAL_LOCALITIES 5 6490899cc0SChe-liang Chiou 6590899cc0SChe-liang Chiou /* Some registers' bit field definitions */ 6690899cc0SChe-liang Chiou #define TIS_STS_VALID (1 << 7) /* 0x80 */ 6790899cc0SChe-liang Chiou #define TIS_STS_COMMAND_READY (1 << 6) /* 0x40 */ 6890899cc0SChe-liang Chiou #define TIS_STS_TPM_GO (1 << 5) /* 0x20 */ 6990899cc0SChe-liang Chiou #define TIS_STS_DATA_AVAILABLE (1 << 4) /* 0x10 */ 7090899cc0SChe-liang Chiou #define TIS_STS_EXPECT (1 << 3) /* 0x08 */ 7190899cc0SChe-liang Chiou #define TIS_STS_RESPONSE_RETRY (1 << 1) /* 0x02 */ 7290899cc0SChe-liang Chiou 7390899cc0SChe-liang Chiou #define TIS_ACCESS_TPM_REG_VALID_STS (1 << 7) /* 0x80 */ 7490899cc0SChe-liang Chiou #define TIS_ACCESS_ACTIVE_LOCALITY (1 << 5) /* 0x20 */ 7590899cc0SChe-liang Chiou #define TIS_ACCESS_BEEN_SEIZED (1 << 4) /* 0x10 */ 7690899cc0SChe-liang Chiou #define TIS_ACCESS_SEIZE (1 << 3) /* 0x08 */ 7790899cc0SChe-liang Chiou #define TIS_ACCESS_PENDING_REQUEST (1 << 2) /* 0x04 */ 7890899cc0SChe-liang Chiou #define TIS_ACCESS_REQUEST_USE (1 << 1) /* 0x02 */ 7990899cc0SChe-liang Chiou #define TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0) /* 0x01 */ 8090899cc0SChe-liang Chiou 8190899cc0SChe-liang Chiou #define TIS_STS_BURST_COUNT_MASK (0xffff) 8290899cc0SChe-liang Chiou #define TIS_STS_BURST_COUNT_SHIFT (8) 8390899cc0SChe-liang Chiou 8490899cc0SChe-liang Chiou /* 1 second is plenty for anything TPM does. */ 8590899cc0SChe-liang Chiou #define MAX_DELAY_US (1000 * 1000) 8690899cc0SChe-liang Chiou 8790899cc0SChe-liang Chiou /* Retrieve burst count value out of the status register contents. */ 8890899cc0SChe-liang Chiou static u16 burst_count(u32 status) 8990899cc0SChe-liang Chiou { 90d616ba5fSSimon Glass return (status >> TIS_STS_BURST_COUNT_SHIFT) & 91d616ba5fSSimon Glass TIS_STS_BURST_COUNT_MASK; 9290899cc0SChe-liang Chiou } 9390899cc0SChe-liang Chiou 9490899cc0SChe-liang Chiou /* TPM access wrappers to support tracing */ 95d616ba5fSSimon Glass static u8 tpm_read_byte(struct tpm_tis_lpc_priv *priv, const u8 *ptr) 9690899cc0SChe-liang Chiou { 9790899cc0SChe-liang Chiou u8 ret = readb(ptr); 9890899cc0SChe-liang Chiou debug(PREFIX "Read reg 0x%4.4x returns 0x%2.2x\n", 99d616ba5fSSimon Glass (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, ret); 10090899cc0SChe-liang Chiou return ret; 10190899cc0SChe-liang Chiou } 10290899cc0SChe-liang Chiou 103d616ba5fSSimon Glass static u32 tpm_read_word(struct tpm_tis_lpc_priv *priv, const u32 *ptr) 10490899cc0SChe-liang Chiou { 10590899cc0SChe-liang Chiou u32 ret = readl(ptr); 10690899cc0SChe-liang Chiou debug(PREFIX "Read reg 0x%4.4x returns 0x%8.8x\n", 107d616ba5fSSimon Glass (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, ret); 10890899cc0SChe-liang Chiou return ret; 10990899cc0SChe-liang Chiou } 11090899cc0SChe-liang Chiou 111d616ba5fSSimon Glass static void tpm_write_byte(struct tpm_tis_lpc_priv *priv, u8 value, u8 *ptr) 11290899cc0SChe-liang Chiou { 11390899cc0SChe-liang Chiou debug(PREFIX "Write reg 0x%4.4x with 0x%2.2x\n", 114d616ba5fSSimon Glass (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, value); 11590899cc0SChe-liang Chiou writeb(value, ptr); 11690899cc0SChe-liang Chiou } 11790899cc0SChe-liang Chiou 118d616ba5fSSimon Glass static void tpm_write_word(struct tpm_tis_lpc_priv *priv, u32 value, 119d616ba5fSSimon Glass u32 *ptr) 12090899cc0SChe-liang Chiou { 12190899cc0SChe-liang Chiou debug(PREFIX "Write reg 0x%4.4x with 0x%8.8x\n", 122d616ba5fSSimon Glass (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, value); 12390899cc0SChe-liang Chiou writel(value, ptr); 12490899cc0SChe-liang Chiou } 12590899cc0SChe-liang Chiou 12690899cc0SChe-liang Chiou /* 12790899cc0SChe-liang Chiou * tis_wait_reg() 12890899cc0SChe-liang Chiou * 12990899cc0SChe-liang Chiou * Wait for at least a second for a register to change its state to match the 13090899cc0SChe-liang Chiou * expected state. Normally the transition happens within microseconds. 13190899cc0SChe-liang Chiou * 13290899cc0SChe-liang Chiou * @reg - pointer to the TPM register 13390899cc0SChe-liang Chiou * @mask - bitmask for the bitfield(s) to watch 13490899cc0SChe-liang Chiou * @expected - value the field(s) are supposed to be set to 13590899cc0SChe-liang Chiou * 13690899cc0SChe-liang Chiou * Returns the register contents in case the expected value was found in the 137d616ba5fSSimon Glass * appropriate register bits, or -ETIMEDOUT on timeout. 13890899cc0SChe-liang Chiou */ 139d616ba5fSSimon Glass static int tis_wait_reg(struct tpm_tis_lpc_priv *priv, u32 *reg, u8 mask, 140d616ba5fSSimon Glass u8 expected) 14190899cc0SChe-liang Chiou { 14290899cc0SChe-liang Chiou u32 time_us = MAX_DELAY_US; 14390899cc0SChe-liang Chiou 14490899cc0SChe-liang Chiou while (time_us > 0) { 145d616ba5fSSimon Glass u32 value = tpm_read_word(priv, reg); 14690899cc0SChe-liang Chiou if ((value & mask) == expected) 14790899cc0SChe-liang Chiou return value; 14890899cc0SChe-liang Chiou udelay(1); /* 1 us */ 14990899cc0SChe-liang Chiou time_us--; 15090899cc0SChe-liang Chiou } 151d616ba5fSSimon Glass 152d616ba5fSSimon Glass return -ETIMEDOUT; 15390899cc0SChe-liang Chiou } 15490899cc0SChe-liang Chiou 15590899cc0SChe-liang Chiou /* 15690899cc0SChe-liang Chiou * Probe the TPM device and try determining its manufacturer/device name. 15790899cc0SChe-liang Chiou * 158d616ba5fSSimon Glass * Returns 0 on success, -ve on error 15990899cc0SChe-liang Chiou */ 160d616ba5fSSimon Glass static int tpm_tis_lpc_probe(struct udevice *dev) 16190899cc0SChe-liang Chiou { 162d616ba5fSSimon Glass struct tpm_tis_lpc_priv *priv = dev_get_priv(dev); 163d616ba5fSSimon Glass fdt_addr_t addr; 164d616ba5fSSimon Glass u32 didvid; 165a982b6f5SGeorge McCollister ulong chip_type = dev_get_driver_data(dev); 16690899cc0SChe-liang Chiou 167*c89d32a7SSimon Glass addr = dev_read_addr(dev); 168d616ba5fSSimon Glass if (addr == FDT_ADDR_T_NONE) 169d616ba5fSSimon Glass return -EINVAL; 170d616ba5fSSimon Glass priv->regs = map_sysmem(addr, 0); 171d616ba5fSSimon Glass didvid = tpm_read_word(priv, &priv->regs[0].did_vid); 17290899cc0SChe-liang Chiou 173a982b6f5SGeorge McCollister if (didvid != chip_didvid[chip_type]) { 174a982b6f5SGeorge McCollister u32 vid, did; 17590899cc0SChe-liang Chiou vid = didvid & 0xffff; 17690899cc0SChe-liang Chiou did = (didvid >> 16) & 0xffff; 177d616ba5fSSimon Glass debug("Invalid vendor/device ID %04x/%04x\n", vid, did); 178a982b6f5SGeorge McCollister return -ENODEV; 17990899cc0SChe-liang Chiou } 18090899cc0SChe-liang Chiou 181a982b6f5SGeorge McCollister debug("Found TPM: %s\n", chip_name[chip_type]); 182d616ba5fSSimon Glass 18390899cc0SChe-liang Chiou return 0; 18490899cc0SChe-liang Chiou } 18590899cc0SChe-liang Chiou 18690899cc0SChe-liang Chiou /* 18790899cc0SChe-liang Chiou * tis_senddata() 18890899cc0SChe-liang Chiou * 18990899cc0SChe-liang Chiou * send the passed in data to the TPM device. 19090899cc0SChe-liang Chiou * 19190899cc0SChe-liang Chiou * @data - address of the data to send, byte by byte 19290899cc0SChe-liang Chiou * @len - length of the data to send 19390899cc0SChe-liang Chiou * 194d616ba5fSSimon Glass * Returns 0 on success, -ve on error (in case the device does not accept 195d616ba5fSSimon Glass * the entire command). 19690899cc0SChe-liang Chiou */ 197d616ba5fSSimon Glass static int tis_senddata(struct udevice *dev, const u8 *data, size_t len) 19890899cc0SChe-liang Chiou { 199d616ba5fSSimon Glass struct tpm_tis_lpc_priv *priv = dev_get_priv(dev); 200d616ba5fSSimon Glass struct tpm_locality *regs = priv->regs; 20190899cc0SChe-liang Chiou u32 offset = 0; 20290899cc0SChe-liang Chiou u16 burst = 0; 20390899cc0SChe-liang Chiou u32 max_cycles = 0; 20490899cc0SChe-liang Chiou u8 locality = 0; 20590899cc0SChe-liang Chiou u32 value; 20690899cc0SChe-liang Chiou 207d616ba5fSSimon Glass value = tis_wait_reg(priv, ®s[locality].tpm_status, 20890899cc0SChe-liang Chiou TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY); 209d616ba5fSSimon Glass if (value == -ETIMEDOUT) { 21090899cc0SChe-liang Chiou printf("%s:%d - failed to get 'command_ready' status\n", 21190899cc0SChe-liang Chiou __FILE__, __LINE__); 212d616ba5fSSimon Glass return value; 21390899cc0SChe-liang Chiou } 21490899cc0SChe-liang Chiou burst = burst_count(value); 21590899cc0SChe-liang Chiou 21690899cc0SChe-liang Chiou while (1) { 21790899cc0SChe-liang Chiou unsigned count; 21890899cc0SChe-liang Chiou 21990899cc0SChe-liang Chiou /* Wait till the device is ready to accept more data. */ 22090899cc0SChe-liang Chiou while (!burst) { 22190899cc0SChe-liang Chiou if (max_cycles++ == MAX_DELAY_US) { 22222230e91SSimon Glass printf("%s:%d failed to feed %zd bytes of %zd\n", 22390899cc0SChe-liang Chiou __FILE__, __LINE__, len - offset, len); 224d616ba5fSSimon Glass return -ETIMEDOUT; 22590899cc0SChe-liang Chiou } 22690899cc0SChe-liang Chiou udelay(1); 227d616ba5fSSimon Glass burst = burst_count(tpm_read_word(priv, 228d616ba5fSSimon Glass ®s[locality].tpm_status)); 22990899cc0SChe-liang Chiou } 23090899cc0SChe-liang Chiou 23190899cc0SChe-liang Chiou max_cycles = 0; 23290899cc0SChe-liang Chiou 23390899cc0SChe-liang Chiou /* 23490899cc0SChe-liang Chiou * Calculate number of bytes the TPM is ready to accept in one 23590899cc0SChe-liang Chiou * shot. 23690899cc0SChe-liang Chiou * 23790899cc0SChe-liang Chiou * We want to send the last byte outside of the loop (hence 23890899cc0SChe-liang Chiou * the -1 below) to make sure that the 'expected' status bit 23990899cc0SChe-liang Chiou * changes to zero exactly after the last byte is fed into the 24090899cc0SChe-liang Chiou * FIFO. 24190899cc0SChe-liang Chiou */ 24222230e91SSimon Glass count = min((size_t)burst, len - offset - 1); 24390899cc0SChe-liang Chiou while (count--) 244d616ba5fSSimon Glass tpm_write_byte(priv, data[offset++], 245d616ba5fSSimon Glass ®s[locality].data); 24690899cc0SChe-liang Chiou 247d616ba5fSSimon Glass value = tis_wait_reg(priv, ®s[locality].tpm_status, 24890899cc0SChe-liang Chiou TIS_STS_VALID, TIS_STS_VALID); 24990899cc0SChe-liang Chiou 250d616ba5fSSimon Glass if ((value == -ETIMEDOUT) || !(value & TIS_STS_EXPECT)) { 25190899cc0SChe-liang Chiou printf("%s:%d TPM command feed overflow\n", 25290899cc0SChe-liang Chiou __FILE__, __LINE__); 253d616ba5fSSimon Glass return value == -ETIMEDOUT ? value : -EIO; 25490899cc0SChe-liang Chiou } 25590899cc0SChe-liang Chiou 25690899cc0SChe-liang Chiou burst = burst_count(value); 25790899cc0SChe-liang Chiou if ((offset == (len - 1)) && burst) { 25890899cc0SChe-liang Chiou /* 25990899cc0SChe-liang Chiou * We need to be able to send the last byte to the 26090899cc0SChe-liang Chiou * device, so burst size must be nonzero before we 26190899cc0SChe-liang Chiou * break out. 26290899cc0SChe-liang Chiou */ 26390899cc0SChe-liang Chiou break; 26490899cc0SChe-liang Chiou } 26590899cc0SChe-liang Chiou } 26690899cc0SChe-liang Chiou 26790899cc0SChe-liang Chiou /* Send the last byte. */ 268d616ba5fSSimon Glass tpm_write_byte(priv, data[offset++], ®s[locality].data); 26990899cc0SChe-liang Chiou /* 27090899cc0SChe-liang Chiou * Verify that TPM does not expect any more data as part of this 27190899cc0SChe-liang Chiou * command. 27290899cc0SChe-liang Chiou */ 273d616ba5fSSimon Glass value = tis_wait_reg(priv, ®s[locality].tpm_status, 27490899cc0SChe-liang Chiou TIS_STS_VALID, TIS_STS_VALID); 275d616ba5fSSimon Glass if ((value == -ETIMEDOUT) || (value & TIS_STS_EXPECT)) { 27690899cc0SChe-liang Chiou printf("%s:%d unexpected TPM status 0x%x\n", 27790899cc0SChe-liang Chiou __FILE__, __LINE__, value); 278d616ba5fSSimon Glass return value == -ETIMEDOUT ? value : -EIO; 27990899cc0SChe-liang Chiou } 28090899cc0SChe-liang Chiou 28190899cc0SChe-liang Chiou /* OK, sitting pretty, let's start the command execution. */ 282d616ba5fSSimon Glass tpm_write_word(priv, TIS_STS_TPM_GO, ®s[locality].tpm_status); 28390899cc0SChe-liang Chiou return 0; 28490899cc0SChe-liang Chiou } 28590899cc0SChe-liang Chiou 28690899cc0SChe-liang Chiou /* 28790899cc0SChe-liang Chiou * tis_readresponse() 28890899cc0SChe-liang Chiou * 28990899cc0SChe-liang Chiou * read the TPM device response after a command was issued. 29090899cc0SChe-liang Chiou * 29190899cc0SChe-liang Chiou * @buffer - address where to read the response, byte by byte. 29290899cc0SChe-liang Chiou * @len - pointer to the size of buffer 29390899cc0SChe-liang Chiou * 29490899cc0SChe-liang Chiou * On success stores the number of received bytes to len and returns 0. On 29590899cc0SChe-liang Chiou * errors (misformatted TPM data or synchronization problems) returns 296d616ba5fSSimon Glass * -ve value. 29790899cc0SChe-liang Chiou */ 298d616ba5fSSimon Glass static int tis_readresponse(struct udevice *dev, u8 *buffer, size_t len) 29990899cc0SChe-liang Chiou { 300d616ba5fSSimon Glass struct tpm_tis_lpc_priv *priv = dev_get_priv(dev); 301d616ba5fSSimon Glass struct tpm_locality *regs = priv->regs; 30290899cc0SChe-liang Chiou u16 burst; 30390899cc0SChe-liang Chiou u32 value; 30490899cc0SChe-liang Chiou u32 offset = 0; 30590899cc0SChe-liang Chiou u8 locality = 0; 30690899cc0SChe-liang Chiou const u32 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID; 307d616ba5fSSimon Glass u32 expected_count = len; 30890899cc0SChe-liang Chiou int max_cycles = 0; 30990899cc0SChe-liang Chiou 31090899cc0SChe-liang Chiou /* Wait for the TPM to process the command. */ 311d616ba5fSSimon Glass value = tis_wait_reg(priv, ®s[locality].tpm_status, 31290899cc0SChe-liang Chiou has_data, has_data); 313d616ba5fSSimon Glass if (value == -ETIMEDOUT) { 31490899cc0SChe-liang Chiou printf("%s:%d failed processing command\n", 31590899cc0SChe-liang Chiou __FILE__, __LINE__); 316d616ba5fSSimon Glass return value; 31790899cc0SChe-liang Chiou } 31890899cc0SChe-liang Chiou 31990899cc0SChe-liang Chiou do { 32090899cc0SChe-liang Chiou while ((burst = burst_count(value)) == 0) { 32190899cc0SChe-liang Chiou if (max_cycles++ == MAX_DELAY_US) { 32290899cc0SChe-liang Chiou printf("%s:%d TPM stuck on read\n", 32390899cc0SChe-liang Chiou __FILE__, __LINE__); 324d616ba5fSSimon Glass return -EIO; 32590899cc0SChe-liang Chiou } 32690899cc0SChe-liang Chiou udelay(1); 327d616ba5fSSimon Glass value = tpm_read_word(priv, ®s[locality].tpm_status); 32890899cc0SChe-liang Chiou } 32990899cc0SChe-liang Chiou 33090899cc0SChe-liang Chiou max_cycles = 0; 33190899cc0SChe-liang Chiou 33290899cc0SChe-liang Chiou while (burst-- && (offset < expected_count)) { 333d616ba5fSSimon Glass buffer[offset++] = tpm_read_byte(priv, 334d616ba5fSSimon Glass ®s[locality].data); 33590899cc0SChe-liang Chiou 33690899cc0SChe-liang Chiou if (offset == 6) { 33790899cc0SChe-liang Chiou /* 33890899cc0SChe-liang Chiou * We got the first six bytes of the reply, 33990899cc0SChe-liang Chiou * let's figure out how many bytes to expect 34090899cc0SChe-liang Chiou * total - it is stored as a 4 byte number in 34190899cc0SChe-liang Chiou * network order, starting with offset 2 into 34290899cc0SChe-liang Chiou * the body of the reply. 34390899cc0SChe-liang Chiou */ 34490899cc0SChe-liang Chiou u32 real_length; 34590899cc0SChe-liang Chiou memcpy(&real_length, 34690899cc0SChe-liang Chiou buffer + 2, 34790899cc0SChe-liang Chiou sizeof(real_length)); 34890899cc0SChe-liang Chiou expected_count = be32_to_cpu(real_length); 34990899cc0SChe-liang Chiou 35090899cc0SChe-liang Chiou if ((expected_count < offset) || 351d616ba5fSSimon Glass (expected_count > len)) { 35290899cc0SChe-liang Chiou printf("%s:%d bad response size %d\n", 35390899cc0SChe-liang Chiou __FILE__, __LINE__, 35490899cc0SChe-liang Chiou expected_count); 355d616ba5fSSimon Glass return -ENOSPC; 35690899cc0SChe-liang Chiou } 35790899cc0SChe-liang Chiou } 35890899cc0SChe-liang Chiou } 35990899cc0SChe-liang Chiou 36090899cc0SChe-liang Chiou /* Wait for the next portion. */ 361d616ba5fSSimon Glass value = tis_wait_reg(priv, ®s[locality].tpm_status, 36290899cc0SChe-liang Chiou TIS_STS_VALID, TIS_STS_VALID); 363d616ba5fSSimon Glass if (value == -ETIMEDOUT) { 36490899cc0SChe-liang Chiou printf("%s:%d failed to read response\n", 36590899cc0SChe-liang Chiou __FILE__, __LINE__); 366d616ba5fSSimon Glass return value; 36790899cc0SChe-liang Chiou } 36890899cc0SChe-liang Chiou 36990899cc0SChe-liang Chiou if (offset == expected_count) 37090899cc0SChe-liang Chiou break; /* We got all we needed. */ 37190899cc0SChe-liang Chiou 37290899cc0SChe-liang Chiou } while ((value & has_data) == has_data); 37390899cc0SChe-liang Chiou 37490899cc0SChe-liang Chiou /* 37590899cc0SChe-liang Chiou * Make sure we indeed read all there was. The TIS_STS_VALID bit is 37690899cc0SChe-liang Chiou * known to be set. 37790899cc0SChe-liang Chiou */ 37890899cc0SChe-liang Chiou if (value & TIS_STS_DATA_AVAILABLE) { 37990899cc0SChe-liang Chiou printf("%s:%d wrong receive status %x\n", 38090899cc0SChe-liang Chiou __FILE__, __LINE__, value); 381d616ba5fSSimon Glass return -EBADMSG; 38290899cc0SChe-liang Chiou } 38390899cc0SChe-liang Chiou 38490899cc0SChe-liang Chiou /* Tell the TPM that we are done. */ 385d616ba5fSSimon Glass tpm_write_word(priv, TIS_STS_COMMAND_READY, 386d616ba5fSSimon Glass ®s[locality].tpm_status); 387d616ba5fSSimon Glass 388d616ba5fSSimon Glass return offset; 38990899cc0SChe-liang Chiou } 39090899cc0SChe-liang Chiou 391d616ba5fSSimon Glass static int tpm_tis_lpc_open(struct udevice *dev) 39290899cc0SChe-liang Chiou { 393d616ba5fSSimon Glass struct tpm_tis_lpc_priv *priv = dev_get_priv(dev); 394d616ba5fSSimon Glass struct tpm_locality *regs = priv->regs; 39590899cc0SChe-liang Chiou u8 locality = 0; /* we use locality zero for everything. */ 396d616ba5fSSimon Glass int ret; 39790899cc0SChe-liang Chiou 39890899cc0SChe-liang Chiou /* now request access to locality. */ 399d616ba5fSSimon Glass tpm_write_word(priv, TIS_ACCESS_REQUEST_USE, ®s[locality].access); 40090899cc0SChe-liang Chiou 40190899cc0SChe-liang Chiou /* did we get a lock? */ 402d616ba5fSSimon Glass ret = tis_wait_reg(priv, ®s[locality].access, 40390899cc0SChe-liang Chiou TIS_ACCESS_ACTIVE_LOCALITY, 404d616ba5fSSimon Glass TIS_ACCESS_ACTIVE_LOCALITY); 405d616ba5fSSimon Glass if (ret == -ETIMEDOUT) { 40690899cc0SChe-liang Chiou printf("%s:%d - failed to lock locality %d\n", 40790899cc0SChe-liang Chiou __FILE__, __LINE__, locality); 408d616ba5fSSimon Glass return ret; 40990899cc0SChe-liang Chiou } 41090899cc0SChe-liang Chiou 411d616ba5fSSimon Glass tpm_write_word(priv, TIS_STS_COMMAND_READY, 412d616ba5fSSimon Glass ®s[locality].tpm_status); 41390899cc0SChe-liang Chiou return 0; 41490899cc0SChe-liang Chiou } 41590899cc0SChe-liang Chiou 416d616ba5fSSimon Glass static int tpm_tis_lpc_close(struct udevice *dev) 41790899cc0SChe-liang Chiou { 418d616ba5fSSimon Glass struct tpm_tis_lpc_priv *priv = dev_get_priv(dev); 419d616ba5fSSimon Glass struct tpm_locality *regs = priv->regs; 42090899cc0SChe-liang Chiou u8 locality = 0; 42190899cc0SChe-liang Chiou 422d616ba5fSSimon Glass if (tpm_read_word(priv, ®s[locality].access) & 42390899cc0SChe-liang Chiou TIS_ACCESS_ACTIVE_LOCALITY) { 424d616ba5fSSimon Glass tpm_write_word(priv, TIS_ACCESS_ACTIVE_LOCALITY, 425d616ba5fSSimon Glass ®s[locality].access); 42690899cc0SChe-liang Chiou 427d616ba5fSSimon Glass if (tis_wait_reg(priv, ®s[locality].access, 428d616ba5fSSimon Glass TIS_ACCESS_ACTIVE_LOCALITY, 0) == -ETIMEDOUT) { 42990899cc0SChe-liang Chiou printf("%s:%d - failed to release locality %d\n", 43090899cc0SChe-liang Chiou __FILE__, __LINE__, locality); 431d616ba5fSSimon Glass return -ETIMEDOUT; 43290899cc0SChe-liang Chiou } 43390899cc0SChe-liang Chiou } 43490899cc0SChe-liang Chiou return 0; 43590899cc0SChe-liang Chiou } 43690899cc0SChe-liang Chiou 437d616ba5fSSimon Glass static int tpm_tis_get_desc(struct udevice *dev, char *buf, int size) 43890899cc0SChe-liang Chiou { 439a982b6f5SGeorge McCollister ulong chip_type = dev_get_driver_data(dev); 440a982b6f5SGeorge McCollister 441d616ba5fSSimon Glass if (size < 50) 442d616ba5fSSimon Glass return -ENOSPC; 443d616ba5fSSimon Glass 444a982b6f5SGeorge McCollister return snprintf(buf, size, "1.2 TPM (%s)", 445a982b6f5SGeorge McCollister chip_name[chip_type]); 44690899cc0SChe-liang Chiou } 44790899cc0SChe-liang Chiou 448d616ba5fSSimon Glass 449d616ba5fSSimon Glass static const struct tpm_ops tpm_tis_lpc_ops = { 450d616ba5fSSimon Glass .open = tpm_tis_lpc_open, 451d616ba5fSSimon Glass .close = tpm_tis_lpc_close, 452d616ba5fSSimon Glass .get_desc = tpm_tis_get_desc, 453d616ba5fSSimon Glass .send = tis_senddata, 454d616ba5fSSimon Glass .recv = tis_readresponse, 455d616ba5fSSimon Glass }; 456d616ba5fSSimon Glass 457d616ba5fSSimon Glass static const struct udevice_id tpm_tis_lpc_ids[] = { 458a982b6f5SGeorge McCollister { .compatible = "infineon,slb9635lpc", .data = SLB9635 }, 459a982b6f5SGeorge McCollister { .compatible = "atmel,at97sc3204", .data = AT97SC3204 }, 460d616ba5fSSimon Glass { } 461d616ba5fSSimon Glass }; 462d616ba5fSSimon Glass 463d616ba5fSSimon Glass U_BOOT_DRIVER(tpm_tis_lpc) = { 464d616ba5fSSimon Glass .name = "tpm_tis_lpc", 465d616ba5fSSimon Glass .id = UCLASS_TPM, 466d616ba5fSSimon Glass .of_match = tpm_tis_lpc_ids, 467d616ba5fSSimon Glass .ops = &tpm_tis_lpc_ops, 468d616ba5fSSimon Glass .probe = tpm_tis_lpc_probe, 469d616ba5fSSimon Glass .priv_auto_alloc_size = sizeof(struct tpm_tis_lpc_priv), 470d616ba5fSSimon Glass }; 471