@ -38,34 +38,66 @@
# include <common.h>
# include <fdtdec.h>
# include <compiler.h>
# include <i2c.h>
# include <tpm.h>
# include <asm-generic/errno.h>
# include <linux/types.h>
# include <linux/unaligned/be_byteshift.h>
# include "compatibility.h"
# include "tpm.h"
# include "tpm_private.h"
DECLARE_GLOBAL_DATA_PTR ;
/* max. buffer size supported by our tpm */
# ifdef TPM_BUFSIZE
# undef TPM_BUFSIZE
# endif
# define TPM_BUFSIZE 1260
/* Address of the TPM on the I2C bus */
# define TPM_I2C_ADDR 0x20
/* max. number of iterations after i2c NAK */
# define MAX_COUNT 3
# define TPM_I2C_ADDR 0x20
/* Max buffer size supported by our tpm */
# define TPM_DEV_BUFSIZE 1260
# define SLEEP_DURATION 60 /*in usec*/
/* Max number of iterations after i2c NAK */
# define MAX_COUNT 3
/* max. number of iterations after i2c NAK for 'long' commands
* we need this especially for sending TPM_READY , since the cleanup after the
/*
* Max number of iterations after i2c NAK for ' long ' commands
*
* We need this especially for sending TPM_READY , since the cleanup after the
* transtion to the ready state may take some time , but it is unpredictable
* how long it will take .
*/
# define MAX_COUNT_LONG 50
# define MAX_COUNT_LONG 50
# define SLEEP_DURATION 60 /* in usec */
# define SLEEP_DURATION_LONG 210 /* in usec */
# define TPM_HEADER_SIZE 10
/*
* Expected value for DIDVID register
*
* The only device the system knows about at this moment is Infineon slb9635 .
*/
# define TPM_TIS_I2C_DID_VID 0x000b15d1L
enum tis_access {
TPM_ACCESS_VALID = 0x80 ,
TPM_ACCESS_ACTIVE_LOCALITY = 0x20 ,
TPM_ACCESS_REQUEST_PENDING = 0x04 ,
TPM_ACCESS_REQUEST_USE = 0x02 ,
} ;
enum tis_status {
TPM_STS_VALID = 0x80 ,
TPM_STS_COMMAND_READY = 0x40 ,
TPM_STS_GO = 0x20 ,
TPM_STS_DATA_AVAIL = 0x10 ,
TPM_STS_DATA_EXPECT = 0x08 ,
} ;
# define SLEEP_DURATION_LONG 210 /* in usec */
enum tis_defaults {
TIS_SHORT_TIMEOUT = 750 , /* ms */
TIS_LONG_TIMEOUT = 2000 , /* ms */
} ;
/* expected value for DIDVID register */
# define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L
@ -83,17 +115,24 @@ static const char * const chip_name[] = {
[ UNKNOWN ] = " unknown/fallback to slb9635 " ,
} ;
# define TPM_ACCESS(l) (0x0000 | ((l) << 4))
# define TPM_STS(l) (0x0001 | ((l) << 4))
# define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4))
# define TPM_DID_VID(l) (0x0006 | ((l) << 4))
/* Structure to store I2C TPM specific stuff */
struct tpm_inf_dev {
struct tpm_dev {
uint addr ;
u8 buf [ TPM_BUFSIZE + sizeof ( u8 ) ] ; /* max. buffer size + addr */
u8 buf [ TPM_DEV_ BUFSIZE + sizeof ( u8 ) ] ; /* Max buffer size + addr */
enum i2c_chip_type chip_type ;
} ;
static struct tpm_inf_ dev tpm_dev = {
static struct tpm_dev tpm_dev = {
. addr = TPM_I2C_ADDR
} ;
static struct tpm_dev tpm_dev ;
/*
* iic_tpm_read ( ) - read from TPM register
* @ addr : register address to read from
@ -108,24 +147,21 @@ static struct tpm_inf_dev tpm_dev = {
*
* Return - EIO on error , 0 on success .
*/
int iic_tpm_read ( u8 addr , u8 * buffer , size_t len )
static int iic_tpm_read ( u8 addr , u8 * buffer , size_t len )
{
int rc ;
int count ;
uint myaddr = addr ;
/* we have to use uint here, uchar hangs the board */
uint32_t addrbuf = addr ;
if ( ( tpm_dev . chip_type = = SLB9635 ) | | ( tpm_dev . chip_type = = UNKNOWN ) ) {
/* slb9635 protocol should work in both cases */
for ( count = 0 ; count < MAX_COUNT ; count + + ) {
rc = i2c_write ( tpm_dev . addr , 0 , 0 ,
( uchar * ) & my addr, 1 ) ;
( uchar * ) & addrbuf , 1 ) ;
if ( rc = = 0 )
break ; /* success, break to skip sleep */
break ; /* Success, break to skip sleep */
udelay ( SLEEP_DURATION ) ;
}
if ( rc )
return - rc ;
@ -140,10 +176,11 @@ int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
break ; /* success, break to skip sleep */
}
} else {
/* use a combined read for newer chips
* unfortunately the smbus functions are not suitable due to
/*
* Use a combined read for newer chips .
* Unfortunately the smbus functions are not suitable due to
* the 32 byte limit of the smbus .
* r etries should usually not be needed , but are kept just to
* R etries should usually not be needed , but are kept just to
* be safe on the safe side .
*/
for ( count = 0 ; count < MAX_COUNT ; count + + ) {
@ -154,7 +191,7 @@ int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
}
}
/* t ake care of 'guard time' */
/* T ake care of 'guard time' */
udelay ( SLEEP_DURATION ) ;
if ( rc )
return - rc ;
@ -163,21 +200,19 @@ int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
}
static int iic_tpm_write_generic ( u8 addr , u8 * buffer , size_t len ,
unsigned int sleep_time ,
u8 max_count )
unsigned int sleep_time , u8 max_count )
{
int rc = 0 ;
int count ;
/* p repare send buffer */
/* P repare send buffer */
tpm_dev . buf [ 0 ] = addr ;
memcpy ( & ( tpm_dev . buf [ 1 ] ) , buffer , len ) ;
for ( count = 0 ; count < max_count ; count + + ) {
rc = i2c_write ( tpm_dev . addr , 0 , 0 , tpm_dev . buf , len + 1 ) ;
if ( rc = = 0 )
break ; /* success, break to skip sleep */
break ; /* Success, break to skip sleep */
udelay ( sleep_time ) ;
}
@ -214,42 +249,16 @@ static int iic_tpm_write(u8 addr, u8 *buffer, size_t len)
/*
* This function is needed especially for the cleanup situation after
* sending TPM_READY
* */
*/
static int iic_tpm_write_long ( u8 addr , u8 * buffer , size_t len )
{
return iic_tpm_write_generic ( addr , buffer , len , SLEEP_DURATION_LONG ,
MAX_COUNT_LONG ) ;
}
# define TPM_HEADER_SIZE 10
enum tis_access {
TPM_ACCESS_VALID = 0x80 ,
TPM_ACCESS_ACTIVE_LOCALITY = 0x20 ,
TPM_ACCESS_REQUEST_PENDING = 0x04 ,
TPM_ACCESS_REQUEST_USE = 0x02 ,
} ;
enum tis_status {
TPM_STS_VALID = 0x80 ,
TPM_STS_COMMAND_READY = 0x40 ,
TPM_STS_GO = 0x20 ,
TPM_STS_DATA_AVAIL = 0x10 ,
TPM_STS_DATA_EXPECT = 0x08 ,
} ;
enum tis_defaults {
TIS_SHORT_TIMEOUT = 750 , /* ms */
TIS_LONG_TIMEOUT = 2000 , /* 2 sec */
} ;
# define TPM_ACCESS(l) (0x0000 | ((l) << 4))
# define TPM_STS(l) (0x0001 | ((l) << 4))
# define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4))
# define TPM_DID_VID(l) (0x0006 | ((l) << 4))
static int check_locality ( struct tpm_chip * chip , int loc )
{
const u8 mask = TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID ;
u8 buf ;
int rc ;
@ -257,8 +266,7 @@ static int check_locality(struct tpm_chip *chip, int loc)
if ( rc < 0 )
return rc ;
if ( ( buf & ( TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID ) ) = =
( TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID ) ) {
if ( ( buf & mask ) = = mask ) {
chip - > vendor . locality = loc ;
return loc ;
}
@ -268,12 +276,13 @@ static int check_locality(struct tpm_chip *chip, int loc)
static void release_locality ( struct tpm_chip * chip , int loc , int force )
{
const u8 mask = TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID ;
u8 buf ;
if ( iic_tpm_read ( TPM_ACCESS ( loc ) , & buf , 1 ) < 0 )
return ;
if ( force | | ( buf & ( TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID ) ) = =
( TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID ) ) {
if ( force | | ( buf & mask ) = = mask ) {
buf = TPM_ACCESS_ACTIVE_LOCALITY ;
iic_tpm_write ( TPM_ACCESS ( loc ) , & buf , 1 ) ;
}
@ -285,17 +294,17 @@ static int request_locality(struct tpm_chip *chip, int loc)
u8 buf = TPM_ACCESS_REQUEST_USE ;
if ( check_locality ( chip , loc ) > = 0 )
return loc ; /* w e already have the locality */
return loc ; /* W e already have the locality */
iic_tpm_write ( TPM_ACCESS ( loc ) , & buf , 1 ) ;
/* w ait for burstcount */
/* W ait for burstcount */
start = get_timer ( 0 ) ;
stop = chip - > vendor . timeout_a ;
do {
if ( check_locality ( chip , loc ) > = 0 )
return loc ;
msleep ( TPM_TIMEOUT ) ;
udelay ( TPM_TIMEOUT * 1000 ) ;
} while ( get_timer ( start ) < stop ) ;
return - 1 ;
@ -303,8 +312,9 @@ static int request_locality(struct tpm_chip *chip, int loc)
static u8 tpm_tis_i2c_status ( struct tpm_chip * chip )
{
/* NOTE: s ince i2c read may fail, return 0 in this case --> time-out */
/* NOTE: S ince i2c read may fail, return 0 in this case --> time-out */
u8 buf ;
if ( iic_tpm_read ( TPM_STS ( chip - > vendor . locality ) , & buf , 1 ) < 0 )
return 0 ;
else
@ -313,8 +323,9 @@ static u8 tpm_tis_i2c_status(struct tpm_chip *chip)
static void tpm_tis_i2c_ready ( struct tpm_chip * chip )
{
/* t his causes the current command to be aborted */
/* T his causes the current command to be aborted */
u8 buf = TPM_STS_COMMAND_READY ;
iic_tpm_write_long ( TPM_STS ( chip - > vendor . locality ) , & buf , 1 ) ;
}
@ -322,34 +333,34 @@ static ssize_t get_burstcount(struct tpm_chip *chip)
{
unsigned long start , stop ;
ssize_t burstcnt ;
u8 buf [ 3 ] ;
u8 addr , buf [ 3 ] ;
/* w ait for burstcount */
/* which timeout value, s pec has 2 answers (c & d) */
/* W ait for burstcount */
/* XXX: Which timeout value? S pec has 2 answers (c & d) */
start = get_timer ( 0 ) ;
stop = chip - > vendor . timeout_d ;
do {
/* Note: STS is little endian */
if ( iic_tpm_read ( TPM_STS ( chip - > vendor . locality ) + 1 , buf , 3 )
< 0 )
addr = TPM_STS ( chip - > vendor . locality ) + 1 ;
if ( iic_tpm_read ( addr , buf , 3 ) < 0 )
burstcnt = 0 ;
else
burstcnt = ( buf [ 2 ] < < 16 ) + ( buf [ 1 ] < < 8 ) + buf [ 0 ] ;
if ( burstcnt )
return burstcnt ;
msleep ( TPM_TIMEOUT ) ;
udelay ( TPM_TIMEOUT * 1000 ) ;
} while ( get_timer ( start ) < stop ) ;
return - EBUSY ;
}
static int wait_for_stat ( struct tpm_chip * chip , u8 mask , unsigned long timeout ,
int * status )
int * status )
{
unsigned long start , stop ;
/* c heck current status */
/* C heck current status */
* status = tpm_tis_i2c_status ( chip ) ;
if ( ( * status & mask ) = = mask )
return 0 ;
@ -357,11 +368,10 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
start = get_timer ( 0 ) ;
stop = timeout ;
do {
msleep ( TPM_TIMEOUT ) ;
udelay ( TPM_TIMEOUT * 1000 ) ;
* status = tpm_tis_i2c_status ( chip ) ;
if ( ( * status & mask ) = = mask )
return 0 ;
} while ( get_timer ( start ) < stop ) ;
return - ETIME ;
@ -376,17 +386,16 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
while ( size < count ) {
burstcnt = get_burstcount ( chip ) ;
/* burstcount < 0 = tpm is busy */
/* burstcount < 0 -> tpm is busy */
if ( burstcnt < 0 )
return burstcnt ;
/* limit received data to max. left */
/* Limit received data to max left */
if ( burstcnt > ( count - size ) )
burstcnt = count - size ;
rc = iic_tpm_read ( TPM_DATA_FIFO ( chip - > vendor . locality ) ,
& ( buf [ size ] ) ,
burstcnt ) ;
& ( buf [ size ] ) , burstcnt ) ;
if ( rc = = 0 )
size + = burstcnt ;
}
@ -404,10 +413,10 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
goto out ;
}
/* r ead first 10 bytes, including tag, paramsize, and result */
/* R ead first 10 bytes, including tag, paramsize, and result */
size = recv_data ( chip , buf , TPM_HEADER_SIZE ) ;
if ( size < TPM_HEADER_SIZE ) {
dev_err ( chip - > dev , " Unable to read header \n " ) ;
error ( " Unable to read header \n " ) ;
goto out ;
}
@ -418,23 +427,24 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
}
size + = recv_data ( chip , & buf [ TPM_HEADER_SIZE ] ,
expected - TPM_HEADER_SIZE ) ;
expected - TPM_HEADER_SIZE ) ;
if ( size < expected ) {
dev_err ( chip - > dev , " Unable to read remainder of result \n " ) ;
error ( " Unable to read remainder of result \n " ) ;
size = - ETIME ;
goto out ;
}
wait_for_stat ( chip , TPM_STS_VALID , chip - > vendor . timeout_c , & status ) ;
if ( status & TPM_STS_DATA_AVAIL ) { /* r etry? */
dev_err ( chip - > dev , " Error left over data \n " ) ;
if ( status & TPM_STS_DATA_AVAIL ) { /* R etry? */
error ( " Error left over data \n " ) ;
size = - EIO ;
goto out ;
}
out :
tpm_tis_i2c_ready ( chip ) ;
/* The TPM needs some time to clean up here,
/*
* The TPM needs some time to clean up here ,
* so we sleep rather than keeping the bus busy
*/
udelay ( 2000 ) ;
@ -448,10 +458,11 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
int rc , status ;
ssize_t burstcnt ;
size_t count = 0 ;
int retry = 0 ;
u8 sts = TPM_STS_GO ;
if ( len > TPM_BUFSIZE )
return - E2BIG ; /* c ommand is too long for our tpm, sorry */
if ( len > TPM_DEV_ BUFSIZE )
return - E2BIG ; /* C ommand is too long for our tpm, sorry */
if ( request_locality ( chip , 0 ) < 0 )
return - EBUSY ;
@ -459,44 +470,45 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
status = tpm_tis_i2c_status ( chip ) ;
if ( ( status & TPM_STS_COMMAND_READY ) = = 0 ) {
tpm_tis_i2c_ready ( chip ) ;
if ( wait_for_stat
( chip , TPM_STS_COMMAND_READY ,
chip - > vendor . timeout_b , & status ) < 0 ) {
if ( wait_for_stat ( chip , TPM_STS_COMMAND_READY ,
chip - > vendor . timeout_b , & status ) < 0 ) {
rc = - ETIME ;
goto out_err ;
}
}
while ( count < len - 1 ) {
burstcnt = get_burstcount ( chip ) ;
burstcnt = get_burstcount ( chip ) ;
/* burstcount < 0 = tpm is busy */
if ( burstcnt < 0 )
return burstcnt ;
/* burstcount < 0 -> tpm is busy */
if ( burstcnt < 0 )
return burstcnt ;
if ( burstcnt > ( len - 1 - count ) )
burstcnt = len - 1 - count ;
while ( count < len - 1 ) {
if ( burstcnt > len - 1 - count )
burstcnt = len - 1 - count ;
# ifdef CONFIG_TPM_I2C_BURST_LIMITATION
if ( burstcnt > CONFIG_TPM_I2C_BURST_LIMITATION )
burstcnt = CONFIG_TPM_I2C_BURST_LIMITATION ;
# endif /* CONFIG_TPM_I2C_BURST_LIMITATION */
# ifdef CONFIG_TPM_TIS_ I2C_BURST_LIMITATION
if ( retry & & burstcnt > CONFIG_TPM_TIS _I2C_BURST_LIMITATION )
burstcnt = CONFIG_TPM_TIS_ I2C_BURST_LIMITATION ;
# endif /* CONFIG_TPM_TIS_ I2C_BURST_LIMITATION */
rc = iic_tpm_write ( TPM_DATA_FIFO ( chip - > vendor . locality ) ,
& ( buf [ count ] ) , burstcnt ) ;
& ( buf [ count ] ) , burstcnt ) ;
if ( rc = = 0 )
count + = burstcnt ;
wait_for_stat ( chip , TPM_STS_VALID ,
chip - > vendor . timeout_c , & status ) ;
if ( ( status & TPM_STS_DATA_EXPECT ) = = 0 ) {
rc = - EIO ;
goto out_err ;
else {
retry + + ;
wait_for_stat ( chip , TPM_STS_VALID ,
chip - > vendor . timeout_c , & status ) ;
if ( ( status & TPM_STS_DATA_EXPECT ) = = 0 ) {
rc = - EIO ;
goto out_err ;
}
}
}
/* w rite last byte */
/* W rite last byte */
iic_tpm_write ( TPM_DATA_FIFO ( chip - > vendor . locality ) , & ( buf [ count ] ) , 1 ) ;
wait_for_stat ( chip , TPM_STS_VALID , chip - > vendor . timeout_c , & status ) ;
if ( ( status & TPM_STS_DATA_EXPECT ) ! = 0 ) {
@ -504,13 +516,15 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
goto out_err ;
}
/* g o and do it */
/* G o and do it */
iic_tpm_write ( TPM_STS ( chip - > vendor . locality ) , & sts , 1 ) ;
return len ;
out_err :
tpm_tis_i2c_ready ( chip ) ;
/* The TPM needs some time to clean up here,
/*
* The TPM needs some time to clean up here ,
* so we sleep rather than keeping the bus busy
*/
udelay ( 2000 ) ;
@ -529,6 +543,7 @@ static struct tpm_vendor_specific tpm_tis_i2c = {
. req_canceled = TPM_STS_COMMAND_READY ,
} ;
static enum i2c_chip_type tpm_vendor_chip_type ( void )
{
# ifdef CONFIG_OF_CONTROL
@ -543,9 +558,7 @@ static enum i2c_chip_type tpm_vendor_chip_type(void)
return UNKNOWN ;
}
/* initialisation of i2c tpm */
/* Initialisation of i2c tpm */
int tpm_vendor_init ( uint32_t dev_addr )
{
u32 vendor ;
@ -575,12 +588,12 @@ int tpm_vendor_init(uint32_t dev_addr)
chip - > vendor . timeout_c = TIS_SHORT_TIMEOUT ;
chip - > vendor . timeout_d = TIS_SHORT_TIMEOUT ;
if ( request_locality ( chip , 0 ) ! = 0 ) {
if ( request_locality ( chip , 0 ) < 0 ) {
rc = - ENODEV ;
goto out_err ;
}
/* r ead four bytes from DID_VID register */
/* R ead four bytes from DID_VID register */
if ( iic_tpm_read ( TPM_DID_VID ( 0 ) , ( uchar * ) & vendor , 4 ) < 0 ) {
rc = - EIO ;
goto out_release ;
@ -595,13 +608,13 @@ int tpm_vendor_init(uint32_t dev_addr)
}
if ( tpm_dev . chip_type ! = UNKNOWN & & vendor ! = expected_did_vid ) {
dev_err ( dev , " v endor id did not match! ID was %08x\n " , vendor ) ;
error ( " V endor id did not match! ID was %08x\n " , vendor ) ;
rc = - ENODEV ;
goto out_release ;
}
dev_info ( dev , " 1.2 TPM (chip type %s device-id 0x%X) \n " ,
chip_name [ tpm_dev . chip_type ] , vendor > > 16 ) ;
debug ( " 1.2 TPM (chip type %s device-id 0x%X) \n " ,
chip_name [ tpm_dev . chip_type ] , vendor > > 16 ) ;
/*
* A timeout query to TPM can be placed here .