1139fdb3eSNinad Palsule /* 2139fdb3eSNinad Palsule * tpm_tis_i2c.c - QEMU's TPM TIS I2C Device 3139fdb3eSNinad Palsule * 4139fdb3eSNinad Palsule * Copyright (c) 2023 IBM Corporation 5139fdb3eSNinad Palsule * 6139fdb3eSNinad Palsule * Authors: 7139fdb3eSNinad Palsule * Ninad Palsule <ninad@linux.ibm.com> 8139fdb3eSNinad Palsule * 9139fdb3eSNinad Palsule * This work is licensed under the terms of the GNU GPL, version 2 or later. 10139fdb3eSNinad Palsule * See the COPYING file in the top-level directory. 11139fdb3eSNinad Palsule * 12139fdb3eSNinad Palsule * TPM I2C implementation follows TCG TPM I2c Interface specification, 13139fdb3eSNinad Palsule * Family 2.0, Level 00, Revision 1.00 14139fdb3eSNinad Palsule * 15139fdb3eSNinad Palsule * TPM TIS for TPM 2 implementation following TCG PC Client Platform 16*6eedbb5bSMichael Tokarev * TPM Profile (PTP) Specification, Family 2.0, Revision 00.43 17139fdb3eSNinad Palsule * 18139fdb3eSNinad Palsule */ 19139fdb3eSNinad Palsule 20139fdb3eSNinad Palsule #include "qemu/osdep.h" 21139fdb3eSNinad Palsule #include "hw/i2c/i2c.h" 22139fdb3eSNinad Palsule #include "hw/sysbus.h" 23139fdb3eSNinad Palsule #include "hw/acpi/tpm.h" 24139fdb3eSNinad Palsule #include "migration/vmstate.h" 25139fdb3eSNinad Palsule #include "tpm_prop.h" 26139fdb3eSNinad Palsule #include "qemu/log.h" 27139fdb3eSNinad Palsule #include "trace.h" 28139fdb3eSNinad Palsule #include "tpm_tis.h" 29139fdb3eSNinad Palsule 30139fdb3eSNinad Palsule /* Operations */ 31139fdb3eSNinad Palsule #define OP_SEND 1 32139fdb3eSNinad Palsule #define OP_RECV 2 33139fdb3eSNinad Palsule 34139fdb3eSNinad Palsule /* Is locality valid */ 35139fdb3eSNinad Palsule #define TPM_TIS_I2C_IS_VALID_LOCTY(x) TPM_TIS_IS_VALID_LOCTY(x) 36139fdb3eSNinad Palsule 37139fdb3eSNinad Palsule typedef struct TPMStateI2C { 38139fdb3eSNinad Palsule /*< private >*/ 39139fdb3eSNinad Palsule I2CSlave parent_obj; 40139fdb3eSNinad Palsule 41139fdb3eSNinad Palsule uint8_t offset; /* offset into data[] */ 42139fdb3eSNinad Palsule uint8_t operation; /* OP_SEND & OP_RECV */ 43139fdb3eSNinad Palsule uint8_t data[5]; /* Data */ 44139fdb3eSNinad Palsule 45139fdb3eSNinad Palsule /* i2c registers */ 46139fdb3eSNinad Palsule uint8_t loc_sel; /* Current locality */ 47139fdb3eSNinad Palsule uint8_t csum_enable; /* Is checksum enabled */ 48139fdb3eSNinad Palsule 49139fdb3eSNinad Palsule /* Derived from the above */ 50139fdb3eSNinad Palsule const char *reg_name; /* Register name */ 51139fdb3eSNinad Palsule uint32_t tis_addr; /* Converted tis address including locty */ 52139fdb3eSNinad Palsule 53139fdb3eSNinad Palsule /*< public >*/ 54139fdb3eSNinad Palsule TPMState state; /* not a QOM object */ 55139fdb3eSNinad Palsule 56139fdb3eSNinad Palsule } TPMStateI2C; 57139fdb3eSNinad Palsule 58139fdb3eSNinad Palsule DECLARE_INSTANCE_CHECKER(TPMStateI2C, TPM_TIS_I2C, 59139fdb3eSNinad Palsule TYPE_TPM_TIS_I2C) 60139fdb3eSNinad Palsule 61139fdb3eSNinad Palsule /* Prototype */ 62139fdb3eSNinad Palsule static inline void tpm_tis_i2c_to_tis_reg(TPMStateI2C *i2cst, uint8_t i2c_reg); 63139fdb3eSNinad Palsule 64139fdb3eSNinad Palsule /* Register map */ 65139fdb3eSNinad Palsule typedef struct regMap { 66139fdb3eSNinad Palsule uint8_t i2c_reg; /* I2C register */ 67139fdb3eSNinad Palsule uint16_t tis_reg; /* TIS register */ 68139fdb3eSNinad Palsule const char *reg_name; /* Register name */ 69139fdb3eSNinad Palsule } I2CRegMap; 70139fdb3eSNinad Palsule 71139fdb3eSNinad Palsule /* 72139fdb3eSNinad Palsule * The register values in the common code is different than the latest 73139fdb3eSNinad Palsule * register numbers as per the spec hence add the conversion map 74139fdb3eSNinad Palsule */ 75139fdb3eSNinad Palsule static const I2CRegMap tpm_tis_reg_map[] = { 76139fdb3eSNinad Palsule /* 77139fdb3eSNinad Palsule * These registers are sent to TIS layer. The register with UNKNOWN 78139fdb3eSNinad Palsule * mapping are not sent to TIS layer and handled in I2c layer. 79139fdb3eSNinad Palsule * NOTE: Adding frequently used registers at the start 80139fdb3eSNinad Palsule */ 81139fdb3eSNinad Palsule { TPM_I2C_REG_DATA_FIFO, TPM_TIS_REG_DATA_FIFO, "FIFO", }, 82139fdb3eSNinad Palsule { TPM_I2C_REG_STS, TPM_TIS_REG_STS, "STS", }, 83139fdb3eSNinad Palsule { TPM_I2C_REG_DATA_CSUM_GET, TPM_I2C_REG_UNKNOWN, "CSUM_GET", }, 84139fdb3eSNinad Palsule { TPM_I2C_REG_LOC_SEL, TPM_I2C_REG_UNKNOWN, "LOC_SEL", }, 85139fdb3eSNinad Palsule { TPM_I2C_REG_ACCESS, TPM_TIS_REG_ACCESS, "ACCESS", }, 86139fdb3eSNinad Palsule { TPM_I2C_REG_INT_ENABLE, TPM_TIS_REG_INT_ENABLE, "INTR_ENABLE",}, 87139fdb3eSNinad Palsule { TPM_I2C_REG_INT_CAPABILITY, TPM_I2C_REG_UNKNOWN, "INTR_CAP", }, 88139fdb3eSNinad Palsule { TPM_I2C_REG_INTF_CAPABILITY, TPM_TIS_REG_INTF_CAPABILITY, "INTF_CAP", }, 89139fdb3eSNinad Palsule { TPM_I2C_REG_DID_VID, TPM_TIS_REG_DID_VID, "DID_VID", }, 90139fdb3eSNinad Palsule { TPM_I2C_REG_RID, TPM_TIS_REG_RID, "RID", }, 91139fdb3eSNinad Palsule { TPM_I2C_REG_I2C_DEV_ADDRESS, TPM_I2C_REG_UNKNOWN, "DEV_ADDRESS",}, 92139fdb3eSNinad Palsule { TPM_I2C_REG_DATA_CSUM_ENABLE, TPM_I2C_REG_UNKNOWN, "CSUM_ENABLE",}, 93139fdb3eSNinad Palsule }; 94139fdb3eSNinad Palsule 95139fdb3eSNinad Palsule static int tpm_tis_i2c_pre_save(void *opaque) 96139fdb3eSNinad Palsule { 97139fdb3eSNinad Palsule TPMStateI2C *i2cst = opaque; 98139fdb3eSNinad Palsule 99139fdb3eSNinad Palsule return tpm_tis_pre_save(&i2cst->state); 100139fdb3eSNinad Palsule } 101139fdb3eSNinad Palsule 102139fdb3eSNinad Palsule static int tpm_tis_i2c_post_load(void *opaque, int version_id) 103139fdb3eSNinad Palsule { 104139fdb3eSNinad Palsule TPMStateI2C *i2cst = opaque; 105139fdb3eSNinad Palsule 106139fdb3eSNinad Palsule if (i2cst->offset >= 1) { 107139fdb3eSNinad Palsule tpm_tis_i2c_to_tis_reg(i2cst, i2cst->data[0]); 108139fdb3eSNinad Palsule } 109139fdb3eSNinad Palsule 110139fdb3eSNinad Palsule return 0; 111139fdb3eSNinad Palsule } 112139fdb3eSNinad Palsule 113139fdb3eSNinad Palsule static const VMStateDescription vmstate_tpm_tis_i2c = { 114139fdb3eSNinad Palsule .name = "tpm-tis-i2c", 115139fdb3eSNinad Palsule .version_id = 0, 116139fdb3eSNinad Palsule .pre_save = tpm_tis_i2c_pre_save, 117139fdb3eSNinad Palsule .post_load = tpm_tis_i2c_post_load, 118139fdb3eSNinad Palsule .fields = (VMStateField[]) { 119139fdb3eSNinad Palsule VMSTATE_BUFFER(state.buffer, TPMStateI2C), 120139fdb3eSNinad Palsule VMSTATE_UINT16(state.rw_offset, TPMStateI2C), 121139fdb3eSNinad Palsule VMSTATE_UINT8(state.active_locty, TPMStateI2C), 122139fdb3eSNinad Palsule VMSTATE_UINT8(state.aborting_locty, TPMStateI2C), 123139fdb3eSNinad Palsule VMSTATE_UINT8(state.next_locty, TPMStateI2C), 124139fdb3eSNinad Palsule 125139fdb3eSNinad Palsule VMSTATE_STRUCT_ARRAY(state.loc, TPMStateI2C, TPM_TIS_NUM_LOCALITIES, 0, 126139fdb3eSNinad Palsule vmstate_locty, TPMLocality), 127139fdb3eSNinad Palsule 128139fdb3eSNinad Palsule /* i2c specifics */ 129139fdb3eSNinad Palsule VMSTATE_UINT8(offset, TPMStateI2C), 130139fdb3eSNinad Palsule VMSTATE_UINT8(operation, TPMStateI2C), 131139fdb3eSNinad Palsule VMSTATE_BUFFER(data, TPMStateI2C), 132139fdb3eSNinad Palsule VMSTATE_UINT8(loc_sel, TPMStateI2C), 133139fdb3eSNinad Palsule VMSTATE_UINT8(csum_enable, TPMStateI2C), 134139fdb3eSNinad Palsule 135139fdb3eSNinad Palsule VMSTATE_END_OF_LIST() 136139fdb3eSNinad Palsule } 137139fdb3eSNinad Palsule }; 138139fdb3eSNinad Palsule 139139fdb3eSNinad Palsule /* 140139fdb3eSNinad Palsule * Set data value. The i2cst->offset is not updated as called in 141139fdb3eSNinad Palsule * the read path. 142139fdb3eSNinad Palsule */ 143139fdb3eSNinad Palsule static void tpm_tis_i2c_set_data(TPMStateI2C *i2cst, uint32_t data) 144139fdb3eSNinad Palsule { 145139fdb3eSNinad Palsule i2cst->data[1] = data; 146139fdb3eSNinad Palsule i2cst->data[2] = data >> 8; 147139fdb3eSNinad Palsule i2cst->data[3] = data >> 16; 148139fdb3eSNinad Palsule i2cst->data[4] = data >> 24; 149139fdb3eSNinad Palsule } 150139fdb3eSNinad Palsule /* 151139fdb3eSNinad Palsule * Generate interface capability based on what is returned by TIS and what is 152139fdb3eSNinad Palsule * expected by I2C. Save the capability in the data array overwriting the TIS 153139fdb3eSNinad Palsule * capability. 154139fdb3eSNinad Palsule */ 155139fdb3eSNinad Palsule static uint32_t tpm_tis_i2c_interface_capability(TPMStateI2C *i2cst, 156139fdb3eSNinad Palsule uint32_t tis_cap) 157139fdb3eSNinad Palsule { 158139fdb3eSNinad Palsule uint32_t i2c_cap; 159139fdb3eSNinad Palsule 160139fdb3eSNinad Palsule /* Now generate i2c capability */ 161139fdb3eSNinad Palsule i2c_cap = (TPM_I2C_CAP_INTERFACE_TYPE | 162139fdb3eSNinad Palsule TPM_I2C_CAP_INTERFACE_VER | 163139fdb3eSNinad Palsule TPM_I2C_CAP_TPM2_FAMILY | 164139fdb3eSNinad Palsule TPM_I2C_CAP_LOCALITY_CAP | 165139fdb3eSNinad Palsule TPM_I2C_CAP_BUS_SPEED | 166139fdb3eSNinad Palsule TPM_I2C_CAP_DEV_ADDR_CHANGE); 167139fdb3eSNinad Palsule 168139fdb3eSNinad Palsule /* Now check the TIS and set some capabilities */ 169139fdb3eSNinad Palsule 170139fdb3eSNinad Palsule /* Static burst count set */ 171139fdb3eSNinad Palsule if (tis_cap & TPM_TIS_CAP_BURST_COUNT_STATIC) { 172139fdb3eSNinad Palsule i2c_cap |= TPM_I2C_CAP_BURST_COUNT_STATIC; 173139fdb3eSNinad Palsule } 174139fdb3eSNinad Palsule 175139fdb3eSNinad Palsule return i2c_cap; 176139fdb3eSNinad Palsule } 177139fdb3eSNinad Palsule 178139fdb3eSNinad Palsule /* Convert I2C register to TIS address and returns the name of the register */ 179139fdb3eSNinad Palsule static inline void tpm_tis_i2c_to_tis_reg(TPMStateI2C *i2cst, uint8_t i2c_reg) 180139fdb3eSNinad Palsule { 181139fdb3eSNinad Palsule const I2CRegMap *reg_map; 182139fdb3eSNinad Palsule int i; 183139fdb3eSNinad Palsule 184139fdb3eSNinad Palsule i2cst->tis_addr = 0xffffffff; 185139fdb3eSNinad Palsule 186139fdb3eSNinad Palsule /* Special case for the STS register. */ 187139fdb3eSNinad Palsule if (i2c_reg >= TPM_I2C_REG_STS && i2c_reg <= TPM_I2C_REG_STS + 3) { 188139fdb3eSNinad Palsule i2c_reg = TPM_I2C_REG_STS; 189139fdb3eSNinad Palsule } 190139fdb3eSNinad Palsule 191139fdb3eSNinad Palsule for (i = 0; i < ARRAY_SIZE(tpm_tis_reg_map); i++) { 192139fdb3eSNinad Palsule reg_map = &tpm_tis_reg_map[i]; 193139fdb3eSNinad Palsule if (reg_map->i2c_reg == i2c_reg) { 194139fdb3eSNinad Palsule i2cst->reg_name = reg_map->reg_name; 195139fdb3eSNinad Palsule i2cst->tis_addr = reg_map->tis_reg; 196139fdb3eSNinad Palsule 197139fdb3eSNinad Palsule /* Include the locality in the address. */ 198139fdb3eSNinad Palsule assert(TPM_TIS_I2C_IS_VALID_LOCTY(i2cst->loc_sel)); 199139fdb3eSNinad Palsule i2cst->tis_addr += (i2cst->loc_sel << TPM_TIS_LOCALITY_SHIFT); 200139fdb3eSNinad Palsule break; 201139fdb3eSNinad Palsule } 202139fdb3eSNinad Palsule } 203139fdb3eSNinad Palsule } 204139fdb3eSNinad Palsule 205139fdb3eSNinad Palsule /* Clear some fields from the structure. */ 206139fdb3eSNinad Palsule static inline void tpm_tis_i2c_clear_data(TPMStateI2C *i2cst) 207139fdb3eSNinad Palsule { 208139fdb3eSNinad Palsule /* Clear operation and offset */ 209139fdb3eSNinad Palsule i2cst->operation = 0; 210139fdb3eSNinad Palsule i2cst->offset = 0; 211139fdb3eSNinad Palsule i2cst->tis_addr = 0xffffffff; 212139fdb3eSNinad Palsule i2cst->reg_name = NULL; 213139fdb3eSNinad Palsule memset(i2cst->data, 0, sizeof(i2cst->data)); 214139fdb3eSNinad Palsule 215139fdb3eSNinad Palsule return; 216139fdb3eSNinad Palsule } 217139fdb3eSNinad Palsule 218139fdb3eSNinad Palsule /* Send data to TPM */ 219139fdb3eSNinad Palsule static inline void tpm_tis_i2c_tpm_send(TPMStateI2C *i2cst) 220139fdb3eSNinad Palsule { 221139fdb3eSNinad Palsule uint32_t data; 222139fdb3eSNinad Palsule size_t offset = 0; 223139fdb3eSNinad Palsule uint32_t sz = 4; 224139fdb3eSNinad Palsule 225139fdb3eSNinad Palsule if ((i2cst->operation == OP_SEND) && (i2cst->offset > 1)) { 226139fdb3eSNinad Palsule 227139fdb3eSNinad Palsule switch (i2cst->data[0]) { 228139fdb3eSNinad Palsule case TPM_I2C_REG_DATA_CSUM_ENABLE: 229139fdb3eSNinad Palsule /* 230139fdb3eSNinad Palsule * Checksum is not handled by TIS code hence we will consume the 231139fdb3eSNinad Palsule * register here. 232139fdb3eSNinad Palsule */ 233139fdb3eSNinad Palsule i2cst->csum_enable = i2cst->data[1] & TPM_DATA_CSUM_ENABLED; 234139fdb3eSNinad Palsule break; 235139fdb3eSNinad Palsule case TPM_I2C_REG_DATA_FIFO: 236139fdb3eSNinad Palsule /* Handled in the main i2c_send function */ 237139fdb3eSNinad Palsule break; 238139fdb3eSNinad Palsule case TPM_I2C_REG_LOC_SEL: 239139fdb3eSNinad Palsule /* 240139fdb3eSNinad Palsule * This register is not handled by TIS so save the locality 241139fdb3eSNinad Palsule * locally 242139fdb3eSNinad Palsule */ 243139fdb3eSNinad Palsule if (TPM_TIS_I2C_IS_VALID_LOCTY(i2cst->data[1])) { 244139fdb3eSNinad Palsule i2cst->loc_sel = i2cst->data[1]; 245139fdb3eSNinad Palsule } 246139fdb3eSNinad Palsule break; 247139fdb3eSNinad Palsule default: 248139fdb3eSNinad Palsule /* We handle non-FIFO here */ 249139fdb3eSNinad Palsule 250139fdb3eSNinad Palsule /* Index 0 is a register. Convert byte stream to uint32_t */ 251139fdb3eSNinad Palsule data = i2cst->data[1]; 252139fdb3eSNinad Palsule data |= i2cst->data[2] << 8; 253139fdb3eSNinad Palsule data |= i2cst->data[3] << 16; 254139fdb3eSNinad Palsule data |= i2cst->data[4] << 24; 255139fdb3eSNinad Palsule 256139fdb3eSNinad Palsule /* Add register specific masking */ 257139fdb3eSNinad Palsule switch (i2cst->data[0]) { 258139fdb3eSNinad Palsule case TPM_I2C_REG_INT_ENABLE: 259139fdb3eSNinad Palsule data &= TPM_I2C_INT_ENABLE_MASK; 260139fdb3eSNinad Palsule break; 261139fdb3eSNinad Palsule case TPM_I2C_REG_STS ... TPM_I2C_REG_STS + 3: 262139fdb3eSNinad Palsule /* 263139fdb3eSNinad Palsule * STS register has 4 bytes data. 264139fdb3eSNinad Palsule * As per the specs following writes must be allowed. 265139fdb3eSNinad Palsule * - From base address 1 to 4 bytes are allowed. 266139fdb3eSNinad Palsule * - Single byte write to first or last byte must 267139fdb3eSNinad Palsule * be allowed. 268139fdb3eSNinad Palsule */ 269139fdb3eSNinad Palsule offset = i2cst->data[0] - TPM_I2C_REG_STS; 270139fdb3eSNinad Palsule if (offset > 0) { 271139fdb3eSNinad Palsule sz = 1; 272139fdb3eSNinad Palsule } 273139fdb3eSNinad Palsule data &= (TPM_I2C_STS_WRITE_MASK >> (offset * 8)); 274139fdb3eSNinad Palsule break; 275139fdb3eSNinad Palsule } 276139fdb3eSNinad Palsule 277139fdb3eSNinad Palsule tpm_tis_write_data(&i2cst->state, i2cst->tis_addr + offset, data, 278139fdb3eSNinad Palsule sz); 279139fdb3eSNinad Palsule break; 280139fdb3eSNinad Palsule } 281139fdb3eSNinad Palsule 282139fdb3eSNinad Palsule tpm_tis_i2c_clear_data(i2cst); 283139fdb3eSNinad Palsule } 284139fdb3eSNinad Palsule 285139fdb3eSNinad Palsule return; 286139fdb3eSNinad Palsule } 287139fdb3eSNinad Palsule 288139fdb3eSNinad Palsule /* Callback from TPM to indicate that response is copied */ 289139fdb3eSNinad Palsule static void tpm_tis_i2c_request_completed(TPMIf *ti, int ret) 290139fdb3eSNinad Palsule { 291139fdb3eSNinad Palsule TPMStateI2C *i2cst = TPM_TIS_I2C(ti); 292139fdb3eSNinad Palsule TPMState *s = &i2cst->state; 293139fdb3eSNinad Palsule 294139fdb3eSNinad Palsule /* Inform the common code. */ 295139fdb3eSNinad Palsule tpm_tis_request_completed(s, ret); 296139fdb3eSNinad Palsule } 297139fdb3eSNinad Palsule 298139fdb3eSNinad Palsule static enum TPMVersion tpm_tis_i2c_get_tpm_version(TPMIf *ti) 299139fdb3eSNinad Palsule { 300139fdb3eSNinad Palsule TPMStateI2C *i2cst = TPM_TIS_I2C(ti); 301139fdb3eSNinad Palsule TPMState *s = &i2cst->state; 302139fdb3eSNinad Palsule 303139fdb3eSNinad Palsule return tpm_tis_get_tpm_version(s); 304139fdb3eSNinad Palsule } 305139fdb3eSNinad Palsule 306139fdb3eSNinad Palsule static int tpm_tis_i2c_event(I2CSlave *i2c, enum i2c_event event) 307139fdb3eSNinad Palsule { 308139fdb3eSNinad Palsule TPMStateI2C *i2cst = TPM_TIS_I2C(i2c); 309139fdb3eSNinad Palsule int ret = 0; 310139fdb3eSNinad Palsule 311139fdb3eSNinad Palsule switch (event) { 312139fdb3eSNinad Palsule case I2C_START_RECV: 313139fdb3eSNinad Palsule trace_tpm_tis_i2c_event("START_RECV"); 314139fdb3eSNinad Palsule break; 315139fdb3eSNinad Palsule case I2C_START_SEND: 316139fdb3eSNinad Palsule trace_tpm_tis_i2c_event("START_SEND"); 317139fdb3eSNinad Palsule tpm_tis_i2c_clear_data(i2cst); 318139fdb3eSNinad Palsule break; 319139fdb3eSNinad Palsule case I2C_FINISH: 320139fdb3eSNinad Palsule trace_tpm_tis_i2c_event("FINISH"); 321139fdb3eSNinad Palsule if (i2cst->operation == OP_SEND) { 322139fdb3eSNinad Palsule tpm_tis_i2c_tpm_send(i2cst); 323139fdb3eSNinad Palsule } else { 324139fdb3eSNinad Palsule tpm_tis_i2c_clear_data(i2cst); 325139fdb3eSNinad Palsule } 326139fdb3eSNinad Palsule break; 327139fdb3eSNinad Palsule default: 328139fdb3eSNinad Palsule break; 329139fdb3eSNinad Palsule } 330139fdb3eSNinad Palsule 331139fdb3eSNinad Palsule return ret; 332139fdb3eSNinad Palsule } 333139fdb3eSNinad Palsule 334139fdb3eSNinad Palsule /* 335139fdb3eSNinad Palsule * If data is for FIFO then it is received from tpm_tis_common buffer 336139fdb3eSNinad Palsule * otherwise it will be handled using single call to common code and 337139fdb3eSNinad Palsule * cached in the local buffer. 338139fdb3eSNinad Palsule */ 339139fdb3eSNinad Palsule static uint8_t tpm_tis_i2c_recv(I2CSlave *i2c) 340139fdb3eSNinad Palsule { 341139fdb3eSNinad Palsule int ret = 0; 342139fdb3eSNinad Palsule uint32_t data_read; 343139fdb3eSNinad Palsule TPMStateI2C *i2cst = TPM_TIS_I2C(i2c); 344139fdb3eSNinad Palsule TPMState *s = &i2cst->state; 345139fdb3eSNinad Palsule uint16_t i2c_reg = i2cst->data[0]; 346139fdb3eSNinad Palsule size_t offset; 347139fdb3eSNinad Palsule 348139fdb3eSNinad Palsule if (i2cst->operation == OP_RECV) { 349139fdb3eSNinad Palsule 350139fdb3eSNinad Palsule /* Do not cache FIFO data. */ 351139fdb3eSNinad Palsule if (i2cst->data[0] == TPM_I2C_REG_DATA_FIFO) { 352139fdb3eSNinad Palsule data_read = tpm_tis_read_data(s, i2cst->tis_addr, 1); 353139fdb3eSNinad Palsule ret = (data_read & 0xff); 354139fdb3eSNinad Palsule } else if (i2cst->offset < sizeof(i2cst->data)) { 355139fdb3eSNinad Palsule ret = i2cst->data[i2cst->offset++]; 356139fdb3eSNinad Palsule } 357139fdb3eSNinad Palsule 358139fdb3eSNinad Palsule } else if ((i2cst->operation == OP_SEND) && (i2cst->offset < 2)) { 359139fdb3eSNinad Palsule /* First receive call after send */ 360139fdb3eSNinad Palsule 361139fdb3eSNinad Palsule i2cst->operation = OP_RECV; 362139fdb3eSNinad Palsule 363139fdb3eSNinad Palsule switch (i2c_reg) { 364139fdb3eSNinad Palsule case TPM_I2C_REG_LOC_SEL: 365139fdb3eSNinad Palsule /* Location selection register is managed by i2c */ 366139fdb3eSNinad Palsule tpm_tis_i2c_set_data(i2cst, i2cst->loc_sel); 367139fdb3eSNinad Palsule break; 368139fdb3eSNinad Palsule case TPM_I2C_REG_DATA_FIFO: 369139fdb3eSNinad Palsule /* FIFO data is directly read from TPM TIS */ 370139fdb3eSNinad Palsule data_read = tpm_tis_read_data(s, i2cst->tis_addr, 1); 371139fdb3eSNinad Palsule tpm_tis_i2c_set_data(i2cst, (data_read & 0xff)); 372139fdb3eSNinad Palsule break; 373139fdb3eSNinad Palsule case TPM_I2C_REG_DATA_CSUM_ENABLE: 374139fdb3eSNinad Palsule tpm_tis_i2c_set_data(i2cst, i2cst->csum_enable); 375139fdb3eSNinad Palsule break; 376139fdb3eSNinad Palsule case TPM_I2C_REG_INT_CAPABILITY: 377139fdb3eSNinad Palsule /* 378139fdb3eSNinad Palsule * Interrupt is not supported in the linux kernel hence we cannot 379139fdb3eSNinad Palsule * test this model with interrupts. 380139fdb3eSNinad Palsule */ 381139fdb3eSNinad Palsule tpm_tis_i2c_set_data(i2cst, TPM_I2C_INT_ENABLE_MASK); 382139fdb3eSNinad Palsule break; 383139fdb3eSNinad Palsule case TPM_I2C_REG_DATA_CSUM_GET: 384139fdb3eSNinad Palsule /* 385139fdb3eSNinad Palsule * Checksum registers are not supported by common code hence 386139fdb3eSNinad Palsule * call a common code to get the checksum. 387139fdb3eSNinad Palsule */ 388139fdb3eSNinad Palsule data_read = tpm_tis_get_checksum(s); 389139fdb3eSNinad Palsule 390139fdb3eSNinad Palsule /* Save the byte stream in data field */ 391139fdb3eSNinad Palsule tpm_tis_i2c_set_data(i2cst, data_read); 392139fdb3eSNinad Palsule break; 393139fdb3eSNinad Palsule default: 394139fdb3eSNinad Palsule data_read = tpm_tis_read_data(s, i2cst->tis_addr, 4); 395139fdb3eSNinad Palsule 396139fdb3eSNinad Palsule switch (i2c_reg) { 397139fdb3eSNinad Palsule case TPM_I2C_REG_INTF_CAPABILITY: 398139fdb3eSNinad Palsule /* Prepare the capabilities as per I2C interface */ 399139fdb3eSNinad Palsule data_read = tpm_tis_i2c_interface_capability(i2cst, 400139fdb3eSNinad Palsule data_read); 401139fdb3eSNinad Palsule break; 402139fdb3eSNinad Palsule case TPM_I2C_REG_STS ... TPM_I2C_REG_STS + 3: 403139fdb3eSNinad Palsule offset = i2c_reg - TPM_I2C_REG_STS; 404139fdb3eSNinad Palsule /* 405139fdb3eSNinad Palsule * As per specs, STS bit 31:26 are reserved and must 406139fdb3eSNinad Palsule * be set to 0 407139fdb3eSNinad Palsule */ 408139fdb3eSNinad Palsule data_read &= TPM_I2C_STS_READ_MASK; 409139fdb3eSNinad Palsule /* 410139fdb3eSNinad Palsule * STS register has 4 bytes data. 411139fdb3eSNinad Palsule * As per the specs following reads must be allowed. 412139fdb3eSNinad Palsule * - From base address 1 to 4 bytes are allowed. 413139fdb3eSNinad Palsule * - Last byte must be allowed to read as a single byte 414139fdb3eSNinad Palsule * - Second and third byte must be allowed to read as two 415139fdb3eSNinad Palsule * two bytes. 416139fdb3eSNinad Palsule */ 417139fdb3eSNinad Palsule data_read >>= (offset * 8); 418139fdb3eSNinad Palsule break; 419139fdb3eSNinad Palsule } 420139fdb3eSNinad Palsule 421139fdb3eSNinad Palsule /* Save byte stream in data[] */ 422139fdb3eSNinad Palsule tpm_tis_i2c_set_data(i2cst, data_read); 423139fdb3eSNinad Palsule break; 424139fdb3eSNinad Palsule } 425139fdb3eSNinad Palsule 426139fdb3eSNinad Palsule /* Return first byte with this call */ 427139fdb3eSNinad Palsule i2cst->offset = 1; /* keep the register value intact for debug */ 428139fdb3eSNinad Palsule ret = i2cst->data[i2cst->offset++]; 429139fdb3eSNinad Palsule } else { 430139fdb3eSNinad Palsule i2cst->operation = OP_RECV; 431139fdb3eSNinad Palsule } 432139fdb3eSNinad Palsule 433139fdb3eSNinad Palsule trace_tpm_tis_i2c_recv(ret); 434139fdb3eSNinad Palsule 435139fdb3eSNinad Palsule return ret; 436139fdb3eSNinad Palsule } 437139fdb3eSNinad Palsule 438139fdb3eSNinad Palsule /* 439139fdb3eSNinad Palsule * Send function only remembers data in the buffer and then calls 440139fdb3eSNinad Palsule * TPM TIS common code during FINISH event. 441139fdb3eSNinad Palsule */ 442139fdb3eSNinad Palsule static int tpm_tis_i2c_send(I2CSlave *i2c, uint8_t data) 443139fdb3eSNinad Palsule { 444139fdb3eSNinad Palsule TPMStateI2C *i2cst = TPM_TIS_I2C(i2c); 445139fdb3eSNinad Palsule 446139fdb3eSNinad Palsule /* Reject non-supported registers. */ 447139fdb3eSNinad Palsule if (i2cst->offset == 0) { 448139fdb3eSNinad Palsule /* Convert I2C register to TIS register */ 449139fdb3eSNinad Palsule tpm_tis_i2c_to_tis_reg(i2cst, data); 450139fdb3eSNinad Palsule if (i2cst->tis_addr == 0xffffffff) { 451139fdb3eSNinad Palsule return 0xffffffff; 452139fdb3eSNinad Palsule } 453139fdb3eSNinad Palsule 454139fdb3eSNinad Palsule trace_tpm_tis_i2c_send_reg(i2cst->reg_name, data); 455139fdb3eSNinad Palsule 456139fdb3eSNinad Palsule /* We do not support device address change */ 457139fdb3eSNinad Palsule if (data == TPM_I2C_REG_I2C_DEV_ADDRESS) { 458139fdb3eSNinad Palsule qemu_log_mask(LOG_UNIMP, "%s: Device address change " 459139fdb3eSNinad Palsule "is not supported.\n", __func__); 460139fdb3eSNinad Palsule return 0xffffffff; 461139fdb3eSNinad Palsule } 462139fdb3eSNinad Palsule } else { 463139fdb3eSNinad Palsule trace_tpm_tis_i2c_send(data); 464139fdb3eSNinad Palsule } 465139fdb3eSNinad Palsule 466139fdb3eSNinad Palsule if (i2cst->offset < sizeof(i2cst->data)) { 467139fdb3eSNinad Palsule i2cst->operation = OP_SEND; 468139fdb3eSNinad Palsule 469139fdb3eSNinad Palsule /* 470139fdb3eSNinad Palsule * In two cases, we save values in the local buffer. 471139fdb3eSNinad Palsule * 1) The first value is always a register. 472139fdb3eSNinad Palsule * 2) In case of non-FIFO multibyte registers, TIS expects full 473139fdb3eSNinad Palsule * register value hence I2C layer cache the register value and send 474139fdb3eSNinad Palsule * to TIS during FINISH event. 475139fdb3eSNinad Palsule */ 476139fdb3eSNinad Palsule if ((i2cst->offset == 0) || 477139fdb3eSNinad Palsule (i2cst->data[0] != TPM_I2C_REG_DATA_FIFO)) { 478139fdb3eSNinad Palsule i2cst->data[i2cst->offset++] = data; 479139fdb3eSNinad Palsule } else { 480139fdb3eSNinad Palsule /* 481139fdb3eSNinad Palsule * The TIS can process FIFO data one byte at a time hence the FIFO 482139fdb3eSNinad Palsule * data is sent to TIS directly. 483139fdb3eSNinad Palsule */ 484139fdb3eSNinad Palsule tpm_tis_write_data(&i2cst->state, i2cst->tis_addr, data, 1); 485139fdb3eSNinad Palsule } 486139fdb3eSNinad Palsule 487139fdb3eSNinad Palsule return 0; 488139fdb3eSNinad Palsule } 489139fdb3eSNinad Palsule 490139fdb3eSNinad Palsule /* Return non-zero to indicate NAK */ 491139fdb3eSNinad Palsule return 1; 492139fdb3eSNinad Palsule } 493139fdb3eSNinad Palsule 494139fdb3eSNinad Palsule static Property tpm_tis_i2c_properties[] = { 495139fdb3eSNinad Palsule DEFINE_PROP_TPMBE("tpmdev", TPMStateI2C, state.be_driver), 496139fdb3eSNinad Palsule DEFINE_PROP_END_OF_LIST(), 497139fdb3eSNinad Palsule }; 498139fdb3eSNinad Palsule 499139fdb3eSNinad Palsule static void tpm_tis_i2c_realizefn(DeviceState *dev, Error **errp) 500139fdb3eSNinad Palsule { 501139fdb3eSNinad Palsule TPMStateI2C *i2cst = TPM_TIS_I2C(dev); 502139fdb3eSNinad Palsule TPMState *s = &i2cst->state; 503139fdb3eSNinad Palsule 504139fdb3eSNinad Palsule if (!tpm_find()) { 505139fdb3eSNinad Palsule error_setg(errp, "at most one TPM device is permitted"); 506139fdb3eSNinad Palsule return; 507139fdb3eSNinad Palsule } 508139fdb3eSNinad Palsule 509139fdb3eSNinad Palsule /* 510*6eedbb5bSMichael Tokarev * Get the backend pointer. It is not initialized properly during 511139fdb3eSNinad Palsule * device_class_set_props 512139fdb3eSNinad Palsule */ 513139fdb3eSNinad Palsule s->be_driver = qemu_find_tpm_be("tpm0"); 514139fdb3eSNinad Palsule 515139fdb3eSNinad Palsule if (!s->be_driver) { 516139fdb3eSNinad Palsule error_setg(errp, "'tpmdev' property is required"); 517139fdb3eSNinad Palsule return; 518139fdb3eSNinad Palsule } 519139fdb3eSNinad Palsule } 520139fdb3eSNinad Palsule 521139fdb3eSNinad Palsule static void tpm_tis_i2c_reset(DeviceState *dev) 522139fdb3eSNinad Palsule { 523139fdb3eSNinad Palsule TPMStateI2C *i2cst = TPM_TIS_I2C(dev); 524139fdb3eSNinad Palsule TPMState *s = &i2cst->state; 525139fdb3eSNinad Palsule 526139fdb3eSNinad Palsule tpm_tis_i2c_clear_data(i2cst); 527139fdb3eSNinad Palsule 528139fdb3eSNinad Palsule i2cst->csum_enable = 0; 529139fdb3eSNinad Palsule i2cst->loc_sel = 0x00; 530139fdb3eSNinad Palsule 531139fdb3eSNinad Palsule return tpm_tis_reset(s); 532139fdb3eSNinad Palsule } 533139fdb3eSNinad Palsule 534139fdb3eSNinad Palsule static void tpm_tis_i2c_class_init(ObjectClass *klass, void *data) 535139fdb3eSNinad Palsule { 536139fdb3eSNinad Palsule DeviceClass *dc = DEVICE_CLASS(klass); 537139fdb3eSNinad Palsule I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); 538139fdb3eSNinad Palsule TPMIfClass *tc = TPM_IF_CLASS(klass); 539139fdb3eSNinad Palsule 540139fdb3eSNinad Palsule dc->realize = tpm_tis_i2c_realizefn; 541139fdb3eSNinad Palsule dc->reset = tpm_tis_i2c_reset; 542139fdb3eSNinad Palsule dc->vmsd = &vmstate_tpm_tis_i2c; 543139fdb3eSNinad Palsule device_class_set_props(dc, tpm_tis_i2c_properties); 544139fdb3eSNinad Palsule set_bit(DEVICE_CATEGORY_MISC, dc->categories); 545139fdb3eSNinad Palsule 546139fdb3eSNinad Palsule k->event = tpm_tis_i2c_event; 547139fdb3eSNinad Palsule k->recv = tpm_tis_i2c_recv; 548139fdb3eSNinad Palsule k->send = tpm_tis_i2c_send; 549139fdb3eSNinad Palsule 550139fdb3eSNinad Palsule tc->model = TPM_MODEL_TPM_TIS; 551139fdb3eSNinad Palsule tc->request_completed = tpm_tis_i2c_request_completed; 552139fdb3eSNinad Palsule tc->get_version = tpm_tis_i2c_get_tpm_version; 553139fdb3eSNinad Palsule } 554139fdb3eSNinad Palsule 555139fdb3eSNinad Palsule static const TypeInfo tpm_tis_i2c_info = { 556139fdb3eSNinad Palsule .name = TYPE_TPM_TIS_I2C, 557139fdb3eSNinad Palsule .parent = TYPE_I2C_SLAVE, 558139fdb3eSNinad Palsule .instance_size = sizeof(TPMStateI2C), 559139fdb3eSNinad Palsule .class_init = tpm_tis_i2c_class_init, 560139fdb3eSNinad Palsule .interfaces = (InterfaceInfo[]) { 561139fdb3eSNinad Palsule { TYPE_TPM_IF }, 562139fdb3eSNinad Palsule { } 563139fdb3eSNinad Palsule } 564139fdb3eSNinad Palsule }; 565139fdb3eSNinad Palsule 566139fdb3eSNinad Palsule static void tpm_tis_i2c_register_types(void) 567139fdb3eSNinad Palsule { 568139fdb3eSNinad Palsule type_register_static(&tpm_tis_i2c_info); 569139fdb3eSNinad Palsule } 570139fdb3eSNinad Palsule 571139fdb3eSNinad Palsule type_init(tpm_tis_i2c_register_types) 572