190899cc0SChe-liang Chiou /* 290899cc0SChe-liang Chiou * Copyright (c) 2011 The Chromium OS Authors. 390899cc0SChe-liang Chiou * 4*1a459660SWolfgang 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> 1790899cc0SChe-liang Chiou #include <asm/io.h> 1890899cc0SChe-liang Chiou #include <tpm.h> 1990899cc0SChe-liang Chiou 2090899cc0SChe-liang Chiou #define PREFIX "lpc_tpm: " 2190899cc0SChe-liang Chiou 2290899cc0SChe-liang Chiou struct tpm_locality { 2390899cc0SChe-liang Chiou u32 access; 2490899cc0SChe-liang Chiou u8 padding0[4]; 2590899cc0SChe-liang Chiou u32 int_enable; 2690899cc0SChe-liang Chiou u8 vector; 2790899cc0SChe-liang Chiou u8 padding1[3]; 2890899cc0SChe-liang Chiou u32 int_status; 2990899cc0SChe-liang Chiou u32 int_capability; 3090899cc0SChe-liang Chiou u32 tpm_status; 3190899cc0SChe-liang Chiou u8 padding2[8]; 3290899cc0SChe-liang Chiou u8 data; 3390899cc0SChe-liang Chiou u8 padding3[3803]; 3490899cc0SChe-liang Chiou u32 did_vid; 3590899cc0SChe-liang Chiou u8 rid; 3690899cc0SChe-liang Chiou u8 padding4[251]; 3790899cc0SChe-liang Chiou }; 3890899cc0SChe-liang Chiou 3990899cc0SChe-liang Chiou /* 4090899cc0SChe-liang Chiou * This pointer refers to the TPM chip, 5 of its localities are mapped as an 4190899cc0SChe-liang Chiou * array. 4290899cc0SChe-liang Chiou */ 4390899cc0SChe-liang Chiou #define TPM_TOTAL_LOCALITIES 5 4490899cc0SChe-liang Chiou static struct tpm_locality *lpc_tpm_dev = 4590899cc0SChe-liang Chiou (struct tpm_locality *)CONFIG_TPM_TIS_BASE_ADDRESS; 4690899cc0SChe-liang Chiou 4790899cc0SChe-liang Chiou /* Some registers' bit field definitions */ 4890899cc0SChe-liang Chiou #define TIS_STS_VALID (1 << 7) /* 0x80 */ 4990899cc0SChe-liang Chiou #define TIS_STS_COMMAND_READY (1 << 6) /* 0x40 */ 5090899cc0SChe-liang Chiou #define TIS_STS_TPM_GO (1 << 5) /* 0x20 */ 5190899cc0SChe-liang Chiou #define TIS_STS_DATA_AVAILABLE (1 << 4) /* 0x10 */ 5290899cc0SChe-liang Chiou #define TIS_STS_EXPECT (1 << 3) /* 0x08 */ 5390899cc0SChe-liang Chiou #define TIS_STS_RESPONSE_RETRY (1 << 1) /* 0x02 */ 5490899cc0SChe-liang Chiou 5590899cc0SChe-liang Chiou #define TIS_ACCESS_TPM_REG_VALID_STS (1 << 7) /* 0x80 */ 5690899cc0SChe-liang Chiou #define TIS_ACCESS_ACTIVE_LOCALITY (1 << 5) /* 0x20 */ 5790899cc0SChe-liang Chiou #define TIS_ACCESS_BEEN_SEIZED (1 << 4) /* 0x10 */ 5890899cc0SChe-liang Chiou #define TIS_ACCESS_SEIZE (1 << 3) /* 0x08 */ 5990899cc0SChe-liang Chiou #define TIS_ACCESS_PENDING_REQUEST (1 << 2) /* 0x04 */ 6090899cc0SChe-liang Chiou #define TIS_ACCESS_REQUEST_USE (1 << 1) /* 0x02 */ 6190899cc0SChe-liang Chiou #define TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0) /* 0x01 */ 6290899cc0SChe-liang Chiou 6390899cc0SChe-liang Chiou #define TIS_STS_BURST_COUNT_MASK (0xffff) 6490899cc0SChe-liang Chiou #define TIS_STS_BURST_COUNT_SHIFT (8) 6590899cc0SChe-liang Chiou 6690899cc0SChe-liang Chiou /* 6790899cc0SChe-liang Chiou * Error value returned if a tpm register does not enter the expected state 6890899cc0SChe-liang Chiou * after continuous polling. No actual TPM register reading ever returns -1, 6990899cc0SChe-liang Chiou * so this value is a safe error indication to be mixed with possible status 7090899cc0SChe-liang Chiou * register values. 7190899cc0SChe-liang Chiou */ 7290899cc0SChe-liang Chiou #define TPM_TIMEOUT_ERR (-1) 7390899cc0SChe-liang Chiou 7490899cc0SChe-liang Chiou /* Error value returned on various TPM driver errors. */ 7590899cc0SChe-liang Chiou #define TPM_DRIVER_ERR (1) 7690899cc0SChe-liang Chiou 7790899cc0SChe-liang Chiou /* 1 second is plenty for anything TPM does. */ 7890899cc0SChe-liang Chiou #define MAX_DELAY_US (1000 * 1000) 7990899cc0SChe-liang Chiou 8090899cc0SChe-liang Chiou /* Retrieve burst count value out of the status register contents. */ 8190899cc0SChe-liang Chiou static u16 burst_count(u32 status) 8290899cc0SChe-liang Chiou { 8390899cc0SChe-liang Chiou return (status >> TIS_STS_BURST_COUNT_SHIFT) & TIS_STS_BURST_COUNT_MASK; 8490899cc0SChe-liang Chiou } 8590899cc0SChe-liang Chiou 8690899cc0SChe-liang Chiou /* 8790899cc0SChe-liang Chiou * Structures defined below allow creating descriptions of TPM vendor/device 8890899cc0SChe-liang Chiou * ID information for run time discovery. The only device the system knows 8990899cc0SChe-liang Chiou * about at this time is Infineon slb9635. 9090899cc0SChe-liang Chiou */ 9190899cc0SChe-liang Chiou struct device_name { 9290899cc0SChe-liang Chiou u16 dev_id; 9390899cc0SChe-liang Chiou const char * const dev_name; 9490899cc0SChe-liang Chiou }; 9590899cc0SChe-liang Chiou 9690899cc0SChe-liang Chiou struct vendor_name { 9790899cc0SChe-liang Chiou u16 vendor_id; 9890899cc0SChe-liang Chiou const char *vendor_name; 9990899cc0SChe-liang Chiou const struct device_name *dev_names; 10090899cc0SChe-liang Chiou }; 10190899cc0SChe-liang Chiou 10290899cc0SChe-liang Chiou static const struct device_name infineon_devices[] = { 10390899cc0SChe-liang Chiou {0xb, "SLB9635 TT 1.2"}, 10490899cc0SChe-liang Chiou {0} 10590899cc0SChe-liang Chiou }; 10690899cc0SChe-liang Chiou 10790899cc0SChe-liang Chiou static const struct vendor_name vendor_names[] = { 10890899cc0SChe-liang Chiou {0x15d1, "Infineon", infineon_devices}, 10990899cc0SChe-liang Chiou }; 11090899cc0SChe-liang Chiou 11190899cc0SChe-liang Chiou /* 11290899cc0SChe-liang Chiou * Cached vendor/device ID pair to indicate that the device has been already 11390899cc0SChe-liang Chiou * discovered. 11490899cc0SChe-liang Chiou */ 11590899cc0SChe-liang Chiou static u32 vendor_dev_id; 11690899cc0SChe-liang Chiou 11790899cc0SChe-liang Chiou /* TPM access wrappers to support tracing */ 11890899cc0SChe-liang Chiou static u8 tpm_read_byte(const u8 *ptr) 11990899cc0SChe-liang Chiou { 12090899cc0SChe-liang Chiou u8 ret = readb(ptr); 12190899cc0SChe-liang Chiou debug(PREFIX "Read reg 0x%4.4x returns 0x%2.2x\n", 12290899cc0SChe-liang Chiou (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, ret); 12390899cc0SChe-liang Chiou return ret; 12490899cc0SChe-liang Chiou } 12590899cc0SChe-liang Chiou 12690899cc0SChe-liang Chiou static u32 tpm_read_word(const u32 *ptr) 12790899cc0SChe-liang Chiou { 12890899cc0SChe-liang Chiou u32 ret = readl(ptr); 12990899cc0SChe-liang Chiou debug(PREFIX "Read reg 0x%4.4x returns 0x%8.8x\n", 13090899cc0SChe-liang Chiou (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, ret); 13190899cc0SChe-liang Chiou return ret; 13290899cc0SChe-liang Chiou } 13390899cc0SChe-liang Chiou 13490899cc0SChe-liang Chiou static void tpm_write_byte(u8 value, u8 *ptr) 13590899cc0SChe-liang Chiou { 13690899cc0SChe-liang Chiou debug(PREFIX "Write reg 0x%4.4x with 0x%2.2x\n", 13790899cc0SChe-liang Chiou (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, value); 13890899cc0SChe-liang Chiou writeb(value, ptr); 13990899cc0SChe-liang Chiou } 14090899cc0SChe-liang Chiou 14190899cc0SChe-liang Chiou static void tpm_write_word(u32 value, u32 *ptr) 14290899cc0SChe-liang Chiou { 14390899cc0SChe-liang Chiou debug(PREFIX "Write reg 0x%4.4x with 0x%8.8x\n", 14490899cc0SChe-liang Chiou (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, value); 14590899cc0SChe-liang Chiou writel(value, ptr); 14690899cc0SChe-liang Chiou } 14790899cc0SChe-liang Chiou 14890899cc0SChe-liang Chiou /* 14990899cc0SChe-liang Chiou * tis_wait_reg() 15090899cc0SChe-liang Chiou * 15190899cc0SChe-liang Chiou * Wait for at least a second for a register to change its state to match the 15290899cc0SChe-liang Chiou * expected state. Normally the transition happens within microseconds. 15390899cc0SChe-liang Chiou * 15490899cc0SChe-liang Chiou * @reg - pointer to the TPM register 15590899cc0SChe-liang Chiou * @mask - bitmask for the bitfield(s) to watch 15690899cc0SChe-liang Chiou * @expected - value the field(s) are supposed to be set to 15790899cc0SChe-liang Chiou * 15890899cc0SChe-liang Chiou * Returns the register contents in case the expected value was found in the 15990899cc0SChe-liang Chiou * appropriate register bits, or TPM_TIMEOUT_ERR on timeout. 16090899cc0SChe-liang Chiou */ 16190899cc0SChe-liang Chiou static u32 tis_wait_reg(u32 *reg, u8 mask, u8 expected) 16290899cc0SChe-liang Chiou { 16390899cc0SChe-liang Chiou u32 time_us = MAX_DELAY_US; 16490899cc0SChe-liang Chiou 16590899cc0SChe-liang Chiou while (time_us > 0) { 16690899cc0SChe-liang Chiou u32 value = tpm_read_word(reg); 16790899cc0SChe-liang Chiou if ((value & mask) == expected) 16890899cc0SChe-liang Chiou return value; 16990899cc0SChe-liang Chiou udelay(1); /* 1 us */ 17090899cc0SChe-liang Chiou time_us--; 17190899cc0SChe-liang Chiou } 17290899cc0SChe-liang Chiou return TPM_TIMEOUT_ERR; 17390899cc0SChe-liang Chiou } 17490899cc0SChe-liang Chiou 17590899cc0SChe-liang Chiou /* 17690899cc0SChe-liang Chiou * Probe the TPM device and try determining its manufacturer/device name. 17790899cc0SChe-liang Chiou * 17890899cc0SChe-liang Chiou * Returns 0 on success (the device is found or was found during an earlier 17990899cc0SChe-liang Chiou * invocation) or TPM_DRIVER_ERR if the device is not found. 18090899cc0SChe-liang Chiou */ 18190899cc0SChe-liang Chiou int tis_init(void) 18290899cc0SChe-liang Chiou { 18390899cc0SChe-liang Chiou u32 didvid = tpm_read_word(&lpc_tpm_dev[0].did_vid); 18490899cc0SChe-liang Chiou int i; 18590899cc0SChe-liang Chiou const char *device_name = "unknown"; 18690899cc0SChe-liang Chiou const char *vendor_name = device_name; 18790899cc0SChe-liang Chiou u16 vid, did; 18890899cc0SChe-liang Chiou 18990899cc0SChe-liang Chiou if (vendor_dev_id) 19090899cc0SChe-liang Chiou return 0; /* Already probed. */ 19190899cc0SChe-liang Chiou 19290899cc0SChe-liang Chiou if (!didvid || (didvid == 0xffffffff)) { 19390899cc0SChe-liang Chiou printf("%s: No TPM device found\n", __func__); 19490899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 19590899cc0SChe-liang Chiou } 19690899cc0SChe-liang Chiou 19790899cc0SChe-liang Chiou vendor_dev_id = didvid; 19890899cc0SChe-liang Chiou 19990899cc0SChe-liang Chiou vid = didvid & 0xffff; 20090899cc0SChe-liang Chiou did = (didvid >> 16) & 0xffff; 20190899cc0SChe-liang Chiou for (i = 0; i < ARRAY_SIZE(vendor_names); i++) { 20290899cc0SChe-liang Chiou int j = 0; 20390899cc0SChe-liang Chiou u16 known_did; 20490899cc0SChe-liang Chiou 20590899cc0SChe-liang Chiou if (vid == vendor_names[i].vendor_id) 20690899cc0SChe-liang Chiou vendor_name = vendor_names[i].vendor_name; 20790899cc0SChe-liang Chiou 20890899cc0SChe-liang Chiou while ((known_did = vendor_names[i].dev_names[j].dev_id) != 0) { 20990899cc0SChe-liang Chiou if (known_did == did) { 21090899cc0SChe-liang Chiou device_name = 21190899cc0SChe-liang Chiou vendor_names[i].dev_names[j].dev_name; 21290899cc0SChe-liang Chiou break; 21390899cc0SChe-liang Chiou } 21490899cc0SChe-liang Chiou j++; 21590899cc0SChe-liang Chiou } 21690899cc0SChe-liang Chiou break; 21790899cc0SChe-liang Chiou } 21890899cc0SChe-liang Chiou 21990899cc0SChe-liang Chiou printf("Found TPM %s by %s\n", device_name, vendor_name); 22090899cc0SChe-liang Chiou return 0; 22190899cc0SChe-liang Chiou } 22290899cc0SChe-liang Chiou 22390899cc0SChe-liang Chiou /* 22490899cc0SChe-liang Chiou * tis_senddata() 22590899cc0SChe-liang Chiou * 22690899cc0SChe-liang Chiou * send the passed in data to the TPM device. 22790899cc0SChe-liang Chiou * 22890899cc0SChe-liang Chiou * @data - address of the data to send, byte by byte 22990899cc0SChe-liang Chiou * @len - length of the data to send 23090899cc0SChe-liang Chiou * 23190899cc0SChe-liang Chiou * Returns 0 on success, TPM_DRIVER_ERR on error (in case the device does 23290899cc0SChe-liang Chiou * not accept the entire command). 23390899cc0SChe-liang Chiou */ 23490899cc0SChe-liang Chiou static u32 tis_senddata(const u8 * const data, u32 len) 23590899cc0SChe-liang Chiou { 23690899cc0SChe-liang Chiou u32 offset = 0; 23790899cc0SChe-liang Chiou u16 burst = 0; 23890899cc0SChe-liang Chiou u32 max_cycles = 0; 23990899cc0SChe-liang Chiou u8 locality = 0; 24090899cc0SChe-liang Chiou u32 value; 24190899cc0SChe-liang Chiou 24290899cc0SChe-liang Chiou value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status, 24390899cc0SChe-liang Chiou TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY); 24490899cc0SChe-liang Chiou if (value == TPM_TIMEOUT_ERR) { 24590899cc0SChe-liang Chiou printf("%s:%d - failed to get 'command_ready' status\n", 24690899cc0SChe-liang Chiou __FILE__, __LINE__); 24790899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 24890899cc0SChe-liang Chiou } 24990899cc0SChe-liang Chiou burst = burst_count(value); 25090899cc0SChe-liang Chiou 25190899cc0SChe-liang Chiou while (1) { 25290899cc0SChe-liang Chiou unsigned count; 25390899cc0SChe-liang Chiou 25490899cc0SChe-liang Chiou /* Wait till the device is ready to accept more data. */ 25590899cc0SChe-liang Chiou while (!burst) { 25690899cc0SChe-liang Chiou if (max_cycles++ == MAX_DELAY_US) { 25790899cc0SChe-liang Chiou printf("%s:%d failed to feed %d bytes of %d\n", 25890899cc0SChe-liang Chiou __FILE__, __LINE__, len - offset, len); 25990899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 26090899cc0SChe-liang Chiou } 26190899cc0SChe-liang Chiou udelay(1); 26290899cc0SChe-liang Chiou burst = burst_count(tpm_read_word(&lpc_tpm_dev 26390899cc0SChe-liang Chiou [locality].tpm_status)); 26490899cc0SChe-liang Chiou } 26590899cc0SChe-liang Chiou 26690899cc0SChe-liang Chiou max_cycles = 0; 26790899cc0SChe-liang Chiou 26890899cc0SChe-liang Chiou /* 26990899cc0SChe-liang Chiou * Calculate number of bytes the TPM is ready to accept in one 27090899cc0SChe-liang Chiou * shot. 27190899cc0SChe-liang Chiou * 27290899cc0SChe-liang Chiou * We want to send the last byte outside of the loop (hence 27390899cc0SChe-liang Chiou * the -1 below) to make sure that the 'expected' status bit 27490899cc0SChe-liang Chiou * changes to zero exactly after the last byte is fed into the 27590899cc0SChe-liang Chiou * FIFO. 27690899cc0SChe-liang Chiou */ 27790899cc0SChe-liang Chiou count = min(burst, len - offset - 1); 27890899cc0SChe-liang Chiou while (count--) 27990899cc0SChe-liang Chiou tpm_write_byte(data[offset++], 28090899cc0SChe-liang Chiou &lpc_tpm_dev[locality].data); 28190899cc0SChe-liang Chiou 28290899cc0SChe-liang Chiou value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status, 28390899cc0SChe-liang Chiou TIS_STS_VALID, TIS_STS_VALID); 28490899cc0SChe-liang Chiou 28590899cc0SChe-liang Chiou if ((value == TPM_TIMEOUT_ERR) || !(value & TIS_STS_EXPECT)) { 28690899cc0SChe-liang Chiou printf("%s:%d TPM command feed overflow\n", 28790899cc0SChe-liang Chiou __FILE__, __LINE__); 28890899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 28990899cc0SChe-liang Chiou } 29090899cc0SChe-liang Chiou 29190899cc0SChe-liang Chiou burst = burst_count(value); 29290899cc0SChe-liang Chiou if ((offset == (len - 1)) && burst) { 29390899cc0SChe-liang Chiou /* 29490899cc0SChe-liang Chiou * We need to be able to send the last byte to the 29590899cc0SChe-liang Chiou * device, so burst size must be nonzero before we 29690899cc0SChe-liang Chiou * break out. 29790899cc0SChe-liang Chiou */ 29890899cc0SChe-liang Chiou break; 29990899cc0SChe-liang Chiou } 30090899cc0SChe-liang Chiou } 30190899cc0SChe-liang Chiou 30290899cc0SChe-liang Chiou /* Send the last byte. */ 30390899cc0SChe-liang Chiou tpm_write_byte(data[offset++], &lpc_tpm_dev[locality].data); 30490899cc0SChe-liang Chiou /* 30590899cc0SChe-liang Chiou * Verify that TPM does not expect any more data as part of this 30690899cc0SChe-liang Chiou * command. 30790899cc0SChe-liang Chiou */ 30890899cc0SChe-liang Chiou value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status, 30990899cc0SChe-liang Chiou TIS_STS_VALID, TIS_STS_VALID); 31090899cc0SChe-liang Chiou if ((value == TPM_TIMEOUT_ERR) || (value & TIS_STS_EXPECT)) { 31190899cc0SChe-liang Chiou printf("%s:%d unexpected TPM status 0x%x\n", 31290899cc0SChe-liang Chiou __FILE__, __LINE__, value); 31390899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 31490899cc0SChe-liang Chiou } 31590899cc0SChe-liang Chiou 31690899cc0SChe-liang Chiou /* OK, sitting pretty, let's start the command execution. */ 31790899cc0SChe-liang Chiou tpm_write_word(TIS_STS_TPM_GO, &lpc_tpm_dev[locality].tpm_status); 31890899cc0SChe-liang Chiou return 0; 31990899cc0SChe-liang Chiou } 32090899cc0SChe-liang Chiou 32190899cc0SChe-liang Chiou /* 32290899cc0SChe-liang Chiou * tis_readresponse() 32390899cc0SChe-liang Chiou * 32490899cc0SChe-liang Chiou * read the TPM device response after a command was issued. 32590899cc0SChe-liang Chiou * 32690899cc0SChe-liang Chiou * @buffer - address where to read the response, byte by byte. 32790899cc0SChe-liang Chiou * @len - pointer to the size of buffer 32890899cc0SChe-liang Chiou * 32990899cc0SChe-liang Chiou * On success stores the number of received bytes to len and returns 0. On 33090899cc0SChe-liang Chiou * errors (misformatted TPM data or synchronization problems) returns 33190899cc0SChe-liang Chiou * TPM_DRIVER_ERR. 33290899cc0SChe-liang Chiou */ 33390899cc0SChe-liang Chiou static u32 tis_readresponse(u8 *buffer, u32 *len) 33490899cc0SChe-liang Chiou { 33590899cc0SChe-liang Chiou u16 burst; 33690899cc0SChe-liang Chiou u32 value; 33790899cc0SChe-liang Chiou u32 offset = 0; 33890899cc0SChe-liang Chiou u8 locality = 0; 33990899cc0SChe-liang Chiou const u32 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID; 34090899cc0SChe-liang Chiou u32 expected_count = *len; 34190899cc0SChe-liang Chiou int max_cycles = 0; 34290899cc0SChe-liang Chiou 34390899cc0SChe-liang Chiou /* Wait for the TPM to process the command. */ 34490899cc0SChe-liang Chiou value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status, 34590899cc0SChe-liang Chiou has_data, has_data); 34690899cc0SChe-liang Chiou if (value == TPM_TIMEOUT_ERR) { 34790899cc0SChe-liang Chiou printf("%s:%d failed processing command\n", 34890899cc0SChe-liang Chiou __FILE__, __LINE__); 34990899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 35090899cc0SChe-liang Chiou } 35190899cc0SChe-liang Chiou 35290899cc0SChe-liang Chiou do { 35390899cc0SChe-liang Chiou while ((burst = burst_count(value)) == 0) { 35490899cc0SChe-liang Chiou if (max_cycles++ == MAX_DELAY_US) { 35590899cc0SChe-liang Chiou printf("%s:%d TPM stuck on read\n", 35690899cc0SChe-liang Chiou __FILE__, __LINE__); 35790899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 35890899cc0SChe-liang Chiou } 35990899cc0SChe-liang Chiou udelay(1); 36090899cc0SChe-liang Chiou value = tpm_read_word(&lpc_tpm_dev 36190899cc0SChe-liang Chiou [locality].tpm_status); 36290899cc0SChe-liang Chiou } 36390899cc0SChe-liang Chiou 36490899cc0SChe-liang Chiou max_cycles = 0; 36590899cc0SChe-liang Chiou 36690899cc0SChe-liang Chiou while (burst-- && (offset < expected_count)) { 36790899cc0SChe-liang Chiou buffer[offset++] = tpm_read_byte(&lpc_tpm_dev 36890899cc0SChe-liang Chiou [locality].data); 36990899cc0SChe-liang Chiou 37090899cc0SChe-liang Chiou if (offset == 6) { 37190899cc0SChe-liang Chiou /* 37290899cc0SChe-liang Chiou * We got the first six bytes of the reply, 37390899cc0SChe-liang Chiou * let's figure out how many bytes to expect 37490899cc0SChe-liang Chiou * total - it is stored as a 4 byte number in 37590899cc0SChe-liang Chiou * network order, starting with offset 2 into 37690899cc0SChe-liang Chiou * the body of the reply. 37790899cc0SChe-liang Chiou */ 37890899cc0SChe-liang Chiou u32 real_length; 37990899cc0SChe-liang Chiou memcpy(&real_length, 38090899cc0SChe-liang Chiou buffer + 2, 38190899cc0SChe-liang Chiou sizeof(real_length)); 38290899cc0SChe-liang Chiou expected_count = be32_to_cpu(real_length); 38390899cc0SChe-liang Chiou 38490899cc0SChe-liang Chiou if ((expected_count < offset) || 38590899cc0SChe-liang Chiou (expected_count > *len)) { 38690899cc0SChe-liang Chiou printf("%s:%d bad response size %d\n", 38790899cc0SChe-liang Chiou __FILE__, __LINE__, 38890899cc0SChe-liang Chiou expected_count); 38990899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 39090899cc0SChe-liang Chiou } 39190899cc0SChe-liang Chiou } 39290899cc0SChe-liang Chiou } 39390899cc0SChe-liang Chiou 39490899cc0SChe-liang Chiou /* Wait for the next portion. */ 39590899cc0SChe-liang Chiou value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status, 39690899cc0SChe-liang Chiou TIS_STS_VALID, TIS_STS_VALID); 39790899cc0SChe-liang Chiou if (value == TPM_TIMEOUT_ERR) { 39890899cc0SChe-liang Chiou printf("%s:%d failed to read response\n", 39990899cc0SChe-liang Chiou __FILE__, __LINE__); 40090899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 40190899cc0SChe-liang Chiou } 40290899cc0SChe-liang Chiou 40390899cc0SChe-liang Chiou if (offset == expected_count) 40490899cc0SChe-liang Chiou break; /* We got all we needed. */ 40590899cc0SChe-liang Chiou 40690899cc0SChe-liang Chiou } while ((value & has_data) == has_data); 40790899cc0SChe-liang Chiou 40890899cc0SChe-liang Chiou /* 40990899cc0SChe-liang Chiou * Make sure we indeed read all there was. The TIS_STS_VALID bit is 41090899cc0SChe-liang Chiou * known to be set. 41190899cc0SChe-liang Chiou */ 41290899cc0SChe-liang Chiou if (value & TIS_STS_DATA_AVAILABLE) { 41390899cc0SChe-liang Chiou printf("%s:%d wrong receive status %x\n", 41490899cc0SChe-liang Chiou __FILE__, __LINE__, value); 41590899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 41690899cc0SChe-liang Chiou } 41790899cc0SChe-liang Chiou 41890899cc0SChe-liang Chiou /* Tell the TPM that we are done. */ 41990899cc0SChe-liang Chiou tpm_write_word(TIS_STS_COMMAND_READY, &lpc_tpm_dev 42090899cc0SChe-liang Chiou [locality].tpm_status); 42190899cc0SChe-liang Chiou *len = offset; 42290899cc0SChe-liang Chiou return 0; 42390899cc0SChe-liang Chiou } 42490899cc0SChe-liang Chiou 42590899cc0SChe-liang Chiou int tis_open(void) 42690899cc0SChe-liang Chiou { 42790899cc0SChe-liang Chiou u8 locality = 0; /* we use locality zero for everything. */ 42890899cc0SChe-liang Chiou 42990899cc0SChe-liang Chiou if (tis_close()) 43090899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 43190899cc0SChe-liang Chiou 43290899cc0SChe-liang Chiou /* now request access to locality. */ 43390899cc0SChe-liang Chiou tpm_write_word(TIS_ACCESS_REQUEST_USE, &lpc_tpm_dev[locality].access); 43490899cc0SChe-liang Chiou 43590899cc0SChe-liang Chiou /* did we get a lock? */ 43690899cc0SChe-liang Chiou if (tis_wait_reg(&lpc_tpm_dev[locality].access, 43790899cc0SChe-liang Chiou TIS_ACCESS_ACTIVE_LOCALITY, 43890899cc0SChe-liang Chiou TIS_ACCESS_ACTIVE_LOCALITY) == TPM_TIMEOUT_ERR) { 43990899cc0SChe-liang Chiou printf("%s:%d - failed to lock locality %d\n", 44090899cc0SChe-liang Chiou __FILE__, __LINE__, locality); 44190899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 44290899cc0SChe-liang Chiou } 44390899cc0SChe-liang Chiou 44490899cc0SChe-liang Chiou tpm_write_word(TIS_STS_COMMAND_READY, 44590899cc0SChe-liang Chiou &lpc_tpm_dev[locality].tpm_status); 44690899cc0SChe-liang Chiou return 0; 44790899cc0SChe-liang Chiou } 44890899cc0SChe-liang Chiou 44990899cc0SChe-liang Chiou int tis_close(void) 45090899cc0SChe-liang Chiou { 45190899cc0SChe-liang Chiou u8 locality = 0; 45290899cc0SChe-liang Chiou 45390899cc0SChe-liang Chiou if (tpm_read_word(&lpc_tpm_dev[locality].access) & 45490899cc0SChe-liang Chiou TIS_ACCESS_ACTIVE_LOCALITY) { 45590899cc0SChe-liang Chiou tpm_write_word(TIS_ACCESS_ACTIVE_LOCALITY, 45690899cc0SChe-liang Chiou &lpc_tpm_dev[locality].access); 45790899cc0SChe-liang Chiou 45890899cc0SChe-liang Chiou if (tis_wait_reg(&lpc_tpm_dev[locality].access, 45990899cc0SChe-liang Chiou TIS_ACCESS_ACTIVE_LOCALITY, 0) == 46090899cc0SChe-liang Chiou TPM_TIMEOUT_ERR) { 46190899cc0SChe-liang Chiou printf("%s:%d - failed to release locality %d\n", 46290899cc0SChe-liang Chiou __FILE__, __LINE__, locality); 46390899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 46490899cc0SChe-liang Chiou } 46590899cc0SChe-liang Chiou } 46690899cc0SChe-liang Chiou return 0; 46790899cc0SChe-liang Chiou } 46890899cc0SChe-liang Chiou 46990899cc0SChe-liang Chiou int tis_sendrecv(const u8 *sendbuf, size_t send_size, 47090899cc0SChe-liang Chiou u8 *recvbuf, size_t *recv_len) 47190899cc0SChe-liang Chiou { 47290899cc0SChe-liang Chiou if (tis_senddata(sendbuf, send_size)) { 47390899cc0SChe-liang Chiou printf("%s:%d failed sending data to TPM\n", 47490899cc0SChe-liang Chiou __FILE__, __LINE__); 47590899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 47690899cc0SChe-liang Chiou } 47790899cc0SChe-liang Chiou 47890899cc0SChe-liang Chiou return tis_readresponse(recvbuf, (u32 *)recv_len); 47990899cc0SChe-liang Chiou } 480