1*90899cc0SChe-liang Chiou /* 2*90899cc0SChe-liang Chiou * Copyright (c) 2011 The Chromium OS Authors. 3*90899cc0SChe-liang Chiou * 4*90899cc0SChe-liang Chiou * See file CREDITS for list of people who contributed to this 5*90899cc0SChe-liang Chiou * project. 6*90899cc0SChe-liang Chiou * 7*90899cc0SChe-liang Chiou * This program is free software; you can redistribute it and/or 8*90899cc0SChe-liang Chiou * modify it under the terms of the GNU General Public License as 9*90899cc0SChe-liang Chiou * published by the Free Software Foundation; either version 2 of 10*90899cc0SChe-liang Chiou * the License, or (at your option) any later version. 11*90899cc0SChe-liang Chiou * 12*90899cc0SChe-liang Chiou * This program is distributed in the hope that it will be useful, 13*90899cc0SChe-liang Chiou * but WITHOUT ANY WARRANTY; without even the implied warranty of 14*90899cc0SChe-liang Chiou * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*90899cc0SChe-liang Chiou * GNU General Public License for more details. 16*90899cc0SChe-liang Chiou * 17*90899cc0SChe-liang Chiou * You should have received a copy of the GNU General Public License 18*90899cc0SChe-liang Chiou * along with this program; if not, write to the Free Software 19*90899cc0SChe-liang Chiou * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 20*90899cc0SChe-liang Chiou * MA 02111-1307 USA 21*90899cc0SChe-liang Chiou */ 22*90899cc0SChe-liang Chiou 23*90899cc0SChe-liang Chiou /* 24*90899cc0SChe-liang Chiou * The code in this file is based on the article "Writing a TPM Device Driver" 25*90899cc0SChe-liang Chiou * published on http://ptgmedia.pearsoncmg.com. 26*90899cc0SChe-liang Chiou * 27*90899cc0SChe-liang Chiou * One principal difference is that in the simplest config the other than 0 28*90899cc0SChe-liang Chiou * TPM localities do not get mapped by some devices (for instance, by Infineon 29*90899cc0SChe-liang Chiou * slb9635), so this driver provides access to locality 0 only. 30*90899cc0SChe-liang Chiou */ 31*90899cc0SChe-liang Chiou 32*90899cc0SChe-liang Chiou #include <common.h> 33*90899cc0SChe-liang Chiou #include <asm/io.h> 34*90899cc0SChe-liang Chiou #include <tpm.h> 35*90899cc0SChe-liang Chiou 36*90899cc0SChe-liang Chiou #define PREFIX "lpc_tpm: " 37*90899cc0SChe-liang Chiou 38*90899cc0SChe-liang Chiou struct tpm_locality { 39*90899cc0SChe-liang Chiou u32 access; 40*90899cc0SChe-liang Chiou u8 padding0[4]; 41*90899cc0SChe-liang Chiou u32 int_enable; 42*90899cc0SChe-liang Chiou u8 vector; 43*90899cc0SChe-liang Chiou u8 padding1[3]; 44*90899cc0SChe-liang Chiou u32 int_status; 45*90899cc0SChe-liang Chiou u32 int_capability; 46*90899cc0SChe-liang Chiou u32 tpm_status; 47*90899cc0SChe-liang Chiou u8 padding2[8]; 48*90899cc0SChe-liang Chiou u8 data; 49*90899cc0SChe-liang Chiou u8 padding3[3803]; 50*90899cc0SChe-liang Chiou u32 did_vid; 51*90899cc0SChe-liang Chiou u8 rid; 52*90899cc0SChe-liang Chiou u8 padding4[251]; 53*90899cc0SChe-liang Chiou }; 54*90899cc0SChe-liang Chiou 55*90899cc0SChe-liang Chiou /* 56*90899cc0SChe-liang Chiou * This pointer refers to the TPM chip, 5 of its localities are mapped as an 57*90899cc0SChe-liang Chiou * array. 58*90899cc0SChe-liang Chiou */ 59*90899cc0SChe-liang Chiou #define TPM_TOTAL_LOCALITIES 5 60*90899cc0SChe-liang Chiou static struct tpm_locality *lpc_tpm_dev = 61*90899cc0SChe-liang Chiou (struct tpm_locality *)CONFIG_TPM_TIS_BASE_ADDRESS; 62*90899cc0SChe-liang Chiou 63*90899cc0SChe-liang Chiou /* Some registers' bit field definitions */ 64*90899cc0SChe-liang Chiou #define TIS_STS_VALID (1 << 7) /* 0x80 */ 65*90899cc0SChe-liang Chiou #define TIS_STS_COMMAND_READY (1 << 6) /* 0x40 */ 66*90899cc0SChe-liang Chiou #define TIS_STS_TPM_GO (1 << 5) /* 0x20 */ 67*90899cc0SChe-liang Chiou #define TIS_STS_DATA_AVAILABLE (1 << 4) /* 0x10 */ 68*90899cc0SChe-liang Chiou #define TIS_STS_EXPECT (1 << 3) /* 0x08 */ 69*90899cc0SChe-liang Chiou #define TIS_STS_RESPONSE_RETRY (1 << 1) /* 0x02 */ 70*90899cc0SChe-liang Chiou 71*90899cc0SChe-liang Chiou #define TIS_ACCESS_TPM_REG_VALID_STS (1 << 7) /* 0x80 */ 72*90899cc0SChe-liang Chiou #define TIS_ACCESS_ACTIVE_LOCALITY (1 << 5) /* 0x20 */ 73*90899cc0SChe-liang Chiou #define TIS_ACCESS_BEEN_SEIZED (1 << 4) /* 0x10 */ 74*90899cc0SChe-liang Chiou #define TIS_ACCESS_SEIZE (1 << 3) /* 0x08 */ 75*90899cc0SChe-liang Chiou #define TIS_ACCESS_PENDING_REQUEST (1 << 2) /* 0x04 */ 76*90899cc0SChe-liang Chiou #define TIS_ACCESS_REQUEST_USE (1 << 1) /* 0x02 */ 77*90899cc0SChe-liang Chiou #define TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0) /* 0x01 */ 78*90899cc0SChe-liang Chiou 79*90899cc0SChe-liang Chiou #define TIS_STS_BURST_COUNT_MASK (0xffff) 80*90899cc0SChe-liang Chiou #define TIS_STS_BURST_COUNT_SHIFT (8) 81*90899cc0SChe-liang Chiou 82*90899cc0SChe-liang Chiou /* 83*90899cc0SChe-liang Chiou * Error value returned if a tpm register does not enter the expected state 84*90899cc0SChe-liang Chiou * after continuous polling. No actual TPM register reading ever returns -1, 85*90899cc0SChe-liang Chiou * so this value is a safe error indication to be mixed with possible status 86*90899cc0SChe-liang Chiou * register values. 87*90899cc0SChe-liang Chiou */ 88*90899cc0SChe-liang Chiou #define TPM_TIMEOUT_ERR (-1) 89*90899cc0SChe-liang Chiou 90*90899cc0SChe-liang Chiou /* Error value returned on various TPM driver errors. */ 91*90899cc0SChe-liang Chiou #define TPM_DRIVER_ERR (1) 92*90899cc0SChe-liang Chiou 93*90899cc0SChe-liang Chiou /* 1 second is plenty for anything TPM does. */ 94*90899cc0SChe-liang Chiou #define MAX_DELAY_US (1000 * 1000) 95*90899cc0SChe-liang Chiou 96*90899cc0SChe-liang Chiou /* Retrieve burst count value out of the status register contents. */ 97*90899cc0SChe-liang Chiou static u16 burst_count(u32 status) 98*90899cc0SChe-liang Chiou { 99*90899cc0SChe-liang Chiou return (status >> TIS_STS_BURST_COUNT_SHIFT) & TIS_STS_BURST_COUNT_MASK; 100*90899cc0SChe-liang Chiou } 101*90899cc0SChe-liang Chiou 102*90899cc0SChe-liang Chiou /* 103*90899cc0SChe-liang Chiou * Structures defined below allow creating descriptions of TPM vendor/device 104*90899cc0SChe-liang Chiou * ID information for run time discovery. The only device the system knows 105*90899cc0SChe-liang Chiou * about at this time is Infineon slb9635. 106*90899cc0SChe-liang Chiou */ 107*90899cc0SChe-liang Chiou struct device_name { 108*90899cc0SChe-liang Chiou u16 dev_id; 109*90899cc0SChe-liang Chiou const char * const dev_name; 110*90899cc0SChe-liang Chiou }; 111*90899cc0SChe-liang Chiou 112*90899cc0SChe-liang Chiou struct vendor_name { 113*90899cc0SChe-liang Chiou u16 vendor_id; 114*90899cc0SChe-liang Chiou const char *vendor_name; 115*90899cc0SChe-liang Chiou const struct device_name *dev_names; 116*90899cc0SChe-liang Chiou }; 117*90899cc0SChe-liang Chiou 118*90899cc0SChe-liang Chiou static const struct device_name infineon_devices[] = { 119*90899cc0SChe-liang Chiou {0xb, "SLB9635 TT 1.2"}, 120*90899cc0SChe-liang Chiou {0} 121*90899cc0SChe-liang Chiou }; 122*90899cc0SChe-liang Chiou 123*90899cc0SChe-liang Chiou static const struct vendor_name vendor_names[] = { 124*90899cc0SChe-liang Chiou {0x15d1, "Infineon", infineon_devices}, 125*90899cc0SChe-liang Chiou }; 126*90899cc0SChe-liang Chiou 127*90899cc0SChe-liang Chiou /* 128*90899cc0SChe-liang Chiou * Cached vendor/device ID pair to indicate that the device has been already 129*90899cc0SChe-liang Chiou * discovered. 130*90899cc0SChe-liang Chiou */ 131*90899cc0SChe-liang Chiou static u32 vendor_dev_id; 132*90899cc0SChe-liang Chiou 133*90899cc0SChe-liang Chiou /* TPM access wrappers to support tracing */ 134*90899cc0SChe-liang Chiou static u8 tpm_read_byte(const u8 *ptr) 135*90899cc0SChe-liang Chiou { 136*90899cc0SChe-liang Chiou u8 ret = readb(ptr); 137*90899cc0SChe-liang Chiou debug(PREFIX "Read reg 0x%4.4x returns 0x%2.2x\n", 138*90899cc0SChe-liang Chiou (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, ret); 139*90899cc0SChe-liang Chiou return ret; 140*90899cc0SChe-liang Chiou } 141*90899cc0SChe-liang Chiou 142*90899cc0SChe-liang Chiou static u32 tpm_read_word(const u32 *ptr) 143*90899cc0SChe-liang Chiou { 144*90899cc0SChe-liang Chiou u32 ret = readl(ptr); 145*90899cc0SChe-liang Chiou debug(PREFIX "Read reg 0x%4.4x returns 0x%8.8x\n", 146*90899cc0SChe-liang Chiou (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, ret); 147*90899cc0SChe-liang Chiou return ret; 148*90899cc0SChe-liang Chiou } 149*90899cc0SChe-liang Chiou 150*90899cc0SChe-liang Chiou static void tpm_write_byte(u8 value, u8 *ptr) 151*90899cc0SChe-liang Chiou { 152*90899cc0SChe-liang Chiou debug(PREFIX "Write reg 0x%4.4x with 0x%2.2x\n", 153*90899cc0SChe-liang Chiou (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, value); 154*90899cc0SChe-liang Chiou writeb(value, ptr); 155*90899cc0SChe-liang Chiou } 156*90899cc0SChe-liang Chiou 157*90899cc0SChe-liang Chiou static void tpm_write_word(u32 value, u32 *ptr) 158*90899cc0SChe-liang Chiou { 159*90899cc0SChe-liang Chiou debug(PREFIX "Write reg 0x%4.4x with 0x%8.8x\n", 160*90899cc0SChe-liang Chiou (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, value); 161*90899cc0SChe-liang Chiou writel(value, ptr); 162*90899cc0SChe-liang Chiou } 163*90899cc0SChe-liang Chiou 164*90899cc0SChe-liang Chiou /* 165*90899cc0SChe-liang Chiou * tis_wait_reg() 166*90899cc0SChe-liang Chiou * 167*90899cc0SChe-liang Chiou * Wait for at least a second for a register to change its state to match the 168*90899cc0SChe-liang Chiou * expected state. Normally the transition happens within microseconds. 169*90899cc0SChe-liang Chiou * 170*90899cc0SChe-liang Chiou * @reg - pointer to the TPM register 171*90899cc0SChe-liang Chiou * @mask - bitmask for the bitfield(s) to watch 172*90899cc0SChe-liang Chiou * @expected - value the field(s) are supposed to be set to 173*90899cc0SChe-liang Chiou * 174*90899cc0SChe-liang Chiou * Returns the register contents in case the expected value was found in the 175*90899cc0SChe-liang Chiou * appropriate register bits, or TPM_TIMEOUT_ERR on timeout. 176*90899cc0SChe-liang Chiou */ 177*90899cc0SChe-liang Chiou static u32 tis_wait_reg(u32 *reg, u8 mask, u8 expected) 178*90899cc0SChe-liang Chiou { 179*90899cc0SChe-liang Chiou u32 time_us = MAX_DELAY_US; 180*90899cc0SChe-liang Chiou 181*90899cc0SChe-liang Chiou while (time_us > 0) { 182*90899cc0SChe-liang Chiou u32 value = tpm_read_word(reg); 183*90899cc0SChe-liang Chiou if ((value & mask) == expected) 184*90899cc0SChe-liang Chiou return value; 185*90899cc0SChe-liang Chiou udelay(1); /* 1 us */ 186*90899cc0SChe-liang Chiou time_us--; 187*90899cc0SChe-liang Chiou } 188*90899cc0SChe-liang Chiou return TPM_TIMEOUT_ERR; 189*90899cc0SChe-liang Chiou } 190*90899cc0SChe-liang Chiou 191*90899cc0SChe-liang Chiou /* 192*90899cc0SChe-liang Chiou * Probe the TPM device and try determining its manufacturer/device name. 193*90899cc0SChe-liang Chiou * 194*90899cc0SChe-liang Chiou * Returns 0 on success (the device is found or was found during an earlier 195*90899cc0SChe-liang Chiou * invocation) or TPM_DRIVER_ERR if the device is not found. 196*90899cc0SChe-liang Chiou */ 197*90899cc0SChe-liang Chiou int tis_init(void) 198*90899cc0SChe-liang Chiou { 199*90899cc0SChe-liang Chiou u32 didvid = tpm_read_word(&lpc_tpm_dev[0].did_vid); 200*90899cc0SChe-liang Chiou int i; 201*90899cc0SChe-liang Chiou const char *device_name = "unknown"; 202*90899cc0SChe-liang Chiou const char *vendor_name = device_name; 203*90899cc0SChe-liang Chiou u16 vid, did; 204*90899cc0SChe-liang Chiou 205*90899cc0SChe-liang Chiou if (vendor_dev_id) 206*90899cc0SChe-liang Chiou return 0; /* Already probed. */ 207*90899cc0SChe-liang Chiou 208*90899cc0SChe-liang Chiou if (!didvid || (didvid == 0xffffffff)) { 209*90899cc0SChe-liang Chiou printf("%s: No TPM device found\n", __func__); 210*90899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 211*90899cc0SChe-liang Chiou } 212*90899cc0SChe-liang Chiou 213*90899cc0SChe-liang Chiou vendor_dev_id = didvid; 214*90899cc0SChe-liang Chiou 215*90899cc0SChe-liang Chiou vid = didvid & 0xffff; 216*90899cc0SChe-liang Chiou did = (didvid >> 16) & 0xffff; 217*90899cc0SChe-liang Chiou for (i = 0; i < ARRAY_SIZE(vendor_names); i++) { 218*90899cc0SChe-liang Chiou int j = 0; 219*90899cc0SChe-liang Chiou u16 known_did; 220*90899cc0SChe-liang Chiou 221*90899cc0SChe-liang Chiou if (vid == vendor_names[i].vendor_id) 222*90899cc0SChe-liang Chiou vendor_name = vendor_names[i].vendor_name; 223*90899cc0SChe-liang Chiou 224*90899cc0SChe-liang Chiou while ((known_did = vendor_names[i].dev_names[j].dev_id) != 0) { 225*90899cc0SChe-liang Chiou if (known_did == did) { 226*90899cc0SChe-liang Chiou device_name = 227*90899cc0SChe-liang Chiou vendor_names[i].dev_names[j].dev_name; 228*90899cc0SChe-liang Chiou break; 229*90899cc0SChe-liang Chiou } 230*90899cc0SChe-liang Chiou j++; 231*90899cc0SChe-liang Chiou } 232*90899cc0SChe-liang Chiou break; 233*90899cc0SChe-liang Chiou } 234*90899cc0SChe-liang Chiou 235*90899cc0SChe-liang Chiou printf("Found TPM %s by %s\n", device_name, vendor_name); 236*90899cc0SChe-liang Chiou return 0; 237*90899cc0SChe-liang Chiou } 238*90899cc0SChe-liang Chiou 239*90899cc0SChe-liang Chiou /* 240*90899cc0SChe-liang Chiou * tis_senddata() 241*90899cc0SChe-liang Chiou * 242*90899cc0SChe-liang Chiou * send the passed in data to the TPM device. 243*90899cc0SChe-liang Chiou * 244*90899cc0SChe-liang Chiou * @data - address of the data to send, byte by byte 245*90899cc0SChe-liang Chiou * @len - length of the data to send 246*90899cc0SChe-liang Chiou * 247*90899cc0SChe-liang Chiou * Returns 0 on success, TPM_DRIVER_ERR on error (in case the device does 248*90899cc0SChe-liang Chiou * not accept the entire command). 249*90899cc0SChe-liang Chiou */ 250*90899cc0SChe-liang Chiou static u32 tis_senddata(const u8 * const data, u32 len) 251*90899cc0SChe-liang Chiou { 252*90899cc0SChe-liang Chiou u32 offset = 0; 253*90899cc0SChe-liang Chiou u16 burst = 0; 254*90899cc0SChe-liang Chiou u32 max_cycles = 0; 255*90899cc0SChe-liang Chiou u8 locality = 0; 256*90899cc0SChe-liang Chiou u32 value; 257*90899cc0SChe-liang Chiou 258*90899cc0SChe-liang Chiou value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status, 259*90899cc0SChe-liang Chiou TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY); 260*90899cc0SChe-liang Chiou if (value == TPM_TIMEOUT_ERR) { 261*90899cc0SChe-liang Chiou printf("%s:%d - failed to get 'command_ready' status\n", 262*90899cc0SChe-liang Chiou __FILE__, __LINE__); 263*90899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 264*90899cc0SChe-liang Chiou } 265*90899cc0SChe-liang Chiou burst = burst_count(value); 266*90899cc0SChe-liang Chiou 267*90899cc0SChe-liang Chiou while (1) { 268*90899cc0SChe-liang Chiou unsigned count; 269*90899cc0SChe-liang Chiou 270*90899cc0SChe-liang Chiou /* Wait till the device is ready to accept more data. */ 271*90899cc0SChe-liang Chiou while (!burst) { 272*90899cc0SChe-liang Chiou if (max_cycles++ == MAX_DELAY_US) { 273*90899cc0SChe-liang Chiou printf("%s:%d failed to feed %d bytes of %d\n", 274*90899cc0SChe-liang Chiou __FILE__, __LINE__, len - offset, len); 275*90899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 276*90899cc0SChe-liang Chiou } 277*90899cc0SChe-liang Chiou udelay(1); 278*90899cc0SChe-liang Chiou burst = burst_count(tpm_read_word(&lpc_tpm_dev 279*90899cc0SChe-liang Chiou [locality].tpm_status)); 280*90899cc0SChe-liang Chiou } 281*90899cc0SChe-liang Chiou 282*90899cc0SChe-liang Chiou max_cycles = 0; 283*90899cc0SChe-liang Chiou 284*90899cc0SChe-liang Chiou /* 285*90899cc0SChe-liang Chiou * Calculate number of bytes the TPM is ready to accept in one 286*90899cc0SChe-liang Chiou * shot. 287*90899cc0SChe-liang Chiou * 288*90899cc0SChe-liang Chiou * We want to send the last byte outside of the loop (hence 289*90899cc0SChe-liang Chiou * the -1 below) to make sure that the 'expected' status bit 290*90899cc0SChe-liang Chiou * changes to zero exactly after the last byte is fed into the 291*90899cc0SChe-liang Chiou * FIFO. 292*90899cc0SChe-liang Chiou */ 293*90899cc0SChe-liang Chiou count = min(burst, len - offset - 1); 294*90899cc0SChe-liang Chiou while (count--) 295*90899cc0SChe-liang Chiou tpm_write_byte(data[offset++], 296*90899cc0SChe-liang Chiou &lpc_tpm_dev[locality].data); 297*90899cc0SChe-liang Chiou 298*90899cc0SChe-liang Chiou value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status, 299*90899cc0SChe-liang Chiou TIS_STS_VALID, TIS_STS_VALID); 300*90899cc0SChe-liang Chiou 301*90899cc0SChe-liang Chiou if ((value == TPM_TIMEOUT_ERR) || !(value & TIS_STS_EXPECT)) { 302*90899cc0SChe-liang Chiou printf("%s:%d TPM command feed overflow\n", 303*90899cc0SChe-liang Chiou __FILE__, __LINE__); 304*90899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 305*90899cc0SChe-liang Chiou } 306*90899cc0SChe-liang Chiou 307*90899cc0SChe-liang Chiou burst = burst_count(value); 308*90899cc0SChe-liang Chiou if ((offset == (len - 1)) && burst) { 309*90899cc0SChe-liang Chiou /* 310*90899cc0SChe-liang Chiou * We need to be able to send the last byte to the 311*90899cc0SChe-liang Chiou * device, so burst size must be nonzero before we 312*90899cc0SChe-liang Chiou * break out. 313*90899cc0SChe-liang Chiou */ 314*90899cc0SChe-liang Chiou break; 315*90899cc0SChe-liang Chiou } 316*90899cc0SChe-liang Chiou } 317*90899cc0SChe-liang Chiou 318*90899cc0SChe-liang Chiou /* Send the last byte. */ 319*90899cc0SChe-liang Chiou tpm_write_byte(data[offset++], &lpc_tpm_dev[locality].data); 320*90899cc0SChe-liang Chiou /* 321*90899cc0SChe-liang Chiou * Verify that TPM does not expect any more data as part of this 322*90899cc0SChe-liang Chiou * command. 323*90899cc0SChe-liang Chiou */ 324*90899cc0SChe-liang Chiou value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status, 325*90899cc0SChe-liang Chiou TIS_STS_VALID, TIS_STS_VALID); 326*90899cc0SChe-liang Chiou if ((value == TPM_TIMEOUT_ERR) || (value & TIS_STS_EXPECT)) { 327*90899cc0SChe-liang Chiou printf("%s:%d unexpected TPM status 0x%x\n", 328*90899cc0SChe-liang Chiou __FILE__, __LINE__, value); 329*90899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 330*90899cc0SChe-liang Chiou } 331*90899cc0SChe-liang Chiou 332*90899cc0SChe-liang Chiou /* OK, sitting pretty, let's start the command execution. */ 333*90899cc0SChe-liang Chiou tpm_write_word(TIS_STS_TPM_GO, &lpc_tpm_dev[locality].tpm_status); 334*90899cc0SChe-liang Chiou return 0; 335*90899cc0SChe-liang Chiou } 336*90899cc0SChe-liang Chiou 337*90899cc0SChe-liang Chiou /* 338*90899cc0SChe-liang Chiou * tis_readresponse() 339*90899cc0SChe-liang Chiou * 340*90899cc0SChe-liang Chiou * read the TPM device response after a command was issued. 341*90899cc0SChe-liang Chiou * 342*90899cc0SChe-liang Chiou * @buffer - address where to read the response, byte by byte. 343*90899cc0SChe-liang Chiou * @len - pointer to the size of buffer 344*90899cc0SChe-liang Chiou * 345*90899cc0SChe-liang Chiou * On success stores the number of received bytes to len and returns 0. On 346*90899cc0SChe-liang Chiou * errors (misformatted TPM data or synchronization problems) returns 347*90899cc0SChe-liang Chiou * TPM_DRIVER_ERR. 348*90899cc0SChe-liang Chiou */ 349*90899cc0SChe-liang Chiou static u32 tis_readresponse(u8 *buffer, u32 *len) 350*90899cc0SChe-liang Chiou { 351*90899cc0SChe-liang Chiou u16 burst; 352*90899cc0SChe-liang Chiou u32 value; 353*90899cc0SChe-liang Chiou u32 offset = 0; 354*90899cc0SChe-liang Chiou u8 locality = 0; 355*90899cc0SChe-liang Chiou const u32 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID; 356*90899cc0SChe-liang Chiou u32 expected_count = *len; 357*90899cc0SChe-liang Chiou int max_cycles = 0; 358*90899cc0SChe-liang Chiou 359*90899cc0SChe-liang Chiou /* Wait for the TPM to process the command. */ 360*90899cc0SChe-liang Chiou value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status, 361*90899cc0SChe-liang Chiou has_data, has_data); 362*90899cc0SChe-liang Chiou if (value == TPM_TIMEOUT_ERR) { 363*90899cc0SChe-liang Chiou printf("%s:%d failed processing command\n", 364*90899cc0SChe-liang Chiou __FILE__, __LINE__); 365*90899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 366*90899cc0SChe-liang Chiou } 367*90899cc0SChe-liang Chiou 368*90899cc0SChe-liang Chiou do { 369*90899cc0SChe-liang Chiou while ((burst = burst_count(value)) == 0) { 370*90899cc0SChe-liang Chiou if (max_cycles++ == MAX_DELAY_US) { 371*90899cc0SChe-liang Chiou printf("%s:%d TPM stuck on read\n", 372*90899cc0SChe-liang Chiou __FILE__, __LINE__); 373*90899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 374*90899cc0SChe-liang Chiou } 375*90899cc0SChe-liang Chiou udelay(1); 376*90899cc0SChe-liang Chiou value = tpm_read_word(&lpc_tpm_dev 377*90899cc0SChe-liang Chiou [locality].tpm_status); 378*90899cc0SChe-liang Chiou } 379*90899cc0SChe-liang Chiou 380*90899cc0SChe-liang Chiou max_cycles = 0; 381*90899cc0SChe-liang Chiou 382*90899cc0SChe-liang Chiou while (burst-- && (offset < expected_count)) { 383*90899cc0SChe-liang Chiou buffer[offset++] = tpm_read_byte(&lpc_tpm_dev 384*90899cc0SChe-liang Chiou [locality].data); 385*90899cc0SChe-liang Chiou 386*90899cc0SChe-liang Chiou if (offset == 6) { 387*90899cc0SChe-liang Chiou /* 388*90899cc0SChe-liang Chiou * We got the first six bytes of the reply, 389*90899cc0SChe-liang Chiou * let's figure out how many bytes to expect 390*90899cc0SChe-liang Chiou * total - it is stored as a 4 byte number in 391*90899cc0SChe-liang Chiou * network order, starting with offset 2 into 392*90899cc0SChe-liang Chiou * the body of the reply. 393*90899cc0SChe-liang Chiou */ 394*90899cc0SChe-liang Chiou u32 real_length; 395*90899cc0SChe-liang Chiou memcpy(&real_length, 396*90899cc0SChe-liang Chiou buffer + 2, 397*90899cc0SChe-liang Chiou sizeof(real_length)); 398*90899cc0SChe-liang Chiou expected_count = be32_to_cpu(real_length); 399*90899cc0SChe-liang Chiou 400*90899cc0SChe-liang Chiou if ((expected_count < offset) || 401*90899cc0SChe-liang Chiou (expected_count > *len)) { 402*90899cc0SChe-liang Chiou printf("%s:%d bad response size %d\n", 403*90899cc0SChe-liang Chiou __FILE__, __LINE__, 404*90899cc0SChe-liang Chiou expected_count); 405*90899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 406*90899cc0SChe-liang Chiou } 407*90899cc0SChe-liang Chiou } 408*90899cc0SChe-liang Chiou } 409*90899cc0SChe-liang Chiou 410*90899cc0SChe-liang Chiou /* Wait for the next portion. */ 411*90899cc0SChe-liang Chiou value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status, 412*90899cc0SChe-liang Chiou TIS_STS_VALID, TIS_STS_VALID); 413*90899cc0SChe-liang Chiou if (value == TPM_TIMEOUT_ERR) { 414*90899cc0SChe-liang Chiou printf("%s:%d failed to read response\n", 415*90899cc0SChe-liang Chiou __FILE__, __LINE__); 416*90899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 417*90899cc0SChe-liang Chiou } 418*90899cc0SChe-liang Chiou 419*90899cc0SChe-liang Chiou if (offset == expected_count) 420*90899cc0SChe-liang Chiou break; /* We got all we needed. */ 421*90899cc0SChe-liang Chiou 422*90899cc0SChe-liang Chiou } while ((value & has_data) == has_data); 423*90899cc0SChe-liang Chiou 424*90899cc0SChe-liang Chiou /* 425*90899cc0SChe-liang Chiou * Make sure we indeed read all there was. The TIS_STS_VALID bit is 426*90899cc0SChe-liang Chiou * known to be set. 427*90899cc0SChe-liang Chiou */ 428*90899cc0SChe-liang Chiou if (value & TIS_STS_DATA_AVAILABLE) { 429*90899cc0SChe-liang Chiou printf("%s:%d wrong receive status %x\n", 430*90899cc0SChe-liang Chiou __FILE__, __LINE__, value); 431*90899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 432*90899cc0SChe-liang Chiou } 433*90899cc0SChe-liang Chiou 434*90899cc0SChe-liang Chiou /* Tell the TPM that we are done. */ 435*90899cc0SChe-liang Chiou tpm_write_word(TIS_STS_COMMAND_READY, &lpc_tpm_dev 436*90899cc0SChe-liang Chiou [locality].tpm_status); 437*90899cc0SChe-liang Chiou *len = offset; 438*90899cc0SChe-liang Chiou return 0; 439*90899cc0SChe-liang Chiou } 440*90899cc0SChe-liang Chiou 441*90899cc0SChe-liang Chiou int tis_open(void) 442*90899cc0SChe-liang Chiou { 443*90899cc0SChe-liang Chiou u8 locality = 0; /* we use locality zero for everything. */ 444*90899cc0SChe-liang Chiou 445*90899cc0SChe-liang Chiou if (tis_close()) 446*90899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 447*90899cc0SChe-liang Chiou 448*90899cc0SChe-liang Chiou /* now request access to locality. */ 449*90899cc0SChe-liang Chiou tpm_write_word(TIS_ACCESS_REQUEST_USE, &lpc_tpm_dev[locality].access); 450*90899cc0SChe-liang Chiou 451*90899cc0SChe-liang Chiou /* did we get a lock? */ 452*90899cc0SChe-liang Chiou if (tis_wait_reg(&lpc_tpm_dev[locality].access, 453*90899cc0SChe-liang Chiou TIS_ACCESS_ACTIVE_LOCALITY, 454*90899cc0SChe-liang Chiou TIS_ACCESS_ACTIVE_LOCALITY) == TPM_TIMEOUT_ERR) { 455*90899cc0SChe-liang Chiou printf("%s:%d - failed to lock locality %d\n", 456*90899cc0SChe-liang Chiou __FILE__, __LINE__, locality); 457*90899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 458*90899cc0SChe-liang Chiou } 459*90899cc0SChe-liang Chiou 460*90899cc0SChe-liang Chiou tpm_write_word(TIS_STS_COMMAND_READY, 461*90899cc0SChe-liang Chiou &lpc_tpm_dev[locality].tpm_status); 462*90899cc0SChe-liang Chiou return 0; 463*90899cc0SChe-liang Chiou } 464*90899cc0SChe-liang Chiou 465*90899cc0SChe-liang Chiou int tis_close(void) 466*90899cc0SChe-liang Chiou { 467*90899cc0SChe-liang Chiou u8 locality = 0; 468*90899cc0SChe-liang Chiou 469*90899cc0SChe-liang Chiou if (tpm_read_word(&lpc_tpm_dev[locality].access) & 470*90899cc0SChe-liang Chiou TIS_ACCESS_ACTIVE_LOCALITY) { 471*90899cc0SChe-liang Chiou tpm_write_word(TIS_ACCESS_ACTIVE_LOCALITY, 472*90899cc0SChe-liang Chiou &lpc_tpm_dev[locality].access); 473*90899cc0SChe-liang Chiou 474*90899cc0SChe-liang Chiou if (tis_wait_reg(&lpc_tpm_dev[locality].access, 475*90899cc0SChe-liang Chiou TIS_ACCESS_ACTIVE_LOCALITY, 0) == 476*90899cc0SChe-liang Chiou TPM_TIMEOUT_ERR) { 477*90899cc0SChe-liang Chiou printf("%s:%d - failed to release locality %d\n", 478*90899cc0SChe-liang Chiou __FILE__, __LINE__, locality); 479*90899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 480*90899cc0SChe-liang Chiou } 481*90899cc0SChe-liang Chiou } 482*90899cc0SChe-liang Chiou return 0; 483*90899cc0SChe-liang Chiou } 484*90899cc0SChe-liang Chiou 485*90899cc0SChe-liang Chiou int tis_sendrecv(const u8 *sendbuf, size_t send_size, 486*90899cc0SChe-liang Chiou u8 *recvbuf, size_t *recv_len) 487*90899cc0SChe-liang Chiou { 488*90899cc0SChe-liang Chiou if (tis_senddata(sendbuf, send_size)) { 489*90899cc0SChe-liang Chiou printf("%s:%d failed sending data to TPM\n", 490*90899cc0SChe-liang Chiou __FILE__, __LINE__); 491*90899cc0SChe-liang Chiou return TPM_DRIVER_ERR; 492*90899cc0SChe-liang Chiou } 493*90899cc0SChe-liang Chiou 494*90899cc0SChe-liang Chiou return tis_readresponse(recvbuf, (u32 *)recv_len); 495*90899cc0SChe-liang Chiou } 496